@r2digisolutions/components 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/README.md +1 -1
  2. package/dist/components/atoms/Checkbox/Checkbox.svelte +10 -3
  3. package/dist/components/atoms/Checkbox/Checkbox.svelte.d.ts +3 -0
  4. package/dist/components/atoms/IconButton/IconButton.svelte +1 -1
  5. package/dist/components/atoms/Input/Input.svelte +17 -2
  6. package/dist/components/atoms/Input/Input.svelte.d.ts +6 -1
  7. package/dist/components/atoms/MarqueeRect/MarqueeRect.svelte +21 -0
  8. package/dist/components/atoms/MarqueeRect/MarqueeRect.svelte.d.ts +8 -0
  9. package/dist/components/atoms/MediaKindIcon/MediaKindIcon.stories.js +8 -0
  10. package/dist/components/atoms/MediaKindIcon/MediaKindIcon.svelte +122 -0
  11. package/dist/components/atoms/MediaKindIcon/MediaKindIcon.svelte.d.ts +11 -0
  12. package/dist/components/atoms/MediaKindIcon/MediaKindIconStory.svelte +12 -0
  13. package/dist/components/atoms/MediaKindIcon/MediaKindIconStory.svelte.d.ts +18 -0
  14. package/dist/components/atoms/PanKnob/PanKnob.stories.d.ts +9 -0
  15. package/dist/components/atoms/PanKnob/PanKnob.stories.js +8 -0
  16. package/dist/components/atoms/PanKnob/PanKnob.svelte +218 -0
  17. package/dist/components/atoms/PanKnob/PanKnob.svelte.d.ts +19 -0
  18. package/dist/components/atoms/PanKnob/PanKnobStory.svelte +15 -0
  19. package/dist/components/atoms/PanKnob/PanKnobStory.svelte.d.ts +3 -0
  20. package/dist/components/atoms/Playhead/Playhead.stories.js +8 -0
  21. package/dist/components/atoms/Playhead/Playhead.svelte +59 -0
  22. package/dist/components/atoms/Playhead/Playhead.svelte.d.ts +13 -0
  23. package/dist/components/atoms/Playhead/PlayheadStory.svelte +9 -0
  24. package/dist/components/atoms/Playhead/PlayheadStory.svelte.d.ts +18 -0
  25. package/dist/components/atoms/Textarea/Textarea.svelte +4 -1
  26. package/dist/components/atoms/Textarea/Textarea.svelte.d.ts +1 -0
  27. package/dist/components/atoms/TimeRuler/TimeRuler.stories.js +8 -0
  28. package/dist/components/atoms/TimeRuler/TimeRuler.svelte +58 -0
  29. package/dist/components/atoms/TimeRuler/TimeRuler.svelte.d.ts +10 -0
  30. package/dist/components/atoms/TimeRuler/TimeRulerStory.svelte +7 -0
  31. package/dist/components/atoms/TimeRuler/TimeRulerStory.svelte.d.ts +18 -0
  32. package/dist/components/atoms/Toggle/Toggle.svelte +1 -1
  33. package/dist/components/atoms/Tooltip/Tooltip.svelte +1 -1
  34. package/dist/components/atoms/TrimHandle/TrimHandle.stories.js +8 -0
  35. package/dist/components/atoms/TrimHandle/TrimHandle.svelte +63 -0
  36. package/dist/components/atoms/TrimHandle/TrimHandle.svelte.d.ts +12 -0
  37. package/dist/components/atoms/TrimHandle/TrimHandleStory.svelte +11 -0
  38. package/dist/components/atoms/TrimHandle/TrimHandleStory.svelte.d.ts +18 -0
  39. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.stories.d.ts +9 -0
  40. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.stories.js +8 -0
  41. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.svelte +102 -0
  42. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.svelte.d.ts +20 -0
  43. package/dist/components/molecules/AiAssistPanel/AiAssistPanelStory.svelte +34 -0
  44. package/dist/components/molecules/AiAssistPanel/AiAssistPanelStory.svelte.d.ts +3 -0
  45. package/dist/components/molecules/BulkActionBar/BulkActionBar.svelte +112 -62
  46. package/dist/components/molecules/BulkActionBar/BulkActionBar.svelte.d.ts +2 -0
  47. package/dist/components/molecules/BulkEditPanel/BulkEditPanel.stories.js +8 -0
  48. package/dist/components/molecules/BulkEditPanel/BulkEditPanel.svelte +117 -0
  49. package/dist/components/molecules/BulkEditPanel/BulkEditPanel.svelte.d.ts +23 -0
  50. package/dist/components/molecules/BulkEditPanel/BulkEditPanelStory.svelte +18 -0
  51. package/dist/components/molecules/BulkEditPanel/BulkEditPanelStory.svelte.d.ts +18 -0
  52. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanel.stories.js +8 -0
  53. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanel.svelte +858 -0
  54. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanel.svelte.d.ts +43 -0
  55. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanelStory.svelte +7 -0
  56. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanelStory.svelte.d.ts +18 -0
  57. package/dist/components/molecules/CanvasInspector/CanvasInspector.stories.d.ts +9 -0
  58. package/dist/components/molecules/CanvasInspector/CanvasInspector.stories.js +8 -0
  59. package/dist/components/molecules/CanvasInspector/CanvasInspector.svelte +1140 -0
  60. package/dist/components/molecules/CanvasInspector/CanvasInspector.svelte.d.ts +28 -0
  61. package/dist/components/molecules/CanvasInspector/CanvasInspectorStory.svelte +20 -0
  62. package/dist/components/molecules/CanvasInspector/CanvasInspectorStory.svelte.d.ts +3 -0
  63. package/dist/components/molecules/CodeEditor/CodeEditor.svelte +13 -10
  64. package/dist/components/molecules/ColorPicker/ColorPicker.svelte +167 -97
  65. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.stories.d.ts +9 -0
  66. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.stories.js +8 -0
  67. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.svelte +108 -0
  68. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.svelte.d.ts +18 -0
  69. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenuStory.svelte +15 -0
  70. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenuStory.svelte.d.ts +3 -0
  71. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.stories.d.ts +9 -0
  72. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.stories.js +8 -0
  73. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte +412 -0
  74. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanel.svelte.d.ts +14 -0
  75. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanelStory.svelte +27 -0
  76. package/dist/components/molecules/ConditionalFormatPanel/ConditionalFormatPanelStory.svelte.d.ts +3 -0
  77. package/dist/components/molecules/ConflictResolver/ConflictResolver.stories.js +8 -0
  78. package/dist/components/molecules/ConflictResolver/ConflictResolver.svelte +73 -0
  79. package/dist/components/molecules/ConflictResolver/ConflictResolver.svelte.d.ts +16 -0
  80. package/dist/components/molecules/ConflictResolver/ConflictResolverStory.svelte +11 -0
  81. package/dist/components/molecules/ConflictResolver/ConflictResolverStory.svelte.d.ts +18 -0
  82. package/dist/components/molecules/ContextMenu/ContextMenu.svelte +237 -41
  83. package/dist/components/molecules/ContextMenu/ContextMenu.svelte.d.ts +17 -1
  84. package/dist/components/molecules/DateTimePicker/DateTimePicker.svelte.d.ts +1 -1
  85. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.stories.d.ts +9 -0
  86. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.stories.js +8 -0
  87. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.svelte +56 -0
  88. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.svelte.d.ts +12 -0
  89. package/dist/components/molecules/ExpressionEditor/ExpressionEditorStory.svelte +12 -0
  90. package/dist/components/molecules/ExpressionEditor/ExpressionEditorStory.svelte.d.ts +3 -0
  91. package/dist/components/molecules/FilterList/FilterList.stories.d.ts +9 -0
  92. package/dist/components/molecules/FilterList/FilterList.stories.js +8 -0
  93. package/dist/components/molecules/FilterList/FilterList.svelte +101 -0
  94. package/dist/components/molecules/FilterList/FilterList.svelte.d.ts +18 -0
  95. package/dist/components/molecules/FilterList/FilterListStory.svelte +31 -0
  96. package/dist/components/molecules/FilterList/FilterListStory.svelte.d.ts +3 -0
  97. package/dist/components/molecules/FormDateTimePicker/FormDateTimePicker.svelte.d.ts +1 -1
  98. package/dist/components/molecules/Gauge/Gauge.stories.d.ts +1 -1
  99. package/dist/components/molecules/InfiniteScroll/InfiniteScroll.stories.d.ts +1 -1
  100. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.stories.d.ts +9 -0
  101. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.stories.js +8 -0
  102. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.svelte +94 -0
  103. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.svelte.d.ts +15 -0
  104. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowserStory.svelte +18 -0
  105. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowserStory.svelte.d.ts +3 -0
  106. package/dist/components/molecules/MediaAssetCard/MediaAssetCard.stories.js +8 -0
  107. package/dist/components/molecules/MediaAssetCard/MediaAssetCard.svelte +50 -0
  108. package/dist/components/molecules/MediaAssetCard/MediaAssetCard.svelte.d.ts +11 -0
  109. package/dist/components/molecules/MediaAssetCard/MediaAssetCardStory.svelte +13 -0
  110. package/dist/components/molecules/MediaAssetCard/MediaAssetCardStory.svelte.d.ts +18 -0
  111. package/dist/components/molecules/MediaLayerItem/MediaLayerItem.stories.js +8 -0
  112. package/dist/components/molecules/MediaLayerItem/MediaLayerItem.svelte +380 -0
  113. package/dist/components/molecules/MediaLayerItem/MediaLayerItem.svelte.d.ts +33 -0
  114. package/dist/components/molecules/MediaLayerItem/MediaLayerItemStory.svelte +14 -0
  115. package/dist/components/molecules/MediaLayerItem/MediaLayerItemStory.svelte.d.ts +18 -0
  116. package/dist/components/molecules/MediaLayerList/MediaLayerList.stories.d.ts +9 -0
  117. package/dist/components/molecules/MediaLayerList/MediaLayerList.stories.js +8 -0
  118. package/dist/components/molecules/MediaLayerList/MediaLayerList.svelte +399 -0
  119. package/dist/components/molecules/MediaLayerList/MediaLayerList.svelte.d.ts +37 -0
  120. package/dist/components/molecules/MediaLayerList/MediaLayerListStory.svelte +24 -0
  121. package/dist/components/molecules/MediaLayerList/MediaLayerListStory.svelte.d.ts +3 -0
  122. package/dist/components/molecules/MediaStage/MediaStage.stories.d.ts +9 -0
  123. package/dist/components/molecules/MediaStage/MediaStage.stories.js +8 -0
  124. package/dist/components/molecules/MediaStage/MediaStage.svelte +1498 -0
  125. package/dist/components/molecules/MediaStage/MediaStage.svelte.d.ts +45 -0
  126. package/dist/components/molecules/MediaStage/MediaStageStory.svelte +35 -0
  127. package/dist/components/molecules/MediaStage/MediaStageStory.svelte.d.ts +3 -0
  128. package/dist/components/molecules/MediaTimeline/MediaTimeline.stories.d.ts +9 -0
  129. package/dist/components/molecules/MediaTimeline/MediaTimeline.stories.js +8 -0
  130. package/dist/components/molecules/MediaTimeline/MediaTimeline.svelte +131 -0
  131. package/dist/components/molecules/MediaTimeline/MediaTimeline.svelte.d.ts +19 -0
  132. package/dist/components/molecules/MediaTimeline/MediaTimelineStory.svelte +20 -0
  133. package/dist/components/molecules/MediaTimeline/MediaTimelineStory.svelte.d.ts +3 -0
  134. package/dist/components/molecules/MixerChannel/MixerChannel.stories.d.ts +9 -0
  135. package/dist/components/molecules/MixerChannel/MixerChannel.stories.js +8 -0
  136. package/dist/components/molecules/MixerChannel/MixerChannel.svelte +92 -0
  137. package/dist/components/molecules/MixerChannel/MixerChannel.svelte.d.ts +11 -0
  138. package/dist/components/molecules/MixerChannel/MixerChannelStory.svelte +13 -0
  139. package/dist/components/molecules/MixerChannel/MixerChannelStory.svelte.d.ts +3 -0
  140. package/dist/components/molecules/NodeGraph/GraphBlueprintNode.svelte +454 -0
  141. package/dist/components/molecules/NodeGraph/GraphBlueprintNode.svelte.d.ts +8 -0
  142. package/dist/components/molecules/NodeGraph/GraphFlowBridge.svelte +26 -0
  143. package/dist/components/molecules/NodeGraph/GraphFlowBridge.svelte.d.ts +22 -0
  144. package/dist/components/molecules/NodeGraph/NodeGraph.stories.d.ts +12 -0
  145. package/dist/components/molecules/NodeGraph/NodeGraph.stories.js +9 -0
  146. package/dist/components/molecules/NodeGraph/NodeGraph.svelte +1409 -0
  147. package/dist/components/molecules/NodeGraph/NodeGraph.svelte.d.ts +33 -0
  148. package/dist/components/molecules/NodeGraph/NodeGraphStory.svelte +90 -0
  149. package/dist/components/molecules/NodeGraph/NodeGraphStory.svelte.d.ts +3 -0
  150. package/dist/components/molecules/NodePalette/NodePalette.stories.js +8 -0
  151. package/dist/components/molecules/NodePalette/NodePalette.svelte +86 -0
  152. package/dist/components/molecules/NodePalette/NodePalette.svelte.d.ts +11 -0
  153. package/dist/components/molecules/NodePalette/NodePaletteStory.svelte +11 -0
  154. package/dist/components/molecules/NodePalette/NodePaletteStory.svelte.d.ts +18 -0
  155. package/dist/components/molecules/Poll/Poll.stories.d.ts +1 -1
  156. package/dist/components/molecules/ProgramMonitor/ProgramMonitor.stories.js +8 -0
  157. package/dist/components/molecules/ProgramMonitor/ProgramMonitor.svelte +72 -0
  158. package/dist/components/molecules/ProgramMonitor/ProgramMonitor.svelte.d.ts +12 -0
  159. package/dist/components/molecules/ProgramMonitor/ProgramMonitorStory.svelte +16 -0
  160. package/dist/components/molecules/ProgramMonitor/ProgramMonitorStory.svelte.d.ts +18 -0
  161. package/dist/components/molecules/PropertyField/PropertyField.svelte +57 -3
  162. package/dist/components/molecules/PropertyField/PropertyField.svelte.d.ts +10 -0
  163. package/dist/components/molecules/PropertyField/PropertyFieldStory.svelte +21 -0
  164. package/dist/components/molecules/PropertyGroup/PropertyGroup.svelte +1 -1
  165. package/dist/components/molecules/QueryBuilder/QueryBuilder.stories.d.ts +9 -0
  166. package/dist/components/molecules/QueryBuilder/QueryBuilder.stories.js +8 -0
  167. package/dist/components/molecules/QueryBuilder/QueryBuilder.svelte +52 -0
  168. package/dist/components/molecules/QueryBuilder/QueryBuilder.svelte.d.ts +18 -0
  169. package/dist/components/molecules/QueryBuilder/QueryBuilderStory.svelte +62 -0
  170. package/dist/components/molecules/QueryBuilder/QueryBuilderStory.svelte.d.ts +3 -0
  171. package/dist/components/molecules/RelationPicker/RelationPicker.stories.d.ts +9 -0
  172. package/dist/components/molecules/RelationPicker/RelationPicker.stories.js +8 -0
  173. package/dist/components/molecules/RelationPicker/RelationPicker.svelte +180 -0
  174. package/dist/components/molecules/RelationPicker/RelationPicker.svelte.d.ts +24 -0
  175. package/dist/components/molecules/RelationPicker/RelationPickerStory.svelte +16 -0
  176. package/dist/components/molecules/RelationPicker/RelationPickerStory.svelte.d.ts +3 -0
  177. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.stories.d.ts +9 -0
  178. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.stories.js +8 -0
  179. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.svelte +154 -0
  180. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.svelte.d.ts +12 -0
  181. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilderStory.svelte +16 -0
  182. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilderStory.svelte.d.ts +3 -0
  183. package/dist/components/molecules/SecretField/SecretField.stories.d.ts +9 -0
  184. package/dist/components/molecules/SecretField/SecretField.stories.js +8 -0
  185. package/dist/components/molecules/SecretField/SecretField.svelte +58 -0
  186. package/dist/components/molecules/SecretField/SecretField.svelte.d.ts +15 -0
  187. package/dist/components/molecules/SecretField/SecretFieldStory.svelte +8 -0
  188. package/dist/components/molecules/SecretField/SecretFieldStory.svelte.d.ts +3 -0
  189. package/dist/components/molecules/SplitPane/SplitPane.svelte +96 -37
  190. package/dist/components/molecules/SplitPane/SplitPane.svelte.d.ts +10 -2
  191. package/dist/components/molecules/TableToolbar/TableToolbar.svelte.d.ts +1 -1
  192. package/dist/components/molecules/Terminal/Terminal.stories.js +20 -0
  193. package/dist/components/molecules/Terminal/Terminal.svelte +238 -0
  194. package/dist/components/molecules/Terminal/Terminal.svelte.d.ts +19 -0
  195. package/dist/components/molecules/Terminal/TerminalStory.svelte +47 -0
  196. package/dist/components/molecules/Terminal/TerminalStory.svelte.d.ts +6 -0
  197. package/dist/components/molecules/TimelineClip/TimelineClip.stories.js +8 -0
  198. package/dist/components/molecules/TimelineClip/TimelineClip.svelte +116 -0
  199. package/dist/components/molecules/TimelineClip/TimelineClip.svelte.d.ts +15 -0
  200. package/dist/components/molecules/TimelineClip/TimelineClipStory.svelte +18 -0
  201. package/dist/components/molecules/TimelineClip/TimelineClipStory.svelte.d.ts +18 -0
  202. package/dist/components/molecules/TimelineTrack/TimelineTrack.stories.js +8 -0
  203. package/dist/components/molecules/TimelineTrack/TimelineTrack.svelte +56 -0
  204. package/dist/components/molecules/TimelineTrack/TimelineTrack.svelte.d.ts +16 -0
  205. package/dist/components/molecules/TimelineTrack/TimelineTrackStory.svelte +35 -0
  206. package/dist/components/molecules/TimelineTrack/TimelineTrackStory.svelte.d.ts +18 -0
  207. package/dist/components/molecules/TraceWaterfall/TraceWaterfall.stories.js +8 -0
  208. package/dist/components/molecules/TraceWaterfall/TraceWaterfall.svelte +158 -0
  209. package/dist/components/molecules/TraceWaterfall/TraceWaterfall.svelte.d.ts +18 -0
  210. package/dist/components/molecules/TraceWaterfall/TraceWaterfallStory.svelte +55 -0
  211. package/dist/components/molecules/TraceWaterfall/TraceWaterfallStory.svelte.d.ts +18 -0
  212. package/dist/components/molecules/TrackHeader/TrackHeader.stories.d.ts +9 -0
  213. package/dist/components/molecules/TrackHeader/TrackHeader.stories.js +8 -0
  214. package/dist/components/molecules/TrackHeader/TrackHeader.svelte +54 -0
  215. package/dist/components/molecules/TrackHeader/TrackHeader.svelte.d.ts +9 -0
  216. package/dist/components/molecules/TrackHeader/TrackHeaderStory.svelte +10 -0
  217. package/dist/components/molecules/TrackHeader/TrackHeaderStory.svelte.d.ts +3 -0
  218. package/dist/components/molecules/TransportControls/TransportControls.stories.d.ts +9 -0
  219. package/dist/components/molecules/TransportControls/TransportControls.stories.js +8 -0
  220. package/dist/components/molecules/TransportControls/TransportControls.svelte +53 -0
  221. package/dist/components/molecules/TransportControls/TransportControls.svelte.d.ts +12 -0
  222. package/dist/components/molecules/TransportControls/TransportControlsStory.svelte +18 -0
  223. package/dist/components/molecules/TransportControls/TransportControlsStory.svelte.d.ts +3 -0
  224. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanel.stories.js +8 -0
  225. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanel.svelte +117 -0
  226. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanel.svelte.d.ts +20 -0
  227. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanelStory.svelte +36 -0
  228. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanelStory.svelte.d.ts +18 -0
  229. package/dist/components/molecules/VideoPlayer/VideoPlayer.stories.d.ts +1 -1
  230. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.stories.d.ts +9 -0
  231. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.stories.js +8 -0
  232. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.svelte +59 -0
  233. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.svelte.d.ts +9 -0
  234. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeaderStory.svelte +10 -0
  235. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeaderStory.svelte.d.ts +3 -0
  236. package/dist/components/molecules/WaveformRegion/WaveformRegion.stories.js +8 -0
  237. package/dist/components/molecules/WaveformRegion/WaveformRegion.svelte +82 -0
  238. package/dist/components/molecules/WaveformRegion/WaveformRegion.svelte.d.ts +13 -0
  239. package/dist/components/molecules/WaveformRegion/WaveformRegionStory.svelte +17 -0
  240. package/dist/components/molecules/WaveformRegion/WaveformRegionStory.svelte.d.ts +18 -0
  241. package/dist/components/molecules/WidgetCanvas/WidgetCanvas.svelte +13 -4
  242. package/dist/components/molecules/WidgetCanvas/WidgetCanvas.svelte.d.ts +3 -1
  243. package/dist/components/molecules/WidgetCanvas/widgetCanvasContext.d.ts +2 -0
  244. package/dist/components/molecules/WidgetFrame/WidgetFrame.svelte +206 -37
  245. package/dist/components/molecules/WidgetFrame/WidgetFrame.svelte.d.ts +31 -0
  246. package/dist/components/organisms/AssetPickerPage/AssetPickerPage.svelte.d.ts +1 -1
  247. package/dist/components/organisms/AudioEditor/AudioEditor.stories.d.ts +12 -0
  248. package/dist/components/organisms/AudioEditor/AudioEditor.stories.js +9 -0
  249. package/dist/components/organisms/AudioEditor/AudioEditor.svelte +273 -0
  250. package/dist/components/organisms/AudioEditor/AudioEditor.svelte.d.ts +13 -0
  251. package/dist/components/organisms/AudioEditor/AudioEditorStory.svelte +10 -0
  252. package/dist/components/organisms/AudioEditor/AudioEditorStory.svelte.d.ts +3 -0
  253. package/dist/components/organisms/BacklogPage/BacklogPage.svelte.d.ts +1 -1
  254. package/dist/components/organisms/BlogEditor/BlogEditor.stories.d.ts +12 -0
  255. package/dist/components/organisms/BlogEditor/BlogEditor.stories.js +9 -0
  256. package/dist/components/organisms/BlogEditor/BlogEditor.svelte +1208 -0
  257. package/dist/components/organisms/BlogEditor/BlogEditor.svelte.d.ts +16 -0
  258. package/dist/components/organisms/BlogEditor/BlogEditorStory.svelte +144 -0
  259. package/dist/components/organisms/BlogEditor/BlogEditorStory.svelte.d.ts +3 -0
  260. package/dist/components/organisms/BlogEditor/DemoBlogCard.svelte +28 -0
  261. package/dist/components/organisms/BlogEditor/DemoBlogCard.svelte.d.ts +10 -0
  262. package/dist/components/organisms/BlogEditor/DemoBlogStats.svelte +34 -0
  263. package/dist/components/organisms/BlogEditor/DemoBlogStats.svelte.d.ts +11 -0
  264. package/dist/components/organisms/BlogEditor/DemoBlogWidget.svelte +13 -0
  265. package/dist/components/organisms/BlogEditor/DemoBlogWidget.svelte.d.ts +8 -0
  266. package/dist/components/organisms/BlogRenderer/BlogRenderer.stories.js +8 -0
  267. package/dist/components/organisms/BlogRenderer/BlogRenderer.svelte +469 -0
  268. package/dist/components/organisms/BlogRenderer/BlogRenderer.svelte.d.ts +14 -0
  269. package/dist/components/organisms/BlogRenderer/BlogRendererStory.svelte +20 -0
  270. package/dist/components/organisms/BlogRenderer/BlogRendererStory.svelte.d.ts +18 -0
  271. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.stories.d.ts +12 -0
  272. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.stories.js +9 -0
  273. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.svelte +1012 -0
  274. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.svelte.d.ts +16 -0
  275. package/dist/components/organisms/BlueprintEditor/BlueprintEditorStory.svelte +76 -0
  276. package/dist/components/organisms/BlueprintEditor/BlueprintEditorStory.svelte.d.ts +3 -0
  277. package/dist/components/organisms/CalendarApp/CalendarApp.svelte.d.ts +1 -1
  278. package/dist/components/organisms/CanvasEditor/CanvasEditor.stories.d.ts +12 -0
  279. package/dist/components/organisms/CanvasEditor/CanvasEditor.stories.js +9 -0
  280. package/dist/components/organisms/CanvasEditor/CanvasEditor.svelte +1680 -0
  281. package/dist/components/organisms/CanvasEditor/CanvasEditor.svelte.d.ts +18 -0
  282. package/dist/components/organisms/CanvasEditor/CanvasEditorStory.svelte +329 -0
  283. package/dist/components/organisms/CanvasEditor/CanvasEditorStory.svelte.d.ts +3 -0
  284. package/dist/components/organisms/DashboardBuilderPage/DashboardBuilderPage.svelte.d.ts +1 -1
  285. package/dist/components/organisms/DataGrid/DataGrid.stories.d.ts +65 -0
  286. package/dist/components/organisms/DataGrid/DataGrid.stories.js +95 -0
  287. package/dist/components/organisms/DataGrid/DataGrid.svelte +2264 -0
  288. package/dist/components/organisms/DataGrid/DataGrid.svelte.d.ts +99 -0
  289. package/dist/components/organisms/DataGrid/DataGridStory.svelte +659 -0
  290. package/dist/components/organisms/DataGrid/DataGridStory.svelte.d.ts +11 -0
  291. package/dist/components/organisms/DataGrid/breakpoints.d.ts +10 -0
  292. package/dist/components/organisms/DataGrid/breakpoints.js +20 -0
  293. package/dist/components/organisms/DataGrid/cellEditors.d.ts +8 -0
  294. package/dist/components/organisms/DataGrid/cellEditors.js +59 -0
  295. package/dist/components/organisms/DataGrid/conditionalFormat.d.ts +11 -0
  296. package/dist/components/organisms/DataGrid/conditionalFormat.js +98 -0
  297. package/dist/components/organisms/DataGrid/filterRows.d.ts +5 -0
  298. package/dist/components/organisms/DataGrid/filterRows.js +60 -0
  299. package/dist/components/organisms/DataGrid/marks.d.ts +9 -0
  300. package/dist/components/organisms/DataGrid/marks.js +91 -0
  301. package/dist/components/organisms/DataGrid/types.d.ts +126 -0
  302. package/dist/components/organisms/DataGrid/types.js +21 -0
  303. package/dist/components/organisms/DesktopShell/DesktopShell.svelte.d.ts +1 -1
  304. package/dist/components/organisms/EditorShell/EditorShell.svelte +123 -28
  305. package/dist/components/organisms/EditorShell/EditorShell.svelte.d.ts +21 -1
  306. package/dist/components/organisms/FileUploader/FileUploader.svelte +77 -15
  307. package/dist/components/organisms/FileUploader/FileUploader.svelte.d.ts +11 -0
  308. package/dist/components/organisms/ImportWizard/ImportWizard.stories.js +8 -0
  309. package/dist/components/organisms/ImportWizard/ImportWizard.svelte +209 -0
  310. package/dist/components/organisms/ImportWizard/ImportWizard.svelte.d.ts +22 -0
  311. package/dist/components/organisms/ImportWizard/ImportWizardStory.svelte +16 -0
  312. package/dist/components/organisms/ImportWizard/ImportWizardStory.svelte.d.ts +18 -0
  313. package/dist/components/organisms/ResourceStudio/ResourceStudio.stories.d.ts +33 -0
  314. package/dist/components/organisms/ResourceStudio/ResourceStudio.stories.js +56 -0
  315. package/dist/components/organisms/ResourceStudio/ResourceStudio.svelte +830 -0
  316. package/dist/components/organisms/ResourceStudio/ResourceStudio.svelte.d.ts +68 -0
  317. package/dist/components/organisms/ResourceStudio/ResourceStudioStory.svelte +600 -0
  318. package/dist/components/organisms/ResourceStudio/ResourceStudioStory.svelte.d.ts +7 -0
  319. package/dist/components/organisms/ResourceStudio/fieldsToColumns.d.ts +4 -0
  320. package/dist/components/organisms/ResourceStudio/fieldsToColumns.js +20 -0
  321. package/dist/components/organisms/ResourceStudio/fieldsToSchema.d.ts +6 -0
  322. package/dist/components/organisms/ResourceStudio/fieldsToSchema.js +53 -0
  323. package/dist/components/organisms/ResourceStudio/types.d.ts +69 -0
  324. package/dist/components/organisms/ResourceStudio/types.js +15 -0
  325. package/dist/components/organisms/Scheduler/Scheduler.svelte.d.ts +1 -1
  326. package/dist/components/organisms/SchemaForm/SchemaForm.svelte +10 -3
  327. package/dist/components/organisms/SchemaForm/SchemaForm.svelte.d.ts +1 -0
  328. package/dist/components/organisms/VideoEditor/VideoEditor.stories.d.ts +12 -0
  329. package/dist/components/organisms/VideoEditor/VideoEditor.stories.js +9 -0
  330. package/dist/components/organisms/VideoEditor/VideoEditor.svelte +308 -0
  331. package/dist/components/organisms/VideoEditor/VideoEditor.svelte.d.ts +13 -0
  332. package/dist/components/organisms/VideoEditor/VideoEditorStory.svelte +10 -0
  333. package/dist/components/organisms/VideoEditor/VideoEditorStory.svelte.d.ts +3 -0
  334. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.stories.d.ts +12 -0
  335. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.stories.js +9 -0
  336. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.svelte +22 -0
  337. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.svelte.d.ts +13 -0
  338. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplateStory.svelte +8 -0
  339. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplateStory.svelte.d.ts +3 -0
  340. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.stories.d.ts +12 -0
  341. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.stories.js +9 -0
  342. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.svelte +32 -0
  343. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.svelte.d.ts +17 -0
  344. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplateStory.svelte +21 -0
  345. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplateStory.svelte.d.ts +3 -0
  346. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.stories.d.ts +25 -0
  347. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.stories.js +18 -0
  348. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte +192 -0
  349. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplate.svelte.d.ts +62 -0
  350. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplateStory.svelte +129 -0
  351. package/dist/components/templates/ResourceStudioTemplate/ResourceStudioTemplateStory.svelte.d.ts +7 -0
  352. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.stories.d.ts +12 -0
  353. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.stories.js +9 -0
  354. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.svelte +22 -0
  355. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.svelte.d.ts +13 -0
  356. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplateStory.svelte +8 -0
  357. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplateStory.svelte.d.ts +3 -0
  358. package/dist/index.d.ts +94 -1
  359. package/dist/index.js +68 -0
  360. package/dist/types/xyflow-svelte.d.ts +62 -0
  361. package/dist/utils/audioProject.d.ts +19 -0
  362. package/dist/utils/audioProject.js +70 -0
  363. package/dist/utils/blogDocument.d.ts +175 -0
  364. package/dist/utils/blogDocument.js +220 -0
  365. package/dist/utils/blueprintRuntime.d.ts +34 -0
  366. package/dist/utils/blueprintRuntime.js +289 -0
  367. package/dist/utils/canvasDocument.d.ts +239 -0
  368. package/dist/utils/canvasDocument.js +443 -0
  369. package/dist/utils/canvasExport.d.ts +10 -0
  370. package/dist/utils/canvasExport.js +469 -0
  371. package/dist/utils/canvasHierarchy.d.ts +189 -0
  372. package/dist/utils/canvasHierarchy.js +674 -0
  373. package/dist/utils/canvasHistory.d.ts +19 -0
  374. package/dist/utils/canvasHistory.js +48 -0
  375. package/dist/utils/canvasWidget.d.ts +81 -0
  376. package/dist/utils/canvasWidget.js +597 -0
  377. package/dist/utils/marqueeSelect.d.ts +48 -0
  378. package/dist/utils/marqueeSelect.js +189 -0
  379. package/dist/utils/mediaTime.d.ts +16 -0
  380. package/dist/utils/mediaTime.js +57 -0
  381. package/dist/utils/mediaTracks.d.ts +61 -0
  382. package/dist/utils/mediaTracks.js +102 -0
  383. package/dist/utils/nodeGraph.d.ts +354 -0
  384. package/dist/utils/nodeGraph.js +1453 -0
  385. package/dist/utils/queryBridge.d.ts +18 -0
  386. package/dist/utils/queryBridge.js +118 -0
  387. package/dist/utils/videoSequence.d.ts +13 -0
  388. package/dist/utils/videoSequence.js +63 -0
  389. package/package.json +5 -2
@@ -0,0 +1,1208 @@
1
+ <script lang="ts">
2
+ import Button from '../../atoms/Button/Button.svelte';
3
+ import Input from '../../atoms/Input/Input.svelte';
4
+ import Textarea from '../../atoms/Textarea/Textarea.svelte';
5
+ import Select from '../../molecules/Select/Select.svelte';
6
+ import JSONViewer from '../../molecules/JSONViewer/JSONViewer.svelte';
7
+ import {
8
+ NATIVE_BLOCK_TYPES,
9
+ createBlock,
10
+ createComponentBlock,
11
+ emptyBlogDocument,
12
+ getBlogComponent,
13
+ listBlogComponents,
14
+ type BlogAlign,
15
+ type BlogBlock,
16
+ type BlogBlockType,
17
+ type BlogCalloutData,
18
+ type BlogCodeData,
19
+ type BlogComponentData,
20
+ type BlogCtaData,
21
+ type BlogDividerData,
22
+ type BlogDocument,
23
+ type BlogEmbedData,
24
+ type BlogGalleryData,
25
+ type BlogHeadingData,
26
+ type BlogHtmlData,
27
+ type BlogImageData,
28
+ type BlogListData,
29
+ type BlogMarkdownData,
30
+ type BlogParagraphData,
31
+ type BlogQuoteData,
32
+ type BlogSpacerData,
33
+ type BlogTableData,
34
+ type BlogVideoData,
35
+ type BlogWidth
36
+ } from '../../../utils/blogDocument.js';
37
+
38
+ export type { BlogDocument, BlogBlock, BlogBlockType };
39
+
40
+ interface BlogEditorProps {
41
+ value?: BlogDocument;
42
+ showJson?: boolean;
43
+ showMeta?: boolean;
44
+ compact?: boolean;
45
+ class?: string;
46
+ onchange?: (doc: BlogDocument) => void;
47
+ }
48
+
49
+ let {
50
+ value = $bindable(emptyBlogDocument()),
51
+ showJson = true,
52
+ showMeta = true,
53
+ compact = false,
54
+ class: className = '',
55
+ onchange
56
+ }: BlogEditorProps = $props();
57
+
58
+ let addMenuOpen = $state(false);
59
+ let componentMenuOpen = $state(false);
60
+ let metaOpen = $state(true);
61
+
62
+ const registered = $derived(listBlogComponents());
63
+ const blockGroups = $derived(
64
+ NATIVE_BLOCK_TYPES.reduce(
65
+ (acc, item) => {
66
+ (acc[item.group] ??= []).push(item);
67
+ return acc;
68
+ },
69
+ {} as Record<string, typeof NATIVE_BLOCK_TYPES>
70
+ )
71
+ );
72
+
73
+ const ALIGN_OPTS = [
74
+ { value: 'left', label: 'Left' },
75
+ { value: 'center', label: 'Center' },
76
+ { value: 'right', label: 'Right' }
77
+ ];
78
+ const WIDTH_OPTS = [
79
+ { value: 'narrow', label: 'Narrow' },
80
+ { value: 'content', label: 'Content' },
81
+ { value: 'wide', label: 'Wide' },
82
+ { value: 'full', label: 'Full' }
83
+ ];
84
+
85
+ function emit(next: BlogDocument) {
86
+ value = next;
87
+ onchange?.(next);
88
+ }
89
+
90
+ function patchMeta(patch: Partial<BlogDocument>) {
91
+ emit({ ...value, ...patch });
92
+ }
93
+
94
+ function addNative(type: Exclude<BlogBlockType, 'component'>) {
95
+ emit({ ...value, blocks: [...value.blocks, createBlock(type)] });
96
+ addMenuOpen = false;
97
+ }
98
+
99
+ function addComponent(id: string) {
100
+ emit({ ...value, blocks: [...value.blocks, createComponentBlock(id)] });
101
+ componentMenuOpen = false;
102
+ }
103
+
104
+ function updateBlock(id: string, data: BlogBlock['data']) {
105
+ emit({
106
+ ...value,
107
+ blocks: value.blocks.map((b) => (b.id === id ? { ...b, data } : b))
108
+ });
109
+ }
110
+
111
+ function removeBlock(id: string) {
112
+ emit({ ...value, blocks: value.blocks.filter((b) => b.id !== id) });
113
+ }
114
+
115
+ function duplicateBlock(id: string) {
116
+ const idx = value.blocks.findIndex((b) => b.id === id);
117
+ if (idx < 0) return;
118
+ const copy = createBlock(value.blocks[idx].type, {
119
+ ...(value.blocks[idx].data as object)
120
+ } as never);
121
+ const blocks = [...value.blocks];
122
+ blocks.splice(idx + 1, 0, copy);
123
+ emit({ ...value, blocks });
124
+ }
125
+
126
+ function moveBlock(id: string, dir: -1 | 1) {
127
+ const idx = value.blocks.findIndex((b) => b.id === id);
128
+ if (idx < 0) return;
129
+ const nextIdx = idx + dir;
130
+ if (nextIdx < 0 || nextIdx >= value.blocks.length) return;
131
+ const blocks = [...value.blocks];
132
+ const [item] = blocks.splice(idx, 1);
133
+ blocks.splice(nextIdx, 0, item);
134
+ emit({ ...value, blocks });
135
+ }
136
+
137
+ function blockLabel(type: string): string {
138
+ return NATIVE_BLOCK_TYPES.find((t) => t.type === type)?.label ?? type;
139
+ }
140
+
141
+ function updateComponentProp(blockId: string, data: BlogComponentData, key: string, raw: unknown) {
142
+ updateBlock(blockId, {
143
+ ...data,
144
+ props: { ...(data.props ?? {}), [key]: raw }
145
+ });
146
+ }
147
+ </script>
148
+
149
+ <div
150
+ class={[
151
+ 'flex flex-col gap-4 border border-border bg-surface-elevated',
152
+ compact ? 'rounded-lg p-3' : 'rounded-xl p-4',
153
+ className
154
+ ]}
155
+ data-blog-editor
156
+ >
157
+ <div class="flex flex-wrap items-center gap-2">
158
+ <Input
159
+ value={value.title ?? ''}
160
+ placeholder="Post title"
161
+ class="min-w-[12rem] flex-1"
162
+ oninput={(e) => patchMeta({ title: (e.currentTarget as HTMLInputElement).value })}
163
+ />
164
+ {#if showMeta}
165
+ <Button size="sm" variant="ghost" onclick={() => (metaOpen = !metaOpen)}>
166
+ {metaOpen ? 'Hide meta' : 'Meta'}
167
+ </Button>
168
+ {/if}
169
+ <div class="relative">
170
+ <Button size="sm" variant="secondary" onclick={() => (addMenuOpen = !addMenuOpen)}>
171
+ Add block
172
+ </Button>
173
+ {#if addMenuOpen}
174
+ <div
175
+ class="absolute right-0 z-20 mt-1 max-h-80 w-56 overflow-auto rounded-xl border border-border bg-surface-elevated py-1 shadow-lg"
176
+ >
177
+ {#each Object.entries(blockGroups) as [group, items] (group)}
178
+ <p class="px-3 pb-0.5 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted">
179
+ {group}
180
+ </p>
181
+ {#each items as item (item.type)}
182
+ <button
183
+ type="button"
184
+ class="block w-full px-3 py-1.5 text-left text-sm text-primary hover:bg-surface-overlay"
185
+ onclick={() => addNative(item.type)}
186
+ >
187
+ {item.label}
188
+ </button>
189
+ {/each}
190
+ {/each}
191
+ </div>
192
+ {/if}
193
+ </div>
194
+ {#if registered.length}
195
+ <div class="relative">
196
+ <Button
197
+ size="sm"
198
+ variant="secondary"
199
+ onclick={() => (componentMenuOpen = !componentMenuOpen)}
200
+ >
201
+ Add component
202
+ </Button>
203
+ {#if componentMenuOpen}
204
+ <div
205
+ class="absolute right-0 z-20 mt-1 w-60 overflow-hidden rounded-xl border border-border bg-surface-elevated py-1 shadow-lg"
206
+ >
207
+ {#each registered as item (item.id)}
208
+ <button
209
+ type="button"
210
+ class="block w-full px-3 py-1.5 text-left hover:bg-surface-overlay"
211
+ onclick={() => addComponent(item.id)}
212
+ >
213
+ <span class="block text-sm text-primary">{item.registration.label}</span>
214
+ {#if item.registration.description}
215
+ <span class="block text-[11px] text-muted">{item.registration.description}</span>
216
+ {/if}
217
+ </button>
218
+ {/each}
219
+ </div>
220
+ {/if}
221
+ </div>
222
+ {/if}
223
+ </div>
224
+
225
+ {#if showMeta && metaOpen}
226
+ <div class="grid gap-2 rounded-xl border border-border bg-surface-overlay/30 p-3 sm:grid-cols-2">
227
+ <Input
228
+ value={value.description ?? ''}
229
+ placeholder="Description / deck"
230
+ class="sm:col-span-2"
231
+ oninput={(e) => patchMeta({ description: (e.currentTarget as HTMLInputElement).value })}
232
+ />
233
+ <Input
234
+ value={value.author ?? ''}
235
+ placeholder="Author"
236
+ oninput={(e) => patchMeta({ author: (e.currentTarget as HTMLInputElement).value })}
237
+ />
238
+ <Input
239
+ value={value.publishedAt ?? ''}
240
+ placeholder="Published at (ISO or text)"
241
+ oninput={(e) => patchMeta({ publishedAt: (e.currentTarget as HTMLInputElement).value })}
242
+ />
243
+ <Input
244
+ value={value.coverImage ?? ''}
245
+ placeholder="Cover image URL"
246
+ class="sm:col-span-2"
247
+ oninput={(e) => patchMeta({ coverImage: (e.currentTarget as HTMLInputElement).value })}
248
+ />
249
+ <Input
250
+ value={(value.tags ?? []).join(', ')}
251
+ placeholder="Tags (comma separated)"
252
+ class="sm:col-span-2"
253
+ oninput={(e) =>
254
+ patchMeta({
255
+ tags: (e.currentTarget as HTMLInputElement).value
256
+ .split(',')
257
+ .map((t) => t.trim())
258
+ .filter(Boolean)
259
+ })}
260
+ />
261
+ </div>
262
+ {/if}
263
+
264
+ {#if value.blocks.length === 0}
265
+ <p class="rounded-lg border border-dashed border-border px-3 py-8 text-center text-sm text-muted">
266
+ No blocks yet. Add a block or component to start.
267
+ </p>
268
+ {:else}
269
+ <ul class="flex flex-col gap-3">
270
+ {#each value.blocks as block, i (block.id)}
271
+ <li class="rounded-xl border border-border bg-surface-overlay/40 p-3">
272
+ <div class="mb-2 flex items-center justify-between gap-2">
273
+ <span class="text-[11px] font-semibold uppercase tracking-wide text-muted">
274
+ {blockLabel(block.type)}
275
+ </span>
276
+ <div class="flex items-center gap-1">
277
+ <Button
278
+ size="sm"
279
+ variant="ghost"
280
+ disabled={i === 0}
281
+ onclick={() => moveBlock(block.id, -1)}
282
+ >
283
+
284
+ </Button>
285
+ <Button
286
+ size="sm"
287
+ variant="ghost"
288
+ disabled={i === value.blocks.length - 1}
289
+ onclick={() => moveBlock(block.id, 1)}
290
+ >
291
+
292
+ </Button>
293
+ <Button size="sm" variant="ghost" onclick={() => duplicateBlock(block.id)}>
294
+ Duplicate
295
+ </Button>
296
+ <Button size="sm" variant="ghost" onclick={() => removeBlock(block.id)}>
297
+ Remove
298
+ </Button>
299
+ </div>
300
+ </div>
301
+
302
+ {#if block.type === 'heading'}
303
+ {@const data = block.data as BlogHeadingData}
304
+ <div class="flex flex-col gap-2">
305
+ <div class="flex flex-wrap gap-2">
306
+ <Select
307
+ value={String(data.level)}
308
+ options={[
309
+ { value: '1', label: 'H1' },
310
+ { value: '2', label: 'H2' },
311
+ { value: '3', label: 'H3' },
312
+ { value: '4', label: 'H4' }
313
+ ]}
314
+ onchange={(v) =>
315
+ updateBlock(block.id, {
316
+ ...data,
317
+ level: Number(v) as BlogHeadingData['level']
318
+ })}
319
+ class="w-24"
320
+ />
321
+ <Select
322
+ value={data.align ?? 'left'}
323
+ options={ALIGN_OPTS}
324
+ onchange={(v) => updateBlock(block.id, { ...data, align: v as BlogAlign })}
325
+ class="w-28"
326
+ />
327
+ <Input
328
+ value={data.anchor ?? ''}
329
+ placeholder="Anchor id"
330
+ class="w-36"
331
+ oninput={(e) =>
332
+ updateBlock(block.id, {
333
+ ...data,
334
+ anchor: (e.currentTarget as HTMLInputElement).value
335
+ })}
336
+ />
337
+ </div>
338
+ <Input
339
+ value={data.text}
340
+ oninput={(e) =>
341
+ updateBlock(block.id, {
342
+ ...data,
343
+ text: (e.currentTarget as HTMLInputElement).value
344
+ })}
345
+ />
346
+ </div>
347
+ {:else if block.type === 'paragraph'}
348
+ {@const data = block.data as BlogParagraphData}
349
+ <div class="flex flex-col gap-2">
350
+ <div class="flex flex-wrap items-center gap-3">
351
+ <Select
352
+ value={data.align ?? 'left'}
353
+ options={ALIGN_OPTS}
354
+ onchange={(v) => updateBlock(block.id, { ...data, align: v as BlogAlign })}
355
+ class="w-28"
356
+ />
357
+ <label class="flex items-center gap-1.5 text-xs text-muted">
358
+ <input
359
+ type="checkbox"
360
+ checked={!!data.lead}
361
+ onchange={(e) =>
362
+ updateBlock(block.id, {
363
+ ...data,
364
+ lead: (e.currentTarget as HTMLInputElement).checked
365
+ })}
366
+ />
367
+ Lead
368
+ </label>
369
+ <label class="flex items-center gap-1.5 text-xs text-muted">
370
+ <input
371
+ type="checkbox"
372
+ checked={!!data.muted}
373
+ onchange={(e) =>
374
+ updateBlock(block.id, {
375
+ ...data,
376
+ muted: (e.currentTarget as HTMLInputElement).checked
377
+ })}
378
+ />
379
+ Muted
380
+ </label>
381
+ </div>
382
+ <Textarea
383
+ value={data.text}
384
+ rows={3}
385
+ oninput={(e) =>
386
+ updateBlock(block.id, {
387
+ ...data,
388
+ text: (e.currentTarget as HTMLTextAreaElement).value
389
+ })}
390
+ />
391
+ </div>
392
+ {:else if block.type === 'image'}
393
+ {@const data = block.data as BlogImageData}
394
+ <div class="grid gap-2 sm:grid-cols-2">
395
+ <Input
396
+ value={data.src}
397
+ placeholder="Image URL"
398
+ class="sm:col-span-2"
399
+ oninput={(e) =>
400
+ updateBlock(block.id, {
401
+ ...data,
402
+ src: (e.currentTarget as HTMLInputElement).value
403
+ })}
404
+ />
405
+ <Input
406
+ value={data.alt ?? ''}
407
+ placeholder="Alt text"
408
+ oninput={(e) =>
409
+ updateBlock(block.id, {
410
+ ...data,
411
+ alt: (e.currentTarget as HTMLInputElement).value
412
+ })}
413
+ />
414
+ <Input
415
+ value={data.caption ?? ''}
416
+ placeholder="Caption"
417
+ oninput={(e) =>
418
+ updateBlock(block.id, {
419
+ ...data,
420
+ caption: (e.currentTarget as HTMLInputElement).value
421
+ })}
422
+ />
423
+ <Input
424
+ value={data.href ?? ''}
425
+ placeholder="Link URL (optional)"
426
+ class="sm:col-span-2"
427
+ oninput={(e) =>
428
+ updateBlock(block.id, {
429
+ ...data,
430
+ href: (e.currentTarget as HTMLInputElement).value
431
+ })}
432
+ />
433
+ <Select
434
+ value={data.align ?? 'center'}
435
+ options={ALIGN_OPTS}
436
+ onchange={(v) => updateBlock(block.id, { ...data, align: v as BlogAlign })}
437
+ />
438
+ <Select
439
+ value={data.width ?? 'content'}
440
+ options={WIDTH_OPTS}
441
+ onchange={(v) => updateBlock(block.id, { ...data, width: v as BlogWidth })}
442
+ />
443
+ <label class="flex items-center gap-1.5 text-xs text-muted">
444
+ <input
445
+ type="checkbox"
446
+ checked={data.rounded !== false}
447
+ onchange={(e) =>
448
+ updateBlock(block.id, {
449
+ ...data,
450
+ rounded: (e.currentTarget as HTMLInputElement).checked
451
+ })}
452
+ />
453
+ Rounded
454
+ </label>
455
+ <label class="flex items-center gap-1.5 text-xs text-muted">
456
+ <input
457
+ type="checkbox"
458
+ checked={!!data.shadow}
459
+ onchange={(e) =>
460
+ updateBlock(block.id, {
461
+ ...data,
462
+ shadow: (e.currentTarget as HTMLInputElement).checked
463
+ })}
464
+ />
465
+ Shadow
466
+ </label>
467
+ </div>
468
+ {:else if block.type === 'code'}
469
+ {@const data = block.data as BlogCodeData}
470
+ <div class="flex flex-col gap-2">
471
+ <div class="flex flex-wrap gap-2">
472
+ <Input
473
+ value={data.language ?? ''}
474
+ placeholder="Language"
475
+ class="w-36"
476
+ oninput={(e) =>
477
+ updateBlock(block.id, {
478
+ ...data,
479
+ language: (e.currentTarget as HTMLInputElement).value
480
+ })}
481
+ />
482
+ <Input
483
+ value={data.filename ?? ''}
484
+ placeholder="Filename"
485
+ class="flex-1"
486
+ oninput={(e) =>
487
+ updateBlock(block.id, {
488
+ ...data,
489
+ filename: (e.currentTarget as HTMLInputElement).value
490
+ })}
491
+ />
492
+ <label class="flex items-center gap-1.5 text-xs text-muted">
493
+ <input
494
+ type="checkbox"
495
+ checked={!!data.showLineNumbers}
496
+ onchange={(e) =>
497
+ updateBlock(block.id, {
498
+ ...data,
499
+ showLineNumbers: (e.currentTarget as HTMLInputElement).checked
500
+ })}
501
+ />
502
+ Line numbers
503
+ </label>
504
+ </div>
505
+ <Input
506
+ value={data.highlightLines ?? ''}
507
+ placeholder="Highlight lines (e.g. 1,3-5)"
508
+ oninput={(e) =>
509
+ updateBlock(block.id, {
510
+ ...data,
511
+ highlightLines: (e.currentTarget as HTMLInputElement).value
512
+ })}
513
+ />
514
+ <Textarea
515
+ value={data.code}
516
+ rows={6}
517
+ class="font-mono text-xs"
518
+ oninput={(e) =>
519
+ updateBlock(block.id, {
520
+ ...data,
521
+ code: (e.currentTarget as HTMLTextAreaElement).value
522
+ })}
523
+ />
524
+ </div>
525
+ {:else if block.type === 'callout'}
526
+ {@const data = block.data as BlogCalloutData}
527
+ <div class="flex flex-col gap-2">
528
+ <div class="flex flex-wrap gap-2">
529
+ <Select
530
+ value={data.tone ?? 'info'}
531
+ options={[
532
+ { value: 'info', label: 'Info' },
533
+ { value: 'success', label: 'Success' },
534
+ { value: 'warning', label: 'Warning' },
535
+ { value: 'danger', label: 'Danger' },
536
+ { value: 'neutral', label: 'Neutral' }
537
+ ]}
538
+ onchange={(v) =>
539
+ updateBlock(block.id, {
540
+ ...data,
541
+ tone: v as BlogCalloutData['tone']
542
+ })}
543
+ class="w-36"
544
+ />
545
+ <label class="flex items-center gap-1.5 text-xs text-muted">
546
+ <input
547
+ type="checkbox"
548
+ checked={!!data.collapsible}
549
+ onchange={(e) =>
550
+ updateBlock(block.id, {
551
+ ...data,
552
+ collapsible: (e.currentTarget as HTMLInputElement).checked
553
+ })}
554
+ />
555
+ Collapsible
556
+ </label>
557
+ </div>
558
+ <Input
559
+ value={data.title ?? ''}
560
+ placeholder="Title"
561
+ oninput={(e) =>
562
+ updateBlock(block.id, {
563
+ ...data,
564
+ title: (e.currentTarget as HTMLInputElement).value
565
+ })}
566
+ />
567
+ <Textarea
568
+ value={data.text}
569
+ rows={3}
570
+ oninput={(e) =>
571
+ updateBlock(block.id, {
572
+ ...data,
573
+ text: (e.currentTarget as HTMLTextAreaElement).value
574
+ })}
575
+ />
576
+ </div>
577
+ {:else if block.type === 'quote'}
578
+ {@const data = block.data as BlogQuoteData}
579
+ <div class="flex flex-col gap-2">
580
+ <Select
581
+ value={data.align ?? 'left'}
582
+ options={ALIGN_OPTS}
583
+ onchange={(v) => updateBlock(block.id, { ...data, align: v as BlogAlign })}
584
+ class="w-28"
585
+ />
586
+ <Textarea
587
+ value={data.text}
588
+ rows={3}
589
+ oninput={(e) =>
590
+ updateBlock(block.id, {
591
+ ...data,
592
+ text: (e.currentTarget as HTMLTextAreaElement).value
593
+ })}
594
+ />
595
+ <div class="flex gap-2">
596
+ <Input
597
+ value={data.cite ?? ''}
598
+ placeholder="Author"
599
+ class="flex-1"
600
+ oninput={(e) =>
601
+ updateBlock(block.id, {
602
+ ...data,
603
+ cite: (e.currentTarget as HTMLInputElement).value
604
+ })}
605
+ />
606
+ <Input
607
+ value={data.role ?? ''}
608
+ placeholder="Role"
609
+ class="flex-1"
610
+ oninput={(e) =>
611
+ updateBlock(block.id, {
612
+ ...data,
613
+ role: (e.currentTarget as HTMLInputElement).value
614
+ })}
615
+ />
616
+ </div>
617
+ </div>
618
+ {:else if block.type === 'list'}
619
+ {@const data = block.data as BlogListData}
620
+ <div class="flex flex-col gap-2">
621
+ <div class="flex flex-wrap items-center gap-3">
622
+ <label class="flex items-center gap-2 text-xs text-muted">
623
+ <input
624
+ type="checkbox"
625
+ checked={!!data.ordered}
626
+ onchange={(e) =>
627
+ updateBlock(block.id, {
628
+ ...data,
629
+ ordered: (e.currentTarget as HTMLInputElement).checked
630
+ })}
631
+ />
632
+ Ordered
633
+ </label>
634
+ <label class="flex items-center gap-2 text-xs text-muted">
635
+ <input
636
+ type="checkbox"
637
+ checked={!!data.tight}
638
+ onchange={(e) =>
639
+ updateBlock(block.id, {
640
+ ...data,
641
+ tight: (e.currentTarget as HTMLInputElement).checked
642
+ })}
643
+ />
644
+ Tight
645
+ </label>
646
+ {#if data.ordered}
647
+ <Input
648
+ type="number"
649
+ value={String(data.start ?? 1)}
650
+ placeholder="Start"
651
+ class="w-24"
652
+ oninput={(e) =>
653
+ updateBlock(block.id, {
654
+ ...data,
655
+ start: Number((e.currentTarget as HTMLInputElement).value) || 1
656
+ })}
657
+ />
658
+ {/if}
659
+ </div>
660
+ <Textarea
661
+ value={data.items.join('\n')}
662
+ rows={4}
663
+ placeholder="One item per line"
664
+ oninput={(e) =>
665
+ updateBlock(block.id, {
666
+ ...data,
667
+ items: (e.currentTarget as HTMLTextAreaElement).value.split('\n')
668
+ })}
669
+ />
670
+ </div>
671
+ {:else if block.type === 'markdown'}
672
+ {@const data = block.data as BlogMarkdownData}
673
+ <Textarea
674
+ value={data.source}
675
+ rows={6}
676
+ class="font-mono text-xs"
677
+ oninput={(e) =>
678
+ updateBlock(block.id, {
679
+ ...data,
680
+ source: (e.currentTarget as HTMLTextAreaElement).value
681
+ })}
682
+ />
683
+ {:else if block.type === 'divider'}
684
+ {@const data = block.data as BlogDividerData}
685
+ <div class="flex flex-wrap gap-2">
686
+ <Select
687
+ value={data.style ?? 'solid'}
688
+ options={[
689
+ { value: 'solid', label: 'Solid' },
690
+ { value: 'dashed', label: 'Dashed' },
691
+ { value: 'dotted', label: 'Dotted' }
692
+ ]}
693
+ onchange={(v) =>
694
+ updateBlock(block.id, {
695
+ ...data,
696
+ style: v as BlogDividerData['style']
697
+ })}
698
+ class="w-32"
699
+ />
700
+ <Select
701
+ value={data.spacing ?? 'md'}
702
+ options={[
703
+ { value: 'sm', label: 'Spacing S' },
704
+ { value: 'md', label: 'Spacing M' },
705
+ { value: 'lg', label: 'Spacing L' }
706
+ ]}
707
+ onchange={(v) =>
708
+ updateBlock(block.id, {
709
+ ...data,
710
+ spacing: v as BlogDividerData['spacing']
711
+ })}
712
+ class="w-32"
713
+ />
714
+ <Input
715
+ value={data.label ?? ''}
716
+ placeholder="Optional label"
717
+ class="flex-1"
718
+ oninput={(e) =>
719
+ updateBlock(block.id, {
720
+ ...data,
721
+ label: (e.currentTarget as HTMLInputElement).value
722
+ })}
723
+ />
724
+ </div>
725
+ {:else if block.type === 'video'}
726
+ {@const data = block.data as BlogVideoData}
727
+ <div class="grid gap-2 sm:grid-cols-2">
728
+ <Input
729
+ value={data.src}
730
+ placeholder="Video URL"
731
+ class="sm:col-span-2"
732
+ oninput={(e) =>
733
+ updateBlock(block.id, {
734
+ ...data,
735
+ src: (e.currentTarget as HTMLInputElement).value
736
+ })}
737
+ />
738
+ <Input
739
+ value={data.poster ?? ''}
740
+ placeholder="Poster image"
741
+ oninput={(e) =>
742
+ updateBlock(block.id, {
743
+ ...data,
744
+ poster: (e.currentTarget as HTMLInputElement).value
745
+ })}
746
+ />
747
+ <Input
748
+ value={data.caption ?? ''}
749
+ placeholder="Caption"
750
+ oninput={(e) =>
751
+ updateBlock(block.id, {
752
+ ...data,
753
+ caption: (e.currentTarget as HTMLInputElement).value
754
+ })}
755
+ />
756
+ <Select
757
+ value={data.align ?? 'center'}
758
+ options={ALIGN_OPTS}
759
+ onchange={(v) => updateBlock(block.id, { ...data, align: v as BlogAlign })}
760
+ />
761
+ <Select
762
+ value={data.width ?? 'content'}
763
+ options={WIDTH_OPTS}
764
+ onchange={(v) => updateBlock(block.id, { ...data, width: v as BlogWidth })}
765
+ />
766
+ <label class="flex items-center gap-1.5 text-xs text-muted">
767
+ <input
768
+ type="checkbox"
769
+ checked={data.controls !== false}
770
+ onchange={(e) =>
771
+ updateBlock(block.id, {
772
+ ...data,
773
+ controls: (e.currentTarget as HTMLInputElement).checked
774
+ })}
775
+ />
776
+ Controls
777
+ </label>
778
+ <label class="flex items-center gap-1.5 text-xs text-muted">
779
+ <input
780
+ type="checkbox"
781
+ checked={!!data.autoplay}
782
+ onchange={(e) =>
783
+ updateBlock(block.id, {
784
+ ...data,
785
+ autoplay: (e.currentTarget as HTMLInputElement).checked
786
+ })}
787
+ />
788
+ Autoplay
789
+ </label>
790
+ <label class="flex items-center gap-1.5 text-xs text-muted">
791
+ <input
792
+ type="checkbox"
793
+ checked={!!data.loop}
794
+ onchange={(e) =>
795
+ updateBlock(block.id, {
796
+ ...data,
797
+ loop: (e.currentTarget as HTMLInputElement).checked
798
+ })}
799
+ />
800
+ Loop
801
+ </label>
802
+ <label class="flex items-center gap-1.5 text-xs text-muted">
803
+ <input
804
+ type="checkbox"
805
+ checked={!!data.muted}
806
+ onchange={(e) =>
807
+ updateBlock(block.id, {
808
+ ...data,
809
+ muted: (e.currentTarget as HTMLInputElement).checked
810
+ })}
811
+ />
812
+ Muted
813
+ </label>
814
+ </div>
815
+ {:else if block.type === 'embed'}
816
+ {@const data = block.data as BlogEmbedData}
817
+ <div class="grid gap-2 sm:grid-cols-2">
818
+ <Input
819
+ value={data.url}
820
+ placeholder="YouTube / Vimeo / iframe URL"
821
+ class="sm:col-span-2"
822
+ oninput={(e) =>
823
+ updateBlock(block.id, {
824
+ ...data,
825
+ url: (e.currentTarget as HTMLInputElement).value
826
+ })}
827
+ />
828
+ <Input
829
+ value={data.title ?? ''}
830
+ placeholder="Title"
831
+ oninput={(e) =>
832
+ updateBlock(block.id, {
833
+ ...data,
834
+ title: (e.currentTarget as HTMLInputElement).value
835
+ })}
836
+ />
837
+ <Select
838
+ value={data.aspectRatio ?? '16:9'}
839
+ options={[
840
+ { value: '16:9', label: '16:9' },
841
+ { value: '4:3', label: '4:3' },
842
+ { value: '1:1', label: '1:1' },
843
+ { value: '9:16', label: '9:16' }
844
+ ]}
845
+ onchange={(v) =>
846
+ updateBlock(block.id, {
847
+ ...data,
848
+ aspectRatio: v as BlogEmbedData['aspectRatio']
849
+ })}
850
+ />
851
+ <Input
852
+ value={data.caption ?? ''}
853
+ placeholder="Caption"
854
+ class="sm:col-span-2"
855
+ oninput={(e) =>
856
+ updateBlock(block.id, {
857
+ ...data,
858
+ caption: (e.currentTarget as HTMLInputElement).value
859
+ })}
860
+ />
861
+ </div>
862
+ {:else if block.type === 'gallery'}
863
+ {@const data = block.data as BlogGalleryData}
864
+ <div class="flex flex-col gap-2">
865
+ <div class="flex flex-wrap gap-2">
866
+ <Select
867
+ value={String(data.columns ?? 3)}
868
+ options={[
869
+ { value: '2', label: '2 cols' },
870
+ { value: '3', label: '3 cols' },
871
+ { value: '4', label: '4 cols' }
872
+ ]}
873
+ onchange={(v) =>
874
+ updateBlock(block.id, {
875
+ ...data,
876
+ columns: Number(v) as BlogGalleryData['columns']
877
+ })}
878
+ class="w-28"
879
+ />
880
+ <Select
881
+ value={data.gap ?? 'md'}
882
+ options={[
883
+ { value: 'sm', label: 'Gap S' },
884
+ { value: 'md', label: 'Gap M' },
885
+ { value: 'lg', label: 'Gap L' }
886
+ ]}
887
+ onchange={(v) =>
888
+ updateBlock(block.id, {
889
+ ...data,
890
+ gap: v as BlogGalleryData['gap']
891
+ })}
892
+ class="w-28"
893
+ />
894
+ <label class="flex items-center gap-1.5 text-xs text-muted">
895
+ <input
896
+ type="checkbox"
897
+ checked={data.rounded !== false}
898
+ onchange={(e) =>
899
+ updateBlock(block.id, {
900
+ ...data,
901
+ rounded: (e.currentTarget as HTMLInputElement).checked
902
+ })}
903
+ />
904
+ Rounded
905
+ </label>
906
+ </div>
907
+ <Textarea
908
+ value={data.images.map((img) => img.src).join('\n')}
909
+ rows={4}
910
+ placeholder="One image URL per line"
911
+ oninput={(e) =>
912
+ updateBlock(block.id, {
913
+ ...data,
914
+ images: (e.currentTarget as HTMLTextAreaElement).value
915
+ .split('\n')
916
+ .map((src) => ({ src: src.trim(), alt: '' }))
917
+ .filter((img) => img.src.length >= 0)
918
+ })}
919
+ />
920
+ </div>
921
+ {:else if block.type === 'table'}
922
+ {@const data = block.data as BlogTableData}
923
+ <div class="flex flex-col gap-2">
924
+ <div class="flex flex-wrap items-center gap-3">
925
+ <label class="flex items-center gap-1.5 text-xs text-muted">
926
+ <input
927
+ type="checkbox"
928
+ checked={data.striped !== false}
929
+ onchange={(e) =>
930
+ updateBlock(block.id, {
931
+ ...data,
932
+ striped: (e.currentTarget as HTMLInputElement).checked
933
+ })}
934
+ />
935
+ Striped
936
+ </label>
937
+ <label class="flex items-center gap-1.5 text-xs text-muted">
938
+ <input
939
+ type="checkbox"
940
+ checked={!!data.compact}
941
+ onchange={(e) =>
942
+ updateBlock(block.id, {
943
+ ...data,
944
+ compact: (e.currentTarget as HTMLInputElement).checked
945
+ })}
946
+ />
947
+ Compact
948
+ </label>
949
+ <Input
950
+ value={data.caption ?? ''}
951
+ placeholder="Caption"
952
+ class="flex-1"
953
+ oninput={(e) =>
954
+ updateBlock(block.id, {
955
+ ...data,
956
+ caption: (e.currentTarget as HTMLInputElement).value
957
+ })}
958
+ />
959
+ </div>
960
+ <Input
961
+ value={data.headers.join(' | ')}
962
+ placeholder="Headers separated by |"
963
+ oninput={(e) =>
964
+ updateBlock(block.id, {
965
+ ...data,
966
+ headers: (e.currentTarget as HTMLInputElement).value
967
+ .split('|')
968
+ .map((h) => h.trim())
969
+ })}
970
+ />
971
+ <Textarea
972
+ value={data.rows.map((r) => r.join(' | ')).join('\n')}
973
+ rows={4}
974
+ placeholder={'Rows: cell | cell\none row per line'}
975
+ oninput={(e) =>
976
+ updateBlock(block.id, {
977
+ ...data,
978
+ rows: (e.currentTarget as HTMLTextAreaElement).value
979
+ .split('\n')
980
+ .map((line) => line.split('|').map((c) => c.trim()))
981
+ })}
982
+ />
983
+ </div>
984
+ {:else if block.type === 'cta'}
985
+ {@const data = block.data as BlogCtaData}
986
+ <div class="grid gap-2 sm:grid-cols-2">
987
+ <Input
988
+ value={data.label}
989
+ placeholder="Button label"
990
+ oninput={(e) =>
991
+ updateBlock(block.id, {
992
+ ...data,
993
+ label: (e.currentTarget as HTMLInputElement).value
994
+ })}
995
+ />
996
+ <Input
997
+ value={data.href ?? ''}
998
+ placeholder="Href"
999
+ oninput={(e) =>
1000
+ updateBlock(block.id, {
1001
+ ...data,
1002
+ href: (e.currentTarget as HTMLInputElement).value
1003
+ })}
1004
+ />
1005
+ <Select
1006
+ value={data.variant ?? 'primary'}
1007
+ options={[
1008
+ { value: 'primary', label: 'Primary' },
1009
+ { value: 'secondary', label: 'Secondary' },
1010
+ { value: 'ghost', label: 'Ghost' },
1011
+ { value: 'outline', label: 'Outline' }
1012
+ ]}
1013
+ onchange={(v) =>
1014
+ updateBlock(block.id, {
1015
+ ...data,
1016
+ variant: v as BlogCtaData['variant']
1017
+ })}
1018
+ />
1019
+ <Select
1020
+ value={data.align ?? 'center'}
1021
+ options={ALIGN_OPTS}
1022
+ onchange={(v) => updateBlock(block.id, { ...data, align: v as BlogAlign })}
1023
+ />
1024
+ <Input
1025
+ value={data.subtitle ?? ''}
1026
+ placeholder="Subtitle"
1027
+ class="sm:col-span-2"
1028
+ oninput={(e) =>
1029
+ updateBlock(block.id, {
1030
+ ...data,
1031
+ subtitle: (e.currentTarget as HTMLInputElement).value
1032
+ })}
1033
+ />
1034
+ <label class="flex items-center gap-1.5 text-xs text-muted">
1035
+ <input
1036
+ type="checkbox"
1037
+ checked={!!data.openInNewTab}
1038
+ onchange={(e) =>
1039
+ updateBlock(block.id, {
1040
+ ...data,
1041
+ openInNewTab: (e.currentTarget as HTMLInputElement).checked
1042
+ })}
1043
+ />
1044
+ Open in new tab
1045
+ </label>
1046
+ </div>
1047
+ {:else if block.type === 'spacer'}
1048
+ {@const data = block.data as BlogSpacerData}
1049
+ <Select
1050
+ value={data.size ?? 'md'}
1051
+ options={[
1052
+ { value: 'xs', label: 'XS' },
1053
+ { value: 'sm', label: 'S' },
1054
+ { value: 'md', label: 'M' },
1055
+ { value: 'lg', label: 'L' },
1056
+ { value: 'xl', label: 'XL' }
1057
+ ]}
1058
+ onchange={(v) =>
1059
+ updateBlock(block.id, {
1060
+ ...data,
1061
+ size: v as BlogSpacerData['size']
1062
+ })}
1063
+ class="w-32"
1064
+ />
1065
+ {:else if block.type === 'html'}
1066
+ {@const data = block.data as BlogHtmlData}
1067
+ <Textarea
1068
+ value={data.html}
1069
+ rows={5}
1070
+ class="font-mono text-xs"
1071
+ placeholder="<div>...</div>"
1072
+ oninput={(e) =>
1073
+ updateBlock(block.id, {
1074
+ ...data,
1075
+ html: (e.currentTarget as HTMLTextAreaElement).value
1076
+ })}
1077
+ />
1078
+ {:else if block.type === 'component'}
1079
+ {@const data = block.data as BlogComponentData}
1080
+ {@const reg = getBlogComponent(data.componentId)}
1081
+ <div class="flex flex-col gap-2">
1082
+ <p class="text-xs text-muted">
1083
+ Component: <code>{data.componentId}</code>
1084
+ {#if reg?.description}
1085
+ — {reg.description}
1086
+ {/if}
1087
+ </p>
1088
+ {#if reg?.propFields?.length}
1089
+ <div class="grid gap-2 sm:grid-cols-2">
1090
+ {#each reg.propFields as field (field.key)}
1091
+ {#if field.type === 'boolean'}
1092
+ <label class="flex items-center gap-1.5 text-xs text-muted sm:col-span-2">
1093
+ <input
1094
+ type="checkbox"
1095
+ checked={Boolean(data.props?.[field.key])}
1096
+ onchange={(e) =>
1097
+ updateComponentProp(
1098
+ block.id,
1099
+ data,
1100
+ field.key,
1101
+ (e.currentTarget as HTMLInputElement).checked
1102
+ )}
1103
+ />
1104
+ {field.label}
1105
+ </label>
1106
+ {:else if field.type === 'select' && field.options}
1107
+ <div class="flex flex-col gap-1">
1108
+ <span class="text-[11px] text-muted">{field.label}</span>
1109
+ <Select
1110
+ value={String(data.props?.[field.key] ?? '')}
1111
+ options={field.options}
1112
+ onchange={(v) => updateComponentProp(block.id, data, field.key, v)}
1113
+ />
1114
+ </div>
1115
+ {:else if field.type === 'textarea'}
1116
+ <div class="flex flex-col gap-1 sm:col-span-2">
1117
+ <span class="text-[11px] text-muted">{field.label}</span>
1118
+ <Textarea
1119
+ value={String(data.props?.[field.key] ?? '')}
1120
+ rows={3}
1121
+ placeholder={field.placeholder}
1122
+ oninput={(e) =>
1123
+ updateComponentProp(
1124
+ block.id,
1125
+ data,
1126
+ field.key,
1127
+ (e.currentTarget as HTMLTextAreaElement).value
1128
+ )}
1129
+ />
1130
+ </div>
1131
+ {:else if field.type === 'number'}
1132
+ <div class="flex flex-col gap-1">
1133
+ <span class="text-[11px] text-muted">{field.label}</span>
1134
+ <Input
1135
+ type="number"
1136
+ value={String(data.props?.[field.key] ?? '')}
1137
+ placeholder={field.placeholder}
1138
+ oninput={(e) =>
1139
+ updateComponentProp(
1140
+ block.id,
1141
+ data,
1142
+ field.key,
1143
+ Number((e.currentTarget as HTMLInputElement).value)
1144
+ )}
1145
+ />
1146
+ </div>
1147
+ {:else}
1148
+ <div class="flex flex-col gap-1">
1149
+ <span class="text-[11px] text-muted">{field.label}</span>
1150
+ {#if field.type === 'color'}
1151
+ <input
1152
+ type="color"
1153
+ class="h-9 w-full cursor-pointer rounded-md border border-border bg-surface"
1154
+ value={String(data.props?.[field.key] ?? '#0ea5e9')}
1155
+ oninput={(e) =>
1156
+ updateComponentProp(
1157
+ block.id,
1158
+ data,
1159
+ field.key,
1160
+ (e.currentTarget as HTMLInputElement).value
1161
+ )}
1162
+ />
1163
+ {:else}
1164
+ <Input
1165
+ value={String(data.props?.[field.key] ?? '')}
1166
+ placeholder={field.placeholder}
1167
+ oninput={(e) =>
1168
+ updateComponentProp(
1169
+ block.id,
1170
+ data,
1171
+ field.key,
1172
+ (e.currentTarget as HTMLInputElement).value
1173
+ )}
1174
+ />
1175
+ {/if}
1176
+ </div>
1177
+ {/if}
1178
+ {/each}
1179
+ </div>
1180
+ {:else}
1181
+ <Textarea
1182
+ value={JSON.stringify(data.props ?? {}, null, 2)}
1183
+ rows={4}
1184
+ class="font-mono text-xs"
1185
+ oninput={(e) => {
1186
+ try {
1187
+ const props = JSON.parse((e.currentTarget as HTMLTextAreaElement).value);
1188
+ updateBlock(block.id, { ...data, props });
1189
+ } catch {
1190
+ /* ignore invalid JSON while typing */
1191
+ }
1192
+ }}
1193
+ />
1194
+ {/if}
1195
+ </div>
1196
+ {/if}
1197
+ </li>
1198
+ {/each}
1199
+ </ul>
1200
+ {/if}
1201
+
1202
+ {#if showJson}
1203
+ <div class="border-t border-border pt-3">
1204
+ <p class="mb-2 text-xs font-semibold uppercase tracking-wide text-muted">JSON</p>
1205
+ <JSONViewer data={value} />
1206
+ </div>
1207
+ {/if}
1208
+ </div>