@arbor-education/design-system.components 0.9.0 → 0.10.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 (116) hide show
  1. package/.github/workflows/release.yml +1 -1
  2. package/CHANGELOG.md +10 -0
  3. package/dist/components/button/Button.d.ts.map +1 -1
  4. package/dist/components/button/Button.js +2 -2
  5. package/dist/components/button/Button.js.map +1 -1
  6. package/dist/components/combobox/Combobox.d.ts.map +1 -1
  7. package/dist/components/combobox/Combobox.js +2 -1
  8. package/dist/components/combobox/Combobox.js.map +1 -1
  9. package/dist/components/combobox/Combobox.test.js +98 -61
  10. package/dist/components/combobox/Combobox.test.js.map +1 -1
  11. package/dist/components/combobox/useComboboxPopoverBehavior.d.ts +3 -1
  12. package/dist/components/combobox/useComboboxPopoverBehavior.d.ts.map +1 -1
  13. package/dist/components/combobox/useComboboxPopoverBehavior.js +7 -6
  14. package/dist/components/combobox/useComboboxPopoverBehavior.js.map +1 -1
  15. package/dist/components/combobox/useComboboxState.d.ts.map +1 -1
  16. package/dist/components/combobox/useComboboxState.js +4 -1
  17. package/dist/components/combobox/useComboboxState.js.map +1 -1
  18. package/dist/components/datePicker/DatePicker.d.ts +4 -1
  19. package/dist/components/datePicker/DatePicker.d.ts.map +1 -1
  20. package/dist/components/datePicker/DatePicker.js +77 -37
  21. package/dist/components/datePicker/DatePicker.js.map +1 -1
  22. package/dist/components/datePicker/DatePicker.stories.d.ts +28 -3
  23. package/dist/components/datePicker/DatePicker.stories.d.ts.map +1 -1
  24. package/dist/components/datePicker/DatePicker.stories.js +62 -9
  25. package/dist/components/datePicker/DatePicker.stories.js.map +1 -1
  26. package/dist/components/datePicker/DatePicker.test.js +133 -66
  27. package/dist/components/datePicker/DatePicker.test.js.map +1 -1
  28. package/dist/components/datePicker/DatePickerCalendarHeader.d.ts +8 -0
  29. package/dist/components/datePicker/DatePickerCalendarHeader.d.ts.map +1 -0
  30. package/dist/components/datePicker/DatePickerCalendarHeader.js +36 -0
  31. package/dist/components/datePicker/DatePickerCalendarHeader.js.map +1 -0
  32. package/dist/components/datePicker/dateInputUtils.d.ts +25 -0
  33. package/dist/components/datePicker/dateInputUtils.d.ts.map +1 -0
  34. package/dist/components/datePicker/dateInputUtils.js +60 -0
  35. package/dist/components/datePicker/dateInputUtils.js.map +1 -0
  36. package/dist/components/datePicker/datePickerTestUtils.test-helpers.d.ts +2 -0
  37. package/dist/components/datePicker/datePickerTestUtils.test-helpers.d.ts.map +1 -0
  38. package/dist/components/datePicker/datePickerTestUtils.test-helpers.js +4 -0
  39. package/dist/components/datePicker/datePickerTestUtils.test-helpers.js.map +1 -0
  40. package/dist/components/dateTimePicker/DateTimePicker.d.ts +22 -0
  41. package/dist/components/dateTimePicker/DateTimePicker.d.ts.map +1 -0
  42. package/dist/components/dateTimePicker/DateTimePicker.js +132 -0
  43. package/dist/components/dateTimePicker/DateTimePicker.js.map +1 -0
  44. package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts +77 -0
  45. package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts.map +1 -0
  46. package/dist/components/dateTimePicker/DateTimePicker.stories.js +163 -0
  47. package/dist/components/dateTimePicker/DateTimePicker.stories.js.map +1 -0
  48. package/dist/components/dateTimePicker/DateTimePicker.test.d.ts +2 -0
  49. package/dist/components/dateTimePicker/DateTimePicker.test.d.ts.map +1 -0
  50. package/dist/components/dateTimePicker/DateTimePicker.test.js +235 -0
  51. package/dist/components/dateTimePicker/DateTimePicker.test.js.map +1 -0
  52. package/dist/components/formField/FormField.test.d.ts.map +1 -1
  53. package/dist/components/formField/FormField.test.js +5 -5
  54. package/dist/components/formField/FormField.test.js.map +1 -1
  55. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts +1 -0
  56. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts.map +1 -1
  57. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.js +7 -3
  58. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.js.map +1 -1
  59. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.test.js +12 -0
  60. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.test.js.map +1 -1
  61. package/dist/components/formField/inputs/text/TextInput.d.ts +4 -1
  62. package/dist/components/formField/inputs/text/TextInput.d.ts.map +1 -1
  63. package/dist/components/formField/inputs/text/TextInput.js +5 -4
  64. package/dist/components/formField/inputs/text/TextInput.js.map +1 -1
  65. package/dist/components/formField/inputs/text/TextInput.stories.d.ts +4 -1
  66. package/dist/components/formField/inputs/text/TextInput.stories.d.ts.map +1 -1
  67. package/dist/components/table/Table.d.ts.map +1 -1
  68. package/dist/components/table/Table.js +2 -0
  69. package/dist/components/table/Table.js.map +1 -1
  70. package/dist/components/table/Table.stories.d.ts +1 -0
  71. package/dist/components/table/Table.stories.d.ts.map +1 -1
  72. package/dist/components/table/Table.stories.js +37 -0
  73. package/dist/components/table/Table.stories.js.map +1 -1
  74. package/dist/components/table/cellRenderers/BooleanCellRenderer.d.ts +3 -0
  75. package/dist/components/table/cellRenderers/BooleanCellRenderer.d.ts.map +1 -0
  76. package/dist/components/table/cellRenderers/BooleanCellRenderer.js +15 -0
  77. package/dist/components/table/cellRenderers/BooleanCellRenderer.js.map +1 -0
  78. package/dist/components/table/cellRenderers/BooleanCellRenderer.test.d.ts +2 -0
  79. package/dist/components/table/cellRenderers/BooleanCellRenderer.test.d.ts.map +1 -0
  80. package/dist/components/table/cellRenderers/BooleanCellRenderer.test.js +31 -0
  81. package/dist/components/table/cellRenderers/BooleanCellRenderer.test.js.map +1 -0
  82. package/dist/index.css +258 -3
  83. package/dist/index.css.map +1 -1
  84. package/dist/index.d.ts +3 -0
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +2 -0
  87. package/dist/index.js.map +1 -1
  88. package/package.json +1 -1
  89. package/src/components/button/Button.tsx +2 -1
  90. package/src/components/combobox/Combobox.test.tsx +104 -61
  91. package/src/components/combobox/Combobox.tsx +3 -1
  92. package/src/components/combobox/useComboboxPopoverBehavior.ts +10 -5
  93. package/src/components/combobox/useComboboxState.ts +4 -1
  94. package/src/components/datePicker/DatePicker.stories.tsx +67 -9
  95. package/src/components/datePicker/DatePicker.test.tsx +157 -72
  96. package/src/components/datePicker/DatePicker.tsx +163 -69
  97. package/src/components/datePicker/DatePickerCalendarHeader.tsx +82 -0
  98. package/src/components/datePicker/date-field-hint.scss +152 -0
  99. package/src/components/datePicker/dateInputUtils.ts +117 -0
  100. package/src/components/datePicker/datePicker.scss +53 -29
  101. package/src/components/datePicker/datePickerTestUtils.test-helpers.ts +6 -0
  102. package/src/components/dateTimePicker/DateTimePicker.stories.tsx +202 -0
  103. package/src/components/dateTimePicker/DateTimePicker.test.tsx +295 -0
  104. package/src/components/dateTimePicker/DateTimePicker.tsx +293 -0
  105. package/src/components/dateTimePicker/dateTimePicker.scss +17 -0
  106. package/src/components/formField/FormField.test.tsx +5 -5
  107. package/src/components/formField/inputs/selectDropdown/SelectDropdown.test.tsx +28 -0
  108. package/src/components/formField/inputs/selectDropdown/SelectDropdown.tsx +8 -2
  109. package/src/components/formField/inputs/text/TextInput.tsx +6 -3
  110. package/src/components/table/Table.stories.tsx +48 -0
  111. package/src/components/table/Table.tsx +2 -0
  112. package/src/components/table/cellRenderers/BooleanCellRenderer.test.tsx +37 -0
  113. package/src/components/table/cellRenderers/BooleanCellRenderer.tsx +34 -0
  114. package/src/components/table/cellRenderers/booleanCellRenderer.scss +7 -0
  115. package/src/index.scss +2 -0
  116. package/src/index.ts +3 -0
@@ -16,6 +16,7 @@ export type SelectDropdownInputProps = {
16
16
  'id'?: string;
17
17
  'alwaysShowPlaceholder'?: boolean;
18
18
  'initialSelectedValues'?: string[];
19
+ 'selectedValues'?: string[];
19
20
  'open'?: boolean;
20
21
  'onOpenChange'?: (open: boolean) => void;
21
22
  };
@@ -33,11 +34,14 @@ export const SelectDropdown = (props: SelectDropdownInputProps) => {
33
34
  'aria-invalid': ariaInvalid,
34
35
  alwaysShowPlaceholder = false,
35
36
  initialSelectedValues = [],
37
+ selectedValues: controlledSelectedValues,
36
38
  open,
37
39
  onOpenChange,
38
40
  } = props;
39
41
 
40
- const [selectedValues, setSelectedValues] = useState<string[]>(initialSelectedValues);
42
+ const isControlled = controlledSelectedValues !== undefined;
43
+ const [internalSelectedValues, setInternalSelectedValues] = useState<string[]>(initialSelectedValues);
44
+ const selectedValues = isControlled ? controlledSelectedValues : internalSelectedValues;
41
45
  const [renderedSelectContent, setRenderedSelectContent] = useState('');
42
46
  const selectedValuesRef = useRef(selectedValues);
43
47
  selectedValuesRef.current = selectedValues;
@@ -90,7 +94,9 @@ export const SelectDropdown = (props: SelectDropdownInputProps) => {
90
94
  else {
91
95
  nextValues = [...prev, value];
92
96
  }
93
- setSelectedValues(nextValues);
97
+ if (!isControlled) {
98
+ setInternalSelectedValues(nextValues);
99
+ }
94
100
  onSelectionChange?.(nextValues);
95
101
  };
96
102
 
@@ -1,12 +1,12 @@
1
1
  import classNames from 'classnames';
2
- import { type InputHTMLAttributes } from 'react';
2
+ import { forwardRef, type InputHTMLAttributes } from 'react';
3
3
 
4
4
  export type TextInputProps = {
5
5
  size?: 'M' | 'S';
6
6
  hasError?: boolean;
7
7
  } & Omit<InputHTMLAttributes<HTMLInputElement>, 'size'>;
8
8
 
9
- export const TextInput = (props: TextInputProps) => {
9
+ export const TextInput = forwardRef<HTMLInputElement, TextInputProps>((props, ref) => {
10
10
  const {
11
11
  size = 'M',
12
12
  hasError,
@@ -27,9 +27,12 @@ export const TextInput = (props: TextInputProps) => {
27
27
 
28
28
  return (
29
29
  <input
30
+ ref={ref}
30
31
  className={inputClasses}
31
32
  disabled={disabled}
32
33
  {...rest}
33
34
  />
34
35
  );
35
- };
36
+ });
37
+
38
+ TextInput.displayName = 'TextInput';
@@ -1361,4 +1361,52 @@ export const TableWithSemanticColors: Story = {
1361
1361
  },
1362
1362
  };
1363
1363
 
1364
+ interface BooleanRowData {
1365
+ id: number;
1366
+ name: string;
1367
+ hasPet: boolean | null | undefined;
1368
+ isEnrolled: boolean | null | undefined;
1369
+ }
1370
+
1371
+ const booleanCellRendererData: BooleanRowData[] = [
1372
+ { id: 1, name: 'Alice Johnson', hasPet: true, isEnrolled: true },
1373
+ { id: 2, name: 'Bob Smith', hasPet: false, isEnrolled: false },
1374
+ { id: 3, name: 'Charlie Brown', hasPet: null, isEnrolled: undefined },
1375
+ { id: 4, name: 'Diana Prince', hasPet: true, isEnrolled: null },
1376
+ { id: 5, name: 'Ethan Hunt', hasPet: undefined, isEnrolled: true },
1377
+ ];
1378
+
1379
+ const booleanCellRendererColumnDefs: ColDef<BooleanRowData>[] = [
1380
+ { field: 'name', headerName: 'Name' },
1381
+ {
1382
+ field: 'hasPet',
1383
+ headerName: 'Has Pet',
1384
+ cellRenderer: 'dsBooleanCellRenderer',
1385
+ editable: false,
1386
+ },
1387
+ {
1388
+ field: 'isEnrolled',
1389
+ headerName: 'Is Enrolled',
1390
+ cellRenderer: 'dsBooleanCellRenderer',
1391
+ editable: false,
1392
+ },
1393
+ ];
1394
+
1395
+ export const WithBooleanCellRenderer: Story = {
1396
+ parameters: {
1397
+ docs: {
1398
+ description: {
1399
+ story:
1400
+ 'The BooleanCellRenderer displays a true or false icon for boolean values, and renders nothing for any other value regardless of truthiness. Only explicit true and false are accepted, anything else is treated as nullish',
1401
+ },
1402
+ },
1403
+ },
1404
+ args: {
1405
+ rowData: booleanCellRendererData,
1406
+ columnDefs: booleanCellRendererColumnDefs,
1407
+ defaultColDef,
1408
+ domLayout: 'autoHeight',
1409
+ },
1410
+ };
1411
+
1364
1412
  export default meta;
@@ -24,6 +24,7 @@ import { focusFirstFocusableElement } from 'Utils/focusFirstFocusableElement';
24
24
  import { BooleanFilter } from './columnFilters/BooleanFilter/BooleanFilter';
25
25
  import { TimeFilter } from './columnFilters/TimeFilter/TimeFilter';
26
26
  import { TableSettingsDropdown } from './TableSettingsDropdown';
27
+ import { BooleanCellRenderer } from './cellRenderers/BooleanCellRenderer';
27
28
 
28
29
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
30
  type TableProps<TData = any> = {
@@ -194,6 +195,7 @@ export const Table = (props: TableProps) => {
194
195
  dsSelectDropdownCellRenderer: SelectDropdownCellRenderer,
195
196
  dsBooleanFilter: BooleanFilter,
196
197
  dsTimeFilter: TimeFilter,
198
+ dsBooleanCellRenderer: BooleanCellRenderer,
197
199
  ...components,
198
200
  }}
199
201
  {...rest}
@@ -0,0 +1,37 @@
1
+ import '@testing-library/jest-dom/vitest';
2
+ import { describe, expect, test } from 'vitest';
3
+ import { render, screen } from '@testing-library/react';
4
+ import { BooleanCellRenderer } from './BooleanCellRenderer';
5
+ import type { CustomCellRendererProps } from 'ag-grid-react';
6
+
7
+ const renderWithValue = (value: unknown) =>
8
+ render(<BooleanCellRenderer {...{ value } as CustomCellRendererProps} />);
9
+
10
+ describe('BooleanCellRenderer', () => {
11
+ test('renders a check icon when value is true', () => {
12
+ renderWithValue(true);
13
+ expect(screen.getByRole('img', { hidden: true })).toBeInTheDocument();
14
+ expect(screen.getByText('true')).toBeInTheDocument();
15
+ });
16
+
17
+ test('renders an x icon when value is false', () => {
18
+ renderWithValue(false);
19
+ expect(screen.getByRole('img', { hidden: true })).toBeInTheDocument();
20
+ expect(screen.getByText('false')).toBeInTheDocument();
21
+ });
22
+
23
+ test('renders nothing when value is null', () => {
24
+ const { container } = renderWithValue(null);
25
+ expect(container.innerHTML).toBeFalsy();
26
+ });
27
+
28
+ test('renders nothing when value is undefined', () => {
29
+ const { container } = renderWithValue(undefined);
30
+ expect(container.innerHTML).toBeFalsy();
31
+ });
32
+
33
+ test('renders nothing when value is a non-boolean', () => {
34
+ const { container } = renderWithValue('some string');
35
+ expect(container.innerHTML).toBeFalsy();
36
+ });
37
+ });
@@ -0,0 +1,34 @@
1
+ import type { CustomCellRendererProps } from 'ag-grid-react';
2
+ import { Icon } from 'Components/icon/Icon';
3
+
4
+ export const BooleanCellRenderer = (props: CustomCellRendererProps) => {
5
+ const { value } = props;
6
+
7
+ if (value === true) {
8
+ return (
9
+ <div className="ds-boolean-cell-renderer">
10
+ <Icon
11
+ size={24}
12
+ name="check-solid"
13
+ color="var(--color-semantic-success-700)"
14
+ screenReaderText="true"
15
+ />
16
+ </div>
17
+ );
18
+ }
19
+ else if (value === false) {
20
+ return (
21
+ <div className="ds-boolean-cell-renderer">
22
+ <Icon
23
+ size={24}
24
+ name="x-solid"
25
+ color="var(--color-semantic-destructive-700)"
26
+ screenReaderText="false"
27
+ />
28
+ </div>
29
+ );
30
+ }
31
+ else {
32
+ return null;
33
+ }
34
+ };
@@ -0,0 +1,7 @@
1
+ .ds-boolean-cell-renderer {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ width: 100%;
6
+ height: 100%;
7
+ }
package/src/index.scss CHANGED
@@ -37,10 +37,12 @@
37
37
  @use "components/progress/progress.scss";
38
38
  @use "components/toast/toast.scss";
39
39
  @use "components/datePicker/datePicker.scss";
40
+ @use "components/dateTimePicker/dateTimePicker.scss";
40
41
  @use "components/avatar/avatar.scss";
41
42
  @use "components/singleUser/singleUser.scss";
42
43
  @use "components/avatarGroup/avatarGroup.scss";
43
44
  @use "components/userDropdown/userDropdown.scss";
45
+ @use "components/table/cellRenderers/booleanCellRenderer.scss";
44
46
  @use "components/row/row.scss";
45
47
  @use "components/combobox/combobox.scss";
46
48
  @use "components/toggle/toggle.scss";
package/src/index.ts CHANGED
@@ -10,6 +10,8 @@ export { Banner, BANNER_LEVEL, type BannerProps } from 'Components/banner/Banner
10
10
  export { Button } from 'Components/button/Button';
11
11
  export { Card } from 'Components/card/Card';
12
12
  export { DatePicker } from 'Components/datePicker/DatePicker';
13
+ export { DateTimePicker } from 'Components/dateTimePicker/DateTimePicker';
14
+ export type { DateTimePickerDisplayFormat, DateTimePickerProps } from 'Components/dateTimePicker/DateTimePicker';
13
15
  export { Dropdown } from 'Components/dropdown/Dropdown';
14
16
  export { Tag } from 'Components/tag/Tag';
15
17
  export type { TagProps, TagColor } from 'Components/tag/Tag';
@@ -42,6 +44,7 @@ export { SingleUser, type SingleUserProps } from 'Components/singleUser/SingleUs
42
44
  export { Slideover, type SlideoverProps } from 'Components/slideover/Slideover';
43
45
  export { SlideoverManager } from 'Components/slideoverManager/SlideoverManager';
44
46
  export { DefaultCellRenderer } from 'Components/table/cellRenderers/DefaultCellRenderer';
47
+ export { BooleanCellRenderer } from 'Components/table/cellRenderers/BooleanCellRenderer';
45
48
  export { DSDefaultColDef } from 'Components/table/DSDefaultColDef';
46
49
  export { GridApiContext } from 'Components/table/GridApiContext';
47
50
  export { Table } from 'Components/table/Table';