@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.
- package/dist/components/ui/accordion-container/accordion-container.js +14 -14
- package/dist/components/ui/accordion-container/accordion-container.js.map +1 -1
- package/dist/components/ui/app-shell-chat/app-shell-chat.js.map +1 -1
- package/dist/components/ui/area-chart/area-chart.js +141 -139
- package/dist/components/ui/area-chart/area-chart.js.map +1 -1
- package/dist/components/ui/bar-chart/bar-chart.js +295 -293
- package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
- package/dist/components/ui/category-bar/category-bar.js +109 -93
- package/dist/components/ui/category-bar/category-bar.js.map +1 -1
- package/dist/components/ui/chart/chart-palette.js +113 -0
- package/dist/components/ui/chart/chart-palette.js.map +1 -0
- package/dist/components/ui/chart/chart.js +176 -129
- package/dist/components/ui/chart/chart.js.map +1 -1
- package/dist/components/ui/chart-state/chart-state-illustrations.js +310 -0
- package/dist/components/ui/chart-state/chart-state-illustrations.js.map +1 -0
- package/dist/components/ui/chart-state/chart-state.js +48 -34
- package/dist/components/ui/chart-state/chart-state.js.map +1 -1
- package/dist/components/ui/chart-widget/chart-widget.js +87 -0
- package/dist/components/ui/chart-widget/chart-widget.js.map +1 -0
- package/dist/components/ui/composed-chart/composed-chart.js +117 -115
- package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
- package/dist/components/ui/confidence-cone/confidence-cone.js +166 -158
- package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
- package/dist/components/ui/funnel-chart/funnel-chart.js +162 -161
- package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
- package/dist/components/ui/histogram/histogram.js +94 -92
- package/dist/components/ui/histogram/histogram.js.map +1 -1
- package/dist/components/ui/input/input.js.map +1 -1
- package/dist/components/ui/label/label.js +2 -9
- package/dist/components/ui/label/label.js.map +1 -1
- package/dist/components/ui/line-chart/line-chart.js +143 -141
- package/dist/components/ui/line-chart/line-chart.js.map +1 -1
- package/dist/components/ui/metric/metric.js +74 -185
- package/dist/components/ui/metric/metric.js.map +1 -1
- package/dist/components/ui/page-content/page-content.js.map +1 -1
- package/dist/components/ui/pie-chart/pie-chart.js +201 -195
- package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
- package/dist/components/ui/radar-chart/radar-chart.js +133 -131
- package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +297 -265
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
- package/dist/components/ui/sankey-chart/sankey-chart.js +123 -101
- package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -1
- package/dist/components/ui/scatter-chart/scatter-chart.js +76 -74
- package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
- package/dist/components/ui/section/section.js +157 -31
- package/dist/components/ui/section/section.js.map +1 -1
- package/dist/components/ui/stepper/stepper.js +24 -24
- package/dist/components/ui/stepper/stepper.js.map +1 -1
- package/dist/components/ui/stepper-item/stepper-item.js +43 -24
- package/dist/components/ui/stepper-item/stepper-item.js.map +1 -1
- package/dist/components/ui/treemap/treemap.js +133 -124
- package/dist/components/ui/treemap/treemap.js.map +1 -1
- package/dist/components/ui/trend-indicator/trend-indicator.js +34 -69
- package/dist/components/ui/trend-indicator/trend-indicator.js.map +1 -1
- package/dist/components/ui/wizard/wizard.js +59 -0
- package/dist/components/ui/wizard/wizard.js.map +1 -0
- package/dist/hooks/use-wizard.js +75 -0
- package/dist/hooks/use-wizard.js.map +1 -0
- package/dist/index.js +502 -497
- package/dist/index.js.map +1 -1
- package/dist/llms/accordion-container.md +181 -0
- package/dist/llms/accordion.md +124 -0
- package/dist/llms/alert.md +225 -0
- package/dist/llms/app-shell-chat.md +415 -0
- package/dist/llms/area-chart.md +355 -0
- package/dist/llms/avatar.md +208 -0
- package/dist/llms/bar-chart.md +406 -0
- package/dist/llms/breadcrumb.md +326 -0
- package/dist/llms/button-group.md +298 -0
- package/dist/llms/button-icon-input.md +142 -0
- package/dist/llms/button-icon-menu.md +209 -0
- package/dist/llms/button-icon.md +128 -0
- package/dist/llms/button-menu.md +172 -0
- package/dist/llms/button.md +185 -0
- package/dist/llms/calendar-panel.md +733 -0
- package/dist/llms/calendar.md +188 -0
- package/dist/llms/card-filter.md +214 -0
- package/dist/llms/card-section.md +293 -0
- package/dist/llms/card.md +447 -0
- package/dist/llms/carousel-dialog.md +156 -0
- package/dist/llms/category-bar.md +193 -0
- package/dist/llms/chart-state.md +190 -0
- package/dist/llms/chart-widget.md +209 -0
- package/dist/llms/chart.md +182 -0
- package/dist/llms/checkbox.md +257 -0
- package/dist/llms/chip.md +195 -0
- package/dist/llms/combobox.md +164 -0
- package/dist/llms/composed-chart.md +508 -0
- package/dist/llms/confidence-cone.md +277 -0
- package/dist/llms/data-table.md +474 -0
- package/dist/llms/date-range-picker.md +272 -0
- package/dist/llms/description-list.md +131 -0
- package/dist/llms/dialog-footer-carousel.md +147 -0
- package/dist/llms/dialog-footer-default.md +142 -0
- package/dist/llms/dialog-root.md +246 -0
- package/dist/llms/dialog-welcome.md +223 -0
- package/dist/llms/dialog.md +403 -0
- package/dist/llms/dropdown-menu.md +193 -0
- package/dist/llms/empty-overlay.md +146 -0
- package/dist/llms/empty.md +156 -0
- package/dist/llms/field.md +185 -0
- package/dist/llms/filter-cards.md +157 -0
- package/dist/llms/filter-chips.md +323 -0
- package/dist/llms/filter-search.md +512 -0
- package/dist/llms/form.md +154 -0
- package/dist/llms/funnel-chart.md +333 -0
- package/dist/llms/grid.md +80 -0
- package/dist/llms/histogram.md +190 -0
- package/dist/llms/input-date-picker.md +203 -0
- package/dist/llms/input-otp.md +173 -0
- package/dist/llms/input-password.md +197 -0
- package/dist/llms/input-search.md +170 -0
- package/dist/llms/input-select.md +278 -0
- package/dist/llms/input-text-area.md +271 -0
- package/dist/llms/input-text.md +192 -0
- package/dist/llms/line-chart.md +369 -0
- package/dist/llms/link.md +209 -0
- package/dist/llms/loading.md +130 -0
- package/dist/llms/meter.md +177 -0
- package/dist/llms/metric.md +204 -0
- package/dist/llms/number-field.md +122 -0
- package/dist/llms/page-content.md +69 -0
- package/dist/llms/page-header.md +182 -0
- package/dist/llms/pagination.md +133 -0
- package/dist/llms/pie-chart.md +307 -0
- package/dist/llms/popover.md +252 -0
- package/dist/llms/progress-circle.md +126 -0
- package/dist/llms/progress.md +111 -0
- package/dist/llms/radar-chart.md +316 -0
- package/dist/llms/radial-bar-chart.md +319 -0
- package/dist/llms/radio.md +255 -0
- package/dist/llms/resizable.md +195 -0
- package/dist/llms/sankey-chart.md +208 -0
- package/dist/llms/scatter-chart.md +239 -0
- package/dist/llms/scroll-area.md +183 -0
- package/dist/llms/section.md +401 -0
- package/dist/llms/select.md +210 -0
- package/dist/llms/separator.md +87 -0
- package/dist/llms/sheet.md +202 -0
- package/dist/llms/sidebar-primary.md +360 -0
- package/dist/llms/sidebar-secondary.md +417 -0
- package/dist/llms/skeleton.md +81 -0
- package/dist/llms/slider.md +97 -0
- package/dist/llms/spinner.md +100 -0
- package/dist/llms/stack.md +80 -0
- package/dist/llms/stepper-item.md +309 -0
- package/dist/llms/stepper.md +251 -0
- package/dist/llms/switch.md +140 -0
- package/dist/llms/table.md +436 -0
- package/dist/llms/tabs.md +197 -0
- package/dist/llms/tag.md +139 -0
- package/dist/llms/timeline.md +361 -0
- package/dist/llms/timer.md +259 -0
- package/dist/llms/toast.md +241 -0
- package/dist/llms/toggle-group.md +121 -0
- package/dist/llms/toolbar.md +453 -0
- package/dist/llms/tooltip.md +164 -0
- package/dist/llms/treemap.md +254 -0
- package/dist/llms/trend-indicator.md +132 -0
- package/dist/llms/widget-placeholder.md +169 -0
- package/dist/llms/wizard.md +412 -0
- package/dist/llms.txt +142 -0
- package/dist/react.js +502 -497
- package/dist/react.js.map +1 -1
- package/dist/src/components/ui/area-chart/area-chart.d.ts +9 -4
- package/dist/src/components/ui/avatar/avatar.d.ts +1 -1
- package/dist/src/components/ui/bar-chart/bar-chart.d.ts +9 -4
- package/dist/src/components/ui/category-bar/category-bar.d.ts +10 -4
- package/dist/src/components/ui/chart/__stories__/palette-control.d.ts +48 -0
- package/dist/src/components/ui/chart/__tests__/chart-palette.test.d.ts +1 -0
- package/dist/src/components/ui/chart/chart-palette.d.ts +128 -0
- package/dist/src/components/ui/chart/chart.d.ts +66 -15
- package/dist/src/components/ui/chart/index.d.ts +4 -2
- package/dist/src/components/ui/chart-state/chart-state-illustrations.d.ts +6 -0
- package/dist/src/components/ui/chart-state/chart-state.d.ts +13 -2
- package/dist/src/components/ui/chart-state/index.d.ts +1 -0
- package/dist/src/components/ui/chart-widget/chart-widget.d.ts +64 -0
- package/dist/src/components/ui/chart-widget/index.d.ts +1 -0
- package/dist/src/components/ui/composed-chart/composed-chart.d.ts +12 -7
- package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +10 -5
- package/dist/src/components/ui/empty-overlay/empty-overlay.d.ts +1 -1
- package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +11 -5
- package/dist/src/components/ui/histogram/histogram.d.ts +10 -4
- package/dist/src/components/ui/label/index.d.ts +1 -1
- package/dist/src/components/ui/label/label.d.ts +1 -5
- package/dist/src/components/ui/line-chart/line-chart.d.ts +9 -4
- package/dist/src/components/ui/metric/metric.d.ts +13 -14
- package/dist/src/components/ui/pie-chart/pie-chart.d.ts +17 -8
- package/dist/src/components/ui/radar-chart/radar-chart.d.ts +10 -5
- package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +17 -6
- package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +10 -5
- package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +10 -5
- package/dist/src/components/ui/section/index.d.ts +1 -1
- package/dist/src/components/ui/section/section.d.ts +75 -6
- package/dist/src/components/ui/stepper-item/stepper-item.d.ts +6 -5
- package/dist/src/components/ui/tag/tag.d.ts +1 -1
- package/dist/src/components/ui/treemap/treemap.d.ts +11 -5
- package/dist/src/components/ui/trend-indicator/trend-indicator.d.ts +3 -7
- package/dist/src/components/ui/wizard/index.d.ts +1 -0
- package/dist/src/components/ui/wizard/wizard.d.ts +6 -0
- package/dist/src/hooks/index.d.ts +1 -0
- package/dist/src/hooks/use-wizard.d.ts +80 -0
- package/dist/src/index.d.ts +2 -3
- package/dist/ui-react.css +1 -1
- package/package.json +9 -3
- package/dist/components/ui/app-shell/app-shell.js +0 -75
- package/dist/components/ui/app-shell/app-shell.js.map +0 -1
- package/dist/components/ui/auth-layout/auth-layout.js +0 -56
- package/dist/components/ui/auth-layout/auth-layout.js.map +0 -1
- package/dist/components/ui/collapsible/collapsible.js +0 -22
- package/dist/components/ui/collapsible/collapsible.js.map +0 -1
- package/dist/src/components/ui/app-shell/app-shell.d.ts +0 -8
- package/dist/src/components/ui/app-shell/index.d.ts +0 -1
- package/dist/src/components/ui/auth-layout/auth-layout.d.ts +0 -6
- package/dist/src/components/ui/auth-layout/index.d.ts +0 -1
- package/dist/src/components/ui/collapsible/collapsible.d.ts +0 -5
- package/dist/src/components/ui/collapsible/index.d.ts +0 -1
- 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)
|