@arbor-education/design-system.components 0.1.5 → 0.2.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.
Files changed (174) hide show
  1. package/.github/workflows/release.yml +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/dist/components/formField/fieldset/Fieldset.d.ts +6 -0
  4. package/dist/components/formField/fieldset/Fieldset.d.ts.map +1 -0
  5. package/dist/components/formField/fieldset/Fieldset.js +7 -0
  6. package/dist/components/formField/fieldset/Fieldset.js.map +1 -0
  7. package/dist/components/formField/fieldset/Fieldset.stories.d.ts +28 -0
  8. package/dist/components/formField/fieldset/Fieldset.stories.d.ts.map +1 -0
  9. package/dist/components/formField/fieldset/Fieldset.stories.js +51 -0
  10. package/dist/components/formField/fieldset/Fieldset.stories.js.map +1 -0
  11. package/dist/components/formField/fieldset/Fieldset.test.d.ts +2 -0
  12. package/dist/components/formField/fieldset/Fieldset.test.d.ts.map +1 -0
  13. package/dist/components/formField/fieldset/Fieldset.test.js +62 -0
  14. package/dist/components/formField/fieldset/Fieldset.test.js.map +1 -0
  15. package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts +8 -0
  16. package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts.map +1 -0
  17. package/dist/components/formField/inputs/checkbox/CheckboxGroup.js +8 -0
  18. package/dist/components/formField/inputs/checkbox/CheckboxGroup.js.map +1 -0
  19. package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.d.ts +2 -0
  20. package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.d.ts.map +1 -0
  21. package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.js +86 -0
  22. package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.js.map +1 -0
  23. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts +3 -1
  24. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts.map +1 -1
  25. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js +7 -0
  26. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js.map +1 -1
  27. package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts +11 -0
  28. package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts.map +1 -0
  29. package/dist/components/formField/inputs/radio/RadioButtonGroup.js +8 -0
  30. package/dist/components/formField/inputs/radio/RadioButtonGroup.js.map +1 -0
  31. package/dist/components/formField/inputs/radio/RadioButtonGroup.test.d.ts +2 -0
  32. package/dist/components/formField/inputs/radio/RadioButtonGroup.test.d.ts.map +1 -0
  33. package/dist/components/formField/inputs/radio/RadioButtonGroup.test.js +86 -0
  34. package/dist/components/formField/inputs/radio/RadioButtonGroup.test.js.map +1 -0
  35. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts.map +1 -1
  36. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js +8 -2
  37. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js.map +1 -1
  38. package/dist/components/modal/Modal.d.ts +25 -0
  39. package/dist/components/modal/Modal.d.ts.map +1 -0
  40. package/dist/components/modal/Modal.js +22 -0
  41. package/dist/components/modal/Modal.js.map +1 -0
  42. package/dist/components/modal/Modal.stories.d.ts +13 -0
  43. package/dist/components/modal/Modal.stories.d.ts.map +1 -0
  44. package/dist/components/modal/Modal.stories.js +23 -0
  45. package/dist/components/modal/Modal.stories.js.map +1 -0
  46. package/dist/components/modal/Modal.test.d.ts +2 -0
  47. package/dist/components/modal/Modal.test.d.ts.map +1 -0
  48. package/dist/components/modal/Modal.test.js +131 -0
  49. package/dist/components/modal/Modal.test.js.map +1 -0
  50. package/dist/components/modal/ModalBody.d.ts +7 -0
  51. package/dist/components/modal/ModalBody.d.ts.map +1 -0
  52. package/dist/components/modal/ModalBody.js +7 -0
  53. package/dist/components/modal/ModalBody.js.map +1 -0
  54. package/dist/components/modal/ModalCloseButton.d.ts +3 -0
  55. package/dist/components/modal/ModalCloseButton.d.ts.map +1 -0
  56. package/dist/components/modal/ModalCloseButton.js +25 -0
  57. package/dist/components/modal/ModalCloseButton.js.map +1 -0
  58. package/dist/components/modal/ModalFooter.d.ts +7 -0
  59. package/dist/components/modal/ModalFooter.d.ts.map +1 -0
  60. package/dist/components/modal/ModalFooter.js +7 -0
  61. package/dist/components/modal/ModalFooter.js.map +1 -0
  62. package/dist/components/modal/ModalHeader.d.ts +7 -0
  63. package/dist/components/modal/ModalHeader.d.ts.map +1 -0
  64. package/dist/components/modal/ModalHeader.js +8 -0
  65. package/dist/components/modal/ModalHeader.js.map +1 -0
  66. package/dist/components/modal/ModalTitle.d.ts +3 -0
  67. package/dist/components/modal/ModalTitle.d.ts.map +1 -0
  68. package/dist/components/modal/ModalTitle.js +8 -0
  69. package/dist/components/modal/ModalTitle.js.map +1 -0
  70. package/dist/components/modal/modalManager/ModalManager.d.ts +7 -0
  71. package/dist/components/modal/modalManager/ModalManager.d.ts.map +1 -0
  72. package/dist/components/modal/modalManager/ModalManager.js +22 -0
  73. package/dist/components/modal/modalManager/ModalManager.js.map +1 -0
  74. package/dist/components/modal/modalManager/ModalManager.stories.d.ts +13 -0
  75. package/dist/components/modal/modalManager/ModalManager.stories.d.ts.map +1 -0
  76. package/dist/components/modal/modalManager/ModalManager.stories.js +110 -0
  77. package/dist/components/modal/modalManager/ModalManager.stories.js.map +1 -0
  78. package/dist/components/modal/modalManager/ModalManager.test.d.ts +2 -0
  79. package/dist/components/modal/modalManager/ModalManager.test.d.ts.map +1 -0
  80. package/dist/components/modal/modalManager/ModalManager.test.js +191 -0
  81. package/dist/components/modal/modalManager/ModalManager.test.js.map +1 -0
  82. package/dist/components/separator/Separator.d.ts +7 -0
  83. package/dist/components/separator/Separator.d.ts.map +1 -0
  84. package/dist/components/separator/Separator.js +8 -0
  85. package/dist/components/separator/Separator.js.map +1 -0
  86. package/dist/components/separator/Separator.stories.d.ts +10 -0
  87. package/dist/components/separator/Separator.stories.d.ts.map +1 -0
  88. package/dist/components/separator/Separator.stories.js +12 -0
  89. package/dist/components/separator/Separator.stories.js.map +1 -0
  90. package/dist/components/separator/Separator.test.d.ts +2 -0
  91. package/dist/components/separator/Separator.test.d.ts.map +1 -0
  92. package/dist/components/separator/Separator.test.js +10 -0
  93. package/dist/components/separator/Separator.test.js.map +1 -0
  94. package/dist/components/table/Table.d.ts +20 -0
  95. package/dist/components/table/Table.d.ts.map +1 -1
  96. package/dist/components/table/Table.js +45 -7
  97. package/dist/components/table/Table.js.map +1 -1
  98. package/dist/components/table/Table.stories.d.ts.map +1 -1
  99. package/dist/components/table/Table.stories.js +14 -1
  100. package/dist/components/table/Table.stories.js.map +1 -1
  101. package/dist/components/table/Table.test.js +315 -2
  102. package/dist/components/table/Table.test.js.map +1 -1
  103. package/dist/components/table/pagination/TableSettingsDropdown.d.ts +2 -0
  104. package/dist/components/table/pagination/TableSettingsDropdown.d.ts.map +1 -0
  105. package/dist/components/table/pagination/TableSettingsDropdown.js +43 -0
  106. package/dist/components/table/pagination/TableSettingsDropdown.js.map +1 -0
  107. package/dist/components/table/useTableSettings.d.ts +22 -0
  108. package/dist/components/table/useTableSettings.d.ts.map +1 -0
  109. package/dist/components/table/useTableSettings.js +36 -0
  110. package/dist/components/table/useTableSettings.js.map +1 -0
  111. package/dist/index.css +102 -1
  112. package/dist/index.css.map +1 -1
  113. package/dist/index.d.ts +4 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +4 -0
  116. package/dist/index.js.map +1 -1
  117. package/dist/utils/Constants.d.ts +5 -0
  118. package/dist/utils/Constants.d.ts.map +1 -1
  119. package/dist/utils/Constants.js +5 -0
  120. package/dist/utils/Constants.js.map +1 -1
  121. package/dist/utils/ModalUtils.d.ts +7 -0
  122. package/dist/utils/ModalUtils.d.ts.map +1 -0
  123. package/dist/utils/ModalUtils.js +14 -0
  124. package/dist/utils/ModalUtils.js.map +1 -0
  125. package/dist/utils/hooks/useComponentDidUpdate.d.ts +7 -0
  126. package/dist/utils/hooks/useComponentDidUpdate.d.ts.map +1 -0
  127. package/dist/utils/hooks/useComponentDidUpdate.js +18 -0
  128. package/dist/utils/hooks/useComponentDidUpdate.js.map +1 -0
  129. package/dist/utils/hooks/useComponentDidUpdate.test.d.ts +2 -0
  130. package/dist/utils/hooks/useComponentDidUpdate.test.d.ts.map +1 -0
  131. package/dist/utils/hooks/useComponentDidUpdate.test.js +69 -0
  132. package/dist/utils/hooks/useComponentDidUpdate.test.js.map +1 -0
  133. package/package.json +1 -1
  134. package/src/components/formField/fieldset/Fieldset.stories.tsx +89 -0
  135. package/src/components/formField/fieldset/Fieldset.test.tsx +85 -0
  136. package/src/components/formField/fieldset/Fieldset.tsx +17 -0
  137. package/src/components/formField/fieldset/fieldset.scss +19 -0
  138. package/src/components/formField/inputs/checkbox/CheckboxGroup.test.tsx +127 -0
  139. package/src/components/formField/inputs/checkbox/CheckboxGroup.tsx +17 -0
  140. package/src/components/formField/inputs/checkbox/CheckboxInput.stories.tsx +12 -1
  141. package/src/components/formField/inputs/radio/RadioButtonGroup.test.tsx +190 -0
  142. package/src/components/formField/inputs/radio/RadioButtonGroup.tsx +22 -0
  143. package/src/components/formField/inputs/radio/RadioButtonInput.stories.tsx +16 -7
  144. package/src/components/formField/label/label.scss +1 -1
  145. package/src/components/modal/Modal.stories.tsx +37 -0
  146. package/src/components/modal/Modal.test.tsx +244 -0
  147. package/src/components/modal/Modal.tsx +65 -0
  148. package/src/components/modal/ModalBody.tsx +16 -0
  149. package/src/components/modal/ModalCloseButton.tsx +39 -0
  150. package/src/components/modal/ModalFooter.tsx +14 -0
  151. package/src/components/modal/ModalHeader.tsx +20 -0
  152. package/src/components/modal/ModalTitle.tsx +12 -0
  153. package/src/components/modal/modal.scss +74 -0
  154. package/src/components/modal/modalManager/ModalManager.stories.tsx +497 -0
  155. package/src/components/modal/modalManager/ModalManager.test.tsx +255 -0
  156. package/src/components/modal/modalManager/ModalManager.tsx +40 -0
  157. package/src/components/modal/modalManager/modalManager.scss +4 -0
  158. package/src/components/separator/Separator.stories.tsx +15 -0
  159. package/src/components/separator/Separator.test.tsx +10 -0
  160. package/src/components/separator/Separator.tsx +15 -0
  161. package/src/components/separator/separator.scss +6 -0
  162. package/src/components/table/Table.stories.tsx +14 -1
  163. package/src/components/table/Table.test.tsx +553 -1
  164. package/src/components/table/Table.tsx +80 -24
  165. package/src/components/table/pagination/TableSettingsDropdown.tsx +90 -0
  166. package/src/components/table/table.scss +8 -0
  167. package/src/components/table/useTableSettings.ts +59 -0
  168. package/src/index.scss +4 -0
  169. package/src/index.ts +4 -0
  170. package/src/tokens.scss +1 -0
  171. package/src/utils/Constants.ts +6 -0
  172. package/src/utils/ModalUtils.ts +17 -0
  173. package/src/utils/hooks/useComponentDidUpdate.test.ts +107 -0
  174. package/src/utils/hooks/useComponentDidUpdate.ts +19 -0
@@ -2,7 +2,7 @@ import { AllEnterpriseModule, ModuleRegistry, type GridApi } from 'ag-grid-enter
2
2
  import { AgGridReact, type AgGridReactProps } from 'ag-grid-react';
3
3
  import { tableTheme } from './tableTheme';
4
4
  import classNames from 'classnames';
5
- import { useState, type ReactNode } from 'react';
5
+ import { createContext, useState, type ReactNode } from 'react';
6
6
  import { TableFooter } from './TableFooter';
7
7
  import { TableHeader } from './TableHeader';
8
8
  import { GridApiContext } from './GridApiContext';
@@ -12,6 +12,7 @@ import { PaginationControls } from './pagination/PaginationControls';
12
12
  import { RowCountInfo } from './pagination/RowCountInfo';
13
13
  import { BulkActionsDropdown } from './BulkActionsDropdown';
14
14
  import { HideColumnsDropdown } from './HideColumnsDropdown';
15
+ import { useTableSettings, type TableSettings } from './useTableSettings';
15
16
 
16
17
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
18
  type TableProps<TData = any> = {
@@ -22,10 +23,31 @@ type TableProps<TData = any> = {
22
23
  'footerTestId'?: string;
23
24
  'headerContent'?: ReactNode;
24
25
  'headerTestId'?: string;
26
+ 'onTableSettingsChanged'?: (val: TableSettings) => void;
27
+ 'onTableSettingsReset'?: () => void;
28
+ 'onColumnBordersChanged'?: (val: boolean) => void;
29
+ 'onTableSpacingChanged'?: (val: TABLE_SPACING) => void;
25
30
  } & AgGridReactProps<TData>;
26
31
 
27
32
  ModuleRegistry.registerModules([AllEnterpriseModule]);
28
33
 
34
+ export enum TABLE_SPACING {
35
+ XS = 'XS',
36
+ S = 'S',
37
+ M = 'M',
38
+ L = 'L',
39
+ }
40
+
41
+ export const TableSettingsContext = createContext<ReturnType<typeof useTableSettings>>({
42
+ settings: {
43
+ hasColumnBorders: false,
44
+ tableSpacing: TABLE_SPACING.S,
45
+ },
46
+ setTableSpacing: () => {},
47
+ setHasColumnBorders: () => {},
48
+ resetSettings: () => {},
49
+ });
50
+
29
51
  export const Table = (props: TableProps) => {
30
52
  const {
31
53
  'data-testid': testId,
@@ -36,6 +58,10 @@ export const Table = (props: TableProps) => {
36
58
  footerContent,
37
59
  footerTestId,
38
60
  onGridReady,
61
+ onTableSettingsChanged,
62
+ onTableSettingsReset,
63
+ onColumnBordersChanged,
64
+ onTableSpacingChanged,
39
65
  ...rest
40
66
  } = props;
41
67
 
@@ -43,31 +69,61 @@ export const Table = (props: TableProps) => {
43
69
 
44
70
  const [searchValue, setSearchValue] = useState('');
45
71
 
72
+ const {
73
+ settings,
74
+ resetSettings,
75
+ setHasColumnBorders,
76
+ setTableSpacing,
77
+ } = useTableSettings({
78
+ onTableSettingsChanged,
79
+ onTableSettingsReset,
80
+ onColumnBordersChanged,
81
+ onTableSpacingChanged,
82
+ });
83
+
84
+ const { hasColumnBorders, tableSpacing } = settings;
85
+
46
86
  return (
47
87
  <GridApiContext.Provider value={gridApi}>
48
- <section data-testid={testId} className={classNames('ds-table__container', wrapperClassName)}>
49
- {headerContent && (
50
- <TableHeader data-testid={headerTestId} hasSearch={hasSearch} searchValue={searchValue} setSearchValue={setSearchValue}>
51
- {headerContent}
52
- </TableHeader>
53
- )}
54
- <AgGridReact
55
- theme={tableTheme}
56
- onGridReady={(event) => {
57
- const { api } = event;
58
- setGridApi(api);
59
- onGridReady?.(event);
60
- }}
61
- suppressPaginationPanel
62
- {...rest}
63
- {...(hasSearch && { quickFilterText: searchValue })}
64
- />
65
- {footerContent && (
66
- <TableFooter data-testid={footerTestId}>
67
- {footerContent}
68
- </TableFooter>
69
- )}
70
- </section>
88
+ <TableSettingsContext.Provider value={{ settings, resetSettings, setHasColumnBorders, setTableSpacing }}>
89
+ <section data-testid={testId} className={classNames('ds-table__container', wrapperClassName)}>
90
+ {headerContent && (
91
+ <TableHeader data-testid={headerTestId} hasSearch={hasSearch} searchValue={searchValue} setSearchValue={setSearchValue}>
92
+ {headerContent}
93
+ </TableHeader>
94
+ )}
95
+ <AgGridReact
96
+ theme={tableTheme.withParams({
97
+ headerRowBorder: hasColumnBorders,
98
+ rowBorder: hasColumnBorders,
99
+ wrapperBorder: hasColumnBorders,
100
+ columnBorder: hasColumnBorders,
101
+ spacing: {
102
+ // These are offset by one from the usual spacing tokens. We still use the token values to make spacing
103
+ // consistent with other parts of the DS, but --spacing-xsmall was too large for xsmall spacing, and so on
104
+ // for the other tokens
105
+ [TABLE_SPACING.XS]: 0,
106
+ [TABLE_SPACING.S]: 'var(--spacing-xsmall)',
107
+ [TABLE_SPACING.M]: 'var(--spacing-small)',
108
+ [TABLE_SPACING.L]: 'var(--spacing-medium)',
109
+ }[tableSpacing],
110
+ })}
111
+ onGridReady={(event) => {
112
+ const { api } = event;
113
+ setGridApi(api);
114
+ onGridReady?.(event);
115
+ }}
116
+ suppressPaginationPanel
117
+ {...rest}
118
+ {...(hasSearch && { quickFilterText: searchValue })}
119
+ />
120
+ {footerContent && (
121
+ <TableFooter data-testid={footerTestId}>
122
+ {footerContent}
123
+ </TableFooter>
124
+ )}
125
+ </section>
126
+ </TableSettingsContext.Provider>
71
127
  </GridApiContext.Provider>
72
128
  );
73
129
  };
@@ -0,0 +1,90 @@
1
+ import { Button } from 'Components/button/Button';
2
+ import { Dropdown } from 'Components/dropdown/Dropdown';
3
+ import { CheckboxGroup } from 'Components/formField/inputs/checkbox/CheckboxGroup';
4
+ import { RadioButtonGroup } from 'Components/formField/inputs/radio/RadioButtonGroup';
5
+ import { Separator } from 'Components/separator/Separator';
6
+ import { useContext, useState, type ChangeEvent } from 'react';
7
+ import { TABLE_SPACING, TableSettingsContext } from '../Table';
8
+
9
+ const TABLE_SPACING_NAMES = {
10
+ XS: 'X-Small',
11
+ S: 'Small',
12
+ M: 'Medium',
13
+ L: 'Large',
14
+ };
15
+
16
+ export const TableSettingsDropdown = () => {
17
+ const {
18
+ settings: {
19
+ hasColumnBorders,
20
+ tableSpacing,
21
+ },
22
+ setTableSpacing,
23
+ setHasColumnBorders,
24
+ resetSettings,
25
+ } = useContext(TableSettingsContext);
26
+
27
+ const [cellColours, setCellColours] = useState<boolean>(false);
28
+
29
+ return (
30
+ <Dropdown>
31
+ <Dropdown.Trigger>
32
+ <Button
33
+ variant="secondary"
34
+ iconRightName="settings"
35
+ iconRightScreenReaderText="Table settings"
36
+ borderless
37
+ />
38
+ </Dropdown.Trigger>
39
+ <Dropdown.Content>
40
+ <RadioButtonGroup
41
+ legend="Table spacing"
42
+ options={Object.values(TABLE_SPACING).map((option) => {
43
+ return {
44
+ name: 'ds-table-spacing',
45
+ label: TABLE_SPACING_NAMES[option],
46
+ value: option,
47
+ };
48
+ })}
49
+ name="ds-table-spacing"
50
+ checkedValue={tableSpacing}
51
+ onChange={(e: ChangeEvent<HTMLInputElement>) => {
52
+ setTableSpacing(e.target.value as TABLE_SPACING);
53
+ }}
54
+ />
55
+
56
+ <Separator />
57
+
58
+ <CheckboxGroup
59
+ legend="Style"
60
+ options={[
61
+ {
62
+ label: 'Column borders',
63
+ checked: hasColumnBorders,
64
+ onChange: () => {
65
+ setHasColumnBorders(!hasColumnBorders);
66
+ },
67
+ },
68
+ {
69
+ label: 'Cell colours',
70
+ checked: cellColours,
71
+ onChange: () => {
72
+ setCellColours(!cellColours);
73
+ },
74
+ },
75
+ ]}
76
+ />
77
+
78
+ <Separator />
79
+
80
+ <Button
81
+ variant="tertiary"
82
+ iconLeftName="redo"
83
+ onClick={resetSettings}
84
+ >
85
+ Reset Table Settings
86
+ </Button>
87
+ </Dropdown.Content>
88
+ </Dropdown>
89
+ );
90
+ };
@@ -1,4 +1,12 @@
1
1
  .ds-table {
2
+ &__container {
3
+ .ag-header-cell-resize {
4
+ // AG-Grid gives these a z-index of 2 which interferes with our stacking elements
5
+ // so we just unset it here
6
+ z-index: unset;
7
+ }
8
+ }
9
+
2
10
  &__footer,
3
11
  &__header {
4
12
  display: flex;
@@ -0,0 +1,59 @@
1
+ import { useState } from 'react';
2
+ import { TABLE_SPACING } from './Table';
3
+ import { useComponentDidUpdate } from 'Utils/hooks/useComponentDidUpdate';
4
+
5
+ export type TableSettings = {
6
+ hasColumnBorders?: boolean;
7
+ tableSpacing: TABLE_SPACING;
8
+ };
9
+
10
+ type UseTableSettingsParams = {
11
+ onTableSettingsChanged?: (val: TableSettings) => void;
12
+ onTableSettingsReset?: () => void;
13
+ onColumnBordersChanged?: (val: boolean) => void;
14
+ onTableSpacingChanged?: (val: TABLE_SPACING) => void;
15
+ };
16
+
17
+ export const useTableSettings = (params: UseTableSettingsParams = {}) => {
18
+ const {
19
+ onTableSettingsChanged,
20
+ onTableSettingsReset,
21
+ onColumnBordersChanged,
22
+ onTableSpacingChanged,
23
+ } = params;
24
+ const [hasColumnBorders, setHasColumnBorders] = useState(false);
25
+ const [tableSpacing, setTableSpacing] = useState(TABLE_SPACING.M);
26
+
27
+ const settings = {
28
+ hasColumnBorders,
29
+ tableSpacing,
30
+ };
31
+
32
+ const resetSettings = () => {
33
+ setHasColumnBorders(false);
34
+ setTableSpacing(TABLE_SPACING.M);
35
+ if (onTableSettingsReset) {
36
+ onTableSettingsReset();
37
+ }
38
+ };
39
+
40
+ useComponentDidUpdate(() => {
41
+ if (onColumnBordersChanged) {
42
+ onColumnBordersChanged(hasColumnBorders);
43
+ }
44
+ }, [hasColumnBorders]);
45
+
46
+ useComponentDidUpdate(() => {
47
+ if (onTableSpacingChanged) {
48
+ onTableSpacingChanged(tableSpacing);
49
+ }
50
+ }, [tableSpacing]);
51
+
52
+ useComponentDidUpdate(() => {
53
+ if (onTableSettingsChanged) {
54
+ onTableSettingsChanged(settings);
55
+ }
56
+ }, [hasColumnBorders, tableSpacing]);
57
+
58
+ return { settings, resetSettings, setHasColumnBorders, setTableSpacing };
59
+ };
package/src/index.scss CHANGED
@@ -6,6 +6,7 @@
6
6
  @use "components/card/card.scss";
7
7
  @use "components/dropdown/dropdown.scss";
8
8
  @use "components/formField/formField.scss";
9
+ @use "components/formField/fieldset/fieldset.scss";
9
10
  @use "components/formField/inputs/input.scss";
10
11
  @use "components/formField/label/label.scss";
11
12
  @use "components/formField/inputs/number/numberInput.scss";
@@ -22,4 +23,7 @@
22
23
  @use "components/searchBar/searchBar.scss";
23
24
  @use "components/table/pagination/pagination.scss";
24
25
  @use "components/tooltip/tooltip.scss";
26
+ @use "components/separator/separator.scss";
27
+ @use "components/modal/modal.scss";
28
+ @use "components/modal/modalManager/modalManager.scss";
25
29
  @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
@@ -19,3 +19,7 @@ export { Table } from 'Components/table/Table';
19
19
  export { GridApiContext } from 'Components/table/GridApiContext';
20
20
  export { Tooltip } from 'Components/tooltip/Tooltip';
21
21
  export { TooltipWrapper } from 'Components/tooltip/TooltipWrapper';
22
+ export { Fieldset } from 'Components/formField/fieldset/Fieldset';
23
+ export { Separator } from 'Components/separator/Separator';
24
+ export { Modal } from 'Components/modal/Modal';
25
+ export { ModalManager } from 'Components/modal/modalManager/ModalManager';
package/src/tokens.scss CHANGED
@@ -333,6 +333,7 @@
333
333
  --modal-header-color-icon-hover: var(--color-grey-050);
334
334
  --modal-radius: var(--border-radius-small);
335
335
  --modal-color-background: var(--color-grey-050);
336
+ --modal-min-width: 37.5rem;
336
337
  --toast-info-icon-hover-color-background: var(--color-semantic-info-100);
337
338
  --toast-info-icon-color-icon: var(--color-semantic-info-800);
338
339
  --toast-info-color-text: var(--color-semantic-info-800);
@@ -3,3 +3,9 @@ export const SLIDEOVER = {
3
3
  REMOVE_SLIDEOVER: 'ds-remove-slideover',
4
4
  REMOVE_ALL_SLIDEOVERS: 'ds-remove-all-slideover',
5
5
  };
6
+
7
+ export const MODAL = {
8
+ ADD_MODAL: 'ds-add-modal',
9
+ REMOVE_MODAL: 'ds-remove-modal',
10
+ REMOVE_ALL_MODALS: 'ds-remove-all-modals',
11
+ };
@@ -0,0 +1,17 @@
1
+ import type { ModalProps } from 'Components/modal/Modal';
2
+ import PubSub from './PubSub';
3
+ import { MODAL } from './Constants';
4
+
5
+ export const ModalUtils = {
6
+ addModal: (modal: ModalProps) => {
7
+ PubSub.publish(MODAL.ADD_MODAL, modal);
8
+ },
9
+
10
+ removeModal: () => {
11
+ PubSub.publish(MODAL.REMOVE_MODAL);
12
+ },
13
+
14
+ removeAllModals: () => {
15
+ PubSub.publish(MODAL.REMOVE_ALL_MODALS);
16
+ },
17
+ };
@@ -0,0 +1,107 @@
1
+ import { expect, test, describe, vi } from 'vitest';
2
+ import { renderHook } from '@testing-library/react';
3
+ import { useComponentDidUpdate } from './useComponentDidUpdate';
4
+
5
+ describe('useComponentDidUpdate', () => {
6
+ test('does not call effect on initial render', () => {
7
+ const effect = vi.fn();
8
+ renderHook(() => useComponentDidUpdate(effect, []));
9
+
10
+ expect(effect).not.toHaveBeenCalled();
11
+ });
12
+
13
+ test('calls effect on subsequent renders when dependencies change', () => {
14
+ const effect = vi.fn();
15
+ const { rerender } = renderHook(
16
+ ({ deps }) => useComponentDidUpdate(effect, deps),
17
+ { initialProps: { deps: [1] } },
18
+ );
19
+
20
+ expect(effect).not.toHaveBeenCalled();
21
+
22
+ rerender({ deps: [2] });
23
+ expect(effect).toHaveBeenCalledTimes(1);
24
+ });
25
+
26
+ test('does not call effect when dependencies do not change', () => {
27
+ const effect = vi.fn();
28
+ const { rerender } = renderHook(
29
+ ({ deps }) => useComponentDidUpdate(effect, deps),
30
+ { initialProps: { deps: [1] } },
31
+ );
32
+
33
+ expect(effect).not.toHaveBeenCalled();
34
+
35
+ rerender({ deps: [1] });
36
+ expect(effect).not.toHaveBeenCalled();
37
+ });
38
+
39
+ test('calls effect multiple times on multiple updates', () => {
40
+ const effect = vi.fn();
41
+ const { rerender } = renderHook(
42
+ ({ deps }) => useComponentDidUpdate(effect, deps),
43
+ { initialProps: { deps: [1] } },
44
+ );
45
+
46
+ rerender({ deps: [2] });
47
+ expect(effect).toHaveBeenCalledTimes(1);
48
+
49
+ rerender({ deps: [3] });
50
+ expect(effect).toHaveBeenCalledTimes(2);
51
+
52
+ rerender({ deps: [4] });
53
+ expect(effect).toHaveBeenCalledTimes(3);
54
+ });
55
+
56
+ test('calls cleanup function returned from effect', () => {
57
+ const cleanup = vi.fn();
58
+ const effect = vi.fn(() => cleanup);
59
+ const { rerender, unmount } = renderHook(
60
+ ({ deps }) => useComponentDidUpdate(effect, deps),
61
+ { initialProps: { deps: [1] } },
62
+ );
63
+
64
+ rerender({ deps: [2] });
65
+ expect(effect).toHaveBeenCalledTimes(1);
66
+ expect(cleanup).not.toHaveBeenCalled();
67
+
68
+ rerender({ deps: [3] });
69
+ expect(cleanup).toHaveBeenCalledTimes(1);
70
+ expect(effect).toHaveBeenCalledTimes(2);
71
+
72
+ unmount();
73
+ expect(cleanup).toHaveBeenCalledTimes(2);
74
+ });
75
+
76
+ test('works with multiple dependencies', () => {
77
+ const effect = vi.fn();
78
+ const { rerender } = renderHook(
79
+ ({ deps }) => useComponentDidUpdate(effect, deps),
80
+ { initialProps: { deps: [1, 'a', true] } },
81
+ );
82
+
83
+ expect(effect).not.toHaveBeenCalled();
84
+
85
+ // Change one dependency
86
+ rerender({ deps: [1, 'a', false] });
87
+ expect(effect).toHaveBeenCalledTimes(1);
88
+
89
+ // Change another dependency
90
+ rerender({ deps: [1, 'b', false] });
91
+ expect(effect).toHaveBeenCalledTimes(2);
92
+
93
+ // Change multiple dependencies
94
+ rerender({ deps: [2, 'c', true] });
95
+ expect(effect).toHaveBeenCalledTimes(3);
96
+ });
97
+
98
+ test('works with empty dependency array', () => {
99
+ const effect = vi.fn();
100
+ const { rerender } = renderHook(() => useComponentDidUpdate(effect, []));
101
+
102
+ expect(effect).not.toHaveBeenCalled();
103
+
104
+ rerender();
105
+ expect(effect).not.toHaveBeenCalled();
106
+ });
107
+ });
@@ -0,0 +1,19 @@
1
+ import { useEffect, useRef, type DependencyList, type EffectCallback } from 'react';
2
+
3
+ /**
4
+ * This is a hook that is functionally identical to useEffect, except it only runs on
5
+ * updates, never on first render
6
+ */
7
+ export const useComponentDidUpdate = (effect: EffectCallback, deps: DependencyList) => {
8
+ const isFirstRenderRef = useRef(true);
9
+
10
+ useEffect(() => {
11
+ if (isFirstRenderRef.current) {
12
+ isFirstRenderRef.current = false;
13
+ return;
14
+ }
15
+ else {
16
+ return effect();
17
+ }
18
+ }, deps);
19
+ };