From 86b42906247efce7e041b88472b85dd4f73cc414 Mon Sep 17 00:00:00 2001 From: LuLaValva <lukelavalva@gmail.com> Date: Tue, 19 Nov 2024 11:03:23 -0800 Subject: [PATCH 1/7] feat(filter-menu): search header --- src/components/ebay-filter-menu/component.ts | 28 +- .../ebay-filter-menu/examples/data.json | 974 ++++++++++++++++++ .../examples/with-search.marko | 31 + .../ebay-filter-menu/filter-menu.stories.ts | 45 +- src/components/ebay-filter-menu/index.marko | 23 +- 5 files changed, 1088 insertions(+), 13 deletions(-) create mode 100644 src/components/ebay-filter-menu/examples/data.json create mode 100644 src/components/ebay-filter-menu/examples/with-search.marko diff --git a/src/components/ebay-filter-menu/component.ts b/src/components/ebay-filter-menu/component.ts index f1562b95c..8c438ed0f 100644 --- a/src/components/ebay-filter-menu/component.ts +++ b/src/components/ebay-filter-menu/component.ts @@ -34,16 +34,23 @@ interface FilterMenuInput "a11y-footer-text"?: AttrString; } >; + "search-header-placeholder-text"?: string; + "a11y-search-header-clear-text"?: string; "render-body"?: Marko.Body; "on-footer-click"?: (event: FilterMenuEvent) => void; "on-form-submit"?: (event: FilterMenuEvent) => void; "on-change"?: (event: FilterMenuEvent) => void; "on-keydown"?: (event: FilterMenuEvent) => void; + "on-search-change"?: (value: string) => void; } export interface Input extends WithNormalizedProps<FilterMenuInput> {} -export default class extends MenuUtils<Input, MenuState> { +export interface State extends MenuState { + searchTerm?: string; +} + +export default class extends MenuUtils<Input, State> { declare _rovingTabIndex: ReturnType<typeof createLinear>; declare lastTabIndexPosition: number; @@ -56,6 +63,16 @@ export default class extends MenuUtils<Input, MenuState> { this.lastTabIndexPosition = 0; } + handleSearch(e: InputEvent) { + this.state.searchTerm = (e.target as HTMLInputElement).value; + this.emit("search-change", this.state.searchTerm); + } + + clearSearch() { + this.state.searchTerm = ""; + this.emit("search-change", this.state.searchTerm); + } + handleRadioClick(index: number, ev: RadioEvent, itemEl: Element) { this._toggleItemChecked(index, ev.originalEvent, itemEl); } @@ -102,7 +119,10 @@ export default class extends MenuUtils<Input, MenuState> { } onInput(input: Input) { - this.state = super.getInputState(input); + this.state = { + ...super.getInputState(input), + searchTerm: this.state ? this.state.searchTerm : "", + }; } onMount() { @@ -158,7 +178,7 @@ export default class extends MenuUtils<Input, MenuState> { autoInit: this.lastTabIndexPosition || "interactive", }); - scrollKeyPreventer.add(this.getEl("container")); + scrollKeyPreventer.add(this.getEl("menu")); } } @@ -167,7 +187,7 @@ export default class extends MenuUtils<Input, MenuState> { this.lastTabIndexPosition = this._rovingTabIndex.index; this._rovingTabIndex.destroy(); this._rovingTabIndex = undefined; - scrollKeyPreventer.remove(this.getEl("container")); + scrollKeyPreventer.remove(this.getEl("menu")); } } } diff --git a/src/components/ebay-filter-menu/examples/data.json b/src/components/ebay-filter-menu/examples/data.json new file mode 100644 index 000000000..6de354b55 --- /dev/null +++ b/src/components/ebay-filter-menu/examples/data.json @@ -0,0 +1,974 @@ +[ + { + "name": "Afghanistan", + "code": "AF" + }, + { + "name": "Ã…landIslands", + "code": "AX" + }, + { + "name": "Albania", + "code": "AL" + }, + { + "name": "Algeria", + "code": "DZ" + }, + { + "name": "AmericanSamoa", + "code": "AS" + }, + { + "name": "AndorrA", + "code": "AD" + }, + { + "name": "Angola", + "code": "AO" + }, + { + "name": "Anguilla", + "code": "AI" + }, + { + "name": "Antarctica", + "code": "AQ" + }, + { + "name": "Antiguaand Barbuda", + "code": "AG" + }, + { + "name": "Argentina", + "code": "AR" + }, + { + "name": "Armenia", + "code": "AM" + }, + { + "name": "Aruba", + "code": "AW" + }, + { + "name": "Australia", + "code": "AU" + }, + { + "name": "Austria", + "code": "AT" + }, + { + "name": "Azerbaijan", + "code": "AZ" + }, + { + "name": "Bahamas", + "code": "BS" + }, + { + "name": "Bahrain", + "code": "BH" + }, + { + "name": "Bangladesh", + "code": "BD" + }, + { + "name": "Barbados", + "code": "BB" + }, + { + "name": "Belarus", + "code": "BY" + }, + { + "name": "Belgium", + "code": "BE" + }, + { + "name": "Belize", + "code": "BZ" + }, + { + "name": "Benin", + "code": "BJ" + }, + { + "name": "Bermuda", + "code": "BM" + }, + { + "name": "Bhutan", + "code": "BT" + }, + { + "name": "Bolivia", + "code": "BO" + }, + { + "name": "Bosniaand Herzegovina", + "code": "BA" + }, + { + "name": "Botswana", + "code": "BW" + }, + { + "name": "BouvetIsland", + "code": "BV" + }, + { + "name": "Brazil", + "code": "BR" + }, + { + "name": "BritishIndian Ocean Territory", + "code": "IO" + }, + { + "name": "BruneiDarussalam", + "code": "BN" + }, + { + "name": "Bulgaria", + "code": "BG" + }, + { + "name": "BurkinaFaso", + "code": "BF" + }, + { + "name": "Burundi", + "code": "BI" + }, + { + "name": "Cambodia", + "code": "KH" + }, + { + "name": "Cameroon", + "code": "CM" + }, + { + "name": "Canada", + "code": "CA" + }, + { + "name": "CapeVerde", + "code": "CV" + }, + { + "name": "CaymanIslands", + "code": "KY" + }, + { + "name": "CentralAfrican Republic", + "code": "CF" + }, + { + "name": "Chad", + "code": "TD" + }, + { + "name": "Chile", + "code": "CL" + }, + { + "name": "China", + "code": "CN" + }, + { + "name": "ChristmasIsland", + "code": "CX" + }, + { + "name": "Cocos(Keeling) Islands", + "code": "CC" + }, + { + "name": "Colombia", + "code": "CO" + }, + { + "name": "Comoros", + "code": "KM" + }, + { + "name": "Congo", + "code": "CG" + }, + { + "name": "Congo The Democratic Republic of the", + "code": "CD" + }, + { + "name": "CookIslands", + "code": "CK" + }, + { + "name": "CostaRica", + "code": "CR" + }, + { + "name": "CoteD'Ivoire", + "code": "CI" + }, + { + "name": "Croatia", + "code": "HR" + }, + { + "name": "Cuba", + "code": "CU" + }, + { + "name": "Cyprus", + "code": "CY" + }, + { + "name": "CzechRepublic", + "code": "CZ" + }, + { + "name": "Denmark", + "code": "DK" + }, + { + "name": "Djibouti", + "code": "DJ" + }, + { + "name": "Dominica", + "code": "DM" + }, + { + "name": "DominicanRepublic", + "code": "DO" + }, + { + "name": "Ecuador", + "code": "EC" + }, + { + "name": "Egypt", + "code": "EG" + }, + { + "name": "ElSalvador", + "code": "SV" + }, + { + "name": "EquatorialGuinea", + "code": "GQ" + }, + { + "name": "Eritrea", + "code": "ER" + }, + { + "name": "Estonia", + "code": "EE" + }, + { + "name": "Ethiopia", + "code": "ET" + }, + { + "name": "FalklandIslands (Malvinas)", + "code": "FK" + }, + { + "name": "FaroeIslands", + "code": "FO" + }, + { + "name": "Fiji", + "code": "FJ" + }, + { + "name": "Finland", + "code": "FI" + }, + { + "name": "France", + "code": "FR" + }, + { + "name": "FrenchGuiana", + "code": "GF" + }, + { + "name": "FrenchPolynesia", + "code": "PF" + }, + { + "name": "FrenchSouthern Territories", + "code": "TF" + }, + { + "name": "Gabon", + "code": "GA" + }, + { + "name": "Gambia", + "code": "GM" + }, + { + "name": "Georgia", + "code": "GE" + }, + { + "name": "Germany", + "code": "DE" + }, + { + "name": "Ghana", + "code": "GH" + }, + { + "name": "Gibraltar", + "code": "GI" + }, + { + "name": "Greece", + "code": "GR" + }, + { + "name": "Greenland", + "code": "GL" + }, + { + "name": "Grenada", + "code": "GD" + }, + { + "name": "Guadeloupe", + "code": "GP" + }, + { + "name": "Guam", + "code": "GU" + }, + { + "name": "Guatemala", + "code": "GT" + }, + { + "name": "Guernsey", + "code": "GG" + }, + { + "name": "Guinea", + "code": "GN" + }, + { + "name": "GuineaBissau", + "code": "GW" + }, + { + "name": "Guyana", + "code": "GY" + }, + { + "name": "Haiti", + "code": "HT" + }, + { + "name": "HeardIsland and Mcdonald Islands", + "code": "HM" + }, + { + "name": "HolySee (Vatican City State)", + "code": "VA" + }, + { + "name": "Honduras", + "code": "HN" + }, + { + "name": "HongKong", + "code": "HK" + }, + { + "name": "Hungary", + "code": "HU" + }, + { + "name": "Iceland", + "code": "IS" + }, + { + "name": "India", + "code": "IN" + }, + { + "name": "Indonesia", + "code": "ID" + }, + { + "name": "Iran Islamic Republic Of", + "code": "IR" + }, + { + "name": "Iraq", + "code": "IQ" + }, + { + "name": "Ireland", + "code": "IE" + }, + { + "name": "Isleof Man", + "code": "IM" + }, + { + "name": "Israel", + "code": "IL" + }, + { + "name": "Italy", + "code": "IT" + }, + { + "name": "Jamaica", + "code": "JM" + }, + { + "name": "Japan", + "code": "JP" + }, + { + "name": "Jersey", + "code": "JE" + }, + { + "name": "Jordan", + "code": "JO" + }, + { + "name": "Kazakhstan", + "code": "KZ" + }, + { + "name": "Kenya", + "code": "KE" + }, + { + "name": "Kiribati", + "code": "KI" + }, + { + "name": "Korea Democratic People'S Republic of", + "code": "KP" + }, + { + "name": "Korea Republic of", + "code": "KR" + }, + { + "name": "Kuwait", + "code": "KW" + }, + { + "name": "Kyrgyzstan", + "code": "KG" + }, + { + "name": "LaoPeopleS Democratic Republic", + "code": "LA" + }, + { + "name": "Latvia", + "code": "LV" + }, + { + "name": "Lebanon", + "code": "LB" + }, + { + "name": "Lesotho", + "code": "LS" + }, + { + "name": "Liberia", + "code": "LR" + }, + { + "name": "LibyanArab Jamahiriya", + "code": "LY" + }, + { + "name": "Liechtenstein", + "code": "LI" + }, + { + "name": "Lithuania", + "code": "LT" + }, + { + "name": "Luxembourg", + "code": "LU" + }, + { + "name": "Macao", + "code": "MO" + }, + { + "name": "Macedonia The Former Yugoslav Republic of", + "code": "MK" + }, + { + "name": "Madagascar", + "code": "MG" + }, + { + "name": "Malawi", + "code": "MW" + }, + { + "name": "Malaysia", + "code": "MY" + }, + { + "name": "Maldives", + "code": "MV" + }, + { + "name": "Mali", + "code": "ML" + }, + { + "name": "Malta", + "code": "MT" + }, + { + "name": "MarshallIslands", + "code": "MH" + }, + { + "name": "Martinique", + "code": "MQ" + }, + { + "name": "Mauritania", + "code": "MR" + }, + { + "name": "Mauritius", + "code": "MU" + }, + { + "name": "Mayotte", + "code": "YT" + }, + { + "name": "Mexico", + "code": "MX" + }, + { + "name": "Micronesia Federated States of", + "code": "FM" + }, + { + "name": "Moldova Republic of", + "code": "MD" + }, + { + "name": "Monaco", + "code": "MC" + }, + { + "name": "Mongolia", + "code": "MN" + }, + { + "name": "Montserrat", + "code": "MS" + }, + { + "name": "Morocco", + "code": "MA" + }, + { + "name": "Mozambique", + "code": "MZ" + }, + { + "name": "Myanmar", + "code": "MM" + }, + { + "name": "Namibia", + "code": "NA" + }, + { + "name": "Nauru", + "code": "NR" + }, + { + "name": "Nepal", + "code": "NP" + }, + { + "name": "Netherlands", + "code": "NL" + }, + { + "name": "NetherlandsAntilles", + "code": "AN" + }, + { + "name": "NewCaledonia", + "code": "NC" + }, + { + "name": "NewZealand", + "code": "NZ" + }, + { + "name": "Nicaragua", + "code": "NI" + }, + { + "name": "Niger", + "code": "NE" + }, + { + "name": "Nigeria", + "code": "NG" + }, + { + "name": "Niue", + "code": "NU" + }, + { + "name": "NorfolkIsland", + "code": "NF" + }, + { + "name": "NorthernMariana Islands", + "code": "MP" + }, + { + "name": "Norway", + "code": "NO" + }, + { + "name": "Oman", + "code": "OM" + }, + { + "name": "Pakistan", + "code": "PK" + }, + { + "name": "Palau", + "code": "PW" + }, + { + "name": "PalestinianTerritory Occupied", + "code": "PS" + }, + { + "name": "Panama", + "code": "PA" + }, + { + "name": "PapuaNew Guinea", + "code": "PG" + }, + { + "name": "Paraguay", + "code": "PY" + }, + { + "name": "Peru", + "code": "PE" + }, + { + "name": "Philippines", + "code": "PH" + }, + { + "name": "Pitcairn", + "code": "PN" + }, + { + "name": "Poland", + "code": "PL" + }, + { + "name": "Portugal", + "code": "PT" + }, + { + "name": "PuertoRico", + "code": "PR" + }, + { + "name": "Qatar", + "code": "QA" + }, + { + "name": "Reunion", + "code": "RE" + }, + { + "name": "Romania", + "code": "RO" + }, + { + "name": "RussianFederation", + "code": "RU" + }, + { + "name": "RWANDA", + "code": "RW" + }, + { + "name": "SaintHelena", + "code": "SH" + }, + { + "name": "SaintKitts and Nevis", + "code": "KN" + }, + { + "name": "SaintLucia", + "code": "LC" + }, + { + "name": "SaintPierre and Miquelon", + "code": "PM" + }, + { + "name": "SaintVincent and the Grenadines", + "code": "VC" + }, + { + "name": "Samoa", + "code": "WS" + }, + { + "name": "SanMarino", + "code": "SM" + }, + { + "name": "SaoTome and Principe", + "code": "ST" + }, + { + "name": "SaudiArabia", + "code": "SA" + }, + { + "name": "Senegal", + "code": "SN" + }, + { + "name": "Serbiaand Montenegro", + "code": "CS" + }, + { + "name": "Seychelles", + "code": "SC" + }, + { + "name": "SierraLeone", + "code": "SL" + }, + { + "name": "Singapore", + "code": "SG" + }, + { + "name": "Slovakia", + "code": "SK" + }, + { + "name": "Slovenia", + "code": "SI" + }, + { + "name": "SolomonIslands", + "code": "SB" + }, + { + "name": "Somalia", + "code": "SO" + }, + { + "name": "SouthAfrica", + "code": "ZA" + }, + { + "name": "SouthGeorgia and the South Sandwich Islands", + "code": "GS" + }, + { + "name": "Spain", + "code": "ES" + }, + { + "name": "SriLanka", + "code": "LK" + }, + { + "name": "Sudan", + "code": "SD" + }, + { + "name": "Suriname", + "code": "SR" + }, + { + "name": "Svalbardand Jan Mayen", + "code": "SJ" + }, + { + "name": "Swaziland", + "code": "SZ" + }, + { + "name": "Sweden", + "code": "SE" + }, + { + "name": "Switzerland", + "code": "CH" + }, + { + "name": "SyrianArab Republic", + "code": "SY" + }, + { + "name": "Taiwan Province of China", + "code": "TW" + }, + { + "name": "Tajikistan", + "code": "TJ" + }, + { + "name": "Tanzania United Republic of", + "code": "TZ" + }, + { + "name": "Thailand", + "code": "TH" + }, + { + "name": "TimorLeste", + "code": "TL" + }, + { + "name": "Togo", + "code": "TG" + }, + { + "name": "Tokelau", + "code": "TK" + }, + { + "name": "Tonga", + "code": "TO" + }, + { + "name": "Trinidadand Tobago", + "code": "TT" + }, + { + "name": "Tunisia", + "code": "TN" + }, + { + "name": "Turkey", + "code": "TR" + }, + { + "name": "Turkmenistan", + "code": "TM" + }, + { + "name": "Turksand Caicos Islands", + "code": "TC" + }, + { + "name": "Tuvalu", + "code": "TV" + }, + { + "name": "Uganda", + "code": "UG" + }, + { + "name": "Ukraine", + "code": "UA" + }, + { + "name": "UnitedArab Emirates", + "code": "AE" + }, + { + "name": "UnitedKingdom", + "code": "GB" + }, + { + "name": "United States", + "code": "US" + }, + { + "name": "United States Minor Outlying Islands", + "code": "UM" + }, + { + "name": "Uruguay", + "code": "UY" + }, + { + "name": "Uzbekistan", + "code": "UZ" + }, + { + "name": "Vanuatu", + "code": "VU" + }, + { + "name": "Venezuela", + "code": "VE" + }, + { + "name": "VietNam", + "code": "VN" + }, + { + "name": "VirginIslands British", + "code": "VG" + }, + { + "name": "VirginIslands U.S.", + "code": "VI" + }, + { + "name": "Wallisand Futuna", + "code": "WF" + }, + { + "name": "WesternSahara", + "code": "EH" + }, + { + "name": "Yemen", + "code": "YE" + }, + { + "name": "Zambia", + "code": "ZM" + }, + { + "name": "Zimbabwe", + "code": "ZW" + } +] diff --git a/src/components/ebay-filter-menu/examples/with-search.marko b/src/components/ebay-filter-menu/examples/with-search.marko new file mode 100644 index 000000000..085131f43 --- /dev/null +++ b/src/components/ebay-filter-menu/examples/with-search.marko @@ -0,0 +1,31 @@ +import countries from "./data.json"; +class { + declare state: { + searchTerm: string; + }; + + onCreate() { + this.state = { + searchTerm: "", + }; + } + + handleSearchChange(value: string) { + this.state.searchTerm = value.toLowerCase(); + } +} + +<ebay-filter-menu + search-header-placeholder-text="Search" + a11y-search-header-clear-text="Clear" + on-search-change("handleSearchChange") + ...input +> + <for|{ name, code }| of=countries> + <if(name.toLowerCase().includes(state.searchTerm))> + <@item value=code> + ${name} + </@item> + </if> + </for> +</ebay-filter-menu> diff --git a/src/components/ebay-filter-menu/filter-menu.stories.ts b/src/components/ebay-filter-menu/filter-menu.stories.ts index 3e0f06383..920532123 100644 --- a/src/components/ebay-filter-menu/filter-menu.stories.ts +++ b/src/components/ebay-filter-menu/filter-menu.stories.ts @@ -1,9 +1,14 @@ import { Story } from "@storybook/marko"; import { tagToString } from "../../common/storybook/storybook-code-source"; -import { addRenderBodies } from "../../common/storybook/utils"; +import { + addRenderBodies, + buildExtensionTemplate, +} from "../../common/storybook/utils"; import Readme from "./README.md"; import Component from "./index.marko"; import type { Input } from "./component"; +import WithSearchTemplate from "./examples/with-search.marko"; +import WithSearchCode from "./examples/with-search.marko?raw"; const Template: Story<Input> = (args) => ({ input: addRenderBodies(args), @@ -47,6 +52,15 @@ export default { control: { type: "text" }, description: "forms `method` attribute", }, + searchHeaderPlaceholderText: { + control: { type: "text" }, + description: + "enables the search header and populates placeholder text. `a11y-search-header-clear-text` is required if this is enabled.", + }, + a11ySearchHeaderClearText: { + control: { type: "text" }, + description: "a11y text for the search header clear button", + }, item: { table: { category: "@attribute tags", @@ -74,6 +88,12 @@ export default { control: { type: "boolean" }, description: "whether or not the item is disabled", }, + footer: { + name: "@footer", + table: { + category: "@attribute tags", + }, + }, onChange: { action: "on-change", description: "Triggered on item clicked", @@ -96,8 +116,7 @@ export default { }, }, }, - - footerClick: { + "onFooter-click": { action: "on-footer-click", description: "Triggered on footer clicked", table: { @@ -107,10 +126,10 @@ export default { }, }, }, - formSubmit: { + "onForm-submit": { action: "on-form-submit", description: - 'when using `variant="form"`, and form is submitted (emits current checked state)', + 'Triggered when using `variant="form"`, and form is submitted (emits current checked state)', table: { category: "Events", defaultValue: { @@ -118,10 +137,14 @@ export default { }, }, }, - footer: { - name: "@footer", + "onSearch-change": { + action: "on-search-change", + description: "Triggered when the search input updates", table: { - category: "@attribute tags", + category: "Events", + defaultValue: { + summary: "{ checked, originalEvent }", + }, }, }, }, @@ -158,3 +181,9 @@ Standard.parameters = { }, }, }; + +export const WithSearch = buildExtensionTemplate( + WithSearchTemplate, + WithSearchCode, + {}, +); diff --git a/src/components/ebay-filter-menu/index.marko b/src/components/ebay-filter-menu/index.marko index 287745433..c2b462087 100644 --- a/src/components/ebay-filter-menu/index.marko +++ b/src/components/ebay-filter-menu/index.marko @@ -14,6 +14,8 @@ $ const { type, ariaLabel, ariaLabelledby, + searchHeaderPlaceholderText, + a11ySearchHeaderClearText, ...htmlInput } = input; $ var isRadio = type === "radio"; @@ -22,10 +24,28 @@ $ var baseClass = classPrefix || "filter-menu"; $ var isForm = variant === "form"; <span ...processHtmlAttributes(htmlInput) - key="container" class=[classPrefix ? `${baseClass}__menu` : baseClass, inputClass] style=style > + <if(searchHeaderPlaceholderText)> + <div class="filter-menu__header"> + <ebay-search-16-icon/> + <input + type="text" + value=state.searchTerm + class="filter-menu__search" + placeholder=searchHeaderPlaceholderText + aria-owns:scoped="search-items" + on-input("handleSearch") + > + <button + on-click("clearSearch") + aria-label=a11ySearchHeaderClearText + > + <ebay-clear-20-icon/> + </button> + </div> + </if> <${isForm && "form"} name=formName action=formAction @@ -35,6 +55,7 @@ $ var isForm = variant === "form"; <div key="menu" class=`${baseClass}__items` + id:scoped=searchHeaderPlaceholderText && "search-items" role=!isForm && "menu" aria-label=ariaLabel aria-labelledby=ariaLabelledby From af71cf8b453f9e2c12aee240609e2547c1905da6 Mon Sep 17 00:00:00 2001 From: LuLaValva <lukelavalva@gmail.com> Date: Tue, 19 Nov 2024 11:16:12 -0800 Subject: [PATCH 2/7] feat(filter-menu-button): search header --- .../ebay-filter-menu-button/component.ts | 3 + .../examples/data.json | 974 ++++++++++++++++++ .../examples/with-search.marko | 33 + .../filter-menu-button.stories.ts | 42 +- .../ebay-filter-menu-button/index.marko | 7 +- 5 files changed, 1052 insertions(+), 7 deletions(-) create mode 100644 src/components/ebay-filter-menu-button/examples/data.json create mode 100644 src/components/ebay-filter-menu-button/examples/with-search.marko diff --git a/src/components/ebay-filter-menu-button/component.ts b/src/components/ebay-filter-menu-button/component.ts index cabc4713e..405243858 100644 --- a/src/components/ebay-filter-menu-button/component.ts +++ b/src/components/ebay-filter-menu-button/component.ts @@ -34,11 +34,14 @@ interface FilterMenuButtonInput "form-method"?: string; disabled?: boolean; "a11y-text"?: AttrString; + "search-header-placeholder-text"?: string; + "a11y-search-header-clear-text"?: string; "on-expand"?: () => void; "on-change"?: (event: FilterMenuButtonEvent) => void; "on-collapse"?: (event: FilterMenuButtonEvent) => void; "on-footer-click"?: (event: FilterMenuButtonEvent) => void; "on-form-submit"?: (event: FilterMenuButtonEvent) => void; + "on-search-change"?: (value: string) => void; } export interface Input extends WithNormalizedProps<FilterMenuButtonInput> {} diff --git a/src/components/ebay-filter-menu-button/examples/data.json b/src/components/ebay-filter-menu-button/examples/data.json new file mode 100644 index 000000000..6de354b55 --- /dev/null +++ b/src/components/ebay-filter-menu-button/examples/data.json @@ -0,0 +1,974 @@ +[ + { + "name": "Afghanistan", + "code": "AF" + }, + { + "name": "Ã…landIslands", + "code": "AX" + }, + { + "name": "Albania", + "code": "AL" + }, + { + "name": "Algeria", + "code": "DZ" + }, + { + "name": "AmericanSamoa", + "code": "AS" + }, + { + "name": "AndorrA", + "code": "AD" + }, + { + "name": "Angola", + "code": "AO" + }, + { + "name": "Anguilla", + "code": "AI" + }, + { + "name": "Antarctica", + "code": "AQ" + }, + { + "name": "Antiguaand Barbuda", + "code": "AG" + }, + { + "name": "Argentina", + "code": "AR" + }, + { + "name": "Armenia", + "code": "AM" + }, + { + "name": "Aruba", + "code": "AW" + }, + { + "name": "Australia", + "code": "AU" + }, + { + "name": "Austria", + "code": "AT" + }, + { + "name": "Azerbaijan", + "code": "AZ" + }, + { + "name": "Bahamas", + "code": "BS" + }, + { + "name": "Bahrain", + "code": "BH" + }, + { + "name": "Bangladesh", + "code": "BD" + }, + { + "name": "Barbados", + "code": "BB" + }, + { + "name": "Belarus", + "code": "BY" + }, + { + "name": "Belgium", + "code": "BE" + }, + { + "name": "Belize", + "code": "BZ" + }, + { + "name": "Benin", + "code": "BJ" + }, + { + "name": "Bermuda", + "code": "BM" + }, + { + "name": "Bhutan", + "code": "BT" + }, + { + "name": "Bolivia", + "code": "BO" + }, + { + "name": "Bosniaand Herzegovina", + "code": "BA" + }, + { + "name": "Botswana", + "code": "BW" + }, + { + "name": "BouvetIsland", + "code": "BV" + }, + { + "name": "Brazil", + "code": "BR" + }, + { + "name": "BritishIndian Ocean Territory", + "code": "IO" + }, + { + "name": "BruneiDarussalam", + "code": "BN" + }, + { + "name": "Bulgaria", + "code": "BG" + }, + { + "name": "BurkinaFaso", + "code": "BF" + }, + { + "name": "Burundi", + "code": "BI" + }, + { + "name": "Cambodia", + "code": "KH" + }, + { + "name": "Cameroon", + "code": "CM" + }, + { + "name": "Canada", + "code": "CA" + }, + { + "name": "CapeVerde", + "code": "CV" + }, + { + "name": "CaymanIslands", + "code": "KY" + }, + { + "name": "CentralAfrican Republic", + "code": "CF" + }, + { + "name": "Chad", + "code": "TD" + }, + { + "name": "Chile", + "code": "CL" + }, + { + "name": "China", + "code": "CN" + }, + { + "name": "ChristmasIsland", + "code": "CX" + }, + { + "name": "Cocos(Keeling) Islands", + "code": "CC" + }, + { + "name": "Colombia", + "code": "CO" + }, + { + "name": "Comoros", + "code": "KM" + }, + { + "name": "Congo", + "code": "CG" + }, + { + "name": "Congo The Democratic Republic of the", + "code": "CD" + }, + { + "name": "CookIslands", + "code": "CK" + }, + { + "name": "CostaRica", + "code": "CR" + }, + { + "name": "CoteD'Ivoire", + "code": "CI" + }, + { + "name": "Croatia", + "code": "HR" + }, + { + "name": "Cuba", + "code": "CU" + }, + { + "name": "Cyprus", + "code": "CY" + }, + { + "name": "CzechRepublic", + "code": "CZ" + }, + { + "name": "Denmark", + "code": "DK" + }, + { + "name": "Djibouti", + "code": "DJ" + }, + { + "name": "Dominica", + "code": "DM" + }, + { + "name": "DominicanRepublic", + "code": "DO" + }, + { + "name": "Ecuador", + "code": "EC" + }, + { + "name": "Egypt", + "code": "EG" + }, + { + "name": "ElSalvador", + "code": "SV" + }, + { + "name": "EquatorialGuinea", + "code": "GQ" + }, + { + "name": "Eritrea", + "code": "ER" + }, + { + "name": "Estonia", + "code": "EE" + }, + { + "name": "Ethiopia", + "code": "ET" + }, + { + "name": "FalklandIslands (Malvinas)", + "code": "FK" + }, + { + "name": "FaroeIslands", + "code": "FO" + }, + { + "name": "Fiji", + "code": "FJ" + }, + { + "name": "Finland", + "code": "FI" + }, + { + "name": "France", + "code": "FR" + }, + { + "name": "FrenchGuiana", + "code": "GF" + }, + { + "name": "FrenchPolynesia", + "code": "PF" + }, + { + "name": "FrenchSouthern Territories", + "code": "TF" + }, + { + "name": "Gabon", + "code": "GA" + }, + { + "name": "Gambia", + "code": "GM" + }, + { + "name": "Georgia", + "code": "GE" + }, + { + "name": "Germany", + "code": "DE" + }, + { + "name": "Ghana", + "code": "GH" + }, + { + "name": "Gibraltar", + "code": "GI" + }, + { + "name": "Greece", + "code": "GR" + }, + { + "name": "Greenland", + "code": "GL" + }, + { + "name": "Grenada", + "code": "GD" + }, + { + "name": "Guadeloupe", + "code": "GP" + }, + { + "name": "Guam", + "code": "GU" + }, + { + "name": "Guatemala", + "code": "GT" + }, + { + "name": "Guernsey", + "code": "GG" + }, + { + "name": "Guinea", + "code": "GN" + }, + { + "name": "GuineaBissau", + "code": "GW" + }, + { + "name": "Guyana", + "code": "GY" + }, + { + "name": "Haiti", + "code": "HT" + }, + { + "name": "HeardIsland and Mcdonald Islands", + "code": "HM" + }, + { + "name": "HolySee (Vatican City State)", + "code": "VA" + }, + { + "name": "Honduras", + "code": "HN" + }, + { + "name": "HongKong", + "code": "HK" + }, + { + "name": "Hungary", + "code": "HU" + }, + { + "name": "Iceland", + "code": "IS" + }, + { + "name": "India", + "code": "IN" + }, + { + "name": "Indonesia", + "code": "ID" + }, + { + "name": "Iran Islamic Republic Of", + "code": "IR" + }, + { + "name": "Iraq", + "code": "IQ" + }, + { + "name": "Ireland", + "code": "IE" + }, + { + "name": "Isleof Man", + "code": "IM" + }, + { + "name": "Israel", + "code": "IL" + }, + { + "name": "Italy", + "code": "IT" + }, + { + "name": "Jamaica", + "code": "JM" + }, + { + "name": "Japan", + "code": "JP" + }, + { + "name": "Jersey", + "code": "JE" + }, + { + "name": "Jordan", + "code": "JO" + }, + { + "name": "Kazakhstan", + "code": "KZ" + }, + { + "name": "Kenya", + "code": "KE" + }, + { + "name": "Kiribati", + "code": "KI" + }, + { + "name": "Korea Democratic People'S Republic of", + "code": "KP" + }, + { + "name": "Korea Republic of", + "code": "KR" + }, + { + "name": "Kuwait", + "code": "KW" + }, + { + "name": "Kyrgyzstan", + "code": "KG" + }, + { + "name": "LaoPeopleS Democratic Republic", + "code": "LA" + }, + { + "name": "Latvia", + "code": "LV" + }, + { + "name": "Lebanon", + "code": "LB" + }, + { + "name": "Lesotho", + "code": "LS" + }, + { + "name": "Liberia", + "code": "LR" + }, + { + "name": "LibyanArab Jamahiriya", + "code": "LY" + }, + { + "name": "Liechtenstein", + "code": "LI" + }, + { + "name": "Lithuania", + "code": "LT" + }, + { + "name": "Luxembourg", + "code": "LU" + }, + { + "name": "Macao", + "code": "MO" + }, + { + "name": "Macedonia The Former Yugoslav Republic of", + "code": "MK" + }, + { + "name": "Madagascar", + "code": "MG" + }, + { + "name": "Malawi", + "code": "MW" + }, + { + "name": "Malaysia", + "code": "MY" + }, + { + "name": "Maldives", + "code": "MV" + }, + { + "name": "Mali", + "code": "ML" + }, + { + "name": "Malta", + "code": "MT" + }, + { + "name": "MarshallIslands", + "code": "MH" + }, + { + "name": "Martinique", + "code": "MQ" + }, + { + "name": "Mauritania", + "code": "MR" + }, + { + "name": "Mauritius", + "code": "MU" + }, + { + "name": "Mayotte", + "code": "YT" + }, + { + "name": "Mexico", + "code": "MX" + }, + { + "name": "Micronesia Federated States of", + "code": "FM" + }, + { + "name": "Moldova Republic of", + "code": "MD" + }, + { + "name": "Monaco", + "code": "MC" + }, + { + "name": "Mongolia", + "code": "MN" + }, + { + "name": "Montserrat", + "code": "MS" + }, + { + "name": "Morocco", + "code": "MA" + }, + { + "name": "Mozambique", + "code": "MZ" + }, + { + "name": "Myanmar", + "code": "MM" + }, + { + "name": "Namibia", + "code": "NA" + }, + { + "name": "Nauru", + "code": "NR" + }, + { + "name": "Nepal", + "code": "NP" + }, + { + "name": "Netherlands", + "code": "NL" + }, + { + "name": "NetherlandsAntilles", + "code": "AN" + }, + { + "name": "NewCaledonia", + "code": "NC" + }, + { + "name": "NewZealand", + "code": "NZ" + }, + { + "name": "Nicaragua", + "code": "NI" + }, + { + "name": "Niger", + "code": "NE" + }, + { + "name": "Nigeria", + "code": "NG" + }, + { + "name": "Niue", + "code": "NU" + }, + { + "name": "NorfolkIsland", + "code": "NF" + }, + { + "name": "NorthernMariana Islands", + "code": "MP" + }, + { + "name": "Norway", + "code": "NO" + }, + { + "name": "Oman", + "code": "OM" + }, + { + "name": "Pakistan", + "code": "PK" + }, + { + "name": "Palau", + "code": "PW" + }, + { + "name": "PalestinianTerritory Occupied", + "code": "PS" + }, + { + "name": "Panama", + "code": "PA" + }, + { + "name": "PapuaNew Guinea", + "code": "PG" + }, + { + "name": "Paraguay", + "code": "PY" + }, + { + "name": "Peru", + "code": "PE" + }, + { + "name": "Philippines", + "code": "PH" + }, + { + "name": "Pitcairn", + "code": "PN" + }, + { + "name": "Poland", + "code": "PL" + }, + { + "name": "Portugal", + "code": "PT" + }, + { + "name": "PuertoRico", + "code": "PR" + }, + { + "name": "Qatar", + "code": "QA" + }, + { + "name": "Reunion", + "code": "RE" + }, + { + "name": "Romania", + "code": "RO" + }, + { + "name": "RussianFederation", + "code": "RU" + }, + { + "name": "RWANDA", + "code": "RW" + }, + { + "name": "SaintHelena", + "code": "SH" + }, + { + "name": "SaintKitts and Nevis", + "code": "KN" + }, + { + "name": "SaintLucia", + "code": "LC" + }, + { + "name": "SaintPierre and Miquelon", + "code": "PM" + }, + { + "name": "SaintVincent and the Grenadines", + "code": "VC" + }, + { + "name": "Samoa", + "code": "WS" + }, + { + "name": "SanMarino", + "code": "SM" + }, + { + "name": "SaoTome and Principe", + "code": "ST" + }, + { + "name": "SaudiArabia", + "code": "SA" + }, + { + "name": "Senegal", + "code": "SN" + }, + { + "name": "Serbiaand Montenegro", + "code": "CS" + }, + { + "name": "Seychelles", + "code": "SC" + }, + { + "name": "SierraLeone", + "code": "SL" + }, + { + "name": "Singapore", + "code": "SG" + }, + { + "name": "Slovakia", + "code": "SK" + }, + { + "name": "Slovenia", + "code": "SI" + }, + { + "name": "SolomonIslands", + "code": "SB" + }, + { + "name": "Somalia", + "code": "SO" + }, + { + "name": "SouthAfrica", + "code": "ZA" + }, + { + "name": "SouthGeorgia and the South Sandwich Islands", + "code": "GS" + }, + { + "name": "Spain", + "code": "ES" + }, + { + "name": "SriLanka", + "code": "LK" + }, + { + "name": "Sudan", + "code": "SD" + }, + { + "name": "Suriname", + "code": "SR" + }, + { + "name": "Svalbardand Jan Mayen", + "code": "SJ" + }, + { + "name": "Swaziland", + "code": "SZ" + }, + { + "name": "Sweden", + "code": "SE" + }, + { + "name": "Switzerland", + "code": "CH" + }, + { + "name": "SyrianArab Republic", + "code": "SY" + }, + { + "name": "Taiwan Province of China", + "code": "TW" + }, + { + "name": "Tajikistan", + "code": "TJ" + }, + { + "name": "Tanzania United Republic of", + "code": "TZ" + }, + { + "name": "Thailand", + "code": "TH" + }, + { + "name": "TimorLeste", + "code": "TL" + }, + { + "name": "Togo", + "code": "TG" + }, + { + "name": "Tokelau", + "code": "TK" + }, + { + "name": "Tonga", + "code": "TO" + }, + { + "name": "Trinidadand Tobago", + "code": "TT" + }, + { + "name": "Tunisia", + "code": "TN" + }, + { + "name": "Turkey", + "code": "TR" + }, + { + "name": "Turkmenistan", + "code": "TM" + }, + { + "name": "Turksand Caicos Islands", + "code": "TC" + }, + { + "name": "Tuvalu", + "code": "TV" + }, + { + "name": "Uganda", + "code": "UG" + }, + { + "name": "Ukraine", + "code": "UA" + }, + { + "name": "UnitedArab Emirates", + "code": "AE" + }, + { + "name": "UnitedKingdom", + "code": "GB" + }, + { + "name": "United States", + "code": "US" + }, + { + "name": "United States Minor Outlying Islands", + "code": "UM" + }, + { + "name": "Uruguay", + "code": "UY" + }, + { + "name": "Uzbekistan", + "code": "UZ" + }, + { + "name": "Vanuatu", + "code": "VU" + }, + { + "name": "Venezuela", + "code": "VE" + }, + { + "name": "VietNam", + "code": "VN" + }, + { + "name": "VirginIslands British", + "code": "VG" + }, + { + "name": "VirginIslands U.S.", + "code": "VI" + }, + { + "name": "Wallisand Futuna", + "code": "WF" + }, + { + "name": "WesternSahara", + "code": "EH" + }, + { + "name": "Yemen", + "code": "YE" + }, + { + "name": "Zambia", + "code": "ZM" + }, + { + "name": "Zimbabwe", + "code": "ZW" + } +] diff --git a/src/components/ebay-filter-menu-button/examples/with-search.marko b/src/components/ebay-filter-menu-button/examples/with-search.marko new file mode 100644 index 000000000..3a8358119 --- /dev/null +++ b/src/components/ebay-filter-menu-button/examples/with-search.marko @@ -0,0 +1,33 @@ +import countries from "./data.json"; + +class { + declare state: { + searchTerm: string; + }; + + onCreate() { + this.state = { + searchTerm: "", + }; + } + + handleSearchChange(value: string) { + this.state.searchTerm = value.toLowerCase(); + } +} + +<ebay-filter-menu-button + text="Country" + search-header-placeholder-text="Search" + a11y-search-header-clear-text="Clear" + on-search-change("handleSearchChange") + ...input +> + <for|{ name, code }| of=countries> + <if(name.toLowerCase().includes(state.searchTerm))> + <@item value=code> + ${name} + </@item> + </if> + </for> +</ebay-filter-menu-button> diff --git a/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts b/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts index 0d5e8a5a5..0719bafa7 100644 --- a/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts +++ b/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts @@ -1,9 +1,14 @@ import { Story } from "@storybook/marko"; import { tagToString } from "../../common/storybook/storybook-code-source"; -import { addRenderBodies } from "../../common/storybook/utils"; +import { + addRenderBodies, + buildExtensionTemplate, +} from "../../common/storybook/utils"; import Readme from "./README.md"; import Component from "./index.marko"; import type { Input } from "./component"; +import WithSearchTemplate from "./examples/with-search.marko"; +import WithSearchCode from "./examples/with-search.marko?raw"; const Template: Story<Input> = (args) => ({ input: addRenderBodies(args), @@ -63,6 +68,15 @@ export default { category: "@attribute tags", }, }, + searchHeaderPlaceholderText: { + control: { type: "text" }, + description: + "enables the search header and populates placeholder text. `a11y-search-header-clear-text` is required if this is enabled.", + }, + a11ySearchHeaderClearText: { + control: { type: "text" }, + description: "a11y text for the search header clear button", + }, formName: { control: { type: "text" }, description: "forms `name` attribute", @@ -92,6 +106,12 @@ export default { description: "the items value (returned in emitted events when checked)", }, + footer: { + name: "@footer", + table: { + category: "@attribute tags", + }, + }, onCollapse: { action: "on-collapse", description: "Triggered on menu collapse", @@ -122,7 +142,7 @@ export default { }, }, }, - footerClick: { + "onFooter-click": { action: "on-footer-click", description: "Triggered on footer clicked", table: { @@ -132,7 +152,7 @@ export default { }, }, }, - formSubmit: { + "onForm-submit": { action: "on-form-submit", description: 'when using `variant="form"`, and form is submitted (emits current checked state)', @@ -143,10 +163,14 @@ export default { }, }, }, - footer: { - name: "@footer", + "onSearch-change": { + action: "on-search-change", + description: "Triggered when the search input updates", table: { - category: "@attribute tags", + category: "Events", + defaultValue: { + summary: "{ checked, originalEvent }", + }, }, }, }, @@ -209,3 +233,9 @@ WithFooter.parameters = { }, }, }; + +export const WithSearch = buildExtensionTemplate( + WithSearchTemplate, + WithSearchCode, + {}, +); diff --git a/src/components/ebay-filter-menu-button/index.marko b/src/components/ebay-filter-menu-button/index.marko index 668f648cd..901d8b1be 100644 --- a/src/components/ebay-filter-menu-button/index.marko +++ b/src/components/ebay-filter-menu-button/index.marko @@ -13,6 +13,8 @@ $ const { formAction, formMethod, items, + searchHeaderPlaceholderText, + a11ySearchHeaderClearText, type: inputType, ...htmlInput } = input; @@ -46,10 +48,13 @@ $ const { formMethod=formMethod footerText=footerText a11yFooterText=a11yFooterText + searchHeaderPlaceholderText=searchHeaderPlaceholderText + a11ySearchHeaderClearText=a11ySearchHeaderClearText on-keydown("handleMenuKeydown") on-change("handleMenuChange") on-form-submit("handleFormSubmit") - on-footer-click("handleFooterButtonClick")> + on-footer-click("handleFooterButtonClick") + on-search-change("emit", "search-change")> <for|item, i| of=(items || [])> <@item ...item checked=component.isChecked(i)/> </for> From 3ba07a8a7c46ae81abfdf28285377c5956d78534 Mon Sep 17 00:00:00 2001 From: LuLaValva <lukelavalva@gmail.com> Date: Tue, 19 Nov 2024 11:16:38 -0800 Subject: [PATCH 3/7] chore: add changeset --- .changeset/famous-peas-own.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/famous-peas-own.md diff --git a/.changeset/famous-peas-own.md b/.changeset/famous-peas-own.md new file mode 100644 index 000000000..60e93e4da --- /dev/null +++ b/.changeset/famous-peas-own.md @@ -0,0 +1,5 @@ +--- +"@ebay/ebayui-core": minor +--- + +Search header for filter menu & filter menu button From 708167350906daf6737d779b41292df705f48aab Mon Sep 17 00:00:00 2001 From: LuLaValva <lukelavalva@gmail.com> Date: Tue, 19 Nov 2024 11:20:12 -0800 Subject: [PATCH 4/7] chore: update tests --- .../test/__snapshots__/test.server.js.snap | 24 ++++++++++----- .../test/__snapshots__/test.server.js.snap | 30 ++++++++++++------- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/components/ebay-filter-menu-button/test/__snapshots__/test.server.js.snap b/src/components/ebay-filter-menu-button/test/__snapshots__/test.server.js.snap index c99fb3229..c91cb3ecd 100644 --- a/src/components/ebay-filter-menu-button/test/__snapshots__/test.server.js.snap +++ b/src/components/ebay-filter-menu-button/test/__snapshots__/test.server.js.snap @@ -49,9 +49,10 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` <span class="filter-menu-button__menu" > - <!--F#f_0--> + <!--F#f_6--> <div class="filter-menu-button__items" + id="s0-3" role="menu" > <div @@ -85,7 +86,7 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` <span class="filter-menu-button__text" > - <!--F#11[0]--> + <!--F#17[0]--> item 1 <!--F/--> </span> @@ -111,7 +112,7 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` <span class="filter-menu-button__text" > - <!--F#11[1]--> + <!--F#17[1]--> item 2 <!--F/--> </span> @@ -137,7 +138,7 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` <span class="filter-menu-button__text" > - <!--F#11[2]--> + <!--F#17[2]--> item 3 <!--F/--> </span> @@ -197,9 +198,10 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` <span class="filter-menu-button__menu" > - <!--F#f_0--> + <!--F#f_6--> <div class="filter-menu-button__items" + id="s0-3" role="menu" > <div @@ -233,7 +235,7 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` <span class="filter-menu-button__text" > - <!--F#11[0]--> + <!--F#17[0]--> item 1 <!--F/--> </span> @@ -259,7 +261,7 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` <span class="filter-menu-button__text" > - <!--F#11[1]--> + <!--F#17[1]--> item 2 <!--F/--> </span> @@ -285,7 +287,7 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` <span class="filter-menu-button__text" > - <!--F#11[2]--> + <!--F#17[2]--> item 3 <!--F/--> </span> @@ -422,6 +424,7 @@ exports[`filter-menu > renders basic version 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu-button__items"[39m + [33mid[39m=[32m"s0-3"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -560,6 +563,7 @@ exports[`filter-menu > renders checked item 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu-button__items"[39m + [33mid[39m=[32m"s0-3"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -698,6 +702,7 @@ exports[`filter-menu > renders disabled item 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu-button__items"[39m + [33mid[39m=[32m"s0-3"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -836,6 +841,7 @@ exports[`filter-menu > renders with footer 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu-button__items"[39m + [33mid[39m=[32m"s0-3"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -981,6 +987,7 @@ exports[`filter-menu > renders with footer text 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu-button__items"[39m + [33mid[39m=[32m"s0-3"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -1125,6 +1132,7 @@ exports[`filter-menu > renders with footer text and accessible text 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu-button__items"[39m + [33mid[39m=[32m"s0-3"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m diff --git a/src/components/ebay-filter-menu/test/__snapshots__/test.server.js.snap b/src/components/ebay-filter-menu/test/__snapshots__/test.server.js.snap index e48a43f1b..4b3763d61 100644 --- a/src/components/ebay-filter-menu/test/__snapshots__/test.server.js.snap +++ b/src/components/ebay-filter-menu/test/__snapshots__/test.server.js.snap @@ -9,9 +9,10 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` text="Button" type="number" > - <!--F#f_0--> + <!--F#f_6--> <div class="filter-menu__items" + id="s0" role="menu" > <div @@ -45,7 +46,7 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` <span class="filter-menu__text" > - <!--F#11[0]--> + <!--F#17[0]--> item 1 <!--F/--> </span> @@ -71,7 +72,7 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` <span class="filter-menu__text" > - <!--F#11[1]--> + <!--F#17[1]--> item 2 <!--F/--> </span> @@ -97,7 +98,7 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` <span class="filter-menu__text" > - <!--F#11[2]--> + <!--F#17[2]--> item 3 <!--F/--> </span> @@ -108,7 +109,7 @@ exports[`filter-menu > passes through additional html attributes 1`] = ` class="filter-menu__footer" type="button" > - <!--F#14--> + <!--F#20--> Apply <!--F/--> </button> @@ -125,9 +126,10 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` text="Button" type="number" > - <!--F#f_0--> + <!--F#f_6--> <div class="filter-menu__items" + id="s0" role="menu" > <div @@ -161,7 +163,7 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` <span class="filter-menu__text" > - <!--F#11[0]--> + <!--F#17[0]--> item 1 <!--F/--> </span> @@ -187,7 +189,7 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` <span class="filter-menu__text" > - <!--F#11[1]--> + <!--F#17[1]--> item 2 <!--F/--> </span> @@ -213,7 +215,7 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` <span class="filter-menu__text" > - <!--F#11[2]--> + <!--F#17[2]--> item 3 <!--F/--> </span> @@ -224,7 +226,7 @@ exports[`filter-menu > passes through additional html attributes 2`] = ` class="filter-menu__footer" type="button" > - <!--F#14--> + <!--F#20--> Apply <!--F/--> </button> @@ -318,6 +320,7 @@ exports[`filter-menu > renders basic version 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -422,6 +425,7 @@ exports[`filter-menu > renders checked item 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -526,6 +530,7 @@ exports[`filter-menu > renders disabled item 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -631,6 +636,7 @@ exports[`filter-menu > renders with aria-label 1`] = ` [36m<div[39m [33maria-label[39m=[32m"test"[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -736,6 +742,7 @@ exports[`filter-menu > renders with aria-labelledby 1`] = ` [36m<div[39m [33maria-labelledby[39m=[32m"test"[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -840,6 +847,7 @@ exports[`filter-menu > renders with footer render body 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -944,6 +952,7 @@ exports[`filter-menu > renders with footer text 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m @@ -1047,6 +1056,7 @@ exports[`filter-menu > renders with footer text and accessible text 1`] = ` [36m>[39m [36m<div[39m [33mclass[39m=[32m"filter-menu__items"[39m + [33mid[39m=[32m"s0"[39m [33mrole[39m=[32m"menu"[39m [36m>[39m [36m<div[39m From 1b9b43cba0f569d76ade3872ddd44a97eeda75ab Mon Sep 17 00:00:00 2001 From: LuLaValva <lukelavalva@gmail.com> Date: Tue, 19 Nov 2024 12:38:34 -0800 Subject: [PATCH 5/7] fix(filter-menu): use ebay-button --- src/components/ebay-filter-menu/index.marko | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/ebay-filter-menu/index.marko b/src/components/ebay-filter-menu/index.marko index c2b462087..4df3d6283 100644 --- a/src/components/ebay-filter-menu/index.marko +++ b/src/components/ebay-filter-menu/index.marko @@ -38,12 +38,13 @@ $ var isForm = variant === "form"; aria-owns:scoped="search-items" on-input("handleSearch") > - <button + <ebay-button + priority="none" on-click("clearSearch") aria-label=a11ySearchHeaderClearText > <ebay-clear-20-icon/> - </button> + </ebay-button> </div> </if> <${isForm && "form"} From 495147f844306cae81ae738a24c3fd90f5114dfa Mon Sep 17 00:00:00 2001 From: LuLaValva <lukelavalva@gmail.com> Date: Wed, 20 Nov 2024 15:44:19 -0800 Subject: [PATCH 6/7] fix(examples): preserve search results --- .../examples/with-search.marko | 35 +++++++++++++------ .../examples/with-search.marko | 34 +++++++++++++----- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/components/ebay-filter-menu-button/examples/with-search.marko b/src/components/ebay-filter-menu-button/examples/with-search.marko index 3a8358119..68bdd9152 100644 --- a/src/components/ebay-filter-menu-button/examples/with-search.marko +++ b/src/components/ebay-filter-menu-button/examples/with-search.marko @@ -1,18 +1,34 @@ import countries from "./data.json"; - +import type { Input as FilterMenuButtonInput } from "<ebay-filter-menu-button>"; class { declare state: { - searchTerm: string; + checkedCodes: { [code: string]: boolean }; + visibleCountries: typeof countries; }; onCreate() { this.state = { - searchTerm: "", + checkedCodes: {}, + visibleCountries: countries, }; } handleSearchChange(value: string) { - this.state.searchTerm = value.toLowerCase(); + const searchTerm = value.toLowerCase(); + this.state.visibleCountries = countries.filter(({ name }) => + name.toLowerCase().includes(searchTerm), + ); + } + + handleChange({ + index, + currentChecked, + }: Parameters<NonNullable<FilterMenuButtonInput["on-change"]>>[0]) { + if (index === undefined) return; + this.state.checkedCodes = { + ...this.state.checkedCodes, + [this.state.visibleCountries[index].code]: !!currentChecked, + }; } } @@ -21,13 +37,12 @@ class { search-header-placeholder-text="Search" a11y-search-header-clear-text="Clear" on-search-change("handleSearchChange") + on-change("handleChange") ...input > - <for|{ name, code }| of=countries> - <if(name.toLowerCase().includes(state.searchTerm))> - <@item value=code> - ${name} - </@item> - </if> + <for|{ name, code }| of=state.visibleCountries> + <@item value=code checked=state.checkedCodes[code]> + ${name} + </@item> </for> </ebay-filter-menu-button> diff --git a/src/components/ebay-filter-menu/examples/with-search.marko b/src/components/ebay-filter-menu/examples/with-search.marko index 085131f43..fdda54a7d 100644 --- a/src/components/ebay-filter-menu/examples/with-search.marko +++ b/src/components/ebay-filter-menu/examples/with-search.marko @@ -1,17 +1,34 @@ import countries from "./data.json"; +import type { Input as FilterMenuInput } from "<ebay-filter-menu>"; class { declare state: { - searchTerm: string; + checkedCodes: { [code: string]: boolean }; + visibleCountries: typeof countries; }; onCreate() { this.state = { - searchTerm: "", + checkedCodes: {}, + visibleCountries: countries, }; } handleSearchChange(value: string) { - this.state.searchTerm = value.toLowerCase(); + const searchTerm = value.toLowerCase(); + this.state.visibleCountries = countries.filter(({ name }) => + name.toLowerCase().includes(searchTerm), + ); + } + + handleChange({ + index, + currentChecked, + }: Parameters<NonNullable<FilterMenuInput["on-change"]>>[0]) { + if (index === undefined) return; + this.state.checkedCodes = { + ...this.state.checkedCodes, + [this.state.visibleCountries[index].code]: !!currentChecked, + }; } } @@ -19,13 +36,12 @@ class { search-header-placeholder-text="Search" a11y-search-header-clear-text="Clear" on-search-change("handleSearchChange") + on-change("handleChange") ...input > - <for|{ name, code }| of=countries> - <if(name.toLowerCase().includes(state.searchTerm))> - <@item value=code> - ${name} - </@item> - </if> + <for|{ name, code }| of=state.visibleCountries> + <@item value=code checked=state.checkedCodes[code]> + ${name} + </@item> </for> </ebay-filter-menu> From e92122aca238cf5f3413da5594bdf4b9ae473a13 Mon Sep 17 00:00:00 2001 From: LuLaValva <lukelavalva@gmail.com> Date: Thu, 21 Nov 2024 10:29:33 -0800 Subject: [PATCH 7/7] feat(filter-menu): allow search value override --- src/components/ebay-filter-menu-button/component.ts | 5 +++-- .../filter-menu-button.stories.ts | 5 +++++ src/components/ebay-filter-menu-button/index.marko | 2 ++ src/components/ebay-filter-menu/component.ts | 12 +++++++++--- .../ebay-filter-menu/filter-menu.stories.ts | 5 +++++ src/components/ebay-filter-menu/index.marko | 1 + 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/components/ebay-filter-menu-button/component.ts b/src/components/ebay-filter-menu-button/component.ts index 405243858..d318eed07 100644 --- a/src/components/ebay-filter-menu-button/component.ts +++ b/src/components/ebay-filter-menu-button/component.ts @@ -34,8 +34,9 @@ interface FilterMenuButtonInput "form-method"?: string; disabled?: boolean; "a11y-text"?: AttrString; - "search-header-placeholder-text"?: string; - "a11y-search-header-clear-text"?: string; + "search-header-value"?: string; + "search-header-placeholder-text"?: AttrString; + "a11y-search-header-clear-text"?: AttrString; "on-expand"?: () => void; "on-change"?: (event: FilterMenuButtonEvent) => void; "on-collapse"?: (event: FilterMenuButtonEvent) => void; diff --git a/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts b/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts index 0719bafa7..a7eac7723 100644 --- a/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts +++ b/src/components/ebay-filter-menu-button/filter-menu-button.stories.ts @@ -68,6 +68,11 @@ export default { category: "@attribute tags", }, }, + searchHeaderValue: { + control: { type: "text" }, + description: + "optional value override for the input in the search header", + }, searchHeaderPlaceholderText: { control: { type: "text" }, description: diff --git a/src/components/ebay-filter-menu-button/index.marko b/src/components/ebay-filter-menu-button/index.marko index 901d8b1be..7527a1551 100644 --- a/src/components/ebay-filter-menu-button/index.marko +++ b/src/components/ebay-filter-menu-button/index.marko @@ -13,6 +13,7 @@ $ const { formAction, formMethod, items, + searchHeaderValue, searchHeaderPlaceholderText, a11ySearchHeaderClearText, type: inputType, @@ -48,6 +49,7 @@ $ const { formMethod=formMethod footerText=footerText a11yFooterText=a11yFooterText + searchHeaderValue=searchHeaderValue searchHeaderPlaceholderText=searchHeaderPlaceholderText a11ySearchHeaderClearText=a11ySearchHeaderClearText on-keydown("handleMenuKeydown") diff --git a/src/components/ebay-filter-menu/component.ts b/src/components/ebay-filter-menu/component.ts index 8c438ed0f..87c67ada4 100644 --- a/src/components/ebay-filter-menu/component.ts +++ b/src/components/ebay-filter-menu/component.ts @@ -34,8 +34,9 @@ interface FilterMenuInput "a11y-footer-text"?: AttrString; } >; - "search-header-placeholder-text"?: string; - "a11y-search-header-clear-text"?: string; + "search-header-value"?: string; + "search-header-placeholder-text"?: AttrString; + "a11y-search-header-clear-text"?: AttrString; "render-body"?: Marko.Body; "on-footer-click"?: (event: FilterMenuEvent) => void; "on-form-submit"?: (event: FilterMenuEvent) => void; @@ -121,7 +122,12 @@ export default class extends MenuUtils<Input, State> { onInput(input: Input) { this.state = { ...super.getInputState(input), - searchTerm: this.state ? this.state.searchTerm : "", + searchTerm: + input.searchHeaderValue !== undefined + ? input.searchHeaderValue + : this.state + ? this.state.searchTerm + : "", }; } diff --git a/src/components/ebay-filter-menu/filter-menu.stories.ts b/src/components/ebay-filter-menu/filter-menu.stories.ts index 920532123..919eb24ce 100644 --- a/src/components/ebay-filter-menu/filter-menu.stories.ts +++ b/src/components/ebay-filter-menu/filter-menu.stories.ts @@ -52,6 +52,11 @@ export default { control: { type: "text" }, description: "forms `method` attribute", }, + searchHeaderValue: { + control: { type: "text" }, + description: + "optional value override for the input in the search header", + }, searchHeaderPlaceholderText: { control: { type: "text" }, description: diff --git a/src/components/ebay-filter-menu/index.marko b/src/components/ebay-filter-menu/index.marko index 4df3d6283..9986295d4 100644 --- a/src/components/ebay-filter-menu/index.marko +++ b/src/components/ebay-filter-menu/index.marko @@ -14,6 +14,7 @@ $ const { type, ariaLabel, ariaLabelledby, + searchHeaderValue, searchHeaderPlaceholderText, a11ySearchHeaderClearText, ...htmlInput