@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,441 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SceneBlockWidget — Squisq-Scene-backed canvas mounted under a
|
|
3
|
-
* heading whose `dataTemplate` is `layout` or `drawing`.
|
|
4
|
-
*
|
|
5
|
-
* Owns the maximize toggle and picks the right adapter for the mode.
|
|
6
|
-
* Resolves the heading's position dynamically each render via
|
|
7
|
-
* `headingKey`, so the widget survives attribute-only doc changes
|
|
8
|
-
* without going stale when content above shifts.
|
|
9
|
-
*
|
|
10
|
-
* In `drawing` mode it also hosts the shape palette (gallery of shape
|
|
11
|
-
* kinds) and the properties panel for the current selection — surfaced
|
|
12
|
-
* from the drawing adapter + the Scene's `onSelectionChange`.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
16
|
-
import type { ReactNode } from 'react';
|
|
17
|
-
import type { Editor } from '@tiptap/react';
|
|
18
|
-
import type { Layer } from '@bendyline/squisq/schemas';
|
|
19
|
-
import { Scene } from './Scene';
|
|
20
|
-
import { useLayoutAdapter } from './adapters/LayoutAdapter';
|
|
21
|
-
import { useDrawingAdapter, type ConnectorStyleInput } from './adapters/DrawingAdapter';
|
|
22
|
-
import type { SceneCommand, SceneEdge } from './commands/SceneCommand';
|
|
23
|
-
import { findSceneHeadingPos } from './SceneBlockExtension';
|
|
24
|
-
import { shapeIdFromLayerId } from './layers/shapeLayers';
|
|
25
|
-
import { ShapePalette } from './ShapePalette';
|
|
26
|
-
import { ScenePropsBar } from './ScenePropsBar';
|
|
27
|
-
import { SceneBlockToolbar, type SceneBlockAction, type SceneAlignment } from './SceneBlockToolbar';
|
|
28
|
-
import { SceneSideToolbar } from './SceneSideToolbar';
|
|
29
|
-
import type { SceneTextEditConfig } from './text/sceneTextConfig';
|
|
30
|
-
import { markdownToTiptap } from '../tiptapBridge';
|
|
31
|
-
import { Icon } from '../Icon';
|
|
32
|
-
import { DiagramMaximizedOverlay } from '../diagram/DiagramMaximizedOverlay';
|
|
33
|
-
import type { SceneTextChannel } from './text/sceneTextChannel';
|
|
34
|
-
|
|
35
|
-
export type SceneBlockMode = 'layout' | 'drawing';
|
|
36
|
-
|
|
37
|
-
interface SceneBlockWidgetProps {
|
|
38
|
-
editor: Editor;
|
|
39
|
-
headingKey: string;
|
|
40
|
-
fallbackParentPos: number;
|
|
41
|
-
mode: SceneBlockMode;
|
|
42
|
-
/** Host element for portal targeting (used by maximize overlay). */
|
|
43
|
-
host?: HTMLElement | null;
|
|
44
|
-
textChannel?: SceneTextChannel;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Default viewport for layout/drawing surfaces. Matches Squisq's 16:9
|
|
48
|
-
// preview so layouts authored here render correctly when previewed.
|
|
49
|
-
const SCENE_VIEWPORT = { width: 1920, height: 1080 };
|
|
50
|
-
|
|
51
|
-
// Connector style vocabularies for the inline properties (drawing edges).
|
|
52
|
-
const MARKERS = ['none', 'arrow', 'open', 'diamond', 'circle', 'square'];
|
|
53
|
-
const ROUTINGS = ['straight', 'orthogonal', 'curved'];
|
|
54
|
-
const LINE_STYLES = ['solid', 'dashed', 'dotted'];
|
|
55
|
-
const lineStyleOf = (dasharray: string | undefined): string =>
|
|
56
|
-
dasharray === '8 6' ? 'dashed' : dasharray === '2 6' ? 'dotted' : 'solid';
|
|
57
|
-
|
|
58
|
-
export function SceneBlockWidget({
|
|
59
|
-
editor,
|
|
60
|
-
headingKey,
|
|
61
|
-
fallbackParentPos,
|
|
62
|
-
mode,
|
|
63
|
-
host,
|
|
64
|
-
textChannel,
|
|
65
|
-
}: SceneBlockWidgetProps) {
|
|
66
|
-
const [parentPos, setParentPos] = useState<number>(
|
|
67
|
-
() => findSceneHeadingPos(editor, headingKey, mode) ?? fallbackParentPos,
|
|
68
|
-
);
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
const onUpdate = () => {
|
|
71
|
-
const next = findSceneHeadingPos(editor, headingKey, mode);
|
|
72
|
-
if (next != null && next !== parentPos) setParentPos(next);
|
|
73
|
-
};
|
|
74
|
-
editor.on('transaction', onUpdate);
|
|
75
|
-
return () => {
|
|
76
|
-
editor.off('transaction', onUpdate);
|
|
77
|
-
};
|
|
78
|
-
}, [editor, headingKey, mode, parentPos]);
|
|
79
|
-
|
|
80
|
-
const layout = useLayoutAdapter(editor, parentPos);
|
|
81
|
-
const drawing = useDrawingAdapter(editor, parentPos);
|
|
82
|
-
const isDrawing = mode === 'drawing';
|
|
83
|
-
const adapter = isDrawing ? drawing : layout;
|
|
84
|
-
|
|
85
|
-
// Inline text editing config. Refs keep `getHtml`/`commit` reading the
|
|
86
|
-
// live layers/dispatch while the config object stays stable (so the
|
|
87
|
-
// open editor isn't re-seeded mid-edit). Layout stores rich HTML; drawing
|
|
88
|
-
// stores inline markdown in the shape's heading text.
|
|
89
|
-
const layersRef = useRef(adapter.layers);
|
|
90
|
-
layersRef.current = adapter.layers;
|
|
91
|
-
const dispatchRef = useRef(adapter.dispatch);
|
|
92
|
-
dispatchRef.current = adapter.dispatch;
|
|
93
|
-
const textConfig = useMemo<SceneTextEditConfig>(
|
|
94
|
-
() => ({
|
|
95
|
-
channel: textChannel,
|
|
96
|
-
resolveEditableId: (id) => {
|
|
97
|
-
const l = layersRef.current.find((x) => x.id === id);
|
|
98
|
-
return l && l.type === 'text' ? id : null;
|
|
99
|
-
},
|
|
100
|
-
getHtml: (id) => {
|
|
101
|
-
const l = layersRef.current.find((x) => x.id === id);
|
|
102
|
-
if (!l || l.type !== 'text') return '';
|
|
103
|
-
if (!isDrawing && l.content.html?.trim()) return l.content.html;
|
|
104
|
-
return markdownToTiptap(l.content.text ?? '');
|
|
105
|
-
},
|
|
106
|
-
commit: (id, { html, text }) => {
|
|
107
|
-
if (isDrawing) {
|
|
108
|
-
// Drawing labels persist as plain heading text for now (rich
|
|
109
|
-
// marks on shape labels are a follow-up — the rendering
|
|
110
|
-
// foundation is in place via `content.html`). Store plain text so
|
|
111
|
-
// nothing leaks literal markdown into the label.
|
|
112
|
-
dispatchRef.current({ kind: 'renameLayer', id, label: text });
|
|
113
|
-
} else {
|
|
114
|
-
dispatchRef.current({ kind: 'setLayerText', id, text, html });
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
// Layout textboxes use `block` (marks + lists, no headings) because their
|
|
118
|
-
// content is stored as the child sub-block's markdown body.
|
|
119
|
-
level: isDrawing ? 'inline' : 'block',
|
|
120
|
-
}),
|
|
121
|
-
[isDrawing, textChannel],
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const [maximized, setMaximized] = useState(false);
|
|
125
|
-
const [activeToolId, setActiveToolId] = useState<string>('select');
|
|
126
|
-
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
127
|
-
const [selectedLayerId, setSelectedLayerId] = useState<string | null>(null);
|
|
128
|
-
|
|
129
|
-
const selectedShapeId = isDrawing && selectedLayerId ? shapeIdFromLayerId(selectedLayerId) : null;
|
|
130
|
-
|
|
131
|
-
const canvas = (
|
|
132
|
-
<Scene
|
|
133
|
-
viewport={SCENE_VIEWPORT}
|
|
134
|
-
layers={adapter.layers}
|
|
135
|
-
edges={adapter.edges}
|
|
136
|
-
tools={adapter.tools}
|
|
137
|
-
onCommand={adapter.dispatch}
|
|
138
|
-
onSelectionChange={(ids) => setSelectedLayerId(ids.values().next().value ?? null)}
|
|
139
|
-
activeToolId={activeToolId}
|
|
140
|
-
onActiveToolIdChange={setActiveToolId}
|
|
141
|
-
layerFollows={adapter.layerFollows}
|
|
142
|
-
renderExtras={adapter.renderExtras}
|
|
143
|
-
showMaximize
|
|
144
|
-
maximized={maximized}
|
|
145
|
-
onToggleMaximize={() => setMaximized((m) => !m)}
|
|
146
|
-
showToolbar={false}
|
|
147
|
-
textEditing={textConfig}
|
|
148
|
-
/>
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
// ── Shared toolbar (above the canvas) ──────────────────
|
|
152
|
-
// Drawing creates shapes via its mode tools (Shape/Pen/Text/Connect);
|
|
153
|
-
// layout has only Select, so it gets explicit Add buttons. Both share
|
|
154
|
-
// a Delete action keyed off the current selection.
|
|
155
|
-
const canDelete = isDrawing ? !!selectedLayerId || !!drawing.selectedEdgeId : !!selectedLayerId;
|
|
156
|
-
const deleteSelected = () => {
|
|
157
|
-
if (selectedLayerId) {
|
|
158
|
-
adapter.dispatch({ kind: 'removeLayer', id: selectedLayerId });
|
|
159
|
-
setSelectedLayerId(null);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (isDrawing && drawing.selectedEdge) {
|
|
163
|
-
adapter.dispatch({
|
|
164
|
-
kind: 'removeEdge',
|
|
165
|
-
source: drawing.selectedEdge.source,
|
|
166
|
-
target: drawing.selectedEdge.target,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
const freshLayerId = (prefix: string) => {
|
|
171
|
-
const used = new Set(adapter.layers.map((l) => l.id));
|
|
172
|
-
let i = 1;
|
|
173
|
-
while (used.has(`${prefix}-${i}`)) i++;
|
|
174
|
-
return `${prefix}-${i}`;
|
|
175
|
-
};
|
|
176
|
-
const addLayoutLayer = (layer: Layer) => adapter.dispatch({ kind: 'addLayer', layer });
|
|
177
|
-
|
|
178
|
-
const deleteAction: SceneBlockAction = {
|
|
179
|
-
id: 'delete',
|
|
180
|
-
label: 'Delete',
|
|
181
|
-
icon: <Icon icon="fa-solid fa-trash" />,
|
|
182
|
-
title: 'Delete selected',
|
|
183
|
-
danger: true,
|
|
184
|
-
disabled: !canDelete,
|
|
185
|
-
onClick: deleteSelected,
|
|
186
|
-
};
|
|
187
|
-
const actions: SceneBlockAction[] = isDrawing
|
|
188
|
-
? [deleteAction]
|
|
189
|
-
: [
|
|
190
|
-
{
|
|
191
|
-
id: 'add-text',
|
|
192
|
-
label: 'Text',
|
|
193
|
-
icon: <Icon icon="fa-solid fa-font" />,
|
|
194
|
-
title: 'Add text',
|
|
195
|
-
onClick: () =>
|
|
196
|
-
addLayoutLayer({
|
|
197
|
-
type: 'text',
|
|
198
|
-
id: freshLayerId('text'),
|
|
199
|
-
content: {
|
|
200
|
-
text: 'Text',
|
|
201
|
-
style: {
|
|
202
|
-
fontSize: 48,
|
|
203
|
-
color: '#1e293b',
|
|
204
|
-
textAlign: 'center',
|
|
205
|
-
verticalAlign: 'middle',
|
|
206
|
-
},
|
|
207
|
-
},
|
|
208
|
-
position: { x: 660, y: 440, width: 600, height: 200 },
|
|
209
|
-
}),
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
id: 'add-box',
|
|
213
|
-
label: 'Box',
|
|
214
|
-
icon: <Icon icon="fa-solid fa-square" />,
|
|
215
|
-
title: 'Add box',
|
|
216
|
-
onClick: () =>
|
|
217
|
-
addLayoutLayer({
|
|
218
|
-
type: 'shape',
|
|
219
|
-
id: freshLayerId('box'),
|
|
220
|
-
content: {
|
|
221
|
-
shape: 'rect',
|
|
222
|
-
fill: '#e0e7ff',
|
|
223
|
-
stroke: '#6366f1',
|
|
224
|
-
strokeWidth: 2,
|
|
225
|
-
borderRadius: 8,
|
|
226
|
-
},
|
|
227
|
-
position: { x: 760, y: 390, width: 400, height: 300 },
|
|
228
|
-
}),
|
|
229
|
-
},
|
|
230
|
-
deleteAction,
|
|
231
|
-
];
|
|
232
|
-
|
|
233
|
-
// Text-alignment controls — shown when a layout textbox is selected. They
|
|
234
|
-
// set the layer's whole-box `style.textAlign` / `style.verticalAlign`
|
|
235
|
-
// (the LayoutAdapter persists arbitrary `content.*` paths; drawing/diagram
|
|
236
|
-
// labels don't yet, so this is layout-only for now).
|
|
237
|
-
const selectedLayer = selectedLayerId
|
|
238
|
-
? adapter.layers.find((l) => l.id === selectedLayerId)
|
|
239
|
-
: undefined;
|
|
240
|
-
const alignment: SceneAlignment | undefined =
|
|
241
|
-
mode === 'layout' && selectedLayer?.type === 'text'
|
|
242
|
-
? {
|
|
243
|
-
textAlign: selectedLayer.content.style.textAlign ?? 'left',
|
|
244
|
-
verticalAlign: selectedLayer.content.style.verticalAlign ?? 'top',
|
|
245
|
-
onTextAlign: (v) =>
|
|
246
|
-
adapter.dispatch({
|
|
247
|
-
kind: 'setLayerAttr',
|
|
248
|
-
id: selectedLayer.id,
|
|
249
|
-
path: 'content.style.textAlign',
|
|
250
|
-
value: v,
|
|
251
|
-
}),
|
|
252
|
-
onVerticalAlign: (v) =>
|
|
253
|
-
adapter.dispatch({
|
|
254
|
-
kind: 'setLayerAttr',
|
|
255
|
-
id: selectedLayer.id,
|
|
256
|
-
path: 'content.style.verticalAlign',
|
|
257
|
-
value: v,
|
|
258
|
-
}),
|
|
259
|
-
}
|
|
260
|
-
: undefined;
|
|
261
|
-
|
|
262
|
-
// Per-selection style controls, rendered inline in the contextual toolbar
|
|
263
|
-
// (Fill/Stroke for shapes & boxes, Color for text, marker/line/routing for
|
|
264
|
-
// a drawing connector). Replaces the old floating properties panel.
|
|
265
|
-
const propsBar = buildPropsBar({
|
|
266
|
-
isDrawing,
|
|
267
|
-
selectedLayer,
|
|
268
|
-
selectedShapeId,
|
|
269
|
-
selectedEdge: isDrawing ? drawing.selectedEdge : null,
|
|
270
|
-
setShapeParam: drawing.setShapeParam,
|
|
271
|
-
setConnectorStyle: drawing.setConnectorStyle,
|
|
272
|
-
dispatch: adapter.dispatch,
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
const toolbar = (
|
|
276
|
-
<SceneBlockToolbar
|
|
277
|
-
tools={adapter.tools}
|
|
278
|
-
activeToolId={activeToolId}
|
|
279
|
-
// Clicking the Shape tool opens its palette (dropping down from the
|
|
280
|
-
// button); other tools just activate.
|
|
281
|
-
onSelectTool={(id) => {
|
|
282
|
-
setActiveToolId(id);
|
|
283
|
-
if (id === 'draw') setPaletteOpen(true);
|
|
284
|
-
}}
|
|
285
|
-
actions={actions}
|
|
286
|
-
alignment={alignment}
|
|
287
|
-
properties={propsBar}
|
|
288
|
-
toolPopover={
|
|
289
|
-
isDrawing && paletteOpen
|
|
290
|
-
? {
|
|
291
|
-
toolId: 'draw',
|
|
292
|
-
content: (
|
|
293
|
-
<ShapePalette
|
|
294
|
-
onPick={(kind) => {
|
|
295
|
-
drawing.setPendingKind(kind);
|
|
296
|
-
setActiveToolId('draw');
|
|
297
|
-
setPaletteOpen(false);
|
|
298
|
-
}}
|
|
299
|
-
onClose={() => setPaletteOpen(false)}
|
|
300
|
-
/>
|
|
301
|
-
),
|
|
302
|
-
}
|
|
303
|
-
: undefined
|
|
304
|
-
}
|
|
305
|
-
/>
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
const body = <div className="squisq-scene-stage">{canvas}</div>;
|
|
309
|
-
|
|
310
|
-
if (maximized) {
|
|
311
|
-
return (
|
|
312
|
-
<div className="squisq-scene-inline-placeholder">
|
|
313
|
-
<DiagramMaximizedOverlay host={host ?? null} onClose={() => setMaximized(false)}>
|
|
314
|
-
{/* Maximized has a full screen for a static right column — no collapse. */}
|
|
315
|
-
<div className="squisq-scene-block-max">
|
|
316
|
-
{body}
|
|
317
|
-
<div className="squisq-scene-side-toolbar">{toolbar}</div>
|
|
318
|
-
</div>
|
|
319
|
-
</DiagramMaximizedOverlay>
|
|
320
|
-
</div>
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return (
|
|
325
|
-
<div className="squisq-scene-shell">
|
|
326
|
-
{/* Before the canvas so the narrow-width fallback bar sits above it; the
|
|
327
|
-
wide-width gutter column is absolute and unaffected by DOM order. */}
|
|
328
|
-
<SceneSideToolbar>{toolbar}</SceneSideToolbar>
|
|
329
|
-
<div className="squisq-scene-inline">{body}</div>
|
|
330
|
-
</div>
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Build the inline per-selection style controls for the contextual toolbar.
|
|
336
|
-
* - A drawing connector → marker / line / routing dropdowns.
|
|
337
|
-
* - A text layer → a single Color swatch (drawing text color is the shape's
|
|
338
|
-
* `stroke`; layout text color is `content.style.color`).
|
|
339
|
-
* - A shape / box / path → Fill + Stroke swatches.
|
|
340
|
-
* Returns null when the selection has nothing styleable.
|
|
341
|
-
*/
|
|
342
|
-
function buildPropsBar(args: {
|
|
343
|
-
isDrawing: boolean;
|
|
344
|
-
selectedLayer: Layer | undefined;
|
|
345
|
-
selectedShapeId: string | null;
|
|
346
|
-
selectedEdge: SceneEdge | null;
|
|
347
|
-
setShapeParam: (id: string, key: string, value: string) => void;
|
|
348
|
-
setConnectorStyle: (id: string, style: ConnectorStyleInput) => void;
|
|
349
|
-
dispatch: (cmd: SceneCommand) => void;
|
|
350
|
-
}): ReactNode {
|
|
351
|
-
const {
|
|
352
|
-
isDrawing,
|
|
353
|
-
selectedLayer,
|
|
354
|
-
selectedShapeId,
|
|
355
|
-
selectedEdge,
|
|
356
|
-
setShapeParam,
|
|
357
|
-
setConnectorStyle,
|
|
358
|
-
dispatch,
|
|
359
|
-
} = args;
|
|
360
|
-
|
|
361
|
-
if (isDrawing && selectedEdge) {
|
|
362
|
-
const e = selectedEdge;
|
|
363
|
-
const set = (style: ConnectorStyleInput) => setConnectorStyle(e.id, style);
|
|
364
|
-
return (
|
|
365
|
-
<ScenePropsBar
|
|
366
|
-
selects={[
|
|
367
|
-
{
|
|
368
|
-
label: 'End',
|
|
369
|
-
value: e.endMarker ?? 'arrow',
|
|
370
|
-
options: MARKERS,
|
|
371
|
-
onChange: (v) => set({ endStyle: v }),
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
label: 'Start',
|
|
375
|
-
value: e.startMarker ?? 'none',
|
|
376
|
-
options: MARKERS,
|
|
377
|
-
onChange: (v) => set({ startStyle: v }),
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
label: 'Line',
|
|
381
|
-
value: lineStyleOf(e.dasharray),
|
|
382
|
-
options: LINE_STYLES,
|
|
383
|
-
onChange: (v) => set({ lineStyle: v }),
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
label: 'Routing',
|
|
387
|
-
value: e.routing ?? 'straight',
|
|
388
|
-
options: ROUTINGS,
|
|
389
|
-
onChange: (v) => set({ routing: v }),
|
|
390
|
-
},
|
|
391
|
-
]}
|
|
392
|
-
/>
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (!selectedLayer) return null;
|
|
397
|
-
|
|
398
|
-
// Drawing maps a shape's params via its heading id; layout writes layer
|
|
399
|
-
// attribute paths through the adapter's dispatch.
|
|
400
|
-
const setColor = (param: string, path: string) => (v: string) => {
|
|
401
|
-
if (isDrawing && selectedShapeId) setShapeParam(selectedShapeId, param, v);
|
|
402
|
-
else dispatch({ kind: 'setLayerAttr', id: selectedLayer.id, path, value: v });
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
if (selectedLayer.type === 'text') {
|
|
406
|
-
// Drawing stores a text shape's color in its `stroke` param.
|
|
407
|
-
return (
|
|
408
|
-
<ScenePropsBar
|
|
409
|
-
colors={[
|
|
410
|
-
{
|
|
411
|
-
label: 'Color',
|
|
412
|
-
value: selectedLayer.content.style.color,
|
|
413
|
-
onChange: setColor('stroke', 'content.style.color'),
|
|
414
|
-
},
|
|
415
|
-
]}
|
|
416
|
-
/>
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (selectedLayer.type === 'shape' || selectedLayer.type === 'path') {
|
|
421
|
-
return (
|
|
422
|
-
<ScenePropsBar
|
|
423
|
-
colors={[
|
|
424
|
-
{
|
|
425
|
-
label: 'Fill',
|
|
426
|
-
value: selectedLayer.content.fill,
|
|
427
|
-
allowNone: true,
|
|
428
|
-
onChange: setColor('fill', 'content.fill'),
|
|
429
|
-
},
|
|
430
|
-
{
|
|
431
|
-
label: 'Stroke',
|
|
432
|
-
value: selectedLayer.content.stroke,
|
|
433
|
-
onChange: setColor('stroke', 'content.stroke'),
|
|
434
|
-
},
|
|
435
|
-
]}
|
|
436
|
-
/>
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
return null;
|
|
441
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ScenePropsBar — compact, inline per-selection style controls that live
|
|
3
|
-
* INSIDE the contextual toolbar (next to the tool / create buttons), rather
|
|
4
|
-
* than in a separate floating panel.
|
|
5
|
-
*
|
|
6
|
-
* It's intentionally generic: the host (SceneBlockWidget / DiagramWidget)
|
|
7
|
-
* decides what the current selection exposes — color swatches (Fill / Stroke
|
|
8
|
-
* / text Color) and/or dropdowns (a connector's markers, line style, routing)
|
|
9
|
-
* — and passes them as plain `colors` / `selects` descriptors. Renders
|
|
10
|
-
* nothing when the selection has no styleable props.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
interface ScenePropColor {
|
|
14
|
-
label: string;
|
|
15
|
-
/** Current color (`#rrggbb`); shown in the swatch. */
|
|
16
|
-
value?: string;
|
|
17
|
-
/** Show a "none" button that clears the color (emits `'none'`). */
|
|
18
|
-
allowNone?: boolean;
|
|
19
|
-
onChange: (value: string) => void;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface ScenePropSelect {
|
|
23
|
-
label: string;
|
|
24
|
-
value: string;
|
|
25
|
-
options: readonly string[];
|
|
26
|
-
onChange: (value: string) => void;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ScenePropsBarProps {
|
|
30
|
-
colors?: readonly ScenePropColor[];
|
|
31
|
-
selects?: readonly ScenePropSelect[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function ScenePropsBar({ colors = [], selects = [] }: ScenePropsBarProps) {
|
|
35
|
-
if (colors.length === 0 && selects.length === 0) return null;
|
|
36
|
-
return (
|
|
37
|
-
<div className="squisq-scene-block-props" role="group" aria-label="Selection style">
|
|
38
|
-
{colors.map((c) => (
|
|
39
|
-
<span className="squisq-scene-prop" key={c.label}>
|
|
40
|
-
<span className="squisq-scene-prop-label">{c.label}</span>
|
|
41
|
-
<input
|
|
42
|
-
type="color"
|
|
43
|
-
className="squisq-scene-prop-color"
|
|
44
|
-
aria-label={`${c.label} color`}
|
|
45
|
-
value={toHexInput(c.value)}
|
|
46
|
-
onChange={(e) => c.onChange(e.target.value)}
|
|
47
|
-
/>
|
|
48
|
-
{c.allowNone && (
|
|
49
|
-
<button
|
|
50
|
-
type="button"
|
|
51
|
-
className="squisq-scene-prop-clear"
|
|
52
|
-
onClick={() => c.onChange('none')}
|
|
53
|
-
>
|
|
54
|
-
none
|
|
55
|
-
</button>
|
|
56
|
-
)}
|
|
57
|
-
</span>
|
|
58
|
-
))}
|
|
59
|
-
{selects.map((s) => (
|
|
60
|
-
<label className="squisq-scene-prop" key={s.label}>
|
|
61
|
-
<span className="squisq-scene-prop-label">{s.label}</span>
|
|
62
|
-
<select
|
|
63
|
-
className="squisq-scene-prop-select"
|
|
64
|
-
value={s.value}
|
|
65
|
-
onChange={(e) => s.onChange(e.target.value)}
|
|
66
|
-
>
|
|
67
|
-
{s.options.map((o) => (
|
|
68
|
-
<option key={o} value={o}>
|
|
69
|
-
{o}
|
|
70
|
-
</option>
|
|
71
|
-
))}
|
|
72
|
-
</select>
|
|
73
|
-
</label>
|
|
74
|
-
))}
|
|
75
|
-
</div>
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Coerce an arbitrary color (or `none`/undefined) to a `#rrggbb` the native
|
|
80
|
-
* color input can display. Non-hex values fall back to black. */
|
|
81
|
-
function toHexInput(value: string | undefined): string {
|
|
82
|
-
return value && /^#[0-9a-fA-F]{6}$/.test(value) ? value : '#000000';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export default ScenePropsBar;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SceneSelection — selection outline + corner handles for resize.
|
|
3
|
-
*
|
|
4
|
-
* Renders a dashed bounding box per selected layer plus eight grip
|
|
5
|
-
* handles (four corners + four edges). The Scene wires the handles to
|
|
6
|
-
* SelectTool's `beginHandleDrag` so a pointer-down on a handle starts a
|
|
7
|
-
* resize gesture instead of a move.
|
|
8
|
-
*
|
|
9
|
-
* All coordinates are viewport units — the parent group transform
|
|
10
|
-
* carries pan/zoom. Handle dimensions and stroke widths use
|
|
11
|
-
* `vector-effect: non-scaling-stroke` (set in scene.css) so they stay
|
|
12
|
-
* the same pixel size regardless of zoom.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { HitTestable } from './hooks/useSceneHitTest';
|
|
16
|
-
|
|
17
|
-
export type ResizeCorner = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';
|
|
18
|
-
|
|
19
|
-
interface SceneSelectionProps {
|
|
20
|
-
selection: ReadonlySet<string>;
|
|
21
|
-
hitItems: readonly HitTestable[];
|
|
22
|
-
/** Live offset during a move-drag (applied to outline + handles). */
|
|
23
|
-
liveOffset?: { dx: number; dy: number } | null;
|
|
24
|
-
/** Live resize bounds, applied to the matching layer's outline. */
|
|
25
|
-
liveResize?: {
|
|
26
|
-
layerId: string;
|
|
27
|
-
bounds: { x: number; y: number; width: number; height: number };
|
|
28
|
-
} | null;
|
|
29
|
-
/** Fired when the user presses a corner/edge handle. */
|
|
30
|
-
onHandlePointerDown?: (e: React.PointerEvent<SVGElement>, corner: ResizeCorner) => void;
|
|
31
|
-
/** Whether to render resize handles in addition to the selection outline. */
|
|
32
|
-
showHandles?: boolean;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const HANDLE_SIZE = 8;
|
|
36
|
-
|
|
37
|
-
export function SceneSelection({
|
|
38
|
-
selection,
|
|
39
|
-
hitItems,
|
|
40
|
-
liveOffset,
|
|
41
|
-
liveResize,
|
|
42
|
-
onHandlePointerDown,
|
|
43
|
-
showHandles = true,
|
|
44
|
-
}: SceneSelectionProps) {
|
|
45
|
-
if (selection.size === 0) return null;
|
|
46
|
-
const selected = hitItems.filter((it) => selection.has(it.id));
|
|
47
|
-
if (selected.length === 0) return null;
|
|
48
|
-
const offset = liveOffset ?? { dx: 0, dy: 0 };
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<g className="squisq-scene-selection-group">
|
|
52
|
-
{selected.map((it) => {
|
|
53
|
-
// Prefer the live-resize bounds for the matching layer; otherwise
|
|
54
|
-
// apply the move offset.
|
|
55
|
-
let x: number;
|
|
56
|
-
let y: number;
|
|
57
|
-
let w: number;
|
|
58
|
-
let h: number;
|
|
59
|
-
if (liveResize && liveResize.layerId === it.id) {
|
|
60
|
-
x = liveResize.bounds.x;
|
|
61
|
-
y = liveResize.bounds.y;
|
|
62
|
-
w = liveResize.bounds.width;
|
|
63
|
-
h = liveResize.bounds.height;
|
|
64
|
-
} else {
|
|
65
|
-
x = it.bounds.x + offset.dx;
|
|
66
|
-
y = it.bounds.y + offset.dy;
|
|
67
|
-
w = it.bounds.width;
|
|
68
|
-
h = it.bounds.height;
|
|
69
|
-
}
|
|
70
|
-
const corners: { corner: ResizeCorner; cx: number; cy: number; cursor: string }[] = [
|
|
71
|
-
{ corner: 'nw', cx: x, cy: y, cursor: 'nwse-resize' },
|
|
72
|
-
{ corner: 'n', cx: x + w / 2, cy: y, cursor: 'ns-resize' },
|
|
73
|
-
{ corner: 'ne', cx: x + w, cy: y, cursor: 'nesw-resize' },
|
|
74
|
-
{ corner: 'e', cx: x + w, cy: y + h / 2, cursor: 'ew-resize' },
|
|
75
|
-
{ corner: 'se', cx: x + w, cy: y + h, cursor: 'nwse-resize' },
|
|
76
|
-
{ corner: 's', cx: x + w / 2, cy: y + h, cursor: 'ns-resize' },
|
|
77
|
-
{ corner: 'sw', cx: x, cy: y + h, cursor: 'nesw-resize' },
|
|
78
|
-
{ corner: 'w', cx: x, cy: y + h / 2, cursor: 'ew-resize' },
|
|
79
|
-
];
|
|
80
|
-
return (
|
|
81
|
-
<g key={it.id} className="squisq-scene-selection">
|
|
82
|
-
<rect
|
|
83
|
-
x={x}
|
|
84
|
-
y={y}
|
|
85
|
-
width={w}
|
|
86
|
-
height={h}
|
|
87
|
-
className="squisq-scene-selection-outline"
|
|
88
|
-
pointerEvents="none"
|
|
89
|
-
/>
|
|
90
|
-
{showHandles &&
|
|
91
|
-
corners.map(({ corner, cx, cy, cursor }) => (
|
|
92
|
-
<rect
|
|
93
|
-
key={corner}
|
|
94
|
-
x={cx - HANDLE_SIZE / 2}
|
|
95
|
-
y={cy - HANDLE_SIZE / 2}
|
|
96
|
-
width={HANDLE_SIZE}
|
|
97
|
-
height={HANDLE_SIZE}
|
|
98
|
-
className="squisq-scene-selection-handle"
|
|
99
|
-
style={{ cursor }}
|
|
100
|
-
onPointerDown={
|
|
101
|
-
onHandlePointerDown ? (e) => onHandlePointerDown(e, corner) : undefined
|
|
102
|
-
}
|
|
103
|
-
data-corner={corner}
|
|
104
|
-
/>
|
|
105
|
-
))}
|
|
106
|
-
</g>
|
|
107
|
-
);
|
|
108
|
-
})}
|
|
109
|
-
</g>
|
|
110
|
-
);
|
|
111
|
-
}
|