@bendyline/squisq-editor-react 1.6.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/index.d.ts +1304 -208
- package/dist/index.js +22838 -14494
- package/dist/index.js.map +1 -1
- package/dist/monaco.d.ts +1 -0
- package/dist/monaco.js +4 -0
- package/dist/monaco.js.map +1 -0
- package/dist/styles/index.css +2384 -408
- package/package.json +9 -5
- package/src/BlockPropertiesPopover.tsx +48 -17
- package/src/DocumentSettingsDialog.tsx +13 -21
- package/src/EditorContext.tsx +199 -42
- package/src/EditorShell.tsx +403 -270
- package/src/ImageEditor.tsx +22 -1
- package/src/InlinePreviewGutter.tsx +16 -8
- package/src/MediaBin.tsx +276 -40
- package/src/OutlinePanel.tsx +202 -7
- package/src/PlainHtmlPreview.tsx +40 -1
- package/src/PreviewControls.tsx +466 -93
- package/src/PreviewPanel.tsx +313 -77
- package/src/RawEditor.tsx +13 -2
- package/src/StatusBar.tsx +5 -2
- package/src/TemplateAnnotation.ts +34 -10
- package/src/TemplateContentPreview.tsx +56 -0
- package/src/TemplatePicker.tsx +355 -134
- package/src/ThemeCustomizerPanel.tsx +30 -15
- package/src/ThemePicker.tsx +10 -5
- package/src/TimelineBlockPreview.tsx +1 -1
- package/src/Toolbar.tsx +719 -238
- package/src/TransitionPicker.tsx +44 -5
- package/src/ViewMenuPanel.tsx +12 -14
- package/src/ViewSwitcher.tsx +4 -4
- package/src/WysiwygEditor.tsx +167 -92
- package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +33 -0
- package/src/__tests__/blockTagActivity.test.ts +183 -0
- package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +75 -0
- package/src/__tests__/buildPreviewDocContent.test.ts +48 -0
- package/src/__tests__/buildPreviewDocTransition.test.ts +22 -3
- package/src/__tests__/canvasSurfaceTextEditing.test.tsx +60 -0
- package/src/__tests__/customLayoutManagerTheme.test.tsx +34 -0
- package/src/__tests__/documentSettingsDialog.test.tsx +29 -1
- package/src/__tests__/editorScrollHandoff.test.tsx +102 -0
- package/src/__tests__/editorScrollSync.test.ts +65 -0
- package/src/__tests__/editorShellProps.test.tsx +390 -1
- package/src/__tests__/emojiPicker.test.tsx +2 -42
- package/src/__tests__/headingTransition.test.ts +53 -15
- package/src/__tests__/imageEditAffordance.test.tsx +5 -1
- package/src/__tests__/imageEditModalContract.test.tsx +119 -0
- package/src/__tests__/imageEditorShell.test.tsx +38 -1
- package/src/__tests__/jsonEditor.test.tsx +56 -1
- package/src/__tests__/layersPanel.test.tsx +75 -5
- package/src/__tests__/majorApiTypes.test.ts +26 -0
- package/src/__tests__/mediaBinDrop.test.tsx +90 -0
- package/src/__tests__/mediaReferences.test.ts +82 -0
- package/src/__tests__/narrationSave.test.ts +148 -0
- package/src/__tests__/outlinePanel.test.tsx +93 -3
- package/src/__tests__/outlineSource.test.ts +217 -0
- package/src/__tests__/plainHtmlPreview.test.tsx +17 -1
- package/src/__tests__/presentationMode.test.tsx +290 -0
- package/src/__tests__/previewControls.test.tsx +312 -6
- package/src/__tests__/previewPanelAudioFailure.test.tsx +46 -0
- package/src/__tests__/previewPanelPresentation.test.tsx +126 -0
- package/src/__tests__/previewPanelTransforms.test.tsx +117 -0
- package/src/__tests__/rawEditorModelIsolation.test.ts +19 -0
- package/src/__tests__/resolveBlockVisual.test.ts +43 -0
- package/src/__tests__/statusBar.test.tsx +27 -0
- package/src/__tests__/teleprompter.test.tsx +190 -0
- package/src/__tests__/templateAnnotationRoundTrip.test.ts +49 -2
- package/src/__tests__/templateContentPreview.test.ts +101 -0
- package/src/__tests__/templatePickerPortal.test.tsx +62 -0
- package/src/__tests__/tiptapBridge.test.ts +70 -0
- package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +109 -0
- package/src/__tests__/transformStyleId.test.ts +13 -0
- package/src/__tests__/useImageEditor.test.tsx +67 -0
- package/src/__tests__/useMediaRecorder.test.ts +75 -0
- package/src/__tests__/viewMenuPanel.test.tsx +130 -0
- package/src/__tests__/wysiwygImageUpload.test.ts +69 -0
- package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +56 -0
- package/src/asciiDiagram/AsciiDiagramExtension.ts +343 -0
- package/src/asciiDiagram/AsciiDiagramWidget.tsx +224 -0
- package/src/asciiDiagram/RepairableDiagramExtension.ts +200 -0
- package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +145 -0
- package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +159 -0
- package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +227 -0
- package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +114 -0
- package/src/asciiDiagram/__tests__/asciiPaste.test.ts +43 -0
- package/src/asciiDiagram/asciiDiagramCommands.ts +148 -0
- package/src/asciiDiagram/asciiDiagramData.ts +116 -0
- package/src/asciiDiagram/asciiDiagramOps.ts +219 -0
- package/src/asciiDiagram/asciiPaste.ts +19 -0
- package/src/blockTagActivity.ts +233 -0
- package/src/buildDocumentPreviewMarkdown.ts +168 -0
- package/src/buildPreviewDoc.ts +19 -12
- package/src/customTemplates/CustomLayoutManager.tsx +3 -2
- package/src/customTemplates/CustomTemplateContext.tsx +6 -0
- package/src/customTemplates/TemplateDesigner.tsx +7 -4
- package/src/customTemplates/__tests__/library.test.ts +8 -0
- package/src/customTemplates/designer.css +158 -99
- package/src/customTemplates/library.ts +16 -3
- package/src/customThemes/CustomThemeContext.tsx +6 -0
- package/src/customThemes/CustomThemeDialog.tsx +35 -5
- package/src/customThemes/ImportThemeSection.tsx +178 -0
- package/src/customThemes/__tests__/customThemeLibrary.test.ts +9 -0
- package/src/customThemes/__tests__/importThemeSection.test.tsx +192 -0
- package/src/customThemes/customThemeLibrary.ts +7 -4
- package/src/customThemes/index.ts +7 -1
- package/src/customThemes/themeDraft.ts +23 -7
- package/src/diagram/DiagramCanvas.tsx +9 -4
- package/src/diagram/types.ts +35 -0
- package/src/editorScrollSync.ts +73 -0
- package/src/emojiData.ts +3 -23
- package/src/headingTransition.ts +85 -25
- package/src/imageEditor/CanvasSurface.tsx +29 -23
- package/src/imageEditor/LayersPanel.tsx +78 -3
- package/src/imageEditor/Toolbar.tsx +5 -1
- package/src/imageEditor/icons.tsx +4 -0
- package/src/imageEditor/image-editor.css +75 -0
- package/src/imageEditor/layers/SelectionHandles.tsx +1 -1
- package/src/imageEditor/useImageEditor.ts +71 -14
- package/src/index.ts +193 -20
- package/src/jsonEditor/JsonEditorContext.tsx +12 -6
- package/src/jsonEditor/RenderNode.tsx +24 -3
- package/src/jsonEditor/editors.tsx +86 -19
- package/src/mediaEntries.ts +12 -0
- package/src/mediaReferences.ts +299 -0
- package/src/monaco.ts +35 -0
- package/src/monacoWorkers.ts +89 -0
- package/src/outlineSource.ts +171 -0
- package/src/presentation/PresentationMode.tsx +596 -0
- package/src/rawEditorIsolation.ts +18 -0
- package/src/recorder/hooks/useMediaRecorder.ts +97 -53
- package/src/resolveBlockVisual.ts +10 -4
- package/src/scene/Scene.tsx +101 -25
- package/src/scene/SceneBlockExtension.ts +17 -10
- package/src/scene/SceneBlockWidget.tsx +11 -4
- package/src/scene/SceneSelection.tsx +19 -15
- package/src/scene/SceneSideToolbar.tsx +89 -0
- package/src/scene/SceneViewport.tsx +7 -3
- package/src/scene/ShapePalette.tsx +17 -2
- package/src/scene/__tests__/DiagramAdapter.test.ts +86 -0
- package/src/scene/__tests__/SceneBlockExtension.test.ts +33 -0
- package/src/scene/__tests__/sceneIsolation.test.tsx +93 -0
- package/src/scene/adapters/DiagramAdapter.ts +12 -101
- package/src/scene/commands/SceneCommand.ts +4 -1
- package/src/scene/index.ts +1 -6
- package/src/scene/layers/DiagramEdges.tsx +24 -9
- package/src/scene/layers/edgeGeometry.ts +31 -4
- package/src/scene/layers/nodeCard.tsx +27 -8
- package/src/scene/scene.css +145 -2
- package/src/scene/text/SceneTextOverlay.tsx +5 -5
- package/src/scene/text/sceneTextChannel.ts +26 -20
- package/src/scene/text/sceneTextConfig.ts +4 -0
- package/src/scene/tools/ConnectTool.ts +126 -28
- package/src/scene/tools/DrawingConnectTool.ts +86 -16
- package/src/scene/tools/SceneTool.ts +10 -0
- package/src/scene/tools/SelectTool.ts +34 -18
- package/src/scene/tools/ShapeTool.ts +2 -3
- package/src/styles/ascii-diagram.css +79 -0
- package/src/styles/ascii-timeline.css +499 -0
- package/src/styles/editor.css +1566 -219
- package/src/styles/index.css +3 -0
- package/src/styles/tree-view.css +139 -0
- package/src/teleprompter/TeleprompterControls.tsx +218 -0
- package/src/teleprompter/TeleprompterSelfView.tsx +22 -0
- package/src/teleprompter/TeleprompterSurface.tsx +267 -0
- package/src/teleprompter/TeleprompterView.tsx +338 -0
- package/src/teleprompter/canvasRenderer.ts +161 -0
- package/src/teleprompter/floatingWindow.ts +352 -0
- package/src/teleprompter/index.ts +61 -0
- package/src/teleprompter/pcmWorklet.ts +62 -0
- package/src/teleprompter/recording/insertPreamble.ts +80 -0
- package/src/teleprompter/recording/narrationSave.ts +134 -0
- package/src/teleprompter/recording/useNarrationRecorder.ts +367 -0
- package/src/teleprompter/scrollModel.ts +85 -0
- package/src/teleprompter/teleprompterTheme.ts +303 -0
- package/src/teleprompter/types.ts +38 -0
- package/src/teleprompter/useFloatingWindow.ts +74 -0
- package/src/teleprompter/useMicAnalysis.ts +211 -0
- package/src/teleprompter/useTeleprompter.ts +421 -0
- package/src/templateContentPreviewResolver.ts +360 -0
- package/src/timeline/TimelineEditorWidget.tsx +702 -0
- package/src/timeline/TimelineViewExtension.ts +252 -0
- package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +355 -0
- package/src/timeline/__tests__/TimelineViewExtension.test.ts +163 -0
- package/src/timeline/__tests__/timelineCommands.test.ts +327 -0
- package/src/timeline/__tests__/timelineOps.test.ts +222 -0
- package/src/timeline/__tests__/timelinePaste.test.ts +34 -0
- package/src/timeline/timelineCommands.ts +367 -0
- package/src/timeline/timelineData.ts +54 -0
- package/src/timeline/timelineOps.ts +277 -0
- package/src/timeline/timelinePaste.ts +8 -0
- package/src/tiptapBridge.ts +84 -49
- package/src/transformStyleId.ts +17 -0
- package/src/treeview/TreeOutlineWidget.tsx +240 -0
- package/src/treeview/TreeViewExtension.ts +250 -0
- package/src/treeview/__tests__/TreeViewExtension.test.ts +122 -0
- package/src/treeview/__tests__/treeOps.test.ts +125 -0
- package/src/treeview/__tests__/treePaste.test.ts +40 -0
- package/src/treeview/__tests__/treeViewCommands.test.ts +163 -0
- package/src/treeview/treeOps.ts +172 -0
- package/src/treeview/treePaste.ts +13 -0
- package/src/treeview/treeViewCommands.ts +94 -0
- package/src/treeview/treeViewData.ts +41 -0
- package/src/useMonacoLoader.ts +11 -34
- package/src/wysiwygImageUpload.ts +113 -0
- package/src/diagram/DiagramExtension.ts +0 -209
- package/src/diagram/DiagramWidget.tsx +0 -270
- package/src/diagram/useDiagramData.ts +0 -126
package/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,
|
|
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)
|
|
@@ -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;
|
|
@@ -1549,6 +1689,10 @@ interface PreviewSettings {
|
|
|
1549
1689
|
* that style. The single entry point so the toggle buttons persist in one
|
|
1550
1690
|
* frontmatter write. */
|
|
1551
1691
|
setCaptionMode: (mode: CaptionMode) => void;
|
|
1692
|
+
/** Whether Squisq should synthesize and show its managed cover slide. */
|
|
1693
|
+
activeCoverSlide: boolean;
|
|
1694
|
+
/** Enable/disable the managed cover slide. */
|
|
1695
|
+
setCoverSlideEnabled: (enabled: boolean) => void;
|
|
1552
1696
|
/** User-authored themes (doc + browser library) for the picker's "Custom" group. */
|
|
1553
1697
|
customThemes: Theme[];
|
|
1554
1698
|
/** Open the custom-theme designer for a theme (or null to create a new one). */
|
|
@@ -1563,7 +1707,7 @@ interface PreviewSettings {
|
|
|
1563
1707
|
interface ThemeDesignerConfig {
|
|
1564
1708
|
value: Theme | null;
|
|
1565
1709
|
onChange: (theme: Theme) => void;
|
|
1566
|
-
onSave: (theme: Theme, target: ThemeSaveTarget) => void;
|
|
1710
|
+
onSave: (theme: Theme, target: ThemeSaveTarget, extras?: ThemeSaveExtras) => void;
|
|
1567
1711
|
onClose: () => void;
|
|
1568
1712
|
}
|
|
1569
1713
|
declare function usePreviewSettings(): PreviewSettings;
|
|
@@ -1586,31 +1730,39 @@ declare function PreviewSettingsProvider({ doc, children, themeOverride, }: Prev
|
|
|
1586
1730
|
* whole row in and out at a fixed window-width breakpoint, the controls
|
|
1587
1731
|
* measure how many of them actually fit in the width the toolbar gives them
|
|
1588
1732
|
* and keep that many inline, folding the rest — from the low-priority end of
|
|
1589
|
-
* {@link CONTROL_KEYS} — into a single
|
|
1733
|
+
* {@link CONTROL_KEYS} — into a single ellipsis button's popover. As
|
|
1590
1734
|
* the toolbar widens or narrows, controls migrate one at a time between the
|
|
1591
1735
|
* inline row and the menu, so the available space is always well used and the
|
|
1592
1736
|
* row never wraps onto a second line.
|
|
1593
1737
|
*/
|
|
1594
1738
|
declare function PreviewToolbarControls(): react_jsx_runtime.JSX.Element;
|
|
1595
1739
|
/**
|
|
1596
|
-
* Segmented display-mode switch
|
|
1597
|
-
*
|
|
1598
|
-
*
|
|
1599
|
-
* `activeDisplayMode` in preview settings.
|
|
1740
|
+
* Segmented display-mode switch retained as a public, embeddable control.
|
|
1741
|
+
* The editor shell uses {@link PreviewModeMenu} beside its Use tab instead.
|
|
1742
|
+
* Narrate is hidden when the host disables `allowNarrate`.
|
|
1600
1743
|
*/
|
|
1601
1744
|
declare function PreviewModeSwitch(): react_jsx_runtime.JSX.Element;
|
|
1602
1745
|
/**
|
|
1603
|
-
*
|
|
1604
|
-
*
|
|
1605
|
-
*
|
|
1606
|
-
|
|
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;
|
|
1755
|
+
/**
|
|
1756
|
+
* Segmented aspect-ratio switch (16:9 / 1:1 / 9:16 / 4:3), used inline in the
|
|
1757
|
+
* Use toolbar and inside its overflow popover. Reads and writes the same
|
|
1758
|
+
* `activePreset` in preview settings.
|
|
1607
1759
|
*/
|
|
1608
1760
|
declare function PreviewFormatSwitch(): react_jsx_runtime.JSX.Element;
|
|
1609
1761
|
|
|
1610
1762
|
/**
|
|
1611
1763
|
* ViewSwitcher
|
|
1612
1764
|
*
|
|
1613
|
-
* Tab bar for switching between
|
|
1765
|
+
* Tab bar for switching between Write, Source, and Use editor views.
|
|
1614
1766
|
*/
|
|
1615
1767
|
interface ViewSwitcherProps {
|
|
1616
1768
|
/** Additional class name */
|
|
@@ -1626,13 +1778,15 @@ interface ToolbarProps {
|
|
|
1626
1778
|
className?: string;
|
|
1627
1779
|
/** Whether the Files panel is currently shown */
|
|
1628
1780
|
showFiles?: boolean;
|
|
1781
|
+
/** Number of files currently available through the MediaProvider. */
|
|
1782
|
+
fileCount?: number;
|
|
1629
1783
|
/** Toggle the Files panel. When provided, a "Files" button appears in the toolbar. */
|
|
1630
1784
|
onToggleFiles?: () => void;
|
|
1631
1785
|
/** Content rendered at the left edge of the toolbar, before the view tabs. */
|
|
1632
1786
|
slotLeft?: ReactNode;
|
|
1633
1787
|
/** Content rendered immediately after the view tabs, on the left side of the
|
|
1634
1788
|
* toolbar (before the formatting controls). Used for the preview mode
|
|
1635
|
-
* switch in
|
|
1789
|
+
* switch in Use view. */
|
|
1636
1790
|
slotAfterTabs?: ReactNode;
|
|
1637
1791
|
/** Content rendered after the formatting controls (in the middle area). */
|
|
1638
1792
|
slotAfterActions?: ReactNode;
|
|
@@ -1650,7 +1804,7 @@ interface ToolbarProps {
|
|
|
1650
1804
|
* - WYSIWYG: calls Tiptap chain commands (toggleBold, etc.)
|
|
1651
1805
|
* - Raw: appends markdown syntax to the source
|
|
1652
1806
|
*/
|
|
1653
|
-
declare function Toolbar({ className, showFiles, onToggleFiles, slotLeft, slotAfterTabs, slotAfterActions, slotRight, showPlayTab, }: ToolbarProps): react_jsx_runtime.JSX.Element;
|
|
1807
|
+
declare function Toolbar({ className, showFiles, fileCount, onToggleFiles, slotLeft, slotAfterTabs, slotAfterActions, slotRight, showPlayTab, }: ToolbarProps): react_jsx_runtime.JSX.Element;
|
|
1654
1808
|
|
|
1655
1809
|
/**
|
|
1656
1810
|
* VersionHistoryPanel
|
|
@@ -1688,8 +1842,10 @@ interface OutlinePanelProps {
|
|
|
1688
1842
|
width?: number;
|
|
1689
1843
|
/** Optional CSS class for the outer container. */
|
|
1690
1844
|
className?: string;
|
|
1845
|
+
/** Disable heading-level changes and section reordering. */
|
|
1846
|
+
readOnly?: boolean;
|
|
1691
1847
|
}
|
|
1692
|
-
declare function OutlinePanel({ width, className }: OutlinePanelProps): react_jsx_runtime.JSX.Element;
|
|
1848
|
+
declare function OutlinePanel({ width, className, readOnly }: OutlinePanelProps): react_jsx_runtime.JSX.Element;
|
|
1693
1849
|
|
|
1694
1850
|
interface ThemeCustomizerPanelProps {
|
|
1695
1851
|
/** Current custom theme (or null to start from defaults). */
|
|
@@ -1700,8 +1856,19 @@ interface ThemeCustomizerPanelProps {
|
|
|
1700
1856
|
onSave?: (theme: Theme, json: string) => void;
|
|
1701
1857
|
/** Fired when the user clicks Reset. Host typically clears its persistent storage. */
|
|
1702
1858
|
onReset?: () => void;
|
|
1859
|
+
/** Optional text trigger. Omit to use the compact icon trigger. */
|
|
1860
|
+
triggerLabel?: string;
|
|
1861
|
+
}
|
|
1862
|
+
declare function ThemeCustomizerPanel({ value, onChange, onSave, onReset, triggerLabel, }: ThemeCustomizerPanelProps): react_jsx_runtime.JSX.Element;
|
|
1863
|
+
|
|
1864
|
+
interface TemplatePreviewSource {
|
|
1865
|
+
block: Block;
|
|
1866
|
+
theme: Theme;
|
|
1867
|
+
viewport: ViewportConfig;
|
|
1868
|
+
basePath?: string;
|
|
1869
|
+
mediaProvider?: MediaProvider | null;
|
|
1870
|
+
customTemplates?: readonly CustomTemplateDefinition[];
|
|
1703
1871
|
}
|
|
1704
|
-
declare function ThemeCustomizerPanel({ value, onChange, onSave, onReset, }: ThemeCustomizerPanelProps): react_jsx_runtime.JSX.Element;
|
|
1705
1872
|
|
|
1706
1873
|
/**
|
|
1707
1874
|
* Convert a camelCase template id to a human-readable label. Accepts both
|
|
@@ -1714,6 +1881,8 @@ declare function templateLabel(name: string, customTemplates?: readonly CustomTe
|
|
|
1714
1881
|
interface TemplatePickerProps {
|
|
1715
1882
|
value: string;
|
|
1716
1883
|
onChange: (name: string) => void;
|
|
1884
|
+
/** Active editor chrome theme, used by the portaled dialog. */
|
|
1885
|
+
colorScheme?: 'light' | 'dark';
|
|
1717
1886
|
/** When true, shows only the trigger button (no popover) — used in the overflow menu. */
|
|
1718
1887
|
compact?: boolean;
|
|
1719
1888
|
/**
|
|
@@ -1729,8 +1898,14 @@ interface TemplatePickerProps {
|
|
|
1729
1898
|
* hidden.
|
|
1730
1899
|
*/
|
|
1731
1900
|
onOpenDesigner?: () => void;
|
|
1901
|
+
/**
|
|
1902
|
+
* Active block content used to render live template thumbnails. When omitted,
|
|
1903
|
+
* or when a template cannot be meaningfully derived from the block, cards use
|
|
1904
|
+
* their static wireframe icons.
|
|
1905
|
+
*/
|
|
1906
|
+
previewSource?: TemplatePreviewSource;
|
|
1732
1907
|
}
|
|
1733
|
-
declare function TemplatePicker({ value, onChange, compact, recommended, onOpenDesigner, }: TemplatePickerProps): react_jsx_runtime.JSX.Element;
|
|
1908
|
+
declare function TemplatePicker({ value, onChange, colorScheme, compact, recommended, onOpenDesigner, previewSource, }: TemplatePickerProps): react_jsx_runtime.JSX.Element;
|
|
1734
1909
|
|
|
1735
1910
|
/**
|
|
1736
1911
|
* headingTransition
|
|
@@ -1740,16 +1915,13 @@ declare function TemplatePicker({ value, onChange, compact, recommended, onOpenD
|
|
|
1740
1915
|
*
|
|
1741
1916
|
* - Markdown (Monaco): operate on the raw heading line string.
|
|
1742
1917
|
* - WYSIWYG (Tiptap): operate on the heading node's `dataBlockAttrs` string
|
|
1743
|
-
* (
|
|
1744
|
-
* `
|
|
1918
|
+
* (Pandoc `{…}` inner) and `dataTemplateParams` string (the params inside
|
|
1919
|
+
* the squisq-native `{[…]}` annotation).
|
|
1745
1920
|
*
|
|
1746
|
-
*
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1749
|
-
*
|
|
1750
|
-
* value set here round-trips through a Doc render without being duplicated
|
|
1751
|
-
* or moved. Reads still look at the `{[…]}` params too, so a hand-typed
|
|
1752
|
-
* `{[title transition=fade]}` shows up in the picker.
|
|
1921
|
+
* The editor writes transitions to the squisq-native `{[…]}` annotation by
|
|
1922
|
+
* default. It still reads legacy Pandoc `{transition=…}` attributes and
|
|
1923
|
+
* removes/migrates those keys when rewriting, so the two channels cannot drift
|
|
1924
|
+
* after a toolbar edit.
|
|
1753
1925
|
*
|
|
1754
1926
|
* All the brace-matching / tokenizing / serializing is delegated to the
|
|
1755
1927
|
* shared core helpers so this stays in lockstep with the parser by import
|
|
@@ -1767,35 +1939,47 @@ interface TransitionFields {
|
|
|
1767
1939
|
declare const EMPTY_TRANSITION: TransitionFields;
|
|
1768
1940
|
/**
|
|
1769
1941
|
* Read the transition fields off a heading line. Looks in both the Pandoc
|
|
1770
|
-
* `{…}` block (
|
|
1942
|
+
* `{…}` block (legacy) and the `{[…]}` template params (canonical),
|
|
1771
1943
|
* with the Pandoc block taking precedence. Returns the empty transition for
|
|
1772
1944
|
* non-heading lines.
|
|
1773
1945
|
*/
|
|
1774
1946
|
declare function readHeadingLineTransition(line: string): TransitionFields;
|
|
1775
1947
|
/**
|
|
1776
1948
|
* Return `line` with its transition rewritten from `next`, writing into the
|
|
1777
|
-
*
|
|
1778
|
-
* Non-heading lines are
|
|
1949
|
+
* squisq-native `{[…]}` annotation. Legacy Pandoc transition keys are removed
|
|
1950
|
+
* while preserving ids, classes, and other Pandoc params. Non-heading lines are
|
|
1951
|
+
* returned unchanged.
|
|
1779
1952
|
*/
|
|
1780
1953
|
declare function setHeadingLineTransition(line: string, next: TransitionFields): string;
|
|
1781
1954
|
/**
|
|
1782
|
-
* Read the transition fields from a heading node's `dataBlockAttrs` (
|
|
1783
|
-
* inner) plus `dataTemplateParams` (
|
|
1955
|
+
* Read the transition fields from a heading node's `dataBlockAttrs` (legacy
|
|
1956
|
+
* Pandoc inner) plus `dataTemplateParams` (canonical `{[…]}` params). Pandoc
|
|
1957
|
+
* wins so the picker mirrors the value that `markdownToDoc` will render when
|
|
1958
|
+
* both channels are present.
|
|
1784
1959
|
*/
|
|
1785
1960
|
declare function readBlockAttrsTransition(blockAttrsInner: string | null | undefined, templateParams: string | null | undefined): TransitionFields;
|
|
1961
|
+
interface HeadingTransitionAttrs {
|
|
1962
|
+
/** Inner of the Pandoc `{…}` block, without braces. */
|
|
1963
|
+
blockAttrsInner: string | null;
|
|
1964
|
+
/** Param string inside the `{[…]}` annotation, without the template token. */
|
|
1965
|
+
templateParams: string | null;
|
|
1966
|
+
}
|
|
1786
1967
|
/**
|
|
1787
|
-
* Rewrite
|
|
1788
|
-
*
|
|
1789
|
-
*
|
|
1790
|
-
* (absent attribute → null, not `{}`).
|
|
1968
|
+
* Rewrite a heading node's transition for Tiptap, writing the transition
|
|
1969
|
+
* family into `dataTemplateParams` and removing any legacy transition keys
|
|
1970
|
+
* from `dataBlockAttrs`.
|
|
1791
1971
|
*/
|
|
1792
|
-
declare function
|
|
1972
|
+
declare function setHeadingAttrsTransition(blockAttrsInner: string | null | undefined, templateParams: string | null | undefined, next: TransitionFields): HeadingTransitionAttrs;
|
|
1793
1973
|
|
|
1794
1974
|
interface TransitionPickerProps {
|
|
1795
1975
|
value: TransitionFields;
|
|
1796
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;
|
|
1797
1981
|
}
|
|
1798
|
-
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;
|
|
1799
1983
|
|
|
1800
1984
|
/**
|
|
1801
1985
|
* transitionCatalog
|
|
@@ -1883,12 +2067,11 @@ declare function summarizeBlockProps(blockAttrs: string | null | undefined, temp
|
|
|
1883
2067
|
*
|
|
1884
2068
|
* The on-canvas "block properties" palette — the sibling of the block-template
|
|
1885
2069
|
* badge. Anchored at the `.squisq-props-badge` chip on a heading, it edits the
|
|
1886
|
-
* block's playback/animation metadata
|
|
1887
|
-
* attribute block (`dataBlockAttrs`):
|
|
2070
|
+
* block's playback/animation metadata:
|
|
1888
2071
|
*
|
|
1889
|
-
* - Transition (type / direction / duration) —
|
|
1890
|
-
* - Duration (`duration`) —
|
|
1891
|
-
* - Start time (`startTime`) —
|
|
2072
|
+
* - Transition (type / direction / duration) — stored in `{[…]}` params
|
|
2073
|
+
* - Duration (`duration`) — stored in Pandoc `dataBlockAttrs`
|
|
2074
|
+
* - Start time (`startTime`) — stored in Pandoc `dataBlockAttrs`
|
|
1892
2075
|
*
|
|
1893
2076
|
* The popover holds the `dataBlockAttrs` inner string as working state and
|
|
1894
2077
|
* re-derives each control from it, so successive edits compose. Every change
|
|
@@ -1905,9 +2088,18 @@ interface BlockPropertiesPopoverProps {
|
|
|
1905
2088
|
templateParams: string | null;
|
|
1906
2089
|
/** Apply a new `dataBlockAttrs` inner to the heading (null clears it). */
|
|
1907
2090
|
onChange: (nextInner: string | null) => void;
|
|
2091
|
+
/** Apply a paired `dataBlockAttrs` / `dataTemplateParams` transition rewrite. */
|
|
2092
|
+
onAnnotationChange: (next: {
|
|
2093
|
+
blockAttrsInner: string | null;
|
|
2094
|
+
templateParams: string | null;
|
|
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;
|
|
1908
2100
|
onClose: () => void;
|
|
1909
2101
|
}
|
|
1910
|
-
declare function BlockPropertiesPopover({ anchorRect, blockAttrs, templateParams, onChange, onClose, }: BlockPropertiesPopoverProps): react.ReactPortal;
|
|
2102
|
+
declare function BlockPropertiesPopover({ anchorRect, blockAttrs, templateParams, onChange, onAnnotationChange, colorScheme, accentColor, onClose, }: BlockPropertiesPopoverProps): react.ReactPortal;
|
|
1911
2103
|
|
|
1912
2104
|
interface InlinePreviewGutterProps {
|
|
1913
2105
|
/** Width of the gutter in pixels (default: 320). */
|
|
@@ -1939,9 +2131,11 @@ interface MediaBinProps {
|
|
|
1939
2131
|
isDark: boolean;
|
|
1940
2132
|
/** Incremented externally to signal a re-scan of the media list */
|
|
1941
2133
|
refreshKey?: number;
|
|
2134
|
+
/** Relative media paths currently referenced by the document. */
|
|
2135
|
+
usedMediaPaths?: ReadonlySet<string>;
|
|
1942
2136
|
/**
|
|
1943
|
-
* Fired after a successful upload via the MediaBin's
|
|
1944
|
-
* 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
|
|
1945
2139
|
* value embedded in markdown refs, e.g. `attachments/xyz.png`);
|
|
1946
2140
|
* `name` is the uploader-chosen filename before storage renamed
|
|
1947
2141
|
* it. Consumers typically use this to insert a markdown image ref
|
|
@@ -1950,8 +2144,15 @@ interface MediaBinProps {
|
|
|
1950
2144
|
* else, leaving the message body empty when the user hit Send.
|
|
1951
2145
|
*/
|
|
1952
2146
|
onMediaUploaded?: (relativePath: string, name: string, mimeType: string) => void | Promise<void>;
|
|
2147
|
+
/**
|
|
2148
|
+
* Fired after a file is removed through the MediaBin context menu.
|
|
2149
|
+
* Hosts use this to remove matching markdown refs from the document.
|
|
2150
|
+
*/
|
|
2151
|
+
onMediaRemoved?: (relativePath: string, entry: MediaEntry) => void | Promise<void>;
|
|
2152
|
+
/** Fired whenever the panel scans media and knows the current entry count. */
|
|
2153
|
+
onCountChange?: (count: number) => void;
|
|
1953
2154
|
}
|
|
1954
|
-
declare function MediaBin({ mediaProvider, isDark, refreshKey, onMediaUploaded }: MediaBinProps): react_jsx_runtime.JSX.Element;
|
|
2155
|
+
declare function MediaBin({ mediaProvider, isDark, refreshKey, usedMediaPaths, onMediaUploaded, onMediaRemoved, onCountChange, }: MediaBinProps): react_jsx_runtime.JSX.Element;
|
|
1955
2156
|
|
|
1956
2157
|
/**
|
|
1957
2158
|
* StatusBar
|
|
@@ -2118,6 +2319,63 @@ interface UseMonacoLoaderResult {
|
|
|
2118
2319
|
*/
|
|
2119
2320
|
declare function useMonacoLoader(): UseMonacoLoaderResult;
|
|
2120
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
|
+
|
|
2121
2379
|
interface CustomTemplateContextValue {
|
|
2122
2380
|
/** Templates inlined into the current doc's frontmatter. */
|
|
2123
2381
|
docTemplates: CustomTemplateDefinition[];
|
|
@@ -2193,20 +2451,9 @@ interface DocCustomTemplates {
|
|
|
2193
2451
|
}
|
|
2194
2452
|
declare function useDocCustomTemplates(): DocCustomTemplates;
|
|
2195
2453
|
|
|
2196
|
-
/**
|
|
2197
|
-
* Read diagram nodes + edges from the live Tiptap state.
|
|
2198
|
-
*
|
|
2199
|
-
* For a given parent heading position, walks the diagram section's child
|
|
2200
|
-
* headings, builds synthetic `Block` objects from their text + Pandoc
|
|
2201
|
-
* attributes, runs `computeDiagramLayout` from core to fill in missing
|
|
2202
|
-
* positions, and returns the result in the shape React Flow consumes.
|
|
2203
|
-
*
|
|
2204
|
-
* The hook re-derives on every editor transaction — no caching layer
|
|
2205
|
-
* means there's nothing to invalidate when the user types or the markdown
|
|
2206
|
-
* is reloaded from disk.
|
|
2207
|
-
*/
|
|
2454
|
+
/** Data shapes consumed by `DiagramCanvas` / `buildDiagramScene`. */
|
|
2208
2455
|
|
|
2209
|
-
interface
|
|
2456
|
+
interface DiagramNode {
|
|
2210
2457
|
id: string;
|
|
2211
2458
|
position: {
|
|
2212
2459
|
x: number;
|
|
@@ -2216,23 +2463,29 @@ interface DiagramRFNode {
|
|
|
2216
2463
|
label: string;
|
|
2217
2464
|
};
|
|
2218
2465
|
type?: string;
|
|
2219
|
-
/** Per-node width override
|
|
2466
|
+
/** Per-node width override in canvas units. */
|
|
2220
2467
|
width?: number;
|
|
2221
|
-
/** Per-node height override
|
|
2468
|
+
/** Per-node height override in canvas units. */
|
|
2222
2469
|
height?: number;
|
|
2470
|
+
/** Render as a background container card (top-anchored label, muted fill). */
|
|
2471
|
+
kind?: 'container';
|
|
2223
2472
|
}
|
|
2224
|
-
interface
|
|
2473
|
+
interface DiagramEdge {
|
|
2225
2474
|
id: string;
|
|
2226
2475
|
source: string;
|
|
2227
2476
|
target: string;
|
|
2228
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;
|
|
2229
2483
|
}
|
|
2230
2484
|
interface DiagramData {
|
|
2231
|
-
nodes:
|
|
2232
|
-
edges:
|
|
2485
|
+
nodes: DiagramNode[];
|
|
2486
|
+
edges: DiagramEdge[];
|
|
2233
2487
|
warnings: string[];
|
|
2234
2488
|
}
|
|
2235
|
-
declare function useDiagramData(editor: Editor$1, parentPos: number): DiagramData;
|
|
2236
2489
|
|
|
2237
2490
|
/**
|
|
2238
2491
|
* Tiptap Bridge
|
|
@@ -2283,9 +2536,10 @@ declare function buildPreviewDoc(doc: Doc): Doc;
|
|
|
2283
2536
|
/**
|
|
2284
2537
|
* TemplateAnnotation — Tiptap Heading Extension
|
|
2285
2538
|
*
|
|
2286
|
-
* Extends Tiptap's built-in Heading node to support `data-template
|
|
2287
|
-
* `data-template-params` HTML attributes. These
|
|
2288
|
-
*
|
|
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.
|
|
2289
2543
|
*
|
|
2290
2544
|
* When present, the heading renders a visible badge (styled CSS chip)
|
|
2291
2545
|
* showing the template name, e.g. `[chart]`.
|
|
@@ -2300,27 +2554,6 @@ declare function buildPreviewDoc(doc: Doc): Doc;
|
|
|
2300
2554
|
*/
|
|
2301
2555
|
declare const HeadingWithTemplate: _tiptap_core.Node<_tiptap_extension_heading.HeadingOptions, any>;
|
|
2302
2556
|
|
|
2303
|
-
/**
|
|
2304
|
-
* DiagramExtension — Tiptap/ProseMirror plugin that:
|
|
2305
|
-
*
|
|
2306
|
-
* 1. Mounts a React-Flow canvas (`DiagramWidget`) immediately after every
|
|
2307
|
-
* heading whose `dataTemplate === 'diagram'`.
|
|
2308
|
-
* 2. Hides the direct sub-headings of each diagram parent (until the next
|
|
2309
|
-
* equal-or-shallower heading) by tagging them with a `data-squisq-diagram-child`
|
|
2310
|
-
* attribute — CSS in `styles/diagram.css` does the actual hiding.
|
|
2311
|
-
*
|
|
2312
|
-
* Widgets are rendered as plain DOM nodes attached to a ProseMirror
|
|
2313
|
-
* `Decoration.widget`. React is mounted into the widget DOM with
|
|
2314
|
-
* `react-dom/client`'s `createRoot`, and unmounted on the widget's
|
|
2315
|
-
* `destroy` hook.
|
|
2316
|
-
*/
|
|
2317
|
-
|
|
2318
|
-
interface DiagramExtensionOptions {
|
|
2319
|
-
/** When false, the extension is inert (no widgets, no decorations). */
|
|
2320
|
-
enabled?: boolean;
|
|
2321
|
-
}
|
|
2322
|
-
declare const DiagramExtension: Extension<DiagramExtensionOptions, any>;
|
|
2323
|
-
|
|
2324
2557
|
type DiagramCommand = {
|
|
2325
2558
|
kind: 'moveNode';
|
|
2326
2559
|
nodeId: string;
|
|
@@ -2354,8 +2587,8 @@ type DiagramCommand = {
|
|
|
2354
2587
|
nodeId: string;
|
|
2355
2588
|
};
|
|
2356
2589
|
interface DiagramCanvasProps {
|
|
2357
|
-
nodes:
|
|
2358
|
-
edges:
|
|
2590
|
+
nodes: DiagramNode[];
|
|
2591
|
+
edges: DiagramEdge[];
|
|
2359
2592
|
onCommand: (cmd: DiagramCommand) => void;
|
|
2360
2593
|
/** When true, render the maximize button. Click toggles `onToggleMaximize`. */
|
|
2361
2594
|
showMaximize?: boolean;
|
|
@@ -2372,99 +2605,525 @@ interface DiagramCanvasProps {
|
|
|
2372
2605
|
onActiveToolIdChange?: (id: string) => void;
|
|
2373
2606
|
/** Forwarded to the Scene so the host can drive a Delete action. */
|
|
2374
2607
|
onSelectionChange?: (ids: ReadonlySet<string>) => void;
|
|
2608
|
+
/** Per-editor toolbar bridge for detached scene roots. */
|
|
2609
|
+
textChannel?: SceneTextChannel;
|
|
2610
|
+
}
|
|
2611
|
+
declare function DiagramCanvas({ nodes: incomingNodes, edges: incomingEdges, onCommand, showMaximize, maximized, onToggleMaximize, activeToolId: controlledToolId, onActiveToolIdChange, onSelectionChange, textChannel, }: DiagramCanvasProps): react_jsx_runtime.JSX.Element;
|
|
2612
|
+
|
|
2613
|
+
/**
|
|
2614
|
+
* AsciiDiagramExtension — Tiptap/ProseMirror plugin that turns code blocks
|
|
2615
|
+
* containing ASCII box-and-line diagrams into interactive diagram canvases.
|
|
2616
|
+
*
|
|
2617
|
+
* The FENCE TEXT REMAINS THE SOURCE OF TRUTH: the plugin never converts
|
|
2618
|
+
* the document. For each qualifying codeBlock it:
|
|
2619
|
+
* 1. hides the `<pre>` via a node decoration (or tags it visible-monospace
|
|
2620
|
+
* when the user toggles "source" mode), and
|
|
2621
|
+
* 2. mounts an `AsciiDiagramWidget` after it via a widget decoration.
|
|
2622
|
+
*
|
|
2623
|
+
* Identity: codeBlocks have no persisted id and their content changes on
|
|
2624
|
+
* every canvas edit (self-inflicted fence rewrite), so neither a content
|
|
2625
|
+
* hash nor a raw position can key the widget. Instead the plugin keeps a
|
|
2626
|
+
* POSITION REGISTRY in its state: each qualifying block gets a synthetic
|
|
2627
|
+
* session id (`ascii-N`); on every doc change old positions are remapped
|
|
2628
|
+
* through `tr.mapping` and matched against the new doc walk. Same id →
|
|
2629
|
+
* same widget decoration key → ProseMirror keeps the DOM + React root
|
|
2630
|
+
* alive (pan/zoom survives), exactly like the heading-key trick the
|
|
2631
|
+
* legacy DiagramExtension used.
|
|
2632
|
+
*
|
|
2633
|
+
* Hysteresis: a NEW block must pass full detection (`detectAsciiDiagram`,
|
|
2634
|
+
* ≥2 boxes + thresholds); an already-registered block stays interactive
|
|
2635
|
+
* while its fence still parses to ≥1 box, so deleting down to one node
|
|
2636
|
+
* doesn't kick the user back to a raw code block mid-edit.
|
|
2637
|
+
*/
|
|
2638
|
+
|
|
2639
|
+
interface AsciiDiagramBlockEntry {
|
|
2640
|
+
/** Synthetic session id (`ascii-N`), stable across edits for one block. */
|
|
2641
|
+
id: string;
|
|
2642
|
+
/** Document position of the codeBlock node at the current state. */
|
|
2643
|
+
pos: number;
|
|
2644
|
+
}
|
|
2645
|
+
interface AsciiDiagramPluginState {
|
|
2646
|
+
entries: AsciiDiagramBlockEntry[];
|
|
2647
|
+
decorations: DecorationSet;
|
|
2648
|
+
sourceVisible: ReadonlySet<string>;
|
|
2649
|
+
/** Monotonic id allocator. */
|
|
2650
|
+
seq: number;
|
|
2651
|
+
}
|
|
2652
|
+
/** Resolve a registered block's current doc position (null when gone). */
|
|
2653
|
+
declare function findAsciiDiagramBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
2654
|
+
declare function isAsciiSourceVisible(editor: Editor$1, blockId: string): boolean;
|
|
2655
|
+
/** Toggle the raw-fence view for one diagram block (meta-only transaction). */
|
|
2656
|
+
declare function toggleAsciiSource(editor: Editor$1, blockId: string): void;
|
|
2657
|
+
interface AsciiDiagramExtensionOptions {
|
|
2658
|
+
/** When false, the extension is inert (no widgets, no decorations). */
|
|
2659
|
+
enabled?: boolean;
|
|
2660
|
+
textChannel?: SceneTextChannel;
|
|
2375
2661
|
}
|
|
2376
|
-
declare
|
|
2662
|
+
declare const AsciiDiagramExtension: Extension<AsciiDiagramExtensionOptions, any>;
|
|
2377
2663
|
|
|
2378
|
-
interface
|
|
2664
|
+
interface AsciiDiagramWidgetProps {
|
|
2379
2665
|
editor: Editor$1;
|
|
2380
|
-
/**
|
|
2381
|
-
|
|
2382
|
-
/** Position
|
|
2383
|
-
|
|
2384
|
-
* transaction). */
|
|
2385
|
-
fallbackParentPos: number;
|
|
2666
|
+
/** Session id from the extension's position registry. */
|
|
2667
|
+
blockId: string;
|
|
2668
|
+
/** Position at widget-creation time — display-only fallback. */
|
|
2669
|
+
fallbackPos: number;
|
|
2386
2670
|
/** Host element used for portal targeting by the maximize overlay. */
|
|
2387
2671
|
host?: HTMLElement | null;
|
|
2672
|
+
textChannel?: SceneTextChannel;
|
|
2388
2673
|
}
|
|
2389
|
-
declare function
|
|
2674
|
+
declare function AsciiDiagramWidget({ editor, blockId, host, textChannel, }: AsciiDiagramWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
2675
|
+
|
|
2676
|
+
/**
|
|
2677
|
+
* Read direction of the ASCII diagram loop: fence text → canvas data.
|
|
2678
|
+
*
|
|
2679
|
+
* `useAsciiDiagramData` re-derives on every editor transaction (mirroring
|
|
2680
|
+
* the philosophy of the old heading-based `useDiagramData`: no store, so
|
|
2681
|
+
* nothing to invalidate). Parsing is memoized per PMNode instance by the
|
|
2682
|
+
* extension's WeakMap caches, so untouched fences cost nothing.
|
|
2683
|
+
*/
|
|
2684
|
+
|
|
2685
|
+
interface AsciiDiagramView {
|
|
2686
|
+
/** Canvas nodes, containers ordered first so their cards paint behind. */
|
|
2687
|
+
nodes: DiagramNode[];
|
|
2688
|
+
edges: DiagramEdge[];
|
|
2689
|
+
warnings: string[];
|
|
2690
|
+
style: 'unicode' | 'ascii';
|
|
2691
|
+
/** The current fence text. */
|
|
2692
|
+
text: string;
|
|
2693
|
+
/** The parse behind `nodes`/`edges` (grid units) — ops operate on this. */
|
|
2694
|
+
diagram: AsciiDiagram;
|
|
2695
|
+
}
|
|
2696
|
+
/** Grid model → canvas model, containers-first for paint order. */
|
|
2697
|
+
declare function asciiDiagramToCanvas(diagram: AsciiDiagram): Pick<AsciiDiagramView, 'nodes' | 'edges'>;
|
|
2698
|
+
/**
|
|
2699
|
+
* Live view of one registered ASCII diagram block. Returns null when the
|
|
2700
|
+
* block no longer exists or no longer parses (the extension will drop the
|
|
2701
|
+
* widget on its next pass).
|
|
2702
|
+
*/
|
|
2703
|
+
declare function useAsciiDiagramData(editor: Editor$1, blockId: string): AsciiDiagramView | null;
|
|
2390
2704
|
|
|
2391
2705
|
/**
|
|
2392
|
-
*
|
|
2706
|
+
* Write direction of the ASCII diagram loop: canvas command → fence rewrite.
|
|
2393
2707
|
*
|
|
2394
|
-
*
|
|
2395
|
-
*
|
|
2396
|
-
*
|
|
2397
|
-
*
|
|
2398
|
-
*
|
|
2708
|
+
* Every semantic edit is one functional transformation of the fence text
|
|
2709
|
+
* (`renderAscii(applyOp(parseAscii(text)))`) committed as a single
|
|
2710
|
+
* ProseMirror transaction (= a single undo step). Before committing, the
|
|
2711
|
+
* rendered art is re-parsed and verified — if the renderer ever produced
|
|
2712
|
+
* something the parser disagrees with, the command aborts instead of
|
|
2713
|
+
* corrupting the fence.
|
|
2399
2714
|
*/
|
|
2400
2715
|
|
|
2401
|
-
|
|
2402
|
-
|
|
2716
|
+
/**
|
|
2717
|
+
* Replace the TEXT inside the codeBlock at `pos` and, when `ensureLanguage`
|
|
2718
|
+
* is given, promote its `language` attribute in the SAME transaction (one
|
|
2719
|
+
* undo step). Promoting the language to the explicit `diagram`/`tree` tag is
|
|
2720
|
+
* how a semantic edit makes the block's identity "sticky" — the language
|
|
2721
|
+
* class survives markdown ↔ Tiptap round-trips, so a once-edited diagram/tree
|
|
2722
|
+
* is re-recognized even after it's flattened. No-op (returns false) only when
|
|
2723
|
+
* BOTH the text is already identical AND the language already matches, so
|
|
2724
|
+
* history stays clean on a true no-op.
|
|
2725
|
+
*/
|
|
2726
|
+
declare function replaceAsciiFenceText(editor: Editor$1, pos: number, nextText: string, ensureLanguage?: string): boolean;
|
|
2727
|
+
/**
|
|
2728
|
+
* Reconstruct a broken box-art fence into clean, `diagram`-tagged art in a
|
|
2729
|
+
* single transaction (one undo step). The AsciiDiagramExtension then claims
|
|
2730
|
+
* the tagged fence and mounts the interactive canvas. Returns false when the
|
|
2731
|
+
* block is gone or nothing recoverable (the button simply no-ops).
|
|
2732
|
+
*/
|
|
2733
|
+
declare function applyRepairCommand(editor: Editor$1, blockId: string): boolean;
|
|
2734
|
+
/** Full pipeline for a canvas command against a registered fence block. */
|
|
2735
|
+
declare function applyAsciiDiagramCommand(editor: Editor$1, blockId: string, cmd: DiagramCommand): boolean;
|
|
2736
|
+
|
|
2737
|
+
/**
|
|
2738
|
+
* RepairableDiagramExtension — mounts an inline "Repair as diagram" button on
|
|
2739
|
+
* code fences that hold BROKEN box-and-line art.
|
|
2740
|
+
*
|
|
2741
|
+
* The three states of a box-drawing fence partition cleanly:
|
|
2742
|
+
* - a clean diagram → AsciiDiagramExtension mounts the canvas;
|
|
2743
|
+
* - a file tree / outline → TreeViewExtension mounts the outline;
|
|
2744
|
+
* - broken box art → neither claims it (it renders as a faithful
|
|
2745
|
+
* code block), and THIS extension offers a button
|
|
2746
|
+
* to reconstruct it via `repairAsciiDiagram`.
|
|
2747
|
+
*
|
|
2748
|
+
* Unlike the diagram/tree extensions it does NOT hide the fence or mount a
|
|
2749
|
+
* persistent interactive widget — the code stays visible and editable, and a
|
|
2750
|
+
* single click rewrites the fence to clean `diagram`-tagged art (which the
|
|
2751
|
+
* AsciiDiagramExtension then turns into a canvas). So the position registry
|
|
2752
|
+
* only needs to survive until the click; it mirrors the other extensions'
|
|
2753
|
+
* mapping so the button always resolves the right fence.
|
|
2754
|
+
*/
|
|
2755
|
+
|
|
2756
|
+
interface RepairableBlockEntry {
|
|
2757
|
+
/** Synthetic session id (`repair-N`), stable across edits for one block. */
|
|
2758
|
+
id: string;
|
|
2759
|
+
/** Document position of the codeBlock node at the current state. */
|
|
2403
2760
|
pos: number;
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2761
|
+
}
|
|
2762
|
+
interface RepairablePluginState {
|
|
2763
|
+
entries: RepairableBlockEntry[];
|
|
2764
|
+
decorations: DecorationSet;
|
|
2765
|
+
seq: number;
|
|
2766
|
+
}
|
|
2767
|
+
declare const REPAIRABLE_KEY: PluginKey<RepairablePluginState>;
|
|
2768
|
+
/** True when a codeBlock holds broken box art worth offering to repair. */
|
|
2769
|
+
declare function isRepairableFence(node: Node): boolean;
|
|
2770
|
+
/** Resolve a registered block's current doc position (null when gone). */
|
|
2771
|
+
declare function findRepairableBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
2772
|
+
/** Handler the mounted button invokes; wired by the host via extension options. */
|
|
2773
|
+
interface RepairableDiagramExtensionOptions {
|
|
2774
|
+
enabled?: boolean;
|
|
2775
|
+
/** Invoked when a repair button is clicked, with the block's synthetic id. */
|
|
2776
|
+
onRepair?: (editor: Editor$1, blockId: string) => void;
|
|
2777
|
+
}
|
|
2778
|
+
declare const RepairableDiagramExtension: Extension<RepairableDiagramExtensionOptions, any>;
|
|
2779
|
+
|
|
2780
|
+
/**
|
|
2781
|
+
* Pure data operations over the ASCII diagram model — the write-direction
|
|
2782
|
+
* half of the fence-is-source-of-truth loop:
|
|
2783
|
+
*
|
|
2784
|
+
* fence text → parseAsciiDiagram → op → renderAsciiDiagram → fence text
|
|
2785
|
+
*
|
|
2786
|
+
* Every op returns a new AsciiDiagram (inputs are never mutated) and
|
|
2787
|
+
* maintains the invariants the renderer/parser fixpoint relies on:
|
|
2788
|
+
* container moves translate whole subtrees, removals promote children and
|
|
2789
|
+
* drop incident edges, sizes never fall below what a label needs.
|
|
2790
|
+
*/
|
|
2791
|
+
|
|
2792
|
+
/**
|
|
2793
|
+
* Make arbitrary (rename-dialog) input safe as a box label: box-drawing /
|
|
2794
|
+
* arrow glyphs would corrupt the art, and the Scene's inline editor is
|
|
2795
|
+
* single-line, so newlines collapse to spaces.
|
|
2796
|
+
*/
|
|
2797
|
+
declare function sanitizeAsciiLabel(label: string): string;
|
|
2798
|
+
/** Move a node to (col, row); a container drags its whole subtree along. */
|
|
2799
|
+
declare function moveNodeOp(diagram: AsciiDiagram, nodeId: string, col: number, row: number): AsciiDiagram;
|
|
2800
|
+
/** Resize a node (grid cells). Clamped so the label always fits. */
|
|
2801
|
+
declare function resizeNodeOp(diagram: AsciiDiagram, nodeId: string, wCols: number, hRows: number): AsciiDiagram;
|
|
2802
|
+
/** Add a directed edge; duplicates (same source/target/label) are no-ops. */
|
|
2803
|
+
declare function addEdgeOp(diagram: AsciiDiagram, source: string, target: string, label?: string): AsciiDiagram;
|
|
2804
|
+
/**
|
|
2805
|
+
* Remove an edge. A label-qualified call removes the exact match; without
|
|
2806
|
+
* a label the first (source, target) match goes — mirroring the legacy
|
|
2807
|
+
* `removeConnection` semantics.
|
|
2808
|
+
*/
|
|
2809
|
+
declare function removeEdgeOp(diagram: AsciiDiagram, source: string, target: string, label?: string): AsciiDiagram;
|
|
2810
|
+
/**
|
|
2811
|
+
* Rename a node. The label drives the node's parse-derived id, so edges
|
|
2812
|
+
* and containment references are rewritten to the id the next parse will
|
|
2813
|
+
* produce. (Selection in the canvas drops after a rename — documented.)
|
|
2814
|
+
*/
|
|
2815
|
+
declare function renameNodeOp(diagram: AsciiDiagram, nodeId: string, label: string): AsciiDiagram;
|
|
2816
|
+
/** Add a node at (col, row). Inherits a container when placed inside one. */
|
|
2817
|
+
declare function addNodeOp(diagram: AsciiDiagram, opts: {
|
|
2818
|
+
col: number;
|
|
2819
|
+
row: number;
|
|
2820
|
+
label?: string;
|
|
2821
|
+
}): {
|
|
2822
|
+
diagram: AsciiDiagram;
|
|
2823
|
+
label: string;
|
|
2824
|
+
};
|
|
2825
|
+
/**
|
|
2826
|
+
* Remove a node: incident edges (both directions) drop, direct children
|
|
2827
|
+
* are promoted to the removed node's own container (or top level).
|
|
2828
|
+
*/
|
|
2829
|
+
declare function removeNodeOp(diagram: AsciiDiagram, nodeId: string): AsciiDiagram;
|
|
2830
|
+
|
|
2831
|
+
/**
|
|
2832
|
+
* Paste gate for bare (unfenced) ASCII diagram art.
|
|
2833
|
+
*
|
|
2834
|
+
* `+--+ | |` art pasted as plain text is otherwise mangled: its `| x |`
|
|
2835
|
+
* rows match the GFM table-row pattern in `detectMarkdown`, so the paste
|
|
2836
|
+
* handler routes it through the markdown converter, fails table
|
|
2837
|
+
* validation, and emits one broken paragraph per line. When this gate
|
|
2838
|
+
* matches, the paste handler inserts the text verbatim into a fresh code
|
|
2839
|
+
* block instead — which the AsciiDiagramExtension then picks up as an
|
|
2840
|
+
* interactive diagram.
|
|
2841
|
+
*/
|
|
2842
|
+
declare function shouldPasteAsAsciiFence(text: string): boolean;
|
|
2843
|
+
|
|
2844
|
+
/**
|
|
2845
|
+
* TreeViewExtension — Tiptap/ProseMirror plugin that turns code blocks
|
|
2846
|
+
* containing ASCII file-tree / outline art into interactive outline editors.
|
|
2847
|
+
*
|
|
2848
|
+
* Structurally identical to AsciiDiagramExtension (position registry, stable
|
|
2849
|
+
* synthetic ids, hysteresis, self-rewrite-survival via the decoration key);
|
|
2850
|
+
* only the detect/parse gates and class names differ. The fence text stays
|
|
2851
|
+
* the source of truth — every edit re-renders the tree art.
|
|
2852
|
+
*
|
|
2853
|
+
* Mutual exclusion with the diagram extension: a fence with ≥2 closed boxes
|
|
2854
|
+
* is a diagram, never a tree (checked in both gates), so at most one
|
|
2855
|
+
* extension claims any given fence.
|
|
2856
|
+
*/
|
|
2857
|
+
|
|
2858
|
+
interface TreeBlockEntry {
|
|
2859
|
+
/** Synthetic session id (`tree-N`), stable across edits for one block. */
|
|
2409
2860
|
id: string;
|
|
2861
|
+
/** Document position of the codeBlock node at the current state. */
|
|
2862
|
+
pos: number;
|
|
2863
|
+
}
|
|
2864
|
+
interface TreeViewPluginState {
|
|
2865
|
+
entries: TreeBlockEntry[];
|
|
2866
|
+
decorations: DecorationSet;
|
|
2867
|
+
seq: number;
|
|
2868
|
+
}
|
|
2869
|
+
declare function findTreeBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
2870
|
+
interface TreeViewExtensionOptions {
|
|
2871
|
+
/** When false, the extension is inert (no widgets, no decorations). */
|
|
2872
|
+
enabled?: boolean;
|
|
2873
|
+
}
|
|
2874
|
+
declare const TreeViewExtension: Extension<TreeViewExtensionOptions, any>;
|
|
2875
|
+
|
|
2876
|
+
interface TreeOutlineWidgetProps {
|
|
2877
|
+
editor: Editor$1;
|
|
2878
|
+
blockId: string;
|
|
2879
|
+
fallbackPos: number;
|
|
2880
|
+
host?: HTMLElement | null;
|
|
2881
|
+
}
|
|
2882
|
+
declare function TreeOutlineWidget({ editor, blockId }: TreeOutlineWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
2883
|
+
|
|
2884
|
+
/**
|
|
2885
|
+
* Read direction of the tree loop: fence text → outline view.
|
|
2886
|
+
*
|
|
2887
|
+
* `useTreeViewData` re-derives on every editor transaction; parsing is
|
|
2888
|
+
* memoized per PMNode by the extension's WeakMap caches, so untouched
|
|
2889
|
+
* fences cost nothing.
|
|
2890
|
+
*/
|
|
2891
|
+
|
|
2892
|
+
interface TreeViewData {
|
|
2893
|
+
tree: Tree;
|
|
2894
|
+
text: string;
|
|
2895
|
+
warnings: string[];
|
|
2410
2896
|
}
|
|
2897
|
+
/** Live view of one registered tree block; null when it no longer parses. */
|
|
2898
|
+
declare function useTreeViewData(editor: Editor$1, blockId: string): TreeViewData | null;
|
|
2899
|
+
|
|
2411
2900
|
/**
|
|
2412
|
-
*
|
|
2413
|
-
* parent heading with `dataTemplate === 'diagram'`). Returns the headings
|
|
2414
|
-
* that should appear as diagram nodes — defined as every heading at the
|
|
2415
|
-
* **shallowest** depth greater than the parent within the section, until
|
|
2416
|
-
* the next equal-or-shallower heading.
|
|
2901
|
+
* Write direction of the tree loop: outline command → fence rewrite.
|
|
2417
2902
|
*
|
|
2418
|
-
*
|
|
2419
|
-
*
|
|
2420
|
-
*
|
|
2421
|
-
* as direct children of the `#` parent. Any headings deeper than the
|
|
2422
|
-
* detected child depth are sub-sections of a node and are not surfaced as
|
|
2423
|
-
* separate diagram nodes.
|
|
2903
|
+
* parse → op → render → verify-reparse → single-transaction fence replace
|
|
2904
|
+
* (one undo step). Reuses the generic `replaceAsciiFenceText` (it only
|
|
2905
|
+
* touches codeBlock text, attributes untouched).
|
|
2424
2906
|
*/
|
|
2425
|
-
|
|
2907
|
+
|
|
2908
|
+
type TreeCommand = {
|
|
2909
|
+
kind: 'addItem';
|
|
2910
|
+
targetId: string;
|
|
2911
|
+
position: 'child' | 'siblingAfter';
|
|
2912
|
+
label?: string;
|
|
2913
|
+
isDir?: boolean;
|
|
2914
|
+
} | {
|
|
2915
|
+
kind: 'renameItem';
|
|
2916
|
+
id: string;
|
|
2917
|
+
label: string;
|
|
2918
|
+
} | {
|
|
2919
|
+
kind: 'indentItem';
|
|
2920
|
+
id: string;
|
|
2921
|
+
} | {
|
|
2922
|
+
kind: 'outdentItem';
|
|
2923
|
+
id: string;
|
|
2924
|
+
} | {
|
|
2925
|
+
kind: 'moveItemUp';
|
|
2926
|
+
id: string;
|
|
2927
|
+
} | {
|
|
2928
|
+
kind: 'moveItemDown';
|
|
2929
|
+
id: string;
|
|
2930
|
+
} | {
|
|
2931
|
+
kind: 'removeItem';
|
|
2932
|
+
id: string;
|
|
2933
|
+
} | {
|
|
2934
|
+
kind: 'toggleDir';
|
|
2935
|
+
id: string;
|
|
2936
|
+
};
|
|
2937
|
+
|
|
2938
|
+
declare function applyTreeCommand(editor: Editor$1, blockId: string, cmd: TreeCommand): boolean;
|
|
2939
|
+
|
|
2426
2940
|
/**
|
|
2427
|
-
*
|
|
2941
|
+
* Pure outline operations over the tree model — the write-direction half of
|
|
2942
|
+
* the fence-is-source-of-truth loop:
|
|
2943
|
+
*
|
|
2944
|
+
* fence text → parseTree → op → renderTree → fence text
|
|
2428
2945
|
*
|
|
2429
|
-
*
|
|
2430
|
-
*
|
|
2431
|
-
*
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
2434
|
-
* Freezing converts the implicit layout into explicit per-node
|
|
2435
|
-
* positions on the first interaction, after which each node moves
|
|
2436
|
-
* independently.
|
|
2946
|
+
* Every op returns a NEW Tree (inputs untouched). These are the genuinely
|
|
2947
|
+
* new operations with no diagram analog: indent / outdent (re-parent a node
|
|
2948
|
+
* carrying its subtree), move-up / move-down (reorder siblings), plus
|
|
2949
|
+
* add / rename / remove / toggle-directory. Connector rails re-derive in
|
|
2950
|
+
* render, so ops only touch structure + labels.
|
|
2437
2951
|
*/
|
|
2438
|
-
|
|
2952
|
+
|
|
2953
|
+
/** Make an arbitrary rename safe as a tree label: no connector glyphs / newlines. */
|
|
2954
|
+
declare function sanitizeTreeLabel(label: string): string;
|
|
2955
|
+
declare function renameItemOp(tree: Tree, id: string, label: string): Tree;
|
|
2956
|
+
declare function addItemOp(tree: Tree, targetId: string, position: 'child' | 'siblingAfter', label?: string, isDir?: boolean): Tree;
|
|
2957
|
+
declare function removeItemOp(tree: Tree, id: string): Tree;
|
|
2958
|
+
/** Node becomes the last child of its immediate preceding sibling. */
|
|
2959
|
+
declare function indentItemOp(tree: Tree, id: string): Tree;
|
|
2960
|
+
/** Node becomes a sibling of its parent, inserted directly after it (subtree carried). */
|
|
2961
|
+
declare function outdentItemOp(tree: Tree, id: string): Tree;
|
|
2962
|
+
declare function moveItemUpOp(tree: Tree, id: string): Tree;
|
|
2963
|
+
declare function moveItemDownOp(tree: Tree, id: string): Tree;
|
|
2964
|
+
/** Toggle the trailing-slash directory marker on a node's label. */
|
|
2965
|
+
declare function toggleDirOp(tree: Tree, id: string): Tree;
|
|
2966
|
+
|
|
2439
2967
|
/**
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2968
|
+
* Paste gate for bare (unfenced) ASCII tree art. `├──`/`└──` file-tree lines
|
|
2969
|
+
* would otherwise route through the markdown converter and mangle; when this
|
|
2970
|
+
* matches, the paste handler drops the text verbatim into a fresh code block
|
|
2971
|
+
* that the TreeViewExtension picks up as an interactive outline.
|
|
2442
2972
|
*/
|
|
2443
|
-
declare function
|
|
2973
|
+
declare function shouldPasteAsTreeFence(text: string): boolean;
|
|
2974
|
+
|
|
2444
2975
|
/**
|
|
2445
|
-
*
|
|
2446
|
-
*
|
|
2447
|
-
*
|
|
2976
|
+
* TimelineViewExtension — mounts a WYSIWYG timeline editor over qualifying
|
|
2977
|
+
* authored timeline code fences while keeping the fence text as source of
|
|
2978
|
+
* truth. Every semantic edit is rendered back through the core codec.
|
|
2448
2979
|
*/
|
|
2449
|
-
|
|
2980
|
+
|
|
2981
|
+
interface TimelineBlockEntry {
|
|
2982
|
+
/** Synthetic session id, stable across edits to one fence. */
|
|
2983
|
+
id: string;
|
|
2984
|
+
/** Current document position of the codeBlock node. */
|
|
2985
|
+
pos: number;
|
|
2986
|
+
}
|
|
2987
|
+
interface TimelineViewPluginState {
|
|
2988
|
+
entries: TimelineBlockEntry[];
|
|
2989
|
+
decorations: DecorationSet;
|
|
2990
|
+
seq: number;
|
|
2991
|
+
}
|
|
2992
|
+
declare const TIMELINE_VIEW_KEY: PluginKey<TimelineViewPluginState>;
|
|
2993
|
+
/** Conservative full-detection gate used when first claiming a code fence. */
|
|
2994
|
+
declare function getTimelineForNode(node: Node): AsciiTimeline | null;
|
|
2995
|
+
/** Relaxed/sticky gate for a block already registered by this extension. */
|
|
2996
|
+
declare function parseTimelineForNode(node: Node): AsciiTimeline | null;
|
|
2997
|
+
declare function findTimelineBlockPos(editor: Editor$1, blockId: string): number | null;
|
|
2998
|
+
interface TimelineViewExtensionOptions {
|
|
2999
|
+
/** When false, the extension does not claim fences or mount widgets. */
|
|
3000
|
+
enabled?: boolean;
|
|
3001
|
+
}
|
|
3002
|
+
declare const TimelineViewExtension: Extension<TimelineViewExtensionOptions, any>;
|
|
3003
|
+
|
|
3004
|
+
interface TimelineEditorWidgetProps {
|
|
3005
|
+
editor: Editor$1;
|
|
3006
|
+
blockId: string;
|
|
3007
|
+
}
|
|
3008
|
+
declare function TimelineEditorWidget({ editor, blockId }: TimelineEditorWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
3009
|
+
|
|
3010
|
+
/** Live read-direction adapter from a registered timeline fence to React. */
|
|
3011
|
+
|
|
3012
|
+
interface TimelineViewData {
|
|
3013
|
+
timeline: AsciiTimeline;
|
|
3014
|
+
text: string;
|
|
3015
|
+
warnings: string[];
|
|
3016
|
+
}
|
|
3017
|
+
declare function useTimelineData(editor: Editor$1, blockId: string): TimelineViewData | null;
|
|
3018
|
+
|
|
3019
|
+
/**
|
|
3020
|
+
* Pure edits over the authored ASCII timeline model.
|
|
3021
|
+
*
|
|
3022
|
+
* The code fence remains the source of truth. Canvas coordinates are
|
|
3023
|
+
* normalized to the same global, shared scale used by
|
|
3024
|
+
* `asciiTimelineToTemplateData`; commands render the edited model back into
|
|
3025
|
+
* canonical fence text after applying one of these operations.
|
|
3026
|
+
*/
|
|
3027
|
+
|
|
3028
|
+
interface TimelineEventPatch {
|
|
3029
|
+
label?: string;
|
|
3030
|
+
/** `null` clears the optional description. */
|
|
3031
|
+
description?: string | null;
|
|
3032
|
+
side?: AsciiTimelineSide;
|
|
3033
|
+
/** `null` restores the label side/default placement. */
|
|
3034
|
+
descriptionSide?: AsciiTimelineSide | null;
|
|
3035
|
+
callout?: boolean;
|
|
3036
|
+
marker?: AsciiTimelineMarker;
|
|
3037
|
+
/** Normalized position on the global timeline scale. */
|
|
3038
|
+
position?: number;
|
|
3039
|
+
}
|
|
3040
|
+
interface AddTimelineEventOptions {
|
|
3041
|
+
id?: string;
|
|
3042
|
+
label?: string;
|
|
3043
|
+
description?: string;
|
|
3044
|
+
side?: AsciiTimelineSide;
|
|
3045
|
+
descriptionSide?: AsciiTimelineSide;
|
|
3046
|
+
callout?: boolean;
|
|
3047
|
+
marker?: AsciiTimelineMarker;
|
|
3048
|
+
}
|
|
3049
|
+
interface AddTimelineEventResult {
|
|
3050
|
+
timeline: AsciiTimeline;
|
|
3051
|
+
eventId: string;
|
|
3052
|
+
}
|
|
2450
3053
|
/**
|
|
2451
|
-
*
|
|
2452
|
-
*
|
|
3054
|
+
* Normalize editable one-line prose exactly as the canonical core renderer
|
|
3055
|
+
* does. This prevents the verified command path from accepting a value that
|
|
3056
|
+
* is silently reinterpreted as timeline syntax on its first render.
|
|
2453
3057
|
*/
|
|
2454
|
-
declare function
|
|
3058
|
+
declare function sanitizeTimelineText(value: string): string;
|
|
3059
|
+
/** Return a globally unique, renderer-safe event id. */
|
|
3060
|
+
declare function nextTimelineEventId(timeline: AsciiTimeline, base?: string): string;
|
|
2455
3061
|
/**
|
|
2456
|
-
*
|
|
2457
|
-
*
|
|
2458
|
-
*
|
|
2459
|
-
* coordinates.
|
|
3062
|
+
* Add a visible point to `trackId` at a normalized global rail position.
|
|
3063
|
+
* Returns the stable id so the canvas can select/focus the new point after
|
|
3064
|
+
* the fence rewrite.
|
|
2460
3065
|
*/
|
|
2461
|
-
declare function
|
|
3066
|
+
declare function addTimelineEventOp(timeline: AsciiTimeline, trackId: string, position: number, options?: AddTimelineEventOptions): AddTimelineEventResult | null;
|
|
3067
|
+
/** Update one point without changing its stable id or branch endpoints. */
|
|
3068
|
+
declare function updateTimelineEventOp(timeline: AsciiTimeline, eventId: string, patch: TimelineEventPatch): AsciiTimeline;
|
|
2462
3069
|
/**
|
|
2463
|
-
* Remove a
|
|
2464
|
-
*
|
|
2465
|
-
*
|
|
3070
|
+
* Remove a point and every incident branch. Empty tracks are removed because
|
|
3071
|
+
* the canonical renderer cannot represent them. The last point in the whole
|
|
3072
|
+
* timeline is retained so an edit cannot erase its own source fence/widget.
|
|
2466
3073
|
*/
|
|
2467
|
-
declare function
|
|
3074
|
+
declare function removeTimelineEventOp(timeline: AsciiTimeline, eventId: string): AsciiTimeline;
|
|
3075
|
+
|
|
3076
|
+
/**
|
|
3077
|
+
* Write direction for the WYSIWYG timeline editor:
|
|
3078
|
+
*
|
|
3079
|
+
* fence text -> parse -> pure op -> render -> verify -> one fence rewrite
|
|
3080
|
+
*
|
|
3081
|
+
* The original code block remains the source of truth and every successful
|
|
3082
|
+
* edit is a single ProseMirror transaction/undo step.
|
|
3083
|
+
*/
|
|
3084
|
+
|
|
3085
|
+
type TimelineCommand = {
|
|
3086
|
+
kind: 'addEvent';
|
|
3087
|
+
trackId: string;
|
|
3088
|
+
/** Normalized position on the global timeline rail. */
|
|
3089
|
+
position: number;
|
|
3090
|
+
id?: string;
|
|
3091
|
+
label?: string;
|
|
3092
|
+
description?: string;
|
|
3093
|
+
side?: AsciiTimelineSide;
|
|
3094
|
+
descriptionSide?: AsciiTimelineSide;
|
|
3095
|
+
callout?: boolean;
|
|
3096
|
+
marker?: AsciiTimelineMarker;
|
|
3097
|
+
} | {
|
|
3098
|
+
kind: 'updateEvent';
|
|
3099
|
+
eventId: string;
|
|
3100
|
+
patch: TimelineEventPatch;
|
|
3101
|
+
} | {
|
|
3102
|
+
kind: 'removeEvent';
|
|
3103
|
+
eventId: string;
|
|
3104
|
+
};
|
|
3105
|
+
interface TimelineCommandResult {
|
|
3106
|
+
applied: boolean;
|
|
3107
|
+
/** Present after add so the widget can select/focus the new marker. */
|
|
3108
|
+
eventId?: string;
|
|
3109
|
+
/** Why an otherwise valid semantic edit was deliberately blocked. */
|
|
3110
|
+
reason?: 'read-only' | 'unsafe-source';
|
|
3111
|
+
}
|
|
3112
|
+
/**
|
|
3113
|
+
* Semantic operations replace the whole fence with canonical rendered art.
|
|
3114
|
+
* Fail closed when that would discard source the timeline model cannot
|
|
3115
|
+
* represent. Warnings catch unresolved/unlabeled constructs; the semantic
|
|
3116
|
+
* round-trip catches renderer normalization that changes modeled content;
|
|
3117
|
+
* exact metadata validation rejects partially consumed attrs; and a linear
|
|
3118
|
+
* semantic-residue comparison catches ignored prose/symbol rows without
|
|
3119
|
+
* reparsing a successively shorter document for every source line.
|
|
3120
|
+
*/
|
|
3121
|
+
declare function isTimelineSourceSafeForSemanticEdit(source: string, timeline: AsciiTimeline): boolean;
|
|
3122
|
+
/** Apply one semantic timeline command to a registered fence block. */
|
|
3123
|
+
declare function applyTimelineCommand(editor: Editor$1, blockId: string, command: TimelineCommand): TimelineCommandResult;
|
|
3124
|
+
|
|
3125
|
+
/** Paste gate for bare, high-confidence Unicode timeline art. */
|
|
3126
|
+
declare function shouldPasteAsTimelineFence(text: string): boolean;
|
|
2468
3127
|
|
|
2469
3128
|
interface JsonEditorProps {
|
|
2470
3129
|
/** Schema describing the value's shape (with optional `squisq` hints). */
|
|
@@ -2869,6 +3528,443 @@ declare function encodeTimingJson(timing: TimingJson): Uint8Array;
|
|
|
2869
3528
|
*/
|
|
2870
3529
|
declare function timingPathFor(audioRelativePath: string): string;
|
|
2871
3530
|
|
|
3531
|
+
/** Editor plumbing the recording flow needs; omit for prompter-only use. */
|
|
3532
|
+
interface TeleprompterRecordingDeps {
|
|
3533
|
+
mediaProvider: MediaProvider;
|
|
3534
|
+
container: ContentContainer | null;
|
|
3535
|
+
markdownSource: string;
|
|
3536
|
+
setMarkdownSource: (next: string) => void;
|
|
3537
|
+
bumpMediaRevision: () => void;
|
|
3538
|
+
}
|
|
3539
|
+
interface TeleprompterViewProps {
|
|
3540
|
+
doc: Doc | null;
|
|
3541
|
+
theme: Theme;
|
|
3542
|
+
/** Kept for API symmetry with PreviewPanel; recording uses `recording.container`. */
|
|
3543
|
+
workspaceContainer?: ContentContainer | null;
|
|
3544
|
+
/** Media base path (reserved for future preview integrations). */
|
|
3545
|
+
basePath?: string;
|
|
3546
|
+
/**
|
|
3547
|
+
* Optional audience-window portal owned by the editor's Presentation mode.
|
|
3548
|
+
* The main controller remains authoritative; only this live surface is
|
|
3549
|
+
* mirrored into the target.
|
|
3550
|
+
*/
|
|
3551
|
+
presentationTarget?: HTMLElement | null;
|
|
3552
|
+
/** Recording deps; null/omitted disables the Record affordance. */
|
|
3553
|
+
recording?: TeleprompterRecordingDeps | null;
|
|
3554
|
+
}
|
|
3555
|
+
declare function TeleprompterView(props: TeleprompterViewProps): react_jsx_runtime.JSX.Element;
|
|
3556
|
+
|
|
3557
|
+
/**
|
|
3558
|
+
* Mic capture + PCM transport for the teleprompter.
|
|
3559
|
+
*
|
|
3560
|
+
* getUserMedia → AudioContext → AudioWorklet tap → subscriber callbacks
|
|
3561
|
+
* with 1024-sample Float32Array hops on the main thread. The DSP itself
|
|
3562
|
+
* lives in core (`@bendyline/squisq/narration`) — this hook only moves
|
|
3563
|
+
* samples. Falls back to a ScriptProcessorNode when `audioWorklet` is
|
|
3564
|
+
* unavailable (same push model, so pacing still isn't tied to rAF).
|
|
3565
|
+
*/
|
|
3566
|
+
type MicAnalysisStatus = 'idle' | 'starting' | 'live' | 'error';
|
|
3567
|
+
type PcmHopListener = (pcm: Float32Array, audioTimeSec: number) => void;
|
|
3568
|
+
interface MicAnalysisHandle {
|
|
3569
|
+
status: MicAnalysisStatus;
|
|
3570
|
+
error: Error | null;
|
|
3571
|
+
/** The live mic stream (feeds the narration recorder too), or null. */
|
|
3572
|
+
stream: MediaStream | null;
|
|
3573
|
+
/** AudioContext sample rate once live. */
|
|
3574
|
+
sampleRate: number | null;
|
|
3575
|
+
/** Known audio inputs (labels appear after the first grant). */
|
|
3576
|
+
devices: MediaDeviceInfo[];
|
|
3577
|
+
/**
|
|
3578
|
+
* Start (or restart) capture. Resolves with the live stream — callers
|
|
3579
|
+
* that need it immediately must use the return value, not the `stream`
|
|
3580
|
+
* state field, which only updates on the NEXT render (stale-closure
|
|
3581
|
+
* hazard right after an await). Null on failure/supersession.
|
|
3582
|
+
*/
|
|
3583
|
+
start: (deviceId: string | null) => Promise<MediaStream | null>;
|
|
3584
|
+
stop: () => void;
|
|
3585
|
+
/** Subscribe to PCM hops; returns an unsubscribe. */
|
|
3586
|
+
subscribeHop: (listener: PcmHopListener) => () => void;
|
|
3587
|
+
}
|
|
3588
|
+
declare function useMicAnalysis(): MicAnalysisHandle;
|
|
3589
|
+
|
|
3590
|
+
/**
|
|
3591
|
+
* Narration recorder for the teleprompter — an in-place (no modal)
|
|
3592
|
+
* capture flow.
|
|
3593
|
+
*
|
|
3594
|
+
* Audio records THE MIC ANALYSIS STREAM (what paces the prompter is
|
|
3595
|
+
* exactly what lands in the take); the optional camera is a separate
|
|
3596
|
+
* video-only capture whose start skew vs the audio recorder is measured
|
|
3597
|
+
* and persisted (`cameraOffsetSec`) — the audio file is the doc clock,
|
|
3598
|
+
* so camera skew never affects narration timing. While recording, a
|
|
3599
|
+
* sparse live trace of the prompter position is sampled; after stop,
|
|
3600
|
+
* the take is decoded and run through core's offline aligner
|
|
3601
|
+
* (`alignNarration`) to produce word/block timestamps for the sidecar.
|
|
3602
|
+
* Decode/alignment failure degrades gracefully: saving still works,
|
|
3603
|
+
* just without re-timing.
|
|
3604
|
+
*/
|
|
3605
|
+
|
|
3606
|
+
type NarrationRecorderState = 'idle' | 'starting' | 'recording' | 'processing' | 'review' | 'saving' | 'error';
|
|
3607
|
+
interface NarrationTake {
|
|
3608
|
+
audioBlob: Blob;
|
|
3609
|
+
audioMime: string;
|
|
3610
|
+
audioExt: string;
|
|
3611
|
+
cameraBlob: Blob | null;
|
|
3612
|
+
cameraMime: string | null;
|
|
3613
|
+
cameraExt: string | null;
|
|
3614
|
+
durationSec: number;
|
|
3615
|
+
cameraOffsetSec: number | undefined;
|
|
3616
|
+
trace: NarrationTrace;
|
|
3617
|
+
alignment: NarrationAlignment | null;
|
|
3618
|
+
script: NarrationScript;
|
|
3619
|
+
}
|
|
3620
|
+
interface UseNarrationRecorderOptions {
|
|
3621
|
+
mic: MicAnalysisHandle;
|
|
3622
|
+
getScript: () => NarrationScript | null;
|
|
3623
|
+
/** Live prompter position, sampled into the trace while recording. */
|
|
3624
|
+
getWordPos: () => number;
|
|
3625
|
+
getMicDeviceId: () => string | null;
|
|
3626
|
+
/** Fired when capture actually starts (View starts the prompter). */
|
|
3627
|
+
onRecordingStart?: () => void;
|
|
3628
|
+
onRecordingStop?: () => void;
|
|
3629
|
+
}
|
|
3630
|
+
interface NarrationRecorderController {
|
|
3631
|
+
state: NarrationRecorderState;
|
|
3632
|
+
error: Error | null;
|
|
3633
|
+
withCamera: boolean;
|
|
3634
|
+
setWithCamera: (on: boolean) => void;
|
|
3635
|
+
/** Live camera stream for the self-view while recording. */
|
|
3636
|
+
cameraStream: MediaStream | null;
|
|
3637
|
+
take: NarrationTake | null;
|
|
3638
|
+
start: () => Promise<void>;
|
|
3639
|
+
stop: () => Promise<void>;
|
|
3640
|
+
retake: () => void;
|
|
3641
|
+
discard: () => void;
|
|
3642
|
+
/** Transition into/out of 'saving'; the View owns the actual I/O. */
|
|
3643
|
+
beginSave: () => void;
|
|
3644
|
+
finishSave: (ok: boolean, error?: Error) => void;
|
|
3645
|
+
}
|
|
3646
|
+
declare function useNarrationRecorder(options: UseNarrationRecorderOptions): NarrationRecorderController;
|
|
3647
|
+
|
|
3648
|
+
/**
|
|
3649
|
+
* Pure save-plan builder for a narration take, plus its executor.
|
|
3650
|
+
*
|
|
3651
|
+
* Follows the recorder's conventions (`RecorderModal.handleSave`):
|
|
3652
|
+
* audio at `audio/<narration-…>` via `MediaProvider.addMedia` (the
|
|
3653
|
+
* RETURNED path is authoritative — providers may rename), the timing
|
|
3654
|
+
* sidecar at `<audio>.timing.json` via `container.writeFile` (falling
|
|
3655
|
+
* back to `addMedia` with a warning), and ONE `setMarkdownSource` write
|
|
3656
|
+
* composing every markdown edit from a single snapshot (the single-write
|
|
3657
|
+
* rule — successive writes each derive from stale source and clobber
|
|
3658
|
+
* each other).
|
|
3659
|
+
*
|
|
3660
|
+
* Block timings deliberately do NOT get baked into heading `duration=`
|
|
3661
|
+
* pins: pins outrank narration in `applyNarrationTiming`, so baking
|
|
3662
|
+
* them would shadow every retake. The sidecar owns the timing.
|
|
3663
|
+
*/
|
|
3664
|
+
|
|
3665
|
+
interface NarrationSavePlanArgs {
|
|
3666
|
+
script: NarrationScript;
|
|
3667
|
+
/** Null when decode/alignment failed — the sidecar still saves (empty timing). */
|
|
3668
|
+
alignment: NarrationAlignment | null;
|
|
3669
|
+
durationSec: number;
|
|
3670
|
+
audioExt: string;
|
|
3671
|
+
cameraExt: string | null;
|
|
3672
|
+
baseWpm: number;
|
|
3673
|
+
cameraOffsetSec?: number;
|
|
3674
|
+
}
|
|
3675
|
+
interface NarrationSavePlan {
|
|
3676
|
+
audioRelativeName: string;
|
|
3677
|
+
cameraRelativeName: string | null;
|
|
3678
|
+
sidecarPayload: NarrationTimingJsonV3;
|
|
3679
|
+
/** Sidecar path for a given (possibly renamed) saved audio path. */
|
|
3680
|
+
sidecarPathFor: (savedAudioPath: string) => string;
|
|
3681
|
+
/** Compose ALL markdown edits from one source snapshot. */
|
|
3682
|
+
nextMarkdown: (currentSource: string, savedAudioPath: string, savedCameraPath: string | null) => string;
|
|
3683
|
+
}
|
|
3684
|
+
declare function buildNarrationSavePlan(args: NarrationSavePlanArgs): NarrationSavePlan;
|
|
3685
|
+
interface ExecuteNarrationSaveDeps {
|
|
3686
|
+
mediaProvider: MediaProvider;
|
|
3687
|
+
container: ContentContainer | null;
|
|
3688
|
+
markdownSource: string;
|
|
3689
|
+
setMarkdownSource: (next: string) => void;
|
|
3690
|
+
bumpMediaRevision: () => void;
|
|
3691
|
+
}
|
|
3692
|
+
interface NarrationSaveResult {
|
|
3693
|
+
audioPath: string;
|
|
3694
|
+
cameraPath: string | null;
|
|
3695
|
+
sidecarPath: string;
|
|
3696
|
+
}
|
|
3697
|
+
/** Execute a save plan: media writes, sidecar, then the single markdown write. */
|
|
3698
|
+
declare function executeNarrationSave(plan: NarrationSavePlan, take: {
|
|
3699
|
+
audioBlob: Blob;
|
|
3700
|
+
audioMime: string;
|
|
3701
|
+
cameraBlob: Blob | null;
|
|
3702
|
+
cameraMime: string | null;
|
|
3703
|
+
}, deps: ExecuteNarrationSaveDeps): Promise<NarrationSaveResult>;
|
|
3704
|
+
|
|
3705
|
+
/**
|
|
3706
|
+
* Pure markdown edit: insert (or replace) the narration reference at the
|
|
3707
|
+
* start of the document.
|
|
3708
|
+
*
|
|
3709
|
+
* The narration take is referenced by a preamble media annotation —
|
|
3710
|
+
* `{[audio src=audio/narration-….webm anchor=document]}` — the canonical
|
|
3711
|
+
* authored form `markdownToDoc` lifts into `doc.documentMedia`. A prior
|
|
3712
|
+
* teleprompter take's line (matched by the `audio/narration-` prefix +
|
|
3713
|
+
* `anchor=document`) is replaced, so retakes swap the reference instead
|
|
3714
|
+
* of stacking narrations. The optional camera companion rides on the
|
|
3715
|
+
* next line as an inline `<video>` (deliberately NOT doc-anchored:
|
|
3716
|
+
* document-anchored video renders full-bleed behind every block and is
|
|
3717
|
+
* excluded from export audio — not a talking head).
|
|
3718
|
+
*/
|
|
3719
|
+
declare function narrationAnnotationLine(audioPath: string): string;
|
|
3720
|
+
declare function cameraVideoLine(cameraPath: string): string;
|
|
3721
|
+
/**
|
|
3722
|
+
* Insert the narration preamble after the frontmatter (or at the top),
|
|
3723
|
+
* replacing any previous teleprompter take's lines.
|
|
3724
|
+
*/
|
|
3725
|
+
declare function insertNarrationPreamble(source: string, audioPath: string, cameraPath: string | null): string;
|
|
3726
|
+
|
|
3727
|
+
interface TeleprompterSurfaceProps {
|
|
3728
|
+
script: NarrationScript;
|
|
3729
|
+
/** Fractional word position; floor is the active token. */
|
|
3730
|
+
wordPos: number;
|
|
3731
|
+
fontSizePx: number;
|
|
3732
|
+
mirrored: boolean;
|
|
3733
|
+
lineGuide: boolean;
|
|
3734
|
+
countdownRemaining: number | null;
|
|
3735
|
+
recordingIndicator: boolean;
|
|
3736
|
+
theme: Theme;
|
|
3737
|
+
/** Hide block markers / tighten padding for small float windows. */
|
|
3738
|
+
compact?: boolean;
|
|
3739
|
+
/** Click a word to jump the prompter there. */
|
|
3740
|
+
onSeekToken?: (tokenIndex: number) => void;
|
|
3741
|
+
}
|
|
3742
|
+
declare function TeleprompterSurface({ script, wordPos, fontSizePx, mirrored, lineGuide, countdownRemaining, recordingIndicator, theme, compact, onSeekToken, }: TeleprompterSurfaceProps): react_jsx_runtime.JSX.Element;
|
|
3743
|
+
|
|
3744
|
+
/**
|
|
3745
|
+
* Shared types for the Narrate (teleprompter) display mode.
|
|
3746
|
+
*/
|
|
3747
|
+
interface TeleprompterPrefs {
|
|
3748
|
+
/** Prompter type size in px (28–96). */
|
|
3749
|
+
fontSizePx: number;
|
|
3750
|
+
/** Beam-splitter mirror flip. */
|
|
3751
|
+
mirrored: boolean;
|
|
3752
|
+
/** Base speaking rate in words per minute (80–260). */
|
|
3753
|
+
baseWpm: number;
|
|
3754
|
+
/** Voice-adaptive pacing on/off; off = constant-rate manual mode. */
|
|
3755
|
+
voiceTracking: boolean;
|
|
3756
|
+
/** VAD sensitivity 0–1 (0.5 = engine defaults). */
|
|
3757
|
+
vadSensitivity: number;
|
|
3758
|
+
/** Countdown before the prompter starts rolling. */
|
|
3759
|
+
countdownSec: 0 | 3 | 5 | 10;
|
|
3760
|
+
/** Eye-line chevrons + focus band. */
|
|
3761
|
+
lineGuide: boolean;
|
|
3762
|
+
/** Preferred mic device id (null = system default). */
|
|
3763
|
+
micDeviceId: string | null;
|
|
3764
|
+
}
|
|
3765
|
+
declare const DEFAULT_TELEPROMPTER_PREFS: TeleprompterPrefs;
|
|
3766
|
+
type PrompterTransport = 'stopped' | 'countdown' | 'rolling' | 'paused' | 'finished';
|
|
3767
|
+
/** Floating-surface tier, best first. */
|
|
3768
|
+
type FloatTier = 'document-pip' | 'video-pip' | 'popup' | 'docked';
|
|
3769
|
+
|
|
3770
|
+
/**
|
|
3771
|
+
* The teleprompter controller — single source of truth, always in the
|
|
3772
|
+
* MAIN window (floats are render targets only).
|
|
3773
|
+
*
|
|
3774
|
+
* Loop-ownership rule: **the audio worklet owns time; the main window
|
|
3775
|
+
* owns state; the visible surface owns pixels.** Voice-mode position
|
|
3776
|
+
* advances on worklet PCM hops (immune to rAF/timer throttling while
|
|
3777
|
+
* the browser is occluded by recording software); manual constant-rate
|
|
3778
|
+
* mode uses rAF and is documented as best-effort under occlusion. React
|
|
3779
|
+
* state publishes at ~15 Hz; per-hop subscribers (`subscribeTick`)
|
|
3780
|
+
* exist for the video-PiP canvas pump.
|
|
3781
|
+
*/
|
|
3782
|
+
|
|
3783
|
+
interface TeleprompterController {
|
|
3784
|
+
script: NarrationScript | null;
|
|
3785
|
+
transport: PrompterTransport;
|
|
3786
|
+
countdownRemaining: number | null;
|
|
3787
|
+
/** Fractional word position (published ~15 Hz). */
|
|
3788
|
+
wordPos: number;
|
|
3789
|
+
/** Smoothed mic level 0–1 for the meter. */
|
|
3790
|
+
micLevel: number;
|
|
3791
|
+
/** VAD flag for the meter tint. */
|
|
3792
|
+
voiceActive: boolean;
|
|
3793
|
+
mic: MicAnalysisHandle;
|
|
3794
|
+
prefs: TeleprompterPrefs;
|
|
3795
|
+
setPrefs: (patch: Partial<TeleprompterPrefs>) => void;
|
|
3796
|
+
play: () => void;
|
|
3797
|
+
pause: () => void;
|
|
3798
|
+
restart: () => void;
|
|
3799
|
+
/** Move the prompter by whole tokens and re-anchor voice tracking. */
|
|
3800
|
+
nudge: (deltaTokens: number) => void;
|
|
3801
|
+
/** Jump to an absolute token index (e.g. click a block marker). */
|
|
3802
|
+
seekToToken: (tokenIndex: number) => void;
|
|
3803
|
+
/** Per-analysis-tick subscription (video-PiP pump). Not throttled. */
|
|
3804
|
+
subscribeTick: (cb: (wordPos: number) => void) => () => void;
|
|
3805
|
+
handleKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
|
|
3806
|
+
}
|
|
3807
|
+
/** Map the 0–1 sensitivity pref onto VAD thresholds (0.5 = engine defaults). */
|
|
3808
|
+
declare function vadConfigForSensitivity(sensitivity: number): Partial<VadConfig>;
|
|
3809
|
+
declare function useTeleprompter(opts: {
|
|
3810
|
+
doc: Doc | null;
|
|
3811
|
+
}): TeleprompterController;
|
|
3812
|
+
|
|
3813
|
+
/**
|
|
3814
|
+
* Floating-teleprompter window manager — framework-free.
|
|
3815
|
+
*
|
|
3816
|
+
* Capability ladder, best first:
|
|
3817
|
+
* 1. `document-pip` — Document Picture-in-Picture (Chromium 116+,
|
|
3818
|
+
* Firefox 151+): a true always-on-top window hosting live DOM; the
|
|
3819
|
+
* React surface portals into it.
|
|
3820
|
+
* 2. `video-pip` — canvas → `captureStream(0)` → `<video>` →
|
|
3821
|
+
* `requestPictureInPicture()` (Safari's only always-on-top path;
|
|
3822
|
+
* `webkitSetPresentationMode` fallback). Read-only: the main
|
|
3823
|
+
* window draws frames and calls `requestFrame()` on analysis
|
|
3824
|
+
* ticks — never rAF, which throttles under occlusion.
|
|
3825
|
+
* 3. `popup` — `window.open` (positionable, not always-on-top).
|
|
3826
|
+
* 4. `docked` — no float.
|
|
3827
|
+
*
|
|
3828
|
+
* Every tier is feature-detected at open time and falls through to the
|
|
3829
|
+
* next on ANY failure. All interactive state stays in the main window;
|
|
3830
|
+
* floats are render targets only.
|
|
3831
|
+
*/
|
|
3832
|
+
|
|
3833
|
+
interface FloatOpenOptions {
|
|
3834
|
+
width: number;
|
|
3835
|
+
height: number;
|
|
3836
|
+
/** Try this tier first; the ladder continues below it on failure. */
|
|
3837
|
+
preferredTier?: FloatTier;
|
|
3838
|
+
title: string;
|
|
3839
|
+
}
|
|
3840
|
+
interface CanvasSink {
|
|
3841
|
+
canvas: HTMLCanvasElement;
|
|
3842
|
+
width: number;
|
|
3843
|
+
height: number;
|
|
3844
|
+
/** Push the freshly drawn canvas frame into the PiP video. */
|
|
3845
|
+
requestFrame: () => void;
|
|
3846
|
+
}
|
|
3847
|
+
type FloatEvent = 'closed' | 'tierchange';
|
|
3848
|
+
interface FloatingWindowManager {
|
|
3849
|
+
readonly tier: FloatTier;
|
|
3850
|
+
readonly isOpen: boolean;
|
|
3851
|
+
/** Resolves with the tier that actually opened ('docked' if none could). */
|
|
3852
|
+
open(opts: FloatOpenOptions): Promise<FloatTier>;
|
|
3853
|
+
/** Idempotent; restores docked and emits 'closed'. */
|
|
3854
|
+
close(): void;
|
|
3855
|
+
/** Portal container for 'document-pip' | 'popup'; null otherwise. */
|
|
3856
|
+
getPortalTarget(): HTMLElement | null;
|
|
3857
|
+
/** Canvas sink for 'video-pip'; null otherwise. */
|
|
3858
|
+
getCanvasSink(): CanvasSink | null;
|
|
3859
|
+
on(event: FloatEvent, cb: (tier: FloatTier) => void): () => void;
|
|
3860
|
+
/** Tear everything down (unmount); like close() but silent-safe. */
|
|
3861
|
+
dispose(): void;
|
|
3862
|
+
}
|
|
3863
|
+
/** Feature-detect the available float tiers, best first. */
|
|
3864
|
+
declare function detectFloatTiers(): FloatTier[];
|
|
3865
|
+
declare function createFloatingWindowManager(deps: {
|
|
3866
|
+
styleCss: string;
|
|
3867
|
+
}): FloatingWindowManager;
|
|
3868
|
+
|
|
3869
|
+
/**
|
|
3870
|
+
* React binding over {@link createFloatingWindowManager}: exposes the
|
|
3871
|
+
* current tier + portal target as state and guarantees the float closes
|
|
3872
|
+
* when the owning view unmounts (mode switch, Use-tab exit, shell
|
|
3873
|
+
* teardown).
|
|
3874
|
+
*/
|
|
3875
|
+
|
|
3876
|
+
interface FloatingWindowHandle {
|
|
3877
|
+
tier: FloatTier;
|
|
3878
|
+
isOpen: boolean;
|
|
3879
|
+
/** Non-docked tiers this browser supports, best first. */
|
|
3880
|
+
supportedTiers: FloatTier[];
|
|
3881
|
+
portalTarget: HTMLElement | null;
|
|
3882
|
+
canvasSink: CanvasSink | null;
|
|
3883
|
+
open: (preferredTier?: FloatTier) => Promise<void>;
|
|
3884
|
+
close: () => void;
|
|
3885
|
+
}
|
|
3886
|
+
declare function useFloatingWindow(styleCss: string): FloatingWindowHandle;
|
|
3887
|
+
|
|
3888
|
+
interface TeleprompterControlsProps {
|
|
3889
|
+
controller: TeleprompterController;
|
|
3890
|
+
float: FloatingWindowHandle;
|
|
3891
|
+
/** Phase B mounts the narration Record button here. */
|
|
3892
|
+
recordSlot?: ReactNode;
|
|
3893
|
+
}
|
|
3894
|
+
declare function TeleprompterControls({ controller, float, recordSlot }: TeleprompterControlsProps): react_jsx_runtime.JSX.Element;
|
|
3895
|
+
|
|
3896
|
+
/**
|
|
3897
|
+
* The PCM tap AudioWorklet, shipped as an inline source string.
|
|
3898
|
+
*
|
|
3899
|
+
* Why inline → Blob URL instead of a bundled asset: `audioWorklet
|
|
3900
|
+
* .addModule(url)` resolves relative to the host DOCUMENT, so a
|
|
3901
|
+
* dist-relative asset would need every consumer's bundler to rewrite
|
|
3902
|
+
* and serve it (editor-react ships zero runtime assets today). The
|
|
3903
|
+
* worklet is ~30 lines with no imports; inlining follows the
|
|
3904
|
+
* `PLAYER_BUNDLE` source-string precedent and needs zero bundler
|
|
3905
|
+
* config. The worklet does NO DSP — it batches 128-sample render
|
|
3906
|
+
* quanta into 1024-sample frames and posts them (transferably) to the
|
|
3907
|
+
* main thread, where the pure engine in `@bendyline/squisq/narration`
|
|
3908
|
+
* runs. The audio render thread never throttles, so pacing keeps
|
|
3909
|
+
* working while the browser window is fully occluded by recording
|
|
3910
|
+
* software — the whole point of the teleprompter's scenario 2.
|
|
3911
|
+
*/
|
|
3912
|
+
declare const PCM_WORKLET_NAME = "squisq-pcm-tap";
|
|
3913
|
+
declare const PCM_WORKLET_SOURCE = "\nclass SquisqPcmTap extends AudioWorkletProcessor {\n constructor() {\n super();\n this._buf = new Float32Array(1024);\n this._len = 0;\n }\n process(inputs) {\n const channel = inputs[0] && inputs[0][0];\n if (channel && channel.length > 0) {\n let i = 0;\n while (i < channel.length) {\n const n = Math.min(channel.length - i, this._buf.length - this._len);\n this._buf.set(channel.subarray(i, i + n), this._len);\n this._len += n;\n i += n;\n if (this._len === this._buf.length) {\n const out = this._buf;\n this._buf = new Float32Array(1024);\n this._len = 0;\n // Clone, don't transfer: Chrome recycles buffers transferred out\n // of the worklet scope once the receiving handler returns, so a\n // transferred hop reads as zeros if anything retains it. A 4 KB\n // structured clone at ~47 Hz is negligible.\n this.port.postMessage({ pcm: out, audioTime: currentTime });\n }\n }\n }\n return true;\n }\n}\nregisterProcessor('squisq-pcm-tap', SquisqPcmTap);\n";
|
|
3914
|
+
/** Register the tap on an AudioContext via a same-origin Blob URL. */
|
|
3915
|
+
declare function registerPcmWorklet(ctx: AudioContext): Promise<void>;
|
|
3916
|
+
|
|
3917
|
+
/**
|
|
3918
|
+
* Pure scroll math for the teleprompter surface.
|
|
3919
|
+
*
|
|
3920
|
+
* The surface renders the whole script into one absolutely-positioned
|
|
3921
|
+
* column and translates it so the active word sits at the eye-line
|
|
3922
|
+
* (~35% from the top). These helpers are DOM-free except for the
|
|
3923
|
+
* measurement entry point, which only reads layout.
|
|
3924
|
+
*/
|
|
3925
|
+
interface TokenLineMap {
|
|
3926
|
+
/** Top offset (px, within the scroll column) of each token span. */
|
|
3927
|
+
tokenTops: number[];
|
|
3928
|
+
/** Height of each token's line box (px). */
|
|
3929
|
+
tokenHeights: number[];
|
|
3930
|
+
}
|
|
3931
|
+
/** Fraction of the viewport height where the active line is held. */
|
|
3932
|
+
declare const EYE_LINE_FRACTION = 0.35;
|
|
3933
|
+
/**
|
|
3934
|
+
* Measure the top offset of every `[data-token-idx]` span inside the
|
|
3935
|
+
* scroll column. Layout read only — call on mount, resize, and font-size
|
|
3936
|
+
* changes, not per frame.
|
|
3937
|
+
*/
|
|
3938
|
+
declare function measureTokenLines(scrollColumn: HTMLElement): TokenLineMap;
|
|
3939
|
+
/**
|
|
3940
|
+
* The translateY offset (px) that puts the (fractional) word position on
|
|
3941
|
+
* the eye-line. Interpolates between the current and next token tops so
|
|
3942
|
+
* the column glides instead of stepping line by line.
|
|
3943
|
+
*/
|
|
3944
|
+
declare function targetOffsetFor(wordPos: number, lines: TokenLineMap, viewportHeightPx: number, eyeLine?: number): number;
|
|
3945
|
+
/**
|
|
3946
|
+
* Advance the current scroll offset toward the target: exponential
|
|
3947
|
+
* approach (critically-damped feel) with an absolute speed clamp so a
|
|
3948
|
+
* hard resync glides rather than teleporting.
|
|
3949
|
+
*/
|
|
3950
|
+
declare function stepScroll(currentPx: number, targetPx: number, dtMs: number, maxPxPerSec?: number): number;
|
|
3951
|
+
|
|
3952
|
+
/**
|
|
3953
|
+
* Self-contained styling for the teleprompter.
|
|
3954
|
+
*
|
|
3955
|
+
* Everything the prompter surface needs ships as one CSS string plus a
|
|
3956
|
+
* set of inline `--squisq-prompter-*` custom properties derived from the
|
|
3957
|
+
* doc Theme. The docked surface, a Document-PiP window, and a popup all
|
|
3958
|
+
* inject the SAME string, so the surface never depends on the host
|
|
3959
|
+
* page's cascade (the VideoExportModal self-theming strategy).
|
|
3960
|
+
*/
|
|
3961
|
+
|
|
3962
|
+
/** Inline CSS vars for the surface root, derived from the doc theme. */
|
|
3963
|
+
declare function prompterVarsFromTheme(theme: Theme): Record<string, string>;
|
|
3964
|
+
/** Inject {@link TELEPROMPTER_CSS} into a document once (main doc or a float window). */
|
|
3965
|
+
declare function ensureTeleprompterStyles(doc: Document): void;
|
|
3966
|
+
declare const TELEPROMPTER_CSS = "\n.squisq-teleprompter-root {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n background: var(--squisq-bg, #f5f5f5);\n outline: none;\n}\n.squisq-teleprompter-stage {\n position: relative;\n flex: 1;\n min-height: 0;\n display: flex;\n}\n\n.squisq-teleprompter-surface {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n background: var(--squisq-prompter-bg, #101014);\n color: var(--squisq-prompter-text, #f5f5f2);\n font-family: var(--squisq-prompter-font, system-ui, sans-serif);\n user-select: none;\n}\n.squisq-teleprompter-flip {\n position: absolute;\n inset: 0;\n}\n.squisq-teleprompter-surface--mirrored .squisq-teleprompter-flip {\n transform: scaleX(-1);\n}\n.squisq-teleprompter-scroll {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n will-change: transform;\n padding: 40vh 8% 60vh;\n box-sizing: border-box;\n}\n.squisq-teleprompter-line-guide {\n position: absolute;\n left: 0;\n right: 0;\n pointer-events: none;\n z-index: 2;\n}\n.squisq-teleprompter-line-guide::before,\n.squisq-teleprompter-line-guide::after {\n content: '';\n position: absolute;\n top: 50%;\n border: 9px solid transparent;\n transform: translateY(-50%);\n}\n.squisq-teleprompter-line-guide::before {\n left: 6px;\n border-left-color: var(--squisq-prompter-accent, #e8b64c);\n}\n.squisq-teleprompter-line-guide::after {\n right: 6px;\n border-right-color: var(--squisq-prompter-accent, #e8b64c);\n}\n.squisq-teleprompter-guide-band {\n position: absolute;\n left: 0;\n right: 0;\n background: color-mix(in srgb, var(--squisq-prompter-accent, #e8b64c) 9%, transparent);\n pointer-events: none;\n z-index: 1;\n}\n\n.squisq-teleprompter-block-marker {\n display: block;\n margin: 1.1em 0 0.35em;\n font-size: 0.38em;\n font-weight: 600;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--squisq-prompter-muted, #9a9aa0);\n border-top: 1px solid color-mix(in srgb, var(--squisq-prompter-muted, #9a9aa0) 35%, transparent);\n padding-top: 0.6em;\n}\n.squisq-teleprompter-para {\n margin: 0 0 0.55em;\n line-height: 1.4;\n font-weight: 500;\n}\n.squisq-teleprompter-word {\n opacity: 0.45;\n transition: color 0.1s linear, opacity 0.1s linear;\n}\n.squisq-teleprompter-word--read {\n opacity: 0.9;\n}\n.squisq-teleprompter-word--active {\n opacity: 1;\n font-weight: 800;\n color: var(--squisq-prompter-accent, #e8b64c);\n}\n\n.squisq-teleprompter-countdown {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 3;\n background: color-mix(in srgb, var(--squisq-prompter-bg, #101014) 72%, transparent);\n}\n.squisq-teleprompter-countdown-digit {\n font-size: 18vmin;\n font-weight: 800;\n color: var(--squisq-prompter-accent, #e8b64c);\n animation: squisq-prompter-pulse 1s ease-in-out infinite;\n}\n.squisq-teleprompter-recdot {\n position: absolute;\n top: 14px;\n right: 16px;\n z-index: 4;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: #e5484d;\n box-shadow: 0 0 0 3px color-mix(in srgb, #e5484d 30%, transparent);\n animation: squisq-prompter-pulse 1.4s ease-in-out infinite;\n}\n/* Counter-flip overlays so they stay readable in mirror mode. */\n.squisq-teleprompter-surface--mirrored .squisq-teleprompter-countdown,\n.squisq-teleprompter-surface--mirrored .squisq-teleprompter-recdot {\n transform: scaleX(-1);\n}\n\n.squisq-teleprompter-selfview {\n position: absolute;\n right: 14px;\n bottom: 14px;\n width: 160px;\n border-radius: 8px;\n border: 2px solid color-mix(in srgb, #e5484d 60%, transparent);\n z-index: 5;\n background: #000;\n}\n\n.squisq-teleprompter-review {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 10px;\n padding: 8px 12px;\n border-top: 1px solid var(--squisq-border, #e5e7eb);\n background: var(--squisq-surface, var(--squisq-bg, #fff));\n color: var(--squisq-text, #111827);\n font-size: 12.5px;\n}\n.squisq-teleprompter-review audio {\n height: 28px;\n max-width: 260px;\n}\n.squisq-teleprompter-review button {\n font: inherit;\n color: inherit;\n background: var(--squisq-input-bg, #fff);\n border: 1px solid var(--squisq-border, #d1d5db);\n border-radius: 6px;\n padding: 4px 10px;\n cursor: pointer;\n}\n\n.squisq-teleprompter-float-note {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n color: var(--squisq-text-muted, #6b7280);\n font-size: 14px;\n}\n\n.squisq-teleprompter-controls {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 10px;\n padding: 8px 12px;\n border-top: 1px solid var(--squisq-border, #e5e7eb);\n background: var(--squisq-surface, var(--squisq-bg, #fff));\n color: var(--squisq-text, #111827);\n font-size: 12.5px;\n}\n.squisq-teleprompter-controls .squisq-teleprompter-group {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n white-space: nowrap;\n}\n.squisq-teleprompter-controls button {\n font: inherit;\n color: inherit;\n background: var(--squisq-input-bg, #fff);\n border: 1px solid var(--squisq-border, #d1d5db);\n border-radius: 6px;\n padding: 4px 10px;\n cursor: pointer;\n}\n.squisq-teleprompter-controls button:hover {\n background: var(--squisq-surface-hover, #f3f4f6);\n}\n.squisq-teleprompter-controls button[aria-pressed='true'] {\n background: var(--squisq-text, #111827);\n color: var(--squisq-bg, #fff);\n border-color: var(--squisq-text, #111827);\n}\n.squisq-teleprompter-controls select,\n.squisq-teleprompter-controls input[type='range'] {\n font: inherit;\n color: inherit;\n background: var(--squisq-input-bg, #fff);\n border: 1px solid var(--squisq-border, #d1d5db);\n border-radius: 6px;\n max-width: 170px;\n}\n.squisq-teleprompter-controls input[type='range'] {\n border: none;\n background: transparent;\n width: 110px;\n}\n.squisq-teleprompter-meter {\n position: relative;\n width: 64px;\n height: 8px;\n border-radius: 4px;\n overflow: hidden;\n background: var(--squisq-border, #e5e7eb);\n}\n.squisq-teleprompter-meter-fill {\n position: absolute;\n inset: 0 auto 0 0;\n background: #9ca3af;\n transition: width 0.08s linear;\n}\n.squisq-teleprompter-meter--voice .squisq-teleprompter-meter-fill {\n background: #30a46c;\n}\n\n@keyframes squisq-prompter-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.45; }\n}\n@media (prefers-reduced-motion: reduce) {\n .squisq-teleprompter-countdown-digit,\n .squisq-teleprompter-recdot {\n animation: none;\n }\n .squisq-teleprompter-word {\n transition: none;\n }\n}\n";
|
|
3967
|
+
|
|
2872
3968
|
interface ImageEditorProps {
|
|
2873
3969
|
/**
|
|
2874
3970
|
* Scoped sidecar container for this image — typically
|
|
@@ -3057,4 +4153,4 @@ interface UseImageEditorReturn {
|
|
|
3057
4153
|
}
|
|
3058
4154
|
declare function useImageEditor(options: UseImageEditorOptions): UseImageEditorReturn;
|
|
3059
4155
|
|
|
3060
|
-
export {
|
|
4156
|
+
export { ALL_PICKER_ENTRIES, type AddTimelineEventOptions, type AddTimelineEventResult, type AsciiDiagramBlockEntry, AsciiDiagramExtension, type AsciiDiagramExtensionOptions, type AsciiDiagramPluginState, type AsciiDiagramView, AsciiDiagramWidget, BlockCardView, type BlockCardViewProps, type BlockNavigator, BlockPropertiesPopover, type BlockPropertiesPopoverProps, type BlockRange, type BlockSlice, type BlockTagVisibility, type CameraStreamOptions, type CanvasRect, type CanvasSink, type CaptureKind, type CodeContext, type CodeContextSection, CodeContextZones, type CustomTemplateContextValue, CustomTemplateProvider, type CustomTemplateProviderProps, type CustomThemeContextValue, CustomThemeProvider, type CustomThemeProviderProps, DEFAULT_TELEPROMPTER_PREFS, DiagramCanvas, type DiagramCommand, type DiagramData, type DiagramEdge, type DiagramNode, type DirectionModel, type DocCustomTemplates, type DocCustomThemes, type DocumentLinkCandidate, type DocumentLinkProvider, DocumentSettingsDialog, type DocumentSettingsDialogProps, type DragContentType, type DropTarget, DropZoneOverlay, type DropZoneOverlayProps, EMPTY_TRANSITION, EYE_LINE_FRACTION, type EditorActions, type EditorColorScheme, type EditorContextValue, type EditorMode, EditorProvider, type EditorProviderProps, EditorShell, type EditorShellProps, type EditorState, type EditorView, EmojiPicker, type EmojiPickerProps, type FileCategory, type FileKind, type FloatOpenOptions, type FloatTier, type FloatingWindowHandle, type FloatingWindowManager, type FolderEntry, FolderView, type FolderViewProps, type HeadingTransitionAttrs, HeadingWithTemplate, type ImageDisplayMode, ImageEditor, type ImageEditorAction, type ImageEditorProps, type ImageEditorState, type ImageEditorTool, ImageViewer, type ImageViewerProps, ImportThemeSection, type ImportThemeSectionProps, type ImportedThemeResult, InlinePreviewGutter, type InlinePreviewGutterProps, JsonEditor, type JsonEditorProps, type LayoutMode, MediaBin, type MediaBinProps, type MediaClipPatch, type MentionCandidate, type MentionProvider, type MicAnalysisHandle, type MicAnalysisStatus, type MonacoWorkerConstructor, type MonacoWorkerConstructors, type NarrationRecorderController, type NarrationRecorderState, type NarrationSavePlan, type NarrationSaveResult, type NarrationTake, OutlinePanel, type OutlinePanelProps, PCM_WORKLET_NAME, PCM_WORKLET_SOURCE, PICKER_CATEGORIES, type PickerCategory, type PickerEntry, PlainHtmlPreview, type PlainHtmlPreviewProps, PreviewFormatSwitch, PreviewModeMenu, PreviewModeSwitch, PreviewPanel, type PreviewPanelProps, type PreviewSettings, PreviewSettingsProvider, PreviewToolbarControls, type PrompterTransport, REPAIRABLE_KEY, RawEditor, type RawEditorProps, type RecordedBookmark, RecorderButton, type RecorderButtonProps, RecorderModal, type RecorderModalProps, RecorderPanel, type RecorderPanelProps, type RecorderSaveResult, type RecorderSource, type RecorderState, type RepairableBlockEntry, RepairableDiagramExtension, type RepairableDiagramExtensionOptions, type RepairablePluginState, type ResolvedFormat, type ScreenStreamHandle, type ScreenStreamOptions, StatusBar, type StatusBarProps, TELEPROMPTER_CSS, TIMELINE_VIEW_KEY, TRANSITION_ENTRIES, TRANSITION_GROUPS, type TeleprompterController, TeleprompterControls, type TeleprompterControlsProps, type TeleprompterPrefs, type TeleprompterRecordingDeps, TeleprompterSurface, type TeleprompterSurfaceProps, TeleprompterView, type TeleprompterViewProps, TemplatePicker, ThemeCustomizerPanel, type ThemeCustomizerPanelProps, type ThemeInheritance, ThemePicker, type ThemePickerProps, type ThemeSaveExtras, type TimelineBlockEntry, type TimelineCommand, type TimelineCommandResult, TimelineEditorWidget, type TimelineEditorWidgetProps, type TimelineEventPatch, TimelineTrack, type TimelineTrackProps, type TimelineViewData, TimelineViewExtension, type TimelineViewExtensionOptions, type TimelineViewPluginState, type TimingJson, type TokenLineMap, Toolbar, type ToolbarProps, TooltipLayer, type TransitionCatalogEntry, type TransitionFields, type TransitionGroup, TransitionPicker, type TransitionPickerProps, type TreeBlockEntry, type TreeCommand, TreeOutlineWidget, type TreeViewData, TreeViewExtension, type TreeViewExtensionOptions, type TreeViewPluginState, type UseBlockNavigatorOptions, type UseFileDropOptions, type UseFileDropResult, type UseImageEditorOptions, type UseImageEditorReturn, type UseMediaRecorderOptions, type UseMediaRecorderResult, type UseMonacoLoaderResult, VersionHistoryPanel, ViewMenuPanel, type ViewPreferences, ViewSwitcher, type ViewSwitcherProps, WysiwygEditor, type WysiwygEditorProps, addEdgeOp, addItemOp, addNodeOp, addTimelineEventOp, applyAsciiDiagramCommand, applyRepairCommand, applyTimelineCommand, applyTreeCommand, asciiDiagramToCanvas, buildFilename, buildNarrationSavePlan, buildPreviewDoc, buildTimingJson, cameraVideoLine, classifyFile, configureMonacoWorkers, createFloatingWindowManager, detectFloatTiers, detectLanguageFromFileName, draftPatchFromImportedTheme, encodeTimingJson, ensureTeleprompterStyles, executeNarrationSave, findAsciiDiagramBlockPos, findRepairableBlockPos, findTimelineBlockPos, findTransitionEntry, findTreeBlockPos, formatSeconds, getBlockSlices, getCaptureKind, getTimelineForNode, imageEditorReducer, indentItemOp, initialImageEditorState, insertNarrationPreamble, isAsciiSourceVisible, isRepairableFence, isTimelineSourceSafeForSemanticEdit, lineToOffset, markdownToTiptap, measureTokenLines, moveItemDownOp, moveItemUpOp, moveNodeOp, narrationAnnotationLine, nextTimelineEventId, offsetToLine, outdentItemOp, parseTimelineForNode, partitionFiles, processMediaFiles, processTextFile, processTextFiles, prompterVarsFromTheme, readBlockAttrsParams, readBlockAttrsTransition, readBlockAttrsValue, readHeadingLineTransition, registerPcmWorklet, removeEdgeOp, removeItemOp, removeNodeOp, removeTimelineEventOp, renameItemOp, renameNodeOp, replaceAsciiFenceText, replaceAsciiFenceText as replaceTreeFenceText, requestCameraStream, requestMicStream, requestScreenStream, resizeNodeOp, resolveFileKind, resolveFormat, sanitizeAsciiLabel, sanitizeTimelineText, sanitizeTreeLabel, searchPickerEntries, setBlockAttrsValue, setBlockDurationInSource, setHeadingAttrsTransition, setHeadingLineTransition, setMediaClipInSource, shouldPasteAsAsciiFence, shouldPasteAsTimelineFence, shouldPasteAsTreeFence, sliceIndexAtOffset, spliceBlock, stepScroll, summarizeBlockProps, supportsDisplayMedia, supportsMediaRecorder, supportsUserMedia, targetOffsetFor, templateLabel, timingPathFor, tiptapToMarkdown, toggleAsciiSource, toggleDirOp, transitionLabel, updateTimelineEventOp, useAsciiDiagramData, useBlockNavigator, useCustomTemplates, useCustomThemes, useDocCustomTemplates, useDocCustomThemes, useEditorContext, useFileDrop, useFloatingWindow, useImageEditor, useMediaRecorder, useMicAnalysis, useMonacoLoader, useNarrationRecorder, usePreviewSettings, useStreamPreview, useTeleprompter, useTimelineData, useTreeViewData, vadConfigForSensitivity };
|