@bendyline/squisq-editor-react 1.5.2 → 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 +16910 -6844
- 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 +216 -29
- 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 +61 -31
- 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 +17 -2
- 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 +105 -0
- package/src/useTimelineClock.ts +76 -0
- package/src/utils/dropUtils.ts +1 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CustomTemplateContext — exposes the merged set of doc-level + library
|
|
3
|
+
* custom templates to the rest of the editor (chiefly TemplatePicker
|
|
4
|
+
* and TemplateDesigner).
|
|
5
|
+
*
|
|
6
|
+
* The host wraps the editor in a provider, supplying:
|
|
7
|
+
* - `docTemplates`: the list currently sourced from the active doc's
|
|
8
|
+
* frontmatter (read from `Doc.customTemplates`).
|
|
9
|
+
* - `onDocTemplatesChange`: a callback the host uses to persist a
|
|
10
|
+
* change back into the doc (e.g. by updating the markdown source).
|
|
11
|
+
*
|
|
12
|
+
* Library templates come from `localStorage` via `library.ts` and are
|
|
13
|
+
* managed entirely within the context — the host doesn't see them.
|
|
14
|
+
*
|
|
15
|
+
* `applyTemplate(def)` is the bridge between the two pools: when a
|
|
16
|
+
* user picks a library template for a block, we copy its definition
|
|
17
|
+
* into the doc's customTemplates (if it isn't already there) so the
|
|
18
|
+
* doc remains self-sufficient for SSR / export. The block's annotation
|
|
19
|
+
* (`{[name]}`) is what actually selects the template at render time;
|
|
20
|
+
* this just ensures the registry merge has the definition.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
createContext,
|
|
25
|
+
useCallback,
|
|
26
|
+
useContext,
|
|
27
|
+
useEffect,
|
|
28
|
+
useMemo,
|
|
29
|
+
useState,
|
|
30
|
+
type ReactNode,
|
|
31
|
+
} from 'react';
|
|
32
|
+
import type { CustomTemplateDefinition } from '@bendyline/squisq/schemas';
|
|
33
|
+
import {
|
|
34
|
+
listLibraryTemplates,
|
|
35
|
+
saveLibraryTemplate as saveLibraryTemplateRaw,
|
|
36
|
+
deleteLibraryTemplate as deleteLibraryTemplateRaw,
|
|
37
|
+
} from './library';
|
|
38
|
+
|
|
39
|
+
export interface CustomTemplateContextValue {
|
|
40
|
+
/** Templates inlined into the current doc's frontmatter. */
|
|
41
|
+
docTemplates: CustomTemplateDefinition[];
|
|
42
|
+
/** Templates the user has saved to their browser-local library. */
|
|
43
|
+
libraryTemplates: CustomTemplateDefinition[];
|
|
44
|
+
/**
|
|
45
|
+
* Convenience: the union of doc + library, with library entries
|
|
46
|
+
* skipped when a doc template of the same name already exists.
|
|
47
|
+
* Used by the picker so a single "Custom" section covers both
|
|
48
|
+
* sources without duplicates.
|
|
49
|
+
*/
|
|
50
|
+
allTemplates: CustomTemplateDefinition[];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Persist a template into the current doc. Replaces any existing
|
|
54
|
+
* entry with the same `name`. Triggers the host's
|
|
55
|
+
* `onDocTemplatesChange` so the doc's frontmatter ends up updated.
|
|
56
|
+
*/
|
|
57
|
+
upsertDocTemplate: (def: CustomTemplateDefinition) => void;
|
|
58
|
+
/** Persist a template into the user's library (replaces by name). */
|
|
59
|
+
upsertLibraryTemplate: (def: CustomTemplateDefinition) => void;
|
|
60
|
+
/** Remove a doc-level template by name. */
|
|
61
|
+
removeDocTemplate: (name: string) => void;
|
|
62
|
+
/** Remove a library template by name. */
|
|
63
|
+
removeLibraryTemplate: (name: string) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Apply a template to the current doc. If the template is already in
|
|
66
|
+
* the doc, this is a no-op. If it's only in the library, it's
|
|
67
|
+
* copied into the doc so SSR / export work. Returns the resolved
|
|
68
|
+
* definition so callers can also write the heading annotation.
|
|
69
|
+
*/
|
|
70
|
+
applyTemplate: (def: CustomTemplateDefinition) => CustomTemplateDefinition;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const CustomTemplateContext = createContext<CustomTemplateContextValue | null>(null);
|
|
74
|
+
|
|
75
|
+
export interface CustomTemplateProviderProps {
|
|
76
|
+
/** The current doc's custom templates (from `Doc.customTemplates`). */
|
|
77
|
+
docTemplates: CustomTemplateDefinition[];
|
|
78
|
+
/**
|
|
79
|
+
* Callback the host uses to persist a new doc-template list back
|
|
80
|
+
* into the doc (e.g. by writing the encoded payload into the
|
|
81
|
+
* markdown's `squisq-custom-templates` frontmatter key).
|
|
82
|
+
*/
|
|
83
|
+
onDocTemplatesChange: (next: CustomTemplateDefinition[]) => void;
|
|
84
|
+
children: ReactNode;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function CustomTemplateProvider({
|
|
88
|
+
docTemplates,
|
|
89
|
+
onDocTemplatesChange,
|
|
90
|
+
children,
|
|
91
|
+
}: CustomTemplateProviderProps) {
|
|
92
|
+
const [libraryTemplates, setLibraryTemplates] = useState<CustomTemplateDefinition[]>(() =>
|
|
93
|
+
listLibraryTemplates(),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Re-read the library when this provider mounts so cross-tab edits
|
|
97
|
+
// (or initial first-paint quirks) are picked up. We don't subscribe
|
|
98
|
+
// to localStorage events in v1 — opening the picker re-renders and
|
|
99
|
+
// re-reads, which is enough for the single-tab common case.
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
setLibraryTemplates(listLibraryTemplates());
|
|
102
|
+
}, []);
|
|
103
|
+
|
|
104
|
+
const upsertDocTemplate = useCallback(
|
|
105
|
+
(def: CustomTemplateDefinition) => {
|
|
106
|
+
const existingIdx = docTemplates.findIndex((t) => t.name === def.name);
|
|
107
|
+
const next =
|
|
108
|
+
existingIdx >= 0
|
|
109
|
+
? docTemplates.map((t, i) => (i === existingIdx ? def : t))
|
|
110
|
+
: [...docTemplates, def];
|
|
111
|
+
onDocTemplatesChange(next);
|
|
112
|
+
},
|
|
113
|
+
[docTemplates, onDocTemplatesChange],
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const removeDocTemplate = useCallback(
|
|
117
|
+
(name: string) => {
|
|
118
|
+
const next = docTemplates.filter((t) => t.name !== name);
|
|
119
|
+
if (next.length !== docTemplates.length) onDocTemplatesChange(next);
|
|
120
|
+
},
|
|
121
|
+
[docTemplates, onDocTemplatesChange],
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const upsertLibraryTemplate = useCallback((def: CustomTemplateDefinition) => {
|
|
125
|
+
setLibraryTemplates(saveLibraryTemplateRaw(def));
|
|
126
|
+
}, []);
|
|
127
|
+
|
|
128
|
+
const removeLibraryTemplate = useCallback((name: string) => {
|
|
129
|
+
setLibraryTemplates(deleteLibraryTemplateRaw(name));
|
|
130
|
+
}, []);
|
|
131
|
+
|
|
132
|
+
const applyTemplate = useCallback(
|
|
133
|
+
(def: CustomTemplateDefinition) => {
|
|
134
|
+
// If the doc already has this template (matching name), leave
|
|
135
|
+
// both alone — the existing entry might be a customized copy.
|
|
136
|
+
const inDoc = docTemplates.find((t) => t.name === def.name);
|
|
137
|
+
if (!inDoc) upsertDocTemplate(def);
|
|
138
|
+
return inDoc ?? def;
|
|
139
|
+
},
|
|
140
|
+
[docTemplates, upsertDocTemplate],
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const allTemplates = useMemo(() => {
|
|
144
|
+
const seen = new Set(docTemplates.map((t) => t.name));
|
|
145
|
+
return [...docTemplates, ...libraryTemplates.filter((t) => !seen.has(t.name))];
|
|
146
|
+
}, [docTemplates, libraryTemplates]);
|
|
147
|
+
|
|
148
|
+
const value = useMemo<CustomTemplateContextValue>(
|
|
149
|
+
() => ({
|
|
150
|
+
docTemplates,
|
|
151
|
+
libraryTemplates,
|
|
152
|
+
allTemplates,
|
|
153
|
+
upsertDocTemplate,
|
|
154
|
+
upsertLibraryTemplate,
|
|
155
|
+
removeDocTemplate,
|
|
156
|
+
removeLibraryTemplate,
|
|
157
|
+
applyTemplate,
|
|
158
|
+
}),
|
|
159
|
+
[
|
|
160
|
+
docTemplates,
|
|
161
|
+
libraryTemplates,
|
|
162
|
+
allTemplates,
|
|
163
|
+
upsertDocTemplate,
|
|
164
|
+
upsertLibraryTemplate,
|
|
165
|
+
removeDocTemplate,
|
|
166
|
+
removeLibraryTemplate,
|
|
167
|
+
applyTemplate,
|
|
168
|
+
],
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
return <CustomTemplateContext.Provider value={value}>{children}</CustomTemplateContext.Provider>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Hook returning the current context. Returns null when no provider is
|
|
176
|
+
* mounted — callers can degrade to "no custom templates" rather than
|
|
177
|
+
* throwing, since the feature is optional.
|
|
178
|
+
*/
|
|
179
|
+
// eslint-disable-next-line react-refresh/only-export-components -- hook is co-located with its provider by design; splitting it into its own module would fragment the context API for no runtime benefit
|
|
180
|
+
export function useCustomTemplates(): CustomTemplateContextValue | null {
|
|
181
|
+
return useContext(CustomTemplateContext);
|
|
182
|
+
}
|