Skip to content

Commit

Permalink
refactor(ui5-input): events changes (#8769)
Browse files Browse the repository at this point in the history
* refactor(ui5-input): events changes

BREAKING CHANGE: Remove suggestion-item-select event.
Rename and modify suggestion-item-preview event.
Remove openPicker method and replace it with public property "open".

* refactor(ui5-input): events changes

* refactor(ui5-input): property open tests

* refactor(ui5-input): events change

* refactor(ui5-input): events change

* refactor(ui5-input): events changes

* refactor(ui5-input): events changes

* refactor(ui5-input): events changes
  • Loading branch information
nikoletavnv authored May 8, 2024
1 parent 1ca5c2c commit 9f5c8a4
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 348 deletions.
1 change: 0 additions & 1 deletion packages/fiori/src/themes/ShellBar.css
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,6 @@ slot[name="profile"] {
box-shadow: var(--_ui5_shellbar_search_field_box_shadow_hover);
}

/* Todo: modify this selector after ui5-input is updated */
::slotted([ui5-input][focused]) {
outline: var(--_ui5_shellbar_search_field_outline_focused);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/fiori/test/pages/ShellBar.html
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ <h3>ShellBar in Compact</h3>
</ui5-shellbar>

<script>
mySearch.addEventListener("ui5-suggestion-item-select", function (event) {
mySearch.addEventListener("ui5-selection-change", function (event) {
console.log(event);
});

Expand Down
178 changes: 62 additions & 116 deletions packages/main/src/Input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ type AccInfo = {
enum INPUT_EVENTS {
CHANGE = "change",
INPUT = "input",
SUGGESTION_ITEM_SELECT = "suggestion-item-select",
SELECTION_CHANGE = "selection-change",
}

// all user interactions
Expand All @@ -137,13 +137,9 @@ type InputEventDetail = {
inputType: string;
}

type InputSuggestionItemSelectEventDetail = {
item: IInputSuggestionItem;
}

type InputSuggestionItemPreviewEventDetail = {
item: IInputSuggestionItem;
targetRef: SuggestionListItem;
type InputSelectionChangeEventDetail = {
item: IInputSuggestionItem | null;
targetRef: SuggestionListItem | null;
}

type InputSuggestionScrollEventDetail = {
Expand Down Expand Up @@ -176,8 +172,8 @@ type InputSuggestionScrollEventDetail = {
*
* - [Escape] - Closes the suggestion list, if open. If closed or not enabled, cancels changes and reverts to the value which the Input field had when it got the focus.
* - [Enter] or [Return] - If suggestion list is open takes over the current matching item and closes it. If value state or group header is focused, does nothing.
* - [Down] - Focuses the next matching item in the suggestion list.
* - [Up] - Focuses the previous matching item in the suggestion list.
* - [Down] - Focuses the next matching item in the suggestion list. Selection-change event is fired.
* - [Up] - Focuses the previous matching item in the suggestion list. Selection-change event is fired.
* - [Home] - If focus is in the text input, moves caret before the first character. If focus is in the list, highlights the first item and updates the input accordingly.
* - [End] - If focus is in the text input, moves caret after the last character. If focus is in the list, highlights the last item and updates the input accordingly.
* - [Page Up] - If focus is in the list, moves highlight up by page size (10 items by default). If focus is in the input, does nothing.
Expand Down Expand Up @@ -222,30 +218,15 @@ type InputSuggestionScrollEventDetail = {
*/
@event("input")

/**
* Fired when a suggestion item, that is displayed in the suggestion popup, is selected.
* @param {HTMLElement} item The selected item.
* @public
* @allowPreventDefault
*/
@event<InputSuggestionItemSelectEventDetail>("suggestion-item-select", {
detail: {
/**
* @public
*/
item: { type: HTMLElement },
},
})

/**
* Fired when the user navigates to a suggestion item via the ARROW keys,
* as a preview, before the final selection.
* @param {HTMLElement} item The previewed suggestion item.
* @param {HTMLElement} targetRef The DOM ref of the suggestion item.
* @public
* @since 1.0.0-rc.8
* @since 2.0.0
*/
@event<InputSuggestionItemPreviewEventDetail>("suggestion-item-preview", {
@event<InputSelectionChangeEventDetail>("selection-change", {
detail: {
/**
* @public
Expand Down Expand Up @@ -569,8 +550,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {

hasSuggestionItemSelected: boolean;
valueBeforeItemSelection: string;
valueBeforeItemPreview: string
suggestionSelectionCancelled: boolean;
valueBeforeSelectionStart: string;
previousValue: string;
firstRendering: boolean;
typedInValue: string;
Expand All @@ -588,7 +568,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
_clearIconClicked?: boolean;
_focusedAfterClear: boolean;
_performTextSelection?: boolean;
_previewItem?: SuggestionListItem;
_isLatestValueFromSuggestions: boolean;
static i18nBundle: I18nBundle;

constructor() {
Expand All @@ -605,10 +585,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
// Represents the value before user moves selection between the suggestion items
// and its value remains the same when the user navigates up or down the list.
// Note: Used to cancel selection upon [Escape].
this.valueBeforeItemPreview = "";

// Indicates if the user selection has been canceled with [Escape].
this.suggestionSelectionCancelled = false;
this.valueBeforeSelectionStart = "";

// tracks the value between focus in and focus out to detect that change event should be fired.
this.previousValue = "";
Expand All @@ -628,6 +605,9 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
// Suggestions array initialization
this.suggestionObjects = [];

// Indicates whether the value of the input is comming from a suggestion item
this._isLatestValueFromSuggestions = false;

this._handleResizeBound = this._handleResize.bind(this);

this._keepInnerValue = false;
Expand Down Expand Up @@ -813,17 +793,21 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
const suggestionItemPressed = !!(this.Suggestions && this.Suggestions.onEnter(e));

const innerInput = this.getInputDOMRefSync()!;
let matchingIndex = -1;
// Check for autocompleted item
const matchingItem = this.suggestionItems.find(item => {
const matchingItem = this.suggestionItems.find((item, index) => {
matchingIndex = index;
return (item.text && item.text === this.value) || (item.textContent === this.value);
});

if (matchingItem) {
const itemText = matchingItem.text ? matchingItem.text : (matchingItem.textContent || "");
const listItem = this.Suggestions!._getItems()[matchingIndex]!;

innerInput.setSelectionRange(itemText.length, itemText.length);
if (!suggestionItemPressed) {
this.selectSuggestion(matchingItem, true);
this.fireSelectionChange(matchingItem, listItem, true);
this.acceptSuggestion(matchingItem, true);
this.open = false;
}
}
Expand Down Expand Up @@ -888,11 +872,8 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {

if (isOpen && this.Suggestions!._isItemOnTarget()) {
// Restore the value.
this.value = this.typedInValue || this.valueBeforeItemPreview;
this.value = this.typedInValue || this.valueBeforeSelectionStart;

// Mark that the selection has been cancelled, so the popover can close
// and not reopen, due to receiving focus.
this.suggestionSelectionCancelled = true;
this.focused = true;

return;
Expand All @@ -915,7 +896,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
this.previousValue = this.value;
}

this.valueBeforeItemPreview = this.value;
this.valueBeforeSelectionStart = this.value;
this._inputIconFocused = !!e.target && e.target === this.querySelector<Icon>("[ui5-icon]");
this._focusedAfterClear = false;
}
Expand Down Expand Up @@ -989,6 +970,7 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
this.value = "";
this.fireEvent<InputEventDetail>(INPUT_EVENTS.INPUT, { inputType: "" });
if (!this._isPhone) {
this.fireResetSelectionChange();
this.focus();
this._focusedAfterClear = true;
}
Expand Down Expand Up @@ -1030,7 +1012,6 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
];

this._shouldAutocomplete = !allowedEventTypes.includes(eventType) && !this.noTypeahead;
this.suggestionSelectionCancelled = false;

if (e instanceof InputEvent) {
// ---- Special cases of numeric Input ----
Expand Down Expand Up @@ -1225,26 +1206,19 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
}
}

selectSuggestion(item: IInputSuggestionItem, keyboardUsed: boolean) {
acceptSuggestion(item: IInputSuggestionItem, keyboardUsed: boolean) {
if (item.groupItem) {
return;
}

const value = this.typedInValue || this.value;
const itemText = item.text || item.textContent || ""; // keep textContent for compatibility
const fireInput = keyboardUsed
const fireChange = keyboardUsed
? this.valueBeforeItemSelection !== itemText : value !== itemText;

this.hasSuggestionItemSelected = true;

const valueOriginal = this.value;
const valueBeforeItemSelectionOriginal = this.valueBeforeItemSelection;
const lastConfirmedValueOriginal = this.lastConfirmedValue;
const performTextSelectionOriginal = this._performTextSelection;
const typedInValueOriginal = this.typedInValue;
const previousValueOriginal = this.previousValue;

if (fireInput) {
if (fireChange) {
this.value = itemText;
this.valueBeforeItemSelection = itemText;
this.lastConfirmedValue = itemText;
Expand All @@ -1253,77 +1227,30 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {

this.fireEvent(INPUT_EVENTS.CHANGE);

if (isPhone()) {
this.fireEvent(INPUT_EVENTS.INPUT);
}

// value might change in the change event handler
this.typedInValue = this.value;
this.previousValue = this.value;
}

this.valueBeforeItemPreview = "";
this.suggestionSelectionCancelled = false;

// Fire suggestion-item-select event after input change events for backward compatibility, but revert all input properties set before suggestion was prevented.
// For v2.0 this code will be reworked.
const isCancelledByUser = !this.fireEvent<InputSuggestionItemSelectEventDetail>(INPUT_EVENTS.SUGGESTION_ITEM_SELECT, { item }, true);

if (isCancelledByUser) {
this.Suggestions?._clearSelectedSuggestionAndAccInfo();
this.hasSuggestionItemSelected = false;
this.suggestionSelectionCancelled = true;

if (fireInput) {
// revert properties set during fireInput
if (itemText === this.value) { // If no chnages were made to the input value after suggestion-item-select was prevented - revert value to the original text
this.value = valueOriginal;
}
this.valueBeforeItemSelection = valueBeforeItemSelectionOriginal;
this.lastConfirmedValue = lastConfirmedValueOriginal;
this._performTextSelection = performTextSelectionOriginal;
this.typedInValue = typedInValueOriginal;
this.previousValue = previousValueOriginal;
}
}
this.valueBeforeSelectionStart = "";

this.isTyping = false;
this.openOnMobile = false;
this._forceOpen = false;
}

previewSuggestion(item: SuggestionListItem) {
this.valueBeforeItemSelection = this.value;
this.updateValueOnPreview(item);
this.announceSelectedItem();
this._previewItem = item;
}

/**
* Updates the input value on item preview.
* @param item The item that is on preview
* Updates the input value on item select.
* @param item The item that is on select
*/
updateValueOnPreview(item: SuggestionListItem) {
const noPreview = item.type === "Inactive" || item.groupItem;
const itemValue = noPreview ? this.valueBeforeItemPreview : (item.effectiveTitle || item.textContent || "");
updateValueOnSelect(item: SuggestionListItem) {
const nonSelectable = item.type === "Inactive" || item.groupItem;
const itemValue = nonSelectable ? this.valueBeforeSelectionStart : (item.effectiveTitle || item.textContent || "");

this.value = itemValue;
this._performTextSelection = true;
}

/**
* The suggestion item on preview.
* @default null
* @public
*/
get previewItem() : IInputSuggestionItem | null {
if (!this._previewItem) {
return null;
}

return this.getSuggestionByListItem(this._previewItem);
}

fireEventByAction(action: INPUT_ACTIONS, e: InputEvent) {
if (this.disabled || this.readonly) {
return;
Expand All @@ -1334,12 +1261,13 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {

this.value = inputValue;
this.typedInValue = inputValue;
this.valueBeforeItemPreview = inputValue;
this.valueBeforeSelectionStart = inputValue;

if (isUserInput) { // input
this.fireEvent<InputEventDetail>(INPUT_EVENTS.INPUT, { inputType: e.inputType });
// Angular two way data binding
this.fireEvent("value-changed");
this.fireResetSelectionChange();
}
}

Expand Down Expand Up @@ -1423,16 +1351,22 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
e.preventDefault();
}

onItemSelected(item: SuggestionItem, keyboardUsed: boolean) {
this.selectSuggestion(item, keyboardUsed);
onItemSelected(suggestionItem: SuggestionItem, listItem: SuggestionListItem | null, keyboardUsed: boolean) {
const shouldFireSelectionChange = !keyboardUsed && !listItem?.focused && this.valueBeforeItemSelection !== suggestionItem.text;

if (shouldFireSelectionChange) {
this.fireSelectionChange(suggestionItem, listItem, true);
}

this.acceptSuggestion(suggestionItem, keyboardUsed);
}

onItemPreviewed(item: SuggestionListItem) {
this.previewSuggestion(item);
this.fireEvent<InputSuggestionItemPreviewEventDetail>("suggestion-item-preview", {
item: this.getSuggestionByListItem(item),
targetRef: item,
});
onItemSelect(item: SuggestionListItem) {
this.valueBeforeItemSelection = this.value;
this.updateValueOnSelect(item);
this.announceSelectedItem();

this.fireSelectionChange(this.getSuggestionByListItem(item), item, true);
}

get valueStateTypeMappings() {
Expand All @@ -1459,6 +1393,19 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
invisibleText.textContent = this.itemSelectionAnnounce;
}

fireSelectionChange(item: IInputSuggestionItem | null, targetRef: SuggestionListItem | null, isValueFromSuggestions: boolean) {
if (this.Suggestions) {
this.fireEvent<InputSelectionChangeEventDetail>(INPUT_EVENTS.SELECTION_CHANGE, { item, targetRef });
this._isLatestValueFromSuggestions = isValueFromSuggestions;
}
}

fireResetSelectionChange() {
if (this._isLatestValueFromSuggestions) {
this.fireSelectionChange(null, null, false);
}
}

get _readonly() {
return this.readonly && !this.disabled;
}
Expand Down Expand Up @@ -1738,7 +1685,6 @@ export default Input;
export type {
IInputSuggestionItem,
InputSuggestionScrollEventDetail,
InputSuggestionItemSelectEventDetail,
InputSuggestionItemPreviewEventDetail,
InputSelectionChangeEventDetail,
InputEventDetail,
};
Loading

0 comments on commit 9f5c8a4

Please sign in to comment.