@vegastack/design 0.7.3 → 0.7.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vegastack/design",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "VegaStack design system — cn utility, icon runtime, Tailwind v4 preset, and the vegastack-design CLI (tokens ship separately as @vegastack/design-tokens)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -58,26 +58,81 @@ link` (upstream's set, verbatim). `destructive` is a soft tint, not a solid red
58
58
  control height — `Chip` (`sm`/`md`, the inline and control pill scales), `StatusIcon`, `Stat` and
59
59
  `Image`'s corner — and they say so on their own pages.
60
60
  - **Compose `app-shell`** for a sidebar + header + main layout — never hand-roll the landmark trio.
61
+ - **Space a page with the page-rhythm recipe** — gutters `px-4 py-6` / `md:px-8 md:py-8`,
62
+ `gap-6` under `PageHeader`, `gap-8` between sections, `gap-3` from a section heading or a list
63
+ toolbar to its content, `--card-spacing` inside a card, and `FieldGroup`'s own gaps in a form
64
+ (<https://design.vegastack.com/docs/foundations/spacing#page-rhythm>).
61
65
  - **`select`** for a short fixed option set; **`searchable-select`** when the list is long enough to
62
66
  need a search field (it is the preset `country-select` and `region-select` are built from — reach
63
67
  for it before composing `combobox` by hand); **`combobox`** directly only for free text,
64
68
  suggestions or multi-select chips.
65
- - **`toggle-group`** with `spacing={0}` for 2–5 exclusive options inline; **`tabs`** when the
66
- choice switches page regions.
69
+ - **One view-switch rule.** A form value is a **`radio-group`**. An immediate view or scope switch
70
+ over the same content (Mine | Team, All | Unread, Grid | List) is a single-select
71
+ **`toggle-group`** that always keeps one item pressed — ignore the empty value in
72
+ `onValueChange` — with `spacing={0}` for 2–5 options inline. Swapping in-page regions is
73
+ **`tabs`**; moving between URLs is navigation — links, not `tabs` (a route-tabs recipe is
74
+ not shipped yet).
75
+ - **Empty is tiered** — nothing yet, no matches ("Clear filters"), couldn't load (`role="alert"`,
76
+ "Try again"), blocked. Pick the tier from the empty-state foundation
77
+ (<https://design.vegastack.com/docs/foundations/empty-states>); never leave a region blank.
67
78
  - **`alert`** for an in-content notice — `variant` is `default · destructive · success · warning ·
68
79
  info`, each an ink on the `card` surface with a required icon; **`announcement-banner`** only for
69
80
  the full-width inverse strip at the very top of the page.
70
81
  - **`chip` is the ONE pill** — `hue` × `size` (`sm` inline · `md` control-scale) × `active`, with
71
- `onRemove` giving a real 24×24 remove control. `Tag`, `FilterChip` and `ComboboxChip` are that
72
- primitive composed through `render`; never hand-roll a pill with its own height, radius, or a
73
- sub-24px `×`. A **`badge`** is the different job: status, never removable, never a selection.
82
+ `onRemove` giving a real 24×24 remove control. `Tag` and `FilterChip` wrap that primitive; `ComboboxChip` is Base UI's own chip and does not share its geometry
83
+ yet. Never hand-roll a pill with its own height, radius, or a sub-24px `×`. A **`badge`** is the different job: status, never removable, never a selection.
74
84
  - **`useAnnouncer` is the one live region** — destructure `announce` and `Announcer` from it and
75
85
  render ONE `Announcer` element per component, mounted for its life. It keeps the region observed from first paint
76
86
  and re-keys it per call, so repeating an identical string still announces. Do not hand-roll a
77
87
  `role="status"` node with a `{text, seq}` counter.
88
+ - **Theme choice lives in the user menu** — a `DropdownMenuRadioGroup` of Light, Dark and System
89
+ bound to `theme` and `setTheme` from `useVegaStackTheme()`. There is no `theme-toggle` registry
90
+ item yet (a known gap); do not hand-roll a local toggle button.
78
91
  - **`code-block`** for static syntax-highlighted source; **`terminal`** for command sessions.
79
92
  - **`navigation-menu`** is top-level site navigation with panels, not a menu inside a page.
80
93
 
94
+ ### Names hide abilities
95
+
96
+ A component's name undersells it. Before composing something by hand, check this list:
97
+
98
+ | Component | What it already does |
99
+ | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
100
+ | `Command` | Renders inline as well as in `CommandDialog`. An item's check mark is `data-checked` — visual only, so it is not a form value. |
101
+ | `Combobox` | `multiple` with `ComboboxChips`; `filter={null}` hands filtering to your server. |
102
+ | `SearchableSelect` | The Select-shaped search picker, with `clearable`. Single-select today. |
103
+ | `Item` | A link tile with `render={<a />}`; `ItemGroup` gives a set of items list semantics. |
104
+ | `DialogContent` | `size`: `sm · default · lg · xl`. Never a width class. |
105
+ | `DataList` | Per-column `mobile` (`merge` · `visible` · `hidden`) and `minWidth`. `DataGrid` adds editing, multi-key sort and a column picker; `Table` is static markup. |
106
+ | `FilterBar` / `FilterBuilder` | `FilterBar` is a flat chip row with search; `FilterBuilder` (the `filter-bar-managed` item) edits a nested and/or tree over your field vocabulary. Both are controlled. |
107
+ | `Stat` | `StatDelta` for change, `StatEmpty` for nothing to report. |
108
+ | `PropertyList` · `DataList` · `SettingsRow` | A record's facts · many records · one setting with its control. |
109
+ | `ActionBar` | The docked bar for bulk selection ("5 selected"), unsaved changes and batch progress. |
110
+ | `TruncatedText` · `IconText` · `TableCellText` | Overflow detection, hover and keyboard reveal, and tap-to-toggle on touch. |
111
+ | `RelativeTime` | `mode="ago"` ("3 minutes ago") or `mode="day"` ("Yesterday"). |
112
+ | `EditableCell` · `AutoSaveInput` · `useInlineEdit` | Click-to-edit in a table · a field that saves as you type, with its status · the hook `EditableCell` is built on. |
113
+ | `AttachmentGroup` · `Dropzone` · `useFileDrop` | A file list with per-file state · a drop target · the drop and paste engine. |
114
+ | `PageHeader` | Title, description, `breadcrumb`, a back link (`backHref`) and `actions`. |
115
+ | `MultiStepForm` · `Stepper` · `Questionnaire` · `Tabs` | A form in steps · progress display (`navigable` on request) · one question at a time · peer regions. |
116
+ | `NativeSelect` | The platform `<select>`, so a touch device opens its own picker. |
117
+ | `Board` | A column's `lockedReason` explains why it cannot take a card. |
118
+ | `AudioPlayer` | `mediaRef` to drive playback, a transcript button and a waveform. |
119
+ | `Tabs` | `TabsList variant="line"` and `Tabs orientation="vertical"`. |
120
+ | `MessageScroller` | `defaultScrollPosition` (`start` · `end` · `last-anchor`), `scrollToMessage` from `useMessageScroller()`, and `useMessageScrollerVisibility()`. |
121
+
122
+ ### Which component for X
123
+
124
+ - **A page** → `AppShell` › `AppShellContent` › `PageHeader` › `FilterBar` › `DataList` (or
125
+ `DataGrid`) › the `Empty` tier that fits. The spacing between them is the page-rhythm recipe
126
+ (<https://design.vegastack.com/docs/foundations/spacing#page-rhythm>).
127
+ - **A record's details** → `PropertyList`, in `Card` sections titled with an `h2` in `CardTitle`.
128
+ - **Settings** → `SettingsSection` › `SettingsCard` › `SettingsRow`.
129
+ - **A button that navigates** → `<Link className={buttonVariants()}>` (see Composition patterns).
130
+ - **A status** → `Badge` with a status `variant`; an in-content notice → `Alert`.
131
+ - **A metric** → `Stat`.
132
+ - **A confirmation that interrupts** → `AlertDialog`; a form or detail in an overlay → `Dialog` or
133
+ `Sheet`.
134
+ - **Feedback after an action** → `toast.add({ title })`.
135
+
81
136
  ## Tokens
82
137
 
83
138
  Semantic CSS custom properties from `@vegastack/design-tokens/theme.css` (OKLCH, `:root` + `.dark`),
@@ -174,12 +229,14 @@ contract.
174
229
  inside a portal + positioner. Theme, toast, tooltip, and direction providers all come from
175
230
  `<VegaStackProvider>`; your app root needs `isolation: isolate` or portaled popups can render under
176
231
  page chrome.
177
- - **Compound parts import flat** — `import { DialogTrigger, DialogContent }`. Sub-property access
178
- (`<Dialog.Trigger>`) only works inside a `'use client'` file, because across the RSC boundary the
179
- compound is a client-reference proxy and the sub-property is `undefined`.
180
- - **Polymorphism** uses Base UI's `render` prop, never Radix's `asChild`. When `render` swaps a
181
- button-like component's element for a non-button (e.g. `Button render={<Link/>}`), also pass
182
- `nativeButton={false}` — Base UI warns otherwise.
232
+ - **Compound parts are flat exports** — `import { DialogTrigger, DialogContent }`. There is no
233
+ `Dialog.Trigger`: the parts are separate named exports, never sub-properties of the root.
234
+ - **Polymorphism** uses Base UI's `render` prop, never Radix's `asChild`.
235
+ - **A link that looks like a button is a link** — one recipe:
236
+ `<Link href="…" className={buttonVariants({ variant, size })}>`. Never
237
+ `Button render={<Link/>} nativeButton={false}`: Base UI sets `role="button"` on a non-native
238
+ element, so navigation announces as an action. `buttonVariants` comes from a module with no
239
+ `'use client'`, so a Server Component uses it directly.
183
240
 
184
241
  ## Do / Don't
185
242
 
@@ -192,6 +249,10 @@ contract.
192
249
  - Implement every applicable state: default, hover, focus, loading, empty, error, success, disabled.
193
250
  - Put `truncate` on an inner span, with `min-w-0` on the flex container.
194
251
  - Let the parent decide a form control's width — every control is `w-full`.
252
+ - Set numbers — counts, dates, amounts, quantities — in the regular font with `tabular-nums`, and
253
+ right-align a numeric column. `font-mono` is for code and identifiers (`SYS-1042`) only.
254
+ - Title a page with `PageHeader` (`font-heading text-2xl font-semibold`); a section heading is
255
+ `font-heading text-base font-medium`, a group label `text-xs font-medium text-muted-foreground`.
195
256
  - Reach for a plain Tailwind utility for size, radius, shadow, z-index, alpha, weight and motion:
196
257
  `h-8`, `size-4`, `rounded-xl`, `shadow-md`, `z-50`, `bg-foreground/10`, `opacity-50`,
197
258
  `font-semibold`, `transition-colors duration-100 ease-in-out` are all on-system now.
@@ -219,19 +280,19 @@ contract.
219
280
  silently renders as body text. `vegastack-design doctor` scans your source and lists every
220
281
  occurrence with `file:line`; run it after any upgrade or generated change.
221
282
 
222
- | Retired | Write instead |
223
- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------- |
224
- | `text-h1` · `text-h2` · `text-h3` · `text-h4` | `text-3xl` · `text-2xl` · `text-lg` + `font-semibold`; `text-base font-medium` |
225
- | `text-label` · `text-label-sm` · `text-strong` | `text-sm font-medium` · `text-xs font-medium` · `text-sm font-semibold` |
226
- | `text-mono-label` · `text-code` · `text-code-sm` | `text-xs font-medium` (a label is sans) · `font-mono text-sm` · `font-mono text-xs` |
227
- | `text-display-{sm,md,lg,xl}` | `text-4xl` · `text-5xl` · `text-6xl` · `text-7xl` |
228
- | `bg-{destructive,success,warning,info}-subtle` | `bg-destructive/10` (the family at `/10`), `-text` ink on it |
229
- | `--alpha-*` · `--opacity-*` | the literal: `bg-foreground/10`, `opacity-50` |
230
- | `--z-*` | `z-10` (raised) · `z-50` (every overlay; DOM order decides) |
231
- | `shadow-overlay` · `backdrop-blur-glass` | `shadow-md` (popover) / `shadow-lg` (modal) · delete it |
232
- | `icon-button` · `segmented` | `Button size="icon"` + `aria-label` · joined `ToggleGroup` |
233
- | `progress-indicator` · `field-inline` · `floating-surface` | `Progress` / `Spinner` · `EditableCell` · `Popover` |
234
- | `section-header` · `sonner` | your own heading markup · `toast` (`toast.add({ title })`) |
283
+ | Retired | Write instead |
284
+ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
285
+ | `text-h1` · `text-h2` · `text-h3` · `text-h4` | `PageHeader` (page) · `font-heading text-base font-medium` (section) · `text-lg font-semibold`; `text-base font-medium` |
286
+ | `text-label` · `text-label-sm` · `text-strong` | `text-sm font-medium` · `text-xs font-medium` · `text-sm font-semibold` |
287
+ | `text-mono-label` · `text-code` · `text-code-sm` | `text-xs font-medium` (a label is sans) · `font-mono text-sm` · `font-mono text-xs` |
288
+ | `text-display-{sm,md,lg,xl}` | `text-4xl` · `text-5xl` · `text-6xl` · `text-7xl` |
289
+ | `bg-{destructive,success,warning,info}-subtle` | `bg-destructive/10` (the family at `/10`), `-text` ink on it |
290
+ | `--alpha-*` · `--opacity-*` | the literal: `bg-foreground/10`, `opacity-50` |
291
+ | `--z-*` | `z-10` (raised) · `z-50` (every overlay; DOM order decides) |
292
+ | `shadow-overlay` · `backdrop-blur-glass` | `shadow-md` (popover, menu) · `shadow-lg` (sheet, submenu, toast) · none on a dialog · delete it |
293
+ | `icon-button` · `segmented` | `Button size="icon"` + `aria-label` · joined `ToggleGroup` |
294
+ | `progress-indicator` · `field-inline` · `floating-surface` | `Progress` / `Spinner` · `EditableCell` · `Popover` |
295
+ | `section-header` · `sonner` | your own heading markup · `toast` (`toast.add({ title })`) |
235
296
 
236
297
  ## Reference
237
298
 
@@ -3,7 +3,7 @@
3
3
  <!-- GENERATED — do not hand-edit. Regenerated from the design system's component contract,
4
4
  which is the authority for membership and counts. -->
5
5
 
6
- **112 components**, plus 467 animated-icon items, 11 hooks (`use-animation-replay`, `use-announcer`, `use-drag-reorder`, `use-file-drop`, `use-inline-edit`, `use-list-nav`, `use-media-query`, `use-mobile`, `use-modal-inert`, `use-overflow`, `use-platform`), 4 starter blocks (`app-shell-01`, `board-01`, `login-01`, `settings-01`), 68 chart blocks across 7 families, and 2 data libs (`geo-data`, `drag-item`) — 664 registry items in total.
6
+ **114 components**, plus 467 animated-icon items, 11 hooks (`use-animation-replay`, `use-announcer`, `use-drag-reorder`, `use-file-drop`, `use-inline-edit`, `use-list-nav`, `use-media-query`, `use-mobile`, `use-modal-inert`, `use-overflow`, `use-platform`), 4 starter blocks (`app-shell-01`, `board-01`, `login-01`, `settings-01`), 68 chart blocks across 7 families, and 2 data libs (`geo-data`, `drag-item`) — 666 registry items in total.
7
7
 
8
8
  Install any of them with `shadcn add @vegastack/<name>`. Animated icons install as
9
9
  `@vegastack/icon-<name>`; the bare name is reserved for components, so a component whose name
@@ -22,14 +22,14 @@ starts with `icon-` is a component and never an icon.
22
22
  - **`auto-save-input`** — An input that debounces edits and persists them via an async onSave, with an inline idle/saving/saved/error status.
23
23
  - **`calendar`** — A date-field calendar on React DayPicker — single, multiple and range selection.
24
24
  - **`checkbox`** — A binary (or indeterminate) toggle on Base UI Checkbox, with a 24px invisible hit area (A11Y-2).
25
- - **`chip-input`** — Free-token entry field — Enter/comma/paste commits chips, Backspace removes, per-chip validation marks invalid entries instead of dropping them. Combobox field chrome + real Tag chips.
25
+ - **`chip-input`** — Free-token entry field — Enter/comma/paste commits chips, Backspace removes, per-chip validation marks invalid entries instead of dropping them. InputGroup field chrome + real Tag chips.
26
26
  - **`color-picker`** — A swatch-triggered popover presenting a grid of preset colors — pick one, fire onValueChange, mark the selection.
27
27
  - **`combobox`** — A filterable listbox behind a text input — grouped items, an announced empty state and a chips mode.
28
28
  - **`country-select`** — A searchable country picker returning the ISO 3166-1 alpha-2 code, with flag + name. A thin wrapper over SearchableSelect fed by the geo-data item.
29
29
  - **`date-picker`** — Pick a single date or a date range from a calendar popover — token-styled, keyboard-navigable, with optional quick presets.
30
30
  - **`dropzone`** — File acquisition surface — drop, click-to-browse, and paste — as a thin shell over use-file-drop; the surface is the named focusable control over a hidden picker-bridge input; data-dragging/data-drag-invalid styling flags.
31
31
  - **`editable-cell`** — Inline-editable value with an async commit lifecycle — optimistic display, saving/saved/error status, revert on a rejected write, and a typed text/select/custom editor registry.
32
- - **`emoji-picker`** — A popover with a searchable, category-grouped grid of emoji that returns the selected character via onSelect (curated set, not full Unicode).
32
+ - **`emoji-picker`** — A popover with a searchable, category-grouped grid of emoji that returns the selected character via onValueChange (curated set, not full Unicode).
33
33
  - **`field`** — The form-field scaffold — label, description, error, legend, separator and choice-card layouts.
34
34
  - **`input`** — A styled Base UI input for every text-entry type, with the text-entry focus border tint (FOC-3).
35
35
  - **`input-group`** — An input or textarea with addons — icons, text, buttons, kbd hints and spinners on one surface.
@@ -49,7 +49,7 @@ starts with `icon-` is a component and never an icon.
49
49
 
50
50
  ## Display
51
51
 
52
- - **`chip`** — The one labelled pill primitive — 10 decorative hues, two tiers, an optional selection rung, and a real 24x24 remove control. Behind Tag, FilterChip and Combobox chips.
52
+ - **`chip`** — The one labelled pill primitive — 10 decorative hues, two tiers, an optional selection rung, and a real 24x24 remove control. Behind Tag and FilterChip; ComboboxChip is Base UI's own chip, not this primitive.
53
53
  - **`code-block`** — A code panel with a language header and copy affordance — the shared code surface for chat transcripts, docs, and examples.
54
54
  - **`stat`** — A labelled value block — muted label over a value, honest faint empty state, optional delta line. Two scales.
55
55
  - **`tag-group`** — Hue-tinted label chips on the 10-hue tag palette, with +N overflow collapsing and removable tags.
@@ -81,9 +81,10 @@ starts with `icon-` is a component and never an icon.
81
81
  - **`data-list-pager`** — A controlled paging footer for DataList — a tabular-numeral range summary, a rows-per-page Select, and a windowed Pagination that hides on a single page.
82
82
  - **`data-table-parts`** — The chrome DataList and DataGrid share — sort header, selection cells, skeleton rows, the empty row, column class rules, and the selection/sort/controlled-state hooks.
83
83
  - **`filter-bar`** — A row of removable filter chips, an "Add filter" dropdown, and an optional search input — for list and table filter toolbars.
84
- - **`filter-bar-managed`** — The stateful nested and/or filter builder — host-injected field grammar (vocabulary + per-type value editors), depth and condition caps, focus-managed removal, and a removable FilterChip summary.
84
+ - **`filter-bar-managed`** — The controlled nested and/or filter builder — host-injected field grammar (vocabulary + per-type value editors), depth and condition caps, focus-managed removal, and a removable FilterChip summary.
85
+ - **`load-more`** — The shared Load more footer for keyset lists — an outline button that keeps its width while loading, an error line with Try again, and an optional end caption.
85
86
  - **`property-list`** — Record-facts rows: an icon+label column beside a value column, as an accessible definition list.
86
- - **`sortable-list`** — Reorderable rows on ItemGroup/Item via use-drag-reorder — pointer drag with drop indicators, keyboard move mode, a lossless Move menu, and server-refusable moves. Controlled; the host owns the order.
87
+ - **`sortable-list`** — Reorderable rows or tiles on ItemGroup/Item via use-drag-reorder — pointer drag with drop indicators, keyboard move mode, a lossless row menu, locked rows, inline actions, a grid layout, and server-refusable moves. Controlled; the host owns the order.
87
88
 
88
89
  ## Overlay
89
90
 
@@ -126,7 +127,7 @@ starts with `icon-` is a component and never an icon.
126
127
 
127
128
  - **`app-shell`** — The shared dashboard layout — a skip-linked sidebar + header + scrollable main region, composing Sidebar/SidebarTrigger into one reusable, hash-tracked shell.
128
129
  - **`aspect-ratio`** — Constrains its children to a given width-to-height ratio.
129
- - **`board`** — Kanban columns over use-drag-reorder — content/chrome split (host renders card content only), pointer drag, keyboard move mode + roving focus, lossless per-card Move menu with lock reasons, server-refusable moves, collapsed lanes, Empty-bordered drop targets.
130
+ - **`board`** — Kanban columns over use-drag-reorder — content/chrome split (host renders card content only), pointer drag, keyboard move mode + roving focus, lossless per-card Move menu with lock reasons, server-refusable moves, named lanes with a muted total count, loading and custom empty lanes, collapsed lanes, cards as real links, Empty-bordered drop targets.
130
131
  - **`direction`** — Base UI's DirectionProvider and useDirection — the text-direction context components read.
131
132
  - **`resizable`** — Accessible resizable panel groups and layouts with keyboard support — horizontal or vertical, nestable, with an optional visible grip.
132
133
  - **`scroll-area`** — Augments native scroll functionality for custom, cross-browser styling — a viewport, an auto-hiding scrollbar, and a corner.
@@ -135,10 +136,10 @@ starts with `icon-` is a component and never an icon.
135
136
 
136
137
  ## Media
137
138
 
138
- - **`audio-player`** — A custom audio transport with play/pause, skip, seek, a tappable speed control, and keyboard shortcuts (mute on the M key); a single line on a wide player, two lines with an optional transcript control on a narrow, mobile-width player.
139
+ - **`audio-player`** — A custom audio transport with play/pause, skip, seek, a tappable speed control, and keyboard shortcuts (mute on the M key); a single line on a wide player, two lines with an optional transcript control on a narrow, mobile-width player. Docks to the bottom of a scroll column with a close, resolves a lazy source on first play, and seeks from outside through actionsRef.
139
140
  - **`image`** — A presentational framed image with aspect-ratio, rounding, a loading skeleton, and an error fallback.
140
141
  - **`media-player-controls`** — The shared media transport — play/pause, skip, seek, elapsed/duration, mute + volume, playback speed, and one keyboard shortcut map (useMediaShortcuts) — composed by Audio Player and Video Player.
141
- - **`notification-bell`** — A bell icon button with an unread-count badge overlay. Presentational — the app supplies the count.
142
+ - **`notification-bell`** — A bell icon button with an unread-count badge overlay, plus the shared NotificationDot unread marker. Presentational — the app supplies the count.
142
143
  - **`video-player`** — A framed video player with the same grouped custom transport controls as Audio Player.
143
144
 
144
145
  ## Rich text
@@ -151,12 +152,13 @@ starts with `icon-` is a component and never an icon.
151
152
 
152
153
  ## Communication
153
154
 
154
- - **`attachment`** — A file chip / thumbnail card for chat and message-compose surfaces — media slot, name + meta, idle/uploading/processing/error/done states, an actions row and a full-bleed trigger.
155
+ - **`attachment`** — A file chip / thumbnail card for chat, record-file and upload-queue surfaces — media slot, name + meta, idle/uploading/processing/error/done states, determinate progress, a muted tile, an actions row, a full-bleed trigger, and a scrolling or grid group.
155
156
  - **`bubble`** — A chat speech bubble - 7 token-driven variants (incl. brand-tinted), start/end alignment, interactive content, and a floating reactions chip.
156
157
  - **`marker`** — An inline conversation marker - status lines, system notes, and labelled dividers. 3 variants, Base UI render-polymorphic.
157
158
  - **`message`** — Layout primitives for a conversation row - avatar anchoring, content column, header/footer slots, start/end alignment. Server-safe.
158
- - **`message-scroller`** — A virtualised, auto-scrolling conversation viewport - pins to the latest message, preserves position on prepend, tracks the anchor, and a floating scroll-to-end button.
159
+ - **`message-scroller`** — An auto-scrolling conversation viewport (not virtualised) - pins to the latest message, preserves position on prepend, tracks the anchor, and a floating scroll-to-end button.
159
160
  - **`questionnaire`** — A guided one-question-at-a-time form — choices, freeform answers, skip, shortcuts, validation, resume and conditional items, built on the @shadcn/react questionnaire state machine.
161
+ - **`transcript`** — A timestamped, speaker-labelled transcript on MessageScroller's primitive - marks the line playing at currentTime, follows it, pauses on a user scroll with a Back to current line button, seeks from each timestamp, and searches with highlighted, announced matches.
160
162
 
161
163
  ## Marketing
162
164