@acronis-platform/ui-react 5.0.0 → 5.1.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 (65) hide show
  1. package/dist/components/ui/area-chart/area-chart.js +191 -85
  2. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  3. package/dist/components/ui/bar-chart/bar-chart.js +288 -225
  4. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  5. package/dist/components/ui/card-widget-carousel/card-widget-carousel.js +85 -0
  6. package/dist/components/ui/card-widget-carousel/card-widget-carousel.js.map +1 -0
  7. package/dist/components/ui/card-widget-carousel/card-widget.js +82 -0
  8. package/dist/components/ui/card-widget-carousel/card-widget.js.map +1 -0
  9. package/dist/components/ui/category-bar/category-bar.js.map +1 -1
  10. package/dist/components/ui/chart/chart-format.js +25 -22
  11. package/dist/components/ui/chart/chart-format.js.map +1 -1
  12. package/dist/components/ui/chart/chart-palette.js +9 -8
  13. package/dist/components/ui/chart/chart-palette.js.map +1 -1
  14. package/dist/components/ui/chart/chart.js +118 -83
  15. package/dist/components/ui/chart/chart.js.map +1 -1
  16. package/dist/components/ui/line-chart/line-chart.js +194 -86
  17. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  18. package/dist/components/ui/scatter-chart/scatter-chart.js +5 -2
  19. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  20. package/dist/components/ui/separator/separator.js +52 -10
  21. package/dist/components/ui/separator/separator.js.map +1 -1
  22. package/dist/components/ui/sidebar-secondary/sidebar-secondary.js +144 -121
  23. package/dist/components/ui/sidebar-secondary/sidebar-secondary.js.map +1 -1
  24. package/dist/components/ui/tree-item/tree-item.js +67 -0
  25. package/dist/components/ui/tree-item/tree-item.js.map +1 -0
  26. package/dist/components/ui/treemap/treemap.js +73 -66
  27. package/dist/components/ui/treemap/treemap.js.map +1 -1
  28. package/dist/index.js +109 -107
  29. package/dist/llms/area-chart.md +2 -1
  30. package/dist/llms/bar-chart.md +132 -33
  31. package/dist/llms/card-widget-carousel.md +252 -0
  32. package/dist/llms/category-bar.md +2 -2
  33. package/dist/llms/line-chart.md +2 -1
  34. package/dist/llms/metric.md +10 -5
  35. package/dist/llms/scatter-chart.md +2 -1
  36. package/dist/llms/separator.md +27 -8
  37. package/dist/llms/sidebar-secondary.md +235 -4
  38. package/dist/llms/tree-item.md +359 -0
  39. package/dist/llms/treemap.md +47 -36
  40. package/dist/llms.txt +4 -3
  41. package/dist/react.js +109 -107
  42. package/dist/src/components/ui/area-chart/area-chart.d.ts +10 -0
  43. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +75 -10
  44. package/dist/src/components/ui/bar-chart/bar-chart.docs.d.ts +146 -0
  45. package/dist/src/components/ui/bar-chart/index.d.ts +1 -1
  46. package/dist/src/components/ui/card-widget-carousel/card-widget-carousel.d.ts +9 -0
  47. package/dist/src/components/ui/card-widget-carousel/card-widget.d.ts +43 -0
  48. package/dist/src/components/ui/card-widget-carousel/index.d.ts +2 -0
  49. package/dist/src/components/ui/chart/chart-format.d.ts +9 -1
  50. package/dist/src/components/ui/chart/chart-palette.d.ts +38 -10
  51. package/dist/src/components/ui/chart/index.d.ts +2 -2
  52. package/dist/src/components/ui/line-chart/line-chart.d.ts +11 -1
  53. package/dist/src/components/ui/separator/separator.d.ts +9 -1
  54. package/dist/src/components/ui/sidebar-secondary/sidebar-secondary.d.ts +23 -3
  55. package/dist/src/components/ui/tree-item/index.d.ts +1 -0
  56. package/dist/src/components/ui/tree-item/tree-item.d.ts +64 -0
  57. package/dist/src/components/ui/treemap/treemap.d.ts +16 -5
  58. package/dist/src/index.d.ts +2 -1
  59. package/dist/ui-react.css +1 -1
  60. package/package.json +3 -3
  61. package/dist/components/ui/meter/meter.js +0 -79
  62. package/dist/components/ui/meter/meter.js.map +0 -1
  63. package/dist/llms/meter.md +0 -177
  64. package/dist/src/components/ui/meter/index.d.ts +0 -1
  65. package/dist/src/components/ui/meter/meter.d.ts +0 -25
@@ -2,7 +2,7 @@
2
2
 
3
3
  > A thin rule that visually and semantically divides content. Built on the Base UI Separator primitive (sets the `separator` role + aria-orientation). Ported from the legacy shadcn-uikit `Separator`; uses the shared divider token.
4
4
 
5
- **Status:** draft · **Category:** layout · **Since:** v0.15.0
5
+ **Status:** ready · **Category:** layout · **Since:** v0.15.0
6
6
 
7
7
  ## Import
8
8
 
@@ -15,14 +15,15 @@ import { Separator } from '@acronis-platform/ui-react'
15
15
  ```tsx
16
16
  <Separator className="my-4" />
17
17
  <Separator orientation="vertical" />
18
+ <Separator size="S2" />
18
19
  ```
19
20
 
20
21
  A thin rule that divides content, horizontally or vertically.
21
22
 
22
- > **Status: draft (design-pending v1).** Ported from the legacy
23
- > `@acronis-platform/shadcn-uikit` `Separator`; uses the shared `bg-border`
24
- > divider token (no `--ui-separator-*` tier). Reconcile with
25
- > `/figma-component Separator <url> --update` once a mockup lands.
23
+ > Ported from the legacy `@acronis-platform/shadcn-uikit` `Separator`; matched
24
+ > to Figma's `DividerHorizontal` component set (node 788:15147). Uses the
25
+ > shared `--ui-border-on-surface-divider` token directly (no `--ui-separator-*`
26
+ > tier).
26
27
 
27
28
  ## When to use
28
29
 
@@ -46,6 +47,9 @@ import { Separator } from '@acronis-platform/ui-react';
46
47
  <Separator orientation="vertical" />
47
48
  <span>Recovery</span>
48
49
  </div>
50
+
51
+ {/* size (S1/S2/S3, Figma default S1) applies built-in surrounding spacing */}
52
+ <Separator size="S2" />
49
53
  ```
50
54
 
51
55
  ## Props
@@ -53,11 +57,12 @@ import { Separator } from '@acronis-platform/ui-react';
53
57
  | Prop | Type | Default | Required | Description |
54
58
  |------|------|---------|----------|-------------|
55
59
  | `orientation` | `'horizontal' | 'vertical'` | `'horizontal'` | no | Direction of the rule; sets aria-orientation and swaps the 1px dimension. |
60
+ | `size` | `'S1' | 'S2' | 'S3'` | `'S1'` | no | Surrounding spacing baked into the rule (Figma variant `Size`). `S1` (default) has none; `S2`/`S3` apply `--ui-gap-4`/`--ui-gap-8` as margin on the axis perpendicular to the line. |
56
61
 
57
62
  ## Behavior
58
63
 
59
- Separator is a static divider. It has no props beyond `orientation`, no state,
60
- and no interaction.
64
+ Separator is a static divider. It has no state and no interaction; its only
65
+ props are `orientation` and `size`.
61
66
 
62
67
  ```gherkin
63
68
  Scenario: Horizontal rule (default)
@@ -72,6 +77,20 @@ Scenario: Vertical rule
72
77
  And it needs a sized (height-bearing) flex/inline context to be visible
73
78
  ```
74
79
 
80
+ ```gherkin
81
+ Scenario: Default size has no built-in spacing
82
+ Given a Separator with no size
83
+ Then it renders with size="S1" and applies no surrounding margin
84
+ ```
85
+
86
+ ```gherkin
87
+ Scenario: S2/S3 apply built-in surrounding spacing
88
+ Given a Separator with size="S2" or size="S3"
89
+ Then it applies --ui-gap-4 or --ui-gap-8 as margin on the axis
90
+ perpendicular to the rule (vertical margin for horizontal, horizontal
91
+ margin for vertical)
92
+ ```
93
+
75
94
  ## Accessibility
76
95
 
77
96
  - Renders `role="separator"` (Base UI), with `aria-orientation` reflecting the
@@ -83,5 +102,5 @@ Scenario: Vertical rule
83
102
 
84
103
  ## Contrast
85
104
 
86
- The line uses `--ui-border-on-surface-border`, which meets non-text contrast
105
+ The line uses `--ui-border-on-surface-divider`, which meets non-text contrast
87
106
  against the page surface in light and dark themes.
@@ -67,7 +67,7 @@ breadcrumb rail.
67
67
  | `SidebarSecondaryMenuSubContent` | `Collapsible.Panel` `<div><ul>` | Level-2 child list |
68
68
  | `SidebarSecondaryMenuSubItem` | `<li><a>` | Level-2 indented leaf |
69
69
  | `SidebarSecondaryMenuItemExtras` | `<span>` | Trailing shortcut / external-link / tag |
70
- | `SidebarSecondaryCollapseTrigger` | `<li><button>` | Footer "Collapse menu" button; toggles `expanded` |
70
+ | `SidebarSecondaryCollapseTrigger` | `<li><button>` | Footer "Collapse menu" button; toggles `expanded` (`disabled` when not collapsible) |
71
71
 
72
72
  ## Quick Examples
73
73
 
@@ -149,6 +149,44 @@ Author both the `SidebarSecondaryContent` (section list) and the
149
149
  `expanded` state via CSS — both stay in the DOM, so the breadcrumb is
150
150
  SSR-present and no JS branch is needed.
151
151
 
152
+ ## Locking the collapse state
153
+
154
+ `collapsible` defaults to `true`. Pass `collapsible={false}` when the surface
155
+ must not let the user change the panel's expanded/collapsed state. It locks that
156
+ toggle only — **not the width**, which the user can still change by dragging or
157
+ Arrow-shrinking while the panel is expanded. `resizable={false}` is what locks
158
+ the width value itself; the two props are independent and compose:
159
+
160
+ ```tsx
161
+ <SidebarSecondary collapsible={false}>{/* … */}</SidebarSecondary>
162
+ ```
163
+
164
+ - Every user-initiated collapse/expand path is blocked — resize-edge click,
165
+ double-click-to-expand, drag past the collapse threshold, the resize edge's
166
+ Arrow/Enter/Space/Home keys, and the footer
167
+ `SidebarSecondaryCollapseTrigger` (which renders natively `disabled` and
168
+ shows no `expandTooltip`).
169
+ - **Resizing still works while the panel is expanded.** A drag or Arrow-shrink
170
+ that would have collapsed the panel clamps to the minimum width instead. Pass
171
+ `resizable={false}` as well to lock the width outright.
172
+ - It does **not** force `expanded`. `collapsible={false}` with
173
+ `defaultExpanded={false}` is valid and renders a permanently collapsed rail; a
174
+ controlled `expanded` prop still has full authority. On that permanently
175
+ collapsed rail the resize edge stays focusable and keeps its accessible name,
176
+ but it is inert — drag, click and the Arrow keys do nothing observable, and
177
+ only `Home` (or a double-click) still writes the default width, invisibly.
178
+ - Every tooltip is adjusted for you, so the copy never advertises an inert
179
+ gesture. The footer collapse trigger's `expandTooltip` is suppressed outright
180
+ (a disabled control cannot expand anything; an explicit value does not bring
181
+ it back). The two resize-edge defaults narrow: **Expanded**, the default drops
182
+ the
183
+ "Collapse: Click" line and reads "Resize: Drag" / "Reset size: Double click".
184
+ **Collapsed**, the default narrows to "Reset size: Double click" alone —
185
+ dragging and clicking a permanently collapsed rail do nothing, but a
186
+ double-click still resets the width. An explicit `resizeTooltipExpanded` /
187
+ `resizeTooltipCollapsed` value always wins, including `null` to suppress the
188
+ tooltip entirely.
189
+
152
190
  ## Spec Files
153
191
 
154
192
  | File | Contents |
@@ -177,10 +215,11 @@ SSR-present and no JS branch is needed.
177
215
  | `actions` | `ReactNode` | `undefined` | no | Trailing header actions on the section-label (e.g. a ghost ButtonIcon), rendered outside the toggle so they stay independently operable. |
178
216
  | `unreadRollup` | `ReactNode` | `undefined` | no | A rollup badge (e.g. a Tag with an unread count) shown in an expandable section's header only while it is collapsed. |
179
217
  | `resizable` | `boolean` | `true` | no | Enable the draggable resize edge on the right border. When `true`, the sidebar can be resized between the expanded-width token and twice that value. |
218
+ | `collapsible` | `boolean` | `true` | no | Allow the user to collapse/expand the panel (resize-edge click, drag past the collapse threshold, keyboard, and the footer collapse trigger). When `false` those interactions never change `expanded` and the footer collapse trigger renders natively disabled with no `aria-expanded`; while the panel is expanded, dragging still resizes it, clamped to the minimum width. Independent of `expanded` — pair it with `defaultExpanded: false` for a permanently collapsed rail, on which the resize edge stays focusable but is inert apart from the (invisible) width reset, which `Home` and a double-click on the edge both still perform. |
180
219
  | `resizeAriaLabel` | `string` | `'Resize sidebar'` | no | Accessible label for the resize edge (`role="separator"`). Consumers should localize this string for i18n. |
181
- | `resizeTooltipExpanded` | `ReactNode` | `(English tooltip: Resize/Collapse/Reset)` | no | Tooltip content shown when the sidebar is expanded. Pass `null` to hide the tooltip entirely. Consumers should localize for i18n. |
182
- | `resizeTooltipCollapsed` | `ReactNode` | `(English tooltip: Resize/Expand)` | no | Tooltip content shown when the sidebar is collapsed. Pass `null` to hide the tooltip entirely. Consumers should localize for i18n. |
183
- | `expandTooltip` | `ReactNode` | `'Expand'` | no | Tooltip text shown on the collapse trigger when the sidebar is collapsed. Consumers should localize this string for i18n. |
220
+ | `resizeTooltipExpanded` | `ReactNode` | `(English tooltip: Resize/Collapse/Reset; Resize/Reset when not collapsible)` | no | Tooltip content shown when the sidebar is expanded. The default depends on `collapsible`: with `collapsible: false` it drops the "Collapse: Click" line, since clicking the edge can no longer collapse the panel. Pass `null` to hide the tooltip entirely. Consumers should localize for i18n. |
221
+ | `resizeTooltipCollapsed` | `ReactNode` | `(English tooltip: Resize/Expand; 'Reset size: Double click' only when not collapsible)` | no | Tooltip content shown when the sidebar is collapsed. The default depends on `collapsible`: with `collapsible: false` it narrows to the single "Reset size: Double click" line, because dragging and clicking a permanently collapsed rail have no effect while a double-click still resets the width. Pass `null` to hide the tooltip entirely, or an explicit node to replace it. Consumers should localize for i18n. |
222
+ | `expandTooltip` | `ReactNode` | `'Expand'` | no | Tooltip text shown on the collapse trigger when the sidebar is collapsed. Suppressed entirely with `collapsible: false` — the trigger is disabled then, so the copy would advertise an action that cannot run. An explicit value does not override that suppression. Consumers should localize this string for i18n. |
184
223
  | `extras-variant` | `'tag' | 'externalLink' | 'shortcut' | 'tag-externalLink'` | — | yes | Which trailing affordance the extras part renders. React: the `variant` prop on `SidebarSecondaryMenuItemExtras`. (Named here without the bare `variant` key reserved for a root cva axis.) |
185
224
  | `shortcut` | `string` | `undefined` | no | Keyboard-shortcut text for the extras `shortcut` variant. |
186
225
  | `tag` | `ReactNode` | `undefined` | no | Tag content for the extras `tag` / `tag-externalLink` variants. |
@@ -256,6 +295,111 @@ SSR-present and no JS branch is needed.
256
295
  > DOM; visibility is toggled purely by `data-[state]` selectors (SSR-safe, no JS
257
296
  > branch).
258
297
 
298
+ #### `collapsible={false}` blocks every user collapse/expand path
299
+
300
+ **Given** a SidebarSecondary with `collapsible={false}`
301
+ **When** the user clicks the resize edge, double-clicks it while collapsed,
302
+ drags it past the collapse threshold, presses the shrink Arrow at the minimum
303
+ width, presses the grow Arrow while collapsed, presses Enter/Space on the resize
304
+ edge, presses Home while collapsed, or activates the footer
305
+ `SidebarSecondaryCollapseTrigger`
306
+ **Then** `expanded` never changes and `data-state` stays as it was
307
+ **And** the footer collapse trigger renders natively `disabled`
308
+
309
+ > **The width reset is not inert while collapsed.** Blocking the expand does not
310
+ > block the width reset: on the resize edge of a `collapsible={false}`, collapsed
311
+ > panel, **`Home` and a double-click** both still reset the stored width to
312
+ > `defaultWidth` — neither write is gated on `collapsible` (in
313
+ > `handleDoubleClick`, only its `toggleExpanded()` call is). `onWidthChange`
314
+ > fires **only when `defaultWidth` differs from the current stored width**:
315
+ > `setWidth` returns early on `next === currentWidth`, so a width write that
316
+ > resolves to the current value is a no-op, and on a panel whose width has never
317
+ > moved these two gestures emit nothing. When the width _has_ moved, nothing
318
+ > changes visually at that moment (the rail stays collapsed), but a
319
+ > controlled consumer observes the new width, and it takes effect the moment the
320
+ > panel is expanded by other means (a controlled `expanded` prop). Every _other_
321
+ > expand-triggering gesture — a single click, a drag, the grow Arrow, Enter/Space
322
+ > — is genuinely inert in that state.
323
+
324
+ #### A disabled collapse trigger looks inert
325
+
326
+ **Given** a SidebarSecondary with `collapsible={false}` (or an explicitly
327
+ `disabled` `SidebarSecondaryCollapseTrigger`)
328
+ **When** the footer collapse trigger renders
329
+ **Then** it shows a `not-allowed` cursor instead of the pointer cursor
330
+ **And** its label and icon use the disabled on-surface foreground token
331
+ **And** hovering or pressing it produces no highlight — the hover and active
332
+ fills stay pinned to the row's idle container color
333
+ **And** this is in addition to the native `disabled` attribute above, so the
334
+ row reads as visually inert exactly where it is functionally inert
335
+
336
+ #### Resizing stays live and clamps at the minimum
337
+
338
+ **Given** an expanded, `resizable` SidebarSecondary with `collapsible={false}`
339
+ **When** the user drags the resize edge below the collapse threshold, or presses
340
+ the shrink Arrow so the next step would fall under `minWidth`
341
+ **Then** the width clamps to `minWidth` (the expanded-width token's shipped
342
+ default, 256px) instead of collapsing
343
+ **And** drag/Arrow resizing between `minWidth` and `maxWidth` behaves exactly as
344
+ it does when `collapsible` is `true`
345
+
346
+ #### A permanently collapsed rail is a valid combination
347
+
348
+ **Given** `collapsible={false}` together with `defaultExpanded={false}`
349
+ **When** the panel renders
350
+ **Then** it renders as the collapsed breadcrumb rail (`data-state="collapsed"`)
351
+ **And** no user interaction can expand it — only a controlled `expanded` prop can
352
+ **And** the resize edge stays focusable and keeps its accessible name, but is
353
+ inert: dragging it, clicking it, and the grow/shrink Arrow keys produce no
354
+ observable change
355
+ **And** the one exception is the width reset — `Home` **and** a double-click on
356
+ the edge both still write `defaultWidth` while the rail stays visually
357
+ unchanged, firing `onWidthChange` only when `defaultWidth` differs from the
358
+ current stored width (see the width-reset note above)
359
+
360
+ > `collapsible` never forces `expanded` to a value; it only gates the
361
+ > user-initiated transitions. A controlled `expanded` prop keeps full authority
362
+ > either way.
363
+
364
+ #### The expanded default tooltip drops the click gesture
365
+
366
+ **Given** `collapsible={false}`, an **expanded** panel, and no
367
+ `resizeTooltipExpanded` override
368
+ **When** the user hovers the resize edge
369
+ **Then** the tooltip reads "**Resize:** Drag" and "**Reset size:** Double click"
370
+ — the "**Collapse:** Click" line the `collapsible={true}` default carries is
371
+ omitted, because clicking the edge can no longer collapse the panel
372
+ **And** an explicit `resizeTooltipExpanded` value still wins, including `null`
373
+ to suppress the tooltip
374
+
375
+ #### A permanently collapsed rail's tooltip advertises only the double-click
376
+
377
+ **Given** `collapsible={false}`, a **collapsed** panel, and no
378
+ `resizeTooltipCollapsed` override
379
+ **When** the user hovers the resize edge
380
+ **Then** the tooltip reads "**Reset size:** Double click" — and nothing else
381
+ **And** the other two lines the `collapsible={true}` collapsed default carries
382
+ are dropped, because neither gesture is live: clicking the edge bails in
383
+ `handleClick`, and the collapsed drag branch only ever calls `toggleExpanded()`
384
+ (itself gated off) and never writes a width, so both "**Resize:** Drag" and
385
+ "**Expand:** Click" would be false claims
386
+ **And** the double-click line _is_ honest: `handleDoubleClick` writes
387
+ `defaultWidth` unconditionally, so it stays a live pointer gesture — the pointer
388
+ counterpart of `Home`
389
+ **And** an explicit `resizeTooltipCollapsed` value still wins, including `null`
390
+ to suppress the tooltip entirely
391
+
392
+ #### The collapse trigger shows no tooltip at all
393
+
394
+ **Given** `collapsible={false}` and a footer `SidebarSecondaryCollapseTrigger`
395
+ **When** the user hovers or focuses that trigger while the panel is collapsed
396
+ **Then** no tooltip appears — the trigger's own `Tooltip` is disabled whenever
397
+ the panel is expanded **or** not collapsible
398
+ **And** this holds even when an explicit `expandTooltip` value is passed, unlike
399
+ the two resize-edge tooltips where an override still wins: the trigger is
400
+ natively `disabled` here, so any "Expand" copy would advertise an action the
401
+ user cannot perform
402
+
259
403
  ---
260
404
 
261
405
  ### Disclosure (expandable sections)
@@ -360,6 +504,33 @@ When collapsed, the section list is hidden and a vertical breadcrumb is shown
360
504
  (`aria-hidden`). Any menu-item labels that remain are kept in the DOM as
361
505
  `sr-only`, never `display:none`.
362
506
 
507
+ ### Collapse trigger (footer)
508
+
509
+ `SidebarSecondaryCollapseTrigger` is a `<button>` that toggles the panel width.
510
+
511
+ | `collapsible` | Exposed as | `expandTooltip` while collapsed |
512
+ | ------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------- |
513
+ | `true` | `aria-expanded` mirrors the panel's `expanded` state; button enabled unless the consumer passes `disabled` | shown on hover/focus |
514
+ | `false` | **no** `aria-expanded`; button carries the native `disabled` | **suppressed** (no tooltip) |
515
+
516
+ When `collapsible` is `false` the button has no state to expose or flip, so
517
+ `aria-expanded` is omitted rather than pinned to a value a user cannot change,
518
+ and `disabled` communicates the unavailable action to assistive tech. Its
519
+ `expandTooltip` is suppressed for the same reason — under `collapsible={false}`
520
+ the panel can never be expanded by the user, so an "Expand" hint would be a
521
+ false affordance. (The tooltip is likewise suppressed whenever the panel is
522
+ expanded, in either mode: there is nothing to expand.)
523
+
524
+ The suppression keys off `collapsible`, not off the button's disabled state:
525
+ passing `disabled` directly to the trigger while `collapsible` is `true` still
526
+ disables the button, but the `expandTooltip` keeps showing on hover.
527
+
528
+ ### Resize edge
529
+
530
+ When `resizable`, the panel renders a focusable handle on its inline-end border
531
+ with `role="separator"`, `aria-orientation="vertical"`, `tabIndex={0}` and an
532
+ overridable `aria-label` (default `'Resize sidebar'`).
533
+
363
534
  ---
364
535
 
365
536
  ## Keyboard Navigation
@@ -374,6 +545,55 @@ When collapsed, the section list is hidden and a vertical breadcrumb is shown
374
545
  No roving tabindex — this is a list of links plus disclosure buttons, not a
375
546
  `menu`/`menubar`.
376
547
 
548
+ ### Resize edge (`role="separator"`)
549
+
550
+ Arrow keys follow the writing direction: the **grow** key is `ArrowRight` in LTR
551
+ and `ArrowLeft` in RTL; the **shrink** key is the mirror.
552
+
553
+ | Key | `collapsible: true` | `collapsible: false` |
554
+ | ----------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
555
+ | Grow key | Expanded: +16px. Collapsed: expands the panel | Expanded: +16px. Collapsed: **inert** |
556
+ | Shrink key | Expanded: −16px; below the minimum width it collapses the panel. Collapsed: **inert** | Expanded: −16px, **clamps at the minimum width**, never collapses. Collapsed: **inert** |
557
+ | Enter/Space | Toggles expanded/collapsed | **Inert** |
558
+ | Home | Expands (if collapsed) and resets to the default width | Resets to the default width; never expands |
559
+
560
+ With `collapsible={false}` the edge stays focusable and keeps its accessible
561
+ name. **While the panel is expanded**, resizing is still a real operation — only
562
+ the collapse transition is suppressed. **While the panel is permanently
563
+ collapsed** (`collapsible={false}` + collapsed) the edge is a focusable but
564
+ visually inert tab stop: it keeps its `role="separator"` and accessible name,
565
+ yet dragging, clicking, and both Arrow keys produce no observable change. Every
566
+ **expand-triggering** gesture is inert here: dragging, a single click, the grow
567
+ key and Enter/Space all fire no `toggleExpanded`, so `data-state` stays
568
+ `collapsed`. **Two gestures remain live** — `Home` on the keyboard and a
569
+ **double-click** on the edge. Both reset the stored width to `defaultWidth`, and
570
+ neither is gated on `collapsible` (in `handleDoubleClick`, only the
571
+ `toggleExpanded()` call is). They fire `onWidthChange` **only when
572
+ `defaultWidth` differs from the current stored width** — `setWidth` returns
573
+ early on `next === currentWidth`, so a width write that resolves to the current
574
+ value is a no-op, and on a panel whose width has never moved these two gestures
575
+ write nothing at all. When the width _has_ moved, the callback fires even though
576
+ the rail is collapsed and looks unchanged at that moment; the reset only becomes
577
+ visible if the panel is later expanded by other means (a controlled `expanded`
578
+ prop flip), so a controlled consumer that mirrors `onWidthChange` must expect a
579
+ width update while the panel is collapsed.
580
+
581
+ > **Tooltip copy.** With `collapsible={false}` every tooltip on the panel is
582
+ > adjusted for you, so the copy never advertises a gesture that is inert. The
583
+ > footer collapse trigger's own `expandTooltip` is **suppressed outright** —
584
+ > nothing can expand the panel, and an explicit value does not bring the
585
+ > tooltip back — and both resize-edge tooltip defaults narrow.
586
+ > **Expanded**, the resize-edge default drops the "**Collapse:** Click" line
587
+ > and reads "**Resize:** Drag" / "**Reset size:** Double click". **Collapsed**,
588
+ > the default
589
+ > narrows to the single line "**Reset size:** Double click" — dragging and
590
+ > clicking a permanently collapsed rail do nothing, but a double-click still
591
+ > writes the default width, so that is the one pointer gesture the tooltip can
592
+ > honestly advertise. An explicit `resizeTooltipExpanded` /
593
+ > `resizeTooltipCollapsed` value always wins over the default (including `null`
594
+ > to suppress the tooltip entirely), `collapsible` notwithstanding. All of these
595
+ > strings are English by default and must be localized regardless.
596
+
377
597
  ---
378
598
 
379
599
  ## Focus
@@ -415,3 +635,14 @@ A keyboard-focused row shows a visible focus ring using the shared
415
635
  - [ ] Disclosure trigger exposes `aria-expanded` / `aria-controls`; toggles on click + Enter/Space
416
636
  - [ ] Level-2 sub-items are indented and reachable via Tab when open
417
637
  - [ ] Collapsed rows keep an accessible name (sr-only label, not removed)
638
+ - [ ] Resize edge is `role="separator"`, focusable, and has an overridable `aria-label`
639
+ - [ ] With `collapsible={false}`: the footer collapse trigger is `disabled`,
640
+ exposes no `aria-expanded`, and shows **no Expand tooltip** on hover or
641
+ focus; Enter/Space on the resize edge does not change
642
+ `data-state`; the shrink key clamps at the minimum width
643
+ - [ ] With `collapsible={false}` while collapsed: Home **and a double-click on
644
+ the edge** leave `data-state` `collapsed` but still reset the stored width
645
+ (`onWidthChange` fires with `defaultWidth` only if that differs from the
646
+ current stored width)
647
+ - [ ] With `collapsible={false}` while collapsed: the default resize tooltip
648
+ reads "Reset size: Double click" only