@bendyline/squisq-editor-react 1.5.1 → 1.5.3

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 (405) hide show
  1. package/dist/index.d.ts +1991 -90
  2. package/dist/index.js +17162 -82
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -4
  5. package/src/RawEditor.tsx +49 -18
  6. package/src/VersionHistoryPanel.tsx +59 -17
  7. package/src/recorder/hooks/useMediaRecorder.ts +9 -1
  8. package/src/useMonacoLoader.ts +83 -0
  9. package/dist/DocumentSettingsDialog.d.ts +0 -26
  10. package/dist/DocumentSettingsDialog.d.ts.map +0 -1
  11. package/dist/DocumentSettingsDialog.js +0 -115
  12. package/dist/DocumentSettingsDialog.js.map +0 -1
  13. package/dist/DropZoneOverlay.d.ts +0 -24
  14. package/dist/DropZoneOverlay.d.ts.map +0 -1
  15. package/dist/DropZoneOverlay.js +0 -53
  16. package/dist/DropZoneOverlay.js.map +0 -1
  17. package/dist/EditorContext.d.ts +0 -391
  18. package/dist/EditorContext.d.ts.map +0 -1
  19. package/dist/EditorContext.js +0 -471
  20. package/dist/EditorContext.js.map +0 -1
  21. package/dist/EditorShell.d.ts +0 -328
  22. package/dist/EditorShell.d.ts.map +0 -1
  23. package/dist/EditorShell.js +0 -290
  24. package/dist/EditorShell.js.map +0 -1
  25. package/dist/EmojiPicker.d.ts +0 -50
  26. package/dist/EmojiPicker.d.ts.map +0 -1
  27. package/dist/EmojiPicker.js +0 -182
  28. package/dist/EmojiPicker.js.map +0 -1
  29. package/dist/ImageEditor.d.ts +0 -68
  30. package/dist/ImageEditor.d.ts.map +0 -1
  31. package/dist/ImageEditor.js +0 -166
  32. package/dist/ImageEditor.js.map +0 -1
  33. package/dist/ImageNodeView.d.ts +0 -27
  34. package/dist/ImageNodeView.d.ts.map +0 -1
  35. package/dist/ImageNodeView.js +0 -215
  36. package/dist/ImageNodeView.js.map +0 -1
  37. package/dist/ImageViewer.d.ts +0 -26
  38. package/dist/ImageViewer.d.ts.map +0 -1
  39. package/dist/ImageViewer.js +0 -119
  40. package/dist/ImageViewer.js.map +0 -1
  41. package/dist/InlineIcon.d.ts +0 -17
  42. package/dist/InlineIcon.d.ts.map +0 -1
  43. package/dist/InlineIcon.js +0 -72
  44. package/dist/InlineIcon.js.map +0 -1
  45. package/dist/InlinePreviewGutter.d.ts +0 -52
  46. package/dist/InlinePreviewGutter.d.ts.map +0 -1
  47. package/dist/InlinePreviewGutter.js +0 -397
  48. package/dist/InlinePreviewGutter.js.map +0 -1
  49. package/dist/LinkDialog.d.ts +0 -43
  50. package/dist/LinkDialog.d.ts.map +0 -1
  51. package/dist/LinkDialog.js +0 -102
  52. package/dist/LinkDialog.js.map +0 -1
  53. package/dist/MediaBin.d.ts +0 -29
  54. package/dist/MediaBin.d.ts.map +0 -1
  55. package/dist/MediaBin.js +0 -166
  56. package/dist/MediaBin.js.map +0 -1
  57. package/dist/MentionExtension.d.ts +0 -22
  58. package/dist/MentionExtension.d.ts.map +0 -1
  59. package/dist/MentionExtension.js +0 -245
  60. package/dist/MentionExtension.js.map +0 -1
  61. package/dist/OutlinePanel.d.ts +0 -17
  62. package/dist/OutlinePanel.d.ts.map +0 -1
  63. package/dist/OutlinePanel.js +0 -167
  64. package/dist/OutlinePanel.js.map +0 -1
  65. package/dist/PlainHtmlPreview.d.ts +0 -50
  66. package/dist/PlainHtmlPreview.d.ts.map +0 -1
  67. package/dist/PlainHtmlPreview.js +0 -155
  68. package/dist/PlainHtmlPreview.js.map +0 -1
  69. package/dist/PreviewControls.d.ts +0 -55
  70. package/dist/PreviewControls.d.ts.map +0 -1
  71. package/dist/PreviewControls.js +0 -277
  72. package/dist/PreviewControls.js.map +0 -1
  73. package/dist/PreviewPanel.d.ts +0 -29
  74. package/dist/PreviewPanel.d.ts.map +0 -1
  75. package/dist/PreviewPanel.js +0 -94
  76. package/dist/PreviewPanel.js.map +0 -1
  77. package/dist/RawEditor.d.ts +0 -32
  78. package/dist/RawEditor.d.ts.map +0 -1
  79. package/dist/RawEditor.js +0 -440
  80. package/dist/RawEditor.js.map +0 -1
  81. package/dist/RecorderEntry.d.ts +0 -24
  82. package/dist/RecorderEntry.d.ts.map +0 -1
  83. package/dist/RecorderEntry.js +0 -139
  84. package/dist/RecorderEntry.js.map +0 -1
  85. package/dist/StatusBar.d.ts +0 -15
  86. package/dist/StatusBar.d.ts.map +0 -1
  87. package/dist/StatusBar.js +0 -24
  88. package/dist/StatusBar.js.map +0 -1
  89. package/dist/TemplateAnnotation.d.ts +0 -20
  90. package/dist/TemplateAnnotation.d.ts.map +0 -1
  91. package/dist/TemplateAnnotation.js +0 -97
  92. package/dist/TemplateAnnotation.js.map +0 -1
  93. package/dist/TemplatePicker.d.ts +0 -53
  94. package/dist/TemplatePicker.d.ts.map +0 -1
  95. package/dist/TemplatePicker.js +0 -388
  96. package/dist/TemplatePicker.js.map +0 -1
  97. package/dist/ThemeCustomizerPanel.d.ts +0 -32
  98. package/dist/ThemeCustomizerPanel.d.ts.map +0 -1
  99. package/dist/ThemeCustomizerPanel.js +0 -256
  100. package/dist/ThemeCustomizerPanel.js.map +0 -1
  101. package/dist/ThemePicker.d.ts +0 -33
  102. package/dist/ThemePicker.d.ts.map +0 -1
  103. package/dist/ThemePicker.js +0 -148
  104. package/dist/ThemePicker.js.map +0 -1
  105. package/dist/Toolbar.d.ts +0 -36
  106. package/dist/Toolbar.d.ts.map +0 -1
  107. package/dist/Toolbar.js +0 -1001
  108. package/dist/Toolbar.js.map +0 -1
  109. package/dist/Tooltip.d.ts +0 -10
  110. package/dist/Tooltip.d.ts.map +0 -1
  111. package/dist/Tooltip.js +0 -104
  112. package/dist/Tooltip.js.map +0 -1
  113. package/dist/VersionHistoryPanel.d.ts +0 -14
  114. package/dist/VersionHistoryPanel.d.ts.map +0 -1
  115. package/dist/VersionHistoryPanel.js +0 -147
  116. package/dist/VersionHistoryPanel.js.map +0 -1
  117. package/dist/ViewMenuPanel.d.ts +0 -13
  118. package/dist/ViewMenuPanel.d.ts.map +0 -1
  119. package/dist/ViewMenuPanel.js +0 -58
  120. package/dist/ViewMenuPanel.js.map +0 -1
  121. package/dist/ViewSwitcher.d.ts +0 -14
  122. package/dist/ViewSwitcher.d.ts.map +0 -1
  123. package/dist/ViewSwitcher.js +0 -26
  124. package/dist/ViewSwitcher.js.map +0 -1
  125. package/dist/WysiwygEditor.d.ts +0 -39
  126. package/dist/WysiwygEditor.d.ts.map +0 -1
  127. package/dist/WysiwygEditor.js +0 -537
  128. package/dist/WysiwygEditor.js.map +0 -1
  129. package/dist/__tests__/detectMarkdown.test.d.ts +0 -2
  130. package/dist/__tests__/detectMarkdown.test.d.ts.map +0 -1
  131. package/dist/__tests__/detectMarkdown.test.js +0 -55
  132. package/dist/__tests__/detectMarkdown.test.js.map +0 -1
  133. package/dist/__tests__/documentSettingsDialog.test.d.ts +0 -2
  134. package/dist/__tests__/documentSettingsDialog.test.d.ts.map +0 -1
  135. package/dist/__tests__/documentSettingsDialog.test.js +0 -132
  136. package/dist/__tests__/documentSettingsDialog.test.js.map +0 -1
  137. package/dist/__tests__/emojiPicker.test.d.ts +0 -2
  138. package/dist/__tests__/emojiPicker.test.d.ts.map +0 -1
  139. package/dist/__tests__/emojiPicker.test.js +0 -111
  140. package/dist/__tests__/emojiPicker.test.js.map +0 -1
  141. package/dist/__tests__/fileKind.test.d.ts +0 -2
  142. package/dist/__tests__/fileKind.test.d.ts.map +0 -1
  143. package/dist/__tests__/fileKind.test.js +0 -94
  144. package/dist/__tests__/fileKind.test.js.map +0 -1
  145. package/dist/__tests__/imageEditAffordance.test.d.ts +0 -2
  146. package/dist/__tests__/imageEditAffordance.test.d.ts.map +0 -1
  147. package/dist/__tests__/imageEditAffordance.test.js +0 -188
  148. package/dist/__tests__/imageEditAffordance.test.js.map +0 -1
  149. package/dist/__tests__/imageEditorShell.test.d.ts +0 -2
  150. package/dist/__tests__/imageEditorShell.test.d.ts.map +0 -1
  151. package/dist/__tests__/imageEditorShell.test.js +0 -52
  152. package/dist/__tests__/imageEditorShell.test.js.map +0 -1
  153. package/dist/__tests__/imageEditorState.test.d.ts +0 -3
  154. package/dist/__tests__/imageEditorState.test.d.ts.map +0 -1
  155. package/dist/__tests__/imageEditorState.test.js +0 -148
  156. package/dist/__tests__/imageEditorState.test.js.map +0 -1
  157. package/dist/__tests__/inlinePreviewGutter.test.d.ts +0 -2
  158. package/dist/__tests__/inlinePreviewGutter.test.d.ts.map +0 -1
  159. package/dist/__tests__/inlinePreviewGutter.test.js +0 -51
  160. package/dist/__tests__/inlinePreviewGutter.test.js.map +0 -1
  161. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts +0 -2
  162. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts.map +0 -1
  163. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js +0 -63
  164. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js.map +0 -1
  165. package/dist/__tests__/jsonEditor.test.d.ts +0 -2
  166. package/dist/__tests__/jsonEditor.test.d.ts.map +0 -1
  167. package/dist/__tests__/jsonEditor.test.js +0 -134
  168. package/dist/__tests__/jsonEditor.test.js.map +0 -1
  169. package/dist/__tests__/layersPanel.test.d.ts +0 -2
  170. package/dist/__tests__/layersPanel.test.d.ts.map +0 -1
  171. package/dist/__tests__/layersPanel.test.js +0 -84
  172. package/dist/__tests__/layersPanel.test.js.map +0 -1
  173. package/dist/__tests__/linkDialogDocPicker.test.d.ts +0 -7
  174. package/dist/__tests__/linkDialogDocPicker.test.d.ts.map +0 -1
  175. package/dist/__tests__/linkDialogDocPicker.test.js +0 -75
  176. package/dist/__tests__/linkDialogDocPicker.test.js.map +0 -1
  177. package/dist/__tests__/mediaAttachmentFlow.test.d.ts +0 -2
  178. package/dist/__tests__/mediaAttachmentFlow.test.d.ts.map +0 -1
  179. package/dist/__tests__/mediaAttachmentFlow.test.js +0 -99
  180. package/dist/__tests__/mediaAttachmentFlow.test.js.map +0 -1
  181. package/dist/__tests__/outlinePanel.test.d.ts +0 -2
  182. package/dist/__tests__/outlinePanel.test.d.ts.map +0 -1
  183. package/dist/__tests__/outlinePanel.test.js +0 -68
  184. package/dist/__tests__/outlinePanel.test.js.map +0 -1
  185. package/dist/__tests__/plainHtmlPreview.test.d.ts +0 -2
  186. package/dist/__tests__/plainHtmlPreview.test.d.ts.map +0 -1
  187. package/dist/__tests__/plainHtmlPreview.test.js +0 -87
  188. package/dist/__tests__/plainHtmlPreview.test.js.map +0 -1
  189. package/dist/__tests__/propertiesPanel.test.d.ts +0 -2
  190. package/dist/__tests__/propertiesPanel.test.d.ts.map +0 -1
  191. package/dist/__tests__/propertiesPanel.test.js +0 -64
  192. package/dist/__tests__/propertiesPanel.test.js.map +0 -1
  193. package/dist/__tests__/recorderFormats.test.d.ts +0 -2
  194. package/dist/__tests__/recorderFormats.test.d.ts.map +0 -1
  195. package/dist/__tests__/recorderFormats.test.js +0 -121
  196. package/dist/__tests__/recorderFormats.test.js.map +0 -1
  197. package/dist/__tests__/recorderTimingJson.test.d.ts +0 -2
  198. package/dist/__tests__/recorderTimingJson.test.d.ts.map +0 -1
  199. package/dist/__tests__/recorderTimingJson.test.js +0 -37
  200. package/dist/__tests__/recorderTimingJson.test.js.map +0 -1
  201. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts +0 -2
  202. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts.map +0 -1
  203. package/dist/__tests__/templateAnnotationRoundTrip.test.js +0 -31
  204. package/dist/__tests__/templateAnnotationRoundTrip.test.js.map +0 -1
  205. package/dist/__tests__/tiptapBridge.test.d.ts +0 -2
  206. package/dist/__tests__/tiptapBridge.test.d.ts.map +0 -1
  207. package/dist/__tests__/tiptapBridge.test.js +0 -303
  208. package/dist/__tests__/tiptapBridge.test.js.map +0 -1
  209. package/dist/__tests__/tiptapImageRoundTrip.test.d.ts +0 -2
  210. package/dist/__tests__/tiptapImageRoundTrip.test.d.ts.map +0 -1
  211. package/dist/__tests__/tiptapImageRoundTrip.test.js +0 -68
  212. package/dist/__tests__/tiptapImageRoundTrip.test.js.map +0 -1
  213. package/dist/__tests__/useImageEditor.test.d.ts +0 -2
  214. package/dist/__tests__/useImageEditor.test.d.ts.map +0 -1
  215. package/dist/__tests__/useImageEditor.test.js +0 -131
  216. package/dist/__tests__/useImageEditor.test.js.map +0 -1
  217. package/dist/__tests__/useMediaRecorder.test.d.ts +0 -2
  218. package/dist/__tests__/useMediaRecorder.test.d.ts.map +0 -1
  219. package/dist/__tests__/useMediaRecorder.test.js +0 -153
  220. package/dist/__tests__/useMediaRecorder.test.js.map +0 -1
  221. package/dist/__tests__/versionHistory.test.d.ts +0 -2
  222. package/dist/__tests__/versionHistory.test.d.ts.map +0 -1
  223. package/dist/__tests__/versionHistory.test.js +0 -124
  224. package/dist/__tests__/versionHistory.test.js.map +0 -1
  225. package/dist/blockSlice.d.ts +0 -24
  226. package/dist/blockSlice.d.ts.map +0 -1
  227. package/dist/blockSlice.js +0 -63
  228. package/dist/blockSlice.js.map +0 -1
  229. package/dist/buildPreviewDoc.d.ts +0 -22
  230. package/dist/buildPreviewDoc.d.ts.map +0 -1
  231. package/dist/buildPreviewDoc.js +0 -262
  232. package/dist/buildPreviewDoc.js.map +0 -1
  233. package/dist/detectMarkdown.d.ts +0 -20
  234. package/dist/detectMarkdown.d.ts.map +0 -1
  235. package/dist/detectMarkdown.js +0 -61
  236. package/dist/detectMarkdown.js.map +0 -1
  237. package/dist/emojiData.d.ts +0 -81
  238. package/dist/emojiData.d.ts.map +0 -1
  239. package/dist/emojiData.js +0 -1283
  240. package/dist/emojiData.js.map +0 -1
  241. package/dist/fileKind.d.ts +0 -34
  242. package/dist/fileKind.d.ts.map +0 -1
  243. package/dist/fileKind.js +0 -144
  244. package/dist/fileKind.js.map +0 -1
  245. package/dist/hooks/useFileDrop.d.ts +0 -41
  246. package/dist/hooks/useFileDrop.d.ts.map +0 -1
  247. package/dist/hooks/useFileDrop.js +0 -205
  248. package/dist/hooks/useFileDrop.js.map +0 -1
  249. package/dist/imageEditor/CanvasSurface.d.ts +0 -31
  250. package/dist/imageEditor/CanvasSurface.d.ts.map +0 -1
  251. package/dist/imageEditor/CanvasSurface.js +0 -264
  252. package/dist/imageEditor/CanvasSurface.js.map +0 -1
  253. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts +0 -39
  254. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts.map +0 -1
  255. package/dist/imageEditor/ImageVersionHistoryDropdown.js +0 -283
  256. package/dist/imageEditor/ImageVersionHistoryDropdown.js.map +0 -1
  257. package/dist/imageEditor/LayersPanel.d.ts +0 -14
  258. package/dist/imageEditor/LayersPanel.d.ts.map +0 -1
  259. package/dist/imageEditor/LayersPanel.js +0 -43
  260. package/dist/imageEditor/LayersPanel.js.map +0 -1
  261. package/dist/imageEditor/PropertiesPanel.d.ts +0 -14
  262. package/dist/imageEditor/PropertiesPanel.d.ts.map +0 -1
  263. package/dist/imageEditor/PropertiesPanel.js +0 -97
  264. package/dist/imageEditor/PropertiesPanel.js.map +0 -1
  265. package/dist/imageEditor/Toolbar.d.ts +0 -30
  266. package/dist/imageEditor/Toolbar.d.ts.map +0 -1
  267. package/dist/imageEditor/Toolbar.js +0 -108
  268. package/dist/imageEditor/Toolbar.js.map +0 -1
  269. package/dist/imageEditor/icons.d.ts +0 -24
  270. package/dist/imageEditor/icons.d.ts.map +0 -1
  271. package/dist/imageEditor/icons.js +0 -45
  272. package/dist/imageEditor/icons.js.map +0 -1
  273. package/dist/imageEditor/layers/EditorImageLayer.d.ts +0 -16
  274. package/dist/imageEditor/layers/EditorImageLayer.d.ts.map +0 -1
  275. package/dist/imageEditor/layers/EditorImageLayer.js +0 -37
  276. package/dist/imageEditor/layers/EditorImageLayer.js.map +0 -1
  277. package/dist/imageEditor/layers/EditorShapeLayer.d.ts +0 -15
  278. package/dist/imageEditor/layers/EditorShapeLayer.d.ts.map +0 -1
  279. package/dist/imageEditor/layers/EditorShapeLayer.js +0 -20
  280. package/dist/imageEditor/layers/EditorShapeLayer.js.map +0 -1
  281. package/dist/imageEditor/layers/EditorTextLayer.d.ts +0 -18
  282. package/dist/imageEditor/layers/EditorTextLayer.d.ts.map +0 -1
  283. package/dist/imageEditor/layers/EditorTextLayer.js +0 -13
  284. package/dist/imageEditor/layers/EditorTextLayer.js.map +0 -1
  285. package/dist/imageEditor/layers/SelectionHandles.d.ts +0 -17
  286. package/dist/imageEditor/layers/SelectionHandles.d.ts.map +0 -1
  287. package/dist/imageEditor/layers/SelectionHandles.js +0 -19
  288. package/dist/imageEditor/layers/SelectionHandles.js.map +0 -1
  289. package/dist/imageEditor/state.d.ts +0 -76
  290. package/dist/imageEditor/state.d.ts.map +0 -1
  291. package/dist/imageEditor/state.js +0 -87
  292. package/dist/imageEditor/state.js.map +0 -1
  293. package/dist/imageEditor/useImageEditor.d.ts +0 -53
  294. package/dist/imageEditor/useImageEditor.d.ts.map +0 -1
  295. package/dist/imageEditor/useImageEditor.js +0 -244
  296. package/dist/imageEditor/useImageEditor.js.map +0 -1
  297. package/dist/imageEditor/useImageEditorTokens.d.ts +0 -16
  298. package/dist/imageEditor/useImageEditorTokens.d.ts.map +0 -1
  299. package/dist/imageEditor/useImageEditorTokens.js +0 -45
  300. package/dist/imageEditor/useImageEditorTokens.js.map +0 -1
  301. package/dist/index.d.ts.map +0 -1
  302. package/dist/jsonEditor/EmbeddedRichTextField.d.ts +0 -15
  303. package/dist/jsonEditor/EmbeddedRichTextField.d.ts.map +0 -1
  304. package/dist/jsonEditor/EmbeddedRichTextField.js +0 -74
  305. package/dist/jsonEditor/EmbeddedRichTextField.js.map +0 -1
  306. package/dist/jsonEditor/JsonEditor.d.ts +0 -36
  307. package/dist/jsonEditor/JsonEditor.d.ts.map +0 -1
  308. package/dist/jsonEditor/JsonEditor.js +0 -15
  309. package/dist/jsonEditor/JsonEditor.js.map +0 -1
  310. package/dist/jsonEditor/JsonEditorContext.d.ts +0 -28
  311. package/dist/jsonEditor/JsonEditorContext.d.ts.map +0 -1
  312. package/dist/jsonEditor/JsonEditorContext.js +0 -41
  313. package/dist/jsonEditor/JsonEditorContext.js.map +0 -1
  314. package/dist/jsonEditor/RenderNode.d.ts +0 -16
  315. package/dist/jsonEditor/RenderNode.d.ts.map +0 -1
  316. package/dist/jsonEditor/RenderNode.js +0 -32
  317. package/dist/jsonEditor/RenderNode.js.map +0 -1
  318. package/dist/jsonEditor/editors.d.ts +0 -36
  319. package/dist/jsonEditor/editors.d.ts.map +0 -1
  320. package/dist/jsonEditor/editors.js +0 -347
  321. package/dist/jsonEditor/editors.js.map +0 -1
  322. package/dist/jsonEditor/index.d.ts +0 -3
  323. package/dist/jsonEditor/index.d.ts.map +0 -1
  324. package/dist/jsonEditor/index.js +0 -2
  325. package/dist/jsonEditor/index.js.map +0 -1
  326. package/dist/jsonEditor/useJsonEditorTokens.d.ts +0 -13
  327. package/dist/jsonEditor/useJsonEditorTokens.d.ts.map +0 -1
  328. package/dist/jsonEditor/useJsonEditorTokens.js +0 -38
  329. package/dist/jsonEditor/useJsonEditorTokens.js.map +0 -1
  330. package/dist/mediaDragMime.d.ts +0 -17
  331. package/dist/mediaDragMime.d.ts.map +0 -1
  332. package/dist/mediaDragMime.js +0 -22
  333. package/dist/mediaDragMime.js.map +0 -1
  334. package/dist/recorder/RecorderButton.d.ts +0 -31
  335. package/dist/recorder/RecorderButton.d.ts.map +0 -1
  336. package/dist/recorder/RecorderButton.js +0 -24
  337. package/dist/recorder/RecorderButton.js.map +0 -1
  338. package/dist/recorder/RecorderModal.d.ts +0 -59
  339. package/dist/recorder/RecorderModal.d.ts.map +0 -1
  340. package/dist/recorder/RecorderModal.js +0 -333
  341. package/dist/recorder/RecorderModal.js.map +0 -1
  342. package/dist/recorder/RecorderPanel.d.ts +0 -25
  343. package/dist/recorder/RecorderPanel.d.ts.map +0 -1
  344. package/dist/recorder/RecorderPanel.js +0 -30
  345. package/dist/recorder/RecorderPanel.js.map +0 -1
  346. package/dist/recorder/formats.d.ts +0 -51
  347. package/dist/recorder/formats.d.ts.map +0 -1
  348. package/dist/recorder/formats.js +0 -144
  349. package/dist/recorder/formats.js.map +0 -1
  350. package/dist/recorder/hooks/useMediaRecorder.d.ts +0 -90
  351. package/dist/recorder/hooks/useMediaRecorder.d.ts.map +0 -1
  352. package/dist/recorder/hooks/useMediaRecorder.js +0 -277
  353. package/dist/recorder/hooks/useMediaRecorder.js.map +0 -1
  354. package/dist/recorder/hooks/useStreamPreview.d.ts +0 -22
  355. package/dist/recorder/hooks/useStreamPreview.d.ts.map +0 -1
  356. package/dist/recorder/hooks/useStreamPreview.js +0 -44
  357. package/dist/recorder/hooks/useStreamPreview.js.map +0 -1
  358. package/dist/recorder/sources/cameraStream.d.ts +0 -22
  359. package/dist/recorder/sources/cameraStream.d.ts.map +0 -1
  360. package/dist/recorder/sources/cameraStream.js +0 -24
  361. package/dist/recorder/sources/cameraStream.js.map +0 -1
  362. package/dist/recorder/sources/micStream.d.ts +0 -15
  363. package/dist/recorder/sources/micStream.d.ts.map +0 -1
  364. package/dist/recorder/sources/micStream.js +0 -24
  365. package/dist/recorder/sources/micStream.js.map +0 -1
  366. package/dist/recorder/sources/screenStream.d.ts +0 -53
  367. package/dist/recorder/sources/screenStream.d.ts.map +0 -1
  368. package/dist/recorder/sources/screenStream.js +0 -114
  369. package/dist/recorder/sources/screenStream.js.map +0 -1
  370. package/dist/recorder/timingJson.d.ts +0 -51
  371. package/dist/recorder/timingJson.d.ts.map +0 -1
  372. package/dist/recorder/timingJson.js +0 -42
  373. package/dist/recorder/timingJson.js.map +0 -1
  374. package/dist/tiptap/TiptapAudio.d.ts +0 -26
  375. package/dist/tiptap/TiptapAudio.d.ts.map +0 -1
  376. package/dist/tiptap/TiptapAudio.js +0 -58
  377. package/dist/tiptap/TiptapAudio.js.map +0 -1
  378. package/dist/tiptap/TiptapVideo.d.ts +0 -30
  379. package/dist/tiptap/TiptapVideo.d.ts.map +0 -1
  380. package/dist/tiptap/TiptapVideo.js +0 -66
  381. package/dist/tiptap/TiptapVideo.js.map +0 -1
  382. package/dist/tiptap/useResolvedMediaSrc.d.ts +0 -2
  383. package/dist/tiptap/useResolvedMediaSrc.d.ts.map +0 -1
  384. package/dist/tiptap/useResolvedMediaSrc.js +0 -42
  385. package/dist/tiptap/useResolvedMediaSrc.js.map +0 -1
  386. package/dist/tiptapBridge.d.ts +0 -24
  387. package/dist/tiptapBridge.d.ts.map +0 -1
  388. package/dist/tiptapBridge.js +0 -749
  389. package/dist/tiptapBridge.js.map +0 -1
  390. package/dist/useHeadingLayout.d.ts +0 -54
  391. package/dist/useHeadingLayout.d.ts.map +0 -1
  392. package/dist/useHeadingLayout.js +0 -260
  393. package/dist/useHeadingLayout.js.map +0 -1
  394. package/dist/utils/collectInlineFontAwesomeCss.d.ts +0 -21
  395. package/dist/utils/collectInlineFontAwesomeCss.d.ts.map +0 -1
  396. package/dist/utils/collectInlineFontAwesomeCss.js +0 -68
  397. package/dist/utils/collectInlineFontAwesomeCss.js.map +0 -1
  398. package/dist/utils/dropUtils.d.ts +0 -55
  399. package/dist/utils/dropUtils.d.ts.map +0 -1
  400. package/dist/utils/dropUtils.js +0 -110
  401. package/dist/utils/dropUtils.js.map +0 -1
  402. package/dist/utils/normalizeMalformedAssetUrl.d.ts +0 -15
  403. package/dist/utils/normalizeMalformedAssetUrl.d.ts.map +0 -1
  404. package/dist/utils/normalizeMalformedAssetUrl.js +0 -27
  405. package/dist/utils/normalizeMalformedAssetUrl.js.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"sources":["../src/EditorShell.tsx","../src/EditorContext.tsx","../src/TemplatePicker.tsx","../src/tiptapBridge.ts","../src/fileKind.ts","../src/Toolbar.tsx","../src/VersionHistoryPanel.tsx","../src/useMonacoLoader.ts","../src/RecorderEntry.tsx","../src/recorder/RecorderPanel.tsx","../src/recorder/RecorderModal.tsx","../src/recorder/hooks/useMediaRecorder.ts","../src/recorder/formats.ts","../src/recorder/sources/micStream.ts","../src/recorder/sources/cameraStream.ts","../src/recorder/sources/screenStream.ts","../src/recorder/hooks/useStreamPreview.ts","../src/recorder/timingJson.ts","../src/ViewMenuPanel.tsx","../src/blockSlice.ts","../src/LinkDialog.tsx","../src/DocumentSettingsDialog.tsx","../src/ThemePicker.tsx","../src/EmojiPicker.tsx","../src/emojiData.ts","../src/StatusBar.tsx","../src/RawEditor.tsx","../src/mediaDragMime.ts","../src/WysiwygEditor.tsx","../../../node_modules/@tiptap/core/src/helpers/createChainableState.ts","../../../node_modules/@tiptap/core/src/CommandManager.ts","../../../node_modules/@tiptap/core/src/EventEmitter.ts","../../../node_modules/@tiptap/core/src/helpers/getExtensionField.ts","../../../node_modules/@tiptap/core/src/helpers/splitExtensions.ts","../../../node_modules/@tiptap/core/src/helpers/getAttributesFromExtensions.ts","../../../node_modules/@tiptap/core/src/helpers/getNodeType.ts","../../../node_modules/@tiptap/core/src/utilities/mergeAttributes.ts","../../../node_modules/@tiptap/core/src/helpers/getRenderedAttributes.ts","../../../node_modules/@tiptap/core/src/utilities/isFunction.ts","../../../node_modules/@tiptap/core/src/utilities/callOrReturn.ts","../../../node_modules/@tiptap/core/src/utilities/isEmptyObject.ts","../../../node_modules/@tiptap/core/src/utilities/fromString.ts","../../../node_modules/@tiptap/core/src/helpers/injectExtensionAttributesToParseRule.ts","../../../node_modules/@tiptap/core/src/helpers/getSchemaByResolvedExtensions.ts","../../../node_modules/@tiptap/core/src/helpers/getSchemaTypeByName.ts","../../../node_modules/@tiptap/core/src/helpers/isExtensionRulesEnabled.ts","../../../node_modules/@tiptap/core/src/helpers/getHTMLFromFragment.ts","../../../node_modules/@tiptap/core/src/helpers/getTextContentFromNodes.ts","../../../node_modules/@tiptap/core/src/utilities/isRegExp.ts","../../../node_modules/@tiptap/core/src/InputRule.ts","../../../node_modules/@tiptap/core/src/utilities/isPlainObject.ts","../../../node_modules/@tiptap/core/src/utilities/mergeDeep.ts","../../../node_modules/@tiptap/core/src/Mark.ts","../../../node_modules/@tiptap/core/src/utilities/isNumber.ts","../../../node_modules/@tiptap/core/src/PasteRule.ts","../../../node_modules/@tiptap/core/src/utilities/findDuplicates.ts","../../../node_modules/@tiptap/core/src/ExtensionManager.ts","../../../node_modules/@tiptap/core/src/Extension.ts","../../../node_modules/@tiptap/core/src/helpers/getTextBetween.ts","../../../node_modules/@tiptap/core/src/helpers/getTextSerializersFromSchema.ts","../../../node_modules/@tiptap/core/src/extensions/clipboardTextSerializer.ts","../../../node_modules/@tiptap/core/src/commands/blur.ts","../../../node_modules/@tiptap/core/src/commands/clearContent.ts","../../../node_modules/@tiptap/core/src/commands/clearNodes.ts","../../../node_modules/@tiptap/core/src/commands/command.ts","../../../node_modules/@tiptap/core/src/commands/createParagraphNear.ts","../../../node_modules/@tiptap/core/src/commands/cut.ts","../../../node_modules/@tiptap/core/src/commands/deleteCurrentNode.ts","../../../node_modules/@tiptap/core/src/commands/deleteNode.ts","../../../node_modules/@tiptap/core/src/commands/deleteRange.ts","../../../node_modules/@tiptap/core/src/commands/deleteSelection.ts","../../../node_modules/@tiptap/core/src/commands/enter.ts","../../../node_modules/@tiptap/core/src/commands/exitCode.ts","../../../node_modules/@tiptap/core/src/utilities/objectIncludes.ts","../../../node_modules/@tiptap/core/src/helpers/getMarkRange.ts","../../../node_modules/@tiptap/core/src/helpers/getMarkType.ts","../../../node_modules/@tiptap/core/src/commands/extendMarkRange.ts","../../../node_modules/@tiptap/core/src/commands/first.ts","../../../node_modules/@tiptap/core/src/helpers/isTextSelection.ts","../../../node_modules/@tiptap/core/src/utilities/minMax.ts","../../../node_modules/@tiptap/core/src/helpers/resolveFocusPosition.ts","../../../node_modules/@tiptap/core/src/utilities/isAndroid.ts","../../../node_modules/@tiptap/core/src/utilities/isiOS.ts","../../../node_modules/@tiptap/core/src/utilities/isSafari.ts","../../../node_modules/@tiptap/core/src/commands/focus.ts","../../../node_modules/@tiptap/core/src/commands/forEach.ts","../../../node_modules/@tiptap/core/src/commands/insertContent.ts","../../../node_modules/@tiptap/core/src/utilities/elementFromString.ts","../../../node_modules/@tiptap/core/src/helpers/createNodeFromContent.ts","../../../node_modules/@tiptap/core/src/helpers/selectionToInsertionEnd.ts","../../../node_modules/@tiptap/core/src/commands/insertContentAt.ts","../../../node_modules/@tiptap/core/src/commands/join.ts","../../../node_modules/@tiptap/core/src/commands/joinItemBackward.ts","../../../node_modules/@tiptap/core/src/commands/joinItemForward.ts","../../../node_modules/@tiptap/core/src/commands/joinTextblockBackward.ts","../../../node_modules/@tiptap/core/src/commands/joinTextblockForward.ts","../../../node_modules/@tiptap/core/src/utilities/isMacOS.ts","../../../node_modules/@tiptap/core/src/commands/keyboardShortcut.ts","../../../node_modules/@tiptap/core/src/helpers/isNodeActive.ts","../../../node_modules/@tiptap/core/src/commands/lift.ts","../../../node_modules/@tiptap/core/src/commands/liftEmptyBlock.ts","../../../node_modules/@tiptap/core/src/commands/liftListItem.ts","../../../node_modules/@tiptap/core/src/commands/newlineInCode.ts","../../../node_modules/@tiptap/core/src/helpers/getSchemaTypeNameByName.ts","../../../node_modules/@tiptap/core/src/utilities/deleteProps.ts","../../../node_modules/@tiptap/core/src/commands/resetAttributes.ts","../../../node_modules/@tiptap/core/src/commands/scrollIntoView.ts","../../../node_modules/@tiptap/core/src/commands/selectAll.ts","../../../node_modules/@tiptap/core/src/commands/selectNodeBackward.ts","../../../node_modules/@tiptap/core/src/commands/selectNodeForward.ts","../../../node_modules/@tiptap/core/src/commands/selectParentNode.ts","../../../node_modules/@tiptap/core/src/commands/selectTextblockEnd.ts","../../../node_modules/@tiptap/core/src/commands/selectTextblockStart.ts","../../../node_modules/@tiptap/core/src/helpers/createDocument.ts","../../../node_modules/@tiptap/core/src/commands/setContent.ts","../../../node_modules/@tiptap/core/src/helpers/getMarkAttributes.ts","../../../node_modules/@tiptap/core/src/helpers/combineTransactionSteps.ts","../../../node_modules/@tiptap/core/src/helpers/defaultBlockAt.ts","../../../node_modules/@tiptap/core/src/helpers/findChildren.ts","../../../node_modules/@tiptap/core/src/helpers/findChildrenInRange.ts","../../../node_modules/@tiptap/core/src/helpers/findParentNodeClosestToPos.ts","../../../node_modules/@tiptap/core/src/helpers/findParentNode.ts","../../../node_modules/@tiptap/core/src/helpers/getSchema.ts","../../../node_modules/@tiptap/core/src/helpers/generateHTML.ts","../../../node_modules/@tiptap/core/src/helpers/generateJSON.ts","../../../node_modules/@tiptap/core/src/helpers/getText.ts","../../../node_modules/@tiptap/core/src/helpers/generateText.ts","../../../node_modules/@tiptap/core/src/helpers/getNodeAttributes.ts","../../../node_modules/@tiptap/core/src/helpers/getAttributes.ts","../../../node_modules/@tiptap/core/src/utilities/removeDuplicates.ts","../../../node_modules/@tiptap/core/src/helpers/getChangedRanges.ts","../../../node_modules/@tiptap/core/src/helpers/getDebugJSON.ts","../../../node_modules/@tiptap/core/src/helpers/getMarksBetween.ts","../../../node_modules/@tiptap/core/src/helpers/getNodeAtPosition.ts","../../../node_modules/@tiptap/core/src/helpers/getSplittedAttributes.ts","../../../node_modules/@tiptap/core/src/helpers/isMarkActive.ts","../../../node_modules/@tiptap/core/src/helpers/isActive.ts","../../../node_modules/@tiptap/core/src/helpers/isAtEndOfNode.ts","../../../node_modules/@tiptap/core/src/helpers/isAtStartOfNode.ts","../../../node_modules/@tiptap/core/src/helpers/isList.ts","../../../node_modules/@tiptap/core/src/helpers/isNodeEmpty.ts","../../../node_modules/@tiptap/core/src/helpers/isNodeSelection.ts","../../../node_modules/@tiptap/core/src/helpers/posToDOMRect.ts","../../../node_modules/@tiptap/core/src/helpers/rewriteUnknownContent.ts","../../../node_modules/@tiptap/core/src/commands/setMark.ts","../../../node_modules/@tiptap/core/src/commands/setMeta.ts","../../../node_modules/@tiptap/core/src/commands/setNode.ts","../../../node_modules/@tiptap/core/src/commands/setNodeSelection.ts","../../../node_modules/@tiptap/core/src/commands/setTextSelection.ts","../../../node_modules/@tiptap/core/src/commands/sinkListItem.ts","../../../node_modules/@tiptap/core/src/commands/splitBlock.ts","../../../node_modules/@tiptap/core/src/commands/splitListItem.ts","../../../node_modules/@tiptap/core/src/commands/toggleList.ts","../../../node_modules/@tiptap/core/src/commands/toggleMark.ts","../../../node_modules/@tiptap/core/src/commands/toggleNode.ts","../../../node_modules/@tiptap/core/src/commands/toggleWrap.ts","../../../node_modules/@tiptap/core/src/commands/undoInputRule.ts","../../../node_modules/@tiptap/core/src/commands/unsetAllMarks.ts","../../../node_modules/@tiptap/core/src/commands/unsetMark.ts","../../../node_modules/@tiptap/core/src/commands/updateAttributes.ts","../../../node_modules/@tiptap/core/src/commands/wrapIn.ts","../../../node_modules/@tiptap/core/src/commands/wrapInList.ts","../../../node_modules/@tiptap/core/src/extensions/commands.ts","../../../node_modules/@tiptap/core/src/extensions/drop.ts","../../../node_modules/@tiptap/core/src/extensions/editable.ts","../../../node_modules/@tiptap/core/src/extensions/focusEvents.ts","../../../node_modules/@tiptap/core/src/extensions/keymap.ts","../../../node_modules/@tiptap/core/src/extensions/paste.ts","../../../node_modules/@tiptap/core/src/extensions/tabindex.ts","../../../node_modules/@tiptap/core/src/NodePos.ts","../../../node_modules/@tiptap/core/src/style.ts","../../../node_modules/@tiptap/core/src/utilities/createStyleTag.ts","../../../node_modules/@tiptap/core/src/Editor.ts","../../../node_modules/@tiptap/core/src/inputRules/markInputRule.ts","../../../node_modules/@tiptap/core/src/inputRules/nodeInputRule.ts","../../../node_modules/@tiptap/core/src/inputRules/textblockTypeInputRule.ts","../../../node_modules/@tiptap/core/src/inputRules/textInputRule.ts","../../../node_modules/@tiptap/core/src/inputRules/wrappingInputRule.ts","../../../node_modules/@tiptap/core/src/Node.ts","../../../node_modules/@tiptap/core/src/NodeView.ts","../../../node_modules/@tiptap/core/src/pasteRules/markPasteRule.ts","../../../node_modules/@tiptap/core/src/utilities/canInsertNode.ts","../../../node_modules/@tiptap/core/src/utilities/escapeForRegEx.ts","../../../node_modules/@tiptap/core/src/utilities/isString.ts","../../../node_modules/@tiptap/core/src/pasteRules/nodePasteRule.ts","../../../node_modules/@tiptap/core/src/pasteRules/textPasteRule.ts","../../../node_modules/@tiptap/core/src/Tracker.ts","../../../node_modules/@tiptap/extension-heading/src/heading.ts","../src/TemplateAnnotation.ts","../src/InlineIcon.ts","../src/ImageNodeView.tsx","../src/utils/normalizeMalformedAssetUrl.ts","../src/tiptap/TiptapVideo.tsx","../src/tiptap/useResolvedMediaSrc.ts","../src/tiptap/TiptapAudio.tsx","../src/MentionExtension.tsx","../src/detectMarkdown.ts","../src/PreviewControls.tsx","../src/InlinePreviewGutter.tsx","../src/useHeadingLayout.ts","../src/OutlinePanel.tsx","../src/PreviewPanel.tsx","../src/buildPreviewDoc.ts","../src/PlainHtmlPreview.tsx","../src/utils/collectInlineFontAwesomeCss.ts","../src/ImageViewer.tsx","../src/ImageEditor.tsx","../src/imageEditor/CanvasSurface.tsx","../src/imageEditor/layers/EditorImageLayer.tsx","../src/imageEditor/layers/EditorTextLayer.tsx","../src/imageEditor/layers/EditorShapeLayer.tsx","../src/imageEditor/layers/SelectionHandles.tsx","../src/imageEditor/ImageVersionHistoryDropdown.tsx","../src/imageEditor/icons.tsx","../src/imageEditor/LayersPanel.tsx","../src/imageEditor/PropertiesPanel.tsx","../src/imageEditor/Toolbar.tsx","../src/imageEditor/useImageEditor.ts","../src/imageEditor/state.ts","../src/imageEditor/useImageEditorTokens.ts","../src/MediaBin.tsx","../src/DropZoneOverlay.tsx","../src/Tooltip.tsx","../src/hooks/useFileDrop.ts","../src/utils/dropUtils.ts","../src/ViewSwitcher.tsx","../src/ThemeCustomizerPanel.tsx","../src/jsonEditor/JsonEditorContext.tsx","../src/jsonEditor/RenderNode.tsx","../src/jsonEditor/editors.tsx","../src/jsonEditor/EmbeddedRichTextField.tsx","../src/jsonEditor/useJsonEditorTokens.ts","../src/jsonEditor/JsonEditor.tsx","../src/recorder/RecorderButton.tsx"],"sourcesContent":["/**\n * EditorShell\n *\n * Top-level shell component that composes the Toolbar, ViewSwitcher, editor\n * views, and StatusBar into a complete editing experience. Wraps everything\n * in an EditorProvider for shared state.\n */\n\nimport { useEffect, useRef, useState, useCallback, useMemo } from 'react';\nimport {\n EditorProvider,\n useEditorContext,\n type EditorView,\n type ImageDisplayMode,\n type MentionProvider,\n type DocumentLinkProvider,\n type ViewPreferences,\n type ThemeInheritance,\n} from './EditorContext';\nimport { Toolbar } from './Toolbar';\nimport { StatusBar } from './StatusBar';\nimport { RawEditor } from './RawEditor';\nimport { WysiwygEditor } from './WysiwygEditor';\nimport { InlinePreviewGutter } from './InlinePreviewGutter';\nimport { OutlinePanel } from './OutlinePanel';\nimport { PreviewPanel } from './PreviewPanel';\nimport { ImageViewer } from './ImageViewer';\nimport { ImageEditor } from './ImageEditor';\nimport { PreviewSettingsProvider, PreviewToolbarControls } from './PreviewControls';\nimport { MediaBin } from './MediaBin';\nimport { DropZoneOverlay } from './DropZoneOverlay';\nimport { TooltipLayer } from './Tooltip';\nimport { useFileDrop, type DropTarget } from './hooks/useFileDrop';\nimport {\n partitionFiles,\n processMediaFiles,\n processTextFile,\n processTextFiles,\n} from './utils/dropUtils';\nimport type { MediaProvider, Theme } from '@bendyline/squisq/schemas';\nimport { DARK_SURFACE, LIGHT_SURFACE } from '@bendyline/squisq/schemas';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport {\n MemoryContentContainer,\n scopeContainer,\n createMediaProviderFromContainer,\n} from '@bendyline/squisq/storage';\nimport type { PrunePolicy, SaveVersionResult } from '@bendyline/squisq/versions';\nimport type { CSSProperties, ReactNode } from 'react';\n\nexport type { EditorTheme } from './EditorContext';\n\nexport interface EditorShellProps {\n /** Initial markdown content */\n initialMarkdown?: string;\n /** Initial active view */\n /** Initial active view (default: 'wysiwyg') */\n initialView?: EditorView;\n /** Article ID for Doc generation */\n articleId?: string;\n /** Base path for media URLs in preview */\n basePath?: string;\n /** Called when markdown source changes */\n onChange?: (source: string) => void;\n /** Color theme: 'light' or 'dark' (default: 'light') */\n theme?: 'light' | 'dark';\n /** Additional class name */\n className?: string;\n /** CSS height for the shell container (default: '100vh') */\n height?: string;\n /**\n * Minimum CSS height for the shell. When either `minHeight` or\n * `maxHeight` is set, the shell switches to **auto-grow mode**:\n * `height` is ignored, the root becomes `height: auto` between the\n * bounds, and the content area scrolls internally when content\n * exceeds `maxHeight`. Useful for chat composers that should grow\n * with content up to some cap.\n */\n minHeight?: string;\n /** See `minHeight`. Upper bound of the auto-grow range. */\n maxHeight?: string;\n /** Optional MediaProvider for the Files panel. When set (even to null), a Files toggle appears in the toolbar. */\n mediaProvider?: MediaProvider | null;\n /**\n * The workspace-scoped `ContentContainer` for this document — the\n * folder that contains the doc, its `_files/` sidecar, sibling\n * documents, and any version snapshots. Used for:\n * - audio mapping (MP3 discovery + timing.json reading);\n * - version history snapshots (when `allowVersioning` is true);\n * - reading sibling `.md` files for the recursive HTML export;\n * - resolving per-document scoped views (e.g. the image-edit\n * sidecar derived via `scopeContainer`).\n * Doc-scoped concerns (per-doc media URLs, per-doc asset writes)\n * flow through `mediaProvider` instead — typically derived from\n * this container via `createMediaProviderFromContainer`.\n */\n workspaceContainer?: ContentContainer | null;\n /**\n * @deprecated Renamed to `workspaceContainer` to make the workspace-\n * vs. doc-scoped distinction explicit. Still accepted as a fallback\n * for now; remove in the next breaking release.\n */\n container?: ContentContainer | null;\n /**\n * Enable version history. Snapshots are stored at\n * `.versions/<basename>.<timestamp>.md` inside the same\n * `workspaceContainer`, so they ride along with the document when\n * the host serializes.\n *\n * Snapshots fire on idle (controlled by `versioningAutoSaveIdleMs`)\n * and can also be triggered host-side via the manager exposed in the\n * context (`useEditorContext().versioning`). Has no effect without a\n * `workspaceContainer` — a `console.warn` flags the misconfiguration\n * in dev.\n */\n allowVersioning?: boolean;\n /**\n * Override the document basename used in version filenames. Defaults\n * to the basename of the container's primary document path.\n */\n versionBasename?: string;\n /**\n * Prune policy applied after each successful save. Defaults to\n * `{ type: 'keep-last-n', n: 50 }` so the snapshot count stays bounded.\n */\n versioningPrunePolicy?: PrunePolicy;\n /**\n * Idle delay (ms) before the editor auto-saves a version. `0` disables\n * auto-save entirely (snapshots are then only saved when the host\n * calls `versioning.saveVersion()` from the context). Default: 5000.\n */\n versioningAutoSaveIdleMs?: number;\n /**\n * Notified after each `saveVersion` attempt. Fires for both successful\n * saves (`reason: 'saved'`) and skips (`'unchanged'`, `'no-document'`,\n * `'empty'`). Useful for hosts that want a \"Last saved\" indicator.\n */\n onSaveVersion?: (result: SaveVersionResult) => void;\n /** Show the Files toggle in the toolbar. Defaults to true when mediaProvider is passed. */\n showFilesToggle?: boolean;\n /** Content rendered at the left edge of the toolbar, before the view tabs. */\n toolbarSlotLeft?: ReactNode;\n /** Content rendered after the formatting controls (in the middle area of the toolbar). */\n toolbarSlotAfterActions?: ReactNode;\n /** Content rendered at the rightmost end of the toolbar, after all other elements. */\n toolbarSlotRight?: ReactNode;\n /**\n * Whether to show the \"Play\" (preview) tab in the toolbar. When false, the\n * tab and its preview panel are hidden, and ⌘3 becomes a no-op. Use this\n * when embedding the editor somewhere the slideshow preview doesn't make\n * sense (e.g. editing free-form prompt documents). Defaults to true.\n */\n showPlayTab?: boolean;\n /**\n * Optional \"submit on Enter\" callback. When provided, a plain Enter\n * keypress fires this callback instead of inserting a newline, and\n * Cmd/Ctrl+Enter inserts a newline instead. Matches chat-composer UX\n * (Slack, Discord). When omitted, the editor behaves normally.\n */\n submitOnEnter?: () => void;\n /**\n * Let the WYSIWYG editing surface fill its container instead of rendering\n * as a centered 800px \"page\" column. Useful when embedding in chat\n * composers, side panels, or any layout where the page metaphor doesn't\n * fit. Defaults to false (page mode).\n */\n fullWidth?: boolean;\n /**\n * Font-family stack applied to the editor **chrome** — toolbar buttons,\n * tabs, status bar, and control surfaces. The actual editing areas\n * (Tiptap / Monaco) keep their own fonts so document editing isn't\n * affected. Use this when the editor is embedded in a larger product\n * that has its own UX type system and you want the controls to blend in.\n *\n * @example\n * ```tsx\n * <EditorShell uxFont=\"'Hanken Grotesk', system-ui, sans-serif\" ... />\n * ```\n */\n uxFont?: string;\n /**\n * Drop the editor's generous page-style padding in favor of a tight\n * layout that hugs its container. The default WYSIWYG surface uses\n * 16×24px padding suitable for editing long-form documents; chat\n * composers want much less. Applies to the editing area only — the\n * toolbar, tabs, and status bar keep their normal sizing.\n */\n thinMargins?: boolean;\n /**\n * Render the bottom status bar (word / character / line / block counts\n * and parse-state indicator). Defaults to `true`. Set to `false` in\n * embedded surfaces — chat composers and other short-form inputs —\n * where the stats are noise.\n */\n showStatusBar?: boolean;\n /**\n * How images should be displayed in the WYSIWYG view. `'inline'`\n * (default) flows them at natural size up to the container width;\n * `'thumbnail'` constrains each image to a 100×100 box with\n * aspect-preserving containment — useful for chat composers and other\n * dense surfaces where a full-resolution paste would dominate the\n * layout. Storage bytes are unchanged either way.\n */\n imageDisplayMode?: ImageDisplayMode;\n /**\n * File name (e.g. `foo.ts`) or bare extension that the content\n * represents. When set to a non-markdown/text extension, the shell\n * enters **code mode**: Monaco picks the right language based on the\n * extension, the WYSIWYG and Preview tabs disappear, and the toolbar\n * drops its markdown-specific formatting buttons. Markdown-ish\n * extensions (`.md`, `.markdown`, `.mdown`, `.txt`) keep the full\n * experience. Omit to get today's markdown behavior unchanged.\n */\n fileName?: string;\n /**\n * Explicit Monaco language ID override (e.g. `'typescript'`,\n * `'python'`, `'json'`). Wins over the language derived from\n * `fileName`. Anything other than `'markdown'` or `'plaintext'`\n * switches the shell into code mode.\n */\n language?: string;\n /**\n * Optional async provider for `@`-mention suggestions. When supplied,\n * typing `@` inside the editor opens a popover of candidates; selecting\n * one inserts a `@[Label](scheme:id)` mention token. Used by chat\n * composers and any other surface that wants to address named entities\n * inline. Omit to disable mentions entirely.\n */\n mentionProvider?: MentionProvider | null;\n /**\n * Optional async provider for sibling-document suggestions in the\n * link insert dialog. When supplied, the dialog gains a \"Browse\n * documents\" picker so authors can pick a neighbor `.md` by name and\n * insert a relative-path link without typing the URL by hand. Hosts\n * that organize docs in a workspace (file-system, IndexedDB slot,\n * remote API, …) implement this; the editor stays agnostic.\n */\n documentLinkProvider?: DocumentLinkProvider | null;\n /**\n * Whether the in-editor media recorder is surfaced in the toolbar.\n * Defaults to true — when a `mediaProvider` is wired, a record\n * button appears next to the version history. Pass `false` to\n * suppress it (read-only embeds, surfaces where camera/screen\n * permission prompts would be jarring). Without a `mediaProvider`,\n * the button is hidden regardless of this prop.\n */\n allowRecording?: boolean;\n /**\n * Placeholder text shown in the WYSIWYG editor while the document is\n * empty. When omitted, the editor rotates through its own generic\n * \"start typing…\" prompts; pass a value here to override with copy\n * that fits the embedding surface (e.g. a chat composer knows who\n * the message is going to and can say so).\n */\n placeholder?: string;\n /**\n * When true, both editing surfaces become non-editable: Monaco runs in\n * `readOnly` mode and Tiptap is set to `editable: false`. The toolbar\n * still renders — hide it from the host side if you want a pure preview.\n * Useful for reference panels that show file content without inviting\n * accidental edits.\n */\n readOnly?: boolean;\n /**\n * Image source URL used when the resolved file mode is `image` (PNG,\n * JPEG, GIF, WebP, BMP, ICO, AVIF). When this prop is set, the shell\n * replaces its text-editing surfaces with a dedicated `ImageViewer`.\n *\n * Lifecycle of the URL is the caller's responsibility — when fed a\n * `blob:` URL, the host should `URL.revokeObjectURL` on unmount or\n * src change.\n */\n imageSrc?: string;\n /** Alt text passed through to the underlying ImageViewer. */\n imageAlt?: string;\n /**\n * Whether the image surface should render as a read-only viewer\n * (`'view'`, default) or as the editable {@link ImageEditor}\n * (`'edit'`). Editing requires {@link EditorShellProps.imageEditorContainer}\n * — without it the shell falls back to view mode and logs a warning.\n */\n imageMode?: 'view' | 'edit';\n /**\n * Sidecar `ContentContainer` for the image being edited. Conventionally\n * scoped to `<basename>_files/` via\n * `scopeContainer(parentContainer, basename + '_files')`. The image\n * editor persists `state.json`, layer assets in `assets/`, and (when\n * `allowVersioning` is true) snapshots in `.versions/` inside it.\n */\n imageEditorContainer?: ContentContainer;\n /**\n * Called after the user clicks Export in the image editor and the\n * raster blob is produced. When omitted, the editor triggers a\n * default browser download.\n */\n onImageExport?: (blob: Blob, format: 'png' | 'jpeg' | 'webp') => void;\n /**\n * Show an inline preview gutter to the right of the WYSIWYG editor.\n * The gutter renders one small SVG card per template-annotated block in\n * the document, letting authors see their rendered output without\n * leaving Edit mode. Auto-hidden via container query when the editor\n * body is narrower than ~720px. Defaults to `false`.\n */\n inlinePreview?: boolean;\n /**\n * Width in pixels for the inline preview gutter. Defaults to 320.\n * Only takes effect when {@link EditorShellProps.inlinePreview} is true.\n */\n inlinePreviewWidth?: number;\n /**\n * Show an outline pane on the left of the WYSIWYG editor — a\n * hierarchical tree of the document's headings (h1 → h2 → h3) with\n * click-to-scroll. Auto-hidden via container query on narrow editors.\n * Defaults to `false`. The toolbar's View menu can toggle this at\n * runtime regardless of the initial value.\n */\n outline?: boolean;\n /**\n * Width in pixels for the outline pane. Defaults to 240. Only takes\n * effect when {@link EditorShellProps.outline} is true (or the View\n * menu has toggled it on).\n */\n outlineWidth?: number;\n /**\n * Initial visibility of inline block-template tags on headings — the\n * chip rendered next to each heading in the WYSIWYG view that opens\n * the block-template picker. Defaults to true; the View menu can\n * toggle it at runtime regardless of the initial value.\n */\n blockTags?: boolean;\n /**\n * How much of the active Squisq theme the WYSIWYG editing surface\n * mirrors. Defaults to `'fonts'` — the historical behavior of\n * inheriting body / heading fonts only. The View menu can change it\n * at runtime.\n */\n themeInheritance?: ThemeInheritance;\n /**\n * Bundled view preferences — a serializable JSON blob covering the\n * runtime-toggleable view options surfaced in the View menu. When\n * provided, fields here override the corresponding individual props\n * (`outline`, `inlinePreview`, `showStatusBar`). Pair with\n * {@link onViewPreferencesChange} to externalize storage of these\n * preferences in the host.\n */\n viewPreferences?: ViewPreferences;\n /**\n * Notified after each user-driven toggle in the View menu. The\n * argument is a full snapshot of all view preferences — hosts can\n * persist it as-is. Not called when {@link viewPreferences} is\n * changed externally.\n */\n onViewPreferencesChange?: (prefs: ViewPreferences) => void;\n /**\n * Override the preview theme with an explicit `Theme` object. When set,\n * `Doc.themeId` and the user's theme dropdown selection are ignored for\n * the preview surface. Used by the theme customizer to live-preview an\n * in-progress theme without mutating the document.\n */\n themeOverride?: Theme | null;\n}\n\n/**\n * Complete markdown editor shell with toolbar, view switcher, and three\n * editing modes: Raw (Monaco), WYSIWYG (Tiptap), and Preview.\n */\nexport function EditorShell({\n initialMarkdown = '',\n initialView = 'wysiwyg',\n articleId = 'untitled',\n basePath = '/',\n onChange,\n theme = 'light',\n className,\n height = '100vh',\n minHeight,\n maxHeight,\n mediaProvider,\n workspaceContainer,\n container,\n allowVersioning = false,\n versionBasename,\n versioningPrunePolicy,\n versioningAutoSaveIdleMs,\n onSaveVersion,\n showFilesToggle,\n toolbarSlotLeft,\n toolbarSlotAfterActions,\n toolbarSlotRight,\n showPlayTab = true,\n submitOnEnter,\n fullWidth = false,\n uxFont,\n thinMargins = false,\n showStatusBar = true,\n imageDisplayMode = 'inline',\n fileName,\n language,\n mentionProvider,\n documentLinkProvider,\n allowRecording = true,\n placeholder,\n readOnly = false,\n imageSrc,\n imageAlt,\n imageMode = 'view',\n imageEditorContainer,\n onImageExport,\n inlinePreview = false,\n inlinePreviewWidth = 320,\n outline = false,\n outlineWidth = 240,\n blockTags = true,\n themeInheritance = 'fonts',\n viewPreferences,\n onViewPreferencesChange,\n themeOverride = null,\n}: EditorShellProps) {\n const effectiveContainer = workspaceContainer ?? container ?? null;\n\n // If the host gave us a `workspaceContainer` but no explicit `mediaProvider`,\n // derive one automatically. Without this, drag-and-drop of an image\n // into the editor silently failed (no provider \\u2192 nothing to upload to)\n // even though we had a perfectly good ContentContainer to write into.\n const effectiveMediaProvider = useMemo<MediaProvider | null | undefined>(() => {\n if (mediaProvider !== undefined) return mediaProvider;\n if (effectiveContainer) return createMediaProviderFromContainer(effectiveContainer);\n return undefined;\n }, [mediaProvider, effectiveContainer]);\n\n // Show the toggle when explicitly opted in, or when mediaProvider prop was passed at all\n const filesToggleEnabled = showFilesToggle ?? effectiveMediaProvider !== undefined;\n\n // If the host hides the Play tab but asked for it as the initial view,\n // fall back to wysiwyg so we don't boot into a tab the user can't leave.\n const effectiveInitialView: EditorView =\n !showPlayTab && initialView === 'preview' ? 'wysiwyg' : initialView;\n\n return (\n <EditorProvider\n initialMarkdown={initialMarkdown}\n initialView={effectiveInitialView}\n articleId={articleId}\n theme={theme}\n workspaceContainer={effectiveContainer}\n allowVersioning={allowVersioning}\n versionBasename={versionBasename}\n versioningPrunePolicy={versioningPrunePolicy}\n versioningAutoSaveIdleMs={versioningAutoSaveIdleMs}\n onSaveVersion={onSaveVersion}\n mediaProvider={effectiveMediaProvider}\n imageDisplayMode={imageDisplayMode}\n mentionProvider={mentionProvider}\n documentLinkProvider={documentLinkProvider}\n allowRecording={allowRecording}\n fileName={fileName}\n language={language}\n inlinePreview={inlinePreview}\n showStatusBar={showStatusBar}\n outline={outline}\n blockTags={blockTags}\n themeInheritance={themeInheritance}\n viewPreferences={viewPreferences}\n onViewPreferencesChange={onViewPreferencesChange}\n >\n <EditorShellInner\n basePath={basePath}\n onChange={onChange}\n className={className}\n height={height}\n minHeight={minHeight}\n maxHeight={maxHeight}\n placeholder={placeholder}\n mediaProvider={effectiveMediaProvider ?? null}\n workspaceContainer={effectiveContainer}\n filesToggleEnabled={filesToggleEnabled}\n toolbarSlotLeft={toolbarSlotLeft}\n toolbarSlotAfterActions={toolbarSlotAfterActions}\n toolbarSlotRight={toolbarSlotRight}\n showPlayTab={showPlayTab}\n submitOnEnter={submitOnEnter}\n fullWidth={fullWidth}\n uxFont={uxFont}\n thinMargins={thinMargins}\n readOnly={readOnly}\n imageSrc={imageSrc}\n imageAlt={imageAlt}\n imageMode={imageMode}\n imageEditorContainer={imageEditorContainer}\n onImageExport={onImageExport}\n allowVersioning={allowVersioning}\n versioningAutoSaveIdleMs={versioningAutoSaveIdleMs}\n inlinePreviewWidth={inlinePreviewWidth}\n outlineWidth={outlineWidth}\n themeOverride={themeOverride}\n />\n </EditorProvider>\n );\n}\n\ninterface EditorShellInnerProps {\n basePath: string;\n onChange?: (source: string) => void;\n className?: string;\n height: string;\n minHeight?: string;\n maxHeight?: string;\n placeholder?: string;\n mediaProvider: MediaProvider | null;\n workspaceContainer?: ContentContainer | null;\n filesToggleEnabled: boolean;\n toolbarSlotLeft?: ReactNode;\n toolbarSlotAfterActions?: ReactNode;\n toolbarSlotRight?: ReactNode;\n showPlayTab: boolean;\n submitOnEnter?: () => void;\n fullWidth: boolean;\n uxFont?: string;\n thinMargins: boolean;\n readOnly: boolean;\n imageSrc?: string;\n imageAlt?: string;\n imageMode: 'view' | 'edit';\n imageEditorContainer?: ContentContainer;\n onImageExport?: (blob: Blob, format: 'png' | 'jpeg' | 'webp') => void;\n allowVersioning: boolean;\n versioningAutoSaveIdleMs?: number;\n inlinePreviewWidth: number;\n outlineWidth: number;\n themeOverride: Theme | null;\n}\n\nfunction EditorShellInner({\n basePath,\n onChange,\n className,\n height,\n minHeight,\n maxHeight,\n placeholder,\n mediaProvider,\n workspaceContainer,\n filesToggleEnabled,\n toolbarSlotLeft,\n toolbarSlotAfterActions,\n toolbarSlotRight,\n showPlayTab,\n submitOnEnter,\n fullWidth,\n uxFont,\n thinMargins,\n readOnly,\n imageSrc,\n imageAlt,\n imageMode,\n imageEditorContainer,\n onImageExport,\n allowVersioning,\n versioningAutoSaveIdleMs,\n inlinePreviewWidth,\n outlineWidth,\n themeOverride,\n}: EditorShellInnerProps) {\n const {\n activeView,\n markdownSource,\n doc,\n theme,\n editorMode,\n insertAtCursor,\n replaceAll,\n tiptapEditor,\n monacoEditor,\n setMarkdownSource,\n inlinePreviewVisible,\n statusBarVisible,\n outlineVisible,\n imageEditTarget,\n closeImageEdit,\n bumpMediaRevision,\n } = useEditorContext();\n const isPreview = activeView === 'preview';\n const isCodeMode = editorMode === 'code';\n const isImageMode = editorMode === 'image';\n const isMarkdownMode = editorMode === 'markdown';\n const [showFiles, setShowFiles] = useState(false);\n const [mediaRefreshKey, setMediaRefreshKey] = useState(0);\n // Persistent fallback container for image-edit sidecars when the host\n // didn't supply one. Lifted to shell scope so opening the same image\n // multiple times sees the same `.imageEdits/<sanitized>/.versions/...`\n // snapshots — otherwise each modal mount would start from an empty\n // in-memory container and history would vanish on close.\n const imageEditFallbackContainerRef = useRef<MemoryContentContainer | null>(null);\n if (imageEditFallbackContainerRef.current === null) {\n imageEditFallbackContainerRef.current = new MemoryContentContainer();\n }\n const imageEditFallbackContainer = imageEditFallbackContainerRef.current;\n const isDark = theme === 'dark';\n\n const handleToggleFiles = useCallback(() => {\n setShowFiles((prev) => !prev);\n }, []);\n\n // ── Drag-and-drop file handling ──\n\n /**\n * Insert an uploaded media file at the editor's current cursor.\n *\n * - In **WYSIWYG** mode, insert an actual tiptap image node via\n * `setImage({src, alt})` (images) or a link mark (non-images).\n * Going through `setImage` directly mirrors the Toolbar's image\n * button and avoids the round-trip through `markdownToTiptap`\n * that historically lost `<img>` tags to tag-strip passes.\n * - In **raw (Monaco)** or **preview** mode, fall back to\n * `insertAtCursor` which emits the markdown snippet.\n *\n * Without this, upload-via-MediaBin and upload-via-drop both\n * added the file to the bin and nowhere else — the composer sent\n * an empty body and the downstream gezel reported \"nothing came\n * through.\"\n */\n const insertMediaRef = useCallback(\n (relativePath: string, name: string, mimeType: string) => {\n const alt = name.replace(/\\.[^.]+$/, '').replace(/[-_]/g, ' ');\n const isImage = mimeType.startsWith('image/');\n const snippet = isImage ? `![${alt}](${relativePath})` : `[${alt}](${relativePath})`;\n\n if (activeView === 'wysiwyg' && tiptapEditor) {\n if (isImage) {\n tiptapEditor.chain().focus().setImage({ src: relativePath, alt }).run();\n } else {\n tiptapEditor\n .chain()\n .focus()\n .insertContent([\n {\n type: 'text',\n marks: [{ type: 'link', attrs: { href: relativePath } }],\n text: alt,\n },\n ])\n .run();\n }\n return;\n }\n if (activeView === 'raw' && monacoEditor) {\n insertAtCursor(snippet);\n return;\n }\n // Preview mode — no interactive editor to insert into. Append\n // to markdown source so the ref is still in the buffer.\n setMarkdownSource(markdownSource ? `${markdownSource}\\n\\n${snippet}` : snippet);\n },\n [activeView, tiptapEditor, monacoEditor, insertAtCursor, markdownSource, setMarkdownSource],\n );\n\n const handleFileDrop = useCallback(\n async (files: File[], target: DropTarget) => {\n try {\n const { media, text } = partitionFiles(files);\n\n // Process media files\n if (media.length > 0 && mediaProvider) {\n const paths = await processMediaFiles(media, mediaProvider);\n setMediaRefreshKey((k) => k + 1);\n // Auto-open the media bin so the user sees the new files\n if (!showFiles) setShowFiles(true);\n // Insert each uploaded file as a markdown ref at the cursor so\n // the body actually contains the attachment. Without this the\n // bin holds the file but the serialized markdown stays empty,\n // and anything downstream (chat send, document save) sees no\n // reference to the upload.\n for (let i = 0; i < media.length; i++) {\n const file = media[i];\n const path = paths[i];\n if (!file || !path) continue;\n insertMediaRef(path, file.name, file.type || 'application/octet-stream');\n }\n }\n\n // Process text files\n if (text.length > 0) {\n if (target === 'replace') {\n // Replace with first text file\n const content = await processTextFile(text[0]);\n replaceAll(content);\n } else {\n // Insert all text files concatenated\n const content = await processTextFiles(text);\n insertAtCursor(content);\n }\n }\n } catch (err: unknown) {\n console.error('Failed to process dropped files:', err instanceof Error ? err.message : err);\n }\n },\n [mediaProvider, showFiles, replaceAll, insertAtCursor, insertMediaRef],\n );\n\n const { isDragging, dragContentType, containerProps, zoneProps } = useFileDrop({\n onDrop: handleFileDrop,\n });\n\n // Notify parent of changes\n useEffect(() => {\n onChange?.(markdownSource);\n }, [markdownSource, onChange]);\n\n // Keyboard shortcuts for view switching\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.ctrlKey || e.metaKey) {\n switch (e.key) {\n case '1':\n e.preventDefault();\n document.querySelector<HTMLButtonElement>('[data-view=\"wysiwyg\"]')?.click();\n break;\n case '2':\n e.preventDefault();\n document.querySelector<HTMLButtonElement>('[data-view=\"raw\"]')?.click();\n break;\n case '3':\n if (!showPlayTab) return;\n e.preventDefault();\n document.querySelector<HTMLButtonElement>('[data-view=\"preview\"]')?.click();\n break;\n }\n }\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [showPlayTab]);\n\n const autoGrow = minHeight !== undefined || maxHeight !== undefined;\n\n return (\n <div\n className={`squisq-editor-shell ${className || ''}`}\n data-theme={theme}\n data-full-width={fullWidth ? 'true' : undefined}\n data-thin-margins={thinMargins ? 'true' : undefined}\n data-outline-visible={isMarkdownMode && outlineVisible ? 'true' : undefined}\n style={{\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n ...(autoGrow ? { minHeight, maxHeight } : { height }),\n // When a consumer supplies a UX font stack, expose it to the\n // editor CSS via this custom property. Chrome elements (toolbar,\n // tabs, status bar) consume `--squisq-ux-font` as their\n // `font-family`, falling back to the system stack when unset.\n ...(uxFont ? ({ '--squisq-ux-font': uxFont } as CSSProperties) : {}),\n // Exposed so the toolbar's view-tabs section can match the outline\n // pane's width, lining up its right-edge separator with the\n // outline's right edge. The variable is set unconditionally so the\n // outline pane itself can also read it if needed; the\n // `data-outline-visible` gate above keeps the toolbar override\n // scoped to the case where alignment matters.\n ...({ '--squisq-outline-width': `${outlineWidth}px` } as CSSProperties),\n }}\n {...containerProps}\n >\n <PreviewSettingsProvider doc={doc} themeOverride={themeOverride}>\n {/* Header. In image mode the full markdown/code Toolbar is replaced\n with a minimal slot bar — view tabs, formatting, and preview\n controls don't apply to a binary asset. */}\n {isImageMode ? (\n (toolbarSlotLeft || toolbarSlotRight) && (\n <div className=\"squisq-editor-header squisq-editor-header--image\">\n {toolbarSlotLeft}\n <div style={{ flex: 1 }} />\n {toolbarSlotRight}\n </div>\n )\n ) : (\n <div className=\"squisq-editor-header\">\n <Toolbar\n showFiles={showFiles}\n onToggleFiles={!isCodeMode && filesToggleEnabled ? handleToggleFiles : undefined}\n slotLeft={toolbarSlotLeft}\n slotAfterActions={\n <>\n {toolbarSlotAfterActions}\n {!isCodeMode && isPreview && <PreviewToolbarControls />}\n </>\n }\n slotRight={toolbarSlotRight}\n showPlayTab={showPlayTab}\n />\n </div>\n )}\n\n {/* Main content area */}\n <div\n className=\"squisq-editor-content\"\n style={{\n flex: autoGrow ? '1 1 auto' : 1,\n overflowY: autoGrow ? 'auto' : 'hidden',\n overflowX: 'hidden',\n minHeight: 0,\n position: 'relative',\n display: 'flex',\n }}\n >\n <div\n style={{\n flex: autoGrow ? '1 1 auto' : 1,\n overflow: autoGrow ? 'visible' : 'hidden',\n minHeight: 0,\n position: 'relative',\n }}\n >\n {isImageMode &&\n imageSrc &&\n (imageMode === 'edit' && imageEditorContainer ? (\n <ImageEditor\n filesContainer={imageEditorContainer}\n initialSrc={imageSrc}\n allowVersioning={allowVersioning}\n versioningAutoSaveIdleMs={versioningAutoSaveIdleMs}\n onExport={onImageExport}\n />\n ) : (\n <ImageViewer src={imageSrc} alt={imageAlt} theme={theme} />\n ))}\n {/* Raw (Monaco) view. Always wrapped in `.squisq-editor-with-gutter`\n so toggling a pane on/off doesn't change the editor's tree\n position — Monaco stays mounted and `monacoEditor` in\n context stays stable, which is what `useHeadingLayout` needs\n to compute positions. */}\n {!isImageMode && activeView === 'raw' && (\n <div className=\"squisq-editor-with-gutter\" key=\"raw-shell\">\n {isMarkdownMode && outlineVisible && (\n <OutlinePanel key=\"outline\" width={outlineWidth} />\n )}\n <div key=\"raw-editor\" className=\"squisq-raw-editor-container\">\n <RawEditor\n theme={theme === 'dark' ? 'vs-dark' : 'vs'}\n submitOnEnter={submitOnEnter}\n readOnly={readOnly}\n />\n </div>\n {isMarkdownMode && inlinePreviewVisible && (\n <InlinePreviewGutter\n key=\"inline\"\n width={inlinePreviewWidth}\n basePath={basePath}\n mediaProvider={mediaProvider}\n />\n )}\n </div>\n )}\n {/* WYSIWYG + Preview are markdown-only surfaces — skip them\n entirely in code or image mode so Tiptap never initializes\n and the preview pipeline stays idle. Same always-wrapped\n pattern as the Raw branch above so pane toggles don't\n remount Tiptap. */}\n {isMarkdownMode && activeView === 'wysiwyg' && (\n <div className=\"squisq-editor-with-gutter\" key=\"wysiwyg-shell\">\n {outlineVisible && <OutlinePanel key=\"outline\" width={outlineWidth} />}\n <WysiwygEditor\n key=\"wysiwyg-editor\"\n submitOnEnter={submitOnEnter}\n placeholder={placeholder}\n readOnly={readOnly}\n />\n {inlinePreviewVisible && (\n <InlinePreviewGutter\n key=\"inline\"\n width={inlinePreviewWidth}\n basePath={basePath}\n mediaProvider={mediaProvider}\n />\n )}\n </div>\n )}\n {isMarkdownMode && isPreview && (\n <PreviewPanel basePath={basePath} workspaceContainer={workspaceContainer} />\n )}\n </div>\n\n {isMarkdownMode && showFiles && (\n <MediaBin\n mediaProvider={mediaProvider}\n isDark={isDark}\n refreshKey={mediaRefreshKey}\n onMediaUploaded={insertMediaRef}\n />\n )}\n\n {/* Drop zone overlay — image / text drop UX is markdown-specific.\n In WYSIWYG, image drops are handled directly by Tiptap's\n `handleDrop` (uploads to the MediaProvider and inserts an\n image node at the mouse position). The overlay would sit on\n top with z-index: 50 and intercept the drop, so we skip it\n when the dragged content is media-only on the WYSIWYG view —\n the user gets a one-step \"drop where you want it\" flow\n instead of a two-step \"drop in bin, then insert\" flow. */}\n {isMarkdownMode &&\n isDragging &&\n !(activeView === 'wysiwyg' && dragContentType === 'media') && (\n <DropZoneOverlay\n dragContentType={dragContentType}\n zoneProps={zoneProps}\n hasMediaProvider={mediaProvider !== null}\n />\n )}\n </div>\n\n {/* Status bar — word / char / line / block counts. Host can\n suppress via `showStatusBar={false}` for embedded chat-style\n composers where the stats are noise. The image viewer has its\n own dimension/zoom status row, so suppress here too. */}\n {statusBarVisible && !isImageMode && <StatusBar />}\n </PreviewSettingsProvider>\n <TooltipLayer />\n {imageEditTarget !== null && mediaProvider && (\n <ImageEditModal\n relativePath={imageEditTarget}\n container={workspaceContainer ?? imageEditFallbackContainer}\n mediaProvider={mediaProvider}\n onClose={closeImageEdit}\n onSaved={() => {\n bumpMediaRevision();\n closeImageEdit();\n }}\n allowVersioning={allowVersioning}\n versioningAutoSaveIdleMs={versioningAutoSaveIdleMs}\n shellTheme={theme}\n />\n )}\n </div>\n );\n}\n\n// ─── ImageEditModal ────────────────────────────────────────\n\ninterface ImageEditModalProps {\n relativePath: string;\n /**\n * Host's `ContentContainer`. When non-null the editor's per-image\n * sidecar is scoped underneath it as `.imageEdits/<sanitized>/` so\n * version snapshots travel with the doc. When null (host wired only a\n * `mediaProvider`) the modal creates a fresh in-memory container for\n * the edit session — export still writes the result back through\n * `mediaProvider`.\n */\n container: ContentContainer | null;\n mediaProvider: MediaProvider;\n onClose: () => void;\n onSaved: () => void;\n allowVersioning: boolean;\n versioningAutoSaveIdleMs?: number;\n /** EditorShell's `theme` prop — 'light' or 'dark'. Threaded through so\n * the image editor chrome matches the host shell. */\n shellTheme?: 'light' | 'dark';\n}\n\n/**\n * Modal overlay that mounts a full `<ImageEditor>` against a sidecar\n * container scoped under `.imageEdits/<sanitized-path>/` of the document's\n * `ContentContainer`. Opens when a user clicks the \"Edit\" affordance on an\n * image in the WYSIWYG view; on Export, rewrites the original image bytes\n * via `mediaProvider.addMedia(relativePath, blob, mime)` and bumps\n * `mediaRevision` so live `<img>` nodes pick up the new content.\n */\nfunction ImageEditModal({\n relativePath,\n container,\n mediaProvider,\n onClose,\n onSaved,\n allowVersioning,\n versioningAutoSaveIdleMs,\n shellTheme,\n}: ImageEditModalProps) {\n // Each unique image path gets its own sidecar so multiple images in the\n // same doc can be edited independently without colliding state. When the\n // host didn't supply a `container`, fall back to a fresh in-memory one\n // — the edit session is transient anyway and the final raster is what\n // gets written back through `mediaProvider`.\n const sidecar = useMemo(() => {\n const sanitized = relativePath.replace(/[^a-zA-Z0-9._-]+/g, '_');\n const parent: ContentContainer = container ?? new MemoryContentContainer();\n return scopeContainer(parent, `.imageEdits/${sanitized}`);\n }, [container, relativePath]);\n\n const [initialSrc, setInitialSrc] = useState<string | null>(null);\n const [resolveError, setResolveError] = useState<string | null>(null);\n useEffect(() => {\n let cancelled = false;\n mediaProvider.resolveUrl(relativePath).then(\n (url) => {\n if (!cancelled) setInitialSrc(url);\n },\n (err: unknown) => {\n if (!cancelled) {\n setResolveError(err instanceof Error ? err.message : String(err));\n }\n },\n );\n return () => {\n cancelled = true;\n };\n }, [mediaProvider, relativePath]);\n\n const handleExport = useCallback(\n (blob: Blob, format: 'png' | 'jpeg' | 'webp') => {\n const mime = `image/${format}`;\n mediaProvider.addMedia(relativePath, blob, mime).then(\n () => onSaved(),\n (err: unknown) => {\n console.error('Failed to write image back:', err instanceof Error ? err.message : err);\n },\n );\n },\n [mediaProvider, relativePath, onSaved],\n );\n\n // Close on Escape — global listener so it works regardless of focus.\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [onClose]);\n\n return (\n <div\n className=\"squisq-image-edit-modal\"\n data-testid=\"image-edit-modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={`Edit ${relativePath}`}\n onClick={(e) => {\n // Click on the dim backdrop (but not on the surface) → close.\n if (e.target === e.currentTarget) onClose();\n }}\n >\n <div className=\"squisq-image-edit-modal__surface\">\n <header className=\"squisq-image-edit-modal__header\">\n <span className=\"squisq-image-edit-modal__title\">Edit image</span>\n <span className=\"squisq-image-edit-modal__path\">{relativePath}</span>\n <button\n type=\"button\"\n className=\"squisq-image-edit-modal__close\"\n data-testid=\"image-edit-modal-close\"\n onClick={onClose}\n aria-label=\"Close image editor\"\n >\n ×\n </button>\n </header>\n <div className=\"squisq-image-edit-modal__body\">\n {resolveError ? (\n <div className=\"squisq-image-edit-modal__error\">\n Failed to load image: {resolveError}\n </div>\n ) : !initialSrc ? (\n <div className=\"squisq-image-edit-modal__loading\">Loading image…</div>\n ) : (\n <ImageEditor\n filesContainer={sidecar}\n initialSrc={initialSrc}\n allowVersioning={allowVersioning}\n versioningAutoSaveIdleMs={versioningAutoSaveIdleMs}\n onExport={handleExport}\n saveBehavior=\"export\"\n saveFormat=\"png\"\n saveLabel=\"Save and close\"\n saveTitle=\"Save changes back to the image and close\"\n surface={shellTheme === 'dark' ? DARK_SURFACE : LIGHT_SURFACE}\n />\n )}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * EditorContext\n *\n * Shared React context that synchronizes state across all three editor views\n * (Raw/Monaco, WYSIWYG/Tiptap, Preview/DocPlayer). When any view modifies the\n * markdown source, the context re-parses and regenerates the MarkdownDocument\n * and Doc so all views stay in sync.\n */\n\nimport {\n createContext,\n useContext,\n useState,\n useCallback,\n useMemo,\n useRef,\n useEffect,\n type ReactNode,\n} from 'react';\nimport type { Doc, MediaProvider } from '@bendyline/squisq/schemas';\nimport type { MarkdownDocument } from '@bendyline/squisq/markdown';\nimport { parseMarkdown, stringifyMarkdown } from '@bendyline/squisq/markdown';\nimport { markdownToDoc } from '@bendyline/squisq/doc';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport {\n DocumentVersionManager,\n type PrunePolicy,\n type SaveVersionOptions,\n type SaveVersionResult,\n} from '@bendyline/squisq/versions';\nimport type { Editor as TiptapEditor } from '@tiptap/core';\nimport type { editor as MonacoEditorNs } from 'monaco-editor';\nimport { markdownToTiptap } from './tiptapBridge';\nimport { resolveFileKind } from './fileKind';\n\n/** Monaco standalone code editor instance type */\ntype MonacoEditor = MonacoEditorNs.IStandaloneCodeEditor;\n\n/**\n * One candidate returned by a {@link MentionProvider}. Shown in the editor's\n * `@` popover. `id` is the stable identifier (serialized into the mention\n * wire format); `label` is what the reader sees; `scheme` is the namespace\n * (e.g. `'user'`, `'issue'`) written into the markdown as `@[label](scheme:id)`;\n * `description` and `group` are optional hints for richer suggestion UIs.\n *\n * Different candidates in the same result set may carry different schemes —\n * a provider that returns both users and issues, for example, tags each\n * candidate with its own namespace and the editor emits mentions accordingly.\n */\nexport interface MentionCandidate {\n id: string;\n label: string;\n scheme: string;\n description?: string;\n group?: string;\n}\n\n/**\n * Looks up mention candidates matching a query. Called as the user types\n * after `@`. The provider is free to do server-side or client-side filtering;\n * the editor only cares that candidates come back in relevance order.\n */\nexport type MentionProvider = (query: string) => Promise<MentionCandidate[]>;\n\n/**\n * A document that the link dialog's \"Browse documents\" picker can offer.\n * `path` is what lands in the markdown URL (typically relative to the\n * current document so `home.md → resume.md` round-trips through file-\n * system serializers). `label` is the human name shown in the list.\n * `description` is an optional secondary line (e.g. workspace folder,\n * last-modified date).\n */\nexport interface DocumentLinkCandidate {\n path: string;\n label: string;\n description?: string;\n}\n\n/**\n * Resolves sibling / workspace document candidates for the link dialog.\n * The editor itself has no notion of \"neighbors\" — hosts that organize\n * docs in a workspace (e.g. docblocks) implement this to power the\n * dialog's document picker. Pass `''` as the query for an initial list\n * (the dialog calls it once on open); subsequent calls narrow by user\n * input.\n */\nexport type DocumentLinkProvider = (query: string) => Promise<DocumentLinkCandidate[]>;\n\n// ─── Types ───────────────────────────────────────────────\n\nexport type EditorView = 'raw' | 'wysiwyg' | 'preview';\nexport type EditorTheme = 'light' | 'dark';\n/**\n * How much of the active Squisq theme the WYSIWYG editing surface\n * mirrors. `'fonts'` is the historical default — body and heading\n * fonts only. `'fonts-colors'` also borrows the theme canvas / text\n * colors. `'none'` opts out completely.\n */\nexport type ThemeInheritance = 'none' | 'fonts' | 'fonts-colors';\n/**\n * Editor operating mode. `markdown` is the full experience (WYSIWYG +\n * Preview tabs, formatting toolbar). `code` is a Monaco-only view used\n * when the content represents a non-markdown file like `foo.ts`.\n */\nexport type EditorMode = 'markdown' | 'code' | 'image';\n\nexport interface EditorState {\n /** Raw markdown source string */\n markdownSource: string;\n /** Parsed markdown document (JSON DOM) */\n markdownDoc: MarkdownDocument | null;\n /** Generated Doc (block hierarchy) */\n doc: Doc | null;\n /** Currently active editor view */\n activeView: EditorView;\n /** Parse error, if any */\n parseError: string | null;\n /** Whether a parse is pending */\n isParsing: boolean;\n /** Current color theme */\n theme: EditorTheme;\n /** Operating mode — 'markdown' for the full shell, 'code' for Monaco-only. */\n editorMode: EditorMode;\n /** Monaco language ID for the Raw editor. */\n language: string;\n /**\n * Whether the inline preview gutter (per-block card previews next to the\n * WYSIWYG surface) is currently visible. Initialized from the EditorShell\n * `inlinePreview` prop; the View menu in the toolbar can toggle it at\n * runtime.\n */\n inlinePreviewVisible: boolean;\n /**\n * Whether the bottom status bar is currently visible. Initialized from\n * the EditorShell `showStatusBar` prop (default true); the View menu in\n * the toolbar can toggle it at runtime.\n */\n statusBarVisible: boolean;\n /**\n * Whether the left-side outline pane is currently visible. Initialized\n * from the EditorShell `outline` prop (default false); the View menu in\n * the toolbar can toggle it at runtime.\n */\n outlineVisible: boolean;\n /**\n * Whether inline block-template tags (the chip next to each templated\n * heading in the WYSIWYG view, plus the subtle affordance chip on plain\n * headings) are currently visible. Initialized from the EditorShell\n * `blockTags` prop (default true); the View menu in the toolbar can\n * toggle it at runtime.\n */\n blockTagsVisible: boolean;\n /**\n * How much of the active Squisq theme the WYSIWYG editing surface should\n * inherit. `'none'` shows the default editor styling, `'fonts'` (the\n * default) matches body and heading fonts only, and `'fonts-colors'`\n * also borrows the theme's canvas / text colors so authors get a\n * closer preview while editing.\n */\n themeInheritance: ThemeInheritance;\n /**\n * Relative path of an image the user requested to edit, or `null` when\n * no editor is open. Surfaced by `<ImageNodeView>`'s hover affordance\n * and consumed by `<EditorShell>` to render the modal `<ImageEditor>`.\n */\n imageEditTarget: string | null;\n /**\n * Monotonic counter bumped whenever a managed media asset is rewritten\n * (e.g. after the image-editor modal saves back). Image render paths\n * that cache resolved blob URLs should include this in their effect\n * deps so the new bytes get picked up.\n */\n mediaRevision: number;\n /**\n * Whether the in-editor media recorder should be available. Defaults\n * to true when a `mediaProvider` is wired; hosts that explicitly\n * don't want the affordance (e.g. read-only embeds, surfaces where\n * camera/screen prompts would be jarring) can pass `false` on the\n * shell.\n */\n allowRecording: boolean;\n}\n\nexport interface EditorActions {\n /** Set markdown source and trigger re-parse */\n setMarkdownSource: (source: string) => void;\n /** Set markdown from a MarkdownDocument (e.g. from WYSIWYG) */\n setMarkdownDoc: (doc: MarkdownDocument) => void;\n /** Switch the active view */\n setActiveView: (view: EditorView) => void;\n /** Register / unregister the Tiptap editor instance (called by WysiwygEditor) */\n setTiptapEditor: (editor: TiptapEditor | null) => void;\n /** Register / unregister the Monaco editor instance (called by RawEditor) */\n setMonacoEditor: (editor: MonacoEditor | null) => void;\n /** Set the color theme */\n setTheme: (theme: EditorTheme) => void;\n /** Show or hide the inline preview gutter at runtime (driven by the View menu). */\n setInlinePreviewVisible: (visible: boolean) => void;\n /** Show or hide the bottom status bar at runtime (driven by the View menu). */\n setStatusBarVisible: (visible: boolean) => void;\n /** Show or hide the left-side outline pane at runtime (driven by the View menu). */\n setOutlineVisible: (visible: boolean) => void;\n /** Show or hide inline block-template tags at runtime (driven by the View menu). */\n setBlockTagsVisible: (visible: boolean) => void;\n /** Change how much of the active Squisq theme the WYSIWYG surface mirrors. */\n setThemeInheritance: (mode: ThemeInheritance) => void;\n /** Insert text at the current cursor position in the active editor */\n insertAtCursor: (text: string) => void;\n /** Replace all editor content with the given text */\n replaceAll: (text: string) => void;\n /**\n * Request the modal image editor open on the given relative media path.\n * The path must resolve through the active `mediaProvider`. No-op when\n * no provider is wired — callers should hide the affordance in that\n * case.\n */\n openImageEdit: (relativePath: string) => void;\n /** Close the image editor modal without saving. */\n closeImageEdit: () => void;\n /**\n * Bump `mediaRevision`. Called after the image editor writes back to\n * the original media path so dependent `<img>` nodes re-resolve their\n * blob URL.\n */\n bumpMediaRevision: () => void;\n}\n\nexport interface EditorContextValue extends EditorState, EditorActions {\n /** The live Tiptap editor instance (null when WYSIWYG is not mounted) */\n tiptapEditor: TiptapEditor | null;\n /** The live Monaco editor instance (null when Raw is not mounted) */\n monacoEditor: MonacoEditor | null;\n /**\n * Workspace-scoped `ContentContainer` for this document — the folder\n * holding the doc, its `_files/` sidecar, sibling documents, and any\n * version snapshots. Drives audio mapping, version history, and\n * sibling-doc reads for the recursive HTML export.\n */\n workspaceContainer: ContentContainer | null;\n /**\n * Version manager — non-null only when the host opted into versioning\n * (`allowVersioning` + a `workspaceContainer`). Components can call\n * `saveVersion` directly, or render the version-history panel which\n * reads it from here.\n */\n versioning: DocumentVersionManager | null;\n /**\n * Stamp a new snapshot of the current document. No-op (returns\n * `unchanged`) when content matches the latest version. Always safe\n * to call — when versioning is disabled, returns `no-document`\n * without writing.\n */\n saveVersion: (options?: SaveVersionOptions) => Promise<SaveVersionResult>;\n /** MediaProvider for resolving image URLs in the WYSIWYG editor */\n mediaProvider: MediaProvider | null;\n /**\n * How pasted/inserted images should be displayed in the WYSIWYG view.\n * `'inline'` (default) lets them flow at natural size up to the editor\n * width; `'thumbnail'` constrains them to a 100×100 box so chat\n * composers and other dense surfaces don't get dominated by a single\n * pasted screenshot. The stored image bytes are unchanged — this is a\n * pure render-time decision.\n */\n imageDisplayMode: ImageDisplayMode;\n /**\n * Optional provider for `@`-mention suggestions. When set, both the\n * WYSIWYG (Tiptap) and Raw (Monaco) editors show a mention popover as\n * the user types `@<query>`. When unset, `@` is just a literal character.\n */\n mentionProvider: MentionProvider | null;\n /**\n * Optional provider for sibling-document suggestions in the link\n * dialog. When set, the dialog shows a \"Browse documents\" picker that\n * lets authors search neighbor docs by name and insert a relative-\n * path link. When unset, the dialog falls back to URL-only.\n */\n documentLinkProvider: DocumentLinkProvider | null;\n}\n\nexport type ImageDisplayMode = 'inline' | 'thumbnail';\n\n// ─── Context ─────────────────────────────────────────────\n\nconst EditorContext = createContext<EditorContextValue | null>(null);\n\n/**\n * Hook to access the editor context. Must be used within an EditorProvider.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useEditorContext(): EditorContextValue {\n const ctx = useContext(EditorContext);\n if (!ctx) {\n throw new Error('useEditorContext must be used within an <EditorProvider>');\n }\n return ctx;\n}\n\n// ─── Provider ────────────────────────────────────────────\n\nexport interface EditorProviderProps {\n /** Initial markdown content */\n initialMarkdown?: string;\n /** Initial active view */\n initialView?: EditorView;\n /** Article ID used when generating the Doc */\n articleId?: string;\n /** Color theme */\n theme?: EditorTheme;\n /**\n * Workspace-scoped `ContentContainer` for this document — the folder\n * holding the doc, its `_files/` sidecar, sibling documents, and any\n * version snapshots. Required for `allowVersioning` to take effect.\n */\n workspaceContainer?: ContentContainer | null;\n /**\n * Enable version history. Snapshots are stored at\n * `.versions/<basename>.<timestamp>.md` inside `workspaceContainer`.\n * Auto-save fires after `versioningAutoSaveIdleMs` of idle; hosts can\n * also call `saveVersion()` from the context. Without a\n * `workspaceContainer`, this prop is ignored (and a `console.warn` is\n * emitted).\n */\n allowVersioning?: boolean;\n /** Override the basename used in version filenames. Defaults to the\n * basename of the container's primary document path. */\n versionBasename?: string;\n /**\n * Prune policy applied after each successful auto-save. Defaults to\n * keeping the last 50 snapshots so the count doesn't grow unbounded.\n */\n versioningPrunePolicy?: PrunePolicy;\n /**\n * Idle delay (ms) before auto-saving a version. `0` disables auto-save\n * entirely (versions are saved only via host-driven `saveVersion`\n * calls). Default: 5000.\n */\n versioningAutoSaveIdleMs?: number;\n /**\n * Notified after each `saveVersion` attempt — both successful saves\n * (`reason: 'saved'`) and skips (`'unchanged'`, `'no-document'`,\n * `'empty'`). Useful for hosts that want a \"Last saved\" indicator.\n */\n onSaveVersion?: (result: SaveVersionResult) => void;\n /** MediaProvider for resolving image URLs */\n mediaProvider?: MediaProvider | null;\n /** Display mode for images in the WYSIWYG view. Defaults to `'inline'`. */\n imageDisplayMode?: ImageDisplayMode;\n /**\n * Async provider for `@`-mention suggestions. Omit to disable mentions\n * entirely — typing `@` becomes just a literal character again.\n */\n mentionProvider?: MentionProvider | null;\n /**\n * Async provider for sibling-document suggestions in the link dialog.\n * Omit to fall back to URL-only link insertion.\n */\n documentLinkProvider?: DocumentLinkProvider | null;\n /**\n * Whether the in-editor media recorder is available in the toolbar.\n * Defaults to true. Set to false to suppress the recorder affordance\n * even when a `mediaProvider` is wired (e.g. read-only embeds,\n * surfaces where camera/screen prompts would be jarring).\n */\n allowRecording?: boolean;\n /**\n * File name (e.g. `foo.ts`) or bare extension — used to pick a Monaco\n * language and decide between markdown vs. code mode.\n */\n fileName?: string;\n /** Explicit Monaco language ID — wins over the fileName-derived one. */\n language?: string;\n /**\n * Initial visibility of the inline preview gutter. Defaults to false.\n * The toolbar's View menu can toggle it at runtime.\n */\n inlinePreview?: boolean;\n /**\n * Initial visibility of the bottom status bar. Defaults to true.\n * The toolbar's View menu can toggle it at runtime.\n */\n showStatusBar?: boolean;\n /**\n * Initial visibility of the left-side outline pane. Defaults to false.\n * The toolbar's View menu can toggle it at runtime.\n */\n outline?: boolean;\n /**\n * Initial visibility of inline block-template tags on headings.\n * Defaults to true. The toolbar's View menu can toggle it at runtime.\n */\n blockTags?: boolean;\n /**\n * Initial value for how much of the active Squisq theme the WYSIWYG\n * editing surface should mirror. Defaults to `'fonts'` — the\n * historical behavior of inheriting body / heading fonts only. The\n * toolbar's View menu can change it at runtime.\n */\n themeInheritance?: ThemeInheritance;\n /**\n * Bundled view preferences — a serializable JSON blob covering all\n * runtime-toggleable view options. When provided, individual values\n * here override the matching individual props (`inlinePreview`,\n * `showStatusBar`, `outline`). Hosts wiring this up typically load\n * the blob from their own preferences storage and pair it with\n * {@link onViewPreferencesChange}.\n */\n viewPreferences?: ViewPreferences;\n /**\n * Notified after each user-driven toggle in the View menu (or any\n * programmatic call to the corresponding context setters). The\n * argument is a full snapshot — hosts can persist it as-is.\n * Not called when {@link viewPreferences} is changed externally.\n */\n onViewPreferencesChange?: (prefs: ViewPreferences) => void;\n children: ReactNode;\n}\n\n/**\n * Serializable bundle of all runtime-toggleable view preferences for\n * the editor shell. Hosts can persist this verbatim (e.g. to\n * localStorage) and pass it back via {@link EditorProviderProps.viewPreferences}\n * to restore the user's last view configuration.\n */\nexport interface ViewPreferences {\n /** Whether the left-side outline pane is visible. */\n outline?: boolean;\n /** Whether the inline preview gutter (per-block cards) is visible. */\n inlinePreview?: boolean;\n /** Whether the bottom status bar is visible. */\n showStatusBar?: boolean;\n /** Whether inline block-template tags on headings are visible. */\n blockTags?: boolean;\n /** How much of the active Squisq theme the WYSIWYG surface mirrors. */\n themeInheritance?: ThemeInheritance;\n}\n\n/**\n * Provides shared editor state to all child components.\n * Automatically parses markdown and generates a Doc whenever the source changes.\n */\nconst DEFAULT_PRUNE_POLICY: PrunePolicy = { type: 'keep-last-n', n: 50 };\nconst DEFAULT_AUTOSAVE_IDLE_MS = 5_000;\n\nexport function EditorProvider({\n initialMarkdown = '',\n initialView = 'raw',\n articleId = 'untitled',\n theme: initialTheme = 'light',\n workspaceContainer = null,\n allowVersioning = false,\n versionBasename,\n versioningPrunePolicy = DEFAULT_PRUNE_POLICY,\n versioningAutoSaveIdleMs = DEFAULT_AUTOSAVE_IDLE_MS,\n onSaveVersion,\n mediaProvider = null,\n imageDisplayMode = 'inline',\n mentionProvider = null,\n documentLinkProvider = null,\n allowRecording = true,\n fileName,\n language,\n inlinePreview = false,\n showStatusBar = true,\n outline = false,\n blockTags = true,\n themeInheritance = 'fonts',\n viewPreferences,\n onViewPreferencesChange,\n children,\n}: EditorProviderProps) {\n // Resolve effective initial values: bundled `viewPreferences` wins over\n // individual props when both are passed. Individual props remain valid\n // for hosts that haven't migrated to the bundled API.\n const effectiveInlinePreview = viewPreferences?.inlinePreview ?? inlinePreview;\n const effectiveShowStatusBar = viewPreferences?.showStatusBar ?? showStatusBar;\n const effectiveOutline = viewPreferences?.outline ?? outline;\n const effectiveBlockTags = viewPreferences?.blockTags ?? blockTags;\n const effectiveThemeInheritance = viewPreferences?.themeInheritance ?? themeInheritance;\n // Resolve once per provider mount. Changing fileName/language after mount\n // would require recreating the Monaco model anyway, so treat it as static.\n const { mode: editorMode, language: resolvedLanguage } = useMemo(\n () => resolveFileKind(fileName, language),\n [fileName, language],\n );\n // In code mode, WYSIWYG and Preview aren't rendered — force the starting\n // view to 'raw' so we don't boot into an unmounted surface. Image mode\n // has no text-editing surface at all; keep the same fallback so that any\n // host that switches into image mode doesn't end up in a stale view id.\n const [markdownSource, setMarkdownSourceRaw] = useState(initialMarkdown);\n const [markdownDoc, setMarkdownDocState] = useState<MarkdownDocument | null>(null);\n const [doc, setDoc] = useState<Doc | null>(null);\n const [activeView, setActiveViewRaw] = useState<EditorView>(\n editorMode === 'markdown' ? initialView : 'raw',\n );\n const setActiveView = useCallback(\n (view: EditorView) => {\n // In code mode only the raw view is valid. In image mode no text view\n // is valid at all — ignore any switch attempt.\n if (editorMode === 'code' && view !== 'raw') return;\n if (editorMode === 'image') return;\n setActiveViewRaw(view);\n },\n [editorMode],\n );\n const [parseError, setParseError] = useState<string | null>(null);\n const [isParsing, setIsParsing] = useState(false);\n const [theme, setTheme] = useState<EditorTheme>(initialTheme);\n const [inlinePreviewVisible, setInlinePreviewVisibleRaw] =\n useState<boolean>(effectiveInlinePreview);\n // Sync visibility when the host changes the prop (e.g., toggle from outside).\n useEffect(() => {\n setInlinePreviewVisibleRaw(inlinePreview);\n }, [inlinePreview]);\n const [statusBarVisible, setStatusBarVisibleRaw] = useState<boolean>(effectiveShowStatusBar);\n useEffect(() => {\n setStatusBarVisibleRaw(showStatusBar);\n }, [showStatusBar]);\n const [outlineVisible, setOutlineVisibleRaw] = useState<boolean>(effectiveOutline);\n useEffect(() => {\n setOutlineVisibleRaw(outline);\n }, [outline]);\n const [blockTagsVisible, setBlockTagsVisibleRaw] = useState<boolean>(effectiveBlockTags);\n useEffect(() => {\n setBlockTagsVisibleRaw(blockTags);\n }, [blockTags]);\n const [themeInheritanceState, setThemeInheritanceRaw] =\n useState<ThemeInheritance>(effectiveThemeInheritance);\n useEffect(() => {\n setThemeInheritanceRaw(themeInheritance);\n }, [themeInheritance]);\n const [imageEditTarget, setImageEditTarget] = useState<string | null>(null);\n const [mediaRevision, setMediaRevision] = useState(0);\n const openImageEdit = useCallback((relativePath: string) => {\n setImageEditTarget(relativePath);\n }, []);\n const closeImageEdit = useCallback(() => {\n setImageEditTarget(null);\n }, []);\n const bumpMediaRevision = useCallback(() => {\n setMediaRevision((n) => n + 1);\n }, []);\n\n // Sync from the bundled `viewPreferences` prop. Runs in addition to the\n // individual prop syncs above. When both APIs are present, the bundled\n // values are applied here last, keeping `viewPreferences` authoritative.\n useEffect(() => {\n if (!viewPreferences) return;\n if (viewPreferences.inlinePreview !== undefined) {\n setInlinePreviewVisibleRaw(viewPreferences.inlinePreview);\n }\n if (viewPreferences.showStatusBar !== undefined) {\n setStatusBarVisibleRaw(viewPreferences.showStatusBar);\n }\n if (viewPreferences.outline !== undefined) {\n setOutlineVisibleRaw(viewPreferences.outline);\n }\n if (viewPreferences.blockTags !== undefined) {\n setBlockTagsVisibleRaw(viewPreferences.blockTags);\n }\n if (viewPreferences.themeInheritance !== undefined) {\n setThemeInheritanceRaw(viewPreferences.themeInheritance);\n }\n }, [viewPreferences]);\n\n // Wrap the three setters so user-driven toggles emit a snapshot via\n // `onViewPreferencesChange`. Refs hold the latest values + callback so\n // each wrapper can build a current snapshot without re-creating itself\n // on every state change (the setters are kept referentially stable for\n // the context value's memoization).\n const onViewPreferencesChangeRef = useRef(onViewPreferencesChange);\n onViewPreferencesChangeRef.current = onViewPreferencesChange;\n const inlinePreviewRef = useRef(inlinePreviewVisible);\n inlinePreviewRef.current = inlinePreviewVisible;\n const statusBarRef = useRef(statusBarVisible);\n statusBarRef.current = statusBarVisible;\n const outlineRef = useRef(outlineVisible);\n outlineRef.current = outlineVisible;\n const blockTagsRef = useRef(blockTagsVisible);\n blockTagsRef.current = blockTagsVisible;\n const themeInheritanceRef = useRef(themeInheritanceState);\n themeInheritanceRef.current = themeInheritanceState;\n const setInlinePreviewVisible = useCallback((visible: boolean) => {\n setInlinePreviewVisibleRaw(visible);\n onViewPreferencesChangeRef.current?.({\n inlinePreview: visible,\n showStatusBar: statusBarRef.current,\n outline: outlineRef.current,\n blockTags: blockTagsRef.current,\n themeInheritance: themeInheritanceRef.current,\n });\n }, []);\n const setStatusBarVisible = useCallback((visible: boolean) => {\n setStatusBarVisibleRaw(visible);\n onViewPreferencesChangeRef.current?.({\n inlinePreview: inlinePreviewRef.current,\n showStatusBar: visible,\n outline: outlineRef.current,\n blockTags: blockTagsRef.current,\n themeInheritance: themeInheritanceRef.current,\n });\n }, []);\n const setOutlineVisible = useCallback((visible: boolean) => {\n setOutlineVisibleRaw(visible);\n onViewPreferencesChangeRef.current?.({\n inlinePreview: inlinePreviewRef.current,\n showStatusBar: statusBarRef.current,\n outline: visible,\n blockTags: blockTagsRef.current,\n themeInheritance: themeInheritanceRef.current,\n });\n }, []);\n const setBlockTagsVisible = useCallback((visible: boolean) => {\n setBlockTagsVisibleRaw(visible);\n onViewPreferencesChangeRef.current?.({\n inlinePreview: inlinePreviewRef.current,\n showStatusBar: statusBarRef.current,\n outline: outlineRef.current,\n blockTags: visible,\n themeInheritance: themeInheritanceRef.current,\n });\n }, []);\n const setThemeInheritance = useCallback((mode: ThemeInheritance) => {\n setThemeInheritanceRaw(mode);\n onViewPreferencesChangeRef.current?.({\n inlinePreview: inlinePreviewRef.current,\n showStatusBar: statusBarRef.current,\n outline: outlineRef.current,\n blockTags: blockTagsRef.current,\n themeInheritance: mode,\n });\n }, []);\n const [tiptapEditor, setTiptapEditor] = useState<TiptapEditor | null>(null);\n const [monacoEditor, setMonacoEditor] = useState<MonacoEditor | null>(null);\n\n const articleIdRef = useRef(articleId);\n articleIdRef.current = articleId;\n\n // Sync theme when prop changes\n useEffect(() => {\n setTheme(initialTheme);\n }, [initialTheme]);\n\n // Debounced parse on markdown source change\n const parseTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const doParse = useCallback((source: string) => {\n setIsParsing(true);\n try {\n const parsed = parseMarkdown(source);\n setMarkdownDocState(parsed);\n setParseError(null);\n\n // Generate Doc from parsed markdown\n try {\n const generatedDoc = markdownToDoc(parsed, {\n articleId: articleIdRef.current,\n });\n setDoc(generatedDoc);\n } catch (docErr: unknown) {\n // Doc generation can fail but markdown parse succeeded\n setDoc(null);\n console.warn('Doc generation failed:', docErr instanceof Error ? docErr.message : docErr);\n }\n } catch (err: unknown) {\n setParseError(err instanceof Error ? err.message : 'Parse error');\n setMarkdownDocState(null);\n setDoc(null);\n } finally {\n setIsParsing(false);\n }\n }, []);\n\n // Parse on source changes with debounce. Skipped in code/image mode —\n // the WYSIWYG/Preview surfaces that consume markdownDoc/doc aren't\n // mounted, so there's nothing to feed and no reason to run the markdown\n // parser on TypeScript / JSON / a binary image asset.\n useEffect(() => {\n if (editorMode !== 'markdown') return;\n if (parseTimeoutRef.current) {\n clearTimeout(parseTimeoutRef.current);\n }\n parseTimeoutRef.current = setTimeout(() => {\n doParse(markdownSource);\n }, 150);\n return () => {\n if (parseTimeoutRef.current) {\n clearTimeout(parseTimeoutRef.current);\n }\n };\n }, [markdownSource, doParse, editorMode]);\n\n // Initial parse\n useEffect(() => {\n if (editorMode !== 'markdown') return;\n if (initialMarkdown) {\n doParse(initialMarkdown);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const setMarkdownSource = useCallback((source: string) => {\n setMarkdownSourceRaw(source);\n }, []);\n\n const insertAtCursor = useCallback(\n (text: string) => {\n if (activeView === 'wysiwyg' && tiptapEditor) {\n // Insert as HTML so formatting is preserved\n const html = markdownToTiptap(text);\n tiptapEditor.chain().focus().insertContent(html).run();\n } else if (activeView === 'raw' && monacoEditor) {\n const position = monacoEditor.getPosition();\n if (position) {\n const model = monacoEditor.getModel();\n if (model) {\n const range = {\n startLineNumber: position.lineNumber,\n startColumn: position.column,\n endLineNumber: position.lineNumber,\n endColumn: position.column,\n };\n monacoEditor.executeEdits('drop', [{ range, text }]);\n }\n } else {\n // No cursor — append\n setMarkdownSourceRaw((prev) => prev + '\\n\\n' + text);\n }\n } else {\n // Preview or no editor — append to end\n setMarkdownSourceRaw((prev) => prev + '\\n\\n' + text);\n }\n },\n [activeView, tiptapEditor, monacoEditor],\n );\n\n const replaceAll = useCallback(\n (text: string) => {\n setMarkdownSourceRaw(text);\n\n // Push to editors if mounted\n if (tiptapEditor) {\n const html = markdownToTiptap(text);\n tiptapEditor.commands.setContent(html);\n }\n if (monacoEditor) {\n monacoEditor.setValue(text);\n }\n },\n [tiptapEditor, monacoEditor],\n );\n\n // ── Versioning ─────────────────────────────────────────\n // Build a manager only when versioning is opted in *and* a workspace\n // container exists. A versioning request without one is a misconfiguration\n // — warn once so it surfaces in dev without breaking the editor.\n const versioningWarnedRef = useRef(false);\n useEffect(() => {\n if (allowVersioning && !workspaceContainer && !versioningWarnedRef.current) {\n console.warn(\n '[squisq-editor] allowVersioning requires a `workspaceContainer` prop; versioning is disabled.',\n );\n versioningWarnedRef.current = true;\n }\n }, [allowVersioning, workspaceContainer]);\n\n const versioning = useMemo<DocumentVersionManager | null>(() => {\n if (!allowVersioning || !workspaceContainer) return null;\n return new DocumentVersionManager(workspaceContainer, { basename: versionBasename });\n }, [allowVersioning, workspaceContainer, versionBasename]);\n\n const onSaveVersionRef = useRef(onSaveVersion);\n onSaveVersionRef.current = onSaveVersion;\n const prunePolicyRef = useRef(versioningPrunePolicy);\n prunePolicyRef.current = versioningPrunePolicy;\n\n const saveVersion = useCallback(\n async (options?: SaveVersionOptions): Promise<SaveVersionResult> => {\n if (!versioning) {\n const skipped: SaveVersionResult = { saved: false, version: null, reason: 'no-document' };\n onSaveVersionRef.current?.(skipped);\n return skipped;\n }\n const result = await versioning.saveVersion(options);\n onSaveVersionRef.current?.(result);\n if (result.saved) {\n // Fire-and-forget prune. Failures here shouldn't block the save.\n versioning.pruneVersions(prunePolicyRef.current).catch((err: unknown) => {\n console.warn(\n '[squisq-editor] pruneVersions failed:',\n err instanceof Error ? err.message : err,\n );\n });\n }\n return result;\n },\n [versioning],\n );\n\n // Auto-save: stamp a new snapshot after `versioningAutoSaveIdleMs` of\n // idle. The \"only save if different\" check inside `saveVersion` makes\n // most ticks no-ops, so this is cheap. Disabled when the idle delay is\n // 0 or versioning isn't active.\n //\n // We pass the live `markdownSource` explicitly so saveVersion never has\n // to fall back to `container.readDocument()`. That fallback would fail\n // in setups where the markdown file lives outside the versioning\n // container's scope (e.g. DocBlocks, where the container points at\n // `<basename>_files/` while the doc itself lives in the parent\n // directory). Using the editor's live state also ensures the snapshot\n // captures the most recent edit even if the host's autosave to the\n // container hasn't flushed yet.\n useEffect(() => {\n if (!versioning) return;\n if (versioningAutoSaveIdleMs <= 0) return;\n const timer = setTimeout(() => {\n saveVersion({ content: markdownSource }).catch((err: unknown) => {\n console.warn(\n '[squisq-editor] auto-save version failed:',\n err instanceof Error ? err.message : err,\n );\n });\n }, versioningAutoSaveIdleMs);\n return () => clearTimeout(timer);\n }, [markdownSource, versioning, versioningAutoSaveIdleMs, saveVersion]);\n\n const setMarkdownDoc = useCallback((newDoc: MarkdownDocument) => {\n setMarkdownDocState(newDoc);\n // Stringify to update the raw source\n try {\n const newSource = stringifyMarkdown(newDoc);\n setMarkdownSourceRaw(newSource);\n setParseError(null);\n\n // Generate Doc\n try {\n const generatedDoc = markdownToDoc(newDoc, {\n articleId: articleIdRef.current,\n });\n setDoc(generatedDoc);\n } catch (docErr: unknown) {\n setDoc(null);\n console.warn('Doc generation failed:', docErr instanceof Error ? docErr.message : docErr);\n }\n } catch (err: unknown) {\n setParseError(err instanceof Error ? err.message : 'Stringify error');\n }\n }, []);\n\n const value = useMemo<EditorContextValue>(\n () => ({\n markdownSource,\n markdownDoc,\n doc,\n activeView,\n parseError,\n isParsing,\n theme,\n editorMode,\n language: resolvedLanguage,\n inlinePreviewVisible,\n statusBarVisible,\n outlineVisible,\n blockTagsVisible,\n themeInheritance: themeInheritanceState,\n imageEditTarget,\n mediaRevision,\n allowRecording,\n tiptapEditor,\n monacoEditor,\n workspaceContainer,\n versioning,\n saveVersion,\n mediaProvider,\n imageDisplayMode,\n mentionProvider,\n documentLinkProvider,\n setMarkdownSource,\n setMarkdownDoc,\n setActiveView,\n setTiptapEditor,\n setMonacoEditor,\n setTheme,\n setInlinePreviewVisible,\n setStatusBarVisible,\n setOutlineVisible,\n setBlockTagsVisible,\n setThemeInheritance,\n insertAtCursor,\n replaceAll,\n openImageEdit,\n closeImageEdit,\n bumpMediaRevision,\n }),\n [\n markdownSource,\n markdownDoc,\n doc,\n activeView,\n parseError,\n isParsing,\n theme,\n editorMode,\n resolvedLanguage,\n inlinePreviewVisible,\n statusBarVisible,\n outlineVisible,\n blockTagsVisible,\n themeInheritanceState,\n tiptapEditor,\n monacoEditor,\n workspaceContainer,\n versioning,\n saveVersion,\n mediaProvider,\n imageDisplayMode,\n mentionProvider,\n documentLinkProvider,\n setMarkdownSource,\n setMarkdownDoc,\n setActiveView,\n setTiptapEditor,\n setMonacoEditor,\n setTheme,\n setInlinePreviewVisible,\n setStatusBarVisible,\n setOutlineVisible,\n setBlockTagsVisible,\n setThemeInheritance,\n insertAtCursor,\n replaceAll,\n imageEditTarget,\n mediaRevision,\n allowRecording,\n openImageEdit,\n closeImageEdit,\n bumpMediaRevision,\n ],\n );\n\n return <EditorContext.Provider value={value}>{children}</EditorContext.Provider>;\n}\n","/**\n * TemplatePicker\n *\n * A custom popover that replaces the plain <select> for block templates.\n * Each template entry shows a mini wireframe SVG, a human-readable label,\n * and a one-sentence description so authors can quickly find the right layout.\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\n// ── Template metadata ─────────────────────────────────────────────\n\ninterface TemplateEntry {\n name: string;\n label: string;\n description: string;\n icon: JSX.Element;\n}\n\nconst W = 56;\nconst H = 40;\n\n/** Neutral fill for structural shapes */\nconst F1 = '#d1d5db';\n/** Slightly darker fill for important / featured elements */\nconst F2 = '#9ca3af';\n/** Accent fill (stat number, image, play button) */\nconst FA = '#818cf8';\n\nfunction TemplateIcon({ children }: { children: React.ReactNode }) {\n return (\n <svg\n width={W}\n height={H}\n viewBox={`0 0 ${W} ${H}`}\n aria-hidden=\"true\"\n className=\"squisq-template-picker-icon\"\n >\n {children}\n </svg>\n );\n}\n\nconst NONE_ENTRY: TemplateEntry = {\n name: '',\n label: '— none —',\n description: 'Plain heading block with no visual template.',\n icon: (\n <TemplateIcon>\n <rect\n x={4}\n y={4}\n width={48}\n height={32}\n rx={2}\n fill=\"none\"\n stroke={F1}\n strokeWidth={1.5}\n strokeDasharray=\"3 2\"\n />\n <rect x={12} y={15} width={32} height={4} rx={1} fill={F1} />\n <rect x={16} y={22} width={24} height={3} rx={1} fill={F1} opacity={0.6} />\n </TemplateIcon>\n ),\n};\n\nconst TEMPLATE_ENTRIES: TemplateEntry[] = [\n {\n name: 'title',\n label: 'Title',\n description: 'A bold opening slide with large title text, perfect for covers and chapters.',\n icon: (\n <TemplateIcon>\n <rect x={4} y={4} width={48} height={32} rx={2} fill={F1} opacity={0.3} />\n <rect x={8} y={11} width={40} height={8} rx={1} fill={FA} />\n <rect x={14} y={23} width={28} height={3} rx={1} fill={F2} />\n <rect x={20} y={29} width={16} height={2} rx={1} fill={F1} />\n </TemplateIcon>\n ),\n },\n {\n name: 'sectionHeader',\n label: 'Section Header',\n description: 'A clean section break with a prominent title and optional subtitle.',\n icon: (\n <TemplateIcon>\n <rect x={4} y={4} width={3} height={32} rx={1} fill={FA} />\n <rect x={11} y={8} width={36} height={6} rx={1} fill={F2} />\n <rect x={11} y={18} width={28} height={3} rx={1} fill={F1} />\n <rect x={11} y={24} width={20} height={2.5} rx={1} fill={F1} opacity={0.7} />\n </TemplateIcon>\n ),\n },\n {\n name: 'statHighlight',\n label: 'Stat Highlight',\n description: 'Showcases a single key number or metric with supporting context.',\n icon: (\n <TemplateIcon>\n <rect x={14} y={4} width={28} height={16} rx={2} fill={FA} />\n <rect x={10} y={24} width={36} height={3.5} rx={1} fill={F2} />\n <rect x={16} y={30} width={24} height={2.5} rx={1} fill={F1} />\n </TemplateIcon>\n ),\n },\n {\n name: 'quote',\n label: 'Quote',\n description: 'Displays a stylized pull quote with decorative marks and attribution.',\n icon: (\n <TemplateIcon>\n <text\n x={5}\n y={18}\n fontSize={18}\n fill={FA}\n fontFamily=\"serif\"\n fontWeight=\"bold\"\n opacity={0.7}\n >\n \"\n </text>\n <rect x={16} y={8} width={36} height={4} rx={1} fill={F2} />\n <rect x={16} y={15} width={32} height={4} rx={1} fill={F2} />\n <rect x={16} y={22} width={24} height={4} rx={1} fill={F2} />\n <rect x={16} y={31} width={18} height={2.5} rx={1} fill={F1} />\n </TemplateIcon>\n ),\n },\n {\n name: 'factCard',\n label: 'Fact Card',\n description: 'Presents a focused fact or insight with a labeled header and body text.',\n icon: (\n <TemplateIcon>\n <rect x={4} y={4} width={20} height={6} rx={3} fill={FA} opacity={0.8} />\n <rect x={4} y={14} width={48} height={5} rx={1} fill={F2} />\n <rect x={4} y={22} width={44} height={3.5} rx={1} fill={F1} />\n <rect x={4} y={28} width={36} height={3} rx={1} fill={F1} opacity={0.7} />\n </TemplateIcon>\n ),\n },\n {\n name: 'twoColumn',\n label: 'Two Column',\n description: 'Divides the slide into two equal side-by-side content columns.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={4} width={23} height={32} rx={2} fill={F1} opacity={0.4} />\n <rect x={3} y={4} width={23} height={7} rx={2} fill={F2} opacity={0.6} />\n <rect x={6} y={15} width={17} height={3} rx={1} fill={F1} />\n <rect x={6} y={21} width={14} height={2.5} rx={1} fill={F1} opacity={0.7} />\n <rect x={30} y={4} width={23} height={32} rx={2} fill={F1} opacity={0.4} />\n <rect x={30} y={4} width={23} height={7} rx={2} fill={F2} opacity={0.6} />\n <rect x={33} y={15} width={17} height={3} rx={1} fill={F1} />\n <rect x={33} y={21} width={14} height={2.5} rx={1} fill={F1} opacity={0.7} />\n </TemplateIcon>\n ),\n },\n {\n name: 'dateEvent',\n label: 'Date Event',\n description: 'Highlights a date-based event or milestone with a prominent date display.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={4} width={18} height={18} rx={3} fill={FA} opacity={0.85} />\n <rect x={6} y={8} width={12} height={2} rx={1} fill=\"white\" opacity={0.7} />\n <rect x={6} y={13} width={12} height={6} rx={1} fill=\"white\" opacity={0.5} />\n <rect x={25} y={6} width={27} height={5} rx={1} fill={F2} />\n <rect x={25} y={15} width={22} height={3} rx={1} fill={F1} />\n <rect x={25} y={21} width={16} height={2.5} rx={1} fill={F1} opacity={0.7} />\n <rect x={3} y={27} width={50} height={2.5} rx={1} fill={F1} opacity={0.5} />\n <rect x={3} y={32} width={40} height={2} rx={1} fill={F1} opacity={0.4} />\n </TemplateIcon>\n ),\n },\n {\n name: 'imageWithCaption',\n label: 'Image with Caption',\n description: 'Displays a full-bleed image with an optional caption below.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={3} width={50} height={28} rx={2} fill={F2} opacity={0.5} />\n <line x1={3} y1={14} x2={53} y2={14} stroke=\"white\" strokeWidth={0.5} opacity={0.3} />\n <polygon points=\"22,10 22,20 32,15\" fill=\"white\" opacity={0.4} />\n <rect x={10} y={35} width={36} height={2.5} rx={1} fill={F1} />\n </TemplateIcon>\n ),\n },\n {\n name: 'leftFeature',\n label: 'Left Feature',\n description: 'Image on the left, title and body text stacked on the right.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={4} width={24} height={32} rx={2} fill={F2} opacity={0.55} />\n <polygon points=\"11,16 11,24 19,20\" fill=\"white\" opacity={0.5} />\n <rect x={31} y={9} width={20} height={4} rx={1} fill={FA} />\n <rect x={31} y={17} width={22} height={2.5} rx={1} fill={F1} />\n <rect x={31} y={22} width={22} height={2.5} rx={1} fill={F1} opacity={0.75} />\n <rect x={31} y={27} width={16} height={2.5} rx={1} fill={F1} opacity={0.6} />\n </TemplateIcon>\n ),\n },\n {\n name: 'rightFeature',\n label: 'Right Feature',\n description: 'Image on the right, title and body text stacked on the left.',\n icon: (\n <TemplateIcon>\n <rect x={29} y={4} width={24} height={32} rx={2} fill={F2} opacity={0.55} />\n <polygon points=\"37,16 37,24 45,20\" fill=\"white\" opacity={0.5} />\n <rect x={3} y={9} width={20} height={4} rx={1} fill={FA} />\n <rect x={3} y={17} width={22} height={2.5} rx={1} fill={F1} />\n <rect x={3} y={22} width={22} height={2.5} rx={1} fill={F1} opacity={0.75} />\n <rect x={3} y={27} width={16} height={2.5} rx={1} fill={F1} opacity={0.6} />\n </TemplateIcon>\n ),\n },\n {\n name: 'map',\n label: 'Map',\n description: 'Embeds an interactive map centered on a geographic location.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={3} width={50} height={34} rx={2} fill={F1} opacity={0.3} />\n <line x1={3} y1={13} x2={53} y2={13} stroke={F1} strokeWidth={1} />\n <line x1={3} y1={23} x2={53} y2={23} stroke={F1} strokeWidth={1} />\n <line x1={18} y1={3} x2={18} y2={37} stroke={F1} strokeWidth={1} />\n <line x1={38} y1={3} x2={38} y2={37} stroke={F1} strokeWidth={1} />\n <circle cx={28} cy={18} r={4} fill={FA} opacity={0.8} />\n <line x1={28} y1={22} x2={28} y2={26} stroke={FA} strokeWidth={1.5} opacity={0.6} />\n </TemplateIcon>\n ),\n },\n {\n name: 'fullBleedQuote',\n label: 'Full Bleed Quote',\n description: 'A full-width quote that spans the entire slide for maximum impact.',\n icon: (\n <TemplateIcon>\n <rect x={4} y={4} width={48} height={32} rx={2} fill={F2} opacity={0.2} />\n <text\n x={5}\n y={15}\n fontSize={16}\n fill={FA}\n fontFamily=\"serif\"\n fontWeight=\"bold\"\n opacity={0.8}\n >\n \"\n </text>\n <rect x={4} y={14} width={48} height={5} rx={1} fill={F2} />\n <rect x={4} y={22} width={44} height={5} rx={1} fill={F2} />\n <rect x={4} y={30} width={30} height={4} rx={1} fill={F2} opacity={0.7} />\n </TemplateIcon>\n ),\n },\n {\n name: 'list',\n label: 'List',\n description: 'Renders a bulleted or numbered list in a clean, card-style layout.',\n icon: (\n <TemplateIcon>\n <rect x={4} y={5} width={6} height={5} rx={3} fill={FA} opacity={0.8} />\n <rect x={14} y={6} width={38} height={4} rx={1} fill={F2} />\n <rect x={4} y={17} width={6} height={5} rx={3} fill={FA} opacity={0.8} />\n <rect x={14} y={18} width={34} height={4} rx={1} fill={F2} />\n <rect x={4} y={29} width={6} height={5} rx={3} fill={FA} opacity={0.8} />\n <rect x={14} y={30} width={36} height={4} rx={1} fill={F2} />\n </TemplateIcon>\n ),\n },\n {\n name: 'photoGrid',\n label: 'Photo Grid',\n description: 'Arranges multiple photos in a 2×2 or 3×3 mosaic grid.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={3} width={23} height={16} rx={1.5} fill={F2} opacity={0.55} />\n <rect x={30} y={3} width={23} height={16} rx={1.5} fill={F2} opacity={0.7} />\n <rect x={3} y={22} width={23} height={16} rx={1.5} fill={F2} opacity={0.8} />\n <rect x={30} y={22} width={23} height={16} rx={1.5} fill={F2} opacity={0.5} />\n </TemplateIcon>\n ),\n },\n {\n name: 'definitionCard',\n label: 'Definition Card',\n description: 'Shows a term and its definition in a structured, dictionary-style card.',\n icon: (\n <TemplateIcon>\n <rect x={4} y={6} width={32} height={6} rx={1} fill={FA} opacity={0.8} />\n <rect x={4} y={17} width={48} height={3.5} rx={1} fill={F1} />\n <rect x={4} y={23} width={44} height={3} rx={1} fill={F1} opacity={0.8} />\n <rect x={4} y={29} width={36} height={3} rx={1} fill={F1} opacity={0.6} />\n </TemplateIcon>\n ),\n },\n {\n name: 'comparisonBar',\n label: 'Comparison Bar',\n description: 'Visualizes two or more values side-by-side with labeled horizontal bars.',\n icon: (\n <TemplateIcon>\n <rect x={4} y={5} width={14} height={3} rx={1} fill={F1} />\n <rect x={20} y={4} width={32} height={5} rx={1} fill={FA} opacity={0.85} />\n <rect x={4} y={16} width={14} height={3} rx={1} fill={F1} />\n <rect x={20} y={15} width={22} height={5} rx={1} fill={F2} opacity={0.7} />\n <rect x={4} y={27} width={14} height={3} rx={1} fill={F1} />\n <rect x={20} y={26} width={28} height={5} rx={1} fill={F2} opacity={0.5} />\n </TemplateIcon>\n ),\n },\n {\n name: 'pullQuote',\n label: 'Pull Quote',\n description: 'A stylized pull quote with large decorative marks and centered text.',\n icon: (\n <TemplateIcon>\n <text x={3} y={20} fontSize={26} fill={FA} fontFamily=\"serif\" opacity={0.5}>\n \"\n </text>\n <rect x={16} y={7} width={36} height={4.5} rx={1} fill={F2} />\n <rect x={16} y={15} width={34} height={4.5} rx={1} fill={F2} />\n <rect x={16} y={23} width={28} height={4.5} rx={1} fill={F2} />\n <rect x={32} y={31} width={20} height={3} rx={1} fill={F1} />\n <text x={44} y={42} fontSize={26} fill={FA} fontFamily=\"serif\" opacity={0.3}>\n \"\n </text>\n </TemplateIcon>\n ),\n },\n {\n name: 'videoWithCaption',\n label: 'Video with Caption',\n description: 'Embeds a video player with an optional caption below.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={3} width={50} height={28} rx={2} fill={F1} opacity={0.4} />\n <rect x={3} y={3} width={50} height={28} rx={2} fill={F2} opacity={0.25} />\n <circle cx={28} cy={17} r={8} fill={FA} opacity={0.7} />\n <polygon points=\"25,13 25,21 33,17\" fill=\"white\" />\n <rect x={10} y={35} width={36} height={2.5} rx={1} fill={F1} />\n </TemplateIcon>\n ),\n },\n {\n name: 'videoPullQuote',\n label: 'Video Pull Quote',\n description: 'Combines a video panel with a highlighted pull quote side-by-side.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={4} width={23} height={32} rx={2} fill={F2} opacity={0.35} />\n <circle cx={14.5} cy={20} r={6} fill={FA} opacity={0.65} />\n <polygon points=\"12,17 12,23 18,20\" fill=\"white\" />\n <rect x={30} y={4} width={23} height={32} rx={2} fill={F1} opacity={0.3} />\n <text x={32} y={16} fontSize={12} fill={FA} fontFamily=\"serif\" opacity={0.6}>\n \"\n </text>\n <rect x={30} y={17} width={20} height={3.5} rx={1} fill={F2} />\n <rect x={30} y={23} width={18} height={3} rx={1} fill={F1} />\n <rect x={30} y={29} width={14} height={2.5} rx={1} fill={F1} opacity={0.7} />\n </TemplateIcon>\n ),\n },\n {\n name: 'dataTable',\n label: 'Data Table',\n description: 'Renders tabular data in a clean, styled table with a header row.',\n icon: (\n <TemplateIcon>\n <rect x={3} y={3} width={50} height={8} rx={1.5} fill={FA} opacity={0.7} />\n <rect x={3} y={13} width={50} height={6} rx={1} fill={F1} opacity={0.5} />\n <rect x={3} y={21} width={50} height={6} rx={1} fill={F1} opacity={0.35} />\n <rect x={3} y={29} width={50} height={6} rx={1} fill={F1} opacity={0.5} />\n <line x1={20} y1={3} x2={20} y2={35} stroke=\"white\" strokeWidth={1} opacity={0.4} />\n <line x1={37} y1={3} x2={37} y2={35} stroke=\"white\" strokeWidth={1} opacity={0.4} />\n </TemplateIcon>\n ),\n },\n];\n\n/**\n * Canonical template names known to the picker, in the order they\n * appear in the gallery. Exported so callers can hand the same list to\n * `recommendTemplatesForBlock()` and stay in sync with the visual\n * order.\n */\nexport const TEMPLATE_NAMES: readonly string[] = TEMPLATE_ENTRIES.map((e) => e.name);\n\n/**\n * Convert a camelCase template id to a human-readable label. Accepts both\n * the canonical short ids (`title`, `quote`, `map`, `list`) and the\n * legacy long ones (`titleBlock`, `quoteBlock`, `mapBlock`, `listBlock`)\n * so existing documents keep showing a friendly label without first\n * normalizing their annotations.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function templateLabel(name: string): string {\n if (!name) return '— none —';\n const resolved = TEMPLATE_NAME_ALIASES[name] ?? name;\n const entry = TEMPLATE_ENTRIES.find((e) => e.name === resolved);\n if (entry) return entry.label;\n // Fallback: split camelCase\n return resolved.replace(/([A-Z])/g, ' $1').replace(/^./, (s) => s.toUpperCase());\n}\n\n/**\n * Legacy template id → canonical short id. Kept inline to avoid pulling\n * the core package's runtime registry into the picker's bundle — the\n * picker only needs this for label resolution.\n */\nconst TEMPLATE_NAME_ALIASES: Readonly<Record<string, string>> = {\n titleBlock: 'title',\n quoteBlock: 'quote',\n mapBlock: 'map',\n listBlock: 'list',\n};\n\n// ── Component ─────────────────────────────────────────────────────\n\nexport interface TemplatePickerProps {\n value: string;\n onChange: (name: string) => void;\n /** When true, shows only the trigger button (no popover) — used in the overflow menu. */\n compact?: boolean;\n /**\n * Template names to surface in a \"Recommended for this block\" section\n * above the full list. When omitted or empty, the gallery renders as a\n * single ungrouped grid (legacy behavior).\n */\n recommended?: readonly string[];\n}\n\nexport function TemplatePicker({ value, onChange, compact, recommended }: TemplatePickerProps) {\n const [open, setOpen] = useState(false);\n const [popoverStyle, setPopoverStyle] = useState<React.CSSProperties>({});\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n\n // Position the portal popover below the trigger button. Clamp the\n // left edge so the gallery (up to 780px wide) doesn't overflow the\n // viewport when the toolbar trigger sits near the right edge of the\n // window — previously the popover was left-aligned to the trigger,\n // which pushed half the cards off-screen at narrow widths.\n const updatePosition = () => {\n if (!triggerRef.current) return;\n const rect = triggerRef.current.getBoundingClientRect();\n const popoverEl = document.getElementById('squisq-template-gallery-portal');\n // Use the actual rendered width if the popover is already mounted;\n // otherwise fall back to the CSS-defined max so the first paint\n // doesn't overflow either. Measure the portal element directly —\n // its `firstElementChild` is the (small) \"(none)\" option, not the\n // gallery itself.\n const popoverWidth = popoverEl?.getBoundingClientRect().width ?? 780;\n const margin = 8;\n const maxLeft = Math.max(margin, window.innerWidth - popoverWidth - margin);\n const left = Math.min(Math.max(margin, rect.left), maxLeft);\n setPopoverStyle({\n position: 'fixed',\n top: rect.bottom + 6,\n left,\n zIndex: 9999,\n });\n };\n\n const handleOpen = () => {\n updatePosition();\n setOpen((v) => !v);\n };\n\n // Close on outside click\n useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n const target = e.target as Node;\n const inTrigger = triggerRef.current?.contains(target);\n const inPopover = document.getElementById('squisq-template-gallery-portal')?.contains(target);\n if (!inTrigger && !inPopover) {\n setOpen(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [open]);\n\n // Close on Escape\n useEffect(() => {\n if (!open) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false);\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [open]);\n\n // Reposition on scroll/resize while open\n useEffect(() => {\n if (!open) return;\n // Reposition once on the next frame so the clamp uses the actual\n // rendered popover width (the initial open() runs before mount).\n requestAnimationFrame(updatePosition);\n const handler = () => updatePosition();\n window.addEventListener('scroll', handler, true);\n window.addEventListener('resize', handler);\n return () => {\n window.removeEventListener('scroll', handler, true);\n window.removeEventListener('resize', handler);\n };\n }, [open]);\n\n const handleSelect = (name: string) => {\n onChange(name);\n setOpen(false);\n };\n\n const currentLabel = templateLabel(value);\n const currentEntry: TemplateEntry =\n (value && TEMPLATE_ENTRIES.find((e) => e.name === value)) || NONE_ENTRY;\n\n if (compact) {\n // In overflow menu, use a simple select for space efficiency\n const all: TemplateEntry[] = [NONE_ENTRY, ...TEMPLATE_ENTRIES];\n return (\n <select\n className=\"squisq-template-picker-select\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n >\n {all.map((e) => (\n <option key={e.name} value={e.name}>\n {e.label}\n </option>\n ))}\n </select>\n );\n }\n\n const gallery = open\n ? createPortal(\n <TemplateGalleryBody\n value={value}\n onSelect={handleSelect}\n style={popoverStyle}\n recommended={recommended}\n />,\n document.body,\n )\n : null;\n\n return (\n <div className=\"squisq-template-picker-popover-host\" ref={containerRef}>\n <button\n ref={triggerRef}\n type=\"button\"\n className={`squisq-template-picker-trigger${open ? ' squisq-template-picker-trigger--open' : ''}`}\n onClick={handleOpen}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n title=\"Choose block template\"\n >\n <span className=\"squisq-template-picker-trigger-label\">Block:</span>\n <span className=\"squisq-template-picker-trigger-thumb\" aria-hidden=\"true\">\n {currentEntry.icon}\n </span>\n <span className=\"squisq-template-picker-trigger-value\">\n {value ? currentLabel : '(No visual)'}\n </span>\n <svg\n className=\"squisq-template-picker-trigger-caret\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M2 3.5l3 3 3-3\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n </button>\n {gallery}\n </div>\n );\n}\n\n// ── Reusable gallery body ──────────────────────────────────────────\n\n/**\n * The popover/grid markup shared by the toolbar `TemplatePicker` and the\n * inline `TemplateBadgeMenu`. Renders all template cards plus the\n * \"(none)\" option; no positioning logic — callers supply `style` (typically\n * a `position: fixed` rect from `getBoundingClientRect()`).\n */\nfunction TemplateCard({\n entry,\n value,\n onSelect,\n}: {\n entry: TemplateEntry;\n value: string;\n onSelect: (name: string) => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={value === entry.name}\n className={`squisq-template-gallery-card${value === entry.name ? ' squisq-template-gallery-card--selected' : ''}`}\n onClick={() => onSelect(entry.name)}\n title={entry.description}\n >\n <div className=\"squisq-template-gallery-card-icon\">{entry.icon}</div>\n <div className=\"squisq-template-gallery-card-body\">\n <span className=\"squisq-template-gallery-card-name\">{entry.label}</span>\n <span className=\"squisq-template-gallery-card-desc\">{entry.description}</span>\n </div>\n </button>\n );\n}\n\nfunction TemplateGalleryBody({\n value,\n onSelect,\n style,\n recommended,\n}: {\n value: string;\n onSelect: (name: string) => void;\n style: React.CSSProperties;\n recommended?: readonly string[];\n}) {\n const recommendedSet = recommended && recommended.length > 0 ? new Set(recommended) : null;\n const recommendedEntries = recommendedSet\n ? TEMPLATE_ENTRIES.filter((e) => recommendedSet.has(e.name))\n : [];\n const restEntries = recommendedSet\n ? TEMPLATE_ENTRIES.filter((e) => !recommendedSet.has(e.name))\n : TEMPLATE_ENTRIES;\n const segmented = recommendedEntries.length > 0;\n\n return (\n <div\n id=\"squisq-template-gallery-portal\"\n className={`squisq-template-gallery${segmented ? ' squisq-template-gallery--segmented' : ''}`}\n role=\"listbox\"\n aria-label=\"Block templates\"\n style={style}\n >\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={value === ''}\n className={`squisq-template-gallery-none${value === '' ? ' squisq-template-gallery-card--selected' : ''}`}\n onClick={() => onSelect('')}\n >\n {NONE_ENTRY.icon}\n <span className=\"squisq-template-gallery-none-label\">{NONE_ENTRY.label}</span>\n <span className=\"squisq-template-gallery-none-desc\">{NONE_ENTRY.description}</span>\n </button>\n\n {segmented && (\n <div className=\"squisq-template-gallery-section\">\n <h3 className=\"squisq-template-gallery-section-title\">Recommended for this block</h3>\n <div className=\"squisq-template-gallery-grid\">\n {recommendedEntries.map((entry) => (\n <TemplateCard key={entry.name} entry={entry} value={value} onSelect={onSelect} />\n ))}\n </div>\n </div>\n )}\n\n {segmented ? (\n <div className=\"squisq-template-gallery-section\">\n <h3 className=\"squisq-template-gallery-section-title\">All templates</h3>\n <div className=\"squisq-template-gallery-grid\">\n {restEntries.map((entry) => (\n <TemplateCard key={entry.name} entry={entry} value={value} onSelect={onSelect} />\n ))}\n </div>\n </div>\n ) : (\n <div className=\"squisq-template-gallery-grid\">\n {restEntries.map((entry) => (\n <TemplateCard key={entry.name} entry={entry} value={value} onSelect={onSelect} />\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// ── Inline badge popover (anchored at a heading badge) ─────────────\n\nexport interface TemplateBadgePopoverProps {\n /** DOMRect of the badge that triggered the popover (in viewport coords). */\n anchorRect: DOMRect;\n /** Currently active template name (empty string for none). */\n value: string;\n onChange: (name: string) => void;\n onClose: () => void;\n /** Optional list of template names to surface as \"Recommended for this block\". */\n recommended?: readonly string[];\n}\n\n/**\n * Standalone popover that mirrors the toolbar `TemplatePicker`'s gallery,\n * but is anchored to a caller-supplied DOM rect (typically a clicked\n * `.squisq-template-badge` span). Handles its own positioning, outside\n * clicks, Escape, and viewport-edge clamping.\n */\nexport function TemplateBadgePopover({\n anchorRect,\n value,\n onChange,\n onClose,\n recommended,\n}: TemplateBadgePopoverProps) {\n const [style, setStyle] = useState<React.CSSProperties>(() => computePopoverStyle(anchorRect));\n\n // Reposition once after mount using the actual rendered popover width.\n useEffect(() => {\n requestAnimationFrame(() => setStyle(computePopoverStyle(anchorRect)));\n }, [anchorRect]);\n\n // Outside click + Escape close\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n const onMouse = (e: MouseEvent) => {\n const target = e.target as Node;\n const inPopover = document.getElementById('squisq-template-gallery-portal')?.contains(target);\n if (!inPopover) onClose();\n };\n // Defer the mousedown listener by one frame so the click that opened\n // us doesn't immediately close us.\n const id = requestAnimationFrame(() => {\n document.addEventListener('mousedown', onMouse);\n });\n document.addEventListener('keydown', onKey);\n return () => {\n cancelAnimationFrame(id);\n document.removeEventListener('mousedown', onMouse);\n document.removeEventListener('keydown', onKey);\n };\n }, [onClose]);\n\n const handleSelect = (name: string) => {\n onChange(name);\n onClose();\n };\n\n return createPortal(\n <TemplateGalleryBody\n value={value}\n onSelect={handleSelect}\n style={style}\n recommended={recommended}\n />,\n document.body,\n );\n}\n\nfunction computePopoverStyle(rect: DOMRect): React.CSSProperties {\n // The portal *is* the gallery (`#squisq-template-gallery-portal` is the\n // outer `.squisq-template-gallery` div). Measure it directly — using\n // `firstElementChild` returns the \"(none)\" option, which is ~50px tall\n // and made the \"fits below\" check incorrectly pass on tall galleries.\n const popoverEl = document.getElementById('squisq-template-gallery-portal');\n const popoverRect = popoverEl?.getBoundingClientRect();\n const popoverWidth = popoverRect?.width ?? 780;\n const popoverHeight = popoverRect?.height ?? 520;\n const margin = 8;\n const gap = 6;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n // Vertical placement: prefer below the badge, fall back to above.\n // If neither fits, center the popover in the viewport (dialog-style)\n // so the gallery is always fully visible no matter where the chip\n // sits in the editor (top, middle, bottom).\n const spaceBelow = vh - rect.bottom - margin;\n const spaceAbove = rect.top - margin;\n let top: number;\n let left: number;\n if (popoverHeight + gap <= spaceBelow) {\n top = rect.bottom + gap;\n const maxLeft = Math.max(margin, vw - popoverWidth - margin);\n left = Math.min(Math.max(margin, rect.left), maxLeft);\n } else if (popoverHeight + gap <= spaceAbove) {\n top = rect.top - popoverHeight - gap;\n const maxLeft = Math.max(margin, vw - popoverWidth - margin);\n left = Math.min(Math.max(margin, rect.left), maxLeft);\n } else {\n // Center it.\n top = Math.max(margin, Math.floor((vh - popoverHeight) / 2));\n left = Math.max(margin, Math.floor((vw - popoverWidth) / 2));\n }\n\n return {\n position: 'fixed',\n top,\n left,\n // Cap height so an oversized gallery still fits and scrolls\n // gracefully instead of pushing past the viewport.\n maxHeight: `${vh - 2 * margin}px`,\n overflowY: 'auto',\n zIndex: 9999,\n };\n}\n","/**\n * Tiptap Bridge\n *\n * Conversion utilities between raw markdown source and Tiptap's JSON/HTML\n * content format. Uses a lightweight HTML-based approach: we convert markdown\n * to a simple HTML representation that Tiptap can consume, and parse\n * Tiptap's HTML output back to markdown.\n *\n * This bridge preserves markdown semantics much better than going through\n * Tiptap's native markdown extension, since we control the conversion\n * using squisq's own parser.\n */\n\nimport { templateLabel } from './TemplatePicker';\nimport { resolveIcon } from '@bendyline/squisq/icons';\n\n// Hoisted regex patterns for inline markdown ↔ HTML conversion\nconst RE_BOLD_STAR = /\\*\\*(.+?)\\*\\*/g;\nconst RE_BOLD_UNDER = /__(.+?)__/g;\nconst RE_ITALIC_STAR = /\\*(.+?)\\*/g;\nconst RE_ITALIC_UNDER = /_(.+?)_/g;\nconst RE_STRIKETHROUGH = /~~(.+?)~~/g;\nconst RE_INLINE_CODE = /`(.+?)`/g;\nconst RE_LINK = /\\[(.+?)\\]\\((.+?)\\)/g;\n// `*?` on the alt — an empty alt (`![](foo.png)`) is valid markdown and\n// the most common shape for pasted/uploaded images that don't yet have\n// a human-picked caption. Previously required at least one alt char,\n// which dropped those images on the floor during markdown→HTML.\nconst RE_IMAGE = /!\\[(.*?)\\]\\((.+?)\\)/g;\n// Mentions: `@[Display](scheme:id)` — scheme-part must start with a letter\n// so plain `$100` or price-style parentheticals don't accidentally match.\n// remark-stringify may round-trip the colon as `\\:` — tolerate either.\nconst RE_MENTION = /@\\[([^\\]]+?)\\]\\(([a-z][a-z0-9+.-]*)\\\\?:([^)\\s]+)\\)/gi;\nconst RE_MENTION_TAG = /<span\\b[^>]*?\\bdata-mention\\b[^>]*?>(?:<[^>]+>)*([^<]*)<\\/span>/gi;\n\n// Inline FontAwesome icon. Markdown form: `{[github]}` (bare) or\n// `{[fa-solid:user]}` (qualified). HTML form (produced by the\n// `InlineIcon` Tiptap node and consumed back by `htmlToInline`):\n// `<i data-icon=\"github\" data-family=\"brands\" data-name=\"github\"\n// class=\"fa-brands fa-github\" contenteditable=\"false\"></i>`.\nconst RE_ICON_MD = /\\{\\[([a-zA-Z0-9_:-]+)\\]\\}/g;\nconst RE_ICON_TAG = /<i\\b[^>]*?\\bdata-icon=\"([^\"]*)\"[^>]*?><\\/i>/gi;\nconst RE_STRONG_TAG = /<strong>(.*?)<\\/strong>/g;\nconst RE_B_TAG = /<b>(.*?)<\\/b>/g;\nconst RE_EM_TAG = /<em>(.*?)<\\/em>/g;\nconst RE_I_TAG = /<i>(.*?)<\\/i>/g;\nconst RE_S_TAG = /<s>(.*?)<\\/s>/g;\nconst RE_DEL_TAG = /<del>(.*?)<\\/del>/g;\nconst RE_CODE_TAG = /<code>(.*?)<\\/code>/g;\nconst RE_A_TAG = /<a[^>]+href=\"([^\"]*)\"[^>]*>(.*?)<\\/a>/g;\n// Matches any `<img>` tag and captures its `src` + `alt` regardless of\n// attribute order. TipTap's Image extension renders `<img src=\"...\"\n// alt=\"...\">` (src first), while some other producers — including our\n// own `markdownToTiptap` conversion — emit alt-first. The previous\n// regex required alt-before-src and silently dropped every src-first\n// image; `RE_STRIP_TAGS` below would then delete the unmatched tag,\n// so the outgoing markdown had no image reference at all.\nconst RE_IMG_TAG = /<img\\b([^>]*)>/g;\nconst RE_STRIP_TAGS = /<[^>]+>/g;\n\n/**\n * Convert raw markdown source to Tiptap-consumable HTML content.\n * Uses a simple markdown-to-HTML conversion that maps cleanly to\n * Tiptap's ProseMirror schema.\n */\nexport function markdownToTiptap(markdown: string): string {\n if (!markdown.trim()) return '<p></p>';\n\n // Normalize line endings — content from zip archives may use \\r\\n\n const html = markdown.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n\n // Process blocks line by line for accurate conversion\n const lines = html.split('\\n');\n const outputBlocks: string[] = [];\n let inCodeBlock = false;\n let codeBlockLang = '';\n let codeBlockLines: string[] = [];\n let inList = false;\n let listItems: string[] = [];\n let listType: 'ul' | 'ol' | 'task' = 'ul';\n let inTable = false;\n let tableLines: string[] = [];\n\n const flushList = () => {\n if (inList && listItems.length > 0) {\n const tag = listType === 'ol' ? 'ol' : 'ul';\n const attr = listType === 'task' ? ' data-type=\"taskList\"' : '';\n outputBlocks.push(`<${tag}${attr}>${listItems.join('')}</${tag}>`);\n listItems = [];\n inList = false;\n }\n };\n\n const flushTable = () => {\n if (!inTable || tableLines.length === 0) {\n inTable = false;\n tableLines = [];\n return;\n }\n\n // Validate: need at least 2 lines and second must be a separator\n const separatorCells = tableLines.length >= 2 ? parseTableCells(tableLines[1]) : [];\n const isSeparator =\n separatorCells.length > 0 && separatorCells.every((cell) => /^:?-+:?$/.test(cell.trim()));\n\n if (tableLines.length < 2 || !isSeparator) {\n // Not a valid table — render accumulated lines as paragraphs\n for (const tl of tableLines) {\n outputBlocks.push(`<p>${inlineToHtml(tl)}</p>`);\n }\n inTable = false;\n tableLines = [];\n return;\n }\n\n const alignments = parseAlignments(tableLines[1]);\n const headerCells = parseTableCells(tableLines[0]);\n\n // Build header row\n const thHtml = headerCells\n .map((cell, i) => {\n const align = alignments[i];\n const style = align ? ` style=\"text-align: ${align}\"` : '';\n return `<th${style}>${inlineToHtml(cell)}</th>`;\n })\n .join('');\n\n // Build body rows\n const bodyHtml = tableLines\n .slice(2)\n .map((rowLine) => {\n const cells = parseTableCells(rowLine);\n const tdHtml = cells\n .map((cell, i) => {\n const align = alignments[i];\n const style = align ? ` style=\"text-align: ${align}\"` : '';\n return `<td${style}>${inlineToHtml(cell)}</td>`;\n })\n .join('');\n return `<tr>${tdHtml}</tr>`;\n })\n .join('');\n\n outputBlocks.push(`<table><thead><tr>${thHtml}</tr></thead><tbody>${bodyHtml}</tbody></table>`);\n\n inTable = false;\n tableLines = [];\n };\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Code fence handling\n if (line.startsWith('```')) {\n if (!inCodeBlock) {\n flushList();\n inCodeBlock = true;\n codeBlockLang = line.slice(3).trim();\n codeBlockLines = [];\n continue;\n } else {\n const langAttr = codeBlockLang ? ` class=\"language-${escapeHtml(codeBlockLang)}\"` : '';\n outputBlocks.push(\n `<pre><code${langAttr}>${escapeHtml(codeBlockLines.join('\\n'))}</code></pre>`,\n );\n inCodeBlock = false;\n codeBlockLang = '';\n codeBlockLines = [];\n continue;\n }\n }\n\n if (inCodeBlock) {\n codeBlockLines.push(line);\n continue;\n }\n\n // If in table and current line is not a table row, flush\n if (inTable && !/^\\|.*\\|$/.test(line.trim())) {\n flushTable();\n }\n\n // Blank line flushes list\n if (line.trim() === '') {\n flushList();\n continue;\n }\n\n // Headings\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n flushList();\n const level = headingMatch[1].length;\n let text = headingMatch[2];\n let attrs = '';\n\n // Extract {[template key=value …]} annotation. Trailing `[\\s\\]\\}]*`\n // tolerates accidental doubled `]}` that users type while learning\n // the syntax — must stay in sync with TEMPLATE_ANNOTATION_RE in\n // packages/core/src/markdown/convert.ts.\n const annotMatch = text.match(/\\s*\\{\\[([^\\]]+)\\]\\}[\\s\\]}]*$/);\n if (annotMatch) {\n text = text.slice(0, annotMatch.index!).trimEnd();\n const tokens = annotMatch[1].trim().split(/\\s+/);\n attrs = ` data-template=\"${escapeHtml(tokens[0])}\"`;\n const params = tokens.slice(1).filter((t) => t.includes('='));\n if (params.length > 0) {\n attrs += ` data-template-params=\"${escapeHtml(params.join(' '))}\"`;\n }\n }\n\n outputBlocks.push(`<h${level}${attrs}>${inlineToHtml(text)}</h${level}>`);\n continue;\n }\n\n // Thematic break\n if (/^(---|\\*\\*\\*|___)(\\s*)$/.test(line.trim())) {\n flushList();\n outputBlocks.push('<hr>');\n continue;\n }\n\n // Blockquote\n if (line.startsWith('> ')) {\n flushList();\n outputBlocks.push(`<blockquote><p>${inlineToHtml(line.slice(2))}</p></blockquote>`);\n continue;\n }\n\n // Task list item\n const taskMatch = line.match(/^[-*+]\\s+\\[([xX ])\\]\\s+(.+)$/);\n if (taskMatch) {\n if (!inList || listType !== 'task') {\n flushList();\n inList = true;\n listType = 'task';\n }\n const checked = taskMatch[1].toLowerCase() === 'x' ? ' data-checked=\"true\"' : '';\n listItems.push(\n `<li data-type=\"taskItem\"${checked}><label><input type=\"checkbox\"${checked ? ' checked' : ''}>${inlineToHtml(taskMatch[2])}</label></li>`,\n );\n continue;\n }\n\n // Unordered list item\n const ulMatch = line.match(/^[-*+]\\s+(.+)$/);\n if (ulMatch) {\n if (!inList || listType !== 'ul') {\n flushList();\n inList = true;\n listType = 'ul';\n }\n listItems.push(`<li><p>${inlineToHtml(ulMatch[1])}</p></li>`);\n continue;\n }\n\n // Ordered list item\n const olMatch = line.match(/^\\d+\\.\\s+(.+)$/);\n if (olMatch) {\n if (!inList || listType !== 'ol') {\n flushList();\n inList = true;\n listType = 'ol';\n }\n listItems.push(`<li><p>${inlineToHtml(olMatch[1])}</p></li>`);\n continue;\n }\n\n // Table row\n if (/^\\|.*\\|$/.test(line.trim())) {\n if (!inTable) {\n flushList();\n inTable = true;\n tableLines = [];\n }\n tableLines.push(line);\n continue;\n }\n\n // Standalone image — emit as a top-level block `<img>` instead of\n // wrapping in `<p>`. The Tiptap Image extension is configured with\n // `inline: false`, so `<p><img></p>` parses to an empty paragraph\n // (the block image can't live inside the paragraph). That bug\n // manifested as a broken-image glyph after a markdown → WYSIWYG\n // round-trip for any dropped/pasted image.\n const standaloneImageMatch = line.trim().match(/^!\\[(.*?)\\]\\((.+?)\\)$/);\n if (standaloneImageMatch) {\n flushList();\n const alt = escapeHtml(standaloneImageMatch[1] ?? '');\n const src = escapeHtml(standaloneImageMatch[2] ?? '');\n outputBlocks.push(`<img alt=\"${alt}\" src=\"${src}\">`);\n continue;\n }\n\n // Standalone raw HTML `<img>` line — emitted by `tiptapToMarkdown`\n // when the user has resized an image (width/height attrs are\n // serialized as HTML rather than markdown shorthand so the\n // dimensions survive round-trip). Pass the tag through unchanged\n // so Tiptap's Image extension parses width/height attributes.\n const trimmed = line.trim();\n if (/^<img\\b[^>]*>$/i.test(trimmed)) {\n flushList();\n outputBlocks.push(trimmed);\n continue;\n }\n\n // Standalone `<video>` / `<audio>` line — emitted by the recorder\n // (RecorderEntry) when it saves a clip, and by `tiptapToMarkdown`\n // when the WYSIWYG editor's TiptapVideo/TiptapAudio nodes serialize\n // back to markdown. Pass through unchanged so the editor's parseHTML\n // picks up the tag attributes (`src`, `controls`, …).\n if (/^<(?:video|audio)\\b[^>]*>(?:[\\s\\S]*?<\\/(?:video|audio)>)?$/i.test(trimmed)) {\n flushList();\n outputBlocks.push(trimmed);\n continue;\n }\n\n // Regular paragraph\n flushList();\n outputBlocks.push(`<p>${inlineToHtml(line)}</p>`);\n }\n\n // Close any remaining open blocks\n if (inCodeBlock) {\n const langAttr = codeBlockLang ? ` class=\"language-${escapeHtml(codeBlockLang)}\"` : '';\n outputBlocks.push(\n `<pre><code${langAttr}>${escapeHtml(codeBlockLines.join('\\n'))}</code></pre>`,\n );\n }\n flushList();\n flushTable();\n\n return outputBlocks.join('') || '<p></p>';\n}\n\n/**\n * Convert Tiptap HTML output back to markdown source.\n * Extracts semantic structure from HTML and produces clean markdown.\n */\nexport function tiptapToMarkdown(html: string): string {\n if (!html || html === '<p></p>') return '';\n\n const lines: string[] = [];\n\n // Simple regex-based HTML to markdown conversion\n // This works because Tiptap produces clean, predictable HTML\n let remaining = html;\n\n while (remaining.length > 0) {\n // Headings\n const headingMatch = remaining.match(/^<h([1-6])([^>]*)>(.*?)<\\/h\\1>/s);\n if (headingMatch) {\n const level = parseInt(headingMatch[1], 10);\n const attrs = headingMatch[2];\n let text = htmlToInline(headingMatch[3]);\n\n // Re-inject template annotation from data attributes\n const tmplMatch = attrs.match(/data-template=\"([^\"]+)\"/);\n if (tmplMatch) {\n let annotation = tmplMatch[1];\n // Defensive: an earlier broken build briefly rendered the\n // template label as a real text node inside the badge, which\n // bled the label into the heading's textContent. Strip a\n // trailing copy of the template's label so existing documents\n // self-heal on save.\n const label = templateLabel(annotation);\n if (label && text.endsWith(label)) {\n text = text.slice(0, -label.length).trimEnd();\n }\n const paramsMatch = attrs.match(/data-template-params=\"([^\"]+)\"/);\n if (paramsMatch) {\n annotation += ' ' + unescapeHtml(paramsMatch[1]);\n }\n text += ` {[${annotation}]}`;\n }\n\n lines.push('#'.repeat(level) + ' ' + text);\n lines.push('');\n remaining = remaining.slice(headingMatch[0].length);\n continue;\n }\n\n // Code blocks\n const codeMatch = remaining.match(\n /^<pre><code(?:\\s+class=\"language-([^\"]*)\")?>(.*?)<\\/code><\\/pre>/s,\n );\n if (codeMatch) {\n const lang = codeMatch[1] || '';\n const code = unescapeHtml(codeMatch[2]);\n lines.push('```' + lang);\n lines.push(code);\n lines.push('```');\n lines.push('');\n remaining = remaining.slice(codeMatch[0].length);\n continue;\n }\n\n // Blockquote\n const bqMatch = remaining.match(/^<blockquote>(.*?)<\\/blockquote>/s);\n if (bqMatch) {\n const inner = htmlToInline(bqMatch[1].replace(/<\\/?p>/g, ''));\n lines.push('> ' + inner);\n lines.push('');\n remaining = remaining.slice(bqMatch[0].length);\n continue;\n }\n\n // Horizontal rule\n if (\n remaining.startsWith('<hr>') ||\n remaining.startsWith('<hr/>') ||\n remaining.startsWith('<hr />')\n ) {\n const hrMatch = remaining.match(/^<hr\\s*\\/?>/);\n lines.push('---');\n lines.push('');\n remaining = remaining.slice(hrMatch![0].length);\n continue;\n }\n\n // Table (with optional Tiptap tableWrapper div; table tag may have style attrs)\n const tableMatch =\n remaining.match(\n /^<div[^>]*class=\"[^\"]*tableWrapper[^\"]*\"[^>]*><table[^>]*>(.*?)<\\/table>\\s*<\\/div>/s,\n ) || remaining.match(/^<table[^>]*>(.*?)<\\/table>/s);\n if (tableMatch) {\n const tableContent = tableMatch[1];\n\n // Extract all rows with their cells\n const rows: { content: string; align: string | null; isHeader: boolean }[][] = [];\n const rowRegex = /<tr[^>]*>(.*?)<\\/tr>/gs;\n let rowExec;\n while ((rowExec = rowRegex.exec(tableContent)) !== null) {\n const rowHtml = rowExec[1];\n const cells: { content: string; align: string | null; isHeader: boolean }[] = [];\n const cellRegex = /<(th|td)([^>]*)>(.*?)<\\/\\1>/gs;\n let cellExec;\n while ((cellExec = cellRegex.exec(rowHtml)) !== null) {\n const tag = cellExec[1];\n const attrs = cellExec[2];\n const content = htmlToInline(cellExec[3].replace(/<\\/?p>/g, ''));\n const alignExec = attrs.match(/text-align:\\s*(left|center|right)/);\n cells.push({\n content,\n align: alignExec ? alignExec[1] : null,\n isHeader: tag === 'th',\n });\n }\n if (cells.length > 0) {\n rows.push(cells);\n }\n }\n\n if (rows.length > 0) {\n // Header row = first row with th cells, or just the first row\n const headerIdx = rows.findIndex((r) => r.some((c) => c.isHeader));\n const hIdx = headerIdx >= 0 ? headerIdx : 0;\n const headerRow = rows[hIdx];\n const dataRows = rows.filter((_, i) => i !== hIdx);\n\n const aligns = headerRow.map((c) => c.align);\n lines.push('| ' + headerRow.map((c) => c.content || ' ').join(' | ') + ' |');\n lines.push(\n '| ' +\n aligns\n .map((a) => {\n if (a === 'center') return ':---:';\n if (a === 'right') return '---:';\n return '---';\n })\n .join(' | ') +\n ' |',\n );\n for (const row of dataRows) {\n lines.push('| ' + row.map((c) => c.content || ' ').join(' | ') + ' |');\n }\n lines.push('');\n }\n\n remaining = remaining.slice(tableMatch[0].length);\n continue;\n }\n\n // Task list\n const taskListMatch = remaining.match(/^<ul[^>]*data-type=\"taskList\"[^>]*>(.*?)<\\/ul>/s);\n if (taskListMatch) {\n const items = taskListMatch[1].matchAll(\n /<li[^>]*data-type=\"taskItem\"[^>]*(data-checked=\"true\")?[^>]*>.*?<\\/li>/gs,\n );\n for (const item of items) {\n const checked = item[0].includes('data-checked=\"true\"') || item[0].includes('checked');\n const textMatch = item[0].match(/<label>.*?<\\/label>|<p>(.*?)<\\/p>/s);\n const text = textMatch ? htmlToInline(textMatch[0].replace(/<[^>]+>/g, '')) : '';\n lines.push(`- [${checked ? 'x' : ' '}] ${text}`);\n }\n lines.push('');\n remaining = remaining.slice(taskListMatch[0].length);\n continue;\n }\n\n // Unordered list\n const ulMatch = remaining.match(/^<ul>(.*?)<\\/ul>/s);\n if (ulMatch) {\n const items = ulMatch[1].matchAll(/<li>(.*?)<\\/li>/gs);\n for (const item of items) {\n lines.push(...renderListItem('- ', item[1]));\n }\n lines.push('');\n remaining = remaining.slice(ulMatch[0].length);\n continue;\n }\n\n // Ordered list\n const olMatch = remaining.match(/^<ol[^>]*>(.*?)<\\/ol>/s);\n if (olMatch) {\n const items = [...olMatch[1].matchAll(/<li>(.*?)<\\/li>/gs)];\n items.forEach((item, idx) => {\n lines.push(...renderListItem(`${idx + 1}. `, item[1]));\n });\n lines.push('');\n remaining = remaining.slice(olMatch[0].length);\n continue;\n }\n\n // Paragraph\n const pMatch = remaining.match(/^<p>(.*?)<\\/p>/s);\n if (pMatch) {\n const text = htmlToInline(pMatch[1]);\n if (text.trim()) {\n lines.push(text);\n lines.push('');\n }\n remaining = remaining.slice(pMatch[0].length);\n continue;\n }\n\n // Block-level image. TipTap's Image extension with `inline: false`\n // emits `<img src alt>` as a bare top-level element (no wrapping\n // `<p>`). Without this handler the skip-unknown-tags catch-all\n // below silently drops the image from the outgoing markdown —\n // the bug that made the chat composer ship image-less messages\n // even though the editor showed the picture. Handled here,\n // before the inline walker ever sees it.\n const imgMatch = remaining.match(/^<img\\b([^>]*)>/);\n if (imgMatch) {\n const attrs = imgMatch[1] ?? '';\n const src = /\\bsrc=\"([^\"]*)\"/i.exec(attrs)?.[1];\n if (src) {\n const alt = /\\balt=\"([^\"]*)\"/i.exec(attrs)?.[1] ?? '';\n lines.push(serializeImage(src, alt, attrs));\n lines.push('');\n }\n remaining = remaining.slice(imgMatch[0].length);\n continue;\n }\n\n // Block-level `<video>` / `<audio>` — emitted by our TiptapVideo /\n // TiptapAudio atom nodes (block group). Serialize the whole tag\n // (opening + closing) back to markdown unchanged; CommonMark allows\n // inline HTML, and our renderer plus the InlinePreviewGutter both\n // know how to parse the htmlElement back out.\n const mediaMatch = remaining.match(/^<(video|audio)\\b([^>]*)>(?:[\\s\\S]*?<\\/\\1>)?/);\n if (mediaMatch) {\n const tag = mediaMatch[1] === 'video' ? 'video' : 'audio';\n lines.push(serializeMediaTag(tag, mediaMatch[2] ?? ''));\n lines.push('');\n remaining = remaining.slice(mediaMatch[0].length);\n continue;\n }\n\n // Skip unknown tags or whitespace\n const skipMatch = remaining.match(/^(<[^>]+>|\\s+)/);\n if (skipMatch) {\n remaining = remaining.slice(skipMatch[0].length);\n continue;\n }\n\n // Plain text (shouldn't happen in well-formed Tiptap output)\n const textMatch = remaining.match(/^([^<]+)/);\n if (textMatch) {\n lines.push(unescapeHtml(textMatch[1]));\n remaining = remaining.slice(textMatch[0].length);\n continue;\n }\n\n // Safety: skip one character to avoid infinite loop\n remaining = remaining.slice(1);\n }\n\n // Clean up trailing blank lines\n return (\n lines\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim() + '\\n'\n );\n}\n\n/**\n * Render a list item's HTML content as one or more markdown lines.\n * Handles `<p>` paragraph breaks (blank line) and `<br>` hard breaks\n * (two trailing spaces). Continuation lines are indented to keep them\n * inside the list item.\n */\nfunction renderListItem(prefix: string, html: string): string[] {\n const indent = ' '.repeat(prefix.length);\n\n // Split on </p><p> to detect paragraph breaks within the item\n const paragraphs = html\n .split(/<\\/p>\\s*<p[^>]*>/i)\n .map((p) => p.replace(/^<p[^>]*>/i, '').replace(/<\\/p>\\s*$/i, ''));\n\n const result: string[] = [];\n paragraphs.forEach((paragraph, pIdx) => {\n const inline = htmlToInline(paragraph).trim();\n if (!inline) return;\n\n // Each <br> already became \" \\n\" in htmlToInline; split on it now.\n const subLines = inline.split('\\n');\n subLines.forEach((sub, sIdx) => {\n if (pIdx === 0 && sIdx === 0) {\n result.push(prefix + sub);\n } else {\n // Blank line separator between paragraphs (sIdx === 0 means new paragraph)\n if (sIdx === 0) result.push('');\n result.push(indent + sub);\n }\n });\n });\n\n return result.length > 0 ? result : [prefix];\n}\n\n// ─── Table helpers ───────────────────────────────────────\n\n/** Split a GFM table row into trimmed cell strings (strips outer pipes). */\nfunction parseTableCells(line: string): string[] {\n let inner = line.trim();\n if (inner.startsWith('|')) inner = inner.slice(1);\n if (inner.endsWith('|')) inner = inner.slice(0, -1);\n return inner.split('|').map((cell) => cell.trim());\n}\n\n/** Parse a GFM separator line into column alignments. */\nfunction parseAlignments(separatorLine: string): (string | null)[] {\n return parseTableCells(separatorLine).map((cell) => {\n const s = cell.replace(/\\s/g, '');\n if (s.startsWith(':') && s.endsWith(':')) return 'center';\n if (s.endsWith(':')) return 'right';\n if (s.startsWith(':')) return 'left';\n return null;\n });\n}\n\n// ─── Helpers ─────────────────────────────────────────────\n\n/**\n * Serialize a parsed `<img>` tag back to markdown. When the tag carries\n * an explicit `width` and/or `height` we emit a raw HTML `<img>` (the\n * markdown shorthand `![alt](src)` has no syntax for dimensions);\n * otherwise the friendlier shorthand is used. Markdown allows inline\n * HTML, so the HTML form parses and renders identically in any\n * CommonMark/GFM viewer.\n */\n/**\n * Serialize a `<video>` or `<audio>` tag (from the Tiptap atom node's\n * `renderHTML`) back to markdown. We re-emit only the attributes the\n * recorder + the renderer care about, in a stable order, so the\n * round-tripped markdown stays deterministic regardless of how Tiptap\n * decided to order them on its output.\n */\nfunction serializeMediaTag(tag: 'video' | 'audio', attrs: string): string {\n const src = /\\bsrc=\"([^\"]*)\"/i.exec(attrs)?.[1] ?? '';\n const controls = /\\bcontrols\\b/i.test(attrs);\n const width = /\\bwidth=\"([^\"]*)\"/i.exec(attrs)?.[1];\n const height = /\\bheight=\"([^\"]*)\"/i.exec(attrs)?.[1];\n const poster = tag === 'video' ? /\\bposter=\"([^\"]*)\"/i.exec(attrs)?.[1] : undefined;\n const parts = [`<${tag} src=\"${src}\"`];\n if (controls) parts.push(' controls');\n if (width) parts.push(` width=\"${width}\"`);\n if (height) parts.push(` height=\"${height}\"`);\n if (poster) parts.push(` poster=\"${poster}\"`);\n parts.push(`></${tag}>`);\n return parts.join('');\n}\n\nfunction serializeImage(src: string, alt: string, attrs: string): string {\n const width = /\\bwidth=\"([^\"]*)\"/i.exec(attrs)?.[1];\n const height = /\\bheight=\"([^\"]*)\"/i.exec(attrs)?.[1];\n const title = /\\btitle=\"([^\"]*)\"/i.exec(attrs)?.[1];\n if (!width && !height) {\n return `![${alt}](${src})`;\n }\n const parts = [`<img alt=\"${alt}\" src=\"${src}\"`];\n if (width) parts.push(` width=\"${width}\"`);\n if (height) parts.push(` height=\"${height}\"`);\n if (title) parts.push(` title=\"${title}\"`);\n parts.push('>');\n return parts.join('');\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nfunction unescapeHtml(text: string): string {\n return text\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&amp;/g, '&');\n}\n\n/** Convert inline markdown to HTML for Tiptap consumption */\nfunction inlineToHtml(text: string): string {\n // Extract images/mentions/links to opaque placeholders BEFORE running\n // any inline-formatting regexes. Otherwise `_` characters inside a URL\n // (e.g. `mikehome_files/IMG_6829.JPEG`) get turned into `<em>` tags by\n // the underscore-italic rule, mangling the src so the image renders\n // broken after a markdown ↔ WYSIWYG round-trip.\n const placeholders: string[] = [];\n const stash = (html: string): string => {\n const token = `\\u0000PH${placeholders.length}\\u0000`;\n placeholders.push(html);\n return token;\n };\n\n // We run extraction on the RAW text (before escapeHtml) so the\n // captured groups are the literal markdown contents; then we\n // selectively escape the parts of each placeholder that need it.\n\n // Images first: ![alt](src) — must be before links so the `!` prefix is consumed\n let staged = text.replace(RE_IMAGE, (_m, alt, src) =>\n stash(`<img alt=\"${escapeHtml(alt)}\" src=\"${escapeHtml(src)}\">`),\n );\n\n // Mentions: @[Display](scheme:id) — must run before links so the\n // bracket+paren isn't consumed as a regular link.\n staged = staged.replace(RE_MENTION, (_m, label, kind, id) =>\n stash(\n `<span data-mention=\"true\" data-kind=\"${escapeHtml(kind)}\" data-id=\"${escapeHtml(id)}\" data-label=\"${escapeHtml(label)}\" class=\"mention\">@${escapeHtml(label)}</span>`,\n ),\n );\n\n // FontAwesome inline icons: {[github]} / {[fa-solid:user]} — resolve\n // against the FA catalog so unknown / ambiguous tokens stay as\n // literal text (preserved through escapeHtml later). Stashing here\n // alongside images/mentions keeps the `_` and other punctuation in\n // the class attribute from being mangled by the underscore-italic\n // regex below.\n staged = staged.replace(RE_ICON_MD, (full, token) => {\n const icon = resolveIcon(token);\n if (!icon) return full; // leave literal text — author may have meant it\n return stash(\n `<i class=\"fa-${icon.family} fa-${icon.name}\" data-icon=\"${escapeHtml(token)}\" data-family=\"${icon.family}\" data-name=\"${icon.name}\" contenteditable=\"false\"></i>`,\n );\n });\n\n // Links: [text](url) — stash but keep the link text available to\n // inline formatting by recursing.\n staged = staged.replace(RE_LINK, (_m, linkText, href) =>\n stash(`<a href=\"${escapeHtml(href)}\">${inlineToHtml(linkText)}</a>`),\n );\n\n let result = escapeHtml(staged);\n\n // Bold: **text** or __text__\n result = result.replace(RE_BOLD_STAR, '<strong>$1</strong>');\n result = result.replace(RE_BOLD_UNDER, '<strong>$1</strong>');\n\n // Italic: *text* or _text_\n result = result.replace(RE_ITALIC_STAR, '<em>$1</em>');\n result = result.replace(RE_ITALIC_UNDER, '<em>$1</em>');\n\n // Strikethrough: ~~text~~\n result = result.replace(RE_STRIKETHROUGH, '<s>$1</s>');\n\n // Inline code: `text`\n result = result.replace(RE_INLINE_CODE, '<code>$1</code>');\n\n // Restore placeholders. escapeHtml turned each `\\u0000PHn\\u0000` into\n // the same string (the NULs and digits are escape-safe), so the\n // restoration regex still matches.\n // eslint-disable-next-line no-control-regex\n result = result.replace(/\\u0000PH(\\d+)\\u0000/g, (_m, idx) => placeholders[Number(idx)] ?? '');\n\n return result;\n}\n\n/** Convert inline HTML back to markdown */\nfunction htmlToInline(html: string): string {\n let result = html;\n\n // Soft line breaks — convert <br> to GFM hard-break syntax (two trailing\n // spaces + newline) before stripping tags so the newline survives.\n result = result.replace(/<br\\s*\\/?>/gi, ' \\n');\n\n // FontAwesome inline icons — emit the original token. Must run before\n // RE_I_TAG (which matches a bare `<i>` and would otherwise eat icon\n // tags too). The token captured via data-icon already carries the\n // qualified form when needed, so source round-trips exactly.\n result = result.replace(RE_ICON_TAG, (_m, token) => `{[${token}]}`);\n\n // Strong\n result = result.replace(RE_STRONG_TAG, '**$1**');\n result = result.replace(RE_B_TAG, '**$1**');\n\n // Em\n result = result.replace(RE_EM_TAG, '*$1*');\n result = result.replace(RE_I_TAG, '*$1*');\n\n // Strikethrough\n result = result.replace(RE_S_TAG, '~~$1~~');\n result = result.replace(RE_DEL_TAG, '~~$1~~');\n\n // Code\n result = result.replace(RE_CODE_TAG, '`$1`');\n\n // Mentions — match before the link handler so the span isn't stripped\n // out as an unknown tag. Pull kind + id out of the data attributes.\n result = result.replace(RE_MENTION_TAG, (match, _inner) => {\n const kind = /data-kind=\"([^\"]*)\"/i.exec(match)?.[1] ?? '';\n const id = /data-id=\"([^\"]*)\"/i.exec(match)?.[1] ?? '';\n const label = /data-label=\"([^\"]*)\"/i.exec(match)?.[1] ?? '';\n if (!kind || !id || !label) return match;\n return `@[${label}](${kind}:${id})`;\n });\n\n // Links\n result = result.replace(RE_A_TAG, '[$2]($1)');\n\n // Images — order-agnostic attribute parsing (tiptap emits src-first,\n // our markdown-to-html emits alt-first; either must serialize back).\n // When a width/height is present we serialize as raw HTML `<img>` so\n // the dimensions survive the round-trip; otherwise the markdown\n // shorthand `![alt](src)` is used.\n result = result.replace(RE_IMG_TAG, (match, attrs: string) => {\n const src = /\\bsrc=\"([^\"]*)\"/i.exec(attrs)?.[1];\n if (!src) return match;\n const alt = /\\balt=\"([^\"]*)\"/i.exec(attrs)?.[1] ?? '';\n return serializeImage(src, alt, attrs);\n });\n\n // Strip remaining tags\n result = result.replace(RE_STRIP_TAGS, '');\n\n return unescapeHtml(result);\n}\n","/**\n * fileKind\n *\n * Maps a file name (or bare extension) to a Monaco language ID and decides\n * whether the editor shell should operate in markdown mode (full WYSIWYG +\n * Preview experience) or code mode (Monaco-only view with formatting\n * buttons hidden).\n *\n * The mapping favors common web / systems languages that Monaco ships with\n * out of the box. Unknown extensions fall back to markdown mode so the\n * existing UX remains the default for anything we don't recognize.\n */\n\nexport interface FileKind {\n /**\n * 'markdown' keeps the full editor (WYSIWYG + Preview tabs); 'code' is\n * Monaco-only; 'image' renders a dedicated image viewer with no text\n * editing surface.\n */\n mode: 'markdown' | 'code' | 'image';\n /** Monaco language ID — passed to `<Editor defaultLanguage={...} />`. */\n language: string;\n}\n\n/**\n * Extension → Monaco language ID. Keys are lowercase, no leading dot.\n * Extend as needed; unknown extensions fall back to markdown mode.\n */\nconst EXT_TO_LANGUAGE: Record<string, string> = {\n md: 'markdown',\n markdown: 'markdown',\n mdown: 'markdown',\n txt: 'plaintext',\n ts: 'typescript',\n tsx: 'typescript',\n js: 'javascript',\n jsx: 'javascript',\n mjs: 'javascript',\n cjs: 'javascript',\n json: 'json',\n jsonc: 'json',\n html: 'html',\n htm: 'html',\n css: 'css',\n scss: 'scss',\n less: 'less',\n py: 'python',\n go: 'go',\n rs: 'rust',\n rb: 'ruby',\n java: 'java',\n c: 'c',\n h: 'c',\n cpp: 'cpp',\n hpp: 'cpp',\n cc: 'cpp',\n cs: 'csharp',\n php: 'php',\n sh: 'shell',\n bash: 'shell',\n zsh: 'shell',\n yml: 'yaml',\n yaml: 'yaml',\n toml: 'ini',\n ini: 'ini',\n xml: 'xml',\n svg: 'xml',\n sql: 'sql',\n lua: 'lua',\n swift: 'swift',\n kt: 'kotlin',\n kts: 'kotlin',\n dockerfile: 'dockerfile',\n png: 'image',\n jpg: 'image',\n jpeg: 'image',\n gif: 'image',\n webp: 'image',\n bmp: 'image',\n ico: 'image',\n avif: 'image',\n};\n\n/**\n * Languages that keep the full markdown shell (WYSIWYG + Preview). Anything\n * outside this set is treated as code, except for languages in\n * `IMAGE_MODE_LANGUAGES`.\n */\nconst MARKDOWN_MODE_LANGUAGES = new Set(['markdown', 'plaintext']);\n\n/**\n * Languages that switch the shell into image-viewer mode — no text editing\n * surface, no markdown chrome.\n */\nconst IMAGE_MODE_LANGUAGES = new Set(['image']);\n\n/**\n * Pull the lowercase extension (no leading dot) from a file name or bare\n * extension string. Returns null when none is discernible.\n *\n * Examples:\n * \"foo.ts\" → \"ts\"\n * \"foo.tar.gz\" → \"gz\"\n * \".ts\" → \"ts\"\n * \"ts\" → \"ts\"\n * \"Dockerfile\" → \"dockerfile\" (full name match for extensionless files)\n * \"\" → null\n */\nfunction extractExtension(fileName: string): string | null {\n const trimmed = fileName.trim();\n if (!trimmed) return null;\n\n // Strip any leading path — take only the basename.\n const base = trimmed.replace(/^.*[/\\\\]/, '');\n if (!base) return null;\n\n const dotIdx = base.lastIndexOf('.');\n if (dotIdx === -1) {\n // No dot — could still be a recognized bare name (Dockerfile) or a bare\n // extension passed by a caller like \"ts\". Lower-case and return.\n return base.toLowerCase();\n }\n if (dotIdx === base.length - 1) return null; // Trailing dot, no extension.\n return base.slice(dotIdx + 1).toLowerCase();\n}\n\n/**\n * Detect a Monaco language ID from a file name. Returns null when the\n * extension (or bare name) is not in the mapping.\n */\nexport function detectLanguageFromFileName(fileName: string): string | null {\n const ext = extractExtension(fileName);\n if (!ext) return null;\n return EXT_TO_LANGUAGE[ext] ?? null;\n}\n\n/**\n * Resolve the editor mode + Monaco language for a given file. The explicit\n * `language` argument, if provided, wins over any detection from\n * `fileName`. When nothing matches, falls back to markdown mode.\n */\nexport function resolveFileKind(fileName?: string, language?: string): FileKind {\n const resolvedLanguage = language ?? (fileName ? detectLanguageFromFileName(fileName) : null);\n\n if (!resolvedLanguage) {\n return { mode: 'markdown', language: 'markdown' };\n }\n\n let mode: FileKind['mode'];\n if (IMAGE_MODE_LANGUAGES.has(resolvedLanguage)) {\n mode = 'image';\n } else if (MARKDOWN_MODE_LANGUAGES.has(resolvedLanguage)) {\n mode = 'markdown';\n } else {\n mode = 'code';\n }\n return { mode, language: resolvedLanguage };\n}\n","/**\n * Toolbar\n *\n * Formatting toolbar that provides common markdown editing actions.\n * In WYSIWYG mode, uses Tiptap's chain commands to toggle marks / set nodes.\n * In Raw mode, appends markdown syntax at the cursor (or end of source).\n * Hidden in Preview mode.\n */\n\nimport type { ReactNode } from 'react';\nimport { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react';\nimport type { Editor as TiptapEditor } from '@tiptap/core';\nimport type { IRange } from 'monaco-editor';\nimport { useEditorContext, type EditorView } from './EditorContext';\nimport { VersionHistoryPanel } from './VersionHistoryPanel';\nimport { RecorderEntry } from './RecorderEntry';\nimport { ViewMenuPanel } from './ViewMenuPanel';\nimport { TemplatePicker, TEMPLATE_NAMES } from './TemplatePicker';\nimport { profileBlockContents, recommendTemplatesForBlock } from '@bendyline/squisq/recommend';\nimport { findBlockSliceAtLine, findBlockSliceByHeadingIndex } from './blockSlice';\nimport { LinkDialog } from './LinkDialog';\nimport { DocumentSettingsDialog } from './DocumentSettingsDialog';\nimport { EmojiPicker, EMOJI_PICKER_WIDTH, EMOJI_PICKER_MAX_HEIGHT } from './EmojiPicker';\nimport type { PickerEntry } from './emojiData';\nimport { createPortal } from 'react-dom';\n\nconst VIEWS: { id: EditorView; label: string; shortLabel?: string; shortcut: string }[] = [\n { id: 'wysiwyg', label: 'Editor', shortcut: '⌘1' },\n { id: 'raw', label: 'Markdown', shortLabel: 'MD', shortcut: '⌘2' },\n { id: 'preview', label: 'Play', shortcut: '⌘3' },\n];\n\nexport interface ToolbarProps {\n /** Additional class name */\n className?: string;\n /** Whether the Files panel is currently shown */\n showFiles?: boolean;\n /** Toggle the Files panel. When provided, a \"Files\" button appears in the toolbar. */\n onToggleFiles?: () => void;\n /** Content rendered at the left edge of the toolbar, before the view tabs. */\n slotLeft?: ReactNode;\n /** Content rendered after the formatting controls (in the middle area). */\n slotAfterActions?: ReactNode;\n /** Content rendered at the rightmost end of the toolbar, after all other elements. */\n slotRight?: ReactNode;\n /**\n * Whether to include the \"Play\" (preview) tab in the view switcher.\n * Defaults to true. Hosts that don't want the slideshow preview — e.g.\n * editing free-form prompts — can pass false to suppress it.\n */\n showPlayTab?: boolean;\n}\n\ninterface ToolbarButton {\n id: string;\n label: string;\n icon: string;\n title: string;\n group: 'format' | 'lists' | 'structure' | 'insert' | 'media';\n /** CSS font style for the icon (e.g. italic for the I button) */\n iconStyle?: React.CSSProperties;\n}\n\nconst BUTTONS: ToolbarButton[] = [\n // Format group — B/I/S trio.\n {\n id: 'bold',\n label: 'B',\n icon: 'B',\n title: 'Bold (Ctrl+B)',\n group: 'format',\n iconStyle: { fontWeight: 700 },\n },\n {\n id: 'italic',\n label: 'I',\n icon: 'I',\n title: 'Italic (Ctrl+I)',\n group: 'format',\n iconStyle: { fontStyle: 'italic' },\n },\n {\n id: 'strikethrough',\n label: 'S',\n icon: 'S',\n title: 'Strikethrough',\n group: 'format',\n iconStyle: { textDecoration: 'line-through' },\n },\n\n // Lists group — sits between format and structure so bullets/numbers\n // are adjacent to the inline formatters people reach for together.\n { id: 'ul', label: '•', icon: '•', title: 'Bullet list', group: 'lists' },\n { id: 'ol', label: '1.', icon: '1.', title: 'Numbered list', group: 'lists' },\n\n // Structure group\n { id: 'h1', label: 'H1', icon: 'H1', title: 'Heading 1', group: 'structure' },\n { id: 'h2', label: 'H2', icon: 'H2', title: 'Heading 2', group: 'structure' },\n { id: 'h3', label: 'H3', icon: 'H3', title: 'Heading 3', group: 'structure' },\n { id: 'h4', label: 'H4', icon: 'H4', title: 'Heading 4', group: 'structure' },\n { id: 'h5', label: 'H5', icon: 'H5', title: 'Heading 5', group: 'structure' },\n { id: 'h6', label: 'H6', icon: 'H6', title: 'Heading 6', group: 'structure' },\n\n // Insert group — block-level inserts (quote, code blocks, rules)\n { id: 'quote', label: '❝', icon: '❝', title: 'Blockquote', group: 'insert' },\n { id: 'codeblock', label: '{ }', icon: '{ }', title: 'Code block', group: 'insert' },\n { id: 'code', label: '</>', icon: '</>', title: 'Inline code', group: 'insert' },\n { id: 'hr', label: '—', icon: '—', title: 'Horizontal rule', group: 'insert' },\n\n // Media group — links, tables, images, emoji\n { id: 'link', label: '🔗', icon: '🔗', title: 'Insert link', group: 'media' },\n { id: 'table', label: 'table', icon: '', title: 'Insert table', group: 'media' },\n { id: 'image', label: '🖼', icon: '🖼', title: 'Insert image', group: 'media' },\n { id: 'emoji', label: '😊', icon: '😊', title: 'Insert emoji', group: 'media' },\n];\n\n// ─── Inline SVG icons (line-art, currentColor) ──────────\n\nconst TABLE_ICON = (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n >\n <rect x=\"1\" y=\"1\" width=\"12\" height=\"12\" rx=\"1\" />\n <line x1=\"1\" y1=\"5\" x2=\"13\" y2=\"5\" />\n <line x1=\"1\" y1=\"9\" x2=\"13\" y2=\"9\" />\n <line x1=\"5\" y1=\"1\" x2=\"5\" y2=\"13\" />\n <line x1=\"9\" y1=\"1\" x2=\"9\" y2=\"13\" />\n </svg>\n);\n\nconst LINK_ICON = (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M5.75 8.25 L8.25 5.75\" />\n <path d=\"M6.5 3.75 L8 2.25 a2.5 2.5 0 0 1 3.54 3.54 L10 7.25\" />\n <path d=\"M7.5 10.25 L6 11.75 a2.5 2.5 0 0 1 -3.54 -3.54 L4 6.75\" />\n </svg>\n);\n\nconst IMAGE_ICON = (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"9\" rx=\"1\" />\n <circle cx=\"5\" cy=\"5.5\" r=\"0.9\" />\n <path d=\"M2 10 L5.5 7 L8 9 L10 7.5 L12.5 10\" />\n </svg>\n);\n\nconst PAPERCLIP_ICON = (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M11 4 L5.5 9.5 a1.75 1.75 0 0 0 2.5 2.5 L12.5 7.5 a3 3 0 0 0 -4.25 -4.25 L3 8.5 a4.25 4.25 0 0 0 6 6 L13 10.5\" />\n </svg>\n);\n\nconst EMOJI_ICON = (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"7\" cy=\"7\" r=\"5.25\" />\n <circle cx=\"5.25\" cy=\"5.75\" r=\"0.6\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"8.75\" cy=\"5.75\" r=\"0.6\" fill=\"currentColor\" stroke=\"none\" />\n <path d=\"M4.75 8.5 a2.5 2.5 0 0 0 4.5 0\" />\n </svg>\n);\n\n/** Returns an SVG element when the button id maps to one, otherwise null. */\nfunction buttonIconSvg(id: string): React.ReactNode | null {\n switch (id) {\n case 'table':\n return TABLE_ICON;\n case 'link':\n return LINK_ICON;\n case 'image':\n return IMAGE_ICON;\n case 'emoji':\n return EMOJI_ICON;\n default:\n return null;\n }\n}\n\n// ─── Tiptap active-state map ────────────────────────────\n\n/** Returns true if the given button id is currently active in Tiptap */\nfunction isTiptapActive(editor: TiptapEditor, id: string): boolean {\n if (!editor) return false;\n switch (id) {\n case 'bold':\n return editor.isActive('bold');\n case 'italic':\n return editor.isActive('italic');\n case 'strikethrough':\n return editor.isActive('strike');\n case 'code':\n return editor.isActive('code');\n case 'h1':\n return editor.isActive('heading', { level: 1 });\n case 'h2':\n return editor.isActive('heading', { level: 2 });\n case 'h3':\n return editor.isActive('heading', { level: 3 });\n case 'h4':\n return editor.isActive('heading', { level: 4 });\n case 'h5':\n return editor.isActive('heading', { level: 5 });\n case 'h6':\n return editor.isActive('heading', { level: 6 });\n case 'quote':\n return editor.isActive('blockquote');\n case 'ul':\n return editor.isActive('bulletList');\n case 'ol':\n return editor.isActive('orderedList');\n case 'codeblock':\n return editor.isActive('codeBlock');\n default:\n return false;\n }\n}\n\n/**\n * Formatting toolbar.\n * - WYSIWYG: calls Tiptap chain commands (toggleBold, etc.)\n * - Raw: appends markdown syntax to the source\n */\nexport function Toolbar({\n className,\n showFiles,\n onToggleFiles,\n slotLeft,\n slotAfterActions,\n slotRight,\n showPlayTab = true,\n}: ToolbarProps) {\n const {\n activeView,\n setActiveView,\n markdownSource,\n setMarkdownSource,\n tiptapEditor,\n monacoEditor,\n mediaProvider,\n editorMode,\n versioning,\n allowRecording,\n documentLinkProvider,\n theme,\n } = useEditorContext();\n const isCodeMode = editorMode === 'code';\n // In code mode only the raw view is meaningful; the WYSIWYG and Preview\n // surfaces aren't mounted, so hide their tabs.\n const visibleViews = VIEWS.filter((v) => {\n if (isCodeMode) return v.id === 'raw';\n if (v.id === 'preview' && !showPlayTab) return false;\n return true;\n });\n const showViewTabs = visibleViews.length > 1;\n\n // Hidden file input for image picker\n const imageInputRef = useRef<HTMLInputElement>(null);\n\n // Link dialog — shared by WYSIWYG and Raw views.\n const [linkDialog, setLinkDialog] = useState<{\n mode: 'insert' | 'update';\n target: 'wysiwyg' | 'raw';\n initialText: string;\n initialUrl: string;\n /** For target='raw': the range to replace when editing an existing\n * [text](url) under the cursor. Null means use the current Monaco\n * selection (insert at cursor / wrap selection). */\n rawRange: IRange | null;\n } | null>(null);\n\n // Emoji picker — toolbar-anchored popover. We track the trigger\n // button's screen rect so the picker can position itself just below\n // it via createPortal (the toolbar's overflow:hidden actions row\n // would otherwise clip the popover).\n const emojiButtonRef = useRef<HTMLButtonElement | null>(null);\n const [emojiPickerAnchor, setEmojiPickerAnchor] = useState<{\n top: number;\n left: number;\n } | null>(null);\n\n const openEmojiPicker = useCallback(() => {\n const btn = emojiButtonRef.current;\n if (!btn) return;\n const rect = btn.getBoundingClientRect();\n // Position just below the trigger by default, then clamp into the\n // visible viewport so the picker is never clipped on the right or\n // bottom — flips above the trigger when there isn't room below.\n const gap = 6;\n const margin = 8;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n let left = rect.left;\n if (left + EMOJI_PICKER_WIDTH + margin > vw) {\n left = Math.max(margin, vw - EMOJI_PICKER_WIDTH - margin);\n }\n let top = rect.bottom + gap;\n if (top + EMOJI_PICKER_MAX_HEIGHT + margin > vh) {\n const flipped = rect.top - EMOJI_PICKER_MAX_HEIGHT - gap;\n // Prefer flipping above when there's more room there; otherwise\n // pin to the top edge with margin and let the picker's own\n // maxHeight clip it.\n top = flipped >= margin ? flipped : margin;\n }\n setEmojiPickerAnchor({ top, left });\n }, []);\n\n const closeEmojiPicker = useCallback(() => setEmojiPickerAnchor(null), []);\n\n // ── Narrow-screen detection ──────────────────────────\n const [isNarrow, setIsNarrow] = useState(\n () => typeof window !== 'undefined' && window.matchMedia('(max-width: 768px)').matches,\n );\n useEffect(() => {\n const mq = window.matchMedia('(max-width: 768px)');\n const handler = (e: MediaQueryListEvent) => setIsNarrow(e.matches);\n mq.addEventListener('change', handler);\n return () => mq.removeEventListener('change', handler);\n }, []);\n\n // ── Overflow detection ────────────────────────────────\n const actionsRef = useRef<HTMLDivElement>(null);\n const [measuredOverflowIndex, setMeasuredOverflowIndex] = useState<number | null>(null);\n const [showOverflow, setShowOverflow] = useState(false);\n const overflowRef = useRef<HTMLDivElement>(null);\n\n // Document settings (frontmatter) dialog\n const [showDocSettings, setShowDocSettings] = useState(false);\n\n // On narrow screens, force all buttons into the overflow menu\n const overflowIndex = isNarrow ? 0 : measuredOverflowIndex;\n\n useEffect(() => {\n if (isNarrow) return; // Skip measurement on narrow — everything overflows\n const container = actionsRef.current;\n if (!container) return;\n\n const measure = () => {\n const containerRight = container.getBoundingClientRect().right;\n const children = container.querySelectorAll<HTMLElement>(\n ':scope > .squisq-toolbar-group > .squisq-toolbar-button',\n );\n let firstHidden: number | null = null;\n children.forEach((child, i) => {\n if (firstHidden !== null) return;\n const rect = child.getBoundingClientRect();\n // A button is hidden if its right edge extends past the container\n if (rect.right > containerRight + 2) {\n firstHidden = i;\n }\n });\n setMeasuredOverflowIndex(firstHidden);\n };\n\n const ro = new ResizeObserver(measure);\n ro.observe(container);\n measure();\n return () => ro.disconnect();\n }, [activeView, isNarrow]);\n\n // Close overflow menu on outside click\n useEffect(() => {\n if (!showOverflow) return;\n const handleClick = (e: MouseEvent) => {\n if (overflowRef.current && !overflowRef.current.contains(e.target as Node)) {\n setShowOverflow(false);\n }\n };\n document.addEventListener('mousedown', handleClick);\n return () => document.removeEventListener('mousedown', handleClick);\n }, [showOverflow]);\n\n // Open-up vs open-down: the overflow menu is anchored to its trigger with\n // `top: 100%` by default. When the toolbar lives near the bottom of a\n // small container (e.g. a chat composer), a downward menu gets clipped.\n // Measure on open and flip the anchor to `bottom: 100%` if the space\n // above the trigger is larger than the space below.\n const [overflowPlacement, setOverflowPlacement] = useState<'down' | 'up'>('down');\n useEffect(() => {\n if (!showOverflow || !overflowRef.current) return;\n const trigger = overflowRef.current.querySelector<HTMLElement>(\n '.squisq-toolbar-overflow-trigger',\n );\n if (!trigger) return;\n const rect = trigger.getBoundingClientRect();\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n // Assume a typical menu height; exact measurement is unreliable on first\n // open because the menu hasn't rendered yet when this runs.\n const ESTIMATED_MENU_HEIGHT = 260;\n if (spaceBelow < ESTIMATED_MENU_HEIGHT && spaceAbove > spaceBelow) {\n setOverflowPlacement('up');\n } else {\n setOverflowPlacement('down');\n }\n }, [showOverflow]);\n\n // Force re-render when Tiptap selection or formatting state changes\n const [, forceUpdate] = useReducer((c: number) => c + 1, 0);\n useEffect(() => {\n if (!tiptapEditor) return;\n tiptapEditor.on('transaction', forceUpdate);\n return () => {\n tiptapEditor.off('transaction', forceUpdate);\n };\n }, [tiptapEditor]);\n\n // ── Tiptap handler ─────────────────────────────────────\n const handleTiptap = useCallback(\n (id: string) => {\n if (!tiptapEditor) return;\n const chain = tiptapEditor.chain().focus();\n switch (id) {\n case 'bold':\n chain.toggleBold().run();\n break;\n case 'italic':\n chain.toggleItalic().run();\n break;\n case 'strikethrough':\n chain.toggleStrike().run();\n break;\n case 'code':\n chain.toggleCode().run();\n break;\n case 'h1':\n chain.toggleHeading({ level: 1 }).run();\n break;\n case 'h2':\n chain.toggleHeading({ level: 2 }).run();\n break;\n case 'h3':\n chain.toggleHeading({ level: 3 }).run();\n break;\n case 'h4':\n chain.toggleHeading({ level: 4 }).run();\n break;\n case 'h5':\n chain.toggleHeading({ level: 5 }).run();\n break;\n case 'h6':\n chain.toggleHeading({ level: 6 }).run();\n break;\n case 'quote':\n chain.toggleBlockquote().run();\n break;\n case 'ul':\n chain.toggleBulletList().run();\n break;\n case 'ol':\n chain.toggleOrderedList().run();\n break;\n case 'codeblock':\n chain.toggleCodeBlock().run();\n break;\n case 'hr':\n chain.setHorizontalRule().run();\n break;\n case 'link': {\n const isActive = tiptapEditor.isActive('link');\n let initialText = '';\n let initialUrl = '';\n if (isActive) {\n // Snap selection to the full link mark so editing replaces\n // the entire `[text](url)` rather than just the cursor word.\n tiptapEditor.chain().focus().extendMarkRange('link').run();\n const sel = tiptapEditor.state.selection;\n initialText = tiptapEditor.state.doc.textBetween(sel.from, sel.to, ' ');\n initialUrl = (tiptapEditor.getAttributes('link') as { href?: string }).href ?? '';\n } else {\n const { from, to, empty } = tiptapEditor.state.selection;\n if (!empty) {\n initialText = tiptapEditor.state.doc.textBetween(from, to, ' ');\n }\n }\n setLinkDialog({\n mode: isActive ? 'update' : 'insert',\n target: 'wysiwyg',\n initialText,\n initialUrl,\n rawRange: null,\n });\n break;\n }\n case 'table':\n tiptapEditor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();\n break;\n }\n },\n [tiptapEditor],\n );\n\n // ── Raw markdown handler ───────────────────────────────\n const handleRaw = useCallback(\n (id: string) => {\n if (monacoEditor) {\n // Use Monaco's selection API for proper wrap/insert behavior\n const selection = monacoEditor.getSelection();\n const model = monacoEditor.getModel();\n if (!selection || !model) return;\n\n const selectedText = model.getValueInRange(selection);\n const hasSelection = selectedText.length > 0;\n\n let replacement = '';\n let newCursorOffset = 0; // offset from start of replacement to place cursor\n\n // Inline wrapping: wrap selection or insert placeholder\n const wrapInline = (before: string, after: string, placeholder: string) => {\n if (hasSelection) {\n replacement = before + selectedText + after;\n } else {\n replacement = before + placeholder + after;\n // Select the placeholder text after insertion\n newCursorOffset = before.length;\n }\n };\n\n // Block-level: prefix each selected line, or insert a new block\n const prefixLines = (prefix: string, placeholder: string) => {\n if (hasSelection) {\n replacement = selectedText\n .split('\\n')\n .map((line: string) => prefix + line)\n .join('\\n');\n } else {\n replacement = prefix + placeholder;\n newCursorOffset = prefix.length;\n }\n };\n\n switch (id) {\n case 'bold':\n wrapInline('**', '**', 'bold text');\n break;\n case 'italic':\n wrapInline('*', '*', 'italic text');\n break;\n case 'strikethrough':\n wrapInline('~~', '~~', 'strikethrough');\n break;\n case 'code':\n wrapInline('`', '`', 'code');\n break;\n case 'h1':\n prefixLines('# ', 'Heading 1');\n break;\n case 'h2':\n prefixLines('## ', 'Heading 2');\n break;\n case 'h3':\n prefixLines('### ', 'Heading 3');\n break;\n case 'h4':\n prefixLines('#### ', 'Heading 4');\n break;\n case 'h5':\n prefixLines('##### ', 'Heading 5');\n break;\n case 'h6':\n prefixLines('###### ', 'Heading 6');\n break;\n case 'quote':\n prefixLines('> ', 'Quote');\n break;\n case 'ul':\n prefixLines('- ', 'Item');\n break;\n case 'ol':\n prefixLines('1. ', 'Item');\n break;\n case 'codeblock': {\n const inner = hasSelection ? selectedText : 'code';\n replacement = '```\\n' + inner + '\\n```';\n if (!hasSelection) newCursorOffset = 4; // after ```\\n\n break;\n }\n case 'hr': {\n replacement = '\\n---\\n';\n break;\n }\n case 'link': {\n // Open the LinkDialog instead of inserting literal text. If the\n // cursor sits inside an existing `[text](url)` on this line,\n // prefill from it and replace the whole match on confirm.\n const lineNumber = selection.startLineNumber;\n const lineText = model.getLineContent(lineNumber);\n const cursorCol = selection.startColumn;\n const linkRe = /\\[([^\\]]*)\\]\\(([^)]*)\\)/g;\n let match: RegExpExecArray | null;\n let existing: { text: string; url: string; range: IRange } | null = null;\n while ((match = linkRe.exec(lineText)) !== null) {\n const startCol = match.index + 1; // 1-based\n const endCol = startCol + match[0].length;\n if (cursorCol >= startCol && cursorCol <= endCol) {\n existing = {\n text: match[1],\n url: match[2],\n range: {\n startLineNumber: lineNumber,\n startColumn: startCol,\n endLineNumber: lineNumber,\n endColumn: endCol,\n },\n };\n break;\n }\n }\n setLinkDialog({\n mode: existing ? 'update' : 'insert',\n target: 'raw',\n initialText: existing ? existing.text : hasSelection ? selectedText : '',\n initialUrl: existing ? existing.url : '',\n rawRange: existing ? existing.range : null,\n });\n // Skip the executeEdits/setPosition tail below — the dialog will\n // apply its own edit on confirm.\n return;\n }\n case 'table': {\n const tpl =\n '| Header 1 | Header 2 | Header 3 |\\n| --- | --- | --- |\\n| Cell | Cell | Cell |\\n| Cell | Cell | Cell |';\n replacement = '\\n' + tpl + '\\n';\n newCursorOffset = 3; // after \\n|\n break;\n }\n }\n\n // Apply the edit via Monaco's executeEdits for proper undo support\n const range = selection;\n monacoEditor.executeEdits('toolbar', [{ range, text: replacement }]);\n\n // If no selection, select the placeholder text so user can type over it\n if (!hasSelection && newCursorOffset > 0) {\n const startPos = model.getPositionAt(\n model.getOffsetAt(range.getStartPosition()) + newCursorOffset,\n );\n // Just place cursor after the prefix\n monacoEditor.setPosition(startPos);\n }\n\n monacoEditor.focus();\n } else {\n // Fallback: no Monaco instance, just append\n let insertion = '';\n switch (id) {\n case 'bold':\n insertion = '**bold text**';\n break;\n case 'italic':\n insertion = '*italic text*';\n break;\n case 'strikethrough':\n insertion = '~~strikethrough~~';\n break;\n case 'code':\n insertion = '`code`';\n break;\n case 'h1':\n insertion = '\\n# Heading 1\\n';\n break;\n case 'h2':\n insertion = '\\n## Heading 2\\n';\n break;\n case 'h3':\n insertion = '\\n### Heading 3\\n';\n break;\n case 'quote':\n insertion = '\\n> Quote\\n';\n break;\n case 'ul':\n insertion = '\\n- Item\\n';\n break;\n case 'ol':\n insertion = '\\n1. Item\\n';\n break;\n case 'codeblock':\n insertion = '\\n```\\ncode\\n```\\n';\n break;\n case 'hr':\n insertion = '\\n---\\n';\n break;\n case 'link':\n insertion = '[link text](url)';\n break;\n case 'table':\n insertion =\n '\\n| Header 1 | Header 2 | Header 3 |\\n| --- | --- | --- |\\n| Cell | Cell | Cell |\\n| Cell | Cell | Cell |\\n';\n break;\n }\n if (insertion) {\n setMarkdownSource(markdownSource + insertion);\n }\n }\n },\n [monacoEditor, markdownSource, setMarkdownSource],\n );\n\n // ── Image upload handler ───────────────────────────────\n const handleImageFile = useCallback(\n async (file: File) => {\n if (!mediaProvider) return;\n const buffer = await file.arrayBuffer();\n const relativePath = await mediaProvider.addMedia(file.name, buffer, file.type);\n const altText = file.name.replace(/\\.[^.]+$/, '').replace(/[-_]/g, ' ');\n\n if (activeView === 'wysiwyg' && tiptapEditor) {\n tiptapEditor.chain().focus().setImage({ src: relativePath, alt: altText }).run();\n } else if (monacoEditor) {\n const selection = monacoEditor.getSelection();\n const model = monacoEditor.getModel();\n if (selection && model) {\n const md = `![${altText}](${relativePath})`;\n monacoEditor.executeEdits('toolbar', [{ range: selection, text: md }]);\n monacoEditor.focus();\n }\n } else {\n setMarkdownSource(markdownSource + `\\n![${altText}](${relativePath})\\n`);\n }\n },\n [mediaProvider, activeView, tiptapEditor, monacoEditor, markdownSource, setMarkdownSource],\n );\n\n const handleAction = useCallback(\n (id: string) => {\n if (id === 'image') {\n imageInputRef.current?.click();\n return;\n }\n if (id === 'emoji') {\n // Toggle the popover: clicking the button again closes it.\n if (emojiPickerAnchor) closeEmojiPicker();\n else openEmojiPicker();\n return;\n }\n if (activeView === 'wysiwyg' && tiptapEditor) {\n handleTiptap(id);\n } else {\n handleRaw(id);\n }\n },\n [\n activeView,\n tiptapEditor,\n handleTiptap,\n handleRaw,\n emojiPickerAnchor,\n openEmojiPicker,\n closeEmojiPicker,\n ],\n );\n\n // ── Picker insert (emoji or FontAwesome icon) ──────\n // Inserts a chosen picker entry at the cursor. We bypass\n // `insertAtCursor` (which routes through markdown→Tiptap conversion\n // and wraps the input in a paragraph) so entries land inline at the\n // caret rather than starting a new block. Emoji insert as a plain\n // character; FontAwesome icons insert as the `InlineIcon` Tiptap\n // node so the editor renders them inline immediately.\n const handleEmojiSelect = useCallback(\n (entry: PickerEntry) => {\n if (activeView === 'wysiwyg' && tiptapEditor) {\n if (entry.kind === 'emoji') {\n tiptapEditor.chain().focus().insertContent(entry.char).run();\n } else {\n tiptapEditor\n .chain()\n .focus()\n .insertContent({\n type: 'inlineIcon',\n attrs: { token: entry.token, family: entry.family, name: entry.name },\n })\n .run();\n }\n } else if (activeView === 'raw' && monacoEditor) {\n const insertion = entry.kind === 'emoji' ? entry.char : `{[${entry.token}]}`;\n const position = monacoEditor.getPosition();\n if (position) {\n const range = {\n startLineNumber: position.lineNumber,\n startColumn: position.column,\n endLineNumber: position.lineNumber,\n endColumn: position.column,\n };\n monacoEditor.executeEdits('picker-insert', [{ range, text: insertion }]);\n monacoEditor.focus();\n } else {\n setMarkdownSource(markdownSource + insertion);\n }\n } else {\n const insertion = entry.kind === 'emoji' ? entry.char : `{[${entry.token}]}`;\n setMarkdownSource(markdownSource + insertion);\n }\n closeEmojiPicker();\n },\n [activeView, tiptapEditor, monacoEditor, markdownSource, setMarkdownSource, closeEmojiPicker],\n );\n\n // ── Ctrl+K / Cmd+K → open the link dialog ────────────\n // Mirrors the behaviour of common editors (Word, Google Docs, VS Code's\n // Markdown preview): if the cursor is in a Squisq editor surface, the\n // shortcut routes through the same handler the toolbar Link button uses,\n // which prefills the dialog from the current selection (or the link\n // under the cursor) before opening.\n useEffect(() => {\n const onKeyDown = (e: KeyboardEvent) => {\n if (!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey) return;\n if (e.key.toLowerCase() !== 'k') return;\n const target = e.target as HTMLElement | null;\n if (!target) return;\n // Only intercept when focus is inside one of our editor surfaces.\n const inEditor = !!target.closest(\n '.squisq-wysiwyg-editor, .ProseMirror, .squisq-raw-editor-container, .monaco-editor',\n );\n if (!inEditor) return;\n e.preventDefault();\n e.stopPropagation();\n handleAction('link');\n };\n window.addEventListener('keydown', onKeyDown, true);\n return () => window.removeEventListener('keydown', onKeyDown, true);\n }, [handleAction]);\n\n // ── Link dialog confirm ──────────────────────────────\n const handleLinkConfirm = useCallback(\n (text: string, url: string) => {\n if (!linkDialog) return;\n const trimmedUrl = url.trim();\n const trimmedText = text.trim();\n\n if (linkDialog.target === 'wysiwyg' && tiptapEditor) {\n if (!trimmedUrl) {\n // Empty URL on update = unlink. On insert with no URL, do nothing.\n if (linkDialog.mode === 'update') {\n tiptapEditor.chain().focus().unsetLink().run();\n }\n setLinkDialog(null);\n return;\n }\n const visibleText = trimmedText || trimmedUrl;\n const chain = tiptapEditor.chain().focus();\n // Insert (or replace selection) with text carrying a link mark. When\n // updating an existing link, the selection was extended to the full\n // mark range earlier, so this replaces the entire `[text](url)`.\n chain\n .insertContent({\n type: 'text',\n text: visibleText,\n marks: [{ type: 'link', attrs: { href: trimmedUrl } }],\n })\n .run();\n setLinkDialog(null);\n return;\n }\n\n if (linkDialog.target === 'raw' && monacoEditor) {\n const model = monacoEditor.getModel();\n if (!model) {\n setLinkDialog(null);\n return;\n }\n if (!trimmedUrl && linkDialog.mode === 'update' && linkDialog.rawRange) {\n // Empty URL on update = strip the markdown link, keep the text.\n monacoEditor.executeEdits('toolbar-link-edit', [\n { range: linkDialog.rawRange, text: trimmedText || linkDialog.initialText },\n ]);\n monacoEditor.focus();\n setLinkDialog(null);\n return;\n }\n if (!trimmedUrl) {\n setLinkDialog(null);\n return;\n }\n const visibleText = trimmedText || trimmedUrl;\n const replacement = `[${visibleText}](${trimmedUrl})`;\n const range = linkDialog.rawRange ?? monacoEditor.getSelection();\n if (!range) {\n setLinkDialog(null);\n return;\n }\n monacoEditor.executeEdits('toolbar-link-edit', [{ range, text: replacement }]);\n monacoEditor.focus();\n setLinkDialog(null);\n return;\n }\n\n setLinkDialog(null);\n },\n [linkDialog, tiptapEditor, monacoEditor],\n );\n\n const groups = ['format', 'lists', 'structure', 'insert', 'media'] as const;\n const isWysiwyg = activeView === 'wysiwyg' && tiptapEditor;\n const isPreview = activeView === 'preview';\n\n // ── Progressive heading disclosure ───────────────────\n // H1\\u2013H3 are always visible. H4 appears once the document already\n // contains an H3, H5 once it contains an H4, and H6 once it contains\n // an H5. This keeps the toolbar compact for typical short documents\n // while letting deeply nested documents reach every level.\n const maxHeadingLevelInDoc = useMemo(() => {\n if (!markdownSource) return 0;\n let max = 0;\n let inFence = false;\n for (const rawLine of markdownSource.split('\\n')) {\n const line = rawLine.trimEnd();\n if (/^\\s*```/.test(line)) {\n inFence = !inFence;\n continue;\n }\n if (inFence) continue;\n const m = /^(#{1,6})\\s+\\S/.exec(line);\n if (m && m[1].length > max) max = m[1].length;\n }\n return max;\n }, [markdownSource]);\n // Show H(n+1) when the document already contains H(n), starting from H3.\n const visibleHeadingMax = Math.min(6, Math.max(3, maxHeadingLevelInDoc + 1));\n const isButtonVisible = (id: string): boolean => {\n const m = /^h([1-6])$/.exec(id);\n if (!m) return true;\n return Number(m[1]) <= visibleHeadingMax;\n };\n\n // Detect whether cursor is inside a table (WYSIWYG mode only)\n const isInTable = isWysiwyg ? tiptapEditor.isActive('table') : false;\n\n // Detect current heading template (WYSIWYG mode only)\n const wysiwygTemplate = isWysiwyg\n ? tiptapEditor.isActive('heading')\n ? (tiptapEditor.getAttributes('heading')?.dataTemplate ?? '')\n : null\n : null;\n\n // ── Monaco heading detection (Markdown view) ─────────────────────\n // Watch the Monaco cursor and surface the template picker whenever the\n // cursor is on a heading line. `null` hides the picker; '' shows it\n // with no template selected; any other string is the current template.\n const isRawView = activeView === 'raw';\n const [rawTemplate, setRawTemplate] = useState<string | null>(null);\n const [rawHeadingLine, setRawHeadingLine] = useState<number | null>(null);\n useEffect(() => {\n if (!isRawView || !monacoEditor) {\n setRawTemplate(null);\n setRawHeadingLine(null);\n return;\n }\n const recompute = () => {\n const model = monacoEditor.getModel();\n const pos = monacoEditor.getPosition();\n if (!model || !pos) {\n setRawTemplate(null);\n setRawHeadingLine(null);\n return;\n }\n const line = model.getLineContent(pos.lineNumber);\n const headingMatch = line.match(/^#{1,6}\\s+(.+)$/);\n if (!headingMatch) {\n setRawTemplate(null);\n setRawHeadingLine(null);\n return;\n }\n setRawHeadingLine(pos.lineNumber);\n const annotMatch = headingMatch[1].match(/\\s*\\{\\[([^\\]]+)\\]\\}[\\s\\]}]*$/);\n if (annotMatch) {\n // First whitespace-delimited token is the template name; the rest are params.\n const name = annotMatch[1].trim().split(/\\s+/)[0];\n setRawTemplate(name);\n } else {\n setRawTemplate('');\n }\n };\n recompute();\n const cursorSub = monacoEditor.onDidChangeCursorPosition(recompute);\n const contentSub = monacoEditor.onDidChangeModelContent(recompute);\n return () => {\n cursorSub.dispose();\n contentSub.dispose();\n };\n }, [isRawView, monacoEditor]);\n\n // Track the index of the heading the WYSIWYG cursor is in among all\n // top-level headings. Used to locate the same heading in the markdown\n // source for content-based template recommendations.\n const [wysiwygHeadingIndex, setWysiwygHeadingIndex] = useState<number | null>(null);\n useEffect(() => {\n if (!isWysiwyg || !tiptapEditor) {\n setWysiwygHeadingIndex(null);\n return;\n }\n const recompute = () => {\n if (!tiptapEditor.isActive('heading')) {\n setWysiwygHeadingIndex(null);\n return;\n }\n const cursor = tiptapEditor.state.selection.from;\n let index = -1;\n let count = 0;\n tiptapEditor.state.doc.descendants((node, pos) => {\n if (node.type.name !== 'heading') return;\n if (pos <= cursor && pos + node.nodeSize > cursor) {\n index = count;\n return false;\n }\n count++;\n });\n setWysiwygHeadingIndex(index >= 0 ? index : null);\n };\n recompute();\n tiptapEditor.on('selectionUpdate', recompute);\n tiptapEditor.on('update', recompute);\n return () => {\n tiptapEditor.off('selectionUpdate', recompute);\n tiptapEditor.off('update', recompute);\n };\n }, [isWysiwyg, tiptapEditor]);\n\n const currentTemplate = isWysiwyg ? wysiwygTemplate : isRawView ? rawTemplate : null;\n\n // Compute recommended templates for the active block. Heading slice\n // comes from markdownSource — raw view supplies the cursor line,\n // WYSIWYG supplies the heading index.\n const recommendedTemplates = useMemo(() => {\n if (currentTemplate === null) return undefined;\n let slice = null;\n if (isRawView && rawHeadingLine !== null) {\n slice = findBlockSliceAtLine(markdownSource, rawHeadingLine);\n } else if (isWysiwyg && wysiwygHeadingIndex !== null) {\n slice = findBlockSliceByHeadingIndex(markdownSource, wysiwygHeadingIndex);\n }\n if (slice === null) return undefined;\n const profile = profileBlockContents(slice);\n return recommendTemplatesForBlock(profile, TEMPLATE_NAMES).recommended;\n }, [currentTemplate, isRawView, isWysiwyg, rawHeadingLine, wysiwygHeadingIndex, markdownSource]);\n\n const handleTemplatePick = (value: string) => {\n // Raw (Monaco) — rewrite the heading line's annotation suffix in place.\n if (isRawView && monacoEditor) {\n const model = monacoEditor.getModel();\n const pos = monacoEditor.getPosition();\n if (!model || !pos) return;\n const lineNumber = pos.lineNumber;\n const lineText = model.getLineContent(lineNumber);\n const headingMatch = lineText.match(/^(#{1,6}\\s+)(.+)$/);\n if (!headingMatch) return;\n const prefix = headingMatch[1];\n // Strip any existing trailing annotation\n const bareText = headingMatch[2].replace(/\\s*\\{\\[[^\\]]+\\]\\}[\\s\\]}]*$/, '').trimEnd();\n const newLine = value === '' ? `${prefix}${bareText}` : `${prefix}${bareText} {[${value}]}`;\n monacoEditor.executeEdits('toolbar-template-pick', [\n {\n range: {\n startLineNumber: lineNumber,\n startColumn: 1,\n endLineNumber: lineNumber,\n endColumn: lineText.length + 1,\n },\n text: newLine,\n },\n ]);\n monacoEditor.focus();\n return;\n }\n // WYSIWYG — update the heading node attributes.\n if (!tiptapEditor) return;\n if (value === '') {\n tiptapEditor\n .chain()\n .focus()\n .updateAttributes('heading', { dataTemplate: null, dataTemplateParams: null })\n .run();\n } else {\n tiptapEditor.chain().focus().updateAttributes('heading', { dataTemplate: value }).run();\n }\n };\n\n return (\n <div\n className={`squisq-toolbar ${className || ''}`}\n role=\"toolbar\"\n aria-label=\"Formatting toolbar\"\n >\n {/* Hidden file input for image picker */}\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n style={{ display: 'none' }}\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (file) handleImageFile(file);\n // Reset so the same file can be re-selected\n e.target.value = '';\n }}\n />\n {/* Left slot — before view tabs */}\n {slotLeft}\n {/* View tabs — hidden when only one view is available (e.g. code mode). */}\n {showViewTabs && (\n <div className=\"squisq-toolbar-view-tabs\" role=\"tablist\" aria-label=\"Editor view\">\n {visibleViews.map((view) => (\n <button\n key={view.id}\n role=\"tab\"\n data-view={view.id}\n aria-selected={activeView === view.id}\n className={`squisq-toolbar-view-tab${activeView === view.id ? ' squisq-toolbar-view-tab--active' : ''}`}\n onClick={() => setActiveView(view.id)}\n data-tooltip={`${view.label} (${view.shortcut})`}\n >\n <span\n className=\"squisq-toolbar-view-tab-label squisq-toolbar-view-tab-label--long\"\n data-label={view.label}\n >\n {view.label}\n </span>\n {view.shortLabel && view.shortLabel !== view.label && (\n <span\n className=\"squisq-toolbar-view-tab-label squisq-toolbar-view-tab-label--short\"\n data-label={view.shortLabel}\n >\n {view.shortLabel}\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n {/* Formatting buttons — hidden in preview mode, narrow screens, and code mode */}\n {!isPreview && !isNarrow && !isCodeMode && (\n <div className=\"squisq-toolbar-actions\" ref={actionsRef}>\n {groups.map((group, gi) => (\n <div key={group} className=\"squisq-toolbar-group\">\n {gi > 0 && <div className=\"squisq-toolbar-separator\" />}\n {BUTTONS.filter((b) => b.group === group && isButtonVisible(b.id)).map((btn) => {\n const active =\n btn.id === 'emoji'\n ? emojiPickerAnchor !== null\n : isWysiwyg\n ? isTiptapActive(tiptapEditor, btn.id)\n : false;\n const disabled = btn.id === 'image' && !mediaProvider;\n return (\n <button\n key={btn.id}\n ref={btn.id === 'emoji' ? emojiButtonRef : undefined}\n className={`squisq-toolbar-button${active ? ' squisq-toolbar-button--active' : ''}`}\n data-tooltip={disabled ? 'Insert image (requires media provider)' : btn.title}\n onClick={() => handleAction(btn.id)}\n aria-label={btn.title}\n aria-pressed={active}\n disabled={disabled}\n style={btn.iconStyle}\n >\n {buttonIconSvg(btn.id) ?? btn.icon}\n </button>\n );\n })}\n </div>\n ))}\n\n {/* Template picker — visible when the cursor is in a heading.\n In WYSIWYG, reads from the heading node's `dataTemplate`; in\n Markdown view, parses the `{[...]}` suffix on the cursor's line. */}\n {currentTemplate !== null && (\n <>\n <div className=\"squisq-toolbar-separator\" />\n <div className=\"squisq-toolbar-group squisq-template-picker\">\n <TemplatePicker\n value={currentTemplate}\n onChange={handleTemplatePick}\n recommended={recommendedTemplates}\n />\n </div>\n </>\n )}\n\n {/* Table controls — visible when cursor is in a table (WYSIWYG) */}\n {isInTable && (\n <>\n <div className=\"squisq-toolbar-separator\" />\n <div className=\"squisq-toolbar-group squisq-table-controls\">\n <span className=\"squisq-table-controls-label\">Table:</span>\n <button\n className=\"squisq-toolbar-button\"\n data-tooltip=\"Add column before\"\n onClick={() => tiptapEditor!.chain().focus().addColumnBefore().run()}\n aria-label=\"Add column before\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n >\n <rect x=\"7\" y=\"2\" width=\"8\" height=\"12\" rx=\"1\" />\n <line x1=\"11\" y1=\"2\" x2=\"11\" y2=\"14\" />\n <line x1=\"1\" y1=\"8\" x2=\"4.5\" y2=\"8\" />\n <line x1=\"2.75\" y1=\"6.25\" x2=\"2.75\" y2=\"9.75\" />\n </svg>\n </button>\n <button\n className=\"squisq-toolbar-button\"\n data-tooltip=\"Add column after\"\n onClick={() => tiptapEditor!.chain().focus().addColumnAfter().run()}\n aria-label=\"Add column after\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n >\n <rect x=\"1\" y=\"2\" width=\"8\" height=\"12\" rx=\"1\" />\n <line x1=\"5\" y1=\"2\" x2=\"5\" y2=\"14\" />\n <line x1=\"11.5\" y1=\"8\" x2=\"15\" y2=\"8\" />\n <line x1=\"13.25\" y1=\"6.25\" x2=\"13.25\" y2=\"9.75\" />\n </svg>\n </button>\n <button\n className=\"squisq-toolbar-button\"\n data-tooltip=\"Delete column\"\n onClick={() => tiptapEditor!.chain().focus().deleteColumn().run()}\n aria-label=\"Delete column\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n >\n <rect x=\"4\" y=\"1\" width=\"8\" height=\"14\" rx=\"1\" />\n <line x1=\"6\" y1=\"5.5\" x2=\"10\" y2=\"10.5\" />\n <line x1=\"10\" y1=\"5.5\" x2=\"6\" y2=\"10.5\" />\n </svg>\n </button>\n <button\n className=\"squisq-toolbar-button\"\n data-tooltip=\"Add row above\"\n onClick={() => tiptapEditor!.chain().focus().addRowBefore().run()}\n aria-label=\"Add row above\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n >\n <rect x=\"2\" y=\"6\" width=\"12\" height=\"9\" rx=\"1\" />\n <line x1=\"2\" y1=\"10.5\" x2=\"14\" y2=\"10.5\" />\n <line x1=\"8\" y1=\"1\" x2=\"8\" y2=\"4.5\" />\n <line x1=\"6.25\" y1=\"2.75\" x2=\"9.75\" y2=\"2.75\" />\n </svg>\n </button>\n <button\n className=\"squisq-toolbar-button\"\n data-tooltip=\"Add row below\"\n onClick={() => tiptapEditor!.chain().focus().addRowAfter().run()}\n aria-label=\"Add row below\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n >\n <rect x=\"2\" y=\"1\" width=\"12\" height=\"9\" rx=\"1\" />\n <line x1=\"2\" y1=\"5.5\" x2=\"14\" y2=\"5.5\" />\n <line x1=\"8\" y1=\"11.5\" x2=\"8\" y2=\"15\" />\n <line x1=\"6.25\" y1=\"13.25\" x2=\"9.75\" y2=\"13.25\" />\n </svg>\n </button>\n <button\n className=\"squisq-toolbar-button\"\n data-tooltip=\"Delete row\"\n onClick={() => tiptapEditor!.chain().focus().deleteRow().run()}\n aria-label=\"Delete row\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n >\n <rect x=\"1\" y=\"4\" width=\"14\" height=\"8\" rx=\"1\" />\n <line x1=\"5.5\" y1=\"6\" x2=\"10.5\" y2=\"10\" />\n <line x1=\"10.5\" y1=\"6\" x2=\"5.5\" y2=\"10\" />\n </svg>\n </button>\n <button\n className=\"squisq-toolbar-button squisq-toolbar-button--danger\"\n data-tooltip=\"Delete table\"\n onClick={() => tiptapEditor!.chain().focus().deleteTable().run()}\n aria-label=\"Delete table\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n >\n <rect x=\"1\" y=\"1\" width=\"14\" height=\"14\" rx=\"1\" />\n <line x1=\"1\" y1=\"5.5\" x2=\"15\" y2=\"5.5\" />\n <line x1=\"5.5\" y1=\"1\" x2=\"5.5\" y2=\"15\" />\n <line x1=\"4.5\" y1=\"4.5\" x2=\"11.5\" y2=\"11.5\" strokeWidth=\"2\" />\n <line x1=\"11.5\" y1=\"4.5\" x2=\"4.5\" y2=\"11.5\" strokeWidth=\"2\" />\n </svg>\n </button>\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Overflow menu — outside the overflow:hidden actions container */}\n {!isPreview && !isCodeMode && overflowIndex !== null && (\n <div className=\"squisq-toolbar-overflow\" ref={overflowRef}>\n <button\n className={`squisq-toolbar-button squisq-toolbar-overflow-trigger${showOverflow ? ' squisq-toolbar-button--active' : ''}`}\n data-tooltip=\"More actions\"\n onClick={() => setShowOverflow((v) => !v)}\n aria-label=\"More actions\"\n aria-expanded={showOverflow}\n >\n ···\n </button>\n {showOverflow && (\n <div\n className={`squisq-toolbar-overflow-menu squisq-toolbar-overflow-menu--${overflowPlacement}`}\n >\n {BUTTONS.slice(overflowIndex)\n .filter((b) => isButtonVisible(b.id))\n .map((btn) => {\n const active =\n btn.id === 'emoji'\n ? emojiPickerAnchor !== null\n : isWysiwyg\n ? isTiptapActive(tiptapEditor, btn.id)\n : false;\n const disabled = btn.id === 'image' && !mediaProvider;\n return (\n <button\n key={btn.id}\n ref={btn.id === 'emoji' ? emojiButtonRef : undefined}\n className={`squisq-toolbar-overflow-item${active ? ' squisq-toolbar-overflow-item--active' : ''}`}\n onClick={() => {\n handleAction(btn.id);\n // Keep the overflow open when opening the emoji\n // picker — otherwise its anchor (the overflow\n // item) unmounts and the popover loses its ref.\n if (btn.id !== 'emoji') setShowOverflow(false);\n }}\n disabled={disabled}\n >\n {buttonIconSvg(btn.id) ?? (\n <span className=\"squisq-toolbar-overflow-icon\" style={btn.iconStyle}>\n {btn.icon}\n </span>\n )}\n <span>{btn.title}</span>\n </button>\n );\n })}\n\n {/* Contextual: template picker in overflow */}\n {currentTemplate !== null && (\n <div className=\"squisq-toolbar-overflow-item squisq-toolbar-overflow-template\">\n <span>Template:</span>\n <TemplatePicker\n value={currentTemplate}\n onChange={(v) => {\n handleTemplatePick(v);\n setShowOverflow(false);\n }}\n recommended={recommendedTemplates}\n />\n </div>\n )}\n\n {/* Contextual: table controls in overflow */}\n {isInTable && (\n <>\n <div\n className=\"squisq-toolbar-separator\"\n style={{ margin: '4px 0', width: '100%', height: 1 }}\n />\n {[\n {\n label: 'Add column before',\n action: () => tiptapEditor!.chain().focus().addColumnBefore().run(),\n },\n {\n label: 'Add column after',\n action: () => tiptapEditor!.chain().focus().addColumnAfter().run(),\n },\n {\n label: 'Delete column',\n action: () => tiptapEditor!.chain().focus().deleteColumn().run(),\n },\n {\n label: 'Add row above',\n action: () => tiptapEditor!.chain().focus().addRowBefore().run(),\n },\n {\n label: 'Add row below',\n action: () => tiptapEditor!.chain().focus().addRowAfter().run(),\n },\n {\n label: 'Delete row',\n action: () => tiptapEditor!.chain().focus().deleteRow().run(),\n },\n {\n label: 'Delete table',\n action: () => tiptapEditor!.chain().focus().deleteTable().run(),\n },\n ].map((item) => (\n <button\n key={item.label}\n className={`squisq-toolbar-overflow-item${item.label.startsWith('Delete') ? ' squisq-toolbar-overflow-item--danger' : ''}`}\n onClick={() => {\n item.action();\n setShowOverflow(false);\n }}\n >\n <span>{item.label}</span>\n </button>\n ))}\n </>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* After-actions slot — after formatting controls */}\n {slotAfterActions}\n {/* Spacer — only needed when the actions container (which has flex:1\n and already pushes right-side items to the end) isn't rendered. */}\n {(isPreview || isNarrow || isCodeMode) && <div style={{ flex: 1 }} />}\n {/* Version history — renders only when the host enabled versioning\n and a container is wired up. The component owns its own button\n and popover; we just give it a slot in the toolbar. */}\n {versioning && !isCodeMode && <VersionHistoryPanel />}\n {/* Media recorder — surfaces when the host has a mediaProvider\n and hasn't opted out. RecorderEntry returns null when no\n provider is wired, so this stays a no-op for hosts that\n haven't enabled media at all. */}\n {allowRecording && !isCodeMode && mediaProvider && <RecorderEntry />}\n {!isCodeMode && (\n <button\n type=\"button\"\n className=\"squisq-toolbar-button\"\n onClick={() => setShowDocSettings(true)}\n data-tooltip=\"Document settings\"\n aria-label=\"Document settings\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M3 2.5h7l3 3v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-10a1 1 0 0 1 1-1Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinejoin=\"round\"\n />\n <path d=\"M10 2.5v3h3\" stroke=\"currentColor\" strokeWidth=\"1.3\" strokeLinejoin=\"round\" />\n <path\n d=\"M5 8.5h6M5 11h4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n )}\n {!isCodeMode && <ViewMenuPanel />}\n {/* Files toggle — visible when callback is provided */}\n {onToggleFiles && (\n <button\n className={`squisq-toolbar-button squisq-toolbar-files-toggle${showFiles ? ' squisq-toolbar-button--active' : ''}`}\n onClick={onToggleFiles}\n data-tooltip={showFiles ? 'Hide Files panel' : 'Show Files panel'}\n aria-pressed={showFiles}\n aria-label=\"Toggle Files panel\"\n >\n {PAPERCLIP_ICON}\n </button>\n )}\n {/* Right slot — rightmost end of toolbar */}\n {slotRight}\n\n {/* Document settings (frontmatter) dialog */}\n {showDocSettings && (\n <DocumentSettingsDialog\n markdownSource={markdownSource}\n onSave={(next) => {\n setMarkdownSource(next);\n setShowDocSettings(false);\n }}\n onClose={() => setShowDocSettings(false)}\n />\n )}\n\n {/* Link insert/edit dialog — shared by WYSIWYG and Raw views. */}\n {linkDialog && (\n <LinkDialog\n mode={linkDialog.mode}\n initialText={linkDialog.initialText}\n initialUrl={linkDialog.initialUrl}\n onConfirm={handleLinkConfirm}\n onClose={() => setLinkDialog(null)}\n documentLinkProvider={documentLinkProvider}\n />\n )}\n\n {/* Emoji picker — portaled to the document body so the toolbar's\n overflow:hidden actions row doesn't clip the popover. Position\n is computed from the trigger button's screen rect at open. */}\n {emojiPickerAnchor &&\n createPortal(\n <EmojiPicker\n open\n onSelect={handleEmojiSelect}\n onClose={closeEmojiPicker}\n anchorRef={emojiButtonRef as React.RefObject<HTMLElement>}\n theme={theme === 'dark' ? 'dark' : 'light'}\n style={{\n position: 'fixed',\n top: emojiPickerAnchor.top,\n left: emojiPickerAnchor.left,\n }}\n />,\n document.body,\n )}\n </div>\n );\n}\n","/**\n * VersionHistoryPanel\n *\n * Toolbar-anchored popover that lists prior version snapshots and lets\n * the user revert to one. When a snapshot is selected, a Monaco diff\n * view appears to the left of the list comparing the snapshot (original,\n * left) with the current editor content (modified, right).\n *\n * Wraps the toolbar trigger button + popover surface. Versioning state\n * is read from the EditorContext — render this component anywhere inside\n * a provider that has `allowVersioning` and a `container`.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';\nimport { DiffEditor } from '@monaco-editor/react';\nimport type { Version } from '@bendyline/squisq/versions';\nimport { useEditorContext } from './EditorContext';\nimport { useMonacoLoader } from './useMonacoLoader';\n\ninterface LazyDiffEditorProps {\n original: string;\n modified: string;\n theme: 'vs' | 'vs-dark';\n}\n\nconst lazyLoadingStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '100%',\n height: '100%',\n color: 'var(--squisq-editor-muted-foreground, #6a6258)',\n fontSize: 12,\n};\n\n/**\n * Defers the `<DiffEditor>` mount until the lazy monaco namespace +\n * `loader.config()` are in place. Without the gate, the\n * `@monaco-editor/react` singleton loader would fall back to its CDN\n * default for any consumer that hasn't already mounted `<RawEditor>`.\n *\n * This wrapper is what makes `useMonacoLoader` worth using here —\n * VersionHistoryPanel itself is always present in the toolbar, so\n * subscribing at its level would defeat the lazy-load. The hook only\n * fires when a snapshot is actually selected.\n */\nfunction LazyDiffEditor({ original, modified, theme }: LazyDiffEditorProps) {\n const { ready } = useMonacoLoader();\n if (!ready) {\n return <div style={lazyLoadingStyle}>Loading diff…</div>;\n }\n return (\n <DiffEditor\n original={original}\n modified={modified}\n language=\"markdown\"\n theme={theme}\n options={{\n readOnly: true,\n renderSideBySide: true,\n minimap: { enabled: false },\n scrollBeyondLastLine: false,\n wordWrap: 'on',\n automaticLayout: true,\n fontSize: 12,\n lineNumbers: 'off',\n glyphMargin: false,\n folding: false,\n overviewRulerLanes: 0,\n renderOverviewRuler: false,\n }}\n />\n );\n}\n\ninterface PanelState {\n loading: boolean;\n versions: Version[];\n /** The snapshot currently shown in the diff view, with its content. */\n selected: { version: Version; content: string } | null;\n pendingRevert: Version | null;\n error: string | null;\n /** Stamp captured each time the popover opens — labels the synthetic\n * \"Current\" row so it reads as a moment in time alongside the\n * snapshots. */\n currentStamp: Date;\n /** Cached content of the most recent snapshot, used to detect (and\n * hide) a snapshot that's byte-identical to the current draft so the\n * synthetic Current row alone represents that state. Compared against\n * the live `markdownSource` on every render, so the suppressed row\n * re-appears as soon as the user types. */\n latestSnapshotContent: string | null;\n}\n\nconst initialState: PanelState = {\n loading: false,\n versions: [],\n selected: null,\n pendingRevert: null,\n error: null,\n currentStamp: new Date(),\n latestSnapshotContent: null,\n};\n\nconst dateFormatter = new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n});\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport function VersionHistoryPanel() {\n const { versioning, replaceAll, markdownSource, theme } = useEditorContext();\n const [open, setOpen] = useState(false);\n const [state, setState] = useState<PanelState>(initialState);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const refresh = useCallback(async () => {\n if (!versioning) return;\n setState((s) => ({ ...s, loading: true, error: null }));\n try {\n const versions = await versioning.listVersions();\n // Cache the latest snapshot's content so we can hide it when it\n // matches the live draft (the Current row already represents it).\n const latest = versions[0];\n const latestSnapshotContent = latest ? await versioning.readVersion(latest) : null;\n setState((s) => ({ ...s, loading: false, versions, latestSnapshotContent }));\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to list versions';\n setState((s) => ({ ...s, loading: false, error: message }));\n }\n }, [versioning]);\n\n // Refresh the list whenever the popover opens.\n useEffect(() => {\n if (open) {\n setState((s) => ({ ...s, currentStamp: new Date() }));\n void refresh();\n } else {\n // Reset transient UI when closing so the next open is clean.\n setState((s) => ({ ...s, selected: null, pendingRevert: null }));\n }\n }, [open, refresh]);\n\n // Click-outside to close, mirroring the toolbar overflow menu.\n useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [open]);\n\n const handleSelect = useCallback(\n async (version: Version) => {\n if (!versioning) return;\n // Toggle off if this version is already selected.\n if (state.selected?.version.path === version.path) {\n setState((s) => ({ ...s, selected: null }));\n return;\n }\n const content = await versioning.readVersion(version);\n if (content === null) {\n setState((s) => ({ ...s, error: 'Snapshot is no longer available.' }));\n return;\n }\n setState((s) => ({ ...s, selected: { version, content }, error: null }));\n },\n [versioning, state.selected],\n );\n\n const handleRevertConfirm = useCallback(\n async (version: Version) => {\n if (!versioning) return;\n try {\n const result = await versioning.revertToVersion(version, { snapshotCurrent: true });\n if (!result.reverted) {\n setState((s) => ({ ...s, error: 'Revert failed — snapshot missing.' }));\n return;\n }\n const reverted = await versioning.readVersion(version);\n if (reverted !== null) {\n replaceAll(reverted);\n }\n setState((s) => ({ ...s, pendingRevert: null, selected: null }));\n await refresh();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Revert failed';\n setState((s) => ({ ...s, error: message }));\n }\n },\n [versioning, replaceAll, refresh],\n );\n\n // Hide the most recent snapshot when its content is byte-identical to\n // the live draft — the Current row already represents that state, and\n // the diff against it would be empty anyway.\n const latestMatchesCurrent =\n state.latestSnapshotContent !== null && state.latestSnapshotContent === markdownSource;\n const visibleVersions = useMemo(\n () => (latestMatchesCurrent ? state.versions.slice(1) : state.versions),\n [state.versions, latestMatchesCurrent],\n );\n const currentSize = useMemo(\n () => new TextEncoder().encode(markdownSource).byteLength,\n [markdownSource],\n );\n const hasDiff = state.selected !== null;\n const diffTheme = theme === 'dark' ? 'vs-dark' : 'vs';\n\n if (!versioning) return null;\n\n return (\n <div className=\"squisq-version-history\" ref={containerRef}>\n <button\n type=\"button\"\n className={`squisq-toolbar-button squisq-version-history-trigger${\n open ? ' squisq-toolbar-button--active' : ''\n }`}\n data-tooltip=\"Version history\"\n aria-label=\"Version history\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M2.5 8a5.5 5.5 0 1 0 1.6-3.9\" />\n <polyline points=\"2.5,2.5 2.5,4.5 4.5,4.5\" />\n <polyline points=\"8,4.5 8,8 11,9.5\" />\n </svg>\n </button>\n {open && (\n <div\n className={`squisq-version-history-popover${\n hasDiff ? ' squisq-version-history-popover--with-diff' : ''\n }`}\n role=\"dialog\"\n aria-label=\"Version history\"\n >\n {hasDiff && state.selected && (\n <div className=\"squisq-version-history-diff\">\n <div className=\"squisq-version-history-diff-header\">\n <span className=\"squisq-version-history-diff-label\">\n <strong>Snapshot</strong> {dateFormatter.format(state.selected.version.timestamp)}\n </span>\n <span className=\"squisq-version-history-diff-label\">\n <strong>Current</strong>\n </span>\n </div>\n <div className=\"squisq-version-history-diff-body\">\n <LazyDiffEditor\n original={state.selected.content}\n modified={markdownSource}\n theme={diffTheme}\n />\n </div>\n </div>\n )}\n <div className=\"squisq-version-history-list-pane\">\n <div className=\"squisq-version-history-header\">\n <span className=\"squisq-version-history-title\">Version history</span>\n </div>\n {state.error && <div className=\"squisq-version-history-error\">{state.error}</div>}\n {state.loading ? (\n <div className=\"squisq-version-history-empty\">Loading…</div>\n ) : visibleVersions.length === 0 ? (\n <div className=\"squisq-version-history-empty\">\n No versions yet. Versions are saved automatically as you edit.\n </div>\n ) : (\n <ul className=\"squisq-version-history-list\">\n <li\n className={`squisq-version-history-row squisq-version-history-row--current${\n state.selected === null ? ' squisq-version-history-row--selected' : ''\n }`}\n >\n <button\n type=\"button\"\n className=\"squisq-version-history-row-select\"\n onClick={() => setState((s) => ({ ...s, selected: null }))}\n >\n <span className=\"squisq-version-history-row__time\">\n <strong>Current</strong> &middot; {dateFormatter.format(state.currentStamp)}\n </span>\n <span className=\"squisq-version-history-row__size\">\n {formatBytes(currentSize)}\n </span>\n </button>\n </li>\n {visibleVersions.map((v) => {\n const pending =\n state.pendingRevert !== null && state.pendingRevert.path === v.path;\n const selected = state.selected?.version.path === v.path;\n return (\n <li\n key={v.path}\n className={`squisq-version-history-row${\n selected ? ' squisq-version-history-row--selected' : ''\n }`}\n >\n <button\n type=\"button\"\n className=\"squisq-version-history-row-select\"\n onClick={() => void handleSelect(v)}\n >\n <span className=\"squisq-version-history-row__time\">\n {dateFormatter.format(v.timestamp)}\n </span>\n <span className=\"squisq-version-history-row__size\">\n {formatBytes(v.size)}\n </span>\n </button>\n <span className=\"squisq-version-history-row__actions\">\n <button\n type=\"button\"\n className=\"squisq-version-history-link\"\n onClick={() => setState((s) => ({ ...s, pendingRevert: v }))}\n >\n Revert\n </button>\n </span>\n {pending && (\n <div className=\"squisq-version-history-confirm\">\n <span>\n Revert to this version? Your current draft will be saved as a new\n snapshot first. Reverting will reset your editor undo state.\n </span>\n <span className=\"squisq-version-history-confirm-actions\">\n <button\n type=\"button\"\n className=\"squisq-version-history-link\"\n onClick={() => setState((s) => ({ ...s, pendingRevert: null }))}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"squisq-version-history-link squisq-version-history-link--primary\"\n onClick={() => handleRevertConfirm(v)}\n >\n Revert\n </button>\n </span>\n </div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n","/**\n * useMonacoLoader\n *\n * Idempotently dynamic-imports `monaco-editor` and points the\n * `@monaco-editor/react` singleton loader at the bundled copy. Replaces\n * the historical top-of-module `import * as monaco from 'monaco-editor';\n * loader.config({ monaco })` pattern, which forced every consumer of\n * `@bendyline/squisq-editor-react` — including ones that only import\n * `JsonEditor` or a type — to drag in monaco's ~9MB worth of language\n * services and workers at module evaluation time.\n *\n * Hosts that want the smallest possible bundle can keep aliasing\n * `monaco-editor` to a slim entry as before; the behavior is identical\n * once the dynamic import settles.\n *\n * The promise is cached at module scope so the first subscriber\n * anywhere in the app pays the import cost and every later subscriber\n * reuses the same settled value.\n */\n\nimport { useEffect, useState } from 'react';\nimport { loader } from '@monaco-editor/react';\n\n/** In-flight (or settled) dynamic import shared across all callers. */\nlet monacoPromise: Promise<typeof import('monaco-editor')> | null = null;\n\n/** Settled namespace once the promise resolves — read synchronously by mount-time consumers. */\nlet monacoNamespace: typeof import('monaco-editor') | null = null;\n\nexport interface UseMonacoLoaderResult {\n /** The monaco namespace once loaded, or `null` while the import is in flight. */\n monaco: typeof import('monaco-editor') | null;\n /** Flips to `true` after the import settles. Gate `<Editor>` / `<DiffEditor>` renders on this. */\n ready: boolean;\n}\n\n/**\n * Subscribe to the lazy-loaded monaco namespace. The first caller\n * triggers `import('monaco-editor')` and configures the\n * `@monaco-editor/react` loader; subsequent callers receive the same\n * cached value.\n */\nexport function useMonacoLoader(): UseMonacoLoaderResult {\n const [state, setState] = useState<UseMonacoLoaderResult>(() => ({\n monaco: monacoNamespace,\n ready: monacoNamespace !== null,\n }));\n\n useEffect(() => {\n if (state.ready) return;\n if (!monacoPromise) {\n // Import the explicit ESM entry file rather than the bare\n // package specifier `'monaco-editor'`. The package's\n // `package.json` has no `main` / no `exports` (only `module`),\n // which trips Vite's strict resolver on both static and\n // dynamic imports of the bare name. Pointing at the file\n // directly — the same path monaco's `module` field points at —\n // turns this into a regular file-path resolve that doesn't\n // care about the manifest's entry fields. Works identically\n // in Vite dev / build, vitest's transform pipeline, and any\n // bundler-using downstream consumer.\n monacoPromise = (\n import('monaco-editor/esm/vs/editor/editor.api.js') as unknown as Promise<\n typeof import('monaco-editor')\n >\n ).then((m) => {\n loader.config({ monaco: m });\n monacoNamespace = m;\n return m;\n });\n }\n let cancelled = false;\n void monacoPromise.then((m) => {\n if (cancelled) return;\n setState({ monaco: m, ready: true });\n });\n return () => {\n cancelled = true;\n };\n }, [state.ready]);\n\n return state;\n}\n","/**\n * RecorderEntry — toolbar slot that wires `RecorderPanel` from\n * `@bendyline/squisq-recorder-react` into the editor.\n *\n * Reads `mediaProvider`, `workspaceContainer`, `activeView`,\n * `tiptapEditor`, and the markdown editing helpers from\n * `useEditorContext()`. On a successful save it:\n * - inserts an HTML5 media element at the cursor — `<video>` for\n * camera / screen recordings, `<audio>` for narration / mic\n * recordings — which the markdown renderer turns into an inline\n * `<InlineVideoPlayer>` / `<InlineAudioPlayer>` with native\n * controls;\n * - for narration, also annotates the nearest heading with\n * `{[audio=filename]}` so `resolveAudioMapping()` continues to tie\n * the recording to that block during slideshow playback;\n * - bumps `mediaRevision` so any blob URLs the media bin cached for\n * the previous file list are invalidated.\n *\n * The component returns `null` when no `mediaProvider` is wired —\n * recording without a place to write the captured bytes is a\n * misconfiguration, not a feature.\n */\n\nimport { useCallback } from 'react';\nimport { RecorderPanel } from './recorder/RecorderPanel.js';\nimport type { RecorderSaveResult } from './recorder/RecorderModal.js';\nimport { useEditorContext } from './EditorContext';\n\n/**\n * Insert a narration annotation `{[audio=filename]}` onto the heading\n * line currently above the cursor in the Monaco editor. Pure-text\n * insertion at the line's end keeps the markdown valid and matches the\n * shape `resolveAudioMapping()` reads. Returns true if a heading line\n * was found and updated.\n */\nfunction annotateMonacoHeading(\n editor: NonNullable<ReturnType<typeof useEditorContext>['monacoEditor']>,\n filename: string,\n): boolean {\n const model = editor.getModel();\n if (!model) return false;\n const position = editor.getPosition();\n if (!position) return false;\n // Walk upward from the cursor to find the nearest heading line.\n for (let line = position.lineNumber; line >= 1; line--) {\n const text = model.getLineContent(line);\n if (!/^#{1,6}\\s/.test(text)) continue;\n // Skip if the heading already has an audio annotation — don't\n // stomp the user's existing wiring. Add a separate annotation in\n // that case wouldn't help either (resolveAudioMapping reads only\n // the first audio= entry).\n if (/\\{\\[audio=/.test(text)) return true;\n const trimmed = text.replace(/\\s+$/, '');\n const insertText = ` {[audio=${filename}]}`;\n const column = trimmed.length + 1;\n editor.executeEdits('recorder-annotation', [\n {\n range: {\n startLineNumber: line,\n startColumn: column,\n endLineNumber: line,\n endColumn: column,\n },\n text: insertText,\n },\n ]);\n return true;\n }\n return false;\n}\n\nexport function RecorderEntry() {\n const {\n mediaProvider,\n workspaceContainer,\n activeView,\n monacoEditor,\n tiptapEditor,\n insertAtCursor,\n bumpMediaRevision,\n markdownSource,\n setMarkdownSource,\n } = useEditorContext();\n\n const handleSave = useCallback(\n (result: RecorderSaveResult) => {\n bumpMediaRevision();\n\n if (result.source === 'mic') {\n // Narration — annotate the nearest heading (drives the\n // slideshow narration pipeline at `core/src/doc/audioMapping.ts`)\n // *and* insert an inline `<audio controls>` so the user can\n // audition the recording inside the editor. The two roles are\n // orthogonal: the annotation is metadata for playback timing,\n // the HTML tag is an in-editor preview control.\n if (activeView === 'raw' && monacoEditor) {\n annotateMonacoHeading(monacoEditor, result.filename);\n }\n const audioTag = `<audio src=\"${result.relativePath}\" controls></audio>`;\n if (activeView === 'wysiwyg' && tiptapEditor) {\n tiptapEditor\n .chain()\n .focus()\n .insertContent({\n type: 'audio',\n attrs: { src: result.relativePath, controls: true },\n })\n .run();\n return;\n }\n if (activeView === 'raw' && monacoEditor) {\n // The annotation went onto the heading line; drop the player\n // on a fresh line at the cursor.\n insertAtCursor(`\\n\\n${audioTag}\\n`);\n return;\n }\n setMarkdownSource(markdownSource ? `${markdownSource}\\n\\n${audioTag}` : audioTag);\n return;\n }\n\n // Camera / screen / screen+mic — inline video player. We pin\n // width=480 so the editor preview doesn't blow up to natural\n // resolution on big monitors; the height is intrinsic, so the\n // aspect ratio is preserved regardless of source dimensions.\n const videoTag = `<video src=\"${result.relativePath}\" controls width=\"480\"></video>`;\n if (activeView === 'wysiwyg' && tiptapEditor) {\n tiptapEditor\n .chain()\n .focus()\n .insertContent({\n type: 'video',\n attrs: { src: result.relativePath, controls: true, width: 480 },\n })\n .run();\n return;\n }\n if (activeView === 'raw' && monacoEditor) {\n insertAtCursor(videoTag);\n return;\n }\n setMarkdownSource(markdownSource ? `${markdownSource}\\n\\n${videoTag}` : videoTag);\n },\n [\n activeView,\n monacoEditor,\n tiptapEditor,\n insertAtCursor,\n bumpMediaRevision,\n markdownSource,\n setMarkdownSource,\n ],\n );\n\n if (!mediaProvider) return null;\n\n return (\n <RecorderPanel\n mediaProvider={mediaProvider}\n container={workspaceContainer}\n onSave={handleSave}\n className=\"squisq-toolbar-button\"\n />\n );\n}\n","/**\n * RecorderPanel — toolbar-anchored trigger that opens the\n * {@link RecorderModal} in a portal. Shaped to slot into an editor\n * toolbar alongside other panels (e.g. `VersionHistoryPanel`); ships a\n * compact mic/record icon and no label by default.\n *\n * For a button that owns its own visual label, use {@link RecorderButton}\n * instead.\n */\n\nimport { useCallback, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { MediaProvider } from '@bendyline/squisq/schemas';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { RecorderModal, type RecorderSaveResult } from './RecorderModal.js';\nimport type { RecorderSource } from './hooks/useMediaRecorder.js';\n\nexport interface RecorderPanelProps {\n mediaProvider: MediaProvider;\n container?: ContentContainer | null;\n initialMode?: RecorderSource;\n onSave?: (result: RecorderSaveResult) => void;\n /** ARIA / tooltip label. Defaults to `'Record media'`. */\n tooltip?: string;\n /** Optional className for the trigger button. */\n className?: string;\n}\n\n/**\n * Inline 16×16 SVG mic icon — currentColor-driven so it inherits the\n * toolbar's icon color regardless of theme.\n */\nfunction MicIcon() {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect x={5.5} y={2} width={5} height={8} rx={2.5} />\n <path d=\"M3.5 7.5v1a4.5 4.5 0 0 0 9 0v-1\" />\n <line x1={8} y1={13} x2={8} y2={15} />\n <line x1={5.5} y1={15} x2={10.5} y2={15} />\n </svg>\n );\n}\n\nexport function RecorderPanel({\n mediaProvider,\n container = null,\n initialMode = 'mic',\n onSave,\n tooltip = 'Record media',\n className,\n}: RecorderPanelProps) {\n const [open, setOpen] = useState(false);\n const handleClose = useCallback(() => setOpen(false), []);\n\n return (\n <>\n <button\n type=\"button\"\n className={className}\n data-tooltip={tooltip}\n aria-label={tooltip}\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n >\n <MicIcon />\n </button>\n {open &&\n typeof document !== 'undefined' &&\n createPortal(\n <RecorderModal\n mediaProvider={mediaProvider}\n container={container}\n initialMode={initialMode}\n onClose={handleClose}\n onSave={(result) => {\n onSave?.(result);\n }}\n />,\n document.body,\n )}\n </>\n );\n}\n","/**\n * RecorderModal — configure-and-capture dialog for browser-based audio,\n * camera, and screen recording.\n *\n * States: configure (pick mode + optional script) → previewing (acquired\n * stream, not yet recording) → recording → review (blob in hand) → saved\n * | error. The user can cancel from any state.\n *\n * Persists the captured `Blob` into the supplied `MediaProvider` and,\n * for narration mode, writes a `.timing.json` sidecar so\n * `resolveAudioMapping()` in `@bendyline/squisq` picks it up at the next\n * doc parse.\n *\n * Visual conventions match `VideoExportModal` from `@bendyline/squisq-\n * video-react` (cream / gold palette, inline styles, no external CSS).\n */\n\nimport { useCallback, useEffect, useRef, useState, type CSSProperties } from 'react';\nimport type { MediaProvider } from '@bendyline/squisq/schemas';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { useMediaRecorder, type RecorderSource } from './hooks/useMediaRecorder.js';\nimport { useStreamPreview } from './hooks/useStreamPreview.js';\nimport { buildFilename } from './formats.js';\nimport { buildTimingJson, encodeTimingJson, timingPathFor } from './timingJson.js';\n\n// ── Types ──────────────────────────────────────────────────────────\n\nexport interface RecorderModalProps {\n /** Required — recordings are written here. */\n mediaProvider: MediaProvider;\n /**\n * Optional — when provided, narration-mode recordings drop a\n * `.timing.json` sidecar at the matching container path so\n * `resolveAudioMapping()` can auto-link them. Without it, only the\n * raw recording is saved.\n */\n container?: ContentContainer | null;\n /** Initial capture source. Defaults to `'mic'` (narration). */\n initialMode?: RecorderSource;\n /** Called after the modal is dismissed (save or cancel). */\n onClose: () => void;\n /**\n * Fired after a successful save. Hosts typically use this to insert a\n * markdown reference at the cursor — see {@link RecorderSaveResult}\n * for the fields a host needs to build that reference.\n */\n onSave?: (result: RecorderSaveResult) => void;\n}\n\n/** Payload handed to {@link RecorderModalProps.onSave} on a successful save. */\nexport interface RecorderSaveResult {\n /** Path returned by `mediaProvider.addMedia()` — what the doc should reference. */\n relativePath: string;\n /** Filename the modal chose (e.g. `narration-20260516-091200.webm`). */\n filename: string;\n /** Capture source the user picked. */\n source: RecorderSource;\n /** MIME type of the saved blob. */\n mimeType: string;\n /** Recording length in seconds. */\n duration: number;\n /** Whether a narration sidecar was written. Always `false` for video sources. */\n hasTimingSidecar: boolean;\n /** Script text the user typed (narration only). */\n sourceText?: string;\n}\n\n// ── Styles ─────────────────────────────────────────────────────────\n\nconst overlayStyle: CSSProperties = {\n position: 'fixed',\n inset: 0,\n background: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10000,\n};\n\nconst modalStyle: CSSProperties = {\n background: '#FFFDF7',\n border: '1px solid #c9b98a',\n borderRadius: 0,\n padding: '24px 28px',\n width: 'min(560px, calc(100vw - 48px))',\n maxHeight: 'calc(100vh - 48px)',\n overflowY: 'auto',\n boxShadow: '0 8px 32px rgba(0,0,0,0.18)',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n color: '#4a3c1f',\n};\n\nconst titleStyle: CSSProperties = {\n margin: '0 0 16px 0',\n fontSize: 18,\n fontWeight: 600,\n color: '#2d2310',\n};\n\nconst labelStyle: CSSProperties = {\n display: 'block',\n fontSize: 13,\n fontWeight: 500,\n marginBottom: 4,\n color: '#5a4a2a',\n};\n\nconst inputStyle: CSSProperties = {\n width: '100%',\n padding: '6px 8px',\n fontSize: 13,\n fontFamily: 'inherit',\n border: '1px solid #c9b98a',\n borderRadius: 0,\n background: '#fff',\n color: '#4a3c1f',\n marginBottom: 12,\n boxSizing: 'border-box',\n};\n\nconst textareaStyle: CSSProperties = {\n ...inputStyle,\n resize: 'vertical',\n minHeight: 72,\n};\n\nconst btnPrimary: CSSProperties = {\n padding: '8px 20px',\n fontSize: 14,\n fontFamily: 'inherit',\n fontWeight: 500,\n cursor: 'pointer',\n background: '#8B6914',\n color: '#fff',\n border: '1px solid #7a5c10',\n borderRadius: 0,\n};\n\nconst btnSecondary: CSSProperties = {\n padding: '8px 20px',\n fontSize: 14,\n fontFamily: 'inherit',\n fontWeight: 500,\n cursor: 'pointer',\n background: '#E8DFC6',\n color: '#4a3c1f',\n border: '1px solid #c9b98a',\n borderRadius: 0,\n};\n\nconst btnDanger: CSSProperties = {\n ...btnPrimary,\n background: '#B33A3A',\n borderColor: '#902929',\n};\n\nconst tabRowStyle: CSSProperties = {\n display: 'flex',\n gap: 4,\n marginBottom: 16,\n borderBottom: '1px solid #c9b98a',\n};\n\nconst tabBase: CSSProperties = {\n padding: '6px 12px',\n fontSize: 13,\n fontFamily: 'inherit',\n cursor: 'pointer',\n background: 'transparent',\n color: '#5a4a2a',\n border: 'none',\n borderBottom: '2px solid transparent',\n marginBottom: -1,\n};\n\nconst tabActive: CSSProperties = {\n ...tabBase,\n color: '#2d2310',\n fontWeight: 600,\n // Use the `borderBottom` shorthand (not `borderBottomColor` longhand)\n // so React's style diff cleanly resets the underline when this tab\n // goes inactive — mixing shorthand + longhand can leave the old\n // color stuck on a previously-active tab between renders.\n borderBottom: '2px solid #8B6914',\n};\n\nconst previewBoxStyle: CSSProperties = {\n width: '100%',\n background: '#000',\n borderRadius: 0,\n marginBottom: 12,\n overflow: 'hidden',\n aspectRatio: '16 / 9',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#888',\n fontSize: 13,\n};\n\nconst audioMeterStyle: CSSProperties = {\n width: '100%',\n height: 56,\n background: '#F2EBD9',\n border: '1px solid #c9b98a',\n marginBottom: 12,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#5a4a2a',\n fontSize: 13,\n fontVariantNumeric: 'tabular-nums',\n};\n\nconst errorStyle: CSSProperties = {\n background: '#FCEEEE',\n border: '1px solid #D88A8A',\n color: '#8C2A2A',\n padding: '8px 10px',\n fontSize: 13,\n marginBottom: 12,\n};\n\nconst buttonRowStyle: CSSProperties = {\n display: 'flex',\n gap: 8,\n justifyContent: 'flex-end',\n marginTop: 8,\n};\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction formatDurationMs(ms: number): string {\n const totalSec = Math.floor(ms / 1000);\n const m = Math.floor(totalSec / 60);\n const s = totalSec % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nconst TABS: Array<{ id: RecorderSource; label: string; description: string }> = [\n {\n id: 'mic',\n label: 'Narration',\n description: 'Voice-only audio. Pairs with a written script for auto-mapping to blocks.',\n },\n { id: 'camera', label: 'Camera', description: 'Camera + microphone. Saved as a video clip.' },\n { id: 'screen', label: 'Screen', description: 'Screen capture. System audio when available.' },\n { id: 'screen+mic', label: 'Screen + Mic', description: 'Screen with your microphone mixed in.' },\n];\n\n// ── Component ──────────────────────────────────────────────────────\n\nexport function RecorderModal({\n mediaProvider,\n container = null,\n initialMode = 'mic',\n onClose,\n onSave,\n}: RecorderModalProps) {\n const [source, setSource] = useState<RecorderSource>(initialMode);\n const [sourceText, setSourceText] = useState('');\n const [basename, setBasename] = useState('');\n const [includeSystemAudio, setIncludeSystemAudio] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [playbackUrl, setPlaybackUrl] = useState<string | null>(null);\n\n const previewRef = useRef<HTMLVideoElement | null>(null);\n\n const recorder = useMediaRecorder({\n source,\n systemAudio: source === 'screen' || source === 'screen+mic' ? includeSystemAudio : false,\n });\n\n useStreamPreview(previewRef, recorder.state === 'stopped' ? null : recorder.stream);\n\n // Generate (and later revoke) a blob URL for the recorded clip so the\n // playback element has something to point at. The dependency on the\n // blob identity means a new URL is created every time a fresh\n // recording lands, and the cleanup callback revokes the previous one.\n useEffect(() => {\n if (!recorder.blob) {\n setPlaybackUrl(null);\n return;\n }\n const url = URL.createObjectURL(recorder.blob);\n setPlaybackUrl(url);\n return () => {\n URL.revokeObjectURL(url);\n };\n }, [recorder.blob]);\n\n // Switching capture source mid-session: tear down whatever stream/\n // recorder we had so the new mode acquires a fresh one. The hook\n // already handles its own internal teardown on unmount; cancel()\n // here covers in-place source changes.\n const previousSourceRef = useRef(source);\n useEffect(() => {\n if (previousSourceRef.current !== source) {\n previousSourceRef.current = source;\n recorder.cancel();\n }\n }, [source, recorder]);\n\n // Make sure tearing down the modal always releases the camera /\n // screen-capture indicator. The hook's own unmount effect handles\n // this, but we also kill the stream eagerly on close so a slow\n // unmount doesn't leave the indicator lit between renders.\n const handleClose = useCallback(() => {\n recorder.cancel();\n onClose();\n }, [recorder, onClose]);\n\n const handleRequest = useCallback(async () => {\n setSaveError(null);\n try {\n await recorder.request();\n } catch {\n // Already surfaced via recorder.error.\n }\n }, [recorder]);\n\n const handleStart = useCallback(() => {\n setSaveError(null);\n recorder.start();\n }, [recorder]);\n\n const handleStop = useCallback(async () => {\n setSaveError(null);\n await recorder.stop();\n }, [recorder]);\n\n const handleSave = useCallback(async () => {\n if (!recorder.blob || !recorder.mimeType || !recorder.extension || !recorder.directory) {\n setSaveError('Nothing to save yet — record something first.');\n return;\n }\n setIsSaving(true);\n setSaveError(null);\n try {\n const filename = buildFilename(\n source === 'mic' ? 'audio' : 'video',\n recorder.extension,\n basename,\n );\n const relativeName = `${recorder.directory}/${filename}`;\n const relativePath = await mediaProvider.addMedia(\n relativeName,\n recorder.blob,\n recorder.mimeType,\n );\n\n let hasTimingSidecar = false;\n if (source === 'mic') {\n const timing = buildTimingJson(sourceText, recorder.durationMs / 1000);\n const encoded = encodeTimingJson(timing);\n const sidecarPath = timingPathFor(relativePath);\n // Prefer direct container write so the sidecar lands at the\n // exact path the audio-mapping pipeline expects. Fall back to\n // addMedia(), which may rename — log if so.\n if (container) {\n await container.writeFile(sidecarPath, encoded, 'application/json');\n hasTimingSidecar = true;\n } else {\n const written = await mediaProvider.addMedia(sidecarPath, encoded, 'application/json');\n hasTimingSidecar = written === sidecarPath;\n if (!hasTimingSidecar) {\n console.warn(\n `[squisq-recorder] timing.json was saved as \"${written}\" instead of \"${sidecarPath}\" — auto-mapping may not pick it up.`,\n );\n }\n }\n }\n\n const result: RecorderSaveResult = {\n relativePath,\n filename,\n source,\n mimeType: recorder.mimeType,\n duration: recorder.durationMs / 1000,\n hasTimingSidecar,\n };\n if (source === 'mic') {\n result.sourceText = sourceText;\n }\n onSave?.(result);\n handleClose();\n } catch (err: unknown) {\n setSaveError(err instanceof Error ? err.message : 'Failed to save recording');\n } finally {\n setIsSaving(false);\n }\n }, [recorder, source, basename, sourceText, mediaProvider, container, onSave, handleClose]);\n\n const handleDiscard = useCallback(() => {\n recorder.reset();\n }, [recorder]);\n\n const isAudioOnly = source === 'mic';\n const showPreview = recorder.state !== 'idle' && recorder.state !== 'error';\n const canRecord = recorder.state === 'ready';\n const canStop = recorder.state === 'recording';\n const canSave = recorder.state === 'stopped' && recorder.blob !== null;\n const isBusy = recorder.state === 'requesting' || recorder.state === 'stopping' || isSaving;\n\n const activeTabDescription = TABS.find((t) => t.id === source)?.description;\n\n return (\n <div style={overlayStyle} role=\"dialog\" aria-modal=\"true\" aria-label=\"Record media\">\n <div style={modalStyle} onClick={(e) => e.stopPropagation()}>\n <h2 style={titleStyle}>Record media</h2>\n\n <div style={tabRowStyle} role=\"tablist\">\n {TABS.map((tab) => {\n const active = tab.id === source;\n return (\n <button\n key={tab.id}\n role=\"tab\"\n aria-selected={active}\n type=\"button\"\n style={active ? tabActive : tabBase}\n onClick={() => setSource(tab.id)}\n disabled={recorder.state === 'recording' || recorder.state === 'requesting'}\n >\n {tab.label}\n </button>\n );\n })}\n </div>\n\n {activeTabDescription && (\n <p style={{ margin: '0 0 12px 0', fontSize: 12, color: '#5a4a2a' }}>\n {activeTabDescription}\n </p>\n )}\n\n {recorder.error && <div style={errorStyle}>{recorder.error.message}</div>}\n {saveError && <div style={errorStyle}>{saveError}</div>}\n\n {/* Preview surface. Three modes:\n - Pre-acquisition (idle / error): a static prompt.\n - Live (ready / recording / requesting / stopping): the stream\n piped into a muted <video>, or a recording meter for mic.\n - Playback (stopped): the captured blob bound to a <video>/<audio>\n with native controls so the user can audition before saving.\n */}\n {!showPreview && (\n <div style={previewBoxStyle}>\n <span>Click Start Preview to start a recording.</span>\n </div>\n )}\n {showPreview && recorder.state !== 'stopped' && !isAudioOnly && (\n <div style={previewBoxStyle}>\n <video\n ref={previewRef}\n autoPlay\n muted\n playsInline\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n />\n </div>\n )}\n {showPreview && recorder.state !== 'stopped' && isAudioOnly && (\n <div style={audioMeterStyle}>\n {recorder.state === 'recording' ? (\n <>● Recording {formatDurationMs(recorder.durationMs)}</>\n ) : (\n <>Microphone ready</>\n )}\n </div>\n )}\n {recorder.state === 'stopped' && playbackUrl && !isAudioOnly && (\n <div style={previewBoxStyle}>\n <video\n src={playbackUrl}\n controls\n playsInline\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n />\n </div>\n )}\n {recorder.state === 'stopped' && playbackUrl && isAudioOnly && (\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...audioMeterStyle, marginBottom: 8 }}>\n ✓ Recorded {formatDurationMs(recorder.durationMs)}\n </div>\n <audio src={playbackUrl} controls style={{ width: '100%' }} />\n </div>\n )}\n\n {/* Mode-specific fields */}\n {source === 'mic' && (\n <>\n <label style={labelStyle} htmlFor=\"recorder-source-text\">\n Script (used to auto-match this narration to a block)\n </label>\n <textarea\n id=\"recorder-source-text\"\n style={textareaStyle}\n placeholder=\"Type the text you're going to read aloud.\"\n value={sourceText}\n onChange={(e) => setSourceText(e.target.value)}\n disabled={recorder.state === 'recording'}\n />\n </>\n )}\n {(source === 'screen' || source === 'screen+mic') && (\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n marginBottom: 12,\n fontSize: 13,\n }}\n >\n <input\n type=\"checkbox\"\n checked={includeSystemAudio}\n onChange={(e) => setIncludeSystemAudio(e.target.checked)}\n disabled={recorder.state === 'recording' || recorder.state === 'requesting'}\n />\n Include system audio (Chrome only)\n </label>\n )}\n\n <label style={labelStyle} htmlFor=\"recorder-basename\">\n Filename (optional)\n </label>\n <input\n id=\"recorder-basename\"\n type=\"text\"\n style={inputStyle}\n placeholder={source === 'mic' ? 'narration' : 'recording'}\n value={basename}\n onChange={(e) => setBasename(e.target.value)}\n disabled={recorder.state === 'recording'}\n />\n\n {/* Live duration during recording */}\n {recorder.state === 'recording' && !isAudioOnly && (\n <div\n style={{\n fontSize: 13,\n fontVariantNumeric: 'tabular-nums',\n marginBottom: 12,\n color: '#8B6914',\n fontWeight: 600,\n }}\n >\n ● Recording {formatDurationMs(recorder.durationMs)}\n </div>\n )}\n\n {/* Action buttons. Layout depends on state. */}\n <div style={buttonRowStyle}>\n <button type=\"button\" style={btnSecondary} onClick={handleClose} disabled={isBusy}>\n Close\n </button>\n\n {(recorder.state === 'idle' ||\n recorder.state === 'error' ||\n recorder.state === 'requesting') && (\n <button type=\"button\" style={btnPrimary} onClick={handleRequest} disabled={isBusy}>\n {recorder.state === 'requesting' ? 'Requesting…' : 'Start preview'}\n </button>\n )}\n\n {canRecord && (\n <button type=\"button\" style={btnPrimary} onClick={handleStart} disabled={isBusy}>\n Record\n </button>\n )}\n\n {canStop && (\n <button type=\"button\" style={btnDanger} onClick={handleStop} disabled={isBusy}>\n Stop\n </button>\n )}\n\n {canSave && (\n <>\n <button type=\"button\" style={btnSecondary} onClick={handleDiscard} disabled={isBusy}>\n Discard & re-record\n </button>\n <button type=\"button\" style={btnPrimary} onClick={handleSave} disabled={isBusy}>\n {isSaving ? 'Saving…' : 'Save to document'}\n </button>\n </>\n )}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * useMediaRecorder\n *\n * React wrapper around `MediaRecorder` that handles stream acquisition,\n * the recorder lifecycle, and produces a single `Blob` on stop. Selects\n * a browser-supported MIME type via {@link resolveFormat}.\n *\n * Mirrors the shape of `useVideoExport` in `@bendyline/squisq-video-react`\n * (request → start → stop → blob), inverted for capture rather than\n * export.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n resolveFormat,\n supportsMediaRecorder,\n type CaptureKind,\n type ResolvedFormat,\n} from '../formats.js';\nimport { requestMicStream } from '../sources/micStream.js';\nimport { requestCameraStream } from '../sources/cameraStream.js';\nimport { requestScreenStream, type ScreenStreamHandle } from '../sources/screenStream.js';\n\n/** Which capture source to use. `screen+mic` mixes the microphone into the screen stream. */\nexport type RecorderSource = 'mic' | 'camera' | 'screen' | 'screen+mic';\n\n/** Discriminated state describing what the recorder is currently doing. */\nexport type RecorderState =\n | 'idle'\n | 'requesting'\n | 'ready'\n | 'recording'\n | 'stopping'\n | 'stopped'\n | 'error';\n\nexport interface UseMediaRecorderOptions {\n /** Which capture pipeline to use. */\n source: RecorderSource;\n /**\n * Preferred MIME type override. When the browser supports it, this\n * wins over the default candidate list. When unset (or unsupported),\n * the hook probes a built-in priority list.\n */\n mimeType?: string;\n /** Video track constraints for camera / screen sources. */\n videoConstraints?: MediaTrackConstraints | boolean;\n /** Audio track constraints for mic / camera / screen+mic sources. */\n audioConstraints?: MediaTrackConstraints | boolean;\n /**\n * Bits-per-second hint passed to `MediaRecorder`. Most browsers cap to\n * reasonable defaults internally; leaving this undefined is usually\n * fine.\n */\n bitsPerSecond?: number;\n /**\n * Whether to attempt to capture system audio when `source === 'screen'`\n * or `'screen+mic'`. Browser support is limited (desktop Chromium\n * only); when unsupported the resulting stream simply omits it.\n */\n systemAudio?: boolean;\n}\n\nexport interface UseMediaRecorderResult {\n /** Current recorder state. */\n state: RecorderState;\n /** Live `MediaStream` after `request()` succeeds; useful for preview. */\n stream: MediaStream | null;\n /** Final `Blob` after `stop()` resolves, or `null` while recording. */\n blob: Blob | null;\n /** MIME type the recorder actually used (after `request()`). */\n mimeType: string | null;\n /** File extension matching `mimeType` (e.g. `.webm`). */\n extension: string | null;\n /** Suggested container directory (`'audio'` for mic, `'video'` for camera/screen). */\n directory: 'audio' | 'video' | null;\n /** Milliseconds elapsed since `start()` was called. Updates ~10× per second while recording. */\n durationMs: number;\n /** Most recent error, if any. */\n error: Error | null;\n /**\n * Acquire the stream and prepare a `MediaRecorder`. After this resolves\n * the hook is in `'ready'` state and a `<video>`/`<audio>` element can\n * preview `stream`. Call `start()` to begin recording.\n */\n request: () => Promise<void>;\n /** Start recording. Must be called from `'ready'`. */\n start: () => void;\n /**\n * Stop recording and resolve with the resulting `Blob`. Safe to call\n * from `'recording'`; a no-op from any other state (resolves with the\n * existing `blob`, or `null`).\n */\n stop: () => Promise<Blob | null>;\n /**\n * Tear everything down — stops the recorder if running, releases all\n * tracks, disposes the AudioContext mixer (if any), and returns to\n * `'idle'`. Always safe to call.\n */\n cancel: () => void;\n /** Reset state without releasing the stream. Useful for re-recording. */\n reset: () => void;\n}\n\n/**\n * Acquire the right stream for the chosen source. Returns the stream\n * plus an optional `dispose` callback for sources that own auxiliary\n * resources (e.g. the screen+mic AudioContext mixer).\n */\nasync function acquireStream(\n opts: UseMediaRecorderOptions,\n): Promise<{ stream: MediaStream; dispose: () => void }> {\n switch (opts.source) {\n case 'mic': {\n const audio = typeof opts.audioConstraints === 'object' ? opts.audioConstraints : undefined;\n const stream = await requestMicStream(audio);\n return { stream, dispose: () => {} };\n }\n case 'camera': {\n const stream = await requestCameraStream({\n video: opts.videoConstraints ?? true,\n audio: opts.audioConstraints ?? true,\n });\n return { stream, dispose: () => {} };\n }\n case 'screen':\n case 'screen+mic': {\n const handle: ScreenStreamHandle = await requestScreenStream({\n video: opts.videoConstraints ?? true,\n systemAudio: opts.systemAudio ?? false,\n includeMicrophone: opts.source === 'screen+mic',\n microphoneConstraints:\n typeof opts.audioConstraints === 'object' ? opts.audioConstraints : undefined,\n });\n return { stream: handle.stream, dispose: handle.dispose };\n }\n }\n}\n\n/** Whether the chosen source records video (vs. audio-only). */\nfunction captureKindFor(source: RecorderSource): CaptureKind {\n return source === 'mic' ? 'audio' : 'video';\n}\n\n/**\n * Returns the kind of capture that the given source produces. Exposed\n * separately from {@link useMediaRecorder} so non-React callers\n * (e.g. headless tests) can resolve a format up front.\n */\nexport function getCaptureKind(source: RecorderSource): CaptureKind {\n return captureKindFor(source);\n}\n\nexport function useMediaRecorder(options: UseMediaRecorderOptions): UseMediaRecorderResult {\n const [state, setState] = useState<RecorderState>('idle');\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [blob, setBlob] = useState<Blob | null>(null);\n const [format, setFormat] = useState<ResolvedFormat | null>(null);\n const [durationMs, setDurationMs] = useState(0);\n const [error, setError] = useState<Error | null>(null);\n\n const recorderRef = useRef<MediaRecorder | null>(null);\n const chunksRef = useRef<Blob[]>([]);\n const disposeStreamRef = useRef<(() => void) | null>(null);\n const startTimestampRef = useRef<number | null>(null);\n const tickerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const stopResolversRef = useRef<Array<(blob: Blob | null) => void>>([]);\n\n // Stable copy of options for callbacks that read them late. Re-evaluated\n // each render, but each callback closes over the ref so we don't have\n // to recreate them on every options change.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const clearTicker = useCallback(() => {\n if (tickerRef.current !== null) {\n clearInterval(tickerRef.current);\n tickerRef.current = null;\n }\n }, []);\n\n const releaseStream = useCallback(() => {\n const s = recorderRef.current?.stream;\n if (s) {\n s.getTracks().forEach((t) => t.stop());\n }\n // Also stop whatever we last handed to setStream — it may differ\n // from recorderRef.current.stream when stream/recorder lifecycles\n // diverged (e.g. cancel before start).\n setStream((current) => {\n current?.getTracks().forEach((t) => t.stop());\n return null;\n });\n disposeStreamRef.current?.();\n disposeStreamRef.current = null;\n }, []);\n\n const reset = useCallback(() => {\n setBlob(null);\n setDurationMs(0);\n setError(null);\n chunksRef.current = [];\n startTimestampRef.current = null;\n clearTicker();\n // If a stream is still live from a prior `request()`, hop back to\n // `'ready'` so the UI can offer \"record again\" without the caller\n // having to re-acquire permissions. Otherwise drop to `'idle'`.\n const rec = recorderRef.current;\n if (rec && rec.state === 'inactive' && rec.stream.active) {\n setState('ready');\n } else {\n setState('idle');\n }\n }, [clearTicker]);\n\n const cancel = useCallback(() => {\n const rec = recorderRef.current;\n if (rec && rec.state !== 'inactive') {\n try {\n rec.stop();\n } catch {\n // Ignore — we're tearing down anyway.\n }\n }\n recorderRef.current = null;\n releaseStream();\n clearTicker();\n chunksRef.current = [];\n startTimestampRef.current = null;\n // Any in-flight stop() promises won't get a blob.\n stopResolversRef.current.splice(0).forEach((resolve) => resolve(null));\n setBlob(null);\n setDurationMs(0);\n setError(null);\n setState('idle');\n }, [clearTicker, releaseStream]);\n\n const request = useCallback(async () => {\n if (!supportsMediaRecorder()) {\n const err = new Error('MediaRecorder is not supported in this environment.');\n setError(err);\n setState('error');\n throw err;\n }\n if (state === 'recording' || state === 'stopping') {\n // Don't start a parallel acquisition while one is in flight.\n return;\n }\n setError(null);\n setState('requesting');\n try {\n const { stream: nextStream, dispose } = await acquireStream(optionsRef.current);\n const resolved = resolveFormat(\n captureKindFor(optionsRef.current.source),\n optionsRef.current.mimeType,\n );\n const recorderOptions: MediaRecorderOptions = {};\n if (resolved.mimeType) recorderOptions.mimeType = resolved.mimeType;\n if (optionsRef.current.bitsPerSecond) {\n recorderOptions.bitsPerSecond = optionsRef.current.bitsPerSecond;\n }\n const recorder = new MediaRecorder(nextStream, recorderOptions);\n\n recorder.ondataavailable = (e) => {\n if (e.data && e.data.size > 0) chunksRef.current.push(e.data);\n };\n recorder.onstop = () => {\n // The recorded MIME type is authoritative once data is in hand —\n // some browsers down-negotiate the format (e.g. drop codec hint).\n const recordedType = recorder.mimeType || resolved.mimeType || 'application/octet-stream';\n const finalBlob = new Blob(chunksRef.current, { type: recordedType });\n chunksRef.current = [];\n setBlob(finalBlob);\n setState('stopped');\n clearTicker();\n stopResolversRef.current.splice(0).forEach((resolve) => resolve(finalBlob));\n };\n recorder.onerror = (event) => {\n const detail = (event as unknown as { error?: DOMException }).error;\n const err = detail instanceof Error ? detail : new Error('Recorder error');\n setError(err);\n setState('error');\n clearTicker();\n stopResolversRef.current.splice(0).forEach((resolve) => resolve(null));\n };\n\n recorderRef.current = recorder;\n disposeStreamRef.current = dispose;\n setStream(nextStream);\n setFormat(resolved);\n setBlob(null);\n setDurationMs(0);\n setState('ready');\n } catch (err: unknown) {\n const normalized = err instanceof Error ? err : new Error('Stream acquisition failed');\n setError(normalized);\n setState('error');\n throw normalized;\n }\n }, [state, clearTicker]);\n\n const start = useCallback(() => {\n const rec = recorderRef.current;\n if (!rec) {\n const err = new Error('Recorder is not ready. Call request() first.');\n setError(err);\n setState('error');\n return;\n }\n if (rec.state === 'recording') return;\n chunksRef.current = [];\n setBlob(null);\n setDurationMs(0);\n startTimestampRef.current = Date.now();\n rec.start(1000);\n setState('recording');\n clearTicker();\n tickerRef.current = setInterval(() => {\n if (startTimestampRef.current !== null) {\n setDurationMs(Date.now() - startTimestampRef.current);\n }\n }, 100);\n }, [clearTicker]);\n\n const stop = useCallback((): Promise<Blob | null> => {\n const rec = recorderRef.current;\n if (!rec || rec.state === 'inactive') {\n return Promise.resolve(blob);\n }\n setState('stopping');\n return new Promise<Blob | null>((resolve) => {\n stopResolversRef.current.push(resolve);\n try {\n rec.stop();\n } catch (err: unknown) {\n const normalized = err instanceof Error ? err : new Error('Failed to stop recorder');\n setError(normalized);\n setState('error');\n clearTicker();\n stopResolversRef.current.splice(0).forEach((r) => r(null));\n }\n });\n }, [blob, clearTicker]);\n\n // Final unmount cleanup — make sure we don't leak the camera light /\n // screen-capture indicator if the component disappears mid-recording.\n //\n // `stopResolversRef.current` is captured at effect-run time into a\n // local. That ref is initialized once at construction and never\n // reassigned, so the local handle stays a live view onto the same\n // mutable array — entries pushed by later `stop()` calls still\n // appear here on cleanup. Capturing keeps `react-hooks/exhaustive-deps`\n // satisfied without changing the runtime behavior.\n useEffect(() => {\n const pendingResolvers = stopResolversRef.current;\n return () => {\n const rec = recorderRef.current;\n if (rec && rec.state !== 'inactive') {\n try {\n rec.stop();\n } catch {\n // ignore\n }\n }\n releaseStream();\n clearTicker();\n pendingResolvers.splice(0).forEach((resolve) => resolve(null));\n };\n }, [releaseStream, clearTicker]);\n\n return {\n state,\n stream,\n blob,\n mimeType: format?.mimeType ?? null,\n extension: format?.extension ?? null,\n directory: format?.directory ?? null,\n durationMs,\n error,\n request,\n start,\n stop,\n cancel,\n reset,\n };\n}\n","/**\n * Format probing for MediaRecorder.\n *\n * Different browsers expose different container/codec combinations. Chrome\n * and Firefox produce WebM (VP8/VP9 + Opus); Safari produces MP4 (H.264 +\n * AAC). We probe at runtime via `MediaRecorder.isTypeSupported()` and pick\n * the best supported option, falling back to whatever the browser hands\n * back when no probe succeeds.\n */\n\n/** What the recorded stream is intended to capture. */\nexport type CaptureKind = 'audio' | 'video';\n\n/** A probed format choice — what to pass to `MediaRecorder` and where to write it. */\nexport interface ResolvedFormat {\n /** MIME type to pass to `new MediaRecorder(stream, { mimeType })`. Empty string means \"let the browser pick\". */\n mimeType: string;\n /** File extension to use when writing to the container, including the leading dot. */\n extension: string;\n /** Container directory inside the `ContentContainer` (no trailing slash). */\n directory: 'audio' | 'video';\n}\n\n/**\n * Preferred MIME types for audio-only recording, in priority order. The\n * first one `MediaRecorder.isTypeSupported()` accepts wins.\n *\n * Opus in a WebM container is the modern default (Chrome, Firefox, Edge).\n * MP4/AAC covers Safari. Bare strings are kept as a final fallback for\n * older browsers that don't accept codec hints.\n */\nconst AUDIO_CANDIDATES = [\n 'audio/webm;codecs=opus',\n 'audio/webm',\n 'audio/mp4;codecs=mp4a.40.2',\n 'audio/mp4',\n 'audio/ogg;codecs=opus',\n];\n\n/**\n * Preferred MIME types for video recording. VP9/Opus on top because it\n * yields good quality at modest bitrate in Chrome/Firefox. VP8 follows for\n * older Chromium. MP4/H.264 covers Safari.\n */\nconst VIDEO_CANDIDATES = [\n 'video/webm;codecs=vp9,opus',\n 'video/webm;codecs=vp8,opus',\n 'video/webm',\n 'video/mp4;codecs=avc1.42E01E,mp4a.40.2',\n 'video/mp4',\n];\n\n/**\n * Map a chosen MIME type to a file extension. Best-effort — if we can't\n * tell, default to `.bin` so the file is at least retrievable.\n */\nfunction extensionForMime(mimeType: string): string {\n const m = mimeType.toLowerCase();\n if (m.startsWith('audio/webm')) return '.webm';\n if (m.startsWith('audio/ogg')) return '.ogg';\n if (m.startsWith('audio/mp4')) return '.m4a';\n if (m.startsWith('audio/mpeg')) return '.mp3';\n if (m.startsWith('audio/wav')) return '.wav';\n if (m.startsWith('video/webm')) return '.webm';\n if (m.startsWith('video/mp4')) return '.mp4';\n return '.bin';\n}\n\n/**\n * Probe `MediaRecorder.isTypeSupported()` and return the first supported\n * MIME type from the candidate list. Returns `null` when the\n * MediaRecorder API itself is unavailable or none of the candidates pass.\n */\nfunction probeMimeType(candidates: readonly string[]): string | null {\n if (typeof MediaRecorder === 'undefined') return null;\n for (const candidate of candidates) {\n try {\n if (MediaRecorder.isTypeSupported(candidate)) return candidate;\n } catch {\n // isTypeSupported isn't supposed to throw, but Safari has historically\n // misbehaved on unknown codec strings. Keep probing.\n }\n }\n return null;\n}\n\n/**\n * Resolve the format the recorder will use for a given capture kind. If a\n * `preferred` MIME type is supported, it wins; otherwise we fall through\n * the priority list. When nothing matches (extremely old browser), we\n * return an empty `mimeType` — `MediaRecorder` will pick a default and we\n * tag the file with `.webm` as a best guess.\n */\nexport function resolveFormat(kind: CaptureKind, preferred?: string): ResolvedFormat {\n const candidates = kind === 'audio' ? AUDIO_CANDIDATES : VIDEO_CANDIDATES;\n const probed = (preferred && probeMimeType([preferred])) ?? probeMimeType(candidates) ?? '';\n const directory = kind === 'audio' ? 'audio' : 'video';\n const extension = probed ? extensionForMime(probed) : '.webm';\n return { mimeType: probed, extension, directory };\n}\n\n/**\n * `MediaRecorder` support probe. Returns false when running in a\n * non-browser environment (e.g. SSR) or on a browser that doesn't\n * implement the API at all.\n */\nexport function supportsMediaRecorder(): boolean {\n return typeof MediaRecorder !== 'undefined';\n}\n\n/**\n * `getUserMedia` support probe (for mic / camera capture).\n */\nexport function supportsUserMedia(): boolean {\n return (\n typeof navigator !== 'undefined' &&\n typeof navigator.mediaDevices !== 'undefined' &&\n typeof navigator.mediaDevices.getUserMedia === 'function'\n );\n}\n\n/**\n * `getDisplayMedia` support probe (for screen capture). Browsers may\n * implement `mediaDevices` without `getDisplayMedia` (Firefox on Android\n * being the long-standing example), so this is its own probe.\n */\nexport function supportsDisplayMedia(): boolean {\n return (\n typeof navigator !== 'undefined' &&\n typeof navigator.mediaDevices !== 'undefined' &&\n typeof navigator.mediaDevices.getDisplayMedia === 'function'\n );\n}\n\n/**\n * Build a default filename for a recording. `basename` is a hint\n * (e.g. user-typed name); when omitted, a sortable timestamp is used so\n * concurrent recordings don't collide.\n */\nexport function buildFilename(kind: CaptureKind, extension: string, basename?: string): string {\n const safe = basename\n ? basename\n .trim()\n .replace(/[\\\\/:*?\"<>|]+/g, '-')\n .replace(/\\s+/g, '-')\n : '';\n if (safe) return `${safe}${extension}`;\n const now = new Date();\n const stamp =\n now.getFullYear().toString().padStart(4, '0') +\n (now.getMonth() + 1).toString().padStart(2, '0') +\n now.getDate().toString().padStart(2, '0') +\n '-' +\n now.getHours().toString().padStart(2, '0') +\n now.getMinutes().toString().padStart(2, '0') +\n now.getSeconds().toString().padStart(2, '0');\n const prefix = kind === 'audio' ? 'narration' : 'recording';\n return `${prefix}-${stamp}${extension}`;\n}\n","/**\n * Microphone-only capture via `getUserMedia({ audio: true })`.\n */\n\nimport { supportsUserMedia } from '../formats.js';\n\n/**\n * Request a microphone-only `MediaStream`. Caller owns the stream and\n * must stop its tracks when done.\n *\n * @param constraints - Optional audio constraints (sample rate, device\n * id, echo cancellation, etc.). Defaults to `true` — let the browser\n * pick.\n * @throws When `mediaDevices` is unavailable, or when the user denies\n * permission (the underlying `getUserMedia` rejection propagates).\n */\nexport async function requestMicStream(constraints?: MediaTrackConstraints): Promise<MediaStream> {\n if (!supportsUserMedia()) {\n throw new Error('navigator.mediaDevices.getUserMedia is not available in this environment.');\n }\n return navigator.mediaDevices.getUserMedia({\n audio: constraints ?? true,\n video: false,\n });\n}\n","/**\n * Camera + microphone capture via `getUserMedia({ video, audio })`.\n */\n\nimport { supportsUserMedia } from '../formats.js';\n\nexport interface CameraStreamOptions {\n /** Video track constraints (resolution, facing mode, frame rate). Pass `true` for browser default, or `false` to omit video. */\n video?: boolean | MediaTrackConstraints;\n /** Audio track constraints. Pass `true` for browser default, or `false` to omit audio. */\n audio?: boolean | MediaTrackConstraints;\n}\n\n/**\n * Request a camera + mic `MediaStream`. Caller owns the stream and must\n * stop its tracks when done.\n *\n * Both tracks are requested by default. To capture video only, pass\n * `audio: false`; to capture audio only use {@link requestMicStream}\n * instead.\n *\n * @throws When `mediaDevices` is unavailable, or when the user denies\n * permission.\n */\nexport async function requestCameraStream(options?: CameraStreamOptions): Promise<MediaStream> {\n if (!supportsUserMedia()) {\n throw new Error('navigator.mediaDevices.getUserMedia is not available in this environment.');\n }\n const video = options?.video ?? true;\n const audio = options?.audio ?? true;\n return navigator.mediaDevices.getUserMedia({ video, audio });\n}\n","/**\n * Screen capture via `getDisplayMedia`, with optional microphone mixing.\n *\n * The browser-native `getDisplayMedia({ audio: true })` flag only\n * captures *system* audio (and only on Chromium on desktop). For\n * narrated screencasts, hosts usually want the speaker's voice too —\n * we provide an opt-in \"include mic\" path that pulls a parallel\n * `getUserMedia` audio track and mixes it into the screen stream via\n * `AudioContext`, so the resulting `MediaStream` carries a single audio\n * track and a single video track.\n */\n\nimport { supportsDisplayMedia, supportsUserMedia } from '../formats.js';\n\nexport interface ScreenStreamOptions {\n /** Video constraints for the screen surface. Pass `true` for browser default. */\n video?: boolean | MediaTrackConstraints;\n /**\n * Whether to attempt to capture the system audio (tab / window / monitor\n * audio). Browser support is limited (desktop Chromium only); when the\n * platform doesn't honor this flag, the resulting stream simply omits\n * the system audio track.\n */\n systemAudio?: boolean;\n /**\n * Whether to also pull the microphone via `getUserMedia` and mix it\n * into the resulting stream's audio track. When both `systemAudio` and\n * `includeMicrophone` produce tracks, they're combined via\n * `AudioContext` into a single output track.\n */\n includeMicrophone?: boolean;\n /** Microphone track constraints, when `includeMicrophone` is true. */\n microphoneConstraints?: MediaTrackConstraints;\n}\n\n/**\n * Combine zero-or-more audio source streams into one mixed output track\n * via an `AudioContext`. Returns `null` when no input tracks were\n * supplied so the caller can decide what to do.\n */\nfunction mixAudioTracks(streams: MediaStream[]): {\n track: MediaStreamTrack;\n context: AudioContext;\n} | null {\n const sources = streams\n .map((s) => s.getAudioTracks())\n .flat()\n .filter((t) => t.readyState === 'live');\n if (sources.length === 0) return null;\n\n const AC = window.AudioContext;\n if (typeof AC === 'undefined') return null;\n const ctx = new AC();\n const dest = ctx.createMediaStreamDestination();\n for (const track of sources) {\n const src = ctx.createMediaStreamSource(new MediaStream([track]));\n src.connect(dest);\n }\n const [mixed] = dest.stream.getAudioTracks();\n if (!mixed) return null;\n return { track: mixed, context: ctx };\n}\n\n/**\n * Handle returned by {@link requestScreenStream}. The `stream` is what\n * gets handed to `MediaRecorder`; the `dispose()` callback shuts down\n * any auxiliary resources (e.g. the mic-mix `AudioContext`). Callers\n * must also stop the stream's tracks via `stream.getTracks().forEach(t\n * => t.stop())` when done — `dispose()` cleans up everything that isn't\n * the stream itself.\n */\nexport interface ScreenStreamHandle {\n stream: MediaStream;\n /** Auxiliary cleanup beyond the stream tracks. Safe to call multiple times. */\n dispose: () => void;\n}\n\n/**\n * Request a screen-capture `MediaStream`, optionally with a mixed-in\n * microphone track. Caller owns the resulting stream.\n *\n * @throws When `getDisplayMedia` isn't available, or when the user\n * cancels the picker / denies permission.\n */\nexport async function requestScreenStream(\n options?: ScreenStreamOptions,\n): Promise<ScreenStreamHandle> {\n if (!supportsDisplayMedia()) {\n throw new Error('navigator.mediaDevices.getDisplayMedia is not available in this environment.');\n }\n const video = options?.video ?? true;\n const systemAudio = options?.systemAudio ?? false;\n const includeMic = options?.includeMicrophone ?? false;\n\n const displayStream = await navigator.mediaDevices.getDisplayMedia({\n video,\n audio: systemAudio,\n });\n\n if (!includeMic) {\n return {\n stream: displayStream,\n dispose: () => {},\n };\n }\n\n if (!supportsUserMedia()) {\n // Fall back to display-only — the caller asked for mic but the\n // platform can't deliver. Surfacing an error here would be more\n // user-hostile than just dropping the requested addition.\n return {\n stream: displayStream,\n dispose: () => {},\n };\n }\n\n let micStream: MediaStream | null = null;\n try {\n micStream = await navigator.mediaDevices.getUserMedia({\n audio: options?.microphoneConstraints ?? true,\n video: false,\n });\n } catch (err: unknown) {\n // Stop the screen tracks too so the user isn't left with a stranded\n // capture indicator.\n displayStream.getTracks().forEach((t) => t.stop());\n throw err;\n }\n\n const mix = mixAudioTracks([displayStream, micStream]);\n\n if (!mix) {\n // No audio at all — just hand back the display stream and shut down\n // the mic acquisition we made.\n micStream.getTracks().forEach((t) => t.stop());\n return {\n stream: displayStream,\n dispose: () => {},\n };\n }\n\n // Build the output stream: video from display + a single mixed audio\n // track. Replace any system-audio track that came back from\n // getDisplayMedia (it's now folded into the mix).\n const [videoTrack] = displayStream.getVideoTracks();\n const output = new MediaStream();\n if (videoTrack) output.addTrack(videoTrack);\n output.addTrack(mix.track);\n\n // Stop the now-unused raw audio tracks so the browser releases them;\n // the mixed output keeps its own copies via the AudioContext graph.\n displayStream.getAudioTracks().forEach((t) => t.stop());\n\n const dispose = () => {\n // Keep mic alive until disposal so the mix keeps producing audio.\n micStream?.getTracks().forEach((t) => t.stop());\n micStream = null;\n void mix.context.close().catch(() => {});\n };\n\n return { stream: output, dispose };\n}\n","/**\n * useStreamPreview — binds a `MediaStream` to a `<video>` element's\n * `srcObject`. Decouples the preview surface from `useMediaRecorder`,\n * letting hosts compose the preview element however they like.\n */\n\nimport { useEffect, type RefObject } from 'react';\n\n/**\n * Assign `stream` to `<video>.srcObject` whenever either changes; clears\n * it on unmount or when `stream` is `null`. The element is set to\n * `playsInline` + `muted` automatically because previewing your own\n * microphone with audio playthrough creates a feedback loop.\n *\n * @example\n * ```tsx\n * const videoRef = useRef<HTMLVideoElement>(null);\n * const { stream } = useMediaRecorder({ source: 'camera' });\n * useStreamPreview(videoRef, stream);\n * return <video ref={videoRef} autoPlay />;\n * ```\n */\nexport function useStreamPreview(\n ref: RefObject<HTMLVideoElement | null>,\n stream: MediaStream | null,\n): void {\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n el.muted = true;\n el.playsInline = true;\n el.srcObject = stream;\n if (stream) {\n // Some browsers don't auto-play on srcObject assignment; trigger\n // it explicitly and ignore the inevitable \"user gesture required\"\n // rejections — the preview will play on the next interaction.\n void el.play().catch(() => {});\n }\n return () => {\n // Only detach when this effect is tearing down. Don't stop tracks\n // — that's the recorder's responsibility.\n if (el.srcObject === stream) {\n el.srcObject = null;\n }\n };\n }, [ref, stream]);\n}\n","/**\n * Build the `.timing.json` sidecar that pairs with a narration recording.\n *\n * The shape matches what `resolveAudioMapping()` in\n * `@bendyline/squisq` reads at runtime: `sourceText`, `duration`, and\n * `bookmarks[]`. Sidecars are stored at `<audio-path>.timing.json`\n * inside the same `ContentContainer`, so the recorder can drop them\n * alongside its audio file and have the existing audio-mapping pipeline\n * pick them up with no schema changes.\n */\n\n/**\n * Word-level timing bookmark — same shape as `AudioBookmark` in\n * `@bendyline/squisq`. Recorder output produces an empty `bookmarks`\n * array; word-level timing is the domain of TTS pipelines, not\n * browser-side dictation.\n */\nexport interface RecordedBookmark {\n id: string;\n time: number;\n charOffset: number;\n textFragment?: string;\n}\n\nexport interface TimingJson {\n /** Plain text the user said (or intended to say) during the recording. */\n sourceText: string;\n /** Recording length in seconds. */\n duration: number;\n /** Word-level timing data. Empty by default — populated only when a downstream tool aligns the audio. */\n bookmarks: RecordedBookmark[];\n}\n\n/**\n * Build a `TimingJson` payload from a user-typed script and the\n * recording's measured duration. Both fields are required by the\n * downstream `parseTimingJson()` validator; missing them produces a\n * sidecar that gets silently dropped by the audio-mapping pipeline.\n */\nexport function buildTimingJson(sourceText: string, durationSec: number): TimingJson {\n return {\n sourceText: sourceText ?? '',\n duration: Number.isFinite(durationSec) && durationSec >= 0 ? durationSec : 0,\n bookmarks: [],\n };\n}\n\n/**\n * Serialize a `TimingJson` payload to a `Uint8Array` ready to hand to\n * `ContentContainer.writeFile()`. Pretty-printed so authors can hand-\n * edit the sidecar if they ever want to.\n */\nexport function encodeTimingJson(timing: TimingJson): Uint8Array {\n const text = JSON.stringify(timing, null, 2);\n return new TextEncoder().encode(text);\n}\n\n/**\n * The container path convention `resolveAudioMapping()` expects:\n * `<audio-path>.timing.json`. Pass the audio file's relative path\n * (e.g. `'audio/narration-001.webm'`) and the matching sidecar path is\n * returned (`'audio/narration-001.webm.timing.json'`).\n */\nexport function timingPathFor(audioRelativePath: string): string {\n return `${audioRelativePath}.timing.json`;\n}\n","/**\n * ViewMenuPanel\n *\n * Toolbar overflow menu (`…` button) for view-related toggles. Currently\n * houses the inline preview gutter toggle; new view options can be added\n * as additional `<MenuToggle>` rows without restructuring.\n *\n * State lives in EditorContext so the toggle survives view switches and\n * the host doesn't need to manage it. The initial value comes from the\n * EditorShell `inlinePreview` prop.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useEditorContext, type ThemeInheritance } from './EditorContext';\n\nexport function ViewMenuPanel() {\n const {\n inlinePreviewVisible,\n setInlinePreviewVisible,\n statusBarVisible,\n setStatusBarVisible,\n outlineVisible,\n setOutlineVisible,\n blockTagsVisible,\n setBlockTagsVisible,\n themeInheritance,\n setThemeInheritance,\n } = useEditorContext();\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Click-outside to close, mirroring VersionHistoryPanel.\n useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [open]);\n\n const toggleInlinePreview = useCallback(() => {\n setInlinePreviewVisible(!inlinePreviewVisible);\n }, [inlinePreviewVisible, setInlinePreviewVisible]);\n\n const toggleStatusBar = useCallback(() => {\n setStatusBarVisible(!statusBarVisible);\n }, [statusBarVisible, setStatusBarVisible]);\n\n const toggleOutline = useCallback(() => {\n setOutlineVisible(!outlineVisible);\n }, [outlineVisible, setOutlineVisible]);\n\n const toggleBlockTags = useCallback(() => {\n setBlockTagsVisible(!blockTagsVisible);\n }, [blockTagsVisible, setBlockTagsVisible]);\n\n return (\n <div className=\"squisq-view-menu\" ref={containerRef}>\n <button\n type=\"button\"\n className={`squisq-toolbar-button squisq-view-menu-trigger${\n open ? ' squisq-toolbar-button--active' : ''\n }`}\n data-tooltip=\"View options\"\n aria-label=\"View options\"\n aria-expanded={open}\n aria-haspopup=\"menu\"\n onClick={() => setOpen((v) => !v)}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M1.5 8 C 3 4.5 5.5 3 8 3 S 13 4.5 14.5 8 C 13 11.5 10.5 13 8 13 S 3 11.5 1.5 8 Z\" />\n <circle cx=\"8\" cy=\"8\" r=\"2.2\" />\n </svg>\n </button>\n {open && (\n <div className=\"squisq-view-menu-popover\" role=\"menu\" aria-label=\"View options\">\n <MenuToggle label=\"Show outline\" checked={outlineVisible} onChange={toggleOutline} />\n <MenuToggle\n label=\"Show block previews\"\n checked={inlinePreviewVisible}\n onChange={toggleInlinePreview}\n />\n <MenuToggle\n label=\"Show block tags\"\n checked={blockTagsVisible}\n onChange={toggleBlockTags}\n />\n <MenuToggle\n label=\"Show status bar\"\n checked={statusBarVisible}\n onChange={toggleStatusBar}\n />\n <div className=\"squisq-view-menu-separator\" role=\"separator\" />\n <MenuRadioGroup\n label=\"Editor styling from theme\"\n name=\"theme-inheritance\"\n value={themeInheritance}\n onChange={(v) => setThemeInheritance(v as ThemeInheritance)}\n options={[\n { value: 'none', label: \"Don't inherit\" },\n { value: 'fonts', label: 'Fonts only' },\n { value: 'fonts-colors', label: 'Fonts & colors' },\n ]}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction MenuToggle({\n label,\n checked,\n onChange,\n}: {\n label: string;\n checked: boolean;\n onChange: () => void;\n}) {\n return (\n <label className=\"squisq-view-menu-row\" role=\"menuitemcheckbox\" aria-checked={checked}>\n <input\n type=\"checkbox\"\n className=\"squisq-view-menu-checkbox\"\n checked={checked}\n onChange={onChange}\n />\n <span className=\"squisq-view-menu-label\">{label}</span>\n </label>\n );\n}\n\nfunction MenuRadioGroup({\n label,\n name,\n value,\n onChange,\n options,\n}: {\n label: string;\n name: string;\n value: string;\n onChange: (next: string) => void;\n options: readonly { value: string; label: string }[];\n}) {\n return (\n <div\n className=\"squisq-view-menu-row squisq-view-menu-row--radios\"\n role=\"radiogroup\"\n aria-label={label}\n >\n <span className=\"squisq-view-menu-label\">{label}</span>\n {options.map((o) => {\n const checked = o.value === value;\n return (\n <label\n key={o.value}\n className=\"squisq-view-menu-radio-row\"\n role=\"menuitemradio\"\n aria-checked={checked}\n >\n <input\n type=\"radio\"\n className=\"squisq-view-menu-radio\"\n name={name}\n value={o.value}\n checked={checked}\n onChange={() => onChange(o.value)}\n />\n <span className=\"squisq-view-menu-radio-label\">{o.label}</span>\n </label>\n );\n })}\n </div>\n );\n}\n","/**\n * Helpers for extracting the immediate body of the heading-defined block\n * that's currently being edited. The template picker uses this slice to\n * decide which templates to surface as \"Recommended for this block\".\n *\n * Block boundary: from the target heading's position, take subsequent\n * top-level siblings up to (but not including) the next heading at any\n * depth. This matches the doc model where each heading owns its\n * immediate `contents` and subheadings become nested blocks.\n */\n\nimport { parseMarkdown } from '@bendyline/squisq/markdown';\nimport type {\n MarkdownBlockNode,\n MarkdownDocument,\n MarkdownHeading,\n} from '@bendyline/squisq/markdown';\n\nfunction slicePastHeading(\n doc: MarkdownDocument,\n headingNode: MarkdownHeading,\n): MarkdownBlockNode[] {\n const children = doc.children;\n const startIdx = children.indexOf(headingNode);\n if (startIdx < 0) return [];\n const out: MarkdownBlockNode[] = [];\n for (let i = startIdx + 1; i < children.length; i++) {\n const node = children[i];\n if (node.type === 'heading') break;\n out.push(node);\n }\n return out;\n}\n\n/**\n * Parse `source` and return the body of the heading whose source range\n * covers `lineNumber` (1-indexed). Returns `null` if `lineNumber` isn't\n * on a heading line.\n */\nexport function findBlockSliceAtLine(\n source: string,\n lineNumber: number,\n): MarkdownBlockNode[] | null {\n const doc = parseMarkdown(source);\n for (const node of doc.children) {\n if (node.type !== 'heading') continue;\n const pos = node.position;\n if (!pos) continue;\n if (pos.start.line <= lineNumber && pos.end.line >= lineNumber) {\n return slicePastHeading(doc, node);\n }\n }\n return null;\n}\n\n/**\n * Parse `source` and return the body of the Nth top-level heading\n * (0-indexed). Used by the WYSIWYG path, which knows the heading's\n * index in the Tiptap doc but not its source line.\n */\nexport function findBlockSliceByHeadingIndex(\n source: string,\n headingIndex: number,\n): MarkdownBlockNode[] | null {\n const doc = parseMarkdown(source);\n let seen = 0;\n for (const node of doc.children) {\n if (node.type !== 'heading') continue;\n if (seen === headingIndex) {\n return slicePastHeading(doc, node);\n }\n seen++;\n }\n return null;\n}\n","/**\n * LinkDialog — modal for inserting or editing a markdown link.\n *\n * Used by both the WYSIWYG and Raw markdown toolbars so the link-editing\n * UX is identical regardless of view. Shows separate fields for the link\n * text (caption) and the URL target so the user can see and edit both.\n *\n * When a `documentLinkProvider` is supplied, the dialog also exposes a\n * second tab — \"Browse documents\" — that lists neighbor docs from the\n * host's workspace. Selecting one fills the URL with the candidate\n * path (and the caption, if it was still empty), so authors can link\n * `home.md → resume.md` without typing the relative path by hand.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { DocumentLinkProvider, DocumentLinkCandidate } from './EditorContext';\n\nexport interface LinkDialogProps {\n /** Whether this is a brand-new link (Insert) or an existing one (Update). */\n mode: 'insert' | 'update';\n /** Initial value for the caption field. */\n initialText: string;\n /** Initial value for the URL field. */\n initialUrl: string;\n /**\n * Confirm — `text` may be empty if the caller wants to fall back to URL\n * as the visible text. Empty `url` means the user cleared it; callers\n * should treat that as \"remove link\" when in update mode.\n */\n onConfirm: (text: string, url: string) => void;\n /** Dismiss without applying changes. */\n onClose: () => void;\n /**\n * Optional sibling-document picker. When provided, the dialog shows\n * a \"Browse documents\" tab that queries the provider as the author\n * types and offers click-to-pick suggestions.\n */\n documentLinkProvider?: DocumentLinkProvider | null;\n}\n\n/**\n * Centered modal with Text and URL inputs. Submits on Enter, dismisses\n * on Escape or backdrop click. Auto-focuses URL when the text field is\n * already populated; otherwise focuses Text.\n */\nexport function LinkDialog({\n mode,\n initialText,\n initialUrl,\n onConfirm,\n onClose,\n documentLinkProvider,\n}: LinkDialogProps) {\n const [text, setText] = useState(initialText);\n const [url, setUrl] = useState(initialUrl);\n const [tab, setTab] = useState<'url' | 'documents'>('url');\n const [docQuery, setDocQuery] = useState('');\n const [docResults, setDocResults] = useState<DocumentLinkCandidate[]>([]);\n const [docLoading, setDocLoading] = useState(false);\n const textRef = useRef<HTMLInputElement>(null);\n const urlRef = useRef<HTMLInputElement>(null);\n const docSearchRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n // If we have a caption already, the URL is what the user is most\n // likely here to edit; otherwise focus the caption field first.\n const target = initialText ? urlRef.current : textRef.current;\n target?.focus();\n target?.select();\n }, [initialText]);\n\n // Refresh the document candidate list whenever the user types into\n // the picker or first opens it. Empty query = initial list.\n useEffect(() => {\n if (!documentLinkProvider || tab !== 'documents') return;\n let cancelled = false;\n setDocLoading(true);\n documentLinkProvider(docQuery)\n .then((results) => {\n if (!cancelled) {\n setDocResults(results);\n setDocLoading(false);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setDocResults([]);\n setDocLoading(false);\n }\n });\n return () => {\n cancelled = true;\n };\n }, [docQuery, documentLinkProvider, tab]);\n\n // Auto-focus the search field when the documents tab opens.\n useEffect(() => {\n if (tab === 'documents') {\n const t = setTimeout(() => docSearchRef.current?.focus(), 0);\n return () => clearTimeout(t);\n }\n return undefined;\n }, [tab]);\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n onClose();\n }\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose]);\n\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n onConfirm(text, url);\n },\n [text, url, onConfirm],\n );\n\n const handleBackdropClick = useCallback(\n (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n },\n [onClose],\n );\n\n const isUpdate = mode === 'update';\n const submitLabel = isUpdate ? 'Update' : 'Insert';\n const heading = isUpdate ? 'Edit link' : 'Insert link';\n\n const handlePickCandidate = useCallback((candidate: DocumentLinkCandidate) => {\n // Picking a document fills the URL and the caption (when the\n // caption is still empty — preserve any caption the user already\n // typed). Switch back to the URL tab so the result is immediately\n // visible and editable, and so Enter submits the form.\n setUrl(candidate.path);\n setText((existing) => existing || candidate.label);\n setTab('url');\n }, []);\n\n return (\n <div className=\"squisq-link-dialog-overlay\" onMouseDown={handleBackdropClick}>\n <form className=\"squisq-link-dialog\" onSubmit={handleSubmit}>\n <div className=\"squisq-link-dialog-header\">\n <h2 className=\"squisq-link-dialog-title\">{heading}</h2>\n <button\n type=\"button\"\n className=\"squisq-link-dialog-close\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n &times;\n </button>\n </div>\n <div className=\"squisq-link-dialog-body\">\n {documentLinkProvider && (\n <div className=\"squisq-link-dialog-tabs\" role=\"tablist\">\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === 'url'}\n className={`squisq-link-dialog-tab${tab === 'url' ? ' squisq-link-dialog-tab--active' : ''}`}\n onClick={() => setTab('url')}\n >\n URL\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === 'documents'}\n className={`squisq-link-dialog-tab${tab === 'documents' ? ' squisq-link-dialog-tab--active' : ''}`}\n onClick={() => setTab('documents')}\n >\n Browse documents\n </button>\n </div>\n )}\n <label className=\"squisq-link-dialog-field\">\n <span className=\"squisq-link-dialog-label\">Text</span>\n <input\n ref={textRef}\n type=\"text\"\n className=\"squisq-link-dialog-input\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n placeholder=\"Link caption\"\n />\n </label>\n {tab === 'url' ? (\n <label className=\"squisq-link-dialog-field\">\n <span className=\"squisq-link-dialog-label\">URL</span>\n <input\n ref={urlRef}\n type=\"text\"\n className=\"squisq-link-dialog-input\"\n value={url}\n onChange={(e) => setUrl(e.target.value)}\n placeholder=\"https://example.com\"\n spellCheck={false}\n autoComplete=\"off\"\n />\n </label>\n ) : (\n <div className=\"squisq-link-dialog-doc-picker\">\n <label className=\"squisq-link-dialog-field\">\n <span className=\"squisq-link-dialog-label\">Search</span>\n <input\n ref={docSearchRef}\n type=\"text\"\n className=\"squisq-link-dialog-input\"\n value={docQuery}\n onChange={(e) => setDocQuery(e.target.value)}\n placeholder=\"Type to filter…\"\n spellCheck={false}\n autoComplete=\"off\"\n />\n </label>\n <div\n className=\"squisq-link-dialog-doc-list\"\n role=\"listbox\"\n aria-label=\"Document candidates\"\n aria-busy={docLoading}\n >\n {docLoading && docResults.length === 0 ? (\n <div className=\"squisq-link-dialog-doc-empty\">Loading…</div>\n ) : docResults.length === 0 ? (\n <div className=\"squisq-link-dialog-doc-empty\">\n {docQuery.trim() ? `No matches for \"${docQuery.trim()}\"` : 'No documents'}\n </div>\n ) : (\n docResults.map((c) => (\n <button\n key={c.path}\n type=\"button\"\n role=\"option\"\n aria-selected={url === c.path}\n className={`squisq-link-dialog-doc-item${url === c.path ? ' squisq-link-dialog-doc-item--selected' : ''}`}\n onClick={() => handlePickCandidate(c)}\n >\n <span className=\"squisq-link-dialog-doc-item-label\">{c.label}</span>\n <span className=\"squisq-link-dialog-doc-item-path\">{c.path}</span>\n {c.description && (\n <span className=\"squisq-link-dialog-doc-item-desc\">{c.description}</span>\n )}\n </button>\n ))\n )}\n </div>\n {url && (\n <div className=\"squisq-link-dialog-doc-current\">\n Selected: <code>{url}</code>\n </div>\n )}\n </div>\n )}\n </div>\n <div className=\"squisq-link-dialog-footer\">\n <button\n type=\"button\"\n className=\"squisq-link-dialog-btn squisq-link-dialog-btn--secondary\"\n onClick={onClose}\n >\n Cancel\n </button>\n <button type=\"submit\" className=\"squisq-link-dialog-btn squisq-link-dialog-btn--primary\">\n {submitLabel}\n </button>\n </div>\n </form>\n </div>\n );\n}\n","/**\n * DocumentSettingsDialog\n *\n * Modal editor for the frontmatter values that Squisq currently\n * understands: document title plus the persisted preview keys\n * (`squisq-theme`, `squisq-transform`, `squisq-captions`). Writes back\n * to the same `setFrontmatterValues` channel that `PreviewControls`\n * uses, so any change made here is reflected in the play-mode controls\n * (and vice versa).\n *\n * Title behavior: the placeholder shows the title that\n * `inferDocumentTitle()` would derive from frontmatter or headings.\n * When the user-entered title is empty or equal to the inferred title,\n * the `title:` key is removed from frontmatter — there's no point\n * storing a redundant value.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n inferDocumentTitle,\n parseMarkdown,\n setFrontmatterValues,\n} from '@bendyline/squisq/markdown';\nimport { getTransformStyleSummaries } from '@bendyline/squisq/transform';\nimport { ThemePicker } from './ThemePicker';\n\n// ── Frontmatter key constants ─────────────────────────────────────\n\n/** Mirror of `FM_KEYS` in PreviewControls.tsx. Canonical names are the\n * ones we write; legacy aliases are still read so older docs work. */\nconst FM = {\n theme: { canonical: 'squisq-theme', legacy: 'theme' },\n transform: { canonical: 'squisq-transform', legacy: 'transform-style' },\n captions: { canonical: 'squisq-captions', legacy: 'caption-style' },\n} as const;\n\nfunction readFm(\n fm: Record<string, unknown> | undefined,\n canonical: string,\n legacy: string,\n): string {\n if (!fm) return '';\n const v = Object.prototype.hasOwnProperty.call(fm, canonical) ? fm[canonical] : fm[legacy];\n return typeof v === 'string' ? v : '';\n}\n\nconst CAPTION_OPTIONS: readonly { key: string; label: string }[] = [\n { key: '', label: 'Default (Standard)' },\n { key: 'standard', label: 'Standard' },\n { key: 'social', label: 'Social' },\n];\n\n// ── Props ─────────────────────────────────────────────────────────\n\nexport interface DocumentSettingsDialogProps {\n /** Current markdown source string (frontmatter + body). */\n markdownSource: string;\n /** Called with the rewritten source after the user clicks Save. */\n onSave: (nextSource: string) => void;\n /** Called when the dialog is dismissed (Cancel, Escape, backdrop click). */\n onClose: () => void;\n}\n\n// ── Component ─────────────────────────────────────────────────────\n\nexport function DocumentSettingsDialog({\n markdownSource,\n onSave,\n onClose,\n}: DocumentSettingsDialogProps) {\n // Parse once at open; further edits flow through local form state and\n // are committed in a single `setFrontmatterValues` call on Save.\n const parsed = useMemo(() => parseMarkdown(markdownSource), [markdownSource]);\n const frontmatter = parsed.frontmatter;\n const inferredTitle = useMemo(() => inferDocumentTitle(parsed), [parsed]);\n\n const currentTitle = typeof frontmatter?.title === 'string' ? (frontmatter.title as string) : '';\n const currentTheme = readFm(frontmatter, FM.theme.canonical, FM.theme.legacy);\n const currentTransform = readFm(frontmatter, FM.transform.canonical, FM.transform.legacy);\n const currentCaptions = readFm(frontmatter, FM.captions.canonical, FM.captions.legacy);\n\n const [title, setTitle] = useState(currentTitle);\n const [theme, setTheme] = useState(currentTheme);\n const [transform, setTransform] = useState(currentTransform);\n const [captions, setCaptions] = useState(currentCaptions);\n\n const titleRef = useRef<HTMLInputElement>(null);\n useEffect(() => {\n titleRef.current?.focus();\n titleRef.current?.select();\n }, []);\n\n // Esc closes; click on backdrop closes (but not on dialog itself).\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [onClose]);\n\n const handleBackdrop = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget) onClose();\n },\n [onClose],\n );\n\n // Dropdown options — built once per render; cheap.\n const transformOptions = useMemo(\n () => [\n { key: '', label: 'None' },\n ...getTransformStyleSummaries().map((s) => ({ key: s.id, label: s.name })),\n ],\n [],\n );\n\n const handleSave = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n const trimmedTitle = title.trim();\n const titleMatchesInferred = !!inferredTitle && trimmedTitle === inferredTitle;\n // Empty input OR matches the value we'd infer otherwise → no\n // explicit title needed in frontmatter.\n const nextTitle = !trimmedTitle || titleMatchesInferred ? null : trimmedTitle;\n\n const updates: Record<string, string | null> = {\n title: nextTitle,\n [FM.theme.canonical]: theme || null,\n // Legacy `theme` key would shadow our canonical one — clear it\n // when the user changes the theme so the canonical write wins.\n ...(currentTheme && theme !== currentTheme ? { [FM.theme.legacy]: null } : {}),\n [FM.transform.canonical]: transform || null,\n ...(currentTransform && transform !== currentTransform\n ? { [FM.transform.legacy]: null }\n : {}),\n [FM.captions.canonical]: captions || null,\n ...(currentCaptions && captions !== currentCaptions ? { [FM.captions.legacy]: null } : {}),\n };\n\n const nextSource = setFrontmatterValues(markdownSource, updates);\n onSave(nextSource);\n },\n [\n title,\n theme,\n transform,\n captions,\n inferredTitle,\n markdownSource,\n currentTheme,\n currentTransform,\n currentCaptions,\n onSave,\n ],\n );\n\n return (\n <div className=\"squisq-doc-settings-overlay\" onMouseDown={handleBackdrop}>\n <form className=\"squisq-doc-settings-dialog\" onSubmit={handleSave}>\n <div className=\"squisq-doc-settings-header\">\n <h2 className=\"squisq-doc-settings-title\">Document settings</h2>\n <button\n type=\"button\"\n className=\"squisq-doc-settings-close\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n &times;\n </button>\n </div>\n\n <div className=\"squisq-doc-settings-body\">\n <div className=\"squisq-doc-settings-field\">\n <label className=\"squisq-doc-settings-label\" htmlFor=\"squisq-doc-settings-title\">\n Title\n </label>\n <input\n ref={titleRef}\n id=\"squisq-doc-settings-title\"\n type=\"text\"\n className=\"squisq-doc-settings-input\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder={inferredTitle ?? 'Document title'}\n spellCheck\n />\n {inferredTitle ? (\n <span className=\"squisq-doc-settings-hint\">\n Defaults to <strong>{inferredTitle}</strong> — leave blank to use it.\n </span>\n ) : (\n <span className=\"squisq-doc-settings-hint\">\n No title heading found — set one here or add an H1 to the document.\n </span>\n )}\n </div>\n\n <div className=\"squisq-doc-settings-field\">\n <span className=\"squisq-doc-settings-label\">Theme</span>\n <ThemePicker\n value={theme}\n onChange={setTheme}\n includeDefault\n variant=\"full\"\n ariaLabel=\"Theme\"\n />\n </div>\n\n <div className=\"squisq-doc-settings-field\">\n <label className=\"squisq-doc-settings-label\" htmlFor=\"squisq-doc-settings-transform\">\n Transform\n </label>\n <select\n id=\"squisq-doc-settings-transform\"\n className=\"squisq-doc-settings-input\"\n value={transform}\n onChange={(e) => setTransform(e.target.value)}\n >\n {transformOptions.map((o) => (\n <option key={o.key} value={o.key}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"squisq-doc-settings-field\">\n <label className=\"squisq-doc-settings-label\" htmlFor=\"squisq-doc-settings-captions\">\n Captions\n </label>\n <select\n id=\"squisq-doc-settings-captions\"\n className=\"squisq-doc-settings-input\"\n value={captions}\n onChange={(e) => setCaptions(e.target.value)}\n >\n {CAPTION_OPTIONS.map((o) => (\n <option key={o.key} value={o.key}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <div className=\"squisq-doc-settings-footer\">\n <button\n type=\"button\"\n className=\"squisq-doc-settings-btn squisq-doc-settings-btn--secondary\"\n onClick={onClose}\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n className=\"squisq-doc-settings-btn squisq-doc-settings-btn--primary\"\n >\n Save\n </button>\n </div>\n </form>\n </div>\n );\n}\n","/**\n * ThemePicker\n *\n * Custom theme dropdown that replaces a plain `<select>` with a popover\n * showing each theme as a card: the theme name rendered in the theme's\n * own background / foreground / title font, plus three color swatches\n * (primary, secondary, highlight). Used by both the play-mode preview\n * toolbar and the Document Settings dialog so authors see a\n * preview-on-hover style listing rather than a wall of names.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n getThemeSummaries,\n resolveTheme,\n resolveFontFamily,\n FONT_FALLBACKS,\n} from '@bendyline/squisq/schemas';\nimport type { Theme } from '@bendyline/squisq/schemas';\n\n// ── Props ─────────────────────────────────────────────────────────\n\nexport interface ThemePickerProps {\n /** Currently selected theme id. Empty string represents \"default\". */\n value: string;\n /** Called with the new theme id. The empty string is emitted when the\n * user picks the \"Default\" option (only available with\n * `includeDefault`). */\n onChange: (id: string) => void;\n /**\n * Show a \"Default\" entry at the top of the popover that emits an empty\n * string. Used by the Document Settings dialog so the user can choose\n * \"no explicit theme\" (frontmatter omits the key entirely).\n */\n includeDefault?: boolean;\n /**\n * `'compact'` (default) renders a small toolbar trigger; `'full'`\n * stretches to fill the parent and is sized for dialog layouts.\n */\n variant?: 'compact' | 'full';\n /** Accessible label, e.g. \"Theme\". */\n ariaLabel?: string;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────\n\nconst SUMMARIES = getThemeSummaries();\n\ninterface ThemeEntry {\n id: string;\n name: string;\n description?: string;\n theme: Theme;\n}\n\nconst THEME_ENTRIES: ThemeEntry[] = SUMMARIES.map((s) => ({\n id: s.id,\n name: s.name,\n description: s.description,\n theme: resolveTheme(s.id),\n}));\n\nfunction entryById(id: string): ThemeEntry | undefined {\n return THEME_ENTRIES.find((e) => e.id === id);\n}\n\nfunction previewFont(theme: Theme): string {\n return resolveFontFamily(theme.typography.titleFont, FONT_FALLBACKS.sans);\n}\n\n// ── Trigger button ────────────────────────────────────────────────\n\nfunction ThemeNameChip({\n theme,\n label,\n className,\n}: {\n theme: Theme;\n label: string;\n className?: string;\n}) {\n return (\n <span\n className={`squisq-theme-picker-name-chip${className ? ` ${className}` : ''}`}\n style={{\n background: theme.colors.background,\n color: theme.colors.text,\n fontFamily: previewFont(theme),\n borderColor: theme.colors.backgroundLight,\n }}\n >\n {label}\n </span>\n );\n}\n\nfunction Swatches({ theme }: { theme: Theme }) {\n return (\n <span className=\"squisq-theme-picker-swatches\" aria-hidden=\"true\">\n <span className=\"squisq-theme-picker-swatch\" style={{ background: theme.colors.primary }} />\n <span className=\"squisq-theme-picker-swatch\" style={{ background: theme.colors.secondary }} />\n <span className=\"squisq-theme-picker-swatch\" style={{ background: theme.colors.highlight }} />\n </span>\n );\n}\n\n// ── Component ─────────────────────────────────────────────────────\n\nexport function ThemePicker({\n value,\n onChange,\n includeDefault,\n variant = 'compact',\n ariaLabel = 'Theme',\n}: ThemePickerProps) {\n const [open, setOpen] = useState(false);\n const [popoverStyle, setPopoverStyle] = useState<React.CSSProperties>({});\n const triggerRef = useRef<HTMLButtonElement>(null);\n\n const selectedEntry = useMemo<ThemeEntry | null>(() => {\n if (!value) return null;\n return entryById(value) ?? null;\n }, [value]);\n\n // The trigger always wants *something* to preview. When `includeDefault`\n // is on and the value is empty, we treat the selection as the implicit\n // \"Default\" — the chip uses plain OS styling (white bg, dark text,\n // italic) rather than the standard theme's actual dark-navy palette.\n const isDefault = !selectedEntry && includeDefault === true;\n const previewEntry = selectedEntry ?? entryById('standard') ?? THEME_ENTRIES[0];\n const triggerLabel = selectedEntry\n ? selectedEntry.name\n : includeDefault\n ? 'Default'\n : (previewEntry?.name ?? 'Theme');\n\n const updatePosition = useCallback(() => {\n if (!triggerRef.current) return;\n const rect = triggerRef.current.getBoundingClientRect();\n const margin = 8;\n const gap = 4;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const popoverWidth = Math.max(280, rect.width);\n const maxLeft = Math.max(margin, vw - popoverWidth - margin);\n const left = Math.min(Math.max(margin, rect.left), maxLeft);\n\n // Measure the rendered popover so we know whether it fits below the\n // trigger as-is. On the first open it doesn't exist yet — we'll\n // re-run after mount via the requestAnimationFrame in the open\n // effect, so estimate generously for paint #1.\n const popoverEl = document.getElementById('squisq-theme-picker-popover');\n const measured = popoverEl?.scrollHeight ?? 520;\n const spaceBelow = vh - rect.bottom - margin - gap;\n const spaceAbove = rect.top - margin - gap;\n\n // Prefer below when it fits; flip above when below is too tight AND\n // above has more room. Either way, clamp maxHeight to the available\n // space so the internal scroll handles oversized lists.\n let top: number;\n let maxHeight: number;\n if (measured <= spaceBelow || spaceBelow >= spaceAbove) {\n top = rect.bottom + gap;\n maxHeight = spaceBelow;\n } else {\n maxHeight = Math.min(measured, spaceAbove);\n top = rect.top - gap - maxHeight;\n }\n\n setPopoverStyle({\n position: 'fixed',\n top,\n left,\n width: popoverWidth,\n maxHeight,\n overflowY: 'auto',\n zIndex: 9999,\n });\n }, []);\n\n const handleToggle = () => {\n if (!open) updatePosition();\n setOpen((v) => !v);\n };\n\n // Close on outside click / Esc; reposition on scroll/resize while open.\n useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n const target = e.target as Node;\n if (triggerRef.current?.contains(target)) return;\n const popoverEl = document.getElementById('squisq-theme-picker-popover');\n if (popoverEl?.contains(target)) return;\n setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false);\n };\n const onReposition = () => updatePosition();\n document.addEventListener('mousedown', onDown);\n document.addEventListener('keydown', onKey);\n window.addEventListener('scroll', onReposition, true);\n window.addEventListener('resize', onReposition);\n requestAnimationFrame(updatePosition);\n return () => {\n document.removeEventListener('mousedown', onDown);\n document.removeEventListener('keydown', onKey);\n window.removeEventListener('scroll', onReposition, true);\n window.removeEventListener('resize', onReposition);\n };\n }, [open, updatePosition]);\n\n const handleSelect = (id: string) => {\n onChange(id);\n setOpen(false);\n };\n\n const popover = open\n ? createPortal(\n <div\n id=\"squisq-theme-picker-popover\"\n className=\"squisq-theme-picker-popover\"\n role=\"listbox\"\n aria-label={ariaLabel}\n style={popoverStyle}\n >\n {includeDefault && (\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={value === ''}\n aria-label=\"Default\"\n className={`squisq-theme-picker-row${value === '' ? ' squisq-theme-picker-row--selected' : ''}`}\n onClick={() => handleSelect('')}\n >\n <ThemeNameChip\n theme={resolveTheme('standard')}\n label=\"Default\"\n className=\"squisq-theme-picker-name-chip--default\"\n />\n <span className=\"squisq-theme-picker-row-meta\">\n <span className=\"squisq-theme-picker-row-name\">No explicit theme</span>\n <span className=\"squisq-theme-picker-row-desc\">\n Uses the document&apos;s default styling.\n </span>\n </span>\n </button>\n )}\n {THEME_ENTRIES.map((entry) => (\n <button\n key={entry.id}\n type=\"button\"\n role=\"option\"\n aria-selected={value === entry.id}\n aria-label={entry.name}\n className={`squisq-theme-picker-row${value === entry.id ? ' squisq-theme-picker-row--selected' : ''}`}\n onClick={() => handleSelect(entry.id)}\n title={entry.description ?? entry.name}\n >\n <ThemeNameChip theme={entry.theme} label={entry.name} />\n <span className=\"squisq-theme-picker-row-meta\">\n <Swatches theme={entry.theme} />\n {entry.description && (\n <span className=\"squisq-theme-picker-row-desc\">{entry.description}</span>\n )}\n </span>\n </button>\n ))}\n </div>,\n document.body,\n )\n : null;\n\n return (\n <>\n <button\n ref={triggerRef}\n type=\"button\"\n className={`squisq-theme-picker-trigger squisq-theme-picker-trigger--${variant}${\n open ? ' squisq-theme-picker-trigger--open' : ''\n }`}\n onClick={handleToggle}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-label={ariaLabel}\n >\n {previewEntry && (\n <ThemeNameChip\n theme={previewEntry.theme}\n label={triggerLabel}\n className={`squisq-theme-picker-name-chip--trigger${\n isDefault ? ' squisq-theme-picker-name-chip--default' : ''\n }`}\n />\n )}\n {previewEntry && variant === 'full' && !isDefault && (\n <Swatches theme={previewEntry.theme} />\n )}\n <svg\n className=\"squisq-theme-picker-caret\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M2 3.5l3 3 3-3\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n </button>\n {popover}\n </>\n );\n}\n","/**\n * EmojiPicker\n *\n * Toolbar-anchored popover for inserting emoji. The user picks a\n * category from a row of tabs along the top, sees a scrollable grid\n * for that category, and can type into a search box to narrow across\n * all categories at once. Click → `onSelect(char)` → caller is\n * responsible for routing the character into the active editor.\n *\n * Keeps the data flat and the rendering simple: there's no fuzzy\n * search, no recently-used persistence, no skin-tone modifiers — just\n * a fast, predictable picker. We can layer those on later without\n * changing the public surface.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport type { CSSProperties } from 'react';\nimport { PICKER_CATEGORIES, searchPickerEntries } from './emojiData';\nimport type { PickerEntry } from './emojiData';\n\nexport interface EmojiPickerProps {\n /** Whether the picker is visible. */\n open: boolean;\n /**\n * Fired when the user picks an entry. Carries either an emoji glyph\n * or a FontAwesome icon descriptor — the caller dispatches on\n * `kind` to insert it into the active editor. The caller is also\n * responsible for closing the popover.\n */\n onSelect: (entry: PickerEntry) => void;\n /** Fired on Escape, click-outside, or selection so the caller can close. */\n onClose: () => void;\n /** Optional anchor element — used for click-outside detection. When the\n * popover is rendered inside the same container as the trigger, pointer\n * events on the trigger don't fire the outside handler. */\n anchorRef?: React.RefObject<HTMLElement>;\n /** Optional CSS class for the popover root. */\n className?: string;\n /** Optional inline style for the popover root (e.g. positioning). */\n style?: CSSProperties;\n /**\n * Editor theme — `'light'` or `'dark'`. Drives the picker's color\n * palette. Required for the picker to render correctly when portaled\n * outside the editor shell, since CSS custom properties defined on\n * the shell don't cascade to portal targets. Defaults to `'light'`.\n */\n theme?: 'light' | 'dark';\n}\n\ninterface PickerPalette {\n bg: string;\n border: string;\n inputBg: string;\n text: string;\n textMuted: string;\n accent: string;\n accentSoft: string;\n}\n\nconst LIGHT_PALETTE: PickerPalette = {\n bg: '#fff',\n border: '#d4cdb5',\n inputBg: '#fff',\n text: '#1f2937',\n textMuted: '#8a7a5a',\n accent: '#8B6914',\n accentSoft: '#f3eedb',\n};\n\nconst DARK_PALETTE: PickerPalette = {\n bg: '#1f2937',\n border: '#4b5563',\n inputBg: '#374151',\n text: '#e5e7eb',\n textMuted: '#9ca3af',\n accent: '#fbbf24',\n accentSoft: '#374151',\n};\n\n/** Default popover dimensions. The Toolbar reads these to position the\n * popover with viewport-aware clamping so it never gets clipped. */\nexport const EMOJI_PICKER_WIDTH = 480;\nexport const EMOJI_PICKER_MAX_HEIGHT = 560;\n\nfunction buildPopoverStyle(palette: PickerPalette): CSSProperties {\n return {\n position: 'absolute',\n zIndex: 100,\n background: palette.bg,\n border: `1px solid ${palette.border}`,\n borderRadius: 6,\n // Dark mode needs a deeper shadow than the light palette uses,\n // because the popover sits on a dark surface where a soft 15%\n // shadow effectively disappears.\n boxShadow:\n palette === DARK_PALETTE ? '0 8px 32px rgba(0, 0, 0, 0.5)' : '0 6px 24px rgba(0, 0, 0, 0.15)',\n color: palette.text,\n width: EMOJI_PICKER_WIDTH,\n maxWidth: '95vw',\n maxHeight: EMOJI_PICKER_MAX_HEIGHT,\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n };\n}\n\nexport function EmojiPicker({\n open,\n onSelect,\n onClose,\n anchorRef,\n className,\n style,\n theme = 'light',\n}: EmojiPickerProps) {\n const palette = theme === 'dark' ? DARK_PALETTE : LIGHT_PALETTE;\n const [activeCategory, setActiveCategory] = useState<string>(PICKER_CATEGORIES[0].id);\n const [query, setQuery] = useState('');\n const popoverRef = useRef<HTMLDivElement>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n\n // Focus the search box when the popover opens; reset query when it\n // closes so the next open starts fresh.\n useEffect(() => {\n if (open) {\n // Defer so the input is mounted.\n const t = setTimeout(() => searchInputRef.current?.focus(), 0);\n return () => clearTimeout(t);\n }\n setQuery('');\n setActiveCategory(PICKER_CATEGORIES[0].id);\n return undefined;\n }, [open]);\n\n // Close on outside click and Escape.\n useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: MouseEvent) => {\n const target = e.target as Node | null;\n if (!target) return;\n if (popoverRef.current?.contains(target)) return;\n if (anchorRef?.current?.contains(target)) return;\n onClose();\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('mousedown', onPointerDown);\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('mousedown', onPointerDown);\n document.removeEventListener('keydown', onKey);\n };\n }, [open, onClose, anchorRef]);\n\n const visibleEntries = useMemo<PickerEntry[]>(() => {\n if (query.trim()) return searchPickerEntries(query);\n const cat = PICKER_CATEGORIES.find((c) => c.id === activeCategory);\n return cat ? cat.entries : [];\n }, [query, activeCategory]);\n\n if (!open) return null;\n\n return (\n <div\n ref={popoverRef}\n className={`squisq-emoji-picker ${className ?? ''}`}\n data-theme={theme}\n style={{ ...buildPopoverStyle(palette), ...style }}\n role=\"dialog\"\n aria-label=\"Insert emoji\"\n data-testid=\"emoji-picker\"\n >\n {/* Search */}\n <div\n style={{\n padding: '8px 10px',\n borderBottom: `1px solid ${palette.border}`,\n }}\n >\n <input\n ref={searchInputRef}\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search emoji & icons…\"\n aria-label=\"Search emoji & icons\"\n style={{\n width: '100%',\n padding: '6px 8px',\n fontSize: 13,\n fontFamily: 'inherit',\n border: `1px solid ${palette.border}`,\n borderRadius: 4,\n background: palette.inputBg,\n color: palette.text,\n boxSizing: 'border-box',\n }}\n />\n </div>\n\n {/* Category tabs — hidden when a search is active because the grid\n collapses across categories.\n\n Two-row grid layout: with 9 emoji buckets + 3 FA families we'd\n otherwise need a horizontal scrollbar to fit them all in the\n 480px-wide picker, and the scrollbar visually obscures the\n tabs themselves. A 6-column grid gives exactly two even rows\n that always fit without scrolling. */}\n {!query.trim() && (\n <div\n role=\"tablist\"\n aria-label=\"Emoji & icon categories\"\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(6, 1fr)',\n gap: 2,\n padding: '4px 6px',\n borderBottom: `1px solid ${palette.border}`,\n }}\n >\n {PICKER_CATEGORIES.map((cat) => {\n const active = cat.id === activeCategory;\n return (\n <button\n key={cat.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n aria-label={cat.label}\n title={cat.label}\n onClick={() => setActiveCategory(cat.id)}\n style={{\n fontSize: 18,\n lineHeight: 1,\n padding: '6px 0',\n cursor: 'pointer',\n background: active ? palette.accentSoft : 'transparent',\n border: '1px solid transparent',\n borderBottom: active ? `2px solid ${palette.accent}` : '2px solid transparent',\n borderRadius: 4,\n color: palette.text,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {cat.tab.kind === 'emoji' ? (\n cat.tab.char\n ) : (\n <i className={`fa-${cat.tab.family} fa-${cat.tab.name}`} aria-hidden=\"true\" />\n )}\n </button>\n );\n })}\n </div>\n )}\n\n {/* Grid — grows to fill the picker. The wrapper's `maxHeight`\n caps the popover overall (set on the root element above), so\n the grid scrolls only when the content doesn't fit. With the\n default sizing (480 wide × 560 tall, 10 columns) the common\n categories fit without a scrollbar at all. */}\n <div\n style={{\n padding: 6,\n flex: 1,\n minHeight: 0,\n overflowY: 'auto',\n display: 'grid',\n gridTemplateColumns: 'repeat(10, 1fr)',\n gap: 2,\n }}\n >\n {visibleEntries.length === 0 ? (\n <div\n style={{\n gridColumn: '1 / -1',\n padding: '20px 8px',\n textAlign: 'center',\n color: palette.textMuted,\n fontSize: 13,\n }}\n >\n {query.trim() ? `No matches for \"${query.trim()}\"` : 'No entries'}\n </div>\n ) : (\n visibleEntries.map((entry, idx) => {\n const tooltip = entry.kind === 'emoji' ? entry.name : entry.label;\n const key =\n entry.kind === 'emoji' ? `e-${entry.char}-${idx}` : `i-${entry.token}-${idx}`;\n return (\n <button\n key={key}\n type=\"button\"\n title={tooltip}\n aria-label={tooltip}\n data-picker-kind={entry.kind}\n onClick={() => onSelect(entry)}\n style={{\n fontSize: 22,\n lineHeight: 1,\n padding: 4,\n background: 'transparent',\n border: '1px solid transparent',\n borderRadius: 4,\n cursor: 'pointer',\n color: palette.text,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.background = palette.accentSoft;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.background = 'transparent';\n }}\n >\n {entry.kind === 'emoji' ? (\n entry.char\n ) : (\n <i className={`fa-${entry.family} fa-${entry.name}`} aria-hidden=\"true\" />\n )}\n </button>\n );\n })\n )}\n </div>\n </div>\n );\n}\n","/**\n * Emoji Dataset\n *\n * Curated set of common emoji grouped by Unicode CLDR category. Used by\n * `EmojiPicker` for both the category tabs and the search index.\n *\n * Each entry is a flat tuple `[char, name, ...keywords]` so the data\n * stays compact in source and is cheap to scan for the typeahead\n * search. Categories follow the official Unicode buckets in display\n * order (CLDR v44 grouping), trimmed to common picks per category —\n * we deliberately don't ship the whole Unicode emoji set (thousands)\n * because the picker is meant for quick insertion, not exhaustive\n * lookup; the user can paste anything we don't have.\n */\n\nexport interface EmojiEntry {\n /** The actual emoji glyph (may be multi-codepoint, e.g. ZWJ sequences). */\n char: string;\n /** Display name shown in the tooltip. */\n name: string;\n /** Lowercase keywords for the search index — name words plus aliases. */\n keywords: string;\n}\n\nexport interface EmojiCategory {\n id: string;\n label: string;\n /** Single-glyph icon shown on the tab. */\n icon: string;\n emojis: EmojiEntry[];\n}\n\nfunction e(char: string, name: string, ...kw: string[]): EmojiEntry {\n return { char, name, keywords: [name, ...kw].join(' ').toLowerCase() };\n}\n\nexport const EMOJI_CATEGORIES: EmojiCategory[] = [\n {\n id: 'smileys',\n label: 'Smileys',\n icon: '😀',\n emojis: [\n e('😀', 'grinning'),\n e('😃', 'smiley'),\n e('😄', 'smile', 'happy'),\n e('😁', 'grin', 'beaming'),\n e('😆', 'laughing'),\n e('😅', 'sweat smile'),\n e('🤣', 'rofl', 'rolling laughing'),\n e('😂', 'joy', 'laughing tears'),\n e('🙂', 'slight smile'),\n e('🙃', 'upside down'),\n e('😉', 'wink'),\n e('😊', 'blush'),\n e('😇', 'innocent', 'halo'),\n e('🥰', 'smiling hearts'),\n e('😍', 'heart eyes'),\n e('🤩', 'star struck'),\n e('😘', 'kiss', 'blow kiss'),\n e('😗', 'kissing'),\n e('😚', 'kissing closed eyes'),\n e('😙', 'kissing smile'),\n e('🥲', 'smiling tear'),\n e('😋', 'yum', 'tongue'),\n e('😛', 'tongue out'),\n e('😜', 'wink tongue'),\n e('🤪', 'zany', 'crazy'),\n e('😝', 'squint tongue'),\n e('🤑', 'money face'),\n e('🤗', 'hugging'),\n e('🤭', 'hand over mouth'),\n e('🤫', 'shushing'),\n e('🤔', 'thinking'),\n e('🤐', 'zipper mouth'),\n e('🤨', 'raised eyebrow'),\n e('😐', 'neutral'),\n e('😑', 'expressionless'),\n e('😶', 'no mouth'),\n e('😏', 'smirk'),\n e('😒', 'unamused'),\n e('🙄', 'eye roll'),\n e('😬', 'grimace'),\n e('🤥', 'lying', 'pinocchio'),\n e('😌', 'relieved'),\n e('😔', 'pensive'),\n e('😪', 'sleepy'),\n e('🤤', 'drool'),\n e('😴', 'sleeping', 'zzz'),\n e('😷', 'mask'),\n e('🤒', 'thermometer face'),\n e('🤕', 'head bandage'),\n e('🤢', 'nauseated'),\n e('🤮', 'vomiting'),\n e('🤧', 'sneeze'),\n e('🥵', 'hot face'),\n e('🥶', 'cold face'),\n e('🥴', 'woozy'),\n e('😵', 'dizzy'),\n e('🤯', 'mind blown', 'exploding head'),\n e('🤠', 'cowboy'),\n e('🥳', 'partying'),\n e('🥸', 'disguised'),\n e('😎', 'sunglasses', 'cool'),\n e('🤓', 'nerd', 'glasses'),\n e('🧐', 'monocle'),\n e('😕', 'confused'),\n e('😟', 'worried'),\n e('🙁', 'slight frown'),\n e('☹️', 'frown'),\n e('😮', 'open mouth'),\n e('😯', 'hushed'),\n e('😲', 'astonished'),\n e('😳', 'flushed'),\n e('🥺', 'pleading'),\n e('😦', 'frowning open mouth'),\n e('😧', 'anguished'),\n e('😨', 'fearful'),\n e('😰', 'anxious sweat'),\n e('😥', 'sad relieved'),\n e('😢', 'cry'),\n e('😭', 'sobbing', 'loud cry'),\n e('😱', 'screaming', 'shocked'),\n e('😖', 'confounded'),\n e('😣', 'persevering'),\n e('😞', 'disappointed'),\n e('😓', 'downcast sweat'),\n e('😩', 'weary'),\n e('😫', 'tired'),\n e('😤', 'triumph'),\n e('😡', 'pout', 'red angry'),\n e('😠', 'angry'),\n e('🤬', 'cursing', 'symbols'),\n e('😈', 'smiling devil'),\n e('👿', 'angry devil'),\n e('💀', 'skull'),\n e('💩', 'poop', 'pile'),\n e('🤡', 'clown'),\n e('👻', 'ghost'),\n e('👽', 'alien'),\n e('🤖', 'robot'),\n e('🎃', 'jack o lantern', 'pumpkin'),\n ],\n },\n {\n id: 'people',\n label: 'People',\n icon: '👋',\n emojis: [\n e('👋', 'wave', 'hello'),\n e('🤚', 'raised back hand'),\n e('🖐️', 'raised hand fingers'),\n e('✋', 'raised hand', 'stop'),\n e('🖖', 'vulcan'),\n e('👌', 'ok hand'),\n e('🤌', 'pinched fingers'),\n e('🤏', 'pinching'),\n e('✌️', 'peace'),\n e('🤞', 'crossed fingers', 'luck'),\n e('🤟', 'love you gesture'),\n e('🤘', 'rock on', 'horns'),\n e('🤙', 'call me'),\n e('👈', 'point left'),\n e('👉', 'point right'),\n e('👆', 'point up'),\n e('👇', 'point down'),\n e('☝️', 'index up'),\n e('👍', 'thumbs up', 'like'),\n e('👎', 'thumbs down', 'dislike'),\n e('✊', 'raised fist'),\n e('👊', 'oncoming fist', 'punch'),\n e('🤛', 'left fist', 'bump'),\n e('🤜', 'right fist'),\n e('👏', 'clap'),\n e('🙌', 'raised hands', 'praise'),\n e('👐', 'open hands'),\n e('🤲', 'palms up'),\n e('🤝', 'handshake'),\n e('🙏', 'pray', 'thanks'),\n e('💪', 'muscle', 'strong'),\n e('🦵', 'leg'),\n e('🦶', 'foot'),\n e('👂', 'ear'),\n e('🦻', 'ear hearing aid'),\n e('👃', 'nose'),\n e('🧠', 'brain'),\n e('🫀', 'heart anatomy'),\n e('🫁', 'lungs'),\n e('🦷', 'tooth'),\n e('🦴', 'bone'),\n e('👀', 'eyes'),\n e('👁️', 'eye'),\n e('👅', 'tongue'),\n e('👄', 'mouth'),\n e('💋', 'lipstick kiss'),\n e('👶', 'baby'),\n e('🧒', 'child'),\n e('👦', 'boy'),\n e('👧', 'girl'),\n e('🧑', 'person'),\n e('👨', 'man'),\n e('👩', 'woman'),\n e('🧓', 'older person'),\n e('👴', 'old man'),\n e('👵', 'old woman'),\n e('👮', 'police'),\n e('🕵️', 'detective'),\n e('💂', 'guard'),\n e('🧑‍⚕️', 'health worker'),\n e('🧑‍🎓', 'student'),\n e('🧑‍🏫', 'teacher'),\n e('🧑‍🔧', 'mechanic'),\n e('🧑‍💻', 'technologist', 'developer'),\n e('🧑‍🎨', 'artist'),\n e('🧑‍🚀', 'astronaut'),\n e('🧑‍🚒', 'firefighter'),\n e('👷', 'construction worker'),\n e('🤴', 'prince'),\n e('👸', 'princess'),\n e('🦸', 'superhero'),\n e('🦹', 'supervillain'),\n e('🧙', 'mage', 'wizard'),\n e('🧚', 'fairy'),\n e('🧛', 'vampire'),\n e('🧜', 'merperson'),\n e('🧝', 'elf'),\n e('🧞', 'genie'),\n e('🧟', 'zombie'),\n ],\n },\n {\n id: 'nature',\n label: 'Nature',\n icon: '🌿',\n emojis: [\n e('🐶', 'dog face'),\n e('🐱', 'cat face'),\n e('🐭', 'mouse'),\n e('🐹', 'hamster'),\n e('🐰', 'rabbit face'),\n e('🦊', 'fox'),\n e('🐻', 'bear'),\n e('🐼', 'panda'),\n e('🐻‍❄️', 'polar bear'),\n e('🐨', 'koala'),\n e('🐯', 'tiger face'),\n e('🦁', 'lion'),\n e('🐮', 'cow face'),\n e('🐷', 'pig face'),\n e('🐽', 'pig nose'),\n e('🐸', 'frog'),\n e('🐵', 'monkey face'),\n e('🙈', 'see no evil'),\n e('🙉', 'hear no evil'),\n e('🙊', 'speak no evil'),\n e('🐒', 'monkey'),\n e('🐔', 'chicken'),\n e('🐧', 'penguin'),\n e('🐦', 'bird'),\n e('🐤', 'baby chick'),\n e('🐣', 'hatching chick'),\n e('🦆', 'duck'),\n e('🦅', 'eagle'),\n e('🦉', 'owl'),\n e('🦇', 'bat'),\n e('🐺', 'wolf'),\n e('🐗', 'boar'),\n e('🐴', 'horse face'),\n e('🦄', 'unicorn'),\n e('🐝', 'bee'),\n e('🐛', 'bug'),\n e('🦋', 'butterfly'),\n e('🐌', 'snail'),\n e('🐞', 'lady beetle'),\n e('🐜', 'ant'),\n e('🦂', 'scorpion'),\n e('🕷️', 'spider'),\n e('🐢', 'turtle'),\n e('🐍', 'snake'),\n e('🦖', 'trex'),\n e('🦕', 'sauropod'),\n e('🐙', 'octopus'),\n e('🦑', 'squid'),\n e('🦐', 'shrimp'),\n e('🦞', 'lobster'),\n e('🦀', 'crab'),\n e('🐡', 'blowfish'),\n e('🐠', 'tropical fish'),\n e('🐟', 'fish'),\n e('🐬', 'dolphin'),\n e('🐳', 'spouting whale'),\n e('🐋', 'whale'),\n e('🦈', 'shark'),\n e('🐊', 'crocodile'),\n e('🐅', 'tiger'),\n e('🐆', 'leopard'),\n e('🦓', 'zebra'),\n e('🦍', 'gorilla'),\n e('🦧', 'orangutan'),\n e('🐘', 'elephant'),\n e('🦛', 'hippopotamus'),\n e('🦏', 'rhinoceros'),\n e('🐪', 'camel'),\n e('🐫', 'two hump camel'),\n e('🦒', 'giraffe'),\n e('🦘', 'kangaroo'),\n e('🐃', 'water buffalo'),\n e('🐂', 'ox'),\n e('🐄', 'cow'),\n e('🐎', 'horse'),\n e('🐖', 'pig'),\n e('🐏', 'ram'),\n e('🐑', 'ewe'),\n e('🦙', 'llama'),\n e('🐐', 'goat'),\n e('🦌', 'deer'),\n e('🐕', 'dog'),\n e('🐩', 'poodle'),\n e('🦮', 'guide dog'),\n e('🐕‍🦺', 'service dog'),\n e('🐈', 'cat'),\n e('🐈‍⬛', 'black cat'),\n e('🐓', 'rooster'),\n e('🦃', 'turkey'),\n e('🦚', 'peacock'),\n e('🦜', 'parrot'),\n e('🦢', 'swan'),\n e('🌲', 'evergreen tree'),\n e('🌳', 'deciduous tree'),\n e('🌴', 'palm tree'),\n e('🌵', 'cactus'),\n e('🌷', 'tulip'),\n e('🌸', 'cherry blossom'),\n e('🌹', 'rose'),\n e('🥀', 'wilted flower'),\n e('🌺', 'hibiscus'),\n e('🌻', 'sunflower'),\n e('🌼', 'blossom'),\n e('🌱', 'seedling'),\n e('🪴', 'potted plant'),\n e('🌿', 'herb'),\n e('☘️', 'shamrock'),\n e('🍀', 'four leaf clover'),\n e('🍁', 'maple leaf'),\n e('🍂', 'fallen leaf'),\n e('🍃', 'leaf wind'),\n e('🌞', 'sun face'),\n e('☀️', 'sun'),\n e('🌝', 'full moon face'),\n e('🌚', 'new moon face'),\n e('🌛', 'first quarter moon face'),\n e('🌜', 'last quarter moon face'),\n e('🌙', 'crescent moon'),\n e('🌎', 'earth americas'),\n e('🌍', 'earth europe africa'),\n e('🌏', 'earth asia australia'),\n e('🪐', 'ringed planet'),\n e('⭐', 'star'),\n e('🌟', 'glowing star'),\n e('✨', 'sparkles'),\n e('⚡', 'lightning', 'bolt'),\n e('☄️', 'comet'),\n e('🔥', 'fire'),\n e('💥', 'collision', 'boom'),\n e('🌈', 'rainbow'),\n e('☁️', 'cloud'),\n e('⛅', 'sun behind cloud'),\n e('🌧️', 'rain cloud'),\n e('⛈️', 'thunder cloud'),\n e('🌩️', 'lightning cloud'),\n e('🌨️', 'snow cloud'),\n e('❄️', 'snowflake'),\n e('⛄', 'snowman'),\n e('🌪️', 'tornado'),\n e('🌫️', 'fog'),\n e('🌊', 'wave'),\n e('💧', 'droplet'),\n e('💦', 'sweat drops'),\n ],\n },\n {\n id: 'food',\n label: 'Food',\n icon: '🍎',\n emojis: [\n e('🍏', 'green apple'),\n e('🍎', 'red apple'),\n e('🍐', 'pear'),\n e('🍊', 'tangerine', 'orange'),\n e('🍋', 'lemon'),\n e('🍌', 'banana'),\n e('🍉', 'watermelon'),\n e('🍇', 'grapes'),\n e('🍓', 'strawberry'),\n e('🫐', 'blueberries'),\n e('🍈', 'melon'),\n e('🍒', 'cherries'),\n e('🍑', 'peach'),\n e('🥭', 'mango'),\n e('🍍', 'pineapple'),\n e('🥥', 'coconut'),\n e('🥝', 'kiwi'),\n e('🍅', 'tomato'),\n e('🍆', 'eggplant'),\n e('🥑', 'avocado'),\n e('🥦', 'broccoli'),\n e('🥬', 'leafy green'),\n e('🥒', 'cucumber'),\n e('🌶️', 'pepper'),\n e('🫑', 'bell pepper'),\n e('🌽', 'corn'),\n e('🥕', 'carrot'),\n e('🫒', 'olive'),\n e('🧄', 'garlic'),\n e('🧅', 'onion'),\n e('🥔', 'potato'),\n e('🍠', 'sweet potato'),\n e('🥐', 'croissant'),\n e('🥯', 'bagel'),\n e('🍞', 'bread'),\n e('🥖', 'baguette'),\n e('🥨', 'pretzel'),\n e('🧀', 'cheese'),\n e('🥚', 'egg'),\n e('🍳', 'cooking', 'frying'),\n e('🧈', 'butter'),\n e('🥞', 'pancakes'),\n e('🧇', 'waffle'),\n e('🥓', 'bacon'),\n e('🥩', 'cut of meat'),\n e('🍗', 'poultry leg'),\n e('🍖', 'meat on bone'),\n e('🌭', 'hot dog'),\n e('🍔', 'hamburger'),\n e('🍟', 'fries'),\n e('🍕', 'pizza'),\n e('🥪', 'sandwich'),\n e('🌮', 'taco'),\n e('🌯', 'burrito'),\n e('🥙', 'stuffed flatbread'),\n e('🧆', 'falafel'),\n e('🥗', 'salad'),\n e('🥘', 'shallow pan of food'),\n e('🍝', 'spaghetti'),\n e('🍜', 'steaming bowl'),\n e('🍲', 'pot of food'),\n e('🍛', 'curry'),\n e('🍣', 'sushi'),\n e('🍱', 'bento'),\n e('🥟', 'dumpling'),\n e('🍤', 'shrimp tempura'),\n e('🍙', 'rice ball'),\n e('🍚', 'rice'),\n e('🍘', 'rice cracker'),\n e('🥠', 'fortune cookie'),\n e('🥮', 'moon cake'),\n e('🍢', 'oden'),\n e('🍡', 'dango'),\n e('🦪', 'oyster'),\n e('🍦', 'soft serve'),\n e('🍧', 'shaved ice'),\n e('🍨', 'ice cream'),\n e('🍩', 'doughnut'),\n e('🍪', 'cookie'),\n e('🎂', 'birthday cake'),\n e('🍰', 'shortcake'),\n e('🧁', 'cupcake'),\n e('🥧', 'pie'),\n e('🍫', 'chocolate bar'),\n e('🍬', 'candy'),\n e('🍭', 'lollipop'),\n e('🍮', 'custard'),\n e('🍯', 'honey'),\n e('🍼', 'baby bottle'),\n e('🥛', 'milk'),\n e('☕', 'coffee'),\n e('🫖', 'teapot'),\n e('🍵', 'tea'),\n e('🍶', 'sake'),\n e('🍾', 'champagne'),\n e('🍷', 'wine glass'),\n e('🍸', 'cocktail'),\n e('🍹', 'tropical drink'),\n e('🍺', 'beer'),\n e('🍻', 'clink beers'),\n e('🥂', 'clink champagne'),\n e('🥃', 'tumbler'),\n e('🥤', 'cup straw'),\n e('🧋', 'bubble tea'),\n e('🧃', 'juice box'),\n e('🧉', 'mate'),\n e('🧊', 'ice cube'),\n ],\n },\n {\n id: 'travel',\n label: 'Travel',\n icon: '✈️',\n emojis: [\n e('🚗', 'car'),\n e('🚕', 'taxi'),\n e('🚙', 'suv'),\n e('🚌', 'bus'),\n e('🚎', 'trolleybus'),\n e('🏎️', 'racing car'),\n e('🚓', 'police car'),\n e('🚑', 'ambulance'),\n e('🚒', 'fire engine'),\n e('🚐', 'minibus'),\n e('🛻', 'pickup truck'),\n e('🚚', 'delivery truck'),\n e('🚛', 'semi truck'),\n e('🚜', 'tractor'),\n e('🛵', 'motor scooter'),\n e('🏍️', 'motorcycle'),\n e('🚲', 'bicycle'),\n e('🛴', 'kick scooter'),\n e('🛹', 'skateboard'),\n e('🛼', 'roller skate'),\n e('🚂', 'locomotive'),\n e('🚃', 'railway car'),\n e('🚄', 'high speed train'),\n e('🚅', 'bullet train'),\n e('🚆', 'train'),\n e('🚇', 'metro'),\n e('🚈', 'light rail'),\n e('🚉', 'station'),\n e('🚝', 'monorail'),\n e('🚞', 'mountain railway'),\n e('🚋', 'tram'),\n e('🚊', 'tram car'),\n e('🚟', 'suspension railway'),\n e('🚠', 'mountain cableway'),\n e('🚡', 'aerial tramway'),\n e('✈️', 'airplane'),\n e('🛫', 'departing'),\n e('🛬', 'arriving'),\n e('🛩️', 'small airplane'),\n e('🚁', 'helicopter'),\n e('🛸', 'flying saucer'),\n e('🚀', 'rocket'),\n e('🛰️', 'satellite'),\n e('🛶', 'canoe'),\n e('⛵', 'sailboat'),\n e('🚤', 'speedboat'),\n e('🛥️', 'motor boat'),\n e('🛳️', 'passenger ship'),\n e('⛴️', 'ferry'),\n e('🚢', 'ship'),\n e('⚓', 'anchor'),\n e('🪝', 'hook'),\n e('⛽', 'fuel pump'),\n e('🚧', 'construction'),\n e('🚦', 'traffic light'),\n e('🚥', 'horizontal traffic light'),\n e('🗺️', 'map'),\n e('🗿', 'moai'),\n e('🗽', 'statue of liberty'),\n e('🗼', 'tokyo tower'),\n e('🏰', 'castle'),\n e('🏯', 'japanese castle'),\n e('🏟️', 'stadium'),\n e('🎡', 'ferris wheel'),\n e('🎢', 'roller coaster'),\n e('🎠', 'carousel'),\n e('⛲', 'fountain'),\n e('⛱️', 'umbrella ground'),\n e('🏖️', 'beach umbrella'),\n e('🏝️', 'desert island'),\n e('🏜️', 'desert'),\n e('🌋', 'volcano'),\n e('⛰️', 'mountain'),\n e('🏔️', 'snow mountain'),\n e('🗻', 'mount fuji'),\n e('🏕️', 'camping'),\n e('⛺', 'tent'),\n e('🛖', 'hut'),\n e('🏠', 'house'),\n e('🏡', 'house with garden'),\n e('🏘️', 'houses'),\n e('🏚️', 'derelict house'),\n e('🏗️', 'construction site'),\n e('🏭', 'factory'),\n e('🏢', 'office building'),\n e('🏬', 'department store'),\n e('🏣', 'japanese post office'),\n e('🏤', 'post office'),\n e('🏥', 'hospital'),\n e('🏦', 'bank'),\n e('🏨', 'hotel'),\n e('🏪', 'convenience store'),\n e('🏫', 'school'),\n e('🏩', 'love hotel'),\n e('💒', 'wedding'),\n e('🏛️', 'classical building'),\n e('⛪', 'church'),\n e('🕌', 'mosque'),\n e('🛕', 'hindu temple'),\n e('🕍', 'synagogue'),\n e('⛩️', 'shrine'),\n e('🌁', 'foggy city'),\n e('🌃', 'night stars'),\n e('🌄', 'sunrise mountains'),\n e('🌅', 'sunrise'),\n e('🌆', 'cityscape dusk'),\n e('🌇', 'sunset'),\n e('🌉', 'bridge night'),\n e('♨️', 'hot springs'),\n e('🎑', 'moon viewing'),\n e('🏞️', 'national park'),\n ],\n },\n {\n id: 'activities',\n label: 'Activities',\n icon: '⚽',\n emojis: [\n e('⚽', 'soccer'),\n e('🏀', 'basketball'),\n e('🏈', 'football'),\n e('⚾', 'baseball'),\n e('🥎', 'softball'),\n e('🎾', 'tennis'),\n e('🏐', 'volleyball'),\n e('🏉', 'rugby'),\n e('🥏', 'flying disc', 'frisbee'),\n e('🎱', 'pool', 'eight ball'),\n e('🪀', 'yoyo'),\n e('🏓', 'ping pong'),\n e('🏸', 'badminton'),\n e('🏒', 'ice hockey'),\n e('🏑', 'field hockey'),\n e('🥍', 'lacrosse'),\n e('🏏', 'cricket'),\n e('🪃', 'boomerang'),\n e('🥅', 'goal net'),\n e('⛳', 'flag in hole', 'golf'),\n e('🪁', 'kite'),\n e('🏹', 'bow and arrow'),\n e('🎣', 'fishing'),\n e('🤿', 'diving mask'),\n e('🥊', 'boxing glove'),\n e('🥋', 'martial arts'),\n e('🎽', 'running shirt'),\n e('🛹', 'skateboard'),\n e('🛼', 'roller skate'),\n e('🛷', 'sled'),\n e('⛸️', 'ice skate'),\n e('🥌', 'curling stone'),\n e('🎿', 'skis'),\n e('⛷️', 'skier'),\n e('🏂', 'snowboarder'),\n e('🪂', 'parachute'),\n e('🏋️', 'weight lifting'),\n e('🤼', 'wrestling'),\n e('🤸', 'cartwheel'),\n e('⛹️', 'bouncing ball'),\n e('🤺', 'fencing'),\n e('🤾', 'handball'),\n e('🏌️', 'golfing'),\n e('🏇', 'horse racing'),\n e('🧘', 'meditation', 'yoga'),\n e('🏄', 'surfing'),\n e('🏊', 'swimming'),\n e('🤽', 'water polo'),\n e('🚣', 'rowing'),\n e('🧗', 'climbing'),\n e('🚵', 'mountain biker'),\n e('🚴', 'biker'),\n e('🏆', 'trophy'),\n e('🥇', 'gold medal'),\n e('🥈', 'silver medal'),\n e('🥉', 'bronze medal'),\n e('🏅', 'sports medal'),\n e('🎖️', 'military medal'),\n e('🏵️', 'rosette'),\n e('🎗️', 'reminder ribbon'),\n e('🎫', 'ticket'),\n e('🎟️', 'admission tickets'),\n e('🎪', 'circus tent'),\n e('🎭', 'theatre masks'),\n e('🎨', 'art palette'),\n e('🎬', 'clapper board'),\n e('🎤', 'microphone'),\n e('🎧', 'headphone'),\n e('🎼', 'musical score'),\n e('🎹', 'piano'),\n e('🥁', 'drum'),\n e('🪘', 'long drum'),\n e('🎷', 'saxophone'),\n e('🎺', 'trumpet'),\n e('🎸', 'guitar'),\n e('🪕', 'banjo'),\n e('🎻', 'violin'),\n e('🪗', 'accordion'),\n e('🎲', 'game die'),\n e('♟️', 'chess pawn'),\n e('🎯', 'bullseye', 'dart'),\n e('🎳', 'bowling'),\n e('🎮', 'video game'),\n e('🎰', 'slot machine'),\n e('🧩', 'jigsaw'),\n ],\n },\n {\n id: 'objects',\n label: 'Objects',\n icon: '💡',\n emojis: [\n e('💡', 'light bulb', 'idea'),\n e('🔦', 'flashlight'),\n e('🕯️', 'candle'),\n e('🪔', 'diya lamp'),\n e('🧯', 'fire extinguisher'),\n e('🛢️', 'oil drum'),\n e('💸', 'money wings'),\n e('💵', 'dollar'),\n e('💴', 'yen banknote'),\n e('💶', 'euro banknote'),\n e('💷', 'pound banknote'),\n e('💰', 'money bag'),\n e('💳', 'credit card'),\n e('💎', 'gem'),\n e('⚖️', 'balance scale'),\n e('🪜', 'ladder'),\n e('🧰', 'toolbox'),\n e('🔧', 'wrench'),\n e('🪛', 'screwdriver'),\n e('🔨', 'hammer'),\n e('⚒️', 'hammer and pick'),\n e('🛠️', 'hammer and wrench'),\n e('⛏️', 'pick'),\n e('🪚', 'saw'),\n e('🔩', 'nut and bolt'),\n e('⚙️', 'gear'),\n e('🧱', 'brick'),\n e('⛓️', 'chains'),\n e('🧲', 'magnet'),\n e('🔫', 'water pistol'),\n e('💣', 'bomb'),\n e('🧨', 'firecracker'),\n e('🪓', 'axe'),\n e('🔪', 'kitchen knife'),\n e('🗡️', 'dagger'),\n e('⚔️', 'crossed swords'),\n e('🛡️', 'shield'),\n e('🚬', 'cigarette'),\n e('⚰️', 'coffin'),\n e('🪦', 'headstone'),\n e('⚱️', 'urn'),\n e('🏺', 'amphora'),\n e('🔮', 'crystal ball'),\n e('📿', 'prayer beads'),\n e('🧿', 'nazar amulet'),\n e('💈', 'barber pole'),\n e('⚗️', 'alembic'),\n e('🔭', 'telescope'),\n e('🔬', 'microscope'),\n e('🕳️', 'hole'),\n e('🩹', 'bandage'),\n e('🩺', 'stethoscope'),\n e('💊', 'pill'),\n e('💉', 'syringe'),\n e('🩸', 'blood drop'),\n e('🧬', 'dna'),\n e('🦠', 'microbe'),\n e('🧫', 'petri dish'),\n e('🧪', 'test tube'),\n e('🌡️', 'thermometer'),\n e('🧹', 'broom'),\n e('🪠', 'plunger'),\n e('🧺', 'basket'),\n e('🧻', 'roll of paper'),\n e('🚽', 'toilet'),\n e('🚰', 'tap water'),\n e('🚿', 'shower'),\n e('🛁', 'bathtub'),\n e('🛀', 'person bathing'),\n e('🧼', 'soap'),\n e('🪥', 'toothbrush'),\n e('🪒', 'razor'),\n e('🧽', 'sponge'),\n e('🪣', 'bucket'),\n e('🧴', 'lotion'),\n e('🛎️', 'bellhop bell'),\n e('🔑', 'key'),\n e('🗝️', 'old key'),\n e('🚪', 'door'),\n e('🪑', 'chair'),\n e('🛋️', 'couch'),\n e('🛏️', 'bed'),\n e('🛌', 'person in bed'),\n e('🧸', 'teddy bear'),\n e('🖼️', 'framed picture'),\n e('🪞', 'mirror'),\n e('🪟', 'window'),\n e('🛍️', 'shopping bags'),\n e('🛒', 'cart'),\n e('🎁', 'gift'),\n e('🎀', 'ribbon'),\n e('🎊', 'confetti ball'),\n e('🎉', 'party popper', 'celebration'),\n e('🎈', 'balloon'),\n e('🪄', 'magic wand'),\n e('📱', 'mobile'),\n e('📲', 'incoming phone'),\n e('☎️', 'phone'),\n e('📞', 'phone receiver'),\n e('📟', 'pager'),\n e('📠', 'fax'),\n e('🔋', 'battery'),\n e('🔌', 'plug'),\n e('💻', 'laptop'),\n e('🖥️', 'desktop'),\n e('🖨️', 'printer'),\n e('⌨️', 'keyboard'),\n e('🖱️', 'mouse'),\n e('🖲️', 'trackball'),\n e('💽', 'minidisc'),\n e('💾', 'floppy', 'save'),\n e('💿', 'cd'),\n e('📀', 'dvd'),\n e('🧮', 'abacus'),\n e('🎥', 'movie camera'),\n e('🎞️', 'film frames'),\n e('📽️', 'film projector'),\n e('📺', 'television'),\n e('📷', 'camera'),\n e('📸', 'camera flash'),\n e('📹', 'video camera'),\n e('📼', 'videocassette'),\n e('🔍', 'magnifying left'),\n e('🔎', 'magnifying right'),\n e('🕰️', 'mantelpiece clock'),\n e('⏰', 'alarm clock'),\n e('⏱️', 'stopwatch'),\n e('⏲️', 'timer'),\n e('⏳', 'hourglass flowing'),\n e('⌛', 'hourglass done'),\n e('📡', 'satellite antenna'),\n e('📚', 'books'),\n e('📖', 'open book'),\n e('🔖', 'bookmark'),\n e('🏷️', 'tag'),\n e('📰', 'newspaper'),\n e('🗞️', 'rolled newspaper'),\n e('📄', 'page'),\n e('📃', 'page curl'),\n e('📑', 'bookmark tabs'),\n e('📜', 'scroll'),\n e('📋', 'clipboard'),\n e('📅', 'calendar'),\n e('📆', 'tear off calendar'),\n e('🗓️', 'spiral calendar'),\n e('📇', 'card index'),\n e('🗃️', 'card file box'),\n e('🗳️', 'ballot box'),\n e('🗄️', 'file cabinet'),\n e('📂', 'open folder'),\n e('📁', 'folder'),\n e('📊', 'bar chart'),\n e('📈', 'chart up'),\n e('📉', 'chart down'),\n e('📌', 'pushpin'),\n e('📍', 'round pushpin'),\n e('📎', 'paperclip'),\n e('🖇️', 'linked paperclips'),\n e('📏', 'straight ruler'),\n e('📐', 'triangular ruler'),\n e('✂️', 'scissors'),\n e('🖊️', 'pen'),\n e('🖋️', 'fountain pen'),\n e('✒️', 'black nib'),\n e('🖌️', 'paintbrush'),\n e('🖍️', 'crayon'),\n e('📝', 'memo', 'note'),\n e('✏️', 'pencil'),\n e('🔏', 'locked with pen'),\n e('🔐', 'locked with key'),\n e('🔒', 'locked'),\n e('🔓', 'unlocked'),\n e('🧿', 'amulet'),\n e('🪬', 'hamsa'),\n ],\n },\n {\n id: 'symbols',\n label: 'Symbols',\n icon: '❤️',\n emojis: [\n e('❤️', 'red heart'),\n e('🧡', 'orange heart'),\n e('💛', 'yellow heart'),\n e('💚', 'green heart'),\n e('💙', 'blue heart'),\n e('💜', 'purple heart'),\n e('🖤', 'black heart'),\n e('🤍', 'white heart'),\n e('🤎', 'brown heart'),\n e('💔', 'broken heart'),\n e('❣️', 'heart exclamation'),\n e('💕', 'two hearts'),\n e('💞', 'revolving hearts'),\n e('💓', 'beating heart'),\n e('💗', 'growing heart'),\n e('💖', 'sparkling heart'),\n e('💘', 'heart arrow'),\n e('💝', 'heart with ribbon'),\n e('💟', 'heart decoration'),\n e('☮️', 'peace'),\n e('✝️', 'cross'),\n e('☪️', 'star and crescent'),\n e('🕉️', 'om'),\n e('☸️', 'wheel of dharma'),\n e('✡️', 'star of david'),\n e('🔯', 'six pointed star'),\n e('🕎', 'menorah'),\n e('☯️', 'yin yang'),\n e('☦️', 'orthodox cross'),\n e('🛐', 'place of worship'),\n e('⛎', 'ophiuchus'),\n e('♈', 'aries'),\n e('♉', 'taurus'),\n e('♊', 'gemini'),\n e('♋', 'cancer'),\n e('♌', 'leo'),\n e('♍', 'virgo'),\n e('♎', 'libra'),\n e('♏', 'scorpio'),\n e('♐', 'sagittarius'),\n e('♑', 'capricorn'),\n e('♒', 'aquarius'),\n e('♓', 'pisces'),\n e('🆔', 'id'),\n e('⚛️', 'atom'),\n e('🉑', 'accept'),\n e('☢️', 'radioactive'),\n e('☣️', 'biohazard'),\n e('📴', 'phone off'),\n e('📳', 'vibration'),\n e('🈶', 'not free'),\n e('🈚', 'free'),\n e('🈸', 'application'),\n e('🈺', 'open for business'),\n e('🈷️', 'monthly amount'),\n e('✴️', 'eight pointed star'),\n e('🆚', 'vs'),\n e('💮', 'white flower'),\n e('🉐', 'bargain'),\n e('㊙️', 'secret'),\n e('㊗️', 'congratulations'),\n e('🈴', 'passing grade'),\n e('🈵', 'no vacancy'),\n e('🈹', 'discount'),\n e('🈲', 'prohibited'),\n e('🅰️', 'a button'),\n e('🅱️', 'b button'),\n e('🆎', 'ab button'),\n e('🆑', 'cl button'),\n e('🅾️', 'o button'),\n e('🆘', 'sos'),\n e('❌', 'cross mark'),\n e('⭕', 'circle'),\n e('🛑', 'stop sign'),\n e('⛔', 'no entry'),\n e('📛', 'name badge'),\n e('🚫', 'prohibited sign'),\n e('💯', '100', 'hundred'),\n e('💢', 'anger'),\n e('♨️', 'hot springs'),\n e('🚷', 'no pedestrians'),\n e('🚯', 'no littering'),\n e('🚳', 'no bicycles'),\n e('🚱', 'non potable'),\n e('🔞', 'no minors'),\n e('📵', 'no phones'),\n e('🚭', 'no smoking'),\n e('❗', 'exclamation'),\n e('❕', 'white exclamation'),\n e('❓', 'question'),\n e('❔', 'white question'),\n e('‼️', 'double exclamation'),\n e('⁉️', 'exclamation question'),\n e('🔅', 'dim'),\n e('🔆', 'bright'),\n e('〽️', 'part alternation'),\n e('⚠️', 'warning'),\n e('🚸', 'children crossing'),\n e('🔱', 'trident'),\n e('⚜️', 'fleur de lis'),\n e('🔰', 'beginner'),\n e('♻️', 'recycle'),\n e('✅', 'check mark'),\n e('🈯', 'reserved'),\n e('💹', 'chart with yen'),\n e('❇️', 'sparkle'),\n e('✳️', 'eight spoked asterisk'),\n e('❎', 'cross box'),\n e('🌐', 'globe meridians'),\n e('💠', 'diamond'),\n e('Ⓜ️', 'circled m'),\n e('🌀', 'cyclone'),\n e('💤', 'zzz', 'sleep'),\n e('🏧', 'atm'),\n e('🚾', 'water closet'),\n e('♿', 'wheelchair'),\n e('🅿️', 'parking'),\n e('🛗', 'elevator'),\n e('🈳', 'vacancy'),\n e('🈂️', 'service'),\n e('🛂', 'passport control'),\n e('🛃', 'customs'),\n e('🛄', 'baggage claim'),\n e('🛅', 'left luggage'),\n e('🚹', 'mens'),\n e('🚺', 'womens'),\n e('🚼', 'baby symbol'),\n e('🚻', 'restroom'),\n e('🚮', 'litter bin'),\n e('🎦', 'cinema'),\n e('📶', 'antenna bars'),\n e('🈁', 'here'),\n e('🔣', 'input symbols'),\n e('ℹ️', 'info'),\n e('🔤', 'input latin'),\n e('🔡', 'input lowercase'),\n e('🔠', 'input uppercase'),\n e('🆖', 'ng'),\n e('🆗', 'ok'),\n e('🆙', 'up'),\n e('🆒', 'cool'),\n e('🆕', 'new'),\n e('🆓', 'free'),\n e('0️⃣', 'keycap 0'),\n e('1️⃣', 'keycap 1'),\n e('2️⃣', 'keycap 2'),\n e('3️⃣', 'keycap 3'),\n e('4️⃣', 'keycap 4'),\n e('5️⃣', 'keycap 5'),\n e('6️⃣', 'keycap 6'),\n e('7️⃣', 'keycap 7'),\n e('8️⃣', 'keycap 8'),\n e('9️⃣', 'keycap 9'),\n e('🔟', 'keycap 10'),\n e('🔢', 'input numbers'),\n e('#️⃣', 'keycap hash'),\n e('*️⃣', 'keycap asterisk'),\n e('▶️', 'play'),\n e('⏸️', 'pause'),\n e('⏯️', 'play or pause'),\n e('⏹️', 'stop button'),\n e('⏺️', 'record'),\n e('⏭️', 'next track'),\n e('⏮️', 'last track'),\n e('⏩', 'fast forward'),\n e('⏪', 'fast reverse'),\n e('⏫', 'fast up'),\n e('⏬', 'fast down'),\n e('◀️', 'reverse'),\n e('🔼', 'up button'),\n e('🔽', 'down button'),\n e('➡️', 'right arrow'),\n e('⬅️', 'left arrow'),\n e('⬆️', 'up arrow'),\n e('⬇️', 'down arrow'),\n e('↗️', 'up right arrow'),\n e('↘️', 'down right arrow'),\n e('↙️', 'down left arrow'),\n e('↖️', 'up left arrow'),\n e('↕️', 'up down arrow'),\n e('↔️', 'left right arrow'),\n e('↪️', 'right arrow curving'),\n e('↩️', 'left arrow curving'),\n e('⤴️', 'arrow up curve'),\n e('⤵️', 'arrow down curve'),\n e('🔀', 'shuffle'),\n e('🔁', 'repeat'),\n e('🔂', 'repeat single'),\n e('🔄', 'arrows ccw'),\n e('🔃', 'arrows cw'),\n e('🎵', 'note'),\n e('🎶', 'notes'),\n e('➕', 'plus'),\n e('➖', 'minus'),\n e('➗', 'divide'),\n e('✖️', 'multiply'),\n e('🟰', 'equals'),\n e('♾️', 'infinity'),\n e('💲', 'dollar'),\n e('💱', 'currency exchange'),\n e('™️', 'tm'),\n e('©️', 'copyright'),\n e('®️', 'registered'),\n e('〰️', 'wavy'),\n e('➰', 'curly loop'),\n e('➿', 'double curly loop'),\n e('🔚', 'end'),\n e('🔙', 'back'),\n e('🔛', 'on'),\n e('🔝', 'top'),\n e('🔜', 'soon'),\n e('✔️', 'check'),\n e('☑️', 'ballot box check'),\n e('🔘', 'radio button'),\n e('🔴', 'red circle'),\n e('🟠', 'orange circle'),\n e('🟡', 'yellow circle'),\n e('🟢', 'green circle'),\n e('🔵', 'blue circle'),\n e('🟣', 'purple circle'),\n e('🟤', 'brown circle'),\n e('⚫', 'black circle'),\n e('⚪', 'white circle'),\n e('🟥', 'red square'),\n e('🟧', 'orange square'),\n e('🟨', 'yellow square'),\n e('🟩', 'green square'),\n e('🟦', 'blue square'),\n e('🟪', 'purple square'),\n e('🟫', 'brown square'),\n e('⬛', 'black square'),\n e('⬜', 'white square'),\n e('◼️', 'medium black square'),\n e('◻️', 'medium white square'),\n e('◾', 'small black square'),\n e('◽', 'small white square'),\n e('▪️', 'tiny black square'),\n e('▫️', 'tiny white square'),\n e('🔶', 'large orange diamond'),\n e('🔷', 'large blue diamond'),\n e('🔸', 'small orange diamond'),\n e('🔹', 'small blue diamond'),\n e('🔺', 'red triangle up'),\n e('🔻', 'red triangle down'),\n e('🔳', 'white square button'),\n e('🔲', 'black square button'),\n ],\n },\n {\n id: 'flags',\n label: 'Flags',\n icon: '🏳️',\n emojis: [\n e('🏁', 'checkered flag'),\n e('🚩', 'triangular flag'),\n e('🎌', 'crossed flags'),\n e('🏴', 'black flag'),\n e('🏳️', 'white flag'),\n e('🏳️‍🌈', 'rainbow flag'),\n e('🏳️‍⚧️', 'transgender flag'),\n e('🏴‍☠️', 'pirate flag'),\n e('🇺🇸', 'united states', 'us', 'usa'),\n e('🇨🇦', 'canada'),\n e('🇲🇽', 'mexico'),\n e('🇬🇧', 'united kingdom', 'uk'),\n e('🇮🇪', 'ireland'),\n e('🇫🇷', 'france'),\n e('🇩🇪', 'germany'),\n e('🇮🇹', 'italy'),\n e('🇪🇸', 'spain'),\n e('🇵🇹', 'portugal'),\n e('🇳🇱', 'netherlands'),\n e('🇧🇪', 'belgium'),\n e('🇨🇭', 'switzerland'),\n e('🇦🇹', 'austria'),\n e('🇸🇪', 'sweden'),\n e('🇳🇴', 'norway'),\n e('🇩🇰', 'denmark'),\n e('🇫🇮', 'finland'),\n e('🇮🇸', 'iceland'),\n e('🇵🇱', 'poland'),\n e('🇨🇿', 'czech republic'),\n e('🇸🇰', 'slovakia'),\n e('🇭🇺', 'hungary'),\n e('🇷🇴', 'romania'),\n e('🇧🇬', 'bulgaria'),\n e('🇬🇷', 'greece'),\n e('🇹🇷', 'turkey'),\n e('🇷🇺', 'russia'),\n e('🇺🇦', 'ukraine'),\n e('🇨🇳', 'china'),\n e('🇯🇵', 'japan'),\n e('🇰🇷', 'south korea', 'korea'),\n e('🇮🇳', 'india'),\n e('🇵🇰', 'pakistan'),\n e('🇧🇩', 'bangladesh'),\n e('🇹🇭', 'thailand'),\n e('🇻🇳', 'vietnam'),\n e('🇮🇩', 'indonesia'),\n e('🇵🇭', 'philippines'),\n e('🇲🇾', 'malaysia'),\n e('🇸🇬', 'singapore'),\n e('🇦🇺', 'australia'),\n e('🇳🇿', 'new zealand'),\n e('🇧🇷', 'brazil'),\n e('🇦🇷', 'argentina'),\n e('🇨🇱', 'chile'),\n e('🇨🇴', 'colombia'),\n e('🇵🇪', 'peru'),\n e('🇻🇪', 'venezuela'),\n e('🇿🇦', 'south africa'),\n e('🇪🇬', 'egypt'),\n e('🇲🇦', 'morocco'),\n e('🇰🇪', 'kenya'),\n e('🇳🇬', 'nigeria'),\n e('🇸🇦', 'saudi arabia'),\n e('🇦🇪', 'uae'),\n e('🇮🇱', 'israel'),\n e('🇮🇷', 'iran'),\n e('🇮🇶', 'iraq'),\n e('🇸🇾', 'syria'),\n e('🇱🇧', 'lebanon'),\n e('🇯🇴', 'jordan'),\n e('🇪🇺', 'european union', 'eu'),\n e('🇺🇳', 'united nations', 'un'),\n ],\n },\n];\n\n/**\n * Flat list of every emoji across all categories — used as the search\n * corpus and to expose a `getEmojiByChar` lookup.\n */\nexport const ALL_EMOJIS: EmojiEntry[] = EMOJI_CATEGORIES.flatMap((c) => c.emojis);\n\n/** Search for emoji whose name or keywords contain the query (case-insensitive). */\nexport function searchEmojis(query: string, limit = 80): EmojiEntry[] {\n const q = query.trim().toLowerCase();\n if (!q) return [];\n const out: EmojiEntry[] = [];\n for (const entry of ALL_EMOJIS) {\n if (entry.keywords.includes(q)) {\n out.push(entry);\n if (out.length >= limit) break;\n }\n }\n return out;\n}\n\n// ── Unified picker entries (emoji + FontAwesome icons) ─────────────\n\nimport { ICONS } from '@bendyline/squisq/icons';\nimport { canonicalIconToken } from '@bendyline/squisq/icons';\nimport type { IconEntry, IconFamily } from '@bendyline/squisq/icons';\n\n/**\n * Discriminated picker entry. The picker UI dispatches on `kind` to\n * render either an emoji glyph or a FontAwesome `<i>` element. The\n * Toolbar consumes the selected entry to insert into the editor.\n */\nexport type PickerEntry =\n | { kind: 'emoji'; char: string; name: string; keywords: string }\n | {\n kind: 'icon';\n family: IconFamily;\n name: string;\n label: string;\n keywords: string;\n /** Canonical token used in the markdown source (bare or qualified). */\n token: string;\n };\n\nexport interface PickerCategory {\n id: string;\n label: string;\n /** What to render on the category tab. Emoji glyph or FA class. */\n tab: { kind: 'emoji'; char: string } | { kind: 'icon'; family: IconFamily; name: string };\n entries: PickerEntry[];\n}\n\nfunction buildIconCategory(family: IconFamily, label: string): PickerCategory {\n // Pick a representative icon for the tab — `github` for brands, `house` for solid,\n // `face-smile` for regular. We fall back to the family's first entry if the\n // representative is missing in a future FA version.\n const repName = family === 'brands' ? 'github' : family === 'solid' ? 'house' : 'face-smile';\n const familyIcons = ICONS.filter((i) => i.family === family);\n const rep = familyIcons.find((i) => i.name === repName) ?? familyIcons[0];\n const tabIcon = rep\n ? { kind: 'icon' as const, family, name: rep.name }\n : { kind: 'emoji' as const, char: '◆' };\n return {\n id: `fa-${family}`,\n label,\n tab: tabIcon,\n entries: familyIcons.map(\n (i: IconEntry): PickerEntry => ({\n kind: 'icon',\n family: i.family,\n name: i.name,\n label: i.label,\n keywords: i.keywords,\n token: canonicalIconToken(i),\n }),\n ),\n };\n}\n\n/**\n * The full picker category list — emoji buckets followed by the three\n * FontAwesome families. Drives the EmojiPicker tabs.\n */\nexport const PICKER_CATEGORIES: PickerCategory[] = [\n ...EMOJI_CATEGORIES.map(\n (c): PickerCategory => ({\n id: c.id,\n label: c.label,\n tab: { kind: 'emoji', char: c.icon },\n entries: c.emojis.map(\n (e): PickerEntry => ({\n kind: 'emoji',\n char: e.char,\n name: e.name,\n keywords: e.keywords,\n }),\n ),\n }),\n ),\n buildIconCategory('brands', 'Brands'),\n buildIconCategory('solid', 'Solid'),\n buildIconCategory('regular', 'Regular'),\n];\n\n/** Flat corpus for the picker search index. */\nexport const ALL_PICKER_ENTRIES: PickerEntry[] = PICKER_CATEGORIES.flatMap((c) => c.entries);\n\n/** Lowercase substring search across emoji + icon entries. */\nexport function searchPickerEntries(query: string, limit = 80): PickerEntry[] {\n const q = query.trim().toLowerCase();\n if (!q) return [];\n const out: PickerEntry[] = [];\n for (const entry of ALL_PICKER_ENTRIES) {\n if (entry.keywords.includes(q)) {\n out.push(entry);\n if (out.length >= limit) break;\n }\n }\n return out;\n}\n","/**\n * StatusBar\n *\n * Bottom status bar showing document statistics and parse status.\n */\n\nimport { useMemo } from 'react';\nimport { useEditorContext } from './EditorContext';\n\nexport interface StatusBarProps {\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Status bar displaying document statistics: character count, word count,\n * block count, and parse/error status.\n */\nexport function StatusBar({ className }: StatusBarProps) {\n const { markdownSource, doc, parseError, isParsing } = useEditorContext();\n\n const stats = useMemo(() => {\n const chars = markdownSource.length;\n const words = markdownSource.trim() ? markdownSource.trim().split(/\\s+/).length : 0;\n const lines = markdownSource.split('\\n').length;\n const blocks = doc?.blocks.length ?? 0;\n return { chars, words, lines, blocks };\n }, [markdownSource, doc]);\n\n return (\n <div className={`squisq-status-bar ${className || ''}`}>\n <span className=\"squisq-status-item\">{stats.words} words</span>\n <span className=\"squisq-status-item\">{stats.chars} chars</span>\n <span className=\"squisq-status-item\">{stats.lines} lines</span>\n <span className=\"squisq-status-item\">{stats.blocks} blocks</span>\n <span className=\"squisq-status-spacer\" />\n {isParsing && <span className=\"squisq-status-item squisq-status-parsing\">Parsing…</span>}\n {parseError && (\n <span className=\"squisq-status-item squisq-status-error\" title={parseError}>\n ⚠ Error\n </span>\n )}\n {!isParsing && !parseError && (\n <span className=\"squisq-status-item squisq-status-ok\">✓ OK</span>\n )}\n </div>\n );\n}\n","/**\n * RawEditor\n *\n * Monaco-based raw markdown editor. Provides full VS Code-like editing\n * experience with syntax highlighting, minimap, and bracket matching.\n * Syncs changes back to EditorContext on every keystroke (debounced).\n */\n\nimport { useRef, useCallback, useEffect } from 'react';\nimport Editor, { type OnMount, type OnChange, type BeforeMount } from '@monaco-editor/react';\nimport type * as monaco from 'monaco-editor';\nimport { useEditorContext } from './EditorContext';\nimport { getAvailableTemplates } from '@bendyline/squisq/doc';\nimport { suggestIcons, resolveIcon, iconGlyph } from '@bendyline/squisq/icons';\nimport { SQUISQ_MEDIA_MIME, parseSquisqMediaPayload } from './mediaDragMime';\nimport { useMonacoLoader } from './useMonacoLoader';\n\n// Monaco is loaded lazily through `useMonacoLoader` (see the hook for the\n// rationale). The type-only `import type * as monaco from 'monaco-editor'`\n// above gives us `monaco.editor.IStandaloneCodeEditor`, `monaco.Range`,\n// etc. for typing without pulling the package into the static module\n// graph — which is the whole point: a consumer importing `JsonEditor` or\n// a type from the package barrel no longer drags ~9MB of language\n// services into the resolver.\n//\n// Consumers that *do* want the raw editor can still slim the bundle by\n// aliasing `monaco-editor` to a custom entry in their bundler config.\n// For example with Vite:\n//\n// resolve: { alias: [{ find: /^monaco-editor$/, replacement: './monaco-slim.ts' }] }\n//\n// Where monaco-slim.ts re-exports 'monaco-editor/esm/vs/editor/editor.api'\n// plus only the language contributions needed (e.g. markdown, javascript).\n\n// Squisq Monaco themes: same syntax highlighting as vs / vs-dark, but with\n// Monaco's internal gutter (line numbers + folding margin) and overview\n// ruler tinted to match the side-pane \"desk\" colors so the canvas's\n// internal furniture blends with its surroundings. The seam color is the\n// 1px line Monaco draws between the white canvas and the overview ruler;\n// matches the `::after` border on `.margin` so both sides of the canvas\n// frame look the same.\nconst SQUISQ_LIGHT_GUTTER = '#dcd8d0';\nconst SQUISQ_DARK_GUTTER = '#0f1219';\nconst SQUISQ_LIGHT_SEAM = '#b0a99a';\nconst SQUISQ_DARK_SEAM = '#2a3144';\n\nconst SQUISQ_THEMES: Record<string, string> = {\n vs: 'squisq-light',\n 'vs-dark': 'squisq-dark',\n};\n\nexport interface RawEditorProps {\n /** Monaco editor theme (default: 'vs-dark') */\n theme?: string;\n /** Show minimap (default: false) */\n minimap?: boolean;\n /** Font size in pixels (default: 14) */\n fontSize?: number;\n /** Word wrap setting (default: 'on') */\n wordWrap?: 'on' | 'off' | 'wordWrapColumn' | 'bounded';\n /** Additional class name for the container */\n className?: string;\n /**\n * Chat-composer mode: Enter fires this callback (submit) and Cmd/Ctrl+Enter\n * inserts a newline. When undefined, behaves normally.\n */\n submitOnEnter?: () => void;\n /** Make Monaco read-only (no edits, no cursor blink). */\n readOnly?: boolean;\n}\n\n/**\n * Raw markdown editor using Monaco Editor.\n * Binds to the shared EditorContext for source synchronization.\n */\nexport function RawEditor({\n theme = 'vs',\n minimap = false,\n fontSize = 14,\n wordWrap = 'on',\n className,\n submitOnEnter,\n readOnly = false,\n}: RawEditorProps) {\n const { markdownSource, setMarkdownSource, setMonacoEditor, language, mentionProvider } =\n useEditorContext();\n const { monaco: monacoNs, ready: monacoReady } = useMonacoLoader();\n const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);\n const isExternalUpdate = useRef(false);\n const completionDisposable = useRef<monaco.IDisposable | null>(null);\n const mentionCompletionDisposable = useRef<monaco.IDisposable | null>(null);\n const iconCompletionDisposable = useRef<monaco.IDisposable | null>(null);\n const iconGlyphDecorations = useRef<monaco.editor.IEditorDecorationsCollection | null>(null);\n const dropCleanupRef = useRef<(() => void) | null>(null);\n const keyDisposable = useRef<monaco.IDisposable | null>(null);\n // Ref so the keydown handler always sees the latest callback.\n const submitOnEnterRef = useRef(submitOnEnter);\n useEffect(() => {\n submitOnEnterRef.current = submitOnEnter;\n }, [submitOnEnter]);\n // Ref so the completion provider — registered once at mount — always\n // sees the latest mentionProvider without needing to unregister.\n const mentionProviderRef = useRef(mentionProvider);\n useEffect(() => {\n mentionProviderRef.current = mentionProvider;\n }, [mentionProvider]);\n\n const handleBeforeMount: BeforeMount = useCallback((monaco) => {\n monaco.editor.defineTheme('squisq-light', {\n base: 'vs',\n inherit: true,\n rules: [],\n colors: {\n 'editorGutter.background': SQUISQ_LIGHT_GUTTER,\n 'editorOverviewRuler.background': SQUISQ_LIGHT_GUTTER,\n 'editorOverviewRuler.border': SQUISQ_LIGHT_SEAM,\n 'minimap.background': SQUISQ_LIGHT_GUTTER,\n },\n });\n monaco.editor.defineTheme('squisq-dark', {\n base: 'vs-dark',\n inherit: true,\n rules: [],\n colors: {\n 'editorGutter.background': SQUISQ_DARK_GUTTER,\n 'editorOverviewRuler.background': SQUISQ_DARK_GUTTER,\n 'editorOverviewRuler.border': SQUISQ_DARK_SEAM,\n 'minimap.background': SQUISQ_DARK_GUTTER,\n },\n });\n }, []);\n\n const handleMount: OnMount = useCallback(\n (editor, monaco) => {\n editorRef.current = editor;\n setMonacoEditor(editor);\n editor.focus();\n\n // Dispose any previous completion provider (from a prior mount)\n completionDisposable.current?.dispose();\n completionDisposable.current = null;\n mentionCompletionDisposable.current?.dispose();\n mentionCompletionDisposable.current = null;\n iconCompletionDisposable.current?.dispose();\n iconCompletionDisposable.current = null;\n\n // Register the `{[template]}` completion provider only for markdown\n // files — it's meaningless for TypeScript, JSON, Python, etc.\n if (language === 'markdown') {\n const templates = getAvailableTemplates();\n completionDisposable.current = monaco.languages.registerCompletionItemProvider('markdown', {\n triggerCharacters: ['['],\n provideCompletionItems(model: monaco.editor.ITextModel, position: monaco.Position) {\n const lineContent = model.getLineContent(position.lineNumber);\n\n // Only trigger inside a heading line that has {[ before the cursor\n if (!/^#{1,6}\\s/.test(lineContent)) return { suggestions: [] };\n\n const textBeforeCursor = lineContent.substring(0, position.column - 1);\n const textAfterCursor = lineContent.substring(position.column - 1);\n const bracketIdx = textBeforeCursor.lastIndexOf('{[');\n if (bracketIdx === -1) return { suggestions: [] };\n\n // When Monaco's bracket auto-pair has already produced the\n // closing `]}` we just leave it in place and skip the\n // suffix — otherwise accepting `sectionHeader` on\n // `{[gi]}` would yield `{[sectionHeader]}]}`.\n const closingMatch = textAfterCursor.match(/^\\]\\}/);\n const suffix = closingMatch ? '' : ']}';\n\n const startCol = bracketIdx + 3; // after {[\n const range = new monaco.Range(\n position.lineNumber,\n startCol,\n position.lineNumber,\n position.column,\n );\n\n const suggestions = templates.map((name) => ({\n label: name,\n filterText: name,\n kind: monaco.languages.CompletionItemKind.Value,\n insertText: name + suffix,\n range,\n detail: 'Block template',\n sortText: name,\n }));\n\n return { suggestions };\n },\n });\n\n // `@mention` completion — queries the shared MentionProvider. Keep\n // this in its own registration so we can dispose it independently\n // of the template provider, and so the trigger character is just\n // `@` (not `[`).\n mentionCompletionDisposable.current = monaco.languages.registerCompletionItemProvider(\n 'markdown',\n {\n triggerCharacters: ['@'],\n async provideCompletionItems(model, position) {\n const provider = mentionProviderRef.current;\n if (!provider) return { suggestions: [] };\n const lineContent = model.getLineContent(position.lineNumber);\n const textBeforeCursor = lineContent.substring(0, position.column - 1);\n const atIdx = textBeforeCursor.lastIndexOf('@');\n if (atIdx === -1) return { suggestions: [] };\n // `@` must be at line start or preceded by whitespace/punct —\n // skip e.g. email addresses like `foo@bar`.\n if (atIdx > 0) {\n const prevChar = textBeforeCursor[atIdx - 1];\n if (!/[\\s\\p{P}]/u.test(prevChar)) return { suggestions: [] };\n }\n const query = textBeforeCursor.slice(atIdx + 1);\n // Only fire for short queries — once the user has typed\n // a full word, the popover gets noisy.\n if (query.length > 40) return { suggestions: [] };\n if (/\\s/.test(query)) return { suggestions: [] };\n\n let candidates;\n try {\n candidates = await provider(query);\n } catch {\n return { suggestions: [] };\n }\n\n const range = new monaco.Range(\n position.lineNumber,\n atIdx + 1,\n position.lineNumber,\n position.column,\n );\n\n return {\n suggestions: candidates.map((c) => ({\n label: `@${c.label}`,\n kind: monaco.languages.CompletionItemKind.User,\n insertText: `@[${c.label}](${c.scheme}:${c.id}) `,\n range,\n ...(c.description ? { detail: c.description } : {}),\n sortText: c.label,\n })),\n };\n },\n },\n );\n\n // FontAwesome icon completion. Fires inside any `{[…]}` opener\n // anywhere in the doc (not just headings — icons are inline).\n // Suggestions cover the whole FA Free catalog filtered by the\n // partial token; we cap at 50 to keep the popup readable. The\n // template provider above still handles heading lines, so on\n // a `## Title {[…]}` the user sees both template names AND\n // icons interleaved by the regular Monaco filter.\n iconCompletionDisposable.current = monaco.languages.registerCompletionItemProvider(\n 'markdown',\n {\n triggerCharacters: ['['],\n provideCompletionItems(model, position) {\n const lineContent = model.getLineContent(position.lineNumber);\n const textBeforeCursor = lineContent.substring(0, position.column - 1);\n const textAfterCursor = lineContent.substring(position.column - 1);\n const bracketIdx = textBeforeCursor.lastIndexOf('{[');\n if (bracketIdx === -1) return { suggestions: [] };\n // Bail if any `]` already closes this annotation between\n // `{[` and the cursor — we'd be past the token, not in it.\n const between = textBeforeCursor.slice(bracketIdx + 2);\n if (between.includes(']')) return { suggestions: [] };\n // Tokens are alphanumeric + `-_:`; anything else means\n // we're not inside an icon (probably a code/link bracket).\n if (between && !/^[a-zA-Z0-9_:-]*$/.test(between)) {\n return { suggestions: [] };\n }\n const query = between.toLowerCase();\n\n // When Monaco's bracket auto-pair has already produced a\n // closing `]}` we don't want to insert another — but we\n // also don't want to consume the existing one, since\n // then we'd have to re-emit it and the round-trip is\n // brittle. Leave the closing in place and just insert\n // the bare token; if no closing exists yet, append it.\n const closingMatch = textAfterCursor.match(/^\\]\\}/);\n const suffix = closingMatch ? '' : ']}';\n\n const range = new monaco.Range(\n position.lineNumber,\n bracketIdx + 3, // after `{[`\n position.lineNumber,\n position.column,\n );\n\n const top = suggestIcons(query, 50);\n return {\n suggestions: top.map((m, i) => ({\n // Embed the FA codepoint as the first character of\n // the label. CSS targets the suggest widget with\n // FontAwesome as a font fallback, so the codepoint\n // renders as the glyph and the name renders in the\n // editor's normal font.\n label: {\n label: `${iconGlyph(m.entry)} ${m.token}`,\n description: `fa-${m.entry.family}`,\n },\n // `filterText` excludes the glyph + spacing so Monaco\n // filters against the actual icon name only.\n filterText: m.token,\n kind: monaco.languages.CompletionItemKind.Constant,\n insertText: `${m.token}${suffix}`,\n range,\n detail: m.entry.label,\n // Documentation pane (rendered when Monaco's\n // suggestion preview is expanded) shows a large\n // version of the glyph alongside the canonical token.\n documentation: {\n value: `<i class=\"fa-${m.entry.family} fa-${m.entry.name}\" style=\"font-size: 2em; display: inline-block; margin-right: 8px; vertical-align: middle\"></i> **${m.token}** *(${m.entry.label})*`,\n isTrusted: true,\n supportHtml: true,\n },\n // Sort key: 1-digit score prefix keeps \"starts with\"\n // matches above \"contains\" / keyword matches.\n sortText: `${m.score}${String(i).padStart(4, '0')}`,\n })),\n };\n },\n },\n );\n }\n\n // Chat-composer mode: intercept Enter before Monaco inserts a newline.\n // Cmd/Ctrl+Enter falls through so the native newline still works.\n keyDisposable.current?.dispose();\n keyDisposable.current = editor.onKeyDown((e) => {\n if (e.keyCode !== monaco.KeyCode.Enter) return;\n if (!submitOnEnterRef.current) return;\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n e.preventDefault();\n e.stopPropagation();\n submitOnEnterRef.current();\n });\n\n // Attach native drop listeners for in-app MediaBin drags. Monaco's own\n // drop handling doesn't know about our custom MIME type, so we insert\n // markdown image syntax explicitly in the capture phase.\n dropCleanupRef.current?.();\n const domNode = editor.getDomNode();\n if (domNode) {\n const onDragOver = (e: DragEvent) => {\n if (e.dataTransfer?.types.includes(SQUISQ_MEDIA_MIME)) {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'copy';\n }\n };\n const onDrop = (e: DragEvent) => {\n const dt = e.dataTransfer;\n if (!dt) return;\n const raw = dt.getData(SQUISQ_MEDIA_MIME);\n if (!raw) return;\n const payload = parseSquisqMediaPayload(raw);\n if (!payload || !payload.mimeType.startsWith('image/')) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n const target = editor.getTargetAtClientPoint(e.clientX, e.clientY);\n const position = target?.position ?? editor.getPosition();\n if (!position) return;\n\n const markdown = `![${payload.alt}](${payload.name})`;\n editor.executeEdits('squisq-media-drop', [\n {\n range: new monaco.Range(\n position.lineNumber,\n position.column,\n position.lineNumber,\n position.column,\n ),\n text: markdown,\n forceMoveMarkers: true,\n },\n ]);\n editor.focus();\n };\n domNode.addEventListener('dragover', onDragOver, true);\n domNode.addEventListener('drop', onDrop, true);\n dropCleanupRef.current = () => {\n domNode.removeEventListener('dragover', onDragOver, true);\n domNode.removeEventListener('drop', onDrop, true);\n };\n }\n },\n [setMonacoEditor, language],\n );\n\n // Unregister on unmount\n useEffect(() => {\n return () => {\n setMonacoEditor(null);\n completionDisposable.current?.dispose();\n completionDisposable.current = null;\n mentionCompletionDisposable.current?.dispose();\n mentionCompletionDisposable.current = null;\n iconCompletionDisposable.current?.dispose();\n iconCompletionDisposable.current = null;\n iconGlyphDecorations.current?.clear();\n iconGlyphDecorations.current = null;\n dropCleanupRef.current?.();\n dropCleanupRef.current = null;\n keyDisposable.current?.dispose();\n keyDisposable.current = null;\n };\n }, [setMonacoEditor]);\n\n const handleChange: OnChange = useCallback(\n (value) => {\n if (isExternalUpdate.current) return;\n if (value !== undefined) {\n setMarkdownSource(value);\n }\n },\n [setMarkdownSource],\n );\n\n // When external changes happen (e.g. from WYSIWYG), update Monaco\n useEffect(() => {\n const editor = editorRef.current;\n if (editor) {\n const currentValue = editor.getValue();\n if (currentValue !== markdownSource) {\n isExternalUpdate.current = true;\n editor.setValue(markdownSource);\n isExternalUpdate.current = false;\n }\n }\n }, [markdownSource]);\n\n // ── Inline FontAwesome glyph decorations ────────────\n // Walk the markdown source on every change, find each resolvable\n // `{[icon-name]}` span, and overlay the actual glyph (via Monaco's\n // `before:` content decoration) just before the brackets. The CSS\n // classes `.fa-glyph-decoration-<family>` set the per-family font\n // and weight; the codepoint character is the decoration's content.\n useEffect(() => {\n const editor = editorRef.current;\n // `monacoNs` is read from the lazy loader's state rather than a\n // top-level import. Re-run when it transitions from null → loaded\n // so decorations show up the moment monaco is in hand.\n if (!editor || !monacoNs) return;\n if (language !== 'markdown') return;\n const model = editor.getModel();\n if (!model) return;\n\n const decorations: monaco.editor.IModelDeltaDecoration[] = [];\n const lines = model.getLineCount();\n const re = /\\{\\[([a-zA-Z0-9_:-]+)\\]\\}/g;\n for (let line = 1; line <= lines; line++) {\n const text = model.getLineContent(line);\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(text)) !== null) {\n const icon = resolveIcon(match[1]);\n if (!icon) continue;\n const glyph = iconGlyph(icon);\n if (!glyph) continue;\n // Position the decoration as a zero-width range at the `{`\n // of the matched token. `before.contentText` renders the\n // glyph as content prepended visually to that position.\n const col = match.index + 1; // Monaco columns are 1-based\n decorations.push({\n range: new monacoNs.Range(line, col, line, col),\n options: {\n before: {\n content: glyph,\n inlineClassName: `fa-glyph-decoration-${icon.family}`,\n },\n },\n });\n }\n }\n\n if (!iconGlyphDecorations.current) {\n iconGlyphDecorations.current = editor.createDecorationsCollection(decorations);\n } else {\n iconGlyphDecorations.current.set(decorations);\n }\n }, [markdownSource, language, monacoNs]);\n\n const effectiveTheme = SQUISQ_THEMES[theme] ?? theme;\n\n // Wait for the lazy monaco namespace + `loader.config()` to settle\n // before mounting `<Editor>`. Without this gate, the @monaco-editor/\n // react singleton loader would fall back to its built-in CDN fetch\n // for any consumer that hasn't aliased monaco-editor — which is the\n // exact regression the lazy-loading move is meant to avoid.\n if (!monacoReady) {\n return (\n <div\n className={className}\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--squisq-editor-muted-foreground, #6a6258)',\n fontSize: 13,\n }}\n data-testid=\"raw-editor\"\n data-monaco-loading\n >\n Loading editor…\n </div>\n );\n }\n\n return (\n <div className={className} style={{ width: '100%', height: '100%' }} data-testid=\"raw-editor\">\n <Editor\n defaultLanguage={language}\n value={markdownSource}\n theme={effectiveTheme}\n beforeMount={handleBeforeMount}\n onMount={handleMount}\n onChange={handleChange}\n options={{\n fontSize,\n wordWrap,\n minimap: { enabled: minimap },\n lineNumbers: 'on',\n scrollBeyondLastLine: false,\n automaticLayout: true,\n tabSize: 2,\n renderWhitespace: 'selection',\n bracketPairColorization: { enabled: true },\n guides: { indentation: true },\n padding: { top: 12, bottom: 12 },\n // Markdown's tokenizer classifies most body text as \"string\"\n // or \"comment\" context, which suppresses `quickSuggestions`\n // by default. Enable in all three so our `{[icon]}` and\n // `@mention` typeaheads keep firing as the user types past\n // the trigger character.\n quickSuggestions: { other: true, comments: true, strings: true },\n suggestOnTriggerCharacters: true,\n // Breathing room between the gutter and the first character.\n // Done via Monaco's own option so cursor + hit-testing stay in\n // sync — CSS-padding `.view-lines` shifts the text but not the\n // cursors layer, which causes the cursor to drift left of the\n // model column. Monaco's default is 10. We set 22 (12 extra),\n // and CSS paints the rightmost 12px of the gutter as canvas\n // color so the breathing room looks like it sits *inside* the\n // canvas rather than widening the gutter.\n lineDecorationsWidth: 22,\n readOnly,\n domReadOnly: readOnly,\n }}\n />\n </div>\n );\n}\n","/**\n * Shared MIME type used to signal an in-app drag from the MediaBin to either\n * the Raw or WYSIWYG editor. Carries a JSON payload of the form\n * `{ name, mimeType, alt }` so the receiving editor can insert a reference\n * to an existing media entry without re-uploading it.\n */\nexport const SQUISQ_MEDIA_MIME = 'application/x-squisq-media';\n\nexport interface SquisqMediaDragPayload {\n /** Relative path / filename as stored in the MediaProvider. */\n name: string;\n /** MIME type of the entry. */\n mimeType: string;\n /** Default alt text derived from the filename. */\n alt: string;\n}\n\nexport function parseSquisqMediaPayload(raw: string): SquisqMediaDragPayload | null {\n try {\n const parsed = JSON.parse(raw) as Partial<SquisqMediaDragPayload>;\n if (\n typeof parsed.name === 'string' &&\n typeof parsed.mimeType === 'string' &&\n typeof parsed.alt === 'string'\n ) {\n return parsed as SquisqMediaDragPayload;\n }\n } catch {\n // fall through\n }\n return null;\n}\n","/**\n * WysiwygEditor\n *\n * Tiptap-based rich text editor that provides a WYSIWYG editing experience\n * for markdown content. Uses squisq's parseMarkdown/stringifyMarkdown for\n * conversion rather than Tiptap's built-in HTML serialization, ensuring\n * perfect fidelity with the markdown format.\n *\n * Includes extensions for GFM features: tables, task lists, strikethrough,\n * and code blocks.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport type { CSSProperties } from 'react';\nimport { useEditor, EditorContent } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport Table from '@tiptap/extension-table';\nimport TableRow from '@tiptap/extension-table-row';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport TaskList from '@tiptap/extension-task-list';\nimport TaskItem from '@tiptap/extension-task-item';\nimport Link from '@tiptap/extension-link';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { resolveFontFamily, FONT_FALLBACKS } from '@bendyline/squisq/schemas';\nimport { HeadingWithTemplate } from './TemplateAnnotation';\nimport { InlineIcon } from './InlineIcon';\nimport { ImageWithMediaProvider } from './ImageNodeView';\nimport { TiptapVideo } from './tiptap/TiptapVideo';\nimport { TiptapAudio } from './tiptap/TiptapAudio';\nimport { TemplateBadgePopover, TEMPLATE_NAMES } from './TemplatePicker';\nimport { profileBlockContents, recommendTemplatesForBlock } from '@bendyline/squisq/recommend';\nimport { findBlockSliceByHeadingIndex } from './blockSlice';\nimport { useEditorContext } from './EditorContext';\nimport { buildMentionExtension } from './MentionExtension';\nimport { markdownToTiptap, tiptapToMarkdown } from './tiptapBridge';\nimport { looksLikeMarkdown } from './detectMarkdown';\nimport { SQUISQ_MEDIA_MIME, parseSquisqMediaPayload } from './mediaDragMime';\nimport { usePreviewSettingsOptional } from './PreviewControls';\n\n// ── Frontmatter helpers ────────────────────────────────────────────\n\n/** Regex matching a YAML frontmatter block at the start of the document. */\nconst FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/;\n\n/** Strip YAML frontmatter from markdown, returning both parts. */\nfunction stripFrontmatter(md: string): { body: string; frontmatter: string } {\n const m = md.match(FRONTMATTER_RE);\n if (!m) return { body: md, frontmatter: '' };\n return { body: md.slice(m[0].length), frontmatter: m[0] };\n}\n\n/**\n * Rotating placeholder prompts shown when the editor is empty. One is\n * picked at random per editor mount. Hosts can override by passing the\n * `placeholder` prop with a fixed string.\n */\nconst EMPTY_PROMPTS = [\n 'Start typing your content, or drop images on top of me…',\n 'Write anything — paste markdown, drag in images, or just start typing…',\n 'Type away. Markdown syntax works too…',\n 'Chapter 1 begins here…',\n 'Once upon a time…',\n 'A blank page. Exciting, isn\\u2019t it?',\n 'The first word is always the hardest…',\n 'Plot twist: this is where it all starts…',\n 'Write something the future you will thank you for…',\n 'Begin at the beginning…',\n];\n\nfunction pickEmptyPrompt(): string {\n return EMPTY_PROMPTS[Math.floor(Math.random() * EMPTY_PROMPTS.length)];\n}\n\nexport interface WysiwygEditorProps {\n /**\n * Placeholder text when the editor is empty. If omitted, one of several\n * rotating prompts is picked at random on mount. Pass a fixed string to\n * override with a host-specific call to action.\n */\n placeholder?: string;\n /** Additional class name for the container */\n className?: string;\n /**\n * If set, a plain Enter keypress fires this callback instead of inserting\n * a newline, and Cmd/Ctrl+Enter inserts a soft break. Chat-composer UX.\n */\n submitOnEnter?: () => void;\n /** Disable Tiptap editing — renders content but blocks input. */\n readOnly?: boolean;\n}\n\n/**\n * Rich WYSIWYG markdown editor built on Tiptap (ProseMirror).\n * Binds to the shared EditorContext for source synchronization.\n */\nexport function WysiwygEditor({\n placeholder,\n className,\n submitOnEnter,\n readOnly = false,\n}: WysiwygEditorProps) {\n const {\n markdownSource,\n setMarkdownSource,\n setTiptapEditor,\n mediaProvider,\n mentionProvider,\n blockTagsVisible,\n themeInheritance,\n } = useEditorContext();\n // Keep a ref so the mention extension — created once at editor mount —\n // always sees the latest provider. Swapping projects changes\n // the provider without remounting the editor.\n const mentionProviderRef = useRef(mentionProvider);\n useEffect(() => {\n mentionProviderRef.current = mentionProvider;\n }, [mentionProvider]);\n // Stable per mount: either the host-supplied string, or a random pick\n // from EMPTY_PROMPTS. Re-renders don't reshuffle.\n const resolvedPlaceholder = useMemo(() => placeholder ?? pickEmptyPrompt(), [placeholder]);\n const isExternalUpdate = useRef(false);\n const lastSourceRef = useRef(markdownSource);\n // Keep a ref so the editor's drop/paste handlers (created once) always\n // see the current MediaProvider without needing to recreate the editor.\n const mediaProviderRef = useRef(mediaProvider);\n useEffect(() => {\n mediaProviderRef.current = mediaProvider;\n }, [mediaProvider]);\n // Preserve frontmatter across edits — hidden from WYSIWYG but prepended on save\n const frontmatterRef = useRef(stripFrontmatter(markdownSource).frontmatter);\n // Stash the latest submit callback so the editor's handleKeyDown (bound\n // once at creation) always sees the current value.\n const submitOnEnterRef = useRef(submitOnEnter);\n useEffect(() => {\n submitOnEnterRef.current = submitOnEnter;\n }, [submitOnEnter]);\n\n const editor = useEditor({\n editable: !readOnly,\n extensions: [\n StarterKit.configure({\n // Disable built-in heading; we use HeadingWithTemplate instead\n heading: false,\n codeBlock: {\n HTMLAttributes: { class: 'squisq-code-block' },\n },\n }),\n HeadingWithTemplate.configure({ levels: [1, 2, 3, 4, 5, 6] }),\n Table.configure({ resizable: true }),\n TableRow,\n TableCell,\n TableHeader,\n TaskList,\n TaskItem.configure({ nested: true }),\n Link.configure({\n openOnClick: false,\n autolink: true,\n HTMLAttributes: { rel: 'noopener noreferrer', target: '_blank' },\n }),\n ImageWithMediaProvider.configure({ inline: false }),\n TiptapVideo,\n TiptapAudio,\n Placeholder.configure({ placeholder: resolvedPlaceholder }),\n buildMentionExtension(() => mentionProviderRef.current),\n InlineIcon,\n ],\n content: markdownToTiptap(stripFrontmatter(markdownSource).body),\n onUpdate: ({ editor: ed }) => {\n if (isExternalUpdate.current) return;\n const html = ed.getHTML();\n const bodyMd = tiptapToMarkdown(html);\n const newSource = frontmatterRef.current + bodyMd;\n lastSourceRef.current = newSource;\n setMarkdownSource(newSource);\n },\n editorProps: {\n attributes: {\n class: 'squisq-wysiwyg-editor',\n 'data-testid': 'wysiwyg-editor',\n },\n // Chat-composer mode: Enter commits via submitOnEnter(), Cmd/Ctrl+Enter\n // inserts a soft break. When no callback is set, fall through to Tiptap's\n // normal behavior (Enter = paragraph break, Shift+Enter = soft break).\n handleKeyDown: (view, event) => {\n if (event.key !== 'Enter' || !submitOnEnterRef.current) return false;\n // Defer Enter to an open mention/suggestion popover so the user\n // can pick the highlighted candidate. ProseMirror plugins fire\n // AFTER editorProps.handleKeyDown, so without this short-circuit\n // plain Enter submits the message and the popover closes\n // without inserting the mention. The MentionExtension marks\n // its container with `display: block` while items are showing\n // and `display: none` when empty — only short-circuit when\n // there's actually a candidate to pick.\n const popover = document.querySelector<HTMLElement>('.squisq-mention-popover');\n if (popover && popover.style.display !== 'none') {\n return false;\n }\n if (event.metaKey || event.ctrlKey) {\n // User wants a newline. Insert a hard-break and stop propagation so\n // we don't also create a new paragraph.\n event.preventDefault();\n view.dispatch(\n view.state.tr.replaceSelectionWith(view.state.schema.nodes.hardBreak.create()),\n );\n return true;\n }\n if (event.shiftKey) {\n // Preserve the conventional Shift+Enter soft break.\n return false;\n }\n // Plain Enter — submit.\n event.preventDefault();\n submitOnEnterRef.current();\n return true;\n },\n // When the clipboard's plain-text payload looks like markdown source,\n // convert it via tiptapBridge before pasting. This applies even when\n // the clipboard also contains HTML (most rich-text sources do), since\n // the markdown-looking text is usually what the user actually wants.\n // Without this, pasted markdown shows up as literal \"# Heading\" text\n // instead of becoming a real heading.\n handlePaste: (view, event) => {\n const clipboard = event.clipboardData;\n if (!clipboard) return false;\n\n // Image files in the clipboard → upload via MediaProvider and insert\n const imageFiles = filesFromClipboard(clipboard);\n if (imageFiles.length > 0 && mediaProviderRef.current) {\n event.preventDefault();\n uploadAndInsertImages(view, imageFiles, mediaProviderRef.current);\n return true;\n }\n\n const text = clipboard.getData('text/plain');\n if (!text || !looksLikeMarkdown(text)) return false;\n const html = markdownToTiptap(text);\n if (!html) return false;\n event.preventDefault();\n view.pasteHTML(html);\n return true;\n },\n // When image files are dropped onto the editor, upload them via the\n // MediaProvider and insert <img> nodes referencing the relative paths.\n // Also handles drags from the MediaBin, which reference existing\n // entries via a custom MIME type and skip the upload step.\n // Falls through to default handling for non-image drops or when no\n // MediaProvider is available.\n handleDrop: (view, event, _slice, moved) => {\n const dt = event.dataTransfer;\n if (!dt) return false;\n\n // Internal node move (the user dragged an existing node within\n // the document). ProseMirror's `moved` flag is true in this\n // case; let it handle the reposition natively so width/height\n // attributes are preserved and the source node is removed.\n // Without this short-circuit, the browser also exposes the\n // dragged `<img>` as a virtual file in `dataTransfer`, so the\n // upload-and-insert path below would fire — producing a\n // dimension-less duplicate next to the original.\n if (moved) return false;\n\n // In-app drag from the MediaBin — insert without uploading\n const squisqRaw = dt.getData(SQUISQ_MEDIA_MIME);\n if (squisqRaw) {\n const payload = parseSquisqMediaPayload(squisqRaw);\n if (payload && payload.mimeType.startsWith('image/')) {\n event.preventDefault();\n moveSelectionToDropPoint(view, event);\n insertImageNode(view, payload.name, payload.alt);\n return true;\n }\n }\n\n const imageFiles = filesFromDataTransfer(dt);\n if (imageFiles.length === 0) {\n // Nothing image-like in the drop. Let the browser / ProseMirror\n // handle it (links, text, etc.). Log enough to debug if the user\n // expected this to be an image drop — Windows/browser combos\n // sometimes deliver image drags without a usable File payload.\n if (dt.files.length > 0 || dt.items.length > 0) {\n console.warn(\n '[squisq-editor] Drop received with no recognizable image File. Types:',\n Array.from(dt.types ?? []),\n 'files:',\n Array.from(dt.files).map((f) => `${f.name} (${f.type || 'no-type'})`),\n );\n }\n return false;\n }\n if (!mediaProviderRef.current) {\n console.warn(\n '[squisq-editor] Image drop received but no MediaProvider is wired up; cannot persist the image. Pass `mediaProvider` to EditorShell / EditorProvider.',\n );\n return false;\n }\n\n event.preventDefault();\n moveSelectionToDropPoint(view, event);\n uploadAndInsertImages(view, imageFiles, mediaProviderRef.current);\n return true;\n },\n },\n });\n\n // Register / unregister the Tiptap editor instance with the shared context\n useEffect(() => {\n if (editor) {\n setTiptapEditor(editor);\n }\n return () => setTiptapEditor(null);\n }, [editor, setTiptapEditor]);\n\n // Tiptap reads `editable` only at creation; mirror later changes via\n // setEditable so flipping readOnly from the host takes effect without\n // remounting the editor.\n useEffect(() => {\n if (editor) editor.setEditable(!readOnly);\n }, [editor, readOnly]);\n\n // ── Template badge → popover ─────────────────────────────────────\n // The HeadingWithTemplate extension renders an inert `.squisq-template-badge`\n // span inside templated headings. We delegate clicks at the container\n // level so we can locate the heading position and open the gallery\n // anchored at that badge.\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [badgeMenu, setBadgeMenu] = useState<{\n rect: DOMRect;\n template: string;\n headingPos: number;\n headingIndex: number;\n } | null>(null);\n\n useEffect(() => {\n if (!editor) return;\n const root = containerRef.current;\n if (!root) return;\n const onClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n const badge = target.closest('.squisq-template-badge') as HTMLElement | null;\n if (!badge || !root.contains(badge)) return;\n e.preventDefault();\n e.stopPropagation();\n // Find the parent heading element and resolve its document position.\n const headingEl = badge.closest('h1,h2,h3,h4,h5,h6') as HTMLElement | null;\n if (!headingEl) return;\n let pos: number | null = null;\n try {\n pos = editor.view.posAtDOM(headingEl, 0);\n } catch {\n pos = null;\n }\n if (pos == null) return;\n // posAtDOM returns the position *inside* the heading; subtract 1\n // to land on the heading node itself so setNodeMarkup targets it.\n const headingPos = Math.max(0, pos - 1);\n const node = editor.state.doc.nodeAt(headingPos);\n if (!node || node.type.name !== 'heading') return;\n // Count how many headings precede this one so the markdown-source\n // slice helper can locate the matching heading by index.\n let headingIndex = 0;\n let count = 0;\n editor.state.doc.descendants((n, p) => {\n if (n.type.name !== 'heading') return;\n if (p === headingPos) {\n headingIndex = count;\n return false;\n }\n count++;\n });\n setBadgeMenu({\n rect: badge.getBoundingClientRect(),\n template: (node.attrs.dataTemplate as string | null) ?? '',\n headingPos,\n headingIndex,\n });\n };\n root.addEventListener('mousedown', onClick);\n return () => root.removeEventListener('mousedown', onClick);\n }, [editor]);\n\n // Sync external changes into Tiptap\n useEffect(() => {\n if (!editor) return;\n // Only update if the source changed externally (not from our own onUpdate)\n if (markdownSource !== lastSourceRef.current) {\n isExternalUpdate.current = true;\n const { body, frontmatter } = stripFrontmatter(markdownSource);\n frontmatterRef.current = frontmatter;\n const content = markdownToTiptap(body);\n editor.commands.setContent(content);\n lastSourceRef.current = markdownSource;\n isExternalUpdate.current = false;\n }\n }, [markdownSource, editor]);\n\n // Match the WYSIWYG editor's appearance to the active Squisq theme\n // when one is set in frontmatter or picked in the preview dropdown.\n // Driven by the View menu's \"Theme inheritance\" setting:\n // - 'none' → don't inherit anything\n // - 'fonts' → body + heading fonts only (historical default)\n // - 'fonts-colors' → fonts plus the theme's canvas / text colors\n // Pushed as CSS custom properties on the container so the stylesheet\n // can pick them up (with sensible fallbacks for hosts that don't have\n // a PreviewSettingsProvider in scope).\n const previewSettings = usePreviewSettingsOptional();\n const activeTheme = previewSettings?.activeTheme;\n const themeStyle = useMemo<CSSProperties>(() => {\n if (themeInheritance === 'none' || !activeTheme) return {};\n const out: Record<string, string> = {\n '--squisq-theme-body-font': resolveFontFamily(\n activeTheme.typography.bodyFont,\n FONT_FALLBACKS.sans,\n ),\n '--squisq-theme-title-font': resolveFontFamily(\n activeTheme.typography.titleFont,\n FONT_FALLBACKS.sans,\n ),\n };\n if (themeInheritance === 'fonts-colors') {\n const colors = activeTheme.colors;\n out['--squisq-theme-bg'] = colors.background;\n // backgroundLight gives a subtle on-canvas surface for inline emphasis\n // (inline `code`, code blocks). Themes always define it.\n out['--squisq-theme-bg-muted'] = colors.backgroundLight;\n out['--squisq-theme-text'] = colors.text;\n out['--squisq-theme-text-muted'] = colors.textMuted;\n out['--squisq-theme-primary'] = colors.primary;\n }\n return out as CSSProperties;\n }, [activeTheme, themeInheritance]);\n\n return (\n <div\n className={`squisq-wysiwyg-container${className ? ` ${className}` : ''}`}\n style={{ width: '100%', height: '100%', overflow: 'auto', ...themeStyle }}\n data-testid=\"wysiwyg-container\"\n data-block-tags={blockTagsVisible ? 'visible' : 'hidden'}\n data-theme-inheritance={themeInheritance}\n ref={containerRef}\n >\n <EditorContent editor={editor} style={{ height: '100%' }} />\n {badgeMenu && (\n <TemplateBadgePopover\n anchorRect={badgeMenu.rect}\n value={badgeMenu.template}\n recommended={(() => {\n const slice = findBlockSliceByHeadingIndex(markdownSource, badgeMenu.headingIndex);\n if (!slice) return undefined;\n const profile = profileBlockContents(slice);\n return recommendTemplatesForBlock(profile, TEMPLATE_NAMES).recommended;\n })()}\n onChange={(name) => {\n if (!editor) return;\n const tr = editor.state.tr.setNodeMarkup(badgeMenu.headingPos, undefined, {\n ...editor.state.doc.nodeAt(badgeMenu.headingPos)?.attrs,\n dataTemplate: name === '' ? null : name,\n });\n editor.view.dispatch(tr);\n }}\n onClose={() => setBadgeMenu(null)}\n />\n )}\n </div>\n );\n}\n\n// ── Image drop / paste helpers ─────────────────────────────────────\n\n/** Extension-based fallback when a dragged file has no `type` set (rare\n * but happens when sources omit the MIME — e.g. some screenshot tools). */\nconst IMAGE_EXT_RE = /\\.(png|jpe?g|gif|webp|bmp|svg|avif|ico)$/i;\n\nfunction looksLikeImageFile(file: File): boolean {\n if (file.type.startsWith('image/')) return true;\n return IMAGE_EXT_RE.test(file.name);\n}\n\n/** Extract image File objects from a DataTransfer (drop event). Reads\n * from both `dt.files` and `dt.items`; some drag sources (cross-tab\n * drags, certain native apps) populate only one of the two. */\nfunction filesFromDataTransfer(dt: DataTransfer): File[] {\n const files: File[] = [];\n const seen = new Set<string>();\n\n for (let i = 0; i < dt.files.length; i++) {\n const file = dt.files[i];\n if (looksLikeImageFile(file)) {\n files.push(file);\n seen.add(`${file.name}|${file.size}`);\n }\n }\n\n if (dt.items) {\n for (let i = 0; i < dt.items.length; i++) {\n const item = dt.items[i];\n if (item.kind !== 'file') continue;\n const file = item.getAsFile();\n if (!file) continue;\n if (!looksLikeImageFile(file)) continue;\n const key = `${file.name}|${file.size}`;\n if (seen.has(key)) continue;\n files.push(file);\n seen.add(key);\n }\n }\n\n return files;\n}\n\n/** Extract image File objects from a clipboard's items (paste event). */\nfunction filesFromClipboard(clipboard: DataTransfer): File[] {\n const files: File[] = [];\n // clipboardData.items is the most reliable source for pasted images\n if (clipboard.items) {\n for (let i = 0; i < clipboard.items.length; i++) {\n const item = clipboard.items[i];\n if (item.kind === 'file' && item.type.startsWith('image/')) {\n const file = item.getAsFile();\n if (file) files.push(file);\n }\n }\n }\n return files;\n}\n\n/**\n * Upload image files to the MediaProvider and insert <img> nodes at the\n * current selection. Inserts a placeholder name when files lack one\n * (e.g., screenshots from the system clipboard).\n */\nasync function uploadAndInsertImages(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n view: any,\n files: File[],\n mediaProvider: import('@bendyline/squisq/schemas').MediaProvider,\n): Promise<void> {\n for (const file of files) {\n try {\n const buffer = await file.arrayBuffer();\n const mimeType = file.type || 'image/png';\n const name =\n file.name && file.name !== 'image.png'\n ? file.name\n : `pasted-${uniquePasteToken()}.${extFromMime(mimeType)}`;\n const relativePath = await mediaProvider.addMedia(name, buffer, mimeType);\n const altText = name.replace(/\\.[^.]+$/, '').replace(/[-_]/g, ' ');\n insertImageNode(view, relativePath, altText);\n } catch (err) {\n console.error('Failed to upload dropped image:', err);\n }\n }\n}\n\n/** Insert an image node at the current selection using the schema image type. */\nfunction insertImageNode(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n view: any,\n src: string,\n alt: string,\n): void {\n const { schema } = view.state;\n const imageType = schema.nodes.image;\n if (!imageType) return;\n const node = imageType.create({ src, alt });\n const tr = view.state.tr.replaceSelectionWith(node);\n view.dispatch(tr);\n}\n\n/** Move the selection to the document position under the drop event's coordinates. */\nfunction moveSelectionToDropPoint(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n view: any,\n event: DragEvent,\n): void {\n const coords = view.posAtCoords({ left: event.clientX, top: event.clientY });\n if (!coords) return;\n const tr = view.state.tr.setSelection(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (view.state.selection.constructor as any).near(view.state.doc.resolve(coords.pos)),\n );\n view.dispatch(tr);\n}\n\n/**\n * Produce a unique token for a pasted-file name. `Date.now()` alone can\n * collide when a user pastes several clipboard images in the same tick\n * (multi-image paste from a screenshot grid, for example), which would make\n * `MediaProvider.addMedia` overwrite or reject later entries. Prefer\n * `crypto.randomUUID()` when available and fall back to a counter so the\n * helper stays pure-JS-everywhere.\n */\nlet pasteCounter = 0;\nfunction uniquePasteToken(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n pasteCounter = (pasteCounter + 1) % 1_000_000;\n return `${Date.now()}-${pasteCounter.toString(36)}`;\n}\n\nfunction extFromMime(mime: string): string {\n const map: Record<string, string> = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/jpg': 'jpg',\n 'image/gif': 'gif',\n 'image/webp': 'webp',\n 'image/svg+xml': 'svg',\n 'image/avif': 'avif',\n };\n return map[mime.toLowerCase()] ?? 'png';\n}\n\n/**\n * Hook to access the Tiptap editor instance for toolbar commands.\n * The WysiwygEditor must be mounted as a sibling or descendant.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport { useEditor as useTiptapEditor } from '@tiptap/react';\n","import { EditorState, Transaction } from '@tiptap/pm/state'\n\n/**\n * Takes a Transaction & Editor State and turns it into a chainable state object\n * @param config The transaction and state to create the chainable state from\n * @returns A chainable Editor state object\n */\nexport function createChainableState(config: {\n transaction: Transaction\n state: EditorState\n}): EditorState {\n const { state, transaction } = config\n let { selection } = transaction\n let { doc } = transaction\n let { storedMarks } = transaction\n\n return {\n ...state,\n apply: state.apply.bind(state),\n applyTransaction: state.applyTransaction.bind(state),\n plugins: state.plugins,\n schema: state.schema,\n reconfigure: state.reconfigure.bind(state),\n toJSON: state.toJSON.bind(state),\n get storedMarks() {\n return storedMarks\n },\n get selection() {\n return selection\n },\n get doc() {\n return doc\n },\n get tr() {\n selection = transaction.selection\n doc = transaction.doc\n storedMarks = transaction.storedMarks\n\n return transaction\n },\n }\n}\n","import { EditorState, Transaction } from '@tiptap/pm/state'\n\nimport { Editor } from './Editor.js'\nimport { createChainableState } from './helpers/createChainableState.js'\nimport {\n AnyCommands, CanCommands, ChainedCommands, CommandProps, SingleCommands,\n} from './types.js'\n\nexport class CommandManager {\n editor: Editor\n\n rawCommands: AnyCommands\n\n customState?: EditorState\n\n constructor(props: { editor: Editor; state?: EditorState }) {\n this.editor = props.editor\n this.rawCommands = this.editor.extensionManager.commands\n this.customState = props.state\n }\n\n get hasCustomState(): boolean {\n return !!this.customState\n }\n\n get state(): EditorState {\n return this.customState || this.editor.state\n }\n\n get commands(): SingleCommands {\n const { rawCommands, editor, state } = this\n const { view } = editor\n const { tr } = state\n const props = this.buildProps(tr)\n\n return Object.fromEntries(\n Object.entries(rawCommands).map(([name, command]) => {\n const method = (...args: any[]) => {\n const callback = command(...args)(props)\n\n if (!tr.getMeta('preventDispatch') && !this.hasCustomState) {\n view.dispatch(tr)\n }\n\n return callback\n }\n\n return [name, method]\n }),\n ) as unknown as SingleCommands\n }\n\n get chain(): () => ChainedCommands {\n return () => this.createChain()\n }\n\n get can(): () => CanCommands {\n return () => this.createCan()\n }\n\n public createChain(startTr?: Transaction, shouldDispatch = true): ChainedCommands {\n const { rawCommands, editor, state } = this\n const { view } = editor\n const callbacks: boolean[] = []\n const hasStartTransaction = !!startTr\n const tr = startTr || state.tr\n\n const run = () => {\n if (\n !hasStartTransaction\n && shouldDispatch\n && !tr.getMeta('preventDispatch')\n && !this.hasCustomState\n ) {\n view.dispatch(tr)\n }\n\n return callbacks.every(callback => callback === true)\n }\n\n const chain = {\n ...Object.fromEntries(\n Object.entries(rawCommands).map(([name, command]) => {\n const chainedCommand = (...args: never[]) => {\n const props = this.buildProps(tr, shouldDispatch)\n const callback = command(...args)(props)\n\n callbacks.push(callback)\n\n return chain\n }\n\n return [name, chainedCommand]\n }),\n ),\n run,\n } as unknown as ChainedCommands\n\n return chain\n }\n\n public createCan(startTr?: Transaction): CanCommands {\n const { rawCommands, state } = this\n const dispatch = false\n const tr = startTr || state.tr\n const props = this.buildProps(tr, dispatch)\n const formattedCommands = Object.fromEntries(\n Object.entries(rawCommands).map(([name, command]) => {\n return [name, (...args: never[]) => command(...args)({ ...props, dispatch: undefined })]\n }),\n ) as unknown as SingleCommands\n\n return {\n ...formattedCommands,\n chain: () => this.createChain(tr, dispatch),\n } as CanCommands\n }\n\n public buildProps(tr: Transaction, shouldDispatch = true): CommandProps {\n const { rawCommands, editor, state } = this\n const { view } = editor\n\n const props: CommandProps = {\n tr,\n editor,\n view,\n state: createChainableState({\n state,\n transaction: tr,\n }),\n dispatch: shouldDispatch ? () => undefined : undefined,\n chain: () => this.createChain(tr, shouldDispatch),\n can: () => this.createCan(tr),\n get commands() {\n return Object.fromEntries(\n Object.entries(rawCommands).map(([name, command]) => {\n return [name, (...args: never[]) => command(...args)(props)]\n }),\n ) as unknown as SingleCommands\n },\n }\n\n return props\n }\n}\n","type StringKeyOf<T> = Extract<keyof T, string>\ntype CallbackType<\n T extends Record<string, any>,\n EventName extends StringKeyOf<T>,\n> = T[EventName] extends any[] ? T[EventName] : [T[EventName]]\ntype CallbackFunction<\n T extends Record<string, any>,\n EventName extends StringKeyOf<T>,\n> = (...props: CallbackType<T, EventName>) => any\n\nexport class EventEmitter<T extends Record<string, any>> {\n\n private callbacks: { [key: string]: Array<(...args: any[])=>void> } = {}\n\n public on<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this {\n if (!this.callbacks[event]) {\n this.callbacks[event] = []\n }\n\n this.callbacks[event].push(fn)\n\n return this\n }\n\n public emit<EventName extends StringKeyOf<T>>(event: EventName, ...args: CallbackType<T, EventName>): this {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n callbacks.forEach(callback => callback.apply(this, args))\n }\n\n return this\n }\n\n public off<EventName extends StringKeyOf<T>>(event: EventName, fn?: CallbackFunction<T, EventName>): this {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n if (fn) {\n this.callbacks[event] = callbacks.filter(callback => callback !== fn)\n } else {\n delete this.callbacks[event]\n }\n }\n\n return this\n }\n\n public once<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this {\n const onceFn = (...args: CallbackType<T, EventName>) => {\n this.off(event, onceFn)\n fn.apply(this, args)\n }\n\n return this.on(event, onceFn)\n }\n\n public removeAllListeners(): void {\n this.callbacks = {}\n }\n}\n","import { AnyExtension, MaybeThisParameterType, RemoveThis } from '../types.js'\n\n/**\n * Returns a field from an extension\n * @param extension The Tiptap extension\n * @param field The field, for example `renderHTML` or `priority`\n * @param context The context object that should be passed as `this` into the function\n * @returns The field value\n */\nexport function getExtensionField<T = any>(\n extension: AnyExtension,\n field: string,\n context?: Omit<MaybeThisParameterType<T>, 'parent'>,\n): RemoveThis<T> {\n\n if (extension.config[field] === undefined && extension.parent) {\n return getExtensionField(extension.parent, field, context)\n }\n\n if (typeof extension.config[field] === 'function') {\n const value = extension.config[field].bind({\n ...context,\n parent: extension.parent\n ? getExtensionField(extension.parent, field, context)\n : null,\n })\n\n return value\n }\n\n return extension.config[field]\n}\n","import { Extension } from '../Extension.js'\nimport { Mark } from '../Mark.js'\nimport { Node } from '../Node.js'\nimport { Extensions } from '../types.js'\n\nexport function splitExtensions(extensions: Extensions) {\n const baseExtensions = extensions.filter(extension => extension.type === 'extension') as Extension[]\n const nodeExtensions = extensions.filter(extension => extension.type === 'node') as Node[]\n const markExtensions = extensions.filter(extension => extension.type === 'mark') as Mark[]\n\n return {\n baseExtensions,\n nodeExtensions,\n markExtensions,\n }\n}\n","import { MarkConfig, NodeConfig } from '../index.js'\nimport {\n AnyConfig,\n Attribute,\n Attributes,\n ExtensionAttribute,\n Extensions,\n} from '../types.js'\nimport { getExtensionField } from './getExtensionField.js'\nimport { splitExtensions } from './splitExtensions.js'\n\n/**\n * Get a list of all extension attributes defined in `addAttribute` and `addGlobalAttribute`.\n * @param extensions List of extensions\n */\nexport function getAttributesFromExtensions(extensions: Extensions): ExtensionAttribute[] {\n const extensionAttributes: ExtensionAttribute[] = []\n const { nodeExtensions, markExtensions } = splitExtensions(extensions)\n const nodeAndMarkExtensions = [...nodeExtensions, ...markExtensions]\n const defaultAttribute: Required<Attribute> = {\n default: null,\n rendered: true,\n renderHTML: null,\n parseHTML: null,\n keepOnSplit: true,\n isRequired: false,\n }\n\n extensions.forEach(extension => {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n extensions: nodeAndMarkExtensions,\n }\n\n const addGlobalAttributes = getExtensionField<AnyConfig['addGlobalAttributes']>(\n extension,\n 'addGlobalAttributes',\n context,\n )\n\n if (!addGlobalAttributes) {\n return\n }\n\n const globalAttributes = addGlobalAttributes()\n\n globalAttributes.forEach(globalAttribute => {\n globalAttribute.types.forEach(type => {\n Object\n .entries(globalAttribute.attributes)\n .forEach(([name, attribute]) => {\n extensionAttributes.push({\n type,\n name,\n attribute: {\n ...defaultAttribute,\n ...attribute,\n },\n })\n })\n })\n })\n })\n\n nodeAndMarkExtensions.forEach(extension => {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n }\n\n const addAttributes = getExtensionField<NodeConfig['addAttributes'] | MarkConfig['addAttributes']>(\n extension,\n 'addAttributes',\n context,\n )\n\n if (!addAttributes) {\n return\n }\n\n // TODO: remove `as Attributes`\n const attributes = addAttributes() as Attributes\n\n Object\n .entries(attributes)\n .forEach(([name, attribute]) => {\n const mergedAttr = {\n ...defaultAttribute,\n ...attribute,\n }\n\n if (typeof mergedAttr?.default === 'function') {\n mergedAttr.default = mergedAttr.default()\n }\n\n if (mergedAttr?.isRequired && mergedAttr?.default === undefined) {\n delete mergedAttr.default\n }\n\n extensionAttributes.push({\n type: extension.name,\n name,\n attribute: mergedAttr,\n })\n })\n })\n\n return extensionAttributes\n}\n","import { NodeType, Schema } from '@tiptap/pm/model'\n\nexport function getNodeType(nameOrType: string | NodeType, schema: Schema): NodeType {\n if (typeof nameOrType === 'string') {\n if (!schema.nodes[nameOrType]) {\n throw Error(\n `There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`,\n )\n }\n\n return schema.nodes[nameOrType]\n }\n\n return nameOrType\n}\n","export function mergeAttributes(...objects: Record<string, any>[]): Record<string, any> {\n return objects\n .filter(item => !!item)\n .reduce((items, item) => {\n const mergedAttributes = { ...items }\n\n Object.entries(item).forEach(([key, value]) => {\n const exists = mergedAttributes[key]\n\n if (!exists) {\n mergedAttributes[key] = value\n\n return\n }\n\n if (key === 'class') {\n const valueClasses: string[] = value ? String(value).split(' ') : []\n const existingClasses: string[] = mergedAttributes[key] ? mergedAttributes[key].split(' ') : []\n\n const insertClasses = valueClasses.filter(\n valueClass => !existingClasses.includes(valueClass),\n )\n\n mergedAttributes[key] = [...existingClasses, ...insertClasses].join(' ')\n } else if (key === 'style') {\n const newStyles: string[] = value ? value.split(';').map((style: string) => style.trim()).filter(Boolean) : []\n const existingStyles: string[] = mergedAttributes[key] ? mergedAttributes[key].split(';').map((style: string) => style.trim()).filter(Boolean) : []\n\n const styleMap = new Map<string, string>()\n\n existingStyles.forEach(style => {\n const [property, val] = style.split(':').map(part => part.trim())\n\n styleMap.set(property, val)\n })\n\n newStyles.forEach(style => {\n const [property, val] = style.split(':').map(part => part.trim())\n\n styleMap.set(property, val)\n })\n\n mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join('; ')\n } else {\n mergedAttributes[key] = value\n }\n })\n\n return mergedAttributes\n }, {})\n}\n","import { Mark, Node } from '@tiptap/pm/model'\n\nimport { ExtensionAttribute } from '../types.js'\nimport { mergeAttributes } from '../utilities/mergeAttributes.js'\n\nexport function getRenderedAttributes(\n nodeOrMark: Node | Mark,\n extensionAttributes: ExtensionAttribute[],\n): Record<string, any> {\n return extensionAttributes\n .filter(\n attribute => attribute.type === nodeOrMark.type.name,\n )\n .filter(item => item.attribute.rendered)\n .map(item => {\n if (!item.attribute.renderHTML) {\n return {\n [item.name]: nodeOrMark.attrs[item.name],\n }\n }\n\n return item.attribute.renderHTML(nodeOrMark.attrs) || {}\n })\n .reduce((attributes, attribute) => mergeAttributes(attributes, attribute), {})\n}\n","// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport function isFunction(value: any): value is Function {\n return typeof value === 'function'\n}\n","import { MaybeReturnType } from '../types.js'\nimport { isFunction } from './isFunction.js'\n\n/**\n * Optionally calls `value` as a function.\n * Otherwise it is returned directly.\n * @param value Function or any value.\n * @param context Optional context to bind to function.\n * @param props Optional props to pass to function.\n */\nexport function callOrReturn<T>(value: T, context: any = undefined, ...props: any[]): MaybeReturnType<T> {\n if (isFunction(value)) {\n if (context) {\n return value.bind(context)(...props)\n }\n\n return value(...props)\n }\n\n return value as MaybeReturnType<T>\n}\n","export function isEmptyObject(value = {}): boolean {\n return Object.keys(value).length === 0 && value.constructor === Object\n}\n","export function fromString(value: any): any {\n if (typeof value !== 'string') {\n return value\n }\n\n if (value.match(/^[+-]?(?:\\d*\\.)?\\d+$/)) {\n return Number(value)\n }\n\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n return value\n}\n","import { ParseRule } from '@tiptap/pm/model'\n\nimport { ExtensionAttribute } from '../types.js'\nimport { fromString } from '../utilities/fromString.js'\n\n/**\n * This function merges extension attributes into parserule attributes (`attrs` or `getAttrs`).\n * Cancels when `getAttrs` returned `false`.\n * @param parseRule ProseMirror ParseRule\n * @param extensionAttributes List of attributes to inject\n */\nexport function injectExtensionAttributesToParseRule(\n parseRule: ParseRule,\n extensionAttributes: ExtensionAttribute[],\n): ParseRule {\n if ('style' in parseRule) {\n return parseRule\n }\n\n return {\n ...parseRule,\n getAttrs: (node: HTMLElement) => {\n const oldAttributes = parseRule.getAttrs ? parseRule.getAttrs(node) : parseRule.attrs\n\n if (oldAttributes === false) {\n return false\n }\n\n const newAttributes = extensionAttributes.reduce((items, item) => {\n const value = item.attribute.parseHTML\n ? item.attribute.parseHTML(node)\n : fromString((node).getAttribute(item.name))\n\n if (value === null || value === undefined) {\n return items\n }\n\n return {\n ...items,\n [item.name]: value,\n }\n }, {})\n\n return { ...oldAttributes, ...newAttributes }\n },\n }\n}\n","import {\n MarkSpec, NodeSpec, Schema, TagParseRule,\n} from '@tiptap/pm/model'\n\nimport { Editor, MarkConfig, NodeConfig } from '../index.js'\nimport { AnyConfig, Extensions } from '../types.js'\nimport { callOrReturn } from '../utilities/callOrReturn.js'\nimport { isEmptyObject } from '../utilities/isEmptyObject.js'\nimport { getAttributesFromExtensions } from './getAttributesFromExtensions.js'\nimport { getExtensionField } from './getExtensionField.js'\nimport { getRenderedAttributes } from './getRenderedAttributes.js'\nimport { injectExtensionAttributesToParseRule } from './injectExtensionAttributesToParseRule.js'\nimport { splitExtensions } from './splitExtensions.js'\n\nfunction cleanUpSchemaItem<T>(data: T) {\n return Object.fromEntries(\n // @ts-ignore\n Object.entries(data).filter(([key, value]) => {\n if (key === 'attrs' && isEmptyObject(value as object | undefined)) {\n return false\n }\n\n return value !== null && value !== undefined\n }),\n ) as T\n}\n\n/**\n * Creates a new Prosemirror schema based on the given extensions.\n * @param extensions An array of Tiptap extensions\n * @param editor The editor instance\n * @returns A Prosemirror schema\n */\nexport function getSchemaByResolvedExtensions(extensions: Extensions, editor?: Editor): Schema {\n const allAttributes = getAttributesFromExtensions(extensions)\n const { nodeExtensions, markExtensions } = splitExtensions(extensions)\n const topNode = nodeExtensions.find(extension => getExtensionField(extension, 'topNode'))?.name\n\n const nodes = Object.fromEntries(\n nodeExtensions.map(extension => {\n const extensionAttributes = allAttributes.filter(\n attribute => attribute.type === extension.name,\n )\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n editor,\n }\n\n const extraNodeFields = extensions.reduce((fields, e) => {\n const extendNodeSchema = getExtensionField<AnyConfig['extendNodeSchema']>(\n e,\n 'extendNodeSchema',\n context,\n )\n\n return {\n ...fields,\n ...(extendNodeSchema ? extendNodeSchema(extension) : {}),\n }\n }, {})\n\n const schema: NodeSpec = cleanUpSchemaItem({\n ...extraNodeFields,\n content: callOrReturn(\n getExtensionField<NodeConfig['content']>(extension, 'content', context),\n ),\n marks: callOrReturn(getExtensionField<NodeConfig['marks']>(extension, 'marks', context)),\n group: callOrReturn(getExtensionField<NodeConfig['group']>(extension, 'group', context)),\n inline: callOrReturn(getExtensionField<NodeConfig['inline']>(extension, 'inline', context)),\n atom: callOrReturn(getExtensionField<NodeConfig['atom']>(extension, 'atom', context)),\n selectable: callOrReturn(\n getExtensionField<NodeConfig['selectable']>(extension, 'selectable', context),\n ),\n draggable: callOrReturn(\n getExtensionField<NodeConfig['draggable']>(extension, 'draggable', context),\n ),\n code: callOrReturn(getExtensionField<NodeConfig['code']>(extension, 'code', context)),\n whitespace: callOrReturn(getExtensionField<NodeConfig['whitespace']>(extension, 'whitespace', context)),\n linebreakReplacement: callOrReturn(getExtensionField<NodeConfig['linebreakReplacement']>(extension, 'linebreakReplacement', context)),\n defining: callOrReturn(\n getExtensionField<NodeConfig['defining']>(extension, 'defining', context),\n ),\n isolating: callOrReturn(\n getExtensionField<NodeConfig['isolating']>(extension, 'isolating', context),\n ),\n attrs: Object.fromEntries(\n extensionAttributes.map(extensionAttribute => {\n return [extensionAttribute.name, { default: extensionAttribute?.attribute?.default }]\n }),\n ),\n })\n\n const parseHTML = callOrReturn(\n getExtensionField<NodeConfig['parseHTML']>(extension, 'parseHTML', context),\n )\n\n if (parseHTML) {\n schema.parseDOM = parseHTML.map(parseRule => injectExtensionAttributesToParseRule(parseRule, extensionAttributes)) as TagParseRule[]\n }\n\n const renderHTML = getExtensionField<NodeConfig['renderHTML']>(\n extension,\n 'renderHTML',\n context,\n )\n\n if (renderHTML) {\n schema.toDOM = node => renderHTML({\n node,\n HTMLAttributes: getRenderedAttributes(node, extensionAttributes),\n })\n }\n\n const renderText = getExtensionField<NodeConfig['renderText']>(\n extension,\n 'renderText',\n context,\n )\n\n if (renderText) {\n schema.toText = renderText\n }\n\n return [extension.name, schema]\n }),\n )\n\n const marks = Object.fromEntries(\n markExtensions.map(extension => {\n const extensionAttributes = allAttributes.filter(\n attribute => attribute.type === extension.name,\n )\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n editor,\n }\n\n const extraMarkFields = extensions.reduce((fields, e) => {\n const extendMarkSchema = getExtensionField<AnyConfig['extendMarkSchema']>(\n e,\n 'extendMarkSchema',\n context,\n )\n\n return {\n ...fields,\n ...(extendMarkSchema ? extendMarkSchema(extension as any) : {}),\n }\n }, {})\n\n const schema: MarkSpec = cleanUpSchemaItem({\n ...extraMarkFields,\n inclusive: callOrReturn(\n getExtensionField<MarkConfig['inclusive']>(extension, 'inclusive', context),\n ),\n excludes: callOrReturn(\n getExtensionField<MarkConfig['excludes']>(extension, 'excludes', context),\n ),\n group: callOrReturn(getExtensionField<MarkConfig['group']>(extension, 'group', context)),\n spanning: callOrReturn(\n getExtensionField<MarkConfig['spanning']>(extension, 'spanning', context),\n ),\n code: callOrReturn(getExtensionField<MarkConfig['code']>(extension, 'code', context)),\n attrs: Object.fromEntries(\n extensionAttributes.map(extensionAttribute => {\n return [extensionAttribute.name, { default: extensionAttribute?.attribute?.default }]\n }),\n ),\n })\n\n const parseHTML = callOrReturn(\n getExtensionField<MarkConfig['parseHTML']>(extension, 'parseHTML', context),\n )\n\n if (parseHTML) {\n schema.parseDOM = parseHTML.map(parseRule => injectExtensionAttributesToParseRule(parseRule, extensionAttributes))\n }\n\n const renderHTML = getExtensionField<MarkConfig['renderHTML']>(\n extension,\n 'renderHTML',\n context,\n )\n\n if (renderHTML) {\n schema.toDOM = mark => renderHTML({\n mark,\n HTMLAttributes: getRenderedAttributes(mark, extensionAttributes),\n })\n }\n\n return [extension.name, schema]\n }),\n )\n\n return new Schema({\n topNode,\n nodes,\n marks,\n })\n}\n","import { MarkType, NodeType, Schema } from '@tiptap/pm/model'\n\n/**\n * Tries to get a node or mark type by its name.\n * @param name The name of the node or mark type\n * @param schema The Prosemiror schema to search in\n * @returns The node or mark type, or null if it doesn't exist\n */\nexport function getSchemaTypeByName(name: string, schema: Schema): NodeType | MarkType | null {\n return schema.nodes[name] || schema.marks[name] || null\n}\n","import { AnyExtension, EnableRules } from '../types.js'\n\nexport function isExtensionRulesEnabled(extension: AnyExtension, enabled: EnableRules): boolean {\n if (Array.isArray(enabled)) {\n return enabled.some(enabledExtension => {\n const name = typeof enabledExtension === 'string'\n ? enabledExtension\n : enabledExtension.name\n\n return name === extension.name\n })\n }\n\n return enabled\n}\n","import { DOMSerializer, Fragment, Schema } from '@tiptap/pm/model'\n\nexport function getHTMLFromFragment(fragment: Fragment, schema: Schema): string {\n const documentFragment = DOMSerializer.fromSchema(schema).serializeFragment(fragment)\n\n const temporaryDocument = document.implementation.createHTMLDocument()\n const container = temporaryDocument.createElement('div')\n\n container.appendChild(documentFragment)\n\n return container.innerHTML\n}\n","import { ResolvedPos } from '@tiptap/pm/model'\n\n/**\n * Returns the text content of a resolved prosemirror position\n * @param $from The resolved position to get the text content from\n * @param maxMatch The maximum number of characters to match\n * @returns The text content\n */\nexport const getTextContentFromNodes = ($from: ResolvedPos, maxMatch = 500) => {\n let textBefore = ''\n\n const sliceEndPos = $from.parentOffset\n\n $from.parent.nodesBetween(\n Math.max(0, sliceEndPos - maxMatch),\n sliceEndPos,\n (node, pos, parent, index) => {\n const chunk = node.type.spec.toText?.({\n node,\n pos,\n parent,\n index,\n })\n || node.textContent\n || '%leaf%'\n\n textBefore += node.isAtom && !node.isText ? chunk : chunk.slice(0, Math.max(0, sliceEndPos - pos))\n },\n )\n\n return textBefore\n}\n","export function isRegExp(value: any): value is RegExp {\n return Object.prototype.toString.call(value) === '[object RegExp]'\n}\n","import { Fragment, Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { EditorState, Plugin, TextSelection } from '@tiptap/pm/state'\n\nimport { CommandManager } from './CommandManager.js'\nimport { Editor } from './Editor.js'\nimport { createChainableState } from './helpers/createChainableState.js'\nimport { getHTMLFromFragment } from './helpers/getHTMLFromFragment.js'\nimport { getTextContentFromNodes } from './helpers/getTextContentFromNodes.js'\nimport {\n CanCommands,\n ChainedCommands,\n ExtendedRegExpMatchArray,\n Range,\n SingleCommands,\n} from './types.js'\nimport { isRegExp } from './utilities/isRegExp.js'\n\nexport type InputRuleMatch = {\n index: number;\n text: string;\n replaceWith?: string;\n match?: RegExpMatchArray;\n data?: Record<string, any>;\n};\n\nexport type InputRuleFinder = RegExp | ((text: string) => InputRuleMatch | null);\n\nexport class InputRule {\n find: InputRuleFinder\n\n handler: (props: {\n state: EditorState;\n range: Range;\n match: ExtendedRegExpMatchArray;\n commands: SingleCommands;\n chain: () => ChainedCommands;\n can: () => CanCommands;\n }) => void | null\n\n constructor(config: {\n find: InputRuleFinder;\n handler: (props: {\n state: EditorState;\n range: Range;\n match: ExtendedRegExpMatchArray;\n commands: SingleCommands;\n chain: () => ChainedCommands;\n can: () => CanCommands;\n }) => void | null;\n }) {\n this.find = config.find\n this.handler = config.handler\n }\n}\n\nconst inputRuleMatcherHandler = (\n text: string,\n find: InputRuleFinder,\n): ExtendedRegExpMatchArray | null => {\n if (isRegExp(find)) {\n return find.exec(text)\n }\n\n const inputRuleMatch = find(text)\n\n if (!inputRuleMatch) {\n return null\n }\n\n const result: ExtendedRegExpMatchArray = [inputRuleMatch.text]\n\n result.index = inputRuleMatch.index\n result.input = text\n result.data = inputRuleMatch.data\n\n if (inputRuleMatch.replaceWith) {\n if (!inputRuleMatch.text.includes(inputRuleMatch.replaceWith)) {\n console.warn(\n '[tiptap warn]: \"inputRuleMatch.replaceWith\" must be part of \"inputRuleMatch.text\".',\n )\n }\n\n result.push(inputRuleMatch.replaceWith)\n }\n\n return result\n}\n\nfunction run(config: {\n editor: Editor;\n from: number;\n to: number;\n text: string;\n rules: InputRule[];\n plugin: Plugin;\n}): boolean {\n const {\n editor, from, to, text, rules, plugin,\n } = config\n const { view } = editor\n\n if (view.composing) {\n return false\n }\n\n const $from = view.state.doc.resolve(from)\n\n if (\n // check for code node\n $from.parent.type.spec.code\n // check for code mark\n || !!($from.nodeBefore || $from.nodeAfter)?.marks.find(mark => mark.type.spec.code)\n ) {\n return false\n }\n\n let matched = false\n\n const textBefore = getTextContentFromNodes($from) + text\n\n rules.forEach(rule => {\n if (matched) {\n return\n }\n\n const match = inputRuleMatcherHandler(textBefore, rule.find)\n\n if (!match) {\n return\n }\n\n const tr = view.state.tr\n const state = createChainableState({\n state: view.state,\n transaction: tr,\n })\n const range = {\n from: from - (match[0].length - text.length),\n to,\n }\n\n const { commands, chain, can } = new CommandManager({\n editor,\n state,\n })\n\n const handler = rule.handler({\n state,\n range,\n match,\n commands,\n chain,\n can,\n })\n\n // stop if there are no changes\n if (handler === null || !tr.steps.length) {\n return\n }\n\n // store transform as meta data\n // so we can undo input rules within the `undoInputRules` command\n tr.setMeta(plugin, {\n transform: tr,\n from,\n to,\n text,\n })\n\n view.dispatch(tr)\n matched = true\n })\n\n return matched\n}\n\n/**\n * Create an input rules plugin. When enabled, it will cause text\n * input that matches any of the given rules to trigger the rule’s\n * action.\n */\nexport function inputRulesPlugin(props: { editor: Editor; rules: InputRule[] }): Plugin {\n const { editor, rules } = props\n const plugin = new Plugin({\n state: {\n init() {\n return null\n },\n apply(tr, prev, state) {\n const stored = tr.getMeta(plugin)\n\n if (stored) {\n return stored\n }\n\n // if InputRule is triggered by insertContent()\n const simulatedInputMeta = tr.getMeta('applyInputRules') as\n | undefined\n | {\n from: number;\n text: string | ProseMirrorNode | Fragment;\n }\n const isSimulatedInput = !!simulatedInputMeta\n\n if (isSimulatedInput) {\n setTimeout(() => {\n let { text } = simulatedInputMeta\n\n if (typeof text === 'string') {\n text = text as string\n } else {\n text = getHTMLFromFragment(Fragment.from(text), state.schema)\n }\n\n const { from } = simulatedInputMeta\n const to = from + text.length\n\n run({\n editor,\n from,\n to,\n text,\n rules,\n plugin,\n })\n })\n }\n\n return tr.selectionSet || tr.docChanged ? null : prev\n },\n },\n\n props: {\n handleTextInput(view, from, to, text) {\n return run({\n editor,\n from,\n to,\n text,\n rules,\n plugin,\n })\n },\n\n handleDOMEvents: {\n compositionend: view => {\n setTimeout(() => {\n const { $cursor } = view.state.selection as TextSelection\n\n if ($cursor) {\n run({\n editor,\n from: $cursor.pos,\n to: $cursor.pos,\n text: '',\n rules,\n plugin,\n })\n }\n })\n\n return false\n },\n },\n\n // add support for input rules to trigger on enter\n // this is useful for example for code blocks\n handleKeyDown(view, event) {\n if (event.key !== 'Enter') {\n return false\n }\n\n const { $cursor } = view.state.selection as TextSelection\n\n if ($cursor) {\n return run({\n editor,\n from: $cursor.pos,\n to: $cursor.pos,\n text: '\\n',\n rules,\n plugin,\n })\n }\n\n return false\n },\n },\n\n // @ts-ignore\n isInputRules: true,\n }) as Plugin\n\n return plugin\n}\n","// see: https://github.com/mesqueeb/is-what/blob/88d6e4ca92fb2baab6003c54e02eedf4e729e5ab/src/index.ts\n\nfunction getType(value: any): string {\n return Object.prototype.toString.call(value).slice(8, -1)\n}\n\nexport function isPlainObject(value: any): value is Record<string, any> {\n if (getType(value) !== 'Object') {\n return false\n }\n\n return value.constructor === Object && Object.getPrototypeOf(value) === Object.prototype\n}\n","import { isPlainObject } from './isPlainObject.js'\n\nexport function mergeDeep(target: Record<string, any>, source: Record<string, any>): Record<string, any> {\n const output = { ...target }\n\n if (isPlainObject(target) && isPlainObject(source)) {\n Object.keys(source).forEach(key => {\n if (isPlainObject(source[key]) && isPlainObject(target[key])) {\n output[key] = mergeDeep(target[key], source[key])\n } else {\n output[key] = source[key]\n }\n })\n }\n\n return output\n}\n","import {\n DOMOutputSpec, Mark as ProseMirrorMark, MarkSpec, MarkType,\n} from '@tiptap/pm/model'\nimport { Plugin, Transaction } from '@tiptap/pm/state'\n\nimport { Editor } from './Editor.js'\nimport { getExtensionField } from './helpers/getExtensionField.js'\nimport { MarkConfig } from './index.js'\nimport { InputRule } from './InputRule.js'\nimport { Node } from './Node.js'\nimport { PasteRule } from './PasteRule.js'\nimport {\n AnyConfig,\n Attributes,\n Extensions,\n GlobalAttributes,\n KeyboardShortcutCommand,\n ParentConfig,\n RawCommands,\n} from './types.js'\nimport { callOrReturn } from './utilities/callOrReturn.js'\nimport { mergeDeep } from './utilities/mergeDeep.js'\n\ndeclare module '@tiptap/core' {\n export interface MarkConfig<Options = any, Storage = any> {\n // @ts-ignore - this is a dynamic key\n [key: string]: any\n\n /**\n * The extension name - this must be unique.\n * It will be used to identify the extension.\n *\n * @example 'myExtension'\n */\n name: string\n\n /**\n * The priority of your extension. The higher, the earlier it will be called\n * and will take precedence over other extensions with a lower priority.\n * @default 100\n * @example 101\n */\n priority?: number\n\n /**\n * The default options for this extension.\n * @example\n * defaultOptions: {\n * myOption: 'foo',\n * myOtherOption: 10,\n * }\n */\n defaultOptions?: Options\n\n /**\n * This method will add options to this extension\n * @see https://tiptap.dev/guide/custom-extensions#settings\n * @example\n * addOptions() {\n * return {\n * myOption: 'foo',\n * myOtherOption: 10,\n * }\n */\n addOptions?: (this: {\n name: string\n parent: Exclude<ParentConfig<MarkConfig<Options, Storage>>['addOptions'], undefined>\n }) => Options\n\n /**\n * The default storage this extension can save data to.\n * @see https://tiptap.dev/guide/custom-extensions#storage\n * @example\n * defaultStorage: {\n * prefetchedUsers: [],\n * loading: false,\n * }\n */\n addStorage?: (this: {\n name: string\n options: Options\n parent: Exclude<ParentConfig<MarkConfig<Options, Storage>>['addStorage'], undefined>\n }) => Storage\n\n /**\n * This function adds globalAttributes to specific nodes.\n * @see https://tiptap.dev/guide/custom-extensions#global-attributes\n * @example\n * addGlobalAttributes() {\n * return [\n * {\n // Extend the following extensions\n * types: [\n * 'heading',\n * 'paragraph',\n * ],\n * // … with those attributes\n * attributes: {\n * textAlign: {\n * default: 'left',\n * renderHTML: attributes => ({\n * style: `text-align: ${attributes.textAlign}`,\n * }),\n * parseHTML: element => element.style.textAlign || 'left',\n * },\n * },\n * },\n * ]\n * }\n */\n addGlobalAttributes?: (this: {\n name: string\n options: Options\n storage: Storage\n extensions: (Node | Mark)[]\n parent: ParentConfig<MarkConfig<Options, Storage>>['addGlobalAttributes']\n }) => GlobalAttributes\n\n /**\n * This function adds commands to the editor\n * @see https://tiptap.dev/guide/custom-extensions#keyboard-shortcuts\n * @example\n * addCommands() {\n * return {\n * myCommand: () => ({ chain }) => chain().setMark('type', 'foo').run(),\n * }\n * }\n */\n addCommands?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['addCommands']\n }) => Partial<RawCommands>\n\n /**\n * This function registers keyboard shortcuts.\n * @see https://tiptap.dev/guide/custom-extensions#keyboard-shortcuts\n * @example\n * addKeyboardShortcuts() {\n * return {\n * 'Mod-l': () => this.editor.commands.toggleBulletList(),\n * }\n * },\n */\n addKeyboardShortcuts?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['addKeyboardShortcuts']\n }) => {\n [key: string]: KeyboardShortcutCommand\n }\n\n /**\n * This function adds input rules to the editor.\n * @see https://tiptap.dev/guide/custom-extensions#input-rules\n * @example\n * addInputRules() {\n * return [\n * markInputRule({\n * find: inputRegex,\n * type: this.type,\n * }),\n * ]\n * },\n */\n addInputRules?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['addInputRules']\n }) => InputRule[]\n\n /**\n * This function adds paste rules to the editor.\n * @see https://tiptap.dev/guide/custom-extensions#paste-rules\n * @example\n * addPasteRules() {\n * return [\n * markPasteRule({\n * find: pasteRegex,\n * type: this.type,\n * }),\n * ]\n * },\n */\n addPasteRules?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['addPasteRules']\n }) => PasteRule[]\n\n /**\n * This function adds Prosemirror plugins to the editor\n * @see https://tiptap.dev/guide/custom-extensions#prosemirror-plugins\n * @example\n * addProseMirrorPlugins() {\n * return [\n * customPlugin(),\n * ]\n * }\n */\n addProseMirrorPlugins?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['addProseMirrorPlugins']\n }) => Plugin[]\n\n /**\n * This function adds additional extensions to the editor. This is useful for\n * building extension kits.\n * @example\n * addExtensions() {\n * return [\n * BulletList,\n * OrderedList,\n * ListItem\n * ]\n * }\n */\n addExtensions?: (this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['addExtensions']\n }) => Extensions\n\n /**\n * This function extends the schema of the node.\n * @example\n * extendNodeSchema() {\n * return {\n * group: 'inline',\n * selectable: false,\n * }\n * }\n */\n extendNodeSchema?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['extendNodeSchema']\n },\n extension: Node,\n ) => Record<string, any>)\n | null\n\n /**\n * This function extends the schema of the mark.\n * @example\n * extendMarkSchema() {\n * return {\n * group: 'inline',\n * selectable: false,\n * }\n * }\n */\n extendMarkSchema?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['extendMarkSchema']\n },\n extension: Mark,\n ) => Record<string, any>)\n | null\n\n /**\n * The editor is not ready yet.\n */\n onBeforeCreate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onBeforeCreate']\n }) => void)\n | null\n\n /**\n * The editor is ready.\n */\n onCreate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onCreate']\n }) => void)\n | null\n\n /**\n * The content has changed.\n */\n onUpdate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onUpdate']\n }) => void)\n | null\n\n /**\n * The selection has changed.\n */\n onSelectionUpdate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onSelectionUpdate']\n }) => void)\n | null\n\n /**\n * The editor state has changed.\n */\n onTransaction?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onTransaction']\n },\n props: {\n editor: Editor\n transaction: Transaction\n },\n ) => void)\n | null\n\n /**\n * The editor is focused.\n */\n onFocus?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onFocus']\n },\n props: {\n event: FocusEvent\n },\n ) => void)\n | null\n\n /**\n * The editor isn’t focused anymore.\n */\n onBlur?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onBlur']\n },\n props: {\n event: FocusEvent\n },\n ) => void)\n | null\n\n /**\n * The editor is destroyed.\n */\n onDestroy?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: MarkType\n parent: ParentConfig<MarkConfig<Options, Storage>>['onDestroy']\n }) => void)\n | null\n\n /**\n * Keep mark after split node\n */\n keepOnSplit?: boolean | (() => boolean)\n\n /**\n * Inclusive\n */\n inclusive?:\n | MarkSpec['inclusive']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['inclusive']\n editor?: Editor\n }) => MarkSpec['inclusive'])\n\n /**\n * Excludes\n */\n excludes?:\n | MarkSpec['excludes']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['excludes']\n editor?: Editor\n }) => MarkSpec['excludes'])\n\n /**\n * Marks this Mark as exitable\n */\n exitable?: boolean | (() => boolean)\n\n /**\n * Group\n */\n group?:\n | MarkSpec['group']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['group']\n editor?: Editor\n }) => MarkSpec['group'])\n\n /**\n * Spanning\n */\n spanning?:\n | MarkSpec['spanning']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['spanning']\n editor?: Editor\n }) => MarkSpec['spanning'])\n\n /**\n * Code\n */\n code?:\n | boolean\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['code']\n editor?: Editor\n }) => boolean)\n\n /**\n * Parse HTML\n */\n parseHTML?: (this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['parseHTML']\n editor?: Editor\n }) => MarkSpec['parseDOM']\n\n /**\n * Render HTML\n */\n renderHTML?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['renderHTML']\n editor?: Editor\n },\n props: {\n mark: ProseMirrorMark\n HTMLAttributes: Record<string, any>\n },\n ) => DOMOutputSpec)\n | null\n\n /**\n * Attributes\n */\n addAttributes?: (this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<MarkConfig<Options, Storage>>['addAttributes']\n editor?: Editor\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n }) => Attributes | {}\n }\n}\n\n/**\n * The Mark class is used to create custom mark extensions.\n * @see https://tiptap.dev/api/extensions#create-a-new-extension\n */\nexport class Mark<Options = any, Storage = any> {\n type = 'mark'\n\n name = 'mark'\n\n parent: Mark | null = null\n\n child: Mark | null = null\n\n options: Options\n\n storage: Storage\n\n config: MarkConfig = {\n name: this.name,\n defaultOptions: {},\n }\n\n constructor(config: Partial<MarkConfig<Options, Storage>> = {}) {\n this.config = {\n ...this.config,\n ...config,\n }\n\n this.name = this.config.name\n\n if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {\n console.warn(\n `[tiptap warn]: BREAKING CHANGE: \"defaultOptions\" is deprecated. Please use \"addOptions\" instead. Found in extension: \"${this.name}\".`,\n )\n }\n\n // TODO: remove `addOptions` fallback\n this.options = this.config.defaultOptions\n\n if (this.config.addOptions) {\n this.options = callOrReturn(\n getExtensionField<AnyConfig['addOptions']>(this, 'addOptions', {\n name: this.name,\n }),\n )\n }\n\n this.storage = callOrReturn(\n getExtensionField<AnyConfig['addStorage']>(this, 'addStorage', {\n name: this.name,\n options: this.options,\n }),\n ) || {}\n }\n\n static create<O = any, S = any>(config: Partial<MarkConfig<O, S>> = {}) {\n return new Mark<O, S>(config)\n }\n\n configure(options: Partial<Options> = {}) {\n // return a new instance so we can use the same extension\n // with different calls of `configure`\n const extension = this.extend<Options, Storage>({\n ...this.config,\n addOptions: () => {\n return mergeDeep(this.options as Record<string, any>, options) as Options\n },\n })\n\n // Always preserve the current name\n extension.name = this.name\n // Set the parent to be our parent\n extension.parent = this.parent\n\n return extension\n }\n\n extend<ExtendedOptions = Options, ExtendedStorage = Storage>(\n extendedConfig: Partial<MarkConfig<ExtendedOptions, ExtendedStorage>> = {},\n ) {\n const extension = new Mark<ExtendedOptions, ExtendedStorage>(extendedConfig)\n\n extension.parent = this\n\n this.child = extension\n\n extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name\n\n if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {\n console.warn(\n `[tiptap warn]: BREAKING CHANGE: \"defaultOptions\" is deprecated. Please use \"addOptions\" instead. Found in extension: \"${extension.name}\".`,\n )\n }\n\n extension.options = callOrReturn(\n getExtensionField<AnyConfig['addOptions']>(extension, 'addOptions', {\n name: extension.name,\n }),\n )\n\n extension.storage = callOrReturn(\n getExtensionField<AnyConfig['addStorage']>(extension, 'addStorage', {\n name: extension.name,\n options: extension.options,\n }),\n )\n\n return extension\n }\n\n static handleExit({ editor, mark }: { editor: Editor; mark: Mark }) {\n const { tr } = editor.state\n const currentPos = editor.state.selection.$from\n const isAtEnd = currentPos.pos === currentPos.end()\n\n if (isAtEnd) {\n const currentMarks = currentPos.marks()\n const isInMark = !!currentMarks.find(m => m?.type.name === mark.name)\n\n if (!isInMark) {\n return false\n }\n\n const removeMark = currentMarks.find(m => m?.type.name === mark.name)\n\n if (removeMark) {\n tr.removeStoredMark(removeMark)\n }\n tr.insertText(' ', currentPos.pos)\n\n editor.view.dispatch(tr)\n\n return true\n }\n\n return false\n }\n}\n","export function isNumber(value: any): value is number {\n return typeof value === 'number'\n}\n","import { Fragment, Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { EditorState, Plugin } from '@tiptap/pm/state'\n\nimport { CommandManager } from './CommandManager.js'\nimport { Editor } from './Editor.js'\nimport { createChainableState } from './helpers/createChainableState.js'\nimport { getHTMLFromFragment } from './helpers/getHTMLFromFragment.js'\nimport {\n CanCommands,\n ChainedCommands,\n ExtendedRegExpMatchArray,\n Range,\n SingleCommands,\n} from './types.js'\nimport { isNumber } from './utilities/isNumber.js'\nimport { isRegExp } from './utilities/isRegExp.js'\n\nexport type PasteRuleMatch = {\n index: number;\n text: string;\n replaceWith?: string;\n match?: RegExpMatchArray;\n data?: Record<string, any>;\n};\n\nexport type PasteRuleFinder =\n | RegExp\n | ((text: string, event?: ClipboardEvent | null) => PasteRuleMatch[] | null | undefined);\n\n/**\n * Paste rules are used to react to pasted content.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules\n */\nexport class PasteRule {\n find: PasteRuleFinder\n\n handler: (props: {\n state: EditorState;\n range: Range;\n match: ExtendedRegExpMatchArray;\n commands: SingleCommands;\n chain: () => ChainedCommands;\n can: () => CanCommands;\n pasteEvent: ClipboardEvent | null;\n dropEvent: DragEvent | null;\n }) => void | null\n\n constructor(config: {\n find: PasteRuleFinder;\n handler: (props: {\n can: () => CanCommands;\n chain: () => ChainedCommands;\n commands: SingleCommands;\n dropEvent: DragEvent | null;\n match: ExtendedRegExpMatchArray;\n pasteEvent: ClipboardEvent | null;\n range: Range;\n state: EditorState;\n }) => void | null;\n }) {\n this.find = config.find\n this.handler = config.handler\n }\n}\n\nconst pasteRuleMatcherHandler = (\n text: string,\n find: PasteRuleFinder,\n event?: ClipboardEvent | null,\n): ExtendedRegExpMatchArray[] => {\n if (isRegExp(find)) {\n return [...text.matchAll(find)]\n }\n\n const matches = find(text, event)\n\n if (!matches) {\n return []\n }\n\n return matches.map(pasteRuleMatch => {\n const result: ExtendedRegExpMatchArray = [pasteRuleMatch.text]\n\n result.index = pasteRuleMatch.index\n result.input = text\n result.data = pasteRuleMatch.data\n\n if (pasteRuleMatch.replaceWith) {\n if (!pasteRuleMatch.text.includes(pasteRuleMatch.replaceWith)) {\n console.warn(\n '[tiptap warn]: \"pasteRuleMatch.replaceWith\" must be part of \"pasteRuleMatch.text\".',\n )\n }\n\n result.push(pasteRuleMatch.replaceWith)\n }\n\n return result\n })\n}\n\nfunction run(config: {\n editor: Editor;\n state: EditorState;\n from: number;\n to: number;\n rule: PasteRule;\n pasteEvent: ClipboardEvent | null;\n dropEvent: DragEvent | null;\n}): boolean {\n const {\n editor, state, from, to, rule, pasteEvent, dropEvent,\n } = config\n\n const { commands, chain, can } = new CommandManager({\n editor,\n state,\n })\n\n const handlers: (void | null)[] = []\n\n state.doc.nodesBetween(from, to, (node, pos) => {\n if (!node.isTextblock || node.type.spec.code) {\n return\n }\n\n const resolvedFrom = Math.max(from, pos)\n const resolvedTo = Math.min(to, pos + node.content.size)\n const textToMatch = node.textBetween(resolvedFrom - pos, resolvedTo - pos, undefined, '\\ufffc')\n\n const matches = pasteRuleMatcherHandler(textToMatch, rule.find, pasteEvent)\n\n matches.forEach(match => {\n if (match.index === undefined) {\n return\n }\n\n const start = resolvedFrom + match.index + 1\n const end = start + match[0].length\n const range = {\n from: state.tr.mapping.map(start),\n to: state.tr.mapping.map(end),\n }\n\n const handler = rule.handler({\n state,\n range,\n match,\n commands,\n chain,\n can,\n pasteEvent,\n dropEvent,\n })\n\n handlers.push(handler)\n })\n })\n\n const success = handlers.every(handler => handler !== null)\n\n return success\n}\n\n// When dragging across editors, must get another editor instance to delete selection content.\nlet tiptapDragFromOtherEditor: Editor | null = null\n\nconst createClipboardPasteEvent = (text: string) => {\n const event = new ClipboardEvent('paste', {\n clipboardData: new DataTransfer(),\n })\n\n event.clipboardData?.setData('text/html', text)\n\n return event\n}\n\n/**\n * Create an paste rules plugin. When enabled, it will cause pasted\n * text that matches any of the given rules to trigger the rule’s\n * action.\n */\nexport function pasteRulesPlugin(props: { editor: Editor; rules: PasteRule[] }): Plugin[] {\n const { editor, rules } = props\n let dragSourceElement: Element | null = null\n let isPastedFromProseMirror = false\n let isDroppedFromProseMirror = false\n let pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null\n let dropEvent: DragEvent | null\n\n try {\n dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null\n } catch {\n dropEvent = null\n }\n\n const processEvent = ({\n state,\n from,\n to,\n rule,\n pasteEvt,\n }: {\n state: EditorState;\n from: number;\n to: { b: number };\n rule: PasteRule;\n pasteEvt: ClipboardEvent | null;\n }) => {\n const tr = state.tr\n const chainableState = createChainableState({\n state,\n transaction: tr,\n })\n\n const handler = run({\n editor,\n state: chainableState,\n from: Math.max(from - 1, 0),\n to: to.b - 1,\n rule,\n pasteEvent: pasteEvt,\n dropEvent,\n })\n\n if (!handler || !tr.steps.length) {\n return\n }\n\n try {\n dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null\n } catch {\n dropEvent = null\n }\n pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null\n\n return tr\n }\n\n const plugins = rules.map(rule => {\n return new Plugin({\n // we register a global drag handler to track the current drag source element\n view(view) {\n const handleDragstart = (event: DragEvent) => {\n dragSourceElement = view.dom.parentElement?.contains(event.target as Element)\n ? view.dom.parentElement\n : null\n\n if (dragSourceElement) {\n tiptapDragFromOtherEditor = editor\n }\n }\n\n const handleDragend = () => {\n if (tiptapDragFromOtherEditor) {\n tiptapDragFromOtherEditor = null\n }\n }\n\n window.addEventListener('dragstart', handleDragstart)\n window.addEventListener('dragend', handleDragend)\n\n return {\n destroy() {\n window.removeEventListener('dragstart', handleDragstart)\n window.removeEventListener('dragend', handleDragend)\n },\n }\n },\n\n props: {\n handleDOMEvents: {\n drop: (view, event: Event) => {\n isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement\n dropEvent = event as DragEvent\n\n if (!isDroppedFromProseMirror) {\n const dragFromOtherEditor = tiptapDragFromOtherEditor\n\n if (dragFromOtherEditor?.isEditable) {\n // setTimeout to avoid the wrong content after drop, timeout arg can't be empty or 0\n setTimeout(() => {\n const selection = dragFromOtherEditor.state.selection\n\n if (selection) {\n dragFromOtherEditor.commands.deleteRange({ from: selection.from, to: selection.to })\n }\n }, 10)\n }\n }\n return false\n },\n\n paste: (_view, event: Event) => {\n const html = (event as ClipboardEvent).clipboardData?.getData('text/html')\n\n pasteEvent = event as ClipboardEvent\n\n isPastedFromProseMirror = !!html?.includes('data-pm-slice')\n\n return false\n },\n },\n },\n\n appendTransaction: (transactions, oldState, state) => {\n const transaction = transactions[0]\n const isPaste = transaction.getMeta('uiEvent') === 'paste' && !isPastedFromProseMirror\n const isDrop = transaction.getMeta('uiEvent') === 'drop' && !isDroppedFromProseMirror\n\n // if PasteRule is triggered by insertContent()\n const simulatedPasteMeta = transaction.getMeta('applyPasteRules') as\n | undefined\n | { from: number; text: string | ProseMirrorNode | Fragment }\n const isSimulatedPaste = !!simulatedPasteMeta\n\n if (!isPaste && !isDrop && !isSimulatedPaste) {\n return\n }\n\n // Handle simulated paste\n if (isSimulatedPaste) {\n let { text } = simulatedPasteMeta\n\n if (typeof text === 'string') {\n text = text as string\n } else {\n text = getHTMLFromFragment(Fragment.from(text), state.schema)\n }\n\n const { from } = simulatedPasteMeta\n const to = from + text.length\n\n const pasteEvt = createClipboardPasteEvent(text)\n\n return processEvent({\n rule,\n state,\n from,\n to: { b: to },\n pasteEvt,\n })\n }\n\n // handle actual paste/drop\n const from = oldState.doc.content.findDiffStart(state.doc.content)\n const to = oldState.doc.content.findDiffEnd(state.doc.content)\n\n // stop if there is no changed range\n if (!isNumber(from) || !to || from === to.b) {\n return\n }\n\n return processEvent({\n rule,\n state,\n from,\n to,\n pasteEvt: pasteEvent,\n })\n },\n })\n })\n\n return plugins\n}\n","export function findDuplicates(items: any[]): any[] {\n const filtered = items.filter((el, index) => items.indexOf(el) !== index)\n\n return Array.from(new Set(filtered))\n}\n","import { keymap } from '@tiptap/pm/keymap'\nimport { Schema } from '@tiptap/pm/model'\nimport { Plugin } from '@tiptap/pm/state'\nimport { NodeViewConstructor } from '@tiptap/pm/view'\n\nimport type { Editor } from './Editor.js'\nimport { getAttributesFromExtensions } from './helpers/getAttributesFromExtensions.js'\nimport { getExtensionField } from './helpers/getExtensionField.js'\nimport { getNodeType } from './helpers/getNodeType.js'\nimport { getRenderedAttributes } from './helpers/getRenderedAttributes.js'\nimport { getSchemaByResolvedExtensions } from './helpers/getSchemaByResolvedExtensions.js'\nimport { getSchemaTypeByName } from './helpers/getSchemaTypeByName.js'\nimport { isExtensionRulesEnabled } from './helpers/isExtensionRulesEnabled.js'\nimport { splitExtensions } from './helpers/splitExtensions.js'\nimport type { NodeConfig } from './index.js'\nimport { InputRule, inputRulesPlugin } from './InputRule.js'\nimport { Mark } from './Mark.js'\nimport { PasteRule, pasteRulesPlugin } from './PasteRule.js'\nimport { AnyConfig, Extensions, RawCommands } from './types.js'\nimport { callOrReturn } from './utilities/callOrReturn.js'\nimport { findDuplicates } from './utilities/findDuplicates.js'\n\nexport class ExtensionManager {\n editor: Editor\n\n schema: Schema\n\n extensions: Extensions\n\n splittableMarks: string[] = []\n\n constructor(extensions: Extensions, editor: Editor) {\n this.editor = editor\n this.extensions = ExtensionManager.resolve(extensions)\n this.schema = getSchemaByResolvedExtensions(this.extensions, editor)\n this.setupExtensions()\n }\n\n /**\n * Returns a flattened and sorted extension list while\n * also checking for duplicated extensions and warns the user.\n * @param extensions An array of Tiptap extensions\n * @returns An flattened and sorted array of Tiptap extensions\n */\n static resolve(extensions: Extensions): Extensions {\n const resolvedExtensions = ExtensionManager.sort(ExtensionManager.flatten(extensions))\n const duplicatedNames = findDuplicates(resolvedExtensions.map(extension => extension.name))\n\n if (duplicatedNames.length) {\n console.warn(\n `[tiptap warn]: Duplicate extension names found: [${duplicatedNames\n .map(item => `'${item}'`)\n .join(', ')}]. This can lead to issues.`,\n )\n }\n\n return resolvedExtensions\n }\n\n /**\n * Create a flattened array of extensions by traversing the `addExtensions` field.\n * @param extensions An array of Tiptap extensions\n * @returns A flattened array of Tiptap extensions\n */\n static flatten(extensions: Extensions): Extensions {\n return (\n extensions\n .map(extension => {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n }\n\n const addExtensions = getExtensionField<AnyConfig['addExtensions']>(\n extension,\n 'addExtensions',\n context,\n )\n\n if (addExtensions) {\n return [extension, ...this.flatten(addExtensions())]\n }\n\n return extension\n })\n // `Infinity` will break TypeScript so we set a number that is probably high enough\n .flat(10)\n )\n }\n\n /**\n * Sort extensions by priority.\n * @param extensions An array of Tiptap extensions\n * @returns A sorted array of Tiptap extensions by priority\n */\n static sort(extensions: Extensions): Extensions {\n const defaultPriority = 100\n\n return extensions.sort((a, b) => {\n const priorityA = getExtensionField<AnyConfig['priority']>(a, 'priority') || defaultPriority\n const priorityB = getExtensionField<AnyConfig['priority']>(b, 'priority') || defaultPriority\n\n if (priorityA > priorityB) {\n return -1\n }\n\n if (priorityA < priorityB) {\n return 1\n }\n\n return 0\n })\n }\n\n /**\n * Get all commands from the extensions.\n * @returns An object with all commands where the key is the command name and the value is the command function\n */\n get commands(): RawCommands {\n return this.extensions.reduce((commands, extension) => {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n editor: this.editor,\n type: getSchemaTypeByName(extension.name, this.schema),\n }\n\n const addCommands = getExtensionField<AnyConfig['addCommands']>(\n extension,\n 'addCommands',\n context,\n )\n\n if (!addCommands) {\n return commands\n }\n\n return {\n ...commands,\n ...addCommands(),\n }\n }, {} as RawCommands)\n }\n\n /**\n * Get all registered Prosemirror plugins from the extensions.\n * @returns An array of Prosemirror plugins\n */\n get plugins(): Plugin[] {\n const { editor } = this\n\n // With ProseMirror, first plugins within an array are executed first.\n // In Tiptap, we provide the ability to override plugins,\n // so it feels more natural to run plugins at the end of an array first.\n // That’s why we have to reverse the `extensions` array and sort again\n // based on the `priority` option.\n const extensions = ExtensionManager.sort([...this.extensions].reverse())\n\n const inputRules: InputRule[] = []\n const pasteRules: PasteRule[] = []\n\n const allPlugins = extensions\n .map(extension => {\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n editor,\n type: getSchemaTypeByName(extension.name, this.schema),\n }\n\n const plugins: Plugin[] = []\n\n const addKeyboardShortcuts = getExtensionField<AnyConfig['addKeyboardShortcuts']>(\n extension,\n 'addKeyboardShortcuts',\n context,\n )\n\n let defaultBindings: Record<string, () => boolean> = {}\n\n // bind exit handling\n if (extension.type === 'mark' && getExtensionField<AnyConfig['exitable']>(extension, 'exitable', context)) {\n defaultBindings.ArrowRight = () => Mark.handleExit({ editor, mark: extension as Mark })\n }\n\n if (addKeyboardShortcuts) {\n const bindings = Object.fromEntries(\n Object.entries(addKeyboardShortcuts()).map(([shortcut, method]) => {\n return [shortcut, () => method({ editor })]\n }),\n )\n\n defaultBindings = { ...defaultBindings, ...bindings }\n }\n\n const keyMapPlugin = keymap(defaultBindings)\n\n plugins.push(keyMapPlugin)\n\n const addInputRules = getExtensionField<AnyConfig['addInputRules']>(\n extension,\n 'addInputRules',\n context,\n )\n\n if (isExtensionRulesEnabled(extension, editor.options.enableInputRules) && addInputRules) {\n inputRules.push(...addInputRules())\n }\n\n const addPasteRules = getExtensionField<AnyConfig['addPasteRules']>(\n extension,\n 'addPasteRules',\n context,\n )\n\n if (isExtensionRulesEnabled(extension, editor.options.enablePasteRules) && addPasteRules) {\n pasteRules.push(...addPasteRules())\n }\n\n const addProseMirrorPlugins = getExtensionField<AnyConfig['addProseMirrorPlugins']>(\n extension,\n 'addProseMirrorPlugins',\n context,\n )\n\n if (addProseMirrorPlugins) {\n const proseMirrorPlugins = addProseMirrorPlugins()\n\n plugins.push(...proseMirrorPlugins)\n }\n\n return plugins\n })\n .flat()\n\n return [\n inputRulesPlugin({\n editor,\n rules: inputRules,\n }),\n ...pasteRulesPlugin({\n editor,\n rules: pasteRules,\n }),\n ...allPlugins,\n ]\n }\n\n /**\n * Get all attributes from the extensions.\n * @returns An array of attributes\n */\n get attributes() {\n return getAttributesFromExtensions(this.extensions)\n }\n\n /**\n * Get all node views from the extensions.\n * @returns An object with all node views where the key is the node name and the value is the node view function\n */\n get nodeViews(): Record<string, NodeViewConstructor> {\n const { editor } = this\n const { nodeExtensions } = splitExtensions(this.extensions)\n\n return Object.fromEntries(\n nodeExtensions\n .filter(extension => !!getExtensionField(extension, 'addNodeView'))\n .map(extension => {\n const extensionAttributes = this.attributes.filter(\n attribute => attribute.type === extension.name,\n )\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n editor,\n type: getNodeType(extension.name, this.schema),\n }\n const addNodeView = getExtensionField<NodeConfig['addNodeView']>(\n extension,\n 'addNodeView',\n context,\n )\n\n if (!addNodeView) {\n return []\n }\n\n const nodeview: NodeViewConstructor = (\n node,\n view,\n getPos,\n decorations,\n innerDecorations,\n ) => {\n const HTMLAttributes = getRenderedAttributes(node, extensionAttributes)\n\n return addNodeView()({\n // pass-through\n node,\n view,\n getPos: getPos as () => number,\n decorations,\n innerDecorations,\n // tiptap-specific\n editor,\n extension,\n HTMLAttributes,\n })\n }\n\n return [extension.name, nodeview]\n }),\n )\n }\n\n /**\n * Go through all extensions, create extension storages & setup marks\n * & bind editor event listener.\n */\n private setupExtensions() {\n this.extensions.forEach(extension => {\n // store extension storage in editor\n this.editor.extensionStorage[extension.name] = extension.storage\n\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n editor: this.editor,\n type: getSchemaTypeByName(extension.name, this.schema),\n }\n\n if (extension.type === 'mark') {\n const keepOnSplit = callOrReturn(getExtensionField(extension, 'keepOnSplit', context)) ?? true\n\n if (keepOnSplit) {\n this.splittableMarks.push(extension.name)\n }\n }\n\n const onBeforeCreate = getExtensionField<AnyConfig['onBeforeCreate']>(\n extension,\n 'onBeforeCreate',\n context,\n )\n const onCreate = getExtensionField<AnyConfig['onCreate']>(extension, 'onCreate', context)\n const onUpdate = getExtensionField<AnyConfig['onUpdate']>(extension, 'onUpdate', context)\n const onSelectionUpdate = getExtensionField<AnyConfig['onSelectionUpdate']>(\n extension,\n 'onSelectionUpdate',\n context,\n )\n const onTransaction = getExtensionField<AnyConfig['onTransaction']>(\n extension,\n 'onTransaction',\n context,\n )\n const onFocus = getExtensionField<AnyConfig['onFocus']>(extension, 'onFocus', context)\n const onBlur = getExtensionField<AnyConfig['onBlur']>(extension, 'onBlur', context)\n const onDestroy = getExtensionField<AnyConfig['onDestroy']>(extension, 'onDestroy', context)\n\n if (onBeforeCreate) {\n this.editor.on('beforeCreate', onBeforeCreate)\n }\n\n if (onCreate) {\n this.editor.on('create', onCreate)\n }\n\n if (onUpdate) {\n this.editor.on('update', onUpdate)\n }\n\n if (onSelectionUpdate) {\n this.editor.on('selectionUpdate', onSelectionUpdate)\n }\n\n if (onTransaction) {\n this.editor.on('transaction', onTransaction)\n }\n\n if (onFocus) {\n this.editor.on('focus', onFocus)\n }\n\n if (onBlur) {\n this.editor.on('blur', onBlur)\n }\n\n if (onDestroy) {\n this.editor.on('destroy', onDestroy)\n }\n })\n }\n}\n","import { Plugin, Transaction } from '@tiptap/pm/state'\n\nimport { Editor } from './Editor.js'\nimport { getExtensionField } from './helpers/getExtensionField.js'\nimport { ExtensionConfig } from './index.js'\nimport { InputRule } from './InputRule.js'\nimport { Mark } from './Mark.js'\nimport { Node } from './Node.js'\nimport { PasteRule } from './PasteRule.js'\nimport {\n AnyConfig,\n Extensions,\n GlobalAttributes,\n KeyboardShortcutCommand,\n ParentConfig,\n RawCommands,\n} from './types.js'\nimport { callOrReturn } from './utilities/callOrReturn.js'\nimport { mergeDeep } from './utilities/mergeDeep.js'\n\ndeclare module '@tiptap/core' {\n interface ExtensionConfig<Options = any, Storage = any> {\n // @ts-ignore - this is a dynamic key\n [key: string]: any\n\n /**\n * The extension name - this must be unique.\n * It will be used to identify the extension.\n *\n * @example 'myExtension'\n */\n name: string\n\n /**\n * The priority of your extension. The higher, the earlier it will be called\n * and will take precedence over other extensions with a lower priority.\n * @default 100\n * @example 101\n */\n priority?: number\n\n /**\n * The default options for this extension.\n * @example\n * defaultOptions: {\n * myOption: 'foo',\n * myOtherOption: 10,\n * }\n */\n defaultOptions?: Options\n\n /**\n * This method will add options to this extension\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#settings\n * @example\n * addOptions() {\n * return {\n * myOption: 'foo',\n * myOtherOption: 10,\n * }\n */\n addOptions?: (this: {\n name: string\n parent: Exclude<ParentConfig<ExtensionConfig<Options, Storage>>['addOptions'], undefined>\n }) => Options\n\n /**\n * The default storage this extension can save data to.\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#storage\n * @example\n * defaultStorage: {\n * prefetchedUsers: [],\n * loading: false,\n * }\n */\n addStorage?: (this: {\n name: string\n options: Options\n parent: Exclude<ParentConfig<ExtensionConfig<Options, Storage>>['addStorage'], undefined>\n }) => Storage\n\n /**\n * This function adds globalAttributes to specific nodes.\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#global-attributes\n * @example\n * addGlobalAttributes() {\n * return [\n * {\n // Extend the following extensions\n * types: [\n * 'heading',\n * 'paragraph',\n * ],\n * // … with those attributes\n * attributes: {\n * textAlign: {\n * default: 'left',\n * renderHTML: attributes => ({\n * style: `text-align: ${attributes.textAlign}`,\n * }),\n * parseHTML: element => element.style.textAlign || 'left',\n * },\n * },\n * },\n * ]\n * }\n */\n addGlobalAttributes?: (this: {\n name: string\n options: Options\n storage: Storage\n extensions: (Node | Mark)[]\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['addGlobalAttributes']\n }) => GlobalAttributes\n\n /**\n * This function adds commands to the editor\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#commands\n * @example\n * addCommands() {\n * return {\n * myCommand: () => ({ chain }) => chain().setMark('type', 'foo').run(),\n * }\n * }\n */\n addCommands?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['addCommands']\n }) => Partial<RawCommands>\n\n /**\n * This function registers keyboard shortcuts.\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#keyboard-shortcuts\n * @example\n * addKeyboardShortcuts() {\n * return {\n * 'Mod-l': () => this.editor.commands.toggleBulletList(),\n * }\n * },\n */\n addKeyboardShortcuts?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['addKeyboardShortcuts']\n }) => {\n [key: string]: KeyboardShortcutCommand\n }\n\n /**\n * This function adds input rules to the editor.\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#input-rules\n * @example\n * addInputRules() {\n * return [\n * markInputRule({\n * find: inputRegex,\n * type: this.type,\n * }),\n * ]\n * },\n */\n addInputRules?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['addInputRules']\n }) => InputRule[]\n\n /**\n * This function adds paste rules to the editor.\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#paste-rules\n * @example\n * addPasteRules() {\n * return [\n * markPasteRule({\n * find: pasteRegex,\n * type: this.type,\n * }),\n * ]\n * },\n */\n addPasteRules?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['addPasteRules']\n }) => PasteRule[]\n\n /**\n * This function adds Prosemirror plugins to the editor\n * @see https://tiptap.dev/docs/editor/guide/custom-extensions#prosemirror-plugins\n * @example\n * addProseMirrorPlugins() {\n * return [\n * customPlugin(),\n * ]\n * }\n */\n addProseMirrorPlugins?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['addProseMirrorPlugins']\n }) => Plugin[]\n\n /**\n * This function adds additional extensions to the editor. This is useful for\n * building extension kits.\n * @example\n * addExtensions() {\n * return [\n * BulletList,\n * OrderedList,\n * ListItem\n * ]\n * }\n */\n addExtensions?: (this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['addExtensions']\n }) => Extensions\n\n /**\n * This function extends the schema of the node.\n * @example\n * extendNodeSchema() {\n * return {\n * group: 'inline',\n * selectable: false,\n * }\n * }\n */\n extendNodeSchema?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['extendNodeSchema']\n },\n extension: Node,\n ) => Record<string, any>)\n | null\n\n /**\n * This function extends the schema of the mark.\n * @example\n * extendMarkSchema() {\n * return {\n * group: 'inline',\n * selectable: false,\n * }\n * }\n */\n extendMarkSchema?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['extendMarkSchema']\n },\n extension: Mark,\n ) => Record<string, any>)\n | null\n\n /**\n * The editor is not ready yet.\n */\n onBeforeCreate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onBeforeCreate']\n }) => void)\n | null\n\n /**\n * The editor is ready.\n */\n onCreate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onCreate']\n }) => void)\n | null\n\n /**\n * The content has changed.\n */\n onUpdate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onUpdate']\n }) => void)\n | null\n\n /**\n * The selection has changed.\n */\n onSelectionUpdate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onSelectionUpdate']\n }) => void)\n | null\n\n /**\n * The editor state has changed.\n */\n onTransaction?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onTransaction']\n },\n props: {\n editor: Editor\n transaction: Transaction\n },\n ) => void)\n | null\n\n /**\n * The editor is focused.\n */\n onFocus?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onFocus']\n },\n props: {\n event: FocusEvent\n },\n ) => void)\n | null\n\n /**\n * The editor isn’t focused anymore.\n */\n onBlur?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onBlur']\n },\n props: {\n event: FocusEvent\n },\n ) => void)\n | null\n\n /**\n * The editor is destroyed.\n */\n onDestroy?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n parent: ParentConfig<ExtensionConfig<Options, Storage>>['onDestroy']\n }) => void)\n | null\n }\n}\n\n/**\n * The Extension class is the base class for all extensions.\n * @see https://tiptap.dev/api/extensions#create-a-new-extension\n */\nexport class Extension<Options = any, Storage = any> {\n type = 'extension'\n\n name = 'extension'\n\n parent: Extension | null = null\n\n child: Extension | null = null\n\n options: Options\n\n storage: Storage\n\n config: ExtensionConfig = {\n name: this.name,\n defaultOptions: {},\n }\n\n constructor(config: Partial<ExtensionConfig<Options, Storage>> = {}) {\n this.config = {\n ...this.config,\n ...config,\n }\n\n this.name = this.config.name\n\n if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {\n console.warn(\n `[tiptap warn]: BREAKING CHANGE: \"defaultOptions\" is deprecated. Please use \"addOptions\" instead. Found in extension: \"${this.name}\".`,\n )\n }\n\n // TODO: remove `addOptions` fallback\n this.options = this.config.defaultOptions\n\n if (this.config.addOptions) {\n this.options = callOrReturn(\n getExtensionField<AnyConfig['addOptions']>(this, 'addOptions', {\n name: this.name,\n }),\n )\n }\n\n this.storage = callOrReturn(\n getExtensionField<AnyConfig['addStorage']>(this, 'addStorage', {\n name: this.name,\n options: this.options,\n }),\n ) || {}\n }\n\n static create<O = any, S = any>(config: Partial<ExtensionConfig<O, S>> = {}) {\n return new Extension<O, S>(config)\n }\n\n configure(options: Partial<Options> = {}) {\n // return a new instance so we can use the same extension\n // with different calls of `configure`\n const extension = this.extend<Options, Storage>({\n ...this.config,\n addOptions: () => {\n return mergeDeep(this.options as Record<string, any>, options) as Options\n },\n })\n\n // Always preserve the current name\n extension.name = this.name\n // Set the parent to be our parent\n extension.parent = this.parent\n\n return extension\n }\n\n extend<ExtendedOptions = Options, ExtendedStorage = Storage>(\n extendedConfig: Partial<ExtensionConfig<ExtendedOptions, ExtendedStorage>> = {},\n ) {\n const extension = new Extension<ExtendedOptions, ExtendedStorage>({ ...this.config, ...extendedConfig })\n\n extension.parent = this\n\n this.child = extension\n\n extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name\n\n if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {\n console.warn(\n `[tiptap warn]: BREAKING CHANGE: \"defaultOptions\" is deprecated. Please use \"addOptions\" instead. Found in extension: \"${extension.name}\".`,\n )\n }\n\n extension.options = callOrReturn(\n getExtensionField<AnyConfig['addOptions']>(extension, 'addOptions', {\n name: extension.name,\n }),\n )\n\n extension.storage = callOrReturn(\n getExtensionField<AnyConfig['addStorage']>(extension, 'addStorage', {\n name: extension.name,\n options: extension.options,\n }),\n )\n\n return extension\n }\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { Range, TextSerializer } from '../types.js'\n\n/**\n * Gets the text between two positions in a Prosemirror node\n * and serializes it using the given text serializers and block separator (see getText)\n * @param startNode The Prosemirror node to start from\n * @param range The range of the text to get\n * @param options Options for the text serializer & block separator\n * @returns The text between the two positions\n */\nexport function getTextBetween(\n startNode: ProseMirrorNode,\n range: Range,\n options?: {\n blockSeparator?: string\n textSerializers?: Record<string, TextSerializer>\n },\n): string {\n const { from, to } = range\n const { blockSeparator = '\\n\\n', textSerializers = {} } = options || {}\n let text = ''\n\n startNode.nodesBetween(from, to, (node, pos, parent, index) => {\n if (node.isBlock && pos > from) {\n text += blockSeparator\n }\n\n const textSerializer = textSerializers?.[node.type.name]\n\n if (textSerializer) {\n if (parent) {\n text += textSerializer({\n node,\n pos,\n parent,\n index,\n range,\n })\n }\n // do not descend into child nodes when there exists a serializer\n return false\n }\n\n if (node.isText) {\n text += node?.text?.slice(Math.max(from, pos) - pos, to - pos) // eslint-disable-line\n }\n })\n\n return text\n}\n","import { Schema } from '@tiptap/pm/model'\n\nimport { TextSerializer } from '../types.js'\n\n/**\n * Find text serializers `toText` in a Prosemirror schema\n * @param schema The Prosemirror schema to search in\n * @returns A record of text serializers by node name\n */\nexport function getTextSerializersFromSchema(schema: Schema): Record<string, TextSerializer> {\n return Object.fromEntries(\n Object.entries(schema.nodes)\n .filter(([, node]) => node.spec.toText)\n .map(([name, node]) => [name, node.spec.toText]),\n )\n}\n","import { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { Extension } from '../Extension.js'\nimport { getTextBetween } from '../helpers/getTextBetween.js'\nimport { getTextSerializersFromSchema } from '../helpers/getTextSerializersFromSchema.js'\n\nexport type ClipboardTextSerializerOptions = {\n blockSeparator?: string,\n}\n\nexport const ClipboardTextSerializer = Extension.create<ClipboardTextSerializerOptions>({\n name: 'clipboardTextSerializer',\n\n addOptions() {\n return {\n blockSeparator: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('clipboardTextSerializer'),\n props: {\n clipboardTextSerializer: () => {\n const { editor } = this\n const { state, schema } = editor\n const { doc, selection } = state\n const { ranges } = selection\n const from = Math.min(...ranges.map(range => range.$from.pos))\n const to = Math.max(...ranges.map(range => range.$to.pos))\n const textSerializers = getTextSerializersFromSchema(schema)\n const range = { from, to }\n\n return getTextBetween(doc, range, {\n ...(this.options.blockSeparator !== undefined\n ? { blockSeparator: this.options.blockSeparator }\n : {}),\n textSerializers,\n })\n },\n },\n }),\n ]\n },\n})\n","import { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n blur: {\n /**\n * Removes focus from the editor.\n * @example editor.commands.blur()\n */\n blur: () => ReturnType,\n }\n }\n}\n\nexport const blur: RawCommands['blur'] = () => ({ editor, view }) => {\n requestAnimationFrame(() => {\n if (!editor.isDestroyed) {\n (view.dom as HTMLElement).blur()\n\n // Browsers should remove the caret on blur but safari does not.\n // See: https://github.com/ueberdosis/tiptap/issues/2405\n window?.getSelection()?.removeAllRanges()\n }\n })\n\n return true\n}\n","import { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n clearContent: {\n /**\n * Clear the whole document.\n * @param emitUpdate Whether to emit an update event.\n * @example editor.commands.clearContent()\n */\n clearContent: (emitUpdate?: boolean) => ReturnType,\n }\n }\n}\n\nexport const clearContent: RawCommands['clearContent'] = (emitUpdate = false) => ({ commands }) => {\n return commands.setContent('', emitUpdate)\n}\n","import { liftTarget } from '@tiptap/pm/transform'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n clearNodes: {\n /**\n * Normalize nodes to a simple paragraph.\n * @example editor.commands.clearNodes()\n */\n clearNodes: () => ReturnType,\n }\n }\n}\n\nexport const clearNodes: RawCommands['clearNodes'] = () => ({ state, tr, dispatch }) => {\n const { selection } = tr\n const { ranges } = selection\n\n if (!dispatch) {\n return true\n }\n\n ranges.forEach(({ $from, $to }) => {\n state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {\n if (node.type.isText) {\n return\n }\n\n const { doc, mapping } = tr\n const $mappedFrom = doc.resolve(mapping.map(pos))\n const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize))\n const nodeRange = $mappedFrom.blockRange($mappedTo)\n\n if (!nodeRange) {\n return\n }\n\n const targetLiftDepth = liftTarget(nodeRange)\n\n if (node.type.isTextblock) {\n const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index())\n\n tr.setNodeMarkup(nodeRange.start, defaultType)\n }\n\n if (targetLiftDepth || targetLiftDepth === 0) {\n tr.lift(nodeRange, targetLiftDepth)\n }\n })\n })\n\n return true\n}\n","import { Command, RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n command: {\n /**\n * Define a command inline.\n * @param fn The command function.\n * @example\n * editor.commands.command(({ tr, state }) => {\n * ...\n * return true\n * })\n */\n command: (fn: (props: Parameters<Command>[0]) => boolean) => ReturnType,\n }\n }\n}\n\nexport const command: RawCommands['command'] = fn => props => {\n return fn(props)\n}\n","import { createParagraphNear as originalCreateParagraphNear } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n createParagraphNear: {\n /**\n * Create a paragraph nearby.\n * @example editor.commands.createParagraphNear()\n */\n createParagraphNear: () => ReturnType\n }\n }\n}\n\nexport const createParagraphNear: RawCommands['createParagraphNear'] = () => ({ state, dispatch }) => {\n return originalCreateParagraphNear(state, dispatch)\n}\n","import { TextSelection } from '@tiptap/pm/state'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n cut: {\n /**\n * Cuts content from a range and inserts it at a given position.\n * @param range The range to cut.\n * @param range.from The start position of the range.\n * @param range.to The end position of the range.\n * @param targetPos The position to insert the content at.\n * @example editor.commands.cut({ from: 1, to: 3 }, 5)\n */\n cut: ({ from, to }: { from: number, to: number }, targetPos: number) => ReturnType,\n }\n }\n}\n\nexport const cut: RawCommands['cut'] = (originRange, targetPos) => ({ editor, tr }) => {\n const { state } = editor\n\n const contentSlice = state.doc.slice(originRange.from, originRange.to)\n\n tr.deleteRange(originRange.from, originRange.to)\n const newPos = tr.mapping.map(targetPos)\n\n tr.insert(newPos, contentSlice.content)\n\n tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))))\n\n return true\n}\n","import { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n deleteCurrentNode: {\n /**\n * Delete the node that currently has the selection anchor.\n * @example editor.commands.deleteCurrentNode()\n */\n deleteCurrentNode: () => ReturnType,\n }\n }\n}\n\nexport const deleteCurrentNode: RawCommands['deleteCurrentNode'] = () => ({ tr, dispatch }) => {\n const { selection } = tr\n const currentNode = selection.$anchor.node()\n\n // if there is content inside the current node, break out of this command\n if (currentNode.content.size > 0) {\n return false\n }\n\n const $pos = tr.selection.$anchor\n\n for (let depth = $pos.depth; depth > 0; depth -= 1) {\n const node = $pos.node(depth)\n\n if (node.type === currentNode.type) {\n if (dispatch) {\n const from = $pos.before(depth)\n const to = $pos.after(depth)\n\n tr.delete(from, to).scrollIntoView()\n }\n\n return true\n }\n }\n\n return false\n}\n","import { NodeType } from '@tiptap/pm/model'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n deleteNode: {\n /**\n * Delete a node with a given type or name.\n * @param typeOrName The type or name of the node.\n * @example editor.commands.deleteNode('paragraph')\n */\n deleteNode: (typeOrName: string | NodeType) => ReturnType,\n }\n }\n}\n\nexport const deleteNode: RawCommands['deleteNode'] = typeOrName => ({ tr, state, dispatch }) => {\n const type = getNodeType(typeOrName, state.schema)\n const $pos = tr.selection.$anchor\n\n for (let depth = $pos.depth; depth > 0; depth -= 1) {\n const node = $pos.node(depth)\n\n if (node.type === type) {\n if (dispatch) {\n const from = $pos.before(depth)\n const to = $pos.after(depth)\n\n tr.delete(from, to).scrollIntoView()\n }\n\n return true\n }\n }\n\n return false\n}\n","import { Range, RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n deleteRange: {\n /**\n * Delete a given range.\n * @param range The range to delete.\n * @example editor.commands.deleteRange({ from: 1, to: 3 })\n */\n deleteRange: (range: Range) => ReturnType,\n }\n }\n}\n\nexport const deleteRange: RawCommands['deleteRange'] = range => ({ tr, dispatch }) => {\n const { from, to } = range\n\n if (dispatch) {\n tr.delete(from, to)\n }\n\n return true\n}\n","import { deleteSelection as originalDeleteSelection } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n deleteSelection: {\n /**\n * Delete the selection, if there is one.\n * @example editor.commands.deleteSelection()\n */\n deleteSelection: () => ReturnType\n }\n }\n}\n\nexport const deleteSelection: RawCommands['deleteSelection'] = () => ({ state, dispatch }) => {\n return originalDeleteSelection(state, dispatch)\n}\n","import { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n enter: {\n /**\n * Trigger enter.\n * @example editor.commands.enter()\n */\n enter: () => ReturnType,\n }\n }\n}\n\nexport const enter: RawCommands['enter'] = () => ({ commands }) => {\n return commands.keyboardShortcut('Enter')\n}\n","import { exitCode as originalExitCode } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n exitCode: {\n /**\n * Exit from a code block.\n * @example editor.commands.exitCode()\n */\n exitCode: () => ReturnType\n }\n }\n}\n\nexport const exitCode: RawCommands['exitCode'] = () => ({ state, dispatch }) => {\n return originalExitCode(state, dispatch)\n}\n","import { isRegExp } from './isRegExp.js'\n\n/**\n * Check if object1 includes object2\n * @param object1 Object\n * @param object2 Object\n */\nexport function objectIncludes(\n object1: Record<string, any>,\n object2: Record<string, any>,\n options: { strict: boolean } = { strict: true },\n): boolean {\n const keys = Object.keys(object2)\n\n if (!keys.length) {\n return true\n }\n\n return keys.every(key => {\n if (options.strict) {\n return object2[key] === object1[key]\n }\n\n if (isRegExp(object2[key])) {\n return object2[key].test(object1[key])\n }\n\n return object2[key] === object1[key]\n })\n}\n","import { Mark as ProseMirrorMark, MarkType, ResolvedPos } from '@tiptap/pm/model'\n\nimport { Range } from '../types.js'\nimport { objectIncludes } from '../utilities/objectIncludes.js'\n\nfunction findMarkInSet(\n marks: ProseMirrorMark[],\n type: MarkType,\n attributes: Record<string, any> = {},\n): ProseMirrorMark | undefined {\n return marks.find(item => {\n return (\n item.type === type\n && objectIncludes(\n // Only check equality for the attributes that are provided\n Object.fromEntries(Object.keys(attributes).map(k => [k, item.attrs[k]])),\n attributes,\n )\n )\n })\n}\n\nfunction isMarkInSet(\n marks: ProseMirrorMark[],\n type: MarkType,\n attributes: Record<string, any> = {},\n): boolean {\n return !!findMarkInSet(marks, type, attributes)\n}\n\n/**\n * Get the range of a mark at a resolved position.\n */\nexport function getMarkRange(\n /**\n * The position to get the mark range for.\n */\n $pos: ResolvedPos,\n /**\n * The mark type to get the range for.\n */\n type: MarkType,\n /**\n * The attributes to match against.\n * If not provided, only the first mark at the position will be matched.\n */\n attributes?: Record<string, any>,\n): Range | void {\n if (!$pos || !type) {\n return\n }\n let start = $pos.parent.childAfter($pos.parentOffset)\n\n // If the cursor is at the start of a text node that does not have the mark, look backward\n if (!start.node || !start.node.marks.some(mark => mark.type === type)) {\n start = $pos.parent.childBefore($pos.parentOffset)\n }\n\n // If there is no text node with the mark even backward, return undefined\n if (!start.node || !start.node.marks.some(mark => mark.type === type)) {\n return\n }\n\n // Default to only matching against the first mark's attributes\n attributes = attributes || start.node.marks[0]?.attrs\n\n // We now know that the cursor is either at the start, middle or end of a text node with the specified mark\n // so we can look it up on the targeted mark\n const mark = findMarkInSet([...start.node.marks], type, attributes)\n\n if (!mark) {\n return\n }\n\n let startIndex = start.index\n let startPos = $pos.start() + start.offset\n let endIndex = startIndex + 1\n let endPos = startPos + start.node.nodeSize\n\n while (\n startIndex > 0\n && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)\n ) {\n startIndex -= 1\n startPos -= $pos.parent.child(startIndex).nodeSize\n }\n\n while (\n endIndex < $pos.parent.childCount\n && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)\n ) {\n endPos += $pos.parent.child(endIndex).nodeSize\n endIndex += 1\n }\n\n return {\n from: startPos,\n to: endPos,\n }\n}\n","import { MarkType, Schema } from '@tiptap/pm/model'\n\nexport function getMarkType(nameOrType: string | MarkType, schema: Schema): MarkType {\n if (typeof nameOrType === 'string') {\n if (!schema.marks[nameOrType]) {\n throw Error(\n `There is no mark type named '${nameOrType}'. Maybe you forgot to add the extension?`,\n )\n }\n\n return schema.marks[nameOrType]\n }\n\n return nameOrType\n}\n","import { MarkType } from '@tiptap/pm/model'\nimport { TextSelection } from '@tiptap/pm/state'\n\nimport { getMarkRange } from '../helpers/getMarkRange.js'\nimport { getMarkType } from '../helpers/getMarkType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n extendMarkRange: {\n /**\n * Extends the text selection to the current mark by type or name.\n * @param typeOrName The type or name of the mark.\n * @param attributes The attributes of the mark.\n * @example editor.commands.extendMarkRange('bold')\n * @example editor.commands.extendMarkRange('mention', { userId: \"1\" })\n */\n extendMarkRange: (\n /**\n * The type or name of the mark.\n */\n typeOrName: string | MarkType,\n\n /**\n * The attributes of the mark.\n */\n attributes?: Record<string, any>,\n ) => ReturnType\n }\n }\n}\n\nexport const extendMarkRange: RawCommands['extendMarkRange'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {\n const type = getMarkType(typeOrName, state.schema)\n const { doc, selection } = tr\n const { $from, from, to } = selection\n\n if (dispatch) {\n const range = getMarkRange($from, type, attributes)\n\n if (range && range.from <= from && range.to >= to) {\n const newSelection = TextSelection.create(doc, range.from, range.to)\n\n tr.setSelection(newSelection)\n }\n }\n\n return true\n}\n","import { Command, CommandProps, RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n first: {\n /**\n * Runs one command after the other and stops at the first which returns true.\n * @param commands The commands to run.\n * @example editor.commands.first([command1, command2])\n */\n first: (commands: Command[] | ((props: CommandProps) => Command[])) => ReturnType,\n }\n }\n}\n\nexport const first: RawCommands['first'] = commands => props => {\n const items = typeof commands === 'function'\n ? commands(props)\n : commands\n\n for (let i = 0; i < items.length; i += 1) {\n if (items[i](props)) {\n return true\n }\n }\n\n return false\n}\n","import { TextSelection } from '@tiptap/pm/state'\n\nexport function isTextSelection(value: unknown): value is TextSelection {\n return value instanceof TextSelection\n}\n","export function minMax(value = 0, min = 0, max = 0): number {\n return Math.min(Math.max(value, min), max)\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Selection, TextSelection } from '@tiptap/pm/state'\n\nimport { FocusPosition } from '../types.js'\nimport { minMax } from '../utilities/minMax.js'\n\nexport function resolveFocusPosition(\n doc: ProseMirrorNode,\n position: FocusPosition = null,\n): Selection | null {\n if (!position) {\n return null\n }\n\n const selectionAtStart = Selection.atStart(doc)\n const selectionAtEnd = Selection.atEnd(doc)\n\n if (position === 'start' || position === true) {\n return selectionAtStart\n }\n\n if (position === 'end') {\n return selectionAtEnd\n }\n\n const minPos = selectionAtStart.from\n const maxPos = selectionAtEnd.to\n\n if (position === 'all') {\n return TextSelection.create(\n doc,\n minMax(0, minPos, maxPos),\n minMax(doc.content.size, minPos, maxPos),\n )\n }\n\n return TextSelection.create(\n doc,\n minMax(position, minPos, maxPos),\n minMax(position, minPos, maxPos),\n )\n}\n","export function isAndroid(): boolean {\n return navigator.platform === 'Android' || /android/i.test(navigator.userAgent)\n}\n","export function isiOS(): boolean {\n return [\n 'iPad Simulator',\n 'iPhone Simulator',\n 'iPod Simulator',\n 'iPad',\n 'iPhone',\n 'iPod',\n ].includes(navigator.platform)\n // iPad on iOS 13 detection\n || (navigator.userAgent.includes('Mac') && 'ontouchend' in document)\n}\n","/**\n * Detects if the current browser is Safari (but not iOS Safari or Chrome).\n * @returns `true` if the browser is Safari, `false` otherwise.\n * @example\n * if (isSafari()) {\n * // Safari-specific handling\n * }\n */\nexport function isSafari(): boolean {\n return typeof navigator !== 'undefined' ? /^((?!chrome|android).)*safari/i.test(navigator.userAgent) : false\n}\n","import { isTextSelection } from '../helpers/isTextSelection.js'\nimport { resolveFocusPosition } from '../helpers/resolveFocusPosition.js'\nimport { FocusPosition, RawCommands } from '../types.js'\nimport { isAndroid } from '../utilities/isAndroid.js'\nimport { isiOS } from '../utilities/isiOS.js'\nimport { isSafari } from '../utilities/isSafari.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n focus: {\n /**\n * Focus the editor at the given position.\n * @param position The position to focus at.\n * @param options.scrollIntoView Scroll the focused position into view after focusing\n * @example editor.commands.focus()\n * @example editor.commands.focus(32, { scrollIntoView: false })\n */\n focus: (\n /**\n * The position to focus at.\n */\n position?: FocusPosition,\n\n /**\n * Optional options\n * @default { scrollIntoView: true }\n */\n options?: {\n scrollIntoView?: boolean,\n },\n ) => ReturnType,\n }\n }\n}\n\nexport const focus: RawCommands['focus'] = (position = null, options = {}) => ({\n editor,\n view,\n tr,\n dispatch,\n}) => {\n options = {\n scrollIntoView: true,\n ...options,\n }\n\n const delayedFocus = () => {\n // focus within `requestAnimationFrame` breaks focus on iOS and Android\n // so we have to call this\n if (isiOS() || isAndroid()) {\n (view.dom as HTMLElement).focus()\n }\n\n // For React we have to focus asynchronously. Otherwise wild things happen.\n // see: https://github.com/ueberdosis/tiptap/issues/1520\n requestAnimationFrame(() => {\n if (!editor.isDestroyed) {\n view.focus()\n\n // Safari requires preventScroll to avoid the browser scrolling to the\n // top of the editor when focus is called before the selection is set.\n // We exclude iOS and Android since they are already handled above.\n // see: https://github.com/ueberdosis/tiptap/issues/7318\n if (isSafari() && !isiOS() && !isAndroid()) {\n (view.dom as HTMLElement).focus({ preventScroll: true })\n }\n }\n })\n }\n\n if ((view.hasFocus() && position === null) || position === false) {\n return true\n }\n\n // we don’t try to resolve a NodeSelection or CellSelection\n if (dispatch && position === null && !isTextSelection(editor.state.selection)) {\n delayedFocus()\n return true\n }\n\n // pass through tr.doc instead of editor.state.doc\n // since transactions could change the editors state before this command has been run\n const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection\n const isSameSelection = editor.state.selection.eq(selection)\n\n if (dispatch) {\n if (!isSameSelection) {\n tr.setSelection(selection)\n }\n\n // `tr.setSelection` resets the stored marks\n // so we’ll restore them if the selection is the same as before\n if (isSameSelection && tr.storedMarks) {\n tr.setStoredMarks(tr.storedMarks)\n }\n\n delayedFocus()\n }\n\n return true\n}\n","import { CommandProps, RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n forEach: {\n /**\n * Loop through an array of items.\n */\n forEach: <T>(\n items: T[],\n fn: (\n item: T,\n props: CommandProps & {\n index: number,\n },\n ) => boolean,\n ) => ReturnType,\n }\n }\n}\n\nexport const forEach: RawCommands['forEach'] = (items, fn) => props => {\n return items.every((item, index) => fn(item, { ...props, index }))\n}\n","import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model'\n\nimport { Content, RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n insertContent: {\n /**\n * Insert a node or string of HTML at the current position.\n * @example editor.commands.insertContent('<h1>Example</h1>')\n * @example editor.commands.insertContent('<h1>Example</h1>', { updateSelection: false })\n */\n insertContent: (\n /**\n * The ProseMirror content to insert.\n */\n value: Content | ProseMirrorNode | Fragment,\n\n /**\n * Optional options\n */\n options?: {\n /**\n * Options for parsing the content.\n */\n parseOptions?: ParseOptions;\n\n /**\n * Whether to update the selection after inserting the content.\n */\n updateSelection?: boolean;\n applyInputRules?: boolean;\n applyPasteRules?: boolean;\n }\n ) => ReturnType;\n };\n }\n}\n\nexport const insertContent: RawCommands['insertContent'] = (value, options) => ({ tr, commands }) => {\n return commands.insertContentAt(\n { from: tr.selection.from, to: tr.selection.to },\n value,\n options,\n )\n}\n","const removeWhitespaces = (node: HTMLElement) => {\n const children = node.childNodes\n\n for (let i = children.length - 1; i >= 0; i -= 1) {\n const child = children[i]\n\n if (child.nodeType === 3 && child.nodeValue && /^(\\n\\s\\s|\\n)$/.test(child.nodeValue)) {\n node.removeChild(child)\n } else if (child.nodeType === 1) {\n removeWhitespaces(child as HTMLElement)\n }\n }\n\n return node\n}\n\nexport function elementFromString(value: string): HTMLElement {\n // add a wrapper to preserve leading and trailing whitespace\n const wrappedValue = `<body>${value}</body>`\n\n const html = new window.DOMParser().parseFromString(wrappedValue, 'text/html').body\n\n return removeWhitespaces(html)\n}\n","import {\n DOMParser,\n Fragment,\n Node as ProseMirrorNode,\n ParseOptions,\n Schema,\n} from '@tiptap/pm/model'\n\nimport { Content } from '../types.js'\nimport { elementFromString } from '../utilities/elementFromString.js'\n\nexport type CreateNodeFromContentOptions = {\n slice?: boolean\n parseOptions?: ParseOptions\n errorOnInvalidContent?: boolean\n}\n\n/**\n * Takes a JSON or HTML content and creates a Prosemirror node or fragment from it.\n * @param content The JSON or HTML content to create the node from\n * @param schema The Prosemirror schema to use for the node\n * @param options Options for the parser\n * @returns The created Prosemirror node or fragment\n */\nexport function createNodeFromContent(\n content: Content | ProseMirrorNode | Fragment,\n schema: Schema,\n options?: CreateNodeFromContentOptions,\n): ProseMirrorNode | Fragment {\n if (content instanceof ProseMirrorNode || content instanceof Fragment) {\n return content\n }\n options = {\n slice: true,\n parseOptions: {},\n ...options,\n }\n\n const isJSONContent = typeof content === 'object' && content !== null\n const isTextContent = typeof content === 'string'\n\n if (isJSONContent) {\n try {\n const isArrayContent = Array.isArray(content) && content.length > 0\n\n // if the JSON Content is an array of nodes, create a fragment for each node\n if (isArrayContent) {\n return Fragment.fromArray(content.map(item => schema.nodeFromJSON(item)))\n }\n\n const node = schema.nodeFromJSON(content)\n\n if (options.errorOnInvalidContent) {\n node.check()\n }\n\n return node\n } catch (error) {\n if (options.errorOnInvalidContent) {\n throw new Error('[tiptap error]: Invalid JSON content', { cause: error as Error })\n }\n\n console.warn('[tiptap warn]: Invalid content.', 'Passed value:', content, 'Error:', error)\n\n return createNodeFromContent('', schema, options)\n }\n }\n\n if (isTextContent) {\n\n // Check for invalid content\n if (options.errorOnInvalidContent) {\n let hasInvalidContent = false\n let invalidContent = ''\n\n // A copy of the current schema with a catch-all node at the end\n const contentCheckSchema = new Schema({\n topNode: schema.spec.topNode,\n marks: schema.spec.marks,\n // Prosemirror's schemas are executed such that: the last to execute, matches last\n // This means that we can add a catch-all node at the end of the schema to catch any content that we don't know how to handle\n nodes: schema.spec.nodes.append({\n __tiptap__private__unknown__catch__all__node: {\n content: 'inline*',\n group: 'block',\n parseDOM: [\n {\n tag: '*',\n getAttrs: e => {\n // If this is ever called, we know that the content has something that we don't know how to handle in the schema\n hasInvalidContent = true\n // Try to stringify the element for a more helpful error message\n invalidContent = typeof e === 'string' ? e : e.outerHTML\n return null\n },\n },\n ],\n },\n }),\n })\n\n if (options.slice) {\n DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions)\n } else {\n DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions)\n }\n\n if (options.errorOnInvalidContent && hasInvalidContent) {\n throw new Error('[tiptap error]: Invalid HTML content', { cause: new Error(`Invalid element found: ${invalidContent}`) })\n }\n }\n\n const parser = DOMParser.fromSchema(schema)\n\n if (options.slice) {\n return parser.parseSlice(elementFromString(content), options.parseOptions).content\n }\n\n return parser.parse(elementFromString(content), options.parseOptions)\n\n }\n\n return createNodeFromContent('', schema, options)\n}\n","import { Selection, Transaction } from '@tiptap/pm/state'\nimport { ReplaceAroundStep, ReplaceStep } from '@tiptap/pm/transform'\n\n// source: https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.js#L466\nexport function selectionToInsertionEnd(tr: Transaction, startLen: number, bias: number) {\n const last = tr.steps.length - 1\n\n if (last < startLen) {\n return\n }\n\n const step = tr.steps[last]\n\n if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep)) {\n return\n }\n\n const map = tr.mapping.maps[last]\n let end = 0\n\n map.forEach((_from, _to, _newFrom, newTo) => {\n if (end === 0) {\n end = newTo\n }\n })\n\n tr.setSelection(Selection.near(tr.doc.resolve(end), bias))\n}\n","import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model'\n\nimport { createNodeFromContent } from '../helpers/createNodeFromContent.js'\nimport { selectionToInsertionEnd } from '../helpers/selectionToInsertionEnd.js'\nimport { Content, Range, RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n insertContentAt: {\n /**\n * Insert a node or string of HTML at a specific position.\n * @example editor.commands.insertContentAt(0, '<h1>Example</h1>')\n */\n insertContentAt: (\n /**\n * The position to insert the content at.\n */\n position: number | Range,\n\n /**\n * The ProseMirror content to insert.\n */\n value: Content | ProseMirrorNode | Fragment,\n\n /**\n * Optional options\n */\n options?: {\n /**\n * Options for parsing the content.\n */\n parseOptions?: ParseOptions\n\n /**\n * Whether to update the selection after inserting the content.\n */\n updateSelection?: boolean\n\n /**\n * Whether to apply input rules after inserting the content.\n */\n applyInputRules?: boolean\n\n /**\n * Whether to apply paste rules after inserting the content.\n */\n applyPasteRules?: boolean\n\n /**\n * Whether to throw an error if the content is invalid.\n */\n errorOnInvalidContent?: boolean\n },\n ) => ReturnType\n }\n }\n}\n\nconst isFragment = (nodeOrFragment: ProseMirrorNode | Fragment): nodeOrFragment is Fragment => {\n return !('type' in nodeOrFragment)\n}\n\nexport const insertContentAt: RawCommands['insertContentAt'] = (position, value, options) => ({ tr, dispatch, editor }) => {\n if (dispatch) {\n options = {\n parseOptions: editor.options.parseOptions,\n updateSelection: true,\n applyInputRules: false,\n applyPasteRules: false,\n ...options,\n }\n\n let content: Fragment | ProseMirrorNode\n\n const emitContentError = (error: Error) => {\n editor.emit('contentError', {\n editor,\n error,\n disableCollaboration: () => {\n if (editor.storage.collaboration) {\n editor.storage.collaboration.isDisabled = true\n }\n },\n })\n }\n\n const parseOptions: ParseOptions = {\n preserveWhitespace: 'full',\n ...options.parseOptions,\n }\n\n // If `emitContentError` is enabled, we want to check the content for errors\n // but ignore them (do not remove the invalid content from the document)\n if (!options.errorOnInvalidContent && !editor.options.enableContentCheck && editor.options.emitContentError) {\n try {\n createNodeFromContent(value, editor.schema, {\n parseOptions,\n errorOnInvalidContent: true,\n })\n } catch (e) {\n emitContentError(e as Error)\n }\n }\n\n try {\n content = createNodeFromContent(value, editor.schema, {\n parseOptions,\n errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,\n })\n } catch (e) {\n emitContentError(e as Error)\n return false\n }\n\n let { from, to } = typeof position === 'number' ? { from: position, to: position } : { from: position.from, to: position.to }\n\n let isOnlyTextContent = true\n let isOnlyBlockContent = true\n const nodes = isFragment(content) ? content : [content]\n\n nodes.forEach(node => {\n // check if added node is valid\n node.check()\n\n isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false\n\n isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false\n })\n\n // check if we can replace the wrapping node by\n // the newly inserted content\n // example:\n // replace an empty paragraph by an inserted image\n // instead of inserting the image below the paragraph\n if (from === to && isOnlyBlockContent) {\n const { parent } = tr.doc.resolve(from)\n const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount\n\n if (isEmptyTextBlock) {\n from -= 1\n to += 1\n }\n }\n\n let newContent\n\n // if there is only plain text we have to use `insertText`\n // because this will keep the current marks\n if (isOnlyTextContent) {\n // if value is string, we can use it directly\n // otherwise if it is an array, we have to join it\n if (Array.isArray(value)) {\n newContent = value.map(v => v.text || '').join('')\n } else if (value instanceof Fragment) {\n let text = ''\n\n value.forEach(node => {\n if (node.text) {\n text += node.text\n }\n })\n\n newContent = text\n } else if (typeof value === 'object' && !!value && !!value.text) {\n newContent = value.text\n } else {\n newContent = value as string\n }\n\n tr.insertText(newContent, from, to)\n } else {\n newContent = content\n\n tr.replaceWith(from, to, newContent)\n }\n\n // set cursor at end of inserted content\n if (options.updateSelection) {\n selectionToInsertionEnd(tr, tr.steps.length - 1, -1)\n }\n\n if (options.applyInputRules) {\n tr.setMeta('applyInputRules', { from, text: newContent })\n }\n\n if (options.applyPasteRules) {\n tr.setMeta('applyPasteRules', { from, text: newContent })\n }\n }\n\n return true\n}\n","import {\n joinBackward as originalJoinBackward,\n joinDown as originalJoinDown,\n joinForward as originalJoinForward,\n joinUp as originalJoinUp,\n} from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n joinUp: {\n /**\n * Join the selected block or, if there is a text selection, the closest ancestor block of the selection that can be joined, with the sibling above it.\n * @example editor.commands.joinUp()\n */\n joinUp: () => ReturnType\n }\n joinDown: {\n /**\n * Join the selected block, or the closest ancestor of the selection that can be joined, with the sibling after it.\n * @example editor.commands.joinDown()\n */\n joinDown: () => ReturnType\n }\n joinBackward: {\n /**\n * If the selection is empty and at the start of a textblock, try to reduce the distance between that block and the one before it—if there's a block directly before it that can be joined, join them.\n * If not, try to move the selected block closer to the next one in the document structure by lifting it out of its\n * parent or moving it into a parent of the previous block. Will use the view for accurate (bidi-aware) start-of-textblock detection if given.\n * @example editor.commands.joinBackward()\n */\n joinBackward: () => ReturnType\n }\n joinForward: {\n /**\n * If the selection is empty and the cursor is at the end of a textblock, try to reduce or remove the boundary between that block and the one after it,\n * either by joining them or by moving the other block closer to this one in the tree structure.\n * Will use the view for accurate start-of-textblock detection if given.\n * @example editor.commands.joinForward()\n */\n joinForward: () => ReturnType\n }\n }\n}\n\nexport const joinUp: RawCommands['joinUp'] = () => ({ state, dispatch }) => {\n return originalJoinUp(state, dispatch)\n}\n\nexport const joinDown: RawCommands['joinDown'] = () => ({ state, dispatch }) => {\n return originalJoinDown(state, dispatch)\n}\n\nexport const joinBackward: RawCommands['joinBackward'] = () => ({ state, dispatch }) => {\n return originalJoinBackward(state, dispatch)\n}\n\nexport const joinForward: RawCommands['joinForward'] = () => ({ state, dispatch }) => {\n return originalJoinForward(state, dispatch)\n}\n","import { joinPoint } from '@tiptap/pm/transform'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n joinItemBackward: {\n /**\n * Join two items backward.\n * @example editor.commands.joinItemBackward()\n */\n joinItemBackward: () => ReturnType\n }\n }\n}\n\nexport const joinItemBackward: RawCommands['joinItemBackward'] = () => ({\n state,\n dispatch,\n tr,\n}) => {\n try {\n const point = joinPoint(state.doc, state.selection.$from.pos, -1)\n\n if (point === null || point === undefined) {\n return false\n }\n\n tr.join(point, 2)\n\n if (dispatch) {\n dispatch(tr)\n }\n\n return true\n } catch {\n return false\n }\n}\n","import { joinPoint } from '@tiptap/pm/transform'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n joinItemForward: {\n /**\n * Join two items Forwards.\n * @example editor.commands.joinItemForward()\n */\n joinItemForward: () => ReturnType\n }\n }\n}\n\nexport const joinItemForward: RawCommands['joinItemForward'] = () => ({\n state,\n dispatch,\n tr,\n}) => {\n try {\n const point = joinPoint(state.doc, state.selection.$from.pos, +1)\n\n if (point === null || point === undefined) {\n return false\n }\n\n tr.join(point, 2)\n\n if (dispatch) {\n dispatch(tr)\n }\n\n return true\n } catch {\n return false\n }\n}\n","import { joinTextblockBackward as originalCommand } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n joinTextblockBackward: {\n /**\n * A more limited form of joinBackward that only tries to join the current textblock to the one before it, if the cursor is at the start of a textblock.\n */\n joinTextblockBackward: () => ReturnType\n }\n }\n}\n\nexport const joinTextblockBackward: RawCommands['joinTextblockBackward'] = () => ({ state, dispatch }) => {\n return originalCommand(state, dispatch)\n}\n","import { joinTextblockForward as originalCommand } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n joinTextblockForward: {\n /**\n * A more limited form of joinForward that only tries to join the current textblock to the one after it, if the cursor is at the end of a textblock.\n */\n joinTextblockForward: () => ReturnType\n }\n }\n}\n\nexport const joinTextblockForward: RawCommands['joinTextblockForward'] = () => ({ state, dispatch }) => {\n return originalCommand(state, dispatch)\n}\n","export function isMacOS(): boolean {\n return typeof navigator !== 'undefined'\n ? /Mac/.test(navigator.platform)\n : false\n}\n","import { RawCommands } from '../types.js'\nimport { isiOS } from '../utilities/isiOS.js'\nimport { isMacOS } from '../utilities/isMacOS.js'\n\nfunction normalizeKeyName(name: string) {\n const parts = name.split(/-(?!$)/)\n let result = parts[parts.length - 1]\n\n if (result === 'Space') {\n result = ' '\n }\n\n let alt\n let ctrl\n let shift\n let meta\n\n for (let i = 0; i < parts.length - 1; i += 1) {\n const mod = parts[i]\n\n if (/^(cmd|meta|m)$/i.test(mod)) {\n meta = true\n } else if (/^a(lt)?$/i.test(mod)) {\n alt = true\n } else if (/^(c|ctrl|control)$/i.test(mod)) {\n ctrl = true\n } else if (/^s(hift)?$/i.test(mod)) {\n shift = true\n } else if (/^mod$/i.test(mod)) {\n if (isiOS() || isMacOS()) {\n meta = true\n } else {\n ctrl = true\n }\n } else {\n throw new Error(`Unrecognized modifier name: ${mod}`)\n }\n }\n\n if (alt) {\n result = `Alt-${result}`\n }\n\n if (ctrl) {\n result = `Ctrl-${result}`\n }\n\n if (meta) {\n result = `Meta-${result}`\n }\n\n if (shift) {\n result = `Shift-${result}`\n }\n\n return result\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n keyboardShortcut: {\n /**\n * Trigger a keyboard shortcut.\n * @param name The name of the keyboard shortcut.\n * @example editor.commands.keyboardShortcut('Mod-b')\n */\n keyboardShortcut: (name: string) => ReturnType,\n }\n }\n}\n\nexport const keyboardShortcut: RawCommands['keyboardShortcut'] = name => ({\n editor,\n view,\n tr,\n dispatch,\n}) => {\n const keys = normalizeKeyName(name).split(/-(?!$)/)\n const key = keys.find(item => !['Alt', 'Ctrl', 'Meta', 'Shift'].includes(item))\n const event = new KeyboardEvent('keydown', {\n key: key === 'Space'\n ? ' '\n : key,\n altKey: keys.includes('Alt'),\n ctrlKey: keys.includes('Ctrl'),\n metaKey: keys.includes('Meta'),\n shiftKey: keys.includes('Shift'),\n bubbles: true,\n cancelable: true,\n })\n\n const capturedTransaction = editor.captureTransaction(() => {\n view.someProp('handleKeyDown', f => f(view, event))\n })\n\n capturedTransaction?.steps.forEach(step => {\n const newStep = step.map(tr.mapping)\n\n if (newStep && dispatch) {\n tr.maybeStep(newStep)\n }\n })\n\n return true\n}\n","import { NodeType } from '@tiptap/pm/model'\nimport { EditorState } from '@tiptap/pm/state'\n\nimport { NodeRange } from '../types.js'\nimport { objectIncludes } from '../utilities/objectIncludes.js'\nimport { getNodeType } from './getNodeType.js'\n\nexport function isNodeActive(\n state: EditorState,\n typeOrName: NodeType | string | null,\n attributes: Record<string, any> = {},\n): boolean {\n const { from, to, empty } = state.selection\n const type = typeOrName ? getNodeType(typeOrName, state.schema) : null\n\n const nodeRanges: NodeRange[] = []\n\n state.doc.nodesBetween(from, to, (node, pos) => {\n if (node.isText) {\n return\n }\n\n const relativeFrom = Math.max(from, pos)\n const relativeTo = Math.min(to, pos + node.nodeSize)\n\n nodeRanges.push({\n node,\n from: relativeFrom,\n to: relativeTo,\n })\n })\n\n const selectionRange = to - from\n const matchedNodeRanges = nodeRanges\n .filter(nodeRange => {\n if (!type) {\n return true\n }\n\n return type.name === nodeRange.node.type.name\n })\n .filter(nodeRange => objectIncludes(nodeRange.node.attrs, attributes, { strict: false }))\n\n if (empty) {\n return !!matchedNodeRanges.length\n }\n\n const range = matchedNodeRanges.reduce((sum, nodeRange) => sum + nodeRange.to - nodeRange.from, 0)\n\n return range >= selectionRange\n}\n","import { lift as originalLift } from '@tiptap/pm/commands'\nimport { NodeType } from '@tiptap/pm/model'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { isNodeActive } from '../helpers/isNodeActive.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n lift: {\n /**\n * Removes an existing wrap if possible lifting the node out of it\n * @param typeOrName The type or name of the node.\n * @param attributes The attributes of the node.\n * @example editor.commands.lift('paragraph')\n * @example editor.commands.lift('heading', { level: 1 })\n */\n lift: (typeOrName: string | NodeType, attributes?: Record<string, any>) => ReturnType\n }\n }\n}\n\nexport const lift: RawCommands['lift'] = (typeOrName, attributes = {}) => ({ state, dispatch }) => {\n const type = getNodeType(typeOrName, state.schema)\n const isActive = isNodeActive(state, type, attributes)\n\n if (!isActive) {\n return false\n }\n\n return originalLift(state, dispatch)\n}\n","import { liftEmptyBlock as originalLiftEmptyBlock } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n liftEmptyBlock: {\n /**\n * If the cursor is in an empty textblock that can be lifted, lift the block.\n * @example editor.commands.liftEmptyBlock()\n */\n liftEmptyBlock: () => ReturnType,\n }\n }\n}\n\nexport const liftEmptyBlock: RawCommands['liftEmptyBlock'] = () => ({ state, dispatch }) => {\n return originalLiftEmptyBlock(state, dispatch)\n}\n","import { NodeType } from '@tiptap/pm/model'\nimport { liftListItem as originalLiftListItem } from '@tiptap/pm/schema-list'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n liftListItem: {\n /**\n * Create a command to lift the list item around the selection up into a wrapping list.\n * @param typeOrName The type or name of the node.\n * @example editor.commands.liftListItem('listItem')\n */\n liftListItem: (typeOrName: string | NodeType) => ReturnType\n }\n }\n}\n\nexport const liftListItem: RawCommands['liftListItem'] = typeOrName => ({ state, dispatch }) => {\n const type = getNodeType(typeOrName, state.schema)\n\n return originalLiftListItem(type)(state, dispatch)\n}\n","import { newlineInCode as originalNewlineInCode } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n newlineInCode: {\n /**\n * Add a newline character in code.\n * @example editor.commands.newlineInCode()\n */\n newlineInCode: () => ReturnType\n }\n }\n}\n\nexport const newlineInCode: RawCommands['newlineInCode'] = () => ({ state, dispatch }) => {\n return originalNewlineInCode(state, dispatch)\n}\n","import { Schema } from '@tiptap/pm/model'\n\n/**\n * Get the type of a schema item by its name.\n * @param name The name of the schema item\n * @param schema The Prosemiror schema to search in\n * @returns The type of the schema item (`node` or `mark`), or null if it doesn't exist\n */\nexport function getSchemaTypeNameByName(name: string, schema: Schema): 'node' | 'mark' | null {\n if (schema.nodes[name]) {\n return 'node'\n }\n\n if (schema.marks[name]) {\n return 'mark'\n }\n\n return null\n}\n","/**\n * Remove a property or an array of properties from an object\n * @param obj Object\n * @param key Key to remove\n */\nexport function deleteProps(obj: Record<string, any>, propOrProps: string | string[]): Record<string, any> {\n const props = typeof propOrProps === 'string'\n ? [propOrProps]\n : propOrProps\n\n return Object\n .keys(obj)\n .reduce((newObj: Record<string, any>, prop) => {\n if (!props.includes(prop)) {\n newObj[prop] = obj[prop]\n }\n\n return newObj\n }, {})\n}\n","import { MarkType, NodeType } from '@tiptap/pm/model'\n\nimport { getMarkType } from '../helpers/getMarkType.js'\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { getSchemaTypeNameByName } from '../helpers/getSchemaTypeNameByName.js'\nimport { RawCommands } from '../types.js'\nimport { deleteProps } from '../utilities/deleteProps.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n resetAttributes: {\n /**\n * Resets some node attributes to the default value.\n * @param typeOrName The type or name of the node.\n * @param attributes The attributes of the node to reset.\n * @example editor.commands.resetAttributes('heading', 'level')\n */\n resetAttributes: (\n typeOrName: string | NodeType | MarkType,\n attributes: string | string[],\n ) => ReturnType\n }\n }\n}\n\nexport const resetAttributes: RawCommands['resetAttributes'] = (typeOrName, attributes) => ({ tr, state, dispatch }) => {\n let nodeType: NodeType | null = null\n let markType: MarkType | null = null\n\n const schemaType = getSchemaTypeNameByName(\n typeof typeOrName === 'string' ? typeOrName : typeOrName.name,\n state.schema,\n )\n\n if (!schemaType) {\n return false\n }\n\n if (schemaType === 'node') {\n nodeType = getNodeType(typeOrName as NodeType, state.schema)\n }\n\n if (schemaType === 'mark') {\n markType = getMarkType(typeOrName as MarkType, state.schema)\n }\n\n if (dispatch) {\n tr.selection.ranges.forEach(range => {\n state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => {\n if (nodeType && nodeType === node.type) {\n tr.setNodeMarkup(pos, undefined, deleteProps(node.attrs, attributes))\n }\n\n if (markType && node.marks.length) {\n node.marks.forEach(mark => {\n if (markType === mark.type) {\n tr.addMark(\n pos,\n pos + node.nodeSize,\n markType.create(deleteProps(mark.attrs, attributes)),\n )\n }\n })\n }\n })\n })\n }\n\n return true\n}\n","import { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n scrollIntoView: {\n /**\n * Scroll the selection into view.\n * @example editor.commands.scrollIntoView()\n */\n scrollIntoView: () => ReturnType,\n }\n }\n}\n\nexport const scrollIntoView: RawCommands['scrollIntoView'] = () => ({ tr, dispatch }) => {\n if (dispatch) {\n tr.scrollIntoView()\n }\n\n return true\n}\n","import { AllSelection } from '@tiptap/pm/state'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n selectAll: {\n /**\n * Select the whole document.\n * @example editor.commands.selectAll()\n */\n selectAll: () => ReturnType,\n }\n }\n}\n\nexport const selectAll: RawCommands['selectAll'] = () => ({ tr, dispatch }) => {\n if (dispatch) {\n const selection = new AllSelection(tr.doc)\n\n tr.setSelection(selection)\n }\n\n return true\n}\n","import { selectNodeBackward as originalSelectNodeBackward } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n selectNodeBackward: {\n /**\n * Select a node backward.\n * @example editor.commands.selectNodeBackward()\n */\n selectNodeBackward: () => ReturnType\n }\n }\n}\n\nexport const selectNodeBackward: RawCommands['selectNodeBackward'] = () => ({ state, dispatch }) => {\n return originalSelectNodeBackward(state, dispatch)\n}\n","import { selectNodeForward as originalSelectNodeForward } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n selectNodeForward: {\n /**\n * Select a node forward.\n * @example editor.commands.selectNodeForward()\n */\n selectNodeForward: () => ReturnType\n }\n }\n}\n\nexport const selectNodeForward: RawCommands['selectNodeForward'] = () => ({ state, dispatch }) => {\n return originalSelectNodeForward(state, dispatch)\n}\n","import { selectParentNode as originalSelectParentNode } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n selectParentNode: {\n /**\n * Select the parent node.\n * @example editor.commands.selectParentNode()\n */\n selectParentNode: () => ReturnType\n }\n }\n}\n\nexport const selectParentNode: RawCommands['selectParentNode'] = () => ({ state, dispatch }) => {\n return originalSelectParentNode(state, dispatch)\n}\n","// @ts-ignore\n// TODO: add types to @types/prosemirror-commands\nimport { selectTextblockEnd as originalSelectTextblockEnd } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n selectTextblockEnd: {\n /**\n * Moves the cursor to the end of current text block.\n * @example editor.commands.selectTextblockEnd()\n */\n selectTextblockEnd: () => ReturnType\n }\n }\n}\n\nexport const selectTextblockEnd: RawCommands['selectTextblockEnd'] = () => ({ state, dispatch }) => {\n return originalSelectTextblockEnd(state, dispatch)\n}\n","// @ts-ignore\n// TODO: add types to @types/prosemirror-commands\nimport { selectTextblockStart as originalSelectTextblockStart } from '@tiptap/pm/commands'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n selectTextblockStart: {\n /**\n * Moves the cursor to the start of current text block.\n * @example editor.commands.selectTextblockStart()\n */\n selectTextblockStart: () => ReturnType\n }\n }\n}\n\nexport const selectTextblockStart: RawCommands['selectTextblockStart'] = () => ({ state, dispatch }) => {\n return originalSelectTextblockStart(state, dispatch)\n}\n","import {\n Fragment, Node as ProseMirrorNode, ParseOptions, Schema,\n} from '@tiptap/pm/model'\n\nimport { Content } from '../types.js'\nimport { createNodeFromContent } from './createNodeFromContent.js'\n\n/**\n * Create a new Prosemirror document node from content.\n * @param content The JSON or HTML content to create the document from\n * @param schema The Prosemirror schema to use for the document\n * @param parseOptions Options for the parser\n * @returns The created Prosemirror document node\n */\nexport function createDocument(\n content: Content | ProseMirrorNode | Fragment,\n schema: Schema,\n parseOptions: ParseOptions = {},\n options: { errorOnInvalidContent?: boolean } = {},\n): ProseMirrorNode {\n return createNodeFromContent(content, schema, {\n slice: false,\n parseOptions,\n errorOnInvalidContent: options.errorOnInvalidContent,\n }) as ProseMirrorNode\n}\n","import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model'\n\nimport { createDocument } from '../helpers/createDocument.js'\nimport { Content, RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n setContent: {\n /**\n * Replace the whole document with new content.\n * @param content The new content.\n * @param emitUpdate Whether to emit an update event.\n * @param parseOptions Options for parsing the content.\n * @example editor.commands.setContent('<p>Example text</p>')\n */\n setContent: (\n /**\n * The new content.\n */\n content: Content | Fragment | ProseMirrorNode,\n\n /**\n * Whether to emit an update event.\n * @default false\n */\n emitUpdate?: boolean,\n\n /**\n * Options for parsing the content.\n * @default {}\n */\n parseOptions?: ParseOptions,\n /**\n * Options for `setContent`.\n */\n options?: {\n /**\n * Whether to throw an error if the content is invalid.\n */\n errorOnInvalidContent?: boolean;\n }\n ) => ReturnType;\n };\n }\n}\n\nexport const setContent: RawCommands['setContent'] = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({\n editor, tr, dispatch, commands,\n}) => {\n const { doc } = tr\n\n // This is to keep backward compatibility with the previous behavior\n // TODO remove this in the next major version\n if (parseOptions.preserveWhitespace !== 'full') {\n const document = createDocument(content, editor.schema, parseOptions, {\n errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,\n })\n\n if (dispatch) {\n tr.replaceWith(0, doc.content.size, document).setMeta('preventUpdate', !emitUpdate)\n }\n return true\n }\n\n if (dispatch) {\n tr.setMeta('preventUpdate', !emitUpdate)\n }\n\n return commands.insertContentAt({ from: 0, to: doc.content.size }, content, {\n parseOptions,\n errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,\n })\n}\n","import { Mark, MarkType } from '@tiptap/pm/model'\nimport { EditorState } from '@tiptap/pm/state'\n\nimport { getMarkType } from './getMarkType.js'\n\nexport function getMarkAttributes(\n state: EditorState,\n typeOrName: string | MarkType,\n): Record<string, any> {\n const type = getMarkType(typeOrName, state.schema)\n const { from, to, empty } = state.selection\n const marks: Mark[] = []\n\n if (empty) {\n if (state.storedMarks) {\n marks.push(...state.storedMarks)\n }\n\n marks.push(...state.selection.$head.marks())\n } else {\n state.doc.nodesBetween(from, to, node => {\n marks.push(...node.marks)\n })\n }\n\n const mark = marks.find(markItem => markItem.type.name === type.name)\n\n if (!mark) {\n return {}\n }\n\n return { ...mark.attrs }\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Transaction } from '@tiptap/pm/state'\nimport { Transform } from '@tiptap/pm/transform'\n\n/**\n * Returns a new `Transform` based on all steps of the passed transactions.\n * @param oldDoc The Prosemirror node to start from\n * @param transactions The transactions to combine\n * @returns A new `Transform` with all steps of the passed transactions\n */\nexport function combineTransactionSteps(\n oldDoc: ProseMirrorNode,\n transactions: Transaction[],\n): Transform {\n const transform = new Transform(oldDoc)\n\n transactions.forEach(transaction => {\n transaction.steps.forEach(step => {\n transform.step(step)\n })\n })\n\n return transform\n}\n","import { ContentMatch, NodeType } from '@tiptap/pm/model'\n\n/**\n * Gets the default block type at a given match\n * @param match The content match to get the default block type from\n * @returns The default block type or null\n */\nexport function defaultBlockAt(match: ContentMatch): NodeType | null {\n for (let i = 0; i < match.edgeCount; i += 1) {\n const { type } = match.edge(i)\n\n if (type.isTextblock && !type.hasRequiredAttrs()) {\n return type\n }\n }\n\n return null\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { NodeWithPos, Predicate } from '../types.js'\n\n/**\n * Find children inside a Prosemirror node that match a predicate.\n * @param node The Prosemirror node to search in\n * @param predicate The predicate to match\n * @returns An array of nodes with their positions\n */\nexport function findChildren(node: ProseMirrorNode, predicate: Predicate): NodeWithPos[] {\n const nodesWithPos: NodeWithPos[] = []\n\n node.descendants((child, pos) => {\n if (predicate(child)) {\n nodesWithPos.push({\n node: child,\n pos,\n })\n }\n })\n\n return nodesWithPos\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { NodeWithPos, Predicate, Range } from '../types.js'\n\n/**\n * Same as `findChildren` but searches only within a `range`.\n * @param node The Prosemirror node to search in\n * @param range The range to search in\n * @param predicate The predicate to match\n * @returns An array of nodes with their positions\n */\nexport function findChildrenInRange(\n node: ProseMirrorNode,\n range: Range,\n predicate: Predicate,\n): NodeWithPos[] {\n const nodesWithPos: NodeWithPos[] = []\n\n // if (range.from === range.to) {\n // const nodeAt = node.nodeAt(range.from)\n\n // if (nodeAt) {\n // nodesWithPos.push({\n // node: nodeAt,\n // pos: range.from,\n // })\n // }\n // }\n\n node.nodesBetween(range.from, range.to, (child, pos) => {\n if (predicate(child)) {\n nodesWithPos.push({\n node: child,\n pos,\n })\n }\n })\n\n return nodesWithPos\n}\n","import { Node as ProseMirrorNode, ResolvedPos } from '@tiptap/pm/model'\n\nimport { Predicate } from '../types.js'\n\n/**\n * Finds the closest parent node to a resolved position that matches a predicate.\n * @param $pos The resolved position to search from\n * @param predicate The predicate to match\n * @returns The closest parent node to the resolved position that matches the predicate\n * @example ```js\n * findParentNodeClosestToPos($from, node => node.type.name === 'paragraph')\n * ```\n */\nexport function findParentNodeClosestToPos(\n $pos: ResolvedPos,\n predicate: Predicate,\n):\n | {\n pos: number\n start: number\n depth: number\n node: ProseMirrorNode\n }\n | undefined {\n for (let i = $pos.depth; i > 0; i -= 1) {\n const node = $pos.node(i)\n\n if (predicate(node)) {\n return {\n pos: i > 0 ? $pos.before(i) : 0,\n start: $pos.start(i),\n depth: i,\n node,\n }\n }\n }\n}\n","import { Selection } from '@tiptap/pm/state'\n\nimport { Predicate } from '../types.js'\nimport { findParentNodeClosestToPos } from './findParentNodeClosestToPos.js'\n\n/**\n * Finds the closest parent node to the current selection that matches a predicate.\n * @param predicate The predicate to match\n * @returns A command that finds the closest parent node to the current selection that matches the predicate\n * @example ```js\n * findParentNode(node => node.type.name === 'paragraph')\n * ```\n */\nexport function findParentNode(predicate: Predicate) {\n return (selection: Selection) => findParentNodeClosestToPos(selection.$from, predicate)\n}\n","import { Schema } from '@tiptap/pm/model'\n\nimport { Editor } from '../Editor.js'\nimport { ExtensionManager } from '../ExtensionManager.js'\nimport { Extensions } from '../types.js'\nimport { getSchemaByResolvedExtensions } from './getSchemaByResolvedExtensions.js'\n\nexport function getSchema(extensions: Extensions, editor?: Editor): Schema {\n const resolvedExtensions = ExtensionManager.resolve(extensions)\n\n return getSchemaByResolvedExtensions(resolvedExtensions, editor)\n}\n","import { Node } from '@tiptap/pm/model'\n\nimport { Extensions, JSONContent } from '../types.js'\nimport { getHTMLFromFragment } from './getHTMLFromFragment.js'\nimport { getSchema } from './getSchema.js'\n\n/**\n * Generate HTML from a JSONContent\n * @param doc The JSONContent to generate HTML from\n * @param extensions The extensions to use for the schema\n * @returns The generated HTML\n */\nexport function generateHTML(doc: JSONContent, extensions: Extensions): string {\n const schema = getSchema(extensions)\n const contentNode = Node.fromJSON(schema, doc)\n\n return getHTMLFromFragment(contentNode.content, schema)\n}\n","import { DOMParser } from '@tiptap/pm/model'\n\nimport { Extensions } from '../types.js'\nimport { elementFromString } from '../utilities/elementFromString.js'\nimport { getSchema } from './getSchema.js'\n\n/**\n * Generate JSONContent from HTML\n * @param html The HTML to generate JSONContent from\n * @param extensions The extensions to use for the schema\n * @returns The generated JSONContent\n */\nexport function generateJSON(html: string, extensions: Extensions): Record<string, any> {\n const schema = getSchema(extensions)\n const dom = elementFromString(html)\n\n return DOMParser.fromSchema(schema).parse(dom).toJSON()\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { TextSerializer } from '../types.js'\nimport { getTextBetween } from './getTextBetween.js'\n\n/**\n * Gets the text of a Prosemirror node\n * @param node The Prosemirror node\n * @param options Options for the text serializer & block separator\n * @returns The text of the node\n * @example ```js\n * const text = getText(node, { blockSeparator: '\\n' })\n * ```\n */\nexport function getText(\n node: ProseMirrorNode,\n options?: {\n blockSeparator?: string\n textSerializers?: Record<string, TextSerializer>\n },\n) {\n const range = {\n from: 0,\n to: node.content.size,\n }\n\n return getTextBetween(node, range, options)\n}\n","import { Node } from '@tiptap/pm/model'\n\nimport { Extensions, JSONContent, TextSerializer } from '../types.js'\nimport { getSchema } from './getSchema.js'\nimport { getText } from './getText.js'\nimport { getTextSerializersFromSchema } from './getTextSerializersFromSchema.js'\n\n/**\n * Generate raw text from a JSONContent\n * @param doc The JSONContent to generate text from\n * @param extensions The extensions to use for the schema\n * @param options Options for the text generation f.e. blockSeparator or textSerializers\n * @returns The generated text\n */\nexport function generateText(\n doc: JSONContent,\n extensions: Extensions,\n options?: {\n blockSeparator?: string\n textSerializers?: Record<string, TextSerializer>\n },\n): string {\n const { blockSeparator = '\\n\\n', textSerializers = {} } = options || {}\n const schema = getSchema(extensions)\n const contentNode = Node.fromJSON(schema, doc)\n\n return getText(contentNode, {\n blockSeparator,\n textSerializers: {\n ...getTextSerializersFromSchema(schema),\n ...textSerializers,\n },\n })\n}\n","import { Node, NodeType } from '@tiptap/pm/model'\nimport { EditorState } from '@tiptap/pm/state'\n\nimport { getNodeType } from './getNodeType.js'\n\nexport function getNodeAttributes(\n state: EditorState,\n typeOrName: string | NodeType,\n): Record<string, any> {\n const type = getNodeType(typeOrName, state.schema)\n const { from, to } = state.selection\n const nodes: Node[] = []\n\n state.doc.nodesBetween(from, to, node => {\n nodes.push(node)\n })\n\n const node = nodes.reverse().find(nodeItem => nodeItem.type.name === type.name)\n\n if (!node) {\n return {}\n }\n\n return { ...node.attrs }\n}\n","import { MarkType, NodeType } from '@tiptap/pm/model'\nimport { EditorState } from '@tiptap/pm/state'\n\nimport { getMarkAttributes } from './getMarkAttributes.js'\nimport { getNodeAttributes } from './getNodeAttributes.js'\nimport { getSchemaTypeNameByName } from './getSchemaTypeNameByName.js'\n\n/**\n * Get node or mark attributes by type or name on the current editor state\n * @param state The current editor state\n * @param typeOrName The node or mark type or name\n * @returns The attributes of the node or mark or an empty object\n */\nexport function getAttributes(\n state: EditorState,\n typeOrName: string | NodeType | MarkType,\n): Record<string, any> {\n const schemaType = getSchemaTypeNameByName(\n typeof typeOrName === 'string' ? typeOrName : typeOrName.name,\n state.schema,\n )\n\n if (schemaType === 'node') {\n return getNodeAttributes(state, typeOrName as NodeType)\n }\n\n if (schemaType === 'mark') {\n return getMarkAttributes(state, typeOrName as MarkType)\n }\n\n return {}\n}\n","/**\n * Removes duplicated values within an array.\n * Supports numbers, strings and objects.\n */\nexport function removeDuplicates<T>(array: T[], by = JSON.stringify): T[] {\n const seen: Record<any, any> = {}\n\n return array.filter(item => {\n const key = by(item)\n\n return Object.prototype.hasOwnProperty.call(seen, key)\n ? false\n : (seen[key] = true)\n })\n}\n","import { Step, Transform } from '@tiptap/pm/transform'\n\nimport { Range } from '../types.js'\nimport { removeDuplicates } from '../utilities/removeDuplicates.js'\n\nexport type ChangedRange = {\n oldRange: Range,\n newRange: Range,\n}\n\n/**\n * Removes duplicated ranges and ranges that are\n * fully captured by other ranges.\n */\nfunction simplifyChangedRanges(changes: ChangedRange[]): ChangedRange[] {\n const uniqueChanges = removeDuplicates(changes)\n\n return uniqueChanges.length === 1\n ? uniqueChanges\n : uniqueChanges.filter((change, index) => {\n const rest = uniqueChanges.filter((_, i) => i !== index)\n\n return !rest.some(otherChange => {\n return change.oldRange.from >= otherChange.oldRange.from\n && change.oldRange.to <= otherChange.oldRange.to\n && change.newRange.from >= otherChange.newRange.from\n && change.newRange.to <= otherChange.newRange.to\n })\n })\n}\n\n/**\n * Returns a list of changed ranges\n * based on the first and last state of all steps.\n */\nexport function getChangedRanges(transform: Transform): ChangedRange[] {\n const { mapping, steps } = transform\n const changes: ChangedRange[] = []\n\n mapping.maps.forEach((stepMap, index) => {\n const ranges: Range[] = []\n\n // This accounts for step changes where no range was actually altered\n // e.g. when setting a mark, node attribute, etc.\n // @ts-ignore\n if (!stepMap.ranges.length) {\n const { from, to } = steps[index] as Step & {\n from?: number,\n to?: number,\n }\n\n if (from === undefined || to === undefined) {\n return\n }\n\n ranges.push({ from, to })\n } else {\n stepMap.forEach((from, to) => {\n ranges.push({ from, to })\n })\n }\n\n ranges.forEach(({ from, to }) => {\n const newStart = mapping.slice(index).map(from, -1)\n const newEnd = mapping.slice(index).map(to)\n const oldStart = mapping.invert().map(newStart, -1)\n const oldEnd = mapping.invert().map(newEnd)\n\n changes.push({\n oldRange: {\n from: oldStart,\n to: oldEnd,\n },\n newRange: {\n from: newStart,\n to: newEnd,\n },\n })\n })\n })\n\n return simplifyChangedRanges(changes)\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { JSONContent } from '../types.js'\n\ninterface DebugJSONContent extends JSONContent {\n from: number\n to: number\n}\n\nexport function getDebugJSON(node: ProseMirrorNode, startOffset = 0): DebugJSONContent {\n const isTopNode = node.type === node.type.schema.topNodeType\n const increment = isTopNode ? 0 : 1\n const from = startOffset\n const to = from + node.nodeSize\n const marks = node.marks.map(mark => {\n const output: { type: string; attrs?: Record<string, any> } = {\n type: mark.type.name,\n }\n\n if (Object.keys(mark.attrs).length) {\n output.attrs = { ...mark.attrs }\n }\n\n return output\n })\n const attrs = { ...node.attrs }\n const output: DebugJSONContent = {\n type: node.type.name,\n from,\n to,\n }\n\n if (Object.keys(attrs).length) {\n output.attrs = attrs\n }\n\n if (marks.length) {\n output.marks = marks\n }\n\n if (node.content.childCount) {\n output.content = []\n\n node.forEach((child, offset) => {\n output.content?.push(getDebugJSON(child, startOffset + offset + increment))\n })\n }\n\n if (node.text) {\n output.text = node.text\n }\n\n return output\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\n\nimport { MarkRange } from '../types.js'\nimport { getMarkRange } from './getMarkRange.js'\n\nexport function getMarksBetween(from: number, to: number, doc: ProseMirrorNode): MarkRange[] {\n const marks: MarkRange[] = []\n\n // get all inclusive marks on empty selection\n if (from === to) {\n doc\n .resolve(from)\n .marks()\n .forEach(mark => {\n const $pos = doc.resolve(from)\n const range = getMarkRange($pos, mark.type)\n\n if (!range) {\n return\n }\n\n marks.push({\n mark,\n ...range,\n })\n })\n } else {\n doc.nodesBetween(from, to, (node, pos) => {\n if (!node || node?.nodeSize === undefined) {\n return\n }\n\n marks.push(\n ...node.marks.map(mark => ({\n from: pos,\n to: pos + node.nodeSize,\n mark,\n })),\n )\n })\n }\n\n return marks\n}\n","import { Node, NodeType } from '@tiptap/pm/model'\nimport { EditorState } from '@tiptap/pm/state'\n\n/**\n * Finds the first node of a given type or name in the current selection.\n * @param state The editor state.\n * @param typeOrName The node type or name.\n * @param pos The position to start searching from.\n * @param maxDepth The maximum depth to search.\n * @returns The node and the depth as an array.\n */\nexport const getNodeAtPosition = (state: EditorState, typeOrName: string | NodeType, pos: number, maxDepth = 20) => {\n const $pos = state.doc.resolve(pos)\n\n let currentDepth = maxDepth\n let node: Node | null = null\n\n while (currentDepth > 0 && node === null) {\n const currentNode = $pos.node(currentDepth)\n\n if (currentNode?.type.name === typeOrName) {\n node = currentNode\n } else {\n currentDepth -= 1\n }\n }\n\n return [node, currentDepth] as [Node | null, number]\n}\n","import { ExtensionAttribute } from '../types.js'\n\n/**\n * Return attributes of an extension that should be splitted by keepOnSplit flag\n * @param extensionAttributes Array of extension attributes\n * @param typeName The type of the extension\n * @param attributes The attributes of the extension\n * @returns The splitted attributes\n */\nexport function getSplittedAttributes(\n extensionAttributes: ExtensionAttribute[],\n typeName: string,\n attributes: Record<string, any>,\n): Record<string, any> {\n return Object.fromEntries(Object\n .entries(attributes)\n .filter(([name]) => {\n const extensionAttribute = extensionAttributes.find(item => {\n return item.type === typeName && item.name === name\n })\n\n if (!extensionAttribute) {\n return false\n }\n\n return extensionAttribute.attribute.keepOnSplit\n }))\n}\n","import { MarkType } from '@tiptap/pm/model'\nimport { EditorState } from '@tiptap/pm/state'\n\nimport { MarkRange } from '../types.js'\nimport { objectIncludes } from '../utilities/objectIncludes.js'\nimport { getMarkType } from './getMarkType.js'\n\nexport function isMarkActive(\n state: EditorState,\n typeOrName: MarkType | string | null,\n attributes: Record<string, any> = {},\n): boolean {\n const { empty, ranges } = state.selection\n const type = typeOrName ? getMarkType(typeOrName, state.schema) : null\n\n if (empty) {\n return !!(state.storedMarks || state.selection.$from.marks())\n .filter(mark => {\n if (!type) {\n return true\n }\n\n return type.name === mark.type.name\n })\n .find(mark => objectIncludes(mark.attrs, attributes, { strict: false }))\n }\n\n let selectionRange = 0\n const markRanges: MarkRange[] = []\n\n ranges.forEach(({ $from, $to }) => {\n const from = $from.pos\n const to = $to.pos\n\n state.doc.nodesBetween(from, to, (node, pos) => {\n if (!node.isText && !node.marks.length) {\n return\n }\n\n const relativeFrom = Math.max(from, pos)\n const relativeTo = Math.min(to, pos + node.nodeSize)\n const range = relativeTo - relativeFrom\n\n selectionRange += range\n\n markRanges.push(\n ...node.marks.map(mark => ({\n mark,\n from: relativeFrom,\n to: relativeTo,\n })),\n )\n })\n })\n\n if (selectionRange === 0) {\n return false\n }\n\n // calculate range of matched mark\n const matchedRange = markRanges\n .filter(markRange => {\n if (!type) {\n return true\n }\n\n return type.name === markRange.mark.type.name\n })\n .filter(markRange => objectIncludes(markRange.mark.attrs, attributes, { strict: false }))\n .reduce((sum, markRange) => sum + markRange.to - markRange.from, 0)\n\n // calculate range of marks that excludes the searched mark\n // for example `code` doesn’t allow any other marks\n const excludedRange = markRanges\n .filter(markRange => {\n if (!type) {\n return true\n }\n\n return markRange.mark.type !== type && markRange.mark.type.excludes(type)\n })\n .reduce((sum, markRange) => sum + markRange.to - markRange.from, 0)\n\n // we only include the result of `excludedRange`\n // if there is a match at all\n const range = matchedRange > 0 ? matchedRange + excludedRange : matchedRange\n\n return range >= selectionRange\n}\n","import { EditorState } from '@tiptap/pm/state'\n\nimport { getSchemaTypeNameByName } from './getSchemaTypeNameByName.js'\nimport { isMarkActive } from './isMarkActive.js'\nimport { isNodeActive } from './isNodeActive.js'\n\nexport function isActive(\n state: EditorState,\n name: string | null,\n attributes: Record<string, any> = {},\n): boolean {\n if (!name) {\n return isNodeActive(state, null, attributes) || isMarkActive(state, null, attributes)\n }\n\n const schemaType = getSchemaTypeNameByName(name, state.schema)\n\n if (schemaType === 'node') {\n return isNodeActive(state, name, attributes)\n }\n\n if (schemaType === 'mark') {\n return isMarkActive(state, name, attributes)\n }\n\n return false\n}\n","import { EditorState } from '@tiptap/pm/state'\n\nimport { findParentNode } from './findParentNode.js'\n\nexport const isAtEndOfNode = (state: EditorState, nodeType?: string) => {\n const { $from, $to, $anchor } = state.selection\n\n if (nodeType) {\n const parentNode = findParentNode(node => node.type.name === nodeType)(state.selection)\n\n if (!parentNode) {\n return false\n }\n\n const $parentPos = state.doc.resolve(parentNode.pos + 1)\n\n if ($anchor.pos + 1 === $parentPos.end()) {\n return true\n }\n\n return false\n }\n\n if ($to.parentOffset < $to.parent.nodeSize - 2 || $from.pos !== $to.pos) {\n return false\n }\n\n return true\n}\n","import { EditorState } from '@tiptap/pm/state'\n\nexport const isAtStartOfNode = (state: EditorState) => {\n const { $from, $to } = state.selection\n\n if ($from.parentOffset > 0 || $from.pos !== $to.pos) {\n return false\n }\n\n return true\n}\n","import { getExtensionField } from '../helpers/getExtensionField.js'\nimport { NodeConfig } from '../index.js'\nimport { Extensions } from '../types.js'\nimport { callOrReturn } from '../utilities/callOrReturn.js'\nimport { splitExtensions } from './splitExtensions.js'\n\nexport function isList(name: string, extensions: Extensions): boolean {\n const { nodeExtensions } = splitExtensions(extensions)\n const extension = nodeExtensions.find(item => item.name === name)\n\n if (!extension) {\n return false\n }\n\n const context = {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n }\n const group = callOrReturn(getExtensionField<NodeConfig['group']>(extension, 'group', context))\n\n if (typeof group !== 'string') {\n return false\n }\n\n return group.split(' ').includes('list')\n}\n","import { Node as ProseMirrorNode } from '@tiptap/pm/model'\n\n/**\n * Returns true if the given prosemirror node is empty.\n */\nexport function isNodeEmpty(\n node: ProseMirrorNode,\n {\n checkChildren = true,\n ignoreWhitespace = false,\n }: {\n /**\n * When true (default), it will also check if all children are empty.\n */\n checkChildren?: boolean;\n /**\n * When true, it will ignore whitespace when checking for emptiness.\n */\n ignoreWhitespace?: boolean;\n } = {},\n): boolean {\n if (ignoreWhitespace) {\n if (node.type.name === 'hardBreak') {\n // Hard breaks are considered empty\n return true\n }\n if (node.isText) {\n return /^\\s*$/m.test(node.text ?? '')\n }\n }\n\n if (node.isText) {\n return !node.text\n }\n\n if (node.isAtom || node.isLeaf) {\n return false\n }\n\n if (node.content.childCount === 0) {\n return true\n }\n\n if (checkChildren) {\n let isContentEmpty = true\n\n node.content.forEach(childNode => {\n if (isContentEmpty === false) {\n // Exit early for perf\n return\n }\n\n if (!isNodeEmpty(childNode, { ignoreWhitespace, checkChildren })) {\n isContentEmpty = false\n }\n })\n\n return isContentEmpty\n }\n\n return false\n}\n","import { NodeSelection } from '@tiptap/pm/state'\n\nexport function isNodeSelection(value: unknown): value is NodeSelection {\n return value instanceof NodeSelection\n}\n","import { EditorView } from '@tiptap/pm/view'\n\nimport { minMax } from '../utilities/minMax.js'\n\nexport function posToDOMRect(view: EditorView, from: number, to: number): DOMRect {\n const minPos = 0\n const maxPos = view.state.doc.content.size\n const resolvedFrom = minMax(from, minPos, maxPos)\n const resolvedEnd = minMax(to, minPos, maxPos)\n const start = view.coordsAtPos(resolvedFrom)\n const end = view.coordsAtPos(resolvedEnd, -1)\n const top = Math.min(start.top, end.top)\n const bottom = Math.max(start.bottom, end.bottom)\n const left = Math.min(start.left, end.left)\n const right = Math.max(start.right, end.right)\n const width = right - left\n const height = bottom - top\n const x = left\n const y = top\n const data = {\n top,\n bottom,\n left,\n right,\n width,\n height,\n x,\n y,\n }\n\n return {\n ...data,\n toJSON: () => data,\n }\n}\n","import type { Schema } from '@tiptap/pm/model'\n\nimport type { JSONContent } from '../types.js'\n\ntype RewriteUnknownContentOptions = {\n /**\n * If true, unknown nodes will be treated as paragraphs\n * @default true\n */\n fallbackToParagraph?: boolean;\n};\n\ntype RewrittenContent = {\n /**\n * The original JSON content that was rewritten\n */\n original: JSONContent;\n /**\n * The name of the node or mark that was unsupported\n */\n unsupported: string;\n}[];\n\n/**\n * The actual implementation of the rewriteUnknownContent function\n */\nfunction rewriteUnknownContentInner({\n json,\n validMarks,\n validNodes,\n options,\n rewrittenContent = [],\n}: {\n json: JSONContent;\n validMarks: Set<string>;\n validNodes: Set<string>;\n options?: RewriteUnknownContentOptions;\n rewrittenContent?: RewrittenContent;\n}): {\n /**\n * The cleaned JSON content\n */\n json: JSONContent | null;\n /**\n * The array of nodes and marks that were rewritten\n */\n rewrittenContent: RewrittenContent;\n} {\n if (json.marks && Array.isArray(json.marks)) {\n json.marks = json.marks.filter(mark => {\n const name = typeof mark === 'string' ? mark : mark.type\n\n if (validMarks.has(name)) {\n return true\n }\n\n rewrittenContent.push({\n original: JSON.parse(JSON.stringify(mark)),\n unsupported: name,\n })\n // Just ignore any unknown marks\n return false\n })\n }\n\n if (json.content && Array.isArray(json.content)) {\n json.content = json.content\n .map(\n value => rewriteUnknownContentInner({\n json: value,\n validMarks,\n validNodes,\n options,\n rewrittenContent,\n }).json,\n )\n .filter(a => a !== null && a !== undefined)\n }\n\n if (json.type && !validNodes.has(json.type)) {\n rewrittenContent.push({\n original: JSON.parse(JSON.stringify(json)),\n unsupported: json.type,\n })\n\n if (json.content && Array.isArray(json.content) && (options?.fallbackToParagraph !== false)) {\n // Just treat it like a paragraph and hope for the best\n json.type = 'paragraph'\n\n return {\n json,\n rewrittenContent,\n }\n }\n\n // or just omit it entirely\n return {\n json: null,\n rewrittenContent,\n }\n }\n\n return { json, rewrittenContent }\n}\n\n/**\n * Rewrite unknown nodes and marks within JSON content\n * Allowing for user within the editor\n */\nexport function rewriteUnknownContent(\n /**\n * The JSON content to clean of unknown nodes and marks\n */\n json: JSONContent,\n /**\n * The schema to use for validation\n */\n schema: Schema,\n /**\n * Options for the cleaning process\n */\n options?: RewriteUnknownContentOptions,\n): {\n /**\n * The cleaned JSON content\n */\n json: JSONContent | null;\n /**\n * The array of nodes and marks that were rewritten\n */\n rewrittenContent: {\n /**\n * The original JSON content that was rewritten\n */\n original: JSONContent;\n /**\n * The name of the node or mark that was unsupported\n */\n unsupported: string;\n }[];\n} {\n return rewriteUnknownContentInner({\n json,\n validNodes: new Set(Object.keys(schema.nodes)),\n validMarks: new Set(Object.keys(schema.marks)),\n options,\n })\n}\n","import { MarkType, ResolvedPos } from '@tiptap/pm/model'\nimport { EditorState, Transaction } from '@tiptap/pm/state'\n\nimport { getMarkAttributes } from '../helpers/getMarkAttributes.js'\nimport { getMarkType } from '../helpers/getMarkType.js'\nimport { isTextSelection } from '../helpers/index.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n setMark: {\n /**\n * Add a mark with new attributes.\n * @param typeOrName The mark type or name.\n * @example editor.commands.setMark('bold', { level: 1 })\n */\n setMark: (typeOrName: string | MarkType, attributes?: Record<string, any>) => ReturnType\n }\n }\n}\n\nfunction canSetMark(state: EditorState, tr: Transaction, newMarkType: MarkType) {\n const { selection } = tr\n let cursor: ResolvedPos | null = null\n\n if (isTextSelection(selection)) {\n cursor = selection.$cursor\n }\n\n if (cursor) {\n const currentMarks = state.storedMarks ?? cursor.marks()\n\n // There can be no current marks that exclude the new mark\n return (\n !!newMarkType.isInSet(currentMarks)\n || !currentMarks.some(mark => mark.type.excludes(newMarkType))\n )\n }\n\n const { ranges } = selection\n\n return ranges.some(({ $from, $to }) => {\n let someNodeSupportsMark = $from.depth === 0\n ? state.doc.inlineContent && state.doc.type.allowsMarkType(newMarkType)\n : false\n\n state.doc.nodesBetween($from.pos, $to.pos, (node, _pos, parent) => {\n // If we already found a mark that we can enable, return false to bypass the remaining search\n if (someNodeSupportsMark) {\n return false\n }\n\n if (node.isInline) {\n const parentAllowsMarkType = !parent || parent.type.allowsMarkType(newMarkType)\n const currentMarksAllowMarkType = !!newMarkType.isInSet(node.marks)\n || !node.marks.some(otherMark => otherMark.type.excludes(newMarkType))\n\n someNodeSupportsMark = parentAllowsMarkType && currentMarksAllowMarkType\n }\n return !someNodeSupportsMark\n })\n\n return someNodeSupportsMark\n })\n}\nexport const setMark: RawCommands['setMark'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {\n const { selection } = tr\n const { empty, ranges } = selection\n const type = getMarkType(typeOrName, state.schema)\n\n if (dispatch) {\n if (empty) {\n const oldAttributes = getMarkAttributes(state, type)\n\n tr.addStoredMark(\n type.create({\n ...oldAttributes,\n ...attributes,\n }),\n )\n } else {\n ranges.forEach(range => {\n const from = range.$from.pos\n const to = range.$to.pos\n\n state.doc.nodesBetween(from, to, (node, pos) => {\n const trimmedFrom = Math.max(pos, from)\n const trimmedTo = Math.min(pos + node.nodeSize, to)\n const someHasMark = node.marks.find(mark => mark.type === type)\n\n // if there is already a mark of this type\n // we know that we have to merge its attributes\n // otherwise we add a fresh new mark\n if (someHasMark) {\n node.marks.forEach(mark => {\n if (type === mark.type) {\n tr.addMark(\n trimmedFrom,\n trimmedTo,\n type.create({\n ...mark.attrs,\n ...attributes,\n }),\n )\n }\n })\n } else {\n tr.addMark(trimmedFrom, trimmedTo, type.create(attributes))\n }\n })\n })\n }\n }\n\n return canSetMark(state, tr, type)\n}\n","import type { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n setMeta: {\n /**\n * Store a metadata property in the current transaction.\n * @param key The key of the metadata property.\n * @param value The value to store.\n * @example editor.commands.setMeta('foo', 'bar')\n */\n setMeta: (key: string | Plugin | PluginKey, value: any) => ReturnType,\n }\n }\n}\n\nexport const setMeta: RawCommands['setMeta'] = (key, value) => ({ tr }) => {\n tr.setMeta(key, value)\n\n return true\n}\n","import { setBlockType } from '@tiptap/pm/commands'\nimport { NodeType } from '@tiptap/pm/model'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n setNode: {\n /**\n * Replace a given range with a node.\n * @param typeOrName The type or name of the node\n * @param attributes The attributes of the node\n * @example editor.commands.setNode('paragraph')\n */\n setNode: (typeOrName: string | NodeType, attributes?: Record<string, any>) => ReturnType\n }\n }\n}\n\nexport const setNode: RawCommands['setNode'] = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {\n const type = getNodeType(typeOrName, state.schema)\n\n let attributesToCopy: Record<string, any> | undefined\n\n if (state.selection.$anchor.sameParent(state.selection.$head)) {\n // only copy attributes if the selection is pointing to a node of the same type\n attributesToCopy = state.selection.$anchor.parent.attrs\n }\n\n // TODO: use a fallback like insertContent?\n if (!type.isTextblock) {\n console.warn('[tiptap warn]: Currently \"setNode()\" only supports text block nodes.')\n\n return false\n }\n\n return (\n chain()\n // try to convert node to default node if needed\n .command(({ commands }) => {\n const canSetBlock = setBlockType(type, { ...attributesToCopy, ...attributes })(state)\n\n if (canSetBlock) {\n return true\n }\n\n return commands.clearNodes()\n })\n .command(({ state: updatedState }) => {\n return setBlockType(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch)\n })\n .run()\n )\n}\n","import { NodeSelection } from '@tiptap/pm/state'\n\nimport { RawCommands } from '../types.js'\nimport { minMax } from '../utilities/minMax.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n setNodeSelection: {\n /**\n * Creates a NodeSelection.\n * @param position - Position of the node.\n * @example editor.commands.setNodeSelection(10)\n */\n setNodeSelection: (position: number) => ReturnType\n }\n }\n}\n\nexport const setNodeSelection: RawCommands['setNodeSelection'] = position => ({ tr, dispatch }) => {\n if (dispatch) {\n const { doc } = tr\n const from = minMax(position, 0, doc.content.size)\n const selection = NodeSelection.create(doc, from)\n\n tr.setSelection(selection)\n }\n\n return true\n}\n","import { TextSelection } from '@tiptap/pm/state'\n\nimport { Range, RawCommands } from '../types.js'\nimport { minMax } from '../utilities/minMax.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n setTextSelection: {\n /**\n * Creates a TextSelection.\n * @param position The position of the selection.\n * @example editor.commands.setTextSelection(10)\n */\n setTextSelection: (position: number | Range) => ReturnType\n }\n }\n}\n\nexport const setTextSelection: RawCommands['setTextSelection'] = position => ({ tr, dispatch }) => {\n if (dispatch) {\n const { doc } = tr\n const { from, to } = typeof position === 'number' ? { from: position, to: position } : position\n const minPos = TextSelection.atStart(doc).from\n const maxPos = TextSelection.atEnd(doc).to\n const resolvedFrom = minMax(from, minPos, maxPos)\n const resolvedEnd = minMax(to, minPos, maxPos)\n const selection = TextSelection.create(doc, resolvedFrom, resolvedEnd)\n\n tr.setSelection(selection)\n }\n\n return true\n}\n","import { NodeType } from '@tiptap/pm/model'\nimport { sinkListItem as originalSinkListItem } from '@tiptap/pm/schema-list'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n sinkListItem: {\n /**\n * Sink the list item down into an inner list.\n * @param typeOrName The type or name of the node.\n * @example editor.commands.sinkListItem('listItem')\n */\n sinkListItem: (typeOrName: string | NodeType) => ReturnType\n }\n }\n}\n\nexport const sinkListItem: RawCommands['sinkListItem'] = typeOrName => ({ state, dispatch }) => {\n const type = getNodeType(typeOrName, state.schema)\n\n return originalSinkListItem(type)(state, dispatch)\n}\n","import { EditorState, NodeSelection, TextSelection } from '@tiptap/pm/state'\nimport { canSplit } from '@tiptap/pm/transform'\n\nimport { defaultBlockAt } from '../helpers/defaultBlockAt.js'\nimport { getSplittedAttributes } from '../helpers/getSplittedAttributes.js'\nimport { RawCommands } from '../types.js'\n\nfunction ensureMarks(state: EditorState, splittableMarks?: string[]) {\n const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks())\n\n if (marks) {\n const filteredMarks = marks.filter(mark => splittableMarks?.includes(mark.type.name))\n\n state.tr.ensureMarks(filteredMarks)\n }\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n splitBlock: {\n /**\n * Forks a new node from an existing node.\n * @param options.keepMarks Keep marks from the previous node.\n * @example editor.commands.splitBlock()\n * @example editor.commands.splitBlock({ keepMarks: true })\n */\n splitBlock: (options?: { keepMarks?: boolean }) => ReturnType\n }\n }\n}\n\nexport const splitBlock: RawCommands['splitBlock'] = ({ keepMarks = true } = {}) => ({\n tr, state, dispatch, editor,\n}) => {\n const { selection, doc } = tr\n const { $from, $to } = selection\n const extensionAttributes = editor.extensionManager.attributes\n const newAttributes = getSplittedAttributes(\n extensionAttributes,\n $from.node().type.name,\n $from.node().attrs,\n )\n\n if (selection instanceof NodeSelection && selection.node.isBlock) {\n if (!$from.parentOffset || !canSplit(doc, $from.pos)) {\n return false\n }\n\n if (dispatch) {\n if (keepMarks) {\n ensureMarks(state, editor.extensionManager.splittableMarks)\n }\n\n tr.split($from.pos).scrollIntoView()\n }\n\n return true\n }\n\n if (!$from.parent.isBlock) {\n return false\n }\n\n const atEnd = $to.parentOffset === $to.parent.content.size\n\n const deflt = $from.depth === 0\n ? undefined\n : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)))\n\n let types = atEnd && deflt\n ? [\n {\n type: deflt,\n attrs: newAttributes,\n },\n ]\n : undefined\n\n let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types)\n\n if (\n !types\n && !can\n && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : undefined)\n ) {\n can = true\n types = deflt\n ? [\n {\n type: deflt,\n attrs: newAttributes,\n },\n ]\n : undefined\n }\n\n if (dispatch) {\n if (can) {\n if (selection instanceof TextSelection) {\n tr.deleteSelection()\n }\n\n tr.split(tr.mapping.map($from.pos), 1, types)\n\n if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {\n const first = tr.mapping.map($from.before())\n const $first = tr.doc.resolve(first)\n\n if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) {\n tr.setNodeMarkup(tr.mapping.map($from.before()), deflt)\n }\n }\n }\n\n if (keepMarks) {\n ensureMarks(state, editor.extensionManager.splittableMarks)\n }\n\n tr.scrollIntoView()\n }\n\n return can\n}\n","import {\n Fragment, Node as ProseMirrorNode, NodeType, Slice,\n} from '@tiptap/pm/model'\nimport { TextSelection } from '@tiptap/pm/state'\nimport { canSplit } from '@tiptap/pm/transform'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { getSplittedAttributes } from '../helpers/getSplittedAttributes.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n splitListItem: {\n /**\n * Splits one list item into two list items.\n * @param typeOrName The type or name of the node.\n * @param overrideAttrs The attributes to ensure on the new node.\n * @example editor.commands.splitListItem('listItem')\n */\n splitListItem: (typeOrName: string | NodeType, overrideAttrs?: Record<string, any>) => ReturnType\n }\n }\n}\n\nexport const splitListItem: RawCommands['splitListItem'] = (typeOrName, overrideAttrs = {}) => ({\n tr, state, dispatch, editor,\n}) => {\n const type = getNodeType(typeOrName, state.schema)\n const { $from, $to } = state.selection\n\n // @ts-ignore\n // eslint-disable-next-line\n const node: ProseMirrorNode = state.selection.node\n\n if ((node && node.isBlock) || $from.depth < 2 || !$from.sameParent($to)) {\n return false\n }\n\n const grandParent = $from.node(-1)\n\n if (grandParent.type !== type) {\n return false\n }\n\n const extensionAttributes = editor.extensionManager.attributes\n\n if ($from.parent.content.size === 0 && $from.node(-1).childCount === $from.indexAfter(-1)) {\n // In an empty block. If this is a nested list, the wrapping\n // list item should be split. Otherwise, bail out and let next\n // command handle lifting.\n if (\n $from.depth === 2\n || $from.node(-3).type !== type\n || $from.index(-2) !== $from.node(-2).childCount - 1\n ) {\n return false\n }\n\n if (dispatch) {\n let wrap = Fragment.empty\n // eslint-disable-next-line\n const depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3\n\n // Build a fragment containing empty versions of the structure\n // from the outer list item to the parent node of the cursor\n for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d -= 1) {\n wrap = Fragment.from($from.node(d).copy(wrap))\n }\n\n // eslint-disable-next-line\n const depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3\n\n // Add a second list item with an empty default start node\n const newNextTypeAttributes = {\n ...getSplittedAttributes(\n extensionAttributes,\n $from.node().type.name,\n $from.node().attrs,\n ),\n ...overrideAttrs,\n }\n const nextType = type.contentMatch.defaultType?.createAndFill(newNextTypeAttributes) || undefined\n\n wrap = wrap.append(Fragment.from(type.createAndFill(null, nextType) || undefined))\n\n const start = $from.before($from.depth - (depthBefore - 1))\n\n tr.replace(start, $from.after(-depthAfter), new Slice(wrap, 4 - depthBefore, 0))\n\n let sel = -1\n\n tr.doc.nodesBetween(start, tr.doc.content.size, (n, pos) => {\n if (sel > -1) {\n return false\n }\n\n if (n.isTextblock && n.content.size === 0) {\n sel = pos + 1\n }\n })\n\n if (sel > -1) {\n tr.setSelection(TextSelection.near(tr.doc.resolve(sel)))\n }\n\n tr.scrollIntoView()\n }\n\n return true\n }\n\n const nextType = $to.pos === $from.end() ? grandParent.contentMatchAt(0).defaultType : null\n\n const newTypeAttributes = {\n ...getSplittedAttributes(\n extensionAttributes,\n grandParent.type.name,\n grandParent.attrs,\n ),\n ...overrideAttrs,\n }\n const newNextTypeAttributes = {\n ...getSplittedAttributes(\n extensionAttributes,\n $from.node().type.name,\n $from.node().attrs,\n ),\n ...overrideAttrs,\n }\n\n tr.delete($from.pos, $to.pos)\n\n const types = nextType\n ? [\n { type, attrs: newTypeAttributes },\n { type: nextType, attrs: newNextTypeAttributes },\n ]\n : [{ type, attrs: newTypeAttributes }]\n\n if (!canSplit(tr.doc, $from.pos, 2)) {\n return false\n }\n\n if (dispatch) {\n const { selection, storedMarks } = state\n const { splittableMarks } = editor.extensionManager\n const marks = storedMarks || (selection.$to.parentOffset && selection.$from.marks())\n\n tr.split($from.pos, 2, types).scrollIntoView()\n\n if (!marks || !dispatch) {\n return true\n }\n\n const filteredMarks = marks.filter(mark => splittableMarks.includes(mark.type.name))\n\n tr.ensureMarks(filteredMarks)\n }\n\n return true\n}\n","import { NodeType } from '@tiptap/pm/model'\nimport { Transaction } from '@tiptap/pm/state'\nimport { canJoin } from '@tiptap/pm/transform'\n\nimport { findParentNode } from '../helpers/findParentNode.js'\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { isList } from '../helpers/isList.js'\nimport { RawCommands } from '../types.js'\n\nconst joinListBackwards = (tr: Transaction, listType: NodeType): boolean => {\n const list = findParentNode(node => node.type === listType)(tr.selection)\n\n if (!list) {\n return true\n }\n\n const before = tr.doc.resolve(Math.max(0, list.pos - 1)).before(list.depth)\n\n if (before === undefined) {\n return true\n }\n\n const nodeBefore = tr.doc.nodeAt(before)\n const canJoinBackwards = list.node.type === nodeBefore?.type && canJoin(tr.doc, list.pos)\n\n if (!canJoinBackwards) {\n return true\n }\n\n tr.join(list.pos)\n\n return true\n}\n\nconst joinListForwards = (tr: Transaction, listType: NodeType): boolean => {\n const list = findParentNode(node => node.type === listType)(tr.selection)\n\n if (!list) {\n return true\n }\n\n const after = tr.doc.resolve(list.start).after(list.depth)\n\n if (after === undefined) {\n return true\n }\n\n const nodeAfter = tr.doc.nodeAt(after)\n const canJoinForwards = list.node.type === nodeAfter?.type && canJoin(tr.doc, after)\n\n if (!canJoinForwards) {\n return true\n }\n\n tr.join(after)\n\n return true\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n toggleList: {\n /**\n * Toggle between different list types.\n * @param listTypeOrName The type or name of the list.\n * @param itemTypeOrName The type or name of the list item.\n * @param keepMarks Keep marks when toggling.\n * @param attributes Attributes for the new list.\n * @example editor.commands.toggleList('bulletList', 'listItem')\n */\n toggleList: (listTypeOrName: string | NodeType, itemTypeOrName: string | NodeType, keepMarks?: boolean, attributes?: Record<string, any>) => ReturnType;\n }\n }\n}\n\nexport const toggleList: RawCommands['toggleList'] = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({\n editor, tr, state, dispatch, chain, commands, can,\n}) => {\n const { extensions, splittableMarks } = editor.extensionManager\n const listType = getNodeType(listTypeOrName, state.schema)\n const itemType = getNodeType(itemTypeOrName, state.schema)\n const { selection, storedMarks } = state\n const { $from, $to } = selection\n const range = $from.blockRange($to)\n\n const marks = storedMarks || (selection.$to.parentOffset && selection.$from.marks())\n\n if (!range) {\n return false\n }\n\n const parentList = findParentNode(node => isList(node.type.name, extensions))(selection)\n\n if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {\n // remove list\n if (parentList.node.type === listType) {\n return commands.liftListItem(itemType)\n }\n\n // change list type\n if (\n isList(parentList.node.type.name, extensions)\n && listType.validContent(parentList.node.content)\n && dispatch\n ) {\n return chain()\n .command(() => {\n tr.setNodeMarkup(parentList.pos, listType)\n\n return true\n })\n .command(() => joinListBackwards(tr, listType))\n .command(() => joinListForwards(tr, listType))\n .run()\n }\n }\n if (!keepMarks || !marks || !dispatch) {\n\n return chain()\n // try to convert node to default node if needed\n .command(() => {\n const canWrapInList = can().wrapInList(listType, attributes)\n\n if (canWrapInList) {\n return true\n }\n\n return commands.clearNodes()\n })\n .wrapInList(listType, attributes)\n .command(() => joinListBackwards(tr, listType))\n .command(() => joinListForwards(tr, listType))\n .run()\n }\n\n return (\n chain()\n // try to convert node to default node if needed\n .command(() => {\n const canWrapInList = can().wrapInList(listType, attributes)\n\n const filteredMarks = marks.filter(mark => splittableMarks.includes(mark.type.name))\n\n tr.ensureMarks(filteredMarks)\n\n if (canWrapInList) {\n return true\n }\n\n return commands.clearNodes()\n })\n .wrapInList(listType, attributes)\n .command(() => joinListBackwards(tr, listType))\n .command(() => joinListForwards(tr, listType))\n .run()\n )\n}\n","import { MarkType } from '@tiptap/pm/model'\n\nimport { getMarkType } from '../helpers/getMarkType.js'\nimport { isMarkActive } from '../helpers/isMarkActive.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n toggleMark: {\n /**\n * Toggle a mark on and off.\n * @param typeOrName The mark type or name.\n * @param attributes The attributes of the mark.\n * @param options.extendEmptyMarkRange Removes the mark even across the current selection. Defaults to `false`.\n * @example editor.commands.toggleMark('bold')\n */\n toggleMark: (\n /**\n * The mark type or name.\n */\n typeOrName: string | MarkType,\n\n /**\n * The attributes of the mark.\n */\n attributes?: Record<string, any>,\n\n options?: {\n /**\n * Removes the mark even across the current selection. Defaults to `false`.\n */\n extendEmptyMarkRange?: boolean\n },\n ) => ReturnType\n }\n }\n}\n\nexport const toggleMark: RawCommands['toggleMark'] = (typeOrName, attributes = {}, options = {}) => ({ state, commands }) => {\n const { extendEmptyMarkRange = false } = options\n const type = getMarkType(typeOrName, state.schema)\n const isActive = isMarkActive(state, type, attributes)\n\n if (isActive) {\n return commands.unsetMark(type, { extendEmptyMarkRange })\n }\n\n return commands.setMark(type, attributes)\n}\n","import { NodeType } from '@tiptap/pm/model'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { isNodeActive } from '../helpers/isNodeActive.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n toggleNode: {\n /**\n * Toggle a node with another node.\n * @param typeOrName The type or name of the node.\n * @param toggleTypeOrName The type or name of the node to toggle.\n * @param attributes The attributes of the node.\n * @example editor.commands.toggleNode('heading', 'paragraph')\n */\n toggleNode: (\n typeOrName: string | NodeType,\n toggleTypeOrName: string | NodeType,\n attributes?: Record<string, any>,\n ) => ReturnType\n }\n }\n}\n\nexport const toggleNode: RawCommands['toggleNode'] = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state, commands }) => {\n const type = getNodeType(typeOrName, state.schema)\n const toggleType = getNodeType(toggleTypeOrName, state.schema)\n const isActive = isNodeActive(state, type, attributes)\n\n let attributesToCopy: Record<string, any> | undefined\n\n if (state.selection.$anchor.sameParent(state.selection.$head)) {\n // only copy attributes if the selection is pointing to a node of the same type\n attributesToCopy = state.selection.$anchor.parent.attrs\n }\n\n if (isActive) {\n return commands.setNode(toggleType, attributesToCopy)\n }\n\n // If the node is not active, we want to set the new node type with the given attributes\n // Copying over the attributes from the current node if the selection is pointing to a node of the same type\n return commands.setNode(type, { ...attributesToCopy, ...attributes })\n}\n","import { NodeType } from '@tiptap/pm/model'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { isNodeActive } from '../helpers/isNodeActive.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n toggleWrap: {\n /**\n * Wraps nodes in another node, or removes an existing wrap.\n * @param typeOrName The type or name of the node.\n * @param attributes The attributes of the node.\n * @example editor.commands.toggleWrap('blockquote')\n */\n toggleWrap: (typeOrName: string | NodeType, attributes?: Record<string, any>) => ReturnType\n }\n }\n}\n\nexport const toggleWrap: RawCommands['toggleWrap'] = (typeOrName, attributes = {}) => ({ state, commands }) => {\n const type = getNodeType(typeOrName, state.schema)\n const isActive = isNodeActive(state, type, attributes)\n\n if (isActive) {\n return commands.lift(type)\n }\n\n return commands.wrapIn(type, attributes)\n}\n","import { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n undoInputRule: {\n /**\n * Undo an input rule.\n * @example editor.commands.undoInputRule()\n */\n undoInputRule: () => ReturnType,\n }\n }\n}\n\nexport const undoInputRule: RawCommands['undoInputRule'] = () => ({ state, dispatch }) => {\n const plugins = state.plugins\n\n for (let i = 0; i < plugins.length; i += 1) {\n const plugin = plugins[i]\n let undoable\n\n // @ts-ignore\n // eslint-disable-next-line\n if (plugin.spec.isInputRules && (undoable = plugin.getState(state))) {\n if (dispatch) {\n const tr = state.tr\n const toUndo = undoable.transform\n\n for (let j = toUndo.steps.length - 1; j >= 0; j -= 1) {\n tr.step(toUndo.steps[j].invert(toUndo.docs[j]))\n }\n\n if (undoable.text) {\n const marks = tr.doc.resolve(undoable.from).marks()\n\n tr.replaceWith(undoable.from, undoable.to, state.schema.text(undoable.text, marks))\n } else {\n tr.delete(undoable.from, undoable.to)\n }\n }\n\n return true\n }\n }\n\n return false\n}\n","import { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n unsetAllMarks: {\n /**\n * Remove all marks in the current selection.\n * @example editor.commands.unsetAllMarks()\n */\n unsetAllMarks: () => ReturnType,\n }\n }\n}\n\nexport const unsetAllMarks: RawCommands['unsetAllMarks'] = () => ({ tr, dispatch }) => {\n const { selection } = tr\n const { empty, ranges } = selection\n\n if (empty) {\n return true\n }\n\n if (dispatch) {\n ranges.forEach(range => {\n tr.removeMark(range.$from.pos, range.$to.pos)\n })\n }\n\n return true\n}\n","import { MarkType } from '@tiptap/pm/model'\n\nimport { getMarkRange } from '../helpers/getMarkRange.js'\nimport { getMarkType } from '../helpers/getMarkType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n unsetMark: {\n /**\n * Remove all marks in the current selection.\n * @param typeOrName The mark type or name.\n * @param options.extendEmptyMarkRange Removes the mark even across the current selection. Defaults to `false`.\n * @example editor.commands.unsetMark('bold')\n */\n unsetMark: (\n /**\n * The mark type or name.\n */\n typeOrName: string | MarkType,\n\n options?: {\n /**\n * Removes the mark even across the current selection. Defaults to `false`.\n */\n extendEmptyMarkRange?: boolean\n },\n ) => ReturnType\n }\n }\n}\n\nexport const unsetMark: RawCommands['unsetMark'] = (typeOrName, options = {}) => ({ tr, state, dispatch }) => {\n const { extendEmptyMarkRange = false } = options\n const { selection } = tr\n const type = getMarkType(typeOrName, state.schema)\n const { $from, empty, ranges } = selection\n\n if (!dispatch) {\n return true\n }\n\n if (empty && extendEmptyMarkRange) {\n let { from, to } = selection\n const attrs = $from.marks().find(mark => mark.type === type)?.attrs\n const range = getMarkRange($from, type, attrs)\n\n if (range) {\n from = range.from\n to = range.to\n }\n\n tr.removeMark(from, to, type)\n } else {\n ranges.forEach(range => {\n tr.removeMark(range.$from.pos, range.$to.pos, type)\n })\n }\n\n tr.removeStoredMark(type)\n\n return true\n}\n","import {\n Mark, MarkType, Node, NodeType,\n} from '@tiptap/pm/model'\nimport { SelectionRange } from '@tiptap/pm/state'\n\nimport { getMarkType } from '../helpers/getMarkType.js'\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { getSchemaTypeNameByName } from '../helpers/getSchemaTypeNameByName.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n updateAttributes: {\n /**\n * Update attributes of a node or mark.\n * @param typeOrName The type or name of the node or mark.\n * @param attributes The attributes of the node or mark.\n * @example editor.commands.updateAttributes('mention', { userId: \"2\" })\n */\n updateAttributes: (\n /**\n * The type or name of the node or mark.\n */\n typeOrName: string | NodeType | MarkType,\n\n /**\n * The attributes of the node or mark.\n */\n attributes: Record<string, any>,\n ) => ReturnType\n }\n }\n}\n\nexport const updateAttributes: RawCommands['updateAttributes'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {\n\n let nodeType: NodeType | null = null\n let markType: MarkType | null = null\n\n const schemaType = getSchemaTypeNameByName(\n typeof typeOrName === 'string' ? typeOrName : typeOrName.name,\n state.schema,\n )\n\n if (!schemaType) {\n return false\n }\n\n if (schemaType === 'node') {\n nodeType = getNodeType(typeOrName as NodeType, state.schema)\n }\n\n if (schemaType === 'mark') {\n markType = getMarkType(typeOrName as MarkType, state.schema)\n }\n\n if (dispatch) {\n tr.selection.ranges.forEach((range: SelectionRange) => {\n\n const from = range.$from.pos\n const to = range.$to.pos\n\n let lastPos: number | undefined\n let lastNode: Node | undefined\n let trimmedFrom: number\n let trimmedTo: number\n\n if (tr.selection.empty) {\n state.doc.nodesBetween(from, to, (node: Node, pos: number) => {\n\n if (nodeType && nodeType === node.type) {\n trimmedFrom = Math.max(pos, from)\n trimmedTo = Math.min(pos + node.nodeSize, to)\n lastPos = pos\n lastNode = node\n }\n })\n } else {\n state.doc.nodesBetween(from, to, (node: Node, pos: number) => {\n\n if (pos < from && nodeType && nodeType === node.type) {\n trimmedFrom = Math.max(pos, from)\n trimmedTo = Math.min(pos + node.nodeSize, to)\n lastPos = pos\n lastNode = node\n }\n\n if (pos >= from && pos <= to) {\n\n if (nodeType && nodeType === node.type) {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n ...attributes,\n })\n }\n\n if (markType && node.marks.length) {\n node.marks.forEach((mark: Mark) => {\n\n if (markType === mark.type) {\n const trimmedFrom2 = Math.max(pos, from)\n const trimmedTo2 = Math.min(pos + node.nodeSize, to)\n\n tr.addMark(\n trimmedFrom2,\n trimmedTo2,\n markType.create({\n ...mark.attrs,\n ...attributes,\n }),\n )\n }\n })\n }\n }\n })\n }\n\n if (lastNode) {\n\n if (lastPos !== undefined) {\n tr.setNodeMarkup(lastPos, undefined, {\n ...lastNode.attrs,\n ...attributes,\n })\n }\n\n if (markType && lastNode.marks.length) {\n lastNode.marks.forEach((mark: Mark) => {\n\n if (markType === mark.type) {\n tr.addMark(\n trimmedFrom,\n trimmedTo,\n markType.create({\n ...mark.attrs,\n ...attributes,\n }),\n )\n }\n })\n }\n }\n })\n }\n\n return true\n}\n","import { wrapIn as originalWrapIn } from '@tiptap/pm/commands'\nimport { NodeType } from '@tiptap/pm/model'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n wrapIn: {\n /**\n * Wraps nodes in another node.\n * @param typeOrName The type or name of the node.\n * @param attributes The attributes of the node.\n * @example editor.commands.wrapIn('blockquote')\n */\n wrapIn: (typeOrName: string | NodeType, attributes?: Record<string, any>) => ReturnType\n }\n }\n}\n\nexport const wrapIn: RawCommands['wrapIn'] = (typeOrName, attributes = {}) => ({ state, dispatch }) => {\n const type = getNodeType(typeOrName, state.schema)\n\n return originalWrapIn(type, attributes)(state, dispatch)\n}\n","import { NodeType } from '@tiptap/pm/model'\nimport { wrapInList as originalWrapInList } from '@tiptap/pm/schema-list'\n\nimport { getNodeType } from '../helpers/getNodeType.js'\nimport { RawCommands } from '../types.js'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n wrapInList: {\n /**\n * Wrap a node in a list.\n * @param typeOrName The type or name of the node.\n * @param attributes The attributes of the node.\n * @example editor.commands.wrapInList('bulletList')\n */\n wrapInList: (typeOrName: string | NodeType, attributes?: Record<string, any>) => ReturnType\n }\n }\n}\n\nexport const wrapInList: RawCommands['wrapInList'] = (typeOrName, attributes = {}) => ({ state, dispatch }) => {\n const type = getNodeType(typeOrName, state.schema)\n\n return originalWrapInList(type, attributes)(state, dispatch)\n}\n","import * as commands from '../commands/index.js'\nimport { Extension } from '../Extension.js'\n\nexport * from '../commands/index.js'\n\nexport const Commands = Extension.create({\n name: 'commands',\n\n addCommands() {\n return {\n ...commands,\n }\n },\n})\n","import { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { Extension } from '../Extension.js'\n\nexport const Drop = Extension.create({\n name: 'drop',\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('tiptapDrop'),\n\n props: {\n handleDrop: (_, e, slice, moved) => {\n this.editor.emit('drop', {\n editor: this.editor,\n event: e,\n slice,\n moved,\n })\n },\n },\n }),\n ]\n },\n})\n","import { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { Extension } from '../Extension.js'\n\nexport const Editable = Extension.create({\n name: 'editable',\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('editable'),\n props: {\n editable: () => this.editor.options.editable,\n },\n }),\n ]\n },\n})\n","import { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { Extension } from '../Extension.js'\n\nexport const focusEventsPluginKey = new PluginKey('focusEvents')\n\nexport const FocusEvents = Extension.create({\n name: 'focusEvents',\n\n addProseMirrorPlugins() {\n const { editor } = this\n\n return [\n new Plugin({\n key: focusEventsPluginKey,\n props: {\n handleDOMEvents: {\n focus: (view, event: Event) => {\n editor.isFocused = true\n\n const transaction = editor.state.tr\n .setMeta('focus', { event })\n .setMeta('addToHistory', false)\n\n view.dispatch(transaction)\n\n return false\n },\n blur: (view, event: Event) => {\n editor.isFocused = false\n\n const transaction = editor.state.tr\n .setMeta('blur', { event })\n .setMeta('addToHistory', false)\n\n view.dispatch(transaction)\n\n return false\n },\n },\n },\n }),\n ]\n },\n})\n","import { Plugin, PluginKey, Selection } from '@tiptap/pm/state'\n\nimport { CommandManager } from '../CommandManager.js'\nimport { Extension } from '../Extension.js'\nimport { createChainableState } from '../helpers/createChainableState.js'\nimport { isNodeEmpty } from '../helpers/isNodeEmpty.js'\nimport { isiOS } from '../utilities/isiOS.js'\nimport { isMacOS } from '../utilities/isMacOS.js'\n\nexport const Keymap = Extension.create({\n name: 'keymap',\n\n addKeyboardShortcuts() {\n const handleBackspace = () => this.editor.commands.first(({ commands }) => [\n () => commands.undoInputRule(),\n\n // maybe convert first text block node to default node\n () => commands.command(({ tr }) => {\n const { selection, doc } = tr\n const { empty, $anchor } = selection\n const { pos, parent } = $anchor\n const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor\n const parentIsIsolating = $parentPos.parent.type.spec.isolating\n\n const parentPos = $anchor.pos - $anchor.parentOffset\n\n const isAtStart = (parentIsIsolating && $parentPos.parent.childCount === 1)\n ? parentPos === $anchor.pos\n : Selection.atStart(doc).from === pos\n\n if (\n !empty\n || !parent.type.isTextblock\n || parent.textContent.length\n || !isAtStart\n || (isAtStart && $anchor.parent.type.name === 'paragraph') // prevent clearNodes when no nodes to clear, otherwise history stack is appended\n ) {\n return false\n }\n\n return commands.clearNodes()\n }),\n\n () => commands.deleteSelection(),\n () => commands.joinBackward(),\n () => commands.selectNodeBackward(),\n ])\n\n const handleDelete = () => this.editor.commands.first(({ commands }) => [\n () => commands.deleteSelection(),\n () => commands.deleteCurrentNode(),\n () => commands.joinForward(),\n () => commands.selectNodeForward(),\n ])\n\n const handleEnter = () => this.editor.commands.first(({ commands }) => [\n () => commands.newlineInCode(),\n () => commands.createParagraphNear(),\n () => commands.liftEmptyBlock(),\n () => commands.splitBlock(),\n ])\n\n const baseKeymap = {\n Enter: handleEnter,\n 'Mod-Enter': () => this.editor.commands.exitCode(),\n Backspace: handleBackspace,\n 'Mod-Backspace': handleBackspace,\n 'Shift-Backspace': handleBackspace,\n Delete: handleDelete,\n 'Mod-Delete': handleDelete,\n 'Mod-a': () => this.editor.commands.selectAll(),\n }\n\n const pcKeymap = {\n ...baseKeymap,\n }\n\n const macKeymap = {\n ...baseKeymap,\n 'Ctrl-h': handleBackspace,\n 'Alt-Backspace': handleBackspace,\n 'Ctrl-d': handleDelete,\n 'Ctrl-Alt-Backspace': handleDelete,\n 'Alt-Delete': handleDelete,\n 'Alt-d': handleDelete,\n 'Ctrl-a': () => this.editor.commands.selectTextblockStart(),\n 'Ctrl-e': () => this.editor.commands.selectTextblockEnd(),\n }\n\n if (isiOS() || isMacOS()) {\n return macKeymap\n }\n\n return pcKeymap\n },\n\n addProseMirrorPlugins() {\n return [\n // With this plugin we check if the whole document was selected and deleted.\n // In this case we will additionally call `clearNodes()` to convert e.g. a heading\n // to a paragraph if necessary.\n // This is an alternative to ProseMirror's `AllSelection`, which doesn’t work well\n // with many other commands.\n new Plugin({\n key: new PluginKey('clearDocument'),\n appendTransaction: (transactions, oldState, newState) => {\n if (transactions.some(tr => tr.getMeta('composition'))) {\n return\n }\n\n const docChanges = transactions.some(transaction => transaction.docChanged)\n && !oldState.doc.eq(newState.doc)\n\n const ignoreTr = transactions.some(transaction => transaction.getMeta('preventClearDocument'))\n\n if (!docChanges || ignoreTr) {\n return\n }\n\n const { empty, from, to } = oldState.selection\n const allFrom = Selection.atStart(oldState.doc).from\n const allEnd = Selection.atEnd(oldState.doc).to\n const allWasSelected = from === allFrom && to === allEnd\n\n if (empty || !allWasSelected) {\n return\n }\n\n const isEmpty = isNodeEmpty(newState.doc)\n\n if (!isEmpty) {\n return\n }\n\n const tr = newState.tr\n const state = createChainableState({\n state: newState,\n transaction: tr,\n })\n const { commands } = new CommandManager({\n editor: this.editor,\n state,\n })\n\n commands.clearNodes()\n\n if (!tr.steps.length) {\n return\n }\n\n return tr\n },\n }),\n ]\n },\n})\n","import { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { Extension } from '../Extension.js'\n\nexport const Paste = Extension.create({\n name: 'paste',\n\n addProseMirrorPlugins() {\n\n return [\n new Plugin({\n key: new PluginKey('tiptapPaste'),\n\n props: {\n handlePaste: (_view, e, slice) => {\n this.editor.emit('paste', {\n editor: this.editor,\n event: e,\n slice,\n })\n },\n },\n }),\n ]\n },\n})\n","import { Plugin, PluginKey } from '@tiptap/pm/state'\n\nimport { Extension } from '../Extension.js'\n\nexport const Tabindex = Extension.create({\n name: 'tabindex',\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('tabindex'),\n props: {\n attributes: (): { [name: string]: string; } => (this.editor.isEditable ? { tabindex: '0' } : {}),\n },\n }),\n ]\n },\n})\n","import {\n Fragment, Node, ResolvedPos,\n} from '@tiptap/pm/model'\n\nimport { Editor } from './Editor.js'\nimport { Content, Range } from './types.js'\n\nexport class NodePos {\n private resolvedPos: ResolvedPos\n\n private isBlock: boolean\n\n private editor: Editor\n\n private get name(): string {\n return this.node.type.name\n }\n\n constructor(pos: ResolvedPos, editor: Editor, isBlock = false, node: Node | null = null) {\n this.isBlock = isBlock\n this.resolvedPos = pos\n this.editor = editor\n this.currentNode = node\n }\n\n private currentNode: Node | null = null\n\n get node(): Node {\n return this.currentNode || this.resolvedPos.node()\n }\n\n get element(): HTMLElement {\n return this.editor.view.domAtPos(this.pos).node as HTMLElement\n }\n\n public actualDepth: number | null = null\n\n get depth(): number {\n return this.actualDepth ?? this.resolvedPos.depth\n }\n\n get pos(): number {\n return this.resolvedPos.pos\n }\n\n get content(): Fragment {\n return this.node.content\n }\n\n set content(content: Content) {\n let from = this.from\n let to = this.to\n\n if (this.isBlock) {\n if (this.content.size === 0) {\n console.error(`You can’t set content on a block node. Tried to set content on ${this.name} at ${this.pos}`)\n return\n }\n\n from = this.from + 1\n to = this.to - 1\n }\n\n this.editor.commands.insertContentAt({ from, to }, content)\n }\n\n get attributes(): { [key: string]: any } {\n return this.node.attrs\n }\n\n get textContent(): string {\n return this.node.textContent\n }\n\n get size(): number {\n return this.node.nodeSize\n }\n\n get from(): number {\n if (this.isBlock) {\n return this.pos\n }\n\n return this.resolvedPos.start(this.resolvedPos.depth)\n }\n\n get range(): Range {\n return {\n from: this.from,\n to: this.to,\n }\n }\n\n get to(): number {\n if (this.isBlock) {\n return this.pos + this.size\n }\n\n return this.resolvedPos.end(this.resolvedPos.depth) + (this.node.isText ? 0 : 1)\n }\n\n get parent(): NodePos | null {\n if (this.depth === 0) {\n return null\n }\n\n const parentPos = this.resolvedPos.start(this.resolvedPos.depth - 1)\n const $pos = this.resolvedPos.doc.resolve(parentPos)\n\n return new NodePos($pos, this.editor)\n }\n\n get before(): NodePos | null {\n let $pos = this.resolvedPos.doc.resolve(this.from - (this.isBlock ? 1 : 2))\n\n if ($pos.depth !== this.depth) {\n $pos = this.resolvedPos.doc.resolve(this.from - 3)\n }\n\n return new NodePos($pos, this.editor)\n }\n\n get after(): NodePos | null {\n let $pos = this.resolvedPos.doc.resolve(this.to + (this.isBlock ? 2 : 1))\n\n if ($pos.depth !== this.depth) {\n $pos = this.resolvedPos.doc.resolve(this.to + 3)\n }\n\n return new NodePos($pos, this.editor)\n }\n\n get children(): NodePos[] {\n const children: NodePos[] = []\n\n this.node.content.forEach((node, offset) => {\n const isBlock = node.isBlock && !node.isTextblock\n const isNonTextAtom = node.isAtom && !node.isText\n\n const targetPos = this.pos + offset + (isNonTextAtom ? 0 : 1)\n\n // Check if targetPos is within valid document range\n if (targetPos < 0 || targetPos > this.resolvedPos.doc.nodeSize - 2) {\n return\n }\n\n const $pos = this.resolvedPos.doc.resolve(targetPos)\n\n if (!isBlock && $pos.depth <= this.depth) {\n return\n }\n\n const childNodePos = new NodePos($pos, this.editor, isBlock, isBlock ? node : null)\n\n if (isBlock) {\n childNodePos.actualDepth = this.depth + 1\n }\n\n children.push(new NodePos($pos, this.editor, isBlock, isBlock ? node : null))\n })\n\n return children\n }\n\n get firstChild(): NodePos | null {\n return this.children[0] || null\n }\n\n get lastChild(): NodePos | null {\n const children = this.children\n\n return children[children.length - 1] || null\n }\n\n closest(selector: string, attributes: { [key: string]: any } = {}): NodePos | null {\n let node: NodePos | null = null\n let currentNode = this.parent\n\n while (currentNode && !node) {\n if (currentNode.node.type.name === selector) {\n if (Object.keys(attributes).length > 0) {\n const nodeAttributes = currentNode.node.attrs\n const attrKeys = Object.keys(attributes)\n\n for (let index = 0; index < attrKeys.length; index += 1) {\n const key = attrKeys[index]\n\n if (nodeAttributes[key] !== attributes[key]) {\n break\n }\n }\n } else {\n node = currentNode\n }\n }\n\n currentNode = currentNode.parent\n }\n\n return node\n }\n\n querySelector(selector: string, attributes: { [key: string]: any } = {}): NodePos | null {\n return this.querySelectorAll(selector, attributes, true)[0] || null\n }\n\n querySelectorAll(selector: string, attributes: { [key: string]: any } = {}, firstItemOnly = false): NodePos[] {\n let nodes: NodePos[] = []\n\n if (!this.children || this.children.length === 0) {\n return nodes\n }\n const attrKeys = Object.keys(attributes)\n\n /**\n * Finds all children recursively that match the selector and attributes\n * If firstItemOnly is true, it will return the first item found\n */\n this.children.forEach(childPos => {\n // If we already found a node and we only want the first item, we dont need to keep going\n if (firstItemOnly && nodes.length > 0) {\n return\n }\n\n if (childPos.node.type.name === selector) {\n const doesAllAttributesMatch = attrKeys.every(key => attributes[key] === childPos.node.attrs[key])\n\n if (doesAllAttributesMatch) {\n nodes.push(childPos)\n }\n }\n\n // If we already found a node and we only want the first item, we can stop here and skip the recursion\n if (firstItemOnly && nodes.length > 0) {\n return\n }\n\n nodes = nodes.concat(childPos.querySelectorAll(selector, attributes, firstItemOnly))\n })\n\n return nodes\n }\n\n setAttribute(attributes: { [key: string]: any }) {\n const { tr } = this.editor.state\n\n tr.setNodeMarkup(this.from, undefined, {\n ...this.node.attrs,\n ...attributes,\n })\n\n this.editor.view.dispatch(tr)\n }\n}\n","export const style = `.ProseMirror {\n position: relative;\n}\n\n.ProseMirror {\n word-wrap: break-word;\n white-space: pre-wrap;\n white-space: break-spaces;\n -webkit-font-variant-ligatures: none;\n font-variant-ligatures: none;\n font-feature-settings: \"liga\" 0; /* the above doesn't seem to work in Edge */\n}\n\n.ProseMirror [contenteditable=\"false\"] {\n white-space: normal;\n}\n\n.ProseMirror [contenteditable=\"false\"] [contenteditable=\"true\"] {\n white-space: pre-wrap;\n}\n\n.ProseMirror pre {\n white-space: pre-wrap;\n}\n\nimg.ProseMirror-separator {\n display: inline !important;\n border: none !important;\n margin: 0 !important;\n width: 0 !important;\n height: 0 !important;\n}\n\n.ProseMirror-gapcursor {\n display: none;\n pointer-events: none;\n position: absolute;\n margin: 0;\n}\n\n.ProseMirror-gapcursor:after {\n content: \"\";\n display: block;\n position: absolute;\n top: -2px;\n width: 20px;\n border-top: 1px solid black;\n animation: ProseMirror-cursor-blink 1.1s steps(2, start) infinite;\n}\n\n@keyframes ProseMirror-cursor-blink {\n to {\n visibility: hidden;\n }\n}\n\n.ProseMirror-hideselection *::selection {\n background: transparent;\n}\n\n.ProseMirror-hideselection *::-moz-selection {\n background: transparent;\n}\n\n.ProseMirror-hideselection * {\n caret-color: transparent;\n}\n\n.ProseMirror-focused .ProseMirror-gapcursor {\n display: block;\n}\n\n.tippy-box[data-animation=fade][data-state=hidden] {\n opacity: 0\n}`\n","export function createStyleTag(style: string, nonce?: string, suffix?: string): HTMLStyleElement {\n const tiptapStyleTag = (<HTMLStyleElement>document.querySelector(`style[data-tiptap-style${suffix ? `-${suffix}` : ''}]`))\n\n if (tiptapStyleTag !== null) {\n return tiptapStyleTag\n }\n\n const styleNode = document.createElement('style')\n\n if (nonce) {\n styleNode.setAttribute('nonce', nonce)\n }\n\n styleNode.setAttribute(`data-tiptap-style${suffix ? `-${suffix}` : ''}`, '')\n styleNode.innerHTML = style\n document.getElementsByTagName('head')[0].appendChild(styleNode)\n\n return styleNode\n}\n","/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport {\n MarkType,\n Node as ProseMirrorNode,\n NodeType,\n Schema,\n} from '@tiptap/pm/model'\nimport {\n EditorState, Plugin, PluginKey, Transaction,\n} from '@tiptap/pm/state'\nimport { EditorView } from '@tiptap/pm/view'\n\nimport { CommandManager } from './CommandManager.js'\nimport { EventEmitter } from './EventEmitter.js'\nimport { ExtensionManager } from './ExtensionManager.js'\nimport {\n ClipboardTextSerializer, Commands, Drop, Editable, FocusEvents, Keymap, Paste,\n Tabindex,\n} from './extensions/index.js'\nimport { createDocument } from './helpers/createDocument.js'\nimport { getAttributes } from './helpers/getAttributes.js'\nimport { getHTMLFromFragment } from './helpers/getHTMLFromFragment.js'\nimport { getText } from './helpers/getText.js'\nimport { getTextSerializersFromSchema } from './helpers/getTextSerializersFromSchema.js'\nimport { isActive } from './helpers/isActive.js'\nimport { isNodeEmpty } from './helpers/isNodeEmpty.js'\nimport { resolveFocusPosition } from './helpers/resolveFocusPosition.js'\nimport { NodePos } from './NodePos.js'\nimport { style } from './style.js'\nimport {\n CanCommands,\n ChainedCommands,\n EditorEvents,\n EditorOptions,\n JSONContent,\n SingleCommands,\n TextSerializer,\n} from './types.js'\nimport { createStyleTag } from './utilities/createStyleTag.js'\nimport { isFunction } from './utilities/isFunction.js'\n\nexport * as extensions from './extensions/index.js'\n\n// @ts-ignore\nexport interface TiptapEditorHTMLElement extends HTMLElement {\n editor?: Editor\n}\n\nexport class Editor extends EventEmitter<EditorEvents> {\n private commandManager!: CommandManager\n\n public extensionManager!: ExtensionManager\n\n private css!: HTMLStyleElement\n\n public schema!: Schema\n\n public view!: EditorView\n\n public isFocused = false\n\n /**\n * The editor is considered initialized after the `create` event has been emitted.\n */\n public isInitialized = false\n\n public extensionStorage: Record<string, any> = {}\n\n public options: EditorOptions = {\n element: document.createElement('div'),\n content: '',\n injectCSS: true,\n injectNonce: undefined,\n extensions: [],\n autofocus: false,\n editable: true,\n editorProps: {},\n parseOptions: {},\n coreExtensionOptions: {},\n enableInputRules: true,\n enablePasteRules: true,\n enableCoreExtensions: true,\n enableContentCheck: false,\n emitContentError: false,\n onBeforeCreate: () => null,\n onCreate: () => null,\n onUpdate: () => null,\n onSelectionUpdate: () => null,\n onTransaction: () => null,\n onFocus: () => null,\n onBlur: () => null,\n onDestroy: () => null,\n onContentError: ({ error }) => { throw error },\n onPaste: () => null,\n onDrop: () => null,\n }\n\n constructor(options: Partial<EditorOptions> = {}) {\n super()\n this.setOptions(options)\n this.createExtensionManager()\n this.createCommandManager()\n this.createSchema()\n this.on('beforeCreate', this.options.onBeforeCreate)\n this.emit('beforeCreate', { editor: this })\n this.on('contentError', this.options.onContentError)\n this.createView()\n this.injectCSS()\n this.on('create', this.options.onCreate)\n this.on('update', this.options.onUpdate)\n this.on('selectionUpdate', this.options.onSelectionUpdate)\n this.on('transaction', this.options.onTransaction)\n this.on('focus', this.options.onFocus)\n this.on('blur', this.options.onBlur)\n this.on('destroy', this.options.onDestroy)\n this.on('drop', ({ event, slice, moved }) => this.options.onDrop(event, slice, moved))\n this.on('paste', ({ event, slice }) => this.options.onPaste(event, slice))\n\n window.setTimeout(() => {\n if (this.isDestroyed) {\n return\n }\n\n this.commands.focus(this.options.autofocus)\n this.emit('create', { editor: this })\n this.isInitialized = true\n }, 0)\n }\n\n /**\n * Returns the editor storage.\n */\n public get storage(): Record<string, any> {\n return this.extensionStorage\n }\n\n /**\n * An object of all registered commands.\n */\n public get commands(): SingleCommands {\n return this.commandManager.commands\n }\n\n /**\n * Create a command chain to call multiple commands at once.\n */\n public chain(): ChainedCommands {\n return this.commandManager.chain()\n }\n\n /**\n * Check if a command or a command chain can be executed. Without executing it.\n */\n public can(): CanCommands {\n return this.commandManager.can()\n }\n\n /**\n * Inject CSS styles.\n */\n private injectCSS(): void {\n if (this.options.injectCSS && document) {\n this.css = createStyleTag(style, this.options.injectNonce)\n }\n }\n\n /**\n * Update editor options.\n *\n * @param options A list of options\n */\n public setOptions(options: Partial<EditorOptions> = {}): void {\n this.options = {\n ...this.options,\n ...options,\n }\n\n if (!this.view || !this.state || this.isDestroyed) {\n return\n }\n\n if (this.options.editorProps) {\n this.view.setProps(this.options.editorProps)\n }\n\n this.view.updateState(this.state)\n }\n\n /**\n * Update editable state of the editor.\n */\n public setEditable(editable: boolean, emitUpdate = true): void {\n this.setOptions({ editable })\n\n if (emitUpdate) {\n this.emit('update', { editor: this, transaction: this.state.tr })\n }\n }\n\n /**\n * Returns whether the editor is editable.\n */\n public get isEditable(): boolean {\n // since plugins are applied after creating the view\n // `editable` is always `true` for one tick.\n // that’s why we also have to check for `options.editable`\n return this.options.editable && this.view && this.view.editable\n }\n\n /**\n * Returns the editor state.\n */\n public get state(): EditorState {\n return this.view.state\n }\n\n /**\n * Register a ProseMirror plugin.\n *\n * @param plugin A ProseMirror plugin\n * @param handlePlugins Control how to merge the plugin into the existing plugins.\n * @returns The new editor state\n */\n public registerPlugin(\n plugin: Plugin,\n handlePlugins?: (newPlugin: Plugin, plugins: Plugin[]) => Plugin[],\n ): EditorState {\n const plugins = isFunction(handlePlugins)\n ? handlePlugins(plugin, [...this.state.plugins])\n : [...this.state.plugins, plugin]\n\n const state = this.state.reconfigure({ plugins })\n\n this.view.updateState(state)\n\n return state\n }\n\n /**\n * Unregister a ProseMirror plugin.\n *\n * @param nameOrPluginKeyToRemove The plugins name\n * @returns The new editor state or undefined if the editor is destroyed\n */\n public unregisterPlugin(nameOrPluginKeyToRemove: string | PluginKey | (string | PluginKey)[]): EditorState | undefined {\n if (this.isDestroyed) {\n return undefined\n }\n\n const prevPlugins = this.state.plugins\n let plugins = prevPlugins;\n\n ([] as (string | PluginKey)[]).concat(nameOrPluginKeyToRemove).forEach(nameOrPluginKey => {\n // @ts-ignore\n const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key\n\n // @ts-ignore\n plugins = plugins.filter(plugin => !plugin.key.startsWith(name))\n })\n\n if (prevPlugins.length === plugins.length) {\n // No plugin was removed, so we don’t need to update the state\n return undefined\n }\n\n const state = this.state.reconfigure({\n plugins,\n })\n\n this.view.updateState(state)\n\n return state\n }\n\n /**\n * Creates an extension manager.\n */\n private createExtensionManager(): void {\n\n const coreExtensions = this.options.enableCoreExtensions ? [\n Editable,\n ClipboardTextSerializer.configure({\n blockSeparator: this.options.coreExtensionOptions?.clipboardTextSerializer?.blockSeparator,\n }),\n Commands,\n FocusEvents,\n Keymap,\n Tabindex,\n Drop,\n Paste,\n ].filter(ext => {\n if (typeof this.options.enableCoreExtensions === 'object') {\n return this.options.enableCoreExtensions[ext.name as keyof typeof this.options.enableCoreExtensions] !== false\n }\n return true\n }) : []\n const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {\n return ['extension', 'node', 'mark'].includes(extension?.type)\n })\n\n this.extensionManager = new ExtensionManager(allExtensions, this)\n }\n\n /**\n * Creates an command manager.\n */\n private createCommandManager(): void {\n this.commandManager = new CommandManager({\n editor: this,\n })\n }\n\n /**\n * Creates a ProseMirror schema.\n */\n private createSchema(): void {\n this.schema = this.extensionManager.schema\n }\n\n /**\n * Creates a ProseMirror view.\n */\n private createView(): void {\n let doc: ProseMirrorNode\n\n try {\n doc = createDocument(\n this.options.content,\n this.schema,\n this.options.parseOptions,\n { errorOnInvalidContent: this.options.enableContentCheck },\n )\n } catch (e) {\n if (!(e instanceof Error) || !['[tiptap error]: Invalid JSON content', '[tiptap error]: Invalid HTML content'].includes(e.message)) {\n // Not the content error we were expecting\n throw e\n }\n this.emit('contentError', {\n editor: this,\n error: e as Error,\n disableCollaboration: () => {\n if (this.storage.collaboration) {\n this.storage.collaboration.isDisabled = true\n }\n // To avoid syncing back invalid content, reinitialize the extensions without the collaboration extension\n this.options.extensions = this.options.extensions.filter(extension => extension.name !== 'collaboration')\n\n // Restart the initialization process by recreating the extension manager with the new set of extensions\n this.createExtensionManager()\n },\n })\n\n // Content is invalid, but attempt to create it anyway, stripping out the invalid parts\n doc = createDocument(\n this.options.content,\n this.schema,\n this.options.parseOptions,\n { errorOnInvalidContent: false },\n )\n }\n const selection = resolveFocusPosition(doc, this.options.autofocus)\n\n this.view = new EditorView(this.options.element, {\n ...this.options.editorProps,\n attributes: {\n // add `role=\"textbox\"` to the editor element\n role: 'textbox',\n ...this.options.editorProps?.attributes,\n },\n dispatchTransaction: this.dispatchTransaction.bind(this),\n state: EditorState.create({\n doc,\n selection: selection || undefined,\n }),\n })\n\n // `editor.view` is not yet available at this time.\n // Therefore we will add all plugins and node views directly afterwards.\n const newState = this.state.reconfigure({\n plugins: this.extensionManager.plugins,\n })\n\n this.view.updateState(newState)\n\n this.createNodeViews()\n this.prependClass()\n\n // Let’s store the editor instance in the DOM element.\n // So we’ll have access to it for tests.\n // @ts-ignore\n const dom = this.view.dom as TiptapEditorHTMLElement\n\n dom.editor = this\n }\n\n /**\n * Creates all node views.\n */\n public createNodeViews(): void {\n if (this.view.isDestroyed) {\n return\n }\n\n this.view.setProps({\n nodeViews: this.extensionManager.nodeViews,\n })\n }\n\n /**\n * Prepend class name to element.\n */\n public prependClass(): void {\n this.view.dom.className = `tiptap ${this.view.dom.className}`\n }\n\n public isCapturingTransaction = false\n\n private capturedTransaction: Transaction | null = null\n\n public captureTransaction(fn: () => void) {\n this.isCapturingTransaction = true\n fn()\n this.isCapturingTransaction = false\n\n const tr = this.capturedTransaction\n\n this.capturedTransaction = null\n\n return tr\n }\n\n /**\n * The callback over which to send transactions (state updates) produced by the view.\n *\n * @param transaction An editor state transaction\n */\n private dispatchTransaction(transaction: Transaction): void {\n // if the editor / the view of the editor was destroyed\n // the transaction should not be dispatched as there is no view anymore.\n if (this.view.isDestroyed) {\n return\n }\n\n if (this.isCapturingTransaction) {\n if (!this.capturedTransaction) {\n this.capturedTransaction = transaction\n\n return\n }\n\n transaction.steps.forEach(step => this.capturedTransaction?.step(step))\n\n return\n }\n\n const state = this.state.apply(transaction)\n const selectionHasChanged = !this.state.selection.eq(state.selection)\n\n this.emit('beforeTransaction', {\n editor: this,\n transaction,\n nextState: state,\n })\n this.view.updateState(state)\n this.emit('transaction', {\n editor: this,\n transaction,\n })\n\n if (selectionHasChanged) {\n this.emit('selectionUpdate', {\n editor: this,\n transaction,\n })\n }\n\n const focus = transaction.getMeta('focus')\n const blur = transaction.getMeta('blur')\n\n if (focus) {\n this.emit('focus', {\n editor: this,\n event: focus.event,\n transaction,\n })\n }\n\n if (blur) {\n this.emit('blur', {\n editor: this,\n event: blur.event,\n transaction,\n })\n }\n\n if (!transaction.docChanged || transaction.getMeta('preventUpdate')) {\n return\n }\n\n this.emit('update', {\n editor: this,\n transaction,\n })\n }\n\n /**\n * Get attributes of the currently selected node or mark.\n */\n public getAttributes(nameOrType: string | NodeType | MarkType): Record<string, any> {\n return getAttributes(this.state, nameOrType)\n }\n\n /**\n * Returns if the currently selected node or mark is active.\n *\n * @param name Name of the node or mark\n * @param attributes Attributes of the node or mark\n */\n public isActive(name: string, attributes?: {}): boolean\n public isActive(attributes: {}): boolean\n public isActive(nameOrAttributes: string, attributesOrUndefined?: {}): boolean {\n const name = typeof nameOrAttributes === 'string' ? nameOrAttributes : null\n\n const attributes = typeof nameOrAttributes === 'string' ? attributesOrUndefined : nameOrAttributes\n\n return isActive(this.state, name, attributes)\n }\n\n /**\n * Get the document as JSON.\n */\n public getJSON(): JSONContent {\n return this.state.doc.toJSON()\n }\n\n /**\n * Get the document as HTML.\n */\n public getHTML(): string {\n return getHTMLFromFragment(this.state.doc.content, this.schema)\n }\n\n /**\n * Get the document as text.\n */\n public getText(options?: {\n blockSeparator?: string\n textSerializers?: Record<string, TextSerializer>\n }): string {\n const { blockSeparator = '\\n\\n', textSerializers = {} } = options || {}\n\n return getText(this.state.doc, {\n blockSeparator,\n textSerializers: {\n ...getTextSerializersFromSchema(this.schema),\n ...textSerializers,\n },\n })\n }\n\n /**\n * Check if there is no content.\n */\n public get isEmpty(): boolean {\n return isNodeEmpty(this.state.doc)\n }\n\n /**\n * Get the number of characters for the current document.\n *\n * @deprecated\n */\n public getCharacterCount(): number {\n console.warn(\n '[tiptap warn]: \"editor.getCharacterCount()\" is deprecated. Please use \"editor.storage.characterCount.characters()\" instead.',\n )\n\n return this.state.doc.content.size - 2\n }\n\n /**\n * Destroy the editor.\n */\n public destroy(): void {\n this.emit('destroy')\n\n if (this.view) {\n // Cleanup our reference to prevent circular references which caused memory leaks\n // @ts-ignore\n const dom = this.view.dom as TiptapEditorHTMLElement\n\n if (dom && dom.editor) {\n delete dom.editor\n }\n this.view.destroy()\n }\n\n this.removeAllListeners()\n }\n\n /**\n * Check if the editor is already destroyed.\n */\n public get isDestroyed(): boolean {\n // @ts-ignore\n return !this.view?.docView\n }\n\n public $node(selector: string, attributes?: { [key: string]: any }): NodePos | null {\n return this.$doc?.querySelector(selector, attributes) || null\n }\n\n public $nodes(selector: string, attributes?: { [key: string]: any }): NodePos[] | null {\n return this.$doc?.querySelectorAll(selector, attributes) || null\n }\n\n public $pos(pos: number) {\n const $pos = this.state.doc.resolve(pos)\n\n return new NodePos($pos, this)\n }\n\n get $doc() {\n return this.$pos(0)\n }\n}\n","import { MarkType } from '@tiptap/pm/model'\n\nimport { getMarksBetween } from '../helpers/getMarksBetween.js'\nimport { InputRule, InputRuleFinder } from '../InputRule.js'\nimport { ExtendedRegExpMatchArray } from '../types.js'\nimport { callOrReturn } from '../utilities/callOrReturn.js'\n\n/**\n * Build an input rule that adds a mark when the\n * matched text is typed into it.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules\n */\nexport function markInputRule(config: {\n find: InputRuleFinder\n type: MarkType\n getAttributes?:\n | Record<string, any>\n | ((match: ExtendedRegExpMatchArray) => Record<string, any>)\n | false\n | null\n}) {\n return new InputRule({\n find: config.find,\n handler: ({ state, range, match }) => {\n const attributes = callOrReturn(config.getAttributes, undefined, match)\n\n if (attributes === false || attributes === null) {\n return null\n }\n\n const { tr } = state\n const captureGroup = match[match.length - 1]\n const fullMatch = match[0]\n\n if (captureGroup) {\n const startSpaces = fullMatch.search(/\\S/)\n const textStart = range.from + fullMatch.indexOf(captureGroup)\n const textEnd = textStart + captureGroup.length\n\n const excludedMarks = getMarksBetween(range.from, range.to, state.doc)\n .filter(item => {\n // @ts-ignore\n const excluded = item.mark.type.excluded as MarkType[]\n\n return excluded.find(type => type === config.type && type !== item.mark.type)\n })\n .filter(item => item.to > textStart)\n\n if (excludedMarks.length) {\n return null\n }\n\n if (textEnd < range.to) {\n tr.delete(textEnd, range.to)\n }\n\n if (textStart > range.from) {\n tr.delete(range.from + startSpaces, textStart)\n }\n\n const markEnd = range.from + startSpaces + captureGroup.length\n\n tr.addMark(range.from + startSpaces, markEnd, config.type.create(attributes || {}))\n\n tr.removeStoredMark(config.type)\n }\n },\n })\n}\n","import { NodeType } from '@tiptap/pm/model'\n\nimport { InputRule, InputRuleFinder } from '../InputRule.js'\nimport { ExtendedRegExpMatchArray } from '../types.js'\nimport { callOrReturn } from '../utilities/callOrReturn.js'\n\n/**\n * Build an input rule that adds a node when the\n * matched text is typed into it.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules\n */\nexport function nodeInputRule(config: {\n /**\n * The regex to match.\n */\n find: InputRuleFinder\n\n /**\n * The node type to add.\n */\n type: NodeType\n\n /**\n * A function that returns the attributes for the node\n * can also be an object of attributes\n */\n getAttributes?:\n | Record<string, any>\n | ((match: ExtendedRegExpMatchArray) => Record<string, any>)\n | false\n | null\n}) {\n return new InputRule({\n find: config.find,\n handler: ({ state, range, match }) => {\n const attributes = callOrReturn(config.getAttributes, undefined, match) || {}\n const { tr } = state\n const start = range.from\n let end = range.to\n\n const newNode = config.type.create(attributes)\n\n if (match[1]) {\n const offset = match[0].lastIndexOf(match[1])\n let matchStart = start + offset\n\n if (matchStart > end) {\n matchStart = end\n } else {\n end = matchStart + match[1].length\n }\n\n // insert last typed character\n const lastChar = match[0][match[0].length - 1]\n\n tr.insertText(lastChar, start + match[0].length - 1)\n\n // insert node from input rule\n tr.replaceWith(matchStart, end, newNode)\n } else if (match[0]) {\n const insertionStart = config.type.isInline ? start : start - 1\n\n tr.insert(insertionStart, config.type.create(attributes)).delete(\n tr.mapping.map(start),\n tr.mapping.map(end),\n )\n }\n\n tr.scrollIntoView()\n },\n })\n}\n","import { NodeType } from '@tiptap/pm/model'\n\nimport { InputRule, InputRuleFinder } from '../InputRule.js'\nimport { ExtendedRegExpMatchArray } from '../types.js'\nimport { callOrReturn } from '../utilities/callOrReturn.js'\n\n/**\n * Build an input rule that changes the type of a textblock when the\n * matched text is typed into it. When using a regular expresion you’ll\n * probably want the regexp to start with `^`, so that the pattern can\n * only occur at the start of a textblock.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules\n */\nexport function textblockTypeInputRule(config: {\n find: InputRuleFinder\n type: NodeType\n getAttributes?:\n | Record<string, any>\n | ((match: ExtendedRegExpMatchArray) => Record<string, any>)\n | false\n | null\n}) {\n return new InputRule({\n find: config.find,\n handler: ({ state, range, match }) => {\n const $start = state.doc.resolve(range.from)\n const attributes = callOrReturn(config.getAttributes, undefined, match) || {}\n\n if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), config.type)) {\n return null\n }\n\n state.tr\n .delete(range.from, range.to)\n .setBlockType(range.from, range.from, config.type, attributes)\n },\n })\n}\n","import { InputRule, InputRuleFinder } from '../InputRule.js'\n\n/**\n * Build an input rule that replaces text when the\n * matched text is typed into it.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules\n */\nexport function textInputRule(config: {\n find: InputRuleFinder,\n replace: string,\n}) {\n return new InputRule({\n find: config.find,\n handler: ({ state, range, match }) => {\n let insert = config.replace\n let start = range.from\n const end = range.to\n\n if (match[1]) {\n const offset = match[0].lastIndexOf(match[1])\n\n insert += match[0].slice(offset + match[1].length)\n start += offset\n\n const cutOff = start - end\n\n if (cutOff > 0) {\n insert = match[0].slice(offset - cutOff, offset) + insert\n start = end\n }\n }\n\n state.tr.insertText(insert, start, end)\n },\n })\n}\n","import { Node as ProseMirrorNode, NodeType } from '@tiptap/pm/model'\nimport { canJoin, findWrapping } from '@tiptap/pm/transform'\n\nimport { Editor } from '../Editor.js'\nimport { InputRule, InputRuleFinder } from '../InputRule.js'\nimport { ExtendedRegExpMatchArray } from '../types.js'\nimport { callOrReturn } from '../utilities/callOrReturn.js'\n\n/**\n * Build an input rule for automatically wrapping a textblock when a\n * given string is typed. When using a regular expresion you’ll\n * probably want the regexp to start with `^`, so that the pattern can\n * only occur at the start of a textblock.\n *\n * `type` is the type of node to wrap in.\n *\n * By default, if there’s a node with the same type above the newly\n * wrapped node, the rule will try to join those\n * two nodes. You can pass a join predicate, which takes a regular\n * expression match and the node before the wrapped node, and can\n * return a boolean to indicate whether a join should happen.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules\n */\nexport function wrappingInputRule(config: {\n find: InputRuleFinder,\n type: NodeType,\n keepMarks?: boolean,\n keepAttributes?: boolean,\n editor?: Editor\n getAttributes?:\n | Record<string, any>\n | ((match: ExtendedRegExpMatchArray) => Record<string, any>)\n | false\n | null\n ,\n joinPredicate?: (match: ExtendedRegExpMatchArray, node: ProseMirrorNode) => boolean,\n}) {\n return new InputRule({\n find: config.find,\n handler: ({\n state, range, match, chain,\n }) => {\n const attributes = callOrReturn(config.getAttributes, undefined, match) || {}\n const tr = state.tr.delete(range.from, range.to)\n const $start = tr.doc.resolve(range.from)\n const blockRange = $start.blockRange()\n const wrapping = blockRange && findWrapping(blockRange, config.type, attributes)\n\n if (!wrapping) {\n return null\n }\n\n tr.wrap(blockRange, wrapping)\n\n if (config.keepMarks && config.editor) {\n const { selection, storedMarks } = state\n const { splittableMarks } = config.editor.extensionManager\n const marks = storedMarks || (selection.$to.parentOffset && selection.$from.marks())\n\n if (marks) {\n const filteredMarks = marks.filter(mark => splittableMarks.includes(mark.type.name))\n\n tr.ensureMarks(filteredMarks)\n }\n }\n if (config.keepAttributes) {\n /** If the nodeType is `bulletList` or `orderedList` set the `nodeType` as `listItem` */\n const nodeType = config.type.name === 'bulletList' || config.type.name === 'orderedList' ? 'listItem' : 'taskList'\n\n chain().updateAttributes(nodeType, attributes).run()\n }\n\n const before = tr.doc.resolve(range.from - 1).nodeBefore\n\n if (\n before\n && before.type === config.type\n && canJoin(tr.doc, range.from - 1)\n && (!config.joinPredicate || config.joinPredicate(match, before))\n ) {\n tr.join(range.from - 1)\n }\n },\n })\n}\n","import {\n DOMOutputSpec, Node as ProseMirrorNode, NodeSpec, NodeType,\n} from '@tiptap/pm/model'\nimport { Plugin, Transaction } from '@tiptap/pm/state'\n\nimport { Editor } from './Editor.js'\nimport { getExtensionField } from './helpers/getExtensionField.js'\nimport { NodeConfig } from './index.js'\nimport { InputRule } from './InputRule.js'\nimport { Mark } from './Mark.js'\nimport { PasteRule } from './PasteRule.js'\nimport {\n AnyConfig,\n Attributes,\n Extensions,\n GlobalAttributes,\n KeyboardShortcutCommand,\n NodeViewRenderer,\n ParentConfig,\n RawCommands,\n} from './types.js'\nimport { callOrReturn } from './utilities/callOrReturn.js'\nimport { mergeDeep } from './utilities/mergeDeep.js'\n\ndeclare module '@tiptap/core' {\n interface NodeConfig<Options = any, Storage = any> {\n // @ts-ignore - this is a dynamic key\n [key: string]: any\n\n /**\n * The extension name - this must be unique.\n * It will be used to identify the extension.\n *\n * @example 'myExtension'\n */\n name: string\n\n /**\n * The priority of your extension. The higher, the earlier it will be called\n * and will take precedence over other extensions with a lower priority.\n * @default 100\n * @example 101\n */\n priority?: number\n\n /**\n * The default options for this extension.\n * @example\n * defaultOptions: {\n * myOption: 'foo',\n * myOtherOption: 10,\n * }\n */\n defaultOptions?: Options\n\n /**\n * This method will add options to this extension\n * @see https://tiptap.dev/guide/custom-extensions#settings\n * @example\n * addOptions() {\n * return {\n * myOption: 'foo',\n * myOtherOption: 10,\n * }\n */\n addOptions?: (this: {\n name: string\n parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addOptions'], undefined>\n }) => Options\n\n /**\n * The default storage this extension can save data to.\n * @see https://tiptap.dev/guide/custom-extensions#storage\n * @example\n * defaultStorage: {\n * prefetchedUsers: [],\n * loading: false,\n * }\n */\n addStorage?: (this: {\n name: string\n options: Options\n parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addStorage'], undefined>\n }) => Storage\n\n /**\n * This function adds globalAttributes to specific nodes.\n * @see https://tiptap.dev/guide/custom-extensions#global-attributes\n * @example\n * addGlobalAttributes() {\n * return [\n * {\n // Extend the following extensions\n * types: [\n * 'heading',\n * 'paragraph',\n * ],\n * // … with those attributes\n * attributes: {\n * textAlign: {\n * default: 'left',\n * renderHTML: attributes => ({\n * style: `text-align: ${attributes.textAlign}`,\n * }),\n * parseHTML: element => element.style.textAlign || 'left',\n * },\n * },\n * },\n * ]\n * }\n */\n addGlobalAttributes?: (this: {\n name: string\n options: Options\n storage: Storage\n extensions: (Node | Mark)[]\n parent: ParentConfig<NodeConfig<Options, Storage>>['addGlobalAttributes']\n }) => GlobalAttributes\n\n /**\n * This function adds commands to the editor\n * @see https://tiptap.dev/guide/custom-extensions#keyboard-shortcuts\n * @example\n * addCommands() {\n * return {\n * myCommand: () => ({ chain }) => chain().setMark('type', 'foo').run(),\n * }\n * }\n */\n addCommands?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['addCommands']\n }) => Partial<RawCommands>\n\n /**\n * This function registers keyboard shortcuts.\n * @see https://tiptap.dev/guide/custom-extensions#keyboard-shortcuts\n * @example\n * addKeyboardShortcuts() {\n * return {\n * 'Mod-l': () => this.editor.commands.toggleBulletList(),\n * }\n * },\n */\n addKeyboardShortcuts?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['addKeyboardShortcuts']\n }) => {\n [key: string]: KeyboardShortcutCommand\n }\n\n /**\n * This function adds input rules to the editor.\n * @see https://tiptap.dev/guide/custom-extensions#input-rules\n * @example\n * addInputRules() {\n * return [\n * markInputRule({\n * find: inputRegex,\n * type: this.type,\n * }),\n * ]\n * },\n */\n addInputRules?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['addInputRules']\n }) => InputRule[]\n\n /**\n * This function adds paste rules to the editor.\n * @see https://tiptap.dev/guide/custom-extensions#paste-rules\n * @example\n * addPasteRules() {\n * return [\n * markPasteRule({\n * find: pasteRegex,\n * type: this.type,\n * }),\n * ]\n * },\n */\n addPasteRules?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['addPasteRules']\n }) => PasteRule[]\n\n /**\n * This function adds Prosemirror plugins to the editor\n * @see https://tiptap.dev/guide/custom-extensions#prosemirror-plugins\n * @example\n * addProseMirrorPlugins() {\n * return [\n * customPlugin(),\n * ]\n * }\n */\n addProseMirrorPlugins?: (this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['addProseMirrorPlugins']\n }) => Plugin[]\n\n /**\n * This function adds additional extensions to the editor. This is useful for\n * building extension kits.\n * @example\n * addExtensions() {\n * return [\n * BulletList,\n * OrderedList,\n * ListItem\n * ]\n * }\n */\n addExtensions?: (this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['addExtensions']\n }) => Extensions\n\n /**\n * This function extends the schema of the node.\n * @example\n * extendNodeSchema() {\n * return {\n * group: 'inline',\n * selectable: false,\n * }\n * }\n */\n extendNodeSchema?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['extendNodeSchema']\n },\n extension: Node,\n ) => Record<string, any>)\n | null\n\n /**\n * This function extends the schema of the mark.\n * @example\n * extendMarkSchema() {\n * return {\n * group: 'inline',\n * selectable: false,\n * }\n * }\n */\n extendMarkSchema?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['extendMarkSchema']\n editor?: Editor\n },\n extension: Node,\n ) => Record<string, any>)\n | null\n\n /**\n * The editor is not ready yet.\n */\n onBeforeCreate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onBeforeCreate']\n }) => void)\n | null\n\n /**\n * The editor is ready.\n */\n onCreate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onCreate']\n }) => void)\n | null\n\n /**\n * The content has changed.\n */\n onUpdate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onUpdate']\n }) => void)\n | null\n\n /**\n * The selection has changed.\n */\n onSelectionUpdate?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onSelectionUpdate']\n }) => void)\n | null\n\n /**\n * The editor state has changed.\n */\n onTransaction?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onTransaction']\n },\n props: {\n editor: Editor\n transaction: Transaction\n },\n ) => void)\n | null\n\n /**\n * The editor is focused.\n */\n onFocus?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onFocus']\n },\n props: {\n event: FocusEvent\n },\n ) => void)\n | null\n\n /**\n * The editor isn’t focused anymore.\n */\n onBlur?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onBlur']\n },\n props: {\n event: FocusEvent\n },\n ) => void)\n | null\n\n /**\n * The editor is destroyed.\n */\n onDestroy?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['onDestroy']\n }) => void)\n | null\n\n /**\n * Node View\n */\n addNodeView?:\n | ((this: {\n name: string\n options: Options\n storage: Storage\n editor: Editor\n type: NodeType\n parent: ParentConfig<NodeConfig<Options, Storage>>['addNodeView']\n }) => NodeViewRenderer)\n | null\n\n /**\n * Defines if this node should be a top level node (doc)\n * @default false\n * @example true\n */\n topNode?: boolean\n\n /**\n * The content expression for this node, as described in the [schema\n * guide](/docs/guide/#schema.content_expressions). When not given,\n * the node does not allow any content.\n *\n * You can read more about it on the Prosemirror documentation here\n * @see https://prosemirror.net/docs/guide/#schema.content_expressions\n * @default undefined\n * @example content: 'block+'\n * @example content: 'headline paragraph block*'\n */\n content?:\n | NodeSpec['content']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['content']\n editor?: Editor\n }) => NodeSpec['content'])\n\n /**\n * The marks that are allowed inside of this node. May be a\n * space-separated string referring to mark names or groups, `\"_\"`\n * to explicitly allow all marks, or `\"\"` to disallow marks. When\n * not given, nodes with inline content default to allowing all\n * marks, other nodes default to not allowing marks.\n *\n * @example marks: 'strong em'\n */\n marks?:\n | NodeSpec['marks']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['marks']\n editor?: Editor\n }) => NodeSpec['marks'])\n\n /**\n * The group or space-separated groups to which this node belongs,\n * which can be referred to in the content expressions for the\n * schema.\n *\n * By default Tiptap uses the groups 'block' and 'inline' for nodes. You\n * can also use custom groups if you want to group specific nodes together\n * and handle them in your schema.\n * @example group: 'block'\n * @example group: 'inline'\n * @example group: 'customBlock' // this uses a custom group\n */\n group?:\n | NodeSpec['group']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['group']\n editor?: Editor\n }) => NodeSpec['group'])\n\n /**\n * Should be set to true for inline nodes. (Implied for text nodes.)\n */\n inline?:\n | NodeSpec['inline']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['inline']\n editor?: Editor\n }) => NodeSpec['inline'])\n\n /**\n * Can be set to true to indicate that, though this isn't a [leaf\n * node](https://prosemirror.net/docs/ref/#model.NodeType.isLeaf), it doesn't have directly editable\n * content and should be treated as a single unit in the view.\n *\n * @example atom: true\n */\n atom?:\n | NodeSpec['atom']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['atom']\n editor?: Editor\n }) => NodeSpec['atom'])\n\n /**\n * Controls whether nodes of this type can be selected as a [node\n * selection](https://prosemirror.net/docs/ref/#state.NodeSelection). Defaults to true for non-text\n * nodes.\n *\n * @default true\n * @example selectable: false\n */\n selectable?:\n | NodeSpec['selectable']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['selectable']\n editor?: Editor\n }) => NodeSpec['selectable'])\n\n /**\n * Determines whether nodes of this type can be dragged without\n * being selected. Defaults to false.\n *\n * @default: false\n * @example: draggable: true\n */\n draggable?:\n | NodeSpec['draggable']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['draggable']\n editor?: Editor\n }) => NodeSpec['draggable'])\n\n /**\n * Can be used to indicate that this node contains code, which\n * causes some commands to behave differently.\n */\n code?:\n | NodeSpec['code']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['code']\n editor?: Editor\n }) => NodeSpec['code'])\n\n /**\n * Controls way whitespace in this a node is parsed. The default is\n * `\"normal\"`, which causes the [DOM parser](https://prosemirror.net/docs/ref/#model.DOMParser) to\n * collapse whitespace in normal mode, and normalize it (replacing\n * newlines and such with spaces) otherwise. `\"pre\"` causes the\n * parser to preserve spaces inside the node. When this option isn't\n * given, but [`code`](https://prosemirror.net/docs/ref/#model.NodeSpec.code) is true, `whitespace`\n * will default to `\"pre\"`. Note that this option doesn't influence\n * the way the node is rendered—that should be handled by `toDOM`\n * and/or styling.\n */\n whitespace?:\n | NodeSpec['whitespace']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['whitespace']\n editor?: Editor\n }) => NodeSpec['whitespace'])\n\n /**\n * Allows a **single** node to be set as linebreak equivalent (e.g. hardBreak).\n * When converting between block types that have whitespace set to \"pre\"\n * and don't support the linebreak node (e.g. codeBlock) and other block types\n * that do support the linebreak node (e.g. paragraphs) - this node will be used\n * as the linebreak instead of stripping the newline.\n *\n * See [linebreakReplacement](https://prosemirror.net/docs/ref/#model.NodeSpec.linebreakReplacement).\n */\n linebreakReplacement?:\n | NodeSpec['linebreakReplacement']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['linebreakReplacement']\n editor?: Editor\n }) => NodeSpec['linebreakReplacement'])\n\n /**\n * When enabled, enables both\n * [`definingAsContext`](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext) and\n * [`definingForContent`](https://prosemirror.net/docs/ref/#model.NodeSpec.definingForContent).\n *\n * @default false\n * @example isolating: true\n */\n defining?:\n | NodeSpec['defining']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['defining']\n editor?: Editor\n }) => NodeSpec['defining'])\n\n /**\n * When enabled (default is false), the sides of nodes of this type\n * count as boundaries that regular editing operations, like\n * backspacing or lifting, won't cross. An example of a node that\n * should probably have this enabled is a table cell.\n */\n isolating?:\n | NodeSpec['isolating']\n | ((this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['isolating']\n editor?: Editor\n }) => NodeSpec['isolating'])\n\n /**\n * Associates DOM parser information with this node, which can be\n * used by [`DOMParser.fromSchema`](https://prosemirror.net/docs/ref/#model.DOMParser^fromSchema) to\n * automatically derive a parser. The `node` field in the rules is\n * implied (the name of this node will be filled in automatically).\n * If you supply your own parser, you do not need to also specify\n * parsing rules in your schema.\n *\n * @example parseHTML: [{ tag: 'div', attrs: { 'data-id': 'my-block' } }]\n */\n parseHTML?: (this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['parseHTML']\n editor?: Editor\n }) => NodeSpec['parseDOM']\n\n /**\n * A description of a DOM structure. Can be either a string, which is\n * interpreted as a text node, a DOM node, which is interpreted as\n * itself, a `{dom, contentDOM}` object, or an array.\n *\n * An array describes a DOM element. The first value in the array\n * should be a string—the name of the DOM element, optionally prefixed\n * by a namespace URL and a space. If the second element is plain\n * object, it is interpreted as a set of attributes for the element.\n * Any elements after that (including the 2nd if it's not an attribute\n * object) are interpreted as children of the DOM elements, and must\n * either be valid `DOMOutputSpec` values, or the number zero.\n *\n * The number zero (pronounced “hole”) is used to indicate the place\n * where a node's child nodes should be inserted. If it occurs in an\n * output spec, it should be the only child element in its parent\n * node.\n *\n * @example toDOM: ['div[data-id=\"my-block\"]', { class: 'my-block' }, 0]\n */\n renderHTML?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['renderHTML']\n editor?: Editor\n },\n props: {\n node: ProseMirrorNode\n HTMLAttributes: Record<string, any>\n },\n ) => DOMOutputSpec)\n | null\n\n /**\n * renders the node as text\n * @example renderText: () => 'foo\n */\n renderText?:\n | ((\n this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['renderText']\n editor?: Editor\n },\n props: {\n node: ProseMirrorNode\n pos: number\n parent: ProseMirrorNode\n index: number\n },\n ) => string)\n | null\n\n /**\n * Add attributes to the node\n * @example addAttributes: () => ({ class: 'foo' })\n */\n addAttributes?: (this: {\n name: string\n options: Options\n storage: Storage\n parent: ParentConfig<NodeConfig<Options, Storage>>['addAttributes']\n editor?: Editor\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n }) => Attributes | {}\n }\n}\n\n/**\n * The Node class is used to create custom node extensions.\n * @see https://tiptap.dev/api/extensions#create-a-new-extension\n */\nexport class Node<Options = any, Storage = any> {\n type = 'node'\n\n name = 'node'\n\n parent: Node | null = null\n\n child: Node | null = null\n\n options: Options\n\n storage: Storage\n\n config: NodeConfig = {\n name: this.name,\n defaultOptions: {},\n }\n\n constructor(config: Partial<NodeConfig<Options, Storage>> = {}) {\n this.config = {\n ...this.config,\n ...config,\n }\n\n this.name = this.config.name\n\n if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {\n console.warn(\n `[tiptap warn]: BREAKING CHANGE: \"defaultOptions\" is deprecated. Please use \"addOptions\" instead. Found in extension: \"${this.name}\".`,\n )\n }\n\n // TODO: remove `addOptions` fallback\n this.options = this.config.defaultOptions\n\n if (this.config.addOptions) {\n this.options = callOrReturn(\n getExtensionField<AnyConfig['addOptions']>(this, 'addOptions', {\n name: this.name,\n }),\n )\n }\n\n this.storage = callOrReturn(\n getExtensionField<AnyConfig['addStorage']>(this, 'addStorage', {\n name: this.name,\n options: this.options,\n }),\n ) || {}\n }\n\n static create<O = any, S = any>(config: Partial<NodeConfig<O, S>> = {}) {\n return new Node<O, S>(config)\n }\n\n configure(options: Partial<Options> = {}) {\n // return a new instance so we can use the same extension\n // with different calls of `configure`\n const extension = this.extend<Options, Storage>({\n ...this.config,\n addOptions: () => {\n return mergeDeep(this.options as Record<string, any>, options) as Options\n },\n })\n\n // Always preserve the current name\n extension.name = this.name\n // Set the parent to be our parent\n extension.parent = this.parent\n\n return extension\n }\n\n extend<ExtendedOptions = Options, ExtendedStorage = Storage>(\n extendedConfig: Partial<NodeConfig<ExtendedOptions, ExtendedStorage>> = {},\n ) {\n const extension = new Node<ExtendedOptions, ExtendedStorage>(extendedConfig)\n\n extension.parent = this\n\n this.child = extension\n\n extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name\n\n if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {\n console.warn(\n `[tiptap warn]: BREAKING CHANGE: \"defaultOptions\" is deprecated. Please use \"addOptions\" instead. Found in extension: \"${extension.name}\".`,\n )\n }\n\n extension.options = callOrReturn(\n getExtensionField<AnyConfig['addOptions']>(extension, 'addOptions', {\n name: extension.name,\n }),\n )\n\n extension.storage = callOrReturn(\n getExtensionField<AnyConfig['addStorage']>(extension, 'addStorage', {\n name: extension.name,\n options: extension.options,\n }),\n )\n\n return extension\n }\n}\n","import { NodeSelection } from '@tiptap/pm/state'\nimport { NodeView as ProseMirrorNodeView, ViewMutationRecord } from '@tiptap/pm/view'\n\nimport { Editor as CoreEditor } from './Editor.js'\nimport { DecorationWithType, NodeViewRendererOptions, NodeViewRendererProps } from './types.js'\nimport { isAndroid } from './utilities/isAndroid.js'\nimport { isiOS } from './utilities/isiOS.js'\n\n/**\n * Node views are used to customize the rendered DOM structure of a node.\n * @see https://tiptap.dev/guide/node-views\n */\nexport class NodeView<\n Component,\n NodeEditor extends CoreEditor = CoreEditor,\n Options extends NodeViewRendererOptions = NodeViewRendererOptions,\n> implements ProseMirrorNodeView {\n component: Component\n\n editor: NodeEditor\n\n options: Options\n\n extension: NodeViewRendererProps['extension']\n\n node: NodeViewRendererProps['node']\n\n decorations: NodeViewRendererProps['decorations']\n\n innerDecorations: NodeViewRendererProps['innerDecorations']\n\n view: NodeViewRendererProps['view']\n\n getPos: NodeViewRendererProps['getPos']\n\n HTMLAttributes: NodeViewRendererProps['HTMLAttributes']\n\n isDragging = false\n\n constructor(component: Component, props: NodeViewRendererProps, options?: Partial<Options>) {\n this.component = component\n this.editor = props.editor as NodeEditor\n this.options = {\n stopEvent: null,\n ignoreMutation: null,\n ...options,\n } as Options\n this.extension = props.extension\n this.node = props.node\n this.decorations = props.decorations as DecorationWithType[]\n this.innerDecorations = props.innerDecorations\n this.view = props.view\n this.HTMLAttributes = props.HTMLAttributes\n this.getPos = props.getPos\n this.mount()\n }\n\n mount() {\n // eslint-disable-next-line\n return\n }\n\n get dom(): HTMLElement {\n return this.editor.view.dom as HTMLElement\n }\n\n get contentDOM(): HTMLElement | null {\n return null\n }\n\n onDragStart(event: DragEvent) {\n const { view } = this.editor\n const target = event.target as HTMLElement\n\n // get the drag handle element\n // `closest` is not available for text nodes so we may have to use its parent\n const dragHandle = target.nodeType === 3\n ? target.parentElement?.closest('[data-drag-handle]')\n : target.closest('[data-drag-handle]')\n\n if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {\n return\n }\n\n let x = 0\n let y = 0\n\n // calculate offset for drag element if we use a different drag handle element\n if (this.dom !== dragHandle) {\n const domBox = this.dom.getBoundingClientRect()\n const handleBox = dragHandle.getBoundingClientRect()\n\n // In React, we have to go through nativeEvent to reach offsetX/offsetY.\n const offsetX = event.offsetX ?? (event as any).nativeEvent?.offsetX\n const offsetY = event.offsetY ?? (event as any).nativeEvent?.offsetY\n\n x = handleBox.x - domBox.x + offsetX\n y = handleBox.y - domBox.y + offsetY\n }\n\n const clonedNode = this.dom.cloneNode(true) as HTMLElement\n\n event.dataTransfer?.setDragImage(clonedNode, x, y)\n\n const pos = this.getPos()\n\n if (typeof pos !== 'number') {\n return\n }\n // we need to tell ProseMirror that we want to move the whole node\n // so we create a NodeSelection\n const selection = NodeSelection.create(view.state.doc, pos)\n const transaction = view.state.tr.setSelection(selection)\n\n view.dispatch(transaction)\n }\n\n stopEvent(event: Event) {\n if (!this.dom) {\n return false\n }\n\n if (typeof this.options.stopEvent === 'function') {\n return this.options.stopEvent({ event })\n }\n\n const target = event.target as HTMLElement\n const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target)\n\n // any event from child nodes should be handled by ProseMirror\n if (!isInElement) {\n return false\n }\n\n const isDragEvent = event.type.startsWith('drag')\n const isDropEvent = event.type === 'drop'\n const isInput = ['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA'].includes(target.tagName) || target.isContentEditable\n\n // any input event within node views should be ignored by ProseMirror\n if (isInput && !isDropEvent && !isDragEvent) {\n return true\n }\n\n const { isEditable } = this.editor\n const { isDragging } = this\n const isDraggable = !!this.node.type.spec.draggable\n const isSelectable = NodeSelection.isSelectable(this.node)\n const isCopyEvent = event.type === 'copy'\n const isPasteEvent = event.type === 'paste'\n const isCutEvent = event.type === 'cut'\n const isClickEvent = event.type === 'mousedown'\n\n // ProseMirror tries to drag selectable nodes\n // even if `draggable` is set to `false`\n // this fix prevents that\n if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {\n event.preventDefault()\n }\n\n if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {\n event.preventDefault()\n return false\n }\n\n // we have to store that dragging started\n if (isDraggable && isEditable && !isDragging && isClickEvent) {\n const dragHandle = target.closest('[data-drag-handle]')\n const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle))\n\n if (isValidDragHandle) {\n this.isDragging = true\n\n document.addEventListener(\n 'dragend',\n () => {\n this.isDragging = false\n },\n { once: true },\n )\n\n document.addEventListener(\n 'drop',\n () => {\n this.isDragging = false\n },\n { once: true },\n )\n\n document.addEventListener(\n 'mouseup',\n () => {\n this.isDragging = false\n },\n { once: true },\n )\n }\n }\n\n // these events are handled by prosemirror\n if (\n isDragging\n || isDropEvent\n || isCopyEvent\n || isPasteEvent\n || isCutEvent\n || (isClickEvent && isSelectable)\n ) {\n return false\n }\n\n return true\n }\n\n /**\n * Called when a DOM [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) or a selection change happens within the view.\n * @return `false` if the editor should re-read the selection or re-parse the range around the mutation\n * @return `true` if it can safely be ignored.\n */\n ignoreMutation(mutation: ViewMutationRecord) {\n if (!this.dom || !this.contentDOM) {\n return true\n }\n\n if (typeof this.options.ignoreMutation === 'function') {\n return this.options.ignoreMutation({ mutation })\n }\n\n // a leaf/atom node is like a black box for ProseMirror\n // and should be fully handled by the node view\n if (this.node.isLeaf || this.node.isAtom) {\n return true\n }\n\n // ProseMirror should handle any selections\n if (mutation.type === 'selection') {\n return false\n }\n\n // try to prevent a bug on iOS and Android that will break node views on enter\n // this is because ProseMirror can’t preventDispatch on enter\n // this will lead to a re-render of the node view on enter\n // see: https://github.com/ueberdosis/tiptap/issues/1214\n // see: https://github.com/ueberdosis/tiptap/issues/2534\n if (\n this.dom.contains(mutation.target)\n && mutation.type === 'childList'\n && (isiOS() || isAndroid())\n && this.editor.isFocused\n ) {\n const changedNodes = [\n ...Array.from(mutation.addedNodes),\n ...Array.from(mutation.removedNodes),\n ] as HTMLElement[]\n\n // we’ll check if every changed node is contentEditable\n // to make sure it’s probably mutated by ProseMirror\n if (changedNodes.every(node => node.isContentEditable)) {\n return false\n }\n }\n\n // we will allow mutation contentDOM with attributes\n // so we can for example adding classes within our node view\n if (this.contentDOM === mutation.target && mutation.type === 'attributes') {\n return true\n }\n\n // ProseMirror should handle any changes within contentDOM\n if (this.contentDOM.contains(mutation.target)) {\n return false\n }\n\n return true\n }\n\n /**\n * Update the attributes of the prosemirror node.\n */\n updateAttributes(attributes: Record<string, any>): void {\n this.editor.commands.command(({ tr }) => {\n const pos = this.getPos()\n\n if (typeof pos !== 'number') {\n return false\n }\n\n tr.setNodeMarkup(pos, undefined, {\n ...this.node.attrs,\n ...attributes,\n })\n\n return true\n })\n }\n\n /**\n * Delete the node.\n */\n deleteNode(): void {\n const from = this.getPos()\n\n if (typeof from !== 'number') {\n return\n }\n const to = from + this.node.nodeSize\n\n this.editor.commands.deleteRange({ from, to })\n }\n}\n","import { MarkType } from '@tiptap/pm/model'\n\nimport { getMarksBetween } from '../helpers/getMarksBetween.js'\nimport { PasteRule, PasteRuleFinder } from '../PasteRule.js'\nimport { ExtendedRegExpMatchArray } from '../types.js'\nimport { callOrReturn } from '../utilities/callOrReturn.js'\n\n/**\n * Build an paste rule that adds a mark when the\n * matched text is pasted into it.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules\n */\nexport function markPasteRule(config: {\n find: PasteRuleFinder\n type: MarkType\n getAttributes?:\n | Record<string, any>\n | ((match: ExtendedRegExpMatchArray, event: ClipboardEvent) => Record<string, any>)\n | false\n | null\n}) {\n return new PasteRule({\n find: config.find,\n handler: ({\n state, range, match, pasteEvent,\n }) => {\n const attributes = callOrReturn(config.getAttributes, undefined, match, pasteEvent)\n\n if (attributes === false || attributes === null) {\n return null\n }\n\n const { tr } = state\n const captureGroup = match[match.length - 1]\n const fullMatch = match[0]\n let markEnd = range.to\n\n if (captureGroup) {\n const startSpaces = fullMatch.search(/\\S/)\n const textStart = range.from + fullMatch.indexOf(captureGroup)\n const textEnd = textStart + captureGroup.length\n\n const excludedMarks = getMarksBetween(range.from, range.to, state.doc)\n .filter(item => {\n // @ts-ignore\n const excluded = item.mark.type.excluded as MarkType[]\n\n return excluded.find(type => type === config.type && type !== item.mark.type)\n })\n .filter(item => item.to > textStart)\n\n if (excludedMarks.length) {\n return null\n }\n\n if (textEnd < range.to) {\n tr.delete(textEnd, range.to)\n }\n\n if (textStart > range.from) {\n tr.delete(range.from + startSpaces, textStart)\n }\n\n markEnd = range.from + startSpaces + captureGroup.length\n\n tr.addMark(range.from + startSpaces, markEnd, config.type.create(attributes || {}))\n\n tr.removeStoredMark(config.type)\n }\n },\n })\n}\n","import type { NodeType } from '@tiptap/pm/model'\nimport { type EditorState, NodeSelection } from '@tiptap/pm/state'\n\nexport function canInsertNode(state: EditorState, nodeType: NodeType): boolean {\n const { selection } = state\n const { $from } = selection\n\n // Special handling for NodeSelection\n if (selection instanceof NodeSelection) {\n const index = $from.index()\n const parent = $from.parent\n\n // Can we replace the selected node with the horizontal rule?\n return parent.canReplaceWith(index, index + 1, nodeType)\n }\n\n // Default: check if we can insert at the current position\n let depth = $from.depth\n\n while (depth >= 0) {\n const index = $from.index(depth)\n const parent = $from.node(depth)\n const match = parent.contentMatchAt(index)\n\n if (match.matchType(nodeType)) {\n return true\n }\n depth -= 1\n }\n return false\n}\n","// source: https://stackoverflow.com/a/6969486\nexport function escapeForRegEx(string: string): string {\n return string.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&')\n}\n","export function isString(value: any): value is string {\n return typeof value === 'string'\n}\n","import { NodeType } from '@tiptap/pm/model'\n\nimport { PasteRule, PasteRuleFinder } from '../PasteRule.js'\nimport { ExtendedRegExpMatchArray, JSONContent } from '../types.js'\nimport { callOrReturn } from '../utilities/index.js'\n\n/**\n * Build an paste rule that adds a node when the\n * matched text is pasted into it.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules\n */\nexport function nodePasteRule(config: {\n find: PasteRuleFinder\n type: NodeType\n getAttributes?:\n | Record<string, any>\n | ((match: ExtendedRegExpMatchArray, event: ClipboardEvent) => Record<string, any>)\n | false\n | null\n getContent?:\n | JSONContent[]\n | ((attrs: Record<string, any>) => JSONContent[])\n | false\n | null\n}) {\n return new PasteRule({\n find: config.find,\n handler({\n match, chain, range, pasteEvent,\n }) {\n const attributes = callOrReturn(config.getAttributes, undefined, match, pasteEvent)\n const content = callOrReturn(config.getContent, undefined, attributes)\n\n if (attributes === false || attributes === null) {\n return null\n }\n\n const node = { type: config.type.name, attrs: attributes } as JSONContent\n\n if (content) {\n node.content = content\n }\n\n if (match.input) {\n chain().deleteRange(range).insertContentAt(range.from, node)\n }\n },\n })\n}\n","import { PasteRule, PasteRuleFinder } from '../PasteRule.js'\n\n/**\n * Build an paste rule that replaces text when the\n * matched text is pasted into it.\n * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules\n */\nexport function textPasteRule(config: {\n find: PasteRuleFinder,\n replace: string,\n}) {\n return new PasteRule({\n find: config.find,\n handler: ({ state, range, match }) => {\n let insert = config.replace\n let start = range.from\n const end = range.to\n\n if (match[1]) {\n const offset = match[0].lastIndexOf(match[1])\n\n insert += match[0].slice(offset + match[1].length)\n start += offset\n\n const cutOff = start - end\n\n if (cutOff > 0) {\n insert = match[0].slice(offset - cutOff, offset) + insert\n start = end\n }\n }\n\n state.tr.insertText(insert, start, end)\n },\n })\n}\n","import { Transaction } from '@tiptap/pm/state'\n\nexport interface TrackerResult {\n position: number\n deleted: boolean\n}\n\nexport class Tracker {\n transaction: Transaction\n\n currentStep: number\n\n constructor(transaction: Transaction) {\n this.transaction = transaction\n this.currentStep = this.transaction.steps.length\n }\n\n map(position: number): TrackerResult {\n let deleted = false\n\n const mappedPosition = this.transaction.steps\n .slice(this.currentStep)\n .reduce((newPosition, step) => {\n const mapResult = step.getMap().mapResult(newPosition)\n\n if (mapResult.deleted) {\n deleted = true\n }\n\n return mapResult.pos\n }, position)\n\n return {\n position: mappedPosition,\n deleted,\n }\n }\n}\n","import { mergeAttributes, Node, textblockTypeInputRule } from '@tiptap/core'\n\n/**\n * The heading level options.\n */\nexport type Level = 1 | 2 | 3 | 4 | 5 | 6\n\nexport interface HeadingOptions {\n /**\n * The available heading levels.\n * @default [1, 2, 3, 4, 5, 6]\n * @example [1, 2, 3]\n */\n levels: Level[],\n\n /**\n * The HTML attributes for a heading node.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>,\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n heading: {\n /**\n * Set a heading node\n * @param attributes The heading attributes\n * @example editor.commands.setHeading({ level: 1 })\n */\n setHeading: (attributes: { level: Level }) => ReturnType,\n /**\n * Toggle a heading node\n * @param attributes The heading attributes\n * @example editor.commands.toggleHeading({ level: 1 })\n */\n toggleHeading: (attributes: { level: Level }) => ReturnType,\n }\n }\n}\n\n/**\n * This extension allows you to create headings.\n * @see https://www.tiptap.dev/api/nodes/heading\n */\nexport const Heading = Node.create<HeadingOptions>({\n name: 'heading',\n\n addOptions() {\n return {\n levels: [1, 2, 3, 4, 5, 6],\n HTMLAttributes: {},\n }\n },\n\n content: 'inline*',\n\n group: 'block',\n\n defining: true,\n\n addAttributes() {\n return {\n level: {\n default: 1,\n rendered: false,\n },\n }\n },\n\n parseHTML() {\n return this.options.levels\n .map((level: Level) => ({\n tag: `h${level}`,\n attrs: { level },\n }))\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const hasLevel = this.options.levels.includes(node.attrs.level)\n const level = hasLevel\n ? node.attrs.level\n : this.options.levels[0]\n\n return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n addCommands() {\n return {\n setHeading: attributes => ({ commands }) => {\n if (!this.options.levels.includes(attributes.level)) {\n return false\n }\n\n return commands.setNode(this.name, attributes)\n },\n toggleHeading: attributes => ({ commands }) => {\n if (!this.options.levels.includes(attributes.level)) {\n return false\n }\n\n return commands.toggleNode(this.name, 'paragraph', attributes)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return this.options.levels.reduce((items, level) => ({\n ...items,\n ...{\n [`Mod-Alt-${level}`]: () => this.editor.commands.toggleHeading({ level }),\n },\n }), {})\n },\n\n addInputRules() {\n return this.options.levels.map(level => {\n return textblockTypeInputRule({\n find: new RegExp(`^(#{${Math.min(...this.options.levels)},${level}})\\\\s$`),\n type: this.type,\n getAttributes: {\n level,\n },\n })\n })\n },\n})\n","/**\n * TemplateAnnotation — Tiptap Heading Extension\n *\n * Extends Tiptap's built-in Heading node to support `data-template` and\n * `data-template-params` HTML attributes. These attributes store which block\n * template should be used for a heading section.\n *\n * When present, the heading renders a visible badge (styled CSS chip)\n * showing the template name, e.g. `[chart]`.\n *\n * The tiptapBridge converts `### Title {[chart]}` markdown into\n * `<h3 data-template=\"chart\">Title</h3>` and back, so this extension\n * ensures Tiptap's schema preserves those attributes through edits.\n */\n\nimport Heading from '@tiptap/extension-heading';\nimport { templateLabel } from './TemplatePicker';\n\n/**\n * HeadingWithTemplate — drop-in replacement for Tiptap's Heading that\n * persists template annotation attributes.\n */\nexport const HeadingWithTemplate = Heading.extend({\n addAttributes() {\n return {\n ...this.parent?.(),\n dataTemplate: {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute('data-template') || null,\n renderHTML: (attributes: Record<string, unknown>) => {\n if (!attributes.dataTemplate) return {};\n return { 'data-template': attributes.dataTemplate };\n },\n },\n dataTemplateParams: {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute('data-template-params') || null,\n renderHTML: (attributes: Record<string, unknown>) => {\n if (!attributes.dataTemplateParams) return {};\n return { 'data-template-params': attributes.dataTemplateParams };\n },\n },\n };\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const level = node.attrs.level;\n const tag = `h${level}`;\n const templateName = HTMLAttributes['data-template'];\n\n // Render heading with a trailing badge span. The badge has no text\n // content — its label is painted via CSS `content: attr(data-template-label)`\n // so the template name never becomes part of the serialized heading\n // text (which would leak into markdown on round-trip).\n //\n // When no template is set we still render a subtle \"empty\" badge so\n // authors have a visible affordance for opening the template picker\n // straight from the heading (matches the clicky chip shown for\n // templated headings). The empty variant has no `data-template`\n // attribute, so the bridge treats the heading as plain on save.\n if (templateName) {\n return [\n tag,\n HTMLAttributes,\n ['span', { class: 'squisq-heading-content' }, 0],\n [\n 'span',\n {\n class: 'squisq-template-badge',\n contenteditable: 'false',\n role: 'button',\n tabindex: '0',\n 'aria-haspopup': 'listbox',\n title: 'Change block template',\n 'data-template': templateName,\n 'data-template-label': templateLabel(templateName),\n },\n ],\n ];\n }\n\n return [\n tag,\n HTMLAttributes,\n ['span', { class: 'squisq-heading-content' }, 0],\n [\n 'span',\n {\n class: 'squisq-template-badge squisq-template-badge--empty',\n contenteditable: 'false',\n role: 'button',\n tabindex: '0',\n 'aria-haspopup': 'listbox',\n title: 'Choose block template',\n },\n ],\n ];\n },\n});\n","/**\n * InlineIcon — Tiptap Node Extension\n *\n * Atomic inline node that round-trips FontAwesome icons through the\n * WYSIWYG editor. The markdown bridge stashes `{[github]}` source as\n * `<i data-icon=\"github\" data-family=\"brands\" data-name=\"github\"\n * class=\"fa-brands fa-github\"></i>`; this extension lets ProseMirror\n * recognize that markup, persist the attributes through edits, and\n * re-emit it when serializing back to HTML/markdown.\n *\n * Atom / inline / non-selectable means the icon behaves like an emoji:\n * the caret can land before or after it, Backspace deletes it whole,\n * and Tiptap won't try to put content inside it.\n */\n\nimport { Node, mergeAttributes } from '@tiptap/core';\n\ninterface InlineIconAttrs {\n /** Token as authored in markdown — e.g. `github`, `fa-solid:user`. */\n token: string;\n family: 'brands' | 'solid' | 'regular';\n name: string;\n}\n\nexport const InlineIcon = Node.create({\n name: 'inlineIcon',\n group: 'inline',\n inline: true,\n atom: true,\n selectable: true,\n draggable: false,\n\n addAttributes() {\n return {\n token: {\n default: '',\n parseHTML: (el: HTMLElement) => el.getAttribute('data-icon') ?? '',\n renderHTML: (attrs: InlineIconAttrs) => (attrs.token ? { 'data-icon': attrs.token } : {}),\n },\n family: {\n default: 'solid',\n parseHTML: (el: HTMLElement) => el.getAttribute('data-family') ?? 'solid',\n renderHTML: (attrs: InlineIconAttrs) =>\n attrs.family ? { 'data-family': attrs.family } : {},\n },\n name: {\n default: '',\n parseHTML: (el: HTMLElement) => el.getAttribute('data-name') ?? '',\n renderHTML: (attrs: InlineIconAttrs) => (attrs.name ? { 'data-name': attrs.name } : {}),\n },\n };\n },\n\n parseHTML() {\n // Tiptap's built-in Italic mark also claims `<i>` tags. We need a\n // higher priority than the default (50) so ProseMirror picks\n // InlineIcon over Italic for `<i data-icon=…>` markup — otherwise\n // the markdown → WYSIWYG round-trip silently drops the icon and\n // produces an empty italic mark instead.\n return [\n {\n tag: 'i[data-icon]',\n priority: 100,\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const family = (HTMLAttributes['data-family'] as string | undefined) ?? 'solid';\n const name = (HTMLAttributes['data-name'] as string | undefined) ?? '';\n // The `<i>` carries `class=\"fa-brands fa-github\"` so the bundled\n // FontAwesome CSS picks it up. We also keep `data-*` mirrors so\n // the bridge regex can round-trip back to markdown without\n // parsing the class string.\n const className = name ? `fa-${family} fa-${name}` : '';\n return [\n 'i',\n mergeAttributes(HTMLAttributes, {\n class: className,\n contenteditable: 'false',\n }),\n ];\n },\n});\n","/**\n * ImageNodeView — Custom Tiptap NodeView for images.\n *\n * Resolves image `src` attributes through the EditorContext's MediaProvider,\n * converting relative paths (e.g. \"images/hero.jpg\") to displayable blob URLs.\n *\n * The ProseMirror node retains the original relative path so markdown roundtrip\n * is preserved — only the rendered DOM uses the resolved URL.\n *\n * When the image is hovered or selected, a small floating \"Edit\" affordance\n * appears in the top-right corner — clicking it calls `openImageEdit` on the\n * editor context, which `<EditorShell>` consumes to open a modal\n * `<ImageEditor>` on the source path. Only shown for paths that are\n * relative (i.e. live in the document's media container).\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react';\nimport type { NodeViewProps } from '@tiptap/react';\nimport Image from '@tiptap/extension-image';\nimport { useEditorContext } from './EditorContext';\nimport { normalizeMalformedAssetUrl } from './utils/normalizeMalformedAssetUrl';\n\nfunction ImageComponent({ node, selected, editor, updateAttributes }: NodeViewProps) {\n const { src, alt, title, width } = node.attrs as {\n src: string;\n alt: string;\n title: string;\n width: number | null;\n height: number | null;\n };\n const { mediaProvider, imageDisplayMode, openImageEdit, mediaRevision } = useEditorContext();\n const [resolvedSrc, setResolvedSrc] = useState(src);\n const [hovered, setHovered] = useState(false);\n const imgRef = useRef<HTMLImageElement | null>(null);\n // Live preview width while a resize gesture is in flight. Null means\n // \"use the persisted width attr\". Committed to node attrs on mouseup.\n const [previewWidth, setPreviewWidth] = useState<number | null>(null);\n const isThumbnail = imageDisplayMode === 'thumbnail';\n const isEditable = editor?.isEditable ?? true;\n\n // MS \"Save Page As Web Page\" / pandoc-style imports sometimes leave\n // image srcs in the shape `http://<doc>_files/<asset>` — the asset\n // folder got URL-parsed as a hostname because no scheme separator was\n // ever there. Detect that shape (bare hostname, no dots/ports, ending\n // in `_files`) and recover the original relative path so the media\n // provider can resolve it from the workspace.\n const normalizedRelativePath = normalizeMalformedAssetUrl(src);\n const isRelative =\n src &&\n !src.startsWith('blob:') &&\n !src.startsWith('http') &&\n !src.startsWith('data:') &&\n !src.startsWith('/');\n const resolveAs = normalizedRelativePath ?? (isRelative ? src : null);\n\n useEffect(() => {\n if (!mediaProvider || !resolveAs) {\n setResolvedSrc(src);\n return;\n }\n\n let cancelled = false;\n mediaProvider.resolveUrl(resolveAs).then(\n (resolved) => {\n if (!cancelled) setResolvedSrc(resolved);\n },\n () => {\n if (!cancelled) setResolvedSrc(src);\n },\n );\n\n return () => {\n cancelled = true;\n };\n // `mediaRevision` is bumped after the image editor writes back to the\n // same path — re-resolve so we pick up the fresh blob URL.\n }, [src, resolveAs, mediaProvider, mediaRevision]);\n\n // The Edit affordance is only meaningful when:\n // - the editor is editable (read-only previews skip it),\n // - the path is relative (lives in the doc's container, so the editor\n // can read+write it back), and\n // - a media provider is wired (the modal resolves the URL through it).\n const canEdit = isEditable && isRelative && mediaProvider !== null;\n const showAffordance = canEdit && (selected || hovered);\n // Resize handle is shown for any selected image in an editable view —\n // even non-relative ones (external URLs, data URIs) — so authors can\n // size remote pictures the same way as local ones.\n const canResize = isEditable && !isThumbnail;\n const showResize = canResize && (selected || hovered);\n\n // Effective render width: live preview while dragging, otherwise the\n // persisted attr. Height is always derived from the natural aspect\n // ratio of the image element so authors can't accidentally squash it.\n const effectiveWidth = previewWidth ?? width ?? null;\n\n const beginResize = (event: React.MouseEvent) => {\n if (!canResize) return;\n event.preventDefault();\n event.stopPropagation();\n const imgEl = imgRef.current;\n if (!imgEl) return;\n const startWidth = imgEl.getBoundingClientRect().width;\n const startX = event.clientX;\n // Cap at the image's natural width so dragging out doesn't upscale\n // past the source pixels (which just looks blurry).\n const maxWidth = imgEl.naturalWidth || Infinity;\n const minWidth = 24;\n\n const onMove = (e: MouseEvent) => {\n const next = Math.max(minWidth, Math.min(maxWidth, startWidth + (e.clientX - startX)));\n setPreviewWidth(Math.round(next));\n };\n const onUp = (e: MouseEvent) => {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n const finalWidth = Math.max(minWidth, Math.min(maxWidth, startWidth + (e.clientX - startX)));\n const naturalW = imgEl.naturalWidth;\n const naturalH = imgEl.naturalHeight;\n const w = Math.round(finalWidth);\n const h = naturalW > 0 && naturalH > 0 ? Math.round((w * naturalH) / naturalW) : null;\n setPreviewWidth(null);\n updateAttributes({ width: w, height: h });\n };\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n };\n\n const resetSize = (event: React.MouseEvent) => {\n if (!canResize) return;\n event.preventDefault();\n event.stopPropagation();\n setPreviewWidth(null);\n updateAttributes({ width: null, height: null });\n };\n\n const baseStyle: React.CSSProperties = isThumbnail\n ? {\n maxWidth: '100px',\n maxHeight: '100px',\n width: 'auto',\n height: 'auto',\n objectFit: 'contain',\n display: 'block',\n }\n : effectiveWidth\n ? {\n width: `${effectiveWidth}px`,\n maxWidth: '100%',\n height: 'auto',\n display: 'block',\n }\n : { maxWidth: '100%', height: 'auto', display: 'block' };\n\n return (\n <NodeViewWrapper\n as=\"figure\"\n // `data-drag-handle` tells ProseMirror that drags starting on this\n // wrapper are NODE moves (not OS-level image drags). Without it,\n // grabbing the inner `<img>` fires the browser's default image-drag\n // behaviour: the picture is packaged as a virtual file in\n // `dataTransfer.files`, the drop is treated as an external upload,\n // and the source node is never removed — producing a duplicate.\n // Combined with `draggable: true` in the node spec, this gives\n // ProseMirror's default dropHandler a real internal move which\n // preserves the `width`/`height` attrs and deletes the original.\n draggable\n data-drag-handle\n style={{ margin: '0.5em 0', position: 'relative', display: 'inline-block', maxWidth: '100%' }}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n >\n <img\n ref={imgRef}\n src={resolvedSrc}\n alt={alt || ''}\n title={title || undefined}\n className={isThumbnail ? 'squisq-image squisq-image--thumbnail' : 'squisq-image'}\n style={baseStyle}\n // Disable the inner `<img>`'s native HTML5 drag so the gesture is\n // captured by the wrapper's `data-drag-handle` instead. (Without\n // this the browser still emits its own dragstart on the image\n // and ProseMirror sees an external file drop.)\n draggable={false}\n onDragStart={(e) => e.preventDefault()}\n data-selected={selected ? 'true' : undefined}\n />\n {showAffordance && (\n <button\n type=\"button\"\n className=\"squisq-image-edit-affordance\"\n data-testid=\"image-edit-affordance\"\n // Stop the click from re-selecting the ProseMirror node and from\n // bubbling to host handlers like file-drop overlays.\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n openImageEdit(src);\n }}\n title=\"Edit image\"\n aria-label={`Edit image ${alt || src}`}\n >\n <span aria-hidden=\"true\" style={{ fontSize: '0.95em', lineHeight: 1 }}>\n ✎\n </span>\n <span>Edit</span>\n </button>\n )}\n {showResize && (\n <>\n <span\n className=\"squisq-image-resize-handle\"\n data-testid=\"image-resize-handle\"\n onMouseDown={beginResize}\n // Double-click clears the persisted width/height so the image\n // returns to its natural rendered size.\n onDoubleClick={resetSize}\n title=\"Drag to resize · double-click to reset\"\n aria-label=\"Resize image\"\n role=\"separator\"\n />\n {(previewWidth != null || width != null) && (\n <span className=\"squisq-image-resize-readout\" aria-hidden=\"true\">\n {Math.round(effectiveWidth ?? 0)}px\n </span>\n )}\n </>\n )}\n </NodeViewWrapper>\n );\n}\n\n/**\n * Image extension with a custom React NodeView that resolves URLs\n * through the EditorContext's MediaProvider, plus author-controlled\n * width/height attributes for in-editor resizing.\n *\n * When `width` (and optionally `height`) is set, the markdown serializer\n * (`tiptapToMarkdown` in `tiptapBridge.ts`) emits an HTML `<img>` tag\n * rather than the `![alt](src)` shorthand so dimensions survive a\n * markdown ↔ WYSIWYG round-trip.\n */\nexport const ImageWithMediaProvider = Image.extend({\n // Mark the node draggable so ProseMirror handles drag-to-reposition\n // as an internal node move (preserves `width`/`height` attrs and\n // removes the source node automatically). Combined with the\n // `data-drag-handle` on the NodeViewWrapper, this is what makes the\n // `moved` flag true in `handleDrop` so the editor's file-upload path\n // doesn't fire on a drag-reorder.\n draggable: true,\n addAttributes() {\n const parent = this.parent?.() ?? {};\n return {\n ...parent,\n width: {\n default: null,\n parseHTML: (element) => {\n const raw = element.getAttribute('width');\n if (!raw) return null;\n const n = parseInt(raw, 10);\n return Number.isFinite(n) && n > 0 ? n : null;\n },\n renderHTML: (attrs: { width?: number | null }) =>\n attrs.width ? { width: String(attrs.width) } : {},\n },\n height: {\n default: null,\n parseHTML: (element) => {\n const raw = element.getAttribute('height');\n if (!raw) return null;\n const n = parseInt(raw, 10);\n return Number.isFinite(n) && n > 0 ? n : null;\n },\n renderHTML: (attrs: { height?: number | null }) =>\n attrs.height ? { height: String(attrs.height) } : {},\n },\n };\n },\n addNodeView() {\n return ReactNodeViewRenderer(ImageComponent);\n },\n});\n","/**\n * Detect image URLs that were malformed by an MS \"Save Page As Web Page\" /\n * pandoc import: a relative path like `mikehome_files/foo.png` gets\n * `http://` prepended somewhere upstream, so the URL parser interprets\n * `mikehome_files` as a hostname. The browser then either fails to load\n * the image or has it blocked by CSP.\n *\n * Heuristic: hostname has no dots and no port, and ends in `_files` —\n * that's the Word-style asset-folder naming convention, not a real host.\n *\n * Returns the recovered relative path (e.g. `mikehome_files/foo.png`)\n * when the shape matches, or `null` otherwise.\n */\nexport function normalizeMalformedAssetUrl(src: string | null | undefined): string | null {\n if (!src) return null;\n const match = src.match(/^https?:\\/\\/([^/?#]+)\\/(.+)$/i);\n if (!match) return null;\n const [, host, rest] = match;\n if (host.includes('.') || host.includes(':')) return null;\n if (!host.toLowerCase().endsWith('_files')) return null;\n return `${host}/${rest}`;\n}\n","/**\n * TiptapVideo — block-level atom Tiptap node for HTML5 `<video>` elements.\n *\n * Without this extension, Tiptap's StarterKit strips unknown HTML tags\n * when parsing the editor's content. By registering `<video>` as a known\n * node, the editor can render a recording's inline player inside the\n * WYSIWYG surface and round-trip the tag through markdown.\n *\n * The NodeView renders a real `<video controls>` whose src is resolved\n * through the EditorContext's MediaProvider — same mechanism\n * `ImageNodeView` uses for `<img>`.\n */\nimport { Node, mergeAttributes } from '@tiptap/core';\nimport { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react';\nimport type { NodeViewProps } from '@tiptap/react';\nimport { useResolvedMediaSrc } from './useResolvedMediaSrc.js';\n\nexport interface TiptapVideoOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n video: {\n setVideo: (attrs: {\n src: string;\n width?: number | string | null;\n controls?: boolean;\n }) => ReturnType;\n };\n }\n}\n\nfunction VideoNodeView({ node }: NodeViewProps) {\n const { src, width, height, poster, controls } = node.attrs as {\n src: string;\n width: string | number | null;\n height: string | number | null;\n poster: string | null;\n controls: boolean;\n };\n const resolvedSrc = useResolvedMediaSrc(src ?? '');\n // Resolve poster through the same provider when present so a\n // workspace-local frame thumbnail also renders inside the editor.\n const resolvedPoster = useResolvedMediaSrc(poster ?? '');\n\n return (\n <NodeViewWrapper\n as=\"span\"\n className=\"squisq-inline-video-player\"\n // Mark as a drag handle so ProseMirror moves the node when the user\n // drags it, rather than the browser starting a native media-drag.\n data-drag-handle\n draggable\n >\n <video\n src={resolvedSrc || undefined}\n poster={poster ? resolvedPoster : undefined}\n controls={controls}\n playsInline\n preload=\"metadata\"\n width={width ?? undefined}\n height={height ?? undefined}\n />\n </NodeViewWrapper>\n );\n}\n\nexport const TiptapVideo = Node.create<TiptapVideoOptions>({\n name: 'video',\n group: 'block',\n atom: true,\n draggable: true,\n selectable: true,\n\n addOptions() {\n return { HTMLAttributes: {} };\n },\n\n addAttributes() {\n return {\n src: { default: null },\n width: { default: null },\n height: { default: null },\n poster: { default: null },\n // The HTML5 `controls` attribute is boolean-presence; parse its\n // existence (even with an empty string value) as `true`, otherwise\n // default to true (we want recordings to be playable by default).\n controls: {\n default: true,\n parseHTML: (el) => el.hasAttribute('controls'),\n renderHTML: (attrs) => (attrs.controls ? { controls: '' } : {}),\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'video' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['video', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(VideoNodeView);\n },\n\n addCommands() {\n return {\n setVideo:\n (attrs) =>\n ({ commands }) =>\n commands.insertContent({ type: this.name, attrs }),\n };\n },\n});\n\nexport default TiptapVideo;\n","/**\n * useResolvedMediaSrc — resolve a relative media path through the\n * EditorContext's MediaProvider, mirroring the pattern used by\n * `ImageNodeView`. Returns the resolved URL (or the original `src`\n * when no provider is available, the path is absolute, or resolution\n * fails). Used by the Tiptap video / audio NodeViews so a relative\n * `audio/foo.webm` plays from the workspace container instead of\n * 404-ing against the dev server.\n */\nimport { useEffect, useState } from 'react';\nimport { useEditorContext } from '../EditorContext.js';\n\nexport function useResolvedMediaSrc(src: string): string {\n const { mediaProvider, mediaRevision } = useEditorContext();\n const [resolved, setResolved] = useState(src);\n\n const isRelative =\n !!src &&\n !src.startsWith('blob:') &&\n !src.startsWith('http:') &&\n !src.startsWith('https:') &&\n !src.startsWith('data:') &&\n !src.startsWith('/');\n\n useEffect(() => {\n if (!mediaProvider || !isRelative) {\n setResolved(src);\n return;\n }\n let cancelled = false;\n mediaProvider.resolveUrl(src).then(\n (url) => {\n if (!cancelled) setResolved(url);\n },\n () => {\n if (!cancelled) setResolved(src);\n },\n );\n return () => {\n cancelled = true;\n };\n // `mediaRevision` bumps after writes — re-resolve so the player\n // picks up the new blob URL after a re-record / edit.\n }, [src, isRelative, mediaProvider, mediaRevision]);\n\n return resolved;\n}\n","/**\n * TiptapAudio — inline atom Tiptap node for HTML5 `<audio>` elements.\n *\n * Lets the WYSIWYG editor preserve `<audio>` tags that the recorder\n * drops into the markdown for narration / voice recordings, and render\n * a native playback control inside the editor surface. The resolved src\n * goes through the EditorContext's MediaProvider so a workspace-local\n * `audio/foo.webm` returns a blob URL.\n */\nimport { Node, mergeAttributes } from '@tiptap/core';\nimport { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react';\nimport type { NodeViewProps } from '@tiptap/react';\nimport { useResolvedMediaSrc } from './useResolvedMediaSrc.js';\n\nexport interface TiptapAudioOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n audio: {\n setAudio: (attrs: { src: string; controls?: boolean }) => ReturnType;\n };\n }\n}\n\nfunction AudioNodeView({ node }: NodeViewProps) {\n const { src, controls } = node.attrs as { src: string; controls: boolean };\n const resolvedSrc = useResolvedMediaSrc(src ?? '');\n\n return (\n <NodeViewWrapper as=\"span\" className=\"squisq-inline-audio-player\" data-drag-handle draggable>\n <audio src={resolvedSrc || undefined} controls={controls} preload=\"metadata\" />\n </NodeViewWrapper>\n );\n}\n\nexport const TiptapAudio = Node.create<TiptapAudioOptions>({\n name: 'audio',\n // Block-level so each recording lives on its own line in the WYSIWYG —\n // matches how the recorder inserts the tag (on a fresh line) and\n // avoids odd inline-flow alignment when the native controls take more\n // vertical space than a line of text.\n group: 'block',\n atom: true,\n draggable: true,\n selectable: true,\n\n addOptions() {\n return { HTMLAttributes: {} };\n },\n\n addAttributes() {\n return {\n src: { default: null },\n controls: {\n default: true,\n parseHTML: (el) => el.hasAttribute('controls'),\n renderHTML: (attrs) => (attrs.controls ? { controls: '' } : {}),\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'audio' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['audio', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(AudioNodeView);\n },\n\n addCommands() {\n return {\n setAudio:\n (attrs) =>\n ({ commands }) =>\n commands.insertContent({ type: this.name, attrs }),\n };\n },\n});\n\nexport default TiptapAudio;\n","/**\n * MentionExtension\n *\n * Tiptap mention configuration paired with a small absolutely-positioned\n * suggestion popover. Shares a caller-supplied async provider (see\n * `MentionProvider` in EditorContext) with the Monaco `@` completion\n * provider in `RawEditor`, so both editing modes surface the same roster.\n *\n * The mention chip renders as `<span data-mention data-kind data-id\n * data-label class=\"mention\">@Label</span>`, matching the wire format that\n * `tiptapBridge` emits when converting markdown → Tiptap HTML. On serialize\n * back to markdown, the bridge emits `@[Label](kind:id)`.\n */\n\nimport Mention from '@tiptap/extension-mention';\nimport { PluginKey } from '@tiptap/pm/state';\nimport type { Editor, Range } from '@tiptap/core';\nimport type { MentionCandidate, MentionProvider } from './EditorContext';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype SuggestionProps = any;\n\n/**\n * Fallback namespace for defensive code paths — used when a mention node\n * somehow lacks a `kind` attribute (e.g. legacy HTML parsed without one).\n * Inserts from the suggestion popover always carry the candidate's own\n * `scheme`, so this only surfaces for malformed/legacy content.\n */\nconst FALLBACK_KIND = 'mention';\n\ntype SuggestionState = {\n items: MentionCandidate[];\n selected: number;\n};\n\n/**\n * Build the Tiptap mention extension for an editor. The returned extension\n * captures a reference to `getProvider` at configure-time and calls it on\n * every keystroke — keep the reference stable so we don't recreate the\n * editor just to change who answers the `@` query.\n */\nexport function buildMentionExtension(getProvider: () => MentionProvider | null) {\n return Mention.configure({\n HTMLAttributes: {\n class: 'mention',\n 'data-mention': 'true',\n },\n renderHTML({ options, node }) {\n const label =\n (node.attrs.label as string | undefined) ?? (node.attrs.id as string | undefined) ?? '';\n const id = (node.attrs.id as string | undefined) ?? '';\n const kind = (node.attrs.kind as string | undefined) ?? FALLBACK_KIND;\n return [\n 'span',\n {\n ...options.HTMLAttributes,\n 'data-kind': kind,\n 'data-id': id,\n 'data-label': label,\n },\n `@${label}`,\n ];\n },\n renderText({ node }) {\n const label =\n (node.attrs.label as string | undefined) ?? (node.attrs.id as string | undefined) ?? '';\n const id = (node.attrs.id as string | undefined) ?? '';\n const kind = (node.attrs.kind as string | undefined) ?? FALLBACK_KIND;\n return `@[${label}](${kind}:${id})`;\n },\n }).extend({\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (el) => el.getAttribute('data-id'),\n renderHTML: (attrs) => (attrs.id ? { 'data-id': attrs.id } : {}),\n },\n label: {\n default: null,\n parseHTML: (el) => el.getAttribute('data-label'),\n renderHTML: (attrs) => (attrs.label ? { 'data-label': attrs.label } : {}),\n },\n kind: {\n default: FALLBACK_KIND,\n parseHTML: (el) => el.getAttribute('data-kind') ?? FALLBACK_KIND,\n renderHTML: (attrs) => ({ 'data-kind': attrs.kind ?? FALLBACK_KIND }),\n },\n };\n },\n addOptions() {\n return {\n ...(this.parent?.() ?? {}),\n suggestion: {\n char: '@',\n // Custom plugin key so the mention suggestion doesn't collide\n // with any future `:` or `/` popovers.\n pluginKey: new PluginKey('mentionSuggestion'),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n command: ({ editor, range, props }: { editor: Editor; range: Range; props: any }) => {\n const id = (props?.id as string | null) ?? '';\n const label = (props?.label as string | null) ?? id;\n const kind = (props?.kind as string | undefined) ?? FALLBACK_KIND;\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: 'mention',\n attrs: { id, label, kind },\n },\n { type: 'text', text: ' ' },\n ])\n .run();\n },\n items: async ({ query }: { query: string }) => {\n const provider = getProvider();\n if (!provider) return [];\n try {\n return await provider(query);\n } catch {\n return [];\n }\n },\n render: renderSuggestionFactory(),\n },\n };\n },\n });\n}\n\n/**\n * Lightweight suggestion popover. Uses a plain absolutely-positioned div\n * anchored to the caret rect — no tippy.js needed. Keyboard nav handled via\n * the `onKeyDown` hook Tiptap wires up.\n */\nfunction renderSuggestionFactory() {\n return () => {\n let container: HTMLDivElement | null = null;\n let state: SuggestionState = { items: [], selected: 0 };\n let currentProps: SuggestionProps | null = null;\n\n const update = () => {\n if (!container || !currentProps) return;\n container.innerHTML = '';\n if (state.items.length === 0) {\n container.style.display = 'none';\n return;\n }\n container.style.display = 'block';\n\n for (let i = 0; i < state.items.length; i++) {\n const item = state.items[i];\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'squisq-mention-item' + (i === state.selected ? ' is-selected' : '');\n btn.dataset.index = String(i);\n btn.innerHTML = '';\n const label = document.createElement('span');\n label.className = 'squisq-mention-label';\n label.textContent = item.label;\n btn.appendChild(label);\n if (item.description) {\n const desc = document.createElement('span');\n desc.className = 'squisq-mention-desc';\n desc.textContent = item.description;\n btn.appendChild(desc);\n }\n btn.addEventListener('mousedown', (ev) => {\n ev.preventDefault();\n selectAt(i);\n });\n container.appendChild(btn);\n }\n\n positionTo(container, currentProps.clientRect);\n };\n\n const selectAt = (index: number) => {\n const item = state.items[index];\n if (!item || !currentProps) return;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const command = (currentProps as any).command;\n if (typeof command === 'function') {\n command({ id: item.id, label: item.label, kind: item.scheme });\n }\n };\n\n return {\n onStart: (props: SuggestionProps) => {\n currentProps = props;\n state = { items: props.items ?? [], selected: 0 };\n if (!container) {\n container = document.createElement('div');\n container.className = 'squisq-mention-popover';\n container.style.position = 'absolute';\n container.style.zIndex = '10000';\n document.body.appendChild(container);\n }\n update();\n },\n onUpdate: (props: SuggestionProps) => {\n currentProps = props;\n if (Array.isArray(props.items)) {\n state = { items: props.items, selected: 0 };\n }\n update();\n },\n onKeyDown: ({ event }: { event: KeyboardEvent }) => {\n if (!state.items.length) return false;\n if (event.key === 'ArrowDown') {\n state.selected = (state.selected + 1) % state.items.length;\n update();\n return true;\n }\n if (event.key === 'ArrowUp') {\n state.selected = (state.selected - 1 + state.items.length) % state.items.length;\n update();\n return true;\n }\n if (event.key === 'Enter' || event.key === 'Tab') {\n selectAt(state.selected);\n return true;\n }\n if (event.key === 'Escape') {\n state = { items: [], selected: 0 };\n update();\n return true;\n }\n return false;\n },\n onExit: () => {\n if (container?.parentNode) container.parentNode.removeChild(container);\n container = null;\n currentProps = null;\n },\n };\n };\n}\n\nfunction positionTo(\n el: HTMLDivElement,\n clientRect: (() => DOMRect | null) | null | undefined,\n): void {\n const rect = clientRect?.();\n if (!rect) return;\n // Anchor above the caret first — chat composers live near the\n // bottom of the viewport, where a \"below\" popover gets clipped or\n // covers the just-typed text. Fall back to below only when there's\n // no room above (top of a long document, etc.).\n const viewportH = window.innerHeight;\n const estH = Math.min(el.offsetHeight || 240, viewportH - 16);\n const above = rect.top - estH - 4;\n const fitsAbove = above >= 0;\n el.style.left = `${rect.left + window.scrollX}px`;\n if (fitsAbove) {\n el.style.top = `${above + window.scrollY}px`;\n } else {\n el.style.top = `${rect.bottom + 4 + window.scrollY}px`;\n }\n}\n","/**\n * Markdown detection — heuristic for spotting markdown source in pasted text.\n *\n * Used by the WYSIWYG editor's paste handler to decide whether plain-text\n * paste content should be parsed as markdown rather than inserted literally.\n *\n * The heuristic prefers false negatives (treating markdown as plain text)\n * over false positives (mangling plain text that happens to contain a few\n * special characters).\n */\n\n/** Block-level patterns that strongly indicate markdown. Any one is enough. */\nconst STRONG_BLOCK_PATTERNS: RegExp[] = [\n /^#{1,6}\\s+\\S/, // # Heading\n /^[-*+]\\s+\\S/, // - bullet\n /^\\d+\\.\\s+\\S/, // 1. ordered\n /^>\\s+\\S/, // > blockquote\n /^```/, // ``` code fence\n /^\\|.+\\|\\s*$/, // | table | row |\n /^[-*+]\\s+\\[[ xX]\\]\\s+/, // - [ ] task\n];\n\n/** Inline patterns that are weaker indicators on their own. */\nconst INLINE_PATTERNS: RegExp[] = [\n /\\*\\*[^*\\n]+\\*\\*/, // **bold**\n /__[^_\\n]+__/, // __bold__\n /`[^`\\n]+`/, // `code`\n /\\[[^\\]\\n]+\\]\\([^)\\n]+\\)/, // [link](url)\n /!\\[[^\\]\\n]*\\]\\([^)\\n]+\\)/, // ![image](url)\n /~~[^~\\n]+~~/, // ~~strike~~\n];\n\n/**\n * Returns true if the text looks like markdown source.\n *\n * Detection rules:\n * - Any line matching a strong block pattern → yes\n * - Two or more inline pattern matches anywhere in the text → yes\n * - Otherwise → no\n */\nexport function looksLikeMarkdown(text: string): boolean {\n if (!text || text.length < 2) return false;\n\n const lines = text.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n for (const re of STRONG_BLOCK_PATTERNS) {\n if (re.test(trimmed)) return true;\n }\n }\n\n let inlineHits = 0;\n for (const re of INLINE_PATTERNS) {\n if (re.test(text)) {\n inlineHits++;\n if (inlineHits >= 2) return true;\n }\n }\n\n return false;\n}\n","/* eslint-disable react-refresh/only-export-components */\n/**\n * PreviewControls\n *\n * Shared context and inline toolbar component for preview settings\n * (viewport format, display mode, theme, transform, caption style).\n *\n * The context is provided by EditorShell and consumed by both:\n * - PreviewControls (toolbar dropdowns, rendered in the main toolbar)\n * - PreviewPanel (the actual player, which reads the selected values)\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useState,\n useMemo,\n useEffect,\n useRef,\n} from 'react';\nimport type { ReactNode } from 'react';\nimport type { DisplayMode, CaptionStyle } from '@bendyline/squisq-react';\nimport type { ViewportPreset, ViewportConfig } from '@bendyline/squisq/schemas';\nimport { VIEWPORT_PRESETS, getThemeSummaries, resolveTheme } from '@bendyline/squisq/schemas';\nimport type { Theme } from '@bendyline/squisq/schemas';\nimport { ThemePicker } from './ThemePicker';\nimport { getTransformStyleSummaries } from '@bendyline/squisq/transform';\nimport type { Doc } from '@bendyline/squisq/schemas';\nimport { setFrontmatterValues } from '@bendyline/squisq/markdown';\nimport { useEditorContext } from './EditorContext';\n\n// ── Context ──────────────────────────────────────────────────────\n\nexport interface PreviewSettings {\n activePreset: ViewportPreset;\n setSelectedPreset: (preset: ViewportPreset | null) => void;\n activeViewport: ViewportConfig;\n activeDisplayMode: DisplayMode;\n setSelectedDisplayMode: (mode: DisplayMode | null) => void;\n activeThemeId: string;\n setSelectedThemeId: (id: string | null) => void;\n activeTheme: Theme;\n activeTransformStyle: string;\n setSelectedTransformStyle: (id: string | null) => void;\n activeCaptionStyle: CaptionStyle;\n setSelectedCaptionStyle: (style: CaptionStyle | null) => void;\n}\n\nconst PreviewSettingsContext = createContext<PreviewSettings | null>(null);\n\nexport function usePreviewSettings(): PreviewSettings {\n const ctx = useContext(PreviewSettingsContext);\n if (!ctx) throw new Error('usePreviewSettings must be used within PreviewSettingsProvider');\n return ctx;\n}\n\n/**\n * Like {@link usePreviewSettings} but returns `null` when no provider is\n * mounted. For consumers (e.g. WysiwygEditor) that want to react to the\n * active theme when available without forcing every test harness to\n * wrap them in a PreviewSettingsProvider.\n */\nexport function usePreviewSettingsOptional(): PreviewSettings | null {\n return useContext(PreviewSettingsContext);\n}\n\n// ── Frontmatter resolvers ────────────────────────────────────────\n\nfunction resolveRenderAs(value: unknown): ViewportPreset | null {\n if (typeof value !== 'string') return null;\n const v = value.trim().toLowerCase();\n const mapping: Record<string, ViewportPreset> = {\n landscape: 'landscape',\n '16:9': 'landscape',\n widescreen: 'landscape',\n portrait: 'portrait',\n '9:16': 'portrait',\n vertical: 'portrait',\n stories: 'portrait',\n square: 'square',\n '1:1': 'square',\n standard: 'standard',\n '4:3': 'standard',\n };\n return mapping[v] ?? null;\n}\n\nfunction resolveDisplayMode(value: unknown): DisplayMode | null {\n if (typeof value !== 'string') return null;\n const v = value.trim().toLowerCase();\n if (v === 'video' || v === 'slideshow' || v === 'linear' || v === 'page') return v;\n if (v === 'slides' || v === 'presentation' || v === 'deck') return 'slideshow';\n if (v === 'document' || v === 'scroll') return 'linear';\n if (v === 'html' || v === 'plain' || v === 'reader') return 'page';\n return null;\n}\n\nconst VALID_THEME_IDS = new Set(getThemeSummaries().map((s) => s.id));\n\nfunction resolveFrontmatterTheme(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const v = value.trim().toLowerCase();\n if (VALID_THEME_IDS.has(v)) return v;\n const normalized = v.replace(/\\s+/g, '-');\n if (VALID_THEME_IDS.has(normalized)) return normalized;\n return null;\n}\n\nconst VALID_TRANSFORM_IDS = new Set(getTransformStyleSummaries().map((s) => s.id));\n\nfunction resolveFrontmatterTransform(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const v = value.trim().toLowerCase();\n if (VALID_TRANSFORM_IDS.has(v)) return v;\n const normalized = v.replace(/\\s+/g, '-');\n if (VALID_TRANSFORM_IDS.has(normalized)) return normalized;\n return null;\n}\n\nfunction resolveFrontmatterCaptionStyle(value: unknown): CaptionStyle | null {\n if (typeof value !== 'string') return null;\n const v = value.trim().toLowerCase();\n if (v === 'standard' || v === 'social') return v;\n if (v === 'instagram' || v === 'tiktok' || v === 'reels') return 'social';\n return null;\n}\n\n// ── Provider ─────────────────────────────────────────────────────\n\nexport interface PreviewSettingsProviderProps {\n doc: Doc | null;\n children: ReactNode;\n /**\n * Optional Theme to use for the preview, regardless of `Doc.themeId` or\n * the user's theme dropdown selection. Used by the theme customizer to\n * preview an in-progress theme without mutating the document. When\n * present, `activeTheme` is this value and `activeThemeId` is its `id`.\n */\n themeOverride?: Theme | null;\n}\n\n/** Frontmatter keys we read/write for preview settings. The squisq-prefixed\n * keys are the canonical names; the legacy keys are still read so existing\n * documents keep working. Persistence (writes) uses only the squisq names. */\nconst FM_KEYS = {\n theme: { canonical: 'squisq-theme', legacy: 'theme' as const },\n transform: { canonical: 'squisq-transform', legacy: 'transform-style' as const },\n captions: { canonical: 'squisq-captions', legacy: 'caption-style' as const },\n} as const;\n\nfunction readFrontmatterKey(\n fm: Record<string, unknown> | undefined,\n canonical: string,\n legacy: string,\n): unknown {\n if (!fm) return undefined;\n return Object.prototype.hasOwnProperty.call(fm, canonical) ? fm[canonical] : fm[legacy];\n}\n\nexport function PreviewSettingsProvider({\n doc,\n children,\n themeOverride,\n}: PreviewSettingsProviderProps) {\n const frontmatter = doc?.frontmatter;\n const { markdownSource, setMarkdownSource } = useEditorContext();\n\n const persistFrontmatter = useCallback(\n (updates: Record<string, string | null>) => {\n const next = setFrontmatterValues(markdownSource, updates);\n if (next !== markdownSource) {\n setMarkdownSource(next);\n }\n },\n [markdownSource, setMarkdownSource],\n );\n\n // Viewport\n const fmPreset = useMemo(\n () => resolveRenderAs(frontmatter?.['document-render-as']),\n [frontmatter],\n );\n const [selectedPreset, setSelectedPreset] = useState<ViewportPreset | null>(null);\n useEffect(() => setSelectedPreset(null), [fmPreset]);\n const activePreset = selectedPreset ?? fmPreset ?? 'landscape';\n const activeViewport = VIEWPORT_PRESETS[activePreset];\n\n // Display mode\n const fmMode = useMemo(() => resolveDisplayMode(frontmatter?.['display-mode']), [frontmatter]);\n const [selectedDisplayMode, setSelectedDisplayMode] = useState<DisplayMode | null>(null);\n useEffect(() => setSelectedDisplayMode(null), [fmMode]);\n const activeDisplayMode = selectedDisplayMode ?? fmMode ?? 'video';\n\n // Theme — persisted to `squisq-theme` (legacy `theme` still read for compat)\n const fmTheme = useMemo(\n () =>\n resolveFrontmatterTheme(\n readFrontmatterKey(frontmatter, FM_KEYS.theme.canonical, FM_KEYS.theme.legacy),\n ),\n [frontmatter],\n );\n const [selectedThemeId, setSelectedThemeId] = useState<string | null>(null);\n useEffect(() => setSelectedThemeId(null), [fmTheme]);\n const resolvedThemeId = selectedThemeId ?? fmTheme ?? 'standard';\n const resolvedTheme = useMemo(() => resolveTheme(resolvedThemeId), [resolvedThemeId]);\n // themeOverride wins over both dropdown selection and frontmatter\n const activeThemeId = themeOverride?.id ?? resolvedThemeId;\n const activeTheme = themeOverride ?? resolvedTheme;\n const handleSetThemeId = useCallback(\n (id: string | null) => {\n setSelectedThemeId(id);\n if (id !== null) persistFrontmatter({ [FM_KEYS.theme.canonical]: id });\n },\n [persistFrontmatter],\n );\n\n // Transform — persisted to `squisq-transform` (legacy `transform-style` read for compat)\n const fmTransform = useMemo(\n () =>\n resolveFrontmatterTransform(\n readFrontmatterKey(frontmatter, FM_KEYS.transform.canonical, FM_KEYS.transform.legacy),\n ),\n [frontmatter],\n );\n const [selectedTransformStyle, setSelectedTransformStyle] = useState<string | null>(null);\n useEffect(() => setSelectedTransformStyle(null), [fmTransform]);\n const activeTransformStyle = selectedTransformStyle ?? fmTransform ?? '';\n const handleSetTransformStyle = useCallback(\n (id: string | null) => {\n setSelectedTransformStyle(id);\n if (id !== null) {\n // Empty string = \"None\" — remove the key rather than writing a blank value.\n persistFrontmatter({ [FM_KEYS.transform.canonical]: id === '' ? null : id });\n }\n },\n [persistFrontmatter],\n );\n\n // Caption style — persisted to `squisq-captions` (legacy `caption-style` read for compat)\n const fmCaption = useMemo(\n () =>\n resolveFrontmatterCaptionStyle(\n readFrontmatterKey(frontmatter, FM_KEYS.captions.canonical, FM_KEYS.captions.legacy),\n ),\n [frontmatter],\n );\n const [selectedCaptionStyle, setSelectedCaptionStyle] = useState<CaptionStyle | null>(null);\n useEffect(() => setSelectedCaptionStyle(null), [fmCaption]);\n const activeCaptionStyle = selectedCaptionStyle ?? fmCaption ?? 'standard';\n const handleSetCaptionStyle = useCallback(\n (style: CaptionStyle | null) => {\n setSelectedCaptionStyle(style);\n if (style !== null) persistFrontmatter({ [FM_KEYS.captions.canonical]: style });\n },\n [persistFrontmatter],\n );\n\n const value = useMemo<PreviewSettings>(\n () => ({\n activePreset,\n setSelectedPreset,\n activeViewport,\n activeDisplayMode,\n setSelectedDisplayMode,\n activeThemeId,\n setSelectedThemeId: handleSetThemeId,\n activeTheme,\n activeTransformStyle,\n setSelectedTransformStyle: handleSetTransformStyle,\n activeCaptionStyle,\n setSelectedCaptionStyle: handleSetCaptionStyle,\n }),\n [\n activePreset,\n activeViewport,\n activeDisplayMode,\n activeThemeId,\n activeTheme,\n activeTransformStyle,\n activeCaptionStyle,\n handleSetThemeId,\n handleSetTransformStyle,\n handleSetCaptionStyle,\n ],\n );\n\n return (\n <PreviewSettingsContext.Provider value={value}>{children}</PreviewSettingsContext.Provider>\n );\n}\n\n// ── Dropdown options ─────────────────────────────────────────────\n\nconst VIEWPORT_OPTIONS: { key: ViewportPreset; label: string }[] = [\n { key: 'landscape', label: '16:9' },\n { key: 'portrait', label: '9:16' },\n { key: 'square', label: '1:1' },\n { key: 'standard', label: '4:3' },\n];\n\nconst DISPLAY_MODE_OPTIONS: { key: DisplayMode; label: string }[] = [\n { key: 'video', label: 'Video' },\n { key: 'slideshow', label: 'Slideshow' },\n { key: 'linear', label: 'Document' },\n { key: 'page', label: 'Page' },\n];\n\nconst TRANSFORM_STYLE_OPTIONS = [\n { key: '', label: 'None' },\n ...getTransformStyleSummaries().map((s) => ({ key: s.id, label: s.name })),\n];\n\nconst CAPTION_STYLE_OPTIONS: { key: CaptionStyle; label: string }[] = [\n { key: 'standard', label: 'Standard' },\n { key: 'social', label: 'Social' },\n];\n\n// ── Shared styles ────────────────────────────────────────────────\n\nconst labelStyle: React.CSSProperties = {\n color: 'var(--squisq-text-muted, #6b7280)',\n fontSize: '12px',\n whiteSpace: 'nowrap',\n};\n\nconst selectStyle: React.CSSProperties = {\n padding: '2px 6px',\n borderRadius: '4px',\n border: '1px solid var(--squisq-border, #d1d5db)',\n background: 'var(--squisq-input-bg, #fff)',\n color: 'var(--squisq-text, #1f2937)',\n fontSize: '12px',\n cursor: 'pointer',\n};\n\n// ── Toolbar Controls Component ───────────────────────────────────\n\n/** Hook to track whether the viewport is narrow. */\nfunction useIsNarrow(breakpoint = 600): boolean {\n const [narrow, setNarrow] = useState(\n () => typeof window !== 'undefined' && window.innerWidth <= breakpoint,\n );\n useEffect(() => {\n const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);\n const handler = (e: MediaQueryListEvent) => setNarrow(e.matches);\n mq.addEventListener('change', handler);\n return () => mq.removeEventListener('change', handler);\n }, [breakpoint]);\n return narrow;\n}\n\n/**\n * Inline preview controls rendered in the main toolbar row.\n * On narrow viewports, collapses into a single settings button with a dropdown.\n */\nexport function PreviewToolbarControls() {\n const s = usePreviewSettings();\n const isNarrow = useIsNarrow(768);\n const [popoverOpen, setPopoverOpen] = useState(false);\n const popoverRef = useRef<HTMLDivElement>(null);\n\n // Close popover on outside click\n useEffect(() => {\n if (!popoverOpen) return;\n const handler = (e: MouseEvent) => {\n if (popoverRef.current && !popoverRef.current.contains(e.target as Node)) {\n setPopoverOpen(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [popoverOpen]);\n\n const controls = (\n <>\n <PreviewSelect\n label=\"Format\"\n value={s.activePreset}\n options={VIEWPORT_OPTIONS}\n onChange={(v) => s.setSelectedPreset(v as ViewportPreset)}\n compact={isNarrow}\n />\n <PreviewSelect\n label=\"Mode\"\n value={s.activeDisplayMode}\n options={DISPLAY_MODE_OPTIONS}\n onChange={(v) => s.setSelectedDisplayMode(v as DisplayMode)}\n compact={isNarrow}\n />\n <div\n className={`squisq-preview-control${isNarrow ? ' squisq-preview-control--compact' : ''}`}\n >\n <label style={labelStyle}>Theme:</label>\n <ThemePicker\n value={s.activeThemeId}\n onChange={(v) => s.setSelectedThemeId(v)}\n ariaLabel=\"Theme\"\n />\n </div>\n <PreviewSelect\n label=\"Transform\"\n value={s.activeTransformStyle}\n options={TRANSFORM_STYLE_OPTIONS}\n onChange={(v) => s.setSelectedTransformStyle(v)}\n compact={isNarrow}\n />\n <PreviewSelect\n label=\"Captions\"\n value={s.activeCaptionStyle}\n options={CAPTION_STYLE_OPTIONS}\n onChange={(v) => s.setSelectedCaptionStyle(v as CaptionStyle)}\n compact={isNarrow}\n />\n </>\n );\n\n if (isNarrow) {\n return (\n <div className=\"squisq-preview-controls-compact\" ref={popoverRef}>\n <button\n className=\"squisq-toolbar-button\"\n onClick={() => setPopoverOpen((v) => !v)}\n aria-label=\"Preview settings\"\n title=\"Preview settings\"\n aria-expanded={popoverOpen}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"2.5\" />\n <path d=\"M13.5 8a5.5 5.5 0 01-.4 1.8l1.2 1.2-1.6 1.6-1.2-1.2A5.5 5.5 0 018 13.5a5.5 5.5 0 01-3.5-1.3L3.3 13.4 1.7 11.8l1.2-1.2A5.5 5.5 0 012.5 8c0-.6.1-1.2.4-1.8L1.7 5 3.3 3.4l1.2 1.2A5.5 5.5 0 018 2.5c1.3 0 2.5.5 3.5 1.3l1.2-1.2 1.6 1.6-1.2 1.2c.3.6.4 1.2.4 1.6z\" />\n </svg>\n </button>\n {popoverOpen && <div className=\"squisq-preview-controls-popover\">{controls}</div>}\n </div>\n );\n }\n\n return <div className=\"squisq-preview-controls-inline\">{controls}</div>;\n}\n\nfunction PreviewSelect({\n label,\n value,\n options,\n onChange,\n compact,\n}: {\n label: string;\n value: string;\n options: { key: string; label: string }[];\n onChange: (value: string) => void;\n compact?: boolean;\n}) {\n return (\n <div className={`squisq-preview-control${compact ? ' squisq-preview-control--compact' : ''}`}>\n <label style={labelStyle}>{label}:</label>\n <select value={value} onChange={(e) => onChange(e.target.value)} style={selectStyle}>\n {options.map((o) => (\n <option key={o.key} value={o.key}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n );\n}\n","/**\n * InlinePreviewGutter\n *\n * Renders one small SVG preview card per template-annotated block in the\n * current document, positioned to vertically align with its corresponding\n * heading in whichever editor view is active. A diagonal connector line\n * + vertical block-extent bars bridge each heading and its preview card.\n *\n * The gutter consumes the parsed `Doc` from `useEditorContext()` and reuses\n * the same template-resolution path as `LinearDocView` (heading text →\n * template defaults → `getLayers()` → `BlockRenderer`).\n *\n * Auto-hides via container queries when the surrounding container is too\n * narrow (see `.squisq-editor-with-gutter` rules in `styles/editor.css`).\n *\n * Implementation notes:\n * - **View-agnostic positioning** — heading positions, page edges, and\n * click-to-scroll all come from `useHeadingLayout()`, which has\n * per-view backends (DOM-query for WYSIWYG, Monaco API for Markdown).\n * The component only handles card stacking (which needs rendered card\n * heights) and the visual rendering layer.\n * - **Card stacking** — cards are absolutely positioned with `top` set\n * from each heading's hook-supplied position. If two headings sit too\n * close together, the lower card slides down so cards never overlap;\n * the connector line then slopes from the (still heading-anchored)\n * bar across to the (now lower) card.\n */\n\nimport { useLayoutEffect, useMemo, useRef, useState, type CSSProperties } from 'react';\nimport type { Block, DocBlock, ViewportConfig } from '@bendyline/squisq/schemas';\nimport { VIEWPORT_PRESETS } from '@bendyline/squisq/schemas';\nimport {\n flattenBlocks,\n getLayers,\n hasTemplate,\n DEFAULT_THEME,\n type RenderContext,\n} from '@bendyline/squisq/doc';\nimport { extractPlainText, getChildren } from '@bendyline/squisq/markdown';\nimport { usePreviewSettingsOptional } from './PreviewControls';\nimport type {\n MarkdownBlockNode,\n MarkdownList,\n MarkdownNode,\n MarkdownTable,\n} from '@bendyline/squisq/markdown';\nimport { BlockRenderer, MediaContext } from '@bendyline/squisq-react';\nimport type { MediaProvider } from '@bendyline/squisq/schemas';\nimport { useEditorContext } from './EditorContext';\nimport { templateLabel } from './TemplatePicker';\nimport { useHeadingLayout } from './useHeadingLayout';\n\n// ── Helpers (mirrored from LinearDocView; kept local to avoid cross-package\n// churn — extract to a shared module if a fourth copy appears) ────────────\n\nfunction isAnnotated(block: Block): boolean {\n const annotation = block.sourceHeading?.templateAnnotation;\n if (!annotation) return false;\n return !!annotation.template && hasTemplate(annotation.template);\n}\n\nfunction extractBodyPlainText(contents?: MarkdownBlockNode[]): string {\n if (!contents || contents.length === 0) return '';\n return contents\n .map((n) => extractPlainText(n))\n .join('\\n')\n .trim();\n}\n\nfunction extractListItems(contents?: MarkdownBlockNode[]): string[] {\n if (!contents) return [];\n const items: string[] = [];\n for (const node of contents) {\n if (node.type === 'list') {\n for (const item of (node as MarkdownList).children) {\n const text = extractPlainText(item).trim();\n if (text) items.push(text);\n }\n }\n }\n return items;\n}\n\ninterface PreviewImage {\n src: string;\n alt: string;\n width?: number;\n height?: number;\n}\n\nfunction parseDim(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined;\n const n = parseFloat(raw);\n return Number.isFinite(n) && n > 0 ? n : undefined;\n}\n\nfunction extractBlockImages(contents?: MarkdownBlockNode[]): PreviewImage[] {\n if (!contents || contents.length === 0) return [];\n const images: PreviewImage[] = [];\n\n // Walk an HTML sub-DOM looking for <img src=\"...\"> elements that the\n // markdown parser produced for HTML-block / inline-HTML image tags.\n // (When WYSIWYG persists an explicit width/height the image round-trips\n // as <img …> rather than the ![](src) shorthand.)\n function walkHtml(node: {\n type: string;\n tagName?: string;\n attributes?: Record<string, string>;\n children?: unknown[];\n }): void {\n if (node.type === 'htmlElement' && node.tagName === 'img') {\n const src = node.attributes?.src;\n if (src) {\n images.push({\n src,\n alt: node.attributes?.alt ?? '',\n width: parseDim(node.attributes?.width),\n height: parseDim(node.attributes?.height),\n });\n }\n }\n if (Array.isArray(node.children)) {\n for (const child of node.children) {\n walkHtml(child as { type: string });\n }\n }\n }\n\n function walk(node: MarkdownNode): void {\n if ('type' in node && node.type === 'image' && 'url' in node) {\n const img = node as { url: string; alt?: string };\n if (img.url) images.push({ src: img.url, alt: img.alt ?? '' });\n }\n if ('type' in node && node.type === 'htmlBlock') {\n const block = node as unknown as { htmlChildren?: unknown[] };\n for (const child of block.htmlChildren ?? []) {\n walkHtml(child as { type: string });\n }\n }\n for (const child of getChildren(node)) walk(child);\n }\n for (const node of contents) walk(node);\n return images;\n}\n\n/** Like extractBlockImages, but also descends into the block's child blocks\n * so an annotated parent block can pick up media defined in a sub-section. */\nfunction collectImagesDeep(block: Block): PreviewImage[] {\n const images: PreviewImage[] = [];\n const seen = new Set<string>();\n function visit(b: Block): void {\n for (const img of extractBlockImages(b.contents)) {\n if (seen.has(img.src)) continue;\n seen.add(img.src);\n images.push(img);\n }\n for (const child of b.children ?? []) visit(child);\n }\n visit(block);\n return images;\n}\n\nfunction extractTableData(contents?: MarkdownBlockNode[]): {\n headers: string[];\n rows: string[][];\n align?: (('left' | 'right' | 'center') | null)[];\n} | null {\n if (!contents) return null;\n for (const node of contents) {\n if (node.type === 'table') {\n const table = node as MarkdownTable;\n const [headerRow, ...bodyRows] = table.children;\n if (!headerRow) return null;\n const headers = headerRow.children.map((cell) => extractPlainText(cell).trim());\n const rows = bodyRows.map((row) => row.children.map((cell) => extractPlainText(cell).trim()));\n return { headers, rows, align: table.align };\n }\n }\n return null;\n}\n\nfunction getTemplateDefaults(\n templateName: string,\n headingText: string,\n bodyText: string,\n contents?: MarkdownBlockNode[],\n images: PreviewImage[] = [],\n): Record<string, unknown> {\n switch (templateName) {\n case 'statHighlight':\n return { stat: headingText, description: bodyText || headingText };\n case 'quote':\n case 'fullBleedQuote':\n case 'pullQuote':\n return { quote: bodyText || headingText };\n case 'factCard':\n return { fact: headingText, explanation: bodyText || headingText };\n case 'comparisonBar':\n return { leftLabel: 'A', leftValue: 60, rightLabel: 'B', rightValue: 40 };\n case 'list': {\n const items = extractListItems(contents);\n return { items: items.length > 0 ? items : ['Item 1', 'Item 2', 'Item 3'] };\n }\n case 'definitionCard':\n return { term: headingText, definition: bodyText || headingText };\n case 'dateEvent':\n return { date: headingText, description: bodyText || headingText };\n case 'dataTable': {\n const tableData = extractTableData(contents);\n return tableData ?? { headers: ['Column'], rows: [['Data']] };\n }\n case 'imageWithCaption': {\n const first = images[0];\n return {\n imageSrc: first?.src ?? '',\n imageAlt: first?.alt ?? headingText,\n caption: bodyText || headingText,\n captionPosition: 'bottom',\n };\n }\n case 'leftFeature':\n case 'rightFeature': {\n // Mirror the LinearDocView / buildPreviewDoc defaults so the\n // mini gutter card shows the same content as the main preview.\n const first = images[0];\n return {\n imageSrc: first?.src ?? '',\n imageAlt: first?.alt ?? headingText,\n imageWidth: first?.width,\n imageHeight: first?.height,\n title: headingText,\n body: bodyText,\n };\n }\n case 'videoWithCaption': {\n const first = images[0];\n return {\n videoSrc: first?.src ?? '',\n caption: bodyText || headingText,\n captionPosition: 'bottom',\n };\n }\n default:\n return {};\n }\n}\n\n// ── Types ──────────────────────────────────────────────────────────\n\nexport interface InlinePreviewGutterProps {\n /** Width of the gutter in pixels (default: 320). */\n width?: number;\n /** Base path for resolving media URLs in card thumbnails. */\n basePath?: string;\n /** Viewport used to render each card (default: landscape preset). */\n viewport?: ViewportConfig;\n /** Optional CSS class for the outer container. */\n className?: string;\n /**\n * Width in pixels of the connector strip that bridges the editor and\n * the gutter. Defaults to 24.\n */\n connectorWidth?: number;\n /**\n * Optional MediaProvider used to resolve relative image src values inside\n * preview cards. When omitted, images with relative paths fall back to\n * `basePath`-prefixed URLs (which usually 404 in container-backed editors).\n */\n mediaProvider?: MediaProvider | null;\n}\n\ninterface PreviewItem {\n id: string;\n template: string;\n headingText: string;\n block: Block;\n}\n\n// ── Connector layout constants ─────────────────────────────────────\n\n/** Distance from the strip's right edge to the bar's right edge (px). */\nconst BAR_RIGHT_OFFSET = 14;\n/** Vertical offset within a card to the center of the caption row. Card\n * padding (8) + half line-height of the 12px label (~8) ≈ 16. */\nconst CARD_LABEL_OFFSET = 16;\n/** Vertical offset from heading top to the left connector dot. Matches\n * CARD_LABEL_OFFSET so the line is horizontal when the card sits at its\n * natural (heading-aligned) position. */\nconst EXTENT_TOP_PAD = CARD_LABEL_OFFSET;\n/** Card's `left: 12px` inside the gutter — used to land the right circle on\n * the card's left edge for the diagonal connector line. */\nconst CARD_LEFT_INSET = 12;\n\n// ── Component ──────────────────────────────────────────────────────\n\nexport function InlinePreviewGutter({\n width = 320,\n basePath = '/',\n viewport = VIEWPORT_PRESETS.landscape,\n className,\n connectorWidth = 24,\n mediaProvider = null,\n}: InlinePreviewGutterProps) {\n const { doc } = useEditorContext();\n const gutterRef = useRef<HTMLElement | null>(null);\n const { entries: headingEntries, scrollToBlock } = useHeadingLayout(gutterRef);\n // Follow the document's active theme so the mini cards reflect the\n // same palette as the main preview surface. PreviewSettingsProvider\n // resolves this from frontmatter (`squisq-theme` / legacy `theme`)\n // and theme overrides, so we never duplicate that logic here. Falls\n // back to DEFAULT_THEME when the gutter is mounted outside the\n // provider (defensive — EditorShell always wraps with it).\n const previewSettings = usePreviewSettingsOptional();\n const activeTheme = previewSettings?.activeTheme ?? DEFAULT_THEME;\n\n // Build the renderable PreviewItem list (just for annotated blocks).\n const items = useMemo<PreviewItem[]>(() => {\n if (!doc || !doc.blocks.length) return [];\n const flat = flattenBlocks(doc.blocks);\n const totalBlocks = flat.length;\n const result: PreviewItem[] = [];\n\n flat.forEach((block, index) => {\n if (!isAnnotated(block)) return;\n const annotation = block.sourceHeading!.templateAnnotation!;\n const template = annotation.template!;\n const headingText = block.sourceHeading ? extractPlainText(block.sourceHeading) : '';\n const bodyText = extractBodyPlainText(block.contents);\n\n const templateBlock: Record<string, unknown> = {\n id: block.id,\n template,\n startTime: 0,\n duration: 1,\n audioSegment: 0,\n title: headingText,\n ...getTemplateDefaults(\n template,\n headingText,\n bodyText,\n block.contents,\n collectImagesDeep(block),\n ),\n ...annotation.params,\n ...block.templateOverrides,\n };\n\n const ctx: RenderContext = {\n blockIndex: index,\n totalBlocks,\n theme: activeTheme,\n viewport,\n };\n\n try {\n const layers = getLayers(templateBlock as unknown as DocBlock, ctx);\n const visualBlock = {\n ...block,\n layers,\n template,\n } as Block;\n result.push({\n id: block.id,\n template,\n headingText,\n block: visualBlock,\n });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(`[InlinePreviewGutter] Skipped block \"${block.id}\" (${template}): ${message}`);\n }\n });\n\n return result;\n }, [doc, viewport, activeTheme]);\n\n // Heading top per item id — derived from the layout hook. The connector\n // dot tracks this even when stacking pushes the card below.\n const connectorTops = useMemo(() => {\n const m = new Map<string, number>();\n headingEntries.forEach((e) => m.set(e.block.id, e.top));\n return m;\n }, [headingEntries]);\n\n // Card stacking state — populated by a small post-render measurement\n // pass that reads each card's height to push subsequent cards down.\n const [positions, setPositions] = useState<Map<string, number>>(new Map());\n\n useLayoutEffect(() => {\n if (items.length === 0) {\n setPositions((prev) => (prev.size === 0 ? prev : new Map()));\n return;\n }\n const gutter = gutterRef.current;\n if (!gutter) return;\n const cardEls = gutter.querySelectorAll<HTMLElement>('.squisq-inline-preview-card');\n const STACK_GAP = 12;\n const FALLBACK_CARD_HEIGHT = 220;\n let lastBottom = -Infinity;\n const next = new Map<string, number>();\n items.forEach((item, i) => {\n const headingTop = connectorTops.get(item.id);\n if (headingTop == null) return;\n const top = Math.max(headingTop, lastBottom + STACK_GAP);\n next.set(item.id, top);\n const cardEl = cardEls[i];\n const cardHeight = cardEl ? cardEl.getBoundingClientRect().height : FALLBACK_CARD_HEIGHT;\n lastBottom = top + cardHeight;\n });\n setPositions((prev) => {\n if (prev.size === next.size) {\n let same = true;\n for (const [k, v] of next) {\n const p = prev.get(k);\n if (p == null || Math.abs(p - v) > 0.5) {\n same = false;\n break;\n }\n }\n if (same) return prev;\n }\n return next;\n });\n }, [items, connectorTops]);\n\n const isEmpty = items.length === 0;\n const totalWidth = width + connectorWidth;\n const gutterStyle: CSSProperties = {\n position: 'relative',\n width: `${totalWidth}px`,\n flex: `0 0 ${totalWidth}px`,\n overflow: 'hidden',\n };\n\n return (\n <aside\n ref={gutterRef}\n className={`squisq-inline-preview-gutter ${className ?? ''}`}\n style={gutterStyle}\n data-testid=\"inline-preview-gutter\"\n aria-label=\"Block previews\"\n >\n {/* Connector strip — vertical bracket bars per heading, on the\n left edge of the gutter so they sit immediately next to the\n editor body. */}\n {headingEntries.length > 0 && (\n <div\n className=\"squisq-inline-preview-connectors\"\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: connectorWidth,\n height: '100%',\n overflow: 'hidden',\n pointerEvents: 'none',\n }}\n >\n {headingEntries.map((ex, i) => {\n const EXTENT_GAP = 6;\n const height = Math.max(2, ex.bottom - ex.top - EXTENT_GAP);\n return (\n <div\n key={`h-${i}-${ex.block.id}`}\n className={`squisq-inline-preview-extent${\n ex.annotated ? '' : ' squisq-inline-preview-extent--untagged'\n }`}\n style={{\n position: 'absolute',\n top: `${ex.top}px`,\n height: `${height}px`,\n right: `${BAR_RIGHT_OFFSET}px`,\n }}\n />\n );\n })}\n </div>\n )}\n {/* Diagonal connector SVG — overlays the connector strip + the\n start of the card area, drawing a line from each bar to its\n card's caption row. */}\n {items.length > 0 && (\n <svg\n className=\"squisq-inline-preview-connector-svg\"\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: connectorWidth + CARD_LEFT_INSET,\n height: '100%',\n pointerEvents: 'none',\n overflow: 'visible',\n }}\n >\n {items.map((item) => {\n const headingTop = connectorTops.get(item.id);\n const cardTop = positions.get(item.id);\n if (headingTop == null || cardTop == null) return null;\n const x1 = connectorWidth - BAR_RIGHT_OFFSET - 2;\n const y1 = headingTop + EXTENT_TOP_PAD;\n const x2 = connectorWidth + CARD_LEFT_INSET;\n const y2 = cardTop + CARD_LABEL_OFFSET;\n return (\n <g key={item.id}>\n <line\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n stroke=\"#6366f1\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n <circle cx={x1} cy={y1} r=\"4\" fill=\"#6366f1\" stroke=\"#ffffff\" strokeWidth=\"2\" />\n <circle cx={x2} cy={y2} r=\"4\" fill=\"#6366f1\" stroke=\"#ffffff\" strokeWidth=\"2\" />\n </g>\n );\n })}\n </svg>\n )}\n\n {/* Card area — empty placeholder OR positioned cards. */}\n {isEmpty ? (\n <div\n className=\"squisq-inline-preview-empty\"\n style={{ position: 'absolute', top: 12, left: connectorWidth + 12, right: 12 }}\n >\n <p>Tag a heading with a template to see a preview here.</p>\n </div>\n ) : (\n <MediaContext.Provider value={mediaProvider ?? null}>\n {items.map((item) => {\n const top = positions.get(item.id);\n const hidden = top == null;\n return (\n <div\n key={item.id}\n className=\"squisq-inline-preview-card\"\n data-template={item.template}\n style={{\n position: 'absolute',\n top: `${top ?? 0}px`,\n left: connectorWidth + CARD_LEFT_INSET,\n right: 12,\n visibility: hidden ? 'hidden' : 'visible',\n }}\n onClick={() => scrollToBlock(item.block)}\n >\n <div className=\"squisq-inline-preview-card-label\">\n <span className=\"squisq-inline-preview-card-template\">\n {templateLabel(item.template)}\n </span>\n {item.headingText && (\n <>\n <span className=\"squisq-inline-preview-card-sep\">—</span>\n <span className=\"squisq-inline-preview-card-title\">{item.headingText}</span>\n </>\n )}\n </div>\n <div\n className=\"squisq-inline-preview-card-svg\"\n style={{\n aspectRatio: `${viewport.width} / ${viewport.height}`,\n }}\n >\n <BlockRenderer\n block={item.block}\n blockTime={0}\n basePath={basePath}\n viewport={viewport}\n />\n </div>\n </div>\n );\n })}\n </MediaContext.Provider>\n )}\n </aside>\n );\n}\n","/**\n * useHeadingLayout\n *\n * Shared positioning hook for the editor gutters (`OutlinePanel` and\n * `InlinePreviewGutter`). Each gutter needs to know:\n * - where every heading sits vertically inside the wrapper\n * - where the editor \"page\" edges sit horizontally\n * - how to scroll the editor to a particular heading\n *\n * Two backends, picked from `EditorContext.activeView`:\n * - **wysiwyg** — query DOM headings inside `.squisq-wysiwyg-container`,\n * measure with `getBoundingClientRect`, scroll via `scrollIntoView`.\n * Live updates via `ResizeObserver` + `MutationObserver`.\n * - **raw** — walk `doc.blocks`, derive each heading's line number from\n * `MarkdownHeading.position.start.line`, ask Monaco for the line's\n * pixel offset via `getTopForLineNumber`, scroll via\n * `revealLineInCenterIfOutsideViewport` + `setPosition`. Live updates\n * via `onDidScrollChange` + `onDidChangeModelContent`.\n *\n * Both backends produce coordinates in the *wrapper's* reference frame\n * (i.e., `.squisq-editor-with-gutter`), so the rendering layers — cards,\n * extent bars, outline rows — don't care which editor is active.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { RefObject } from 'react';\nimport type { Block } from '@bendyline/squisq/schemas';\nimport { flattenBlocks, hasTemplate } from '@bendyline/squisq/doc';\nimport { useEditorContext } from './EditorContext';\n\nexport interface HeadingLayoutEntry {\n /** The block (heading-rooted unit) this entry represents. */\n block: Block;\n /** Heading top, in px relative to the wrapper's top edge. */\n top: number;\n /** Where this block ends — the next heading's top, or the editor bottom. */\n bottom: number;\n /** True when the heading has a recognised template annotation. */\n annotated: boolean;\n}\n\nexport interface HeadingLayout {\n /** All headings, in document order. */\n entries: HeadingLayoutEntry[];\n /** Editor page's left/right edges, in px relative to the wrapper. */\n pageEdges: { left: number; right: number } | null;\n /** Scroll the active editor to bring the block's heading into view. */\n scrollToBlock: (block: Block) => void;\n /** True once a measurement has produced numbers (avoids flicker on mount). */\n ready: boolean;\n}\n\n/**\n * @param refInsideWrapper — any DOM ref under `.squisq-editor-with-gutter`.\n * The hook walks up to find the wrapper.\n */\nexport function useHeadingLayout(refInsideWrapper: RefObject<HTMLElement | null>): HeadingLayout {\n const { doc, activeView, monacoEditor, tiptapEditor } = useEditorContext();\n\n const flatBlocks = useMemo(() => (doc ? flattenBlocks(doc.blocks) : []), [doc]);\n\n const [entries, setEntries] = useState<HeadingLayoutEntry[]>([]);\n const [pageEdges, setPageEdges] = useState<{ left: number; right: number } | null>(null);\n\n // ── WYSIWYG backend ────────────────────────────────────────────────\n\n useEffect(() => {\n if (activeView !== 'wysiwyg') return;\n const node = refInsideWrapper.current;\n if (!node) return;\n const wrapper = findWrapper(node);\n if (!wrapper) return;\n const wysiwygContainer = wrapper.querySelector<HTMLElement>('.squisq-wysiwyg-container');\n if (!wysiwygContainer) return;\n\n let raf = 0;\n const recompute = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n const headings = Array.from(\n wysiwygContainer.querySelectorAll<HTMLElement>('h1, h2, h3, h4, h5, h6'),\n );\n const wrapperRect = wrapper.getBoundingClientRect();\n const editorRect = wysiwygContainer.getBoundingClientRect();\n const next: HeadingLayoutEntry[] = [];\n flatBlocks.forEach((block, i) => {\n const h = headings[i];\n if (!h) return;\n const top = h.getBoundingClientRect().top - wrapperRect.top;\n const nextH = headings[i + 1];\n const bottom = nextH\n ? nextH.getBoundingClientRect().top - wrapperRect.top\n : editorRect.bottom - wrapperRect.top;\n next.push({\n block,\n top,\n bottom,\n annotated: !!h.getAttribute('data-template'),\n });\n });\n setEntries((prev) => (sameEntries(prev, next) ? prev : next));\n\n // Page edges — anchor to the .squisq-wysiwyg-editor (the centered \"page\").\n const page = wysiwygContainer.querySelector<HTMLElement>('.squisq-wysiwyg-editor');\n if (page) {\n const pageRect = page.getBoundingClientRect();\n const left = pageRect.left - wrapperRect.left;\n const right = pageRect.right - wrapperRect.left;\n setPageEdges((prev) =>\n prev != null && Math.abs(prev.left - left) < 0.5 && Math.abs(prev.right - right) < 0.5\n ? prev\n : { left, right },\n );\n }\n });\n };\n\n recompute();\n const ro = new ResizeObserver(recompute);\n ro.observe(wysiwygContainer);\n const editorSurface = wysiwygContainer.querySelector('.squisq-wysiwyg-editor');\n if (editorSurface) ro.observe(editorSurface);\n const mo = new MutationObserver(recompute);\n mo.observe(wysiwygContainer, {\n childList: true,\n subtree: true,\n characterData: true,\n attributes: true,\n attributeFilter: ['data-template', 'data-template-params'],\n });\n wysiwygContainer.addEventListener('scroll', recompute, { passive: true });\n window.addEventListener('resize', recompute);\n const settle = window.setTimeout(recompute, 250);\n\n return () => {\n cancelAnimationFrame(raf);\n window.clearTimeout(settle);\n ro.disconnect();\n mo.disconnect();\n wysiwygContainer.removeEventListener('scroll', recompute);\n window.removeEventListener('resize', recompute);\n };\n }, [activeView, flatBlocks, refInsideWrapper]);\n\n // ── Raw (Monaco) backend ───────────────────────────────────────────\n\n useEffect(() => {\n if (activeView !== 'raw') return;\n if (!monacoEditor) return;\n const node = refInsideWrapper.current;\n if (!node) return;\n const wrapper = findWrapper(node);\n if (!wrapper) return;\n\n let raf = 0;\n const recompute = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n const wrapperRect = wrapper.getBoundingClientRect();\n const monacoRoot = monacoEditor.getDomNode() as HTMLElement | null;\n if (!monacoRoot) return;\n const monacoRect = monacoRoot.getBoundingClientRect();\n // Y of the editor's content top in wrapper coordinates.\n const monacoTop = monacoRect.top - wrapperRect.top;\n const scrollTop = monacoEditor.getScrollTop();\n\n const layoutInfo = monacoEditor.getLayoutInfo();\n const next: HeadingLayoutEntry[] = [];\n flatBlocks.forEach((block, i) => {\n const line = block.sourceHeading?.position?.start.line;\n if (typeof line !== 'number') return;\n const lineTop = monacoEditor.getTopForLineNumber(line) - scrollTop + monacoTop;\n // Bottom = next block's top, or the visible bottom of the editor.\n const nextBlock = flatBlocks[i + 1];\n const nextLine = nextBlock?.sourceHeading?.position?.start.line;\n const bottom =\n typeof nextLine === 'number'\n ? monacoEditor.getTopForLineNumber(nextLine) - scrollTop + monacoTop\n : monacoTop + layoutInfo.height;\n const tplName = block.sourceHeading?.templateAnnotation?.template;\n next.push({\n block,\n top: lineTop,\n bottom,\n annotated: !!tplName && hasTemplate(tplName),\n });\n });\n setEntries((prev) => (sameEntries(prev, next) ? prev : next));\n\n // Page edges — Monaco's editor area extends to its container's\n // box edges; treat the whole editor as the \"page\".\n const left = monacoRect.left - wrapperRect.left;\n const right = monacoRect.right - wrapperRect.left;\n setPageEdges((prev) =>\n prev != null && Math.abs(prev.left - left) < 0.5 && Math.abs(prev.right - right) < 0.5\n ? prev\n : { left, right },\n );\n });\n };\n\n recompute();\n const scrollSub = monacoEditor.onDidScrollChange(recompute);\n const contentSub = monacoEditor.onDidChangeModelContent(recompute);\n const layoutSub = monacoEditor.onDidLayoutChange(recompute);\n const ro = new ResizeObserver(recompute);\n const monacoRoot = monacoEditor.getDomNode();\n if (monacoRoot) ro.observe(monacoRoot);\n window.addEventListener('resize', recompute);\n const settle = window.setTimeout(recompute, 250);\n\n return () => {\n cancelAnimationFrame(raf);\n window.clearTimeout(settle);\n scrollSub.dispose();\n contentSub.dispose();\n layoutSub.dispose();\n ro.disconnect();\n window.removeEventListener('resize', recompute);\n };\n }, [activeView, monacoEditor, flatBlocks, refInsideWrapper]);\n\n // Reset edges when the active view changes — the previous view's\n // measurements don't carry over to the next.\n useEffect(() => {\n setEntries([]);\n setPageEdges(null);\n }, [activeView]);\n\n // ── scrollToBlock ──────────────────────────────────────────────────\n\n const scrollToBlock = useCallback(\n (block: Block) => {\n if (activeView === 'wysiwyg') {\n const node = refInsideWrapper.current;\n const wrapper = node ? findWrapper(node) : null;\n const wysiwygContainer = wrapper?.querySelector<HTMLElement>('.squisq-wysiwyg-container');\n if (!wysiwygContainer) return;\n const headings = wysiwygContainer.querySelectorAll<HTMLElement>('h1, h2, h3, h4, h5, h6');\n const index = flatBlocks.findIndex((b) => b.id === block.id);\n if (index < 0 || index >= headings.length) return;\n headings[index].scrollIntoView({ behavior: 'smooth', block: 'start' });\n if (tiptapEditor) {\n try {\n tiptapEditor.chain().focus().run();\n } catch {\n // ignore\n }\n }\n return;\n }\n if (activeView === 'raw' && monacoEditor) {\n const line = block.sourceHeading?.position?.start.line;\n if (typeof line !== 'number') return;\n monacoEditor.revealLineInCenter(line);\n monacoEditor.setPosition({ lineNumber: line, column: 1 });\n monacoEditor.focus();\n }\n },\n [activeView, flatBlocks, monacoEditor, refInsideWrapper, tiptapEditor],\n );\n\n return {\n entries,\n pageEdges,\n scrollToBlock,\n ready: entries.length > 0 || pageEdges != null,\n };\n}\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction findWrapper(node: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = node.parentElement;\n while (cur) {\n if (cur.classList.contains('squisq-editor-with-gutter')) return cur;\n cur = cur.parentElement;\n }\n // Fallback: immediate parent (during transitional renames).\n return node.parentElement;\n}\n\nfunction sameEntries(a: HeadingLayoutEntry[], b: HeadingLayoutEntry[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n const x = a[i];\n const y = b[i];\n if (x.block.id !== y.block.id) return false;\n if (x.annotated !== y.annotated) return false;\n if (Math.abs(x.top - y.top) > 0.5) return false;\n if (Math.abs(x.bottom - y.bottom) > 0.5) return false;\n }\n return true;\n}\n","/**\n * OutlinePanel\n *\n * Left-side companion to the InlinePreviewGutter. Renders a hierarchical\n * tree of the document's headings (h1 → h2 → h3 …) so the structure is\n * graspable at a glance and the user can jump to any section. Works in\n * BOTH the WYSIWYG and Markdown editor views — view-specific positioning\n * lives in `useHeadingLayout`.\n */\n\nimport { type CSSProperties, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { Block } from '@bendyline/squisq/schemas';\nimport { flattenBlocks, hasTemplate } from '@bendyline/squisq/doc';\nimport { extractPlainText } from '@bendyline/squisq/markdown';\nimport { useEditorContext } from './EditorContext';\nimport { templateLabel } from './TemplatePicker';\nimport { useHeadingLayout } from './useHeadingLayout';\nimport { usePreviewSettingsOptional } from './PreviewControls';\n\nexport interface OutlinePanelProps {\n /** Width of the pane in pixels (default: 240). */\n width?: number;\n /** Optional CSS class for the outer container. */\n className?: string;\n}\n\nexport function OutlinePanel({ width = 240, className }: OutlinePanelProps) {\n const { doc, markdownSource, setMarkdownSource } = useEditorContext();\n const paneRef = useRef<HTMLElement | null>(null);\n const { scrollToBlock } = useHeadingLayout(paneRef);\n const activeBlockId = useActiveOutlineBlockId();\n\n // Promote / demote the row's heading by rewriting just the `#` prefix\n // on the heading line. Falls through when the new depth would leave the\n // legal H1–H6 range, so the buttons disable themselves at the edges.\n // Both editor surfaces resync from `markdownSource` automatically.\n const changeHeadingLevel = useCallback(\n (block: Block, delta: number) => {\n const line = block.sourceHeading?.position?.start.line;\n if (typeof line !== 'number') return;\n const next = bumpHeadingLevelInSource(markdownSource, line, delta);\n if (next != null) setMarkdownSource(next);\n },\n [markdownSource, setMarkdownSource],\n );\n\n // Inherit the active document theme's primary color so the current-row\n // highlight and template-name chips match the rest of the editor's\n // accent palette (e.g. warm-earth's terracotta) instead of the\n // hard-coded purple fallback. Falls through to the CSS defaults when\n // no PreviewSettingsProvider is mounted.\n const previewSettings = usePreviewSettingsOptional();\n const accentColor = previewSettings?.activeTheme?.colors?.primary;\n\n const isEmpty = !doc || doc.blocks.length === 0 || !hasAnyHeading(doc.blocks);\n const paneStyle: CSSProperties = {\n width: `${width}px`,\n flex: `0 0 ${width}px`,\n overflow: 'auto',\n ...(accentColor\n ? ({ ['--squisq-outline-accent' as string]: accentColor } as CSSProperties)\n : {}),\n };\n\n return (\n <aside\n ref={paneRef}\n className={`squisq-outline${className ? ` ${className}` : ''}`}\n style={paneStyle}\n data-testid=\"outline-panel\"\n aria-label=\"Document outline\"\n >\n {isEmpty ? (\n <div className=\"squisq-outline-empty\">\n <p>Add a heading to populate the outline.</p>\n </div>\n ) : (\n <ul className=\"squisq-outline-tree\" role=\"tree\">\n {doc!.blocks.map((b) => (\n <OutlineNode\n key={b.id}\n block={b}\n activeBlockId={activeBlockId}\n onSelect={scrollToBlock}\n onChangeLevel={changeHeadingLevel}\n />\n ))}\n </ul>\n )}\n </aside>\n );\n}\n\n// ── Subcomponents ──────────────────────────────────────────────────\n\nfunction OutlineNode({\n block,\n activeBlockId,\n onSelect,\n onChangeLevel,\n}: {\n block: Block;\n activeBlockId: string | null;\n onSelect: (b: Block) => void;\n onChangeLevel: (block: Block, delta: number) => void;\n}) {\n const heading = block.sourceHeading;\n const depth = heading?.depth ?? 1;\n const text = heading ? extractPlainText(heading).trim() : '';\n const annotation = heading?.templateAnnotation;\n const tplName = annotation?.template;\n const showChip = tplName && hasTemplate(tplName);\n const isActive = block.id === activeBlockId;\n const canPromote = !!heading && depth > 1;\n const canDemote = !!heading && depth < 6;\n\n return (\n <li className=\"squisq-outline-item\" role=\"treeitem\" aria-current={isActive || undefined}>\n <div className=\"squisq-outline-row-wrap\">\n <button\n type=\"button\"\n className={`squisq-outline-row squisq-outline-row--depth-${depth}${\n isActive ? ' squisq-outline-row--current' : ''\n }`}\n onClick={() => onSelect(block)}\n title={text || '(empty heading)'}\n >\n <span className=\"squisq-outline-row-text\">{text || '(untitled)'}</span>\n {showChip && (\n <span className=\"squisq-outline-template-chip\">{templateLabel(tplName!)}</span>\n )}\n </button>\n {heading && (\n <span className=\"squisq-outline-row-actions\">\n <button\n type=\"button\"\n className=\"squisq-outline-row-arrow\"\n aria-label={`Promote heading (currently H${depth})`}\n title=\"Promote heading\"\n disabled={!canPromote}\n onClick={() => onChangeLevel(block, -1)}\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path\n d=\"M6.5 2.5 L3 5 L6.5 7.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n className=\"squisq-outline-row-arrow\"\n aria-label={`Demote heading (currently H${depth})`}\n title=\"Demote heading\"\n disabled={!canDemote}\n onClick={() => onChangeLevel(block, +1)}\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path\n d=\"M3.5 2.5 L7 5 L3.5 7.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n />\n </svg>\n </button>\n </span>\n )}\n </div>\n {block.children && block.children.length > 0 && (\n <ul className=\"squisq-outline-tree\">\n {block.children.map((child) => (\n <OutlineNode\n key={child.id}\n block={child}\n activeBlockId={activeBlockId}\n onSelect={onSelect}\n onChangeLevel={onChangeLevel}\n />\n ))}\n </ul>\n )}\n </li>\n );\n}\n\n// ── Active-block tracking ──────────────────────────────────────────\n\n/**\n * Tracks which heading the user's cursor is currently inside (or most\n * recently passed). In WYSIWYG mode this watches Tiptap's selection;\n * in Raw mode it watches Monaco's cursor line. The Preview surface has\n * no cursor concept and reports `null`.\n *\n * The lookup mirrors the heading-pairing logic in `useHeadingLayout`:\n * the Nth heading in document order maps to `flattenBlocks(doc.blocks)[N]`.\n */\nfunction useActiveOutlineBlockId(): string | null {\n const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();\n const flatBlocks = useMemo(() => (doc ? flattenBlocks(doc.blocks) : []), [doc]);\n const [activeId, setActiveId] = useState<string | null>(null);\n\n // Reset whenever the active surface changes — a stale highlight from\n // the previous view would mislead the user before the new surface's\n // cursor handler runs.\n useEffect(() => {\n setActiveId(null);\n }, [activeView]);\n\n useEffect(() => {\n if (activeView !== 'wysiwyg' || !tiptapEditor) return;\n\n const update = () => {\n const { from } = tiptapEditor.state.selection;\n let lastIndex = -1;\n let seen = -1;\n tiptapEditor.state.doc.forEach((node, offset) => {\n if (node.type.name !== 'heading') return;\n seen += 1;\n if (offset <= from) lastIndex = seen;\n });\n const block = lastIndex >= 0 ? flatBlocks[lastIndex] : null;\n setActiveId(block?.id ?? null);\n };\n\n update();\n tiptapEditor.on('selectionUpdate', update);\n tiptapEditor.on('update', update);\n return () => {\n tiptapEditor.off('selectionUpdate', update);\n tiptapEditor.off('update', update);\n };\n }, [activeView, tiptapEditor, flatBlocks]);\n\n useEffect(() => {\n if (activeView !== 'raw' || !monacoEditor) return;\n\n const update = () => {\n const line = monacoEditor.getPosition()?.lineNumber;\n if (typeof line !== 'number') {\n setActiveId(null);\n return;\n }\n let lastIndex = -1;\n flatBlocks.forEach((b, i) => {\n const headingLine = b.sourceHeading?.position?.start.line;\n if (typeof headingLine === 'number' && headingLine <= line) lastIndex = i;\n });\n const block = lastIndex >= 0 ? flatBlocks[lastIndex] : null;\n setActiveId(block?.id ?? null);\n };\n\n update();\n const sub = monacoEditor.onDidChangeCursorPosition(update);\n return () => sub.dispose();\n }, [activeView, monacoEditor, flatBlocks]);\n\n return activeId;\n}\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction hasAnyHeading(blocks: Block[]): boolean {\n for (const b of blocks) {\n if (b.sourceHeading) return true;\n if (b.children && hasAnyHeading(b.children)) return true;\n }\n return false;\n}\n\n/**\n * Rewrites just the leading `#` run on the given 1-based line, shifting\n * the heading depth by `delta`. Returns `null` when the line isn't an\n * ATX heading or the resulting depth would fall outside 1–6. Leaves the\n * rest of the line (including any `{[template]}` annotation) untouched.\n */\nfunction bumpHeadingLevelInSource(source: string, line: number, delta: number): string | null {\n const lines = source.split('\\n');\n const idx = line - 1;\n if (idx < 0 || idx >= lines.length) return null;\n const original = lines[idx];\n const match = original.match(/^(#{1,6})(\\s|$)/);\n if (!match) return null;\n const currentDepth = match[1].length;\n const newDepth = currentDepth + delta;\n if (newDepth < 1 || newDepth > 6) return null;\n lines[idx] = '#'.repeat(newDepth) + original.slice(currentDepth);\n return lines.join('\\n');\n}\n","/**\n * PreviewPanel\n *\n * Renders a live preview of the current markdown document as a slideshow\n * using the DocPlayer component from @bendyline/squisq-react. The\n * markdown → player-Doc conversion is delegated to the shared\n * `buildPreviewDoc` helper so live preview and the export pipeline stay\n * in sync.\n */\n\nimport { useState, useEffect } from 'react';\nimport { DocPlayer, LinearDocView, useMediaProvider } from '@bendyline/squisq-react';\nimport type { Doc } from '@bendyline/squisq/schemas';\nimport { applyTransform } from '@bendyline/squisq/transform';\nimport { resolveAudioMapping } from '@bendyline/squisq/doc';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { useEditorContext } from './EditorContext';\nimport { usePreviewSettings } from './PreviewControls';\nimport { buildPreviewDoc } from './buildPreviewDoc';\nimport { PlainHtmlPreview } from './PlainHtmlPreview';\n\nexport interface PreviewPanelProps {\n /** Base path for resolving media URLs in DocPlayer */\n basePath?: string;\n /** Additional class name for the container */\n className?: string;\n /**\n * Workspace-scoped `ContentContainer` (the folder holding the doc and\n * its siblings). Used here for audio mapping — MP3 discovery and\n * `timing.json` reading.\n */\n workspaceContainer?: ContentContainer | null;\n}\n\n// ── Component ──────────────────────────────────────────────────────\n\n/**\n * Live preview panel that renders the current document as a slideshow\n * or document view. Controls (viewport, mode, theme, transform, captions)\n * are rendered in the main toolbar via PreviewToolbarControls.\n */\nexport function PreviewPanel({ basePath = '/', className, workspaceContainer }: PreviewPanelProps) {\n const { doc, parseError, isParsing, markdownSource, mediaRevision } = useEditorContext();\n const mediaProvider = useMediaProvider();\n const {\n activeViewport,\n activeDisplayMode,\n activeTheme,\n activeTransformStyle,\n activeCaptionStyle,\n } = usePreviewSettings();\n\n // Build the player-ready Doc whenever the parsed doc changes.\n // Transform runs on the ORIGINAL doc (which has block.contents with\n // markdown body text) so the content extractor can analyze it.\n // Then buildPreviewDoc converts the result for DocPlayer.\n //\n // Audio mapping is async (reads container files), so we use a two-phase\n // approach: first build the base doc synchronously, then resolve audio\n // in an effect and update the state.\n const [previewDoc, setPreviewDoc] = useState<Doc | null>(null);\n\n useEffect(() => {\n if (!doc || !doc.blocks.length) {\n setPreviewDoc(null);\n return;\n }\n\n let sourceDoc = doc;\n if (activeTransformStyle) {\n const result = applyTransform(doc, activeTransformStyle);\n sourceDoc = result.doc;\n }\n\n // If we have a workspace container, try to resolve audio mapping before building preview\n if (workspaceContainer) {\n let cancelled = false;\n resolveAudioMapping(sourceDoc, workspaceContainer).then((audioDoc) => {\n if (!cancelled) {\n setPreviewDoc(buildPreviewDoc(audioDoc));\n }\n });\n // Set an immediate preview without audio while mapping resolves\n setPreviewDoc(buildPreviewDoc(sourceDoc));\n return () => {\n cancelled = true;\n };\n }\n\n setPreviewDoc(buildPreviewDoc(sourceDoc));\n }, [doc, activeTransformStyle, workspaceContainer]);\n\n // Status overlays for non-ready states\n if (isParsing) {\n return (\n <div className={`squisq-preview-status ${className || ''}`} data-testid=\"preview-panel\">\n <p>Parsing…</p>\n </div>\n );\n }\n\n if (parseError) {\n return (\n <div className={`squisq-preview-status ${className || ''}`} data-testid=\"preview-panel\">\n <h3>Parse Error</h3>\n <pre>{parseError}</pre>\n </div>\n );\n }\n\n // Page mode renders directly from markdown — it doesn't depend on the\n // parsed Doc tree or the player preview build, so let it fall through\n // even when those aren't ready yet.\n if (!previewDoc && activeDisplayMode !== 'page') {\n return (\n <div className={`squisq-preview-status ${className || ''}`} data-testid=\"preview-panel\">\n <p>No content to preview. Start typing in the editor.</p>\n </div>\n );\n }\n\n const fillsContainer =\n activeDisplayMode === 'linear' || activeDisplayMode === 'page' ? 'stretch' : 'center';\n\n return (\n <div\n className={`squisq-preview-container ${className || ''}`}\n data-testid=\"preview-panel\"\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n background: 'var(--squisq-bg, #f5f5f5)',\n }}\n >\n {/* Player / Document / Page view */}\n <div\n className=\"squisq-preview-player\"\n style={{\n flex: 1,\n display: 'flex',\n alignItems: fillsContainer,\n justifyContent: 'center',\n overflow: 'hidden',\n minHeight: 0,\n }}\n >\n {activeDisplayMode === 'page' ? (\n <PlainHtmlPreview\n markdown={markdownSource}\n title={(doc?.frontmatter?.title as string | undefined) ?? undefined}\n mediaProvider={mediaProvider}\n mediaRevision={mediaRevision}\n theme={activeTheme}\n />\n ) : activeDisplayMode === 'linear' ? (\n <LinearDocView\n doc={doc!}\n basePath={basePath}\n viewport={activeViewport}\n theme={activeTheme}\n />\n ) : (\n <DocPlayer\n script={previewDoc!}\n basePath={basePath}\n showControls\n muted\n forceViewport={activeViewport}\n displayMode={activeDisplayMode}\n theme={activeTheme}\n captionStyle={activeCaptionStyle}\n />\n )}\n </div>\n </div>\n );\n}\n","/**\n * buildPreviewDoc — Converts a markdown-derived Doc into a player-ready Doc\n * with TemplateBlock slides and interleaved images.\n *\n * Shared between PreviewPanel (live preview) and export flows (HTML/video).\n *\n * Pipeline:\n * 1. Flatten hierarchical blocks into a linear slide sequence\n * 2. Convert each block into a TemplateBlock-compatible object\n * 3. Interleave images as standalone imageWithCaption slides\n * 4. Synthesize a dummy audio segment for timer-based playback\n */\n\nimport { flattenBlocks, hasTemplate } from '@bendyline/squisq/doc';\nimport { extractPlainText } from '@bendyline/squisq/markdown';\nimport { getChildren } from '@bendyline/squisq/markdown';\nimport type { Block, Doc } from '@bendyline/squisq/schemas';\nimport type { MarkdownBlockNode, MarkdownList, MarkdownNode } from '@bendyline/squisq/markdown';\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction extractBodyText(contents: MarkdownBlockNode[] | undefined): string {\n if (!contents || contents.length === 0) return '';\n const parts: string[] = [];\n for (const node of contents) {\n parts.push(extractPlainText(node));\n }\n return parts.join('\\n').trim();\n}\n\ninterface ExtractedImage {\n src: string;\n alt: string;\n /** Explicit width from `<img width>` (markdown shorthand has none). */\n width?: number;\n /** Explicit height from `<img height>`. */\n height?: number;\n}\n\nfunction parseDim(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined;\n const n = parseFloat(raw);\n return Number.isFinite(n) && n > 0 ? n : undefined;\n}\n\nfunction extractBlockImages(contents: MarkdownBlockNode[] | undefined): ExtractedImage[] {\n if (!contents || contents.length === 0) return [];\n const images: ExtractedImage[] = [];\n\n function walkHtml(node: unknown): void {\n if (!node || typeof node !== 'object') return;\n const n = node as Record<string, unknown>;\n if (n.type === 'htmlElement' && (n.tagName as string).toLowerCase() === 'img') {\n const attrs = n.attributes as Record<string, string> | undefined;\n const src = attrs?.src;\n if (typeof src === 'string' && src) {\n images.push({\n src,\n alt: typeof attrs?.alt === 'string' ? attrs.alt : '',\n width: parseDim(attrs?.width),\n height: parseDim(attrs?.height),\n });\n }\n }\n if (Array.isArray(n.children)) {\n for (const child of n.children) walkHtml(child);\n }\n }\n\n function walk(node: MarkdownNode): void {\n if ('type' in node && node.type === 'image' && 'url' in node) {\n const img = node as { url: string; alt?: string };\n if (img.url) {\n images.push({ src: img.url, alt: img.alt ?? '' });\n }\n }\n // Resized images round-trip as raw HTML. Pick them up so feature\n // and slideshow previews show the actual image rather than a blank\n // placeholder.\n if ('type' in node && (node.type === 'htmlBlock' || node.type === 'htmlInline')) {\n const html = node as unknown as { htmlChildren?: unknown[] };\n for (const child of html.htmlChildren ?? []) walkHtml(child);\n }\n for (const child of getChildren(node)) {\n walk(child);\n }\n }\n\n for (const node of contents) {\n walk(node);\n }\n return images;\n}\n\nfunction collectAllDocImages(blocks: Block[]): Array<{ src: string; alt: string }> {\n const seen = new Set<string>();\n const images: Array<{ src: string; alt: string }> = [];\n\n function walkBlocks(blockList: Block[]): void {\n for (const block of blockList) {\n for (const img of extractBlockImages(block.contents)) {\n if (!seen.has(img.src)) {\n seen.add(img.src);\n images.push(img);\n }\n }\n if (block.children) {\n walkBlocks(block.children);\n }\n }\n }\n\n walkBlocks(blocks);\n return images;\n}\n\nfunction extractListItems(contents: MarkdownBlockNode[] | undefined): string[] {\n if (!contents) return [];\n const items: string[] = [];\n for (const node of contents) {\n if (node.type === 'list') {\n for (const item of (node as MarkdownList).children) {\n const text = extractPlainText(item).trim();\n if (text) items.push(text);\n }\n }\n }\n return items;\n}\n\nfunction getTemplateDefaults(\n templateName: string,\n headingText: string,\n block: Block,\n): Record<string, unknown> {\n const body = extractBodyText(block.contents);\n\n switch (templateName) {\n case 'statHighlight':\n return { stat: headingText, description: body || headingText };\n case 'quote':\n case 'fullBleedQuote':\n case 'pullQuote':\n return { quote: body || headingText };\n case 'factCard':\n return { fact: headingText, explanation: body || headingText };\n case 'comparisonBar':\n return { leftLabel: 'A', leftValue: 60, rightLabel: 'B', rightValue: 40 };\n case 'list': {\n const items = extractListItems(block.contents);\n return { items: items.length > 0 ? items : ['Item 1', 'Item 2', 'Item 3'] };\n }\n case 'definitionCard':\n return { term: headingText, definition: body || headingText };\n case 'dateEvent':\n return { date: headingText, description: body || headingText };\n case 'leftFeature':\n case 'rightFeature': {\n // Feature blocks need imageSrc from body content and use the\n // heading text as the visible title alongside the body paragraph.\n const images = extractBlockImages(block.contents);\n const img = images[0];\n return {\n imageSrc: img?.src ?? '',\n imageAlt: img?.alt || headingText,\n imageWidth: img?.width,\n imageHeight: img?.height,\n title: headingText,\n body: body || headingText,\n };\n }\n default:\n return {};\n }\n}\n\nfunction blockToSlide(block: Block, index: number): Record<string, unknown> {\n const headingText = block.sourceHeading\n ? extractPlainText(block.sourceHeading)\n : block.title || block.id || `Slide ${index + 1}`;\n\n const requestedTemplate = block.template || 'sectionHeader';\n const template = hasTemplate(requestedTemplate) ? requestedTemplate : 'sectionHeader';\n const defaults = getTemplateDefaults(template, headingText, block);\n\n const {\n id: _id,\n startTime: _st,\n duration: _d,\n audioSegment: _as,\n layers: _l,\n transition: _tr,\n template: _t,\n title: _ti,\n children: _c,\n contents: _co,\n sourceHeading: _sh,\n templateOverrides: _to,\n ...extraFields\n } = block as unknown as Record<string, unknown>;\n\n return {\n id: block.id,\n template,\n duration: block.duration,\n audioSegment: 0,\n transition: index > 0 ? { type: 'fade', duration: 0.5 } : undefined,\n title: headingText,\n ...defaults,\n ...extraFields,\n ...block.templateOverrides,\n };\n}\n\nconst IMAGE_MOTIONS: Array<'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight'> = [\n 'zoomIn',\n 'zoomOut',\n 'panLeft',\n 'panRight',\n];\n\n// ── Public API ─────────────────────────────────────────────────────\n\n/**\n * Build a player-ready Doc from a markdown-derived Doc.\n *\n * Flattens hierarchical blocks, converts each to a TemplateBlock-compatible\n * slide, interleaves images, recalculates timing, and adds a synthetic\n * audio segment.\n */\nexport function buildPreviewDoc(doc: Doc): Doc {\n const flat = flattenBlocks(doc.blocks);\n const allImages = collectAllDocImages(doc.blocks);\n const usedImageSrcs = new Set<string>();\n\n const slides: Record<string, unknown>[] = [];\n let motionIndex = 0;\n\n for (let i = 0; i < flat.length; i++) {\n const block = flat[i];\n const blockImages = extractBlockImages(block.contents);\n const slide = blockToSlide(block, i);\n\n if (blockImages.length > 0 && slide.template === 'sectionHeader') {\n const img = blockImages[0];\n usedImageSrcs.add(img.src);\n slide.template = 'imageWithCaption';\n slide.imageSrc = img.src;\n slide.imageAlt = img.alt;\n slide.caption = slide.title as string;\n slide.captionPosition = 'bottom';\n slide.ambientMotion = IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length];\n } else if (blockImages.length > 0) {\n const img = blockImages[0];\n usedImageSrcs.add(img.src);\n if (!slide.accentImage) {\n slide.accentImage = {\n src: img.src,\n alt: img.alt,\n position: 'left-strip',\n ambientMotion: IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length],\n };\n }\n }\n\n slides.push(slide);\n }\n\n // Interleave unused images\n const unusedImages = allImages.filter((img) => !usedImageSrcs.has(img.src));\n if (unusedImages.length > 0 && slides.length > 0) {\n const interval = Math.max(2, Math.floor(slides.length / (unusedImages.length + 1)));\n let insertOffset = 0;\n for (let imgIdx = 0; imgIdx < unusedImages.length; imgIdx++) {\n const insertAt = Math.min((imgIdx + 1) * interval + insertOffset, slides.length);\n const img = unusedImages[imgIdx];\n slides.splice(insertAt, 0, {\n id: `img-interleave-${imgIdx}`,\n template: 'imageWithCaption',\n duration: 5,\n audioSegment: 0,\n imageSrc: img.src,\n imageAlt: img.alt,\n ambientMotion: IMAGE_MOTIONS[motionIndex++ % IMAGE_MOTIONS.length],\n transition: { type: 'fade', duration: 0.5 },\n });\n insertOffset++;\n }\n }\n\n // Recalculate timing\n let t = 0;\n for (const slide of slides) {\n slide.startTime = t;\n t += slide.duration as number;\n }\n\n return {\n articleId: doc.articleId,\n duration: t,\n blocks: slides as unknown as Block[],\n audio: {\n segments: t > 0 ? [{ src: '', name: 'preview', duration: t, startTime: 0 }] : [],\n },\n ...(doc.captions ? { captions: doc.captions } : {}),\n ...(doc.startBlock ? { startBlock: doc.startBlock } : {}),\n ...(doc.themeId ? { themeId: doc.themeId } : {}),\n };\n}\n","/**\n * PlainHtmlPreview\n *\n * Live WYSIWYG preview of the plain-HTML export. Renders the result of\n * `markdownDocToPlainHtml` inside a sandboxed `<iframe srcDoc>` so the\n * exported document's inline `<style>` block can't leak into the host\n * page — and so the preview looks identical to what users get when they\n * open the downloaded `.html`.\n *\n * Image handling: relative `<img src>` references in the markdown can't\n * load directly from inside the iframe (there's no real document\n * origin). When a `mediaProvider` is supplied, this component walks the\n * parsed markdown for image refs, resolves each through\n * `mediaProvider.resolveUrl()` (which returns a cached blob URL), and\n * passes the resolved map to the renderer so the iframe gets blob URLs\n * it can fetch.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport type { CSSProperties } from 'react';\nimport { parseMarkdown } from '@bendyline/squisq/markdown';\nimport type { MarkdownDocument, HtmlNode } from '@bendyline/squisq/markdown';\nimport type { MediaProvider, Theme } from '@bendyline/squisq/schemas';\nimport { markdownDocToPlainHtml } from '@bendyline/squisq-formats/html';\nimport { normalizeMalformedAssetUrl } from './utils/normalizeMalformedAssetUrl';\nimport { collectInlineFontAwesomeCss } from './utils/collectInlineFontAwesomeCss';\n\nexport interface PlainHtmlPreviewProps {\n /** Raw markdown source. */\n markdown: string;\n /** Document title — populates the iframe's `<title>`. */\n title?: string;\n /**\n * Pre-resolved image substitutions (export-time use). Takes precedence\n * over live `mediaProvider` resolution for any URL it contains.\n */\n images?: Map<string, string>;\n /**\n * When passed, relative image URLs in the markdown are resolved live\n * via this provider. Skip for static previews where `images` already\n * contains everything.\n */\n mediaProvider?: MediaProvider | null;\n /** Token that, when changed, forces re-resolution of media URLs.\n * Mirrors the `mediaRevision` bump the editor uses after an image\n * edit so saves show up in the preview without remount. */\n mediaRevision?: number;\n /**\n * Squisq theme to apply. When set, the iframe loads any Google-\n * hosted fonts the theme uses and the rendered HTML adopts the\n * theme's colors and typography.\n */\n theme?: Theme;\n className?: string;\n style?: CSSProperties;\n}\n\nconst IFRAME_STYLE: CSSProperties = {\n width: '100%',\n height: '100%',\n border: 'none',\n background: '#fff',\n display: 'block',\n};\n\nexport function PlainHtmlPreview({\n markdown,\n title,\n images,\n mediaProvider,\n mediaRevision,\n theme,\n className,\n style,\n}: PlainHtmlPreviewProps) {\n const mdDoc = useMemo<MarkdownDocument>(() => parseMarkdown(markdown), [markdown]);\n\n // Resolve any relative image URLs the doc references. Blob URLs are\n // cheap once cached, so re-resolving on every keystroke is fine —\n // `resolveUrl` is memoized inside the provider.\n const [resolvedImages, setResolvedImages] = useState<Map<string, string> | null>(null);\n\n useEffect(() => {\n if (!mediaProvider) {\n setResolvedImages(null);\n return;\n }\n let cancelled = false;\n const refs = Array.from(collectImageRefs(mdDoc));\n Promise.all(\n refs.map(async (ref) => {\n // Word-style imports may have `http://<doc>_files/foo.png` —\n // recover the relative path so the workspace provider resolves\n // it, otherwise the iframe tries to fetch a nonsense hostname.\n const recovered = normalizeMalformedAssetUrl(ref);\n if (!recovered && isExternal(ref)) return [ref, ref] as const;\n const lookup = recovered ?? ref;\n try {\n const url = await mediaProvider.resolveUrl(lookup);\n return [ref, url] as const;\n } catch {\n return [ref, ref] as const;\n }\n }),\n ).then((pairs) => {\n if (cancelled) return;\n const next = new Map<string, string>(pairs);\n setResolvedImages(next);\n });\n return () => {\n cancelled = true;\n };\n }, [mdDoc, mediaProvider, mediaRevision]);\n\n const mergedImages = useMemo(() => {\n if (!resolvedImages && !images) return undefined;\n const merged = new Map<string, string>();\n if (resolvedImages) for (const [k, v] of resolvedImages) merged.set(k, v);\n if (images) for (const [k, v] of images) merged.set(k, v);\n return merged;\n }, [resolvedImages, images]);\n\n // Gather FontAwesome @font-face + utility rules from the host page's\n // own stylesheets so the iframe doesn't have to depend on a cross-\n // origin CDN fetch (which sandbox / tracking-prevention can silently\n // drop, leaving the icons invisible). The host (editor-react) already\n // bundles FA, so the rules are guaranteed to be present and the font\n // URLs inside them resolve to same-origin assets the iframe can\n // fetch under `allow-same-origin`.\n const iconsCss = useMemo(() => collectInlineFontAwesomeCss(), []);\n\n const html = useMemo(\n () => markdownDocToPlainHtml(mdDoc, { title, images: mergedImages, theme, iconsCss }),\n [mdDoc, title, mergedImages, theme, iconsCss],\n );\n\n return (\n <iframe\n className={className}\n data-testid=\"plain-html-preview\"\n title={title ?? 'HTML preview'}\n srcDoc={html}\n // `allow-same-origin` is required so the iframe can fetch blob:\n // URLs created by the host's media provider. We intentionally do\n // NOT include `allow-scripts` — the rendered HTML is plain-output\n // markup with no JS, and refusing scripts hardens against\n // accidental `<script>` content in user markdown.\n sandbox=\"allow-same-origin\"\n style={{ ...IFRAME_STYLE, ...style }}\n />\n );\n}\n\n// ── Image collection ───────────────────────────────────────────────\n\nfunction isExternal(url: string): boolean {\n return (\n !url ||\n url.startsWith('data:') ||\n url.startsWith('blob:') ||\n url.startsWith('http://') ||\n url.startsWith('https://') ||\n url.startsWith('//')\n );\n}\n\n/**\n * Collect every image URL referenced anywhere in the doc — markdown\n * `image` nodes plus any `<img src>` inside raw HTML blocks/inlines\n * (the WYSIWYG editor emits the HTML form for resized images).\n */\nfunction collectImageRefs(doc: MarkdownDocument): Set<string> {\n const refs = new Set<string>();\n\n function visitHtml(nodes: HtmlNode[]): void {\n for (const n of nodes) {\n if (n.type !== 'htmlElement') continue;\n const tag = n.tagName.toLowerCase();\n // <img>, <video>, and <audio> all reference media via `src`.\n // The export pipeline rewrites whichever map entries exist, so\n // collecting them under the same set is enough — `ctx.images`\n // is generic media despite the historical name.\n if (tag === 'img' || tag === 'video' || tag === 'audio' || tag === 'source') {\n const src = n.attributes.src;\n if (typeof src === 'string' && src) refs.add(src);\n }\n if (tag === 'video' || tag === 'audio') {\n const poster = n.attributes.poster;\n if (typeof poster === 'string' && poster) refs.add(poster);\n }\n visitHtml(n.children);\n }\n }\n\n function visit(node: unknown): void {\n if (!node || typeof node !== 'object') return;\n const n = node as Record<string, unknown>;\n if (n.type === 'image' && typeof n.url === 'string' && n.url) {\n refs.add(n.url);\n }\n if ((n.type === 'htmlBlock' || n.type === 'htmlInline') && Array.isArray(n.htmlChildren)) {\n visitHtml(n.htmlChildren as HtmlNode[]);\n }\n if (Array.isArray(n.children)) {\n for (const child of n.children) visit(child);\n }\n }\n\n for (const child of doc.children) visit(child);\n return refs;\n}\n","/**\n * Collect FontAwesome `@font-face` + utility CSS rules from the host\n * document's loaded stylesheets so we can inline them into a sandboxed\n * iframe preview.\n *\n * Why: an iframe rendered via `srcDoc` cannot reliably load\n * FontAwesome from a cross-origin CDN. Tracking prevention, stricter\n * origin policies, and the iframe's about:srcdoc origin all conspire\n * to silently drop font fetches. The icons end up invisible even\n * though the `<i class=\"fa-…\">` tags are present in the markup. The\n * host page (editor-react ships a bundled `@import` of\n * `@fortawesome/fontawesome-free`) already has the font loaded and its\n * woff2 URLs resolve to same-origin assets, so we extract those rules\n * once and pass them into the renderer as inline CSS.\n *\n * Returns `undefined` when no FA rules are found — typical for SSR or\n * for hosts that don't bundle FA — in which case the renderer falls\n * back to its cdnjs `<link>` (still works in plain standalone HTML).\n */\nexport function collectInlineFontAwesomeCss(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n\n const collected: string[] = [];\n\n for (const sheet of Array.from(document.styleSheets)) {\n let rules: CSSRuleList | null = null;\n try {\n rules = sheet.cssRules;\n } catch {\n // Cross-origin stylesheets throw on `.cssRules` access. We can't\n // read them, but they're also not where editor-react's bundled\n // FA lives, so it's safe to skip them.\n continue;\n }\n if (!rules) continue;\n\n for (const rule of Array.from(rules)) {\n if (isFontAwesomeRule(rule)) {\n collected.push(rule.cssText);\n }\n }\n }\n\n return collected.length > 0 ? collected.join('\\n') : undefined;\n}\n\n/**\n * Match `@font-face` declarations whose family starts with\n * \"Font Awesome\", plus the FA utility classes (the `.fa-*` rules that\n * set `content: \"\\fXXX\"` and font-family). The former gets the woff2\n * loaded into the iframe, the latter wires the `<i>` markup to it.\n */\nfunction isFontAwesomeRule(rule: CSSRule): boolean {\n const text = rule.cssText;\n // `@font-face { font-family: \"Font Awesome 6 Brands\"; … }`\n if (rule.type === CSSRule.FONT_FACE_RULE) {\n return /font-family:\\s*['\"]?Font Awesome/i.test(text);\n }\n // `.fa-github::before { content: \"\\f09b\"; }` and the base\n // `.fa-brands { font-family: \"Font Awesome 6 Brands\"; … }` rules.\n // FA's stylesheet prefixes selectors with `.fa`, `.fas`, `.far`,\n // `.fab`, `.fa-solid`, `.fa-regular`, `.fa-brands`. Match the\n // family name in the declaration block to avoid false positives\n // (e.g. someone else's `.fa-…` class that doesn't use the font).\n if (rule.type === CSSRule.STYLE_RULE) {\n return /Font Awesome/i.test(text) || /content:\\s*[\"']\\\\[ef]/.test(text);\n }\n return false;\n}\n","/**\n * ImageViewer\n *\n * Read-only image viewer used when EditorShell runs in `image` file mode\n * (PNG/JPEG/etc.). Renders a centered image that fits its container with\n * a small overlay toolbar for fit / 100% / zoom in / zoom out, and a\n * status row showing intrinsic dimensions and current zoom.\n *\n * Lifecycle of the `src` URL is the caller's responsibility — when fed a\n * blob URL, the host should `URL.revokeObjectURL` on unmount or src change.\n *\n * Future image-editing actions (rotate, flip, crop) will slot in alongside\n * the existing zoom controls.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';\n\nexport interface ImageViewerProps {\n /** Image source — typically a blob: URL the host owns and revokes. */\n src: string;\n /** Alt text for accessibility. Defaults to empty string (decorative). */\n alt?: string;\n /** Additional class name on the outer container. */\n className?: string;\n /** Color theme for the chrome around the image. */\n theme?: 'light' | 'dark';\n}\n\nconst MIN_ZOOM = 0.1;\nconst MAX_ZOOM = 16;\nconst ZOOM_STEP = 1.25;\n\ntype FitState = { mode: 'fit' } | { mode: 'manual'; zoom: number };\n\nexport function ImageViewer({ src, alt = '', className, theme = 'light' }: ImageViewerProps) {\n const imgRef = useRef<HTMLImageElement | null>(null);\n const stageRef = useRef<HTMLDivElement | null>(null);\n\n const [naturalSize, setNaturalSize] = useState<{ w: number; h: number } | null>(null);\n const [fitZoom, setFitZoom] = useState<number>(1);\n const [state, setState] = useState<FitState>({ mode: 'fit' });\n const [pan, setPan] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n setNaturalSize(null);\n setState({ mode: 'fit' });\n setPan({ x: 0, y: 0 });\n setError(null);\n }, [src]);\n\n const recomputeFitZoom = useCallback(() => {\n const stage = stageRef.current;\n if (!stage || !naturalSize) return;\n const { clientWidth, clientHeight } = stage;\n if (clientWidth === 0 || clientHeight === 0) return;\n const fit = Math.min(clientWidth / naturalSize.w, clientHeight / naturalSize.h, 1);\n setFitZoom(fit > 0 ? fit : 1);\n }, [naturalSize]);\n\n useEffect(() => {\n recomputeFitZoom();\n if (typeof ResizeObserver === 'undefined') return;\n const stage = stageRef.current;\n if (!stage) return;\n const ro = new ResizeObserver(() => recomputeFitZoom());\n ro.observe(stage);\n return () => ro.disconnect();\n }, [recomputeFitZoom]);\n\n const handleLoad = useCallback(() => {\n const img = imgRef.current;\n if (!img) return;\n setNaturalSize({ w: img.naturalWidth, h: img.naturalHeight });\n }, []);\n\n const handleError = useCallback(() => {\n setError('Failed to load image');\n }, []);\n\n const effectiveZoom = state.mode === 'fit' ? fitZoom : state.zoom;\n\n const setZoom = useCallback((next: number) => {\n const clamped = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, next));\n setState({ mode: 'manual', zoom: clamped });\n }, []);\n\n const onFit = useCallback(() => {\n setState({ mode: 'fit' });\n setPan({ x: 0, y: 0 });\n }, []);\n const onActual = useCallback(() => {\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }, [setZoom]);\n const onZoomIn = useCallback(() => setZoom(effectiveZoom * ZOOM_STEP), [effectiveZoom, setZoom]);\n const onZoomOut = useCallback(() => setZoom(effectiveZoom / ZOOM_STEP), [effectiveZoom, setZoom]);\n\n const dragRef = useRef<{ startX: number; startY: number; panX: number; panY: number } | null>(\n null,\n );\n const onMouseDown = useCallback(\n (e: ReactMouseEvent<HTMLDivElement>) => {\n if (effectiveZoom <= fitZoom) return;\n dragRef.current = { startX: e.clientX, startY: e.clientY, panX: pan.x, panY: pan.y };\n e.preventDefault();\n },\n [effectiveZoom, fitZoom, pan.x, pan.y],\n );\n\n useEffect(() => {\n const onMove = (e: MouseEvent) => {\n const drag = dragRef.current;\n if (!drag) return;\n setPan({\n x: drag.panX + (e.clientX - drag.startX),\n y: drag.panY + (e.clientY - drag.startY),\n });\n };\n const onUp = () => {\n dragRef.current = null;\n };\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n return () => {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n };\n }, []);\n\n const isPannable = effectiveZoom > fitZoom + 1e-6;\n\n const imgStyle: CSSProperties = naturalSize\n ? {\n width: `${naturalSize.w * effectiveZoom}px`,\n height: `${naturalSize.h * effectiveZoom}px`,\n transform: `translate(${pan.x}px, ${pan.y}px)`,\n }\n : { maxWidth: '100%', maxHeight: '100%' };\n\n const containerCls = ['squisq-image-viewer', `squisq-image-viewer--${theme}`, className]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={containerCls} data-testid=\"image-viewer\">\n <div\n ref={stageRef}\n className=\"squisq-image-viewer-stage\"\n onMouseDown={onMouseDown}\n style={{ cursor: isPannable ? (dragRef.current ? 'grabbing' : 'grab') : 'default' }}\n >\n {/* future: rotate, flip, crop overlays go here */}\n {error ? (\n <div className=\"squisq-image-viewer-error\">{error}</div>\n ) : (\n <img\n ref={imgRef}\n src={src}\n alt={alt}\n className=\"squisq-image-viewer-img\"\n style={imgStyle}\n onLoad={handleLoad}\n onError={handleError}\n draggable={false}\n />\n )}\n <div className=\"squisq-image-viewer-toolbar\">\n <button\n type=\"button\"\n className=\"squisq-image-viewer-btn\"\n onClick={onZoomOut}\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n >\n −\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-viewer-btn\"\n onClick={onFit}\n aria-pressed={state.mode === 'fit'}\n title=\"Fit to viewport\"\n >\n Fit\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-viewer-btn\"\n onClick={onActual}\n title=\"Actual size (100%)\"\n >\n 100%\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-viewer-btn\"\n onClick={onZoomIn}\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n >\n +\n </button>\n </div>\n </div>\n <div className=\"squisq-image-viewer-status\">\n {naturalSize ? (\n <>\n <span>\n {naturalSize.w} × {naturalSize.h}\n </span>\n <span>{Math.round(effectiveZoom * 100)}%</span>\n </>\n ) : (\n <span>Loading…</span>\n )}\n </div>\n </div>\n );\n}\n","/**\n * ImageEditor — top-level shell that wires together the toolbar,\n * canvas surface, layers panel, and properties panel against an\n * `ImageEditDoc` persisted in a sidecar `ContentContainer`.\n *\n * Hosts pass an already-scoped container (typically built with\n * `scopeContainer(parent, basename + '_files')`). On first mount, if\n * the sidecar has no `state.json`, the editor seeds it from\n * `initialSrc` — the source bytes are copied to `assets/source.<ext>`\n * so the doc is portable and round-trips through ZIP serialization.\n *\n * The export pipeline is `state.json` → SVG → raster blob via\n * `exportImageEditDoc` from `@bendyline/squisq/imageEdit`.\n */\n\nimport { useCallback, useState } from 'react';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { exportImageEditDoc, type ImageEditExportFormat } from '@bendyline/squisq/imageEdit';\nimport type { SurfaceScheme, Theme } from '@bendyline/squisq/schemas';\nimport { CanvasSurface } from './imageEditor/CanvasSurface.js';\nimport { ImageVersionHistoryDropdown } from './imageEditor/ImageVersionHistoryDropdown.js';\nimport { LayersPanel } from './imageEditor/LayersPanel.js';\nimport { PropertiesPanel } from './imageEditor/PropertiesPanel.js';\nimport { Toolbar } from './imageEditor/Toolbar.js';\nimport { useImageEditor } from './imageEditor/useImageEditor.js';\nimport { useImageEditorTokens } from './imageEditor/useImageEditorTokens.js';\n\nexport interface ImageEditorProps {\n /**\n * Scoped sidecar container for this image — typically\n * `scopeContainer(parent, basename + '_files')`.\n */\n filesContainer: ContentContainer;\n /**\n * Source URL used to seed `assets/source.<ext>` and layer 0 the\n * first time the sidecar is opened. Ignored once `state.json` exists.\n */\n initialSrc?: string;\n /** Override the state filename. Default: `state.json`. */\n stateFilename?: string;\n /** Enable version-history snapshots in `.versions/`. Default: `false`. */\n allowVersioning?: boolean;\n /** Auto-save idle delay (ms) for version snapshots. Default: `5000`. */\n versioningAutoSaveIdleMs?: number;\n /** Called after the user clicks Export and the blob is produced. */\n onExport?: (blob: Blob, format: ImageEditExportFormat) => void;\n /**\n * What the toolbar's Save button does:\n * - `'flush'` (default): write `state.json` to the sidecar.\n * - `'export'`: rasterize the canvas in `saveFormat` and fire\n * {@link onExport} — the same code path the Export menu uses.\n * Hosts that want one-click \"save and close\" semantics use this.\n */\n saveBehavior?: 'flush' | 'export';\n /** Format used when `saveBehavior === 'export'`. Default: `'png'`. */\n saveFormat?: ImageEditExportFormat;\n /** Override the Save button label. Default: `'Save'`. */\n saveLabel?: string;\n /** Override the Save button tooltip. */\n saveTitle?: string;\n /**\n * Squisq Theme to color the editor chrome (toolbar, panels, controls).\n * Defaults to `DEFAULT_THEME`. Combined with {@link surface} the same\n * way `<JsonView>` and `<LinearDocView>` do.\n */\n theme?: Theme;\n /**\n * Surface scheme — `LIGHT_SURFACE`, `DARK_SURFACE`, an explicit\n * `SurfaceScheme` object, or `'auto'` to track the user's OS\n * `prefers-color-scheme`. When omitted, the theme's own background is\n * used as-is.\n */\n surface?: SurfaceScheme | 'auto';\n /** Optional className for the root element. */\n className?: string;\n}\n\nexport function ImageEditor(props: ImageEditorProps) {\n const {\n filesContainer,\n initialSrc,\n stateFilename,\n allowVersioning,\n versioningAutoSaveIdleMs,\n onExport,\n saveBehavior = 'flush',\n saveFormat = 'png',\n saveLabel,\n saveTitle,\n theme,\n surface,\n className,\n } = props;\n\n const tokens = useImageEditorTokens(theme, surface);\n\n const { state, dispatch, flush, resolveAssetUrl, uploadAsset, versioning, ready, error } =\n useImageEditor({\n container: filesContainer,\n initialSrc,\n stateFilename,\n allowVersioning,\n versioningAutoSaveIdleMs,\n });\n\n // Bumped after every save/version write so the history popover\n // re-lists without polling.\n const [historyRefreshKey, setHistoryRefreshKey] = useState(0);\n\n const handleExport = useCallback(\n async (format: ImageEditExportFormat) => {\n if (!state) return;\n try {\n const blob = await exportImageEditDoc(state.doc, filesContainer, { format });\n if (onExport) {\n onExport(blob, format);\n } else {\n // Default behavior: trigger a browser download.\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `image.${format === 'jpeg' ? 'jpg' : format}`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n }\n } catch (err: unknown) {\n console.warn(\n '[squisq-editor] image export failed:',\n err instanceof Error ? err.message : err,\n );\n }\n },\n [state, filesContainer, onExport],\n );\n\n /**\n * Save-and-close pipeline. Critical: we must `await flush()` *before*\n * triggering the export, otherwise the parent modal may close (via the\n * `onExport` chain) before the debounced state.json write fires —\n * losing any layer/edit changes since the last debounce. We also save\n * a version snapshot so the history dropdown captures the moment of\n * save and the user can revert later.\n */\n const handleSaveAndClose = useCallback(async () => {\n try {\n await flush();\n if (versioning) {\n try {\n await versioning.saveVersion();\n setHistoryRefreshKey((k) => k + 1);\n } catch (err: unknown) {\n console.warn(\n '[squisq-editor] image-edit save-version failed:',\n err instanceof Error ? err.message : err,\n );\n }\n }\n await handleExport(saveFormat);\n } catch (err: unknown) {\n console.warn(\n '[squisq-editor] image-edit save-and-close failed:',\n err instanceof Error ? err.message : err,\n );\n }\n }, [flush, versioning, handleExport, saveFormat]);\n\n /**\n * Revert `state.json` (and the in-memory editor state) to a prior\n * snapshot. We delegate to `versioning.revertToVersion` so the\n * sidecar write happens through the same code path as direct API\n * use, including a snapshot of the *current* state before overwrite\n * — that way the user can undo a revert via the same dropdown.\n */\n const handleRevertToVersion = useCallback(\n async (version: import('@bendyline/squisq/versions').Version) => {\n if (!versioning) return;\n // Cancel any pending debounced write so it can't clobber the\n // reverted state.json after we replace it.\n try {\n await flush();\n } catch {\n /* swallow — best effort */\n }\n const result = await versioning.revertToVersion(version);\n if (!result.reverted) return;\n const doc = await versioning.readVersion(version);\n if (doc) {\n dispatch({ type: 'load', doc });\n // Bump the history list so the just-saved \\\"pre-revert\\\"\n // snapshot shows up in the dropdown.\n setHistoryRefreshKey((k) => k + 1);\n }\n },\n [dispatch, flush, versioning],\n );\n\n const handleCreateTextAt = useCallback(\n (x: number, y: number) => {\n dispatch({\n type: 'add-layer',\n layer: {\n type: 'text',\n name: 'Text',\n position: { x: Math.round(x), y: Math.round(y), width: 240, height: 48 },\n content: {\n text: 'New text',\n style: { fontSize: 32, color: '#111111', fontFamily: 'sans-serif' },\n },\n },\n });\n dispatch({ type: 'set-tool', tool: 'select' });\n },\n [dispatch],\n );\n\n const handleCreateShapeAt = useCallback(\n (x: number, y: number) => {\n dispatch({\n type: 'add-layer',\n layer: {\n type: 'shape',\n name: 'Rectangle',\n position: {\n x: Math.round(x - 60),\n y: Math.round(y - 40),\n width: 120,\n height: 80,\n },\n content: {\n shape: 'rect',\n fill: '#3399ff',\n stroke: '#1a4d80',\n strokeWidth: 2,\n borderRadius: 8,\n },\n },\n });\n dispatch({ type: 'set-tool', tool: 'select' });\n },\n [dispatch],\n );\n\n if (error) {\n return (\n <div\n className={['squisq-image-editor', className].filter(Boolean).join(' ')}\n style={tokens.style}\n >\n <div className=\"squisq-image-editor-error\">\n Failed to load image editor: {error.message}\n </div>\n </div>\n );\n }\n\n if (!ready || !state) {\n return (\n <div\n className={['squisq-image-editor', className].filter(Boolean).join(' ')}\n style={tokens.style}\n >\n <div className=\"squisq-image-editor-loading\">Loading image editor…</div>\n </div>\n );\n }\n\n return (\n <div\n className={['squisq-image-editor', className].filter(Boolean).join(' ')}\n style={tokens.style}\n data-testid=\"image-editor\"\n >\n <Toolbar\n doc={state.doc}\n tool={state.tool}\n dispatch={dispatch}\n uploadAsset={uploadAsset}\n onExport={handleExport}\n onSave={saveBehavior === 'export' ? handleSaveAndClose : flush}\n saveLabel={saveLabel ?? (saveBehavior === 'export' ? 'Save and close' : 'Save')}\n saveTitle={\n saveTitle ??\n (saveBehavior === 'export'\n ? `Rasterize and save as ${saveFormat.toUpperCase()}`\n : 'Save state.json')\n }\n extraTools={\n versioning ? (\n <ImageVersionHistoryDropdown\n versioning={versioning}\n container={filesContainer}\n onRevert={handleRevertToVersion}\n refreshKey={historyRefreshKey}\n />\n ) : null\n }\n />\n <div className=\"squisq-image-editor-body\">\n <div className=\"squisq-image-editor-center\">\n <CanvasSurface\n doc={state.doc}\n selectedLayerId={state.selectedLayerId}\n tool={state.tool}\n resolveAssetUrl={resolveAssetUrl}\n dispatch={dispatch}\n onCreateTextAt={handleCreateTextAt}\n onCreateShapeAt={handleCreateShapeAt}\n />\n </div>\n <div className=\"squisq-image-editor-side\">\n <LayersPanel\n doc={state.doc}\n selectedLayerId={state.selectedLayerId}\n dispatch={dispatch}\n />\n <PropertiesPanel\n doc={state.doc}\n selectedLayerId={state.selectedLayerId}\n dispatch={dispatch}\n />\n </div>\n </div>\n </div>\n );\n}\n","/**\n * CanvasSurface — the SVG editing surface for `<ImageEditor>`.\n *\n * Renders the doc's canvas (with background and per-layer rendering) in\n * an `<svg>` whose `viewBox` matches the canvas dimensions. Pointer\n * events are normalized to canvas coordinates and dispatched as either\n * selection / drag / resize gestures (select tool) or as a crop-rect\n * gesture (crop tool).\n *\n * Layer rendering uses small purpose-built renderers in `./layers/`,\n * not the heavier `@bendyline/squisq-react` layer components — the\n * editor doesn't need media-context lookup, animation, or\n * blockTime-driven reflow.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';\nimport type { CanvasRect, ImageEditorAction, ImageEditorTool } from './state.js';\nimport { EditorImageLayer } from './layers/EditorImageLayer.js';\nimport { EditorTextLayer } from './layers/EditorTextLayer.js';\nimport { EditorShapeLayer } from './layers/EditorShapeLayer.js';\nimport { SelectionHandles, type Handle } from './layers/SelectionHandles.js';\n\nexport interface CanvasSurfaceProps {\n doc: ImageEditDoc;\n selectedLayerId: string | null;\n tool: ImageEditorTool;\n resolveAssetUrl: (path: string) => Promise<string>;\n dispatch: (action: ImageEditorAction) => void;\n /** When the text tool drops a new layer at a given canvas point. */\n onCreateTextAt?: (x: number, y: number) => void;\n /** When the shape tool drops a new layer at a given canvas point. */\n onCreateShapeAt?: (x: number, y: number) => void;\n /** Background fill behind the canvas (the editor \"paper\"). */\n workspaceBackground?: string;\n}\n\ninterface DragState {\n layerId: string;\n startCanvasX: number;\n startCanvasY: number;\n startBox: CanvasRect;\n handle: Handle | 'move';\n}\n\ninterface CropDragState {\n startCanvasX: number;\n startCanvasY: number;\n currentX: number;\n currentY: number;\n}\n\nexport function CanvasSurface({\n doc,\n selectedLayerId,\n tool,\n resolveAssetUrl,\n dispatch,\n onCreateTextAt,\n onCreateShapeAt,\n workspaceBackground,\n}: CanvasSurfaceProps) {\n const svgRef = useRef<SVGSVGElement | null>(null);\n const dragRef = useRef<DragState | null>(null);\n const [, forceRender] = useState(0);\n const [cropDrag, setCropDrag] = useState<CropDragState | null>(null);\n\n /** Convert client-space coordinates to canvas coordinates. */\n const toCanvas = useCallback(\n (clientX: number, clientY: number): { x: number; y: number } => {\n const svg = svgRef.current;\n if (!svg) return { x: 0, y: 0 };\n const rect = svg.getBoundingClientRect();\n const x = ((clientX - rect.left) / rect.width) * doc.canvas.width;\n const y = ((clientY - rect.top) / rect.height) * doc.canvas.height;\n return { x, y };\n },\n [doc.canvas.width, doc.canvas.height],\n );\n\n // ── Pointer handlers ───────────────────────────────────────────────────\n const onPointerDownLayer = useCallback(\n (e: React.PointerEvent<SVGGElement>, layer: ImageEditLayer) => {\n if (tool !== 'select') return;\n if (layer.locked) return;\n e.stopPropagation();\n const pt = toCanvas(e.clientX, e.clientY);\n dispatch({ type: 'select', layerId: layer.id });\n const box = layerBox(layer, doc);\n dragRef.current = {\n layerId: layer.id,\n startCanvasX: pt.x,\n startCanvasY: pt.y,\n startBox: box,\n handle: 'move',\n };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n },\n [tool, dispatch, toCanvas, doc],\n );\n\n const onPointerDownHandle = useCallback(\n (e: React.PointerEvent<SVGRectElement>, handle: Handle) => {\n if (!selectedLayerId) return;\n const layer = doc.layers.find((l) => l.id === selectedLayerId);\n if (!layer || layer.locked) return;\n e.stopPropagation();\n const pt = toCanvas(e.clientX, e.clientY);\n const box = layerBox(layer, doc);\n dragRef.current = {\n layerId: layer.id,\n startCanvasX: pt.x,\n startCanvasY: pt.y,\n startBox: box,\n handle,\n };\n (e.target as Element).setPointerCapture?.(e.pointerId);\n },\n [selectedLayerId, doc, toCanvas],\n );\n\n const onPointerDownEmpty = useCallback(\n (e: React.PointerEvent<SVGSVGElement>) => {\n const pt = toCanvas(e.clientX, e.clientY);\n if (tool === 'select') {\n dispatch({ type: 'select', layerId: null });\n return;\n }\n if (tool === 'crop') {\n e.preventDefault();\n setCropDrag({ startCanvasX: pt.x, startCanvasY: pt.y, currentX: pt.x, currentY: pt.y });\n (e.target as Element).setPointerCapture?.(e.pointerId);\n return;\n }\n if (tool === 'text') {\n onCreateTextAt?.(pt.x, pt.y);\n return;\n }\n if (tool === 'shape') {\n onCreateShapeAt?.(pt.x, pt.y);\n }\n },\n [tool, dispatch, toCanvas, onCreateTextAt, onCreateShapeAt],\n );\n\n useEffect(() => {\n function onMove(e: PointerEvent) {\n const drag = dragRef.current;\n if (drag) {\n const pt = toCanvas(e.clientX, e.clientY);\n const dx = pt.x - drag.startCanvasX;\n const dy = pt.y - drag.startCanvasY;\n const next = applyHandle(drag.startBox, drag.handle, dx, dy);\n dispatch({\n type: 'update-layer',\n layerId: drag.layerId,\n patch: {\n position: {\n x: Math.round(next.x),\n y: Math.round(next.y),\n width: Math.round(next.width),\n height: Math.round(next.height),\n },\n },\n });\n return;\n }\n if (cropDrag) {\n const pt = toCanvas(e.clientX, e.clientY);\n setCropDrag((prev) => (prev ? { ...prev, currentX: pt.x, currentY: pt.y } : prev));\n }\n }\n function onUp() {\n if (dragRef.current) {\n dragRef.current = null;\n forceRender((n) => n + 1);\n }\n if (cropDrag) {\n const rect = normalizeCropRect(cropDrag);\n if (rect.width >= 8 && rect.height >= 8) {\n dispatch({ type: 'crop', rect });\n dispatch({ type: 'set-tool', tool: 'select' });\n }\n setCropDrag(null);\n }\n }\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onUp);\n return () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onUp);\n };\n }, [toCanvas, dispatch, cropDrag]);\n\n // ── Render ─────────────────────────────────────────────────────────────\n const selectedLayer = selectedLayerId\n ? (doc.layers.find((l) => l.id === selectedLayerId) ?? null)\n : null;\n const selectedBox = selectedLayer ? layerBox(selectedLayer, doc) : null;\n const selectionBox =\n selectedLayer && selectedLayer.type === 'text'\n ? measureTextLayerBox(selectedLayer, selectedBox!)\n : selectedBox;\n\n return (\n <div\n className=\"squisq-image-editor-surface\"\n style={{ background: workspaceBackground ?? '#1f1f24' }}\n >\n <svg\n ref={svgRef}\n viewBox={`0 0 ${doc.canvas.width} ${doc.canvas.height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n className={`squisq-image-editor-canvas squisq-image-editor-canvas--tool-${tool}`}\n onPointerDown={onPointerDownEmpty}\n >\n {/* Canvas background */}\n <rect\n x={0}\n y={0}\n width={doc.canvas.width}\n height={doc.canvas.height}\n fill={\n doc.canvas.background && doc.canvas.background !== 'transparent'\n ? doc.canvas.background\n : 'url(#squisq-image-editor-checker)'\n }\n />\n <defs>\n <pattern\n id=\"squisq-image-editor-checker\"\n width=\"16\"\n height=\"16\"\n patternUnits=\"userSpaceOnUse\"\n >\n <rect width=\"16\" height=\"16\" fill=\"#f0f0f0\" />\n <rect width=\"8\" height=\"8\" fill=\"#d0d0d0\" />\n <rect x=\"8\" y=\"8\" width=\"8\" height=\"8\" fill=\"#d0d0d0\" />\n </pattern>\n </defs>\n\n {/* Layers, back-to-front */}\n {doc.layers.map((layer) => {\n if (layer.visible === false) return null;\n const onPointerDown = (e: React.PointerEvent<SVGGElement>) =>\n onPointerDownLayer(e, layer);\n const opacity = layer.opacity ?? 1;\n return (\n <g\n key={layer.id}\n data-layer-id={layer.id}\n opacity={opacity}\n style={{ cursor: tool === 'select' && !layer.locked ? 'move' : undefined }}\n onPointerDown={onPointerDown}\n >\n {layer.type === 'image' && (\n <EditorImageLayer\n layer={layer}\n canvas={doc.canvas}\n resolveAssetUrl={resolveAssetUrl}\n />\n )}\n {layer.type === 'text' && <EditorTextLayer layer={layer} canvas={doc.canvas} />}\n {layer.type === 'shape' && <EditorShapeLayer layer={layer} canvas={doc.canvas} />}\n </g>\n );\n })}\n\n {/* Selection handles */}\n {selectedLayer && selectionBox && tool === 'select' && !selectedLayer.locked && (\n <SelectionHandles box={selectionBox} onHandlePointerDown={onPointerDownHandle} />\n )}\n\n {/* Crop rectangle preview */}\n {cropDrag &&\n (() => {\n const r = normalizeCropRect(cropDrag);\n return (\n <g pointerEvents=\"none\">\n <rect\n x={r.x}\n y={r.y}\n width={r.width}\n height={r.height}\n fill=\"rgba(255,255,255,0.05)\"\n stroke=\"#39f\"\n strokeWidth={2}\n strokeDasharray=\"6 4\"\n />\n </g>\n );\n })()}\n </svg>\n </div>\n );\n}\n\n// ============================================\n// Helpers\n// ============================================\n\n/** Resolve a layer's pixel box, ignoring anchor/percentage strings (the editor authors numeric coords). */\nfunction layerBox(layer: ImageEditLayer, doc: ImageEditDoc): CanvasRect {\n const p = layer.position;\n const x = typeof p.x === 'number' ? p.x : 0;\n const y = typeof p.y === 'number' ? p.y : 0;\n const width = typeof p.width === 'number' ? p.width : doc.canvas.width;\n const height = typeof p.height === 'number' ? p.height : doc.canvas.height;\n return { x, y, width, height };\n}\n\nconst MIN_DIM = 4;\n\nfunction applyHandle(box: CanvasRect, handle: Handle | 'move', dx: number, dy: number): CanvasRect {\n if (handle === 'move') return { ...box, x: box.x + dx, y: box.y + dy };\n let { x, y, width, height } = box;\n // Each handle adjusts a subset of (x, y, width, height).\n if (handle.includes('w')) {\n const newWidth = Math.max(MIN_DIM, width - dx);\n x = x + (width - newWidth);\n width = newWidth;\n } else if (handle.includes('e')) {\n width = Math.max(MIN_DIM, width + dx);\n }\n if (handle.includes('n')) {\n const newHeight = Math.max(MIN_DIM, height - dy);\n y = y + (height - newHeight);\n height = newHeight;\n } else if (handle.includes('s')) {\n height = Math.max(MIN_DIM, height + dy);\n }\n return { x, y, width, height };\n}\n\nfunction normalizeCropRect(d: CropDragState): CanvasRect {\n const x = Math.min(d.startCanvasX, d.currentX);\n const y = Math.min(d.startCanvasY, d.currentY);\n const width = Math.abs(d.currentX - d.startCanvasX);\n const height = Math.abs(d.currentY - d.startCanvasY);\n return { x, y, width, height };\n}\n\n/**\n * Measure the visual bounding box of a text layer using a 2D canvas.\n * Falls back to the layer's authored width/height if measurement isn't\n * available (SSR, headless test envs without canvas). The returned box\n * tightly wraps the rendered glyphs so the selection rectangle hugs the\n * actual text rather than an arbitrary author-supplied frame.\n */\nlet measureCtx: CanvasRenderingContext2D | null | undefined;\nfunction getMeasureCtx(): CanvasRenderingContext2D | null {\n if (measureCtx !== undefined) return measureCtx;\n if (typeof document === 'undefined') {\n measureCtx = null;\n return null;\n }\n try {\n const c = document.createElement('canvas');\n measureCtx = c.getContext('2d');\n } catch {\n measureCtx = null;\n }\n return measureCtx ?? null;\n}\n\nfunction measureTextLayerBox(\n layer: ImageEditLayer & { type: 'text' },\n fallback: CanvasRect,\n): CanvasRect {\n const ctx = getMeasureCtx();\n if (!ctx) return fallback;\n const { text, style } = layer.content;\n const fontSize = style.fontSize;\n const fontWeight = style.fontWeight ?? 'normal';\n const fontFamily = style.fontFamily ?? 'sans-serif';\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n const lines = (text ?? '').split('\\n');\n let maxWidth = 0;\n for (const line of lines) {\n const w = ctx.measureText(line || ' ').width;\n if (w > maxWidth) maxWidth = w;\n }\n const lineHeight = style.lineHeight ?? 1.4;\n const lineHeightPx = fontSize * lineHeight;\n // First line spans fontSize tall; subsequent lines add lineHeightPx each.\n const totalHeight = fontSize + Math.max(0, lines.length - 1) * lineHeightPx;\n // Mirror the textAnchor logic in EditorTextLayer.\n const anchor =\n style.textAlign === 'center' ? 'middle' : style.textAlign === 'right' ? 'end' : 'start';\n const x =\n anchor === 'middle'\n ? fallback.x - maxWidth / 2\n : anchor === 'end'\n ? fallback.x - maxWidth\n : fallback.x;\n return {\n x,\n y: fallback.y,\n width: Math.max(MIN_DIM, Math.ceil(maxWidth)),\n height: Math.max(MIN_DIM, Math.ceil(totalHeight)),\n };\n}\n","/**\n * SVG renderer for an `ImageEditLayer` of kind `image` inside the editor.\n * Resolves the asset path to a blob URL via the host-supplied\n * `resolveAssetUrl` (typically backed by the sidecar container).\n */\n\nimport { useEffect, useState } from 'react';\nimport type { ImageEditCanvas, ImageEditLayer } from '@bendyline/squisq/schemas';\n\ninterface Props {\n layer: ImageEditLayer & { type: 'image' };\n canvas: ImageEditCanvas;\n resolveAssetUrl: (path: string) => Promise<string>;\n}\n\nexport function EditorImageLayer({ layer, canvas, resolveAssetUrl }: Props) {\n const [href, setHref] = useState<string | null>(null);\n const src = layer.content.src;\n\n useEffect(() => {\n let cancelled = false;\n resolveAssetUrl(src)\n .then((url) => {\n if (!cancelled) setHref(url);\n })\n .catch(() => {\n if (!cancelled) setHref(null);\n });\n return () => {\n cancelled = true;\n };\n }, [src, resolveAssetUrl]);\n\n if (!href) return null;\n\n const p = layer.position;\n const x = typeof p.x === 'number' ? p.x : 0;\n const y = typeof p.y === 'number' ? p.y : 0;\n const width = typeof p.width === 'number' ? p.width : canvas.width;\n const height = typeof p.height === 'number' ? p.height : canvas.height;\n const fit = layer.content.fit ?? 'fill';\n const par = fit === 'cover' ? 'xMidYMid slice' : fit === 'contain' ? 'xMidYMid meet' : 'none';\n\n return <image href={href} x={x} y={y} width={width} height={height} preserveAspectRatio={par} />;\n}\n","/**\n * SVG renderer for an `ImageEditLayer` of kind `text` inside the editor.\n *\n * Multi-line text is laid out as a `<text>` element with one `<tspan>`\n * per line. The first line sits at `y + fontSize` so the visible top\n * of the glyph block aligns with the layer's `y` coordinate (matches\n * what users expect from a top-anchored bounding box).\n */\n\nimport type { ImageEditCanvas, ImageEditLayer } from '@bendyline/squisq/schemas';\n\ninterface Props {\n layer: ImageEditLayer & { type: 'text' };\n canvas: ImageEditCanvas;\n}\n\nexport function EditorTextLayer({ layer, canvas: _canvas }: Props) {\n const p = layer.position;\n const x = typeof p.x === 'number' ? p.x : 0;\n const y = typeof p.y === 'number' ? p.y : 0;\n const { text, style } = layer.content;\n const lineHeight = style.lineHeight ?? 1.4;\n const lineHeightPx = style.fontSize * lineHeight;\n const lines = (text ?? '').split('\\n');\n const textAnchor =\n style.textAlign === 'center' ? 'middle' : style.textAlign === 'right' ? 'end' : 'start';\n\n return (\n <text\n x={x}\n y={y + style.fontSize}\n fontFamily={style.fontFamily ?? 'sans-serif'}\n fontSize={style.fontSize}\n fontWeight={style.fontWeight ?? 'normal'}\n fill={style.color}\n textAnchor={textAnchor}\n >\n {lines.map((line, i) => (\n <tspan key={i} x={x} dy={i === 0 ? 0 : lineHeightPx}>\n {line || '\\u00A0'}\n </tspan>\n ))}\n </text>\n );\n}\n","/**\n * SVG renderer for an `ImageEditLayer` of kind `shape` inside the editor.\n * Mirrors `react/src/layers/ShapeLayer.tsx` minus the animation/anchor\n * logic since the editor authors layers with numeric, top-left positions.\n */\n\nimport type { ImageEditCanvas, ImageEditLayer } from '@bendyline/squisq/schemas';\n\ninterface Props {\n layer: ImageEditLayer & { type: 'shape' };\n canvas: ImageEditCanvas;\n}\n\nexport function EditorShapeLayer({ layer, canvas: _canvas }: Props) {\n const p = layer.position;\n const x = typeof p.x === 'number' ? p.x : 0;\n const y = typeof p.y === 'number' ? p.y : 0;\n const width = typeof p.width === 'number' ? p.width : 100;\n const height = typeof p.height === 'number' ? p.height : 100;\n const c = layer.content;\n const fill = c.fill ?? 'none';\n const stroke = c.stroke;\n const strokeWidth = c.strokeWidth;\n\n if (c.shape === 'rect') {\n return (\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n rx={c.borderRadius}\n ry={c.borderRadius}\n fill={fill}\n stroke={stroke}\n strokeWidth={strokeWidth}\n />\n );\n }\n if (c.shape === 'circle') {\n return (\n <circle\n cx={x + width / 2}\n cy={y + height / 2}\n r={Math.min(width, height) / 2}\n fill={fill}\n stroke={stroke}\n strokeWidth={strokeWidth}\n />\n );\n }\n return (\n <line\n x1={x}\n y1={y}\n x2={x + width}\n y2={y + height}\n stroke={stroke ?? '#000'}\n strokeWidth={strokeWidth ?? 1}\n />\n );\n}\n","/**\n * SelectionHandles\n *\n * Renders the dashed selection rectangle plus eight resize handles around\n * the currently-selected layer's bounding box. Pointer events on each\n * handle bubble back through `onHandlePointerDown` so the surrounding\n * `<CanvasSurface>` can run its drag loop with the right resize semantics.\n */\n\nimport type { CanvasRect } from '../state.js';\n\nexport type Handle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';\n\nconst HANDLE_SIZE = 10; // canvas-pixel size of each square handle\n\ninterface Props {\n box: CanvasRect;\n onHandlePointerDown: (e: React.PointerEvent<SVGRectElement>, handle: Handle) => void;\n}\n\nexport function SelectionHandles({ box, onHandlePointerDown }: Props) {\n const half = HANDLE_SIZE / 2;\n const cx = box.x + box.width / 2;\n const cy = box.y + box.height / 2;\n\n const handles: Array<{ id: Handle; x: number; y: number; cursor: string }> = [\n { id: 'nw', x: box.x, y: box.y, cursor: 'nwse-resize' },\n { id: 'n', x: cx, y: box.y, cursor: 'ns-resize' },\n { id: 'ne', x: box.x + box.width, y: box.y, cursor: 'nesw-resize' },\n { id: 'e', x: box.x + box.width, y: cy, cursor: 'ew-resize' },\n { id: 'se', x: box.x + box.width, y: box.y + box.height, cursor: 'nwse-resize' },\n { id: 's', x: cx, y: box.y + box.height, cursor: 'ns-resize' },\n { id: 'sw', x: box.x, y: box.y + box.height, cursor: 'nesw-resize' },\n { id: 'w', x: box.x, y: cy, cursor: 'ew-resize' },\n ];\n\n return (\n <g pointerEvents=\"none\">\n {/*\n * Outline: rendered as two stacked rectangles so the selection\n * stays visible over both light and dark imagery. The white\n * \"halo\" goes underneath; the blue dashed line on top. Both use\n * `vector-effect: non-scaling-stroke` so the stroke width stays\n * crisp at any zoom level (the SVG viewBox is the canvas size,\n * which can be much larger than the rendered element).\n */}\n <rect\n x={box.x}\n y={box.y}\n width={box.width}\n height={box.height}\n fill=\"none\"\n stroke=\"#ffffff\"\n strokeOpacity={0.9}\n strokeWidth={4}\n vectorEffect=\"non-scaling-stroke\"\n />\n <rect\n x={box.x}\n y={box.y}\n width={box.width}\n height={box.height}\n fill=\"none\"\n stroke=\"#39f\"\n strokeWidth={2}\n strokeDasharray=\"6 4\"\n vectorEffect=\"non-scaling-stroke\"\n />\n {handles.map((h) => (\n <rect\n key={h.id}\n x={h.x - half}\n y={h.y - half}\n width={HANDLE_SIZE}\n height={HANDLE_SIZE}\n fill=\"#fff\"\n stroke=\"#39f\"\n strokeWidth={2}\n vectorEffect=\"non-scaling-stroke\"\n style={{ cursor: h.cursor, pointerEvents: 'all' }}\n onPointerDown={(e) => onHandlePointerDown(e, h.id)}\n />\n ))}\n </g>\n );\n}\n","/**\n * ImageVersionHistoryDropdown\n *\n * Toolbar-anchored popover that lists image-edit version snapshots from\n * the sidecar and lets the user revert to any of them.\n *\n * For each snapshot we render a small thumbnail (rasterized via\n * `exportImageEditDoc` at a thumbnail-sized scale) plus a one-line diff\n * summary describing what changed relative to the *previous* (older)\n * snapshot — e.g. \"Resized 4800×920 → 1200×920\", \"Added text layer\",\n * \"Removed Background\". This makes it possible to identify the right\n * snapshot to revert to without having to revert blindly.\n *\n * Thumbnails and diffs are computed lazily and cached by version path.\n * Loads happen in the background after the popover opens.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n exportImageEditDoc,\n type ImageEditDoc,\n type ImageEditLayer,\n type ImageEditVersionManager,\n} from '@bendyline/squisq/imageEdit';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport type { Version } from '@bendyline/squisq/versions';\n\ninterface Props {\n versioning: ImageEditVersionManager;\n /**\n * Sidecar container backing the snapshots — same one passed to the\n * `<ImageEditor>`. Required for thumbnail rendering since\n * `exportImageEditDoc` reads asset bytes from the container.\n */\n container: ContentContainer;\n /** Called when the user picks a snapshot to load into the editor. */\n onRevert: (version: Version) => void | Promise<void>;\n /**\n * Persistence revision counter. When the host saves a new snapshot\n * (e.g. on flush), bumping this triggers a re-list so the popover\n * stays in sync without polling.\n */\n refreshKey?: number;\n}\n\ninterface VersionMeta {\n doc: ImageEditDoc;\n thumbUrl: string | null;\n}\n\nconst THUMB_MAX_DIM = 96;\n\nexport function ImageVersionHistoryDropdown({\n versioning,\n container,\n onRevert,\n refreshKey,\n}: Props) {\n const [open, setOpen] = useState(false);\n const [versions, setVersions] = useState<Version[]>([]);\n const [loading, setLoading] = useState(false);\n const [busyTimestamp, setBusyTimestamp] = useState<number | null>(null);\n // Per-version metadata (doc + thumbnail). Keyed by version.path.\n const [meta, setMeta] = useState<Record<string, VersionMeta>>({});\n const popoverRef = useRef<HTMLDivElement | null>(null);\n const triggerRef = useRef<HTMLButtonElement | null>(null);\n // Track object URLs so we can revoke them on unmount / cache reset.\n const urlsRef = useRef<Set<string>>(new Set());\n\n // Re-load the list when the popover opens or when the host bumps refreshKey.\n useEffect(() => {\n if (!open) return;\n let cancelled = false;\n setLoading(true);\n versioning\n .listVersions()\n .then((list) => {\n if (cancelled) return;\n // Newest first.\n const sorted = [...list].sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n setVersions(sorted);\n })\n .catch(() => {\n if (cancelled) return;\n setVersions([]);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [open, versioning, refreshKey]);\n\n // Lazily load doc + thumbnail for any version we don't have cached yet.\n // We do this sequentially to avoid hammering the canvas pipeline.\n useEffect(() => {\n if (!open) return;\n if (versions.length === 0) return;\n let cancelled = false;\n (async () => {\n for (const v of versions) {\n if (cancelled) return;\n if (meta[v.path]) continue;\n try {\n const doc = await versioning.readVersion(v);\n if (cancelled) return;\n if (!doc) {\n setMeta((m) => ({ ...m, [v.path]: { doc: emptyDoc(), thumbUrl: null } }));\n continue;\n }\n let thumbUrl: string | null = null;\n try {\n const scale = computeThumbScale(doc.canvas.width, doc.canvas.height);\n const blob = await exportImageEditDoc(doc, container, {\n format: 'png',\n scale,\n });\n if (cancelled) return;\n thumbUrl = URL.createObjectURL(blob);\n urlsRef.current.add(thumbUrl);\n } catch {\n // Best-effort thumbnail — fall back to a placeholder.\n thumbUrl = null;\n }\n setMeta((m) => ({ ...m, [v.path]: { doc, thumbUrl } }));\n } catch {\n // Skip on read error; the row will render without a thumb.\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [open, versions, versioning, container, meta]);\n\n // Revoke object URLs on unmount.\n useEffect(() => {\n const urls = urlsRef.current;\n return () => {\n for (const url of urls) URL.revokeObjectURL(url);\n urls.clear();\n };\n }, []);\n\n // When refreshKey changes, blow away the cache so newly-saved\n // snapshots are re-thumbnailed (and old thumbs aren't stale).\n useEffect(() => {\n for (const url of urlsRef.current) URL.revokeObjectURL(url);\n urlsRef.current.clear();\n setMeta({});\n }, [refreshKey]);\n\n // Close on outside click / Escape.\n useEffect(() => {\n if (!open) return;\n function onDocClick(e: MouseEvent) {\n const t = e.target as Node | null;\n if (!t) return;\n if (popoverRef.current?.contains(t)) return;\n if (triggerRef.current?.contains(t)) return;\n setOpen(false);\n }\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') setOpen(false);\n }\n document.addEventListener('mousedown', onDocClick);\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('mousedown', onDocClick);\n document.removeEventListener('keydown', onKey);\n };\n }, [open]);\n\n const handleRevert = useCallback(\n async (v: Version) => {\n setBusyTimestamp(v.timestamp.getTime());\n try {\n await onRevert(v);\n setOpen(false);\n } catch (err: unknown) {\n console.warn(\n '[squisq-editor] image-edit revert failed:',\n err instanceof Error ? err.message : err,\n );\n } finally {\n setBusyTimestamp(null);\n }\n },\n [onRevert],\n );\n\n return (\n <div className=\"squisq-image-editor-version-dropdown\">\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"squisq-image-editor-tool-button squisq-image-editor-tool-button--with-label\"\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-haspopup=\"menu\"\n title=\"Version history\"\n data-testid=\"image-editor-history-trigger\"\n >\n <span>History</span>\n <span aria-hidden=\"true\" style={{ fontSize: '0.8em' }}>\n ▾\n </span>\n </button>\n {open && (\n <div\n ref={popoverRef}\n className=\"squisq-image-editor-version-popover\"\n role=\"menu\"\n data-testid=\"image-editor-history-popover\"\n >\n <div className=\"squisq-image-editor-version-popover__title\">Version history</div>\n {loading && <div className=\"squisq-image-editor-version-popover__empty\">Loading…</div>}\n {!loading && versions.length === 0 && (\n <div className=\"squisq-image-editor-version-popover__empty\">No snapshots yet</div>\n )}\n {!loading && versions.length > 0 && (\n <ul className=\"squisq-image-editor-version-popover__list\">\n {versions.map((v, i) => {\n const ts = v.timestamp.getTime();\n const m = meta[v.path];\n const isCurrent = i === 0;\n const isOriginal = i + 1 >= versions.length;\n // Diff is computed against the *next* (older) version in\n // the newest-first list. The oldest snapshot has no\n // older neighbor, so we label it \"Original\".\n const olderMeta = i + 1 < versions.length ? meta[versions[i + 1]!.path] : undefined;\n const summary = isOriginal\n ? 'Original'\n : m && olderMeta\n ? summarizeDiff(olderMeta.doc, m.doc)\n : '';\n return (\n <li\n key={ts}\n className={\n 'squisq-image-editor-version-popover__row' +\n (isCurrent ? ' squisq-image-editor-version-popover__row--current' : '')\n }\n >\n <div className=\"squisq-image-editor-version-popover__thumb\">\n {m?.thumbUrl ? (\n <img\n src={m.thumbUrl}\n alt=\"\"\n className=\"squisq-image-editor-version-popover__thumb-img\"\n />\n ) : (\n <div\n className=\"squisq-image-editor-version-popover__thumb-placeholder\"\n aria-hidden=\"true\"\n />\n )}\n </div>\n <div className=\"squisq-image-editor-version-popover__info\">\n <div className=\"squisq-image-editor-version-popover__when\">\n {isCurrent && (\n <span className=\"squisq-image-editor-version-popover__badge\">\n Current\n </span>\n )}\n {formatTimestamp(v.timestamp)}\n </div>\n <div className=\"squisq-image-editor-version-popover__summary\" title={summary}>\n {summary || (m ? '' : 'Loading…')}\n </div>\n </div>\n <button\n type=\"button\"\n className=\"squisq-image-editor-tool-button\"\n onClick={() => handleRevert(v)}\n disabled={isCurrent || busyTimestamp === ts}\n title={isCurrent ? 'This is the current version' : 'Revert to this version'}\n >\n {busyTimestamp === ts ? 'Loading…' : 'Revert'}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n )}\n </div>\n );\n}\n\n/**\n * Pick a `scale` factor for `exportImageEditDoc` so the rendered\n * thumbnail's longest side is at most `THUMB_MAX_DIM` pixels. Always\n * ≤1 to avoid up-rendering small canvases.\n */\nfunction computeThumbScale(width: number, height: number): number {\n const longest = Math.max(width, height);\n if (longest <= THUMB_MAX_DIM) return 1;\n return THUMB_MAX_DIM / longest;\n}\n\n/**\n * Convert a Date to a human-readable local time.\n */\nfunction formatTimestamp(stamp: Date): string {\n if (Number.isNaN(stamp.getTime())) return String(stamp);\n return stamp.toLocaleString(undefined, {\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n });\n}\n\n/**\n * Build a one-line, human-readable summary of what changed between\n * two snapshots. Reports (in priority order):\n *\n * 1. Canvas size change — \"Resized 4800×920 → 1200×920\"\n * 2. Layer additions/removals — \"Added text\", \"Removed Background\"\n * 3. Per-layer position/size — \"Moved Text\", \"Resized Image\"\n * 4. Per-layer content/style — \"Edited Text\"\n *\n * Returns \"No changes\" if the two docs are byte-equivalent in the\n * fields we compare.\n */\nfunction summarizeDiff(prev: ImageEditDoc, next: ImageEditDoc): string {\n const parts: string[] = [];\n\n // 1. Canvas size.\n if (prev.canvas.width !== next.canvas.width || prev.canvas.height !== next.canvas.height) {\n parts.push(\n `Resized ${prev.canvas.width}×${prev.canvas.height} → ${next.canvas.width}×${next.canvas.height}`,\n );\n } else if (prev.canvas.background !== next.canvas.background) {\n parts.push('Changed background');\n }\n\n // 2. Layer add / remove (by id).\n const prevIds = new Set(prev.layers.map((l) => l.id));\n const nextIds = new Set(next.layers.map((l) => l.id));\n const added = next.layers.filter((l) => !prevIds.has(l.id));\n const removed = prev.layers.filter((l) => !nextIds.has(l.id));\n for (const l of added) parts.push(`Added ${describeLayer(l)}`);\n for (const l of removed) parts.push(`Removed ${describeLayer(l)}`);\n\n // 3 & 4. Per-layer changes for layers present in both.\n for (const n of next.layers) {\n const p = prev.layers.find((l) => l.id === n.id);\n if (!p) continue;\n const change = describeLayerChange(p, n);\n if (change) parts.push(change);\n }\n\n if (parts.length === 0) return 'No changes';\n // Cap to a sane length — the popover row is one line.\n return parts.slice(0, 3).join(' · ') + (parts.length > 3 ? ` (+${parts.length - 3})` : '');\n}\n\nfunction describeLayer(layer: ImageEditLayer): string {\n const name = layer.name?.trim();\n return name && name.length > 0 ? `“${name}”` : layer.type;\n}\n\nfunction describeLayerChange(p: ImageEditLayer, n: ImageEditLayer): string | null {\n const label = describeLayer(n);\n const posChanged =\n p.position.x !== n.position.x ||\n p.position.y !== n.position.y ||\n p.position.width !== n.position.width ||\n p.position.height !== n.position.height;\n const sizeChanged =\n p.position.width !== n.position.width || p.position.height !== n.position.height;\n // Treat content + style as a single \"edited\" bucket.\n const contentChanged = JSON.stringify(p.content) !== JSON.stringify(n.content);\n\n if (sizeChanged && !contentChanged) return `Resized ${label}`;\n if (posChanged && !contentChanged) return `Moved ${label}`;\n if (contentChanged) return `Edited ${label}`;\n return null;\n}\n\n/**\n * Fallback used when a snapshot fails to load — keeps render code\n * branch-free without polluting the diff summary with errors.\n */\nfunction emptyDoc(): ImageEditDoc {\n return {\n version: 1,\n canvas: { width: 0, height: 0, background: 'transparent' },\n layers: [],\n };\n}\n","/**\n * Inline SVG line icons for the image editor chrome. Stroke-based,\n * `currentColor`-driven so they pick up `--squisq-image-editor-text` etc.\n * automatically. Sized via `font-size`/`em` so they scale with their\n * button label. Kept inline (no sprite, no font) so the package has zero\n * extra runtime cost and tree-shakes per-icon.\n */\n\nimport type { SVGProps } from 'react';\n\ntype IconProps = Omit<SVGProps<SVGSVGElement>, 'children'>;\n\nfunction Svg({ children, ...rest }: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.75}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...rest}\n >\n {children}\n </svg>\n );\n}\n\nexport function EyeIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M2.5 12s3.5-6.5 9.5-6.5S21.5 12 21.5 12s-3.5 6.5-9.5 6.5S2.5 12 2.5 12Z\" />\n <circle cx=\"12\" cy=\"12\" r=\"2.75\" />\n </Svg>\n );\n}\n\nexport function EyeOffIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M3.5 3.5l17 17\" />\n <path d=\"M9.5 5.7A10.6 10.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a17 17 0 0 1-3.2 4\" />\n <path d=\"M6.2 7.6A17 17 0 0 0 2.5 12s3.5 6.5 9.5 6.5a10.6 10.6 0 0 0 4.3-.9\" />\n <path d=\"M9.9 9.9a3 3 0 0 0 4.2 4.2\" />\n </Svg>\n );\n}\n\nexport function LockIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <rect x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"1.5\" />\n <path d=\"M8 11V8a4 4 0 0 1 8 0v3\" />\n </Svg>\n );\n}\n\nexport function UnlockIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <rect x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"1.5\" />\n <path d=\"M8 11V8a4 4 0 0 1 7.6-1.7\" />\n </Svg>\n );\n}\n\nexport function ChevronUpIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M6 14l6-6 6 6\" />\n </Svg>\n );\n}\n\nexport function ChevronDownIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M6 10l6 6 6-6\" />\n </Svg>\n );\n}\n\nexport function CloseIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M6 6l12 12M18 6L6 18\" />\n </Svg>\n );\n}\n\nexport function CursorIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M5 4l6.5 14.5 2.2-6 6-2.2L5 4Z\" />\n </Svg>\n );\n}\n\nexport function TextIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M5 6h14M12 6v13M9 19h6\" />\n </Svg>\n );\n}\n\nexport function ShapeIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\" />\n </Svg>\n );\n}\n\nexport function CropIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M7 2v15a1 1 0 0 0 1 1h15\" />\n <path d=\"M2 7h15a1 1 0 0 1 1 1v15\" />\n </Svg>\n );\n}\n\nexport function PlusIcon(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M12 5v14M5 12h14\" />\n </Svg>\n );\n}\n\nexport function NoneIcon(props: IconProps) {\n // Used for \"no fill / transparent\" affordance.\n return (\n <Svg {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n <path d=\"M6.3 6.3l11.4 11.4\" />\n </Svg>\n );\n}\n","/**\n * LayersPanel — list of layers with visibility / lock / reorder / delete\n * controls. Newest layer is rendered last (top of the SVG stack), so the\n * panel shows the array reversed so \"top\" appears at the top of the list.\n */\n\nimport type { ImageEditDoc } from '@bendyline/squisq/schemas';\nimport type { ImageEditorAction } from './state.js';\nimport {\n ChevronDownIcon,\n ChevronUpIcon,\n CloseIcon,\n EyeIcon,\n EyeOffIcon,\n LockIcon,\n UnlockIcon,\n} from './icons.js';\n\nexport interface LayersPanelProps {\n doc: ImageEditDoc;\n selectedLayerId: string | null;\n dispatch: (action: ImageEditorAction) => void;\n}\n\nexport function LayersPanel({ doc, selectedLayerId, dispatch }: LayersPanelProps) {\n // Visual order: top of stack first.\n const ordered = doc.layers.slice().reverse();\n\n return (\n <div className=\"squisq-image-editor-layers\" data-testid=\"image-editor-layers\">\n <div className=\"squisq-image-editor-panel-header\">Layers</div>\n <ul className=\"squisq-image-editor-layer-list\">\n {ordered.length === 0 && <li className=\"squisq-image-editor-layer-empty\">No layers yet</li>}\n {ordered.map((layer) => {\n const visible = layer.visible !== false;\n const locked = !!layer.locked;\n const stackIndex = doc.layers.findIndex((l) => l.id === layer.id);\n const canMoveUp = stackIndex < doc.layers.length - 1;\n const canMoveDown = stackIndex > 0;\n const isSelected = selectedLayerId === layer.id;\n\n return (\n <li\n key={layer.id}\n className={[\n 'squisq-image-editor-layer-item',\n isSelected ? 'is-selected' : '',\n visible ? '' : 'is-hidden',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <button\n type=\"button\"\n className=\"squisq-image-editor-layer-toggle\"\n onClick={() =>\n dispatch({\n type: 'update-layer',\n layerId: layer.id,\n patch: { visible: !visible },\n })\n }\n aria-label={visible ? 'Hide layer' : 'Show layer'}\n title={visible ? 'Hide layer' : 'Show layer'}\n >\n {visible ? <EyeIcon /> : <EyeOffIcon />}\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-editor-layer-toggle\"\n onClick={() =>\n dispatch({\n type: 'update-layer',\n layerId: layer.id,\n patch: { locked: !locked },\n })\n }\n aria-label={locked ? 'Unlock layer' : 'Lock layer'}\n title={locked ? 'Unlock layer' : 'Lock layer'}\n >\n {locked ? <LockIcon /> : <UnlockIcon />}\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-editor-layer-name\"\n onClick={() => dispatch({ type: 'select', layerId: layer.id })}\n >\n {layer.name ?? defaultLayerName(layer)}\n <span className=\"squisq-image-editor-layer-kind\">{layer.type}</span>\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-editor-layer-toggle\"\n disabled={!canMoveUp}\n onClick={() =>\n dispatch({ type: 'reorder-layer', layerId: layer.id, toIndex: stackIndex + 1 })\n }\n aria-label=\"Move layer up\"\n title=\"Move layer up\"\n >\n <ChevronUpIcon />\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-editor-layer-toggle\"\n disabled={!canMoveDown}\n onClick={() =>\n dispatch({ type: 'reorder-layer', layerId: layer.id, toIndex: stackIndex - 1 })\n }\n aria-label=\"Move layer down\"\n title=\"Move layer down\"\n >\n <ChevronDownIcon />\n </button>\n <button\n type=\"button\"\n className=\"squisq-image-editor-layer-toggle\"\n onClick={() => dispatch({ type: 'remove-layer', layerId: layer.id })}\n aria-label=\"Delete layer\"\n title=\"Delete layer\"\n >\n <CloseIcon />\n </button>\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n\nfunction defaultLayerName(layer: { type: string; content?: unknown }): string {\n if (layer.type === 'text') {\n const c = layer.content as { text?: string } | undefined;\n return c?.text?.split('\\n')[0]?.slice(0, 24) || 'Text';\n }\n if (layer.type === 'image') return 'Image';\n if (layer.type === 'shape') {\n const c = layer.content as { shape?: string } | undefined;\n return c?.shape ? c.shape[0]!.toUpperCase() + c.shape.slice(1) : 'Shape';\n }\n return layer.type;\n}\n","/**\n * PropertiesPanel — kind-aware editors for the canvas and the selected\n * layer. Plain controls only (no JsonEditor dependency) so the panel\n * stays focused on the image-editing vocabulary.\n */\n\nimport type { ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';\nimport type { ImageEditorAction } from './state.js';\nimport { NoneIcon } from './icons.js';\n\nexport interface PropertiesPanelProps {\n doc: ImageEditDoc;\n selectedLayerId: string | null;\n dispatch: (action: ImageEditorAction) => void;\n}\n\nexport function PropertiesPanel({ doc, selectedLayerId, dispatch }: PropertiesPanelProps) {\n const selected = selectedLayerId\n ? (doc.layers.find((l) => l.id === selectedLayerId) ?? null)\n : null;\n\n return (\n <div className=\"squisq-image-editor-properties\" data-testid=\"image-editor-properties\">\n <div className=\"squisq-image-editor-panel-header\">Properties</div>\n <CanvasSection doc={doc} dispatch={dispatch} />\n {selected ? (\n <LayerSection layer={selected} dispatch={dispatch} />\n ) : (\n <div className=\"squisq-image-editor-properties-empty\">No layer selected</div>\n )}\n </div>\n );\n}\n\n// ============================================\n// Canvas section\n// ============================================\n\nfunction CanvasSection({\n doc,\n dispatch,\n}: {\n doc: ImageEditDoc;\n dispatch: (a: ImageEditorAction) => void;\n}) {\n const setCanvas = (patch: Partial<ImageEditDoc['canvas']>) => {\n dispatch({ type: 'set-canvas', canvas: { ...doc.canvas, ...patch } });\n };\n return (\n <fieldset className=\"squisq-image-editor-fieldset\">\n <legend>Canvas</legend>\n <NumberField\n label=\"Width\"\n value={doc.canvas.width}\n min={1}\n onChange={(v) => setCanvas({ width: Math.round(v) })}\n />\n <NumberField\n label=\"Height\"\n value={doc.canvas.height}\n min={1}\n onChange={(v) => setCanvas({ height: Math.round(v) })}\n />\n <ColorField\n label=\"Background\"\n value={doc.canvas.background ?? 'transparent'}\n allowTransparent\n onChange={(v) => setCanvas({ background: v })}\n />\n </fieldset>\n );\n}\n\n// ============================================\n// Layer section\n// ============================================\n\nfunction LayerSection({\n layer,\n dispatch,\n}: {\n layer: ImageEditLayer;\n dispatch: (a: ImageEditorAction) => void;\n}) {\n const update = (patch: Partial<ImageEditLayer>) =>\n dispatch({ type: 'update-layer', layerId: layer.id, patch });\n\n return (\n <>\n <fieldset className=\"squisq-image-editor-fieldset\">\n <legend>Layer</legend>\n <TextField label=\"Name\" value={layer.name ?? ''} onChange={(name) => update({ name })} />\n <NumberField\n label=\"Opacity\"\n value={layer.opacity ?? 1}\n min={0}\n max={1}\n step={0.05}\n onChange={(opacity) => update({ opacity })}\n />\n </fieldset>\n\n <PositionFields layer={layer} update={update} />\n\n {layer.type === 'image' && <ImageFields layer={layer} update={update} />}\n {layer.type === 'text' && <TextFields layer={layer} update={update} />}\n {layer.type === 'shape' && <ShapeFields layer={layer} update={update} />}\n </>\n );\n}\n\nfunction PositionFields({\n layer,\n update,\n}: {\n layer: ImageEditLayer;\n update: (patch: Partial<ImageEditLayer>) => void;\n}) {\n const p = layer.position;\n const setPos = (patch: Partial<typeof p>) =>\n update({ position: { ...p, ...patch } } as Partial<ImageEditLayer>);\n return (\n <fieldset className=\"squisq-image-editor-fieldset\">\n <legend>Position</legend>\n <NumberField\n label=\"X\"\n value={typeof p.x === 'number' ? p.x : 0}\n onChange={(x) => setPos({ x: Math.round(x) })}\n />\n <NumberField\n label=\"Y\"\n value={typeof p.y === 'number' ? p.y : 0}\n onChange={(y) => setPos({ y: Math.round(y) })}\n />\n <NumberField\n label=\"Width\"\n value={typeof p.width === 'number' ? p.width : 0}\n onChange={(width) => setPos({ width: Math.round(width) })}\n />\n <NumberField\n label=\"Height\"\n value={typeof p.height === 'number' ? p.height : 0}\n onChange={(height) => setPos({ height: Math.round(height) })}\n />\n </fieldset>\n );\n}\n\nfunction ImageFields({\n layer,\n update,\n}: {\n layer: ImageEditLayer & { type: 'image' };\n update: (patch: Partial<ImageEditLayer>) => void;\n}) {\n const c = layer.content;\n const setContent = (patch: Partial<typeof c>) =>\n update({ content: { ...c, ...patch } } as Partial<ImageEditLayer>);\n return (\n <fieldset className=\"squisq-image-editor-fieldset\">\n <legend>Image</legend>\n <TextField label=\"Alt\" value={c.alt ?? ''} onChange={(alt) => setContent({ alt })} />\n <SelectField\n label=\"Fit\"\n value={c.fit ?? 'fill'}\n options={[\n ['fill', 'Fill'],\n ['contain', 'Contain'],\n ['cover', 'Cover'],\n ]}\n onChange={(fit) => setContent({ fit: fit as 'fill' | 'contain' | 'cover' })}\n />\n </fieldset>\n );\n}\n\nfunction TextFields({\n layer,\n update,\n}: {\n layer: ImageEditLayer & { type: 'text' };\n update: (patch: Partial<ImageEditLayer>) => void;\n}) {\n const c = layer.content;\n const setContent = (patch: Partial<typeof c>) =>\n update({ content: { ...c, ...patch } } as Partial<ImageEditLayer>);\n const setStyle = (patch: Partial<typeof c.style>) =>\n setContent({ style: { ...c.style, ...patch } });\n return (\n <fieldset className=\"squisq-image-editor-fieldset\">\n <legend>Text</legend>\n <TextAreaField label=\"Text\" value={c.text} onChange={(text) => setContent({ text })} />\n <NumberField\n label=\"Font size\"\n value={c.style.fontSize}\n min={1}\n onChange={(fontSize) => setStyle({ fontSize: Math.round(fontSize) })}\n />\n <ColorField label=\"Color\" value={c.style.color} onChange={(color) => setStyle({ color })} />\n <SelectField\n label=\"Weight\"\n value={c.style.fontWeight ?? 'normal'}\n options={[\n ['normal', 'Normal'],\n ['bold', 'Bold'],\n ]}\n onChange={(fontWeight) => setStyle({ fontWeight: fontWeight as 'normal' | 'bold' })}\n />\n <SelectField\n label=\"Align\"\n value={c.style.textAlign ?? 'left'}\n options={[\n ['left', 'Left'],\n ['center', 'Center'],\n ['right', 'Right'],\n ]}\n onChange={(textAlign) => setStyle({ textAlign: textAlign as 'left' | 'center' | 'right' })}\n />\n </fieldset>\n );\n}\n\nfunction ShapeFields({\n layer,\n update,\n}: {\n layer: ImageEditLayer & { type: 'shape' };\n update: (patch: Partial<ImageEditLayer>) => void;\n}) {\n const c = layer.content;\n const setContent = (patch: Partial<typeof c>) =>\n update({ content: { ...c, ...patch } } as Partial<ImageEditLayer>);\n return (\n <fieldset className=\"squisq-image-editor-fieldset\">\n <legend>Shape</legend>\n <SelectField\n label=\"Shape\"\n value={c.shape}\n options={[\n ['rect', 'Rectangle'],\n ['circle', 'Circle'],\n ['line', 'Line'],\n ]}\n onChange={(shape) => setContent({ shape: shape as 'rect' | 'circle' | 'line' })}\n />\n <ColorField\n label=\"Fill\"\n value={c.fill ?? '#000000'}\n allowTransparent\n onChange={(fill) => setContent({ fill })}\n />\n <ColorField\n label=\"Stroke\"\n value={c.stroke ?? '#000000'}\n allowTransparent\n onChange={(stroke) => setContent({ stroke })}\n />\n <NumberField\n label=\"Stroke width\"\n value={c.strokeWidth ?? 0}\n min={0}\n onChange={(strokeWidth) => setContent({ strokeWidth })}\n />\n {c.shape === 'rect' && (\n <NumberField\n label=\"Corner radius\"\n value={c.borderRadius ?? 0}\n min={0}\n onChange={(borderRadius) => setContent({ borderRadius: Math.round(borderRadius) })}\n />\n )}\n </fieldset>\n );\n}\n\n// ============================================\n// Field primitives\n// ============================================\n\nfunction NumberField({\n label,\n value,\n min,\n max,\n step,\n onChange,\n}: {\n label: string;\n value: number;\n min?: number;\n max?: number;\n step?: number;\n onChange: (v: number) => void;\n}) {\n return (\n <label className=\"squisq-image-editor-field\">\n <span>{label}</span>\n <input\n type=\"number\"\n value={Number.isFinite(value) ? value : 0}\n min={min}\n max={max}\n step={step ?? 1}\n onChange={(e) => {\n const n = Number(e.target.value);\n if (Number.isFinite(n)) onChange(n);\n }}\n />\n </label>\n );\n}\n\nfunction TextField({\n label,\n value,\n onChange,\n}: {\n label: string;\n value: string;\n onChange: (v: string) => void;\n}) {\n return (\n <label className=\"squisq-image-editor-field\">\n <span>{label}</span>\n <input type=\"text\" value={value} onChange={(e) => onChange(e.target.value)} />\n </label>\n );\n}\n\nfunction TextAreaField({\n label,\n value,\n onChange,\n}: {\n label: string;\n value: string;\n onChange: (v: string) => void;\n}) {\n return (\n <label className=\"squisq-image-editor-field squisq-image-editor-field--multiline\">\n <span>{label}</span>\n <textarea rows={3} value={value} onChange={(e) => onChange(e.target.value)} />\n </label>\n );\n}\n\nfunction SelectField({\n label,\n value,\n options,\n onChange,\n}: {\n label: string;\n value: string;\n options: Array<[string, string]>;\n onChange: (v: string) => void;\n}) {\n return (\n <label className=\"squisq-image-editor-field\">\n <span>{label}</span>\n <select value={value} onChange={(e) => onChange(e.target.value)}>\n {options.map(([v, l]) => (\n <option key={v} value={v}>\n {l}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction ColorField({\n label,\n value,\n allowTransparent,\n onChange,\n}: {\n label: string;\n value: string;\n allowTransparent?: boolean;\n onChange: (v: string) => void;\n}) {\n const isTransparent = value === 'transparent' || value === 'none';\n return (\n <label className=\"squisq-image-editor-field\">\n <span>{label}</span>\n <span className=\"squisq-image-editor-color-row\">\n <input\n type=\"color\"\n value={isTransparent ? '#000000' : normalizeColor(value)}\n onChange={(e) => onChange(e.target.value)}\n />\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n spellCheck={false}\n />\n {allowTransparent && (\n <button\n type=\"button\"\n onClick={() => onChange('transparent')}\n title=\"Set transparent\"\n aria-label=\"Set transparent\"\n className=\"squisq-image-editor-color-clear\"\n >\n <NoneIcon />\n </button>\n )}\n </span>\n </label>\n );\n}\n\nfunction normalizeColor(v: string): string {\n if (/^#[0-9a-f]{6}$/i.test(v)) return v;\n if (/^#[0-9a-f]{3}$/i.test(v)) {\n return (\n '#' +\n v\n .slice(1)\n .split('')\n .map((c) => c + c)\n .join('')\n );\n }\n return '#000000';\n}\n","/**\n * Toolbar — tool selector, layer-creation buttons, file-bin uploader,\n * and a Save/Export button. Versioning controls live in\n * `<ImageEditor>` so the toolbar stays purely about authoring tools.\n */\n\nimport { useRef, useState, useEffect } from 'react';\nimport type { ImageEditDoc } from '@bendyline/squisq/schemas';\nimport type { ImageEditorAction, ImageEditorTool } from './state.js';\nimport { CropIcon, CursorIcon, PlusIcon, ShapeIcon, TextIcon } from './icons.js';\n\nexport interface ToolbarProps {\n doc: ImageEditDoc;\n tool: ImageEditorTool;\n dispatch: (a: ImageEditorAction) => void;\n /** Upload an image asset and return its sidecar-relative path. */\n uploadAsset: (file: Blob, suggestedName?: string) => Promise<string>;\n /** Trigger an export (PNG/JPEG/WebP) of the flattened canvas. */\n onExport: (format: 'png' | 'jpeg' | 'webp') => void;\n /** Force-flush the state.json (host's \"save\" button). */\n onSave?: () => void;\n /** Override the Save button label. Default: \"Save\". */\n saveLabel?: string;\n /** Override the Save button tooltip. Default: \"Save state.json\". */\n saveTitle?: string;\n /**\n * Optional extra controls rendered just before the Save / Export\n * buttons in the right-aligned tool group. Used by `<ImageEditor>` to\n * mount the version-history dropdown when versioning is enabled.\n */\n extraTools?: React.ReactNode;\n}\n\nconst TOOLS: Array<{\n id: ImageEditorTool;\n icon: React.ReactNode;\n title: string;\n}> = [\n { id: 'select', icon: <CursorIcon />, title: 'Select / move (V)' },\n { id: 'text', icon: <TextIcon />, title: 'Add text (T)' },\n { id: 'shape', icon: <ShapeIcon />, title: 'Add shape (S)' },\n { id: 'crop', icon: <CropIcon />, title: 'Crop (C)' },\n];\n\nexport function Toolbar({\n doc,\n tool,\n dispatch,\n uploadAsset,\n onExport,\n onSave,\n saveLabel = 'Save',\n saveTitle = 'Save state.json',\n extraTools,\n}: ToolbarProps) {\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n\n const onFilePicked = async (file: File) => {\n try {\n const path = await uploadAsset(file, file.name);\n // Place the imported image centered at its native size up to canvas.\n const dims = await probeDims(file);\n const w = Math.min(dims.width, doc.canvas.width);\n const h = Math.min(dims.height, doc.canvas.height);\n dispatch({\n type: 'add-layer',\n layer: {\n type: 'image',\n name: file.name,\n position: {\n x: Math.round((doc.canvas.width - w) / 2),\n y: Math.round((doc.canvas.height - h) / 2),\n width: w,\n height: h,\n },\n content: { src: path, alt: file.name, fit: 'fill' },\n },\n });\n } catch (err: unknown) {\n console.warn(\n '[squisq-editor] image upload failed:',\n err instanceof Error ? err.message : err,\n );\n }\n };\n\n return (\n <div className=\"squisq-image-editor-toolbar\" data-testid=\"image-editor-toolbar\">\n <div className=\"squisq-image-editor-tool-group\" role=\"radiogroup\" aria-label=\"Tools\">\n {TOOLS.map((t) => (\n <button\n key={t.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={tool === t.id}\n className={['squisq-image-editor-tool-button', tool === t.id ? 'is-active' : '']\n .filter(Boolean)\n .join(' ')}\n onClick={() => dispatch({ type: 'set-tool', tool: t.id })}\n title={t.title}\n aria-label={t.title}\n >\n {t.icon}\n </button>\n ))}\n </div>\n\n <div className=\"squisq-image-editor-tool-group\">\n <button\n type=\"button\"\n className=\"squisq-image-editor-tool-button squisq-image-editor-tool-button--with-label\"\n onClick={() => fileInputRef.current?.click()}\n title=\"Import image as new layer\"\n aria-label=\"Import image as new layer\"\n >\n <PlusIcon />\n <span>Image</span>\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (file) void onFilePicked(file);\n e.target.value = '';\n }}\n />\n </div>\n\n <div className=\"squisq-image-editor-tool-group squisq-image-editor-tool-group--right\">\n {extraTools}\n {onSave && (\n <button\n type=\"button\"\n className=\"squisq-image-editor-tool-button\"\n onClick={onSave}\n title={saveTitle}\n >\n {saveLabel}\n </button>\n )}\n <ExportDropdown onExport={onExport} />\n </div>\n </div>\n );\n}\n\n/**\n * Single export dropdown listing all output formats. Replaces the\n * earlier split \"Export PNG / Other format…\" pair so the toolbar reads\n * as one Export control with a stable label and consistent sizing.\n */\nfunction ExportDropdown({ onExport }: { onExport: (f: 'png' | 'jpeg' | 'webp') => void }) {\n const [open, setOpen] = useState(false);\n const wrapRef = useRef<HTMLSpanElement | null>(null);\n const triggerRef = useRef<HTMLButtonElement | null>(null);\n\n useEffect(() => {\n if (!open) return;\n function onDocClick(e: MouseEvent) {\n const t = e.target as Node | null;\n if (!t) return;\n if (wrapRef.current?.contains(t)) return;\n setOpen(false);\n }\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') setOpen(false);\n }\n document.addEventListener('mousedown', onDocClick);\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('mousedown', onDocClick);\n document.removeEventListener('keydown', onKey);\n };\n }, [open]);\n\n const pick = (f: 'png' | 'jpeg' | 'webp') => {\n setOpen(false);\n onExport(f);\n };\n\n return (\n <span ref={wrapRef} className=\"squisq-image-editor-version-dropdown\">\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"squisq-image-editor-tool-button squisq-image-editor-tool-button--with-label\"\n onClick={() => setOpen((o) => !o)}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n title=\"Export image\"\n >\n <span>Export</span>\n <span aria-hidden=\"true\" style={{ fontSize: '0.8em' }}>\n ▾\n </span>\n </button>\n {open && (\n <div className=\"squisq-image-editor-version-popover\" role=\"menu\" style={{ minWidth: 160 }}>\n <ul className=\"squisq-image-editor-version-popover__list\" style={{ maxHeight: 'none' }}>\n {(\n [\n { f: 'png', label: 'PNG' },\n { f: 'jpeg', label: 'JPEG' },\n { f: 'webp', label: 'WebP' },\n ] as const\n ).map(({ f, label }) => (\n <li key={f} className=\"squisq-image-editor-version-popover__row\">\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"squisq-image-editor-tool-button squisq-image-editor-tool-button--menu\"\n onClick={() => pick(f)}\n >\n Export as {label}\n </button>\n </li>\n ))}\n </ul>\n </div>\n )}\n </span>\n );\n}\n\nfunction probeDims(file: Blob): Promise<{ width: number; height: number }> {\n return new Promise((resolve) => {\n const url = URL.createObjectURL(file);\n const img = new Image();\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve({ width: img.naturalWidth, height: img.naturalHeight });\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n resolve({ width: 200, height: 200 });\n };\n img.src = url;\n });\n}\n","/**\n * React hook that bundles the image-editor reducer with sidecar\n * persistence, versioning, and an object-URL cache for asset bytes.\n *\n * Hosts pass an already-scoped {@link ContentContainer} (typically built\n * with `scopeContainer(parent, basename + '_files')`); the hook never\n * looks above that root.\n */\n\nimport { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport type { ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';\nimport {\n IMAGE_EDIT_ASSETS_PREFIX,\n IMAGE_EDIT_STATE_FILENAME,\n ImageEditVersionManager,\n createEmptyImageEditDoc,\n readImageEditDoc,\n writeImageEditDoc,\n} from '@bendyline/squisq/imageEdit';\nimport {\n imageEditorReducer,\n initialImageEditorState,\n type ImageEditorAction,\n type ImageEditorState,\n} from './state.js';\n\nexport interface UseImageEditorOptions {\n /** Sidecar container for the image being edited. */\n container: ContentContainer;\n /**\n * Initial source image URL — used to seed layer 0 when the sidecar has\n * no `state.json` yet. Bytes are fetched and copied into\n * `assets/source.<ext>` so the doc is portable.\n */\n initialSrc?: string;\n /** Override the state filename. Defaults to `state.json`. */\n stateFilename?: string;\n /** Enable version history. Default: `false`. */\n allowVersioning?: boolean;\n /** Auto-save idle delay (ms). `0` disables. Default: `5000`. */\n versioningAutoSaveIdleMs?: number;\n /** Debounced write delay for state.json (ms). Default: `500`. */\n persistDebounceMs?: number;\n}\n\nexport interface UseImageEditorReturn {\n /** Current reducer state (or `null` while still loading the initial doc). */\n state: ImageEditorState | null;\n /** Dispatch a reducer action. No-op while loading. */\n dispatch: (action: ImageEditorAction) => void;\n /** Manually trigger a synchronous write of `state.json`. */\n flush: () => Promise<void>;\n /** Resolve an asset path inside the sidecar to a blob URL (cached). */\n resolveAssetUrl: (path: string) => Promise<string>;\n /**\n * Write a new asset (raster image) into `assets/` and return the\n * sidecar-relative path. The caller is then expected to push a layer\n * referencing that path.\n */\n uploadAsset: (file: Blob, suggestedName?: string) => Promise<string>;\n /** Versioning handle. `null` when `allowVersioning` is false or no container. */\n versioning: ImageEditVersionManager | null;\n /** True after the initial load completes (either an existing doc or seeded). */\n ready: boolean;\n /** Last load / persistence error, if any. */\n error: Error | null;\n}\n\nexport function useImageEditor(options: UseImageEditorOptions): UseImageEditorReturn {\n const {\n container,\n initialSrc,\n stateFilename = IMAGE_EDIT_STATE_FILENAME,\n allowVersioning = false,\n versioningAutoSaveIdleMs = 5000,\n persistDebounceMs = 500,\n } = options;\n\n const [state, dispatch] = useReducer(\n (s: ImageEditorState | null, a: ImageEditorAction): ImageEditorState | null => {\n if (s === null) return a.type === 'load' ? initialImageEditorState(a.doc) : null;\n return imageEditorReducer(s, a);\n },\n null,\n );\n const [ready, setReady] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n // Set to true inside the initial-load effect when we just seeded the\n // sidecar (no prior `state.json`). The versioning effect below reads\n // this flag to write an \"original\" snapshot once the manager exists.\n const seededOnLoadRef = useRef(false);\n\n // ── Initial load (or seed from initialSrc) ────────────────────────────\n useEffect(() => {\n let cancelled = false;\n setReady(false);\n setError(null);\n\n (async () => {\n try {\n const existing = await readImageEditDoc(container, stateFilename);\n if (cancelled) return;\n if (existing) {\n dispatch({ type: 'load', doc: existing });\n setReady(true);\n return;\n }\n // No existing state — seed.\n const seeded = await seedFromSource(container, initialSrc);\n if (cancelled) return;\n await writeImageEditDoc(container, seeded, stateFilename);\n dispatch({ type: 'load', doc: seeded });\n setReady(true);\n // Capture an initial snapshot of the freshly-seeded state so the\n // version history always has an \"original\" entry the user can\n // revert to after their first edit.\n seededOnLoadRef.current = true;\n } catch (err: unknown) {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setReady(true);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [container, stateFilename, initialSrc]);\n\n // ── Debounced persistence of state.json ────────────────────────────────\n const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const docRef = useRef<ImageEditDoc | null>(null);\n docRef.current = state?.doc ?? null;\n\n useEffect(() => {\n if (!state?.dirty) return;\n if (persistTimerRef.current) clearTimeout(persistTimerRef.current);\n persistTimerRef.current = setTimeout(() => {\n const doc = docRef.current;\n if (!doc) return;\n writeImageEditDoc(container, doc, stateFilename)\n .then(() => dispatch({ type: 'mark-clean' }))\n .catch((err: unknown) => {\n console.warn(\n '[squisq-editor] image-edit state persist failed:',\n err instanceof Error ? err.message : err,\n );\n });\n }, persistDebounceMs);\n return () => {\n if (persistTimerRef.current) clearTimeout(persistTimerRef.current);\n };\n }, [state?.dirty, state?.doc, container, stateFilename, persistDebounceMs]);\n\n const flush = useCallback(async () => {\n const doc = docRef.current;\n if (!doc) return;\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n }\n await writeImageEditDoc(container, doc, stateFilename);\n dispatch({ type: 'mark-clean' });\n }, [container, stateFilename]);\n\n // ── Versioning ─────────────────────────────────────────────────────────\n const versioning = useMemo(\n () => (allowVersioning ? new ImageEditVersionManager(container, { stateFilename }) : null),\n [allowVersioning, container, stateFilename],\n );\n\n // Drop the \"original\" snapshot once versioning is wired and we just\n // seeded a fresh sidecar. Guarded by `seededOnLoadRef` so we never\n // duplicate-snapshot on subsequent renders. Uses `force: true` so the\n // initial entry always lands even though no diff has occurred yet.\n useEffect(() => {\n if (!versioning) return;\n if (!ready) return;\n if (!seededOnLoadRef.current) return;\n seededOnLoadRef.current = false;\n versioning.saveVersion({ force: true }).catch((err: unknown) => {\n console.warn(\n '[squisq-editor] image-edit initial snapshot failed:',\n err instanceof Error ? err.message : err,\n );\n });\n }, [versioning, ready]);\n\n useEffect(() => {\n if (!versioning) return;\n if (versioningAutoSaveIdleMs <= 0) return;\n if (!state?.doc) return;\n const timer = setTimeout(() => {\n versioning.saveVersion({ doc: docRef.current ?? undefined }).catch((err: unknown) => {\n console.warn(\n '[squisq-editor] image-edit auto-save version failed:',\n err instanceof Error ? err.message : err,\n );\n });\n }, versioningAutoSaveIdleMs);\n return () => clearTimeout(timer);\n }, [versioning, versioningAutoSaveIdleMs, state?.doc]);\n\n // ── Asset URL cache ────────────────────────────────────────────────────\n const urlCacheRef = useRef<Map<string, string>>(new Map());\n\n const resolveAssetUrl = useCallback(\n async (path: string): Promise<string> => {\n const cache = urlCacheRef.current;\n const cached = cache.get(path);\n if (cached) return cached;\n const data = await container.readFile(path);\n if (!data) throw new Error(`useImageEditor: missing asset \"${path}\"`);\n const list = await container.listFiles(path);\n const mime = list.find((e) => e.path === path)?.mimeType ?? 'application/octet-stream';\n const url = URL.createObjectURL(new Blob([data], { type: mime }));\n cache.set(path, url);\n return url;\n },\n [container],\n );\n\n // Revoke all cached object URLs on unmount / container swap\n useEffect(() => {\n const cache = urlCacheRef.current;\n return () => {\n for (const url of cache.values()) URL.revokeObjectURL(url);\n cache.clear();\n };\n }, [container]);\n\n const uploadAsset = useCallback(\n async (file: Blob, suggestedName?: string): Promise<string> => {\n const ext = guessExtensionFromMime(file.type) ?? extensionFromName(suggestedName) ?? 'bin';\n const id = randomId();\n const path = `${IMAGE_EDIT_ASSETS_PREFIX}${id}.${ext}`;\n const buf = await file.arrayBuffer();\n await container.writeFile(path, buf, file.type || undefined);\n return path;\n },\n [container],\n );\n\n return {\n state,\n dispatch,\n flush,\n resolveAssetUrl,\n uploadAsset,\n versioning,\n ready,\n error,\n };\n}\n\n// ============================================\n// Helpers\n// ============================================\n\nasync function seedFromSource(\n container: ContentContainer,\n initialSrc: string | undefined,\n): Promise<ImageEditDoc> {\n if (!initialSrc) {\n return createEmptyImageEditDoc(800, 600);\n }\n // Fetch the source bytes (works for blob:, data:, http(s):, and same-origin\n // relative URLs).\n const resp = await fetch(initialSrc);\n if (!resp.ok) throw new Error(`useImageEditor: failed to fetch initialSrc (${resp.status})`);\n const blob = await resp.blob();\n const ext = guessExtensionFromMime(blob.type) ?? 'png';\n const assetPath = `${IMAGE_EDIT_ASSETS_PREFIX}source.${ext}`;\n await container.writeFile(assetPath, await blob.arrayBuffer(), blob.type || undefined);\n\n // Probe natural dimensions by loading into an Image.\n const dims = await probeImageDimensions(initialSrc);\n const w = dims?.width ?? 800;\n const h = dims?.height ?? 600;\n\n const layer: ImageEditLayer = {\n id: 'base',\n type: 'image',\n name: 'Background',\n position: { x: 0, y: 0, width: w, height: h },\n content: { src: assetPath, alt: '', fit: 'fill' },\n };\n return {\n version: 1,\n canvas: { width: w, height: h, background: 'transparent' },\n layers: [layer],\n meta: {\n sourcePath: assetPath,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n },\n };\n}\n\nfunction probeImageDimensions(src: string): Promise<{ width: number; height: number } | null> {\n return new Promise((resolve) => {\n const img = new Image();\n img.onload = () => resolve({ width: img.naturalWidth, height: img.naturalHeight });\n img.onerror = () => resolve(null);\n img.src = src;\n });\n}\n\nfunction guessExtensionFromMime(mime: string | undefined): string | null {\n if (!mime) return null;\n if (mime.includes('png')) return 'png';\n if (mime.includes('jpeg') || mime.includes('jpg')) return 'jpg';\n if (mime.includes('webp')) return 'webp';\n if (mime.includes('gif')) return 'gif';\n if (mime.includes('svg')) return 'svg';\n return null;\n}\n\nfunction extensionFromName(name: string | undefined): string | null {\n if (!name) return null;\n const dot = name.lastIndexOf('.');\n return dot >= 0 ? name.slice(dot + 1).toLowerCase() : null;\n}\n\nfunction randomId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n","/**\n * Pure state + reducer for the `<ImageEditor>` component.\n *\n * Kept React-free so it's easy to unit-test in isolation. The actual\n * React hook that wires this to a {@link ContentContainer} (and the\n * version manager) lives in `useImageEditor.ts`.\n */\n\nimport type { ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';\nimport {\n addLayer,\n removeLayer,\n reorderLayer,\n setCanvas,\n updateLayer,\n touch,\n} from '@bendyline/squisq/imageEdit';\n\n/**\n * Layer payload accepted by the `add-layer` action — the `id` field is\n * optional and will be assigned by the underlying `addLayer` helper if\n * the caller doesn't supply one.\n */\nexport type ImageEditLayerInput = ImageEditLayer | (Omit<ImageEditLayer, 'id'> & { id?: string });\n\n/** The currently active interaction tool. */\nexport type ImageEditorTool = 'select' | 'text' | 'shape' | 'image' | 'crop';\n\n/** A pixel-space rectangle in canvas coordinates. */\nexport interface CanvasRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ImageEditorState {\n /** The persisted document. */\n doc: ImageEditDoc;\n /** Selected layer id, or `null` when nothing is selected. */\n selectedLayerId: string | null;\n /** Active tool. */\n tool: ImageEditorTool;\n /**\n * Dirty flag — true when the in-memory doc has unsaved changes\n * relative to the last `markClean()` call. The hook uses this to\n * debounce writes back to `state.json`.\n */\n dirty: boolean;\n}\n\nexport type ImageEditorAction =\n | { type: 'load'; doc: ImageEditDoc }\n | { type: 'mark-clean' }\n | { type: 'set-tool'; tool: ImageEditorTool }\n | { type: 'select'; layerId: string | null }\n | { type: 'set-canvas'; canvas: ImageEditDoc['canvas'] }\n | { type: 'add-layer'; layer: ImageEditLayerInput; select?: boolean }\n | { type: 'remove-layer'; layerId: string }\n | { type: 'update-layer'; layerId: string; patch: Partial<ImageEditLayer> }\n | { type: 'reorder-layer'; layerId: string; toIndex: number }\n | { type: 'crop'; rect: CanvasRect };\n\n/** Build the initial state from a freshly-loaded doc. */\nexport function initialImageEditorState(doc: ImageEditDoc): ImageEditorState {\n return {\n doc,\n selectedLayerId: null,\n tool: 'select',\n dirty: false,\n };\n}\n\nexport function imageEditorReducer(\n state: ImageEditorState,\n action: ImageEditorAction,\n): ImageEditorState {\n switch (action.type) {\n case 'load':\n return { doc: action.doc, selectedLayerId: null, tool: 'select', dirty: false };\n\n case 'mark-clean':\n return state.dirty ? { ...state, dirty: false } : state;\n\n case 'set-tool':\n return state.tool === action.tool ? state : { ...state, tool: action.tool };\n\n case 'select':\n return state.selectedLayerId === action.layerId\n ? state\n : { ...state, selectedLayerId: action.layerId };\n\n case 'set-canvas': {\n const next = setCanvas(state.doc, action.canvas);\n return next === state.doc ? state : { ...state, doc: next, dirty: true };\n }\n\n case 'add-layer': {\n // `addLayer` from core assigns an id when missing; cast through\n // `ImageEditLayer` for the existing helper signature.\n const next = addLayer(state.doc, action.layer as ImageEditLayer);\n // Pick up the assigned id (last layer)\n const newId = next.layers[next.layers.length - 1]!.id;\n return {\n ...state,\n doc: next,\n dirty: true,\n selectedLayerId: action.select === false ? state.selectedLayerId : newId,\n };\n }\n\n case 'remove-layer': {\n const next = removeLayer(state.doc, action.layerId);\n if (next === state.doc) return state;\n return {\n ...state,\n doc: next,\n dirty: true,\n selectedLayerId: state.selectedLayerId === action.layerId ? null : state.selectedLayerId,\n };\n }\n\n case 'update-layer': {\n const next = updateLayer(state.doc, action.layerId, action.patch);\n return next === state.doc ? state : { ...state, doc: next, dirty: true };\n }\n\n case 'reorder-layer': {\n const next = reorderLayer(state.doc, action.layerId, action.toIndex);\n return next === state.doc ? state : { ...state, doc: next, dirty: true };\n }\n\n case 'crop': {\n const { rect } = action;\n const newCanvas = {\n ...state.doc.canvas,\n width: Math.max(1, Math.round(rect.width)),\n height: Math.max(1, Math.round(rect.height)),\n };\n // Translate every layer by (-rect.x, -rect.y). Only handles numeric\n // positions; percentage strings are left alone (rare for image-edit\n // layers, which the editor produces with numeric coords).\n const translated: ImageEditLayer[] = state.doc.layers.map((layer) => {\n const { position } = layer;\n const x = typeof position.x === 'number' ? position.x - rect.x : position.x;\n const y = typeof position.y === 'number' ? position.y - rect.y : position.y;\n return { ...layer, position: { ...position, x, y } } as ImageEditLayer;\n });\n const next = touch({ ...state.doc, canvas: newCanvas, layers: translated });\n return { ...state, doc: next, dirty: true };\n }\n }\n}\n","/**\n * Derive `--squisq-image-editor-*` CSS custom properties from a Theme +\n * SurfaceScheme, mirroring `useJsonViewTokens` in squisq-react. Lets the\n * ImageEditor re-theme consistently with the rest of Squisq (light/dark\n * surface, theme palette, font family overrides).\n */\n\nimport { useMemo, type CSSProperties } from 'react';\nimport {\n applySurface,\n resolveFontFamily,\n type SurfaceScheme,\n type Theme,\n} from '@bendyline/squisq/schemas';\nimport { DEFAULT_THEME } from '@bendyline/squisq/doc';\nimport { useAutoSurface } from '@bendyline/squisq-react';\n\nexport interface ImageEditorTokens {\n /** Inline style object to spread onto the root `.squisq-image-editor`. */\n style: CSSProperties;\n /** The effective theme (after surface application). */\n theme: Theme;\n}\n\nexport function useImageEditorTokens(\n theme: Theme | undefined,\n surface: SurfaceScheme | 'auto' | undefined,\n): ImageEditorTokens {\n const auto = useAutoSurface(surface === 'auto');\n const effectiveSurface = surface === 'auto' ? auto : (surface ?? undefined);\n\n return useMemo(() => {\n const baseTheme = theme ?? DEFAULT_THEME;\n const finalTheme = effectiveSurface ? applySurface(baseTheme, effectiveSurface) : baseTheme;\n\n const bg = finalTheme.colors.background;\n const text = finalTheme.colors.text;\n const muted = finalTheme.colors.textMuted;\n const accent = finalTheme.colors.primary;\n\n // Panel / control surfaces are derived by mixing toward the opposite\n // pole (text color), so the same recipe works for both light and dark\n // surfaces without conditional branches.\n const panelBg = `color-mix(in srgb, ${bg} 92%, ${text} 8%)`;\n const panelBorder = `color-mix(in srgb, ${bg} 80%, ${text} 20%)`;\n const controlBg = `color-mix(in srgb, ${bg} 86%, ${text} 14%)`;\n const controlBorder = `color-mix(in srgb, ${bg} 72%, ${text} 28%)`;\n const workspaceBg = `color-mix(in srgb, ${bg} 95%, ${text} 5%)`;\n\n const bodyFont = resolveFontFamily(\n finalTheme.typography.bodyFont,\n 'system-ui, -apple-system, sans-serif',\n );\n\n const style: CSSProperties = {\n ['--squisq-image-editor-bg' as string]: bg,\n ['--squisq-image-editor-panel-bg' as string]: panelBg,\n ['--squisq-image-editor-panel-border' as string]: panelBorder,\n ['--squisq-image-editor-text' as string]: text,\n ['--squisq-image-editor-text-muted' as string]: muted,\n ['--squisq-image-editor-accent' as string]: accent,\n ['--squisq-image-editor-control-bg' as string]: controlBg,\n ['--squisq-image-editor-control-border' as string]: controlBorder,\n ['--squisq-image-editor-workspace-bg' as string]: workspaceBg,\n ['--squisq-image-editor-body-font' as string]: bodyFont,\n };\n\n return { style, theme: finalTheme };\n }, [theme, effectiveSurface]);\n}\n","/**\n * MediaBin\n *\n * Toggleable side panel that displays files associated with the current\n * content. Shows image thumbnails, icons for other types, file sizes,\n * and provides an upload button to add new media.\n */\n\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport type { MediaProvider, MediaEntry } from '@bendyline/squisq/schemas';\nimport { SQUISQ_MEDIA_MIME } from './mediaDragMime';\n\n// ============================================\n// Types\n// ============================================\n\nexport interface MediaBinProps {\n /** The active MediaProvider (null when no media context is available) */\n mediaProvider: MediaProvider | null;\n /** Whether the editor is in dark mode */\n isDark: boolean;\n /** Incremented externally to signal a re-scan of the media list */\n refreshKey?: number;\n /**\n * Fired after a successful upload via the MediaBin's own \"+ Upload\"\n * button. `relativePath` is what the provider returned (the same\n * value embedded in markdown refs, e.g. `attachments/xyz.png`);\n * `name` is the uploader-chosen filename before storage renamed\n * it. Consumers typically use this to insert a markdown image ref\n * at the editor's cursor so the file actually participates in the\n * outgoing message — previously files went to the bin and nowhere\n * else, leaving the message body empty when the user hit Send.\n */\n onMediaUploaded?: (relativePath: string, name: string, mimeType: string) => void | Promise<void>;\n}\n\n// ============================================\n// Helpers\n// ============================================\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction iconForMime(mimeType: string): string {\n if (mimeType.startsWith('image/')) return '\\u{1F5BC}';\n if (mimeType.startsWith('audio/')) return '\\u{1F50A}';\n if (mimeType.startsWith('video/')) return '\\u{1F3AC}';\n if (mimeType.includes('json')) return '{ }';\n if (mimeType.includes('xml') || mimeType.includes('ssml')) return '\\u{2329}/\\u{232A}';\n return '\\u{1F4C4}';\n}\n\nfunction isImageMime(mimeType: string): boolean {\n return mimeType.startsWith('image/');\n}\n\n// ============================================\n// Component\n// ============================================\n\nexport function MediaBin({ mediaProvider, isDark, refreshKey, onMediaUploaded }: MediaBinProps) {\n const [entries, setEntries] = useState<MediaEntry[]>([]);\n const [thumbUrls, setThumbUrls] = useState<Record<string, string>>({});\n const [loading, setLoading] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Scan media entries whenever the provider changes or refreshKey bumps\n useEffect(() => {\n if (!mediaProvider) {\n setEntries([]);\n setThumbUrls({});\n return;\n }\n\n let cancelled = false;\n\n async function scan() {\n setLoading(true);\n try {\n const list = await mediaProvider!.listMedia();\n if (cancelled) return;\n\n list.sort((a, b) => {\n const aImg = isImageMime(a.mimeType) ? 0 : 1;\n const bImg = isImageMime(b.mimeType) ? 0 : 1;\n if (aImg !== bImg) return aImg - bImg;\n return a.name.localeCompare(b.name);\n });\n setEntries(list);\n\n const urls: Record<string, string> = {};\n for (const entry of list) {\n if (isImageMime(entry.mimeType)) {\n try {\n urls[entry.name] = await mediaProvider!.resolveUrl(entry.name);\n } catch {\n // skip failed resolve\n }\n }\n }\n if (!cancelled) setThumbUrls(urls);\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n\n scan();\n return () => {\n cancelled = true;\n };\n }, [mediaProvider, refreshKey]);\n\n // ---- Upload ----\n\n const handleUploadClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n const handleFileChange = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n if (!files || !mediaProvider) return;\n\n setLoading(true);\n try {\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n if (!file) continue;\n const buffer = await file.arrayBuffer();\n const mimeType = file.type || 'application/octet-stream';\n const relativePath = await mediaProvider.addMedia(file.name, buffer, mimeType);\n if (onMediaUploaded) {\n try {\n await onMediaUploaded(relativePath, file.name, mimeType);\n } catch {\n /* callback is a nice-to-have; don't abort the upload batch */\n }\n }\n }\n // Re-scan\n const list = await mediaProvider.listMedia();\n list.sort((a, b) => {\n const aImg = isImageMime(a.mimeType) ? 0 : 1;\n const bImg = isImageMime(b.mimeType) ? 0 : 1;\n if (aImg !== bImg) return aImg - bImg;\n return a.name.localeCompare(b.name);\n });\n setEntries(list);\n\n const urls: Record<string, string> = {};\n for (const entry of list) {\n if (isImageMime(entry.mimeType)) {\n try {\n urls[entry.name] = await mediaProvider.resolveUrl(entry.name);\n } catch {\n // skip\n }\n }\n }\n setThumbUrls(urls);\n } finally {\n setLoading(false);\n if (fileInputRef.current) fileInputRef.current.value = '';\n }\n },\n [mediaProvider, onMediaUploaded],\n );\n\n return (\n <div className={`squisq-media-bin${isDark ? ' squisq-media-bin--dark' : ''}`}>\n {/* Header */}\n <div className=\"squisq-media-bin-header\">\n <span className=\"squisq-media-bin-title\">\n Files {entries.length > 0 && `(${entries.length})`}\n </span>\n\n <button\n className=\"squisq-media-bin-upload\"\n onClick={handleUploadClick}\n disabled={!mediaProvider || loading}\n title={\n mediaProvider ? 'Upload files' : 'Load a content zip or select a storage slot first'\n }\n >\n + Upload\n </button>\n </div>\n\n {/* File list */}\n <div className=\"squisq-media-bin-list\">\n {!mediaProvider && (\n <div className=\"squisq-media-bin-empty\">\n No media context.\n <br />\n Load a content zip or select a storage slot.\n </div>\n )}\n\n {mediaProvider && entries.length === 0 && !loading && (\n <div className=\"squisq-media-bin-empty\">No files yet.</div>\n )}\n\n {entries.map((entry) => {\n const thumb = thumbUrls[entry.name];\n const basename = entry.name.includes('/') ? entry.name.split('/').pop()! : entry.name;\n const isImage = isImageMime(entry.mimeType);\n const altText = basename.replace(/\\.[^.]+$/, '').replace(/[-_]/g, ' ');\n\n const handleDragStart = (e: React.DragEvent<HTMLDivElement>) => {\n if (!isImage) return;\n const payload = JSON.stringify({\n name: entry.name,\n mimeType: entry.mimeType,\n alt: altText,\n });\n e.dataTransfer.setData(SQUISQ_MEDIA_MIME, payload);\n e.dataTransfer.setData('text/plain', `![${altText}](${entry.name})`);\n e.dataTransfer.effectAllowed = 'copy';\n };\n\n return (\n <div\n key={entry.name}\n className=\"squisq-media-bin-item\"\n title={`${entry.name}\\n${entry.mimeType}\\n${formatSize(entry.size)}`}\n draggable={isImage}\n onDragStart={handleDragStart}\n >\n {/* Thumbnail or icon */}\n {thumb ? (\n <img\n src={thumb}\n alt={basename}\n className=\"squisq-media-bin-thumb\"\n draggable={false}\n />\n ) : (\n <span className=\"squisq-media-bin-icon\">{iconForMime(entry.mimeType)}</span>\n )}\n\n {/* Name + size */}\n <div className=\"squisq-media-bin-meta\">\n <div className=\"squisq-media-bin-name\">{basename}</div>\n <div className=\"squisq-media-bin-size\">{formatSize(entry.size)}</div>\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n </div>\n );\n}\n","/**\n * DropZoneOverlay\n *\n * Full-editor overlay that appears when files are dragged over the editor.\n * Shows contextual drop zones depending on the type of files being dragged:\n * - Media files → single \"Media\" drop zone\n * - Text files → two zones: \"Insert\" (at cursor) and \"Replace\" (all content)\n * - Mixed files → all three zones\n */\n\nimport { useState } from 'react';\nimport type { DragContentType, DropTarget, UseFileDropResult } from './hooks/useFileDrop';\n\nexport interface DropZoneOverlayProps {\n /** What kind of content is being dragged */\n dragContentType: DragContentType;\n /** Factory that creates event props for a specific drop target */\n zoneProps: UseFileDropResult['zoneProps'];\n /** Whether a MediaProvider is available (disables media zone when false) */\n hasMediaProvider: boolean;\n}\n\n/**\n * Full-size overlay with contextual drop targets for file uploads.\n * Rendered conditionally by EditorShell when files are dragged over the editor.\n */\nexport function DropZoneOverlay({\n dragContentType,\n zoneProps,\n hasMediaProvider,\n}: DropZoneOverlayProps) {\n const showMedia = dragContentType === 'media' || dragContentType === 'mixed';\n const showText = dragContentType === 'text' || dragContentType === 'mixed';\n\n return (\n <div className=\"squisq-drop-overlay\">\n <div className=\"squisq-drop-overlay-inner\">\n {showMedia && (\n <DropZone\n target=\"media\"\n zoneProps={zoneProps}\n icon=\"📷\"\n label=\"Media\"\n description={hasMediaProvider ? 'Add to file bin' : 'No file storage configured'}\n disabled={!hasMediaProvider}\n variant=\"media\"\n />\n )}\n {showText && (\n <>\n <DropZone\n target=\"insert\"\n zoneProps={zoneProps}\n icon=\"📋\"\n label=\"Insert\"\n description=\"Insert content at cursor\"\n variant=\"insert\"\n />\n <DropZone\n target=\"replace\"\n zoneProps={zoneProps}\n icon=\"🔄\"\n label=\"Replace\"\n description=\"Replace all editor content\"\n variant=\"replace\"\n />\n </>\n )}\n </div>\n </div>\n );\n}\n\n// ─── Individual drop zone ────────────────────────────────\n\ninterface DropZoneProps {\n target: DropTarget;\n zoneProps: UseFileDropResult['zoneProps'];\n icon: string;\n label: string;\n description: string;\n disabled?: boolean;\n variant: 'media' | 'insert' | 'replace';\n}\n\nfunction DropZone({\n target,\n zoneProps,\n icon,\n label,\n description,\n disabled,\n variant,\n}: DropZoneProps) {\n const [isHovering, setIsHovering] = useState(false);\n const props = zoneProps(target);\n\n return (\n <div\n className={[\n 'squisq-drop-zone',\n `squisq-drop-zone--${variant}`,\n isHovering && !disabled ? 'squisq-drop-zone--active' : '',\n disabled ? 'squisq-drop-zone--disabled' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n onDragOver={(e) => {\n if (disabled) {\n e.preventDefault();\n return;\n }\n props.onDragOver(e);\n }}\n onDragEnter={(e) => {\n e.preventDefault();\n if (!disabled) setIsHovering(true);\n }}\n onDragLeave={(e) => {\n e.preventDefault();\n setIsHovering(false);\n }}\n onDrop={(e) => {\n setIsHovering(false);\n if (disabled) {\n e.preventDefault();\n return;\n }\n props.onDrop(e);\n }}\n >\n <span className=\"squisq-drop-zone-icon\">{icon}</span>\n <span className=\"squisq-drop-zone-label\">{label}</span>\n <span className=\"squisq-drop-zone-desc\">{description}</span>\n </div>\n );\n}\n","/**\n * TooltipLayer\n *\n * A single portal-mounted tooltip that activates on hover over any element\n * with a `data-tooltip` attribute. Shorter delay than native browser\n * tooltips and fires regardless of window focus, making toolbar hints feel\n * immediate. Mount once near the root of the editor shell.\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nconst SHOW_DELAY_MS = 180;\n\ninterface TooltipState {\n label: string;\n top: number;\n left: number;\n}\n\nexport function TooltipLayer() {\n const [state, setState] = useState<TooltipState | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const currentTargetRef = useRef<HTMLElement | null>(null);\n // Visibility tracked in a ref so `handleOver` can decide whether to swap\n // the label immediately vs. re-delay — reading it from state would force\n // the effect to re-run (and re-register all listeners) on every change.\n const visibleRef = useRef(false);\n\n useEffect(() => {\n const clearTimer = () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const hide = () => {\n clearTimer();\n currentTargetRef.current = null;\n visibleRef.current = false;\n setState(null);\n };\n\n const show = (el: HTMLElement, label: string) => {\n const rect = el.getBoundingClientRect();\n visibleRef.current = true;\n setState({\n label,\n top: rect.bottom + 6,\n left: rect.left + rect.width / 2,\n });\n };\n\n const handleOver = (e: MouseEvent) => {\n const el = (e.target as Element | null)?.closest?.<HTMLElement>('[data-tooltip]');\n if (!el) return;\n if (el === currentTargetRef.current) return;\n const label = el.getAttribute('data-tooltip');\n if (!label) return;\n\n // Switching from one tooltip target to another: if a tooltip is\n // already visible, swap the label immediately (no re-delay).\n const wasVisible = visibleRef.current;\n currentTargetRef.current = el;\n clearTimer();\n\n if (wasVisible) {\n show(el, label);\n } else {\n timerRef.current = setTimeout(() => {\n if (currentTargetRef.current === el && document.body.contains(el)) {\n show(el, label);\n }\n }, SHOW_DELAY_MS);\n }\n };\n\n const handleOut = (e: MouseEvent) => {\n const target = currentTargetRef.current;\n if (!target) return;\n const related = e.relatedTarget as Node | null;\n // Still hovering inside the same target (e.g. moved over a child)\n if (related && target.contains(related)) return;\n // Moving to another element with a tooltip — handleOver will swap in.\n const relatedTooltip = (related as Element | null)?.closest?.('[data-tooltip]');\n if (relatedTooltip) return;\n hide();\n };\n\n const handleScroll = () => hide();\n const handleBlur = () => hide();\n\n document.addEventListener('mouseover', handleOver);\n document.addEventListener('mouseout', handleOut);\n document.addEventListener('scroll', handleScroll, true);\n window.addEventListener('blur', handleBlur);\n\n return () => {\n clearTimer();\n document.removeEventListener('mouseover', handleOver);\n document.removeEventListener('mouseout', handleOut);\n document.removeEventListener('scroll', handleScroll, true);\n window.removeEventListener('blur', handleBlur);\n };\n }, []);\n\n if (!state) return null;\n\n return createPortal(\n <div\n role=\"tooltip\"\n className=\"squisq-tooltip\"\n style={{\n position: 'fixed',\n top: state.top,\n left: state.left,\n }}\n >\n {state.label}\n </div>,\n document.body,\n );\n}\n","/**\n * useFileDrop\n *\n * React hook that manages HTML5 drag-and-drop state for file uploads.\n * Tracks whether files are being dragged over the target element,\n * classifies dragged file types (media vs text), and dispatches\n * drop events to callers.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\n// ─── File classification ────────────────────────────────\n\nconst MEDIA_EXTENSIONS = new Set([\n 'png',\n 'jpg',\n 'jpeg',\n 'gif',\n 'webp',\n 'svg',\n 'avif',\n 'ico',\n 'mp4',\n 'webm',\n 'mov',\n 'avi',\n 'mp3',\n 'wav',\n 'ogg',\n 'aac',\n 'm4a',\n 'flac',\n]);\n\nconst TEXT_EXTENSIONS = new Set(['md', 'txt', 'docx']);\n\nexport type FileCategory = 'media' | 'text' | 'unknown';\nexport type DragContentType = 'media' | 'text' | 'mixed' | null;\nexport type DropTarget = 'media' | 'insert' | 'replace';\n\nfunction extensionOf(name: string): string {\n const dot = name.lastIndexOf('.');\n return dot >= 0 ? name.slice(dot + 1).toLowerCase() : '';\n}\n\nexport function classifyFile(file: { name: string; type: string }): FileCategory {\n const ext = extensionOf(file.name);\n if (MEDIA_EXTENSIONS.has(ext)) return 'media';\n if (TEXT_EXTENSIONS.has(ext)) return 'text';\n\n // Fallback to MIME type\n if (\n file.type.startsWith('image/') ||\n file.type.startsWith('video/') ||\n file.type.startsWith('audio/')\n ) {\n return 'media';\n }\n if (file.type === 'text/plain' || file.type === 'text/markdown') {\n return 'text';\n }\n return 'unknown';\n}\n\n/**\n * Classify dragged items from a DataTransfer during dragenter/dragover.\n * Browsers restrict full file access during drag — only MIME types are\n * available via DataTransferItem.type.\n */\nfunction classifyDataTransferItems(items: DataTransferItemList): DragContentType {\n let hasMedia = false;\n let hasText = false;\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (item.kind !== 'file') continue;\n\n const mime = item.type.toLowerCase();\n if (mime.startsWith('image/') || mime.startsWith('video/') || mime.startsWith('audio/')) {\n hasMedia = true;\n } else if (\n mime === 'text/plain' ||\n mime === 'text/markdown' ||\n mime === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'\n ) {\n hasText = true;\n } else {\n // Unknown MIME — browsers often report '' for many file types during drag.\n // We can't classify, so assume mixed to show all drop zones.\n hasMedia = true;\n hasText = true;\n }\n }\n\n if (hasMedia && hasText) return 'mixed';\n if (hasMedia) return 'media';\n if (hasText) return 'text';\n return null;\n}\n\n// ─── Hook ────────────────────────────────────────────────\n\nexport interface UseFileDropOptions {\n /** Called when files are dropped on a specific target zone. */\n onDrop: (files: File[], target: DropTarget) => void;\n /** Whether drop is enabled (default: true) */\n enabled?: boolean;\n}\n\nexport interface UseFileDropResult {\n /** Whether a drag-with-files is currently hovering over the container */\n isDragging: boolean;\n /** Classification of the dragged content */\n dragContentType: DragContentType;\n /** Attach these to the container element */\n containerProps: {\n onDragEnter: (e: React.DragEvent) => void;\n onDragOver: (e: React.DragEvent) => void;\n onDragLeave: (e: React.DragEvent) => void;\n onDrop: (e: React.DragEvent) => void;\n };\n /** Create props for an individual drop zone target */\n zoneProps: (target: DropTarget) => {\n onDragOver: (e: React.DragEvent) => void;\n onDrop: (e: React.DragEvent) => void;\n };\n}\n\nexport function useFileDrop({ onDrop, enabled = true }: UseFileDropOptions): UseFileDropResult {\n const [isDragging, setIsDragging] = useState(false);\n const [dragContentType, setDragContentType] = useState<DragContentType>(null);\n\n // Counter-based tracking: dragenter/dragleave fire on child elements,\n // so we track a count rather than a boolean.\n const dragCounterRef = useRef(0);\n\n // True while a drag that originated *inside* this page is in flight.\n // Browsers expose draggable `<img>` elements as virtual files in\n // `dataTransfer.types` (so they can be dropped onto the desktop), so\n // checking for `'Files'` alone can't tell an OS file drop apart from\n // an in-app image reorder. We watch the document-level `dragstart`\n // event — only OS drags from outside the page lack a `dragstart` —\n // and bail out of the overlay logic when this flag is set.\n const inPageDragRef = useRef(false);\n useEffect(() => {\n if (!enabled) return;\n const onStart = () => {\n inPageDragRef.current = true;\n };\n const onEnd = () => {\n inPageDragRef.current = false;\n };\n document.addEventListener('dragstart', onStart, true);\n document.addEventListener('dragend', onEnd, true);\n document.addEventListener('drop', onEnd, true);\n return () => {\n document.removeEventListener('dragstart', onStart, true);\n document.removeEventListener('dragend', onEnd, true);\n document.removeEventListener('drop', onEnd, true);\n };\n }, [enabled]);\n\n const handleDragEnter = useCallback(\n (e: React.DragEvent) => {\n if (!enabled) return;\n\n // Drag started inside the page (e.g. repositioning an `<img>`\n // already in the WYSIWYG document, or dragging a thumbnail out of\n // the MediaBin). Do NOT show the file-drop overlay — let\n // ProseMirror handle the in-document move with its dropcursor.\n if (inPageDragRef.current) return;\n\n // For OS-level drags, the browser sets the special `'Files'`\n // type. Bail out for anything else (text drags between apps,\n // etc.) so we don't flash the overlay on irrelevant gestures.\n const types = e.dataTransfer.types;\n const hasFiles = types && Array.from(types).includes('Files');\n if (!hasFiles) return;\n\n const classification = e.dataTransfer.items\n ? classifyDataTransferItems(e.dataTransfer.items)\n : 'mixed';\n if (!classification) return;\n\n e.preventDefault();\n dragCounterRef.current++;\n\n if (dragCounterRef.current === 1) {\n setIsDragging(true);\n setDragContentType(classification);\n }\n },\n [enabled],\n );\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n if (!enabled) return;\n e.preventDefault();\n // Required to allow drop\n e.dataTransfer.dropEffect = 'copy';\n },\n [enabled],\n );\n\n const handleDragLeave = useCallback(\n (e: React.DragEvent) => {\n if (!enabled) return;\n e.preventDefault();\n dragCounterRef.current = Math.max(0, dragCounterRef.current - 1);\n\n if (dragCounterRef.current === 0) {\n setIsDragging(false);\n setDragContentType(null);\n }\n },\n [enabled],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n if (!enabled) return;\n e.preventDefault();\n dragCounterRef.current = 0;\n setIsDragging(false);\n setDragContentType(null);\n // Actual file handling is done by zone-specific onDrop\n },\n [enabled],\n );\n\n const zoneProps = useCallback(\n (target: DropTarget) => ({\n onDragOver: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n e.dataTransfer.dropEffect = 'copy';\n },\n onDrop: (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n dragCounterRef.current = 0;\n setIsDragging(false);\n setDragContentType(null);\n\n const files = Array.from(e.dataTransfer.files);\n if (files.length > 0) {\n onDrop(files, target);\n }\n },\n }),\n [onDrop],\n );\n\n return {\n isDragging,\n dragContentType,\n containerProps: {\n onDragEnter: handleDragEnter,\n onDragOver: handleDragOver,\n onDragLeave: handleDragLeave,\n onDrop: handleDrop,\n },\n zoneProps,\n };\n}\n","/**\n * Drop Utilities\n *\n * File processing pipeline for dropped files. Classifies files by type,\n * processes media files into a MediaProvider, and converts text files\n * (.md, .txt, .docx) to markdown strings.\n */\n\nimport type { MediaProvider } from '@bendyline/squisq/schemas';\nimport { stringifyMarkdown } from '@bendyline/squisq/markdown';\nimport { docxToMarkdownDoc } from '@bendyline/squisq-formats/docx';\nimport { classifyFile, type FileCategory } from '../hooks/useFileDrop';\n\nexport type { FileCategory };\nexport { classifyFile };\n\n/**\n * Partition an array of files into media and text categories.\n * Files with unknown type are skipped.\n */\nexport function partitionFiles(files: File[]): { media: File[]; text: File[] } {\n const media: File[] = [];\n const text: File[] = [];\n\n for (const file of files) {\n const cat = classifyFile(file);\n if (cat === 'media') media.push(file);\n else if (cat === 'text') text.push(file);\n }\n\n return { media, text };\n}\n\n/**\n * Add media files to a MediaProvider. Returns the relative paths\n * assigned by the provider, with `null` slots where a file could not\n * be processed — keeping the result aligned with the input array so\n * callers can correlate indices.\n *\n * Two failure modes are handled defensively:\n *\n * 1. `file.arrayBuffer()` throws (`InvalidStateError` — \"An operation\n * that depends on state cached in an interface object was made but\n * the state had changed since it was read from disk\"). This happens\n * with virtual drag sources whose File reference goes stale before\n * the async read completes — Phone Link / iOS continuity / certain\n * screenshot tools / etc.\n *\n * 2. `file.arrayBuffer()` returns a 0-byte buffer. Some virtual\n * sources resolve the read successfully but with no payload,\n * leaving an empty file in the media bin. We skip those so the\n * bin doesn't accumulate placeholders.\n *\n * In both cases we warn via console rather than throwing, so a single\n * problematic file doesn't abort a multi-file drop.\n */\nexport async function processMediaFiles(\n files: File[],\n mediaProvider: MediaProvider,\n): Promise<(string | null)[]> {\n const paths: (string | null)[] = [];\n\n for (const file of files) {\n let buffer: ArrayBuffer;\n try {\n buffer = await file.arrayBuffer();\n } catch (err: unknown) {\n console.warn(\n `[squisq-editor] Skipped dropped file \"${file.name}\" — could not read its contents.`,\n 'This is typical for drags from virtual sources (Phone Link, screenshot tools, cross-tab drags) whose File reference goes stale before the async read completes.',\n err instanceof Error ? err.message : err,\n );\n paths.push(null);\n continue;\n }\n\n if (buffer.byteLength === 0) {\n console.warn(\n `[squisq-editor] Skipped dropped file \"${file.name}\" — its contents read as 0 bytes. ` +\n 'The drag source likely never materialized the file (try saving it to disk first, then dragging from there).',\n );\n paths.push(null);\n continue;\n }\n\n const mimeType = file.type || 'application/octet-stream';\n try {\n const path = await mediaProvider.addMedia(file.name, buffer, mimeType);\n paths.push(path);\n } catch (err: unknown) {\n console.warn(\n `[squisq-editor] Failed to save \"${file.name}\" via mediaProvider:`,\n err instanceof Error ? err.message : err,\n );\n paths.push(null);\n }\n }\n\n return paths;\n}\n\n/**\n * Read a text-content file and return its content as a markdown string.\n *\n * - `.md` and `.txt` files are read as UTF-8 text directly\n * - `.docx` files are converted to markdown via `@bendyline/squisq-formats/docx`\n */\nexport async function processTextFile(file: File): Promise<string> {\n const ext = file.name.split('.').pop()?.toLowerCase() ?? '';\n\n if (ext === 'md' || ext === 'txt') {\n return await file.text();\n }\n\n if (ext === 'docx') {\n const buffer = await file.arrayBuffer();\n const markdownDoc = await docxToMarkdownDoc(buffer);\n return stringifyMarkdown(markdownDoc);\n }\n\n return await file.text();\n}\n\n/**\n * Process multiple text files and concatenate their content.\n */\nexport async function processTextFiles(files: File[]): Promise<string> {\n const results: string[] = [];\n\n for (const file of files) {\n const content = await processTextFile(file);\n results.push(content);\n }\n\n return results.join('\\n\\n');\n}\n","/**\n * ViewSwitcher\n *\n * Tab bar for switching between Raw, WYSIWYG, and Preview editor views.\n */\n\nimport { useEditorContext, type EditorView } from './EditorContext';\n\nconst VIEWS: { id: EditorView; label: string; shortLabel?: string; shortcut: string }[] = [\n { id: 'raw', label: 'Markdown', shortLabel: 'MD', shortcut: '⌘1' },\n { id: 'wysiwyg', label: 'Editor', shortcut: '⌘2' },\n { id: 'preview', label: 'Preview', shortcut: '⌘3' },\n];\n\nexport interface ViewSwitcherProps {\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Tab-style view switcher for the three editor modes.\n */\nexport function ViewSwitcher({ className }: ViewSwitcherProps) {\n const { activeView, setActiveView, editorMode } = useEditorContext();\n // In code mode, only the raw view is meaningful. With just one entry in\n // the tab list there's nothing to switch between, so suppress the whole\n // switcher rather than render a single lonely tab.\n const visibleViews = editorMode === 'code' ? VIEWS.filter((v) => v.id === 'raw') : VIEWS;\n if (visibleViews.length <= 1) return null;\n\n return (\n <div\n className={`squisq-view-switcher ${className || ''}`}\n role=\"tablist\"\n aria-label=\"Editor view\"\n >\n {visibleViews.map((view) => (\n <button\n key={view.id}\n role=\"tab\"\n aria-selected={activeView === view.id}\n className={`squisq-view-tab ${activeView === view.id ? 'squisq-view-tab--active' : ''}`}\n onClick={() => setActiveView(view.id)}\n title={`${view.label} (${view.shortcut})`}\n >\n <span className=\"squisq-view-tab-label squisq-view-tab-label--long\">{view.label}</span>\n {view.shortLabel && view.shortLabel !== view.label && (\n <span className=\"squisq-view-tab-label squisq-view-tab-label--short\">\n {view.shortLabel}\n </span>\n )}\n </button>\n ))}\n </div>\n );\n}\n","/**\n * ThemeCustomizerPanel\n *\n * Drop-in toolbar button + popover that lets the user author a custom\n * Theme by picking seed colors, fonts, and a few thematic presets.\n *\n * Design:\n * - **Controlled component** — host owns the `value` and forwards\n * `onChange` whenever the user edits anything. This avoids coupling\n * the panel to any specific preview wiring; the host decides whether\n * to register the theme, set it as the preview theme, persist it, etc.\n * - **Subset of the Theme schema** — the panel exposes seed colors,\n * curated/free-text fonts, and a handful of preset groups. Everything\n * else (templateHints, layoutOverrides, persistentLayers, individual\n * colorSchemes, animation defaults) inherits from the compiler's\n * STARTER_THEME and can only be edited by hand-modifying the JSON.\n * - **Industry-standard mental model** — primary / secondary / accent +\n * derived lighter/darker variants, like Material UI / Tailwind / Radix.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { Theme, FontFamily, ThemeSeedColors } from '@bendyline/squisq/schemas';\nimport {\n AVAILABLE_FONT_STACKS,\n compileTheme,\n deriveScale,\n isHex,\n serializeTheme,\n} from '@bendyline/squisq/schemas';\n\n// ── Preset → schema-value tables ────────────────────────────────────\n\nconst BORDER_RADIUS_PRESETS = {\n sharp: 0,\n soft: 6,\n rounded: 16,\n} as const;\ntype BorderRadiusPreset = keyof typeof BORDER_RADIUS_PRESETS;\n\nconst ANIMATION_SPEED_PRESETS = {\n static: 0,\n subtle: 1.4,\n normal: 1.0,\n expressive: 0.7,\n} as const;\ntype AnimationSpeedPreset = keyof typeof ANIMATION_SPEED_PRESETS;\n\nconst TEXT_SHADOW_PRESETS = {\n off: false,\n on: true,\n} as const;\ntype TextShadowPreset = keyof typeof TEXT_SHADOW_PRESETS;\n\nconst CONTRAST_PRESETS = ['subtle', 'balanced', 'high'] as const;\ntype ContrastPreset = (typeof CONTRAST_PRESETS)[number];\n\nconst FALLBACK_OPTIONS = ['sans-serif', 'serif', 'monospace', 'system-ui'] as const;\ntype FallbackOption = (typeof FALLBACK_OPTIONS)[number];\n\n// ── Draft state — reflects the editable subset of the schema ────────\n\ninterface CustomFontInput {\n kind: 'curated' | 'custom';\n stackId?: string;\n customName?: string;\n customFallback?: FallbackOption;\n}\n\ninterface Draft {\n name: string;\n seeds: ThemeSeedColors;\n titleFont: CustomFontInput;\n bodyFont: CustomFontInput;\n borderRadius: BorderRadiusPreset;\n animationSpeed: AnimationSpeedPreset;\n textShadow: TextShadowPreset;\n contrast: ContrastPreset;\n}\n\nconst DEFAULT_DRAFT: Draft = {\n name: 'My Theme',\n seeds: {\n primary: '#3182ce',\n secondary: '#4a5568',\n accent: '#63b3ed',\n background: '#1a202c',\n text: '#f7fafc',\n },\n titleFont: { kind: 'curated', stackId: 'system-serif' },\n bodyFont: { kind: 'curated', stackId: 'system-sans' },\n borderRadius: 'soft',\n animationSpeed: 'normal',\n textShadow: 'on',\n contrast: 'balanced',\n};\n\nfunction findRadiusPreset(value: number | undefined): BorderRadiusPreset {\n if (value === undefined) return 'soft';\n let best: BorderRadiusPreset = 'soft';\n let bestDist = Infinity;\n (Object.entries(BORDER_RADIUS_PRESETS) as [BorderRadiusPreset, number][]).forEach(([k, v]) => {\n const d = Math.abs(v - value);\n if (d < bestDist) {\n best = k;\n bestDist = d;\n }\n });\n return best;\n}\n\nfunction findAnimationPreset(value: number | undefined): AnimationSpeedPreset {\n if (value === undefined || value === 0) return value === 0 ? 'static' : 'normal';\n let best: AnimationSpeedPreset = 'normal';\n let bestDist = Infinity;\n (Object.entries(ANIMATION_SPEED_PRESETS) as [AnimationSpeedPreset, number][]).forEach(\n ([k, v]) => {\n if (v === 0) return; // 'static' handled above\n const d = Math.abs(v - value);\n if (d < bestDist) {\n best = k;\n bestDist = d;\n }\n },\n );\n return best;\n}\n\nfunction fontFamilyToInput(f: FontFamily | undefined, fallbackStackId: string): CustomFontInput {\n if (!f) return { kind: 'curated', stackId: fallbackStackId };\n if ('stackId' in f) return { kind: 'curated', stackId: f.stackId };\n if ('custom' in f)\n return {\n kind: 'custom',\n customName: f.custom.name,\n customFallback: f.custom.fallback,\n };\n return { kind: 'curated', stackId: fallbackStackId };\n}\n\nfunction inputToFontFamily(input: CustomFontInput): FontFamily {\n if (input.kind === 'curated') {\n return { stackId: input.stackId ?? 'system-sans' };\n }\n return {\n custom: {\n name: input.customName ?? 'Sans',\n fallback: input.customFallback ?? 'sans-serif',\n },\n };\n}\n\nfunction themeToDraft(theme: Theme | null): Draft {\n if (!theme) return { ...DEFAULT_DRAFT };\n const seeds: ThemeSeedColors = theme.seedColors ?? {\n primary: theme.colors.primary,\n secondary: theme.colors.secondary,\n accent: theme.colors.highlight,\n background: theme.colors.background,\n text: theme.colors.text,\n };\n return {\n name: theme.name,\n seeds: {\n primary: seeds.primary,\n secondary: seeds.secondary,\n accent: seeds.accent,\n background: seeds.background,\n text: seeds.text,\n },\n titleFont: fontFamilyToInput(theme.typography.titleFont, 'system-serif'),\n bodyFont: fontFamilyToInput(theme.typography.bodyFont, 'system-sans'),\n borderRadius: findRadiusPreset(theme.style.borderRadius),\n animationSpeed: findAnimationPreset(theme.style.animationSpeed),\n textShadow: theme.style.textShadow === false ? 'off' : 'on',\n contrast: 'balanced',\n };\n}\n\nfunction slugify(s: string): string {\n return (\n s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'custom'\n );\n}\n\nfunction compileDraft(draft: Draft, baseId?: string): Theme {\n const id = baseId && baseId.startsWith('custom-') ? baseId : `custom-${slugify(draft.name)}`;\n return compileTheme(\n {\n id,\n name: draft.name,\n seedColors: draft.seeds,\n typography: {\n titleFont: inputToFontFamily(draft.titleFont),\n bodyFont: inputToFontFamily(draft.bodyFont),\n },\n style: {\n borderRadius: BORDER_RADIUS_PRESETS[draft.borderRadius],\n animationSpeed: ANIMATION_SPEED_PRESETS[draft.animationSpeed],\n textShadow: TEXT_SHADOW_PRESETS[draft.textShadow],\n },\n },\n { contrast: draft.contrast },\n );\n}\n\n// ── Component ───────────────────────────────────────────────────────\n\nexport interface ThemeCustomizerPanelProps {\n /** Current custom theme (or null to start from defaults). */\n value: Theme | null;\n /** Fired on every edit. Host typically registers the theme + previews it. */\n onChange: (theme: Theme) => void;\n /** Fired when the user clicks Save. Host typically persists the theme JSON. */\n onSave?: (theme: Theme, json: string) => void;\n /** Fired when the user clicks Reset. Host typically clears its persistent storage. */\n onReset?: () => void;\n}\n\nexport function ThemeCustomizerPanel({\n value,\n onChange,\n onSave,\n onReset,\n}: ThemeCustomizerPanelProps) {\n const [open, setOpen] = useState(false);\n const [draft, setDraft] = useState<Draft>(() => themeToDraft(value));\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Whenever an external value lands (e.g., page load with persisted theme),\n // sync the draft. Internal edits update both draft and value via onChange.\n const externalIdRef = useRef<string | null>(value?.id ?? null);\n useEffect(() => {\n const incomingId = value?.id ?? null;\n if (incomingId !== externalIdRef.current) {\n externalIdRef.current = incomingId;\n setDraft(themeToDraft(value));\n }\n }, [value]);\n\n // Click-outside to close.\n useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [open]);\n\n const updateDraft = useCallback(\n (patch: Partial<Draft> | ((d: Draft) => Draft)) => {\n setDraft((prev) => {\n const next = typeof patch === 'function' ? patch(prev) : { ...prev, ...patch };\n try {\n const compiled = compileDraft(next, value?.id);\n onChange(compiled);\n } catch {\n // Invalid intermediate state (e.g., bad hex while typing) — skip emit.\n }\n return next;\n });\n },\n [onChange, value?.id],\n );\n\n const updateSeed = useCallback(\n (key: keyof ThemeSeedColors, hex: string) => {\n updateDraft((d) => ({ ...d, seeds: { ...d.seeds, [key]: hex } }));\n },\n [updateDraft],\n );\n\n const handleSave = useCallback(() => {\n try {\n const compiled = compileDraft(draft, value?.id);\n onSave?.(compiled, serializeTheme(compiled));\n } catch {\n // Validation should already have surfaced via the disabled state.\n }\n }, [draft, onSave, value?.id]);\n\n const handleReset = useCallback(() => {\n setDraft({ ...DEFAULT_DRAFT });\n try {\n onChange(compileDraft(DEFAULT_DRAFT));\n } catch {\n // ignore\n }\n onReset?.();\n }, [onChange, onReset]);\n\n const previewSwatches = useMemo(() => {\n const seed = draft.seeds.primary;\n if (!isHex(seed)) return null;\n return deriveScale(\n seed,\n draft.contrast === 'high' ? 0.22 : draft.contrast === 'subtle' ? 0.08 : 0.15,\n );\n }, [draft.seeds.primary, draft.contrast]);\n\n return (\n <div className=\"squisq-theme-customizer\" ref={containerRef}>\n <button\n type=\"button\"\n className={`squisq-toolbar-button squisq-theme-customizer-trigger${\n open ? ' squisq-toolbar-button--active' : ''\n }`}\n data-tooltip=\"Customize theme\"\n aria-label=\"Customize theme\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"6\" />\n <path d=\"M8 2 A6 6 0 0 1 8 14 Z\" fill=\"currentColor\" stroke=\"none\" />\n </svg>\n </button>\n {open && (\n <div className=\"squisq-theme-customizer-popover\" role=\"dialog\" aria-label=\"Customize theme\">\n <div className=\"squisq-theme-customizer-header\">\n <span className=\"squisq-theme-customizer-title\">Customize theme</span>\n </div>\n\n <div className=\"squisq-theme-customizer-body\">\n <Section title=\"Name\">\n <input\n type=\"text\"\n className=\"squisq-theme-customizer-input\"\n value={draft.name}\n onChange={(e) => updateDraft({ name: e.target.value })}\n aria-label=\"Theme name\"\n />\n </Section>\n\n <Section title=\"Colors\" hint=\"Pick seed colors. The rest is derived.\">\n <SeedColorRow\n label=\"Primary\"\n value={draft.seeds.primary}\n onChange={(v) => updateSeed('primary', v)}\n />\n <SeedColorRow\n label=\"Secondary\"\n value={draft.seeds.secondary ?? ''}\n onChange={(v) => updateSeed('secondary', v)}\n />\n <SeedColorRow\n label=\"Accent\"\n value={draft.seeds.accent ?? ''}\n onChange={(v) => updateSeed('accent', v)}\n />\n <SeedColorRow\n label=\"Background\"\n value={draft.seeds.background ?? ''}\n onChange={(v) => updateSeed('background', v)}\n />\n <SeedColorRow\n label=\"Text\"\n value={draft.seeds.text ?? ''}\n onChange={(v) => updateSeed('text', v)}\n />\n {previewSwatches && (\n <div className=\"squisq-theme-customizer-scale\" aria-label=\"Derived primary scale\">\n {(['lighter2', 'lighter1', 'base', 'darker1', 'darker2'] as const).map((k) => (\n <span\n key={k}\n className=\"squisq-theme-customizer-swatch\"\n style={{ background: previewSwatches[k] }}\n title={`${k}: ${previewSwatches[k]}`}\n />\n ))}\n </div>\n )}\n </Section>\n\n <Section title=\"Typography\">\n <FontPicker\n label=\"Heading\"\n value={draft.titleFont}\n onChange={(next) => updateDraft({ titleFont: next })}\n />\n <FontPicker\n label=\"Body\"\n value={draft.bodyFont}\n onChange={(next) => updateDraft({ bodyFont: next })}\n />\n </Section>\n\n <Section title=\"Style\">\n <PresetRow\n label=\"Border radius\"\n value={draft.borderRadius}\n options={Object.keys(BORDER_RADIUS_PRESETS) as BorderRadiusPreset[]}\n onChange={(v) => updateDraft({ borderRadius: v })}\n />\n <PresetRow\n label=\"Animation\"\n value={draft.animationSpeed}\n options={Object.keys(ANIMATION_SPEED_PRESETS) as AnimationSpeedPreset[]}\n onChange={(v) => updateDraft({ animationSpeed: v })}\n />\n <PresetRow\n label=\"Text shadow\"\n value={draft.textShadow}\n options={Object.keys(TEXT_SHADOW_PRESETS) as TextShadowPreset[]}\n onChange={(v) => updateDraft({ textShadow: v })}\n />\n <PresetRow\n label=\"Contrast\"\n value={draft.contrast}\n options={CONTRAST_PRESETS as readonly ContrastPreset[]}\n onChange={(v) => updateDraft({ contrast: v })}\n />\n </Section>\n </div>\n\n <div className=\"squisq-theme-customizer-footer\">\n <button type=\"button\" className=\"squisq-theme-customizer-button\" onClick={handleReset}>\n Reset\n </button>\n {onSave && (\n <button\n type=\"button\"\n className=\"squisq-theme-customizer-button squisq-theme-customizer-button--primary\"\n onClick={handleSave}\n >\n Save\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ── Subcomponents ───────────────────────────────────────────────────\n\nfunction Section({\n title,\n hint,\n children,\n}: {\n title: string;\n hint?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className=\"squisq-theme-customizer-section\">\n <div className=\"squisq-theme-customizer-section-title\">{title}</div>\n {hint && <div className=\"squisq-theme-customizer-section-hint\">{hint}</div>}\n <div className=\"squisq-theme-customizer-section-body\">{children}</div>\n </div>\n );\n}\n\nfunction SeedColorRow({\n label,\n value,\n onChange,\n}: {\n label: string;\n value: string;\n onChange: (hex: string) => void;\n}) {\n const safeValue = isHex(value) ? value : '#000000';\n return (\n <label className=\"squisq-theme-customizer-row\">\n <span className=\"squisq-theme-customizer-row-label\">{label}</span>\n <input\n type=\"color\"\n className=\"squisq-theme-customizer-color\"\n value={safeValue}\n onChange={(e) => onChange(e.target.value)}\n />\n <input\n type=\"text\"\n className=\"squisq-theme-customizer-input squisq-theme-customizer-input--hex\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n spellCheck={false}\n aria-label={`${label} hex value`}\n />\n </label>\n );\n}\n\nfunction FontPicker({\n label,\n value,\n onChange,\n}: {\n label: string;\n value: CustomFontInput;\n onChange: (next: CustomFontInput) => void;\n}) {\n return (\n <div className=\"squisq-theme-customizer-row squisq-theme-customizer-row--font\">\n <span className=\"squisq-theme-customizer-row-label\">{label}</span>\n <select\n className=\"squisq-theme-customizer-input\"\n value={value.kind === 'custom' ? '__custom__' : (value.stackId ?? '')}\n onChange={(e) => {\n const v = e.target.value;\n if (v === '__custom__') {\n onChange({\n kind: 'custom',\n customName: value.customName ?? '',\n customFallback: value.customFallback ?? 'sans-serif',\n });\n } else {\n onChange({ kind: 'curated', stackId: v });\n }\n }}\n aria-label={`${label} font`}\n >\n {AVAILABLE_FONT_STACKS.map((stack) => (\n <option key={stack.id} value={stack.id}>\n {stack.label}\n </option>\n ))}\n <option value=\"__custom__\">Custom…</option>\n </select>\n {value.kind === 'custom' && (\n <>\n <input\n type=\"text\"\n className=\"squisq-theme-customizer-input\"\n placeholder=\"Font name\"\n value={value.customName ?? ''}\n onChange={(e) => onChange({ ...value, customName: e.target.value })}\n aria-label={`${label} custom font name`}\n />\n <select\n className=\"squisq-theme-customizer-input\"\n value={value.customFallback ?? 'sans-serif'}\n onChange={(e) =>\n onChange({ ...value, customFallback: e.target.value as FallbackOption })\n }\n aria-label={`${label} custom font fallback`}\n >\n {FALLBACK_OPTIONS.map((opt) => (\n <option key={opt} value={opt}>\n {opt}\n </option>\n ))}\n </select>\n </>\n )}\n </div>\n );\n}\n\nfunction PresetRow<T extends string>({\n label,\n value,\n options,\n onChange,\n}: {\n label: string;\n value: T;\n options: readonly T[];\n onChange: (v: T) => void;\n}) {\n return (\n <label className=\"squisq-theme-customizer-row\">\n <span className=\"squisq-theme-customizer-row-label\">{label}</span>\n <select\n className=\"squisq-theme-customizer-input\"\n value={value}\n onChange={(e) => onChange(e.target.value as T)}\n aria-label={label}\n >\n {options.map((o) => (\n <option key={o} value={o}>\n {o}\n </option>\n ))}\n </select>\n </label>\n );\n}\n","/**\n * Shared state for `<JsonEditor>`. Each editor renderer reads its\n * slice via JSON Pointer and calls `setAtPath` to commit edits — the\n * top-level component owns the canonical value and propagates changes\n * to the host's `onChange`.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport type {\n JsonFormValidationError,\n JsonFormValidator,\n SquisqAnnotatedSchema,\n} from '@bendyline/squisq/jsonForm';\nimport { setByPointer } from '@bendyline/squisq/jsonForm';\n\nexport interface JsonEditorContextValue {\n rootSchema: SquisqAnnotatedSchema;\n rootData: unknown;\n /** Commit a new value at `pointer`, computing & emitting a new root. */\n setAtPath: (pointer: string, value: unknown) => void;\n density: 'comfortable' | 'compact';\n errors: ReadonlyMap<string, JsonFormValidationError[]>;\n /** Optional richtext editor component, supplied internally. */\n}\n\nconst JsonEditorContext = createContext<JsonEditorContextValue | null>(null);\n\nexport interface JsonEditorProviderProps {\n rootSchema: SquisqAnnotatedSchema;\n rootData: unknown;\n onRootChange: (next: unknown) => void;\n density: 'comfortable' | 'compact';\n validate?: JsonFormValidator;\n onValidate?: (errors: readonly JsonFormValidationError[]) => void;\n children: ReactNode;\n}\n\nexport function JsonEditorProvider(props: JsonEditorProviderProps) {\n const { rootSchema, rootData, onRootChange, density, validate, onValidate, children } = props;\n\n const errors = useMemo(() => {\n if (!validate) return new Map<string, JsonFormValidationError[]>();\n const list = validate(rootData, rootSchema);\n if (onValidate) onValidate(list);\n const grouped = new Map<string, JsonFormValidationError[]>();\n for (const e of list) {\n const arr = grouped.get(e.path) ?? [];\n arr.push(e);\n grouped.set(e.path, arr);\n }\n return grouped;\n }, [validate, rootData, rootSchema, onValidate]);\n\n const setAtPath = useMemo(\n () => (pointer: string, value: unknown) => {\n const next = setByPointer(rootData, pointer, value);\n onRootChange(next);\n },\n [rootData, onRootChange],\n );\n\n const value: JsonEditorContextValue = useMemo(\n () => ({ rootSchema, rootData, setAtPath, density, errors }),\n [rootSchema, rootData, setAtPath, density, errors],\n );\n\n return <JsonEditorContext.Provider value={value}>{children}</JsonEditorContext.Provider>;\n}\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useJsonEditor(): JsonEditorContextValue {\n const ctx = useContext(JsonEditorContext);\n if (!ctx) throw new Error('useJsonEditor must be used inside <JsonEditor>');\n return ctx;\n}\n","/**\n * Recursive editor dispatcher: looks at a schema slice, evaluates\n * `hidden`/`disabled` rules, picks an editor component, and wraps it\n * with label + help + error chrome unless the editor is composite\n * (group / card-stack / tabs / richtext, which present their own).\n */\n\nimport {\n chooseControl,\n resolveFlag,\n resolveRef,\n type SquisqAnnotatedSchema,\n} from '@bendyline/squisq/jsonForm';\nimport { useJsonEditor } from './JsonEditorContext';\nimport { EDITORS, isCompositeControl } from './editors';\n\nexport interface RenderNodeProps {\n value: unknown;\n schema: SquisqAnnotatedSchema;\n pointer: string;\n parentDisabled?: boolean;\n suppressTopGroupTitle?: boolean;\n}\n\nexport function RenderNode(props: RenderNodeProps): React.ReactElement | null {\n const { rootSchema, rootData, errors } = useJsonEditor();\n const resolved = resolveRef(props.schema, rootSchema) ?? props.schema;\n\n if (resolveFlag(resolved.squisq?.hidden, rootData)) return null;\n\n const disabled =\n (props.parentDisabled ?? false) || resolveFlag(resolved.squisq?.disabled, rootData);\n const kind = chooseControl(resolved);\n const Editor = EDITORS[kind];\n const label = resolved.squisq?.label ?? resolved.title;\n const help = resolved.squisq?.help ?? resolved.description;\n const fieldErrors = errors.get(props.pointer) ?? [];\n\n const editorEl = (\n <Editor\n value={props.value}\n schema={resolved}\n pointer={props.pointer}\n disabled={disabled}\n // GroupEditor honors this — other editors ignore the extra prop.\n // @ts-expect-error optional renderer-specific prop\n suppressTitle={props.suppressTopGroupTitle}\n />\n );\n\n if (isCompositeControl(kind, resolved)) {\n // Composite editors handle their own labeling.\n return editorEl;\n }\n\n return (\n <div className={`squisq-jf-field${disabled ? ' squisq-jf-field--disabled' : ''}`}>\n {label ? <label className=\"squisq-jf-field__label\">{label}</label> : null}\n {editorEl}\n {help ? <p className=\"squisq-jf-field__help\">{help}</p> : null}\n {fieldErrors.length > 0 ? (\n <p className=\"squisq-jf-field__error\">{fieldErrors[0].message}</p>\n ) : null}\n </div>\n );\n}\n","/**\n * Editable renderers for `<JsonEditor>`. Each editor is a small\n * controlled component that reads its slice from the\n * `JsonEditorContext` via JSON Pointer and writes back via\n * `setAtPath`. Composite renderers (group, card-stack, tabs) recurse\n * into `RenderNode`.\n */\n\nimport { useEffect, useId, useRef, useState, type ChangeEvent } from 'react';\nimport {\n arrayItemKind,\n type ControlKind,\n type SquisqAnnotatedSchema,\n} from '@bendyline/squisq/jsonForm';\nimport { useJsonEditor } from './JsonEditorContext';\nimport { RenderNode } from './RenderNode';\nimport { EmbeddedRichTextField } from './EmbeddedRichTextField';\n\nexport interface EditorProps {\n value: unknown;\n schema: SquisqAnnotatedSchema;\n pointer: string;\n disabled: boolean;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────\n\nfunction asString(v: unknown): string {\n if (v === undefined || v === null) return '';\n return String(v);\n}\n\nfunction asNumber(v: unknown): number | '' {\n if (v === undefined || v === null || v === '') return '';\n const n = Number(v);\n return Number.isFinite(n) ? n : '';\n}\n\n// ── Primitive editors ────────────────────────────────────────────\n\nexport function TextEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n return (\n <input\n type=\"text\"\n className=\"squisq-jf-input\"\n value={asString(value)}\n placeholder={schema.squisq?.placeholder}\n disabled={disabled}\n onChange={(e) => setAtPath(pointer, e.target.value)}\n />\n );\n}\n\nexport function MultilineEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const ref = useRef<HTMLTextAreaElement>(null);\n // Auto-grow vertically.\n useEffect(() => {\n const ta = ref.current;\n if (!ta) return;\n ta.style.height = 'auto';\n ta.style.height = `${ta.scrollHeight + 2}px`;\n }, [value]);\n return (\n <textarea\n ref={ref}\n className=\"squisq-jf-textarea\"\n value={asString(value)}\n placeholder={schema.squisq?.placeholder}\n disabled={disabled}\n onChange={(e) => setAtPath(pointer, e.target.value)}\n />\n );\n}\n\nexport function RichTextEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n return (\n <EmbeddedRichTextField\n value={asString(value)}\n placeholder={schema.squisq?.placeholder}\n readOnly={disabled}\n onChange={(md) => setAtPath(pointer, md)}\n />\n );\n}\n\nexport function NumberStepperEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const isInt = schema.type === 'integer';\n const step = schema.squisq?.step ?? schema.multipleOf ?? (isInt ? 1 : 0.1);\n const num = asNumber(value);\n const update = (next: number) => {\n const min = schema.minimum ?? schema.exclusiveMinimum;\n const max = schema.maximum ?? schema.exclusiveMaximum;\n let clamped = next;\n if (typeof min === 'number') clamped = Math.max(min, clamped);\n if (typeof max === 'number') clamped = Math.min(max, clamped);\n setAtPath(pointer, isInt ? Math.round(clamped) : clamped);\n };\n return (\n <span className=\"squisq-jf-stepper\">\n <button\n type=\"button\"\n className=\"squisq-jf-stepper__btn\"\n disabled={disabled}\n onClick={() => update((typeof num === 'number' ? num : 0) - step)}\n aria-label=\"Decrease\"\n >\n −\n </button>\n <input\n className=\"squisq-jf-stepper__input\"\n type=\"number\"\n value={num === '' ? '' : num}\n step={step}\n disabled={disabled}\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.value === '') {\n setAtPath(pointer, undefined);\n return;\n }\n const n = Number(e.target.value);\n if (Number.isFinite(n)) update(n);\n }}\n />\n <button\n type=\"button\"\n className=\"squisq-jf-stepper__btn\"\n disabled={disabled}\n onClick={() => update((typeof num === 'number' ? num : 0) + step)}\n aria-label=\"Increase\"\n >\n +\n </button>\n </span>\n );\n}\n\nexport function SliderEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const min = (schema.minimum ?? schema.exclusiveMinimum ?? 0) as number;\n const max = (schema.maximum ?? schema.exclusiveMaximum ?? 100) as number;\n const step = schema.squisq?.step ?? schema.multipleOf ?? (schema.type === 'integer' ? 1 : 1);\n const num = asNumber(value);\n const display = typeof num === 'number' ? num : min;\n return (\n <span className=\"squisq-jf-slider-row\">\n <input\n type=\"range\"\n className=\"squisq-jf-slider\"\n min={min}\n max={max}\n step={step}\n value={display}\n disabled={disabled}\n onChange={(e) => setAtPath(pointer, Number(e.target.value))}\n />\n <span className=\"squisq-jf-slider-readout\">{display}</span>\n </span>\n );\n}\n\nexport function ToggleEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const on = Boolean(value);\n return (\n <button\n type=\"button\"\n className={`squisq-jf-toggle${on ? ' squisq-jf-toggle--on' : ''}`}\n disabled={disabled}\n onClick={() => setAtPath(pointer, !on)}\n aria-pressed={on}\n >\n <span className=\"squisq-jf-toggle__track\">\n <span className=\"squisq-jf-toggle__thumb\" />\n </span>\n <span className=\"squisq-jf-toggle__label\">\n {on\n ? schema.squisq?.label\n ? `${schema.squisq.label}: On`\n : 'On'\n : schema.squisq?.label\n ? `${schema.squisq.label}: Off`\n : 'Off'}\n </span>\n </button>\n );\n}\n\nexport function CheckboxEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const id = useId();\n return (\n <label htmlFor={id} className=\"squisq-jf-toggle\">\n <input\n id={id}\n type=\"checkbox\"\n checked={Boolean(value)}\n disabled={disabled}\n onChange={(e) => setAtPath(pointer, e.target.checked)}\n />\n {schema.squisq?.label ?? schema.title ?? ''}\n </label>\n );\n}\n\nfunction enumOptions(schema: SquisqAnnotatedSchema): { value: unknown; label: string }[] {\n const labels = schema.squisq?.enumLabels;\n return (schema.enum ?? []).map((v) => ({\n value: v,\n label: labels && typeof v === 'string' ? (labels[v] ?? String(v)) : String(v),\n }));\n}\n\nexport function SegmentedEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const options = enumOptions(schema);\n return (\n <span className=\"squisq-jf-segmented\">\n {options.map((opt, i) => {\n const active = value === opt.value;\n return (\n <button\n key={i}\n type=\"button\"\n className={`squisq-jf-segmented__btn${active ? ' squisq-jf-segmented__btn--active' : ''}`}\n disabled={disabled}\n onClick={() => setAtPath(pointer, opt.value)}\n >\n {opt.label}\n </button>\n );\n })}\n </span>\n );\n}\n\nexport function RadioEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const options = enumOptions(schema);\n const name = useId();\n return (\n <div className=\"squisq-jf-radio\">\n {options.map((opt, i) => {\n const active = value === opt.value;\n return (\n <label key={i} className=\"squisq-jf-radio__option\">\n <input\n type=\"radio\"\n name={name}\n checked={active}\n disabled={disabled}\n onChange={() => setAtPath(pointer, opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\nexport function ComboboxEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const options = enumOptions(schema);\n return (\n <select\n className=\"squisq-jf-select\"\n value={asString(value)}\n disabled={disabled}\n onChange={(e) => {\n const raw = e.target.value;\n const matched = options.find((opt) => String(opt.value) === raw);\n setAtPath(pointer, matched ? matched.value : raw);\n }}\n >\n {options.map((opt, i) => (\n <option key={i} value={String(opt.value)}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n}\n\nexport function ColorEditor({ value, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const hex = typeof value === 'string' && /^#[0-9a-f]{6}$/i.test(value) ? value : '#000000';\n return (\n <span className=\"squisq-jf-color\">\n <input\n type=\"color\"\n className=\"squisq-jf-color__input\"\n value={hex}\n disabled={disabled}\n onChange={(e) => setAtPath(pointer, e.target.value)}\n />\n <input\n type=\"text\"\n className=\"squisq-jf-input squisq-jf-color__hex\"\n value={asString(value)}\n disabled={disabled}\n onChange={(e) => setAtPath(pointer, e.target.value)}\n />\n </span>\n );\n}\n\nexport function DateEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const fmt = schema.format;\n const inputType = fmt === 'time' ? 'time' : fmt === 'date' ? 'date' : 'datetime-local';\n // datetime-local needs YYYY-MM-DDTHH:mm; if the value is an ISO string we\n // strip the trailing Z + seconds for the input, then write back the full\n // value the user picked.\n const display =\n inputType === 'datetime-local' && typeof value === 'string' && value.includes('T')\n ? value.replace(/Z$|:\\d{2}\\.\\d+Z?$/, '').slice(0, 16)\n : asString(value);\n return (\n <input\n type={inputType}\n className=\"squisq-jf-input\"\n value={display}\n disabled={disabled}\n onChange={(e) => setAtPath(pointer, e.target.value)}\n />\n );\n}\n\n// ── Composite editors ────────────────────────────────────────────\n\nexport function GroupEditor(props: EditorProps & { suppressTitle?: boolean }) {\n const { value, schema, pointer, disabled, suppressTitle } = props;\n const title = !suppressTitle ? (schema.squisq?.label ?? schema.title) : undefined;\n const help = schema.squisq?.help ?? schema.description;\n const obj = (value && typeof value === 'object' ? (value as Record<string, unknown>) : {}) ?? {};\n const propEntries = Object.entries(schema.properties ?? {});\n\n return (\n <section className=\"squisq-jf-group\">\n {title ? <h3 className=\"squisq-jf-group__title\">{title}</h3> : null}\n {help ? <p className=\"squisq-jf-group__help\">{help}</p> : null}\n {propEntries.map(([key, propSchema]) => (\n <RenderNode\n key={key}\n value={obj[key]}\n schema={propSchema}\n pointer={`${pointer}/${key}`}\n parentDisabled={disabled}\n />\n ))}\n </section>\n );\n}\n\nexport function ChipBinEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const items: unknown[] = Array.isArray(value) ? value : [];\n const itemSchema = (Array.isArray(schema.items) ? schema.items[0] : schema.items) ?? {\n type: 'string',\n };\n const labels = itemSchema.squisq?.enumLabels;\n const enumOpts = itemSchema.enum;\n const [draft, setDraft] = useState('');\n\n const remove = (index: number) => {\n const next = items.slice();\n next.splice(index, 1);\n setAtPath(pointer, next);\n };\n const add = (raw: string) => {\n if (raw === '') return;\n const coerced = coerceToSchema(raw, itemSchema);\n setAtPath(pointer, [...items, coerced]);\n setDraft('');\n };\n\n return (\n <div className=\"squisq-jf-chip-bin\">\n {items.map((item, i) => {\n const display =\n labels && typeof item === 'string' ? (labels[item] ?? String(item)) : String(item);\n return (\n <span key={i} className=\"squisq-jf-chip\">\n {display}\n <button\n type=\"button\"\n className=\"squisq-jf-chip__remove\"\n disabled={disabled}\n onClick={() => remove(i)}\n aria-label={`Remove ${display}`}\n >\n ×\n </button>\n </span>\n );\n })}\n {!disabled && enumOpts && enumOpts.length > 0 ? (\n <select\n className=\"squisq-jf-select\"\n value=\"\"\n onChange={(e) => add(e.target.value)}\n style={{ width: 'auto' }}\n >\n <option value=\"\" disabled>\n {schema.squisq?.addLabel ?? '+ Add'}\n </option>\n {enumOpts\n .filter((v: unknown) => !items.includes(v))\n .map((v: unknown, i: number) => (\n <option key={i} value={String(v)}>\n {labels && typeof v === 'string' ? (labels[v] ?? String(v)) : String(v)}\n </option>\n ))}\n </select>\n ) : !disabled ? (\n <input\n type=\"text\"\n className=\"squisq-jf-chip-bin__add-input\"\n placeholder={schema.squisq?.addLabel ?? '+ Add'}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ',') {\n e.preventDefault();\n add(draft.trim());\n }\n }}\n onBlur={() => add(draft.trim())}\n />\n ) : null}\n </div>\n );\n}\n\nfunction coerceToSchema(raw: string, schema: SquisqAnnotatedSchema): unknown {\n switch (schema.type) {\n case 'integer':\n return parseInt(raw, 10);\n case 'number':\n return Number(raw);\n case 'boolean':\n return raw === 'true' || raw === '1';\n default:\n return raw;\n }\n}\n\nexport function CardStackEditor({ value, schema, pointer, disabled }: EditorProps) {\n const { setAtPath } = useJsonEditor();\n const items: unknown[] = Array.isArray(value) ? value : [];\n const itemSchema = (Array.isArray(schema.items) ? schema.items[0] : schema.items) ?? {\n type: 'object',\n };\n const itemLabel = itemSchema.squisq?.itemLabel;\n const addLabel = schema.squisq?.addLabel ?? '+ Add';\n\n const updateItems = (next: unknown[]) => setAtPath(pointer, next);\n const addItem = () => updateItems([...items, defaultForSchema(itemSchema)]);\n const removeItem = (i: number) => {\n const next = items.slice();\n next.splice(i, 1);\n updateItems(next);\n };\n const moveItem = (i: number, delta: number) => {\n const j = i + delta;\n if (j < 0 || j >= items.length) return;\n const next = items.slice();\n [next[i], next[j]] = [next[j], next[i]];\n updateItems(next);\n };\n\n return (\n <div>\n <div className=\"squisq-jf-card-stack\">\n {items.map((item, i) => {\n const title = resolveItemTitle(itemLabel, item, i);\n return (\n <div key={i} className=\"squisq-jf-card\">\n <div className=\"squisq-jf-card__header\">\n <h4 className=\"squisq-jf-card__title\">{title}</h4>\n {!disabled ? (\n <span className=\"squisq-jf-card__actions\">\n <button\n type=\"button\"\n className=\"squisq-jf-icon-btn\"\n onClick={() => moveItem(i, -1)}\n disabled={i === 0}\n aria-label=\"Move up\"\n title=\"Move up\"\n >\n ↑\n </button>\n <button\n type=\"button\"\n className=\"squisq-jf-icon-btn\"\n onClick={() => moveItem(i, +1)}\n disabled={i === items.length - 1}\n aria-label=\"Move down\"\n title=\"Move down\"\n >\n ↓\n </button>\n <button\n type=\"button\"\n className=\"squisq-jf-icon-btn squisq-jf-icon-btn--danger\"\n onClick={() => removeItem(i)}\n aria-label={schema.squisq?.removeLabel ?? 'Remove'}\n title={schema.squisq?.removeLabel ?? 'Remove'}\n >\n ×\n </button>\n </span>\n ) : null}\n </div>\n <RenderNode\n value={item}\n schema={itemSchema}\n pointer={`${pointer}/${i}`}\n parentDisabled={disabled}\n suppressTopGroupTitle\n />\n </div>\n );\n })}\n </div>\n {!disabled ? (\n <button\n type=\"button\"\n className=\"squisq-jf-add-btn\"\n onClick={addItem}\n style={{ marginTop: 8 }}\n >\n {addLabel}\n </button>\n ) : null}\n </div>\n );\n}\n\nfunction resolveItemTitle(\n spec: string | { fromField: string } | undefined,\n item: unknown,\n index: number,\n): string {\n if (!spec) return `Item ${index + 1}`;\n if (typeof spec === 'string') return spec;\n if (item && typeof item === 'object') {\n const v = (item as Record<string, unknown>)[spec.fromField];\n if (typeof v === 'string' && v !== '') return v;\n if (typeof v === 'number') return String(v);\n }\n return `Item ${index + 1}`;\n}\n\nfunction defaultForSchema(schema: SquisqAnnotatedSchema): unknown {\n if (schema.default !== undefined) return schema.default;\n const t = Array.isArray(schema.type) ? schema.type.find((x) => x !== 'null') : schema.type;\n switch (t) {\n case 'object': {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(schema.properties ?? {})) {\n out[k] = defaultForSchema(v);\n }\n return out;\n }\n case 'array':\n return [];\n case 'string':\n return '';\n case 'number':\n case 'integer':\n return (schema.minimum ?? 0) as number;\n case 'boolean':\n return false;\n default:\n return undefined;\n }\n}\n\nexport function TabsEditor({ value, schema, pointer, disabled }: EditorProps) {\n const branches = (schema.oneOf ?? schema.anyOf ?? []) as readonly SquisqAnnotatedSchema[];\n const initial = pickMatchingBranch(branches, value);\n const [active, setActive] = useState(initial);\n // Sync if value changes externally to a different branch shape.\n useEffect(() => {\n setActive(pickMatchingBranch(branches, value));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value]);\n\n const branch = branches[active];\n if (!branch) return null;\n return (\n <div>\n <div className=\"squisq-jf-tabs__strip\">\n {branches.map((b, i) => (\n <button\n key={i}\n type=\"button\"\n className={`squisq-jf-tabs__tab${i === active ? ' squisq-jf-tabs__tab--active' : ''}`}\n disabled={disabled}\n onClick={() => setActive(i)}\n >\n {b.squisq?.label ?? b.title ?? `Option ${i + 1}`}\n </button>\n ))}\n </div>\n <RenderNode value={value} schema={branch} pointer={pointer} parentDisabled={disabled} />\n </div>\n );\n}\n\nfunction pickMatchingBranch(branches: readonly SquisqAnnotatedSchema[], value: unknown): number {\n for (let i = 0; i < branches.length; i++) {\n if (matchesShape(branches[i], value)) return i;\n }\n return 0;\n}\n\nfunction matchesShape(schema: SquisqAnnotatedSchema, value: unknown): boolean {\n const t = schema.type;\n const target = Array.isArray(t) ? t.find((x) => x !== 'null') : t;\n if (!target) return true;\n switch (target) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n case 'integer':\n return typeof value === 'number';\n case 'boolean':\n return typeof value === 'boolean';\n case 'null':\n return value === null;\n case 'array':\n return Array.isArray(value);\n case 'object':\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n default:\n return false;\n }\n}\n\n// ── Registry ──────────────────────────────────────────────────────\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport const EDITORS: Record<ControlKind, React.ComponentType<EditorProps>> = {\n text: TextEditor,\n multiline: MultilineEditor,\n richtext: RichTextEditor,\n color: ColorEditor,\n date: DateEditor,\n time: DateEditor,\n datetime: DateEditor,\n slider: SliderEditor,\n stepper: NumberStepperEditor,\n segmented: SegmentedEditor,\n radio: RadioEditor,\n combobox: ComboboxEditor,\n toggle: ToggleEditor,\n checkbox: CheckboxEditor,\n card: GroupEditor,\n group: GroupEditor,\n 'card-stack': CardStackEditor,\n 'chip-bin': ChipBinEditor,\n tabs: TabsEditor,\n};\n\n/** True when this control kind handles its own grouping/heading. */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function isCompositeControl(kind: ControlKind, schema: SquisqAnnotatedSchema): boolean {\n if (kind === 'group' || kind === 'card' || kind === 'tabs' || kind === 'card-stack') return true;\n if (kind === 'richtext') return true;\n if (kind === 'chip-bin') return arrayItemKind(schema) === 'object';\n return false;\n}\n","/**\n * Standalone Tiptap-backed rich text field for use inside `<JsonEditor>`.\n * Doesn't share `EditorContext` with the document editor — value is a\n * controlled markdown string. Reuses `markdownToTiptap` /\n * `tiptapToMarkdown` so fidelity matches the WysiwygEditor.\n */\n\nimport { useEffect, useRef } from 'react';\nimport { useEditor, EditorContent } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport Table from '@tiptap/extension-table';\nimport TableRow from '@tiptap/extension-table-row';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport TaskList from '@tiptap/extension-task-list';\nimport TaskItem from '@tiptap/extension-task-item';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { markdownToTiptap, tiptapToMarkdown } from '../tiptapBridge';\n\nexport interface EmbeddedRichTextFieldProps {\n value: string;\n onChange: (next: string) => void;\n readOnly?: boolean;\n placeholder?: string;\n className?: string;\n}\n\nexport function EmbeddedRichTextField(props: EmbeddedRichTextFieldProps) {\n const { value, onChange, readOnly = false, placeholder, className } = props;\n const isExternalUpdate = useRef(false);\n const lastValueRef = useRef(value);\n\n const editor = useEditor({\n editable: !readOnly,\n extensions: [\n StarterKit.configure({\n codeBlock: { HTMLAttributes: { class: 'squisq-code-block' } },\n }),\n Table.configure({ resizable: false }),\n TableRow,\n TableCell,\n TableHeader,\n TaskList,\n TaskItem.configure({ nested: true }),\n Placeholder.configure({ placeholder: placeholder ?? '' }),\n ],\n content: markdownToTiptap(value),\n onUpdate: ({ editor: ed }) => {\n if (isExternalUpdate.current) return;\n const html = ed.getHTML();\n const md = tiptapToMarkdown(html);\n lastValueRef.current = md;\n onChange(md);\n },\n editorProps: {\n attributes: {\n class: 'squisq-jf-richtext-prose',\n },\n },\n });\n\n // Sync external value changes back into the editor (e.g., undo at the host level).\n useEffect(() => {\n if (!editor) return;\n if (value === lastValueRef.current) return;\n isExternalUpdate.current = true;\n try {\n editor.commands.setContent(markdownToTiptap(value), false);\n lastValueRef.current = value;\n } finally {\n isExternalUpdate.current = false;\n }\n }, [editor, value]);\n\n useEffect(() => {\n if (editor) editor.setEditable(!readOnly);\n }, [editor, readOnly]);\n\n const cls = 'squisq-jf-richtext' + (className ? ` ${className}` : '');\n return <EditorContent editor={editor} className={cls} />;\n}\n","/**\n * Derive the CSS custom-property bag for `<JsonEditor>` from a Theme +\n * Surface. Mirrors the JsonView token hook in the react package, but\n * uses an editor-specific prefix so the two can coexist on a page.\n */\n\nimport { useMemo } from 'react';\nimport type { CSSProperties } from 'react';\nimport {\n applySurface,\n resolveFontFamily,\n type SurfaceScheme,\n type Theme,\n DEFAULT_THEME,\n DARK_SURFACE,\n LIGHT_SURFACE,\n} from '@bendyline/squisq/schemas';\n\nexport interface JsonEditorTokens {\n style: CSSProperties;\n theme: Theme;\n}\n\nexport function useJsonEditorTokens(\n theme: Theme | undefined,\n surface: SurfaceScheme | 'auto' | undefined,\n): JsonEditorTokens {\n return useMemo(() => {\n const baseTheme = theme ?? DEFAULT_THEME;\n const resolvedSurface =\n surface === 'auto'\n ? typeof window !== 'undefined' &&\n window.matchMedia?.('(prefers-color-scheme: dark)').matches\n ? DARK_SURFACE\n : LIGHT_SURFACE\n : (surface ?? undefined);\n const finalTheme = resolvedSurface ? applySurface(baseTheme, resolvedSurface) : baseTheme;\n\n const titleFont = resolveFontFamily(finalTheme.typography.titleFont, 'system-ui, sans-serif');\n const bodyFont = resolveFontFamily(finalTheme.typography.bodyFont, 'system-ui, sans-serif');\n const monoFont = resolveFontFamily(\n finalTheme.typography.monoFont,\n 'ui-monospace, Consolas, monospace',\n );\n\n const style: CSSProperties = {\n ['--squisq-jsonform-bg' as string]: finalTheme.colors.background,\n ['--squisq-jsonform-text' as string]: finalTheme.colors.text,\n ['--squisq-jsonform-muted' as string]: finalTheme.colors.textMuted,\n ['--squisq-jsonform-primary' as string]: finalTheme.colors.primary,\n ['--squisq-jsonform-accent' as string]: finalTheme.colors.secondary,\n ['--squisq-jsonform-warning' as string]: finalTheme.colors.warning,\n ['--squisq-jsonform-border' as string]: `color-mix(in srgb, ${finalTheme.colors.textMuted} 35%, transparent)`,\n ['--squisq-jsonform-input-bg' as string]: finalTheme.colors.backgroundLight,\n ['--squisq-jsonform-title-font' as string]: titleFont,\n ['--squisq-jsonform-body-font' as string]: bodyFont,\n ['--squisq-jsonform-mono-font' as string]: monoFont,\n ['--squisq-jsonform-radius' as string]: `${finalTheme.style.borderRadius ?? 8}px`,\n };\n\n return { style, theme: finalTheme };\n }, [theme, surface]);\n}\n","/**\n * <JsonEditor>\n *\n * Friendly, theme-aware editor for any JSON value bound to a Squisq-\n * annotated JSON Schema. Hides JSON syntax behind delightful controls:\n * arrays of objects become card stacks, arrays of primitives become\n * chip bins, color fields become swatches, and so on.\n *\n * Companion to `<JsonView>` from `@bendyline/squisq-react` — both share\n * the same `chooseControl()` dispatcher in core, so view and edit modes\n * always agree on what each field _is_.\n */\n\nimport type {\n JsonFormValidationError,\n JsonFormValidator,\n SquisqAnnotatedSchema,\n} from '@bendyline/squisq/jsonForm';\nimport type { SurfaceScheme, Theme } from '@bendyline/squisq/schemas';\nimport { JsonEditorProvider } from './JsonEditorContext';\nimport { RenderNode } from './RenderNode';\nimport { useJsonEditorTokens } from './useJsonEditorTokens';\n\nexport interface JsonEditorProps {\n /** Schema describing the value's shape (with optional `squisq` hints). */\n schema: SquisqAnnotatedSchema;\n /** Controlled value. */\n value: unknown;\n /** Called with the new root after each edit. Omit for read-only behavior. */\n onChange?: (next: unknown) => void;\n /** Optional theme. Defaults to `DEFAULT_THEME`. */\n theme?: Theme;\n /** Light/dark surface override; `'auto'` uses `prefers-color-scheme`. */\n surface?: SurfaceScheme | 'auto';\n /** Padding/gap density. Default: 'comfortable'. */\n density?: 'comfortable' | 'compact';\n /** Optional consumer-supplied validator (e.g. ajv-backed). */\n validate?: JsonFormValidator;\n /** Notified after validation runs. */\n onValidate?: (errors: readonly JsonFormValidationError[]) => void;\n /** Optional CSS class for the outer container. */\n className?: string;\n}\n\nexport function JsonEditor(props: JsonEditorProps) {\n const {\n schema,\n value,\n onChange,\n theme,\n surface,\n density = 'comfortable',\n validate,\n onValidate,\n className,\n } = props;\n const { style } = useJsonEditorTokens(theme, surface);\n\n // No onChange → fully inert (still validates if a validator is supplied).\n const handleChange = onChange ?? (() => {});\n\n const cls =\n 'squisq-jsonform' +\n (density === 'compact' ? ' squisq-jsonform--compact' : '') +\n (className ? ` ${className}` : '');\n\n return (\n <div className={cls} style={style}>\n <JsonEditorProvider\n rootSchema={schema}\n rootData={value}\n onRootChange={handleChange}\n density={density}\n validate={validate}\n onValidate={onValidate}\n >\n <RenderNode value={value} schema={schema} pointer=\"\" parentDisabled={!onChange} />\n </JsonEditorProvider>\n </div>\n );\n}\n","/**\n * RecorderButton — drop-in button that opens the {@link RecorderModal}\n * in a portal anchored to `document.body`. Convenience wrapper for\n * hosts that don't need to manage modal open/close state themselves.\n *\n * Mirrors the consumption pattern of `VideoExportButton` in\n * `@bendyline/squisq-video-react`.\n */\n\nimport { useCallback, useState, type CSSProperties } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { MediaProvider } from '@bendyline/squisq/schemas';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { RecorderModal, type RecorderSaveResult } from './RecorderModal.js';\nimport type { RecorderSource } from './hooks/useMediaRecorder.js';\n\nexport interface RecorderButtonProps {\n /** Where to write the resulting recording. Required. */\n mediaProvider: MediaProvider;\n /** Optional container for narration `.timing.json` sidecar writes. */\n container?: ContentContainer | null;\n /** Initial capture source. Defaults to `'mic'`. */\n initialMode?: RecorderSource;\n /** Fired after a successful save. */\n onSave?: (result: RecorderSaveResult) => void;\n /** Button label. Defaults to `'Record'`. */\n label?: string;\n /** Optional inline button styles. */\n style?: CSSProperties;\n /** Whether the button is disabled. */\n disabled?: boolean;\n}\n\nexport function RecorderButton({\n mediaProvider,\n container = null,\n initialMode = 'mic',\n onSave,\n label = 'Record',\n style,\n disabled,\n}: RecorderButtonProps) {\n const [open, setOpen] = useState(false);\n const handleOpen = useCallback(() => setOpen(true), []);\n const handleClose = useCallback(() => setOpen(false), []);\n const handleSave = useCallback(\n (result: RecorderSaveResult) => {\n onSave?.(result);\n },\n [onSave],\n );\n\n return (\n <>\n <button type=\"button\" onClick={handleOpen} style={style} disabled={disabled}>\n {label}\n </button>\n {open &&\n typeof document !== 'undefined' &&\n createPortal(\n <RecorderModal\n mediaProvider={mediaProvider}\n container={container}\n initialMode={initialMode}\n onClose={handleClose}\n onSave={handleSave}\n />,\n document.body,\n )}\n </>\n );\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","useCallback","useMemo","useState","useRef","useEffect","e","textMatch","jsx","useState","useEffect","useRef","useCallback","useEffect","useMemo","useRef","useState","useCallback","useEffect","useMemo","useRef","useState","useEffect","useState","jsx","jsxs","useState","useRef","useCallback","useEffect","e","useMemo","useCallback","useCallback","useState","createPortal","useCallback","useEffect","useRef","useState","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","e","useEffect","useEffect","jsx","jsxs","useState","useRef","useEffect","useCallback","e","Fragment","jsx","jsxs","useState","useCallback","createPortal","jsx","useCallback","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","e","useCallback","parseMarkdown","useCallback","useEffect","useRef","useState","jsx","jsxs","e","useCallback","useEffect","useMemo","useRef","useState","parseMarkdown","useCallback","useEffect","useMemo","useRef","useState","createPortal","Fragment","jsx","jsxs","e","jsx","jsxs","useMemo","parseMarkdown","useState","useRef","useEffect","e","useCallback","useEffect","useMemo","useRef","useState","e","jsx","jsxs","useState","useRef","useEffect","e","useMemo","createPortal","Fragment","jsx","jsxs","useRef","useState","useCallback","useEffect","e","useMemo","useMemo","jsx","jsxs","useMemo","useRef","useCallback","useEffect","resolveIcon","jsx","useRef","useEffect","useCallback","e","resolveIcon","useEffect","useMemo","useRef","useState","resolveFontFamily","FONT_FALLBACKS","command","range","commands","originalCreateParagraphNear","originalDeleteSelection","originalExitCode","mark","ProseMirrorNode","Fragment","e","originalJoinUp","originalJoinDown","originalJoinBackward","originalJoinForward","originalCommand","originalLift","originalLiftEmptyBlock","originalLiftListItem","originalNewlineInCode","originalSelectNodeBackward","originalSelectNodeForward","originalSelectParentNode","originalSelectTextblockEnd","originalSelectTextblockStart","document","range","commands","originalSinkListItem","first","Fragment","newNextTypeAttributes","nextType","originalWrapIn","originalWrapInList","e","tr","commands","useEffect","useRef","useState","Image","Fragment","jsx","jsxs","updateAttributes","useState","useRef","useEffect","e","Image","NodeViewWrapper","ReactNodeViewRenderer","useEffect","useState","useState","useEffect","jsx","NodeViewWrapper","ReactNodeViewRenderer","commands","NodeViewWrapper","ReactNodeViewRenderer","jsx","NodeViewWrapper","ReactNodeViewRenderer","commands","profileBlockContents","recommendTemplatesForBlock","PluginKey","command","createContext","useCallback","useContext","useState","useMemo","useEffect","useRef","getThemeSummaries","resolveTheme","getTransformStyleSummaries","setFrontmatterValues","Fragment","jsx","jsxs","createContext","useContext","getThemeSummaries","getTransformStyleSummaries","useCallback","setFrontmatterValues","useMemo","useState","useEffect","resolveTheme","labelStyle","e","useRef","useEditor","jsx","jsxs","useRef","useEffect","useMemo","useState","e","resolveFontFamily","FONT_FALLBACKS","profileBlockContents","recommendTemplatesForBlock","useMemo","useRef","useState","VIEWPORT_PRESETS","flattenBlocks","hasTemplate","useCallback","useEffect","useMemo","useState","useMemo","useState","useEffect","monacoRoot","useCallback","Fragment","jsx","jsxs","hasTemplate","first","VIEWPORT_PRESETS","useRef","useMemo","flattenBlocks","e","useState","useCallback","useEffect","useMemo","useRef","useState","flattenBlocks","hasTemplate","extractPlainText","jsx","jsxs","useRef","useCallback","extractPlainText","hasTemplate","useMemo","flattenBlocks","useState","useEffect","useState","useEffect","flattenBlocks","hasTemplate","extractPlainText","getChildren","parseDim","extractBlockImages","extractListItems","getTemplateDefaults","useEffect","useMemo","useState","parseMarkdown","jsx","useMemo","parseMarkdown","useState","useEffect","jsx","jsxs","useState","useEffect","useCallback","useEffect","useRef","useState","Fragment","jsx","jsxs","e","useCallback","useState","exportImageEditDoc","useCallback","useEffect","useRef","useState","useEffect","useState","jsx","jsx","jsx","jsx","jsxs","e","jsx","jsxs","useRef","useState","useCallback","e","useEffect","useCallback","useEffect","useRef","useState","jsx","jsxs","setMeta","e","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","setCanvas","setContent","e","useRef","useState","useEffect","jsx","jsxs","Toolbar","useRef","e","useState","useEffect","useCallback","useEffect","useMemo","useReducer","useRef","useState","useReducer","useState","useRef","useEffect","useCallback","useMemo","e","useMemo","resolveFontFamily","DEFAULT_THEME","jsx","jsxs","useState","useCallback","exportImageEditDoc","Toolbar","useState","useEffect","useRef","useCallback","jsx","jsxs","useState","useRef","useEffect","useCallback","e","useState","Fragment","jsx","jsxs","e","useEffect","useRef","useState","createPortal","jsx","e","useCallback","useEffect","useRef","useState","e","stringifyMarkdown","stringifyMarkdown","Fragment","jsx","jsxs","useMemo","useState","useRef","useCallback","useEffect","e","jsx","jsxs","VIEWS","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","e","createContext","useContext","useMemo","jsx","e","value","useEffect","useRef","useState","useEffect","useRef","useEditor","EditorContent","StarterKit","Table","TableRow","TableCell","TableHeader","TaskList","TaskItem","Placeholder","jsx","useRef","useEditor","StarterKit","Table","TableRow","TableCell","TableHeader","TaskList","TaskItem","Placeholder","useEffect","EditorContent","jsx","jsxs","e","useRef","useEffect","useState","jsx","jsxs","Editor","useMemo","applySurface","resolveFontFamily","DEFAULT_THEME","DARK_SURFACE","LIGHT_SURFACE","jsx","useCallback","useState","createPortal","Fragment","jsx","jsxs","useState","useCallback","createPortal"]}