-
Notifications
You must be signed in to change notification settings - Fork 280
feat(ui5-ai-input): introduce new component #12407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
StefanDimitrov04
wants to merge
56
commits into
main
Choose a base branch
from
ai-input
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
4d676e0
feat(ui5-ai-textarea): introduce new component
ndeshev d18dcac
feat(ui5-ai-textarea): introduce new component
ndeshev 8ded4f7
feat(ui5-ai-textarea): introduce new component
ndeshev 4842d6a
feat(ui5-ai-textarea): introduce new component
ndeshev 7fe9641
feat(ui5-ai-textarea): introduce new component
ndeshev 65161cb
feat(ui5-ai-textarea): introduce new component
ndeshev 531abcf
Merge branch 'main' into ai-textarea
ndeshev 89e1cf2
Merge branch 'main' into ai-textarea
ndeshev 4d2c79a
feat(ui5-ai-textarea): introduce new component
ndeshev 84f38f6
Merge branch 'main' into ai-textarea
ndeshev 8b25d8f
feat(ui5-ai-textarea): introduce new component
ndeshev 8cf7379
Merge branch 'main' into ai-textarea
ndeshev 1b26913
Merge branch 'main' into ai-textarea
ndeshev b8ac3b6
Merge branch 'main' into ai-textarea
ndeshev 6511964
feat(ui5-ai-textarea): introduce new component
ndeshev 78f4ced
feat(ui5-ai-textarea): introduce new component
ndeshev e6856b7
Merge branch 'main' into ai-textarea
ndeshev 7a9e48d
feat(ui5-ai-textarea): introduce new component
ndeshev cea2409
Merge branch 'ai-textarea' of https://github.com/SAP/ui5-webcomponent…
ndeshev 37672ff
Merge branch 'main' into ai-textarea
ndeshev 1d7d19c
feat(ui5-ai-textarea): introduce new component
ndeshev 8811b32
Merge branch 'ai-textarea' of https://github.com/SAP/ui5-webcomponent…
ndeshev ece74f7
feat(ui5-ai-textarea): introduce new component
ndeshev 7b5274c
Merge branch 'main' into ai-textarea
ndeshev 9fa18af
Merge branch 'main' into ai-textarea
ndeshev c483d45
Merge branch 'main' of https://github.com/SAP/ui5-webcomponents into …
ndeshev 4fd733d
Merge branch 'main' into ai-textarea
ndeshev d66e7fe
feat(ui5-ai-textarea): introduce new component
ndeshev 988e535
Merge branch 'main' into ai-textarea
ndeshev 4e59f48
feat(ui5-ai-textarea): introduce new component
ndeshev e9e9432
feat(ui5-ai-textarea): introduce new component
ndeshev f1e6023
feat(ui5-ai-textarea): introduce new component
ndeshev 7bab270
feat(ai-input): introduce new component POC
StefanDimitrov04 8d09a5b
Merge branch 'ai-textarea' of github.com:SAP/ui5-webcomponents into a…
StefanDimitrov04 72b6443
feat(ui5-ai-input): resolve conflicts
StefanDimitrov04 83b8c1e
Merge branch 'main' into ai-textarea
ndeshev d435c83
feat(ui5-ai-textarea): introduce new component
ndeshev 787d306
Merge branch 'main' into ai-textarea
ndeshev 5387e67
feat(ui5-ai-textarea): introduce new component
ndeshev 76637d8
Merge branch 'ai-textarea' of https://github.com/UI5/webcomponents in…
ndeshev eab3293
Merge branch 'main' into ai-textarea
ndeshev 18e06dc
feat(ui5-ai-textarea): introduce new component
ndeshev fbae010
feat(ui5-ai-textarea): introduce new component
ndeshev 15445a7
feat(ui5-ai-textarea): introduce new component
ndeshev 342efdc
Merge branch 'ai-textarea' of github.com:SAP/ui5-webcomponents into a…
StefanDimitrov04 ad08bb2
feat(ui5-ai-input): add tests and simplify code
StefanDimitrov04 1db10a0
feat(ui5-ai-input): fix imports
StefanDimitrov04 21decf5
feat(ui5-ai-input): fix imports
StefanDimitrov04 214955d
Merge branch 'main' of github.com:SAP/ui5-webcomponents into ai-input
StefanDimitrov04 f6d9a3d
feat(ui5-ai-input): remove input versioning
StefanDimitrov04 3d723a9
feat(ui5-ai-input): add tests
StefanDimitrov04 d22240e
feat(ui5-ai-input): fix css
StefanDimitrov04 42af0f3
feat(ui5-ai-input): fix lint
StefanDimitrov04 989df7d
feat(ui5-ai-input): resolve comments
StefanDimitrov04 be4a38c
feat(ui5-ai-input): fix css
StefanDimitrov04 01978f0
feat(ui5-ai-input): fix comments and design
StefanDimitrov04 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| import { customElement, property, slot } from "@ui5/webcomponents-base"; | ||
| import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js"; | ||
| import BaseInput from "@ui5/webcomponents/dist/Input.js"; | ||
| import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js"; | ||
| import type Menu from "@ui5/webcomponents/dist/Menu.js"; | ||
| import type Button from "./Button.js"; | ||
|
|
||
| // styles | ||
| import AIInputCss from "./generated/themes/Input.css.js"; | ||
| import InputCss from "@ui5/webcomponents/dist/generated/themes/Input.css.js"; | ||
| import ResponsivePopoverCommonCss from "@ui5/webcomponents/dist/generated/themes/ResponsivePopoverCommon.css.js"; | ||
| import ValueStateMessageCss from "@ui5/webcomponents/dist/generated/themes/ValueStateMessage.css.js"; | ||
| import SuggestionsCss from "@ui5/webcomponents/dist/generated/themes/Suggestions.css.js"; | ||
|
|
||
| // templates | ||
| import InputTemplate from "./InputTemplate.js"; | ||
| import { | ||
| VERSIONING_NEXT_BUTTON_TEXT, | ||
| VERSIONING_PREVIOUS_BUTTON_TEXT, | ||
| INPUT_WRITING_ASSISTANT_LABEL, | ||
| WRITING_ASSISTANT_GENERATING_ANNOUNCEMENT, | ||
| } from "./generated/i18n/i18n-defaults.js"; | ||
|
|
||
| @customElement({ | ||
| tag: "ui5-ai-input", | ||
| languageAware: true, | ||
| renderer: jsxRenderer, | ||
| template: InputTemplate, | ||
| styles: [ | ||
| AIInputCss, | ||
| InputCss, | ||
| ResponsivePopoverCommonCss, | ||
| ValueStateMessageCss, | ||
| SuggestionsCss, | ||
| ], | ||
| }) | ||
|
|
||
| /** | ||
| * Fired when the user clicks on the AI button. | ||
| * @public | ||
| */ | ||
| @event("button-click", { | ||
| cancelable: true, | ||
| }) | ||
|
|
||
| /** | ||
| * Fired when the user clicks on the "Stop" button to stop ongoing AI text generation. | ||
| * @public | ||
| */ | ||
| @event("stop-generation") | ||
|
|
||
| /** | ||
| * Fired when the user clicks on version navigation buttons. | ||
| * | ||
| * @param {boolean} backwards - Indicates if navigation is backwards (true) or forwards (false, default) | ||
| * @public | ||
| */ | ||
| @event("version-change") | ||
|
|
||
| class Input extends BaseInput { | ||
| eventDetails!: BaseInput["eventDetails"] & { | ||
| "version-change": { | ||
| backwards: boolean; | ||
| }; | ||
| "stop-generation": object; | ||
| "button-click": object; | ||
| }; | ||
|
|
||
| /** | ||
| * Indicates the index of the currently displayed version. | ||
| * | ||
| * @default 0 | ||
| */ | ||
| @property({ type: Number }) | ||
| currentVersion = 0; | ||
|
|
||
| /** | ||
| * Indicates the total number of result versions available. | ||
| * | ||
| * When not set or `0`, versioning UI will be hidden. | ||
| * | ||
| * @default 0 | ||
| * @public | ||
| */ | ||
| @property({ type: Number }) | ||
| totalVersions = 0; | ||
|
|
||
| /** | ||
| * Defines whether the AI Writing Assistant is currently loading. | ||
| * | ||
| * When `true`, indicates that an AI action is in progress. | ||
| * | ||
| * @default false | ||
| */ | ||
| @property({ type: Boolean }) | ||
| loading: boolean = false; | ||
|
|
||
| /** | ||
| * Indicates if the menu is open. | ||
| * @default 0 | ||
| * @private | ||
| */ | ||
| @property({ type: Boolean }) | ||
| _isMenuOpen: boolean = false; | ||
|
|
||
| /** | ||
| * Defines the items of the menu for the component. | ||
| * @public | ||
| */ | ||
| @slot({ | ||
| type: HTMLElement, | ||
| invalidateOnChildChange: true, | ||
| }) | ||
| actions!: Array<HTMLElement>; | ||
|
|
||
| _previousCurrentStep = 0; | ||
| _previousTotalSteps = 0; | ||
| isFocused: boolean = false; | ||
|
|
||
| _onfocusin(e: FocusEvent): void { | ||
| super._onfocusin(e); | ||
| this.isFocused = true; | ||
| } | ||
|
|
||
| _onfocusout(e: FocusEvent): void { | ||
| super._onfocusout(e); | ||
| this.isFocused = false; | ||
| } | ||
|
|
||
| /** | ||
| * Manages focus when navigation buttons become disabled/enabled. | ||
| * Automatically moves focus to available button when user reaches boundaries. | ||
| * @private | ||
| */ | ||
| _manageVersionButtonsFocus() { | ||
| const previousButton = this.shadowRoot?.querySelectorAll("ui5-button")[0] as Button; | ||
| const nextButton = this.shadowRoot?.querySelectorAll("ui5-button")[1] as Button; | ||
| const isPreviousDisabled = this.currentVersion <= 1; | ||
| const isNextDisabled = this.currentVersion >= this.totalVersions; | ||
|
|
||
| if (isPreviousDisabled && previousButton) { | ||
| setTimeout(() => { | ||
| nextButton.focus(); | ||
| }, 0); | ||
| } else if (isNextDisabled && nextButton) { | ||
| setTimeout(() => { | ||
| previousButton.focus(); | ||
| }, 0); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Handles the click event for the AI generate icon. | ||
| * Fires the appropriate event based on the AI icon state. | ||
| * @private | ||
| */ | ||
| _handleAIIconClick(e: Event) { | ||
| const target = e.target as HTMLElement & { name?: string }; | ||
| if (target?.name === "stop") { | ||
| this.fireDecoratorEvent("stop-generation"); | ||
| } else { | ||
| const opener = this.shadowRoot?.querySelector(".ui5-input-ai-icon") as HTMLElement; | ||
| this.fireDecoratorEvent("button-click"); | ||
| this.menu.opener = opener; | ||
| this.menu.open = true; | ||
| this.menu.horizontalAlign = "End"; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Handles the version change event from the versioning component. | ||
| * | ||
| * @param {CustomEvent} e - The version change event | ||
| */ | ||
| _handleVersionChange(e: CustomEvent<{ backwards: boolean }>) { | ||
| this.fireDecoratorEvent("version-change", { | ||
| backwards: e.detail.backwards, | ||
| }); | ||
| this._manageVersionButtonsFocus(); | ||
| } | ||
|
|
||
| /** | ||
| * Handles the click event for the "Previous Version" button. | ||
| * Updates the current version index and syncs content. | ||
| * @private | ||
| */ | ||
| _handlePreviousButtonClick(): void { | ||
| this._handleVersionChange(new CustomEvent("version-change", { detail: { backwards: true } })); | ||
| } | ||
|
|
||
| /** | ||
| * Handles the click event for the "Next Version" button. | ||
| * Updates the current version index and syncs content. | ||
| * @private | ||
| */ | ||
| _handleNextButtonClick(): void { | ||
| this._handleVersionChange(new CustomEvent("version-change", { detail: { backwards: false } })); | ||
| } | ||
|
|
||
| _onMenuIconClick(): void { | ||
| this.menu?.addEventListener("item-click", (e: Event) => { | ||
| const customEvent = e as CustomEvent; | ||
| this.dispatchEvent(new CustomEvent("item-click", { | ||
| detail: customEvent.detail, | ||
| bubbles: true, | ||
| composed: true, | ||
| })); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Handles keydown events for keyboard shortcuts. | ||
| * @private | ||
| */ | ||
| _onkeydown(e: KeyboardEvent): void { | ||
| super._onkeydown(e); | ||
| this.menu.opener = this.shadowRoot?.querySelector(".ui5-input-ai-icon") as HTMLElement; | ||
|
|
||
| if (e.key === "F4" && e.shiftKey) { | ||
| e.preventDefault(); | ||
| this.menu.open = true; | ||
| this.menu.horizontalAlign = "End"; | ||
| } | ||
| const goPreviousStep = e.key === "Z" && e.shiftKey && e.ctrlKey; | ||
| const goNextStep = e.key === "Y" && e.shiftKey && e.ctrlKey; | ||
|
|
||
| if (goPreviousStep) { | ||
| e.preventDefault(); | ||
| this._handlePreviousButtonClick(); | ||
| } else if (goNextStep) { | ||
| e.preventDefault(); | ||
| this._handleNextButtonClick(); | ||
| } | ||
| } | ||
|
|
||
| get ariaLabel() { | ||
| return this.accessibleName || !this.loading ? Input.i18nBundle.getText(INPUT_WRITING_ASSISTANT_LABEL) : Input.i18nBundle.getText(WRITING_ASSISTANT_GENERATING_ANNOUNCEMENT); | ||
| } | ||
|
|
||
| get stopGeneratingTooltip() { | ||
| return Input.i18nBundle.getText(WRITING_ASSISTANT_GENERATING_ANNOUNCEMENT); | ||
| } | ||
|
|
||
| get nextButtonAccessibleName() { | ||
| return Input.i18nBundle.getText(VERSIONING_NEXT_BUTTON_TEXT); | ||
| } | ||
|
|
||
| get previousButtonAccessibleName() { | ||
| return Input.i18nBundle.getText(VERSIONING_PREVIOUS_BUTTON_TEXT); | ||
| } | ||
|
|
||
| get menu() { | ||
| return this.shadowRoot?.querySelector("ui5-menu") as Menu; | ||
| } | ||
| } | ||
|
|
||
| Input.define(); | ||
|
|
||
| export default Input; | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.