@svgrid/enterprise 2.3.0 → 2.3.2
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/cdn/{pdfmake-C6pyKjX0.js → pdfmake-DVbZqKeD.js} +2297 -2327
- package/dist/cdn/rolldown-runtime-DtPi1Y-2.js +13 -0
- package/dist/cdn/{smart.export-CfW2zpyq.js → smart.export-D9FF4wAB.js} +54 -51
- package/dist/cdn/svgrid-enterprise.svelte-external.js +11308 -7898
- package/dist/cdn/{vfs_fonts-BktEULEs.js → vfs_fonts-iHMTEkpG.js} +1 -1
- package/dist/designer/assets/GridMenus-CW-rnHS9.js +7 -0
- package/dist/designer/assets/SvDateTimePicker-Cygij-dr.css +1 -0
- package/dist/designer/assets/SvDateTimePicker-DOBYyLeN.js +1 -0
- package/dist/designer/assets/SvGridChart-BEDNTdc5.js +2 -0
- package/dist/designer/assets/SvGridChart-Vu4Nvjiv.css +1 -0
- package/dist/designer/assets/SvGridChartPanel-x3lzSxuf.js +10 -0
- package/dist/designer/assets/SvGridChartView-CAKhPELi.js +1 -0
- package/dist/designer/assets/SvGridChartView-DX9HfkBR.css +1 -0
- package/dist/designer/assets/SvGridDropdown-CAYG7Y-O.js +1 -0
- package/dist/designer/assets/SvGridDropdown-Crwb2P3Q.css +1 -0
- package/dist/designer/assets/SvListBox-BMSfFJJT.css +1 -0
- package/dist/designer/assets/SvListBox-BVzVfCG3.js +1 -0
- package/dist/designer/assets/chart-DHEgt4lN.js +1 -0
- package/dist/designer/assets/disclose-version-CIm4S9xS.js +2 -0
- package/dist/designer/assets/dismissable-2EZKoens.js +1 -0
- package/dist/designer/assets/dismissable-BF-9TJSd.css +1 -0
- package/dist/designer/assets/easing-zaypKrr0.js +3 -0
- package/dist/designer/assets/export-format-DwjuTfrQ.js +6 -0
- package/dist/designer/assets/index-DVrv9dH6.js +75797 -0
- package/dist/designer/assets/index-DjPp1mn7.css +1 -0
- package/dist/designer/assets/js-scroller.svelte-tHanKJx0.js +110 -0
- package/dist/designer/assets/jszip.min-CX2fPs3O.js +2 -0
- package/dist/designer/assets/pdfmake-BpIYFHoG.js +242 -0
- package/dist/designer/assets/popover-CUkLsvRX.js +1 -0
- package/dist/designer/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/dist/designer/assets/smart.export-CDCwbFH4.js +37 -0
- package/dist/designer/assets/src-BRKu53tV.js +2842 -0
- package/dist/designer/assets/src-DseB1VRN.css +1 -0
- package/dist/designer/assets/vfs_fonts-BV-Ul9v2.js +1 -0
- package/dist/designer/index.html +32 -0
- package/dist/node/studio.js +16778 -12672
- package/package.json +10 -7
- package/src/SvGridBoard.svelte +4 -1
- package/src/SvGridScheduler.svelte +114 -90
- package/src/ai-export-pdf.dom.test.ts +77 -77
- package/src/ai-export-xlsx.dom.test.ts +90 -90
- package/src/ai-export.dom.test.ts +114 -114
- package/src/export-ooxml.ts +4 -0
- package/src/export-xls.ts +3 -0
- package/src/expressions/evaluate.ts +9 -0
- package/src/import.test.ts +1 -1
- package/src/import.ts +1 -1
- package/src/index.ts +12 -0
- package/src/pivot.test.ts +0 -1
- package/src/schema-designer.ts +1 -1
- package/src/sources/introspect-supabase.ts +2 -2
- package/src/studio/emit-project.test.ts +298 -7
- package/src/studio/emit-project.ts +484 -30
- package/src/studio/emit-schema.ts +20 -10
- package/src/studio/index.ts +34 -0
- package/src/studio/init-flow.test.ts +364 -0
- package/src/studio/init-flow.ts +409 -0
- package/src/studio/project.test.ts +0 -1
- package/src/studio/project.ts +109 -2
- package/src/studio/samples/datasets.test.ts +84 -0
- package/src/studio/samples/datasets.ts +340 -0
- package/src/studio/samples/live-data.test.ts +1 -1
- package/src/studio/samples/samples.test.ts +268 -268
- package/src/studio/samples/shared.ts +7 -150
- package/src/studio/screen-suites.test.ts +226 -0
- package/src/studio/screen-suites.ts +445 -0
- package/src/studio/ui-components-surface.test.ts +2 -2
- package/src/studio/ui-components.generated.ts +1643 -106
- package/src/studio/ui-components.ts +742 -641
- package/src/sveltekit/index.ts +1 -0
- package/src/sveltekit/sql-source.ts +1 -1
- package/src/sveltekit/transport-scope.test.ts +125 -0
- package/src/sveltekit/transport.ts +76 -2
|
@@ -1,641 +1,742 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A curated catalogue of SvGrid UI-kit components a Studio screen can host as a
|
|
3
|
-
* `'component'` block (see `ComponentConfig` in `project.ts`) - entity-agnostic,
|
|
4
|
-
* usable on any screen including a freestanding one. Pure metadata: no Svelte
|
|
5
|
-
* import here (this subtree stays Svelte-free), so the designer holds the live
|
|
6
|
-
* component references and this module only describes what to configure and how
|
|
7
|
-
* to generate.
|
|
8
|
-
*
|
|
9
|
-
* Only "chrome" props (scalar values a form can drive) are listed - every
|
|
10
|
-
* component's real content is typically a Svelte `Snippet`, which this registry
|
|
11
|
-
* can't represent. A component with `hasContent` gets one extra literal-text
|
|
12
|
-
* field in the property panel (stored under the reserved `_content` props key)
|
|
13
|
-
* that becomes its plain-text children in both the live preview and codegen.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { GENERATED_UI_SURFACE } from './ui-components.generated.js'
|
|
17
|
-
|
|
18
|
-
export type UiPropType = 'string' | 'number' | 'boolean' | 'select' | 'color' | 'json' | 'date'
|
|
19
|
-
|
|
20
|
-
export type UiPropGroup = 'common' | 'appearance' | 'behavior' | 'advanced'
|
|
21
|
-
|
|
22
|
-
export type UiComponentProp = {
|
|
23
|
-
key: string
|
|
24
|
-
label: string
|
|
25
|
-
type: UiPropType
|
|
26
|
-
/** Choices for `type: 'select'`. */
|
|
27
|
-
options?: string[]
|
|
28
|
-
default?: unknown
|
|
29
|
-
/** Guidance shown as the property panel tooltip - sourced from the component's
|
|
30
|
-
* own JSDoc via the extractor, so it stays true to the source. */
|
|
31
|
-
description?: string
|
|
32
|
-
/** Property-panel grouping (defaults to 'common'). */
|
|
33
|
-
group?: UiPropGroup
|
|
34
|
-
/** A function / code-only prop (e.g. loadChildren) - listed read-only, set in code. */
|
|
35
|
-
code?: boolean
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** A wireable component event: `key` is the handle event name (`ctx.x.on<key>`),
|
|
39
|
-
* `prop` the component callback prop that fires it (e.g. `onChange`). */
|
|
40
|
-
export type UiComponentEvent = { key: string; label: string; prop?: string; description?: string }
|
|
41
|
-
|
|
42
|
-
/** Standard DOM / interaction events EVERY component block can wire (VS-style full
|
|
43
|
-
* event surface) - forwarded by the generated wrapper to the block's handle. `dom`
|
|
44
|
-
* is the DOM event the wrapper listens for; `key` is the handle event name. */
|
|
45
|
-
export const STANDARD_UI_EVENTS: ReadonlyArray<{ key: string; label: string; dom: string; description: string }> = [
|
|
46
|
-
{ key: 'click', label: 'Click', dom: 'click', description: 'The component (or a child) was clicked.' },
|
|
47
|
-
{ key: 'dblclick', label: 'Double click', dom: 'dblclick', description: 'The component was double-clicked.' },
|
|
48
|
-
{ key: 'change', label: 'Change', dom: 'change', description: 'A committed value change (fires on blur for inputs).' },
|
|
49
|
-
{ key: 'input', label: 'Input', dom: 'input', description: 'Fires on every keystroke / immediate value edit.' },
|
|
50
|
-
{ key: 'focus', label: 'Focus', dom: 'focusin', description: 'The component (or a child) gained focus.' },
|
|
51
|
-
{ key: 'blur', label: 'Blur', dom: 'focusout', description: 'The component (or a child) lost focus.' },
|
|
52
|
-
{ key: 'keydown', label: 'Key down', dom: 'keydown', description: 'A key was pressed while focused.' },
|
|
53
|
-
{ key: 'keyup', label: 'Key up', dom: 'keyup', description: 'A key was released while focused.' },
|
|
54
|
-
{ key: 'contextmenu', label: 'Context menu', dom: 'contextmenu', description: 'Right-click / context-menu request.' },
|
|
55
|
-
{ key: 'mouseenter', label: 'Mouse enter', dom: 'mouseenter', description: 'The pointer entered the component.' },
|
|
56
|
-
{ key: 'mouseleave', label: 'Mouse leave', dom: 'mouseleave', description: 'The pointer left the component.' },
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
export type UiComponentSpec = {
|
|
60
|
-
/** Registry key - stored as `ComponentConfig.component`. */
|
|
61
|
-
key: string
|
|
62
|
-
label: string
|
|
63
|
-
category: string
|
|
64
|
-
/** Named export from `@svgrid/grid`. */
|
|
65
|
-
importName: string
|
|
66
|
-
/** Hand-curated prop entries. In the EXPORTED registry these are merged with
|
|
67
|
-
* the extracted full surface (ui-components.generated.ts): hand entries win
|
|
68
|
-
* by key (label/options/default), extraction supplies the rest + tooltips. */
|
|
69
|
-
props: UiComponentProp[]
|
|
70
|
-
/** Wireable events (merged with extracted function-prop events the same way). */
|
|
71
|
-
events?: UiComponentEvent[]
|
|
72
|
-
/** Extracted props to keep OUT of the property panel (edge cases). */
|
|
73
|
-
hiddenProps?: string[]
|
|
74
|
-
/** True if the component's real content is a `children` snippet - adds one
|
|
75
|
-
* literal-text field to the property panel, stored under `props._content`. */
|
|
76
|
-
hasContent?: boolean
|
|
77
|
-
contentLabel?: string
|
|
78
|
-
contentDefault?: string
|
|
79
|
-
/** Array / object props a scalar form can't express (a Timeline's `items`, a
|
|
80
|
-
* Sparkline's `data`). Each is emitted verbatim in codegen as `key={<expr>}`
|
|
81
|
-
* with a baked demo dataset the user then edits in Code view, and its `preview`
|
|
82
|
-
* value drives the live designer canvas. Not shown in the property panel. */
|
|
83
|
-
fixed?: Array<{ key: string; expr: string; preview: unknown }>
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const BASE_REGISTRY: ReadonlyArray<UiComponentSpec> = [
|
|
87
|
-
{
|
|
88
|
-
key: 'button',
|
|
89
|
-
label: 'Button',
|
|
90
|
-
category: 'Actions',
|
|
91
|
-
importName: 'SvButton',
|
|
92
|
-
props: [
|
|
93
|
-
{ key: 'variant', label: 'Variant', type: 'select', options: ['primary', 'secondary', 'outline', 'ghost', 'danger'], default: 'primary' },
|
|
94
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
95
|
-
{ key: 'block', label: 'Full width', type: 'boolean', default: false },
|
|
96
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
97
|
-
],
|
|
98
|
-
hasContent: true,
|
|
99
|
-
contentLabel: 'Label',
|
|
100
|
-
contentDefault: 'Click me',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
key: 'badge',
|
|
104
|
-
label: 'Badge',
|
|
105
|
-
category: 'Feedback',
|
|
106
|
-
importName: 'SvBadge',
|
|
107
|
-
props: [
|
|
108
|
-
{ key: 'variant', label: 'Variant', type: 'select', options: ['neutral', 'accent', 'success', 'warning', 'danger', 'info'], default: 'neutral' },
|
|
109
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md'], default: 'md' },
|
|
110
|
-
{ key: 'pill', label: 'Pill shape', type: 'boolean', default: true },
|
|
111
|
-
{ key: 'dot', label: 'Show dot', type: 'boolean', default: false },
|
|
112
|
-
],
|
|
113
|
-
hasContent: true,
|
|
114
|
-
contentLabel: 'Text',
|
|
115
|
-
contentDefault: 'Badge',
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
key: 'alert',
|
|
119
|
-
label: 'Alert',
|
|
120
|
-
category: 'Feedback',
|
|
121
|
-
importName: 'SvAlert',
|
|
122
|
-
props: [
|
|
123
|
-
{ key: 'variant', label: 'Variant', type: 'select', options: ['info', 'success', 'warning', 'danger', 'neutral'], default: 'info' },
|
|
124
|
-
{ key: 'title', label: 'Title', type: 'string' },
|
|
125
|
-
{ key: 'dismissible', label: 'Dismissible', type: 'boolean', default: false },
|
|
126
|
-
{ key: 'soft', label: 'Soft (tinted) style', type: 'boolean', default: false },
|
|
127
|
-
],
|
|
128
|
-
hasContent: true,
|
|
129
|
-
contentLabel: 'Message',
|
|
130
|
-
contentDefault: 'This is an alert message.',
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
key: 'progress',
|
|
134
|
-
label: 'Progress bar',
|
|
135
|
-
category: 'Feedback',
|
|
136
|
-
importName: 'SvProgress',
|
|
137
|
-
props: [
|
|
138
|
-
{ key: 'value', label: 'Value', type: 'number', default: 60 },
|
|
139
|
-
{ key: 'max', label: 'Max', type: 'number', default: 100 },
|
|
140
|
-
{ key: 'color', label: 'Color', type: 'select', options: ['accent', 'success', 'warning', 'danger'], default: 'accent' },
|
|
141
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
142
|
-
{ key: 'showLabel', label: 'Show percentage', type: 'boolean', default: false },
|
|
143
|
-
{ key: 'striped', label: 'Striped', type: 'boolean', default: false },
|
|
144
|
-
],
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
key: 'card',
|
|
148
|
-
label: 'Card',
|
|
149
|
-
category: 'Layout',
|
|
150
|
-
importName: 'SvCard',
|
|
151
|
-
props: [
|
|
152
|
-
{ key: 'title', label: 'Title', type: 'string', default: 'Card title' },
|
|
153
|
-
{ key: 'subtitle', label: 'Subtitle', type: 'string' },
|
|
154
|
-
{ key: 'hoverable', label: 'Hover elevation', type: 'boolean', default: false },
|
|
155
|
-
{ key: 'flush', label: 'Flush padding', type: 'boolean', default: false },
|
|
156
|
-
],
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
key: 'divider',
|
|
160
|
-
label: 'Divider',
|
|
161
|
-
category: 'Layout',
|
|
162
|
-
importName: 'SvDivider',
|
|
163
|
-
props: [
|
|
164
|
-
{ key: 'orientation', label: 'Orientation', type: 'select', options: ['horizontal', 'vertical'], default: 'horizontal' },
|
|
165
|
-
{ key: 'label', label: 'Label', type: 'string' },
|
|
166
|
-
{ key: 'align', label: 'Label align', type: 'select', options: ['start', 'center', 'end'], default: 'center' },
|
|
167
|
-
{ key: 'dashed', label: 'Dashed', type: 'boolean', default: false },
|
|
168
|
-
],
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
key: 'avatar',
|
|
172
|
-
label: 'Avatar',
|
|
173
|
-
category: 'Display',
|
|
174
|
-
importName: 'SvAvatar',
|
|
175
|
-
props: [
|
|
176
|
-
{ key: 'name', label: 'Name', type: 'string', default: 'Jordan Lee' },
|
|
177
|
-
{ key: 'src', label: 'Image URL', type: 'string' },
|
|
178
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
179
|
-
{ key: 'shape', label: 'Shape', type: 'select', options: ['circle', 'square'], default: 'circle' },
|
|
180
|
-
{ key: 'status', label: 'Status', type: 'select', options: ['', 'online', 'offline', 'busy', 'away'], default: '' },
|
|
181
|
-
{ key: 'color', label: 'Color override', type: 'color' },
|
|
182
|
-
],
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
key: 'stat',
|
|
186
|
-
label: 'Stat',
|
|
187
|
-
category: 'Display',
|
|
188
|
-
importName: 'SvStat',
|
|
189
|
-
props: [
|
|
190
|
-
{ key: 'label', label: 'Label', type: 'string', default: 'Revenue' },
|
|
191
|
-
{ key: 'value', label: 'Value', type: 'string', default: '$48,200' },
|
|
192
|
-
{ key: 'delta', label: 'Delta', type: 'string' },
|
|
193
|
-
{ key: 'trend', label: 'Trend', type: 'select', options: ['', 'up', 'down', 'flat'], default: '' },
|
|
194
|
-
{ key: 'hint', label: 'Hint', type: 'string' },
|
|
195
|
-
{ key: 'invert', label: 'Invert trend colors', type: 'boolean', default: false },
|
|
196
|
-
],
|
|
197
|
-
},
|
|
198
|
-
|
|
199
|
-
// --- Actions -------------------------------------------------------------
|
|
200
|
-
{
|
|
201
|
-
key: 'toggle-button',
|
|
202
|
-
label: 'Toggle button',
|
|
203
|
-
category: 'Actions',
|
|
204
|
-
importName: 'SvToggleButton',
|
|
205
|
-
props: [
|
|
206
|
-
{ key: 'pressed', label: 'Pressed', type: 'boolean', default: false },
|
|
207
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
208
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
209
|
-
],
|
|
210
|
-
hasContent: true,
|
|
211
|
-
contentLabel: 'Label',
|
|
212
|
-
contentDefault: 'Toggle',
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
key: 'switch',
|
|
216
|
-
label: 'Switch',
|
|
217
|
-
category: 'Actions',
|
|
218
|
-
importName: 'SvSwitchButton',
|
|
219
|
-
props: [
|
|
220
|
-
{ key: 'checked', label: 'On', type: 'boolean', default: true },
|
|
221
|
-
{ key: 'label', label: 'Field label', type: 'string' },
|
|
222
|
-
{ key: 'onLabel', label: 'On label', type: 'string', default: 'On' },
|
|
223
|
-
{ key: 'offLabel', label: 'Off label', type: 'string', default: 'Off' },
|
|
224
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
225
|
-
],
|
|
226
|
-
},
|
|
227
|
-
|
|
228
|
-
// --- Inputs --------------------------------------------------------------
|
|
229
|
-
{
|
|
230
|
-
key: 'text-input',
|
|
231
|
-
label: 'Text input',
|
|
232
|
-
category: 'Inputs',
|
|
233
|
-
importName: 'SvTextInput',
|
|
234
|
-
props: [
|
|
235
|
-
{ key: 'label', label: 'Label', type: 'string', default: 'Name' },
|
|
236
|
-
{ key: 'placeholder', label: 'Placeholder', type: 'string', default: 'Type here…' },
|
|
237
|
-
{ key: 'type', label: 'Type', type: 'select', options: ['text', 'email', 'url', 'tel', 'search'], default: 'text' },
|
|
238
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
239
|
-
{ key: 'clearable', label: 'Clearable', type: 'boolean', default: false },
|
|
240
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
241
|
-
{ key: 'readonly', label: 'Read only', type: 'boolean', default: false },
|
|
242
|
-
],
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
key: 'textarea',
|
|
246
|
-
label: 'Text area',
|
|
247
|
-
category: 'Inputs',
|
|
248
|
-
importName: 'SvTextArea',
|
|
249
|
-
props: [
|
|
250
|
-
{ key: 'label', label: 'Label', type: 'string', default: 'Notes' },
|
|
251
|
-
{ key: 'placeholder', label: 'Placeholder', type: 'string', default: 'Write something…' },
|
|
252
|
-
{ key: 'rows', label: 'Rows', type: 'number', default: 3 },
|
|
253
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
254
|
-
],
|
|
255
|
-
},
|
|
256
|
-
{
|
|
257
|
-
key: 'number-input',
|
|
258
|
-
label: 'Number input',
|
|
259
|
-
category: 'Inputs',
|
|
260
|
-
importName: 'SvNumberInput',
|
|
261
|
-
props: [
|
|
262
|
-
{ key: 'label', label: 'Label', type: 'string', default: 'Amount' },
|
|
263
|
-
{ key: 'placeholder', label: 'Placeholder', type: 'string' },
|
|
264
|
-
{ key: 'min', label: 'Min', type: 'number' },
|
|
265
|
-
{ key: 'max', label: 'Max', type: 'number' },
|
|
266
|
-
{ key: 'step', label: 'Step', type: 'number', default: 1 },
|
|
267
|
-
{ key: 'prefix', label: 'Prefix', type: 'string' },
|
|
268
|
-
{ key: 'suffix', label: 'Suffix', type: 'string' },
|
|
269
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
270
|
-
],
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
key: 'password-input',
|
|
274
|
-
label: 'Password input',
|
|
275
|
-
category: 'Inputs',
|
|
276
|
-
importName: 'SvPasswordInput',
|
|
277
|
-
props: [
|
|
278
|
-
{ key: 'label', label: 'Label', type: 'string', default: 'Password' },
|
|
279
|
-
{ key: 'placeholder', label: 'Placeholder', type: 'string', default: '••••••••' },
|
|
280
|
-
{ key: 'revealable', label: 'Reveal toggle', type: 'boolean', default: true },
|
|
281
|
-
{ key: 'showStrength', label: 'Strength meter', type: 'boolean', default: false },
|
|
282
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
283
|
-
],
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
key: 'color-input',
|
|
287
|
-
label: 'Color input',
|
|
288
|
-
category: 'Inputs',
|
|
289
|
-
importName: 'SvColorInput',
|
|
290
|
-
props: [
|
|
291
|
-
{ key: 'label', label: 'Label', type: 'string', default: 'Brand color' },
|
|
292
|
-
{ key: 'value', label: 'Value', type: 'color', default: '#6366f1' },
|
|
293
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
294
|
-
],
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
key: 'checkbox',
|
|
298
|
-
label: 'Checkbox',
|
|
299
|
-
category: 'Inputs',
|
|
300
|
-
importName: 'SvCheckBox',
|
|
301
|
-
props: [
|
|
302
|
-
{ key: 'checked', label: 'Checked', type: 'boolean', default: true },
|
|
303
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
304
|
-
],
|
|
305
|
-
hasContent: true,
|
|
306
|
-
contentLabel: 'Label',
|
|
307
|
-
contentDefault: 'I agree to the terms',
|
|
308
|
-
},
|
|
309
|
-
{
|
|
310
|
-
key: 'rating',
|
|
311
|
-
label: 'Rating',
|
|
312
|
-
category: 'Inputs',
|
|
313
|
-
importName: 'SvRating',
|
|
314
|
-
props: [
|
|
315
|
-
{ key: 'value', label: 'Value', type: 'number', default: 3 },
|
|
316
|
-
{ key: 'max', label: 'Stars', type: 'number', default: 5 },
|
|
317
|
-
{ key: 'allowHalf', label: 'Allow half', type: 'boolean', default: false },
|
|
318
|
-
{ key: 'readOnly', label: 'Read only', type: 'boolean', default: false },
|
|
319
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
320
|
-
],
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
key: 'slider',
|
|
324
|
-
label: 'Slider',
|
|
325
|
-
category: 'Inputs',
|
|
326
|
-
importName: 'SvSlider',
|
|
327
|
-
props: [
|
|
328
|
-
{ key: 'value', label: 'Value', type: 'number', default: 50 },
|
|
329
|
-
{ key: 'min', label: 'Min', type: 'number', default: 0 },
|
|
330
|
-
{ key: 'max', label: 'Max', type: 'number', default: 100 },
|
|
331
|
-
{ key: 'step', label: 'Step', type: 'number', default: 1 },
|
|
332
|
-
{ key: 'showValue', label: 'Show value', type: 'boolean', default: false },
|
|
333
|
-
{ key: 'labels', label: 'Tick labels', type: 'select', options: ['none', 'endpoints', 'all'], default: 'none' },
|
|
334
|
-
],
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
key: 'otp-input',
|
|
338
|
-
label: 'OTP input',
|
|
339
|
-
category: 'Inputs',
|
|
340
|
-
importName: 'SvOtpInput',
|
|
341
|
-
props: [
|
|
342
|
-
{ key: 'label', label: 'Label', type: 'string', default: 'Verification code' },
|
|
343
|
-
{ key: 'length', label: 'Digits', type: 'number', default: 6 },
|
|
344
|
-
{ key: 'mask', label: 'Mask input', type: 'boolean', default: false },
|
|
345
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
346
|
-
],
|
|
347
|
-
},
|
|
348
|
-
|
|
349
|
-
// --- Feedback ------------------------------------------------------------
|
|
350
|
-
{
|
|
351
|
-
key: 'circular-progress',
|
|
352
|
-
label: 'Circular progress',
|
|
353
|
-
category: 'Feedback',
|
|
354
|
-
importName: 'SvCircularProgress',
|
|
355
|
-
props: [
|
|
356
|
-
{ key: 'value', label: 'Value', type: 'number', default: 66 },
|
|
357
|
-
{ key: 'max', label: 'Max', type: 'number', default: 100 },
|
|
358
|
-
{ key: 'size', label: 'Diameter (px)', type: 'number', default: 52 },
|
|
359
|
-
{ key: 'thickness', label: 'Thickness', type: 'number', default: 4 },
|
|
360
|
-
{ key: 'color', label: 'Color', type: 'select', options: ['accent', 'success', 'warning', 'danger'], default: 'accent' },
|
|
361
|
-
{ key: 'showLabel', label: 'Show percentage', type: 'boolean', default: true },
|
|
362
|
-
{ key: 'indeterminate', label: 'Indeterminate', type: 'boolean', default: false },
|
|
363
|
-
],
|
|
364
|
-
},
|
|
365
|
-
{
|
|
366
|
-
key: 'skeleton',
|
|
367
|
-
label: 'Skeleton',
|
|
368
|
-
category: 'Feedback',
|
|
369
|
-
importName: 'SvSkeleton',
|
|
370
|
-
props: [
|
|
371
|
-
{ key: 'variant', label: 'Variant', type: 'select', options: ['text', 'rect', 'circle'], default: 'text' },
|
|
372
|
-
{ key: 'lines', label: 'Lines (text)', type: 'number', default: 3 },
|
|
373
|
-
{ key: 'width', label: 'Width (CSS)', type: 'string' },
|
|
374
|
-
{ key: 'height', label: 'Height (CSS)', type: 'string' },
|
|
375
|
-
{ key: 'animated', label: 'Animated', type: 'boolean', default: true },
|
|
376
|
-
],
|
|
377
|
-
},
|
|
378
|
-
|
|
379
|
-
// --- Display -------------------------------------------------------------
|
|
380
|
-
{
|
|
381
|
-
key: 'chip',
|
|
382
|
-
label: 'Chip',
|
|
383
|
-
category: 'Display',
|
|
384
|
-
importName: 'SvChip',
|
|
385
|
-
props: [
|
|
386
|
-
{ key: 'variant', label: 'Variant', type: 'select', options: ['neutral', 'accent', 'success', 'warning', 'danger', 'info'], default: 'neutral' },
|
|
387
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md'], default: 'md' },
|
|
388
|
-
{ key: 'solid', label: 'Solid', type: 'boolean', default: false },
|
|
389
|
-
{ key: 'removable', label: 'Removable', type: 'boolean', default: false },
|
|
390
|
-
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
391
|
-
],
|
|
392
|
-
hasContent: true,
|
|
393
|
-
contentLabel: 'Text',
|
|
394
|
-
contentDefault: 'Chip',
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
key: 'empty-state',
|
|
398
|
-
label: 'Empty state',
|
|
399
|
-
category: 'Display',
|
|
400
|
-
importName: 'SvEmptyState',
|
|
401
|
-
props: [
|
|
402
|
-
{ key: 'title', label: 'Title', type: 'string', default: 'No results yet' },
|
|
403
|
-
{ key: 'description', label: 'Description', type: 'string', default: 'Try adjusting your filters or add a new record.' },
|
|
404
|
-
{ key: 'compact', label: 'Compact', type: 'boolean', default: false },
|
|
405
|
-
],
|
|
406
|
-
},
|
|
407
|
-
{
|
|
408
|
-
key: 'timeline',
|
|
409
|
-
label: 'Timeline',
|
|
410
|
-
category: 'Display',
|
|
411
|
-
importName: 'SvTimeline',
|
|
412
|
-
props: [],
|
|
413
|
-
fixed: [
|
|
414
|
-
{
|
|
415
|
-
key: 'items',
|
|
416
|
-
expr: `[{ title: 'Order placed', time: '09:12', color: '#16a34a' }, { title: 'Packed', time: '11:30', description: 'Ready to ship' }, { title: 'Shipped', time: '14:40', color: '#6366f1' }, { title: 'Delivered', time: '17:05' }]`,
|
|
417
|
-
preview: [
|
|
418
|
-
{ title: 'Order placed', time: '09:12', color: '#16a34a' },
|
|
419
|
-
{ title: 'Packed', time: '11:30', description: 'Ready to ship' },
|
|
420
|
-
{ title: 'Shipped', time: '14:40', color: '#6366f1' },
|
|
421
|
-
{ title: 'Delivered', time: '17:05' },
|
|
422
|
-
],
|
|
423
|
-
},
|
|
424
|
-
],
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
key: 'sparkline',
|
|
428
|
-
label: 'Sparkline',
|
|
429
|
-
category: 'Display',
|
|
430
|
-
importName: 'SvSparkline',
|
|
431
|
-
props: [
|
|
432
|
-
{ key: 'type', label: 'Type', type: 'select', options: ['line', 'area', 'bar', 'winloss'], default: 'area' },
|
|
433
|
-
{ key: 'color', label: 'Color', type: 'color', default: '#6366f1' },
|
|
434
|
-
{ key: 'width', label: 'Width (px)', type: 'number', default: 120 },
|
|
435
|
-
{ key: 'height', label: 'Height (px)', type: 'number', default: 32 },
|
|
436
|
-
],
|
|
437
|
-
fixed: [
|
|
438
|
-
{ key: 'data', expr: `[4, 8, 5, 9, 7, 11, 8, 13, 10, 15]`, preview: [4, 8, 5, 9, 7, 11, 8, 13, 10, 15] },
|
|
439
|
-
],
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
key: 'avatar-group',
|
|
443
|
-
label: 'Avatar group',
|
|
444
|
-
category: 'Display',
|
|
445
|
-
importName: 'SvAvatarGroup',
|
|
446
|
-
props: [
|
|
447
|
-
{ key: 'max', label: 'Max shown', type: 'number', default: 4 },
|
|
448
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
449
|
-
],
|
|
450
|
-
fixed: [
|
|
451
|
-
{
|
|
452
|
-
key: 'avatars',
|
|
453
|
-
expr: `[{ name: 'Jordan Lee' }, { name: 'Sam Rivera' }, { name: 'Alex Kim' }, { name: 'Priya Patel' }, { name: 'Chris Diaz' }]`,
|
|
454
|
-
preview: [{ name: 'Jordan Lee' }, { name: 'Sam Rivera' }, { name: 'Alex Kim' }, { name: 'Priya Patel' }, { name: 'Chris Diaz' }],
|
|
455
|
-
},
|
|
456
|
-
],
|
|
457
|
-
},
|
|
458
|
-
|
|
459
|
-
// --- Navigation ----------------------------------------------------------
|
|
460
|
-
{
|
|
461
|
-
key: 'pagination',
|
|
462
|
-
label: 'Pagination',
|
|
463
|
-
category: 'Navigation',
|
|
464
|
-
importName: 'SvPagination',
|
|
465
|
-
props: [
|
|
466
|
-
{ key: 'page', label: 'Current page', type: 'number', default: 1 },
|
|
467
|
-
{ key: 'pageCount', label: 'Page count', type: 'number', default: 5 },
|
|
468
|
-
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
469
|
-
{ key: 'showFirstLast', label: 'First / last', type: 'boolean', default: true },
|
|
470
|
-
{ key: 'showPrevNext', label: 'Prev / next', type: 'boolean', default: true },
|
|
471
|
-
{ key: 'siblingCount', label: 'Sibling count', type: 'number', default: 1 },
|
|
472
|
-
],
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
key: 'breadcrumb',
|
|
476
|
-
label: 'Breadcrumb',
|
|
477
|
-
category: 'Navigation',
|
|
478
|
-
importName: 'SvBreadcrumb',
|
|
479
|
-
props: [],
|
|
480
|
-
fixed: [
|
|
481
|
-
{
|
|
482
|
-
key: 'items',
|
|
483
|
-
expr: `[{ label: 'Home', href: '/' }, { label: 'Orders', href: '/orders' }, { label: '#1024' }]`,
|
|
484
|
-
preview: [{ label: 'Home', href: '/' }, { label: 'Orders', href: '/orders' }, { label: '#1024' }],
|
|
485
|
-
},
|
|
486
|
-
],
|
|
487
|
-
},
|
|
488
|
-
{
|
|
489
|
-
key: 'stepper',
|
|
490
|
-
label: 'Stepper',
|
|
491
|
-
category: 'Navigation',
|
|
492
|
-
importName: 'SvStepper',
|
|
493
|
-
props: [
|
|
494
|
-
{ key: 'current', label: 'Current step', type: 'number', default: 1 },
|
|
495
|
-
{ key: 'orientation', label: 'Orientation', type: 'select', options: ['horizontal', 'vertical'], default: 'horizontal' },
|
|
496
|
-
{ key: 'linear', label: 'Linear', type: 'boolean', default: true },
|
|
497
|
-
],
|
|
498
|
-
fixed: [
|
|
499
|
-
{
|
|
500
|
-
key: 'steps',
|
|
501
|
-
expr: `[{ label: 'Cart' }, { label: 'Shipping' }, { label: 'Payment' }, { label: 'Review' }]`,
|
|
502
|
-
preview: [{ label: 'Cart' }, { label: 'Shipping' }, { label: 'Payment' }, { label: 'Review' }],
|
|
503
|
-
},
|
|
504
|
-
],
|
|
505
|
-
},
|
|
506
|
-
// --- wave 1: full-kit registration (props/events come from the extractor) ---
|
|
507
|
-
{ key: 'masked-input', label: 'Masked input', category: 'Inputs', importName: 'SvMaskedInput', props: [] },
|
|
508
|
-
{ key: 'phone-input', label: 'Phone input', category: 'Inputs', importName: 'SvPhoneInput', props: [] },
|
|
509
|
-
{
|
|
510
|
-
key: 'tags-input', label: 'Tags input', category: 'Inputs', importName: 'SvTagsInput',
|
|
511
|
-
props: [{ key: 'value', label: 'Tags', type: 'json', default: ['svelte', 'grid'] }],
|
|
512
|
-
},
|
|
513
|
-
{ key: 'duration-input', label: 'Duration input', category: 'Inputs', importName: 'SvDurationInput', props: [] },
|
|
514
|
-
{
|
|
515
|
-
key: 'radio-group', label: 'Radio group', category: 'Inputs', importName: 'SvRadioGroup',
|
|
516
|
-
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: 'a', label: 'Option A' }, { value: 'b', label: 'Option B' }, { value: 'c', label: 'Option C' }] }],
|
|
517
|
-
},
|
|
518
|
-
{
|
|
519
|
-
key: 'button-group', label: 'Button group', category: 'Actions', importName: 'SvButtonGroup',
|
|
520
|
-
props: [{ key: 'items', label: 'Items', type: 'json', default: [{ value: 'day', label: 'Day' }, { value: 'week', label: 'Week' }, { value: 'month', label: 'Month' }] }],
|
|
521
|
-
},
|
|
522
|
-
{
|
|
523
|
-
key: 'list-box', label: 'List box', category: 'Inputs', importName: 'SvListBox',
|
|
524
|
-
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
key: 'dropdown-list', label: 'Dropdown list', category: 'Inputs', importName: 'SvDropDownList',
|
|
528
|
-
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
529
|
-
},
|
|
530
|
-
{
|
|
531
|
-
key: 'combo-box', label: 'Combo box', category: 'Inputs', importName: 'SvComboBox',
|
|
532
|
-
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
key: 'auto-complete', label: 'Auto complete', category: 'Inputs', importName: 'SvAutoComplete',
|
|
536
|
-
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: 'red', label: 'Red' }, { value: 'green', label: 'Green' }, { value: 'blue', label: 'Blue' }] }],
|
|
537
|
-
},
|
|
538
|
-
{
|
|
539
|
-
key: 'multi-select', label: 'Multi select', category: 'Inputs', importName: 'SvMultiSelect',
|
|
540
|
-
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
541
|
-
},
|
|
542
|
-
{ key: 'repeat-button', label: 'Repeat button', category: 'Actions', importName: 'SvRepeatButton', props: [], hasContent: true, contentLabel: 'Label', contentDefault: 'Hold me' },
|
|
543
|
-
{ key: 'rich-text', label: 'Rich text editor', category: 'Inputs', importName: 'SvRichText', props: [] },
|
|
544
|
-
{
|
|
545
|
-
key: 'tree', label: 'Tree', category: 'Display', importName: 'SvTree',
|
|
546
|
-
props: [{ key: 'nodes', label: 'Nodes', type: 'json', default: [{ id: '1', label: 'Documents', children: [{ id: '1-1', label: 'Reports' }, { id: '1-2', label: 'Invoices' }] }, { id: '2', label: 'Pictures' }] }],
|
|
547
|
-
},
|
|
548
|
-
{ key: 'country-input', label: 'Country input', category: 'Inputs', importName: 'SvCountryInput', props: [] },
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
//
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
//
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
1
|
+
/**
|
|
2
|
+
* A curated catalogue of SvGrid UI-kit components a Studio screen can host as a
|
|
3
|
+
* `'component'` block (see `ComponentConfig` in `project.ts`) - entity-agnostic,
|
|
4
|
+
* usable on any screen including a freestanding one. Pure metadata: no Svelte
|
|
5
|
+
* import here (this subtree stays Svelte-free), so the designer holds the live
|
|
6
|
+
* component references and this module only describes what to configure and how
|
|
7
|
+
* to generate.
|
|
8
|
+
*
|
|
9
|
+
* Only "chrome" props (scalar values a form can drive) are listed - every
|
|
10
|
+
* component's real content is typically a Svelte `Snippet`, which this registry
|
|
11
|
+
* can't represent. A component with `hasContent` gets one extra literal-text
|
|
12
|
+
* field in the property panel (stored under the reserved `_content` props key)
|
|
13
|
+
* that becomes its plain-text children in both the live preview and codegen.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { GENERATED_UI_SURFACE } from './ui-components.generated.js'
|
|
17
|
+
|
|
18
|
+
export type UiPropType = 'string' | 'number' | 'boolean' | 'select' | 'color' | 'json' | 'date'
|
|
19
|
+
|
|
20
|
+
export type UiPropGroup = 'common' | 'appearance' | 'behavior' | 'advanced'
|
|
21
|
+
|
|
22
|
+
export type UiComponentProp = {
|
|
23
|
+
key: string
|
|
24
|
+
label: string
|
|
25
|
+
type: UiPropType
|
|
26
|
+
/** Choices for `type: 'select'`. */
|
|
27
|
+
options?: string[]
|
|
28
|
+
default?: unknown
|
|
29
|
+
/** Guidance shown as the property panel tooltip - sourced from the component's
|
|
30
|
+
* own JSDoc via the extractor, so it stays true to the source. */
|
|
31
|
+
description?: string
|
|
32
|
+
/** Property-panel grouping (defaults to 'common'). */
|
|
33
|
+
group?: UiPropGroup
|
|
34
|
+
/** A function / code-only prop (e.g. loadChildren) - listed read-only, set in code. */
|
|
35
|
+
code?: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A wireable component event: `key` is the handle event name (`ctx.x.on<key>`),
|
|
39
|
+
* `prop` the component callback prop that fires it (e.g. `onChange`). */
|
|
40
|
+
export type UiComponentEvent = { key: string; label: string; prop?: string; description?: string }
|
|
41
|
+
|
|
42
|
+
/** Standard DOM / interaction events EVERY component block can wire (VS-style full
|
|
43
|
+
* event surface) - forwarded by the generated wrapper to the block's handle. `dom`
|
|
44
|
+
* is the DOM event the wrapper listens for; `key` is the handle event name. */
|
|
45
|
+
export const STANDARD_UI_EVENTS: ReadonlyArray<{ key: string; label: string; dom: string; description: string }> = [
|
|
46
|
+
{ key: 'click', label: 'Click', dom: 'click', description: 'The component (or a child) was clicked.' },
|
|
47
|
+
{ key: 'dblclick', label: 'Double click', dom: 'dblclick', description: 'The component was double-clicked.' },
|
|
48
|
+
{ key: 'change', label: 'Change', dom: 'change', description: 'A committed value change (fires on blur for inputs).' },
|
|
49
|
+
{ key: 'input', label: 'Input', dom: 'input', description: 'Fires on every keystroke / immediate value edit.' },
|
|
50
|
+
{ key: 'focus', label: 'Focus', dom: 'focusin', description: 'The component (or a child) gained focus.' },
|
|
51
|
+
{ key: 'blur', label: 'Blur', dom: 'focusout', description: 'The component (or a child) lost focus.' },
|
|
52
|
+
{ key: 'keydown', label: 'Key down', dom: 'keydown', description: 'A key was pressed while focused.' },
|
|
53
|
+
{ key: 'keyup', label: 'Key up', dom: 'keyup', description: 'A key was released while focused.' },
|
|
54
|
+
{ key: 'contextmenu', label: 'Context menu', dom: 'contextmenu', description: 'Right-click / context-menu request.' },
|
|
55
|
+
{ key: 'mouseenter', label: 'Mouse enter', dom: 'mouseenter', description: 'The pointer entered the component.' },
|
|
56
|
+
{ key: 'mouseleave', label: 'Mouse leave', dom: 'mouseleave', description: 'The pointer left the component.' },
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
export type UiComponentSpec = {
|
|
60
|
+
/** Registry key - stored as `ComponentConfig.component`. */
|
|
61
|
+
key: string
|
|
62
|
+
label: string
|
|
63
|
+
category: string
|
|
64
|
+
/** Named export from `@svgrid/grid`. */
|
|
65
|
+
importName: string
|
|
66
|
+
/** Hand-curated prop entries. In the EXPORTED registry these are merged with
|
|
67
|
+
* the extracted full surface (ui-components.generated.ts): hand entries win
|
|
68
|
+
* by key (label/options/default), extraction supplies the rest + tooltips. */
|
|
69
|
+
props: UiComponentProp[]
|
|
70
|
+
/** Wireable events (merged with extracted function-prop events the same way). */
|
|
71
|
+
events?: UiComponentEvent[]
|
|
72
|
+
/** Extracted props to keep OUT of the property panel (edge cases). */
|
|
73
|
+
hiddenProps?: string[]
|
|
74
|
+
/** True if the component's real content is a `children` snippet - adds one
|
|
75
|
+
* literal-text field to the property panel, stored under `props._content`. */
|
|
76
|
+
hasContent?: boolean
|
|
77
|
+
contentLabel?: string
|
|
78
|
+
contentDefault?: string
|
|
79
|
+
/** Array / object props a scalar form can't express (a Timeline's `items`, a
|
|
80
|
+
* Sparkline's `data`). Each is emitted verbatim in codegen as `key={<expr>}`
|
|
81
|
+
* with a baked demo dataset the user then edits in Code view, and its `preview`
|
|
82
|
+
* value drives the live designer canvas. Not shown in the property panel. */
|
|
83
|
+
fixed?: Array<{ key: string; expr: string; preview: unknown }>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const BASE_REGISTRY: ReadonlyArray<UiComponentSpec> = [
|
|
87
|
+
{
|
|
88
|
+
key: 'button',
|
|
89
|
+
label: 'Button',
|
|
90
|
+
category: 'Actions',
|
|
91
|
+
importName: 'SvButton',
|
|
92
|
+
props: [
|
|
93
|
+
{ key: 'variant', label: 'Variant', type: 'select', options: ['primary', 'secondary', 'outline', 'ghost', 'danger'], default: 'primary' },
|
|
94
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
95
|
+
{ key: 'block', label: 'Full width', type: 'boolean', default: false },
|
|
96
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
97
|
+
],
|
|
98
|
+
hasContent: true,
|
|
99
|
+
contentLabel: 'Label',
|
|
100
|
+
contentDefault: 'Click me',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
key: 'badge',
|
|
104
|
+
label: 'Badge',
|
|
105
|
+
category: 'Feedback',
|
|
106
|
+
importName: 'SvBadge',
|
|
107
|
+
props: [
|
|
108
|
+
{ key: 'variant', label: 'Variant', type: 'select', options: ['neutral', 'accent', 'success', 'warning', 'danger', 'info'], default: 'neutral' },
|
|
109
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md'], default: 'md' },
|
|
110
|
+
{ key: 'pill', label: 'Pill shape', type: 'boolean', default: true },
|
|
111
|
+
{ key: 'dot', label: 'Show dot', type: 'boolean', default: false },
|
|
112
|
+
],
|
|
113
|
+
hasContent: true,
|
|
114
|
+
contentLabel: 'Text',
|
|
115
|
+
contentDefault: 'Badge',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
key: 'alert',
|
|
119
|
+
label: 'Alert',
|
|
120
|
+
category: 'Feedback',
|
|
121
|
+
importName: 'SvAlert',
|
|
122
|
+
props: [
|
|
123
|
+
{ key: 'variant', label: 'Variant', type: 'select', options: ['info', 'success', 'warning', 'danger', 'neutral'], default: 'info' },
|
|
124
|
+
{ key: 'title', label: 'Title', type: 'string' },
|
|
125
|
+
{ key: 'dismissible', label: 'Dismissible', type: 'boolean', default: false },
|
|
126
|
+
{ key: 'soft', label: 'Soft (tinted) style', type: 'boolean', default: false },
|
|
127
|
+
],
|
|
128
|
+
hasContent: true,
|
|
129
|
+
contentLabel: 'Message',
|
|
130
|
+
contentDefault: 'This is an alert message.',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
key: 'progress',
|
|
134
|
+
label: 'Progress bar',
|
|
135
|
+
category: 'Feedback',
|
|
136
|
+
importName: 'SvProgress',
|
|
137
|
+
props: [
|
|
138
|
+
{ key: 'value', label: 'Value', type: 'number', default: 60 },
|
|
139
|
+
{ key: 'max', label: 'Max', type: 'number', default: 100 },
|
|
140
|
+
{ key: 'color', label: 'Color', type: 'select', options: ['accent', 'success', 'warning', 'danger'], default: 'accent' },
|
|
141
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
142
|
+
{ key: 'showLabel', label: 'Show percentage', type: 'boolean', default: false },
|
|
143
|
+
{ key: 'striped', label: 'Striped', type: 'boolean', default: false },
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
key: 'card',
|
|
148
|
+
label: 'Card',
|
|
149
|
+
category: 'Layout',
|
|
150
|
+
importName: 'SvCard',
|
|
151
|
+
props: [
|
|
152
|
+
{ key: 'title', label: 'Title', type: 'string', default: 'Card title' },
|
|
153
|
+
{ key: 'subtitle', label: 'Subtitle', type: 'string' },
|
|
154
|
+
{ key: 'hoverable', label: 'Hover elevation', type: 'boolean', default: false },
|
|
155
|
+
{ key: 'flush', label: 'Flush padding', type: 'boolean', default: false },
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
key: 'divider',
|
|
160
|
+
label: 'Divider',
|
|
161
|
+
category: 'Layout',
|
|
162
|
+
importName: 'SvDivider',
|
|
163
|
+
props: [
|
|
164
|
+
{ key: 'orientation', label: 'Orientation', type: 'select', options: ['horizontal', 'vertical'], default: 'horizontal' },
|
|
165
|
+
{ key: 'label', label: 'Label', type: 'string' },
|
|
166
|
+
{ key: 'align', label: 'Label align', type: 'select', options: ['start', 'center', 'end'], default: 'center' },
|
|
167
|
+
{ key: 'dashed', label: 'Dashed', type: 'boolean', default: false },
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
key: 'avatar',
|
|
172
|
+
label: 'Avatar',
|
|
173
|
+
category: 'Display',
|
|
174
|
+
importName: 'SvAvatar',
|
|
175
|
+
props: [
|
|
176
|
+
{ key: 'name', label: 'Name', type: 'string', default: 'Jordan Lee' },
|
|
177
|
+
{ key: 'src', label: 'Image URL', type: 'string' },
|
|
178
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
179
|
+
{ key: 'shape', label: 'Shape', type: 'select', options: ['circle', 'square'], default: 'circle' },
|
|
180
|
+
{ key: 'status', label: 'Status', type: 'select', options: ['', 'online', 'offline', 'busy', 'away'], default: '' },
|
|
181
|
+
{ key: 'color', label: 'Color override', type: 'color' },
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
key: 'stat',
|
|
186
|
+
label: 'Stat',
|
|
187
|
+
category: 'Display',
|
|
188
|
+
importName: 'SvStat',
|
|
189
|
+
props: [
|
|
190
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Revenue' },
|
|
191
|
+
{ key: 'value', label: 'Value', type: 'string', default: '$48,200' },
|
|
192
|
+
{ key: 'delta', label: 'Delta', type: 'string' },
|
|
193
|
+
{ key: 'trend', label: 'Trend', type: 'select', options: ['', 'up', 'down', 'flat'], default: '' },
|
|
194
|
+
{ key: 'hint', label: 'Hint', type: 'string' },
|
|
195
|
+
{ key: 'invert', label: 'Invert trend colors', type: 'boolean', default: false },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// --- Actions -------------------------------------------------------------
|
|
200
|
+
{
|
|
201
|
+
key: 'toggle-button',
|
|
202
|
+
label: 'Toggle button',
|
|
203
|
+
category: 'Actions',
|
|
204
|
+
importName: 'SvToggleButton',
|
|
205
|
+
props: [
|
|
206
|
+
{ key: 'pressed', label: 'Pressed', type: 'boolean', default: false },
|
|
207
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
208
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
209
|
+
],
|
|
210
|
+
hasContent: true,
|
|
211
|
+
contentLabel: 'Label',
|
|
212
|
+
contentDefault: 'Toggle',
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
key: 'switch',
|
|
216
|
+
label: 'Switch',
|
|
217
|
+
category: 'Actions',
|
|
218
|
+
importName: 'SvSwitchButton',
|
|
219
|
+
props: [
|
|
220
|
+
{ key: 'checked', label: 'On', type: 'boolean', default: true },
|
|
221
|
+
{ key: 'label', label: 'Field label', type: 'string' },
|
|
222
|
+
{ key: 'onLabel', label: 'On label', type: 'string', default: 'On' },
|
|
223
|
+
{ key: 'offLabel', label: 'Off label', type: 'string', default: 'Off' },
|
|
224
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
225
|
+
],
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
// --- Inputs --------------------------------------------------------------
|
|
229
|
+
{
|
|
230
|
+
key: 'text-input',
|
|
231
|
+
label: 'Text input',
|
|
232
|
+
category: 'Inputs',
|
|
233
|
+
importName: 'SvTextInput',
|
|
234
|
+
props: [
|
|
235
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Name' },
|
|
236
|
+
{ key: 'placeholder', label: 'Placeholder', type: 'string', default: 'Type here…' },
|
|
237
|
+
{ key: 'type', label: 'Type', type: 'select', options: ['text', 'email', 'url', 'tel', 'search'], default: 'text' },
|
|
238
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
239
|
+
{ key: 'clearable', label: 'Clearable', type: 'boolean', default: false },
|
|
240
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
241
|
+
{ key: 'readonly', label: 'Read only', type: 'boolean', default: false },
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
key: 'textarea',
|
|
246
|
+
label: 'Text area',
|
|
247
|
+
category: 'Inputs',
|
|
248
|
+
importName: 'SvTextArea',
|
|
249
|
+
props: [
|
|
250
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Notes' },
|
|
251
|
+
{ key: 'placeholder', label: 'Placeholder', type: 'string', default: 'Write something…' },
|
|
252
|
+
{ key: 'rows', label: 'Rows', type: 'number', default: 3 },
|
|
253
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
254
|
+
],
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
key: 'number-input',
|
|
258
|
+
label: 'Number input',
|
|
259
|
+
category: 'Inputs',
|
|
260
|
+
importName: 'SvNumberInput',
|
|
261
|
+
props: [
|
|
262
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Amount' },
|
|
263
|
+
{ key: 'placeholder', label: 'Placeholder', type: 'string' },
|
|
264
|
+
{ key: 'min', label: 'Min', type: 'number' },
|
|
265
|
+
{ key: 'max', label: 'Max', type: 'number' },
|
|
266
|
+
{ key: 'step', label: 'Step', type: 'number', default: 1 },
|
|
267
|
+
{ key: 'prefix', label: 'Prefix', type: 'string' },
|
|
268
|
+
{ key: 'suffix', label: 'Suffix', type: 'string' },
|
|
269
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
270
|
+
],
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
key: 'password-input',
|
|
274
|
+
label: 'Password input',
|
|
275
|
+
category: 'Inputs',
|
|
276
|
+
importName: 'SvPasswordInput',
|
|
277
|
+
props: [
|
|
278
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Password' },
|
|
279
|
+
{ key: 'placeholder', label: 'Placeholder', type: 'string', default: '••••••••' },
|
|
280
|
+
{ key: 'revealable', label: 'Reveal toggle', type: 'boolean', default: true },
|
|
281
|
+
{ key: 'showStrength', label: 'Strength meter', type: 'boolean', default: false },
|
|
282
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
key: 'color-input',
|
|
287
|
+
label: 'Color input',
|
|
288
|
+
category: 'Inputs',
|
|
289
|
+
importName: 'SvColorInput',
|
|
290
|
+
props: [
|
|
291
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Brand color' },
|
|
292
|
+
{ key: 'value', label: 'Value', type: 'color', default: '#6366f1' },
|
|
293
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
294
|
+
],
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
key: 'checkbox',
|
|
298
|
+
label: 'Checkbox',
|
|
299
|
+
category: 'Inputs',
|
|
300
|
+
importName: 'SvCheckBox',
|
|
301
|
+
props: [
|
|
302
|
+
{ key: 'checked', label: 'Checked', type: 'boolean', default: true },
|
|
303
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
304
|
+
],
|
|
305
|
+
hasContent: true,
|
|
306
|
+
contentLabel: 'Label',
|
|
307
|
+
contentDefault: 'I agree to the terms',
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
key: 'rating',
|
|
311
|
+
label: 'Rating',
|
|
312
|
+
category: 'Inputs',
|
|
313
|
+
importName: 'SvRating',
|
|
314
|
+
props: [
|
|
315
|
+
{ key: 'value', label: 'Value', type: 'number', default: 3 },
|
|
316
|
+
{ key: 'max', label: 'Stars', type: 'number', default: 5 },
|
|
317
|
+
{ key: 'allowHalf', label: 'Allow half', type: 'boolean', default: false },
|
|
318
|
+
{ key: 'readOnly', label: 'Read only', type: 'boolean', default: false },
|
|
319
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
320
|
+
],
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
key: 'slider',
|
|
324
|
+
label: 'Slider',
|
|
325
|
+
category: 'Inputs',
|
|
326
|
+
importName: 'SvSlider',
|
|
327
|
+
props: [
|
|
328
|
+
{ key: 'value', label: 'Value', type: 'number', default: 50 },
|
|
329
|
+
{ key: 'min', label: 'Min', type: 'number', default: 0 },
|
|
330
|
+
{ key: 'max', label: 'Max', type: 'number', default: 100 },
|
|
331
|
+
{ key: 'step', label: 'Step', type: 'number', default: 1 },
|
|
332
|
+
{ key: 'showValue', label: 'Show value', type: 'boolean', default: false },
|
|
333
|
+
{ key: 'labels', label: 'Tick labels', type: 'select', options: ['none', 'endpoints', 'all'], default: 'none' },
|
|
334
|
+
],
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
key: 'otp-input',
|
|
338
|
+
label: 'OTP input',
|
|
339
|
+
category: 'Inputs',
|
|
340
|
+
importName: 'SvOtpInput',
|
|
341
|
+
props: [
|
|
342
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Verification code' },
|
|
343
|
+
{ key: 'length', label: 'Digits', type: 'number', default: 6 },
|
|
344
|
+
{ key: 'mask', label: 'Mask input', type: 'boolean', default: false },
|
|
345
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
// --- Feedback ------------------------------------------------------------
|
|
350
|
+
{
|
|
351
|
+
key: 'circular-progress',
|
|
352
|
+
label: 'Circular progress',
|
|
353
|
+
category: 'Feedback',
|
|
354
|
+
importName: 'SvCircularProgress',
|
|
355
|
+
props: [
|
|
356
|
+
{ key: 'value', label: 'Value', type: 'number', default: 66 },
|
|
357
|
+
{ key: 'max', label: 'Max', type: 'number', default: 100 },
|
|
358
|
+
{ key: 'size', label: 'Diameter (px)', type: 'number', default: 52 },
|
|
359
|
+
{ key: 'thickness', label: 'Thickness', type: 'number', default: 4 },
|
|
360
|
+
{ key: 'color', label: 'Color', type: 'select', options: ['accent', 'success', 'warning', 'danger'], default: 'accent' },
|
|
361
|
+
{ key: 'showLabel', label: 'Show percentage', type: 'boolean', default: true },
|
|
362
|
+
{ key: 'indeterminate', label: 'Indeterminate', type: 'boolean', default: false },
|
|
363
|
+
],
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
key: 'skeleton',
|
|
367
|
+
label: 'Skeleton',
|
|
368
|
+
category: 'Feedback',
|
|
369
|
+
importName: 'SvSkeleton',
|
|
370
|
+
props: [
|
|
371
|
+
{ key: 'variant', label: 'Variant', type: 'select', options: ['text', 'rect', 'circle'], default: 'text' },
|
|
372
|
+
{ key: 'lines', label: 'Lines (text)', type: 'number', default: 3 },
|
|
373
|
+
{ key: 'width', label: 'Width (CSS)', type: 'string' },
|
|
374
|
+
{ key: 'height', label: 'Height (CSS)', type: 'string' },
|
|
375
|
+
{ key: 'animated', label: 'Animated', type: 'boolean', default: true },
|
|
376
|
+
],
|
|
377
|
+
},
|
|
378
|
+
|
|
379
|
+
// --- Display -------------------------------------------------------------
|
|
380
|
+
{
|
|
381
|
+
key: 'chip',
|
|
382
|
+
label: 'Chip',
|
|
383
|
+
category: 'Display',
|
|
384
|
+
importName: 'SvChip',
|
|
385
|
+
props: [
|
|
386
|
+
{ key: 'variant', label: 'Variant', type: 'select', options: ['neutral', 'accent', 'success', 'warning', 'danger', 'info'], default: 'neutral' },
|
|
387
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md'], default: 'md' },
|
|
388
|
+
{ key: 'solid', label: 'Solid', type: 'boolean', default: false },
|
|
389
|
+
{ key: 'removable', label: 'Removable', type: 'boolean', default: false },
|
|
390
|
+
{ key: 'disabled', label: 'Disabled', type: 'boolean', default: false },
|
|
391
|
+
],
|
|
392
|
+
hasContent: true,
|
|
393
|
+
contentLabel: 'Text',
|
|
394
|
+
contentDefault: 'Chip',
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
key: 'empty-state',
|
|
398
|
+
label: 'Empty state',
|
|
399
|
+
category: 'Display',
|
|
400
|
+
importName: 'SvEmptyState',
|
|
401
|
+
props: [
|
|
402
|
+
{ key: 'title', label: 'Title', type: 'string', default: 'No results yet' },
|
|
403
|
+
{ key: 'description', label: 'Description', type: 'string', default: 'Try adjusting your filters or add a new record.' },
|
|
404
|
+
{ key: 'compact', label: 'Compact', type: 'boolean', default: false },
|
|
405
|
+
],
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
key: 'timeline',
|
|
409
|
+
label: 'Timeline',
|
|
410
|
+
category: 'Display',
|
|
411
|
+
importName: 'SvTimeline',
|
|
412
|
+
props: [],
|
|
413
|
+
fixed: [
|
|
414
|
+
{
|
|
415
|
+
key: 'items',
|
|
416
|
+
expr: `[{ title: 'Order placed', time: '09:12', color: '#16a34a' }, { title: 'Packed', time: '11:30', description: 'Ready to ship' }, { title: 'Shipped', time: '14:40', color: '#6366f1' }, { title: 'Delivered', time: '17:05' }]`,
|
|
417
|
+
preview: [
|
|
418
|
+
{ title: 'Order placed', time: '09:12', color: '#16a34a' },
|
|
419
|
+
{ title: 'Packed', time: '11:30', description: 'Ready to ship' },
|
|
420
|
+
{ title: 'Shipped', time: '14:40', color: '#6366f1' },
|
|
421
|
+
{ title: 'Delivered', time: '17:05' },
|
|
422
|
+
],
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
key: 'sparkline',
|
|
428
|
+
label: 'Sparkline',
|
|
429
|
+
category: 'Display',
|
|
430
|
+
importName: 'SvSparkline',
|
|
431
|
+
props: [
|
|
432
|
+
{ key: 'type', label: 'Type', type: 'select', options: ['line', 'area', 'bar', 'winloss'], default: 'area' },
|
|
433
|
+
{ key: 'color', label: 'Color', type: 'color', default: '#6366f1' },
|
|
434
|
+
{ key: 'width', label: 'Width (px)', type: 'number', default: 120 },
|
|
435
|
+
{ key: 'height', label: 'Height (px)', type: 'number', default: 32 },
|
|
436
|
+
],
|
|
437
|
+
fixed: [
|
|
438
|
+
{ key: 'data', expr: `[4, 8, 5, 9, 7, 11, 8, 13, 10, 15]`, preview: [4, 8, 5, 9, 7, 11, 8, 13, 10, 15] },
|
|
439
|
+
],
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
key: 'avatar-group',
|
|
443
|
+
label: 'Avatar group',
|
|
444
|
+
category: 'Display',
|
|
445
|
+
importName: 'SvAvatarGroup',
|
|
446
|
+
props: [
|
|
447
|
+
{ key: 'max', label: 'Max shown', type: 'number', default: 4 },
|
|
448
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
449
|
+
],
|
|
450
|
+
fixed: [
|
|
451
|
+
{
|
|
452
|
+
key: 'avatars',
|
|
453
|
+
expr: `[{ name: 'Jordan Lee' }, { name: 'Sam Rivera' }, { name: 'Alex Kim' }, { name: 'Priya Patel' }, { name: 'Chris Diaz' }]`,
|
|
454
|
+
preview: [{ name: 'Jordan Lee' }, { name: 'Sam Rivera' }, { name: 'Alex Kim' }, { name: 'Priya Patel' }, { name: 'Chris Diaz' }],
|
|
455
|
+
},
|
|
456
|
+
],
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
// --- Navigation ----------------------------------------------------------
|
|
460
|
+
{
|
|
461
|
+
key: 'pagination',
|
|
462
|
+
label: 'Pagination',
|
|
463
|
+
category: 'Navigation',
|
|
464
|
+
importName: 'SvPagination',
|
|
465
|
+
props: [
|
|
466
|
+
{ key: 'page', label: 'Current page', type: 'number', default: 1 },
|
|
467
|
+
{ key: 'pageCount', label: 'Page count', type: 'number', default: 5 },
|
|
468
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
469
|
+
{ key: 'showFirstLast', label: 'First / last', type: 'boolean', default: true },
|
|
470
|
+
{ key: 'showPrevNext', label: 'Prev / next', type: 'boolean', default: true },
|
|
471
|
+
{ key: 'siblingCount', label: 'Sibling count', type: 'number', default: 1 },
|
|
472
|
+
],
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
key: 'breadcrumb',
|
|
476
|
+
label: 'Breadcrumb',
|
|
477
|
+
category: 'Navigation',
|
|
478
|
+
importName: 'SvBreadcrumb',
|
|
479
|
+
props: [],
|
|
480
|
+
fixed: [
|
|
481
|
+
{
|
|
482
|
+
key: 'items',
|
|
483
|
+
expr: `[{ label: 'Home', href: '/' }, { label: 'Orders', href: '/orders' }, { label: '#1024' }]`,
|
|
484
|
+
preview: [{ label: 'Home', href: '/' }, { label: 'Orders', href: '/orders' }, { label: '#1024' }],
|
|
485
|
+
},
|
|
486
|
+
],
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
key: 'stepper',
|
|
490
|
+
label: 'Stepper',
|
|
491
|
+
category: 'Navigation',
|
|
492
|
+
importName: 'SvStepper',
|
|
493
|
+
props: [
|
|
494
|
+
{ key: 'current', label: 'Current step', type: 'number', default: 1 },
|
|
495
|
+
{ key: 'orientation', label: 'Orientation', type: 'select', options: ['horizontal', 'vertical'], default: 'horizontal' },
|
|
496
|
+
{ key: 'linear', label: 'Linear', type: 'boolean', default: true },
|
|
497
|
+
],
|
|
498
|
+
fixed: [
|
|
499
|
+
{
|
|
500
|
+
key: 'steps',
|
|
501
|
+
expr: `[{ label: 'Cart' }, { label: 'Shipping' }, { label: 'Payment' }, { label: 'Review' }]`,
|
|
502
|
+
preview: [{ label: 'Cart' }, { label: 'Shipping' }, { label: 'Payment' }, { label: 'Review' }],
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
},
|
|
506
|
+
// --- wave 1: full-kit registration (props/events come from the extractor) ---
|
|
507
|
+
{ key: 'masked-input', label: 'Masked input', category: 'Inputs', importName: 'SvMaskedInput', props: [] },
|
|
508
|
+
{ key: 'phone-input', label: 'Phone input', category: 'Inputs', importName: 'SvPhoneInput', props: [] },
|
|
509
|
+
{
|
|
510
|
+
key: 'tags-input', label: 'Tags input', category: 'Inputs', importName: 'SvTagsInput',
|
|
511
|
+
props: [{ key: 'value', label: 'Tags', type: 'json', default: ['svelte', 'grid'] }],
|
|
512
|
+
},
|
|
513
|
+
{ key: 'duration-input', label: 'Duration input', category: 'Inputs', importName: 'SvDurationInput', props: [] },
|
|
514
|
+
{
|
|
515
|
+
key: 'radio-group', label: 'Radio group', category: 'Inputs', importName: 'SvRadioGroup',
|
|
516
|
+
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: 'a', label: 'Option A' }, { value: 'b', label: 'Option B' }, { value: 'c', label: 'Option C' }] }],
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
key: 'button-group', label: 'Button group', category: 'Actions', importName: 'SvButtonGroup',
|
|
520
|
+
props: [{ key: 'items', label: 'Items', type: 'json', default: [{ value: 'day', label: 'Day' }, { value: 'week', label: 'Week' }, { value: 'month', label: 'Month' }] }],
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
key: 'list-box', label: 'List box', category: 'Inputs', importName: 'SvListBox',
|
|
524
|
+
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
key: 'dropdown-list', label: 'Dropdown list', category: 'Inputs', importName: 'SvDropDownList',
|
|
528
|
+
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
key: 'combo-box', label: 'Combo box', category: 'Inputs', importName: 'SvComboBox',
|
|
532
|
+
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
key: 'auto-complete', label: 'Auto complete', category: 'Inputs', importName: 'SvAutoComplete',
|
|
536
|
+
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: 'red', label: 'Red' }, { value: 'green', label: 'Green' }, { value: 'blue', label: 'Blue' }] }],
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
key: 'multi-select', label: 'Multi select', category: 'Inputs', importName: 'SvMultiSelect',
|
|
540
|
+
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: '1', label: 'First' }, { value: '2', label: 'Second' }, { value: '3', label: 'Third' }] }],
|
|
541
|
+
},
|
|
542
|
+
{ key: 'repeat-button', label: 'Repeat button', category: 'Actions', importName: 'SvRepeatButton', props: [], hasContent: true, contentLabel: 'Label', contentDefault: 'Hold me' },
|
|
543
|
+
{ key: 'rich-text', label: 'Rich text editor', category: 'Inputs', importName: 'SvRichText', props: [] },
|
|
544
|
+
{
|
|
545
|
+
key: 'tree', label: 'Tree', category: 'Display', importName: 'SvTree',
|
|
546
|
+
props: [{ key: 'nodes', label: 'Nodes', type: 'json', default: [{ id: '1', label: 'Documents', children: [{ id: '1-1', label: 'Reports' }, { id: '1-2', label: 'Invoices' }] }, { id: '2', label: 'Pictures' }] }],
|
|
547
|
+
},
|
|
548
|
+
{ key: 'country-input', label: 'Country input', category: 'Inputs', importName: 'SvCountryInput', props: [] },
|
|
549
|
+
|
|
550
|
+
// --- Typography / prose -------------------------------------------------
|
|
551
|
+
// The kit's text primitives. Cheap to expose and they are what a freestanding
|
|
552
|
+
// page (an "About", a help panel) is mostly made of - without them a designer
|
|
553
|
+
// user has no way to place a heading or a paragraph.
|
|
554
|
+
{
|
|
555
|
+
key: 'title', label: 'Heading', category: 'Display', importName: 'SvTitle',
|
|
556
|
+
props: [{ key: 'size', label: 'Level', type: 'select', options: ['1', '2', '3', '4', '5', '6'], default: '2' }],
|
|
557
|
+
hasContent: true, contentLabel: 'Text', contentDefault: 'Section heading',
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
key: 'text', label: 'Text', category: 'Display', importName: 'SvText',
|
|
561
|
+
props: [
|
|
562
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['xs', 'sm', 'md', 'lg', 'xl'], default: 'md' },
|
|
563
|
+
{ key: 'weight', label: 'Weight', type: 'select', options: ['normal', 'medium', 'semibold', 'bold'], default: 'normal' },
|
|
564
|
+
{ key: 'tone', label: 'Tone', type: 'select', options: ['default', 'muted', 'accent', 'success', 'warning', 'error'], default: 'default' },
|
|
565
|
+
],
|
|
566
|
+
hasContent: true, contentLabel: 'Text', contentDefault: 'Body text.',
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
key: 'anchor', label: 'Link', category: 'Display', importName: 'SvAnchor',
|
|
570
|
+
props: [
|
|
571
|
+
{ key: 'href', label: 'URL', type: 'string', default: '#' },
|
|
572
|
+
{ key: 'tone', label: 'Tone', type: 'select', options: ['accent', 'default', 'muted'], default: 'accent' },
|
|
573
|
+
{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
|
|
574
|
+
],
|
|
575
|
+
hasContent: true, contentLabel: 'Label', contentDefault: 'Read more',
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
key: 'blockquote', label: 'Quote', category: 'Display', importName: 'SvBlockquote',
|
|
579
|
+
props: [], hasContent: true, contentLabel: 'Quote', contentDefault: 'A quoted passage.',
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
key: 'code', label: 'Inline code', category: 'Display', importName: 'SvCode',
|
|
583
|
+
props: [], hasContent: true, contentLabel: 'Code', contentDefault: 'npm install',
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
key: 'kbd', label: 'Keyboard key', category: 'Display', importName: 'SvKbd',
|
|
587
|
+
props: [{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md'], default: 'md' }],
|
|
588
|
+
hasContent: true, contentLabel: 'Key', contentDefault: 'Ctrl',
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
key: 'mark', label: 'Highlight', category: 'Display', importName: 'SvMark',
|
|
592
|
+
props: [{ key: 'tone', label: 'Tone', type: 'select', options: ['yellow', 'accent', 'success', 'warning', 'error'], default: 'yellow' }],
|
|
593
|
+
hasContent: true, contentLabel: 'Text', contentDefault: 'highlighted',
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
key: 'list', label: 'List', category: 'Display', importName: 'SvList',
|
|
597
|
+
props: [],
|
|
598
|
+
fixed: [{ key: 'items', expr: "['First item', 'Second item', 'Third item']", preview: ['First item', 'Second item', 'Third item'] }],
|
|
599
|
+
},
|
|
600
|
+
|
|
601
|
+
// --- Feedback -----------------------------------------------------------
|
|
602
|
+
{
|
|
603
|
+
key: 'spinner', label: 'Spinner', category: 'Feedback', importName: 'SvSpinner',
|
|
604
|
+
props: [{ key: 'size', label: 'Size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' }],
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
key: 'loading-overlay', label: 'Loading overlay', category: 'Feedback', importName: 'SvLoadingOverlay',
|
|
608
|
+
props: [
|
|
609
|
+
{ key: 'visible', label: 'Visible', type: 'boolean', default: true },
|
|
610
|
+
{ key: 'label', label: 'Label', type: 'string', default: 'Loading...' },
|
|
611
|
+
],
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
key: 'result', label: 'Result', category: 'Feedback', importName: 'SvResult',
|
|
615
|
+
props: [
|
|
616
|
+
{ key: 'status', label: 'Status', type: 'select', options: ['success', 'error', 'warning', 'info'], default: 'success' },
|
|
617
|
+
{ key: 'title', label: 'Title', type: 'string', default: 'All done' },
|
|
618
|
+
],
|
|
619
|
+
},
|
|
620
|
+
|
|
621
|
+
// --- Structure ----------------------------------------------------------
|
|
622
|
+
{
|
|
623
|
+
key: 'collapsible', label: 'Collapsible', category: 'Layout', importName: 'SvCollapsible',
|
|
624
|
+
props: [
|
|
625
|
+
{ key: 'title', label: 'Title', type: 'string', default: 'Details' },
|
|
626
|
+
{ key: 'open', label: 'Open', type: 'boolean', default: false },
|
|
627
|
+
],
|
|
628
|
+
hasContent: true, contentLabel: 'Content', contentDefault: 'Hidden until expanded.',
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
key: 'carousel', label: 'Carousel', category: 'Layout', importName: 'SvCarousel',
|
|
632
|
+
props: [],
|
|
633
|
+
},
|
|
634
|
+
|
|
635
|
+
// --- Date / time + richer pickers ---------------------------------------
|
|
636
|
+
// These are grid cell editors too; as standalone blocks they are what a
|
|
637
|
+
// filter bar or a booking form is built from.
|
|
638
|
+
{ key: 'date-time-picker', label: 'Date & time picker', category: 'Inputs', importName: 'SvDateTimePicker', props: [] },
|
|
639
|
+
{ key: 'time-picker', label: 'Time picker', category: 'Inputs', importName: 'SvTimePicker', props: [] },
|
|
640
|
+
{ key: 'date-range-input', label: 'Date range', category: 'Inputs', importName: 'SvDateRangeInput', props: [] },
|
|
641
|
+
{
|
|
642
|
+
key: 'segmented', label: 'Segmented control', category: 'Inputs', importName: 'SvSegmented',
|
|
643
|
+
props: [{ key: 'options', label: 'Options', type: 'json', default: [{ value: 'day', label: 'Day' }, { value: 'week', label: 'Week' }, { value: 'month', label: 'Month' }] }],
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
key: 'tree-select', label: 'Tree select', category: 'Inputs', importName: 'SvTreeSelect',
|
|
647
|
+
props: [{ key: 'nodes', label: 'Nodes', type: 'json', default: [{ id: '1', label: 'Europe', children: [{ id: '1-1', label: 'France' }, { id: '1-2', label: 'Spain' }] }, { id: '2', label: 'Asia' }] }],
|
|
648
|
+
},
|
|
649
|
+
{ key: 'file-upload', label: 'File upload', category: 'Inputs', importName: 'SvFileUpload', props: [] },
|
|
650
|
+
]
|
|
651
|
+
|
|
652
|
+
// ---------------------------------------------------------------------------
|
|
653
|
+
// Merge: the exported registry = hand-curated spec + the component's FULL
|
|
654
|
+
// extracted surface (ui-components.generated.ts). Hand entries win by key;
|
|
655
|
+
// extraction contributes every remaining prop with its JSDoc tooltip, plus
|
|
656
|
+
// the event list. Consumers see one complete `props`/`events` per component.
|
|
657
|
+
// ---------------------------------------------------------------------------
|
|
658
|
+
|
|
659
|
+
const GROUP_ORDER: Record<UiPropGroup, number> = { common: 0, appearance: 1, behavior: 2, advanced: 3 }
|
|
660
|
+
|
|
661
|
+
function mergeSpec(spec: UiComponentSpec): UiComponentSpec {
|
|
662
|
+
const generated = GENERATED_UI_SURFACE[spec.importName]
|
|
663
|
+
if (!generated) return spec
|
|
664
|
+
const skip = new Set<string>([...(spec.hiddenProps ?? []), ...(spec.fixed ?? []).map((f) => f.key), '_content'])
|
|
665
|
+
const genByKey = new Map(generated.props.map((p) => [p.key, p]))
|
|
666
|
+
// Hand-curated entries first (their order is intentional), enriched with the
|
|
667
|
+
// extracted description/group when the hand entry doesn't set them.
|
|
668
|
+
const curated = spec.props
|
|
669
|
+
.filter((p) => !skip.has(p.key))
|
|
670
|
+
.map((p) => {
|
|
671
|
+
const g = genByKey.get(p.key)
|
|
672
|
+
return g ? { ...g, ...p, description: p.description ?? g.description, group: p.group ?? g.group } : p
|
|
673
|
+
})
|
|
674
|
+
const curatedKeys = new Set(curated.map((p) => p.key))
|
|
675
|
+
const rest = generated.props
|
|
676
|
+
.filter((p) => !skip.has(p.key) && !curatedKeys.has(p.key))
|
|
677
|
+
.map((p) => ({ ...p }) as UiComponentProp)
|
|
678
|
+
.sort((a, b) => GROUP_ORDER[a.group ?? 'common'] - GROUP_ORDER[b.group ?? 'common'])
|
|
679
|
+
// Events: extracted list as the base, hand entries override by key.
|
|
680
|
+
const handEvents = new Map((spec.events ?? []).map((e) => [e.key, e]))
|
|
681
|
+
const events: UiComponentEvent[] = [
|
|
682
|
+
...generated.events.map((e) => ({ ...e, ...(handEvents.get(e.key) ?? {}) })),
|
|
683
|
+
...(spec.events ?? []).filter((e) => !generated.events.some((g) => g.key === e.key)),
|
|
684
|
+
]
|
|
685
|
+
return { ...spec, props: [...curated, ...rest], events }
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
export const UI_COMPONENT_REGISTRY: ReadonlyArray<UiComponentSpec> = BASE_REGISTRY.map(mergeSpec)
|
|
689
|
+
|
|
690
|
+
export function uiComponentSpec(key: string): UiComponentSpec | undefined {
|
|
691
|
+
return UI_COMPONENT_REGISTRY.find((s) => s.key === key)
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// --- Grid: the "All properties" surface ------------------------------------
|
|
695
|
+
// The grid block has rich CURATED controls (column/form builders, grouping, paging,
|
|
696
|
+
// ...). These are the SvGrid props those controls already drive - excluded from the
|
|
697
|
+
// grid's "All properties" panel so nothing shows twice. Everything else in the
|
|
698
|
+
// extracted SvGrid surface is offered as a raw, editable override (config.props).
|
|
699
|
+
export const GRID_CURATED_PROPS: ReadonlySet<string> = new Set<string>([
|
|
700
|
+
'data', 'columns', 'board', 'scheduler', 'loading', 'loadingOverlay', 'emptyMessage',
|
|
701
|
+
'fitColumns', 'sortable', 'externalSort', 'filterable', 'externalFilter', 'filterMode',
|
|
702
|
+
'showGlobalFilter', 'showColumnFilters', 'showFilterRow', 'showFilterMenu', 'showGroupingControls',
|
|
703
|
+
'groupable', 'showRowSelection', 'selectionMode', 'enableCellSelection', 'enableRowSummaries',
|
|
704
|
+
'zebraRows', 'showPagination', 'pageable', 'externalPagination', 'rowCount', 'pageIndex',
|
|
705
|
+
'pageSize', 'pageSizeOptions', 'paginationPosition', 'rowHeight', 'containerHeight',
|
|
706
|
+
'columnVirtualization', 'initialColumnPinning', 'conditionalFormats', 'features', 'editable',
|
|
707
|
+
'enableInlineEditing',
|
|
708
|
+
])
|
|
709
|
+
|
|
710
|
+
/** The Grid's raw prop surface for the "All properties" panel: every extracted SvGrid
|
|
711
|
+
* prop the curated controls do NOT already manage. Sorted by group then label. */
|
|
712
|
+
export function gridPropSurface(): UiComponentProp[] {
|
|
713
|
+
const g = GENERATED_UI_SURFACE['SvGrid']
|
|
714
|
+
if (!g) return []
|
|
715
|
+
const order: Record<string, number> = { common: 0, appearance: 1, behavior: 2, advanced: 3 }
|
|
716
|
+
return g.props
|
|
717
|
+
.filter((p) => !GRID_CURATED_PROPS.has(p.key))
|
|
718
|
+
.map((p) => ({ ...p }) as UiComponentProp)
|
|
719
|
+
.sort((a, b) => (order[a.group ?? 'common']! - order[b.group ?? 'common']!) || a.label.localeCompare(b.label))
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Props NOT offered on `ctx.grid` as runtime-settable options: structural data,
|
|
723
|
+
// controller-owned plumbing, and seed-once `initial*` props (the grid reads those at
|
|
724
|
+
// mount, so `setOption` on them is a no-op - excluding them keeps intellisense honest).
|
|
725
|
+
const GRID_API_UNSETTABLE: ReadonlySet<string> = new Set<string>([
|
|
726
|
+
'data', 'columns', 'features', 'loading', 'onApiReady',
|
|
727
|
+
'externalSort', 'externalFilter', 'externalPagination', 'rowCount', 'pageIndex',
|
|
728
|
+
'initialSorting', 'initialColumnPinning', 'initialHiddenColumns', 'columnOrder',
|
|
729
|
+
])
|
|
730
|
+
|
|
731
|
+
/** The Grid props settable at runtime through `ctx.grid.<prop> = value` (backed by
|
|
732
|
+
* `api.setOption`): the full extracted SvGrid surface minus controller-owned /
|
|
733
|
+
* seed-once props and function/snippet props. Drives the `ctx.grid` type + the code
|
|
734
|
+
* view autocomplete. Sorted alphabetically. */
|
|
735
|
+
export function gridApiSettableProps(): UiComponentProp[] {
|
|
736
|
+
const g = GENERATED_UI_SURFACE['SvGrid']
|
|
737
|
+
if (!g) return []
|
|
738
|
+
return g.props
|
|
739
|
+
.filter((p) => !GRID_API_UNSETTABLE.has(p.key) && !p.code && !/^on[A-Z]/.test(p.key))
|
|
740
|
+
.map((p) => ({ ...p }) as UiComponentProp)
|
|
741
|
+
.sort((a, b) => a.key.localeCompare(b.key))
|
|
742
|
+
}
|