@dowel-ui/registry 0.4.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.d.ts +32 -4
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +528 -78
- package/dist/build.js.map +1 -1
- package/dist/generate.d.ts +71 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +324 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +184 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +648 -2
- package/dist/index.js.map +1 -0
- package/dist/{schema-ByqIpT47.js → schema-BbyNjH6Q.js} +25 -5
- package/dist/schema-BbyNjH6Q.js.map +1 -0
- package/dist/{schema-Cc32v3R-.d.ts → schema-BmYeKe9e.d.ts} +36 -2
- package/dist/schema-BmYeKe9e.d.ts.map +1 -0
- package/package.json +12 -4
- package/src/agent-docs.ts +544 -0
- package/src/build.ts +66 -4
- package/src/custom.ts +312 -0
- package/src/generate.ts +500 -0
- package/src/index.ts +41 -0
- package/src/schema.ts +23 -0
- package/dist/schema-ByqIpT47.js.map +0 -1
- package/dist/schema-Cc32v3R-.d.ts.map +0 -1
package/dist/build.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as hashContent, o as registryIndexSchema, s as registryItemSchema } from "./schema-BbyNjH6Q.js";
|
|
2
2
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -9,7 +9,7 @@ function defineMeta(meta) {
|
|
|
9
9
|
}
|
|
10
10
|
//#endregion
|
|
11
11
|
//#region ../ui/dist/components/accordion/meta.js
|
|
12
|
-
const meta$
|
|
12
|
+
const meta$91 = defineMeta({
|
|
13
13
|
name: "accordion",
|
|
14
14
|
title: "Accordion",
|
|
15
15
|
description: "Vertically stacked sections that expand to reveal their content.",
|
|
@@ -22,7 +22,7 @@ const meta$67 = defineMeta({
|
|
|
22
22
|
});
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region ../ui/dist/components/activity-feed/meta.js
|
|
25
|
-
const meta$
|
|
25
|
+
const meta$90 = defineMeta({
|
|
26
26
|
name: "activity-feed",
|
|
27
27
|
title: "Activity Feed",
|
|
28
28
|
description: "A chronological list of events, with a connecting timeline rail.",
|
|
@@ -35,7 +35,7 @@ const meta$66 = defineMeta({
|
|
|
35
35
|
});
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region ../ui/dist/components/ai-action-ledger/meta.js
|
|
38
|
-
const meta$
|
|
38
|
+
const meta$89 = defineMeta({
|
|
39
39
|
name: "ai-action-ledger",
|
|
40
40
|
title: "AI Action Ledger",
|
|
41
41
|
description: "What an agent actually did, classified by what can be undone.",
|
|
@@ -48,7 +48,7 @@ const meta$65 = defineMeta({
|
|
|
48
48
|
});
|
|
49
49
|
//#endregion
|
|
50
50
|
//#region ../ui/dist/components/ai-agent-plan/meta.js
|
|
51
|
-
const meta$
|
|
51
|
+
const meta$88 = defineMeta({
|
|
52
52
|
name: "ai-agent-plan",
|
|
53
53
|
title: "AI Agent Plan",
|
|
54
54
|
description: "What an agent intends to do — including when it changes its mind mid-run.",
|
|
@@ -61,7 +61,7 @@ const meta$64 = defineMeta({
|
|
|
61
61
|
});
|
|
62
62
|
//#endregion
|
|
63
63
|
//#region ../ui/dist/components/ai-agent-status/meta.js
|
|
64
|
-
const meta$
|
|
64
|
+
const meta$87 = defineMeta({
|
|
65
65
|
name: "ai-agent-status",
|
|
66
66
|
title: "AI Agent Status",
|
|
67
67
|
description: "A pill showing what an agent is doing, in words as well as colour.",
|
|
@@ -74,7 +74,7 @@ const meta$63 = defineMeta({
|
|
|
74
74
|
});
|
|
75
75
|
//#endregion
|
|
76
76
|
//#region ../ui/dist/components/ai-approval-request/meta.js
|
|
77
|
-
const meta$
|
|
77
|
+
const meta$86 = defineMeta({
|
|
78
78
|
name: "ai-approval-request",
|
|
79
79
|
title: "AI Approval Request",
|
|
80
80
|
description: "Approve a tool call — after correcting the arguments the model got wrong.",
|
|
@@ -87,7 +87,7 @@ const meta$62 = defineMeta({
|
|
|
87
87
|
});
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region ../ui/dist/components/ai-conversation/meta.js
|
|
90
|
-
const meta$
|
|
90
|
+
const meta$85 = defineMeta({
|
|
91
91
|
name: "ai-conversation",
|
|
92
92
|
title: "AI Conversation",
|
|
93
93
|
description: "The scrolling transcript container, with follow-on-new-content and a status region.",
|
|
@@ -100,7 +100,7 @@ const meta$61 = defineMeta({
|
|
|
100
100
|
});
|
|
101
101
|
//#endregion
|
|
102
102
|
//#region ../ui/dist/components/ai-disclosure/meta.js
|
|
103
|
-
const meta$
|
|
103
|
+
const meta$84 = defineMeta({
|
|
104
104
|
name: "ai-disclosure",
|
|
105
105
|
title: "AI Disclosure",
|
|
106
106
|
description: "Tells a reader they are looking at AI, and what is actually known about it.",
|
|
@@ -112,8 +112,21 @@ const meta$60 = defineMeta({
|
|
|
112
112
|
a11y: "The text is the disclosure and the icon is decoration, marked aria-hidden — a sparkle alone is a mark a sighted reader may not decode and a screen reader passes over in silence, which is the exact failure this component exists to prevent. Each of the four kinds carries wording of its own, so the distinction between generated, manipulated and human-reviewed survives for anyone who cannot see the styling. The provenance panel states in words whether anyone checked the claims and who, rather than implying it with a tick, and its three states are told apart by their sentences rather than by colour. Scope: this renders the human-visible disclosures of EU AI Act Article 50(1) and 50(4). It cannot satisfy 50(2), which requires machine-readable marking inside the artifact by whoever generated it, and no React component can. Not legal advice."
|
|
113
113
|
});
|
|
114
114
|
//#endregion
|
|
115
|
+
//#region ../ui/dist/components/ai-extraction-review/meta.js
|
|
116
|
+
const meta$83 = defineMeta({
|
|
117
|
+
name: "ai-extraction-review",
|
|
118
|
+
title: "AI Extraction Review",
|
|
119
|
+
description: "Check extracted fields against the document they came from, and decide each one.",
|
|
120
|
+
category: "ai",
|
|
121
|
+
status: "stable",
|
|
122
|
+
dependencies: [],
|
|
123
|
+
registryDependencies: [],
|
|
124
|
+
files: ["extraction-model.ts", "ai-extraction-review.tsx"],
|
|
125
|
+
a11y: "Every field quotes its evidence in text under the value, so a reviewer who cannot see the highlight in the source still has what the model read. A value with no evidence is said in words — never left to look like a good one. The source is a focusable named region because it scrolls, and its highlights are mark elements with nothing spliced into the text, since a document read aloud with field names inserted is no longer the document. Focus anywhere in a field brings its evidence into view without moving focus, so a keyboard user is shown the source rather than sent into it. Each control's name carries the field it belongs to, so ten Accept buttons are ten different buttons. Status is a word, outside the label so editing never renames the control, and the running count is a polite live region present from the start. Enter accepts, except while an IME is composing."
|
|
126
|
+
});
|
|
127
|
+
//#endregion
|
|
115
128
|
//#region ../ui/dist/components/ai-inline-completion/meta.js
|
|
116
|
-
const meta$
|
|
129
|
+
const meta$82 = defineMeta({
|
|
117
130
|
name: "ai-inline-completion",
|
|
118
131
|
title: "AI Inline Completion",
|
|
119
132
|
description: "Ghost-text suggestion inside a real textarea, accepted with Tab.",
|
|
@@ -126,7 +139,7 @@ const meta$59 = defineMeta({
|
|
|
126
139
|
});
|
|
127
140
|
//#endregion
|
|
128
141
|
//#region ../ui/dist/components/ai-message/meta.js
|
|
129
|
-
const meta$
|
|
142
|
+
const meta$81 = defineMeta({
|
|
130
143
|
name: "ai-message",
|
|
131
144
|
title: "AI Message",
|
|
132
145
|
description: "One turn in a conversation, with role, avatar, actions and footer slots.",
|
|
@@ -139,7 +152,7 @@ const meta$58 = defineMeta({
|
|
|
139
152
|
});
|
|
140
153
|
//#endregion
|
|
141
154
|
//#region ../ui/dist/components/ai-model-selector/meta.js
|
|
142
|
-
const meta$
|
|
155
|
+
const meta$80 = defineMeta({
|
|
143
156
|
name: "ai-model-selector",
|
|
144
157
|
title: "AI Model Selector",
|
|
145
158
|
description: "Picks the model a conversation runs on, with descriptions and availability.",
|
|
@@ -152,7 +165,7 @@ const meta$57 = defineMeta({
|
|
|
152
165
|
});
|
|
153
166
|
//#endregion
|
|
154
167
|
//#region ../ui/dist/components/ai-prompt-input/meta.js
|
|
155
|
-
const meta$
|
|
168
|
+
const meta$79 = defineMeta({
|
|
156
169
|
name: "ai-prompt-input",
|
|
157
170
|
title: "AI Prompt Input",
|
|
158
171
|
description: "The composer: auto-growing textarea, send-on-Enter, and a send/stop control.",
|
|
@@ -165,7 +178,7 @@ const meta$56 = defineMeta({
|
|
|
165
178
|
});
|
|
166
179
|
//#endregion
|
|
167
180
|
//#region ../ui/dist/components/ai-reasoning/meta.js
|
|
168
|
-
const meta$
|
|
181
|
+
const meta$78 = defineMeta({
|
|
169
182
|
name: "ai-reasoning",
|
|
170
183
|
title: "AI Reasoning",
|
|
171
184
|
description: "A collapsible disclosure for the model's reasoning.",
|
|
@@ -178,7 +191,7 @@ const meta$55 = defineMeta({
|
|
|
178
191
|
});
|
|
179
192
|
//#endregion
|
|
180
193
|
//#region ../ui/dist/components/ai-response/meta.js
|
|
181
|
-
const meta$
|
|
194
|
+
const meta$77 = defineMeta({
|
|
182
195
|
name: "ai-response",
|
|
183
196
|
title: "AI Response",
|
|
184
197
|
description: "Assistant response text, with a streaming caret and a thinking indicator.",
|
|
@@ -191,7 +204,7 @@ const meta$54 = defineMeta({
|
|
|
191
204
|
});
|
|
192
205
|
//#endregion
|
|
193
206
|
//#region ../ui/dist/components/ai-sources/meta.js
|
|
194
|
-
const meta$
|
|
207
|
+
const meta$76 = defineMeta({
|
|
195
208
|
name: "ai-sources",
|
|
196
209
|
title: "AI Sources",
|
|
197
210
|
description: "Inline citation markers and the source list they refer to.",
|
|
@@ -204,7 +217,7 @@ const meta$53 = defineMeta({
|
|
|
204
217
|
});
|
|
205
218
|
//#endregion
|
|
206
219
|
//#region ../ui/dist/components/ai-structured-output/meta.js
|
|
207
|
-
const meta$
|
|
220
|
+
const meta$75 = defineMeta({
|
|
208
221
|
name: "ai-structured-output",
|
|
209
222
|
title: "AI Structured Output",
|
|
210
223
|
description: "An object arriving field by field from the model, without the layout jumping.",
|
|
@@ -216,8 +229,21 @@ const meta$52 = defineMeta({
|
|
|
216
229
|
a11y: "A description list, so each value is associated with its label rather than floating beside it. The region is aria-live=\"polite\" with aria-busy while streaming, so fields are announced as they settle instead of re-reading the whole object on every token. Height is reserved from the declared field list, which keeps focus and reading position stable as values arrive. Confidence is stated as a number in words, never as a colour alone."
|
|
217
230
|
});
|
|
218
231
|
//#endregion
|
|
232
|
+
//#region ../ui/dist/components/ai-suggested-value/meta.js
|
|
233
|
+
const meta$74 = defineMeta({
|
|
234
|
+
name: "ai-suggested-value",
|
|
235
|
+
title: "AI Suggested Value",
|
|
236
|
+
description: "An AI-proposed value for any form control, pending until accepted and marked afterwards.",
|
|
237
|
+
category: "ai",
|
|
238
|
+
status: "stable",
|
|
239
|
+
dependencies: [],
|
|
240
|
+
registryDependencies: [],
|
|
241
|
+
files: ["ai-suggested-value.tsx"],
|
|
242
|
+
a11y: "The suggestion is the control's description, so a reader who lands on the field hears it without any announcement — and announcing is opt-in, because a form filling twenty fields at once would narrate all twenty. The row that holds it is rendered from the start and never display:none, so when announcing is on, a suggestion arriving after mount is actually heard. Each button's name carries the field it belongs to, so a page of Accepts is a page of different buttons. Provenance and confidence are words with a number, never a colour. Acceptance is reported, not performed: the control is the consumer's, so its value, its label and its own keyboard behaviour are untouched — there is no shortcut hijacked from a select or a date field. The id and ARIA a FormControl passes down are forwarded to the control, and an existing aria-describedby is merged rather than replaced."
|
|
243
|
+
});
|
|
244
|
+
//#endregion
|
|
219
245
|
//#region ../ui/dist/components/ai-token-usage/meta.js
|
|
220
|
-
const meta$
|
|
246
|
+
const meta$73 = defineMeta({
|
|
221
247
|
name: "ai-token-usage",
|
|
222
248
|
title: "AI Token Usage",
|
|
223
249
|
description: "A gauge showing how much of the context window a conversation has used.",
|
|
@@ -230,7 +256,7 @@ const meta$51 = defineMeta({
|
|
|
230
256
|
});
|
|
231
257
|
//#endregion
|
|
232
258
|
//#region ../ui/dist/components/ai-tool/meta.js
|
|
233
|
-
const meta$
|
|
259
|
+
const meta$72 = defineMeta({
|
|
234
260
|
name: "ai-tool",
|
|
235
261
|
title: "AI Tool Call",
|
|
236
262
|
description: "A collapsible record of a tool the model called, its arguments and its result.",
|
|
@@ -243,7 +269,7 @@ const meta$50 = defineMeta({
|
|
|
243
269
|
});
|
|
244
270
|
//#endregion
|
|
245
271
|
//#region ../ui/dist/components/alert/meta.js
|
|
246
|
-
const meta$
|
|
272
|
+
const meta$71 = defineMeta({
|
|
247
273
|
name: "alert",
|
|
248
274
|
title: "Alert",
|
|
249
275
|
description: "A callout that draws attention to an important message.",
|
|
@@ -256,7 +282,7 @@ const meta$49 = defineMeta({
|
|
|
256
282
|
});
|
|
257
283
|
//#endregion
|
|
258
284
|
//#region ../ui/dist/components/avatar/meta.js
|
|
259
|
-
const meta$
|
|
285
|
+
const meta$70 = defineMeta({
|
|
260
286
|
name: "avatar",
|
|
261
287
|
title: "Avatar",
|
|
262
288
|
description: "An image representation of a user or entity with a graceful text fallback.",
|
|
@@ -269,7 +295,7 @@ const meta$48 = defineMeta({
|
|
|
269
295
|
});
|
|
270
296
|
//#endregion
|
|
271
297
|
//#region ../ui/dist/components/badge/meta.js
|
|
272
|
-
const meta$
|
|
298
|
+
const meta$69 = defineMeta({
|
|
273
299
|
name: "badge",
|
|
274
300
|
title: "Badge",
|
|
275
301
|
description: "A compact marker for status, counts and categories.",
|
|
@@ -281,8 +307,21 @@ const meta$47 = defineMeta({
|
|
|
281
307
|
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."
|
|
282
308
|
});
|
|
283
309
|
//#endregion
|
|
310
|
+
//#region ../ui/dist/components/breadcrumb/meta.js
|
|
311
|
+
const meta$68 = defineMeta({
|
|
312
|
+
name: "breadcrumb",
|
|
313
|
+
title: "Breadcrumb",
|
|
314
|
+
description: "Where the current page sits in the hierarchy, and how to get back up it.",
|
|
315
|
+
category: "navigation",
|
|
316
|
+
status: "stable",
|
|
317
|
+
dependencies: ["radix-ui"],
|
|
318
|
+
registryDependencies: [],
|
|
319
|
+
files: ["breadcrumb.tsx"],
|
|
320
|
+
a11y: "The current page is a span carrying aria-current=\"page\", not a link: a link to the page you are already on does nothing, and in a list of links it is indistinguishable from the ones that go somewhere. Separators are hidden from assistive technology, because the list already conveys the sequence and reading \"slash\" between every item is the design's punctuation leaking into the content. The ellipsis is the exception and is named, because it is content: it says levels have been left out."
|
|
321
|
+
});
|
|
322
|
+
//#endregion
|
|
284
323
|
//#region ../ui/dist/components/button/meta.js
|
|
285
|
-
const meta$
|
|
324
|
+
const meta$67 = defineMeta({
|
|
286
325
|
name: "button",
|
|
287
326
|
title: "Button",
|
|
288
327
|
description: "Triggers an action or event, with variants for every level of emphasis.",
|
|
@@ -295,7 +334,7 @@ const meta$46 = defineMeta({
|
|
|
295
334
|
});
|
|
296
335
|
//#endregion
|
|
297
336
|
//#region ../ui/dist/components/calendar/meta.js
|
|
298
|
-
const meta$
|
|
337
|
+
const meta$66 = defineMeta({
|
|
299
338
|
name: "calendar",
|
|
300
339
|
title: "Calendar",
|
|
301
340
|
description: "A date grid for selecting a day, several days or a range.",
|
|
@@ -308,7 +347,7 @@ const meta$45 = defineMeta({
|
|
|
308
347
|
});
|
|
309
348
|
//#endregion
|
|
310
349
|
//#region ../ui/dist/components/card/meta.js
|
|
311
|
-
const meta$
|
|
350
|
+
const meta$65 = defineMeta({
|
|
312
351
|
name: "card",
|
|
313
352
|
title: "Card",
|
|
314
353
|
description: "A surface that groups related content and actions into a single block.",
|
|
@@ -321,7 +360,7 @@ const meta$44 = defineMeta({
|
|
|
321
360
|
});
|
|
322
361
|
//#endregion
|
|
323
362
|
//#region ../ui/dist/components/checkbox/meta.js
|
|
324
|
-
const meta$
|
|
363
|
+
const meta$64 = defineMeta({
|
|
325
364
|
name: "checkbox",
|
|
326
365
|
title: "Checkbox",
|
|
327
366
|
description: "A control for an on/off choice, with support for an indeterminate state.",
|
|
@@ -334,7 +373,7 @@ const meta$43 = defineMeta({
|
|
|
334
373
|
});
|
|
335
374
|
//#endregion
|
|
336
375
|
//#region ../ui/dist/components/code-block/meta.js
|
|
337
|
-
const meta$
|
|
376
|
+
const meta$63 = defineMeta({
|
|
338
377
|
name: "code-block",
|
|
339
378
|
title: "Code Block",
|
|
340
379
|
description: "A block of code with a copy control, ready for any highlighter.",
|
|
@@ -346,8 +385,21 @@ const meta$42 = defineMeta({
|
|
|
346
385
|
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."
|
|
347
386
|
});
|
|
348
387
|
//#endregion
|
|
388
|
+
//#region ../ui/dist/components/collapsible/meta.js
|
|
389
|
+
const meta$62 = defineMeta({
|
|
390
|
+
name: "collapsible",
|
|
391
|
+
title: "Collapsible",
|
|
392
|
+
description: "A single section that opens and closes, without an accordion's set semantics.",
|
|
393
|
+
category: "layout",
|
|
394
|
+
status: "stable",
|
|
395
|
+
dependencies: ["radix-ui"],
|
|
396
|
+
registryDependencies: [],
|
|
397
|
+
files: ["collapsible.tsx"],
|
|
398
|
+
a11y: "The trigger carries aria-expanded and points at the region it controls, both from the primitive. Reach for this rather than an Accordion of one item: a single-item Accordion gives its trigger a heading role and a position in a list of one, neither of which is true."
|
|
399
|
+
});
|
|
400
|
+
//#endregion
|
|
349
401
|
//#region ../ui/dist/components/combobox/meta.js
|
|
350
|
-
const meta$
|
|
402
|
+
const meta$61 = defineMeta({
|
|
351
403
|
name: "combobox",
|
|
352
404
|
title: "Combobox",
|
|
353
405
|
description: "A searchable single-select built on the ARIA combobox pattern.",
|
|
@@ -360,7 +412,7 @@ const meta$41 = defineMeta({
|
|
|
360
412
|
});
|
|
361
413
|
//#endregion
|
|
362
414
|
//#region ../ui/dist/components/command/meta.js
|
|
363
|
-
const meta$
|
|
415
|
+
const meta$60 = defineMeta({
|
|
364
416
|
name: "command",
|
|
365
417
|
title: "Command",
|
|
366
418
|
description: "A searchable command palette, with groups and a ⌘K dialog variant.",
|
|
@@ -372,8 +424,34 @@ const meta$40 = defineMeta({
|
|
|
372
424
|
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."
|
|
373
425
|
});
|
|
374
426
|
//#endregion
|
|
427
|
+
//#region ../ui/dist/components/confirm-typed/meta.js
|
|
428
|
+
const meta$59 = defineMeta({
|
|
429
|
+
name: "confirm-typed",
|
|
430
|
+
title: "Confirm Typed",
|
|
431
|
+
description: "Type the name to confirm — and be told, not ignored, when it does not match.",
|
|
432
|
+
category: "form",
|
|
433
|
+
status: "stable",
|
|
434
|
+
dependencies: [],
|
|
435
|
+
registryDependencies: ["button", "input"],
|
|
436
|
+
files: ["confirm-typed.tsx"],
|
|
437
|
+
a11y: "The button stays reachable while the text does not match, dimmed rather than disabled, and pressing it or Enter announces what was expected, marks the field invalid and returns focus to it — the common version disables the button and says nothing, so a keyboard user cannot tell whether anything happened. The match is announced once, on the transition, naming the action that became available, so nobody has to watch the button change colour. Typing itself stays silent, because a verdict on every keystroke is noise. The hint is the field's description and the button's, and the status region exists from the first render so the first announcement is heard. Pasting is allowed: blocking it punishes people who cannot type a long name easily and stops nobody who can select-all and copy."
|
|
438
|
+
});
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region ../ui/dist/components/cron-editor/meta.js
|
|
441
|
+
const meta$58 = defineMeta({
|
|
442
|
+
name: "cron-editor",
|
|
443
|
+
title: "Cron Editor",
|
|
444
|
+
description: "A schedule as a cron expression, with a plain-language reading and the next runs.",
|
|
445
|
+
category: "form",
|
|
446
|
+
status: "stable",
|
|
447
|
+
dependencies: [],
|
|
448
|
+
registryDependencies: ["input", "select"],
|
|
449
|
+
files: ["cron-expression.ts", "cron-editor.tsx"],
|
|
450
|
+
a11y: "The expression field is described by one element that holds either the plain-language reading or the reason the expression is invalid, so a reader hears the error replace the reading rather than both at once; an invalid expression is never applied. The builder's day buttons are a named group of aria-pressed toggles with the full day name as the accessible name, and the last selected day cannot be removed silently — the group says why. Days 29 to 31 say in text that shorter months skip them. Next runs are a list of time elements with machine-readable datetimes, headed by the zone they are in, because a time with no zone is the classic scheduling mistake. Nothing clock-dependent renders until the clock is known, so server and client cannot disagree."
|
|
451
|
+
});
|
|
452
|
+
//#endregion
|
|
375
453
|
//#region ../ui/dist/components/data-table/meta.js
|
|
376
|
-
const meta$
|
|
454
|
+
const meta$57 = defineMeta({
|
|
377
455
|
name: "data-table",
|
|
378
456
|
title: "Data Table",
|
|
379
457
|
description: "Presentation for a TanStack Table instance: sorting, column visibility and pagination.",
|
|
@@ -391,7 +469,7 @@ const meta$39 = defineMeta({
|
|
|
391
469
|
});
|
|
392
470
|
//#endregion
|
|
393
471
|
//#region ../ui/dist/components/date-picker/meta.js
|
|
394
|
-
const meta$
|
|
472
|
+
const meta$56 = defineMeta({
|
|
395
473
|
name: "date-picker",
|
|
396
474
|
title: "Date Picker",
|
|
397
475
|
description: "A button that opens a calendar to pick a date or a date range.",
|
|
@@ -407,8 +485,21 @@ const meta$38 = defineMeta({
|
|
|
407
485
|
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."
|
|
408
486
|
});
|
|
409
487
|
//#endregion
|
|
488
|
+
//#region ../ui/dist/components/direction/meta.js
|
|
489
|
+
const meta$55 = defineMeta({
|
|
490
|
+
name: "direction",
|
|
491
|
+
title: "Direction Provider",
|
|
492
|
+
description: "Tells the component primitives which way the writing runs, so menus and sliders mirror with the rest of the page.",
|
|
493
|
+
category: "foundation",
|
|
494
|
+
status: "stable",
|
|
495
|
+
dependencies: ["radix-ui"],
|
|
496
|
+
registryDependencies: [],
|
|
497
|
+
files: ["direction.tsx"],
|
|
498
|
+
a11y: "Needed only for right-to-left languages, and needed in addition to `dir` on the document rather than instead of it. The styling here is written with logical properties and follows `dir` by itself; the primitives underneath read direction from React context and assume left-to-right without a provider, which mirrors a page correctly except for its menus, selects and sliders — worse than not mirroring at all, because it looks deliberate."
|
|
499
|
+
});
|
|
500
|
+
//#endregion
|
|
410
501
|
//#region ../ui/dist/components/dialog/meta.js
|
|
411
|
-
const meta$
|
|
502
|
+
const meta$54 = defineMeta({
|
|
412
503
|
name: "dialog",
|
|
413
504
|
title: "Dialog",
|
|
414
505
|
description: "A modal window that interrupts the user to gather a response.",
|
|
@@ -421,7 +512,7 @@ const meta$37 = defineMeta({
|
|
|
421
512
|
});
|
|
422
513
|
//#endregion
|
|
423
514
|
//#region ../ui/dist/components/diff-viewer/meta.js
|
|
424
|
-
const meta$
|
|
515
|
+
const meta$53 = defineMeta({
|
|
425
516
|
name: "diff-viewer",
|
|
426
517
|
title: "Diff Viewer",
|
|
427
518
|
description: "A diff you can style, and accept or reject hunk by hunk.",
|
|
@@ -433,8 +524,21 @@ const meta$36 = defineMeta({
|
|
|
433
524
|
a11y: "A semantic table, not a grid. role=\"grid\" would promise cell-by-cell arrow navigation that does not exist here and makes no sense for reading code. Every row states added, removed or unchanged in text, because a plus sign and a green tint are not information — a diff read aloud without it is just the same file twice. Line numbers are aria-hidden: they orient a sighted reader, and announcing two numbers before every line makes the diff unlistenable. Changed words are marked with mark elements so they survive as structure, and the empty half of a split pair is hidden rather than read as a blank line of code."
|
|
434
525
|
});
|
|
435
526
|
//#endregion
|
|
527
|
+
//#region ../ui/dist/components/dns-record/meta.js
|
|
528
|
+
const meta$52 = defineMeta({
|
|
529
|
+
name: "dns-record",
|
|
530
|
+
title: "DNS Record",
|
|
531
|
+
description: "Add this record at your provider: parts copied separately, checked with what was found.",
|
|
532
|
+
category: "data",
|
|
533
|
+
status: "stable",
|
|
534
|
+
dependencies: [],
|
|
535
|
+
registryDependencies: ["button", "spinner"],
|
|
536
|
+
files: ["dns-record.tsx"],
|
|
537
|
+
a11y: "The card is a region named by the record's type and purpose. Each part is a definition with its own copy button, named by the part it copies, so five Copy buttons are five different buttons. Verification status is a word in a polite live region, so the answer to a check arrives where it was asked for, and the card is aria-busy while checking. Copy results are announced in a separate region, present from the start, so a copy never replaces a check result mid-sentence; failure is announced with what to do instead. What the check found is a list, not a colour."
|
|
538
|
+
});
|
|
539
|
+
//#endregion
|
|
436
540
|
//#region ../ui/dist/components/drawer/meta.js
|
|
437
|
-
const meta$
|
|
541
|
+
const meta$51 = defineMeta({
|
|
438
542
|
name: "drawer",
|
|
439
543
|
title: "Drawer",
|
|
440
544
|
description: "A bottom sheet that can be dismissed by dragging it down.",
|
|
@@ -447,7 +551,7 @@ const meta$35 = defineMeta({
|
|
|
447
551
|
});
|
|
448
552
|
//#endregion
|
|
449
553
|
//#region ../ui/dist/components/dropdown-menu/meta.js
|
|
450
|
-
const meta$
|
|
554
|
+
const meta$50 = defineMeta({
|
|
451
555
|
name: "dropdown-menu",
|
|
452
556
|
title: "Dropdown Menu",
|
|
453
557
|
description: "A menu of actions revealed from a trigger, with submenus and selectable items.",
|
|
@@ -460,7 +564,7 @@ const meta$34 = defineMeta({
|
|
|
460
564
|
});
|
|
461
565
|
//#endregion
|
|
462
566
|
//#region ../ui/dist/components/empty-state/meta.js
|
|
463
|
-
const meta$
|
|
567
|
+
const meta$49 = defineMeta({
|
|
464
568
|
name: "empty-state",
|
|
465
569
|
title: "Empty State",
|
|
466
570
|
description: "Shown where content would be, explaining why it is empty and what to do next.",
|
|
@@ -473,7 +577,7 @@ const meta$33 = defineMeta({
|
|
|
473
577
|
});
|
|
474
578
|
//#endregion
|
|
475
579
|
//#region ../ui/dist/components/file-upload/meta.js
|
|
476
|
-
const meta$
|
|
580
|
+
const meta$48 = defineMeta({
|
|
477
581
|
name: "file-upload",
|
|
478
582
|
title: "File Upload",
|
|
479
583
|
description: "A dropzone over a real file input, plus the upload queue nobody ships.",
|
|
@@ -486,7 +590,7 @@ const meta$32 = defineMeta({
|
|
|
486
590
|
});
|
|
487
591
|
//#endregion
|
|
488
592
|
//#region ../ui/dist/components/form/meta.js
|
|
489
|
-
const meta$
|
|
593
|
+
const meta$47 = defineMeta({
|
|
490
594
|
name: "form",
|
|
491
595
|
title: "Form",
|
|
492
596
|
description: "Accessible field wiring that works with any form library, or none.",
|
|
@@ -499,7 +603,7 @@ const meta$31 = defineMeta({
|
|
|
499
603
|
});
|
|
500
604
|
//#endregion
|
|
501
605
|
//#region ../ui/dist/components/input/meta.js
|
|
502
|
-
const meta$
|
|
606
|
+
const meta$46 = defineMeta({
|
|
503
607
|
name: "input",
|
|
504
608
|
title: "Input",
|
|
505
609
|
description: "A single-line text field with size variants and native validation styling.",
|
|
@@ -512,7 +616,7 @@ const meta$30 = defineMeta({
|
|
|
512
616
|
});
|
|
513
617
|
//#endregion
|
|
514
618
|
//#region ../ui/dist/components/label/meta.js
|
|
515
|
-
const meta$
|
|
619
|
+
const meta$45 = defineMeta({
|
|
516
620
|
name: "label",
|
|
517
621
|
title: "Label",
|
|
518
622
|
description: "An accessible caption that associates text with a form control.",
|
|
@@ -525,7 +629,7 @@ const meta$29 = defineMeta({
|
|
|
525
629
|
});
|
|
526
630
|
//#endregion
|
|
527
631
|
//#region ../ui/dist/components/log-viewer/meta.js
|
|
528
|
-
const meta$
|
|
632
|
+
const meta$44 = defineMeta({
|
|
529
633
|
name: "log-viewer",
|
|
530
634
|
title: "Log Viewer",
|
|
531
635
|
description: "A streaming console with filtering, level facets and follow mode.",
|
|
@@ -538,7 +642,7 @@ const meta$28 = defineMeta({
|
|
|
538
642
|
});
|
|
539
643
|
//#endregion
|
|
540
644
|
//#region ../ui/dist/components/meter/meta.js
|
|
541
|
-
const meta$
|
|
645
|
+
const meta$43 = defineMeta({
|
|
542
646
|
name: "meter",
|
|
543
647
|
title: "Meter",
|
|
544
648
|
description: "A measurement against a capacity — quota, seats, spend — segmented by category.",
|
|
@@ -551,7 +655,7 @@ const meta$27 = defineMeta({
|
|
|
551
655
|
});
|
|
552
656
|
//#endregion
|
|
553
657
|
//#region ../ui/dist/components/metric-delta/meta.js
|
|
554
|
-
const meta$
|
|
658
|
+
const meta$42 = defineMeta({
|
|
555
659
|
name: "metric-delta",
|
|
556
660
|
title: "Metric Delta",
|
|
557
661
|
description: "A headline number with a change indicator that knows which direction is good.",
|
|
@@ -564,7 +668,7 @@ const meta$26 = defineMeta({
|
|
|
564
668
|
});
|
|
565
669
|
//#endregion
|
|
566
670
|
//#region ../ui/dist/components/pagination/meta.js
|
|
567
|
-
const meta$
|
|
671
|
+
const meta$41 = defineMeta({
|
|
568
672
|
name: "pagination",
|
|
569
673
|
title: "Pagination",
|
|
570
674
|
description: "Navigation between pages of a list.",
|
|
@@ -576,8 +680,21 @@ const meta$25 = defineMeta({
|
|
|
576
680
|
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."
|
|
577
681
|
});
|
|
578
682
|
//#endregion
|
|
683
|
+
//#region ../ui/dist/components/permission-matrix/meta.js
|
|
684
|
+
const meta$40 = defineMeta({
|
|
685
|
+
name: "permission-matrix",
|
|
686
|
+
title: "Permission Matrix",
|
|
687
|
+
description: "Roles across, permissions down, with inheritance, locked roles and one tab stop.",
|
|
688
|
+
category: "data",
|
|
689
|
+
status: "stable",
|
|
690
|
+
dependencies: [],
|
|
691
|
+
registryDependencies: ["checkbox"],
|
|
692
|
+
files: ["permission-model.ts", "permission-matrix.tsx"],
|
|
693
|
+
a11y: "A grid in the WAI-ARIA sense: role=\"grid\" with one tab stop, arrow keys between cells, Home and End along a row and Ctrl with them across the whole matrix — the right call for a matrix that is operated, where it was the wrong one for a diff that is read. Every checkbox is named by both coordinates, \"Delete projects for Editor\", so a reader arriving by arrow key knows where they are without re-reading the headers. An inherited grant is a checked box that cannot be changed here, marked aria-disabled rather than disabled so it stays in the keyboard path, with the role it came from as its description. A locked role says in each cell's description that nothing can be changed. Group toggles are tri-state, and the column header counts each role's grants in text."
|
|
694
|
+
});
|
|
695
|
+
//#endregion
|
|
579
696
|
//#region ../ui/dist/components/popover/meta.js
|
|
580
|
-
const meta$
|
|
697
|
+
const meta$39 = defineMeta({
|
|
581
698
|
name: "popover",
|
|
582
699
|
title: "Popover",
|
|
583
700
|
description: "Rich floating content anchored to a trigger.",
|
|
@@ -590,7 +707,7 @@ const meta$24 = defineMeta({
|
|
|
590
707
|
});
|
|
591
708
|
//#endregion
|
|
592
709
|
//#region ../ui/dist/components/progress/meta.js
|
|
593
|
-
const meta$
|
|
710
|
+
const meta$38 = defineMeta({
|
|
594
711
|
name: "progress",
|
|
595
712
|
title: "Progress",
|
|
596
713
|
description: "Shows how far along a task is, or that one is running at all.",
|
|
@@ -603,7 +720,7 @@ const meta$23 = defineMeta({
|
|
|
603
720
|
});
|
|
604
721
|
//#endregion
|
|
605
722
|
//#region ../ui/dist/components/radio-group/meta.js
|
|
606
|
-
const meta$
|
|
723
|
+
const meta$37 = defineMeta({
|
|
607
724
|
name: "radio-group",
|
|
608
725
|
title: "Radio Group",
|
|
609
726
|
description: "A set of mutually exclusive options.",
|
|
@@ -616,7 +733,7 @@ const meta$22 = defineMeta({
|
|
|
616
733
|
});
|
|
617
734
|
//#endregion
|
|
618
735
|
//#region ../ui/dist/components/record-diff/meta.js
|
|
619
|
-
const meta$
|
|
736
|
+
const meta$36 = defineMeta({
|
|
620
737
|
name: "record-diff",
|
|
621
738
|
title: "Record Diff",
|
|
622
739
|
description: "Field-level before and after, for audit entries, settings history and revisions.",
|
|
@@ -628,8 +745,21 @@ const meta$21 = defineMeta({
|
|
|
628
745
|
a11y: "A real table, not a grid of divs. Each field name is a th with scope=\"row\", so a value is announced with the field it belongs to rather than as a loose cell. The kind of change is never carried by row colour alone — every row states added, removed or changed in text for screen readers, satisfying WCAG 1.4.1. The unchanged-field toggle is a real button with aria-expanded. Redacted values never reach the DOM at all."
|
|
629
746
|
});
|
|
630
747
|
//#endregion
|
|
748
|
+
//#region ../ui/dist/components/secret-field/meta.js
|
|
749
|
+
const meta$35 = defineMeta({
|
|
750
|
+
name: "secret-field",
|
|
751
|
+
title: "Secret Field",
|
|
752
|
+
description: "An API key in its three states: shown once, hidden but revealable, and gone.",
|
|
753
|
+
category: "form",
|
|
754
|
+
status: "stable",
|
|
755
|
+
dependencies: [],
|
|
756
|
+
registryDependencies: ["button", "input"],
|
|
757
|
+
files: ["secret-field.tsx"],
|
|
758
|
+
a11y: "The value sits in a read-only input rather than a disabled one, so it can be focused, selected and read, and focusing a shown value selects all of it for copying by hand. The field's state — shown once, hidden, revealed, gone — is a sentence attached as its description, never a colour or an icon. Copying is announced through a status region that exists before the first copy, and failure is announced too, with what to do instead, because the clipboard can be refused. Every button carries the field's label in its name, so a settings page with several keys has several distinct Copy buttons. Regenerating is confirmed inline in a named group that states the consequence, since it revokes the current key."
|
|
759
|
+
});
|
|
760
|
+
//#endregion
|
|
631
761
|
//#region ../ui/dist/components/select/meta.js
|
|
632
|
-
const meta$
|
|
762
|
+
const meta$34 = defineMeta({
|
|
633
763
|
name: "select",
|
|
634
764
|
title: "Select",
|
|
635
765
|
description: "Picks one value from a short list of options.",
|
|
@@ -642,7 +772,7 @@ const meta$20 = defineMeta({
|
|
|
642
772
|
});
|
|
643
773
|
//#endregion
|
|
644
774
|
//#region ../ui/dist/components/separator/meta.js
|
|
645
|
-
const meta$
|
|
775
|
+
const meta$33 = defineMeta({
|
|
646
776
|
name: "separator",
|
|
647
777
|
title: "Separator",
|
|
648
778
|
description: "A horizontal or vertical rule that divides content.",
|
|
@@ -654,8 +784,34 @@ const meta$19 = defineMeta({
|
|
|
654
784
|
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."
|
|
655
785
|
});
|
|
656
786
|
//#endregion
|
|
787
|
+
//#region ../ui/dist/components/session-expiry/meta.js
|
|
788
|
+
const meta$32 = defineMeta({
|
|
789
|
+
name: "session-expiry",
|
|
790
|
+
title: "Session Expiry",
|
|
791
|
+
description: "The idle-timeout warning WCAG 2.2.1 asks for: warned, extendable, and not dismissable by accident.",
|
|
792
|
+
category: "feedback",
|
|
793
|
+
status: "stable",
|
|
794
|
+
dependencies: [],
|
|
795
|
+
registryDependencies: ["button", "dialog"],
|
|
796
|
+
files: ["session-expiry.tsx"],
|
|
797
|
+
a11y: "An alert dialog, named by its heading and described by the sentence that says how long is left. Escape and the backdrop do nothing, because dismissing a session warning without choosing is choosing nothing; the two buttons are the way out, and focus opens on the safe one. The visible countdown is not live — a number every second for two minutes drowns the question — and a separate status region speaks four times: when the warning opens, at one minute, thirty seconds and ten, still saying a threshold a slow tick skipped over. The clock is read in an effect, so the server renders nothing rather than a countdown from the wrong instant. This satisfies the warn-and-extend half of WCAG 2.2.1 Timing Adjustable; the twenty-second minimum is the default window's business and the application's."
|
|
798
|
+
});
|
|
799
|
+
//#endregion
|
|
800
|
+
//#region ../ui/dist/components/sidebar/meta.js
|
|
801
|
+
const meta$31 = defineMeta({
|
|
802
|
+
name: "sidebar",
|
|
803
|
+
title: "Sidebar",
|
|
804
|
+
description: "The application's own navigation: a collapsible rail on a wide screen, an overlay on a narrow one.",
|
|
805
|
+
category: "navigation",
|
|
806
|
+
status: "stable",
|
|
807
|
+
dependencies: ["radix-ui"],
|
|
808
|
+
registryDependencies: ["sheet"],
|
|
809
|
+
files: ["sidebar.tsx"],
|
|
810
|
+
a11y: "The navigation landmark must be named — a page has several, and three regions all called \"navigation\" is a list nobody can choose from. The active entry carries aria-current=\"page\" rather than only a background colour. On a narrow screen it is a Sheet, not a styled div: an overlay needs a focus trap and an Escape key, and without them the page behind stays reachable by Tab while the menu covers it. When the rail collapses, labels are visually hidden rather than removed — removing them leaves controls whose only content is an icon, which is how a collapsed sidebar becomes a column of links all announced as \"link\". The trigger says what pressing it will do, not what the state currently is. The overlay is mounted only on a narrow screen and has its own open state: a modal dialog that CSS hides is still modal, and mounting it always made every wide screen aria-hidden and unclickable whenever the rail was open."
|
|
811
|
+
});
|
|
812
|
+
//#endregion
|
|
657
813
|
//#region ../ui/dist/components/sheet/meta.js
|
|
658
|
-
const meta$
|
|
814
|
+
const meta$30 = defineMeta({
|
|
659
815
|
name: "sheet",
|
|
660
816
|
title: "Sheet",
|
|
661
817
|
description: "A panel that enters from an edge of the viewport for secondary content.",
|
|
@@ -667,8 +823,21 @@ const meta$18 = defineMeta({
|
|
|
667
823
|
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."
|
|
668
824
|
});
|
|
669
825
|
//#endregion
|
|
826
|
+
//#region ../ui/dist/components/shortcut-recorder/meta.js
|
|
827
|
+
const meta$29 = defineMeta({
|
|
828
|
+
name: "shortcut-recorder",
|
|
829
|
+
title: "Shortcut Recorder",
|
|
830
|
+
description: "Press the keys you want: records a chord, platform-aware, and says when it clashes.",
|
|
831
|
+
category: "form",
|
|
832
|
+
status: "stable",
|
|
833
|
+
dependencies: [],
|
|
834
|
+
registryDependencies: [],
|
|
835
|
+
files: ["shortcut-model.ts", "shortcut-recorder.tsx"],
|
|
836
|
+
a11y: "The recorder is a button named by what the shortcut does and described by its value in words — Command Shift K — while the key caps on it are hidden from assistive technology, since ⌘⇧K read aloud is noise. While recording it is aria-pressed and its description says what to do; Tab always leaves and Escape always cancels, so it is never a keyboard trap. Every outcome is announced through a status region present from the start: recorded, refused with the reason, clashing with which command, cancelled, cleared. Symbols are shown on a Mac and words elsewhere, and the description uses the platform's own names for its keys."
|
|
837
|
+
});
|
|
838
|
+
//#endregion
|
|
670
839
|
//#region ../ui/dist/components/skeleton/meta.js
|
|
671
|
-
const meta$
|
|
840
|
+
const meta$28 = defineMeta({
|
|
672
841
|
name: "skeleton",
|
|
673
842
|
title: "Skeleton",
|
|
674
843
|
description: "A shaped placeholder that holds layout while content loads.",
|
|
@@ -681,7 +850,7 @@ const meta$17 = defineMeta({
|
|
|
681
850
|
});
|
|
682
851
|
//#endregion
|
|
683
852
|
//#region ../ui/dist/components/slider/meta.js
|
|
684
|
-
const meta$
|
|
853
|
+
const meta$27 = defineMeta({
|
|
685
854
|
name: "slider",
|
|
686
855
|
title: "Slider",
|
|
687
856
|
description: "Selects a value, or a range, from a continuous span.",
|
|
@@ -694,7 +863,7 @@ const meta$16 = defineMeta({
|
|
|
694
863
|
});
|
|
695
864
|
//#endregion
|
|
696
865
|
//#region ../ui/dist/components/spinner/meta.js
|
|
697
|
-
const meta$
|
|
866
|
+
const meta$26 = defineMeta({
|
|
698
867
|
name: "spinner",
|
|
699
868
|
title: "Spinner",
|
|
700
869
|
description: "An indeterminate loading indicator for buttons, panels and inline content.",
|
|
@@ -707,7 +876,7 @@ const meta$15 = defineMeta({
|
|
|
707
876
|
});
|
|
708
877
|
//#endregion
|
|
709
878
|
//#region ../ui/dist/components/switch/meta.js
|
|
710
|
-
const meta$
|
|
879
|
+
const meta$25 = defineMeta({
|
|
711
880
|
name: "switch",
|
|
712
881
|
title: "Switch",
|
|
713
882
|
description: "An immediate on/off toggle for settings that apply straight away.",
|
|
@@ -719,8 +888,21 @@ const meta$14 = defineMeta({
|
|
|
719
888
|
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."
|
|
720
889
|
});
|
|
721
890
|
//#endregion
|
|
891
|
+
//#region ../ui/dist/components/sync-status/meta.js
|
|
892
|
+
const meta$24 = defineMeta({
|
|
893
|
+
name: "sync-status",
|
|
894
|
+
title: "Sync Status",
|
|
895
|
+
description: "Offline, saving, saved or failed — with the count of changes being held.",
|
|
896
|
+
category: "feedback",
|
|
897
|
+
status: "stable",
|
|
898
|
+
dependencies: [],
|
|
899
|
+
registryDependencies: ["button"],
|
|
900
|
+
files: ["sync-status.tsx"],
|
|
901
|
+
a11y: "The word is the status and the coloured dot is decoration, hidden from assistive technology. The visible text is not a live region: every save flips it and a region on it would narrate the whole session. A separate region, present from the first render, announces transitions only — went offline with what will happen to the changes, came back with what is being saved, could not save, saved after a failure — and never the churn of saving itself. Announcing is on by default because going offline is the one thing a reader who is typing has to be told, and it can be turned off. The server render assumes online, since a page with no interface to report has no business saying offline."
|
|
902
|
+
});
|
|
903
|
+
//#endregion
|
|
722
904
|
//#region ../ui/dist/components/table/meta.js
|
|
723
|
-
const meta$
|
|
905
|
+
const meta$23 = defineMeta({
|
|
724
906
|
name: "table",
|
|
725
907
|
title: "Table",
|
|
726
908
|
description: "Semantic table primitives for tabular data.",
|
|
@@ -733,7 +915,7 @@ const meta$13 = defineMeta({
|
|
|
733
915
|
});
|
|
734
916
|
//#endregion
|
|
735
917
|
//#region ../ui/dist/components/tabs/meta.js
|
|
736
|
-
const meta$
|
|
918
|
+
const meta$22 = defineMeta({
|
|
737
919
|
name: "tabs",
|
|
738
920
|
title: "Tabs",
|
|
739
921
|
description: "Switches between panels of related content.",
|
|
@@ -746,7 +928,7 @@ const meta$12 = defineMeta({
|
|
|
746
928
|
});
|
|
747
929
|
//#endregion
|
|
748
930
|
//#region ../ui/dist/components/tags-input/meta.js
|
|
749
|
-
const meta$
|
|
931
|
+
const meta$21 = defineMeta({
|
|
750
932
|
name: "tags-input",
|
|
751
933
|
title: "Tags Input",
|
|
752
934
|
description: "A list of short values, where invalid entries stay visible instead of vanishing.",
|
|
@@ -759,7 +941,7 @@ const meta$11 = defineMeta({
|
|
|
759
941
|
});
|
|
760
942
|
//#endregion
|
|
761
943
|
//#region ../ui/dist/components/time-range-picker/meta.js
|
|
762
|
-
const meta$
|
|
944
|
+
const meta$20 = defineMeta({
|
|
763
945
|
name: "time-range-picker",
|
|
764
946
|
title: "Time Range Picker",
|
|
765
947
|
description: "A time range whose value is an expression, so it stays relative across a reload.",
|
|
@@ -776,8 +958,21 @@ const meta$10 = defineMeta({
|
|
|
776
958
|
a11y: "The trigger is named by the range it holds — \"Last 6 hours\" — and the window that resolves to is read after it, so the relative choice is not replaced by two timestamps. The popover carries role=\"dialog\" and is named. Presets are buttons rather than radios because choosing one both selects and dismisses, with aria-pressed carrying which matches the current expression. The expression field reports why an unparseable entry is invalid through one aria-describedby element that the preview and the error share, so a reader hears the error replace the preview rather than both at once; an invalid expression is never applied, because a chart silently re-scoping itself is worse than one that refuses."
|
|
777
959
|
});
|
|
778
960
|
//#endregion
|
|
961
|
+
//#region ../ui/dist/components/textarea/meta.js
|
|
962
|
+
const meta$19 = defineMeta({
|
|
963
|
+
name: "textarea",
|
|
964
|
+
title: "Textarea",
|
|
965
|
+
description: "A multi-line text field, with optional auto-resize and a character count that knows when to stay quiet.",
|
|
966
|
+
category: "form",
|
|
967
|
+
status: "stable",
|
|
968
|
+
dependencies: ["class-variance-authority"],
|
|
969
|
+
registryDependencies: [],
|
|
970
|
+
files: ["textarea.tsx"],
|
|
971
|
+
a11y: "Pair with a Label via htmlFor/id. The error state is driven by aria-invalid, so assistive technology and styling stay in sync. The character count is described by the field rather than announced on every keystroke — a permanently live counter reads the remaining number between every letter typed, which is unusable — so it goes live only once the limit is close, and states the remainder in words rather than as a bare ratio that is read aloud as two unlabelled numbers. Horizontal resizing is off by default, because a field dragged wider than its container is a broken layout."
|
|
972
|
+
});
|
|
973
|
+
//#endregion
|
|
779
974
|
//#region ../ui/dist/components/toast/meta.js
|
|
780
|
-
const meta$
|
|
975
|
+
const meta$18 = defineMeta({
|
|
781
976
|
name: "toast",
|
|
782
977
|
title: "Toast",
|
|
783
978
|
description: "Brief, non-blocking messages with an imperative API callable from anywhere.",
|
|
@@ -790,7 +985,7 @@ const meta$9 = defineMeta({
|
|
|
790
985
|
});
|
|
791
986
|
//#endregion
|
|
792
987
|
//#region ../ui/dist/components/tooltip/meta.js
|
|
793
|
-
const meta$
|
|
988
|
+
const meta$17 = defineMeta({
|
|
794
989
|
name: "tooltip",
|
|
795
990
|
title: "Tooltip",
|
|
796
991
|
description: "A short label revealed on hover or keyboard focus.",
|
|
@@ -813,6 +1008,31 @@ const meta$8 = defineMeta({
|
|
|
813
1008
|
* `meta.test.ts` fails if a block directory exists that is missing from here.
|
|
814
1009
|
*/
|
|
815
1010
|
const blockMetas = [
|
|
1011
|
+
defineMeta({
|
|
1012
|
+
name: "admin-dashboard",
|
|
1013
|
+
kind: "block",
|
|
1014
|
+
title: "Admin dashboard",
|
|
1015
|
+
description: "An administration console: the shell every admin page shares — navigation, breadcrumb, account menu — and the overview that is its front page, with what needs attention first.",
|
|
1016
|
+
category: "layout",
|
|
1017
|
+
status: "stable",
|
|
1018
|
+
access: "pro",
|
|
1019
|
+
dependencies: [],
|
|
1020
|
+
registryDependencies: [
|
|
1021
|
+
"alert",
|
|
1022
|
+
"avatar",
|
|
1023
|
+
"badge",
|
|
1024
|
+
"breadcrumb",
|
|
1025
|
+
"button",
|
|
1026
|
+
"card",
|
|
1027
|
+
"dropdown-menu",
|
|
1028
|
+
"empty-state",
|
|
1029
|
+
"metric-delta",
|
|
1030
|
+
"sidebar",
|
|
1031
|
+
"table"
|
|
1032
|
+
],
|
|
1033
|
+
files: ["admin-dashboard.tsx"],
|
|
1034
|
+
a11y: "What needs attention comes first and is the only loud part of the page; it is not a live region, because the list is there on load and re-announcing it on every refresh would make the console unusable. The navigation is a landmark called Admin, the breadcrumb another, so neither is one more thing called 'navigation'. The current page carries aria-current, a count beside a nav item says what it counts, the account menu is named after its owner, and each Open button is named after its account. Every status is a word, with colour agreeing rather than replacing."
|
|
1035
|
+
}),
|
|
816
1036
|
defineMeta({
|
|
817
1037
|
name: "admin-users",
|
|
818
1038
|
kind: "block",
|
|
@@ -834,6 +1054,27 @@ const blockMetas = [
|
|
|
834
1054
|
files: ["admin-users.tsx"],
|
|
835
1055
|
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."
|
|
836
1056
|
}),
|
|
1057
|
+
defineMeta({
|
|
1058
|
+
name: "agent-console",
|
|
1059
|
+
kind: "block",
|
|
1060
|
+
title: "Agent console",
|
|
1061
|
+
description: "One agent run, watched: the plan it is working from, the approval it is blocked on, and the ledger of what it has already done.",
|
|
1062
|
+
category: "ai",
|
|
1063
|
+
status: "stable",
|
|
1064
|
+
dependencies: [],
|
|
1065
|
+
registryDependencies: [
|
|
1066
|
+
"ai-action-ledger",
|
|
1067
|
+
"ai-agent-plan",
|
|
1068
|
+
"ai-agent-status",
|
|
1069
|
+
"ai-approval-request",
|
|
1070
|
+
"ai-token-usage",
|
|
1071
|
+
"button",
|
|
1072
|
+
"card",
|
|
1073
|
+
"empty-state"
|
|
1074
|
+
],
|
|
1075
|
+
files: ["agent-console.tsx"],
|
|
1076
|
+
a11y: "Whatever the run is blocked on is rendered first rather than below a scrolling plan, because it is the only part of the page waiting on a person. This is the one agent on the page, so its status announces its own transitions — a list of runs each doing that would be noise, which is why the underlying component makes it opt in. Every completed action states whether it can be undone, offset or not taken back at all, in words, since presenting all three behind one Undo is a lie discovered after the click."
|
|
1077
|
+
}),
|
|
837
1078
|
defineMeta({
|
|
838
1079
|
name: "ai-chat",
|
|
839
1080
|
kind: "block",
|
|
@@ -858,6 +1099,137 @@ const blockMetas = [
|
|
|
858
1099
|
files: ["ai-chat.tsx"],
|
|
859
1100
|
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\"."
|
|
860
1101
|
}),
|
|
1102
|
+
defineMeta({
|
|
1103
|
+
name: "ai-dashboard",
|
|
1104
|
+
kind: "block",
|
|
1105
|
+
title: "AI dashboard",
|
|
1106
|
+
description: "What the AI features cost and whether they worked: tokens, spend, failure rate, a breakdown by model, and the runs still going.",
|
|
1107
|
+
category: "ai",
|
|
1108
|
+
status: "stable",
|
|
1109
|
+
dependencies: [],
|
|
1110
|
+
registryDependencies: [
|
|
1111
|
+
"ai-agent-status",
|
|
1112
|
+
"ai-token-usage",
|
|
1113
|
+
"card",
|
|
1114
|
+
"empty-state",
|
|
1115
|
+
"metric-delta",
|
|
1116
|
+
"table"
|
|
1117
|
+
],
|
|
1118
|
+
files: ["ai-dashboard.tsx"],
|
|
1119
|
+
a11y: "Spend and failure rate are declared lower-is-better, so a rising bill is not painted green — which is the mistake most usage dashboards make. The totals row is a real table footer rather than a last body row that looks like one, because inside the body it is announced as another model and there is no model called Total. Statuses in the run list do not announce their own changes: several runs each doing that turns a list into a stream of interruptions, and watching one run is the agent console's job."
|
|
1120
|
+
}),
|
|
1121
|
+
defineMeta({
|
|
1122
|
+
name: "ai-workspace",
|
|
1123
|
+
kind: "block",
|
|
1124
|
+
title: "AI workspace",
|
|
1125
|
+
description: "A whole AI application surface: conversations down one side, the active transcript with reasoning, tool calls and sources in the middle, and the context — window usage, attachments and a structured result — on the other.",
|
|
1126
|
+
category: "ai",
|
|
1127
|
+
status: "stable",
|
|
1128
|
+
access: "pro",
|
|
1129
|
+
dependencies: [],
|
|
1130
|
+
registryDependencies: [
|
|
1131
|
+
"ai-conversation",
|
|
1132
|
+
"ai-message",
|
|
1133
|
+
"ai-model-selector",
|
|
1134
|
+
"ai-prompt-input",
|
|
1135
|
+
"ai-reasoning",
|
|
1136
|
+
"ai-response",
|
|
1137
|
+
"ai-sources",
|
|
1138
|
+
"ai-structured-output",
|
|
1139
|
+
"ai-token-usage",
|
|
1140
|
+
"ai-tool",
|
|
1141
|
+
"button",
|
|
1142
|
+
"empty-state",
|
|
1143
|
+
"sidebar"
|
|
1144
|
+
],
|
|
1145
|
+
files: ["ai-workspace.tsx"],
|
|
1146
|
+
a11y: "Three landmarks, each named: the conversation list is a navigation called Conversations, the transcript is the main content, and the context is a complementary region called Context, so a screen reader user can jump between them and skip the one they do not want. The transcript is a list and never a live region; the response state is announced from a separate status line, so a streaming answer does not read itself aloud token by token. Each attachment's remove button is named after its file. On a narrow screen the conversation list becomes a sheet with a focus trap and an Escape key, not a div slid over content that stays reachable by Tab."
|
|
1147
|
+
}),
|
|
1148
|
+
defineMeta({
|
|
1149
|
+
name: "analytics",
|
|
1150
|
+
kind: "block",
|
|
1151
|
+
title: "Analytics",
|
|
1152
|
+
description: "An analytics page: headline metrics against the previous period, a series over time, and the breakdown that made it up.",
|
|
1153
|
+
category: "data",
|
|
1154
|
+
status: "stable",
|
|
1155
|
+
dependencies: [],
|
|
1156
|
+
registryDependencies: [
|
|
1157
|
+
"button",
|
|
1158
|
+
"card",
|
|
1159
|
+
"metric-delta",
|
|
1160
|
+
"select",
|
|
1161
|
+
"table"
|
|
1162
|
+
],
|
|
1163
|
+
files: ["analytics.tsx"],
|
|
1164
|
+
a11y: "The bars are declared as a single image with a one-sentence summary — where the series started, where it ended, and where its extremes were — rather than as forty separately labelled elements, which reads as noise instead of a shape. The exact numbers live in a real table that is collapsed for everyone and revealed for everyone from a control on the page, rather than in a visually-hidden copy only screen readers can reach, because the hidden copy is the one that goes stale. The range selector is a select rather than a tab set: tabs promise panels, and a range selector has none — it changes the data behind the whole page, so styled-as-tabs it points every tab at a panel that does not exist."
|
|
1165
|
+
}),
|
|
1166
|
+
defineMeta({
|
|
1167
|
+
name: "billing",
|
|
1168
|
+
kind: "block",
|
|
1169
|
+
title: "Billing",
|
|
1170
|
+
description: "A billing page: the current plan, metered usage against its limits, the payment method and the invoice history.",
|
|
1171
|
+
category: "data",
|
|
1172
|
+
status: "stable",
|
|
1173
|
+
dependencies: [],
|
|
1174
|
+
registryDependencies: [
|
|
1175
|
+
"badge",
|
|
1176
|
+
"button",
|
|
1177
|
+
"card",
|
|
1178
|
+
"empty-state",
|
|
1179
|
+
"progress",
|
|
1180
|
+
"table"
|
|
1181
|
+
],
|
|
1182
|
+
files: ["billing.tsx"],
|
|
1183
|
+
a11y: "Every usage meter states where it stands in words — \"8 of 10 seats used, 2 left\", or how far over the limit it is — because a bar that turns red says nothing to a screen reader and nothing to anyone who cannot tell the colours apart; the bar itself is hidden from the accessibility tree so the same fact is not announced twice. Each invoice download is named after its invoice rather than being one of ten identical \"Download\" links, which is all a links list would show. A card's last four digits are spoken as digits instead of as a four-figure number. Dates carry a machine-readable time element."
|
|
1184
|
+
}),
|
|
1185
|
+
defineMeta({
|
|
1186
|
+
name: "command-center",
|
|
1187
|
+
kind: "block",
|
|
1188
|
+
title: "Command center",
|
|
1189
|
+
description: "Operations at a glance: service health worst-first, open incidents by severity, capacity meters, a filterable log stream, and a command palette for every action an operator reaches for.",
|
|
1190
|
+
category: "data",
|
|
1191
|
+
status: "stable",
|
|
1192
|
+
access: "pro",
|
|
1193
|
+
dependencies: [],
|
|
1194
|
+
registryDependencies: [
|
|
1195
|
+
"alert",
|
|
1196
|
+
"badge",
|
|
1197
|
+
"button",
|
|
1198
|
+
"card",
|
|
1199
|
+
"command",
|
|
1200
|
+
"empty-state",
|
|
1201
|
+
"log-viewer",
|
|
1202
|
+
"meter"
|
|
1203
|
+
],
|
|
1204
|
+
files: ["command-center.tsx"],
|
|
1205
|
+
a11y: "The overall status is one sentence computed from the worst service, and it comes first — 'one service is down' rather than a wall of tiles to scan. It is not a live region: the page is refreshed by the application, and a status that re-announces on every poll is one nobody can work beside. Health and severity are words on every row, sorted on, with colour agreeing rather than replacing. ⌘K opens the palette but the Actions button is always visible, so the shortcut is an accelerator and not the only way in. New log lines are not read aloud unless asked."
|
|
1206
|
+
}),
|
|
1207
|
+
defineMeta({
|
|
1208
|
+
name: "crm",
|
|
1209
|
+
kind: "block",
|
|
1210
|
+
title: "CRM",
|
|
1211
|
+
description: "A sales pipeline: open value by stage, the deals in it with filtering and sorting, the win rate and cycle length, and the last few touches.",
|
|
1212
|
+
category: "data",
|
|
1213
|
+
status: "stable",
|
|
1214
|
+
access: "pro",
|
|
1215
|
+
dependencies: ["@tanstack/react-table"],
|
|
1216
|
+
registryDependencies: [
|
|
1217
|
+
"activity-feed",
|
|
1218
|
+
"avatar",
|
|
1219
|
+
"badge",
|
|
1220
|
+
"button",
|
|
1221
|
+
"card",
|
|
1222
|
+
"data-table",
|
|
1223
|
+
"empty-state",
|
|
1224
|
+
"input",
|
|
1225
|
+
"label",
|
|
1226
|
+
"meter",
|
|
1227
|
+
"metric-delta",
|
|
1228
|
+
"select"
|
|
1229
|
+
],
|
|
1230
|
+
files: ["crm.tsx"],
|
|
1231
|
+
a11y: "The pipeline is one bar split by stage, with the same figures listed beside it as numbers, so nobody reads a proportion off a coloured segment; the meter announces the total and its legend names every stage. Sales cycle is declared lower-is-better, so a slowing pipeline is not painted green. The deal filter has a real label and announces the matching count politely, and each Open button is named after its deal rather than being one of ten identical buttons."
|
|
1232
|
+
}),
|
|
861
1233
|
defineMeta({
|
|
862
1234
|
name: "dashboard",
|
|
863
1235
|
kind: "block",
|
|
@@ -913,6 +1285,23 @@ const blockMetas = [
|
|
|
913
1285
|
files: ["login.tsx"],
|
|
914
1286
|
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."
|
|
915
1287
|
}),
|
|
1288
|
+
defineMeta({
|
|
1289
|
+
name: "onboarding",
|
|
1290
|
+
kind: "block",
|
|
1291
|
+
title: "Onboarding",
|
|
1292
|
+
description: "A setup checklist: what is done, which step is current, and what is blocked and why.",
|
|
1293
|
+
category: "feedback",
|
|
1294
|
+
status: "stable",
|
|
1295
|
+
dependencies: [],
|
|
1296
|
+
registryDependencies: [
|
|
1297
|
+
"badge",
|
|
1298
|
+
"button",
|
|
1299
|
+
"card",
|
|
1300
|
+
"progress"
|
|
1301
|
+
],
|
|
1302
|
+
files: ["onboarding.tsx"],
|
|
1303
|
+
a11y: "Every step states its state in a word — Done, In progress, Not started, Blocked — because a green tick announces nothing and means nothing to a reader who cannot tell the colours apart; the tick and the step number are decoration on top of that. Progress is given as a count rather than only as a bar, and the bar is hidden so the same fact is not announced twice. The current step carries aria-current, so it can be found rather than merely seen. Blocked is a distinct state from not-started and says why. Each step's action is named after its step, so six buttons are not six identical \"Start\" entries in a controls list."
|
|
1304
|
+
}),
|
|
916
1305
|
defineMeta({
|
|
917
1306
|
name: "pricing",
|
|
918
1307
|
kind: "block",
|
|
@@ -988,6 +1377,30 @@ const blockMetas = [
|
|
|
988
1377
|
* words — `switch` cannot be a binding name.
|
|
989
1378
|
*/
|
|
990
1379
|
const componentMetas = [
|
|
1380
|
+
meta$91,
|
|
1381
|
+
meta$90,
|
|
1382
|
+
meta$89,
|
|
1383
|
+
meta$88,
|
|
1384
|
+
meta$87,
|
|
1385
|
+
meta$86,
|
|
1386
|
+
meta$85,
|
|
1387
|
+
meta$84,
|
|
1388
|
+
meta$83,
|
|
1389
|
+
meta$82,
|
|
1390
|
+
meta$81,
|
|
1391
|
+
meta$80,
|
|
1392
|
+
meta$79,
|
|
1393
|
+
meta$78,
|
|
1394
|
+
meta$77,
|
|
1395
|
+
meta$76,
|
|
1396
|
+
meta$75,
|
|
1397
|
+
meta$74,
|
|
1398
|
+
meta$73,
|
|
1399
|
+
meta$72,
|
|
1400
|
+
meta$71,
|
|
1401
|
+
meta$70,
|
|
1402
|
+
meta$69,
|
|
1403
|
+
meta$68,
|
|
991
1404
|
meta$67,
|
|
992
1405
|
meta$66,
|
|
993
1406
|
meta$65,
|
|
@@ -1000,8 +1413,8 @@ const componentMetas = [
|
|
|
1000
1413
|
meta$58,
|
|
1001
1414
|
meta$57,
|
|
1002
1415
|
meta$56,
|
|
1003
|
-
meta$55,
|
|
1004
1416
|
meta$54,
|
|
1417
|
+
meta$55,
|
|
1005
1418
|
meta$53,
|
|
1006
1419
|
meta$52,
|
|
1007
1420
|
meta$51,
|
|
@@ -1024,8 +1437,8 @@ const componentMetas = [
|
|
|
1024
1437
|
meta$34,
|
|
1025
1438
|
meta$33,
|
|
1026
1439
|
meta$32,
|
|
1027
|
-
meta$31,
|
|
1028
1440
|
meta$30,
|
|
1441
|
+
meta$31,
|
|
1029
1442
|
meta$29,
|
|
1030
1443
|
meta$28,
|
|
1031
1444
|
meta$27,
|
|
@@ -1038,16 +1451,7 @@ const componentMetas = [
|
|
|
1038
1451
|
meta$20,
|
|
1039
1452
|
meta$19,
|
|
1040
1453
|
meta$18,
|
|
1041
|
-
meta$17
|
|
1042
|
-
meta$16,
|
|
1043
|
-
meta$15,
|
|
1044
|
-
meta$14,
|
|
1045
|
-
meta$13,
|
|
1046
|
-
meta$12,
|
|
1047
|
-
meta$11,
|
|
1048
|
-
meta$10,
|
|
1049
|
-
meta$9,
|
|
1050
|
-
meta$8
|
|
1454
|
+
meta$17
|
|
1051
1455
|
];
|
|
1052
1456
|
//#endregion
|
|
1053
1457
|
//#region src/build.ts
|
|
@@ -1097,7 +1501,8 @@ function buildSourceItem(meta) {
|
|
|
1097
1501
|
dependencies: meta.dependencies,
|
|
1098
1502
|
registryDependencies: meta.registryDependencies,
|
|
1099
1503
|
files,
|
|
1100
|
-
a11y: meta.a11y
|
|
1504
|
+
a11y: meta.a11y,
|
|
1505
|
+
access: meta.access ?? "free"
|
|
1101
1506
|
});
|
|
1102
1507
|
}
|
|
1103
1508
|
/**
|
|
@@ -1167,6 +1572,14 @@ function buildRegistry() {
|
|
|
1167
1572
|
...blockMetas.map(buildSourceItem)
|
|
1168
1573
|
];
|
|
1169
1574
|
}
|
|
1575
|
+
/** Items whose source anyone may fetch. */
|
|
1576
|
+
function freeItems(items) {
|
|
1577
|
+
return items.filter((item) => item.access !== "pro");
|
|
1578
|
+
}
|
|
1579
|
+
/** Items whose source requires a licence. */
|
|
1580
|
+
function proItems(items) {
|
|
1581
|
+
return items.filter((item) => item.access === "pro");
|
|
1582
|
+
}
|
|
1170
1583
|
function buildIndex(items) {
|
|
1171
1584
|
const entries = items.map((item) => ({
|
|
1172
1585
|
name: item.name,
|
|
@@ -1177,6 +1590,7 @@ function buildIndex(items) {
|
|
|
1177
1590
|
status: item.status,
|
|
1178
1591
|
dependencies: item.dependencies,
|
|
1179
1592
|
registryDependencies: item.registryDependencies,
|
|
1593
|
+
access: item.access,
|
|
1180
1594
|
fileCount: item.files.length
|
|
1181
1595
|
}));
|
|
1182
1596
|
return registryIndexSchema.parse({
|
|
@@ -1186,28 +1600,64 @@ function buildIndex(items) {
|
|
|
1186
1600
|
items: entries
|
|
1187
1601
|
});
|
|
1188
1602
|
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Writes the public registry.
|
|
1605
|
+
*
|
|
1606
|
+
* The index lists everything, including licensed items — that is the catalogue,
|
|
1607
|
+
* and an item nobody can see is an item nobody buys. What it does *not* write is
|
|
1608
|
+
* a licensed item's body: those files never touch the directory a CDN serves,
|
|
1609
|
+
* because a paywall that can be stepped around by fetching the JSON directly is
|
|
1610
|
+
* not a paywall. Their bodies go to `writeLicensedModule` instead, behind a
|
|
1611
|
+
* request the server can refuse.
|
|
1612
|
+
*/
|
|
1189
1613
|
function writeRegistry(outDir) {
|
|
1190
1614
|
const items = buildRegistry();
|
|
1191
1615
|
const index = buildIndex(items);
|
|
1616
|
+
const free = freeItems(items);
|
|
1192
1617
|
rmSync(outDir, {
|
|
1193
1618
|
recursive: true,
|
|
1194
1619
|
force: true
|
|
1195
1620
|
});
|
|
1196
1621
|
mkdirSync(outDir, { recursive: true });
|
|
1197
1622
|
writeFileSync(join(outDir, "index.json"), `${JSON.stringify(index, null, 2)}\n`);
|
|
1198
|
-
for (const item of
|
|
1623
|
+
for (const item of free) writeFileSync(join(outDir, `${item.name}.json`), `${JSON.stringify(item, null, 2)}\n`);
|
|
1199
1624
|
return {
|
|
1200
1625
|
items: items.length,
|
|
1201
|
-
files:
|
|
1626
|
+
files: free.reduce((total, item) => total + item.files.length, 0),
|
|
1627
|
+
licensed: items.length - free.length
|
|
1202
1628
|
};
|
|
1203
1629
|
}
|
|
1630
|
+
/**
|
|
1631
|
+
* Writes the licensed item bodies as a TypeScript module.
|
|
1632
|
+
*
|
|
1633
|
+
* A module rather than a directory of JSON, because the server that serves
|
|
1634
|
+
* these runs on a platform that traces imports to decide what to deploy. A file
|
|
1635
|
+
* read at runtime from a path the bundler never saw is a file that is not there
|
|
1636
|
+
* in production — and the failure appears only once someone with a valid
|
|
1637
|
+
* licence tries to install something.
|
|
1638
|
+
*/
|
|
1639
|
+
function writeLicensedModule(outFile) {
|
|
1640
|
+
const licensed = proItems(buildRegistry());
|
|
1641
|
+
const byName = Object.fromEntries(licensed.map((item) => [item.name, item]));
|
|
1642
|
+
mkdirSync(dirname(outFile), { recursive: true });
|
|
1643
|
+
writeFileSync(outFile, `// Generated by @dowel-ui/registry. Do not edit.
|
|
1644
|
+
//
|
|
1645
|
+
// The bodies of licensed registry items. Imported by the route that serves them
|
|
1646
|
+
// so the platform's dependency tracing includes them in the deployment; they are
|
|
1647
|
+
// deliberately absent from the public registry directory.
|
|
1648
|
+
import type { RegistryItem } from "@dowel-ui/registry";
|
|
1649
|
+
|
|
1650
|
+
export const licensedItems: Record<string, RegistryItem> = ${JSON.stringify(byName, null, 2)};
|
|
1651
|
+
`);
|
|
1652
|
+
return licensed.length;
|
|
1653
|
+
}
|
|
1204
1654
|
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
1205
1655
|
const outIndex = process.argv.indexOf("--out");
|
|
1206
1656
|
const outDir = outIndex === -1 ? join(here, "..", "r") : process.argv[outIndex + 1] ?? join(here, "..", "r");
|
|
1207
1657
|
const result = writeRegistry(outDir);
|
|
1208
|
-
console.log(`Registry written to ${outDir}: ${String(result.items)} items, ${String(result.files)} files.`);
|
|
1658
|
+
console.log(`Registry written to ${outDir}: ${String(result.items)} items, ${String(result.files)} files` + (result.licensed > 0 ? `, ${String(result.licensed)} licensed item(s) withheld.` : "."));
|
|
1209
1659
|
}
|
|
1210
1660
|
//#endregion
|
|
1211
|
-
export { buildIndex, buildRegistry, writeRegistry };
|
|
1661
|
+
export { buildIndex, buildRegistry, freeItems, proItems, writeLicensedModule, writeRegistry };
|
|
1212
1662
|
|
|
1213
1663
|
//# sourceMappingURL=build.js.map
|