@bendyline/squisq-editor-react 1.6.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/index.d.ts +1275 -183
- package/dist/index.js +20345 -12777
- package/dist/index.js.map +1 -1
- package/dist/monaco.d.ts +1 -0
- package/dist/monaco.js +4 -0
- package/dist/monaco.js.map +1 -0
- package/dist/styles/index.css +1607 -241
- package/package.json +9 -5
- package/src/BlockPropertiesPopover.tsx +30 -15
- package/src/DocumentSettingsDialog.tsx +39 -33
- package/src/EditorContext.tsx +199 -42
- package/src/EditorShell.tsx +349 -261
- package/src/ImageEditor.tsx +22 -1
- package/src/InlinePreviewGutter.tsx +16 -8
- package/src/MediaBin.tsx +107 -14
- package/src/OutlinePanel.tsx +202 -7
- package/src/PlainHtmlPreview.tsx +40 -1
- package/src/PreviewControls.tsx +362 -89
- package/src/PreviewPanel.tsx +312 -78
- package/src/RawEditor.tsx +13 -2
- package/src/RecorderEntry.tsx +2 -0
- package/src/StatusBar.tsx +5 -2
- package/src/TemplateAnnotation.ts +12 -3
- package/src/TemplatePicker.tsx +75 -21
- package/src/ThemeCustomizerPanel.tsx +8 -0
- package/src/ThemePicker.tsx +10 -5
- package/src/TimelineBlockPreview.tsx +1 -1
- package/src/Toolbar.tsx +357 -51
- package/src/TransitionPicker.tsx +36 -4
- package/src/ViewMenuPanel.tsx +12 -14
- package/src/WysiwygEditor.tsx +124 -91
- package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +33 -0
- package/src/__tests__/blockTagActivity.test.ts +183 -0
- package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +75 -0
- package/src/__tests__/buildPreviewDocContent.test.ts +48 -0
- package/src/__tests__/buildPreviewDocTransition.test.ts +21 -1
- package/src/__tests__/canvasSurfaceTextEditing.test.tsx +60 -0
- package/src/__tests__/codeContextSectionView.test.tsx +8 -6
- package/src/__tests__/customLayoutManagerTheme.test.tsx +34 -0
- package/src/__tests__/documentSettingsDialog.test.tsx +51 -1
- package/src/__tests__/editorScrollHandoff.test.tsx +102 -0
- package/src/__tests__/editorScrollSync.test.ts +65 -0
- package/src/__tests__/editorShellProps.test.tsx +123 -1
- package/src/__tests__/emojiPicker.test.tsx +2 -42
- package/src/__tests__/headingTransition.test.ts +0 -12
- package/src/__tests__/imageEditAffordance.test.tsx +5 -1
- package/src/__tests__/imageEditModalContract.test.tsx +119 -0
- package/src/__tests__/imageEditorShell.test.tsx +15 -1
- package/src/__tests__/jsonEditor.test.tsx +56 -1
- package/src/__tests__/layersPanel.test.tsx +75 -5
- package/src/__tests__/majorApiTypes.test.ts +26 -0
- package/src/__tests__/mediaAttachmentFlow.test.ts +2 -2
- package/src/__tests__/mediaBinDrop.test.tsx +90 -0
- package/src/__tests__/narrationSave.test.ts +148 -0
- package/src/__tests__/outlinePanel.test.tsx +93 -3
- package/src/__tests__/outlineSource.test.ts +217 -0
- package/src/__tests__/plainHtmlPreview.test.tsx +17 -1
- package/src/__tests__/presentationMode.test.tsx +290 -0
- package/src/__tests__/previewControls.test.tsx +382 -5
- package/src/__tests__/previewPanelAudioFailure.test.tsx +46 -0
- package/src/__tests__/previewPanelPresentation.test.tsx +126 -0
- package/src/__tests__/previewPanelTransforms.test.tsx +117 -0
- package/src/__tests__/rawEditorModelIsolation.test.ts +19 -0
- package/src/__tests__/recorderTheme.test.tsx +42 -0
- package/src/__tests__/resolveBlockVisual.test.ts +43 -0
- package/src/__tests__/selectionConversions.test.ts +80 -0
- package/src/__tests__/statusBar.test.tsx +27 -0
- package/src/__tests__/teleprompter.test.tsx +190 -0
- package/src/__tests__/templateAnnotationRoundTrip.test.ts +26 -0
- package/src/__tests__/templatePickerPortal.test.tsx +62 -0
- package/src/__tests__/tiptapBridge.test.ts +71 -7
- package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +109 -0
- package/src/__tests__/tiptapImageRoundTrip.test.ts +1 -1
- package/src/__tests__/toolbarSelectionConversion.test.tsx +164 -0
- package/src/__tests__/transformStyleId.test.ts +13 -0
- package/src/__tests__/useImageEditor.test.tsx +67 -0
- package/src/__tests__/useMediaRecorder.test.ts +75 -0
- package/src/__tests__/viewMenuPanel.test.tsx +130 -0
- package/src/__tests__/wysiwygImageUpload.test.ts +69 -0
- package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +56 -0
- package/src/asciiDiagram/AsciiDiagramExtension.ts +343 -0
- package/src/asciiDiagram/AsciiDiagramWidget.tsx +254 -0
- package/src/asciiDiagram/RepairableDiagramExtension.ts +200 -0
- package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +145 -0
- package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +159 -0
- package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +284 -0
- package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +114 -0
- package/src/asciiDiagram/__tests__/asciiPaste.test.ts +43 -0
- package/src/asciiDiagram/asciiDiagramCommands.ts +174 -0
- package/src/asciiDiagram/asciiDiagramData.ts +149 -0
- package/src/asciiDiagram/asciiDiagramOps.ts +238 -0
- package/src/asciiDiagram/asciiPaste.ts +19 -0
- package/src/blockTagActivity.ts +233 -0
- package/src/buildDocumentPreviewMarkdown.ts +168 -0
- package/src/buildPreviewDoc.ts +19 -12
- package/src/codeContext/types.ts +1 -1
- package/src/customTemplates/CustomLayoutManager.tsx +3 -2
- package/src/customTemplates/CustomTemplateContext.tsx +6 -0
- package/src/customTemplates/TemplateDesigner.tsx +7 -4
- package/src/customTemplates/__tests__/library.test.ts +8 -0
- package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +13 -0
- package/src/customTemplates/designer.css +158 -99
- package/src/customTemplates/library.ts +16 -3
- package/src/customTemplates/useMemoryLayerAdapter.ts +7 -1
- package/src/customThemes/CustomThemeContext.tsx +6 -0
- package/src/customThemes/CustomThemeDialog.tsx +35 -5
- package/src/customThemes/ImportThemeSection.tsx +178 -0
- package/src/customThemes/__tests__/customThemeLibrary.test.ts +9 -0
- package/src/customThemes/__tests__/importThemeSection.test.tsx +192 -0
- package/src/customThemes/customThemeLibrary.ts +7 -4
- package/src/customThemes/index.ts +7 -1
- package/src/customThemes/themeDraft.ts +23 -7
- package/src/diagram/DiagramCanvas.tsx +25 -6
- package/src/diagram/types.ts +35 -0
- package/src/editorScrollSync.ts +73 -0
- package/src/emojiData.ts +3 -23
- package/src/frontmatterSettings.ts +23 -0
- package/src/headingTransition.ts +0 -15
- package/src/imageEditor/CanvasSurface.tsx +29 -23
- package/src/imageEditor/LayersPanel.tsx +78 -3
- package/src/imageEditor/Toolbar.tsx +5 -1
- package/src/imageEditor/icons.tsx +4 -0
- package/src/imageEditor/image-editor.css +75 -0
- package/src/imageEditor/layers/SelectionHandles.tsx +1 -1
- package/src/imageEditor/useImageEditor.ts +71 -14
- package/src/index.ts +198 -20
- package/src/jsonEditor/JsonEditorContext.tsx +12 -6
- package/src/jsonEditor/RenderNode.tsx +24 -3
- package/src/jsonEditor/editors.tsx +86 -19
- package/src/mediaEntries.ts +12 -0
- package/src/monaco.ts +35 -0
- package/src/monacoWorkers.ts +89 -0
- package/src/outlineSource.ts +171 -0
- package/src/presentation/PresentationMode.tsx +596 -0
- package/src/rawEditorIsolation.ts +18 -0
- package/src/recorder/RecorderButton.tsx +9 -1
- package/src/recorder/RecorderModal.tsx +84 -41
- package/src/recorder/RecorderPanel.tsx +9 -1
- package/src/recorder/hooks/useMediaRecorder.ts +97 -53
- package/src/resolveBlockVisual.ts +10 -4
- package/src/scene/Scene.tsx +48 -18
- package/src/scene/SceneBlockExtension.ts +17 -10
- package/src/scene/SceneBlockWidget.tsx +5 -1
- package/src/scene/SceneViewport.tsx +7 -3
- package/src/scene/ShapePalette.tsx +17 -2
- package/src/scene/__tests__/DiagramAdapter.test.ts +86 -0
- package/src/scene/__tests__/SceneBlockExtension.test.ts +33 -0
- package/src/scene/__tests__/sceneIsolation.test.tsx +119 -0
- package/src/scene/adapters/DiagramAdapter.ts +12 -101
- package/src/scene/adapters/DrawingAdapter.ts +6 -1
- package/src/scene/adapters/LayoutAdapter.ts +3 -0
- package/src/scene/commands/SceneCommand.ts +17 -3
- package/src/scene/index.ts +1 -6
- package/src/scene/layers/DiagramEdges.tsx +21 -7
- package/src/scene/layers/edgeGeometry.ts +9 -1
- package/src/scene/layers/nodeCard.tsx +27 -8
- package/src/scene/scene.css +5 -2
- package/src/scene/text/SceneTextOverlay.tsx +5 -5
- package/src/scene/text/sceneTextChannel.ts +26 -20
- package/src/scene/text/sceneTextConfig.ts +4 -0
- package/src/scene/tools/ConnectTool.ts +13 -4
- package/src/scene/tools/SceneTool.ts +8 -0
- package/src/scene/tools/SelectTool.ts +39 -23
- package/src/scene/tools/ShapeTool.ts +2 -3
- package/src/selectionConversions.ts +155 -0
- package/src/styles/ascii-diagram.css +79 -0
- package/src/styles/ascii-timeline.css +596 -0
- package/src/styles/editor.css +736 -120
- package/src/styles/index.css +3 -0
- package/src/styles/tree-view.css +189 -0
- package/src/teleprompter/TeleprompterControls.tsx +218 -0
- package/src/teleprompter/TeleprompterSelfView.tsx +22 -0
- package/src/teleprompter/TeleprompterSurface.tsx +267 -0
- package/src/teleprompter/TeleprompterView.tsx +338 -0
- package/src/teleprompter/canvasRenderer.ts +161 -0
- package/src/teleprompter/floatingWindow.ts +352 -0
- package/src/teleprompter/index.ts +61 -0
- package/src/teleprompter/pcmWorklet.ts +62 -0
- package/src/teleprompter/recording/insertPreamble.ts +80 -0
- package/src/teleprompter/recording/narrationSave.ts +134 -0
- package/src/teleprompter/recording/useNarrationRecorder.ts +367 -0
- package/src/teleprompter/scrollModel.ts +85 -0
- package/src/teleprompter/teleprompterTheme.ts +303 -0
- package/src/teleprompter/types.ts +38 -0
- package/src/teleprompter/useFloatingWindow.ts +74 -0
- package/src/teleprompter/useMicAnalysis.ts +211 -0
- package/src/teleprompter/useTeleprompter.ts +421 -0
- package/src/templateContentPreviewResolver.ts +12 -5
- package/src/timeline/TimelineEditorWidget.tsx +861 -0
- package/src/timeline/TimelineViewExtension.ts +252 -0
- package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +414 -0
- package/src/timeline/__tests__/TimelineViewExtension.test.ts +163 -0
- package/src/timeline/__tests__/timelineCommands.test.ts +359 -0
- package/src/timeline/__tests__/timelineOps.test.ts +277 -0
- package/src/timeline/__tests__/timelinePaste.test.ts +34 -0
- package/src/timeline/timelineCommands.ts +421 -0
- package/src/timeline/timelineData.ts +54 -0
- package/src/timeline/timelineOps.ts +381 -0
- package/src/timeline/timelinePaste.ts +8 -0
- package/src/tiptapBridge.ts +47 -21
- package/src/transformStyleId.ts +17 -0
- package/src/treeview/TreeOutlineWidget.tsx +390 -0
- package/src/treeview/TreeViewExtension.ts +250 -0
- package/src/treeview/__tests__/TreeOutlineWidget.test.tsx +156 -0
- package/src/treeview/__tests__/TreeViewExtension.test.ts +122 -0
- package/src/treeview/__tests__/treeOps.test.ts +177 -0
- package/src/treeview/__tests__/treePaste.test.ts +40 -0
- package/src/treeview/__tests__/treeViewCommands.test.ts +179 -0
- package/src/treeview/treeOps.ts +231 -0
- package/src/treeview/treePaste.ts +13 -0
- package/src/treeview/treeViewCommands.ts +99 -0
- package/src/treeview/treeViewData.ts +41 -0
- package/src/useMonacoLoader.ts +11 -34
- package/src/wysiwygImageUpload.ts +113 -0
- package/src/diagram/DiagramExtension.ts +0 -209
- package/src/diagram/DiagramWidget.tsx +0 -272
- 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,
|
|
5
|
-
import { MarkdownDocument
|
|
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 {
|
|
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 —
|
|
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`.
|
|
37
|
-
*
|
|
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
|
|
163
|
-
*
|
|
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
|
-
*
|
|
432
|
-
*
|
|
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
|
|
453
|
-
* the blob from their own preferences storage
|
|
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)
|
|
@@ -541,7 +581,7 @@ interface CodeContext {
|
|
|
541
581
|
/** Line-anchored sections. Array order is preserved for equal lines. */
|
|
542
582
|
sections?: CodeContextSection[];
|
|
543
583
|
/**
|
|
544
|
-
* Extra URI schemes section links may use (e.g. `['
|
|
584
|
+
* Extra URI schemes section links may use (e.g. `['workspace-nav']`).
|
|
545
585
|
* http/https/mailto/tel are always allowed; executable schemes
|
|
546
586
|
* (javascript:, data:) are never allowed regardless.
|
|
547
587
|
*/
|
|
@@ -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
|
-
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
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`
|
|
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,
|
|
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
|
|
1601
|
-
*
|
|
1602
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2466
|
+
/** Per-node width override in canvas units. */
|
|
2266
2467
|
width?: number;
|
|
2267
|
-
/** Per-node height override
|
|
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
|
|
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:
|
|
2278
|
-
edges:
|
|
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
|
|
2333
|
-
* `data-template-params` HTML attributes. These
|
|
2334
|
-
*
|
|
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;
|
|
@@ -2377,6 +2564,8 @@ type DiagramCommand = {
|
|
|
2377
2564
|
nodeId: string;
|
|
2378
2565
|
width: number;
|
|
2379
2566
|
height: number;
|
|
2567
|
+
x?: number;
|
|
2568
|
+
y?: number;
|
|
2380
2569
|
} | {
|
|
2381
2570
|
kind: 'addConnection';
|
|
2382
2571
|
source: string;
|
|
@@ -2400,8 +2589,8 @@ type DiagramCommand = {
|
|
|
2400
2589
|
nodeId: string;
|
|
2401
2590
|
};
|
|
2402
2591
|
interface DiagramCanvasProps {
|
|
2403
|
-
nodes:
|
|
2404
|
-
edges:
|
|
2592
|
+
nodes: DiagramNode[];
|
|
2593
|
+
edges: DiagramEdge[];
|
|
2405
2594
|
onCommand: (cmd: DiagramCommand) => void;
|
|
2406
2595
|
/** When true, render the maximize button. Click toggles `onToggleMaximize`. */
|
|
2407
2596
|
showMaximize?: boolean;
|
|
@@ -2418,99 +2607,558 @@ interface DiagramCanvasProps {
|
|
|
2418
2607
|
onActiveToolIdChange?: (id: string) => void;
|
|
2419
2608
|
/** Forwarded to the Scene so the host can drive a Delete action. */
|
|
2420
2609
|
onSelectionChange?: (ids: ReadonlySet<string>) => void;
|
|
2610
|
+
/** Per-editor toolbar bridge for detached scene roots. */
|
|
2611
|
+
textChannel?: SceneTextChannel;
|
|
2421
2612
|
}
|
|
2422
|
-
declare function DiagramCanvas({ nodes: incomingNodes, edges: incomingEdges, onCommand, showMaximize, maximized, onToggleMaximize, activeToolId: controlledToolId, onActiveToolIdChange, onSelectionChange, }: DiagramCanvasProps): react_jsx_runtime.JSX.Element;
|
|
2613
|
+
declare function DiagramCanvas({ nodes: incomingNodes, edges: incomingEdges, onCommand, showMaximize, maximized, onToggleMaximize, activeToolId: controlledToolId, onActiveToolIdChange, onSelectionChange, textChannel, }: DiagramCanvasProps): react_jsx_runtime.JSX.Element;
|
|
2423
2614
|
|
|
2424
|
-
|
|
2615
|
+
/**
|
|
2616
|
+
* AsciiDiagramExtension — Tiptap/ProseMirror plugin that turns code blocks
|
|
2617
|
+
* containing ASCII box-and-line diagrams into interactive diagram canvases.
|
|
2618
|
+
*
|
|
2619
|
+
* The FENCE TEXT REMAINS THE SOURCE OF TRUTH: the plugin never converts
|
|
2620
|
+
* the document. For each qualifying codeBlock it:
|
|
2621
|
+
* 1. hides the `<pre>` via a node decoration (or tags it visible-monospace
|
|
2622
|
+
* when the user toggles "source" mode), and
|
|
2623
|
+
* 2. mounts an `AsciiDiagramWidget` after it via a widget decoration.
|
|
2624
|
+
*
|
|
2625
|
+
* Identity: codeBlocks have no persisted id and their content changes on
|
|
2626
|
+
* every canvas edit (self-inflicted fence rewrite), so neither a content
|
|
2627
|
+
* hash nor a raw position can key the widget. Instead the plugin keeps a
|
|
2628
|
+
* POSITION REGISTRY in its state: each qualifying block gets a synthetic
|
|
2629
|
+
* session id (`ascii-N`); on every doc change old positions are remapped
|
|
2630
|
+
* through `tr.mapping` and matched against the new doc walk. Same id →
|
|
2631
|
+
* same widget decoration key → ProseMirror keeps the DOM + React root
|
|
2632
|
+
* alive (pan/zoom survives), exactly like the heading-key trick the
|
|
2633
|
+
* legacy DiagramExtension used.
|
|
2634
|
+
*
|
|
2635
|
+
* Hysteresis: a NEW block must pass full detection (`detectAsciiDiagram`,
|
|
2636
|
+
* ≥2 boxes + thresholds); an already-registered block stays interactive
|
|
2637
|
+
* while its fence still parses to ≥1 box, so deleting down to one node
|
|
2638
|
+
* doesn't kick the user back to a raw code block mid-edit.
|
|
2639
|
+
*/
|
|
2640
|
+
|
|
2641
|
+
interface AsciiDiagramBlockEntry {
|
|
2642
|
+
/** Synthetic session id (`ascii-N`), stable across edits for one block. */
|
|
2643
|
+
id: string;
|
|
2644
|
+
/** Document position of the codeBlock node at the current state. */
|
|
2645
|
+
pos: number;
|
|
2646
|
+
}
|
|
2647
|
+
interface AsciiDiagramPluginState {
|
|
2648
|
+
entries: AsciiDiagramBlockEntry[];
|
|
2649
|
+
decorations: DecorationSet;
|
|
2650
|
+
sourceVisible: ReadonlySet<string>;
|
|
2651
|
+
/** Monotonic id allocator. */
|
|
2652
|
+
seq: number;
|
|
2653
|
+
}
|
|
2654
|
+
/** Resolve a registered block's current doc position (null when gone). */
|
|
2655
|
+
declare function findAsciiDiagramBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
2656
|
+
declare function isAsciiSourceVisible(editor: Editor$1, blockId: string): boolean;
|
|
2657
|
+
/** Toggle the raw-fence view for one diagram block (meta-only transaction). */
|
|
2658
|
+
declare function toggleAsciiSource(editor: Editor$1, blockId: string): void;
|
|
2659
|
+
interface AsciiDiagramExtensionOptions {
|
|
2660
|
+
/** When false, the extension is inert (no widgets, no decorations). */
|
|
2661
|
+
enabled?: boolean;
|
|
2662
|
+
textChannel?: SceneTextChannel;
|
|
2663
|
+
}
|
|
2664
|
+
declare const AsciiDiagramExtension: Extension<AsciiDiagramExtensionOptions, any>;
|
|
2665
|
+
|
|
2666
|
+
interface AsciiDiagramWidgetProps {
|
|
2425
2667
|
editor: Editor$1;
|
|
2426
|
-
/**
|
|
2427
|
-
|
|
2428
|
-
/** Position
|
|
2429
|
-
|
|
2430
|
-
* transaction). */
|
|
2431
|
-
fallbackParentPos: number;
|
|
2668
|
+
/** Session id from the extension's position registry. */
|
|
2669
|
+
blockId: string;
|
|
2670
|
+
/** Position at widget-creation time — display-only fallback. */
|
|
2671
|
+
fallbackPos: number;
|
|
2432
2672
|
/** Host element used for portal targeting by the maximize overlay. */
|
|
2433
2673
|
host?: HTMLElement | null;
|
|
2674
|
+
textChannel?: SceneTextChannel;
|
|
2675
|
+
}
|
|
2676
|
+
declare function AsciiDiagramWidget({ editor, blockId, host, textChannel, }: AsciiDiagramWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
2677
|
+
|
|
2678
|
+
/**
|
|
2679
|
+
* Read direction of the ASCII diagram loop: fence text → canvas data.
|
|
2680
|
+
*
|
|
2681
|
+
* `useAsciiDiagramData` re-derives on every editor transaction (mirroring
|
|
2682
|
+
* the philosophy of the old heading-based `useDiagramData`: no store, so
|
|
2683
|
+
* nothing to invalidate). Parsing is memoized per PMNode instance by the
|
|
2684
|
+
* extension's WeakMap caches, so untouched fences cost nothing.
|
|
2685
|
+
*/
|
|
2686
|
+
|
|
2687
|
+
interface AsciiDiagramView {
|
|
2688
|
+
/** Canvas nodes, containers ordered first so their cards paint behind. */
|
|
2689
|
+
nodes: DiagramNode[];
|
|
2690
|
+
edges: DiagramEdge[];
|
|
2691
|
+
warnings: string[];
|
|
2692
|
+
style: 'unicode' | 'ascii';
|
|
2693
|
+
/** The current fence text. */
|
|
2694
|
+
text: string;
|
|
2695
|
+
/** The parse behind `nodes`/`edges` (grid units) — ops operate on this. */
|
|
2696
|
+
diagram: AsciiDiagram;
|
|
2697
|
+
}
|
|
2698
|
+
/** Grid model → canvas model, containers-first for paint order. */
|
|
2699
|
+
declare function asciiDiagramToCanvas(diagram: AsciiDiagram): Pick<AsciiDiagramView, 'nodes' | 'edges'>;
|
|
2700
|
+
/**
|
|
2701
|
+
* Live view of one registered ASCII diagram block. Returns null when the
|
|
2702
|
+
* block no longer exists or no longer parses (the extension will drop the
|
|
2703
|
+
* widget on its next pass).
|
|
2704
|
+
*/
|
|
2705
|
+
declare function useAsciiDiagramData(editor: Editor$1, blockId: string): AsciiDiagramView | null;
|
|
2706
|
+
|
|
2707
|
+
/**
|
|
2708
|
+
* Write direction of the ASCII diagram loop: canvas command → fence rewrite.
|
|
2709
|
+
*
|
|
2710
|
+
* Every semantic edit is one functional transformation of the fence text
|
|
2711
|
+
* (`renderAscii(applyOp(parseAscii(text)))`) committed as a single
|
|
2712
|
+
* ProseMirror transaction (= a single undo step). Before committing, the
|
|
2713
|
+
* rendered art is re-parsed and verified — if the renderer ever produced
|
|
2714
|
+
* something the parser disagrees with, the command aborts instead of
|
|
2715
|
+
* corrupting the fence.
|
|
2716
|
+
*/
|
|
2717
|
+
|
|
2718
|
+
interface ApplyAsciiDiagramCommandOptions {
|
|
2719
|
+
/**
|
|
2720
|
+
* Virtual grid offset currently shown by the canvas for legacy art. It is
|
|
2721
|
+
* folded into the source in the same transaction as the user's first edit.
|
|
2722
|
+
*/
|
|
2723
|
+
diagramOffset?: {
|
|
2724
|
+
col: number;
|
|
2725
|
+
row: number;
|
|
2726
|
+
};
|
|
2434
2727
|
}
|
|
2435
|
-
|
|
2728
|
+
/**
|
|
2729
|
+
* Replace the TEXT inside the codeBlock at `pos` and, when `ensureLanguage`
|
|
2730
|
+
* is given, promote its `language` attribute in the SAME transaction (one
|
|
2731
|
+
* undo step). Promoting the language to the explicit `diagram`/`tree` tag is
|
|
2732
|
+
* how a semantic edit makes the block's identity "sticky" — the language
|
|
2733
|
+
* class survives markdown ↔ Tiptap round-trips, so a once-edited diagram/tree
|
|
2734
|
+
* is re-recognized even after it's flattened. No-op (returns false) only when
|
|
2735
|
+
* BOTH the text is already identical AND the language already matches, so
|
|
2736
|
+
* history stays clean on a true no-op.
|
|
2737
|
+
*/
|
|
2738
|
+
declare function replaceAsciiFenceText(editor: Editor$1, pos: number, nextText: string, ensureLanguage?: string): boolean;
|
|
2739
|
+
/**
|
|
2740
|
+
* Reconstruct a broken box-art fence into clean, `diagram`-tagged art in a
|
|
2741
|
+
* single transaction (one undo step). The AsciiDiagramExtension then claims
|
|
2742
|
+
* the tagged fence and mounts the interactive canvas. Returns false when the
|
|
2743
|
+
* block is gone or nothing recoverable (the button simply no-ops).
|
|
2744
|
+
*/
|
|
2745
|
+
declare function applyRepairCommand(editor: Editor$1, blockId: string): boolean;
|
|
2746
|
+
/** Full pipeline for a canvas command against a registered fence block. */
|
|
2747
|
+
declare function applyAsciiDiagramCommand(editor: Editor$1, blockId: string, cmd: DiagramCommand, options?: ApplyAsciiDiagramCommandOptions): boolean;
|
|
2436
2748
|
|
|
2437
2749
|
/**
|
|
2438
|
-
*
|
|
2750
|
+
* RepairableDiagramExtension — mounts an inline "Repair as diagram" button on
|
|
2751
|
+
* code fences that hold BROKEN box-and-line art.
|
|
2439
2752
|
*
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2442
|
-
*
|
|
2443
|
-
*
|
|
2444
|
-
*
|
|
2753
|
+
* The three states of a box-drawing fence partition cleanly:
|
|
2754
|
+
* - a clean diagram → AsciiDiagramExtension mounts the canvas;
|
|
2755
|
+
* - a file tree / outline → TreeViewExtension mounts the outline;
|
|
2756
|
+
* - broken box art → neither claims it (it renders as a faithful
|
|
2757
|
+
* code block), and THIS extension offers a button
|
|
2758
|
+
* to reconstruct it via `repairAsciiDiagram`.
|
|
2759
|
+
*
|
|
2760
|
+
* Unlike the diagram/tree extensions it does NOT hide the fence or mount a
|
|
2761
|
+
* persistent interactive widget — the code stays visible and editable, and a
|
|
2762
|
+
* single click rewrites the fence to clean `diagram`-tagged art (which the
|
|
2763
|
+
* AsciiDiagramExtension then turns into a canvas). So the position registry
|
|
2764
|
+
* only needs to survive until the click; it mirrors the other extensions'
|
|
2765
|
+
* mapping so the button always resolves the right fence.
|
|
2445
2766
|
*/
|
|
2446
2767
|
|
|
2447
|
-
interface
|
|
2448
|
-
/**
|
|
2768
|
+
interface RepairableBlockEntry {
|
|
2769
|
+
/** Synthetic session id (`repair-N`), stable across edits for one block. */
|
|
2770
|
+
id: string;
|
|
2771
|
+
/** Document position of the codeBlock node at the current state. */
|
|
2449
2772
|
pos: number;
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2773
|
+
}
|
|
2774
|
+
interface RepairablePluginState {
|
|
2775
|
+
entries: RepairableBlockEntry[];
|
|
2776
|
+
decorations: DecorationSet;
|
|
2777
|
+
seq: number;
|
|
2778
|
+
}
|
|
2779
|
+
declare const REPAIRABLE_KEY: PluginKey<RepairablePluginState>;
|
|
2780
|
+
/** True when a codeBlock holds broken box art worth offering to repair. */
|
|
2781
|
+
declare function isRepairableFence(node: Node): boolean;
|
|
2782
|
+
/** Resolve a registered block's current doc position (null when gone). */
|
|
2783
|
+
declare function findRepairableBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
2784
|
+
/** Handler the mounted button invokes; wired by the host via extension options. */
|
|
2785
|
+
interface RepairableDiagramExtensionOptions {
|
|
2786
|
+
enabled?: boolean;
|
|
2787
|
+
/** Invoked when a repair button is clicked, with the block's synthetic id. */
|
|
2788
|
+
onRepair?: (editor: Editor$1, blockId: string) => void;
|
|
2789
|
+
}
|
|
2790
|
+
declare const RepairableDiagramExtension: Extension<RepairableDiagramExtensionOptions, any>;
|
|
2791
|
+
|
|
2792
|
+
/**
|
|
2793
|
+
* Pure data operations over the ASCII diagram model — the write-direction
|
|
2794
|
+
* half of the fence-is-source-of-truth loop:
|
|
2795
|
+
*
|
|
2796
|
+
* fence text → parseAsciiDiagram → op → renderAsciiDiagram → fence text
|
|
2797
|
+
*
|
|
2798
|
+
* Every op returns a new AsciiDiagram (inputs are never mutated) and
|
|
2799
|
+
* maintains the invariants the renderer/parser fixpoint relies on:
|
|
2800
|
+
* container moves translate whole subtrees, removals promote children and
|
|
2801
|
+
* drop incident edges, sizes never fall below what a label needs.
|
|
2802
|
+
*/
|
|
2803
|
+
|
|
2804
|
+
/**
|
|
2805
|
+
* Make arbitrary (rename-dialog) input safe as a box label: box-drawing /
|
|
2806
|
+
* arrow glyphs would corrupt the art, and the Scene's inline editor is
|
|
2807
|
+
* single-line, so newlines collapse to spaces.
|
|
2808
|
+
*/
|
|
2809
|
+
declare function sanitizeAsciiLabel(label: string): string;
|
|
2810
|
+
/** Translate every node by the same grid delta (edges/containment are unchanged). */
|
|
2811
|
+
declare function translateDiagramOp(diagram: AsciiDiagram, dCol: number, dRow: number): AsciiDiagram;
|
|
2812
|
+
/** Move a node to (col, row); a container drags its whole subtree along. */
|
|
2813
|
+
declare function moveNodeOp(diagram: AsciiDiagram, nodeId: string, col: number, row: number): AsciiDiagram;
|
|
2814
|
+
/** Resize a node (grid cells). Clamped so the label always fits. */
|
|
2815
|
+
declare function resizeNodeOp(diagram: AsciiDiagram, nodeId: string, wCols: number, hRows: number): AsciiDiagram;
|
|
2816
|
+
/** Add a directed edge; duplicates (same source/target/label) are no-ops. */
|
|
2817
|
+
declare function addEdgeOp(diagram: AsciiDiagram, source: string, target: string, label?: string): AsciiDiagram;
|
|
2818
|
+
/**
|
|
2819
|
+
* Remove an edge. A label-qualified call removes the exact match; without
|
|
2820
|
+
* a label the first (source, target) match goes — mirroring the legacy
|
|
2821
|
+
* `removeConnection` semantics.
|
|
2822
|
+
*/
|
|
2823
|
+
declare function removeEdgeOp(diagram: AsciiDiagram, source: string, target: string, label?: string): AsciiDiagram;
|
|
2824
|
+
/**
|
|
2825
|
+
* Rename a node. The label drives the node's parse-derived id, so edges
|
|
2826
|
+
* and containment references are rewritten to the id the next parse will
|
|
2827
|
+
* produce. (Selection in the canvas drops after a rename — documented.)
|
|
2828
|
+
*/
|
|
2829
|
+
declare function renameNodeOp(diagram: AsciiDiagram, nodeId: string, label: string): AsciiDiagram;
|
|
2830
|
+
/** Add a node at (col, row). Inherits a container when placed inside one. */
|
|
2831
|
+
declare function addNodeOp(diagram: AsciiDiagram, opts: {
|
|
2832
|
+
col: number;
|
|
2833
|
+
row: number;
|
|
2834
|
+
label?: string;
|
|
2835
|
+
}): {
|
|
2836
|
+
diagram: AsciiDiagram;
|
|
2837
|
+
label: string;
|
|
2838
|
+
};
|
|
2839
|
+
/**
|
|
2840
|
+
* Remove a node: incident edges (both directions) drop, direct children
|
|
2841
|
+
* are promoted to the removed node's own container (or top level).
|
|
2842
|
+
*/
|
|
2843
|
+
declare function removeNodeOp(diagram: AsciiDiagram, nodeId: string): AsciiDiagram;
|
|
2844
|
+
|
|
2845
|
+
/**
|
|
2846
|
+
* Paste gate for bare (unfenced) ASCII diagram art.
|
|
2847
|
+
*
|
|
2848
|
+
* `+--+ | |` art pasted as plain text is otherwise mangled: its `| x |`
|
|
2849
|
+
* rows match the GFM table-row pattern in `detectMarkdown`, so the paste
|
|
2850
|
+
* handler routes it through the markdown converter, fails table
|
|
2851
|
+
* validation, and emits one broken paragraph per line. When this gate
|
|
2852
|
+
* matches, the paste handler inserts the text verbatim into a fresh code
|
|
2853
|
+
* block instead — which the AsciiDiagramExtension then picks up as an
|
|
2854
|
+
* interactive diagram.
|
|
2855
|
+
*/
|
|
2856
|
+
declare function shouldPasteAsAsciiFence(text: string): boolean;
|
|
2857
|
+
|
|
2858
|
+
/**
|
|
2859
|
+
* TreeViewExtension — Tiptap/ProseMirror plugin that turns code blocks
|
|
2860
|
+
* containing ASCII file-tree / outline art into interactive outline editors.
|
|
2861
|
+
*
|
|
2862
|
+
* Structurally identical to AsciiDiagramExtension (position registry, stable
|
|
2863
|
+
* synthetic ids, hysteresis, self-rewrite-survival via the decoration key);
|
|
2864
|
+
* only the detect/parse gates and class names differ. The fence text stays
|
|
2865
|
+
* the source of truth — every edit re-renders the tree art.
|
|
2866
|
+
*
|
|
2867
|
+
* Mutual exclusion with the diagram extension: a fence with ≥2 closed boxes
|
|
2868
|
+
* is a diagram, never a tree (checked in both gates), so at most one
|
|
2869
|
+
* extension claims any given fence.
|
|
2870
|
+
*/
|
|
2871
|
+
|
|
2872
|
+
interface TreeBlockEntry {
|
|
2873
|
+
/** Synthetic session id (`tree-N`), stable across edits for one block. */
|
|
2455
2874
|
id: string;
|
|
2875
|
+
/** Document position of the codeBlock node at the current state. */
|
|
2876
|
+
pos: number;
|
|
2877
|
+
}
|
|
2878
|
+
interface TreeViewPluginState {
|
|
2879
|
+
entries: TreeBlockEntry[];
|
|
2880
|
+
decorations: DecorationSet;
|
|
2881
|
+
seq: number;
|
|
2882
|
+
}
|
|
2883
|
+
declare function findTreeBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
2884
|
+
interface TreeViewExtensionOptions {
|
|
2885
|
+
/** When false, the extension is inert (no widgets, no decorations). */
|
|
2886
|
+
enabled?: boolean;
|
|
2887
|
+
}
|
|
2888
|
+
declare const TreeViewExtension: Extension<TreeViewExtensionOptions, any>;
|
|
2889
|
+
|
|
2890
|
+
interface TreeOutlineWidgetProps {
|
|
2891
|
+
editor: Editor$1;
|
|
2892
|
+
blockId: string;
|
|
2893
|
+
fallbackPos: number;
|
|
2894
|
+
host?: HTMLElement | null;
|
|
2456
2895
|
}
|
|
2896
|
+
declare function TreeOutlineWidget({ editor, blockId }: TreeOutlineWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
2897
|
+
|
|
2898
|
+
/**
|
|
2899
|
+
* Read direction of the tree loop: fence text → outline view.
|
|
2900
|
+
*
|
|
2901
|
+
* `useTreeViewData` re-derives on every editor transaction; parsing is
|
|
2902
|
+
* memoized per PMNode by the extension's WeakMap caches, so untouched
|
|
2903
|
+
* fences cost nothing.
|
|
2904
|
+
*/
|
|
2905
|
+
|
|
2906
|
+
interface TreeViewData {
|
|
2907
|
+
tree: Tree;
|
|
2908
|
+
text: string;
|
|
2909
|
+
warnings: string[];
|
|
2910
|
+
}
|
|
2911
|
+
/** Live view of one registered tree block; null when it no longer parses. */
|
|
2912
|
+
declare function useTreeViewData(editor: Editor$1, blockId: string): TreeViewData | null;
|
|
2913
|
+
|
|
2914
|
+
/**
|
|
2915
|
+
* Pure outline operations over the tree model — the write-direction half of
|
|
2916
|
+
* the fence-is-source-of-truth loop:
|
|
2917
|
+
*
|
|
2918
|
+
* fence text → parseTree → op → renderTree → fence text
|
|
2919
|
+
*
|
|
2920
|
+
* Every op returns a NEW Tree (inputs untouched). These are the genuinely
|
|
2921
|
+
* new operations with no diagram analog: indent / outdent (re-parent a node
|
|
2922
|
+
* carrying its subtree), move-up / move-down (reorder siblings), plus
|
|
2923
|
+
* add / rename / remove / toggle-directory. Connector rails re-derive in
|
|
2924
|
+
* render, so ops only touch structure + labels.
|
|
2925
|
+
*/
|
|
2926
|
+
|
|
2927
|
+
/** Make an arbitrary rename safe as a tree label: no connector glyphs / newlines. */
|
|
2928
|
+
declare function sanitizeTreeLabel(label: string): string;
|
|
2929
|
+
type TreeDropPosition = 'before' | 'child' | 'after';
|
|
2930
|
+
declare function renameItemOp(tree: Tree, id: string, label: string): Tree;
|
|
2931
|
+
declare function addItemOp(tree: Tree, targetId: string, position: 'child' | 'siblingAfter', label?: string, isDir?: boolean): Tree;
|
|
2932
|
+
declare function removeItemOp(tree: Tree, id: string): Tree;
|
|
2933
|
+
/** Node becomes the last child of its immediate preceding sibling. */
|
|
2934
|
+
declare function indentItemOp(tree: Tree, id: string): Tree;
|
|
2935
|
+
/** Node becomes a sibling of its parent, inserted directly after it (subtree carried). */
|
|
2936
|
+
declare function outdentItemOp(tree: Tree, id: string): Tree;
|
|
2937
|
+
declare function moveItemUpOp(tree: Tree, id: string): Tree;
|
|
2938
|
+
declare function moveItemDownOp(tree: Tree, id: string): Tree;
|
|
2939
|
+
/** Toggle the trailing-slash directory marker on a node's label. */
|
|
2940
|
+
declare function toggleDirOp(tree: Tree, id: string): Tree;
|
|
2941
|
+
|
|
2457
2942
|
/**
|
|
2458
|
-
*
|
|
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.
|
|
2943
|
+
* Write direction of the tree loop: outline command → fence rewrite.
|
|
2463
2944
|
*
|
|
2464
|
-
*
|
|
2465
|
-
*
|
|
2466
|
-
*
|
|
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.
|
|
2945
|
+
* parse → op → render → verify-reparse → single-transaction fence replace
|
|
2946
|
+
* (one undo step). Reuses the generic `replaceAsciiFenceText` (it only
|
|
2947
|
+
* touches codeBlock text, attributes untouched).
|
|
2470
2948
|
*/
|
|
2471
|
-
|
|
2949
|
+
|
|
2950
|
+
type TreeCommand = {
|
|
2951
|
+
kind: 'addItem';
|
|
2952
|
+
targetId: string;
|
|
2953
|
+
position: 'child' | 'siblingAfter';
|
|
2954
|
+
label?: string;
|
|
2955
|
+
isDir?: boolean;
|
|
2956
|
+
} | {
|
|
2957
|
+
kind: 'renameItem';
|
|
2958
|
+
id: string;
|
|
2959
|
+
label: string;
|
|
2960
|
+
} | {
|
|
2961
|
+
kind: 'indentItem';
|
|
2962
|
+
id: string;
|
|
2963
|
+
} | {
|
|
2964
|
+
kind: 'outdentItem';
|
|
2965
|
+
id: string;
|
|
2966
|
+
} | {
|
|
2967
|
+
kind: 'moveItem';
|
|
2968
|
+
id: string;
|
|
2969
|
+
targetId: string;
|
|
2970
|
+
position: TreeDropPosition;
|
|
2971
|
+
} | {
|
|
2972
|
+
kind: 'moveItemUp';
|
|
2973
|
+
id: string;
|
|
2974
|
+
} | {
|
|
2975
|
+
kind: 'moveItemDown';
|
|
2976
|
+
id: string;
|
|
2977
|
+
} | {
|
|
2978
|
+
kind: 'removeItem';
|
|
2979
|
+
id: string;
|
|
2980
|
+
} | {
|
|
2981
|
+
kind: 'toggleDir';
|
|
2982
|
+
id: string;
|
|
2983
|
+
};
|
|
2984
|
+
|
|
2985
|
+
declare function applyTreeCommand(editor: Editor$1, blockId: string, cmd: TreeCommand): boolean;
|
|
2986
|
+
|
|
2472
2987
|
/**
|
|
2473
|
-
*
|
|
2988
|
+
* Paste gate for bare (unfenced) ASCII tree art. `├──`/`└──` file-tree lines
|
|
2989
|
+
* would otherwise route through the markdown converter and mangle; when this
|
|
2990
|
+
* matches, the paste handler drops the text verbatim into a fresh code block
|
|
2991
|
+
* that the TreeViewExtension picks up as an interactive outline.
|
|
2992
|
+
*/
|
|
2993
|
+
declare function shouldPasteAsTreeFence(text: string): boolean;
|
|
2994
|
+
|
|
2995
|
+
/**
|
|
2996
|
+
* TimelineViewExtension — mounts a WYSIWYG timeline editor over qualifying
|
|
2997
|
+
* authored timeline code fences while keeping the fence text as source of
|
|
2998
|
+
* truth. Every semantic edit is rendered back through the core codec.
|
|
2999
|
+
*/
|
|
3000
|
+
|
|
3001
|
+
interface TimelineBlockEntry {
|
|
3002
|
+
/** Synthetic session id, stable across edits to one fence. */
|
|
3003
|
+
id: string;
|
|
3004
|
+
/** Current document position of the codeBlock node. */
|
|
3005
|
+
pos: number;
|
|
3006
|
+
}
|
|
3007
|
+
interface TimelineViewPluginState {
|
|
3008
|
+
entries: TimelineBlockEntry[];
|
|
3009
|
+
decorations: DecorationSet;
|
|
3010
|
+
seq: number;
|
|
3011
|
+
}
|
|
3012
|
+
declare const TIMELINE_VIEW_KEY: PluginKey<TimelineViewPluginState>;
|
|
3013
|
+
/** Conservative full-detection gate used when first claiming a code fence. */
|
|
3014
|
+
declare function getTimelineForNode(node: Node): AsciiTimeline | null;
|
|
3015
|
+
/** Relaxed/sticky gate for a block already registered by this extension. */
|
|
3016
|
+
declare function parseTimelineForNode(node: Node): AsciiTimeline | null;
|
|
3017
|
+
declare function findTimelineBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
3018
|
+
interface TimelineViewExtensionOptions {
|
|
3019
|
+
/** When false, the extension does not claim fences or mount widgets. */
|
|
3020
|
+
enabled?: boolean;
|
|
3021
|
+
}
|
|
3022
|
+
declare const TimelineViewExtension: Extension<TimelineViewExtensionOptions, any>;
|
|
3023
|
+
|
|
3024
|
+
interface TimelineEditorWidgetProps {
|
|
3025
|
+
editor: Editor$1;
|
|
3026
|
+
blockId: string;
|
|
3027
|
+
}
|
|
3028
|
+
declare function TimelineEditorWidget({ editor, blockId }: TimelineEditorWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
3029
|
+
|
|
3030
|
+
/** Live read-direction adapter from a registered timeline fence to React. */
|
|
3031
|
+
|
|
3032
|
+
interface TimelineViewData {
|
|
3033
|
+
timeline: AsciiTimeline;
|
|
3034
|
+
text: string;
|
|
3035
|
+
warnings: string[];
|
|
3036
|
+
}
|
|
3037
|
+
declare function useTimelineData(editor: Editor$1, blockId: string): TimelineViewData | null;
|
|
3038
|
+
|
|
3039
|
+
/**
|
|
3040
|
+
* Pure edits over the authored ASCII timeline model.
|
|
2474
3041
|
*
|
|
2475
|
-
*
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2478
|
-
*
|
|
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.
|
|
3042
|
+
* The code fence remains the source of truth. Canvas coordinates are
|
|
3043
|
+
* normalized to the same global, shared scale used by
|
|
3044
|
+
* `asciiTimelineToTemplateData`; commands render the edited model back into
|
|
3045
|
+
* canonical fence text after applying one of these operations.
|
|
2483
3046
|
*/
|
|
2484
|
-
|
|
3047
|
+
|
|
3048
|
+
interface TimelineEventPatch {
|
|
3049
|
+
label?: string;
|
|
3050
|
+
/** `null` clears the optional description. */
|
|
3051
|
+
description?: string | null;
|
|
3052
|
+
side?: AsciiTimelineSide;
|
|
3053
|
+
/** `null` restores the label side/default placement. */
|
|
3054
|
+
descriptionSide?: AsciiTimelineSide | null;
|
|
3055
|
+
callout?: boolean;
|
|
3056
|
+
marker?: AsciiTimelineMarker;
|
|
3057
|
+
/** Normalized position on the global timeline scale. */
|
|
3058
|
+
position?: number;
|
|
3059
|
+
}
|
|
3060
|
+
interface AddTimelineEventOptions {
|
|
3061
|
+
id?: string;
|
|
3062
|
+
label?: string;
|
|
3063
|
+
description?: string;
|
|
3064
|
+
side?: AsciiTimelineSide;
|
|
3065
|
+
descriptionSide?: AsciiTimelineSide;
|
|
3066
|
+
callout?: boolean;
|
|
3067
|
+
marker?: AsciiTimelineMarker;
|
|
3068
|
+
}
|
|
3069
|
+
interface AddTimelineEventResult {
|
|
3070
|
+
timeline: AsciiTimeline;
|
|
3071
|
+
eventId: string;
|
|
3072
|
+
}
|
|
2485
3073
|
/**
|
|
2486
|
-
*
|
|
2487
|
-
*
|
|
3074
|
+
* Normalize editable one-line prose exactly as the canonical core renderer
|
|
3075
|
+
* does. This prevents the verified command path from accepting a value that
|
|
3076
|
+
* is silently reinterpreted as timeline syntax on its first render.
|
|
2488
3077
|
*/
|
|
2489
|
-
declare function
|
|
3078
|
+
declare function sanitizeTimelineText(value: string): string;
|
|
3079
|
+
/** Return a globally unique, renderer-safe event id. */
|
|
3080
|
+
declare function nextTimelineEventId(timeline: AsciiTimeline, base?: string): string;
|
|
2490
3081
|
/**
|
|
2491
|
-
*
|
|
2492
|
-
*
|
|
2493
|
-
*
|
|
3082
|
+
* Add a visible point to `trackId` at a normalized global rail position.
|
|
3083
|
+
* Returns the stable id so the canvas can select/focus the new point after
|
|
3084
|
+
* the fence rewrite.
|
|
2494
3085
|
*/
|
|
2495
|
-
declare function
|
|
3086
|
+
declare function addTimelineEventOp(timeline: AsciiTimeline, trackId: string, position: number, options?: AddTimelineEventOptions): AddTimelineEventResult | null;
|
|
3087
|
+
/** Update one point without changing its stable id or branch endpoints. */
|
|
3088
|
+
declare function updateTimelineEventOp(timeline: AsciiTimeline, eventId: string, patch: TimelineEventPatch): AsciiTimeline;
|
|
2496
3089
|
/**
|
|
2497
|
-
*
|
|
2498
|
-
*
|
|
3090
|
+
* Remove a point and every incident branch. Empty tracks are removed because
|
|
3091
|
+
* the canonical renderer cannot represent them. The last point in the whole
|
|
3092
|
+
* timeline is retained so an edit cannot erase its own source fence/widget.
|
|
2499
3093
|
*/
|
|
2500
|
-
declare function
|
|
3094
|
+
declare function removeTimelineEventOp(timeline: AsciiTimeline, eventId: string): AsciiTimeline;
|
|
3095
|
+
|
|
2501
3096
|
/**
|
|
2502
|
-
*
|
|
2503
|
-
*
|
|
2504
|
-
*
|
|
2505
|
-
*
|
|
3097
|
+
* Write direction for the WYSIWYG timeline editor:
|
|
3098
|
+
*
|
|
3099
|
+
* fence text -> parse -> pure op -> render -> verify -> one fence rewrite
|
|
3100
|
+
*
|
|
3101
|
+
* The original code block remains the source of truth and every successful
|
|
3102
|
+
* edit is a single ProseMirror transaction/undo step.
|
|
2506
3103
|
*/
|
|
2507
|
-
|
|
3104
|
+
|
|
3105
|
+
type TimelineCommand = {
|
|
3106
|
+
kind: 'addTrack';
|
|
3107
|
+
id?: string;
|
|
3108
|
+
label?: string;
|
|
3109
|
+
eventId?: string;
|
|
3110
|
+
eventLabel?: string;
|
|
3111
|
+
} | {
|
|
3112
|
+
kind: 'updateTrack';
|
|
3113
|
+
trackId: string;
|
|
3114
|
+
label: string;
|
|
3115
|
+
} | {
|
|
3116
|
+
kind: 'removeTrack';
|
|
3117
|
+
trackId: string;
|
|
3118
|
+
} | {
|
|
3119
|
+
kind: 'addEvent';
|
|
3120
|
+
trackId: string;
|
|
3121
|
+
/** Normalized position on the global timeline rail. */
|
|
3122
|
+
position: number;
|
|
3123
|
+
id?: string;
|
|
3124
|
+
label?: string;
|
|
3125
|
+
description?: string;
|
|
3126
|
+
side?: AsciiTimelineSide;
|
|
3127
|
+
descriptionSide?: AsciiTimelineSide;
|
|
3128
|
+
callout?: boolean;
|
|
3129
|
+
marker?: AsciiTimelineMarker;
|
|
3130
|
+
} | {
|
|
3131
|
+
kind: 'updateEvent';
|
|
3132
|
+
eventId: string;
|
|
3133
|
+
patch: TimelineEventPatch;
|
|
3134
|
+
} | {
|
|
3135
|
+
kind: 'removeEvent';
|
|
3136
|
+
eventId: string;
|
|
3137
|
+
};
|
|
3138
|
+
interface TimelineCommandResult {
|
|
3139
|
+
applied: boolean;
|
|
3140
|
+
/** Present after add so the widget can select/focus the new marker. */
|
|
3141
|
+
eventId?: string;
|
|
3142
|
+
/** Present after adding a track. */
|
|
3143
|
+
trackId?: string;
|
|
3144
|
+
/** Why an otherwise valid semantic edit was deliberately blocked. */
|
|
3145
|
+
reason?: 'read-only' | 'unsafe-source';
|
|
3146
|
+
}
|
|
2508
3147
|
/**
|
|
2509
|
-
*
|
|
2510
|
-
*
|
|
2511
|
-
*
|
|
3148
|
+
* Semantic operations replace the whole fence with canonical rendered art.
|
|
3149
|
+
* Fail closed when that would discard source the timeline model cannot
|
|
3150
|
+
* represent. Warnings catch unresolved/unlabeled constructs; the semantic
|
|
3151
|
+
* round-trip catches renderer normalization that changes modeled content;
|
|
3152
|
+
* exact metadata validation rejects partially consumed attrs; and a linear
|
|
3153
|
+
* semantic-residue comparison catches ignored prose/symbol rows without
|
|
3154
|
+
* reparsing a successively shorter document for every source line.
|
|
2512
3155
|
*/
|
|
2513
|
-
declare function
|
|
3156
|
+
declare function isTimelineSourceSafeForSemanticEdit(source: string, timeline: AsciiTimeline): boolean;
|
|
3157
|
+
/** Apply one semantic timeline command to a registered fence block. */
|
|
3158
|
+
declare function applyTimelineCommand(editor: Editor$1, blockId: string, command: TimelineCommand): TimelineCommandResult;
|
|
3159
|
+
|
|
3160
|
+
/** Paste gate for bare, high-confidence Unicode timeline art. */
|
|
3161
|
+
declare function shouldPasteAsTimelineFence(text: string): boolean;
|
|
2514
3162
|
|
|
2515
3163
|
interface JsonEditorProps {
|
|
2516
3164
|
/** Schema describing the value's shape (with optional `squisq` hints). */
|
|
@@ -2682,6 +3330,7 @@ interface UseMediaRecorderResult {
|
|
|
2682
3330
|
declare function getCaptureKind(source: RecorderSource): CaptureKind;
|
|
2683
3331
|
declare function useMediaRecorder(options?: UseMediaRecorderOptions): UseMediaRecorderResult;
|
|
2684
3332
|
|
|
3333
|
+
type RecorderColorScheme = 'light' | 'dark';
|
|
2685
3334
|
interface RecorderModalProps {
|
|
2686
3335
|
/** Required — recordings are written here. */
|
|
2687
3336
|
mediaProvider: MediaProvider;
|
|
@@ -2694,6 +3343,8 @@ interface RecorderModalProps {
|
|
|
2694
3343
|
container?: ContentContainer | null;
|
|
2695
3344
|
/** Initial capture source. Defaults to `'mic'` (narration). */
|
|
2696
3345
|
initialMode?: RecorderSource;
|
|
3346
|
+
/** Light/dark chrome scheme. Defaults to `'light'`. */
|
|
3347
|
+
colorScheme?: RecorderColorScheme;
|
|
2697
3348
|
/** Called after the modal is dismissed (save or cancel). */
|
|
2698
3349
|
onClose: () => void;
|
|
2699
3350
|
/**
|
|
@@ -2720,7 +3371,7 @@ interface RecorderSaveResult {
|
|
|
2720
3371
|
/** Script text the user typed (narration only). */
|
|
2721
3372
|
sourceText?: string;
|
|
2722
3373
|
}
|
|
2723
|
-
declare function RecorderModal({ mediaProvider, container, initialMode, onClose, onSave, }: RecorderModalProps): react_jsx_runtime.JSX.Element;
|
|
3374
|
+
declare function RecorderModal({ mediaProvider, container, initialMode, colorScheme, onClose, onSave, }: RecorderModalProps): react_jsx_runtime.JSX.Element;
|
|
2724
3375
|
|
|
2725
3376
|
interface RecorderButtonProps {
|
|
2726
3377
|
/** Where to write the resulting recording. Required. */
|
|
@@ -2729,6 +3380,8 @@ interface RecorderButtonProps {
|
|
|
2729
3380
|
container?: ContentContainer | null;
|
|
2730
3381
|
/** Initial capture source. Defaults to `'mic'`. */
|
|
2731
3382
|
initialMode?: RecorderSource;
|
|
3383
|
+
/** Light/dark chrome scheme copied onto the portaled modal. */
|
|
3384
|
+
colorScheme?: RecorderColorScheme;
|
|
2732
3385
|
/** Fired after a successful save. */
|
|
2733
3386
|
onSave?: (result: RecorderSaveResult) => void;
|
|
2734
3387
|
/** Button label. Defaults to `'Record'`. */
|
|
@@ -2738,19 +3391,21 @@ interface RecorderButtonProps {
|
|
|
2738
3391
|
/** Whether the button is disabled. */
|
|
2739
3392
|
disabled?: boolean;
|
|
2740
3393
|
}
|
|
2741
|
-
declare function RecorderButton({ mediaProvider, container, initialMode, onSave, label, style, disabled, }: RecorderButtonProps): react_jsx_runtime.JSX.Element;
|
|
3394
|
+
declare function RecorderButton({ mediaProvider, container, initialMode, colorScheme, onSave, label, style, disabled, }: RecorderButtonProps): react_jsx_runtime.JSX.Element;
|
|
2742
3395
|
|
|
2743
3396
|
interface RecorderPanelProps {
|
|
2744
3397
|
mediaProvider: MediaProvider;
|
|
2745
3398
|
container?: ContentContainer | null;
|
|
2746
3399
|
initialMode?: RecorderSource;
|
|
3400
|
+
/** Light/dark chrome scheme copied onto the portaled modal. */
|
|
3401
|
+
colorScheme?: RecorderColorScheme;
|
|
2747
3402
|
onSave?: (result: RecorderSaveResult) => void;
|
|
2748
3403
|
/** ARIA / tooltip label. Defaults to `'Record media'`. */
|
|
2749
3404
|
tooltip?: string;
|
|
2750
3405
|
/** Optional className for the trigger button. */
|
|
2751
3406
|
className?: string;
|
|
2752
3407
|
}
|
|
2753
|
-
declare function RecorderPanel({ mediaProvider, container, initialMode, onSave, tooltip, className, }: RecorderPanelProps): react_jsx_runtime.JSX.Element;
|
|
3408
|
+
declare function RecorderPanel({ mediaProvider, container, initialMode, colorScheme, onSave, tooltip, className, }: RecorderPanelProps): react_jsx_runtime.JSX.Element;
|
|
2754
3409
|
|
|
2755
3410
|
/**
|
|
2756
3411
|
* useStreamPreview — binds a `MediaStream` to a `<video>` element's
|
|
@@ -2915,6 +3570,443 @@ declare function encodeTimingJson(timing: TimingJson): Uint8Array;
|
|
|
2915
3570
|
*/
|
|
2916
3571
|
declare function timingPathFor(audioRelativePath: string): string;
|
|
2917
3572
|
|
|
3573
|
+
/** Editor plumbing the recording flow needs; omit for prompter-only use. */
|
|
3574
|
+
interface TeleprompterRecordingDeps {
|
|
3575
|
+
mediaProvider: MediaProvider;
|
|
3576
|
+
container: ContentContainer | null;
|
|
3577
|
+
markdownSource: string;
|
|
3578
|
+
setMarkdownSource: (next: string) => void;
|
|
3579
|
+
bumpMediaRevision: () => void;
|
|
3580
|
+
}
|
|
3581
|
+
interface TeleprompterViewProps {
|
|
3582
|
+
doc: Doc | null;
|
|
3583
|
+
theme: Theme;
|
|
3584
|
+
/** Kept for API symmetry with PreviewPanel; recording uses `recording.container`. */
|
|
3585
|
+
workspaceContainer?: ContentContainer | null;
|
|
3586
|
+
/** Media base path (reserved for future preview integrations). */
|
|
3587
|
+
basePath?: string;
|
|
3588
|
+
/**
|
|
3589
|
+
* Optional audience-window portal owned by the editor's Presentation mode.
|
|
3590
|
+
* The main controller remains authoritative; only this live surface is
|
|
3591
|
+
* mirrored into the target.
|
|
3592
|
+
*/
|
|
3593
|
+
presentationTarget?: HTMLElement | null;
|
|
3594
|
+
/** Recording deps; null/omitted disables the Record affordance. */
|
|
3595
|
+
recording?: TeleprompterRecordingDeps | null;
|
|
3596
|
+
}
|
|
3597
|
+
declare function TeleprompterView(props: TeleprompterViewProps): react_jsx_runtime.JSX.Element;
|
|
3598
|
+
|
|
3599
|
+
/**
|
|
3600
|
+
* Mic capture + PCM transport for the teleprompter.
|
|
3601
|
+
*
|
|
3602
|
+
* getUserMedia → AudioContext → AudioWorklet tap → subscriber callbacks
|
|
3603
|
+
* with 1024-sample Float32Array hops on the main thread. The DSP itself
|
|
3604
|
+
* lives in core (`@bendyline/squisq/narration`) — this hook only moves
|
|
3605
|
+
* samples. Falls back to a ScriptProcessorNode when `audioWorklet` is
|
|
3606
|
+
* unavailable (same push model, so pacing still isn't tied to rAF).
|
|
3607
|
+
*/
|
|
3608
|
+
type MicAnalysisStatus = 'idle' | 'starting' | 'live' | 'error';
|
|
3609
|
+
type PcmHopListener = (pcm: Float32Array, audioTimeSec: number) => void;
|
|
3610
|
+
interface MicAnalysisHandle {
|
|
3611
|
+
status: MicAnalysisStatus;
|
|
3612
|
+
error: Error | null;
|
|
3613
|
+
/** The live mic stream (feeds the narration recorder too), or null. */
|
|
3614
|
+
stream: MediaStream | null;
|
|
3615
|
+
/** AudioContext sample rate once live. */
|
|
3616
|
+
sampleRate: number | null;
|
|
3617
|
+
/** Known audio inputs (labels appear after the first grant). */
|
|
3618
|
+
devices: MediaDeviceInfo[];
|
|
3619
|
+
/**
|
|
3620
|
+
* Start (or restart) capture. Resolves with the live stream — callers
|
|
3621
|
+
* that need it immediately must use the return value, not the `stream`
|
|
3622
|
+
* state field, which only updates on the NEXT render (stale-closure
|
|
3623
|
+
* hazard right after an await). Null on failure/supersession.
|
|
3624
|
+
*/
|
|
3625
|
+
start: (deviceId: string | null) => Promise<MediaStream | null>;
|
|
3626
|
+
stop: () => void;
|
|
3627
|
+
/** Subscribe to PCM hops; returns an unsubscribe. */
|
|
3628
|
+
subscribeHop: (listener: PcmHopListener) => () => void;
|
|
3629
|
+
}
|
|
3630
|
+
declare function useMicAnalysis(): MicAnalysisHandle;
|
|
3631
|
+
|
|
3632
|
+
/**
|
|
3633
|
+
* Narration recorder for the teleprompter — an in-place (no modal)
|
|
3634
|
+
* capture flow.
|
|
3635
|
+
*
|
|
3636
|
+
* Audio records THE MIC ANALYSIS STREAM (what paces the prompter is
|
|
3637
|
+
* exactly what lands in the take); the optional camera is a separate
|
|
3638
|
+
* video-only capture whose start skew vs the audio recorder is measured
|
|
3639
|
+
* and persisted (`cameraOffsetSec`) — the audio file is the doc clock,
|
|
3640
|
+
* so camera skew never affects narration timing. While recording, a
|
|
3641
|
+
* sparse live trace of the prompter position is sampled; after stop,
|
|
3642
|
+
* the take is decoded and run through core's offline aligner
|
|
3643
|
+
* (`alignNarration`) to produce word/block timestamps for the sidecar.
|
|
3644
|
+
* Decode/alignment failure degrades gracefully: saving still works,
|
|
3645
|
+
* just without re-timing.
|
|
3646
|
+
*/
|
|
3647
|
+
|
|
3648
|
+
type NarrationRecorderState = 'idle' | 'starting' | 'recording' | 'processing' | 'review' | 'saving' | 'error';
|
|
3649
|
+
interface NarrationTake {
|
|
3650
|
+
audioBlob: Blob;
|
|
3651
|
+
audioMime: string;
|
|
3652
|
+
audioExt: string;
|
|
3653
|
+
cameraBlob: Blob | null;
|
|
3654
|
+
cameraMime: string | null;
|
|
3655
|
+
cameraExt: string | null;
|
|
3656
|
+
durationSec: number;
|
|
3657
|
+
cameraOffsetSec: number | undefined;
|
|
3658
|
+
trace: NarrationTrace;
|
|
3659
|
+
alignment: NarrationAlignment | null;
|
|
3660
|
+
script: NarrationScript;
|
|
3661
|
+
}
|
|
3662
|
+
interface UseNarrationRecorderOptions {
|
|
3663
|
+
mic: MicAnalysisHandle;
|
|
3664
|
+
getScript: () => NarrationScript | null;
|
|
3665
|
+
/** Live prompter position, sampled into the trace while recording. */
|
|
3666
|
+
getWordPos: () => number;
|
|
3667
|
+
getMicDeviceId: () => string | null;
|
|
3668
|
+
/** Fired when capture actually starts (View starts the prompter). */
|
|
3669
|
+
onRecordingStart?: () => void;
|
|
3670
|
+
onRecordingStop?: () => void;
|
|
3671
|
+
}
|
|
3672
|
+
interface NarrationRecorderController {
|
|
3673
|
+
state: NarrationRecorderState;
|
|
3674
|
+
error: Error | null;
|
|
3675
|
+
withCamera: boolean;
|
|
3676
|
+
setWithCamera: (on: boolean) => void;
|
|
3677
|
+
/** Live camera stream for the self-view while recording. */
|
|
3678
|
+
cameraStream: MediaStream | null;
|
|
3679
|
+
take: NarrationTake | null;
|
|
3680
|
+
start: () => Promise<void>;
|
|
3681
|
+
stop: () => Promise<void>;
|
|
3682
|
+
retake: () => void;
|
|
3683
|
+
discard: () => void;
|
|
3684
|
+
/** Transition into/out of 'saving'; the View owns the actual I/O. */
|
|
3685
|
+
beginSave: () => void;
|
|
3686
|
+
finishSave: (ok: boolean, error?: Error) => void;
|
|
3687
|
+
}
|
|
3688
|
+
declare function useNarrationRecorder(options: UseNarrationRecorderOptions): NarrationRecorderController;
|
|
3689
|
+
|
|
3690
|
+
/**
|
|
3691
|
+
* Pure save-plan builder for a narration take, plus its executor.
|
|
3692
|
+
*
|
|
3693
|
+
* Follows the recorder's conventions (`RecorderModal.handleSave`):
|
|
3694
|
+
* audio at `audio/<narration-…>` via `MediaProvider.addMedia` (the
|
|
3695
|
+
* RETURNED path is authoritative — providers may rename), the timing
|
|
3696
|
+
* sidecar at `<audio>.timing.json` via `container.writeFile` (falling
|
|
3697
|
+
* back to `addMedia` with a warning), and ONE `setMarkdownSource` write
|
|
3698
|
+
* composing every markdown edit from a single snapshot (the single-write
|
|
3699
|
+
* rule — successive writes each derive from stale source and clobber
|
|
3700
|
+
* each other).
|
|
3701
|
+
*
|
|
3702
|
+
* Block timings deliberately do NOT get baked into heading `duration=`
|
|
3703
|
+
* pins: pins outrank narration in `applyNarrationTiming`, so baking
|
|
3704
|
+
* them would shadow every retake. The sidecar owns the timing.
|
|
3705
|
+
*/
|
|
3706
|
+
|
|
3707
|
+
interface NarrationSavePlanArgs {
|
|
3708
|
+
script: NarrationScript;
|
|
3709
|
+
/** Null when decode/alignment failed — the sidecar still saves (empty timing). */
|
|
3710
|
+
alignment: NarrationAlignment | null;
|
|
3711
|
+
durationSec: number;
|
|
3712
|
+
audioExt: string;
|
|
3713
|
+
cameraExt: string | null;
|
|
3714
|
+
baseWpm: number;
|
|
3715
|
+
cameraOffsetSec?: number;
|
|
3716
|
+
}
|
|
3717
|
+
interface NarrationSavePlan {
|
|
3718
|
+
audioRelativeName: string;
|
|
3719
|
+
cameraRelativeName: string | null;
|
|
3720
|
+
sidecarPayload: NarrationTimingJsonV3;
|
|
3721
|
+
/** Sidecar path for a given (possibly renamed) saved audio path. */
|
|
3722
|
+
sidecarPathFor: (savedAudioPath: string) => string;
|
|
3723
|
+
/** Compose ALL markdown edits from one source snapshot. */
|
|
3724
|
+
nextMarkdown: (currentSource: string, savedAudioPath: string, savedCameraPath: string | null) => string;
|
|
3725
|
+
}
|
|
3726
|
+
declare function buildNarrationSavePlan(args: NarrationSavePlanArgs): NarrationSavePlan;
|
|
3727
|
+
interface ExecuteNarrationSaveDeps {
|
|
3728
|
+
mediaProvider: MediaProvider;
|
|
3729
|
+
container: ContentContainer | null;
|
|
3730
|
+
markdownSource: string;
|
|
3731
|
+
setMarkdownSource: (next: string) => void;
|
|
3732
|
+
bumpMediaRevision: () => void;
|
|
3733
|
+
}
|
|
3734
|
+
interface NarrationSaveResult {
|
|
3735
|
+
audioPath: string;
|
|
3736
|
+
cameraPath: string | null;
|
|
3737
|
+
sidecarPath: string;
|
|
3738
|
+
}
|
|
3739
|
+
/** Execute a save plan: media writes, sidecar, then the single markdown write. */
|
|
3740
|
+
declare function executeNarrationSave(plan: NarrationSavePlan, take: {
|
|
3741
|
+
audioBlob: Blob;
|
|
3742
|
+
audioMime: string;
|
|
3743
|
+
cameraBlob: Blob | null;
|
|
3744
|
+
cameraMime: string | null;
|
|
3745
|
+
}, deps: ExecuteNarrationSaveDeps): Promise<NarrationSaveResult>;
|
|
3746
|
+
|
|
3747
|
+
/**
|
|
3748
|
+
* Pure markdown edit: insert (or replace) the narration reference at the
|
|
3749
|
+
* start of the document.
|
|
3750
|
+
*
|
|
3751
|
+
* The narration take is referenced by a preamble media annotation —
|
|
3752
|
+
* `{[audio src=audio/narration-….webm anchor=document]}` — the canonical
|
|
3753
|
+
* authored form `markdownToDoc` lifts into `doc.documentMedia`. A prior
|
|
3754
|
+
* teleprompter take's line (matched by the `audio/narration-` prefix +
|
|
3755
|
+
* `anchor=document`) is replaced, so retakes swap the reference instead
|
|
3756
|
+
* of stacking narrations. The optional camera companion rides on the
|
|
3757
|
+
* next line as an inline `<video>` (deliberately NOT doc-anchored:
|
|
3758
|
+
* document-anchored video renders full-bleed behind every block and is
|
|
3759
|
+
* excluded from export audio — not a talking head).
|
|
3760
|
+
*/
|
|
3761
|
+
declare function narrationAnnotationLine(audioPath: string): string;
|
|
3762
|
+
declare function cameraVideoLine(cameraPath: string): string;
|
|
3763
|
+
/**
|
|
3764
|
+
* Insert the narration preamble after the frontmatter (or at the top),
|
|
3765
|
+
* replacing any previous teleprompter take's lines.
|
|
3766
|
+
*/
|
|
3767
|
+
declare function insertNarrationPreamble(source: string, audioPath: string, cameraPath: string | null): string;
|
|
3768
|
+
|
|
3769
|
+
interface TeleprompterSurfaceProps {
|
|
3770
|
+
script: NarrationScript;
|
|
3771
|
+
/** Fractional word position; floor is the active token. */
|
|
3772
|
+
wordPos: number;
|
|
3773
|
+
fontSizePx: number;
|
|
3774
|
+
mirrored: boolean;
|
|
3775
|
+
lineGuide: boolean;
|
|
3776
|
+
countdownRemaining: number | null;
|
|
3777
|
+
recordingIndicator: boolean;
|
|
3778
|
+
theme: Theme;
|
|
3779
|
+
/** Hide block markers / tighten padding for small float windows. */
|
|
3780
|
+
compact?: boolean;
|
|
3781
|
+
/** Click a word to jump the prompter there. */
|
|
3782
|
+
onSeekToken?: (tokenIndex: number) => void;
|
|
3783
|
+
}
|
|
3784
|
+
declare function TeleprompterSurface({ script, wordPos, fontSizePx, mirrored, lineGuide, countdownRemaining, recordingIndicator, theme, compact, onSeekToken, }: TeleprompterSurfaceProps): react_jsx_runtime.JSX.Element;
|
|
3785
|
+
|
|
3786
|
+
/**
|
|
3787
|
+
* Shared types for the Narrate (teleprompter) display mode.
|
|
3788
|
+
*/
|
|
3789
|
+
interface TeleprompterPrefs {
|
|
3790
|
+
/** Prompter type size in px (28–96). */
|
|
3791
|
+
fontSizePx: number;
|
|
3792
|
+
/** Beam-splitter mirror flip. */
|
|
3793
|
+
mirrored: boolean;
|
|
3794
|
+
/** Base speaking rate in words per minute (80–260). */
|
|
3795
|
+
baseWpm: number;
|
|
3796
|
+
/** Voice-adaptive pacing on/off; off = constant-rate manual mode. */
|
|
3797
|
+
voiceTracking: boolean;
|
|
3798
|
+
/** VAD sensitivity 0–1 (0.5 = engine defaults). */
|
|
3799
|
+
vadSensitivity: number;
|
|
3800
|
+
/** Countdown before the prompter starts rolling. */
|
|
3801
|
+
countdownSec: 0 | 3 | 5 | 10;
|
|
3802
|
+
/** Eye-line chevrons + focus band. */
|
|
3803
|
+
lineGuide: boolean;
|
|
3804
|
+
/** Preferred mic device id (null = system default). */
|
|
3805
|
+
micDeviceId: string | null;
|
|
3806
|
+
}
|
|
3807
|
+
declare const DEFAULT_TELEPROMPTER_PREFS: TeleprompterPrefs;
|
|
3808
|
+
type PrompterTransport = 'stopped' | 'countdown' | 'rolling' | 'paused' | 'finished';
|
|
3809
|
+
/** Floating-surface tier, best first. */
|
|
3810
|
+
type FloatTier = 'document-pip' | 'video-pip' | 'popup' | 'docked';
|
|
3811
|
+
|
|
3812
|
+
/**
|
|
3813
|
+
* The teleprompter controller — single source of truth, always in the
|
|
3814
|
+
* MAIN window (floats are render targets only).
|
|
3815
|
+
*
|
|
3816
|
+
* Loop-ownership rule: **the audio worklet owns time; the main window
|
|
3817
|
+
* owns state; the visible surface owns pixels.** Voice-mode position
|
|
3818
|
+
* advances on worklet PCM hops (immune to rAF/timer throttling while
|
|
3819
|
+
* the browser is occluded by recording software); manual constant-rate
|
|
3820
|
+
* mode uses rAF and is documented as best-effort under occlusion. React
|
|
3821
|
+
* state publishes at ~15 Hz; per-hop subscribers (`subscribeTick`)
|
|
3822
|
+
* exist for the video-PiP canvas pump.
|
|
3823
|
+
*/
|
|
3824
|
+
|
|
3825
|
+
interface TeleprompterController {
|
|
3826
|
+
script: NarrationScript | null;
|
|
3827
|
+
transport: PrompterTransport;
|
|
3828
|
+
countdownRemaining: number | null;
|
|
3829
|
+
/** Fractional word position (published ~15 Hz). */
|
|
3830
|
+
wordPos: number;
|
|
3831
|
+
/** Smoothed mic level 0–1 for the meter. */
|
|
3832
|
+
micLevel: number;
|
|
3833
|
+
/** VAD flag for the meter tint. */
|
|
3834
|
+
voiceActive: boolean;
|
|
3835
|
+
mic: MicAnalysisHandle;
|
|
3836
|
+
prefs: TeleprompterPrefs;
|
|
3837
|
+
setPrefs: (patch: Partial<TeleprompterPrefs>) => void;
|
|
3838
|
+
play: () => void;
|
|
3839
|
+
pause: () => void;
|
|
3840
|
+
restart: () => void;
|
|
3841
|
+
/** Move the prompter by whole tokens and re-anchor voice tracking. */
|
|
3842
|
+
nudge: (deltaTokens: number) => void;
|
|
3843
|
+
/** Jump to an absolute token index (e.g. click a block marker). */
|
|
3844
|
+
seekToToken: (tokenIndex: number) => void;
|
|
3845
|
+
/** Per-analysis-tick subscription (video-PiP pump). Not throttled. */
|
|
3846
|
+
subscribeTick: (cb: (wordPos: number) => void) => () => void;
|
|
3847
|
+
handleKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
|
|
3848
|
+
}
|
|
3849
|
+
/** Map the 0–1 sensitivity pref onto VAD thresholds (0.5 = engine defaults). */
|
|
3850
|
+
declare function vadConfigForSensitivity(sensitivity: number): Partial<VadConfig>;
|
|
3851
|
+
declare function useTeleprompter(opts: {
|
|
3852
|
+
doc: Doc | null;
|
|
3853
|
+
}): TeleprompterController;
|
|
3854
|
+
|
|
3855
|
+
/**
|
|
3856
|
+
* Floating-teleprompter window manager — framework-free.
|
|
3857
|
+
*
|
|
3858
|
+
* Capability ladder, best first:
|
|
3859
|
+
* 1. `document-pip` — Document Picture-in-Picture (Chromium 116+,
|
|
3860
|
+
* Firefox 151+): a true always-on-top window hosting live DOM; the
|
|
3861
|
+
* React surface portals into it.
|
|
3862
|
+
* 2. `video-pip` — canvas → `captureStream(0)` → `<video>` →
|
|
3863
|
+
* `requestPictureInPicture()` (Safari's only always-on-top path;
|
|
3864
|
+
* `webkitSetPresentationMode` fallback). Read-only: the main
|
|
3865
|
+
* window draws frames and calls `requestFrame()` on analysis
|
|
3866
|
+
* ticks — never rAF, which throttles under occlusion.
|
|
3867
|
+
* 3. `popup` — `window.open` (positionable, not always-on-top).
|
|
3868
|
+
* 4. `docked` — no float.
|
|
3869
|
+
*
|
|
3870
|
+
* Every tier is feature-detected at open time and falls through to the
|
|
3871
|
+
* next on ANY failure. All interactive state stays in the main window;
|
|
3872
|
+
* floats are render targets only.
|
|
3873
|
+
*/
|
|
3874
|
+
|
|
3875
|
+
interface FloatOpenOptions {
|
|
3876
|
+
width: number;
|
|
3877
|
+
height: number;
|
|
3878
|
+
/** Try this tier first; the ladder continues below it on failure. */
|
|
3879
|
+
preferredTier?: FloatTier;
|
|
3880
|
+
title: string;
|
|
3881
|
+
}
|
|
3882
|
+
interface CanvasSink {
|
|
3883
|
+
canvas: HTMLCanvasElement;
|
|
3884
|
+
width: number;
|
|
3885
|
+
height: number;
|
|
3886
|
+
/** Push the freshly drawn canvas frame into the PiP video. */
|
|
3887
|
+
requestFrame: () => void;
|
|
3888
|
+
}
|
|
3889
|
+
type FloatEvent = 'closed' | 'tierchange';
|
|
3890
|
+
interface FloatingWindowManager {
|
|
3891
|
+
readonly tier: FloatTier;
|
|
3892
|
+
readonly isOpen: boolean;
|
|
3893
|
+
/** Resolves with the tier that actually opened ('docked' if none could). */
|
|
3894
|
+
open(opts: FloatOpenOptions): Promise<FloatTier>;
|
|
3895
|
+
/** Idempotent; restores docked and emits 'closed'. */
|
|
3896
|
+
close(): void;
|
|
3897
|
+
/** Portal container for 'document-pip' | 'popup'; null otherwise. */
|
|
3898
|
+
getPortalTarget(): HTMLElement | null;
|
|
3899
|
+
/** Canvas sink for 'video-pip'; null otherwise. */
|
|
3900
|
+
getCanvasSink(): CanvasSink | null;
|
|
3901
|
+
on(event: FloatEvent, cb: (tier: FloatTier) => void): () => void;
|
|
3902
|
+
/** Tear everything down (unmount); like close() but silent-safe. */
|
|
3903
|
+
dispose(): void;
|
|
3904
|
+
}
|
|
3905
|
+
/** Feature-detect the available float tiers, best first. */
|
|
3906
|
+
declare function detectFloatTiers(): FloatTier[];
|
|
3907
|
+
declare function createFloatingWindowManager(deps: {
|
|
3908
|
+
styleCss: string;
|
|
3909
|
+
}): FloatingWindowManager;
|
|
3910
|
+
|
|
3911
|
+
/**
|
|
3912
|
+
* React binding over {@link createFloatingWindowManager}: exposes the
|
|
3913
|
+
* current tier + portal target as state and guarantees the float closes
|
|
3914
|
+
* when the owning view unmounts (mode switch, Use-tab exit, shell
|
|
3915
|
+
* teardown).
|
|
3916
|
+
*/
|
|
3917
|
+
|
|
3918
|
+
interface FloatingWindowHandle {
|
|
3919
|
+
tier: FloatTier;
|
|
3920
|
+
isOpen: boolean;
|
|
3921
|
+
/** Non-docked tiers this browser supports, best first. */
|
|
3922
|
+
supportedTiers: FloatTier[];
|
|
3923
|
+
portalTarget: HTMLElement | null;
|
|
3924
|
+
canvasSink: CanvasSink | null;
|
|
3925
|
+
open: (preferredTier?: FloatTier) => Promise<void>;
|
|
3926
|
+
close: () => void;
|
|
3927
|
+
}
|
|
3928
|
+
declare function useFloatingWindow(styleCss: string): FloatingWindowHandle;
|
|
3929
|
+
|
|
3930
|
+
interface TeleprompterControlsProps {
|
|
3931
|
+
controller: TeleprompterController;
|
|
3932
|
+
float: FloatingWindowHandle;
|
|
3933
|
+
/** Phase B mounts the narration Record button here. */
|
|
3934
|
+
recordSlot?: ReactNode;
|
|
3935
|
+
}
|
|
3936
|
+
declare function TeleprompterControls({ controller, float, recordSlot }: TeleprompterControlsProps): react_jsx_runtime.JSX.Element;
|
|
3937
|
+
|
|
3938
|
+
/**
|
|
3939
|
+
* The PCM tap AudioWorklet, shipped as an inline source string.
|
|
3940
|
+
*
|
|
3941
|
+
* Why inline → Blob URL instead of a bundled asset: `audioWorklet
|
|
3942
|
+
* .addModule(url)` resolves relative to the host DOCUMENT, so a
|
|
3943
|
+
* dist-relative asset would need every consumer's bundler to rewrite
|
|
3944
|
+
* and serve it (editor-react ships zero runtime assets today). The
|
|
3945
|
+
* worklet is ~30 lines with no imports; inlining follows the
|
|
3946
|
+
* `PLAYER_BUNDLE` source-string precedent and needs zero bundler
|
|
3947
|
+
* config. The worklet does NO DSP — it batches 128-sample render
|
|
3948
|
+
* quanta into 1024-sample frames and posts them (transferably) to the
|
|
3949
|
+
* main thread, where the pure engine in `@bendyline/squisq/narration`
|
|
3950
|
+
* runs. The audio render thread never throttles, so pacing keeps
|
|
3951
|
+
* working while the browser window is fully occluded by recording
|
|
3952
|
+
* software — the whole point of the teleprompter's scenario 2.
|
|
3953
|
+
*/
|
|
3954
|
+
declare const PCM_WORKLET_NAME = "squisq-pcm-tap";
|
|
3955
|
+
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";
|
|
3956
|
+
/** Register the tap on an AudioContext via a same-origin Blob URL. */
|
|
3957
|
+
declare function registerPcmWorklet(ctx: AudioContext): Promise<void>;
|
|
3958
|
+
|
|
3959
|
+
/**
|
|
3960
|
+
* Pure scroll math for the teleprompter surface.
|
|
3961
|
+
*
|
|
3962
|
+
* The surface renders the whole script into one absolutely-positioned
|
|
3963
|
+
* column and translates it so the active word sits at the eye-line
|
|
3964
|
+
* (~35% from the top). These helpers are DOM-free except for the
|
|
3965
|
+
* measurement entry point, which only reads layout.
|
|
3966
|
+
*/
|
|
3967
|
+
interface TokenLineMap {
|
|
3968
|
+
/** Top offset (px, within the scroll column) of each token span. */
|
|
3969
|
+
tokenTops: number[];
|
|
3970
|
+
/** Height of each token's line box (px). */
|
|
3971
|
+
tokenHeights: number[];
|
|
3972
|
+
}
|
|
3973
|
+
/** Fraction of the viewport height where the active line is held. */
|
|
3974
|
+
declare const EYE_LINE_FRACTION = 0.35;
|
|
3975
|
+
/**
|
|
3976
|
+
* Measure the top offset of every `[data-token-idx]` span inside the
|
|
3977
|
+
* scroll column. Layout read only — call on mount, resize, and font-size
|
|
3978
|
+
* changes, not per frame.
|
|
3979
|
+
*/
|
|
3980
|
+
declare function measureTokenLines(scrollColumn: HTMLElement): TokenLineMap;
|
|
3981
|
+
/**
|
|
3982
|
+
* The translateY offset (px) that puts the (fractional) word position on
|
|
3983
|
+
* the eye-line. Interpolates between the current and next token tops so
|
|
3984
|
+
* the column glides instead of stepping line by line.
|
|
3985
|
+
*/
|
|
3986
|
+
declare function targetOffsetFor(wordPos: number, lines: TokenLineMap, viewportHeightPx: number, eyeLine?: number): number;
|
|
3987
|
+
/**
|
|
3988
|
+
* Advance the current scroll offset toward the target: exponential
|
|
3989
|
+
* approach (critically-damped feel) with an absolute speed clamp so a
|
|
3990
|
+
* hard resync glides rather than teleporting.
|
|
3991
|
+
*/
|
|
3992
|
+
declare function stepScroll(currentPx: number, targetPx: number, dtMs: number, maxPxPerSec?: number): number;
|
|
3993
|
+
|
|
3994
|
+
/**
|
|
3995
|
+
* Self-contained styling for the teleprompter.
|
|
3996
|
+
*
|
|
3997
|
+
* Everything the prompter surface needs ships as one CSS string plus a
|
|
3998
|
+
* set of inline `--squisq-prompter-*` custom properties derived from the
|
|
3999
|
+
* doc Theme. The docked surface, a Document-PiP window, and a popup all
|
|
4000
|
+
* inject the SAME string, so the surface never depends on the host
|
|
4001
|
+
* page's cascade (the VideoExportModal self-theming strategy).
|
|
4002
|
+
*/
|
|
4003
|
+
|
|
4004
|
+
/** Inline CSS vars for the surface root, derived from the doc theme. */
|
|
4005
|
+
declare function prompterVarsFromTheme(theme: Theme): Record<string, string>;
|
|
4006
|
+
/** Inject {@link TELEPROMPTER_CSS} into a document once (main doc or a float window). */
|
|
4007
|
+
declare function ensureTeleprompterStyles(doc: Document): void;
|
|
4008
|
+
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";
|
|
4009
|
+
|
|
2918
4010
|
interface ImageEditorProps {
|
|
2919
4011
|
/**
|
|
2920
4012
|
* Scoped sidecar container for this image — typically
|
|
@@ -3103,4 +4195,4 @@ interface UseImageEditorReturn {
|
|
|
3103
4195
|
}
|
|
3104
4196
|
declare function useImageEditor(options: UseImageEditorOptions): UseImageEditorReturn;
|
|
3105
4197
|
|
|
3106
|
-
export {
|
|
4198
|
+
export { ALL_PICKER_ENTRIES, type AddTimelineEventOptions, type AddTimelineEventResult, type ApplyAsciiDiagramCommandOptions, 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, type RecorderColorScheme, 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, translateDiagramOp, updateTimelineEventOp, useAsciiDiagramData, useBlockNavigator, useCustomTemplates, useCustomThemes, useDocCustomTemplates, useDocCustomThemes, useEditorContext, useFileDrop, useFloatingWindow, useImageEditor, useMediaRecorder, useMicAnalysis, useMonacoLoader, useNarrationRecorder, usePreviewSettings, useStreamPreview, useTeleprompter, useTimelineData, useTreeViewData, vadConfigForSensitivity };
|