@bendyline/squisq-editor-react 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +40 -0
  3. package/README.md +10 -2
  4. package/dist/index.d.ts +683 -60
  5. package/dist/index.js +9648 -3750
  6. package/dist/monaco.js +0 -1
  7. package/dist/styles/index.css +1160 -241
  8. package/package.json +10 -6
  9. package/dist/index.js.map +0 -1
  10. package/dist/monaco.js.map +0 -1
  11. package/src/BlockCardView.tsx +0 -121
  12. package/src/BlockPreviewPanel.tsx +0 -69
  13. package/src/BlockPropertiesPopover.tsx +0 -222
  14. package/src/DocumentSettingsDialog.tsx +0 -272
  15. package/src/DropZoneOverlay.tsx +0 -137
  16. package/src/EditorContext.tsx +0 -1247
  17. package/src/EditorShell.tsx +0 -1334
  18. package/src/EmojiPicker.tsx +0 -332
  19. package/src/FolderView.tsx +0 -131
  20. package/src/Icon.tsx +0 -26
  21. package/src/ImageEditor.tsx +0 -395
  22. package/src/ImageNodeView.tsx +0 -284
  23. package/src/ImageViewer.tsx +0 -221
  24. package/src/InlineIcon.ts +0 -84
  25. package/src/InlinePreviewGutter.tsx +0 -590
  26. package/src/LinkDialog.tsx +0 -276
  27. package/src/MediaBin.tsx +0 -500
  28. package/src/MentionExtension.tsx +0 -261
  29. package/src/OutlinePanel.tsx +0 -547
  30. package/src/PlainHtmlPreview.tsx +0 -277
  31. package/src/PreviewControls.tsx +0 -1250
  32. package/src/PreviewPanel.tsx +0 -422
  33. package/src/RawEditor.tsx +0 -731
  34. package/src/RecorderEntry.tsx +0 -159
  35. package/src/StatusBar.tsx +0 -51
  36. package/src/TemplateAnnotation.ts +0 -167
  37. package/src/TemplateContentPreview.tsx +0 -56
  38. package/src/TemplatePicker.tsx +0 -1314
  39. package/src/ThemeCustomizerPanel.tsx +0 -304
  40. package/src/ThemePicker.tsx +0 -433
  41. package/src/TimelineBlockPreview.tsx +0 -37
  42. package/src/TimelineTrack.tsx +0 -671
  43. package/src/Toolbar.tsx +0 -2587
  44. package/src/Tooltip.tsx +0 -142
  45. package/src/TransitionPicker.tsx +0 -390
  46. package/src/VersionHistoryPanel.tsx +0 -359
  47. package/src/ViewMenuPanel.tsx +0 -189
  48. package/src/ViewSwitcher.tsx +0 -56
  49. package/src/WysiwygEditor.tsx +0 -792
  50. package/src/__tests__/blockProperties.test.ts +0 -92
  51. package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +0 -33
  52. package/src/__tests__/blockRange.test.ts +0 -105
  53. package/src/__tests__/blockTagActivity.test.ts +0 -183
  54. package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +0 -75
  55. package/src/__tests__/buildPreviewDocContent.test.ts +0 -48
  56. package/src/__tests__/buildPreviewDocTransition.test.ts +0 -92
  57. package/src/__tests__/canvasSurfaceTextEditing.test.tsx +0 -60
  58. package/src/__tests__/codeContextSectionView.test.tsx +0 -97
  59. package/src/__tests__/codeContextZoneManager.test.ts +0 -127
  60. package/src/__tests__/createShapeLayer.test.ts +0 -46
  61. package/src/__tests__/customLayoutManagerTheme.test.tsx +0 -34
  62. package/src/__tests__/detectMarkdown.test.ts +0 -73
  63. package/src/__tests__/diffContextSections.test.ts +0 -39
  64. package/src/__tests__/documentSettingsDialog.test.tsx +0 -197
  65. package/src/__tests__/drawingShapeRoundTrip.test.ts +0 -49
  66. package/src/__tests__/editorScrollHandoff.test.tsx +0 -102
  67. package/src/__tests__/editorScrollSync.test.ts +0 -65
  68. package/src/__tests__/editorShellCodeContext.test.tsx +0 -86
  69. package/src/__tests__/editorShellProps.test.tsx +0 -485
  70. package/src/__tests__/embeddedMedia.test.ts +0 -48
  71. package/src/__tests__/emojiPicker.test.tsx +0 -93
  72. package/src/__tests__/fileKind.test.ts +0 -112
  73. package/src/__tests__/headingTransition.test.ts +0 -176
  74. package/src/__tests__/imageEditAffordance.test.tsx +0 -272
  75. package/src/__tests__/imageEditModalContract.test.tsx +0 -119
  76. package/src/__tests__/imageEditorShell.test.tsx +0 -94
  77. package/src/__tests__/imageEditorState.test.ts +0 -171
  78. package/src/__tests__/inlinePreviewGutter.test.tsx +0 -62
  79. package/src/__tests__/inlinePreviewGutterAllBlocks.test.tsx +0 -103
  80. package/src/__tests__/jsonEditor.test.tsx +0 -223
  81. package/src/__tests__/layersPanel.test.tsx +0 -167
  82. package/src/__tests__/layoutChildRoundTrip.test.ts +0 -71
  83. package/src/__tests__/linkDialogDocPicker.test.tsx +0 -137
  84. package/src/__tests__/majorApiTypes.test.ts +0 -26
  85. package/src/__tests__/mediaAttachmentFlow.test.ts +0 -110
  86. package/src/__tests__/mediaBinDrop.test.tsx +0 -90
  87. package/src/__tests__/mediaReferences.test.ts +0 -82
  88. package/src/__tests__/narrationSave.test.ts +0 -148
  89. package/src/__tests__/outlinePanel.test.tsx +0 -169
  90. package/src/__tests__/outlineSource.test.ts +0 -217
  91. package/src/__tests__/plainHtmlPreview.test.tsx +0 -125
  92. package/src/__tests__/presentationMode.test.tsx +0 -290
  93. package/src/__tests__/previewControls.test.tsx +0 -540
  94. package/src/__tests__/previewPanelAudioFailure.test.tsx +0 -46
  95. package/src/__tests__/previewPanelPresentation.test.tsx +0 -126
  96. package/src/__tests__/previewPanelTransforms.test.tsx +0 -117
  97. package/src/__tests__/propertiesPanel.test.tsx +0 -69
  98. package/src/__tests__/rawEditorModelIsolation.test.ts +0 -19
  99. package/src/__tests__/recorderFormats.test.ts +0 -146
  100. package/src/__tests__/recorderMediaInsert.test.ts +0 -86
  101. package/src/__tests__/recorderTheme.test.tsx +0 -42
  102. package/src/__tests__/recorderTimingJson.test.ts +0 -41
  103. package/src/__tests__/resolveBlockVisual.test.ts +0 -43
  104. package/src/__tests__/selectionConversions.test.ts +0 -80
  105. package/src/__tests__/statusBar.test.tsx +0 -27
  106. package/src/__tests__/teleprompter.test.tsx +0 -190
  107. package/src/__tests__/templateAnnotationRoundTrip.test.ts +0 -99
  108. package/src/__tests__/templateContentPreview.test.ts +0 -101
  109. package/src/__tests__/templatePickerMetadata.test.ts +0 -32
  110. package/src/__tests__/templatePickerPortal.test.tsx +0 -62
  111. package/src/__tests__/timelineSource.test.ts +0 -134
  112. package/src/__tests__/tiptapBridge.test.ts +0 -566
  113. package/src/__tests__/tiptapBridgeConformance.test.ts +0 -47
  114. package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +0 -109
  115. package/src/__tests__/tiptapImageRoundTrip.test.ts +0 -73
  116. package/src/__tests__/toolbarSelectionConversion.test.tsx +0 -164
  117. package/src/__tests__/tooltip.test.tsx +0 -72
  118. package/src/__tests__/transformStyleId.test.ts +0 -13
  119. package/src/__tests__/transitionCatalog.test.ts +0 -64
  120. package/src/__tests__/useBlockNavigator.test.tsx +0 -67
  121. package/src/__tests__/useImageEditor.test.tsx +0 -226
  122. package/src/__tests__/useJsonEditorTokens.test.ts +0 -59
  123. package/src/__tests__/useMediaRecorder.test.ts +0 -302
  124. package/src/__tests__/useTimelineClock.test.ts +0 -21
  125. package/src/__tests__/versionHistory.test.tsx +0 -197
  126. package/src/__tests__/viewMenuPanel.test.tsx +0 -130
  127. package/src/__tests__/wysiwygImageUpload.test.ts +0 -69
  128. package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +0 -56
  129. package/src/asciiDiagram/AsciiDiagramExtension.ts +0 -343
  130. package/src/asciiDiagram/AsciiDiagramWidget.tsx +0 -254
  131. package/src/asciiDiagram/RepairableDiagramExtension.ts +0 -200
  132. package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +0 -145
  133. package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +0 -159
  134. package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +0 -284
  135. package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +0 -114
  136. package/src/asciiDiagram/__tests__/asciiPaste.test.ts +0 -43
  137. package/src/asciiDiagram/asciiDiagramCommands.ts +0 -174
  138. package/src/asciiDiagram/asciiDiagramData.ts +0 -149
  139. package/src/asciiDiagram/asciiDiagramOps.ts +0 -238
  140. package/src/asciiDiagram/asciiPaste.ts +0 -19
  141. package/src/blockProperties.ts +0 -88
  142. package/src/blockRange.ts +0 -132
  143. package/src/blockSlice.ts +0 -75
  144. package/src/blockTagActivity.ts +0 -233
  145. package/src/buildDocumentPreviewMarkdown.ts +0 -168
  146. package/src/buildPreviewDoc.ts +0 -405
  147. package/src/codeContext/CodeContextSectionView.tsx +0 -124
  148. package/src/codeContext/CodeContextZoneManager.ts +0 -149
  149. package/src/codeContext/CodeContextZones.tsx +0 -121
  150. package/src/codeContext/diffContextSections.ts +0 -38
  151. package/src/codeContext/types.ts +0 -75
  152. package/src/customTemplates/AddBin.tsx +0 -126
  153. package/src/customTemplates/CustomLayoutManager.tsx +0 -234
  154. package/src/customTemplates/CustomTemplateContext.tsx +0 -188
  155. package/src/customTemplates/LayerToolbar.tsx +0 -580
  156. package/src/customTemplates/ShapeGlyph.tsx +0 -47
  157. package/src/customTemplates/TemplateDesigner.tsx +0 -433
  158. package/src/customTemplates/__tests__/library.test.ts +0 -96
  159. package/src/customTemplates/__tests__/normalizePositions.test.ts +0 -109
  160. package/src/customTemplates/__tests__/shapeDefs.test.ts +0 -49
  161. package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +0 -108
  162. package/src/customTemplates/designer.css +0 -732
  163. package/src/customTemplates/index.ts +0 -31
  164. package/src/customTemplates/library.ts +0 -110
  165. package/src/customTemplates/normalizePositions.ts +0 -75
  166. package/src/customTemplates/shapeDefs.ts +0 -131
  167. package/src/customTemplates/thumbnail.tsx +0 -63
  168. package/src/customTemplates/tokenDefs.ts +0 -60
  169. package/src/customTemplates/useDocCustomTemplates.ts +0 -52
  170. package/src/customTemplates/useMemoryLayerAdapter.ts +0 -129
  171. package/src/customThemes/CustomThemeContext.tsx +0 -185
  172. package/src/customThemes/CustomThemeDialog.tsx +0 -316
  173. package/src/customThemes/ImportThemeSection.tsx +0 -178
  174. package/src/customThemes/__tests__/CustomThemeContext.test.tsx +0 -64
  175. package/src/customThemes/__tests__/CustomThemeDialog.test.tsx +0 -47
  176. package/src/customThemes/__tests__/customThemeLibrary.test.ts +0 -60
  177. package/src/customThemes/__tests__/importThemeSection.test.tsx +0 -192
  178. package/src/customThemes/customThemeLibrary.ts +0 -100
  179. package/src/customThemes/index.ts +0 -37
  180. package/src/customThemes/themeControls.tsx +0 -229
  181. package/src/customThemes/themeDraft.ts +0 -288
  182. package/src/customThemes/useDocCustomThemes.ts +0 -49
  183. package/src/detectMarkdown.ts +0 -62
  184. package/src/diagram/DiagramCanvas.tsx +0 -259
  185. package/src/diagram/DiagramMaximizedOverlay.tsx +0 -46
  186. package/src/diagram/diagramCommands.ts +0 -604
  187. package/src/diagram/diagramConstants.ts +0 -17
  188. package/src/diagram/types.ts +0 -35
  189. package/src/editorScrollSync.ts +0 -73
  190. package/src/embeddedMedia.ts +0 -78
  191. package/src/emojiData.ts +0 -1317
  192. package/src/fileKind.ts +0 -158
  193. package/src/frontmatter.ts +0 -29
  194. package/src/frontmatterSettings.ts +0 -23
  195. package/src/headingTransition.ts +0 -291
  196. package/src/hooks/useFileDrop.ts +0 -266
  197. package/src/imageEditor/CanvasSurface.tsx +0 -703
  198. package/src/imageEditor/ImageVersionHistoryDropdown.tsx +0 -396
  199. package/src/imageEditor/LayersPanel.tsx +0 -218
  200. package/src/imageEditor/PropertiesPanel.tsx +0 -474
  201. package/src/imageEditor/Toolbar.tsx +0 -459
  202. package/src/imageEditor/createShapeLayer.ts +0 -280
  203. package/src/imageEditor/icons.tsx +0 -68
  204. package/src/imageEditor/image-editor.css +0 -574
  205. package/src/imageEditor/layers/EditorImageLayer.tsx +0 -45
  206. package/src/imageEditor/layers/EditorShapeLayer.tsx +0 -62
  207. package/src/imageEditor/layers/EditorTextLayer.tsx +0 -45
  208. package/src/imageEditor/layers/SelectionHandles.tsx +0 -86
  209. package/src/imageEditor/state.ts +0 -173
  210. package/src/imageEditor/useImageEditor.ts +0 -385
  211. package/src/imageEditor/useImageEditorTokens.ts +0 -70
  212. package/src/index.ts +0 -470
  213. package/src/jsonEditor/EmbeddedRichTextField.tsx +0 -81
  214. package/src/jsonEditor/JsonEditor.tsx +0 -81
  215. package/src/jsonEditor/JsonEditorContext.tsx +0 -81
  216. package/src/jsonEditor/RenderNode.tsx +0 -87
  217. package/src/jsonEditor/editors.tsx +0 -745
  218. package/src/jsonEditor/index.ts +0 -2
  219. package/src/jsonEditor/json-editor.css +0 -463
  220. package/src/jsonEditor/useJsonEditorTokens.ts +0 -33
  221. package/src/mediaDragMime.ts +0 -32
  222. package/src/mediaEntries.ts +0 -12
  223. package/src/mediaReferences.ts +0 -299
  224. package/src/monaco.ts +0 -35
  225. package/src/monacoWorkers.ts +0 -89
  226. package/src/outlineSource.ts +0 -171
  227. package/src/presentation/PresentationMode.tsx +0 -596
  228. package/src/rawEditorIsolation.ts +0 -18
  229. package/src/recorder/RecorderButton.tsx +0 -80
  230. package/src/recorder/RecorderModal.tsx +0 -706
  231. package/src/recorder/RecorderPanel.tsx +0 -77
  232. package/src/recorder/formats.ts +0 -159
  233. package/src/recorder/hooks/useMediaRecorder.ts +0 -436
  234. package/src/recorder/hooks/useStreamPreview.ts +0 -47
  235. package/src/recorder/insertMediaBlock.ts +0 -30
  236. package/src/recorder/sources/cameraStream.ts +0 -32
  237. package/src/recorder/sources/micStream.ts +0 -25
  238. package/src/recorder/sources/screenStream.ts +0 -162
  239. package/src/recorder/timingJson.ts +0 -66
  240. package/src/resolveBlockVisual.ts +0 -39
  241. package/src/scene/Scene.tsx +0 -616
  242. package/src/scene/SceneBlockExtension.ts +0 -205
  243. package/src/scene/SceneBlockToolbar.tsx +0 -201
  244. package/src/scene/SceneBlockWidget.tsx +0 -441
  245. package/src/scene/ScenePropsBar.tsx +0 -85
  246. package/src/scene/SceneSelection.tsx +0 -111
  247. package/src/scene/SceneSideToolbar.tsx +0 -89
  248. package/src/scene/SceneViewport.tsx +0 -106
  249. package/src/scene/ShapePalette.tsx +0 -196
  250. package/src/scene/__tests__/DiagramAdapter.test.ts +0 -142
  251. package/src/scene/__tests__/SceneBlockExtension.test.ts +0 -33
  252. package/src/scene/__tests__/bezierEdit.test.ts +0 -85
  253. package/src/scene/__tests__/blockLayers.test.ts +0 -57
  254. package/src/scene/__tests__/sceneIsolation.test.tsx +0 -119
  255. package/src/scene/__tests__/shapeLayers.test.ts +0 -106
  256. package/src/scene/__tests__/useSceneHitTest.test.ts +0 -90
  257. package/src/scene/__tests__/useScenePanZoom.test.ts +0 -103
  258. package/src/scene/adapters/DiagramAdapter.ts +0 -79
  259. package/src/scene/adapters/DrawingAdapter.ts +0 -420
  260. package/src/scene/adapters/LayoutAdapter.ts +0 -313
  261. package/src/scene/adapters/blockLayers.ts +0 -159
  262. package/src/scene/commands/SceneCommand.ts +0 -84
  263. package/src/scene/commands/drawingCommands.ts +0 -318
  264. package/src/scene/commands/layoutCommands.ts +0 -301
  265. package/src/scene/hooks/useSceneHitTest.ts +0 -105
  266. package/src/scene/hooks/useScenePanZoom.ts +0 -147
  267. package/src/scene/hooks/useSceneSelection.ts +0 -62
  268. package/src/scene/index.ts +0 -90
  269. package/src/scene/layers/DiagramEdges.tsx +0 -142
  270. package/src/scene/layers/edgeGeometry.ts +0 -104
  271. package/src/scene/layers/nodeCard.tsx +0 -164
  272. package/src/scene/layers/renderLayer.tsx +0 -70
  273. package/src/scene/layers/shapeLayers.ts +0 -201
  274. package/src/scene/paths/bezierEdit.ts +0 -208
  275. package/src/scene/scene.css +0 -792
  276. package/src/scene/text/SceneTextOverlay.tsx +0 -161
  277. package/src/scene/text/sceneTextChannel.ts +0 -46
  278. package/src/scene/text/sceneTextConfig.ts +0 -31
  279. package/src/scene/text/sceneTiptap.ts +0 -36
  280. package/src/scene/text/useSceneTextEditing.ts +0 -39
  281. package/src/scene/tools/ConnectTool.ts +0 -209
  282. package/src/scene/tools/DrawingConnectTool.ts +0 -231
  283. package/src/scene/tools/PathTool.ts +0 -158
  284. package/src/scene/tools/PlaceTool.ts +0 -47
  285. package/src/scene/tools/SceneTool.ts +0 -85
  286. package/src/scene/tools/SelectTool.ts +0 -300
  287. package/src/scene/tools/ShapeTool.ts +0 -143
  288. package/src/scene/tools/TextTool.ts +0 -72
  289. package/src/scene/tools/TokenTool.ts +0 -95
  290. package/src/scene/tools/createDrawShapeTool.ts +0 -82
  291. package/src/selectionConversions.ts +0 -155
  292. package/src/styles/ascii-diagram.css +0 -79
  293. package/src/styles/ascii-timeline.css +0 -596
  294. package/src/styles/code-context.css +0 -155
  295. package/src/styles/diagram.css +0 -183
  296. package/src/styles/editor.css +0 -6811
  297. package/src/styles/folder-view.css +0 -210
  298. package/src/styles/image-edit-affordance.css +0 -201
  299. package/src/styles/index.css +0 -18
  300. package/src/styles/tree-view.css +0 -189
  301. package/src/teleprompter/TeleprompterControls.tsx +0 -218
  302. package/src/teleprompter/TeleprompterSelfView.tsx +0 -22
  303. package/src/teleprompter/TeleprompterSurface.tsx +0 -267
  304. package/src/teleprompter/TeleprompterView.tsx +0 -338
  305. package/src/teleprompter/canvasRenderer.ts +0 -161
  306. package/src/teleprompter/floatingWindow.ts +0 -352
  307. package/src/teleprompter/index.ts +0 -61
  308. package/src/teleprompter/pcmWorklet.ts +0 -62
  309. package/src/teleprompter/recording/insertPreamble.ts +0 -80
  310. package/src/teleprompter/recording/narrationSave.ts +0 -134
  311. package/src/teleprompter/recording/useNarrationRecorder.ts +0 -367
  312. package/src/teleprompter/scrollModel.ts +0 -85
  313. package/src/teleprompter/teleprompterTheme.ts +0 -303
  314. package/src/teleprompter/types.ts +0 -38
  315. package/src/teleprompter/useFloatingWindow.ts +0 -74
  316. package/src/teleprompter/useMicAnalysis.ts +0 -211
  317. package/src/teleprompter/useTeleprompter.ts +0 -421
  318. package/src/templateContentPreviewResolver.ts +0 -360
  319. package/src/timeline/TimelineEditorWidget.tsx +0 -861
  320. package/src/timeline/TimelineViewExtension.ts +0 -252
  321. package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +0 -414
  322. package/src/timeline/__tests__/TimelineViewExtension.test.ts +0 -163
  323. package/src/timeline/__tests__/timelineCommands.test.ts +0 -359
  324. package/src/timeline/__tests__/timelineOps.test.ts +0 -277
  325. package/src/timeline/__tests__/timelinePaste.test.ts +0 -34
  326. package/src/timeline/timelineCommands.ts +0 -421
  327. package/src/timeline/timelineData.ts +0 -54
  328. package/src/timeline/timelineOps.ts +0 -381
  329. package/src/timeline/timelinePaste.ts +0 -8
  330. package/src/timelineSource.ts +0 -244
  331. package/src/tiptap/TiptapAudio.tsx +0 -86
  332. package/src/tiptap/TiptapVideo.tsx +0 -119
  333. package/src/tiptap/useResolvedMediaSrc.ts +0 -47
  334. package/src/tiptapBridge.ts +0 -986
  335. package/src/tooltipPlacement.ts +0 -13
  336. package/src/transformStyleId.ts +0 -17
  337. package/src/transitionCatalog.ts +0 -159
  338. package/src/treeview/TreeOutlineWidget.tsx +0 -390
  339. package/src/treeview/TreeViewExtension.ts +0 -250
  340. package/src/treeview/__tests__/TreeOutlineWidget.test.tsx +0 -156
  341. package/src/treeview/__tests__/TreeViewExtension.test.ts +0 -122
  342. package/src/treeview/__tests__/treeOps.test.ts +0 -177
  343. package/src/treeview/__tests__/treePaste.test.ts +0 -40
  344. package/src/treeview/__tests__/treeViewCommands.test.ts +0 -179
  345. package/src/treeview/treeOps.ts +0 -231
  346. package/src/treeview/treePaste.ts +0 -13
  347. package/src/treeview/treeViewCommands.ts +0 -99
  348. package/src/treeview/treeViewData.ts +0 -41
  349. package/src/types/monaco-shims.d.ts +0 -10
  350. package/src/useBlockNavigator.ts +0 -153
  351. package/src/useHeadingLayout.ts +0 -294
  352. package/src/useMonacoLoader.ts +0 -82
  353. package/src/useTimelineClock.ts +0 -76
  354. package/src/utils/collectInlineFontAwesomeCss.ts +0 -69
  355. package/src/utils/dropUtils.ts +0 -136
  356. package/src/utils/normalizeMalformedAssetUrl.ts +0 -22
  357. package/src/wysiwygImageUpload.ts +0 -113
@@ -1,167 +0,0 @@
1
- /**
2
- * @vitest-environment jsdom
3
- */
4
- import { describe, it, expect, vi } from 'vitest';
5
- import { fireEvent, render, screen } from '@testing-library/react';
6
- import type { ImageEditDoc } from '@bendyline/squisq/schemas';
7
- import { LayersPanel } from '../imageEditor/LayersPanel.js';
8
- import type { ImageEditorAction } from '../imageEditor/state.js';
9
-
10
- const ignoreAddLayer = () => {};
11
-
12
- function buildDoc(): ImageEditDoc {
13
- return {
14
- version: 1,
15
- canvas: { width: 100, height: 100 },
16
- layers: [
17
- {
18
- id: 'a',
19
- type: 'shape',
20
- name: 'Bottom',
21
- position: { x: 0, y: 0, width: 10, height: 10 },
22
- content: { shape: 'rect' },
23
- },
24
- {
25
- id: 'b',
26
- type: 'text',
27
- name: 'Middle',
28
- position: { x: 0, y: 0, width: 50, height: 20 },
29
- content: { text: 'Hi', style: { fontSize: 16, color: '#000' } },
30
- },
31
- {
32
- id: 'c',
33
- type: 'shape',
34
- name: 'Top',
35
- visible: false,
36
- position: { x: 0, y: 0, width: 10, height: 10 },
37
- content: { shape: 'rect' },
38
- },
39
- ],
40
- };
41
- }
42
-
43
- describe('LayersPanel', () => {
44
- it('renders layers with the top of the SVG stack first', () => {
45
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
46
- render(
47
- <LayersPanel
48
- doc={buildDoc()}
49
- selectedLayerId={null}
50
- dispatch={dispatch}
51
- onAddLayer={ignoreAddLayer}
52
- />,
53
- );
54
- const items = screen.getAllByText(/Bottom|Middle|Top/);
55
- expect(items[0]?.textContent).toContain('Top');
56
- expect(items[items.length - 1]?.textContent).toContain('Bottom');
57
- });
58
-
59
- it('clicking the layer name dispatches a select action', () => {
60
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
61
- render(
62
- <LayersPanel
63
- doc={buildDoc()}
64
- selectedLayerId={null}
65
- dispatch={dispatch}
66
- onAddLayer={ignoreAddLayer}
67
- />,
68
- );
69
- fireEvent.click(screen.getByText('Middle'));
70
- expect(dispatch).toHaveBeenCalledWith({ type: 'select', layerId: 'b' });
71
- });
72
-
73
- it('exposes the full layer name as a tooltip when the row is truncated', () => {
74
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
75
- render(
76
- <LayersPanel
77
- doc={buildDoc()}
78
- selectedLayerId={null}
79
- dispatch={dispatch}
80
- onAddLayer={ignoreAddLayer}
81
- />,
82
- );
83
- expect(screen.getByTitle('Middle').textContent).toContain('Middle');
84
- });
85
-
86
- it('opens the add-layer menu and reports the selected layer kind', () => {
87
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
88
- const onAddLayer = vi.fn();
89
- render(
90
- <LayersPanel
91
- doc={buildDoc()}
92
- selectedLayerId={null}
93
- dispatch={dispatch}
94
- onAddLayer={onAddLayer}
95
- />,
96
- );
97
-
98
- fireEvent.click(screen.getByRole('button', { name: 'Add layer' }));
99
- expect(screen.getByRole('menu')).toBeTruthy();
100
- fireEvent.click(screen.getByRole('menuitem', { name: 'Text layer' }));
101
- expect(onAddLayer).toHaveBeenCalledWith('text');
102
- expect(screen.queryByRole('menu')).toBeNull();
103
- });
104
-
105
- it('toggling visibility dispatches an update-layer action', () => {
106
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
107
- render(
108
- <LayersPanel
109
- doc={buildDoc()}
110
- selectedLayerId={null}
111
- dispatch={dispatch}
112
- onAddLayer={ignoreAddLayer}
113
- />,
114
- );
115
- // The "Hide layer" buttons exist for visible layers.
116
- const hideButtons = screen.getAllByRole('button', { name: 'Hide layer' });
117
- fireEvent.click(hideButtons[0]!); // top-most visible layer is 'b'
118
- expect(dispatch).toHaveBeenCalledWith({
119
- type: 'update-layer',
120
- layerId: 'b',
121
- patch: { visible: false },
122
- });
123
- });
124
-
125
- it('move-up button is disabled at the top of the stack', () => {
126
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
127
- render(
128
- <LayersPanel
129
- doc={buildDoc()}
130
- selectedLayerId={null}
131
- dispatch={dispatch}
132
- onAddLayer={ignoreAddLayer}
133
- />,
134
- );
135
- const upButtons = screen.getAllByRole('button', { name: 'Move layer up' });
136
- // Visual order is c, b, a; layer 'c' is at the top of the stack and cannot move up.
137
- expect((upButtons[0] as HTMLButtonElement).disabled).toBe(true);
138
- });
139
-
140
- it('delete button dispatches a remove-layer action', () => {
141
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
142
- render(
143
- <LayersPanel
144
- doc={buildDoc()}
145
- selectedLayerId={null}
146
- dispatch={dispatch}
147
- onAddLayer={ignoreAddLayer}
148
- />,
149
- );
150
- const delButtons = screen.getAllByRole('button', { name: 'Delete layer' });
151
- fireEvent.click(delButtons[0]!); // top of stack ('c')
152
- expect(dispatch).toHaveBeenCalledWith({ type: 'remove-layer', layerId: 'c' });
153
- });
154
-
155
- it('shows an empty-state message when there are no layers', () => {
156
- const dispatch = vi.fn<(a: ImageEditorAction) => void>();
157
- render(
158
- <LayersPanel
159
- doc={{ version: 1, canvas: { width: 1, height: 1 }, layers: [] }}
160
- selectedLayerId={null}
161
- dispatch={dispatch}
162
- onAddLayer={ignoreAddLayer}
163
- />,
164
- );
165
- expect(screen.getByText(/no layers yet/i)).toBeTruthy();
166
- });
167
- });
@@ -1,71 +0,0 @@
1
- /**
2
- * Layout child sub-blocks round-trip through the markdown ↔ Tiptap bridge.
3
- *
4
- * Layouts now persist each layer as a readable `### {#id} {[type …]}` child
5
- * heading (no base64 `layers=` blob); a text layer's content is the child's
6
- * markdown body. These tests pin that serialization seam — the same
7
- * `data-template` / `data-template-params` / `data-block-attrs` attributes the
8
- * LayoutAdapter reads back — without standing up a full editor.
9
- */
10
-
11
- import { describe, it, expect } from 'vitest';
12
- import { markdownToTiptap, tiptapToMarkdown } from '../tiptapBridge';
13
-
14
- // Parent title "Pricing" (not "Layout") avoids the bridge's template-label
15
- // de-dup heuristic, which would strip a title equal to the template's label.
16
- const LAYOUT = [
17
- '## Pricing {[layout]}',
18
- '',
19
- '### {#text-1} {[text x=360 y=380 width=1200 height=320 align=center]}',
20
- '',
21
- 'Welcome to the **bold** layout',
22
- '',
23
- '- first point',
24
- '- second point',
25
- '',
26
- '### {#box-1} {[rectangle x=760 y=390 width=400 height=300 fill="#e0e7ff"]}',
27
- '',
28
- '### {#pic-1} {[image x=40 y=40 width=320 height=240 src=cover.png alt="Cover"]}',
29
- ].join('\n');
30
-
31
- describe('Layout child sub-block round-trip', () => {
32
- it('extracts a text layer annotation into the template + block-attr attributes', () => {
33
- const html = markdownToTiptap('### {#text-1} {[text x=360 y=380 width=1200 height=320]}');
34
- expect(html).toContain('data-template="text"');
35
- expect(html).toContain('data-template-params="x=360 y=380 width=1200 height=320"');
36
- expect(html).toContain('data-block-attrs="#text-1"');
37
- expect(html).not.toContain('{[text'); // raw annotation text stripped
38
- });
39
-
40
- it('keeps a text layer body (marks + list) as sibling blocks, not in the heading', () => {
41
- const html = markdownToTiptap(
42
- ['### {#text-1} {[text x=0 y=0]}', '', 'Hello **world**', '', '- a', '- b'].join('\n'),
43
- );
44
- // Heading is empty; the body is its own paragraph + list.
45
- expect(html).toContain('<strong>world</strong>');
46
- expect(html).toContain('<ul>');
47
- expect(html).toContain('<li>');
48
- });
49
-
50
- it('round-trips a full layout (text + box + image) losslessly and idempotently', () => {
51
- const back = tiptapToMarkdown(markdownToTiptap(LAYOUT));
52
- expect(back).toContain('## Pricing {[layout]}');
53
- // Child sub-blocks keep their id + annotation (empty-text headings get an
54
- // extra space after `###`, which re-parses identically — assert spacing-free).
55
- expect(back).toContain('{#text-1} {[text x=360 y=380 width=1200 height=320 align=center]}');
56
- expect(back).toContain(
57
- '{#box-1} {[rectangle x=760 y=390 width=400 height=300 fill="#e0e7ff"]}',
58
- );
59
- expect(back).toContain(
60
- '{#pic-1} {[image x=40 y=40 width=320 height=240 src=cover.png alt="Cover"]}',
61
- );
62
- // The text layer's body markdown survives as readable content.
63
- expect(back).toContain('Welcome to the **bold** layout');
64
- expect(back).toContain('- first point');
65
- expect(back).toContain('- second point');
66
- // No base64 layers blob anywhere — the whole point of the change.
67
- expect(back).not.toContain('layers=');
68
- // Stable: a second pass reproduces the first exactly.
69
- expect(tiptapToMarkdown(markdownToTiptap(back))).toBe(back);
70
- });
71
- });
@@ -1,137 +0,0 @@
1
- /**
2
- * Covers the LinkDialog's "Browse documents" picker added behind the
3
- * `documentLinkProvider` prop. The picker is purely additive — when
4
- * the prop is absent the dialog renders its original URL-only layout.
5
- */
6
-
7
- import { describe, expect, it, vi } from 'vitest';
8
- import { fireEvent, render, screen, waitFor } from '@testing-library/react';
9
- import { LinkDialog } from '../LinkDialog';
10
- import type { DocumentLinkProvider } from '../EditorContext';
11
-
12
- const NEIGHBORS = [
13
- { path: 'resume.md', label: 'Resume', description: 'My CV' },
14
- { path: 'projects.md', label: 'Projects' },
15
- { path: 'misc/notes.md', label: 'Notes', description: 'Scratchpad' },
16
- ];
17
-
18
- const provider: DocumentLinkProvider = async (q) => {
19
- const query = q.trim().toLowerCase();
20
- if (!query) return NEIGHBORS;
21
- return NEIGHBORS.filter(
22
- (n) => n.label.toLowerCase().includes(query) || n.path.toLowerCase().includes(query),
23
- );
24
- };
25
-
26
- describe('LinkDialog — document picker', () => {
27
- it('hides the documents tab when no provider is supplied', () => {
28
- render(
29
- <LinkDialog
30
- mode="insert"
31
- initialText=""
32
- initialUrl=""
33
- onConfirm={() => {}}
34
- onClose={() => {}}
35
- />,
36
- );
37
- expect(screen.queryByRole('tab', { name: /browse documents/i })).toBeNull();
38
- });
39
-
40
- it('shows both tabs when the provider is supplied', () => {
41
- render(
42
- <LinkDialog
43
- mode="insert"
44
- initialText=""
45
- initialUrl=""
46
- onConfirm={() => {}}
47
- onClose={() => {}}
48
- documentLinkProvider={provider}
49
- />,
50
- );
51
- expect(screen.getByRole('tab', { name: 'URL' })).toBeTruthy();
52
- expect(screen.getByRole('tab', { name: 'Browse documents' })).toBeTruthy();
53
- });
54
-
55
- it('lists initial candidates when the documents tab opens', async () => {
56
- render(
57
- <LinkDialog
58
- mode="insert"
59
- initialText=""
60
- initialUrl=""
61
- onConfirm={() => {}}
62
- onClose={() => {}}
63
- documentLinkProvider={provider}
64
- />,
65
- );
66
- fireEvent.click(screen.getByRole('tab', { name: 'Browse documents' }));
67
- await waitFor(() => {
68
- expect(screen.getByText('Resume')).toBeTruthy();
69
- expect(screen.getByText('Projects')).toBeTruthy();
70
- expect(screen.getByText('Notes')).toBeTruthy();
71
- });
72
- });
73
-
74
- it('filters candidates as the user types', async () => {
75
- render(
76
- <LinkDialog
77
- mode="insert"
78
- initialText=""
79
- initialUrl=""
80
- onConfirm={() => {}}
81
- onClose={() => {}}
82
- documentLinkProvider={provider}
83
- />,
84
- );
85
- fireEvent.click(screen.getByRole('tab', { name: 'Browse documents' }));
86
- await waitFor(() => screen.getByText('Resume'));
87
- const search = screen.getByLabelText('Search') as HTMLInputElement;
88
- fireEvent.change(search, { target: { value: 'proj' } });
89
- await waitFor(() => {
90
- expect(screen.getByText('Projects')).toBeTruthy();
91
- expect(screen.queryByText('Resume')).toBeNull();
92
- });
93
- });
94
-
95
- it('picking a document fills the URL and auto-fills the caption when empty', async () => {
96
- const onConfirm = vi.fn();
97
- render(
98
- <LinkDialog
99
- mode="insert"
100
- initialText=""
101
- initialUrl=""
102
- onConfirm={onConfirm}
103
- onClose={() => {}}
104
- documentLinkProvider={provider}
105
- />,
106
- );
107
- fireEvent.click(screen.getByRole('tab', { name: 'Browse documents' }));
108
- await waitFor(() => screen.getByText('Resume'));
109
- fireEvent.click(screen.getByRole('option', { name: /Resume/i }));
110
- // After picking, the dialog jumps back to the URL tab so Enter submits.
111
- const urlInput = screen.getByLabelText('URL') as HTMLInputElement;
112
- expect(urlInput.value).toBe('resume.md');
113
- const textInput = screen.getByLabelText('Text') as HTMLInputElement;
114
- expect(textInput.value).toBe('Resume');
115
- // Submit
116
- fireEvent.submit(urlInput.closest('form')!);
117
- expect(onConfirm).toHaveBeenCalledWith('Resume', 'resume.md');
118
- });
119
-
120
- it('preserves a caption the user already typed when picking a document', async () => {
121
- render(
122
- <LinkDialog
123
- mode="insert"
124
- initialText="Read my work"
125
- initialUrl=""
126
- onConfirm={() => {}}
127
- onClose={() => {}}
128
- documentLinkProvider={provider}
129
- />,
130
- );
131
- fireEvent.click(screen.getByRole('tab', { name: 'Browse documents' }));
132
- await waitFor(() => screen.getByText('Resume'));
133
- fireEvent.click(screen.getByRole('option', { name: /Resume/i }));
134
- const textInput = screen.getByLabelText('Text') as HTMLInputElement;
135
- expect(textInput.value).toBe('Read my work');
136
- });
137
- });
@@ -1,26 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import type { DiagramEdge, DiagramNode, EditorShellProps } from '../index';
3
-
4
- // @ts-expect-error React Flow-prefixed types were removed in the major API cleanup.
5
- import type { DiagramRFNode } from '../index';
6
-
7
- describe('major-version editor API types', () => {
8
- it('uses implementation-neutral diagram names', () => {
9
- const node: DiagramNode = { id: 'a', position: { x: 0, y: 0 }, data: { label: 'A' } };
10
- const edge: DiagramEdge = { id: 'a-b', source: 'a', target: 'b' };
11
- expect([node.id, edge.id]).toEqual(['a', 'a-b']);
12
- });
13
-
14
- it('does not accept the removed EditorShell container prop', () => {
15
- const props: EditorShellProps = {
16
- // @ts-expect-error Use workspaceContainer; container was removed.
17
- container: null,
18
- };
19
- expect(props).toHaveProperty('container');
20
- });
21
-
22
- it('keeps the old type import absent', () => {
23
- const legacy: DiagramRFNode | null = null;
24
- expect(legacy).toBeNull();
25
- });
26
- });
@@ -1,110 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import type { MediaProvider } from '@bendyline/squisq/schemas';
3
- import { markdownToTiptap, tiptapToMarkdown } from '../tiptapBridge';
4
-
5
- /**
6
- * Attachment-flow regression: earlier versions of MediaBin dropped
7
- * uploaded files into the bin without inserting a markdown ref into
8
- * the editor body. A user would upload an image, hit Send in the
9
- * downstream chat composer, and the outgoing markdown would have no
10
- * image reference — the downstream consumer would reply "nothing came through."
11
- *
12
- * The fix: after `mediaProvider.addMedia(...)` succeeds, MediaBin
13
- * fires `onMediaUploaded(relativePath, name, mimeType)`. The
14
- * EditorShell wires this to an `insertAtCursor` that emits
15
- * `![alt](attachments/<filename>)` so the file actually participates
16
- * in the outgoing markdown.
17
- *
18
- * These tests exercise the contract directly: the markdown snippet
19
- * produced by the upload callback, once round-tripped through the
20
- * editor's markdown↔HTML bridge, must round-trip back to a form
21
- * the downstream service's image-extraction regex can see.
22
- */
23
-
24
- function fakeMediaProvider(records: string[]): MediaProvider {
25
- let counter = 0;
26
- return {
27
- async addMedia(name: string, _data: ArrayBuffer | Blob | Uint8Array, _mime: string) {
28
- counter += 1;
29
- const relative = `attachments/${counter}-${name}`;
30
- records.push(relative);
31
- return relative;
32
- },
33
- async resolveUrl(relPath: string) {
34
- return relPath;
35
- },
36
- async listMedia() {
37
- return [];
38
- },
39
- async removeMedia(_relPath: string) {
40
- /* no-op */
41
- },
42
- dispose() {
43
- /* no-op */
44
- },
45
- };
46
- }
47
-
48
- /**
49
- * Re-implements the exact snippet EditorShell's `insertMediaRef`
50
- * builds. Keeping this aligned with the real impl would ordinarily
51
- * rely on directly importing the helper; since it's currently inline
52
- * in EditorShell, mirror the logic here and lean on the test to
53
- * alert us if we drift apart.
54
- */
55
- function buildAttachmentSnippet(relativePath: string, name: string, mimeType: string): string {
56
- const alt = name.replace(/\.[^.]+$/, '').replace(/[-_]/g, ' ');
57
- return mimeType.startsWith('image/') ? `![${alt}](${relativePath})` : `[${alt}](${relativePath})`;
58
- }
59
-
60
- describe('media attachment flow', () => {
61
- it('addMedia → buildAttachmentSnippet → markdown round-trip keeps the ref', async () => {
62
- const records: string[] = [];
63
- const provider = fakeMediaProvider(records);
64
-
65
- // Simulate MediaBin.handleFileChange for a single PNG drop.
66
- const pngBytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
67
- const relative = await provider.addMedia('my_screenshot.png', pngBytes, 'image/png');
68
-
69
- expect(records).toEqual([relative]);
70
- const snippet = buildAttachmentSnippet(relative, 'my_screenshot.png', 'image/png');
71
- expect(snippet).toBe(`![my screenshot](${relative})`);
72
-
73
- // Insert snippet into the editor: markdown → HTML → markdown.
74
- // This is the path a real insertAtCursor + tiptap onUpdate goes
75
- // through. The outbound markdown must still contain the ref.
76
- const html = markdownToTiptap(snippet);
77
- expect(html).toMatch(/<img\b/);
78
- expect(html).toContain(`src="${relative}"`);
79
-
80
- const back = tiptapToMarkdown(html);
81
- expect(back).toContain(`![my screenshot](${relative})`);
82
- });
83
-
84
- it('handles empty-alt (most common pasted-image shape)', async () => {
85
- const records: string[] = [];
86
- const provider = fakeMediaProvider(records);
87
- const relative = await provider.addMedia('pasted.png', new Uint8Array([0]), 'image/png');
88
-
89
- // Simulate what happens when alt is empty — common for bare pastes
90
- // where the user hasn't typed a caption.
91
- const snippet = `![](${relative})`;
92
- const html = markdownToTiptap(snippet);
93
- expect(html).toMatch(/<img\b/);
94
- expect(html).toContain(`src="${relative}"`);
95
- const back = tiptapToMarkdown(html);
96
- expect(back).toContain(`![](${relative})`);
97
- });
98
-
99
- it('non-image files fall back to a plain link, still preserving the ref', async () => {
100
- const records: string[] = [];
101
- const provider = fakeMediaProvider(records);
102
- const relative = await provider.addMedia('design.pdf', new Uint8Array([0]), 'application/pdf');
103
- const snippet = buildAttachmentSnippet(relative, 'design.pdf', 'application/pdf');
104
- expect(snippet).toBe(`[design](${relative})`);
105
- // Non-images don't go through the `<img>` regex — they stay as
106
- // plain markdown links, which the service-side extractor ignores
107
- // but the UI renders as normal hyperlinks.
108
- expect(snippet).not.toContain('!');
109
- });
110
- });
@@ -1,90 +0,0 @@
1
- /**
2
- * @vitest-environment jsdom
3
- */
4
- import { describe, expect, it, vi } from 'vitest';
5
- import { fireEvent, render, screen, waitFor } from '@testing-library/react';
6
- import type { MediaEntry, MediaProvider } from '@bendyline/squisq/schemas';
7
- import { MediaBin } from '../MediaBin.js';
8
-
9
- function createProvider(): { provider: MediaProvider; added: string[] } {
10
- const entries: MediaEntry[] = [];
11
- const added: string[] = [];
12
- return {
13
- added,
14
- provider: {
15
- async addMedia(name, data, mimeType) {
16
- const relativePath = `attachments/${name}`;
17
- added.push(relativePath);
18
- entries.push({
19
- name: relativePath,
20
- mimeType,
21
- size: data instanceof Blob ? data.size : data.byteLength,
22
- });
23
- return relativePath;
24
- },
25
- async resolveUrl(path) {
26
- return `blob:${path}`;
27
- },
28
- async listMedia() {
29
- return [...entries];
30
- },
31
- async removeMedia() {},
32
- dispose() {},
33
- },
34
- };
35
- }
36
-
37
- function dataTransfer(files: File[], itemTypes: string[]) {
38
- return {
39
- files,
40
- items: itemTypes.map((type) => ({ kind: 'file', type })),
41
- types: ['Files'],
42
- dropEffect: 'none',
43
- };
44
- }
45
-
46
- describe('MediaBin image drop target', () => {
47
- it('shows a drop affordance and uploads a dropped image through the normal callback', async () => {
48
- const { provider, added } = createProvider();
49
- const onMediaUploaded = vi.fn();
50
- const image = new File([new Uint8Array([1, 2, 3])], 'photo.png', { type: 'image/png' });
51
- Object.defineProperty(image, 'arrayBuffer', {
52
- configurable: true,
53
- value: async () => new Uint8Array([1, 2, 3]).buffer,
54
- });
55
-
56
- const { container } = render(
57
- <MediaBin mediaProvider={provider} isDark onMediaUploaded={onMediaUploaded} />,
58
- );
59
- const bin = container.querySelector('.squisq-media-bin') as HTMLElement;
60
- const transfer = dataTransfer([image], ['image/png']);
61
- await screen.findByText('No files yet.');
62
-
63
- fireEvent.dragEnter(bin, { dataTransfer: transfer });
64
- expect(bin.classList.contains('squisq-media-bin--drop-active')).toBe(true);
65
- expect(screen.getByText('Drop images here')).toBeTruthy();
66
-
67
- fireEvent.drop(bin, { dataTransfer: transfer });
68
-
69
- await waitFor(() => expect(added).toEqual(['attachments/photo.png']));
70
- expect(onMediaUploaded).toHaveBeenCalledWith('attachments/photo.png', 'photo.png', 'image/png');
71
- expect(await screen.findByText('photo.png')).toBeTruthy();
72
- expect(screen.queryByText('Drop images here')).toBeNull();
73
- });
74
-
75
- it('does not activate or upload for a non-image file', async () => {
76
- const { provider, added } = createProvider();
77
- const text = new File(['notes'], 'notes.txt', { type: 'text/plain' });
78
- const { container } = render(<MediaBin mediaProvider={provider} isDark={false} />);
79
- const bin = container.querySelector('.squisq-media-bin') as HTMLElement;
80
- const transfer = dataTransfer([text], ['text/plain']);
81
- await screen.findByText('No files yet.');
82
-
83
- fireEvent.dragEnter(bin, { dataTransfer: transfer });
84
- fireEvent.drop(bin, { dataTransfer: transfer });
85
-
86
- expect(bin.classList.contains('squisq-media-bin--drop-active')).toBe(false);
87
- expect(screen.queryByText('Drop images here')).toBeNull();
88
- await waitFor(() => expect(added).toEqual([]));
89
- });
90
- });
@@ -1,82 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import {
3
- collectMediaReferencesFromMarkdown,
4
- removeMediaReferencesFromMarkdown,
5
- } from '../mediaReferences';
6
-
7
- describe('collectMediaReferencesFromMarkdown', () => {
8
- it('collects markdown image/link and html media references', () => {
9
- const refs = collectMediaReferencesFromMarkdown(
10
- [
11
- '![One](attachments/one.png)',
12
- '[Two](attachments/two.pdf)',
13
- '<video src="video/clip.webm" poster="video/poster.png"></video>',
14
- '<a href="attachments/three.txt">Three</a>',
15
- ].join('\n'),
16
- );
17
-
18
- expect([...refs].sort()).toEqual([
19
- 'attachments/one.png',
20
- 'attachments/three.txt',
21
- 'attachments/two.pdf',
22
- 'video/clip.webm',
23
- 'video/poster.png',
24
- ]);
25
- });
26
-
27
- it('collects media references from squiggly annotations', () => {
28
- const refs = collectMediaReferencesFromMarkdown(
29
- [
30
- '## Intro {[audio=audio/take.mp3]}',
31
- '{[video src="video/clip with spaces.webm"]}',
32
- '### Image {#hero} {[image src=images/hero.png alt="Hero"]}',
33
- ].join('\n'),
34
- );
35
-
36
- expect([...refs].sort()).toEqual([
37
- 'audio/take.mp3',
38
- 'images/hero.png',
39
- 'video/clip with spaces.webm',
40
- ]);
41
- });
42
- });
43
-
44
- describe('removeMediaReferencesFromMarkdown', () => {
45
- it('removes standalone image references to the media path', () => {
46
- const source = ['Before', '', '![Screenshot](attachments/pasted.png)', '', 'After'].join('\n');
47
-
48
- expect(removeMediaReferencesFromMarkdown(source, 'attachments/pasted.png')).toBe(
49
- ['Before', '', '', 'After'].join('\n'),
50
- );
51
- });
52
-
53
- it('removes inline image and link references without touching similar paths', () => {
54
- const source = [
55
- 'Keep ![Other](attachments/pasted.png.backup).',
56
- 'Drop ![Screenshot](attachments/pasted.png) and [file](attachments/pasted.png).',
57
- ].join('\n');
58
-
59
- expect(removeMediaReferencesFromMarkdown(source, 'attachments/pasted.png')).toBe(
60
- ['Keep ![Other](attachments/pasted.png.backup).', 'Drop and .'].join('\n'),
61
- );
62
- });
63
-
64
- it('supports angle-wrapped destinations and markdown titles', () => {
65
- const source =
66
- 'Drop ![A](<attachments/my pasted image.png>) and [A](attachments/simple.png "title").';
67
-
68
- expect(removeMediaReferencesFromMarkdown(source, 'attachments/my pasted image.png')).toBe(
69
- 'Drop and [A](attachments/simple.png "title").',
70
- );
71
- expect(removeMediaReferencesFromMarkdown(source, 'attachments/simple.png')).toBe(
72
- 'Drop ![A](<attachments/my pasted image.png>) and .',
73
- );
74
- });
75
-
76
- it('removes resized raw HTML image tags and raw HTML anchors', () => {
77
- const source =
78
- '<img alt="Screenshot" src="attachments/pasted.png" width="320">\n<a href="attachments/pasted.png">Screenshot</a>';
79
-
80
- expect(removeMediaReferencesFromMarkdown(source, 'attachments/pasted.png')).toBe('\n');
81
- });
82
- });