@vegastack/design 0.4.1 → 0.5.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.
@@ -3,74 +3,72 @@
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
- **116 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`), 1 starter block (`dashboard-01`), and 2 data libs (`geo-data`, `drag-item`) — 597 registry items in total.
6
+ **109 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`), 32 starter blocks (`app-shell-01`, `board-01`, `dashboard-01`, `login-01`, `login-02`, `login-03`, `login-04`, `login-05`, `onboarding-01`, `preview-03`, `settings-01`, `sidebar-01`, `sidebar-02`, `sidebar-03`, `sidebar-04`, `sidebar-05`, `sidebar-06`, `sidebar-07`, `sidebar-08`, `sidebar-09`, `sidebar-10`, `sidebar-11`, `sidebar-12`, `sidebar-13`, `sidebar-14`, `sidebar-15`, `sidebar-16`, `signup-01`, `signup-02`, `signup-03`, `signup-04`, `signup-05`), 68 chart blocks across 7 families, and 2 data libs (`geo-data`, `drag-item`) — 689 registry items in total.
7
7
 
8
8
  Install any of them with `shadcn add @vegastack/<name>`. Animated icons install as
9
- `@vegastack/icon-<name>`; the bare name is reserved for components, so `icon-button` is the
10
- component and never an icon.
9
+ `@vegastack/icon-<name>`; the bare name is reserved for components, so a component whose name
10
+ starts with `icon-` is a component and never an icon.
11
11
 
12
12
  ## Actions
13
13
 
14
- - **`button`** — Trigger an action. Six variants × five tones × four sizes, with loading + Base UI Button semantics.
14
+ - **`button`** — Trigger an action — upstream's six variants and eight sizes, plus a loading state (API-5).
15
+ - **`button-group`** — Joins buttons, inputs, selects and dropdowns into one connected control group — horizontal or vertical, with a separator and a text addon.
15
16
  - **`copy-button`** — Copy a value to the clipboard with transient check feedback — a ghost icon button that swaps Copy → Check and fires onCopied.
16
- - **`icon-button`** — A square or round icon-only action button — a thin Button wrapper that requires an accessible label.
17
- - **`segmented`** — Segmented control — a single-select, always-one-selected view/mode switcher on a muted track with a raised active chip.
18
- - **`split-button`** — A primary action joined to a dropdown of related secondary actions — one default click, plus a chevron menu.
19
- - **`toggle`** — A two-state button that can be pressed on or off — bold/italic, mute, pin.
20
- - **`toggle-group`** — Joined toggle buttons sharing one selection — single or multiple, variants/sizes, horizontal/vertical, full keyboard navigation.
17
+ - **`toggle`** — A two-state button that can be pressed on or off, with a loading state (API-5).
18
+ - **`toggle-group`** — Toggle buttons sharing one selection — single or multiple, horizontal or vertical.
21
19
 
22
20
  ## Form
23
21
 
24
22
  - **`auto-save-input`** — An input that debounces edits and persists them via an async onSave, with an inline idle/saving/saved/error status.
25
- - **`checkbox`** — A binary (or tri-state) toggle — checked, unchecked, indeterminate, disabled, built on Base UI Checkbox.
26
- - **`checkbox-group`** — Shared state for a set of checkboxes, with first-class “select all” — parent, mixed, and the whole-set toggle, built on Base UI Checkbox Group.
23
+ - **`calendar`** — A date-field calendar on React DayPicker — single, multiple and range selection.
24
+ - **`checkbox`** — A binary (or indeterminate) toggle on Base UI Checkbox, with a 24px invisible hit area (A11Y-2).
27
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.
28
26
  - **`color-picker`** — A swatch-triggered popover presenting a grid of preset colors — pick one, fire onValueChange, mark the selection.
29
- - **`combobox`** — A filterable, keyboard-navigable listbox behind a text input — type-to-filter, grouped items, async status, and a multi-select chip mode.
27
+ - **`combobox`** — A filterable listbox behind a text input — grouped items, an announced empty state and a chips mode.
30
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.
31
29
  - **`date-picker`** — Pick a single date or a date range from a calendar popover — token-styled, keyboard-navigable, with optional quick presets.
32
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.
33
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.
34
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).
35
- - **`field`** — A form-field wrapper — label, inline label action, description, and error/success message, built on Base UI Field.
36
- - **`field-inline`** — Click-to-edit text — displays a value, swaps to a focused input on click, commits on Enter or blur, cancels on Escape.
37
- - **`input`** — A styled Base UI input — all input types, Field state data attributes, error and disabled states, a focus border tint, and optional prefix/suffix addons.
38
- - **`label`** — A styled native label for form controls — htmlFor association, disabled dimming, optional required indicator.
39
- - **`number-field`** — Locale-aware numeric input on Base UI's NumberField in Input's field chrome — Intl formatting (money is a format prop), min/max/step, keyboard stepping, wheel scrub, full-height steppers.
40
- - **`otp-input`** — A multi-slot one-time-passcode input — keyboard navigation, paste distribution, masking, disabled, built on Base UI OTP Field.
41
- - **`password-input`** — A password field with a show/hide eye toggle and an optional live requirements checklist.
42
- - **`radio-group`** — A set of mutually-exclusive options — single selection, arrow-key navigation, disabled, built on Base UI Radio Group.
33
+ - **`field`** — The form-field scaffold — label, description, error, legend, separator and choice-card layouts.
34
+ - **`input`** — A styled Base UI input for every text-entry type, with the text-entry focus border tint (FOC-3).
35
+ - **`input-group`** — An input or textarea with addons — icons, text, buttons, kbd hints and spinners on one surface.
36
+ - **`input-otp`** — A one-time-password field with per-character slots, driven by one hidden input.
37
+ - **`label`** — A styled native label for form controls.
38
+ - **`native-select`** — The platform <select>, tokenized — the OS picker on mobile, with option groups.
39
+ - **`number-field`** — Locale-aware numeric input on Base UI's NumberField in upstream's InputGroup chrome, with full-height flanking steppers.
40
+ - **`radio-group`** — Mutually-exclusive options with arrow-key navigation and a 24px invisible hit area (A11Y-2).
43
41
  - **`region-select`** — A searchable picker of states/provinces for a country, with a free-text fallback for countries with no subdivisions. A thin wrapper over SearchableSelect fed by the geo-data item.
44
42
  - **`searchable-select`** — The Select-shaped Combobox preset: a full-width trigger, an in-panel search field, a check on the selected row and an optional clear control. Single-select, controlled through value/onValueChange.
45
- - **`select`** — A dropdown for choosing one option — trigger with value and chevron, grouped scrollable popup, full keyboard navigation, animated enter/exit.
46
- - **`slider`** — Pick a number or a [from, to] range from a continuous track — keyboard accessible, with optional steps. Built on Base UI Slider.
47
- - **`switch`** — An on/off toggle for instant, self-saving binary settings — built on Base UI Switch.
48
- - **`textarea`** — A styled native textarea for multi-line text — error/disabled states, a focus border tint, and an optional auto-grow mode.
43
+ - **`select`** — A dropdown for one value — trigger, grouped scrollable popup and item-aligned positioning.
44
+ - **`slider`** — A number or range over a continuous track — horizontal or vertical, any number of thumbs.
45
+ - **`switch`** — An on/off toggle for instant settings — two sizes and a 24px invisible hit area (A11Y-2).
46
+ - **`textarea`** — A styled native textarea that grows with its content, with the text-entry focus border tint (FOC-3).
49
47
 
50
48
  ## Display
51
49
 
52
50
  - **`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.
53
51
  - **`code-block`** — A code panel with a language header and copy affordance — the shared code surface for chat transcripts, docs, and examples.
54
- - **`onboarding-checklist`** — A getting-started card — segmented progress + step rows, collapsible to a progress pill.
55
52
  - **`stat`** — A labelled value block — muted label over a value, honest faint empty state, optional delta line. Two scales.
56
53
  - **`tag-group`** — Hue-tinted label chips on the 10-hue tag palette, with +N overflow collapsing and removable tags.
57
54
 
58
55
  ## Data display
59
56
 
60
- - **`accordion`** — A stack of collapsible sections — single or multiple open, animated height, a rotating chevron, full keyboard support.
57
+ - **`accordion`** — A vertically stacked set of interactive headings that each reveal a section of content — one open at a time, or several.
61
58
  - **`animated-number`** — A number display that tweens from its previous value to a new one on every change — Intl.NumberFormat-aware (currency/percent/compact), instant under reduced motion, the dashboard stat-card counter.
62
- - **`avatar`** — A circular user/entity image with an initials fallback, five sizes, and an overlapping AvatarGroup stack.
63
- - **`badge`** — A compact status or label chip — solid / soft / outline / minimal × 5 semantic colors × 3 real size tiers, with a dot, a leading icon, and loading.
64
- - **`card`** — A borders-only content surface — no shadows, with composable header, content, and footer parts.
65
- - **`chart`** — A themed Recharts wrapper — token-only series colors (--chart-1…--chart-8), a bordered tooltip/legend, and Recharts' own built-in keyboard + screen-reader layer.
66
- - **`collapsible`** — A single toggleable open/close region with an animated height, built on Base UI Collapsible.
67
- - **`empty`** — A zero-data placeholder — icon, title, description, actions, with intent tints and a plain, card, or dashed container.
68
- - **`item`** — A compact anatomy row for list/feed content — media, title, description, actions, groupable with dividers.
69
- - **`kbd`** — The one keyboard-key chip — modifier labels the caller resolves per platform, a keys array, and three inline sizes.
59
+ - **`avatar`** — A circular user or entity image with a fallback, a badge, and an overlapping group.
60
+ - **`badge`** — A compact label or status chip — upstream's six variants plus our four status tones (COL-12).
61
+ - **`card`** — A content surface with composable header, content, footer and action parts.
62
+ - **`carousel`** — A slide track with previous and next controls — horizontal or vertical, any slide size or spacing, Embla options, events and plugins.
63
+ - **`chart`** — A themed Recharts wrapper — a ChartConfig that maps each series to a colour and a label, a bordered tooltip and legend, and Recharts' own built-in keyboard + screen-reader layer.
64
+ - **`collapsible`** — An interactive component which expands and collapses a panel, with an animated height and a trigger you supply.
65
+ - **`empty`** — A zero-data placeholder — media, title, description and a content slot.
66
+ - **`item`** — A composable row for list and feed content — media, title, description, actions.
67
+ - **`kbd`** — A keyboard-key chip, and a group that lays several of them out inline.
70
68
  - **`markdown-view`** — Render a markdown string to safe, token-styled HTML — headings, lists, code, blockquotes, links, GFM tables — XSS-safe, no raw HTML.
71
69
  - **`relative-time`** — Render a date as a human-relative string ("2 hours ago", "yesterday") with native Intl.RelativeTimeFormat — self-updating, with an absolute-date tooltip.
72
70
  - **`status-icon`** — A small status indicator icon — todo, in progress, blocked, done — each mapping to a lucide icon and semantic color.
73
- - **`table`** — Styled semantic table primitives — a scrollable container plus header, body, footer, row, head, cell, caption.
71
+ - **`table`** — A responsive table component — caption, header, body, footer, row, head and cell parts over semantic table markup.
74
72
  - **`timeline`** — Rail geometry for chronological records — a continuous connector with a node per entry. Rows compose Item parts; separators render through Marker; entries carry content-visibility render skipping.
75
73
  - **`truncated-text`** — Truncate text to one line or N lines with an ellipsis, revealing the full text in a tooltip only when it overflows — with per-region control over the tab stop.
76
74
 
@@ -86,46 +84,50 @@ component and never an icon.
86
84
 
87
85
  ## Overlay
88
86
 
89
- - **`alert-dialog`** — A modal confirmation dialog with four semantic intents — non-dismissable, forcing a deliberate Cancel/confirm choice.
90
- - **`context-menu`** — A menu of actions revealed by right-click (or long-press) — items, submenus, separators, labels, shortcuts, checkbox/radio.
91
- - **`dialog`** — A modal overlay — five sizes, a header/footer layout, focus trapping, and animated enter/exit.
92
- - **`dropdown-menu`** — A menu of actions triggered by a button — items, submenus, separators, labels, shortcuts, and checkbox/radio selections.
93
- - **`floating-surface`** — The shared floating-overlay module: one Portal/Positioner/Popup composer, the popup surface recipes, the list-item recipe, and the in-panel search row.
94
- - **`hover-card`** — A rich preview panel that opens on hover or focus — interactive content, four directions, forgiving delays.
95
- - **`popover`** — A click-triggered floating panel for arbitrary content — positioning, an optional arrow, and built-in dismiss.
96
- - **`sheet`** — A dialog that slides in from a screen edge — four sides, header/footer layout, focus trapping, animated slide.
87
+ - **`alert-dialog`** — A modal that interrupts for a decision — an optional media slot, two sizes and an action/cancel footer.
88
+ - **`context-menu`** — The same menu vocabulary opened by right-click, positioned at the pointer.
89
+ - **`dialog`** — A modal overlay — a backdrop, a centred popup, an optional close button and a sticky footer band.
90
+ - **`drawer`** — A swipeable panel with snap points — four directions, a swipe handle, nesting and a non-modal mode.
91
+ - **`dropdown-menu`** — An anchored action menu — items, submenus, checkboxes, radio groups, shortcuts and a destructive variant.
92
+ - **`hover-card`** — A preview surface that opens on hover or focus, with configurable delays and sides.
93
+ - **`panel-search`** — The sticky, box-free search row a filtering popup puts at the top of its panel (decision OVL-11) — shared by EmojiPicker and ShortcutOverlay.
94
+ - **`popover`** — An anchored, dismissible surface for secondary content, with a header, title and description.
95
+ - **`sheet`** — A panel that slides in from any edge — Dialog semantics with a side, a header and a footer.
97
96
  - **`shortcut-overlay`** — The ?-triggered dialog listing keyboard shortcuts, rendered from a declaration registry (keys, label, category, when) — grouped, filterable, platform-aware via use-platform + Kbd.
98
- - **`tooltip`** — A floating label on hover or focus — smart shared delay, rich content, optional keyboard hints, collision-aware positioning.
97
+ - **`tooltip`** — A floating label on hover or focus, portaled inside the theme scope (OVL-13).
99
98
 
100
99
  ## Navigation
101
100
 
102
101
  - **`breadcrumb`** — A hierarchical navigation trail — links, separators, the current page, and ellipsis collapse for long paths.
103
102
  - **`command`** — A searchable command palette — filtered, grouped items with keyboard navigation, optionally inside a ⌘K dialog.
104
- - **`navigation-menu`** — Site-nav mega-dropdown on the Base UI NavigationMenu primitive — chip triggers, one shared sliding panel, grid links.
103
+ - **`menubar`** — A persistent horizontal bar of menus — application-style File / Edit / View navigation.
104
+ - **`navigation-menu`** — A collection of links for navigating websites — triggers that open one shared panel, and plain links styled to match.
105
105
  - **`page-header`** — The standardized header at the top of a page — back button, breadcrumb trail, title, description, actions, secondary menu, and a favorite star.
106
106
  - **`pagination`** — Page navigation — previous/next, numbered page links, an ellipsis for long ranges, and the active page.
107
- - **`sidebar`** — A collapsible app navigation rail — header/content/footer, labelled groups, menu items with active state, and an expand/collapse trigger.
107
+ - **`sidebar`** — A composable, themeable and customizable sidebar — a provider, a collapsible panel with header, content and footer, labelled groups, menu rows with actions, badges and submenus, a rail and a trigger.
108
108
  - **`stepper`** — A bounded linear process as an ordered list — complete/current/upcoming/error states on StatusIcon's vocabulary, aria-current=step, advance-gating message, focus follows the process.
109
- - **`tabs`** — Layered content sections — line or pill variants, optional icons and count badges, horizontal or vertical, full keyboard navigation.
109
+ - **`tabs`** — A set of layered sections of content — known as tab panels — that are displayed one at a time.
110
110
 
111
111
  ## Feedback
112
112
 
113
113
  - **`action-bar`** — Floating contextual bar — status region + action children, CSS-only enter/exit, raised band. Bulk selection, unsaved changes, and batch progress are recipes over it.
114
- - **`alert`** — A status banner — five semantic variants, an optional icon, and an optional dismiss button.
115
- - **`progress`** — A horizontal progress bar for measurable, ongoing tasks — determinate or a sweeping indeterminate segment, built on Base UI Progress.
116
- - **`progress-indicator`** — A compact circular pie-fill progress indicator (0–100%) with optional visible percentage variants.
114
+ - **`alert`** — A status banner — upstream's two variants plus our three extra status tones (COL-12).
115
+ - **`progress`** — Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
117
116
  - **`provider`** — The single app-root wrapper — theme (next-themes), Base UI toasts, tooltip delays, and text direction in one mount-once component.
118
- - **`skeleton`** — A token-driven loading placeholder — line, circle, rect, card shapes, a configurable count, and a pulse that stops under reduced motion.
119
- - **`spinner`** — An indeterminate loading indicator — a spinning icon inheriting currentColor, four sizes, role=status by default.
120
- - **`toast`** — Brief, non-blocking notifications — a stacking Base UI Toast surface with success, error, warning, info and loading types, promise toasts and swipe-to-dismiss.
117
+ - **`skeleton`** — A pulsing placeholder that reserves layout space while content loads.
118
+ - **`sonner`** — The sonner toaster, themed onto the token contract — an alternative notification engine with its own imperative API.
119
+ - **`spinner`** — An indeterminate loading indicator that inherits its host's ink.
120
+ - **`toast`** — Brief, non-blocking notifications — a stacking Base UI Toast surface with typed icons, actions and promise toasts.
121
121
 
122
122
  ## Layout
123
123
 
124
124
  - **`app-shell`** — The shared dashboard layout — a skip-linked sidebar + header + scrollable main region, composing Sidebar/SidebarTrigger into one reusable, hash-tracked shell.
125
+ - **`aspect-ratio`** — Constrains its children to a given width-to-height ratio.
125
126
  - **`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.
126
- - **`resizable`** — Draggable, keyboard-resizable split panes — horizontal or vertical, nestable, with an optional collapsible panel. Built on react-resizable-panels.
127
- - **`scroll-area`** — A scroll container with custom, auto-hiding scrollbars — dual-axis, token-styled, built on Base UI ScrollArea.
128
- - **`separator`** — A thin rule dividing content — horizontal or vertical, decorative by default, built on Base UI.
127
+ - **`direction`** — Base UI's DirectionProvider and useDirection — the text-direction context components read.
128
+ - **`resizable`** — Accessible resizable panel groups and layouts with keyboard support — horizontal or vertical, nestable, with an optional visible grip.
129
+ - **`scroll-area`** — Augments native scroll functionality for custom, cross-browser styling — a viewport, an auto-hiding scrollbar, and a corner.
130
+ - **`separator`** — A thin rule dividing content — horizontal or vertical, built on Base UI.
129
131
  - **`settings-row`** — A borders-only settings layout — titled sections, bordered cards, and label-plus-control rows.
130
132
 
131
133
  ## Media
@@ -146,26 +148,14 @@ component and never an icon.
146
148
 
147
149
  ## Communication
148
150
 
149
- - **`attachment`** — A file chip / thumbnail card for chat and message-compose surfaces - media slot, name + meta, uploading/error/complete states, remove/download actions.
151
+ - **`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.
150
152
  - **`bubble`** — A chat speech bubble - 7 token-driven variants (incl. brand-tinted), start/end alignment, interactive content, and a floating reactions chip.
151
153
  - **`marker`** — An inline conversation marker - status lines, system notes, and labelled dividers. 3 variants, Base UI render-polymorphic.
152
154
  - **`message`** — Layout primitives for a conversation row - avatar anchoring, content column, header/footer slots, start/end alignment. Server-safe.
153
155
  - **`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.
156
+ - **`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.
154
157
 
155
158
  ## Marketing
156
159
 
157
160
  - **`announcement-banner`** — A dismissible one-line announcement — the full-width inverse page-top band (in-content notices use Alert variant=strip).
158
- - **`comparison-matrix`** — A plan-feature matrix with accessible ✓/− availability cells and a highlighted plan column.
159
- - **`figure-frame`** — A sharp-cornered media frame with an optional mono FIG-annotation caption.
160
- - **`logo-row`** — A muted logo/wordmark strip — alpha-dimmed at rest, restoring on hover for linked items.
161
- - **`marketing-surface`** — Opts a subtree into the brand's dark warm ground, independent of the page's .dark class.
162
- - **`particle-field`** — A deterministic, very-low-alpha canvas field of drifting phosphor dots — hero atmosphere only.
163
- - **`pricing-section`** — Marketing plan cards — mono price display, check feature lists, highlighted-plan treatment.
164
- - **`ruled-band`** — A hairline-bounded editorial strip with mono-label ends — the changelog/serial-number furniture.
165
- - **`section-header`** — A marketing section lead-in — mono uppercase eyebrow, display-scale title, optional description.
166
161
  - **`terminal`** — A dark mono command block with a phosphor prompt glyph and a composed copy button.
167
- - **`testimonial`** — A pull-quote — a serif-italic quote over a mono uppercase attribution line.
168
-
169
- ## Marketing motion
170
-
171
- - **`staggered-text-reveal`** — Display text whose words rise in on mount, staggered one motion-enter-up step apart — CSS-only.
@@ -1,186 +0,0 @@
1
- // src/index.ts
2
- import { clsx } from "clsx";
3
- import { extendTailwindMerge } from "tailwind-merge";
4
-
5
- // src/prose.ts
6
- var prose = {
7
- /** The root's own ink and size — every rule below is relative to this. */
8
- root: "text-base text-foreground",
9
- // Headings. `scroll-m-20` keeps an anchored heading clear of a sticky header; the weight ladder
10
- // caps at 500, which the `text-h*` roles already carry.
11
- h1: "[&_h1]:mt-6 [&_h1]:mb-3 [&_h1]:scroll-m-20 [&_h1]:text-h1 [&_h1]:text-foreground [&_h1]:first:mt-0",
12
- h2: "[&_h2]:mt-6 [&_h2]:mb-3 [&_h2]:scroll-m-20 [&_h2]:text-h2 [&_h2]:text-foreground [&_h2]:first:mt-0",
13
- h3: "[&_h3]:mt-5 [&_h3]:mb-2 [&_h3]:scroll-m-20 [&_h3]:text-h3 [&_h3]:text-foreground [&_h3]:first:mt-0",
14
- h4: "[&_h4]:mt-4 [&_h4]:mb-2 [&_h4]:scroll-m-20 [&_h4]:text-h4 [&_h4]:text-foreground [&_h4]:first:mt-0",
15
- // h5/h6 leave the display tier and become labels — the type scale has no sixth heading size.
16
- h5: "[&_h5]:mt-4 [&_h5]:mb-2 [&_h5]:text-label [&_h5]:text-foreground [&_h5]:first:mt-0",
17
- h6: "[&_h6]:mt-4 [&_h6]:mb-2 [&_h6]:text-label [&_h6]:text-muted-foreground [&_h6]:first:mt-0",
18
- p: "[&_p]:my-3 [&_p]:leading-relaxed [&_p]:text-foreground [&_p]:first:mt-0 [&_p]:last:mb-0",
19
- // Marks. Links are `info` ink per design.md §Colours; `s` is Tiptap's strike element and `del`
20
- // is GFM's — the same mark from two producers.
21
- a: "[&_a]:font-medium [&_a]:text-info-text [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-info-text/(--alpha-link-hover)",
22
- strong: "[&_strong]:font-medium [&_strong]:text-foreground",
23
- em: "[&_em]:italic",
24
- del: "[&_del]:text-muted-foreground [&_del]:line-through [&_s]:text-muted-foreground [&_s]:line-through",
25
- // Lists. A GFM task list carries `contains-task-list` and its checkbox IS the marker, so the
26
- // disc goes — expressed as a second, more specific descendant rule rather than a class on the
27
- // element, which would lose the cascade (see the header).
28
- ul: "[&_ul]:my-3 [&_ul]:ms-6 [&_ul]:list-disc [&_ul]:text-foreground [&_ul]:marker:text-muted-foreground [&_ul.contains-task-list]:list-none",
29
- ol: "[&_ol]:my-3 [&_ol]:ms-6 [&_ol]:list-decimal [&_ol]:text-foreground [&_ol]:marker:text-muted-foreground",
30
- li: "[&_li]:mt-1.5 [&_li]:leading-relaxed",
31
- blockquote: "[&_blockquote]:my-3 [&_blockquote]:border-s-2 [&_blockquote]:border-border [&_blockquote]:ps-4 [&_blockquote]:text-muted-foreground [&_blockquote]:italic",
32
- // Inline code is a chip. Code inside a `pre` is not: it inherits the panel's ground, so the chip
33
- // is undone at higher specificity (`[&_pre_code]` is (0,1,2) against the chip's (0,1,1)).
34
- code: "[&_code]:rounded-sm [&_code]:bg-muted [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-base [&_code]:text-foreground",
35
- // A bare `<pre>` wears `CodeBlock`'s surface — the same sunken panel, one vocabulary (B4-09).
36
- // `CodeBlock`'s own `pre` is excluded: it already sits inside a `figure` carrying the border,
37
- // radius and ground, and re-applying them here would draw a second panel inside the first.
38
- pre: "[&_pre:not([data-slot='code-block-pre'])]:my-3 [&_pre:not([data-slot='code-block-pre'])]:overflow-x-auto [&_pre:not([data-slot='code-block-pre'])]:rounded-lg [&_pre:not([data-slot='code-block-pre'])]:border [&_pre:not([data-slot='code-block-pre'])]:border-border [&_pre:not([data-slot='code-block-pre'])]:bg-muted [&_pre:not([data-slot='code-block-pre'])]:p-4 [&_pre:not([data-slot='code-block-pre'])]:text-foreground",
39
- preCode: "[&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:font-mono [&_pre_code]:text-code [&_pre_code]:text-foreground",
40
- hr: "[&_hr]:my-6 [&_hr]:border-border",
41
- // GFM tables. The scroll container is structural and belongs to the consumer (MarkdownView wraps
42
- // the table in an `overflow-x-auto` div); these are the cell and rule tokens.
43
- table: "[&_table]:w-full [&_table]:border-collapse [&_table]:text-base [&_table]:text-foreground [&_thead]:border-b [&_thead]:border-border [&_tr]:border-b [&_tr]:border-border [&_tr]:last:border-0 [&_th]:px-3 [&_th]:py-2 [&_th]:text-start [&_th]:font-medium [&_th]:text-foreground [&_td]:px-3 [&_td]:py-2 [&_td]:text-muted-foreground",
44
- img: "[&_img]:my-3 [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-border"
45
- };
46
- var proseClassName = Object.values(prose).join(" ");
47
-
48
- // src/index.ts
49
- var twMerge = extendTailwindMerge({
50
- extend: {
51
- classGroups: {
52
- "font-size": [
53
- {
54
- text: [
55
- "h1",
56
- "h2",
57
- "h3",
58
- "h4",
59
- "label",
60
- "label-sm",
61
- "code",
62
- "code-sm",
63
- "mono-label",
64
- "display-sm",
65
- "display-md",
66
- "display-lg",
67
- "display-xl"
68
- ]
69
- }
70
- ]
71
- }
72
- }
73
- });
74
- function cn(...inputs) {
75
- return twMerge(clsx(inputs));
76
- }
77
- var surfaceInteractive = "hover:bg-surface-2 active:bg-surface-3";
78
- var surfaceInteractiveGroup = "group-hover/wash:bg-surface-2 group-active/wash:bg-surface-3";
79
- var fillInteractive = {
80
- foreground: "hover:bg-foreground/(--alpha-hover) active:bg-foreground/(--alpha-pressed)",
81
- primary: "hover:bg-primary/(--alpha-hover) active:bg-primary/(--alpha-pressed)",
82
- destructive: "hover:bg-destructive/(--alpha-hover) active:bg-destructive/(--alpha-pressed)",
83
- success: "hover:bg-success/(--alpha-hover) active:bg-success/(--alpha-pressed)",
84
- warning: "hover:bg-warning/(--alpha-hover) active:bg-warning/(--alpha-pressed)",
85
- info: "hover:bg-info/(--alpha-hover) active:bg-info/(--alpha-pressed)",
86
- brand: "hover:bg-brand/(--alpha-hover) active:bg-brand/(--alpha-pressed)"
87
- };
88
- var fieldControl = [
89
- "rounded-md border border-input bg-transparent dark:bg-input/(--alpha-input)",
90
- "placeholder:text-muted-foreground-faint",
91
- "not-disabled:not-data-disabled:hover:border-foreground/(--alpha-border-subtle)",
92
- "focus:border-ring/(--alpha-tint-border)",
93
- "not-focus:aria-invalid:border-destructive-border/(--alpha-tint-border)",
94
- "not-focus:data-invalid:border-destructive-border/(--alpha-tint-border)",
95
- "disabled:cursor-not-allowed disabled:bg-surface-1 disabled:opacity-(--opacity-dim)",
96
- "data-disabled:cursor-not-allowed data-disabled:bg-surface-1 data-disabled:opacity-(--opacity-dim)"
97
- ].join(" ");
98
- var fieldControlGroup = [
99
- "rounded-md border border-input bg-transparent dark:bg-input/(--alpha-input)",
100
- "not-has-disabled:not-data-disabled:hover:border-foreground/(--alpha-border-subtle)",
101
- "focus-within:border-ring/(--alpha-tint-border)",
102
- "data-focused:border-ring/(--alpha-tint-border)",
103
- // Both the SELF and the DESCENDANT form of the invalid tint (2026-09-09). `has-aria-invalid:` is
104
- // a `:has()` over descendants, so a group that carries `aria-invalid` on ITSELF — which is where
105
- // `<NumberField aria-invalid />` lands the attribute, on the `[data-field-group]` element —
106
- // matched nothing and measured the neutral `--input` border. Inside a `Field` the state arrives
107
- // as `data-invalid` on the group and was always correct; this is the standalone path.
108
- "not-focus-within:aria-invalid:border-destructive-border/(--alpha-tint-border)",
109
- "not-focus-within:has-aria-invalid:border-destructive-border/(--alpha-tint-border)",
110
- "not-focus-within:data-invalid:border-destructive-border/(--alpha-tint-border)",
111
- "has-disabled:cursor-not-allowed has-disabled:bg-surface-1 has-disabled:opacity-(--opacity-dim)",
112
- "data-disabled:cursor-not-allowed data-disabled:bg-surface-1 data-disabled:opacity-(--opacity-dim)"
113
- ].join(" ");
114
- var selectedChipVariants = {
115
- /**
116
- * The muted track the chips sit in — the ladder's well rung with a drawn inset boundary. The
117
- * pseudo-element keeps the 28 / 32px track boxes unchanged; a real root border would add 2px and
118
- * silently break the shared control scale.
119
- */
120
- track: "relative bg-surface-1 after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-border after:content-['']",
121
- /**
122
- * Chrome shared by every chip: a transparent hairline reserved at rest (so selecting adds no
123
- * layout shift) and the muted→ink text step.
124
- */
125
- item: "border border-transparent hover:text-foreground",
126
- /** Selected keyed on Base UI's `data-pressed` — Toggle, ToggleGroup, Segmented. */
127
- pressed: "not-data-pressed:hover:bg-foreground/(--alpha-hover) not-data-pressed:active:bg-foreground/(--alpha-pressed) data-pressed:border-border data-pressed:bg-foreground/(--alpha-ink-tint) data-pressed:text-foreground data-pressed:hover:bg-foreground/(--alpha-ink-tint-strong) data-pressed:active:bg-foreground/(--alpha-ink-tint)",
128
- /** Selected keyed on Base UI's `data-active` — Tabs. */
129
- active: "not-data-[active]:hover:bg-foreground/(--alpha-hover) not-data-[active]:active:bg-foreground/(--alpha-pressed) data-[active]:border-border data-[active]:bg-foreground/(--alpha-ink-tint) data-[active]:text-foreground data-[active]:hover:bg-foreground/(--alpha-ink-tint-strong) data-[active]:active:bg-foreground/(--alpha-ink-tint)"
130
- };
131
- var TIMINGS = {
132
- /** How long transient success feedback holds before reverting (CopyButton "Copied ✓"). */
133
- feedbackRevertMs: 1500,
134
- /** Debounce before auto-persisting a text field (AutoSaveInput). */
135
- autoSaveDebounceMs: 800,
136
- /** Hover delay before a rich preview (HoverCard) opens — guards accidental opens. */
137
- hoverOpenDelayMs: 700,
138
- /** Hover delay before a rich preview closes — lets the pointer travel into the card. */
139
- hoverCloseDelayMs: 300,
140
- /**
141
- * Hover delay before a tooltip opens. A tooltip is a cheap label, not a preview, so it is
142
- * deliberately much faster than {@link TIMINGS.hoverOpenDelayMs} — long enough that sweeping
143
- * across a toolbar does not flash five tips, short enough that a deliberate hover feels
144
- * instant. Base UI's `Tooltip.Provider` grouping then opens adjacent tips with no delay at
145
- * all. Set once, in the app-root provider.
146
- */
147
- tooltipOpenDelayMs: 300,
148
- /**
149
- * Delay before a tooltip closes. Zero: a tooltip has nothing to travel into (it is not
150
- * hoverable content, unlike a HoverCard), so holding it after the pointer leaves only
151
- * obscures what the user moved on to.
152
- */
153
- tooltipCloseDelayMs: 0
154
- };
155
- var FLOATING = {
156
- sideOffsetAttached: 4,
157
- sideOffsetDetached: 8,
158
- collisionPadding: 8
159
- };
160
- function mergeRefs(...refs) {
161
- return (node) => {
162
- for (const ref of refs) {
163
- if (ref == null) continue;
164
- if (typeof ref === "function") {
165
- ref(node);
166
- } else {
167
- ref.current = node;
168
- }
169
- }
170
- };
171
- }
172
-
173
- export {
174
- prose,
175
- proseClassName,
176
- cn,
177
- surfaceInteractive,
178
- surfaceInteractiveGroup,
179
- fillInteractive,
180
- fieldControl,
181
- fieldControlGroup,
182
- selectedChipVariants,
183
- TIMINGS,
184
- FLOATING,
185
- mergeRefs
186
- };