@dotcms/uve 1.2.0 → 1.2.1-next.10

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.
@@ -0,0 +1,809 @@
1
+ /**
2
+ * Available field types for the style editor.
3
+ *
4
+ * Each field type represents a different input control that can be used
5
+ * in the style editor form. Currently supported field types:
6
+ * - `input`: Text or number input fields
7
+ * - `dropdown`: Single-value selection from a dropdown list
8
+ * - `radio`: Single-value selection from radio button options
9
+ * - `checkboxGroup`: Multiple-value selection from checkbox options
10
+ * - `switch`: Boolean toggle switch (reserved for future implementation)
11
+ */
12
+ export type StyleEditorFieldType = 'input' | 'dropdown' | 'radio' | 'checkboxGroup';
13
+ /**
14
+ * Available input types for input fields in the style editor.
15
+ *
16
+ * Determines the type of input control and the expected value type:
17
+ * - `'text'`: Standard text input for string values (e.g., font names, color codes)
18
+ * - `'number'`: Numeric input for number values (e.g., font sizes, dimensions)
19
+ *
20
+ * The input type is used in conjunction with `StyleEditorInputField` to ensure
21
+ * type safety between the input type and the default value.
22
+ */
23
+ export type StyleEditorFieldInputType = 'text' | 'number';
24
+ /**
25
+ * Helper type that maps input types to their corresponding default value types.
26
+ *
27
+ * This conditional type ensures type safety between `inputType` and `defaultValue`:
28
+ * - When `T` is `'number'`, the mapped type is `number`
29
+ * - When `T` is `'text'`, the mapped type is `string`
30
+ *
31
+ * Used by `StyleEditorInputFieldConfig` to enforce the correct default value type
32
+ * based on the input type.
33
+ */
34
+ export type StyleEditorInputValueType<T extends StyleEditorFieldInputType> = T extends 'number' ? number : string;
35
+ /**
36
+ * Configuration type for creating input fields with type-safe default values.
37
+ *
38
+ * This generic type ensures that the `defaultValue` type matches the `inputType`:
39
+ * - When `inputType` is `'number'`, `defaultValue` must be a `number`
40
+ * - When `inputType` is `'text'`, `defaultValue` must be a `string`
41
+ *
42
+ * This type is used by `styleEditorField.input()` to provide compile-time
43
+ * type checking and prevent mismatched input types and default values.
44
+ *
45
+ * @typeParam T - The input type ('text' or 'number')
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // Valid: number inputType with number defaultValue
50
+ * const config: StyleEditorInputFieldConfig<'number'> = {
51
+ * label: 'Font Size',
52
+ * inputType: 'number',
53
+ * defaultValue: 16 // ✓ Correct: number
54
+ * };
55
+ *
56
+ * // TypeScript error: string not assignable to number
57
+ * const invalid: StyleEditorInputFieldConfig<'number'> = {
58
+ * label: 'Font Size',
59
+ * inputType: 'number',
60
+ * defaultValue: '16' // ✗ Error: Type 'string' is not assignable to type 'number'
61
+ * };
62
+ * ```
63
+ */
64
+ export interface StyleEditorInputFieldConfig<T extends StyleEditorFieldInputType> {
65
+ /** The unique identifier for this field */
66
+ id: string;
67
+ /** The label text displayed to users for this field */
68
+ label: string;
69
+ /** The input type that determines the value type ('text' for strings, 'number' for numbers) */
70
+ inputType: T;
71
+ /** Optional placeholder text shown when the input is empty */
72
+ placeholder?: string;
73
+ /** Optional default value (type is enforced based on inputType: number for 'number', string for 'text') */
74
+ defaultValue?: StyleEditorInputValueType<T>;
75
+ }
76
+ /**
77
+ * Base option object with label and value properties.
78
+ *
79
+ * Used in dropdown, radio, and checkbox group fields to define
80
+ * selectable options with separate display labels and values.
81
+ *
82
+ * @property label - Display label shown to users
83
+ * @property value - Value returned when this option is selected
84
+ */
85
+ export interface StyleEditorOptionObject {
86
+ /** Display label shown to users */
87
+ label: string;
88
+ /** Value returned when this option is selected */
89
+ value: string;
90
+ }
91
+ /**
92
+ * Extended option object for radio fields with visual properties.
93
+ *
94
+ * Extends the base option with optional image properties for
95
+ * creating visual radio button options (e.g., layout selectors with preview images).
96
+ *
97
+ * @property label - Display label shown to users
98
+ * @property value - Value returned when this option is selected
99
+ * @property imageURL - Optional URL to an image displayed for this option
100
+ */
101
+ export interface StyleEditorRadioOptionObject extends StyleEditorOptionObject {
102
+ /** Optional URL to an image displayed for this option */
103
+ imageURL?: string;
104
+ }
105
+ /**
106
+ * Option type for dropdown and checkbox group fields.
107
+ *
108
+ * Can be a simple string (used as both label and value)
109
+ * or an object with separate label and value properties.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * // String option - 'Arial' is used as both label and value
114
+ * const stringOption: StyleEditorOption = 'Arial';
115
+ *
116
+ * // Object option - separate label and value
117
+ * const objectOption: StyleEditorOption = {
118
+ * label: 'Times New Roman',
119
+ * value: 'times'
120
+ * };
121
+ * ```
122
+ */
123
+ export type StyleEditorOption = StyleEditorOptionObject;
124
+ /**
125
+ * Helper type that extracts the union of all option values from an array of options.
126
+ *
127
+ * This type extracts the `value` property from each option object and creates
128
+ * a union type of all possible values. This enables type-safe `defaultValue`
129
+ * that can only be one of the option values when used with `as const`.
130
+ *
131
+ * **Note:** For full type safety and autocomplete, use `as const` when defining options:
132
+ * ```typescript
133
+ * const options = [
134
+ * { label: 'The one', value: 'one' },
135
+ * { label: 'The two', value: 'two' }
136
+ * ] as const;
137
+ * ```
138
+ *
139
+ * @typeParam T - Array of option objects (should be `as const` for best results)
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const options = [
144
+ * { label: 'The one', value: 'one' },
145
+ * { label: 'The two', value: 'two' }
146
+ * ] as const;
147
+ *
148
+ * type OptionValues = StyleEditorOptionValues<typeof options>;
149
+ * // Result: 'one' | 'two'
150
+ * ```
151
+ */
152
+ export type StyleEditorOptionValues<T extends readonly StyleEditorOption[]> = T[number] extends {
153
+ value: infer V;
154
+ } ? V : never;
155
+ /**
156
+ * Helper type that extracts the union of all radio option values from an array of radio options.
157
+ *
158
+ * Similar to `StyleEditorOptionValues`, but handles radio options which can be
159
+ * strings or objects. Extracts the `value` property from option objects, or uses
160
+ * the string itself if the option is a string.
161
+ *
162
+ * **Note:** For full type safety and autocomplete, use `as const` when defining options:
163
+ * ```typescript
164
+ * const options = [
165
+ * { label: 'The one', value: 'one' },
166
+ * { label: 'The two', value: 'two' }
167
+ * ] as const;
168
+ * ```
169
+ *
170
+ * @typeParam T - Array of radio option objects or strings (should be `as const` for best results)
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const options = [
175
+ * { label: 'The one', value: 'one' },
176
+ * { label: 'The two', value: 'two' }
177
+ * ] as const;
178
+ *
179
+ * type RadioOptionValues = StyleEditorRadioOptionValues<typeof options>;
180
+ * // Result: 'one' | 'two'
181
+ * ```
182
+ */
183
+ export type StyleEditorRadioOptionValues<T extends readonly StyleEditorRadioOption[]> = T[number] extends infer U ? U extends string ? U : U extends {
184
+ value: infer V;
185
+ } ? V : never : never;
186
+ /**
187
+ * Option type for radio fields with visual support.
188
+ *
189
+ * Can be a simple string (used as both label and value)
190
+ * or an object with label, value, and optional image properties.
191
+ *
192
+ * @example
193
+ * ```typescript
194
+ * // String option
195
+ * const stringOption: StyleEditorRadioOption = 'Left';
196
+ *
197
+ * // Object option with image
198
+ * const imageOption: StyleEditorRadioOption = {
199
+ * label: 'Left Layout',
200
+ * value: 'left',
201
+ * imageURL: 'https://example.com/left-layout.png'
202
+ * };
203
+ * ```
204
+ */
205
+ export type StyleEditorRadioOption = string | StyleEditorRadioOptionObject;
206
+ /**
207
+ * Checkbox option object with label, key identifier, and default boolean value.
208
+ *
209
+ * Unlike dropdown and radio options where `value` represents the actual value,
210
+ * checkbox options use `key` as the identifier and `value` as the default checked state (boolean).
211
+ * This distinction makes it clear that the boolean is the actual value, not just an identifier.
212
+ *
213
+ * @property label - Display label shown to users
214
+ * @property key - Unique identifier/key used in the defaultValue object
215
+ * @property value - Default checked state (true or false)
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * const checkboxOption: StyleEditorCheckboxOption = {
220
+ * label: 'Underline',
221
+ * key: 'underline',
222
+ * value: true
223
+ * };
224
+ * ```
225
+ */
226
+ export interface StyleEditorCheckboxOption {
227
+ /** Display label shown to users */
228
+ label: string;
229
+ /** Unique identifier/key used in the defaultValue object */
230
+ key: string;
231
+ /** Default checked state (true = checked by default, false = unchecked by default) */
232
+ value: boolean;
233
+ }
234
+ /**
235
+ * Default value type for checkbox group fields.
236
+ *
237
+ * A record mapping option keys to their boolean checked state.
238
+ * This is derived automatically from checkbox options during normalization.
239
+ * Keys match the `key` property from checkbox options, values indicate whether the option is checked.
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * const defaultState: StyleEditorCheckboxDefaultValue = {
244
+ * 'underline': true,
245
+ * 'overline': false,
246
+ * 'line-through': false
247
+ * };
248
+ * ```
249
+ */
250
+ export type StyleEditorCheckboxDefaultValue = Record<string, boolean>;
251
+ /**
252
+ * Base field definition that all field types extend.
253
+ *
254
+ * Provides the common properties shared by all field types in the style editor.
255
+ * All specific field types must include these base properties. The `type` property
256
+ * serves as a discriminator that allows TypeScript to narrow union types based on
257
+ * the field type.
258
+ *
259
+ * @property type - The type of field (discriminator for union types, enables type narrowing)
260
+ * @property label - The human-readable label displayed for this field in the UI
261
+ */
262
+ export interface StyleEditorBaseField {
263
+ /** The unique identifier for this field */
264
+ id: string;
265
+ /** The type of field, used to discriminate between different field types in union types */
266
+ type: StyleEditorFieldType;
267
+ /** The label text displayed to users for this field */
268
+ label: string;
269
+ }
270
+ /**
271
+ * Input field definition with type-safe defaultValue based on inputType.
272
+ *
273
+ * This is a discriminated union type that ensures type safety between
274
+ * the `inputType` and `defaultValue` properties. TypeScript will enforce
275
+ * that the `defaultValue` type matches the `inputType`:
276
+ * - When `inputType` is `'number'`, `defaultValue` must be a `number`
277
+ * - When `inputType` is `'text'`, `defaultValue` must be a `string`
278
+ *
279
+ * This type safety prevents runtime errors and ensures that numeric inputs
280
+ * receive numeric values and text inputs receive string values.
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * // Number input with number defaultValue
285
+ * const numberField: StyleEditorInputField = {
286
+ * type: 'input',
287
+ * label: 'Font Size',
288
+ * inputType: 'number',
289
+ * defaultValue: 16, // TypeScript ensures this is a number
290
+ * placeholder: 'Enter font size'
291
+ * };
292
+ *
293
+ * // Text input with string defaultValue
294
+ * const textField: StyleEditorInputField = {
295
+ * type: 'input',
296
+ * label: 'Font Name',
297
+ * inputType: 'text',
298
+ * defaultValue: 'Arial', // TypeScript ensures this is a string
299
+ * placeholder: 'Enter font name'
300
+ * };
301
+ *
302
+ * // TypeScript error: type mismatch
303
+ * // const invalid: StyleEditorInputField = {
304
+ * // type: 'input',
305
+ * // label: 'Size',
306
+ * // inputType: 'number',
307
+ * // defaultValue: '16' // Error: string not assignable to number
308
+ * // };
309
+ * ```
310
+ */
311
+ export type StyleEditorInputField = (StyleEditorBaseField & {
312
+ /** Discriminator: must be 'input' */
313
+ type: 'input';
314
+ /** Input type for number values */
315
+ inputType: 'number';
316
+ /** Optional placeholder text shown when the input is empty */
317
+ placeholder?: string;
318
+ /** Optional default value (must be a number when inputType is 'number') */
319
+ defaultValue?: number;
320
+ }) | (StyleEditorBaseField & {
321
+ /** Discriminator: must be 'input' */
322
+ type: 'input';
323
+ /** Input type for text/string values */
324
+ inputType: 'text';
325
+ /** Optional placeholder text shown when the input is empty */
326
+ placeholder?: string;
327
+ /** Optional default value (must be a string when inputType is 'text') */
328
+ defaultValue?: string;
329
+ });
330
+ /**
331
+ * Dropdown field definition for single-value selection.
332
+ *
333
+ * Allows users to select a single option from a dropdown list.
334
+ * Options can be provided as simple strings or as objects with
335
+ * separate label and value properties for more flexibility.
336
+ *
337
+ * **Type Safety Tip:** For autocomplete on `defaultValue`, use `as const` when defining options:
338
+ * ```typescript
339
+ * const options = [
340
+ * { label: 'The one', value: 'one' },
341
+ * { label: 'The two', value: 'two' }
342
+ * ] as const;
343
+ *
344
+ * styleEditorField.dropdown({
345
+ * options,
346
+ * defaultValue: 'one' // ✓ Autocomplete works! TypeScript knows 'one' | 'two'
347
+ * })
348
+ * ```
349
+ *
350
+ * @property type - Must be 'dropdown'
351
+ * @property options - Array of selectable options. Can be strings or objects with label/value
352
+ * @property defaultValue - Optional default selected value (must match one of the option values)
353
+ *
354
+ * @example
355
+ * ```typescript
356
+ * const dropdownField: StyleEditorDropdownField = {
357
+ * type: 'dropdown',
358
+ * label: 'Font Family',
359
+ * options: ['Arial', 'Helvetica', { label: 'Times New Roman', value: 'times' }],
360
+ * defaultValue: 'Arial'
361
+ * };
362
+ * ```
363
+ */
364
+ export interface StyleEditorDropdownField extends StyleEditorBaseField {
365
+ /** Discriminator: must be 'dropdown' */
366
+ type: 'dropdown';
367
+ /** Array of selectable options. Can be strings or objects with label and value properties */
368
+ options: StyleEditorOption[];
369
+ /** Optional default selected value (must match one of the option values) */
370
+ defaultValue?: string;
371
+ }
372
+ /**
373
+ * Radio button field definition for single-value selection with visual options.
374
+ *
375
+ * Allows users to select a single option from a radio button group.
376
+ * Supports visual options with background images for enhanced UI/UX.
377
+ * Options can be provided as simple strings or as objects with label,
378
+ * value, and optional image properties.
379
+ *
380
+ * **Layout Options:**
381
+ * - `columns: 1` (default): Single column list layout
382
+ * - `columns: 2`: Two-column grid layout, ideal for visual options with images
383
+ *
384
+ * **Type Safety Tip:** For autocomplete on `defaultValue`, use `as const` when defining options:
385
+ * ```typescript
386
+ * const options = [
387
+ * { label: 'The one', value: 'one' },
388
+ * { label: 'The two', value: 'two' }
389
+ * ] as const;
390
+ *
391
+ * styleEditorField.radio({
392
+ * id: 'my-field',
393
+ * label: 'Select option',
394
+ * options,
395
+ * defaultValue: 'one' // ✓ Autocomplete works! TypeScript knows 'one' | 'two'
396
+ * // defaultValue: 'three' // ✗ TypeScript error: not assignable
397
+ * })
398
+ * ```
399
+ *
400
+ * Without `as const`, the function still works but won't provide autocomplete:
401
+ * ```typescript
402
+ * styleEditorField.radio({
403
+ * id: 'my-field',
404
+ * label: 'Select option',
405
+ * options: [
406
+ * { label: 'The one', value: 'one' },
407
+ * { label: 'The two', value: 'two' }
408
+ * ],
409
+ * defaultValue: 'one' // Works, but no autocomplete
410
+ * })
411
+ * ```
412
+ *
413
+ * @property type - Must be 'radio'
414
+ * @property options - Array of selectable options. Can be strings or objects with label, value, and optional image properties
415
+ * @property defaultValue - Optional default selected value (must match one of the option values)
416
+ * @property columns - Optional number of columns for layout (1 or 2). Defaults to 1
417
+ *
418
+ * @example
419
+ * ```typescript
420
+ * // With type safety - use 'as const' for autocomplete
421
+ * const options = [
422
+ * { label: 'The one', value: 'one' },
423
+ * { label: 'The two', value: 'two' }
424
+ * ] as const;
425
+ *
426
+ * const radioField: StyleEditorRadioField = {
427
+ * type: 'radio',
428
+ * id: 'my-field',
429
+ * label: 'Select option',
430
+ * options,
431
+ * defaultValue: 'one' // ✓ Autocomplete works!
432
+ * };
433
+ *
434
+ * // Single column layout (default)
435
+ * const alignmentField: StyleEditorRadioField = {
436
+ * type: 'radio',
437
+ * id: 'alignment',
438
+ * label: 'Alignment',
439
+ * options: ['Left', 'Center', 'Right'],
440
+ * defaultValue: 'Left'
441
+ * };
442
+ *
443
+ * // Two-column grid layout with images
444
+ * const layoutField: StyleEditorRadioField = {
445
+ * type: 'radio',
446
+ * id: 'layout',
447
+ * label: 'Layout',
448
+ * columns: 2,
449
+ * options: [
450
+ * {
451
+ * label: 'Left',
452
+ * value: 'left',
453
+ * imageURL: 'https://example.com/layout-left.png'
454
+ * },
455
+ * {
456
+ * label: 'Right',
457
+ * value: 'right',
458
+ * imageURL: 'https://example.com/layout-right.png'
459
+ * },
460
+ * { label: 'Center', value: 'center' },
461
+ * { label: 'Overlap', value: 'overlap' }
462
+ * ],
463
+ * defaultValue: 'right'
464
+ * };
465
+ * ```
466
+ */
467
+ export interface StyleEditorRadioField extends StyleEditorBaseField {
468
+ /** Discriminator: must be 'radio' */
469
+ type: 'radio';
470
+ /**
471
+ * Array of selectable options. Can be:
472
+ * - Simple strings (used as both label and value)
473
+ * - Objects with label, value, and optional imageURL for visual options
474
+ */
475
+ options: StyleEditorRadioOption[];
476
+ /** Optional default selected value (must match one of the option values) */
477
+ defaultValue?: string;
478
+ /**
479
+ * Number of columns to display options in.
480
+ * - `1`: Single column list layout (default)
481
+ * - `2`: Two-column grid layout
482
+ */
483
+ columns?: 1 | 2;
484
+ }
485
+ /**
486
+ * Checkbox group field definition for multiple-value selection.
487
+ *
488
+ * Allows users to select multiple options simultaneously. Each option
489
+ * can be independently checked or unchecked. The default checked state
490
+ * is defined directly in each option's `value` property (boolean).
491
+ *
492
+ * **Key Differences from Other Field Types:**
493
+ * - Uses `key` instead of `value` for the identifier (to avoid confusion)
494
+ * - Uses `value` for the default boolean checked state (the actual value)
495
+ * - No separate `defaultValue` property - defaults are embedded in options
496
+ *
497
+ * @property type - Must be 'checkboxGroup'
498
+ * @property options - Array of checkbox options with label, key, and value (boolean)
499
+ *
500
+ * @example
501
+ * ```typescript
502
+ * const checkboxField: StyleEditorCheckboxGroupField = {
503
+ * type: 'checkboxGroup',
504
+ * id: 'text-decoration',
505
+ * label: 'Text Decoration',
506
+ * options: [
507
+ * { label: 'Underline', key: 'underline', value: true },
508
+ * { label: 'Overline', key: 'overline', value: false },
509
+ * { label: 'Line Through', key: 'line-through', value: false }
510
+ * ]
511
+ * // No defaultValue needed - it's derived from options during normalization
512
+ * };
513
+ * ```
514
+ */
515
+ export interface StyleEditorCheckboxGroupField extends StyleEditorBaseField {
516
+ /** Discriminator: must be 'checkboxGroup' */
517
+ type: 'checkboxGroup';
518
+ /**
519
+ * Array of checkbox options. Each option contains:
520
+ * - `label`: Display text shown to users
521
+ * - `key`: Unique identifier used in the normalized defaultValue object
522
+ * - `value`: Default checked state (true = checked, false = unchecked)
523
+ */
524
+ options: StyleEditorCheckboxOption[];
525
+ }
526
+ /**
527
+ * Union type of all possible field definitions.
528
+ *
529
+ * Represents any valid field type that can be used in a style editor form.
530
+ * This is a discriminated union type, meaning TypeScript can narrow the type
531
+ * based on the `type` property. Use this type when you need to work with
532
+ * fields of unknown or mixed types.
533
+ *
534
+ * **Supported Field Types:**
535
+ * - `StyleEditorInputField`: Text or number input fields
536
+ * - `StyleEditorDropdownField`: Single-value selection from dropdown
537
+ * - `StyleEditorRadioField`: Single-value selection from radio buttons
538
+ * - `StyleEditorCheckboxGroupField`: Multiple-value selection from checkboxes
539
+ *
540
+ * **Note:** The `switch` field type is reserved for future implementation
541
+ * and is not currently included in this union type.
542
+ *
543
+ * @example
544
+ * ```typescript
545
+ * const fields: StyleEditorField[] = [
546
+ * { type: 'input', id: 'font-size', label: 'Font Size', inputType: 'number', defaultValue: 16 },
547
+ * { type: 'dropdown', id: 'font-family', label: 'Font Family', options: ['Arial', 'Helvetica'] },
548
+ * { type: 'radio', id: 'theme', label: 'Theme', options: ['Light', 'Dark'] },
549
+ * {
550
+ * type: 'checkboxGroup',
551
+ * id: 'styles',
552
+ * label: 'Styles',
553
+ * options: [
554
+ * { label: 'Bold', key: 'bold', value: true },
555
+ * { label: 'Italic', key: 'italic', value: false }
556
+ * ]
557
+ * }
558
+ * ];
559
+ *
560
+ * // TypeScript can narrow the type based on the discriminator
561
+ * function processField(field: StyleEditorField) {
562
+ * if (field.type === 'input') {
563
+ * // field is now narrowed to StyleEditorInputField
564
+ * console.log(field.inputType); // Type-safe access
565
+ * }
566
+ * }
567
+ * ```
568
+ */
569
+ export type StyleEditorField = StyleEditorInputField | StyleEditorDropdownField | StyleEditorRadioField | StyleEditorCheckboxGroupField;
570
+ /**
571
+ * Section definition for organizing fields in a style editor form.
572
+ *
573
+ * Sections group related fields together with a title. All sections use a
574
+ * single-column layout with a flat array of fields. During normalization,
575
+ * these fields are automatically organized into the multi-dimensional array
576
+ * structure required by UVE.
577
+ *
578
+ * @property title - The section title displayed to users
579
+ * @property fields - Array of field definitions in this section
580
+ *
581
+ * @example
582
+ * ```typescript
583
+ * const section: StyleEditorSection = {
584
+ * title: 'Typography',
585
+ * fields: [
586
+ * { type: 'input', label: 'Font Size', inputType: 'number', defaultValue: 16 },
587
+ * { type: 'dropdown', label: 'Font Family', options: ['Arial', 'Helvetica'] },
588
+ * { type: 'radio', label: 'Alignment', options: ['Left', 'Center', 'Right'] }
589
+ * ]
590
+ * };
591
+ * ```
592
+ */
593
+ export interface StyleEditorSection {
594
+ /** The section title displayed to users */
595
+ title: string;
596
+ /** Array of field definitions in this section */
597
+ fields: StyleEditorField[];
598
+ }
599
+ /**
600
+ * Complete style editor form definition.
601
+ *
602
+ * Represents the full structure of a style editor form, including
603
+ * the content type identifier and all sections with their fields.
604
+ * This is the developer-friendly format used to define forms before
605
+ * they are normalized and sent to UVE.
606
+ *
607
+ * **Form Structure:**
608
+ * - Each form is associated with a specific content type via `contentType`
609
+ * - Forms contain one or more sections, each with a title and array of fields
610
+ * - All sections use a single-column layout (flat array of fields)
611
+ * - During normalization via `defineStyleEditorForm`, sections are automatically
612
+ * converted to the multi-dimensional array structure required by UVE
613
+ *
614
+ * @property contentType - The content type identifier this form is associated with
615
+ * @property sections - Array of sections, each containing a title and fields array
616
+ *
617
+ * @example
618
+ * ```typescript
619
+ * const form: StyleEditorForm = {
620
+ * contentType: 'my-content-type',
621
+ * sections: [
622
+ * {
623
+ * title: 'Typography',
624
+ * fields: [
625
+ * { type: 'input', label: 'Font Size', inputType: 'number', defaultValue: 16 },
626
+ * { type: 'dropdown', label: 'Font Family', options: ['Arial', 'Helvetica'] },
627
+ * { type: 'radio', label: 'Alignment', options: ['Left', 'Center', 'Right'] }
628
+ * ]
629
+ * },
630
+ * {
631
+ * title: 'Colors',
632
+ * fields: [
633
+ * { type: 'input', label: 'Primary Color', inputType: 'text', defaultValue: '#000000' },
634
+ * { type: 'input', label: 'Secondary Color', inputType: 'text', defaultValue: '#FFFFFF' }
635
+ * ]
636
+ * }
637
+ * ]
638
+ * };
639
+ * ```
640
+ */
641
+ export interface StyleEditorForm {
642
+ /** The content type identifier this form is associated with */
643
+ contentType: string;
644
+ /** Array of sections, each containing a title and fields */
645
+ sections: StyleEditorSection[];
646
+ }
647
+ /**
648
+ * ============================================================================
649
+ * UVE Style Editor Schema Types
650
+ * ============================================================================
651
+ *
652
+ * The following types represent the normalized schema format sent to UVE
653
+ * (Universal Visual Editor). These are the output types after processing
654
+ * and normalizing the developer-friendly StyleEditorForm definitions.
655
+ * ============================================================================
656
+ */
657
+ /**
658
+ * Configuration object for normalized field schemas.
659
+ *
660
+ * Contains all possible field-specific properties after normalization.
661
+ * This interface is used by `StyleEditorFieldSchema` to define the `config` property.
662
+ *
663
+ * **Note:** All properties are optional since different field types use different subsets:
664
+ * - Input fields use: `inputType`, `placeholder`, `defaultValue`
665
+ * - Dropdown fields use: `options`, `defaultValue`
666
+ * - Radio fields use: `options`, `columns`, `defaultValue`
667
+ * - Checkbox fields use: `options`, `defaultValue` (derived from option values during normalization)
668
+ */
669
+ export interface StyleEditorFieldSchemaConfig {
670
+ /** Optional input type for input fields ('text' or 'number') */
671
+ inputType?: StyleEditorFieldInputType;
672
+ /** Optional placeholder text shown when the field is empty */
673
+ placeholder?: string;
674
+ /**
675
+ * Optional array of normalized options for dropdown, radio, and checkbox fields.
676
+ * In the normalized schema, options are always in object form (strings are converted).
677
+ * Uses `StyleEditorRadioOptionObject` as the superset that supports all option properties.
678
+ */
679
+ options?: StyleEditorRadioOptionObject[];
680
+ /**
681
+ * Optional default value. Type depends on field type:
682
+ * - Input fields: string or number
683
+ * - Switch fields: boolean
684
+ * - Checkbox groups: StyleEditorCheckboxDefaultValue
685
+ */
686
+ defaultValue?: string | number | boolean | StyleEditorCheckboxDefaultValue;
687
+ /**
688
+ * Number of columns to display options in (for radio fields).
689
+ * - `1`: Single column list layout (default)
690
+ * - `2`: Two-column grid layout
691
+ */
692
+ columns?: 1 | 2;
693
+ }
694
+ /**
695
+ * Normalized field schema sent to UVE.
696
+ *
697
+ * This is the transformed format of field definitions after normalization.
698
+ * All field-specific properties are moved into a `config` object, ensuring
699
+ * a consistent structure that UVE can consume.
700
+ *
701
+ * **Normalization Process:**
702
+ * - Type-specific properties (like `inputType`, `options`, `placeholder`) are moved into `config`
703
+ * - String options are normalized to `{ label, value }` objects
704
+ * - Radio field image properties (`imageURL`) are preserved in option objects
705
+ * - The `type` and `label` remain at the top level for easy access
706
+ *
707
+ * @property type - The field type identifier (discriminator for field types)
708
+ * @property label - The human-readable label displayed for this field
709
+ * @property config - Object containing all field-specific configuration properties
710
+ */
711
+ export interface StyleEditorFieldSchema {
712
+ /** The unique identifier for this field */
713
+ id: string;
714
+ /** The field type identifier */
715
+ type: StyleEditorFieldType;
716
+ /** The field label */
717
+ label: string;
718
+ /** Object containing all field-specific configuration */
719
+ config: StyleEditorFieldSchemaConfig;
720
+ }
721
+ /**
722
+ * Normalized section schema sent to UVE.
723
+ *
724
+ * Represents a section in the normalized UVE format. All sections
725
+ * use a consistent multi-dimensional array structure (array of arrays),
726
+ * even for single-column layouts. This ensures a uniform schema format
727
+ * that UVE can consume.
728
+ *
729
+ * **Structure:**
730
+ * - The `fields` property is always a two-dimensional array
731
+ * - Each inner array represents a column (currently all sections use a single column)
732
+ * - Each field in the inner arrays is a normalized `StyleEditorFieldSchema` with
733
+ * all properties moved into the `config` object
734
+ *
735
+ * @property title - The section title displayed to users
736
+ * @property fields - Two-dimensional array where each inner array contains normalized field schemas for a column
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * // Single-column section (normalized format)
741
+ * const sectionSchema: StyleEditorSectionSchema = {
742
+ * title: 'Typography',
743
+ * fields: [
744
+ * // Single column containing all fields
745
+ * [
746
+ * { type: 'input', label: 'Font Size', config: { inputType: 'number', defaultValue: 16 } },
747
+ * { type: 'dropdown', label: 'Font Family', config: { options: [...] } }
748
+ * ]
749
+ * ]
750
+ * };
751
+ * ```
752
+ */
753
+ export interface StyleEditorSectionSchema {
754
+ /** The section title displayed to users */
755
+ title: string;
756
+ /** Two-dimensional array where each inner array contains normalized field schemas for a column */
757
+ fields: StyleEditorFieldSchema[];
758
+ }
759
+ /**
760
+ * Complete normalized form schema sent to UVE.
761
+ *
762
+ * This is the final output format after normalizing a `StyleEditorForm` using
763
+ * `defineStyleEditorForm`. The form structure is transformed into a consistent
764
+ * schema format that UVE (Universal Visual Editor) can consume.
765
+ *
766
+ * **Normalization Characteristics:**
767
+ * - All sections use the multi-dimensional array structure (`fields: StyleEditorFieldSchema[][]`)
768
+ * - All field-specific properties are moved into `config` objects
769
+ * - String options are normalized to `{ label, value }` objects
770
+ * - The `contentType` identifier is preserved for association with content types
771
+ *
772
+ * This schema format is ready to be sent to UVE via `registerStyleEditorSchemas`.
773
+ *
774
+ * @property contentType - The content type identifier this form is associated with
775
+ * @property sections - Array of normalized section schemas, each with fields organized as a multi-dimensional array
776
+ *
777
+ * @example
778
+ * ```typescript
779
+ * const formSchema: StyleEditorFormSchema = {
780
+ * contentType: 'my-content-type',
781
+ * sections: [
782
+ * {
783
+ * title: 'Typography',
784
+ * fields: [
785
+ * // Single column containing all fields
786
+ * [
787
+ * { type: 'input', label: 'Font Size', config: { inputType: 'number', defaultValue: 16 } },
788
+ * { type: 'dropdown', label: 'Font Family', config: { options: [{ label: 'Arial', value: 'Arial' }] } }
789
+ * ]
790
+ * ]
791
+ * },
792
+ * {
793
+ * title: 'Colors',
794
+ * fields: [
795
+ * [
796
+ * { type: 'input', label: 'Primary Color', config: { inputType: 'text', defaultValue: '#000000' } }
797
+ * ]
798
+ * ]
799
+ * }
800
+ * ]
801
+ * };
802
+ * ```
803
+ */
804
+ export interface StyleEditorFormSchema {
805
+ /** The content type identifier this form is associated with */
806
+ contentType: string;
807
+ /** Array of normalized section schemas */
808
+ sections: StyleEditorSectionSchema[];
809
+ }