@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.
Files changed (165) hide show
  1. package/dist/index.d.ts +757 -20
  2. package/dist/index.js +16910 -6844
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -4
  5. package/src/BlockCardView.tsx +121 -0
  6. package/src/BlockPreviewPanel.tsx +69 -0
  7. package/src/BlockPropertiesPopover.tsx +191 -0
  8. package/src/EditorContext.tsx +143 -0
  9. package/src/EditorShell.tsx +200 -120
  10. package/src/FolderView.tsx +131 -0
  11. package/src/Icon.tsx +26 -0
  12. package/src/ImageEditor.tsx +69 -22
  13. package/src/OutlinePanel.tsx +38 -3
  14. package/src/PlainHtmlPreview.tsx +30 -3
  15. package/src/PreviewControls.tsx +180 -8
  16. package/src/RawEditor.tsx +216 -29
  17. package/src/RecorderEntry.tsx +9 -16
  18. package/src/TemplateAnnotation.ts +44 -0
  19. package/src/TemplatePicker.tsx +329 -54
  20. package/src/ThemeCustomizerPanel.tsx +30 -336
  21. package/src/ThemePicker.tsx +112 -3
  22. package/src/TimelineBlockPreview.tsx +37 -0
  23. package/src/TimelineTrack.tsx +671 -0
  24. package/src/Toolbar.tsx +528 -174
  25. package/src/Tooltip.tsx +22 -4
  26. package/src/TransitionPicker.tsx +351 -0
  27. package/src/VersionHistoryPanel.tsx +61 -31
  28. package/src/ViewMenuPanel.tsx +17 -14
  29. package/src/WysiwygEditor.tsx +161 -65
  30. package/src/__tests__/blockProperties.test.ts +92 -0
  31. package/src/__tests__/blockRange.test.ts +105 -0
  32. package/src/__tests__/buildPreviewDocTransition.test.ts +73 -0
  33. package/src/__tests__/createShapeLayer.test.ts +46 -0
  34. package/src/__tests__/drawingShapeRoundTrip.test.ts +49 -0
  35. package/src/__tests__/embeddedMedia.test.ts +48 -0
  36. package/src/__tests__/headingTransition.test.ts +138 -0
  37. package/src/__tests__/layoutChildRoundTrip.test.ts +71 -0
  38. package/src/__tests__/plainHtmlPreview.test.tsx +10 -8
  39. package/src/__tests__/recorderMediaInsert.test.ts +86 -0
  40. package/src/__tests__/templateAnnotationRoundTrip.test.ts +18 -0
  41. package/src/__tests__/templatePickerMetadata.test.ts +32 -0
  42. package/src/__tests__/timelineSource.test.ts +134 -0
  43. package/src/__tests__/tiptapBridge.test.ts +92 -0
  44. package/src/__tests__/tiptapBridgeConformance.test.ts +47 -0
  45. package/src/__tests__/tooltip.test.tsx +72 -0
  46. package/src/__tests__/transitionCatalog.test.ts +64 -0
  47. package/src/__tests__/useBlockNavigator.test.tsx +67 -0
  48. package/src/__tests__/useMediaRecorder.test.ts +24 -0
  49. package/src/__tests__/useTimelineClock.test.ts +21 -0
  50. package/src/blockProperties.ts +88 -0
  51. package/src/blockRange.ts +132 -0
  52. package/src/buildPreviewDoc.ts +98 -9
  53. package/src/customTemplates/AddBin.tsx +126 -0
  54. package/src/customTemplates/CustomLayoutManager.tsx +233 -0
  55. package/src/customTemplates/CustomTemplateContext.tsx +182 -0
  56. package/src/customTemplates/LayerToolbar.tsx +580 -0
  57. package/src/customTemplates/ShapeGlyph.tsx +47 -0
  58. package/src/customTemplates/TemplateDesigner.tsx +430 -0
  59. package/src/customTemplates/__tests__/library.test.ts +88 -0
  60. package/src/customTemplates/__tests__/normalizePositions.test.ts +109 -0
  61. package/src/customTemplates/__tests__/shapeDefs.test.ts +49 -0
  62. package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +95 -0
  63. package/src/customTemplates/designer.css +673 -0
  64. package/src/customTemplates/index.ts +31 -0
  65. package/src/customTemplates/library.ts +97 -0
  66. package/src/customTemplates/normalizePositions.ts +75 -0
  67. package/src/customTemplates/shapeDefs.ts +131 -0
  68. package/src/customTemplates/thumbnail.tsx +63 -0
  69. package/src/customTemplates/tokenDefs.ts +60 -0
  70. package/src/customTemplates/useDocCustomTemplates.ts +52 -0
  71. package/src/customTemplates/useMemoryLayerAdapter.ts +123 -0
  72. package/src/customThemes/CustomThemeContext.tsx +179 -0
  73. package/src/customThemes/CustomThemeDialog.tsx +286 -0
  74. package/src/customThemes/__tests__/CustomThemeContext.test.tsx +64 -0
  75. package/src/customThemes/__tests__/CustomThemeDialog.test.tsx +47 -0
  76. package/src/customThemes/__tests__/customThemeLibrary.test.ts +51 -0
  77. package/src/customThemes/customThemeLibrary.ts +97 -0
  78. package/src/customThemes/index.ts +31 -0
  79. package/src/customThemes/themeControls.tsx +229 -0
  80. package/src/customThemes/themeDraft.ts +272 -0
  81. package/src/customThemes/useDocCustomThemes.ts +49 -0
  82. package/src/diagram/DiagramCanvas.tsx +240 -0
  83. package/src/diagram/DiagramExtension.ts +209 -0
  84. package/src/diagram/DiagramMaximizedOverlay.tsx +46 -0
  85. package/src/diagram/DiagramWidget.tsx +270 -0
  86. package/src/diagram/diagramCommands.ts +604 -0
  87. package/src/diagram/diagramConstants.ts +17 -0
  88. package/src/diagram/useDiagramData.ts +126 -0
  89. package/src/embeddedMedia.ts +78 -0
  90. package/src/frontmatter.ts +29 -0
  91. package/src/headingTransition.ts +231 -0
  92. package/src/imageEditor/CanvasSurface.tsx +383 -88
  93. package/src/imageEditor/PropertiesPanel.tsx +47 -1
  94. package/src/imageEditor/Toolbar.tsx +229 -16
  95. package/src/imageEditor/createShapeLayer.ts +280 -0
  96. package/src/imageEditor/icons.tsx +34 -114
  97. package/src/imageEditor/image-editor.css +54 -5
  98. package/src/imageEditor/state.ts +23 -3
  99. package/src/index.ts +77 -0
  100. package/src/recorder/RecorderModal.tsx +120 -53
  101. package/src/recorder/RecorderPanel.tsx +2 -26
  102. package/src/recorder/hooks/useMediaRecorder.ts +17 -2
  103. package/src/recorder/insertMediaBlock.ts +30 -0
  104. package/src/resolveBlockVisual.ts +33 -0
  105. package/src/scene/Scene.tsx +540 -0
  106. package/src/scene/SceneBlockExtension.ts +198 -0
  107. package/src/scene/SceneBlockToolbar.tsx +201 -0
  108. package/src/scene/SceneBlockWidget.tsx +434 -0
  109. package/src/scene/ScenePropsBar.tsx +85 -0
  110. package/src/scene/SceneSelection.tsx +107 -0
  111. package/src/scene/SceneViewport.tsx +102 -0
  112. package/src/scene/ShapePalette.tsx +181 -0
  113. package/src/scene/__tests__/DiagramAdapter.test.ts +56 -0
  114. package/src/scene/__tests__/bezierEdit.test.ts +85 -0
  115. package/src/scene/__tests__/blockLayers.test.ts +57 -0
  116. package/src/scene/__tests__/shapeLayers.test.ts +106 -0
  117. package/src/scene/__tests__/useSceneHitTest.test.ts +90 -0
  118. package/src/scene/__tests__/useScenePanZoom.test.ts +103 -0
  119. package/src/scene/adapters/DiagramAdapter.ts +168 -0
  120. package/src/scene/adapters/DrawingAdapter.ts +415 -0
  121. package/src/scene/adapters/LayoutAdapter.ts +310 -0
  122. package/src/scene/adapters/blockLayers.ts +159 -0
  123. package/src/scene/commands/SceneCommand.ts +70 -0
  124. package/src/scene/commands/drawingCommands.ts +318 -0
  125. package/src/scene/commands/layoutCommands.ts +301 -0
  126. package/src/scene/hooks/useSceneHitTest.ts +105 -0
  127. package/src/scene/hooks/useScenePanZoom.ts +147 -0
  128. package/src/scene/hooks/useSceneSelection.ts +62 -0
  129. package/src/scene/index.ts +95 -0
  130. package/src/scene/layers/DiagramEdges.tsx +127 -0
  131. package/src/scene/layers/edgeGeometry.ts +77 -0
  132. package/src/scene/layers/nodeCard.tsx +145 -0
  133. package/src/scene/layers/renderLayer.tsx +70 -0
  134. package/src/scene/layers/shapeLayers.ts +201 -0
  135. package/src/scene/paths/bezierEdit.ts +208 -0
  136. package/src/scene/scene.css +649 -0
  137. package/src/scene/text/SceneTextOverlay.tsx +161 -0
  138. package/src/scene/text/sceneTextChannel.ts +40 -0
  139. package/src/scene/text/sceneTextConfig.ts +27 -0
  140. package/src/scene/text/sceneTiptap.ts +36 -0
  141. package/src/scene/text/useSceneTextEditing.ts +39 -0
  142. package/src/scene/tools/ConnectTool.ts +111 -0
  143. package/src/scene/tools/DrawingConnectTool.ts +161 -0
  144. package/src/scene/tools/PathTool.ts +158 -0
  145. package/src/scene/tools/PlaceTool.ts +47 -0
  146. package/src/scene/tools/SceneTool.ts +75 -0
  147. package/src/scene/tools/SelectTool.ts +284 -0
  148. package/src/scene/tools/ShapeTool.ts +144 -0
  149. package/src/scene/tools/TextTool.ts +72 -0
  150. package/src/scene/tools/TokenTool.ts +95 -0
  151. package/src/scene/tools/createDrawShapeTool.ts +82 -0
  152. package/src/styles/diagram.css +183 -0
  153. package/src/styles/editor.css +1615 -203
  154. package/src/styles/folder-view.css +210 -0
  155. package/src/styles/image-edit-affordance.css +2 -2
  156. package/src/styles/index.css +4 -0
  157. package/src/timelineSource.ts +244 -0
  158. package/src/tiptapBridge.ts +115 -34
  159. package/src/tooltipPlacement.ts +13 -0
  160. package/src/transitionCatalog.ts +159 -0
  161. package/src/types/monaco-shims.d.ts +10 -0
  162. package/src/useBlockNavigator.ts +153 -0
  163. package/src/useMonacoLoader.ts +105 -0
  164. package/src/useTimelineClock.ts +76 -0
  165. package/src/utils/dropUtils.ts +1 -1
package/dist/index.d.ts CHANGED
@@ -1,19 +1,46 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, CSSProperties, RefObject } from 'react';
4
- import { Doc, MediaProvider, Theme, ViewportPreset, ViewportConfig, SurfaceScheme, ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';
5
- import { MarkdownDocument } from '@bendyline/squisq/markdown';
4
+ import { Doc, MediaProvider, Theme, ViewportPreset, ViewportConfig, CustomTemplateDefinition, SurfaceScheme, ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';
5
+ import { MarkdownDocument, HeadingAttributes } from '@bendyline/squisq/markdown';
6
6
  import { ContentContainer } from '@bendyline/squisq/storage';
7
7
  import { DocumentVersionManager, SaveVersionOptions, SaveVersionResult, PrunePolicy } from '@bendyline/squisq/versions';
8
8
  import * as _tiptap_core from '@tiptap/core';
9
- import { Editor } from '@tiptap/core';
9
+ import { Editor, Extension } from '@tiptap/core';
10
10
  import { editor } from 'monaco-editor';
11
11
  import { IconFamily } from '@bendyline/squisq/icons';
12
12
  import { DisplayMode, CaptionStyle } from '@bendyline/squisq-react';
13
13
  import * as _tiptap_extension_heading from '@tiptap/extension-heading';
14
+ import { Editor as Editor$1 } from '@tiptap/react';
15
+ import { Node } from '@tiptap/pm/model';
14
16
  import { SquisqAnnotatedSchema, JsonFormValidator, JsonFormValidationError } from '@bendyline/squisq/jsonForm';
15
17
  import { ImageEditExportFormat, ImageEditVersionManager } from '@bendyline/squisq/imageEdit';
16
18
 
19
+ /**
20
+ * Configuration a Scene host (diagram / drawing / layout widget) supplies
21
+ * so the shared inline text editor knows how to read and write the text of
22
+ * a given layer. The Scene owns the editing UI (overlay + positioning);
23
+ * the host owns persistence (markdown heading vs. layout JSON blob).
24
+ */
25
+ type SceneTextLevel = 'inline' | 'block' | 'rich';
26
+
27
+ /**
28
+ * sceneTextChannel — a module singleton that bridges the canvas's inline
29
+ * text editor (which renders in a **detached React root** created by the
30
+ * Diagram/SceneBlock ProseMirror extensions, outside `<EditorProvider>`)
31
+ * to the provider, so the top formatting toolbar can target it.
32
+ *
33
+ * The active textbox's `SceneTextOverlay` publishes its Tiptap editor here
34
+ * on focus and clears it on blur/unmount; `EditorProvider` subscribes and
35
+ * mirrors the handle into `activeSceneText`. Singleton because only one
36
+ * canvas textbox can be focused at a time.
37
+ */
38
+
39
+ interface SceneTextHandle {
40
+ editor: Editor;
41
+ level: SceneTextLevel;
42
+ }
43
+
17
44
  /** Monaco standalone code editor instance type */
18
45
  type MonacoEditor = editor.IStandaloneCodeEditor;
19
46
  /**
@@ -64,6 +91,15 @@ interface DocumentLinkCandidate {
64
91
  type DocumentLinkProvider = (query: string) => Promise<DocumentLinkCandidate[]>;
65
92
  type EditorView = 'raw' | 'wysiwyg' | 'preview';
66
93
  type EditorTheme = 'light' | 'dark';
94
+ /**
95
+ * Document layout mode. `'document'` shows the whole markdown document in
96
+ * the active view (the historical behavior). `'block'` is the
97
+ * block-at-a-time view — one heading-defined block on a card at a time,
98
+ * with the editor scoped to just that block. `'timeline'` is block mode plus
99
+ * a horizontal timeline track for editing block durations and media slices.
100
+ * See {@link useBlockNavigator}.
101
+ */
102
+ type LayoutMode = 'document' | 'block' | 'timeline';
67
103
  /**
68
104
  * How much of the active Squisq theme the WYSIWYG editing surface
69
105
  * mirrors. `'fonts'` is the historical default — body and heading
@@ -152,10 +188,47 @@ interface EditorState {
152
188
  * shell.
153
189
  */
154
190
  allowRecording: boolean;
191
+ /**
192
+ * Document layout mode. `'document'` (default) edits the whole document;
193
+ * `'block'` activates the block-at-a-time card view. Initialized from the
194
+ * EditorShell `layoutMode` prop; the View menu can toggle it at runtime.
195
+ */
196
+ layoutMode: LayoutMode;
197
+ /**
198
+ * The markdown the active text editor should bind to: the full source in
199
+ * `'document'` mode, or just the active block's slice in `'block'` mode.
200
+ * Editors read this instead of `markdownSource` so the same surfaces work
201
+ * in both layouts.
202
+ */
203
+ editorSource: string;
204
+ /** Number of navigable blocks (cards) in the current document. */
205
+ blockCount: number;
206
+ /** Index of the block currently shown on the card (block mode). */
207
+ activeBlockKey: number;
208
+ /** 1-based source line where the active block begins, or null. */
209
+ activeBlockStartLine: number | null;
155
210
  }
156
211
  interface EditorActions {
157
212
  /** Set markdown source and trigger re-parse */
158
213
  setMarkdownSource: (source: string) => void;
214
+ /**
215
+ * Write through the active editor channel. In `'document'` mode this is
216
+ * `setMarkdownSource`; in `'block'` mode it splices the edited block back
217
+ * into the full document. Editors call this instead of `setMarkdownSource`.
218
+ */
219
+ setEditorSource: (source: string) => void;
220
+ /** Switch between Document and Block-at-a-time layouts. */
221
+ setLayoutMode: (mode: LayoutMode) => void;
222
+ /** Show a block by index in block mode (clamped to range). */
223
+ goToBlock: (key: number) => void;
224
+ /** Show the block that owns a given 1-based source line (used by the outline). */
225
+ goToBlockByLine: (line: number) => void;
226
+ /** Move the card to the previous block. */
227
+ prevBlock: () => void;
228
+ /** Move the card to the next block. */
229
+ nextBlock: () => void;
230
+ /** Insert a new heading block after the active one and move to it. */
231
+ addBlock: () => void;
159
232
  /** Set markdown from a MarkdownDocument (e.g. from WYSIWYG) */
160
233
  setMarkdownDoc: (doc: MarkdownDocument) => void;
161
234
  /** Switch the active view */
@@ -201,6 +274,14 @@ interface EditorContextValue extends EditorState, EditorActions {
201
274
  tiptapEditor: Editor | null;
202
275
  /** The live Monaco editor instance (null when Raw is not mounted) */
203
276
  monacoEditor: MonacoEditor | null;
277
+ /**
278
+ * The focused canvas textbox editor, if any — a small Tiptap instance for
279
+ * a diagram/drawing/layout textbox being edited inline. Published via
280
+ * `sceneTextChannel` (the canvas renders in a detached React root). The
281
+ * top formatting toolbar retargets to this when set. `level` gates which
282
+ * buttons apply (`inline` = marks only; `rich` = headings/lists too).
283
+ */
284
+ activeSceneText: SceneTextHandle | null;
204
285
  /**
205
286
  * Workspace-scoped `ContentContainer` for this document — the folder
206
287
  * holding the doc, its `_files/` sidecar, sibling documents, and any
@@ -351,6 +432,12 @@ interface EditorProviderProps {
351
432
  * toolbar's View menu can change it at runtime.
352
433
  */
353
434
  themeInheritance?: ThemeInheritance;
435
+ /**
436
+ * Initial layout mode. Defaults to `'document'` (whole-document editing).
437
+ * `'block'` boots into the block-at-a-time card view. The toolbar's View
438
+ * menu can toggle it at runtime.
439
+ */
440
+ layoutMode?: LayoutMode;
354
441
  /**
355
442
  * Bundled view preferences — a serializable JSON blob covering all
356
443
  * runtime-toggleable view options. When provided, individual values
@@ -386,8 +473,10 @@ interface ViewPreferences {
386
473
  blockTags?: boolean;
387
474
  /** How much of the active Squisq theme the WYSIWYG surface mirrors. */
388
475
  themeInheritance?: ThemeInheritance;
476
+ /** Document vs. block-at-a-time layout. */
477
+ layoutMode?: LayoutMode;
389
478
  }
390
- declare function EditorProvider({ initialMarkdown, initialView, articleId, theme: initialTheme, workspaceContainer, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, mediaProvider, imageDisplayMode, mentionProvider, documentLinkProvider, allowRecording, fileName, language, inlinePreview, showStatusBar, outline, blockTags, themeInheritance, viewPreferences, onViewPreferencesChange, children, }: EditorProviderProps): react_jsx_runtime.JSX.Element;
479
+ declare function EditorProvider({ initialMarkdown, initialView, articleId, theme: initialTheme, workspaceContainer, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, mediaProvider, imageDisplayMode, mentionProvider, documentLinkProvider, allowRecording, fileName, language, inlinePreview, showStatusBar, outline, blockTags, themeInheritance, layoutMode, viewPreferences, onViewPreferencesChange, children, }: EditorProviderProps): react_jsx_runtime.JSX.Element;
391
480
 
392
481
  interface EditorShellProps {
393
482
  /** Initial markdown content */
@@ -704,6 +793,225 @@ interface EditorShellProps {
704
793
  */
705
794
  declare function EditorShell({ initialMarkdown, initialView, articleId, basePath, onChange, theme, className, height, minHeight, maxHeight, mediaProvider, workspaceContainer, container, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, showFilesToggle, toolbarSlotLeft, toolbarSlotAfterActions, toolbarSlotRight, showPlayTab, submitOnEnter, fullWidth, uxFont, thinMargins, showStatusBar, imageDisplayMode, fileName, language, mentionProvider, documentLinkProvider, allowRecording, placeholder, readOnly, imageSrc, imageAlt, imageMode, imageEditorContainer, onImageExport, inlinePreview, inlinePreviewWidth, outline, outlineWidth, blockTags, themeInheritance, viewPreferences, onViewPreferencesChange, themeOverride, }: EditorShellProps): react_jsx_runtime.JSX.Element;
706
795
 
796
+ /**
797
+ * One entry in a {@link FolderView} — a file or subfolder. Host-defined
798
+ * `path` is opaque to this component: it's used as the React key and
799
+ * handed back verbatim to the open callbacks so the host can resolve it.
800
+ */
801
+ interface FolderEntry {
802
+ /** Display name (basename). */
803
+ name: string;
804
+ /** Full host path. Opaque here; passed back on open. */
805
+ path: string;
806
+ isDirectory: boolean;
807
+ }
808
+ interface FolderViewProps {
809
+ /** Folder display name (basename) shown in the header. */
810
+ name: string;
811
+ /** Immediate children of the folder — subfolders and files. */
812
+ entries: FolderEntry[];
813
+ /** Open a file entry. The host decides what "open" means. */
814
+ onOpenFile: (entry: FolderEntry) => void;
815
+ /** Drill into a subfolder. */
816
+ onOpenFolder: (entry: FolderEntry) => void;
817
+ /** Primary action — create a new document in this folder. */
818
+ onNewDocument: () => void;
819
+ /** Secondary action — create a new subfolder. Omit to hide the button. */
820
+ onNewFolder?: () => void;
821
+ /** Color theme (default `'light'`). */
822
+ theme?: 'light' | 'dark';
823
+ /** CSS height for the container (default `'100%'`). */
824
+ height?: string;
825
+ /** Override the per-entry icon. Defaults to FontAwesome file/folder glyphs. */
826
+ iconFor?: (entry: FolderEntry) => ReactNode;
827
+ }
828
+ /**
829
+ * FolderView — a standalone folder browser surface.
830
+ *
831
+ * Lists a folder's files and subfolders plus a prominent "New document"
832
+ * action (and an optional "New folder"). It's the companion to
833
+ * {@link EditorShell}: where the shell edits a single document, this
834
+ * presents the directory around it.
835
+ *
836
+ * Like the shell, it's host-agnostic — the consumer supplies the
837
+ * `entries` and the open / new callbacks, and FolderView owns only the
838
+ * presentation and theming. It holds no state and reads nothing from
839
+ * disk, so it composes into any storage backend.
840
+ */
841
+ declare function FolderView({ name, entries, onOpenFile, onOpenFolder, onNewDocument, onNewFolder, theme, height, iconFor, }: FolderViewProps): react_jsx_runtime.JSX.Element;
842
+
843
+ /**
844
+ * useBlockNavigator
845
+ *
846
+ * Standalone hook powering the block-at-a-time editing view. Given a
847
+ * `(source, setSource)` pair it slices the markdown into blocks (via
848
+ * `blockRange.ts`), tracks which block is active, and exposes a derived
849
+ * **content channel** (`editorSource` / `setEditorSource`) plus navigation.
850
+ *
851
+ * It depends only on its arguments — no `EditorContext`, no `EditorShell` —
852
+ * so any host (an embedded single-block editor, a chat composer, a review
853
+ * surface) can drive a block-at-a-time UI by calling it directly.
854
+ *
855
+ * When `enabled` is false the channel is an identity passthrough: the editors
856
+ * see and write the full source exactly as before.
857
+ */
858
+ interface BlockNavigator {
859
+ /** What the bound editor should show: the active slice (block mode) or the full source. */
860
+ editorSource: string;
861
+ /** What the bound editor writes through: splices back into the full source (block mode). */
862
+ setEditorSource: (s: string) => void;
863
+ /** Number of navigable blocks in the current source. */
864
+ blockCount: number;
865
+ /** Index of the active block (clamped into range). */
866
+ activeBlockKey: number;
867
+ /** Jump to a block by index (clamped). */
868
+ goToBlock: (key: number) => void;
869
+ /**
870
+ * Select the block that owns a given 1-based source line — used by the
871
+ * outline, which knows a heading's source line but not its slice index
872
+ * (slice order includes the optional preamble, so it needn't match
873
+ * `flattenBlocks` order).
874
+ */
875
+ goToBlockByLine: (line: number) => void;
876
+ /** 1-based source line where the active block begins (for outline highlight). */
877
+ activeBlockStartLine: number | null;
878
+ /** Move to the previous block (no-op at the start). */
879
+ prevBlock: () => void;
880
+ /** Move to the next block (no-op at the end). */
881
+ nextBlock: () => void;
882
+ /** Insert a new heading-defined block after the active one and move to it. */
883
+ addBlock: () => void;
884
+ }
885
+ interface UseBlockNavigatorOptions {
886
+ /**
887
+ * When false (the default), the channel passes through to the full source
888
+ * and navigation is inert. Hosts flip this on to enter block-at-a-time mode.
889
+ */
890
+ enabled?: boolean;
891
+ }
892
+ declare function useBlockNavigator(source: string, setSource: (s: string) => void, opts?: UseBlockNavigatorOptions): BlockNavigator;
893
+
894
+ interface BlockCardViewProps {
895
+ /** Total number of navigable blocks. */
896
+ blockCount: number;
897
+ /** Index of the block currently shown (0-based). */
898
+ activeBlockKey: number;
899
+ /** Move to the previous block. */
900
+ onPrev: () => void;
901
+ /** Move to the next block. */
902
+ onNext: () => void;
903
+ /** Insert a new block after the current one. Omit to hide the affordance. */
904
+ onAdd?: () => void;
905
+ /** The editor surface (or any content) for the active block. */
906
+ children: ReactNode;
907
+ /** Optional extra class for the outer container. */
908
+ className?: string;
909
+ }
910
+ declare function BlockCardView({ blockCount, activeBlockKey, onPrev, onNext, onAdd, children, className, }: BlockCardViewProps): react_jsx_runtime.JSX.Element;
911
+
912
+ /**
913
+ * blockRange
914
+ *
915
+ * Source-text-range slicing for the block-at-a-time editing view. Splits a
916
+ * full markdown document into ordered, contiguous slices — one per
917
+ * heading-defined block plus an optional leading preamble — so a single
918
+ * block can be shown in isolation and edits spliced back into the parent.
919
+ *
920
+ * A block runs from its heading line through the character just before the
921
+ * next heading at ANY depth (or EOF). Sub-headings therefore start their own
922
+ * slices — they are NOT folded into their parent — which matches the
923
+ * "don't see child blocks" requirement and the `slicePastHeading` boundary
924
+ * in `blockSlice.ts`. Ranges are half-open `[startOffset, endOffset)` and
925
+ * line-aligned, so trailing blank lines stay with the current block and
926
+ * `spliceBlock(src, range, getBlockSlices(src)[i].text) === src` for every i.
927
+ *
928
+ * These are pure functions over a markdown string — no React, no editor
929
+ * coupling — so any host can reuse them.
930
+ */
931
+ /** Half-open character range into the full source: `[startOffset, endOffset)`. */
932
+ interface BlockRange {
933
+ startOffset: number;
934
+ endOffset: number;
935
+ }
936
+ /** One block's source text plus the range it occupies in the full document. */
937
+ interface BlockSlice {
938
+ text: string;
939
+ range: BlockRange;
940
+ }
941
+ /**
942
+ * Split `fullSource` into ordered block slices.
943
+ *
944
+ * - With no headings, the entire post-frontmatter body is a single slice
945
+ * (so an empty or heading-less document still shows one editable card).
946
+ * - With headings, a leading preamble slice is included only when the text
947
+ * before the first heading has non-whitespace content. Each heading then
948
+ * yields one slice spanning up to the next heading (any depth) or EOF.
949
+ *
950
+ * Frontmatter is never part of any slice — slices start at the body offset.
951
+ */
952
+ declare function getBlockSlices(fullSource: string): BlockSlice[];
953
+ /** Replace the text in `range` with `newText`, returning the new full source. */
954
+ declare function spliceBlock(fullSource: string, range: BlockRange, newText: string): string;
955
+ /** Character offset of the start of 1-based `line` (clamps past EOF). */
956
+ declare function lineToOffset(source: string, line: number): number;
957
+ /** 1-based line number containing `offset`. */
958
+ declare function offsetToLine(source: string, offset: number): number;
959
+ /** Index of the slice whose range contains `offset`, or -1. */
960
+ declare function sliceIndexAtOffset(slices: BlockSlice[], offset: number): number;
961
+
962
+ /**
963
+ * TimelineTrack
964
+ *
965
+ * Horizontal timeline strip for the Timeline view. Shows every block as a bar
966
+ * (width ∝ duration, x ∝ startTime) with its media clips as sub-bars below.
967
+ * Clicking a block selects it (the editor above follows). Dragging a block's
968
+ * right edge changes its duration; dragging its left edge changes the previous
969
+ * block's duration (the boundary, since startTime is derived). Dragging a media
970
+ * clip moves its `startAt`; dragging the clip's right edge changes its length;
971
+ * double-clicking a clip toggles `spillover`. All edits are written back to the
972
+ * markdown source via {@link timelineSource}.
973
+ */
974
+ interface TimelineTrackProps {
975
+ height?: number;
976
+ }
977
+ declare function TimelineTrack({ height }: TimelineTrackProps): react_jsx_runtime.JSX.Element | null;
978
+
979
+ /**
980
+ * timelineSource
981
+ *
982
+ * Line-level markdown rewrites for the timeline editor: set a block's
983
+ * `duration` on its heading's Pandoc attribute block, and patch a media
984
+ * clip's `startAt` / `clipStart` / `clipEnd` / `spillover` on its `{[audio …]}`
985
+ * / `{[video …]}` annotation line. Both preserve everything else on the line
986
+ * (template annotations, ids, classes, other params) by reusing the shared
987
+ * tokenizers rather than regex-replacing values.
988
+ */
989
+ /** Format a seconds value compactly: integers bare, else up to 2 decimals. */
990
+ declare function formatSeconds(seconds: number): string;
991
+ /**
992
+ * Set/insert a `duration` on the heading at 1-based `line`, written in the
993
+ * squisq-native squiggly form — `{[duration=<seconds>]}` on its own, or
994
+ * folded into an existing `{[template …]}` annotation. Preserves any `{#id}`,
995
+ * classes, and other Pandoc params, and migrates a legacy Pandoc
996
+ * `{duration=…}` to the squiggly form (dropping the stale Pandoc key so the
997
+ * two can't disagree). Returns the new full source, or null when the line
998
+ * isn't an ATX heading.
999
+ */
1000
+ declare function setBlockDurationInSource(source: string, line: number, seconds: number): string | null;
1001
+ /** A patch to a media clip; numeric values are seconds, `null` removes the key. */
1002
+ interface MediaClipPatch {
1003
+ startAt?: number | null;
1004
+ clipStart?: number | null;
1005
+ clipEnd?: number | null;
1006
+ spillover?: boolean | null;
1007
+ }
1008
+ /**
1009
+ * Patch the `{[audio …]}` / `{[video …]}` annotation at 1-based `line`.
1010
+ * Preserves the template name and any params not in the patch. Returns the
1011
+ * new full source, or null when the line isn't a media annotation.
1012
+ */
1013
+ declare function setMediaClipInSource(source: string, line: number, patch: MediaClipPatch): string | null;
1014
+
707
1015
  /**
708
1016
  * fileKind
709
1017
  *
@@ -994,16 +1302,6 @@ interface DocumentSettingsDialogProps {
994
1302
  }
995
1303
  declare function DocumentSettingsDialog({ markdownSource, onSave, onClose, }: DocumentSettingsDialogProps): react_jsx_runtime.JSX.Element;
996
1304
 
997
- /**
998
- * ThemePicker
999
- *
1000
- * Custom theme dropdown that replaces a plain `<select>` with a popover
1001
- * showing each theme as a card: the theme name rendered in the theme's
1002
- * own background / foreground / title font, plus three color swatches
1003
- * (primary, secondary, highlight). Used by both the play-mode preview
1004
- * toolbar and the Document Settings dialog so authors see a
1005
- * preview-on-hover style listing rather than a wall of names.
1006
- */
1007
1305
  interface ThemePickerProps {
1008
1306
  /** Currently selected theme id. Empty string represents "default". */
1009
1307
  value: string;
@@ -1024,8 +1322,23 @@ interface ThemePickerProps {
1024
1322
  variant?: 'compact' | 'full';
1025
1323
  /** Accessible label, e.g. "Theme". */
1026
1324
  ariaLabel?: string;
1325
+ /**
1326
+ * User-authored themes to list in a "Custom" group (doc + library, from
1327
+ * `useCustomThemes().allThemes`). When omitted, only built-ins show — so
1328
+ * the base-theme picker and other embeds stay built-ins only.
1329
+ */
1330
+ customThemes?: Theme[];
1331
+ /** When provided, renders a "+ Create custom theme" row that calls this. */
1332
+ onCreateCustom?: () => void;
1333
+ /** Per-custom-card edit affordance (opens the designer for that theme). */
1334
+ onEditCustom?: (id: string) => void;
1335
+ /** Per-custom-card delete affordance. */
1336
+ onDeleteCustom?: (id: string) => void;
1027
1337
  }
1028
- declare function ThemePicker({ value, onChange, includeDefault, variant, ariaLabel, }: ThemePickerProps): react_jsx_runtime.JSX.Element;
1338
+ declare function ThemePicker({ value, onChange, includeDefault, variant, ariaLabel, customThemes, onCreateCustom, onEditCustom, onDeleteCustom, }: ThemePickerProps): react_jsx_runtime.JSX.Element;
1339
+
1340
+ /** Where a saved theme lands — mirrors `DesignerSaveTarget` for templates. */
1341
+ type ThemeSaveTarget = 'doc' | 'library';
1029
1342
 
1030
1343
  interface PreviewSettings {
1031
1344
  activePreset: ViewportPreset;
@@ -1040,6 +1353,22 @@ interface PreviewSettings {
1040
1353
  setSelectedTransformStyle: (id: string | null) => void;
1041
1354
  activeCaptionStyle: CaptionStyle;
1042
1355
  setSelectedCaptionStyle: (style: CaptionStyle | null) => void;
1356
+ /** User-authored themes (doc + browser library) for the picker's "Custom" group. */
1357
+ customThemes: Theme[];
1358
+ /** Open the custom-theme designer for a theme (or null to create a new one). */
1359
+ openThemeDesigner: (theme: Theme | null) => void;
1360
+ /** Remove a custom theme from the doc and the library. */
1361
+ deleteCustomTheme: (id: string) => void;
1362
+ /** Config for the docked theme designer, or null when closed. Rendered by
1363
+ * `<ThemeDesignerDock>` in the editor's content row. */
1364
+ themeDesigner: ThemeDesignerConfig | null;
1365
+ }
1366
+ /** Everything `<ThemeDesignerDock>` needs to render the designer pane. */
1367
+ interface ThemeDesignerConfig {
1368
+ value: Theme | null;
1369
+ onChange: (theme: Theme) => void;
1370
+ onSave: (theme: Theme, target: ThemeSaveTarget) => void;
1371
+ onClose: () => void;
1043
1372
  }
1044
1373
  declare function usePreviewSettings(): PreviewSettings;
1045
1374
  interface PreviewSettingsProviderProps {
@@ -1164,7 +1493,7 @@ declare function ThemeCustomizerPanel({ value, onChange, onSave, onReset, }: The
1164
1493
  * so existing documents keep showing a friendly label without first
1165
1494
  * normalizing their annotations.
1166
1495
  */
1167
- declare function templateLabel(name: string): string;
1496
+ declare function templateLabel(name: string, customTemplates?: readonly CustomTemplateDefinition[]): string;
1168
1497
  interface TemplatePickerProps {
1169
1498
  value: string;
1170
1499
  onChange: (name: string) => void;
@@ -1176,8 +1505,192 @@ interface TemplatePickerProps {
1176
1505
  * single ungrouped grid (legacy behavior).
1177
1506
  */
1178
1507
  recommended?: readonly string[];
1508
+ /**
1509
+ * Optional callback fired when the user clicks the "+ New custom
1510
+ * template" card pinned at the top of the gallery. The host wires this
1511
+ * to open the modal `TemplateDesigner`. When omitted, the card is
1512
+ * hidden.
1513
+ */
1514
+ onOpenDesigner?: () => void;
1515
+ }
1516
+ declare function TemplatePicker({ value, onChange, compact, recommended, onOpenDesigner, }: TemplatePickerProps): react_jsx_runtime.JSX.Element;
1517
+
1518
+ /**
1519
+ * headingTransition
1520
+ *
1521
+ * Read and write a block's transition (`transition` / `transitionDirection` /
1522
+ * `transitionDuration`) on a heading, in both editing surfaces:
1523
+ *
1524
+ * - Markdown (Monaco): operate on the raw heading line string.
1525
+ * - WYSIWYG (Tiptap): operate on the heading node's `dataBlockAttrs` string
1526
+ * (the inner of the Pandoc `{…}` block, no braces — matching how
1527
+ * `tiptapBridge` stores and re-emits it).
1528
+ *
1529
+ * Transitions are stored in the Pandoc `{#id .class key=value}` attribute
1530
+ * block, NOT the `{[template …]}` annotation. That mirrors the canonical
1531
+ * serializer (`core/doc/docToMarkdown.ts` → `ensureTransitionAttributes`,
1532
+ * which always emits the `{…}` form) and `diagram/diagramCommands.ts`, so a
1533
+ * value set here round-trips through a Doc render without being duplicated
1534
+ * or moved. Reads still look at the `{[…]}` params too, so a hand-typed
1535
+ * `{[title transition=fade]}` shows up in the picker.
1536
+ *
1537
+ * All the brace-matching / tokenizing / serializing is delegated to the
1538
+ * shared core helpers so this stays in lockstep with the parser by import
1539
+ * rather than by copied regexes.
1540
+ */
1541
+ /** Raw (un-coerced) transition attribute values for one block. */
1542
+ interface TransitionFields {
1543
+ /** `transition` value. Empty string means "none" (`cut`). */
1544
+ type: string;
1545
+ /** `transitionDirection` value, or '' when unset. */
1546
+ direction: string;
1547
+ /** `transitionDuration` value (raw, e.g. `0.7` or `700ms`), or '' when unset. */
1548
+ duration: string;
1179
1549
  }
1180
- declare function TemplatePicker({ value, onChange, compact, recommended }: TemplatePickerProps): react_jsx_runtime.JSX.Element;
1550
+ declare const EMPTY_TRANSITION: TransitionFields;
1551
+ /**
1552
+ * Read the transition fields off a heading line. Looks in both the Pandoc
1553
+ * `{…}` block (canonical) and the `{[…]}` template params (hand-typed),
1554
+ * with the Pandoc block taking precedence. Returns the empty transition for
1555
+ * non-heading lines.
1556
+ */
1557
+ declare function readHeadingLineTransition(line: string): TransitionFields;
1558
+ /**
1559
+ * Return `line` with its transition rewritten from `next`, writing into the
1560
+ * Pandoc `{…}` block and leaving the `{[…]}` template annotation untouched.
1561
+ * Non-heading lines are returned unchanged.
1562
+ */
1563
+ declare function setHeadingLineTransition(line: string, next: TransitionFields): string;
1564
+ /**
1565
+ * Read the transition fields from a heading node's `dataBlockAttrs` (Pandoc
1566
+ * inner) plus `dataTemplateParams` (the `{[…]}` params). Pandoc wins.
1567
+ */
1568
+ declare function readBlockAttrsTransition(blockAttrsInner: string | null | undefined, templateParams: string | null | undefined): TransitionFields;
1569
+ /**
1570
+ * Rewrite the transition in a heading node's `dataBlockAttrs` inner string.
1571
+ * Returns the new inner (no braces), or null when the block carries no
1572
+ * attributes at all — matching how `tiptapBridge` stores `dataBlockAttrs`
1573
+ * (absent attribute → null, not `{}`).
1574
+ */
1575
+ declare function setBlockAttrsTransition(blockAttrsInner: string | null | undefined, next: TransitionFields): string | null;
1576
+
1577
+ interface TransitionPickerProps {
1578
+ value: TransitionFields;
1579
+ onChange: (next: TransitionFields) => void;
1580
+ }
1581
+ declare function TransitionPicker({ value, onChange }: TransitionPickerProps): react_jsx_runtime.JSX.Element;
1582
+
1583
+ /**
1584
+ * transitionCatalog
1585
+ *
1586
+ * Editor-facing, curated presentation of the block transition vocabulary.
1587
+ *
1588
+ * Core's `TRANSITION_TYPES` (packages/core/src/schemas/Transitions.ts) lists
1589
+ * ~80 names, including legacy aliases and near-duplicate spellings. This
1590
+ * catalog hand-picks the distinct, useful transitions, gives each a friendly
1591
+ * label, and groups them for the toolbar's transition flyout — the same
1592
+ * "core holds the truth, the editor holds the presentation" split the block
1593
+ * `TemplatePicker` uses.
1594
+ *
1595
+ * Every `value` here MUST be a real `TransitionType`; `transitionCatalog.test.ts`
1596
+ * enforces that so a renamed/removed core transition fails the build instead
1597
+ * of silently producing an invalid `transition=` annotation. The catalog is
1598
+ * intentionally NOT exhaustive — aliases and redundant spellings are omitted.
1599
+ */
1600
+ /**
1601
+ * How a transition takes a direction, driving which direction sub-control
1602
+ * the picker shows. Mirrors core's `getTransitionVisualClass` dispatch:
1603
+ * - `lrud`: left / right / up / down (push, wipe, cover, uncover, reveal, pan)
1604
+ * - `axis`: horizontal / vertical (split, blinds)
1605
+ * Entries without a model take no `transitionDirection`.
1606
+ */
1607
+ type DirectionModel = 'lrud' | 'axis';
1608
+ interface TransitionCatalogEntry {
1609
+ /** Canonical `transition=` value — must be a core `TransitionType`. */
1610
+ value: string;
1611
+ /** Friendly label shown in the flyout and trigger. */
1612
+ label: string;
1613
+ /** Direction model, when the transition is directional. */
1614
+ direction?: DirectionModel;
1615
+ }
1616
+ interface TransitionGroup {
1617
+ title: string;
1618
+ entries: TransitionCatalogEntry[];
1619
+ }
1620
+ declare const TRANSITION_GROUPS: readonly TransitionGroup[];
1621
+ /** Flat list of every catalog entry, in group order. */
1622
+ declare const TRANSITION_ENTRIES: readonly TransitionCatalogEntry[];
1623
+ /** Look up a catalog entry by its `transition=` value. */
1624
+ declare function findTransitionEntry(value: string): TransitionCatalogEntry | undefined;
1625
+ /**
1626
+ * Human label for a transition value. Returns 'None' for the empty value and
1627
+ * falls back to a camelCase-humanized form for any valid-but-uncurated type
1628
+ * (e.g. a hand-typed alias) so the trigger still reads sensibly.
1629
+ */
1630
+ declare function transitionLabel(value: string): string;
1631
+
1632
+ /**
1633
+ * blockProperties
1634
+ *
1635
+ * Generic read/write of a single block-meta key on a heading's Pandoc `{…}`
1636
+ * attribute block (stored as the `dataBlockAttrs` inner string in the WYSIWYG
1637
+ * heading node — no braces, matching `tiptapBridge`).
1638
+ *
1639
+ * The transition family (which spans three coupled keys) has its own helpers
1640
+ * in `headingTransition.ts`; this module covers the standalone scalar keys the
1641
+ * block-properties palette edits — `duration`, `startTime`, `x`, `y`, … — all
1642
+ * of which are plain `key=value` params. Parse/serialize is delegated to the
1643
+ * shared core helpers so quoting and ordering match the parser exactly.
1644
+ */
1645
+ /** Parse a `dataBlockAttrs` inner string into its flat `key → value` map. */
1646
+ declare function readBlockAttrsParams(inner: string | null | undefined): Record<string, string>;
1647
+ /** Read a single block-meta param, or '' when unset. */
1648
+ declare function readBlockAttrsValue(inner: string | null | undefined, key: string): string;
1649
+ /**
1650
+ * Set (or, when `value` is empty, remove) a single param in a `dataBlockAttrs`
1651
+ * inner string. Returns the new inner (no braces), or null when the block is
1652
+ * left with no attributes at all — matching how `tiptapBridge` stores an
1653
+ * absent attribute (null, not `{}`).
1654
+ */
1655
+ declare function setBlockAttrsValue(inner: string | null | undefined, key: string, value: string): string | null;
1656
+ /**
1657
+ * A concise, human-readable summary of a block's authored properties for the
1658
+ * on-canvas badge — e.g. `Doors · 1:30 start · 3:20 long`. Returns '' when no
1659
+ * properties are set (the badge then shows just its icon). Reads transition
1660
+ * from both the Pandoc block and the `{[…]}` params; timing from the block.
1661
+ */
1662
+ declare function summarizeBlockProps(blockAttrs: string | null | undefined, templateParams: string | null | undefined): string;
1663
+
1664
+ /**
1665
+ * BlockPropertiesPopover
1666
+ *
1667
+ * The on-canvas "block properties" palette — the sibling of the block-template
1668
+ * badge. Anchored at the `.squisq-props-badge` chip on a heading, it edits the
1669
+ * block's playback/animation metadata, all stored in the heading's Pandoc `{…}`
1670
+ * attribute block (`dataBlockAttrs`):
1671
+ *
1672
+ * - Transition (type / direction / duration) — reuses `TransitionPicker`
1673
+ * - Duration (`duration`) — how long the block is shown
1674
+ * - Start time (`startTime`) — timeline position
1675
+ *
1676
+ * The popover holds the `dataBlockAttrs` inner string as working state and
1677
+ * re-derives each control from it, so successive edits compose. Every change
1678
+ * serializes a new inner and bubbles up through `onChange`; the host applies it
1679
+ * to the heading node. Positioning/portal/outside-click mirror
1680
+ * `TemplateBadgePopover`.
1681
+ */
1682
+ interface BlockPropertiesPopoverProps {
1683
+ /** DOMRect of the badge that triggered the popover (viewport coords). */
1684
+ anchorRect: DOMRect;
1685
+ /** Current `dataBlockAttrs` inner (Pandoc), or null when unset. */
1686
+ blockAttrs: string | null;
1687
+ /** `dataTemplateParams`, so a hand-typed `{[… transition=]}` reads through. */
1688
+ templateParams: string | null;
1689
+ /** Apply a new `dataBlockAttrs` inner to the heading (null clears it). */
1690
+ onChange: (nextInner: string | null) => void;
1691
+ onClose: () => void;
1692
+ }
1693
+ declare function BlockPropertiesPopover({ anchorRect, blockAttrs, templateParams, onChange, onClose, }: BlockPropertiesPopoverProps): react.ReactPortal;
1181
1694
 
1182
1695
  interface InlinePreviewGutterProps {
1183
1696
  /** Width of the gutter in pixels (default: 320). */
@@ -1421,6 +1934,213 @@ declare function buildPreviewDoc(doc: Doc): Doc;
1421
1934
  */
1422
1935
  declare const HeadingWithTemplate: _tiptap_core.Node<_tiptap_extension_heading.HeadingOptions, any>;
1423
1936
 
1937
+ /**
1938
+ * DiagramExtension — Tiptap/ProseMirror plugin that:
1939
+ *
1940
+ * 1. Mounts a React-Flow canvas (`DiagramWidget`) immediately after every
1941
+ * heading whose `dataTemplate === 'diagram'`.
1942
+ * 2. Hides the direct sub-headings of each diagram parent (until the next
1943
+ * equal-or-shallower heading) by tagging them with a `data-squisq-diagram-child`
1944
+ * attribute — CSS in `styles/diagram.css` does the actual hiding.
1945
+ *
1946
+ * Widgets are rendered as plain DOM nodes attached to a ProseMirror
1947
+ * `Decoration.widget`. React is mounted into the widget DOM with
1948
+ * `react-dom/client`'s `createRoot`, and unmounted on the widget's
1949
+ * `destroy` hook.
1950
+ */
1951
+
1952
+ interface DiagramExtensionOptions {
1953
+ /** When false, the extension is inert (no widgets, no decorations). */
1954
+ enabled?: boolean;
1955
+ }
1956
+ declare const DiagramExtension: Extension<DiagramExtensionOptions, any>;
1957
+
1958
+ /**
1959
+ * Read diagram nodes + edges from the live Tiptap state.
1960
+ *
1961
+ * For a given parent heading position, walks the diagram section's child
1962
+ * headings, builds synthetic `Block` objects from their text + Pandoc
1963
+ * attributes, runs `computeDiagramLayout` from core to fill in missing
1964
+ * positions, and returns the result in the shape React Flow consumes.
1965
+ *
1966
+ * The hook re-derives on every editor transaction — no caching layer
1967
+ * means there's nothing to invalidate when the user types or the markdown
1968
+ * is reloaded from disk.
1969
+ */
1970
+
1971
+ interface DiagramRFNode {
1972
+ id: string;
1973
+ position: {
1974
+ x: number;
1975
+ y: number;
1976
+ };
1977
+ data: {
1978
+ label: string;
1979
+ };
1980
+ type?: string;
1981
+ /** Per-node width override (from the heading's `w=` Pandoc param). */
1982
+ width?: number;
1983
+ /** Per-node height override (from the heading's `h=` Pandoc param). */
1984
+ height?: number;
1985
+ }
1986
+ interface DiagramRFEdge {
1987
+ id: string;
1988
+ source: string;
1989
+ target: string;
1990
+ label?: string;
1991
+ }
1992
+ interface DiagramData {
1993
+ nodes: DiagramRFNode[];
1994
+ edges: DiagramRFEdge[];
1995
+ warnings: string[];
1996
+ }
1997
+ declare function useDiagramData(editor: Editor$1, parentPos: number): DiagramData;
1998
+
1999
+ type DiagramCommand = {
2000
+ kind: 'moveNode';
2001
+ nodeId: string;
2002
+ x: number;
2003
+ y: number;
2004
+ } | {
2005
+ kind: 'resizeNode';
2006
+ nodeId: string;
2007
+ width: number;
2008
+ height: number;
2009
+ } | {
2010
+ kind: 'addConnection';
2011
+ source: string;
2012
+ target: string;
2013
+ type?: string;
2014
+ } | {
2015
+ kind: 'removeConnection';
2016
+ source: string;
2017
+ target: string;
2018
+ type?: string;
2019
+ } | {
2020
+ kind: 'renameNode';
2021
+ nodeId: string;
2022
+ newLabel: string;
2023
+ } | {
2024
+ kind: 'addNode';
2025
+ x: number;
2026
+ y: number;
2027
+ } | {
2028
+ kind: 'removeNode';
2029
+ nodeId: string;
2030
+ };
2031
+ interface DiagramCanvasProps {
2032
+ nodes: DiagramRFNode[];
2033
+ edges: DiagramRFEdge[];
2034
+ onCommand: (cmd: DiagramCommand) => void;
2035
+ /** When true, render the maximize button. Click toggles `onToggleMaximize`. */
2036
+ showMaximize?: boolean;
2037
+ /** Whether the canvas is currently maximized (affects button icon). */
2038
+ maximized?: boolean;
2039
+ /** Callback when the maximize button is clicked. */
2040
+ onToggleMaximize?: () => void;
2041
+ /**
2042
+ * Active tool id, controlled by the host (DiagramWidget) so the tool
2043
+ * buttons can live in the shared toolbar above the canvas. Falls back
2044
+ * to internal state when omitted.
2045
+ */
2046
+ activeToolId?: string;
2047
+ onActiveToolIdChange?: (id: string) => void;
2048
+ /** Forwarded to the Scene so the host can drive a Delete action. */
2049
+ onSelectionChange?: (ids: ReadonlySet<string>) => void;
2050
+ }
2051
+ declare function DiagramCanvas({ nodes: incomingNodes, edges: incomingEdges, onCommand, showMaximize, maximized, onToggleMaximize, activeToolId: controlledToolId, onActiveToolIdChange, onSelectionChange, }: DiagramCanvasProps): react_jsx_runtime.JSX.Element;
2052
+
2053
+ interface DiagramWidgetProps {
2054
+ editor: Editor$1;
2055
+ /** Stable id derived from the parent heading (slug / `#id`). */
2056
+ headingKey: string;
2057
+ /** Position of the parent heading at widget-creation time. Used as a
2058
+ * fallback when the dynamic lookup fails (e.g. before the first
2059
+ * transaction). */
2060
+ fallbackParentPos: number;
2061
+ /** Host element used for portal targeting by the maximize overlay. */
2062
+ host?: HTMLElement | null;
2063
+ }
2064
+ declare function DiagramWidget({ editor, headingKey, fallbackParentPos, host }: DiagramWidgetProps): react_jsx_runtime.JSX.Element;
2065
+
2066
+ /**
2067
+ * Tiptap commands for diagram editing.
2068
+ *
2069
+ * Each command finds the relevant heading inside a diagram section (parent
2070
+ * heading + its direct sub-headings until the next equal-or-shallower
2071
+ * heading) and mutates either its `data-block-attrs` attribute or its
2072
+ * text content. All edits flow back into markdown via the existing
2073
+ * `tiptapBridge` round-trip — no parallel data store.
2074
+ */
2075
+
2076
+ interface HeadingLocation {
2077
+ /** Node start position in the doc (absolute). */
2078
+ pos: number;
2079
+ /** The heading PMNode. */
2080
+ node: Node;
2081
+ /** Parsed attributes derived from the heading's `data-block-attrs` (always defined). */
2082
+ attrs: HeadingAttributes;
2083
+ /** Computed id: explicit `#id` if set, otherwise the slugified heading text. */
2084
+ id: string;
2085
+ }
2086
+ /**
2087
+ * Find the diagram section that starts at `parentPos` (the position of the
2088
+ * parent heading with `dataTemplate === 'diagram'`). Returns the headings
2089
+ * that should appear as diagram nodes — defined as every heading at the
2090
+ * **shallowest** depth greater than the parent within the section, until
2091
+ * the next equal-or-shallower heading.
2092
+ *
2093
+ * Using the shallowest deeper depth (rather than a strict parentDepth + 1)
2094
+ * mirrors `markdownToDoc`'s stack behavior: when authors skip a level
2095
+ * (e.g. `# parent` + `### child`), those `###` headings are still treated
2096
+ * as direct children of the `#` parent. Any headings deeper than the
2097
+ * detected child depth are sub-sections of a node and are not surfaced as
2098
+ * separate diagram nodes.
2099
+ */
2100
+ declare function listDiagramChildren(editor: Editor$1, parentPos: number): HeadingLocation[];
2101
+ /**
2102
+ * Update a node's `x` / `y` attributes from a drag.
2103
+ *
2104
+ * Before writing the moved node, this also "freezes" any siblings that
2105
+ * lack an explicit position by snapshotting their currently-displayed
2106
+ * (auto-laid) coordinates. Without that, `computeDiagramLayout`'s grid
2107
+ * auto-placement is relative to the bounding box of pinned nodes — so
2108
+ * dragging one node would pull every unpinned sibling along behind it.
2109
+ * Freezing converts the implicit layout into explicit per-node
2110
+ * positions on the first interaction, after which each node moves
2111
+ * independently.
2112
+ */
2113
+ declare function moveNode(editor: Editor$1, parentPos: number, nodeId: string, x: number, y: number): boolean;
2114
+ /**
2115
+ * Add a connection from `sourceId` to `targetId` (optionally typed). No-op
2116
+ * if the same connection already exists.
2117
+ */
2118
+ declare function addConnection(editor: Editor$1, parentPos: number, sourceId: string, targetId: string, type?: string): boolean;
2119
+ /**
2120
+ * Remove a connection from `sourceId` to `targetId`. If `type` is provided,
2121
+ * only the matching-typed entry is removed; otherwise the first match
2122
+ * (regardless of type) is removed.
2123
+ */
2124
+ declare function removeConnection(editor: Editor$1, parentPos: number, sourceId: string, targetId: string, type?: string): boolean;
2125
+ /**
2126
+ * Replace a heading's text content (used when the user renames a node
2127
+ * via a double-click in the canvas).
2128
+ */
2129
+ declare function renameNode(editor: Editor$1, parentPos: number, nodeId: string, newText: string): boolean;
2130
+ /**
2131
+ * Insert a new heading node at the end of the diagram section. The new
2132
+ * heading carries `data-block-attrs` with the supplied id and position,
2133
+ * so the freshly-inserted node appears in React Flow at the expected
2134
+ * coordinates.
2135
+ */
2136
+ declare function addNode(editor: Editor$1, parentPos: number, id: string, label: string, x: number, y: number): boolean;
2137
+ /**
2138
+ * Remove a child node's heading (and any body content under it up to the
2139
+ * next heading). Also strips inbound `connectsTo` references on remaining
2140
+ * siblings so the diagram doesn't carry dangling targets.
2141
+ */
2142
+ declare function removeNode(editor: Editor$1, parentPos: number, nodeId: string): boolean;
2143
+
1424
2144
  interface JsonEditorProps {
1425
2145
  /** Schema describing the value's shape (with optional `squisq` hints). */
1426
2146
  schema: SquisqAnnotatedSchema;
@@ -1535,6 +2255,13 @@ interface UseMediaRecorderOptions {
1535
2255
  * only); when unsupported the resulting stream simply omits it.
1536
2256
  */
1537
2257
  systemAudio?: boolean;
2258
+ /**
2259
+ * For `source === 'camera'`, whether to include the microphone track.
2260
+ * Defaults to `true` (camera + mic). Set `false` to capture silent
2261
+ * video. Ignored for other sources, whose mic handling is encoded in
2262
+ * the source itself (`'mic'`, `'screen+mic'`).
2263
+ */
2264
+ includeMicrophone?: boolean;
1538
2265
  }
1539
2266
  interface UseMediaRecorderResult {
1540
2267
  /** Current recorder state. */
@@ -1876,16 +2603,17 @@ declare function ImageEditor(props: ImageEditorProps): react_jsx_runtime.JSX.Ele
1876
2603
  * version manager) lives in `useImageEditor.ts`.
1877
2604
  */
1878
2605
 
2606
+ type DOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
1879
2607
  /**
1880
2608
  * Layer payload accepted by the `add-layer` action — the `id` field is
1881
2609
  * optional and will be assigned by the underlying `addLayer` helper if
1882
2610
  * the caller doesn't supply one.
1883
2611
  */
1884
- type ImageEditLayerInput = ImageEditLayer | (Omit<ImageEditLayer, 'id'> & {
2612
+ type ImageEditLayerInput = ImageEditLayer | (DOmit<ImageEditLayer, 'id'> & {
1885
2613
  id?: string;
1886
2614
  });
1887
2615
  /** The currently active interaction tool. */
1888
- type ImageEditorTool = 'select' | 'text' | 'shape' | 'image' | 'crop';
2616
+ type ImageEditorTool = 'select' | 'text' | 'shape' | 'image' | 'crop' | 'zoom-rect';
1889
2617
  /** A pixel-space rectangle in canvas coordinates. */
1890
2618
  interface CanvasRect {
1891
2619
  x: number;
@@ -1900,6 +2628,12 @@ interface ImageEditorState {
1900
2628
  selectedLayerId: string | null;
1901
2629
  /** Active tool. */
1902
2630
  tool: ImageEditorTool;
2631
+ /**
2632
+ * The shape kind the shape tool will drop next (a drawing palette kind,
2633
+ * e.g. `'rectangle'`, `'diamond'`, `'arrow-right'`). Set when the user
2634
+ * picks from the shape palette; defaults to `'rectangle'`.
2635
+ */
2636
+ shapeKind: string;
1903
2637
  /**
1904
2638
  * Dirty flag — true when the in-memory doc has unsaved changes
1905
2639
  * relative to the last `markClean()` call. The hook uses this to
@@ -1915,6 +2649,9 @@ type ImageEditorAction = {
1915
2649
  } | {
1916
2650
  type: 'set-tool';
1917
2651
  tool: ImageEditorTool;
2652
+ } | {
2653
+ type: 'set-shape-kind';
2654
+ kind: string;
1918
2655
  } | {
1919
2656
  type: 'select';
1920
2657
  layerId: string | null;
@@ -1995,4 +2732,4 @@ interface UseImageEditorReturn {
1995
2732
  }
1996
2733
  declare function useImageEditor(options: UseImageEditorOptions): UseImageEditorReturn;
1997
2734
 
1998
- export { ALL_EMOJIS, type CameraStreamOptions, type CanvasRect, type CaptureKind, type DocumentLinkCandidate, type DocumentLinkProvider, DocumentSettingsDialog, type DocumentSettingsDialogProps, type DragContentType, type DropTarget, DropZoneOverlay, type DropZoneOverlayProps, EMOJI_CATEGORIES, type EditorActions, type EditorContextValue, type EditorMode, EditorProvider, type EditorProviderProps, EditorShell, type EditorShellProps, type EditorState, type EditorTheme, type EditorView, type EmojiCategory, type EmojiEntry, EmojiPicker, type EmojiPickerProps, type FileCategory, type FileKind, HeadingWithTemplate, type ImageDisplayMode, ImageEditor, type ImageEditorAction, type ImageEditorProps, type ImageEditorState, type ImageEditorTool, ImageViewer, type ImageViewerProps, InlinePreviewGutter, type InlinePreviewGutterProps, JsonEditor, type JsonEditorProps, MediaBin, type MediaBinProps, type MentionCandidate, type MentionProvider, OutlinePanel, type OutlinePanelProps, PlainHtmlPreview, type PlainHtmlPreviewProps, PreviewPanel, type PreviewPanelProps, type PreviewSettings, PreviewSettingsProvider, PreviewToolbarControls, RawEditor, type RawEditorProps, type RecordedBookmark, RecorderButton, type RecorderButtonProps, RecorderModal, type RecorderModalProps, RecorderPanel, type RecorderPanelProps, type RecorderSaveResult, type RecorderSource, type RecorderState, type ResolvedFormat, type ScreenStreamHandle, type ScreenStreamOptions, StatusBar, type StatusBarProps, TemplatePicker, ThemeCustomizerPanel, type ThemeCustomizerPanelProps, type ThemeInheritance, ThemePicker, type ThemePickerProps, type TimingJson, Toolbar, type ToolbarProps, TooltipLayer, type UseFileDropOptions, type UseFileDropResult, type UseImageEditorOptions, type UseImageEditorReturn, type UseMediaRecorderOptions, type UseMediaRecorderResult, VersionHistoryPanel, ViewMenuPanel, type ViewPreferences, ViewSwitcher, type ViewSwitcherProps, WysiwygEditor, type WysiwygEditorProps, buildFilename, buildPreviewDoc, buildTimingJson, classifyFile, detectLanguageFromFileName, encodeTimingJson, getCaptureKind, imageEditorReducer, initialImageEditorState, markdownToTiptap, partitionFiles, processMediaFiles, processTextFile, processTextFiles, requestCameraStream, requestMicStream, requestScreenStream, resolveFileKind, resolveFormat, searchEmojis, supportsDisplayMedia, supportsMediaRecorder, supportsUserMedia, templateLabel, timingPathFor, tiptapToMarkdown, useEditorContext, useFileDrop, useImageEditor, useMediaRecorder, usePreviewSettings, useStreamPreview };
2735
+ export { ALL_EMOJIS, BlockCardView, type BlockCardViewProps, type BlockNavigator, BlockPropertiesPopover, type BlockPropertiesPopoverProps, type BlockRange, type BlockSlice, type CameraStreamOptions, type CanvasRect, type CaptureKind, DiagramCanvas, type DiagramCommand, type DiagramData, DiagramExtension, type DiagramRFEdge, type DiagramRFNode, DiagramWidget, type DirectionModel, type DocumentLinkCandidate, type DocumentLinkProvider, DocumentSettingsDialog, type DocumentSettingsDialogProps, type DragContentType, type DropTarget, DropZoneOverlay, type DropZoneOverlayProps, EMOJI_CATEGORIES, EMPTY_TRANSITION, type EditorActions, type EditorContextValue, type EditorMode, EditorProvider, type EditorProviderProps, EditorShell, type EditorShellProps, type EditorState, type EditorTheme, type EditorView, type EmojiCategory, type EmojiEntry, EmojiPicker, type EmojiPickerProps, type FileCategory, type FileKind, type FolderEntry, FolderView, type FolderViewProps, HeadingWithTemplate, type ImageDisplayMode, ImageEditor, type ImageEditorAction, type ImageEditorProps, type ImageEditorState, type ImageEditorTool, ImageViewer, type ImageViewerProps, InlinePreviewGutter, type InlinePreviewGutterProps, JsonEditor, type JsonEditorProps, type LayoutMode, MediaBin, type MediaBinProps, type MediaClipPatch, type MentionCandidate, type MentionProvider, OutlinePanel, type OutlinePanelProps, PlainHtmlPreview, type PlainHtmlPreviewProps, PreviewPanel, type PreviewPanelProps, type PreviewSettings, PreviewSettingsProvider, PreviewToolbarControls, RawEditor, type RawEditorProps, type RecordedBookmark, RecorderButton, type RecorderButtonProps, RecorderModal, type RecorderModalProps, RecorderPanel, type RecorderPanelProps, type RecorderSaveResult, type RecorderSource, type RecorderState, type ResolvedFormat, type ScreenStreamHandle, type ScreenStreamOptions, StatusBar, type StatusBarProps, TRANSITION_ENTRIES, TRANSITION_GROUPS, TemplatePicker, ThemeCustomizerPanel, type ThemeCustomizerPanelProps, type ThemeInheritance, ThemePicker, type ThemePickerProps, TimelineTrack, type TimelineTrackProps, type TimingJson, Toolbar, type ToolbarProps, TooltipLayer, type TransitionCatalogEntry, type TransitionFields, type TransitionGroup, TransitionPicker, type TransitionPickerProps, type UseBlockNavigatorOptions, type UseFileDropOptions, type UseFileDropResult, type UseImageEditorOptions, type UseImageEditorReturn, type UseMediaRecorderOptions, type UseMediaRecorderResult, VersionHistoryPanel, ViewMenuPanel, type ViewPreferences, ViewSwitcher, type ViewSwitcherProps, WysiwygEditor, type WysiwygEditorProps, addConnection, addNode, buildFilename, buildPreviewDoc, buildTimingJson, classifyFile, detectLanguageFromFileName, encodeTimingJson, findTransitionEntry, formatSeconds, getBlockSlices, getCaptureKind, imageEditorReducer, initialImageEditorState, lineToOffset, listDiagramChildren, markdownToTiptap, moveNode, offsetToLine, partitionFiles, processMediaFiles, processTextFile, processTextFiles, readBlockAttrsParams, readBlockAttrsTransition, readBlockAttrsValue, readHeadingLineTransition, removeConnection, removeNode, renameNode, requestCameraStream, requestMicStream, requestScreenStream, resolveFileKind, resolveFormat, searchEmojis, setBlockAttrsTransition, setBlockAttrsValue, setBlockDurationInSource, setHeadingLineTransition, setMediaClipInSource, sliceIndexAtOffset, spliceBlock, summarizeBlockProps, supportsDisplayMedia, supportsMediaRecorder, supportsUserMedia, templateLabel, timingPathFor, tiptapToMarkdown, transitionLabel, useBlockNavigator, useDiagramData, useEditorContext, useFileDrop, useImageEditor, useMediaRecorder, usePreviewSettings, useStreamPreview };