Skip to content

Commit 178f869

Browse files
authored
fix(ui5-search): align autocomplete with ui5-combobox (#12189)
* fix(ui5-search): align autocomplete with ui5-combobox Typeahead will autocomplete the text only to items that start with the typed text.
1 parent 174de61 commit 178f869

File tree

3 files changed

+7
-177
lines changed

3 files changed

+7
-177
lines changed

packages/fiori/cypress/specs/Search.cy.tsx

Lines changed: 1 addition & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -397,84 +397,6 @@ describe("Properties", () => {
397397
.should("have.value", "I");
398398
});
399399

400-
it("typeahead and value confirmation - autocomplete by contains", () => {
401-
cy.mount(
402-
<Search>
403-
<SearchItem text="Item 1" icon={history} />
404-
<SearchItem scopeName="Items" text="Item 2" selected />
405-
</Search>
406-
);
407-
408-
cy.get("[ui5-search]")
409-
.shadow()
410-
.find("input")
411-
.realClick();
412-
413-
cy.get("[ui5-search]")
414-
.should("be.focused");
415-
416-
cy.get("[ui5-search]")
417-
.realPress("2");
418-
419-
cy.get("[ui5-search]")
420-
.realPress("Enter");
421-
422-
cy.get("[ui5-search]")
423-
.should("have.value", "Item 2");
424-
});
425-
426-
it("typeahead and Arrow Right - autocomplete by contains", () => {
427-
cy.mount(
428-
<Search>
429-
<SearchItem text="Item 1" icon={history} />
430-
<SearchItem scopeName="Items" text="Item 2" selected />
431-
</Search>
432-
);
433-
434-
cy.get("[ui5-search]")
435-
.shadow()
436-
.find("input")
437-
.realClick();
438-
439-
cy.get("[ui5-search]")
440-
.should("be.focused");
441-
442-
cy.get("[ui5-search]")
443-
.realPress("2");
444-
445-
cy.get("[ui5-search]")
446-
.realPress("ArrowRight");
447-
448-
cy.get("[ui5-search]")
449-
.should("have.value", "2");
450-
});
451-
452-
it("typeahead and Escape - autocomplete by contains", () => {
453-
cy.mount(
454-
<Search>
455-
<SearchItem text="Item 1" icon={history} />
456-
<SearchItem scopeName="Items" text="Item 2" selected />
457-
</Search>
458-
);
459-
460-
cy.get("[ui5-search]")
461-
.shadow()
462-
.find("input")
463-
.realClick();
464-
465-
cy.get("[ui5-search]")
466-
.should("be.focused");
467-
468-
cy.get("[ui5-search]")
469-
.realPress("2");
470-
471-
cy.get("[ui5-search]")
472-
.realPress("Escape");
473-
474-
cy.get("[ui5-search]")
475-
.should("have.value", "2");
476-
});
477-
478400
it("Popup properties", () => {
479401
cy.mount(
480402
<Search>
@@ -566,7 +488,7 @@ describe("Properties", () => {
566488

567489
cy.realPress("I");
568490

569-
cy.get("[ui5-search-item]")
491+
cy.get("[ui5-search-item]")
570492
.eq(0)
571493
.realHover();
572494

@@ -700,43 +622,6 @@ describe("Events", () => {
700622
}));
701623
});
702624

703-
it("search event with autocomplete by contains", () => {
704-
const spy = cy.spy();
705-
cy.mount(
706-
<Search>
707-
<SearchItem text="Item 1" icon={history} />
708-
<SearchItem scopeName="Items" text="Item 2" selected />
709-
</Search>
710-
);
711-
712-
cy.get("[ui5-search]")
713-
.then(search => {
714-
search.get(0).addEventListener("ui5-search", spy);
715-
search.get(0).addEventListener("ui5-search", cy.stub().as("searched"));
716-
});
717-
718-
cy.get("[ui5-search]")
719-
.shadow()
720-
.find("input")
721-
.realClick();
722-
723-
cy.get("[ui5-search]")
724-
.should("be.focused");
725-
726-
cy.get("[ui5-search]")
727-
.realPress("2");
728-
729-
cy.get("[ui5-search]")
730-
.realPress("Enter");
731-
732-
cy.get("@searched")
733-
.should("have.been.calledOnce");
734-
735-
cy.wrap(spy).should("have.been.calledWithMatch", Cypress.sinon.match(event => {
736-
return event.detail.item.text === "Item 2";
737-
}));
738-
});
739-
740625
it("search event prevention", () => {
741626
cy.mount(
742627
<Search>

packages/fiori/src/Search.ts

Lines changed: 5 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ import {
1818
isPageDown,
1919
isHome,
2020
isEnd,
21-
isRight,
2221
isTabPrevious,
2322
} from "@ui5/webcomponents-base/dist/Keys.js";
2423

2524
import SearchTemplate from "./SearchTemplate.js";
2625
import SearchCss from "./generated/themes/Search.css.js";
2726
import SearchField from "./SearchField.js";
28-
import { StartsWith, StartsWithPerTerm } from "@ui5/webcomponents/dist/Filters.js";
27+
import { StartsWith } from "@ui5/webcomponents/dist/Filters.js";
2928
import type UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
3029
import type SearchItem from "./SearchItem.js";
3130
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
@@ -208,12 +207,6 @@ class Search extends SearchField {
208207
*/
209208
_valueBeforeOpen: string;
210209

211-
/**
212-
* True if the first matching item is matched by starts with per term, rather than by starts with.
213-
* @private
214-
*/
215-
_matchedPerTerm: boolean;
216-
217210
/**
218211
* Holds the currently proposed item which will be selected if the user presses Enter.
219212
* @private
@@ -228,7 +221,6 @@ class Search extends SearchField {
228221

229222
// The typed in value.
230223
this._typedInValue = "";
231-
this._matchedPerTerm = false;
232224
this._valueBeforeOpen = this.getAttribute("value") || "";
233225
}
234226

@@ -317,29 +309,17 @@ class Search extends SearchField {
317309

318310
_handleTypeAhead(item: ISearchSuggestionItem) {
319311
const originalValue = item.text || "";
320-
let displayValue = originalValue;
321-
322-
if (!originalValue.toLowerCase().startsWith(this.value.toLowerCase())) {
323-
this._matchedPerTerm = true;
324-
displayValue = `${this.value} - ${originalValue}`;
325-
} else {
326-
this._matchedPerTerm = false;
327-
}
328312

329313
this._typedInValue = this.value;
330-
this._innerValue = displayValue;
314+
this._innerValue = originalValue;
331315
this._performTextSelection = true;
332-
this.value = displayValue;
316+
this.value = originalValue;
333317
}
334318

335319
_startsWithMatchingItems(str: string): Array<ISearchSuggestionItem> {
336320
return StartsWith(str, this._flattenItems.filter(item => !this._isGroupItem(item) && !this._isShowMoreItem(item)), "text");
337321
}
338322

339-
_startsWithPerTermMatchingItems(str: string): Array<ISearchSuggestionItem> {
340-
return StartsWithPerTerm(str, this._flattenItems.filter(item => !this._isGroupItem(item) && !this._isShowMoreItem(item)), "text");
341-
}
342-
343323
_isGroupItem(item: HTMLElement): item is SearchItemGroup {
344324
return item.hasAttribute("ui5-search-item-group");
345325
}
@@ -374,15 +354,6 @@ class Search extends SearchField {
374354
}
375355
}
376356

377-
_handleRight(e: KeyboardEvent) {
378-
if (this._matchedPerTerm) {
379-
e.preventDefault();
380-
this.value = this._typedInValue;
381-
this._innerValue = this._typedInValue;
382-
this._proposedItem = undefined;
383-
}
384-
}
385-
386357
_handleInnerClick() {
387358
if (isPhone()) {
388359
this.open = true;
@@ -405,12 +376,6 @@ class Search extends SearchField {
405376
}
406377

407378
const innerInput = this.nativeInput!;
408-
if (this._matchedPerTerm) {
409-
this.value = this._proposedItem?.text || this.value;
410-
this._innerValue = this.value;
411-
this._typedInValue = this.value;
412-
this._matchedPerTerm = false;
413-
}
414379

415380
innerInput.setSelectionRange(this.value.length, this.value.length);
416381
this.open = false;
@@ -510,10 +475,6 @@ class Search extends SearchField {
510475
this._shouldAutocomplete = !this.noTypeahead
511476
&& !(isBackSpace(e) || isDelete(e) || isEscape(e) || isUp(e) || isDown(e) || isTabNext(e) || isEnter(e) || isPageUp(e) || isPageDown(e) || isHome(e) || isEnd(e) || isEscape(e));
512477

513-
if (isRight(e)) {
514-
this._handleRight(e);
515-
}
516-
517478
if (isDown(e)) {
518479
this._handleDown(e);
519480
}
@@ -523,15 +484,6 @@ class Search extends SearchField {
523484
}
524485
}
525486

526-
_onfocusout() {
527-
super._onfocusout();
528-
if (this._matchedPerTerm) {
529-
this.value = this._typedInValue;
530-
this._innerValue = this._typedInValue;
531-
}
532-
this._matchedPerTerm = false;
533-
}
534-
535487
_onFocusOutSearch(e:FocusEvent) {
536488
const target = e.relatedTarget as HTMLElement;
537489

@@ -587,19 +539,12 @@ class Search extends SearchField {
587539
}
588540

589541
const startsWithMatches = this._startsWithMatchingItems(current);
590-
const partialMatches = this._startsWithPerTermMatchingItems(current);
591542

592543
if (!startsWithMatches.length) {
593-
return partialMatches[0] ?? undefined;
594-
}
595-
596-
if (!partialMatches.length) {
597-
return startsWithMatches[0];
544+
return undefined;
598545
}
599546

600-
return this._flattenItems.indexOf(startsWithMatches[0]) <= this._flattenItems.indexOf(partialMatches[0])
601-
? startsWithMatches[0]
602-
: partialMatches[0];
547+
return startsWithMatches[0];
603548
}
604549

605550
_getPicker() {

packages/fiori/test/pages/Search.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
<div class="container" style="padding-top: 1rem;">
175175
<ui5-label>Search with Suggestions - Filter by typing</ui5-label>
176176
<ui5-search id="filtering" show-clear-icon placeholder="Start typing ..."></ui5-search>
177-
<ui5-text style="padding-top: 0.25rem; font-style: italic;">The examples shows filtering per user input, highlighting user input and showcases "contains" and "starts with" typeahead. Type "a" to see "contains typeahead" or "t" to see "starts with typeahead"</ui5-text>
177+
<ui5-text style="padding-top: 0.25rem; font-style: italic;">The examples shows filtering per user input and highlighting user input. Type "a" to see highlighting. Type "t" to see "typeahead"</ui5-text>
178178
</div>
179179

180180
<div class="container" style="padding-top: 1rem;">

0 commit comments

Comments
 (0)