From af90fea2b10c05a18f92d740af7f21fd79d42ce9 Mon Sep 17 00:00:00 2001 From: eliza Date: Tue, 15 Jul 2025 13:30:06 -0700 Subject: [PATCH 01/19] feat(combobox): Provide context when filtering and there are no matching results --- .../combobox/assets/t9n/messages.en.json | 4 ++- .../combobox/assets/t9n/messages.json | 4 ++- .../src/components/combobox/combobox.scss | 10 +++++++ .../src/components/combobox/combobox.tsx | 27 ++++++++++++++++++- .../src/components/combobox/resources.ts | 1 + 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json b/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json index 9c98490d937..a9ee6163aa4 100644 --- a/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json +++ b/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json @@ -1,8 +1,10 @@ { + "add": "Add", "all": "All", "allSelected": "All selected", - "selectAll": "Select All", "clear": "Clear value", + "noMatches": "No matches", "removeTag": "Remove tag", + "selectAll": "Select All", "selected": "selected" } diff --git a/packages/calcite-components/src/components/combobox/assets/t9n/messages.json b/packages/calcite-components/src/components/combobox/assets/t9n/messages.json index 9c98490d937..a9ee6163aa4 100644 --- a/packages/calcite-components/src/components/combobox/assets/t9n/messages.json +++ b/packages/calcite-components/src/components/combobox/assets/t9n/messages.json @@ -1,8 +1,10 @@ { + "add": "Add", "all": "All", "allSelected": "All selected", - "selectAll": "Select All", "clear": "Clear value", + "noMatches": "No matches", "removeTag": "Remove tag", + "selectAll": "Select All", "selected": "selected" } diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 6980026544b..52974f4c6fb 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -250,6 +250,16 @@ calcite-chip { z-index: var(--calcite-z-index-sticky); } +.no-matches { + @apply block px-4 py-2; + color: var(--calcite-close-icon-color, var(--calcite-color-text-3)); + background: var(--calcite-combobox-background-color, var(--calcite-color-foreground-1)); + + strong { + color: var(--calcite-combobox-input-text-color, var(--calcite-color-text-1)); + } +} + @include disabled(); @include x-button( $background-color: "var(--calcite-close-background-color, var(--calcite-color-foreground-2))", diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 7d660751cbd..ad2a629a56d 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -156,7 +156,7 @@ export class Combobox }); if (setOpenToEmptyState) { - this.open = this.filterText.trim().length > 0 && this.keyboardNavItems.length > 0; + this.open = this.filterText.trim().length > 0; } if (emit) { @@ -1788,6 +1788,30 @@ export class Combobox return mappedListBoxOptions; } + private renderNoMatchesOrAddCustomText(): JsxNode { + const { allowCustomValues, filterText, open } = this; + if (!open || !filterText) { + return null; + } + + const filteredItems = this.filteredItems.filter((item) => !isHidden(item)); + if (filteredItems.length > 0) { + return null; + } + + // const noMatchesMsg = messageOverrides?.noMatches ?? messages.noMatches; + // const addMsg = messageOverrides?.add ?? messages.add; + + if (allowCustomValues) { + return ( +
  • + {"Add"} {filterText} +
  • + ); + } + return
  • {"No matches"}
  • ; + } + private renderFloatingUIContainer(): JsxNode { const { setFloatingEl, setContainerEl, open, scale } = this; const classes = { @@ -1817,6 +1841,7 @@ export class Combobox /> )} + {this.renderNoMatchesOrAddCustomText()} diff --git a/packages/calcite-components/src/components/combobox/resources.ts b/packages/calcite-components/src/components/combobox/resources.ts index 40ccdcd9a7d..cafc52479a3 100644 --- a/packages/calcite-components/src/components/combobox/resources.ts +++ b/packages/calcite-components/src/components/combobox/resources.ts @@ -12,6 +12,7 @@ export const CSS = { label: "label", labelIcon: "label--icon", listContainer: "list-container", + noMatches: "no-matches", placeholderIcon: "placeholder-icon", selectAll: "select-all", selectionDisplayFit: "selection-display--fit", From fc2d92b01194ef2a2d8b1b1a29fbaf372c5c5762 Mon Sep 17 00:00:00 2001 From: eliza Date: Tue, 15 Jul 2025 13:59:46 -0700 Subject: [PATCH 02/19] story noMatchesOrAddCustomValue --- .../components/combobox/combobox.stories.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/calcite-components/src/components/combobox/combobox.stories.ts b/packages/calcite-components/src/components/combobox/combobox.stories.ts index b3fd698ce55..f166b7c0243 100644 --- a/packages/calcite-components/src/components/combobox/combobox.stories.ts +++ b/packages/calcite-components/src/components/combobox/combobox.stories.ts @@ -1030,6 +1030,25 @@ export const withDescriptionShortLabelAndContentSlots = (): string => html` `; + +export const noMatchesOrAddCustomValue = (): string => html` +
    +
    + + + + +
    + +
    + + + + +
    +
    +`; + withDescriptionShortLabelAndContentSlots.args = { selectionMode: ["single", "multiple"], }; From 390402ae45fa0a1973b05cedcecfbd329bd003ae Mon Sep 17 00:00:00 2001 From: eliza Date: Wed, 16 Jul 2025 11:59:19 -0700 Subject: [PATCH 03/19] add screenshot and noMatches state --- .../src/components/combobox/combobox.e2e.ts | 15 ++++--- .../src/components/combobox/combobox.tsx | 41 ++++++++----------- .../src/custom-theme/combobox.ts | 7 ++++ 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.e2e.ts b/packages/calcite-components/src/components/combobox/combobox.e2e.ts index 861ce684b33..808555d4447 100644 --- a/packages/calcite-components/src/components/combobox/combobox.e2e.ts +++ b/packages/calcite-components/src/components/combobox/combobox.e2e.ts @@ -2209,12 +2209,15 @@ describe("calcite-combobox", () => { it("should allow enter unknown tag when tabbing away", async () => { const page = await newE2EPage(); await page.setContent(html` - - - - - - +
    + + + + + + +
    +
    `); const chip = await page.find("calcite-combobox >>> calcite-chip"); const eventSpy = await page.spyOnEvent("calciteComboboxChange"); diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index ad2a629a56d..8337a1bc4f7 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -148,6 +148,12 @@ export class Combobox } }); + if (this.filteredItems.length === 0 && this.filterText) { + this.noMatches = this.allowCustomValues ? "add" : "none"; + } else { + this.noMatches = null; + } + this.filterTextMatchPattern = this.filterText && new RegExp(`(${escapeRegExp(this.filterText)})`, "i"); @@ -292,6 +298,8 @@ export class Combobox return filteredItems; } + @state() noMatches: "none" | "add" | null = null; + //#endregion //#region Public Properties @@ -1788,30 +1796,6 @@ export class Combobox return mappedListBoxOptions; } - private renderNoMatchesOrAddCustomText(): JsxNode { - const { allowCustomValues, filterText, open } = this; - if (!open || !filterText) { - return null; - } - - const filteredItems = this.filteredItems.filter((item) => !isHidden(item)); - if (filteredItems.length > 0) { - return null; - } - - // const noMatchesMsg = messageOverrides?.noMatches ?? messages.noMatches; - // const addMsg = messageOverrides?.add ?? messages.add; - - if (allowCustomValues) { - return ( -
  • - {"Add"} {filterText} -
  • - ); - } - return
  • {"No matches"}
  • ; - } - private renderFloatingUIContainer(): JsxNode { const { setFloatingEl, setContainerEl, open, scale } = this; const classes = { @@ -1819,6 +1803,8 @@ export class Combobox [FloatingCSS.animation]: true, [FloatingCSS.animationActive]: open, }; + // const noMatchesMsg = messageOverrides?.noMatches ?? messages.noMatches; + // const addMsg = messageOverrides?.add ?? messages.add; return (
    @@ -1841,7 +1827,12 @@ export class Combobox /> )} - {this.renderNoMatchesOrAddCustomText()} + {this.noMatches === "add" && ( +
  • + {"Add"} {this.filterText} +
  • + )} + {this.noMatches === "none" &&
  • {"No matches"}
  • }
    diff --git a/packages/calcite-components/src/custom-theme/combobox.ts b/packages/calcite-components/src/custom-theme/combobox.ts index 4a1241dc696..d56ba5c8194 100644 --- a/packages/calcite-components/src/custom-theme/combobox.ts +++ b/packages/calcite-components/src/custom-theme/combobox.ts @@ -38,3 +38,10 @@ export const comboboxWithPlaceHolderIcon = html` `; + +export const noMatches = html` + + + + +`; From 11ba6937a1ce1fe3c972c9fa7d42e589cc4ba7cd Mon Sep 17 00:00:00 2001 From: eliza Date: Wed, 16 Jul 2025 12:11:23 -0700 Subject: [PATCH 04/19] add messages variable --- .../src/components/combobox/combobox.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 8337a1bc4f7..46454edf448 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1797,14 +1797,14 @@ export class Combobox } private renderFloatingUIContainer(): JsxNode { - const { setFloatingEl, setContainerEl, open, scale } = this; + const { messages, messageOverrides, setFloatingEl, setContainerEl, open, scale } = this; const classes = { [CSS.listContainer]: true, [FloatingCSS.animation]: true, [FloatingCSS.animationActive]: open, }; - // const noMatchesMsg = messageOverrides?.noMatches ?? messages.noMatches; - // const addMsg = messageOverrides?.add ?? messages.add; + const noMatches = messageOverrides?.noMatches ?? messages.noMatches; + const add = messageOverrides?.add ?? messages.add; return (
    @@ -1829,10 +1829,10 @@ export class Combobox {this.noMatches === "add" && (
  • - {"Add"} {this.filterText} + {add} {this.filterText}
  • )} - {this.noMatches === "none" &&
  • {"No matches"}
  • } + {this.noMatches === "none" &&
  • {noMatches}
  • }
    From 4672c6e7c6a7e1c4ae5ab7ad6586a71df76ccdf9 Mon Sep 17 00:00:00 2001 From: eliza Date: Wed, 16 Jul 2025 15:02:21 -0700 Subject: [PATCH 05/19] add e2e test --- .../src/components/combobox/combobox.e2e.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/calcite-components/src/components/combobox/combobox.e2e.ts b/packages/calcite-components/src/components/combobox/combobox.e2e.ts index 808555d4447..1dd5f52303b 100644 --- a/packages/calcite-components/src/components/combobox/combobox.e2e.ts +++ b/packages/calcite-components/src/components/combobox/combobox.e2e.ts @@ -3331,5 +3331,40 @@ describe("calcite-combobox", () => { }, }); }); + + describe("no-matches", () => { + themed( + async () => { + const page = await newE2EPage(); + await page.setContent(` + + + + + `); + + const combobox = await page.find("calcite-combobox"); + combobox.setProperty("filterText", "Oak"); + await page.waitForChanges(); + await page.waitForTimeout(DEBOUNCE.filter); + + return { tag: "calcite-combobox", page }; + }, + { + "--calcite-combobox-background-color": { + shadowSelector: `.${CSS.noMatches}`, + targetProp: "backgroundColor", + }, + "--calcite-close-icon-color": { + shadowSelector: `.${CSS.noMatches}`, + targetProp: "color", + }, + "--calcite-combobox-input-text-color": { + shadowSelector: `.${CSS.noMatches} >>> strong`, + targetProp: "color", + }, + }, + ); + }); }); }); From 58f47649035f903e763608a9cc0eaa4aa58339cb Mon Sep 17 00:00:00 2001 From: eliza Date: Thu, 17 Jul 2025 14:52:08 -0700 Subject: [PATCH 06/19] allow adding custom chip with a click on context dropdown --- .../src/components/combobox/combobox.tsx | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 76681e3433d..687e92bfdfb 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -251,6 +251,29 @@ export class Combobox */ messages = useT9n(); + private get effectiveFilterProps(): string[] { + if (!this.filterProps) { + return ["description", "label", "metadata", "shortHeading", "textLabel"]; + } + + return this.filterProps.filter((prop) => prop !== "el"); + } + + private get showingInlineIcon(): boolean { + const { placeholderIcon, selectionMode, selectedItems, open } = this; + const selectedItem = selectedItems[0]; + const selectedIcon = selectedItem?.icon; + const singleSelectionMode = isSingleLike(selectionMode); + + return !open && selectedItem + ? !!selectedIcon && singleSelectionMode + : !!placeholderIcon && (!selectedItem || singleSelectionMode); + } + + private customChipAddHandler = (): void => { + this.addCustomChip(this.filterText, true); + }; + //#endregion //#region State Properties @@ -640,25 +663,6 @@ export class Combobox this.calciteComboboxChange.emit(); } - private get effectiveFilterProps(): string[] { - if (!this.filterProps) { - return ["description", "label", "metadata", "shortHeading", "textLabel"]; - } - - return this.filterProps.filter((prop) => prop !== "el"); - } - - private get showingInlineIcon(): boolean { - const { placeholderIcon, selectionMode, selectedItems, open } = this; - const selectedItem = selectedItems[0]; - const selectedIcon = selectedItem?.icon; - const singleSelectionMode = isSingleLike(selectionMode); - - return !open && selectedItem - ? !!selectedIcon && singleSelectionMode - : !!placeholderIcon && (!selectedItem || singleSelectionMode); - } - private filterTextChange(value: string): void { this.updateActiveItemIndex(-1); this.filterItems(value, true); @@ -1820,7 +1824,14 @@ export class Combobox )} {this.noMatches === "add" && ( -
  • +
  • {add} {this.filterText}
  • )} From 5ccaee531cd85560e639c2a4695e5c9ea1bf7d74 Mon Sep 17 00:00:00 2001 From: eliza Date: Tue, 22 Jul 2025 18:06:52 -0700 Subject: [PATCH 07/19] : will take any English grammar concerns out of translation --- .../calcite-components/src/components/combobox/combobox.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 687e92bfdfb..a4dde908ec3 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1825,14 +1825,14 @@ export class Combobox {this.noMatches === "add" && (
  • - {add} {this.filterText} + {add}: {this.filterText}
  • )} {this.noMatches === "none" &&
  • {noMatches}
  • } From 6e383a2ec807ae614a96ec259c859d1b2ecd9e2d Mon Sep 17 00:00:00 2001 From: eliza Date: Fri, 25 Jul 2025 11:25:47 -0700 Subject: [PATCH 08/19] cleanup --- .../src/components/combobox/combobox.scss | 1 + .../src/components/combobox/combobox.tsx | 43 ++++++++++--------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 52974f4c6fb..0c110e09ccd 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -254,6 +254,7 @@ calcite-chip { @apply block px-4 py-2; color: var(--calcite-close-icon-color, var(--calcite-color-text-3)); background: var(--calcite-combobox-background-color, var(--calcite-color-foreground-1)); + cursor: pointer; strong { color: var(--calcite-combobox-input-text-color, var(--calcite-color-text-1)); diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index c48711abea4..17ff2674d7f 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -253,6 +253,29 @@ export class Combobox private focusSetter = useSetFocus()(this); + private get effectiveFilterProps(): string[] { + if (!this.filterProps) { + return ["description", "label", "metadata", "shortHeading", "textLabel"]; + } + + return this.filterProps.filter((prop) => prop !== "el"); + } + + private get showingInlineIcon(): boolean { + const { placeholderIcon, selectionMode, selectedItems, open } = this; + const selectedItem = selectedItems[0]; + const selectedIcon = selectedItem?.icon; + const singleSelectionMode = isSingleLike(selectionMode); + + return !open && selectedItem + ? !!selectedIcon && singleSelectionMode + : !!placeholderIcon && (!selectedItem || singleSelectionMode); + } + + private customChipAddHandler = (): void => { + this.addCustomChip(this.filterText, true); + }; + //#endregion //#region State Properties @@ -638,29 +661,10 @@ export class Combobox //#region Private Methods - private get effectiveFilterProps(): string[] { - if (!this.filterProps) { - return ["description", "label", "metadata", "shortHeading", "textLabel"]; - } - - return this.filterProps.filter((prop) => prop !== "el"); - } - private emitComboboxChange(): void { this.calciteComboboxChange.emit(); } - private get showingInlineIcon(): boolean { - const { placeholderIcon, selectionMode, selectedItems, open } = this; - const selectedItem = selectedItems[0]; - const selectedIcon = selectedItem?.icon; - const singleSelectionMode = isSingleLike(selectionMode); - - return !open && selectedItem - ? !!selectedIcon && singleSelectionMode - : !!placeholderIcon && (!selectedItem || singleSelectionMode); - } - private filterTextChange(value: string): void { this.updateActiveItemIndex(-1); this.filterItems(value, true); @@ -1827,7 +1831,6 @@ export class Combobox class={CSS.noMatches} onClick={this.customChipAddHandler} role="option" - style={{ cursor: "pointer" }} tabIndex={0} > {add}: {this.filterText} From 3eba460fbd3b6a1dee9b511dae6c1a7406cbf870 Mon Sep 17 00:00:00 2001 From: eliza Date: Fri, 25 Jul 2025 14:19:28 -0700 Subject: [PATCH 09/19] add entire string Add: {text} --- .../src/components/combobox/assets/t9n/messages.en.json | 2 +- .../src/components/combobox/assets/t9n/messages.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json b/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json index a9ee6163aa4..ad8c1033dcc 100644 --- a/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json +++ b/packages/calcite-components/src/components/combobox/assets/t9n/messages.en.json @@ -1,5 +1,5 @@ { - "add": "Add", + "add": "Add: {text}", "all": "All", "allSelected": "All selected", "clear": "Clear value", diff --git a/packages/calcite-components/src/components/combobox/assets/t9n/messages.json b/packages/calcite-components/src/components/combobox/assets/t9n/messages.json index a9ee6163aa4..ad8c1033dcc 100644 --- a/packages/calcite-components/src/components/combobox/assets/t9n/messages.json +++ b/packages/calcite-components/src/components/combobox/assets/t9n/messages.json @@ -1,5 +1,5 @@ { - "add": "Add", + "add": "Add: {text}", "all": "All", "allSelected": "All selected", "clear": "Clear value", From 9e9eba2994d54b676479b06b1f147df327856483 Mon Sep 17 00:00:00 2001 From: eliza Date: Fri, 25 Jul 2025 14:27:57 -0700 Subject: [PATCH 10/19] cleanup --- .../src/components/combobox/combobox.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 17ff2674d7f..3a6da3e00d7 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1795,14 +1795,12 @@ export class Combobox } private renderFloatingUIContainer(): JsxNode { - const { messages, messageOverrides, setFloatingEl, setContainerEl, open, scale } = this; + const { messages, setFloatingEl, setContainerEl, open, scale } = this; const classes = { [CSS.listContainer]: true, [FloatingCSS.animation]: true, [FloatingCSS.animationActive]: open, }; - const noMatches = messageOverrides?.noMatches ?? messages.noMatches; - const add = messageOverrides?.add ?? messages.add; return (
    @@ -1827,16 +1825,16 @@ export class Combobox {this.noMatches === "add" && (
  • - {add}: {this.filterText} + {messages.add}: {this.filterText}
  • )} - {this.noMatches === "none" &&
  • {noMatches}
  • } + {this.noMatches === "none" &&
  • {messages.noMatches}
  • }
    From ad0abf3d6331cfa4294d457ce97efb4755051bab Mon Sep 17 00:00:00 2001 From: eliza Date: Fri, 25 Jul 2025 17:20:43 -0700 Subject: [PATCH 11/19] correct string formatting --- .../calcite-components/src/components/combobox/combobox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index b3093cc9c88..848624a44fd 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1801,7 +1801,7 @@ export class Combobox } private renderFloatingUIContainer(): JsxNode { - const { messages, setFloatingEl, setContainerEl, open, scale } = this; + const { filterText, messages, setFloatingEl, setContainerEl, open, scale } = this; const classes = { [CSS.listContainer]: true, [FloatingCSS.animation]: true, @@ -1831,13 +1831,13 @@ export class Combobox {this.noMatches === "add" && (
  • - {messages.add}: {this.filterText} + {this.messages.add.replace("{text}", `${filterText}`)}
  • )} {this.noMatches === "none" &&
  • {messages.noMatches}
  • } From b797790242523c9b16c23400b62bd8faf187d3a3 Mon Sep 17 00:00:00 2001 From: eliza Date: Mon, 28 Jul 2025 15:57:31 -0700 Subject: [PATCH 12/19] formatting --- .../src/components/combobox/combobox.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 848624a44fd..f0d26032c23 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1819,25 +1819,30 @@ export class Combobox class={CSS.selectAll} id={`${this.guid}-select-all-enabled-interactive`} indeterminate={this.indeterminate} - label={this.messages.selectAll} + label={messages.selectAll} ref={this.selectAllComboboxItemReferenceEl} scale={scale} selected={this.allSelected} tabIndex="-1" - text-label={this.messages.selectAll} + text-label={messages.selectAll} value="select-all" /> )} {this.noMatches === "add" && (
  • - {this.messages.add.replace("{text}", `${filterText}`)} + {messages.add + .split("{text}") + .map((part, index) => + index === 0 ? part : [{filterText}], + ) + .flat()}
  • )} {this.noMatches === "none" &&
  • {messages.noMatches}
  • } From bd4eb0341bc7780918df9565dd6a35179ff14482 Mon Sep 17 00:00:00 2001 From: eliza Date: Tue, 29 Jul 2025 15:55:14 -0700 Subject: [PATCH 13/19] highlightText, spacing, and noMatchesScaledOrAddCustomValue --- .../src/components/combobox/combobox.scss | 4 +++- .../components/combobox/combobox.stories.ts | 16 +++++++++++++--- .../src/components/combobox/combobox.tsx | 19 ++++++++++--------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 0c110e09ccd..34b98f9dd80 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -251,7 +251,9 @@ calcite-chip { } .no-matches { - @apply block px-4 py-2; + padding-block: var(--calcite-internal-combobox-spacing-unit-s); + padding-inline: var(--calcite-internal-combobox-spacing-unit-l); + color: var(--calcite-close-icon-color, var(--calcite-color-text-3)); background: var(--calcite-combobox-background-color, var(--calcite-color-foreground-1)); cursor: pointer; diff --git a/packages/calcite-components/src/components/combobox/combobox.stories.ts b/packages/calcite-components/src/components/combobox/combobox.stories.ts index f166b7c0243..2a65bd0dbbf 100644 --- a/packages/calcite-components/src/components/combobox/combobox.stories.ts +++ b/packages/calcite-components/src/components/combobox/combobox.stories.ts @@ -1031,10 +1031,20 @@ export const withDescriptionShortLabelAndContentSlots = (): string => html` `; -export const noMatchesOrAddCustomValue = (): string => html` +export const noMatchesScaledOrAddCustomValue = (): string => html`
    -
    - +
    + + + + + + + + + + + diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index f0d26032c23..e1d4865f7cd 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -56,6 +56,7 @@ import { useT9n } from "../../controllers/useT9n"; import type { Chip } from "../chip/chip"; import type { ComboboxItemGroup as HTMLCalciteComboboxItemGroupElement } from "../combobox-item-group/combobox-item-group"; import type { ComboboxItem as HTMLCalciteComboboxItemElement } from "../combobox-item/combobox-item"; +import { highlightText } from "../../utils/text"; import type { Label } from "../label/label"; import { useSetFocus } from "../../controllers/useSetFocus"; import { useCancelable } from "../../controllers/useCancelable"; @@ -1801,13 +1802,15 @@ export class Combobox } private renderFloatingUIContainer(): JsxNode { - const { filterText, messages, setFloatingEl, setContainerEl, open, scale } = this; + const { messages, setFloatingEl, setContainerEl, open, scale } = this; const classes = { [CSS.listContainer]: true, [FloatingCSS.animation]: true, [FloatingCSS.animationActive]: open, }; + const label = this.filterText ? messages.add.replace("{text}", `${this.filterText}`) : ""; + return (
    @@ -1829,20 +1832,18 @@ export class Combobox /> )} - {this.noMatches === "add" && ( + {this.noMatches === "add" && this.filterText && (
  • - {messages.add - .split("{text}") - .map((part, index) => - index === 0 ? part : [{filterText}], - ) - .flat()} + {highlightText({ + text: label, + pattern: new RegExp(`(${escapeRegExp(this.filterText)})`, "i"), + })}
  • )} {this.noMatches === "none" &&
  • {messages.noMatches}
  • } From b56144b3cc46f6f0945cd5319e4ad92f927db3ce Mon Sep 17 00:00:00 2001 From: eliza Date: Thu, 31 Jul 2025 16:51:08 -0700 Subject: [PATCH 14/19] include text-highlight-item() mixin --- .../calcite-components/src/components/combobox/combobox.scss | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 34b98f9dd80..539c8daebeb 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -257,10 +257,6 @@ calcite-chip { color: var(--calcite-close-icon-color, var(--calcite-color-text-3)); background: var(--calcite-combobox-background-color, var(--calcite-color-foreground-1)); cursor: pointer; - - strong { - color: var(--calcite-combobox-input-text-color, var(--calcite-color-text-1)); - } } @include disabled(); @@ -272,6 +268,7 @@ calcite-chip { @include form-validation-message(); @include hidden-form-input(); @include base-component(); +@include text-highlight-item(); ::slotted(calcite-combobox-item-group:not(:first-child)) { padding-block-start: var(--calcite-internal-combobox-spacing-unit-l); From e6542f03117bd7d3387c3c31ed21ff8b9ce22e78 Mon Sep 17 00:00:00 2001 From: eliza Date: Fri, 1 Aug 2025 15:00:01 -0700 Subject: [PATCH 15/19] simplify conditional --- .../src/components/combobox/combobox.scss | 11 ++++- .../src/components/combobox/combobox.tsx | 40 +++++++++---------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 539c8daebeb..28f073b1f3b 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -13,6 +13,15 @@ * @prop --calcite-combobox-input-text-color: When `selectionDisplay` is `"single"`, specifies the text color of the component's input. */ +// AUTO-GENERATED — do not modify. Changes will be overwritten. +// +// Internal CSS custom properties for component use only. Overwriting is not recommended. +// +// --calcite-internal-close-size +// --calcite-internal-combobox-input-margin-block +// --calcite-internal-combobox-spacing-unit-l +// --calcite-internal-combobox-spacing-unit-s + :host { @apply relative block; } @@ -254,7 +263,7 @@ calcite-chip { padding-block: var(--calcite-internal-combobox-spacing-unit-s); padding-inline: var(--calcite-internal-combobox-spacing-unit-l); - color: var(--calcite-close-icon-color, var(--calcite-color-text-3)); + color: var(--calcite-combobox-input-text-color, var(--calcite-color-text-1)); background: var(--calcite-combobox-background-color, var(--calcite-color-foreground-1)); cursor: pointer; } diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index e1d4865f7cd..74301de067a 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -143,11 +143,7 @@ export class Combobox } }); - if (this.filteredItems.length === 0 && this.filterText) { - this.noMatches = this.allowCustomValues ? "add" : "none"; - } else { - this.noMatches = null; - } + this.noMatchesFound = this.filteredItems.length === 0 && !!this.filterText; this.filterTextMatchPattern = this.filterText && new RegExp(`(${escapeRegExp(this.filterText)})`, "i"); @@ -318,7 +314,7 @@ export class Combobox return filteredItems; } - @state() noMatches: "none" | "add" | null = null; + @state() noMatchesFound: boolean; //#endregion @@ -1832,21 +1828,23 @@ export class Combobox /> )} - {this.noMatches === "add" && this.filterText && ( -
  • - {highlightText({ - text: label, - pattern: new RegExp(`(${escapeRegExp(this.filterText)})`, "i"), - })} -
  • - )} - {this.noMatches === "none" &&
  • {messages.noMatches}
  • } + {this.noMatchesFound && + (this.allowCustomValues ? ( +
  • + {highlightText({ + text: label, + pattern: new RegExp(`(${escapeRegExp(this.filterText)})`, "i"), + })} +
  • + ) : ( +
  • {messages.noMatches}
  • + ))}
    From c3a34a2bb2165e4a76871bec6f71ff758e8d363b Mon Sep 17 00:00:00 2001 From: eliza Date: Fri, 1 Aug 2025 16:35:29 -0700 Subject: [PATCH 16/19] cleanup --- .../src/components/combobox/combobox.e2e.ts | 6 +----- .../calcite-components/src/components/combobox/combobox.tsx | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.e2e.ts b/packages/calcite-components/src/components/combobox/combobox.e2e.ts index d5319049303..05ddf88d38e 100644 --- a/packages/calcite-components/src/components/combobox/combobox.e2e.ts +++ b/packages/calcite-components/src/components/combobox/combobox.e2e.ts @@ -3365,12 +3365,8 @@ describe("calcite-combobox", () => { shadowSelector: `.${CSS.noMatches}`, targetProp: "backgroundColor", }, - "--calcite-close-icon-color": { - shadowSelector: `.${CSS.noMatches}`, - targetProp: "color", - }, "--calcite-combobox-input-text-color": { - shadowSelector: `.${CSS.noMatches} >>> strong`, + shadowSelector: `.${CSS.noMatches} >>> mark`, targetProp: "color", }, }, diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 74301de067a..bed68b82e8a 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1805,7 +1805,8 @@ export class Combobox [FloatingCSS.animationActive]: open, }; - const label = this.filterText ? messages.add.replace("{text}", `${this.filterText}`) : ""; + const label = + this.filterText && messages.add ? messages.add.replace("{text}", `${this.filterText}`) : ""; return (
    From 8cbf2a5f7304271a127d92342736a41e88834bba Mon Sep 17 00:00:00 2001 From: eliza Date: Fri, 1 Aug 2025 16:49:59 -0700 Subject: [PATCH 17/19] simplify conditional --- .../calcite-components/src/components/combobox/combobox.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index bed68b82e8a..b582657e85b 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1805,8 +1805,7 @@ export class Combobox [FloatingCSS.animationActive]: open, }; - const label = - this.filterText && messages.add ? messages.add.replace("{text}", `${this.filterText}`) : ""; + const label = (this.filterText && messages.add?.replace("{text}", `${this.filterText}`)) ?? ""; return (
    From 6a446d91ec75caa80f3ed425f5d165653114af5f Mon Sep 17 00:00:00 2001 From: eliza Date: Mon, 4 Aug 2025 11:31:09 -0700 Subject: [PATCH 18/19] no-matches-placeholder message text-3 --- .../calcite-components/src/components/combobox/combobox.scss | 4 ++++ .../calcite-components/src/components/combobox/combobox.tsx | 4 +++- .../calcite-components/src/components/combobox/resources.ts | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 28f073b1f3b..20f743a2bb8 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -268,6 +268,10 @@ calcite-chip { cursor: pointer; } +.no-matches-placeholder { + color: var(--calcite-combobox-icon-color, var(--calcite-color-text-3)); +} + @include disabled(); @include x-button( $background-color: "var(--calcite-close-background-color, var(--calcite-color-foreground-2))", diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index b582657e85b..779d150cda8 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1843,7 +1843,9 @@ export class Combobox })} ) : ( -
  • {messages.noMatches}
  • +
  • + {messages.noMatches} +
  • ))}
    diff --git a/packages/calcite-components/src/components/combobox/resources.ts b/packages/calcite-components/src/components/combobox/resources.ts index 6e9b217dbad..4135247240a 100644 --- a/packages/calcite-components/src/components/combobox/resources.ts +++ b/packages/calcite-components/src/components/combobox/resources.ts @@ -13,6 +13,7 @@ export const CSS = { labelIcon: "label--icon", listContainer: "list-container", noMatches: "no-matches", + noMatchesPlaceholder: "no-matches-placeholder", placeholderIcon: "placeholder-icon", selectAll: "select-all", selectionDisplayFit: "selection-display--fit", From edb459bb53d5e23fe5d4d3ee920a8c1bb1c1d271 Mon Sep 17 00:00:00 2001 From: eliza Date: Mon, 4 Aug 2025 13:34:28 -0700 Subject: [PATCH 19/19] default cursor for placeholder message --- .../calcite-components/src/components/combobox/combobox.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 20f743a2bb8..a4033dc2d33 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -270,6 +270,7 @@ calcite-chip { .no-matches-placeholder { color: var(--calcite-combobox-icon-color, var(--calcite-color-text-3)); + cursor: default; } @include disabled();