@arbor-education/design-system.components 3.6.0 → 4.0.0

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/components/combobox/ComboboxButtonTrigger.d.ts +1 -1
  3. package/dist/components/combobox/ComboboxButtonTrigger.d.ts.map +1 -1
  4. package/dist/components/combobox/ComboboxListbox.d.ts +2 -2
  5. package/dist/components/combobox/ComboboxListbox.d.ts.map +1 -1
  6. package/dist/components/combobox/ComboboxTrigger.d.ts +2 -2
  7. package/dist/components/combobox/ComboboxTrigger.d.ts.map +1 -1
  8. package/dist/components/combobox/useComboboxListboxDom.d.ts +1 -1
  9. package/dist/components/combobox/useComboboxListboxDom.d.ts.map +1 -1
  10. package/dist/components/heading/Heading.d.ts +28 -14
  11. package/dist/components/heading/Heading.d.ts.map +1 -1
  12. package/dist/components/heading/Heading.stories.d.ts +28 -14
  13. package/dist/components/heading/Heading.stories.d.ts.map +1 -1
  14. package/dist/components/table/Table.test.js +18 -14
  15. package/dist/components/table/Table.test.js.map +1 -1
  16. package/dist/components/tabs/TabsItem.stories.d.ts +50 -22
  17. package/dist/components/tabs/TabsItem.stories.d.ts.map +1 -1
  18. package/dist/components/tagList/useTagListCollapsedLayout.d.ts +3 -3
  19. package/dist/components/tagList/useTagListCollapsedLayout.d.ts.map +1 -1
  20. package/dist/packageManifest.test.d.ts +2 -0
  21. package/dist/packageManifest.test.d.ts.map +1 -0
  22. package/dist/packageManifest.test.js +22 -0
  23. package/dist/packageManifest.test.js.map +1 -0
  24. package/dist/utils/hooks/useIsMounted.d.ts +1 -1
  25. package/dist/utils/hooks/useIsMounted.d.ts.map +1 -1
  26. package/package.json +19 -5
  27. package/src/components/arborLogo/__snapshots__/ArborLogo.test.tsx.snap +18 -18
  28. package/src/components/combobox/ComboboxButtonTrigger.tsx +1 -1
  29. package/src/components/combobox/ComboboxListbox.tsx +2 -2
  30. package/src/components/combobox/ComboboxTrigger.tsx +2 -2
  31. package/src/components/combobox/useComboboxListboxDom.ts +1 -1
  32. package/src/components/table/Table.test.tsx +18 -14
  33. package/src/components/tagList/useTagListCollapsedLayout.ts +3 -3
  34. package/src/docs/UsingComponents.mdx +6 -0
  35. package/src/packageManifest.test.ts +43 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  exports[`ArborLogo > renders the icon-only variant 1`] = `
4
4
  <svg
5
- aria-labelledby=":r1:"
5
+ aria-labelledby="_r_1_"
6
6
  fill="none"
7
7
  height="25"
8
8
  role="img"
@@ -11,12 +11,12 @@ exports[`ArborLogo > renders the icon-only variant 1`] = `
11
11
  xmlns="http://www.w3.org/2000/svg"
12
12
  >
13
13
  <title
14
- id=":r1:"
14
+ id="_r_1_"
15
15
  >
16
16
  Arbor
17
17
  </title>
18
18
  <g
19
- clip-path="url(#:r0:)"
19
+ clip-path="url(#_r_0_)"
20
20
  >
21
21
  <path
22
22
  d="M12.6821 12.448C12.6821 9.06699 15.4229 6.32623 18.8039 6.32623C18.8039 2.94571 16.0631 0.205391 12.6817 0.205391C9.30163 0.205391 6.56086 2.94571 6.56042 6.32623C9.94138 6.32623 12.6817 9.06699 12.6821 12.448Z"
@@ -53,7 +53,7 @@ exports[`ArborLogo > renders the icon-only variant 1`] = `
53
53
  </g>
54
54
  <defs>
55
55
  <clippath
56
- id=":r0:"
56
+ id="_r_0_"
57
57
  >
58
58
  <rect
59
59
  fill="white"
@@ -67,7 +67,7 @@ exports[`ArborLogo > renders the icon-only variant 1`] = `
67
67
 
68
68
  exports[`ArborLogo > renders the icon-only variant with a custom aria-label 1`] = `
69
69
  <svg
70
- aria-labelledby=":r5:"
70
+ aria-labelledby="_r_5_"
71
71
  fill="none"
72
72
  height="25"
73
73
  role="img"
@@ -76,12 +76,12 @@ exports[`ArborLogo > renders the icon-only variant with a custom aria-label 1`]
76
76
  xmlns="http://www.w3.org/2000/svg"
77
77
  >
78
78
  <title
79
- id=":r5:"
79
+ id="_r_5_"
80
80
  >
81
81
  Arbor Education logo
82
82
  </title>
83
83
  <g
84
- clip-path="url(#:r4:)"
84
+ clip-path="url(#_r_4_)"
85
85
  >
86
86
  <path
87
87
  d="M12.6821 12.448C12.6821 9.06699 15.4229 6.32623 18.8039 6.32623C18.8039 2.94571 16.0631 0.205391 12.6817 0.205391C9.30163 0.205391 6.56086 2.94571 6.56042 6.32623C9.94138 6.32623 12.6817 9.06699 12.6821 12.448Z"
@@ -118,7 +118,7 @@ exports[`ArborLogo > renders the icon-only variant with a custom aria-label 1`]
118
118
  </g>
119
119
  <defs>
120
120
  <clippath
121
- id=":r4:"
121
+ id="_r_4_"
122
122
  >
123
123
  <rect
124
124
  fill="white"
@@ -140,7 +140,7 @@ exports[`ArborLogo > renders the icon-only variant with aria-hidden 1`] = `
140
140
  xmlns="http://www.w3.org/2000/svg"
141
141
  >
142
142
  <g
143
- clip-path="url(#:r2:)"
143
+ clip-path="url(#_r_2_)"
144
144
  >
145
145
  <path
146
146
  d="M12.6821 12.448C12.6821 9.06699 15.4229 6.32623 18.8039 6.32623C18.8039 2.94571 16.0631 0.205391 12.6817 0.205391C9.30163 0.205391 6.56086 2.94571 6.56042 6.32623C9.94138 6.32623 12.6817 9.06699 12.6821 12.448Z"
@@ -177,7 +177,7 @@ exports[`ArborLogo > renders the icon-only variant with aria-hidden 1`] = `
177
177
  </g>
178
178
  <defs>
179
179
  <clippath
180
- id=":r2:"
180
+ id="_r_2_"
181
181
  >
182
182
  <rect
183
183
  fill="white"
@@ -199,7 +199,7 @@ exports[`ArborLogo > renders the text variant with aria-hidden 1`] = `
199
199
  xmlns="http://www.w3.org/2000/svg"
200
200
  >
201
201
  <g
202
- clip-path="url(#:ra:)"
202
+ clip-path="url(#_r_a_)"
203
203
  >
204
204
  <path
205
205
  d="M12.6822 12.4479C12.6822 9.06698 15.423 6.32622 18.8039 6.32622C18.8039 2.9457 16.0632 0.205383 12.6818 0.205383C9.30169 0.205383 6.56093 2.9457 6.56049 6.32622C9.94145 6.32622 12.6818 9.06698 12.6822 12.4479Z"
@@ -256,7 +256,7 @@ exports[`ArborLogo > renders the text variant with aria-hidden 1`] = `
256
256
  </g>
257
257
  <defs>
258
258
  <clippath
259
- id=":ra:"
259
+ id="_r_a_"
260
260
  >
261
261
  <rect
262
262
  fill="white"
@@ -270,7 +270,7 @@ exports[`ArborLogo > renders the text variant with aria-hidden 1`] = `
270
270
 
271
271
  exports[`ArborLogo > renders the text variant with black text 1`] = `
272
272
  <svg
273
- aria-labelledby=":r7:"
273
+ aria-labelledby="_r_7_"
274
274
  fill="none"
275
275
  height="26"
276
276
  role="img"
@@ -279,12 +279,12 @@ exports[`ArborLogo > renders the text variant with black text 1`] = `
279
279
  xmlns="http://www.w3.org/2000/svg"
280
280
  >
281
281
  <title
282
- id=":r7:"
282
+ id="_r_7_"
283
283
  >
284
284
  Arbor
285
285
  </title>
286
286
  <g
287
- clip-path="url(#:r6:)"
287
+ clip-path="url(#_r_6_)"
288
288
  >
289
289
  <path
290
290
  d="M12.6822 12.4479C12.6822 9.06698 15.423 6.32622 18.8039 6.32622C18.8039 2.9457 16.0632 0.205383 12.6818 0.205383C9.30169 0.205383 6.56093 2.9457 6.56049 6.32622C9.94145 6.32622 12.6818 9.06698 12.6822 12.4479Z"
@@ -341,7 +341,7 @@ exports[`ArborLogo > renders the text variant with black text 1`] = `
341
341
  </g>
342
342
  <defs>
343
343
  <clippath
344
- id=":r6:"
344
+ id="_r_6_"
345
345
  >
346
346
  <rect
347
347
  fill="white"
@@ -355,7 +355,7 @@ exports[`ArborLogo > renders the text variant with black text 1`] = `
355
355
 
356
356
  exports[`ArborLogo > renders the text variant with white text 1`] = `
357
357
  <svg
358
- aria-labelledby=":r9:"
358
+ aria-labelledby="_r_9_"
359
359
  fill="none"
360
360
  height="26"
361
361
  role="img"
@@ -364,7 +364,7 @@ exports[`ArborLogo > renders the text variant with white text 1`] = `
364
364
  xmlns="http://www.w3.org/2000/svg"
365
365
  >
366
366
  <title
367
- id=":r9:"
367
+ id="_r_9_"
368
368
  >
369
369
  Arbor
370
370
  </title>
@@ -11,7 +11,7 @@ import type { ComboboxAriaInvalid, ComboboxOption, ComboboxSelectedValueDisplay
11
11
  import { useVisibleTriggerTags } from './useVisibleTriggerTags.js';
12
12
 
13
13
  export type ComboboxButtonTriggerProps = {
14
- triggerRef: React.RefObject<HTMLDivElement>;
14
+ triggerRef: React.RefObject<HTMLDivElement | null>;
15
15
  listboxId: string;
16
16
  isOpen: boolean;
17
17
  hasError: boolean;
@@ -4,7 +4,7 @@ import { ComboboxOptionRow } from './ComboboxOptionRow.js';
4
4
  import type { ComboboxAriaInvalid, ComboboxOption, ComboboxSearchType } from './types.js';
5
5
 
6
6
  export type ComboboxListboxProps = {
7
- listboxRef: React.RefObject<HTMLUListElement>;
7
+ listboxRef: React.RefObject<HTMLUListElement | null>;
8
8
  listboxId: string;
9
9
  multiple: boolean;
10
10
  ariaLabel: string | undefined;
@@ -27,7 +27,7 @@ export type ComboboxListboxProps = {
27
27
  filteredOptionsLength: number;
28
28
  preventMouseDefault: (e: React.MouseEvent) => void;
29
29
  renderSearchInputInListbox: boolean;
30
- inputRef: React.RefObject<HTMLInputElement>;
30
+ inputRef: React.RefObject<HTMLInputElement | null>;
31
31
  comboboxId: string;
32
32
  shouldShowPopover: boolean;
33
33
  activeDescendant: string | undefined;
@@ -5,8 +5,8 @@ import { Popover } from 'radix-ui';
5
5
  import type { ComboboxAriaInvalid, ComboboxOption, ComboboxSelectedValueDisplay } from './types.js';
6
6
 
7
7
  export type ComboboxTriggerProps = {
8
- 'inputRef': React.RefObject<HTMLInputElement>;
9
- 'triggerRef': React.RefObject<HTMLDivElement>;
8
+ 'inputRef': React.RefObject<HTMLInputElement | null>;
9
+ 'triggerRef': React.RefObject<HTMLDivElement | null>;
10
10
  'comboboxId': string;
11
11
  'listboxId': string;
12
12
  'isOpen': boolean;
@@ -6,7 +6,7 @@ type UseComboboxListboxDomParams = {
6
6
  };
7
7
 
8
8
  export type UseComboboxListboxDomReturn = {
9
- listboxRef: React.RefObject<HTMLUListElement>;
9
+ listboxRef: React.RefObject<HTMLUListElement | null>;
10
10
  getOptionId: (index: number) => string;
11
11
  scrollHighlightedIntoView: (index: number) => void;
12
12
  };
@@ -1354,7 +1354,7 @@ describe('Table', () => {
1354
1354
  cellRendererParams: { options: options, placeholder: 'Placeholder Text' },
1355
1355
  }];
1356
1356
 
1357
- test('renders with placeholder', () => {
1357
+ test('renders with placeholder', async () => {
1358
1358
  const rowData = [{ selectField: null }];
1359
1359
  render(
1360
1360
  <Table
@@ -1362,10 +1362,10 @@ describe('Table', () => {
1362
1362
  rowData={rowData}
1363
1363
  />,
1364
1364
  );
1365
- expect(screen.getByText('Placeholder Text')).toBeInTheDocument();
1365
+ expect(await screen.findByText('Placeholder Text')).toBeInTheDocument();
1366
1366
  });
1367
1367
 
1368
- test('renders with option', () => {
1368
+ test('renders with option', async () => {
1369
1369
  const rowData = [{ selectField: 'option1' }];
1370
1370
  render(
1371
1371
  <Table
@@ -1373,10 +1373,10 @@ describe('Table', () => {
1373
1373
  rowData={rowData}
1374
1374
  />,
1375
1375
  );
1376
- expect(screen.getByText('Option 1')).toBeInTheDocument();
1376
+ expect(await screen.findByText('Option 1')).toBeInTheDocument();
1377
1377
  });
1378
1378
 
1379
- test('renders with value not in options as raw string', () => {
1379
+ test('renders with value not in options as raw string', async () => {
1380
1380
  const rowData = [{ selectField: 'unknown-value' }];
1381
1381
  render(
1382
1382
  <Table
@@ -1384,10 +1384,10 @@ describe('Table', () => {
1384
1384
  rowData={rowData}
1385
1385
  />,
1386
1386
  );
1387
- expect(screen.getByText('unknown-value')).toBeInTheDocument();
1387
+ expect(await screen.findByText('unknown-value')).toBeInTheDocument();
1388
1388
  });
1389
1389
 
1390
- test('renders with empty string shows placeholder', () => {
1390
+ test('renders with empty string shows placeholder', async () => {
1391
1391
  const rowData = [{ selectField: '' }];
1392
1392
  render(
1393
1393
  <Table
@@ -1395,10 +1395,10 @@ describe('Table', () => {
1395
1395
  rowData={rowData}
1396
1396
  />,
1397
1397
  );
1398
- expect(screen.getByText('Placeholder Text')).toBeInTheDocument();
1398
+ expect(await screen.findByText('Placeholder Text')).toBeInTheDocument();
1399
1399
  });
1400
1400
 
1401
- test('renders dropdown button variant in cell', () => {
1401
+ test('renders dropdown button variant in cell', async () => {
1402
1402
  const rowData = [{ selectField: 'option1' }];
1403
1403
  const { container } = render(
1404
1404
  <Table
@@ -1406,9 +1406,11 @@ describe('Table', () => {
1406
1406
  rowData={rowData}
1407
1407
  />,
1408
1408
  );
1409
- const dropdownWrapper = container.querySelector('.ds-table__select-dropdown');
1410
- const dropdownButton = dropdownWrapper?.querySelector('.ds-button--dropdown');
1411
- expect(dropdownButton).toBeInTheDocument();
1409
+ await waitFor(() => {
1410
+ const dropdownWrapper = container.querySelector('.ds-table__select-dropdown');
1411
+ const dropdownButton = dropdownWrapper?.querySelector('.ds-button--dropdown');
1412
+ expect(dropdownButton).toBeInTheDocument();
1413
+ });
1412
1414
  });
1413
1415
  });
1414
1416
 
@@ -1858,6 +1860,7 @@ describe('Table', () => {
1858
1860
  />,
1859
1861
  );
1860
1862
  await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
1863
+ await waitFor(() => expect(gridApi).toBeDefined());
1861
1864
 
1862
1865
  gridApi!.startEditingCell({ rowIndex: 0, colKey: 'dateOfBirth' });
1863
1866
 
@@ -1879,6 +1882,7 @@ describe('Table', () => {
1879
1882
  />,
1880
1883
  );
1881
1884
  await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
1885
+ await waitFor(() => expect(gridApi).toBeDefined());
1882
1886
 
1883
1887
  gridApi!.setFocusedCell(0, 'dateOfBirth');
1884
1888
  await userEvent.keyboard('{Enter}');
@@ -1912,6 +1916,7 @@ describe('Table', () => {
1912
1916
  />,
1913
1917
  );
1914
1918
  await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
1919
+ await waitFor(() => expect(gridApi).toBeDefined());
1915
1920
 
1916
1921
  gridApi!.startEditingCell({ rowIndex: 0, colKey: 'dateOfBirth' });
1917
1922
  await waitFor(() => expect(container.querySelector('input[type="date"]')).toBeInTheDocument());
@@ -2068,8 +2073,7 @@ describe('Table', () => {
2068
2073
  test('setting suppressCellFocusAndFocusFirstElement to true should add the ds-table__cell--suppress-focus class', async () => {
2069
2074
  const { container } = render(<Table columnDefs={columnDefs} rowData={rowData} />);
2070
2075
  await screen.findByRole('grid', {}, { timeout: 10000 });
2071
- const cellWithClass = container.querySelector('.ds-table__cell--suppress-focus');
2072
- expect(cellWithClass).toBeInTheDocument();
2076
+ await waitFor(() => expect(container.querySelector('.ds-table__cell--suppress-focus')).toBeInTheDocument());
2073
2077
  });
2074
2078
 
2075
2079
  test('setting suppressCellFocusAndFocusFirstElement to true should suppress cell focus and focus the first element', async () => {
@@ -11,9 +11,9 @@ type UseTagListCollapsedLayoutParams = {
11
11
  };
12
12
 
13
13
  type TagListCollapsedLayout = {
14
- contentRef: React.RefObject<HTMLDivElement>;
15
- measureTrackRef: React.RefObject<HTMLUListElement>;
16
- overflowProbeRef: React.RefObject<HTMLDivElement>;
14
+ contentRef: React.RefObject<HTMLDivElement | null>;
15
+ measureTrackRef: React.RefObject<HTMLUListElement | null>;
16
+ overflowProbeRef: React.RefObject<HTMLDivElement | null>;
17
17
  shouldCollapse: boolean;
18
18
  visibleItemIndices: number[];
19
19
  visibleItems: TagListItem[];
@@ -30,6 +30,12 @@ Or with npm:
30
30
  npm install @arbor-education/design-system.components
31
31
  ```
32
32
 
33
+ ### Requirements
34
+
35
+ The design system doesn't bundle React; it uses the copy your project already has. Make sure your project has `react` and `react-dom` installed at version 18 or 19. React 19 is the preferred version -- projects on React 18 should plan to upgrade to 19.
36
+
37
+ If your project uses TypeScript, it also needs `@types/react` and `@types/react-dom`.
38
+
33
39
  ---
34
40
 
35
41
  ## Importing the stylesheet
@@ -0,0 +1,43 @@
1
+ import { readFileSync } from 'fs';
2
+ import path from 'path';
3
+ import { describe, expect, test } from 'vitest';
4
+
5
+ type PackageManifest = {
6
+ dependencies?: Record<string, string>;
7
+ peerDependencies?: Record<string, string>;
8
+ peerDependenciesMeta?: Record<string, { optional?: boolean }>;
9
+ };
10
+
11
+ // Read from disk rather than imported: tsconfig's rootDir is ./src, so a JSON import of the
12
+ // root package.json would fail type-checking.
13
+ const manifest: PackageManifest = JSON.parse(
14
+ readFileSync(path.resolve(__dirname, '../package.json'), 'utf8'),
15
+ );
16
+
17
+ const SUPPORTED_REACT_RANGE = '^18.0.0 || ^19.0.0';
18
+ const REACT_PACKAGES = ['react', 'react-dom'];
19
+ const REACT_TYPE_PACKAGES = ['@types/react', '@types/react-dom'];
20
+
21
+ describe('package.json keeps React as a peer so consumers never get a second React copy', () => {
22
+ test.each([...REACT_PACKAGES, ...REACT_TYPE_PACKAGES])(
23
+ 'does not bundle %s as a dependency, which would nest a second copy inside consumers',
24
+ (packageName) => {
25
+ expect(manifest.dependencies ?? {}).not.toHaveProperty([packageName]);
26
+ },
27
+ );
28
+
29
+ test.each(REACT_PACKAGES)(
30
+ 'accepts both React 18 and React 19 for %s so either consumer can install it',
31
+ (packageName) => {
32
+ expect(manifest.peerDependencies?.[packageName]).toBe(SUPPORTED_REACT_RANGE);
33
+ },
34
+ );
35
+
36
+ test.each(REACT_TYPE_PACKAGES)(
37
+ 'lists %s as an optional peer so JavaScript consumers are not forced to install types',
38
+ (packageName) => {
39
+ expect(manifest.peerDependencies ?? {}).toHaveProperty([packageName]);
40
+ expect(manifest.peerDependenciesMeta?.[packageName]?.optional).toBe(true);
41
+ },
42
+ );
43
+ });