@krizaka/ui 3.20.0 → 3.22.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 (263) hide show
  1. package/README.md +1 -0
  2. package/dist/action-bar.js +4 -4
  3. package/dist/app-shell.js +1 -1
  4. package/dist/argument-card.js +4 -4
  5. package/dist/blocks.css +1 -1
  6. package/dist/button.js +3 -2
  7. package/dist/card.js +3 -3
  8. package/dist/{chunk-5MH64NIL.js → chunk-2L67YTNV.js} +2 -2
  9. package/dist/{chunk-2NB27LM7.js → chunk-3IN6TOPM.js} +4 -4
  10. package/dist/{chunk-VDR2EP6K.js → chunk-4QN5YJ3D.js} +17 -5
  11. package/dist/chunk-4QN5YJ3D.js.map +1 -0
  12. package/dist/chunk-AQSZJJAJ.js +126 -0
  13. package/dist/chunk-AQSZJJAJ.js.map +1 -0
  14. package/dist/{chunk-3GODX3D6.js → chunk-QDXV544C.js} +2 -2
  15. package/dist/chunk-QDXV544C.js.map +1 -0
  16. package/dist/chunk-R6NK6ZNY.js +1080 -0
  17. package/dist/chunk-R6NK6ZNY.js.map +1 -0
  18. package/dist/chunk-TDG7ED2W.js +1 -0
  19. package/dist/chunk-TDG7ED2W.js.map +1 -0
  20. package/dist/{chunk-LIPK4UCS.js → chunk-YCIBJ6OQ.js} +140 -209
  21. package/dist/chunk-YCIBJ6OQ.js.map +1 -0
  22. package/dist/code-block.js +17 -5
  23. package/dist/code-block.js.map +1 -1
  24. package/dist/comparison-table.d.ts +44 -0
  25. package/dist/comparison-table.js +84 -0
  26. package/dist/comparison-table.js.map +1 -0
  27. package/dist/data-table.js +19 -1066
  28. package/dist/data-table.js.map +1 -1
  29. package/dist/date-picker.js +5 -5
  30. package/dist/date-picker.js.map +1 -1
  31. package/dist/force-update-screen.d.ts +80 -0
  32. package/dist/force-update-screen.js +38 -0
  33. package/dist/force-update-screen.js.map +1 -0
  34. package/dist/genui.d.ts +219 -0
  35. package/dist/genui.js +506 -0
  36. package/dist/genui.js.map +1 -0
  37. package/dist/index.d.ts +17 -24
  38. package/dist/index.js +1 -1
  39. package/dist/maintenance-screen.d.ts +68 -0
  40. package/dist/maintenance-screen.js +35 -0
  41. package/dist/maintenance-screen.js.map +1 -0
  42. package/dist/marketing-layout.js +1 -1
  43. package/dist/marketing-layout.js.map +1 -1
  44. package/dist/media-grid.js +44 -152
  45. package/dist/media-grid.js.map +1 -1
  46. package/dist/meta-row.d.ts +54 -0
  47. package/dist/meta-row.js +35 -0
  48. package/dist/meta-row.js.map +1 -0
  49. package/dist/native.d.ts +92 -16
  50. package/dist/native.js +873 -814
  51. package/dist/native.js.map +1 -1
  52. package/dist/nav-bar.d.ts +30 -7
  53. package/dist/nav-bar.js +71 -17
  54. package/dist/nav-bar.js.map +1 -1
  55. package/dist/page-hero.js +5 -5
  56. package/dist/radio-group.js +1 -1
  57. package/dist/settings-layout.js +1 -1
  58. package/dist/settings-layout.js.map +1 -1
  59. package/dist/site-footer.js +2 -2
  60. package/dist/skip-link.js +1 -1
  61. package/dist/step-showcase.d.ts +62 -0
  62. package/dist/step-showcase.js +227 -0
  63. package/dist/step-showcase.js.map +1 -0
  64. package/dist/tabs.js +2 -2
  65. package/dist/tabs.js.map +1 -1
  66. package/dist/update-prompt.d.ts +86 -0
  67. package/dist/update-prompt.js +41 -0
  68. package/dist/update-prompt.js.map +1 -0
  69. package/dist/video-player.d.ts +1 -1
  70. package/dist/video-player.js +16 -3
  71. package/dist/video-player.js.map +1 -1
  72. package/package.json +108 -9
  73. package/registry/achievement.json +1 -1
  74. package/registry/action-bar.json +1 -1
  75. package/registry/activity-feed.json +1 -1
  76. package/registry/alert.json +1 -1
  77. package/registry/app-shell.json +1 -1
  78. package/registry/argument-card.json +1 -1
  79. package/registry/audio-player.json +1 -1
  80. package/registry/auth-layout.json +1 -1
  81. package/registry/avatar.json +1 -1
  82. package/registry/badge.json +1 -1
  83. package/registry/button.json +1 -1
  84. package/registry/card-grid.json +1 -1
  85. package/registry/card.json +1 -1
  86. package/registry/catalogue-page.json +1 -1
  87. package/registry/changelog-page.json +1 -1
  88. package/registry/chat.json +1 -1
  89. package/registry/checkbox.json +1 -1
  90. package/registry/chip-link.json +1 -1
  91. package/registry/chip.json +1 -1
  92. package/registry/choice-grid.json +1 -1
  93. package/registry/code-block.json +1 -1
  94. package/registry/combobox.json +1 -1
  95. package/registry/command.json +1 -1
  96. package/registry/comparison-table.json +207 -0
  97. package/registry/component-page.json +1 -1
  98. package/registry/confirm-button.json +1 -1
  99. package/registry/contact-page.json +1 -1
  100. package/registry/continue-prompt.json +1 -1
  101. package/registry/countdown.json +1 -1
  102. package/registry/cta-panel.json +1 -1
  103. package/registry/dashboard-layout.json +1 -1
  104. package/registry/data-table.json +1 -1
  105. package/registry/date-picker.json +3 -3
  106. package/registry/decision-list.json +1 -1
  107. package/registry/description-list.json +1 -1
  108. package/registry/detail-layout.json +1 -1
  109. package/registry/dialog.json +1 -1
  110. package/registry/docs-article-page.json +1 -1
  111. package/registry/docs-hub-page.json +1 -1
  112. package/registry/docs-layout.json +1 -1
  113. package/registry/document-viewer.json +1 -1
  114. package/registry/dropdown-menu.json +1 -1
  115. package/registry/empty-state.json +1 -1
  116. package/registry/error-page.json +1 -1
  117. package/registry/examples/comparison-table/versus.d.ts +4 -0
  118. package/registry/examples/comparison-table/versus.js +28 -0
  119. package/registry/examples/comparison-table/versus.tsx +20 -0
  120. package/registry/examples/dialog/native/sheet.dark.png +0 -0
  121. package/registry/examples/dialog/native/sheet.light.png +0 -0
  122. package/registry/examples/force-update-screen/default.d.ts +4 -0
  123. package/registry/examples/force-update-screen/default.js +25 -0
  124. package/registry/examples/force-update-screen/default.tsx +19 -0
  125. package/registry/examples/force-update-screen/native/default.d.ts +4 -0
  126. package/registry/examples/force-update-screen/native/default.dark.png +0 -0
  127. package/registry/examples/force-update-screen/native/default.js +24 -0
  128. package/registry/examples/force-update-screen/native/default.light.png +0 -0
  129. package/registry/examples/force-update-screen/native/default.tsx +18 -0
  130. package/registry/examples/genui/streaming.d.ts +4 -0
  131. package/registry/examples/genui/streaming.js +18 -0
  132. package/registry/examples/genui/streaming.tsx +14 -0
  133. package/registry/examples/genui/table.d.ts +4 -0
  134. package/registry/examples/genui/table.js +19 -0
  135. package/registry/examples/genui/table.tsx +14 -0
  136. package/registry/examples/maintenance-screen/default.d.ts +4 -0
  137. package/registry/examples/maintenance-screen/default.js +22 -0
  138. package/registry/examples/maintenance-screen/default.tsx +16 -0
  139. package/registry/examples/maintenance-screen/native/default.d.ts +4 -0
  140. package/registry/examples/maintenance-screen/native/default.dark.png +0 -0
  141. package/registry/examples/maintenance-screen/native/default.js +21 -0
  142. package/registry/examples/maintenance-screen/native/default.light.png +0 -0
  143. package/registry/examples/maintenance-screen/native/default.tsx +15 -0
  144. package/registry/examples/meta-row/native/video.d.ts +4 -0
  145. package/registry/examples/meta-row/native/video.dark.png +0 -0
  146. package/registry/examples/meta-row/native/video.js +11 -0
  147. package/registry/examples/meta-row/native/video.light.png +0 -0
  148. package/registry/examples/meta-row/native/video.tsx +5 -0
  149. package/registry/examples/meta-row/status.d.ts +4 -0
  150. package/registry/examples/meta-row/status.js +12 -0
  151. package/registry/examples/meta-row/status.tsx +7 -0
  152. package/registry/examples/meta-row/video.d.ts +4 -0
  153. package/registry/examples/meta-row/video.js +12 -0
  154. package/registry/examples/meta-row/video.tsx +7 -0
  155. package/registry/examples/nav-bar/family-product.js +16 -13
  156. package/registry/examples/nav-bar/family-product.tsx +19 -19
  157. package/registry/examples/step-showcase/desktop.d.ts +4 -0
  158. package/registry/examples/step-showcase/desktop.js +24 -0
  159. package/registry/examples/step-showcase/desktop.tsx +19 -0
  160. package/registry/examples/step-showcase/phone.d.ts +4 -0
  161. package/registry/examples/step-showcase/phone.js +24 -0
  162. package/registry/examples/step-showcase/phone.tsx +19 -0
  163. package/registry/examples/update-prompt/default.d.ts +4 -0
  164. package/registry/examples/update-prompt/default.js +24 -0
  165. package/registry/examples/update-prompt/default.tsx +18 -0
  166. package/registry/examples/update-prompt/native/default.d.ts +4 -0
  167. package/registry/examples/update-prompt/native/default.dark.png +0 -0
  168. package/registry/examples/update-prompt/native/default.js +23 -0
  169. package/registry/examples/update-prompt/native/default.light.png +0 -0
  170. package/registry/examples/update-prompt/native/default.tsx +17 -0
  171. package/registry/field.json +1 -1
  172. package/registry/file-upload.json +1 -1
  173. package/registry/filter-bar.json +1 -1
  174. package/registry/force-update-screen.json +323 -0
  175. package/registry/form.json +1 -1
  176. package/registry/gallery-page.json +1 -1
  177. package/registry/genui.json +409 -0
  178. package/registry/glow-card.json +1 -1
  179. package/registry/goal-gauge.json +1 -1
  180. package/registry/how-it-works-page.json +1 -1
  181. package/registry/image-cropper.json +1 -1
  182. package/registry/index.json +223 -4
  183. package/registry/iso.json +1 -1
  184. package/registry/kanban.json +1 -1
  185. package/registry/kbd.json +1 -1
  186. package/registry/landing-page.json +1 -1
  187. package/registry/landscape.json +1 -1
  188. package/registry/legal-page.json +1 -1
  189. package/registry/link-card.json +1 -1
  190. package/registry/list.json +1 -1
  191. package/registry/loader.json +1 -1
  192. package/registry/longform-page.json +1 -1
  193. package/registry/maintenance-screen.json +259 -0
  194. package/registry/map.json +2 -2
  195. package/registry/markdown.json +1 -1
  196. package/registry/marketing-layout.json +1 -1
  197. package/registry/marquee.json +1 -1
  198. package/registry/mascot-quote.json +1 -1
  199. package/registry/mascot-state.json +1 -1
  200. package/registry/mascots.json +1 -1
  201. package/registry/match-dialog.json +1 -1
  202. package/registry/media-capture.json +1 -1
  203. package/registry/media-grid.json +2 -2
  204. package/registry/meta-row.json +215 -0
  205. package/registry/meter.json +1 -1
  206. package/registry/nav-bar.json +58 -25
  207. package/registry/number-ticker.json +1 -1
  208. package/registry/page-header.json +1 -1
  209. package/registry/page-hero.json +1 -1
  210. package/registry/page.json +1 -1
  211. package/registry/pagination.json +1 -1
  212. package/registry/photo-grid.json +1 -1
  213. package/registry/pointer-light.json +1 -1
  214. package/registry/popover.json +1 -1
  215. package/registry/pricing-page.json +1 -1
  216. package/registry/product-page.json +1 -1
  217. package/registry/profile-card.json +1 -1
  218. package/registry/progress.json +1 -1
  219. package/registry/promise-card.json +1 -1
  220. package/registry/radio-group.json +2 -2
  221. package/registry/recipes.json +1 -1
  222. package/registry/scroll-stage.json +1 -1
  223. package/registry/search-field.json +1 -1
  224. package/registry/section-backdrop.json +1 -1
  225. package/registry/separator.json +1 -1
  226. package/registry/settings-layout.json +2 -2
  227. package/registry/showcase.json +1 -1
  228. package/registry/site-footer.json +13 -13
  229. package/registry/sites.json +1 -1
  230. package/registry/skeleton.json +1 -1
  231. package/registry/skip-link.json +2 -2
  232. package/registry/slider.json +1 -1
  233. package/registry/slot.json +1 -1
  234. package/registry/spinner.json +1 -1
  235. package/registry/split-view.json +1 -1
  236. package/registry/stage-banner.json +1 -1
  237. package/registry/stat.json +1 -1
  238. package/registry/status-page.json +1 -1
  239. package/registry/step-progress.json +1 -1
  240. package/registry/step-showcase.json +296 -0
  241. package/registry/stepper.json +1 -1
  242. package/registry/swipe-deck.json +1 -1
  243. package/registry/switch.json +1 -1
  244. package/registry/tabs.json +3 -3
  245. package/registry/tag-input.json +1 -1
  246. package/registry/tag-selector.json +1 -1
  247. package/registry/terminal-replay.json +1 -1
  248. package/registry/theme.json +1 -1
  249. package/registry/toast.json +1 -1
  250. package/registry/toc.json +1 -1
  251. package/registry/tooltip.json +1 -1
  252. package/registry/tree-view.json +1 -1
  253. package/registry/update-prompt.json +316 -0
  254. package/registry/verified-badge.json +1 -1
  255. package/registry/vertical-video.json +1 -1
  256. package/registry/video-player.json +4 -4
  257. package/registry/video-trimmer.json +1 -1
  258. package/registry/virtual.json +1 -1
  259. package/dist/chunk-3GODX3D6.js.map +0 -1
  260. package/dist/chunk-LIPK4UCS.js.map +0 -1
  261. package/dist/chunk-VDR2EP6K.js.map +0 -1
  262. /package/dist/{chunk-5MH64NIL.js.map → chunk-2L67YTNV.js.map} +0 -0
  263. /package/dist/{chunk-2NB27LM7.js.map → chunk-3IN6TOPM.js.map} +0 -0
package/dist/genui.js ADDED
@@ -0,0 +1,506 @@
1
+ "use client";
2
+ import {
3
+ CardBody,
4
+ CardRoot,
5
+ CardTitle,
6
+ Skeleton
7
+ } from "./chunk-AQSZJJAJ.js";
8
+ import {
9
+ DataTable
10
+ } from "./chunk-R6NK6ZNY.js";
11
+ import "./chunk-7Z4KHPFC.js";
12
+ import "./chunk-JXLDUDTD.js";
13
+ import "./chunk-3BC4XQ6C.js";
14
+ import "./chunk-KVDB4GXV.js";
15
+ import "./chunk-FKBHWS4N.js";
16
+ import "./chunk-7UCPGXKN.js";
17
+ import "./chunk-D3T54RSL.js";
18
+ import "./chunk-J3NC6ER4.js";
19
+ import {
20
+ cn
21
+ } from "./chunk-2FRWNSRO.js";
22
+ import "./chunk-REPTKUJ6.js";
23
+ import "./chunk-ZIXB33X7.js";
24
+ import "./chunk-FZBWEDQI.js";
25
+ import "./chunk-CPA5CF35.js";
26
+
27
+ // src/genui/catalog.tsx
28
+ import { formatCompact, formatMoney, formatNumber, formatPercent } from "@krizaka/intl";
29
+
30
+ // src/alert/alert.tsx
31
+ import { tv } from "tailwind-variants";
32
+ import { jsx, jsxs } from "react/jsx-runtime";
33
+ var alertVariants = tv({
34
+ slots: {
35
+ root: "relative flex w-full items-start gap-3 rounded-xl border p-4 text-sm text-fg",
36
+ icon: "mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5",
37
+ content: "flex min-w-0 flex-1 flex-col gap-1",
38
+ title: "font-semibold text-fg",
39
+ description: "text-fg-secondary",
40
+ action: "flex shrink-0 items-center gap-2 self-center"
41
+ },
42
+ variants: {
43
+ tone: {
44
+ info: { root: "border-info/40 bg-info/10", icon: "text-info" },
45
+ success: { root: "border-success/40 bg-success/10", icon: "text-success" },
46
+ warning: { root: "border-warning/50 bg-warning/10", icon: "text-warning" },
47
+ danger: { root: "border-danger/50 bg-danger/10", icon: "text-danger" }
48
+ }
49
+ },
50
+ defaultVariants: { tone: "info" }
51
+ });
52
+ function Alert({ tone = "info", icon, title, action, className, children, ...props }) {
53
+ const s = alertVariants({ tone });
54
+ return /* @__PURE__ */ jsxs("div", { role: tone === "danger" || tone === "warning" ? "alert" : "status", "data-tone": tone, className: s.root({ className }), ...props, children: [
55
+ icon && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: s.icon(), children: icon }),
56
+ /* @__PURE__ */ jsxs("div", { className: s.content(), children: [
57
+ title && /* @__PURE__ */ jsx("p", { className: s.title(), children: title }),
58
+ children && /* @__PURE__ */ jsx("div", { className: s.description(), children })
59
+ ] }),
60
+ action && /* @__PURE__ */ jsx("div", { className: s.action(), children: action })
61
+ ] });
62
+ }
63
+
64
+ // src/genui/spec.ts
65
+ var GENUI_VERSION = "v0.9";
66
+ var GENUI_CATALOG_ID = "krizaka:genui/v1";
67
+ var GENUI_LIMITS = {
68
+ /** Components per surface. */
69
+ components: 300,
70
+ /** Nesting depth from the root. */
71
+ depth: 12,
72
+ /** Characters in one string. */
73
+ string: 4e3,
74
+ /** Items in one array of the data model. */
75
+ array: 1e3,
76
+ /** Nesting depth of a data model value. */
77
+ dataDepth: 12,
78
+ /** Values (objects, arrays, scalars) in one data model update. */
79
+ dataNodes: 5e4,
80
+ /** Segments of a data path. */
81
+ pathSegments: 16
82
+ };
83
+ var ID = /^[A-Za-z0-9_-]{1,64}$/;
84
+ var MESSAGE_KEYS = ["createSurface", "updateComponents", "updateDataModel", "deleteSurface"];
85
+ var FORBIDDEN_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
86
+ var fail = (error) => ({ ok: false, error });
87
+ function isPlainObject(value) {
88
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
89
+ const proto = Object.getPrototypeOf(value);
90
+ return proto === Object.prototype || proto === null;
91
+ }
92
+ function onlyKeys(value, allowed, where) {
93
+ for (const key of Object.keys(value)) if (!allowed.includes(key)) return `${where}: unknown key "${key}"`;
94
+ return null;
95
+ }
96
+ function checkId(value, where) {
97
+ return typeof value === "string" && ID.test(value) ? null : `${where}: an id is 1-64 characters of [A-Za-z0-9_-]`;
98
+ }
99
+ function parsePath(path) {
100
+ if (typeof path !== "string" || path !== "/" && !path.startsWith("/") || path.length > 512) return fail("a path is a JSON pointer: /a/b");
101
+ if (path === "/") return { ok: true, value: [] };
102
+ const segments = path.slice(1).split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
103
+ if (segments.length > GENUI_LIMITS.pathSegments) return fail(`a path has at most ${GENUI_LIMITS.pathSegments} segments`);
104
+ for (const s of segments) {
105
+ if (s === "" || FORBIDDEN_SEGMENTS.has(s)) return fail(`a path may not hold the segment "${s}"`);
106
+ }
107
+ return { ok: true, value: segments };
108
+ }
109
+ function isBinding(value) {
110
+ return isPlainObject(value) && Object.keys(value).length === 1 && typeof value.path === "string";
111
+ }
112
+ function sanitizeData(value) {
113
+ let nodes = 0;
114
+ const walk = (v, depth) => {
115
+ if (++nodes > GENUI_LIMITS.dataNodes) return fail(`the data holds more than ${GENUI_LIMITS.dataNodes} values`);
116
+ if (depth > GENUI_LIMITS.dataDepth) return fail(`the data nests deeper than ${GENUI_LIMITS.dataDepth}`);
117
+ if (v === null || typeof v === "boolean") return { ok: true, value: v };
118
+ if (typeof v === "number") return Number.isFinite(v) ? { ok: true, value: v } : fail("a number must be finite");
119
+ if (typeof v === "string") return v.length <= GENUI_LIMITS.string ? { ok: true, value: v } : fail(`a string has at most ${GENUI_LIMITS.string} characters`);
120
+ if (Array.isArray(v)) {
121
+ if (v.length > GENUI_LIMITS.array) return fail(`an array has at most ${GENUI_LIMITS.array} items`);
122
+ const out = [];
123
+ for (const item of v) {
124
+ const r = walk(item, depth + 1);
125
+ if (!r.ok) return r;
126
+ out.push(r.value);
127
+ }
128
+ return { ok: true, value: out };
129
+ }
130
+ if (isPlainObject(v)) {
131
+ const out = /* @__PURE__ */ Object.create(null);
132
+ for (const [key, item] of Object.entries(v)) {
133
+ if (FORBIDDEN_SEGMENTS.has(key)) return fail(`a key may not be "${key}"`);
134
+ const r = walk(item, depth + 1);
135
+ if (!r.ok) return r;
136
+ out[key] = r.value;
137
+ }
138
+ return { ok: true, value: out };
139
+ }
140
+ return fail("the data is plain JSON only");
141
+ };
142
+ return walk(value, 0);
143
+ }
144
+ function validateMessage(input, catalog) {
145
+ if (!isPlainObject(input)) return fail("a message is a JSON object");
146
+ if (input.version !== GENUI_VERSION) return fail(`version must be "${GENUI_VERSION}"`);
147
+ const present = MESSAGE_KEYS.filter((k) => k in input);
148
+ if (present.length !== 1) return fail("a message holds exactly one of createSurface, updateComponents, updateDataModel, deleteSurface");
149
+ const kind = present[0];
150
+ const extra = onlyKeys(input, ["version", kind], "message");
151
+ if (extra) return fail(extra);
152
+ const body = input[kind];
153
+ if (!isPlainObject(body)) return fail(`${kind} is an object`);
154
+ const surface = checkId(body.surfaceId, `${kind}.surfaceId`);
155
+ if (surface) return fail(surface);
156
+ switch (kind) {
157
+ case "createSurface": {
158
+ const keys = onlyKeys(body, ["surfaceId", "catalogId", "theme", "sendDataModel"], kind);
159
+ if (keys) return fail(keys);
160
+ if (body.catalogId !== GENUI_CATALOG_ID) return fail(`catalogId must be "${GENUI_CATALOG_ID}"`);
161
+ return { ok: true, value: { version: GENUI_VERSION, createSurface: { surfaceId: body.surfaceId, catalogId: GENUI_CATALOG_ID } } };
162
+ }
163
+ case "updateComponents": {
164
+ const keys = onlyKeys(body, ["surfaceId", "components"], kind);
165
+ if (keys) return fail(keys);
166
+ if (!Array.isArray(body.components) || body.components.length > GENUI_LIMITS.components) {
167
+ return fail(`components is an array of at most ${GENUI_LIMITS.components}`);
168
+ }
169
+ const components = [];
170
+ for (const raw of body.components) {
171
+ if (!isPlainObject(raw)) return fail("a component is an object");
172
+ const id = checkId(raw.id, "component.id");
173
+ if (id) return fail(id);
174
+ if (typeof raw.component !== "string" || !Object.hasOwn(catalog, raw.component)) {
175
+ return fail(`component "${String(raw.id)}": "${String(raw.component)}" is not in the catalog`);
176
+ }
177
+ const clean = sanitizeData(raw);
178
+ if (!clean.ok) return fail(`component "${raw.id}": ${clean.error}`);
179
+ const component = { ...clean.value };
180
+ const problem = catalog[raw.component].check(component);
181
+ if (problem) return fail(`component "${raw.id}" (${raw.component}): ${problem}`);
182
+ components.push(component);
183
+ }
184
+ return { ok: true, value: { version: GENUI_VERSION, updateComponents: { surfaceId: body.surfaceId, components } } };
185
+ }
186
+ case "updateDataModel": {
187
+ const keys = onlyKeys(body, ["surfaceId", "path", "value"], kind);
188
+ if (keys) return fail(keys);
189
+ const path = body.path === void 0 ? "/" : body.path;
190
+ const parsed = parsePath(path);
191
+ if (!parsed.ok) return parsed;
192
+ if (!("value" in body)) return { ok: true, value: { version: GENUI_VERSION, updateDataModel: { surfaceId: body.surfaceId, path } } };
193
+ const clean = sanitizeData(body.value);
194
+ if (!clean.ok) return clean;
195
+ return { ok: true, value: { version: GENUI_VERSION, updateDataModel: { surfaceId: body.surfaceId, path, value: clean.value } } };
196
+ }
197
+ default: {
198
+ const keys = onlyKeys(body, ["surfaceId"], kind);
199
+ if (keys) return fail(keys);
200
+ return { ok: true, value: { version: GENUI_VERSION, deleteSurface: { surfaceId: body.surfaceId } } };
201
+ }
202
+ }
203
+ }
204
+ function allowKeys(component, keys) {
205
+ return onlyKeys(component, ["id", "component", ...keys], "properties");
206
+ }
207
+ function checkText(value, name, required) {
208
+ if (value === void 0) return required ? `${name} is required` : null;
209
+ if (isBinding(value)) return parsePath(value.path).ok ? null : `${name}: a bad path`;
210
+ return typeof value === "string" ? null : `${name} is a string`;
211
+ }
212
+ function checkEnum(value, name, allowed, required = false) {
213
+ if (value === void 0) return required ? `${name} is required` : null;
214
+ return typeof value === "string" && allowed.includes(value) ? null : `${name} is one of ${allowed.join(", ")}`;
215
+ }
216
+ function checkChildren(value, name = "children") {
217
+ if (!Array.isArray(value) || value.length > GENUI_LIMITS.components) return `${name} is an array of component ids`;
218
+ for (const id of value) if (checkId(id, name)) return `${name} holds ids only`;
219
+ return null;
220
+ }
221
+ function checkBinding(value, name) {
222
+ if (!isBinding(value)) return `${name} is a binding { "path": "/\u2026" }`;
223
+ return parsePath(value.path).ok ? null : `${name}: a bad path`;
224
+ }
225
+ function checkNumber(value, name, required) {
226
+ if (value === void 0) return required ? `${name} is required` : null;
227
+ if (isBinding(value)) return parsePath(value.path).ok ? null : `${name}: a bad path`;
228
+ return typeof value === "number" && Number.isFinite(value) ? null : `${name} is a number`;
229
+ }
230
+ var GENUI_FORMATS = ["number", "integer", "compact", "percent", "money"];
231
+ function checkCurrency(value, required) {
232
+ if (value === void 0) return required ? "currency is required with the money format" : null;
233
+ return typeof value === "string" && /^[A-Z]{3}$/.test(value) ? null : "currency is a three-letter code (CAD)";
234
+ }
235
+
236
+ // src/genui/catalog.tsx
237
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
238
+ var first = (...problems) => problems.find((p) => p !== null) ?? null;
239
+ function asText(value) {
240
+ if (typeof value === "string") return value.slice(0, GENUI_LIMITS.string);
241
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
242
+ return "";
243
+ }
244
+ function formatGenUiValue(value, format, locale, currency) {
245
+ if (typeof value !== "number" || !Number.isFinite(value)) return asText(value);
246
+ switch (format) {
247
+ case "integer":
248
+ return formatNumber(Math.round(value), { locale, maximumFractionDigits: 0 });
249
+ case "compact":
250
+ return formatCompact(value, { locale });
251
+ case "percent":
252
+ return formatPercent(value, { locale, maximumFractionDigits: 1 });
253
+ case "money":
254
+ return currency ? formatMoney(Math.round(value), { currency, locale }) : formatNumber(value, { locale });
255
+ default:
256
+ return formatNumber(value, { locale, maximumFractionDigits: 2 });
257
+ }
258
+ }
259
+ var TONES = ["info", "success", "warning", "danger"];
260
+ var VARIANTS = ["body", "heading", "caption"];
261
+ var column = {
262
+ check: (c) => first(allowKeys(c, ["children"]), checkChildren(c.children)),
263
+ render: (c, ctx) => /* @__PURE__ */ jsx2("div", { className: "flex min-w-0 flex-col gap-4", children: ctx.children(c.children) })
264
+ };
265
+ var row = {
266
+ check: (c) => first(allowKeys(c, ["children"]), checkChildren(c.children)),
267
+ render: (c, ctx) => /* @__PURE__ */ jsx2("div", { className: "grid min-w-0 gap-4 [grid-template-columns:repeat(auto-fit,minmax(12rem,1fr))]", children: ctx.children(c.children) })
268
+ };
269
+ var text = {
270
+ check: (c) => first(allowKeys(c, ["text", "variant"]), checkText(c.text, "text", true), checkEnum(c.variant, "variant", VARIANTS)),
271
+ render: (c, ctx) => {
272
+ const value = asText(ctx.resolve(c.text));
273
+ if (c.variant === "heading") return /* @__PURE__ */ jsx2("h3", { className: "text-base font-semibold text-fg", children: value });
274
+ if (c.variant === "caption") return /* @__PURE__ */ jsx2("p", { className: "text-xs text-fg-muted", children: value });
275
+ return /* @__PURE__ */ jsx2("p", { className: "text-sm text-fg", children: value });
276
+ }
277
+ };
278
+ var card = {
279
+ check: (c) => first(allowKeys(c, ["title", "child"]), checkText(c.title, "title", false), c.child === void 0 ? null : checkId(c.child, "child")),
280
+ render: (c, ctx) => /* @__PURE__ */ jsx2(CardRoot, { children: /* @__PURE__ */ jsxs2(CardBody, { children: [
281
+ c.title !== void 0 && /* @__PURE__ */ jsx2(CardTitle, { children: asText(ctx.resolve(c.title)) }),
282
+ c.child !== void 0 && /* @__PURE__ */ jsx2("div", { className: "mt-3", children: ctx.child(c.child) })
283
+ ] }) })
284
+ };
285
+ var callout = {
286
+ check: (c) => first(allowKeys(c, ["tone", "title", "text"]), checkEnum(c.tone, "tone", TONES), checkText(c.title, "title", false), checkText(c.text, "text", false)),
287
+ render: (c, ctx) => /* @__PURE__ */ jsx2(Alert, { tone: c.tone ?? "info", title: c.title === void 0 ? void 0 : asText(ctx.resolve(c.title)), children: c.text === void 0 ? void 0 : asText(ctx.resolve(c.text)) })
288
+ };
289
+ function checkColumns(value) {
290
+ if (!Array.isArray(value) || value.length === 0 || value.length > 12) return "columns is an array of 1 to 12";
291
+ for (const raw of value) {
292
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return "a column is an object";
293
+ const col = raw;
294
+ const keys = Object.keys(col).find((k) => !["key", "label", "format", "currency"].includes(k));
295
+ if (keys) return `a column has no key "${keys}"`;
296
+ if (typeof col.key !== "string" || !/^[A-Za-z0-9_]{1,64}$/.test(col.key)) return "a column key is 1-64 characters of [A-Za-z0-9_]";
297
+ if (typeof col.label !== "string" || col.label.length > 120) return "a column label is a string";
298
+ const problem = first(checkEnum(col.format, "format", GENUI_FORMATS), checkCurrency(col.currency, col.format === "money"));
299
+ if (problem) return problem;
300
+ }
301
+ return null;
302
+ }
303
+ function TableView({ c, ctx }) {
304
+ const columns = c.columns;
305
+ const raw = ctx.resolve(c.rows);
306
+ const rows = Array.isArray(raw) ? raw.slice(0, GENUI_LIMITS.array).flatMap((r, i) => r !== null && typeof r === "object" && !Array.isArray(r) ? [{ ...r, __genuiRow: String(i) }] : []) : [];
307
+ const cols = columns.map((col) => ({
308
+ id: col.key,
309
+ header: col.label,
310
+ sortable: true,
311
+ type: col.format ? "number" : "text",
312
+ value: (r) => {
313
+ const v = r[col.key];
314
+ return typeof v === "number" || typeof v === "string" ? v : null;
315
+ },
316
+ cell: (r) => formatGenUiValue(r[col.key], col.format, ctx.locale, col.currency)
317
+ }));
318
+ if (rows.length === 0) return /* @__PURE__ */ jsx2("p", { className: "text-sm text-fg-muted", children: ctx.labels.noData });
319
+ return /* @__PURE__ */ jsx2(DataTable, { rows, columns: cols, getRowId: (r) => r.__genuiRow, caption: c.caption === void 0 ? ctx.labels.surface : asText(ctx.resolve(c.caption)), showCaption: c.caption !== void 0 });
320
+ }
321
+ var table = {
322
+ check: (c) => first(allowKeys(c, ["caption", "columns", "rows"]), checkText(c.caption, "caption", false), checkColumns(c.columns), checkBinding(c.rows, "rows")),
323
+ render: (c, ctx) => /* @__PURE__ */ jsx2(TableView, { c, ctx })
324
+ };
325
+ var baseGenUiCatalog = { Column: column, Row: row, Text: text, Card: card, Callout: callout, Table: table };
326
+
327
+ // src/genui/store.ts
328
+ var emptyGenUiState = { surfaces: /* @__PURE__ */ new Map(), order: [], errors: [] };
329
+ var withError = (state, error) => ({ ...state, errors: [...state.errors, error] });
330
+ function setAt(root, segments, value, remove) {
331
+ if (segments.length === 0) return remove ? /* @__PURE__ */ Object.create(null) : value;
332
+ const [head, ...rest] = segments;
333
+ if (Array.isArray(root)) {
334
+ const index = Number(head);
335
+ if (!Number.isInteger(index) || index < 0 || index > root.length || index >= GENUI_LIMITS.array) return root;
336
+ const copy = [...root];
337
+ if (remove && rest.length === 0) copy.splice(index, 1);
338
+ else copy[index] = setAt(root[index], rest, value, remove);
339
+ return copy;
340
+ }
341
+ const base = Object.assign(/* @__PURE__ */ Object.create(null), root !== null && typeof root === "object" ? root : {});
342
+ if (remove && rest.length === 0) delete base[head];
343
+ else base[head] = setAt(base[head], rest, value, remove);
344
+ return base;
345
+ }
346
+ function readPath(data, path) {
347
+ const parsed = parsePath(path);
348
+ if (!parsed.ok) return void 0;
349
+ let cursor = data;
350
+ for (const segment of parsed.value) {
351
+ if (cursor === null || typeof cursor !== "object") return void 0;
352
+ if (!Object.hasOwn(cursor, segment)) return void 0;
353
+ cursor = cursor[segment];
354
+ }
355
+ return cursor;
356
+ }
357
+ function applyMessage(state, message) {
358
+ if ("createSurface" in message) {
359
+ const { surfaceId: surfaceId2 } = message.createSurface;
360
+ if (state.surfaces.has(surfaceId2)) return withError(state, `surface "${surfaceId2}" already exists`);
361
+ const surfaces2 = new Map(state.surfaces);
362
+ surfaces2.set(surfaceId2, { id: surfaceId2, components: /* @__PURE__ */ new Map(), data: /* @__PURE__ */ Object.create(null) });
363
+ return { ...state, surfaces: surfaces2, order: [...state.order, surfaceId2] };
364
+ }
365
+ if ("deleteSurface" in message) {
366
+ const surfaces2 = new Map(state.surfaces);
367
+ surfaces2.delete(message.deleteSurface.surfaceId);
368
+ return { ...state, surfaces: surfaces2, order: state.order.filter((id) => id !== message.deleteSurface.surfaceId) };
369
+ }
370
+ const surfaceId = "updateComponents" in message ? message.updateComponents.surfaceId : message.updateDataModel.surfaceId;
371
+ const surface = state.surfaces.get(surfaceId);
372
+ if (!surface) return withError(state, `surface "${surfaceId}" was not created`);
373
+ const surfaces = new Map(state.surfaces);
374
+ if ("updateComponents" in message) {
375
+ const components = new Map(surface.components);
376
+ for (const component of message.updateComponents.components) components.set(component.id, component);
377
+ if (components.size > GENUI_LIMITS.components) return withError(state, `surface "${surfaceId}" holds more than ${GENUI_LIMITS.components} components`);
378
+ surfaces.set(surfaceId, { ...surface, components });
379
+ } else {
380
+ const { path, value } = message.updateDataModel;
381
+ const parsed = parsePath(path);
382
+ if (!parsed.ok) return withError(state, parsed.error);
383
+ surfaces.set(surfaceId, { ...surface, data: setAt(surface.data, parsed.value, value, !("value" in message.updateDataModel)) });
384
+ }
385
+ return { ...state, surfaces };
386
+ }
387
+ function applyLine(state, line, catalog) {
388
+ const text2 = line.trim();
389
+ if (!text2) return state;
390
+ let json;
391
+ try {
392
+ json = JSON.parse(text2);
393
+ } catch {
394
+ return withError(state, "a line is not JSON");
395
+ }
396
+ const result = validateMessage(json, catalog);
397
+ return result.ok ? applyMessage(state, result.value) : withError(state, result.error);
398
+ }
399
+ var FENCE = /```a2ui[^\n]*\n/;
400
+ function extractGenUi(text2) {
401
+ const open = FENCE.exec(text2);
402
+ if (!open) return { lines: [], closed: false, prose: text2, found: false };
403
+ const start = open.index + open[0].length;
404
+ const end = text2.indexOf("\n```", start - 1);
405
+ const closed = end >= 0;
406
+ const body = closed ? text2.slice(start, end) : text2.slice(start);
407
+ const parts = body.split("\n");
408
+ const lines = closed ? parts : parts.slice(0, -1);
409
+ const after = closed ? text2.slice(end + 4).replace(/^[^\n]*\n?/, "") : "";
410
+ const prose = [text2.slice(0, open.index).trim(), after.trim()].filter(Boolean).join("\n\n");
411
+ return { lines: lines.filter((l) => l.trim()), closed, prose, found: true };
412
+ }
413
+ function readStream(text2, catalog) {
414
+ const { lines, prose, found } = extractGenUi(text2);
415
+ const state = lines.reduce((s, line) => applyLine(s, line, catalog), emptyGenUiState);
416
+ return { ...state, prose, found };
417
+ }
418
+
419
+ // src/genui/surface.tsx
420
+ import * as React from "react";
421
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
422
+ var genUiLabels = { loading: "Building the view\u2026", surface: "Generated view", noData: "No data" };
423
+ function GenUiSurface({ surface, catalog, streaming = false, labels, locale = "en", onError, className }) {
424
+ const words = { ...genUiLabels, ...labels };
425
+ const problems = [];
426
+ const seen = /* @__PURE__ */ new Set();
427
+ const draw = (id, depth) => {
428
+ if (typeof id !== "string") return null;
429
+ if (depth > GENUI_LIMITS.depth) {
430
+ problems.push(`"${id}" is deeper than ${GENUI_LIMITS.depth}`);
431
+ return null;
432
+ }
433
+ if (seen.has(id)) {
434
+ problems.push(`"${id}" is drawn twice (a cycle or two parents)`);
435
+ return null;
436
+ }
437
+ const component = surface.components.get(id);
438
+ if (!component) {
439
+ if (!streaming) problems.push(`"${id}" never arrived`);
440
+ return streaming ? /* @__PURE__ */ jsx3(Skeleton, { className: "h-10 w-full rounded-lg" }, id) : null;
441
+ }
442
+ const entry = Object.hasOwn(catalog, component.component) ? catalog[component.component] : void 0;
443
+ if (!entry) return null;
444
+ seen.add(id);
445
+ const context = {
446
+ child: (c) => draw(c, depth + 1),
447
+ children: (ids) => Array.isArray(ids) ? ids.map((c) => /* @__PURE__ */ jsx3(React.Fragment, { children: draw(c, depth + 1) }, String(c))) : [],
448
+ resolve: (value) => isBinding(value) ? readPath(surface.data, value.path) : value,
449
+ labels: words,
450
+ locale
451
+ };
452
+ return /* @__PURE__ */ jsx3(React.Fragment, { children: entry.render(component, context) }, id);
453
+ };
454
+ const root = draw("root", 0);
455
+ React.useEffect(() => {
456
+ if (onError) for (const problem of problems) onError(problem);
457
+ }, [surface, streaming]);
458
+ return /* @__PURE__ */ jsx3("section", { "aria-label": words.surface, "aria-busy": streaming || void 0, "data-genui-surface": surface.id, className: cn("flex flex-col gap-4", className), children: root ?? (streaming ? /* @__PURE__ */ jsx3(Skeleton, { className: "h-24 w-full rounded-xl" }) : null) });
459
+ }
460
+ function GenUiStream({ text: text2, catalog, streaming, renderProse, fallback, onError, ...rest }) {
461
+ const state = React.useMemo(() => readStream(text2, catalog), [text2, catalog]);
462
+ const reported = React.useRef(0);
463
+ React.useEffect(() => {
464
+ if (!onError) return;
465
+ for (const error of state.errors.slice(reported.current)) onError(error);
466
+ reported.current = state.errors.length;
467
+ }, [state, onError]);
468
+ const prose = (value) => renderProse ? renderProse(value) : value.split(/\n{2,}/).map((p, i) => /* @__PURE__ */ jsx3("p", { children: p }, i));
469
+ const surfaces = state.order.map((id) => state.surfaces.get(id)).filter((s) => !!s && s.components.has("root"));
470
+ if (!state.found || !streaming && surfaces.length === 0) return /* @__PURE__ */ jsx3(Fragment2, { children: fallback ? fallback(text2) : prose(text2) });
471
+ return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-4", "data-genui-stream": "", children: [
472
+ state.prose && prose(state.prose),
473
+ surfaces.map((surface) => /* @__PURE__ */ jsx3(GenUiSurface, { surface, catalog, streaming, onError, ...rest }, surface.id)),
474
+ streaming && surfaces.length === 0 && /* @__PURE__ */ jsx3(Skeleton, { className: "h-24 w-full rounded-xl" })
475
+ ] });
476
+ }
477
+ export {
478
+ GENUI_CATALOG_ID,
479
+ GENUI_FORMATS,
480
+ GENUI_LIMITS,
481
+ GENUI_VERSION,
482
+ GenUiStream,
483
+ GenUiSurface,
484
+ allowKeys,
485
+ applyLine,
486
+ applyMessage,
487
+ baseGenUiCatalog,
488
+ checkBinding,
489
+ checkChildren,
490
+ checkCurrency,
491
+ checkEnum,
492
+ checkId,
493
+ checkNumber,
494
+ checkText,
495
+ emptyGenUiState,
496
+ extractGenUi,
497
+ formatGenUiValue,
498
+ genUiLabels,
499
+ isBinding,
500
+ parsePath,
501
+ readPath,
502
+ readStream,
503
+ sanitizeData,
504
+ validateMessage
505
+ };
506
+ //# sourceMappingURL=genui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/genui/catalog.tsx","../src/alert/alert.tsx","../src/genui/spec.ts","../src/genui/store.ts","../src/genui/surface.tsx"],"sourcesContent":["// The base catalog of `krizaka:genui/v1` (ADR-082): layout, text, card, callout and table — what a model may draw with\n// @krizaka/ui alone. `KpiStat` and `ChartCard` come from @krizaka/charts (`chartsGenUiCatalog`), which depends on this\n// package, never the reverse.\nimport { formatCompact, formatMoney, formatNumber, formatPercent } from \"@krizaka/intl\";\nimport type * as React from \"react\";\n\nimport { Alert } from \"../alert\";\nimport { CardBody, CardRoot, CardTitle } from \"../card\";\nimport { DataTable, type DataTableColumn } from \"../data-table\";\nimport {\n allowKeys,\n checkBinding,\n checkChildren,\n checkCurrency,\n checkEnum,\n checkId,\n checkText,\n GENUI_FORMATS,\n GENUI_LIMITS,\n type GenUiComponent,\n type GenUiFormat,\n} from \"./spec\";\nimport type { GenUiCatalog, GenUiEntry, GenUiRenderContext } from \"./surface\";\n\nconst first = (...problems: (string | null)[]) => problems.find((p) => p !== null) ?? null;\n\n/** A resolved value as text — strings and numbers only; anything else is not drawn. */\nfunction asText(value: unknown): string {\n if (typeof value === \"string\") return value.slice(0, GENUI_LIMITS.string);\n if (typeof value === \"number\" && Number.isFinite(value)) return String(value);\n return \"\";\n}\n\n/** A number written in one of the closed formats. */\nexport function formatGenUiValue(value: unknown, format: GenUiFormat | undefined, locale: string, currency?: string): string {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return asText(value);\n switch (format) {\n case \"integer\":\n return formatNumber(Math.round(value), { locale, maximumFractionDigits: 0 });\n case \"compact\":\n return formatCompact(value, { locale });\n case \"percent\":\n return formatPercent(value, { locale, maximumFractionDigits: 1 });\n case \"money\":\n return currency ? formatMoney(Math.round(value), { currency, locale }) : formatNumber(value, { locale });\n default:\n return formatNumber(value, { locale, maximumFractionDigits: 2 });\n }\n}\n\nconst TONES = [\"info\", \"success\", \"warning\", \"danger\"] as const;\nconst VARIANTS = [\"body\", \"heading\", \"caption\"] as const;\n\nconst column: GenUiEntry = {\n check: (c) => first(allowKeys(c, [\"children\"]), checkChildren(c.children)),\n render: (c, ctx) => <div className=\"flex min-w-0 flex-col gap-4\">{ctx.children(c.children)}</div>,\n};\n\nconst row: GenUiEntry = {\n check: (c) => first(allowKeys(c, [\"children\"]), checkChildren(c.children)),\n render: (c, ctx) => <div className=\"grid min-w-0 gap-4 [grid-template-columns:repeat(auto-fit,minmax(12rem,1fr))]\">{ctx.children(c.children)}</div>,\n};\n\nconst text: GenUiEntry = {\n check: (c) => first(allowKeys(c, [\"text\", \"variant\"]), checkText(c.text, \"text\", true), checkEnum(c.variant, \"variant\", VARIANTS)),\n render: (c, ctx) => {\n const value = asText(ctx.resolve(c.text));\n if (c.variant === \"heading\") return <h3 className=\"text-base font-semibold text-fg\">{value}</h3>;\n if (c.variant === \"caption\") return <p className=\"text-xs text-fg-muted\">{value}</p>;\n return <p className=\"text-sm text-fg\">{value}</p>;\n },\n};\n\nconst card: GenUiEntry = {\n check: (c) => first(allowKeys(c, [\"title\", \"child\"]), checkText(c.title, \"title\", false), c.child === undefined ? null : checkId(c.child, \"child\")),\n render: (c, ctx) => (\n <CardRoot>\n <CardBody>\n {c.title !== undefined && <CardTitle>{asText(ctx.resolve(c.title))}</CardTitle>}\n {c.child !== undefined && <div className=\"mt-3\">{ctx.child(c.child)}</div>}\n </CardBody>\n </CardRoot>\n ),\n};\n\nconst callout: GenUiEntry = {\n check: (c) => first(allowKeys(c, [\"tone\", \"title\", \"text\"]), checkEnum(c.tone, \"tone\", TONES), checkText(c.title, \"title\", false), checkText(c.text, \"text\", false)),\n render: (c, ctx) => (\n <Alert tone={(c.tone as (typeof TONES)[number] | undefined) ?? \"info\"} title={c.title === undefined ? undefined : asText(ctx.resolve(c.title))}>\n {c.text === undefined ? undefined : asText(ctx.resolve(c.text))}\n </Alert>\n ),\n};\n\ntype Column = { key: string; label: string; format?: GenUiFormat; currency?: string };\n\nfunction checkColumns(value: unknown): string | null {\n if (!Array.isArray(value) || value.length === 0 || value.length > 12) return \"columns is an array of 1 to 12\";\n for (const raw of value) {\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return \"a column is an object\";\n const col = raw as Record<string, unknown>;\n const keys = Object.keys(col).find((k) => ![\"key\", \"label\", \"format\", \"currency\"].includes(k));\n if (keys) return `a column has no key \"${keys}\"`;\n if (typeof col.key !== \"string\" || !/^[A-Za-z0-9_]{1,64}$/.test(col.key)) return \"a column key is 1-64 characters of [A-Za-z0-9_]\";\n if (typeof col.label !== \"string\" || col.label.length > 120) return \"a column label is a string\";\n const problem = first(checkEnum(col.format, \"format\", GENUI_FORMATS), checkCurrency(col.currency, col.format === \"money\"));\n if (problem) return problem;\n }\n return null;\n}\n\ntype Row = Record<string, unknown> & { __genuiRow: string };\n\nfunction TableView({ c, ctx }: { c: GenUiComponent; ctx: GenUiRenderContext }) {\n const columns = c.columns as readonly Column[];\n const raw = ctx.resolve(c.rows);\n const rows: Row[] = Array.isArray(raw)\n ? raw.slice(0, GENUI_LIMITS.array).flatMap((r, i) => (r !== null && typeof r === \"object\" && !Array.isArray(r) ? [{ ...(r as Record<string, unknown>), __genuiRow: String(i) }] : []))\n : [];\n const cols: DataTableColumn<Row>[] = columns.map((col) => ({\n id: col.key,\n header: col.label,\n sortable: true,\n type: col.format ? \"number\" : \"text\",\n value: (r) => {\n const v = r[col.key];\n return typeof v === \"number\" || typeof v === \"string\" ? v : null;\n },\n cell: (r) => formatGenUiValue(r[col.key], col.format, ctx.locale, col.currency),\n }));\n if (rows.length === 0) return <p className=\"text-sm text-fg-muted\">{ctx.labels.noData}</p>;\n return <DataTable rows={rows} columns={cols} getRowId={(r) => r.__genuiRow} caption={c.caption === undefined ? ctx.labels.surface : asText(ctx.resolve(c.caption))} showCaption={c.caption !== undefined} />;\n}\n\nconst table: GenUiEntry = {\n check: (c) => first(allowKeys(c, [\"caption\", \"columns\", \"rows\"]), checkText(c.caption, \"caption\", false), checkColumns(c.columns), checkBinding(c.rows, \"rows\")),\n render: (c, ctx): React.ReactNode => <TableView c={c} ctx={ctx} />,\n};\n\n/** `Column`, `Row`, `Text`, `Card`, `Callout`, `Table` — the catalog @krizaka/ui draws on its own. */\nexport const baseGenUiCatalog: GenUiCatalog = { Column: column, Row: row, Text: text, Card: card, Callout: callout, Table: table };\n","// Server-safe. A message in the flow of the page (not a toast): a tone, an icon, a title, a text, an action.\n// danger and warning are announced at once (role=\"alert\"); info and success politely (role=\"status\").\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\n// Soft tones (a tint, a tinted border, a coloured icon): the text stays a text role — the invariant status tokens are\n// too light for small text on a light surface (WCAG AA).\nexport const alertVariants = tv({\n slots: {\n root: \"relative flex w-full items-start gap-3 rounded-xl border p-4 text-sm text-fg\",\n icon: \"mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n content: \"flex min-w-0 flex-1 flex-col gap-1\",\n title: \"font-semibold text-fg\",\n description: \"text-fg-secondary\",\n action: \"flex shrink-0 items-center gap-2 self-center\",\n },\n variants: {\n tone: {\n info: { root: \"border-info/40 bg-info/10\", icon: \"text-info\" },\n success: { root: \"border-success/40 bg-success/10\", icon: \"text-success\" },\n warning: { root: \"border-warning/50 bg-warning/10\", icon: \"text-warning\" },\n danger: { root: \"border-danger/50 bg-danger/10\", icon: \"text-danger\" },\n },\n },\n defaultVariants: { tone: \"info\" },\n});\n\nexport type AlertTone = NonNullable<VariantProps<typeof alertVariants>[\"tone\"]>;\n\nexport type AlertProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The tone: `danger` and `warning` are announced at once (`role=\"alert\"`), `info` and `success` politely. */\n tone?: AlertTone;\n /** A decorative icon (hidden from assistive technology). */\n icon?: React.ReactNode;\n /** The headline, in bold above the text. */\n title?: React.ReactNode;\n /** What to do: a Button, a link. */\n action?: React.ReactNode;\n};\n\nexport function Alert({ tone = \"info\", icon, title, action, className, children, ...props }: AlertProps) {\n const s = alertVariants({ tone });\n return (\n <div role={tone === \"danger\" || tone === \"warning\" ? \"alert\" : \"status\"} data-tone={tone} className={s.root({ className })} {...props}>\n {icon && (\n <span aria-hidden className={s.icon()}>\n {icon}\n </span>\n )}\n <div className={s.content()}>\n {title && <p className={s.title()}>{title}</p>}\n {children && <div className={s.description()}>{children}</div>}\n </div>\n {action && <div className={s.action()}>{action}</div>}\n </div>\n );\n}\n","// The data-driven UI spec: a strict subset of A2UI v0.9 (ADR-082, krizaka/orazaka-packs). A model describes an interface\n// as data — never code — and only with the components of a catalog the client declares. Everything here is a pure\n// function over JSON: parse, validate, apply. Nothing is evaluated, nothing is trusted.\n\n/** The protocol version every message carries. */\nexport const GENUI_VERSION = \"v0.9\";\n\n/** The catalog a surface must name: the Krizaka components, version 1. */\nexport const GENUI_CATALOG_ID = \"krizaka:genui/v1\";\n\n/** The bounds of a surface — what a model may ask for, at most. */\nexport const GENUI_LIMITS = {\n /** Components per surface. */\n components: 300,\n /** Nesting depth from the root. */\n depth: 12,\n /** Characters in one string. */\n string: 4000,\n /** Items in one array of the data model. */\n array: 1000,\n /** Nesting depth of a data model value. */\n dataDepth: 12,\n /** Values (objects, arrays, scalars) in one data model update. */\n dataNodes: 50_000,\n /** Segments of a data path. */\n pathSegments: 16,\n} as const;\n\n/** One component as the model writes it: an id, the catalog name, its properties. */\nexport type GenUiComponent = { readonly id: string; readonly component: string } & Readonly<Record<string, unknown>>;\n\n/** A value bound to the data model: `{ \"path\": \"/rows\" }`. */\nexport type GenUiBinding = { readonly path: string };\n\n/** The four messages of A2UI v0.9. */\nexport type GenUiMessage =\n | { readonly version: typeof GENUI_VERSION; readonly createSurface: { readonly surfaceId: string; readonly catalogId: string } }\n | { readonly version: typeof GENUI_VERSION; readonly updateComponents: { readonly surfaceId: string; readonly components: readonly GenUiComponent[] } }\n | { readonly version: typeof GENUI_VERSION; readonly updateDataModel: { readonly surfaceId: string; readonly path: string; readonly value?: unknown } }\n | { readonly version: typeof GENUI_VERSION; readonly deleteSurface: { readonly surfaceId: string } };\n\n/** What validating a message says. */\nexport type GenUiResult<T> = { readonly ok: true; readonly value: T } | { readonly ok: false; readonly error: string };\n\n/** How a catalog entry checks a component's own properties: `null` when they are fine, else why not. */\nexport type GenUiPropsCheck = (component: GenUiComponent) => string | null;\n\nconst ID = /^[A-Za-z0-9_-]{1,64}$/;\nconst MESSAGE_KEYS = [\"createSurface\", \"updateComponents\", \"updateDataModel\", \"deleteSurface\"] as const;\nconst FORBIDDEN_SEGMENTS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\nconst fail = (error: string): { ok: false; error: string } => ({ ok: false, error });\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction onlyKeys(value: Record<string, unknown>, allowed: readonly string[], where: string): string | null {\n for (const key of Object.keys(value)) if (!allowed.includes(key)) return `${where}: unknown key \"${key}\"`;\n return null;\n}\n\n/** An id of a surface or a component, or why not. */\nexport function checkId(value: unknown, where: string): string | null {\n return typeof value === \"string\" && ID.test(value) ? null : `${where}: an id is 1-64 characters of [A-Za-z0-9_-]`;\n}\n\n/** The segments of a JSON pointer (`/a/b/0`), or why it is refused — `__proto__` and friends never pass. */\nexport function parsePath(path: unknown): GenUiResult<readonly string[]> {\n if (typeof path !== \"string\" || (path !== \"/\" && !path.startsWith(\"/\")) || path.length > 512) return fail(\"a path is a JSON pointer: /a/b\");\n if (path === \"/\") return { ok: true, value: [] };\n const segments = path\n .slice(1)\n .split(\"/\")\n .map((s) => s.replace(/~1/g, \"/\").replace(/~0/g, \"~\"));\n if (segments.length > GENUI_LIMITS.pathSegments) return fail(`a path has at most ${GENUI_LIMITS.pathSegments} segments`);\n for (const s of segments) {\n if (s === \"\" || FORBIDDEN_SEGMENTS.has(s)) return fail(`a path may not hold the segment \"${s}\"`);\n }\n return { ok: true, value: segments };\n}\n\n/** `true` when the value is a binding `{ path }` (and only that). */\nexport function isBinding(value: unknown): value is GenUiBinding {\n return isPlainObject(value) && Object.keys(value).length === 1 && typeof value.path === \"string\";\n}\n\n/**\n * A copy of a data model value that is plain JSON within the limits — strings, finite numbers, booleans, null, arrays\n * and plain objects — or why it is refused. The copy has a null prototype for every object: nothing it holds can\n * reach `Object.prototype`.\n */\nexport function sanitizeData(value: unknown): GenUiResult<unknown> {\n let nodes = 0;\n const walk = (v: unknown, depth: number): GenUiResult<unknown> => {\n if (++nodes > GENUI_LIMITS.dataNodes) return fail(`the data holds more than ${GENUI_LIMITS.dataNodes} values`);\n if (depth > GENUI_LIMITS.dataDepth) return fail(`the data nests deeper than ${GENUI_LIMITS.dataDepth}`);\n if (v === null || typeof v === \"boolean\") return { ok: true, value: v };\n if (typeof v === \"number\") return Number.isFinite(v) ? { ok: true, value: v } : fail(\"a number must be finite\");\n if (typeof v === \"string\") return v.length <= GENUI_LIMITS.string ? { ok: true, value: v } : fail(`a string has at most ${GENUI_LIMITS.string} characters`);\n if (Array.isArray(v)) {\n if (v.length > GENUI_LIMITS.array) return fail(`an array has at most ${GENUI_LIMITS.array} items`);\n const out: unknown[] = [];\n for (const item of v) {\n const r = walk(item, depth + 1);\n if (!r.ok) return r;\n out.push(r.value);\n }\n return { ok: true, value: out };\n }\n if (isPlainObject(v)) {\n const out: Record<string, unknown> = Object.create(null);\n for (const [key, item] of Object.entries(v)) {\n if (FORBIDDEN_SEGMENTS.has(key)) return fail(`a key may not be \"${key}\"`);\n const r = walk(item, depth + 1);\n if (!r.ok) return r;\n out[key] = r.value;\n }\n return { ok: true, value: out };\n }\n return fail(\"the data is plain JSON only\");\n };\n return walk(value, 0);\n}\n\n/**\n * A message as the model sent it — parsed and checked against the spec and the catalog, or why it is refused. A\n * component's own properties are checked by its catalog entry; a component the catalog does not hold is refused.\n */\nexport function validateMessage(input: unknown, catalog: Readonly<Record<string, { readonly check: GenUiPropsCheck }>>): GenUiResult<GenUiMessage> {\n if (!isPlainObject(input)) return fail(\"a message is a JSON object\");\n if (input.version !== GENUI_VERSION) return fail(`version must be \"${GENUI_VERSION}\"`);\n const present = MESSAGE_KEYS.filter((k) => k in input);\n if (present.length !== 1) return fail(\"a message holds exactly one of createSurface, updateComponents, updateDataModel, deleteSurface\");\n const kind = present[0];\n const extra = onlyKeys(input, [\"version\", kind], \"message\");\n if (extra) return fail(extra);\n const body = input[kind];\n if (!isPlainObject(body)) return fail(`${kind} is an object`);\n const surface = checkId(body.surfaceId, `${kind}.surfaceId`);\n if (surface) return fail(surface);\n\n switch (kind) {\n case \"createSurface\": {\n const keys = onlyKeys(body, [\"surfaceId\", \"catalogId\", \"theme\", \"sendDataModel\"], kind);\n if (keys) return fail(keys);\n if (body.catalogId !== GENUI_CATALOG_ID) return fail(`catalogId must be \"${GENUI_CATALOG_ID}\"`);\n return { ok: true, value: { version: GENUI_VERSION, createSurface: { surfaceId: body.surfaceId as string, catalogId: GENUI_CATALOG_ID } } };\n }\n case \"updateComponents\": {\n const keys = onlyKeys(body, [\"surfaceId\", \"components\"], kind);\n if (keys) return fail(keys);\n if (!Array.isArray(body.components) || body.components.length > GENUI_LIMITS.components) {\n return fail(`components is an array of at most ${GENUI_LIMITS.components}`);\n }\n const components: GenUiComponent[] = [];\n for (const raw of body.components) {\n if (!isPlainObject(raw)) return fail(\"a component is an object\");\n const id = checkId(raw.id, \"component.id\");\n if (id) return fail(id);\n if (typeof raw.component !== \"string\" || !Object.hasOwn(catalog, raw.component)) {\n return fail(`component \"${String(raw.id)}\": \"${String(raw.component)}\" is not in the catalog`);\n }\n const clean = sanitizeData(raw);\n if (!clean.ok) return fail(`component \"${raw.id}\": ${clean.error}`);\n const component = { ...(clean.value as Record<string, unknown>) } as GenUiComponent;\n const problem = catalog[raw.component].check(component);\n if (problem) return fail(`component \"${raw.id}\" (${raw.component}): ${problem}`);\n components.push(component);\n }\n return { ok: true, value: { version: GENUI_VERSION, updateComponents: { surfaceId: body.surfaceId as string, components } } };\n }\n case \"updateDataModel\": {\n const keys = onlyKeys(body, [\"surfaceId\", \"path\", \"value\"], kind);\n if (keys) return fail(keys);\n const path = body.path === undefined ? \"/\" : body.path;\n const parsed = parsePath(path);\n if (!parsed.ok) return parsed;\n if (!(\"value\" in body)) return { ok: true, value: { version: GENUI_VERSION, updateDataModel: { surfaceId: body.surfaceId as string, path: path as string } } };\n const clean = sanitizeData(body.value);\n if (!clean.ok) return clean;\n return { ok: true, value: { version: GENUI_VERSION, updateDataModel: { surfaceId: body.surfaceId as string, path: path as string, value: clean.value } } };\n }\n default: {\n const keys = onlyKeys(body, [\"surfaceId\"], kind);\n if (keys) return fail(keys);\n return { ok: true, value: { version: GENUI_VERSION, deleteSurface: { surfaceId: body.surfaceId as string } } };\n }\n }\n}\n\n// ── checks the catalog entries share ─────────────────────────────────────────────────────────────────────────────\n\n/** Why the component's keys are refused, or null: only `id`, `component` and the entry's own keys. */\nexport function allowKeys(component: GenUiComponent, keys: readonly string[]): string | null {\n return onlyKeys(component, [\"id\", \"component\", ...keys], \"properties\");\n}\n\n/** A short text (or a binding to one), required or not. */\nexport function checkText(value: unknown, name: string, required: boolean): string | null {\n if (value === undefined) return required ? `${name} is required` : null;\n if (isBinding(value)) return parsePath(value.path).ok ? null : `${name}: a bad path`;\n return typeof value === \"string\" ? null : `${name} is a string`;\n}\n\n/** A value among a closed list. */\nexport function checkEnum(value: unknown, name: string, allowed: readonly string[], required = false): string | null {\n if (value === undefined) return required ? `${name} is required` : null;\n return typeof value === \"string\" && allowed.includes(value) ? null : `${name} is one of ${allowed.join(\", \")}`;\n}\n\n/** A list of child ids. */\nexport function checkChildren(value: unknown, name = \"children\"): string | null {\n if (!Array.isArray(value) || value.length > GENUI_LIMITS.components) return `${name} is an array of component ids`;\n for (const id of value) if (checkId(id, name)) return `${name} holds ids only`;\n return null;\n}\n\n/** A binding to the data model (required). */\nexport function checkBinding(value: unknown, name: string): string | null {\n if (!isBinding(value)) return `${name} is a binding { \"path\": \"/…\" }`;\n return parsePath(value.path).ok ? null : `${name}: a bad path`;\n}\n\n/** A number, or a binding to one. */\nexport function checkNumber(value: unknown, name: string, required: boolean): string | null {\n if (value === undefined) return required ? `${name} is required` : null;\n if (isBinding(value)) return parsePath(value.path).ok ? null : `${name}: a bad path`;\n return typeof value === \"number\" && Number.isFinite(value) ? null : `${name} is a number`;\n}\n\n/** The value formats a model may name. */\nexport const GENUI_FORMATS = [\"number\", \"integer\", \"compact\", \"percent\", \"money\"] as const;\nexport type GenUiFormat = (typeof GENUI_FORMATS)[number];\n\n/** A three-letter currency code. */\nexport function checkCurrency(value: unknown, required: boolean): string | null {\n if (value === undefined) return required ? \"currency is required with the money format\" : null;\n return typeof value === \"string\" && /^[A-Z]{3}$/.test(value) ? null : \"currency is a three-letter code (CAD)\";\n}\n","// The surfaces a stream of A2UI messages builds — pure: `applyMessage` returns a new state, `readStream` turns a growing\n// text (a model's answer as it arrives) into the messages it holds so far. Nothing here renders.\nimport { GENUI_LIMITS, type GenUiComponent, type GenUiMessage, type GenUiPropsCheck, parsePath, validateMessage } from \"./spec\";\n\n/** One surface: its components by id, and its data model. */\nexport type GenUiSurfaceState = {\n readonly id: string;\n readonly components: ReadonlyMap<string, GenUiComponent>;\n readonly data: unknown;\n};\n\n/** Every surface of a stream, and what was refused on the way. */\nexport type GenUiState = {\n readonly surfaces: ReadonlyMap<string, GenUiSurfaceState>;\n /** The order surfaces were created in. */\n readonly order: readonly string[];\n /** Why messages were dropped, in order (a dropped message leaves the rest of the surface as it was). */\n readonly errors: readonly string[];\n};\n\nexport const emptyGenUiState: GenUiState = { surfaces: new Map(), order: [], errors: [] };\n\nconst withError = (state: GenUiState, error: string): GenUiState => ({ ...state, errors: [...state.errors, error] });\n\nfunction setAt(root: unknown, segments: readonly string[], value: unknown, remove: boolean): unknown {\n if (segments.length === 0) return remove ? Object.create(null) : value;\n const [head, ...rest] = segments;\n if (Array.isArray(root)) {\n const index = Number(head);\n if (!Number.isInteger(index) || index < 0 || index > root.length || index >= GENUI_LIMITS.array) return root;\n const copy = [...root];\n if (remove && rest.length === 0) copy.splice(index, 1);\n else copy[index] = setAt(root[index], rest, value, remove);\n return copy;\n }\n const base: Record<string, unknown> = Object.assign(Object.create(null), root !== null && typeof root === \"object\" ? root : {});\n if (remove && rest.length === 0) delete base[head];\n else base[head] = setAt(base[head], rest, value, remove);\n return base;\n}\n\n/** The value at a JSON pointer of the data model, `undefined` when there is none. */\nexport function readPath(data: unknown, path: string): unknown {\n const parsed = parsePath(path);\n if (!parsed.ok) return undefined;\n let cursor: unknown = data;\n for (const segment of parsed.value) {\n if (cursor === null || typeof cursor !== \"object\") return undefined;\n if (!Object.hasOwn(cursor, segment)) return undefined;\n cursor = (cursor as Record<string, unknown>)[segment];\n }\n return cursor;\n}\n\n/** The state after one validated message. */\nexport function applyMessage(state: GenUiState, message: GenUiMessage): GenUiState {\n if (\"createSurface\" in message) {\n const { surfaceId } = message.createSurface;\n if (state.surfaces.has(surfaceId)) return withError(state, `surface \"${surfaceId}\" already exists`);\n const surfaces = new Map(state.surfaces);\n surfaces.set(surfaceId, { id: surfaceId, components: new Map(), data: Object.create(null) });\n return { ...state, surfaces, order: [...state.order, surfaceId] };\n }\n if (\"deleteSurface\" in message) {\n const surfaces = new Map(state.surfaces);\n surfaces.delete(message.deleteSurface.surfaceId);\n return { ...state, surfaces, order: state.order.filter((id) => id !== message.deleteSurface.surfaceId) };\n }\n const surfaceId = \"updateComponents\" in message ? message.updateComponents.surfaceId : message.updateDataModel.surfaceId;\n const surface = state.surfaces.get(surfaceId);\n if (!surface) return withError(state, `surface \"${surfaceId}\" was not created`);\n const surfaces = new Map(state.surfaces);\n if (\"updateComponents\" in message) {\n const components = new Map(surface.components);\n for (const component of message.updateComponents.components) components.set(component.id, component);\n if (components.size > GENUI_LIMITS.components) return withError(state, `surface \"${surfaceId}\" holds more than ${GENUI_LIMITS.components} components`);\n surfaces.set(surfaceId, { ...surface, components });\n } else {\n const { path, value } = message.updateDataModel;\n const parsed = parsePath(path);\n if (!parsed.ok) return withError(state, parsed.error);\n surfaces.set(surfaceId, { ...surface, data: setAt(surface.data, parsed.value, value, !(\"value\" in message.updateDataModel)) });\n }\n return { ...state, surfaces };\n}\n\n/** The state after a line of JSON (one message), the line refused with its reason when it is not valid. */\nexport function applyLine(state: GenUiState, line: string, catalog: Readonly<Record<string, { readonly check: GenUiPropsCheck }>>): GenUiState {\n const text = line.trim();\n if (!text) return state;\n let json: unknown;\n try {\n json = JSON.parse(text);\n } catch {\n return withError(state, \"a line is not JSON\");\n }\n const result = validateMessage(json, catalog);\n return result.ok ? applyMessage(state, result.value) : withError(state, result.error);\n}\n\n/** Where a fenced `a2ui` block sits in a text: its JSON Lines so far, whether it is closed, and the prose around it. */\nexport type GenUiExtract = { readonly lines: readonly string[]; readonly closed: boolean; readonly prose: string; readonly found: boolean };\n\nconst FENCE = /```a2ui[^\\n]*\\n/;\n\n/**\n * Splits a model's answer — complete or still arriving — into its prose and the complete lines of its `a2ui` fence.\n * A line still being written (no newline yet, the fence open) is left for the next call: the surface grows message by\n * message as the answer streams.\n */\nexport function extractGenUi(text: string): GenUiExtract {\n const open = FENCE.exec(text);\n if (!open) return { lines: [], closed: false, prose: text, found: false };\n const start = open.index + open[0].length;\n const end = text.indexOf(\"\\n```\", start - 1);\n const closed = end >= 0;\n const body = closed ? text.slice(start, end) : text.slice(start);\n const parts = body.split(\"\\n\");\n const lines = closed ? parts : parts.slice(0, -1);\n const after = closed ? text.slice(end + 4).replace(/^[^\\n]*\\n?/, \"\") : \"\";\n const prose = [text.slice(0, open.index).trim(), after.trim()].filter(Boolean).join(\"\\n\\n\");\n return { lines: lines.filter((l) => l.trim()), closed, prose, found: true };\n}\n\n/** The state of every surface a model's answer describes so far. */\nexport function readStream(text: string, catalog: Readonly<Record<string, { readonly check: GenUiPropsCheck }>>): GenUiState & { readonly prose: string; readonly found: boolean } {\n const { lines, prose, found } = extractGenUi(text);\n const state = lines.reduce((s, line) => applyLine(s, line, catalog), emptyGenUiState);\n return { ...state, prose, found };\n}\n","// Renders a surface from its root: each component through its catalog entry, children by id, bound values from the data\n// model. A tree only — a component met twice (a cycle, two parents) or beyond the depth is not drawn — and a child still\n// to come (the answer is streaming) is a skeleton. Text is text: React escapes it, nothing is ever parsed as HTML.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { Skeleton } from \"../skeleton\";\nimport { GENUI_LIMITS, type GenUiComponent, type GenUiPropsCheck, isBinding } from \"./spec\";\nimport { type GenUiState, type GenUiSurfaceState, readPath, readStream } from \"./store\";\n\n/** What an entry gets to draw a component. */\nexport type GenUiRenderContext = {\n /** A child by id: drawn, a skeleton while it has not arrived, nothing when refused. */\n child: (id: unknown) => React.ReactNode;\n /** Children by id, in order. */\n children: (ids: unknown) => React.ReactNode[];\n /** A literal, or the value a binding `{ path }` points at in the data model. */\n resolve: (value: unknown) => unknown;\n /** The words of the surface. */\n labels: GenUiLabels;\n /** The locale numbers and dates are written in. */\n locale: string;\n};\n\n/** One component of a catalog: how its properties are checked, how it is drawn. */\nexport type GenUiEntry = {\n /** `null` when the component's own properties are fine, else why not (the message is refused). */\n readonly check: GenUiPropsCheck;\n /** Draws the component. */\n readonly render: (component: GenUiComponent, context: GenUiRenderContext) => React.ReactNode;\n};\n\n/** The components a model may use, by name: `baseGenUiCatalog`, merged with `chartsGenUiCatalog` of @krizaka/charts. */\nexport type GenUiCatalog = Readonly<Record<string, GenUiEntry>>;\n\n/** The surface's own words (passed translated). */\nexport type GenUiLabels = {\n /** Announced while the surface is still arriving. */\n loading: string;\n /** The accessible name of the surface. */\n surface: string;\n /** Under a table whose data has not arrived or is not a list. */\n noData: string;\n};\n\nexport const genUiLabels: GenUiLabels = { loading: \"Building the view…\", surface: \"Generated view\", noData: \"No data\" };\n\nexport type GenUiSurfaceProps = {\n /** The surface to draw (from `readStream` or `applyMessage`). */\n surface: GenUiSurfaceState;\n /** The components it may use. */\n catalog: GenUiCatalog;\n /** The answer is still arriving: missing children are skeletons and the surface is busy. */\n streaming?: boolean;\n /** The surface's words. */\n labels?: Partial<GenUiLabels>;\n /** The locale numbers are written in. Default `en`. */\n locale?: string;\n /** Called with what could not be drawn (a cycle, a missing child once the answer is complete). */\n onError?: (error: string) => void;\n /** Extra classes on the frame. */\n className?: string;\n};\n\n/** One surface, drawn from its root. */\nexport function GenUiSurface({ surface, catalog, streaming = false, labels, locale = \"en\", onError, className }: GenUiSurfaceProps) {\n const words = { ...genUiLabels, ...labels };\n const problems: string[] = [];\n const seen = new Set<string>();\n\n const draw = (id: unknown, depth: number): React.ReactNode => {\n if (typeof id !== \"string\") return null;\n if (depth > GENUI_LIMITS.depth) {\n problems.push(`\"${id}\" is deeper than ${GENUI_LIMITS.depth}`);\n return null;\n }\n if (seen.has(id)) {\n problems.push(`\"${id}\" is drawn twice (a cycle or two parents)`);\n return null;\n }\n const component = surface.components.get(id);\n if (!component) {\n if (!streaming) problems.push(`\"${id}\" never arrived`);\n return streaming ? <Skeleton key={id} className=\"h-10 w-full rounded-lg\" /> : null;\n }\n const entry = Object.hasOwn(catalog, component.component) ? catalog[component.component] : undefined;\n if (!entry) return null;\n seen.add(id);\n const context: GenUiRenderContext = {\n child: (c) => draw(c, depth + 1),\n children: (ids) => (Array.isArray(ids) ? ids.map((c) => <React.Fragment key={String(c)}>{draw(c, depth + 1)}</React.Fragment>) : []),\n resolve: (value) => (isBinding(value) ? readPath(surface.data, value.path) : value),\n labels: words,\n locale,\n };\n return <React.Fragment key={id}>{entry.render(component, context)}</React.Fragment>;\n };\n\n const root = draw(\"root\", 0);\n React.useEffect(() => {\n if (onError) for (const problem of problems) onError(problem);\n // Reported once per drawn state.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [surface, streaming]);\n\n return (\n <section aria-label={words.surface} aria-busy={streaming || undefined} data-genui-surface={surface.id} className={cn(\"flex flex-col gap-4\", className)}>\n {root ?? (streaming ? <Skeleton className=\"h-24 w-full rounded-xl\" /> : null)}\n </section>\n );\n}\n\nexport type GenUiStreamProps = Omit<GenUiSurfaceProps, \"surface\"> & {\n /** A model's answer, complete or still arriving: its prose and its `a2ui` fence. */\n text: string;\n /** Draws the prose (markdown in a chat); default: paragraphs of text. */\n renderProse?: (prose: string) => React.ReactNode;\n /** What to show when the answer holds no valid surface: the answer itself, as text (the fallback). */\n fallback?: (text: string) => React.ReactNode;\n};\n\n/**\n * A model's answer with its generated view: the prose, then every surface of its `a2ui` fence, growing as the answer\n * streams. An answer without a valid surface falls back to its text.\n */\nexport function GenUiStream({ text, catalog, streaming, renderProse, fallback, onError, ...rest }: GenUiStreamProps) {\n const state = React.useMemo(() => readStream(text, catalog), [text, catalog]);\n const reported = React.useRef(0);\n React.useEffect(() => {\n if (!onError) return;\n for (const error of state.errors.slice(reported.current)) onError(error);\n reported.current = state.errors.length;\n }, [state, onError]);\n const prose = (value: string) => (renderProse ? renderProse(value) : value.split(/\\n{2,}/).map((p, i) => <p key={i}>{p}</p>));\n const surfaces = state.order.map((id) => state.surfaces.get(id)).filter((s): s is GenUiSurfaceState => !!s && s.components.has(\"root\"));\n if (!state.found || (!streaming && surfaces.length === 0)) return <>{fallback ? fallback(text) : prose(text)}</>;\n return (\n <div className=\"flex flex-col gap-4\" data-genui-stream=\"\">\n {state.prose && prose(state.prose)}\n {surfaces.map((surface) => (\n <GenUiSurface key={surface.id} surface={surface} catalog={catalog} streaming={streaming} onError={onError} {...rest} />\n ))}\n {streaming && surfaces.length === 0 && <Skeleton className=\"h-24 w-full rounded-xl\" />}\n </div>\n );\n}\n\n/** The state a list of messages builds — for a surface the app holds itself (not from a model's text). */\nexport type { GenUiState };\n"],"mappings":"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","names":["jsx","jsxs","surfaceId","surfaces","text","Fragment","jsx","jsxs","text"]}