@arbor-education/design-system.components 0.22.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/component-library.md +62 -0
- package/dist/components/combobox/Combobox.js +1 -1
- package/dist/components/combobox/Combobox.js.map +1 -1
- package/dist/components/combobox/Combobox.stories.d.ts +4 -0
- package/dist/components/combobox/Combobox.stories.d.ts.map +1 -1
- package/dist/components/combobox/Combobox.stories.js +144 -12
- package/dist/components/combobox/Combobox.stories.js.map +1 -1
- package/dist/components/combobox/Combobox.test.js +22 -0
- package/dist/components/combobox/Combobox.test.js.map +1 -1
- package/dist/components/combobox/ComboboxButtonTrigger.d.ts +4 -4
- package/dist/components/combobox/ComboboxButtonTrigger.d.ts.map +1 -1
- package/dist/components/combobox/ComboboxButtonTrigger.js +35 -40
- package/dist/components/combobox/ComboboxButtonTrigger.js.map +1 -1
- package/dist/components/combobox/ComboboxTrigger.d.ts.map +1 -1
- package/dist/components/combobox/ComboboxTrigger.js +11 -4
- package/dist/components/combobox/ComboboxTrigger.js.map +1 -1
- package/dist/components/combobox/useVisibleTriggerTags.d.ts +21 -0
- package/dist/components/combobox/useVisibleTriggerTags.d.ts.map +1 -0
- package/dist/components/combobox/useVisibleTriggerTags.js +46 -0
- package/dist/components/combobox/useVisibleTriggerTags.js.map +1 -0
- package/dist/components/combobox/useVisibleTriggerTags.test.d.ts +2 -0
- package/dist/components/combobox/useVisibleTriggerTags.test.d.ts.map +1 -0
- package/dist/components/combobox/useVisibleTriggerTags.test.js +81 -0
- package/dist/components/combobox/useVisibleTriggerTags.test.js.map +1 -0
- package/dist/components/filterBar/FilterBar.d.ts +71 -0
- package/dist/components/filterBar/FilterBar.d.ts.map +1 -0
- package/dist/components/filterBar/FilterBar.js +89 -0
- package/dist/components/filterBar/FilterBar.js.map +1 -0
- package/dist/components/filterBar/FilterBar.stories.d.ts +170 -0
- package/dist/components/filterBar/FilterBar.stories.d.ts.map +1 -0
- package/dist/components/filterBar/FilterBar.stories.js +894 -0
- package/dist/components/filterBar/FilterBar.stories.js.map +1 -0
- package/dist/components/filterBar/FilterBar.test.d.ts +2 -0
- package/dist/components/filterBar/FilterBar.test.d.ts.map +1 -0
- package/dist/components/filterBar/FilterBar.test.js +164 -0
- package/dist/components/filterBar/FilterBar.test.js.map +1 -0
- package/dist/components/icon/allowedIcons.d.ts +1 -0
- package/dist/components/icon/allowedIcons.d.ts.map +1 -1
- package/dist/components/icon/allowedIcons.js +2 -1
- package/dist/components/icon/allowedIcons.js.map +1 -1
- package/dist/components/table/cellRenderers/ComboboxCellRenderer.test.d.ts.map +1 -1
- package/dist/components/table/cellRenderers/ComboboxCellRenderer.test.js +13 -2
- package/dist/components/table/cellRenderers/ComboboxCellRenderer.test.js.map +1 -1
- package/dist/index.css +142 -3
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/combobox/Combobox.stories.tsx +186 -12
- package/src/components/combobox/Combobox.test.tsx +53 -0
- package/src/components/combobox/Combobox.tsx +3 -3
- package/src/components/combobox/ComboboxButtonTrigger.tsx +52 -56
- package/src/components/combobox/ComboboxTrigger.tsx +19 -16
- package/src/components/combobox/combobox.scss +8 -3
- package/src/components/combobox/useVisibleTriggerTags.test.tsx +91 -0
- package/src/components/combobox/useVisibleTriggerTags.ts +83 -0
- package/src/components/filterBar/FilterBar.stories.tsx +1199 -0
- package/src/components/filterBar/FilterBar.test.tsx +248 -0
- package/src/components/filterBar/FilterBar.tsx +298 -0
- package/src/components/filterBar/filterBar.scss +143 -0
- package/src/components/icon/allowedIcons.tsx +3 -1
- package/src/components/table/cellRenderers/ComboboxCellRenderer.test.tsx +20 -3
- package/src/index.scss +3 -0
- package/src/index.ts +10 -0
- package/src/tokens.scss +1 -0
- package/stylelint.config.mjs +1 -0
- package/dist/components/combobox/useElementWidth.d.ts +0 -2
- package/dist/components/combobox/useElementWidth.d.ts.map +0 -1
- package/dist/components/combobox/useElementWidth.js +0 -31
- package/dist/components/combobox/useElementWidth.js.map +0 -1
- package/dist/components/combobox/useVisibleChips.d.ts +0 -21
- package/dist/components/combobox/useVisibleChips.d.ts.map +0 -1
- package/dist/components/combobox/useVisibleChips.js +0 -59
- package/dist/components/combobox/useVisibleChips.js.map +0 -1
- package/dist/components/combobox/useVisibleChips.test.d.ts +0 -2
- package/dist/components/combobox/useVisibleChips.test.d.ts.map +0 -1
- package/dist/components/combobox/useVisibleChips.test.js +0 -81
- package/dist/components/combobox/useVisibleChips.test.js.map +0 -1
- package/src/components/combobox/useElementWidth.ts +0 -40
- package/src/components/combobox/useVisibleChips.test.tsx +0 -91
- package/src/components/combobox/useVisibleChips.ts +0 -100
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
Link,
|
|
56
56
|
List,
|
|
57
57
|
ListFilterPlus,
|
|
58
|
+
ListTree,
|
|
58
59
|
LoaderCircle,
|
|
59
60
|
Lock,
|
|
60
61
|
LockOpen,
|
|
@@ -90,10 +91,10 @@ import {
|
|
|
90
91
|
UsersRound, X,
|
|
91
92
|
} from 'lucide-react';
|
|
92
93
|
import { AskArbor } from './customIcons/AskArbor.js';
|
|
93
|
-
import type { CustomIconProps } from './types.js';
|
|
94
94
|
import { CheckSolid } from './customIcons/CheckSolid.js';
|
|
95
95
|
import { Google } from './customIcons/Google.js';
|
|
96
96
|
import { XSolid } from './customIcons/XSolid.js';
|
|
97
|
+
import type { CustomIconProps } from './types.js';
|
|
97
98
|
|
|
98
99
|
export const allowedIcons = {
|
|
99
100
|
// lucide icons
|
|
@@ -156,6 +157,7 @@ export const allowedIcons = {
|
|
|
156
157
|
'link': Link,
|
|
157
158
|
'list-filter-plus': ListFilterPlus,
|
|
158
159
|
'list': List,
|
|
160
|
+
'list-tree': ListTree,
|
|
159
161
|
'loader': LoaderCircle,
|
|
160
162
|
'lock-open': LockOpen,
|
|
161
163
|
'lock': Lock,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { describe, expect, test, vi, afterEach } from 'vitest';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
1
|
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
4
3
|
import userEvent from '@testing-library/user-event';
|
|
5
4
|
import type { SuppressKeyboardEventParams } from 'ag-grid-community';
|
|
6
5
|
import type { CustomCellRendererProps } from 'ag-grid-react';
|
|
7
|
-
import { ComboboxCellRenderer } from './ComboboxCellRenderer.js';
|
|
8
6
|
import type { ComboboxOption, ComboboxProps } from 'Components/combobox/types';
|
|
7
|
+
import { afterEach, describe, expect, test, vi } from 'vitest';
|
|
8
|
+
import { ComboboxCellRenderer } from './ComboboxCellRenderer.js';
|
|
9
9
|
|
|
10
10
|
const options: ComboboxOption[] = [
|
|
11
11
|
{ value: 'opt1', label: 'Option 1' },
|
|
@@ -104,6 +104,23 @@ describe('ComboboxCellRenderer', () => {
|
|
|
104
104
|
expect(screen.getByRole('combobox')).toBeInTheDocument();
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
+
test('renders selected tags for multiple button-trigger values', () => {
|
|
108
|
+
const { container } = render(
|
|
109
|
+
<ComboboxCellRenderer
|
|
110
|
+
{...createMockProps({
|
|
111
|
+
'value': ['opt1', 'opt2'],
|
|
112
|
+
'multiple': true,
|
|
113
|
+
'triggerVariant': 'button',
|
|
114
|
+
'aria-label': 'Choose tags',
|
|
115
|
+
})}
|
|
116
|
+
/>,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
expect(screen.getByRole('button', { name: 'Choose tags' })).toBeInTheDocument();
|
|
120
|
+
expect(container.querySelector('.ds-combobox__button-tags-viewport .ds-tag-list')).toBeInTheDocument();
|
|
121
|
+
expect(container.querySelectorAll('.ds-combobox__button-tags-viewport .ds-tag')).toHaveLength(2);
|
|
122
|
+
});
|
|
123
|
+
|
|
107
124
|
test('registers cellKeyDown listener on mount', () => {
|
|
108
125
|
const addEventListener = vi.fn();
|
|
109
126
|
const removeEventListener = vi.fn();
|
package/src/index.scss
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
@use "components/formField/inputs/colourPickerDropdown/colourPickerDropdown.scss";
|
|
21
21
|
@use "components/tag/tag.scss";
|
|
22
22
|
@use "components/tagList/tagList.scss";
|
|
23
|
+
@use "components/filterBar/filterBar.scss";
|
|
23
24
|
@use "components/dot/dot.scss";
|
|
24
25
|
@use "components/badge/badge.scss";
|
|
25
26
|
@use "components/pill/pill.scss";
|
|
@@ -54,4 +55,6 @@
|
|
|
54
55
|
@use "components/toggle/toggle.scss";
|
|
55
56
|
@use "components/dataViewCard/dataViewCard.scss";
|
|
56
57
|
@use "components/treeRow/treeRow.scss";
|
|
58
|
+
|
|
59
|
+
// stylelint-disable-next-line at-rule-disallowed-list -- plain CSS import (font face), exempt from Sass @import deprecation
|
|
57
60
|
@import "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap";
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,16 @@ export { DateTimePicker } from 'Components/dateTimePicker/DateTimePicker';
|
|
|
11
11
|
export { Dot } from 'Components/dot/Dot';
|
|
12
12
|
export { Dropdown } from 'Components/dropdown/Dropdown';
|
|
13
13
|
export { EditableText } from 'Components/editableText/EditableText';
|
|
14
|
+
export {
|
|
15
|
+
FilterBar,
|
|
16
|
+
type FilterBarActiveListProps,
|
|
17
|
+
type FilterBarButtonProps,
|
|
18
|
+
type FilterBarProps,
|
|
19
|
+
type FilterBarTagItem,
|
|
20
|
+
type FilterBarTagProps,
|
|
21
|
+
type FilterBarToolbarProps,
|
|
22
|
+
type FilterBarType,
|
|
23
|
+
} from 'Components/filterBar/FilterBar';
|
|
14
24
|
export { Fieldset } from 'Components/formField/fieldset/Fieldset';
|
|
15
25
|
export { FormField } from 'Components/formField/FormField';
|
|
16
26
|
export { CheckboxGroup } from 'Components/formField/inputs/checkbox/CheckboxGroup';
|
package/src/tokens.scss
CHANGED
|
@@ -476,6 +476,7 @@
|
|
|
476
476
|
--banner-spacing-vertical: var(--spacing-large);
|
|
477
477
|
--banner-spacing-horizontal: var(--spacing-large);
|
|
478
478
|
--button-small-radius: var(--border-radius-round);
|
|
479
|
+
--button-toolbar-radius: var(--border-radius-small);
|
|
479
480
|
--button-small-primary-focus-color-icon: var(--color-mono-white);
|
|
480
481
|
--button-small-primary-focus-color-text: var(--color-mono-white);
|
|
481
482
|
--button-small-primary-focus-color-background: var(--color-brand-600);
|
package/stylelint.config.mjs
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useElementWidth.d.ts","sourceRoot":"","sources":["../../../src/components/combobox/useElementWidth.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,GAC1B,KAAK,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EACxC,UAAU,MAAM,KACf,MAkCF,CAAC"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { useCallback, useLayoutEffect, useState } from 'react';
|
|
2
|
-
export const useElementWidth = (ref, watchKey) => {
|
|
3
|
-
const [measurement, setMeasurement] = useState({ width: 0, hasMeasured: false });
|
|
4
|
-
const element = ref.current;
|
|
5
|
-
const update = useCallback(() => {
|
|
6
|
-
const currentElement = ref.current;
|
|
7
|
-
if (!currentElement) {
|
|
8
|
-
setMeasurement({ width: 0, hasMeasured: true });
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
setMeasurement({
|
|
12
|
-
width: currentElement.getBoundingClientRect().width,
|
|
13
|
-
hasMeasured: true,
|
|
14
|
-
});
|
|
15
|
-
}, [ref]);
|
|
16
|
-
useLayoutEffect(() => {
|
|
17
|
-
// Re-run measurement when callers know the element's contents/layout inputs changed.
|
|
18
|
-
update();
|
|
19
|
-
}, [update, watchKey]);
|
|
20
|
-
useLayoutEffect(() => {
|
|
21
|
-
if (!element)
|
|
22
|
-
return;
|
|
23
|
-
const observer = new ResizeObserver(update);
|
|
24
|
-
observer.observe(element);
|
|
25
|
-
return () => {
|
|
26
|
-
observer.disconnect();
|
|
27
|
-
};
|
|
28
|
-
}, [element, update]);
|
|
29
|
-
return measurement.width;
|
|
30
|
-
};
|
|
31
|
-
//# sourceMappingURL=useElementWidth.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useElementWidth.js","sourceRoot":"","sources":["../../../src/components/combobox/useElementWidth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE/D,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAAwC,EACxC,QAAgB,EACR,EAAE;IACV,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAE5B,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC;QACnC,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QAED,cAAc,CAAC;YACb,KAAK,EAAE,cAAc,CAAC,qBAAqB,EAAE,CAAC,KAAK;YACnD,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEV,eAAe,CAAC,GAAG,EAAE;QACnB,qFAAqF;QACrF,MAAM,EAAE,CAAC;IACX,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvB,eAAe,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QAC5C,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE1B,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,UAAU,EAAE,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAEtB,OAAO,WAAW,CAAC,KAAK,CAAC;AAC3B,CAAC,CAAC"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
type ComputeTriggerLayoutModelParams = {
|
|
2
|
-
containerWidth: number;
|
|
3
|
-
chipWidths: number[];
|
|
4
|
-
chipGap: number;
|
|
5
|
-
badgeWidth: number;
|
|
6
|
-
ellipsisWidth: number;
|
|
7
|
-
showBadge: boolean;
|
|
8
|
-
safetyBuffer?: number;
|
|
9
|
-
};
|
|
10
|
-
export type TriggerLayoutModel = {
|
|
11
|
-
visibleChipIndices: number[];
|
|
12
|
-
hiddenChipCount: number;
|
|
13
|
-
showBadge: boolean;
|
|
14
|
-
showEllipsis: boolean;
|
|
15
|
-
hasOverflow: boolean;
|
|
16
|
-
};
|
|
17
|
-
export declare const computeTriggerLayoutModel: ({ containerWidth, chipWidths, chipGap, badgeWidth, ellipsisWidth, showBadge, safetyBuffer, }: ComputeTriggerLayoutModelParams) => TriggerLayoutModel;
|
|
18
|
-
type UseVisibleChipsParams = ComputeTriggerLayoutModelParams;
|
|
19
|
-
export declare const useVisibleChips: (params: UseVisibleChipsParams) => TriggerLayoutModel;
|
|
20
|
-
export {};
|
|
21
|
-
//# sourceMappingURL=useVisibleChips.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useVisibleChips.d.ts","sourceRoot":"","sources":["../../../src/components/combobox/useVisibleChips.ts"],"names":[],"mappings":"AAEA,KAAK,+BAA+B,GAAG;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAoBF,eAAO,MAAM,yBAAyB,GAAI,8FAQvC,+BAA+B,KAAG,kBAmCpC,CAAC;AAEF,KAAK,qBAAqB,GAAG,+BAA+B,CAAC;AAE7D,eAAO,MAAM,eAAe,GAAI,QAAQ,qBAAqB,KAAG,kBAc7D,CAAC"}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
const fitCount = (availableWidth, chipWidths, chipGap) => {
|
|
3
|
-
if (availableWidth <= 0 || chipWidths.length === 0)
|
|
4
|
-
return 0;
|
|
5
|
-
let used = 0;
|
|
6
|
-
let count = 0;
|
|
7
|
-
for (let i = 0; i < chipWidths.length; i += 1) {
|
|
8
|
-
const required = chipWidths[i] + (i > 0 ? chipGap : 0);
|
|
9
|
-
if (used + required > availableWidth)
|
|
10
|
-
break;
|
|
11
|
-
used += required;
|
|
12
|
-
count += 1;
|
|
13
|
-
}
|
|
14
|
-
return count;
|
|
15
|
-
};
|
|
16
|
-
export const computeTriggerLayoutModel = ({ containerWidth, chipWidths, chipGap, badgeWidth, ellipsisWidth, showBadge, safetyBuffer = 1, }) => {
|
|
17
|
-
const selectedCount = chipWidths.length;
|
|
18
|
-
const shouldShowBadge = showBadge && selectedCount > 0;
|
|
19
|
-
if (selectedCount === 0 || containerWidth <= 0) {
|
|
20
|
-
return {
|
|
21
|
-
visibleChipIndices: [],
|
|
22
|
-
hiddenChipCount: 0,
|
|
23
|
-
showBadge: shouldShowBadge,
|
|
24
|
-
showEllipsis: false,
|
|
25
|
-
hasOverflow: false,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
const badgeReserve = shouldShowBadge
|
|
29
|
-
? badgeWidth + chipGap
|
|
30
|
-
: 0;
|
|
31
|
-
const availableWithoutEllipsis = Math.max(0, containerWidth - badgeReserve - safetyBuffer);
|
|
32
|
-
const countWithoutEllipsis = fitCount(availableWithoutEllipsis, chipWidths, chipGap);
|
|
33
|
-
const hasOverflow = countWithoutEllipsis < selectedCount;
|
|
34
|
-
const ellipsisReserve = hasOverflow
|
|
35
|
-
? ellipsisWidth + chipGap
|
|
36
|
-
: 0;
|
|
37
|
-
const availableForChips = Math.max(0, containerWidth - badgeReserve - ellipsisReserve - safetyBuffer);
|
|
38
|
-
const visibleCount = fitCount(availableForChips, chipWidths, chipGap);
|
|
39
|
-
return {
|
|
40
|
-
visibleChipIndices: Array.from({ length: visibleCount }, (_, index) => index),
|
|
41
|
-
hiddenChipCount: Math.max(0, selectedCount - visibleCount),
|
|
42
|
-
showBadge: shouldShowBadge,
|
|
43
|
-
showEllipsis: visibleCount < selectedCount,
|
|
44
|
-
hasOverflow: visibleCount < selectedCount,
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
export const useVisibleChips = (params) =>
|
|
48
|
-
// Deps list each field instead of `[params]`: callers often pass a new `params` object every
|
|
49
|
-
// render; depending on object identity would rerun the layout every time even when values are unchanged.
|
|
50
|
-
useMemo(() => computeTriggerLayoutModel(params), [
|
|
51
|
-
params.badgeWidth,
|
|
52
|
-
params.chipGap,
|
|
53
|
-
params.chipWidths,
|
|
54
|
-
params.containerWidth,
|
|
55
|
-
params.ellipsisWidth,
|
|
56
|
-
params.safetyBuffer,
|
|
57
|
-
params.showBadge,
|
|
58
|
-
]);
|
|
59
|
-
//# sourceMappingURL=useVisibleChips.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useVisibleChips.js","sourceRoot":"","sources":["../../../src/components/combobox/useVisibleChips.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useVisibleChips.test.d.ts","sourceRoot":"","sources":["../../../src/components/combobox/useVisibleChips.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { computeTriggerLayoutModel } from './useVisibleChips.js';
|
|
3
|
-
describe('computeTriggerLayoutModel', () => {
|
|
4
|
-
test('shows all chips and no ellipsis when there is no overflow', () => {
|
|
5
|
-
const result = computeTriggerLayoutModel({
|
|
6
|
-
containerWidth: 300,
|
|
7
|
-
chipWidths: [70, 80, 60],
|
|
8
|
-
chipGap: 4,
|
|
9
|
-
badgeWidth: 24,
|
|
10
|
-
ellipsisWidth: 12,
|
|
11
|
-
showBadge: true,
|
|
12
|
-
});
|
|
13
|
-
expect(result).toEqual({
|
|
14
|
-
visibleChipIndices: [0, 1, 2],
|
|
15
|
-
hiddenChipCount: 0,
|
|
16
|
-
showBadge: true,
|
|
17
|
-
showEllipsis: false,
|
|
18
|
-
hasOverflow: false,
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
test('reserves badge and ellipsis before fitting chips when overflow exists', () => {
|
|
22
|
-
const result = computeTriggerLayoutModel({
|
|
23
|
-
containerWidth: 160,
|
|
24
|
-
chipWidths: [60, 60, 60],
|
|
25
|
-
chipGap: 4,
|
|
26
|
-
badgeWidth: 24,
|
|
27
|
-
ellipsisWidth: 12,
|
|
28
|
-
showBadge: true,
|
|
29
|
-
});
|
|
30
|
-
expect(result.visibleChipIndices).toEqual([0]);
|
|
31
|
-
expect(result.hiddenChipCount).toBe(2);
|
|
32
|
-
expect(result.showEllipsis).toBe(true);
|
|
33
|
-
expect(result.hasOverflow).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
test('allows zero chips when badge and ellipsis take priority in tiny space', () => {
|
|
36
|
-
const result = computeTriggerLayoutModel({
|
|
37
|
-
containerWidth: 36,
|
|
38
|
-
chipWidths: [80, 80],
|
|
39
|
-
chipGap: 4,
|
|
40
|
-
badgeWidth: 24,
|
|
41
|
-
ellipsisWidth: 12,
|
|
42
|
-
showBadge: true,
|
|
43
|
-
});
|
|
44
|
-
expect(result.visibleChipIndices).toEqual([]);
|
|
45
|
-
expect(result.hiddenChipCount).toBe(2);
|
|
46
|
-
expect(result.showEllipsis).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
test('reserving badge space reduces visible count', () => {
|
|
49
|
-
const withBadge = computeTriggerLayoutModel({
|
|
50
|
-
containerWidth: 180,
|
|
51
|
-
chipWidths: [60, 60, 60],
|
|
52
|
-
chipGap: 4,
|
|
53
|
-
badgeWidth: 24,
|
|
54
|
-
ellipsisWidth: 12,
|
|
55
|
-
showBadge: true,
|
|
56
|
-
});
|
|
57
|
-
const withoutBadge = computeTriggerLayoutModel({
|
|
58
|
-
containerWidth: 180,
|
|
59
|
-
chipWidths: [60, 60, 60],
|
|
60
|
-
chipGap: 4,
|
|
61
|
-
badgeWidth: 24,
|
|
62
|
-
ellipsisWidth: 12,
|
|
63
|
-
showBadge: false,
|
|
64
|
-
});
|
|
65
|
-
expect(withoutBadge.visibleChipIndices.length).toBeGreaterThanOrEqual(withBadge.visibleChipIndices.length);
|
|
66
|
-
});
|
|
67
|
-
test('uses safety buffer to avoid a clipped final chip on boundary widths', () => {
|
|
68
|
-
const result = computeTriggerLayoutModel({
|
|
69
|
-
containerWidth: 195.5,
|
|
70
|
-
chipWidths: [73.4, 73.4, 20],
|
|
71
|
-
chipGap: 4,
|
|
72
|
-
badgeWidth: 24.2,
|
|
73
|
-
ellipsisWidth: 11.6,
|
|
74
|
-
showBadge: true,
|
|
75
|
-
safetyBuffer: 1,
|
|
76
|
-
});
|
|
77
|
-
expect(result.visibleChipIndices).toEqual([0]);
|
|
78
|
-
expect(result.showEllipsis).toBe(true);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
//# sourceMappingURL=useVisibleChips.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useVisibleChips.test.js","sourceRoot":"","sources":["../../../src/components/combobox/useVisibleChips.test.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { useCallback, useLayoutEffect, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
export const useElementWidth = (
|
|
4
|
-
ref: React.RefObject<HTMLElement | null>,
|
|
5
|
-
watchKey: string,
|
|
6
|
-
): number => {
|
|
7
|
-
const [measurement, setMeasurement] = useState({ width: 0, hasMeasured: false });
|
|
8
|
-
const element = ref.current;
|
|
9
|
-
|
|
10
|
-
const update = useCallback(() => {
|
|
11
|
-
const currentElement = ref.current;
|
|
12
|
-
if (!currentElement) {
|
|
13
|
-
setMeasurement({ width: 0, hasMeasured: true });
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
setMeasurement({
|
|
18
|
-
width: currentElement.getBoundingClientRect().width,
|
|
19
|
-
hasMeasured: true,
|
|
20
|
-
});
|
|
21
|
-
}, [ref]);
|
|
22
|
-
|
|
23
|
-
useLayoutEffect(() => {
|
|
24
|
-
// Re-run measurement when callers know the element's contents/layout inputs changed.
|
|
25
|
-
update();
|
|
26
|
-
}, [update, watchKey]);
|
|
27
|
-
|
|
28
|
-
useLayoutEffect(() => {
|
|
29
|
-
if (!element) return;
|
|
30
|
-
|
|
31
|
-
const observer = new ResizeObserver(update);
|
|
32
|
-
observer.observe(element);
|
|
33
|
-
|
|
34
|
-
return () => {
|
|
35
|
-
observer.disconnect();
|
|
36
|
-
};
|
|
37
|
-
}, [element, update]);
|
|
38
|
-
|
|
39
|
-
return measurement.width;
|
|
40
|
-
};
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { computeTriggerLayoutModel } from './useVisibleChips.js';
|
|
3
|
-
|
|
4
|
-
describe('computeTriggerLayoutModel', () => {
|
|
5
|
-
test('shows all chips and no ellipsis when there is no overflow', () => {
|
|
6
|
-
const result = computeTriggerLayoutModel({
|
|
7
|
-
containerWidth: 300,
|
|
8
|
-
chipWidths: [70, 80, 60],
|
|
9
|
-
chipGap: 4,
|
|
10
|
-
badgeWidth: 24,
|
|
11
|
-
ellipsisWidth: 12,
|
|
12
|
-
showBadge: true,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
expect(result).toEqual({
|
|
16
|
-
visibleChipIndices: [0, 1, 2],
|
|
17
|
-
hiddenChipCount: 0,
|
|
18
|
-
showBadge: true,
|
|
19
|
-
showEllipsis: false,
|
|
20
|
-
hasOverflow: false,
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('reserves badge and ellipsis before fitting chips when overflow exists', () => {
|
|
25
|
-
const result = computeTriggerLayoutModel({
|
|
26
|
-
containerWidth: 160,
|
|
27
|
-
chipWidths: [60, 60, 60],
|
|
28
|
-
chipGap: 4,
|
|
29
|
-
badgeWidth: 24,
|
|
30
|
-
ellipsisWidth: 12,
|
|
31
|
-
showBadge: true,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
expect(result.visibleChipIndices).toEqual([0]);
|
|
35
|
-
expect(result.hiddenChipCount).toBe(2);
|
|
36
|
-
expect(result.showEllipsis).toBe(true);
|
|
37
|
-
expect(result.hasOverflow).toBe(true);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('allows zero chips when badge and ellipsis take priority in tiny space', () => {
|
|
41
|
-
const result = computeTriggerLayoutModel({
|
|
42
|
-
containerWidth: 36,
|
|
43
|
-
chipWidths: [80, 80],
|
|
44
|
-
chipGap: 4,
|
|
45
|
-
badgeWidth: 24,
|
|
46
|
-
ellipsisWidth: 12,
|
|
47
|
-
showBadge: true,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
expect(result.visibleChipIndices).toEqual([]);
|
|
51
|
-
expect(result.hiddenChipCount).toBe(2);
|
|
52
|
-
expect(result.showEllipsis).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('reserving badge space reduces visible count', () => {
|
|
56
|
-
const withBadge = computeTriggerLayoutModel({
|
|
57
|
-
containerWidth: 180,
|
|
58
|
-
chipWidths: [60, 60, 60],
|
|
59
|
-
chipGap: 4,
|
|
60
|
-
badgeWidth: 24,
|
|
61
|
-
ellipsisWidth: 12,
|
|
62
|
-
showBadge: true,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const withoutBadge = computeTriggerLayoutModel({
|
|
66
|
-
containerWidth: 180,
|
|
67
|
-
chipWidths: [60, 60, 60],
|
|
68
|
-
chipGap: 4,
|
|
69
|
-
badgeWidth: 24,
|
|
70
|
-
ellipsisWidth: 12,
|
|
71
|
-
showBadge: false,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
expect(withoutBadge.visibleChipIndices.length).toBeGreaterThanOrEqual(withBadge.visibleChipIndices.length);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('uses safety buffer to avoid a clipped final chip on boundary widths', () => {
|
|
78
|
-
const result = computeTriggerLayoutModel({
|
|
79
|
-
containerWidth: 195.5,
|
|
80
|
-
chipWidths: [73.4, 73.4, 20],
|
|
81
|
-
chipGap: 4,
|
|
82
|
-
badgeWidth: 24.2,
|
|
83
|
-
ellipsisWidth: 11.6,
|
|
84
|
-
showBadge: true,
|
|
85
|
-
safetyBuffer: 1,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
expect(result.visibleChipIndices).toEqual([0]);
|
|
89
|
-
expect(result.showEllipsis).toBe(true);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
|
|
3
|
-
type ComputeTriggerLayoutModelParams = {
|
|
4
|
-
containerWidth: number;
|
|
5
|
-
chipWidths: number[];
|
|
6
|
-
chipGap: number;
|
|
7
|
-
badgeWidth: number;
|
|
8
|
-
ellipsisWidth: number;
|
|
9
|
-
showBadge: boolean;
|
|
10
|
-
safetyBuffer?: number;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export type TriggerLayoutModel = {
|
|
14
|
-
visibleChipIndices: number[];
|
|
15
|
-
hiddenChipCount: number;
|
|
16
|
-
showBadge: boolean;
|
|
17
|
-
showEllipsis: boolean;
|
|
18
|
-
hasOverflow: boolean;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const fitCount = (
|
|
22
|
-
availableWidth: number,
|
|
23
|
-
chipWidths: number[],
|
|
24
|
-
chipGap: number,
|
|
25
|
-
): number => {
|
|
26
|
-
if (availableWidth <= 0 || chipWidths.length === 0) return 0;
|
|
27
|
-
|
|
28
|
-
let used = 0;
|
|
29
|
-
let count = 0;
|
|
30
|
-
for (let i = 0; i < chipWidths.length; i += 1) {
|
|
31
|
-
const required = chipWidths[i]! + (i > 0 ? chipGap : 0);
|
|
32
|
-
if (used + required > availableWidth) break;
|
|
33
|
-
used += required;
|
|
34
|
-
count += 1;
|
|
35
|
-
}
|
|
36
|
-
return count;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const computeTriggerLayoutModel = ({
|
|
40
|
-
containerWidth,
|
|
41
|
-
chipWidths,
|
|
42
|
-
chipGap,
|
|
43
|
-
badgeWidth,
|
|
44
|
-
ellipsisWidth,
|
|
45
|
-
showBadge,
|
|
46
|
-
safetyBuffer = 1,
|
|
47
|
-
}: ComputeTriggerLayoutModelParams): TriggerLayoutModel => {
|
|
48
|
-
const selectedCount = chipWidths.length;
|
|
49
|
-
const shouldShowBadge = showBadge && selectedCount > 0;
|
|
50
|
-
|
|
51
|
-
if (selectedCount === 0 || containerWidth <= 0) {
|
|
52
|
-
return {
|
|
53
|
-
visibleChipIndices: [],
|
|
54
|
-
hiddenChipCount: 0,
|
|
55
|
-
showBadge: shouldShowBadge,
|
|
56
|
-
showEllipsis: false,
|
|
57
|
-
hasOverflow: false,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const badgeReserve = shouldShowBadge
|
|
62
|
-
? badgeWidth + chipGap
|
|
63
|
-
: 0;
|
|
64
|
-
|
|
65
|
-
const availableWithoutEllipsis = Math.max(0, containerWidth - badgeReserve - safetyBuffer);
|
|
66
|
-
const countWithoutEllipsis = fitCount(availableWithoutEllipsis, chipWidths, chipGap);
|
|
67
|
-
const hasOverflow = countWithoutEllipsis < selectedCount;
|
|
68
|
-
|
|
69
|
-
const ellipsisReserve = hasOverflow
|
|
70
|
-
? ellipsisWidth + chipGap
|
|
71
|
-
: 0;
|
|
72
|
-
const availableForChips = Math.max(0, containerWidth - badgeReserve - ellipsisReserve - safetyBuffer);
|
|
73
|
-
const visibleCount = fitCount(availableForChips, chipWidths, chipGap);
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
visibleChipIndices: Array.from({ length: visibleCount }, (_, index) => index),
|
|
77
|
-
hiddenChipCount: Math.max(0, selectedCount - visibleCount),
|
|
78
|
-
showBadge: shouldShowBadge,
|
|
79
|
-
showEllipsis: visibleCount < selectedCount,
|
|
80
|
-
hasOverflow: visibleCount < selectedCount,
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
type UseVisibleChipsParams = ComputeTriggerLayoutModelParams;
|
|
85
|
-
|
|
86
|
-
export const useVisibleChips = (params: UseVisibleChipsParams): TriggerLayoutModel =>
|
|
87
|
-
// Deps list each field instead of `[params]`: callers often pass a new `params` object every
|
|
88
|
-
// render; depending on object identity would rerun the layout every time even when values are unchanged.
|
|
89
|
-
useMemo(
|
|
90
|
-
() => computeTriggerLayoutModel(params),
|
|
91
|
-
[
|
|
92
|
-
params.badgeWidth,
|
|
93
|
-
params.chipGap,
|
|
94
|
-
params.chipWidths,
|
|
95
|
-
params.containerWidth,
|
|
96
|
-
params.ellipsisWidth,
|
|
97
|
-
params.safetyBuffer,
|
|
98
|
-
params.showBadge,
|
|
99
|
-
],
|
|
100
|
-
);
|