@urbicon-ui/blocks 6.40.4 → 6.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Chat/A2UIView/A2UINode.svelte +20 -39
- package/dist/components/Chat/A2UIView/A2UIView.svelte +47 -50
- package/dist/components/Chat/A2UIView/a2ui-basic-catalog.d.ts +17 -0
- package/dist/components/Chat/A2UIView/a2ui-basic-catalog.js +69 -0
- package/dist/components/Chat/A2UIView/a2ui-catalog.d.ts +95 -0
- package/dist/components/Chat/A2UIView/a2ui-catalog.js +87 -0
- package/dist/components/Chat/A2UIView/a2ui-node-common.d.ts +40 -0
- package/dist/components/Chat/A2UIView/a2ui-node-common.js +72 -0
- package/dist/components/Chat/A2UIView/a2ui-prompt.d.ts +21 -10
- package/dist/components/Chat/A2UIView/a2ui-prompt.js +170 -24
- package/dist/components/Chat/A2UIView/a2ui-registry.d.ts +1 -1
- package/dist/components/Chat/A2UIView/a2ui-registry.js +2 -1
- package/dist/components/Chat/A2UIView/a2ui-render.d.ts +30 -0
- package/dist/components/Chat/A2UIView/a2ui-render.js +61 -23
- package/dist/components/Chat/A2UIView/a2ui-router.d.ts +136 -0
- package/dist/components/Chat/A2UIView/a2ui-router.js +264 -0
- package/dist/components/Chat/A2UIView/a2ui-schema.d.ts +45 -0
- package/dist/components/Chat/A2UIView/a2ui-schema.js +133 -0
- package/dist/components/Chat/A2UIView/a2ui-stream.d.ts +120 -0
- package/dist/components/Chat/A2UIView/a2ui-stream.js +406 -0
- package/dist/components/Chat/A2UIView/a2ui-transcript.d.ts +65 -0
- package/dist/components/Chat/A2UIView/a2ui-transcript.js +101 -0
- package/dist/components/Chat/A2UIView/a2ui-validate.d.ts +33 -1
- package/dist/components/Chat/A2UIView/a2ui-validate.js +167 -63
- package/dist/components/Chat/A2UIView/a2ui.types.d.ts +50 -0
- package/dist/components/Chat/A2UIView/a2ui.types.js +38 -1
- package/dist/components/Chat/A2UIView/index.d.ts +35 -2
- package/dist/components/Chat/A2UIView/index.js +13 -0
- package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte +831 -0
- package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte.d.ts +4 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.d.ts +14 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.js +87 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.d.ts +78 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.js +783 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.d.ts +43 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.js +33 -0
- package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.d.ts +7 -0
- package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.js +86 -0
- package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +19 -19
- package/dist/components/FileUpload/fileUpload.variants.js +15 -4
- package/dist/components/PinInput/PinInput.svelte +1 -0
- package/dist/components/PinInput/pin-input.variants.js +14 -1
- package/dist/components/TimeInput/time-input.variants.js +16 -1
- package/dist/internal/field-chrome.d.ts +18 -1
- package/dist/internal/field-chrome.js +18 -1
- package/dist/primitives/Avatar/avatar.variants.js +4 -1
- package/dist/primitives/Badge/badge.variants.js +11 -2
- package/dist/primitives/Button/button.variants.js +4 -1
- package/dist/primitives/Card/card.variants.js +4 -1
- package/dist/primitives/Checkbox/checkbox.variants.js +7 -1
- package/dist/primitives/Combobox/Combobox.svelte +9 -1
- package/dist/primitives/Combobox/combobox.variants.d.ts +25 -0
- package/dist/primitives/Combobox/combobox.variants.js +32 -3
- package/dist/primitives/Combobox/index.d.ts +8 -2
- package/dist/primitives/Dialog/dialog.variants.js +4 -1
- package/dist/primitives/Drawer/drawer.variants.js +4 -1
- package/dist/primitives/Input/input.variants.js +17 -1
- package/dist/primitives/Menu/menu.variants.js +5 -1
- package/dist/primitives/Progress/progress.variants.js +5 -2
- package/dist/primitives/RadioGroup/radioGroup.variants.js +68 -9
- package/dist/primitives/Select/select.variants.js +13 -4
- package/dist/primitives/Slider/Slider.svelte +4 -1
- package/dist/primitives/Slider/slider.variants.js +9 -2
- package/dist/primitives/Textarea/textarea.variants.js +15 -1
- package/dist/primitives/Toast/toast.variants.js +5 -1
- package/dist/primitives/Toggle/toggle.variants.js +92 -18
- package/dist/primitives/Tooltip/tooltip.variants.d.ts +3 -3
- package/dist/primitives/Tooltip/tooltip.variants.js +5 -1
- package/dist/utils/persistent-state.svelte.d.ts +25 -1
- package/dist/utils/persistent-state.svelte.js +98 -10
- package/docs/MIGRATION-v5.md +29 -0
- package/package.json +3 -3
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Urbicon-native A2UI catalog registry — the single source of truth for
|
|
3
|
+
* validation AND the Urbicon system prompt, exactly like the Basic registry but
|
|
4
|
+
* carrying the FULL Urbicon vocabulary the Basic subset flattens away: real
|
|
5
|
+
* intents (primary/secondary/success/warning/danger/neutral), a size axis, the
|
|
6
|
+
* component-native `variant` axes, a structure layer (`Section`), a
|
|
7
|
+
* plain-vs-markdown split (`Text` vs `RichText`) and labelled disclosure
|
|
8
|
+
* (`Accordion`).
|
|
9
|
+
*
|
|
10
|
+
* HAND-curated (descriptions, childId conventions, prop whitelist) but the axis
|
|
11
|
+
* VALUES it advertises are library truth: every prop that carries an `axis` is
|
|
12
|
+
* coupled to `urbicon-axes.gen.ts` (generated from the docs-gen catalog) by a
|
|
13
|
+
* blocks-internal drift test — curated `values ⊆ axis`, `default ===`, and every
|
|
14
|
+
* `urbicon` reference exists. So the catalog can never offer a variant the real
|
|
15
|
+
* component does not support. No Svelte imports: a server building the prompt has
|
|
16
|
+
* no DOM.
|
|
17
|
+
*
|
|
18
|
+
* Curation rules (never in the catalog): snippets, callbacks (`on*`),
|
|
19
|
+
* `class`/`unstyled`/`slotClasses`/`preset`/`mint`/`tier`, style booleans.
|
|
20
|
+
* Snippet slots become `childId`s; composites become data props (Stepper steps
|
|
21
|
+
* as a string list, Accordion items as `labeledChildren`); two-way state is a
|
|
22
|
+
* `dynamic` prop the renderer writes back. Field errors travel on a single
|
|
23
|
+
* `error?: string` (the renderer sets intent=danger) — NO per-field intent axis.
|
|
24
|
+
*/
|
|
25
|
+
import { A2UI_ISSUE_CODES } from '../a2ui.types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Axes shared across many components, defined ONCE so the prompt can document
|
|
28
|
+
* them a single time and each prop reference them (compression) instead of
|
|
29
|
+
* repeating the full list. Per-prop `default`s still vary (a Button defaults to
|
|
30
|
+
* neutral, a Badge to primary), so only the value SET is shared.
|
|
31
|
+
*/
|
|
32
|
+
export const SHARED_AXES = {
|
|
33
|
+
/** The six semantic intents. Alert additionally offers `info` (its own axis). */
|
|
34
|
+
intent: ['primary', 'secondary', 'success', 'warning', 'danger', 'neutral'],
|
|
35
|
+
/** The curated size subset (the library also has 2xs/xs/xl/2xl — deliberately omitted). */
|
|
36
|
+
size: ['sm', 'md', 'lg']
|
|
37
|
+
};
|
|
38
|
+
/** The opaque catalog id this catalog advertises in `createSurface`. Custom catalogs are spec-sanctioned via `catalogId`. */
|
|
39
|
+
export const URBICON_A2UI_CATALOG_ID = 'urbicon-ui/urbicon-catalog/v1';
|
|
40
|
+
/** Mapped `Icon.name` values: the Basic 16 plus 10 curated domain glyphs. */
|
|
41
|
+
export const URBICON_A2UI_ICON_NAMES = [
|
|
42
|
+
// Basic 16
|
|
43
|
+
'add',
|
|
44
|
+
'arrowBack',
|
|
45
|
+
'check',
|
|
46
|
+
'close',
|
|
47
|
+
'delete',
|
|
48
|
+
'edit',
|
|
49
|
+
'error',
|
|
50
|
+
'home',
|
|
51
|
+
'info',
|
|
52
|
+
'mail',
|
|
53
|
+
'menu',
|
|
54
|
+
'search',
|
|
55
|
+
'send',
|
|
56
|
+
'settings',
|
|
57
|
+
'star',
|
|
58
|
+
'warning',
|
|
59
|
+
// Curated 10 (domain depth: scheduling, identity, contact, place, money, data ops, navigation)
|
|
60
|
+
'calendar',
|
|
61
|
+
'clock',
|
|
62
|
+
'user',
|
|
63
|
+
'phone',
|
|
64
|
+
'mapPin',
|
|
65
|
+
'euro',
|
|
66
|
+
'filter',
|
|
67
|
+
'refresh',
|
|
68
|
+
'chevronRight',
|
|
69
|
+
'link'
|
|
70
|
+
];
|
|
71
|
+
/** Real Urbicon components deliberately not in the v1 catalog (error chip, not "unknown"). */
|
|
72
|
+
export const UNSUPPORTED_URBICON_A2UI_COMPONENTS = new Set([
|
|
73
|
+
'Tabs',
|
|
74
|
+
'Combobox',
|
|
75
|
+
'Toolbar',
|
|
76
|
+
'ButtonGroup',
|
|
77
|
+
'FormField',
|
|
78
|
+
'SegmentGroup',
|
|
79
|
+
'Dialog',
|
|
80
|
+
'Drawer',
|
|
81
|
+
'Popover',
|
|
82
|
+
'Menu',
|
|
83
|
+
'Tooltip',
|
|
84
|
+
'Table',
|
|
85
|
+
'CommandPalette'
|
|
86
|
+
]);
|
|
87
|
+
/** Props recognised anywhere but intentionally ignored (validation warning only, dropped before render). */
|
|
88
|
+
export const URBICON_A2UI_IGNORED_PROPS = new Set([
|
|
89
|
+
'checks',
|
|
90
|
+
'validationRegexp'
|
|
91
|
+
]);
|
|
92
|
+
const COMMON_PROPS = {
|
|
93
|
+
accessibility: {
|
|
94
|
+
kind: 'accessibility',
|
|
95
|
+
description: 'Accessibility attributes { label, description } for assistive technologies. label is a short (1–3 word) purpose string; description adds instructions or format requirements.'
|
|
96
|
+
},
|
|
97
|
+
weight: {
|
|
98
|
+
kind: 'number',
|
|
99
|
+
description: 'Relative flex-grow weight within a Row or Column (like CSS flex-grow). ONLY honored when this component is a direct child of a Row or Column.'
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
function withCommon(props) {
|
|
103
|
+
return { ...props, ...COMMON_PROPS };
|
|
104
|
+
}
|
|
105
|
+
/** An `intent` prop drawn from the six shared intents, with a component-specific default. */
|
|
106
|
+
function intentProp(def, description) {
|
|
107
|
+
return {
|
|
108
|
+
kind: 'enum',
|
|
109
|
+
values: SHARED_AXES.intent,
|
|
110
|
+
default: def,
|
|
111
|
+
sharedAxis: 'intent',
|
|
112
|
+
axis: 'intent',
|
|
113
|
+
description
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** A `size` prop drawn from the shared size subset (default md). */
|
|
117
|
+
function sizeProp(description = 'Size of the component.') {
|
|
118
|
+
return {
|
|
119
|
+
kind: 'enum',
|
|
120
|
+
values: SHARED_AXES.size,
|
|
121
|
+
default: 'md',
|
|
122
|
+
sharedAxis: 'size',
|
|
123
|
+
axis: 'size',
|
|
124
|
+
description
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export const URBICON_A2UI_REGISTRY = Object.freeze({
|
|
128
|
+
// ── Layout ────────────────────────────────────────────────────────────────
|
|
129
|
+
Column: {
|
|
130
|
+
category: 'Layout',
|
|
131
|
+
description: 'A layout container that arranges its children vertically. Nest Rows inside a Column to build a grid.',
|
|
132
|
+
props: withCommon({
|
|
133
|
+
children: {
|
|
134
|
+
kind: 'childList',
|
|
135
|
+
required: true,
|
|
136
|
+
description: 'The children: either an array of component IDs, or a template { componentId, path } that repeats one component over a data-model array. Children are referenced by ID only — never defined inline.'
|
|
137
|
+
},
|
|
138
|
+
justify: {
|
|
139
|
+
kind: 'enum',
|
|
140
|
+
values: ['start', 'center', 'end', 'spaceBetween', 'spaceAround', 'spaceEvenly', 'stretch'],
|
|
141
|
+
default: 'start',
|
|
142
|
+
description: 'Arrangement along the main (vertical) axis. Use spaceBetween to push items to the top and bottom edges.'
|
|
143
|
+
},
|
|
144
|
+
align: {
|
|
145
|
+
kind: 'enum',
|
|
146
|
+
values: ['start', 'center', 'end', 'stretch'],
|
|
147
|
+
default: 'stretch',
|
|
148
|
+
description: 'Alignment along the cross (horizontal) axis, like CSS align-items.'
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
},
|
|
152
|
+
Row: {
|
|
153
|
+
category: 'Layout',
|
|
154
|
+
description: 'A layout container that arranges its children horizontally. Nest Columns inside a Row to build a grid.',
|
|
155
|
+
props: withCommon({
|
|
156
|
+
children: {
|
|
157
|
+
kind: 'childList',
|
|
158
|
+
required: true,
|
|
159
|
+
description: 'The children: either an array of component IDs, or a template { componentId, path } that repeats one component over a data-model array. Children are referenced by ID only — never defined inline.'
|
|
160
|
+
},
|
|
161
|
+
justify: {
|
|
162
|
+
kind: 'enum',
|
|
163
|
+
values: ['start', 'center', 'end', 'spaceBetween', 'spaceAround', 'spaceEvenly', 'stretch'],
|
|
164
|
+
default: 'start',
|
|
165
|
+
description: 'Arrangement along the main (horizontal) axis. Use spaceBetween to push items to the left and right edges.'
|
|
166
|
+
},
|
|
167
|
+
align: {
|
|
168
|
+
kind: 'enum',
|
|
169
|
+
values: ['start', 'center', 'end', 'stretch'],
|
|
170
|
+
default: 'center',
|
|
171
|
+
description: 'Alignment along the cross (vertical) axis, like CSS align-items.'
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
},
|
|
175
|
+
List: {
|
|
176
|
+
category: 'Layout',
|
|
177
|
+
description: 'A list container. Prefer a template { componentId, path } to render one row per data-model array item.',
|
|
178
|
+
props: withCommon({
|
|
179
|
+
children: {
|
|
180
|
+
kind: 'childList',
|
|
181
|
+
required: true,
|
|
182
|
+
description: 'The children: an array of component IDs, or a template { componentId, path }. Children are referenced by ID only.'
|
|
183
|
+
},
|
|
184
|
+
direction: {
|
|
185
|
+
kind: 'enum',
|
|
186
|
+
values: ['vertical', 'horizontal'],
|
|
187
|
+
default: 'vertical',
|
|
188
|
+
description: 'The direction list items flow in.'
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
},
|
|
192
|
+
Card: {
|
|
193
|
+
category: 'Layout',
|
|
194
|
+
urbicon: 'Card',
|
|
195
|
+
description: 'A visually grouped container. Its main content is one `child` (wrap several elements in a Column/Row). Optional `header` and `footer` childIds frame it.',
|
|
196
|
+
props: withCommon({
|
|
197
|
+
child: {
|
|
198
|
+
kind: 'childId',
|
|
199
|
+
required: true,
|
|
200
|
+
description: 'The ID of the main child component. Pass a layout container ID for multiple elements. Never inline the child.'
|
|
201
|
+
},
|
|
202
|
+
header: {
|
|
203
|
+
kind: 'childId',
|
|
204
|
+
description: 'Optional header child ID, rendered above the content with a divider.'
|
|
205
|
+
},
|
|
206
|
+
footer: {
|
|
207
|
+
kind: 'childId',
|
|
208
|
+
description: 'Optional footer child ID, rendered below the content with a divider.'
|
|
209
|
+
},
|
|
210
|
+
variant: {
|
|
211
|
+
kind: 'enum',
|
|
212
|
+
values: ['elevated', 'floating', 'outlined', 'quiet'],
|
|
213
|
+
default: 'quiet',
|
|
214
|
+
axis: 'variant',
|
|
215
|
+
description: 'Surface style. quiet is a flat panel; outlined adds a border; elevated/floating add shadow.'
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
},
|
|
219
|
+
Separator: {
|
|
220
|
+
category: 'Layout',
|
|
221
|
+
urbicon: 'Separator',
|
|
222
|
+
description: 'A thin rule that visually separates content.',
|
|
223
|
+
props: withCommon({
|
|
224
|
+
orientation: {
|
|
225
|
+
kind: 'enum',
|
|
226
|
+
values: ['horizontal', 'vertical'],
|
|
227
|
+
default: 'horizontal',
|
|
228
|
+
axis: 'orientation',
|
|
229
|
+
description: 'Orientation of the separator.'
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
},
|
|
233
|
+
Section: {
|
|
234
|
+
category: 'Layout',
|
|
235
|
+
description: 'A titled content block: a heading (and optional description) above one `child`. The building block for page-like structure — group related controls under a Section instead of a bare Column.',
|
|
236
|
+
props: withCommon({
|
|
237
|
+
title: {
|
|
238
|
+
kind: 'string',
|
|
239
|
+
required: true,
|
|
240
|
+
dynamic: true,
|
|
241
|
+
description: 'The section heading.'
|
|
242
|
+
},
|
|
243
|
+
description: {
|
|
244
|
+
kind: 'string',
|
|
245
|
+
dynamic: true,
|
|
246
|
+
description: 'Optional supporting text under the heading.'
|
|
247
|
+
},
|
|
248
|
+
child: {
|
|
249
|
+
kind: 'childId',
|
|
250
|
+
required: true,
|
|
251
|
+
description: 'The ID of the section body (usually a Column). Never inline the child.'
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
},
|
|
255
|
+
EmptyState: {
|
|
256
|
+
category: 'Layout',
|
|
257
|
+
urbicon: 'EmptyState',
|
|
258
|
+
description: 'A centered placeholder for "no data" / "nothing here yet": an optional icon, a title, supporting text, and an optional call-to-action button.',
|
|
259
|
+
props: withCommon({
|
|
260
|
+
title: {
|
|
261
|
+
kind: 'string',
|
|
262
|
+
required: true,
|
|
263
|
+
dynamic: true,
|
|
264
|
+
description: 'The primary message (e.g. "No appointments yet").'
|
|
265
|
+
},
|
|
266
|
+
description: {
|
|
267
|
+
kind: 'string',
|
|
268
|
+
dynamic: true,
|
|
269
|
+
description: 'Optional secondary text explaining the state or the next step.'
|
|
270
|
+
},
|
|
271
|
+
icon: {
|
|
272
|
+
kind: 'icon',
|
|
273
|
+
values: URBICON_A2UI_ICON_NAMES,
|
|
274
|
+
description: 'Optional icon name shown above the title.'
|
|
275
|
+
},
|
|
276
|
+
cta: {
|
|
277
|
+
kind: 'childId',
|
|
278
|
+
description: 'Optional call-to-action child ID (usually a Button). Never inline the child.'
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
},
|
|
282
|
+
// ── Text ──────────────────────────────────────────────────────────────────
|
|
283
|
+
Text: {
|
|
284
|
+
category: 'Text',
|
|
285
|
+
description: 'Displays PLAIN text — no Markdown is parsed (a literal `**x**` shows the asterisks). Use RichText for formatted prose. Choose a `variant` for the typographic role.',
|
|
286
|
+
props: withCommon({
|
|
287
|
+
text: {
|
|
288
|
+
kind: 'string',
|
|
289
|
+
required: true,
|
|
290
|
+
dynamic: true,
|
|
291
|
+
description: 'The text to display. Bind to the data model with { path } for live values.'
|
|
292
|
+
},
|
|
293
|
+
variant: {
|
|
294
|
+
kind: 'enum',
|
|
295
|
+
values: ['h1', 'h2', 'h3', 'h4', 'h5', 'body', 'caption'],
|
|
296
|
+
default: 'body',
|
|
297
|
+
description: 'Typographic role. h1–h5 are headings; caption is small secondary text; body is default.'
|
|
298
|
+
}
|
|
299
|
+
})
|
|
300
|
+
},
|
|
301
|
+
RichText: {
|
|
302
|
+
category: 'Text',
|
|
303
|
+
description: 'Displays formatted prose from Markdown (bold, italic, lists, code, and links). Links are gated by the host URL policy. Use this — NOT Text — whenever you need any formatting.',
|
|
304
|
+
props: withCommon({
|
|
305
|
+
content: {
|
|
306
|
+
kind: 'string',
|
|
307
|
+
required: true,
|
|
308
|
+
dynamic: true,
|
|
309
|
+
description: 'The Markdown source. Bind with { path } for live values. Images are blocked; links follow the host policy.'
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
},
|
|
313
|
+
// ── Form ──────────────────────────────────────────────────────────────────
|
|
314
|
+
Button: {
|
|
315
|
+
category: 'Form',
|
|
316
|
+
urbicon: 'Button',
|
|
317
|
+
description: 'A clickable button. Its `child` is the label (a Text). `action` MUST be a server event. Use `intent` for meaning (primary CTA, danger action) and `variant` for emphasis.',
|
|
318
|
+
props: withCommon({
|
|
319
|
+
child: {
|
|
320
|
+
kind: 'childId',
|
|
321
|
+
required: true,
|
|
322
|
+
description: 'The ID of the label component (usually a Text). For an icon-only button pass an Icon ID. Never inline the child.'
|
|
323
|
+
},
|
|
324
|
+
action: {
|
|
325
|
+
kind: 'action',
|
|
326
|
+
required: true,
|
|
327
|
+
description: 'The interaction handler. Use the server-event form { event: { name, context } }. Resolve dynamic context values with { path } bindings; use literals for static values.'
|
|
328
|
+
},
|
|
329
|
+
intent: intentProp('neutral', 'Semantic intent. primary is the main call to action; danger a destructive action; success/warning as appropriate.'),
|
|
330
|
+
variant: {
|
|
331
|
+
kind: 'enum',
|
|
332
|
+
values: ['filled', 'ghost', 'outlined', 'text'],
|
|
333
|
+
default: 'filled',
|
|
334
|
+
axis: 'variant',
|
|
335
|
+
description: 'Emphasis. filled is solid; outlined is bordered; ghost is subtle; text is link-like.'
|
|
336
|
+
},
|
|
337
|
+
size: sizeProp('Button size.'),
|
|
338
|
+
disabled: {
|
|
339
|
+
kind: 'boolean',
|
|
340
|
+
dynamic: true,
|
|
341
|
+
description: 'Whether the button is disabled. Bind with { path } to gate on data-model state.'
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
},
|
|
345
|
+
Input: {
|
|
346
|
+
category: 'Form',
|
|
347
|
+
urbicon: 'Input',
|
|
348
|
+
description: 'A single-line text input. `label` is required. Bind `value` to a data-model path for two-way binding (typing writes to the model immediately). Report a field error via `error`.',
|
|
349
|
+
props: withCommon({
|
|
350
|
+
label: { kind: 'string', required: true, dynamic: true, description: 'The field label.' },
|
|
351
|
+
value: {
|
|
352
|
+
kind: 'string',
|
|
353
|
+
dynamic: true,
|
|
354
|
+
description: 'The field value. Bind with { path } for two-way binding.'
|
|
355
|
+
},
|
|
356
|
+
placeholder: { kind: 'string', dynamic: true, description: 'Placeholder text when empty.' },
|
|
357
|
+
inputType: {
|
|
358
|
+
kind: 'enum',
|
|
359
|
+
values: ['text', 'email', 'number', 'tel', 'url', 'password'],
|
|
360
|
+
default: 'text',
|
|
361
|
+
description: 'The input type (controls the keyboard and validation).'
|
|
362
|
+
},
|
|
363
|
+
error: {
|
|
364
|
+
kind: 'string',
|
|
365
|
+
dynamic: true,
|
|
366
|
+
description: 'A validation error message. When non-empty the field renders in the danger intent with the message below.'
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
},
|
|
370
|
+
Textarea: {
|
|
371
|
+
category: 'Form',
|
|
372
|
+
urbicon: 'Textarea',
|
|
373
|
+
description: 'A multi-line text input. `label` is required. Bind `value` for two-way binding. Report a field error via `error`.',
|
|
374
|
+
props: withCommon({
|
|
375
|
+
label: { kind: 'string', required: true, dynamic: true, description: 'The field label.' },
|
|
376
|
+
value: {
|
|
377
|
+
kind: 'string',
|
|
378
|
+
dynamic: true,
|
|
379
|
+
description: 'The field value. Bind with { path } for two-way binding.'
|
|
380
|
+
},
|
|
381
|
+
placeholder: { kind: 'string', dynamic: true, description: 'Placeholder text when empty.' },
|
|
382
|
+
rows: { kind: 'number', description: 'Visible number of text rows.' },
|
|
383
|
+
error: {
|
|
384
|
+
kind: 'string',
|
|
385
|
+
dynamic: true,
|
|
386
|
+
description: 'A validation error message; non-empty renders the field in the danger intent.'
|
|
387
|
+
}
|
|
388
|
+
})
|
|
389
|
+
},
|
|
390
|
+
Checkbox: {
|
|
391
|
+
category: 'Form',
|
|
392
|
+
urbicon: 'Checkbox',
|
|
393
|
+
description: 'A single boolean checkbox with a label. Bind `value` to a data-model boolean for two-way binding.',
|
|
394
|
+
props: withCommon({
|
|
395
|
+
label: {
|
|
396
|
+
kind: 'string',
|
|
397
|
+
required: true,
|
|
398
|
+
dynamic: true,
|
|
399
|
+
description: 'The text shown next to the checkbox.'
|
|
400
|
+
},
|
|
401
|
+
value: {
|
|
402
|
+
kind: 'boolean',
|
|
403
|
+
required: true,
|
|
404
|
+
dynamic: true,
|
|
405
|
+
description: 'The checked state. Bind with { path } for two-way binding.'
|
|
406
|
+
}
|
|
407
|
+
})
|
|
408
|
+
},
|
|
409
|
+
RadioGroup: {
|
|
410
|
+
category: 'Form',
|
|
411
|
+
urbicon: 'RadioGroup',
|
|
412
|
+
description: 'Single-choice selection from a list of options. Bind `value` to the selected option value (a single string).',
|
|
413
|
+
props: withCommon({
|
|
414
|
+
options: {
|
|
415
|
+
kind: 'options',
|
|
416
|
+
required: true,
|
|
417
|
+
dynamic: true,
|
|
418
|
+
description: 'The available options as an array of { label, value } objects; `value` is a stable string. Bind it when the options come from data you fetched.'
|
|
419
|
+
},
|
|
420
|
+
value: {
|
|
421
|
+
kind: 'string',
|
|
422
|
+
required: true,
|
|
423
|
+
dynamic: true,
|
|
424
|
+
description: 'The selected option value. Bind with { path } for two-way binding.'
|
|
425
|
+
},
|
|
426
|
+
label: { kind: 'string', dynamic: true, description: 'An optional label for the group.' },
|
|
427
|
+
orientation: {
|
|
428
|
+
kind: 'enum',
|
|
429
|
+
values: ['horizontal', 'vertical'],
|
|
430
|
+
default: 'vertical',
|
|
431
|
+
axis: 'orientation',
|
|
432
|
+
description: 'Layout direction of the radio items.'
|
|
433
|
+
}
|
|
434
|
+
})
|
|
435
|
+
},
|
|
436
|
+
Select: {
|
|
437
|
+
category: 'Form',
|
|
438
|
+
urbicon: 'Select',
|
|
439
|
+
description: 'A dropdown select. Bind `value` to a data-model STRING ARRAY (single-select writes a one-element array). Set `multiple` for multi-select.',
|
|
440
|
+
props: withCommon({
|
|
441
|
+
options: {
|
|
442
|
+
kind: 'options',
|
|
443
|
+
required: true,
|
|
444
|
+
dynamic: true,
|
|
445
|
+
description: 'The options as an array of { label, value } objects; `value` is a stable string. Bind it when the options come from data you fetched.'
|
|
446
|
+
},
|
|
447
|
+
value: {
|
|
448
|
+
kind: 'stringList',
|
|
449
|
+
required: true,
|
|
450
|
+
dynamic: true,
|
|
451
|
+
description: 'The selected values as a string array in the data model. Single-select writes a one-element array.'
|
|
452
|
+
},
|
|
453
|
+
multiple: {
|
|
454
|
+
kind: 'boolean',
|
|
455
|
+
default: false,
|
|
456
|
+
description: 'Allow selecting several options.'
|
|
457
|
+
},
|
|
458
|
+
label: { kind: 'string', dynamic: true, description: 'An optional label for the select.' },
|
|
459
|
+
placeholder: {
|
|
460
|
+
kind: 'string',
|
|
461
|
+
dynamic: true,
|
|
462
|
+
description: 'Placeholder when nothing is selected.'
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
},
|
|
466
|
+
Slider: {
|
|
467
|
+
category: 'Form',
|
|
468
|
+
urbicon: 'Slider',
|
|
469
|
+
description: 'A numeric slider. `value` and `max` are required (`min` defaults to 0). Bind `value` for two-way binding.',
|
|
470
|
+
props: withCommon({
|
|
471
|
+
value: {
|
|
472
|
+
kind: 'number',
|
|
473
|
+
required: true,
|
|
474
|
+
dynamic: true,
|
|
475
|
+
description: 'The current value. Bind with { path } for two-way binding.'
|
|
476
|
+
},
|
|
477
|
+
max: { kind: 'number', required: true, description: 'The maximum value.' },
|
|
478
|
+
min: { kind: 'number', default: 0, description: 'The minimum value (default 0).' },
|
|
479
|
+
step: { kind: 'number', description: 'The step increment.' },
|
|
480
|
+
label: { kind: 'string', dynamic: true, description: 'An optional label for the slider.' }
|
|
481
|
+
})
|
|
482
|
+
},
|
|
483
|
+
Toggle: {
|
|
484
|
+
category: 'Form',
|
|
485
|
+
urbicon: 'Toggle',
|
|
486
|
+
description: 'An on/off switch with a label. Bind `value` to a data-model boolean for two-way binding.',
|
|
487
|
+
props: withCommon({
|
|
488
|
+
label: {
|
|
489
|
+
kind: 'string',
|
|
490
|
+
required: true,
|
|
491
|
+
dynamic: true,
|
|
492
|
+
description: 'The text shown next to the switch.'
|
|
493
|
+
},
|
|
494
|
+
value: {
|
|
495
|
+
kind: 'boolean',
|
|
496
|
+
required: true,
|
|
497
|
+
dynamic: true,
|
|
498
|
+
description: 'The on/off state. Bind with { path } for two-way binding.'
|
|
499
|
+
}
|
|
500
|
+
})
|
|
501
|
+
},
|
|
502
|
+
DatePicker: {
|
|
503
|
+
category: 'Form',
|
|
504
|
+
urbicon: 'DatePicker',
|
|
505
|
+
description: 'A calendar date input. `value` is an ISO date STRING (YYYY-MM-DD, "" when unset). Bind `value` for two-way binding; initialize the bound path with "".',
|
|
506
|
+
props: withCommon({
|
|
507
|
+
value: {
|
|
508
|
+
kind: 'string',
|
|
509
|
+
required: true,
|
|
510
|
+
dynamic: true,
|
|
511
|
+
description: 'The ISO date (YYYY-MM-DD, "" when unset). Bind with { path } for two-way binding.'
|
|
512
|
+
},
|
|
513
|
+
label: { kind: 'string', dynamic: true, description: 'The field label.' },
|
|
514
|
+
min: { kind: 'string', dynamic: true, description: 'Minimum allowed date (YYYY-MM-DD).' },
|
|
515
|
+
max: { kind: 'string', dynamic: true, description: 'Maximum allowed date (YYYY-MM-DD).' },
|
|
516
|
+
error: {
|
|
517
|
+
kind: 'string',
|
|
518
|
+
dynamic: true,
|
|
519
|
+
description: 'A validation error message; non-empty renders the field in the danger intent.'
|
|
520
|
+
}
|
|
521
|
+
})
|
|
522
|
+
},
|
|
523
|
+
TimeInput: {
|
|
524
|
+
category: 'Form',
|
|
525
|
+
urbicon: 'TimeInput',
|
|
526
|
+
description: 'A time-of-day input. `value` is an ISO time STRING (HH:MM, "" when unset). Bind `value` for two-way binding; initialize the bound path with "".',
|
|
527
|
+
props: withCommon({
|
|
528
|
+
value: {
|
|
529
|
+
kind: 'string',
|
|
530
|
+
required: true,
|
|
531
|
+
dynamic: true,
|
|
532
|
+
description: 'The ISO time (HH:MM, "" when unset). Bind with { path } for two-way binding.'
|
|
533
|
+
},
|
|
534
|
+
label: { kind: 'string', dynamic: true, description: 'The field label.' },
|
|
535
|
+
min: { kind: 'string', dynamic: true, description: 'Minimum allowed time (HH:MM).' },
|
|
536
|
+
max: { kind: 'string', dynamic: true, description: 'Maximum allowed time (HH:MM).' },
|
|
537
|
+
error: {
|
|
538
|
+
kind: 'string',
|
|
539
|
+
dynamic: true,
|
|
540
|
+
description: 'A validation error message; non-empty renders the field in the danger intent.'
|
|
541
|
+
}
|
|
542
|
+
})
|
|
543
|
+
},
|
|
544
|
+
// ── Status / Media ──────────────────────────────────────────────────────────
|
|
545
|
+
Badge: {
|
|
546
|
+
category: 'Status',
|
|
547
|
+
urbicon: 'Badge',
|
|
548
|
+
description: 'A small status/label pill. Its `text` is the label. Use `intent` for meaning and `variant` for style.',
|
|
549
|
+
props: withCommon({
|
|
550
|
+
text: {
|
|
551
|
+
kind: 'string',
|
|
552
|
+
required: true,
|
|
553
|
+
dynamic: true,
|
|
554
|
+
description: 'The badge label. Bind with { path } for a live value.'
|
|
555
|
+
},
|
|
556
|
+
intent: intentProp('primary', 'Semantic intent (colour) of the badge.'),
|
|
557
|
+
variant: {
|
|
558
|
+
kind: 'enum',
|
|
559
|
+
values: ['filled', 'soft', 'outlined', 'dot'],
|
|
560
|
+
default: 'filled',
|
|
561
|
+
axis: 'variant',
|
|
562
|
+
description: 'Fill style. dot renders a leading status dot before the label.'
|
|
563
|
+
}
|
|
564
|
+
})
|
|
565
|
+
},
|
|
566
|
+
Alert: {
|
|
567
|
+
category: 'Status',
|
|
568
|
+
urbicon: 'Alert',
|
|
569
|
+
description: 'A prominent inline message (info/success/warning/danger). `title` is required; add a `child` for rich body content. Use the `info` intent for neutral notices.',
|
|
570
|
+
props: withCommon({
|
|
571
|
+
title: {
|
|
572
|
+
kind: 'string',
|
|
573
|
+
required: true,
|
|
574
|
+
dynamic: true,
|
|
575
|
+
description: 'The alert heading. Bind with { path } for a live value.'
|
|
576
|
+
},
|
|
577
|
+
description: {
|
|
578
|
+
kind: 'string',
|
|
579
|
+
dynamic: true,
|
|
580
|
+
description: 'Optional supporting text under the title.'
|
|
581
|
+
},
|
|
582
|
+
child: {
|
|
583
|
+
kind: 'childId',
|
|
584
|
+
description: 'Optional rich body child ID (e.g. a Column of controls). Never inline the child.'
|
|
585
|
+
},
|
|
586
|
+
intent: {
|
|
587
|
+
kind: 'enum',
|
|
588
|
+
values: ['info', 'success', 'warning', 'danger', 'primary', 'neutral'],
|
|
589
|
+
default: 'primary',
|
|
590
|
+
axis: 'intent',
|
|
591
|
+
description: 'Semantic intent. info is a neutral notice; danger a critical error.'
|
|
592
|
+
},
|
|
593
|
+
variant: {
|
|
594
|
+
kind: 'enum',
|
|
595
|
+
values: ['soft', 'filled', 'inline'],
|
|
596
|
+
default: 'soft',
|
|
597
|
+
axis: 'variant',
|
|
598
|
+
description: 'Emphasis. soft is tinted; filled is solid; inline is compact.'
|
|
599
|
+
}
|
|
600
|
+
})
|
|
601
|
+
},
|
|
602
|
+
Progress: {
|
|
603
|
+
category: 'Status',
|
|
604
|
+
urbicon: 'Progress',
|
|
605
|
+
description: 'A progress bar. Bind `value` (0..max) for live progress, or set `indeterminate` for an unknown-duration pulse.',
|
|
606
|
+
props: withCommon({
|
|
607
|
+
value: {
|
|
608
|
+
kind: 'number',
|
|
609
|
+
dynamic: true,
|
|
610
|
+
description: 'The current progress (0..max). Bind with { path } for live updates.'
|
|
611
|
+
},
|
|
612
|
+
max: { kind: 'number', default: 100, description: 'The maximum value (default 100).' },
|
|
613
|
+
indeterminate: {
|
|
614
|
+
kind: 'boolean',
|
|
615
|
+
default: false,
|
|
616
|
+
description: 'Show an indeterminate (unknown-duration) animation instead of a value.'
|
|
617
|
+
},
|
|
618
|
+
intent: intentProp('primary', 'Semantic intent (colour) of the bar.'),
|
|
619
|
+
label: { kind: 'string', dynamic: true, description: 'An optional label above the bar.' }
|
|
620
|
+
})
|
|
621
|
+
},
|
|
622
|
+
Stepper: {
|
|
623
|
+
category: 'Status',
|
|
624
|
+
urbicon: 'Stepper',
|
|
625
|
+
description: 'A read-only progress indicator across ordered steps. `steps` are the step labels; `current` is the zero-based active step index.',
|
|
626
|
+
props: withCommon({
|
|
627
|
+
steps: {
|
|
628
|
+
kind: 'stringList',
|
|
629
|
+
required: true,
|
|
630
|
+
description: 'The ordered step labels as a string array.'
|
|
631
|
+
},
|
|
632
|
+
current: {
|
|
633
|
+
kind: 'number',
|
|
634
|
+
dynamic: true,
|
|
635
|
+
description: 'The zero-based index of the active step. Bind with { path } for live progress.'
|
|
636
|
+
},
|
|
637
|
+
orientation: {
|
|
638
|
+
kind: 'enum',
|
|
639
|
+
values: ['horizontal', 'vertical'],
|
|
640
|
+
default: 'horizontal',
|
|
641
|
+
axis: 'orientation',
|
|
642
|
+
description: 'Layout direction of the steps.'
|
|
643
|
+
},
|
|
644
|
+
variant: {
|
|
645
|
+
kind: 'enum',
|
|
646
|
+
values: ['default', 'minimal', 'outlined'],
|
|
647
|
+
default: 'default',
|
|
648
|
+
axis: 'variant',
|
|
649
|
+
description: 'Visual style of the step markers.'
|
|
650
|
+
}
|
|
651
|
+
})
|
|
652
|
+
},
|
|
653
|
+
Accordion: {
|
|
654
|
+
category: 'Layout',
|
|
655
|
+
urbicon: 'Accordion',
|
|
656
|
+
description: 'A vertical list of collapsible sections. `items` is an array of { label, child }: the label is the header, the child is the panel body (a component ID). Set `multiple` to allow several open at once.',
|
|
657
|
+
props: withCommon({
|
|
658
|
+
items: {
|
|
659
|
+
kind: 'labeledChildren',
|
|
660
|
+
required: true,
|
|
661
|
+
description: 'The sections as an array of { label, child }. label is the header text; child is the panel body component ID (never inlined).'
|
|
662
|
+
},
|
|
663
|
+
multiple: {
|
|
664
|
+
kind: 'boolean',
|
|
665
|
+
default: false,
|
|
666
|
+
description: 'Allow more than one section open at the same time.'
|
|
667
|
+
},
|
|
668
|
+
variant: {
|
|
669
|
+
kind: 'enum',
|
|
670
|
+
values: ['default', 'card', 'ghost'],
|
|
671
|
+
default: 'default',
|
|
672
|
+
axis: 'variant',
|
|
673
|
+
description: 'Visual style of the accordion.'
|
|
674
|
+
}
|
|
675
|
+
})
|
|
676
|
+
},
|
|
677
|
+
Avatar: {
|
|
678
|
+
category: 'Media',
|
|
679
|
+
urbicon: 'Avatar',
|
|
680
|
+
description: 'A user/entity avatar. Provide `src` (an image URL, subject to the host policy) and/or `name` (initials fallback). Choose `variant` for shape and `size`.',
|
|
681
|
+
props: withCommon({
|
|
682
|
+
src: {
|
|
683
|
+
kind: 'string',
|
|
684
|
+
dynamic: true,
|
|
685
|
+
description: 'The image URL (blocked by default unless the host allows the source).'
|
|
686
|
+
},
|
|
687
|
+
name: {
|
|
688
|
+
kind: 'string',
|
|
689
|
+
dynamic: true,
|
|
690
|
+
description: 'A name used for initials and the accessible label when no image loads.'
|
|
691
|
+
},
|
|
692
|
+
variant: {
|
|
693
|
+
kind: 'enum',
|
|
694
|
+
values: ['circle', 'rounded', 'square'],
|
|
695
|
+
default: 'circle',
|
|
696
|
+
axis: 'variant',
|
|
697
|
+
description: 'Shape of the avatar.'
|
|
698
|
+
},
|
|
699
|
+
size: sizeProp('Avatar size.')
|
|
700
|
+
})
|
|
701
|
+
},
|
|
702
|
+
Icon: {
|
|
703
|
+
category: 'Media',
|
|
704
|
+
description: 'Displays a named icon from the mapped set. Use `name` with one of the supported names; unknown names fall back to a generic glyph.',
|
|
705
|
+
props: withCommon({
|
|
706
|
+
name: {
|
|
707
|
+
kind: 'icon',
|
|
708
|
+
required: true,
|
|
709
|
+
values: URBICON_A2UI_ICON_NAMES,
|
|
710
|
+
description: 'The icon name (one of the supported names). May also bind to the data model with { path }. Custom vector art via { svgPath } is accepted but discouraged.'
|
|
711
|
+
}
|
|
712
|
+
})
|
|
713
|
+
},
|
|
714
|
+
Image: {
|
|
715
|
+
category: 'Media',
|
|
716
|
+
description: 'Displays an image from a URL. Images are blocked by default unless the host allows the source — provide a meaningful `description` so a blocked image still conveys meaning.',
|
|
717
|
+
props: withCommon({
|
|
718
|
+
url: {
|
|
719
|
+
kind: 'string',
|
|
720
|
+
required: true,
|
|
721
|
+
dynamic: true,
|
|
722
|
+
description: 'The image URL. Subject to the host URL policy (blocked by default).'
|
|
723
|
+
},
|
|
724
|
+
description: {
|
|
725
|
+
kind: 'string',
|
|
726
|
+
dynamic: true,
|
|
727
|
+
description: 'Alt text describing the image for accessibility and when the image is blocked.'
|
|
728
|
+
},
|
|
729
|
+
fit: {
|
|
730
|
+
kind: 'enum',
|
|
731
|
+
values: ['contain', 'cover', 'fill', 'none', 'scaleDown'],
|
|
732
|
+
default: 'cover',
|
|
733
|
+
description: 'How the image resizes to fit its box (CSS object-fit).'
|
|
734
|
+
},
|
|
735
|
+
variant: {
|
|
736
|
+
kind: 'enum',
|
|
737
|
+
values: ['icon', 'avatar', 'smallFeature', 'mediumFeature', 'largeFeature', 'header'],
|
|
738
|
+
default: 'mediumFeature',
|
|
739
|
+
description: 'Size/style preset for the image.'
|
|
740
|
+
}
|
|
741
|
+
})
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
/**
|
|
745
|
+
* Heuristic for "this looks like Markdown" — bold, inline code, a link, or an
|
|
746
|
+
* ATX heading. Conservative (a stray `*` won't trip it) so the MARKDOWN_IN_TEXT
|
|
747
|
+
* warning stays a helpful nudge toward RichText, not noise.
|
|
748
|
+
*/
|
|
749
|
+
const MARKDOWN_HINT_RE = /(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\([^)]+\)|^#{1,6}\s)/m;
|
|
750
|
+
/**
|
|
751
|
+
* The Urbicon catalog, spec half (Svelte-free — a server building the prompt can
|
|
752
|
+
* import this). The Svelte wiring (`Node`, `createIcons`) is added in
|
|
753
|
+
* `a2ui-urbicon-catalog.ts`. `flexContainers` and the layered check semantics
|
|
754
|
+
* mirror the Basic catalog; the sole catalog-specific check nudges the agent
|
|
755
|
+
* from plain `Text` toward `RichText` when it emits Markdown.
|
|
756
|
+
*/
|
|
757
|
+
export const urbiconA2uiCatalogSpec = {
|
|
758
|
+
catalogId: URBICON_A2UI_CATALOG_ID,
|
|
759
|
+
registry: URBICON_A2UI_REGISTRY,
|
|
760
|
+
iconNames: URBICON_A2UI_ICON_NAMES,
|
|
761
|
+
unsupportedComponents: UNSUPPORTED_URBICON_A2UI_COMPONENTS,
|
|
762
|
+
ignoredProps: URBICON_A2UI_IGNORED_PROPS,
|
|
763
|
+
flexContainers: new Set(['Row', 'Column']),
|
|
764
|
+
componentChecks: {
|
|
765
|
+
Text: ({ id, props, surfaceId, base }) => {
|
|
766
|
+
const value = props.get('text');
|
|
767
|
+
if (typeof value === 'string' && MARKDOWN_HINT_RE.test(value)) {
|
|
768
|
+
return [
|
|
769
|
+
{
|
|
770
|
+
severity: 'warning',
|
|
771
|
+
code: A2UI_ISSUE_CODES.MARKDOWN_IN_TEXT,
|
|
772
|
+
message: `Text "${id}" contains Markdown syntax, but Text renders PLAIN — use RichText for formatting`,
|
|
773
|
+
surfaceId,
|
|
774
|
+
path: base
|
|
775
|
+
}
|
|
776
|
+
];
|
|
777
|
+
}
|
|
778
|
+
return [];
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
/** The axis truth this registry couples to — re-exported for the drift test. */
|
|
783
|
+
export { URBICON_AXES } from './urbicon-axes.gen.js';
|