@dotcms/uve 1.5.1-next.1964 → 1.5.1-next.1965
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/README.md +5 -1010
- package/index.cjs.js +1 -621
- package/index.esm.js +2 -624
- package/internal.cjs.js +301 -1
- package/internal.esm.js +300 -3
- package/package.json +1 -1
- package/src/index.d.ts +0 -2
- package/src/internal.d.ts +3 -0
- package/src/lib/style-editor/internal.d.ts +18 -1
- package/src/lib/style-editor/public.d.ts +3 -341
- package/src/lib/style-editor/types.d.ts +6 -620
package/README.md
CHANGED
|
@@ -32,18 +32,7 @@ With `@dotcms/uve`, framework SDKs are able to:
|
|
|
32
32
|
- [`sendMessageToUVE()`](#sendmessagetouvemessage)
|
|
33
33
|
- [Style Editor](#style-editor)
|
|
34
34
|
- [What is the Style Editor?](#what-is-the-style-editor)
|
|
35
|
-
- [Quick Start](#quick-start)
|
|
36
|
-
- [`defineStyleEditorSchema()`](#definestyleeditorschemaform)
|
|
37
|
-
- [Field Types](#field-types)
|
|
38
|
-
- [`styleEditorField.input()`](#styleeditorfieldinputconfig)
|
|
39
|
-
- [`styleEditorField.dropdown()`](#styleeditorfielddropdownconfig)
|
|
40
|
-
- [`styleEditorField.radio()`](#styleditorfieldradioconfig)
|
|
41
|
-
- [`styleEditorField.checkboxGroup()`](#styleeditorfieldcheckboxgroupconfig)
|
|
42
|
-
- [`registerStyleEditorSchemas()`](#registerstyleeditorschemasschemas)
|
|
43
|
-
- [`useStyleEditorSchemas()` (React Hook)](#usestyleeditorschemasschemas-react-hook)
|
|
44
35
|
- [Accessing Style Values](#accessing-style-values)
|
|
45
|
-
- [Best Practices](#best-practices)
|
|
46
|
-
- [Complete Example](#complete-example)
|
|
47
36
|
- [Current Capabilities and Limitations](#current-capabilities-and-limitations)
|
|
48
37
|
- [Troubleshooting](#troubleshooting)
|
|
49
38
|
- [Common Issues & Solutions](#common-issues--solutions)
|
|
@@ -492,15 +481,15 @@ sendMessageToUVE({
|
|
|
492
481
|
|
|
493
482
|
### What is the Style Editor?
|
|
494
483
|
|
|
495
|
-
The Style Editor is a powerful feature that enables content authors
|
|
484
|
+
The Style Editor is a powerful feature that enables content authors to customize component appearance, layout, typography, colors, and other configurable aspects in real time within the Universal Visual Editor (UVE), without requiring code changes or page reloads.
|
|
485
|
+
|
|
486
|
+
Style editor schemas are configured in the DotCMS admin UI under **Content Types** (in the content type metadata). The SDK fetches schemas automatically — no schema definition code is required in your application.
|
|
496
487
|
|
|
497
488
|
**Key Benefits:**
|
|
498
489
|
|
|
499
490
|
- **Real-Time Visual Editing**: Modify component styles and see changes instantly in the editor
|
|
500
491
|
- **Content-Specific Customization**: Different content types can have unique style schemas, and the same contentlet could have different styles depending on if it is located in a different container or page
|
|
501
|
-
- **
|
|
502
|
-
- **Flexible Configuration**: Support for text inputs, dropdowns, radio buttons, and checkbox groups
|
|
503
|
-
- **Type-Safe**: Full TypeScript support with type inference for option values
|
|
492
|
+
- **Admin-Managed**: Style schemas are defined in the DotCMS admin UI under Content Types and fetched automatically by the SDK
|
|
504
493
|
|
|
505
494
|
**Use Cases:**
|
|
506
495
|
|
|
@@ -511,568 +500,6 @@ The Style Editor is a powerful feature that enables content authors and develope
|
|
|
511
500
|
- Control responsive behavior
|
|
512
501
|
- Modify animation settings
|
|
513
502
|
|
|
514
|
-
### Quick Start
|
|
515
|
-
|
|
516
|
-
**1. Install the required packages:**
|
|
517
|
-
|
|
518
|
-
```bash
|
|
519
|
-
npm install @dotcms/uve@latest
|
|
520
|
-
npm install @dotcms/types@latest --save-dev
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
**2. Define a style editor schema:**
|
|
524
|
-
|
|
525
|
-
```typescript
|
|
526
|
-
import { defineStyleEditorSchema, styleEditorField } from '@dotcms/uve';
|
|
527
|
-
|
|
528
|
-
const mySchema = defineStyleEditorSchema({
|
|
529
|
-
contentType: 'BlogPost',
|
|
530
|
-
sections: [
|
|
531
|
-
{
|
|
532
|
-
title: 'Typography',
|
|
533
|
-
fields: [
|
|
534
|
-
styleEditorField.dropdown({
|
|
535
|
-
id: 'font-size',
|
|
536
|
-
label: 'Font Size',
|
|
537
|
-
options: [
|
|
538
|
-
{ label: 'Small (14px)', value: '14px' },
|
|
539
|
-
{ label: 'Medium (16px)', value: '16px' },
|
|
540
|
-
{ label: 'Large (18px)', value: '18px' }
|
|
541
|
-
]
|
|
542
|
-
})
|
|
543
|
-
]
|
|
544
|
-
}
|
|
545
|
-
]
|
|
546
|
-
});
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
**3. Register the schema:**
|
|
550
|
-
|
|
551
|
-
**Using React:**
|
|
552
|
-
|
|
553
|
-
```typescript
|
|
554
|
-
import { useStyleEditorSchemas } from '@dotcms/react';
|
|
555
|
-
|
|
556
|
-
function MyComponent() {
|
|
557
|
-
useStyleEditorSchemas([mySchema]);
|
|
558
|
-
|
|
559
|
-
return <div>Your component content</div>;
|
|
560
|
-
}
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
**Using vanilla JavaScript:**
|
|
564
|
-
|
|
565
|
-
```typescript
|
|
566
|
-
import { registerStyleEditorSchemas } from '@dotcms/uve';
|
|
567
|
-
|
|
568
|
-
registerStyleEditorSchemas([mySchema]);
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
### `defineStyleEditorSchema(form)`
|
|
572
|
-
|
|
573
|
-
`defineStyleEditorSchema` creates a normalized style editor schema that UVE can process. It validates your form definition and converts it into the format expected by the Universal Visual Editor.
|
|
574
|
-
|
|
575
|
-
| Input | Type | Required | Description |
|
|
576
|
-
| ------ | ------------------ | -------- | ------------------------------------------------------ |
|
|
577
|
-
| `form` | `StyleEditorForm` | ✅ | The form definition with content type, sections, and fields |
|
|
578
|
-
|
|
579
|
-
**Returns:** `StyleEditorFormSchema` - A normalized schema ready for registration with UVE
|
|
580
|
-
|
|
581
|
-
#### StyleEditorForm Structure
|
|
582
|
-
|
|
583
|
-
```typescript
|
|
584
|
-
interface StyleEditorForm {
|
|
585
|
-
contentType: string; // The content type identifier
|
|
586
|
-
sections: StyleEditorSection[]; // Array of form sections
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
interface StyleEditorSection {
|
|
590
|
-
title: string; // Section heading displayed in the editor
|
|
591
|
-
fields: StyleEditorField[]; // Array of field definitions
|
|
592
|
-
}
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
#### Usage
|
|
596
|
-
|
|
597
|
-
```typescript
|
|
598
|
-
import { defineStyleEditorSchema, styleEditorField } from '@dotcms/uve';
|
|
599
|
-
|
|
600
|
-
const schema = defineStyleEditorSchema({
|
|
601
|
-
contentType: 'Activity',
|
|
602
|
-
sections: [
|
|
603
|
-
{
|
|
604
|
-
title: 'Typography',
|
|
605
|
-
fields: [
|
|
606
|
-
styleEditorField.input({
|
|
607
|
-
id: 'heading-size',
|
|
608
|
-
label: 'Heading Size',
|
|
609
|
-
inputType: 'number',
|
|
610
|
-
placeholder: '24'
|
|
611
|
-
}),
|
|
612
|
-
styleEditorField.dropdown({
|
|
613
|
-
id: 'font-family',
|
|
614
|
-
label: 'Font Family',
|
|
615
|
-
options: ['Arial', 'Helvetica', 'Georgia']
|
|
616
|
-
})
|
|
617
|
-
]
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
title: 'Layout',
|
|
621
|
-
fields: [
|
|
622
|
-
styleEditorField.radio({
|
|
623
|
-
id: 'alignment',
|
|
624
|
-
label: 'Text Alignment',
|
|
625
|
-
options: ['Left', 'Center', 'Right']
|
|
626
|
-
})
|
|
627
|
-
]
|
|
628
|
-
}
|
|
629
|
-
]
|
|
630
|
-
});
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
**⚠️ Important Notes:**
|
|
634
|
-
|
|
635
|
-
- Each field must have a unique `id` within the schema
|
|
636
|
-
- The `contentType` must match the content type in your dotCMS instance
|
|
637
|
-
- Schemas are only processed when UVE is in EDIT mode
|
|
638
|
-
|
|
639
|
-
### Field Types
|
|
640
|
-
|
|
641
|
-
The Style Editor supports four field types, each designed for specific use cases. Use the `styleEditorField` factory functions to create type-safe field definitions.
|
|
642
|
-
|
|
643
|
-
#### `styleEditorField.input(config)`
|
|
644
|
-
|
|
645
|
-
Creates a text or number input field for free-form entry.
|
|
646
|
-
|
|
647
|
-
**Configuration:**
|
|
648
|
-
|
|
649
|
-
```typescript
|
|
650
|
-
interface StyleEditorInputFieldConfig {
|
|
651
|
-
id: string; // Unique identifier
|
|
652
|
-
label: string; // Display label
|
|
653
|
-
inputType: StyleEditorFieldInputType; // Input type
|
|
654
|
-
placeholder?: string; // Optional placeholder text
|
|
655
|
-
}
|
|
656
|
-
```
|
|
657
|
-
|
|
658
|
-
**Use Cases:**
|
|
659
|
-
|
|
660
|
-
- Custom values (e.g., font sizes, margins, colors)
|
|
661
|
-
- Numeric settings (e.g., animation duration, opacity)
|
|
662
|
-
- Text values (e.g., CSS class names, custom IDs)
|
|
663
|
-
|
|
664
|
-
**Examples:**
|
|
665
|
-
|
|
666
|
-
```typescript
|
|
667
|
-
// Number input for pixel values
|
|
668
|
-
styleEditorField.input({
|
|
669
|
-
id: 'padding-top',
|
|
670
|
-
label: 'Top Padding (px)',
|
|
671
|
-
inputType: 'number',
|
|
672
|
-
placeholder: '16'
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
// Text input for custom CSS
|
|
676
|
-
styleEditorField.input({
|
|
677
|
-
id: 'custom-class',
|
|
678
|
-
label: 'Custom CSS Class',
|
|
679
|
-
inputType: 'text',
|
|
680
|
-
placeholder: 'my-custom-style'
|
|
681
|
-
});
|
|
682
|
-
|
|
683
|
-
// Number input with decimal values
|
|
684
|
-
styleEditorField.input({
|
|
685
|
-
id: 'opacity',
|
|
686
|
-
label: 'Opacity',
|
|
687
|
-
inputType: 'number',
|
|
688
|
-
placeholder: '1.0'
|
|
689
|
-
});
|
|
690
|
-
```
|
|
691
|
-
|
|
692
|
-
#### `styleEditorField.dropdown(config)`
|
|
693
|
-
|
|
694
|
-
Creates a dropdown (select) field with predefined options. Users can select one value from the list.
|
|
695
|
-
|
|
696
|
-
**Configuration:**
|
|
697
|
-
|
|
698
|
-
```typescript
|
|
699
|
-
interface StyleEditorDropdownField {
|
|
700
|
-
id: string; // Unique identifier
|
|
701
|
-
label: string; // Display label
|
|
702
|
-
options: StyleEditorOption[]; // Array of options
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
type StyleEditorOption = { label: string; value: string };
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
**Use Cases:**
|
|
709
|
-
|
|
710
|
-
- Predefined sizes (e.g., small, medium, large)
|
|
711
|
-
- Font families or style presets
|
|
712
|
-
- Color themes
|
|
713
|
-
- Any single-choice selection from a list
|
|
714
|
-
|
|
715
|
-
**Examples:**
|
|
716
|
-
|
|
717
|
-
```typescript
|
|
718
|
-
// Font size options
|
|
719
|
-
const FONT_SIZES = [
|
|
720
|
-
{ label: 'Extra Small (12px)', value: '12px' },
|
|
721
|
-
{ label: 'Small (14px)', value: '14px' },
|
|
722
|
-
{ label: 'Medium (16px)', value: '16px' },
|
|
723
|
-
{ label: 'Large (18px)', value: '18px' },
|
|
724
|
-
{ label: 'Extra Large (24px)', value: '24px' }
|
|
725
|
-
];
|
|
726
|
-
|
|
727
|
-
styleEditorField.dropdown({
|
|
728
|
-
id: 'font-size',
|
|
729
|
-
label: 'Font Size',
|
|
730
|
-
options: FONT_SIZES
|
|
731
|
-
});
|
|
732
|
-
|
|
733
|
-
// Theme selection
|
|
734
|
-
styleEditorField.dropdown({
|
|
735
|
-
id: 'theme',
|
|
736
|
-
label: 'Color Theme',
|
|
737
|
-
options: [
|
|
738
|
-
{ label: 'Light Theme', value: 'light' },
|
|
739
|
-
{ label: 'Dark Theme', value: 'dark' },
|
|
740
|
-
{ label: 'High Contrast', value: 'high-contrast' }
|
|
741
|
-
]
|
|
742
|
-
});
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
#### `styleEditorField.radio(config)`
|
|
747
|
-
|
|
748
|
-
Creates a radio button group for single-choice selection. Optionally supports images for visual selection.
|
|
749
|
-
|
|
750
|
-
**Configuration:**
|
|
751
|
-
|
|
752
|
-
```typescript
|
|
753
|
-
interface StyleEditorRadioField {
|
|
754
|
-
id: string; // Unique identifier
|
|
755
|
-
label: string; // Display label
|
|
756
|
-
options: StyleEditorRadioOption[]; // Array of options
|
|
757
|
-
columns?: 1 | 2; // Layout: 1 or 2 columns (default: 1)
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
type StyleEditorRadioOption = {
|
|
761
|
-
label: string;
|
|
762
|
-
value: string;
|
|
763
|
-
imageURL?: string; // Optional preview image
|
|
764
|
-
};
|
|
765
|
-
```
|
|
766
|
-
|
|
767
|
-
**Use Cases:**
|
|
768
|
-
|
|
769
|
-
- Layout selection with visual previews
|
|
770
|
-
- Alignment options (left, center, right)
|
|
771
|
-
- Style variants with images
|
|
772
|
-
- Any single-choice where visual feedback is helpful
|
|
773
|
-
|
|
774
|
-
**Examples:**
|
|
775
|
-
|
|
776
|
-
```typescript
|
|
777
|
-
// Simple text options
|
|
778
|
-
styleEditorField.radio({
|
|
779
|
-
id: 'text-align',
|
|
780
|
-
label: 'Text Alignment',
|
|
781
|
-
options: [
|
|
782
|
-
{ label: 'Left', value: 'left' },
|
|
783
|
-
{ label: 'Center', value: 'center' },
|
|
784
|
-
{ label: 'Right', value: 'right' },
|
|
785
|
-
{ label: 'Justify', value: 'justify' }
|
|
786
|
-
]
|
|
787
|
-
});
|
|
788
|
-
|
|
789
|
-
// Two-column layout with images
|
|
790
|
-
const LAYOUT_OPTIONS = [
|
|
791
|
-
{
|
|
792
|
-
label: 'Left Sidebar',
|
|
793
|
-
value: 'left',
|
|
794
|
-
imageURL: 'https://example.com/layouts/left-sidebar.png'
|
|
795
|
-
},
|
|
796
|
-
{
|
|
797
|
-
label: 'Right Sidebar',
|
|
798
|
-
value: 'right',
|
|
799
|
-
imageURL: 'https://example.com/layouts/right-sidebar.png'
|
|
800
|
-
},
|
|
801
|
-
{
|
|
802
|
-
label: 'Full Width',
|
|
803
|
-
value: 'full',
|
|
804
|
-
imageURL: 'https://example.com/layouts/full-width.png'
|
|
805
|
-
},
|
|
806
|
-
{
|
|
807
|
-
label: 'Split View',
|
|
808
|
-
value: 'split',
|
|
809
|
-
imageURL: 'https://example.com/layouts/split-view.png'
|
|
810
|
-
}
|
|
811
|
-
];
|
|
812
|
-
|
|
813
|
-
styleEditorField.radio({
|
|
814
|
-
id: 'page-layout',
|
|
815
|
-
label: 'Page Layout',
|
|
816
|
-
columns: 2, // Display in 2-column grid
|
|
817
|
-
options: LAYOUT_OPTIONS
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
// Font weight selection
|
|
821
|
-
styleEditorField.radio({
|
|
822
|
-
id: 'font-weight',
|
|
823
|
-
label: 'Font Weight',
|
|
824
|
-
options: [
|
|
825
|
-
{ label: 'Normal', value: '400' },
|
|
826
|
-
{ label: 'Medium', value: '500' },
|
|
827
|
-
{ label: 'Semi-Bold', value: '600' },
|
|
828
|
-
{ label: 'Bold', value: '700' }
|
|
829
|
-
]
|
|
830
|
-
});
|
|
831
|
-
```
|
|
832
|
-
|
|
833
|
-
**💡 Image Guidelines:**
|
|
834
|
-
|
|
835
|
-
- Use clear, recognizable preview images
|
|
836
|
-
- Recommended size: 200x150px or similar aspect ratio
|
|
837
|
-
- Use consistent image dimensions within a radio group
|
|
838
|
-
- Images should clearly differentiate between options
|
|
839
|
-
|
|
840
|
-
#### `styleEditorField.checkboxGroup(config)`
|
|
841
|
-
|
|
842
|
-
Creates a group of checkboxes for multi-selection. Each checkbox returns a boolean value (checked/unchecked).
|
|
843
|
-
|
|
844
|
-
**Configuration:**
|
|
845
|
-
|
|
846
|
-
```typescript
|
|
847
|
-
interface StyleEditorCheckboxGroupField {
|
|
848
|
-
id: string; // Unique identifier for the group
|
|
849
|
-
label: string; // Display label for the group
|
|
850
|
-
options: StyleEditorCheckboxOption[]; // Array of checkbox options
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
interface StyleEditorCheckboxOption {
|
|
854
|
-
label: string; // Display text for the checkbox
|
|
855
|
-
key: string; // Unique identifier (NOT 'value')
|
|
856
|
-
}
|
|
857
|
-
```
|
|
858
|
-
|
|
859
|
-
**⚠️ Important:** Checkbox options use `key` instead of `value` because the actual value is boolean (true/false).
|
|
860
|
-
|
|
861
|
-
**Use Cases:**
|
|
862
|
-
|
|
863
|
-
- Text decorations (bold, italic, underline)
|
|
864
|
-
- Feature toggles (enable shadows, borders, animations)
|
|
865
|
-
- Multiple style attributes
|
|
866
|
-
- Any multi-select boolean options
|
|
867
|
-
|
|
868
|
-
**Examples:**
|
|
869
|
-
|
|
870
|
-
```typescript
|
|
871
|
-
// Typography settings
|
|
872
|
-
styleEditorField.checkboxGroup({
|
|
873
|
-
id: 'text-style',
|
|
874
|
-
label: 'Text Style',
|
|
875
|
-
options: [
|
|
876
|
-
{ label: 'Bold', key: 'bold' },
|
|
877
|
-
{ label: 'Italic', key: 'italic' },
|
|
878
|
-
{ label: 'Underline', key: 'underline' },
|
|
879
|
-
{ label: 'Strikethrough', key: 'strikethrough' }
|
|
880
|
-
]
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
// Component features
|
|
884
|
-
styleEditorField.checkboxGroup({
|
|
885
|
-
id: 'component-features',
|
|
886
|
-
label: 'Component Features',
|
|
887
|
-
options: [
|
|
888
|
-
{ label: 'Show Shadow', key: 'shadow' },
|
|
889
|
-
{ label: 'Show Border', key: 'border' },
|
|
890
|
-
{ label: 'Enable Animation', key: 'animate' },
|
|
891
|
-
{ label: 'Rounded Corners', key: 'rounded' }
|
|
892
|
-
]
|
|
893
|
-
});
|
|
894
|
-
|
|
895
|
-
// Responsive behavior
|
|
896
|
-
styleEditorField.checkboxGroup({
|
|
897
|
-
id: 'responsive',
|
|
898
|
-
label: 'Responsive Options',
|
|
899
|
-
options: [
|
|
900
|
-
{ label: 'Hide on Mobile', key: 'hide-mobile' },
|
|
901
|
-
{ label: 'Hide on Tablet', key: 'hide-tablet' },
|
|
902
|
-
{ label: 'Full Width on Mobile', key: 'full-width-mobile' }
|
|
903
|
-
]
|
|
904
|
-
});
|
|
905
|
-
```
|
|
906
|
-
|
|
907
|
-
**Return Value Structure:**
|
|
908
|
-
|
|
909
|
-
```typescript
|
|
910
|
-
// Example return value when checkboxes are checked
|
|
911
|
-
{
|
|
912
|
-
"bold": true,
|
|
913
|
-
"italic": false,
|
|
914
|
-
"underline": true,
|
|
915
|
-
"strikethrough": false
|
|
916
|
-
}
|
|
917
|
-
```
|
|
918
|
-
|
|
919
|
-
### `registerStyleEditorSchemas(schemas)`
|
|
920
|
-
|
|
921
|
-
`registerStyleEditorSchemas` registers one or more style editor schemas with UVE. This function should be called during your component initialization to make the schemas available in the editor.
|
|
922
|
-
|
|
923
|
-
| Input | Type | Required | Description |
|
|
924
|
-
| --------- | --------------------------- | -------- | ------------------------------------------------ |
|
|
925
|
-
| `schemas` | `StyleEditorFormSchema[]` | ✅ | Array of normalized schemas from `defineStyleEditorSchema` |
|
|
926
|
-
|
|
927
|
-
**Returns:** `void`
|
|
928
|
-
|
|
929
|
-
**Behavior:**
|
|
930
|
-
|
|
931
|
-
- Only registers schemas when UVE is in **EDIT** mode
|
|
932
|
-
- Silently returns if UVE is not in EDIT mode
|
|
933
|
-
- Validates that each schema has a `contentType` property
|
|
934
|
-
- Logs a warning and skips schemas without `contentType`
|
|
935
|
-
- Sends validated schemas to UVE via internal messaging
|
|
936
|
-
|
|
937
|
-
#### Usage
|
|
938
|
-
|
|
939
|
-
```typescript
|
|
940
|
-
import { defineStyleEditorSchema, styleEditorField, registerStyleEditorSchemas } from '@dotcms/uve';
|
|
941
|
-
|
|
942
|
-
// Create schemas
|
|
943
|
-
const blogSchema = defineStyleEditorSchema({
|
|
944
|
-
contentType: 'BlogPost',
|
|
945
|
-
sections: [
|
|
946
|
-
{
|
|
947
|
-
title: 'Typography',
|
|
948
|
-
fields: [
|
|
949
|
-
styleEditorField.dropdown({
|
|
950
|
-
id: 'font-size',
|
|
951
|
-
label: 'Font Size',
|
|
952
|
-
options: ['14px', '16px', '18px']
|
|
953
|
-
})
|
|
954
|
-
]
|
|
955
|
-
}
|
|
956
|
-
]
|
|
957
|
-
});
|
|
958
|
-
|
|
959
|
-
const activitySchema = defineStyleEditorSchema({
|
|
960
|
-
contentType: 'Activity',
|
|
961
|
-
sections: [
|
|
962
|
-
{
|
|
963
|
-
title: 'Layout',
|
|
964
|
-
fields: [
|
|
965
|
-
styleEditorField.radio({
|
|
966
|
-
id: 'layout',
|
|
967
|
-
label: 'Layout',
|
|
968
|
-
options: ['Left', 'Right', 'Center']
|
|
969
|
-
})
|
|
970
|
-
]
|
|
971
|
-
}
|
|
972
|
-
]
|
|
973
|
-
});
|
|
974
|
-
|
|
975
|
-
// Register multiple schemas at once
|
|
976
|
-
registerStyleEditorSchemas([blogSchema, activitySchema]);
|
|
977
|
-
```
|
|
978
|
-
|
|
979
|
-
**⚠️ Important Notes:**
|
|
980
|
-
|
|
981
|
-
- Call this function after UVE initialization (`initUVE`)
|
|
982
|
-
- Schemas are only processed in EDIT mode
|
|
983
|
-
- Missing `contentType` will cause the schema to be skipped
|
|
984
|
-
- You can register multiple schemas for different content types
|
|
985
|
-
|
|
986
|
-
### `useStyleEditorSchemas(schemas)` (React Hook)
|
|
987
|
-
|
|
988
|
-
**Available in:** `@dotcms/react` package
|
|
989
|
-
|
|
990
|
-
`useStyleEditorSchemas` is a React hook that simplifies schema registration by automatically handling the component lifecycle. It registers schemas when the component mounts and re-registers if the schemas array reference changes.
|
|
991
|
-
|
|
992
|
-
| Input | Type | Required | Description |
|
|
993
|
-
| -------- | --------------------------- | -------- | ------------------------------- |
|
|
994
|
-
| `schemas` | `StyleEditorFormSchema[]` | ✅ | Array of normalized form schemas |
|
|
995
|
-
|
|
996
|
-
**Returns:** `void`
|
|
997
|
-
|
|
998
|
-
**Behavior:**
|
|
999
|
-
|
|
1000
|
-
- Registers schemas on component mount
|
|
1001
|
-
- Re-registers when the `schemas` array reference changes
|
|
1002
|
-
- Internally calls `registerStyleEditorSchemas()`
|
|
1003
|
-
- Safe to call in multiple components
|
|
1004
|
-
|
|
1005
|
-
#### Usage
|
|
1006
|
-
|
|
1007
|
-
```typescript
|
|
1008
|
-
import { useStyleEditorSchemas } from '@dotcms/react';
|
|
1009
|
-
import { defineStyleEditorSchema, styleEditorField } from '@dotcms/uve';
|
|
1010
|
-
|
|
1011
|
-
function BlogPostEditor() {
|
|
1012
|
-
// Define schemas
|
|
1013
|
-
const schemas = [
|
|
1014
|
-
defineStyleEditorSchema({
|
|
1015
|
-
contentType: 'BlogPost',
|
|
1016
|
-
sections: [
|
|
1017
|
-
{
|
|
1018
|
-
title: 'Typography',
|
|
1019
|
-
fields: [
|
|
1020
|
-
styleEditorField.dropdown({
|
|
1021
|
-
id: 'font-size',
|
|
1022
|
-
label: 'Font Size',
|
|
1023
|
-
options: [
|
|
1024
|
-
{ label: '14px', value: '14px' },
|
|
1025
|
-
{ label: '16px', value: '16px' },
|
|
1026
|
-
{ label: '18px', value: '18px' },
|
|
1027
|
-
{ label: '24px', value: '24px' }
|
|
1028
|
-
]
|
|
1029
|
-
}),
|
|
1030
|
-
styleEditorField.radio({
|
|
1031
|
-
id: 'font-weight',
|
|
1032
|
-
label: 'Font Weight',
|
|
1033
|
-
options: [
|
|
1034
|
-
{ label: 'Normal', value: 'normal' },
|
|
1035
|
-
{ label: 'Bold', value: 'bold' }
|
|
1036
|
-
]
|
|
1037
|
-
})
|
|
1038
|
-
]
|
|
1039
|
-
}
|
|
1040
|
-
]
|
|
1041
|
-
})
|
|
1042
|
-
];
|
|
1043
|
-
|
|
1044
|
-
// Register schemas automatically
|
|
1045
|
-
useStyleEditorSchemas(schemas);
|
|
1046
|
-
|
|
1047
|
-
return (
|
|
1048
|
-
<div>
|
|
1049
|
-
<h1>Blog Post Editor</h1>
|
|
1050
|
-
{/* Your component content */}
|
|
1051
|
-
</div>
|
|
1052
|
-
);
|
|
1053
|
-
}
|
|
1054
|
-
```
|
|
1055
|
-
|
|
1056
|
-
**💡 Performance Tip:** For better performance in components that re-render frequently, you can optionally use `useMemo` to prevent re-creating the schema on every render:
|
|
1057
|
-
|
|
1058
|
-
```typescript
|
|
1059
|
-
import { useMemo } from 'react';
|
|
1060
|
-
|
|
1061
|
-
function BlogPostEditor() {
|
|
1062
|
-
const schemas = useMemo(
|
|
1063
|
-
() => [
|
|
1064
|
-
defineStyleEditorSchema({
|
|
1065
|
-
/* schema definition */
|
|
1066
|
-
})
|
|
1067
|
-
],
|
|
1068
|
-
[] // Empty deps = create once
|
|
1069
|
-
);
|
|
1070
|
-
|
|
1071
|
-
useStyleEditorSchemas(schemas);
|
|
1072
|
-
return <div>Content</div>;
|
|
1073
|
-
}
|
|
1074
|
-
```
|
|
1075
|
-
|
|
1076
503
|
### Accessing Style Values
|
|
1077
504
|
|
|
1078
505
|
Style Editor values are managed internally by UVE and passed to your components through the `dotStyleProperties` attribute. This attribute is available in your contentlet component props.
|
|
@@ -1183,439 +610,7 @@ function BlogPost(props) {
|
|
|
1183
610
|
}
|
|
1184
611
|
```
|
|
1185
612
|
|
|
1186
|
-
**💡 Note:** The `dotStyleProperties` prop is automatically passed to your contentlet components by the framework SDK when UVE is active
|
|
1187
|
-
|
|
1188
|
-
### Best Practices
|
|
1189
|
-
|
|
1190
|
-
#### 1. Use Meaningful IDs and Labels
|
|
1191
|
-
|
|
1192
|
-
```typescript
|
|
1193
|
-
// ✅ Good: Clear, descriptive IDs and labels
|
|
1194
|
-
styleEditorField.dropdown({
|
|
1195
|
-
id: 'heading-font-size',
|
|
1196
|
-
label: 'Heading Font Size',
|
|
1197
|
-
options: [
|
|
1198
|
-
{ label: 'Small (18px)', value: '18px' },
|
|
1199
|
-
{ label: 'Medium (24px)', value: '24px' },
|
|
1200
|
-
{ label: 'Large (32px)', value: '32px' }
|
|
1201
|
-
]
|
|
1202
|
-
});
|
|
1203
|
-
|
|
1204
|
-
// ❌ Bad: Vague IDs and labels
|
|
1205
|
-
styleEditorField.dropdown({
|
|
1206
|
-
id: 'size',
|
|
1207
|
-
label: 'Size',
|
|
1208
|
-
options: ['18px', '24px', '32px']
|
|
1209
|
-
});
|
|
1210
|
-
```
|
|
1211
|
-
|
|
1212
|
-
#### 2. Group Related Fields in Sections
|
|
1213
|
-
|
|
1214
|
-
```typescript
|
|
1215
|
-
// ✅ Good: Logical grouping by functionality
|
|
1216
|
-
defineStyleEditorSchema({
|
|
1217
|
-
contentType: 'BlogPost',
|
|
1218
|
-
sections: [
|
|
1219
|
-
{
|
|
1220
|
-
title: 'Typography',
|
|
1221
|
-
fields: [
|
|
1222
|
-
/* font-related fields */
|
|
1223
|
-
]
|
|
1224
|
-
},
|
|
1225
|
-
{
|
|
1226
|
-
title: 'Layout',
|
|
1227
|
-
fields: [
|
|
1228
|
-
/* layout-related fields */
|
|
1229
|
-
]
|
|
1230
|
-
},
|
|
1231
|
-
{
|
|
1232
|
-
title: 'Colors',
|
|
1233
|
-
fields: [
|
|
1234
|
-
/* color-related fields */
|
|
1235
|
-
]
|
|
1236
|
-
}
|
|
1237
|
-
]
|
|
1238
|
-
});
|
|
1239
|
-
|
|
1240
|
-
// ❌ Bad: All fields in one section
|
|
1241
|
-
defineStyleEditorSchema({
|
|
1242
|
-
contentType: 'BlogPost',
|
|
1243
|
-
sections: [
|
|
1244
|
-
{
|
|
1245
|
-
title: 'Settings',
|
|
1246
|
-
fields: [
|
|
1247
|
-
/* all fields mixed together */
|
|
1248
|
-
]
|
|
1249
|
-
}
|
|
1250
|
-
]
|
|
1251
|
-
});
|
|
1252
|
-
```
|
|
1253
|
-
|
|
1254
|
-
#### 3. Provide Clear Option Labels
|
|
1255
|
-
|
|
1256
|
-
```typescript
|
|
1257
|
-
// ✅ Good: Descriptive labels with context
|
|
1258
|
-
styleEditorField.dropdown({
|
|
1259
|
-
id: 'font-size',
|
|
1260
|
-
label: 'Font Size',
|
|
1261
|
-
options: [
|
|
1262
|
-
{ label: 'Extra Small (12px)', value: '12px' },
|
|
1263
|
-
{ label: 'Small (14px)', value: '14px' },
|
|
1264
|
-
{ label: 'Medium (16px)', value: '16px' },
|
|
1265
|
-
{ label: 'Large (18px)', value: '18px' }
|
|
1266
|
-
]
|
|
1267
|
-
});
|
|
1268
|
-
|
|
1269
|
-
// ❌ Bad: Unclear labels
|
|
1270
|
-
styleEditorField.dropdown({
|
|
1271
|
-
id: 'font-size',
|
|
1272
|
-
label: 'Font Size',
|
|
1273
|
-
options: ['XS', 'S', 'M', 'L']
|
|
1274
|
-
});
|
|
1275
|
-
```
|
|
1276
|
-
|
|
1277
|
-
#### 4. Use Appropriate Field Types
|
|
1278
|
-
|
|
1279
|
-
```typescript
|
|
1280
|
-
// ✅ Good: Radio with images for visual layouts
|
|
1281
|
-
styleEditorField.radio({
|
|
1282
|
-
id: 'page-layout',
|
|
1283
|
-
label: 'Layout',
|
|
1284
|
-
columns: 2,
|
|
1285
|
-
options: [
|
|
1286
|
-
{ label: 'Left', value: 'left', imageURL: '...' },
|
|
1287
|
-
{ label: 'Right', value: 'right', imageURL: '...' }
|
|
1288
|
-
]
|
|
1289
|
-
});
|
|
1290
|
-
|
|
1291
|
-
// ✅ Good: Dropdown for text-only options
|
|
1292
|
-
styleEditorField.dropdown({
|
|
1293
|
-
id: 'font-family',
|
|
1294
|
-
label: 'Font',
|
|
1295
|
-
options: ['Arial', 'Georgia', 'Verdana']
|
|
1296
|
-
});
|
|
1297
|
-
|
|
1298
|
-
// ✅ Good: Checkbox group for boolean flags
|
|
1299
|
-
styleEditorField.checkboxGroup({
|
|
1300
|
-
id: 'text-decorations',
|
|
1301
|
-
label: 'Text Decorations',
|
|
1302
|
-
options: [
|
|
1303
|
-
{ label: 'Bold', key: 'bold' },
|
|
1304
|
-
{ label: 'Italic', key: 'italic' }
|
|
1305
|
-
]
|
|
1306
|
-
});
|
|
1307
|
-
```
|
|
1308
|
-
|
|
1309
|
-
#### 5. Validate Content Type Matching
|
|
1310
|
-
|
|
1311
|
-
```typescript
|
|
1312
|
-
// ✅ Good: Content type matches your dotCMS content type
|
|
1313
|
-
defineStyleEditorSchema({
|
|
1314
|
-
contentType: 'BlogPost', // Matches content type in dotCMS
|
|
1315
|
-
sections: [
|
|
1316
|
-
/* ... */
|
|
1317
|
-
]
|
|
1318
|
-
});
|
|
1319
|
-
|
|
1320
|
-
// ❌ Bad: Typo or mismatch
|
|
1321
|
-
defineStyleEditorSchema({
|
|
1322
|
-
contentType: 'blog-post', // Won't match 'BlogPost' in dotCMS
|
|
1323
|
-
sections: [
|
|
1324
|
-
/* ... */
|
|
1325
|
-
]
|
|
1326
|
-
});
|
|
1327
|
-
```
|
|
1328
|
-
|
|
1329
|
-
#### 6. Provide Sensible Defaults
|
|
1330
|
-
|
|
1331
|
-
When using style properties, always provide fallback defaults:
|
|
1332
|
-
|
|
1333
|
-
```typescript
|
|
1334
|
-
// ✅ Good: Fallback values prevent errors
|
|
1335
|
-
const fontSize = dotStyleProperties?.['font-size'] || '16px';
|
|
1336
|
-
const layout = dotStyleProperties?.layout || 'default';
|
|
1337
|
-
const textStyles = dotStyleProperties?.['text-style'] || {};
|
|
1338
|
-
|
|
1339
|
-
// ❌ Bad: No fallbacks (could cause errors)
|
|
1340
|
-
const fontSize = dotStyleProperties?.['font-size'];
|
|
1341
|
-
const layout = dotStyleProperties?.layout;
|
|
1342
|
-
```
|
|
1343
|
-
|
|
1344
|
-
### Complete Example
|
|
1345
|
-
|
|
1346
|
-
Here's a comprehensive example demonstrating all Style Editor features:
|
|
1347
|
-
|
|
1348
|
-
```typescript
|
|
1349
|
-
import { useStyleEditorSchemas } from '@dotcms/react';
|
|
1350
|
-
import { defineStyleEditorSchema, styleEditorField } from '@dotcms/uve';
|
|
1351
|
-
|
|
1352
|
-
export function BlogPostStyleEditor() {
|
|
1353
|
-
// Define option constants
|
|
1354
|
-
const FONT_SIZES = [
|
|
1355
|
-
{ label: 'Extra Small (12px)', value: '12px' },
|
|
1356
|
-
{ label: 'Small (14px)', value: '14px' },
|
|
1357
|
-
{ label: 'Medium (16px)', value: '16px' },
|
|
1358
|
-
{ label: 'Large (18px)', value: '18px' },
|
|
1359
|
-
{ label: 'Extra Large (24px)', value: '24px' },
|
|
1360
|
-
{ label: 'Huge (32px)', value: '32px' }
|
|
1361
|
-
];
|
|
1362
|
-
|
|
1363
|
-
const FONT_FAMILIES = [
|
|
1364
|
-
{ label: 'Arial', value: 'arial' },
|
|
1365
|
-
{ label: 'Georgia', value: 'georgia' },
|
|
1366
|
-
{ label: 'Helvetica', value: 'helvetica' },
|
|
1367
|
-
{ label: 'Times New Roman', value: 'times' },
|
|
1368
|
-
{ label: 'Verdana', value: 'verdana' },
|
|
1369
|
-
{ label: 'Courier New', value: 'courier' }
|
|
1370
|
-
];
|
|
1371
|
-
|
|
1372
|
-
const LAYOUT_OPTIONS = [
|
|
1373
|
-
{
|
|
1374
|
-
label: 'Left Sidebar',
|
|
1375
|
-
value: 'sidebar-left',
|
|
1376
|
-
imageURL: 'https://example.com/layouts/sidebar-left.png'
|
|
1377
|
-
},
|
|
1378
|
-
{
|
|
1379
|
-
label: 'Right Sidebar',
|
|
1380
|
-
value: 'sidebar-right',
|
|
1381
|
-
imageURL: 'https://example.com/layouts/sidebar-right.png'
|
|
1382
|
-
},
|
|
1383
|
-
{
|
|
1384
|
-
label: 'Full Width',
|
|
1385
|
-
value: 'full-width',
|
|
1386
|
-
imageURL: 'https://example.com/layouts/full-width.png'
|
|
1387
|
-
},
|
|
1388
|
-
{
|
|
1389
|
-
label: 'Centered',
|
|
1390
|
-
value: 'centered',
|
|
1391
|
-
imageURL: 'https://example.com/layouts/centered.png'
|
|
1392
|
-
}
|
|
1393
|
-
];
|
|
1394
|
-
|
|
1395
|
-
const COLOR_THEMES = [
|
|
1396
|
-
{ label: 'Light Theme', value: 'light' },
|
|
1397
|
-
{ label: 'Dark Theme', value: 'dark' },
|
|
1398
|
-
{ label: 'High Contrast', value: 'high-contrast' },
|
|
1399
|
-
{ label: 'Sepia', value: 'sepia' }
|
|
1400
|
-
];
|
|
1401
|
-
|
|
1402
|
-
// Define schema (optionally use useMemo to prevent re-creation on every render)
|
|
1403
|
-
const schemas = [
|
|
1404
|
-
defineStyleEditorSchema({
|
|
1405
|
-
contentType: 'BlogPost',
|
|
1406
|
-
sections: [
|
|
1407
|
-
{
|
|
1408
|
-
title: 'Typography',
|
|
1409
|
-
fields: [
|
|
1410
|
-
styleEditorField.dropdown({
|
|
1411
|
-
id: 'heading-font-size',
|
|
1412
|
-
label: 'Heading Font Size',
|
|
1413
|
-
options: FONT_SIZES
|
|
1414
|
-
}),
|
|
1415
|
-
styleEditorField.dropdown({
|
|
1416
|
-
id: 'body-font-size',
|
|
1417
|
-
label: 'Body Font Size',
|
|
1418
|
-
options: FONT_SIZES.slice(0, 4) // Only smaller sizes
|
|
1419
|
-
}),
|
|
1420
|
-
styleEditorField.dropdown({
|
|
1421
|
-
id: 'font-family',
|
|
1422
|
-
label: 'Font Family',
|
|
1423
|
-
options: FONT_FAMILIES
|
|
1424
|
-
}),
|
|
1425
|
-
styleEditorField.input({
|
|
1426
|
-
id: 'line-height',
|
|
1427
|
-
label: 'Line Height',
|
|
1428
|
-
inputType: 'number',
|
|
1429
|
-
placeholder: '1.5'
|
|
1430
|
-
}),
|
|
1431
|
-
styleEditorField.checkboxGroup({
|
|
1432
|
-
id: 'text-style',
|
|
1433
|
-
label: 'Text Style',
|
|
1434
|
-
options: [
|
|
1435
|
-
{ label: 'Bold Headings', key: 'bold-headings' },
|
|
1436
|
-
{ label: 'Italic Quotes', key: 'italic-quotes' },
|
|
1437
|
-
{ label: 'Underline Links', key: 'underline-links' }
|
|
1438
|
-
]
|
|
1439
|
-
})
|
|
1440
|
-
]
|
|
1441
|
-
},
|
|
1442
|
-
{
|
|
1443
|
-
title: 'Layout',
|
|
1444
|
-
fields: [
|
|
1445
|
-
styleEditorField.radio({
|
|
1446
|
-
id: 'page-layout',
|
|
1447
|
-
label: 'Page Layout',
|
|
1448
|
-
columns: 2,
|
|
1449
|
-
options: LAYOUT_OPTIONS
|
|
1450
|
-
}),
|
|
1451
|
-
styleEditorField.radio({
|
|
1452
|
-
id: 'content-width',
|
|
1453
|
-
label: 'Content Width',
|
|
1454
|
-
options: [
|
|
1455
|
-
{ label: 'Narrow (800px)', value: '800px' },
|
|
1456
|
-
{ label: 'Medium (1000px)', value: '1000px' },
|
|
1457
|
-
{ label: 'Wide (1200px)', value: '1200px' },
|
|
1458
|
-
{ label: 'Extra Wide (1400px)', value: '1400px' }
|
|
1459
|
-
]
|
|
1460
|
-
}),
|
|
1461
|
-
styleEditorField.input({
|
|
1462
|
-
id: 'section-spacing',
|
|
1463
|
-
label: 'Section Spacing (px)',
|
|
1464
|
-
inputType: 'number',
|
|
1465
|
-
placeholder: '40'
|
|
1466
|
-
})
|
|
1467
|
-
]
|
|
1468
|
-
},
|
|
1469
|
-
{
|
|
1470
|
-
title: 'Colors & Theme',
|
|
1471
|
-
fields: [
|
|
1472
|
-
styleEditorField.dropdown({
|
|
1473
|
-
id: 'color-theme',
|
|
1474
|
-
label: 'Color Theme',
|
|
1475
|
-
options: COLOR_THEMES
|
|
1476
|
-
}),
|
|
1477
|
-
styleEditorField.input({
|
|
1478
|
-
id: 'primary-color',
|
|
1479
|
-
label: 'Primary Color',
|
|
1480
|
-
inputType: 'text',
|
|
1481
|
-
placeholder: '#007bff'
|
|
1482
|
-
}),
|
|
1483
|
-
styleEditorField.input({
|
|
1484
|
-
id: 'secondary-color',
|
|
1485
|
-
label: 'Secondary Color',
|
|
1486
|
-
inputType: 'text',
|
|
1487
|
-
placeholder: '#6c757d'
|
|
1488
|
-
}),
|
|
1489
|
-
styleEditorField.input({
|
|
1490
|
-
id: 'background-color',
|
|
1491
|
-
label: 'Background Color',
|
|
1492
|
-
inputType: 'text',
|
|
1493
|
-
placeholder: '#ffffff'
|
|
1494
|
-
})
|
|
1495
|
-
]
|
|
1496
|
-
},
|
|
1497
|
-
{
|
|
1498
|
-
title: 'Component Features',
|
|
1499
|
-
fields: [
|
|
1500
|
-
styleEditorField.checkboxGroup({
|
|
1501
|
-
id: 'features',
|
|
1502
|
-
label: 'Enable Features',
|
|
1503
|
-
options: [
|
|
1504
|
-
{ label: 'Drop Shadow', key: 'shadow' },
|
|
1505
|
-
{ label: 'Border', key: 'border' },
|
|
1506
|
-
{ label: 'Rounded Corners', key: 'rounded' },
|
|
1507
|
-
{ label: 'Smooth Animations', key: 'animate' },
|
|
1508
|
-
{ label: 'Hover Effects', key: 'hover-effects' }
|
|
1509
|
-
]
|
|
1510
|
-
}),
|
|
1511
|
-
styleEditorField.checkboxGroup({
|
|
1512
|
-
id: 'responsive',
|
|
1513
|
-
label: 'Responsive Options',
|
|
1514
|
-
options: [
|
|
1515
|
-
{ label: 'Hide on Mobile', key: 'hide-mobile' },
|
|
1516
|
-
{ label: 'Stack on Tablet', key: 'stack-tablet' },
|
|
1517
|
-
{
|
|
1518
|
-
label: 'Full Width on Mobile',
|
|
1519
|
-
key: 'full-width-mobile'
|
|
1520
|
-
}
|
|
1521
|
-
]
|
|
1522
|
-
})
|
|
1523
|
-
]
|
|
1524
|
-
}
|
|
1525
|
-
]
|
|
1526
|
-
})
|
|
1527
|
-
];
|
|
1528
|
-
|
|
1529
|
-
// Register schemas with UVE
|
|
1530
|
-
useStyleEditorSchemas(schemas);
|
|
1531
|
-
|
|
1532
|
-
return (
|
|
1533
|
-
<div>
|
|
1534
|
-
<h1>Blog Post Style Editor</h1>
|
|
1535
|
-
<p>Style editor schema is registered and available in UVE edit mode.</p>
|
|
1536
|
-
</div>
|
|
1537
|
-
);
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
// Example: Using style properties in a component
|
|
1541
|
-
export function BlogPostRenderer(props) {
|
|
1542
|
-
const { title, body, dotStyleProperties } = props;
|
|
1543
|
-
|
|
1544
|
-
// Extract style values with defaults
|
|
1545
|
-
const headingSize = dotStyleProperties?.['heading-font-size'] || '24px';
|
|
1546
|
-
const bodySize = dotStyleProperties?.['body-font-size'] || '16px';
|
|
1547
|
-
const fontFamily = dotStyleProperties?.['font-family'] || 'arial';
|
|
1548
|
-
const lineHeight = dotStyleProperties?.['line-height'] || '1.5';
|
|
1549
|
-
const layout = dotStyleProperties?.['page-layout'] || 'full-width';
|
|
1550
|
-
const contentWidth = dotStyleProperties?.['content-width'] || '1000px';
|
|
1551
|
-
const sectionSpacing = dotStyleProperties?.['section-spacing'] || 40;
|
|
1552
|
-
const theme = dotStyleProperties?.['color-theme'] || 'light';
|
|
1553
|
-
const primaryColor = dotStyleProperties?.['primary-color'] || '#007bff';
|
|
1554
|
-
const backgroundColor = dotStyleProperties?.['background-color'] || '#ffffff';
|
|
1555
|
-
|
|
1556
|
-
// Extract checkbox group values
|
|
1557
|
-
const textStyle = dotStyleProperties?.['text-style'] || {};
|
|
1558
|
-
const features = dotStyleProperties?.features || {};
|
|
1559
|
-
const responsive = dotStyleProperties?.responsive || {};
|
|
1560
|
-
|
|
1561
|
-
// Build CSS classes based on values
|
|
1562
|
-
const containerClasses = [
|
|
1563
|
-
`layout-${layout}`,
|
|
1564
|
-
`theme-${theme}`,
|
|
1565
|
-
features.shadow ? 'has-shadow' : '',
|
|
1566
|
-
features.border ? 'has-border' : '',
|
|
1567
|
-
features.rounded ? 'has-rounded' : '',
|
|
1568
|
-
features.animate ? 'has-animations' : '',
|
|
1569
|
-
responsive['hide-mobile'] ? 'hide-mobile' : '',
|
|
1570
|
-
responsive['stack-tablet'] ? 'stack-tablet' : ''
|
|
1571
|
-
]
|
|
1572
|
-
.filter(Boolean)
|
|
1573
|
-
.join(' ');
|
|
1574
|
-
|
|
1575
|
-
return (
|
|
1576
|
-
<div
|
|
1577
|
-
className={containerClasses}
|
|
1578
|
-
style={{
|
|
1579
|
-
fontFamily,
|
|
1580
|
-
lineHeight,
|
|
1581
|
-
backgroundColor,
|
|
1582
|
-
maxWidth: contentWidth,
|
|
1583
|
-
paddingTop: `${sectionSpacing}px`,
|
|
1584
|
-
paddingBottom: `${sectionSpacing}px`
|
|
1585
|
-
}}
|
|
1586
|
-
>
|
|
1587
|
-
<h1
|
|
1588
|
-
style={{
|
|
1589
|
-
fontSize: headingSize,
|
|
1590
|
-
fontWeight: textStyle['bold-headings'] ? 'bold' : 'normal',
|
|
1591
|
-
color: primaryColor
|
|
1592
|
-
}}
|
|
1593
|
-
>
|
|
1594
|
-
{title}
|
|
1595
|
-
</h1>
|
|
1596
|
-
|
|
1597
|
-
<div
|
|
1598
|
-
style={{
|
|
1599
|
-
fontSize: bodySize
|
|
1600
|
-
}}
|
|
1601
|
-
>
|
|
1602
|
-
{body}
|
|
1603
|
-
</div>
|
|
1604
|
-
</div>
|
|
1605
|
-
);
|
|
1606
|
-
}
|
|
1607
|
-
```
|
|
1608
|
-
|
|
1609
|
-
**This example demonstrates:**
|
|
1610
|
-
|
|
1611
|
-
- ✅ Organized option constants
|
|
1612
|
-
- ✅ Logical section grouping (Typography, Layout, Colors, Features)
|
|
1613
|
-
- ✅ All four field types (input, dropdown, radio, checkboxGroup)
|
|
1614
|
-
- ✅ Visual layout selection with images
|
|
1615
|
-
- ✅ Checkbox groups for boolean flags
|
|
1616
|
-
- ✅ Clear, descriptive labels
|
|
1617
|
-
- ✅ Safe value extraction with defaults using `dotStyleProperties`
|
|
1618
|
-
- ✅ Dynamic styling based on style values
|
|
613
|
+
**💡 Note:** The `dotStyleProperties` prop is automatically passed to your contentlet components by the framework SDK when UVE is active.
|
|
1619
614
|
|
|
1620
615
|
### Current Capabilities and Limitations:
|
|
1621
616
|
|