@tpitre/story-ui 2.6.1 → 2.7.1
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 +36 -37
- package/dist/cli/deploy.d.ts +4 -3
- package/dist/cli/deploy.d.ts.map +1 -1
- package/dist/cli/deploy.js +542 -46
- package/dist/cli/index.js +17 -14
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +4 -110
- package/dist/cli/setup.js.map +1 -0
- package/dist/cloudflare-edge/src/mcp-session.js +462 -0
- package/dist/cloudflare-edge/src/types.js +4 -0
- package/dist/cloudflare-edge/src/worker.js +106 -0
- package/dist/cloudflare-pages/vite.config.js +14 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/mcp-server/mcp-stdio-server.js.map +1 -0
- package/dist/mcp-server/routes/claude.js.map +1 -0
- package/dist/mcp-server/routes/components.js.map +1 -0
- package/dist/mcp-server/routes/generateStory.js.map +1 -0
- package/dist/mcp-server/routes/hybridStories.js.map +1 -0
- package/dist/mcp-server/routes/memoryStories.js.map +1 -0
- package/dist/mcp-server/routes/storySync.js.map +1 -0
- package/dist/mcp-server/routes/updateStory.js +246 -0
- package/dist/mcp-server/sessionManager.js.map +1 -0
- package/dist/playground/components/AIAssistant/AIAssistant.d.ts +6 -0
- package/dist/playground/components/AIAssistant/AIAssistant.d.ts.map +1 -0
- package/dist/playground/components/AIAssistant/AIAssistant.js +109 -0
- package/dist/playground/components/AIAssistant/AIAssistant.js.map +1 -0
- package/dist/playground/components/AIAssistant/AIAssistant.module.css +166 -0
- package/dist/playground/components/Canvas/Canvas.d.ts +9 -0
- package/dist/playground/components/Canvas/Canvas.d.ts.map +1 -0
- package/dist/playground/components/Canvas/Canvas.js +58 -0
- package/dist/playground/components/Canvas/Canvas.js.map +1 -0
- package/dist/playground/components/Canvas/Canvas.module.css +189 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.d.ts +9 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.d.ts.map +1 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.js +158 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.js.map +1 -0
- package/dist/playground/components/Canvas/ComponentRenderer.d.ts +15 -0
- package/dist/playground/components/Canvas/ComponentRenderer.d.ts.map +1 -0
- package/dist/playground/components/Canvas/ComponentRenderer.js +177 -0
- package/dist/playground/components/Canvas/ComponentRenderer.js.map +1 -0
- package/dist/playground/components/Canvas/DraggableComponent.d.ts +15 -0
- package/dist/playground/components/Canvas/DraggableComponent.d.ts.map +1 -0
- package/dist/playground/components/Canvas/DraggableComponent.js +49 -0
- package/dist/playground/components/Canvas/DraggableComponent.js.map +1 -0
- package/dist/playground/components/Canvas/index.d.ts +9 -0
- package/dist/playground/components/Canvas/index.d.ts.map +1 -0
- package/dist/playground/components/Canvas/index.js +5 -0
- package/dist/playground/components/Canvas/index.js.map +1 -0
- package/dist/playground/components/CodeView/CodeView.d.ts +12 -0
- package/dist/playground/components/CodeView/CodeView.d.ts.map +1 -0
- package/dist/playground/components/CodeView/CodeView.js +77 -0
- package/dist/playground/components/CodeView/CodeView.js.map +1 -0
- package/dist/playground/components/CodeView/CodeView.module.css +178 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.d.ts +17 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.d.ts.map +1 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.js +138 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.js.map +1 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.module.css +217 -0
- package/dist/playground/components/ComponentPalette/index.d.ts +3 -0
- package/dist/playground/components/ComponentPalette/index.d.ts.map +1 -0
- package/dist/playground/components/ComponentPalette/index.js +2 -0
- package/dist/playground/components/ComponentPalette/index.js.map +1 -0
- package/dist/playground/components/DropZone/DropZone.d.ts +17 -0
- package/dist/playground/components/DropZone/DropZone.d.ts.map +1 -0
- package/dist/playground/components/DropZone/DropZone.js +73 -0
- package/dist/playground/components/DropZone/DropZone.js.map +1 -0
- package/dist/playground/components/DropZone/DropZone.module.css +86 -0
- package/dist/playground/components/ExportDialog/ExportDialog.d.ts +10 -0
- package/dist/playground/components/ExportDialog/ExportDialog.d.ts.map +1 -0
- package/dist/playground/components/ExportDialog/ExportDialog.js +57 -0
- package/dist/playground/components/ExportDialog/ExportDialog.js.map +1 -0
- package/dist/playground/components/ExportDialog/ExportDialog.module.css +328 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.d.ts +134 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.d.ts.map +1 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.js +254 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.js.map +1 -0
- package/dist/playground/components/LayoutHelpers/index.d.ts +3 -0
- package/dist/playground/components/LayoutHelpers/index.d.ts.map +1 -0
- package/dist/playground/components/LayoutHelpers/index.js +2 -0
- package/dist/playground/components/LayoutHelpers/index.js.map +1 -0
- package/dist/playground/components/Playground/Playground.d.ts +10 -0
- package/dist/playground/components/Playground/Playground.d.ts.map +1 -0
- package/dist/playground/components/Playground/Playground.js +128 -0
- package/dist/playground/components/Playground/Playground.js.map +1 -0
- package/dist/playground/components/Playground/Playground.module.css +308 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.d.ts +10 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.d.ts.map +1 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.js +150 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.js.map +1 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.module.css +155 -0
- package/dist/playground/components/PropertiesPanel/index.d.ts +3 -0
- package/dist/playground/components/PropertiesPanel/index.d.ts.map +1 -0
- package/dist/playground/components/PropertiesPanel/index.js +2 -0
- package/dist/playground/components/PropertiesPanel/index.js.map +1 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.d.ts +12 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.js +14 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.d.ts +12 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.js +62 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/IconEditor.d.ts +12 -0
- package/dist/playground/components/PropertyEditors/IconEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/IconEditor.js +123 -0
- package/dist/playground/components/PropertyEditors/IconEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.d.ts +15 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.js +46 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/PropertyEditors.module.css +432 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.d.ts +19 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.js +17 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.d.ts +19 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.js +162 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.module.css +214 -0
- package/dist/playground/components/PropertyEditors/TextEditor.d.ts +14 -0
- package/dist/playground/components/PropertyEditors/TextEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/TextEditor.js +38 -0
- package/dist/playground/components/PropertyEditors/TextEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.d.ts +23 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.js +50 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/index.d.ts +20 -0
- package/dist/playground/components/PropertyEditors/index.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/index.js +12 -0
- package/dist/playground/components/PropertyEditors/index.js.map +1 -0
- package/dist/playground/components/TreeView/TreeView.d.ts +10 -0
- package/dist/playground/components/TreeView/TreeView.d.ts.map +1 -0
- package/dist/playground/components/TreeView/TreeView.js +146 -0
- package/dist/playground/components/TreeView/TreeView.js.map +1 -0
- package/dist/playground/components/TreeView/TreeView.module.css +214 -0
- package/dist/playground/components/TreeView/index.d.ts +3 -0
- package/dist/playground/components/TreeView/index.d.ts.map +1 -0
- package/dist/playground/components/TreeView/index.js +2 -0
- package/dist/playground/components/TreeView/index.js.map +1 -0
- package/dist/playground/config/propertyDefinitions.d.ts +73 -0
- package/dist/playground/config/propertyDefinitions.d.ts.map +1 -0
- package/dist/playground/config/propertyDefinitions.js +809 -0
- package/dist/playground/config/propertyDefinitions.js.map +1 -0
- package/dist/playground/hooks/useKeyboardShortcuts.d.ts +38 -0
- package/dist/playground/hooks/useKeyboardShortcuts.d.ts.map +1 -0
- package/dist/playground/hooks/useKeyboardShortcuts.js +191 -0
- package/dist/playground/hooks/useKeyboardShortcuts.js.map +1 -0
- package/dist/playground/index.d.ts +21 -0
- package/dist/playground/index.d.ts.map +1 -0
- package/dist/playground/index.js +23 -0
- package/dist/playground/index.js.map +1 -0
- package/dist/playground/services/CodeGenerator.d.ts +73 -0
- package/dist/playground/services/CodeGenerator.d.ts.map +1 -0
- package/dist/playground/services/CodeGenerator.js +359 -0
- package/dist/playground/services/CodeGenerator.js.map +1 -0
- package/dist/playground/services/DragDropManager.d.ts +95 -0
- package/dist/playground/services/DragDropManager.d.ts.map +1 -0
- package/dist/playground/services/DragDropManager.js +408 -0
- package/dist/playground/services/DragDropManager.js.map +1 -0
- package/dist/playground/services/StoryParser.d.ts +73 -0
- package/dist/playground/services/StoryParser.d.ts.map +1 -0
- package/dist/playground/services/StoryParser.js +419 -0
- package/dist/playground/services/StoryParser.js.map +1 -0
- package/dist/playground/store/playgroundStore.d.ts +86 -0
- package/dist/playground/store/playgroundStore.d.ts.map +1 -0
- package/dist/playground/store/playgroundStore.js +337 -0
- package/dist/playground/store/playgroundStore.js.map +1 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.d.ts +13 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.js +227 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.js.map +1 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.d.ts +13 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.js +334 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.js.map +1 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.d.ts +14 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.js +512 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.js.map +1 -0
- package/dist/playground/stories/PlaygroundProperties.stories.d.ts +13 -0
- package/dist/playground/stories/PlaygroundProperties.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundProperties.stories.js +342 -0
- package/dist/playground/stories/PlaygroundProperties.stories.js.map +1 -0
- package/dist/playground/types/index.d.ts +251 -0
- package/dist/playground/types/index.d.ts.map +1 -0
- package/dist/playground/types/index.js +5 -0
- package/dist/playground/types/index.js.map +1 -0
- package/dist/scripts/verify-framework-adapters.js +105 -0
- package/dist/story-generator/componentBlacklist.js.map +1 -0
- package/dist/story-generator/componentDiscovery.js.map +1 -0
- package/dist/story-generator/configLoader.js.map +1 -0
- package/dist/story-generator/considerationsLoader.js.map +1 -0
- package/dist/story-generator/documentation-sources.js.map +1 -0
- package/dist/story-generator/documentationLoader.js.map +1 -0
- package/dist/story-generator/dynamicPackageDiscovery.js.map +1 -0
- package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
- package/dist/story-generator/enhancedComponentDiscovery.js +4 -6
- package/dist/story-generator/enhancedComponentDiscovery.js.map +1 -0
- package/dist/story-generator/generateStory.js.map +1 -0
- package/dist/story-generator/gitignoreManager.js.map +1 -0
- package/dist/story-generator/inMemoryStoryService.js.map +1 -0
- package/dist/story-generator/llm-providers/settings-manager.js +4 -4
- package/dist/story-generator/logger.js.map +1 -0
- package/dist/story-generator/postProcessStory.js.map +1 -0
- package/dist/story-generator/productionGitignoreManager.d.ts.map +1 -1
- package/dist/story-generator/productionGitignoreManager.js +6 -0
- package/dist/story-generator/productionGitignoreManager.js.map +1 -0
- package/dist/story-generator/promptGenerator.js.map +1 -0
- package/dist/story-generator/providerPresets.d.ts +54 -0
- package/dist/story-generator/providerPresets.d.ts.map +1 -0
- package/dist/story-generator/providerPresets.js +214 -0
- package/dist/story-generator/storyHistory.js.map +1 -0
- package/dist/story-generator/storySync.js.map +1 -0
- package/dist/story-generator/storyTracker.js.map +1 -0
- package/dist/story-generator/storyValidator.js.map +1 -0
- package/dist/story-generator/test_validation.d.ts +2 -0
- package/dist/story-generator/test_validation.d.ts.map +1 -0
- package/dist/story-generator/test_validation.js +51 -0
- package/dist/story-generator/universalDesignSystemAdapter.js.map +1 -0
- package/dist/story-generator/urlRedirectService.js.map +1 -0
- package/dist/story-generator/validateStory.js.map +1 -0
- package/dist/story-ui.config.js.map +1 -0
- package/dist/story-ui.config.loader.d.ts +36 -0
- package/dist/story-ui.config.loader.d.ts.map +1 -0
- package/dist/story-ui.config.loader.js +205 -0
- package/dist/story-ui.config.loader.js.map +1 -0
- package/dist/temp/package/templates/StoryUI/StoryUIPanel.js +807 -0
- package/dist/temp/package/templates/StoryUI/StoryUIPanel.stories.js +37 -0
- package/dist/temp/package/templates/StoryUI/index.js +2 -0
- package/dist/templates/StoryUI/StoryUIPanel.js.map +1 -0
- package/dist/templates/StoryUI/StoryUIPanel.stories.js.map +1 -0
- package/dist/templates/StoryUI/index.js.map +1 -0
- package/dist/templates/StoryUI/manager.d.ts +14 -0
- package/dist/templates/StoryUI/manager.d.ts.map +1 -0
- package/dist/templates/production-app/src/App.d.ts +10 -0
- package/dist/templates/production-app/src/App.d.ts.map +1 -0
- package/dist/templates/production-app/src/App.js +653 -0
- package/dist/templates/production-app/src/LivePreviewRenderer.d.ts +24 -0
- package/dist/templates/production-app/src/LivePreviewRenderer.d.ts.map +1 -0
- package/dist/templates/production-app/src/LivePreviewRenderer.js +199 -0
- package/dist/templates/production-app/src/componentRegistry.d.ts +20 -0
- package/dist/templates/production-app/src/componentRegistry.d.ts.map +1 -0
- package/dist/templates/production-app/src/componentRegistry.js +316 -0
- package/dist/templates/production-app/src/main.d.ts +9 -0
- package/dist/templates/production-app/src/main.d.ts.map +1 -0
- package/dist/templates/production-app/src/main.js +18 -0
- package/dist/templates/production-app/vite.config.d.ts +3 -0
- package/dist/templates/production-app/vite.config.d.ts.map +1 -0
- package/dist/templates/production-app/vite.config.js +71 -0
- package/dist/test-storybooks/angular-material-storybook/src/main.js +66 -0
- package/dist/test-storybooks/chakra-storybook/vite.config.js +6 -0
- package/dist/test-storybooks/mantine-storybook/vite.config.js +93 -0
- package/dist/test-storybooks/web-components-shoelace/vite.config.js +9 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/visual-builder/components/Canvas/Canvas.js +70 -0
- package/dist/visual-builder/components/Canvas/ComponentRenderer.js +545 -0
- package/dist/visual-builder/components/CodeExporter/CodeExporter.js +25 -0
- package/dist/visual-builder/components/CodeExporter/codeGenerator.js +99 -0
- package/dist/visual-builder/components/ComponentPalette/ComponentPalette.js +8 -0
- package/dist/visual-builder/components/ComponentPalette/ComponentPaletteItem.js +51 -0
- package/dist/visual-builder/components/EmbeddedVisualBuilder.js +107 -0
- package/dist/visual-builder/components/PropertyEditor/PropertyEditor.js +16 -0
- package/dist/visual-builder/components/PropertyEditor/PropertyForm.js +88 -0
- package/dist/visual-builder/components/PropertyEditor/SpacingControl.js +145 -0
- package/dist/visual-builder/components/PropertyEditor/SpacingEditor.js +32 -0
- package/dist/visual-builder/components/StoryManager/SaveOnlyManager.js +94 -0
- package/dist/visual-builder/components/StoryManager/StoryManager.js +68 -0
- package/dist/visual-builder/components/StoryManager/index.js +1 -0
- package/dist/visual-builder/components/VisualBuilder.js +256 -0
- package/dist/visual-builder/config/componentRegistry.js +1758 -0
- package/dist/visual-builder/decorators/VisualBuilderDecorator.js +184 -0
- package/dist/visual-builder/example-integration.js +59 -0
- package/dist/visual-builder/example.js +23 -0
- package/dist/visual-builder/hooks/useDragAndDrop.js +137 -0
- package/dist/visual-builder/hooks/useSelection.js +27 -0
- package/dist/visual-builder/index.js +7 -0
- package/dist/visual-builder/store/visualBuilderStore.js +305 -0
- package/dist/visual-builder/types/index.js +1 -0
- package/dist/visual-builder/utils/__tests__/storyFileUpdater.test.js +145 -0
- package/dist/visual-builder/utils/aiParser.js +336 -0
- package/dist/visual-builder/utils/componentTreeUtils.js +111 -0
- package/dist/visual-builder/utils/parserValidation.js +122 -0
- package/dist/visual-builder/utils/storyFileManager.js +73 -0
- package/dist/visual-builder/utils/storyFileUpdater.js +326 -0
- package/dist/visual-builder/utils/storyNameExtraction.test.js +211 -0
- package/dist/visual-builder/utils/storyPersistence.js +180 -0
- package/dist/visual-builder/utils/storyToBuilder.js +813 -0
- package/package.json +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export const generateJSXCode = (components) => {
|
|
2
|
+
if (components.length === 0) {
|
|
3
|
+
return `import React from 'react';
|
|
4
|
+
import { Box } from '@mantine/core';
|
|
5
|
+
|
|
6
|
+
export const GeneratedComponent = () => {
|
|
7
|
+
return (
|
|
8
|
+
<Box>
|
|
9
|
+
{/* Add your components here */}
|
|
10
|
+
</Box>
|
|
11
|
+
);
|
|
12
|
+
};`;
|
|
13
|
+
}
|
|
14
|
+
const imports = generateImports(components);
|
|
15
|
+
const componentCode = generateComponentCode(components);
|
|
16
|
+
return `import React from 'react';
|
|
17
|
+
${imports}
|
|
18
|
+
|
|
19
|
+
export const GeneratedComponent = () => {
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
${componentCode.split('\n').map(line => line ? ` ${line}` : '').join('\n')}
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
};`;
|
|
26
|
+
};
|
|
27
|
+
const generateImports = (components) => {
|
|
28
|
+
const usedComponents = new Set();
|
|
29
|
+
const collectComponents = (comps) => {
|
|
30
|
+
comps.forEach(comp => {
|
|
31
|
+
usedComponents.add(comp.type);
|
|
32
|
+
if (comp.children) {
|
|
33
|
+
collectComponents(comp.children);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
collectComponents(components);
|
|
38
|
+
const sortedComponents = Array.from(usedComponents).sort();
|
|
39
|
+
return `import { ${sortedComponents.join(', ')} } from '@mantine/core';`;
|
|
40
|
+
};
|
|
41
|
+
const generateComponentCode = (components, indent = 0) => {
|
|
42
|
+
const indentStr = ' '.repeat(indent);
|
|
43
|
+
return components.map(component => {
|
|
44
|
+
const { type, props, children } = component;
|
|
45
|
+
const hasChildren = children && children.length > 0;
|
|
46
|
+
const hasTextContent = props.children && typeof props.children === 'string';
|
|
47
|
+
// Generate props string
|
|
48
|
+
const propsString = generatePropsString(props, type);
|
|
49
|
+
if (hasChildren) {
|
|
50
|
+
// Component with children
|
|
51
|
+
return `${indentStr}<${type}${propsString}>
|
|
52
|
+
${generateComponentCode(children, indent + 1)}
|
|
53
|
+
${indentStr}</${type}>`;
|
|
54
|
+
}
|
|
55
|
+
else if (hasTextContent) {
|
|
56
|
+
// Component with text content
|
|
57
|
+
return `${indentStr}<${type}${propsString}>
|
|
58
|
+
${indentStr} ${props.children}
|
|
59
|
+
${indentStr}</${type}>`;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Self-closing component
|
|
63
|
+
return `${indentStr}<${type}${propsString} />`;
|
|
64
|
+
}
|
|
65
|
+
}).join('\n');
|
|
66
|
+
};
|
|
67
|
+
const generatePropsString = (props, componentType) => {
|
|
68
|
+
const propEntries = Object.entries(props);
|
|
69
|
+
// Filter out children prop for components that don't use it as text content
|
|
70
|
+
const filteredProps = propEntries.filter(([key, value]) => {
|
|
71
|
+
if (key === 'children') {
|
|
72
|
+
// Keep children prop only for text-based components
|
|
73
|
+
return ['Button', 'Text', 'Title'].includes(componentType) && typeof value === 'string';
|
|
74
|
+
}
|
|
75
|
+
// Filter out undefined, null, empty string, and default values
|
|
76
|
+
if (value === undefined || value === null || value === '')
|
|
77
|
+
return false;
|
|
78
|
+
return true;
|
|
79
|
+
});
|
|
80
|
+
if (filteredProps.length === 0)
|
|
81
|
+
return '';
|
|
82
|
+
const propsString = filteredProps
|
|
83
|
+
.map(([key, value]) => {
|
|
84
|
+
if (typeof value === 'boolean') {
|
|
85
|
+
return value ? key : `${key}={false}`;
|
|
86
|
+
}
|
|
87
|
+
else if (typeof value === 'string') {
|
|
88
|
+
return `${key}="${value}"`;
|
|
89
|
+
}
|
|
90
|
+
else if (typeof value === 'number') {
|
|
91
|
+
return `${key}={${value}}`;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return `${key}={${JSON.stringify(value)}}`;
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
.join(' ');
|
|
98
|
+
return propsString ? ` ${propsString}` : '';
|
|
99
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, Accordion } from '@mantine/core';
|
|
3
|
+
import { ComponentPaletteItem } from './ComponentPaletteItem';
|
|
4
|
+
import { getComponentsByCategory } from '../../config/componentRegistry';
|
|
5
|
+
export const ComponentPalette = () => {
|
|
6
|
+
const componentsByCategory = getComponentsByCategory();
|
|
7
|
+
return (_jsx(Box, { p: "sm", children: _jsx(Accordion, { defaultValue: ['Layout', 'Inputs', 'Typography'], multiple: true, children: Object.entries(componentsByCategory).map(([category, components]) => (_jsxs(Accordion.Item, { value: category, children: [_jsx(Accordion.Control, { children: _jsx(Text, { fw: 500, size: "sm", children: category }) }), _jsx(Accordion.Panel, { children: _jsx(Box, { style: { display: 'flex', flexDirection: 'column', gap: '0.5rem' }, children: components.map((component) => (_jsx(ComponentPaletteItem, { config: component }, component.type))) }) })] }, category))) }) }));
|
|
8
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useDraggable } from '@dnd-kit/core';
|
|
3
|
+
import { Box, Text } from '@mantine/core';
|
|
4
|
+
export const ComponentPaletteItem = ({ config }) => {
|
|
5
|
+
const { attributes, listeners, setNodeRef, transform, isDragging, } = useDraggable({
|
|
6
|
+
id: `palette-${config.type}`,
|
|
7
|
+
data: {
|
|
8
|
+
isFromPalette: true,
|
|
9
|
+
componentType: config.type,
|
|
10
|
+
config
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const style = transform ? {
|
|
14
|
+
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
|
15
|
+
opacity: isDragging ? 0.5 : 1,
|
|
16
|
+
zIndex: isDragging ? 1000 : 1,
|
|
17
|
+
} : undefined;
|
|
18
|
+
return (_jsxs(Box, { ref: setNodeRef, style: {
|
|
19
|
+
...style,
|
|
20
|
+
padding: '.75rem',
|
|
21
|
+
backgroundColor: '#f8f9fa',
|
|
22
|
+
borderRadius: '6px',
|
|
23
|
+
border: '1px solid #e9ecef',
|
|
24
|
+
cursor: 'grab',
|
|
25
|
+
userSelect: 'none',
|
|
26
|
+
transition: 'all 0.2s ease',
|
|
27
|
+
':hover': {
|
|
28
|
+
backgroundColor: '#e9ecef',
|
|
29
|
+
borderColor: '#dee2e6'
|
|
30
|
+
}
|
|
31
|
+
}, ...attributes, ...listeners, onMouseEnter: (e) => {
|
|
32
|
+
e.currentTarget.style.backgroundColor = '#e9ecef';
|
|
33
|
+
e.currentTarget.style.borderColor = '#dee2e6';
|
|
34
|
+
}, onMouseLeave: (e) => {
|
|
35
|
+
e.currentTarget.style.backgroundColor = '#f8f9fa';
|
|
36
|
+
e.currentTarget.style.borderColor = '#e9ecef';
|
|
37
|
+
}, children: [_jsx(Text, { size: "sm", fw: 500, children: config.displayName }), _jsx(Text, { size: "xs", c: "dimmed", mt: 2, children: getComponentDescription(config.type) })] }));
|
|
38
|
+
};
|
|
39
|
+
const getComponentDescription = (type) => {
|
|
40
|
+
const descriptions = {
|
|
41
|
+
Button: 'Interactive button element',
|
|
42
|
+
TextInput: 'Text input field',
|
|
43
|
+
Text: 'Text display element',
|
|
44
|
+
Title: 'Heading element',
|
|
45
|
+
Container: 'Layout container',
|
|
46
|
+
Group: 'Horizontal layout',
|
|
47
|
+
Stack: 'Vertical layout',
|
|
48
|
+
Card: 'Card container'
|
|
49
|
+
};
|
|
50
|
+
return descriptions[type] || 'Component';
|
|
51
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { DndContext } from '@dnd-kit/core';
|
|
4
|
+
import { Box, Group, Button, Alert, Text, Modal, Stack } from '@mantine/core';
|
|
5
|
+
import { Canvas } from './Canvas/Canvas';
|
|
6
|
+
import { ComponentPalette } from './ComponentPalette/ComponentPalette';
|
|
7
|
+
import { PropertyEditor } from './PropertyEditor/PropertyEditor';
|
|
8
|
+
import { CodeExporter } from './CodeExporter/CodeExporter';
|
|
9
|
+
import { useDragAndDrop } from '../hooks/useDragAndDrop';
|
|
10
|
+
import { useVisualBuilderStore } from '../store/visualBuilderStore';
|
|
11
|
+
import { parseAIGeneratedCode } from '../utils/aiParser';
|
|
12
|
+
export const EmbeddedVisualBuilder = ({ initialCode, height = '600px', showPalette = true, showProperties = true, onCodeExport, compact = false, storyMetadata }) => {
|
|
13
|
+
const { sensors, handleDragStart, handleDragOver, handleDragEnd, handleDragCancel } = useDragAndDrop();
|
|
14
|
+
const { components, clearCanvas, openCodeModal, loadFromCode, loadFromAI, importFromStoryUI, setCurrentStoryName } = useVisualBuilderStore();
|
|
15
|
+
const [loadError, setLoadError] = useState(null);
|
|
16
|
+
const [loadWarnings, setLoadWarnings] = useState([]);
|
|
17
|
+
const [showLoadDialog, setShowLoadDialog] = useState(false);
|
|
18
|
+
// Load initial code if provided
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (initialCode) {
|
|
21
|
+
handleLoadCode(initialCode);
|
|
22
|
+
}
|
|
23
|
+
}, [initialCode]);
|
|
24
|
+
const handleLoadCode = async (code) => {
|
|
25
|
+
setLoadError(null);
|
|
26
|
+
setLoadWarnings([]);
|
|
27
|
+
try {
|
|
28
|
+
// First try to parse as Story UI content
|
|
29
|
+
if (code.includes('render:') || code.includes('.stories.')) {
|
|
30
|
+
const storyResult = await importFromStoryUI(code);
|
|
31
|
+
if (storyResult.success) {
|
|
32
|
+
// Use story metadata if available and story name extraction failed
|
|
33
|
+
if (storyMetadata?.title && storyMetadata.isExisting) {
|
|
34
|
+
const { currentStoryName } = useVisualBuilderStore.getState();
|
|
35
|
+
if (currentStoryName === 'Imported Story') {
|
|
36
|
+
setCurrentStoryName(storyMetadata.title);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (storyResult.warnings.length > 0) {
|
|
40
|
+
setLoadWarnings(storyResult.warnings);
|
|
41
|
+
setShowLoadDialog(true);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// If Story UI parsing fails, fall back to AI parser
|
|
47
|
+
console.warn('Story UI parsing failed, falling back to AI parser:', storyResult.errors);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Fall back to AI generated code parser
|
|
51
|
+
const result = parseAIGeneratedCode(code);
|
|
52
|
+
if (result.errors.length > 0) {
|
|
53
|
+
setLoadError(result.errors.join(', '));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (result.warnings.length > 0) {
|
|
57
|
+
setLoadWarnings(result.warnings);
|
|
58
|
+
}
|
|
59
|
+
loadFromAI(result.components);
|
|
60
|
+
if (result.warnings.length > 0) {
|
|
61
|
+
setShowLoadDialog(true);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
setLoadError(error instanceof Error ? error.message : 'Failed to parse code');
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const handleExport = async () => {
|
|
69
|
+
if (onCodeExport && components.length > 0) {
|
|
70
|
+
try {
|
|
71
|
+
// Generate code and pass to callback
|
|
72
|
+
const { generateJSXCode } = await import('./CodeExporter/codeGenerator');
|
|
73
|
+
const code = generateJSXCode(components);
|
|
74
|
+
onCodeExport(code);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.error('Failed to generate code:', error);
|
|
78
|
+
openCodeModal();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
openCodeModal();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const paletteWidth = showPalette ? (compact ? 240 : 280) : 0;
|
|
86
|
+
const propertiesWidth = showProperties ? (compact ? 280 : 320) : 0;
|
|
87
|
+
return (_jsxs(_Fragment, { children: [_jsx(DndContext, { sensors: sensors, onDragStart: handleDragStart, onDragOver: handleDragOver, onDragEnd: handleDragEnd, onDragCancel: handleDragCancel, children: _jsxs(Box, { style: {
|
|
88
|
+
display: 'flex',
|
|
89
|
+
height,
|
|
90
|
+
backgroundColor: '#f8f9fa',
|
|
91
|
+
border: '1px solid #e9ecef',
|
|
92
|
+
borderRadius: compact ? '8px' : '12px',
|
|
93
|
+
overflow: 'hidden'
|
|
94
|
+
}, children: [showPalette && (_jsxs(Box, { style: {
|
|
95
|
+
width: paletteWidth,
|
|
96
|
+
backgroundColor: 'white',
|
|
97
|
+
borderRight: '1px solid #e9ecef',
|
|
98
|
+
display: 'flex',
|
|
99
|
+
flexDirection: 'column'
|
|
100
|
+
}, children: [_jsxs(Box, { p: compact ? 'sm' : 'md', style: { borderBottom: '1px solid #e9ecef' }, children: [_jsx(Group, { justify: "space-between", mb: "xs", children: _jsx(Text, { size: compact ? 'sm' : 'md', fw: 600, children: "Components" }) }), _jsxs(Group, { gap: "xs", children: [_jsx(Button, { size: "xs", variant: "outline", onClick: clearCanvas, children: "Clear" }), _jsx(Button, { size: "xs", variant: "filled", onClick: handleExport, children: "Export" })] })] }), _jsx(Box, { style: { flex: 1, overflow: 'auto' }, children: _jsx(ComponentPalette, {}) })] })), _jsxs(Box, { style: { flex: 1, display: 'flex', flexDirection: 'column' }, children: [_jsx(Box, { p: compact ? 'sm' : 'md', style: { borderBottom: '1px solid #e9ecef', backgroundColor: 'white' }, children: _jsxs(Group, { justify: "space-between", children: [_jsx(Text, { size: compact ? 'sm' : 'md', fw: 600, children: "Canvas" }), !showPalette && (_jsxs(Group, { gap: "xs", children: [_jsx(Button, { size: "xs", variant: "outline", onClick: clearCanvas, children: "Clear" }), _jsx(Button, { size: "xs", variant: "filled", onClick: handleExport, children: "Export" })] }))] }) }), loadError && (_jsx(Box, { p: "sm", children: _jsx(Alert, { color: "red", title: "Parse Error", children: loadError }) })), _jsx(Box, { style: { flex: 1, overflow: 'auto' }, children: _jsx(Canvas, {}) })] }), showProperties && (_jsxs(Box, { style: {
|
|
101
|
+
width: propertiesWidth,
|
|
102
|
+
backgroundColor: 'white',
|
|
103
|
+
borderLeft: '1px solid #e9ecef',
|
|
104
|
+
display: 'flex',
|
|
105
|
+
flexDirection: 'column'
|
|
106
|
+
}, children: [_jsx(Box, { p: compact ? 'sm' : 'md', style: { borderBottom: '1px solid #e9ecef' }, children: _jsx(Text, { size: compact ? 'sm' : 'md', fw: 600, children: "Properties" }) }), _jsx(Box, { style: { flex: 1, overflow: 'auto' }, children: _jsx(PropertyEditor, {}) })] })), _jsx(CodeExporter, {})] }) }), _jsx(Modal, { opened: showLoadDialog, onClose: () => setShowLoadDialog(false), title: "Code Loaded with Warnings", size: "md", children: _jsxs(Stack, { gap: "md", children: [_jsx(Text, { children: "The code was successfully loaded into the Visual Builder, but there were some warnings:" }), _jsx(Box, { p: "md", style: { backgroundColor: '#fff3cd', borderRadius: '4px' }, children: loadWarnings.map((warning, index) => (_jsxs(Text, { size: "sm", c: "orange.8", children: ["\u2022 ", warning] }, index))) }), _jsx(Text, { size: "sm", c: "dimmed", children: "These warnings don't prevent you from editing the component, but you may want to review them." }), _jsx(Group, { justify: "flex-end", children: _jsx(Button, { onClick: () => setShowLoadDialog(false), children: "Continue Editing" }) })] }) })] }));
|
|
107
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, Button, Group } from '@mantine/core';
|
|
3
|
+
import { PropertyForm } from './PropertyForm';
|
|
4
|
+
import { useVisualBuilderStore } from '../../store/visualBuilderStore';
|
|
5
|
+
export const PropertyEditor = () => {
|
|
6
|
+
const { selectedComponent, removeComponent } = useVisualBuilderStore();
|
|
7
|
+
if (!selectedComponent) {
|
|
8
|
+
return (_jsx(Box, { p: "sm", children: _jsx(Text, { c: "dimmed", ta: "center", mt: "xl", children: "Select a component to edit its properties" }) }));
|
|
9
|
+
}
|
|
10
|
+
const handleDelete = () => {
|
|
11
|
+
if (selectedComponent) {
|
|
12
|
+
removeComponent(selectedComponent.id);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
return (_jsxs(Box, { p: "sm", children: [_jsxs(Box, { mb: "lg", children: [_jsxs(Group, { justify: "space-between", align: "center", mb: "sm", children: [_jsx(Text, { fw: 600, size: "sm", children: selectedComponent.type }), _jsx(Button, { size: "xs", variant: "light", color: "red", onClick: handleDelete, children: "Delete" })] }), _jsxs(Text, { size: "xs", c: "dimmed", children: ["Component ID: ", selectedComponent.id] })] }), _jsx(PropertyForm, { componentId: selectedComponent.id, componentType: selectedComponent.type, currentProps: selectedComponent.props })] }));
|
|
16
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Box, TextInput, Select, Switch, Text, Divider, Accordion, Group, Badge } from '@mantine/core';
|
|
4
|
+
import { useVisualBuilderStore } from '../../store/visualBuilderStore';
|
|
5
|
+
import { getComponentConfig } from '../../config/componentRegistry';
|
|
6
|
+
import { useDebouncedCallback } from '@mantine/hooks';
|
|
7
|
+
import { SpacingControl } from './SpacingControl';
|
|
8
|
+
export const PropertyForm = ({ componentId, componentType, currentProps }) => {
|
|
9
|
+
const { updateComponent } = useVisualBuilderStore();
|
|
10
|
+
const config = getComponentConfig(componentType);
|
|
11
|
+
// Local state for inputs to prevent focus loss
|
|
12
|
+
const [localValues, setLocalValues] = useState({});
|
|
13
|
+
// Sync local values when currentProps changes
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
setLocalValues(currentProps);
|
|
16
|
+
}, [currentProps]);
|
|
17
|
+
if (!config) {
|
|
18
|
+
return (_jsx(Text, { c: "dimmed", ta: "center", children: "No properties available for this component" }));
|
|
19
|
+
}
|
|
20
|
+
// Debounced update to store for text inputs
|
|
21
|
+
const debouncedUpdate = useDebouncedCallback((propertyName, value) => {
|
|
22
|
+
updateComponent(componentId, {
|
|
23
|
+
props: {
|
|
24
|
+
...currentProps,
|
|
25
|
+
[propertyName]: value
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}, 300);
|
|
29
|
+
// Immediate update for non-text inputs
|
|
30
|
+
const handleImmediatePropertyChange = (propertyName, value) => {
|
|
31
|
+
const newProps = { ...currentProps, [propertyName]: value };
|
|
32
|
+
setLocalValues(newProps);
|
|
33
|
+
updateComponent(componentId, {
|
|
34
|
+
props: newProps
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
// Handle text input changes with debouncing
|
|
38
|
+
const handleTextPropertyChange = (propertyName, value) => {
|
|
39
|
+
const newProps = { ...currentProps, [propertyName]: value };
|
|
40
|
+
setLocalValues(newProps);
|
|
41
|
+
debouncedUpdate(propertyName, value);
|
|
42
|
+
};
|
|
43
|
+
// Handle blur events to ensure immediate update
|
|
44
|
+
const handleTextBlur = (propertyName, value) => {
|
|
45
|
+
updateComponent(componentId, {
|
|
46
|
+
props: {
|
|
47
|
+
...currentProps,
|
|
48
|
+
[propertyName]: value
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
// Group properties by category
|
|
53
|
+
const groupedProperties = config.properties.reduce((acc, property) => {
|
|
54
|
+
const category = property.category || 'general';
|
|
55
|
+
if (!acc[category]) {
|
|
56
|
+
acc[category] = [];
|
|
57
|
+
}
|
|
58
|
+
acc[category].push(property);
|
|
59
|
+
return acc;
|
|
60
|
+
}, {});
|
|
61
|
+
const renderPropertyInput = (property) => {
|
|
62
|
+
// Skip individual spacing properties as they'll be handled by SpacingControl
|
|
63
|
+
const spacingProps = ['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my', 'p', 'pt', 'pr', 'pb', 'pl', 'px', 'py'];
|
|
64
|
+
if (spacingProps.includes(property.name)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return (_jsxs(Box, { mb: "xs", children: [_jsxs(Group, { justify: "space-between", mb: "xs", children: [_jsx(Text, { size: "sm", fw: 500, children: property.name.charAt(0).toUpperCase() + property.name.slice(1) }), property.category && (_jsx(Badge, { size: "xs", variant: "light", color: "gray", children: property.category }))] }), property.description && (_jsx(Text, { size: "xs", c: "dimmed", mb: "xs", children: property.description })), property.type === 'string' && (_jsx(TextInput, { value: localValues[property.name] || '', onChange: (e) => handleTextPropertyChange(property.name, e.target.value), onBlur: (e) => handleTextBlur(property.name, e.target.value), placeholder: `Enter ${property.name}...`, size: "sm" })), property.type === 'number' && (_jsx(TextInput, { type: "number", value: localValues[property.name] || 0, onChange: (e) => handleTextPropertyChange(property.name, Number(e.target.value)), onBlur: (e) => handleTextBlur(property.name, Number(e.target.value)), placeholder: `Enter ${property.name}...`, size: "sm" })), property.type === 'boolean' && (_jsx(Switch, { checked: Boolean(localValues[property.name]), onChange: (e) => handleImmediatePropertyChange(property.name, e.target.checked), label: property.description || `Enable ${property.name}`, size: "sm" })), property.type === 'select' && property.options && (_jsx(Select, { value: String(localValues[property.name] !== undefined ? localValues[property.name] : property.defaultValue), onChange: (value) => {
|
|
68
|
+
// Convert back to number if needed
|
|
69
|
+
const finalValue = property.name === 'order' && value ? Number(value) : value;
|
|
70
|
+
handleImmediatePropertyChange(property.name, finalValue);
|
|
71
|
+
}, data: property.options.map(option => ({
|
|
72
|
+
value: String(option),
|
|
73
|
+
label: String(option)
|
|
74
|
+
})), placeholder: `Select ${property.name}...`, size: "sm", clearable: true, allowDeselect: true })), property.type === 'color' && (_jsx(TextInput, { value: localValues[property.name] || '', onChange: (e) => handleTextPropertyChange(property.name, e.target.value), onBlur: (e) => handleTextBlur(property.name, e.target.value), placeholder: "Enter color (hex, rgb, or name)...", size: "sm" }))] }, property.name));
|
|
75
|
+
};
|
|
76
|
+
const categoryOrder = ['content', 'appearance', 'spacing', 'behavior'];
|
|
77
|
+
const orderedCategories = categoryOrder.filter(cat => groupedProperties[cat]);
|
|
78
|
+
const remainingCategories = Object.keys(groupedProperties).filter(cat => !categoryOrder.includes(cat));
|
|
79
|
+
const allCategories = [...orderedCategories, ...remainingCategories];
|
|
80
|
+
return (_jsx(Box, { children: _jsx(Accordion, { multiple: true, defaultValue: ['content', 'appearance', 'spacing'], children: allCategories.map((category) => (_jsxs(Accordion.Item, { value: category, children: [_jsx(Accordion.Control, { children: _jsxs(Group, { justify: "space-between", children: [_jsx(Text, { fw: 600, tt: "capitalize", children: category }), _jsx(Badge, { size: "xs", variant: "light", children: groupedProperties[category].length })] }) }), _jsx(Accordion.Panel, { children: category === 'spacing' ? (_jsx(SpacingControl, { values: localValues, onChange: handleImmediatePropertyChange })) : (groupedProperties[category]
|
|
81
|
+
.map((property, propertyIndex) => {
|
|
82
|
+
const renderedInput = renderPropertyInput(property);
|
|
83
|
+
if (!renderedInput)
|
|
84
|
+
return null;
|
|
85
|
+
return (_jsxs(Box, { children: [renderedInput, propertyIndex < groupedProperties[category].length - 1 && (_jsx(Divider, { mb: "xs" }))] }, property.name));
|
|
86
|
+
})
|
|
87
|
+
.filter(Boolean)) })] }, category))) }) }));
|
|
88
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Group, Text, ActionIcon, NumberInput, Select, Stack, Paper, Tooltip, Switch } from '@mantine/core';
|
|
4
|
+
const SPACING_OPTIONS = ['0', 'xs', 'sm', 'md', 'lg', 'xl', 'auto'];
|
|
5
|
+
export const SpacingControl = ({ values, onChange }) => {
|
|
6
|
+
const [marginLocked, setMarginLocked] = useState(false);
|
|
7
|
+
const [paddingLocked, setPaddingLocked] = useState(false);
|
|
8
|
+
const [marginXLocked, setMarginXLocked] = useState(false);
|
|
9
|
+
const [marginYLocked, setMarginYLocked] = useState(false);
|
|
10
|
+
const [paddingXLocked, setPaddingXLocked] = useState(false);
|
|
11
|
+
const [paddingYLocked, setPaddingYLocked] = useState(false);
|
|
12
|
+
const [useNumbers, setUseNumbers] = useState(false);
|
|
13
|
+
const handleChange = (property, value) => {
|
|
14
|
+
const finalValue = value === null || value === '' ? undefined : value;
|
|
15
|
+
onChange(property, finalValue);
|
|
16
|
+
// Handle locked states
|
|
17
|
+
if (marginLocked && property.startsWith('m') && !property.includes('x') && !property.includes('y')) {
|
|
18
|
+
const props = ['mt', 'mr', 'mb', 'ml'];
|
|
19
|
+
props.forEach(prop => {
|
|
20
|
+
if (prop !== property)
|
|
21
|
+
onChange(prop, finalValue);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (paddingLocked && property.startsWith('p') && !property.includes('x') && !property.includes('y')) {
|
|
25
|
+
const props = ['pt', 'pr', 'pb', 'pl'];
|
|
26
|
+
props.forEach(prop => {
|
|
27
|
+
if (prop !== property)
|
|
28
|
+
onChange(prop, finalValue);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// Handle axis-specific locks
|
|
32
|
+
if (marginXLocked && (property === 'ml' || property === 'mr')) {
|
|
33
|
+
if (property === 'ml')
|
|
34
|
+
onChange('mr', finalValue);
|
|
35
|
+
if (property === 'mr')
|
|
36
|
+
onChange('ml', finalValue);
|
|
37
|
+
}
|
|
38
|
+
if (marginYLocked && (property === 'mt' || property === 'mb')) {
|
|
39
|
+
if (property === 'mt')
|
|
40
|
+
onChange('mb', finalValue);
|
|
41
|
+
if (property === 'mb')
|
|
42
|
+
onChange('mt', finalValue);
|
|
43
|
+
}
|
|
44
|
+
if (paddingXLocked && (property === 'pl' || property === 'pr')) {
|
|
45
|
+
if (property === 'pl')
|
|
46
|
+
onChange('pr', finalValue);
|
|
47
|
+
if (property === 'pr')
|
|
48
|
+
onChange('pl', finalValue);
|
|
49
|
+
}
|
|
50
|
+
if (paddingYLocked && (property === 'pt' || property === 'pb')) {
|
|
51
|
+
if (property === 'pt')
|
|
52
|
+
onChange('pb', finalValue);
|
|
53
|
+
if (property === 'pb')
|
|
54
|
+
onChange('pt', finalValue);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const renderSpacingInput = (property, placeholder) => {
|
|
58
|
+
const value = values[property];
|
|
59
|
+
if (useNumbers) {
|
|
60
|
+
return (_jsxs(Group, { gap: 2, children: [_jsx(NumberInput, { value: typeof value === 'number' ? value : undefined, onChange: (val) => handleChange(property, val), placeholder: placeholder, size: "xs", w: 50, min: 0, hideControls: true }), _jsx(ActionIcon, { size: "xs", variant: "light", onClick: () => {
|
|
61
|
+
const currentVal = typeof value === 'number' ? value : 0;
|
|
62
|
+
handleChange(property, currentVal + 4);
|
|
63
|
+
}, children: "+" }), _jsx(ActionIcon, { size: "xs", variant: "light", onClick: () => {
|
|
64
|
+
const currentVal = typeof value === 'number' ? value : 0;
|
|
65
|
+
handleChange(property, Math.max(0, currentVal - 4));
|
|
66
|
+
}, children: "-" })] }));
|
|
67
|
+
}
|
|
68
|
+
return (_jsx(Select, { value: value ? String(value) : null, onChange: (val) => handleChange(property, val), data: SPACING_OPTIONS, placeholder: placeholder, size: "xs", w: 75, clearable: true, allowDeselect: true, styles: {
|
|
69
|
+
dropdown: { zIndex: 1000 }
|
|
70
|
+
} }));
|
|
71
|
+
};
|
|
72
|
+
return (_jsxs(Stack, { gap: "xs", children: [_jsxs(Group, { justify: "space-between", gap: "xs", children: [_jsx(Text, { size: "xs", fw: 500, children: "Spacing" }), _jsx(Switch, { label: "Numbers", size: "xs", checked: useNumbers, onChange: (event) => setUseNumbers(event.currentTarget.checked) })] }), _jsxs(Paper, { p: 4, withBorder: true, children: [_jsxs(Group, { justify: "space-between", mb: 4, gap: "xs", children: [_jsx(Text, { size: "xs", fw: 500, c: "blue", children: "Margin" }), _jsxs(Group, { gap: 2, children: [_jsx(Tooltip, { label: "Lock X-axis (left & right)", children: _jsx(ActionIcon, { size: "xs", variant: marginXLocked ? "filled" : "light", color: "blue", onClick: () => setMarginXLocked(!marginXLocked), children: marginXLocked ? '🔒' : '🔓' }) }), _jsx(Tooltip, { label: "Lock Y-axis (top & bottom)", children: _jsx(ActionIcon, { size: "xs", variant: marginYLocked ? "filled" : "light", color: "blue", onClick: () => setMarginYLocked(!marginYLocked), children: marginYLocked ? '🔒' : '🔓' }) }), _jsx(Tooltip, { label: "Lock all sides", children: _jsx(ActionIcon, { size: "xs", variant: marginLocked ? "filled" : "light", color: "blue", onClick: () => setMarginLocked(!marginLocked), children: marginLocked ? '🔒' : '🔓' }) })] })] }), _jsxs(Box, { style: {
|
|
73
|
+
position: 'relative',
|
|
74
|
+
border: '1px dashed #228be6',
|
|
75
|
+
borderRadius: '4px',
|
|
76
|
+
padding: '25px',
|
|
77
|
+
minHeight: '140px'
|
|
78
|
+
}, children: [_jsx(Box, { style: {
|
|
79
|
+
position: 'absolute',
|
|
80
|
+
top: '-8px',
|
|
81
|
+
left: '50%',
|
|
82
|
+
transform: 'translateX(-50%)',
|
|
83
|
+
zIndex: 2
|
|
84
|
+
}, children: renderSpacingInput('mt', 'top') }), _jsx(Box, { style: {
|
|
85
|
+
position: 'absolute',
|
|
86
|
+
right: '-20px',
|
|
87
|
+
top: '50%',
|
|
88
|
+
transform: 'translateY(-50%)',
|
|
89
|
+
zIndex: 2
|
|
90
|
+
}, children: renderSpacingInput('mr', 'right') }), _jsx(Box, { style: {
|
|
91
|
+
position: 'absolute',
|
|
92
|
+
bottom: '-4px',
|
|
93
|
+
left: '50%',
|
|
94
|
+
transform: 'translateX(-50%)',
|
|
95
|
+
zIndex: 2
|
|
96
|
+
}, children: renderSpacingInput('mb', 'bottom') }), _jsx(Box, { style: {
|
|
97
|
+
position: 'absolute',
|
|
98
|
+
left: '-20px',
|
|
99
|
+
top: '50%',
|
|
100
|
+
transform: 'translateY(-50%)',
|
|
101
|
+
zIndex: 2
|
|
102
|
+
}, children: renderSpacingInput('ml', 'left') }), _jsxs(Box, { style: {
|
|
103
|
+
position: 'absolute',
|
|
104
|
+
top: '26%',
|
|
105
|
+
left: '50%',
|
|
106
|
+
transform: 'translateX(-50%)',
|
|
107
|
+
textAlign: 'center'
|
|
108
|
+
}, children: [_jsx(Text, { size: "xs", c: "dimmed", mb: 2, children: "All" }), renderSpacingInput('m', 'all')] })] }), _jsxs(Group, { justify: "center", mt: 10, gap: "xs", children: [_jsxs(Box, { ta: "center", children: [_jsx(Text, { size: "xs", c: "dimmed", children: "X" }), renderSpacingInput('mx', 'x')] }), _jsxs(Box, { ta: "center", children: [_jsx(Text, { size: "xs", c: "dimmed", children: "Y" }), renderSpacingInput('my', 'y')] })] })] }), _jsxs(Paper, { p: 4, withBorder: true, children: [_jsxs(Group, { justify: "space-between", mb: 4, gap: "xs", children: [_jsx(Text, { size: "xs", fw: 500, c: "green", children: "Padding" }), _jsxs(Group, { gap: 2, children: [_jsx(Tooltip, { label: "Lock X-axis (left & right)", children: _jsx(ActionIcon, { size: "xs", variant: paddingXLocked ? "filled" : "light", color: "green", onClick: () => setPaddingXLocked(!paddingXLocked), children: paddingXLocked ? '🔒' : '🔓' }) }), _jsx(Tooltip, { label: "Lock Y-axis (top & bottom)", children: _jsx(ActionIcon, { size: "xs", variant: paddingYLocked ? "filled" : "light", color: "green", onClick: () => setPaddingYLocked(!paddingYLocked), children: paddingYLocked ? '🔒' : '🔓' }) }), _jsx(Tooltip, { label: "Lock all sides", children: _jsx(ActionIcon, { size: "xs", variant: paddingLocked ? "filled" : "light", color: "green", onClick: () => setPaddingLocked(!paddingLocked), children: paddingLocked ? '🔒' : '🔓' }) })] })] }), _jsxs(Box, { style: {
|
|
109
|
+
position: 'relative',
|
|
110
|
+
border: '1px dashed #40c057',
|
|
111
|
+
borderRadius: '4px',
|
|
112
|
+
padding: '25px',
|
|
113
|
+
minHeight: '140px'
|
|
114
|
+
}, children: [_jsx(Box, { style: {
|
|
115
|
+
position: 'absolute',
|
|
116
|
+
top: '-8px',
|
|
117
|
+
left: '50%',
|
|
118
|
+
transform: 'translateX(-50%)',
|
|
119
|
+
zIndex: 2
|
|
120
|
+
}, children: renderSpacingInput('pt', 'top') }), _jsx(Box, { style: {
|
|
121
|
+
position: 'absolute',
|
|
122
|
+
right: '-20px',
|
|
123
|
+
top: '50%',
|
|
124
|
+
transform: 'translateY(-50%)',
|
|
125
|
+
zIndex: 2
|
|
126
|
+
}, children: renderSpacingInput('pr', 'right') }), _jsx(Box, { style: {
|
|
127
|
+
position: 'absolute',
|
|
128
|
+
bottom: '-4px',
|
|
129
|
+
left: '50%',
|
|
130
|
+
transform: 'translateX(-50%)',
|
|
131
|
+
zIndex: 2
|
|
132
|
+
}, children: renderSpacingInput('pb', 'bottom') }), _jsx(Box, { style: {
|
|
133
|
+
position: 'absolute',
|
|
134
|
+
left: '-20px',
|
|
135
|
+
top: '50%',
|
|
136
|
+
transform: 'translateY(-50%)',
|
|
137
|
+
zIndex: 2
|
|
138
|
+
}, children: renderSpacingInput('pl', 'left') }), _jsxs(Box, { style: {
|
|
139
|
+
position: 'absolute',
|
|
140
|
+
top: '26%',
|
|
141
|
+
left: '50%',
|
|
142
|
+
transform: 'translateX(-50%)',
|
|
143
|
+
textAlign: 'center'
|
|
144
|
+
}, children: [_jsx(Text, { size: "xs", c: "dimmed", mb: 2, children: "All" }), renderSpacingInput('p', 'all')] })] }), _jsxs(Group, { justify: "center", mt: 10, gap: "xs", children: [_jsxs(Box, { ta: "center", children: [_jsx(Text, { size: "xs", c: "dimmed", children: "X" }), renderSpacingInput('px', 'x')] }), _jsxs(Box, { ta: "center", children: [_jsx(Text, { size: "xs", c: "dimmed", children: "Y" }), renderSpacingInput('py', 'y')] })] })] })] }));
|
|
145
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, NumberInput, SegmentedControl, Switch, Group, Stack, Paper } from '@mantine/core';
|
|
4
|
+
export const SpacingEditor = ({ type, values = {}, onChange }) => {
|
|
5
|
+
const [unit, setUnit] = useState('px');
|
|
6
|
+
const [useUniform, setUseUniform] = useState(true);
|
|
7
|
+
const handleValueChange = (side, value) => {
|
|
8
|
+
if (useUniform && side === 'all') {
|
|
9
|
+
onChange({
|
|
10
|
+
top: value,
|
|
11
|
+
right: value,
|
|
12
|
+
bottom: value,
|
|
13
|
+
left: value,
|
|
14
|
+
all: value
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
onChange({
|
|
19
|
+
...values,
|
|
20
|
+
[side]: value
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const currentValue = useUniform
|
|
25
|
+
? values.all || values.top || 0
|
|
26
|
+
: null;
|
|
27
|
+
return (_jsx(Paper, { p: "xs", withBorder: true, children: _jsxs(Stack, { gap: "xs", children: [_jsxs(Group, { justify: "space-between", children: [_jsx(Text, { size: "sm", fw: 500, c: type === 'margin' ? 'blue.6' : 'green.6', children: type.charAt(0).toUpperCase() + type.slice(1) }), _jsx(SegmentedControl, { size: "xs", value: unit, onChange: (value) => setUnit(value), data: [
|
|
28
|
+
{ label: 'px', value: 'px' },
|
|
29
|
+
{ label: 'rem', value: 'rem' },
|
|
30
|
+
{ label: '%', value: '%' }
|
|
31
|
+
] })] }), _jsx(Switch, { size: "xs", label: "Uniform spacing", checked: useUniform, onChange: (e) => setUseUniform(e.currentTarget.checked) }), useUniform ? (_jsx(NumberInput, { size: "xs", label: "All sides", value: currentValue, onChange: (value) => handleValueChange('all', value), suffix: unit, min: 0 })) : (_jsxs(Box, { children: [_jsxs(Group, { gap: "xs", mb: "xs", children: [_jsx(NumberInput, { size: "xs", label: "Top", value: values.top || 0, onChange: (value) => handleValueChange('top', value), suffix: unit, min: 0, style: { flex: 1 } }), _jsx(NumberInput, { size: "xs", label: "Right", value: values.right || 0, onChange: (value) => handleValueChange('right', value), suffix: unit, min: 0, style: { flex: 1 } })] }), _jsxs(Group, { gap: "xs", children: [_jsx(NumberInput, { size: "xs", label: "Bottom", value: values.bottom || 0, onChange: (value) => handleValueChange('bottom', value), suffix: unit, min: 0, style: { flex: 1 } }), _jsx(NumberInput, { size: "xs", label: "Left", value: values.left || 0, onChange: (value) => handleValueChange('left', value), suffix: unit, min: 0, style: { flex: 1 } })] })] }))] }) }));
|
|
32
|
+
};
|