@arbor-education/design-system.components 3.2.0 → 3.3.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 (90) hide show
  1. package/.gather/skills/write-stories/README.md +8 -4
  2. package/.gather/skills/write-stories/SKILL.md +59 -5
  3. package/CHANGELOG.md +24 -0
  4. package/dist/components/breadcrumbs/Breadcrumbs.stories.d.ts +1 -0
  5. package/dist/components/breadcrumbs/Breadcrumbs.stories.d.ts.map +1 -1
  6. package/dist/components/breadcrumbs/Breadcrumbs.stories.js +103 -21
  7. package/dist/components/breadcrumbs/Breadcrumbs.stories.js.map +1 -1
  8. package/dist/components/card/Card.stories.d.ts.map +1 -1
  9. package/dist/components/card/Card.stories.js +46 -41
  10. package/dist/components/card/Card.stories.js.map +1 -1
  11. package/dist/components/editableText/EditableText.stories.d.ts.map +1 -1
  12. package/dist/components/editableText/EditableText.stories.js +19 -6
  13. package/dist/components/editableText/EditableText.stories.js.map +1 -1
  14. package/dist/components/filterBar/FilterBar.d.ts +2 -2
  15. package/dist/components/filterBar/FilterBar.d.ts.map +1 -1
  16. package/dist/components/filterBar/FilterBar.js +7 -3
  17. package/dist/components/filterBar/FilterBar.js.map +1 -1
  18. package/dist/components/filterBar/FilterBar.stories.d.ts +16 -0
  19. package/dist/components/filterBar/FilterBar.stories.d.ts.map +1 -1
  20. package/dist/components/filterBar/FilterBar.stories.js +101 -7
  21. package/dist/components/filterBar/FilterBar.stories.js.map +1 -1
  22. package/dist/components/filterBar/FilterBar.test.js +30 -0
  23. package/dist/components/filterBar/FilterBar.test.js.map +1 -1
  24. package/dist/components/formField/fieldset/Fieldset.stories.d.ts.map +1 -1
  25. package/dist/components/formField/fieldset/Fieldset.stories.js +5 -3
  26. package/dist/components/formField/fieldset/Fieldset.stories.js.map +1 -1
  27. package/dist/components/row/Row.stories.d.ts.map +1 -1
  28. package/dist/components/row/Row.stories.js +22 -13
  29. package/dist/components/row/Row.stories.js.map +1 -1
  30. package/dist/components/sidebar/Sidebar.stories.d.ts.map +1 -1
  31. package/dist/components/sidebar/Sidebar.stories.js +19 -24
  32. package/dist/components/sidebar/Sidebar.stories.js.map +1 -1
  33. package/dist/components/table/Table.d.ts.map +1 -1
  34. package/dist/components/table/Table.js +2 -1
  35. package/dist/components/table/Table.js.map +1 -1
  36. package/dist/components/table/Table.stories.d.ts +7 -0
  37. package/dist/components/table/Table.stories.d.ts.map +1 -1
  38. package/dist/components/table/Table.stories.js +60 -10
  39. package/dist/components/table/Table.stories.js.map +1 -1
  40. package/dist/components/table/Table.test.js +23 -0
  41. package/dist/components/table/Table.test.js.map +1 -1
  42. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.d.ts.map +1 -1
  43. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js +8 -5
  44. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js.map +1 -1
  45. package/dist/components/table/tableControls/TableControls.d.ts +2 -0
  46. package/dist/components/table/tableControls/TableControls.d.ts.map +1 -1
  47. package/dist/components/table/tableControls/TableControls.js +2 -2
  48. package/dist/components/table/tableControls/TableControls.js.map +1 -1
  49. package/dist/components/table/tableControls/TableControls.stories.d.ts +26 -1
  50. package/dist/components/table/tableControls/TableControls.stories.d.ts.map +1 -1
  51. package/dist/components/table/tableControls/TableControls.stories.js +50 -21
  52. package/dist/components/table/tableControls/TableControls.stories.js.map +1 -1
  53. package/dist/components/table/tableControls/TableControls.test.js +16 -0
  54. package/dist/components/table/tableControls/TableControls.test.js.map +1 -1
  55. package/dist/components/table/useTableSettings.d.ts +2 -0
  56. package/dist/components/table/useTableSettings.d.ts.map +1 -1
  57. package/dist/components/table/useTableSettings.js +12 -7
  58. package/dist/components/table/useTableSettings.js.map +1 -1
  59. package/dist/components/widget/Widget.stories.d.ts +13 -0
  60. package/dist/components/widget/Widget.stories.d.ts.map +1 -1
  61. package/dist/components/widget/Widget.stories.js +45 -6
  62. package/dist/components/widget/Widget.stories.js.map +1 -1
  63. package/dist/components/widgetCalendar/WidgetCalendar.stories.d.ts +88 -16
  64. package/dist/components/widgetCalendar/WidgetCalendar.stories.d.ts.map +1 -1
  65. package/dist/components/widgetCalendar/WidgetCalendar.stories.js +443 -30
  66. package/dist/components/widgetCalendar/WidgetCalendar.stories.js.map +1 -1
  67. package/dist/index.css +1 -4
  68. package/dist/index.css.map +1 -1
  69. package/package.json +1 -1
  70. package/src/components/breadcrumbs/Breadcrumbs.stories.tsx +112 -21
  71. package/src/components/card/Card.stories.tsx +46 -41
  72. package/src/components/datePicker/datePicker.scss +0 -5
  73. package/src/components/editableText/EditableText.stories.tsx +26 -29
  74. package/src/components/filterBar/FilterBar.stories.tsx +126 -4
  75. package/src/components/filterBar/FilterBar.test.tsx +51 -0
  76. package/src/components/filterBar/FilterBar.tsx +18 -12
  77. package/src/components/formField/fieldset/Fieldset.stories.tsx +5 -3
  78. package/src/components/row/Row.stories.tsx +20 -14
  79. package/src/components/sidebar/Sidebar.stories.tsx +61 -112
  80. package/src/components/table/Table.stories.tsx +82 -10
  81. package/src/components/table/Table.test.tsx +42 -0
  82. package/src/components/table/Table.tsx +2 -0
  83. package/src/components/table/cellRenderers/SelectDropdownCellRenderer.stories.tsx +8 -5
  84. package/src/components/table/tableControls/TableControls.stories.tsx +54 -21
  85. package/src/components/table/tableControls/TableControls.test.tsx +20 -0
  86. package/src/components/table/tableControls/TableControls.tsx +6 -0
  87. package/src/components/table/useTableSettings.ts +20 -6
  88. package/src/components/widget/Widget.stories.tsx +61 -6
  89. package/src/components/widgetCalendar/WidgetCalendar.stories.tsx +547 -74
  90. package/src/tokens.scss +1 -0
@@ -51,7 +51,9 @@ const USAGE_GUIDANCE = [
51
51
  '|---|---|---|',
52
52
  '| `bulkActions` | Start | Array of `{ displayName, callback, disabled? }` — shown as a dropdown when rows are selected |',
53
53
  '| `onUndo` | Start | Renders an undo icon button |',
54
+ '| `isUndoDisabled` | Start | Disables the undo button (e.g. when there is nothing to undo) |',
54
55
  '| `onRedo` | Start | Renders a redo icon button |',
56
+ '| `isRedoDisabled` | Start | Disables the redo button (e.g. when there is nothing to redo) |',
55
57
  '| `showHideColumns` | Start | Renders the `HideColumnsDropdown` |',
56
58
  '| `hasSearch` | End | Renders the `SearchBar` |',
57
59
  '| `onDownload` | End | Renders a download icon button |',
@@ -65,7 +67,7 @@ const DEVELOPER_NOTES = [
65
67
  '### Wiring into `<Table />`',
66
68
  '',
67
69
  '```tsx',
68
- "import { Table, TableControls } from '@arbor-education/design-system.components';",
70
+ "import { Table } from '@arbor-education/design-system.components';",
69
71
  '',
70
72
  'function MyTable() {',
71
73
  ' return (',
@@ -73,12 +75,13 @@ const DEVELOPER_NOTES = [
73
75
  ' rowData={rows}',
74
76
  ' columnDefs={colDefs}',
75
77
  ' headerContent={(',
76
- ' <TableControls',
78
+ ' <Table.TableControls',
77
79
  ' bulkActions={[',
78
80
  ' { displayName: "Export selected", callback: api => exportCsv(api) },',
79
81
  ' { displayName: "Delete selected", callback: api => deleteRows(api) },',
80
82
  ' ]}',
81
83
  ' onUndo={handleUndo}',
84
+ ' isUndoDisabled={!canUndo}',
82
85
  ' showHideColumns',
83
86
  ' onDownload={handleDownload}',
84
87
  ' showSettings',
@@ -93,16 +96,19 @@ const DEVELOPER_NOTES = [
93
96
  '',
94
97
  '---',
95
98
  '',
96
- '### `BulkAction` type',
99
+ '### `Table.BulkAction` type',
97
100
  '',
98
101
  '```ts',
99
- "import type { BulkAction } from '@arbor-education/design-system.components';",
102
+ "import { Table } from '@arbor-education/design-system.components';",
100
103
  '',
101
- 'type BulkAction = {',
102
- ' displayName: string;',
103
- ' callback: (gridApi: GridApi) => void;',
104
- ' disabled?: boolean;',
105
- '};',
104
+ 'type MyAction = Table.BulkAction;',
105
+ '',
106
+ '// shape:',
107
+ '// {',
108
+ '// displayName: string;',
109
+ '// callback: (gridApi: GridApi) => void;',
110
+ '// disabled?: boolean;',
111
+ '// }',
106
112
  '```',
107
113
  '',
108
114
  '---',
@@ -115,7 +121,7 @@ const DEVELOPER_NOTES = [
115
121
  'prop to supply columns manually:',
116
122
  '',
117
123
  '```tsx',
118
- '<TableControls',
124
+ '<Table.TableControls',
119
125
  ' showHideColumns',
120
126
  ' hideColumnsProps={{',
121
127
  ' columns: myColumns,',
@@ -129,8 +135,10 @@ const DEVELOPER_NOTES = [
129
135
  '### TypeScript types',
130
136
  '',
131
137
  '```ts',
132
- "import { TableControls } from '@arbor-education/design-system.components';",
133
- "import type { TableControlsProps, BulkAction } from '@arbor-education/design-system.components';",
138
+ "import { Table } from '@arbor-education/design-system.components';",
139
+ '',
140
+ 'type MyControlsProps = Table.ControlsProps;',
141
+ 'type MyAction = Table.BulkAction;',
134
142
  '```',
135
143
  ].join('\n');
136
144
 
@@ -190,11 +198,21 @@ const meta = {
190
198
  control: false,
191
199
  table: { type: { summary: '() => void' }, defaultValue: { summary: 'undefined' } },
192
200
  },
201
+ isUndoDisabled: {
202
+ description: 'When `true`, disables the undo button (e.g. when there is nothing to undo). Has no effect if `onUndo` is not provided.',
203
+ control: 'boolean',
204
+ table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' } },
205
+ },
193
206
  onRedo: {
194
207
  description: 'Renders a redo icon button in the start group. Called with no arguments on click.',
195
208
  control: false,
196
209
  table: { type: { summary: '() => void' }, defaultValue: { summary: 'undefined' } },
197
210
  },
211
+ isRedoDisabled: {
212
+ description: 'When `true`, disables the redo button (e.g. when there is nothing to redo). Has no effect if `onRedo` is not provided.',
213
+ control: 'boolean',
214
+ table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' } },
215
+ },
198
216
  showHideColumns: {
199
217
  description: 'When `true`, renders the `HideColumnsDropdown` in the start group. Reads column visibility from `GridApiContext` (provided by `<Table />`). Pass `hideColumnsProps` for manual column control.',
200
218
  control: 'boolean',
@@ -294,6 +312,21 @@ export const StartGroupOnly: Story = withDescription(
294
312
  + 'see the **Within a Table** story for a fully wired example.',
295
313
  );
296
314
 
315
+ export const UndoRedoDisabled: Story = withDescription(
316
+ {
317
+ args: {
318
+ onUndo: fn(),
319
+ isUndoDisabled: true,
320
+ onRedo: fn(),
321
+ isRedoDisabled: true,
322
+ },
323
+ },
324
+ 'Undo and redo rendered with `isUndoDisabled` / `isRedoDisabled` set — use these when there is '
325
+ + 'nothing left to undo or redo, so the buttons stay visible but communicate they are unavailable '
326
+ + 'instead of silently no-opping when clicked. Toggle `isUndoDisabled` / `isRedoDisabled` off in the '
327
+ + 'Controls panel to compare against the enabled state.',
328
+ );
329
+
297
330
  export const EndGroupOnly: Story = withDescription(
298
331
  {
299
332
  parameters: { controls: { disable: true } },
@@ -317,7 +350,7 @@ export const BulkActionsOnly: Story = withDescription(
317
350
  source: {
318
351
  language: 'tsx',
319
352
  code: `
320
- import { Table, TableControls } from '@arbor-education/design-system.components';
353
+ import { Table } from '@arbor-education/design-system.components';
321
354
 
322
355
  function MyTable() {
323
356
  return (
@@ -326,7 +359,7 @@ function MyTable() {
326
359
  columnDefs={colDefs}
327
360
  rowSelection={{ mode: 'multiRow', checkboxes: true }}
328
361
  headerContent={(
329
- <TableControls
362
+ <Table.TableControls
330
363
  bulkActions={[
331
364
  { displayName: 'Export selected', callback: api => api.exportDataAsCsv() },
332
365
  { displayName: 'Delete selected', callback: handleDelete, disabled: !canDelete },
@@ -355,7 +388,7 @@ export default MyTable;
355
388
  + 'Pass `disabled: true` to a specific action to grey it out (e.g. "Delete selected" when nothing is selected).',
356
389
  );
357
390
 
358
- export const FullToolbar: Story = withDescription(
391
+ export const MaximumStandaloneToolbar: Story = withDescription(
359
392
  {
360
393
  parameters: {
361
394
  controls: { disable: true },
@@ -363,7 +396,7 @@ export const FullToolbar: Story = withDescription(
363
396
  source: {
364
397
  language: 'tsx',
365
398
  code: `
366
- import { Table, TableControls } from '@arbor-education/design-system.components';
399
+ import { Table } from '@arbor-education/design-system.components';
367
400
 
368
401
  function FullTableExample() {
369
402
  return (
@@ -372,7 +405,7 @@ function FullTableExample() {
372
405
  columnDefs={colDefs}
373
406
  rowSelection={{ mode: 'multiRow', checkboxes: true }}
374
407
  headerContent={(
375
- <TableControls
408
+ <Table.TableControls
376
409
  bulkActions={[
377
410
  { displayName: 'Export selected', callback: api => api.exportDataAsCsv() },
378
411
  { displayName: 'Delete selected', callback: handleDelete },
@@ -408,8 +441,8 @@ export default FullTableExample;
408
441
  onExpandToggle: fn(),
409
442
  },
410
443
  },
411
- 'The full toolbar with both groups populated: bulk actions, undo, redo, hide columns, download, settings, help, and expand. '
412
- + 'This is the maximum control density — only include the slots your users actually need. '
413
- + '`showHideColumns` renders a `HideColumnsDropdown` that reads columns from `GridApiContext`; '
414
- + 'in this standalone preview it is disabled since there is no enclosing `<Table />` providing that context.',
444
+ 'Every standalone control except `showHideColumns`: bulk actions, undo, redo, download, settings, help, and expand. '
445
+ + '`showHideColumns` is left `false` here because `HideColumnsDropdown` needs a `GridApiContext` to read column data, '
446
+ + 'and that context is only provided by a real `<Table />` — it cannot be faked in this standalone preview. '
447
+ + 'See [Table](?path=/docs/components-table--docs) for a fully-wired example with `showHideColumns: true` inside an actual `<Table />`.',
415
448
  );
@@ -44,6 +44,26 @@ describe('TableControls', () => {
44
44
  expect(onRedo).toHaveBeenCalledTimes(1);
45
45
  });
46
46
 
47
+ test('disables the undo button when isUndoDisabled is true', () => {
48
+ render(<TableControls onUndo={vi.fn()} isUndoDisabled />);
49
+ expect(screen.getByRole('button', { name: /undo/i })).toBeDisabled();
50
+ });
51
+
52
+ test('does not disable the undo button by default', () => {
53
+ render(<TableControls onUndo={vi.fn()} />);
54
+ expect(screen.getByRole('button', { name: /undo/i })).toBeEnabled();
55
+ });
56
+
57
+ test('disables the redo button when isRedoDisabled is true', () => {
58
+ render(<TableControls onRedo={vi.fn()} isRedoDisabled />);
59
+ expect(screen.getByRole('button', { name: /redo/i })).toBeDisabled();
60
+ });
61
+
62
+ test('does not disable the redo button by default', () => {
63
+ render(<TableControls onRedo={vi.fn()} />);
64
+ expect(screen.getByRole('button', { name: /redo/i })).toBeEnabled();
65
+ });
66
+
47
67
  test('renders bulk actions dropdown when bulkActions is provided', () => {
48
68
  render(
49
69
  <TableControls
@@ -16,6 +16,8 @@ export type TableControlsProps = {
16
16
  bulkActions?: BulkAction[];
17
17
  onUndo?: () => void;
18
18
  onRedo?: () => void;
19
+ isUndoDisabled?: boolean;
20
+ isRedoDisabled?: boolean;
19
21
  showHideColumns?: boolean;
20
22
  hideColumnsProps?: HideColumnsDropdownProps;
21
23
  hasSearch?: boolean;
@@ -36,6 +38,8 @@ export const TableControls = (props: TableControlsProps) => {
36
38
  bulkActions,
37
39
  onUndo,
38
40
  onRedo,
41
+ isUndoDisabled = false,
42
+ isRedoDisabled = false,
39
43
  showHideColumns,
40
44
  hideColumnsProps,
41
45
  hasSearch,
@@ -73,6 +77,7 @@ export const TableControls = (props: TableControlsProps) => {
73
77
  variant="secondary"
74
78
  borderless
75
79
  isRound
80
+ disabled={isUndoDisabled}
76
81
  onClick={onUndo}
77
82
  >
78
83
  <Icon name="undo" screenReaderText="Undo" />
@@ -83,6 +88,7 @@ export const TableControls = (props: TableControlsProps) => {
83
88
  variant="secondary"
84
89
  borderless
85
90
  isRound
91
+ disabled={isRedoDisabled}
86
92
  onClick={onRedo}
87
93
  >
88
94
  <Icon name="redo" screenReaderText="Redo" />
@@ -8,7 +8,14 @@ export type TableSettings = {
8
8
  areCellColorsEnabled?: boolean;
9
9
  };
10
10
 
11
+ export const DEFAULT_TABLE_SETTINGS: Required<TableSettings> = {
12
+ hasColumnBorders: false,
13
+ tableSpacing: TABLE_SPACING.M,
14
+ areCellColorsEnabled: true,
15
+ };
16
+
11
17
  export type UseTableSettingsParams = {
18
+ initialSettings?: Partial<TableSettings>;
12
19
  onTableSettingsChanged?: (val: TableSettings) => void;
13
20
  onTableSettingsReset?: () => void;
14
21
  onColumnBordersChanged?: (val: boolean) => void;
@@ -18,15 +25,22 @@ export type UseTableSettingsParams = {
18
25
 
19
26
  export const useTableSettings = (params: UseTableSettingsParams = {}) => {
20
27
  const {
28
+ initialSettings,
21
29
  onTableSettingsChanged,
22
30
  onTableSettingsReset,
23
31
  onColumnBordersChanged,
24
32
  onTableSpacingChanged,
25
33
  onCellColorsChanged,
26
34
  } = params;
27
- const [hasColumnBorders, setHasColumnBorders] = useState(false);
28
- const [tableSpacing, setTableSpacing] = useState(TABLE_SPACING.M);
29
- const [areCellColorsEnabled, setAreCellColorsEnabled] = useState(true);
35
+ const [hasColumnBorders, setHasColumnBorders] = useState(
36
+ initialSettings?.hasColumnBorders ?? DEFAULT_TABLE_SETTINGS.hasColumnBorders,
37
+ );
38
+ const [tableSpacing, setTableSpacing] = useState(
39
+ initialSettings?.tableSpacing ?? DEFAULT_TABLE_SETTINGS.tableSpacing,
40
+ );
41
+ const [areCellColorsEnabled, setAreCellColorsEnabled] = useState(
42
+ initialSettings?.areCellColorsEnabled ?? DEFAULT_TABLE_SETTINGS.areCellColorsEnabled,
43
+ );
30
44
 
31
45
  const settings = {
32
46
  hasColumnBorders,
@@ -35,9 +49,9 @@ export const useTableSettings = (params: UseTableSettingsParams = {}) => {
35
49
  };
36
50
 
37
51
  const resetSettings = () => {
38
- setHasColumnBorders(false);
39
- setTableSpacing(TABLE_SPACING.M);
40
- setAreCellColorsEnabled(true);
52
+ setHasColumnBorders(DEFAULT_TABLE_SETTINGS.hasColumnBorders);
53
+ setTableSpacing(DEFAULT_TABLE_SETTINGS.tableSpacing);
54
+ setAreCellColorsEnabled(DEFAULT_TABLE_SETTINGS.areCellColorsEnabled);
41
55
  if (onTableSettingsReset) {
42
56
  onTableSettingsReset();
43
57
  }
@@ -165,6 +165,14 @@ const meta = {
165
165
  description: 'Renders an info icon with tooltip beside the header title.',
166
166
  table: { type: { summary: 'string' } },
167
167
  },
168
+ isFloating: {
169
+ control: 'boolean',
170
+ description: 'Gives the widget a permanent elevated shadow (`ds-widget--floating`), on both hover and rest, instead of the default where hovering removes the shadow entirely. Use for widgets that need to visually lift off a busy dashboard background.',
171
+ table: {
172
+ type: { summary: 'boolean' },
173
+ defaultValue: { summary: 'false' },
174
+ },
175
+ },
168
176
  isLoading: {
169
177
  control: 'boolean',
170
178
  description: 'Replaces body content with a loading indicator and sets `aria-busy` on the body.',
@@ -296,7 +304,7 @@ const WithTooltipTemplate = () => (
296
304
  );
297
305
 
298
306
  const CollapsibleTemplate = () => (
299
- <Widget collapsible defaultExpanded>
307
+ <Widget collapsible>
300
308
  <Widget.Header>Attendance summary</Widget.Header>
301
309
  <Widget.Body>
302
310
  <p style={{ margin: 0 }}>Widget body content</p>
@@ -327,9 +335,22 @@ const WithRenderLinkTemplate = () => (
327
335
  </Widget>
328
336
  );
329
337
 
338
+ const FloatingTemplate = () => (
339
+ <Widget isFloating>
340
+ <Widget.Header>Favourites</Widget.Header>
341
+ <Widget.Body>
342
+ <ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
343
+ {Array.from({ length: 6 }, (_, index) => (
344
+ <li key={index}>Favourite</li>
345
+ ))}
346
+ </ul>
347
+ </Widget.Body>
348
+ </Widget>
349
+ );
350
+
330
351
  const FixedHeightOverflowTemplate = () => (
331
352
  <FixedHeightWidgetContainer>
332
- <Widget isFloating>
353
+ <Widget>
333
354
  <Widget.Header>Favourites</Widget.Header>
334
355
  <Widget.Body>
335
356
  <ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
@@ -483,7 +504,7 @@ import { Widget } from '@arbor-education/design-system.components';
483
504
 
484
505
  function WidgetCollapsibleExample() {
485
506
  return (
486
- <Widget collapsible defaultExpanded>
507
+ <Widget collapsible>
487
508
  <Widget.Header>Attendance summary</Widget.Header>
488
509
  <Widget.Body>
489
510
  <p>Widget body content</p>
@@ -515,7 +536,9 @@ function WidgetLoadingExample() {
515
536
  return (
516
537
  <Widget isLoading loadingLabel="Loading alerts">
517
538
  <Widget.Header>Alerts</Widget.Header>
518
- <Widget.Body />
539
+ <Widget.Body>
540
+ <p>Content hidden while loading</p>
541
+ </Widget.Body>
519
542
  </Widget>
520
543
  );
521
544
  }
@@ -544,7 +567,7 @@ function WidgetRenderLinkExample() {
544
567
  <Widget
545
568
  href="/alerts"
546
569
  renderLink={({ href, className, children, linkProps }) => (
547
- <a href={href} className={className} {...linkProps}>
570
+ <a href={href} className={className} data-router-link="true" {...linkProps}>
548
571
  {children}
549
572
  </a>
550
573
  )}
@@ -577,7 +600,7 @@ import { Widget } from '@arbor-education/design-system.components';
577
600
  function WidgetFixedHeightOverflowExample() {
578
601
  return (
579
602
  <div style={{ height: 280, display: 'flex', flexDirection: 'column' }}>
580
- <Widget isFloating>
603
+ <Widget>
581
604
  <Widget.Header>Favourites</Widget.Header>
582
605
  <Widget.Body>
583
606
  <ul>
@@ -598,3 +621,35 @@ export default WidgetFixedHeightOverflowExample;
598
621
  },
599
622
  'Parent container constrains height; the widget header stays pinned while `.ds-widget__body` scrolls overflow content.',
600
623
  );
624
+
625
+ export const Floating: Story = withDescription(
626
+ {
627
+ render: FloatingTemplate,
628
+ parameters: {
629
+ controls: { disable: true },
630
+ docs: {
631
+ source: {
632
+ language: 'tsx',
633
+ code: `
634
+ import { Widget } from '@arbor-education/design-system.components';
635
+
636
+ function WidgetFloatingExample() {
637
+ return (
638
+ <Widget isFloating>
639
+ <Widget.Header>Favourites</Widget.Header>
640
+ <Widget.Body>
641
+ <ul>
642
+ <li>Favourite</li>
643
+ </ul>
644
+ </Widget.Body>
645
+ </Widget>
646
+ );
647
+ }
648
+ export default WidgetFloatingExample;
649
+ `.trim(),
650
+ },
651
+ },
652
+ },
653
+ },
654
+ '`isFloating` gives the widget a permanent elevated shadow that does not clear on hover. Use it to visually lift a widget off a busy dashboard background.',
655
+ );