cortena-ui 1.3.0 → 1.4.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 (280) hide show
  1. package/README.md +74 -3
  2. package/dist/a2ui/catalogue-doc.d.ts +44 -0
  3. package/dist/a2ui/catalogue-doc.js +169 -0
  4. package/dist/a2ui/catalogue-doc.js.map +1 -0
  5. package/dist/a2ui/catalogue.d.ts +44 -0
  6. package/dist/a2ui/catalogue.js +942 -0
  7. package/dist/a2ui/catalogue.js.map +1 -0
  8. package/dist/a2ui/index.d.ts +7 -0
  9. package/dist/a2ui/message.d.ts +232 -0
  10. package/dist/a2ui/message.js +365 -0
  11. package/dist/a2ui/message.js.map +1 -0
  12. package/dist/a2ui/renderer.d.ts +46 -0
  13. package/dist/a2ui/renderer.js +252 -0
  14. package/dist/a2ui/renderer.js.map +1 -0
  15. package/dist/a2ui/views.d.ts +80 -0
  16. package/dist/a2ui/views.js +596 -0
  17. package/dist/a2ui/views.js.map +1 -0
  18. package/dist/a2ui.d.ts +8 -0
  19. package/dist/a2ui.js +7 -0
  20. package/dist/chart.d.ts +9 -0
  21. package/dist/chart.js +9 -0
  22. package/dist/components/accordion.d.ts +22 -0
  23. package/dist/components/accordion.js +63 -0
  24. package/dist/components/accordion.js.map +1 -0
  25. package/dist/components/alert.d.ts +15 -0
  26. package/dist/components/alert.js +64 -0
  27. package/dist/components/alert.js.map +1 -0
  28. package/dist/components/avatar.d.ts +18 -0
  29. package/dist/components/avatar.js +40 -0
  30. package/dist/components/avatar.js.map +1 -0
  31. package/dist/components/badge.d.ts +12 -0
  32. package/dist/components/badge.js +47 -0
  33. package/dist/components/badge.js.map +1 -0
  34. package/dist/components/breadcrumb.d.ts +71 -0
  35. package/dist/components/breadcrumb.js +123 -0
  36. package/dist/components/breadcrumb.js.map +1 -0
  37. package/dist/components/button-link.d.ts +28 -0
  38. package/dist/components/button-link.js +24 -0
  39. package/dist/components/button-link.js.map +1 -0
  40. package/dist/components/button.d.ts +24 -0
  41. package/dist/components/button.js +65 -0
  42. package/dist/components/button.js.map +1 -0
  43. package/dist/components/calendar.d.ts +28 -0
  44. package/dist/components/calendar.js +123 -0
  45. package/dist/components/calendar.js.map +1 -0
  46. package/dist/components/card.d.ts +32 -0
  47. package/dist/components/card.js +57 -0
  48. package/dist/components/card.js.map +1 -0
  49. package/dist/components/chart/chart.d.ts +71 -0
  50. package/dist/components/chart/chart.js +167 -0
  51. package/dist/components/chart/chart.js.map +1 -0
  52. package/dist/components/chart/container.d.ts +88 -0
  53. package/dist/components/chart/container.js +189 -0
  54. package/dist/components/chart/container.js.map +1 -0
  55. package/dist/components/chart/data.js +128 -0
  56. package/dist/components/chart/data.js.map +1 -0
  57. package/dist/components/chart/index.d.ts +9 -0
  58. package/dist/components/chart/index.js +10 -0
  59. package/dist/components/chart/nivo-charts.js +225 -0
  60. package/dist/components/chart/nivo-charts.js.map +1 -0
  61. package/dist/components/chart/nivo-lazy.js +50 -0
  62. package/dist/components/chart/nivo-lazy.js.map +1 -0
  63. package/dist/components/chart/nivo-theme.d.ts +156 -0
  64. package/dist/components/chart/nivo-theme.js +161 -0
  65. package/dist/components/chart/nivo-theme.js.map +1 -0
  66. package/dist/components/chart/recharts-charts.js +276 -0
  67. package/dist/components/chart/recharts-charts.js.map +1 -0
  68. package/dist/components/chart/recharts-lazy.js +58 -0
  69. package/dist/components/chart/recharts-lazy.js.map +1 -0
  70. package/dist/components/chart/recharts-parts.d.ts +10 -0
  71. package/dist/components/chart/recharts-parts.js +25 -0
  72. package/dist/components/chart/recharts-parts.js.map +1 -0
  73. package/dist/components/chart/tokens.d.ts +62 -0
  74. package/dist/components/chart/tokens.js +192 -0
  75. package/dist/components/chart/tokens.js.map +1 -0
  76. package/dist/components/chart/types.d.ts +114 -0
  77. package/dist/components/chart/types.js +27 -0
  78. package/dist/components/chart/types.js.map +1 -0
  79. package/dist/components/checkbox.d.ts +20 -0
  80. package/dist/components/checkbox.js +24 -0
  81. package/dist/components/checkbox.js.map +1 -0
  82. package/dist/components/chip.d.ts +17 -0
  83. package/dist/components/chip.js +47 -0
  84. package/dist/components/chip.js.map +1 -0
  85. package/dist/components/combobox.d.ts +76 -0
  86. package/dist/components/combobox.js +201 -0
  87. package/dist/components/combobox.js.map +1 -0
  88. package/dist/components/command.d.ts +50 -0
  89. package/dist/components/command.js +117 -0
  90. package/dist/components/command.js.map +1 -0
  91. package/dist/components/data-table/data-table.d.ts +65 -0
  92. package/dist/components/data-table/data-table.js +588 -0
  93. package/dist/components/data-table/data-table.js.map +1 -0
  94. package/dist/components/data-table/export.d.ts +23 -0
  95. package/dist/components/data-table/export.js +95 -0
  96. package/dist/components/data-table/export.js.map +1 -0
  97. package/dist/components/data-table/features.d.ts +66 -0
  98. package/dist/components/data-table/features.js +103 -0
  99. package/dist/components/data-table/features.js.map +1 -0
  100. package/dist/components/data-table/index.d.ts +8 -0
  101. package/dist/components/data-table/parts.d.ts +79 -0
  102. package/dist/components/data-table/parts.js +400 -0
  103. package/dist/components/data-table/parts.js.map +1 -0
  104. package/dist/components/data-table/system-columns.js +84 -0
  105. package/dist/components/data-table/system-columns.js.map +1 -0
  106. package/dist/components/data-table/types.d.ts +172 -0
  107. package/dist/components/data-table/use-data-table.d.ts +19 -0
  108. package/dist/components/data-table/use-data-table.js +171 -0
  109. package/dist/components/data-table/use-data-table.js.map +1 -0
  110. package/dist/components/data-table/use-server-source.js +200 -0
  111. package/dist/components/data-table/use-server-source.js.map +1 -0
  112. package/dist/components/date-field.d.ts +54 -0
  113. package/dist/components/date-field.js +235 -0
  114. package/dist/components/date-field.js.map +1 -0
  115. package/dist/components/date-picker.d.ts +42 -0
  116. package/dist/components/date-picker.js +125 -0
  117. package/dist/components/date-picker.js.map +1 -0
  118. package/dist/components/dialog.d.ts +36 -0
  119. package/dist/components/dialog.js +97 -0
  120. package/dist/components/dialog.js.map +1 -0
  121. package/dist/components/dropdown-menu.d.ts +54 -0
  122. package/dist/components/dropdown-menu.js +191 -0
  123. package/dist/components/dropdown-menu.js.map +1 -0
  124. package/dist/components/dropzone.d.ts +48 -0
  125. package/dist/components/dropzone.js +185 -0
  126. package/dist/components/dropzone.js.map +1 -0
  127. package/dist/components/empty-state.d.ts +22 -0
  128. package/dist/components/empty-state.js +46 -0
  129. package/dist/components/empty-state.js.map +1 -0
  130. package/dist/components/error-banner.d.ts +17 -0
  131. package/dist/components/error-banner.js +52 -0
  132. package/dist/components/error-banner.js.map +1 -0
  133. package/dist/components/field.d.ts +64 -0
  134. package/dist/components/field.js +133 -0
  135. package/dist/components/field.js.map +1 -0
  136. package/dist/components/form.d.ts +37 -0
  137. package/dist/components/form.js +103 -0
  138. package/dist/components/form.js.map +1 -0
  139. package/dist/components/input.d.ts +17 -0
  140. package/dist/components/input.js +26 -0
  141. package/dist/components/input.js.map +1 -0
  142. package/dist/components/kbd.d.ts +11 -0
  143. package/dist/components/kbd.js +20 -0
  144. package/dist/components/kbd.js.map +1 -0
  145. package/dist/components/label.d.ts +14 -0
  146. package/dist/components/label.js +28 -0
  147. package/dist/components/label.js.map +1 -0
  148. package/dist/components/loading-skeleton.d.ts +22 -0
  149. package/dist/components/loading-skeleton.js +123 -0
  150. package/dist/components/loading-skeleton.js.map +1 -0
  151. package/dist/components/markdown.d.ts +44 -0
  152. package/dist/components/markdown.js +231 -0
  153. package/dist/components/markdown.js.map +1 -0
  154. package/dist/components/page-header.d.ts +26 -0
  155. package/dist/components/page-header.js +53 -0
  156. package/dist/components/page-header.js.map +1 -0
  157. package/dist/components/popover.d.ts +29 -0
  158. package/dist/components/popover.js +74 -0
  159. package/dist/components/popover.js.map +1 -0
  160. package/dist/components/progress.d.ts +22 -0
  161. package/dist/components/progress.js +49 -0
  162. package/dist/components/progress.js.map +1 -0
  163. package/dist/components/radio-group.d.ts +20 -0
  164. package/dist/components/radio-group.js +29 -0
  165. package/dist/components/radio-group.js.map +1 -0
  166. package/dist/components/scroll-area.d.ts +25 -0
  167. package/dist/components/scroll-area.js +39 -0
  168. package/dist/components/scroll-area.js.map +1 -0
  169. package/dist/components/section-card.d.ts +29 -0
  170. package/dist/components/section-card.js +55 -0
  171. package/dist/components/section-card.js.map +1 -0
  172. package/dist/components/segmented.d.ts +27 -0
  173. package/dist/components/segmented.js +32 -0
  174. package/dist/components/segmented.js.map +1 -0
  175. package/dist/components/select.d.ts +62 -0
  176. package/dist/components/select.js +97 -0
  177. package/dist/components/select.js.map +1 -0
  178. package/dist/components/separator.d.ts +19 -0
  179. package/dist/components/separator.js +23 -0
  180. package/dist/components/separator.js.map +1 -0
  181. package/dist/components/sheet.d.ts +35 -0
  182. package/dist/components/sheet.js +131 -0
  183. package/dist/components/sheet.js.map +1 -0
  184. package/dist/components/skeleton.d.ts +12 -0
  185. package/dist/components/skeleton.js +22 -0
  186. package/dist/components/skeleton.js.map +1 -0
  187. package/dist/components/sortable-list.d.ts +67 -0
  188. package/dist/components/sortable-list.js +206 -0
  189. package/dist/components/sortable-list.js.map +1 -0
  190. package/dist/components/spinner.d.ts +29 -0
  191. package/dist/components/spinner.js +34 -0
  192. package/dist/components/spinner.js.map +1 -0
  193. package/dist/components/status-dot.d.ts +26 -0
  194. package/dist/components/status-dot.js +47 -0
  195. package/dist/components/status-dot.js.map +1 -0
  196. package/dist/components/switch.d.ts +21 -0
  197. package/dist/components/switch.js +21 -0
  198. package/dist/components/switch.js.map +1 -0
  199. package/dist/components/tabs.d.ts +24 -0
  200. package/dist/components/tabs.js +60 -0
  201. package/dist/components/tabs.js.map +1 -0
  202. package/dist/components/textarea.d.ts +19 -0
  203. package/dist/components/textarea.js +47 -0
  204. package/dist/components/textarea.js.map +1 -0
  205. package/dist/components/toast.d.ts +47 -0
  206. package/dist/components/toast.js +106 -0
  207. package/dist/components/toast.js.map +1 -0
  208. package/dist/components/toolbar.d.ts +19 -0
  209. package/dist/components/toolbar.js +45 -0
  210. package/dist/components/toolbar.js.map +1 -0
  211. package/dist/components/tooltip.d.ts +28 -0
  212. package/dist/components/tooltip.js +59 -0
  213. package/dist/components/tooltip.js.map +1 -0
  214. package/dist/core.d.ts +44 -0
  215. package/dist/core.js +44 -0
  216. package/dist/data-table.d.ts +9 -0
  217. package/dist/data-table.js +7 -0
  218. package/dist/form.d.ts +7 -0
  219. package/dist/form.js +7 -0
  220. package/dist/hooks/use-cortena-theme.d.ts +98 -0
  221. package/dist/hooks/use-cortena-theme.js +145 -0
  222. package/dist/hooks/use-cortena-theme.js.map +1 -0
  223. package/dist/index.d.ts +75 -2678
  224. package/dist/index.js +66 -8598
  225. package/dist/lib/cn.d.ts +10 -0
  226. package/dist/lib/cn.js +15 -0
  227. package/dist/lib/cn.js.map +1 -0
  228. package/dist/lib/render.d.ts +23 -0
  229. package/dist/lib/render.js +20 -0
  230. package/dist/lib/render.js.map +1 -0
  231. package/dist/lib/shakeable.js +39 -0
  232. package/dist/lib/shakeable.js.map +1 -0
  233. package/dist/markdown.d.ts +3 -0
  234. package/dist/markdown.js +3 -0
  235. package/dist/sortable-list.d.ts +3 -0
  236. package/dist/sortable-list.js +3 -0
  237. package/package.json +37 -14
  238. package/src/a2ui/catalogue.ts +140 -103
  239. package/src/a2ui/views.tsx +5 -2
  240. package/src/components/alert.tsx +1 -1
  241. package/src/components/badge.tsx +1 -1
  242. package/src/components/button.tsx +1 -1
  243. package/src/components/chart/chart.tsx +72 -25
  244. package/src/components/chart/container.tsx +24 -39
  245. package/src/components/chart/index.tsx +4 -2
  246. package/src/components/chart/nivo-charts.tsx +41 -13
  247. package/src/components/chart/nivo-lazy.tsx +52 -0
  248. package/src/components/chart/recharts-charts.tsx +98 -3
  249. package/src/components/chart/recharts-lazy.tsx +72 -0
  250. package/src/components/chart/recharts-parts.tsx +34 -0
  251. package/src/components/chart/tokens.ts +1 -1
  252. package/src/components/chart/types.ts +14 -0
  253. package/src/components/chip.tsx +1 -1
  254. package/src/components/combobox.tsx +2 -2
  255. package/src/components/data-table/export.ts +18 -2
  256. package/src/components/data-table/features.ts +77 -45
  257. package/src/components/data-table/parts.tsx +15 -0
  258. package/src/components/data-table/use-data-table.ts +7 -2
  259. package/src/components/data-table/use-server-source.ts +17 -4
  260. package/src/components/date-field.tsx +1 -1
  261. package/src/components/error-banner.tsx +1 -1
  262. package/src/components/field.tsx +2 -2
  263. package/src/components/form.tsx +2 -2
  264. package/src/components/input.tsx +1 -1
  265. package/src/components/label.tsx +1 -1
  266. package/src/components/markdown.tsx +5 -4
  267. package/src/components/sheet.tsx +2 -2
  268. package/src/components/sortable-list.tsx +2 -2
  269. package/src/components/textarea.tsx +1 -1
  270. package/src/components/toast.tsx +1 -1
  271. package/src/entries/a2ui.ts +11 -0
  272. package/src/entries/chart.ts +10 -0
  273. package/src/entries/core.ts +91 -0
  274. package/src/entries/data-table.ts +9 -0
  275. package/src/entries/form.ts +24 -0
  276. package/src/entries/markdown.ts +9 -0
  277. package/src/entries/sortable-list.ts +13 -0
  278. package/src/index.ts +32 -98
  279. package/src/lib/shakeable.ts +33 -0
  280. package/dist/index.js.map +0 -1
@@ -0,0 +1,942 @@
1
+ "use client";
2
+ import { shakeable } from "../lib/shakeable.js";
3
+ import { AlertView, BadgeView, ButtonLinkView, ButtonView, CardView, ChartView, CheckboxView, ColumnView, DataTableView, DateFieldView, DividerView, EmptyStateView, ImageView, LinkView, MarkdownView, ProgressViewComponent, RadioGroupView, RowView, SectionCardView, SelectView, SpacerView, StatusDotView, SwitchView, TabsView, TextAreaView, TextFieldView, TextView } from "./views.js";
4
+ import { z } from "zod";
5
+ //#region src/a2ui/catalogue.ts
6
+ /**
7
+ * The A2UI catalogue, bound to cortena-ui.
8
+ *
9
+ * A2UI's safety property is that an agent may only choose from a catalogue the
10
+ * host controls: it cannot emit markup, styles or script, only a component name
11
+ * and properties the host validates. This file is that catalogue. Each entry
12
+ * declares
13
+ *
14
+ * - the A2UI component name an agent writes,
15
+ * - a zod schema for its **resolved** properties (bindings already read),
16
+ * - the event names it can raise,
17
+ * - whether it takes children,
18
+ * - a self-contained example, which is both the doc's sample and a fixture,
19
+ * - the cortena-ui view that draws it.
20
+ *
21
+ * The vocabulary therefore grows with the package rather than with a parser:
22
+ * adding a component here adds it to what every agent can draw, and
23
+ * `catalogue-doc.ts` regenerates the prompt section from the same object, so
24
+ * prompt and renderer cannot drift (DESIGN-34).
25
+ *
26
+ * Schemas describe resolved values because the renderer resolves `{ path }`
27
+ * bindings, unwraps literals and normalises actions before validating. A view
28
+ * therefore never receives an unchecked value, and a property an agent got
29
+ * wrong produces an error card naming the property rather than a blank area.
30
+ */
31
+ /** Keeps each entry's props type tied to its view without widening the record. */
32
+ function entry(definition) {
33
+ return definition;
34
+ }
35
+ /**
36
+ * A resolved action.
37
+ *
38
+ * On the wire an agent writes A2UI v0.9's `{ event: { name, context } }`, the
39
+ * bare `{ name, context }`, or just the name as a string; the renderer
40
+ * normalises all three to this before validation.
41
+ */
42
+ const Action = /* @__PURE__ */ shakeable(() => z.object({
43
+ name: z.string().describe("Event name sent back to the agent."),
44
+ context: z.record(z.string(), z.unknown()).optional().describe("Extra values merged into the action payload.")
45
+ }).describe("An action reported to the agent when the user interacts."));
46
+ const Option = /* @__PURE__ */ shakeable(() => z.object({
47
+ value: z.string().describe("Value written to the data model."),
48
+ label: z.string().optional().describe("Text shown to the user; defaults to the value."),
49
+ disabled: z.boolean().optional()
50
+ }));
51
+ const gap = /* @__PURE__ */ shakeable(() => z.union([
52
+ z.literal(0),
53
+ z.literal(1),
54
+ z.literal(2),
55
+ z.literal(3),
56
+ z.literal(4),
57
+ z.literal(6),
58
+ z.literal(8)
59
+ ]).describe("Spacing step between children."));
60
+ const padding = /* @__PURE__ */ shakeable(() => z.union([
61
+ z.literal(0),
62
+ z.literal(1),
63
+ z.literal(2),
64
+ z.literal(3),
65
+ z.literal(4),
66
+ z.literal(6),
67
+ z.literal(8)
68
+ ]).describe("Inner padding step."));
69
+ const alignment = /* @__PURE__ */ shakeable(() => z.enum([
70
+ "start",
71
+ "center",
72
+ "end",
73
+ "stretch",
74
+ "baseline"
75
+ ]).describe("Cross-axis alignment."));
76
+ const justification = /* @__PURE__ */ shakeable(() => z.enum([
77
+ "start",
78
+ "center",
79
+ "end",
80
+ "between"
81
+ ]).describe("Main-axis distribution."));
82
+ const fieldChrome = /* @__PURE__ */ shakeable(() => ({
83
+ label: z.string().optional().describe("Field label."),
84
+ description: z.string().optional().describe("Helper text under the control."),
85
+ error: z.string().optional().describe("Validation message; also marks the field invalid."),
86
+ disabled: z.boolean().optional()
87
+ }));
88
+ const buttonVariant = /* @__PURE__ */ shakeable(() => z.enum([
89
+ "primary",
90
+ "secondary",
91
+ "outline",
92
+ "ghost",
93
+ "soft",
94
+ "destructive",
95
+ "link"
96
+ ]).describe("Visual weight."));
97
+ const buttonSize = /* @__PURE__ */ shakeable(() => z.enum([
98
+ "sm",
99
+ "md",
100
+ "lg"
101
+ ]).describe("Control size."));
102
+ /**
103
+ * Root-relative means one slash and then a path. `//evil.example/x` is
104
+ * protocol-relative — the browser resolves it against the page's scheme and
105
+ * goes off-origin — and `/\evil.example` is the same trick, because browsers
106
+ * treat a backslash after the leading slash as a second slash.
107
+ */
108
+ const rootRelative = (value) => value.startsWith("/") && value[1] !== "/" && value[1] !== "\\";
109
+ /**
110
+ * A URL an agent may point at.
111
+ *
112
+ * Restricted by scheme rather than sanitised after the fact: `javascript:` and
113
+ * friends never reach the DOM because they never pass validation, so the
114
+ * component gets an error card instead.
115
+ */
116
+ const httpUrl = /* @__PURE__ */ shakeable(() => z.string().refine((value) => /^https?:\/\//i.test(value) || rootRelative(value) || value.startsWith("#"), "Must be an http(s), root-relative or fragment URL.").describe("Destination URL (http, https, root-relative or fragment)."));
117
+ const imageUrl = /* @__PURE__ */ shakeable(() => z.string().refine((value) => /^https?:\/\//i.test(value) || /^data:image\//i.test(value) || rootRelative(value), "Must be an http(s), root-relative or data:image URL.").describe("Image URL (http, https, root-relative or data:image)."));
118
+ /** Every chart type the Chart composite draws, Recharts and Nivo alike. */
119
+ const chartType = /* @__PURE__ */ shakeable(() => z.enum([
120
+ "bar",
121
+ "line",
122
+ "area",
123
+ "pie",
124
+ "donut",
125
+ "scatter",
126
+ "scatterplot",
127
+ "radar",
128
+ "funnel",
129
+ "heatmap",
130
+ "calendar",
131
+ "treemap",
132
+ "sunburst"
133
+ ]).describe("Chart type; the package picks Recharts or Nivo for it."));
134
+ /**
135
+ * A table's rows, or a handle to them.
136
+ *
137
+ * The server form is the point of `04-data-tables.md` in an agent context: the
138
+ * agent calls a tool, gets back a `sourceId`, and passes that. The host resolves
139
+ * it through `resolveDataSource`, so search, sort and paging stay on the backend
140
+ * and a large result never travels through the model.
141
+ */
142
+ const tableSource = /* @__PURE__ */ shakeable(() => z.union([z.object({
143
+ kind: z.literal("client"),
144
+ rows: z.array(z.record(z.string(), z.unknown())).describe("The rows, inline.")
145
+ }), z.object({
146
+ kind: z.literal("server"),
147
+ sourceId: z.string().describe("Handle obtained from a tool; the host resolves it to a server source.")
148
+ })]).describe("Where the table's rows come from."));
149
+ const layout = /* @__PURE__ */ shakeable(() => ({
150
+ Column: entry({
151
+ name: "Column",
152
+ group: "layout",
153
+ summary: "Stacks its children vertically.",
154
+ props: z.object({
155
+ gap: gap.optional(),
156
+ padding: padding.optional(),
157
+ align: alignment.optional(),
158
+ justify: justification.optional()
159
+ }),
160
+ events: [],
161
+ children: "many",
162
+ example: { components: [
163
+ {
164
+ id: "col",
165
+ component: "Column",
166
+ gap: 3,
167
+ children: ["col-a", "col-b"]
168
+ },
169
+ {
170
+ id: "col-a",
171
+ component: "Text",
172
+ text: "First",
173
+ role: "body"
174
+ },
175
+ {
176
+ id: "col-b",
177
+ component: "Text",
178
+ text: "Second",
179
+ role: "body"
180
+ }
181
+ ] },
182
+ view: ColumnView
183
+ }),
184
+ Row: entry({
185
+ name: "Row",
186
+ group: "layout",
187
+ summary: "Lays its children out horizontally, wrapping by default.",
188
+ props: z.object({
189
+ gap: gap.optional(),
190
+ padding: padding.optional(),
191
+ align: alignment.optional(),
192
+ justify: justification.optional(),
193
+ wrap: z.boolean().optional().describe("Set false to keep one line.")
194
+ }),
195
+ events: [],
196
+ children: "many",
197
+ example: { components: [
198
+ {
199
+ id: "row",
200
+ component: "Row",
201
+ gap: 2,
202
+ children: ["row-a", "row-b"]
203
+ },
204
+ {
205
+ id: "row-a",
206
+ component: "Badge",
207
+ label: "Open",
208
+ variant: "info"
209
+ },
210
+ {
211
+ id: "row-b",
212
+ component: "Badge",
213
+ label: "3 days",
214
+ variant: "neutral"
215
+ }
216
+ ] },
217
+ view: RowView
218
+ }),
219
+ Card: entry({
220
+ name: "Card",
221
+ group: "layout",
222
+ summary: "A bordered surface grouping related content.",
223
+ props: z.object({
224
+ accent: z.boolean().optional().describe("Draw the border in the ring colour."),
225
+ flush: z.boolean().optional().describe("Remove the body padding.")
226
+ }),
227
+ events: [],
228
+ children: "many",
229
+ example: { components: [{
230
+ id: "card",
231
+ component: "Card",
232
+ children: ["card-text"]
233
+ }, {
234
+ id: "card-text",
235
+ component: "Text",
236
+ text: "Inside a card.",
237
+ role: "body"
238
+ }] },
239
+ view: CardView
240
+ }),
241
+ SectionCard: entry({
242
+ name: "SectionCard",
243
+ group: "layout",
244
+ summary: "A card with a title and description header above its children.",
245
+ props: z.object({
246
+ title: z.string().describe("Header title."),
247
+ description: z.string().optional().describe("Header description."),
248
+ flush: z.boolean().optional()
249
+ }),
250
+ events: [],
251
+ children: "many",
252
+ example: { components: [{
253
+ id: "section",
254
+ component: "SectionCard",
255
+ title: "Pipeline",
256
+ description: "Deals closing this quarter.",
257
+ children: ["section-text"]
258
+ }, {
259
+ id: "section-text",
260
+ component: "Text",
261
+ text: "Twelve open deals.",
262
+ role: "body"
263
+ }] },
264
+ view: SectionCardView
265
+ }),
266
+ Divider: entry({
267
+ name: "Divider",
268
+ group: "layout",
269
+ summary: "A hairline rule between sections.",
270
+ props: z.object({ orientation: z.enum(["horizontal", "vertical"]).optional() }),
271
+ events: [],
272
+ children: "none",
273
+ example: { components: [{
274
+ id: "divider",
275
+ component: "Divider"
276
+ }] },
277
+ view: DividerView
278
+ }),
279
+ Spacer: entry({
280
+ name: "Spacer",
281
+ group: "layout",
282
+ summary: "Blank vertical space where a gap is not enough.",
283
+ props: z.object({ size: gap.optional().describe("Height step; default 4.") }),
284
+ events: [],
285
+ children: "none",
286
+ example: { components: [{
287
+ id: "spacer",
288
+ component: "Spacer",
289
+ size: 4
290
+ }] },
291
+ view: SpacerView
292
+ })
293
+ }));
294
+ const text = /* @__PURE__ */ shakeable(() => ({
295
+ Text: entry({
296
+ name: "Text",
297
+ group: "text",
298
+ summary: "A run of plain text at one of the type-scale roles.",
299
+ props: z.object({
300
+ text: z.string().describe("The text to show."),
301
+ role: z.enum([
302
+ "heading",
303
+ "subheading",
304
+ "body",
305
+ "caption",
306
+ "eyebrow"
307
+ ]).optional().describe("Type-scale role; default body."),
308
+ tone: z.enum([
309
+ "default",
310
+ "muted",
311
+ "success",
312
+ "warning",
313
+ "danger",
314
+ "info"
315
+ ]).optional().describe("Semantic colour; default foreground."),
316
+ align: z.enum([
317
+ "start",
318
+ "center",
319
+ "end"
320
+ ]).optional(),
321
+ mono: z.boolean().optional().describe("Render in the mono face, for ids and numbers.")
322
+ }),
323
+ events: [],
324
+ children: "none",
325
+ example: { components: [{
326
+ id: "heading",
327
+ component: "Text",
328
+ text: "Quarterly review",
329
+ role: "heading"
330
+ }] },
331
+ view: TextView
332
+ }),
333
+ Markdown: entry({
334
+ name: "Markdown",
335
+ group: "text",
336
+ summary: "Rich text as markdown; sanitised, with GFM tables and code blocks.",
337
+ props: z.object({
338
+ text: z.string().describe("Markdown source."),
339
+ compact: z.boolean().optional().describe("Tighter rhythm, for chat bubbles.")
340
+ }),
341
+ events: [],
342
+ children: "none",
343
+ example: { components: [{
344
+ id: "md",
345
+ component: "Markdown",
346
+ text: "**Summary**\n\n- Revenue up 12%\n- Churn flat\n",
347
+ compact: true
348
+ }] },
349
+ view: MarkdownView
350
+ })
351
+ }));
352
+ const input = /* @__PURE__ */ shakeable(() => ({
353
+ TextField: entry({
354
+ name: "TextField",
355
+ group: "input",
356
+ summary: "A single-line text input.",
357
+ props: z.object({
358
+ ...fieldChrome,
359
+ value: z.string().optional().describe("Current value; bind it to the data model."),
360
+ placeholder: z.string().optional(),
361
+ type: z.enum([
362
+ "text",
363
+ "email",
364
+ "url",
365
+ "tel",
366
+ "number",
367
+ "password",
368
+ "search"
369
+ ]).optional().describe("Input type; default text."),
370
+ required: z.boolean().optional(),
371
+ onChange: Action.optional().describe("Raised after the user stops typing.")
372
+ }),
373
+ events: ["change"],
374
+ children: "none",
375
+ example: {
376
+ data: { form: { name: "" } },
377
+ components: [{
378
+ id: "name",
379
+ component: "TextField",
380
+ label: "Full name",
381
+ value: { path: "/form/name" },
382
+ placeholder: "Ada Lovelace",
383
+ onChange: { event: { name: "nameChanged" } }
384
+ }]
385
+ },
386
+ view: TextFieldView
387
+ }),
388
+ TextArea: entry({
389
+ name: "TextArea",
390
+ group: "input",
391
+ summary: "A multi-line text input.",
392
+ props: z.object({
393
+ ...fieldChrome,
394
+ value: z.string().optional(),
395
+ placeholder: z.string().optional(),
396
+ rows: z.number().int().min(2).max(20).optional().describe("Visible rows; default 4."),
397
+ autoGrow: z.boolean().optional().describe("Grow with the content."),
398
+ onChange: Action.optional()
399
+ }),
400
+ events: ["change"],
401
+ children: "none",
402
+ example: {
403
+ data: { form: { notes: "" } },
404
+ components: [{
405
+ id: "notes",
406
+ component: "TextArea",
407
+ label: "Notes",
408
+ value: { path: "/form/notes" },
409
+ rows: 3,
410
+ onChange: { event: { name: "notesChanged" } }
411
+ }]
412
+ },
413
+ view: TextAreaView
414
+ }),
415
+ Select: entry({
416
+ name: "Select",
417
+ group: "input",
418
+ summary: "A dropdown offering one of a fixed list of options.",
419
+ props: z.object({
420
+ ...fieldChrome,
421
+ value: z.string().optional(),
422
+ placeholder: z.string().optional(),
423
+ options: z.array(Option).min(1).describe("The options to choose from."),
424
+ onChange: Action.optional()
425
+ }),
426
+ events: ["change"],
427
+ children: "none",
428
+ example: {
429
+ data: { form: { region: "ap-south-1" } },
430
+ components: [{
431
+ id: "region",
432
+ component: "Select",
433
+ label: "Region",
434
+ value: { path: "/form/region" },
435
+ options: [{
436
+ value: "ap-south-1",
437
+ label: "Mumbai"
438
+ }, {
439
+ value: "eu-west-1",
440
+ label: "Ireland"
441
+ }],
442
+ onChange: { event: { name: "regionChanged" } }
443
+ }]
444
+ },
445
+ view: SelectView
446
+ }),
447
+ Checkbox: entry({
448
+ name: "Checkbox",
449
+ group: "input",
450
+ summary: "A single on/off box with a label.",
451
+ props: z.object({
452
+ label: z.string().optional().describe("Text beside the box."),
453
+ description: z.string().optional(),
454
+ disabled: z.boolean().optional(),
455
+ checked: z.boolean().optional(),
456
+ onChange: Action.optional()
457
+ }),
458
+ events: ["change"],
459
+ children: "none",
460
+ example: {
461
+ data: { form: { terms: false } },
462
+ components: [{
463
+ id: "terms",
464
+ component: "Checkbox",
465
+ label: "I accept the terms",
466
+ checked: { path: "/form/terms" },
467
+ onChange: { event: { name: "termsChanged" } }
468
+ }]
469
+ },
470
+ view: CheckboxView
471
+ }),
472
+ Switch: entry({
473
+ name: "Switch",
474
+ group: "input",
475
+ summary: "A toggle for a setting that takes effect immediately.",
476
+ props: z.object({
477
+ label: z.string().optional(),
478
+ description: z.string().optional(),
479
+ disabled: z.boolean().optional(),
480
+ checked: z.boolean().optional(),
481
+ onChange: Action.optional()
482
+ }),
483
+ events: ["change"],
484
+ children: "none",
485
+ example: {
486
+ data: { form: { alerts: true } },
487
+ components: [{
488
+ id: "alerts",
489
+ component: "Switch",
490
+ label: "Email alerts",
491
+ checked: { path: "/form/alerts" },
492
+ onChange: { event: { name: "alertsChanged" } }
493
+ }]
494
+ },
495
+ view: SwitchView
496
+ }),
497
+ RadioGroup: entry({
498
+ name: "RadioGroup",
499
+ group: "input",
500
+ summary: "One choice from a short visible list.",
501
+ props: z.object({
502
+ label: z.string().optional(),
503
+ description: z.string().optional(),
504
+ disabled: z.boolean().optional(),
505
+ value: z.string().optional(),
506
+ options: z.array(Option).min(2).describe("Two or more choices."),
507
+ onChange: Action.optional()
508
+ }),
509
+ events: ["change"],
510
+ children: "none",
511
+ example: {
512
+ data: { form: { plan: "pro" } },
513
+ components: [{
514
+ id: "plan",
515
+ component: "RadioGroup",
516
+ label: "Plan",
517
+ value: { path: "/form/plan" },
518
+ options: [{
519
+ value: "free",
520
+ label: "Free"
521
+ }, {
522
+ value: "pro",
523
+ label: "Pro"
524
+ }],
525
+ onChange: { event: { name: "planChanged" } }
526
+ }]
527
+ },
528
+ view: RadioGroupView
529
+ }),
530
+ DateField: entry({
531
+ name: "DateField",
532
+ group: "input",
533
+ summary: "A date, typed or picked from a calendar. ISO yyyy-mm-dd on the wire.",
534
+ props: z.object({
535
+ ...fieldChrome,
536
+ value: z.string().optional().describe("ISO date, yyyy-mm-dd."),
537
+ min: z.string().optional().describe("Earliest selectable ISO date."),
538
+ max: z.string().optional().describe("Latest selectable ISO date."),
539
+ onChange: Action.optional()
540
+ }),
541
+ events: ["change"],
542
+ children: "none",
543
+ example: {
544
+ data: { form: { start: "2026-09-01" } },
545
+ components: [{
546
+ id: "start",
547
+ component: "DateField",
548
+ label: "Start date",
549
+ value: { path: "/form/start" },
550
+ onChange: { event: { name: "startChanged" } }
551
+ }]
552
+ },
553
+ view: DateFieldView
554
+ }),
555
+ Button: entry({
556
+ name: "Button",
557
+ group: "input",
558
+ summary: "A button. Set submit to report the whole data model with the action.",
559
+ props: z.object({
560
+ label: z.string().describe("Button text."),
561
+ variant: buttonVariant.optional().describe("Visual weight; default primary."),
562
+ size: buttonSize.optional(),
563
+ disabled: z.boolean().optional(),
564
+ submit: z.boolean().optional().describe("Send the surface data model as the action payload; use for form submits."),
565
+ onPress: Action.optional().describe("Raised when the user presses the button.")
566
+ }),
567
+ events: ["press", "submit"],
568
+ children: "none",
569
+ example: { components: [{
570
+ id: "save",
571
+ component: "Button",
572
+ label: "Save",
573
+ variant: "primary",
574
+ submit: true,
575
+ onPress: { event: { name: "saveProfile" } }
576
+ }] },
577
+ view: ButtonView
578
+ }),
579
+ ButtonLink: entry({
580
+ name: "ButtonLink",
581
+ group: "input",
582
+ summary: "A link that looks like a button. Navigates; raises no action.",
583
+ props: z.object({
584
+ label: z.string(),
585
+ href: httpUrl,
586
+ variant: buttonVariant.optional().describe("Visual weight; default secondary."),
587
+ size: buttonSize.optional(),
588
+ target: z.enum(["_self", "_blank"]).optional()
589
+ }),
590
+ events: [],
591
+ children: "none",
592
+ example: { components: [{
593
+ id: "docs",
594
+ component: "ButtonLink",
595
+ label: "Open runbook",
596
+ href: "https://example.com/runbook",
597
+ target: "_blank"
598
+ }] },
599
+ view: ButtonLinkView
600
+ })
601
+ }));
602
+ const feedback = /* @__PURE__ */ shakeable(() => ({
603
+ Badge: entry({
604
+ name: "Badge",
605
+ group: "feedback",
606
+ summary: "A small status label.",
607
+ props: z.object({
608
+ label: z.string(),
609
+ variant: z.enum([
610
+ "default",
611
+ "success",
612
+ "warning",
613
+ "danger",
614
+ "info",
615
+ "neutral",
616
+ "outline"
617
+ ]).optional()
618
+ }),
619
+ events: [],
620
+ children: "none",
621
+ example: { components: [{
622
+ id: "badge",
623
+ component: "Badge",
624
+ label: "Active",
625
+ variant: "success"
626
+ }] },
627
+ view: BadgeView
628
+ }),
629
+ Alert: entry({
630
+ name: "Alert",
631
+ group: "feedback",
632
+ summary: "A callout carrying a short message the user should notice.",
633
+ props: z.object({
634
+ title: z.string().optional(),
635
+ description: z.string().optional(),
636
+ variant: z.enum([
637
+ "default",
638
+ "success",
639
+ "warn",
640
+ "danger",
641
+ "info"
642
+ ]).optional()
643
+ }),
644
+ events: [],
645
+ children: "none",
646
+ example: { components: [{
647
+ id: "alert",
648
+ component: "Alert",
649
+ variant: "warn",
650
+ title: "Quota at 90%",
651
+ description: "Upgrade before the end of the month."
652
+ }] },
653
+ view: AlertView
654
+ }),
655
+ Progress: entry({
656
+ name: "Progress",
657
+ group: "feedback",
658
+ summary: "A determinate or indeterminate progress bar.",
659
+ props: z.object({
660
+ value: z.number().nullable().optional().describe("Null renders the indeterminate bar."),
661
+ max: z.number().optional().describe("Maximum; default 100."),
662
+ label: z.string().optional(),
663
+ showValue: z.boolean().optional().describe("Set false to hide the numeric readout.")
664
+ }),
665
+ events: [],
666
+ children: "none",
667
+ example: { components: [{
668
+ id: "progress",
669
+ component: "Progress",
670
+ label: "Indexing",
671
+ value: 64
672
+ }] },
673
+ view: ProgressViewComponent
674
+ }),
675
+ StatusDot: entry({
676
+ name: "StatusDot",
677
+ group: "feedback",
678
+ summary: "A coloured dot with a caption, for live status.",
679
+ props: z.object({
680
+ label: z.string().optional(),
681
+ tone: z.enum([
682
+ "accent",
683
+ "success",
684
+ "warning",
685
+ "danger",
686
+ "info",
687
+ "neutral"
688
+ ]).optional(),
689
+ live: z.boolean().optional().describe("Add a pulsing halo for an active state.")
690
+ }),
691
+ events: [],
692
+ children: "none",
693
+ example: { components: [{
694
+ id: "status",
695
+ component: "StatusDot",
696
+ label: "Running",
697
+ tone: "success",
698
+ live: true
699
+ }] },
700
+ view: StatusDotView
701
+ }),
702
+ EmptyState: entry({
703
+ name: "EmptyState",
704
+ group: "feedback",
705
+ summary: "The 'nothing here' surface; children become its actions.",
706
+ props: z.object({
707
+ title: z.string(),
708
+ description: z.string().optional(),
709
+ size: z.enum(["default", "compact"]).optional()
710
+ }),
711
+ events: [],
712
+ children: "many",
713
+ example: { components: [{
714
+ id: "empty",
715
+ component: "EmptyState",
716
+ title: "No results",
717
+ description: "Try a wider date range.",
718
+ children: ["empty-action"]
719
+ }, {
720
+ id: "empty-action",
721
+ component: "Button",
722
+ label: "Reset filters",
723
+ variant: "secondary",
724
+ onPress: { event: { name: "resetFilters" } }
725
+ }] },
726
+ view: EmptyStateView
727
+ })
728
+ }));
729
+ const data = /* @__PURE__ */ shakeable(() => ({
730
+ DataTable: entry({
731
+ name: "DataTable",
732
+ group: "data",
733
+ summary: "A sortable, searchable table. Pass rows inline, or a server sourceId obtained from a tool.",
734
+ props: z.object({
735
+ columns: z.array(z.object({
736
+ id: z.string().describe("Row property this column reads."),
737
+ label: z.string().optional().describe("Header text; defaults to the id."),
738
+ align: z.enum([
739
+ "start",
740
+ "center",
741
+ "end"
742
+ ]).optional(),
743
+ filter: z.enum(["faceted", "text"]).optional().describe("Add a toolbar filter for this column."),
744
+ width: z.number().optional()
745
+ })).min(1),
746
+ dataSource: tableSource,
747
+ pageSize: z.number().int().min(1).max(200).optional().describe("Rows per page; default 10."),
748
+ density: z.enum(["default", "compact"]).optional(),
749
+ searchPlaceholder: z.string().optional(),
750
+ emptyMessage: z.string().optional(),
751
+ maxHeight: z.number().optional().describe("Scrolling body height in px."),
752
+ onRowClick: Action.optional().describe("Raised with the clicked row.")
753
+ }),
754
+ events: ["rowClick"],
755
+ children: "none",
756
+ example: { components: [{
757
+ id: "table",
758
+ component: "DataTable",
759
+ columns: [
760
+ {
761
+ id: "name",
762
+ label: "Name"
763
+ },
764
+ {
765
+ id: "status",
766
+ label: "Status",
767
+ filter: "faceted"
768
+ },
769
+ {
770
+ id: "deals",
771
+ label: "Deals",
772
+ align: "end"
773
+ }
774
+ ],
775
+ dataSource: {
776
+ kind: "client",
777
+ rows: [{
778
+ name: "Ada Lovelace",
779
+ status: "active",
780
+ deals: 12
781
+ }, {
782
+ name: "Grace Hopper",
783
+ status: "invited",
784
+ deals: 4
785
+ }]
786
+ },
787
+ onRowClick: { event: { name: "openContact" } }
788
+ }] },
789
+ view: DataTableView
790
+ }),
791
+ Chart: entry({
792
+ name: "Chart",
793
+ group: "data",
794
+ summary: "Any chart the package draws: bar, line, area, pie, donut, scatter, radar, funnel, heatmap, calendar, treemap, sunburst.",
795
+ props: z.object({
796
+ type: chartType,
797
+ data: z.unknown().describe("Rows [{category, series…}] for bar/radar; series [{id, data:[{x,y}]}] for line/area/scatter/heatmap; slices [{id,value}] for pie/donut/funnel; days [{day,value}] for calendar; a tree {id, children} for treemap/sunburst."),
798
+ title: z.string().optional().describe("Caption above the chart."),
799
+ height: z.number().int().min(120).max(800).optional().describe("Drawing height in px."),
800
+ stacked: z.boolean().optional(),
801
+ legend: z.boolean().optional(),
802
+ grid: z.boolean().optional(),
803
+ scale: z.enum(["sequential", "diverging"]).optional().describe("Heatmap and calendar scale."),
804
+ indexBy: z.string().optional().describe("Category key for row data."),
805
+ keys: z.array(z.string()).optional().describe("Series keys for row data."),
806
+ from: z.string().optional().describe("Calendar range start, ISO date."),
807
+ to: z.string().optional().describe("Calendar range end, ISO date."),
808
+ emptyMessage: z.string().optional()
809
+ }),
810
+ events: [],
811
+ children: "none",
812
+ example: { components: [{
813
+ id: "chart",
814
+ component: "Chart",
815
+ type: "bar",
816
+ title: "Revenue by month",
817
+ data: [{
818
+ month: "Jan",
819
+ revenue: 42,
820
+ cost: 18
821
+ }, {
822
+ month: "Feb",
823
+ revenue: 51,
824
+ cost: 22
825
+ }]
826
+ }] },
827
+ view: ChartView
828
+ })
829
+ }));
830
+ const other = /* @__PURE__ */ shakeable(() => ({
831
+ Tabs: entry({
832
+ name: "Tabs",
833
+ group: "layout",
834
+ summary: "Tabbed panels; the nth child is the nth tab's panel.",
835
+ props: z.object({
836
+ tabs: z.array(z.object({
837
+ value: z.string(),
838
+ label: z.string()
839
+ })).min(2).describe("Tab bar, in order."),
840
+ value: z.string().optional().describe("Selected tab; defaults to the first."),
841
+ onChange: Action.optional()
842
+ }),
843
+ events: ["tabChange"],
844
+ children: "many",
845
+ example: { components: [
846
+ {
847
+ id: "tabs",
848
+ component: "Tabs",
849
+ tabs: [{
850
+ value: "summary",
851
+ label: "Summary"
852
+ }, {
853
+ value: "detail",
854
+ label: "Detail"
855
+ }],
856
+ children: ["tab-summary", "tab-detail"],
857
+ onChange: { event: { name: "tabChanged" } }
858
+ },
859
+ {
860
+ id: "tab-summary",
861
+ component: "Text",
862
+ text: "Two open incidents.",
863
+ role: "body"
864
+ },
865
+ {
866
+ id: "tab-detail",
867
+ component: "Text",
868
+ text: "INC-42, INC-51.",
869
+ role: "body"
870
+ }
871
+ ] },
872
+ view: TabsView
873
+ }),
874
+ Image: entry({
875
+ name: "Image",
876
+ group: "text",
877
+ summary: "An image. Alt text is required.",
878
+ props: z.object({
879
+ src: imageUrl,
880
+ alt: z.string().describe("Alternative text; required."),
881
+ width: z.number().optional(),
882
+ height: z.number().optional(),
883
+ rounded: z.boolean().optional().describe("Set false for square corners."),
884
+ fit: z.enum(["cover", "contain"]).optional()
885
+ }),
886
+ events: [],
887
+ children: "none",
888
+ example: { components: [{
889
+ id: "image",
890
+ component: "Image",
891
+ src: "https://example.com/chart.png",
892
+ alt: "Revenue by month",
893
+ height: 160
894
+ }] },
895
+ view: ImageView
896
+ }),
897
+ Link: entry({
898
+ name: "Link",
899
+ group: "text",
900
+ summary: "An inline text link.",
901
+ props: z.object({
902
+ label: z.string(),
903
+ href: httpUrl,
904
+ target: z.enum(["_self", "_blank"]).optional()
905
+ }),
906
+ events: [],
907
+ children: "none",
908
+ example: { components: [{
909
+ id: "link",
910
+ component: "Link",
911
+ label: "View the incident",
912
+ href: "https://example.com/inc-42",
913
+ target: "_blank"
914
+ }] },
915
+ view: LinkView
916
+ })
917
+ }));
918
+ /**
919
+ * The catalogue an agent draws from, and the renderer's default.
920
+ *
921
+ * A host may narrow it (hand the renderer a subset) but should not widen it
922
+ * with components the prompt does not describe: an agent can only usefully
923
+ * emit what `catalogue-doc.ts` told it about.
924
+ */
925
+ const defaultCatalogue = /* @__PURE__ */ shakeable(() => Object.freeze({
926
+ ...layout,
927
+ ...text,
928
+ ...input,
929
+ ...feedback,
930
+ ...data,
931
+ ...other
932
+ }));
933
+ /** Catalogue id an agent may echo in `createSurface.catalogId`. */
934
+ const A2UI_CATALOGUE_ID = "https://cortena.ai/a2ui/catalogues/cortena-ui/v1.json";
935
+ /** Every component name in the catalogue, sorted. */
936
+ function catalogueNames(catalogue = defaultCatalogue) {
937
+ return Object.keys(catalogue).sort();
938
+ }
939
+ //#endregion
940
+ export { A2UI_CATALOGUE_ID, catalogueNames, defaultCatalogue };
941
+
942
+ //# sourceMappingURL=catalogue.js.map