@arbor-education/design-system.components 0.16.1 → 0.17.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 (73) hide show
  1. package/.gather/instructions/project-overview.md +0 -4
  2. package/.gather/skills/aroo-hunni/SKILL.md +58 -0
  3. package/CHANGELOG.md +31 -0
  4. package/CONTRIBUTING.md +1 -0
  5. package/dist/components/arborLogo/ArborLogo.d.ts +9 -0
  6. package/dist/components/arborLogo/ArborLogo.d.ts.map +1 -0
  7. package/dist/components/arborLogo/ArborLogo.js +17 -0
  8. package/dist/components/arborLogo/ArborLogo.js.map +1 -0
  9. package/dist/components/arborLogo/ArborLogo.stories.d.ts +94 -0
  10. package/dist/components/arborLogo/ArborLogo.stories.d.ts.map +1 -0
  11. package/dist/components/arborLogo/ArborLogo.stories.js +418 -0
  12. package/dist/components/arborLogo/ArborLogo.stories.js.map +1 -0
  13. package/dist/components/arborLogo/ArborLogo.test.d.ts +2 -0
  14. package/dist/components/arborLogo/ArborLogo.test.d.ts.map +1 -0
  15. package/dist/components/arborLogo/ArborLogo.test.js +32 -0
  16. package/dist/components/arborLogo/ArborLogo.test.js.map +1 -0
  17. package/dist/components/dataViewCard/DataViewCard.d.ts +19 -0
  18. package/dist/components/dataViewCard/DataViewCard.d.ts.map +1 -0
  19. package/dist/components/dataViewCard/DataViewCard.js +13 -0
  20. package/dist/components/dataViewCard/DataViewCard.js.map +1 -0
  21. package/dist/components/dataViewCard/DataViewCard.stories.d.ts +100 -0
  22. package/dist/components/dataViewCard/DataViewCard.stories.d.ts.map +1 -0
  23. package/dist/components/dataViewCard/DataViewCard.stories.js +317 -0
  24. package/dist/components/dataViewCard/DataViewCard.stories.js.map +1 -0
  25. package/dist/components/dataViewCard/DataViewCard.test.d.ts +2 -0
  26. package/dist/components/dataViewCard/DataViewCard.test.d.ts.map +1 -0
  27. package/dist/components/dataViewCard/DataViewCard.test.js +67 -0
  28. package/dist/components/dataViewCard/DataViewCard.test.js.map +1 -0
  29. package/dist/components/row/Row.d.ts +2 -1
  30. package/dist/components/row/Row.d.ts.map +1 -1
  31. package/dist/components/row/Row.js +2 -2
  32. package/dist/components/row/Row.js.map +1 -1
  33. package/dist/components/treeRow/TreeRow.d.ts +32 -0
  34. package/dist/components/treeRow/TreeRow.d.ts.map +1 -0
  35. package/dist/components/treeRow/TreeRow.js +19 -0
  36. package/dist/components/treeRow/TreeRow.js.map +1 -0
  37. package/dist/components/treeRow/TreeRow.stories.d.ts +13 -0
  38. package/dist/components/treeRow/TreeRow.stories.d.ts.map +1 -0
  39. package/dist/components/treeRow/TreeRow.stories.js +774 -0
  40. package/dist/components/treeRow/TreeRow.stories.js.map +1 -0
  41. package/dist/components/treeRow/TreeRow.test.d.ts +2 -0
  42. package/dist/components/treeRow/TreeRow.test.d.ts.map +1 -0
  43. package/dist/components/treeRow/TreeRow.test.js +262 -0
  44. package/dist/components/treeRow/TreeRow.test.js.map +1 -0
  45. package/dist/components/treeRow/TreeRowSection.d.ts +12 -0
  46. package/dist/components/treeRow/TreeRowSection.d.ts.map +1 -0
  47. package/dist/components/treeRow/TreeRowSection.js +20 -0
  48. package/dist/components/treeRow/TreeRowSection.js.map +1 -0
  49. package/dist/index.css +146 -1
  50. package/dist/index.css.map +1 -1
  51. package/dist/index.d.ts +4 -1
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +4 -1
  54. package/dist/index.js.map +1 -1
  55. package/package.json +2 -1
  56. package/src/components/arborLogo/ArborLogo.stories.tsx +663 -0
  57. package/src/components/arborLogo/ArborLogo.test.tsx +36 -0
  58. package/src/components/arborLogo/ArborLogo.tsx +92 -0
  59. package/src/components/arborLogo/__snapshots__/ArborLogo.test.tsx.snap +424 -0
  60. package/src/components/dataViewCard/DataViewCard.stories.tsx +464 -0
  61. package/src/components/dataViewCard/DataViewCard.test.tsx +127 -0
  62. package/src/components/dataViewCard/DataViewCard.tsx +62 -0
  63. package/src/components/dataViewCard/dataViewCard.scss +25 -0
  64. package/src/components/row/Row.tsx +4 -1
  65. package/src/components/row/row.scss +9 -1
  66. package/src/components/treeRow/TreeRow.stories.tsx +870 -0
  67. package/src/components/treeRow/TreeRow.test.tsx +371 -0
  68. package/src/components/treeRow/TreeRow.tsx +85 -0
  69. package/src/components/treeRow/TreeRowSection.tsx +56 -0
  70. package/src/components/treeRow/treeRow.scss +134 -0
  71. package/src/docs/Contributing.mdx +1 -0
  72. package/src/index.scss +2 -0
  73. package/src/index.ts +4 -1
@@ -0,0 +1,774 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Controls, Heading, Markdown, Primary, Stories, Subheading, Subtitle, Title, } from '@storybook/addon-docs/blocks';
4
+ import { TreeRow } from '../treeRow/TreeRow';
5
+ // ---------------------------------------------------------------------------
6
+ // Description blocks
7
+ // ---------------------------------------------------------------------------
8
+ const DESCRIPTION_INTRO = `
9
+ **TreeRow** is a collapsible, hierarchical list component for displaying nested data — think
10
+ school timetables, curriculum structures, student contact breakdowns, or any tree-shaped
11
+ information that benefits from progressive disclosure.
12
+ `.trim();
13
+ const SECTION_PROPS_TABLE = `
14
+ | Prop | Type | Required | Default | Description |
15
+ |------|------|----------|---------|-------------|
16
+ | \`label\` | \`string\` | Yes | — | The heading text shown on the branch row (always visible). |
17
+ | \`children\` | \`ReactNode\` | Yes | — | The content revealed when the section is expanded. Usually \`Row\` components or nested \`TreeRow.Section\` elements. |
18
+ | \`id\` | \`string\` | No | auto-generated | Stable identifier used by Radix Accordion. **Must be provided** if you want \`defaultValue\` to reliably pre-open this section — auto-generated IDs are non-deterministic across renders. |
19
+ | \`onClick\` | \`MouseEventHandler<HTMLDivElement>\` | No | — | When provided, the branch row becomes clickable independently of the expand/collapse trigger. A navigation caret appears on the right. The trigger's click is deliberately isolated via \`stopPropagation\` so both interactions work without conflict. |
20
+ | \`className\` | \`string\` | No | — | Extra CSS class(es) applied to the \`Accordion.Item\` wrapper. |
21
+ `.trim();
22
+ const USAGE_GUIDANCE = `
23
+ ---
24
+
25
+ ## When to use
26
+
27
+ - Displaying hierarchical data that would be overwhelming if shown flat — timetable subjects
28
+ and their lessons, a pupil's assessment breakdown by strand and topic, staff rotas with
29
+ team groupings.
30
+ - When the user needs to explore structure progressively rather than scan everything at once.
31
+ - Sidebar panels, detail drawers, or data-dense cards where vertical space is precious.
32
+
33
+ ## When NOT to use
34
+
35
+ - Simple flat lists — use [\`Row\`](?path=/docs/components-row--docs) directly.
36
+ - Navigation menus — use a dedicated nav component with proper ARIA roles.
37
+ - Data grids or sortable tables — use the \`Table\` component instead.
38
+ - Deeply nested structures beyond 3–4 levels: cognitive load becomes too high; consider
39
+ restructuring the information architecture instead.
40
+
41
+ ---
42
+
43
+ ## Two APIs
44
+
45
+ **TreeRow** supports two usage patterns — pick one per instance, never mix.
46
+
47
+ ### Data-driven (recommended for simple trees)
48
+
49
+ Pass an \`items\` array of \`TreeRowItem\` objects. Nesting is expressed recursively via
50
+ \`children\` arrays on each item. The component works out whether each item is a branch
51
+ (Section) or a leaf (Row) automatically.
52
+
53
+ \`\`\`tsx
54
+ import { TreeRow } from '@arbor-education/design-system.components';
55
+
56
+ const items = [
57
+ {
58
+ id: 'twilight',
59
+ label: 'Twilight',
60
+ children: [
61
+ { label: 'Author', value: 'Stephenie Meyer' },
62
+ { label: 'Published', value: '2005' },
63
+ ],
64
+ },
65
+ ];
66
+
67
+ <TreeRow items={items} defaultValue={['twilight']} />
68
+ \`\`\`
69
+
70
+ ### Compound component (for custom layouts or mixed content)
71
+
72
+ Use \`TreeRow.Section\` and \`Row\` directly as JSX children. This lets you
73
+ nest non-Row content inside sections, apply custom class names per node, or mix
74
+ interactive and static rows freely.
75
+
76
+ \`\`\`tsx
77
+ import { TreeRow, Row } from '@arbor-education/design-system.components';
78
+
79
+ <TreeRow>
80
+ <TreeRow.Section id="biology" label="Biology">
81
+ <Row label="Teacher" value="Dr Cullen" />
82
+ <Row label="Room" value="Lab 3" />
83
+ </TreeRow.Section>
84
+ </TreeRow>
85
+ \`\`\`
86
+
87
+ ---
88
+
89
+ ## Clickable sections
90
+
91
+ Sections can have an \`onClick\` handler in addition to (or instead of) expand/collapse
92
+ behaviour. When \`onClick\` is provided:
93
+
94
+ - A navigation caret appears on the trailing edge of the branch row.
95
+ - Clicking the **row area** fires \`onClick\`.
96
+ - Clicking the **label / chevron trigger** still only toggles expand/collapse — the
97
+ trigger's click is deliberately isolated via \`stopPropagation\`.
98
+
99
+ This means a section can simultaneously navigate somewhere **and** expand to reveal
100
+ child rows — a common pattern in Arbor's sidebar detail panels.
101
+
102
+ ---
103
+
104
+ ## Pre-opening sections
105
+
106
+ Use \`defaultValue\` with an array of section \`id\` strings to open sections on initial
107
+ render. If a section does not have an explicit \`id\` prop, its accordion value is an
108
+ auto-generated React ID that changes between renders — so **always set \`id\` on any
109
+ section you want in \`defaultValue\`**.
110
+
111
+ ---
112
+
113
+ ## Accessibility
114
+
115
+ - Built on [Radix UI Accordion](https://www.radix-ui.com/primitives/docs/components/accordion)
116
+ which ships with full keyboard support and correct ARIA attributes (\`aria-expanded\`,
117
+ \`aria-controls\`, \`role="region"\`) out of the box.
118
+ - Each trigger is a focusable button — keyboard users can navigate with **Tab** and
119
+ toggle sections with **Enter** or **Space**.
120
+ - Only the props listed above are exposed — for advanced accordion behaviour see the
121
+ [Radix Accordion docs](https://www.radix-ui.com/primitives/docs/components/accordion).
122
+ `.trim();
123
+ const RELATED_COMPONENTS = `
124
+ ## Related components
125
+
126
+ - [Row](?path=/docs/components-row--docs) — use directly as children inside \`TreeRow.Section\`.
127
+ `.trim();
128
+ // ---------------------------------------------------------------------------
129
+ // Docs page (compound component pattern)
130
+ // ---------------------------------------------------------------------------
131
+ function TreeRowDocsPage() {
132
+ return (_jsxs(_Fragment, { children: [_jsx(Title, {}), _jsx(Subtitle, {}), _jsx(Markdown, { children: DESCRIPTION_INTRO }), _jsx(Primary, {}), _jsx(Heading, { children: "Props reference" }), _jsx(Subheading, { children: "TreeRow root props" }), _jsx(Controls, {}), _jsx(Subheading, { children: "TreeRow.Section props" }), _jsx(Markdown, { children: SECTION_PROPS_TABLE }), _jsx(Markdown, { children: USAGE_GUIDANCE }), _jsx(Heading, { children: "Stories" }), _jsx(Stories, { title: "" }), _jsx(Markdown, { children: RELATED_COMPONENTS })] }));
133
+ }
134
+ // ---------------------------------------------------------------------------
135
+ // Meta
136
+ // ---------------------------------------------------------------------------
137
+ const meta = {
138
+ title: 'Components/TreeRow',
139
+ component: TreeRow,
140
+ tags: ['autodocs'],
141
+ parameters: {
142
+ docs: {
143
+ page: TreeRowDocsPage,
144
+ },
145
+ },
146
+ argTypes: {
147
+ items: {
148
+ description: 'Data-driven mode: an array of `TreeRowItem` objects to render. Items with a `children` array become collapsible sections; items without become leaf rows. **Mutually exclusive with `children`.**',
149
+ control: false,
150
+ table: {
151
+ type: { summary: 'TreeRowItem[]' },
152
+ defaultValue: { summary: 'undefined' },
153
+ },
154
+ },
155
+ children: {
156
+ description: 'Compound mode: pass `TreeRow.Section` and `Row` elements directly as JSX children. **Mutually exclusive with `items`.**',
157
+ control: false,
158
+ table: {
159
+ type: { summary: 'ReactNode' },
160
+ defaultValue: { summary: 'undefined' },
161
+ },
162
+ },
163
+ defaultValue: {
164
+ description: 'Array of section `id` strings that should be expanded on initial render. Sections without an explicit `id` prop receive a non-deterministic auto-generated ID — always set `id` on any section you want to pre-open.',
165
+ control: false,
166
+ table: {
167
+ type: { summary: 'string[]' },
168
+ defaultValue: { summary: 'undefined' },
169
+ },
170
+ },
171
+ className: {
172
+ description: 'Additional CSS class(es) applied to the root `Accordion.Root` wrapper element.',
173
+ control: 'text',
174
+ table: {
175
+ type: { summary: 'string' },
176
+ defaultValue: { summary: 'undefined' },
177
+ },
178
+ },
179
+ },
180
+ };
181
+ export default meta;
182
+ // ---------------------------------------------------------------------------
183
+ // Default — data-driven, two top-level sections, all collapsed
184
+ // ---------------------------------------------------------------------------
185
+ export const Default = {
186
+ args: {
187
+ items: [
188
+ {
189
+ id: 'english',
190
+ label: 'English Literature',
191
+ children: [
192
+ { label: 'Teacher', value: 'Ms Swan' },
193
+ { label: 'Room', value: 'A12' },
194
+ { label: 'Periods per week', value: '5' },
195
+ ],
196
+ },
197
+ {
198
+ id: 'biology',
199
+ label: 'Biology',
200
+ children: [
201
+ { label: 'Teacher', value: 'Dr Cullen' },
202
+ { label: 'Room', value: 'Lab 3' },
203
+ { label: 'Periods per week', value: '4' },
204
+ ],
205
+ },
206
+ ],
207
+ },
208
+ render: args => _jsx(TreeRow, { ...args }),
209
+ };
210
+ // ---------------------------------------------------------------------------
211
+ // PreOpenedSections — defaultValue with explicit IDs
212
+ // ---------------------------------------------------------------------------
213
+ export const PreOpenedSections = {
214
+ parameters: {
215
+ docs: {
216
+ description: {
217
+ story: 'Sections can be expanded on initial render by passing their `id` values in `defaultValue`. Both a top-level section ("Forks High School") and a nested section ("Year 11") are pre-opened here. Note that every section involved — at any depth — must have an explicit `id` prop for this to work reliably.',
218
+ },
219
+ source: {
220
+ code: `
221
+ import { TreeRow } from '@arbor-education/design-system.components';
222
+
223
+ function TreeRowPreOpenedSectionsExample() {
224
+ return (
225
+ <TreeRow
226
+ defaultValue={['forks-hs', 'year-11']}
227
+ items={[
228
+ {
229
+ id: 'forks-hs',
230
+ label: 'Forks High School',
231
+ children: [
232
+ {
233
+ id: 'year-10',
234
+ label: 'Year 10',
235
+ children: [
236
+ { label: 'Form tutor', value: 'Mr Black' },
237
+ { label: 'Pupils on roll', value: '28' },
238
+ ],
239
+ },
240
+ {
241
+ id: 'year-11',
242
+ label: 'Year 11',
243
+ children: [
244
+ { label: 'Form tutor', value: 'Ms Cullen' },
245
+ { label: 'Pupils on roll', value: '31' },
246
+ ],
247
+ },
248
+ ],
249
+ },
250
+ {
251
+ id: 'la-push-academy',
252
+ label: 'La Push Academy',
253
+ children: [
254
+ { label: 'Headteacher', value: 'Mr Ateara' },
255
+ { label: 'Pupils on roll', value: '142' },
256
+ ],
257
+ },
258
+ ]}
259
+ />
260
+ );
261
+ }
262
+
263
+ export default TreeRowPreOpenedSectionsExample;
264
+ `.trim(),
265
+ },
266
+ },
267
+ },
268
+ render: () => (_jsx(TreeRow, { defaultValue: ['forks-hs', 'year-11'], items: [
269
+ {
270
+ id: 'forks-hs',
271
+ label: 'Forks High School',
272
+ children: [
273
+ {
274
+ id: 'year-10',
275
+ label: 'Year 10',
276
+ children: [
277
+ { label: 'Form tutor', value: 'Mr Black' },
278
+ { label: 'Pupils on roll', value: '28' },
279
+ ],
280
+ },
281
+ {
282
+ id: 'year-11',
283
+ label: 'Year 11',
284
+ children: [
285
+ { label: 'Form tutor', value: 'Ms Cullen' },
286
+ { label: 'Pupils on roll', value: '31' },
287
+ ],
288
+ },
289
+ ],
290
+ },
291
+ {
292
+ id: 'la-push-academy',
293
+ label: 'La Push Academy',
294
+ children: [
295
+ { label: 'Headteacher', value: 'Mr Ateara' },
296
+ { label: 'Pupils on roll', value: '142' },
297
+ ],
298
+ },
299
+ ] })),
300
+ };
301
+ // ---------------------------------------------------------------------------
302
+ // DeepNesting — 4 levels, shows indentation progression
303
+ // ---------------------------------------------------------------------------
304
+ export const DeepNesting = {
305
+ parameters: {
306
+ docs: {
307
+ description: {
308
+ story: 'Nesting can go as deep as the data requires. Each additional level receives `calc(var(--spacing-xxlarge) * depth)` of left padding automatically via the internal `DepthContext`. Three to four levels is the practical maximum before readability suffers — restructure the hierarchy if you need more.',
309
+ },
310
+ source: {
311
+ code: `
312
+ import { TreeRow } from '@arbor-education/design-system.components';
313
+
314
+ function TreeRowDeepNestingExample() {
315
+ return (
316
+ <TreeRow
317
+ defaultValue={['assessment', 'science', 'biology', 'cells']}
318
+ items={[
319
+ {
320
+ id: 'assessment',
321
+ label: 'Assessment — Bella Swan',
322
+ children: [
323
+ {
324
+ id: 'science',
325
+ label: 'Science',
326
+ children: [
327
+ {
328
+ id: 'biology',
329
+ label: 'Biology',
330
+ children: [
331
+ {
332
+ id: 'cells',
333
+ label: 'Cell Biology',
334
+ children: [
335
+ { label: 'Grade', value: 'A*' },
336
+ { label: 'Score', value: '98%' },
337
+ { label: 'Assessed by', value: 'Dr Cullen' },
338
+ ],
339
+ },
340
+ {
341
+ id: 'genetics',
342
+ label: 'Genetics',
343
+ children: [
344
+ { label: 'Grade', value: 'A' },
345
+ { label: 'Score', value: '91%' },
346
+ ],
347
+ },
348
+ ],
349
+ },
350
+ {
351
+ id: 'chemistry',
352
+ label: 'Chemistry',
353
+ children: [
354
+ { label: 'Grade', value: 'B+' },
355
+ { label: 'Score', value: '79%' },
356
+ ],
357
+ },
358
+ ],
359
+ },
360
+ ],
361
+ },
362
+ ]}
363
+ />
364
+ );
365
+ }
366
+
367
+ export default TreeRowDeepNestingExample;
368
+ `.trim(),
369
+ },
370
+ },
371
+ },
372
+ render: () => (_jsx(TreeRow, { defaultValue: ['assessment', 'science', 'biology', 'cells'], items: [
373
+ {
374
+ id: 'assessment',
375
+ label: 'Assessment — Bella Swan',
376
+ children: [
377
+ {
378
+ id: 'science',
379
+ label: 'Science',
380
+ children: [
381
+ {
382
+ id: 'biology',
383
+ label: 'Biology',
384
+ children: [
385
+ {
386
+ id: 'cells',
387
+ label: 'Cell Biology',
388
+ children: [
389
+ { label: 'Grade', value: 'A*' },
390
+ { label: 'Score', value: '98%' },
391
+ { label: 'Assessed by', value: 'Dr Cullen' },
392
+ ],
393
+ },
394
+ {
395
+ id: 'genetics',
396
+ label: 'Genetics',
397
+ children: [
398
+ { label: 'Grade', value: 'A' },
399
+ { label: 'Score', value: '91%' },
400
+ ],
401
+ },
402
+ ],
403
+ },
404
+ {
405
+ id: 'chemistry',
406
+ label: 'Chemistry',
407
+ children: [
408
+ { label: 'Grade', value: 'B+' },
409
+ { label: 'Score', value: '79%' },
410
+ ],
411
+ },
412
+ ],
413
+ },
414
+ ],
415
+ },
416
+ ] })),
417
+ };
418
+ // ---------------------------------------------------------------------------
419
+ // ClickableSections — compound API, all sections have onClick
420
+ // ---------------------------------------------------------------------------
421
+ export const ClickableSections = {
422
+ parameters: {
423
+ docs: {
424
+ description: {
425
+ story: 'When a section has an `onClick` handler, a navigation caret appears on the trailing edge. Clicking the row area fires `onClick`; clicking the label or chevron trigger only toggles expand/collapse. Both interactions are fully independent.',
426
+ },
427
+ source: {
428
+ code: `
429
+ import { TreeRow } from '@arbor-education/design-system.components';
430
+
431
+ function TreeRowClickableSectionsExample() {
432
+ return (
433
+ <TreeRow
434
+ items={[
435
+ {
436
+ id: 'edward',
437
+ label: 'Edward Cullen',
438
+ onClick: () => console.log('Navigate to Edward Cullen'),
439
+ children: [
440
+ { label: 'Year group', value: 'Year 12' },
441
+ { label: 'Form', value: '12C' },
442
+ { label: 'Attendance', value: '100%' },
443
+ ],
444
+ },
445
+ {
446
+ id: 'bella',
447
+ label: 'Bella Swan',
448
+ onClick: () => console.log('Navigate to Bella Swan'),
449
+ children: [
450
+ { label: 'Year group', value: 'Year 12' },
451
+ { label: 'Form', value: '12B' },
452
+ { label: 'Attendance', value: '97.4%' },
453
+ ],
454
+ },
455
+ {
456
+ id: 'jacob',
457
+ label: 'Jacob Black',
458
+ onClick: () => console.log('Navigate to Jacob Black'),
459
+ children: [
460
+ { label: 'Year group', value: 'Year 11' },
461
+ { label: 'Form', value: '11J' },
462
+ { label: 'Attendance', value: '88.2%' },
463
+ ],
464
+ },
465
+ ]}
466
+ />
467
+ );
468
+ }
469
+
470
+ export default TreeRowClickableSectionsExample;
471
+ `.trim(),
472
+ },
473
+ },
474
+ },
475
+ render: () => (_jsx(TreeRow, { items: [
476
+ {
477
+ id: 'edward',
478
+ label: 'Edward Cullen',
479
+ onClick: () => console.log('Navigate to Edward Cullen'),
480
+ children: [
481
+ { label: 'Year group', value: 'Year 12' },
482
+ { label: 'Form', value: '12C' },
483
+ { label: 'Attendance', value: '100%' },
484
+ ],
485
+ },
486
+ {
487
+ id: 'bella',
488
+ label: 'Bella Swan',
489
+ onClick: () => console.log('Navigate to Bella Swan'),
490
+ children: [
491
+ { label: 'Year group', value: 'Year 12' },
492
+ { label: 'Form', value: '12B' },
493
+ { label: 'Attendance', value: '97.4%' },
494
+ ],
495
+ },
496
+ {
497
+ id: 'jacob',
498
+ label: 'Jacob Black',
499
+ onClick: () => console.log('Navigate to Jacob Black'),
500
+ children: [
501
+ { label: 'Year group', value: 'Year 11' },
502
+ { label: 'Form', value: '11J' },
503
+ { label: 'Attendance', value: '88.2%' },
504
+ ],
505
+ },
506
+ ] })),
507
+ };
508
+ // ---------------------------------------------------------------------------
509
+ // ClickableRows — data-driven leaf rows with onClick
510
+ // ---------------------------------------------------------------------------
511
+ export const ClickableRows = {
512
+ parameters: {
513
+ docs: {
514
+ description: {
515
+ story: 'Leaf rows (items without `children`) can also be clickable. Provide an `onClick` on the `TreeRowItem` and it is forwarded to the underlying `Row` component. Useful for navigating to a pupil record, opening a document, or triggering an action inline.',
516
+ },
517
+ source: {
518
+ code: `
519
+ import { TreeRow } from '@arbor-education/design-system.components';
520
+
521
+ function TreeRowClickableRowsExample() {
522
+ return (
523
+ <TreeRow
524
+ defaultValue={['contacts']}
525
+ items={[
526
+ {
527
+ id: 'contacts',
528
+ label: 'Emergency Contacts — Bella Swan',
529
+ children: [
530
+ {
531
+ label: 'Charlie Swan',
532
+ value: 'Father',
533
+ note: '07700 900123',
534
+ onClick: () => console.log('Open Charlie Swan'),
535
+ },
536
+ {
537
+ label: 'Renée Dwyer',
538
+ value: 'Mother',
539
+ note: '07700 900456',
540
+ onClick: () => console.log('Open Renée Dwyer'),
541
+ },
542
+ {
543
+ label: 'Jacob Black',
544
+ value: 'Family friend',
545
+ note: '07700 900789',
546
+ onClick: () => console.log('Open Jacob Black'),
547
+ },
548
+ ],
549
+ },
550
+ ]}
551
+ />
552
+ );
553
+ }
554
+
555
+ export default TreeRowClickableRowsExample;
556
+ `.trim(),
557
+ },
558
+ },
559
+ },
560
+ render: () => (_jsx(TreeRow, { defaultValue: ['contacts'], items: [
561
+ {
562
+ id: 'contacts',
563
+ label: 'Emergency Contacts — Bella Swan',
564
+ children: [
565
+ {
566
+ label: 'Charlie Swan',
567
+ value: 'Father',
568
+ note: '07700 900123',
569
+ onClick: () => console.log('Open Charlie Swan'),
570
+ },
571
+ {
572
+ label: 'Renée Dwyer',
573
+ value: 'Mother',
574
+ note: '07700 900456',
575
+ onClick: () => console.log('Open Renée Dwyer'),
576
+ },
577
+ {
578
+ label: 'Jacob Black',
579
+ value: 'Family friend',
580
+ note: '07700 900789',
581
+ onClick: () => console.log('Open Jacob Black'),
582
+ },
583
+ ],
584
+ },
585
+ ] })),
586
+ };
587
+ // ---------------------------------------------------------------------------
588
+ // MixedClickability — some sections clickable, some not
589
+ // ---------------------------------------------------------------------------
590
+ export const MixedClickability = {
591
+ parameters: {
592
+ docs: {
593
+ description: {
594
+ story: 'The navigation caret only appears on sections that have an `onClick` prop. Sections without one look and behave like plain collapsible groups — a common pattern where some summary rows navigate to a detail view while others are purely informational.',
595
+ },
596
+ source: {
597
+ code: `
598
+ import { TreeRow } from '@arbor-education/design-system.components';
599
+
600
+ function TreeRowMixedClickabilityExample() {
601
+ return (
602
+ <TreeRow
603
+ defaultValue={['cullen-family', 'quileute-tribe']}
604
+ items={[
605
+ {
606
+ id: 'cullen-family',
607
+ label: 'Cullen Family',
608
+ onClick: () => console.log('Navigate to Cullen Family group'),
609
+ children: [
610
+ { label: 'Edward Cullen', value: 'Year 12' },
611
+ { label: 'Alice Cullen', value: 'Year 12' },
612
+ { label: 'Rosalie Hale', value: 'Year 12' },
613
+ { label: 'Emmett Cullen', value: 'Year 12' },
614
+ ],
615
+ },
616
+ {
617
+ id: 'school-info',
618
+ label: 'School Information',
619
+ children: [
620
+ { label: 'School', value: 'Forks High School' },
621
+ { label: 'LA', value: 'Clallam County' },
622
+ { label: 'Ofsted rating', value: 'Outstanding' },
623
+ ],
624
+ },
625
+ {
626
+ id: 'quileute-tribe',
627
+ label: 'Quileute Tribe (La Push)',
628
+ onClick: () => console.log('Navigate to Quileute Tribe group'),
629
+ children: [
630
+ { label: 'Jacob Black', value: 'Year 11' },
631
+ { label: 'Embry Call', value: 'Year 11' },
632
+ { label: 'Quil Ateara', value: 'Year 11' },
633
+ ],
634
+ },
635
+ ]}
636
+ />
637
+ );
638
+ }
639
+
640
+ export default TreeRowMixedClickabilityExample;
641
+ `.trim(),
642
+ },
643
+ },
644
+ },
645
+ render: () => (_jsx(TreeRow, { defaultValue: ['cullen-family', 'quileute-tribe'], items: [
646
+ {
647
+ id: 'cullen-family',
648
+ label: 'Cullen Family',
649
+ onClick: () => console.log('Navigate to Cullen Family group'),
650
+ children: [
651
+ { label: 'Edward Cullen', value: 'Year 12' },
652
+ { label: 'Alice Cullen', value: 'Year 12' },
653
+ { label: 'Rosalie Hale', value: 'Year 12' },
654
+ { label: 'Emmett Cullen', value: 'Year 12' },
655
+ ],
656
+ },
657
+ {
658
+ id: 'school-info',
659
+ label: 'School Information',
660
+ children: [
661
+ { label: 'School', value: 'Forks High School' },
662
+ { label: 'LA', value: 'Clallam County' },
663
+ { label: 'Ofsted rating', value: 'Outstanding' },
664
+ ],
665
+ },
666
+ {
667
+ id: 'quileute-tribe',
668
+ label: 'Quileute Tribe (La Push)',
669
+ onClick: () => console.log('Navigate to Quileute Tribe group'),
670
+ children: [
671
+ { label: 'Jacob Black', value: 'Year 11' },
672
+ { label: 'Embry Call', value: 'Year 11' },
673
+ { label: 'Quil Ateara', value: 'Year 11' },
674
+ ],
675
+ },
676
+ ] })),
677
+ };
678
+ // ---------------------------------------------------------------------------
679
+ // WithClickFeedback — interactive useState story
680
+ // ---------------------------------------------------------------------------
681
+ function WithClickFeedbackExample() {
682
+ const [lastClicked, setLastClicked] = useState(null);
683
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 'var(--spacing-small)' }, children: [_jsx(TreeRow, { defaultValue: ['timetable'], items: [
684
+ {
685
+ id: 'timetable',
686
+ label: 'Timetable — Jacob Black',
687
+ onClick: () => setLastClicked('Timetable — Jacob Black'),
688
+ children: [
689
+ {
690
+ id: 'monday',
691
+ label: 'Monday',
692
+ onClick: () => setLastClicked('Monday'),
693
+ children: [
694
+ { label: 'Period 1', value: 'English', note: 'Room A12 · Ms Swan', onClick: () => setLastClicked('Period 1 — English') },
695
+ { label: 'Period 2', value: 'Biology', note: 'Lab 3 · Dr Cullen', onClick: () => setLastClicked('Period 2 — Biology') },
696
+ { label: 'Period 3', value: 'PE', note: 'Sports Hall · Mr Black', onClick: () => setLastClicked('Period 3 — PE') },
697
+ ],
698
+ },
699
+ {
700
+ id: 'tuesday',
701
+ label: 'Tuesday',
702
+ onClick: () => setLastClicked('Tuesday'),
703
+ children: [
704
+ { label: 'Period 1', value: 'Maths', note: 'Room B4 · Mrs Clearwater', onClick: () => setLastClicked('Period 1 — Maths') },
705
+ { label: 'Period 2', value: 'Art', note: 'Studio · Ms Hale', onClick: () => setLastClicked('Period 2 — Art') },
706
+ ],
707
+ },
708
+ ],
709
+ },
710
+ ] }), _jsx("p", { className: "ds-text", style: { color: 'var(--color-grey-600)' }, children: lastClicked ? `Last clicked: "${lastClicked}"` : 'Click any section or row above.' })] }));
711
+ }
712
+ export const WithClickFeedback = {
713
+ parameters: {
714
+ docs: {
715
+ description: {
716
+ story: 'A fully interactive example demonstrating how both section `onClick` and row `onClick` work together in the same tree. Each click is independent — expanding a section does not fire `onClick`, and clicking a row does not toggle any section. Open the "Monday" or "Tuesday" sections, then click any row or section header to see the feedback update.',
717
+ },
718
+ source: {
719
+ code: `
720
+ import { useState } from 'react';
721
+ import { TreeRow } from '@arbor-education/design-system.components';
722
+
723
+ function TreeRowWithClickFeedbackExample() {
724
+ const [lastClicked, setLastClicked] = useState<string | null>(null);
725
+
726
+ return (
727
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-small)' }}>
728
+ <TreeRow
729
+ defaultValue={['timetable']}
730
+ items={[
731
+ {
732
+ id: 'timetable',
733
+ label: 'Timetable — Jacob Black',
734
+ onClick: () => setLastClicked('Timetable — Jacob Black'),
735
+ children: [
736
+ {
737
+ id: 'monday',
738
+ label: 'Monday',
739
+ onClick: () => setLastClicked('Monday'),
740
+ children: [
741
+ { label: 'Period 1', value: 'English', note: 'Room A12 · Ms Swan', onClick: () => setLastClicked('Period 1 — English') },
742
+ { label: 'Period 2', value: 'Biology', note: 'Lab 3 · Dr Cullen', onClick: () => setLastClicked('Period 2 — Biology') },
743
+ { label: 'Period 3', value: 'PE', note: 'Sports Hall · Mr Black', onClick: () => setLastClicked('Period 3 — PE') },
744
+ ],
745
+ },
746
+ {
747
+ id: 'tuesday',
748
+ label: 'Tuesday',
749
+ onClick: () => setLastClicked('Tuesday'),
750
+ children: [
751
+ { label: 'Period 1', value: 'Maths', note: 'Room B4 · Mrs Clearwater', onClick: () => setLastClicked('Period 1 — Maths') },
752
+ { label: 'Period 2', value: 'Art', note: 'Studio · Ms Hale', onClick: () => setLastClicked('Period 2 — Art') },
753
+ ],
754
+ },
755
+ ],
756
+ },
757
+ ]}
758
+ />
759
+
760
+ <p className="ds-text" style={{ color: 'var(--color-grey-600)' }}>
761
+ {lastClicked ? \`Last clicked: "\${lastClicked}"\` : 'Click any section or row above.'}
762
+ </p>
763
+ </div>
764
+ );
765
+ }
766
+
767
+ export default TreeRowWithClickFeedbackExample;
768
+ `.trim(),
769
+ },
770
+ },
771
+ },
772
+ render: () => _jsx(WithClickFeedbackExample, {}),
773
+ };
774
+ //# sourceMappingURL=TreeRow.stories.js.map