@bendyline/squisq-editor-react 2.1.0 → 2.3.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.
- package/LICENSE +21 -0
- package/NOTICE.md +40 -0
- package/dist/chunk-54UGTQBO.js +862 -0
- package/dist/chunk-5JMHFAVW.js +2408 -0
- package/dist/chunk-5Q4JN4I5.js +132 -0
- package/dist/chunk-6VDYKI3L.js +49 -0
- package/dist/chunk-GS7QWYFT.js +9 -0
- package/dist/chunk-MJJK7YQB.js +949 -0
- package/dist/chunk-NITZVAXL.js +986 -0
- package/dist/chunk-TRCKHRBS.js +35234 -0
- package/dist/chunk-V44VP242.js +3256 -0
- package/dist/image-editor/index.d.ts +223 -0
- package/dist/image-editor/index.js +15 -0
- package/dist/index.d.ts +2060 -4040
- package/dist/index.js +496 -40014
- package/dist/json-editor/index.d.ts +27 -0
- package/dist/json-editor/index.js +7 -0
- package/dist/monaco.d.ts +1 -1
- package/dist/monaco.js +1 -2
- package/dist/recorder/index.d.ts +407 -0
- package/dist/recorder/index.js +43 -0
- package/dist/shell/index.d.ts +9 -0
- package/dist/shell/index.js +22 -0
- package/dist/shell-BxSCBm4H.d.ts +1064 -0
- package/dist/styles/index.css +598 -161
- package/dist/teleprompter/index.d.ts +497 -0
- package/dist/teleprompter/index.js +57 -0
- package/package.json +34 -8
- package/dist/index.js.map +0 -1
- package/dist/monaco.js.map +0 -1
- package/src/BlockCardView.tsx +0 -121
- package/src/BlockPreviewPanel.tsx +0 -69
- package/src/BlockPropertiesPopover.tsx +0 -222
- package/src/DocumentSettingsDialog.tsx +0 -272
- package/src/DropZoneOverlay.tsx +0 -137
- package/src/EditorContext.tsx +0 -1274
- package/src/EditorShell.tsx +0 -1358
- package/src/EmojiPicker.tsx +0 -332
- package/src/FolderView.tsx +0 -131
- package/src/Icon.tsx +0 -26
- package/src/ImageEditor.tsx +0 -395
- package/src/ImageNodeView.tsx +0 -284
- package/src/ImageViewer.tsx +0 -221
- package/src/InlineIcon.ts +0 -84
- package/src/InlinePreviewGutter.tsx +0 -590
- package/src/LinkDialog.tsx +0 -276
- package/src/MediaBin.tsx +0 -500
- package/src/MentionExtension.tsx +0 -261
- package/src/OutlinePanel.tsx +0 -547
- package/src/PlainHtmlPreview.tsx +0 -277
- package/src/PreviewControls.tsx +0 -1265
- package/src/PreviewPanel.tsx +0 -426
- package/src/RawEditor.tsx +0 -743
- package/src/RecorderEntry.tsx +0 -162
- package/src/StatusBar.tsx +0 -51
- package/src/TemplateAnnotation.ts +0 -167
- package/src/TemplateContentPreview.tsx +0 -56
- package/src/TemplatePicker.tsx +0 -1314
- package/src/ThemeCustomizerPanel.tsx +0 -304
- package/src/ThemePicker.tsx +0 -433
- package/src/TimelineBlockPreview.tsx +0 -37
- package/src/TimelineTrack.tsx +0 -671
- package/src/Toolbar.tsx +0 -2885
- package/src/Tooltip.tsx +0 -142
- package/src/TransitionPicker.tsx +0 -390
- package/src/VersionHistoryPanel.tsx +0 -359
- package/src/ViewMenuPanel.tsx +0 -189
- package/src/ViewSwitcher.tsx +0 -56
- package/src/WysiwygEditor.tsx +0 -806
- package/src/__tests__/blockProperties.test.ts +0 -92
- package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +0 -33
- package/src/__tests__/blockRange.test.ts +0 -105
- package/src/__tests__/blockTagActivity.test.ts +0 -183
- package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +0 -75
- package/src/__tests__/buildPreviewDocContent.test.ts +0 -65
- package/src/__tests__/buildPreviewDocTransition.test.ts +0 -92
- package/src/__tests__/canvasSurfaceTextEditing.test.tsx +0 -60
- package/src/__tests__/codeContextSectionView.test.tsx +0 -97
- package/src/__tests__/codeContextZoneManager.test.ts +0 -127
- package/src/__tests__/createShapeLayer.test.ts +0 -46
- package/src/__tests__/customLayoutManagerTheme.test.tsx +0 -34
- package/src/__tests__/detectMarkdown.test.ts +0 -73
- package/src/__tests__/diffContextSections.test.ts +0 -39
- package/src/__tests__/documentSettingsDialog.test.tsx +0 -197
- package/src/__tests__/drawingShapeRoundTrip.test.ts +0 -49
- package/src/__tests__/editorScrollHandoff.test.tsx +0 -102
- package/src/__tests__/editorScrollSync.test.ts +0 -65
- package/src/__tests__/editorShellCodeContext.test.tsx +0 -86
- package/src/__tests__/editorShellProps.test.tsx +0 -550
- package/src/__tests__/embeddedMedia.test.ts +0 -48
- package/src/__tests__/emojiPicker.test.tsx +0 -93
- package/src/__tests__/fileKind.test.ts +0 -112
- package/src/__tests__/findMode.test.tsx +0 -104
- package/src/__tests__/findModel.test.ts +0 -55
- package/src/__tests__/headingTransition.test.ts +0 -176
- package/src/__tests__/imageEditAffordance.test.tsx +0 -272
- package/src/__tests__/imageEditModalContract.test.tsx +0 -119
- package/src/__tests__/imageEditorShell.test.tsx +0 -94
- package/src/__tests__/imageEditorState.test.ts +0 -171
- package/src/__tests__/inlinePreviewGutter.test.tsx +0 -62
- package/src/__tests__/inlinePreviewGutterAllBlocks.test.tsx +0 -103
- package/src/__tests__/jsonEditor.test.tsx +0 -223
- package/src/__tests__/layersPanel.test.tsx +0 -167
- package/src/__tests__/layoutChildRoundTrip.test.ts +0 -71
- package/src/__tests__/linkDialogDocPicker.test.tsx +0 -137
- package/src/__tests__/majorApiTypes.test.ts +0 -26
- package/src/__tests__/markdownCodeFence.test.ts +0 -45
- package/src/__tests__/mediaAttachmentFlow.test.ts +0 -110
- package/src/__tests__/mediaBinDrop.test.tsx +0 -90
- package/src/__tests__/mediaReferences.test.ts +0 -97
- package/src/__tests__/narrationSave.test.ts +0 -148
- package/src/__tests__/outlinePanel.test.tsx +0 -169
- package/src/__tests__/outlineSource.test.ts +0 -217
- package/src/__tests__/plainHtmlPreview.test.tsx +0 -125
- package/src/__tests__/presentationMode.test.tsx +0 -290
- package/src/__tests__/previewControls.test.tsx +0 -571
- package/src/__tests__/previewPanelAudioFailure.test.tsx +0 -46
- package/src/__tests__/previewPanelPresentation.test.tsx +0 -126
- package/src/__tests__/previewPanelTransforms.test.tsx +0 -117
- package/src/__tests__/propertiesPanel.test.tsx +0 -69
- package/src/__tests__/rawEditorModelIsolation.test.ts +0 -19
- package/src/__tests__/recorderFormats.test.ts +0 -146
- package/src/__tests__/recorderMediaInsert.test.ts +0 -86
- package/src/__tests__/recorderTheme.test.tsx +0 -42
- package/src/__tests__/recorderTimingJson.test.ts +0 -41
- package/src/__tests__/resolveBlockVisual.test.ts +0 -43
- package/src/__tests__/selectionConversions.test.ts +0 -80
- package/src/__tests__/statusBar.test.tsx +0 -27
- package/src/__tests__/teleprompter.test.tsx +0 -190
- package/src/__tests__/templateAnnotationRoundTrip.test.ts +0 -99
- package/src/__tests__/templateContentPreview.test.ts +0 -101
- package/src/__tests__/templatePickerMetadata.test.ts +0 -32
- package/src/__tests__/templatePickerPortal.test.tsx +0 -62
- package/src/__tests__/timelineSource.test.ts +0 -134
- package/src/__tests__/tiptapBridge.test.ts +0 -575
- package/src/__tests__/tiptapBridgeConformance.test.ts +0 -47
- package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +0 -109
- package/src/__tests__/tiptapImageRoundTrip.test.ts +0 -73
- package/src/__tests__/toolbarSelectionConversion.test.tsx +0 -190
- package/src/__tests__/tooltip.test.tsx +0 -72
- package/src/__tests__/transformStyleId.test.ts +0 -13
- package/src/__tests__/transitionCatalog.test.ts +0 -64
- package/src/__tests__/useBlockNavigator.test.tsx +0 -67
- package/src/__tests__/useImageEditor.test.tsx +0 -226
- package/src/__tests__/useJsonEditorTokens.test.ts +0 -59
- package/src/__tests__/useMediaRecorder.test.ts +0 -302
- package/src/__tests__/useTimelineClock.test.ts +0 -21
- package/src/__tests__/versionHistory.test.tsx +0 -197
- package/src/__tests__/viewMenuPanel.test.tsx +0 -130
- package/src/__tests__/writeCanvasSettings.test.ts +0 -15
- package/src/__tests__/wysiwygImageUpload.test.ts +0 -69
- package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +0 -56
- package/src/asciiDiagram/AsciiDiagramExtension.ts +0 -343
- package/src/asciiDiagram/AsciiDiagramWidget.tsx +0 -254
- package/src/asciiDiagram/RepairableDiagramExtension.ts +0 -200
- package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +0 -164
- package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +0 -159
- package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +0 -284
- package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +0 -114
- package/src/asciiDiagram/__tests__/asciiPaste.test.ts +0 -43
- package/src/asciiDiagram/asciiDiagramCommands.ts +0 -174
- package/src/asciiDiagram/asciiDiagramData.ts +0 -149
- package/src/asciiDiagram/asciiDiagramOps.ts +0 -238
- package/src/asciiDiagram/asciiPaste.ts +0 -19
- package/src/blockProperties.ts +0 -88
- package/src/blockRange.ts +0 -132
- package/src/blockSlice.ts +0 -75
- package/src/blockTagActivity.ts +0 -233
- package/src/buildDocumentPreviewMarkdown.ts +0 -168
- package/src/buildPreviewDoc.ts +0 -407
- package/src/codeContext/CodeContextSectionView.tsx +0 -124
- package/src/codeContext/CodeContextZoneManager.ts +0 -149
- package/src/codeContext/CodeContextZones.tsx +0 -121
- package/src/codeContext/diffContextSections.ts +0 -38
- package/src/codeContext/types.ts +0 -75
- package/src/codeSnippet/CodeSnippetExtension.ts +0 -205
- package/src/codeSnippet/CodeSnippetWidget.tsx +0 -109
- package/src/codeSnippet/__tests__/CodeSnippetExtension.test.ts +0 -95
- package/src/codeSnippet/__tests__/codeSnippetLanguages.test.ts +0 -50
- package/src/codeSnippet/codeSnippetCommands.ts +0 -21
- package/src/codeSnippet/codeSnippetData.ts +0 -43
- package/src/codeSnippet/codeSnippetLanguages.ts +0 -216
- package/src/customTemplates/AddBin.tsx +0 -126
- package/src/customTemplates/CustomLayoutManager.tsx +0 -234
- package/src/customTemplates/CustomTemplateContext.tsx +0 -188
- package/src/customTemplates/LayerToolbar.tsx +0 -580
- package/src/customTemplates/ShapeGlyph.tsx +0 -47
- package/src/customTemplates/TemplateDesigner.tsx +0 -433
- package/src/customTemplates/__tests__/library.test.ts +0 -96
- package/src/customTemplates/__tests__/normalizePositions.test.ts +0 -109
- package/src/customTemplates/__tests__/shapeDefs.test.ts +0 -49
- package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +0 -108
- package/src/customTemplates/designer.css +0 -732
- package/src/customTemplates/index.ts +0 -31
- package/src/customTemplates/library.ts +0 -110
- package/src/customTemplates/normalizePositions.ts +0 -75
- package/src/customTemplates/shapeDefs.ts +0 -131
- package/src/customTemplates/thumbnail.tsx +0 -63
- package/src/customTemplates/tokenDefs.ts +0 -60
- package/src/customTemplates/useDocCustomTemplates.ts +0 -52
- package/src/customTemplates/useMemoryLayerAdapter.ts +0 -129
- package/src/customThemes/CustomThemeContext.tsx +0 -185
- package/src/customThemes/CustomThemeDialog.tsx +0 -316
- package/src/customThemes/ImportThemeSection.tsx +0 -178
- package/src/customThemes/__tests__/CustomThemeContext.test.tsx +0 -64
- package/src/customThemes/__tests__/CustomThemeDialog.test.tsx +0 -47
- package/src/customThemes/__tests__/customThemeLibrary.test.ts +0 -60
- package/src/customThemes/__tests__/importThemeSection.test.tsx +0 -192
- package/src/customThemes/customThemeLibrary.ts +0 -100
- package/src/customThemes/index.ts +0 -37
- package/src/customThemes/themeControls.tsx +0 -229
- package/src/customThemes/themeDraft.ts +0 -288
- package/src/customThemes/useDocCustomThemes.ts +0 -49
- package/src/detectMarkdown.ts +0 -62
- package/src/diagram/DiagramCanvas.tsx +0 -260
- package/src/diagram/DiagramMaximizedOverlay.tsx +0 -46
- package/src/diagram/diagramCommands.ts +0 -604
- package/src/diagram/diagramConstants.ts +0 -17
- package/src/diagram/types.ts +0 -35
- package/src/editorScrollSync.ts +0 -73
- package/src/embeddedMedia.ts +0 -78
- package/src/emojiData.ts +0 -1317
- package/src/fileKind.ts +0 -158
- package/src/find/FindHighlightExtension.ts +0 -81
- package/src/find/FindToolbar.tsx +0 -314
- package/src/find/findModel.ts +0 -77
- package/src/frontmatter.ts +0 -29
- package/src/frontmatterSettings.ts +0 -23
- package/src/headingTransition.ts +0 -291
- package/src/hooks/useFileDrop.ts +0 -266
- package/src/imageEditor/CanvasSurface.tsx +0 -703
- package/src/imageEditor/ImageVersionHistoryDropdown.tsx +0 -396
- package/src/imageEditor/LayersPanel.tsx +0 -218
- package/src/imageEditor/PropertiesPanel.tsx +0 -474
- package/src/imageEditor/Toolbar.tsx +0 -459
- package/src/imageEditor/createShapeLayer.ts +0 -280
- package/src/imageEditor/icons.tsx +0 -68
- package/src/imageEditor/image-editor.css +0 -574
- package/src/imageEditor/layers/EditorImageLayer.tsx +0 -45
- package/src/imageEditor/layers/EditorShapeLayer.tsx +0 -62
- package/src/imageEditor/layers/EditorTextLayer.tsx +0 -45
- package/src/imageEditor/layers/SelectionHandles.tsx +0 -86
- package/src/imageEditor/state.ts +0 -173
- package/src/imageEditor/useImageEditor.ts +0 -385
- package/src/imageEditor/useImageEditorTokens.ts +0 -70
- package/src/index.ts +0 -559
- package/src/jsonEditor/EmbeddedRichTextField.tsx +0 -81
- package/src/jsonEditor/JsonEditor.tsx +0 -81
- package/src/jsonEditor/JsonEditorContext.tsx +0 -81
- package/src/jsonEditor/RenderNode.tsx +0 -87
- package/src/jsonEditor/editors.tsx +0 -745
- package/src/jsonEditor/index.ts +0 -2
- package/src/jsonEditor/json-editor.css +0 -463
- package/src/jsonEditor/useJsonEditorTokens.ts +0 -33
- package/src/markdownCodeFence.ts +0 -72
- package/src/mediaDragMime.ts +0 -32
- package/src/mediaEntries.ts +0 -12
- package/src/mediaReferences.ts +0 -301
- package/src/mermaid/MermaidDiagramCanvas.tsx +0 -693
- package/src/mermaid/MermaidDiagramExtension.ts +0 -243
- package/src/mermaid/MermaidDiagramTypeThumbnail.tsx +0 -184
- package/src/mermaid/MermaidDiagramWidget.tsx +0 -653
- package/src/mermaid/MermaidShapePalette.tsx +0 -245
- package/src/mermaid/__tests__/MermaidDiagramExtension.test.ts +0 -361
- package/src/mermaid/__tests__/mermaidDiagramTypes.test.ts +0 -35
- package/src/mermaid/__tests__/mermaidRenderer.test.ts +0 -49
- package/src/mermaid/__tests__/mermaidSourceOps.test.ts +0 -213
- package/src/mermaid/__tests__/mermaidSyntax.test.ts +0 -71
- package/src/mermaid/mermaidCommands.ts +0 -34
- package/src/mermaid/mermaidData.ts +0 -31
- package/src/mermaid/mermaidDiagramTypes.ts +0 -325
- package/src/mermaid/mermaidModel.ts +0 -31
- package/src/mermaid/mermaidRenderer.ts +0 -181
- package/src/mermaid/mermaidShapes.ts +0 -113
- package/src/mermaid/mermaidSourceOps.ts +0 -454
- package/src/monaco.ts +0 -35
- package/src/monacoWorkers.ts +0 -89
- package/src/outlineSource.ts +0 -171
- package/src/presentation/PresentationMode.tsx +0 -596
- package/src/rawEditorIsolation.ts +0 -18
- package/src/recorder/RecorderButton.tsx +0 -80
- package/src/recorder/RecorderModal.tsx +0 -706
- package/src/recorder/RecorderPanel.tsx +0 -77
- package/src/recorder/formats.ts +0 -159
- package/src/recorder/hooks/useMediaRecorder.ts +0 -436
- package/src/recorder/hooks/useStreamPreview.ts +0 -47
- package/src/recorder/insertMediaBlock.ts +0 -30
- package/src/recorder/sources/cameraStream.ts +0 -32
- package/src/recorder/sources/micStream.ts +0 -25
- package/src/recorder/sources/screenStream.ts +0 -162
- package/src/recorder/timingJson.ts +0 -66
- package/src/resolveBlockVisual.ts +0 -39
- package/src/scene/Scene.tsx +0 -647
- package/src/scene/SceneBlockExtension.ts +0 -205
- package/src/scene/SceneBlockToolbar.tsx +0 -216
- package/src/scene/SceneBlockWidget.tsx +0 -441
- package/src/scene/ScenePropsBar.tsx +0 -85
- package/src/scene/SceneSelection.tsx +0 -111
- package/src/scene/SceneSideToolbar.tsx +0 -89
- package/src/scene/SceneViewControls.tsx +0 -43
- package/src/scene/SceneViewport.tsx +0 -106
- package/src/scene/ShapePalette.tsx +0 -196
- package/src/scene/__tests__/DiagramAdapter.test.ts +0 -142
- package/src/scene/__tests__/SceneBlockExtension.test.ts +0 -33
- package/src/scene/__tests__/bezierEdit.test.ts +0 -85
- package/src/scene/__tests__/blockLayers.test.ts +0 -57
- package/src/scene/__tests__/fitScale.test.ts +0 -19
- package/src/scene/__tests__/sceneIsolation.test.tsx +0 -119
- package/src/scene/__tests__/shapeLayers.test.ts +0 -106
- package/src/scene/__tests__/useSceneHitTest.test.ts +0 -90
- package/src/scene/__tests__/useScenePanZoom.test.ts +0 -130
- package/src/scene/adapters/DiagramAdapter.ts +0 -79
- package/src/scene/adapters/DrawingAdapter.ts +0 -420
- package/src/scene/adapters/LayoutAdapter.ts +0 -313
- package/src/scene/adapters/blockLayers.ts +0 -159
- package/src/scene/commands/SceneCommand.ts +0 -84
- package/src/scene/commands/drawingCommands.ts +0 -318
- package/src/scene/commands/layoutCommands.ts +0 -301
- package/src/scene/fitScale.ts +0 -17
- package/src/scene/hooks/useSceneHitTest.ts +0 -105
- package/src/scene/hooks/useScenePanZoom.ts +0 -154
- package/src/scene/hooks/useSceneSelection.ts +0 -62
- package/src/scene/index.ts +0 -90
- package/src/scene/layers/DiagramEdges.tsx +0 -142
- package/src/scene/layers/edgeGeometry.ts +0 -104
- package/src/scene/layers/nodeCard.tsx +0 -164
- package/src/scene/layers/renderLayer.tsx +0 -70
- package/src/scene/layers/shapeLayers.ts +0 -201
- package/src/scene/paths/bezierEdit.ts +0 -208
- package/src/scene/scene.css +0 -874
- package/src/scene/text/SceneTextOverlay.tsx +0 -161
- package/src/scene/text/sceneTextChannel.ts +0 -46
- package/src/scene/text/sceneTextConfig.ts +0 -31
- package/src/scene/text/sceneTiptap.ts +0 -36
- package/src/scene/text/useSceneTextEditing.ts +0 -39
- package/src/scene/tools/ConnectTool.ts +0 -209
- package/src/scene/tools/DrawingConnectTool.ts +0 -231
- package/src/scene/tools/PathTool.ts +0 -158
- package/src/scene/tools/PlaceTool.ts +0 -47
- package/src/scene/tools/SceneTool.ts +0 -85
- package/src/scene/tools/SelectTool.ts +0 -300
- package/src/scene/tools/ShapeTool.ts +0 -143
- package/src/scene/tools/TextTool.ts +0 -72
- package/src/scene/tools/TokenTool.ts +0 -95
- package/src/scene/tools/createDrawShapeTool.ts +0 -82
- package/src/selectionConversions.ts +0 -155
- package/src/styles/ascii-diagram.css +0 -79
- package/src/styles/ascii-timeline.css +0 -596
- package/src/styles/code-context.css +0 -155
- package/src/styles/code-snippet.css +0 -76
- package/src/styles/diagram.css +0 -183
- package/src/styles/editor.css +0 -7131
- package/src/styles/folder-view.css +0 -210
- package/src/styles/image-edit-affordance.css +0 -201
- package/src/styles/index.css +0 -20
- package/src/styles/mermaid-diagram.css +0 -487
- package/src/styles/tree-view.css +0 -189
- package/src/teleprompter/TeleprompterControls.tsx +0 -218
- package/src/teleprompter/TeleprompterSelfView.tsx +0 -22
- package/src/teleprompter/TeleprompterSurface.tsx +0 -267
- package/src/teleprompter/TeleprompterView.tsx +0 -338
- package/src/teleprompter/canvasRenderer.ts +0 -161
- package/src/teleprompter/floatingWindow.ts +0 -352
- package/src/teleprompter/index.ts +0 -61
- package/src/teleprompter/pcmWorklet.ts +0 -62
- package/src/teleprompter/recording/insertPreamble.ts +0 -80
- package/src/teleprompter/recording/narrationSave.ts +0 -134
- package/src/teleprompter/recording/useNarrationRecorder.ts +0 -367
- package/src/teleprompter/scrollModel.ts +0 -85
- package/src/teleprompter/teleprompterTheme.ts +0 -303
- package/src/teleprompter/types.ts +0 -38
- package/src/teleprompter/useFloatingWindow.ts +0 -74
- package/src/teleprompter/useMicAnalysis.ts +0 -211
- package/src/teleprompter/useTeleprompter.ts +0 -421
- package/src/templateContentPreviewResolver.ts +0 -360
- package/src/timeline/TimelineEditorWidget.tsx +0 -861
- package/src/timeline/TimelineViewExtension.ts +0 -252
- package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +0 -414
- package/src/timeline/__tests__/TimelineViewExtension.test.ts +0 -163
- package/src/timeline/__tests__/timelineCommands.test.ts +0 -359
- package/src/timeline/__tests__/timelineOps.test.ts +0 -277
- package/src/timeline/__tests__/timelinePaste.test.ts +0 -34
- package/src/timeline/timelineCommands.ts +0 -421
- package/src/timeline/timelineData.ts +0 -54
- package/src/timeline/timelineOps.ts +0 -381
- package/src/timeline/timelinePaste.ts +0 -8
- package/src/timelineSource.ts +0 -244
- package/src/tiptap/TiptapAudio.tsx +0 -86
- package/src/tiptap/TiptapVideo.tsx +0 -119
- package/src/tiptap/useResolvedMediaSrc.ts +0 -47
- package/src/tiptapBridge.ts +0 -986
- package/src/tooltipPlacement.ts +0 -13
- package/src/transformStyleId.ts +0 -17
- package/src/transitionCatalog.ts +0 -159
- package/src/treeview/TreeOutlineWidget.tsx +0 -390
- package/src/treeview/TreeViewExtension.ts +0 -250
- package/src/treeview/__tests__/TreeOutlineWidget.test.tsx +0 -156
- package/src/treeview/__tests__/TreeViewExtension.test.ts +0 -122
- package/src/treeview/__tests__/treeOps.test.ts +0 -177
- package/src/treeview/__tests__/treePaste.test.ts +0 -40
- package/src/treeview/__tests__/treeViewCommands.test.ts +0 -179
- package/src/treeview/treeOps.ts +0 -231
- package/src/treeview/treePaste.ts +0 -13
- package/src/treeview/treeViewCommands.ts +0 -99
- package/src/treeview/treeViewData.ts +0 -41
- package/src/types/monaco-shims.d.ts +0 -10
- package/src/useBlockNavigator.ts +0 -153
- package/src/useHeadingLayout.ts +0 -294
- package/src/useMonacoLoader.ts +0 -82
- package/src/useTimelineClock.ts +0 -76
- package/src/utils/collectInlineFontAwesomeCss.ts +0 -69
- package/src/utils/dropUtils.ts +0 -136
- package/src/utils/normalizeMalformedAssetUrl.ts +0 -22
- package/src/writeCanvasSettings.ts +0 -30
- package/src/wysiwygImageUpload.ts +0 -113
|
@@ -1,550 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @vitest-environment jsdom
|
|
3
|
-
*
|
|
4
|
-
* Prop-contract tests for the v1.5 naming renames:
|
|
5
|
-
* - `<EditorShell>`'s light/dark chrome prop is `colorScheme` (was
|
|
6
|
-
* `theme`), and it drives the `data-theme` attribute on the shell root.
|
|
7
|
-
* - `<RawEditor>`'s Monaco theme-string prop is `monacoTheme` (was
|
|
8
|
-
* `theme`); the shell maps `colorScheme` → `monacoTheme` (`'dark'` →
|
|
9
|
-
* `'vs-dark'`, `'light'` → `'vs'`).
|
|
10
|
-
*
|
|
11
|
-
* The heavy editing surfaces are stubbed so the shell mounts under jsdom
|
|
12
|
-
* without dragging in monaco-editor or Tiptap. The RawEditor stub records
|
|
13
|
-
* the props it receives so we can assert `monacoTheme` reaches it.
|
|
14
|
-
*/
|
|
15
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
16
|
-
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
|
|
17
|
-
import type { RawEditorProps } from '../RawEditor';
|
|
18
|
-
import type { MediaEntry, MediaProvider } from '@bendyline/squisq/schemas';
|
|
19
|
-
import { useMediaProvider } from '@bendyline/squisq-react';
|
|
20
|
-
|
|
21
|
-
// Records the props the shell passes to RawEditor on each render.
|
|
22
|
-
const rawEditorProps: RawEditorProps[] = [];
|
|
23
|
-
|
|
24
|
-
vi.mock('../RawEditor', () => ({
|
|
25
|
-
RawEditor: (props: RawEditorProps) => {
|
|
26
|
-
rawEditorProps.push(props);
|
|
27
|
-
return <div data-testid="raw-editor-stub" />;
|
|
28
|
-
},
|
|
29
|
-
}));
|
|
30
|
-
vi.mock('../WysiwygEditor', () => ({
|
|
31
|
-
WysiwygEditor: () => <div data-testid="wysiwyg-editor-stub" />,
|
|
32
|
-
}));
|
|
33
|
-
vi.mock('../PreviewPanel', () => ({
|
|
34
|
-
PreviewPanel: () => <div data-testid="preview-stub" />,
|
|
35
|
-
}));
|
|
36
|
-
|
|
37
|
-
import { EditorShell } from '../EditorShell';
|
|
38
|
-
import { EditorProvider, useEditorContext } from '../EditorContext';
|
|
39
|
-
import { Toolbar } from '../Toolbar';
|
|
40
|
-
|
|
41
|
-
function MarkdownSourceProbe() {
|
|
42
|
-
const { markdownSource } = useEditorContext();
|
|
43
|
-
return <pre data-testid="markdown-source">{markdownSource}</pre>;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function MediaProviderProbe({ expected }: { expected: MediaProvider }) {
|
|
47
|
-
const provider = useMediaProvider();
|
|
48
|
-
return (
|
|
49
|
-
<span data-testid="media-context-probe">{provider === expected ? 'same' : 'missing'}</span>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function mediaProviderWith(count: number): MediaProvider {
|
|
54
|
-
const entries: MediaEntry[] = Array.from({ length: count }, (_, i) => ({
|
|
55
|
-
name: `file-${i + 1}.png`,
|
|
56
|
-
mimeType: 'image/png',
|
|
57
|
-
size: i + 1,
|
|
58
|
-
}));
|
|
59
|
-
return {
|
|
60
|
-
async addMedia(name: string) {
|
|
61
|
-
return name;
|
|
62
|
-
},
|
|
63
|
-
async resolveUrl(relPath: string) {
|
|
64
|
-
return relPath;
|
|
65
|
-
},
|
|
66
|
-
async listMedia() {
|
|
67
|
-
return entries;
|
|
68
|
-
},
|
|
69
|
-
async removeMedia() {
|
|
70
|
-
/* no-op */
|
|
71
|
-
},
|
|
72
|
-
dispose() {
|
|
73
|
-
/* no-op */
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function mediaProviderWithCounts(counts: number[]): MediaProvider {
|
|
79
|
-
let callCount = 0;
|
|
80
|
-
return {
|
|
81
|
-
async addMedia(name: string) {
|
|
82
|
-
return name;
|
|
83
|
-
},
|
|
84
|
-
async resolveUrl(relPath: string) {
|
|
85
|
-
return relPath;
|
|
86
|
-
},
|
|
87
|
-
async listMedia() {
|
|
88
|
-
const count = counts[Math.min(callCount, counts.length - 1)] ?? 0;
|
|
89
|
-
callCount += 1;
|
|
90
|
-
return Array.from({ length: count }, (_, i) => ({
|
|
91
|
-
name: `file-${i + 1}.png`,
|
|
92
|
-
mimeType: 'image/png',
|
|
93
|
-
size: i + 1,
|
|
94
|
-
}));
|
|
95
|
-
},
|
|
96
|
-
async removeMedia() {
|
|
97
|
-
/* no-op */
|
|
98
|
-
},
|
|
99
|
-
dispose() {
|
|
100
|
-
/* no-op */
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function mutableMediaProviderWith(entries: MediaEntry[]): {
|
|
106
|
-
provider: MediaProvider;
|
|
107
|
-
removed: string[];
|
|
108
|
-
} {
|
|
109
|
-
let current = [...entries];
|
|
110
|
-
const removed: string[] = [];
|
|
111
|
-
return {
|
|
112
|
-
removed,
|
|
113
|
-
provider: {
|
|
114
|
-
async addMedia(name: string) {
|
|
115
|
-
return name;
|
|
116
|
-
},
|
|
117
|
-
async resolveUrl(relPath: string) {
|
|
118
|
-
return relPath;
|
|
119
|
-
},
|
|
120
|
-
async listMedia() {
|
|
121
|
-
return current;
|
|
122
|
-
},
|
|
123
|
-
async removeMedia(relPath: string) {
|
|
124
|
-
removed.push(relPath);
|
|
125
|
-
current = current.filter((entry) => entry.name !== relPath);
|
|
126
|
-
},
|
|
127
|
-
dispose() {
|
|
128
|
-
/* no-op */
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
beforeEach(() => {
|
|
135
|
-
rawEditorProps.length = 0;
|
|
136
|
-
// jsdom lacks matchMedia / ResizeObserver, which the Toolbar uses.
|
|
137
|
-
if (typeof window !== 'undefined' && typeof window.matchMedia !== 'function') {
|
|
138
|
-
Object.defineProperty(window, 'matchMedia', {
|
|
139
|
-
configurable: true,
|
|
140
|
-
value: (query: string) => ({
|
|
141
|
-
matches: false,
|
|
142
|
-
media: query,
|
|
143
|
-
onchange: null,
|
|
144
|
-
addListener: vi.fn(),
|
|
145
|
-
removeListener: vi.fn(),
|
|
146
|
-
addEventListener: vi.fn(),
|
|
147
|
-
removeEventListener: vi.fn(),
|
|
148
|
-
dispatchEvent: vi.fn(() => false),
|
|
149
|
-
}),
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
if (typeof globalThis.ResizeObserver === 'undefined') {
|
|
153
|
-
class ResizeObserverStub {
|
|
154
|
-
observe(): void {}
|
|
155
|
-
unobserve(): void {}
|
|
156
|
-
disconnect(): void {}
|
|
157
|
-
}
|
|
158
|
-
(globalThis as unknown as { ResizeObserver: typeof ResizeObserverStub }).ResizeObserver =
|
|
159
|
-
ResizeObserverStub;
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe('<EditorShell> colorScheme prop', () => {
|
|
164
|
-
it('applies dark chrome via data-theme when colorScheme="dark"', () => {
|
|
165
|
-
const { container } = render(
|
|
166
|
-
<EditorShell initialMarkdown="# hi" initialView="raw" colorScheme="dark" />,
|
|
167
|
-
);
|
|
168
|
-
const shell = container.querySelector('.squisq-editor-shell');
|
|
169
|
-
expect(shell?.getAttribute('data-theme')).toBe('dark');
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('defaults to light chrome when colorScheme is omitted', () => {
|
|
173
|
-
const { container } = render(<EditorShell initialMarkdown="# hi" initialView="raw" />);
|
|
174
|
-
const shell = container.querySelector('.squisq-editor-shell');
|
|
175
|
-
expect(shell?.getAttribute('data-theme')).toBe('light');
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe('<EditorShell> Write canvas settings', () => {
|
|
180
|
-
it('exposes host settings as live CSS variables on the shell', () => {
|
|
181
|
-
const { container, rerender } = render(
|
|
182
|
-
<EditorShell
|
|
183
|
-
initialMarkdown="Paragraph"
|
|
184
|
-
writeCanvasSettings={{ textSize: 18, lineSpacing: 1.9 }}
|
|
185
|
-
/>,
|
|
186
|
-
);
|
|
187
|
-
const shell = container.querySelector<HTMLElement>('.squisq-editor-shell')!;
|
|
188
|
-
expect(shell.style.getPropertyValue('--squisq-write-text-size')).toBe('18px');
|
|
189
|
-
expect(shell.style.getPropertyValue('--squisq-write-line-spacing')).toBe('1.9');
|
|
190
|
-
|
|
191
|
-
rerender(
|
|
192
|
-
<EditorShell
|
|
193
|
-
initialMarkdown="Paragraph"
|
|
194
|
-
writeCanvasSettings={{ textSize: 20, lineSpacing: 2 }}
|
|
195
|
-
/>,
|
|
196
|
-
);
|
|
197
|
-
expect(shell.style.getPropertyValue('--squisq-write-text-size')).toBe('20px');
|
|
198
|
-
expect(shell.style.getPropertyValue('--squisq-write-line-spacing')).toBe('2');
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
describe('RawEditor monacoTheme prop', () => {
|
|
203
|
-
it('maps colorScheme="dark" to monacoTheme="vs-dark"', () => {
|
|
204
|
-
render(<EditorShell initialMarkdown="# hi" initialView="raw" colorScheme="dark" />);
|
|
205
|
-
expect(screen.getByTestId('raw-editor-stub')).toBeTruthy();
|
|
206
|
-
const last = rawEditorProps[rawEditorProps.length - 1];
|
|
207
|
-
expect(last?.monacoTheme).toBe('vs-dark');
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('maps colorScheme="light" to monacoTheme="vs"', () => {
|
|
211
|
-
render(<EditorShell initialMarkdown="# hi" initialView="raw" colorScheme="light" />);
|
|
212
|
-
expect(screen.getByTestId('raw-editor-stub')).toBeTruthy();
|
|
213
|
-
const last = rawEditorProps[rawEditorProps.length - 1];
|
|
214
|
-
expect(last?.monacoTheme).toBe('vs');
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
describe('<EditorShell> instance boundaries', () => {
|
|
219
|
-
it('provides its mediaProvider to React preview/layer consumers', async () => {
|
|
220
|
-
const provider = mediaProviderWith(0);
|
|
221
|
-
await act(async () => {
|
|
222
|
-
render(
|
|
223
|
-
<EditorShell
|
|
224
|
-
initialMarkdown="# hi"
|
|
225
|
-
initialView="raw"
|
|
226
|
-
mediaProvider={provider}
|
|
227
|
-
toolbarSlotLeft={<MediaProviderProbe expected={provider} />}
|
|
228
|
-
/>,
|
|
229
|
-
);
|
|
230
|
-
});
|
|
231
|
-
expect(screen.getByTestId('media-context-probe').textContent).toBe('same');
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('keeps view shortcuts inside the editor that received the key', async () => {
|
|
235
|
-
const { container } = render(
|
|
236
|
-
<>
|
|
237
|
-
<EditorShell initialMarkdown="# first" initialView="raw" />
|
|
238
|
-
<EditorShell initialMarkdown="# second" initialView="raw" />
|
|
239
|
-
</>,
|
|
240
|
-
);
|
|
241
|
-
const shells = container.querySelectorAll<HTMLElement>('.squisq-editor-shell');
|
|
242
|
-
fireEvent.keyDown(within(shells[1]).getByTestId('raw-editor-stub'), {
|
|
243
|
-
key: '1',
|
|
244
|
-
ctrlKey: true,
|
|
245
|
-
});
|
|
246
|
-
await waitFor(() => expect(within(shells[1]).getByTestId('wysiwyg-editor-stub')).toBeTruthy());
|
|
247
|
-
expect(within(shells[0]).getByTestId('raw-editor-stub')).toBeTruthy();
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('ignores file drops in readOnly mode', async () => {
|
|
251
|
-
const { container } = render(
|
|
252
|
-
<EditorShell
|
|
253
|
-
initialMarkdown="# original"
|
|
254
|
-
initialView="raw"
|
|
255
|
-
readOnly
|
|
256
|
-
toolbarSlotRight={<MarkdownSourceProbe />}
|
|
257
|
-
/>,
|
|
258
|
-
);
|
|
259
|
-
const shell = container.querySelector<HTMLElement>('.squisq-editor-shell')!;
|
|
260
|
-
const file = new File(['# replacement'], 'replacement.md', { type: 'text/markdown' });
|
|
261
|
-
fireEvent.drop(shell, {
|
|
262
|
-
dataTransfer: {
|
|
263
|
-
types: ['Files'],
|
|
264
|
-
files: [file],
|
|
265
|
-
items: [{ kind: 'file', type: 'text/markdown', getAsFile: () => file }],
|
|
266
|
-
},
|
|
267
|
-
});
|
|
268
|
-
await act(async () => Promise.resolve());
|
|
269
|
-
expect(screen.getByTestId('markdown-source').textContent).toBe('# original');
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
describe('<EditorShell> Files badge', () => {
|
|
274
|
-
it('shows the mediaProvider file count on the paperclip button', async () => {
|
|
275
|
-
const { container } = render(
|
|
276
|
-
<EditorShell initialMarkdown="# hi" initialView="raw" mediaProvider={mediaProviderWith(3)} />,
|
|
277
|
-
);
|
|
278
|
-
|
|
279
|
-
await waitFor(() => {
|
|
280
|
-
expect(screen.getByLabelText('Toggle Files panel, 3 files')).toBeTruthy();
|
|
281
|
-
});
|
|
282
|
-
expect(container.querySelector('.squisq-toolbar-files-badge')?.textContent).toBe('3');
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
it('compacts large visible counts while keeping the full count in the label', async () => {
|
|
286
|
-
const { container } = render(
|
|
287
|
-
<EditorShell
|
|
288
|
-
initialMarkdown="# hi"
|
|
289
|
-
initialView="raw"
|
|
290
|
-
mediaProvider={mediaProviderWith(120)}
|
|
291
|
-
/>,
|
|
292
|
-
);
|
|
293
|
-
|
|
294
|
-
await waitFor(() => {
|
|
295
|
-
expect(screen.getByLabelText('Toggle Files panel, 120 files')).toBeTruthy();
|
|
296
|
-
});
|
|
297
|
-
expect(container.querySelector('.squisq-toolbar-files-badge')?.textContent).toBe('99+');
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
it('uses the MediaBin scan count when the panel discovers files', async () => {
|
|
301
|
-
const { container } = render(
|
|
302
|
-
<EditorShell
|
|
303
|
-
initialMarkdown="# hi"
|
|
304
|
-
initialView="raw"
|
|
305
|
-
mediaProvider={mediaProviderWithCounts([0, 1])}
|
|
306
|
-
/>,
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
await waitFor(() => {
|
|
310
|
-
expect(screen.getByLabelText('Toggle Files panel')).toBeTruthy();
|
|
311
|
-
});
|
|
312
|
-
fireEvent.click(screen.getByLabelText('Toggle Files panel'));
|
|
313
|
-
|
|
314
|
-
await waitFor(() => {
|
|
315
|
-
expect(screen.getByLabelText('Toggle Files panel, 1 file')).toBeTruthy();
|
|
316
|
-
});
|
|
317
|
-
expect(container.querySelector('.squisq-toolbar-files-badge')?.textContent).toBe('1');
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it('hides .gitignore entries from the Files panel and its count', async () => {
|
|
321
|
-
const { provider } = mutableMediaProviderWith([
|
|
322
|
-
{ name: '.gitignore', mimeType: 'text/plain', size: 11 },
|
|
323
|
-
{ name: 'notes_files/.gitignore', mimeType: 'text/plain', size: 11 },
|
|
324
|
-
{ name: 'notes_files/hero.png', mimeType: 'image/png', size: 1024 },
|
|
325
|
-
]);
|
|
326
|
-
|
|
327
|
-
render(<EditorShell initialMarkdown="# hi" initialView="raw" mediaProvider={provider} />);
|
|
328
|
-
|
|
329
|
-
await waitFor(() => {
|
|
330
|
-
expect(screen.getByLabelText('Toggle Files panel, 1 file')).toBeTruthy();
|
|
331
|
-
});
|
|
332
|
-
fireEvent.click(screen.getByLabelText('Toggle Files panel, 1 file'));
|
|
333
|
-
|
|
334
|
-
expect(await screen.findByText('hero.png')).toBeTruthy();
|
|
335
|
-
expect(screen.queryByText('.gitignore')).toBeNull();
|
|
336
|
-
expect(screen.getByText('Files (1)')).toBeTruthy();
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it('removes a media file and matching markdown refs from the files context menu', async () => {
|
|
340
|
-
const { provider, removed } = mutableMediaProviderWith([
|
|
341
|
-
{
|
|
342
|
-
name: 'attachments/pasted.png',
|
|
343
|
-
mimeType: 'image/png',
|
|
344
|
-
size: 1024,
|
|
345
|
-
},
|
|
346
|
-
]);
|
|
347
|
-
const changes: string[] = [];
|
|
348
|
-
const initialMarkdown = [
|
|
349
|
-
'Before',
|
|
350
|
-
'',
|
|
351
|
-
'',
|
|
352
|
-
'',
|
|
353
|
-
'After',
|
|
354
|
-
].join('\n');
|
|
355
|
-
|
|
356
|
-
render(
|
|
357
|
-
<EditorShell
|
|
358
|
-
initialMarkdown={initialMarkdown}
|
|
359
|
-
initialView="raw"
|
|
360
|
-
mediaProvider={provider}
|
|
361
|
-
onChange={(source) => changes.push(source)}
|
|
362
|
-
/>,
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
await waitFor(() => {
|
|
366
|
-
expect(screen.getByLabelText('Toggle Files panel, 1 file')).toBeTruthy();
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
fireEvent.click(screen.getByLabelText('Toggle Files panel, 1 file'));
|
|
370
|
-
const item = (await screen.findByText('pasted.png')).closest('.squisq-media-bin-item');
|
|
371
|
-
expect(item).toBeTruthy();
|
|
372
|
-
|
|
373
|
-
fireEvent.contextMenu(item as HTMLElement, { clientX: 24, clientY: 32 });
|
|
374
|
-
fireEvent.click(screen.getByRole('menuitem', { name: 'Remove image' }));
|
|
375
|
-
|
|
376
|
-
await waitFor(() => {
|
|
377
|
-
expect(removed).toEqual(['attachments/pasted.png']);
|
|
378
|
-
});
|
|
379
|
-
await waitFor(() => {
|
|
380
|
-
expect(screen.queryByText('pasted.png')).toBeNull();
|
|
381
|
-
});
|
|
382
|
-
await waitFor(() => {
|
|
383
|
-
expect(changes[changes.length - 1]).toBe(['Before', '', '', 'After'].join('\n'));
|
|
384
|
-
});
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
it('marks files as unused when the document does not reference them', async () => {
|
|
388
|
-
const { container } = render(
|
|
389
|
-
<EditorShell
|
|
390
|
-
initialMarkdown={'\n\n# Notes'}
|
|
391
|
-
initialView="raw"
|
|
392
|
-
mediaProvider={
|
|
393
|
-
mutableMediaProviderWith([
|
|
394
|
-
{
|
|
395
|
-
name: 'attachments/used.png',
|
|
396
|
-
mimeType: 'image/png',
|
|
397
|
-
size: 100,
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
name: 'attachments/unused.png',
|
|
401
|
-
mimeType: 'image/png',
|
|
402
|
-
size: 200,
|
|
403
|
-
},
|
|
404
|
-
]).provider
|
|
405
|
-
}
|
|
406
|
-
/>,
|
|
407
|
-
);
|
|
408
|
-
|
|
409
|
-
await waitFor(() => {
|
|
410
|
-
expect(screen.getByLabelText('Toggle Files panel, 2 files')).toBeTruthy();
|
|
411
|
-
});
|
|
412
|
-
fireEvent.click(screen.getByLabelText('Toggle Files panel, 2 files'));
|
|
413
|
-
|
|
414
|
-
await screen.findByText('used.png');
|
|
415
|
-
await screen.findByText('unused.png');
|
|
416
|
-
|
|
417
|
-
const items = Array.from(container.querySelectorAll('.squisq-media-bin-item'));
|
|
418
|
-
const itemNamed = (name: string) =>
|
|
419
|
-
items.find((item) => item.querySelector('.squisq-media-bin-name')?.textContent === name);
|
|
420
|
-
const usedItem = itemNamed('used.png');
|
|
421
|
-
const unusedItem = itemNamed('unused.png');
|
|
422
|
-
|
|
423
|
-
expect(usedItem?.querySelector('.squisq-media-bin-unused-badge')).toBeNull();
|
|
424
|
-
expect(unusedItem?.querySelector('.squisq-media-bin-unused-badge')?.textContent).toBe('Unused');
|
|
425
|
-
});
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
describe('<Toolbar> Files badge', () => {
|
|
429
|
-
it('self-scans mediaProvider when fileCount is not controlled by a parent', async () => {
|
|
430
|
-
const { container } = render(
|
|
431
|
-
<EditorProvider
|
|
432
|
-
initialMarkdown="# hi"
|
|
433
|
-
initialView="raw"
|
|
434
|
-
mediaProvider={mediaProviderWith(2)}
|
|
435
|
-
allowRecording={false}
|
|
436
|
-
>
|
|
437
|
-
<Toolbar onToggleFiles={() => {}} />
|
|
438
|
-
</EditorProvider>,
|
|
439
|
-
);
|
|
440
|
-
|
|
441
|
-
await waitFor(() => {
|
|
442
|
-
expect(screen.getByLabelText('Toggle Files panel, 2 files')).toBeTruthy();
|
|
443
|
-
});
|
|
444
|
-
expect(container.querySelector('.squisq-toolbar-files-badge')?.textContent).toBe('2');
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
it('excludes .gitignore from a self-scanned count', async () => {
|
|
448
|
-
const { provider } = mutableMediaProviderWith([
|
|
449
|
-
{ name: '.gitignore', mimeType: 'text/plain', size: 11 },
|
|
450
|
-
{ name: 'hero.png', mimeType: 'image/png', size: 1024 },
|
|
451
|
-
]);
|
|
452
|
-
const { container } = render(
|
|
453
|
-
<EditorProvider
|
|
454
|
-
initialMarkdown="# hi"
|
|
455
|
-
initialView="raw"
|
|
456
|
-
mediaProvider={provider}
|
|
457
|
-
allowRecording={false}
|
|
458
|
-
>
|
|
459
|
-
<Toolbar onToggleFiles={() => {}} />
|
|
460
|
-
</EditorProvider>,
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
await waitFor(() => {
|
|
464
|
-
expect(screen.getByLabelText('Toggle Files panel, 1 file')).toBeTruthy();
|
|
465
|
-
});
|
|
466
|
-
expect(container.querySelector('.squisq-toolbar-files-badge')?.textContent).toBe('1');
|
|
467
|
-
});
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
describe('<Toolbar> Insert menu', () => {
|
|
471
|
-
it('adds a default task list from the Insert menu in raw fallback mode', async () => {
|
|
472
|
-
render(
|
|
473
|
-
<EditorProvider initialMarkdown="Intro" initialView="raw" allowRecording={false}>
|
|
474
|
-
<Toolbar />
|
|
475
|
-
<MarkdownSourceProbe />
|
|
476
|
-
</EditorProvider>,
|
|
477
|
-
);
|
|
478
|
-
|
|
479
|
-
fireEvent.click(screen.getByLabelText('Insert'));
|
|
480
|
-
const item = await screen.findByRole('menuitem', { name: /Task List/i });
|
|
481
|
-
|
|
482
|
-
fireEvent.click(item);
|
|
483
|
-
|
|
484
|
-
await waitFor(() => {
|
|
485
|
-
expect(screen.getByTestId('markdown-source').textContent).toBe(
|
|
486
|
-
['Intro', '- [ ] Task 1', '- [ ] Task 2', '- [ ] Task 3', ''].join('\n'),
|
|
487
|
-
);
|
|
488
|
-
});
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
it('adds an explicit authored timeline fence from the Insert menu', async () => {
|
|
492
|
-
render(
|
|
493
|
-
<EditorProvider initialMarkdown="Intro" initialView="raw" allowRecording={false}>
|
|
494
|
-
<Toolbar />
|
|
495
|
-
<MarkdownSourceProbe />
|
|
496
|
-
</EditorProvider>,
|
|
497
|
-
);
|
|
498
|
-
|
|
499
|
-
fireEvent.click(screen.getByLabelText('Insert'));
|
|
500
|
-
fireEvent.click(await screen.findByRole('menuitem', { name: /Timeline/i }));
|
|
501
|
-
|
|
502
|
-
await waitFor(() => {
|
|
503
|
-
expect(screen.getByTestId('markdown-source').textContent).toContain(
|
|
504
|
-
'```timeline\nMilestones: ● Start',
|
|
505
|
-
);
|
|
506
|
-
});
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
it('opens the Mermaid type gallery and inserts the selected diagram grammar', async () => {
|
|
510
|
-
render(
|
|
511
|
-
<EditorProvider initialMarkdown="Intro" initialView="raw" allowRecording={false}>
|
|
512
|
-
<Toolbar />
|
|
513
|
-
<MarkdownSourceProbe />
|
|
514
|
-
</EditorProvider>,
|
|
515
|
-
);
|
|
516
|
-
|
|
517
|
-
fireEvent.click(screen.getByLabelText('Insert'));
|
|
518
|
-
fireEvent.click(await screen.findByRole('menuitem', { name: 'Complex Diagram (Mermaid)' }));
|
|
519
|
-
expect(await screen.findByRole('menu', { name: 'Mermaid diagram type' })).toBeTruthy();
|
|
520
|
-
expect(screen.getByText(/Flow direction remains a separate edit/)).toBeTruthy();
|
|
521
|
-
fireEvent.click(await screen.findByRole('menuitem', { name: 'Insert Gantt Mermaid diagram' }));
|
|
522
|
-
|
|
523
|
-
await waitFor(() => {
|
|
524
|
-
expect(screen.getByTestId('markdown-source').textContent).toContain(
|
|
525
|
-
'```mermaid\ngantt\n title Project plan\n dateFormat YYYY-MM-DD',
|
|
526
|
-
);
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
it('adds a typed code fence from the Code Snippet submenu', async () => {
|
|
531
|
-
render(
|
|
532
|
-
<EditorProvider initialMarkdown="Intro" initialView="raw" allowRecording={false}>
|
|
533
|
-
<Toolbar />
|
|
534
|
-
<MarkdownSourceProbe />
|
|
535
|
-
</EditorProvider>,
|
|
536
|
-
);
|
|
537
|
-
|
|
538
|
-
fireEvent.click(screen.getByLabelText('Insert'));
|
|
539
|
-
fireEvent.click(await screen.findByRole('menuitem', { name: 'Insert Code Snippet' }));
|
|
540
|
-
fireEvent.click(
|
|
541
|
-
await screen.findByRole('menuitem', { name: 'Insert TypeScript code snippet' }),
|
|
542
|
-
);
|
|
543
|
-
|
|
544
|
-
await waitFor(() => {
|
|
545
|
-
expect(screen.getByTestId('markdown-source').textContent).toContain(
|
|
546
|
-
"```typescript\nconst message: string = 'Hello, world!';\n```",
|
|
547
|
-
);
|
|
548
|
-
});
|
|
549
|
-
});
|
|
550
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { parseMarkdown } from '@bendyline/squisq/markdown';
|
|
3
|
-
import { markdownToDoc } from '@bendyline/squisq/doc';
|
|
4
|
-
import { collectEmbeddedMedia, mediaKindFromUrl } from '../embeddedMedia';
|
|
5
|
-
|
|
6
|
-
function block(md: string) {
|
|
7
|
-
return markdownToDoc(parseMarkdown(md), { articleId: 't' }).blocks[0];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
describe('mediaKindFromUrl', () => {
|
|
11
|
-
it('classifies by extension', () => {
|
|
12
|
-
expect(mediaKindFromUrl('a/clip.webm')).toBe('video');
|
|
13
|
-
expect(mediaKindFromUrl('take1.mp3')).toBe('audio');
|
|
14
|
-
expect(mediaKindFromUrl('photo.png')).toBeNull();
|
|
15
|
-
expect(mediaKindFromUrl('https://x.com/page')).toBeNull();
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
describe('collectEmbeddedMedia', () => {
|
|
20
|
-
it('finds a recorder <video> HTML tag with its source line', () => {
|
|
21
|
-
const found = collectEmbeddedMedia(
|
|
22
|
-
block('# Tips\n\n<video src="video/recording.webm" controls></video>\n'),
|
|
23
|
-
);
|
|
24
|
-
expect(found).toEqual([{ src: 'video/recording.webm', kind: 'video', sourceLine: 3 }]);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('finds an <audio> tag', () => {
|
|
28
|
-
const found = collectEmbeddedMedia(block('# Intro\n\n<audio src="audio/take.mp3"></audio>\n'));
|
|
29
|
-
expect(found[0]).toMatchObject({ src: 'audio/take.mp3', kind: 'audio' });
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('finds a markdown link/image to media', () => {
|
|
33
|
-
expect(collectEmbeddedMedia(block('# B\n\n[clip](v/r.webm)\n'))[0]).toMatchObject({
|
|
34
|
-
src: 'v/r.webm',
|
|
35
|
-
kind: 'video',
|
|
36
|
-
});
|
|
37
|
-
expect(collectEmbeddedMedia(block('# B\n\n\n'))[0]).toMatchObject({
|
|
38
|
-
src: 'clip.mp4',
|
|
39
|
-
kind: 'video',
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('ignores plain images and non-media links', () => {
|
|
44
|
-
expect(
|
|
45
|
-
collectEmbeddedMedia(block('# B\n\n\n\n[docs](https://x.com/y)\n')),
|
|
46
|
-
).toEqual([]);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
-
import { EmojiPicker, PICKER_CATEGORIES, ALL_PICKER_ENTRIES, searchPickerEntries } from '../index';
|
|
4
|
-
|
|
5
|
-
describe('emojiData — unified picker entries', () => {
|
|
6
|
-
it('appends FA Brands, Solid, and Regular categories after the emoji buckets', () => {
|
|
7
|
-
const ids = PICKER_CATEGORIES.map((c) => c.id);
|
|
8
|
-
expect(ids).toContain('fa-brands');
|
|
9
|
-
expect(ids).toContain('fa-solid');
|
|
10
|
-
expect(ids).toContain('fa-regular');
|
|
11
|
-
// Order matters — emoji first, FA after.
|
|
12
|
-
expect(ids.indexOf('smileys')).toBeLessThan(ids.indexOf('fa-brands'));
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('FA categories carry icon-kind entries', () => {
|
|
16
|
-
const brands = PICKER_CATEGORIES.find((c) => c.id === 'fa-brands')!;
|
|
17
|
-
expect(brands.entries.length).toBeGreaterThan(0);
|
|
18
|
-
const github = brands.entries.find((e) => e.kind === 'icon' && e.name === 'github');
|
|
19
|
-
expect(github).toBeDefined();
|
|
20
|
-
expect(github!.kind).toBe('icon');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('searchPickerEntries matches across emoji and icons', () => {
|
|
24
|
-
const emojiHit = searchPickerEntries('heart').find((e) => e.kind === 'emoji');
|
|
25
|
-
const iconHit = searchPickerEntries('github').find((e) => e.kind === 'icon');
|
|
26
|
-
expect(emojiHit).toBeDefined();
|
|
27
|
-
expect(iconHit).toBeDefined();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('ALL_PICKER_ENTRIES is the concat of all categories', () => {
|
|
31
|
-
const sum = PICKER_CATEGORIES.reduce((acc, c) => acc + c.entries.length, 0);
|
|
32
|
-
expect(ALL_PICKER_ENTRIES.length).toBe(sum);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('EmojiPicker', () => {
|
|
37
|
-
it('does not render when closed', () => {
|
|
38
|
-
render(<EmojiPicker open={false} onSelect={() => {}} onClose={() => {}} />);
|
|
39
|
-
expect(screen.queryByTestId('emoji-picker')).toBeNull();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('renders all emoji + FA tabs when open', () => {
|
|
43
|
-
render(<EmojiPicker open onSelect={() => {}} onClose={() => {}} />);
|
|
44
|
-
for (const cat of PICKER_CATEGORIES) {
|
|
45
|
-
expect(screen.getByRole('tab', { name: cat.label })).toBeTruthy();
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('fires onSelect with an emoji PickerEntry when an emoji tile is clicked', () => {
|
|
50
|
-
const onSelect = vi.fn();
|
|
51
|
-
render(<EmojiPicker open onSelect={onSelect} onClose={() => {}} />);
|
|
52
|
-
fireEvent.click(screen.getByRole('button', { name: 'grinning' }));
|
|
53
|
-
expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({ kind: 'emoji', char: '😀' }));
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('fires onSelect with an icon PickerEntry when an FA tile is clicked', () => {
|
|
57
|
-
const onSelect = vi.fn();
|
|
58
|
-
render(<EmojiPicker open onSelect={onSelect} onClose={() => {}} />);
|
|
59
|
-
fireEvent.click(screen.getByRole('tab', { name: 'Brands' }));
|
|
60
|
-
fireEvent.click(screen.getByRole('button', { name: 'Github' }));
|
|
61
|
-
expect(onSelect).toHaveBeenCalledWith(
|
|
62
|
-
expect.objectContaining({ kind: 'icon', family: 'brands', name: 'github' }),
|
|
63
|
-
);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('switches categories when a tab is clicked', () => {
|
|
67
|
-
render(<EmojiPicker open onSelect={() => {}} onClose={() => {}} />);
|
|
68
|
-
fireEvent.click(screen.getByRole('tab', { name: 'Nature' }));
|
|
69
|
-
expect(screen.getByRole('button', { name: 'dog face' })).toBeTruthy();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('shows search results across emoji + icons and hides the tabs', () => {
|
|
73
|
-
render(<EmojiPicker open onSelect={() => {}} onClose={() => {}} />);
|
|
74
|
-
const search = screen.getByLabelText('Search emoji & icons') as HTMLInputElement;
|
|
75
|
-
fireEvent.change(search, { target: { value: 'github' } });
|
|
76
|
-
expect(screen.getByRole('button', { name: 'Github' })).toBeTruthy();
|
|
77
|
-
expect(screen.queryByRole('tab', { name: 'Smileys' })).toBeNull();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('shows a no-matches state when search returns nothing', () => {
|
|
81
|
-
render(<EmojiPicker open onSelect={() => {}} onClose={() => {}} />);
|
|
82
|
-
const search = screen.getByLabelText('Search emoji & icons') as HTMLInputElement;
|
|
83
|
-
fireEvent.change(search, { target: { value: 'thisdoesnotexist' } });
|
|
84
|
-
expect(screen.getByText(/No matches for/i)).toBeTruthy();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('fires onClose on Escape', () => {
|
|
88
|
-
const onClose = vi.fn();
|
|
89
|
-
render(<EmojiPicker open onSelect={() => {}} onClose={onClose} />);
|
|
90
|
-
fireEvent.keyDown(document, { key: 'Escape' });
|
|
91
|
-
expect(onClose).toHaveBeenCalled();
|
|
92
|
-
});
|
|
93
|
-
});
|