@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
package/src/OutlinePanel.tsx
DELETED
|
@@ -1,547 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OutlinePanel
|
|
3
|
-
*
|
|
4
|
-
* Left-side companion to the InlinePreviewGutter. Renders a hierarchical
|
|
5
|
-
* tree of the document's headings (h1 → h2 → h3 …) so the structure is
|
|
6
|
-
* graspable at a glance and the user can jump to any section. Works in
|
|
7
|
-
* BOTH the WYSIWYG and Markdown editor views — view-specific positioning
|
|
8
|
-
* lives in `useHeadingLayout`.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
type CSSProperties,
|
|
13
|
-
type DragEvent as ReactDragEvent,
|
|
14
|
-
useCallback,
|
|
15
|
-
useEffect,
|
|
16
|
-
useMemo,
|
|
17
|
-
useRef,
|
|
18
|
-
useState,
|
|
19
|
-
} from 'react';
|
|
20
|
-
import type { Block } from '@bendyline/squisq/schemas';
|
|
21
|
-
import { flattenBlocks, hasTemplate } from '@bendyline/squisq/doc';
|
|
22
|
-
import { extractPlainText } from '@bendyline/squisq/markdown';
|
|
23
|
-
import { useEditorContext } from './EditorContext';
|
|
24
|
-
import { templateLabel } from './TemplatePicker';
|
|
25
|
-
import { useHeadingLayout } from './useHeadingLayout';
|
|
26
|
-
import { usePreviewSettingsOptional } from './PreviewControls';
|
|
27
|
-
import { moveHeadingSectionInSource, type OutlineDropPlacement } from './outlineSource';
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Responsive default width for the outline pane, used when no fixed `width`
|
|
31
|
-
* (or `--squisq-outline-width`) is supplied: never narrower than 260px, grows
|
|
32
|
-
* with the viewport so it stretches out to fill horizontal space when there's
|
|
33
|
-
* room, and caps at 460px so it never dominates the editor. A viewport unit
|
|
34
|
-
* (rather than
|
|
35
|
-
* a container unit) keeps the pane and the toolbar's view-tabs — which read the
|
|
36
|
-
* same value — resolving to an identical width, so their right edges stay
|
|
37
|
-
* aligned.
|
|
38
|
-
*/
|
|
39
|
-
export const OUTLINE_RESPONSIVE_WIDTH = 'clamp(260px, 30vw, 460px)';
|
|
40
|
-
|
|
41
|
-
export interface OutlinePanelProps {
|
|
42
|
-
/**
|
|
43
|
-
* Fixed width of the pane in pixels. When omitted, the pane sizes
|
|
44
|
-
* responsively from `--squisq-outline-width` (falling back to
|
|
45
|
-
* {@link OUTLINE_RESPONSIVE_WIDTH}) so it stretches on wider screens.
|
|
46
|
-
*/
|
|
47
|
-
width?: number;
|
|
48
|
-
/** Optional CSS class for the outer container. */
|
|
49
|
-
className?: string;
|
|
50
|
-
/** Disable heading-level changes and section reordering. */
|
|
51
|
-
readOnly?: boolean;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
interface OutlineSectionRef {
|
|
55
|
-
blockId: string;
|
|
56
|
-
headingLine: number;
|
|
57
|
-
depth: number;
|
|
58
|
-
parentId: string | null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface ActiveOutlineDrag extends OutlineSectionRef {
|
|
62
|
-
sourceAtStart: string;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface OutlineDropTarget {
|
|
66
|
-
blockId: string;
|
|
67
|
-
placement: OutlineDropPlacement;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const OUTLINE_DRAG_MIME = 'application/x-squisq-outline-section';
|
|
71
|
-
|
|
72
|
-
export function OutlinePanel({ width, className, readOnly = false }: OutlinePanelProps) {
|
|
73
|
-
const {
|
|
74
|
-
doc,
|
|
75
|
-
markdownSource,
|
|
76
|
-
setMarkdownSource,
|
|
77
|
-
isParsing,
|
|
78
|
-
layoutMode,
|
|
79
|
-
goToBlockByLine,
|
|
80
|
-
activeBlockStartLine,
|
|
81
|
-
} = useEditorContext();
|
|
82
|
-
const paneRef = useRef<HTMLElement | null>(null);
|
|
83
|
-
const { scrollToBlock } = useHeadingLayout(paneRef);
|
|
84
|
-
const cursorActiveId = useActiveOutlineBlockId();
|
|
85
|
-
const activeDragRef = useRef<ActiveOutlineDrag | null>(null);
|
|
86
|
-
const [draggedBlockId, setDraggedBlockId] = useState<string | null>(null);
|
|
87
|
-
const [dropTarget, setDropTarget] = useState<OutlineDropTarget | null>(null);
|
|
88
|
-
|
|
89
|
-
// In block-at-a-time mode there's no live cursor across the whole document
|
|
90
|
-
// (only the active block is mounted), so the highlight follows the card:
|
|
91
|
-
// match the block whose heading begins on the active slice's source line.
|
|
92
|
-
const blockModeActiveId = useMemo(() => {
|
|
93
|
-
if (layoutMode !== 'block' || activeBlockStartLine == null || !doc) return null;
|
|
94
|
-
const match = flattenBlocks(doc.blocks).find(
|
|
95
|
-
(b) => b.sourceHeading?.position?.start.line === activeBlockStartLine,
|
|
96
|
-
);
|
|
97
|
-
return match?.id ?? null;
|
|
98
|
-
}, [layoutMode, activeBlockStartLine, doc]);
|
|
99
|
-
const activeBlockId = layoutMode === 'block' ? blockModeActiveId : cursorActiveId;
|
|
100
|
-
|
|
101
|
-
// Clicking a row jumps the card to that block in block mode, or scrolls the
|
|
102
|
-
// editor to it in document mode.
|
|
103
|
-
const handleSelect = useCallback(
|
|
104
|
-
(block: Block) => {
|
|
105
|
-
if (layoutMode === 'block') {
|
|
106
|
-
const line = block.sourceHeading?.position?.start.line;
|
|
107
|
-
if (typeof line === 'number') {
|
|
108
|
-
goToBlockByLine(line);
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
scrollToBlock(block);
|
|
113
|
-
},
|
|
114
|
-
[layoutMode, goToBlockByLine, scrollToBlock],
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
// Promote / demote the row's heading by rewriting just the `#` prefix
|
|
118
|
-
// on the heading line. Falls through when the new depth would leave the
|
|
119
|
-
// legal H1–H6 range, so the buttons disable themselves at the edges.
|
|
120
|
-
// Both editor surfaces resync from `markdownSource` automatically.
|
|
121
|
-
const changeHeadingLevel = useCallback(
|
|
122
|
-
(block: Block, delta: number) => {
|
|
123
|
-
if (readOnly || isParsing) return;
|
|
124
|
-
const line = block.sourceHeading?.position?.start.line;
|
|
125
|
-
if (typeof line !== 'number') return;
|
|
126
|
-
const next = bumpHeadingLevelInSource(markdownSource, line, delta);
|
|
127
|
-
if (next != null) setMarkdownSource(next);
|
|
128
|
-
},
|
|
129
|
-
[isParsing, markdownSource, readOnly, setMarkdownSource],
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
const clearDragState = useCallback(() => {
|
|
133
|
-
activeDragRef.current = null;
|
|
134
|
-
setDraggedBlockId(null);
|
|
135
|
-
setDropTarget(null);
|
|
136
|
-
}, []);
|
|
137
|
-
|
|
138
|
-
const handleDragStart = useCallback(
|
|
139
|
-
(event: ReactDragEvent<HTMLElement>, section: OutlineSectionRef) => {
|
|
140
|
-
if (readOnly || isParsing) {
|
|
141
|
-
event.preventDefault();
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
activeDragRef.current = { ...section, sourceAtStart: markdownSource };
|
|
146
|
-
setDraggedBlockId(section.blockId);
|
|
147
|
-
setDropTarget(null);
|
|
148
|
-
event.dataTransfer.effectAllowed = 'move';
|
|
149
|
-
// Firefox requires a text payload before it will initiate a native drag.
|
|
150
|
-
// The custom type makes the payload identifiable to other Squisq panes;
|
|
151
|
-
// the in-memory ref remains authoritative for this mounted panel.
|
|
152
|
-
event.dataTransfer.setData(OUTLINE_DRAG_MIME, String(section.headingLine));
|
|
153
|
-
event.dataTransfer.setData('text/plain', String(section.headingLine));
|
|
154
|
-
},
|
|
155
|
-
[isParsing, markdownSource, readOnly],
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
const handleDragOver = useCallback(
|
|
159
|
-
(event: ReactDragEvent<HTMLElement>, section: OutlineSectionRef) => {
|
|
160
|
-
const dragged = activeDragRef.current;
|
|
161
|
-
if (!dragged) return;
|
|
162
|
-
|
|
163
|
-
// Prevent the editor shell's file-drop handler from changing this to a
|
|
164
|
-
// copy operation while an outline section is being moved.
|
|
165
|
-
event.preventDefault();
|
|
166
|
-
event.stopPropagation();
|
|
167
|
-
|
|
168
|
-
if (!canDropOnSection(dragged, section) || readOnly || isParsing) {
|
|
169
|
-
event.dataTransfer.dropEffect = 'none';
|
|
170
|
-
setDropTarget(null);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const placement = placementForPointer(event);
|
|
175
|
-
event.dataTransfer.dropEffect = 'move';
|
|
176
|
-
setDropTarget((current) =>
|
|
177
|
-
current?.blockId === section.blockId && current.placement === placement
|
|
178
|
-
? current
|
|
179
|
-
: { blockId: section.blockId, placement },
|
|
180
|
-
);
|
|
181
|
-
},
|
|
182
|
-
[isParsing, readOnly],
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
const handleDrop = useCallback(
|
|
186
|
-
(event: ReactDragEvent<HTMLElement>, section: OutlineSectionRef) => {
|
|
187
|
-
const dragged = activeDragRef.current;
|
|
188
|
-
if (!dragged) return;
|
|
189
|
-
|
|
190
|
-
event.preventDefault();
|
|
191
|
-
event.stopPropagation();
|
|
192
|
-
const placement = placementForPointer(event);
|
|
193
|
-
const canMove =
|
|
194
|
-
!readOnly &&
|
|
195
|
-
!isParsing &&
|
|
196
|
-
dragged.sourceAtStart === markdownSource &&
|
|
197
|
-
canDropOnSection(dragged, section);
|
|
198
|
-
const next = canMove
|
|
199
|
-
? moveHeadingSectionInSource(
|
|
200
|
-
markdownSource,
|
|
201
|
-
dragged.headingLine,
|
|
202
|
-
section.headingLine,
|
|
203
|
-
placement,
|
|
204
|
-
)
|
|
205
|
-
: null;
|
|
206
|
-
|
|
207
|
-
clearDragState();
|
|
208
|
-
if (next != null) setMarkdownSource(next);
|
|
209
|
-
},
|
|
210
|
-
[clearDragState, isParsing, markdownSource, readOnly, setMarkdownSource],
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
// Inherit the active document theme's primary color so the current-row
|
|
214
|
-
// highlight and template-name chips match the rest of the editor's
|
|
215
|
-
// accent palette (e.g. warm-earth's terracotta) instead of the
|
|
216
|
-
// hard-coded purple fallback. Falls through to the CSS defaults when
|
|
217
|
-
// no PreviewSettingsProvider is mounted.
|
|
218
|
-
const previewSettings = usePreviewSettingsOptional();
|
|
219
|
-
const accentColor = previewSettings?.activeTheme?.colors?.primary;
|
|
220
|
-
|
|
221
|
-
const isEmpty = !doc || doc.blocks.length === 0 || !hasAnyHeading(doc.blocks);
|
|
222
|
-
// Fixed px when a width is supplied; otherwise size from the shared
|
|
223
|
-
// `--squisq-outline-width` variable (the shell sets it, and the toolbar's
|
|
224
|
-
// view-tabs read the same value so their right edges stay aligned). The
|
|
225
|
-
// clamp fallback lets a standalone OutlinePanel stretch on wide screens too.
|
|
226
|
-
const basis =
|
|
227
|
-
width != null ? `${width}px` : `var(--squisq-outline-width, ${OUTLINE_RESPONSIVE_WIDTH})`;
|
|
228
|
-
const paneStyle: CSSProperties = {
|
|
229
|
-
width: basis,
|
|
230
|
-
flex: `0 0 ${basis}`,
|
|
231
|
-
overflow: 'auto',
|
|
232
|
-
...(accentColor
|
|
233
|
-
? ({ ['--squisq-outline-accent' as string]: accentColor } as CSSProperties)
|
|
234
|
-
: {}),
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
return (
|
|
238
|
-
<aside
|
|
239
|
-
ref={paneRef}
|
|
240
|
-
className={`squisq-outline${className ? ` ${className}` : ''}`}
|
|
241
|
-
style={paneStyle}
|
|
242
|
-
data-testid="outline-panel"
|
|
243
|
-
aria-label="Document outline"
|
|
244
|
-
>
|
|
245
|
-
{isEmpty ? (
|
|
246
|
-
<div className="squisq-outline-empty">
|
|
247
|
-
<p>Add a heading to populate the outline.</p>
|
|
248
|
-
</div>
|
|
249
|
-
) : (
|
|
250
|
-
<ul className="squisq-outline-tree" role="tree">
|
|
251
|
-
{doc!.blocks.map((b) => (
|
|
252
|
-
<OutlineNode
|
|
253
|
-
key={b.id}
|
|
254
|
-
block={b}
|
|
255
|
-
parentId={null}
|
|
256
|
-
activeBlockId={activeBlockId}
|
|
257
|
-
draggedBlockId={draggedBlockId}
|
|
258
|
-
dropTarget={dropTarget}
|
|
259
|
-
mutationsDisabled={readOnly || isParsing}
|
|
260
|
-
onSelect={handleSelect}
|
|
261
|
-
onChangeLevel={changeHeadingLevel}
|
|
262
|
-
onDragStart={handleDragStart}
|
|
263
|
-
onDragOver={handleDragOver}
|
|
264
|
-
onDrop={handleDrop}
|
|
265
|
-
onDragEnd={clearDragState}
|
|
266
|
-
/>
|
|
267
|
-
))}
|
|
268
|
-
</ul>
|
|
269
|
-
)}
|
|
270
|
-
</aside>
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// ── Subcomponents ──────────────────────────────────────────────────
|
|
275
|
-
|
|
276
|
-
function OutlineNode({
|
|
277
|
-
block,
|
|
278
|
-
parentId,
|
|
279
|
-
activeBlockId,
|
|
280
|
-
draggedBlockId,
|
|
281
|
-
dropTarget,
|
|
282
|
-
mutationsDisabled,
|
|
283
|
-
onSelect,
|
|
284
|
-
onChangeLevel,
|
|
285
|
-
onDragStart,
|
|
286
|
-
onDragOver,
|
|
287
|
-
onDrop,
|
|
288
|
-
onDragEnd,
|
|
289
|
-
}: {
|
|
290
|
-
block: Block;
|
|
291
|
-
parentId: string | null;
|
|
292
|
-
activeBlockId: string | null;
|
|
293
|
-
draggedBlockId: string | null;
|
|
294
|
-
dropTarget: OutlineDropTarget | null;
|
|
295
|
-
mutationsDisabled: boolean;
|
|
296
|
-
onSelect: (b: Block) => void;
|
|
297
|
-
onChangeLevel: (block: Block, delta: number) => void;
|
|
298
|
-
onDragStart: (event: ReactDragEvent<HTMLElement>, section: OutlineSectionRef) => void;
|
|
299
|
-
onDragOver: (event: ReactDragEvent<HTMLElement>, section: OutlineSectionRef) => void;
|
|
300
|
-
onDrop: (event: ReactDragEvent<HTMLElement>, section: OutlineSectionRef) => void;
|
|
301
|
-
onDragEnd: () => void;
|
|
302
|
-
}) {
|
|
303
|
-
const heading = block.sourceHeading;
|
|
304
|
-
const depth = heading?.depth ?? 1;
|
|
305
|
-
const headingLine = heading?.position?.start.line;
|
|
306
|
-
const text = heading ? extractPlainText(heading).trim() : '';
|
|
307
|
-
const annotation = heading?.templateAnnotation;
|
|
308
|
-
const tplName = annotation?.template;
|
|
309
|
-
const showChip = tplName && hasTemplate(tplName);
|
|
310
|
-
const isActive = block.id === activeBlockId;
|
|
311
|
-
const canPromote = !!heading && depth > 1;
|
|
312
|
-
const canDemote = !!heading && depth < 6;
|
|
313
|
-
const section =
|
|
314
|
-
heading && typeof headingLine === 'number'
|
|
315
|
-
? { blockId: block.id, headingLine, depth, parentId }
|
|
316
|
-
: null;
|
|
317
|
-
const canDrag = section != null && !mutationsDisabled;
|
|
318
|
-
const isDragging = block.id === draggedBlockId;
|
|
319
|
-
const dropPlacement = dropTarget?.blockId === block.id ? dropTarget.placement : null;
|
|
320
|
-
const itemClasses = [
|
|
321
|
-
'squisq-outline-item',
|
|
322
|
-
isDragging ? 'squisq-outline-item--dragging' : '',
|
|
323
|
-
dropPlacement ? `squisq-outline-item--drop-${dropPlacement}` : '',
|
|
324
|
-
]
|
|
325
|
-
.filter(Boolean)
|
|
326
|
-
.join(' ');
|
|
327
|
-
|
|
328
|
-
return (
|
|
329
|
-
<li className={itemClasses} role="treeitem" aria-current={isActive || undefined}>
|
|
330
|
-
<div
|
|
331
|
-
className="squisq-outline-row-wrap"
|
|
332
|
-
onDragOver={section ? (event) => onDragOver(event, section) : undefined}
|
|
333
|
-
onDrop={section ? (event) => onDrop(event, section) : undefined}
|
|
334
|
-
>
|
|
335
|
-
<button
|
|
336
|
-
type="button"
|
|
337
|
-
className={`squisq-outline-row squisq-outline-row--depth-${depth}${
|
|
338
|
-
isActive ? ' squisq-outline-row--current' : ''
|
|
339
|
-
}`}
|
|
340
|
-
onClick={() => onSelect(block)}
|
|
341
|
-
draggable={canDrag}
|
|
342
|
-
aria-grabbed={isDragging || undefined}
|
|
343
|
-
onDragStart={section ? (event) => onDragStart(event, section) : undefined}
|
|
344
|
-
onDragEnd={onDragEnd}
|
|
345
|
-
title={text || '(empty heading)'}
|
|
346
|
-
>
|
|
347
|
-
{canDrag && (
|
|
348
|
-
<span className="squisq-outline-drag-handle" aria-hidden="true">
|
|
349
|
-
<svg width="8" height="12" viewBox="0 0 8 12">
|
|
350
|
-
<circle cx="2" cy="2" r="1" fill="currentColor" />
|
|
351
|
-
<circle cx="6" cy="2" r="1" fill="currentColor" />
|
|
352
|
-
<circle cx="2" cy="6" r="1" fill="currentColor" />
|
|
353
|
-
<circle cx="6" cy="6" r="1" fill="currentColor" />
|
|
354
|
-
<circle cx="2" cy="10" r="1" fill="currentColor" />
|
|
355
|
-
<circle cx="6" cy="10" r="1" fill="currentColor" />
|
|
356
|
-
</svg>
|
|
357
|
-
</span>
|
|
358
|
-
)}
|
|
359
|
-
<span className="squisq-outline-row-text">{text || '(untitled)'}</span>
|
|
360
|
-
{showChip && (
|
|
361
|
-
<span className="squisq-outline-template-chip">{templateLabel(tplName!)}</span>
|
|
362
|
-
)}
|
|
363
|
-
</button>
|
|
364
|
-
{heading && (
|
|
365
|
-
<span className="squisq-outline-row-actions">
|
|
366
|
-
<button
|
|
367
|
-
type="button"
|
|
368
|
-
className="squisq-outline-row-arrow"
|
|
369
|
-
aria-label={`Promote heading (currently H${depth})`}
|
|
370
|
-
title="Promote heading"
|
|
371
|
-
disabled={mutationsDisabled || !canPromote}
|
|
372
|
-
onClick={() => onChangeLevel(block, -1)}
|
|
373
|
-
>
|
|
374
|
-
<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true">
|
|
375
|
-
<path
|
|
376
|
-
d="M6.5 2.5 L3 5 L6.5 7.5"
|
|
377
|
-
stroke="currentColor"
|
|
378
|
-
strokeWidth="1.5"
|
|
379
|
-
strokeLinecap="round"
|
|
380
|
-
strokeLinejoin="round"
|
|
381
|
-
fill="none"
|
|
382
|
-
/>
|
|
383
|
-
</svg>
|
|
384
|
-
</button>
|
|
385
|
-
<button
|
|
386
|
-
type="button"
|
|
387
|
-
className="squisq-outline-row-arrow"
|
|
388
|
-
aria-label={`Demote heading (currently H${depth})`}
|
|
389
|
-
title="Demote heading"
|
|
390
|
-
disabled={mutationsDisabled || !canDemote}
|
|
391
|
-
onClick={() => onChangeLevel(block, +1)}
|
|
392
|
-
>
|
|
393
|
-
<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true">
|
|
394
|
-
<path
|
|
395
|
-
d="M3.5 2.5 L7 5 L3.5 7.5"
|
|
396
|
-
stroke="currentColor"
|
|
397
|
-
strokeWidth="1.5"
|
|
398
|
-
strokeLinecap="round"
|
|
399
|
-
strokeLinejoin="round"
|
|
400
|
-
fill="none"
|
|
401
|
-
/>
|
|
402
|
-
</svg>
|
|
403
|
-
</button>
|
|
404
|
-
</span>
|
|
405
|
-
)}
|
|
406
|
-
</div>
|
|
407
|
-
{block.children && block.children.length > 0 && (
|
|
408
|
-
<ul className="squisq-outline-tree">
|
|
409
|
-
{block.children.map((child) => (
|
|
410
|
-
<OutlineNode
|
|
411
|
-
key={child.id}
|
|
412
|
-
block={child}
|
|
413
|
-
parentId={block.id}
|
|
414
|
-
activeBlockId={activeBlockId}
|
|
415
|
-
draggedBlockId={draggedBlockId}
|
|
416
|
-
dropTarget={dropTarget}
|
|
417
|
-
mutationsDisabled={mutationsDisabled}
|
|
418
|
-
onSelect={onSelect}
|
|
419
|
-
onChangeLevel={onChangeLevel}
|
|
420
|
-
onDragStart={onDragStart}
|
|
421
|
-
onDragOver={onDragOver}
|
|
422
|
-
onDrop={onDrop}
|
|
423
|
-
onDragEnd={onDragEnd}
|
|
424
|
-
/>
|
|
425
|
-
))}
|
|
426
|
-
</ul>
|
|
427
|
-
)}
|
|
428
|
-
</li>
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// ── Active-block tracking ──────────────────────────────────────────
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Tracks which heading the user's cursor is currently inside (or most
|
|
436
|
-
* recently passed). In WYSIWYG mode this watches Tiptap's selection;
|
|
437
|
-
* in Raw mode it watches Monaco's cursor line. The Preview surface has
|
|
438
|
-
* no cursor concept and reports `null`.
|
|
439
|
-
*
|
|
440
|
-
* The lookup mirrors the heading-pairing logic in `useHeadingLayout`:
|
|
441
|
-
* the Nth heading in document order maps to `flattenBlocks(doc.blocks)[N]`.
|
|
442
|
-
*/
|
|
443
|
-
function useActiveOutlineBlockId(): string | null {
|
|
444
|
-
const { doc, activeView, tiptapEditor, monacoEditor } = useEditorContext();
|
|
445
|
-
const flatBlocks = useMemo(() => (doc ? flattenBlocks(doc.blocks) : []), [doc]);
|
|
446
|
-
const [activeId, setActiveId] = useState<string | null>(null);
|
|
447
|
-
|
|
448
|
-
// Reset whenever the active surface changes — a stale highlight from
|
|
449
|
-
// the previous view would mislead the user before the new surface's
|
|
450
|
-
// cursor handler runs.
|
|
451
|
-
useEffect(() => {
|
|
452
|
-
setActiveId(null);
|
|
453
|
-
}, [activeView]);
|
|
454
|
-
|
|
455
|
-
useEffect(() => {
|
|
456
|
-
if (activeView !== 'wysiwyg' || !tiptapEditor) return;
|
|
457
|
-
|
|
458
|
-
const update = () => {
|
|
459
|
-
const { from } = tiptapEditor.state.selection;
|
|
460
|
-
let lastIndex = -1;
|
|
461
|
-
let seen = -1;
|
|
462
|
-
tiptapEditor.state.doc.forEach((node, offset) => {
|
|
463
|
-
if (node.type.name !== 'heading') return;
|
|
464
|
-
seen += 1;
|
|
465
|
-
if (offset <= from) lastIndex = seen;
|
|
466
|
-
});
|
|
467
|
-
const block = lastIndex >= 0 ? flatBlocks[lastIndex] : null;
|
|
468
|
-
setActiveId(block?.id ?? null);
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
update();
|
|
472
|
-
tiptapEditor.on('selectionUpdate', update);
|
|
473
|
-
tiptapEditor.on('update', update);
|
|
474
|
-
return () => {
|
|
475
|
-
tiptapEditor.off('selectionUpdate', update);
|
|
476
|
-
tiptapEditor.off('update', update);
|
|
477
|
-
};
|
|
478
|
-
}, [activeView, tiptapEditor, flatBlocks]);
|
|
479
|
-
|
|
480
|
-
useEffect(() => {
|
|
481
|
-
if (activeView !== 'raw' || !monacoEditor) return;
|
|
482
|
-
|
|
483
|
-
const update = () => {
|
|
484
|
-
const line = monacoEditor.getPosition()?.lineNumber;
|
|
485
|
-
if (typeof line !== 'number') {
|
|
486
|
-
setActiveId(null);
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
let lastIndex = -1;
|
|
490
|
-
flatBlocks.forEach((b, i) => {
|
|
491
|
-
const headingLine = b.sourceHeading?.position?.start.line;
|
|
492
|
-
if (typeof headingLine === 'number' && headingLine <= line) lastIndex = i;
|
|
493
|
-
});
|
|
494
|
-
const block = lastIndex >= 0 ? flatBlocks[lastIndex] : null;
|
|
495
|
-
setActiveId(block?.id ?? null);
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
update();
|
|
499
|
-
const sub = monacoEditor.onDidChangeCursorPosition(update);
|
|
500
|
-
return () => sub.dispose();
|
|
501
|
-
}, [activeView, monacoEditor, flatBlocks]);
|
|
502
|
-
|
|
503
|
-
return activeId;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// ── Helpers ────────────────────────────────────────────────────────
|
|
507
|
-
|
|
508
|
-
function canDropOnSection(dragged: OutlineSectionRef, target: OutlineSectionRef): boolean {
|
|
509
|
-
return (
|
|
510
|
-
dragged.blockId !== target.blockId &&
|
|
511
|
-
dragged.depth === target.depth &&
|
|
512
|
-
dragged.parentId === target.parentId
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
function placementForPointer(event: ReactDragEvent<HTMLElement>): OutlineDropPlacement {
|
|
517
|
-
const bounds = event.currentTarget.getBoundingClientRect();
|
|
518
|
-
return event.clientY < bounds.top + bounds.height / 2 ? 'before' : 'after';
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
function hasAnyHeading(blocks: Block[]): boolean {
|
|
522
|
-
for (const b of blocks) {
|
|
523
|
-
if (b.sourceHeading) return true;
|
|
524
|
-
if (b.children && hasAnyHeading(b.children)) return true;
|
|
525
|
-
}
|
|
526
|
-
return false;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/**
|
|
530
|
-
* Rewrites just the leading `#` run on the given 1-based line, shifting
|
|
531
|
-
* the heading depth by `delta`. Returns `null` when the line isn't an
|
|
532
|
-
* ATX heading or the resulting depth would fall outside 1–6. Leaves the
|
|
533
|
-
* rest of the line (including any `{[template]}` annotation) untouched.
|
|
534
|
-
*/
|
|
535
|
-
function bumpHeadingLevelInSource(source: string, line: number, delta: number): string | null {
|
|
536
|
-
const lines = source.split('\n');
|
|
537
|
-
const idx = line - 1;
|
|
538
|
-
if (idx < 0 || idx >= lines.length) return null;
|
|
539
|
-
const original = lines[idx];
|
|
540
|
-
const match = original.match(/^(#{1,6})(\s|$)/);
|
|
541
|
-
if (!match) return null;
|
|
542
|
-
const currentDepth = match[1].length;
|
|
543
|
-
const newDepth = currentDepth + delta;
|
|
544
|
-
if (newDepth < 1 || newDepth > 6) return null;
|
|
545
|
-
lines[idx] = '#'.repeat(newDepth) + original.slice(currentDepth);
|
|
546
|
-
return lines.join('\n');
|
|
547
|
-
}
|