@windforge/ui 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/llms.txt +592 -0
  4. package/package.json +10 -5
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anthony Gorman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # @windforge/ui
2
+
3
+ React components for **Windforge** — a composable, configurable, strict design
4
+ system built on **Radix + Tailwind** with CSS-variable tokens and zero CSS-in-JS
5
+ runtime.
6
+
7
+ You build with two surfaces:
8
+
9
+ - **Components** take intent-named props (`variant="primary"`, `padding="card"`,
10
+ `gap="md"`, `tone="muted"`) that expose only on-system options — `className` and
11
+ `style` are rejected at the type level, so there's no path off-system. The
12
+ escape hatch is the three layout primitives `Box` / `Stack` / `Grid`, which
13
+ **do** accept `className` (including Tailwind arbitrary values like `w-[37%]`)
14
+ and `style`. So the rare break-glass case stays contained to three named places.
15
+ - **Tokens** (`--wf-*` CSS variables, from [`@windforge/tokens`](https://www.npmjs.com/package/@windforge/tokens))
16
+ reskin the whole library at once. A token change can't break a layout.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ npm install @windforge/ui
22
+ ```
23
+
24
+ `@windforge/tokens` comes along as a dependency. `react` / `react-dom` (^18.3)
25
+ are peer dependencies you'll already have in a React app.
26
+
27
+ ## Setup
28
+
29
+ **1. Wire the Tailwind preset.** It ships the full theme, keyframes, animations,
30
+ and the `tailwindcss-animate` plugin, so there's no config to hand-copy:
31
+
32
+ ```js
33
+ // tailwind.config.cjs
34
+ module.exports = {
35
+ presets: [require('@windforge/ui/tailwind')],
36
+ content: [
37
+ './src/**/*.{ts,tsx}',
38
+ './node_modules/@windforge/ui/src/**/*.{ts,tsx}', // scan the library's classes
39
+ ],
40
+ }
41
+ ```
42
+
43
+ **2. Load the token CSS and wrap your app** in `ThemeProvider`:
44
+
45
+ ```tsx
46
+ import { ThemeProvider, Toaster } from '@windforge/ui'
47
+ import '@windforge/tokens/tokens.css'
48
+
49
+ export function Root() {
50
+ return (
51
+ <ThemeProvider defaultMode="system" persist>
52
+ <App />
53
+ <Toaster />
54
+ </ThemeProvider>
55
+ )
56
+ }
57
+ ```
58
+
59
+ ## Use it
60
+
61
+ ```tsx
62
+ import { Stack, Card, Text, Button } from '@windforge/ui'
63
+
64
+ export function Example() {
65
+ return (
66
+ <Card padding="card">
67
+ <Stack gap="md">
68
+ <Text>Composed entirely from on-system props — no className.</Text>
69
+ <Button variant="primary">Continue</Button>
70
+ </Stack>
71
+ </Card>
72
+ )
73
+ }
74
+ ```
75
+
76
+ ## Re-skin the brand at runtime
77
+
78
+ A brand is one **50→950 color ramp**; `themeVars` derives every role-named
79
+ `--wf-color-brand-*` variable from it (WCAG-aligned and mode-aware) and can swap
80
+ the font and radius in the same call. Because it's applied at the document root,
81
+ the swap reaches portaled overlays too:
82
+
83
+ ```tsx
84
+ import { ThemeProvider, themeVars, type Ramp } from '@windforge/ui'
85
+
86
+ const brand: Ramp = {
87
+ 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa',
88
+ 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a',
89
+ 950: '#172554',
90
+ }
91
+
92
+ <ThemeProvider tokens={(mode) => themeVars({ brand, fontSans: 'Inter, sans-serif' }, mode)}>
93
+ <App />
94
+ </ThemeProvider>
95
+ ```
96
+
97
+ `@windforge/ui` re-exports the entire `@windforge/tokens` surface, so `themeVars`,
98
+ `brandVars`, `brandRamp` (the default indigo ramp), and the `wf*` token constants
99
+ all import from here directly.
100
+
101
+ ## What's included
102
+
103
+ Primitives (`Button`, `Card`, `Input`, `Badge`, `Text`/`H1`–`H6`…), Radix-backed
104
+ interactive components (`Select`, `Dialog`, `Tooltip`, `Tabs`, `Popover`,
105
+ `DropdownMenu`, `Command`, `DatePicker`…), data display (`Table`, `DataTable`,
106
+ `Chart`), layout primitives (`Box`, `Stack`, `Grid`) and shells (`AppShell`,
107
+ `SideNav`, `AppBar`). Use `lucide-react` for icons.
108
+
109
+ ## License
110
+
111
+ MIT
package/llms.txt ADDED
@@ -0,0 +1,592 @@
1
+ # Windforge (@windforge/ui)
2
+
3
+ > A composable, configurable, strict React design system built on Radix + Tailwind
4
+ > with CSS-variable tokens and zero CSS-in-JS runtime. You build with two surfaces:
5
+ > intent-named component props, and `--wf-*` design tokens.
6
+
7
+ ## Rules
8
+
9
+ - Compose components and set intent-named props (e.g. `variant="primary"`,
10
+ `padding="card"`, `gap="md"`). Props expose only the closed set of on-system
11
+ values listed below — do not invent values.
12
+ - `className` and `style` are rejected at the type level on components. Only the
13
+ layout primitives `Box` / `Stack` / `Grid` accept `className` (incl. Tailwind
14
+ arbitrary values like `w-[37%]`) and `style`, as the escape hatch.
15
+ - Use `Box` / `Stack` / `Grid` for layout and `Text` / `H1`–`H6` for type instead
16
+ of bare `<div>` / `<span>`. Components are fluid; size them via the layout around
17
+ them.
18
+ - Re-skin by overriding `--wf-*` tokens (see `@windforge/tokens`), never by editing
19
+ components. A token change cannot break a layout.
20
+
21
+ ## Setup
22
+
23
+ ```js
24
+ // tailwind.config.cjs
25
+ module.exports = {
26
+ presets: [require('@windforge/ui/tailwind')],
27
+ content: ['./src/**/*.{ts,tsx}', './node_modules/@windforge/ui/src/**/*.{ts,tsx}'],
28
+ }
29
+ ```
30
+
31
+ ```tsx
32
+ import { ThemeProvider } from '@windforge/ui'
33
+ import '@windforge/tokens/tokens.css'
34
+
35
+ <ThemeProvider defaultMode="system" persist><App /></ThemeProvider>
36
+ ```
37
+
38
+ ## Components
39
+
40
+ ### Box
41
+ A padded, optionally-surfaced container — the on-system replacement for a bare <div>.
42
+
43
+ Props:
44
+ - `padding`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
45
+ - `paddingX`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
46
+ - `paddingY`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
47
+ - `background`: `none` | `surface` | `subtle` | `inset` | `inverse` | `brand`
48
+ - `border`: `none` | `default` | `subtle` | `strong`
49
+ - `borderRadius`: `none` | `sm` | `md` | `lg` | `xl` | `2xl` | `full`
50
+ - `boxShadow`: `none` | `sm` | `md` | `lg` | `xl`
51
+ - `maxWidth`: `sm` | `md` | `lg` | `xl` | `prose` | `full`
52
+
53
+ Flags:
54
+ - `asChild`: Render as a child element (polymorphic, replaces MUI component=)
55
+
56
+ ### Stack
57
+ A flex Box — the primary way to arrange children in a row or column with on-scale gap.
58
+
59
+ Props:
60
+ - `direction`: `row` | `column`
61
+ - `gap`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
62
+ - `align`: `start` | `center` | `end` | `stretch` | `baseline`
63
+ - `justify`: `start` | `center` | `end` | `between` | `around`
64
+ - `padding`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
65
+ - `paddingX`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
66
+ - `paddingY`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
67
+ - `background`: `none` | `surface` | `subtle` | `inset` | `inverse` | `brand`
68
+ - `border`: `none` | `default` | `subtle` | `strong`
69
+ - `borderRadius`: `none` | `sm` | `md` | `lg` | `xl` | `2xl` | `full`
70
+ - `boxShadow`: `none` | `sm` | `md` | `lg` | `xl`
71
+ - `maxWidth`: `sm` | `md` | `lg` | `xl` | `prose` | `full`
72
+
73
+ Flags:
74
+ - `wrap`: flex-wrap when true
75
+ - `asChild`: Render as a child element (polymorphic)
76
+
77
+ ### Grid
78
+ A closed-vocabulary CSS grid with responsive column counts and on-scale gap.
79
+
80
+ Props:
81
+ - `cols`: `1` | `2` | `3` | `4` | `5` | `6` | `12`
82
+ - `mdCols`: `1` | `2` | `3` | `4` | `5` | `6` | `12`
83
+ - `gap`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
84
+ - `align`: `start` | `center` | `end` | `stretch`
85
+ - `justify`: `start` | `center` | `end` | `stretch`
86
+
87
+ Flags:
88
+ - `asChild`: Render as a child element (polymorphic)
89
+
90
+ ### Text
91
+ The typography primitive — renders a <p> by default; use asChild for semantics.
92
+
93
+ Props:
94
+ - `size`: `sm` | `base` | `lg` | `xl` | `2xl` | `3xl` | `4xl` | `5xl` | `6xl`
95
+ - `weight`: `light` | `regular` | `medium` | `semibold` | `bold`
96
+ - `tone`: `default` | `muted` | `subtle` | `disabled` | `inverse` | `brand` | `link` | `gradient`
97
+ - `align`: `left` | `center` | `right`
98
+ - `variant`: `inline-code`
99
+
100
+ Flags:
101
+ - `truncate`: Adds CSS truncation (single line ellipsis)
102
+ - `mono`: Switches to monospace font
103
+ - `span`: Render inline as a <span> instead of a block <p>
104
+ - `asChild`: Render as the wrapped child element for semantic control
105
+
106
+ ### H1
107
+ Semantic headings: H1–H6 render the matching <h1>–<h6> with a sensible size default per level; override size freely. (H2…H6 share this API.)
108
+
109
+ Props:
110
+ - `size`: `sm` | `base` | `lg` | `xl` | `2xl` | `3xl` | `4xl` | `5xl` | `6xl`
111
+ - `weight`: `light` | `regular` | `medium` | `semibold` | `bold`
112
+ - `tone`: `default` | `muted` | `subtle` | `disabled` | `inverse` | `brand` | `link`
113
+ - `align`: `left` | `center` | `right`
114
+
115
+ Flags:
116
+ - `truncate`: Adds CSS truncation
117
+
118
+ ### Button
119
+ The primary action element. Hierarchy is expressed through variant, never hue.
120
+
121
+ Props:
122
+ - `variant`: `primary` | `secondary` | `tertiary` | `link` | `destructive`
123
+ - `size`: `sm` | `md` | `lg` | `icon`
124
+
125
+ Flags:
126
+ - `asChild`: Render as a child element (e.g. router link)
127
+
128
+ ### ButtonGroup
129
+ Joins a row of Buttons into a segmented control with shared edges and a single outer radius.
130
+
131
+ Flags:
132
+ - `children (Button elements)`: Any Button variant; the group collapses the seams
133
+
134
+ ### ToggleButton
135
+ A pressable button inside ToggleButtonGroup that tracks selected state.
136
+
137
+ Flags:
138
+ - `value`: String identifier used by ToggleButtonGroup to track selection
139
+
140
+ ### ToggleButtonGroup
141
+ Segmented control; type="single" allows one selection, type="multiple" allows many.
142
+
143
+ Props:
144
+ - `type`: `single` | `multiple`
145
+
146
+ ### Link
147
+ An inline anchor styled in the link color. Use asChild to wrap a router link.
148
+
149
+ Props:
150
+ - `underline`: `hover` | `always` | `none`
151
+
152
+ Flags:
153
+ - `asChild`: Render as a child element, keeping Link styling
154
+
155
+ ### Badge
156
+ A static label pill for status, category, or count. Non-interactive.
157
+
158
+ Props:
159
+ - `variant`: `brand` | `subtle` | `neutral` | `outline` | `success` | `warning` | `error` | `info`
160
+ - `size`: `sm` | `md`
161
+
162
+ ### Chip
163
+ An interactive pill for filtering or selection. Distinct from Badge. Pass onDelete for a removable chip.
164
+
165
+ Props:
166
+ - `size`: `sm` | `md`
167
+
168
+ Flags:
169
+ - `selected`: Boolean — shows the neutral selected (inverse) fill when true
170
+ - `clickable`: Set implicitly when onClick is provided
171
+ - `onDelete`: Renders a trailing ✕ dismiss button
172
+ - `disabled`: Dims and disables interaction
173
+ - `icon`: Optional leading ReactNode (e.g. an icon)
174
+
175
+ ### Alert
176
+ An inline status message. Icon carries the hue; body text stays neutral.
177
+
178
+ Props:
179
+ - `variant`: `neutral` | `info` | `success` | `warning` | `error`
180
+
181
+ Flags:
182
+ - `title`: Heading (ReactNode)
183
+ - `description`: Body text (ReactNode)
184
+ - `icon`: Leading status icon (a lucide element)
185
+ - `actions`: Trailing actions, typically buttons (ReactNode)
186
+
187
+ ### Avatar
188
+ A circular image or fallback initials display. The fallback text scales with size.
189
+
190
+ Props:
191
+ - `size`: `sm` | `md` | `lg` | `xl`
192
+
193
+ Flags:
194
+ - `AvatarImage src`: Image URL; falls back to AvatarFallback when unresolvable
195
+ - `AvatarFallback`: Text shown while image loads or if it fails
196
+
197
+ ### Card
198
+ A Box preset with surface background, default border, 2xl radius, and sm shadow. Accepts all Box props except className/style.
199
+
200
+ Props:
201
+ - `padding`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
202
+ - `paddingX`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
203
+ - `paddingY`: `none` | `xs` | `sm` | `md` | `lg` | `xl` | `2xl` | `nbsp` | `card` | `gutter` | `section` | `page`
204
+ - `background`: `none` | `surface` | `subtle` | `inset` | `inverse` | `brand`
205
+ - `border`: `none` | `default` | `subtle` | `strong`
206
+ - `borderRadius`: `none` | `sm` | `md` | `lg` | `xl` | `2xl` | `full`
207
+ - `boxShadow`: `none` | `sm` | `md` | `lg` | `xl`
208
+
209
+ Flags:
210
+ - `title`: Heading (ReactNode)
211
+ - `description`: Sub-heading body text (ReactNode)
212
+ - `headerAction`: Trailing header content opposite the title, e.g. a Badge (ReactNode)
213
+ - `footer`: Footer content, typically buttons (ReactNode)
214
+ - `children`: Card body content
215
+
216
+ ### Input
217
+ A styled text input. Pass standard HTML input props (type, placeholder, disabled, …).
218
+
219
+ Flags:
220
+ - `type`: HTML input type (text, email, password, number, …)
221
+ - `placeholder`: Placeholder text
222
+ - `disabled`: Dims and disables the field
223
+ - `invalid`: Error state — red outline + aria-invalid (usually set by FormField)
224
+
225
+ ### Textarea
226
+ A styled multiline text input. Pass standard HTML textarea props.
227
+
228
+ Flags:
229
+ - `placeholder`: Placeholder text
230
+ - `disabled`: Dims and disables the field
231
+ - `rows`: Number of visible text rows
232
+ - `invalid`: Error state — red outline + aria-invalid (usually set by FormField)
233
+
234
+ ### Label
235
+ A form label that connects to a field via htmlFor (Radix Label under the hood).
236
+
237
+ ### FormField
238
+ Renders a labelled control and wires the label, description, required marker, and error state with correct ids and ARIA. Renders an Input by default; pass a child to wrap Textarea/Select/Autocomplete. The on-system way to build accessible forms.
239
+
240
+ Flags:
241
+ - `label`: Field label (ReactNode); rendered as a <Label> bound to the control
242
+ - `description`: Helper text below the label — normal foreground, meant to be read
243
+ - `placeholder`: Placeholder forwarded onto the control (a prop on the child wins)
244
+ - `type`: Input type for the default control (text, email, password, …)
245
+ - `error`: Error message (ReactNode); its presence sets the control to invalid
246
+ - `required`: Adds a required marker and aria-required
247
+ - `children`: Escape hatch — a non-Input control to wrap; omit to render an Input
248
+
249
+ ### Select
250
+ A styled dropdown select. Pass an options array, or compose the primitives for groups/labels/custom triggers.
251
+
252
+ Flags:
253
+ - `options`: Array of { value: string; label: ReactNode; disabled?: boolean } — the props API
254
+ - `placeholder`: Placeholder shown before a value is chosen
255
+ - `value`: Controlled value
256
+ - `onValueChange`: Callback with the selected value
257
+ - `disabled`: Disables the trigger
258
+ - `invalid`: Error state — red trigger outline + aria-invalid (usually set by FormField)
259
+ - `SelectTrigger`: Escape hatch: the visible trigger element
260
+ - `SelectContent`: Escape hatch: the dropdown panel
261
+ - `SelectItem`: Escape hatch: an individual option (value, children)
262
+ - `SelectGroup`: Escape hatch: groups items under a SelectLabel
263
+ - `SelectLabel`: Escape hatch: a non-selectable group heading
264
+ - `SelectValue`: Escape hatch: renders the current value inside SelectTrigger
265
+
266
+ ### Autocomplete
267
+ A searchable single-select combobox with keyboard navigation.
268
+
269
+ Flags:
270
+ - `options`: Array of { value: string; label: string }
271
+ - `value`: Controlled current value (string | null)
272
+ - `onValueChange`: Called with the new value or null on clear
273
+ - `placeholder`: Input placeholder text
274
+ - `emptyText`: Message shown when filter yields no results
275
+ - `disabled`: Dims and disables the field
276
+ - `invalid`: Error state — red field outline + aria-invalid (usually set by FormField)
277
+
278
+ ### MultiSelect
279
+ A searchable multi-value combobox. Selected values render as removable tags; the dropdown filters as you type. Controlled via value/onValueChange.
280
+
281
+ Flags:
282
+ - `options`: Array of { value: string; label: string }
283
+ - `value`: Controlled selected values (string[])
284
+ - `onValueChange`: Called with the new value array
285
+ - `placeholder`: Field placeholder when nothing is selected
286
+ - `emptyText`: Message shown when the filter yields no results
287
+ - `disabled`: Dims and disables the field
288
+ - `invalid`: Error state — red outline + aria-invalid (usually set by FormField)
289
+
290
+ ### DatePicker
291
+ A single-date field: a styled trigger that opens the Calendar in a Popover. Controlled via value/onValueChange. For ranges, use Calendar directly.
292
+
293
+ Flags:
294
+ - `value`: Selected Date (or undefined)
295
+ - `onValueChange`: Called with the chosen Date (or undefined)
296
+ - `placeholder`: Trigger text before a date is chosen
297
+ - `disabled`: Dims and disables the trigger
298
+ - `invalid`: Error state — red outline + aria-invalid (usually set by FormField)
299
+ - `formatOptions`: Intl.DateTimeFormatOptions for the displayed value
300
+
301
+ ### Calendar
302
+ The date grid (react-day-picker), token-styled with no vendor CSS. Pass any react-day-picker prop — mode="single|range|multiple", selected, onSelect.
303
+
304
+ Props:
305
+ - `mode`: `single` | `multiple` | `range`
306
+
307
+ Flags:
308
+ - `selected`: Selected date(s) — shape depends on mode
309
+ - `onSelect`: Selection callback — shape depends on mode
310
+ - `showOutsideDays`: Render days from adjacent months (default true)
311
+
312
+ ### Command
313
+ A fast, filterable command menu / palette (cmdk). Compose Command > CommandInput + CommandList (CommandEmpty/CommandGroup/CommandItem/CommandSeparator), or use CommandDialog for a ⌘K palette.
314
+
315
+ Flags:
316
+ - `CommandInput`: The search field
317
+ - `CommandList`: Scrollable results region
318
+ - `CommandEmpty`: Shown when nothing matches
319
+ - `CommandGroup`: A labelled group (heading prop)
320
+ - `CommandItem`: A selectable row (onSelect, value)
321
+ - `CommandSeparator`: A divider between groups
322
+ - `CommandShortcut`: Trailing keyboard hint
323
+ - `CommandDialog`: The palette in a centered overlay (open, onOpenChange)
324
+
325
+ ### Checkbox
326
+ A binary toggle. Pair with Label for an accessible label.
327
+
328
+ Flags:
329
+ - `checked`: Controlled checked state
330
+ - `onCheckedChange`: Callback with the new boolean
331
+ - `disabled`: Disables the checkbox
332
+
333
+ ### RadioGroup
334
+ A group of mutually exclusive RadioGroupItem options.
335
+
336
+ Flags:
337
+ - `value`: Controlled value
338
+ - `onValueChange`: Callback with the selected value
339
+ - `RadioGroupItem value`: The string value for each item; pair with Label
340
+
341
+ ### Switch
342
+ A toggle switch (on/off). Pair with Label for an accessible label.
343
+
344
+ Flags:
345
+ - `checked`: Controlled checked state
346
+ - `onCheckedChange`: Callback with the new boolean
347
+ - `disabled`: Disables the switch
348
+
349
+ ### Slider
350
+ A range slider for numeric input.
351
+
352
+ Flags:
353
+ - `value`: Controlled value array e.g. [50]
354
+ - `onValueChange`: Callback with the new value array
355
+ - `min`: Minimum value (default 0)
356
+ - `max`: Maximum value (default 100)
357
+ - `step`: Step increment
358
+ - `disabled`: Disables the slider
359
+
360
+ ### Tabs
361
+ Tabbed content switcher. Pass an items array, or compose TabsList/TabsTrigger/TabsContent by hand.
362
+
363
+ Flags:
364
+ - `items`: Array of { value, label, content, disabled? } — the props API
365
+ - `defaultValue`: Initially active tab value
366
+ - `value`: Controlled active tab value
367
+ - `onValueChange`: Callback with new tab value
368
+ - `TabsList / TabsTrigger / TabsContent`: Escape hatch primitives for hand-composition
369
+
370
+ ### Accordion
371
+ Vertically stacked collapsible sections. Pass an items array, or compose the primitives. type="single" or "multiple".
372
+
373
+ Props:
374
+ - `type`: `single` | `multiple`
375
+
376
+ Flags:
377
+ - `items`: Array of { value, trigger, content, disabled? } — the props API
378
+ - `collapsible`: When type="single", allows deselecting the open item
379
+ - `AccordionItem / AccordionTrigger / AccordionContent`: Escape hatch primitives for hand-composition
380
+
381
+ ### Breadcrumb
382
+ Navigation trail. Pass an items array; the last item is the current (non-link) page.
383
+
384
+ Flags:
385
+ - `items`: Array of { label: ReactNode, href?: string }; the final item renders as the current page
386
+ - `separator`: Divider between crumbs; defaults to a ChevronRight (ReactNode)
387
+
388
+ ### Pagination
389
+ Controlled page navigation with previous/next buttons, a window of sibling pages, and ellipses.
390
+
391
+ Flags:
392
+ - `page`: 1-based current page number
393
+ - `count`: Total number of pages
394
+ - `onPageChange`: Callback with the new page number
395
+ - `siblingCount`: Number of pages to show on each side of the current (default 1)
396
+
397
+ ### Stepper
398
+ Linear progress through a sequence of named steps.
399
+
400
+ Props:
401
+ - `orientation`: `horizontal` | `vertical`
402
+
403
+ Flags:
404
+ - `steps`: Array of { label: string; description?: string }
405
+ - `activeStep`: 0-based index of the current step
406
+
407
+ ### Dialog
408
+ A convenience overlay with title, description, and footer actions — built on Modal.
409
+
410
+ Props:
411
+ - `size`: `sm` | `md` | `lg` | `xl`
412
+
413
+ Flags:
414
+ - `trigger`: The element that opens the dialog
415
+ - `title`: Heading text (required)
416
+ - `description`: Body text below the title
417
+ - `actions`: ReactNode for the footer, typically buttons
418
+ - `open`: Controlled open state
419
+ - `onOpenChange`: Callback when open state changes
420
+
421
+ ### Modal
422
+ Low-level composable overlay (Radix Dialog). Use Dialog for the common case.
423
+
424
+ Props:
425
+ - `size`: `sm` | `md` | `lg` | `xl`
426
+
427
+ Flags:
428
+ - `ModalTrigger`: The trigger element; use asChild to keep your button
429
+ - `ModalContent`: The panel; size prop sets max-width
430
+ - `ModalClose`: Programmatic close trigger; use asChild
431
+ - `hideClose`: Hide the default corner ✕ on ModalContent
432
+
433
+ ### Popover
434
+ A small floating panel anchored to a trigger. Compose: Popover > PopoverTrigger + PopoverContent.
435
+
436
+ Flags:
437
+ - `PopoverTrigger asChild`: Attach the trigger to your own element
438
+ - `PopoverContent align`: Alignment relative to the trigger (start|center|end)
439
+ - `PopoverContent sideOffset`: Distance from the trigger in px (default 6)
440
+
441
+ ### Sheet
442
+ A slide-in drawer anchored to a screen edge.
443
+
444
+ Props:
445
+ - `side`: `top` | `bottom` | `left` | `right`
446
+
447
+ Flags:
448
+ - `SheetTrigger asChild`: Attach the trigger to your own element
449
+ - `SheetContent title`: Accessible sheet title (ReactNode)
450
+ - `SheetContent description`: Supporting body text (ReactNode)
451
+ - `SheetContent footer`: Action row pinned to the bottom (ReactNode)
452
+ - `SheetClose asChild`: Programmatic close trigger
453
+
454
+ ### DropdownMenu
455
+ A contextual menu anchored to a trigger. Pass trigger + items for the common case, or compose the primitives for checkboxes, radios, and sub-menus.
456
+
457
+ Flags:
458
+ - `trigger`: The element that opens the menu (rendered via asChild)
459
+ - `items`: Array of { label, icon?, shortcut?, onSelect?, disabled? } | { type: "separator" } | { type: "label", label } — the props API
460
+ - `DropdownMenuTrigger asChild`: Escape hatch: use your own element as the trigger
461
+ - `DropdownMenuContent`: Escape hatch: the floating menu panel
462
+ - `DropdownMenuItem`: Escape hatch: a clickable item; inset adds left padding
463
+ - `DropdownMenuCheckboxItem`: Escape hatch: a checkable item
464
+ - `DropdownMenuRadioGroup / DropdownMenuRadioItem`: Escape hatch: radio group + items
465
+ - `DropdownMenuLabel / DropdownMenuSeparator / DropdownMenuShortcut`: Escape hatch: label, divider, shortcut
466
+ - `DropdownMenuSub / DropdownMenuSubTrigger / DropdownMenuSubContent`: Escape hatch: nested sub-menus
467
+
468
+ ### Tooltip
469
+ A floating label on hover/focus. Wrap with TooltipProvider at the app root.
470
+
471
+ Flags:
472
+ - `TooltipProvider`: Render once near the app root to share delay
473
+ - `TooltipTrigger asChild`: Attach the tooltip to your own element
474
+ - `TooltipContent`: The tooltip bubble; sideOffset adjusts distance
475
+
476
+ ### Progress
477
+ A horizontal progress bar. value is 0–100.
478
+
479
+ Flags:
480
+ - `value`: Number 0–100 representing completion percentage
481
+ - `indeterminate`: Looping animation for work of unknown duration; ignores value
482
+
483
+ ### Skeleton
484
+ An animated placeholder while content loads. Size with width/height via className on Box.
485
+
486
+ Flags:
487
+ - `className (via Box wrapper)`: Use Box className to size the skeleton
488
+
489
+ ### Toast
490
+ Transient status notifications. Call toast({...}) imperatively; render <Toaster /> once near root.
491
+
492
+ Props:
493
+ - `variant`: `neutral` | `success` | `error` | `warning` | `info`
494
+
495
+ Flags:
496
+ - `title`: Heading text
497
+ - `description`: Body text
498
+ - `duration`: Auto-dismiss time in ms (default 5000; 0 = permanent)
499
+ - `action`: ReactNode action slot inside the toast
500
+ - `Toaster`: Place once near the app root to render active toasts
501
+
502
+ ### Table
503
+ A semantic table. Pass columns + data for the common case, or compose the primitives for full control.
504
+
505
+ Flags:
506
+ - `columns`: Array of { header, accessor: key | (row) => ReactNode, align? } — the props API
507
+ - `data`: Array of row objects rendered against columns
508
+ - `caption`: Caption rendered below the table (ReactNode)
509
+ - `TableHeader / TableBody / TableFooter`: Escape hatch: thead / tbody / tfoot wrappers
510
+ - `TableRow`: Escape hatch: tr with hover and selected states
511
+ - `TableHead / TableCell`: Escape hatch: th / td; both take align="left|center|right"
512
+ - `TableCaption`: Escape hatch: caption rendered below the table
513
+
514
+ ### DataTable
515
+ The batteries-included table: column sorting, row selection, and optional client-side pagination, built on the Table primitives. Pass columns + data + rowKey.
516
+
517
+ Flags:
518
+ - `columns`: Array of { header, accessor, align?, sortable?, sortAccessor? }
519
+ - `data`: Array of row objects
520
+ - `rowKey`: (row) => string — stable id for selection and keys (required)
521
+ - `selectable`: Adds a select-all + per-row checkbox column
522
+ - `selected`: Controlled selection (array of ids); omit for uncontrolled
523
+ - `onSelectedChange`: Callback with the new selected id array
524
+ - `pageSize`: Enable client-side pagination at this page size
525
+ - `caption`: Caption rendered below the table
526
+ - `emptyState`: Content shown when there are no rows
527
+
528
+ ### Chart
529
+ A token-driven ECharts surface. Pass a standard ECharts option; palette, axes, tooltip, and fonts are themed from the live --wf-* tokens and re-skin with the brand and color mode automatically. Auto-resizes.
530
+
531
+ Flags:
532
+ - `option`: A standard ECharts option object (xAxis/yAxis/series/…)
533
+ - `height`: Pixel or CSS height; width fills the container (default 320)
534
+ - `notMerge`: Replace the previous option wholesale instead of merging (default true)
535
+ - `onEvents`: Map of ECharts event name → handler
536
+
537
+ ### Separator
538
+ A horizontal or vertical visual divider.
539
+
540
+ Props:
541
+ - `orientation`: `horizontal` | `vertical`
542
+
543
+ ### CodeBlock
544
+ A syntax-highlighted code surface. Highlighting runs locally (prism-react-renderer, no API); the theme is built from --wf-* tokens, so it re-skins with mode and brand automatically.
545
+
546
+ Flags:
547
+ - `code`: The source string to render
548
+ - `language`: Prism language id (default 'tsx')
549
+ - `filename`: Optional header filename, shown with the language label
550
+ - `showLineNumbers`: Render a 1-based line-number gutter
551
+ - `highlightLines`: Array of 1-based line numbers to emphasize
552
+ - `wrap`: Soft-wrap long lines instead of scrolling
553
+ - `maxHeight`: Max height before vertical scroll, e.g. '24rem'
554
+ - `copyable`: Show the copy button (default true)
555
+
556
+ ### AppShell
557
+ The guaranteed-layout frame: fixed sidebar on desktop, Sheet drawer on mobile, sticky header, scrollable main. Pass header and sidebar as slots.
558
+
559
+ Flags:
560
+ - `header`: Top-bar slot, typically an <AppBar>
561
+ - `sidebar`: Side-navigation slot, typically a <SideNav>
562
+ - `fullBleed`: Drop the default main padding for edge-to-edge content
563
+
564
+ ### AppBar
565
+ The sticky top bar slot for AppShell: menu toggle, logo, title, and actions. Drop a <ModeToggle/> into actions for the light/dark/system switch.
566
+
567
+ Props:
568
+ - `variant`: `glass` | `solid`
569
+ - `color`: `surface` | `subtle` | `inset`
570
+
571
+ Flags:
572
+ - `title`: Optional title text
573
+ - `logo`: Optional logo ReactNode
574
+ - `actions`: Right-aligned action ReactNode(s) — e.g. a <ModeToggle/>
575
+ - `onMenuClick`: Override the menu-button handler (defaults to toggling the nav)
576
+
577
+ ### SideNav
578
+ The data-driven side navigation: pass a typed items tree (item | group | section | divider); renders active state, nesting, and mobile drawer integration.
579
+
580
+ Flags:
581
+ - `items`: NavItem[] — the navigation tree (item/group/section/divider)
582
+ - `activePath`: The currently active path, highlighted in the tree
583
+ - `onNavigate`: Called with a path when a leaf is activated
584
+ - `logo`: Optional logo ReactNode pinned to the nav header
585
+
586
+ ### ThemeProvider
587
+ Provides color mode (light/dark/system) and optional runtime --wf-* token overrides for live re-skinning. Wrap the app once near the root.
588
+
589
+ Flags:
590
+ - `defaultMode`: Initial color mode: light | dark | system (default system)
591
+ - `tokens`: A --wf-* override map, or (mode) => map for mode-aware brand swaps
592
+ - `persist`: Persist the chosen mode to localStorage (default true)
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@windforge/ui",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
+ "license": "MIT",
4
5
  "type": "module",
5
6
  "sideEffects": false,
6
7
  "main": "./dist/index.js",
@@ -9,22 +10,26 @@
9
10
  "files": [
10
11
  "dist",
11
12
  "src",
12
- "tailwind-preset.cjs"
13
+ "tailwind-preset.cjs",
14
+ "llms.txt"
13
15
  ],
14
16
  "publishConfig": {
15
17
  "access": "public"
16
18
  },
17
19
  "scripts": {
18
20
  "check:catalog": "tsx scripts/check-catalog.ts",
21
+ "generate:llms": "tsx scripts/generate-llms.ts",
22
+ "test": "tsx --test scripts/*.test.ts",
19
23
  "build": "tsup",
20
- "prepublishOnly": "npm run build"
24
+ "prepublishOnly": "npm run generate:llms && npm run build"
21
25
  },
22
26
  "exports": {
23
27
  ".": {
24
28
  "types": "./dist/index.d.ts",
25
29
  "import": "./dist/index.js"
26
30
  },
27
- "./tailwind": "./tailwind-preset.cjs"
31
+ "./tailwind": "./tailwind-preset.cjs",
32
+ "./package.json": "./package.json"
28
33
  },
29
34
  "dependencies": {
30
35
  "@radix-ui/react-accordion": "^1.2.2",
@@ -43,7 +48,7 @@
43
48
  "@radix-ui/react-switch": "^1.1.2",
44
49
  "@radix-ui/react-tabs": "^1.1.2",
45
50
  "@radix-ui/react-tooltip": "^1.1.6",
46
- "@windforge/tokens": "^0.1.0",
51
+ "@windforge/tokens": "^0.1.1",
47
52
  "class-variance-authority": "^0.7.1",
48
53
  "clsx": "^2.1.1",
49
54
  "cmdk": "^1.0.4",