@bendyline/squisq-editor-react 1.5.3 → 1.6.1
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/README.md +57 -10
- package/dist/index.d.ts +1114 -52
- package/dist/index.js +18446 -8050
- package/dist/index.js.map +1 -1
- package/dist/styles/fa-brands-400-AHOAZHCU.woff2 +0 -0
- package/dist/styles/fa-regular-400-VRZYIBIZ.woff2 +0 -0
- package/dist/styles/fa-solid-900-MDEYK55F.woff2 +0 -0
- package/dist/styles/fa-v4compatibility-ETEVP6IB.woff2 +0 -0
- package/dist/styles/index.css +13867 -0
- package/package.json +15 -7
- package/src/BlockCardView.tsx +121 -0
- package/src/BlockPreviewPanel.tsx +69 -0
- package/src/BlockPropertiesPopover.tsx +191 -0
- package/src/EditorContext.tsx +165 -16
- package/src/EditorShell.tsx +265 -144
- package/src/FolderView.tsx +131 -0
- package/src/Icon.tsx +26 -0
- package/src/ImageEditor.tsx +69 -22
- package/src/OutlinePanel.tsx +64 -7
- package/src/PlainHtmlPreview.tsx +30 -3
- package/src/PreviewControls.tsx +491 -122
- package/src/PreviewPanel.tsx +15 -9
- package/src/RawEditor.tsx +179 -17
- 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 +544 -180
- package/src/Tooltip.tsx +22 -4
- package/src/TransitionPicker.tsx +351 -0
- package/src/VersionHistoryPanel.tsx +4 -16
- 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__/codeContextSectionView.test.tsx +95 -0
- package/src/__tests__/codeContextZoneManager.test.ts +127 -0
- package/src/__tests__/createShapeLayer.test.ts +46 -0
- package/src/__tests__/diffContextSections.test.ts +39 -0
- package/src/__tests__/drawingShapeRoundTrip.test.ts +49 -0
- package/src/__tests__/editorShellCodeContext.test.tsx +86 -0
- package/src/__tests__/editorShellProps.test.tsx +96 -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__/previewControls.test.tsx +70 -0
- 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__/useJsonEditorTokens.test.ts +59 -0
- package/src/__tests__/useMediaRecorder.test.ts +41 -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/codeContext/CodeContextSectionView.tsx +124 -0
- package/src/codeContext/CodeContextZoneManager.ts +149 -0
- package/src/codeContext/CodeContextZones.tsx +121 -0
- package/src/codeContext/diffContextSections.ts +38 -0
- package/src/codeContext/types.ts +75 -0
- 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 +109 -1
- package/src/jsonEditor/useJsonEditorTokens.ts +13 -43
- package/src/recorder/RecorderModal.tsx +120 -53
- package/src/recorder/RecorderPanel.tsx +2 -26
- package/src/recorder/hooks/useMediaRecorder.ts +17 -11
- 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/code-context.css +155 -0
- package/src/styles/diagram.css +183 -0
- package/src/styles/editor.css +1708 -150
- package/src/styles/folder-view.css +210 -0
- package/src/styles/image-edit-affordance.css +2 -2
- package/src/styles/index.css +5 -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/EditorShell.tsx
CHANGED
|
@@ -22,11 +22,23 @@ import { StatusBar } from './StatusBar';
|
|
|
22
22
|
import { RawEditor } from './RawEditor';
|
|
23
23
|
import { WysiwygEditor } from './WysiwygEditor';
|
|
24
24
|
import { InlinePreviewGutter } from './InlinePreviewGutter';
|
|
25
|
-
import {
|
|
25
|
+
import { BlockPreviewPanel } from './BlockPreviewPanel';
|
|
26
|
+
import { OutlinePanel, OUTLINE_RESPONSIVE_WIDTH } from './OutlinePanel';
|
|
27
|
+
import { CodeContextZones } from './codeContext/CodeContextZones';
|
|
28
|
+
import type { CodeContext } from './codeContext/types';
|
|
29
|
+
import { BlockCardView } from './BlockCardView';
|
|
30
|
+
import { TimelineTrack } from './TimelineTrack';
|
|
26
31
|
import { PreviewPanel } from './PreviewPanel';
|
|
27
32
|
import { ImageViewer } from './ImageViewer';
|
|
28
33
|
import { ImageEditor } from './ImageEditor';
|
|
29
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
PreviewSettingsProvider,
|
|
36
|
+
PreviewToolbarControls,
|
|
37
|
+
PreviewModeSwitch,
|
|
38
|
+
PreviewFormatSwitch,
|
|
39
|
+
ThemeDesignerDock,
|
|
40
|
+
} from './PreviewControls';
|
|
41
|
+
import { CustomThemeProvider, useDocCustomThemes } from './customThemes';
|
|
30
42
|
import { MediaBin } from './MediaBin';
|
|
31
43
|
import { DropZoneOverlay } from './DropZoneOverlay';
|
|
32
44
|
import { TooltipLayer } from './Tooltip';
|
|
@@ -48,7 +60,7 @@ import {
|
|
|
48
60
|
import type { PrunePolicy, SaveVersionResult } from '@bendyline/squisq/versions';
|
|
49
61
|
import type { CSSProperties, ReactNode } from 'react';
|
|
50
62
|
|
|
51
|
-
export type {
|
|
63
|
+
export type { EditorColorScheme } from './EditorContext';
|
|
52
64
|
|
|
53
65
|
export interface EditorShellProps {
|
|
54
66
|
/** Initial markdown content */
|
|
@@ -62,8 +74,13 @@ export interface EditorShellProps {
|
|
|
62
74
|
basePath?: string;
|
|
63
75
|
/** Called when markdown source changes */
|
|
64
76
|
onChange?: (source: string) => void;
|
|
65
|
-
/**
|
|
66
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Light/dark chrome color scheme for the editor shell — toolbar, tabs,
|
|
79
|
+
* status bar, and side panes (default: `'light'`). This is the editor's
|
|
80
|
+
* UI mode, **not** a Squisq `Theme` object; the rendered document's
|
|
81
|
+
* styling is controlled separately via `themeOverride` / `Doc.themeId`.
|
|
82
|
+
*/
|
|
83
|
+
colorScheme?: 'light' | 'dark';
|
|
67
84
|
/** Additional class name */
|
|
68
85
|
className?: string;
|
|
69
86
|
/** CSS height for the shell container (default: '100vh') */
|
|
@@ -158,6 +175,13 @@ export interface EditorShellProps {
|
|
|
158
175
|
* (Slack, Discord). When omitted, the editor behaves normally.
|
|
159
176
|
*/
|
|
160
177
|
submitOnEnter?: () => void;
|
|
178
|
+
/**
|
|
179
|
+
* Host-supplied context dictionary rendered inside the Monaco (raw / code)
|
|
180
|
+
* surface: collapsible markdown sections injected above anchor lines, plus
|
|
181
|
+
* an optional file-top summary. See {@link CodeContext}. Ignored in
|
|
182
|
+
* WYSIWYG / preview / image surfaces.
|
|
183
|
+
*/
|
|
184
|
+
codeContext?: CodeContext;
|
|
161
185
|
/**
|
|
162
186
|
* Let the WYSIWYG editing surface fill its container instead of rendering
|
|
163
187
|
* as a centered 800px "page" column. Useful when embedding in chat
|
|
@@ -316,9 +340,11 @@ export interface EditorShellProps {
|
|
|
316
340
|
*/
|
|
317
341
|
outline?: boolean;
|
|
318
342
|
/**
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
343
|
+
* Fixed width in pixels for the outline pane. When omitted, the pane sizes
|
|
344
|
+
* responsively — never narrower than 260px, growing with the window and
|
|
345
|
+
* capped at 460px — so it stretches out when there's horizontal space to
|
|
346
|
+
* spare. Only takes effect when {@link EditorShellProps.outline} is true (or
|
|
347
|
+
* the View menu has toggled it on).
|
|
322
348
|
*/
|
|
323
349
|
outlineWidth?: number;
|
|
324
350
|
/**
|
|
@@ -370,7 +396,7 @@ export function EditorShell({
|
|
|
370
396
|
articleId = 'untitled',
|
|
371
397
|
basePath = '/',
|
|
372
398
|
onChange,
|
|
373
|
-
|
|
399
|
+
colorScheme = 'light',
|
|
374
400
|
className,
|
|
375
401
|
height = '100vh',
|
|
376
402
|
minHeight,
|
|
@@ -389,6 +415,7 @@ export function EditorShell({
|
|
|
389
415
|
toolbarSlotRight,
|
|
390
416
|
showPlayTab = true,
|
|
391
417
|
submitOnEnter,
|
|
418
|
+
codeContext,
|
|
392
419
|
fullWidth = false,
|
|
393
420
|
uxFont,
|
|
394
421
|
thinMargins = false,
|
|
@@ -409,7 +436,7 @@ export function EditorShell({
|
|
|
409
436
|
inlinePreview = false,
|
|
410
437
|
inlinePreviewWidth = 320,
|
|
411
438
|
outline = false,
|
|
412
|
-
outlineWidth
|
|
439
|
+
outlineWidth,
|
|
413
440
|
blockTags = true,
|
|
414
441
|
themeInheritance = 'fonts',
|
|
415
442
|
viewPreferences,
|
|
@@ -441,7 +468,7 @@ export function EditorShell({
|
|
|
441
468
|
initialMarkdown={initialMarkdown}
|
|
442
469
|
initialView={effectiveInitialView}
|
|
443
470
|
articleId={articleId}
|
|
444
|
-
|
|
471
|
+
colorScheme={colorScheme}
|
|
445
472
|
workspaceContainer={effectiveContainer}
|
|
446
473
|
allowVersioning={allowVersioning}
|
|
447
474
|
versionBasename={versionBasename}
|
|
@@ -479,6 +506,7 @@ export function EditorShell({
|
|
|
479
506
|
toolbarSlotRight={toolbarSlotRight}
|
|
480
507
|
showPlayTab={showPlayTab}
|
|
481
508
|
submitOnEnter={submitOnEnter}
|
|
509
|
+
codeContext={codeContext}
|
|
482
510
|
fullWidth={fullWidth}
|
|
483
511
|
uxFont={uxFont}
|
|
484
512
|
thinMargins={thinMargins}
|
|
@@ -514,6 +542,7 @@ interface EditorShellInnerProps {
|
|
|
514
542
|
toolbarSlotRight?: ReactNode;
|
|
515
543
|
showPlayTab: boolean;
|
|
516
544
|
submitOnEnter?: () => void;
|
|
545
|
+
codeContext?: CodeContext;
|
|
517
546
|
fullWidth: boolean;
|
|
518
547
|
uxFont?: string;
|
|
519
548
|
thinMargins: boolean;
|
|
@@ -526,7 +555,7 @@ interface EditorShellInnerProps {
|
|
|
526
555
|
allowVersioning: boolean;
|
|
527
556
|
versioningAutoSaveIdleMs?: number;
|
|
528
557
|
inlinePreviewWidth: number;
|
|
529
|
-
outlineWidth
|
|
558
|
+
outlineWidth?: number;
|
|
530
559
|
themeOverride: Theme | null;
|
|
531
560
|
}
|
|
532
561
|
|
|
@@ -546,6 +575,7 @@ function EditorShellInner({
|
|
|
546
575
|
toolbarSlotRight,
|
|
547
576
|
showPlayTab,
|
|
548
577
|
submitOnEnter,
|
|
578
|
+
codeContext,
|
|
549
579
|
fullWidth,
|
|
550
580
|
uxFont,
|
|
551
581
|
thinMargins,
|
|
@@ -565,7 +595,7 @@ function EditorShellInner({
|
|
|
565
595
|
activeView,
|
|
566
596
|
markdownSource,
|
|
567
597
|
doc,
|
|
568
|
-
|
|
598
|
+
colorScheme,
|
|
569
599
|
editorMode,
|
|
570
600
|
insertAtCursor,
|
|
571
601
|
replaceAll,
|
|
@@ -575,14 +605,31 @@ function EditorShellInner({
|
|
|
575
605
|
inlinePreviewVisible,
|
|
576
606
|
statusBarVisible,
|
|
577
607
|
outlineVisible,
|
|
608
|
+
layoutMode,
|
|
609
|
+
blockCount,
|
|
610
|
+
activeBlockKey,
|
|
611
|
+
prevBlock,
|
|
612
|
+
nextBlock,
|
|
613
|
+
addBlock,
|
|
578
614
|
imageEditTarget,
|
|
579
615
|
closeImageEdit,
|
|
580
616
|
bumpMediaRevision,
|
|
581
617
|
} = useEditorContext();
|
|
618
|
+
// Dual-catalog custom themes (doc + browser library), mirroring how
|
|
619
|
+
// CustomTemplateProvider is fed. Wraps the preview subtree so the theme
|
|
620
|
+
// picker + designer can read/write both pools.
|
|
621
|
+
const { docThemes, onDocThemesChange } = useDocCustomThemes();
|
|
582
622
|
const isPreview = activeView === 'preview';
|
|
583
623
|
const isCodeMode = editorMode === 'code';
|
|
584
624
|
const isImageMode = editorMode === 'image';
|
|
585
625
|
const isMarkdownMode = editorMode === 'markdown';
|
|
626
|
+
// The block card (one block at a time) applies to the editing surfaces (raw /
|
|
627
|
+
// wysiwyg) in markdown mode — never to preview, code, or image. Both the
|
|
628
|
+
// block-at-a-time and timeline layouts scope the editor to a single block.
|
|
629
|
+
const isCardMode =
|
|
630
|
+
isMarkdownMode && (layoutMode === 'block' || layoutMode === 'timeline') && !isPreview;
|
|
631
|
+
// Timeline mode additionally shows the horizontal timeline track below.
|
|
632
|
+
const isTimelineMode = isMarkdownMode && layoutMode === 'timeline' && !isPreview;
|
|
586
633
|
const [showFiles, setShowFiles] = useState(false);
|
|
587
634
|
const [mediaRefreshKey, setMediaRefreshKey] = useState(0);
|
|
588
635
|
// Persistent fallback container for image-edit sidecars when the host
|
|
@@ -595,7 +642,7 @@ function EditorShellInner({
|
|
|
595
642
|
imageEditFallbackContainerRef.current = new MemoryContentContainer();
|
|
596
643
|
}
|
|
597
644
|
const imageEditFallbackContainer = imageEditFallbackContainerRef.current;
|
|
598
|
-
const isDark =
|
|
645
|
+
const isDark = colorScheme === 'dark';
|
|
599
646
|
|
|
600
647
|
const handleToggleFiles = useCallback(() => {
|
|
601
648
|
setShowFiles((prev) => !prev);
|
|
@@ -736,7 +783,7 @@ function EditorShellInner({
|
|
|
736
783
|
return (
|
|
737
784
|
<div
|
|
738
785
|
className={`squisq-editor-shell ${className || ''}`}
|
|
739
|
-
data-theme={
|
|
786
|
+
data-theme={colorScheme}
|
|
740
787
|
data-full-width={fullWidth ? 'true' : undefined}
|
|
741
788
|
data-thin-margins={thinMargins ? 'true' : undefined}
|
|
742
789
|
data-outline-visible={isMarkdownMode && outlineVisible ? 'true' : undefined}
|
|
@@ -750,145 +797,213 @@ function EditorShellInner({
|
|
|
750
797
|
// tabs, status bar) consume `--squisq-ux-font` as their
|
|
751
798
|
// `font-family`, falling back to the system stack when unset.
|
|
752
799
|
...(uxFont ? ({ '--squisq-ux-font': uxFont } as CSSProperties) : {}),
|
|
753
|
-
// Exposed so the toolbar's view-tabs section
|
|
754
|
-
//
|
|
755
|
-
// outline's right edge.
|
|
756
|
-
//
|
|
757
|
-
// `data-outline-visible` gate above keeps the
|
|
758
|
-
// scoped to the case where alignment matters.
|
|
759
|
-
...({
|
|
800
|
+
// Exposed so the toolbar's view-tabs section AND the outline pane read
|
|
801
|
+
// one shared width, lining up the view-tabs' right-edge separator with
|
|
802
|
+
// the outline's right edge. A fixed `outlineWidth` pins it to px;
|
|
803
|
+
// otherwise it's the responsive clamp so the pane stretches when
|
|
804
|
+
// there's room. The `data-outline-visible` gate above keeps the
|
|
805
|
+
// toolbar override scoped to the case where alignment matters.
|
|
806
|
+
...({
|
|
807
|
+
'--squisq-outline-width':
|
|
808
|
+
outlineWidth != null ? `${outlineWidth}px` : OUTLINE_RESPONSIVE_WIDTH,
|
|
809
|
+
} as CSSProperties),
|
|
760
810
|
}}
|
|
761
811
|
{...containerProps}
|
|
762
812
|
>
|
|
763
|
-
<
|
|
764
|
-
{
|
|
813
|
+
<CustomThemeProvider docThemes={docThemes} onDocThemesChange={onDocThemesChange}>
|
|
814
|
+
<PreviewSettingsProvider doc={doc} themeOverride={themeOverride}>
|
|
815
|
+
{/* Header. In image mode the full markdown/code Toolbar is replaced
|
|
765
816
|
with a minimal slot bar — view tabs, formatting, and preview
|
|
766
817
|
controls don't apply to a binary asset. */}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
818
|
+
{isImageMode ? (
|
|
819
|
+
(toolbarSlotLeft || toolbarSlotRight) && (
|
|
820
|
+
<div className="squisq-editor-header squisq-editor-header--image">
|
|
821
|
+
{toolbarSlotLeft}
|
|
822
|
+
<div style={{ flex: 1 }} />
|
|
823
|
+
{toolbarSlotRight}
|
|
824
|
+
</div>
|
|
825
|
+
)
|
|
826
|
+
) : (
|
|
827
|
+
<div className="squisq-editor-header">
|
|
828
|
+
<Toolbar
|
|
829
|
+
showFiles={showFiles}
|
|
830
|
+
onToggleFiles={!isCodeMode && filesToggleEnabled ? handleToggleFiles : undefined}
|
|
831
|
+
slotLeft={toolbarSlotLeft}
|
|
832
|
+
slotAfterTabs={
|
|
833
|
+
!isCodeMode &&
|
|
834
|
+
isPreview && (
|
|
835
|
+
<div className="squisq-preview-left-controls">
|
|
836
|
+
<PreviewModeSwitch />
|
|
837
|
+
<span className="squisq-preview-seg-divider" aria-hidden="true" />
|
|
838
|
+
<PreviewFormatSwitch />
|
|
839
|
+
</div>
|
|
840
|
+
)
|
|
841
|
+
}
|
|
842
|
+
slotAfterActions={
|
|
843
|
+
<>
|
|
844
|
+
{toolbarSlotAfterActions}
|
|
845
|
+
{!isCodeMode && isPreview && <PreviewToolbarControls />}
|
|
846
|
+
</>
|
|
847
|
+
}
|
|
848
|
+
slotRight={toolbarSlotRight}
|
|
849
|
+
showPlayTab={showPlayTab}
|
|
850
|
+
/>
|
|
773
851
|
</div>
|
|
774
|
-
)
|
|
775
|
-
) : (
|
|
776
|
-
<div className="squisq-editor-header">
|
|
777
|
-
<Toolbar
|
|
778
|
-
showFiles={showFiles}
|
|
779
|
-
onToggleFiles={!isCodeMode && filesToggleEnabled ? handleToggleFiles : undefined}
|
|
780
|
-
slotLeft={toolbarSlotLeft}
|
|
781
|
-
slotAfterActions={
|
|
782
|
-
<>
|
|
783
|
-
{toolbarSlotAfterActions}
|
|
784
|
-
{!isCodeMode && isPreview && <PreviewToolbarControls />}
|
|
785
|
-
</>
|
|
786
|
-
}
|
|
787
|
-
slotRight={toolbarSlotRight}
|
|
788
|
-
showPlayTab={showPlayTab}
|
|
789
|
-
/>
|
|
790
|
-
</div>
|
|
791
|
-
)}
|
|
852
|
+
)}
|
|
792
853
|
|
|
793
|
-
|
|
794
|
-
<div
|
|
795
|
-
className="squisq-editor-content"
|
|
796
|
-
style={{
|
|
797
|
-
flex: autoGrow ? '1 1 auto' : 1,
|
|
798
|
-
overflowY: autoGrow ? 'auto' : 'hidden',
|
|
799
|
-
overflowX: 'hidden',
|
|
800
|
-
minHeight: 0,
|
|
801
|
-
position: 'relative',
|
|
802
|
-
display: 'flex',
|
|
803
|
-
}}
|
|
804
|
-
>
|
|
854
|
+
{/* Main content area */}
|
|
805
855
|
<div
|
|
856
|
+
className="squisq-editor-content"
|
|
806
857
|
style={{
|
|
807
858
|
flex: autoGrow ? '1 1 auto' : 1,
|
|
808
|
-
|
|
859
|
+
overflowY: autoGrow ? 'auto' : 'hidden',
|
|
860
|
+
overflowX: 'hidden',
|
|
809
861
|
minHeight: 0,
|
|
810
862
|
position: 'relative',
|
|
863
|
+
display: 'flex',
|
|
811
864
|
}}
|
|
812
865
|
>
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
866
|
+
<div
|
|
867
|
+
style={{
|
|
868
|
+
flex: autoGrow ? '1 1 auto' : 1,
|
|
869
|
+
overflow: autoGrow ? 'visible' : 'hidden',
|
|
870
|
+
minHeight: 0,
|
|
871
|
+
position: 'relative',
|
|
872
|
+
}}
|
|
873
|
+
>
|
|
874
|
+
{isImageMode &&
|
|
875
|
+
imageSrc &&
|
|
876
|
+
(imageMode === 'edit' && imageEditorContainer ? (
|
|
877
|
+
<ImageEditor
|
|
878
|
+
filesContainer={imageEditorContainer}
|
|
879
|
+
initialSrc={imageSrc}
|
|
880
|
+
allowVersioning={allowVersioning}
|
|
881
|
+
versioningAutoSaveIdleMs={versioningAutoSaveIdleMs}
|
|
882
|
+
onExport={onImageExport}
|
|
883
|
+
/>
|
|
884
|
+
) : (
|
|
885
|
+
<ImageViewer src={imageSrc} alt={imageAlt} theme={colorScheme} />
|
|
886
|
+
))}
|
|
887
|
+
{/* Raw (Monaco) view. Always wrapped in `.squisq-editor-with-gutter`
|
|
827
888
|
so toggling a pane on/off doesn't change the editor's tree
|
|
828
889
|
position — Monaco stays mounted and `monacoEditor` in
|
|
829
890
|
context stays stable, which is what `useHeadingLayout` needs
|
|
830
891
|
to compute positions. */}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
892
|
+
{!isImageMode && activeView === 'raw' && (
|
|
893
|
+
<div className="squisq-editor-with-gutter" key="raw-shell">
|
|
894
|
+
{isMarkdownMode && outlineVisible && (
|
|
895
|
+
<OutlinePanel key="outline" width={outlineWidth} />
|
|
896
|
+
)}
|
|
897
|
+
{isCardMode ? (
|
|
898
|
+
<BlockCardView
|
|
899
|
+
key="raw-card"
|
|
900
|
+
blockCount={blockCount}
|
|
901
|
+
activeBlockKey={activeBlockKey}
|
|
902
|
+
onPrev={prevBlock}
|
|
903
|
+
onNext={nextBlock}
|
|
904
|
+
onAdd={addBlock}
|
|
905
|
+
>
|
|
906
|
+
<div key="raw-editor" className="squisq-raw-editor-container">
|
|
907
|
+
<RawEditor
|
|
908
|
+
monacoTheme={colorScheme === 'dark' ? 'vs-dark' : 'vs'}
|
|
909
|
+
submitOnEnter={submitOnEnter}
|
|
910
|
+
readOnly={readOnly}
|
|
911
|
+
/>
|
|
912
|
+
</div>
|
|
913
|
+
</BlockCardView>
|
|
914
|
+
) : (
|
|
915
|
+
<div key="raw-editor" className="squisq-raw-editor-container">
|
|
916
|
+
<RawEditor
|
|
917
|
+
monacoTheme={colorScheme === 'dark' ? 'vs-dark' : 'vs'}
|
|
918
|
+
submitOnEnter={submitOnEnter}
|
|
919
|
+
readOnly={readOnly}
|
|
920
|
+
/>
|
|
921
|
+
</div>
|
|
922
|
+
)}
|
|
923
|
+
{/* Renders nothing in normal flow — portals context
|
|
924
|
+
sections into Monaco view zones via the context's
|
|
925
|
+
monacoEditor. Code mode only. */}
|
|
926
|
+
{isCodeMode && codeContext && (
|
|
927
|
+
<CodeContextZones key="code-context" options={codeContext} />
|
|
928
|
+
)}
|
|
929
|
+
{isMarkdownMode && isCardMode && inlinePreviewVisible && (
|
|
930
|
+
<BlockPreviewPanel key="block-preview" basePath={basePath} />
|
|
931
|
+
)}
|
|
932
|
+
{isMarkdownMode && !isCardMode && inlinePreviewVisible && (
|
|
933
|
+
<InlinePreviewGutter
|
|
934
|
+
key="inline"
|
|
935
|
+
width={inlinePreviewWidth}
|
|
936
|
+
basePath={basePath}
|
|
937
|
+
mediaProvider={mediaProvider}
|
|
938
|
+
/>
|
|
939
|
+
)}
|
|
842
940
|
</div>
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
key="inline"
|
|
846
|
-
width={inlinePreviewWidth}
|
|
847
|
-
basePath={basePath}
|
|
848
|
-
mediaProvider={mediaProvider}
|
|
849
|
-
/>
|
|
850
|
-
)}
|
|
851
|
-
</div>
|
|
852
|
-
)}
|
|
853
|
-
{/* WYSIWYG + Preview are markdown-only surfaces — skip them
|
|
941
|
+
)}
|
|
942
|
+
{/* WYSIWYG + Preview are markdown-only surfaces — skip them
|
|
854
943
|
entirely in code or image mode so Tiptap never initializes
|
|
855
944
|
and the preview pipeline stays idle. Same always-wrapped
|
|
856
945
|
pattern as the Raw branch above so pane toggles don't
|
|
857
946
|
remount Tiptap. */}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
947
|
+
{isMarkdownMode && activeView === 'wysiwyg' && (
|
|
948
|
+
<div className="squisq-editor-with-gutter" key="wysiwyg-shell">
|
|
949
|
+
{outlineVisible && <OutlinePanel key="outline" width={outlineWidth} />}
|
|
950
|
+
{isCardMode ? (
|
|
951
|
+
<BlockCardView
|
|
952
|
+
key="wysiwyg-card"
|
|
953
|
+
blockCount={blockCount}
|
|
954
|
+
activeBlockKey={activeBlockKey}
|
|
955
|
+
onPrev={prevBlock}
|
|
956
|
+
onNext={nextBlock}
|
|
957
|
+
onAdd={addBlock}
|
|
958
|
+
>
|
|
959
|
+
<WysiwygEditor
|
|
960
|
+
key="wysiwyg-editor"
|
|
961
|
+
submitOnEnter={submitOnEnter}
|
|
962
|
+
placeholder={placeholder}
|
|
963
|
+
readOnly={readOnly}
|
|
964
|
+
/>
|
|
965
|
+
</BlockCardView>
|
|
966
|
+
) : (
|
|
967
|
+
<WysiwygEditor
|
|
968
|
+
key="wysiwyg-editor"
|
|
969
|
+
submitOnEnter={submitOnEnter}
|
|
970
|
+
placeholder={placeholder}
|
|
971
|
+
readOnly={readOnly}
|
|
972
|
+
/>
|
|
973
|
+
)}
|
|
974
|
+
{isCardMode && inlinePreviewVisible && (
|
|
975
|
+
<BlockPreviewPanel key="block-preview" basePath={basePath} />
|
|
976
|
+
)}
|
|
977
|
+
{!isCardMode && inlinePreviewVisible && (
|
|
978
|
+
<InlinePreviewGutter
|
|
979
|
+
key="inline"
|
|
980
|
+
width={inlinePreviewWidth}
|
|
981
|
+
basePath={basePath}
|
|
982
|
+
mediaProvider={mediaProvider}
|
|
983
|
+
/>
|
|
984
|
+
)}
|
|
985
|
+
</div>
|
|
986
|
+
)}
|
|
987
|
+
{isMarkdownMode && isPreview && (
|
|
988
|
+
<PreviewPanel basePath={basePath} workspaceContainer={workspaceContainer} />
|
|
989
|
+
)}
|
|
990
|
+
</div>
|
|
991
|
+
|
|
992
|
+
{isMarkdownMode && showFiles && (
|
|
993
|
+
<MediaBin
|
|
994
|
+
mediaProvider={mediaProvider}
|
|
995
|
+
isDark={isDark}
|
|
996
|
+
refreshKey={mediaRefreshKey}
|
|
997
|
+
onMediaUploaded={insertMediaRef}
|
|
998
|
+
/>
|
|
879
999
|
)}
|
|
880
|
-
</div>
|
|
881
1000
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
refreshKey={mediaRefreshKey}
|
|
887
|
-
onMediaUploaded={insertMediaRef}
|
|
888
|
-
/>
|
|
889
|
-
)}
|
|
1001
|
+
{/* Docked custom-theme designer — a flex sibling of the preview, so
|
|
1002
|
+
opening it reflows the preview narrower. Renders nothing when the
|
|
1003
|
+
designer is closed. */}
|
|
1004
|
+
{isMarkdownMode && <ThemeDesignerDock />}
|
|
890
1005
|
|
|
891
|
-
|
|
1006
|
+
{/* Drop zone overlay — image / text drop UX is markdown-specific.
|
|
892
1007
|
In WYSIWYG, image drops are handled directly by Tiptap's
|
|
893
1008
|
`handleDrop` (uploads to the MediaProvider and inserts an
|
|
894
1009
|
image node at the mouse position). The overlay would sit on
|
|
@@ -896,23 +1011,29 @@ function EditorShellInner({
|
|
|
896
1011
|
when the dragged content is media-only on the WYSIWYG view —
|
|
897
1012
|
the user gets a one-step "drop where you want it" flow
|
|
898
1013
|
instead of a two-step "drop in bin, then insert" flow. */}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1014
|
+
{isMarkdownMode &&
|
|
1015
|
+
isDragging &&
|
|
1016
|
+
!(activeView === 'wysiwyg' && dragContentType === 'media') && (
|
|
1017
|
+
<DropZoneOverlay
|
|
1018
|
+
dragContentType={dragContentType}
|
|
1019
|
+
zoneProps={zoneProps}
|
|
1020
|
+
hasMediaProvider={mediaProvider !== null}
|
|
1021
|
+
/>
|
|
1022
|
+
)}
|
|
1023
|
+
</div>
|
|
1024
|
+
|
|
1025
|
+
{/* Timeline track — horizontal strip of block + media bars shown
|
|
1026
|
+
below the editor in Timeline view. The card editor above (driven by
|
|
1027
|
+
the block navigator) shows whichever block is selected here. */}
|
|
1028
|
+
{isTimelineMode && <TimelineTrack />}
|
|
909
1029
|
|
|
910
|
-
|
|
1030
|
+
{/* Status bar — word / char / line / block counts. Host can
|
|
911
1031
|
suppress via `showStatusBar={false}` for embedded chat-style
|
|
912
1032
|
composers where the stats are noise. The image viewer has its
|
|
913
1033
|
own dimension/zoom status row, so suppress here too. */}
|
|
914
|
-
|
|
915
|
-
|
|
1034
|
+
{statusBarVisible && !isImageMode && <StatusBar />}
|
|
1035
|
+
</PreviewSettingsProvider>
|
|
1036
|
+
</CustomThemeProvider>
|
|
916
1037
|
<TooltipLayer />
|
|
917
1038
|
{imageEditTarget !== null && mediaProvider && (
|
|
918
1039
|
<ImageEditModal
|
|
@@ -926,7 +1047,7 @@ function EditorShellInner({
|
|
|
926
1047
|
}}
|
|
927
1048
|
allowVersioning={allowVersioning}
|
|
928
1049
|
versioningAutoSaveIdleMs={versioningAutoSaveIdleMs}
|
|
929
|
-
shellTheme={
|
|
1050
|
+
shellTheme={colorScheme}
|
|
930
1051
|
/>
|
|
931
1052
|
)}
|
|
932
1053
|
</div>
|
|
@@ -951,8 +1072,8 @@ interface ImageEditModalProps {
|
|
|
951
1072
|
onSaved: () => void;
|
|
952
1073
|
allowVersioning: boolean;
|
|
953
1074
|
versioningAutoSaveIdleMs?: number;
|
|
954
|
-
/** EditorShell's `
|
|
955
|
-
* the image editor chrome matches the host shell. */
|
|
1075
|
+
/** EditorShell's `colorScheme` prop — 'light' or 'dark'. Threaded through
|
|
1076
|
+
* so the image editor chrome matches the host shell. */
|
|
956
1077
|
shellTheme?: 'light' | 'dark';
|
|
957
1078
|
}
|
|
958
1079
|
|