@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,305 @@
1
+ import { create } from 'zustand';
2
+ import { devtools } from 'zustand/middleware';
3
+ import { removeComponentFromTree, insertComponentInTree, findComponentWithParent, isDescendant } from '../utils/componentTreeUtils';
4
+ import { saveStory, loadStory, scheduleAutoSave, cancelAutoSave } from '../utils/storyPersistence';
5
+ export const useVisualBuilderStore = create()(devtools((set, _get) => ({
6
+ // Initial state
7
+ components: [],
8
+ selectedComponent: null,
9
+ draggedComponent: null,
10
+ isCodeModalOpen: false,
11
+ isImportedFromStory: false,
12
+ // Story management state
13
+ currentStoryId: null,
14
+ currentStoryName: 'Untitled Story',
15
+ isDirty: false,
16
+ // Actions
17
+ addComponent: (component, targetId, insertIndex) => {
18
+ set((state) => {
19
+ const newComponent = { ...component, id: `${component.type}-${Date.now()}` };
20
+ let newComponents;
21
+ if (targetId) {
22
+ // Add as child to target component
23
+ const updateComponents = (components) => {
24
+ return components.map(comp => {
25
+ if (comp.id === targetId) {
26
+ const children = comp.children || [];
27
+ const newChildren = insertIndex !== undefined
28
+ ? [...children.slice(0, insertIndex), newComponent, ...children.slice(insertIndex)]
29
+ : [...children, newComponent];
30
+ return {
31
+ ...comp,
32
+ children: newChildren
33
+ };
34
+ }
35
+ if (comp.children) {
36
+ return {
37
+ ...comp,
38
+ children: updateComponents(comp.children)
39
+ };
40
+ }
41
+ return comp;
42
+ });
43
+ };
44
+ newComponents = updateComponents(state.components);
45
+ }
46
+ else {
47
+ // Add to root level
48
+ newComponents = insertIndex !== undefined
49
+ ? [...state.components.slice(0, insertIndex), newComponent, ...state.components.slice(insertIndex)]
50
+ : [...state.components, newComponent];
51
+ }
52
+ // Mark as dirty and schedule auto-save
53
+ scheduleAutoSave(state.currentStoryName, newComponents, state.currentStoryId || undefined);
54
+ return { components: newComponents, isDirty: true };
55
+ });
56
+ },
57
+ removeComponent: (id) => {
58
+ set((state) => {
59
+ const removeFromComponents = (components) => {
60
+ return components
61
+ .filter(comp => comp.id !== id)
62
+ .map(comp => ({
63
+ ...comp,
64
+ children: comp.children ? removeFromComponents(comp.children) : undefined
65
+ }));
66
+ };
67
+ const newComponents = removeFromComponents(state.components);
68
+ // Mark as dirty and schedule auto-save
69
+ scheduleAutoSave(state.currentStoryName, newComponents, state.currentStoryId || undefined);
70
+ return {
71
+ components: newComponents,
72
+ selectedComponent: state.selectedComponent?.id === id ? null : state.selectedComponent,
73
+ isDirty: true
74
+ };
75
+ });
76
+ },
77
+ updateComponent: (id, updates) => {
78
+ set((state) => {
79
+ const updateComponents = (components) => {
80
+ return components.map(comp => {
81
+ if (comp.id === id) {
82
+ return { ...comp, ...updates };
83
+ }
84
+ if (comp.children) {
85
+ return {
86
+ ...comp,
87
+ children: updateComponents(comp.children)
88
+ };
89
+ }
90
+ return comp;
91
+ });
92
+ };
93
+ const newComponents = updateComponents(state.components);
94
+ // Mark as dirty and schedule auto-save
95
+ scheduleAutoSave(state.currentStoryName, newComponents, state.currentStoryId || undefined);
96
+ return { components: newComponents, isDirty: true };
97
+ });
98
+ },
99
+ selectComponent: (component) => {
100
+ set({ selectedComponent: component });
101
+ },
102
+ setDraggedComponent: (component) => {
103
+ set({ draggedComponent: component });
104
+ },
105
+ openCodeModal: () => {
106
+ set({ isCodeModalOpen: true });
107
+ },
108
+ closeCodeModal: () => {
109
+ set({ isCodeModalOpen: false });
110
+ },
111
+ clearCanvas: () => {
112
+ set({
113
+ components: [],
114
+ selectedComponent: null,
115
+ isImportedFromStory: false,
116
+ isDirty: true
117
+ });
118
+ },
119
+ moveComponent: (activeId, overId, insertIndex, insertPosition) => {
120
+ set((state) => {
121
+ // Prevent moving a component into itself or its descendants
122
+ if (activeId === overId || isDescendant(state.components, activeId, overId)) {
123
+ return state;
124
+ }
125
+ // Remove the component from its current location
126
+ const { components: updatedComponents, removed } = removeComponentFromTree(state.components, activeId);
127
+ if (!removed) {
128
+ return state; // Component not found
129
+ }
130
+ // Determine insertion target and index
131
+ let targetContainerId = null;
132
+ let insertionIndex = insertIndex;
133
+ if (insertIndex !== undefined) {
134
+ // Direct insertion at specific index (root level)
135
+ targetContainerId = null;
136
+ }
137
+ else {
138
+ // Insert relative to another component
139
+ const overComponent = findComponentWithParent(updatedComponents, overId);
140
+ if (overComponent) {
141
+ if (overComponent.parent) {
142
+ targetContainerId = overComponent.parent.id;
143
+ insertionIndex = overComponent.index + (insertPosition === 'after' ? 1 : 0);
144
+ }
145
+ else {
146
+ // Insert at root level
147
+ targetContainerId = null;
148
+ insertionIndex = overComponent.index + (insertPosition === 'after' ? 1 : 0);
149
+ }
150
+ }
151
+ }
152
+ // Insert the component at the new location
153
+ const finalComponents = insertComponentInTree(updatedComponents, removed, targetContainerId, insertionIndex);
154
+ // Mark as dirty and schedule auto-save
155
+ scheduleAutoSave(state.currentStoryName, finalComponents, state.currentStoryId || undefined);
156
+ return { components: finalComponents, isDirty: true };
157
+ });
158
+ },
159
+ moveComponentBetweenContainers: (activeId, _fromParentId, toParentId, insertIndex) => {
160
+ set((state) => {
161
+ // Prevent moving a component into itself or its descendants
162
+ if (activeId === toParentId || (toParentId && isDescendant(state.components, activeId, toParentId))) {
163
+ return state;
164
+ }
165
+ // Remove component from its current location
166
+ const { components: afterRemoval, removed } = removeComponentFromTree(state.components, activeId);
167
+ if (!removed) {
168
+ return state; // Component not found
169
+ }
170
+ // Add component to new location
171
+ const finalComponents = insertComponentInTree(afterRemoval, removed, toParentId, insertIndex);
172
+ // Mark as dirty and schedule auto-save
173
+ scheduleAutoSave(state.currentStoryName, finalComponents, state.currentStoryId || undefined);
174
+ return { components: finalComponents, isDirty: true };
175
+ });
176
+ },
177
+ loadFromAI: (components) => {
178
+ set({
179
+ components,
180
+ selectedComponent: null,
181
+ isImportedFromStory: false,
182
+ isDirty: true
183
+ });
184
+ },
185
+ loadFromCode: async (code) => {
186
+ try {
187
+ const { parseAIGeneratedCode } = await import('../utils/aiParser');
188
+ const result = parseAIGeneratedCode(code);
189
+ if (result.errors.length === 0) {
190
+ set({
191
+ components: result.components,
192
+ selectedComponent: null,
193
+ isImportedFromStory: false,
194
+ isDirty: true
195
+ });
196
+ }
197
+ return {
198
+ success: result.errors.length === 0,
199
+ errors: result.errors,
200
+ warnings: result.warnings
201
+ };
202
+ }
203
+ catch (error) {
204
+ return {
205
+ success: false,
206
+ errors: [`Failed to load parser: ${error instanceof Error ? error.message : 'Unknown error'}`],
207
+ warnings: []
208
+ };
209
+ }
210
+ },
211
+ importFromStoryUI: async (storyCode) => {
212
+ try {
213
+ const { parseStoryUIToBuilder, validateParsedComponents, extractStoryName } = await import('../utils/storyToBuilder');
214
+ const parseResult = parseStoryUIToBuilder(storyCode);
215
+ // Validate the parsed components
216
+ const validationIssues = validateParsedComponents(parseResult.components);
217
+ const allWarnings = [...parseResult.warnings, ...validationIssues];
218
+ // Extract story name using the improved extraction function
219
+ const storyName = extractStoryName(storyCode);
220
+ // Determine if this is an existing story (has a valid extracted name)
221
+ const isEditingExistingStory = storyName !== 'Imported Story' && storyName !== 'Untitled Story';
222
+ if (parseResult.errors.length === 0) {
223
+ // Generate or use existing story ID
224
+ const state = _get();
225
+ const storyId = state.currentStoryId || `story-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
226
+ set({
227
+ components: parseResult.components,
228
+ selectedComponent: null,
229
+ isImportedFromStory: true, // Mark as imported from story
230
+ currentStoryName: storyName, // Set the extracted story name
231
+ currentStoryId: storyId, // Set the story ID
232
+ isDirty: isEditingExistingStory ? false : true // Start clean for existing stories, dirty for new imports
233
+ });
234
+ }
235
+ return {
236
+ success: parseResult.errors.length === 0,
237
+ errors: parseResult.errors,
238
+ warnings: allWarnings
239
+ };
240
+ }
241
+ catch (error) {
242
+ return {
243
+ success: false,
244
+ errors: [`Failed to import from Story UI: ${error instanceof Error ? error.message : 'Unknown error'}`],
245
+ warnings: []
246
+ };
247
+ }
248
+ },
249
+ // Story management actions
250
+ saveCurrentStory: (name) => {
251
+ const state = _get();
252
+ const storyName = name || state.currentStoryName;
253
+ const savedStory = saveStory(storyName, state.components, state.currentStoryId || undefined);
254
+ set({
255
+ currentStoryId: savedStory.id,
256
+ currentStoryName: savedStory.name,
257
+ isDirty: false
258
+ });
259
+ // Update URL with story ID
260
+ const url = new URL(window.location.href);
261
+ url.searchParams.set('story', savedStory.id);
262
+ window.history.replaceState({}, '', url.toString());
263
+ return savedStory;
264
+ },
265
+ loadStoryById: (id) => {
266
+ const story = loadStory(id);
267
+ if (story) {
268
+ cancelAutoSave(); // Cancel any pending auto-save
269
+ set({
270
+ components: story.components,
271
+ currentStoryId: story.id,
272
+ currentStoryName: story.name,
273
+ isDirty: false,
274
+ selectedComponent: null,
275
+ isImportedFromStory: false
276
+ });
277
+ return true;
278
+ }
279
+ return false;
280
+ },
281
+ markDirty: () => {
282
+ set({ isDirty: true });
283
+ },
284
+ markClean: () => {
285
+ set({ isDirty: false });
286
+ },
287
+ setCurrentStoryName: (name) => {
288
+ set({ currentStoryName: name, isDirty: true });
289
+ },
290
+ newStory: () => {
291
+ cancelAutoSave();
292
+ set({
293
+ components: [],
294
+ selectedComponent: null,
295
+ currentStoryId: null,
296
+ currentStoryName: 'Untitled Story',
297
+ isDirty: false,
298
+ isImportedFromStory: false
299
+ });
300
+ // Remove story parameter from URL
301
+ const url = new URL(window.location.href);
302
+ url.searchParams.delete('story');
303
+ window.history.replaceState({}, '', url.toString());
304
+ }
305
+ }), { name: 'visual-builder-store' }));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,145 @@
1
+ import { generateStoryFileContent, generatePropsString } from '../storyFileUpdater';
2
+ describe('storyFileUpdater', () => {
3
+ describe('generatePropsString', () => {
4
+ it('should generate correct style props with double curly braces', () => {
5
+ const props = {
6
+ style: { maxWidth: 400, padding: '1rem' }
7
+ };
8
+ const result = generatePropsString(props, 'Card');
9
+ // Should have double curly braces for style object
10
+ expect(result).toBe(' style={{ maxWidth: 400, padding: \'1rem\' }}');
11
+ expect(result).not.toContain('style="');
12
+ expect(result).toContain('style={{');
13
+ });
14
+ it('should handle numeric values in style objects correctly', () => {
15
+ const props = {
16
+ style: { width: 300, height: 200, zIndex: 10 }
17
+ };
18
+ const result = generatePropsString(props, 'div');
19
+ expect(result).toBe(' style={{ width: 300, height: 200, zIndex: 10 }}');
20
+ });
21
+ it('should handle string values in style objects with quotes', () => {
22
+ const props = {
23
+ style: { color: 'red', backgroundColor: '#fff', display: 'flex' }
24
+ };
25
+ const result = generatePropsString(props, 'div');
26
+ expect(result).toBe(' style={{ color: \'red\', backgroundColor: \'#fff\', display: \'flex\' }}');
27
+ });
28
+ it('should handle mixed style values correctly', () => {
29
+ const props = {
30
+ style: {
31
+ maxWidth: 400,
32
+ padding: '1rem',
33
+ margin: 0,
34
+ display: 'block'
35
+ }
36
+ };
37
+ const result = generatePropsString(props, 'Card');
38
+ expect(result).toBe(' style={{ maxWidth: 400, padding: \'1rem\', margin: 0, display: \'block\' }}');
39
+ });
40
+ it('should handle other prop types correctly alongside style', () => {
41
+ const props = {
42
+ shadow: 'md',
43
+ padding: 'xl',
44
+ radius: 'md',
45
+ withBorder: true,
46
+ style: { maxWidth: 400 }
47
+ };
48
+ const result = generatePropsString(props, 'Card');
49
+ expect(result).toContain('shadow="md"');
50
+ expect(result).toContain('padding="xl"');
51
+ expect(result).toContain('radius="md"');
52
+ expect(result).toContain('withBorder');
53
+ expect(result).toContain('style={{ maxWidth: 400 }}');
54
+ expect(result).not.toContain('style="');
55
+ });
56
+ it('should filter out children prop for Text components', () => {
57
+ const props = {
58
+ children: 'Some text',
59
+ size: 'lg'
60
+ };
61
+ const result = generatePropsString(props, 'Text');
62
+ expect(result).toBe(' size="lg"');
63
+ expect(result).not.toContain('children');
64
+ });
65
+ it('should keep children prop for Button components', () => {
66
+ const props = {
67
+ children: 'Click me',
68
+ variant: 'outline'
69
+ };
70
+ const result = generatePropsString(props, 'Button');
71
+ expect(result).toContain('children="Click me"');
72
+ expect(result).toContain('variant="outline"');
73
+ });
74
+ });
75
+ describe('generateStoryFileContent', () => {
76
+ it('should generate story with correct style syntax', () => {
77
+ const components = [{
78
+ id: 'card1',
79
+ type: 'Card',
80
+ displayName: 'Card',
81
+ category: 'mantine',
82
+ props: {
83
+ shadow: 'md',
84
+ padding: 'xl',
85
+ radius: 'md',
86
+ withBorder: true,
87
+ style: { maxWidth: 400 }
88
+ },
89
+ children: []
90
+ }];
91
+ const result = generateStoryFileContent(components, 'TestStory', 'test.stories.tsx');
92
+ // Should contain double curly braces, not single quotes around object
93
+ expect(result).toContain('style={{ maxWidth: 400 }}');
94
+ expect(result).not.toContain('style="{ maxWidth: 400 }"');
95
+ expect(result).not.toContain('style="');
96
+ });
97
+ it('should generate story with complex style objects correctly', () => {
98
+ const components = [{
99
+ id: 'div1',
100
+ type: 'div',
101
+ displayName: 'div',
102
+ category: 'html',
103
+ props: {
104
+ style: {
105
+ maxWidth: 400,
106
+ padding: '1rem',
107
+ margin: 0,
108
+ backgroundColor: '#f8f9fa',
109
+ borderRadius: '8px'
110
+ }
111
+ },
112
+ children: []
113
+ }];
114
+ const result = generateStoryFileContent(components, 'ComplexStyle', 'complex.stories.tsx');
115
+ expect(result).toContain('style={{ maxWidth: 400, padding: \'1rem\', margin: 0, backgroundColor: \'#f8f9fa\', borderRadius: \'8px\' }}');
116
+ expect(result).not.toContain('style="');
117
+ });
118
+ it('should handle nested components with styles correctly', () => {
119
+ const components = [{
120
+ id: 'card1',
121
+ type: 'Card',
122
+ displayName: 'Card',
123
+ category: 'mantine',
124
+ props: {
125
+ style: { maxWidth: 400 }
126
+ },
127
+ children: [{
128
+ id: 'stack1',
129
+ type: 'Stack',
130
+ displayName: 'Stack',
131
+ category: 'mantine',
132
+ props: {
133
+ gap: 'md',
134
+ style: { padding: '1rem' }
135
+ },
136
+ children: []
137
+ }]
138
+ }];
139
+ const result = generateStoryFileContent(components, 'NestedStyles', 'nested.stories.tsx');
140
+ expect(result).toContain('style={{ maxWidth: 400 }}');
141
+ expect(result).toContain('style={{ padding: \'1rem\' }}');
142
+ expect(result).not.toContain('style="');
143
+ });
144
+ });
145
+ });