@bendyline/squisq-editor-react 1.6.1 → 2.0.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/README.md +12 -3
- package/dist/index.d.ts +1304 -208
- package/dist/index.js +22838 -14494
- package/dist/index.js.map +1 -1
- package/dist/monaco.d.ts +1 -0
- package/dist/monaco.js +4 -0
- package/dist/monaco.js.map +1 -0
- package/dist/styles/index.css +2384 -408
- package/package.json +9 -5
- package/src/BlockPropertiesPopover.tsx +48 -17
- package/src/DocumentSettingsDialog.tsx +13 -21
- package/src/EditorContext.tsx +199 -42
- package/src/EditorShell.tsx +403 -270
- package/src/ImageEditor.tsx +22 -1
- package/src/InlinePreviewGutter.tsx +16 -8
- package/src/MediaBin.tsx +276 -40
- package/src/OutlinePanel.tsx +202 -7
- package/src/PlainHtmlPreview.tsx +40 -1
- package/src/PreviewControls.tsx +466 -93
- package/src/PreviewPanel.tsx +313 -77
- package/src/RawEditor.tsx +13 -2
- package/src/StatusBar.tsx +5 -2
- package/src/TemplateAnnotation.ts +34 -10
- package/src/TemplateContentPreview.tsx +56 -0
- package/src/TemplatePicker.tsx +355 -134
- package/src/ThemeCustomizerPanel.tsx +30 -15
- package/src/ThemePicker.tsx +10 -5
- package/src/TimelineBlockPreview.tsx +1 -1
- package/src/Toolbar.tsx +719 -238
- package/src/TransitionPicker.tsx +44 -5
- package/src/ViewMenuPanel.tsx +12 -14
- package/src/ViewSwitcher.tsx +4 -4
- package/src/WysiwygEditor.tsx +167 -92
- package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +33 -0
- package/src/__tests__/blockTagActivity.test.ts +183 -0
- package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +75 -0
- package/src/__tests__/buildPreviewDocContent.test.ts +48 -0
- package/src/__tests__/buildPreviewDocTransition.test.ts +22 -3
- package/src/__tests__/canvasSurfaceTextEditing.test.tsx +60 -0
- package/src/__tests__/customLayoutManagerTheme.test.tsx +34 -0
- package/src/__tests__/documentSettingsDialog.test.tsx +29 -1
- package/src/__tests__/editorScrollHandoff.test.tsx +102 -0
- package/src/__tests__/editorScrollSync.test.ts +65 -0
- package/src/__tests__/editorShellProps.test.tsx +390 -1
- package/src/__tests__/emojiPicker.test.tsx +2 -42
- package/src/__tests__/headingTransition.test.ts +53 -15
- package/src/__tests__/imageEditAffordance.test.tsx +5 -1
- package/src/__tests__/imageEditModalContract.test.tsx +119 -0
- package/src/__tests__/imageEditorShell.test.tsx +38 -1
- package/src/__tests__/jsonEditor.test.tsx +56 -1
- package/src/__tests__/layersPanel.test.tsx +75 -5
- package/src/__tests__/majorApiTypes.test.ts +26 -0
- package/src/__tests__/mediaBinDrop.test.tsx +90 -0
- package/src/__tests__/mediaReferences.test.ts +82 -0
- package/src/__tests__/narrationSave.test.ts +148 -0
- package/src/__tests__/outlinePanel.test.tsx +93 -3
- package/src/__tests__/outlineSource.test.ts +217 -0
- package/src/__tests__/plainHtmlPreview.test.tsx +17 -1
- package/src/__tests__/presentationMode.test.tsx +290 -0
- package/src/__tests__/previewControls.test.tsx +312 -6
- package/src/__tests__/previewPanelAudioFailure.test.tsx +46 -0
- package/src/__tests__/previewPanelPresentation.test.tsx +126 -0
- package/src/__tests__/previewPanelTransforms.test.tsx +117 -0
- package/src/__tests__/rawEditorModelIsolation.test.ts +19 -0
- package/src/__tests__/resolveBlockVisual.test.ts +43 -0
- package/src/__tests__/statusBar.test.tsx +27 -0
- package/src/__tests__/teleprompter.test.tsx +190 -0
- package/src/__tests__/templateAnnotationRoundTrip.test.ts +49 -2
- package/src/__tests__/templateContentPreview.test.ts +101 -0
- package/src/__tests__/templatePickerPortal.test.tsx +62 -0
- package/src/__tests__/tiptapBridge.test.ts +70 -0
- package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +109 -0
- package/src/__tests__/transformStyleId.test.ts +13 -0
- package/src/__tests__/useImageEditor.test.tsx +67 -0
- package/src/__tests__/useMediaRecorder.test.ts +75 -0
- package/src/__tests__/viewMenuPanel.test.tsx +130 -0
- package/src/__tests__/wysiwygImageUpload.test.ts +69 -0
- package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +56 -0
- package/src/asciiDiagram/AsciiDiagramExtension.ts +343 -0
- package/src/asciiDiagram/AsciiDiagramWidget.tsx +224 -0
- package/src/asciiDiagram/RepairableDiagramExtension.ts +200 -0
- package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +145 -0
- package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +159 -0
- package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +227 -0
- package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +114 -0
- package/src/asciiDiagram/__tests__/asciiPaste.test.ts +43 -0
- package/src/asciiDiagram/asciiDiagramCommands.ts +148 -0
- package/src/asciiDiagram/asciiDiagramData.ts +116 -0
- package/src/asciiDiagram/asciiDiagramOps.ts +219 -0
- package/src/asciiDiagram/asciiPaste.ts +19 -0
- package/src/blockTagActivity.ts +233 -0
- package/src/buildDocumentPreviewMarkdown.ts +168 -0
- package/src/buildPreviewDoc.ts +19 -12
- package/src/customTemplates/CustomLayoutManager.tsx +3 -2
- package/src/customTemplates/CustomTemplateContext.tsx +6 -0
- package/src/customTemplates/TemplateDesigner.tsx +7 -4
- package/src/customTemplates/__tests__/library.test.ts +8 -0
- package/src/customTemplates/designer.css +158 -99
- package/src/customTemplates/library.ts +16 -3
- package/src/customThemes/CustomThemeContext.tsx +6 -0
- package/src/customThemes/CustomThemeDialog.tsx +35 -5
- package/src/customThemes/ImportThemeSection.tsx +178 -0
- package/src/customThemes/__tests__/customThemeLibrary.test.ts +9 -0
- package/src/customThemes/__tests__/importThemeSection.test.tsx +192 -0
- package/src/customThemes/customThemeLibrary.ts +7 -4
- package/src/customThemes/index.ts +7 -1
- package/src/customThemes/themeDraft.ts +23 -7
- package/src/diagram/DiagramCanvas.tsx +9 -4
- package/src/diagram/types.ts +35 -0
- package/src/editorScrollSync.ts +73 -0
- package/src/emojiData.ts +3 -23
- package/src/headingTransition.ts +85 -25
- package/src/imageEditor/CanvasSurface.tsx +29 -23
- package/src/imageEditor/LayersPanel.tsx +78 -3
- package/src/imageEditor/Toolbar.tsx +5 -1
- package/src/imageEditor/icons.tsx +4 -0
- package/src/imageEditor/image-editor.css +75 -0
- package/src/imageEditor/layers/SelectionHandles.tsx +1 -1
- package/src/imageEditor/useImageEditor.ts +71 -14
- package/src/index.ts +193 -20
- package/src/jsonEditor/JsonEditorContext.tsx +12 -6
- package/src/jsonEditor/RenderNode.tsx +24 -3
- package/src/jsonEditor/editors.tsx +86 -19
- package/src/mediaEntries.ts +12 -0
- package/src/mediaReferences.ts +299 -0
- package/src/monaco.ts +35 -0
- package/src/monacoWorkers.ts +89 -0
- package/src/outlineSource.ts +171 -0
- package/src/presentation/PresentationMode.tsx +596 -0
- package/src/rawEditorIsolation.ts +18 -0
- package/src/recorder/hooks/useMediaRecorder.ts +97 -53
- package/src/resolveBlockVisual.ts +10 -4
- package/src/scene/Scene.tsx +101 -25
- package/src/scene/SceneBlockExtension.ts +17 -10
- package/src/scene/SceneBlockWidget.tsx +11 -4
- package/src/scene/SceneSelection.tsx +19 -15
- package/src/scene/SceneSideToolbar.tsx +89 -0
- package/src/scene/SceneViewport.tsx +7 -3
- package/src/scene/ShapePalette.tsx +17 -2
- package/src/scene/__tests__/DiagramAdapter.test.ts +86 -0
- package/src/scene/__tests__/SceneBlockExtension.test.ts +33 -0
- package/src/scene/__tests__/sceneIsolation.test.tsx +93 -0
- package/src/scene/adapters/DiagramAdapter.ts +12 -101
- package/src/scene/commands/SceneCommand.ts +4 -1
- package/src/scene/index.ts +1 -6
- package/src/scene/layers/DiagramEdges.tsx +24 -9
- package/src/scene/layers/edgeGeometry.ts +31 -4
- package/src/scene/layers/nodeCard.tsx +27 -8
- package/src/scene/scene.css +145 -2
- package/src/scene/text/SceneTextOverlay.tsx +5 -5
- package/src/scene/text/sceneTextChannel.ts +26 -20
- package/src/scene/text/sceneTextConfig.ts +4 -0
- package/src/scene/tools/ConnectTool.ts +126 -28
- package/src/scene/tools/DrawingConnectTool.ts +86 -16
- package/src/scene/tools/SceneTool.ts +10 -0
- package/src/scene/tools/SelectTool.ts +34 -18
- package/src/scene/tools/ShapeTool.ts +2 -3
- package/src/styles/ascii-diagram.css +79 -0
- package/src/styles/ascii-timeline.css +499 -0
- package/src/styles/editor.css +1566 -219
- package/src/styles/index.css +3 -0
- package/src/styles/tree-view.css +139 -0
- package/src/teleprompter/TeleprompterControls.tsx +218 -0
- package/src/teleprompter/TeleprompterSelfView.tsx +22 -0
- package/src/teleprompter/TeleprompterSurface.tsx +267 -0
- package/src/teleprompter/TeleprompterView.tsx +338 -0
- package/src/teleprompter/canvasRenderer.ts +161 -0
- package/src/teleprompter/floatingWindow.ts +352 -0
- package/src/teleprompter/index.ts +61 -0
- package/src/teleprompter/pcmWorklet.ts +62 -0
- package/src/teleprompter/recording/insertPreamble.ts +80 -0
- package/src/teleprompter/recording/narrationSave.ts +134 -0
- package/src/teleprompter/recording/useNarrationRecorder.ts +367 -0
- package/src/teleprompter/scrollModel.ts +85 -0
- package/src/teleprompter/teleprompterTheme.ts +303 -0
- package/src/teleprompter/types.ts +38 -0
- package/src/teleprompter/useFloatingWindow.ts +74 -0
- package/src/teleprompter/useMicAnalysis.ts +211 -0
- package/src/teleprompter/useTeleprompter.ts +421 -0
- package/src/templateContentPreviewResolver.ts +360 -0
- package/src/timeline/TimelineEditorWidget.tsx +702 -0
- package/src/timeline/TimelineViewExtension.ts +252 -0
- package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +355 -0
- package/src/timeline/__tests__/TimelineViewExtension.test.ts +163 -0
- package/src/timeline/__tests__/timelineCommands.test.ts +327 -0
- package/src/timeline/__tests__/timelineOps.test.ts +222 -0
- package/src/timeline/__tests__/timelinePaste.test.ts +34 -0
- package/src/timeline/timelineCommands.ts +367 -0
- package/src/timeline/timelineData.ts +54 -0
- package/src/timeline/timelineOps.ts +277 -0
- package/src/timeline/timelinePaste.ts +8 -0
- package/src/tiptapBridge.ts +84 -49
- package/src/transformStyleId.ts +17 -0
- package/src/treeview/TreeOutlineWidget.tsx +240 -0
- package/src/treeview/TreeViewExtension.ts +250 -0
- package/src/treeview/__tests__/TreeViewExtension.test.ts +122 -0
- package/src/treeview/__tests__/treeOps.test.ts +125 -0
- package/src/treeview/__tests__/treePaste.test.ts +40 -0
- package/src/treeview/__tests__/treeViewCommands.test.ts +163 -0
- package/src/treeview/treeOps.ts +172 -0
- package/src/treeview/treePaste.ts +13 -0
- package/src/treeview/treeViewCommands.ts +94 -0
- package/src/treeview/treeViewData.ts +41 -0
- package/src/useMonacoLoader.ts +11 -34
- package/src/wysiwygImageUpload.ts +113 -0
- package/src/diagram/DiagramExtension.ts +0 -209
- package/src/diagram/DiagramWidget.tsx +0 -270
- package/src/diagram/useDiagramData.ts +0 -126
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bendyline/squisq-editor-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "React editor shell with raw/WYSIWYG/preview modes for Squisq documents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bendyline",
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"types": "./dist/index.d.ts",
|
|
35
35
|
"import": "./dist/index.js"
|
|
36
36
|
},
|
|
37
|
+
"./monaco": {
|
|
38
|
+
"types": "./dist/monaco.d.ts",
|
|
39
|
+
"import": "./dist/monaco.js"
|
|
40
|
+
},
|
|
37
41
|
"./styles": "./dist/styles/index.css"
|
|
38
42
|
},
|
|
39
43
|
"scripts": {
|
|
@@ -42,7 +46,7 @@
|
|
|
42
46
|
"typecheck": "tsc --noEmit"
|
|
43
47
|
},
|
|
44
48
|
"peerDependencies": {
|
|
45
|
-
"monaco-editor": "
|
|
49
|
+
"monaco-editor": ">=0.50.0",
|
|
46
50
|
"react": "^18.0.0 || ^19.0.0",
|
|
47
51
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
48
52
|
},
|
|
@@ -52,9 +56,9 @@
|
|
|
52
56
|
}
|
|
53
57
|
},
|
|
54
58
|
"dependencies": {
|
|
55
|
-
"@bendyline/squisq": "
|
|
56
|
-
"@bendyline/squisq-formats": "
|
|
57
|
-
"@bendyline/squisq-react": "
|
|
59
|
+
"@bendyline/squisq": "2.0.0",
|
|
60
|
+
"@bendyline/squisq-formats": "2.0.0",
|
|
61
|
+
"@bendyline/squisq-react": "2.0.0",
|
|
58
62
|
"@fortawesome/fontawesome-free": "7.2.0",
|
|
59
63
|
"@monaco-editor/react": "4.7.0",
|
|
60
64
|
"@tiptap/extension-image": "2.27.2",
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The on-canvas "block properties" palette — the sibling of the block-template
|
|
5
5
|
* badge. Anchored at the `.squisq-props-badge` chip on a heading, it edits the
|
|
6
|
-
* block's playback/animation metadata
|
|
7
|
-
* attribute block (`dataBlockAttrs`):
|
|
6
|
+
* block's playback/animation metadata:
|
|
8
7
|
*
|
|
9
|
-
* - Transition (type / direction / duration) —
|
|
10
|
-
* - Duration (`duration`) —
|
|
11
|
-
* - Start time (`startTime`) —
|
|
8
|
+
* - Transition (type / direction / duration) — stored in `{[…]}` params
|
|
9
|
+
* - Duration (`duration`) — stored in Pandoc `dataBlockAttrs`
|
|
10
|
+
* - Start time (`startTime`) — stored in Pandoc `dataBlockAttrs`
|
|
12
11
|
*
|
|
13
12
|
* The popover holds the `dataBlockAttrs` inner string as working state and
|
|
14
13
|
* re-derives each control from it, so successive edits compose. Every change
|
|
@@ -17,12 +16,12 @@
|
|
|
17
16
|
* `TemplateBadgePopover`.
|
|
18
17
|
*/
|
|
19
18
|
|
|
20
|
-
import { useEffect, useState } from 'react';
|
|
19
|
+
import { useEffect, useId, useRef, useState } from 'react';
|
|
21
20
|
import { createPortal } from 'react-dom';
|
|
22
21
|
import { TransitionPicker } from './TransitionPicker';
|
|
23
22
|
import {
|
|
24
23
|
readBlockAttrsTransition,
|
|
25
|
-
|
|
24
|
+
setHeadingAttrsTransition,
|
|
26
25
|
type TransitionFields,
|
|
27
26
|
} from './headingTransition';
|
|
28
27
|
import { readBlockAttrsValue, setBlockAttrsValue } from './blockProperties';
|
|
@@ -36,10 +35,18 @@ export interface BlockPropertiesPopoverProps {
|
|
|
36
35
|
templateParams: string | null;
|
|
37
36
|
/** Apply a new `dataBlockAttrs` inner to the heading (null clears it). */
|
|
38
37
|
onChange: (nextInner: string | null) => void;
|
|
38
|
+
/** Apply a paired `dataBlockAttrs` / `dataTemplateParams` transition rewrite. */
|
|
39
|
+
onAnnotationChange: (next: {
|
|
40
|
+
blockAttrsInner: string | null;
|
|
41
|
+
templateParams: string | null;
|
|
42
|
+
}) => void;
|
|
43
|
+
/** Editor surface scheme. Required explicitly because this popover is portaled to `<body>`. */
|
|
44
|
+
colorScheme?: 'light' | 'dark';
|
|
45
|
+
/** Active document-theme accent used for focus and selected-state highlights. */
|
|
46
|
+
accentColor?: string;
|
|
39
47
|
onClose: () => void;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
|
-
const PANEL_ID = 'squisq-block-props-portal';
|
|
43
50
|
/** The nested transition flyout is portaled out here; don't treat it as "outside". */
|
|
44
51
|
const TRANSITION_FLYOUT = '.squisq-transition-flyout';
|
|
45
52
|
|
|
@@ -48,14 +55,20 @@ export function BlockPropertiesPopover({
|
|
|
48
55
|
blockAttrs,
|
|
49
56
|
templateParams,
|
|
50
57
|
onChange,
|
|
58
|
+
onAnnotationChange,
|
|
59
|
+
colorScheme = 'light',
|
|
60
|
+
accentColor,
|
|
51
61
|
onClose,
|
|
52
62
|
}: BlockPropertiesPopoverProps) {
|
|
63
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
64
|
+
const panelId = `squisq-block-props-portal-${useId().replace(/:/g, '')}`;
|
|
53
65
|
// Working copy of the Pandoc inner; successive edits compose off it.
|
|
54
66
|
const [inner, setInner] = useState<string | null>(blockAttrs);
|
|
67
|
+
const [templateInner, setTemplateInner] = useState<string | null>(templateParams);
|
|
55
68
|
const [style, setStyle] = useState<React.CSSProperties>(() => computeStyle(anchorRect));
|
|
56
69
|
|
|
57
70
|
useEffect(() => {
|
|
58
|
-
requestAnimationFrame(() => setStyle(computeStyle(anchorRect)));
|
|
71
|
+
requestAnimationFrame(() => setStyle(computeStyle(anchorRect, panelRef.current)));
|
|
59
72
|
}, [anchorRect]);
|
|
60
73
|
|
|
61
74
|
// Outside click + Escape close. A click inside the popover OR inside the
|
|
@@ -66,7 +79,7 @@ export function BlockPropertiesPopover({
|
|
|
66
79
|
};
|
|
67
80
|
const onMouse = (e: MouseEvent) => {
|
|
68
81
|
const target = e.target as HTMLElement;
|
|
69
|
-
const inPanel =
|
|
82
|
+
const inPanel = panelRef.current?.contains(target);
|
|
70
83
|
const inFlyout = target.closest?.(TRANSITION_FLYOUT);
|
|
71
84
|
if (!inPanel && !inFlyout) onClose();
|
|
72
85
|
};
|
|
@@ -84,25 +97,37 @@ export function BlockPropertiesPopover({
|
|
|
84
97
|
onChange(next);
|
|
85
98
|
};
|
|
86
99
|
|
|
87
|
-
const transition = readBlockAttrsTransition(inner,
|
|
100
|
+
const transition = readBlockAttrsTransition(inner, templateInner);
|
|
88
101
|
const duration = readBlockAttrsValue(inner, 'duration');
|
|
89
102
|
const startTime = readBlockAttrsValue(inner, 'startTime');
|
|
90
103
|
|
|
91
|
-
const onTransition = (next: TransitionFields) =>
|
|
104
|
+
const onTransition = (next: TransitionFields) => {
|
|
105
|
+
const updated = setHeadingAttrsTransition(inner, templateInner, next);
|
|
106
|
+
setInner(updated.blockAttrsInner);
|
|
107
|
+
setTemplateInner(updated.templateParams);
|
|
108
|
+
onAnnotationChange(updated);
|
|
109
|
+
};
|
|
92
110
|
const onDuration = (v: string) => apply(setBlockAttrsValue(inner, 'duration', v));
|
|
93
111
|
const onStartTime = (v: string) => apply(setBlockAttrsValue(inner, 'startTime', v));
|
|
94
112
|
|
|
95
113
|
return createPortal(
|
|
96
114
|
<div
|
|
97
|
-
|
|
115
|
+
ref={panelRef}
|
|
116
|
+
id={panelId}
|
|
98
117
|
className="squisq-block-props-popover"
|
|
118
|
+
data-theme={colorScheme}
|
|
99
119
|
role="dialog"
|
|
100
120
|
aria-label="Block properties"
|
|
101
|
-
style={style}
|
|
121
|
+
style={{ ...style, ...blockAccentStyle(accentColor) }}
|
|
102
122
|
>
|
|
103
123
|
<div className="squisq-block-props-row">
|
|
104
124
|
<span className="squisq-block-props-label">Transition</span>
|
|
105
|
-
<TransitionPicker
|
|
125
|
+
<TransitionPicker
|
|
126
|
+
value={transition}
|
|
127
|
+
onChange={onTransition}
|
|
128
|
+
colorScheme={colorScheme}
|
|
129
|
+
accentColor={accentColor}
|
|
130
|
+
/>
|
|
106
131
|
</div>
|
|
107
132
|
|
|
108
133
|
<div className="squisq-block-props-row">
|
|
@@ -131,6 +156,12 @@ export function BlockPropertiesPopover({
|
|
|
131
156
|
);
|
|
132
157
|
}
|
|
133
158
|
|
|
159
|
+
function blockAccentStyle(accentColor: string | undefined): React.CSSProperties {
|
|
160
|
+
return accentColor
|
|
161
|
+
? ({ ['--squisq-block-props-accent' as string]: accentColor } as React.CSSProperties)
|
|
162
|
+
: {};
|
|
163
|
+
}
|
|
164
|
+
|
|
134
165
|
function NumberField({
|
|
135
166
|
value,
|
|
136
167
|
placeholder,
|
|
@@ -162,8 +193,8 @@ function NumberField({
|
|
|
162
193
|
}
|
|
163
194
|
|
|
164
195
|
/** Place the panel below the badge, flipping above / clamping to the viewport. */
|
|
165
|
-
function computeStyle(rect: DOMRect): React.CSSProperties {
|
|
166
|
-
const panel =
|
|
196
|
+
function computeStyle(rect: DOMRect, element?: HTMLElement | null): React.CSSProperties {
|
|
197
|
+
const panel = element?.getBoundingClientRect();
|
|
167
198
|
const width = panel?.width ?? 280;
|
|
168
199
|
const height = panel?.height ?? 160;
|
|
169
200
|
const margin = 8;
|
|
@@ -19,17 +19,19 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
19
19
|
import {
|
|
20
20
|
inferDocumentTitle,
|
|
21
21
|
parseMarkdown,
|
|
22
|
+
readFrontmatterThemeId,
|
|
22
23
|
setFrontmatterValues,
|
|
23
24
|
} from '@bendyline/squisq/markdown';
|
|
24
25
|
import { getTransformStyleSummaries } from '@bendyline/squisq/transform';
|
|
25
26
|
import { ThemePicker } from './ThemePicker';
|
|
27
|
+
import { resolvePersistedTransformStyleId } from './transformStyleId';
|
|
26
28
|
|
|
27
29
|
// ── Frontmatter key constants ─────────────────────────────────────
|
|
28
30
|
|
|
29
31
|
/** Mirror of `FM_KEYS` in PreviewControls.tsx. Canonical names are the
|
|
30
32
|
* ones we write; legacy aliases are still read so older docs work. */
|
|
31
33
|
const FM = {
|
|
32
|
-
theme: { canonical: 'squisq-theme', legacy: 'theme' },
|
|
34
|
+
theme: { canonical: 'squisq-theme', legacy: ['themeId', 'theme'] },
|
|
33
35
|
transform: { canonical: 'squisq-transform', legacy: 'transform-style' },
|
|
34
36
|
captions: { canonical: 'squisq-captions', legacy: 'caption-style' },
|
|
35
37
|
} as const;
|
|
@@ -75,8 +77,11 @@ export function DocumentSettingsDialog({
|
|
|
75
77
|
const inferredTitle = useMemo(() => inferDocumentTitle(parsed), [parsed]);
|
|
76
78
|
|
|
77
79
|
const currentTitle = typeof frontmatter?.title === 'string' ? (frontmatter.title as string) : '';
|
|
78
|
-
const currentTheme =
|
|
79
|
-
const currentTransform =
|
|
80
|
+
const currentTheme = readFrontmatterThemeId(frontmatter) ?? '';
|
|
81
|
+
const currentTransform =
|
|
82
|
+
resolvePersistedTransformStyleId(
|
|
83
|
+
readFm(frontmatter, FM.transform.canonical, FM.transform.legacy),
|
|
84
|
+
) ?? '';
|
|
80
85
|
const currentCaptions = readFm(frontmatter, FM.captions.canonical, FM.captions.legacy);
|
|
81
86
|
|
|
82
87
|
const [title, setTitle] = useState(currentTitle);
|
|
@@ -128,13 +133,11 @@ export function DocumentSettingsDialog({
|
|
|
128
133
|
const updates: Record<string, string | null> = {
|
|
129
134
|
title: nextTitle,
|
|
130
135
|
[FM.theme.canonical]: theme || null,
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
// Saving settings canonicalizes all older theme spellings.
|
|
137
|
+
[FM.theme.legacy[0]]: null,
|
|
138
|
+
[FM.theme.legacy[1]]: null,
|
|
134
139
|
[FM.transform.canonical]: transform || null,
|
|
135
|
-
|
|
136
|
-
? { [FM.transform.legacy]: null }
|
|
137
|
-
: {}),
|
|
140
|
+
[FM.transform.legacy]: null,
|
|
138
141
|
[FM.captions.canonical]: captions || null,
|
|
139
142
|
...(currentCaptions && captions !== currentCaptions ? { [FM.captions.legacy]: null } : {}),
|
|
140
143
|
};
|
|
@@ -142,18 +145,7 @@ export function DocumentSettingsDialog({
|
|
|
142
145
|
const nextSource = setFrontmatterValues(markdownSource, updates);
|
|
143
146
|
onSave(nextSource);
|
|
144
147
|
},
|
|
145
|
-
[
|
|
146
|
-
title,
|
|
147
|
-
theme,
|
|
148
|
-
transform,
|
|
149
|
-
captions,
|
|
150
|
-
inferredTitle,
|
|
151
|
-
markdownSource,
|
|
152
|
-
currentTheme,
|
|
153
|
-
currentTransform,
|
|
154
|
-
currentCaptions,
|
|
155
|
-
onSave,
|
|
156
|
-
],
|
|
148
|
+
[title, theme, transform, captions, inferredTitle, markdownSource, currentCaptions, onSave],
|
|
157
149
|
);
|
|
158
150
|
|
|
159
151
|
return (
|