@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,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a complete story file content from components
|
|
3
|
+
*/
|
|
4
|
+
export function generateStoryFileContent(components, storyName, fileName) {
|
|
5
|
+
// Generate the JSX code for the render function
|
|
6
|
+
const jsxCode = generateComponentJSX(components);
|
|
7
|
+
const imports = generateImports(components);
|
|
8
|
+
// Extract the story title from the name, removing any existing prefix
|
|
9
|
+
const baseTitle = storyName
|
|
10
|
+
.replace(/^(Generated|Edited)\//i, '') // Remove existing prefix
|
|
11
|
+
.replace(/([A-Z])/g, ' $1')
|
|
12
|
+
.replace(/^\s+/, '')
|
|
13
|
+
.trim();
|
|
14
|
+
// Use "Edited" prefix for stories that have been edited in Visual Builder
|
|
15
|
+
// Properly escape apostrophes and quotes in the title for JavaScript strings
|
|
16
|
+
const storyTitle = baseTitle.replace(/'/g, "\\'").replace(/"/g, '\\"');
|
|
17
|
+
const storyPrefix = 'Edited'; // Changed from 'Generated' to distinguish edited stories
|
|
18
|
+
// Always use the standard decorator path
|
|
19
|
+
const decoratorPath = '../decorators/VisualBuilderDecorator';
|
|
20
|
+
const content = `import React from 'react';
|
|
21
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
22
|
+
${imports}
|
|
23
|
+
import { withVisualBuilderButton } from '${decoratorPath}';
|
|
24
|
+
|
|
25
|
+
const meta = {
|
|
26
|
+
title: '${storyPrefix}/${storyTitle}',
|
|
27
|
+
parameters: {
|
|
28
|
+
layout: 'centered',
|
|
29
|
+
visualBuilder: true,
|
|
30
|
+
fileName: '${fileName}',
|
|
31
|
+
isEdited: true,
|
|
32
|
+
},
|
|
33
|
+
decorators: [withVisualBuilderButton],
|
|
34
|
+
} satisfies Meta;
|
|
35
|
+
|
|
36
|
+
export default meta;
|
|
37
|
+
type Story = StoryObj<typeof meta>;
|
|
38
|
+
|
|
39
|
+
export const Default: Story = {
|
|
40
|
+
render: () => (
|
|
41
|
+
${jsxCode.split('\n').map(line => ' ' + line).join('\n')}
|
|
42
|
+
)
|
|
43
|
+
};`;
|
|
44
|
+
// Fix and validate the generated content to ensure correct style syntax
|
|
45
|
+
const fixedContent = validateGeneratedContent(content);
|
|
46
|
+
return fixedContent;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate imports for the components
|
|
50
|
+
*/
|
|
51
|
+
function generateImports(components) {
|
|
52
|
+
const usedComponents = new Set();
|
|
53
|
+
const collectComponents = (comps) => {
|
|
54
|
+
comps.forEach(comp => {
|
|
55
|
+
// Map CardSection back to Card for imports
|
|
56
|
+
if (comp.type === 'CardSection') {
|
|
57
|
+
usedComponents.add('Card');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
usedComponents.add(comp.type);
|
|
61
|
+
}
|
|
62
|
+
if (comp.children) {
|
|
63
|
+
collectComponents(comp.children);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
collectComponents(components);
|
|
68
|
+
const sortedComponents = Array.from(usedComponents).sort();
|
|
69
|
+
return `import { ${sortedComponents.join(', ')} } from '@mantine/core';`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generate JSX code for components
|
|
73
|
+
*/
|
|
74
|
+
function generateComponentJSX(components, indent = 0) {
|
|
75
|
+
const indentStr = ' '.repeat(indent);
|
|
76
|
+
return components.map(component => {
|
|
77
|
+
const { type, props, children } = component;
|
|
78
|
+
const hasChildren = children && children.length > 0;
|
|
79
|
+
const hasTextContent = props.children && typeof props.children === 'string';
|
|
80
|
+
// Map CardSection to Card.Section
|
|
81
|
+
const componentName = type === 'CardSection' ? 'Card.Section' : type;
|
|
82
|
+
// Generate props string
|
|
83
|
+
const propsString = generatePropsString(props, type);
|
|
84
|
+
if (hasChildren) {
|
|
85
|
+
// Component with children
|
|
86
|
+
return `${indentStr}<${componentName}${propsString}>
|
|
87
|
+
${generateComponentJSX(children, indent + 1)}
|
|
88
|
+
${indentStr}</${componentName}>`;
|
|
89
|
+
}
|
|
90
|
+
else if (hasTextContent) {
|
|
91
|
+
// Component with text content
|
|
92
|
+
const textContent = props.children;
|
|
93
|
+
// For multi-line text, preserve line breaks and handle indentation properly
|
|
94
|
+
if (textContent.includes('\n')) {
|
|
95
|
+
const lines = textContent.split('\n');
|
|
96
|
+
const indentedLines = lines.map((line, index) => {
|
|
97
|
+
if (index === 0 && line.trim() === '')
|
|
98
|
+
return '';
|
|
99
|
+
return line.trim() === '' ? '' : `${indentStr} ${line.trim()}`;
|
|
100
|
+
}).filter((line, index, arr) => {
|
|
101
|
+
// Remove empty lines at the start and end
|
|
102
|
+
if (index === 0 || index === arr.length - 1) {
|
|
103
|
+
return line.trim() !== '';
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
});
|
|
107
|
+
return `${indentStr}<${componentName}${propsString}>\n${indentedLines.join('\n')}\n${indentStr}</${componentName}>`;
|
|
108
|
+
}
|
|
109
|
+
// Single line text - check if it should be on the same line
|
|
110
|
+
else if (textContent.length < 50) {
|
|
111
|
+
return `${indentStr}<${componentName}${propsString}>${textContent}</${componentName}>`;
|
|
112
|
+
}
|
|
113
|
+
return `${indentStr}<${componentName}${propsString}>\n${indentStr} ${textContent}\n${indentStr}</${componentName}>`;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// Self-closing component
|
|
117
|
+
return `${indentStr}<${componentName}${propsString} />`;
|
|
118
|
+
}
|
|
119
|
+
}).join('\n');
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Generate props string for a component
|
|
123
|
+
*/
|
|
124
|
+
export function generatePropsString(props, componentType) {
|
|
125
|
+
const propEntries = Object.entries(props);
|
|
126
|
+
// Filter out children prop for components that handle text content between tags
|
|
127
|
+
const filteredProps = propEntries.filter(([key, value]) => {
|
|
128
|
+
if (key === 'children') {
|
|
129
|
+
// Never include children as a prop for Text components - they use content between tags
|
|
130
|
+
if (componentType === 'Text' || componentType === 'Title') {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
// Keep children prop only for other text-based components that use it as a prop
|
|
134
|
+
return ['Button', 'Badge', 'Code', 'Mark', 'Anchor'].includes(componentType) &&
|
|
135
|
+
typeof value === 'string';
|
|
136
|
+
}
|
|
137
|
+
// IMPORTANT: Skip problematic style props that are strings
|
|
138
|
+
// These cause repeated JSX syntax errors and aren't essential
|
|
139
|
+
if (key === 'style' && typeof value === 'string') {
|
|
140
|
+
console.warn('Skipping string style prop to prevent JSX syntax errors:', value);
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
// Filter out undefined, null, empty string
|
|
144
|
+
if (value === undefined || value === null || value === '')
|
|
145
|
+
return false;
|
|
146
|
+
// Filter out default values for specific props
|
|
147
|
+
if (key === 'size' && value === 'sm')
|
|
148
|
+
return false;
|
|
149
|
+
if (key === 'variant' && value === 'filled')
|
|
150
|
+
return false;
|
|
151
|
+
return true;
|
|
152
|
+
});
|
|
153
|
+
if (filteredProps.length === 0)
|
|
154
|
+
return '';
|
|
155
|
+
const propsString = filteredProps
|
|
156
|
+
.map(([key, value]) => {
|
|
157
|
+
// Handle special cases
|
|
158
|
+
if (key === 'style') {
|
|
159
|
+
// Check if value is already a string (incorrectly formatted)
|
|
160
|
+
if (typeof value === 'string') {
|
|
161
|
+
console.warn('Style prop received as string:', value);
|
|
162
|
+
// Try to parse it if it looks like an object string
|
|
163
|
+
if (value.startsWith('{') && value.endsWith('}')) {
|
|
164
|
+
try {
|
|
165
|
+
// Remove outer braces and parse
|
|
166
|
+
const styleStr = value.slice(1, -1).trim();
|
|
167
|
+
const stylePairs = styleStr.split(',').map(pair => {
|
|
168
|
+
const [k, v] = pair.split(':').map(s => s.trim());
|
|
169
|
+
// Keep numeric values as numbers, quote strings
|
|
170
|
+
let cssValue = v;
|
|
171
|
+
if (v && !v.includes("'") && !v.includes('"')) {
|
|
172
|
+
// Check if it's a number
|
|
173
|
+
if (/^\d+$/.test(v)) {
|
|
174
|
+
cssValue = v; // Keep as numeric string for now
|
|
175
|
+
}
|
|
176
|
+
else if (/^\d*\.\d+$/.test(v)) {
|
|
177
|
+
cssValue = v; // Keep as numeric string for now
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
cssValue = `'${v}'`; // Quote non-numeric strings
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return `${k}: ${cssValue}`;
|
|
184
|
+
}).join(', ');
|
|
185
|
+
// Return properly formatted JSX style prop
|
|
186
|
+
return `style={{ ${stylePairs} }}`;
|
|
187
|
+
}
|
|
188
|
+
catch (e) {
|
|
189
|
+
console.error('Failed to parse style string:', e);
|
|
190
|
+
// Fallback: clean up the string and wrap properly
|
|
191
|
+
const cleanStyle = value.replace(/[{}]/g, '').trim();
|
|
192
|
+
return `style={{ ${cleanStyle} }}`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// If it doesn't look like an object, try to clean it up
|
|
196
|
+
const cleanStyle = value.replace(/[{}]/g, '').trim();
|
|
197
|
+
return `style={{ ${cleanStyle} }}`;
|
|
198
|
+
}
|
|
199
|
+
else if (typeof value === 'object') {
|
|
200
|
+
const styleEntries = Object.entries(value)
|
|
201
|
+
.map(([k, v]) => {
|
|
202
|
+
// Convert camelCase to proper CSS property names if needed
|
|
203
|
+
const cssKey = k;
|
|
204
|
+
const cssValue = typeof v === 'string' ? `'${v}'` : v;
|
|
205
|
+
return `${cssKey}: ${cssValue}`;
|
|
206
|
+
})
|
|
207
|
+
.join(', ');
|
|
208
|
+
return `style={{ ${styleEntries} }}`;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (typeof value === 'boolean') {
|
|
212
|
+
return value ? key : `${key}={false}`;
|
|
213
|
+
}
|
|
214
|
+
else if (typeof value === 'string') {
|
|
215
|
+
// Special check: if key is 'style' and value looks like an object string, handle it
|
|
216
|
+
if (key === 'style' && (value.includes('{') || value.includes(':'))) {
|
|
217
|
+
console.warn('Style prop detected as string in fallback:', value);
|
|
218
|
+
// Try to clean it up
|
|
219
|
+
const cleanStyle = value.replace(/^["']|["']$/g, '').replace(/[{}]/g, '').trim();
|
|
220
|
+
return `style={{ ${cleanStyle} }}`;
|
|
221
|
+
}
|
|
222
|
+
return `${key}="${value}"`;
|
|
223
|
+
}
|
|
224
|
+
else if (typeof value === 'number') {
|
|
225
|
+
return `${key}={${value}}`;
|
|
226
|
+
}
|
|
227
|
+
else if (Array.isArray(value)) {
|
|
228
|
+
return `${key}={${JSON.stringify(value)}}`;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
// Check if this is a style object that wasn't caught earlier
|
|
232
|
+
if (key === 'style' && typeof value === 'object') {
|
|
233
|
+
console.warn('Style object detected in fallback:', value);
|
|
234
|
+
const styleEntries = Object.entries(value)
|
|
235
|
+
.map(([k, v]) => {
|
|
236
|
+
const cssValue = typeof v === 'string' ? `'${v}'` : v;
|
|
237
|
+
return `${k}: ${cssValue}`;
|
|
238
|
+
})
|
|
239
|
+
.join(', ');
|
|
240
|
+
return `style={{ ${styleEntries} }}`;
|
|
241
|
+
}
|
|
242
|
+
return `${key}={${JSON.stringify(value)}}`;
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
.join(' ');
|
|
246
|
+
return propsString ? ` ${propsString}` : '';
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Update story file via Story UI MCP server
|
|
250
|
+
*/
|
|
251
|
+
export async function updateStoryFile(filePath, components, storyName) {
|
|
252
|
+
try {
|
|
253
|
+
// Extract fileName from filePath - let the MCP server handle file naming logic
|
|
254
|
+
let fileName = filePath.split('/').pop() || filePath;
|
|
255
|
+
// Remove file extension if present - MCP server will add it back
|
|
256
|
+
fileName = fileName.replace(/\.stories\.(tsx?|jsx?)$/, '');
|
|
257
|
+
// Don't apply any prefix transformations here - let the MCP server handle it
|
|
258
|
+
// The MCP server has the smart logic to detect existing files and update them properly
|
|
259
|
+
// Determine the API port from environment or default
|
|
260
|
+
const apiPort = window.STORY_UI_MCP_PORT ||
|
|
261
|
+
window.__STORY_UI_PORT__ ||
|
|
262
|
+
'4001';
|
|
263
|
+
// Call the Story UI server to update the file
|
|
264
|
+
const response = await fetch(`http://localhost:${apiPort}/story-ui/visual-builder/update`, {
|
|
265
|
+
method: 'POST',
|
|
266
|
+
headers: {
|
|
267
|
+
'Content-Type': 'application/json',
|
|
268
|
+
},
|
|
269
|
+
body: JSON.stringify({
|
|
270
|
+
fileName,
|
|
271
|
+
filePath,
|
|
272
|
+
components,
|
|
273
|
+
storyName,
|
|
274
|
+
isEdited: true, // Flag to indicate this is an edited story
|
|
275
|
+
createBackup: false // Never create backups from Visual Builder
|
|
276
|
+
})
|
|
277
|
+
});
|
|
278
|
+
const result = await response.json();
|
|
279
|
+
if (result.success) {
|
|
280
|
+
console.log(`✅ Story file updated via MCP server: ${result.fileName}`);
|
|
281
|
+
return {
|
|
282
|
+
success: true,
|
|
283
|
+
message: result.message || 'Story updated successfully'
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
console.error('Failed to update story file:', result.error);
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
error: result.error || 'Unknown error'
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
console.error('Failed to connect to Story UI server:', error);
|
|
296
|
+
// Fallback to localStorage if server is not available
|
|
297
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
298
|
+
const newContent = generateStoryFileContent(components, storyName, fileName);
|
|
299
|
+
const updateKey = `story-update-${filePath.replace(/[^a-zA-Z0-9]/g, '-')}`;
|
|
300
|
+
localStorage.setItem(updateKey, newContent);
|
|
301
|
+
console.warn('⚠️ Server unavailable, saved to localStorage as fallback');
|
|
302
|
+
return {
|
|
303
|
+
success: false,
|
|
304
|
+
error: 'Story UI server not available. Changes saved locally.'
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Fix and validate generated content to ensure correct style syntax
|
|
310
|
+
*/
|
|
311
|
+
function validateGeneratedContent(content) {
|
|
312
|
+
// Check for incorrect style syntax: style="{ ... }" and fix it
|
|
313
|
+
const incorrectStylePattern = /style="(\{[^}]*\})"/g;
|
|
314
|
+
let fixedContent = content;
|
|
315
|
+
let matchFound = false;
|
|
316
|
+
fixedContent = content.replace(incorrectStylePattern, (match, styleContent) => {
|
|
317
|
+
matchFound = true;
|
|
318
|
+
console.warn(`⚠️ Fixing style syntax: ${match} → style={${styleContent}}`);
|
|
319
|
+
// Convert style="{ ... }" to style={{ ... }}
|
|
320
|
+
return `style={${styleContent}}`;
|
|
321
|
+
});
|
|
322
|
+
if (matchFound) {
|
|
323
|
+
console.log('✅ Automatically fixed style syntax issues in generated content');
|
|
324
|
+
}
|
|
325
|
+
return fixedContent;
|
|
326
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test cases for enhanced story name extraction
|
|
3
|
+
* This verifies that the Visual Builder properly extracts story names
|
|
4
|
+
* from various story formats and never prompts when editing existing stories.
|
|
5
|
+
*/
|
|
6
|
+
import { extractStoryName } from './storyToBuilder';
|
|
7
|
+
describe('Enhanced Story Name Extraction', () => {
|
|
8
|
+
test('extracts name from export const statement', () => {
|
|
9
|
+
const storyCode = `
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { Button, Card } from '@mantine/core';
|
|
12
|
+
|
|
13
|
+
export const LoginButton = {
|
|
14
|
+
render: () => (
|
|
15
|
+
<Card>
|
|
16
|
+
<Button>Login</Button>
|
|
17
|
+
</Card>
|
|
18
|
+
)
|
|
19
|
+
};
|
|
20
|
+
`;
|
|
21
|
+
expect(extractStoryName(storyCode)).toBe('Login Button');
|
|
22
|
+
});
|
|
23
|
+
test('extracts name from title property', () => {
|
|
24
|
+
const storyCode = `
|
|
25
|
+
import React from 'react';
|
|
26
|
+
import { Button } from '@mantine/core';
|
|
27
|
+
|
|
28
|
+
export const MyStory = {
|
|
29
|
+
title: "User Profile Card",
|
|
30
|
+
render: () => <Button>Click me</Button>
|
|
31
|
+
};
|
|
32
|
+
`;
|
|
33
|
+
expect(extractStoryName(storyCode)).toBe('User Profile Card');
|
|
34
|
+
});
|
|
35
|
+
test('extracts name from meta export default title', () => {
|
|
36
|
+
const storyCode = `
|
|
37
|
+
export default {
|
|
38
|
+
title: "Navigation Menu",
|
|
39
|
+
component: MyComponent
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Default = {
|
|
43
|
+
render: () => <div>Menu</div>
|
|
44
|
+
};
|
|
45
|
+
`;
|
|
46
|
+
expect(extractStoryName(storyCode)).toBe('Navigation Menu');
|
|
47
|
+
});
|
|
48
|
+
test('extracts name from comment annotation', () => {
|
|
49
|
+
const storyCode = `
|
|
50
|
+
// @title Shopping Cart
|
|
51
|
+
import React from 'react';
|
|
52
|
+
|
|
53
|
+
export const CartStory = {
|
|
54
|
+
render: () => <div>Cart</div>
|
|
55
|
+
};
|
|
56
|
+
`;
|
|
57
|
+
expect(extractStoryName(storyCode)).toBe('Shopping Cart');
|
|
58
|
+
});
|
|
59
|
+
test('extracts name from JSDoc comment', () => {
|
|
60
|
+
const storyCode = `
|
|
61
|
+
/**
|
|
62
|
+
* @title Product Gallery
|
|
63
|
+
* @description Shows product images
|
|
64
|
+
*/
|
|
65
|
+
export const Gallery = {
|
|
66
|
+
render: () => <div>Gallery</div>
|
|
67
|
+
};
|
|
68
|
+
`;
|
|
69
|
+
expect(extractStoryName(storyCode)).toBe('Product Gallery');
|
|
70
|
+
});
|
|
71
|
+
test('extracts name from component name in JSX', () => {
|
|
72
|
+
const storyCode = `
|
|
73
|
+
export const Example = {
|
|
74
|
+
render: () => (
|
|
75
|
+
<UserDashboard>
|
|
76
|
+
<div>Content</div>
|
|
77
|
+
</UserDashboard>
|
|
78
|
+
)
|
|
79
|
+
};
|
|
80
|
+
`;
|
|
81
|
+
expect(extractStoryName(storyCode)).toBe('User Dashboard');
|
|
82
|
+
});
|
|
83
|
+
test('extracts name from function export', () => {
|
|
84
|
+
const storyCode = `
|
|
85
|
+
export function ContactForm() {
|
|
86
|
+
return <form>Contact</form>;
|
|
87
|
+
}
|
|
88
|
+
`;
|
|
89
|
+
expect(extractStoryName(storyCode)).toBe('Contact Form');
|
|
90
|
+
});
|
|
91
|
+
test('handles complex PascalCase to readable conversion', () => {
|
|
92
|
+
const storyCode = `
|
|
93
|
+
export const MyComplexUIComponentStory = {
|
|
94
|
+
render: () => <div>Complex UI</div>
|
|
95
|
+
};
|
|
96
|
+
`;
|
|
97
|
+
expect(extractStoryName(storyCode)).toBe('My Complex UI Component Story');
|
|
98
|
+
});
|
|
99
|
+
test('ignores generic HTML elements', () => {
|
|
100
|
+
const storyCode = `
|
|
101
|
+
export const Example = {
|
|
102
|
+
render: () => (
|
|
103
|
+
<div>
|
|
104
|
+
<span>Some text</span>
|
|
105
|
+
</div>
|
|
106
|
+
)
|
|
107
|
+
};
|
|
108
|
+
`;
|
|
109
|
+
expect(extractStoryName(storyCode)).toBe('Example');
|
|
110
|
+
});
|
|
111
|
+
test('prefers explicit title over export name', () => {
|
|
112
|
+
const storyCode = `
|
|
113
|
+
export const GenericName = {
|
|
114
|
+
title: "Specific Title",
|
|
115
|
+
render: () => <div>Content</div>
|
|
116
|
+
};
|
|
117
|
+
`;
|
|
118
|
+
expect(extractStoryName(storyCode)).toBe('Specific Title');
|
|
119
|
+
});
|
|
120
|
+
test('returns fallback for unrecognizable code', () => {
|
|
121
|
+
const storyCode = `
|
|
122
|
+
const someRandomCode = "hello";
|
|
123
|
+
console.log(someRandomCode);
|
|
124
|
+
`;
|
|
125
|
+
expect(extractStoryName(storyCode)).toBe('Imported Story');
|
|
126
|
+
});
|
|
127
|
+
test('handles Vite-transformed code gracefully', () => {
|
|
128
|
+
const storyCode = `
|
|
129
|
+
import { __vite__cjsImport } from "something";
|
|
130
|
+
const _jsxDEV = __vite__cjsImport.default;
|
|
131
|
+
export const TransformedStory = {};
|
|
132
|
+
`;
|
|
133
|
+
expect(extractStoryName(storyCode)).toBe('Transformed Story');
|
|
134
|
+
});
|
|
135
|
+
// Real-world examples
|
|
136
|
+
test('handles real Mantine story format', () => {
|
|
137
|
+
const storyCode = `
|
|
138
|
+
import React from 'react';
|
|
139
|
+
import { Button, Card, Stack, Title } from '@mantine/core';
|
|
140
|
+
|
|
141
|
+
export const UserCard = {
|
|
142
|
+
render: () => (
|
|
143
|
+
<Card shadow="sm" padding="lg" radius="md" withBorder>
|
|
144
|
+
<Stack>
|
|
145
|
+
<Title order={3}>John Doe</Title>
|
|
146
|
+
<Button variant="light">View Profile</Button>
|
|
147
|
+
</Stack>
|
|
148
|
+
</Card>
|
|
149
|
+
)
|
|
150
|
+
};
|
|
151
|
+
`;
|
|
152
|
+
expect(extractStoryName(storyCode)).toBe('User Card');
|
|
153
|
+
});
|
|
154
|
+
test('handles Story UI generated format', () => {
|
|
155
|
+
const storyCode = `
|
|
156
|
+
// Generated by Story UI
|
|
157
|
+
import React from 'react';
|
|
158
|
+
import { Container, Title, Text, Button } from '@mantine/core';
|
|
159
|
+
|
|
160
|
+
export const WelcomeScreen = {
|
|
161
|
+
render: () => (
|
|
162
|
+
<Container>
|
|
163
|
+
<Title>Welcome</Title>
|
|
164
|
+
<Text>Get started with our app</Text>
|
|
165
|
+
<Button>Continue</Button>
|
|
166
|
+
</Container>
|
|
167
|
+
)
|
|
168
|
+
};
|
|
169
|
+
`;
|
|
170
|
+
expect(extractStoryName(storyCode)).toBe('Welcome Screen');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
// Integration test for the full flow
|
|
174
|
+
describe('Story Name Integration', () => {
|
|
175
|
+
test('existing story should not prompt for name', async () => {
|
|
176
|
+
const existingStoryCode = `
|
|
177
|
+
export const DashboardLayout = {
|
|
178
|
+
title: "Admin Dashboard",
|
|
179
|
+
render: () => <div>Dashboard</div>
|
|
180
|
+
};
|
|
181
|
+
`;
|
|
182
|
+
const extractedName = extractStoryName(existingStoryCode);
|
|
183
|
+
// Should extract a valid name
|
|
184
|
+
expect(extractedName).toBe('Admin Dashboard');
|
|
185
|
+
expect(extractedName).not.toBe('Imported Story');
|
|
186
|
+
expect(extractedName).not.toBe('Untitled Story');
|
|
187
|
+
// In the Visual Builder, this should NOT trigger a name prompt
|
|
188
|
+
const isGenericName = extractedName === 'Untitled Story' || extractedName === 'Imported Story';
|
|
189
|
+
expect(isGenericName).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
test('new AI-generated story should work normally', () => {
|
|
192
|
+
const newStoryCode = `
|
|
193
|
+
// This is raw AI-generated JSX without story metadata
|
|
194
|
+
import React from 'react';
|
|
195
|
+
|
|
196
|
+
const MyComponent = () => (
|
|
197
|
+
<div>
|
|
198
|
+
<h1>Hello World</h1>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
export default MyComponent;
|
|
203
|
+
`;
|
|
204
|
+
const extractedName = extractStoryName(newStoryCode);
|
|
205
|
+
// Should fall back to generic name
|
|
206
|
+
expect(extractedName).toBe('Imported Story');
|
|
207
|
+
// In the Visual Builder, this SHOULD trigger a name prompt for new stories
|
|
208
|
+
const isGenericName = extractedName === 'Untitled Story' || extractedName === 'Imported Story';
|
|
209
|
+
expect(isGenericName).toBe(true);
|
|
210
|
+
});
|
|
211
|
+
});
|