@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.
Files changed (295) hide show
  1. package/README.md +36 -37
  2. package/dist/cli/deploy.d.ts +4 -3
  3. package/dist/cli/deploy.d.ts.map +1 -1
  4. package/dist/cli/deploy.js +542 -46
  5. package/dist/cli/index.js +17 -14
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/setup.d.ts.map +1 -1
  8. package/dist/cli/setup.js +4 -110
  9. package/dist/cli/setup.js.map +1 -0
  10. package/dist/cloudflare-edge/src/mcp-session.js +462 -0
  11. package/dist/cloudflare-edge/src/types.js +4 -0
  12. package/dist/cloudflare-edge/src/worker.js +106 -0
  13. package/dist/cloudflare-pages/vite.config.js +14 -0
  14. package/dist/index.d.ts +13 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +12 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/mcp-server/index.js.map +1 -0
  19. package/dist/mcp-server/mcp-stdio-server.js.map +1 -0
  20. package/dist/mcp-server/routes/claude.js.map +1 -0
  21. package/dist/mcp-server/routes/components.js.map +1 -0
  22. package/dist/mcp-server/routes/generateStory.js.map +1 -0
  23. package/dist/mcp-server/routes/hybridStories.js.map +1 -0
  24. package/dist/mcp-server/routes/memoryStories.js.map +1 -0
  25. package/dist/mcp-server/routes/storySync.js.map +1 -0
  26. package/dist/mcp-server/routes/updateStory.js +246 -0
  27. package/dist/mcp-server/sessionManager.js.map +1 -0
  28. package/dist/playground/components/AIAssistant/AIAssistant.d.ts +6 -0
  29. package/dist/playground/components/AIAssistant/AIAssistant.d.ts.map +1 -0
  30. package/dist/playground/components/AIAssistant/AIAssistant.js +109 -0
  31. package/dist/playground/components/AIAssistant/AIAssistant.js.map +1 -0
  32. package/dist/playground/components/AIAssistant/AIAssistant.module.css +166 -0
  33. package/dist/playground/components/Canvas/Canvas.d.ts +9 -0
  34. package/dist/playground/components/Canvas/Canvas.d.ts.map +1 -0
  35. package/dist/playground/components/Canvas/Canvas.js +58 -0
  36. package/dist/playground/components/Canvas/Canvas.js.map +1 -0
  37. package/dist/playground/components/Canvas/Canvas.module.css +189 -0
  38. package/dist/playground/components/Canvas/CanvasWithDnd.d.ts +9 -0
  39. package/dist/playground/components/Canvas/CanvasWithDnd.d.ts.map +1 -0
  40. package/dist/playground/components/Canvas/CanvasWithDnd.js +158 -0
  41. package/dist/playground/components/Canvas/CanvasWithDnd.js.map +1 -0
  42. package/dist/playground/components/Canvas/ComponentRenderer.d.ts +15 -0
  43. package/dist/playground/components/Canvas/ComponentRenderer.d.ts.map +1 -0
  44. package/dist/playground/components/Canvas/ComponentRenderer.js +177 -0
  45. package/dist/playground/components/Canvas/ComponentRenderer.js.map +1 -0
  46. package/dist/playground/components/Canvas/DraggableComponent.d.ts +15 -0
  47. package/dist/playground/components/Canvas/DraggableComponent.d.ts.map +1 -0
  48. package/dist/playground/components/Canvas/DraggableComponent.js +49 -0
  49. package/dist/playground/components/Canvas/DraggableComponent.js.map +1 -0
  50. package/dist/playground/components/Canvas/index.d.ts +9 -0
  51. package/dist/playground/components/Canvas/index.d.ts.map +1 -0
  52. package/dist/playground/components/Canvas/index.js +5 -0
  53. package/dist/playground/components/Canvas/index.js.map +1 -0
  54. package/dist/playground/components/CodeView/CodeView.d.ts +12 -0
  55. package/dist/playground/components/CodeView/CodeView.d.ts.map +1 -0
  56. package/dist/playground/components/CodeView/CodeView.js +77 -0
  57. package/dist/playground/components/CodeView/CodeView.js.map +1 -0
  58. package/dist/playground/components/CodeView/CodeView.module.css +178 -0
  59. package/dist/playground/components/ComponentPalette/ComponentPalette.d.ts +17 -0
  60. package/dist/playground/components/ComponentPalette/ComponentPalette.d.ts.map +1 -0
  61. package/dist/playground/components/ComponentPalette/ComponentPalette.js +138 -0
  62. package/dist/playground/components/ComponentPalette/ComponentPalette.js.map +1 -0
  63. package/dist/playground/components/ComponentPalette/ComponentPalette.module.css +217 -0
  64. package/dist/playground/components/ComponentPalette/index.d.ts +3 -0
  65. package/dist/playground/components/ComponentPalette/index.d.ts.map +1 -0
  66. package/dist/playground/components/ComponentPalette/index.js +2 -0
  67. package/dist/playground/components/ComponentPalette/index.js.map +1 -0
  68. package/dist/playground/components/DropZone/DropZone.d.ts +17 -0
  69. package/dist/playground/components/DropZone/DropZone.d.ts.map +1 -0
  70. package/dist/playground/components/DropZone/DropZone.js +73 -0
  71. package/dist/playground/components/DropZone/DropZone.js.map +1 -0
  72. package/dist/playground/components/DropZone/DropZone.module.css +86 -0
  73. package/dist/playground/components/ExportDialog/ExportDialog.d.ts +10 -0
  74. package/dist/playground/components/ExportDialog/ExportDialog.d.ts.map +1 -0
  75. package/dist/playground/components/ExportDialog/ExportDialog.js +57 -0
  76. package/dist/playground/components/ExportDialog/ExportDialog.js.map +1 -0
  77. package/dist/playground/components/ExportDialog/ExportDialog.module.css +328 -0
  78. package/dist/playground/components/LayoutHelpers/LayoutHelpers.d.ts +134 -0
  79. package/dist/playground/components/LayoutHelpers/LayoutHelpers.d.ts.map +1 -0
  80. package/dist/playground/components/LayoutHelpers/LayoutHelpers.js +254 -0
  81. package/dist/playground/components/LayoutHelpers/LayoutHelpers.js.map +1 -0
  82. package/dist/playground/components/LayoutHelpers/index.d.ts +3 -0
  83. package/dist/playground/components/LayoutHelpers/index.d.ts.map +1 -0
  84. package/dist/playground/components/LayoutHelpers/index.js +2 -0
  85. package/dist/playground/components/LayoutHelpers/index.js.map +1 -0
  86. package/dist/playground/components/Playground/Playground.d.ts +10 -0
  87. package/dist/playground/components/Playground/Playground.d.ts.map +1 -0
  88. package/dist/playground/components/Playground/Playground.js +128 -0
  89. package/dist/playground/components/Playground/Playground.js.map +1 -0
  90. package/dist/playground/components/Playground/Playground.module.css +308 -0
  91. package/dist/playground/components/PropertiesPanel/PropertiesPanel.d.ts +10 -0
  92. package/dist/playground/components/PropertiesPanel/PropertiesPanel.d.ts.map +1 -0
  93. package/dist/playground/components/PropertiesPanel/PropertiesPanel.js +150 -0
  94. package/dist/playground/components/PropertiesPanel/PropertiesPanel.js.map +1 -0
  95. package/dist/playground/components/PropertiesPanel/PropertiesPanel.module.css +155 -0
  96. package/dist/playground/components/PropertiesPanel/index.d.ts +3 -0
  97. package/dist/playground/components/PropertiesPanel/index.d.ts.map +1 -0
  98. package/dist/playground/components/PropertiesPanel/index.js +2 -0
  99. package/dist/playground/components/PropertiesPanel/index.js.map +1 -0
  100. package/dist/playground/components/PropertyEditors/BooleanEditor.d.ts +12 -0
  101. package/dist/playground/components/PropertyEditors/BooleanEditor.d.ts.map +1 -0
  102. package/dist/playground/components/PropertyEditors/BooleanEditor.js +14 -0
  103. package/dist/playground/components/PropertyEditors/BooleanEditor.js.map +1 -0
  104. package/dist/playground/components/PropertyEditors/ColorEditor.d.ts +12 -0
  105. package/dist/playground/components/PropertyEditors/ColorEditor.d.ts.map +1 -0
  106. package/dist/playground/components/PropertyEditors/ColorEditor.js +62 -0
  107. package/dist/playground/components/PropertyEditors/ColorEditor.js.map +1 -0
  108. package/dist/playground/components/PropertyEditors/IconEditor.d.ts +12 -0
  109. package/dist/playground/components/PropertyEditors/IconEditor.d.ts.map +1 -0
  110. package/dist/playground/components/PropertyEditors/IconEditor.js +123 -0
  111. package/dist/playground/components/PropertyEditors/IconEditor.js.map +1 -0
  112. package/dist/playground/components/PropertyEditors/NumberEditor.d.ts +15 -0
  113. package/dist/playground/components/PropertyEditors/NumberEditor.d.ts.map +1 -0
  114. package/dist/playground/components/PropertyEditors/NumberEditor.js +46 -0
  115. package/dist/playground/components/PropertyEditors/NumberEditor.js.map +1 -0
  116. package/dist/playground/components/PropertyEditors/PropertyEditors.module.css +432 -0
  117. package/dist/playground/components/PropertyEditors/SelectEditor.d.ts +19 -0
  118. package/dist/playground/components/PropertyEditors/SelectEditor.d.ts.map +1 -0
  119. package/dist/playground/components/PropertyEditors/SelectEditor.js +17 -0
  120. package/dist/playground/components/PropertyEditors/SelectEditor.js.map +1 -0
  121. package/dist/playground/components/PropertyEditors/SpacingEditor.d.ts +19 -0
  122. package/dist/playground/components/PropertyEditors/SpacingEditor.d.ts.map +1 -0
  123. package/dist/playground/components/PropertyEditors/SpacingEditor.js +162 -0
  124. package/dist/playground/components/PropertyEditors/SpacingEditor.js.map +1 -0
  125. package/dist/playground/components/PropertyEditors/SpacingEditor.module.css +214 -0
  126. package/dist/playground/components/PropertyEditors/TextEditor.d.ts +14 -0
  127. package/dist/playground/components/PropertyEditors/TextEditor.d.ts.map +1 -0
  128. package/dist/playground/components/PropertyEditors/TextEditor.js +38 -0
  129. package/dist/playground/components/PropertyEditors/TextEditor.js.map +1 -0
  130. package/dist/playground/components/PropertyEditors/TokenEditor.d.ts +23 -0
  131. package/dist/playground/components/PropertyEditors/TokenEditor.d.ts.map +1 -0
  132. package/dist/playground/components/PropertyEditors/TokenEditor.js +50 -0
  133. package/dist/playground/components/PropertyEditors/TokenEditor.js.map +1 -0
  134. package/dist/playground/components/PropertyEditors/index.d.ts +20 -0
  135. package/dist/playground/components/PropertyEditors/index.d.ts.map +1 -0
  136. package/dist/playground/components/PropertyEditors/index.js +12 -0
  137. package/dist/playground/components/PropertyEditors/index.js.map +1 -0
  138. package/dist/playground/components/TreeView/TreeView.d.ts +10 -0
  139. package/dist/playground/components/TreeView/TreeView.d.ts.map +1 -0
  140. package/dist/playground/components/TreeView/TreeView.js +146 -0
  141. package/dist/playground/components/TreeView/TreeView.js.map +1 -0
  142. package/dist/playground/components/TreeView/TreeView.module.css +214 -0
  143. package/dist/playground/components/TreeView/index.d.ts +3 -0
  144. package/dist/playground/components/TreeView/index.d.ts.map +1 -0
  145. package/dist/playground/components/TreeView/index.js +2 -0
  146. package/dist/playground/components/TreeView/index.js.map +1 -0
  147. package/dist/playground/config/propertyDefinitions.d.ts +73 -0
  148. package/dist/playground/config/propertyDefinitions.d.ts.map +1 -0
  149. package/dist/playground/config/propertyDefinitions.js +809 -0
  150. package/dist/playground/config/propertyDefinitions.js.map +1 -0
  151. package/dist/playground/hooks/useKeyboardShortcuts.d.ts +38 -0
  152. package/dist/playground/hooks/useKeyboardShortcuts.d.ts.map +1 -0
  153. package/dist/playground/hooks/useKeyboardShortcuts.js +191 -0
  154. package/dist/playground/hooks/useKeyboardShortcuts.js.map +1 -0
  155. package/dist/playground/index.d.ts +21 -0
  156. package/dist/playground/index.d.ts.map +1 -0
  157. package/dist/playground/index.js +23 -0
  158. package/dist/playground/index.js.map +1 -0
  159. package/dist/playground/services/CodeGenerator.d.ts +73 -0
  160. package/dist/playground/services/CodeGenerator.d.ts.map +1 -0
  161. package/dist/playground/services/CodeGenerator.js +359 -0
  162. package/dist/playground/services/CodeGenerator.js.map +1 -0
  163. package/dist/playground/services/DragDropManager.d.ts +95 -0
  164. package/dist/playground/services/DragDropManager.d.ts.map +1 -0
  165. package/dist/playground/services/DragDropManager.js +408 -0
  166. package/dist/playground/services/DragDropManager.js.map +1 -0
  167. package/dist/playground/services/StoryParser.d.ts +73 -0
  168. package/dist/playground/services/StoryParser.d.ts.map +1 -0
  169. package/dist/playground/services/StoryParser.js +419 -0
  170. package/dist/playground/services/StoryParser.js.map +1 -0
  171. package/dist/playground/store/playgroundStore.d.ts +86 -0
  172. package/dist/playground/store/playgroundStore.d.ts.map +1 -0
  173. package/dist/playground/store/playgroundStore.js +337 -0
  174. package/dist/playground/store/playgroundStore.js.map +1 -0
  175. package/dist/playground/stories/PlaygroundDragDrop.stories.d.ts +13 -0
  176. package/dist/playground/stories/PlaygroundDragDrop.stories.d.ts.map +1 -0
  177. package/dist/playground/stories/PlaygroundDragDrop.stories.js +227 -0
  178. package/dist/playground/stories/PlaygroundDragDrop.stories.js.map +1 -0
  179. package/dist/playground/stories/PlaygroundPhase4.stories.d.ts +13 -0
  180. package/dist/playground/stories/PlaygroundPhase4.stories.d.ts.map +1 -0
  181. package/dist/playground/stories/PlaygroundPhase4.stories.js +334 -0
  182. package/dist/playground/stories/PlaygroundPhase4.stories.js.map +1 -0
  183. package/dist/playground/stories/PlaygroundPhase5.stories.d.ts +14 -0
  184. package/dist/playground/stories/PlaygroundPhase5.stories.d.ts.map +1 -0
  185. package/dist/playground/stories/PlaygroundPhase5.stories.js +512 -0
  186. package/dist/playground/stories/PlaygroundPhase5.stories.js.map +1 -0
  187. package/dist/playground/stories/PlaygroundProperties.stories.d.ts +13 -0
  188. package/dist/playground/stories/PlaygroundProperties.stories.d.ts.map +1 -0
  189. package/dist/playground/stories/PlaygroundProperties.stories.js +342 -0
  190. package/dist/playground/stories/PlaygroundProperties.stories.js.map +1 -0
  191. package/dist/playground/types/index.d.ts +251 -0
  192. package/dist/playground/types/index.d.ts.map +1 -0
  193. package/dist/playground/types/index.js +5 -0
  194. package/dist/playground/types/index.js.map +1 -0
  195. package/dist/scripts/verify-framework-adapters.js +105 -0
  196. package/dist/story-generator/componentBlacklist.js.map +1 -0
  197. package/dist/story-generator/componentDiscovery.js.map +1 -0
  198. package/dist/story-generator/configLoader.js.map +1 -0
  199. package/dist/story-generator/considerationsLoader.js.map +1 -0
  200. package/dist/story-generator/documentation-sources.js.map +1 -0
  201. package/dist/story-generator/documentationLoader.js.map +1 -0
  202. package/dist/story-generator/dynamicPackageDiscovery.js.map +1 -0
  203. package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
  204. package/dist/story-generator/enhancedComponentDiscovery.js +4 -6
  205. package/dist/story-generator/enhancedComponentDiscovery.js.map +1 -0
  206. package/dist/story-generator/generateStory.js.map +1 -0
  207. package/dist/story-generator/gitignoreManager.js.map +1 -0
  208. package/dist/story-generator/inMemoryStoryService.js.map +1 -0
  209. package/dist/story-generator/llm-providers/settings-manager.js +4 -4
  210. package/dist/story-generator/logger.js.map +1 -0
  211. package/dist/story-generator/postProcessStory.js.map +1 -0
  212. package/dist/story-generator/productionGitignoreManager.d.ts.map +1 -1
  213. package/dist/story-generator/productionGitignoreManager.js +6 -0
  214. package/dist/story-generator/productionGitignoreManager.js.map +1 -0
  215. package/dist/story-generator/promptGenerator.js.map +1 -0
  216. package/dist/story-generator/providerPresets.d.ts +54 -0
  217. package/dist/story-generator/providerPresets.d.ts.map +1 -0
  218. package/dist/story-generator/providerPresets.js +214 -0
  219. package/dist/story-generator/storyHistory.js.map +1 -0
  220. package/dist/story-generator/storySync.js.map +1 -0
  221. package/dist/story-generator/storyTracker.js.map +1 -0
  222. package/dist/story-generator/storyValidator.js.map +1 -0
  223. package/dist/story-generator/test_validation.d.ts +2 -0
  224. package/dist/story-generator/test_validation.d.ts.map +1 -0
  225. package/dist/story-generator/test_validation.js +51 -0
  226. package/dist/story-generator/universalDesignSystemAdapter.js.map +1 -0
  227. package/dist/story-generator/urlRedirectService.js.map +1 -0
  228. package/dist/story-generator/validateStory.js.map +1 -0
  229. package/dist/story-ui.config.js.map +1 -0
  230. package/dist/story-ui.config.loader.d.ts +36 -0
  231. package/dist/story-ui.config.loader.d.ts.map +1 -0
  232. package/dist/story-ui.config.loader.js +205 -0
  233. package/dist/story-ui.config.loader.js.map +1 -0
  234. package/dist/temp/package/templates/StoryUI/StoryUIPanel.js +807 -0
  235. package/dist/temp/package/templates/StoryUI/StoryUIPanel.stories.js +37 -0
  236. package/dist/temp/package/templates/StoryUI/index.js +2 -0
  237. package/dist/templates/StoryUI/StoryUIPanel.js.map +1 -0
  238. package/dist/templates/StoryUI/StoryUIPanel.stories.js.map +1 -0
  239. package/dist/templates/StoryUI/index.js.map +1 -0
  240. package/dist/templates/StoryUI/manager.d.ts +14 -0
  241. package/dist/templates/StoryUI/manager.d.ts.map +1 -0
  242. package/dist/templates/production-app/src/App.d.ts +10 -0
  243. package/dist/templates/production-app/src/App.d.ts.map +1 -0
  244. package/dist/templates/production-app/src/App.js +653 -0
  245. package/dist/templates/production-app/src/LivePreviewRenderer.d.ts +24 -0
  246. package/dist/templates/production-app/src/LivePreviewRenderer.d.ts.map +1 -0
  247. package/dist/templates/production-app/src/LivePreviewRenderer.js +199 -0
  248. package/dist/templates/production-app/src/componentRegistry.d.ts +20 -0
  249. package/dist/templates/production-app/src/componentRegistry.d.ts.map +1 -0
  250. package/dist/templates/production-app/src/componentRegistry.js +316 -0
  251. package/dist/templates/production-app/src/main.d.ts +9 -0
  252. package/dist/templates/production-app/src/main.d.ts.map +1 -0
  253. package/dist/templates/production-app/src/main.js +18 -0
  254. package/dist/templates/production-app/vite.config.d.ts +3 -0
  255. package/dist/templates/production-app/vite.config.d.ts.map +1 -0
  256. package/dist/templates/production-app/vite.config.js +71 -0
  257. package/dist/test-storybooks/angular-material-storybook/src/main.js +66 -0
  258. package/dist/test-storybooks/chakra-storybook/vite.config.js +6 -0
  259. package/dist/test-storybooks/mantine-storybook/vite.config.js +93 -0
  260. package/dist/test-storybooks/web-components-shoelace/vite.config.js +9 -0
  261. package/dist/tsconfig.tsbuildinfo +1 -0
  262. package/dist/visual-builder/components/Canvas/Canvas.js +70 -0
  263. package/dist/visual-builder/components/Canvas/ComponentRenderer.js +545 -0
  264. package/dist/visual-builder/components/CodeExporter/CodeExporter.js +25 -0
  265. package/dist/visual-builder/components/CodeExporter/codeGenerator.js +99 -0
  266. package/dist/visual-builder/components/ComponentPalette/ComponentPalette.js +8 -0
  267. package/dist/visual-builder/components/ComponentPalette/ComponentPaletteItem.js +51 -0
  268. package/dist/visual-builder/components/EmbeddedVisualBuilder.js +107 -0
  269. package/dist/visual-builder/components/PropertyEditor/PropertyEditor.js +16 -0
  270. package/dist/visual-builder/components/PropertyEditor/PropertyForm.js +88 -0
  271. package/dist/visual-builder/components/PropertyEditor/SpacingControl.js +145 -0
  272. package/dist/visual-builder/components/PropertyEditor/SpacingEditor.js +32 -0
  273. package/dist/visual-builder/components/StoryManager/SaveOnlyManager.js +94 -0
  274. package/dist/visual-builder/components/StoryManager/StoryManager.js +68 -0
  275. package/dist/visual-builder/components/StoryManager/index.js +1 -0
  276. package/dist/visual-builder/components/VisualBuilder.js +256 -0
  277. package/dist/visual-builder/config/componentRegistry.js +1758 -0
  278. package/dist/visual-builder/decorators/VisualBuilderDecorator.js +184 -0
  279. package/dist/visual-builder/example-integration.js +59 -0
  280. package/dist/visual-builder/example.js +23 -0
  281. package/dist/visual-builder/hooks/useDragAndDrop.js +137 -0
  282. package/dist/visual-builder/hooks/useSelection.js +27 -0
  283. package/dist/visual-builder/index.js +7 -0
  284. package/dist/visual-builder/store/visualBuilderStore.js +305 -0
  285. package/dist/visual-builder/types/index.js +1 -0
  286. package/dist/visual-builder/utils/__tests__/storyFileUpdater.test.js +145 -0
  287. package/dist/visual-builder/utils/aiParser.js +336 -0
  288. package/dist/visual-builder/utils/componentTreeUtils.js +111 -0
  289. package/dist/visual-builder/utils/parserValidation.js +122 -0
  290. package/dist/visual-builder/utils/storyFileManager.js +73 -0
  291. package/dist/visual-builder/utils/storyFileUpdater.js +326 -0
  292. package/dist/visual-builder/utils/storyNameExtraction.test.js +211 -0
  293. package/dist/visual-builder/utils/storyPersistence.js +180 -0
  294. package/dist/visual-builder/utils/storyToBuilder.js +813 -0
  295. 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
+ });