@bendyline/squisq-editor-react 1.5.1 → 1.5.2

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 (401) hide show
  1. package/dist/index.d.ts +1991 -90
  2. package/dist/index.js +17088 -82
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -4
  5. package/dist/DocumentSettingsDialog.d.ts +0 -26
  6. package/dist/DocumentSettingsDialog.d.ts.map +0 -1
  7. package/dist/DocumentSettingsDialog.js +0 -115
  8. package/dist/DocumentSettingsDialog.js.map +0 -1
  9. package/dist/DropZoneOverlay.d.ts +0 -24
  10. package/dist/DropZoneOverlay.d.ts.map +0 -1
  11. package/dist/DropZoneOverlay.js +0 -53
  12. package/dist/DropZoneOverlay.js.map +0 -1
  13. package/dist/EditorContext.d.ts +0 -391
  14. package/dist/EditorContext.d.ts.map +0 -1
  15. package/dist/EditorContext.js +0 -471
  16. package/dist/EditorContext.js.map +0 -1
  17. package/dist/EditorShell.d.ts +0 -328
  18. package/dist/EditorShell.d.ts.map +0 -1
  19. package/dist/EditorShell.js +0 -290
  20. package/dist/EditorShell.js.map +0 -1
  21. package/dist/EmojiPicker.d.ts +0 -50
  22. package/dist/EmojiPicker.d.ts.map +0 -1
  23. package/dist/EmojiPicker.js +0 -182
  24. package/dist/EmojiPicker.js.map +0 -1
  25. package/dist/ImageEditor.d.ts +0 -68
  26. package/dist/ImageEditor.d.ts.map +0 -1
  27. package/dist/ImageEditor.js +0 -166
  28. package/dist/ImageEditor.js.map +0 -1
  29. package/dist/ImageNodeView.d.ts +0 -27
  30. package/dist/ImageNodeView.d.ts.map +0 -1
  31. package/dist/ImageNodeView.js +0 -215
  32. package/dist/ImageNodeView.js.map +0 -1
  33. package/dist/ImageViewer.d.ts +0 -26
  34. package/dist/ImageViewer.d.ts.map +0 -1
  35. package/dist/ImageViewer.js +0 -119
  36. package/dist/ImageViewer.js.map +0 -1
  37. package/dist/InlineIcon.d.ts +0 -17
  38. package/dist/InlineIcon.d.ts.map +0 -1
  39. package/dist/InlineIcon.js +0 -72
  40. package/dist/InlineIcon.js.map +0 -1
  41. package/dist/InlinePreviewGutter.d.ts +0 -52
  42. package/dist/InlinePreviewGutter.d.ts.map +0 -1
  43. package/dist/InlinePreviewGutter.js +0 -397
  44. package/dist/InlinePreviewGutter.js.map +0 -1
  45. package/dist/LinkDialog.d.ts +0 -43
  46. package/dist/LinkDialog.d.ts.map +0 -1
  47. package/dist/LinkDialog.js +0 -102
  48. package/dist/LinkDialog.js.map +0 -1
  49. package/dist/MediaBin.d.ts +0 -29
  50. package/dist/MediaBin.d.ts.map +0 -1
  51. package/dist/MediaBin.js +0 -166
  52. package/dist/MediaBin.js.map +0 -1
  53. package/dist/MentionExtension.d.ts +0 -22
  54. package/dist/MentionExtension.d.ts.map +0 -1
  55. package/dist/MentionExtension.js +0 -245
  56. package/dist/MentionExtension.js.map +0 -1
  57. package/dist/OutlinePanel.d.ts +0 -17
  58. package/dist/OutlinePanel.d.ts.map +0 -1
  59. package/dist/OutlinePanel.js +0 -167
  60. package/dist/OutlinePanel.js.map +0 -1
  61. package/dist/PlainHtmlPreview.d.ts +0 -50
  62. package/dist/PlainHtmlPreview.d.ts.map +0 -1
  63. package/dist/PlainHtmlPreview.js +0 -155
  64. package/dist/PlainHtmlPreview.js.map +0 -1
  65. package/dist/PreviewControls.d.ts +0 -55
  66. package/dist/PreviewControls.d.ts.map +0 -1
  67. package/dist/PreviewControls.js +0 -277
  68. package/dist/PreviewControls.js.map +0 -1
  69. package/dist/PreviewPanel.d.ts +0 -29
  70. package/dist/PreviewPanel.d.ts.map +0 -1
  71. package/dist/PreviewPanel.js +0 -94
  72. package/dist/PreviewPanel.js.map +0 -1
  73. package/dist/RawEditor.d.ts +0 -32
  74. package/dist/RawEditor.d.ts.map +0 -1
  75. package/dist/RawEditor.js +0 -440
  76. package/dist/RawEditor.js.map +0 -1
  77. package/dist/RecorderEntry.d.ts +0 -24
  78. package/dist/RecorderEntry.d.ts.map +0 -1
  79. package/dist/RecorderEntry.js +0 -139
  80. package/dist/RecorderEntry.js.map +0 -1
  81. package/dist/StatusBar.d.ts +0 -15
  82. package/dist/StatusBar.d.ts.map +0 -1
  83. package/dist/StatusBar.js +0 -24
  84. package/dist/StatusBar.js.map +0 -1
  85. package/dist/TemplateAnnotation.d.ts +0 -20
  86. package/dist/TemplateAnnotation.d.ts.map +0 -1
  87. package/dist/TemplateAnnotation.js +0 -97
  88. package/dist/TemplateAnnotation.js.map +0 -1
  89. package/dist/TemplatePicker.d.ts +0 -53
  90. package/dist/TemplatePicker.d.ts.map +0 -1
  91. package/dist/TemplatePicker.js +0 -388
  92. package/dist/TemplatePicker.js.map +0 -1
  93. package/dist/ThemeCustomizerPanel.d.ts +0 -32
  94. package/dist/ThemeCustomizerPanel.d.ts.map +0 -1
  95. package/dist/ThemeCustomizerPanel.js +0 -256
  96. package/dist/ThemeCustomizerPanel.js.map +0 -1
  97. package/dist/ThemePicker.d.ts +0 -33
  98. package/dist/ThemePicker.d.ts.map +0 -1
  99. package/dist/ThemePicker.js +0 -148
  100. package/dist/ThemePicker.js.map +0 -1
  101. package/dist/Toolbar.d.ts +0 -36
  102. package/dist/Toolbar.d.ts.map +0 -1
  103. package/dist/Toolbar.js +0 -1001
  104. package/dist/Toolbar.js.map +0 -1
  105. package/dist/Tooltip.d.ts +0 -10
  106. package/dist/Tooltip.d.ts.map +0 -1
  107. package/dist/Tooltip.js +0 -104
  108. package/dist/Tooltip.js.map +0 -1
  109. package/dist/VersionHistoryPanel.d.ts +0 -14
  110. package/dist/VersionHistoryPanel.d.ts.map +0 -1
  111. package/dist/VersionHistoryPanel.js +0 -147
  112. package/dist/VersionHistoryPanel.js.map +0 -1
  113. package/dist/ViewMenuPanel.d.ts +0 -13
  114. package/dist/ViewMenuPanel.d.ts.map +0 -1
  115. package/dist/ViewMenuPanel.js +0 -58
  116. package/dist/ViewMenuPanel.js.map +0 -1
  117. package/dist/ViewSwitcher.d.ts +0 -14
  118. package/dist/ViewSwitcher.d.ts.map +0 -1
  119. package/dist/ViewSwitcher.js +0 -26
  120. package/dist/ViewSwitcher.js.map +0 -1
  121. package/dist/WysiwygEditor.d.ts +0 -39
  122. package/dist/WysiwygEditor.d.ts.map +0 -1
  123. package/dist/WysiwygEditor.js +0 -537
  124. package/dist/WysiwygEditor.js.map +0 -1
  125. package/dist/__tests__/detectMarkdown.test.d.ts +0 -2
  126. package/dist/__tests__/detectMarkdown.test.d.ts.map +0 -1
  127. package/dist/__tests__/detectMarkdown.test.js +0 -55
  128. package/dist/__tests__/detectMarkdown.test.js.map +0 -1
  129. package/dist/__tests__/documentSettingsDialog.test.d.ts +0 -2
  130. package/dist/__tests__/documentSettingsDialog.test.d.ts.map +0 -1
  131. package/dist/__tests__/documentSettingsDialog.test.js +0 -132
  132. package/dist/__tests__/documentSettingsDialog.test.js.map +0 -1
  133. package/dist/__tests__/emojiPicker.test.d.ts +0 -2
  134. package/dist/__tests__/emojiPicker.test.d.ts.map +0 -1
  135. package/dist/__tests__/emojiPicker.test.js +0 -111
  136. package/dist/__tests__/emojiPicker.test.js.map +0 -1
  137. package/dist/__tests__/fileKind.test.d.ts +0 -2
  138. package/dist/__tests__/fileKind.test.d.ts.map +0 -1
  139. package/dist/__tests__/fileKind.test.js +0 -94
  140. package/dist/__tests__/fileKind.test.js.map +0 -1
  141. package/dist/__tests__/imageEditAffordance.test.d.ts +0 -2
  142. package/dist/__tests__/imageEditAffordance.test.d.ts.map +0 -1
  143. package/dist/__tests__/imageEditAffordance.test.js +0 -188
  144. package/dist/__tests__/imageEditAffordance.test.js.map +0 -1
  145. package/dist/__tests__/imageEditorShell.test.d.ts +0 -2
  146. package/dist/__tests__/imageEditorShell.test.d.ts.map +0 -1
  147. package/dist/__tests__/imageEditorShell.test.js +0 -52
  148. package/dist/__tests__/imageEditorShell.test.js.map +0 -1
  149. package/dist/__tests__/imageEditorState.test.d.ts +0 -3
  150. package/dist/__tests__/imageEditorState.test.d.ts.map +0 -1
  151. package/dist/__tests__/imageEditorState.test.js +0 -148
  152. package/dist/__tests__/imageEditorState.test.js.map +0 -1
  153. package/dist/__tests__/inlinePreviewGutter.test.d.ts +0 -2
  154. package/dist/__tests__/inlinePreviewGutter.test.d.ts.map +0 -1
  155. package/dist/__tests__/inlinePreviewGutter.test.js +0 -51
  156. package/dist/__tests__/inlinePreviewGutter.test.js.map +0 -1
  157. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts +0 -2
  158. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts.map +0 -1
  159. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js +0 -63
  160. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js.map +0 -1
  161. package/dist/__tests__/jsonEditor.test.d.ts +0 -2
  162. package/dist/__tests__/jsonEditor.test.d.ts.map +0 -1
  163. package/dist/__tests__/jsonEditor.test.js +0 -134
  164. package/dist/__tests__/jsonEditor.test.js.map +0 -1
  165. package/dist/__tests__/layersPanel.test.d.ts +0 -2
  166. package/dist/__tests__/layersPanel.test.d.ts.map +0 -1
  167. package/dist/__tests__/layersPanel.test.js +0 -84
  168. package/dist/__tests__/layersPanel.test.js.map +0 -1
  169. package/dist/__tests__/linkDialogDocPicker.test.d.ts +0 -7
  170. package/dist/__tests__/linkDialogDocPicker.test.d.ts.map +0 -1
  171. package/dist/__tests__/linkDialogDocPicker.test.js +0 -75
  172. package/dist/__tests__/linkDialogDocPicker.test.js.map +0 -1
  173. package/dist/__tests__/mediaAttachmentFlow.test.d.ts +0 -2
  174. package/dist/__tests__/mediaAttachmentFlow.test.d.ts.map +0 -1
  175. package/dist/__tests__/mediaAttachmentFlow.test.js +0 -99
  176. package/dist/__tests__/mediaAttachmentFlow.test.js.map +0 -1
  177. package/dist/__tests__/outlinePanel.test.d.ts +0 -2
  178. package/dist/__tests__/outlinePanel.test.d.ts.map +0 -1
  179. package/dist/__tests__/outlinePanel.test.js +0 -68
  180. package/dist/__tests__/outlinePanel.test.js.map +0 -1
  181. package/dist/__tests__/plainHtmlPreview.test.d.ts +0 -2
  182. package/dist/__tests__/plainHtmlPreview.test.d.ts.map +0 -1
  183. package/dist/__tests__/plainHtmlPreview.test.js +0 -87
  184. package/dist/__tests__/plainHtmlPreview.test.js.map +0 -1
  185. package/dist/__tests__/propertiesPanel.test.d.ts +0 -2
  186. package/dist/__tests__/propertiesPanel.test.d.ts.map +0 -1
  187. package/dist/__tests__/propertiesPanel.test.js +0 -64
  188. package/dist/__tests__/propertiesPanel.test.js.map +0 -1
  189. package/dist/__tests__/recorderFormats.test.d.ts +0 -2
  190. package/dist/__tests__/recorderFormats.test.d.ts.map +0 -1
  191. package/dist/__tests__/recorderFormats.test.js +0 -121
  192. package/dist/__tests__/recorderFormats.test.js.map +0 -1
  193. package/dist/__tests__/recorderTimingJson.test.d.ts +0 -2
  194. package/dist/__tests__/recorderTimingJson.test.d.ts.map +0 -1
  195. package/dist/__tests__/recorderTimingJson.test.js +0 -37
  196. package/dist/__tests__/recorderTimingJson.test.js.map +0 -1
  197. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts +0 -2
  198. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts.map +0 -1
  199. package/dist/__tests__/templateAnnotationRoundTrip.test.js +0 -31
  200. package/dist/__tests__/templateAnnotationRoundTrip.test.js.map +0 -1
  201. package/dist/__tests__/tiptapBridge.test.d.ts +0 -2
  202. package/dist/__tests__/tiptapBridge.test.d.ts.map +0 -1
  203. package/dist/__tests__/tiptapBridge.test.js +0 -303
  204. package/dist/__tests__/tiptapBridge.test.js.map +0 -1
  205. package/dist/__tests__/tiptapImageRoundTrip.test.d.ts +0 -2
  206. package/dist/__tests__/tiptapImageRoundTrip.test.d.ts.map +0 -1
  207. package/dist/__tests__/tiptapImageRoundTrip.test.js +0 -68
  208. package/dist/__tests__/tiptapImageRoundTrip.test.js.map +0 -1
  209. package/dist/__tests__/useImageEditor.test.d.ts +0 -2
  210. package/dist/__tests__/useImageEditor.test.d.ts.map +0 -1
  211. package/dist/__tests__/useImageEditor.test.js +0 -131
  212. package/dist/__tests__/useImageEditor.test.js.map +0 -1
  213. package/dist/__tests__/useMediaRecorder.test.d.ts +0 -2
  214. package/dist/__tests__/useMediaRecorder.test.d.ts.map +0 -1
  215. package/dist/__tests__/useMediaRecorder.test.js +0 -153
  216. package/dist/__tests__/useMediaRecorder.test.js.map +0 -1
  217. package/dist/__tests__/versionHistory.test.d.ts +0 -2
  218. package/dist/__tests__/versionHistory.test.d.ts.map +0 -1
  219. package/dist/__tests__/versionHistory.test.js +0 -124
  220. package/dist/__tests__/versionHistory.test.js.map +0 -1
  221. package/dist/blockSlice.d.ts +0 -24
  222. package/dist/blockSlice.d.ts.map +0 -1
  223. package/dist/blockSlice.js +0 -63
  224. package/dist/blockSlice.js.map +0 -1
  225. package/dist/buildPreviewDoc.d.ts +0 -22
  226. package/dist/buildPreviewDoc.d.ts.map +0 -1
  227. package/dist/buildPreviewDoc.js +0 -262
  228. package/dist/buildPreviewDoc.js.map +0 -1
  229. package/dist/detectMarkdown.d.ts +0 -20
  230. package/dist/detectMarkdown.d.ts.map +0 -1
  231. package/dist/detectMarkdown.js +0 -61
  232. package/dist/detectMarkdown.js.map +0 -1
  233. package/dist/emojiData.d.ts +0 -81
  234. package/dist/emojiData.d.ts.map +0 -1
  235. package/dist/emojiData.js +0 -1283
  236. package/dist/emojiData.js.map +0 -1
  237. package/dist/fileKind.d.ts +0 -34
  238. package/dist/fileKind.d.ts.map +0 -1
  239. package/dist/fileKind.js +0 -144
  240. package/dist/fileKind.js.map +0 -1
  241. package/dist/hooks/useFileDrop.d.ts +0 -41
  242. package/dist/hooks/useFileDrop.d.ts.map +0 -1
  243. package/dist/hooks/useFileDrop.js +0 -205
  244. package/dist/hooks/useFileDrop.js.map +0 -1
  245. package/dist/imageEditor/CanvasSurface.d.ts +0 -31
  246. package/dist/imageEditor/CanvasSurface.d.ts.map +0 -1
  247. package/dist/imageEditor/CanvasSurface.js +0 -264
  248. package/dist/imageEditor/CanvasSurface.js.map +0 -1
  249. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts +0 -39
  250. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts.map +0 -1
  251. package/dist/imageEditor/ImageVersionHistoryDropdown.js +0 -283
  252. package/dist/imageEditor/ImageVersionHistoryDropdown.js.map +0 -1
  253. package/dist/imageEditor/LayersPanel.d.ts +0 -14
  254. package/dist/imageEditor/LayersPanel.d.ts.map +0 -1
  255. package/dist/imageEditor/LayersPanel.js +0 -43
  256. package/dist/imageEditor/LayersPanel.js.map +0 -1
  257. package/dist/imageEditor/PropertiesPanel.d.ts +0 -14
  258. package/dist/imageEditor/PropertiesPanel.d.ts.map +0 -1
  259. package/dist/imageEditor/PropertiesPanel.js +0 -97
  260. package/dist/imageEditor/PropertiesPanel.js.map +0 -1
  261. package/dist/imageEditor/Toolbar.d.ts +0 -30
  262. package/dist/imageEditor/Toolbar.d.ts.map +0 -1
  263. package/dist/imageEditor/Toolbar.js +0 -108
  264. package/dist/imageEditor/Toolbar.js.map +0 -1
  265. package/dist/imageEditor/icons.d.ts +0 -24
  266. package/dist/imageEditor/icons.d.ts.map +0 -1
  267. package/dist/imageEditor/icons.js +0 -45
  268. package/dist/imageEditor/icons.js.map +0 -1
  269. package/dist/imageEditor/layers/EditorImageLayer.d.ts +0 -16
  270. package/dist/imageEditor/layers/EditorImageLayer.d.ts.map +0 -1
  271. package/dist/imageEditor/layers/EditorImageLayer.js +0 -37
  272. package/dist/imageEditor/layers/EditorImageLayer.js.map +0 -1
  273. package/dist/imageEditor/layers/EditorShapeLayer.d.ts +0 -15
  274. package/dist/imageEditor/layers/EditorShapeLayer.d.ts.map +0 -1
  275. package/dist/imageEditor/layers/EditorShapeLayer.js +0 -20
  276. package/dist/imageEditor/layers/EditorShapeLayer.js.map +0 -1
  277. package/dist/imageEditor/layers/EditorTextLayer.d.ts +0 -18
  278. package/dist/imageEditor/layers/EditorTextLayer.d.ts.map +0 -1
  279. package/dist/imageEditor/layers/EditorTextLayer.js +0 -13
  280. package/dist/imageEditor/layers/EditorTextLayer.js.map +0 -1
  281. package/dist/imageEditor/layers/SelectionHandles.d.ts +0 -17
  282. package/dist/imageEditor/layers/SelectionHandles.d.ts.map +0 -1
  283. package/dist/imageEditor/layers/SelectionHandles.js +0 -19
  284. package/dist/imageEditor/layers/SelectionHandles.js.map +0 -1
  285. package/dist/imageEditor/state.d.ts +0 -76
  286. package/dist/imageEditor/state.d.ts.map +0 -1
  287. package/dist/imageEditor/state.js +0 -87
  288. package/dist/imageEditor/state.js.map +0 -1
  289. package/dist/imageEditor/useImageEditor.d.ts +0 -53
  290. package/dist/imageEditor/useImageEditor.d.ts.map +0 -1
  291. package/dist/imageEditor/useImageEditor.js +0 -244
  292. package/dist/imageEditor/useImageEditor.js.map +0 -1
  293. package/dist/imageEditor/useImageEditorTokens.d.ts +0 -16
  294. package/dist/imageEditor/useImageEditorTokens.d.ts.map +0 -1
  295. package/dist/imageEditor/useImageEditorTokens.js +0 -45
  296. package/dist/imageEditor/useImageEditorTokens.js.map +0 -1
  297. package/dist/index.d.ts.map +0 -1
  298. package/dist/jsonEditor/EmbeddedRichTextField.d.ts +0 -15
  299. package/dist/jsonEditor/EmbeddedRichTextField.d.ts.map +0 -1
  300. package/dist/jsonEditor/EmbeddedRichTextField.js +0 -74
  301. package/dist/jsonEditor/EmbeddedRichTextField.js.map +0 -1
  302. package/dist/jsonEditor/JsonEditor.d.ts +0 -36
  303. package/dist/jsonEditor/JsonEditor.d.ts.map +0 -1
  304. package/dist/jsonEditor/JsonEditor.js +0 -15
  305. package/dist/jsonEditor/JsonEditor.js.map +0 -1
  306. package/dist/jsonEditor/JsonEditorContext.d.ts +0 -28
  307. package/dist/jsonEditor/JsonEditorContext.d.ts.map +0 -1
  308. package/dist/jsonEditor/JsonEditorContext.js +0 -41
  309. package/dist/jsonEditor/JsonEditorContext.js.map +0 -1
  310. package/dist/jsonEditor/RenderNode.d.ts +0 -16
  311. package/dist/jsonEditor/RenderNode.d.ts.map +0 -1
  312. package/dist/jsonEditor/RenderNode.js +0 -32
  313. package/dist/jsonEditor/RenderNode.js.map +0 -1
  314. package/dist/jsonEditor/editors.d.ts +0 -36
  315. package/dist/jsonEditor/editors.d.ts.map +0 -1
  316. package/dist/jsonEditor/editors.js +0 -347
  317. package/dist/jsonEditor/editors.js.map +0 -1
  318. package/dist/jsonEditor/index.d.ts +0 -3
  319. package/dist/jsonEditor/index.d.ts.map +0 -1
  320. package/dist/jsonEditor/index.js +0 -2
  321. package/dist/jsonEditor/index.js.map +0 -1
  322. package/dist/jsonEditor/useJsonEditorTokens.d.ts +0 -13
  323. package/dist/jsonEditor/useJsonEditorTokens.d.ts.map +0 -1
  324. package/dist/jsonEditor/useJsonEditorTokens.js +0 -38
  325. package/dist/jsonEditor/useJsonEditorTokens.js.map +0 -1
  326. package/dist/mediaDragMime.d.ts +0 -17
  327. package/dist/mediaDragMime.d.ts.map +0 -1
  328. package/dist/mediaDragMime.js +0 -22
  329. package/dist/mediaDragMime.js.map +0 -1
  330. package/dist/recorder/RecorderButton.d.ts +0 -31
  331. package/dist/recorder/RecorderButton.d.ts.map +0 -1
  332. package/dist/recorder/RecorderButton.js +0 -24
  333. package/dist/recorder/RecorderButton.js.map +0 -1
  334. package/dist/recorder/RecorderModal.d.ts +0 -59
  335. package/dist/recorder/RecorderModal.d.ts.map +0 -1
  336. package/dist/recorder/RecorderModal.js +0 -333
  337. package/dist/recorder/RecorderModal.js.map +0 -1
  338. package/dist/recorder/RecorderPanel.d.ts +0 -25
  339. package/dist/recorder/RecorderPanel.d.ts.map +0 -1
  340. package/dist/recorder/RecorderPanel.js +0 -30
  341. package/dist/recorder/RecorderPanel.js.map +0 -1
  342. package/dist/recorder/formats.d.ts +0 -51
  343. package/dist/recorder/formats.d.ts.map +0 -1
  344. package/dist/recorder/formats.js +0 -144
  345. package/dist/recorder/formats.js.map +0 -1
  346. package/dist/recorder/hooks/useMediaRecorder.d.ts +0 -90
  347. package/dist/recorder/hooks/useMediaRecorder.d.ts.map +0 -1
  348. package/dist/recorder/hooks/useMediaRecorder.js +0 -277
  349. package/dist/recorder/hooks/useMediaRecorder.js.map +0 -1
  350. package/dist/recorder/hooks/useStreamPreview.d.ts +0 -22
  351. package/dist/recorder/hooks/useStreamPreview.d.ts.map +0 -1
  352. package/dist/recorder/hooks/useStreamPreview.js +0 -44
  353. package/dist/recorder/hooks/useStreamPreview.js.map +0 -1
  354. package/dist/recorder/sources/cameraStream.d.ts +0 -22
  355. package/dist/recorder/sources/cameraStream.d.ts.map +0 -1
  356. package/dist/recorder/sources/cameraStream.js +0 -24
  357. package/dist/recorder/sources/cameraStream.js.map +0 -1
  358. package/dist/recorder/sources/micStream.d.ts +0 -15
  359. package/dist/recorder/sources/micStream.d.ts.map +0 -1
  360. package/dist/recorder/sources/micStream.js +0 -24
  361. package/dist/recorder/sources/micStream.js.map +0 -1
  362. package/dist/recorder/sources/screenStream.d.ts +0 -53
  363. package/dist/recorder/sources/screenStream.d.ts.map +0 -1
  364. package/dist/recorder/sources/screenStream.js +0 -114
  365. package/dist/recorder/sources/screenStream.js.map +0 -1
  366. package/dist/recorder/timingJson.d.ts +0 -51
  367. package/dist/recorder/timingJson.d.ts.map +0 -1
  368. package/dist/recorder/timingJson.js +0 -42
  369. package/dist/recorder/timingJson.js.map +0 -1
  370. package/dist/tiptap/TiptapAudio.d.ts +0 -26
  371. package/dist/tiptap/TiptapAudio.d.ts.map +0 -1
  372. package/dist/tiptap/TiptapAudio.js +0 -58
  373. package/dist/tiptap/TiptapAudio.js.map +0 -1
  374. package/dist/tiptap/TiptapVideo.d.ts +0 -30
  375. package/dist/tiptap/TiptapVideo.d.ts.map +0 -1
  376. package/dist/tiptap/TiptapVideo.js +0 -66
  377. package/dist/tiptap/TiptapVideo.js.map +0 -1
  378. package/dist/tiptap/useResolvedMediaSrc.d.ts +0 -2
  379. package/dist/tiptap/useResolvedMediaSrc.d.ts.map +0 -1
  380. package/dist/tiptap/useResolvedMediaSrc.js +0 -42
  381. package/dist/tiptap/useResolvedMediaSrc.js.map +0 -1
  382. package/dist/tiptapBridge.d.ts +0 -24
  383. package/dist/tiptapBridge.d.ts.map +0 -1
  384. package/dist/tiptapBridge.js +0 -749
  385. package/dist/tiptapBridge.js.map +0 -1
  386. package/dist/useHeadingLayout.d.ts +0 -54
  387. package/dist/useHeadingLayout.d.ts.map +0 -1
  388. package/dist/useHeadingLayout.js +0 -260
  389. package/dist/useHeadingLayout.js.map +0 -1
  390. package/dist/utils/collectInlineFontAwesomeCss.d.ts +0 -21
  391. package/dist/utils/collectInlineFontAwesomeCss.d.ts.map +0 -1
  392. package/dist/utils/collectInlineFontAwesomeCss.js +0 -68
  393. package/dist/utils/collectInlineFontAwesomeCss.js.map +0 -1
  394. package/dist/utils/dropUtils.d.ts +0 -55
  395. package/dist/utils/dropUtils.d.ts.map +0 -1
  396. package/dist/utils/dropUtils.js +0 -110
  397. package/dist/utils/dropUtils.js.map +0 -1
  398. package/dist/utils/normalizeMalformedAssetUrl.d.ts +0 -15
  399. package/dist/utils/normalizeMalformedAssetUrl.d.ts.map +0 -1
  400. package/dist/utils/normalizeMalformedAssetUrl.js +0 -27
  401. package/dist/utils/normalizeMalformedAssetUrl.js.map +0 -1
package/dist/Toolbar.js DELETED
@@ -1,1001 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react';
3
- import { useEditorContext } from './EditorContext';
4
- import { VersionHistoryPanel } from './VersionHistoryPanel';
5
- import { RecorderEntry } from './RecorderEntry';
6
- import { ViewMenuPanel } from './ViewMenuPanel';
7
- import { TemplatePicker, TEMPLATE_NAMES } from './TemplatePicker';
8
- import { profileBlockContents, recommendTemplatesForBlock } from '@bendyline/squisq/recommend';
9
- import { findBlockSliceAtLine, findBlockSliceByHeadingIndex } from './blockSlice';
10
- import { LinkDialog } from './LinkDialog';
11
- import { DocumentSettingsDialog } from './DocumentSettingsDialog';
12
- import { EmojiPicker, EMOJI_PICKER_WIDTH, EMOJI_PICKER_MAX_HEIGHT } from './EmojiPicker';
13
- import { createPortal } from 'react-dom';
14
- const VIEWS = [
15
- { id: 'wysiwyg', label: 'Editor', shortcut: '⌘1' },
16
- { id: 'raw', label: 'Markdown', shortLabel: 'MD', shortcut: '⌘2' },
17
- { id: 'preview', label: 'Play', shortcut: '⌘3' },
18
- ];
19
- const BUTTONS = [
20
- // Format group — B/I/S trio.
21
- {
22
- id: 'bold',
23
- label: 'B',
24
- icon: 'B',
25
- title: 'Bold (Ctrl+B)',
26
- group: 'format',
27
- iconStyle: { fontWeight: 700 },
28
- },
29
- {
30
- id: 'italic',
31
- label: 'I',
32
- icon: 'I',
33
- title: 'Italic (Ctrl+I)',
34
- group: 'format',
35
- iconStyle: { fontStyle: 'italic' },
36
- },
37
- {
38
- id: 'strikethrough',
39
- label: 'S',
40
- icon: 'S',
41
- title: 'Strikethrough',
42
- group: 'format',
43
- iconStyle: { textDecoration: 'line-through' },
44
- },
45
- // Lists group — sits between format and structure so bullets/numbers
46
- // are adjacent to the inline formatters people reach for together.
47
- { id: 'ul', label: '•', icon: '•', title: 'Bullet list', group: 'lists' },
48
- { id: 'ol', label: '1.', icon: '1.', title: 'Numbered list', group: 'lists' },
49
- // Structure group
50
- { id: 'h1', label: 'H1', icon: 'H1', title: 'Heading 1', group: 'structure' },
51
- { id: 'h2', label: 'H2', icon: 'H2', title: 'Heading 2', group: 'structure' },
52
- { id: 'h3', label: 'H3', icon: 'H3', title: 'Heading 3', group: 'structure' },
53
- { id: 'h4', label: 'H4', icon: 'H4', title: 'Heading 4', group: 'structure' },
54
- { id: 'h5', label: 'H5', icon: 'H5', title: 'Heading 5', group: 'structure' },
55
- { id: 'h6', label: 'H6', icon: 'H6', title: 'Heading 6', group: 'structure' },
56
- // Insert group — block-level inserts (quote, code blocks, rules)
57
- { id: 'quote', label: '❝', icon: '❝', title: 'Blockquote', group: 'insert' },
58
- { id: 'codeblock', label: '{ }', icon: '{ }', title: 'Code block', group: 'insert' },
59
- { id: 'code', label: '</>', icon: '</>', title: 'Inline code', group: 'insert' },
60
- { id: 'hr', label: '—', icon: '—', title: 'Horizontal rule', group: 'insert' },
61
- // Media group — links, tables, images, emoji
62
- { id: 'link', label: '🔗', icon: '🔗', title: 'Insert link', group: 'media' },
63
- { id: 'table', label: 'table', icon: '', title: 'Insert table', group: 'media' },
64
- { id: 'image', label: '🖼', icon: '🖼', title: 'Insert image', group: 'media' },
65
- { id: 'emoji', label: '😊', icon: '😊', title: 'Insert emoji', group: 'media' },
66
- ];
67
- // ─── Inline SVG icons (line-art, currentColor) ──────────
68
- const TABLE_ICON = (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", children: [_jsx("rect", { x: "1", y: "1", width: "12", height: "12", rx: "1" }), _jsx("line", { x1: "1", y1: "5", x2: "13", y2: "5" }), _jsx("line", { x1: "1", y1: "9", x2: "13", y2: "9" }), _jsx("line", { x1: "5", y1: "1", x2: "5", y2: "13" }), _jsx("line", { x1: "9", y1: "1", x2: "9", y2: "13" })] }));
69
- const LINK_ICON = (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M5.75 8.25 L8.25 5.75" }), _jsx("path", { d: "M6.5 3.75 L8 2.25 a2.5 2.5 0 0 1 3.54 3.54 L10 7.25" }), _jsx("path", { d: "M7.5 10.25 L6 11.75 a2.5 2.5 0 0 1 -3.54 -3.54 L4 6.75" })] }));
70
- const IMAGE_ICON = (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("rect", { x: "1.5", y: "2.5", width: "11", height: "9", rx: "1" }), _jsx("circle", { cx: "5", cy: "5.5", r: "0.9" }), _jsx("path", { d: "M2 10 L5.5 7 L8 9 L10 7.5 L12.5 10" })] }));
71
- const PAPERCLIP_ICON = (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("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" }) }));
72
- const EMOJI_ICON = (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("circle", { cx: "7", cy: "7", r: "5.25" }), _jsx("circle", { cx: "5.25", cy: "5.75", r: "0.6", fill: "currentColor", stroke: "none" }), _jsx("circle", { cx: "8.75", cy: "5.75", r: "0.6", fill: "currentColor", stroke: "none" }), _jsx("path", { d: "M4.75 8.5 a2.5 2.5 0 0 0 4.5 0" })] }));
73
- /** Returns an SVG element when the button id maps to one, otherwise null. */
74
- function buttonIconSvg(id) {
75
- switch (id) {
76
- case 'table':
77
- return TABLE_ICON;
78
- case 'link':
79
- return LINK_ICON;
80
- case 'image':
81
- return IMAGE_ICON;
82
- case 'emoji':
83
- return EMOJI_ICON;
84
- default:
85
- return null;
86
- }
87
- }
88
- // ─── Tiptap active-state map ────────────────────────────
89
- /** Returns true if the given button id is currently active in Tiptap */
90
- function isTiptapActive(editor, id) {
91
- if (!editor)
92
- return false;
93
- switch (id) {
94
- case 'bold':
95
- return editor.isActive('bold');
96
- case 'italic':
97
- return editor.isActive('italic');
98
- case 'strikethrough':
99
- return editor.isActive('strike');
100
- case 'code':
101
- return editor.isActive('code');
102
- case 'h1':
103
- return editor.isActive('heading', { level: 1 });
104
- case 'h2':
105
- return editor.isActive('heading', { level: 2 });
106
- case 'h3':
107
- return editor.isActive('heading', { level: 3 });
108
- case 'h4':
109
- return editor.isActive('heading', { level: 4 });
110
- case 'h5':
111
- return editor.isActive('heading', { level: 5 });
112
- case 'h6':
113
- return editor.isActive('heading', { level: 6 });
114
- case 'quote':
115
- return editor.isActive('blockquote');
116
- case 'ul':
117
- return editor.isActive('bulletList');
118
- case 'ol':
119
- return editor.isActive('orderedList');
120
- case 'codeblock':
121
- return editor.isActive('codeBlock');
122
- default:
123
- return false;
124
- }
125
- }
126
- /**
127
- * Formatting toolbar.
128
- * - WYSIWYG: calls Tiptap chain commands (toggleBold, etc.)
129
- * - Raw: appends markdown syntax to the source
130
- */
131
- export function Toolbar({ className, showFiles, onToggleFiles, slotLeft, slotAfterActions, slotRight, showPlayTab = true, }) {
132
- const { activeView, setActiveView, markdownSource, setMarkdownSource, tiptapEditor, monacoEditor, mediaProvider, editorMode, versioning, allowRecording, documentLinkProvider, theme, } = useEditorContext();
133
- const isCodeMode = editorMode === 'code';
134
- // In code mode only the raw view is meaningful; the WYSIWYG and Preview
135
- // surfaces aren't mounted, so hide their tabs.
136
- const visibleViews = VIEWS.filter((v) => {
137
- if (isCodeMode)
138
- return v.id === 'raw';
139
- if (v.id === 'preview' && !showPlayTab)
140
- return false;
141
- return true;
142
- });
143
- const showViewTabs = visibleViews.length > 1;
144
- // Hidden file input for image picker
145
- const imageInputRef = useRef(null);
146
- // Link dialog — shared by WYSIWYG and Raw views.
147
- const [linkDialog, setLinkDialog] = useState(null);
148
- // Emoji picker — toolbar-anchored popover. We track the trigger
149
- // button's screen rect so the picker can position itself just below
150
- // it via createPortal (the toolbar's overflow:hidden actions row
151
- // would otherwise clip the popover).
152
- const emojiButtonRef = useRef(null);
153
- const [emojiPickerAnchor, setEmojiPickerAnchor] = useState(null);
154
- const openEmojiPicker = useCallback(() => {
155
- const btn = emojiButtonRef.current;
156
- if (!btn)
157
- return;
158
- const rect = btn.getBoundingClientRect();
159
- // Position just below the trigger by default, then clamp into the
160
- // visible viewport so the picker is never clipped on the right or
161
- // bottom — flips above the trigger when there isn't room below.
162
- const gap = 6;
163
- const margin = 8;
164
- const vw = window.innerWidth;
165
- const vh = window.innerHeight;
166
- let left = rect.left;
167
- if (left + EMOJI_PICKER_WIDTH + margin > vw) {
168
- left = Math.max(margin, vw - EMOJI_PICKER_WIDTH - margin);
169
- }
170
- let top = rect.bottom + gap;
171
- if (top + EMOJI_PICKER_MAX_HEIGHT + margin > vh) {
172
- const flipped = rect.top - EMOJI_PICKER_MAX_HEIGHT - gap;
173
- // Prefer flipping above when there's more room there; otherwise
174
- // pin to the top edge with margin and let the picker's own
175
- // maxHeight clip it.
176
- top = flipped >= margin ? flipped : margin;
177
- }
178
- setEmojiPickerAnchor({ top, left });
179
- }, []);
180
- const closeEmojiPicker = useCallback(() => setEmojiPickerAnchor(null), []);
181
- // ── Narrow-screen detection ──────────────────────────
182
- const [isNarrow, setIsNarrow] = useState(() => typeof window !== 'undefined' && window.matchMedia('(max-width: 768px)').matches);
183
- useEffect(() => {
184
- const mq = window.matchMedia('(max-width: 768px)');
185
- const handler = (e) => setIsNarrow(e.matches);
186
- mq.addEventListener('change', handler);
187
- return () => mq.removeEventListener('change', handler);
188
- }, []);
189
- // ── Overflow detection ────────────────────────────────
190
- const actionsRef = useRef(null);
191
- const [measuredOverflowIndex, setMeasuredOverflowIndex] = useState(null);
192
- const [showOverflow, setShowOverflow] = useState(false);
193
- const overflowRef = useRef(null);
194
- // Document settings (frontmatter) dialog
195
- const [showDocSettings, setShowDocSettings] = useState(false);
196
- // On narrow screens, force all buttons into the overflow menu
197
- const overflowIndex = isNarrow ? 0 : measuredOverflowIndex;
198
- useEffect(() => {
199
- if (isNarrow)
200
- return; // Skip measurement on narrow — everything overflows
201
- const container = actionsRef.current;
202
- if (!container)
203
- return;
204
- const measure = () => {
205
- const containerRight = container.getBoundingClientRect().right;
206
- const children = container.querySelectorAll(':scope > .squisq-toolbar-group > .squisq-toolbar-button');
207
- let firstHidden = null;
208
- children.forEach((child, i) => {
209
- if (firstHidden !== null)
210
- return;
211
- const rect = child.getBoundingClientRect();
212
- // A button is hidden if its right edge extends past the container
213
- if (rect.right > containerRight + 2) {
214
- firstHidden = i;
215
- }
216
- });
217
- setMeasuredOverflowIndex(firstHidden);
218
- };
219
- const ro = new ResizeObserver(measure);
220
- ro.observe(container);
221
- measure();
222
- return () => ro.disconnect();
223
- }, [activeView, isNarrow]);
224
- // Close overflow menu on outside click
225
- useEffect(() => {
226
- if (!showOverflow)
227
- return;
228
- const handleClick = (e) => {
229
- if (overflowRef.current && !overflowRef.current.contains(e.target)) {
230
- setShowOverflow(false);
231
- }
232
- };
233
- document.addEventListener('mousedown', handleClick);
234
- return () => document.removeEventListener('mousedown', handleClick);
235
- }, [showOverflow]);
236
- // Open-up vs open-down: the overflow menu is anchored to its trigger with
237
- // `top: 100%` by default. When the toolbar lives near the bottom of a
238
- // small container (e.g. a chat composer), a downward menu gets clipped.
239
- // Measure on open and flip the anchor to `bottom: 100%` if the space
240
- // above the trigger is larger than the space below.
241
- const [overflowPlacement, setOverflowPlacement] = useState('down');
242
- useEffect(() => {
243
- if (!showOverflow || !overflowRef.current)
244
- return;
245
- const trigger = overflowRef.current.querySelector('.squisq-toolbar-overflow-trigger');
246
- if (!trigger)
247
- return;
248
- const rect = trigger.getBoundingClientRect();
249
- const spaceBelow = window.innerHeight - rect.bottom;
250
- const spaceAbove = rect.top;
251
- // Assume a typical menu height; exact measurement is unreliable on first
252
- // open because the menu hasn't rendered yet when this runs.
253
- const ESTIMATED_MENU_HEIGHT = 260;
254
- if (spaceBelow < ESTIMATED_MENU_HEIGHT && spaceAbove > spaceBelow) {
255
- setOverflowPlacement('up');
256
- }
257
- else {
258
- setOverflowPlacement('down');
259
- }
260
- }, [showOverflow]);
261
- // Force re-render when Tiptap selection or formatting state changes
262
- const [, forceUpdate] = useReducer((c) => c + 1, 0);
263
- useEffect(() => {
264
- if (!tiptapEditor)
265
- return;
266
- tiptapEditor.on('transaction', forceUpdate);
267
- return () => {
268
- tiptapEditor.off('transaction', forceUpdate);
269
- };
270
- }, [tiptapEditor]);
271
- // ── Tiptap handler ─────────────────────────────────────
272
- const handleTiptap = useCallback((id) => {
273
- if (!tiptapEditor)
274
- return;
275
- const chain = tiptapEditor.chain().focus();
276
- switch (id) {
277
- case 'bold':
278
- chain.toggleBold().run();
279
- break;
280
- case 'italic':
281
- chain.toggleItalic().run();
282
- break;
283
- case 'strikethrough':
284
- chain.toggleStrike().run();
285
- break;
286
- case 'code':
287
- chain.toggleCode().run();
288
- break;
289
- case 'h1':
290
- chain.toggleHeading({ level: 1 }).run();
291
- break;
292
- case 'h2':
293
- chain.toggleHeading({ level: 2 }).run();
294
- break;
295
- case 'h3':
296
- chain.toggleHeading({ level: 3 }).run();
297
- break;
298
- case 'h4':
299
- chain.toggleHeading({ level: 4 }).run();
300
- break;
301
- case 'h5':
302
- chain.toggleHeading({ level: 5 }).run();
303
- break;
304
- case 'h6':
305
- chain.toggleHeading({ level: 6 }).run();
306
- break;
307
- case 'quote':
308
- chain.toggleBlockquote().run();
309
- break;
310
- case 'ul':
311
- chain.toggleBulletList().run();
312
- break;
313
- case 'ol':
314
- chain.toggleOrderedList().run();
315
- break;
316
- case 'codeblock':
317
- chain.toggleCodeBlock().run();
318
- break;
319
- case 'hr':
320
- chain.setHorizontalRule().run();
321
- break;
322
- case 'link': {
323
- const isActive = tiptapEditor.isActive('link');
324
- let initialText = '';
325
- let initialUrl = '';
326
- if (isActive) {
327
- // Snap selection to the full link mark so editing replaces
328
- // the entire `[text](url)` rather than just the cursor word.
329
- tiptapEditor.chain().focus().extendMarkRange('link').run();
330
- const sel = tiptapEditor.state.selection;
331
- initialText = tiptapEditor.state.doc.textBetween(sel.from, sel.to, ' ');
332
- initialUrl = tiptapEditor.getAttributes('link').href ?? '';
333
- }
334
- else {
335
- const { from, to, empty } = tiptapEditor.state.selection;
336
- if (!empty) {
337
- initialText = tiptapEditor.state.doc.textBetween(from, to, ' ');
338
- }
339
- }
340
- setLinkDialog({
341
- mode: isActive ? 'update' : 'insert',
342
- target: 'wysiwyg',
343
- initialText,
344
- initialUrl,
345
- rawRange: null,
346
- });
347
- break;
348
- }
349
- case 'table':
350
- tiptapEditor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
351
- break;
352
- }
353
- }, [tiptapEditor]);
354
- // ── Raw markdown handler ───────────────────────────────
355
- const handleRaw = useCallback((id) => {
356
- if (monacoEditor) {
357
- // Use Monaco's selection API for proper wrap/insert behavior
358
- const selection = monacoEditor.getSelection();
359
- const model = monacoEditor.getModel();
360
- if (!selection || !model)
361
- return;
362
- const selectedText = model.getValueInRange(selection);
363
- const hasSelection = selectedText.length > 0;
364
- let replacement = '';
365
- let newCursorOffset = 0; // offset from start of replacement to place cursor
366
- // Inline wrapping: wrap selection or insert placeholder
367
- const wrapInline = (before, after, placeholder) => {
368
- if (hasSelection) {
369
- replacement = before + selectedText + after;
370
- }
371
- else {
372
- replacement = before + placeholder + after;
373
- // Select the placeholder text after insertion
374
- newCursorOffset = before.length;
375
- }
376
- };
377
- // Block-level: prefix each selected line, or insert a new block
378
- const prefixLines = (prefix, placeholder) => {
379
- if (hasSelection) {
380
- replacement = selectedText
381
- .split('\n')
382
- .map((line) => prefix + line)
383
- .join('\n');
384
- }
385
- else {
386
- replacement = prefix + placeholder;
387
- newCursorOffset = prefix.length;
388
- }
389
- };
390
- switch (id) {
391
- case 'bold':
392
- wrapInline('**', '**', 'bold text');
393
- break;
394
- case 'italic':
395
- wrapInline('*', '*', 'italic text');
396
- break;
397
- case 'strikethrough':
398
- wrapInline('~~', '~~', 'strikethrough');
399
- break;
400
- case 'code':
401
- wrapInline('`', '`', 'code');
402
- break;
403
- case 'h1':
404
- prefixLines('# ', 'Heading 1');
405
- break;
406
- case 'h2':
407
- prefixLines('## ', 'Heading 2');
408
- break;
409
- case 'h3':
410
- prefixLines('### ', 'Heading 3');
411
- break;
412
- case 'h4':
413
- prefixLines('#### ', 'Heading 4');
414
- break;
415
- case 'h5':
416
- prefixLines('##### ', 'Heading 5');
417
- break;
418
- case 'h6':
419
- prefixLines('###### ', 'Heading 6');
420
- break;
421
- case 'quote':
422
- prefixLines('> ', 'Quote');
423
- break;
424
- case 'ul':
425
- prefixLines('- ', 'Item');
426
- break;
427
- case 'ol':
428
- prefixLines('1. ', 'Item');
429
- break;
430
- case 'codeblock': {
431
- const inner = hasSelection ? selectedText : 'code';
432
- replacement = '```\n' + inner + '\n```';
433
- if (!hasSelection)
434
- newCursorOffset = 4; // after ```\n
435
- break;
436
- }
437
- case 'hr': {
438
- replacement = '\n---\n';
439
- break;
440
- }
441
- case 'link': {
442
- // Open the LinkDialog instead of inserting literal text. If the
443
- // cursor sits inside an existing `[text](url)` on this line,
444
- // prefill from it and replace the whole match on confirm.
445
- const lineNumber = selection.startLineNumber;
446
- const lineText = model.getLineContent(lineNumber);
447
- const cursorCol = selection.startColumn;
448
- const linkRe = /\[([^\]]*)\]\(([^)]*)\)/g;
449
- let match;
450
- let existing = null;
451
- while ((match = linkRe.exec(lineText)) !== null) {
452
- const startCol = match.index + 1; // 1-based
453
- const endCol = startCol + match[0].length;
454
- if (cursorCol >= startCol && cursorCol <= endCol) {
455
- existing = {
456
- text: match[1],
457
- url: match[2],
458
- range: {
459
- startLineNumber: lineNumber,
460
- startColumn: startCol,
461
- endLineNumber: lineNumber,
462
- endColumn: endCol,
463
- },
464
- };
465
- break;
466
- }
467
- }
468
- setLinkDialog({
469
- mode: existing ? 'update' : 'insert',
470
- target: 'raw',
471
- initialText: existing ? existing.text : hasSelection ? selectedText : '',
472
- initialUrl: existing ? existing.url : '',
473
- rawRange: existing ? existing.range : null,
474
- });
475
- // Skip the executeEdits/setPosition tail below — the dialog will
476
- // apply its own edit on confirm.
477
- return;
478
- }
479
- case 'table': {
480
- const tpl = '| Header 1 | Header 2 | Header 3 |\n| --- | --- | --- |\n| Cell | Cell | Cell |\n| Cell | Cell | Cell |';
481
- replacement = '\n' + tpl + '\n';
482
- newCursorOffset = 3; // after \n|
483
- break;
484
- }
485
- }
486
- // Apply the edit via Monaco's executeEdits for proper undo support
487
- const range = selection;
488
- monacoEditor.executeEdits('toolbar', [{ range, text: replacement }]);
489
- // If no selection, select the placeholder text so user can type over it
490
- if (!hasSelection && newCursorOffset > 0) {
491
- const startPos = model.getPositionAt(model.getOffsetAt(range.getStartPosition()) + newCursorOffset);
492
- // Just place cursor after the prefix
493
- monacoEditor.setPosition(startPos);
494
- }
495
- monacoEditor.focus();
496
- }
497
- else {
498
- // Fallback: no Monaco instance, just append
499
- let insertion = '';
500
- switch (id) {
501
- case 'bold':
502
- insertion = '**bold text**';
503
- break;
504
- case 'italic':
505
- insertion = '*italic text*';
506
- break;
507
- case 'strikethrough':
508
- insertion = '~~strikethrough~~';
509
- break;
510
- case 'code':
511
- insertion = '`code`';
512
- break;
513
- case 'h1':
514
- insertion = '\n# Heading 1\n';
515
- break;
516
- case 'h2':
517
- insertion = '\n## Heading 2\n';
518
- break;
519
- case 'h3':
520
- insertion = '\n### Heading 3\n';
521
- break;
522
- case 'quote':
523
- insertion = '\n> Quote\n';
524
- break;
525
- case 'ul':
526
- insertion = '\n- Item\n';
527
- break;
528
- case 'ol':
529
- insertion = '\n1. Item\n';
530
- break;
531
- case 'codeblock':
532
- insertion = '\n```\ncode\n```\n';
533
- break;
534
- case 'hr':
535
- insertion = '\n---\n';
536
- break;
537
- case 'link':
538
- insertion = '[link text](url)';
539
- break;
540
- case 'table':
541
- insertion =
542
- '\n| Header 1 | Header 2 | Header 3 |\n| --- | --- | --- |\n| Cell | Cell | Cell |\n| Cell | Cell | Cell |\n';
543
- break;
544
- }
545
- if (insertion) {
546
- setMarkdownSource(markdownSource + insertion);
547
- }
548
- }
549
- }, [monacoEditor, markdownSource, setMarkdownSource]);
550
- // ── Image upload handler ───────────────────────────────
551
- const handleImageFile = useCallback(async (file) => {
552
- if (!mediaProvider)
553
- return;
554
- const buffer = await file.arrayBuffer();
555
- const relativePath = await mediaProvider.addMedia(file.name, buffer, file.type);
556
- const altText = file.name.replace(/\.[^.]+$/, '').replace(/[-_]/g, ' ');
557
- if (activeView === 'wysiwyg' && tiptapEditor) {
558
- tiptapEditor.chain().focus().setImage({ src: relativePath, alt: altText }).run();
559
- }
560
- else if (monacoEditor) {
561
- const selection = monacoEditor.getSelection();
562
- const model = monacoEditor.getModel();
563
- if (selection && model) {
564
- const md = `![${altText}](${relativePath})`;
565
- monacoEditor.executeEdits('toolbar', [{ range: selection, text: md }]);
566
- monacoEditor.focus();
567
- }
568
- }
569
- else {
570
- setMarkdownSource(markdownSource + `\n![${altText}](${relativePath})\n`);
571
- }
572
- }, [mediaProvider, activeView, tiptapEditor, monacoEditor, markdownSource, setMarkdownSource]);
573
- const handleAction = useCallback((id) => {
574
- if (id === 'image') {
575
- imageInputRef.current?.click();
576
- return;
577
- }
578
- if (id === 'emoji') {
579
- // Toggle the popover: clicking the button again closes it.
580
- if (emojiPickerAnchor)
581
- closeEmojiPicker();
582
- else
583
- openEmojiPicker();
584
- return;
585
- }
586
- if (activeView === 'wysiwyg' && tiptapEditor) {
587
- handleTiptap(id);
588
- }
589
- else {
590
- handleRaw(id);
591
- }
592
- }, [
593
- activeView,
594
- tiptapEditor,
595
- handleTiptap,
596
- handleRaw,
597
- emojiPickerAnchor,
598
- openEmojiPicker,
599
- closeEmojiPicker,
600
- ]);
601
- // ── Picker insert (emoji or FontAwesome icon) ──────
602
- // Inserts a chosen picker entry at the cursor. We bypass
603
- // `insertAtCursor` (which routes through markdown→Tiptap conversion
604
- // and wraps the input in a paragraph) so entries land inline at the
605
- // caret rather than starting a new block. Emoji insert as a plain
606
- // character; FontAwesome icons insert as the `InlineIcon` Tiptap
607
- // node so the editor renders them inline immediately.
608
- const handleEmojiSelect = useCallback((entry) => {
609
- if (activeView === 'wysiwyg' && tiptapEditor) {
610
- if (entry.kind === 'emoji') {
611
- tiptapEditor.chain().focus().insertContent(entry.char).run();
612
- }
613
- else {
614
- tiptapEditor
615
- .chain()
616
- .focus()
617
- .insertContent({
618
- type: 'inlineIcon',
619
- attrs: { token: entry.token, family: entry.family, name: entry.name },
620
- })
621
- .run();
622
- }
623
- }
624
- else if (activeView === 'raw' && monacoEditor) {
625
- const insertion = entry.kind === 'emoji' ? entry.char : `{[${entry.token}]}`;
626
- const position = monacoEditor.getPosition();
627
- if (position) {
628
- const range = {
629
- startLineNumber: position.lineNumber,
630
- startColumn: position.column,
631
- endLineNumber: position.lineNumber,
632
- endColumn: position.column,
633
- };
634
- monacoEditor.executeEdits('picker-insert', [{ range, text: insertion }]);
635
- monacoEditor.focus();
636
- }
637
- else {
638
- setMarkdownSource(markdownSource + insertion);
639
- }
640
- }
641
- else {
642
- const insertion = entry.kind === 'emoji' ? entry.char : `{[${entry.token}]}`;
643
- setMarkdownSource(markdownSource + insertion);
644
- }
645
- closeEmojiPicker();
646
- }, [activeView, tiptapEditor, monacoEditor, markdownSource, setMarkdownSource, closeEmojiPicker]);
647
- // ── Ctrl+K / Cmd+K → open the link dialog ────────────
648
- // Mirrors the behaviour of common editors (Word, Google Docs, VS Code's
649
- // Markdown preview): if the cursor is in a Squisq editor surface, the
650
- // shortcut routes through the same handler the toolbar Link button uses,
651
- // which prefills the dialog from the current selection (or the link
652
- // under the cursor) before opening.
653
- useEffect(() => {
654
- const onKeyDown = (e) => {
655
- if (!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey)
656
- return;
657
- if (e.key.toLowerCase() !== 'k')
658
- return;
659
- const target = e.target;
660
- if (!target)
661
- return;
662
- // Only intercept when focus is inside one of our editor surfaces.
663
- const inEditor = !!target.closest('.squisq-wysiwyg-editor, .ProseMirror, .squisq-raw-editor-container, .monaco-editor');
664
- if (!inEditor)
665
- return;
666
- e.preventDefault();
667
- e.stopPropagation();
668
- handleAction('link');
669
- };
670
- window.addEventListener('keydown', onKeyDown, true);
671
- return () => window.removeEventListener('keydown', onKeyDown, true);
672
- }, [handleAction]);
673
- // ── Link dialog confirm ──────────────────────────────
674
- const handleLinkConfirm = useCallback((text, url) => {
675
- if (!linkDialog)
676
- return;
677
- const trimmedUrl = url.trim();
678
- const trimmedText = text.trim();
679
- if (linkDialog.target === 'wysiwyg' && tiptapEditor) {
680
- if (!trimmedUrl) {
681
- // Empty URL on update = unlink. On insert with no URL, do nothing.
682
- if (linkDialog.mode === 'update') {
683
- tiptapEditor.chain().focus().unsetLink().run();
684
- }
685
- setLinkDialog(null);
686
- return;
687
- }
688
- const visibleText = trimmedText || trimmedUrl;
689
- const chain = tiptapEditor.chain().focus();
690
- // Insert (or replace selection) with text carrying a link mark. When
691
- // updating an existing link, the selection was extended to the full
692
- // mark range earlier, so this replaces the entire `[text](url)`.
693
- chain
694
- .insertContent({
695
- type: 'text',
696
- text: visibleText,
697
- marks: [{ type: 'link', attrs: { href: trimmedUrl } }],
698
- })
699
- .run();
700
- setLinkDialog(null);
701
- return;
702
- }
703
- if (linkDialog.target === 'raw' && monacoEditor) {
704
- const model = monacoEditor.getModel();
705
- if (!model) {
706
- setLinkDialog(null);
707
- return;
708
- }
709
- if (!trimmedUrl && linkDialog.mode === 'update' && linkDialog.rawRange) {
710
- // Empty URL on update = strip the markdown link, keep the text.
711
- monacoEditor.executeEdits('toolbar-link-edit', [
712
- { range: linkDialog.rawRange, text: trimmedText || linkDialog.initialText },
713
- ]);
714
- monacoEditor.focus();
715
- setLinkDialog(null);
716
- return;
717
- }
718
- if (!trimmedUrl) {
719
- setLinkDialog(null);
720
- return;
721
- }
722
- const visibleText = trimmedText || trimmedUrl;
723
- const replacement = `[${visibleText}](${trimmedUrl})`;
724
- const range = linkDialog.rawRange ?? monacoEditor.getSelection();
725
- if (!range) {
726
- setLinkDialog(null);
727
- return;
728
- }
729
- monacoEditor.executeEdits('toolbar-link-edit', [{ range, text: replacement }]);
730
- monacoEditor.focus();
731
- setLinkDialog(null);
732
- return;
733
- }
734
- setLinkDialog(null);
735
- }, [linkDialog, tiptapEditor, monacoEditor]);
736
- const groups = ['format', 'lists', 'structure', 'insert', 'media'];
737
- const isWysiwyg = activeView === 'wysiwyg' && tiptapEditor;
738
- const isPreview = activeView === 'preview';
739
- // ── Progressive heading disclosure ───────────────────
740
- // H1\u2013H3 are always visible. H4 appears once the document already
741
- // contains an H3, H5 once it contains an H4, and H6 once it contains
742
- // an H5. This keeps the toolbar compact for typical short documents
743
- // while letting deeply nested documents reach every level.
744
- const maxHeadingLevelInDoc = useMemo(() => {
745
- if (!markdownSource)
746
- return 0;
747
- let max = 0;
748
- let inFence = false;
749
- for (const rawLine of markdownSource.split('\n')) {
750
- const line = rawLine.trimEnd();
751
- if (/^\s*```/.test(line)) {
752
- inFence = !inFence;
753
- continue;
754
- }
755
- if (inFence)
756
- continue;
757
- const m = /^(#{1,6})\s+\S/.exec(line);
758
- if (m && m[1].length > max)
759
- max = m[1].length;
760
- }
761
- return max;
762
- }, [markdownSource]);
763
- // Show H(n+1) when the document already contains H(n), starting from H3.
764
- const visibleHeadingMax = Math.min(6, Math.max(3, maxHeadingLevelInDoc + 1));
765
- const isButtonVisible = (id) => {
766
- const m = /^h([1-6])$/.exec(id);
767
- if (!m)
768
- return true;
769
- return Number(m[1]) <= visibleHeadingMax;
770
- };
771
- // Detect whether cursor is inside a table (WYSIWYG mode only)
772
- const isInTable = isWysiwyg ? tiptapEditor.isActive('table') : false;
773
- // Detect current heading template (WYSIWYG mode only)
774
- const wysiwygTemplate = isWysiwyg
775
- ? tiptapEditor.isActive('heading')
776
- ? (tiptapEditor.getAttributes('heading')?.dataTemplate ?? '')
777
- : null
778
- : null;
779
- // ── Monaco heading detection (Markdown view) ─────────────────────
780
- // Watch the Monaco cursor and surface the template picker whenever the
781
- // cursor is on a heading line. `null` hides the picker; '' shows it
782
- // with no template selected; any other string is the current template.
783
- const isRawView = activeView === 'raw';
784
- const [rawTemplate, setRawTemplate] = useState(null);
785
- const [rawHeadingLine, setRawHeadingLine] = useState(null);
786
- useEffect(() => {
787
- if (!isRawView || !monacoEditor) {
788
- setRawTemplate(null);
789
- setRawHeadingLine(null);
790
- return;
791
- }
792
- const recompute = () => {
793
- const model = monacoEditor.getModel();
794
- const pos = monacoEditor.getPosition();
795
- if (!model || !pos) {
796
- setRawTemplate(null);
797
- setRawHeadingLine(null);
798
- return;
799
- }
800
- const line = model.getLineContent(pos.lineNumber);
801
- const headingMatch = line.match(/^#{1,6}\s+(.+)$/);
802
- if (!headingMatch) {
803
- setRawTemplate(null);
804
- setRawHeadingLine(null);
805
- return;
806
- }
807
- setRawHeadingLine(pos.lineNumber);
808
- const annotMatch = headingMatch[1].match(/\s*\{\[([^\]]+)\]\}[\s\]}]*$/);
809
- if (annotMatch) {
810
- // First whitespace-delimited token is the template name; the rest are params.
811
- const name = annotMatch[1].trim().split(/\s+/)[0];
812
- setRawTemplate(name);
813
- }
814
- else {
815
- setRawTemplate('');
816
- }
817
- };
818
- recompute();
819
- const cursorSub = monacoEditor.onDidChangeCursorPosition(recompute);
820
- const contentSub = monacoEditor.onDidChangeModelContent(recompute);
821
- return () => {
822
- cursorSub.dispose();
823
- contentSub.dispose();
824
- };
825
- }, [isRawView, monacoEditor]);
826
- // Track the index of the heading the WYSIWYG cursor is in among all
827
- // top-level headings. Used to locate the same heading in the markdown
828
- // source for content-based template recommendations.
829
- const [wysiwygHeadingIndex, setWysiwygHeadingIndex] = useState(null);
830
- useEffect(() => {
831
- if (!isWysiwyg || !tiptapEditor) {
832
- setWysiwygHeadingIndex(null);
833
- return;
834
- }
835
- const recompute = () => {
836
- if (!tiptapEditor.isActive('heading')) {
837
- setWysiwygHeadingIndex(null);
838
- return;
839
- }
840
- const cursor = tiptapEditor.state.selection.from;
841
- let index = -1;
842
- let count = 0;
843
- tiptapEditor.state.doc.descendants((node, pos) => {
844
- if (node.type.name !== 'heading')
845
- return;
846
- if (pos <= cursor && pos + node.nodeSize > cursor) {
847
- index = count;
848
- return false;
849
- }
850
- count++;
851
- });
852
- setWysiwygHeadingIndex(index >= 0 ? index : null);
853
- };
854
- recompute();
855
- tiptapEditor.on('selectionUpdate', recompute);
856
- tiptapEditor.on('update', recompute);
857
- return () => {
858
- tiptapEditor.off('selectionUpdate', recompute);
859
- tiptapEditor.off('update', recompute);
860
- };
861
- }, [isWysiwyg, tiptapEditor]);
862
- const currentTemplate = isWysiwyg ? wysiwygTemplate : isRawView ? rawTemplate : null;
863
- // Compute recommended templates for the active block. Heading slice
864
- // comes from markdownSource — raw view supplies the cursor line,
865
- // WYSIWYG supplies the heading index.
866
- const recommendedTemplates = useMemo(() => {
867
- if (currentTemplate === null)
868
- return undefined;
869
- let slice = null;
870
- if (isRawView && rawHeadingLine !== null) {
871
- slice = findBlockSliceAtLine(markdownSource, rawHeadingLine);
872
- }
873
- else if (isWysiwyg && wysiwygHeadingIndex !== null) {
874
- slice = findBlockSliceByHeadingIndex(markdownSource, wysiwygHeadingIndex);
875
- }
876
- if (slice === null)
877
- return undefined;
878
- const profile = profileBlockContents(slice);
879
- return recommendTemplatesForBlock(profile, TEMPLATE_NAMES).recommended;
880
- }, [currentTemplate, isRawView, isWysiwyg, rawHeadingLine, wysiwygHeadingIndex, markdownSource]);
881
- const handleTemplatePick = (value) => {
882
- // Raw (Monaco) — rewrite the heading line's annotation suffix in place.
883
- if (isRawView && monacoEditor) {
884
- const model = monacoEditor.getModel();
885
- const pos = monacoEditor.getPosition();
886
- if (!model || !pos)
887
- return;
888
- const lineNumber = pos.lineNumber;
889
- const lineText = model.getLineContent(lineNumber);
890
- const headingMatch = lineText.match(/^(#{1,6}\s+)(.+)$/);
891
- if (!headingMatch)
892
- return;
893
- const prefix = headingMatch[1];
894
- // Strip any existing trailing annotation
895
- const bareText = headingMatch[2].replace(/\s*\{\[[^\]]+\]\}[\s\]}]*$/, '').trimEnd();
896
- const newLine = value === '' ? `${prefix}${bareText}` : `${prefix}${bareText} {[${value}]}`;
897
- monacoEditor.executeEdits('toolbar-template-pick', [
898
- {
899
- range: {
900
- startLineNumber: lineNumber,
901
- startColumn: 1,
902
- endLineNumber: lineNumber,
903
- endColumn: lineText.length + 1,
904
- },
905
- text: newLine,
906
- },
907
- ]);
908
- monacoEditor.focus();
909
- return;
910
- }
911
- // WYSIWYG — update the heading node attributes.
912
- if (!tiptapEditor)
913
- return;
914
- if (value === '') {
915
- tiptapEditor
916
- .chain()
917
- .focus()
918
- .updateAttributes('heading', { dataTemplate: null, dataTemplateParams: null })
919
- .run();
920
- }
921
- else {
922
- tiptapEditor.chain().focus().updateAttributes('heading', { dataTemplate: value }).run();
923
- }
924
- };
925
- return (_jsxs("div", { className: `squisq-toolbar ${className || ''}`, role: "toolbar", "aria-label": "Formatting toolbar", children: [_jsx("input", { ref: imageInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: (e) => {
926
- const file = e.target.files?.[0];
927
- if (file)
928
- handleImageFile(file);
929
- // Reset so the same file can be re-selected
930
- e.target.value = '';
931
- } }), slotLeft, showViewTabs && (_jsx("div", { className: "squisq-toolbar-view-tabs", role: "tablist", "aria-label": "Editor view", children: visibleViews.map((view) => (_jsxs("button", { role: "tab", "data-view": view.id, "aria-selected": activeView === view.id, className: `squisq-toolbar-view-tab${activeView === view.id ? ' squisq-toolbar-view-tab--active' : ''}`, onClick: () => setActiveView(view.id), "data-tooltip": `${view.label} (${view.shortcut})`, children: [_jsx("span", { className: "squisq-toolbar-view-tab-label squisq-toolbar-view-tab-label--long", "data-label": view.label, children: view.label }), view.shortLabel && view.shortLabel !== view.label && (_jsx("span", { className: "squisq-toolbar-view-tab-label squisq-toolbar-view-tab-label--short", "data-label": view.shortLabel, children: view.shortLabel }))] }, view.id))) })), !isPreview && !isNarrow && !isCodeMode && (_jsxs("div", { className: "squisq-toolbar-actions", ref: actionsRef, children: [groups.map((group, gi) => (_jsxs("div", { className: "squisq-toolbar-group", children: [gi > 0 && _jsx("div", { className: "squisq-toolbar-separator" }), BUTTONS.filter((b) => b.group === group && isButtonVisible(b.id)).map((btn) => {
932
- const active = btn.id === 'emoji'
933
- ? emojiPickerAnchor !== null
934
- : isWysiwyg
935
- ? isTiptapActive(tiptapEditor, btn.id)
936
- : false;
937
- const disabled = btn.id === 'image' && !mediaProvider;
938
- return (_jsx("button", { ref: btn.id === 'emoji' ? emojiButtonRef : undefined, className: `squisq-toolbar-button${active ? ' squisq-toolbar-button--active' : ''}`, "data-tooltip": disabled ? 'Insert image (requires media provider)' : btn.title, onClick: () => handleAction(btn.id), "aria-label": btn.title, "aria-pressed": active, disabled: disabled, style: btn.iconStyle, children: buttonIconSvg(btn.id) ?? btn.icon }, btn.id));
939
- })] }, group))), currentTemplate !== null && (_jsxs(_Fragment, { children: [_jsx("div", { className: "squisq-toolbar-separator" }), _jsx("div", { className: "squisq-toolbar-group squisq-template-picker", children: _jsx(TemplatePicker, { value: currentTemplate, onChange: handleTemplatePick, recommended: recommendedTemplates }) })] })), isInTable && (_jsxs(_Fragment, { children: [_jsx("div", { className: "squisq-toolbar-separator" }), _jsxs("div", { className: "squisq-toolbar-group squisq-table-controls", children: [_jsx("span", { className: "squisq-table-controls-label", children: "Table:" }), _jsx("button", { className: "squisq-toolbar-button", "data-tooltip": "Add column before", onClick: () => tiptapEditor.chain().focus().addColumnBefore().run(), "aria-label": "Add column before", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [_jsx("rect", { x: "7", y: "2", width: "8", height: "12", rx: "1" }), _jsx("line", { x1: "11", y1: "2", x2: "11", y2: "14" }), _jsx("line", { x1: "1", y1: "8", x2: "4.5", y2: "8" }), _jsx("line", { x1: "2.75", y1: "6.25", x2: "2.75", y2: "9.75" })] }) }), _jsx("button", { className: "squisq-toolbar-button", "data-tooltip": "Add column after", onClick: () => tiptapEditor.chain().focus().addColumnAfter().run(), "aria-label": "Add column after", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [_jsx("rect", { x: "1", y: "2", width: "8", height: "12", rx: "1" }), _jsx("line", { x1: "5", y1: "2", x2: "5", y2: "14" }), _jsx("line", { x1: "11.5", y1: "8", x2: "15", y2: "8" }), _jsx("line", { x1: "13.25", y1: "6.25", x2: "13.25", y2: "9.75" })] }) }), _jsx("button", { className: "squisq-toolbar-button", "data-tooltip": "Delete column", onClick: () => tiptapEditor.chain().focus().deleteColumn().run(), "aria-label": "Delete column", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [_jsx("rect", { x: "4", y: "1", width: "8", height: "14", rx: "1" }), _jsx("line", { x1: "6", y1: "5.5", x2: "10", y2: "10.5" }), _jsx("line", { x1: "10", y1: "5.5", x2: "6", y2: "10.5" })] }) }), _jsx("button", { className: "squisq-toolbar-button", "data-tooltip": "Add row above", onClick: () => tiptapEditor.chain().focus().addRowBefore().run(), "aria-label": "Add row above", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [_jsx("rect", { x: "2", y: "6", width: "12", height: "9", rx: "1" }), _jsx("line", { x1: "2", y1: "10.5", x2: "14", y2: "10.5" }), _jsx("line", { x1: "8", y1: "1", x2: "8", y2: "4.5" }), _jsx("line", { x1: "6.25", y1: "2.75", x2: "9.75", y2: "2.75" })] }) }), _jsx("button", { className: "squisq-toolbar-button", "data-tooltip": "Add row below", onClick: () => tiptapEditor.chain().focus().addRowAfter().run(), "aria-label": "Add row below", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [_jsx("rect", { x: "2", y: "1", width: "12", height: "9", rx: "1" }), _jsx("line", { x1: "2", y1: "5.5", x2: "14", y2: "5.5" }), _jsx("line", { x1: "8", y1: "11.5", x2: "8", y2: "15" }), _jsx("line", { x1: "6.25", y1: "13.25", x2: "9.75", y2: "13.25" })] }) }), _jsx("button", { className: "squisq-toolbar-button", "data-tooltip": "Delete row", onClick: () => tiptapEditor.chain().focus().deleteRow().run(), "aria-label": "Delete row", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [_jsx("rect", { x: "1", y: "4", width: "14", height: "8", rx: "1" }), _jsx("line", { x1: "5.5", y1: "6", x2: "10.5", y2: "10" }), _jsx("line", { x1: "10.5", y1: "6", x2: "5.5", y2: "10" })] }) }), _jsx("button", { className: "squisq-toolbar-button squisq-toolbar-button--danger", "data-tooltip": "Delete table", onClick: () => tiptapEditor.chain().focus().deleteTable().run(), "aria-label": "Delete table", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [_jsx("rect", { x: "1", y: "1", width: "14", height: "14", rx: "1" }), _jsx("line", { x1: "1", y1: "5.5", x2: "15", y2: "5.5" }), _jsx("line", { x1: "5.5", y1: "1", x2: "5.5", y2: "15" }), _jsx("line", { x1: "4.5", y1: "4.5", x2: "11.5", y2: "11.5", strokeWidth: "2" }), _jsx("line", { x1: "11.5", y1: "4.5", x2: "4.5", y2: "11.5", strokeWidth: "2" })] }) })] })] }))] })), !isPreview && !isCodeMode && overflowIndex !== null && (_jsxs("div", { className: "squisq-toolbar-overflow", ref: overflowRef, children: [_jsx("button", { className: `squisq-toolbar-button squisq-toolbar-overflow-trigger${showOverflow ? ' squisq-toolbar-button--active' : ''}`, "data-tooltip": "More actions", onClick: () => setShowOverflow((v) => !v), "aria-label": "More actions", "aria-expanded": showOverflow, children: "\u00B7\u00B7\u00B7" }), showOverflow && (_jsxs("div", { className: `squisq-toolbar-overflow-menu squisq-toolbar-overflow-menu--${overflowPlacement}`, children: [BUTTONS.slice(overflowIndex)
940
- .filter((b) => isButtonVisible(b.id))
941
- .map((btn) => {
942
- const active = btn.id === 'emoji'
943
- ? emojiPickerAnchor !== null
944
- : isWysiwyg
945
- ? isTiptapActive(tiptapEditor, btn.id)
946
- : false;
947
- const disabled = btn.id === 'image' && !mediaProvider;
948
- return (_jsxs("button", { ref: btn.id === 'emoji' ? emojiButtonRef : undefined, className: `squisq-toolbar-overflow-item${active ? ' squisq-toolbar-overflow-item--active' : ''}`, onClick: () => {
949
- handleAction(btn.id);
950
- // Keep the overflow open when opening the emoji
951
- // picker — otherwise its anchor (the overflow
952
- // item) unmounts and the popover loses its ref.
953
- if (btn.id !== 'emoji')
954
- setShowOverflow(false);
955
- }, disabled: disabled, children: [buttonIconSvg(btn.id) ?? (_jsx("span", { className: "squisq-toolbar-overflow-icon", style: btn.iconStyle, children: btn.icon })), _jsx("span", { children: btn.title })] }, btn.id));
956
- }), currentTemplate !== null && (_jsxs("div", { className: "squisq-toolbar-overflow-item squisq-toolbar-overflow-template", children: [_jsx("span", { children: "Template:" }), _jsx(TemplatePicker, { value: currentTemplate, onChange: (v) => {
957
- handleTemplatePick(v);
958
- setShowOverflow(false);
959
- }, recommended: recommendedTemplates })] })), isInTable && (_jsxs(_Fragment, { children: [_jsx("div", { className: "squisq-toolbar-separator", style: { margin: '4px 0', width: '100%', height: 1 } }), [
960
- {
961
- label: 'Add column before',
962
- action: () => tiptapEditor.chain().focus().addColumnBefore().run(),
963
- },
964
- {
965
- label: 'Add column after',
966
- action: () => tiptapEditor.chain().focus().addColumnAfter().run(),
967
- },
968
- {
969
- label: 'Delete column',
970
- action: () => tiptapEditor.chain().focus().deleteColumn().run(),
971
- },
972
- {
973
- label: 'Add row above',
974
- action: () => tiptapEditor.chain().focus().addRowBefore().run(),
975
- },
976
- {
977
- label: 'Add row below',
978
- action: () => tiptapEditor.chain().focus().addRowAfter().run(),
979
- },
980
- {
981
- label: 'Delete row',
982
- action: () => tiptapEditor.chain().focus().deleteRow().run(),
983
- },
984
- {
985
- label: 'Delete table',
986
- action: () => tiptapEditor.chain().focus().deleteTable().run(),
987
- },
988
- ].map((item) => (_jsx("button", { className: `squisq-toolbar-overflow-item${item.label.startsWith('Delete') ? ' squisq-toolbar-overflow-item--danger' : ''}`, onClick: () => {
989
- item.action();
990
- setShowOverflow(false);
991
- }, children: _jsx("span", { children: item.label }) }, item.label)))] }))] }))] })), slotAfterActions, (isPreview || isNarrow || isCodeMode) && _jsx("div", { style: { flex: 1 } }), versioning && !isCodeMode && _jsx(VersionHistoryPanel, {}), allowRecording && !isCodeMode && mediaProvider && _jsx(RecorderEntry, {}), !isCodeMode && (_jsx("button", { type: "button", className: "squisq-toolbar-button", onClick: () => setShowDocSettings(true), "data-tooltip": "Document settings", "aria-label": "Document settings", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [_jsx("path", { d: "M3 2.5h7l3 3v8a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-10a1 1 0 0 1 1-1Z", stroke: "currentColor", strokeWidth: "1.3", strokeLinejoin: "round" }), _jsx("path", { d: "M10 2.5v3h3", stroke: "currentColor", strokeWidth: "1.3", strokeLinejoin: "round" }), _jsx("path", { d: "M5 8.5h6M5 11h4", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round" })] }) })), !isCodeMode && _jsx(ViewMenuPanel, {}), onToggleFiles && (_jsx("button", { className: `squisq-toolbar-button squisq-toolbar-files-toggle${showFiles ? ' squisq-toolbar-button--active' : ''}`, onClick: onToggleFiles, "data-tooltip": showFiles ? 'Hide Files panel' : 'Show Files panel', "aria-pressed": showFiles, "aria-label": "Toggle Files panel", children: PAPERCLIP_ICON })), slotRight, showDocSettings && (_jsx(DocumentSettingsDialog, { markdownSource: markdownSource, onSave: (next) => {
992
- setMarkdownSource(next);
993
- setShowDocSettings(false);
994
- }, onClose: () => setShowDocSettings(false) })), linkDialog && (_jsx(LinkDialog, { mode: linkDialog.mode, initialText: linkDialog.initialText, initialUrl: linkDialog.initialUrl, onConfirm: handleLinkConfirm, onClose: () => setLinkDialog(null), documentLinkProvider: documentLinkProvider })), emojiPickerAnchor &&
995
- createPortal(_jsx(EmojiPicker, { open: true, onSelect: handleEmojiSelect, onClose: closeEmojiPicker, anchorRef: emojiButtonRef, theme: theme === 'dark' ? 'dark' : 'light', style: {
996
- position: 'fixed',
997
- top: emojiPickerAnchor.top,
998
- left: emojiPickerAnchor.left,
999
- } }), document.body)] }));
1000
- }
1001
- //# sourceMappingURL=Toolbar.js.map