@bendyline/squisq-editor-react 1.5.3 → 1.6.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/dist/index.d.ts +757 -20
- package/dist/index.js +16875 -6883
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/BlockCardView.tsx +121 -0
- package/src/BlockPreviewPanel.tsx +69 -0
- package/src/BlockPropertiesPopover.tsx +191 -0
- package/src/EditorContext.tsx +143 -0
- package/src/EditorShell.tsx +200 -120
- package/src/FolderView.tsx +131 -0
- package/src/Icon.tsx +26 -0
- package/src/ImageEditor.tsx +69 -22
- package/src/OutlinePanel.tsx +38 -3
- package/src/PlainHtmlPreview.tsx +30 -3
- package/src/PreviewControls.tsx +180 -8
- package/src/RawEditor.tsx +169 -13
- package/src/RecorderEntry.tsx +9 -16
- package/src/TemplateAnnotation.ts +44 -0
- package/src/TemplatePicker.tsx +329 -54
- package/src/ThemeCustomizerPanel.tsx +30 -336
- package/src/ThemePicker.tsx +112 -3
- package/src/TimelineBlockPreview.tsx +37 -0
- package/src/TimelineTrack.tsx +671 -0
- package/src/Toolbar.tsx +528 -174
- package/src/Tooltip.tsx +22 -4
- package/src/TransitionPicker.tsx +351 -0
- package/src/VersionHistoryPanel.tsx +2 -14
- package/src/ViewMenuPanel.tsx +17 -14
- package/src/WysiwygEditor.tsx +161 -65
- package/src/__tests__/blockProperties.test.ts +92 -0
- package/src/__tests__/blockRange.test.ts +105 -0
- package/src/__tests__/buildPreviewDocTransition.test.ts +73 -0
- package/src/__tests__/createShapeLayer.test.ts +46 -0
- package/src/__tests__/drawingShapeRoundTrip.test.ts +49 -0
- package/src/__tests__/embeddedMedia.test.ts +48 -0
- package/src/__tests__/headingTransition.test.ts +138 -0
- package/src/__tests__/layoutChildRoundTrip.test.ts +71 -0
- package/src/__tests__/plainHtmlPreview.test.tsx +10 -8
- package/src/__tests__/recorderMediaInsert.test.ts +86 -0
- package/src/__tests__/templateAnnotationRoundTrip.test.ts +18 -0
- package/src/__tests__/templatePickerMetadata.test.ts +32 -0
- package/src/__tests__/timelineSource.test.ts +134 -0
- package/src/__tests__/tiptapBridge.test.ts +92 -0
- package/src/__tests__/tiptapBridgeConformance.test.ts +47 -0
- package/src/__tests__/tooltip.test.tsx +72 -0
- package/src/__tests__/transitionCatalog.test.ts +64 -0
- package/src/__tests__/useBlockNavigator.test.tsx +67 -0
- package/src/__tests__/useMediaRecorder.test.ts +24 -0
- package/src/__tests__/useTimelineClock.test.ts +21 -0
- package/src/blockProperties.ts +88 -0
- package/src/blockRange.ts +132 -0
- package/src/buildPreviewDoc.ts +98 -9
- package/src/customTemplates/AddBin.tsx +126 -0
- package/src/customTemplates/CustomLayoutManager.tsx +233 -0
- package/src/customTemplates/CustomTemplateContext.tsx +182 -0
- package/src/customTemplates/LayerToolbar.tsx +580 -0
- package/src/customTemplates/ShapeGlyph.tsx +47 -0
- package/src/customTemplates/TemplateDesigner.tsx +430 -0
- package/src/customTemplates/__tests__/library.test.ts +88 -0
- package/src/customTemplates/__tests__/normalizePositions.test.ts +109 -0
- package/src/customTemplates/__tests__/shapeDefs.test.ts +49 -0
- package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +95 -0
- package/src/customTemplates/designer.css +673 -0
- package/src/customTemplates/index.ts +31 -0
- package/src/customTemplates/library.ts +97 -0
- package/src/customTemplates/normalizePositions.ts +75 -0
- package/src/customTemplates/shapeDefs.ts +131 -0
- package/src/customTemplates/thumbnail.tsx +63 -0
- package/src/customTemplates/tokenDefs.ts +60 -0
- package/src/customTemplates/useDocCustomTemplates.ts +52 -0
- package/src/customTemplates/useMemoryLayerAdapter.ts +123 -0
- package/src/customThemes/CustomThemeContext.tsx +179 -0
- package/src/customThemes/CustomThemeDialog.tsx +286 -0
- package/src/customThemes/__tests__/CustomThemeContext.test.tsx +64 -0
- package/src/customThemes/__tests__/CustomThemeDialog.test.tsx +47 -0
- package/src/customThemes/__tests__/customThemeLibrary.test.ts +51 -0
- package/src/customThemes/customThemeLibrary.ts +97 -0
- package/src/customThemes/index.ts +31 -0
- package/src/customThemes/themeControls.tsx +229 -0
- package/src/customThemes/themeDraft.ts +272 -0
- package/src/customThemes/useDocCustomThemes.ts +49 -0
- package/src/diagram/DiagramCanvas.tsx +240 -0
- package/src/diagram/DiagramExtension.ts +209 -0
- package/src/diagram/DiagramMaximizedOverlay.tsx +46 -0
- package/src/diagram/DiagramWidget.tsx +270 -0
- package/src/diagram/diagramCommands.ts +604 -0
- package/src/diagram/diagramConstants.ts +17 -0
- package/src/diagram/useDiagramData.ts +126 -0
- package/src/embeddedMedia.ts +78 -0
- package/src/frontmatter.ts +29 -0
- package/src/headingTransition.ts +231 -0
- package/src/imageEditor/CanvasSurface.tsx +383 -88
- package/src/imageEditor/PropertiesPanel.tsx +47 -1
- package/src/imageEditor/Toolbar.tsx +229 -16
- package/src/imageEditor/createShapeLayer.ts +280 -0
- package/src/imageEditor/icons.tsx +34 -114
- package/src/imageEditor/image-editor.css +54 -5
- package/src/imageEditor/state.ts +23 -3
- package/src/index.ts +77 -0
- package/src/recorder/RecorderModal.tsx +120 -53
- package/src/recorder/RecorderPanel.tsx +2 -26
- package/src/recorder/hooks/useMediaRecorder.ts +8 -1
- package/src/recorder/insertMediaBlock.ts +30 -0
- package/src/resolveBlockVisual.ts +33 -0
- package/src/scene/Scene.tsx +540 -0
- package/src/scene/SceneBlockExtension.ts +198 -0
- package/src/scene/SceneBlockToolbar.tsx +201 -0
- package/src/scene/SceneBlockWidget.tsx +434 -0
- package/src/scene/ScenePropsBar.tsx +85 -0
- package/src/scene/SceneSelection.tsx +107 -0
- package/src/scene/SceneViewport.tsx +102 -0
- package/src/scene/ShapePalette.tsx +181 -0
- package/src/scene/__tests__/DiagramAdapter.test.ts +56 -0
- package/src/scene/__tests__/bezierEdit.test.ts +85 -0
- package/src/scene/__tests__/blockLayers.test.ts +57 -0
- package/src/scene/__tests__/shapeLayers.test.ts +106 -0
- package/src/scene/__tests__/useSceneHitTest.test.ts +90 -0
- package/src/scene/__tests__/useScenePanZoom.test.ts +103 -0
- package/src/scene/adapters/DiagramAdapter.ts +168 -0
- package/src/scene/adapters/DrawingAdapter.ts +415 -0
- package/src/scene/adapters/LayoutAdapter.ts +310 -0
- package/src/scene/adapters/blockLayers.ts +159 -0
- package/src/scene/commands/SceneCommand.ts +70 -0
- package/src/scene/commands/drawingCommands.ts +318 -0
- package/src/scene/commands/layoutCommands.ts +301 -0
- package/src/scene/hooks/useSceneHitTest.ts +105 -0
- package/src/scene/hooks/useScenePanZoom.ts +147 -0
- package/src/scene/hooks/useSceneSelection.ts +62 -0
- package/src/scene/index.ts +95 -0
- package/src/scene/layers/DiagramEdges.tsx +127 -0
- package/src/scene/layers/edgeGeometry.ts +77 -0
- package/src/scene/layers/nodeCard.tsx +145 -0
- package/src/scene/layers/renderLayer.tsx +70 -0
- package/src/scene/layers/shapeLayers.ts +201 -0
- package/src/scene/paths/bezierEdit.ts +208 -0
- package/src/scene/scene.css +649 -0
- package/src/scene/text/SceneTextOverlay.tsx +161 -0
- package/src/scene/text/sceneTextChannel.ts +40 -0
- package/src/scene/text/sceneTextConfig.ts +27 -0
- package/src/scene/text/sceneTiptap.ts +36 -0
- package/src/scene/text/useSceneTextEditing.ts +39 -0
- package/src/scene/tools/ConnectTool.ts +111 -0
- package/src/scene/tools/DrawingConnectTool.ts +161 -0
- package/src/scene/tools/PathTool.ts +158 -0
- package/src/scene/tools/PlaceTool.ts +47 -0
- package/src/scene/tools/SceneTool.ts +75 -0
- package/src/scene/tools/SelectTool.ts +284 -0
- package/src/scene/tools/ShapeTool.ts +144 -0
- package/src/scene/tools/TextTool.ts +72 -0
- package/src/scene/tools/TokenTool.ts +95 -0
- package/src/scene/tools/createDrawShapeTool.ts +82 -0
- package/src/styles/diagram.css +183 -0
- package/src/styles/editor.css +1615 -203
- package/src/styles/folder-view.css +210 -0
- package/src/styles/image-edit-affordance.css +2 -2
- package/src/styles/index.css +4 -0
- package/src/timelineSource.ts +244 -0
- package/src/tiptapBridge.ts +115 -34
- package/src/tooltipPlacement.ts +13 -0
- package/src/transitionCatalog.ts +159 -0
- package/src/types/monaco-shims.d.ts +10 -0
- package/src/useBlockNavigator.ts +153 -0
- package/src/useMonacoLoader.ts +23 -1
- package/src/useTimelineClock.ts +76 -0
- package/src/utils/dropUtils.ts +1 -1
package/src/EditorContext.tsx
CHANGED
|
@@ -32,6 +32,8 @@ import type { Editor as TiptapEditor } from '@tiptap/core';
|
|
|
32
32
|
import type { editor as MonacoEditorNs } from 'monaco-editor';
|
|
33
33
|
import { markdownToTiptap } from './tiptapBridge';
|
|
34
34
|
import { resolveFileKind } from './fileKind';
|
|
35
|
+
import { useBlockNavigator } from './useBlockNavigator';
|
|
36
|
+
import { sceneTextChannel, type SceneTextHandle } from './scene/text/sceneTextChannel';
|
|
35
37
|
|
|
36
38
|
/** Monaco standalone code editor instance type */
|
|
37
39
|
type MonacoEditor = MonacoEditorNs.IStandaloneCodeEditor;
|
|
@@ -90,6 +92,15 @@ export type DocumentLinkProvider = (query: string) => Promise<DocumentLinkCandid
|
|
|
90
92
|
|
|
91
93
|
export type EditorView = 'raw' | 'wysiwyg' | 'preview';
|
|
92
94
|
export type EditorTheme = 'light' | 'dark';
|
|
95
|
+
/**
|
|
96
|
+
* Document layout mode. `'document'` shows the whole markdown document in
|
|
97
|
+
* the active view (the historical behavior). `'block'` is the
|
|
98
|
+
* block-at-a-time view — one heading-defined block on a card at a time,
|
|
99
|
+
* with the editor scoped to just that block. `'timeline'` is block mode plus
|
|
100
|
+
* a horizontal timeline track for editing block durations and media slices.
|
|
101
|
+
* See {@link useBlockNavigator}.
|
|
102
|
+
*/
|
|
103
|
+
export type LayoutMode = 'document' | 'block' | 'timeline';
|
|
93
104
|
/**
|
|
94
105
|
* How much of the active Squisq theme the WYSIWYG editing surface
|
|
95
106
|
* mirrors. `'fonts'` is the historical default — body and heading
|
|
@@ -179,11 +190,48 @@ export interface EditorState {
|
|
|
179
190
|
* shell.
|
|
180
191
|
*/
|
|
181
192
|
allowRecording: boolean;
|
|
193
|
+
/**
|
|
194
|
+
* Document layout mode. `'document'` (default) edits the whole document;
|
|
195
|
+
* `'block'` activates the block-at-a-time card view. Initialized from the
|
|
196
|
+
* EditorShell `layoutMode` prop; the View menu can toggle it at runtime.
|
|
197
|
+
*/
|
|
198
|
+
layoutMode: LayoutMode;
|
|
199
|
+
/**
|
|
200
|
+
* The markdown the active text editor should bind to: the full source in
|
|
201
|
+
* `'document'` mode, or just the active block's slice in `'block'` mode.
|
|
202
|
+
* Editors read this instead of `markdownSource` so the same surfaces work
|
|
203
|
+
* in both layouts.
|
|
204
|
+
*/
|
|
205
|
+
editorSource: string;
|
|
206
|
+
/** Number of navigable blocks (cards) in the current document. */
|
|
207
|
+
blockCount: number;
|
|
208
|
+
/** Index of the block currently shown on the card (block mode). */
|
|
209
|
+
activeBlockKey: number;
|
|
210
|
+
/** 1-based source line where the active block begins, or null. */
|
|
211
|
+
activeBlockStartLine: number | null;
|
|
182
212
|
}
|
|
183
213
|
|
|
184
214
|
export interface EditorActions {
|
|
185
215
|
/** Set markdown source and trigger re-parse */
|
|
186
216
|
setMarkdownSource: (source: string) => void;
|
|
217
|
+
/**
|
|
218
|
+
* Write through the active editor channel. In `'document'` mode this is
|
|
219
|
+
* `setMarkdownSource`; in `'block'` mode it splices the edited block back
|
|
220
|
+
* into the full document. Editors call this instead of `setMarkdownSource`.
|
|
221
|
+
*/
|
|
222
|
+
setEditorSource: (source: string) => void;
|
|
223
|
+
/** Switch between Document and Block-at-a-time layouts. */
|
|
224
|
+
setLayoutMode: (mode: LayoutMode) => void;
|
|
225
|
+
/** Show a block by index in block mode (clamped to range). */
|
|
226
|
+
goToBlock: (key: number) => void;
|
|
227
|
+
/** Show the block that owns a given 1-based source line (used by the outline). */
|
|
228
|
+
goToBlockByLine: (line: number) => void;
|
|
229
|
+
/** Move the card to the previous block. */
|
|
230
|
+
prevBlock: () => void;
|
|
231
|
+
/** Move the card to the next block. */
|
|
232
|
+
nextBlock: () => void;
|
|
233
|
+
/** Insert a new heading block after the active one and move to it. */
|
|
234
|
+
addBlock: () => void;
|
|
187
235
|
/** Set markdown from a MarkdownDocument (e.g. from WYSIWYG) */
|
|
188
236
|
setMarkdownDoc: (doc: MarkdownDocument) => void;
|
|
189
237
|
/** Switch the active view */
|
|
@@ -230,6 +278,14 @@ export interface EditorContextValue extends EditorState, EditorActions {
|
|
|
230
278
|
tiptapEditor: TiptapEditor | null;
|
|
231
279
|
/** The live Monaco editor instance (null when Raw is not mounted) */
|
|
232
280
|
monacoEditor: MonacoEditor | null;
|
|
281
|
+
/**
|
|
282
|
+
* The focused canvas textbox editor, if any — a small Tiptap instance for
|
|
283
|
+
* a diagram/drawing/layout textbox being edited inline. Published via
|
|
284
|
+
* `sceneTextChannel` (the canvas renders in a detached React root). The
|
|
285
|
+
* top formatting toolbar retargets to this when set. `level` gates which
|
|
286
|
+
* buttons apply (`inline` = marks only; `rich` = headings/lists too).
|
|
287
|
+
*/
|
|
288
|
+
activeSceneText: SceneTextHandle | null;
|
|
233
289
|
/**
|
|
234
290
|
* Workspace-scoped `ContentContainer` for this document — the folder
|
|
235
291
|
* holding the doc, its `_files/` sidecar, sibling documents, and any
|
|
@@ -396,6 +452,12 @@ export interface EditorProviderProps {
|
|
|
396
452
|
* toolbar's View menu can change it at runtime.
|
|
397
453
|
*/
|
|
398
454
|
themeInheritance?: ThemeInheritance;
|
|
455
|
+
/**
|
|
456
|
+
* Initial layout mode. Defaults to `'document'` (whole-document editing).
|
|
457
|
+
* `'block'` boots into the block-at-a-time card view. The toolbar's View
|
|
458
|
+
* menu can toggle it at runtime.
|
|
459
|
+
*/
|
|
460
|
+
layoutMode?: LayoutMode;
|
|
399
461
|
/**
|
|
400
462
|
* Bundled view preferences — a serializable JSON blob covering all
|
|
401
463
|
* runtime-toggleable view options. When provided, individual values
|
|
@@ -432,6 +494,8 @@ export interface ViewPreferences {
|
|
|
432
494
|
blockTags?: boolean;
|
|
433
495
|
/** How much of the active Squisq theme the WYSIWYG surface mirrors. */
|
|
434
496
|
themeInheritance?: ThemeInheritance;
|
|
497
|
+
/** Document vs. block-at-a-time layout. */
|
|
498
|
+
layoutMode?: LayoutMode;
|
|
435
499
|
}
|
|
436
500
|
|
|
437
501
|
/**
|
|
@@ -464,6 +528,7 @@ export function EditorProvider({
|
|
|
464
528
|
outline = false,
|
|
465
529
|
blockTags = true,
|
|
466
530
|
themeInheritance = 'fonts',
|
|
531
|
+
layoutMode = 'document',
|
|
467
532
|
viewPreferences,
|
|
468
533
|
onViewPreferencesChange,
|
|
469
534
|
children,
|
|
@@ -476,6 +541,7 @@ export function EditorProvider({
|
|
|
476
541
|
const effectiveOutline = viewPreferences?.outline ?? outline;
|
|
477
542
|
const effectiveBlockTags = viewPreferences?.blockTags ?? blockTags;
|
|
478
543
|
const effectiveThemeInheritance = viewPreferences?.themeInheritance ?? themeInheritance;
|
|
544
|
+
const effectiveLayoutMode = viewPreferences?.layoutMode ?? layoutMode;
|
|
479
545
|
// Resolve once per provider mount. Changing fileName/language after mount
|
|
480
546
|
// would require recreating the Monaco model anyway, so treat it as static.
|
|
481
547
|
const { mode: editorMode, language: resolvedLanguage } = useMemo(
|
|
@@ -528,6 +594,10 @@ export function EditorProvider({
|
|
|
528
594
|
useEffect(() => {
|
|
529
595
|
setThemeInheritanceRaw(themeInheritance);
|
|
530
596
|
}, [themeInheritance]);
|
|
597
|
+
const [layoutModeState, setLayoutModeRaw] = useState<LayoutMode>(effectiveLayoutMode);
|
|
598
|
+
useEffect(() => {
|
|
599
|
+
setLayoutModeRaw(layoutMode);
|
|
600
|
+
}, [layoutMode]);
|
|
531
601
|
const [imageEditTarget, setImageEditTarget] = useState<string | null>(null);
|
|
532
602
|
const [mediaRevision, setMediaRevision] = useState(0);
|
|
533
603
|
const openImageEdit = useCallback((relativePath: string) => {
|
|
@@ -560,6 +630,9 @@ export function EditorProvider({
|
|
|
560
630
|
if (viewPreferences.themeInheritance !== undefined) {
|
|
561
631
|
setThemeInheritanceRaw(viewPreferences.themeInheritance);
|
|
562
632
|
}
|
|
633
|
+
if (viewPreferences.layoutMode !== undefined) {
|
|
634
|
+
setLayoutModeRaw(viewPreferences.layoutMode);
|
|
635
|
+
}
|
|
563
636
|
}, [viewPreferences]);
|
|
564
637
|
|
|
565
638
|
// Wrap the three setters so user-driven toggles emit a snapshot via
|
|
@@ -579,6 +652,8 @@ export function EditorProvider({
|
|
|
579
652
|
blockTagsRef.current = blockTagsVisible;
|
|
580
653
|
const themeInheritanceRef = useRef(themeInheritanceState);
|
|
581
654
|
themeInheritanceRef.current = themeInheritanceState;
|
|
655
|
+
const layoutModeRef = useRef(layoutModeState);
|
|
656
|
+
layoutModeRef.current = layoutModeState;
|
|
582
657
|
const setInlinePreviewVisible = useCallback((visible: boolean) => {
|
|
583
658
|
setInlinePreviewVisibleRaw(visible);
|
|
584
659
|
onViewPreferencesChangeRef.current?.({
|
|
@@ -587,6 +662,7 @@ export function EditorProvider({
|
|
|
587
662
|
outline: outlineRef.current,
|
|
588
663
|
blockTags: blockTagsRef.current,
|
|
589
664
|
themeInheritance: themeInheritanceRef.current,
|
|
665
|
+
layoutMode: layoutModeRef.current,
|
|
590
666
|
});
|
|
591
667
|
}, []);
|
|
592
668
|
const setStatusBarVisible = useCallback((visible: boolean) => {
|
|
@@ -597,6 +673,7 @@ export function EditorProvider({
|
|
|
597
673
|
outline: outlineRef.current,
|
|
598
674
|
blockTags: blockTagsRef.current,
|
|
599
675
|
themeInheritance: themeInheritanceRef.current,
|
|
676
|
+
layoutMode: layoutModeRef.current,
|
|
600
677
|
});
|
|
601
678
|
}, []);
|
|
602
679
|
const setOutlineVisible = useCallback((visible: boolean) => {
|
|
@@ -607,6 +684,7 @@ export function EditorProvider({
|
|
|
607
684
|
outline: visible,
|
|
608
685
|
blockTags: blockTagsRef.current,
|
|
609
686
|
themeInheritance: themeInheritanceRef.current,
|
|
687
|
+
layoutMode: layoutModeRef.current,
|
|
610
688
|
});
|
|
611
689
|
}, []);
|
|
612
690
|
const setBlockTagsVisible = useCallback((visible: boolean) => {
|
|
@@ -617,6 +695,7 @@ export function EditorProvider({
|
|
|
617
695
|
outline: outlineRef.current,
|
|
618
696
|
blockTags: visible,
|
|
619
697
|
themeInheritance: themeInheritanceRef.current,
|
|
698
|
+
layoutMode: layoutModeRef.current,
|
|
620
699
|
});
|
|
621
700
|
}, []);
|
|
622
701
|
const setThemeInheritance = useCallback((mode: ThemeInheritance) => {
|
|
@@ -627,10 +706,27 @@ export function EditorProvider({
|
|
|
627
706
|
outline: outlineRef.current,
|
|
628
707
|
blockTags: blockTagsRef.current,
|
|
629
708
|
themeInheritance: mode,
|
|
709
|
+
layoutMode: layoutModeRef.current,
|
|
710
|
+
});
|
|
711
|
+
}, []);
|
|
712
|
+
const setLayoutMode = useCallback((mode: LayoutMode) => {
|
|
713
|
+
setLayoutModeRaw(mode);
|
|
714
|
+
onViewPreferencesChangeRef.current?.({
|
|
715
|
+
inlinePreview: inlinePreviewRef.current,
|
|
716
|
+
showStatusBar: statusBarRef.current,
|
|
717
|
+
outline: outlineRef.current,
|
|
718
|
+
blockTags: blockTagsRef.current,
|
|
719
|
+
themeInheritance: themeInheritanceRef.current,
|
|
720
|
+
layoutMode: mode,
|
|
630
721
|
});
|
|
631
722
|
}, []);
|
|
632
723
|
const [tiptapEditor, setTiptapEditor] = useState<TiptapEditor | null>(null);
|
|
633
724
|
const [monacoEditor, setMonacoEditor] = useState<MonacoEditor | null>(null);
|
|
725
|
+
// Mirror the focused canvas textbox editor (published by the inline
|
|
726
|
+
// SceneTextOverlay through a module channel, since the canvas renders in
|
|
727
|
+
// a detached React root outside this provider) so the toolbar can target it.
|
|
728
|
+
const [activeSceneText, setActiveSceneText] = useState<SceneTextHandle | null>(null);
|
|
729
|
+
useEffect(() => sceneTextChannel.subscribe(setActiveSceneText), []);
|
|
634
730
|
|
|
635
731
|
const articleIdRef = useRef(articleId);
|
|
636
732
|
articleIdRef.current = articleId;
|
|
@@ -702,6 +798,27 @@ export function EditorProvider({
|
|
|
702
798
|
setMarkdownSourceRaw(source);
|
|
703
799
|
}, []);
|
|
704
800
|
|
|
801
|
+
// Block-at-a-time navigation. In 'document' mode the channel passes
|
|
802
|
+
// through to the full source; in 'block' mode `editorSource` is the active
|
|
803
|
+
// block's slice and `setEditorSource` splices edits back in. Gated to
|
|
804
|
+
// markdown mode — code/image surfaces always edit the whole file.
|
|
805
|
+
const blockNav = useBlockNavigator(markdownSource, setMarkdownSource, {
|
|
806
|
+
enabled:
|
|
807
|
+
(layoutModeState === 'block' || layoutModeState === 'timeline') && editorMode === 'markdown',
|
|
808
|
+
});
|
|
809
|
+
const {
|
|
810
|
+
editorSource,
|
|
811
|
+
setEditorSource,
|
|
812
|
+
blockCount,
|
|
813
|
+
activeBlockKey,
|
|
814
|
+
activeBlockStartLine,
|
|
815
|
+
goToBlock,
|
|
816
|
+
goToBlockByLine,
|
|
817
|
+
prevBlock,
|
|
818
|
+
nextBlock,
|
|
819
|
+
addBlock,
|
|
820
|
+
} = blockNav;
|
|
821
|
+
|
|
705
822
|
const insertAtCursor = useCallback(
|
|
706
823
|
(text: string) => {
|
|
707
824
|
if (activeView === 'wysiwyg' && tiptapEditor) {
|
|
@@ -862,11 +979,17 @@ export function EditorProvider({
|
|
|
862
979
|
outlineVisible,
|
|
863
980
|
blockTagsVisible,
|
|
864
981
|
themeInheritance: themeInheritanceState,
|
|
982
|
+
layoutMode: layoutModeState,
|
|
983
|
+
editorSource,
|
|
984
|
+
blockCount,
|
|
985
|
+
activeBlockKey,
|
|
986
|
+
activeBlockStartLine,
|
|
865
987
|
imageEditTarget,
|
|
866
988
|
mediaRevision,
|
|
867
989
|
allowRecording,
|
|
868
990
|
tiptapEditor,
|
|
869
991
|
monacoEditor,
|
|
992
|
+
activeSceneText,
|
|
870
993
|
workspaceContainer,
|
|
871
994
|
versioning,
|
|
872
995
|
saveVersion,
|
|
@@ -875,6 +998,13 @@ export function EditorProvider({
|
|
|
875
998
|
mentionProvider,
|
|
876
999
|
documentLinkProvider,
|
|
877
1000
|
setMarkdownSource,
|
|
1001
|
+
setEditorSource,
|
|
1002
|
+
setLayoutMode,
|
|
1003
|
+
goToBlock,
|
|
1004
|
+
goToBlockByLine,
|
|
1005
|
+
prevBlock,
|
|
1006
|
+
nextBlock,
|
|
1007
|
+
addBlock,
|
|
878
1008
|
setMarkdownDoc,
|
|
879
1009
|
setActiveView,
|
|
880
1010
|
setTiptapEditor,
|
|
@@ -906,8 +1036,14 @@ export function EditorProvider({
|
|
|
906
1036
|
outlineVisible,
|
|
907
1037
|
blockTagsVisible,
|
|
908
1038
|
themeInheritanceState,
|
|
1039
|
+
layoutModeState,
|
|
1040
|
+
editorSource,
|
|
1041
|
+
blockCount,
|
|
1042
|
+
activeBlockKey,
|
|
1043
|
+
activeBlockStartLine,
|
|
909
1044
|
tiptapEditor,
|
|
910
1045
|
monacoEditor,
|
|
1046
|
+
activeSceneText,
|
|
911
1047
|
workspaceContainer,
|
|
912
1048
|
versioning,
|
|
913
1049
|
saveVersion,
|
|
@@ -916,6 +1052,13 @@ export function EditorProvider({
|
|
|
916
1052
|
mentionProvider,
|
|
917
1053
|
documentLinkProvider,
|
|
918
1054
|
setMarkdownSource,
|
|
1055
|
+
setEditorSource,
|
|
1056
|
+
setLayoutMode,
|
|
1057
|
+
goToBlock,
|
|
1058
|
+
goToBlockByLine,
|
|
1059
|
+
prevBlock,
|
|
1060
|
+
nextBlock,
|
|
1061
|
+
addBlock,
|
|
919
1062
|
setMarkdownDoc,
|
|
920
1063
|
setActiveView,
|
|
921
1064
|
setTiptapEditor,
|