@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.
package/index.esm.js CHANGED
@@ -1,3 +1,711 @@
1
- export { c as createUVESubscription, e as editContentlet, b as enableBlockEditorInline, g as getUVEState, a as initInlineEditing, d as initUVE, i as isAnalyticsActive, r as reorderMenu, s as sendMessageToUVE, u as updateNavigation } from './public.esm.js';
2
- import '@dotcms/types';
1
+ import { g as getUVEState, s as sendMessageToUVE } from './public.esm.js';
2
+ export { c as createUVESubscription, e as editContentlet, b as enableBlockEditorInline, a as initInlineEditing, d as initUVE, i as isAnalyticsActive, r as reorderMenu, u as updateNavigation } from './public.esm.js';
3
+ import { UVE_MODE, DotCMSUVEAction } from '@dotcms/types';
3
4
  import '@dotcms/types/internal';
5
+
6
+ /**
7
+ * Normalizes a field definition into the schema format expected by UVE.
8
+ *
9
+ * Converts developer-friendly field definitions into a normalized structure where
10
+ * all type-specific configuration properties are moved into a `config` object.
11
+ * This transformation ensures consistency in the schema format sent to UVE.
12
+ *
13
+ * **Field Type Handling:**
14
+ * - **Input fields**: Extracts `inputType`, `placeholder`, and `defaultValue` into config
15
+ * - **Dropdown fields**: Normalizes options (strings become `{ label, value }` objects),
16
+ * extracts `placeholder` and `defaultValue` into config
17
+ * - **Radio fields**: Normalizes options (preserves image properties like `imageURL`, `width`, `height`),
18
+ * extracts `defaultValue` into config
19
+ * - **Checkbox group fields**: Normalizes options and derives `defaultValue` from option values
20
+ * (creates Record<string, boolean> mapping option keys to their boolean values)
21
+ *
22
+ * @experimental This method is experimental and may be subject to change.
23
+ *
24
+ * @param field - The field definition to normalize. Must be one of: input, dropdown, radio, or checkboxGroup
25
+ * @returns The normalized field schema with type, label, and config properties ready to be sent to UVE
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // Input field normalization
30
+ * normalizeField({
31
+ * type: 'input',
32
+ * label: 'Font Size',
33
+ * inputType: 'number',
34
+ * defaultValue: 16,
35
+ * placeholder: 'Enter size'
36
+ * })
37
+ * // Returns: {
38
+ * // type: 'input',
39
+ * // label: 'Font Size',
40
+ * // config: { inputType: 'number', defaultValue: 16, placeholder: 'Enter size' }
41
+ * // }
42
+ *
43
+ * // Dropdown field with string options normalization
44
+ * normalizeField({
45
+ * type: 'dropdown',
46
+ * label: 'Font Family',
47
+ * options: ['Arial', 'Helvetica']
48
+ * })
49
+ * // Returns: {
50
+ * // type: 'dropdown',
51
+ * // label: 'Font Family',
52
+ * // config: { options: [{ label: 'Arial', value: 'Arial' }, { label: 'Helvetica', value: 'Helvetica' }] }
53
+ * // }
54
+ * ```
55
+ */
56
+ function normalizeField(field) {
57
+ const base = {
58
+ type: field.type,
59
+ label: field.label,
60
+ id: field.id
61
+ };
62
+ const config = {};
63
+ // Handle type-specific properties
64
+ if (field.type === 'input') {
65
+ config.inputType = field.inputType;
66
+ config.placeholder = field.placeholder;
67
+ config.defaultValue = field.defaultValue;
68
+ }
69
+ if (field.type === 'dropdown' || field.type === 'radio') {
70
+ // Normalize options to consistent format
71
+ config.options = field.options.map(opt => typeof opt === 'string' ? {
72
+ label: opt,
73
+ value: opt
74
+ } : opt);
75
+ config.defaultValue = field.defaultValue;
76
+ // Handle radio-specific properties
77
+ if (field.type === 'radio') {
78
+ config.columns = field.columns;
79
+ }
80
+ }
81
+ if (field.type === 'checkboxGroup') {
82
+ // Normalize checkbox options - convert to format expected by UVE
83
+ // Options already have label, key, and value (boolean)
84
+ config.options = field.options.map(opt => ({
85
+ label: opt.label,
86
+ value: opt.key // UVE expects 'value' to be the key identifier
87
+ }));
88
+ // Derive defaultValue from options - map key to boolean value
89
+ config.defaultValue = field.options.reduce((acc, opt) => {
90
+ acc[opt.key] = opt.value;
91
+ return acc;
92
+ }, {});
93
+ }
94
+ return {
95
+ ...base,
96
+ config
97
+ };
98
+ }
99
+ /**
100
+ * Normalizes a section definition into the schema format expected by UVE.
101
+ *
102
+ * Converts a section with a flat array of fields into the normalized schema format
103
+ * where fields are organized as a multi-dimensional array (array of column arrays).
104
+ * Currently, all sections are normalized to a single-column layout structure.
105
+ *
106
+ * **Normalization Process:**
107
+ * 1. Normalizes each field in the section using `normalizeField`
108
+ * 2. Wraps the normalized fields array in an outer array to create the column structure
109
+ * 3. Preserves the section title
110
+ *
111
+ * The output format always uses a multi-dimensional array structure (`fields: StyleEditorFieldSchema[][]`),
112
+ * even for single-column layouts, ensuring consistency in the UVE schema format.
113
+ *
114
+ * @experimental This method is experimental and may be subject to change.
115
+ *
116
+ * @param section - The section definition to normalize, containing a title and array of fields
117
+ * @param section.title - The section title displayed to users
118
+ * @param section.fields - Array of field definitions to normalize
119
+ * @returns The normalized section schema with fields organized as a single-column array structure
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * normalizeSection({
124
+ * title: 'Typography',
125
+ * fields: [
126
+ * { type: 'input', label: 'Font Size', inputType: 'number' },
127
+ * { type: 'dropdown', label: 'Font Family', options: ['Arial'] }
128
+ * ]
129
+ * })
130
+ * // Returns: {
131
+ * // title: 'Typography',
132
+ * // fields: [
133
+ * // [
134
+ * // { type: 'input', label: 'Font Size', config: { inputType: 'number' } },
135
+ * // { type: 'dropdown', label: 'Font Family', config: { options: [...] } }
136
+ * // ]
137
+ * // ]
138
+ * // }
139
+ * ```
140
+ */
141
+ function normalizeSection(section) {
142
+ // Determine if fields is multi-column or single column
143
+ const normalizedFields = section.fields.map(normalizeField);
144
+ return {
145
+ title: section.title,
146
+ fields: normalizedFields
147
+ };
148
+ }
149
+ /**
150
+ * Normalizes a complete form definition into the schema format expected by UVE.
151
+ *
152
+ * This is the main entry point for converting a developer-friendly form definition
153
+ * into the normalized schema structure that UVE (Universal Visual Editor) can consume.
154
+ * The normalization process transforms the entire form hierarchy:
155
+ *
156
+ * **Normalization Process:**
157
+ * 1. Preserves the `contentType` identifier
158
+ * 2. Processes each section using `normalizeSection`, which:
159
+ * - Normalizes all fields in the section using `normalizeField`
160
+ * - Organizes fields into the required multi-dimensional array structure
161
+ * 3. Returns a fully normalized schema with consistent structure across all sections
162
+ *
163
+ * The resulting schema has all field-specific properties moved into `config` objects
164
+ * and all sections using the consistent single-column array structure, regardless
165
+ * of the input format.
166
+ *
167
+ * @experimental This method is experimental and may be subject to change.
168
+ *
169
+ * @param form - The complete form definition to normalize
170
+ * @param form.contentType - The content type identifier this form is associated with
171
+ * @param form.sections - Array of section definitions, each containing a title and fields
172
+ * @returns The normalized form schema ready to be sent to UVE, with all fields and sections normalized
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * const schema = normalizeForm({
177
+ * contentType: 'my-content-type',
178
+ * sections: [
179
+ * {
180
+ * title: 'Typography',
181
+ * fields: [
182
+ * { type: 'input', label: 'Font Size', inputType: 'number', defaultValue: 16 },
183
+ * { type: 'dropdown', label: 'Font Family', options: ['Arial', 'Helvetica'] }
184
+ * ]
185
+ * },
186
+ * {
187
+ * title: 'Colors',
188
+ * fields: [
189
+ * { type: 'input', label: 'Primary Color', inputType: 'text', defaultValue: '#000000' }
190
+ * ]
191
+ * }
192
+ * ]
193
+ * });
194
+ * // Returns: {
195
+ * // contentType: 'my-content-type',
196
+ * // sections: [
197
+ * // {
198
+ * // title: 'Typography',
199
+ * // fields: [
200
+ * // [
201
+ * // { type: 'input', label: 'Font Size', config: { inputType: 'number', defaultValue: 16 } },
202
+ * // { type: 'dropdown', label: 'Font Family', config: { options: [...] } }
203
+ * // ]
204
+ * // ]
205
+ * // },
206
+ * // {
207
+ * // title: 'Colors',
208
+ * // fields: [
209
+ * // [
210
+ * // { type: 'input', label: 'Primary Color', config: { inputType: 'text', defaultValue: '#000000' } }
211
+ * // ]
212
+ * // ]
213
+ * // }
214
+ * // ]
215
+ * // }
216
+ * ```
217
+ */
218
+ function normalizeForm(form) {
219
+ return {
220
+ contentType: form.contentType,
221
+ sections: form.sections.map(normalizeSection)
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Helper functions for creating style editor field definitions.
227
+ *
228
+ * Provides type-safe factory functions for creating different types of form fields
229
+ * used in the style editor. Each function creates a field definition with the
230
+ * appropriate `type` property automatically set, eliminating the need to manually
231
+ * specify the type discriminator.
232
+ *
233
+ * **Available Field Types:**
234
+ * - `input`: Text or number input fields
235
+ * - `dropdown`: Single-value selection from a dropdown list
236
+ * - `radio`: Single-value selection from radio button options (supports visual options with images)
237
+ * - `checkboxGroup`: Multiple-value selection from checkbox options
238
+ *
239
+ * These factory functions ensure type safety by inferring the correct field type
240
+ * based on the configuration provided, and they automatically set the `type` property
241
+ * to match the factory function used.
242
+ *
243
+ * @experimental This API is experimental and may be subject to change.
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * const form = defineStyleEditorSchema({
248
+ * contentType: 'my-content-type',
249
+ * sections: [
250
+ * {
251
+ * title: 'Typography',
252
+ * fields: [
253
+ * styleEditorField.input({
254
+ * label: 'Font Size',
255
+ * inputType: 'number',
256
+ * defaultValue: 16
257
+ * }),
258
+ * styleEditorField.dropdown({
259
+ * label: 'Font Family',
260
+ * options: ['Arial', 'Helvetica'],
261
+ * defaultValue: 'Arial'
262
+ * }),
263
+ * styleEditorField.radio({
264
+ * label: 'Alignment',
265
+ * options: ['Left', 'Center', 'Right'],
266
+ * defaultValue: 'Left'
267
+ * })
268
+ * ]
269
+ * }
270
+ * ]
271
+ * });
272
+ * ```
273
+ */
274
+ const styleEditorField = {
275
+ /**
276
+ * Creates an input field definition with type-safe default values.
277
+ *
278
+ * Supports both text and number input types. The `defaultValue` type is
279
+ * enforced based on the `inputType` using TypeScript generics:
280
+ * - When `inputType` is `'number'`, `defaultValue` must be a `number`
281
+ * - When `inputType` is `'text'`, `defaultValue` must be a `string`
282
+ *
283
+ * This provides compile-time type checking to prevent mismatched types,
284
+ * such as passing a string when a number is expected.
285
+ *
286
+ * @experimental This method is experimental and may be subject to change.
287
+ *
288
+ * @typeParam T - The input type ('text' or 'number'), inferred from `config.inputType`
289
+ * @param config - Input field configuration
290
+ * @param config.label - The label displayed for this input field
291
+ * @param config.inputType - The type of input ('text' or 'number')
292
+ * @param config.placeholder - Optional placeholder text for the input
293
+ * @param config.defaultValue - Optional default value (type enforced based on inputType)
294
+ * @returns A complete input field definition with type 'input'
295
+ *
296
+ * @example
297
+ * ```typescript
298
+ * // Number input - defaultValue must be a number
299
+ * styleEditorField.input({
300
+ * label: 'Font Size',
301
+ * inputType: 'number',
302
+ * placeholder: 'Enter font size',
303
+ * defaultValue: 16 // ✓ Correct: number
304
+ * })
305
+ *
306
+ * // Text input - defaultValue must be a string
307
+ * styleEditorField.input({
308
+ * label: 'Font Name',
309
+ * inputType: 'text',
310
+ * placeholder: 'Enter font name',
311
+ * defaultValue: 'Arial' // ✓ Correct: string
312
+ * })
313
+ *
314
+ * // TypeScript error - type mismatch
315
+ * styleEditorField.input({
316
+ * label: 'Font Size',
317
+ * inputType: 'number',
318
+ * defaultValue: '16' // ✗ Error: Type 'string' is not assignable to type 'number'
319
+ * })
320
+ * ```
321
+ */
322
+ input: config => ({
323
+ type: 'input',
324
+ ...config
325
+ }),
326
+ /**
327
+ * Creates a dropdown field definition with type-safe default values.
328
+ *
329
+ * Allows users to select a single value from a list of options.
330
+ * Options can be provided as simple strings or as objects with label and value.
331
+ *
332
+ * **Type Safety Tip:** For autocomplete on `defaultValue`, use `as const` when defining options:
333
+ * ```typescript
334
+ * const options = [
335
+ * { label: 'The one', value: 'one' },
336
+ * { label: 'The two', value: 'two' }
337
+ * ] as const;
338
+ *
339
+ * styleEditorField.dropdown({
340
+ * id: 'my-field',
341
+ * label: 'Select option',
342
+ * options,
343
+ * defaultValue: 'one' // ✓ Autocomplete works! TypeScript knows 'one' | 'two'
344
+ * // defaultValue: 'three' // ✗ TypeScript error: not assignable
345
+ * })
346
+ * ```
347
+ *
348
+ * Without `as const`, the function still works but won't provide autocomplete:
349
+ * ```typescript
350
+ * styleEditorField.dropdown({
351
+ * id: 'my-field',
352
+ * label: 'Select option',
353
+ * options: [
354
+ * { label: 'The one', value: 'one' },
355
+ * { label: 'The two', value: 'two' }
356
+ * ],
357
+ * defaultValue: 'one' // Works, but no autocomplete
358
+ * })
359
+ * ```
360
+ *
361
+ * @experimental This method is experimental and may be subject to change.
362
+ *
363
+ * @typeParam TOptions - The options array type (inferred from config, use `as const` for type safety)
364
+ * @param config - Dropdown field configuration (without the 'type' property)
365
+ * @param config.id - The unique identifier for this field
366
+ * @param config.label - The label displayed for this dropdown field
367
+ * @param config.options - Array of options. Use `as const` for type safety and autocomplete
368
+ * @param config.defaultValue - Optional default selected value (type-safe when options are `as const`)
369
+ * @returns A complete dropdown field definition with type 'dropdown'
370
+ *
371
+ * @example
372
+ * ```typescript
373
+ * // With type safety - use 'as const' for autocomplete
374
+ * const options = [
375
+ * { label: 'The one', value: 'one' },
376
+ * { label: 'The two', value: 'two' }
377
+ * ] as const;
378
+ *
379
+ * styleEditorField.dropdown({
380
+ * id: 'my-field',
381
+ * label: 'Select option',
382
+ * options,
383
+ * defaultValue: 'one' // ✓ Autocomplete works!
384
+ * })
385
+ *
386
+ * // Simple string options
387
+ * styleEditorField.dropdown({
388
+ * id: 'font-family',
389
+ * label: 'Font Family',
390
+ * options: ['Arial', 'Helvetica', 'Times New Roman'],
391
+ * defaultValue: 'Arial',
392
+ * placeholder: 'Select a font'
393
+ * })
394
+ *
395
+ * // Object options with custom labels
396
+ * styleEditorField.dropdown({
397
+ * id: 'theme',
398
+ * label: 'Theme',
399
+ * options: [
400
+ * { label: 'Light Theme', value: 'light' },
401
+ * { label: 'Dark Theme', value: 'dark' }
402
+ * ],
403
+ * defaultValue: 'light'
404
+ * })
405
+ * ```
406
+ */
407
+ dropdown: config => ({
408
+ type: 'dropdown',
409
+ ...config,
410
+ options: config.options,
411
+ defaultValue: config.defaultValue
412
+ }),
413
+ /**
414
+ * Creates a radio button field definition with type-safe default values.
415
+ *
416
+ * Allows users to select a single option from a list. Supports visual
417
+ * options with background images for enhanced UI. Options can be provided
418
+ * as simple strings or as objects with label, value, and optional image properties.
419
+ *
420
+ * **Layout Options:**
421
+ * - `columns: 1` (default): Single column list layout
422
+ * - `columns: 2`: Two-column grid layout, ideal for visual options with images
423
+ *
424
+ * **Type Safety Tip:** For autocomplete on `defaultValue`, use `as const` when defining options:
425
+ * ```typescript
426
+ * const options = [
427
+ * { label: 'The one', value: 'one' },
428
+ * { label: 'The two', value: 'two' }
429
+ * ] as const;
430
+ *
431
+ * styleEditorField.radio({
432
+ * id: 'my-field',
433
+ * label: 'Select option',
434
+ * options,
435
+ * defaultValue: 'one' // ✓ Autocomplete works! TypeScript knows 'one' | 'two'
436
+ * // defaultValue: 'three' // ✗ TypeScript error: not assignable
437
+ * })
438
+ * ```
439
+ *
440
+ * Without `as const`, the function still works but won't provide autocomplete:
441
+ * ```typescript
442
+ * styleEditorField.radio({
443
+ * id: 'my-field',
444
+ * label: 'Select option',
445
+ * options: [
446
+ * { label: 'The one', value: 'one' },
447
+ * { label: 'The two', value: 'two' }
448
+ * ],
449
+ * defaultValue: 'one' // Works, but no autocomplete
450
+ * })
451
+ * ```
452
+ *
453
+ * @experimental This method is experimental and may be subject to change.
454
+ *
455
+ * @typeParam TOptions - The options array type (inferred from config, use `as const` for type safety)
456
+ * @param config - Radio field configuration (without the 'type' property)
457
+ * @param config.id - The unique identifier for this field
458
+ * @param config.label - The label displayed for this radio group
459
+ * @param config.options - Array of options. Use `as const` for type safety and autocomplete
460
+ * @param config.defaultValue - Optional default selected value (type-safe when options are `as const`)
461
+ * @param config.columns - Optional number of columns (1 or 2). Defaults to 1 (single column)
462
+ * @returns A complete radio field definition with type 'radio'
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * // With type safety - use 'as const' for autocomplete
467
+ * const options = [
468
+ * { label: 'The one', value: 'one' },
469
+ * { label: 'The two', value: 'two' }
470
+ * ] as const;
471
+ *
472
+ * styleEditorField.radio({
473
+ * id: 'my-field',
474
+ * label: 'Select option',
475
+ * options,
476
+ * defaultValue: 'one' // ✓ Autocomplete works!
477
+ * })
478
+ *
479
+ * // Simple string options (single column)
480
+ * styleEditorField.radio({
481
+ * id: 'alignment',
482
+ * label: 'Alignment',
483
+ * options: ['Left', 'Center', 'Right'],
484
+ * defaultValue: 'Left'
485
+ * })
486
+ *
487
+ * // Two-column grid layout with images
488
+ * styleEditorField.radio({
489
+ * id: 'layout',
490
+ * label: 'Layout',
491
+ * columns: 2,
492
+ * options: [
493
+ * {
494
+ * label: 'Left',
495
+ * value: 'left',
496
+ * imageURL: 'https://example.com/layout-left.png',
497
+ * },
498
+ * {
499
+ * label: 'Right',
500
+ * value: 'right',
501
+ * imageURL: 'https://example.com/layout-right.png',
502
+ * },
503
+ * { label: 'Center', value: 'center' },
504
+ * { label: 'Overlap', value: 'overlap' }
505
+ * ],
506
+ * defaultValue: 'right'
507
+ * })
508
+ * ```
509
+ */
510
+ radio: config => ({
511
+ type: 'radio',
512
+ ...config,
513
+ options: config.options,
514
+ defaultValue: config.defaultValue
515
+ }),
516
+ /**
517
+ * Creates a checkbox group field definition.
518
+ *
519
+ * Allows users to select multiple options simultaneously. Each option
520
+ * can be independently checked or unchecked. The default checked state
521
+ * is defined directly in each option's `value` property (boolean).
522
+ *
523
+ * **Key Differences from Other Field Types:**
524
+ * - Uses `key` instead of `value` for the identifier (to avoid confusion)
525
+ * - Uses `value` for the default boolean checked state (the actual value)
526
+ * - No separate `defaultValue` property - defaults are embedded in options
527
+ *
528
+ * **Why `key` instead of `value`?**
529
+ * In dropdown and radio fields, `value` represents the actual selected value (string).
530
+ * In checkbox groups, the actual value is boolean (checked/unchecked), so we use
531
+ * `key` for the identifier to avoid confusion. This makes it clear that `value`
532
+ * is the boolean state, not just an identifier.
533
+ *
534
+ * @experimental This method is experimental and may be subject to change.
535
+ *
536
+ * @param config - Checkbox group field configuration (without the 'type' property)
537
+ * @param config.id - The unique identifier for this field
538
+ * @param config.label - The label displayed for this checkbox group
539
+ * @param config.options - Array of checkbox options with label, key, and value (boolean)
540
+ * @returns A complete checkbox group field definition with type 'checkboxGroup'
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * styleEditorField.checkboxGroup({
545
+ * id: 'text-decoration',
546
+ * label: 'Text Decoration',
547
+ * options: [
548
+ * { label: 'Underline', key: 'underline', value: true },
549
+ * { label: 'Overline', key: 'overline', value: false },
550
+ * { label: 'Line Through', key: 'line-through', value: false }
551
+ * ]
552
+ * // No defaultValue needed - it's automatically derived from options
553
+ * })
554
+ *
555
+ * // Example with type settings
556
+ * styleEditorField.checkboxGroup({
557
+ * id: 'type-settings',
558
+ * label: 'Type settings',
559
+ * options: [
560
+ * { label: 'Bold', key: 'bold', value: true },
561
+ * { label: 'Italic', key: 'italic', value: false },
562
+ * { label: 'Underline', key: 'underline', value: false },
563
+ * { label: 'Strikethrough', key: 'strikethrough', value: false }
564
+ * ]
565
+ * })
566
+ * ```
567
+ */
568
+ checkboxGroup: config => ({
569
+ type: 'checkboxGroup',
570
+ ...config
571
+ })
572
+ };
573
+ /**
574
+ * Normalizes and validates a style editor form definition.
575
+ *
576
+ * Converts the developer-friendly form structure into the schema format
577
+ * expected by UVE (Universal Visual Editor). This function processes the
578
+ * form definition and transforms it into the normalized schema format where:
579
+ *
580
+ * - All field-specific properties are moved into `config` objects
581
+ * - String options are normalized to `{ label, value }` objects
582
+ * - Sections are organized into the multi-dimensional array structure required by UVE
583
+ *
584
+ * The normalization process ensures consistency and type safety in the schema
585
+ * format sent to UVE. After normalization, use `registerStyleEditorSchemas`
586
+ * to register the schema with the UVE editor.
587
+ *
588
+ * @experimental This method is experimental and may be subject to change.
589
+ *
590
+ * @param form - The style editor form definition containing contentType and sections
591
+ * @param form.contentType - The content type identifier for this form
592
+ * @param form.sections - Array of sections, each containing a title and fields array
593
+ * @returns The normalized form schema ready to be sent to UVE
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * const formSchema = defineStyleEditorSchema({
598
+ * contentType: 'my-content-type',
599
+ * sections: [
600
+ * {
601
+ * title: 'Typography',
602
+ * fields: [
603
+ * styleEditorField.input({
604
+ * label: 'Font Size',
605
+ * inputType: 'number',
606
+ * defaultValue: 16
607
+ * }),
608
+ * styleEditorField.dropdown({
609
+ * label: 'Font Family',
610
+ * options: ['Arial', 'Helvetica'],
611
+ * defaultValue: 'Arial'
612
+ * })
613
+ * ]
614
+ * },
615
+ * {
616
+ * title: 'Colors',
617
+ * fields: [
618
+ * styleEditorField.input({
619
+ * label: 'Primary Color',
620
+ * inputType: 'text',
621
+ * defaultValue: '#000000'
622
+ * }),
623
+ * styleEditorField.input({
624
+ * label: 'Secondary Color',
625
+ * inputType: 'text',
626
+ * defaultValue: '#FFFFFF'
627
+ * })
628
+ * ]
629
+ * }
630
+ * ]
631
+ * });
632
+ *
633
+ * // Register the schema with UVE
634
+ * registerStyleEditorSchemas([formSchema]);
635
+ * ```
636
+ */
637
+ function defineStyleEditorSchema(form) {
638
+ return normalizeForm(form);
639
+ }
640
+ /**
641
+ * Registers style editor form schemas with the UVE editor.
642
+ *
643
+ * Sends normalized style editor schemas to the UVE (Universal Visual Editor)
644
+ * for registration. The schemas must be normalized using `defineStyleEditorSchema`
645
+ * before being passed to this function.
646
+ *
647
+ * **Behavior:**
648
+ * - Only registers schemas when UVE is in EDIT mode
649
+ * - Validates that each schema has a `contentType` property
650
+ * - Skips schemas without `contentType` and logs a warning
651
+ * - Sends the validated schemas to UVE via the `REGISTER_STYLE_SCHEMAS` action
652
+ *
653
+ * **Note:** This function will silently return early if UVE is not in EDIT mode,
654
+ * so it's safe to call even when the editor is not active.
655
+ *
656
+ * @experimental This method is experimental and may be subject to change.
657
+ *
658
+ * @param schemas - Array of normalized style editor form schemas to register with UVE
659
+ * @returns void - This function does not return a value
660
+ *
661
+ * @example
662
+ * ```typescript
663
+ * // Create and normalize a form schema
664
+ * const formSchema = defineStyleEditorSchema({
665
+ * contentType: 'my-content-type',
666
+ * sections: [
667
+ * {
668
+ * title: 'Typography',
669
+ * fields: [
670
+ * styleEditorField.input({
671
+ * label: 'Font Size',
672
+ * inputType: 'number',
673
+ * defaultValue: 16
674
+ * })
675
+ * ]
676
+ * }
677
+ * ]
678
+ * });
679
+ *
680
+ * // Register the schema with UVE
681
+ * registerStyleEditorSchemas([formSchema]);
682
+ *
683
+ * // Register multiple schemas at once
684
+ * const schema1 = defineStyleEditorSchema({ ... });
685
+ * const schema2 = defineStyleEditorSchema({ ... });
686
+ * registerStyleEditorSchemas([schema1, schema2]);
687
+ * ```
688
+ */
689
+ function registerStyleEditorSchemas(schemas) {
690
+ const {
691
+ mode
692
+ } = getUVEState() || {};
693
+ if (!mode || mode !== UVE_MODE.EDIT) {
694
+ return;
695
+ }
696
+ const validatedSchemas = schemas.filter((schema, index) => {
697
+ if (!schema.contentType) {
698
+ console.warn(`[registerStyleEditorSchemas] Skipping schema with index [${index}] for not having a contentType`);
699
+ return false;
700
+ }
701
+ return true;
702
+ });
703
+ sendMessageToUVE({
704
+ action: DotCMSUVEAction.REGISTER_STYLE_SCHEMAS,
705
+ payload: {
706
+ schemas: validatedSchemas
707
+ }
708
+ });
709
+ }
710
+
711
+ export { defineStyleEditorSchema, getUVEState, registerStyleEditorSchemas, sendMessageToUVE, styleEditorField };