@arbor-education/design-system.components 0.11.0 → 0.12.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 (191) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/avatar/Avatar.d.ts +4 -0
  3. package/dist/components/avatar/Avatar.d.ts.map +1 -1
  4. package/dist/components/avatarGroup/AvatarGroup.d.ts +6 -0
  5. package/dist/components/avatarGroup/AvatarGroup.d.ts.map +1 -1
  6. package/dist/components/badge/Badge.d.ts +5 -0
  7. package/dist/components/badge/Badge.d.ts.map +1 -1
  8. package/dist/components/banner/Banner.d.ts +7 -1
  9. package/dist/components/banner/Banner.d.ts.map +1 -1
  10. package/dist/components/banner/Banner.js +4 -1
  11. package/dist/components/banner/Banner.js.map +1 -1
  12. package/dist/components/button/Button.d.ts +5 -0
  13. package/dist/components/button/Button.d.ts.map +1 -1
  14. package/dist/components/card/Card.d.ts +3 -0
  15. package/dist/components/card/Card.d.ts.map +1 -1
  16. package/dist/components/combobox/Combobox.d.ts +9 -1
  17. package/dist/components/combobox/Combobox.d.ts.map +1 -1
  18. package/dist/components/datePicker/DatePicker.d.ts +3 -0
  19. package/dist/components/datePicker/DatePicker.d.ts.map +1 -1
  20. package/dist/components/dateTimePicker/DateTimePicker.d.ts +4 -1
  21. package/dist/components/dateTimePicker/DateTimePicker.d.ts.map +1 -1
  22. package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts +3 -3
  23. package/dist/components/dot/Dot.d.ts +4 -0
  24. package/dist/components/dot/Dot.d.ts.map +1 -1
  25. package/dist/components/dropdown/Dropdown.d.ts +15 -10
  26. package/dist/components/dropdown/Dropdown.d.ts.map +1 -1
  27. package/dist/components/dropdown/Dropdown.js.map +1 -1
  28. package/dist/components/dropdown/DropdownContent.d.ts +1 -2
  29. package/dist/components/dropdown/DropdownContent.d.ts.map +1 -1
  30. package/dist/components/dropdown/DropdownTrigger.d.ts +3 -2
  31. package/dist/components/dropdown/DropdownTrigger.d.ts.map +1 -1
  32. package/dist/components/dropdown/DropdownTrigger.js.map +1 -1
  33. package/dist/components/formField/FormField.d.ts +4 -2
  34. package/dist/components/formField/FormField.d.ts.map +1 -1
  35. package/dist/components/formField/fieldset/Fieldset.d.ts +3 -0
  36. package/dist/components/formField/fieldset/Fieldset.d.ts.map +1 -1
  37. package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts +4 -2
  38. package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts.map +1 -1
  39. package/dist/components/formField/inputs/checkbox/CheckboxInput.d.ts +3 -0
  40. package/dist/components/formField/inputs/checkbox/CheckboxInput.d.ts.map +1 -1
  41. package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.d.ts +3 -0
  42. package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.d.ts.map +1 -1
  43. package/dist/components/formField/inputs/number/NumberInput.d.ts +3 -0
  44. package/dist/components/formField/inputs/number/NumberInput.d.ts.map +1 -1
  45. package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts +3 -0
  46. package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts.map +1 -1
  47. package/dist/components/formField/inputs/radio/RadioButtonInput.d.ts +3 -0
  48. package/dist/components/formField/inputs/radio/RadioButtonInput.d.ts.map +1 -1
  49. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts +3 -0
  50. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts.map +1 -1
  51. package/dist/components/formField/inputs/text/TextInput.d.ts +3 -0
  52. package/dist/components/formField/inputs/text/TextInput.d.ts.map +1 -1
  53. package/dist/components/formField/inputs/textArea/TextArea.d.ts +3 -0
  54. package/dist/components/formField/inputs/textArea/TextArea.d.ts.map +1 -1
  55. package/dist/components/formField/inputs/time/TimeInput.d.ts +5 -0
  56. package/dist/components/formField/inputs/time/TimeInput.d.ts.map +1 -1
  57. package/dist/components/formField/inputs/time/TimeInput.stories.d.ts +1 -1
  58. package/dist/components/heading/Heading.d.ts +5 -0
  59. package/dist/components/heading/Heading.d.ts.map +1 -1
  60. package/dist/components/icon/Icon.d.ts +7 -1
  61. package/dist/components/icon/Icon.d.ts.map +1 -1
  62. package/dist/components/modal/Modal.d.ts +16 -4
  63. package/dist/components/modal/Modal.d.ts.map +1 -1
  64. package/dist/components/modal/Modal.js.map +1 -1
  65. package/dist/components/progress/Progress.d.ts +3 -0
  66. package/dist/components/progress/Progress.d.ts.map +1 -1
  67. package/dist/components/row/Row.d.ts +3 -0
  68. package/dist/components/row/Row.d.ts.map +1 -1
  69. package/dist/components/singleUser/SingleUser.d.ts +3 -0
  70. package/dist/components/singleUser/SingleUser.d.ts.map +1 -1
  71. package/dist/components/slideover/Slideover.d.ts +3 -0
  72. package/dist/components/slideover/Slideover.d.ts.map +1 -1
  73. package/dist/components/table/Table.d.ts +15 -29
  74. package/dist/components/table/Table.d.ts.map +1 -1
  75. package/dist/components/table/Table.js +11 -23
  76. package/dist/components/table/Table.js.map +1 -1
  77. package/dist/components/table/Table.stories.d.ts +3 -0
  78. package/dist/components/table/Table.stories.d.ts.map +1 -1
  79. package/dist/components/table/Table.stories.js +68 -25
  80. package/dist/components/table/Table.stories.js.map +1 -1
  81. package/dist/components/table/Table.test.js +9 -9
  82. package/dist/components/table/Table.test.js.map +1 -1
  83. package/dist/components/table/TableSettingsContext.d.ts +13 -0
  84. package/dist/components/table/TableSettingsContext.d.ts.map +1 -0
  85. package/dist/components/table/TableSettingsContext.js +15 -0
  86. package/dist/components/table/TableSettingsContext.js.map +1 -0
  87. package/dist/components/table/tableConsts.d.ts +7 -0
  88. package/dist/components/table/tableConsts.d.ts.map +1 -0
  89. package/dist/components/table/tableConsts.js +8 -0
  90. package/dist/components/table/tableConsts.js.map +1 -0
  91. package/dist/components/table/{BulkActionsDropdown.d.ts → tableControls/BulkActionsDropdown.d.ts} +1 -1
  92. package/dist/components/table/tableControls/BulkActionsDropdown.d.ts.map +1 -0
  93. package/dist/components/table/{BulkActionsDropdown.js → tableControls/BulkActionsDropdown.js} +3 -3
  94. package/dist/components/table/tableControls/BulkActionsDropdown.js.map +1 -0
  95. package/dist/components/table/{HideColumnsDropdown.d.ts → tableControls/HideColumnsDropdown.d.ts} +1 -2
  96. package/dist/components/table/tableControls/HideColumnsDropdown.d.ts.map +1 -0
  97. package/dist/components/table/{HideColumnsDropdown.js → tableControls/HideColumnsDropdown.js} +2 -2
  98. package/dist/components/table/tableControls/HideColumnsDropdown.js.map +1 -0
  99. package/dist/components/table/tableControls/TableControls.d.ts +23 -0
  100. package/dist/components/table/tableControls/TableControls.d.ts.map +1 -0
  101. package/dist/components/table/tableControls/TableControls.js +21 -0
  102. package/dist/components/table/tableControls/TableControls.js.map +1 -0
  103. package/dist/components/table/tableControls/TableControls.test.d.ts +2 -0
  104. package/dist/components/table/tableControls/TableControls.test.d.ts.map +1 -0
  105. package/dist/components/table/tableControls/TableControls.test.js +124 -0
  106. package/dist/components/table/tableControls/TableControls.test.js.map +1 -0
  107. package/dist/components/table/tableControls/TableSettingsDropdown.d.ts.map +1 -0
  108. package/dist/components/table/{TableSettingsDropdown.js → tableControls/TableSettingsDropdown.js} +7 -6
  109. package/dist/components/table/tableControls/TableSettingsDropdown.js.map +1 -0
  110. package/dist/components/table/useTableSettings.d.ts +1 -1
  111. package/dist/components/table/useTableSettings.d.ts.map +1 -1
  112. package/dist/components/table/useTableSettings.js +1 -1
  113. package/dist/components/table/useTableSettings.js.map +1 -1
  114. package/dist/components/tag/Tag.d.ts +4 -0
  115. package/dist/components/tag/Tag.d.ts.map +1 -1
  116. package/dist/components/toast/Toast.d.ts +5 -0
  117. package/dist/components/toast/Toast.d.ts.map +1 -1
  118. package/dist/components/tooltip/Tooltip.d.ts +7 -1
  119. package/dist/components/tooltip/Tooltip.d.ts.map +1 -1
  120. package/dist/components/tooltip/Tooltip.js.map +1 -1
  121. package/dist/components/tooltip/TooltipWrapper.d.ts +3 -0
  122. package/dist/components/tooltip/TooltipWrapper.d.ts.map +1 -1
  123. package/dist/components/userDropdown/UserDropdown.d.ts +7 -0
  124. package/dist/components/userDropdown/UserDropdown.d.ts.map +1 -1
  125. package/dist/index.css +18 -0
  126. package/dist/index.css.map +1 -1
  127. package/dist/index.d.ts +20 -22
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.js +18 -13
  130. package/dist/index.js.map +1 -1
  131. package/dist/utils/setAgGridLicenseKey.js +1 -1
  132. package/eslint.config.mts +1 -0
  133. package/package.json +1 -1
  134. package/src/components/avatar/Avatar.tsx +5 -0
  135. package/src/components/avatarGroup/AvatarGroup.tsx +7 -0
  136. package/src/components/badge/Badge.tsx +6 -0
  137. package/src/components/banner/Banner.tsx +10 -1
  138. package/src/components/button/Button.tsx +6 -0
  139. package/src/components/card/Card.tsx +4 -0
  140. package/src/components/combobox/Combobox.tsx +10 -1
  141. package/src/components/datePicker/DatePicker.tsx +4 -0
  142. package/src/components/dateTimePicker/DateTimePicker.tsx +4 -1
  143. package/src/components/dot/Dot.tsx +5 -0
  144. package/src/components/dropdown/Dropdown.tsx +13 -3
  145. package/src/components/dropdown/DropdownContent.tsx +1 -1
  146. package/src/components/dropdown/DropdownTrigger.tsx +3 -1
  147. package/src/components/formField/FormField.tsx +5 -1
  148. package/src/components/formField/fieldset/Fieldset.tsx +4 -0
  149. package/src/components/formField/inputs/checkbox/CheckboxGroup.tsx +5 -1
  150. package/src/components/formField/inputs/checkbox/CheckboxInput.tsx +4 -0
  151. package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.tsx +4 -0
  152. package/src/components/formField/inputs/number/NumberInput.tsx +4 -0
  153. package/src/components/formField/inputs/radio/RadioButtonGroup.tsx +4 -0
  154. package/src/components/formField/inputs/radio/RadioButtonInput.tsx +4 -0
  155. package/src/components/formField/inputs/selectDropdown/SelectDropdown.tsx +4 -0
  156. package/src/components/formField/inputs/text/TextInput.tsx +4 -0
  157. package/src/components/formField/inputs/textArea/TextArea.tsx +4 -0
  158. package/src/components/formField/inputs/time/TimeInput.tsx +6 -0
  159. package/src/components/heading/Heading.tsx +6 -0
  160. package/src/components/icon/Icon.tsx +8 -1
  161. package/src/components/modal/Modal.tsx +13 -3
  162. package/src/components/progress/Progress.tsx +4 -0
  163. package/src/components/row/Row.tsx +4 -0
  164. package/src/components/singleUser/SingleUser.tsx +4 -0
  165. package/src/components/slideover/Slideover.tsx +4 -0
  166. package/src/components/table/Table.stories.tsx +103 -32
  167. package/src/components/table/Table.test.tsx +9 -9
  168. package/src/components/table/Table.tsx +22 -23
  169. package/src/components/table/TableSettingsContext.ts +15 -0
  170. package/src/components/table/table.scss +22 -0
  171. package/src/components/table/tableConsts.ts +6 -0
  172. package/src/components/table/{BulkActionsDropdown.tsx → tableControls/BulkActionsDropdown.tsx} +2 -2
  173. package/src/components/table/{HideColumnsDropdown.tsx → tableControls/HideColumnsDropdown.tsx} +2 -2
  174. package/src/components/table/tableControls/TableControls.test.tsx +150 -0
  175. package/src/components/table/tableControls/TableControls.tsx +143 -0
  176. package/src/components/table/{TableSettingsDropdown.tsx → tableControls/TableSettingsDropdown.tsx} +2 -1
  177. package/src/components/table/useTableSettings.ts +1 -1
  178. package/src/components/tag/Tag.tsx +5 -0
  179. package/src/components/toast/Toast.tsx +6 -0
  180. package/src/components/tooltip/Tooltip.tsx +7 -1
  181. package/src/components/tooltip/TooltipWrapper.tsx +4 -0
  182. package/src/components/userDropdown/UserDropdown.tsx +8 -0
  183. package/src/index.ts +20 -35
  184. package/src/utils/setAgGridLicenseKey.ts +1 -1
  185. package/dist/components/table/BulkActionsDropdown.d.ts.map +0 -1
  186. package/dist/components/table/BulkActionsDropdown.js.map +0 -1
  187. package/dist/components/table/HideColumnsDropdown.d.ts.map +0 -1
  188. package/dist/components/table/HideColumnsDropdown.js.map +0 -1
  189. package/dist/components/table/TableSettingsDropdown.d.ts.map +0 -1
  190. package/dist/components/table/TableSettingsDropdown.js.map +0 -1
  191. /package/dist/components/table/{TableSettingsDropdown.d.ts → tableControls/TableSettingsDropdown.d.ts} +0 -0
@@ -2,14 +2,12 @@ import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { type Column, type ColDef, type ColGroupDef } from 'ag-grid-enterprise';
3
3
  import { Table } from './Table';
4
4
  import { Button } from 'Components/button/Button';
5
- import { Icon } from 'Components/icon/Icon';
6
- import { BulkActionsDropdown } from './BulkActionsDropdown';
7
5
 
8
6
  import { useState, type ComponentProps } from 'react';
9
7
  import { RowCountInfo } from './pagination/RowCountInfo';
10
8
  import { PaginationPanel } from './pagination/PaginationPanel';
11
- import { HideColumnsDropdown } from './HideColumnsDropdown';
12
- import { TableSettingsDropdown } from './TableSettingsDropdown';
9
+ import { HideColumnsDropdown } from './tableControls/HideColumnsDropdown';
10
+ import { TableControls } from './tableControls/TableControls';
13
11
  import { ModalManager } from 'Components/modal/modalManager/ModalManager';
14
12
  import { Modal } from 'Components/modal/Modal';
15
13
  import { ModalUtils } from 'Utils/ModalUtils';
@@ -180,22 +178,14 @@ const footerContent = [
180
178
  </Button>,
181
179
  ];
182
180
 
183
- const headerContent = [
184
- <div key={0} style={{ display: 'flex', gap: '0.5rem' }}>
185
- <Button key={0} variant="secondary" size="S">
186
- Button 1
187
- </Button>
188
- <Button key={1} variant="secondary" size="S">
189
- Button 2
190
- </Button>
191
- </div>,
192
- <div key={1} style={{ display: 'flex', gap: '1rem' }}>
193
- <Icon name="download" />
194
- <TableSettingsDropdown />
195
- <Icon name="circle-help" />
196
- <Icon name="expand" />
197
- </div>,
198
- ];
181
+ const headerContent = (
182
+ <TableControls
183
+ onDownload={() => console.log('download')}
184
+ showSettings
185
+ onHelp={() => console.log('help')}
186
+ onExpandToggle={expanded => console.log('expand', expanded)}
187
+ />
188
+ );
199
189
 
200
190
  export const Default: Story = {
201
191
  args: {
@@ -280,26 +270,107 @@ export const WithBulkActions: Story = {
280
270
  columnDefs: sampleColumnDefs,
281
271
  defaultColDef,
282
272
  domLayout: 'autoHeight',
283
- headerContent: [
284
- <BulkActionsDropdown
285
- key={0}
286
- actions={[
273
+ headerContent: (
274
+ <TableControls
275
+ bulkActions={[
287
276
  {
288
277
  displayName: 'foo',
289
- callback: (gridApi) => {
290
- console.log('clicked on the foo action', gridApi);
291
- },
278
+ callback: (gridApi) => { console.log('clicked on the foo action', gridApi); },
292
279
  },
293
280
  {
294
281
  displayName: 'bar',
295
- callback: (gridApi) => {
296
- console.log('clicked on the bar action', gridApi);
297
- },
282
+ callback: (gridApi) => { console.log('clicked on the bar action', gridApi); },
298
283
  disabled: true,
299
284
  },
300
285
  ]}
301
- />,
302
- ],
286
+ />
287
+ ),
288
+ },
289
+ };
290
+
291
+ export const WithTableControls: Story = {
292
+ parameters: {
293
+ docs: {
294
+ description: {
295
+ story:
296
+ 'TableControls is a pre-composed toolbar that wires up the standard set of table controls. Every slot is opt-in — only pass the props for the controls you need.',
297
+ },
298
+ },
299
+ },
300
+ args: {
301
+ rowData: sampleData,
302
+ columnDefs: sampleColumnDefs,
303
+ defaultColDef,
304
+ domLayout: 'autoHeight',
305
+ headerContent: (
306
+ <TableControls
307
+ bulkActions={[
308
+ { displayName: 'Export selected', callback: api => console.log('export', api) },
309
+ { displayName: 'Delete selected', callback: api => console.log('delete', api), disabled: true },
310
+ ]}
311
+ onUndo={() => console.log('undo')}
312
+ onRedo={() => console.log('redo')}
313
+ showHideColumns
314
+ onDownload={() => console.log('download')}
315
+ showSettings
316
+ onHelp={() => console.log('help')}
317
+ onExpandToggle={expanded => console.log('expand', expanded)}
318
+ />
319
+ ),
320
+ },
321
+ };
322
+
323
+ export const WithTableControlsStartGroupOnly: Story = {
324
+ parameters: {
325
+ docs: {
326
+ description: {
327
+ story:
328
+ 'TableControls with only the start group rendered — bulk actions, undo, redo, and hide columns. No end group props are passed so that side is omitted entirely.',
329
+ },
330
+ },
331
+ },
332
+ args: {
333
+ rowData: sampleData,
334
+ columnDefs: sampleColumnDefs,
335
+ defaultColDef,
336
+ domLayout: 'autoHeight',
337
+ headerContent: (
338
+ <TableControls
339
+ bulkActions={[
340
+ { displayName: 'Export selected', callback: api => console.log('export', api) },
341
+ { displayName: 'Delete selected', callback: api => console.log('delete', api), disabled: true },
342
+ ]}
343
+ onUndo={() => console.log('undo')}
344
+ onRedo={() => console.log('redo')}
345
+ showHideColumns
346
+ />
347
+ ),
348
+ },
349
+ };
350
+
351
+ export const WithTableControlsEndGroupOnly: Story = {
352
+ parameters: {
353
+ docs: {
354
+ description: {
355
+ story:
356
+ 'TableControls with only the end group rendered — search, download, settings, help, and expand. No start group props are passed so that side is omitted entirely.',
357
+ },
358
+ },
359
+ },
360
+ args: {
361
+ rowData: sampleData,
362
+ columnDefs: sampleColumnDefs,
363
+ defaultColDef,
364
+ domLayout: 'autoHeight',
365
+ headerContent: (
366
+ <TableControls
367
+ hasSearch
368
+ onDownload={() => console.log('download')}
369
+ showSettings
370
+ onHelp={() => console.log('help')}
371
+ onExpandToggle={expanded => console.log('expand', expanded)}
372
+ />
373
+ ),
303
374
  },
304
375
  };
305
376
 
@@ -1,10 +1,10 @@
1
1
  import { describe, expect, expectTypeOf, test, vi } from 'vitest';
2
2
  import { render, screen, waitFor } from '@testing-library/react';
3
- import { Table, TABLE_SPACING } from './Table';
3
+ import { Table } from './Table';
4
4
  import '@testing-library/jest-dom/vitest';
5
- import { BulkActionsDropdown } from 'Components/table/BulkActionsDropdown';
6
- import { HideColumnsDropdown } from 'Components/table/HideColumnsDropdown';
7
- import { TableSettingsDropdown } from './TableSettingsDropdown';
5
+ import { BulkActionsDropdown } from 'Components/table/tableControls/BulkActionsDropdown';
6
+ import { HideColumnsDropdown } from 'Components/table/tableControls/HideColumnsDropdown';
7
+ import { TableSettingsDropdown } from './tableControls/TableSettingsDropdown';
8
8
  import userEvent from '@testing-library/user-event';
9
9
  import type { GridApi } from 'ag-grid-enterprise';
10
10
  import * as focusFirstFocusableElementModule from 'Utils/focusFirstFocusableElement';
@@ -817,7 +817,7 @@ describe('Table', () => {
817
817
  expect((largeRadio as HTMLInputElement).checked).toBe(true);
818
818
  });
819
819
  expect(onTableSettingsChanged).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({
820
- tableSpacing: TABLE_SPACING.L,
820
+ tableSpacing: Table.Spacing.L,
821
821
  }));
822
822
 
823
823
  const columnBordersCheckbox = screen.getByLabelText('Column borders');
@@ -896,7 +896,7 @@ describe('Table', () => {
896
896
  await userEvent.click(largeRadio);
897
897
 
898
898
  await waitFor(() => {
899
- expect(onTableSpacingChanged).toHaveBeenCalledExactlyOnceWith(TABLE_SPACING.L);
899
+ expect(onTableSpacingChanged).toHaveBeenCalledExactlyOnceWith(Table.Spacing.L);
900
900
  });
901
901
 
902
902
  const xsmallRadio = screen.getByLabelText('X-Small');
@@ -904,7 +904,7 @@ describe('Table', () => {
904
904
 
905
905
  await waitFor(() => {
906
906
  expect(onTableSpacingChanged).toHaveBeenCalledTimes(2);
907
- expect(onTableSpacingChanged).toHaveBeenNthCalledWith(2, TABLE_SPACING.XS);
907
+ expect(onTableSpacingChanged).toHaveBeenNthCalledWith(2, Table.Spacing.XS);
908
908
  });
909
909
  });
910
910
 
@@ -924,14 +924,14 @@ describe('Table', () => {
924
924
  await userEvent.click(largeRadio);
925
925
 
926
926
  await waitFor(() => {
927
- expect(onTableSpacingChanged).toHaveBeenCalledWith(TABLE_SPACING.L);
927
+ expect(onTableSpacingChanged).toHaveBeenCalledWith(Table.Spacing.L);
928
928
  });
929
929
 
930
930
  const resetButton = screen.getByRole('button', { name: /Reset Table Settings/i });
931
931
  await userEvent.click(resetButton);
932
932
 
933
933
  await waitFor(() => {
934
- expect(onTableSpacingChanged).toHaveBeenCalledWith(TABLE_SPACING.M);
934
+ expect(onTableSpacingChanged).toHaveBeenCalledWith(Table.Spacing.M);
935
935
  });
936
936
  });
937
937
 
@@ -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 { defaultTheme } from './theme/defaultTheme';
4
4
  import classNames from 'classnames';
5
- import { createContext, useRef, useState, type ReactNode } from 'react';
5
+ import { useRef, useState, type ReactNode } from 'react';
6
6
  import { TableFooter } from './TableFooter';
7
7
  import { TableHeader } from './TableHeader';
8
8
  import { GridApiContext } from './GridApiContext';
@@ -10,8 +10,8 @@ import { PaginationPanel } from './pagination/PaginationPanel';
10
10
  import { PageSizeSelector } from './pagination/PageSizeSelector';
11
11
  import { PaginationControls } from './pagination/PaginationControls';
12
12
  import { RowCountInfo } from './pagination/RowCountInfo';
13
- import { BulkActionsDropdown } from './BulkActionsDropdown';
14
- import { HideColumnsDropdown } from './HideColumnsDropdown';
13
+ import { BulkActionsDropdown } from './tableControls/BulkActionsDropdown';
14
+ import { HideColumnsDropdown } from './tableControls/HideColumnsDropdown';
15
15
  import { useTableSettings, type UseTableSettingsParams } from './useTableSettings';
16
16
  import { setAgGridLicenseKey } from 'Utils/setAgGridLicenseKey';
17
17
  import { toggleRowSelectionInCurrentRange } from './toggleRowSelectionInCurrentRange';
@@ -23,9 +23,13 @@ import { tidyTheme } from './theme/tidyTheme';
23
23
  import { focusFirstFocusableElement } from 'Utils/focusFirstFocusableElement';
24
24
  import { BooleanFilter } from './columnFilters/BooleanFilter/BooleanFilter';
25
25
  import { TimeFilter } from './columnFilters/TimeFilter/TimeFilter';
26
- import { TableSettingsDropdown } from './TableSettingsDropdown';
27
- import { CheckboxCellRenderer } from './cellRenderers/CheckboxCellRenderer';
26
+ import { TableSettingsDropdown } from './tableControls/TableSettingsDropdown';
27
+ import { TableControls, type TableControlsProps, type BulkAction as BulkActionType } from './tableControls/TableControls';
28
+ import type { HideColumnsDropdownProps } from './tableControls/HideColumnsDropdown';
29
+ import { TABLE_SPACING } from './tableConsts';
30
+ import { TableSettingsContext } from './TableSettingsContext';
28
31
  import { BooleanCellRenderer } from './cellRenderers/BooleanCellRenderer';
32
+ import { CheckboxCellRenderer } from './cellRenderers/CheckboxCellRenderer';
29
33
 
30
34
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
35
  type TableProps<TData = any> = {
@@ -45,24 +49,7 @@ setAgGridLicenseKey();
45
49
 
46
50
  ModuleRegistry.registerModules([AllEnterpriseModule]);
47
51
 
48
- export enum TABLE_SPACING {
49
- XS = 'XS',
50
- S = 'S',
51
- M = 'M',
52
- L = 'L',
53
- }
54
-
55
- export const TableSettingsContext = createContext<ReturnType<typeof useTableSettings>>({
56
- settings: {
57
- hasColumnBorders: false,
58
- tableSpacing: TABLE_SPACING.S,
59
- areCellColorsEnabled: true,
60
- },
61
- setTableSpacing: () => {},
62
- setHasColumnBorders: () => {},
63
- resetSettings: () => {},
64
- setAreCellColorsEnabled: () => {},
65
- });
52
+ export { TableSettingsContext } from './TableSettingsContext';
66
53
 
67
54
  export const Table = (props: TableProps) => {
68
55
  const {
@@ -223,3 +210,15 @@ Table.HideColumnsDropdown = HideColumnsDropdown;
223
210
  Table.ButtonCellRenderer = ButtonCellRenderer;
224
211
  Table.DefaultValueFormatter = defaultValueFormatter;
225
212
  Table.TableSettingsDropdown = TableSettingsDropdown;
213
+ Table.TableControls = TableControls;
214
+
215
+ Table.Spacing = TABLE_SPACING;
216
+
217
+ export namespace Table {
218
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
219
+ export type Props<TData = any> = TableProps<TData>;
220
+ export type ControlsProps = TableControlsProps;
221
+ export type BulkAction = BulkActionType;
222
+ export type HideColumnsProps = HideColumnsDropdownProps;
223
+ export type Spacing = TABLE_SPACING;
224
+ }
@@ -0,0 +1,15 @@
1
+ import { createContext } from 'react';
2
+ import { TABLE_SPACING } from './tableConsts';
3
+ import { type useTableSettings } from './useTableSettings';
4
+
5
+ export const TableSettingsContext = createContext<ReturnType<typeof useTableSettings>>({
6
+ settings: {
7
+ hasColumnBorders: false,
8
+ tableSpacing: TABLE_SPACING.S,
9
+ areCellColorsEnabled: true,
10
+ },
11
+ setTableSpacing: () => {},
12
+ setHasColumnBorders: () => {},
13
+ resetSettings: () => {},
14
+ setAreCellColorsEnabled: () => {},
15
+ });
@@ -11,6 +11,28 @@
11
11
  }
12
12
  }
13
13
 
14
+ &__controls {
15
+ display: flex;
16
+ flex-direction: row;
17
+ align-items: center;
18
+ justify-content: space-between;
19
+ padding: var(--tables-controls-spacing-horizontal) 0;
20
+ gap: var(--tables-controls-spacing-gap);
21
+ flex: 1;
22
+ }
23
+
24
+ &__controls-start,
25
+ &__controls-end {
26
+ display: flex;
27
+ flex-direction: row;
28
+ align-items: center;
29
+ gap: var(--tables-controls-spacing-gap);
30
+ }
31
+
32
+ &__controls-end {
33
+ margin-inline-start: auto;
34
+ }
35
+
14
36
  &__footer,
15
37
  &__header {
16
38
  display: flex;
@@ -0,0 +1,6 @@
1
+ export enum TABLE_SPACING {
2
+ XS = 'XS',
3
+ S = 'S',
4
+ M = 'M',
5
+ L = 'L',
6
+ }
@@ -1,10 +1,10 @@
1
1
  import { useContext } from 'react';
2
- import { GridApiContext } from './GridApiContext';
2
+ import { GridApiContext } from '../GridApiContext';
3
3
  import type { GridApi } from 'ag-grid-community';
4
4
  import { Button } from 'Components/button/Button';
5
5
  import { Dropdown } from 'Components/dropdown/Dropdown';
6
6
 
7
- type BulkAction = {
7
+ export type BulkAction = {
8
8
  displayName: string;
9
9
  callback: (api: GridApi | null) => void;
10
10
  disabled?: boolean;
@@ -1,9 +1,9 @@
1
1
  import { SelectDropdown } from 'Components/formField/inputs/selectDropdown/SelectDropdown';
2
2
  import { useContext, useState } from 'react';
3
- import { GridApiContext } from './GridApiContext';
3
+ import { GridApiContext } from '../GridApiContext';
4
4
  import type { Column } from 'ag-grid-community';
5
5
 
6
- type HideColumnsDropdownProps = {
6
+ export type HideColumnsDropdownProps = {
7
7
  columns?: Column[];
8
8
  onSelectionChanged?: (cols: string[]) => void;
9
9
  overrideColumnHiding?: boolean;
@@ -0,0 +1,150 @@
1
+ import { describe, expect, test, vi } from 'vitest';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/vitest';
4
+ import { TableControls } from './TableControls';
5
+
6
+ describe('TableControls', () => {
7
+ test('renders nothing when no props are passed', () => {
8
+ const { container } = render(<TableControls />);
9
+ expect(container.firstChild).toBeNull();
10
+ });
11
+
12
+ test('applies ds-table__controls class', () => {
13
+ const { container } = render(<TableControls onUndo={vi.fn()} />);
14
+ expect(container.querySelector('.ds-table__controls')).toBeInTheDocument();
15
+ });
16
+
17
+ test('applies additional className', () => {
18
+ const { container } = render(<TableControls onUndo={vi.fn()} className="custom-class" />);
19
+ expect(container.querySelector('.ds-table__controls')).toHaveClass('custom-class');
20
+ });
21
+
22
+ describe('start group', () => {
23
+ test('renders undo button when onUndo is provided', () => {
24
+ render(<TableControls onUndo={vi.fn()} />);
25
+ expect(screen.getByRole('button', { name: /undo/i })).toBeInTheDocument();
26
+ });
27
+
28
+ test('calls onUndo when undo button is clicked', () => {
29
+ const onUndo = vi.fn();
30
+ render(<TableControls onUndo={onUndo} />);
31
+ fireEvent.click(screen.getByRole('button', { name: /undo/i }));
32
+ expect(onUndo).toHaveBeenCalledTimes(1);
33
+ });
34
+
35
+ test('renders redo button when onRedo is provided', () => {
36
+ render(<TableControls onRedo={vi.fn()} />);
37
+ expect(screen.getByRole('button', { name: /redo/i })).toBeInTheDocument();
38
+ });
39
+
40
+ test('calls onRedo when redo button is clicked', () => {
41
+ const onRedo = vi.fn();
42
+ render(<TableControls onRedo={onRedo} />);
43
+ fireEvent.click(screen.getByRole('button', { name: /redo/i }));
44
+ expect(onRedo).toHaveBeenCalledTimes(1);
45
+ });
46
+
47
+ test('renders bulk actions dropdown when bulkActions is provided', () => {
48
+ render(
49
+ <TableControls
50
+ bulkActions={[{ displayName: 'Delete', callback: vi.fn() }]}
51
+ />,
52
+ );
53
+ expect(screen.getByRole('button', { name: /actions/i })).toBeInTheDocument();
54
+ });
55
+
56
+ test('does not render undo button when onUndo is not provided', () => {
57
+ render(<TableControls onRedo={vi.fn()} />);
58
+ expect(screen.queryByRole('button', { name: /undo/i })).not.toBeInTheDocument();
59
+ });
60
+
61
+ test('renders start group when showHideColumns is true', () => {
62
+ const { container } = render(<TableControls showHideColumns />);
63
+ expect(container.querySelector('.ds-table__controls-start')).toBeInTheDocument();
64
+ });
65
+
66
+ test('does not render start group when only hideColumnsProps is provided without showHideColumns', () => {
67
+ const { container } = render(<TableControls hideColumnsProps={{ overrideColumnHiding: true }} />);
68
+ expect(container.firstChild).toBeNull();
69
+ });
70
+ });
71
+
72
+ describe('end group', () => {
73
+ test('renders download button when onDownload is provided', () => {
74
+ render(<TableControls onDownload={vi.fn()} />);
75
+ expect(screen.getByRole('button', { name: /download/i })).toBeInTheDocument();
76
+ });
77
+
78
+ test('calls onDownload when download button is clicked', () => {
79
+ const onDownload = vi.fn();
80
+ render(<TableControls onDownload={onDownload} />);
81
+ fireEvent.click(screen.getByRole('button', { name: /download/i }));
82
+ expect(onDownload).toHaveBeenCalledTimes(1);
83
+ });
84
+
85
+ test('renders help button when onHelp is provided', () => {
86
+ render(<TableControls onHelp={vi.fn()} />);
87
+ expect(screen.getByRole('button', { name: /help/i })).toBeInTheDocument();
88
+ });
89
+
90
+ test('calls onHelp when help button is clicked', () => {
91
+ const onHelp = vi.fn();
92
+ render(<TableControls onHelp={onHelp} />);
93
+ fireEvent.click(screen.getByRole('button', { name: /help/i }));
94
+ expect(onHelp).toHaveBeenCalledTimes(1);
95
+ });
96
+
97
+ test('renders expand button when onExpandToggle is provided and not expanded', () => {
98
+ render(<TableControls onExpandToggle={vi.fn()} isExpanded={false} />);
99
+ expect(screen.getByRole('button', { name: /expand table/i })).toBeInTheDocument();
100
+ });
101
+
102
+ test('renders shrink button when onExpandToggle is provided and expanded', () => {
103
+ render(<TableControls onExpandToggle={vi.fn()} isExpanded={true} />);
104
+ expect(screen.getByRole('button', { name: /shrink table/i })).toBeInTheDocument();
105
+ });
106
+
107
+ test('calls onExpandToggle with true when expand button is clicked', () => {
108
+ const onExpandToggle = vi.fn();
109
+ render(<TableControls onExpandToggle={onExpandToggle} isExpanded={false} />);
110
+ fireEvent.click(screen.getByRole('button', { name: /expand table/i }));
111
+ expect(onExpandToggle).toHaveBeenCalledWith(true);
112
+ });
113
+
114
+ test('calls onExpandToggle with false when shrink button is clicked', () => {
115
+ const onExpandToggle = vi.fn();
116
+ render(<TableControls onExpandToggle={onExpandToggle} isExpanded={true} />);
117
+ fireEvent.click(screen.getByRole('button', { name: /shrink table/i }));
118
+ expect(onExpandToggle).toHaveBeenCalledWith(false);
119
+ });
120
+
121
+ test('renders tooltips button when onTooltipsToggle is provided', () => {
122
+ render(<TableControls onTooltipsToggle={vi.fn()} tooltipsEnabled={false} />);
123
+ expect(screen.getByRole('button', { name: /enable tooltips/i })).toBeInTheDocument();
124
+ });
125
+
126
+ test('renders disable tooltips button when tooltips are enabled', () => {
127
+ render(<TableControls onTooltipsToggle={vi.fn()} tooltipsEnabled={true} />);
128
+ expect(screen.getByRole('button', { name: /disable tooltips/i })).toBeInTheDocument();
129
+ });
130
+
131
+ test('calls onTooltipsToggle with true when tooltips are disabled', () => {
132
+ const onTooltipsToggle = vi.fn();
133
+ render(<TableControls onTooltipsToggle={onTooltipsToggle} tooltipsEnabled={false} />);
134
+ fireEvent.click(screen.getByRole('button', { name: /enable tooltips/i }));
135
+ expect(onTooltipsToggle).toHaveBeenCalledWith(true);
136
+ });
137
+
138
+ test('calls onTooltipsToggle with false when tooltips are enabled', () => {
139
+ const onTooltipsToggle = vi.fn();
140
+ render(<TableControls onTooltipsToggle={onTooltipsToggle} tooltipsEnabled={true} />);
141
+ fireEvent.click(screen.getByRole('button', { name: /disable tooltips/i }));
142
+ expect(onTooltipsToggle).toHaveBeenCalledWith(false);
143
+ });
144
+
145
+ test('renders search bar when hasSearch is true', () => {
146
+ render(<TableControls hasSearch searchValue="test" />);
147
+ expect(screen.getByRole('textbox', { name: /search input/i })).toBeInTheDocument();
148
+ });
149
+ });
150
+ });
@@ -0,0 +1,143 @@
1
+ import classNames from 'classnames';
2
+ import { Button } from 'Components/button/Button';
3
+ import { SearchBar } from 'Components/searchBar/SearchBar';
4
+ import { BulkActionsDropdown, type BulkAction } from './BulkActionsDropdown';
5
+ import {
6
+ HideColumnsDropdown,
7
+ type HideColumnsDropdownProps,
8
+ } from './HideColumnsDropdown';
9
+ import { TableSettingsDropdown } from './TableSettingsDropdown';
10
+
11
+ export type { BulkAction };
12
+
13
+ export type TableControlsProps = {
14
+ className?: string;
15
+ bulkActions?: BulkAction[];
16
+ onUndo?: () => void;
17
+ onRedo?: () => void;
18
+ showHideColumns?: boolean;
19
+ hideColumnsProps?: HideColumnsDropdownProps;
20
+ hasSearch?: boolean;
21
+ searchValue?: string;
22
+ setSearchValue?: (value: string) => void;
23
+ onDownload?: () => void;
24
+ tooltipsEnabled?: boolean;
25
+ onTooltipsToggle?: (enabled: boolean) => void;
26
+ showSettings?: boolean;
27
+ onHelp?: () => void;
28
+ isExpanded?: boolean;
29
+ onExpandToggle?: (expanded: boolean) => void;
30
+ };
31
+
32
+ export const TableControls = (props: TableControlsProps) => {
33
+ const {
34
+ className,
35
+ bulkActions,
36
+ onUndo,
37
+ onRedo,
38
+ showHideColumns,
39
+ hideColumnsProps,
40
+ hasSearch,
41
+ searchValue,
42
+ setSearchValue,
43
+ onDownload,
44
+ tooltipsEnabled,
45
+ onTooltipsToggle,
46
+ showSettings,
47
+ onHelp,
48
+ isExpanded,
49
+ onExpandToggle,
50
+ } = props;
51
+
52
+ const hasStartGroup = bulkActions || onUndo || onRedo || showHideColumns;
53
+ const hasEndGroup
54
+ = hasSearch
55
+ || onDownload
56
+ || onTooltipsToggle !== undefined
57
+ || showSettings
58
+ || onHelp
59
+ || onExpandToggle !== undefined;
60
+
61
+ if (!hasStartGroup && !hasEndGroup) return null;
62
+
63
+ return (
64
+ <div className={classNames('ds-table__controls', className)}>
65
+ {hasStartGroup && (
66
+ <div className="ds-table__controls-start">
67
+ {bulkActions && <BulkActionsDropdown actions={bulkActions} />}
68
+ {onUndo && (
69
+ <Button
70
+ variant="secondary"
71
+ borderless
72
+ iconRightName="undo"
73
+ iconRightScreenReaderText="Undo"
74
+ onClick={onUndo}
75
+ />
76
+ )}
77
+ {onRedo && (
78
+ <Button
79
+ variant="secondary"
80
+ borderless
81
+ iconRightName="redo"
82
+ iconRightScreenReaderText="Redo"
83
+ onClick={onRedo}
84
+ />
85
+ )}
86
+ {showHideColumns && <HideColumnsDropdown {...hideColumnsProps} />}
87
+ </div>
88
+ )}
89
+ {hasEndGroup && (
90
+ <div className="ds-table__controls-end">
91
+ {hasSearch && (
92
+ <SearchBar
93
+ searchValue={searchValue}
94
+ setSearchValue={setSearchValue}
95
+ />
96
+ )}
97
+ {onDownload && (
98
+ <Button
99
+ variant="secondary"
100
+ borderless
101
+ iconRightName="download"
102
+ iconRightScreenReaderText="Download"
103
+ onClick={onDownload}
104
+ />
105
+ )}
106
+ {onTooltipsToggle && (
107
+ <Button
108
+ variant="secondary"
109
+ borderless
110
+ iconRightName="message-square-more"
111
+ iconRightScreenReaderText={
112
+ tooltipsEnabled ? 'Disable tooltips' : 'Enable tooltips'
113
+ }
114
+ aria-pressed={tooltipsEnabled}
115
+ onClick={() => onTooltipsToggle(!tooltipsEnabled)}
116
+ />
117
+ )}
118
+ {showSettings && <TableSettingsDropdown />}
119
+ {onHelp && (
120
+ <Button
121
+ variant="secondary"
122
+ borderless
123
+ iconRightName="circle-help"
124
+ iconRightScreenReaderText="Help"
125
+ onClick={onHelp}
126
+ />
127
+ )}
128
+ {onExpandToggle && (
129
+ <Button
130
+ variant="secondary"
131
+ borderless
132
+ iconRightName={isExpanded ? 'shrink' : 'expand'}
133
+ iconRightScreenReaderText={
134
+ isExpanded ? 'Shrink table' : 'Expand table'
135
+ }
136
+ onClick={() => onExpandToggle(!isExpanded)}
137
+ />
138
+ )}
139
+ </div>
140
+ )}
141
+ </div>
142
+ );
143
+ };