@acronis-platform/ui-react 3.0.0 → 4.0.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 (219) hide show
  1. package/dist/components/ui/accordion-container/accordion-container.js +14 -14
  2. package/dist/components/ui/accordion-container/accordion-container.js.map +1 -1
  3. package/dist/components/ui/app-shell-chat/app-shell-chat.js.map +1 -1
  4. package/dist/components/ui/area-chart/area-chart.js +141 -139
  5. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  6. package/dist/components/ui/bar-chart/bar-chart.js +295 -293
  7. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  8. package/dist/components/ui/category-bar/category-bar.js +109 -93
  9. package/dist/components/ui/category-bar/category-bar.js.map +1 -1
  10. package/dist/components/ui/chart/chart-palette.js +113 -0
  11. package/dist/components/ui/chart/chart-palette.js.map +1 -0
  12. package/dist/components/ui/chart/chart.js +176 -129
  13. package/dist/components/ui/chart/chart.js.map +1 -1
  14. package/dist/components/ui/chart-state/chart-state-illustrations.js +310 -0
  15. package/dist/components/ui/chart-state/chart-state-illustrations.js.map +1 -0
  16. package/dist/components/ui/chart-state/chart-state.js +48 -34
  17. package/dist/components/ui/chart-state/chart-state.js.map +1 -1
  18. package/dist/components/ui/chart-widget/chart-widget.js +87 -0
  19. package/dist/components/ui/chart-widget/chart-widget.js.map +1 -0
  20. package/dist/components/ui/composed-chart/composed-chart.js +117 -115
  21. package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
  22. package/dist/components/ui/confidence-cone/confidence-cone.js +166 -158
  23. package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
  24. package/dist/components/ui/funnel-chart/funnel-chart.js +162 -161
  25. package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
  26. package/dist/components/ui/histogram/histogram.js +94 -92
  27. package/dist/components/ui/histogram/histogram.js.map +1 -1
  28. package/dist/components/ui/input/input.js.map +1 -1
  29. package/dist/components/ui/label/label.js +2 -9
  30. package/dist/components/ui/label/label.js.map +1 -1
  31. package/dist/components/ui/line-chart/line-chart.js +143 -141
  32. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  33. package/dist/components/ui/metric/metric.js +74 -185
  34. package/dist/components/ui/metric/metric.js.map +1 -1
  35. package/dist/components/ui/page-content/page-content.js.map +1 -1
  36. package/dist/components/ui/pie-chart/pie-chart.js +201 -195
  37. package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
  38. package/dist/components/ui/radar-chart/radar-chart.js +133 -131
  39. package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
  40. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +297 -265
  41. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
  42. package/dist/components/ui/sankey-chart/sankey-chart.js +123 -101
  43. package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -1
  44. package/dist/components/ui/scatter-chart/scatter-chart.js +76 -74
  45. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  46. package/dist/components/ui/section/section.js +157 -31
  47. package/dist/components/ui/section/section.js.map +1 -1
  48. package/dist/components/ui/stepper/stepper.js +24 -24
  49. package/dist/components/ui/stepper/stepper.js.map +1 -1
  50. package/dist/components/ui/stepper-item/stepper-item.js +43 -24
  51. package/dist/components/ui/stepper-item/stepper-item.js.map +1 -1
  52. package/dist/components/ui/treemap/treemap.js +133 -124
  53. package/dist/components/ui/treemap/treemap.js.map +1 -1
  54. package/dist/components/ui/trend-indicator/trend-indicator.js +34 -69
  55. package/dist/components/ui/trend-indicator/trend-indicator.js.map +1 -1
  56. package/dist/components/ui/wizard/wizard.js +59 -0
  57. package/dist/components/ui/wizard/wizard.js.map +1 -0
  58. package/dist/hooks/use-wizard.js +75 -0
  59. package/dist/hooks/use-wizard.js.map +1 -0
  60. package/dist/index.js +502 -497
  61. package/dist/index.js.map +1 -1
  62. package/dist/llms/accordion-container.md +181 -0
  63. package/dist/llms/accordion.md +124 -0
  64. package/dist/llms/alert.md +225 -0
  65. package/dist/llms/app-shell-chat.md +415 -0
  66. package/dist/llms/area-chart.md +355 -0
  67. package/dist/llms/avatar.md +208 -0
  68. package/dist/llms/bar-chart.md +406 -0
  69. package/dist/llms/breadcrumb.md +326 -0
  70. package/dist/llms/button-group.md +298 -0
  71. package/dist/llms/button-icon-input.md +142 -0
  72. package/dist/llms/button-icon-menu.md +209 -0
  73. package/dist/llms/button-icon.md +128 -0
  74. package/dist/llms/button-menu.md +172 -0
  75. package/dist/llms/button.md +185 -0
  76. package/dist/llms/calendar-panel.md +733 -0
  77. package/dist/llms/calendar.md +188 -0
  78. package/dist/llms/card-filter.md +214 -0
  79. package/dist/llms/card-section.md +293 -0
  80. package/dist/llms/card.md +447 -0
  81. package/dist/llms/carousel-dialog.md +156 -0
  82. package/dist/llms/category-bar.md +193 -0
  83. package/dist/llms/chart-state.md +190 -0
  84. package/dist/llms/chart-widget.md +209 -0
  85. package/dist/llms/chart.md +182 -0
  86. package/dist/llms/checkbox.md +257 -0
  87. package/dist/llms/chip.md +195 -0
  88. package/dist/llms/combobox.md +164 -0
  89. package/dist/llms/composed-chart.md +508 -0
  90. package/dist/llms/confidence-cone.md +277 -0
  91. package/dist/llms/data-table.md +474 -0
  92. package/dist/llms/date-range-picker.md +272 -0
  93. package/dist/llms/description-list.md +131 -0
  94. package/dist/llms/dialog-footer-carousel.md +147 -0
  95. package/dist/llms/dialog-footer-default.md +142 -0
  96. package/dist/llms/dialog-root.md +246 -0
  97. package/dist/llms/dialog-welcome.md +223 -0
  98. package/dist/llms/dialog.md +403 -0
  99. package/dist/llms/dropdown-menu.md +193 -0
  100. package/dist/llms/empty-overlay.md +146 -0
  101. package/dist/llms/empty.md +156 -0
  102. package/dist/llms/field.md +185 -0
  103. package/dist/llms/filter-cards.md +157 -0
  104. package/dist/llms/filter-chips.md +323 -0
  105. package/dist/llms/filter-search.md +512 -0
  106. package/dist/llms/form.md +154 -0
  107. package/dist/llms/funnel-chart.md +333 -0
  108. package/dist/llms/grid.md +80 -0
  109. package/dist/llms/histogram.md +190 -0
  110. package/dist/llms/input-date-picker.md +203 -0
  111. package/dist/llms/input-otp.md +173 -0
  112. package/dist/llms/input-password.md +197 -0
  113. package/dist/llms/input-search.md +170 -0
  114. package/dist/llms/input-select.md +278 -0
  115. package/dist/llms/input-text-area.md +271 -0
  116. package/dist/llms/input-text.md +192 -0
  117. package/dist/llms/line-chart.md +369 -0
  118. package/dist/llms/link.md +209 -0
  119. package/dist/llms/loading.md +130 -0
  120. package/dist/llms/meter.md +177 -0
  121. package/dist/llms/metric.md +204 -0
  122. package/dist/llms/number-field.md +122 -0
  123. package/dist/llms/page-content.md +69 -0
  124. package/dist/llms/page-header.md +182 -0
  125. package/dist/llms/pagination.md +133 -0
  126. package/dist/llms/pie-chart.md +307 -0
  127. package/dist/llms/popover.md +252 -0
  128. package/dist/llms/progress-circle.md +126 -0
  129. package/dist/llms/progress.md +111 -0
  130. package/dist/llms/radar-chart.md +316 -0
  131. package/dist/llms/radial-bar-chart.md +319 -0
  132. package/dist/llms/radio.md +255 -0
  133. package/dist/llms/resizable.md +195 -0
  134. package/dist/llms/sankey-chart.md +208 -0
  135. package/dist/llms/scatter-chart.md +239 -0
  136. package/dist/llms/scroll-area.md +183 -0
  137. package/dist/llms/section.md +401 -0
  138. package/dist/llms/select.md +210 -0
  139. package/dist/llms/separator.md +87 -0
  140. package/dist/llms/sheet.md +202 -0
  141. package/dist/llms/sidebar-primary.md +360 -0
  142. package/dist/llms/sidebar-secondary.md +417 -0
  143. package/dist/llms/skeleton.md +81 -0
  144. package/dist/llms/slider.md +97 -0
  145. package/dist/llms/spinner.md +100 -0
  146. package/dist/llms/stack.md +80 -0
  147. package/dist/llms/stepper-item.md +309 -0
  148. package/dist/llms/stepper.md +251 -0
  149. package/dist/llms/switch.md +140 -0
  150. package/dist/llms/table.md +436 -0
  151. package/dist/llms/tabs.md +197 -0
  152. package/dist/llms/tag.md +139 -0
  153. package/dist/llms/timeline.md +361 -0
  154. package/dist/llms/timer.md +259 -0
  155. package/dist/llms/toast.md +241 -0
  156. package/dist/llms/toggle-group.md +121 -0
  157. package/dist/llms/toolbar.md +453 -0
  158. package/dist/llms/tooltip.md +164 -0
  159. package/dist/llms/treemap.md +254 -0
  160. package/dist/llms/trend-indicator.md +132 -0
  161. package/dist/llms/widget-placeholder.md +169 -0
  162. package/dist/llms/wizard.md +412 -0
  163. package/dist/llms.txt +142 -0
  164. package/dist/react.js +502 -497
  165. package/dist/react.js.map +1 -1
  166. package/dist/src/components/ui/area-chart/area-chart.d.ts +9 -4
  167. package/dist/src/components/ui/avatar/avatar.d.ts +1 -1
  168. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +9 -4
  169. package/dist/src/components/ui/category-bar/category-bar.d.ts +10 -4
  170. package/dist/src/components/ui/chart/__stories__/palette-control.d.ts +48 -0
  171. package/dist/src/components/ui/chart/__tests__/chart-palette.test.d.ts +1 -0
  172. package/dist/src/components/ui/chart/chart-palette.d.ts +128 -0
  173. package/dist/src/components/ui/chart/chart.d.ts +66 -15
  174. package/dist/src/components/ui/chart/index.d.ts +4 -2
  175. package/dist/src/components/ui/chart-state/chart-state-illustrations.d.ts +6 -0
  176. package/dist/src/components/ui/chart-state/chart-state.d.ts +13 -2
  177. package/dist/src/components/ui/chart-state/index.d.ts +1 -0
  178. package/dist/src/components/ui/chart-widget/chart-widget.d.ts +64 -0
  179. package/dist/src/components/ui/chart-widget/index.d.ts +1 -0
  180. package/dist/src/components/ui/composed-chart/composed-chart.d.ts +12 -7
  181. package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +10 -5
  182. package/dist/src/components/ui/empty-overlay/empty-overlay.d.ts +1 -1
  183. package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +11 -5
  184. package/dist/src/components/ui/histogram/histogram.d.ts +10 -4
  185. package/dist/src/components/ui/label/index.d.ts +1 -1
  186. package/dist/src/components/ui/label/label.d.ts +1 -5
  187. package/dist/src/components/ui/line-chart/line-chart.d.ts +9 -4
  188. package/dist/src/components/ui/metric/metric.d.ts +13 -14
  189. package/dist/src/components/ui/pie-chart/pie-chart.d.ts +17 -8
  190. package/dist/src/components/ui/radar-chart/radar-chart.d.ts +10 -5
  191. package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +17 -6
  192. package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +10 -5
  193. package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +10 -5
  194. package/dist/src/components/ui/section/index.d.ts +1 -1
  195. package/dist/src/components/ui/section/section.d.ts +75 -6
  196. package/dist/src/components/ui/stepper-item/stepper-item.d.ts +6 -5
  197. package/dist/src/components/ui/tag/tag.d.ts +1 -1
  198. package/dist/src/components/ui/treemap/treemap.d.ts +11 -5
  199. package/dist/src/components/ui/trend-indicator/trend-indicator.d.ts +3 -7
  200. package/dist/src/components/ui/wizard/index.d.ts +1 -0
  201. package/dist/src/components/ui/wizard/wizard.d.ts +6 -0
  202. package/dist/src/hooks/index.d.ts +1 -0
  203. package/dist/src/hooks/use-wizard.d.ts +80 -0
  204. package/dist/src/index.d.ts +2 -3
  205. package/dist/ui-react.css +1 -1
  206. package/package.json +9 -3
  207. package/dist/components/ui/app-shell/app-shell.js +0 -75
  208. package/dist/components/ui/app-shell/app-shell.js.map +0 -1
  209. package/dist/components/ui/auth-layout/auth-layout.js +0 -56
  210. package/dist/components/ui/auth-layout/auth-layout.js.map +0 -1
  211. package/dist/components/ui/collapsible/collapsible.js +0 -22
  212. package/dist/components/ui/collapsible/collapsible.js.map +0 -1
  213. package/dist/src/components/ui/app-shell/app-shell.d.ts +0 -8
  214. package/dist/src/components/ui/app-shell/index.d.ts +0 -1
  215. package/dist/src/components/ui/auth-layout/auth-layout.d.ts +0 -6
  216. package/dist/src/components/ui/auth-layout/index.d.ts +0 -1
  217. package/dist/src/components/ui/collapsible/collapsible.d.ts +0 -5
  218. package/dist/src/components/ui/collapsible/index.d.ts +0 -1
  219. package/dist/src/components/ui/label/label.docs.d.ts +0 -10
@@ -0,0 +1,415 @@
1
+ # AppShellChat
2
+
3
+ > A 3-section, horizontally resizable application scaffold: a sidebar rail (SidebarPrimary, optionally SidebarSecondary) beside a Content page column and a Chat panel. Content and Chat resize against each other by dragging Chat's start border; the sidebars resize Content only (Chat keeps its explicit pixel width). Chat is resize-only: dragging down to its floor width shows an icon-only rail, and dragging up can take it to full width (Content shrinks to 0) since the resize ceiling is measured from the actual available row space. The Chat slot is optional, so the same scaffold also serves an ordinary two-column console screen.
4
+
5
+ **Status:** ready · **Category:** layout · **Since:** v0.57.0
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { AppShellChat, AppShellChatSidebar, AppShellChatContent, AppShellChatContentHeader, AppShellChatContentBody, AppShellChatChat, AppShellChatChatHeader, AppShellChatChatBody, useAppShellChatInitialLayout } from '@acronis-platform/ui-react'
11
+ ```
12
+
13
+ ## Quick example
14
+
15
+ ```tsx
16
+ // useAppShellChatInitialLayout() resolves ONCE at mount from the
17
+ // viewport width — wire it into the sidebars' `defaultExpanded`,
18
+ // since AppShellChatSidebar is a plain slot, not a fixed pairing
19
+ // AppShellChat owns. Chat's own responsive width needs no wiring.
20
+ const initialLayout = useAppShellChatInitialLayout();
21
+
22
+ <AppShellChat>
23
+ <AppShellChatSidebar>
24
+ <SidebarPrimary defaultExpanded={initialLayout.primaryExpanded}>…</SidebarPrimary>
25
+ <SidebarSecondary defaultExpanded={initialLayout.secondaryExpanded}>…</SidebarSecondary>
26
+ </AppShellChatSidebar>
27
+ <AppShellChatContent>
28
+ <AppShellChatContentHeader>Page header</AppShellChatContentHeader>
29
+ <AppShellChatContentBody>{children}</AppShellChatContentBody>
30
+ </AppShellChatContent>
31
+ <AppShellChatChat>
32
+ <AppShellChatChatHeader label="Acronis AI" />
33
+ <AppShellChatChatBody>{chat}</AppShellChatChatBody>
34
+ </AppShellChatChat>
35
+ </AppShellChat>
36
+ ```
37
+
38
+ A 3-section, horizontally resizable application scaffold: a sidebar rail beside a
39
+ Content page column and a Chat panel. Content and Chat resize against each other;
40
+ Chat is resize-only — drag it down to an icon-only rail or up to full width. The
41
+ Chat slot is optional, so the same scaffold also serves an ordinary two-column
42
+ console screen.
43
+
44
+ ## When to Use
45
+
46
+ - A product screen that pairs the main page content with a persistent,
47
+ resizable chat / assistant panel (e.g. "Acronis AI").
48
+ - When the chat must be freely resizable — including down to an icon-only rail
49
+ or up to full width — without disturbing the navigation sidebars.
50
+
51
+ ## When NOT to Use
52
+
53
+ - A transient chat overlay — use a Sheet or Popover.
54
+ - Content that should resize proportionally in percentages — use **Resizable**
55
+ (this component deliberately uses fixed pixel sizing so sidebar changes never
56
+ resize the chat).
57
+
58
+ ## Parts
59
+
60
+ | Part | Element | Role |
61
+ | --------------------------- | --------- | ----------------------------------------------------------------- |
62
+ | `AppShellChat` | `<div>` | Root |
63
+ | `AppShellChatSidebar` | `<aside>` | Rail slot for SidebarPrimary (+ SidebarSecondary) |
64
+ | `AppShellChatContent` | `<div>` | Page column (`flex-1`); can shrink to 0, never unmounts |
65
+ | `AppShellChatContentHeader` | `<div>` | Page header row (bottom divider) |
66
+ | `AppShellChatContentBody` | `<div>` | Scrolling page body |
67
+ | `AppShellChatChat` | `<aside>` | Resizable chat panel |
68
+ | `AppShellChatChatHeader` | `<div>` | Chat header (title + actions, or icon-only rail at the min width) |
69
+ | `AppShellChatChatBody` | `<div>` | Scrolling chat body (hidden at the min width) |
70
+
71
+ The resize edge is rendered automatically inside `AppShellChatChat` and is not a
72
+ public part.
73
+
74
+ ## Quick Example
75
+
76
+ ### React
77
+
78
+ ```tsx
79
+ import {
80
+ AppShellChat,
81
+ AppShellChatSidebar,
82
+ AppShellChatContent,
83
+ AppShellChatContentHeader,
84
+ AppShellChatContentBody,
85
+ AppShellChatChat,
86
+ AppShellChatChatHeader,
87
+ AppShellChatChatBody,
88
+ useAppShellChatInitialLayout,
89
+ SidebarPrimary,
90
+ SidebarSecondary,
91
+ } from '@acronis-platform/ui-react';
92
+
93
+ function Screen() {
94
+ // Resolves ONCE at mount from the viewport width — see "Responsive
95
+ // layout" below. AppShellChatSidebar is a plain slot (not a fixed
96
+ // SidebarPrimary+SidebarSecondary pairing it owns), so wiring the result
97
+ // into each sidebar's `defaultExpanded` is the consumer's job.
98
+ const initialLayout = useAppShellChatInitialLayout();
99
+
100
+ return (
101
+ <AppShellChat className="h-screen">
102
+ <AppShellChatSidebar>
103
+ <SidebarPrimary defaultExpanded={initialLayout.primaryExpanded}>
104
+ {/* … */}
105
+ </SidebarPrimary>
106
+ <SidebarSecondary defaultExpanded={initialLayout.secondaryExpanded}>
107
+ {/* … */}
108
+ </SidebarSecondary>
109
+ </AppShellChatSidebar>
110
+ <AppShellChatContent>
111
+ <AppShellChatContentHeader>Page header</AppShellChatContentHeader>
112
+ <AppShellChatContentBody>{/* page */}</AppShellChatContentBody>
113
+ </AppShellChatContent>
114
+ <AppShellChatChat>
115
+ <AppShellChatChatHeader label="Acronis AI" />
116
+ <AppShellChatChatBody>{/* chat */}</AppShellChatChatBody>
117
+ </AppShellChatChat>
118
+ </AppShellChat>
119
+ );
120
+ }
121
+ ```
122
+
123
+ ## Sizing model
124
+
125
+ Content is `flex-1 min-w-0`; Chat has an explicit pixel width (responsive by
126
+ default, or an inline override once the user drags/keyboard-resizes it — see
127
+ **Responsive layout** below). Because Chat never uses percentages and the
128
+ sidebars sit outside any resizable group, expanding / collapsing / resizing a
129
+ sidebar only reflows Content — Chat keeps its width. Chat's own resize range
130
+ runs from a 48px floor (icon-only rail) up to the row's actual available
131
+ width, so dragging it far enough shrinks Content to 0 and Chat alone fills
132
+ the row — there is no separate full-width toggle.
133
+
134
+ ## Responsive layout
135
+
136
+ Chat's width and the sidebars' initial expanded state both key off the same
137
+ breakpoints (`src/lib/breakpoints.ts` — 1280px / 1680px), but with
138
+ deliberately different lifetimes:
139
+
140
+ - **Chat's width is LIVE** — plain responsive CSS, no wiring required. It
141
+ reflows on every browser resize (512px at 1680px+, 448px from
142
+ 1280-1679px, the 48px icon-rail floor below 1280px) until the user drags
143
+ or keyboard-resizes it, at which point that explicit choice wins until
144
+ double-click/Home resets it.
145
+ - **The sidebars' initial layout is frozen at mount** — resolved once from
146
+ `useAppShellChatInitialLayout()` (exported alongside `AppShellChat`) and
147
+ wired into `SidebarPrimary`/`SidebarSecondary`'s `defaultExpanded` prop
148
+ (see the Quick Example above). At 1680px+ both sidebars start expanded;
149
+ below that, `SidebarPrimary` starts collapsed while `SidebarSecondary`
150
+ stays expanded. A later viewport resize, or the user manually toggling a
151
+ sidebar, never re-derives this — sidebars own real collapse/expand
152
+ controls, so their state shouldn't fight a live viewport change the way
153
+ Chat's plain width safely can.
154
+
155
+ See `behavior.md`'s **Responsive layout** section for the full Given/When/Then
156
+ scenarios.
157
+
158
+ ## Spec Files
159
+
160
+ | File | Contents |
161
+ | ------------------ | ----------------------------------------------------------------- |
162
+ | `index.yaml` | Identity, status, category, dependencies, Figma link |
163
+ | `anatomy.yaml` | Root, parts, layout, states |
164
+ | `api.yaml` | Framework-agnostic contract + framework adapters |
165
+ | `tokens.yaml` | Shared `--ui-*` token references (no component-specific tokens) |
166
+ | `behavior.md` | Given/When/Then behavior scenarios |
167
+ | `accessibility.md` | ARIA roles, keyboard map, screen-reader and contrast requirements |
168
+
169
+ ## Props
170
+
171
+ | Prop | Type | Default | Required | Description |
172
+ |------|------|---------|----------|-------------|
173
+ | `width` | `number` | `undefined` | no | Controlled Chat width in px. When uncontrolled (the default), Chat's width is instead LIVE and breakpoint-responsive — 512px at 1680px+, 448px from 1280-1679px, 48px below that — reflowing on every browser resize until the user drags/keyboard-resizes it. Any explicit width (controlled, or a drag/keyboard override) is clamped during resize to [48, available] — the ceiling is the actual available row width (so Content can shrink to 0 and Chat can reach full width), not a fixed constant. |
174
+ | `resizeAriaLabel` | `string` | `'Resize chat'` | no | Accessible label for the Chat resize edge (`role="separator"`). Consumers should localize this string for i18n. |
175
+ | `resizeTooltip` | `ReactNode` | `(English tooltip: Resize/Reset)` | no | Tooltip content shown on the resize edge. Pass `null` to hide the tooltip entirely. Localize for i18n. |
176
+ | `label` | `ReactNode` | `undefined` | no | Chat header title (or pass as children). Also serves as the icon-only rail's hover tooltip and (when a string) the Acronis mark's accessible name. |
177
+ | `actions` | `ReactNode` | `undefined` | no | Trailing chat-header actions. Hidden while the chat is at its min width (icon-only rail). |
178
+
179
+ ## Events
180
+
181
+ | Event | Payload | Description |
182
+ |-------|---------|-------------|
183
+ | `width-change` | `number` | Fires when the Chat width changes via drag/keyboard. React: `onWidthChange` on AppShellChatChat. |
184
+
185
+ ## Content slots
186
+
187
+ | Slot | Description |
188
+ |------|-------------|
189
+ | `default` | The composed scaffold. Author it from the parts: a sidebar rail slot, a Content column (header + body), and a Chat panel (header + body). The resize edge is rendered automatically inside the Chat panel. |
190
+
191
+ ## Behavior
192
+
193
+ ### Structure
194
+
195
+ #### Renders three logical sections
196
+
197
+ **Given** an AppShellChat wrapping a sidebar rail, a Content column, and a Chat panel
198
+ **When** the component renders
199
+ **Then** the sections lay out left→right as sidebar → Content → Chat
200
+ **And** in `dir="rtl"` they mirror to right→left via CSS logical properties (no JS branch)
201
+ **And** Content is `flex-1 min-w-0` while Chat has an explicit pixel width
202
+
203
+ ---
204
+
205
+ ### Sizing independence
206
+
207
+ #### Sidebar interactions never resize Chat
208
+
209
+ **Given** a Chat panel with a fixed/overridden width
210
+ **When** either sidebar expands, collapses, or is resized
211
+ **Then** only Content's width changes (it absorbs the delta)
212
+ **And** Chat's width is unchanged
213
+
214
+ > This falls out of the layout: Content is the only flex-growing item, and Chat's
215
+ > width is an explicit pixel value (never a percentage), so the sidebars — flex
216
+ > siblings outside any resizable group — cannot alter it.
217
+
218
+ ---
219
+
220
+ ### Content ↔ Chat resize
221
+
222
+ #### Drag resizes Chat against Content, down to the min width
223
+
224
+ **Given** a Chat panel
225
+ **When** the user drags the resize edge on Chat's start border toward the row's end
226
+ **Then** Chat's width tracks the pointer, down to a floor of 48px
227
+ **And** Content reflows to fill the remaining width
228
+ **And** the Content/Chat seam recolors on hover / drag / focus
229
+ **And** there is no collapse threshold or toggle — the drag simply stops at the floor
230
+
231
+ #### Drag resizes Chat up to full width
232
+
233
+ **Given** a Chat panel and its sibling Content column
234
+ **When** the user drags the resize edge toward the row's start
235
+ **Then** Chat's width grows and Content shrinks, down to 0 width if dragged far enough
236
+ **And** the resize ceiling is the row's actual available width at drag start (row
237
+ width minus the sidebar rail), not a fixed constant — so Chat can reach full
238
+ width whenever the row has the room (e.g. both sidebars collapsed), and is
239
+ otherwise bounded by whatever space is actually free
240
+
241
+ #### Double-click and keyboard
242
+
243
+ **Given** the resize edge
244
+ **When** the user double-clicks it
245
+ **Then** the width resets to the current LIVE breakpoint-driven default
246
+ (512px at 1680px+; see **Responsive layout** below) — NOT a fixed 512px
247
+ regardless of viewport
248
+ **And** ArrowLeft/ArrowRight resize by 16px (inverted in RTL), clamped to
249
+ [48px, the same dynamically-measured ceiling used by drag]
250
+ **And** Home resets the width the same way double-click does
251
+
252
+ ---
253
+
254
+ ### Icon-only rail at the min width
255
+
256
+ #### Header and body adapt at 48px
257
+
258
+ **Given** the Chat panel's width is at its 48px floor
259
+ **When** it renders
260
+ **Then** the panel has `data-state="collapsed"`
261
+ **And** the header shows only the Acronis mark, sized to match the header's
262
+ height at any other width; the full label appears on hover
263
+ **And** the chat body is hidden (`hidden`)
264
+ **And** any header `actions` are hidden
265
+
266
+ **Given** the Chat panel's width is above the 48px floor
267
+ **When** it renders
268
+ **Then** the panel has `data-state="expanded"`
269
+ **And** the header shows the title + any `actions`; the body is visible
270
+
271
+ ---
272
+
273
+ ### Responsive layout
274
+
275
+ #### Chat's width is breakpoint-responsive, and stays LIVE until the user resizes it
276
+
277
+ **Given** an uncontrolled Chat panel that the user has not yet dragged or
278
+ keyboard-resized
279
+ **When** the viewport width crosses 1280px or 1680px (the `xl`/`3xl` steps
280
+ pinned in `src/styles/index.css` and mirrored in `src/lib/breakpoints.ts`)
281
+ **Then** Chat's width reflows immediately, with no page reload or remount:
282
+ 48px (icon-only rail) below 1280px, 448px from 1280px up to 1680px, 512px at
283
+ 1680px and up
284
+ **And** this reflow keeps happening on every subsequent browser resize —
285
+ it is NOT a one-time initial measurement
286
+
287
+ **Given** the user has dragged the resize handle, nudged it with the arrow
288
+ keys, or the `width` prop is controlled
289
+ **When** the viewport is resized afterward
290
+ **Then** Chat's width no longer reflows — the explicit value (drag/keyboard
291
+ override, or the controlled `width`) wins until double-click/Home resets it
292
+ back to the live breakpoint-driven value
293
+
294
+ > Unlike the sidebars below, Chat's responsive width needs no wiring from the
295
+ > consumer — it's implemented as plain CSS (`w-12 xl:w-md 3xl:w-lg` on the
296
+ > Chat panel), not a hook. There is no design token for these three widths
297
+ > (a pure layout composition), so the pixel values live only as JS constants
298
+ > in `app-shell-chat.tsx` mirroring the Tailwind classes.
299
+
300
+ #### The sidebars' initial layout is breakpoint-derived, but frozen at mount
301
+
302
+ **Given** a screen that renders `SidebarPrimary` (+ optionally
303
+ `SidebarSecondary`) inside `AppShellChatSidebar`, wiring
304
+ `useAppShellChatInitialLayout()`'s `primaryExpanded`/`secondaryExpanded`
305
+ fields into each sidebar's `defaultExpanded` prop
306
+ **When** the screen first mounts
307
+ **Then** at 1680px and up, `SidebarPrimary` starts expanded and
308
+ `SidebarSecondary` (if present) starts expanded
309
+ **And** below 1680px, `SidebarPrimary` starts collapsed while
310
+ `SidebarSecondary` (if present) still starts expanded
311
+
312
+ **Given** a screen already mounted with that initial layout applied
313
+ **When** the viewport is resized, or the user manually expands/collapses a
314
+ sidebar
315
+ **Then** the sidebars' state is NEVER re-derived from the viewport again —
316
+ `useAppShellChatInitialLayout` reads `window.innerWidth` exactly once, at
317
+ first render, because `defaultExpanded` is itself a one-shot value on the
318
+ sidebar components (a later prop change is silently ignored); re-deriving it
319
+ live would fight the user's own sidebar toggle on every resize
320
+
321
+ > This is the opposite tradeoff from Chat's width, and deliberately so: Chat
322
+ > is a pure visual size with no independent "user already chose something"
323
+ > state to protect, so it can safely stay live forever. A sidebar's
324
+ > expanded/collapsed state IS that kind of state (the user's own toggle), so
325
+ > only the very first paint is allowed to be breakpoint-aware.
326
+
327
+ ---
328
+
329
+ ### Controlled / uncontrolled
330
+
331
+ #### Width supports either mode
332
+
333
+ **Given** `width` (controlled) or the uncontrolled, breakpoint-responsive
334
+ default (see **Responsive layout** above)
335
+ **When** the resize edge is dragged or operated via keyboard
336
+ **Then** uncontrolled state updates internally, controlled state is owned by the consumer
337
+ **And** `onWidthChange` always fires with the next value
338
+
339
+ ## Accessibility
340
+
341
+ A layout scaffold. It contributes little ARIA of its own — the rich landmarks
342
+ (`nav`) come from the SidebarPrimary / SidebarSecondary dropped into its rail
343
+ slot. Its own interactive part is the Chat resize edge.
344
+
345
+ ## ARIA Roles and Attributes
346
+
347
+ ### Root (`div`)
348
+
349
+ | Attribute | Value | Reason |
350
+ | ----------- | ---------------- | -------------------- |
351
+ | `data-slot` | `app-shell-chat` | Styling / query hook |
352
+
353
+ ### Sidebar / Content / Chat regions
354
+
355
+ `<aside>` for the sidebar rail and the Chat panel; `<div>` for the Content
356
+ column. Consumers may add `aria-label` to the Chat `<aside>` to name the region.
357
+
358
+ ### Resize edge (`role="separator"`)
359
+
360
+ | Attribute | Value | Reason |
361
+ | ------------------ | ----------------- | ----------------------------------------- |
362
+ | `role` | `separator` | Exposes the draggable boundary |
363
+ | `aria-orientation` | `vertical` | The boundary is vertical |
364
+ | `aria-label` | `resizeAriaLabel` | Names the control (default "Resize chat") |
365
+ | `tabindex` | `0` | Keyboard-focusable for arrow-key resize |
366
+
367
+ ### Chat header (at the min width)
368
+
369
+ At the 48px floor, the header shows only the Acronis mark. The mark carries an
370
+ accessible name (from the string `label`) and the full label is shown on hover
371
+ via a tooltip; no visible text is rendered in the rail.
372
+
373
+ ---
374
+
375
+ ## Keyboard Navigation
376
+
377
+ | Key | Element | Action |
378
+ | ----------------- | ----------- | -------------------------------------- |
379
+ | Tab / Shift+Tab | any | Moves focus between interactive parts |
380
+ | ArrowLeft / Right | resize edge | Resizes Chat by 16px (inverted in RTL) |
381
+ | Home | resize edge | Resets Chat width to 512px |
382
+
383
+ Arrow-key directions are logical: growing Chat moves the boundary toward the
384
+ row's start, so the grow key is ArrowLeft in LTR and ArrowRight in RTL. There is
385
+ no Enter/Space action — the resize edge has no toggle, only resize.
386
+
387
+ ---
388
+
389
+ ## Focus
390
+
391
+ The resize edge shows a focus ring using `--ui-focus-primary`, visible against
392
+ the panel surface.
393
+
394
+ ---
395
+
396
+ ## Color and Contrast
397
+
398
+ | Element | Minimum Ratio | Standard |
399
+ | -------------------------------- | ------------- | ---------------------- |
400
+ | Chat header title vs surface | 4.5:1 | WCAG 1.4.3 (AA) |
401
+ | Content/Chat seam (resize state) | 3:1 | WCAG 1.4.11 (non-text) |
402
+ | Focus indicators | 3:1 | WCAG 1.4.11 |
403
+
404
+ ---
405
+
406
+ ## Testing Checklist
407
+
408
+ - [ ] Content is always present and can shrink to 0 width; it is never unmounted
409
+ - [ ] The resize edge is a `separator` with a name
410
+ - [ ] Dragging or using arrows/Home on the resize edge resizes Chat between its
411
+ 48px floor and the actual available row width (no fixed cap strands
412
+ Content with a bogus minimum)
413
+ - [ ] Chat header at the 48px floor keeps an accessible name (icon) and hides
414
+ the body; both header states share the same height
415
+ - [ ] Works in `dir="ltr"` and `dir="rtl"` (logical properties)