@growgroup/visual-editor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +52 -0
- package/README.md +143 -0
- package/dist/editor.css +2 -0
- package/package.json +94 -0
- package/src/components/DeckSlideRender.tsx +21 -0
- package/src/components/SaveNote.tsx +21 -0
- package/src/components/auth/AuthProvider.tsx +44 -0
- package/src/components/ui/accordion.tsx +57 -0
- package/src/components/ui/alert-dialog.tsx +141 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.tsx +76 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.tsx +11 -0
- package/src/components/ui/context-menu.tsx +200 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/dropdown-menu.tsx +201 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/scrubbable-label.tsx +95 -0
- package/src/components/ui/select.tsx +159 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/slider.tsx +28 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/tabs.tsx +55 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/components/viewer/useDeck.ts +58 -0
- package/src/editor/EditorContext.tsx +632 -0
- package/src/editor/EditorToolbar.tsx +446 -0
- package/src/editor/FrontendVisualEditor.tsx +2595 -0
- package/src/editor/autosave.ts +34 -0
- package/src/editor/components/AiPromptPopover.tsx +378 -0
- package/src/editor/components/BreakpointGuides.tsx +323 -0
- package/src/editor/components/BreakpointSelector.tsx +180 -0
- package/src/editor/components/ComponentPropertyEditor.tsx +426 -0
- package/src/editor/components/CssEditorDialog.tsx +168 -0
- package/src/editor/components/EditorCanvas.tsx +987 -0
- package/src/editor/components/EditorContextMenu.tsx +515 -0
- package/src/editor/components/EditorFooter.tsx +81 -0
- package/src/editor/components/EditorHeader.tsx +524 -0
- package/src/editor/components/EditorLayerPanel.tsx +1197 -0
- package/src/editor/components/EditorPropertyPanel.tsx +2996 -0
- package/src/editor/components/EditorSidebar.tsx +226 -0
- package/src/editor/components/FigmaColorPicker.tsx +1577 -0
- package/src/editor/components/HtmlEditorDialog.tsx +71 -0
- package/src/editor/components/HtmlImportDialog.tsx +346 -0
- package/src/editor/components/JsEditorDialog.tsx +175 -0
- package/src/editor/components/LayerTreeItem.tsx +494 -0
- package/src/editor/components/MasterComponentEditor.tsx +846 -0
- package/src/editor/components/MediaLibraryDialog.tsx +447 -0
- package/src/editor/components/PageSettingsDialog.tsx +776 -0
- package/src/editor/components/VariablePicker.tsx +355 -0
- package/src/editor/components/VariablesDialog.tsx +564 -0
- package/src/editor/components/VariantEditor.tsx +687 -0
- package/src/editor/components/VariantMatrix.tsx +507 -0
- package/src/editor/components/component-panel/CategoryAccordion.tsx +139 -0
- package/src/editor/components/component-panel/ComponentGrid.tsx +51 -0
- package/src/editor/components/component-panel/ComponentItem.tsx +368 -0
- package/src/editor/components/component-panel/ComponentPanel.tsx +275 -0
- package/src/editor/components/component-panel/ComponentSearch.tsx +82 -0
- package/src/editor/components/component-panel/VariantList.tsx +260 -0
- package/src/editor/components/component-panel/index.ts +12 -0
- package/src/editor/components/index.ts +48 -0
- package/src/editor/components/multi-page/CanvasZoomControls.tsx +71 -0
- package/src/editor/components/multi-page/InfiniteCanvas.tsx +95 -0
- package/src/editor/components/multi-page/MultiPageCanvasView.tsx +1404 -0
- package/src/editor/components/multi-page/PageFrameOverlay.tsx +76 -0
- package/src/editor/components/multi-page/PageLabel.tsx +34 -0
- package/src/editor/components/multi-page/PageLivePreview.tsx +242 -0
- package/src/editor/components/multi-page/PageThumbnail.tsx +59 -0
- package/src/editor/components/multi-page/index.ts +7 -0
- package/src/editor/components/ppt/PptChrome.tsx +2508 -0
- package/src/editor/components/ppt/PptComments.tsx +589 -0
- package/src/editor/components/ppt/PptDesignProposals.tsx +275 -0
- package/src/editor/components/ppt/PptFormatPane.tsx +320 -0
- package/src/editor/components/ppt/PptNotes.tsx +246 -0
- package/src/editor/components/property-panel/AlignmentPanel.tsx +110 -0
- package/src/editor/components/property-panel/AutoLayoutPanel.tsx +615 -0
- package/src/editor/components/property-panel/BorderSection.tsx +104 -0
- package/src/editor/components/property-panel/CompactNumberInput.tsx +237 -0
- package/src/editor/components/property-panel/CompactSizeInput.tsx +148 -0
- package/src/editor/components/property-panel/EffectSection.tsx +157 -0
- package/src/editor/components/property-panel/FillSection.tsx +69 -0
- package/src/editor/components/property-panel/GoogleFontPicker.tsx +192 -0
- package/src/editor/components/property-panel/ImageSection.tsx +206 -0
- package/src/editor/components/property-panel/ImgSrcSection.tsx +125 -0
- package/src/editor/components/property-panel/InstanceOverrideSection.tsx +413 -0
- package/src/editor/components/property-panel/LayoutSection.tsx +105 -0
- package/src/editor/components/property-panel/LinkSection.tsx +103 -0
- package/src/editor/components/property-panel/PropertyVariablePicker.tsx +311 -0
- package/src/editor/components/property-panel/ScalePanel.tsx +212 -0
- package/src/editor/components/property-panel/TypographySection.tsx +230 -0
- package/src/editor/components/property-panel/UnitAwareNumberInput.tsx +238 -0
- package/src/editor/components/property-panel/VariableAwareColorInput.tsx +477 -0
- package/src/editor/components/property-panel/VariableAwareInput.tsx +606 -0
- package/src/editor/components/property-panel/VariableAwareSizeInput.tsx +588 -0
- package/src/editor/components/property-panel/VariableAwareUnitInput.tsx +546 -0
- package/src/editor/components/property-panel/index.ts +24 -0
- package/src/editor/components/property-panel/unit-utils.ts +261 -0
- package/src/editor/components/shell/EditorTopBar.tsx +392 -0
- package/src/editor/components/shell/LeftPanel.tsx +47 -0
- package/src/editor/components/shell/PagesPanel.tsx +118 -0
- package/src/editor/components/variables-panel/ColorValueCell.tsx +165 -0
- package/src/editor/components/variables-panel/TextValueCell.tsx +116 -0
- package/src/editor/components/variables-panel/VariablesPanel.tsx +518 -0
- package/src/editor/components/variables-panel/index.ts +7 -0
- package/src/editor/constants.ts +468 -0
- package/src/editor/contexts/EditorArtboardContext.tsx +229 -0
- package/src/editor/contexts/EditorComponentsContext.tsx +1320 -0
- package/src/editor/contexts/EditorDocumentContext.tsx +113 -0
- package/src/editor/contexts/EditorHistoryContext.tsx +516 -0
- package/src/editor/contexts/EditorRefsContext.tsx +204 -0
- package/src/editor/contexts/EditorSelectionContext.tsx +54 -0
- package/src/editor/contexts/EditorToolContext.tsx +58 -0
- package/src/editor/contexts/EditorUIStateContext.tsx +122 -0
- package/src/editor/contexts/EditorVariablesContext.tsx +397 -0
- package/src/editor/contexts/EditorViewContext.tsx +101 -0
- package/src/editor/contexts/MultiPageCanvasContext.tsx +498 -0
- package/src/editor/contexts/index.ts +17 -0
- package/src/editor/editor-skin.css +122 -0
- package/src/editor/hooks/index.ts +38 -0
- package/src/editor/hooks/useAiReplace.ts +397 -0
- package/src/editor/hooks/useAltMeasure.ts +67 -0
- package/src/editor/hooks/useBrowserZoomPrevention.ts +121 -0
- package/src/editor/hooks/useCanvasControls.ts +1222 -0
- package/src/editor/hooks/useComponentEditMode.ts +658 -0
- package/src/editor/hooks/useComponentInstances.ts +515 -0
- package/src/editor/hooks/useContextMenuHandler.ts +157 -0
- package/src/editor/hooks/useCoordinateTransform.ts +207 -0
- package/src/editor/hooks/useDragResize.ts +1317 -0
- package/src/editor/hooks/useDrawingMode.ts +472 -0
- package/src/editor/hooks/useEditorColors.ts +144 -0
- package/src/editor/hooks/useEditorMessages.ts +108 -0
- package/src/editor/hooks/useElementActions.ts +1754 -0
- package/src/editor/hooks/useElementSelection.ts +1573 -0
- package/src/editor/hooks/useFocusManagement.ts +249 -0
- package/src/editor/hooks/useGoogleFonts.ts +305 -0
- package/src/editor/hooks/useIframeInitializer.ts +584 -0
- package/src/editor/hooks/useIframeSetup.ts +360 -0
- package/src/editor/hooks/useImageUpload.ts +270 -0
- package/src/editor/hooks/useInfiniteCanvas.ts +301 -0
- package/src/editor/hooks/useKeyboardShortcuts.ts +205 -0
- package/src/editor/hooks/useMarqueeSelection.ts +388 -0
- package/src/editor/hooks/useMediaLibrary.ts +129 -0
- package/src/editor/hooks/usePageSettingsManager.ts +739 -0
- package/src/editor/hooks/useResizablePanel.ts +163 -0
- package/src/editor/hooks/useRichPaste.ts +255 -0
- package/src/editor/hooks/useTouchGestures.ts +197 -0
- package/src/editor/index.ts +27 -0
- package/src/editor/types/page-settings.ts +513 -0
- package/src/editor/types.ts +382 -0
- package/src/editor/utils/align-elements.ts +169 -0
- package/src/editor/utils/api-json.ts +21 -0
- package/src/editor/utils/aspect-lock.ts +50 -0
- package/src/editor/utils/component-renderer.ts +702 -0
- package/src/editor/utils/component-sync.ts +845 -0
- package/src/editor/utils/crop-mode.ts +265 -0
- package/src/editor/utils/dom-utils.ts +2238 -0
- package/src/editor/utils/element-effects.ts +218 -0
- package/src/editor/utils/eyedropper.ts +35 -0
- package/src/editor/utils/figma-export.ts +560 -0
- package/src/editor/utils/figma-kiwi-decoder.ts +722 -0
- package/src/editor/utils/figma-kiwi-encoder.ts +583 -0
- package/src/editor/utils/figma-paste.ts +2262 -0
- package/src/editor/utils/flex-reorder.ts +231 -0
- package/src/editor/utils/flex-utils.ts +1230 -0
- package/src/editor/utils/geometry.ts +232 -0
- package/src/editor/utils/grid-layout.ts +210 -0
- package/src/editor/utils/html-utils.ts +470 -0
- package/src/editor/utils/index.ts +11 -0
- package/src/editor/utils/ink-style.ts +57 -0
- package/src/editor/utils/inline-format.ts +236 -0
- package/src/editor/utils/measure-distance.ts +120 -0
- package/src/editor/utils/override-apply.ts +526 -0
- package/src/editor/utils/override-detection.ts +613 -0
- package/src/editor/utils/paste-processors.ts +609 -0
- package/src/editor/utils/paste-sanitizer.ts +244 -0
- package/src/editor/utils/restore-flow.ts +188 -0
- package/src/editor/utils/shape-library.ts +171 -0
- package/src/editor/utils/slide-root.ts +29 -0
- package/src/editor/utils/smart-guides.ts +218 -0
- package/src/editor/utils/style-utils.ts +685 -0
- package/src/editor/utils/table-edit.ts +151 -0
- package/src/editor/utils/tailwind-mappings.ts +778 -0
- package/src/editor/utils/tailwind-utils.ts +804 -0
- package/src/editor/utils/text-highlight.ts +216 -0
- package/src/editor/utils/theme-to-variables.ts +341 -0
- package/src/editor/utils/variant-resolver.ts +456 -0
- package/src/editor/utils/viewport-utils.ts +295 -0
- package/src/hooks/useEditorHistory.ts +195 -0
- package/src/hooks/useEditorShortcuts.ts +260 -0
- package/src/index.ts +40 -0
- package/src/io.ts +134 -0
- package/src/lib/agent/slide-agent/types.ts +547 -0
- package/src/lib/agent/website-agent/types.ts +805 -0
- package/src/lib/api/auth-fetch.ts +58 -0
- package/src/lib/deck.ts +69 -0
- package/src/lib/export.ts +47 -0
- package/src/lib/firebase/config.ts +29 -0
- package/src/lib/firebase/css-variables.ts +378 -0
- package/src/lib/firebase/editor-components.ts +677 -0
- package/src/lib/firebase/storage.ts +469 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/editor.css +52 -0
- package/src/styles/skin.css +122 -0
- package/src/types/css-variables.ts +645 -0
- package/src/types/editor-components.ts +944 -0
- package/src/types/editor.ts +420 -0
- package/src/types/page-master.ts +197 -0
- package/src/types/page.ts +419 -0
- package/src/types/slide.ts +402 -0
- package/src/types/website-theme.ts +788 -0
- package/src/types/website.ts +374 -0
- package/src/vendor/firebase-firestore.ts +13 -0
- package/src/vendor/firebase-functions.ts +17 -0
|
@@ -0,0 +1,944 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor Components Types - Figma-like component system type definitions
|
|
3
|
+
*
|
|
4
|
+
* This module defines the type system for a Figma-inspired component architecture
|
|
5
|
+
* supporting master components, variants, instances, and overrides.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: All dates use ISO 8601 strings for portability across contexts.
|
|
8
|
+
* Firestore Timestamps are converted on read/write operations.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// 1. Overridable Properties
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Defines which properties of an element can be overridden in instances.
|
|
17
|
+
* Maps to Figma's overridable properties concept.
|
|
18
|
+
*/
|
|
19
|
+
export interface OverridableProperties {
|
|
20
|
+
/** Allow text content changes */
|
|
21
|
+
text: boolean;
|
|
22
|
+
/** Allow fill/background color changes */
|
|
23
|
+
fill: boolean;
|
|
24
|
+
/** Allow stroke/border changes */
|
|
25
|
+
stroke: boolean;
|
|
26
|
+
/** Allow visibility toggling */
|
|
27
|
+
visibility: boolean;
|
|
28
|
+
/** Allow image source replacement */
|
|
29
|
+
image: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// 2. ComponentElement - Element structure
|
|
34
|
+
// =============================================================================
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Component element structure representing a node in the component tree.
|
|
38
|
+
* Similar to Figma's layer structure with nested children.
|
|
39
|
+
*/
|
|
40
|
+
export interface ComponentElement {
|
|
41
|
+
/** Unique identifier for this element within the component */
|
|
42
|
+
id: string;
|
|
43
|
+
/** HTML tag name (div, span, button, img, etc.) */
|
|
44
|
+
tagName: string;
|
|
45
|
+
/** HTML attributes (data-*, aria-*, role, href, src, etc.) */
|
|
46
|
+
attributes: Record<string, string>;
|
|
47
|
+
/** CSS class names (space-separated string or empty) */
|
|
48
|
+
className: string;
|
|
49
|
+
/** Text content (for text nodes, undefined for containers) */
|
|
50
|
+
textContent?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Raw innerHTML for elements with mixed content (text + elements).
|
|
53
|
+
* When set, this takes precedence over children array.
|
|
54
|
+
* Used to preserve complex content that can't be represented as a tree.
|
|
55
|
+
*/
|
|
56
|
+
innerHTML?: string;
|
|
57
|
+
/** Nested child elements */
|
|
58
|
+
children: ComponentElement[];
|
|
59
|
+
/** Specifies which properties can be overridden in instances */
|
|
60
|
+
overridable: OverridableProperties;
|
|
61
|
+
/**
|
|
62
|
+
* Inline styles as key-value pairs (camelCase keys).
|
|
63
|
+
* @example { backgroundColor: 'red', fontSize: '16px' }
|
|
64
|
+
*/
|
|
65
|
+
styles: Record<string, string>;
|
|
66
|
+
/** Element display name for layers panel */
|
|
67
|
+
displayName?: string;
|
|
68
|
+
/** Whether this element is locked from editing */
|
|
69
|
+
locked?: boolean;
|
|
70
|
+
/** Whether this element is hidden in the editor */
|
|
71
|
+
hidden?: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// =============================================================================
|
|
75
|
+
// 3. VariantProperty - Variant property definition
|
|
76
|
+
// =============================================================================
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Defines a variant property dimension (e.g., "Size", "State", "Theme").
|
|
80
|
+
* Similar to Figma's variant properties that define the axes of variation.
|
|
81
|
+
*/
|
|
82
|
+
export interface VariantProperty {
|
|
83
|
+
/** Unique identifier for this property */
|
|
84
|
+
id: string;
|
|
85
|
+
/** Display name of the property (e.g., "Size", "State") */
|
|
86
|
+
name: string;
|
|
87
|
+
/** Possible values for this property (e.g., ["small", "medium", "large"]) */
|
|
88
|
+
values: string[];
|
|
89
|
+
/** Default value when creating new instances */
|
|
90
|
+
defaultValue: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// =============================================================================
|
|
94
|
+
// 4. VariantDefinition - Specific variant
|
|
95
|
+
// =============================================================================
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Defines a specific variant combination with its element tree.
|
|
99
|
+
* Each variant represents a unique combination of property values.
|
|
100
|
+
*/
|
|
101
|
+
export interface VariantDefinition {
|
|
102
|
+
/** Unique identifier for this variant */
|
|
103
|
+
id: string;
|
|
104
|
+
/** Display name for this variant */
|
|
105
|
+
name: string;
|
|
106
|
+
/** Property values that define this variant (e.g., { size: "large", state: "hover" }) */
|
|
107
|
+
propertyValues?: Record<string, string>;
|
|
108
|
+
/** Root element tree for this variant (can differ from master) */
|
|
109
|
+
rootElement: ComponentElement;
|
|
110
|
+
/** Optional description for this variant */
|
|
111
|
+
description?: string;
|
|
112
|
+
/** Optional thumbnail URL for preview */
|
|
113
|
+
thumbnailUrl?: string;
|
|
114
|
+
/** Whether this is the default variant */
|
|
115
|
+
isDefault?: boolean;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Alias for VariantDefinition - used by context for clarity.
|
|
120
|
+
* Represents a variant of a component with its visual representation.
|
|
121
|
+
*/
|
|
122
|
+
export type ComponentVariant = VariantDefinition;
|
|
123
|
+
|
|
124
|
+
// =============================================================================
|
|
125
|
+
// 5. ComponentPropertyType - Property type enum
|
|
126
|
+
// =============================================================================
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Types of component properties that can be exposed for configuration.
|
|
130
|
+
* Mirrors Figma's component property types.
|
|
131
|
+
*/
|
|
132
|
+
export type ComponentPropertyType =
|
|
133
|
+
| 'boolean' // Toggle property (show/hide, enabled/disabled)
|
|
134
|
+
| 'text' // Text content property
|
|
135
|
+
| 'instanceSwap' // Swap nested component instance
|
|
136
|
+
| 'variant'; // Change variant selection
|
|
137
|
+
|
|
138
|
+
// =============================================================================
|
|
139
|
+
// 6. ComponentProperty - Property definition
|
|
140
|
+
// =============================================================================
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Defines an exposed component property that users can configure.
|
|
144
|
+
* Properties provide a structured way to customize component instances.
|
|
145
|
+
*/
|
|
146
|
+
export interface ComponentProperty {
|
|
147
|
+
/** Unique identifier for this property */
|
|
148
|
+
id: string;
|
|
149
|
+
/** Display name of the property */
|
|
150
|
+
name: string;
|
|
151
|
+
/** Type of property */
|
|
152
|
+
type: ComponentPropertyType;
|
|
153
|
+
/** Default value (type depends on property type) */
|
|
154
|
+
defaultValue: string | boolean;
|
|
155
|
+
/** Element IDs that this property affects */
|
|
156
|
+
targetElementIds: string[];
|
|
157
|
+
/** For instanceSwap type: IDs of components allowed for swapping */
|
|
158
|
+
allowedComponentIds?: string[];
|
|
159
|
+
/** Optional description for documentation */
|
|
160
|
+
description?: string;
|
|
161
|
+
/** Property group for organization in the UI */
|
|
162
|
+
group?: string;
|
|
163
|
+
/** Whether this property is required */
|
|
164
|
+
required?: boolean;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Alias for ComponentProperty - exposed properties that users can configure.
|
|
169
|
+
* Used by context and firebase for clarity.
|
|
170
|
+
*/
|
|
171
|
+
export type ExposedProperty = ComponentProperty;
|
|
172
|
+
|
|
173
|
+
// =============================================================================
|
|
174
|
+
// 7. ComponentInstance - Instance reference
|
|
175
|
+
// =============================================================================
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Represents an instance of a master component placed in the editor.
|
|
179
|
+
* Instances reference their master and can have local overrides.
|
|
180
|
+
*/
|
|
181
|
+
export interface ComponentInstance {
|
|
182
|
+
/**
|
|
183
|
+
* Unique identifier for this instance.
|
|
184
|
+
* Note: Use `id` as the primary identifier. `instanceId` is deprecated alias.
|
|
185
|
+
*/
|
|
186
|
+
id: string;
|
|
187
|
+
/** Reference to the master component ID */
|
|
188
|
+
masterComponentId: string;
|
|
189
|
+
/** Currently selected variant ID */
|
|
190
|
+
variantId: string;
|
|
191
|
+
/** Overrides applied to this instance */
|
|
192
|
+
overrides: ComponentOverride[];
|
|
193
|
+
/** Current property values (key is property ID) */
|
|
194
|
+
propertyValues: Record<string, string | number | boolean>;
|
|
195
|
+
/** ID of the DOM element representing this instance */
|
|
196
|
+
domElementId: string;
|
|
197
|
+
/** Position within the canvas (optional) */
|
|
198
|
+
position?: {
|
|
199
|
+
x: number;
|
|
200
|
+
y: number;
|
|
201
|
+
};
|
|
202
|
+
/** Size override if different from master (optional) */
|
|
203
|
+
size?: {
|
|
204
|
+
width: number;
|
|
205
|
+
height: number;
|
|
206
|
+
};
|
|
207
|
+
/** Instance name for layers panel (optional) */
|
|
208
|
+
name?: string;
|
|
209
|
+
/** Whether this instance is detached from master */
|
|
210
|
+
isDetached?: boolean;
|
|
211
|
+
/** ISO 8601 timestamp when instance was created */
|
|
212
|
+
createdAt?: string;
|
|
213
|
+
/** ISO 8601 timestamp when instance was last updated */
|
|
214
|
+
updatedAt?: string;
|
|
215
|
+
/** Page ID where this instance exists */
|
|
216
|
+
pageId?: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// =============================================================================
|
|
220
|
+
// 8. ComponentOverride - Single override
|
|
221
|
+
// =============================================================================
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Represents a single override applied to a component instance.
|
|
225
|
+
* Overrides allow instances to diverge from their master component.
|
|
226
|
+
*/
|
|
227
|
+
export interface ComponentOverride {
|
|
228
|
+
/** Unique identifier for this override */
|
|
229
|
+
id: string;
|
|
230
|
+
/**
|
|
231
|
+
* ID of the target element within the component tree.
|
|
232
|
+
* Use this for direct element ID reference.
|
|
233
|
+
*/
|
|
234
|
+
targetElementId?: string;
|
|
235
|
+
/**
|
|
236
|
+
* Path to the target element (e.g., "children.0.children.1" or "root").
|
|
237
|
+
* Alternative to targetElementId for path-based targeting.
|
|
238
|
+
*/
|
|
239
|
+
elementPath?: string;
|
|
240
|
+
/** Type of override being applied */
|
|
241
|
+
type: OverrideType;
|
|
242
|
+
/** Override value (type depends on override type) */
|
|
243
|
+
value: string | boolean | Record<string, string> | ComponentElement[] | OverrideImageValue | OverrideInstanceSwapValue;
|
|
244
|
+
/** Path to nested elements for deeply nested overrides (optional) */
|
|
245
|
+
nestedPath?: string[];
|
|
246
|
+
/** Description of this override (optional) */
|
|
247
|
+
description?: string;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// =============================================================================
|
|
251
|
+
// 9. OverrideType - Override type enum
|
|
252
|
+
// =============================================================================
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Types of overrides that can be applied to instances.
|
|
256
|
+
* Each type corresponds to a different aspect of the element that can be changed.
|
|
257
|
+
*/
|
|
258
|
+
export type OverrideType =
|
|
259
|
+
| 'text' // Text content override
|
|
260
|
+
| 'fill' // Fill/background color override
|
|
261
|
+
| 'stroke' // Stroke/border override
|
|
262
|
+
| 'visibility' // Show/hide override
|
|
263
|
+
| 'image' // Image source override
|
|
264
|
+
| 'style' // CSS style overrides (Record<string, string>)
|
|
265
|
+
| 'attribute' // HTML attribute overrides (Record<string, string>)
|
|
266
|
+
| 'children' // Replace children (ComponentElement[])
|
|
267
|
+
| 'instanceSwap'; // Nested component swap override
|
|
268
|
+
|
|
269
|
+
// =============================================================================
|
|
270
|
+
// 10. ComponentCategory - Library structure
|
|
271
|
+
// =============================================================================
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Represents a category in the component library for organization.
|
|
275
|
+
* Supports nested subcategories for hierarchical organization.
|
|
276
|
+
*/
|
|
277
|
+
export interface ComponentCategory {
|
|
278
|
+
/** Unique identifier */
|
|
279
|
+
id: string;
|
|
280
|
+
/** Display name */
|
|
281
|
+
name: string;
|
|
282
|
+
/**
|
|
283
|
+
* Component IDs directly in this category.
|
|
284
|
+
* Use `componentIds` for consistency with context usage.
|
|
285
|
+
*/
|
|
286
|
+
componentIds: string[];
|
|
287
|
+
/** Nested subcategories (optional) */
|
|
288
|
+
subcategories?: ComponentCategory[];
|
|
289
|
+
/** Icon name for the category (optional) */
|
|
290
|
+
icon?: string;
|
|
291
|
+
/** Category color for visual distinction (optional) */
|
|
292
|
+
color?: string;
|
|
293
|
+
/** Sort order within parent (optional) */
|
|
294
|
+
order?: number;
|
|
295
|
+
/** Description of the category (optional) */
|
|
296
|
+
description?: string;
|
|
297
|
+
/** Parent category ID if nested (optional) */
|
|
298
|
+
parentId?: string;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// =============================================================================
|
|
302
|
+
// 1. MasterComponent - Master component definition (main type)
|
|
303
|
+
// =============================================================================
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Master component definition - the source of truth for a component.
|
|
307
|
+
* Similar to Figma's main component that instances are derived from.
|
|
308
|
+
*/
|
|
309
|
+
export interface MasterComponent {
|
|
310
|
+
/** Unique identifier */
|
|
311
|
+
id: string;
|
|
312
|
+
/** Component name */
|
|
313
|
+
name: string;
|
|
314
|
+
/** Component description (optional) */
|
|
315
|
+
description?: string;
|
|
316
|
+
/**
|
|
317
|
+
* Category ID for organization (e.g., "buttons", "cards", "navigation").
|
|
318
|
+
* References a ComponentCategory.id.
|
|
319
|
+
*/
|
|
320
|
+
categoryId: string;
|
|
321
|
+
/**
|
|
322
|
+
* Root element structure (optional if variants provide their own).
|
|
323
|
+
* @deprecated Prefer using variants[].rootElement instead.
|
|
324
|
+
*/
|
|
325
|
+
rootElement?: ComponentElement;
|
|
326
|
+
/** Variant property definitions (the axes of variation) */
|
|
327
|
+
variantProperties?: VariantProperty[];
|
|
328
|
+
/** All variant definitions (ComponentVariant is alias for VariantDefinition) */
|
|
329
|
+
variants: ComponentVariant[];
|
|
330
|
+
/** ID of the default variant to use for new instances */
|
|
331
|
+
defaultVariantId: string;
|
|
332
|
+
/**
|
|
333
|
+
* Exposed component properties for user configuration.
|
|
334
|
+
* ExposedProperty is alias for ComponentProperty.
|
|
335
|
+
*/
|
|
336
|
+
exposedProperties: ExposedProperty[];
|
|
337
|
+
/** ISO 8601 timestamp when created */
|
|
338
|
+
createdAt: string;
|
|
339
|
+
/** ISO 8601 timestamp when last updated */
|
|
340
|
+
updatedAt: string;
|
|
341
|
+
/** Preview thumbnail URL (optional) */
|
|
342
|
+
thumbnail?: string;
|
|
343
|
+
/** Tags for search and filtering (optional) */
|
|
344
|
+
tags?: string[];
|
|
345
|
+
/** Author user ID (optional) */
|
|
346
|
+
createdBy?: string;
|
|
347
|
+
/** Whether this component is published to the library (optional) */
|
|
348
|
+
isPublished?: boolean;
|
|
349
|
+
/** Version number (incremented on updates) */
|
|
350
|
+
version: number;
|
|
351
|
+
/** Associated Figma data if imported (optional) */
|
|
352
|
+
figmaData?: {
|
|
353
|
+
fileId: string;
|
|
354
|
+
nodeId: string;
|
|
355
|
+
lastSyncedAt: string;
|
|
356
|
+
};
|
|
357
|
+
/** Website ID this component belongs to */
|
|
358
|
+
websiteId: string;
|
|
359
|
+
/** Project ID this component belongs to (optional) */
|
|
360
|
+
projectId?: string;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// =============================================================================
|
|
364
|
+
// Override Value Types
|
|
365
|
+
// =============================================================================
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Image override value structure for image type overrides.
|
|
369
|
+
*/
|
|
370
|
+
export interface OverrideImageValue {
|
|
371
|
+
/** Image URL */
|
|
372
|
+
url: string;
|
|
373
|
+
/** Alt text for accessibility */
|
|
374
|
+
alt?: string;
|
|
375
|
+
/** Object fit mode for sizing */
|
|
376
|
+
objectFit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down';
|
|
377
|
+
/** Object position for alignment */
|
|
378
|
+
objectPosition?: string;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Instance swap override value structure for instanceSwap type overrides.
|
|
383
|
+
*/
|
|
384
|
+
export interface OverrideInstanceSwapValue {
|
|
385
|
+
/** ID of the component to swap in */
|
|
386
|
+
componentId: string;
|
|
387
|
+
/** Variant ID within that component (optional) */
|
|
388
|
+
variantId?: string;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Union type for all possible override values.
|
|
393
|
+
*/
|
|
394
|
+
export type OverrideValue =
|
|
395
|
+
| string
|
|
396
|
+
| boolean
|
|
397
|
+
| OverrideImageValue
|
|
398
|
+
| OverrideInstanceSwapValue;
|
|
399
|
+
|
|
400
|
+
// =============================================================================
|
|
401
|
+
// Type Guards
|
|
402
|
+
// =============================================================================
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Type guard to check if a value is a MasterComponent.
|
|
406
|
+
*/
|
|
407
|
+
export function isMasterComponent(value: unknown): value is MasterComponent {
|
|
408
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
409
|
+
const obj = value as Record<string, unknown>;
|
|
410
|
+
return (
|
|
411
|
+
typeof obj.id === 'string' &&
|
|
412
|
+
typeof obj.name === 'string' &&
|
|
413
|
+
typeof obj.categoryId === 'string' &&
|
|
414
|
+
Array.isArray(obj.variants) &&
|
|
415
|
+
typeof obj.defaultVariantId === 'string' &&
|
|
416
|
+
Array.isArray(obj.exposedProperties) &&
|
|
417
|
+
typeof obj.websiteId === 'string'
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Type guard to check if a value is a ComponentElement.
|
|
423
|
+
*/
|
|
424
|
+
export function isComponentElement(value: unknown): value is ComponentElement {
|
|
425
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
426
|
+
const obj = value as Record<string, unknown>;
|
|
427
|
+
return (
|
|
428
|
+
typeof obj.id === 'string' &&
|
|
429
|
+
typeof obj.tagName === 'string' &&
|
|
430
|
+
typeof obj.attributes === 'object' &&
|
|
431
|
+
typeof obj.className === 'string' &&
|
|
432
|
+
Array.isArray(obj.children) &&
|
|
433
|
+
typeof obj.overridable === 'object' &&
|
|
434
|
+
typeof obj.styles === 'object'
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Type guard to check if a value is a ComponentInstance.
|
|
440
|
+
*/
|
|
441
|
+
export function isComponentInstance(value: unknown): value is ComponentInstance {
|
|
442
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
443
|
+
const obj = value as Record<string, unknown>;
|
|
444
|
+
return (
|
|
445
|
+
typeof obj.id === 'string' &&
|
|
446
|
+
typeof obj.masterComponentId === 'string' &&
|
|
447
|
+
typeof obj.variantId === 'string' &&
|
|
448
|
+
Array.isArray(obj.overrides) &&
|
|
449
|
+
typeof obj.propertyValues === 'object' &&
|
|
450
|
+
typeof obj.domElementId === 'string'
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Type guard to check if a value is a VariantProperty.
|
|
456
|
+
*/
|
|
457
|
+
export function isVariantProperty(value: unknown): value is VariantProperty {
|
|
458
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
459
|
+
const obj = value as Record<string, unknown>;
|
|
460
|
+
return (
|
|
461
|
+
typeof obj.id === 'string' &&
|
|
462
|
+
typeof obj.name === 'string' &&
|
|
463
|
+
Array.isArray(obj.values) &&
|
|
464
|
+
typeof obj.defaultValue === 'string'
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Type guard to check if a value is a VariantDefinition.
|
|
470
|
+
*/
|
|
471
|
+
export function isVariantDefinition(value: unknown): value is VariantDefinition {
|
|
472
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
473
|
+
const obj = value as Record<string, unknown>;
|
|
474
|
+
return (
|
|
475
|
+
typeof obj.id === 'string' &&
|
|
476
|
+
typeof obj.name === 'string' &&
|
|
477
|
+
isComponentElement(obj.rootElement)
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Type guard to check if a value is a ComponentVariant (alias for VariantDefinition).
|
|
483
|
+
*/
|
|
484
|
+
export const isComponentVariant = isVariantDefinition;
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Type guard to check if a value is a ComponentProperty.
|
|
488
|
+
*/
|
|
489
|
+
export function isComponentProperty(value: unknown): value is ComponentProperty {
|
|
490
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
491
|
+
const obj = value as Record<string, unknown>;
|
|
492
|
+
return (
|
|
493
|
+
typeof obj.id === 'string' &&
|
|
494
|
+
typeof obj.name === 'string' &&
|
|
495
|
+
['boolean', 'text', 'instanceSwap', 'variant'].includes(obj.type as string) &&
|
|
496
|
+
(typeof obj.defaultValue === 'string' || typeof obj.defaultValue === 'boolean') &&
|
|
497
|
+
Array.isArray(obj.targetElementIds)
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Type guard to check if a value is a ComponentOverride.
|
|
503
|
+
*/
|
|
504
|
+
export function isComponentOverride(value: unknown): value is ComponentOverride {
|
|
505
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
506
|
+
const obj = value as Record<string, unknown>;
|
|
507
|
+
const hasTarget = typeof obj.targetElementId === 'string' || typeof obj.elementPath === 'string';
|
|
508
|
+
return (
|
|
509
|
+
typeof obj.id === 'string' &&
|
|
510
|
+
hasTarget &&
|
|
511
|
+
['text', 'fill', 'stroke', 'visibility', 'image', 'style', 'attribute', 'children', 'instanceSwap'].includes(obj.type as string)
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Type guard for OverrideImageValue.
|
|
517
|
+
*/
|
|
518
|
+
export function isOverrideImageValue(value: unknown): value is OverrideImageValue {
|
|
519
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
520
|
+
const obj = value as Record<string, unknown>;
|
|
521
|
+
return typeof obj.url === 'string';
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Type guard for OverrideInstanceSwapValue.
|
|
526
|
+
*/
|
|
527
|
+
export function isOverrideInstanceSwapValue(value: unknown): value is OverrideInstanceSwapValue {
|
|
528
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
529
|
+
const obj = value as Record<string, unknown>;
|
|
530
|
+
return typeof obj.componentId === 'string';
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Type guard to check if a value is a ComponentCategory.
|
|
535
|
+
*/
|
|
536
|
+
export function isComponentCategory(value: unknown): value is ComponentCategory {
|
|
537
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
538
|
+
const obj = value as Record<string, unknown>;
|
|
539
|
+
return (
|
|
540
|
+
typeof obj.id === 'string' &&
|
|
541
|
+
typeof obj.name === 'string' &&
|
|
542
|
+
Array.isArray(obj.componentIds)
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// =============================================================================
|
|
547
|
+
// Utility Types
|
|
548
|
+
// =============================================================================
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Partial component element for updates.
|
|
552
|
+
*/
|
|
553
|
+
export type PartialComponentElement = Partial<Omit<ComponentElement, 'children'>> & {
|
|
554
|
+
children?: PartialComponentElement[];
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Create master component input type (without auto-generated fields).
|
|
559
|
+
*/
|
|
560
|
+
export type CreateMasterComponentInput = Omit<
|
|
561
|
+
MasterComponent,
|
|
562
|
+
'id' | 'createdAt' | 'updatedAt' | 'version'
|
|
563
|
+
>;
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Update master component input type.
|
|
567
|
+
*/
|
|
568
|
+
export type UpdateMasterComponentInput = Partial<
|
|
569
|
+
Omit<MasterComponent, 'id' | 'createdAt' | 'websiteId'>
|
|
570
|
+
>;
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Create instance input type.
|
|
574
|
+
*/
|
|
575
|
+
export type CreateComponentInstanceInput = Omit<
|
|
576
|
+
ComponentInstance,
|
|
577
|
+
'id' | 'createdAt' | 'updatedAt'
|
|
578
|
+
>;
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Update instance input type.
|
|
582
|
+
*/
|
|
583
|
+
export type UpdateComponentInstanceInput = Partial<
|
|
584
|
+
Omit<ComponentInstance, 'id' | 'masterComponentId' | 'createdAt'>
|
|
585
|
+
>;
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Element path type for nested element access.
|
|
589
|
+
*/
|
|
590
|
+
export type ElementPath = string[];
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Variant key computed from property values (for Map lookups).
|
|
594
|
+
*/
|
|
595
|
+
export type VariantKey = string;
|
|
596
|
+
|
|
597
|
+
// =============================================================================
|
|
598
|
+
// Default Values & Factory Functions
|
|
599
|
+
// =============================================================================
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Default overridable properties (all enabled).
|
|
603
|
+
*/
|
|
604
|
+
export const DEFAULT_OVERRIDABLE_PROPERTIES: OverridableProperties = {
|
|
605
|
+
text: true,
|
|
606
|
+
fill: true,
|
|
607
|
+
stroke: true,
|
|
608
|
+
visibility: true,
|
|
609
|
+
image: true,
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Locked overridable properties (all disabled).
|
|
614
|
+
*/
|
|
615
|
+
export const LOCKED_OVERRIDABLE_PROPERTIES: OverridableProperties = {
|
|
616
|
+
text: false,
|
|
617
|
+
fill: false,
|
|
618
|
+
stroke: false,
|
|
619
|
+
visibility: false,
|
|
620
|
+
image: false,
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Create an empty component element with sensible defaults.
|
|
625
|
+
*/
|
|
626
|
+
export function createEmptyComponentElement(
|
|
627
|
+
id: string,
|
|
628
|
+
tagName: string = 'div'
|
|
629
|
+
): ComponentElement {
|
|
630
|
+
return {
|
|
631
|
+
id,
|
|
632
|
+
tagName,
|
|
633
|
+
attributes: {},
|
|
634
|
+
className: '',
|
|
635
|
+
children: [],
|
|
636
|
+
overridable: { ...DEFAULT_OVERRIDABLE_PROPERTIES },
|
|
637
|
+
styles: {},
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Create an empty variant property with default values.
|
|
643
|
+
*/
|
|
644
|
+
export function createEmptyVariantProperty(
|
|
645
|
+
id: string,
|
|
646
|
+
name: string
|
|
647
|
+
): VariantProperty {
|
|
648
|
+
return {
|
|
649
|
+
id,
|
|
650
|
+
name,
|
|
651
|
+
values: ['default'],
|
|
652
|
+
defaultValue: 'default',
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Create an empty variant definition.
|
|
658
|
+
*/
|
|
659
|
+
export function createEmptyVariantDefinition(
|
|
660
|
+
id: string,
|
|
661
|
+
name: string,
|
|
662
|
+
rootElement?: ComponentElement,
|
|
663
|
+
propertyValues?: Record<string, string>
|
|
664
|
+
): VariantDefinition {
|
|
665
|
+
return {
|
|
666
|
+
id,
|
|
667
|
+
name,
|
|
668
|
+
propertyValues,
|
|
669
|
+
rootElement: rootElement || createEmptyComponentElement(`${id}-root`),
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Create an empty component property.
|
|
675
|
+
*/
|
|
676
|
+
export function createEmptyComponentProperty(
|
|
677
|
+
id: string,
|
|
678
|
+
name: string,
|
|
679
|
+
type: ComponentPropertyType = 'text'
|
|
680
|
+
): ComponentProperty {
|
|
681
|
+
return {
|
|
682
|
+
id,
|
|
683
|
+
name,
|
|
684
|
+
type,
|
|
685
|
+
defaultValue: type === 'boolean' ? false : '',
|
|
686
|
+
targetElementIds: [],
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Create an empty component override using targetElementId.
|
|
692
|
+
*/
|
|
693
|
+
export function createEmptyComponentOverride(
|
|
694
|
+
id: string,
|
|
695
|
+
targetElementId: string,
|
|
696
|
+
type: OverrideType
|
|
697
|
+
): ComponentOverride {
|
|
698
|
+
const value = type === 'visibility' ? true : '';
|
|
699
|
+
return {
|
|
700
|
+
id,
|
|
701
|
+
targetElementId,
|
|
702
|
+
type,
|
|
703
|
+
value,
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Create a component override using element path.
|
|
709
|
+
*/
|
|
710
|
+
export function createPathBasedOverride(
|
|
711
|
+
id: string,
|
|
712
|
+
elementPath: string,
|
|
713
|
+
type: OverrideType,
|
|
714
|
+
value?: ComponentOverride['value']
|
|
715
|
+
): ComponentOverride {
|
|
716
|
+
return {
|
|
717
|
+
id,
|
|
718
|
+
elementPath,
|
|
719
|
+
type,
|
|
720
|
+
value: value ?? (type === 'visibility' ? true : ''),
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Create a variant key from property values (for indexing/lookup).
|
|
726
|
+
*/
|
|
727
|
+
export function createVariantKey(propertyValues: Record<string, string>): VariantKey {
|
|
728
|
+
return Object.entries(propertyValues)
|
|
729
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
730
|
+
.map(([key, value]) => `${key}:${value}`)
|
|
731
|
+
.join('|');
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Parse a variant key back to property values.
|
|
736
|
+
*/
|
|
737
|
+
export function parseVariantKey(key: VariantKey): Record<string, string> {
|
|
738
|
+
if (!key) return {};
|
|
739
|
+
return Object.fromEntries(
|
|
740
|
+
key.split('|').map(pair => {
|
|
741
|
+
const colonIndex = pair.indexOf(':');
|
|
742
|
+
if (colonIndex === -1) return [pair, ''];
|
|
743
|
+
return [pair.slice(0, colonIndex), pair.slice(colonIndex + 1)];
|
|
744
|
+
})
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// =============================================================================
|
|
749
|
+
// Component Search & Filter Types
|
|
750
|
+
// =============================================================================
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Search filters for component library.
|
|
754
|
+
*/
|
|
755
|
+
export interface ComponentSearchFilters {
|
|
756
|
+
/** Filter by category ID */
|
|
757
|
+
categoryId?: string;
|
|
758
|
+
/** Filter by tags */
|
|
759
|
+
tags?: string[];
|
|
760
|
+
/** Text search query */
|
|
761
|
+
query?: string;
|
|
762
|
+
/** Filter by author */
|
|
763
|
+
authorId?: string;
|
|
764
|
+
/** Only published components */
|
|
765
|
+
publishedOnly?: boolean;
|
|
766
|
+
/** Filter by website ID */
|
|
767
|
+
websiteId?: string;
|
|
768
|
+
/** Filter by project ID */
|
|
769
|
+
projectId?: string;
|
|
770
|
+
/** Sort field */
|
|
771
|
+
sortBy?: 'name' | 'createdAt' | 'updatedAt' | 'usageCount';
|
|
772
|
+
/** Sort direction */
|
|
773
|
+
sortOrder?: 'asc' | 'desc';
|
|
774
|
+
/** Pagination limit */
|
|
775
|
+
limit?: number;
|
|
776
|
+
/** Pagination offset */
|
|
777
|
+
offset?: number;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Component search result.
|
|
782
|
+
*/
|
|
783
|
+
export interface ComponentSearchResult {
|
|
784
|
+
/** Matched components */
|
|
785
|
+
components: MasterComponent[];
|
|
786
|
+
/** Total count for pagination */
|
|
787
|
+
totalCount: number;
|
|
788
|
+
/** Whether there are more results */
|
|
789
|
+
hasMore: boolean;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// =============================================================================
|
|
793
|
+
// Event Types for Component Operations
|
|
794
|
+
// =============================================================================
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Component event types for tracking changes.
|
|
798
|
+
*/
|
|
799
|
+
export type ComponentEventType =
|
|
800
|
+
| 'component:created'
|
|
801
|
+
| 'component:updated'
|
|
802
|
+
| 'component:deleted'
|
|
803
|
+
| 'component:published'
|
|
804
|
+
| 'component:unpublished'
|
|
805
|
+
| 'variant:added'
|
|
806
|
+
| 'variant:updated'
|
|
807
|
+
| 'variant:deleted'
|
|
808
|
+
| 'instance:created'
|
|
809
|
+
| 'instance:updated'
|
|
810
|
+
| 'instance:deleted'
|
|
811
|
+
| 'instance:detached'
|
|
812
|
+
| 'override:applied'
|
|
813
|
+
| 'override:removed'
|
|
814
|
+
| 'override:reset'
|
|
815
|
+
| 'property:changed';
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Component event payload structure.
|
|
819
|
+
*/
|
|
820
|
+
export interface ComponentEvent<T = unknown> {
|
|
821
|
+
/** Event type */
|
|
822
|
+
type: ComponentEventType;
|
|
823
|
+
/** Event payload data */
|
|
824
|
+
payload: T;
|
|
825
|
+
/** Event timestamp */
|
|
826
|
+
timestamp: number;
|
|
827
|
+
/** User ID who triggered the event */
|
|
828
|
+
userId?: string;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// =============================================================================
|
|
832
|
+
// Context State Types
|
|
833
|
+
// =============================================================================
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* State managed by the EditorComponentsContext.
|
|
837
|
+
*/
|
|
838
|
+
export interface EditorComponentsState {
|
|
839
|
+
/** Map of master component ID to master component */
|
|
840
|
+
masterComponents: Map<string, MasterComponent>;
|
|
841
|
+
/** Map of DOM element ID to component instance */
|
|
842
|
+
componentInstances: Map<string, ComponentInstance>;
|
|
843
|
+
/** Component library categories (alias for ComponentCategory) */
|
|
844
|
+
componentLibrary: ComponentLibraryCategory[];
|
|
845
|
+
/** Loading state */
|
|
846
|
+
isLoadingComponents: boolean;
|
|
847
|
+
/** Currently selected master component ID (for editing) */
|
|
848
|
+
selectedMasterComponentId: string | null;
|
|
849
|
+
/** Currently selected instance ID */
|
|
850
|
+
selectedInstanceId: string | null;
|
|
851
|
+
/** Error state */
|
|
852
|
+
error: string | null;
|
|
853
|
+
/** Pending navigation target for "go to main component" feature */
|
|
854
|
+
pendingNavigationTarget: string | null;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Actions available in the EditorComponentsContext.
|
|
859
|
+
* Note: This is a minimal interface - implementations may provide additional methods.
|
|
860
|
+
*/
|
|
861
|
+
export interface EditorComponentsActions {
|
|
862
|
+
// Loading
|
|
863
|
+
loadComponents: (websiteId: string) => Promise<void>;
|
|
864
|
+
|
|
865
|
+
// Master Component CRUD
|
|
866
|
+
createMasterComponent: (
|
|
867
|
+
element: HTMLElement,
|
|
868
|
+
name: string,
|
|
869
|
+
category: string,
|
|
870
|
+
description?: string
|
|
871
|
+
) => MasterComponent;
|
|
872
|
+
updateMasterComponent: (
|
|
873
|
+
id: string,
|
|
874
|
+
updates: Partial<MasterComponent>
|
|
875
|
+
) => void;
|
|
876
|
+
deleteMasterComponent: (id: string) => void;
|
|
877
|
+
getMasterComponent: (id: string) => MasterComponent | null;
|
|
878
|
+
|
|
879
|
+
// Instance CRUD
|
|
880
|
+
createInstance: (
|
|
881
|
+
masterComponentId: string,
|
|
882
|
+
variantId?: string,
|
|
883
|
+
instancePageId?: string,
|
|
884
|
+
/** Optional: pass the master component directly if it's not yet in state */
|
|
885
|
+
providedMaster?: MasterComponent,
|
|
886
|
+
/** Optional: specify domElementId (for duplication) */
|
|
887
|
+
customDomElementId?: string,
|
|
888
|
+
/** Optional: initial overrides to copy (for duplication) */
|
|
889
|
+
initialOverrides?: ComponentOverride[],
|
|
890
|
+
/** Optional: initial property values to copy (for duplication) */
|
|
891
|
+
initialPropertyValues?: Record<string, string | number | boolean>,
|
|
892
|
+
/** Optional: initial position for the instance */
|
|
893
|
+
initialPosition?: { x: number; y: number },
|
|
894
|
+
/** Optional: initial size for the instance */
|
|
895
|
+
initialSize?: { width: number; height: number }
|
|
896
|
+
) => ComponentInstance;
|
|
897
|
+
updateInstance: (
|
|
898
|
+
instanceId: string,
|
|
899
|
+
updates: Partial<ComponentInstance>
|
|
900
|
+
) => void;
|
|
901
|
+
deleteInstance: (instanceId: string) => void;
|
|
902
|
+
getInstanceByDomId: (domElementId: string) => ComponentInstance | null;
|
|
903
|
+
|
|
904
|
+
// Override Management
|
|
905
|
+
addOverride: (
|
|
906
|
+
instanceId: string,
|
|
907
|
+
override: Omit<ComponentOverride, 'id'>
|
|
908
|
+
) => void;
|
|
909
|
+
removeOverride: (instanceId: string, overrideId: string) => void;
|
|
910
|
+
resetAllOverrides: (instanceId: string) => void;
|
|
911
|
+
|
|
912
|
+
// Variant Operations
|
|
913
|
+
changeVariant: (instanceId: string, variantId: string) => void;
|
|
914
|
+
|
|
915
|
+
// Detach
|
|
916
|
+
detachInstance: (instanceId: string) => HTMLElement;
|
|
917
|
+
|
|
918
|
+
// Resolution
|
|
919
|
+
resolveInstance: (
|
|
920
|
+
master: MasterComponent,
|
|
921
|
+
instance: ComponentInstance
|
|
922
|
+
) => ComponentElement;
|
|
923
|
+
|
|
924
|
+
// Navigation
|
|
925
|
+
/** Request to navigate to a master component (opens component panel) */
|
|
926
|
+
navigateToMasterComponent: (masterComponentId: string) => void;
|
|
927
|
+
/** Clear pending navigation request */
|
|
928
|
+
clearNavigationRequest: () => void;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Combined context value type.
|
|
933
|
+
*/
|
|
934
|
+
export type EditorComponentsContextValue = EditorComponentsState &
|
|
935
|
+
EditorComponentsActions;
|
|
936
|
+
|
|
937
|
+
// =============================================================================
|
|
938
|
+
// Alias for backward compatibility
|
|
939
|
+
// =============================================================================
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* Alias for ComponentCategory (backward compatibility).
|
|
943
|
+
*/
|
|
944
|
+
export type ComponentLibraryCategory = ComponentCategory;
|