@dowel-ui/registry 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/build.d.ts +26 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +1012 -0
- package/dist/build.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/schema-ByqIpT47.js +101 -0
- package/dist/schema-ByqIpT47.js.map +1 -0
- package/dist/schema-Cc32v3R-.d.ts +130 -0
- package/dist/schema-Cc32v3R-.d.ts.map +1 -0
- package/package.json +39 -0
- package/src/build.test.ts +131 -0
- package/src/build.ts +206 -0
- package/src/hash.ts +12 -0
- package/src/index.ts +16 -0
- package/src/schema.ts +106 -0
package/dist/build.js
ADDED
|
@@ -0,0 +1,1012 @@
|
|
|
1
|
+
import { a as registryIndexSchema, c as hashContent, o as registryItemSchema } from "./schema-ByqIpT47.js";
|
|
2
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
+
//#region ../ui/dist/registry/schema.js
|
|
6
|
+
/** Identity helper that gives editors autocomplete inside `meta.ts`. */
|
|
7
|
+
function defineMeta(meta) {
|
|
8
|
+
return meta;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region ../ui/dist/components/accordion/meta.js
|
|
12
|
+
const meta$53 = defineMeta({
|
|
13
|
+
name: "accordion",
|
|
14
|
+
title: "Accordion",
|
|
15
|
+
description: "Vertically stacked sections that expand to reveal their content.",
|
|
16
|
+
category: "data",
|
|
17
|
+
status: "stable",
|
|
18
|
+
dependencies: ["radix-ui"],
|
|
19
|
+
registryDependencies: [],
|
|
20
|
+
files: ["accordion.tsx"],
|
|
21
|
+
a11y: "Each trigger is a button inside a heading, so screen reader users can navigate the sections by heading. aria-expanded and aria-controls tie the trigger to its panel, and arrow keys move between triggers."
|
|
22
|
+
});
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region ../ui/dist/components/activity-feed/meta.js
|
|
25
|
+
const meta$52 = defineMeta({
|
|
26
|
+
name: "activity-feed",
|
|
27
|
+
title: "Activity Feed",
|
|
28
|
+
description: "A chronological list of events, with a connecting timeline rail.",
|
|
29
|
+
category: "data",
|
|
30
|
+
status: "stable",
|
|
31
|
+
dependencies: ["radix-ui"],
|
|
32
|
+
registryDependencies: [],
|
|
33
|
+
files: ["activity-feed.tsx"],
|
|
34
|
+
a11y: "An ordered list, so position and count are announced — the order is the meaning here. The rail and the indicators are decorative; the item text has to say what happened. ActivityTime requires a machine-readable dateTime, because a relative label like \"2 hours ago\" is ambiguous outside the moment it was rendered."
|
|
35
|
+
});
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region ../ui/dist/components/ai-agent-status/meta.js
|
|
38
|
+
const meta$51 = defineMeta({
|
|
39
|
+
name: "ai-agent-status",
|
|
40
|
+
title: "AI Agent Status",
|
|
41
|
+
description: "A pill showing what an agent is doing, in words as well as colour.",
|
|
42
|
+
category: "ai",
|
|
43
|
+
status: "stable",
|
|
44
|
+
dependencies: ["class-variance-authority"],
|
|
45
|
+
registryDependencies: [],
|
|
46
|
+
files: ["ai-agent-status.tsx"],
|
|
47
|
+
a11y: "The state is always text. Agent states matter most when something has failed, which is exactly when a colour-only signal fails the people who most need to see it. Live announcements are off by default — several agents each announcing their transitions turns a dashboard into noise; enable it for the one agent being watched."
|
|
48
|
+
});
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region ../ui/dist/components/ai-conversation/meta.js
|
|
51
|
+
const meta$50 = defineMeta({
|
|
52
|
+
name: "ai-conversation",
|
|
53
|
+
title: "AI Conversation",
|
|
54
|
+
description: "The scrolling transcript container, with follow-on-new-content and a status region.",
|
|
55
|
+
category: "ai",
|
|
56
|
+
status: "stable",
|
|
57
|
+
dependencies: [],
|
|
58
|
+
registryDependencies: [],
|
|
59
|
+
files: ["ai-conversation.tsx"],
|
|
60
|
+
a11y: "The transcript is an ordered list, NOT a live region. A live region that updates on every streamed token is unusable with a screen reader, and is the most common accessibility failure in chat interfaces. Announce state — \"generating\", \"response complete\" — through ConversationStatus instead, and let the reader navigate the transcript at their own pace. Auto-scroll stops the moment the reader scrolls up, and ConversationScrollButton is the explicit way back."
|
|
61
|
+
});
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region ../ui/dist/components/ai-message/meta.js
|
|
64
|
+
const meta$49 = defineMeta({
|
|
65
|
+
name: "ai-message",
|
|
66
|
+
title: "AI Message",
|
|
67
|
+
description: "One turn in a conversation, with role, avatar, actions and footer slots.",
|
|
68
|
+
category: "ai",
|
|
69
|
+
status: "stable",
|
|
70
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
71
|
+
registryDependencies: [],
|
|
72
|
+
files: ["ai-message.tsx"],
|
|
73
|
+
a11y: "Every message carries a visually hidden label naming the speaker. Alignment and colour tell a sighted reader who is talking and tell a screen reader user nothing, so the role is always in text. Message actions fade in on hover but stay in the DOM and in the tab order — a control that only exists on hover is unreachable by keyboard and invisible on touch."
|
|
74
|
+
});
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region ../ui/dist/components/ai-model-selector/meta.js
|
|
77
|
+
const meta$48 = defineMeta({
|
|
78
|
+
name: "ai-model-selector",
|
|
79
|
+
title: "AI Model Selector",
|
|
80
|
+
description: "Picks the model a conversation runs on, with descriptions and availability.",
|
|
81
|
+
category: "ai",
|
|
82
|
+
status: "stable",
|
|
83
|
+
dependencies: [],
|
|
84
|
+
registryDependencies: ["select"],
|
|
85
|
+
files: ["ai-model-selector.tsx"],
|
|
86
|
+
a11y: "Inherits Select's listbox keyboard model. Each option sets textValue to the model name so typeahead matches the name rather than the description. A disabled model shows and announces why it is unavailable — a disabled option with no reason reads as a broken interface."
|
|
87
|
+
});
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region ../ui/dist/components/ai-prompt-input/meta.js
|
|
90
|
+
const meta$47 = defineMeta({
|
|
91
|
+
name: "ai-prompt-input",
|
|
92
|
+
title: "AI Prompt Input",
|
|
93
|
+
description: "The composer: auto-growing textarea, send-on-Enter, and a send/stop control.",
|
|
94
|
+
category: "ai",
|
|
95
|
+
status: "stable",
|
|
96
|
+
dependencies: [],
|
|
97
|
+
registryDependencies: [],
|
|
98
|
+
files: ["ai-prompt-input.tsx"],
|
|
99
|
+
a11y: "Enter sends and Shift+Enter inserts a newline, but never while an IME composition is active — for Japanese, Chinese and Korean input Enter confirms a candidate, and sending there truncates the sentence mid-word. The submit control renames itself to \"Stop generating\" while busy, so its accessible name always matches what it does. The character counter stays silent until it nears the limit; announcing every keystroke would be unusable."
|
|
100
|
+
});
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region ../ui/dist/components/ai-reasoning/meta.js
|
|
103
|
+
const meta$46 = defineMeta({
|
|
104
|
+
name: "ai-reasoning",
|
|
105
|
+
title: "AI Reasoning",
|
|
106
|
+
description: "A collapsible disclosure for the model's reasoning.",
|
|
107
|
+
category: "ai",
|
|
108
|
+
status: "stable",
|
|
109
|
+
dependencies: ["radix-ui"],
|
|
110
|
+
registryDependencies: [],
|
|
111
|
+
files: ["ai-reasoning.tsx"],
|
|
112
|
+
a11y: "A standard disclosure with aria-expanded on the trigger. Collapsed by default because reasoning is supporting material — giving it the same weight as the answer buries the answer. The trigger's label changes while reasoning streams, so its accessible name matches what is happening."
|
|
113
|
+
});
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region ../ui/dist/components/ai-response/meta.js
|
|
116
|
+
const meta$45 = defineMeta({
|
|
117
|
+
name: "ai-response",
|
|
118
|
+
title: "AI Response",
|
|
119
|
+
description: "Assistant response text, with a streaming caret and a thinking indicator.",
|
|
120
|
+
category: "ai",
|
|
121
|
+
status: "stable",
|
|
122
|
+
dependencies: [],
|
|
123
|
+
registryDependencies: [],
|
|
124
|
+
files: ["ai-response.tsx"],
|
|
125
|
+
a11y: "Deliberately not a live region: announcing streamed text as it arrives interrupts a screen reader user on every token. Announce state through ConversationStatus and let them read the response when it settles. The caret is decorative; ThinkingIndicator carries a label because it is the only thing on screen while waiting for the first token."
|
|
126
|
+
});
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region ../ui/dist/components/ai-sources/meta.js
|
|
129
|
+
const meta$44 = defineMeta({
|
|
130
|
+
name: "ai-sources",
|
|
131
|
+
title: "AI Sources",
|
|
132
|
+
description: "Inline citation markers and the source list they refer to.",
|
|
133
|
+
category: "ai",
|
|
134
|
+
status: "stable",
|
|
135
|
+
dependencies: ["radix-ui"],
|
|
136
|
+
registryDependencies: [],
|
|
137
|
+
files: ["ai-sources.tsx"],
|
|
138
|
+
a11y: "An inline marker shows a bare number, which conveys nothing on its own, so the source title is carried in its accessible name. A marker with no href renders as text rather than as a link that goes nowhere. The source list is ordered, because the marker numbers refer to positions in it."
|
|
139
|
+
});
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region ../ui/dist/components/ai-token-usage/meta.js
|
|
142
|
+
const meta$43 = defineMeta({
|
|
143
|
+
name: "ai-token-usage",
|
|
144
|
+
title: "AI Token Usage",
|
|
145
|
+
description: "A gauge showing how much of the context window a conversation has used.",
|
|
146
|
+
category: "ai",
|
|
147
|
+
status: "stable",
|
|
148
|
+
dependencies: [],
|
|
149
|
+
registryDependencies: [],
|
|
150
|
+
files: ["ai-token-usage.tsx"],
|
|
151
|
+
a11y: "The numbers are the content and the bar only summarises them, so the bar is aria-hidden rather than a second progressbar to read past. Counts are formatted for the locale. Warning and over-limit states change the wording's colour but never remove the figures."
|
|
152
|
+
});
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region ../ui/dist/components/ai-tool/meta.js
|
|
155
|
+
const meta$42 = defineMeta({
|
|
156
|
+
name: "ai-tool",
|
|
157
|
+
title: "AI Tool Call",
|
|
158
|
+
description: "A collapsible record of a tool the model called, its arguments and its result.",
|
|
159
|
+
category: "ai",
|
|
160
|
+
status: "stable",
|
|
161
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
162
|
+
registryDependencies: [],
|
|
163
|
+
files: ["ai-tool.tsx"],
|
|
164
|
+
a11y: "A disclosure: the trigger exposes aria-expanded and controls the panel. Status is stated in words, not by a coloured dot — colour alone is unavailable to a screen reader and to anyone who cannot distinguish it. Payload blocks are focusable named regions, since JSON scrolls and an unfocusable scroll box is unreachable by keyboard."
|
|
165
|
+
});
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region ../ui/dist/components/alert/meta.js
|
|
168
|
+
const meta$41 = defineMeta({
|
|
169
|
+
name: "alert",
|
|
170
|
+
title: "Alert",
|
|
171
|
+
description: "A callout that draws attention to an important message.",
|
|
172
|
+
category: "feedback",
|
|
173
|
+
status: "stable",
|
|
174
|
+
dependencies: ["class-variance-authority"],
|
|
175
|
+
registryDependencies: [],
|
|
176
|
+
files: ["alert.tsx"],
|
|
177
|
+
a11y: "Not a live region by default. Pass live=\"polite\" for alerts that appear in response to a user action, or live=\"assertive\" for errors that must interrupt. Variant colour is never the only signal — the title carries the meaning."
|
|
178
|
+
});
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region ../ui/dist/components/avatar/meta.js
|
|
181
|
+
const meta$40 = defineMeta({
|
|
182
|
+
name: "avatar",
|
|
183
|
+
title: "Avatar",
|
|
184
|
+
description: "An image representation of a user or entity with a graceful text fallback.",
|
|
185
|
+
category: "display",
|
|
186
|
+
status: "stable",
|
|
187
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
188
|
+
registryDependencies: [],
|
|
189
|
+
files: ["avatar.tsx"],
|
|
190
|
+
a11y: "Give AvatarImage a meaningful alt, or alt=\"\" when the adjacent text already names the person. Fallback initials are decorative and are not announced separately."
|
|
191
|
+
});
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region ../ui/dist/components/badge/meta.js
|
|
194
|
+
const meta$39 = defineMeta({
|
|
195
|
+
name: "badge",
|
|
196
|
+
title: "Badge",
|
|
197
|
+
description: "A compact marker for status, counts and categories.",
|
|
198
|
+
category: "display",
|
|
199
|
+
status: "stable",
|
|
200
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
201
|
+
registryDependencies: [],
|
|
202
|
+
files: ["badge.tsx"],
|
|
203
|
+
a11y: "The badge label must convey the meaning on its own; variant colour is decoration. Use asChild to render an interactive badge as a link or button rather than adding handlers."
|
|
204
|
+
});
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region ../ui/dist/components/button/meta.js
|
|
207
|
+
const meta$38 = defineMeta({
|
|
208
|
+
name: "button",
|
|
209
|
+
title: "Button",
|
|
210
|
+
description: "Triggers an action or event, with variants for every level of emphasis.",
|
|
211
|
+
category: "foundation",
|
|
212
|
+
status: "stable",
|
|
213
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
214
|
+
registryDependencies: ["spinner"],
|
|
215
|
+
files: ["button.tsx"],
|
|
216
|
+
a11y: "Keyboard activatable via Enter and Space. The loading state uses aria-disabled and aria-busy rather than the disabled attribute, so focus is never stranded mid-action. Use `size=\"icon\"` only with an accessible name from aria-label or visually hidden text."
|
|
217
|
+
});
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region ../ui/dist/components/calendar/meta.js
|
|
220
|
+
const meta$37 = defineMeta({
|
|
221
|
+
name: "calendar",
|
|
222
|
+
title: "Calendar",
|
|
223
|
+
description: "A date grid for selecting a day, several days or a range.",
|
|
224
|
+
category: "form",
|
|
225
|
+
status: "stable",
|
|
226
|
+
dependencies: ["react-day-picker"],
|
|
227
|
+
registryDependencies: ["button"],
|
|
228
|
+
files: ["calendar.tsx"],
|
|
229
|
+
a11y: "A real grid with roving focus: arrows move by day, Page Up/Down by month, Home/End to the ends of a week. Selection is announced through aria-selected, and the month caption is a live region so moving between months is announced. Give the calendar an accessible name when more than one is on the page."
|
|
230
|
+
});
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region ../ui/dist/components/card/meta.js
|
|
233
|
+
const meta$36 = defineMeta({
|
|
234
|
+
name: "card",
|
|
235
|
+
title: "Card",
|
|
236
|
+
description: "A surface that groups related content and actions into a single block.",
|
|
237
|
+
category: "display",
|
|
238
|
+
status: "stable",
|
|
239
|
+
dependencies: ["radix-ui"],
|
|
240
|
+
registryDependencies: [],
|
|
241
|
+
files: ["card.tsx"],
|
|
242
|
+
a11y: "Card renders a plain div with no implicit landmark. CardTitle is an h3 by default — use asChild to set the level the page actually needs, since heading levels must increase by one, or to render something that is not a heading at all."
|
|
243
|
+
});
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region ../ui/dist/components/checkbox/meta.js
|
|
246
|
+
const meta$35 = defineMeta({
|
|
247
|
+
name: "checkbox",
|
|
248
|
+
title: "Checkbox",
|
|
249
|
+
description: "A control for an on/off choice, with support for an indeterminate state.",
|
|
250
|
+
category: "form",
|
|
251
|
+
status: "stable",
|
|
252
|
+
dependencies: ["radix-ui"],
|
|
253
|
+
registryDependencies: [],
|
|
254
|
+
files: ["checkbox.tsx"],
|
|
255
|
+
a11y: "Toggles with Space, matching the native control. Always pair with a Label via htmlFor/id — the box alone has no accessible name. Indeterminate is announced as \"mixed\" and is a state the application sets, not one the user can reach by clicking."
|
|
256
|
+
});
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region ../ui/dist/components/code-block/meta.js
|
|
259
|
+
const meta$34 = defineMeta({
|
|
260
|
+
name: "code-block",
|
|
261
|
+
title: "Code Block",
|
|
262
|
+
description: "A block of code with a copy control, ready for any highlighter.",
|
|
263
|
+
category: "data",
|
|
264
|
+
status: "stable",
|
|
265
|
+
dependencies: [],
|
|
266
|
+
registryDependencies: [],
|
|
267
|
+
files: ["code-block.tsx"],
|
|
268
|
+
a11y: "The pre is a focusable named region, since code overflows horizontally and an unfocusable scroll box is unreachable by keyboard. Copying is announced through a polite live region as well as shown, and a refused clipboard write reports failure rather than looking like success."
|
|
269
|
+
});
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region ../ui/dist/components/combobox/meta.js
|
|
272
|
+
const meta$33 = defineMeta({
|
|
273
|
+
name: "combobox",
|
|
274
|
+
title: "Combobox",
|
|
275
|
+
description: "A searchable single-select built on the ARIA combobox pattern.",
|
|
276
|
+
category: "form",
|
|
277
|
+
status: "stable",
|
|
278
|
+
dependencies: ["radix-ui"],
|
|
279
|
+
registryDependencies: [],
|
|
280
|
+
files: ["combobox.tsx"],
|
|
281
|
+
a11y: "The input owns role=\"combobox\" with aria-expanded, aria-controls and aria-autocomplete; the list owns role=\"listbox\" and each option role=\"option\" with aria-selected. Focus stays in the input while arrow keys move aria-activedescendant, so typing is never interrupted. Arrow navigation wraps, Home/End jump, Enter selects the active option and Escape closes."
|
|
282
|
+
});
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region ../ui/dist/components/command/meta.js
|
|
285
|
+
const meta$32 = defineMeta({
|
|
286
|
+
name: "command",
|
|
287
|
+
title: "Command",
|
|
288
|
+
description: "A searchable command palette, with groups and a ⌘K dialog variant.",
|
|
289
|
+
category: "navigation",
|
|
290
|
+
status: "stable",
|
|
291
|
+
dependencies: [],
|
|
292
|
+
registryDependencies: ["dialog"],
|
|
293
|
+
files: ["command.tsx"],
|
|
294
|
+
a11y: "The input owns role=\"combobox\" and the list role=\"listbox\"; focus stays in the input while arrow keys move aria-activedescendant, so typing is never interrupted. Enter runs the active item through the same path as a click. A group whose items are all filtered out hides its heading rather than labelling nothing. CommandDialog always renders a title and description, visually hidden, so the dialog is never unnamed."
|
|
295
|
+
});
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region ../ui/dist/components/data-table/meta.js
|
|
298
|
+
const meta$31 = defineMeta({
|
|
299
|
+
name: "data-table",
|
|
300
|
+
title: "Data Table",
|
|
301
|
+
description: "Presentation for a TanStack Table instance: sorting, column visibility and pagination.",
|
|
302
|
+
category: "data",
|
|
303
|
+
status: "stable",
|
|
304
|
+
dependencies: ["@tanstack/react-table"],
|
|
305
|
+
registryDependencies: [
|
|
306
|
+
"button",
|
|
307
|
+
"dropdown-menu",
|
|
308
|
+
"select",
|
|
309
|
+
"table"
|
|
310
|
+
],
|
|
311
|
+
files: ["data-table.tsx"],
|
|
312
|
+
a11y: "Sortable headers carry aria-sort, so the current sort is announced rather than being conveyed by an arrow icon alone, and each sort button has visually hidden text stating the column and its direction. The pagination status is a polite live region, because paging swaps the rows in place with no other signal. A column that cannot be sorted renders as text, not as a button that does nothing."
|
|
313
|
+
});
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region ../ui/dist/components/date-picker/meta.js
|
|
316
|
+
const meta$30 = defineMeta({
|
|
317
|
+
name: "date-picker",
|
|
318
|
+
title: "Date Picker",
|
|
319
|
+
description: "A button that opens a calendar to pick a date or a date range.",
|
|
320
|
+
category: "form",
|
|
321
|
+
status: "stable",
|
|
322
|
+
dependencies: ["react-day-picker"],
|
|
323
|
+
registryDependencies: [
|
|
324
|
+
"button",
|
|
325
|
+
"calendar",
|
|
326
|
+
"popover"
|
|
327
|
+
],
|
|
328
|
+
files: ["date-picker.tsx"],
|
|
329
|
+
a11y: "The trigger states the selected date, formatted for the locale, so its accessible name changes with the value. The popover is named because it carries role=\"dialog\". Selecting a single date closes the popover and returns focus to the trigger; a range stays open, since one click is only half an answer. Offer a typed input alongside it for dates the user already knows."
|
|
330
|
+
});
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region ../ui/dist/components/dialog/meta.js
|
|
333
|
+
const meta$29 = defineMeta({
|
|
334
|
+
name: "dialog",
|
|
335
|
+
title: "Dialog",
|
|
336
|
+
description: "A modal window that interrupts the user to gather a response.",
|
|
337
|
+
category: "overlay",
|
|
338
|
+
status: "stable",
|
|
339
|
+
dependencies: ["radix-ui"],
|
|
340
|
+
registryDependencies: [],
|
|
341
|
+
files: ["dialog.tsx"],
|
|
342
|
+
a11y: "Focus is trapped while open and restored to the trigger on close; Escape and an overlay click dismiss. Always render a DialogTitle — it names the dialog for screen readers. Use DialogDescription, or aria-describedby, to explain consequential actions."
|
|
343
|
+
});
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region ../ui/dist/components/drawer/meta.js
|
|
346
|
+
const meta$28 = defineMeta({
|
|
347
|
+
name: "drawer",
|
|
348
|
+
title: "Drawer",
|
|
349
|
+
description: "A bottom sheet that can be dismissed by dragging it down.",
|
|
350
|
+
category: "overlay",
|
|
351
|
+
status: "stable",
|
|
352
|
+
dependencies: ["radix-ui"],
|
|
353
|
+
registryDependencies: [],
|
|
354
|
+
files: ["drawer.tsx"],
|
|
355
|
+
a11y: "Drag is pointer-only and never the sole way out: Escape, the overlay and DrawerCancel all dismiss. The grab handle is aria-hidden because it duplicates those affordances. Always render a DrawerTitle."
|
|
356
|
+
});
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region ../ui/dist/components/dropdown-menu/meta.js
|
|
359
|
+
const meta$27 = defineMeta({
|
|
360
|
+
name: "dropdown-menu",
|
|
361
|
+
title: "Dropdown Menu",
|
|
362
|
+
description: "A menu of actions revealed from a trigger, with submenus and selectable items.",
|
|
363
|
+
category: "overlay",
|
|
364
|
+
status: "stable",
|
|
365
|
+
dependencies: ["radix-ui"],
|
|
366
|
+
registryDependencies: [],
|
|
367
|
+
files: ["dropdown-menu.tsx"],
|
|
368
|
+
a11y: "Full menu keyboard model: arrows move, Home/End jump, typeahead searches, Escape closes and restores focus, Right/Left open and close submenus. Highlight is driven by data-highlighted so pointer and keyboard focus never diverge. Use it for actions — links belong in a nav, and value selection belongs in Select."
|
|
369
|
+
});
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region ../ui/dist/components/empty-state/meta.js
|
|
372
|
+
const meta$26 = defineMeta({
|
|
373
|
+
name: "empty-state",
|
|
374
|
+
title: "Empty State",
|
|
375
|
+
description: "Shown where content would be, explaining why it is empty and what to do next.",
|
|
376
|
+
category: "feedback",
|
|
377
|
+
status: "stable",
|
|
378
|
+
dependencies: ["class-variance-authority"],
|
|
379
|
+
registryDependencies: [],
|
|
380
|
+
files: ["empty-state.tsx"],
|
|
381
|
+
a11y: "A plain container with no implicit landmark or live region. When it replaces content after a search, put aria-live on the results region so the change is announced. The icon is decorative — the title has to carry the message on its own."
|
|
382
|
+
});
|
|
383
|
+
//#endregion
|
|
384
|
+
//#region ../ui/dist/components/form/meta.js
|
|
385
|
+
const meta$25 = defineMeta({
|
|
386
|
+
name: "form",
|
|
387
|
+
title: "Form",
|
|
388
|
+
description: "Accessible field wiring that works with any form library, or none.",
|
|
389
|
+
category: "form",
|
|
390
|
+
status: "stable",
|
|
391
|
+
dependencies: ["radix-ui"],
|
|
392
|
+
registryDependencies: [],
|
|
393
|
+
files: ["form.tsx"],
|
|
394
|
+
a11y: "FormField generates the id, points the Label at the control, and assembles aria-describedby from whichever of the description and error are actually present — a dangling reference announces nothing and is flagged by axe. aria-invalid follows the error. FormMessage is a polite live region, so a late validation message is announced without interrupting."
|
|
395
|
+
});
|
|
396
|
+
//#endregion
|
|
397
|
+
//#region ../ui/dist/components/input/meta.js
|
|
398
|
+
const meta$24 = defineMeta({
|
|
399
|
+
name: "input",
|
|
400
|
+
title: "Input",
|
|
401
|
+
description: "A single-line text field with size variants and native validation styling.",
|
|
402
|
+
category: "form",
|
|
403
|
+
status: "stable",
|
|
404
|
+
dependencies: ["class-variance-authority"],
|
|
405
|
+
registryDependencies: [],
|
|
406
|
+
files: ["input.tsx"],
|
|
407
|
+
a11y: "Always pair with a Label via htmlFor/id. Error state is driven by aria-invalid so assistive technology and styling stay in sync; describe the error with aria-describedby."
|
|
408
|
+
});
|
|
409
|
+
//#endregion
|
|
410
|
+
//#region ../ui/dist/components/label/meta.js
|
|
411
|
+
const meta$23 = defineMeta({
|
|
412
|
+
name: "label",
|
|
413
|
+
title: "Label",
|
|
414
|
+
description: "An accessible caption that associates text with a form control.",
|
|
415
|
+
category: "form",
|
|
416
|
+
status: "stable",
|
|
417
|
+
dependencies: ["radix-ui"],
|
|
418
|
+
registryDependencies: [],
|
|
419
|
+
files: ["label.tsx"],
|
|
420
|
+
a11y: "Set htmlFor to the id of the control it labels. Clicking the label moves focus to that control, including composite widgets that are not native inputs."
|
|
421
|
+
});
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region ../ui/dist/components/pagination/meta.js
|
|
424
|
+
const meta$22 = defineMeta({
|
|
425
|
+
name: "pagination",
|
|
426
|
+
title: "Pagination",
|
|
427
|
+
description: "Navigation between pages of a list.",
|
|
428
|
+
category: "navigation",
|
|
429
|
+
status: "stable",
|
|
430
|
+
dependencies: ["radix-ui"],
|
|
431
|
+
registryDependencies: ["button"],
|
|
432
|
+
files: ["pagination.tsx"],
|
|
433
|
+
a11y: "A named nav landmark. The current page carries aria-current=\"page\" — styling it differently conveys nothing on its own. Links by default, since a page of results is a place worth sharing; use asChild for your router's link, or render buttons when paging only changes client state."
|
|
434
|
+
});
|
|
435
|
+
//#endregion
|
|
436
|
+
//#region ../ui/dist/components/popover/meta.js
|
|
437
|
+
const meta$21 = defineMeta({
|
|
438
|
+
name: "popover",
|
|
439
|
+
title: "Popover",
|
|
440
|
+
description: "Rich floating content anchored to a trigger.",
|
|
441
|
+
category: "overlay",
|
|
442
|
+
status: "stable",
|
|
443
|
+
dependencies: ["radix-ui"],
|
|
444
|
+
registryDependencies: [],
|
|
445
|
+
files: ["popover.tsx"],
|
|
446
|
+
a11y: "The content has role=\"dialog\" and therefore REQUIRES an accessible name — pass aria-label, or aria-labelledby pointing at a heading inside it. A development-only warning fires if neither is present. The trigger exposes aria-expanded and aria-controls; Escape closes and returns focus to it. Non-modal by default, so the rest of the page stays reachable; pass `modal` only when the content is a task the user must finish or abandon."
|
|
447
|
+
});
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region ../ui/dist/components/progress/meta.js
|
|
450
|
+
const meta$20 = defineMeta({
|
|
451
|
+
name: "progress",
|
|
452
|
+
title: "Progress",
|
|
453
|
+
description: "Shows how far along a task is, or that one is running at all.",
|
|
454
|
+
category: "feedback",
|
|
455
|
+
status: "stable",
|
|
456
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
457
|
+
registryDependencies: [],
|
|
458
|
+
files: ["progress.tsx"],
|
|
459
|
+
a11y: "Exposed as role=\"progressbar\" with aria-valuenow, and give it a name with aria-label or aria-labelledby. Omitting `value` marks it indeterminate, which is announced differently from zero. Show the percentage in text as well — the bar alone is not readable at a glance for everyone."
|
|
460
|
+
});
|
|
461
|
+
//#endregion
|
|
462
|
+
//#region ../ui/dist/components/radio-group/meta.js
|
|
463
|
+
const meta$19 = defineMeta({
|
|
464
|
+
name: "radio-group",
|
|
465
|
+
title: "Radio Group",
|
|
466
|
+
description: "A set of mutually exclusive options.",
|
|
467
|
+
category: "form",
|
|
468
|
+
status: "stable",
|
|
469
|
+
dependencies: ["radix-ui"],
|
|
470
|
+
registryDependencies: [],
|
|
471
|
+
files: ["radio-group.tsx"],
|
|
472
|
+
a11y: "Arrow keys move between options and select as they go, and the group is a single tab stop — the standard radio model. Give the group an accessible name with aria-labelledby, and each item a Label tied by htmlFor/id."
|
|
473
|
+
});
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region ../ui/dist/components/select/meta.js
|
|
476
|
+
const meta$18 = defineMeta({
|
|
477
|
+
name: "select",
|
|
478
|
+
title: "Select",
|
|
479
|
+
description: "Picks one value from a short list of options.",
|
|
480
|
+
category: "form",
|
|
481
|
+
status: "stable",
|
|
482
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
483
|
+
registryDependencies: [],
|
|
484
|
+
files: ["select.tsx"],
|
|
485
|
+
a11y: "Full listbox keyboard model: arrows move, typeahead jumps, Enter selects, Escape closes and restores focus. Give the trigger a name with aria-labelledby or a Label. Past about a dozen options prefer Combobox — scrolling a long listbox by keyboard is slow."
|
|
486
|
+
});
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region ../ui/dist/components/separator/meta.js
|
|
489
|
+
const meta$17 = defineMeta({
|
|
490
|
+
name: "separator",
|
|
491
|
+
title: "Separator",
|
|
492
|
+
description: "A horizontal or vertical rule that divides content.",
|
|
493
|
+
category: "layout",
|
|
494
|
+
status: "stable",
|
|
495
|
+
dependencies: ["radix-ui"],
|
|
496
|
+
registryDependencies: [],
|
|
497
|
+
files: ["separator.tsx"],
|
|
498
|
+
a11y: "Decorative by default and hidden from assistive technology. Set decorative={false} to expose it as a semantic separator when it divides meaningfully distinct groups."
|
|
499
|
+
});
|
|
500
|
+
//#endregion
|
|
501
|
+
//#region ../ui/dist/components/sheet/meta.js
|
|
502
|
+
const meta$16 = defineMeta({
|
|
503
|
+
name: "sheet",
|
|
504
|
+
title: "Sheet",
|
|
505
|
+
description: "A panel that enters from an edge of the viewport for secondary content.",
|
|
506
|
+
category: "overlay",
|
|
507
|
+
status: "stable",
|
|
508
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
509
|
+
registryDependencies: [],
|
|
510
|
+
files: ["sheet.tsx"],
|
|
511
|
+
a11y: "Modal, with the same focus trapping and restoration as Dialog. Always render a SheetTitle. For a side navigation sheet, put a nav landmark inside rather than relying on placement to convey the role."
|
|
512
|
+
});
|
|
513
|
+
//#endregion
|
|
514
|
+
//#region ../ui/dist/components/skeleton/meta.js
|
|
515
|
+
const meta$15 = defineMeta({
|
|
516
|
+
name: "skeleton",
|
|
517
|
+
title: "Skeleton",
|
|
518
|
+
description: "A shaped placeholder that holds layout while content loads.",
|
|
519
|
+
category: "feedback",
|
|
520
|
+
status: "stable",
|
|
521
|
+
dependencies: [],
|
|
522
|
+
registryDependencies: [],
|
|
523
|
+
files: ["skeleton.tsx"],
|
|
524
|
+
a11y: "Hidden from assistive technology. Put aria-busy on the container that owns the loading data so the state is announced once instead of once per placeholder."
|
|
525
|
+
});
|
|
526
|
+
//#endregion
|
|
527
|
+
//#region ../ui/dist/components/slider/meta.js
|
|
528
|
+
const meta$14 = defineMeta({
|
|
529
|
+
name: "slider",
|
|
530
|
+
title: "Slider",
|
|
531
|
+
description: "Selects a value, or a range, from a continuous span.",
|
|
532
|
+
category: "form",
|
|
533
|
+
status: "stable",
|
|
534
|
+
dependencies: ["radix-ui"],
|
|
535
|
+
registryDependencies: [],
|
|
536
|
+
files: ["slider.tsx"],
|
|
537
|
+
a11y: "Each thumb is a role=\"slider\" with arrow keys, Home/End and Page Up/Down. The name is forwarded onto the thumbs, since the root has no role — a range slider should name each thumb separately with thumbLabels. A development-only warning fires if a thumb would be unnamed. Pass aria-valuetext when the raw number is not meaningful on its own (a price, a duration). Show the current value on screen too — a slider is imprecise, so pair it with a numeric input when exactness matters."
|
|
538
|
+
});
|
|
539
|
+
//#endregion
|
|
540
|
+
//#region ../ui/dist/components/spinner/meta.js
|
|
541
|
+
const meta$13 = defineMeta({
|
|
542
|
+
name: "spinner",
|
|
543
|
+
title: "Spinner",
|
|
544
|
+
description: "An indeterminate loading indicator for buttons, panels and inline content.",
|
|
545
|
+
category: "feedback",
|
|
546
|
+
status: "stable",
|
|
547
|
+
dependencies: ["class-variance-authority"],
|
|
548
|
+
registryDependencies: [],
|
|
549
|
+
files: ["spinner.tsx"],
|
|
550
|
+
a11y: "Renders aria-hidden by default so it does not announce inside controls that already expose a busy state. Pass `label` to announce it standalone via role=\"status\"."
|
|
551
|
+
});
|
|
552
|
+
//#endregion
|
|
553
|
+
//#region ../ui/dist/components/switch/meta.js
|
|
554
|
+
const meta$12 = defineMeta({
|
|
555
|
+
name: "switch",
|
|
556
|
+
title: "Switch",
|
|
557
|
+
description: "An immediate on/off toggle for settings that apply straight away.",
|
|
558
|
+
category: "form",
|
|
559
|
+
status: "stable",
|
|
560
|
+
dependencies: ["radix-ui"],
|
|
561
|
+
registryDependencies: [],
|
|
562
|
+
files: ["switch.tsx"],
|
|
563
|
+
a11y: "Exposed as role=\"switch\" and toggled with Space or Enter. Needs a visible label tied with htmlFor/id. Do not rely on colour alone to show state — position and the label carry it too."
|
|
564
|
+
});
|
|
565
|
+
//#endregion
|
|
566
|
+
//#region ../ui/dist/components/table/meta.js
|
|
567
|
+
const meta$11 = defineMeta({
|
|
568
|
+
name: "table",
|
|
569
|
+
title: "Table",
|
|
570
|
+
description: "Semantic table primitives for tabular data.",
|
|
571
|
+
category: "data",
|
|
572
|
+
status: "stable",
|
|
573
|
+
dependencies: [],
|
|
574
|
+
registryDependencies: [],
|
|
575
|
+
files: ["table.tsx"],
|
|
576
|
+
a11y: "A native table, so row and column position, header association and dimensions are all announced without ARIA. Give it a name with TableCaption or aria-label. The scrolling wrapper is focusable so an overflowing table can be scrolled by keyboard — without that, columns past the edge are unreachable. Use scope=\"row\" on th elements inside tbody."
|
|
577
|
+
});
|
|
578
|
+
//#endregion
|
|
579
|
+
//#region ../ui/dist/components/tabs/meta.js
|
|
580
|
+
const meta$10 = defineMeta({
|
|
581
|
+
name: "tabs",
|
|
582
|
+
title: "Tabs",
|
|
583
|
+
description: "Switches between panels of related content.",
|
|
584
|
+
category: "navigation",
|
|
585
|
+
status: "stable",
|
|
586
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
587
|
+
registryDependencies: [],
|
|
588
|
+
files: ["tabs.tsx"],
|
|
589
|
+
a11y: "Implements the ARIA tabs pattern: arrows move between tabs, Home/End jump to the ends, and only the active tab is in the tab sequence. Panels are focusable so keyboard users reach their content directly. Use activationMode=\"manual\" when showing a panel is expensive, so arrowing past it does not load it."
|
|
590
|
+
});
|
|
591
|
+
//#endregion
|
|
592
|
+
//#region ../ui/dist/components/toast/meta.js
|
|
593
|
+
const meta$9 = defineMeta({
|
|
594
|
+
name: "toast",
|
|
595
|
+
title: "Toast",
|
|
596
|
+
description: "Brief, non-blocking messages with an imperative API callable from anywhere.",
|
|
597
|
+
category: "feedback",
|
|
598
|
+
status: "stable",
|
|
599
|
+
dependencies: ["class-variance-authority", "radix-ui"],
|
|
600
|
+
registryDependencies: [],
|
|
601
|
+
files: ["toast-store.ts", "toast.tsx"],
|
|
602
|
+
a11y: "Toasts are announced through a live region: destructive and warning variants interrupt (foreground), the rest wait for a pause (background). Auto-dismiss timers pause on hover, focus and window blur, and F8 moves focus into the toast list from anywhere. An action must carry altText describing how to do the same thing without the toast, since it may be gone before a screen reader user reaches it."
|
|
603
|
+
});
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region ../ui/dist/components/tooltip/meta.js
|
|
606
|
+
const meta$8 = defineMeta({
|
|
607
|
+
name: "tooltip",
|
|
608
|
+
title: "Tooltip",
|
|
609
|
+
description: "A short label revealed on hover or keyboard focus.",
|
|
610
|
+
category: "overlay",
|
|
611
|
+
status: "stable",
|
|
612
|
+
dependencies: ["radix-ui"],
|
|
613
|
+
registryDependencies: [],
|
|
614
|
+
files: ["tooltip.tsx"],
|
|
615
|
+
a11y: "Opens on focus as well as hover, and Escape dismisses it. Never put essential or interactive content in a tooltip: it is unreachable on touch and vanishes on blur. For an icon-only button, prefer aria-label for the name and use the tooltip only to repeat it visually."
|
|
616
|
+
});
|
|
617
|
+
//#endregion
|
|
618
|
+
//#region ../ui/dist/registry/blocks.js
|
|
619
|
+
/**
|
|
620
|
+
* Every block in the registry.
|
|
621
|
+
*
|
|
622
|
+
* Kept separate from `componentMetas` for the same reason blocks install into a
|
|
623
|
+
* different directory: they are whole page sections, browsed and used
|
|
624
|
+
* differently from the components they are assembled out of.
|
|
625
|
+
*
|
|
626
|
+
* `meta.test.ts` fails if a block directory exists that is missing from here.
|
|
627
|
+
*/
|
|
628
|
+
const blockMetas = [
|
|
629
|
+
defineMeta({
|
|
630
|
+
name: "admin-users",
|
|
631
|
+
kind: "block",
|
|
632
|
+
title: "Admin — users",
|
|
633
|
+
description: "A team administration table with filtering, sorting and per-row actions.",
|
|
634
|
+
category: "data",
|
|
635
|
+
status: "stable",
|
|
636
|
+
dependencies: ["@tanstack/react-table"],
|
|
637
|
+
registryDependencies: [
|
|
638
|
+
"avatar",
|
|
639
|
+
"badge",
|
|
640
|
+
"button",
|
|
641
|
+
"data-table",
|
|
642
|
+
"dropdown-menu",
|
|
643
|
+
"empty-state",
|
|
644
|
+
"input",
|
|
645
|
+
"label"
|
|
646
|
+
],
|
|
647
|
+
files: ["admin-users.tsx"],
|
|
648
|
+
a11y: "Filtering changes the results without the user asking, so the matching count is announced politely. The filter has a real label rather than only a placeholder, which disappears the moment anyone types. Each row's action button is named after its row — four identical \"Actions\" buttons say nothing about which row you are on."
|
|
649
|
+
}),
|
|
650
|
+
defineMeta({
|
|
651
|
+
name: "ai-chat",
|
|
652
|
+
kind: "block",
|
|
653
|
+
title: "AI Chat",
|
|
654
|
+
description: "A complete chat surface: transcript, reasoning, tool calls, sources and composer.",
|
|
655
|
+
category: "ai",
|
|
656
|
+
status: "stable",
|
|
657
|
+
dependencies: [],
|
|
658
|
+
registryDependencies: [
|
|
659
|
+
"ai-conversation",
|
|
660
|
+
"ai-message",
|
|
661
|
+
"ai-model-selector",
|
|
662
|
+
"ai-prompt-input",
|
|
663
|
+
"ai-reasoning",
|
|
664
|
+
"ai-response",
|
|
665
|
+
"ai-sources",
|
|
666
|
+
"ai-token-usage",
|
|
667
|
+
"ai-tool",
|
|
668
|
+
"button",
|
|
669
|
+
"empty-state"
|
|
670
|
+
],
|
|
671
|
+
files: ["ai-chat.tsx"],
|
|
672
|
+
a11y: "Assembled from the AI components rather than reimplementing them, so their decisions still hold: the transcript is a list and not a live region, state is announced separately through ConversationStatus, and the composer will not send while an IME composition is active. Tool payloads are named per tool, so two open tool calls do not present two regions called \"Result\"."
|
|
673
|
+
}),
|
|
674
|
+
defineMeta({
|
|
675
|
+
name: "dashboard",
|
|
676
|
+
kind: "block",
|
|
677
|
+
title: "Dashboard",
|
|
678
|
+
description: "An overview page with headline metrics and a recent activity feed.",
|
|
679
|
+
category: "data",
|
|
680
|
+
status: "stable",
|
|
681
|
+
dependencies: [],
|
|
682
|
+
registryDependencies: [
|
|
683
|
+
"activity-feed",
|
|
684
|
+
"badge",
|
|
685
|
+
"card",
|
|
686
|
+
"skeleton"
|
|
687
|
+
],
|
|
688
|
+
files: ["dashboard.tsx"],
|
|
689
|
+
a11y: "Each metric states its change in words — \"up 12.4%\" — rather than by a coloured arrow, which is unreadable to a screen reader and ambiguous to anyone who cannot distinguish the colours. Whether a rise is good is configurable, since churn going up is not. The metrics sit in a named region so they can be jumped to."
|
|
690
|
+
}),
|
|
691
|
+
defineMeta({
|
|
692
|
+
name: "forgot-password",
|
|
693
|
+
kind: "block",
|
|
694
|
+
title: "Forgot password",
|
|
695
|
+
description: "A password reset request, with a confirmation that does not leak account existence.",
|
|
696
|
+
category: "form",
|
|
697
|
+
status: "stable",
|
|
698
|
+
dependencies: [],
|
|
699
|
+
registryDependencies: [
|
|
700
|
+
"button",
|
|
701
|
+
"card",
|
|
702
|
+
"empty-state",
|
|
703
|
+
"form",
|
|
704
|
+
"input"
|
|
705
|
+
],
|
|
706
|
+
files: ["forgot-password.tsx"],
|
|
707
|
+
a11y: "The confirmation replaces the form, so it is a polite live region — otherwise a screen reader user submits and hears nothing. The wording is deliberately neutral about whether the address exists: confirming it would turn this form into an account enumeration oracle."
|
|
708
|
+
}),
|
|
709
|
+
defineMeta({
|
|
710
|
+
name: "login",
|
|
711
|
+
kind: "block",
|
|
712
|
+
title: "Login",
|
|
713
|
+
description: "A sign-in form with validation, social providers and a busy state.",
|
|
714
|
+
category: "form",
|
|
715
|
+
status: "stable",
|
|
716
|
+
dependencies: [],
|
|
717
|
+
registryDependencies: [
|
|
718
|
+
"button",
|
|
719
|
+
"card",
|
|
720
|
+
"checkbox",
|
|
721
|
+
"form",
|
|
722
|
+
"input",
|
|
723
|
+
"label",
|
|
724
|
+
"separator"
|
|
725
|
+
],
|
|
726
|
+
files: ["login.tsx"],
|
|
727
|
+
a11y: "Email and password fields carry the right type and autocomplete, so password managers and mobile keyboards behave. Field errors are tied to their inputs through the Form wiring; a server error is an assertive alert, because it arrived after the user acted and explains why nothing happened. The submit button reports its own busy state rather than going quiet."
|
|
728
|
+
}),
|
|
729
|
+
defineMeta({
|
|
730
|
+
name: "pricing",
|
|
731
|
+
kind: "block",
|
|
732
|
+
title: "Pricing",
|
|
733
|
+
description: "A pricing section with plan cards and a monthly/yearly toggle.",
|
|
734
|
+
category: "layout",
|
|
735
|
+
status: "stable",
|
|
736
|
+
dependencies: [],
|
|
737
|
+
registryDependencies: [
|
|
738
|
+
"badge",
|
|
739
|
+
"button",
|
|
740
|
+
"card",
|
|
741
|
+
"label",
|
|
742
|
+
"switch"
|
|
743
|
+
],
|
|
744
|
+
files: ["pricing.tsx"],
|
|
745
|
+
a11y: "Switching the billing period rewrites every price on the page, so the change is announced politely rather than happening silently. Each plan's call to action names the plan — three buttons all reading \"Choose\" are indistinguishable out of context. Feature ticks are decorative; the feature text carries the meaning."
|
|
746
|
+
}),
|
|
747
|
+
defineMeta({
|
|
748
|
+
name: "settings",
|
|
749
|
+
kind: "block",
|
|
750
|
+
title: "Settings",
|
|
751
|
+
description: "A settings page with a profile form, immediate toggles and a danger zone.",
|
|
752
|
+
category: "form",
|
|
753
|
+
status: "stable",
|
|
754
|
+
dependencies: [],
|
|
755
|
+
registryDependencies: [
|
|
756
|
+
"avatar",
|
|
757
|
+
"button",
|
|
758
|
+
"card",
|
|
759
|
+
"dialog",
|
|
760
|
+
"form",
|
|
761
|
+
"input",
|
|
762
|
+
"label",
|
|
763
|
+
"separator",
|
|
764
|
+
"switch",
|
|
765
|
+
"tabs"
|
|
766
|
+
],
|
|
767
|
+
files: ["settings.tsx"],
|
|
768
|
+
a11y: "Switches apply immediately and have no Save button — a switch that needs saving is a broken promise, so staged changes live in the form instead. The delete confirmation names what will be destroyed and requires typing the account's email, so the destructive button cannot be reached by muscle memory."
|
|
769
|
+
}),
|
|
770
|
+
defineMeta({
|
|
771
|
+
name: "signup",
|
|
772
|
+
kind: "block",
|
|
773
|
+
title: "Sign up",
|
|
774
|
+
description: "An account creation form with a password strength hint and terms acceptance.",
|
|
775
|
+
category: "form",
|
|
776
|
+
status: "stable",
|
|
777
|
+
dependencies: [],
|
|
778
|
+
registryDependencies: [
|
|
779
|
+
"button",
|
|
780
|
+
"card",
|
|
781
|
+
"checkbox",
|
|
782
|
+
"form",
|
|
783
|
+
"input",
|
|
784
|
+
"progress"
|
|
785
|
+
],
|
|
786
|
+
files: ["signup.tsx"],
|
|
787
|
+
a11y: "The strength label is text and the bar beside it is aria-hidden, so the estimate is not announced twice. autoComplete=\"new-password\" tells password managers to offer a generated password rather than an existing one. Strength is a hint, never a gate: the form is validated on length alone."
|
|
788
|
+
})
|
|
789
|
+
];
|
|
790
|
+
//#endregion
|
|
791
|
+
//#region ../ui/dist/registry/components.js
|
|
792
|
+
/**
|
|
793
|
+
* Every component in the registry.
|
|
794
|
+
*
|
|
795
|
+
* An explicit list rather than a glob: the registry build runs in plain Node,
|
|
796
|
+
* where bundler-only globbing is unavailable, and a static list is also what
|
|
797
|
+
* lets the bundle tree-shake. `meta.test.ts` fails if a component directory
|
|
798
|
+
* exists that is missing from here, so it cannot silently fall out of date.
|
|
799
|
+
*
|
|
800
|
+
* Identifiers carry a `Meta` suffix because component names include reserved
|
|
801
|
+
* words — `switch` cannot be a binding name.
|
|
802
|
+
*/
|
|
803
|
+
const componentMetas = [
|
|
804
|
+
meta$53,
|
|
805
|
+
meta$52,
|
|
806
|
+
meta$51,
|
|
807
|
+
meta$50,
|
|
808
|
+
meta$49,
|
|
809
|
+
meta$48,
|
|
810
|
+
meta$47,
|
|
811
|
+
meta$46,
|
|
812
|
+
meta$45,
|
|
813
|
+
meta$44,
|
|
814
|
+
meta$43,
|
|
815
|
+
meta$42,
|
|
816
|
+
meta$41,
|
|
817
|
+
meta$40,
|
|
818
|
+
meta$39,
|
|
819
|
+
meta$38,
|
|
820
|
+
meta$37,
|
|
821
|
+
meta$36,
|
|
822
|
+
meta$35,
|
|
823
|
+
meta$34,
|
|
824
|
+
meta$33,
|
|
825
|
+
meta$32,
|
|
826
|
+
meta$31,
|
|
827
|
+
meta$30,
|
|
828
|
+
meta$29,
|
|
829
|
+
meta$28,
|
|
830
|
+
meta$27,
|
|
831
|
+
meta$26,
|
|
832
|
+
meta$25,
|
|
833
|
+
meta$24,
|
|
834
|
+
meta$23,
|
|
835
|
+
meta$22,
|
|
836
|
+
meta$21,
|
|
837
|
+
meta$20,
|
|
838
|
+
meta$19,
|
|
839
|
+
meta$18,
|
|
840
|
+
meta$17,
|
|
841
|
+
meta$16,
|
|
842
|
+
meta$15,
|
|
843
|
+
meta$14,
|
|
844
|
+
meta$13,
|
|
845
|
+
meta$12,
|
|
846
|
+
meta$11,
|
|
847
|
+
meta$10,
|
|
848
|
+
meta$9,
|
|
849
|
+
meta$8
|
|
850
|
+
];
|
|
851
|
+
//#endregion
|
|
852
|
+
//#region src/build.ts
|
|
853
|
+
/**
|
|
854
|
+
* Emits the public registry.
|
|
855
|
+
*
|
|
856
|
+
* Everything the CLI installs originates here, from the same source files the
|
|
857
|
+
* library itself builds and tests. There is no second copy of a component to
|
|
858
|
+
* drift out of sync.
|
|
859
|
+
*/
|
|
860
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
861
|
+
const uiSrc = join(here, "..", "..", "ui", "src");
|
|
862
|
+
const themesSrc = join(here, "..", "..", "themes", "src");
|
|
863
|
+
const uiPackageJson = JSON.parse(readFileSync(join(here, "..", "..", "ui", "package.json"), "utf8"));
|
|
864
|
+
function read(path) {
|
|
865
|
+
return readFileSync(path, "utf8");
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Turns a meta into a registry item.
|
|
869
|
+
*
|
|
870
|
+
* Components and blocks differ only in where their source lives and where it is
|
|
871
|
+
* installed, so one function covers both rather than two that drift.
|
|
872
|
+
*/
|
|
873
|
+
function buildSourceItem(meta) {
|
|
874
|
+
const isBlock = meta.kind === "block";
|
|
875
|
+
const sourceDir = join(uiSrc, isBlock ? "blocks" : "components", meta.name);
|
|
876
|
+
const group = isBlock ? "blocks" : "ui";
|
|
877
|
+
const fileType = isBlock ? "registry:block" : "registry:ui";
|
|
878
|
+
const files = meta.files.map((file) => {
|
|
879
|
+
const content = read(join(sourceDir, file));
|
|
880
|
+
return {
|
|
881
|
+
path: `${group}/${file}`,
|
|
882
|
+
type: fileType,
|
|
883
|
+
content,
|
|
884
|
+
hash: hashContent(content)
|
|
885
|
+
};
|
|
886
|
+
});
|
|
887
|
+
return registryItemSchema.parse({
|
|
888
|
+
$schema: "./schema/registry-item.json",
|
|
889
|
+
registryVersion: 1,
|
|
890
|
+
name: meta.name,
|
|
891
|
+
type: fileType,
|
|
892
|
+
title: meta.title,
|
|
893
|
+
description: meta.description,
|
|
894
|
+
category: meta.category,
|
|
895
|
+
status: meta.status,
|
|
896
|
+
dependencies: meta.dependencies,
|
|
897
|
+
registryDependencies: meta.registryDependencies,
|
|
898
|
+
files,
|
|
899
|
+
a11y: meta.a11y
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* The utilities every component imports.
|
|
904
|
+
*
|
|
905
|
+
* Written by `init` rather than by `add`, because a project needs them before
|
|
906
|
+
* the first component and every component assumes they are present.
|
|
907
|
+
*/
|
|
908
|
+
function buildUtilsItem() {
|
|
909
|
+
const files = ["utils.ts", "styles.ts"].map((file) => {
|
|
910
|
+
const content = read(join(uiSrc, "lib", file));
|
|
911
|
+
return {
|
|
912
|
+
path: `lib/${file}`,
|
|
913
|
+
type: "registry:lib",
|
|
914
|
+
content,
|
|
915
|
+
hash: hashContent(content)
|
|
916
|
+
};
|
|
917
|
+
});
|
|
918
|
+
return registryItemSchema.parse({
|
|
919
|
+
registryVersion: 1,
|
|
920
|
+
name: "utils",
|
|
921
|
+
type: "registry:lib",
|
|
922
|
+
title: "Utilities",
|
|
923
|
+
description: "The cn() class merger and the shared interaction-state fragments every component uses.",
|
|
924
|
+
category: "foundation",
|
|
925
|
+
status: "stable",
|
|
926
|
+
dependencies: ["clsx", "tailwind-merge"],
|
|
927
|
+
registryDependencies: [],
|
|
928
|
+
files
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* The design tokens, as CSS to append to the project stylesheet.
|
|
933
|
+
*
|
|
934
|
+
* Appended rather than imported from a package: a consumer who cannot edit the
|
|
935
|
+
* tokens does not really own their design system, which is the whole premise.
|
|
936
|
+
*/
|
|
937
|
+
function buildThemeItem() {
|
|
938
|
+
const content = [
|
|
939
|
+
"/* Design tokens. Safe to edit — this is your copy. */",
|
|
940
|
+
read(join(themesSrc, "tokens.css")),
|
|
941
|
+
read(join(themesSrc, "base.css"))
|
|
942
|
+
].join("\n\n");
|
|
943
|
+
return registryItemSchema.parse({
|
|
944
|
+
registryVersion: 1,
|
|
945
|
+
name: "theme",
|
|
946
|
+
type: "registry:theme",
|
|
947
|
+
title: "Theme",
|
|
948
|
+
description: "Design tokens: colour, radius, typography, elevation and motion, in light and dark.",
|
|
949
|
+
category: "foundation",
|
|
950
|
+
status: "stable",
|
|
951
|
+
dependencies: [],
|
|
952
|
+
registryDependencies: [],
|
|
953
|
+
files: [{
|
|
954
|
+
path: "theme.css",
|
|
955
|
+
type: "registry:style",
|
|
956
|
+
content,
|
|
957
|
+
hash: hashContent(content)
|
|
958
|
+
}]
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
function buildRegistry() {
|
|
962
|
+
return [
|
|
963
|
+
buildUtilsItem(),
|
|
964
|
+
buildThemeItem(),
|
|
965
|
+
...componentMetas.map(buildSourceItem),
|
|
966
|
+
...blockMetas.map(buildSourceItem)
|
|
967
|
+
];
|
|
968
|
+
}
|
|
969
|
+
function buildIndex(items) {
|
|
970
|
+
const entries = items.map((item) => ({
|
|
971
|
+
name: item.name,
|
|
972
|
+
type: item.type,
|
|
973
|
+
title: item.title,
|
|
974
|
+
description: item.description,
|
|
975
|
+
category: item.category,
|
|
976
|
+
status: item.status,
|
|
977
|
+
dependencies: item.dependencies,
|
|
978
|
+
registryDependencies: item.registryDependencies,
|
|
979
|
+
fileCount: item.files.length
|
|
980
|
+
}));
|
|
981
|
+
return registryIndexSchema.parse({
|
|
982
|
+
$schema: "./schema/registry-index.json",
|
|
983
|
+
registryVersion: 1,
|
|
984
|
+
generatedFrom: `${uiPackageJson.name}@${uiPackageJson.version}`,
|
|
985
|
+
items: entries
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
function writeRegistry(outDir) {
|
|
989
|
+
const items = buildRegistry();
|
|
990
|
+
const index = buildIndex(items);
|
|
991
|
+
rmSync(outDir, {
|
|
992
|
+
recursive: true,
|
|
993
|
+
force: true
|
|
994
|
+
});
|
|
995
|
+
mkdirSync(outDir, { recursive: true });
|
|
996
|
+
writeFileSync(join(outDir, "index.json"), `${JSON.stringify(index, null, 2)}\n`);
|
|
997
|
+
for (const item of items) writeFileSync(join(outDir, `${item.name}.json`), `${JSON.stringify(item, null, 2)}\n`);
|
|
998
|
+
return {
|
|
999
|
+
items: items.length,
|
|
1000
|
+
files: items.reduce((total, item) => total + item.files.length, 0)
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
1004
|
+
const outIndex = process.argv.indexOf("--out");
|
|
1005
|
+
const outDir = outIndex === -1 ? join(here, "..", "r") : process.argv[outIndex + 1] ?? join(here, "..", "r");
|
|
1006
|
+
const result = writeRegistry(outDir);
|
|
1007
|
+
console.log(`Registry written to ${outDir}: ${String(result.items)} items, ${String(result.files)} files.`);
|
|
1008
|
+
}
|
|
1009
|
+
//#endregion
|
|
1010
|
+
export { buildIndex, buildRegistry, writeRegistry };
|
|
1011
|
+
|
|
1012
|
+
//# sourceMappingURL=build.js.map
|