From 485f247e9bded7a4403ae40ca17564e049f35eb7 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 29 Sep 2023 16:38:06 -0700 Subject: [PATCH 01/70] feat(combobox): first commit introducing displayMode prop to limit rendered chips --- .../src/components/combobox/combobox.scss | 4 + .../src/components/combobox/combobox.tsx | 103 +++++++++++++++++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 388bbd217b1..43e0247bfeb 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -79,6 +79,10 @@ items-center truncate p-0; + + &.fit-to-line { + @apply flex-nowrap overflow-clip; + } } .input { diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index be4f5a0cb5d..62d0b734284 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -72,6 +72,8 @@ interface ItemData { value: string; } +type DisplayMode = "show-all" | "single" | "fit-to-line"; + const isGroup = (el: ComboboxChildElement): el is HTMLCalciteComboboxItemGroupElement => el.tagName === ComboboxItemGroup; @@ -111,6 +113,13 @@ export class Combobox */ @Prop({ reflect: true }) clearDisabled = false; + /** + * Controls the display behavior of multiple selected items. + * This property does not apply when selection-mode is set to "single". + * - "show-all" + */ + @Prop() displayMode: DisplayMode = "show-all"; + /**When `true`, displays and positions the component. */ @Prop({ reflect: true, mutable: true }) open = false; @@ -277,6 +286,7 @@ export class Combobox this.internalValueChangeFlag = true; this.value = this.getValue(); this.internalValueChangeFlag = false; + this.refreshDisplayMode(); } /** @@ -498,7 +508,10 @@ export class Combobox mutationObserver = createObserver("mutation", () => this.updateItems()); - resizeObserver = createObserver("resize", () => this.setMaxScrollerHeight()); + resizeObserver = createObserver("resize", () => { + this.setMaxScrollerHeight(); + this.refreshDisplayMode(); + }); private guid = guid(); @@ -508,6 +521,8 @@ export class Combobox private referenceEl: HTMLDivElement; + private inputContainerEl: HTMLDivElement; + private listContainerEl: HTMLDivElement; private ignoreSelectedEventsFlag = false; @@ -516,6 +531,8 @@ export class Combobox transitionEl: HTMLDivElement; + private selectedIndicatorChipEl: HTMLCalciteChipElement; + // -------------------------------------------------------------------------- // // Private Methods @@ -761,6 +778,58 @@ export class Combobox this.updateActiveItemIndex(targetIndex); } + private getComputedElementWidth(el: HTMLElement): number { + if (!el) { + return; + } + return Math.round(parseFloat(getComputedStyle(el).width.replace("px", ""))); + } + + private getRenderedTextWidth(text: string, font: string): number { + if (!text) { + return; + } + const canvas = document.createElement("canvas"); + const context = canvas.getContext("2d"); + context.font = font; + return Math.ceil(context.measureText(text).width); + } + + private refreshDisplayMode = () => { + if (this.textInput && !isSingleLike(this.selectionMode) && this.displayMode === "fit-to-line") { + const chipEls = this.el.shadowRoot.querySelectorAll("calcite-chip"); + const computedInputStyle = getComputedStyle(this.textInput); + const placeholderTextWidth = this.getRenderedTextWidth( + this.placeholder, + `${computedInputStyle.fontSize} ${computedInputStyle.fontFamily}` + ); + const inputContainerElWidth = this.getComputedElementWidth(this.inputContainerEl); + const selectedIndicatorChipElWidth = this.getComputedElementWidth( + this.selectedIndicatorChipEl + ); + let availableHorizontalChipElSpace = Math.round(inputContainerElWidth - placeholderTextWidth); + + chipEls.forEach((chipEl: HTMLCalciteChipElement) => { + const chipElWidth = this.getComputedElementWidth(chipEl); + if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { + availableHorizontalChipElSpace -= chipElWidth; + this.selectedIndicatorChipEl.style.position = "absolute"; + this.selectedIndicatorChipEl.style.visibility = "hidden"; + } else { + // TODO: Hide any overflowing chips here + if ( + selectedIndicatorChipElWidth && + selectedIndicatorChipElWidth < availableHorizontalChipElSpace + ) { + availableHorizontalChipElSpace -= selectedIndicatorChipElWidth; + this.selectedIndicatorChipEl.style.position = "static"; + this.selectedIndicatorChipEl.style.visibility = "visible"; + } + } + }); + } + }; + setInactiveIfNotContained = (event: Event): void => { const composedPath = event.composedPath(); @@ -792,11 +861,20 @@ export class Combobox this.transitionEl = el; }; + setInputContainerEl = (el: HTMLDivElement): void => { + this.resizeObserver.observe(el); + this.inputContainerEl = el; + }; + setReferenceEl = (el: HTMLDivElement): void => { this.referenceEl = el; connectFloatingUI(this, this.referenceEl, this.floatingEl); }; + setSelectedIndicatorChipEl = (el: HTMLCalciteChipElement): void => { + this.selectedIndicatorChipEl = el; + }; + private getMaxScrollerHeight(): number { const items = this.getItemsAndGroups().filter((item) => !item.hidden); @@ -1186,6 +1264,22 @@ export class Combobox }); } + renderSelectedIndicatorChip(): VNode { + const label = `+${this.selectedItems.length}`; + return ( + + {label} + + ); + } + renderInput(): VNode { const { guid, disabled, placeholder, selectionMode, selectedItems, open } = this; const single = isSingleLike(selectionMode); @@ -1319,6 +1413,7 @@ export class Combobox const { guid, label, open } = this; const single = isSingleLike(this.selectionMode); const isClearable = !this.clearDisabled && this.value?.length > 0; + const isFitToLine = !single && this.displayMode === "fit-to-line"; return ( @@ -1341,9 +1436,13 @@ export class Combobox // eslint-disable-next-line react/jsx-sort-props -- ref should be last so node attrs/props are in sync (see https://github.com/Esri/calcite-design-system/pull/6530) ref={this.setReferenceEl} > -
+
{this.renderIconStart()} {!single && this.renderChips()} + {!single && this.renderSelectedIndicatorChip()}
+ +
+
Multi select (single display-mode)
+ +
+ label + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ label + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ label + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
Multi select (fit-to-line display-mode)
+ +
+ label + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ label + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ label + + + + + + + + + + + + + + + + + + + + + + +
+
+
Multi select with groups
From 8223f8b38b2171cded3dee1b14a8a5a4ac1a459c Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Tue, 10 Oct 2023 15:35:29 -0700 Subject: [PATCH 14/70] disabling chip's close animation from the combobox styles --- packages/calcite-components/src/components/chip/chip.scss | 1 + .../calcite-components/src/components/combobox/combobox.scss | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/calcite-components/src/components/chip/chip.scss b/packages/calcite-components/src/components/chip/chip.scss index db263afcc73..60d49810bc4 100644 --- a/packages/calcite-components/src/components/chip/chip.scss +++ b/packages/calcite-components/src/components/chip/chip.scss @@ -153,6 +153,7 @@ .close { @apply focus-base + transition-default text-color-1 m-0 cursor-pointer diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 0ab61333017..850b53e8424 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -203,6 +203,10 @@ @apply h-0 overflow-hidden; } +calcite-chip { + --calcite-animation-timing: 0; +} + .chip { margin-block: calc(var(--calcite-combobox-item-spacing-unit-s) / 4); max-inline-size: 100%; From 69625126e426191eef34288dadf7a103345dec15 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Tue, 10 Oct 2023 15:58:42 -0700 Subject: [PATCH 15/70] refactoring away from inline styles to adding css classes to toggle chip visibility --- .../src/components/combobox/combobox.tsx | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 2c9c3dc1b81..d214e8bc5f5 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -791,15 +791,13 @@ export class Combobox } private hideChip(chipEl: HTMLCalciteChipElement): void { - chipEl.style.display = "inline-block"; - chipEl.style.position = "absolute"; - chipEl.style.visibility = "hidden"; + chipEl.classList.remove(CSS.chipVisible); + chipEl.classList.add(CSS.chipInvisible); } private showChip(chipEl: HTMLCalciteChipElement): void { - chipEl.style.display = "inline-block"; - chipEl.style.position = "static"; - chipEl.style.visibility = "visible"; + chipEl.classList.remove(CSS.chipInvisible); + chipEl.classList.add(CSS.chipVisible); } private refreshDisplayMode = () => { @@ -841,7 +839,7 @@ export class Combobox if (chipEl === this.selectedIndicatorChipEl) { return; } - if (chipEl.selected && chipEl.style.visibility === "visible") { + if (chipEl.selected && getComputedStyle(chipEl).visibility === "visible") { selectedVisibleChipsCount++; } }); @@ -1265,8 +1263,6 @@ export class Combobox const ancestors = [...getItemAncestors(item)].reverse(); const pathLabel = [...ancestors, item].map((el) => el.textLabel); const label = selectionMode !== "ancestors" ? item.textLabel : pathLabel.join(" / "); - const style = - displayMode === "fit-to-line" ? { position: "absolute", visibility: "hidden" } : undefined; return ( this.calciteChipCloseHandler(item)} scale={scale} selected={item.selected} - style={style} title={label} value={item.value} > From 649f546f609733ba5b41c6c921850787f9c0a496 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Tue, 10 Oct 2023 16:08:08 -0700 Subject: [PATCH 16/70] adding additional info about rest of displayMode prop options --- .../calcite-components/src/components/combobox/combobox.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index d214e8bc5f5..63603d943a2 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -121,7 +121,9 @@ export class Combobox /** * Controls the display behavior of multiple selected items. * This property does not apply when selection-mode is set to "single". - * - "show-all" + * - "show-all" displays every selected chip, wrapping to the next line if necessary + * - "single" displays a single chip indicating the total amount of selected items + * - "fit-to-line" only displays selected chips that fit horizontally, with a non-closable chip indicating additional selected items as needed */ @Prop() displayMode: DisplayMode = "show-all"; From a9283015f0ebef24101ab7d2a07735793316bc57 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Tue, 10 Oct 2023 16:10:22 -0700 Subject: [PATCH 17/70] adding single-persist to doc comment --- .../calcite-components/src/components/combobox/combobox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 63603d943a2..db4f7098cdb 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -120,7 +120,7 @@ export class Combobox /** * Controls the display behavior of multiple selected items. - * This property does not apply when selection-mode is set to "single". + * This property does not apply when selection-mode is set to "single" or "single-persist". * - "show-all" displays every selected chip, wrapping to the next line if necessary * - "single" displays a single chip indicating the total amount of selected items * - "fit-to-line" only displays selected chips that fit horizontally, with a non-closable chip indicating additional selected items as needed From 3580a8f97fc6e457adc02661c6de450855f19ad7 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 12 Oct 2023 14:19:38 -0700 Subject: [PATCH 18/70] calling refreshDisplayMode in componentDidLoad --- packages/calcite-components/src/components/combobox/combobox.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index e81e55f23ac..0dae71b03c7 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -437,6 +437,7 @@ export class Combobox afterConnectDefaultValueSet(this, this.getValue()); this.reposition(true); setComponentLoaded(this); + this.refreshDisplayMode(); } componentDidRender(): void { From 4214b81d6f075b67c3b93609ac71c0c8e943a7d7 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 12 Oct 2023 15:41:13 -0700 Subject: [PATCH 19/70] setting chip container div to relative positioning --- .../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 850b53e8424..6bed9a70dd1 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -77,6 +77,7 @@ flex-grow flex-wrap items-center + relative truncate p-0; From edc8445eba896c87b0dcb51a970efc7694d3fea9 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 13 Oct 2023 14:35:31 -0700 Subject: [PATCH 20/70] checking presence of visible and invisible css classes instead of using getComputedStyle --- .../calcite-components/src/components/combobox/combobox.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 0dae71b03c7..70964978ce5 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -842,7 +842,11 @@ export class Combobox if (chipEl === this.selectedIndicatorChipEl) { return; } - if (chipEl.selected && getComputedStyle(chipEl).visibility === "visible") { + if ( + chipEl.selected && + chipEl.classList.contains(CSS.chipVisible) && + !chipEl.classList.contains(CSS.chipInvisible) + ) { selectedVisibleChipsCount++; } }); From 9f43743dba549754f47c846e8981f92ffe6751be Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 13 Oct 2023 14:40:17 -0700 Subject: [PATCH 21/70] updating stories to add new display modes --- .../components/combobox/combobox.stories.ts | 212 +++++++++++++++--- 1 file changed, 183 insertions(+), 29 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.stories.ts b/packages/calcite-components/src/components/combobox/combobox.stories.ts index 178a8f5d2aa..1031c1a0e4c 100644 --- a/packages/calcite-components/src/components/combobox/combobox.stories.ts +++ b/packages/calcite-components/src/components/combobox/combobox.stories.ts @@ -13,10 +13,39 @@ export default { ...storyFilters(), }; -export const simple = (): string => html` +export const single = (): string => html` +
+ + + + + + + + + + + + + + + +
+`; + +export const multiple = (): string => html`
html` max-items="${number("max-items", 0)}" > - + - + - + @@ -48,37 +77,119 @@ export const simple = (): string => html`
`; -export const single = (): string => html` -
+export const multipleShowAll = (): string => html` +
- - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +
`; -export const multiple = (): string => html` +export const multipleFitToLine = (): string => html` +
+ + + + + + + + + + + + + + + + + + + + +
+`; + +export const multipleFitToLineAllSelected = (): string => html` +
+ + + + + + + + + + + + + + + + + + + + +
+`; + +export const multipleSingle = (): string => html`
html` ${boolean("allow-custom-values", false)} max-items="${number("max-items", 0)}" > - - - + + + + + + + + + + + + + + + - + +
+`; + +export const multipleSingleAllSelected = (): string => html` +
+ + + + + + + + + + + + + + + + + + +
`; From a01f3c075c0d2ebb714f964454f4ad78b4fd89e8 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 13 Oct 2023 16:10:47 -0700 Subject: [PATCH 22/70] handling case when placeholder text isn't supplied by providing a fallback width of 50px and also adding the chip gap into the width calculation --- .../src/components/combobox/combobox.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 70964978ce5..ab43beb642a 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -811,13 +811,17 @@ export class Combobox return; } if (this.displayMode === "fit-to-line") { - const chipEls = this.el.shadowRoot.querySelectorAll(`calcite-chip`); + const chipEls = this.el.shadowRoot.querySelectorAll("calcite-chip"); const { fontSize, fontFamily } = getComputedStyle(this.textInput); - const placeholderTextWidth = getTextWidth(this.placeholder, `${fontSize} ${fontFamily}`); const inputContainerElWidth = getElementWidth(this.inputContainerEl); + const inputContainerElGap = parseInt( + getComputedStyle(this.inputContainerEl).gap.replace("px", "") + ); + const inputTextWidth = getTextWidth(this.placeholder, `${fontSize} ${fontFamily}`) || 50; const selectedIndicatorChipElWidth = getElementWidth(this.selectedIndicatorChipEl); let availableHorizontalChipElSpace = Math.round( - inputContainerElWidth - (placeholderTextWidth + selectedIndicatorChipElWidth) + inputContainerElWidth - + (selectedIndicatorChipElWidth + inputContainerElGap + inputTextWidth) ); chipEls.forEach((chipEl: HTMLCalciteChipElement) => { @@ -827,7 +831,7 @@ export class Combobox if (chipEl.selected) { const chipElWidth = getElementWidth(chipEl); if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { - availableHorizontalChipElSpace -= chipElWidth; + availableHorizontalChipElSpace -= chipElWidth + inputContainerElGap; this.showChip(chipEl); } else { this.hideChip(chipEl); From 213f14954137026917dc1cd7b7567d94f72b4ee2 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 13 Oct 2023 16:36:17 -0700 Subject: [PATCH 23/70] DRYing up the chipEls selector results to filter out the indicator chip and also fixing the all selected mode in fit-to-line --- .../src/components/combobox/combobox.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index ab43beb642a..9b0f4484ccb 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -811,7 +811,9 @@ export class Combobox return; } if (this.displayMode === "fit-to-line") { - const chipEls = this.el.shadowRoot.querySelectorAll("calcite-chip"); + const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( + (chipEl) => chipEl !== this.selectedIndicatorChipEl + ); const { fontSize, fontFamily } = getComputedStyle(this.textInput); const inputContainerElWidth = getElementWidth(this.inputContainerEl); const inputContainerElGap = parseInt( @@ -825,12 +827,13 @@ export class Combobox ); chipEls.forEach((chipEl: HTMLCalciteChipElement) => { - if (chipEl === this.selectedIndicatorChipEl) { - return; - } if (chipEl.selected) { const chipElWidth = getElementWidth(chipEl); - if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { + if ( + chipElWidth && + chipElWidth < availableHorizontalChipElSpace && + this.getItems().length !== this.getSelectedItems().length + ) { availableHorizontalChipElSpace -= chipElWidth + inputContainerElGap; this.showChip(chipEl); } else { @@ -843,9 +846,6 @@ export class Combobox let selectedVisibleChipsCount = 0; chipEls.forEach((chipEl) => { - if (chipEl === this.selectedIndicatorChipEl) { - return; - } if ( chipEl.selected && chipEl.classList.contains(CSS.chipVisible) && From 985f59927308950b0387cdd58818d746d4061552 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 26 Oct 2023 15:54:48 -0700 Subject: [PATCH 24/70] refactor to use IntersectionObserver --- .../src/components/combobox/combobox.scss | 11 +- .../src/components/combobox/combobox.tsx | 213 ++++++++---------- .../src/components/combobox/resources.ts | 2 +- 3 files changed, 101 insertions(+), 125 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 6bed9a70dd1..7b1159b4ca4 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -74,7 +74,6 @@ .grid-input { @apply flex - flex-grow flex-wrap items-center relative @@ -101,6 +100,7 @@ line-height: var(--calcite-combobox-input-height); inline-size: 100%; margin-block-end: var(--calcite-combobox-item-spacing-unit-s); + min-inline-size: 50px; &:focus { @apply outline-none; } @@ -210,19 +210,18 @@ calcite-chip { .chip { margin-block: calc(var(--calcite-combobox-item-spacing-unit-s) / 4); - max-inline-size: 100%; } .chip--active { @apply bg-foreground-3; } -.chip--invisible { - @apply absolute invisible; +.chip--hidden { + @apply hidden; } -.chip--visible { - @apply inline-block static visible; +.chip--invisible { + @apply invisible; } .item { diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 9b0f4484ccb..e1100735fef 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -15,12 +15,7 @@ import { import { debounce } from "lodash-es"; import { filter } from "../../utils/filter"; -import { - getElementWidth, - getTextWidth, - isPrimaryPointerButton, - toAriaBoolean, -} from "../../utils/dom"; +import { isPrimaryPointerButton, toAriaBoolean } from "../../utils/dom"; import { connectFloatingUI, defaultMenuPlacement, @@ -425,6 +420,13 @@ export class Combobox this.openHandler(); onToggleOpenCloseComponent(this); } + + if (this.displayMode === "fit-to-line") { + this.intersectionObserver = createObserver("intersection", this.intersectionHandler, { + root: this.inputContainerEl, + threshold: 1, + }); + } } async componentWillLoad(): Promise { @@ -437,7 +439,9 @@ export class Combobox afterConnectDefaultValueSet(this, this.getValue()); this.reposition(true); setComponentLoaded(this); - this.refreshDisplayMode(); + if (this.displayMode === "fit-to-line") { + this.intersectionObserveChips(); + } } componentDidRender(): void { @@ -447,10 +451,10 @@ export class Combobox } updateHostInteraction(this); - } - componentDidUpdate(): void { - this.refreshDisplayMode(); + if (this.displayMode === "fit-to-line") { + this.intersectionObserveChips(); + } } disconnectedCallback(): void { @@ -521,12 +525,11 @@ export class Combobox data: ItemData[]; + intersectionObserver: IntersectionObserver; + mutationObserver = createObserver("mutation", () => this.updateItems()); - resizeObserver = createObserver("resize", () => { - this.setMaxScrollerHeight(); - this.refreshDisplayMode(); - }); + resizeObserver = createObserver("resize", () => this.setMaxScrollerHeight()); private guid = guid(); @@ -793,72 +796,6 @@ export class Combobox this.updateActiveItemIndex(targetIndex); } - private hideChip(chipEl: HTMLCalciteChipElement): void { - chipEl.classList.remove(CSS.chipVisible); - chipEl.classList.add(CSS.chipInvisible); - } - - private showChip(chipEl: HTMLCalciteChipElement): void { - chipEl.classList.remove(CSS.chipInvisible); - chipEl.classList.add(CSS.chipVisible); - } - - private refreshDisplayMode = () => { - if (isSingleLike(this.selectionMode)) { - return; - } - if (!this.textInput) { - return; - } - if (this.displayMode === "fit-to-line") { - const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( - (chipEl) => chipEl !== this.selectedIndicatorChipEl - ); - const { fontSize, fontFamily } = getComputedStyle(this.textInput); - const inputContainerElWidth = getElementWidth(this.inputContainerEl); - const inputContainerElGap = parseInt( - getComputedStyle(this.inputContainerEl).gap.replace("px", "") - ); - const inputTextWidth = getTextWidth(this.placeholder, `${fontSize} ${fontFamily}`) || 50; - const selectedIndicatorChipElWidth = getElementWidth(this.selectedIndicatorChipEl); - let availableHorizontalChipElSpace = Math.round( - inputContainerElWidth - - (selectedIndicatorChipElWidth + inputContainerElGap + inputTextWidth) - ); - - chipEls.forEach((chipEl: HTMLCalciteChipElement) => { - if (chipEl.selected) { - const chipElWidth = getElementWidth(chipEl); - if ( - chipElWidth && - chipElWidth < availableHorizontalChipElSpace && - this.getItems().length !== this.getSelectedItems().length - ) { - availableHorizontalChipElSpace -= chipElWidth + inputContainerElGap; - this.showChip(chipEl); - } else { - this.hideChip(chipEl); - } - } else { - this.hideChip(chipEl); - } - }); - - let selectedVisibleChipsCount = 0; - chipEls.forEach((chipEl) => { - if ( - chipEl.selected && - chipEl.classList.contains(CSS.chipVisible) && - !chipEl.classList.contains(CSS.chipInvisible) - ) { - selectedVisibleChipsCount++; - } - }); - this.selectedHiddenChipsCount = this.getSelectedItems().length - selectedVisibleChipsCount; - this.selectedVisibleChipsCount = selectedVisibleChipsCount; - } - }; - private setInactiveIfNotContained = (event: Event): void => { const composedPath = event.composedPath(); @@ -1257,6 +1194,32 @@ export class Combobox this.setInactiveIfNotContained(event); }; + private intersectionHandler = (entries): void => { + entries.forEach(({ target, isIntersecting }) => { + target.classList.toggle(CSS.chipInvisible, !isIntersecting); + }); + let selectedHiddenChipsCount = 0; + let selectedVisibleChipsCount = 0; + const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( + (chipEl) => chipEl !== this.selectedIndicatorChipEl + ); + chipEls.forEach((chipEl) => { + if (chipEl.classList.contains(CSS.chipInvisible)) { + selectedHiddenChipsCount++; + } else { + selectedVisibleChipsCount++; + } + }); + this.selectedHiddenChipsCount = selectedHiddenChipsCount; + this.selectedVisibleChipsCount = selectedVisibleChipsCount; + }; + + private intersectionObserveChips(): void { + Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")) + .filter((chipEl) => chipEl !== this.selectedIndicatorChipEl) + .forEach((chipEl) => this.intersectionObserver.observe(chipEl)); + } + //-------------------------------------------------------------------------- // // Render Methods @@ -1264,9 +1227,8 @@ export class Combobox //-------------------------------------------------------------------------- renderChips(): VNode[] { - const { activeChipIndex, displayMode, scale, selectionMode, messages } = this; - const items = displayMode === "fit-to-line" ? this.items : this.selectedItems; - return items.map((item, i) => { + const { activeChipIndex, scale, selectionMode, messages } = this; + return this.selectedItems.map((item, i) => { const chipClasses = { chip: true, "chip--active": activeChipIndex === i, @@ -1285,7 +1247,6 @@ export class Combobox messageOverrides={{ dismissLabel: messages.removeTag }} onCalciteChipClose={() => this.calciteChipCloseHandler(item)} scale={scale} - selected={item.selected} title={label} value={item.value} > @@ -1295,38 +1256,6 @@ export class Combobox }); } - renderSelectedIndicatorChip(): VNode { - const { - displayMode, - scale, - selectedHiddenChipsCount, - selectedVisibleChipsCount, - setSelectedIndicatorChipEl, - } = this; - let label; - if (this.getItems().length === this.getSelectedItems().length) { - label = "All selected"; - } else if (displayMode === "fit-to-line" && selectedHiddenChipsCount > 0) { - label = - selectedVisibleChipsCount > 0 - ? `+${selectedHiddenChipsCount}` - : `${selectedHiddenChipsCount} selected`; - } else if (displayMode === "single" && this.getSelectedItems().length > 0) { - label = `${this.selectedItems.length} selected`; - } - return ( - - {label} - - ); - } - renderInput(): VNode { const { guid, disabled, placeholder, selectionMode, selectedItems, open } = this; const single = isSingleLike(selectionMode); @@ -1456,6 +1385,54 @@ export class Combobox ); } + renderSelectedIndicatorChip(): VNode { + const { + displayMode, + scale, + selectedHiddenChipsCount, + selectedVisibleChipsCount, + setSelectedIndicatorChipEl, + } = this; + + const itemsCount = this.getItems().length; + const selectedItemsCount = this.getSelectedItems().length; + + let label; + let hideChip = false; + + const allItemsSelected = itemsCount === selectedItemsCount; + + if (displayMode === "single") { + label = allItemsSelected + ? "All selected" + : selectedItemsCount + ? `${this.selectedItems.length} selected` + : ""; + } else if (displayMode === "fit-to-line") { + if (allItemsSelected && !selectedVisibleChipsCount) { + label = "All selected"; + } else { + label = + selectedVisibleChipsCount > 0 + ? `+${selectedHiddenChipsCount}` + : `${selectedHiddenChipsCount} selected`; + hideChip = !selectedHiddenChipsCount; + } + } + + return ( + + {label} + + ); + } + render(): VNode { const { displayMode, guid, label, open } = this; const singleSelectionMode = isSingleLike(this.selectionMode); @@ -1491,7 +1468,6 @@ export class Combobox > {this.renderIconStart()} {!singleSelectionMode && !singleDisplayMode && this.renderChips()} - {!singleSelectionMode && !showAllDisplayMode && this.renderSelectedIndicatorChip()} - {this.renderInput()}
+ {!singleSelectionMode && !showAllDisplayMode && this.renderSelectedIndicatorChip()} + {this.renderInput()} {isClearable ? ( Date: Thu, 26 Oct 2023 15:57:30 -0700 Subject: [PATCH 25/70] renaming inputContainer to chipContainer --- .../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 e1100735fef..defde084eb6 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -423,7 +423,7 @@ export class Combobox if (this.displayMode === "fit-to-line") { this.intersectionObserver = createObserver("intersection", this.intersectionHandler, { - root: this.inputContainerEl, + root: this.chipContainerEl, threshold: 1, }); } @@ -539,7 +539,7 @@ export class Combobox private referenceEl: HTMLDivElement; - private inputContainerEl: HTMLDivElement; + private chipContainerEl: HTMLDivElement; private listContainerEl: HTMLDivElement; @@ -827,9 +827,9 @@ export class Combobox this.transitionEl = el; }; - setInputContainerEl = (el: HTMLDivElement): void => { + setChipContainerEl = (el: HTMLDivElement): void => { this.resizeObserver.observe(el); - this.inputContainerEl = el; + this.chipContainerEl = el; }; setReferenceEl = (el: HTMLDivElement): void => { @@ -1464,7 +1464,7 @@ export class Combobox >
{this.renderIconStart()} {!singleSelectionMode && !singleDisplayMode && this.renderChips()} From d4489e3716084901158e59c5ec78514b60234e1d Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 27 Oct 2023 15:56:22 -0700 Subject: [PATCH 26/70] Revert "refactor to use IntersectionObserver" This reverts commit 985f59927308950b0387cdd58818d746d4061552. --- .../src/components/combobox/combobox.scss | 11 +- .../src/components/combobox/combobox.tsx | 212 ++++++++++-------- .../src/components/combobox/resources.ts | 2 +- 3 files changed, 124 insertions(+), 101 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 7b1159b4ca4..6bed9a70dd1 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -74,6 +74,7 @@ .grid-input { @apply flex + flex-grow flex-wrap items-center relative @@ -100,7 +101,6 @@ line-height: var(--calcite-combobox-input-height); inline-size: 100%; margin-block-end: var(--calcite-combobox-item-spacing-unit-s); - min-inline-size: 50px; &:focus { @apply outline-none; } @@ -210,18 +210,19 @@ calcite-chip { .chip { margin-block: calc(var(--calcite-combobox-item-spacing-unit-s) / 4); + max-inline-size: 100%; } .chip--active { @apply bg-foreground-3; } -.chip--hidden { - @apply hidden; +.chip--invisible { + @apply absolute invisible; } -.chip--invisible { - @apply invisible; +.chip--visible { + @apply inline-block static visible; } .item { diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index defde084eb6..0602dfd0012 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -15,7 +15,12 @@ import { import { debounce } from "lodash-es"; import { filter } from "../../utils/filter"; -import { isPrimaryPointerButton, toAriaBoolean } from "../../utils/dom"; +import { + getElementWidth, + getTextWidth, + isPrimaryPointerButton, + toAriaBoolean, +} from "../../utils/dom"; import { connectFloatingUI, defaultMenuPlacement, @@ -420,13 +425,6 @@ export class Combobox this.openHandler(); onToggleOpenCloseComponent(this); } - - if (this.displayMode === "fit-to-line") { - this.intersectionObserver = createObserver("intersection", this.intersectionHandler, { - root: this.chipContainerEl, - threshold: 1, - }); - } } async componentWillLoad(): Promise { @@ -439,9 +437,7 @@ export class Combobox afterConnectDefaultValueSet(this, this.getValue()); this.reposition(true); setComponentLoaded(this); - if (this.displayMode === "fit-to-line") { - this.intersectionObserveChips(); - } + this.refreshDisplayMode(); } componentDidRender(): void { @@ -451,10 +447,10 @@ export class Combobox } updateHostInteraction(this); + } - if (this.displayMode === "fit-to-line") { - this.intersectionObserveChips(); - } + componentDidUpdate(): void { + this.refreshDisplayMode(); } disconnectedCallback(): void { @@ -525,11 +521,12 @@ export class Combobox data: ItemData[]; - intersectionObserver: IntersectionObserver; - mutationObserver = createObserver("mutation", () => this.updateItems()); - resizeObserver = createObserver("resize", () => this.setMaxScrollerHeight()); + resizeObserver = createObserver("resize", () => { + this.setMaxScrollerHeight(); + this.refreshDisplayMode(); + }); private guid = guid(); @@ -796,6 +793,71 @@ export class Combobox this.updateActiveItemIndex(targetIndex); } + private hideChip(chipEl: HTMLCalciteChipElement): void { + chipEl.classList.remove(CSS.chipVisible); + chipEl.classList.add(CSS.chipInvisible); + } + + private showChip(chipEl: HTMLCalciteChipElement): void { + chipEl.classList.remove(CSS.chipInvisible); + chipEl.classList.add(CSS.chipVisible); + } + + private refreshDisplayMode = () => { + if (isSingleLike(this.selectionMode)) { + return; + } + if (!this.textInput) { + return; + } + if (this.displayMode === "fit-to-line") { + const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( + (chipEl) => chipEl !== this.selectedIndicatorChipEl + ); + const { fontSize, fontFamily } = getComputedStyle(this.textInput); + const chipContainerElWidth = getElementWidth(this.chipContainerEl); + const chipContainerElGap = parseInt( + getComputedStyle(this.chipContainerEl).gap.replace("px", "") + ); + const inputTextWidth = getTextWidth(this.placeholder, `${fontSize} ${fontFamily}`) || 50; + const selectedIndicatorChipElWidth = getElementWidth(this.selectedIndicatorChipEl); + let availableHorizontalChipElSpace = Math.round( + chipContainerElWidth - (selectedIndicatorChipElWidth + chipContainerElGap + inputTextWidth) + ); + + chipEls.forEach((chipEl: HTMLCalciteChipElement) => { + if (chipEl.selected) { + const chipElWidth = getElementWidth(chipEl); + if ( + chipElWidth && + chipElWidth < availableHorizontalChipElSpace && + this.getItems().length !== this.getSelectedItems().length + ) { + availableHorizontalChipElSpace -= chipElWidth + chipContainerElGap; + this.showChip(chipEl); + } else { + this.hideChip(chipEl); + } + } else { + this.hideChip(chipEl); + } + }); + + let selectedVisibleChipsCount = 0; + chipEls.forEach((chipEl) => { + if ( + chipEl.selected && + chipEl.classList.contains(CSS.chipVisible) && + !chipEl.classList.contains(CSS.chipInvisible) + ) { + selectedVisibleChipsCount++; + } + }); + this.selectedHiddenChipsCount = this.getSelectedItems().length - selectedVisibleChipsCount; + this.selectedVisibleChipsCount = selectedVisibleChipsCount; + } + }; + private setInactiveIfNotContained = (event: Event): void => { const composedPath = event.composedPath(); @@ -1194,32 +1256,6 @@ export class Combobox this.setInactiveIfNotContained(event); }; - private intersectionHandler = (entries): void => { - entries.forEach(({ target, isIntersecting }) => { - target.classList.toggle(CSS.chipInvisible, !isIntersecting); - }); - let selectedHiddenChipsCount = 0; - let selectedVisibleChipsCount = 0; - const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( - (chipEl) => chipEl !== this.selectedIndicatorChipEl - ); - chipEls.forEach((chipEl) => { - if (chipEl.classList.contains(CSS.chipInvisible)) { - selectedHiddenChipsCount++; - } else { - selectedVisibleChipsCount++; - } - }); - this.selectedHiddenChipsCount = selectedHiddenChipsCount; - this.selectedVisibleChipsCount = selectedVisibleChipsCount; - }; - - private intersectionObserveChips(): void { - Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")) - .filter((chipEl) => chipEl !== this.selectedIndicatorChipEl) - .forEach((chipEl) => this.intersectionObserver.observe(chipEl)); - } - //-------------------------------------------------------------------------- // // Render Methods @@ -1227,8 +1263,9 @@ export class Combobox //-------------------------------------------------------------------------- renderChips(): VNode[] { - const { activeChipIndex, scale, selectionMode, messages } = this; - return this.selectedItems.map((item, i) => { + const { activeChipIndex, displayMode, scale, selectionMode, messages } = this; + const items = displayMode === "fit-to-line" ? this.items : this.selectedItems; + return items.map((item, i) => { const chipClasses = { chip: true, "chip--active": activeChipIndex === i, @@ -1247,6 +1284,7 @@ export class Combobox messageOverrides={{ dismissLabel: messages.removeTag }} onCalciteChipClose={() => this.calciteChipCloseHandler(item)} scale={scale} + selected={item.selected} title={label} value={item.value} > @@ -1256,6 +1294,38 @@ export class Combobox }); } + renderSelectedIndicatorChip(): VNode { + const { + displayMode, + scale, + selectedHiddenChipsCount, + selectedVisibleChipsCount, + setSelectedIndicatorChipEl, + } = this; + let label; + if (this.getItems().length === this.getSelectedItems().length) { + label = "All selected"; + } else if (displayMode === "fit-to-line" && selectedHiddenChipsCount > 0) { + label = + selectedVisibleChipsCount > 0 + ? `+${selectedHiddenChipsCount}` + : `${selectedHiddenChipsCount} selected`; + } else if (displayMode === "single" && this.getSelectedItems().length > 0) { + label = `${this.selectedItems.length} selected`; + } + return ( + + {label} + + ); + } + renderInput(): VNode { const { guid, disabled, placeholder, selectionMode, selectedItems, open } = this; const single = isSingleLike(selectionMode); @@ -1385,54 +1455,6 @@ export class Combobox ); } - renderSelectedIndicatorChip(): VNode { - const { - displayMode, - scale, - selectedHiddenChipsCount, - selectedVisibleChipsCount, - setSelectedIndicatorChipEl, - } = this; - - const itemsCount = this.getItems().length; - const selectedItemsCount = this.getSelectedItems().length; - - let label; - let hideChip = false; - - const allItemsSelected = itemsCount === selectedItemsCount; - - if (displayMode === "single") { - label = allItemsSelected - ? "All selected" - : selectedItemsCount - ? `${this.selectedItems.length} selected` - : ""; - } else if (displayMode === "fit-to-line") { - if (allItemsSelected && !selectedVisibleChipsCount) { - label = "All selected"; - } else { - label = - selectedVisibleChipsCount > 0 - ? `+${selectedHiddenChipsCount}` - : `${selectedHiddenChipsCount} selected`; - hideChip = !selectedHiddenChipsCount; - } - } - - return ( - - {label} - - ); - } - render(): VNode { const { displayMode, guid, label, open } = this; const singleSelectionMode = isSingleLike(this.selectionMode); @@ -1468,6 +1490,7 @@ export class Combobox > {this.renderIconStart()} {!singleSelectionMode && !singleDisplayMode && this.renderChips()} + {!singleSelectionMode && !showAllDisplayMode && this.renderSelectedIndicatorChip()} + {this.renderInput()}
- {!singleSelectionMode && !showAllDisplayMode && this.renderSelectedIndicatorChip()} - {this.renderInput()} {isClearable ? ( Date: Mon, 30 Oct 2023 12:06:43 -0700 Subject: [PATCH 27/70] fixing display logic for the indicator chip in single, fit-to-line modes --- .../src/components/combobox/combobox.scss | 4 --- .../src/components/combobox/combobox.tsx | 26 +++++++------------ .../src/components/combobox/resources.ts | 1 - 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 6bed9a70dd1..1c4aff7689e 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -221,10 +221,6 @@ calcite-chip { @apply absolute invisible; } -.chip--visible { - @apply inline-block static visible; -} - .item { @apply block; } diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 0602dfd0012..73142323f19 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -794,13 +794,11 @@ export class Combobox } private hideChip(chipEl: HTMLCalciteChipElement): void { - chipEl.classList.remove(CSS.chipVisible); chipEl.classList.add(CSS.chipInvisible); } private showChip(chipEl: HTMLCalciteChipElement): void { chipEl.classList.remove(CSS.chipInvisible); - chipEl.classList.add(CSS.chipVisible); } private refreshDisplayMode = () => { @@ -828,11 +826,7 @@ export class Combobox chipEls.forEach((chipEl: HTMLCalciteChipElement) => { if (chipEl.selected) { const chipElWidth = getElementWidth(chipEl); - if ( - chipElWidth && - chipElWidth < availableHorizontalChipElSpace && - this.getItems().length !== this.getSelectedItems().length - ) { + if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { availableHorizontalChipElSpace -= chipElWidth + chipContainerElGap; this.showChip(chipEl); } else { @@ -845,11 +839,7 @@ export class Combobox let selectedVisibleChipsCount = 0; chipEls.forEach((chipEl) => { - if ( - chipEl.selected && - chipEl.classList.contains(CSS.chipVisible) && - !chipEl.classList.contains(CSS.chipInvisible) - ) { + if (chipEl.selected && !chipEl.classList.contains(CSS.chipInvisible)) { selectedVisibleChipsCount++; } }); @@ -1303,19 +1293,23 @@ export class Combobox setSelectedIndicatorChipEl, } = this; let label; - if (this.getItems().length === this.getSelectedItems().length) { + const allSelected = this.getItems().length === this.getSelectedItems().length; + if ( + (allSelected && displayMode === "single") || + (allSelected && displayMode === "fit-to-line" && !selectedVisibleChipsCount) + ) { label = "All selected"; + } else if (displayMode === "single" && this.getSelectedItems().length > 0) { + label = `${this.selectedItems.length} selected`; } else if (displayMode === "fit-to-line" && selectedHiddenChipsCount > 0) { label = selectedVisibleChipsCount > 0 ? `+${selectedHiddenChipsCount}` : `${selectedHiddenChipsCount} selected`; - } else if (displayMode === "single" && this.getSelectedItems().length > 0) { - label = `${this.selectedItems.length} selected`; } return ( Date: Mon, 30 Oct 2023 12:45:17 -0700 Subject: [PATCH 28/70] displaying chips in selection order for fit-to-line --- .../calcite-components/src/components/combobox/combobox.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 73142323f19..d5d3c8cccd5 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1253,9 +1253,8 @@ export class Combobox //-------------------------------------------------------------------------- renderChips(): VNode[] { - const { activeChipIndex, displayMode, scale, selectionMode, messages } = this; - const items = displayMode === "fit-to-line" ? this.items : this.selectedItems; - return items.map((item, i) => { + const { activeChipIndex, scale, selectionMode, messages } = this; + return this.selectedItems.map((item, i) => { const chipClasses = { chip: true, "chip--active": activeChipIndex === i, From 1440f8773e8a98cc652b05ee29b9aa56c136024c Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 2 Nov 2023 16:46:29 -0700 Subject: [PATCH 29/70] first start to fit-to-line compact mode with an IntersectionObserver on the input el, also resolving stencil warnings on load about the hidden and visible chip states changing during render. --- .../src/components/combobox/combobox.scss | 1 - .../src/components/combobox/combobox.tsx | 48 +++++++++++++++++-- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index f195a4f9599..55b8a30ca84 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -128,7 +128,6 @@ .input--icon { padding-block: 0; - padding-inline: var(--calcite-combobox-item-spacing-unit-l); } .input-wrap { diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 6239bf1d01b..5a80864deec 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -51,6 +51,7 @@ import { import { connectLabel, disconnectLabel, getLabelText, LabelableComponent } from "../../utils/label"; import { componentFocusable, + componentLoaded, LoadableComponent, setComponentLoaded, setUpLoadableComponent, @@ -442,6 +443,17 @@ export class Combobox this.openHandler(); onToggleOpenCloseComponent(this); } + + if (this.displayMode === "fit-to-line") { + this.inputIntersectionObserver = createObserver( + "intersection", + this.inputIntersectionHandler, + { + root: this.chipContainerEl, + threshold: 0.5, + } + ); + } } async componentWillLoad(): Promise { @@ -453,8 +465,10 @@ export class Combobox componentDidLoad(): void { afterConnectDefaultValueSet(this, this.getValue()); this.reposition(true); + if (this.displayMode === "fit-to-line") { + this.inputIntersectionObserver.observe(this.textInput); + } setComponentLoaded(this); - this.refreshDisplayMode(); } componentDidRender(): void { @@ -538,6 +552,8 @@ export class Combobox data: ItemData[]; + inputIntersectionObserver: IntersectionObserver; + mutationObserver = createObserver("mutation", () => this.updateItems()); resizeObserver = createObserver("resize", () => { @@ -818,11 +834,21 @@ export class Combobox chipEl.classList.add(CSS.chipInvisible); } + private inputIntersectionHandler = (entries): void => { + const selectedItemsCount = this.getSelectedItems().length; + entries.forEach(({ isIntersecting }) => { + if (!isIntersecting && !this.selectedVisibleChipsCount && selectedItemsCount > 0) { + this.selectedIndicatorChipEl.innerHTML = `${selectedItemsCount}`; + } + }); + }; + private showChip(chipEl: HTMLCalciteChipElement): void { chipEl.classList.remove(CSS.chipInvisible); } - private refreshDisplayMode = () => { + private refreshDisplayMode = async () => { + await componentLoaded(this); if (isSingleLike(this.selectionMode)) { return; } @@ -864,8 +890,17 @@ export class Combobox selectedVisibleChipsCount++; } }); - this.selectedHiddenChipsCount = this.getSelectedItems().length - selectedVisibleChipsCount; - this.selectedVisibleChipsCount = selectedVisibleChipsCount; + + const newSelectedHiddenChipsCount = + this.getSelectedItems().length - selectedVisibleChipsCount; + + if (newSelectedHiddenChipsCount !== this.selectedHiddenChipsCount) { + this.selectedHiddenChipsCount = newSelectedHiddenChipsCount; + } + + if (selectedVisibleChipsCount !== this.selectedVisibleChipsCount) { + this.selectedVisibleChipsCount = selectedVisibleChipsCount; + } } }; @@ -1292,7 +1327,10 @@ export class Combobox const allSelected = this.getItems().length === this.getSelectedItems().length; if ( (allSelected && displayMode === "single") || - (allSelected && displayMode === "fit-to-line" && !selectedVisibleChipsCount) + (allSelected && + displayMode === "fit-to-line" && + selectedVisibleChipsCount !== undefined && + !selectedVisibleChipsCount) ) { label = "All selected"; } else if (displayMode === "single" && this.getSelectedItems().length > 0) { From 13f5afeafcfb658acc9525e29c6785b006413ab7 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 3 Nov 2023 15:18:23 -0700 Subject: [PATCH 30/70] fine tuning the calculation for available horizontal space by taking into account the typed value in the text input. Also adding the gap value to the input text width to give it a bit more space to prevent the visible text from being concealed by overflow --- .../src/components/combobox/combobox.scss | 1 + .../src/components/combobox/combobox.tsx | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 55b8a30ca84..8735f1c9354 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -101,6 +101,7 @@ line-height: var(--calcite-combobox-input-height); inline-size: 100%; margin-block-end: var(--calcite-combobox-item-spacing-unit-s); + min-inline-size: 4.8125rem; &:focus { @apply outline-none; } diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 5a80864deec..9eebaf16b30 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -450,7 +450,7 @@ export class Combobox this.inputIntersectionHandler, { root: this.chipContainerEl, - threshold: 0.5, + threshold: 1, } ); } @@ -864,10 +864,12 @@ export class Combobox const chipContainerElGap = parseInt( getComputedStyle(this.chipContainerEl).gap.replace("px", "") ); - const inputTextWidth = getTextWidth(this.placeholder, `${fontSize} ${fontFamily}`) || 50; + const inputWidth = + (getTextWidth(this.textInput.value || this.placeholder, `${fontSize} ${fontFamily}`) || + 50) + chipContainerElGap; const selectedIndicatorChipElWidth = getElementWidth(this.selectedIndicatorChipEl); let availableHorizontalChipElSpace = Math.round( - chipContainerElWidth - (selectedIndicatorChipElWidth + chipContainerElGap + inputTextWidth) + chipContainerElWidth - (selectedIndicatorChipElWidth + chipContainerElGap + inputWidth) ); chipEls.forEach((chipEl: HTMLCalciteChipElement) => { From 7a9728190c976ab3844651b5965cd229d5482d6e Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Mon, 6 Nov 2023 12:30:56 -0800 Subject: [PATCH 31/70] removed IntersectionObserver on textInput, moved indicator chip label to a state variable, moved label fetching logic into refreshDisplayMode so it can use the width vars to set the label. Setting compact labels forthcoming. --- .../src/components/combobox/combobox.tsx | 140 +++++++++--------- 1 file changed, 66 insertions(+), 74 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 9eebaf16b30..b50a76a87fb 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -443,17 +443,6 @@ export class Combobox this.openHandler(); onToggleOpenCloseComponent(this); } - - if (this.displayMode === "fit-to-line") { - this.inputIntersectionObserver = createObserver( - "intersection", - this.inputIntersectionHandler, - { - root: this.chipContainerEl, - threshold: 1, - } - ); - } } async componentWillLoad(): Promise { @@ -465,9 +454,6 @@ export class Combobox componentDidLoad(): void { afterConnectDefaultValueSet(this, this.getValue()); this.reposition(true); - if (this.displayMode === "fit-to-line") { - this.inputIntersectionObserver.observe(this.textInput); - } setComponentLoaded(this); } @@ -546,14 +532,14 @@ export class Combobox @State() selectedHiddenChipsCount: number; + @State() selectedIndicatorChipLabel: string; + @State() selectedVisibleChipsCount: number; textInput: HTMLInputElement = null; data: ItemData[]; - inputIntersectionObserver: IntersectionObserver; - mutationObserver = createObserver("mutation", () => this.updateItems()); resizeObserver = createObserver("resize", () => { @@ -834,40 +820,45 @@ export class Combobox chipEl.classList.add(CSS.chipInvisible); } - private inputIntersectionHandler = (entries): void => { - const selectedItemsCount = this.getSelectedItems().length; - entries.forEach(({ isIntersecting }) => { - if (!isIntersecting && !this.selectedVisibleChipsCount && selectedItemsCount > 0) { - this.selectedIndicatorChipEl.innerHTML = `${selectedItemsCount}`; - } - }); - }; - private showChip(chipEl: HTMLCalciteChipElement): void { chipEl.classList.remove(CSS.chipInvisible); } private refreshDisplayMode = async () => { await componentLoaded(this); + if (isSingleLike(this.selectionMode)) { return; } + if (!this.textInput) { return; } - if (this.displayMode === "fit-to-line") { + + const { + chipContainerEl, + displayMode, + getSelectedItems, + hideChip, + placeholder, + selectedIndicatorChipEl, + showChip, + textInput, + } = this; + + const allSelected = this.isAllSelected(); + + if (displayMode === "fit-to-line") { const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( - (chipEl) => chipEl !== this.selectedIndicatorChipEl - ); - const { fontSize, fontFamily } = getComputedStyle(this.textInput); - const chipContainerElWidth = getElementWidth(this.chipContainerEl); - const chipContainerElGap = parseInt( - getComputedStyle(this.chipContainerEl).gap.replace("px", "") + (chipEl) => chipEl !== selectedIndicatorChipEl ); + const { fontSize, fontFamily } = getComputedStyle(textInput); + const chipContainerElWidth = getElementWidth(chipContainerEl); + const chipContainerElGap = parseInt(getComputedStyle(chipContainerEl).gap.replace("px", "")); const inputWidth = - (getTextWidth(this.textInput.value || this.placeholder, `${fontSize} ${fontFamily}`) || - 50) + chipContainerElGap; - const selectedIndicatorChipElWidth = getElementWidth(this.selectedIndicatorChipEl); + (getTextWidth(textInput.value || placeholder, `${fontSize} ${fontFamily}`) || 50) + + chipContainerElGap; + const selectedIndicatorChipElWidth = getElementWidth(selectedIndicatorChipEl); let availableHorizontalChipElSpace = Math.round( chipContainerElWidth - (selectedIndicatorChipElWidth + chipContainerElGap + inputWidth) ); @@ -877,31 +868,52 @@ export class Combobox const chipElWidth = getElementWidth(chipEl); if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { availableHorizontalChipElSpace -= chipElWidth + chipContainerElGap; - this.showChip(chipEl); + showChip(chipEl); } else { - this.hideChip(chipEl); + hideChip(chipEl); } } else { - this.hideChip(chipEl); + hideChip(chipEl); } }); - let selectedVisibleChipsCount = 0; + let newSelectedVisibleChipsCount = 0; chipEls.forEach((chipEl) => { if (chipEl.selected && !chipEl.classList.contains(CSS.chipInvisible)) { - selectedVisibleChipsCount++; + newSelectedVisibleChipsCount++; } }); - const newSelectedHiddenChipsCount = - this.getSelectedItems().length - selectedVisibleChipsCount; + const newSelectedHiddenChipsCount = getSelectedItems().length - newSelectedVisibleChipsCount; if (newSelectedHiddenChipsCount !== this.selectedHiddenChipsCount) { this.selectedHiddenChipsCount = newSelectedHiddenChipsCount; } - if (selectedVisibleChipsCount !== this.selectedVisibleChipsCount) { - this.selectedVisibleChipsCount = selectedVisibleChipsCount; + if (newSelectedVisibleChipsCount !== this.selectedVisibleChipsCount) { + this.selectedVisibleChipsCount = newSelectedVisibleChipsCount; + } + + const { selectedHiddenChipsCount, selectedVisibleChipsCount } = this; + + if (allSelected && selectedVisibleChipsCount !== undefined && !selectedVisibleChipsCount) { + this.selectedIndicatorChipLabel = "All selected"; + } else if (selectedHiddenChipsCount > 0) { + this.selectedIndicatorChipLabel = + newSelectedVisibleChipsCount > 0 + ? `+${selectedHiddenChipsCount}` + : `${selectedHiddenChipsCount} selected`; + } else { + this.selectedIndicatorChipLabel = null; + } + } else if (displayMode === "single") { + const selectedItemsCount = getSelectedItems().length; + if (allSelected) { + this.selectedIndicatorChipLabel = "All selected"; + } else if (selectedItemsCount > 0) { + this.selectedIndicatorChipLabel = `${selectedItemsCount} selected`; + } else { + this.selectedIndicatorChipLabel = null; } } }; @@ -1075,7 +1087,7 @@ export class Combobox return this.items.filter((item) => !item.hidden); } - getSelectedItems(): HTMLCalciteComboboxItemElement[] { + private getSelectedItems = (): HTMLCalciteComboboxItemElement[] => { if (!this.isMulti()) { const match = this.items.find(({ selected }) => selected); return match ? [match] : []; @@ -1097,7 +1109,7 @@ export class Combobox return bIdx - aIdx; }) ); - } + }; private updateItems = (): void => { this.items = this.getItems(); @@ -1268,6 +1280,10 @@ export class Combobox } } + private isAllSelected = (): boolean => { + return this.getItems().length === this.getSelectedItems().length; + }; + isMulti(): boolean { return !isSingleLike(this.selectionMode); } @@ -1318,40 +1334,16 @@ export class Combobox } renderSelectedIndicatorChip(): VNode { - const { - displayMode, - scale, - selectedHiddenChipsCount, - selectedVisibleChipsCount, - setSelectedIndicatorChipEl, - } = this; - let label; - const allSelected = this.getItems().length === this.getSelectedItems().length; - if ( - (allSelected && displayMode === "single") || - (allSelected && - displayMode === "fit-to-line" && - selectedVisibleChipsCount !== undefined && - !selectedVisibleChipsCount) - ) { - label = "All selected"; - } else if (displayMode === "single" && this.getSelectedItems().length > 0) { - label = `${this.selectedItems.length} selected`; - } else if (displayMode === "fit-to-line" && selectedHiddenChipsCount > 0) { - label = - selectedVisibleChipsCount > 0 - ? `+${selectedHiddenChipsCount}` - : `${selectedHiddenChipsCount} selected`; - } + const { scale, selectedIndicatorChipLabel, setSelectedIndicatorChipEl } = this; return ( - {label} + {selectedIndicatorChipLabel} ); } From 218c1f3a77d997d08e385e2082d47341fda1b738 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Mon, 6 Nov 2023 15:56:30 -0800 Subject: [PATCH 32/70] Only include indicator chip width in calculation if its actually visible --- .../src/components/combobox/combobox.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index b50a76a87fb..c1baa21601d 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -855,10 +855,18 @@ export class Combobox const { fontSize, fontFamily } = getComputedStyle(textInput); const chipContainerElWidth = getElementWidth(chipContainerEl); const chipContainerElGap = parseInt(getComputedStyle(chipContainerEl).gap.replace("px", "")); - const inputWidth = - (getTextWidth(textInput.value || placeholder, `${fontSize} ${fontFamily}`) || 50) + - chipContainerElGap; - const selectedIndicatorChipElWidth = getElementWidth(selectedIndicatorChipEl); + const inputTextWidth = getTextWidth( + textInput.value || placeholder, + `${fontSize} ${fontFamily}` + ); + // TODO: use the 48px token here as the minimum input width. + const inputWidth = (inputTextWidth || 48) + chipContainerElGap; + const selectedIndicatorChipElWidth = selectedIndicatorChipEl.classList.contains( + CSS.chipInvisible + ) + ? 0 + : getElementWidth(selectedIndicatorChipEl); + let availableHorizontalChipElSpace = Math.round( chipContainerElWidth - (selectedIndicatorChipElWidth + chipContainerElGap + inputWidth) ); From c8583b33296fceb2570aab176c01a0fe4e21bb2b Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Mon, 6 Nov 2023 16:09:18 -0800 Subject: [PATCH 33/70] Just measure placeholder text in input width calculation --- .../calcite-components/src/components/combobox/combobox.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index c1baa21601d..5c9134b2236 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -855,10 +855,7 @@ export class Combobox const { fontSize, fontFamily } = getComputedStyle(textInput); const chipContainerElWidth = getElementWidth(chipContainerEl); const chipContainerElGap = parseInt(getComputedStyle(chipContainerEl).gap.replace("px", "")); - const inputTextWidth = getTextWidth( - textInput.value || placeholder, - `${fontSize} ${fontFamily}` - ); + const inputTextWidth = getTextWidth(placeholder, `${fontSize} ${fontFamily}`); // TODO: use the 48px token here as the minimum input width. const inputWidth = (inputTextWidth || 48) + chipContainerElGap; const selectedIndicatorChipElWidth = selectedIndicatorChipEl.classList.contains( From e3301c9b3ede5645129afcc4827c938114b6baac Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Wed, 8 Nov 2023 16:35:11 -0800 Subject: [PATCH 34/70] wip: this is an attempt to render all the indicator chips so we can statically analyze their width to determine when to show or hide them based on container size. So far I'm not seeing a layout thrash, but I need to finish up the logic for all the rest of the scenarios, this is a great stride towards getting compact display to work. --- .../assets/combobox/t9n/messages.json | 2 + .../src/components/combobox/combobox.tsx | 137 ++++++++++++++++-- packages/calcite-components/src/utils/dom.ts | 2 +- 3 files changed, 127 insertions(+), 14 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json index f22a4b202dd..4a12d4fa268 100644 --- a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json +++ b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json @@ -1,4 +1,6 @@ { + "all": "All", + "allSelected": "All selected", "clear": "Clear value", "removeTag": "Remove tag" } diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 5c9134b2236..26bc2ff2553 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -565,8 +565,14 @@ export class Combobox transitionEl: HTMLDivElement; + private allSelectedIndicatorChipEl: HTMLCalciteChipElement; + + private allSelectedIndicatorChipCompactEl: HTMLCalciteChipElement; + private selectedIndicatorChipEl: HTMLCalciteChipElement; + private selectedIndicatorChipCompactEl: HTMLCalciteChipElement; + // -------------------------------------------------------------------------- // // Private Methods @@ -824,6 +830,8 @@ export class Combobox chipEl.classList.remove(CSS.chipInvisible); } + private maxCompactBreakpoint: number; + private refreshDisplayMode = async () => { await componentLoaded(this); @@ -836,12 +844,15 @@ export class Combobox } const { + allSelectedIndicatorChipEl, + allSelectedIndicatorChipCompactEl, chipContainerEl, displayMode, getSelectedItems, hideChip, placeholder, selectedIndicatorChipEl, + selectedIndicatorChipCompactEl, showChip, textInput, } = this; @@ -850,7 +861,7 @@ export class Combobox if (displayMode === "fit-to-line") { const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( - (chipEl) => chipEl !== selectedIndicatorChipEl + (chipEl) => chipEl.hasAttribute("closable") ); const { fontSize, fontFamily } = getComputedStyle(textInput); const chipContainerElWidth = getElementWidth(chipContainerEl); @@ -901,16 +912,40 @@ export class Combobox const { selectedHiddenChipsCount, selectedVisibleChipsCount } = this; + const newCompactBreakpoint = Math.round( + getElementWidth(allSelectedIndicatorChipEl) + chipContainerElGap + inputWidth + ); + + if (!this.maxCompactBreakpoint || this.maxCompactBreakpoint < newCompactBreakpoint) { + this.maxCompactBreakpoint = newCompactBreakpoint; + } + + console.log( + this.maxCompactBreakpoint, + "selectedVisibleChipsCount", + selectedVisibleChipsCount + ); + if (allSelected && selectedVisibleChipsCount !== undefined && !selectedVisibleChipsCount) { - this.selectedIndicatorChipLabel = "All selected"; - } else if (selectedHiddenChipsCount > 0) { - this.selectedIndicatorChipLabel = - newSelectedVisibleChipsCount > 0 - ? `+${selectedHiddenChipsCount}` - : `${selectedHiddenChipsCount} selected`; - } else { - this.selectedIndicatorChipLabel = null; + hideChip(selectedIndicatorChipEl); + // TODO: calculate the max width of the all selected chip + gap + placeholder text length to determine the compact breakpoint + if (chipContainerElWidth < this.maxCompactBreakpoint) { + hideChip(allSelectedIndicatorChipEl); + showChip(allSelectedIndicatorChipCompactEl); + } else { + showChip(allSelectedIndicatorChipEl); + hideChip(allSelectedIndicatorChipCompactEl); + } } + // } else if (selectedHiddenChipsCount > 0) { + // this.hideChip(allSelectedIndicatorChipEl); + // this.hideChip(allSelectedIndicatorChipCompactEl); + // this.showChip(selectedIndicatorChipEl); + // } else { + // this.hideChip(allSelectedIndicatorChipEl); + // this.hideChip(allSelectedIndicatorChipCompactEl); + // this.hideChip(selectedIndicatorChipEl); + // } } else if (displayMode === "single") { const selectedItemsCount = getSelectedItems().length; if (allSelected) { @@ -944,10 +979,22 @@ export class Combobox connectFloatingUI(this, this.referenceEl, this.floatingEl); }; + setAllSelectedIndicatorChipEl = (el: HTMLCalciteChipElement): void => { + this.allSelectedIndicatorChipEl = el; + }; + + setAllSelectedIndicatorChipCompactEl = (el: HTMLCalciteChipElement): void => { + this.allSelectedIndicatorChipCompactEl = el; + }; + setSelectedIndicatorChipEl = (el: HTMLCalciteChipElement): void => { this.selectedIndicatorChipEl = el; }; + setSelectedIndicatorChipCompactEl = (el: HTMLCalciteChipElement): void => { + this.selectedIndicatorChipCompactEl = el; + }; + private getMaxScrollerHeight(): number { const items = this.getItemsAndGroups().filter((item) => !item.hidden); @@ -1338,17 +1385,74 @@ export class Combobox }); } + renderAllSelectedIndicatorChip(): VNode { + const { scale, setAllSelectedIndicatorChipEl } = this; + const label = this.messages.allSelected || "All selected"; + return ( + + {label} + + ); + } + + renderAllSelectedIndicatorChipCompact(): VNode { + const { scale, setAllSelectedIndicatorChipCompactEl } = this; + const label = this.messages.all || "All"; + return ( + + {label} + + ); + } + renderSelectedIndicatorChip(): VNode { - const { scale, selectedIndicatorChipLabel, setSelectedIndicatorChipEl } = this; + const { scale, selectedHiddenChipsCount, setSelectedIndicatorChipEl } = this; + const label = `+${selectedHiddenChipsCount}`; return ( + {label} + + ); + } + + renderSelectedIndicatorChipCompact(): VNode { + const { + scale, + selectedHiddenChipsCount, + selectedVisibleChipsCount, + setSelectedIndicatorChipCompactEl, + } = this; + const label = `${selectedHiddenChipsCount || 0}`; + return ( + 0 && !selectedVisibleChipsCount, + }} + ref={setSelectedIndicatorChipCompactEl} + scale={scale} + title={label} value="" > - {selectedIndicatorChipLabel} + {label} ); } @@ -1520,6 +1624,13 @@ export class Combobox {this.renderIconStart()} {!singleSelectionMode && !singleDisplayMode && this.renderChips()} {!singleSelectionMode && !showAllDisplayMode && this.renderSelectedIndicatorChip()} + {/* {!singleSelectionMode && + !showAllDisplayMode && + this.renderSelectedIndicatorChipCompact()} */} + {!singleSelectionMode && !showAllDisplayMode && this.renderAllSelectedIndicatorChip()} + {!singleSelectionMode && + !showAllDisplayMode && + this.renderAllSelectedIndicatorChipCompact()} @@ -1468,10 +1462,10 @@ export class Combobox selectedHiddenChipsCount ), }} - ref={setSelectedIndicatorChipCompactEl} scale={scale} title={label} value="" + ref={setSelectedIndicatorChipCompactEl} > {label}
From bd50d392b98a419be978e670e6953da5fb71ab7b Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 16 Nov 2023 13:28:09 -0800 Subject: [PATCH 37/70] removing some unused refs, fixing display logic for selected indicator chip in fit-to-line --- .../src/components/combobox/combobox.scss | 3 +- .../src/components/combobox/combobox.tsx | 61 +++++++++---------- .../src/components/combobox/resources.ts | 2 + 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 8735f1c9354..df0dce32165 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -83,7 +83,8 @@ gap: var(--calcite-combobox-item-spacing-unit-s); - &.fit-to-line { + &.display-mode-fit-to-line, + &.display-mode-single { @apply flex-nowrap overflow-hidden; } } diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 0941a03d9e7..98b338414bc 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -159,8 +159,7 @@ export class Combobox * * When not set, the component will be associated with its ancestor form element, if any. */ - @Prop({ reflect: true }) - form: string; + @Prop({ reflect: true }) form: string; /** Accessible name for the component. */ @Prop() label!: string; @@ -356,7 +355,8 @@ export class Combobox /** * Updates the position of the component. * - * @param delayed + * @param delayed Reposition the component after a delay + * @returns Promise */ @Method() async reposition(delayed = false): Promise { @@ -567,12 +567,8 @@ export class Combobox private allSelectedIndicatorChipEl: HTMLCalciteChipElement; - private allSelectedIndicatorChipCompactEl: HTMLCalciteChipElement; - private selectedIndicatorChipEl: HTMLCalciteChipElement; - private selectedIndicatorChipCompactEl: HTMLCalciteChipElement; - // -------------------------------------------------------------------------- // // Private Methods @@ -952,18 +948,10 @@ export class Combobox this.allSelectedIndicatorChipEl = el; }; - setAllSelectedIndicatorChipCompactEl = (el: HTMLCalciteChipElement): void => { - this.allSelectedIndicatorChipCompactEl = el; - }; - setSelectedIndicatorChipEl = (el: HTMLCalciteChipElement): void => { this.selectedIndicatorChipEl = el; }; - setSelectedIndicatorChipCompactEl = (el: HTMLCalciteChipElement): void => { - this.selectedIndicatorChipCompactEl = el; - }; - private getMaxScrollerHeight(): number { const items = this.getItemsAndGroups().filter((item) => !item.hidden); @@ -1384,13 +1372,7 @@ export class Combobox } renderAllSelectedIndicatorChipCompact(): VNode { - const { - compactDisplayMode, - isAllSelected, - scale, - selectedVisibleChipsCount, - setAllSelectedIndicatorChipCompactEl, - } = this; + const { compactDisplayMode, isAllSelected, scale, selectedVisibleChipsCount } = this; const label = this.messages.all || "All"; return ( {label} @@ -1415,21 +1396,34 @@ export class Combobox renderSelectedIndicatorChip(): VNode { const { compactDisplayMode, + displayMode, + isAllSelected, scale, selectedHiddenChipsCount, selectedVisibleChipsCount, setSelectedIndicatorChipEl, } = this; - const label = `+${selectedHiddenChipsCount}`; + let chipInvisible, label; + if (compactDisplayMode) { + chipInvisible = true; + } else if (displayMode === "single") { + label = `${selectedHiddenChipsCount} selected`; + } else if (displayMode === "fit-to-line") { + if ((isAllSelected() && selectedVisibleChipsCount === 0) || selectedHiddenChipsCount === 0) { + chipInvisible = true; + } else { + chipInvisible = false; + } + label = + selectedVisibleChipsCount > 0 + ? `+${selectedHiddenChipsCount}` + : `${selectedHiddenChipsCount} selected`; + } return ( {label} @@ -1610,7 +1602,6 @@ export class Combobox const singleDisplayMode = displayMode === "single"; const fitToLineDisplayMode = !singleSelectionMode && displayMode === "fit-to-line"; const isClearable = !this.clearDisabled && this.value?.length > 0; - return (
{this.renderIconStart()} diff --git a/packages/calcite-components/src/components/combobox/resources.ts b/packages/calcite-components/src/components/combobox/resources.ts index 4454fbe479b..33d56456888 100644 --- a/packages/calcite-components/src/components/combobox/resources.ts +++ b/packages/calcite-components/src/components/combobox/resources.ts @@ -4,5 +4,7 @@ export const ComboboxChildSelector = `${ComboboxItem}, ${ComboboxItemGroup}`; export const CSS = { chipInvisible: "chip--invisible", + displayModeFitToLine: "display-mode-fit-to-line", + displayModeSingle: "display-mode-single", listContainer: "list-container", }; From 0c54dbdfb158e37a629451d2e3ace8c72649dbb5 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 16 Nov 2023 14:03:16 -0800 Subject: [PATCH 38/70] moving all the spacing vars we need for single out of the fit-to-line branch and correcting the available space calculation for fit-to-line by only including the selected chip width if its currently visible and also adding the gap to the right of the input --- .../src/components/combobox/combobox.tsx | 84 ++++++++++--------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 98b338414bc..70f470f4a41 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -532,8 +532,6 @@ export class Combobox @State() selectedHiddenChipsCount = 0; - @State() selectedIndicatorChipLabel: string; - @State() selectedVisibleChipsCount = 0; textInput: HTMLInputElement = null; @@ -853,33 +851,38 @@ export class Combobox textInput, } = this; - const allSelected = this.isAllSelected(); + const chipContainerElGap = parseInt(getComputedStyle(chipContainerEl).gap.replace("px", "")); + const chipContainerElWidth = getElementWidth(chipContainerEl); + const { fontSize, fontFamily } = getComputedStyle(textInput); + const inputTextWidth = getTextWidth(placeholder, `${fontSize} ${fontFamily}`); + const inputWidth = (inputTextWidth || 48) + chipContainerElGap; + const allSelectedIndicatorChipElWidth = getElementWidth(allSelectedIndicatorChipEl); + const selectedIndicatorChipElWidth = getElementWidth(selectedIndicatorChipEl); + const largestSelectedIndicatorChipWidth = Math.max( + allSelectedIndicatorChipElWidth, + selectedIndicatorChipElWidth + ); + + // Determine if we are in Compact Display Mode + const newCompactBreakpoint = Math.round( + largestSelectedIndicatorChipWidth + chipContainerElGap + inputWidth + ); + if (!this.maxCompactBreakpoint || this.maxCompactBreakpoint < newCompactBreakpoint) { + this.maxCompactBreakpoint = newCompactBreakpoint; + } + this.compactDisplayMode = chipContainerElWidth < this.maxCompactBreakpoint; if (displayMode === "fit-to-line") { const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( (chipEl) => chipEl.hasAttribute("closable") ); - const { fontSize, fontFamily } = getComputedStyle(textInput); - const chipContainerElWidth = getElementWidth(chipContainerEl); - const chipContainerElGap = parseInt(getComputedStyle(chipContainerEl).gap.replace("px", "")); - const inputTextWidth = getTextWidth(placeholder, `${fontSize} ${fontFamily}`); - // TODO: use the 48px token here as the minimum input width. - const inputWidth = (inputTextWidth || 48) + chipContainerElGap; - - // Determine if we are in Compact Display Mode - const newCompactBreakpoint = Math.round( - getElementWidth(allSelectedIndicatorChipEl) + chipContainerElGap + inputWidth - ); - if (!this.maxCompactBreakpoint || this.maxCompactBreakpoint < newCompactBreakpoint) { - this.maxCompactBreakpoint = newCompactBreakpoint; - } - this.compactDisplayMode = chipContainerElWidth < this.maxCompactBreakpoint; - - // TODO: this probably needs rethought now that we have multiple possible indicator chips to consider - const selectedIndicatorChipElWidth = getElementWidth(selectedIndicatorChipEl); let availableHorizontalChipElSpace = Math.round( - chipContainerElWidth - (selectedIndicatorChipElWidth + chipContainerElGap + inputWidth) + chipContainerElWidth - + ((this.selectedHiddenChipsCount > 0 ? selectedIndicatorChipElWidth : 0) + + chipContainerElGap + + inputWidth + + chipContainerElGap) ); // Refresh Selected Chips @@ -912,14 +915,7 @@ export class Combobox this.selectedHiddenChipsCount = newSelectedHiddenChipsCount; } } else if (displayMode === "single") { - const selectedItemsCount = getSelectedItems().length; - if (allSelected) { - this.selectedIndicatorChipLabel = "All selected"; - } else if (selectedItemsCount > 0) { - this.selectedIndicatorChipLabel = `${selectedItemsCount} selected`; - } else { - this.selectedIndicatorChipLabel = null; - } + // TODO: get this working } }; @@ -1406,18 +1402,24 @@ export class Combobox let chipInvisible, label; if (compactDisplayMode) { chipInvisible = true; - } else if (displayMode === "single") { - label = `${selectedHiddenChipsCount} selected`; - } else if (displayMode === "fit-to-line") { - if ((isAllSelected() && selectedVisibleChipsCount === 0) || selectedHiddenChipsCount === 0) { - chipInvisible = true; - } else { - chipInvisible = false; + } else { + if (displayMode === "single") { + chipInvisible = isAllSelected() ? true : false; + label = `${selectedHiddenChipsCount} selected`; + } else if (displayMode === "fit-to-line") { + if ( + (isAllSelected() && selectedVisibleChipsCount === 0) || + selectedHiddenChipsCount === 0 + ) { + chipInvisible = true; + } else { + chipInvisible = false; + } + label = + selectedVisibleChipsCount > 0 + ? `+${selectedHiddenChipsCount}` + : `${selectedHiddenChipsCount} selected`; } - label = - selectedVisibleChipsCount > 0 - ? `+${selectedHiddenChipsCount}` - : `${selectedHiddenChipsCount} selected`; } return ( Date: Thu, 16 Nov 2023 14:40:11 -0800 Subject: [PATCH 39/70] getting single display mode working right for both compact and non-compact --- .../src/components/combobox/combobox.tsx | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 70f470f4a41..b7ba7c8c4fa 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1393,6 +1393,7 @@ export class Combobox const { compactDisplayMode, displayMode, + getSelectedItems, isAllSelected, scale, selectedHiddenChipsCount, @@ -1405,7 +1406,7 @@ export class Combobox } else { if (displayMode === "single") { chipInvisible = isAllSelected() ? true : false; - label = `${selectedHiddenChipsCount} selected`; + label = `${getSelectedItems().length} selected`; } else if (displayMode === "fit-to-line") { if ( (isAllSelected() && selectedVisibleChipsCount === 0) || @@ -1440,22 +1441,28 @@ export class Combobox renderSelectedIndicatorChipCompact(): VNode { const { compactDisplayMode, + displayMode, + getSelectedItems, isAllSelected, scale, selectedHiddenChipsCount, - selectedVisibleChipsCount, } = this; - const label = `${selectedHiddenChipsCount || 0}`; + let chipInvisible, label; + if (compactDisplayMode) { + chipInvisible = isAllSelected() ? true : false; + if (displayMode === "fit-to-line") { + label = `${selectedHiddenChipsCount || 0}`; + } else if (displayMode === "single") { + label = `${getSelectedItems().length}`; + } + } else { + chipInvisible = true; + } return ( Date: Thu, 16 Nov 2023 15:01:46 -0800 Subject: [PATCH 40/70] fixing chip display for when no items are selected --- .../src/components/combobox/combobox.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index b7ba7c8c4fa..e6640880acc 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1405,7 +1405,14 @@ export class Combobox chipInvisible = true; } else { if (displayMode === "single") { - chipInvisible = isAllSelected() ? true : false; + const selectedItemsCount = getSelectedItems().length; + if (isAllSelected()) { + chipInvisible = true; + } else if (selectedItemsCount > 0) { + chipInvisible = false; + } else { + chipInvisible = true; + } label = `${getSelectedItems().length} selected`; } else if (displayMode === "fit-to-line") { if ( @@ -1449,10 +1456,15 @@ export class Combobox } = this; let chipInvisible, label; if (compactDisplayMode) { + const selectedItemsCount = getSelectedItems().length; chipInvisible = isAllSelected() ? true : false; - if (displayMode === "fit-to-line") { + if (isAllSelected()) { + chipInvisible = true; + } else if (displayMode === "fit-to-line") { + chipInvisible = selectedHiddenChipsCount > 0 ? false : true; label = `${selectedHiddenChipsCount || 0}`; } else if (displayMode === "single") { + chipInvisible = selectedItemsCount > 0 ? false : true; label = `${getSelectedItems().length}`; } } else { From 4239a18457d2a13aa2ce41492263a3b34c8e35ed Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 16 Nov 2023 15:21:23 -0800 Subject: [PATCH 41/70] placeholder ellipses! --- .../calcite-components/src/components/combobox/combobox.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index df0dce32165..52d3a18a28f 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -106,6 +106,9 @@ &:focus { @apply outline-none; } + &:placeholder-shown { + text-overflow: ellipsis; + } } .input--transparent { From a31492b0af4459e28427ca60676c35407f1de905 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 16 Nov 2023 15:41:06 -0800 Subject: [PATCH 42/70] removing unused branch --- .../calcite-components/src/components/combobox/combobox.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index e6640880acc..542219bf665 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -914,8 +914,6 @@ export class Combobox if (newSelectedHiddenChipsCount !== this.selectedHiddenChipsCount) { this.selectedHiddenChipsCount = newSelectedHiddenChipsCount; } - } else if (displayMode === "single") { - // TODO: get this working } }; From 21b0b97f2613488b4c89169f7e6d065ea151bd30 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 16 Nov 2023 16:14:37 -0800 Subject: [PATCH 43/70] applying ellipses with tailwind --- .../calcite-components/src/components/combobox/combobox.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index 52d3a18a28f..d87a3372df5 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -107,7 +107,7 @@ @apply outline-none; } &:placeholder-shown { - text-overflow: ellipsis; + @apply text-ellipsis; } } From b7706da52b99b722059efb49b7dc505f6b1e3475 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 16 Nov 2023 16:25:22 -0800 Subject: [PATCH 44/70] applying text-ellipsis to input and alpha sorting tailwind apply rules --- .../src/components/combobox/combobox.scss | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.scss b/packages/calcite-components/src/components/combobox/combobox.scss index d87a3372df5..25bb2bc813a 100644 --- a/packages/calcite-components/src/components/combobox/combobox.scss +++ b/packages/calcite-components/src/components/combobox/combobox.scss @@ -90,12 +90,13 @@ } .input { - @apply font-inherit - text-color-1 - flex-grow - appearance-none - border-none + @apply appearance-none bg-transparent + border-none + flex-grow + font-inherit + text-color-1 + text-ellipsis p-0; font-size: inherit; block-size: var(--calcite-combobox-input-height); From c89286adefef083f02453c5e792c06f7c699cd3a Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Thu, 16 Nov 2023 16:53:43 -0800 Subject: [PATCH 45/70] adding all new display mode variants to a single story for chromatic regression testing --- .../components/combobox/combobox.stories.ts | 457 ++++++++++-------- 1 file changed, 242 insertions(+), 215 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.stories.ts b/packages/calcite-components/src/components/combobox/combobox.stories.ts index 10ad5800c9c..aaba61f2a17 100644 --- a/packages/calcite-components/src/components/combobox/combobox.stories.ts +++ b/packages/calcite-components/src/components/combobox/combobox.stories.ts @@ -13,16 +13,16 @@ export default { ...storyFilters(), }; -export const single = (): string => html` -
+export const simple = (): string => html` +
@@ -43,217 +43,244 @@ export const single = (): string => html` export const multiple = (): string => html`
- - - - - - - - - - - - - - - - - - - - -
-`; - -export const multipleShowAll = (): string => html` -
- - - - - - - - - - - - - - - - - - - - -
-`; - -export const multipleFitToLine = (): string => html` -
- - - - - - - - - - - - - - - - - - - - -
-`; - -export const multipleFitToLineAllSelected = (): string => html` -
- - - - - - - - - - - - - - - - - - - - -
-`; +

display-mode="show-all" (default)

+ + Some selected + + + + + + + + + + + + All selected + + + + + + + + + + -export const multipleSingle = (): string => html` -
- - - - - - - - - - - - - - - - - - - - -
-`; +

display-mode="fit-to-line"

+ + Some selected with multiple visible chips + + + + + + + + + + + + Some selected with multiple visible chips and overflow chip + + + + + + + + + + + + All selected with multiple visible chips and overflow chip + + + + + + + + + + + + Some selected as a condensed indicator chip + + + + + + + + + + + + All selected as a condensed indicator chip + + + + + + + + + + + + Some selected as a compact indicator chip + + + + + + + + + + + + All selected as a compact indicator chip + + + + + + + + + + -export const multipleSingleAllSelected = (): string => html` -
- - - - - - - - - - - - - - - - - - - - +

display-mode="single"

+ + Some selected + + + + + + + + + + + + All selected + + + + + + + + + + + + Some selected with compact indicator chip + + + + + + + + + + + + All selected with compact indicator chip + + + + + + + + + +
`; From 7c223e0c1d3c4efacac3af47f674e843d9fd0f4b Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 13:43:52 -0800 Subject: [PATCH 46/70] renaming simple story to single --- .../src/components/combobox/combobox.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.stories.ts b/packages/calcite-components/src/components/combobox/combobox.stories.ts index aaba61f2a17..224047eb7c3 100644 --- a/packages/calcite-components/src/components/combobox/combobox.stories.ts +++ b/packages/calcite-components/src/components/combobox/combobox.stories.ts @@ -13,7 +13,7 @@ export default { ...storyFilters(), }; -export const simple = (): string => html` +export const single = (): string => html`
Date: Fri, 17 Nov 2023 13:45:35 -0800 Subject: [PATCH 47/70] syncing messages_en --- .../components/combobox/assets/combobox/t9n/messages_en.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json index f22a4b202dd..4a12d4fa268 100644 --- a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json +++ b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json @@ -1,4 +1,6 @@ { + "all": "All", + "allSelected": "All selected", "clear": "Clear value", "removeTag": "Remove tag" } From 6ef3b326f8d805dcf50043d6736b6dad4a3279d1 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 13:48:49 -0800 Subject: [PATCH 48/70] moving DisplayMode type to interfaces file --- .../calcite-components/src/components/combobox/combobox.tsx | 4 +--- .../calcite-components/src/components/combobox/interfaces.ts | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 542219bf665..84eeff23665 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -68,7 +68,7 @@ import { } from "../../utils/t9n"; import { Scale, SelectionMode } from "../interfaces"; import { ComboboxMessages } from "./assets/combobox/t9n"; -import { ComboboxChildElement } from "./interfaces"; +import { ComboboxChildElement, DisplayMode } from "./interfaces"; import { ComboboxChildSelector, ComboboxItem, ComboboxItemGroup, CSS } from "./resources"; import { getItemAncestors, getItemChildren, hasActiveChildren, isSingleLike } from "./utils"; import { XButton, CSS as XButtonCSS } from "../functional/XButton"; @@ -79,8 +79,6 @@ interface ItemData { value: string; } -type DisplayMode = "show-all" | "single" | "fit-to-line"; - const isGroup = (el: ComboboxChildElement): el is HTMLCalciteComboboxItemGroupElement => el.tagName === ComboboxItemGroup; diff --git a/packages/calcite-components/src/components/combobox/interfaces.ts b/packages/calcite-components/src/components/combobox/interfaces.ts index bdf57a16e9d..211511a5cb2 100644 --- a/packages/calcite-components/src/components/combobox/interfaces.ts +++ b/packages/calcite-components/src/components/combobox/interfaces.ts @@ -4,3 +4,4 @@ export interface listItem { } export type ComboboxChildElement = HTMLCalciteComboboxItemElement | HTMLCalciteComboboxItemGroupElement; +export type DisplayMode = "show-all" | "single" | "fit-to-line"; From 4da1c7d56c4cd9b549f548c81ae37bbd83423c2f Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 13:50:10 -0800 Subject: [PATCH 49/70] reflecting display-mode --- .../calcite-components/src/components/combobox/combobox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 84eeff23665..b8fa12ff299 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -125,7 +125,7 @@ export class Combobox * - "single" displays a single chip indicating the total amount of selected items * - "fit-to-line" only displays selected chips that fit horizontally, with a non-closable chip indicating additional selected items as needed */ - @Prop() displayMode: DisplayMode = "show-all"; + @Prop({ reflect: true }) displayMode: DisplayMode = "show-all"; /**When `true`, displays and positions the component. */ @Prop({ reflect: true, mutable: true }) open = false; From 4752caab63b86d57c2a551a3b37f3bc26578e58f Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 13:51:24 -0800 Subject: [PATCH 50/70] privatizing resizeObserver --- .../calcite-components/src/components/combobox/combobox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index b8fa12ff299..86ec0d3028c 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -538,7 +538,7 @@ export class Combobox mutationObserver = createObserver("mutation", () => this.updateItems()); - resizeObserver = createObserver("resize", () => { + private resizeObserver = createObserver("resize", () => { this.setMaxScrollerHeight(); this.refreshDisplayMode(); }); From 10122ca723636d0ba277f7cd2b5a1918d52f00d1 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 13:55:45 -0800 Subject: [PATCH 51/70] alpha sorting private props/state --- .../src/components/combobox/combobox.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 86ec0d3028c..2046db20fb2 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -485,6 +485,8 @@ export class Combobox // //-------------------------------------------------------------------------- + private allSelectedIndicatorChipEl: HTMLCalciteChipElement; + @Element() el: HTMLCalciteComboboxElement; placement: LogicalPlacement = defaultMenuPlacement; @@ -511,6 +513,10 @@ export class Combobox @State() activeDescendant = ""; + @State() selectedHiddenChipsCount = 0; + + @State() selectedVisibleChipsCount = 0; + @State() text = ""; /** when search text is cleared, reset active to */ @@ -528,10 +534,6 @@ export class Combobox @State() defaultMessages: ComboboxMessages; - @State() selectedHiddenChipsCount = 0; - - @State() selectedVisibleChipsCount = 0; - textInput: HTMLInputElement = null; data: ItemData[]; @@ -559,12 +561,10 @@ export class Combobox openTransitionProp = "opacity"; - transitionEl: HTMLDivElement; - - private allSelectedIndicatorChipEl: HTMLCalciteChipElement; - private selectedIndicatorChipEl: HTMLCalciteChipElement; + transitionEl: HTMLDivElement; + // -------------------------------------------------------------------------- // // Private Methods From 2eeeab31d0d1bb470c13d39af83f9683fe227da4 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 13:58:43 -0800 Subject: [PATCH 52/70] moving 2 private vars to private section --- .../src/components/combobox/combobox.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 2046db20fb2..5c5de2e42a7 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -513,6 +513,8 @@ export class Combobox @State() activeDescendant = ""; + @State() compactDisplayMode = false; + @State() selectedHiddenChipsCount = 0; @State() selectedVisibleChipsCount = 0; @@ -559,6 +561,8 @@ export class Combobox private ignoreSelectedEventsFlag = false; + private maxCompactBreakpoint: number; + openTransitionProp = "opacity"; private selectedIndicatorChipEl: HTMLCalciteChipElement; @@ -822,10 +826,6 @@ export class Combobox chipEl.classList.remove(CSS.chipInvisible); } - private maxCompactBreakpoint: number; - - @State() compactDisplayMode = false; - private refreshDisplayMode = async () => { await componentLoaded(this); From cb13ecc2bb4d979c7440b9511ec2eb948cd12f68 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 14:05:39 -0800 Subject: [PATCH 53/70] removing unnecessary var assignment --- packages/calcite-components/src/components/combobox/combobox.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 5c5de2e42a7..7878024b2a7 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1453,7 +1453,6 @@ export class Combobox let chipInvisible, label; if (compactDisplayMode) { const selectedItemsCount = getSelectedItems().length; - chipInvisible = isAllSelected() ? true : false; if (isAllSelected()) { chipInvisible = true; } else if (displayMode === "fit-to-line") { From cca51b7ac486ae775ee89a8c5d32ff553df849bf Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 14:12:05 -0800 Subject: [PATCH 54/70] using pre-declared variables where necessary --- .../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 7878024b2a7..0a6b9ee1e25 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1409,7 +1409,7 @@ export class Combobox } else { chipInvisible = true; } - label = `${getSelectedItems().length} selected`; + label = `${selectedItemsCount} selected`; } else if (displayMode === "fit-to-line") { if ( (isAllSelected() && selectedVisibleChipsCount === 0) || @@ -1460,7 +1460,7 @@ export class Combobox label = `${selectedHiddenChipsCount || 0}`; } else if (displayMode === "single") { chipInvisible = selectedItemsCount > 0 ? false : true; - label = `${getSelectedItems().length}`; + label = `${selectedItemsCount}`; } } else { chipInvisible = true; From 04edfc35acc83effd8be8fe490e6c099b35ad6b6 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 14:30:08 -0800 Subject: [PATCH 55/70] using property access for closable instead of attribute --- .../calcite-components/src/components/combobox/combobox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 0a6b9ee1e25..45164e870ac 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -872,7 +872,7 @@ export class Combobox if (displayMode === "fit-to-line") { const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( - (chipEl) => chipEl.hasAttribute("closable") + (chipEl) => chipEl.closable ); let availableHorizontalChipElSpace = Math.round( From 44de454ce3422fdf2b332991d1665d8363a19a9d Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 14:47:28 -0800 Subject: [PATCH 56/70] removing allselected messages fallback --- .../calcite-components/src/components/combobox/combobox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 45164e870ac..0e1a1f884ef 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1342,7 +1342,7 @@ export class Combobox selectedVisibleChipsCount, setAllSelectedIndicatorChipEl, } = this; - const label = this.messages.allSelected || "All selected"; + const label = this.messages.allSelected; return ( Date: Fri, 17 Nov 2023 14:56:43 -0800 Subject: [PATCH 57/70] adding translation string message for selected --- .../src/components/combobox/assets/combobox/t9n/messages.json | 3 ++- .../components/combobox/assets/combobox/t9n/messages_en.json | 3 ++- .../calcite-components/src/components/combobox/combobox.tsx | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json index 4a12d4fa268..c55e973fae1 100644 --- a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json +++ b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages.json @@ -2,5 +2,6 @@ "all": "All", "allSelected": "All selected", "clear": "Clear value", - "removeTag": "Remove tag" + "removeTag": "Remove tag", + "selected": "selected" } diff --git a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json index 4a12d4fa268..c55e973fae1 100644 --- a/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json +++ b/packages/calcite-components/src/components/combobox/assets/combobox/t9n/messages_en.json @@ -2,5 +2,6 @@ "all": "All", "allSelected": "All selected", "clear": "Clear value", - "removeTag": "Remove tag" + "removeTag": "Remove tag", + "selected": "selected" } diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 0e1a1f884ef..38dc7c8c2b7 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1409,7 +1409,7 @@ export class Combobox } else { chipInvisible = true; } - label = `${selectedItemsCount} selected`; + label = `${selectedItemsCount} ${this.messages.selected}`; } else if (displayMode === "fit-to-line") { if ( (isAllSelected() && selectedVisibleChipsCount === 0) || @@ -1422,7 +1422,7 @@ export class Combobox label = selectedVisibleChipsCount > 0 ? `+${selectedHiddenChipsCount}` - : `${selectedHiddenChipsCount} selected`; + : `${selectedHiddenChipsCount} ${this.messages.selected}`; } } return ( From ff6d6f284d870a7f57304c46e28b52a86e86eb43 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 15:00:01 -0800 Subject: [PATCH 58/70] returning 0 when no element is referenced in both width util funcs --- packages/calcite-components/src/utils/dom.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/calcite-components/src/utils/dom.ts b/packages/calcite-components/src/utils/dom.ts index 895c916aac8..33f3869c81a 100644 --- a/packages/calcite-components/src/utils/dom.ts +++ b/packages/calcite-components/src/utils/dom.ts @@ -89,7 +89,7 @@ export function getElementProp(el: Element, attribute: string, fallbackValue: an */ export function getElementWidth(el: HTMLElement): number { if (!el) { - return; + return 0; } return Math.round(parseFloat(getComputedStyle(el).inlineSize.replace("px", ""))); } @@ -125,7 +125,7 @@ export function getShadowRootNode(el: Element): ShadowRoot | null { */ export function getTextWidth(text: string, font: string): number { if (!text) { - return; + return 0; } const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); From 99df18907465b4a72e7cdb9b152fd5882c60fb7c Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 15:07:52 -0800 Subject: [PATCH 59/70] simplifying getElementWidth logic --- packages/calcite-components/src/utils/dom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/utils/dom.ts b/packages/calcite-components/src/utils/dom.ts index 33f3869c81a..bed60e8d64e 100644 --- a/packages/calcite-components/src/utils/dom.ts +++ b/packages/calcite-components/src/utils/dom.ts @@ -91,7 +91,7 @@ export function getElementWidth(el: HTMLElement): number { if (!el) { return 0; } - return Math.round(parseFloat(getComputedStyle(el).inlineSize.replace("px", ""))); + return parseFloat(getComputedStyle(el).inlineSize); } /** From 300475efd390a3a061bb3c9ce49cb94d87add0e5 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 15:09:45 -0800 Subject: [PATCH 60/70] removing rounding for getTextWidth result --- packages/calcite-components/src/utils/dom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/utils/dom.ts b/packages/calcite-components/src/utils/dom.ts index bed60e8d64e..c6e6e987eba 100644 --- a/packages/calcite-components/src/utils/dom.ts +++ b/packages/calcite-components/src/utils/dom.ts @@ -130,7 +130,7 @@ export function getTextWidth(text: string, font: string): number { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); context.font = font; - return Math.ceil(context.measureText(text).width); + return context.measureText(text).width; } /** * This helper returns the host of a ShadowRoot. From 22a42e811c1440a1e257355cb3fe4b95d5c3371b Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 15:33:23 -0800 Subject: [PATCH 61/70] converting isAllSelected to a class function --- .../src/components/combobox/combobox.tsx | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 38dc7c8c2b7..2532f29545c 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1281,9 +1281,9 @@ export class Combobox } } - private isAllSelected = (): boolean => { + private isAllSelected(): boolean { return this.getItems().length === this.getSelectedItems().length; - }; + } isMulti(): boolean { return !isSingleLike(this.selectionMode); @@ -1335,20 +1335,15 @@ export class Combobox } renderAllSelectedIndicatorChip(): VNode { - const { - compactDisplayMode, - isAllSelected, - scale, - selectedVisibleChipsCount, - setAllSelectedIndicatorChipEl, - } = this; + const { compactDisplayMode, scale, selectedVisibleChipsCount, setAllSelectedIndicatorChipEl } = + this; const label = this.messages.allSelected; return ( 0) { chipInvisible = false; @@ -1412,7 +1406,7 @@ export class Combobox label = `${selectedItemsCount} ${this.messages.selected}`; } else if (displayMode === "fit-to-line") { if ( - (isAllSelected() && selectedVisibleChipsCount === 0) || + (this.isAllSelected() && selectedVisibleChipsCount === 0) || selectedHiddenChipsCount === 0 ) { chipInvisible = true; @@ -1442,18 +1436,12 @@ export class Combobox } renderSelectedIndicatorChipCompact(): VNode { - const { - compactDisplayMode, - displayMode, - getSelectedItems, - isAllSelected, - scale, - selectedHiddenChipsCount, - } = this; + const { compactDisplayMode, displayMode, getSelectedItems, scale, selectedHiddenChipsCount } = + this; let chipInvisible, label; if (compactDisplayMode) { const selectedItemsCount = getSelectedItems().length; - if (isAllSelected()) { + if (this.isAllSelected()) { chipInvisible = true; } else if (displayMode === "fit-to-line") { chipInvisible = selectedHiddenChipsCount > 0 ? false : true; From ec03bc768e03156bf3eb33dd770f06c164ac7943 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 16:32:29 -0800 Subject: [PATCH 62/70] extracting a few long lines of logic from refreshDisplayMode into their own private class functions --- .../src/components/combobox/combobox.tsx | 100 +++++++++++------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 2532f29545c..d99d38a5b10 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -826,6 +826,26 @@ export class Combobox chipEl.classList.remove(CSS.chipInvisible); } + private refreshChipDisplay({ + chipEls, + availableHorizontalChipElSpace, + chipContainerElGap, + }): void { + chipEls.forEach((chipEl: HTMLCalciteChipElement) => { + if (chipEl.selected) { + const chipElWidth = getElementWidth(chipEl); + if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { + availableHorizontalChipElSpace -= chipElWidth + chipContainerElGap; + this.showChip(chipEl); + } else { + this.hideChip(chipEl); + } + } else { + this.hideChip(chipEl); + } + }); + } + private refreshDisplayMode = async () => { await componentLoaded(this); @@ -841,11 +861,8 @@ export class Combobox allSelectedIndicatorChipEl, chipContainerEl, displayMode, - getSelectedItems, - hideChip, placeholder, selectedIndicatorChipEl, - showChip, textInput, } = this; @@ -861,14 +878,12 @@ export class Combobox selectedIndicatorChipElWidth ); - // Determine if we are in Compact Display Mode - const newCompactBreakpoint = Math.round( - largestSelectedIndicatorChipWidth + chipContainerElGap + inputWidth - ); - if (!this.maxCompactBreakpoint || this.maxCompactBreakpoint < newCompactBreakpoint) { - this.maxCompactBreakpoint = newCompactBreakpoint; - } - this.compactDisplayMode = chipContainerElWidth < this.maxCompactBreakpoint; + this.setCompactDisplayMode({ + chipContainerElGap, + chipContainerElWidth, + inputWidth, + largestSelectedIndicatorChipWidth, + }); if (displayMode === "fit-to-line") { const chipEls = Array.from(this.el.shadowRoot.querySelectorAll("calcite-chip")).filter( @@ -883,35 +898,8 @@ export class Combobox chipContainerElGap) ); - // Refresh Selected Chips - chipEls.forEach((chipEl: HTMLCalciteChipElement) => { - if (chipEl.selected) { - const chipElWidth = getElementWidth(chipEl); - if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { - availableHorizontalChipElSpace -= chipElWidth + chipContainerElGap; - showChip(chipEl); - } else { - hideChip(chipEl); - } - } else { - hideChip(chipEl); - } - }); - - // Calculate Visible and Hidden Selected Chips - let newSelectedVisibleChipsCount = 0; - chipEls.forEach((chipEl) => { - if (chipEl.selected && !chipEl.classList.contains(CSS.chipInvisible)) { - newSelectedVisibleChipsCount++; - } - }); - if (newSelectedVisibleChipsCount !== this.selectedVisibleChipsCount) { - this.selectedVisibleChipsCount = newSelectedVisibleChipsCount; - } - const newSelectedHiddenChipsCount = getSelectedItems().length - newSelectedVisibleChipsCount; - if (newSelectedHiddenChipsCount !== this.selectedHiddenChipsCount) { - this.selectedHiddenChipsCount = newSelectedHiddenChipsCount; - } + this.refreshChipDisplay({ availableHorizontalChipElSpace, chipContainerElGap, chipEls }); + this.setVisibleAndHiddenChips(chipEls); } }; @@ -920,6 +908,21 @@ export class Combobox connectFloatingUI(this, this.referenceEl, this.floatingEl); }; + private setCompactDisplayMode({ + chipContainerElGap, + chipContainerElWidth, + inputWidth, + largestSelectedIndicatorChipWidth, + }): void { + const newCompactBreakpoint = Math.round( + largestSelectedIndicatorChipWidth + chipContainerElGap + inputWidth + ); + if (!this.maxCompactBreakpoint || this.maxCompactBreakpoint < newCompactBreakpoint) { + this.maxCompactBreakpoint = newCompactBreakpoint; + } + this.compactDisplayMode = chipContainerElWidth < this.maxCompactBreakpoint; + } + setContainerEl = (el: HTMLDivElement): void => { this.resizeObserver.observe(el); this.listContainerEl = el; @@ -944,6 +947,23 @@ export class Combobox this.selectedIndicatorChipEl = el; }; + private setVisibleAndHiddenChips(chipEls: HTMLCalciteChipElement[]): void { + let newSelectedVisibleChipsCount = 0; + chipEls.forEach((chipEl) => { + if (chipEl.selected && !chipEl.classList.contains(CSS.chipInvisible)) { + newSelectedVisibleChipsCount++; + } + }); + if (newSelectedVisibleChipsCount !== this.selectedVisibleChipsCount) { + this.selectedVisibleChipsCount = newSelectedVisibleChipsCount; + } + const newSelectedHiddenChipsCount = + this.getSelectedItems().length - newSelectedVisibleChipsCount; + if (newSelectedHiddenChipsCount !== this.selectedHiddenChipsCount) { + this.selectedHiddenChipsCount = newSelectedHiddenChipsCount; + } + } + private getMaxScrollerHeight(): number { const items = this.getItemsAndGroups().filter((item) => !item.hidden); From 2d20e4ecebf136d3accfeee3f19d6d369a878ce6 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 16:39:26 -0800 Subject: [PATCH 63/70] refactoring refreshChipDisplay to return early --- .../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 d99d38a5b10..462693ef4a3 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -832,17 +832,17 @@ export class Combobox chipContainerElGap, }): void { chipEls.forEach((chipEl: HTMLCalciteChipElement) => { - if (chipEl.selected) { + if (!chipEl.selected) { + this.hideChip(chipEl); + } else { const chipElWidth = getElementWidth(chipEl); if (chipElWidth && chipElWidth < availableHorizontalChipElSpace) { availableHorizontalChipElSpace -= chipElWidth + chipContainerElGap; this.showChip(chipEl); - } else { - this.hideChip(chipEl); + return; } - } else { - this.hideChip(chipEl); } + this.hideChip(chipEl); }); } From fbacc2791f545c58c416734ef35fd2a878a2e382 Mon Sep 17 00:00:00 2001 From: Erik Harper Date: Fri, 17 Nov 2023 16:41:37 -0800 Subject: [PATCH 64/70] grouping related render calls --- .../src/components/combobox/combobox.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/calcite-components/src/components/combobox/combobox.tsx b/packages/calcite-components/src/components/combobox/combobox.tsx index 462693ef4a3..52311b6b4fc 100644 --- a/packages/calcite-components/src/components/combobox/combobox.tsx +++ b/packages/calcite-components/src/components/combobox/combobox.tsx @@ -1657,14 +1657,13 @@ export class Combobox > {this.renderIconStart()} {!singleSelectionMode && !singleDisplayMode && this.renderChips()} - {!singleSelectionMode && !showAllDisplayMode && this.renderSelectedIndicatorChip()} {!singleSelectionMode && - !showAllDisplayMode && - this.renderSelectedIndicatorChipCompact()} - {!singleSelectionMode && !showAllDisplayMode && this.renderAllSelectedIndicatorChip()} - {!singleSelectionMode && - !showAllDisplayMode && - this.renderAllSelectedIndicatorChipCompact()} + !showAllDisplayMode && [ + this.renderSelectedIndicatorChip(), + this.renderSelectedIndicatorChipCompact(), + this.renderAllSelectedIndicatorChip(), + this.renderAllSelectedIndicatorChipCompact(), + ]}