Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 133 additions & 2 deletions packages/fiori/cypress/specs/Search.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Button from "@ui5/webcomponents/dist/Button.js";
import ButtonDesign from "@ui5/webcomponents/dist/types/ButtonDesign.js";
import Avatar from "@ui5/webcomponents/dist/Avatar.js";
import AvatarSize from "@ui5/webcomponents/dist/types/AvatarSize.js";
import type ResponsivePopover from "@ui5/webcomponents/dist/ResponsivePopover.js";
import { SEARCH_ITEM_SHOW_MORE_COUNT, SEARCH_ITEM_SHOW_MORE_NO_COUNT } from "../../src/generated/i18n/i18n-defaults.js";

describe("Properties", () => {
Expand Down Expand Up @@ -791,7 +792,7 @@ describe("Events", () => {

cy.get("[ui5-search]")
.then(search => {
search.get(0).addEventListener("ui5-close", cy.stub().as("closed"));
search.get(0).addEventListener("ui5-close", cy.spy().as("closed"));
});

cy.get("[ui5-search]")
Expand All @@ -818,7 +819,7 @@ describe("Events", () => {

cy.get("[ui5-search]")
.then(search => {
search.get(0).addEventListener("ui5-close", cy.stub().as("closed"));
search.get(0).addEventListener("ui5-close", cy.spy().as("closed"));
});

cy.get("[ui5-search]")
Expand Down Expand Up @@ -959,6 +960,136 @@ describe("Events", () => {
cy.get("ui5-search-item").eq(0)
.should("not.have.attr", "selected");
});

it("should reset suggestions highlight on pressing 'clear' button", () => {
cy.mount(
<Search showClearIcon>
<SearchItem text="Item 1" />
</Search>
);

cy.get("[ui5-search]").as("search");

cy.get("@search")
.shadow()
.find("input")
.as("input");

cy.get("@input")
.realClick();

cy.get("@search")
.should("be.focused");

cy.get("@input")
.realPress("I");

cy.get("@search")
.should("have.value", "Item 1");

cy.get("[ui5-search-item]").eq(0)
.should("have.attr", "highlight-text", "I");

cy.get("@search")
.shadow()
.find("[ui5-icon][name='decline']")
.realClick();

cy.get("@search")
.should("have.value", "");

cy.get("@search")
.should("not.have.attr", "open");

cy.get("@search")
.invoke("prop", "open", true);

cy.get("ui5-search-item").eq(0)
.should("have.attr", "highlight-text", "");
});

it("should close the popover on search if no suggestion is selected", () => {
cy.mount(
<Search showClearIcon>
<SearchItem text="Item 1" />
</Search>
);

cy.get("[ui5-search]").as("search");

cy.get("@search")
.shadow()
.find("input")
.as("input");

cy.get("@input")
.realClick();

cy.get("@search")
.should("be.focused");

cy.get("@input")
.realPress("P"); // no matching suggestion

cy.get("@search")
.should("have.value", "P");

cy.get("@search")
.shadow()
.find("[ui5-icon][name='search']")
.realClick();

cy.get("@search")
.should("not.have.attr", "open");
});

it("should close the popover on 'search' if suggestion is selected", () => {
cy.mount(
<Search showClearIcon>
<SearchItem text="Item 1" />
</Search>
);

cy.get("[ui5-search]").as("search");

cy.get("@search")
.shadow()
.find("input")
.as("input");

cy.get("@input")
.realClick();

cy.get("@search")
.should("be.focused");

cy.get("@input")
.realPress("I"); // no matching suggestion

cy.get("@search")
.should("have.value", "Item 1");

cy.get("@search")
.shadow()
.find("[ui5-icon][name='search']")
.realClick();

cy.get("@search")
.should("not.have.attr", "open");
});

it("should open picker by default when 'open' property is set to true", () => {
cy.mount(
<Search open>
<SearchItem text="Item 1" />
</Search>
);

cy.get("[ui5-search]")
.shadow()
.find<ResponsivePopover>("[ui5-responsive-popover]")
.ui5ResponsivePopoverOpened();
});
});

describe("Accessibility", () => {
Expand Down
40 changes: 33 additions & 7 deletions packages/fiori/src/Search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ class Search extends SearchField {
*/
_proposedItem?: ISearchSuggestionItem;

/**
* This property is used during rendering to indicate that the user has started typing in the input
* @private
*/
_isTyping: boolean;

@i18n("@ui5/webcomponents-fiori")
static i18nBundle: I18nBundle;

Expand All @@ -222,26 +228,32 @@ class Search extends SearchField {
// The typed in value.
this._typedInValue = "";
this._valueBeforeOpen = this.getAttribute("value") || "";
this._isTyping = false;
}

onBeforeRendering() {
super.onBeforeRendering();

if (this.collapsed && !isPhone()) {
this.open = false;
return;
}

const innerInput = this.nativeInput;
const autoCompletedChars = innerInput && (innerInput.selectionEnd! - innerInput.selectionStart!);

this.open = this.open || (this._popoupHasAnyContent() && this._isTyping && innerInput!.value.length > 0);

// If there is already a selection the autocomplete has already been performed
if (this._shouldAutocomplete && !autoCompletedChars) {
const item = this._getFirstMatchingItem(this.value);
this._proposedItem = item;

if (!isPhone()) {
this.open = this._popoupHasAnyContent();
}

if (item) {
this._handleTypeAhead(item);
this._selectMatchingItem(item);
} else {
this._deselectItems();
}
}

Expand Down Expand Up @@ -311,8 +323,6 @@ class Search extends SearchField {
this._innerValue = originalValue;
this._performTextSelection = true;
this.value = originalValue;

this._shouldAutocomplete = false;
}

_startsWithMatchingItems(str: string): Array<ISearchSuggestionItem> {
Expand Down Expand Up @@ -383,6 +393,7 @@ class Search extends SearchField {

innerInput.setSelectionRange(this.value.length, this.value.length);
this.open = false;
this._isTyping = false;
}

_onMobileInputKeydown(e: KeyboardEvent) {
Expand All @@ -401,6 +412,7 @@ class Search extends SearchField {
_handleEscape() {
this.value = this._typedInValue || this.value;
this._innerValue = this.value;
this._isTyping = false;
}

_handleInput(e: InputEvent) {
Expand All @@ -411,7 +423,16 @@ class Search extends SearchField {
return;
}

this.open = ((e.currentTarget as HTMLInputElement).value.length > 0) && this._popoupHasAnyContent();
this._isTyping = true;
}

_handleClear(): void {
super._handleClear();

this._typedInValue = "";
this._innerValue = "";
this._shouldAutocomplete = false;
this.open = false;
}

_popoupHasAnyContent() {
Expand Down Expand Up @@ -466,7 +487,10 @@ class Search extends SearchField {
this.value = item.text;
this._innerValue = this.value;
this._typedInValue = this.value;
this._shouldAutocomplete = false;
this._performTextSelection = true;
this.open = false;
this._isTyping = false;
this.focus();
}

Expand Down Expand Up @@ -502,6 +526,7 @@ class Search extends SearchField {
}

this.open = false;
this._isTyping = false;
}

_handleBeforeClose(e: CustomEvent<PopupBeforeCloseEventDetail>) {
Expand All @@ -518,6 +543,7 @@ class Search extends SearchField {

_handleClose() {
this.open = false;
this._isTyping = false;
this.fireDecoratorEvent("close");
}

Expand Down
39 changes: 22 additions & 17 deletions packages/fiori/test/pages/Search.html
Original file line number Diff line number Diff line change
Expand Up @@ -411,24 +411,29 @@

const searchLazy = document.getElementById('search-lazy');
searchLazy.addEventListener('ui5-input', (e) => {
// clear search items
searchLazy.innerHTML = '';

searchLazy.getSlottedNodes("items").forEach(item => {
item.remove();
});

// simulate lazy loading
setTimeout(() => {
const lazyData = [
{ name: 'Red Apple', category: 'Fruit' },
{ name: 'Apple', category: 'Fruit' },
{ name: 'Banana', category: 'Fruit' },
{ name: 'Orange', category: 'Fruit' },
{ name: 'Grapes', category: 'Fruit' },
];
createItems(searchLazy, lazyData);
}, 100);
// clear search items
searchLazy.innerHTML = '';

searchLazy.getSlottedNodes("items").forEach(item => {
item.remove();
});
}, 100)


if(e.target.value.length){
// simulate lazy loading
setTimeout(() => {
const lazyData = [
{ name: `Red Apple ${Math.random()}`, category: 'Fruit' },
{ name: `Apple ${Math.random()}`, category: 'Fruit' },
{ name: `Banana ${Math.random()}`, category: 'Fruit' },
{ name: `Orange ${Math.random()}`, category: 'Fruit' },
{ name: `Grapes ${Math.random()}`, category: 'Fruit' },
];
createItems(searchLazy, lazyData);
}, 300);
}
});
</script>
</body>
Expand Down
Loading