@bendyline/squisq-editor-react 1.6.2 → 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.
Files changed (200) hide show
  1. package/README.md +12 -3
  2. package/dist/index.d.ts +1229 -179
  3. package/dist/index.js +18017 -11231
  4. package/dist/index.js.map +1 -1
  5. package/dist/monaco.d.ts +1 -0
  6. package/dist/monaco.js +4 -0
  7. package/dist/monaco.js.map +1 -0
  8. package/dist/styles/index.css +1471 -245
  9. package/package.json +9 -5
  10. package/src/BlockPropertiesPopover.tsx +30 -15
  11. package/src/DocumentSettingsDialog.tsx +13 -21
  12. package/src/EditorContext.tsx +199 -42
  13. package/src/EditorShell.tsx +348 -260
  14. package/src/ImageEditor.tsx +22 -1
  15. package/src/InlinePreviewGutter.tsx +16 -8
  16. package/src/MediaBin.tsx +107 -14
  17. package/src/OutlinePanel.tsx +202 -7
  18. package/src/PlainHtmlPreview.tsx +40 -1
  19. package/src/PreviewControls.tsx +309 -69
  20. package/src/PreviewPanel.tsx +312 -78
  21. package/src/RawEditor.tsx +13 -2
  22. package/src/StatusBar.tsx +5 -2
  23. package/src/TemplateAnnotation.ts +12 -3
  24. package/src/TemplatePicker.tsx +75 -21
  25. package/src/ThemeCustomizerPanel.tsx +8 -0
  26. package/src/ThemePicker.tsx +10 -5
  27. package/src/TimelineBlockPreview.tsx +1 -1
  28. package/src/Toolbar.tsx +202 -41
  29. package/src/TransitionPicker.tsx +36 -4
  30. package/src/ViewMenuPanel.tsx +12 -14
  31. package/src/WysiwygEditor.tsx +124 -91
  32. package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +33 -0
  33. package/src/__tests__/blockTagActivity.test.ts +183 -0
  34. package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +75 -0
  35. package/src/__tests__/buildPreviewDocContent.test.ts +48 -0
  36. package/src/__tests__/buildPreviewDocTransition.test.ts +21 -1
  37. package/src/__tests__/canvasSurfaceTextEditing.test.tsx +60 -0
  38. package/src/__tests__/customLayoutManagerTheme.test.tsx +34 -0
  39. package/src/__tests__/documentSettingsDialog.test.tsx +29 -1
  40. package/src/__tests__/editorScrollHandoff.test.tsx +102 -0
  41. package/src/__tests__/editorScrollSync.test.ts +65 -0
  42. package/src/__tests__/editorShellProps.test.tsx +123 -1
  43. package/src/__tests__/emojiPicker.test.tsx +2 -42
  44. package/src/__tests__/headingTransition.test.ts +0 -12
  45. package/src/__tests__/imageEditAffordance.test.tsx +5 -1
  46. package/src/__tests__/imageEditModalContract.test.tsx +119 -0
  47. package/src/__tests__/imageEditorShell.test.tsx +15 -1
  48. package/src/__tests__/jsonEditor.test.tsx +56 -1
  49. package/src/__tests__/layersPanel.test.tsx +75 -5
  50. package/src/__tests__/majorApiTypes.test.ts +26 -0
  51. package/src/__tests__/mediaBinDrop.test.tsx +90 -0
  52. package/src/__tests__/narrationSave.test.ts +148 -0
  53. package/src/__tests__/outlinePanel.test.tsx +93 -3
  54. package/src/__tests__/outlineSource.test.ts +217 -0
  55. package/src/__tests__/plainHtmlPreview.test.tsx +17 -1
  56. package/src/__tests__/presentationMode.test.tsx +290 -0
  57. package/src/__tests__/previewControls.test.tsx +218 -5
  58. package/src/__tests__/previewPanelAudioFailure.test.tsx +46 -0
  59. package/src/__tests__/previewPanelPresentation.test.tsx +126 -0
  60. package/src/__tests__/previewPanelTransforms.test.tsx +117 -0
  61. package/src/__tests__/rawEditorModelIsolation.test.ts +19 -0
  62. package/src/__tests__/resolveBlockVisual.test.ts +43 -0
  63. package/src/__tests__/statusBar.test.tsx +27 -0
  64. package/src/__tests__/teleprompter.test.tsx +190 -0
  65. package/src/__tests__/templateAnnotationRoundTrip.test.ts +26 -0
  66. package/src/__tests__/templatePickerPortal.test.tsx +62 -0
  67. package/src/__tests__/tiptapBridge.test.ts +23 -0
  68. package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +109 -0
  69. package/src/__tests__/transformStyleId.test.ts +13 -0
  70. package/src/__tests__/useImageEditor.test.tsx +67 -0
  71. package/src/__tests__/useMediaRecorder.test.ts +75 -0
  72. package/src/__tests__/viewMenuPanel.test.tsx +130 -0
  73. package/src/__tests__/wysiwygImageUpload.test.ts +69 -0
  74. package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +56 -0
  75. package/src/asciiDiagram/AsciiDiagramExtension.ts +343 -0
  76. package/src/asciiDiagram/AsciiDiagramWidget.tsx +224 -0
  77. package/src/asciiDiagram/RepairableDiagramExtension.ts +200 -0
  78. package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +145 -0
  79. package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +159 -0
  80. package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +227 -0
  81. package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +114 -0
  82. package/src/asciiDiagram/__tests__/asciiPaste.test.ts +43 -0
  83. package/src/asciiDiagram/asciiDiagramCommands.ts +148 -0
  84. package/src/asciiDiagram/asciiDiagramData.ts +116 -0
  85. package/src/asciiDiagram/asciiDiagramOps.ts +219 -0
  86. package/src/asciiDiagram/asciiPaste.ts +19 -0
  87. package/src/blockTagActivity.ts +233 -0
  88. package/src/buildDocumentPreviewMarkdown.ts +168 -0
  89. package/src/buildPreviewDoc.ts +19 -12
  90. package/src/customTemplates/CustomLayoutManager.tsx +3 -2
  91. package/src/customTemplates/CustomTemplateContext.tsx +6 -0
  92. package/src/customTemplates/TemplateDesigner.tsx +7 -4
  93. package/src/customTemplates/__tests__/library.test.ts +8 -0
  94. package/src/customTemplates/designer.css +158 -99
  95. package/src/customTemplates/library.ts +16 -3
  96. package/src/customThemes/CustomThemeContext.tsx +6 -0
  97. package/src/customThemes/CustomThemeDialog.tsx +35 -5
  98. package/src/customThemes/ImportThemeSection.tsx +178 -0
  99. package/src/customThemes/__tests__/customThemeLibrary.test.ts +9 -0
  100. package/src/customThemes/__tests__/importThemeSection.test.tsx +192 -0
  101. package/src/customThemes/customThemeLibrary.ts +7 -4
  102. package/src/customThemes/index.ts +7 -1
  103. package/src/customThemes/themeDraft.ts +23 -7
  104. package/src/diagram/DiagramCanvas.tsx +9 -4
  105. package/src/diagram/types.ts +35 -0
  106. package/src/editorScrollSync.ts +73 -0
  107. package/src/emojiData.ts +3 -23
  108. package/src/headingTransition.ts +0 -15
  109. package/src/imageEditor/CanvasSurface.tsx +29 -23
  110. package/src/imageEditor/LayersPanel.tsx +78 -3
  111. package/src/imageEditor/Toolbar.tsx +5 -1
  112. package/src/imageEditor/icons.tsx +4 -0
  113. package/src/imageEditor/image-editor.css +75 -0
  114. package/src/imageEditor/layers/SelectionHandles.tsx +1 -1
  115. package/src/imageEditor/useImageEditor.ts +71 -14
  116. package/src/index.ts +191 -19
  117. package/src/jsonEditor/JsonEditorContext.tsx +12 -6
  118. package/src/jsonEditor/RenderNode.tsx +24 -3
  119. package/src/jsonEditor/editors.tsx +86 -19
  120. package/src/mediaEntries.ts +12 -0
  121. package/src/monaco.ts +35 -0
  122. package/src/monacoWorkers.ts +89 -0
  123. package/src/outlineSource.ts +171 -0
  124. package/src/presentation/PresentationMode.tsx +596 -0
  125. package/src/rawEditorIsolation.ts +18 -0
  126. package/src/recorder/hooks/useMediaRecorder.ts +97 -53
  127. package/src/resolveBlockVisual.ts +10 -4
  128. package/src/scene/Scene.tsx +48 -18
  129. package/src/scene/SceneBlockExtension.ts +17 -10
  130. package/src/scene/SceneBlockWidget.tsx +5 -1
  131. package/src/scene/SceneViewport.tsx +7 -3
  132. package/src/scene/ShapePalette.tsx +17 -2
  133. package/src/scene/__tests__/DiagramAdapter.test.ts +86 -0
  134. package/src/scene/__tests__/SceneBlockExtension.test.ts +33 -0
  135. package/src/scene/__tests__/sceneIsolation.test.tsx +93 -0
  136. package/src/scene/adapters/DiagramAdapter.ts +12 -101
  137. package/src/scene/commands/SceneCommand.ts +4 -1
  138. package/src/scene/index.ts +1 -6
  139. package/src/scene/layers/DiagramEdges.tsx +21 -7
  140. package/src/scene/layers/edgeGeometry.ts +9 -1
  141. package/src/scene/layers/nodeCard.tsx +27 -8
  142. package/src/scene/scene.css +5 -2
  143. package/src/scene/text/SceneTextOverlay.tsx +5 -5
  144. package/src/scene/text/sceneTextChannel.ts +26 -20
  145. package/src/scene/text/sceneTextConfig.ts +4 -0
  146. package/src/scene/tools/ConnectTool.ts +13 -4
  147. package/src/scene/tools/SceneTool.ts +8 -0
  148. package/src/scene/tools/SelectTool.ts +34 -18
  149. package/src/scene/tools/ShapeTool.ts +2 -3
  150. package/src/styles/ascii-diagram.css +79 -0
  151. package/src/styles/ascii-timeline.css +499 -0
  152. package/src/styles/editor.css +706 -120
  153. package/src/styles/index.css +3 -0
  154. package/src/styles/tree-view.css +139 -0
  155. package/src/teleprompter/TeleprompterControls.tsx +218 -0
  156. package/src/teleprompter/TeleprompterSelfView.tsx +22 -0
  157. package/src/teleprompter/TeleprompterSurface.tsx +267 -0
  158. package/src/teleprompter/TeleprompterView.tsx +338 -0
  159. package/src/teleprompter/canvasRenderer.ts +161 -0
  160. package/src/teleprompter/floatingWindow.ts +352 -0
  161. package/src/teleprompter/index.ts +61 -0
  162. package/src/teleprompter/pcmWorklet.ts +62 -0
  163. package/src/teleprompter/recording/insertPreamble.ts +80 -0
  164. package/src/teleprompter/recording/narrationSave.ts +134 -0
  165. package/src/teleprompter/recording/useNarrationRecorder.ts +367 -0
  166. package/src/teleprompter/scrollModel.ts +85 -0
  167. package/src/teleprompter/teleprompterTheme.ts +303 -0
  168. package/src/teleprompter/types.ts +38 -0
  169. package/src/teleprompter/useFloatingWindow.ts +74 -0
  170. package/src/teleprompter/useMicAnalysis.ts +211 -0
  171. package/src/teleprompter/useTeleprompter.ts +421 -0
  172. package/src/templateContentPreviewResolver.ts +12 -5
  173. package/src/timeline/TimelineEditorWidget.tsx +702 -0
  174. package/src/timeline/TimelineViewExtension.ts +252 -0
  175. package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +355 -0
  176. package/src/timeline/__tests__/TimelineViewExtension.test.ts +163 -0
  177. package/src/timeline/__tests__/timelineCommands.test.ts +327 -0
  178. package/src/timeline/__tests__/timelineOps.test.ts +222 -0
  179. package/src/timeline/__tests__/timelinePaste.test.ts +34 -0
  180. package/src/timeline/timelineCommands.ts +367 -0
  181. package/src/timeline/timelineData.ts +54 -0
  182. package/src/timeline/timelineOps.ts +277 -0
  183. package/src/timeline/timelinePaste.ts +8 -0
  184. package/src/tiptapBridge.ts +24 -16
  185. package/src/transformStyleId.ts +17 -0
  186. package/src/treeview/TreeOutlineWidget.tsx +240 -0
  187. package/src/treeview/TreeViewExtension.ts +250 -0
  188. package/src/treeview/__tests__/TreeViewExtension.test.ts +122 -0
  189. package/src/treeview/__tests__/treeOps.test.ts +125 -0
  190. package/src/treeview/__tests__/treePaste.test.ts +40 -0
  191. package/src/treeview/__tests__/treeViewCommands.test.ts +163 -0
  192. package/src/treeview/treeOps.ts +172 -0
  193. package/src/treeview/treePaste.ts +13 -0
  194. package/src/treeview/treeViewCommands.ts +94 -0
  195. package/src/treeview/treeViewData.ts +41 -0
  196. package/src/useMonacoLoader.ts +11 -34
  197. package/src/wysiwygImageUpload.ts +113 -0
  198. package/src/diagram/DiagramExtension.ts +0 -209
  199. package/src/diagram/DiagramWidget.tsx +0 -272
  200. package/src/diagram/useDiagramData.ts +0 -126
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
- import { ReactNode, CSSProperties, RefObject } from 'react';
4
- import { Doc, MediaProvider, Theme, ViewportPreset, ViewportConfig, Block, CustomTemplateDefinition, MediaEntry, SurfaceScheme, ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';
5
- import { MarkdownDocument, HeadingAttributes } from '@bendyline/squisq/markdown';
3
+ import { ReactNode, CSSProperties, RefObject, KeyboardEvent } from 'react';
4
+ import { Doc, MediaProvider, Theme, CustomTemplateDefinition, ThemeSeedColors, ViewportPreset, ViewportConfig, Block, MediaEntry, DiagramEdgeAnchor, SurfaceScheme, ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';
5
+ import { MarkdownDocument } 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';
@@ -11,10 +11,14 @@ import * as monaco_editor from 'monaco-editor';
11
11
  import { editor } from 'monaco-editor';
12
12
  import { IconFamily } from '@bendyline/squisq/icons';
13
13
  import { DisplayMode, CaptionStyle } from '@bendyline/squisq-react';
14
- import { Editor as Editor$1 } from '@tiptap/react';
14
+ import { ConnectorRouting, AsciiDiagram, Tree, AsciiTimeline, AsciiTimelineSide, AsciiTimelineMarker } from '@bendyline/squisq/doc';
15
15
  import * as _tiptap_extension_heading from '@tiptap/extension-heading';
16
+ import { DecorationSet } from '@tiptap/pm/view';
17
+ import { Editor as Editor$1 } from '@tiptap/react';
18
+ import { PluginKey } from '@tiptap/pm/state';
16
19
  import { Node } from '@tiptap/pm/model';
17
20
  import { SquisqAnnotatedSchema, JsonFormValidator, JsonFormValidationError } from '@bendyline/squisq/jsonForm';
21
+ import { NarrationTrace, NarrationAlignment, NarrationScript, NarrationTimingJsonV3, VadConfig } from '@bendyline/squisq/narration';
18
22
  import { ImageEditExportFormat, ImageEditVersionManager } from '@bendyline/squisq/imageEdit';
19
23
 
20
24
  /**
@@ -23,24 +27,31 @@ import { ImageEditExportFormat, ImageEditVersionManager } from '@bendyline/squis
23
27
  * a given layer. The Scene owns the editing UI (overlay + positioning);
24
28
  * the host owns persistence (markdown heading vs. layout JSON blob).
25
29
  */
30
+
26
31
  type SceneTextLevel = 'inline' | 'block' | 'rich';
27
32
 
28
33
  /**
29
- * sceneTextChannel — a module singleton that bridges the canvas's inline
34
+ * sceneTextChannel — an editor-owned channel that bridges the canvas's inline
30
35
  * text editor (which renders in a **detached React root** created by the
31
36
  * Diagram/SceneBlock ProseMirror extensions, outside `<EditorProvider>`)
32
37
  * to the provider, so the top formatting toolbar can target it.
33
38
  *
34
39
  * The active textbox's `SceneTextOverlay` publishes its Tiptap editor here
35
40
  * on focus and clears it on blur/unmount; `EditorProvider` subscribes and
36
- * mirrors the handle into `activeSceneText`. Singleton because only one
37
- * canvas textbox can be focused at a time.
41
+ * mirrors the handle into `activeSceneText`. Each EditorProvider creates its
42
+ * own channel, preventing focus in one editor from mutating another editor.
38
43
  */
39
44
 
40
45
  interface SceneTextHandle {
41
46
  editor: Editor;
42
47
  level: SceneTextLevel;
43
48
  }
49
+ type Listener = (handle: SceneTextHandle | null) => void;
50
+ interface SceneTextChannel {
51
+ set(handle: SceneTextHandle | null): void;
52
+ get(): SceneTextHandle | null;
53
+ subscribe(listener: Listener): () => void;
54
+ }
44
55
 
45
56
  /** Monaco standalone code editor instance type */
46
57
  type MonacoEditor = editor.IStandaloneCodeEditor;
@@ -114,6 +125,11 @@ type LayoutMode = 'document' | 'block' | 'timeline';
114
125
  * colors. `'none'` opts out completely.
115
126
  */
116
127
  type ThemeInheritance = 'none' | 'fonts' | 'fonts-colors';
128
+ /**
129
+ * When inline block-template tags are shown in the WYSIWYG surface.
130
+ * `'active'` shows tags for the cursor's block and the block under the pointer.
131
+ */
132
+ type BlockTagVisibility = 'none' | 'active' | 'always';
117
133
  /**
118
134
  * Editor operating mode. `markdown` is the full experience (WYSIWYG +
119
135
  * Preview tabs, formatting toolbar). `code` is a Monaco-only view used
@@ -158,12 +174,11 @@ interface EditorState {
158
174
  * the toolbar can toggle it at runtime.
159
175
  */
160
176
  outlineVisible: boolean;
177
+ /** When inline block-template tags are shown in the WYSIWYG view. */
178
+ blockTagVisibility: BlockTagVisibility;
161
179
  /**
162
- * Whether inline block-template tags (the chip next to each templated
163
- * heading in the WYSIWYG view, plus the subtle affordance chip on plain
164
- * headings) are currently visible. Initialized from the EditorShell
165
- * `blockTags` prop (default true); the View menu in the toolbar can
166
- * toggle it at runtime.
180
+ * Whether inline block-template tags can currently be visible.
181
+ * Kept for compatibility; prefer {@link blockTagVisibility}.
167
182
  */
168
183
  blockTagsVisible: boolean;
169
184
  /**
@@ -195,6 +210,13 @@ interface EditorState {
195
210
  * shell.
196
211
  */
197
212
  allowRecording: boolean;
213
+ /**
214
+ * Whether the Narrate (teleprompter) display mode is offered under the
215
+ * Use tab. Orthogonal to `allowRecording`: the teleprompter is useful
216
+ * without any capture (reading for external recording software), and a
217
+ * host may allow the recorder modal but not want a prompter surface.
218
+ */
219
+ allowNarrate: boolean;
198
220
  /**
199
221
  * Document layout mode. `'document'` (default) edits the whole document;
200
222
  * `'block'` activates the block-at-a-time card view. Initialized from the
@@ -254,6 +276,8 @@ interface EditorActions {
254
276
  setOutlineVisible: (visible: boolean) => void;
255
277
  /** Show or hide inline block-template tags at runtime (driven by the View menu). */
256
278
  setBlockTagsVisible: (visible: boolean) => void;
279
+ /** Choose when inline block-template tags are shown. */
280
+ setBlockTagVisibility: (visibility: BlockTagVisibility) => void;
257
281
  /** Change how much of the active Squisq theme the WYSIWYG surface mirrors. */
258
282
  setThemeInheritance: (mode: ThemeInheritance) => void;
259
283
  /** Insert text at the current cursor position in the active editor */
@@ -289,6 +313,8 @@ interface EditorContextValue extends EditorState, EditorActions {
289
313
  * buttons apply (`inline` = marks only; `rich` = headings/lists too).
290
314
  */
291
315
  activeSceneText: SceneTextHandle | null;
316
+ /** Instance-owned bridge used by detached scene widget roots. */
317
+ sceneTextChannel: SceneTextChannel;
292
318
  /**
293
319
  * Workspace-scoped `ContentContainer` for this document — the folder
294
320
  * holding the doc, its `_files/` sidecar, sibling documents, and any
@@ -405,6 +431,12 @@ interface EditorProviderProps {
405
431
  * surfaces where camera/screen prompts would be jarring).
406
432
  */
407
433
  allowRecording?: boolean;
434
+ /**
435
+ * Whether the Narrate (teleprompter) display mode is offered under the
436
+ * Use tab. Defaults to true. When false the mode button is hidden and a
437
+ * frontmatter-forced `display-mode: narrate` clamps back to video.
438
+ */
439
+ allowNarrate?: boolean;
408
440
  /**
409
441
  * File name (e.g. `foo.ts`) or bare extension — used to pick a Monaco
410
442
  * language and decide between markdown vs. code mode.
@@ -428,10 +460,16 @@ interface EditorProviderProps {
428
460
  */
429
461
  outline?: boolean;
430
462
  /**
431
- * Initial visibility of inline block-template tags on headings.
432
- * Defaults to true. The toolbar's View menu can toggle it at runtime.
463
+ * Legacy initial visibility of inline block-template tags on headings.
464
+ * `true` maps to always visible and `false` maps to hidden. When omitted,
465
+ * {@link blockTagVisibility} defaults to `'active'`.
433
466
  */
434
467
  blockTags?: boolean;
468
+ /**
469
+ * Initial block-tag visibility mode. When set, this takes precedence over
470
+ * the legacy boolean {@link blockTags} prop. Defaults to `'active'`.
471
+ */
472
+ blockTagVisibility?: BlockTagVisibility;
435
473
  /**
436
474
  * Initial value for how much of the active Squisq theme the WYSIWYG
437
475
  * editing surface should mirror. Defaults to `'fonts'` — the
@@ -449,9 +487,9 @@ interface EditorProviderProps {
449
487
  * Bundled view preferences — a serializable JSON blob covering all
450
488
  * runtime-toggleable view options. When provided, individual values
451
489
  * here override the matching individual props (`inlinePreview`,
452
- * `showStatusBar`, `outline`). Hosts wiring this up typically load
453
- * the blob from their own preferences storage and pair it with
454
- * {@link onViewPreferencesChange}.
490
+ * `showStatusBar`, `outline`, `blockTagVisibility`, `blockTags`). Hosts
491
+ * wiring this up typically load the blob from their own preferences storage
492
+ * and pair it with {@link onViewPreferencesChange}.
455
493
  */
456
494
  viewPreferences?: ViewPreferences;
457
495
  /**
@@ -478,12 +516,14 @@ interface ViewPreferences {
478
516
  showStatusBar?: boolean;
479
517
  /** Whether inline block-template tags on headings are visible. */
480
518
  blockTags?: boolean;
519
+ /** When inline block-template tags are shown. Takes precedence over `blockTags`. */
520
+ blockTagVisibility?: BlockTagVisibility;
481
521
  /** How much of the active Squisq theme the WYSIWYG surface mirrors. */
482
522
  themeInheritance?: ThemeInheritance;
483
523
  /** Document vs. block-at-a-time layout. */
484
524
  layoutMode?: LayoutMode;
485
525
  }
486
- declare function EditorProvider({ initialMarkdown, initialView, articleId, colorScheme: initialColorScheme, 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;
526
+ declare function EditorProvider({ initialMarkdown, initialView, articleId, colorScheme: initialColorScheme, workspaceContainer, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, mediaProvider, imageDisplayMode, mentionProvider, documentLinkProvider, allowRecording, allowNarrate, fileName, language, inlinePreview, showStatusBar, outline, blockTags, blockTagVisibility: initialBlockTagVisibility, themeInheritance, layoutMode, viewPreferences, onViewPreferencesChange, children, }: EditorProviderProps): react_jsx_runtime.JSX.Element;
487
527
 
488
528
  /**
489
529
  * Host-supplied context sections rendered INSIDE the Monaco (raw/code)
@@ -611,12 +651,6 @@ interface EditorShellProps {
611
651
  * this container via `createMediaProviderFromContainer`.
612
652
  */
613
653
  workspaceContainer?: ContentContainer | null;
614
- /**
615
- * @deprecated Renamed to `workspaceContainer` to make the workspace-
616
- * vs. doc-scoped distinction explicit. Still accepted as a fallback
617
- * for now; remove in the next breaking release.
618
- */
619
- container?: ContentContainer | null;
620
654
  /**
621
655
  * Enable version history. Snapshots are stored at
622
656
  * `.versions/<basename>.<timestamp>.md` inside the same
@@ -768,6 +802,14 @@ interface EditorShellProps {
768
802
  * the button is hidden regardless of this prop.
769
803
  */
770
804
  allowRecording?: boolean;
805
+ /**
806
+ * Whether the Narrate (teleprompter) display mode is offered under the
807
+ * Use tab. Defaults to true. Orthogonal to `allowRecording` — the
808
+ * prompter is useful without capture (reading for external recording
809
+ * software), and the in-mode Record affordance additionally requires
810
+ * `allowRecording` + a `mediaProvider`.
811
+ */
812
+ allowNarrate?: boolean;
771
813
  /**
772
814
  * Placeholder text shown in the WYSIWYG editor while the document is
773
815
  * empty. When omitted, the editor rotates through its own generic
@@ -847,12 +889,16 @@ interface EditorShellProps {
847
889
  */
848
890
  outlineWidth?: number;
849
891
  /**
850
- * Initial visibility of inline block-template tags on headings — the
851
- * chip rendered next to each heading in the WYSIWYG view that opens
852
- * the block-template picker. Defaults to true; the View menu can
853
- * toggle it at runtime regardless of the initial value.
892
+ * Legacy initial visibility of inline block-template tags on headings.
893
+ * `true` maps to always visible and `false` maps to hidden. When omitted,
894
+ * {@link blockTagVisibility} defaults to `'active'`.
854
895
  */
855
896
  blockTags?: boolean;
897
+ /**
898
+ * Initial block-tag visibility mode. Takes precedence over `blockTags`.
899
+ * Defaults to `'active'` (selected/hovered block only).
900
+ */
901
+ blockTagVisibility?: BlockTagVisibility;
856
902
  /**
857
903
  * How much of the active Squisq theme the WYSIWYG editing surface
858
904
  * mirrors. Defaults to `'fonts'` — the historical behavior of
@@ -864,7 +910,8 @@ interface EditorShellProps {
864
910
  * Bundled view preferences — a serializable JSON blob covering the
865
911
  * runtime-toggleable view options surfaced in the View menu. When
866
912
  * provided, fields here override the corresponding individual props
867
- * (`outline`, `inlinePreview`, `showStatusBar`). Pair with
913
+ * (`outline`, `inlinePreview`, `showStatusBar`, `blockTagVisibility`,
914
+ * `blockTags`). Pair with
868
915
  * {@link onViewPreferencesChange} to externalize storage of these
869
916
  * preferences in the host.
870
917
  */
@@ -888,7 +935,7 @@ interface EditorShellProps {
888
935
  * Complete markdown editor shell with toolbar, view switcher, and three
889
936
  * editing modes: Raw (Monaco), WYSIWYG (Tiptap), and Preview.
890
937
  */
891
- declare function EditorShell({ initialMarkdown, initialView, articleId, basePath, onChange, colorScheme, className, height, minHeight, maxHeight, mediaProvider, workspaceContainer, container, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, showFilesToggle, toolbarSlotLeft, toolbarSlotAfterActions, toolbarSlotRight, showPlayTab, submitOnEnter, codeContext, 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;
938
+ declare function EditorShell({ initialMarkdown, initialView, articleId, basePath, onChange, colorScheme, className, height, minHeight, maxHeight, mediaProvider, workspaceContainer, allowVersioning, versionBasename, versioningPrunePolicy, versioningAutoSaveIdleMs, onSaveVersion, showFilesToggle, toolbarSlotLeft, toolbarSlotAfterActions, toolbarSlotRight, showPlayTab, submitOnEnter, codeContext, fullWidth, uxFont, thinMargins, showStatusBar, imageDisplayMode, fileName, language, mentionProvider, documentLinkProvider, allowRecording, allowNarrate, placeholder, readOnly, imageSrc, imageAlt, imageMode, imageEditorContainer, onImageExport, inlinePreview, inlinePreviewWidth, outline, outlineWidth, blockTags, blockTagVisibility, themeInheritance, viewPreferences, onViewPreferencesChange, themeOverride, }: EditorShellProps): react_jsx_runtime.JSX.Element;
892
939
 
893
940
  /**
894
941
  * Bridges a host-supplied {@link CodeContext} onto the live Monaco editor:
@@ -1299,8 +1346,10 @@ interface PlainHtmlPreviewProps {
1299
1346
  theme?: Theme;
1300
1347
  className?: string;
1301
1348
  style?: CSSProperties;
1349
+ /** Let unmodified Up/Down arrows scroll the preview without requiring iframe focus. */
1350
+ globalKeyboardShortcuts?: boolean;
1302
1351
  }
1303
- declare function PlainHtmlPreview({ markdown, title, images, mediaProvider, mediaRevision, theme, className, style, }: PlainHtmlPreviewProps): react_jsx_runtime.JSX.Element;
1352
+ declare function PlainHtmlPreview({ markdown, title, images, mediaProvider, mediaRevision, theme, className, style, globalKeyboardShortcuts, }: PlainHtmlPreviewProps): react_jsx_runtime.JSX.Element;
1304
1353
 
1305
1354
  /**
1306
1355
  * Emoji Dataset
@@ -1316,29 +1365,6 @@ declare function PlainHtmlPreview({ markdown, title, images, mediaProvider, medi
1316
1365
  * because the picker is meant for quick insertion, not exhaustive
1317
1366
  * lookup; the user can paste anything we don't have.
1318
1367
  */
1319
- interface EmojiEntry {
1320
- /** The actual emoji glyph (may be multi-codepoint, e.g. ZWJ sequences). */
1321
- char: string;
1322
- /** Display name shown in the tooltip. */
1323
- name: string;
1324
- /** Lowercase keywords for the search index — name words plus aliases. */
1325
- keywords: string;
1326
- }
1327
- interface EmojiCategory {
1328
- id: string;
1329
- label: string;
1330
- /** Single-glyph icon shown on the tab. */
1331
- icon: string;
1332
- emojis: EmojiEntry[];
1333
- }
1334
- declare const EMOJI_CATEGORIES: EmojiCategory[];
1335
- /**
1336
- * Flat list of every emoji across all categories — used as the search
1337
- * corpus and to expose a `getEmojiByChar` lookup.
1338
- */
1339
- declare const ALL_EMOJIS: EmojiEntry[];
1340
- /** Search for emoji whose name or keywords contain the query (case-insensitive). */
1341
- declare function searchEmojis(query: string, limit?: number): EmojiEntry[];
1342
1368
 
1343
1369
  /**
1344
1370
  * Discriminated picker entry. The picker UI dispatches on `kind` to
@@ -1359,6 +1385,29 @@ type PickerEntry = {
1359
1385
  /** Canonical token used in the markdown source (bare or qualified). */
1360
1386
  token: string;
1361
1387
  };
1388
+ interface PickerCategory {
1389
+ id: string;
1390
+ label: string;
1391
+ /** What to render on the category tab. Emoji glyph or FA class. */
1392
+ tab: {
1393
+ kind: 'emoji';
1394
+ char: string;
1395
+ } | {
1396
+ kind: 'icon';
1397
+ family: IconFamily;
1398
+ name: string;
1399
+ };
1400
+ entries: PickerEntry[];
1401
+ }
1402
+ /**
1403
+ * The full picker category list — emoji buckets followed by the three
1404
+ * FontAwesome families. Drives the EmojiPicker tabs.
1405
+ */
1406
+ declare const PICKER_CATEGORIES: PickerCategory[];
1407
+ /** Flat corpus for the picker search index. */
1408
+ declare const ALL_PICKER_ENTRIES: PickerEntry[];
1409
+ /** Lowercase substring search across emoji + icon entries. */
1410
+ declare function searchPickerEntries(query: string, limit?: number): PickerEntry[];
1362
1411
 
1363
1412
  interface EmojiPickerProps {
1364
1413
  /** Whether the picker is visible. */
@@ -1527,6 +1576,97 @@ declare function useDocCustomThemes(): DocCustomThemes;
1527
1576
 
1528
1577
  /** Where a saved theme lands — mirrors `DesignerSaveTarget` for templates. */
1529
1578
  type ThemeSaveTarget = 'doc' | 'library';
1579
+ /** Extra assets riding along with a theme save (file-import byproducts). */
1580
+ interface ThemeSaveExtras {
1581
+ /** Custom layout templates inferred from an imported PPTX. */
1582
+ templates?: CustomTemplateDefinition[];
1583
+ }
1584
+
1585
+ /**
1586
+ * themeDraft — the editable subset of the Theme schema, shared by the
1587
+ * ThemeCustomizerPanel popover and the CustomThemeDialog.
1588
+ *
1589
+ * A `Draft` mirrors the handful of fields a user actually edits (name, seed
1590
+ * colors, N accents, fonts, style presets, and a base theme to inherit from).
1591
+ * `compileDraft` turns it into a full validated `Theme` via `compileTheme`;
1592
+ * everything the draft doesn't mention inherits from the chosen base (or the
1593
+ * compiler's neutral STARTER_THEME when no base is picked).
1594
+ */
1595
+
1596
+ declare const BORDER_RADIUS_PRESETS: {
1597
+ readonly sharp: 0;
1598
+ readonly soft: 6;
1599
+ readonly rounded: 16;
1600
+ };
1601
+ type BorderRadiusPreset = keyof typeof BORDER_RADIUS_PRESETS;
1602
+ declare const ANIMATION_SPEED_PRESETS: {
1603
+ readonly static: 0;
1604
+ readonly subtle: 1.4;
1605
+ readonly normal: 1;
1606
+ readonly expressive: 0.7;
1607
+ };
1608
+ type AnimationSpeedPreset = keyof typeof ANIMATION_SPEED_PRESETS;
1609
+ declare const TEXT_SHADOW_PRESETS: {
1610
+ readonly off: false;
1611
+ readonly on: true;
1612
+ };
1613
+ type TextShadowPreset = keyof typeof TEXT_SHADOW_PRESETS;
1614
+ declare const CONTRAST_PRESETS: readonly ["subtle", "balanced", "high"];
1615
+ type ContrastPreset = (typeof CONTRAST_PRESETS)[number];
1616
+ declare const IMAGE_TREATMENT_PRESETS: readonly ["none", "mono", "duotone", "warm", "cool"];
1617
+ type ImageTreatmentPreset = (typeof IMAGE_TREATMENT_PRESETS)[number];
1618
+ declare const FALLBACK_OPTIONS: readonly ["sans-serif", "serif", "monospace", "system-ui"];
1619
+ type FallbackOption = (typeof FALLBACK_OPTIONS)[number];
1620
+ interface CustomFontInput {
1621
+ kind: 'curated' | 'custom';
1622
+ stackId?: string;
1623
+ customName?: string;
1624
+ customFallback?: FallbackOption;
1625
+ }
1626
+ /** One editable accent: a color plus the colorScheme key it maps to. */
1627
+ interface AccentInput {
1628
+ key: string;
1629
+ color: string;
1630
+ }
1631
+ interface Draft {
1632
+ name: string;
1633
+ /** Id of the base theme this draft inherits render style / layout from. */
1634
+ baseId?: string;
1635
+ seeds: ThemeSeedColors;
1636
+ /** The "N accents" — each becomes a `colorSchemes` entry. */
1637
+ accents: AccentInput[];
1638
+ /** True once the user has touched the accent list; gates wholesale replace. */
1639
+ accentsEdited: boolean;
1640
+ titleFont: CustomFontInput;
1641
+ bodyFont: CustomFontInput;
1642
+ borderRadius: BorderRadiusPreset;
1643
+ animationSpeed: AnimationSpeedPreset;
1644
+ textShadow: TextShadowPreset;
1645
+ contrast: ContrastPreset;
1646
+ imageTreatment: ImageTreatmentPreset;
1647
+ }
1648
+ /**
1649
+ * Draft patch from a theme inferred from an imported office file: name,
1650
+ * seeds, accents (marked authored so the file's schemes survive a re-save),
1651
+ * and fonts. Deliberately leaves `baseId` and the style presets untouched —
1652
+ * the user's in-progress choices there aren't the file's to overwrite.
1653
+ */
1654
+ declare function draftPatchFromImportedTheme(theme: Theme): Partial<Draft>;
1655
+
1656
+ interface ImportedThemeResult {
1657
+ theme: Theme;
1658
+ /** PPTX only, when `allowLayouts`: custom templates derived from slide layouts. */
1659
+ layouts?: CustomTemplateDefinition[];
1660
+ warnings: string[];
1661
+ fileName: string;
1662
+ }
1663
+ interface ImportThemeSectionProps {
1664
+ /** Fired on successful inference with the draft patch + full result. */
1665
+ onImported: (patch: Partial<Draft>, result: ImportedThemeResult) => void;
1666
+ /** Also derive PPTX slide layouts as custom templates. Default false. */
1667
+ allowLayouts?: boolean;
1668
+ }
1669
+ declare function ImportThemeSection({ onImported, allowLayouts }: ImportThemeSectionProps): react_jsx_runtime.JSX.Element;
1530
1670
 
1531
1671
  /** Caption selection: off, or one of the two enabled styles. */
1532
1672
  type CaptionMode = 'off' | CaptionStyle;
@@ -1567,7 +1707,7 @@ interface PreviewSettings {
1567
1707
  interface ThemeDesignerConfig {
1568
1708
  value: Theme | null;
1569
1709
  onChange: (theme: Theme) => void;
1570
- onSave: (theme: Theme, target: ThemeSaveTarget) => void;
1710
+ onSave: (theme: Theme, target: ThemeSaveTarget, extras?: ThemeSaveExtras) => void;
1571
1711
  onClose: () => void;
1572
1712
  }
1573
1713
  declare function usePreviewSettings(): PreviewSettings;
@@ -1597,11 +1737,21 @@ declare function PreviewSettingsProvider({ doc, children, themeOverride, }: Prev
1597
1737
  */
1598
1738
  declare function PreviewToolbarControls(): react_jsx_runtime.JSX.Element;
1599
1739
  /**
1600
- * Segmented display-mode switch (Video / Slideshow / Document / Page), used
1601
- * inline in the Use toolbar and inside its overflow popover. Reads and writes
1602
- * the same `activeDisplayMode` in preview settings.
1740
+ * Segmented display-mode switch retained as a public, embeddable control.
1741
+ * The editor shell uses {@link PreviewModeMenu} beside its Use tab instead.
1742
+ * Narrate is hidden when the host disables `allowNarrate`.
1603
1743
  */
1604
1744
  declare function PreviewModeSwitch(): react_jsx_runtime.JSX.Element;
1745
+ /**
1746
+ * Dropdown trigger rendered directly beside the Use tab. Selecting a mode
1747
+ * also enters the Use view, so the menu works from Write and Source as well
1748
+ * as from an already-active preview.
1749
+ */
1750
+ interface PreviewModeMenuProps {
1751
+ /** Incremented by the parent to open the menu from another control. */
1752
+ openRequest?: number;
1753
+ }
1754
+ declare function PreviewModeMenu({ openRequest }: PreviewModeMenuProps): react_jsx_runtime.JSX.Element;
1605
1755
  /**
1606
1756
  * Segmented aspect-ratio switch (16:9 / 1:1 / 9:16 / 4:3), used inline in the
1607
1757
  * Use toolbar and inside its overflow popover. Reads and writes the same
@@ -1692,8 +1842,10 @@ interface OutlinePanelProps {
1692
1842
  width?: number;
1693
1843
  /** Optional CSS class for the outer container. */
1694
1844
  className?: string;
1845
+ /** Disable heading-level changes and section reordering. */
1846
+ readOnly?: boolean;
1695
1847
  }
1696
- declare function OutlinePanel({ width, className }: OutlinePanelProps): react_jsx_runtime.JSX.Element;
1848
+ declare function OutlinePanel({ width, className, readOnly }: OutlinePanelProps): react_jsx_runtime.JSX.Element;
1697
1849
 
1698
1850
  interface ThemeCustomizerPanelProps {
1699
1851
  /** Current custom theme (or null to start from defaults). */
@@ -1715,6 +1867,7 @@ interface TemplatePreviewSource {
1715
1867
  viewport: ViewportConfig;
1716
1868
  basePath?: string;
1717
1869
  mediaProvider?: MediaProvider | null;
1870
+ customTemplates?: readonly CustomTemplateDefinition[];
1718
1871
  }
1719
1872
 
1720
1873
  /**
@@ -1817,18 +1970,16 @@ interface HeadingTransitionAttrs {
1817
1970
  * from `dataBlockAttrs`.
1818
1971
  */
1819
1972
  declare function setHeadingAttrsTransition(blockAttrsInner: string | null | undefined, templateParams: string | null | undefined, next: TransitionFields): HeadingTransitionAttrs;
1820
- /**
1821
- * Legacy single-channel writer for callers that only own `dataBlockAttrs`.
1822
- * Internal editor surfaces should use {@link setHeadingAttrsTransition} so new
1823
- * transition edits land in the squisq-native `{[…]}` params.
1824
- */
1825
- declare function setBlockAttrsTransition(blockAttrsInner: string | null | undefined, next: TransitionFields): string | null;
1826
1973
 
1827
1974
  interface TransitionPickerProps {
1828
1975
  value: TransitionFields;
1829
1976
  onChange: (next: TransitionFields) => void;
1977
+ /** Surface scheme copied onto the portaled flyout so it can style independently of the shell. */
1978
+ colorScheme?: 'light' | 'dark';
1979
+ /** Active document-theme accent used for open and selected states. */
1980
+ accentColor?: string;
1830
1981
  }
1831
- declare function TransitionPicker({ value, onChange }: TransitionPickerProps): react_jsx_runtime.JSX.Element;
1982
+ declare function TransitionPicker({ value, onChange, colorScheme, accentColor, }: TransitionPickerProps): react_jsx_runtime.JSX.Element;
1832
1983
 
1833
1984
  /**
1834
1985
  * transitionCatalog
@@ -1938,13 +2089,17 @@ interface BlockPropertiesPopoverProps {
1938
2089
  /** Apply a new `dataBlockAttrs` inner to the heading (null clears it). */
1939
2090
  onChange: (nextInner: string | null) => void;
1940
2091
  /** Apply a paired `dataBlockAttrs` / `dataTemplateParams` transition rewrite. */
1941
- onAnnotationChange?: (next: {
2092
+ onAnnotationChange: (next: {
1942
2093
  blockAttrsInner: string | null;
1943
2094
  templateParams: string | null;
1944
2095
  }) => void;
2096
+ /** Editor surface scheme. Required explicitly because this popover is portaled to `<body>`. */
2097
+ colorScheme?: 'light' | 'dark';
2098
+ /** Active document-theme accent used for focus and selected-state highlights. */
2099
+ accentColor?: string;
1945
2100
  onClose: () => void;
1946
2101
  }
1947
- declare function BlockPropertiesPopover({ anchorRect, blockAttrs, templateParams, onChange, onAnnotationChange, onClose, }: BlockPropertiesPopoverProps): react.ReactPortal;
2102
+ declare function BlockPropertiesPopover({ anchorRect, blockAttrs, templateParams, onChange, onAnnotationChange, colorScheme, accentColor, onClose, }: BlockPropertiesPopoverProps): react.ReactPortal;
1948
2103
 
1949
2104
  interface InlinePreviewGutterProps {
1950
2105
  /** Width of the gutter in pixels (default: 320). */
@@ -1979,8 +2134,8 @@ interface MediaBinProps {
1979
2134
  /** Relative media paths currently referenced by the document. */
1980
2135
  usedMediaPaths?: ReadonlySet<string>;
1981
2136
  /**
1982
- * Fired after a successful upload via the MediaBin's own "+ Upload"
1983
- * button. `relativePath` is what the provider returned (the same
2137
+ * Fired after a successful upload via the MediaBin's "+ Upload"
2138
+ * button or image drop target. `relativePath` is what the provider returned (the same
1984
2139
  * value embedded in markdown refs, e.g. `attachments/xyz.png`);
1985
2140
  * `name` is the uploader-chosen filename before storage renamed
1986
2141
  * it. Consumers typically use this to insert a markdown image ref
@@ -2164,6 +2319,63 @@ interface UseMonacoLoaderResult {
2164
2319
  */
2165
2320
  declare function useMonacoLoader(): UseMonacoLoaderResult;
2166
2321
 
2322
+ /**
2323
+ * Monaco language-service worker wiring.
2324
+ *
2325
+ * Monaco offloads its heavy language services — css / html / json / typescript
2326
+ * IntelliSense — plus a base editor service (word-based completions, link
2327
+ * detection, diffing) to web workers. Those worker bundles must be produced by
2328
+ * the HOST application's bundler: the mechanisms for it (Vite's `?worker`
2329
+ * import suffix, `new Worker(new URL(...))`, webpack loaders) are all
2330
+ * bundler-specific and cannot live inside this tsup-built library.
2331
+ *
2332
+ * So the division of labor is: the host supplies the five worker constructors
2333
+ * (one line each with Vite's `?worker`), and this helper owns the
2334
+ * `label → worker` mapping — the part that's fiddly and easy to get wrong.
2335
+ *
2336
+ * Call once, before the first editor mounts (typically in the app entry):
2337
+ *
2338
+ * ```ts
2339
+ * import { configureMonacoWorkers } from '@bendyline/squisq-editor-react';
2340
+ * import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
2341
+ * import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
2342
+ * import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
2343
+ * import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
2344
+ * import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
2345
+ *
2346
+ * configureMonacoWorkers({
2347
+ * editor: EditorWorker, json: JsonWorker, css: CssWorker,
2348
+ * html: HtmlWorker, ts: TsWorker,
2349
+ * });
2350
+ * ```
2351
+ *
2352
+ * This is purely additive: without it, highlighting, editing, and custom
2353
+ * completion providers (e.g. the `{[template]}` typeahead) still work — they
2354
+ * run on the main thread. Only the language-service IntelliSense is dormant
2355
+ * until the workers are wired.
2356
+ */
2357
+ /** Zero-arg worker constructor, as produced by Vite's `?worker` import. */
2358
+ type MonacoWorkerConstructor = new () => Worker;
2359
+ interface MonacoWorkerConstructors {
2360
+ /** Base editor worker (word completions, links, diff). Required. */
2361
+ editor: MonacoWorkerConstructor;
2362
+ /** JSON language service. */
2363
+ json?: MonacoWorkerConstructor;
2364
+ /** CSS/SCSS/LESS language service. */
2365
+ css?: MonacoWorkerConstructor;
2366
+ /** HTML/Handlebars/Razor language service. */
2367
+ html?: MonacoWorkerConstructor;
2368
+ /** TypeScript service — also handles JavaScript. */
2369
+ ts?: MonacoWorkerConstructor;
2370
+ }
2371
+ /**
2372
+ * Install `globalThis.MonacoEnvironment.getWorker` so Monaco routes each
2373
+ * language to the matching worker, falling back to the base editor worker for
2374
+ * any label without a dedicated service (which is every plain language — its
2375
+ * grammar-based highlighting needs no worker).
2376
+ */
2377
+ declare function configureMonacoWorkers(workers: MonacoWorkerConstructors): void;
2378
+
2167
2379
  interface CustomTemplateContextValue {
2168
2380
  /** Templates inlined into the current doc's frontmatter. */
2169
2381
  docTemplates: CustomTemplateDefinition[];
@@ -2239,20 +2451,9 @@ interface DocCustomTemplates {
2239
2451
  }
2240
2452
  declare function useDocCustomTemplates(): DocCustomTemplates;
2241
2453
 
2242
- /**
2243
- * Read diagram nodes + edges from the live Tiptap state.
2244
- *
2245
- * For a given parent heading position, walks the diagram section's child
2246
- * headings, builds synthetic `Block` objects from their text + Pandoc
2247
- * attributes, runs `computeDiagramLayout` from core to fill in missing
2248
- * positions, and returns the result in the shape React Flow consumes.
2249
- *
2250
- * The hook re-derives on every editor transaction — no caching layer
2251
- * means there's nothing to invalidate when the user types or the markdown
2252
- * is reloaded from disk.
2253
- */
2454
+ /** Data shapes consumed by `DiagramCanvas` / `buildDiagramScene`. */
2254
2455
 
2255
- interface DiagramRFNode {
2456
+ interface DiagramNode {
2256
2457
  id: string;
2257
2458
  position: {
2258
2459
  x: number;
@@ -2262,23 +2463,29 @@ interface DiagramRFNode {
2262
2463
  label: string;
2263
2464
  };
2264
2465
  type?: string;
2265
- /** Per-node width override (from the heading's `w=` Pandoc param). */
2466
+ /** Per-node width override in canvas units. */
2266
2467
  width?: number;
2267
- /** Per-node height override (from the heading's `h=` Pandoc param). */
2468
+ /** Per-node height override in canvas units. */
2268
2469
  height?: number;
2470
+ /** Render as a background container card (top-anchored label, muted fill). */
2471
+ kind?: 'container';
2269
2472
  }
2270
- interface DiagramRFEdge {
2473
+ interface DiagramEdge {
2271
2474
  id: string;
2272
2475
  source: string;
2273
2476
  target: string;
2274
2477
  label?: string;
2478
+ /** False → no end arrowhead. Undefined keeps the diagram default (arrow). */
2479
+ directed?: boolean;
2480
+ sourceAnchor?: DiagramEdgeAnchor;
2481
+ targetAnchor?: DiagramEdgeAnchor;
2482
+ routing?: ConnectorRouting;
2275
2483
  }
2276
2484
  interface DiagramData {
2277
- nodes: DiagramRFNode[];
2278
- edges: DiagramRFEdge[];
2485
+ nodes: DiagramNode[];
2486
+ edges: DiagramEdge[];
2279
2487
  warnings: string[];
2280
2488
  }
2281
- declare function useDiagramData(editor: Editor$1, parentPos: number): DiagramData;
2282
2489
 
2283
2490
  /**
2284
2491
  * Tiptap Bridge
@@ -2329,9 +2536,10 @@ declare function buildPreviewDoc(doc: Doc): Doc;
2329
2536
  /**
2330
2537
  * TemplateAnnotation — Tiptap Heading Extension
2331
2538
  *
2332
- * Extends Tiptap's built-in Heading node to support `data-template` and
2333
- * `data-template-params` HTML attributes. These attributes store which block
2334
- * template should be used for a heading section.
2539
+ * Extends Tiptap's built-in Heading node to support `data-template`,
2540
+ * `data-template-params`, and `data-template-empty` HTML attributes. These
2541
+ * attributes store the authored template annotation without exposing its raw
2542
+ * `{[…]}` syntax in the Write view.
2335
2543
  *
2336
2544
  * When present, the heading renders a visible badge (styled CSS chip)
2337
2545
  * showing the template name, e.g. `[chart]`.
@@ -2346,27 +2554,6 @@ declare function buildPreviewDoc(doc: Doc): Doc;
2346
2554
  */
2347
2555
  declare const HeadingWithTemplate: _tiptap_core.Node<_tiptap_extension_heading.HeadingOptions, any>;
2348
2556
 
2349
- /**
2350
- * DiagramExtension — Tiptap/ProseMirror plugin that:
2351
- *
2352
- * 1. Mounts a React-Flow canvas (`DiagramWidget`) immediately after every
2353
- * heading whose `dataTemplate === 'diagram'`.
2354
- * 2. Hides the direct sub-headings of each diagram parent (until the next
2355
- * equal-or-shallower heading) by tagging them with a `data-squisq-diagram-child`
2356
- * attribute — CSS in `styles/diagram.css` does the actual hiding.
2357
- *
2358
- * Widgets are rendered as plain DOM nodes attached to a ProseMirror
2359
- * `Decoration.widget`. React is mounted into the widget DOM with
2360
- * `react-dom/client`'s `createRoot`, and unmounted on the widget's
2361
- * `destroy` hook.
2362
- */
2363
-
2364
- interface DiagramExtensionOptions {
2365
- /** When false, the extension is inert (no widgets, no decorations). */
2366
- enabled?: boolean;
2367
- }
2368
- declare const DiagramExtension: Extension<DiagramExtensionOptions, any>;
2369
-
2370
2557
  type DiagramCommand = {
2371
2558
  kind: 'moveNode';
2372
2559
  nodeId: string;
@@ -2400,8 +2587,8 @@ type DiagramCommand = {
2400
2587
  nodeId: string;
2401
2588
  };
2402
2589
  interface DiagramCanvasProps {
2403
- nodes: DiagramRFNode[];
2404
- edges: DiagramRFEdge[];
2590
+ nodes: DiagramNode[];
2591
+ edges: DiagramEdge[];
2405
2592
  onCommand: (cmd: DiagramCommand) => void;
2406
2593
  /** When true, render the maximize button. Click toggles `onToggleMaximize`. */
2407
2594
  showMaximize?: boolean;
@@ -2418,99 +2605,525 @@ interface DiagramCanvasProps {
2418
2605
  onActiveToolIdChange?: (id: string) => void;
2419
2606
  /** Forwarded to the Scene so the host can drive a Delete action. */
2420
2607
  onSelectionChange?: (ids: ReadonlySet<string>) => void;
2608
+ /** Per-editor toolbar bridge for detached scene roots. */
2609
+ textChannel?: SceneTextChannel;
2610
+ }
2611
+ declare function DiagramCanvas({ nodes: incomingNodes, edges: incomingEdges, onCommand, showMaximize, maximized, onToggleMaximize, activeToolId: controlledToolId, onActiveToolIdChange, onSelectionChange, textChannel, }: DiagramCanvasProps): react_jsx_runtime.JSX.Element;
2612
+
2613
+ /**
2614
+ * AsciiDiagramExtension — Tiptap/ProseMirror plugin that turns code blocks
2615
+ * containing ASCII box-and-line diagrams into interactive diagram canvases.
2616
+ *
2617
+ * The FENCE TEXT REMAINS THE SOURCE OF TRUTH: the plugin never converts
2618
+ * the document. For each qualifying codeBlock it:
2619
+ * 1. hides the `<pre>` via a node decoration (or tags it visible-monospace
2620
+ * when the user toggles "source" mode), and
2621
+ * 2. mounts an `AsciiDiagramWidget` after it via a widget decoration.
2622
+ *
2623
+ * Identity: codeBlocks have no persisted id and their content changes on
2624
+ * every canvas edit (self-inflicted fence rewrite), so neither a content
2625
+ * hash nor a raw position can key the widget. Instead the plugin keeps a
2626
+ * POSITION REGISTRY in its state: each qualifying block gets a synthetic
2627
+ * session id (`ascii-N`); on every doc change old positions are remapped
2628
+ * through `tr.mapping` and matched against the new doc walk. Same id →
2629
+ * same widget decoration key → ProseMirror keeps the DOM + React root
2630
+ * alive (pan/zoom survives), exactly like the heading-key trick the
2631
+ * legacy DiagramExtension used.
2632
+ *
2633
+ * Hysteresis: a NEW block must pass full detection (`detectAsciiDiagram`,
2634
+ * ≥2 boxes + thresholds); an already-registered block stays interactive
2635
+ * while its fence still parses to ≥1 box, so deleting down to one node
2636
+ * doesn't kick the user back to a raw code block mid-edit.
2637
+ */
2638
+
2639
+ interface AsciiDiagramBlockEntry {
2640
+ /** Synthetic session id (`ascii-N`), stable across edits for one block. */
2641
+ id: string;
2642
+ /** Document position of the codeBlock node at the current state. */
2643
+ pos: number;
2644
+ }
2645
+ interface AsciiDiagramPluginState {
2646
+ entries: AsciiDiagramBlockEntry[];
2647
+ decorations: DecorationSet;
2648
+ sourceVisible: ReadonlySet<string>;
2649
+ /** Monotonic id allocator. */
2650
+ seq: number;
2651
+ }
2652
+ /** Resolve a registered block's current doc position (null when gone). */
2653
+ declare function findAsciiDiagramBlockPos(editor: Editor$1, blockId: string): number | null;
2654
+ declare function isAsciiSourceVisible(editor: Editor$1, blockId: string): boolean;
2655
+ /** Toggle the raw-fence view for one diagram block (meta-only transaction). */
2656
+ declare function toggleAsciiSource(editor: Editor$1, blockId: string): void;
2657
+ interface AsciiDiagramExtensionOptions {
2658
+ /** When false, the extension is inert (no widgets, no decorations). */
2659
+ enabled?: boolean;
2660
+ textChannel?: SceneTextChannel;
2421
2661
  }
2422
- declare function DiagramCanvas({ nodes: incomingNodes, edges: incomingEdges, onCommand, showMaximize, maximized, onToggleMaximize, activeToolId: controlledToolId, onActiveToolIdChange, onSelectionChange, }: DiagramCanvasProps): react_jsx_runtime.JSX.Element;
2662
+ declare const AsciiDiagramExtension: Extension<AsciiDiagramExtensionOptions, any>;
2423
2663
 
2424
- interface DiagramWidgetProps {
2664
+ interface AsciiDiagramWidgetProps {
2425
2665
  editor: Editor$1;
2426
- /** Stable id derived from the parent heading (slug / `#id`). */
2427
- headingKey: string;
2428
- /** Position of the parent heading at widget-creation time. Used as a
2429
- * fallback when the dynamic lookup fails (e.g. before the first
2430
- * transaction). */
2431
- fallbackParentPos: number;
2666
+ /** Session id from the extension's position registry. */
2667
+ blockId: string;
2668
+ /** Position at widget-creation time display-only fallback. */
2669
+ fallbackPos: number;
2432
2670
  /** Host element used for portal targeting by the maximize overlay. */
2433
2671
  host?: HTMLElement | null;
2672
+ textChannel?: SceneTextChannel;
2434
2673
  }
2435
- declare function DiagramWidget({ editor, headingKey, fallbackParentPos, host }: DiagramWidgetProps): react_jsx_runtime.JSX.Element;
2674
+ declare function AsciiDiagramWidget({ editor, blockId, host, textChannel, }: AsciiDiagramWidgetProps): react_jsx_runtime.JSX.Element | null;
2436
2675
 
2437
2676
  /**
2438
- * Tiptap commands for diagram editing.
2677
+ * Read direction of the ASCII diagram loop: fence text → canvas data.
2439
2678
  *
2440
- * Each command finds the relevant heading inside a diagram section (parent
2441
- * heading + its direct sub-headings until the next equal-or-shallower
2442
- * heading) and mutates either its `data-block-attrs` attribute or its
2443
- * text content. All edits flow back into markdown via the existing
2444
- * `tiptapBridge` round-trip — no parallel data store.
2679
+ * `useAsciiDiagramData` re-derives on every editor transaction (mirroring
2680
+ * the philosophy of the old heading-based `useDiagramData`: no store, so
2681
+ * nothing to invalidate). Parsing is memoized per PMNode instance by the
2682
+ * extension's WeakMap caches, so untouched fences cost nothing.
2683
+ */
2684
+
2685
+ interface AsciiDiagramView {
2686
+ /** Canvas nodes, containers ordered first so their cards paint behind. */
2687
+ nodes: DiagramNode[];
2688
+ edges: DiagramEdge[];
2689
+ warnings: string[];
2690
+ style: 'unicode' | 'ascii';
2691
+ /** The current fence text. */
2692
+ text: string;
2693
+ /** The parse behind `nodes`/`edges` (grid units) — ops operate on this. */
2694
+ diagram: AsciiDiagram;
2695
+ }
2696
+ /** Grid model → canvas model, containers-first for paint order. */
2697
+ declare function asciiDiagramToCanvas(diagram: AsciiDiagram): Pick<AsciiDiagramView, 'nodes' | 'edges'>;
2698
+ /**
2699
+ * Live view of one registered ASCII diagram block. Returns null when the
2700
+ * block no longer exists or no longer parses (the extension will drop the
2701
+ * widget on its next pass).
2445
2702
  */
2703
+ declare function useAsciiDiagramData(editor: Editor$1, blockId: string): AsciiDiagramView | null;
2446
2704
 
2447
- interface HeadingLocation {
2448
- /** Node start position in the doc (absolute). */
2705
+ /**
2706
+ * Write direction of the ASCII diagram loop: canvas command → fence rewrite.
2707
+ *
2708
+ * Every semantic edit is one functional transformation of the fence text
2709
+ * (`renderAscii(applyOp(parseAscii(text)))`) committed as a single
2710
+ * ProseMirror transaction (= a single undo step). Before committing, the
2711
+ * rendered art is re-parsed and verified — if the renderer ever produced
2712
+ * something the parser disagrees with, the command aborts instead of
2713
+ * corrupting the fence.
2714
+ */
2715
+
2716
+ /**
2717
+ * Replace the TEXT inside the codeBlock at `pos` and, when `ensureLanguage`
2718
+ * is given, promote its `language` attribute in the SAME transaction (one
2719
+ * undo step). Promoting the language to the explicit `diagram`/`tree` tag is
2720
+ * how a semantic edit makes the block's identity "sticky" — the language
2721
+ * class survives markdown ↔ Tiptap round-trips, so a once-edited diagram/tree
2722
+ * is re-recognized even after it's flattened. No-op (returns false) only when
2723
+ * BOTH the text is already identical AND the language already matches, so
2724
+ * history stays clean on a true no-op.
2725
+ */
2726
+ declare function replaceAsciiFenceText(editor: Editor$1, pos: number, nextText: string, ensureLanguage?: string): boolean;
2727
+ /**
2728
+ * Reconstruct a broken box-art fence into clean, `diagram`-tagged art in a
2729
+ * single transaction (one undo step). The AsciiDiagramExtension then claims
2730
+ * the tagged fence and mounts the interactive canvas. Returns false when the
2731
+ * block is gone or nothing recoverable (the button simply no-ops).
2732
+ */
2733
+ declare function applyRepairCommand(editor: Editor$1, blockId: string): boolean;
2734
+ /** Full pipeline for a canvas command against a registered fence block. */
2735
+ declare function applyAsciiDiagramCommand(editor: Editor$1, blockId: string, cmd: DiagramCommand): boolean;
2736
+
2737
+ /**
2738
+ * RepairableDiagramExtension — mounts an inline "Repair as diagram" button on
2739
+ * code fences that hold BROKEN box-and-line art.
2740
+ *
2741
+ * The three states of a box-drawing fence partition cleanly:
2742
+ * - a clean diagram → AsciiDiagramExtension mounts the canvas;
2743
+ * - a file tree / outline → TreeViewExtension mounts the outline;
2744
+ * - broken box art → neither claims it (it renders as a faithful
2745
+ * code block), and THIS extension offers a button
2746
+ * to reconstruct it via `repairAsciiDiagram`.
2747
+ *
2748
+ * Unlike the diagram/tree extensions it does NOT hide the fence or mount a
2749
+ * persistent interactive widget — the code stays visible and editable, and a
2750
+ * single click rewrites the fence to clean `diagram`-tagged art (which the
2751
+ * AsciiDiagramExtension then turns into a canvas). So the position registry
2752
+ * only needs to survive until the click; it mirrors the other extensions'
2753
+ * mapping so the button always resolves the right fence.
2754
+ */
2755
+
2756
+ interface RepairableBlockEntry {
2757
+ /** Synthetic session id (`repair-N`), stable across edits for one block. */
2758
+ id: string;
2759
+ /** Document position of the codeBlock node at the current state. */
2449
2760
  pos: number;
2450
- /** The heading PMNode. */
2451
- node: Node;
2452
- /** Parsed attributes derived from the heading's `data-block-attrs` (always defined). */
2453
- attrs: HeadingAttributes;
2454
- /** Computed id: explicit `#id` if set, otherwise the slugified heading text. */
2761
+ }
2762
+ interface RepairablePluginState {
2763
+ entries: RepairableBlockEntry[];
2764
+ decorations: DecorationSet;
2765
+ seq: number;
2766
+ }
2767
+ declare const REPAIRABLE_KEY: PluginKey<RepairablePluginState>;
2768
+ /** True when a codeBlock holds broken box art worth offering to repair. */
2769
+ declare function isRepairableFence(node: Node): boolean;
2770
+ /** Resolve a registered block's current doc position (null when gone). */
2771
+ declare function findRepairableBlockPos(editor: Editor$1, blockId: string): number | null;
2772
+ /** Handler the mounted button invokes; wired by the host via extension options. */
2773
+ interface RepairableDiagramExtensionOptions {
2774
+ enabled?: boolean;
2775
+ /** Invoked when a repair button is clicked, with the block's synthetic id. */
2776
+ onRepair?: (editor: Editor$1, blockId: string) => void;
2777
+ }
2778
+ declare const RepairableDiagramExtension: Extension<RepairableDiagramExtensionOptions, any>;
2779
+
2780
+ /**
2781
+ * Pure data operations over the ASCII diagram model — the write-direction
2782
+ * half of the fence-is-source-of-truth loop:
2783
+ *
2784
+ * fence text → parseAsciiDiagram → op → renderAsciiDiagram → fence text
2785
+ *
2786
+ * Every op returns a new AsciiDiagram (inputs are never mutated) and
2787
+ * maintains the invariants the renderer/parser fixpoint relies on:
2788
+ * container moves translate whole subtrees, removals promote children and
2789
+ * drop incident edges, sizes never fall below what a label needs.
2790
+ */
2791
+
2792
+ /**
2793
+ * Make arbitrary (rename-dialog) input safe as a box label: box-drawing /
2794
+ * arrow glyphs would corrupt the art, and the Scene's inline editor is
2795
+ * single-line, so newlines collapse to spaces.
2796
+ */
2797
+ declare function sanitizeAsciiLabel(label: string): string;
2798
+ /** Move a node to (col, row); a container drags its whole subtree along. */
2799
+ declare function moveNodeOp(diagram: AsciiDiagram, nodeId: string, col: number, row: number): AsciiDiagram;
2800
+ /** Resize a node (grid cells). Clamped so the label always fits. */
2801
+ declare function resizeNodeOp(diagram: AsciiDiagram, nodeId: string, wCols: number, hRows: number): AsciiDiagram;
2802
+ /** Add a directed edge; duplicates (same source/target/label) are no-ops. */
2803
+ declare function addEdgeOp(diagram: AsciiDiagram, source: string, target: string, label?: string): AsciiDiagram;
2804
+ /**
2805
+ * Remove an edge. A label-qualified call removes the exact match; without
2806
+ * a label the first (source, target) match goes — mirroring the legacy
2807
+ * `removeConnection` semantics.
2808
+ */
2809
+ declare function removeEdgeOp(diagram: AsciiDiagram, source: string, target: string, label?: string): AsciiDiagram;
2810
+ /**
2811
+ * Rename a node. The label drives the node's parse-derived id, so edges
2812
+ * and containment references are rewritten to the id the next parse will
2813
+ * produce. (Selection in the canvas drops after a rename — documented.)
2814
+ */
2815
+ declare function renameNodeOp(diagram: AsciiDiagram, nodeId: string, label: string): AsciiDiagram;
2816
+ /** Add a node at (col, row). Inherits a container when placed inside one. */
2817
+ declare function addNodeOp(diagram: AsciiDiagram, opts: {
2818
+ col: number;
2819
+ row: number;
2820
+ label?: string;
2821
+ }): {
2822
+ diagram: AsciiDiagram;
2823
+ label: string;
2824
+ };
2825
+ /**
2826
+ * Remove a node: incident edges (both directions) drop, direct children
2827
+ * are promoted to the removed node's own container (or top level).
2828
+ */
2829
+ declare function removeNodeOp(diagram: AsciiDiagram, nodeId: string): AsciiDiagram;
2830
+
2831
+ /**
2832
+ * Paste gate for bare (unfenced) ASCII diagram art.
2833
+ *
2834
+ * `+--+ | |` art pasted as plain text is otherwise mangled: its `| x |`
2835
+ * rows match the GFM table-row pattern in `detectMarkdown`, so the paste
2836
+ * handler routes it through the markdown converter, fails table
2837
+ * validation, and emits one broken paragraph per line. When this gate
2838
+ * matches, the paste handler inserts the text verbatim into a fresh code
2839
+ * block instead — which the AsciiDiagramExtension then picks up as an
2840
+ * interactive diagram.
2841
+ */
2842
+ declare function shouldPasteAsAsciiFence(text: string): boolean;
2843
+
2844
+ /**
2845
+ * TreeViewExtension — Tiptap/ProseMirror plugin that turns code blocks
2846
+ * containing ASCII file-tree / outline art into interactive outline editors.
2847
+ *
2848
+ * Structurally identical to AsciiDiagramExtension (position registry, stable
2849
+ * synthetic ids, hysteresis, self-rewrite-survival via the decoration key);
2850
+ * only the detect/parse gates and class names differ. The fence text stays
2851
+ * the source of truth — every edit re-renders the tree art.
2852
+ *
2853
+ * Mutual exclusion with the diagram extension: a fence with ≥2 closed boxes
2854
+ * is a diagram, never a tree (checked in both gates), so at most one
2855
+ * extension claims any given fence.
2856
+ */
2857
+
2858
+ interface TreeBlockEntry {
2859
+ /** Synthetic session id (`tree-N`), stable across edits for one block. */
2455
2860
  id: string;
2861
+ /** Document position of the codeBlock node at the current state. */
2862
+ pos: number;
2863
+ }
2864
+ interface TreeViewPluginState {
2865
+ entries: TreeBlockEntry[];
2866
+ decorations: DecorationSet;
2867
+ seq: number;
2868
+ }
2869
+ declare function findTreeBlockPos(editor: Editor$1, blockId: string): number | null;
2870
+ interface TreeViewExtensionOptions {
2871
+ /** When false, the extension is inert (no widgets, no decorations). */
2872
+ enabled?: boolean;
2873
+ }
2874
+ declare const TreeViewExtension: Extension<TreeViewExtensionOptions, any>;
2875
+
2876
+ interface TreeOutlineWidgetProps {
2877
+ editor: Editor$1;
2878
+ blockId: string;
2879
+ fallbackPos: number;
2880
+ host?: HTMLElement | null;
2881
+ }
2882
+ declare function TreeOutlineWidget({ editor, blockId }: TreeOutlineWidgetProps): react_jsx_runtime.JSX.Element | null;
2883
+
2884
+ /**
2885
+ * Read direction of the tree loop: fence text → outline view.
2886
+ *
2887
+ * `useTreeViewData` re-derives on every editor transaction; parsing is
2888
+ * memoized per PMNode by the extension's WeakMap caches, so untouched
2889
+ * fences cost nothing.
2890
+ */
2891
+
2892
+ interface TreeViewData {
2893
+ tree: Tree;
2894
+ text: string;
2895
+ warnings: string[];
2456
2896
  }
2897
+ /** Live view of one registered tree block; null when it no longer parses. */
2898
+ declare function useTreeViewData(editor: Editor$1, blockId: string): TreeViewData | null;
2899
+
2457
2900
  /**
2458
- * Find the diagram section that starts at `parentPos` (the position of the
2459
- * parent heading with `dataTemplate === 'diagram'`). Returns the headings
2460
- * that should appear as diagram nodes — defined as every heading at the
2461
- * **shallowest** depth greater than the parent within the section, until
2462
- * the next equal-or-shallower heading.
2901
+ * Write direction of the tree loop: outline command fence rewrite.
2463
2902
  *
2464
- * Using the shallowest deeper depth (rather than a strict parentDepth + 1)
2465
- * mirrors `markdownToDoc`'s stack behavior: when authors skip a level
2466
- * (e.g. `# parent` + `### child`), those `###` headings are still treated
2467
- * as direct children of the `#` parent. Any headings deeper than the
2468
- * detected child depth are sub-sections of a node and are not surfaced as
2469
- * separate diagram nodes.
2903
+ * parse op render verify-reparse single-transaction fence replace
2904
+ * (one undo step). Reuses the generic `replaceAsciiFenceText` (it only
2905
+ * touches codeBlock text, attributes untouched).
2470
2906
  */
2471
- declare function listDiagramChildren(editor: Editor$1, parentPos: number): HeadingLocation[];
2907
+
2908
+ type TreeCommand = {
2909
+ kind: 'addItem';
2910
+ targetId: string;
2911
+ position: 'child' | 'siblingAfter';
2912
+ label?: string;
2913
+ isDir?: boolean;
2914
+ } | {
2915
+ kind: 'renameItem';
2916
+ id: string;
2917
+ label: string;
2918
+ } | {
2919
+ kind: 'indentItem';
2920
+ id: string;
2921
+ } | {
2922
+ kind: 'outdentItem';
2923
+ id: string;
2924
+ } | {
2925
+ kind: 'moveItemUp';
2926
+ id: string;
2927
+ } | {
2928
+ kind: 'moveItemDown';
2929
+ id: string;
2930
+ } | {
2931
+ kind: 'removeItem';
2932
+ id: string;
2933
+ } | {
2934
+ kind: 'toggleDir';
2935
+ id: string;
2936
+ };
2937
+
2938
+ declare function applyTreeCommand(editor: Editor$1, blockId: string, cmd: TreeCommand): boolean;
2939
+
2940
+ /**
2941
+ * Pure outline operations over the tree model — the write-direction half of
2942
+ * the fence-is-source-of-truth loop:
2943
+ *
2944
+ * fence text → parseTree → op → renderTree → fence text
2945
+ *
2946
+ * Every op returns a NEW Tree (inputs untouched). These are the genuinely
2947
+ * new operations with no diagram analog: indent / outdent (re-parent a node
2948
+ * carrying its subtree), move-up / move-down (reorder siblings), plus
2949
+ * add / rename / remove / toggle-directory. Connector rails re-derive in
2950
+ * render, so ops only touch structure + labels.
2951
+ */
2952
+
2953
+ /** Make an arbitrary rename safe as a tree label: no connector glyphs / newlines. */
2954
+ declare function sanitizeTreeLabel(label: string): string;
2955
+ declare function renameItemOp(tree: Tree, id: string, label: string): Tree;
2956
+ declare function addItemOp(tree: Tree, targetId: string, position: 'child' | 'siblingAfter', label?: string, isDir?: boolean): Tree;
2957
+ declare function removeItemOp(tree: Tree, id: string): Tree;
2958
+ /** Node becomes the last child of its immediate preceding sibling. */
2959
+ declare function indentItemOp(tree: Tree, id: string): Tree;
2960
+ /** Node becomes a sibling of its parent, inserted directly after it (subtree carried). */
2961
+ declare function outdentItemOp(tree: Tree, id: string): Tree;
2962
+ declare function moveItemUpOp(tree: Tree, id: string): Tree;
2963
+ declare function moveItemDownOp(tree: Tree, id: string): Tree;
2964
+ /** Toggle the trailing-slash directory marker on a node's label. */
2965
+ declare function toggleDirOp(tree: Tree, id: string): Tree;
2966
+
2967
+ /**
2968
+ * Paste gate for bare (unfenced) ASCII tree art. `├──`/`└──` file-tree lines
2969
+ * would otherwise route through the markdown converter and mangle; when this
2970
+ * matches, the paste handler drops the text verbatim into a fresh code block
2971
+ * that the TreeViewExtension picks up as an interactive outline.
2972
+ */
2973
+ declare function shouldPasteAsTreeFence(text: string): boolean;
2974
+
2975
+ /**
2976
+ * TimelineViewExtension — mounts a WYSIWYG timeline editor over qualifying
2977
+ * authored timeline code fences while keeping the fence text as source of
2978
+ * truth. Every semantic edit is rendered back through the core codec.
2979
+ */
2980
+
2981
+ interface TimelineBlockEntry {
2982
+ /** Synthetic session id, stable across edits to one fence. */
2983
+ id: string;
2984
+ /** Current document position of the codeBlock node. */
2985
+ pos: number;
2986
+ }
2987
+ interface TimelineViewPluginState {
2988
+ entries: TimelineBlockEntry[];
2989
+ decorations: DecorationSet;
2990
+ seq: number;
2991
+ }
2992
+ declare const TIMELINE_VIEW_KEY: PluginKey<TimelineViewPluginState>;
2993
+ /** Conservative full-detection gate used when first claiming a code fence. */
2994
+ declare function getTimelineForNode(node: Node): AsciiTimeline | null;
2995
+ /** Relaxed/sticky gate for a block already registered by this extension. */
2996
+ declare function parseTimelineForNode(node: Node): AsciiTimeline | null;
2997
+ declare function findTimelineBlockPos(editor: Editor$1, blockId: string): number | null;
2998
+ interface TimelineViewExtensionOptions {
2999
+ /** When false, the extension does not claim fences or mount widgets. */
3000
+ enabled?: boolean;
3001
+ }
3002
+ declare const TimelineViewExtension: Extension<TimelineViewExtensionOptions, any>;
3003
+
3004
+ interface TimelineEditorWidgetProps {
3005
+ editor: Editor$1;
3006
+ blockId: string;
3007
+ }
3008
+ declare function TimelineEditorWidget({ editor, blockId }: TimelineEditorWidgetProps): react_jsx_runtime.JSX.Element | null;
3009
+
3010
+ /** Live read-direction adapter from a registered timeline fence to React. */
3011
+
3012
+ interface TimelineViewData {
3013
+ timeline: AsciiTimeline;
3014
+ text: string;
3015
+ warnings: string[];
3016
+ }
3017
+ declare function useTimelineData(editor: Editor$1, blockId: string): TimelineViewData | null;
3018
+
2472
3019
  /**
2473
- * Update a node's `x` / `y` attributes from a drag.
3020
+ * Pure edits over the authored ASCII timeline model.
2474
3021
  *
2475
- * Before writing the moved node, this also "freezes" any siblings that
2476
- * lack an explicit position by snapshotting their currently-displayed
2477
- * (auto-laid) coordinates. Without that, `computeDiagramLayout`'s grid
2478
- * auto-placement is relative to the bounding box of pinned nodes — so
2479
- * dragging one node would pull every unpinned sibling along behind it.
2480
- * Freezing converts the implicit layout into explicit per-node
2481
- * positions on the first interaction, after which each node moves
2482
- * independently.
3022
+ * The code fence remains the source of truth. Canvas coordinates are
3023
+ * normalized to the same global, shared scale used by
3024
+ * `asciiTimelineToTemplateData`; commands render the edited model back into
3025
+ * canonical fence text after applying one of these operations.
2483
3026
  */
2484
- declare function moveNode(editor: Editor$1, parentPos: number, nodeId: string, x: number, y: number): boolean;
3027
+
3028
+ interface TimelineEventPatch {
3029
+ label?: string;
3030
+ /** `null` clears the optional description. */
3031
+ description?: string | null;
3032
+ side?: AsciiTimelineSide;
3033
+ /** `null` restores the label side/default placement. */
3034
+ descriptionSide?: AsciiTimelineSide | null;
3035
+ callout?: boolean;
3036
+ marker?: AsciiTimelineMarker;
3037
+ /** Normalized position on the global timeline scale. */
3038
+ position?: number;
3039
+ }
3040
+ interface AddTimelineEventOptions {
3041
+ id?: string;
3042
+ label?: string;
3043
+ description?: string;
3044
+ side?: AsciiTimelineSide;
3045
+ descriptionSide?: AsciiTimelineSide;
3046
+ callout?: boolean;
3047
+ marker?: AsciiTimelineMarker;
3048
+ }
3049
+ interface AddTimelineEventResult {
3050
+ timeline: AsciiTimeline;
3051
+ eventId: string;
3052
+ }
2485
3053
  /**
2486
- * Add a connection from `sourceId` to `targetId` (optionally typed). No-op
2487
- * if the same connection already exists.
3054
+ * Normalize editable one-line prose exactly as the canonical core renderer
3055
+ * does. This prevents the verified command path from accepting a value that
3056
+ * is silently reinterpreted as timeline syntax on its first render.
2488
3057
  */
2489
- declare function addConnection(editor: Editor$1, parentPos: number, sourceId: string, targetId: string, type?: string): boolean;
3058
+ declare function sanitizeTimelineText(value: string): string;
3059
+ /** Return a globally unique, renderer-safe event id. */
3060
+ declare function nextTimelineEventId(timeline: AsciiTimeline, base?: string): string;
2490
3061
  /**
2491
- * Remove a connection from `sourceId` to `targetId`. If `type` is provided,
2492
- * only the matching-typed entry is removed; otherwise the first match
2493
- * (regardless of type) is removed.
3062
+ * Add a visible point to `trackId` at a normalized global rail position.
3063
+ * Returns the stable id so the canvas can select/focus the new point after
3064
+ * the fence rewrite.
2494
3065
  */
2495
- declare function removeConnection(editor: Editor$1, parentPos: number, sourceId: string, targetId: string, type?: string): boolean;
3066
+ declare function addTimelineEventOp(timeline: AsciiTimeline, trackId: string, position: number, options?: AddTimelineEventOptions): AddTimelineEventResult | null;
3067
+ /** Update one point without changing its stable id or branch endpoints. */
3068
+ declare function updateTimelineEventOp(timeline: AsciiTimeline, eventId: string, patch: TimelineEventPatch): AsciiTimeline;
2496
3069
  /**
2497
- * Replace a heading's text content (used when the user renames a node
2498
- * via a double-click in the canvas).
3070
+ * Remove a point and every incident branch. Empty tracks are removed because
3071
+ * the canonical renderer cannot represent them. The last point in the whole
3072
+ * timeline is retained so an edit cannot erase its own source fence/widget.
2499
3073
  */
2500
- declare function renameNode(editor: Editor$1, parentPos: number, nodeId: string, newText: string): boolean;
3074
+ declare function removeTimelineEventOp(timeline: AsciiTimeline, eventId: string): AsciiTimeline;
3075
+
2501
3076
  /**
2502
- * Insert a new heading node at the end of the diagram section. The new
2503
- * heading carries `data-block-attrs` with the supplied id and position,
2504
- * so the freshly-inserted node appears in React Flow at the expected
2505
- * coordinates.
3077
+ * Write direction for the WYSIWYG timeline editor:
3078
+ *
3079
+ * fence text -> parse -> pure op -> render -> verify -> one fence rewrite
3080
+ *
3081
+ * The original code block remains the source of truth and every successful
3082
+ * edit is a single ProseMirror transaction/undo step.
2506
3083
  */
2507
- declare function addNode(editor: Editor$1, parentPos: number, id: string, label: string, x: number, y: number): boolean;
3084
+
3085
+ type TimelineCommand = {
3086
+ kind: 'addEvent';
3087
+ trackId: string;
3088
+ /** Normalized position on the global timeline rail. */
3089
+ position: number;
3090
+ id?: string;
3091
+ label?: string;
3092
+ description?: string;
3093
+ side?: AsciiTimelineSide;
3094
+ descriptionSide?: AsciiTimelineSide;
3095
+ callout?: boolean;
3096
+ marker?: AsciiTimelineMarker;
3097
+ } | {
3098
+ kind: 'updateEvent';
3099
+ eventId: string;
3100
+ patch: TimelineEventPatch;
3101
+ } | {
3102
+ kind: 'removeEvent';
3103
+ eventId: string;
3104
+ };
3105
+ interface TimelineCommandResult {
3106
+ applied: boolean;
3107
+ /** Present after add so the widget can select/focus the new marker. */
3108
+ eventId?: string;
3109
+ /** Why an otherwise valid semantic edit was deliberately blocked. */
3110
+ reason?: 'read-only' | 'unsafe-source';
3111
+ }
2508
3112
  /**
2509
- * Remove a child node's heading (and any body content under it up to the
2510
- * next heading). Also strips inbound `connectsTo` references on remaining
2511
- * siblings so the diagram doesn't carry dangling targets.
3113
+ * Semantic operations replace the whole fence with canonical rendered art.
3114
+ * Fail closed when that would discard source the timeline model cannot
3115
+ * represent. Warnings catch unresolved/unlabeled constructs; the semantic
3116
+ * round-trip catches renderer normalization that changes modeled content;
3117
+ * exact metadata validation rejects partially consumed attrs; and a linear
3118
+ * semantic-residue comparison catches ignored prose/symbol rows without
3119
+ * reparsing a successively shorter document for every source line.
2512
3120
  */
2513
- declare function removeNode(editor: Editor$1, parentPos: number, nodeId: string): boolean;
3121
+ declare function isTimelineSourceSafeForSemanticEdit(source: string, timeline: AsciiTimeline): boolean;
3122
+ /** Apply one semantic timeline command to a registered fence block. */
3123
+ declare function applyTimelineCommand(editor: Editor$1, blockId: string, command: TimelineCommand): TimelineCommandResult;
3124
+
3125
+ /** Paste gate for bare, high-confidence Unicode timeline art. */
3126
+ declare function shouldPasteAsTimelineFence(text: string): boolean;
2514
3127
 
2515
3128
  interface JsonEditorProps {
2516
3129
  /** Schema describing the value's shape (with optional `squisq` hints). */
@@ -2915,6 +3528,443 @@ declare function encodeTimingJson(timing: TimingJson): Uint8Array;
2915
3528
  */
2916
3529
  declare function timingPathFor(audioRelativePath: string): string;
2917
3530
 
3531
+ /** Editor plumbing the recording flow needs; omit for prompter-only use. */
3532
+ interface TeleprompterRecordingDeps {
3533
+ mediaProvider: MediaProvider;
3534
+ container: ContentContainer | null;
3535
+ markdownSource: string;
3536
+ setMarkdownSource: (next: string) => void;
3537
+ bumpMediaRevision: () => void;
3538
+ }
3539
+ interface TeleprompterViewProps {
3540
+ doc: Doc | null;
3541
+ theme: Theme;
3542
+ /** Kept for API symmetry with PreviewPanel; recording uses `recording.container`. */
3543
+ workspaceContainer?: ContentContainer | null;
3544
+ /** Media base path (reserved for future preview integrations). */
3545
+ basePath?: string;
3546
+ /**
3547
+ * Optional audience-window portal owned by the editor's Presentation mode.
3548
+ * The main controller remains authoritative; only this live surface is
3549
+ * mirrored into the target.
3550
+ */
3551
+ presentationTarget?: HTMLElement | null;
3552
+ /** Recording deps; null/omitted disables the Record affordance. */
3553
+ recording?: TeleprompterRecordingDeps | null;
3554
+ }
3555
+ declare function TeleprompterView(props: TeleprompterViewProps): react_jsx_runtime.JSX.Element;
3556
+
3557
+ /**
3558
+ * Mic capture + PCM transport for the teleprompter.
3559
+ *
3560
+ * getUserMedia → AudioContext → AudioWorklet tap → subscriber callbacks
3561
+ * with 1024-sample Float32Array hops on the main thread. The DSP itself
3562
+ * lives in core (`@bendyline/squisq/narration`) — this hook only moves
3563
+ * samples. Falls back to a ScriptProcessorNode when `audioWorklet` is
3564
+ * unavailable (same push model, so pacing still isn't tied to rAF).
3565
+ */
3566
+ type MicAnalysisStatus = 'idle' | 'starting' | 'live' | 'error';
3567
+ type PcmHopListener = (pcm: Float32Array, audioTimeSec: number) => void;
3568
+ interface MicAnalysisHandle {
3569
+ status: MicAnalysisStatus;
3570
+ error: Error | null;
3571
+ /** The live mic stream (feeds the narration recorder too), or null. */
3572
+ stream: MediaStream | null;
3573
+ /** AudioContext sample rate once live. */
3574
+ sampleRate: number | null;
3575
+ /** Known audio inputs (labels appear after the first grant). */
3576
+ devices: MediaDeviceInfo[];
3577
+ /**
3578
+ * Start (or restart) capture. Resolves with the live stream — callers
3579
+ * that need it immediately must use the return value, not the `stream`
3580
+ * state field, which only updates on the NEXT render (stale-closure
3581
+ * hazard right after an await). Null on failure/supersession.
3582
+ */
3583
+ start: (deviceId: string | null) => Promise<MediaStream | null>;
3584
+ stop: () => void;
3585
+ /** Subscribe to PCM hops; returns an unsubscribe. */
3586
+ subscribeHop: (listener: PcmHopListener) => () => void;
3587
+ }
3588
+ declare function useMicAnalysis(): MicAnalysisHandle;
3589
+
3590
+ /**
3591
+ * Narration recorder for the teleprompter — an in-place (no modal)
3592
+ * capture flow.
3593
+ *
3594
+ * Audio records THE MIC ANALYSIS STREAM (what paces the prompter is
3595
+ * exactly what lands in the take); the optional camera is a separate
3596
+ * video-only capture whose start skew vs the audio recorder is measured
3597
+ * and persisted (`cameraOffsetSec`) — the audio file is the doc clock,
3598
+ * so camera skew never affects narration timing. While recording, a
3599
+ * sparse live trace of the prompter position is sampled; after stop,
3600
+ * the take is decoded and run through core's offline aligner
3601
+ * (`alignNarration`) to produce word/block timestamps for the sidecar.
3602
+ * Decode/alignment failure degrades gracefully: saving still works,
3603
+ * just without re-timing.
3604
+ */
3605
+
3606
+ type NarrationRecorderState = 'idle' | 'starting' | 'recording' | 'processing' | 'review' | 'saving' | 'error';
3607
+ interface NarrationTake {
3608
+ audioBlob: Blob;
3609
+ audioMime: string;
3610
+ audioExt: string;
3611
+ cameraBlob: Blob | null;
3612
+ cameraMime: string | null;
3613
+ cameraExt: string | null;
3614
+ durationSec: number;
3615
+ cameraOffsetSec: number | undefined;
3616
+ trace: NarrationTrace;
3617
+ alignment: NarrationAlignment | null;
3618
+ script: NarrationScript;
3619
+ }
3620
+ interface UseNarrationRecorderOptions {
3621
+ mic: MicAnalysisHandle;
3622
+ getScript: () => NarrationScript | null;
3623
+ /** Live prompter position, sampled into the trace while recording. */
3624
+ getWordPos: () => number;
3625
+ getMicDeviceId: () => string | null;
3626
+ /** Fired when capture actually starts (View starts the prompter). */
3627
+ onRecordingStart?: () => void;
3628
+ onRecordingStop?: () => void;
3629
+ }
3630
+ interface NarrationRecorderController {
3631
+ state: NarrationRecorderState;
3632
+ error: Error | null;
3633
+ withCamera: boolean;
3634
+ setWithCamera: (on: boolean) => void;
3635
+ /** Live camera stream for the self-view while recording. */
3636
+ cameraStream: MediaStream | null;
3637
+ take: NarrationTake | null;
3638
+ start: () => Promise<void>;
3639
+ stop: () => Promise<void>;
3640
+ retake: () => void;
3641
+ discard: () => void;
3642
+ /** Transition into/out of 'saving'; the View owns the actual I/O. */
3643
+ beginSave: () => void;
3644
+ finishSave: (ok: boolean, error?: Error) => void;
3645
+ }
3646
+ declare function useNarrationRecorder(options: UseNarrationRecorderOptions): NarrationRecorderController;
3647
+
3648
+ /**
3649
+ * Pure save-plan builder for a narration take, plus its executor.
3650
+ *
3651
+ * Follows the recorder's conventions (`RecorderModal.handleSave`):
3652
+ * audio at `audio/<narration-…>` via `MediaProvider.addMedia` (the
3653
+ * RETURNED path is authoritative — providers may rename), the timing
3654
+ * sidecar at `<audio>.timing.json` via `container.writeFile` (falling
3655
+ * back to `addMedia` with a warning), and ONE `setMarkdownSource` write
3656
+ * composing every markdown edit from a single snapshot (the single-write
3657
+ * rule — successive writes each derive from stale source and clobber
3658
+ * each other).
3659
+ *
3660
+ * Block timings deliberately do NOT get baked into heading `duration=`
3661
+ * pins: pins outrank narration in `applyNarrationTiming`, so baking
3662
+ * them would shadow every retake. The sidecar owns the timing.
3663
+ */
3664
+
3665
+ interface NarrationSavePlanArgs {
3666
+ script: NarrationScript;
3667
+ /** Null when decode/alignment failed — the sidecar still saves (empty timing). */
3668
+ alignment: NarrationAlignment | null;
3669
+ durationSec: number;
3670
+ audioExt: string;
3671
+ cameraExt: string | null;
3672
+ baseWpm: number;
3673
+ cameraOffsetSec?: number;
3674
+ }
3675
+ interface NarrationSavePlan {
3676
+ audioRelativeName: string;
3677
+ cameraRelativeName: string | null;
3678
+ sidecarPayload: NarrationTimingJsonV3;
3679
+ /** Sidecar path for a given (possibly renamed) saved audio path. */
3680
+ sidecarPathFor: (savedAudioPath: string) => string;
3681
+ /** Compose ALL markdown edits from one source snapshot. */
3682
+ nextMarkdown: (currentSource: string, savedAudioPath: string, savedCameraPath: string | null) => string;
3683
+ }
3684
+ declare function buildNarrationSavePlan(args: NarrationSavePlanArgs): NarrationSavePlan;
3685
+ interface ExecuteNarrationSaveDeps {
3686
+ mediaProvider: MediaProvider;
3687
+ container: ContentContainer | null;
3688
+ markdownSource: string;
3689
+ setMarkdownSource: (next: string) => void;
3690
+ bumpMediaRevision: () => void;
3691
+ }
3692
+ interface NarrationSaveResult {
3693
+ audioPath: string;
3694
+ cameraPath: string | null;
3695
+ sidecarPath: string;
3696
+ }
3697
+ /** Execute a save plan: media writes, sidecar, then the single markdown write. */
3698
+ declare function executeNarrationSave(plan: NarrationSavePlan, take: {
3699
+ audioBlob: Blob;
3700
+ audioMime: string;
3701
+ cameraBlob: Blob | null;
3702
+ cameraMime: string | null;
3703
+ }, deps: ExecuteNarrationSaveDeps): Promise<NarrationSaveResult>;
3704
+
3705
+ /**
3706
+ * Pure markdown edit: insert (or replace) the narration reference at the
3707
+ * start of the document.
3708
+ *
3709
+ * The narration take is referenced by a preamble media annotation —
3710
+ * `{[audio src=audio/narration-….webm anchor=document]}` — the canonical
3711
+ * authored form `markdownToDoc` lifts into `doc.documentMedia`. A prior
3712
+ * teleprompter take's line (matched by the `audio/narration-` prefix +
3713
+ * `anchor=document`) is replaced, so retakes swap the reference instead
3714
+ * of stacking narrations. The optional camera companion rides on the
3715
+ * next line as an inline `<video>` (deliberately NOT doc-anchored:
3716
+ * document-anchored video renders full-bleed behind every block and is
3717
+ * excluded from export audio — not a talking head).
3718
+ */
3719
+ declare function narrationAnnotationLine(audioPath: string): string;
3720
+ declare function cameraVideoLine(cameraPath: string): string;
3721
+ /**
3722
+ * Insert the narration preamble after the frontmatter (or at the top),
3723
+ * replacing any previous teleprompter take's lines.
3724
+ */
3725
+ declare function insertNarrationPreamble(source: string, audioPath: string, cameraPath: string | null): string;
3726
+
3727
+ interface TeleprompterSurfaceProps {
3728
+ script: NarrationScript;
3729
+ /** Fractional word position; floor is the active token. */
3730
+ wordPos: number;
3731
+ fontSizePx: number;
3732
+ mirrored: boolean;
3733
+ lineGuide: boolean;
3734
+ countdownRemaining: number | null;
3735
+ recordingIndicator: boolean;
3736
+ theme: Theme;
3737
+ /** Hide block markers / tighten padding for small float windows. */
3738
+ compact?: boolean;
3739
+ /** Click a word to jump the prompter there. */
3740
+ onSeekToken?: (tokenIndex: number) => void;
3741
+ }
3742
+ declare function TeleprompterSurface({ script, wordPos, fontSizePx, mirrored, lineGuide, countdownRemaining, recordingIndicator, theme, compact, onSeekToken, }: TeleprompterSurfaceProps): react_jsx_runtime.JSX.Element;
3743
+
3744
+ /**
3745
+ * Shared types for the Narrate (teleprompter) display mode.
3746
+ */
3747
+ interface TeleprompterPrefs {
3748
+ /** Prompter type size in px (28–96). */
3749
+ fontSizePx: number;
3750
+ /** Beam-splitter mirror flip. */
3751
+ mirrored: boolean;
3752
+ /** Base speaking rate in words per minute (80–260). */
3753
+ baseWpm: number;
3754
+ /** Voice-adaptive pacing on/off; off = constant-rate manual mode. */
3755
+ voiceTracking: boolean;
3756
+ /** VAD sensitivity 0–1 (0.5 = engine defaults). */
3757
+ vadSensitivity: number;
3758
+ /** Countdown before the prompter starts rolling. */
3759
+ countdownSec: 0 | 3 | 5 | 10;
3760
+ /** Eye-line chevrons + focus band. */
3761
+ lineGuide: boolean;
3762
+ /** Preferred mic device id (null = system default). */
3763
+ micDeviceId: string | null;
3764
+ }
3765
+ declare const DEFAULT_TELEPROMPTER_PREFS: TeleprompterPrefs;
3766
+ type PrompterTransport = 'stopped' | 'countdown' | 'rolling' | 'paused' | 'finished';
3767
+ /** Floating-surface tier, best first. */
3768
+ type FloatTier = 'document-pip' | 'video-pip' | 'popup' | 'docked';
3769
+
3770
+ /**
3771
+ * The teleprompter controller — single source of truth, always in the
3772
+ * MAIN window (floats are render targets only).
3773
+ *
3774
+ * Loop-ownership rule: **the audio worklet owns time; the main window
3775
+ * owns state; the visible surface owns pixels.** Voice-mode position
3776
+ * advances on worklet PCM hops (immune to rAF/timer throttling while
3777
+ * the browser is occluded by recording software); manual constant-rate
3778
+ * mode uses rAF and is documented as best-effort under occlusion. React
3779
+ * state publishes at ~15 Hz; per-hop subscribers (`subscribeTick`)
3780
+ * exist for the video-PiP canvas pump.
3781
+ */
3782
+
3783
+ interface TeleprompterController {
3784
+ script: NarrationScript | null;
3785
+ transport: PrompterTransport;
3786
+ countdownRemaining: number | null;
3787
+ /** Fractional word position (published ~15 Hz). */
3788
+ wordPos: number;
3789
+ /** Smoothed mic level 0–1 for the meter. */
3790
+ micLevel: number;
3791
+ /** VAD flag for the meter tint. */
3792
+ voiceActive: boolean;
3793
+ mic: MicAnalysisHandle;
3794
+ prefs: TeleprompterPrefs;
3795
+ setPrefs: (patch: Partial<TeleprompterPrefs>) => void;
3796
+ play: () => void;
3797
+ pause: () => void;
3798
+ restart: () => void;
3799
+ /** Move the prompter by whole tokens and re-anchor voice tracking. */
3800
+ nudge: (deltaTokens: number) => void;
3801
+ /** Jump to an absolute token index (e.g. click a block marker). */
3802
+ seekToToken: (tokenIndex: number) => void;
3803
+ /** Per-analysis-tick subscription (video-PiP pump). Not throttled. */
3804
+ subscribeTick: (cb: (wordPos: number) => void) => () => void;
3805
+ handleKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
3806
+ }
3807
+ /** Map the 0–1 sensitivity pref onto VAD thresholds (0.5 = engine defaults). */
3808
+ declare function vadConfigForSensitivity(sensitivity: number): Partial<VadConfig>;
3809
+ declare function useTeleprompter(opts: {
3810
+ doc: Doc | null;
3811
+ }): TeleprompterController;
3812
+
3813
+ /**
3814
+ * Floating-teleprompter window manager — framework-free.
3815
+ *
3816
+ * Capability ladder, best first:
3817
+ * 1. `document-pip` — Document Picture-in-Picture (Chromium 116+,
3818
+ * Firefox 151+): a true always-on-top window hosting live DOM; the
3819
+ * React surface portals into it.
3820
+ * 2. `video-pip` — canvas → `captureStream(0)` → `<video>` →
3821
+ * `requestPictureInPicture()` (Safari's only always-on-top path;
3822
+ * `webkitSetPresentationMode` fallback). Read-only: the main
3823
+ * window draws frames and calls `requestFrame()` on analysis
3824
+ * ticks — never rAF, which throttles under occlusion.
3825
+ * 3. `popup` — `window.open` (positionable, not always-on-top).
3826
+ * 4. `docked` — no float.
3827
+ *
3828
+ * Every tier is feature-detected at open time and falls through to the
3829
+ * next on ANY failure. All interactive state stays in the main window;
3830
+ * floats are render targets only.
3831
+ */
3832
+
3833
+ interface FloatOpenOptions {
3834
+ width: number;
3835
+ height: number;
3836
+ /** Try this tier first; the ladder continues below it on failure. */
3837
+ preferredTier?: FloatTier;
3838
+ title: string;
3839
+ }
3840
+ interface CanvasSink {
3841
+ canvas: HTMLCanvasElement;
3842
+ width: number;
3843
+ height: number;
3844
+ /** Push the freshly drawn canvas frame into the PiP video. */
3845
+ requestFrame: () => void;
3846
+ }
3847
+ type FloatEvent = 'closed' | 'tierchange';
3848
+ interface FloatingWindowManager {
3849
+ readonly tier: FloatTier;
3850
+ readonly isOpen: boolean;
3851
+ /** Resolves with the tier that actually opened ('docked' if none could). */
3852
+ open(opts: FloatOpenOptions): Promise<FloatTier>;
3853
+ /** Idempotent; restores docked and emits 'closed'. */
3854
+ close(): void;
3855
+ /** Portal container for 'document-pip' | 'popup'; null otherwise. */
3856
+ getPortalTarget(): HTMLElement | null;
3857
+ /** Canvas sink for 'video-pip'; null otherwise. */
3858
+ getCanvasSink(): CanvasSink | null;
3859
+ on(event: FloatEvent, cb: (tier: FloatTier) => void): () => void;
3860
+ /** Tear everything down (unmount); like close() but silent-safe. */
3861
+ dispose(): void;
3862
+ }
3863
+ /** Feature-detect the available float tiers, best first. */
3864
+ declare function detectFloatTiers(): FloatTier[];
3865
+ declare function createFloatingWindowManager(deps: {
3866
+ styleCss: string;
3867
+ }): FloatingWindowManager;
3868
+
3869
+ /**
3870
+ * React binding over {@link createFloatingWindowManager}: exposes the
3871
+ * current tier + portal target as state and guarantees the float closes
3872
+ * when the owning view unmounts (mode switch, Use-tab exit, shell
3873
+ * teardown).
3874
+ */
3875
+
3876
+ interface FloatingWindowHandle {
3877
+ tier: FloatTier;
3878
+ isOpen: boolean;
3879
+ /** Non-docked tiers this browser supports, best first. */
3880
+ supportedTiers: FloatTier[];
3881
+ portalTarget: HTMLElement | null;
3882
+ canvasSink: CanvasSink | null;
3883
+ open: (preferredTier?: FloatTier) => Promise<void>;
3884
+ close: () => void;
3885
+ }
3886
+ declare function useFloatingWindow(styleCss: string): FloatingWindowHandle;
3887
+
3888
+ interface TeleprompterControlsProps {
3889
+ controller: TeleprompterController;
3890
+ float: FloatingWindowHandle;
3891
+ /** Phase B mounts the narration Record button here. */
3892
+ recordSlot?: ReactNode;
3893
+ }
3894
+ declare function TeleprompterControls({ controller, float, recordSlot }: TeleprompterControlsProps): react_jsx_runtime.JSX.Element;
3895
+
3896
+ /**
3897
+ * The PCM tap AudioWorklet, shipped as an inline source string.
3898
+ *
3899
+ * Why inline → Blob URL instead of a bundled asset: `audioWorklet
3900
+ * .addModule(url)` resolves relative to the host DOCUMENT, so a
3901
+ * dist-relative asset would need every consumer's bundler to rewrite
3902
+ * and serve it (editor-react ships zero runtime assets today). The
3903
+ * worklet is ~30 lines with no imports; inlining follows the
3904
+ * `PLAYER_BUNDLE` source-string precedent and needs zero bundler
3905
+ * config. The worklet does NO DSP — it batches 128-sample render
3906
+ * quanta into 1024-sample frames and posts them (transferably) to the
3907
+ * main thread, where the pure engine in `@bendyline/squisq/narration`
3908
+ * runs. The audio render thread never throttles, so pacing keeps
3909
+ * working while the browser window is fully occluded by recording
3910
+ * software — the whole point of the teleprompter's scenario 2.
3911
+ */
3912
+ declare const PCM_WORKLET_NAME = "squisq-pcm-tap";
3913
+ declare const PCM_WORKLET_SOURCE = "\nclass SquisqPcmTap extends AudioWorkletProcessor {\n constructor() {\n super();\n this._buf = new Float32Array(1024);\n this._len = 0;\n }\n process(inputs) {\n const channel = inputs[0] && inputs[0][0];\n if (channel && channel.length > 0) {\n let i = 0;\n while (i < channel.length) {\n const n = Math.min(channel.length - i, this._buf.length - this._len);\n this._buf.set(channel.subarray(i, i + n), this._len);\n this._len += n;\n i += n;\n if (this._len === this._buf.length) {\n const out = this._buf;\n this._buf = new Float32Array(1024);\n this._len = 0;\n // Clone, don't transfer: Chrome recycles buffers transferred out\n // of the worklet scope once the receiving handler returns, so a\n // transferred hop reads as zeros if anything retains it. A 4 KB\n // structured clone at ~47 Hz is negligible.\n this.port.postMessage({ pcm: out, audioTime: currentTime });\n }\n }\n }\n return true;\n }\n}\nregisterProcessor('squisq-pcm-tap', SquisqPcmTap);\n";
3914
+ /** Register the tap on an AudioContext via a same-origin Blob URL. */
3915
+ declare function registerPcmWorklet(ctx: AudioContext): Promise<void>;
3916
+
3917
+ /**
3918
+ * Pure scroll math for the teleprompter surface.
3919
+ *
3920
+ * The surface renders the whole script into one absolutely-positioned
3921
+ * column and translates it so the active word sits at the eye-line
3922
+ * (~35% from the top). These helpers are DOM-free except for the
3923
+ * measurement entry point, which only reads layout.
3924
+ */
3925
+ interface TokenLineMap {
3926
+ /** Top offset (px, within the scroll column) of each token span. */
3927
+ tokenTops: number[];
3928
+ /** Height of each token's line box (px). */
3929
+ tokenHeights: number[];
3930
+ }
3931
+ /** Fraction of the viewport height where the active line is held. */
3932
+ declare const EYE_LINE_FRACTION = 0.35;
3933
+ /**
3934
+ * Measure the top offset of every `[data-token-idx]` span inside the
3935
+ * scroll column. Layout read only — call on mount, resize, and font-size
3936
+ * changes, not per frame.
3937
+ */
3938
+ declare function measureTokenLines(scrollColumn: HTMLElement): TokenLineMap;
3939
+ /**
3940
+ * The translateY offset (px) that puts the (fractional) word position on
3941
+ * the eye-line. Interpolates between the current and next token tops so
3942
+ * the column glides instead of stepping line by line.
3943
+ */
3944
+ declare function targetOffsetFor(wordPos: number, lines: TokenLineMap, viewportHeightPx: number, eyeLine?: number): number;
3945
+ /**
3946
+ * Advance the current scroll offset toward the target: exponential
3947
+ * approach (critically-damped feel) with an absolute speed clamp so a
3948
+ * hard resync glides rather than teleporting.
3949
+ */
3950
+ declare function stepScroll(currentPx: number, targetPx: number, dtMs: number, maxPxPerSec?: number): number;
3951
+
3952
+ /**
3953
+ * Self-contained styling for the teleprompter.
3954
+ *
3955
+ * Everything the prompter surface needs ships as one CSS string plus a
3956
+ * set of inline `--squisq-prompter-*` custom properties derived from the
3957
+ * doc Theme. The docked surface, a Document-PiP window, and a popup all
3958
+ * inject the SAME string, so the surface never depends on the host
3959
+ * page's cascade (the VideoExportModal self-theming strategy).
3960
+ */
3961
+
3962
+ /** Inline CSS vars for the surface root, derived from the doc theme. */
3963
+ declare function prompterVarsFromTheme(theme: Theme): Record<string, string>;
3964
+ /** Inject {@link TELEPROMPTER_CSS} into a document once (main doc or a float window). */
3965
+ declare function ensureTeleprompterStyles(doc: Document): void;
3966
+ declare const TELEPROMPTER_CSS = "\n.squisq-teleprompter-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n background: var(--squisq-bg, #f5f5f5);\n outline: none;\n}\n.squisq-teleprompter-stage {\n position: relative;\n flex: 1;\n min-height: 0;\n display: flex;\n}\n\n.squisq-teleprompter-surface {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n background: var(--squisq-prompter-bg, #101014);\n color: var(--squisq-prompter-text, #f5f5f2);\n font-family: var(--squisq-prompter-font, system-ui, sans-serif);\n user-select: none;\n}\n.squisq-teleprompter-flip {\n position: absolute;\n inset: 0;\n}\n.squisq-teleprompter-surface--mirrored .squisq-teleprompter-flip {\n transform: scaleX(-1);\n}\n.squisq-teleprompter-scroll {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n will-change: transform;\n padding: 40vh 8% 60vh;\n box-sizing: border-box;\n}\n.squisq-teleprompter-line-guide {\n position: absolute;\n left: 0;\n right: 0;\n pointer-events: none;\n z-index: 2;\n}\n.squisq-teleprompter-line-guide::before,\n.squisq-teleprompter-line-guide::after {\n content: '';\n position: absolute;\n top: 50%;\n border: 9px solid transparent;\n transform: translateY(-50%);\n}\n.squisq-teleprompter-line-guide::before {\n left: 6px;\n border-left-color: var(--squisq-prompter-accent, #e8b64c);\n}\n.squisq-teleprompter-line-guide::after {\n right: 6px;\n border-right-color: var(--squisq-prompter-accent, #e8b64c);\n}\n.squisq-teleprompter-guide-band {\n position: absolute;\n left: 0;\n right: 0;\n background: color-mix(in srgb, var(--squisq-prompter-accent, #e8b64c) 9%, transparent);\n pointer-events: none;\n z-index: 1;\n}\n\n.squisq-teleprompter-block-marker {\n display: block;\n margin: 1.1em 0 0.35em;\n font-size: 0.38em;\n font-weight: 600;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--squisq-prompter-muted, #9a9aa0);\n border-top: 1px solid color-mix(in srgb, var(--squisq-prompter-muted, #9a9aa0) 35%, transparent);\n padding-top: 0.6em;\n}\n.squisq-teleprompter-para {\n margin: 0 0 0.55em;\n line-height: 1.4;\n font-weight: 500;\n}\n.squisq-teleprompter-word {\n opacity: 0.45;\n transition: color 0.1s linear, opacity 0.1s linear;\n}\n.squisq-teleprompter-word--read {\n opacity: 0.9;\n}\n.squisq-teleprompter-word--active {\n opacity: 1;\n font-weight: 800;\n color: var(--squisq-prompter-accent, #e8b64c);\n}\n\n.squisq-teleprompter-countdown {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 3;\n background: color-mix(in srgb, var(--squisq-prompter-bg, #101014) 72%, transparent);\n}\n.squisq-teleprompter-countdown-digit {\n font-size: 18vmin;\n font-weight: 800;\n color: var(--squisq-prompter-accent, #e8b64c);\n animation: squisq-prompter-pulse 1s ease-in-out infinite;\n}\n.squisq-teleprompter-recdot {\n position: absolute;\n top: 14px;\n right: 16px;\n z-index: 4;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: #e5484d;\n box-shadow: 0 0 0 3px color-mix(in srgb, #e5484d 30%, transparent);\n animation: squisq-prompter-pulse 1.4s ease-in-out infinite;\n}\n/* Counter-flip overlays so they stay readable in mirror mode. */\n.squisq-teleprompter-surface--mirrored .squisq-teleprompter-countdown,\n.squisq-teleprompter-surface--mirrored .squisq-teleprompter-recdot {\n transform: scaleX(-1);\n}\n\n.squisq-teleprompter-selfview {\n position: absolute;\n right: 14px;\n bottom: 14px;\n width: 160px;\n border-radius: 8px;\n border: 2px solid color-mix(in srgb, #e5484d 60%, transparent);\n z-index: 5;\n background: #000;\n}\n\n.squisq-teleprompter-review {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 10px;\n padding: 8px 12px;\n border-top: 1px solid var(--squisq-border, #e5e7eb);\n background: var(--squisq-surface, var(--squisq-bg, #fff));\n color: var(--squisq-text, #111827);\n font-size: 12.5px;\n}\n.squisq-teleprompter-review audio {\n height: 28px;\n max-width: 260px;\n}\n.squisq-teleprompter-review button {\n font: inherit;\n color: inherit;\n background: var(--squisq-input-bg, #fff);\n border: 1px solid var(--squisq-border, #d1d5db);\n border-radius: 6px;\n padding: 4px 10px;\n cursor: pointer;\n}\n\n.squisq-teleprompter-float-note {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n color: var(--squisq-text-muted, #6b7280);\n font-size: 14px;\n}\n\n.squisq-teleprompter-controls {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 10px;\n padding: 8px 12px;\n border-top: 1px solid var(--squisq-border, #e5e7eb);\n background: var(--squisq-surface, var(--squisq-bg, #fff));\n color: var(--squisq-text, #111827);\n font-size: 12.5px;\n}\n.squisq-teleprompter-controls .squisq-teleprompter-group {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n white-space: nowrap;\n}\n.squisq-teleprompter-controls button {\n font: inherit;\n color: inherit;\n background: var(--squisq-input-bg, #fff);\n border: 1px solid var(--squisq-border, #d1d5db);\n border-radius: 6px;\n padding: 4px 10px;\n cursor: pointer;\n}\n.squisq-teleprompter-controls button:hover {\n background: var(--squisq-surface-hover, #f3f4f6);\n}\n.squisq-teleprompter-controls button[aria-pressed='true'] {\n background: var(--squisq-text, #111827);\n color: var(--squisq-bg, #fff);\n border-color: var(--squisq-text, #111827);\n}\n.squisq-teleprompter-controls select,\n.squisq-teleprompter-controls input[type='range'] {\n font: inherit;\n color: inherit;\n background: var(--squisq-input-bg, #fff);\n border: 1px solid var(--squisq-border, #d1d5db);\n border-radius: 6px;\n max-width: 170px;\n}\n.squisq-teleprompter-controls input[type='range'] {\n border: none;\n background: transparent;\n width: 110px;\n}\n.squisq-teleprompter-meter {\n position: relative;\n width: 64px;\n height: 8px;\n border-radius: 4px;\n overflow: hidden;\n background: var(--squisq-border, #e5e7eb);\n}\n.squisq-teleprompter-meter-fill {\n position: absolute;\n inset: 0 auto 0 0;\n background: #9ca3af;\n transition: width 0.08s linear;\n}\n.squisq-teleprompter-meter--voice .squisq-teleprompter-meter-fill {\n background: #30a46c;\n}\n\n@keyframes squisq-prompter-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.45; }\n}\n@media (prefers-reduced-motion: reduce) {\n .squisq-teleprompter-countdown-digit,\n .squisq-teleprompter-recdot {\n animation: none;\n }\n .squisq-teleprompter-word {\n transition: none;\n }\n}\n";
3967
+
2918
3968
  interface ImageEditorProps {
2919
3969
  /**
2920
3970
  * Scoped sidecar container for this image — typically
@@ -3103,4 +4153,4 @@ interface UseImageEditorReturn {
3103
4153
  }
3104
4154
  declare function useImageEditor(options: UseImageEditorOptions): UseImageEditorReturn;
3105
4155
 
3106
- export { ALL_EMOJIS, BlockCardView, type BlockCardViewProps, type BlockNavigator, BlockPropertiesPopover, type BlockPropertiesPopoverProps, type BlockRange, type BlockSlice, type CameraStreamOptions, type CanvasRect, type CaptureKind, type CodeContext, type CodeContextSection, CodeContextZones, type CustomTemplateContextValue, CustomTemplateProvider, type CustomTemplateProviderProps, type CustomThemeContextValue, CustomThemeProvider, type CustomThemeProviderProps, DiagramCanvas, type DiagramCommand, type DiagramData, DiagramExtension, type DiagramRFEdge, type DiagramRFNode, DiagramWidget, type DirectionModel, type DocCustomTemplates, type DocCustomThemes, type DocumentLinkCandidate, type DocumentLinkProvider, DocumentSettingsDialog, type DocumentSettingsDialogProps, type DragContentType, type DropTarget, DropZoneOverlay, type DropZoneOverlayProps, EMOJI_CATEGORIES, EMPTY_TRANSITION, type EditorActions, type EditorColorScheme, type EditorContextValue, type EditorMode, EditorProvider, type EditorProviderProps, EditorShell, type EditorShellProps, type EditorState, type EditorView, type EmojiCategory, type EmojiEntry, EmojiPicker, type EmojiPickerProps, type FileCategory, type FileKind, type FolderEntry, FolderView, type FolderViewProps, type HeadingTransitionAttrs, 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, PreviewFormatSwitch, PreviewModeSwitch, 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, type UseMonacoLoaderResult, 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, setHeadingAttrsTransition, setHeadingLineTransition, setMediaClipInSource, sliceIndexAtOffset, spliceBlock, summarizeBlockProps, supportsDisplayMedia, supportsMediaRecorder, supportsUserMedia, templateLabel, timingPathFor, tiptapToMarkdown, transitionLabel, useBlockNavigator, useCustomTemplates, useCustomThemes, useDiagramData, useDocCustomTemplates, useDocCustomThemes, useEditorContext, useFileDrop, useImageEditor, useMediaRecorder, useMonacoLoader, usePreviewSettings, useStreamPreview };
4156
+ export { ALL_PICKER_ENTRIES, type AddTimelineEventOptions, type AddTimelineEventResult, type AsciiDiagramBlockEntry, AsciiDiagramExtension, type AsciiDiagramExtensionOptions, type AsciiDiagramPluginState, type AsciiDiagramView, AsciiDiagramWidget, BlockCardView, type BlockCardViewProps, type BlockNavigator, BlockPropertiesPopover, type BlockPropertiesPopoverProps, type BlockRange, type BlockSlice, type BlockTagVisibility, type CameraStreamOptions, type CanvasRect, type CanvasSink, type CaptureKind, type CodeContext, type CodeContextSection, CodeContextZones, type CustomTemplateContextValue, CustomTemplateProvider, type CustomTemplateProviderProps, type CustomThemeContextValue, CustomThemeProvider, type CustomThemeProviderProps, DEFAULT_TELEPROMPTER_PREFS, DiagramCanvas, type DiagramCommand, type DiagramData, type DiagramEdge, type DiagramNode, type DirectionModel, type DocCustomTemplates, type DocCustomThemes, type DocumentLinkCandidate, type DocumentLinkProvider, DocumentSettingsDialog, type DocumentSettingsDialogProps, type DragContentType, type DropTarget, DropZoneOverlay, type DropZoneOverlayProps, EMPTY_TRANSITION, EYE_LINE_FRACTION, type EditorActions, type EditorColorScheme, type EditorContextValue, type EditorMode, EditorProvider, type EditorProviderProps, EditorShell, type EditorShellProps, type EditorState, type EditorView, EmojiPicker, type EmojiPickerProps, type FileCategory, type FileKind, type FloatOpenOptions, type FloatTier, type FloatingWindowHandle, type FloatingWindowManager, type FolderEntry, FolderView, type FolderViewProps, type HeadingTransitionAttrs, HeadingWithTemplate, type ImageDisplayMode, ImageEditor, type ImageEditorAction, type ImageEditorProps, type ImageEditorState, type ImageEditorTool, ImageViewer, type ImageViewerProps, ImportThemeSection, type ImportThemeSectionProps, type ImportedThemeResult, InlinePreviewGutter, type InlinePreviewGutterProps, JsonEditor, type JsonEditorProps, type LayoutMode, MediaBin, type MediaBinProps, type MediaClipPatch, type MentionCandidate, type MentionProvider, type MicAnalysisHandle, type MicAnalysisStatus, type MonacoWorkerConstructor, type MonacoWorkerConstructors, type NarrationRecorderController, type NarrationRecorderState, type NarrationSavePlan, type NarrationSaveResult, type NarrationTake, OutlinePanel, type OutlinePanelProps, PCM_WORKLET_NAME, PCM_WORKLET_SOURCE, PICKER_CATEGORIES, type PickerCategory, type PickerEntry, PlainHtmlPreview, type PlainHtmlPreviewProps, PreviewFormatSwitch, PreviewModeMenu, PreviewModeSwitch, PreviewPanel, type PreviewPanelProps, type PreviewSettings, PreviewSettingsProvider, PreviewToolbarControls, type PrompterTransport, REPAIRABLE_KEY, RawEditor, type RawEditorProps, type RecordedBookmark, RecorderButton, type RecorderButtonProps, RecorderModal, type RecorderModalProps, RecorderPanel, type RecorderPanelProps, type RecorderSaveResult, type RecorderSource, type RecorderState, type RepairableBlockEntry, RepairableDiagramExtension, type RepairableDiagramExtensionOptions, type RepairablePluginState, type ResolvedFormat, type ScreenStreamHandle, type ScreenStreamOptions, StatusBar, type StatusBarProps, TELEPROMPTER_CSS, TIMELINE_VIEW_KEY, TRANSITION_ENTRIES, TRANSITION_GROUPS, type TeleprompterController, TeleprompterControls, type TeleprompterControlsProps, type TeleprompterPrefs, type TeleprompterRecordingDeps, TeleprompterSurface, type TeleprompterSurfaceProps, TeleprompterView, type TeleprompterViewProps, TemplatePicker, ThemeCustomizerPanel, type ThemeCustomizerPanelProps, type ThemeInheritance, ThemePicker, type ThemePickerProps, type ThemeSaveExtras, type TimelineBlockEntry, type TimelineCommand, type TimelineCommandResult, TimelineEditorWidget, type TimelineEditorWidgetProps, type TimelineEventPatch, TimelineTrack, type TimelineTrackProps, type TimelineViewData, TimelineViewExtension, type TimelineViewExtensionOptions, type TimelineViewPluginState, type TimingJson, type TokenLineMap, Toolbar, type ToolbarProps, TooltipLayer, type TransitionCatalogEntry, type TransitionFields, type TransitionGroup, TransitionPicker, type TransitionPickerProps, type TreeBlockEntry, type TreeCommand, TreeOutlineWidget, type TreeViewData, TreeViewExtension, type TreeViewExtensionOptions, type TreeViewPluginState, type UseBlockNavigatorOptions, type UseFileDropOptions, type UseFileDropResult, type UseImageEditorOptions, type UseImageEditorReturn, type UseMediaRecorderOptions, type UseMediaRecorderResult, type UseMonacoLoaderResult, VersionHistoryPanel, ViewMenuPanel, type ViewPreferences, ViewSwitcher, type ViewSwitcherProps, WysiwygEditor, type WysiwygEditorProps, addEdgeOp, addItemOp, addNodeOp, addTimelineEventOp, applyAsciiDiagramCommand, applyRepairCommand, applyTimelineCommand, applyTreeCommand, asciiDiagramToCanvas, buildFilename, buildNarrationSavePlan, buildPreviewDoc, buildTimingJson, cameraVideoLine, classifyFile, configureMonacoWorkers, createFloatingWindowManager, detectFloatTiers, detectLanguageFromFileName, draftPatchFromImportedTheme, encodeTimingJson, ensureTeleprompterStyles, executeNarrationSave, findAsciiDiagramBlockPos, findRepairableBlockPos, findTimelineBlockPos, findTransitionEntry, findTreeBlockPos, formatSeconds, getBlockSlices, getCaptureKind, getTimelineForNode, imageEditorReducer, indentItemOp, initialImageEditorState, insertNarrationPreamble, isAsciiSourceVisible, isRepairableFence, isTimelineSourceSafeForSemanticEdit, lineToOffset, markdownToTiptap, measureTokenLines, moveItemDownOp, moveItemUpOp, moveNodeOp, narrationAnnotationLine, nextTimelineEventId, offsetToLine, outdentItemOp, parseTimelineForNode, partitionFiles, processMediaFiles, processTextFile, processTextFiles, prompterVarsFromTheme, readBlockAttrsParams, readBlockAttrsTransition, readBlockAttrsValue, readHeadingLineTransition, registerPcmWorklet, removeEdgeOp, removeItemOp, removeNodeOp, removeTimelineEventOp, renameItemOp, renameNodeOp, replaceAsciiFenceText, replaceAsciiFenceText as replaceTreeFenceText, requestCameraStream, requestMicStream, requestScreenStream, resizeNodeOp, resolveFileKind, resolveFormat, sanitizeAsciiLabel, sanitizeTimelineText, sanitizeTreeLabel, searchPickerEntries, setBlockAttrsValue, setBlockDurationInSource, setHeadingAttrsTransition, setHeadingLineTransition, setMediaClipInSource, shouldPasteAsAsciiFence, shouldPasteAsTimelineFence, shouldPasteAsTreeFence, sliceIndexAtOffset, spliceBlock, stepScroll, summarizeBlockProps, supportsDisplayMedia, supportsMediaRecorder, supportsUserMedia, targetOffsetFor, templateLabel, timingPathFor, tiptapToMarkdown, toggleAsciiSource, toggleDirOp, transitionLabel, updateTimelineEventOp, useAsciiDiagramData, useBlockNavigator, useCustomTemplates, useCustomThemes, useDocCustomTemplates, useDocCustomThemes, useEditorContext, useFileDrop, useFloatingWindow, useImageEditor, useMediaRecorder, useMicAnalysis, useMonacoLoader, useNarrationRecorder, usePreviewSettings, useStreamPreview, useTeleprompter, useTimelineData, useTreeViewData, vadConfigForSensitivity };