@bendyline/squisq-editor-react 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (446) hide show
  1. package/dist/DocumentSettingsDialog.d.ts +26 -0
  2. package/dist/DocumentSettingsDialog.d.ts.map +1 -0
  3. package/dist/DocumentSettingsDialog.js +115 -0
  4. package/dist/DocumentSettingsDialog.js.map +1 -0
  5. package/dist/EditorContext.d.ts +248 -4
  6. package/dist/EditorContext.d.ts.map +1 -1
  7. package/dist/EditorContext.js +248 -10
  8. package/dist/EditorContext.js.map +1 -1
  9. package/dist/EditorShell.d.ts +173 -4
  10. package/dist/EditorShell.d.ts.map +1 -1
  11. package/dist/EditorShell.js +110 -10
  12. package/dist/EditorShell.js.map +1 -1
  13. package/dist/EmojiPicker.d.ts +50 -0
  14. package/dist/EmojiPicker.d.ts.map +1 -0
  15. package/dist/EmojiPicker.js +182 -0
  16. package/dist/EmojiPicker.js.map +1 -0
  17. package/dist/ImageEditor.d.ts +68 -0
  18. package/dist/ImageEditor.d.ts.map +1 -0
  19. package/dist/ImageEditor.js +166 -0
  20. package/dist/ImageEditor.js.map +1 -0
  21. package/dist/ImageNodeView.d.ts +13 -1
  22. package/dist/ImageNodeView.d.ts.map +1 -1
  23. package/dist/ImageNodeView.js +172 -19
  24. package/dist/ImageNodeView.js.map +1 -1
  25. package/dist/ImageViewer.d.ts +26 -0
  26. package/dist/ImageViewer.d.ts.map +1 -0
  27. package/dist/ImageViewer.js +119 -0
  28. package/dist/ImageViewer.js.map +1 -0
  29. package/dist/InlineIcon.d.ts +17 -0
  30. package/dist/InlineIcon.d.ts.map +1 -0
  31. package/dist/InlineIcon.js +72 -0
  32. package/dist/InlineIcon.js.map +1 -0
  33. package/dist/InlinePreviewGutter.d.ts +52 -0
  34. package/dist/InlinePreviewGutter.d.ts.map +1 -0
  35. package/dist/InlinePreviewGutter.js +397 -0
  36. package/dist/InlinePreviewGutter.js.map +1 -0
  37. package/dist/LinkDialog.d.ts +43 -0
  38. package/dist/LinkDialog.d.ts.map +1 -0
  39. package/dist/LinkDialog.js +102 -0
  40. package/dist/LinkDialog.js.map +1 -0
  41. package/dist/MentionExtension.js +10 -7
  42. package/dist/MentionExtension.js.map +1 -1
  43. package/dist/OutlinePanel.d.ts +17 -0
  44. package/dist/OutlinePanel.d.ts.map +1 -0
  45. package/dist/OutlinePanel.js +167 -0
  46. package/dist/OutlinePanel.js.map +1 -0
  47. package/dist/PlainHtmlPreview.d.ts +50 -0
  48. package/dist/PlainHtmlPreview.d.ts.map +1 -0
  49. package/dist/PlainHtmlPreview.js +155 -0
  50. package/dist/PlainHtmlPreview.js.map +1 -0
  51. package/dist/PreviewControls.d.ts +15 -1
  52. package/dist/PreviewControls.d.ts.map +1 -1
  53. package/dist/PreviewControls.js +75 -18
  54. package/dist/PreviewControls.js.map +1 -1
  55. package/dist/PreviewPanel.d.ts +11 -10
  56. package/dist/PreviewPanel.d.ts.map +1 -1
  57. package/dist/PreviewPanel.js +20 -17
  58. package/dist/PreviewPanel.js.map +1 -1
  59. package/dist/RawEditor.d.ts.map +1 -1
  60. package/dist/RawEditor.js +198 -4
  61. package/dist/RawEditor.js.map +1 -1
  62. package/dist/RecorderEntry.d.ts +24 -0
  63. package/dist/RecorderEntry.d.ts.map +1 -0
  64. package/dist/RecorderEntry.js +139 -0
  65. package/dist/RecorderEntry.js.map +1 -0
  66. package/dist/TemplateAnnotation.d.ts.map +1 -1
  67. package/dist/TemplateAnnotation.js +32 -6
  68. package/dist/TemplateAnnotation.js.map +1 -1
  69. package/dist/TemplatePicker.d.ts +53 -0
  70. package/dist/TemplatePicker.d.ts.map +1 -0
  71. package/dist/TemplatePicker.js +388 -0
  72. package/dist/TemplatePicker.js.map +1 -0
  73. package/dist/ThemeCustomizerPanel.d.ts +32 -0
  74. package/dist/ThemeCustomizerPanel.d.ts.map +1 -0
  75. package/dist/ThemeCustomizerPanel.js +256 -0
  76. package/dist/ThemeCustomizerPanel.js.map +1 -0
  77. package/dist/ThemePicker.d.ts +33 -0
  78. package/dist/ThemePicker.d.ts.map +1 -0
  79. package/dist/ThemePicker.js +148 -0
  80. package/dist/ThemePicker.js.map +1 -0
  81. package/dist/Toolbar.d.ts.map +1 -1
  82. package/dist/Toolbar.js +508 -33
  83. package/dist/Toolbar.js.map +1 -1
  84. package/dist/VersionHistoryPanel.d.ts +14 -0
  85. package/dist/VersionHistoryPanel.d.ts.map +1 -0
  86. package/dist/VersionHistoryPanel.js +147 -0
  87. package/dist/VersionHistoryPanel.js.map +1 -0
  88. package/dist/ViewMenuPanel.d.ts +13 -0
  89. package/dist/ViewMenuPanel.d.ts.map +1 -0
  90. package/dist/ViewMenuPanel.js +58 -0
  91. package/dist/ViewMenuPanel.js.map +1 -0
  92. package/dist/WysiwygEditor.d.ts.map +1 -1
  93. package/dist/WysiwygEditor.js +198 -9
  94. package/dist/WysiwygEditor.js.map +1 -1
  95. package/dist/__tests__/detectMarkdown.test.js +0 -14
  96. package/dist/__tests__/detectMarkdown.test.js.map +1 -1
  97. package/dist/__tests__/documentSettingsDialog.test.d.ts +2 -0
  98. package/dist/__tests__/documentSettingsDialog.test.d.ts.map +1 -0
  99. package/dist/__tests__/documentSettingsDialog.test.js +132 -0
  100. package/dist/__tests__/documentSettingsDialog.test.js.map +1 -0
  101. package/dist/__tests__/emojiPicker.test.d.ts +2 -0
  102. package/dist/__tests__/emojiPicker.test.d.ts.map +1 -0
  103. package/dist/__tests__/emojiPicker.test.js +111 -0
  104. package/dist/__tests__/emojiPicker.test.js.map +1 -0
  105. package/dist/__tests__/fileKind.test.js +13 -0
  106. package/dist/__tests__/fileKind.test.js.map +1 -1
  107. package/dist/__tests__/imageEditAffordance.test.d.ts +2 -0
  108. package/dist/__tests__/imageEditAffordance.test.d.ts.map +1 -0
  109. package/dist/__tests__/imageEditAffordance.test.js +188 -0
  110. package/dist/__tests__/imageEditAffordance.test.js.map +1 -0
  111. package/dist/__tests__/imageEditorShell.test.d.ts +2 -0
  112. package/dist/__tests__/imageEditorShell.test.d.ts.map +1 -0
  113. package/dist/__tests__/imageEditorShell.test.js +52 -0
  114. package/dist/__tests__/imageEditorShell.test.js.map +1 -0
  115. package/dist/__tests__/imageEditorState.test.d.ts +3 -0
  116. package/dist/__tests__/imageEditorState.test.d.ts.map +1 -0
  117. package/dist/__tests__/imageEditorState.test.js +148 -0
  118. package/dist/__tests__/imageEditorState.test.js.map +1 -0
  119. package/dist/__tests__/inlinePreviewGutter.test.d.ts +2 -0
  120. package/dist/__tests__/inlinePreviewGutter.test.d.ts.map +1 -0
  121. package/dist/__tests__/inlinePreviewGutter.test.js +51 -0
  122. package/dist/__tests__/inlinePreviewGutter.test.js.map +1 -0
  123. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts +2 -0
  124. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts.map +1 -0
  125. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js +63 -0
  126. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js.map +1 -0
  127. package/dist/__tests__/jsonEditor.test.d.ts +2 -0
  128. package/dist/__tests__/jsonEditor.test.d.ts.map +1 -0
  129. package/dist/__tests__/jsonEditor.test.js +134 -0
  130. package/dist/__tests__/jsonEditor.test.js.map +1 -0
  131. package/dist/__tests__/layersPanel.test.d.ts +2 -0
  132. package/dist/__tests__/layersPanel.test.d.ts.map +1 -0
  133. package/dist/__tests__/layersPanel.test.js +84 -0
  134. package/dist/__tests__/layersPanel.test.js.map +1 -0
  135. package/dist/__tests__/linkDialogDocPicker.test.d.ts +7 -0
  136. package/dist/__tests__/linkDialogDocPicker.test.d.ts.map +1 -0
  137. package/dist/__tests__/linkDialogDocPicker.test.js +75 -0
  138. package/dist/__tests__/linkDialogDocPicker.test.js.map +1 -0
  139. package/dist/__tests__/outlinePanel.test.d.ts +2 -0
  140. package/dist/__tests__/outlinePanel.test.d.ts.map +1 -0
  141. package/dist/__tests__/outlinePanel.test.js +68 -0
  142. package/dist/__tests__/outlinePanel.test.js.map +1 -0
  143. package/dist/__tests__/plainHtmlPreview.test.d.ts +2 -0
  144. package/dist/__tests__/plainHtmlPreview.test.d.ts.map +1 -0
  145. package/dist/__tests__/plainHtmlPreview.test.js +87 -0
  146. package/dist/__tests__/plainHtmlPreview.test.js.map +1 -0
  147. package/dist/__tests__/propertiesPanel.test.d.ts +2 -0
  148. package/dist/__tests__/propertiesPanel.test.d.ts.map +1 -0
  149. package/dist/__tests__/propertiesPanel.test.js +64 -0
  150. package/dist/__tests__/propertiesPanel.test.js.map +1 -0
  151. package/dist/__tests__/recorderFormats.test.d.ts +2 -0
  152. package/dist/__tests__/recorderFormats.test.d.ts.map +1 -0
  153. package/dist/__tests__/recorderFormats.test.js +121 -0
  154. package/dist/__tests__/recorderFormats.test.js.map +1 -0
  155. package/dist/__tests__/recorderTimingJson.test.d.ts +2 -0
  156. package/dist/__tests__/recorderTimingJson.test.d.ts.map +1 -0
  157. package/dist/__tests__/recorderTimingJson.test.js +37 -0
  158. package/dist/__tests__/recorderTimingJson.test.js.map +1 -0
  159. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts +2 -0
  160. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts.map +1 -0
  161. package/dist/__tests__/templateAnnotationRoundTrip.test.js +31 -0
  162. package/dist/__tests__/templateAnnotationRoundTrip.test.js.map +1 -0
  163. package/dist/__tests__/tiptapBridge.test.js +13 -0
  164. package/dist/__tests__/tiptapBridge.test.js.map +1 -1
  165. package/dist/__tests__/useImageEditor.test.d.ts +2 -0
  166. package/dist/__tests__/useImageEditor.test.d.ts.map +1 -0
  167. package/dist/__tests__/useImageEditor.test.js +131 -0
  168. package/dist/__tests__/useImageEditor.test.js.map +1 -0
  169. package/dist/__tests__/useMediaRecorder.test.d.ts +2 -0
  170. package/dist/__tests__/useMediaRecorder.test.d.ts.map +1 -0
  171. package/dist/__tests__/useMediaRecorder.test.js +153 -0
  172. package/dist/__tests__/useMediaRecorder.test.js.map +1 -0
  173. package/dist/__tests__/versionHistory.test.d.ts +2 -0
  174. package/dist/__tests__/versionHistory.test.d.ts.map +1 -0
  175. package/dist/__tests__/versionHistory.test.js +124 -0
  176. package/dist/__tests__/versionHistory.test.js.map +1 -0
  177. package/dist/blockSlice.d.ts +24 -0
  178. package/dist/blockSlice.d.ts.map +1 -0
  179. package/dist/blockSlice.js +63 -0
  180. package/dist/blockSlice.js.map +1 -0
  181. package/dist/buildPreviewDoc.d.ts.map +1 -1
  182. package/dist/buildPreviewDoc.js +52 -2
  183. package/dist/buildPreviewDoc.js.map +1 -1
  184. package/dist/emojiData.d.ts +81 -0
  185. package/dist/emojiData.d.ts.map +1 -0
  186. package/dist/emojiData.js +1283 -0
  187. package/dist/emojiData.js.map +1 -0
  188. package/dist/fileKind.d.ts +6 -2
  189. package/dist/fileKind.d.ts.map +1 -1
  190. package/dist/fileKind.js +25 -4
  191. package/dist/fileKind.js.map +1 -1
  192. package/dist/hooks/useFileDrop.d.ts.map +1 -1
  193. package/dist/hooks/useFileDrop.js +40 -4
  194. package/dist/hooks/useFileDrop.js.map +1 -1
  195. package/dist/imageEditor/CanvasSurface.d.ts +31 -0
  196. package/dist/imageEditor/CanvasSurface.d.ts.map +1 -0
  197. package/dist/imageEditor/CanvasSurface.js +264 -0
  198. package/dist/imageEditor/CanvasSurface.js.map +1 -0
  199. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts +39 -0
  200. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts.map +1 -0
  201. package/dist/imageEditor/ImageVersionHistoryDropdown.js +283 -0
  202. package/dist/imageEditor/ImageVersionHistoryDropdown.js.map +1 -0
  203. package/dist/imageEditor/LayersPanel.d.ts +14 -0
  204. package/dist/imageEditor/LayersPanel.d.ts.map +1 -0
  205. package/dist/imageEditor/LayersPanel.js +43 -0
  206. package/dist/imageEditor/LayersPanel.js.map +1 -0
  207. package/dist/imageEditor/PropertiesPanel.d.ts +14 -0
  208. package/dist/imageEditor/PropertiesPanel.d.ts.map +1 -0
  209. package/dist/imageEditor/PropertiesPanel.js +97 -0
  210. package/dist/imageEditor/PropertiesPanel.js.map +1 -0
  211. package/dist/imageEditor/Toolbar.d.ts +30 -0
  212. package/dist/imageEditor/Toolbar.d.ts.map +1 -0
  213. package/dist/imageEditor/Toolbar.js +108 -0
  214. package/dist/imageEditor/Toolbar.js.map +1 -0
  215. package/dist/imageEditor/icons.d.ts +24 -0
  216. package/dist/imageEditor/icons.d.ts.map +1 -0
  217. package/dist/imageEditor/icons.js +45 -0
  218. package/dist/imageEditor/icons.js.map +1 -0
  219. package/dist/imageEditor/layers/EditorImageLayer.d.ts +16 -0
  220. package/dist/imageEditor/layers/EditorImageLayer.d.ts.map +1 -0
  221. package/dist/imageEditor/layers/EditorImageLayer.js +37 -0
  222. package/dist/imageEditor/layers/EditorImageLayer.js.map +1 -0
  223. package/dist/imageEditor/layers/EditorShapeLayer.d.ts +15 -0
  224. package/dist/imageEditor/layers/EditorShapeLayer.d.ts.map +1 -0
  225. package/dist/imageEditor/layers/EditorShapeLayer.js +20 -0
  226. package/dist/imageEditor/layers/EditorShapeLayer.js.map +1 -0
  227. package/dist/imageEditor/layers/EditorTextLayer.d.ts +18 -0
  228. package/dist/imageEditor/layers/EditorTextLayer.d.ts.map +1 -0
  229. package/dist/imageEditor/layers/EditorTextLayer.js +13 -0
  230. package/dist/imageEditor/layers/EditorTextLayer.js.map +1 -0
  231. package/dist/imageEditor/layers/SelectionHandles.d.ts +17 -0
  232. package/dist/imageEditor/layers/SelectionHandles.d.ts.map +1 -0
  233. package/dist/imageEditor/layers/SelectionHandles.js +19 -0
  234. package/dist/imageEditor/layers/SelectionHandles.js.map +1 -0
  235. package/dist/imageEditor/state.d.ts +76 -0
  236. package/dist/imageEditor/state.d.ts.map +1 -0
  237. package/dist/imageEditor/state.js +87 -0
  238. package/dist/imageEditor/state.js.map +1 -0
  239. package/dist/imageEditor/useImageEditor.d.ts +53 -0
  240. package/dist/imageEditor/useImageEditor.d.ts.map +1 -0
  241. package/dist/imageEditor/useImageEditor.js +244 -0
  242. package/dist/imageEditor/useImageEditor.js.map +1 -0
  243. package/dist/imageEditor/useImageEditorTokens.d.ts +16 -0
  244. package/dist/imageEditor/useImageEditorTokens.d.ts.map +1 -0
  245. package/dist/imageEditor/useImageEditorTokens.js +45 -0
  246. package/dist/imageEditor/useImageEditorTokens.js.map +1 -0
  247. package/dist/index.d.ts +48 -1
  248. package/dist/index.d.ts.map +1 -1
  249. package/dist/index.js +36 -0
  250. package/dist/index.js.map +1 -1
  251. package/dist/jsonEditor/EmbeddedRichTextField.d.ts +15 -0
  252. package/dist/jsonEditor/EmbeddedRichTextField.d.ts.map +1 -0
  253. package/dist/jsonEditor/EmbeddedRichTextField.js +74 -0
  254. package/dist/jsonEditor/EmbeddedRichTextField.js.map +1 -0
  255. package/dist/jsonEditor/JsonEditor.d.ts +36 -0
  256. package/dist/jsonEditor/JsonEditor.d.ts.map +1 -0
  257. package/dist/jsonEditor/JsonEditor.js +15 -0
  258. package/dist/jsonEditor/JsonEditor.js.map +1 -0
  259. package/dist/jsonEditor/JsonEditorContext.d.ts +28 -0
  260. package/dist/jsonEditor/JsonEditorContext.d.ts.map +1 -0
  261. package/dist/jsonEditor/JsonEditorContext.js +41 -0
  262. package/dist/jsonEditor/JsonEditorContext.js.map +1 -0
  263. package/dist/jsonEditor/RenderNode.d.ts +16 -0
  264. package/dist/jsonEditor/RenderNode.d.ts.map +1 -0
  265. package/dist/jsonEditor/RenderNode.js +32 -0
  266. package/dist/jsonEditor/RenderNode.js.map +1 -0
  267. package/dist/jsonEditor/editors.d.ts +36 -0
  268. package/dist/jsonEditor/editors.d.ts.map +1 -0
  269. package/dist/jsonEditor/editors.js +347 -0
  270. package/dist/jsonEditor/editors.js.map +1 -0
  271. package/dist/jsonEditor/index.d.ts +3 -0
  272. package/dist/jsonEditor/index.d.ts.map +1 -0
  273. package/dist/jsonEditor/index.js +2 -0
  274. package/dist/jsonEditor/index.js.map +1 -0
  275. package/dist/jsonEditor/useJsonEditorTokens.d.ts +13 -0
  276. package/dist/jsonEditor/useJsonEditorTokens.d.ts.map +1 -0
  277. package/dist/jsonEditor/useJsonEditorTokens.js +38 -0
  278. package/dist/jsonEditor/useJsonEditorTokens.js.map +1 -0
  279. package/dist/recorder/RecorderButton.d.ts +31 -0
  280. package/dist/recorder/RecorderButton.d.ts.map +1 -0
  281. package/dist/recorder/RecorderButton.js +24 -0
  282. package/dist/recorder/RecorderButton.js.map +1 -0
  283. package/dist/recorder/RecorderModal.d.ts +59 -0
  284. package/dist/recorder/RecorderModal.d.ts.map +1 -0
  285. package/dist/recorder/RecorderModal.js +333 -0
  286. package/dist/recorder/RecorderModal.js.map +1 -0
  287. package/dist/recorder/RecorderPanel.d.ts +25 -0
  288. package/dist/recorder/RecorderPanel.d.ts.map +1 -0
  289. package/dist/recorder/RecorderPanel.js +30 -0
  290. package/dist/recorder/RecorderPanel.js.map +1 -0
  291. package/dist/recorder/formats.d.ts +51 -0
  292. package/dist/recorder/formats.d.ts.map +1 -0
  293. package/dist/recorder/formats.js +144 -0
  294. package/dist/recorder/formats.js.map +1 -0
  295. package/dist/recorder/hooks/useMediaRecorder.d.ts +90 -0
  296. package/dist/recorder/hooks/useMediaRecorder.d.ts.map +1 -0
  297. package/dist/recorder/hooks/useMediaRecorder.js +277 -0
  298. package/dist/recorder/hooks/useMediaRecorder.js.map +1 -0
  299. package/dist/recorder/hooks/useStreamPreview.d.ts +22 -0
  300. package/dist/recorder/hooks/useStreamPreview.d.ts.map +1 -0
  301. package/dist/recorder/hooks/useStreamPreview.js +44 -0
  302. package/dist/recorder/hooks/useStreamPreview.js.map +1 -0
  303. package/dist/recorder/sources/cameraStream.d.ts +22 -0
  304. package/dist/recorder/sources/cameraStream.d.ts.map +1 -0
  305. package/dist/recorder/sources/cameraStream.js +24 -0
  306. package/dist/recorder/sources/cameraStream.js.map +1 -0
  307. package/dist/recorder/sources/micStream.d.ts +15 -0
  308. package/dist/recorder/sources/micStream.d.ts.map +1 -0
  309. package/dist/recorder/sources/micStream.js +24 -0
  310. package/dist/recorder/sources/micStream.js.map +1 -0
  311. package/dist/recorder/sources/screenStream.d.ts +53 -0
  312. package/dist/recorder/sources/screenStream.d.ts.map +1 -0
  313. package/dist/recorder/sources/screenStream.js +114 -0
  314. package/dist/recorder/sources/screenStream.js.map +1 -0
  315. package/dist/recorder/timingJson.d.ts +51 -0
  316. package/dist/recorder/timingJson.d.ts.map +1 -0
  317. package/dist/recorder/timingJson.js +42 -0
  318. package/dist/recorder/timingJson.js.map +1 -0
  319. package/dist/tiptap/TiptapAudio.d.ts +26 -0
  320. package/dist/tiptap/TiptapAudio.d.ts.map +1 -0
  321. package/dist/tiptap/TiptapAudio.js +58 -0
  322. package/dist/tiptap/TiptapAudio.js.map +1 -0
  323. package/dist/tiptap/TiptapVideo.d.ts +30 -0
  324. package/dist/tiptap/TiptapVideo.d.ts.map +1 -0
  325. package/dist/tiptap/TiptapVideo.js +66 -0
  326. package/dist/tiptap/TiptapVideo.js.map +1 -0
  327. package/dist/tiptap/useResolvedMediaSrc.d.ts +2 -0
  328. package/dist/tiptap/useResolvedMediaSrc.d.ts.map +1 -0
  329. package/dist/tiptap/useResolvedMediaSrc.js +42 -0
  330. package/dist/tiptap/useResolvedMediaSrc.js.map +1 -0
  331. package/dist/tiptapBridge.d.ts.map +1 -1
  332. package/dist/tiptapBridge.js +171 -14
  333. package/dist/tiptapBridge.js.map +1 -1
  334. package/dist/useHeadingLayout.d.ts +54 -0
  335. package/dist/useHeadingLayout.d.ts.map +1 -0
  336. package/dist/useHeadingLayout.js +260 -0
  337. package/dist/useHeadingLayout.js.map +1 -0
  338. package/dist/utils/collectInlineFontAwesomeCss.d.ts +21 -0
  339. package/dist/utils/collectInlineFontAwesomeCss.d.ts.map +1 -0
  340. package/dist/utils/collectInlineFontAwesomeCss.js +68 -0
  341. package/dist/utils/collectInlineFontAwesomeCss.js.map +1 -0
  342. package/dist/utils/dropUtils.d.ts +21 -2
  343. package/dist/utils/dropUtils.d.ts.map +1 -1
  344. package/dist/utils/dropUtils.js +43 -4
  345. package/dist/utils/dropUtils.js.map +1 -1
  346. package/dist/utils/normalizeMalformedAssetUrl.d.ts +15 -0
  347. package/dist/utils/normalizeMalformedAssetUrl.d.ts.map +1 -0
  348. package/dist/utils/normalizeMalformedAssetUrl.js +27 -0
  349. package/dist/utils/normalizeMalformedAssetUrl.js.map +1 -0
  350. package/package.json +8 -5
  351. package/src/DocumentSettingsDialog.tsx +266 -0
  352. package/src/EditorContext.tsx +534 -10
  353. package/src/EditorShell.tsx +571 -55
  354. package/src/EmojiPicker.tsx +332 -0
  355. package/src/ImageEditor.tsx +327 -0
  356. package/src/ImageNodeView.tsx +222 -21
  357. package/src/ImageViewer.tsx +221 -0
  358. package/src/InlineIcon.ts +84 -0
  359. package/src/InlinePreviewGutter.tsx +582 -0
  360. package/src/LinkDialog.tsx +276 -0
  361. package/src/MentionExtension.tsx +10 -7
  362. package/src/OutlinePanel.tsx +295 -0
  363. package/src/PlainHtmlPreview.tsx +211 -0
  364. package/src/PreviewControls.tsx +130 -24
  365. package/src/PreviewPanel.tsx +38 -21
  366. package/src/RawEditor.tsx +215 -4
  367. package/src/RecorderEntry.tsx +164 -0
  368. package/src/TemplateAnnotation.ts +32 -6
  369. package/src/TemplatePicker.tsx +818 -0
  370. package/src/ThemeCustomizerPanel.tsx +595 -0
  371. package/src/ThemePicker.tsx +319 -0
  372. package/src/Toolbar.tsx +708 -111
  373. package/src/VersionHistoryPanel.tsx +329 -0
  374. package/src/ViewMenuPanel.tsx +188 -0
  375. package/src/WysiwygEditor.tsx +229 -9
  376. package/src/__tests__/detectMarkdown.test.ts +0 -15
  377. package/src/__tests__/documentSettingsDialog.test.tsx +147 -0
  378. package/src/__tests__/emojiPicker.test.tsx +133 -0
  379. package/src/__tests__/fileKind.test.ts +16 -0
  380. package/src/__tests__/imageEditAffordance.test.tsx +268 -0
  381. package/src/__tests__/imageEditorShell.test.tsx +57 -0
  382. package/src/__tests__/imageEditorState.test.ts +171 -0
  383. package/src/__tests__/inlinePreviewGutter.test.tsx +62 -0
  384. package/src/__tests__/inlinePreviewGutterAllBlocks.test.tsx +103 -0
  385. package/src/__tests__/jsonEditor.test.tsx +168 -0
  386. package/src/__tests__/layersPanel.test.tsx +97 -0
  387. package/src/__tests__/linkDialogDocPicker.test.tsx +137 -0
  388. package/src/__tests__/outlinePanel.test.tsx +79 -0
  389. package/src/__tests__/plainHtmlPreview.test.tsx +107 -0
  390. package/src/__tests__/propertiesPanel.test.tsx +69 -0
  391. package/src/__tests__/recorderFormats.test.ts +146 -0
  392. package/src/__tests__/recorderTimingJson.test.ts +41 -0
  393. package/src/__tests__/templateAnnotationRoundTrip.test.ts +34 -0
  394. package/src/__tests__/tiptapBridge.test.ts +15 -0
  395. package/src/__tests__/useImageEditor.test.tsx +159 -0
  396. package/src/__tests__/useMediaRecorder.test.ts +186 -0
  397. package/src/__tests__/versionHistory.test.tsx +197 -0
  398. package/src/blockSlice.ts +75 -0
  399. package/src/buildPreviewDoc.ts +61 -6
  400. package/src/emojiData.ts +1337 -0
  401. package/src/fileKind.ts +30 -6
  402. package/src/hooks/useFileDrop.ts +40 -4
  403. package/src/imageEditor/CanvasSurface.tsx +402 -0
  404. package/src/imageEditor/ImageVersionHistoryDropdown.tsx +396 -0
  405. package/src/imageEditor/LayersPanel.tsx +143 -0
  406. package/src/imageEditor/PropertiesPanel.tsx +428 -0
  407. package/src/imageEditor/Toolbar.tsx +242 -0
  408. package/src/imageEditor/icons.tsx +144 -0
  409. package/src/imageEditor/image-editor.css +450 -0
  410. package/src/imageEditor/layers/EditorImageLayer.tsx +45 -0
  411. package/src/imageEditor/layers/EditorShapeLayer.tsx +62 -0
  412. package/src/imageEditor/layers/EditorTextLayer.tsx +45 -0
  413. package/src/imageEditor/layers/SelectionHandles.tsx +86 -0
  414. package/src/imageEditor/state.ts +153 -0
  415. package/src/imageEditor/useImageEditor.ts +328 -0
  416. package/src/imageEditor/useImageEditorTokens.ts +70 -0
  417. package/src/index.ts +82 -0
  418. package/src/jsonEditor/EmbeddedRichTextField.tsx +81 -0
  419. package/src/jsonEditor/JsonEditor.tsx +81 -0
  420. package/src/jsonEditor/JsonEditorContext.tsx +75 -0
  421. package/src/jsonEditor/RenderNode.tsx +66 -0
  422. package/src/jsonEditor/editors.tsx +678 -0
  423. package/src/jsonEditor/index.ts +2 -0
  424. package/src/jsonEditor/json-editor.css +463 -0
  425. package/src/jsonEditor/useJsonEditorTokens.ts +63 -0
  426. package/src/recorder/RecorderButton.tsx +72 -0
  427. package/src/recorder/RecorderModal.tsx +596 -0
  428. package/src/recorder/RecorderPanel.tsx +93 -0
  429. package/src/recorder/formats.ts +159 -0
  430. package/src/recorder/hooks/useMediaRecorder.ts +378 -0
  431. package/src/recorder/hooks/useStreamPreview.ts +47 -0
  432. package/src/recorder/sources/cameraStream.ts +32 -0
  433. package/src/recorder/sources/micStream.ts +25 -0
  434. package/src/recorder/sources/screenStream.ts +162 -0
  435. package/src/recorder/timingJson.ts +66 -0
  436. package/src/styles/editor.css +2490 -51
  437. package/src/styles/image-edit-affordance.css +201 -0
  438. package/src/styles/index.css +10 -0
  439. package/src/tiptap/TiptapAudio.tsx +86 -0
  440. package/src/tiptap/TiptapVideo.tsx +119 -0
  441. package/src/tiptap/useResolvedMediaSrc.ts +47 -0
  442. package/src/tiptapBridge.ts +188 -20
  443. package/src/useHeadingLayout.ts +294 -0
  444. package/src/utils/collectInlineFontAwesomeCss.ts +69 -0
  445. package/src/utils/dropUtils.ts +54 -6
  446. package/src/utils/normalizeMalformedAssetUrl.ts +22 -0
@@ -21,6 +21,13 @@ import type { Doc, MediaProvider } from '@bendyline/squisq/schemas';
21
21
  import type { MarkdownDocument } from '@bendyline/squisq/markdown';
22
22
  import { parseMarkdown, stringifyMarkdown } from '@bendyline/squisq/markdown';
23
23
  import { markdownToDoc } from '@bendyline/squisq/doc';
24
+ import type { ContentContainer } from '@bendyline/squisq/storage';
25
+ import {
26
+ DocumentVersionManager,
27
+ type PrunePolicy,
28
+ type SaveVersionOptions,
29
+ type SaveVersionResult,
30
+ } from '@bendyline/squisq/versions';
24
31
  import type { Editor as TiptapEditor } from '@tiptap/core';
25
32
  import type { editor as MonacoEditorNs } from 'monaco-editor';
26
33
  import { markdownToTiptap } from './tiptapBridge';
@@ -55,16 +62,47 @@ export interface MentionCandidate {
55
62
  */
56
63
  export type MentionProvider = (query: string) => Promise<MentionCandidate[]>;
57
64
 
65
+ /**
66
+ * A document that the link dialog's "Browse documents" picker can offer.
67
+ * `path` is what lands in the markdown URL (typically relative to the
68
+ * current document so `home.md → resume.md` round-trips through file-
69
+ * system serializers). `label` is the human name shown in the list.
70
+ * `description` is an optional secondary line (e.g. workspace folder,
71
+ * last-modified date).
72
+ */
73
+ export interface DocumentLinkCandidate {
74
+ path: string;
75
+ label: string;
76
+ description?: string;
77
+ }
78
+
79
+ /**
80
+ * Resolves sibling / workspace document candidates for the link dialog.
81
+ * The editor itself has no notion of "neighbors" — hosts that organize
82
+ * docs in a workspace (e.g. docblocks) implement this to power the
83
+ * dialog's document picker. Pass `''` as the query for an initial list
84
+ * (the dialog calls it once on open); subsequent calls narrow by user
85
+ * input.
86
+ */
87
+ export type DocumentLinkProvider = (query: string) => Promise<DocumentLinkCandidate[]>;
88
+
58
89
  // ─── Types ───────────────────────────────────────────────
59
90
 
60
91
  export type EditorView = 'raw' | 'wysiwyg' | 'preview';
61
92
  export type EditorTheme = 'light' | 'dark';
93
+ /**
94
+ * How much of the active Squisq theme the WYSIWYG editing surface
95
+ * mirrors. `'fonts'` is the historical default — body and heading
96
+ * fonts only. `'fonts-colors'` also borrows the theme canvas / text
97
+ * colors. `'none'` opts out completely.
98
+ */
99
+ export type ThemeInheritance = 'none' | 'fonts' | 'fonts-colors';
62
100
  /**
63
101
  * Editor operating mode. `markdown` is the full experience (WYSIWYG +
64
102
  * Preview tabs, formatting toolbar). `code` is a Monaco-only view used
65
103
  * when the content represents a non-markdown file like `foo.ts`.
66
104
  */
67
- export type EditorMode = 'markdown' | 'code';
105
+ export type EditorMode = 'markdown' | 'code' | 'image';
68
106
 
69
107
  export interface EditorState {
70
108
  /** Raw markdown source string */
@@ -85,6 +123,62 @@ export interface EditorState {
85
123
  editorMode: EditorMode;
86
124
  /** Monaco language ID for the Raw editor. */
87
125
  language: string;
126
+ /**
127
+ * Whether the inline preview gutter (per-block card previews next to the
128
+ * WYSIWYG surface) is currently visible. Initialized from the EditorShell
129
+ * `inlinePreview` prop; the View menu in the toolbar can toggle it at
130
+ * runtime.
131
+ */
132
+ inlinePreviewVisible: boolean;
133
+ /**
134
+ * Whether the bottom status bar is currently visible. Initialized from
135
+ * the EditorShell `showStatusBar` prop (default true); the View menu in
136
+ * the toolbar can toggle it at runtime.
137
+ */
138
+ statusBarVisible: boolean;
139
+ /**
140
+ * Whether the left-side outline pane is currently visible. Initialized
141
+ * from the EditorShell `outline` prop (default false); the View menu in
142
+ * the toolbar can toggle it at runtime.
143
+ */
144
+ outlineVisible: boolean;
145
+ /**
146
+ * Whether inline block-template tags (the chip next to each templated
147
+ * heading in the WYSIWYG view, plus the subtle affordance chip on plain
148
+ * headings) are currently visible. Initialized from the EditorShell
149
+ * `blockTags` prop (default true); the View menu in the toolbar can
150
+ * toggle it at runtime.
151
+ */
152
+ blockTagsVisible: boolean;
153
+ /**
154
+ * How much of the active Squisq theme the WYSIWYG editing surface should
155
+ * inherit. `'none'` shows the default editor styling, `'fonts'` (the
156
+ * default) matches body and heading fonts only, and `'fonts-colors'`
157
+ * also borrows the theme's canvas / text colors so authors get a
158
+ * closer preview while editing.
159
+ */
160
+ themeInheritance: ThemeInheritance;
161
+ /**
162
+ * Relative path of an image the user requested to edit, or `null` when
163
+ * no editor is open. Surfaced by `<ImageNodeView>`'s hover affordance
164
+ * and consumed by `<EditorShell>` to render the modal `<ImageEditor>`.
165
+ */
166
+ imageEditTarget: string | null;
167
+ /**
168
+ * Monotonic counter bumped whenever a managed media asset is rewritten
169
+ * (e.g. after the image-editor modal saves back). Image render paths
170
+ * that cache resolved blob URLs should include this in their effect
171
+ * deps so the new bytes get picked up.
172
+ */
173
+ mediaRevision: number;
174
+ /**
175
+ * Whether the in-editor media recorder should be available. Defaults
176
+ * to true when a `mediaProvider` is wired; hosts that explicitly
177
+ * don't want the affordance (e.g. read-only embeds, surfaces where
178
+ * camera/screen prompts would be jarring) can pass `false` on the
179
+ * shell.
180
+ */
181
+ allowRecording: boolean;
88
182
  }
89
183
 
90
184
  export interface EditorActions {
@@ -100,10 +194,35 @@ export interface EditorActions {
100
194
  setMonacoEditor: (editor: MonacoEditor | null) => void;
101
195
  /** Set the color theme */
102
196
  setTheme: (theme: EditorTheme) => void;
197
+ /** Show or hide the inline preview gutter at runtime (driven by the View menu). */
198
+ setInlinePreviewVisible: (visible: boolean) => void;
199
+ /** Show or hide the bottom status bar at runtime (driven by the View menu). */
200
+ setStatusBarVisible: (visible: boolean) => void;
201
+ /** Show or hide the left-side outline pane at runtime (driven by the View menu). */
202
+ setOutlineVisible: (visible: boolean) => void;
203
+ /** Show or hide inline block-template tags at runtime (driven by the View menu). */
204
+ setBlockTagsVisible: (visible: boolean) => void;
205
+ /** Change how much of the active Squisq theme the WYSIWYG surface mirrors. */
206
+ setThemeInheritance: (mode: ThemeInheritance) => void;
103
207
  /** Insert text at the current cursor position in the active editor */
104
208
  insertAtCursor: (text: string) => void;
105
209
  /** Replace all editor content with the given text */
106
210
  replaceAll: (text: string) => void;
211
+ /**
212
+ * Request the modal image editor open on the given relative media path.
213
+ * The path must resolve through the active `mediaProvider`. No-op when
214
+ * no provider is wired — callers should hide the affordance in that
215
+ * case.
216
+ */
217
+ openImageEdit: (relativePath: string) => void;
218
+ /** Close the image editor modal without saving. */
219
+ closeImageEdit: () => void;
220
+ /**
221
+ * Bump `mediaRevision`. Called after the image editor writes back to
222
+ * the original media path so dependent `<img>` nodes re-resolve their
223
+ * blob URL.
224
+ */
225
+ bumpMediaRevision: () => void;
107
226
  }
108
227
 
109
228
  export interface EditorContextValue extends EditorState, EditorActions {
@@ -111,6 +230,27 @@ export interface EditorContextValue extends EditorState, EditorActions {
111
230
  tiptapEditor: TiptapEditor | null;
112
231
  /** The live Monaco editor instance (null when Raw is not mounted) */
113
232
  monacoEditor: MonacoEditor | null;
233
+ /**
234
+ * Workspace-scoped `ContentContainer` for this document — the folder
235
+ * holding the doc, its `_files/` sidecar, sibling documents, and any
236
+ * version snapshots. Drives audio mapping, version history, and
237
+ * sibling-doc reads for the recursive HTML export.
238
+ */
239
+ workspaceContainer: ContentContainer | null;
240
+ /**
241
+ * Version manager — non-null only when the host opted into versioning
242
+ * (`allowVersioning` + a `workspaceContainer`). Components can call
243
+ * `saveVersion` directly, or render the version-history panel which
244
+ * reads it from here.
245
+ */
246
+ versioning: DocumentVersionManager | null;
247
+ /**
248
+ * Stamp a new snapshot of the current document. No-op (returns
249
+ * `unchanged`) when content matches the latest version. Always safe
250
+ * to call — when versioning is disabled, returns `no-document`
251
+ * without writing.
252
+ */
253
+ saveVersion: (options?: SaveVersionOptions) => Promise<SaveVersionResult>;
114
254
  /** MediaProvider for resolving image URLs in the WYSIWYG editor */
115
255
  mediaProvider: MediaProvider | null;
116
256
  /**
@@ -128,6 +268,13 @@ export interface EditorContextValue extends EditorState, EditorActions {
128
268
  * the user types `@<query>`. When unset, `@` is just a literal character.
129
269
  */
130
270
  mentionProvider: MentionProvider | null;
271
+ /**
272
+ * Optional provider for sibling-document suggestions in the link
273
+ * dialog. When set, the dialog shows a "Browse documents" picker that
274
+ * lets authors search neighbor docs by name and insert a relative-
275
+ * path link. When unset, the dialog falls back to URL-only.
276
+ */
277
+ documentLinkProvider: DocumentLinkProvider | null;
131
278
  }
132
279
 
133
280
  export type ImageDisplayMode = 'inline' | 'thumbnail';
@@ -159,6 +306,41 @@ export interface EditorProviderProps {
159
306
  articleId?: string;
160
307
  /** Color theme */
161
308
  theme?: EditorTheme;
309
+ /**
310
+ * Workspace-scoped `ContentContainer` for this document — the folder
311
+ * holding the doc, its `_files/` sidecar, sibling documents, and any
312
+ * version snapshots. Required for `allowVersioning` to take effect.
313
+ */
314
+ workspaceContainer?: ContentContainer | null;
315
+ /**
316
+ * Enable version history. Snapshots are stored at
317
+ * `.versions/<basename>.<timestamp>.md` inside `workspaceContainer`.
318
+ * Auto-save fires after `versioningAutoSaveIdleMs` of idle; hosts can
319
+ * also call `saveVersion()` from the context. Without a
320
+ * `workspaceContainer`, this prop is ignored (and a `console.warn` is
321
+ * emitted).
322
+ */
323
+ allowVersioning?: boolean;
324
+ /** Override the basename used in version filenames. Defaults to the
325
+ * basename of the container's primary document path. */
326
+ versionBasename?: string;
327
+ /**
328
+ * Prune policy applied after each successful auto-save. Defaults to
329
+ * keeping the last 50 snapshots so the count doesn't grow unbounded.
330
+ */
331
+ versioningPrunePolicy?: PrunePolicy;
332
+ /**
333
+ * Idle delay (ms) before auto-saving a version. `0` disables auto-save
334
+ * entirely (versions are saved only via host-driven `saveVersion`
335
+ * calls). Default: 5000.
336
+ */
337
+ versioningAutoSaveIdleMs?: number;
338
+ /**
339
+ * Notified after each `saveVersion` attempt — both successful saves
340
+ * (`reason: 'saved'`) and skips (`'unchanged'`, `'no-document'`,
341
+ * `'empty'`). Useful for hosts that want a "Last saved" indicator.
342
+ */
343
+ onSaveVersion?: (result: SaveVersionResult) => void;
162
344
  /** MediaProvider for resolving image URLs */
163
345
  mediaProvider?: MediaProvider | null;
164
346
  /** Display mode for images in the WYSIWYG view. Defaults to `'inline'`. */
@@ -168,6 +350,18 @@ export interface EditorProviderProps {
168
350
  * entirely — typing `@` becomes just a literal character again.
169
351
  */
170
352
  mentionProvider?: MentionProvider | null;
353
+ /**
354
+ * Async provider for sibling-document suggestions in the link dialog.
355
+ * Omit to fall back to URL-only link insertion.
356
+ */
357
+ documentLinkProvider?: DocumentLinkProvider | null;
358
+ /**
359
+ * Whether the in-editor media recorder is available in the toolbar.
360
+ * Defaults to true. Set to false to suppress the recorder affordance
361
+ * even when a `mediaProvider` is wired (e.g. read-only embeds,
362
+ * surfaces where camera/screen prompts would be jarring).
363
+ */
364
+ allowRecording?: boolean;
171
365
  /**
172
366
  * File name (e.g. `foo.ts`) or bare extension — used to pick a Monaco
173
367
  * language and decide between markdown vs. code mode.
@@ -175,25 +369,113 @@ export interface EditorProviderProps {
175
369
  fileName?: string;
176
370
  /** Explicit Monaco language ID — wins over the fileName-derived one. */
177
371
  language?: string;
372
+ /**
373
+ * Initial visibility of the inline preview gutter. Defaults to false.
374
+ * The toolbar's View menu can toggle it at runtime.
375
+ */
376
+ inlinePreview?: boolean;
377
+ /**
378
+ * Initial visibility of the bottom status bar. Defaults to true.
379
+ * The toolbar's View menu can toggle it at runtime.
380
+ */
381
+ showStatusBar?: boolean;
382
+ /**
383
+ * Initial visibility of the left-side outline pane. Defaults to false.
384
+ * The toolbar's View menu can toggle it at runtime.
385
+ */
386
+ outline?: boolean;
387
+ /**
388
+ * Initial visibility of inline block-template tags on headings.
389
+ * Defaults to true. The toolbar's View menu can toggle it at runtime.
390
+ */
391
+ blockTags?: boolean;
392
+ /**
393
+ * Initial value for how much of the active Squisq theme the WYSIWYG
394
+ * editing surface should mirror. Defaults to `'fonts'` — the
395
+ * historical behavior of inheriting body / heading fonts only. The
396
+ * toolbar's View menu can change it at runtime.
397
+ */
398
+ themeInheritance?: ThemeInheritance;
399
+ /**
400
+ * Bundled view preferences — a serializable JSON blob covering all
401
+ * runtime-toggleable view options. When provided, individual values
402
+ * here override the matching individual props (`inlinePreview`,
403
+ * `showStatusBar`, `outline`). Hosts wiring this up typically load
404
+ * the blob from their own preferences storage and pair it with
405
+ * {@link onViewPreferencesChange}.
406
+ */
407
+ viewPreferences?: ViewPreferences;
408
+ /**
409
+ * Notified after each user-driven toggle in the View menu (or any
410
+ * programmatic call to the corresponding context setters). The
411
+ * argument is a full snapshot — hosts can persist it as-is.
412
+ * Not called when {@link viewPreferences} is changed externally.
413
+ */
414
+ onViewPreferencesChange?: (prefs: ViewPreferences) => void;
178
415
  children: ReactNode;
179
416
  }
180
417
 
418
+ /**
419
+ * Serializable bundle of all runtime-toggleable view preferences for
420
+ * the editor shell. Hosts can persist this verbatim (e.g. to
421
+ * localStorage) and pass it back via {@link EditorProviderProps.viewPreferences}
422
+ * to restore the user's last view configuration.
423
+ */
424
+ export interface ViewPreferences {
425
+ /** Whether the left-side outline pane is visible. */
426
+ outline?: boolean;
427
+ /** Whether the inline preview gutter (per-block cards) is visible. */
428
+ inlinePreview?: boolean;
429
+ /** Whether the bottom status bar is visible. */
430
+ showStatusBar?: boolean;
431
+ /** Whether inline block-template tags on headings are visible. */
432
+ blockTags?: boolean;
433
+ /** How much of the active Squisq theme the WYSIWYG surface mirrors. */
434
+ themeInheritance?: ThemeInheritance;
435
+ }
436
+
181
437
  /**
182
438
  * Provides shared editor state to all child components.
183
439
  * Automatically parses markdown and generates a Doc whenever the source changes.
184
440
  */
441
+ const DEFAULT_PRUNE_POLICY: PrunePolicy = { type: 'keep-last-n', n: 50 };
442
+ const DEFAULT_AUTOSAVE_IDLE_MS = 5_000;
443
+
185
444
  export function EditorProvider({
186
445
  initialMarkdown = '',
187
446
  initialView = 'raw',
188
447
  articleId = 'untitled',
189
448
  theme: initialTheme = 'light',
449
+ workspaceContainer = null,
450
+ allowVersioning = false,
451
+ versionBasename,
452
+ versioningPrunePolicy = DEFAULT_PRUNE_POLICY,
453
+ versioningAutoSaveIdleMs = DEFAULT_AUTOSAVE_IDLE_MS,
454
+ onSaveVersion,
190
455
  mediaProvider = null,
191
456
  imageDisplayMode = 'inline',
192
457
  mentionProvider = null,
458
+ documentLinkProvider = null,
459
+ allowRecording = true,
193
460
  fileName,
194
461
  language,
462
+ inlinePreview = false,
463
+ showStatusBar = true,
464
+ outline = false,
465
+ blockTags = true,
466
+ themeInheritance = 'fonts',
467
+ viewPreferences,
468
+ onViewPreferencesChange,
195
469
  children,
196
470
  }: EditorProviderProps) {
471
+ // Resolve effective initial values: bundled `viewPreferences` wins over
472
+ // individual props when both are passed. Individual props remain valid
473
+ // for hosts that haven't migrated to the bundled API.
474
+ const effectiveInlinePreview = viewPreferences?.inlinePreview ?? inlinePreview;
475
+ const effectiveShowStatusBar = viewPreferences?.showStatusBar ?? showStatusBar;
476
+ const effectiveOutline = viewPreferences?.outline ?? outline;
477
+ const effectiveBlockTags = viewPreferences?.blockTags ?? blockTags;
478
+ const effectiveThemeInheritance = viewPreferences?.themeInheritance ?? themeInheritance;
197
479
  // Resolve once per provider mount. Changing fileName/language after mount
198
480
  // would require recreating the Monaco model anyway, so treat it as static.
199
481
  const { mode: editorMode, language: resolvedLanguage } = useMemo(
@@ -201,17 +483,21 @@ export function EditorProvider({
201
483
  [fileName, language],
202
484
  );
203
485
  // In code mode, WYSIWYG and Preview aren't rendered — force the starting
204
- // view to 'raw' so we don't boot into an unmounted surface.
486
+ // view to 'raw' so we don't boot into an unmounted surface. Image mode
487
+ // has no text-editing surface at all; keep the same fallback so that any
488
+ // host that switches into image mode doesn't end up in a stale view id.
205
489
  const [markdownSource, setMarkdownSourceRaw] = useState(initialMarkdown);
206
490
  const [markdownDoc, setMarkdownDocState] = useState<MarkdownDocument | null>(null);
207
491
  const [doc, setDoc] = useState<Doc | null>(null);
208
492
  const [activeView, setActiveViewRaw] = useState<EditorView>(
209
- editorMode === 'code' ? 'raw' : initialView,
493
+ editorMode === 'markdown' ? initialView : 'raw',
210
494
  );
211
495
  const setActiveView = useCallback(
212
496
  (view: EditorView) => {
213
- // In code mode only the raw view is valid; ignore any other requests.
497
+ // In code mode only the raw view is valid. In image mode no text view
498
+ // is valid at all — ignore any switch attempt.
214
499
  if (editorMode === 'code' && view !== 'raw') return;
500
+ if (editorMode === 'image') return;
215
501
  setActiveViewRaw(view);
216
502
  },
217
503
  [editorMode],
@@ -219,6 +505,130 @@ export function EditorProvider({
219
505
  const [parseError, setParseError] = useState<string | null>(null);
220
506
  const [isParsing, setIsParsing] = useState(false);
221
507
  const [theme, setTheme] = useState<EditorTheme>(initialTheme);
508
+ const [inlinePreviewVisible, setInlinePreviewVisibleRaw] =
509
+ useState<boolean>(effectiveInlinePreview);
510
+ // Sync visibility when the host changes the prop (e.g., toggle from outside).
511
+ useEffect(() => {
512
+ setInlinePreviewVisibleRaw(inlinePreview);
513
+ }, [inlinePreview]);
514
+ const [statusBarVisible, setStatusBarVisibleRaw] = useState<boolean>(effectiveShowStatusBar);
515
+ useEffect(() => {
516
+ setStatusBarVisibleRaw(showStatusBar);
517
+ }, [showStatusBar]);
518
+ const [outlineVisible, setOutlineVisibleRaw] = useState<boolean>(effectiveOutline);
519
+ useEffect(() => {
520
+ setOutlineVisibleRaw(outline);
521
+ }, [outline]);
522
+ const [blockTagsVisible, setBlockTagsVisibleRaw] = useState<boolean>(effectiveBlockTags);
523
+ useEffect(() => {
524
+ setBlockTagsVisibleRaw(blockTags);
525
+ }, [blockTags]);
526
+ const [themeInheritanceState, setThemeInheritanceRaw] =
527
+ useState<ThemeInheritance>(effectiveThemeInheritance);
528
+ useEffect(() => {
529
+ setThemeInheritanceRaw(themeInheritance);
530
+ }, [themeInheritance]);
531
+ const [imageEditTarget, setImageEditTarget] = useState<string | null>(null);
532
+ const [mediaRevision, setMediaRevision] = useState(0);
533
+ const openImageEdit = useCallback((relativePath: string) => {
534
+ setImageEditTarget(relativePath);
535
+ }, []);
536
+ const closeImageEdit = useCallback(() => {
537
+ setImageEditTarget(null);
538
+ }, []);
539
+ const bumpMediaRevision = useCallback(() => {
540
+ setMediaRevision((n) => n + 1);
541
+ }, []);
542
+
543
+ // Sync from the bundled `viewPreferences` prop. Runs in addition to the
544
+ // individual prop syncs above. When both APIs are present, the bundled
545
+ // values are applied here last, keeping `viewPreferences` authoritative.
546
+ useEffect(() => {
547
+ if (!viewPreferences) return;
548
+ if (viewPreferences.inlinePreview !== undefined) {
549
+ setInlinePreviewVisibleRaw(viewPreferences.inlinePreview);
550
+ }
551
+ if (viewPreferences.showStatusBar !== undefined) {
552
+ setStatusBarVisibleRaw(viewPreferences.showStatusBar);
553
+ }
554
+ if (viewPreferences.outline !== undefined) {
555
+ setOutlineVisibleRaw(viewPreferences.outline);
556
+ }
557
+ if (viewPreferences.blockTags !== undefined) {
558
+ setBlockTagsVisibleRaw(viewPreferences.blockTags);
559
+ }
560
+ if (viewPreferences.themeInheritance !== undefined) {
561
+ setThemeInheritanceRaw(viewPreferences.themeInheritance);
562
+ }
563
+ }, [viewPreferences]);
564
+
565
+ // Wrap the three setters so user-driven toggles emit a snapshot via
566
+ // `onViewPreferencesChange`. Refs hold the latest values + callback so
567
+ // each wrapper can build a current snapshot without re-creating itself
568
+ // on every state change (the setters are kept referentially stable for
569
+ // the context value's memoization).
570
+ const onViewPreferencesChangeRef = useRef(onViewPreferencesChange);
571
+ onViewPreferencesChangeRef.current = onViewPreferencesChange;
572
+ const inlinePreviewRef = useRef(inlinePreviewVisible);
573
+ inlinePreviewRef.current = inlinePreviewVisible;
574
+ const statusBarRef = useRef(statusBarVisible);
575
+ statusBarRef.current = statusBarVisible;
576
+ const outlineRef = useRef(outlineVisible);
577
+ outlineRef.current = outlineVisible;
578
+ const blockTagsRef = useRef(blockTagsVisible);
579
+ blockTagsRef.current = blockTagsVisible;
580
+ const themeInheritanceRef = useRef(themeInheritanceState);
581
+ themeInheritanceRef.current = themeInheritanceState;
582
+ const setInlinePreviewVisible = useCallback((visible: boolean) => {
583
+ setInlinePreviewVisibleRaw(visible);
584
+ onViewPreferencesChangeRef.current?.({
585
+ inlinePreview: visible,
586
+ showStatusBar: statusBarRef.current,
587
+ outline: outlineRef.current,
588
+ blockTags: blockTagsRef.current,
589
+ themeInheritance: themeInheritanceRef.current,
590
+ });
591
+ }, []);
592
+ const setStatusBarVisible = useCallback((visible: boolean) => {
593
+ setStatusBarVisibleRaw(visible);
594
+ onViewPreferencesChangeRef.current?.({
595
+ inlinePreview: inlinePreviewRef.current,
596
+ showStatusBar: visible,
597
+ outline: outlineRef.current,
598
+ blockTags: blockTagsRef.current,
599
+ themeInheritance: themeInheritanceRef.current,
600
+ });
601
+ }, []);
602
+ const setOutlineVisible = useCallback((visible: boolean) => {
603
+ setOutlineVisibleRaw(visible);
604
+ onViewPreferencesChangeRef.current?.({
605
+ inlinePreview: inlinePreviewRef.current,
606
+ showStatusBar: statusBarRef.current,
607
+ outline: visible,
608
+ blockTags: blockTagsRef.current,
609
+ themeInheritance: themeInheritanceRef.current,
610
+ });
611
+ }, []);
612
+ const setBlockTagsVisible = useCallback((visible: boolean) => {
613
+ setBlockTagsVisibleRaw(visible);
614
+ onViewPreferencesChangeRef.current?.({
615
+ inlinePreview: inlinePreviewRef.current,
616
+ showStatusBar: statusBarRef.current,
617
+ outline: outlineRef.current,
618
+ blockTags: visible,
619
+ themeInheritance: themeInheritanceRef.current,
620
+ });
621
+ }, []);
622
+ const setThemeInheritance = useCallback((mode: ThemeInheritance) => {
623
+ setThemeInheritanceRaw(mode);
624
+ onViewPreferencesChangeRef.current?.({
625
+ inlinePreview: inlinePreviewRef.current,
626
+ showStatusBar: statusBarRef.current,
627
+ outline: outlineRef.current,
628
+ blockTags: blockTagsRef.current,
629
+ themeInheritance: mode,
630
+ });
631
+ }, []);
222
632
  const [tiptapEditor, setTiptapEditor] = useState<TiptapEditor | null>(null);
223
633
  const [monacoEditor, setMonacoEditor] = useState<MonacoEditor | null>(null);
224
634
 
@@ -260,12 +670,12 @@ export function EditorProvider({
260
670
  }
261
671
  }, []);
262
672
 
263
- // Parse on source changes with debounce. Skipped in code mode — the
264
- // WYSIWYG/Preview surfaces that consume markdownDoc/doc aren't mounted,
265
- // so there's nothing to feed and no reason to run the markdown parser on
266
- // TypeScript / JSON / etc.
673
+ // Parse on source changes with debounce. Skipped in code/image mode —
674
+ // the WYSIWYG/Preview surfaces that consume markdownDoc/doc aren't
675
+ // mounted, so there's nothing to feed and no reason to run the markdown
676
+ // parser on TypeScript / JSON / a binary image asset.
267
677
  useEffect(() => {
268
- if (editorMode === 'code') return;
678
+ if (editorMode !== 'markdown') return;
269
679
  if (parseTimeoutRef.current) {
270
680
  clearTimeout(parseTimeoutRef.current);
271
681
  }
@@ -281,7 +691,7 @@ export function EditorProvider({
281
691
 
282
692
  // Initial parse
283
693
  useEffect(() => {
284
- if (editorMode === 'code') return;
694
+ if (editorMode !== 'markdown') return;
285
695
  if (initialMarkdown) {
286
696
  doParse(initialMarkdown);
287
697
  }
@@ -339,6 +749,80 @@ export function EditorProvider({
339
749
  [tiptapEditor, monacoEditor],
340
750
  );
341
751
 
752
+ // ── Versioning ─────────────────────────────────────────
753
+ // Build a manager only when versioning is opted in *and* a workspace
754
+ // container exists. A versioning request without one is a misconfiguration
755
+ // — warn once so it surfaces in dev without breaking the editor.
756
+ const versioningWarnedRef = useRef(false);
757
+ useEffect(() => {
758
+ if (allowVersioning && !workspaceContainer && !versioningWarnedRef.current) {
759
+ console.warn(
760
+ '[squisq-editor] allowVersioning requires a `workspaceContainer` prop; versioning is disabled.',
761
+ );
762
+ versioningWarnedRef.current = true;
763
+ }
764
+ }, [allowVersioning, workspaceContainer]);
765
+
766
+ const versioning = useMemo<DocumentVersionManager | null>(() => {
767
+ if (!allowVersioning || !workspaceContainer) return null;
768
+ return new DocumentVersionManager(workspaceContainer, { basename: versionBasename });
769
+ }, [allowVersioning, workspaceContainer, versionBasename]);
770
+
771
+ const onSaveVersionRef = useRef(onSaveVersion);
772
+ onSaveVersionRef.current = onSaveVersion;
773
+ const prunePolicyRef = useRef(versioningPrunePolicy);
774
+ prunePolicyRef.current = versioningPrunePolicy;
775
+
776
+ const saveVersion = useCallback(
777
+ async (options?: SaveVersionOptions): Promise<SaveVersionResult> => {
778
+ if (!versioning) {
779
+ const skipped: SaveVersionResult = { saved: false, version: null, reason: 'no-document' };
780
+ onSaveVersionRef.current?.(skipped);
781
+ return skipped;
782
+ }
783
+ const result = await versioning.saveVersion(options);
784
+ onSaveVersionRef.current?.(result);
785
+ if (result.saved) {
786
+ // Fire-and-forget prune. Failures here shouldn't block the save.
787
+ versioning.pruneVersions(prunePolicyRef.current).catch((err: unknown) => {
788
+ console.warn(
789
+ '[squisq-editor] pruneVersions failed:',
790
+ err instanceof Error ? err.message : err,
791
+ );
792
+ });
793
+ }
794
+ return result;
795
+ },
796
+ [versioning],
797
+ );
798
+
799
+ // Auto-save: stamp a new snapshot after `versioningAutoSaveIdleMs` of
800
+ // idle. The "only save if different" check inside `saveVersion` makes
801
+ // most ticks no-ops, so this is cheap. Disabled when the idle delay is
802
+ // 0 or versioning isn't active.
803
+ //
804
+ // We pass the live `markdownSource` explicitly so saveVersion never has
805
+ // to fall back to `container.readDocument()`. That fallback would fail
806
+ // in setups where the markdown file lives outside the versioning
807
+ // container's scope (e.g. DocBlocks, where the container points at
808
+ // `<basename>_files/` while the doc itself lives in the parent
809
+ // directory). Using the editor's live state also ensures the snapshot
810
+ // captures the most recent edit even if the host's autosave to the
811
+ // container hasn't flushed yet.
812
+ useEffect(() => {
813
+ if (!versioning) return;
814
+ if (versioningAutoSaveIdleMs <= 0) return;
815
+ const timer = setTimeout(() => {
816
+ saveVersion({ content: markdownSource }).catch((err: unknown) => {
817
+ console.warn(
818
+ '[squisq-editor] auto-save version failed:',
819
+ err instanceof Error ? err.message : err,
820
+ );
821
+ });
822
+ }, versioningAutoSaveIdleMs);
823
+ return () => clearTimeout(timer);
824
+ }, [markdownSource, versioning, versioningAutoSaveIdleMs, saveVersion]);
825
+
342
826
  const setMarkdownDoc = useCallback((newDoc: MarkdownDocument) => {
343
827
  setMarkdownDocState(newDoc);
344
828
  // Stringify to update the raw source
@@ -373,19 +857,39 @@ export function EditorProvider({
373
857
  theme,
374
858
  editorMode,
375
859
  language: resolvedLanguage,
860
+ inlinePreviewVisible,
861
+ statusBarVisible,
862
+ outlineVisible,
863
+ blockTagsVisible,
864
+ themeInheritance: themeInheritanceState,
865
+ imageEditTarget,
866
+ mediaRevision,
867
+ allowRecording,
376
868
  tiptapEditor,
377
869
  monacoEditor,
870
+ workspaceContainer,
871
+ versioning,
872
+ saveVersion,
378
873
  mediaProvider,
379
874
  imageDisplayMode,
380
875
  mentionProvider,
876
+ documentLinkProvider,
381
877
  setMarkdownSource,
382
878
  setMarkdownDoc,
383
879
  setActiveView,
384
880
  setTiptapEditor,
385
881
  setMonacoEditor,
386
882
  setTheme,
883
+ setInlinePreviewVisible,
884
+ setStatusBarVisible,
885
+ setOutlineVisible,
886
+ setBlockTagsVisible,
887
+ setThemeInheritance,
387
888
  insertAtCursor,
388
889
  replaceAll,
890
+ openImageEdit,
891
+ closeImageEdit,
892
+ bumpMediaRevision,
389
893
  }),
390
894
  [
391
895
  markdownSource,
@@ -397,19 +901,39 @@ export function EditorProvider({
397
901
  theme,
398
902
  editorMode,
399
903
  resolvedLanguage,
904
+ inlinePreviewVisible,
905
+ statusBarVisible,
906
+ outlineVisible,
907
+ blockTagsVisible,
908
+ themeInheritanceState,
400
909
  tiptapEditor,
401
910
  monacoEditor,
911
+ workspaceContainer,
912
+ versioning,
913
+ saveVersion,
402
914
  mediaProvider,
403
915
  imageDisplayMode,
404
916
  mentionProvider,
917
+ documentLinkProvider,
405
918
  setMarkdownSource,
406
919
  setMarkdownDoc,
407
920
  setActiveView,
408
921
  setTiptapEditor,
409
922
  setMonacoEditor,
410
923
  setTheme,
924
+ setInlinePreviewVisible,
925
+ setStatusBarVisible,
926
+ setOutlineVisible,
927
+ setBlockTagsVisible,
928
+ setThemeInheritance,
411
929
  insertAtCursor,
412
930
  replaceAll,
931
+ imageEditTarget,
932
+ mediaRevision,
933
+ allowRecording,
934
+ openImageEdit,
935
+ closeImageEdit,
936
+ bumpMediaRevision,
413
937
  ],
414
938
  );
415
939