@bestagentkits/render 0.1.1-next.1 → 0.2.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.
Files changed (113) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/README.md +189 -34
  3. package/assets/fonts/bricolage-grotesque/OFL.txt +93 -0
  4. package/assets/fonts/fraunces/OFL.txt +93 -0
  5. package/assets/fonts/geist/OFL.txt +93 -0
  6. package/assets/fonts/inter-tight/OFL.txt +93 -0
  7. package/assets/fonts/jetbrains-mono/OFL.txt +93 -0
  8. package/assets/fonts/plus-jakarta-sans/OFL.txt +93 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +51 -10
  12. package/dist/cli.js.map +1 -1
  13. package/dist/mcp-server.d.ts +37 -0
  14. package/dist/mcp-server.d.ts.map +1 -0
  15. package/dist/mcp-server.js +274 -0
  16. package/dist/mcp-server.js.map +1 -0
  17. package/dist/registry/roster.d.ts +1 -1
  18. package/dist/registry/roster.d.ts.map +1 -1
  19. package/dist/registry/roster.js +222 -6
  20. package/dist/registry/roster.js.map +1 -1
  21. package/dist/render/block-helpers.d.ts +52 -0
  22. package/dist/render/block-helpers.d.ts.map +1 -0
  23. package/dist/render/block-helpers.js +113 -0
  24. package/dist/render/block-helpers.js.map +1 -0
  25. package/dist/render/blocks.d.ts +3 -4
  26. package/dist/render/blocks.d.ts.map +1 -1
  27. package/dist/render/blocks.js +126 -121
  28. package/dist/render/blocks.js.map +1 -1
  29. package/dist/render/charts.d.ts +5 -0
  30. package/dist/render/charts.d.ts.map +1 -1
  31. package/dist/render/charts.js +205 -90
  32. package/dist/render/charts.js.map +1 -1
  33. package/dist/render/derived-variables.d.ts +17 -0
  34. package/dist/render/derived-variables.d.ts.map +1 -0
  35. package/dist/render/derived-variables.js +17 -0
  36. package/dist/render/derived-variables.js.map +1 -0
  37. package/dist/render/diagram-fallback.d.ts +25 -0
  38. package/dist/render/diagram-fallback.d.ts.map +1 -0
  39. package/dist/render/diagram-fallback.js +86 -0
  40. package/dist/render/diagram-fallback.js.map +1 -0
  41. package/dist/render/document.d.ts +4 -0
  42. package/dist/render/document.d.ts.map +1 -1
  43. package/dist/render/document.js +34 -6
  44. package/dist/render/document.js.map +1 -1
  45. package/dist/render/effects-styles.d.ts +14 -0
  46. package/dist/render/effects-styles.d.ts.map +1 -0
  47. package/dist/render/effects-styles.js +39 -0
  48. package/dist/render/effects-styles.js.map +1 -0
  49. package/dist/render/embedded-fonts.generated.d.ts +22 -0
  50. package/dist/render/embedded-fonts.generated.d.ts.map +1 -0
  51. package/dist/render/embedded-fonts.generated.js +59 -0
  52. package/dist/render/embedded-fonts.generated.js.map +1 -0
  53. package/dist/render/feature-styles.d.ts +14 -0
  54. package/dist/render/feature-styles.d.ts.map +1 -0
  55. package/dist/render/feature-styles.js +161 -0
  56. package/dist/render/feature-styles.js.map +1 -0
  57. package/dist/render/font-faces.d.ts +22 -0
  58. package/dist/render/font-faces.d.ts.map +1 -0
  59. package/dist/render/font-faces.js +60 -0
  60. package/dist/render/font-faces.js.map +1 -0
  61. package/dist/render/outline.d.ts +21 -0
  62. package/dist/render/outline.d.ts.map +1 -0
  63. package/dist/render/outline.js +44 -0
  64. package/dist/render/outline.js.map +1 -0
  65. package/dist/render/render.d.ts.map +1 -1
  66. package/dist/render/render.js +53 -10
  67. package/dist/render/render.js.map +1 -1
  68. package/dist/render/runtime.d.ts.map +1 -1
  69. package/dist/render/runtime.js +184 -10
  70. package/dist/render/runtime.js.map +1 -1
  71. package/dist/render/showcase-blocks.d.ts +47 -0
  72. package/dist/render/showcase-blocks.d.ts.map +1 -0
  73. package/dist/render/showcase-blocks.js +349 -0
  74. package/dist/render/showcase-blocks.js.map +1 -0
  75. package/dist/render/showcase-styles.d.ts +15 -0
  76. package/dist/render/showcase-styles.d.ts.map +1 -0
  77. package/dist/render/showcase-styles.js +217 -0
  78. package/dist/render/showcase-styles.js.map +1 -0
  79. package/dist/render/signature-styles.d.ts +18 -0
  80. package/dist/render/signature-styles.d.ts.map +1 -0
  81. package/dist/render/signature-styles.js +41 -0
  82. package/dist/render/signature-styles.js.map +1 -0
  83. package/dist/render/styles.d.ts +18 -9
  84. package/dist/render/styles.d.ts.map +1 -1
  85. package/dist/render/styles.js +224 -128
  86. package/dist/render/styles.js.map +1 -1
  87. package/dist/render/surface-styles.d.ts +24 -0
  88. package/dist/render/surface-styles.d.ts.map +1 -0
  89. package/dist/render/surface-styles.js +41 -0
  90. package/dist/render/surface-styles.js.map +1 -0
  91. package/dist/render/verify.d.ts.map +1 -1
  92. package/dist/render/verify.js +30 -0
  93. package/dist/render/verify.js.map +1 -1
  94. package/dist/spec/normalize.d.ts.map +1 -1
  95. package/dist/spec/normalize.js +32 -0
  96. package/dist/spec/normalize.js.map +1 -1
  97. package/dist/theme/load-theme.d.ts +2 -2
  98. package/dist/theme/load-theme.d.ts.map +1 -1
  99. package/dist/theme/load-theme.js +46 -10
  100. package/dist/theme/load-theme.js.map +1 -1
  101. package/dist/theme/presets.d.ts +4 -3
  102. package/dist/theme/presets.d.ts.map +1 -1
  103. package/dist/theme/presets.js +35 -18
  104. package/dist/theme/presets.js.map +1 -1
  105. package/dist/theme/tokens.d.ts.map +1 -1
  106. package/dist/theme/tokens.js +4 -4
  107. package/dist/theme/tokens.js.map +1 -1
  108. package/dist/version.d.ts +1 -1
  109. package/dist/version.d.ts.map +1 -1
  110. package/dist/version.js +1 -1
  111. package/dist/version.js.map +1 -1
  112. package/llms.txt +25 -0
  113. package/package.json +9 -3
@@ -0,0 +1,274 @@
1
+ /**
2
+ * `ak-render mcp`: the compiler as a Model Context Protocol server over stdio.
3
+ *
4
+ * The tools mirror the CLI so an agent follows the same loop either way:
5
+ * `catalog` → `describe` → `validate` → `render`. `render` writes the HTML to a
6
+ * file and returns only a summary, because the point of the compiler is to keep
7
+ * presentation bytes out of the model's context.
8
+ *
9
+ * The transport is newline-delimited JSON-RPC 2.0 on stdin/stdout, implemented
10
+ * here without an SDK so the package keeps its single runtime dependency.
11
+ * Nothing in this module touches the network.
12
+ */
13
+ import { mkdirSync, writeFileSync } from 'node:fs';
14
+ import { homedir } from 'node:os';
15
+ import { dirname, resolve } from 'node:path';
16
+ import { createInterface } from 'node:readline';
17
+ import { isRenderError } from './errors.js';
18
+ import { catalog, describe } from './registry/registry.js';
19
+ import { compile } from './render/render.js';
20
+ import { validate } from './spec/validate.js';
21
+ import { buildThemeCatalog } from './theme/theme-catalog.js';
22
+ import { PACKAGE_NAME, VERSION } from './version.js';
23
+ /** Protocol revisions this server answers with; the newest is the default. */
24
+ const PROTOCOL_VERSIONS = ['2024-11-05', '2025-03-26', '2025-06-18', '2025-11-25'];
25
+ const LATEST_PROTOCOL = PROTOCOL_VERSIONS[PROTOCOL_VERSIONS.length - 1];
26
+ const INSTRUCTIONS = `AK Render compiles a Page Spec (YAML or JSON) into one self-contained, offline HTML file.
27
+ Loop: call catalog once, describe only the block types you plan to use, validate the spec and fix every diagnostic by its JSON path, then render to a file.
28
+ Describe meaning, not presentation: the compiler owns layout, colour, typography and motion.`;
29
+ const SPEC_INPUT = {
30
+ description: 'The Page Spec: YAML or JSON text, or the parsed object.',
31
+ anyOf: [{ type: 'string' }, { type: 'object' }],
32
+ };
33
+ const text = (value) => ({
34
+ content: [
35
+ { type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) },
36
+ ],
37
+ });
38
+ const failure = (value) => ({ ...text(value), isError: true });
39
+ const HTML_FILE = /\.html?$/iu;
40
+ function themeCatalogFor(context) {
41
+ return buildThemeCatalog({ cwd: context.cwd, home: context.home, discovery: true });
42
+ }
43
+ function requireString(args, key) {
44
+ const value = args[key];
45
+ if (typeof value !== 'string' || value === '') {
46
+ throw new TypeError(`"${key}" must be a non-empty string`);
47
+ }
48
+ return value;
49
+ }
50
+ const TOOLS = [
51
+ {
52
+ name: 'catalog',
53
+ description: 'List every block type and action with a one-line summary. Call once per task, then describe only the types you use.',
54
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
55
+ run: () => text(catalog()),
56
+ },
57
+ {
58
+ name: 'describe',
59
+ description: 'Full contract for one block type: props with defaults and bounds, slots, actions, runtime features, network needs and accessibility.',
60
+ inputSchema: {
61
+ type: 'object',
62
+ properties: {
63
+ type: { type: 'string', description: 'Block type from catalog, e.g. "hero".' },
64
+ },
65
+ required: ['type'],
66
+ additionalProperties: false,
67
+ },
68
+ run: (args) => text(describe(requireString(args, 'type'))),
69
+ },
70
+ {
71
+ name: 'validate',
72
+ description: 'Check a Page Spec without rendering. Returns ok plus diagnostics, each with a code and the JSON path to fix.',
73
+ inputSchema: {
74
+ type: 'object',
75
+ properties: { spec: SPEC_INPUT },
76
+ required: ['spec'],
77
+ additionalProperties: false,
78
+ },
79
+ run: (args) => {
80
+ const result = validate(args.spec, { source: '<spec>' });
81
+ return result.ok ? text(result) : failure(result);
82
+ },
83
+ },
84
+ {
85
+ name: 'render',
86
+ description: 'Compile a Page Spec and write the standalone HTML to `out`. Returns a summary (bytes, hash, features, warnings), never the HTML itself.',
87
+ inputSchema: {
88
+ type: 'object',
89
+ properties: {
90
+ spec: SPEC_INPUT,
91
+ out: {
92
+ type: 'string',
93
+ description: 'HTML file to write (.html or .htm). A relative path resolves against the server working directory; an absolute path is used as given.',
94
+ },
95
+ theme: { type: 'string', description: 'Optional preset name overriding the spec theme.' },
96
+ },
97
+ required: ['spec', 'out'],
98
+ additionalProperties: false,
99
+ },
100
+ run: (args, context) => {
101
+ const out = resolve(context.cwd, requireString(args, 'out'));
102
+ // The tool only ever writes pages; refusing other extensions keeps a
103
+ // misdirected call from replacing a config or source file with HTML.
104
+ if (!HTML_FILE.test(out))
105
+ throw new TypeError('"out" must end in .html or .htm');
106
+ const theme = args.theme;
107
+ const result = compile(args.spec, {
108
+ source: '<spec>',
109
+ themeCatalog: themeCatalogFor(context),
110
+ ...(typeof theme === 'string' && theme !== '' ? { theme } : {}),
111
+ });
112
+ mkdirSync(dirname(out), { recursive: true });
113
+ writeFileSync(out, result.html, 'utf8');
114
+ return text({
115
+ out,
116
+ bytes: result.bytes,
117
+ hash: result.hash,
118
+ title: result.ir.meta.title,
119
+ theme: result.theme.name,
120
+ features: result.features,
121
+ nodes: result.ir.nodes.length,
122
+ warnings: result.warnings,
123
+ });
124
+ },
125
+ },
126
+ {
127
+ name: 'themes',
128
+ description: 'List theme presets (built-ins plus project or user presets discovered on disk) and any preset file that failed to load.',
129
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
130
+ run: (_args, context) => {
131
+ const themes = themeCatalogFor(context);
132
+ const presets = themes.sources
133
+ .map(({ name, origin }) => ({ name, origin }))
134
+ .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
135
+ // A preset file that failed to load is reported, not silently dropped.
136
+ return text({ presets, problems: themes.problems });
137
+ },
138
+ },
139
+ ];
140
+ function callTool(tool, params, context) {
141
+ const args = (params.arguments ?? {});
142
+ try {
143
+ return tool.run(args, context);
144
+ }
145
+ catch (error) {
146
+ if (isRenderError(error)) {
147
+ return failure({
148
+ code: error.code,
149
+ message: error.message,
150
+ path: error.path ?? '$',
151
+ ...(error.details?.diagnostics === undefined
152
+ ? {}
153
+ : { diagnostics: error.details.diagnostics }),
154
+ });
155
+ }
156
+ return failure(error instanceof Error ? error.message : String(error));
157
+ }
158
+ }
159
+ function isRequest(message) {
160
+ return (typeof message === 'object' &&
161
+ message !== null &&
162
+ message.jsonrpc === '2.0' &&
163
+ typeof message.method === 'string');
164
+ }
165
+ /**
166
+ * Answer one JSON-RPC message. Returns `undefined` for notifications and for
167
+ * responses sent to us, which need no reply.
168
+ */
169
+ export function handleMcpMessage(message, context) {
170
+ if (!isRequest(message)) {
171
+ const id = message?.id;
172
+ const isResponse = typeof message === 'object' &&
173
+ message !== null &&
174
+ ('result' in message || 'error' in message);
175
+ if (isResponse)
176
+ return undefined;
177
+ return {
178
+ jsonrpc: '2.0',
179
+ id: typeof id === 'string' || typeof id === 'number' ? id : null,
180
+ error: { code: -32600, message: 'invalid request' },
181
+ };
182
+ }
183
+ if (message.id === undefined)
184
+ return undefined;
185
+ // MCP requires a string or number id; null is reserved for error replies.
186
+ if (message.id === null) {
187
+ return { jsonrpc: '2.0', id: null, error: { code: -32600, message: 'invalid request' } };
188
+ }
189
+ const id = message.id;
190
+ const params = message.params ?? {};
191
+ const reply = (result) => ({ jsonrpc: '2.0', id, result });
192
+ switch (message.method) {
193
+ case 'initialize': {
194
+ const requested = params.protocolVersion;
195
+ const protocolVersion = PROTOCOL_VERSIONS.find((version) => version === requested);
196
+ return reply({
197
+ protocolVersion: protocolVersion ?? LATEST_PROTOCOL,
198
+ capabilities: { tools: { listChanged: false } },
199
+ serverInfo: { name: PACKAGE_NAME, version: VERSION },
200
+ instructions: INSTRUCTIONS,
201
+ });
202
+ }
203
+ case 'ping':
204
+ return reply({});
205
+ case 'tools/list':
206
+ return reply({
207
+ tools: TOOLS.map(({ name, description, inputSchema }) => ({
208
+ name,
209
+ description,
210
+ inputSchema,
211
+ })),
212
+ });
213
+ case 'tools/call': {
214
+ const tool = TOOLS.find((candidate) => candidate.name === params.name);
215
+ if (tool === undefined) {
216
+ return {
217
+ jsonrpc: '2.0',
218
+ id,
219
+ error: { code: -32602, message: `unknown tool: ${String(params.name)}` },
220
+ };
221
+ }
222
+ return reply(callTool(tool, params, context));
223
+ }
224
+ default:
225
+ return {
226
+ jsonrpc: '2.0',
227
+ id,
228
+ error: { code: -32601, message: `method not found: ${message.method}` },
229
+ };
230
+ }
231
+ }
232
+ /** Answer one line of the stdio transport, or return `undefined` for no reply. */
233
+ export function handleMcpLine(line, context) {
234
+ if (line.trim() === '')
235
+ return undefined;
236
+ let message;
237
+ try {
238
+ message = JSON.parse(line);
239
+ }
240
+ catch {
241
+ return JSON.stringify({
242
+ jsonrpc: '2.0',
243
+ id: null,
244
+ error: { code: -32700, message: 'parse error' },
245
+ });
246
+ }
247
+ // Revision 2025-03-26 allows batches: answer each member, omit the silent ones.
248
+ if (Array.isArray(message)) {
249
+ if (message.length === 0) {
250
+ return JSON.stringify({
251
+ jsonrpc: '2.0',
252
+ id: null,
253
+ error: { code: -32600, message: 'invalid request' },
254
+ });
255
+ }
256
+ const responses = message
257
+ .map((member) => handleMcpMessage(member, context))
258
+ .filter((response) => response !== undefined);
259
+ return responses.length === 0 ? undefined : JSON.stringify(responses);
260
+ }
261
+ const response = handleMcpMessage(message, context);
262
+ return response === undefined ? undefined : JSON.stringify(response);
263
+ }
264
+ /** Serve MCP on stdin/stdout until stdin closes. Logs go to stderr only. */
265
+ export function serveMcp(context = { cwd: process.cwd(), home: homedir() }) {
266
+ const lines = createInterface({ input: process.stdin, crlfDelay: Number.POSITIVE_INFINITY });
267
+ lines.on('line', (line) => {
268
+ const response = handleMcpLine(line, context);
269
+ if (response !== undefined)
270
+ process.stdout.write(`${response}\n`);
271
+ });
272
+ return lines;
273
+ }
274
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAqB,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAErD,8EAA8E;AAC9E,MAAM,iBAAiB,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAU,CAAC;AAC5F,MAAM,eAAe,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAExE,MAAM,YAAY,GAAG;;6FAEwE,CAAC;AAkC9F,MAAM,UAAU,GAAG;IACjB,WAAW,EAAE,yDAAyD;IACtE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;CAChD,CAAC;AAEF,MAAM,IAAI,GAAG,CAAC,KAAc,EAAc,EAAE,CAAC,CAAC;IAC5C,OAAO,EAAE;QACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;KAC3F;CACF,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,CAAC,KAAc,EAAc,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAEpF,MAAM,SAAS,GAAG,YAAY,CAAC;AAE/B,SAAS,eAAe,CAAC,OAAmB;IAC1C,OAAO,iBAAiB,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,aAAa,CAAC,IAA6B,EAAE,GAAW;IAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,IAAI,SAAS,CAAC,IAAI,GAAG,8BAA8B,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,KAAK,GAAoB;IAC7B;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EACT,qHAAqH;QACvH,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;QAC5E,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;KAC3B;IACD;QACE,IAAI,EAAE,UAAU;QAChB,WAAW,EACT,sIAAsI;QACxI,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uCAAuC,EAAE;aAC/E;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;YAClB,oBAAoB,EAAE,KAAK;SAC5B;QACD,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;KAC3D;IACD;QACE,IAAI,EAAE,UAAU;QAChB,WAAW,EACT,8GAA8G;QAChH,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;YAChC,QAAQ,EAAE,CAAC,MAAM,CAAC;YAClB,oBAAoB,EAAE,KAAK;SAC5B;QACD,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;YACZ,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;YACzD,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;KACF;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EACT,yIAAyI;QAC3I,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE,UAAU;gBAChB,GAAG,EAAE;oBACH,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,uIAAuI;iBAC1I;gBACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iDAAiD,EAAE;aAC1F;YACD,QAAQ,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;YACzB,oBAAoB,EAAE,KAAK;SAC5B;QACD,GAAG,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE;YACrB,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YAC7D,qEAAqE;YACrE,qEAAqE;YACrE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;YACjF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACzB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;gBAChC,MAAM,EAAE,QAAQ;gBAChB,YAAY,EAAE,eAAe,CAAC,OAAO,CAAC;gBACtC,GAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChE,CAAC,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;gBACV,GAAG;gBACH,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;gBACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM;gBAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;aAC1B,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EACT,yHAAyH;QAC3H,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;QAC5E,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO;iBAC3B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;iBAC7C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,uEAAuE;YACvE,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtD,CAAC;KACF;CACF,CAAC;AAEF,SAAS,QAAQ,CAAC,IAAU,EAAE,MAA+B,EAAE,OAAmB;IAChF,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAA4B,CAAC;IACjE,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC;gBACb,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,GAAG;gBACvB,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,WAAW,KAAK,SAAS;oBAC1C,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;aAChD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,OAAgB;IACjC,OAAO,CACL,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,KAAK,IAAI;QACf,OAAiC,CAAC,OAAO,KAAK,KAAK;QACpD,OAAQ,OAAgC,CAAC,MAAM,KAAK,QAAQ,CAC7D,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAgB,EAChB,OAAmB;IAEnB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,EAAE,GAAI,OAAmC,EAAE,EAAE,CAAC;QACpD,MAAM,UAAU,GACd,OAAO,OAAO,KAAK,QAAQ;YAC3B,OAAO,KAAK,IAAI;YAChB,CAAC,QAAQ,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC;QAC9C,IAAI,UAAU;YAAE,OAAO,SAAS,CAAC;QACjC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;YAChE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE;SACpD,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,0EAA0E;IAC1E,IAAI,OAAO,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,CAAC;IAC3F,CAAC;IACD,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;IACtB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,CAAC,MAAe,EAAmB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAErF,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;QACvB,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,CAAC;YACzC,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;YACnF,OAAO,KAAK,CAAC;gBACX,eAAe,EAAE,eAAe,IAAI,eAAe;gBACnD,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE;gBAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE;gBACpD,YAAY,EAAE,YAAY;aAC3B,CAAC,CAAC;QACL,CAAC;QACD,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC;QACnB,KAAK,YAAY;YACf,OAAO,KAAK,CAAC;gBACX,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;oBACxD,IAAI;oBACJ,WAAW;oBACX,WAAW;iBACZ,CAAC,CAAC;aACJ,CAAC,CAAC;QACL,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;YACvE,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,EAAE;oBACF,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,iBAAiB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE;iBACzE,CAAC;YACJ,CAAC;YACD,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QAChD,CAAC;QACD;YACE,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,qBAAqB,OAAO,CAAC,MAAM,EAAE,EAAE;aACxE,CAAC;IACN,CAAC;AACH,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAAmB;IAC7D,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACzC,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,IAAI;YACR,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE;SAChD,CAAC,CAAC;IACL,CAAC;IACD,gFAAgF;IAChF,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,OAAO,EAAE,KAAK;gBACd,EAAE,EAAE,IAAI;gBACR,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE;aACpD,CAAC,CAAC;QACL,CAAC;QACD,MAAM,SAAS,GAAG,OAAO;aACtB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;aAClD,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;QAChD,OAAO,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpD,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACvE,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,QAAQ,CAAC,UAAsB,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;IACpF,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC7F,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9C,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import type { ActionType } from './actions.js';
15
15
  import type { PropSchema } from './prop-schema.js';
16
- export type RuntimeFeature = 'tabs' | 'accordion' | 'carousel' | 'slider' | 'copy' | 'filter' | 'theme' | 'dialog' | 'chart' | 'diagram' | 'media';
16
+ export type RuntimeFeature = 'tabs' | 'accordion' | 'carousel' | 'slider' | 'copy' | 'filter' | 'theme' | 'dialog' | 'chart' | 'diagram' | 'media' | 'outline' | 'bento' | 'marquee' | 'terminal' | 'tree' | 'before-after' | 'kpi' | 'showcase' | 'cta' | 'frame' | 'checklist';
17
17
  export interface SlotSpec {
18
18
  /** Types accepted by the slot; `'*'` accepts any block. */
19
19
  accepts: readonly string[] | '*';
@@ -1 +1 @@
1
- {"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../../src/registry/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,WAAW,GACX,UAAU,GACV,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,OAAO,CAAC;AAEZ,MAAM,WAAW,QAAQ;IACvB,2DAA2D;IAC3D,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,eAAe,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,yEAAyE;IACzE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAoFD,gDAAgD;AAChD,eAAO,MAAM,WAAW,2EAQd,CAAC;AA4BX,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EA2nBvD,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAE/D,CAAC"}
1
+ {"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../../src/registry/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,WAAW,GACX,UAAU,GACV,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,OAAO,GACP,SAAS,GACT,OAAO,GACP,SAAS,GACT,UAAU,GACV,MAAM,GACN,cAAc,GACd,KAAK,GACL,UAAU,GACV,KAAK,GACL,OAAO,GACP,WAAW,CAAC;AAEhB,MAAM,WAAW,QAAQ;IACvB,2DAA2D;IAC3D,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,eAAe,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,yEAAyE;IACzE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AA0FD,gDAAgD;AAChD,eAAO,MAAM,WAAW,2EAQd,CAAC;AA4BX,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EAk3BvD,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAE/D,CAAC"}
@@ -28,6 +28,10 @@ const txt = (o = {}) => ({
28
28
  ...o,
29
29
  });
30
30
  const num = (o = {}) => ({ kind: 'number', ...o });
31
+ const bool = (o = {}) => ({
32
+ kind: 'boolean',
33
+ ...o,
34
+ });
31
35
  const urlProp = (o = {}) => ({
32
36
  kind: 'url',
33
37
  ...o,
@@ -103,8 +107,15 @@ export const BLOCK_DEFINITIONS = [
103
107
  define({
104
108
  type: 'section',
105
109
  purpose: 'A titled group of blocks.',
106
- summary: 'Section with an optional heading wrapping child blocks.',
107
- props: { title: OPTIONAL_TITLE, ...anchorProps },
110
+ summary: 'Section with an optional heading wrapping child blocks; an inverse surface sets it on a night band.',
111
+ props: {
112
+ title: OPTIONAL_TITLE,
113
+ surface: enumStr(['plain', 'inverse'], {
114
+ default: 'plain',
115
+ description: 'inverse renders the section on a dark band using the theme dark palette, in both schemes.',
116
+ }),
117
+ ...anchorProps,
118
+ },
108
119
  slots: { children: { accepts: '*', min: 1, max: 200 } },
109
120
  }),
110
121
  define({
@@ -193,7 +204,8 @@ export const BLOCK_DEFINITIONS = [
193
204
  ...anchorProps,
194
205
  },
195
206
  assets: ['code'],
196
- a11y: 'Renders <pre><code> with the authored text; no syntax highlighting requires network access.',
207
+ runtimeFeatures: ['copy'],
208
+ a11y: 'Renders <pre><code> with the authored text and a labelled Copy button; no syntax highlighting requires network access.',
197
209
  serializer: 'Emits the code text verbatim inside the fenced block when serialized back to Markdown.',
198
210
  }),
199
211
  define({
@@ -261,19 +273,29 @@ export const BLOCK_DEFINITIONS = [
261
273
  semantic({
262
274
  type: 'hero',
263
275
  purpose: 'Page opener that states the artifact subject.',
264
- summary: 'Hero: eyebrow, title, and one-line description.',
276
+ summary: 'Hero: eyebrow, title, and one-line description, optionally over a framed product shot.',
265
277
  props: {
266
278
  eyebrow: str({ maxLength: 80 }),
267
279
  title: TITLE,
268
280
  description: txt(),
281
+ align: enumStr(['start', 'center'], { default: 'start' }),
282
+ src: urlProp({
283
+ description: 'Optional product shot shown in a browser frame below the copy.',
284
+ }),
285
+ alt: str({ maxLength: 300, description: 'Required when src is set.' }),
286
+ address: str({
287
+ maxLength: 120,
288
+ description: 'Text shown in the frame address bar; not a link.',
289
+ }),
269
290
  ...anchorProps,
270
291
  },
292
+ network: 'optional',
271
293
  sizing: {
272
294
  sizes: ['medium', 'large'],
273
295
  default: 'large',
274
- responsive: 'Full width; text reflows.',
296
+ responsive: 'Full width; text reflows and the product shot scales to the column without cropping.',
275
297
  },
276
- a11y: 'The hero title is an <h1>; the eyebrow is supporting text, not a heading.',
298
+ a11y: 'The hero title is an <h1>; the eyebrow is supporting text, not a heading. The shot keeps its alt text and its frame is decorative.',
277
299
  }),
278
300
  semantic({
279
301
  type: 'stats',
@@ -506,6 +528,200 @@ export const BLOCK_DEFINITIONS = [
506
528
  a11y: 'Requires a textual fallback summary when the adapter cannot render; the fallback is always emitted.',
507
529
  migration: 'Adapter contract is versioned separately; a spec that no longer compiles degrades to the fallback.',
508
530
  }),
531
+ // --- showcase -----------------------------------------------------------
532
+ semantic({
533
+ type: 'bento',
534
+ purpose: 'Feature mosaic: tiles of mixed size that each carry one idea, figure, or image.',
535
+ summary: 'Bento: asymmetric tile grid; a tile can hold an eyebrow, title, text, a large figure, and a local image.',
536
+ props: {
537
+ title: OPTIONAL_TITLE,
538
+ items: itemsOf({
539
+ title: LABEL,
540
+ text: txt(),
541
+ eyebrow: str({ maxLength: 60 }),
542
+ value: str({ maxLength: 40, description: 'A large figure shown above the title.' }),
543
+ size: enumStr(['small', 'wide', 'tall', 'large'], { default: 'small' }),
544
+ src: urlProp({
545
+ description: 'Optional image; remote sources follow the network policy.',
546
+ }),
547
+ alt: str({
548
+ maxLength: 300,
549
+ description: 'Required when src is set; use "" for a decorative image.',
550
+ }),
551
+ }, { minItems: 1, maxItems: 12 }),
552
+ ...anchorProps,
553
+ },
554
+ runtimeFeatures: ['bento'],
555
+ network: 'optional',
556
+ sizing: {
557
+ sizes: ['large'],
558
+ default: 'large',
559
+ responsive: 'Four columns on wide screens, two on tablets, one on phones; spans collapse with the grid.',
560
+ },
561
+ a11y: 'A list of tiles; each tile title is a heading-styled paragraph, images keep their alt text.',
562
+ }),
563
+ define({
564
+ type: 'marquee',
565
+ purpose: 'Continuously scrolling strip of short highlights.',
566
+ summary: 'Marquee: looping ticker of short items that pauses on hover and stops under reduced motion.',
567
+ props: {
568
+ label: str({ maxLength: 120, default: 'Highlights' }),
569
+ items: list(str({ required: true, maxLength: 80 }), {
570
+ required: true,
571
+ minItems: 1,
572
+ maxItems: 30,
573
+ }),
574
+ speed: enumStr(['slow', 'normal', 'fast'], { default: 'normal' }),
575
+ ...anchorProps,
576
+ },
577
+ runtimeFeatures: ['marquee'],
578
+ a11y: 'Screen readers get one static list; the duplicated scrolling track is aria-hidden, and motion stops under prefers-reduced-motion.',
579
+ }),
580
+ define({
581
+ type: 'terminal',
582
+ purpose: 'A command-line session: commands with their output.',
583
+ summary: 'Terminal: window-framed session whose lines type in on load; commands, output, comments, success, and errors are styled apart.',
584
+ props: {
585
+ title: str({ maxLength: 120, default: 'Terminal' }),
586
+ lines: itemsOf({
587
+ kind: enumStr(['command', 'output', 'comment', 'success', 'error'], {
588
+ default: 'output',
589
+ }),
590
+ text: txt({ required: true, maxLength: 2_000 }),
591
+ }, { minItems: 1, maxItems: 60 }),
592
+ ...anchorProps,
593
+ },
594
+ runtimeFeatures: ['terminal', 'copy'],
595
+ a11y: 'Renders <pre> text; the prompt glyph is decorative, and the line reveal is skipped under reduced motion.',
596
+ }),
597
+ semantic({
598
+ type: 'file-tree',
599
+ purpose: 'Files and folders, optionally with change status, derived from flat paths.',
600
+ summary: 'File tree: nested folders built from slash-separated paths, with per-file status and notes.',
601
+ props: {
602
+ title: OPTIONAL_TITLE,
603
+ items: itemsOf({
604
+ path: str({ required: true, maxLength: 300 }),
605
+ status: enumStr(['added', 'modified', 'deleted', 'renamed', 'unchanged'], {
606
+ default: 'unchanged',
607
+ }),
608
+ note: str({ maxLength: 200 }),
609
+ }, { minItems: 1, maxItems: 200 }),
610
+ ...anchorProps,
611
+ },
612
+ runtimeFeatures: ['tree'],
613
+ a11y: 'Nested lists mirror the folder structure; status is written as text, not only color.',
614
+ }),
615
+ semantic({
616
+ type: 'before-after',
617
+ purpose: 'Before and after: two images of the same frame, revealed by a draggable divider.',
618
+ summary: 'Compare: before/after image slider driven by a native range input; without script both images stay visible.',
619
+ props: {
620
+ title: OPTIONAL_TITLE,
621
+ before: obj({
622
+ src: urlProp({ required: true }),
623
+ alt: str({ required: true, maxLength: 300 }),
624
+ label: str({ maxLength: 40, default: 'Before' }),
625
+ }, { required: true }),
626
+ after: obj({
627
+ src: urlProp({ required: true }),
628
+ alt: str({ required: true, maxLength: 300 }),
629
+ label: str({ maxLength: 40, default: 'After' }),
630
+ }, { required: true }),
631
+ start: num({ min: 0, max: 100, default: 50 }),
632
+ caption: txt(),
633
+ ...anchorProps,
634
+ },
635
+ runtimeFeatures: ['before-after'],
636
+ network: 'optional',
637
+ a11y: 'The divider is a labelled <input type="range">: keyboard, pointer, and touch all move it, and both images keep their alt text.',
638
+ }),
639
+ semantic({
640
+ type: 'kpi',
641
+ purpose: 'Headline metrics with direction of change and a small trend line.',
642
+ summary: 'KPI: metric cards with value, signed delta, good/bad direction, and an optional sparkline series.',
643
+ props: {
644
+ title: OPTIONAL_TITLE,
645
+ items: itemsOf({
646
+ label: LABEL,
647
+ value: str({ required: true, maxLength: 40 }),
648
+ delta: str({ maxLength: 24 }),
649
+ trend: enumStr(['up', 'down', 'flat'], { default: 'flat' }),
650
+ good: enumStr(['up', 'down'], {
651
+ default: 'up',
652
+ description: 'Which direction counts as an improvement for this metric.',
653
+ }),
654
+ series: list(num({ required: true, min: -1e12, max: 1e12 }), { maxItems: 60 }),
655
+ caption: str({ maxLength: 120 }),
656
+ }, { minItems: 1, maxItems: 8 }),
657
+ ...anchorProps,
658
+ },
659
+ runtimeFeatures: ['kpi'],
660
+ a11y: 'Value, delta, and direction are text; the sparkline is decorative and aria-hidden.',
661
+ }),
662
+ semantic({
663
+ type: 'showcase',
664
+ purpose: 'Feature spotlight: copy beside a framed screenshot.',
665
+ summary: 'Showcase: eyebrow, title, text, and bullets beside an image in a browser frame; the image side can flip.',
666
+ props: {
667
+ eyebrow: str({ maxLength: 60 }),
668
+ title: TITLE,
669
+ text: txt(),
670
+ bullets: list(str({ required: true, maxLength: 200 }), { maxItems: 8 }),
671
+ src: urlProp({ required: true }),
672
+ alt: str({ required: true, maxLength: 300 }),
673
+ frame: enumStr(['browser', 'plain'], { default: 'browser' }),
674
+ address: str({
675
+ maxLength: 120,
676
+ description: 'Text shown in the browser frame address bar; not a link.',
677
+ }),
678
+ align: enumStr(['media-right', 'media-left'], { default: 'media-right' }),
679
+ ...anchorProps,
680
+ },
681
+ runtimeFeatures: ['showcase'],
682
+ network: 'optional',
683
+ sizing: {
684
+ sizes: ['large'],
685
+ default: 'large',
686
+ responsive: 'Copy and media sit side by side on wide screens and stack, media last, on narrow ones.',
687
+ },
688
+ a11y: 'The title is a heading; the frame chrome is decorative and the image keeps its alt text.',
689
+ }),
690
+ define({
691
+ type: 'checklist',
692
+ purpose: 'Task list with done and open items and a completion count.',
693
+ summary: 'Checklist: items marked done or open, with a visible completion count.',
694
+ props: {
695
+ title: OPTIONAL_TITLE,
696
+ items: itemsOf({ text: LABEL, done: bool({ default: false }) }, { maxItems: 100 }),
697
+ ...anchorProps,
698
+ },
699
+ a11y: 'Each item states "done" or "open" in text; the check glyph is decorative.',
700
+ runtimeFeatures: ['checklist'],
701
+ }),
702
+ semantic({
703
+ type: 'cta',
704
+ purpose: 'Closing call to action that sends the reader somewhere next.',
705
+ summary: 'CTA: eyebrow, oversized title, text, and up to three link actions on a night band.',
706
+ props: {
707
+ eyebrow: str({ maxLength: 60 }),
708
+ title: TITLE,
709
+ text: txt(),
710
+ actions: list(obj({
711
+ label: LABEL,
712
+ href: urlProp({ required: true }),
713
+ variant: enumStr(['primary', 'secondary'], { default: 'secondary' }),
714
+ }), { maxItems: 3 }),
715
+ ...anchorProps,
716
+ },
717
+ runtimeFeatures: ['cta'],
718
+ sizing: {
719
+ sizes: ['large'],
720
+ default: 'large',
721
+ responsive: 'Full width; the title scales with the viewport and the actions wrap.',
722
+ },
723
+ a11y: 'The title is an <h2>; every action is a real link with its own text.',
724
+ }),
509
725
  // --- media --------------------------------------------------------------
510
726
  define({
511
727
  type: 'image',