phormat 0.0.5
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 +102 -0
- package/dist/assets/example-test.svelte +228 -0
- package/dist/debug/JsonDebug.svelte +19 -0
- package/dist/debug/JsonDebug.svelte.d.ts +6 -0
- package/dist/debug/JsonDebugNode.svelte +138 -0
- package/dist/debug/JsonDebugNode.svelte.d.ts +11 -0
- package/dist/demo/documentLifecycle.d.ts +57 -0
- package/dist/demo/documentLifecycle.js +196 -0
- package/dist/demo/index.d.ts +2 -0
- package/dist/demo/index.js +2 -0
- package/dist/editor/BlockEditor.svelte +112 -0
- package/dist/editor/BlockEditor.svelte.d.ts +7 -0
- package/dist/editor/BlockRow.svelte +76 -0
- package/dist/editor/BlockRow.svelte.d.ts +20 -0
- package/dist/editor/Editor.svelte +103 -0
- package/dist/editor/Editor.svelte.d.ts +7 -0
- package/dist/editor/MarkdownEditor.svelte.d.ts +160 -0
- package/dist/editor/MarkdownEditor.svelte.js +1119 -0
- package/dist/editor/NestedRowChrome.svelte +160 -0
- package/dist/editor/NestedRowChrome.svelte.d.ts +20 -0
- package/dist/editor/PhormatEditor.svelte +206 -0
- package/dist/editor/PhormatEditor.svelte.d.ts +26 -0
- package/dist/editor/RawMarkdownPanel.svelte +39 -0
- package/dist/editor/RawMarkdownPanel.svelte.d.ts +6 -0
- package/dist/editor/block-specs/BlockSpecMissing.svelte +12 -0
- package/dist/editor/block-specs/BlockSpecMissing.svelte.d.ts +7 -0
- package/dist/editor/block-specs/blockquote/BlockquoteRenderer.svelte +32 -0
- package/dist/editor/block-specs/blockquote/BlockquoteRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/blockquote/commands.d.ts +2 -0
- package/dist/editor/block-specs/blockquote/commands.js +65 -0
- package/dist/editor/block-specs/blockquote/index.d.ts +6 -0
- package/dist/editor/block-specs/blockquote/index.js +5 -0
- package/dist/editor/block-specs/blockquote/inlineSecondPass.d.ts +6 -0
- package/dist/editor/block-specs/blockquote/inlineSecondPass.js +35 -0
- package/dist/editor/block-specs/blockquote/parse.d.ts +16 -0
- package/dist/editor/block-specs/blockquote/parse.js +188 -0
- package/dist/editor/block-specs/blockquote/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/blockquote/reconcile.js +9 -0
- package/dist/editor/block-specs/blockquote/serialize.d.ts +6 -0
- package/dist/editor/block-specs/blockquote/serialize.js +55 -0
- package/dist/editor/block-specs/blockquote/types.d.ts +20 -0
- package/dist/editor/block-specs/blockquote/types.js +1 -0
- package/dist/editor/block-specs/blockquoteSpec.d.ts +4 -0
- package/dist/editor/block-specs/blockquoteSpec.js +37 -0
- package/dist/editor/block-specs/callout/CalloutRenderer.svelte +38 -0
- package/dist/editor/block-specs/callout/CalloutRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/callout/CalloutTypeIcon.svelte +14 -0
- package/dist/editor/block-specs/callout/CalloutTypeIcon.svelte.d.ts +7 -0
- package/dist/editor/block-specs/callout/commands.d.ts +2 -0
- package/dist/editor/block-specs/callout/commands.js +65 -0
- package/dist/editor/block-specs/callout/icons.d.ts +10 -0
- package/dist/editor/block-specs/callout/icons.js +52 -0
- package/dist/editor/block-specs/callout/index.d.ts +9 -0
- package/dist/editor/block-specs/callout/index.js +7 -0
- package/dist/editor/block-specs/callout/inlineSecondPass.d.ts +6 -0
- package/dist/editor/block-specs/callout/inlineSecondPass.js +9 -0
- package/dist/editor/block-specs/callout/parse.d.ts +9 -0
- package/dist/editor/block-specs/callout/parse.js +83 -0
- package/dist/editor/block-specs/callout/parseBody.d.ts +6 -0
- package/dist/editor/block-specs/callout/parseBody.js +290 -0
- package/dist/editor/block-specs/callout/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/callout/reconcile.js +8 -0
- package/dist/editor/block-specs/callout/serialize.d.ts +5 -0
- package/dist/editor/block-specs/callout/serialize.js +65 -0
- package/dist/editor/block-specs/callout/types.d.ts +7 -0
- package/dist/editor/block-specs/callout/types.js +1 -0
- package/dist/editor/block-specs/calloutSpec.d.ts +2 -0
- package/dist/editor/block-specs/calloutSpec.js +23 -0
- package/dist/editor/block-specs/codeFence/CodeFenceRenderer.svelte +18 -0
- package/dist/editor/block-specs/codeFence/CodeFenceRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/codeFence/commands.d.ts +2 -0
- package/dist/editor/block-specs/codeFence/commands.js +1 -0
- package/dist/editor/block-specs/codeFence/index.d.ts +5 -0
- package/dist/editor/block-specs/codeFence/index.js +4 -0
- package/dist/editor/block-specs/codeFence/inlineSecondPass.d.ts +3 -0
- package/dist/editor/block-specs/codeFence/inlineSecondPass.js +5 -0
- package/dist/editor/block-specs/codeFence/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/codeFence/reconcile.js +5 -0
- package/dist/editor/block-specs/codeFence/serialize.d.ts +2 -0
- package/dist/editor/block-specs/codeFence/serialize.js +8 -0
- package/dist/editor/block-specs/codeFence/types.d.ts +6 -0
- package/dist/editor/block-specs/codeFence/types.js +1 -0
- package/dist/editor/block-specs/codeFenceSpec.d.ts +2 -0
- package/dist/editor/block-specs/codeFenceSpec.js +23 -0
- package/dist/editor/block-specs/columns/ColumnsRenderer.svelte +18 -0
- package/dist/editor/block-specs/columns/ColumnsRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/columns/EditableColumns.svelte +16 -0
- package/dist/editor/block-specs/columns/EditableColumns.svelte.d.ts +4 -0
- package/dist/editor/block-specs/columns/commands.d.ts +2 -0
- package/dist/editor/block-specs/columns/commands.js +1 -0
- package/dist/editor/block-specs/columns/index.d.ts +6 -0
- package/dist/editor/block-specs/columns/index.js +5 -0
- package/dist/editor/block-specs/columns/inlineSecondPass.d.ts +3 -0
- package/dist/editor/block-specs/columns/inlineSecondPass.js +5 -0
- package/dist/editor/block-specs/columns/parse.d.ts +20 -0
- package/dist/editor/block-specs/columns/parse.js +111 -0
- package/dist/editor/block-specs/columns/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/columns/reconcile.js +6 -0
- package/dist/editor/block-specs/columns/serialize.d.ts +2 -0
- package/dist/editor/block-specs/columns/serialize.js +16 -0
- package/dist/editor/block-specs/columns/types.d.ts +4 -0
- package/dist/editor/block-specs/columns/types.js +1 -0
- package/dist/editor/block-specs/columnsSpec.d.ts +2 -0
- package/dist/editor/block-specs/columnsSpec.js +24 -0
- package/dist/editor/block-specs/heading/HeaderRenderer.svelte +30 -0
- package/dist/editor/block-specs/heading/HeaderRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/heading/commands.d.ts +2 -0
- package/dist/editor/block-specs/heading/commands.js +41 -0
- package/dist/editor/block-specs/heading/edit.d.ts +10 -0
- package/dist/editor/block-specs/heading/edit.js +33 -0
- package/dist/editor/block-specs/heading/index.d.ts +7 -0
- package/dist/editor/block-specs/heading/index.js +6 -0
- package/dist/editor/block-specs/heading/inlineSecondPass.d.ts +4 -0
- package/dist/editor/block-specs/heading/inlineSecondPass.js +20 -0
- package/dist/editor/block-specs/heading/parse.d.ts +5 -0
- package/dist/editor/block-specs/heading/parse.js +18 -0
- package/dist/editor/block-specs/heading/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/heading/reconcile.js +8 -0
- package/dist/editor/block-specs/heading/serialize.d.ts +2 -0
- package/dist/editor/block-specs/heading/serialize.js +9 -0
- package/dist/editor/block-specs/heading/types.d.ts +5 -0
- package/dist/editor/block-specs/heading/types.js +1 -0
- package/dist/editor/block-specs/headingSpec.d.ts +2 -0
- package/dist/editor/block-specs/headingSpec.js +28 -0
- package/dist/editor/block-specs/horizontalRule/HorizontalRuleRenderer.svelte +15 -0
- package/dist/editor/block-specs/horizontalRule/HorizontalRuleRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/horizontalRule/commands.d.ts +2 -0
- package/dist/editor/block-specs/horizontalRule/commands.js +1 -0
- package/dist/editor/block-specs/horizontalRule/index.d.ts +6 -0
- package/dist/editor/block-specs/horizontalRule/index.js +5 -0
- package/dist/editor/block-specs/horizontalRule/inlineSecondPass.d.ts +3 -0
- package/dist/editor/block-specs/horizontalRule/inlineSecondPass.js +5 -0
- package/dist/editor/block-specs/horizontalRule/parse.d.ts +2 -0
- package/dist/editor/block-specs/horizontalRule/parse.js +15 -0
- package/dist/editor/block-specs/horizontalRule/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/horizontalRule/reconcile.js +5 -0
- package/dist/editor/block-specs/horizontalRule/serialize.d.ts +2 -0
- package/dist/editor/block-specs/horizontalRule/serialize.js +3 -0
- package/dist/editor/block-specs/horizontalRule/types.d.ts +3 -0
- package/dist/editor/block-specs/horizontalRule/types.js +1 -0
- package/dist/editor/block-specs/horizontalRuleSpec.d.ts +2 -0
- package/dist/editor/block-specs/horizontalRuleSpec.js +24 -0
- package/dist/editor/block-specs/list/ListRenderer.svelte +70 -0
- package/dist/editor/block-specs/list/ListRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/list/commands.d.ts +2 -0
- package/dist/editor/block-specs/list/commands.js +65 -0
- package/dist/editor/block-specs/list/index.d.ts +6 -0
- package/dist/editor/block-specs/list/index.js +5 -0
- package/dist/editor/block-specs/list/inlineSecondPass.d.ts +6 -0
- package/dist/editor/block-specs/list/inlineSecondPass.js +78 -0
- package/dist/editor/block-specs/list/parse.d.ts +11 -0
- package/dist/editor/block-specs/list/parse.js +312 -0
- package/dist/editor/block-specs/list/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/list/reconcile.js +6 -0
- package/dist/editor/block-specs/list/serialize.d.ts +4 -0
- package/dist/editor/block-specs/list/serialize.js +83 -0
- package/dist/editor/block-specs/list/types.d.ts +27 -0
- package/dist/editor/block-specs/list/types.js +1 -0
- package/dist/editor/block-specs/listSpec.d.ts +4 -0
- package/dist/editor/block-specs/listSpec.js +24 -0
- package/dist/editor/block-specs/paragraph/ParagraphRenderer.svelte +22 -0
- package/dist/editor/block-specs/paragraph/ParagraphRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/paragraph/commands.d.ts +2 -0
- package/dist/editor/block-specs/paragraph/commands.js +41 -0
- package/dist/editor/block-specs/paragraph/edit.d.ts +10 -0
- package/dist/editor/block-specs/paragraph/edit.js +69 -0
- package/dist/editor/block-specs/paragraph/index.d.ts +7 -0
- package/dist/editor/block-specs/paragraph/index.js +6 -0
- package/dist/editor/block-specs/paragraph/inlineSecondPass.d.ts +3 -0
- package/dist/editor/block-specs/paragraph/inlineSecondPass.js +25 -0
- package/dist/editor/block-specs/paragraph/parse.d.ts +9 -0
- package/dist/editor/block-specs/paragraph/parse.js +76 -0
- package/dist/editor/block-specs/paragraph/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/paragraph/reconcile.js +9 -0
- package/dist/editor/block-specs/paragraph/serialize.d.ts +4 -0
- package/dist/editor/block-specs/paragraph/serialize.js +39 -0
- package/dist/editor/block-specs/paragraph/types.d.ts +10 -0
- package/dist/editor/block-specs/paragraph/types.js +1 -0
- package/dist/editor/block-specs/paragraphSpec.d.ts +2 -0
- package/dist/editor/block-specs/paragraphSpec.js +24 -0
- package/dist/editor/block-specs/registry.d.ts +10 -0
- package/dist/editor/block-specs/registry.js +34 -0
- package/dist/editor/block-specs/table/TableRenderer.svelte +53 -0
- package/dist/editor/block-specs/table/TableRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/table/commands.d.ts +2 -0
- package/dist/editor/block-specs/table/commands.js +1 -0
- package/dist/editor/block-specs/table/edit.d.ts +10 -0
- package/dist/editor/block-specs/table/edit.js +127 -0
- package/dist/editor/block-specs/table/editCommands.d.ts +18 -0
- package/dist/editor/block-specs/table/editCommands.js +87 -0
- package/dist/editor/block-specs/table/index.d.ts +8 -0
- package/dist/editor/block-specs/table/index.js +6 -0
- package/dist/editor/block-specs/table/inlineSecondPass.d.ts +3 -0
- package/dist/editor/block-specs/table/inlineSecondPass.js +22 -0
- package/dist/editor/block-specs/table/parse.d.ts +17 -0
- package/dist/editor/block-specs/table/parse.js +181 -0
- package/dist/editor/block-specs/table/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/table/reconcile.js +6 -0
- package/dist/editor/block-specs/table/serialize.d.ts +3 -0
- package/dist/editor/block-specs/table/serialize.js +32 -0
- package/dist/editor/block-specs/table/types.d.ts +11 -0
- package/dist/editor/block-specs/table/types.js +1 -0
- package/dist/editor/block-specs/tableSpec.d.ts +2 -0
- package/dist/editor/block-specs/tableSpec.js +25 -0
- package/dist/editor/block-specs/toc/EditableToc.svelte +16 -0
- package/dist/editor/block-specs/toc/EditableToc.svelte.d.ts +4 -0
- package/dist/editor/block-specs/toc/TocRenderer.svelte +22 -0
- package/dist/editor/block-specs/toc/TocRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/toc/commands.d.ts +2 -0
- package/dist/editor/block-specs/toc/commands.js +1 -0
- package/dist/editor/block-specs/toc/index.d.ts +6 -0
- package/dist/editor/block-specs/toc/index.js +5 -0
- package/dist/editor/block-specs/toc/inlineSecondPass.d.ts +3 -0
- package/dist/editor/block-specs/toc/inlineSecondPass.js +5 -0
- package/dist/editor/block-specs/toc/parse.d.ts +10 -0
- package/dist/editor/block-specs/toc/parse.js +43 -0
- package/dist/editor/block-specs/toc/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/toc/reconcile.js +5 -0
- package/dist/editor/block-specs/toc/serialize.d.ts +2 -0
- package/dist/editor/block-specs/toc/serialize.js +6 -0
- package/dist/editor/block-specs/toc/types.d.ts +8 -0
- package/dist/editor/block-specs/toc/types.js +1 -0
- package/dist/editor/block-specs/tocSpec.d.ts +2 -0
- package/dist/editor/block-specs/tocSpec.js +24 -0
- package/dist/editor/block-specs/toggle/ToggleRenderer.svelte +19 -0
- package/dist/editor/block-specs/toggle/ToggleRenderer.svelte.d.ts +21 -0
- package/dist/editor/block-specs/toggle/commands.d.ts +2 -0
- package/dist/editor/block-specs/toggle/commands.js +1 -0
- package/dist/editor/block-specs/toggle/index.d.ts +7 -0
- package/dist/editor/block-specs/toggle/index.js +5 -0
- package/dist/editor/block-specs/toggle/inlineSecondPass.d.ts +3 -0
- package/dist/editor/block-specs/toggle/inlineSecondPass.js +5 -0
- package/dist/editor/block-specs/toggle/parse.d.ts +9 -0
- package/dist/editor/block-specs/toggle/parse.js +78 -0
- package/dist/editor/block-specs/toggle/reconcile.d.ts +2 -0
- package/dist/editor/block-specs/toggle/reconcile.js +6 -0
- package/dist/editor/block-specs/toggle/serialize.d.ts +4 -0
- package/dist/editor/block-specs/toggle/serialize.js +13 -0
- package/dist/editor/block-specs/toggle/types.d.ts +5 -0
- package/dist/editor/block-specs/toggle/types.js +1 -0
- package/dist/editor/block-specs/toggleSpec.d.ts +2 -0
- package/dist/editor/block-specs/toggleSpec.js +24 -0
- package/dist/editor/block-specs/types.d.ts +26 -0
- package/dist/editor/block-specs/types.js +1 -0
- package/dist/editor/blocks/EditableBlockquote.svelte +52 -0
- package/dist/editor/blocks/EditableBlockquote.svelte.d.ts +10 -0
- package/dist/editor/blocks/EditableBlockquoteNodes.svelte +134 -0
- package/dist/editor/blocks/EditableBlockquoteNodes.svelte.d.ts +14 -0
- package/dist/editor/blocks/EditableBlockquoteParagraph.svelte +44 -0
- package/dist/editor/blocks/EditableBlockquoteParagraph.svelte.d.ts +12 -0
- package/dist/editor/blocks/EditableCallout.svelte +182 -0
- package/dist/editor/blocks/EditableCallout.svelte.d.ts +11 -0
- package/dist/editor/blocks/EditableCalloutListItemRow.svelte +169 -0
- package/dist/editor/blocks/EditableCalloutListItemRow.svelte.d.ts +15 -0
- package/dist/editor/blocks/EditableCalloutNodes.svelte +91 -0
- package/dist/editor/blocks/EditableCalloutNodes.svelte.d.ts +13 -0
- package/dist/editor/blocks/EditableCalloutParagraph.svelte +39 -0
- package/dist/editor/blocks/EditableCalloutParagraph.svelte.d.ts +12 -0
- package/dist/editor/blocks/EditableCodeBlock.svelte +43 -0
- package/dist/editor/blocks/EditableCodeBlock.svelte.d.ts +10 -0
- package/dist/editor/blocks/EditableHeading.svelte +161 -0
- package/dist/editor/blocks/EditableHeading.svelte.d.ts +10 -0
- package/dist/editor/blocks/EditableHorizontalRule.svelte +20 -0
- package/dist/editor/blocks/EditableHorizontalRule.svelte.d.ts +10 -0
- package/dist/editor/blocks/EditableInlineSurface.svelte +423 -0
- package/dist/editor/blocks/EditableInlineSurface.svelte.d.ts +26 -0
- package/dist/editor/blocks/EditableList.svelte +77 -0
- package/dist/editor/blocks/EditableList.svelte.d.ts +17 -0
- package/dist/editor/blocks/EditableListItemRow.svelte +231 -0
- package/dist/editor/blocks/EditableListItemRow.svelte.d.ts +19 -0
- package/dist/editor/blocks/EditableParagraph.svelte +208 -0
- package/dist/editor/blocks/EditableParagraph.svelte.d.ts +10 -0
- package/dist/editor/blocks/EditableParagraphNodes.svelte +89 -0
- package/dist/editor/blocks/EditableParagraphNodes.svelte.d.ts +15 -0
- package/dist/editor/blocks/EditableTable.svelte +83 -0
- package/dist/editor/blocks/EditableTable.svelte.d.ts +10 -0
- package/dist/editor/blocks/EditableTableCell.svelte +89 -0
- package/dist/editor/blocks/EditableTableCell.svelte.d.ts +15 -0
- package/dist/editor/blocks/EditableToggle.svelte +94 -0
- package/dist/editor/blocks/EditableToggle.svelte.d.ts +10 -0
- package/dist/editor/commandMenu.d.ts +18 -0
- package/dist/editor/commandMenu.js +83 -0
- package/dist/editor/commandRegistry.d.ts +48 -0
- package/dist/editor/commandRegistry.js +133 -0
- package/dist/editor/context/assetBaseUrl.d.ts +6 -0
- package/dist/editor/context/assetBaseUrl.js +20 -0
- package/dist/editor/dom/editorHistoryKeydown.d.ts +6 -0
- package/dist/editor/dom/editorHistoryKeydown.js +31 -0
- package/dist/editor/dom/plainEnterKeydown.d.ts +12 -0
- package/dist/editor/dom/plainEnterKeydown.js +53 -0
- package/dist/editor/dom/plaintextCaret.d.ts +12 -0
- package/dist/editor/dom/plaintextCaret.js +61 -0
- package/dist/editor/dom/syncDocumentSelectionFocus.d.ts +17 -0
- package/dist/editor/dom/syncDocumentSelectionFocus.js +56 -0
- package/dist/editor/draftPersistence.d.ts +27 -0
- package/dist/editor/draftPersistence.js +83 -0
- package/dist/editor/editorHistoryHandle.d.ts +16 -0
- package/dist/editor/editorHistoryHandle.js +22 -0
- package/dist/editor/inlineChrome/InlineChromeCoordinator.svelte +174 -0
- package/dist/editor/inlineChrome/InlineChromeCoordinator.svelte.d.ts +8 -0
- package/dist/editor/inlineChrome/InlineFormattingToolbar.svelte +181 -0
- package/dist/editor/inlineChrome/InlineFormattingToolbar.svelte.d.ts +3 -0
- package/dist/editor/inlineChrome/inlineChromeActions.d.ts +17 -0
- package/dist/editor/inlineChrome/inlineChromeActions.js +148 -0
- package/dist/editor/inlineChrome/inlineChromeState.svelte.d.ts +23 -0
- package/dist/editor/inlineChrome/inlineChromeState.svelte.js +21 -0
- package/dist/editor/inlineChrome/inlineToolbarIcons.d.ts +14 -0
- package/dist/editor/inlineChrome/inlineToolbarIcons.js +14 -0
- package/dist/editor/inlineChrome/inlineWrapActive.d.ts +3 -0
- package/dist/editor/inlineChrome/inlineWrapActive.js +19 -0
- package/dist/editor/inlineChrome/selectionRect.d.ts +2 -0
- package/dist/editor/inlineChrome/selectionRect.js +23 -0
- package/dist/editor/model/blockEditCommands.d.ts +73 -0
- package/dist/editor/model/blockEditCommands.js +719 -0
- package/dist/editor/model/blockTree.d.ts +39 -0
- package/dist/editor/model/blockTree.js +185 -0
- package/dist/editor/model/blockTreeDrop.d.ts +9 -0
- package/dist/editor/model/blockTreeDrop.js +295 -0
- package/dist/editor/model/blockTreeMutations.d.ts +10 -0
- package/dist/editor/model/blockTreeMutations.js +68 -0
- package/dist/editor/model/calloutEditCommands.d.ts +39 -0
- package/dist/editor/model/calloutEditCommands.js +305 -0
- package/dist/editor/model/documentSelection.d.ts +8 -0
- package/dist/editor/model/documentSelection.js +56 -0
- package/dist/editor/model/documentSelectionFromSource.d.ts +3 -0
- package/dist/editor/model/documentSelectionFromSource.js +45 -0
- package/dist/editor/model/documentToRenderBlocks.d.ts +3 -0
- package/dist/editor/model/documentToRenderBlocks.js +13 -0
- package/dist/editor/model/editorPipeline.bench.d.ts +1 -0
- package/dist/editor/model/editorPipeline.bench.js +27 -0
- package/dist/editor/model/editorTransactions.d.ts +20 -0
- package/dist/editor/model/editorTransactions.js +68 -0
- package/dist/editor/model/emptyParagraph.d.ts +11 -0
- package/dist/editor/model/emptyParagraph.js +25 -0
- package/dist/editor/model/enterCommands.d.ts +16 -0
- package/dist/editor/model/enterCommands.js +288 -0
- package/dist/editor/model/extensionSyntaxWarnings.d.ts +29 -0
- package/dist/editor/model/extensionSyntaxWarnings.js +122 -0
- package/dist/editor/model/findBlockAtSourceOffset.d.ts +3 -0
- package/dist/editor/model/findBlockAtSourceOffset.js +20 -0
- package/dist/editor/model/fixtures/serialization-fidelity/reorder-gaps.svelte +4 -0
- package/dist/editor/model/focusOutcome.d.ts +25 -0
- package/dist/editor/model/focusOutcome.js +1 -0
- package/dist/editor/model/incrementalReparse.d.ts +16 -0
- package/dist/editor/model/incrementalReparse.js +111 -0
- package/dist/editor/model/index.d.ts +22 -0
- package/dist/editor/model/index.js +19 -0
- package/dist/editor/model/inlineDraftCommit.d.ts +17 -0
- package/dist/editor/model/inlineDraftCommit.js +187 -0
- package/dist/editor/model/inlineDraftMerge.d.ts +8 -0
- package/dist/editor/model/inlineDraftMerge.js +81 -0
- package/dist/editor/model/inlineEditCommands.d.ts +28 -0
- package/dist/editor/model/inlineEditCommands.js +581 -0
- package/dist/editor/model/inlinePlain.d.ts +3 -0
- package/dist/editor/model/inlinePlain.js +28 -0
- package/dist/editor/model/inlineSecondPass.d.ts +4 -0
- package/dist/editor/model/inlineSecondPass.js +47 -0
- package/dist/editor/model/line-utils.d.ts +14 -0
- package/dist/editor/model/line-utils.js +38 -0
- package/dist/editor/model/listEditCommands.d.ts +56 -0
- package/dist/editor/model/listEditCommands.js +299 -0
- package/dist/editor/model/nestedContainerTransactions.d.ts +36 -0
- package/dist/editor/model/nestedContainerTransactions.js +336 -0
- package/dist/editor/model/parseMarkdownDocument.d.ts +2 -0
- package/dist/editor/model/parseMarkdownDocument.js +324 -0
- package/dist/editor/model/quoteEditCommands.d.ts +39 -0
- package/dist/editor/model/quoteEditCommands.js +323 -0
- package/dist/editor/model/reconcileBlockIds.d.ts +9 -0
- package/dist/editor/model/reconcileBlockIds.js +297 -0
- package/dist/editor/model/reparseOptions.d.ts +12 -0
- package/dist/editor/model/reparseOptions.js +1 -0
- package/dist/editor/model/resolveEnterPlainSnapshot.d.ts +6 -0
- package/dist/editor/model/resolveEnterPlainSnapshot.js +23 -0
- package/dist/editor/model/richInlines.d.ts +16 -0
- package/dist/editor/model/richInlines.js +494 -0
- package/dist/editor/model/serializeInlineNodes.d.ts +3 -0
- package/dist/editor/model/serializeInlineNodes.js +45 -0
- package/dist/editor/model/serializeMarkdownDocument.d.ts +30 -0
- package/dist/editor/model/serializeMarkdownDocument.js +150 -0
- package/dist/editor/model/structureParseWarnings.d.ts +10 -0
- package/dist/editor/model/structureParseWarnings.js +60 -0
- package/dist/editor/model/syntheticInlineRanges.d.ts +3 -0
- package/dist/editor/model/syntheticInlineRanges.js +36 -0
- package/dist/editor/model/types.d.ts +185 -0
- package/dist/editor/model/types.js +26 -0
- package/dist/editor/plugins/autolinks/AutolinkRenderer.svelte +20 -0
- package/dist/editor/plugins/autolinks/AutolinkRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/autolinks/index.d.ts +2 -0
- package/dist/editor/plugins/autolinks/index.js +4 -0
- package/dist/editor/plugins/autolinks/parse-autolinks.d.ts +2 -0
- package/dist/editor/plugins/autolinks/parse-autolinks.js +68 -0
- package/dist/editor/plugins/autolinks/types.d.ts +6 -0
- package/dist/editor/plugins/autolinks/types.js +1 -0
- package/dist/editor/plugins/emphasis/EmphasisRenderer.svelte +15 -0
- package/dist/editor/plugins/emphasis/EmphasisRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/emphasis/index.d.ts +2 -0
- package/dist/editor/plugins/emphasis/index.js +4 -0
- package/dist/editor/plugins/emphasis/parse-emphasis.d.ts +2 -0
- package/dist/editor/plugins/emphasis/parse-emphasis.js +188 -0
- package/dist/editor/plugins/emphasis/types.d.ts +24 -0
- package/dist/editor/plugins/emphasis/types.js +1 -0
- package/dist/editor/plugins/escaping/EscapingRenderer.svelte +18 -0
- package/dist/editor/plugins/escaping/EscapingRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/escaping/index.d.ts +2 -0
- package/dist/editor/plugins/escaping/index.js +4 -0
- package/dist/editor/plugins/escaping/parse-escaping.d.ts +6 -0
- package/dist/editor/plugins/escaping/parse-escaping.js +26 -0
- package/dist/editor/plugins/escaping/types.d.ts +10 -0
- package/dist/editor/plugins/escaping/types.js +1 -0
- package/dist/editor/plugins/extended-task-list/ExtendedTaskListRenderer.svelte +25 -0
- package/dist/editor/plugins/extended-task-list/ExtendedTaskListRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/extended-task-list/index.d.ts +2 -0
- package/dist/editor/plugins/extended-task-list/index.js +4 -0
- package/dist/editor/plugins/extended-task-list/parse-extended-task-list.d.ts +2 -0
- package/dist/editor/plugins/extended-task-list/parse-extended-task-list.js +35 -0
- package/dist/editor/plugins/extended-task-list/types.d.ts +6 -0
- package/dist/editor/plugins/extended-task-list/types.js +1 -0
- package/dist/editor/plugins/highlight/HighlightRenderer.svelte +16 -0
- package/dist/editor/plugins/highlight/HighlightRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/highlight/index.d.ts +2 -0
- package/dist/editor/plugins/highlight/index.js +4 -0
- package/dist/editor/plugins/highlight/parse-highlights.d.ts +4 -0
- package/dist/editor/plugins/highlight/parse-highlights.js +49 -0
- package/dist/editor/plugins/highlight/types.d.ts +6 -0
- package/dist/editor/plugins/highlight/types.js +1 -0
- package/dist/editor/plugins/index.d.ts +1 -0
- package/dist/editor/plugins/index.js +1 -0
- package/dist/editor/plugins/links-images/LinksImagesRenderer.svelte +53 -0
- package/dist/editor/plugins/links-images/LinksImagesRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/links-images/index.d.ts +2 -0
- package/dist/editor/plugins/links-images/index.js +4 -0
- package/dist/editor/plugins/links-images/parse-image-layout.d.ts +28 -0
- package/dist/editor/plugins/links-images/parse-image-layout.js +147 -0
- package/dist/editor/plugins/links-images/parse-links-images.d.ts +25 -0
- package/dist/editor/plugins/links-images/parse-links-images.js +236 -0
- package/dist/editor/plugins/links-images/resolve-asset-url.d.ts +5 -0
- package/dist/editor/plugins/links-images/resolve-asset-url.js +21 -0
- package/dist/editor/plugins/links-images/types.d.ts +11 -0
- package/dist/editor/plugins/links-images/types.js +1 -0
- package/dist/editor/plugins/mention/MentionRenderer.svelte +18 -0
- package/dist/editor/plugins/mention/MentionRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/mention/index.d.ts +2 -0
- package/dist/editor/plugins/mention/index.js +4 -0
- package/dist/editor/plugins/mention/parse-mentions.d.ts +2 -0
- package/dist/editor/plugins/mention/parse-mentions.js +54 -0
- package/dist/editor/plugins/mention/types.d.ts +14 -0
- package/dist/editor/plugins/mention/types.js +1 -0
- package/dist/editor/plugins/raw-text/RawTextRenderer.svelte +19 -0
- package/dist/editor/plugins/raw-text/RawTextRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/raw-text/index.d.ts +2 -0
- package/dist/editor/plugins/raw-text/index.js +4 -0
- package/dist/editor/plugins/raw-text/types.d.ts +4 -0
- package/dist/editor/plugins/raw-text/types.js +1 -0
- package/dist/editor/plugins/shared/InlineNodes.svelte +113 -0
- package/dist/editor/plugins/shared/InlineNodes.svelte.d.ts +21 -0
- package/dist/editor/plugins/shared/InlineNodesEdit.svelte +78 -0
- package/dist/editor/plugins/shared/InlineNodesEdit.svelte.d.ts +21 -0
- package/dist/editor/plugins/strikethrough/StrikethroughRenderer.svelte +9 -0
- package/dist/editor/plugins/strikethrough/StrikethroughRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/strikethrough/index.d.ts +2 -0
- package/dist/editor/plugins/strikethrough/index.js +4 -0
- package/dist/editor/plugins/strikethrough/parse-strikethrough.d.ts +3 -0
- package/dist/editor/plugins/strikethrough/parse-strikethrough.js +38 -0
- package/dist/editor/plugins/strikethrough/types.d.ts +4 -0
- package/dist/editor/plugins/strikethrough/types.js +1 -0
- package/dist/editor/plugins/synced-block/SyncedBlockRenderer.svelte +16 -0
- package/dist/editor/plugins/synced-block/SyncedBlockRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/synced-block/index.d.ts +2 -0
- package/dist/editor/plugins/synced-block/index.js +4 -0
- package/dist/editor/plugins/synced-block/parse-synced-blocks.d.ts +2 -0
- package/dist/editor/plugins/synced-block/parse-synced-blocks.js +15 -0
- package/dist/editor/plugins/synced-block/types.d.ts +4 -0
- package/dist/editor/plugins/synced-block/types.js +1 -0
- package/dist/editor/plugins/types.d.ts +19 -0
- package/dist/editor/plugins/types.js +1 -0
- package/dist/editor/plugins/wiki-link/WikiLinkRenderer.svelte +15 -0
- package/dist/editor/plugins/wiki-link/WikiLinkRenderer.svelte.d.ts +21 -0
- package/dist/editor/plugins/wiki-link/index.d.ts +2 -0
- package/dist/editor/plugins/wiki-link/index.js +4 -0
- package/dist/editor/plugins/wiki-link/parse-wiki-links.d.ts +2 -0
- package/dist/editor/plugins/wiki-link/parse-wiki-links.js +30 -0
- package/dist/editor/plugins/wiki-link/types.d.ts +8 -0
- package/dist/editor/plugins/wiki-link/types.js +1 -0
- package/dist/editor/taskCheckboxStates.d.ts +5 -0
- package/dist/editor/taskCheckboxStates.js +28 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +9 -0
- package/dist/styles/index.css +6 -0
- package/package.json +84 -0
|
@@ -0,0 +1,1119 @@
|
|
|
1
|
+
import { applyInlineSecondPass, applyInlineWrap, applyStructuralMarkdownShortcut, applyEditorTransaction, clampSelection, convertHeadingLevel, convertHeadingToParagraph, convertParagraphToHeading, deleteBlockTransaction, documentBlocksToRenderBlocks, duplicateBlockTransaction, EDITOR_HISTORY_LIMIT, findEditorBlockById, findEditorBlockIdAtSourceOffset, mergeWithPreviousBlock, moveBlockDown, moveBlockToIndex as reorderBlockToIndexInDocument, moveBlockUp, parseMarkdownDocument, paragraphBlockToPlainText, paragraphDisplayPlain, reconcileBlockIds, replaceBlockMarkdownSlice, replaceSourceRange, FULL_REPARSE, tryIncrementalReparse, tryRemapDocumentSelectionBlockId, documentSelectionFromSourceOffset, updateBlockPlainText, applyListItemInlineWrapTransaction, applyQuoteParagraphInlineWrapTransaction, deleteListItemTransaction, deleteQuoteParagraphTransaction, duplicateListItemTransaction, duplicateQuoteParagraphTransaction, blockTreeDropTransaction, tabReparentBlockTransaction, listRegionStructMutation, moveListItemSiblingTransaction, moveQuoteParagraphSiblingTransaction, quoteParagraphReorderTransaction, quoteStructMutationTransaction, calloutDocumentStructMutation, deleteCalloutChildTransaction, duplicateCalloutChildTransaction, moveCalloutChildSiblingTransaction, siblingFocusIdForCalloutDelete, siblingFocusIdForListDelete, siblingFocusIdForQuoteDelete, buildEmptyParagraphInsertTransaction, insertEmptyParagraphRelative } from './model';
|
|
2
|
+
import { isDisplayEmptyParagraph, isSoleEmptyParagraphDocument, normalizeEmptySource } from './model/emptyParagraph';
|
|
3
|
+
import { sourceLineAndCharacterCount } from './model/line-utils';
|
|
4
|
+
import { appendTableColumnInDocument, appendTableRowInDocument, commitTableCellInlineDraft, convertBlockToTable, navigateTableCellInDocument } from './block-specs/table/editCommands';
|
|
5
|
+
import { buildEnterCommand } from './model/enterCommands';
|
|
6
|
+
import { ensureCalloutEmptyBodyTransaction } from './model/calloutEditCommands';
|
|
7
|
+
import { findListItemPath, resolveListItem, setListItemBodyPlain } from './model/listEditCommands';
|
|
8
|
+
import { commitBlockquoteBodyInlineDraft, commitBlockquoteParagraphInlineDraft, commitCalloutListItemInlineDraft, commitCalloutOpenerDraft, commitCalloutParagraphInlineDraft, commitHeadingInlineDraft, commitParagraphInlineDraft } from './model/inlineDraftCommit';
|
|
9
|
+
import { cloneInlineNodeDeep } from './model/inlineEditCommands';
|
|
10
|
+
import { findBlockLocation, blockAtSiblingOffset } from './model/blockTree';
|
|
11
|
+
import { serializeListItem } from './block-specs/list/serialize';
|
|
12
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
13
|
+
export class MarkdownEditor {
|
|
14
|
+
#source = $state('');
|
|
15
|
+
#fileName = $state(null);
|
|
16
|
+
#document = $state.raw({ source: '', fileName: null, blocks: [] });
|
|
17
|
+
#blocks = $state.raw([]);
|
|
18
|
+
#isLoading = $state(false);
|
|
19
|
+
#error = $state(null);
|
|
20
|
+
#selection = $state.raw({ anchor: 0, focus: 0 });
|
|
21
|
+
#lastSavedSource = $state('');
|
|
22
|
+
#undoStack = [];
|
|
23
|
+
#redoStack = [];
|
|
24
|
+
/** Block index being edited with coalesced undo; null when not in a plain-text session. */
|
|
25
|
+
#typingSessionBlockIndex = null;
|
|
26
|
+
/** Last plain selection inside a paragraph/heading surface (for inline commands). */
|
|
27
|
+
#inlinePlainFocus = null;
|
|
28
|
+
/** Leaf-block caret/range from editable surfaces that emit document selection. */
|
|
29
|
+
#documentSelection = $state.raw(null);
|
|
30
|
+
/** One-shot focus target after structural Enter/split; cleared once applied. */
|
|
31
|
+
#pendingFocusBlockId = $state.raw(null);
|
|
32
|
+
#pendingFocusTableCell = $state.raw(null);
|
|
33
|
+
#tableCellNavGuard = false;
|
|
34
|
+
/** Suppresses stale blur cleanup while a remounted surface restores focus. */
|
|
35
|
+
#pendingFocusBlurGuardId = null;
|
|
36
|
+
/** Suppress one plain-input commit on this block after Enter (browser may still insert a line break). */
|
|
37
|
+
#plainInputSuppressBlockId = null;
|
|
38
|
+
#reparseDepth = 0;
|
|
39
|
+
#sourceLineCount = $state(0);
|
|
40
|
+
#sourceCharacterCount = $state(0);
|
|
41
|
+
/** Top-level block ids edited this session; drives {@link serializeMarkdownDocumentPreserving}. */
|
|
42
|
+
#dirtyBlockIds = new SvelteSet();
|
|
43
|
+
#readonly = $state(false);
|
|
44
|
+
#suppressSourceNotify = false;
|
|
45
|
+
#sourceChangeListeners = new Set();
|
|
46
|
+
get source() {
|
|
47
|
+
return this.#source;
|
|
48
|
+
}
|
|
49
|
+
set source(value) {
|
|
50
|
+
this.#source = value;
|
|
51
|
+
this.#reparse(value, this.#fileName);
|
|
52
|
+
}
|
|
53
|
+
get fileName() {
|
|
54
|
+
return this.#fileName;
|
|
55
|
+
}
|
|
56
|
+
set fileName(value) {
|
|
57
|
+
this.#fileName = value;
|
|
58
|
+
this.#reparse(this.#source, value);
|
|
59
|
+
}
|
|
60
|
+
get document() {
|
|
61
|
+
return this.#document;
|
|
62
|
+
}
|
|
63
|
+
get blocks() {
|
|
64
|
+
return this.#blocks;
|
|
65
|
+
}
|
|
66
|
+
constructor() {
|
|
67
|
+
this.#applySourceAndSelection(normalizeEmptySource(''), { anchor: 0, focus: 0 });
|
|
68
|
+
}
|
|
69
|
+
get isLoading() {
|
|
70
|
+
return this.#isLoading;
|
|
71
|
+
}
|
|
72
|
+
get error() {
|
|
73
|
+
return this.#error;
|
|
74
|
+
}
|
|
75
|
+
get selection() {
|
|
76
|
+
return this.#selection;
|
|
77
|
+
}
|
|
78
|
+
get documentSelection() {
|
|
79
|
+
return this.#documentSelection;
|
|
80
|
+
}
|
|
81
|
+
get isReparsing() {
|
|
82
|
+
return this.#reparseDepth > 0;
|
|
83
|
+
}
|
|
84
|
+
/** Whether a post-structural focus restore is pending for this block (suppress stale blur cleanup). */
|
|
85
|
+
isPendingFocusTarget(blockId) {
|
|
86
|
+
return this.#pendingFocusBlurGuardId === blockId;
|
|
87
|
+
}
|
|
88
|
+
get sourceLineCount() {
|
|
89
|
+
return this.#sourceLineCount;
|
|
90
|
+
}
|
|
91
|
+
get sourceCharacterCount() {
|
|
92
|
+
return this.#sourceCharacterCount;
|
|
93
|
+
}
|
|
94
|
+
get dirty() {
|
|
95
|
+
return this.#source !== this.#lastSavedSource;
|
|
96
|
+
}
|
|
97
|
+
/** Stable ids of top-level blocks touched by edits (cleared on load, draft restore, undo/redo). Used with `serializeMarkdownDocumentPreserving`. */
|
|
98
|
+
get dirtyBlockIds() {
|
|
99
|
+
return new SvelteSet([...this.#dirtyBlockIds]);
|
|
100
|
+
}
|
|
101
|
+
isBlockDirty(id) {
|
|
102
|
+
return this.#dirtyBlockIds.has(id);
|
|
103
|
+
}
|
|
104
|
+
get readonly() {
|
|
105
|
+
return this.#readonly;
|
|
106
|
+
}
|
|
107
|
+
setReadonly(value) {
|
|
108
|
+
this.#readonly = value;
|
|
109
|
+
}
|
|
110
|
+
get canUndo() {
|
|
111
|
+
return this.#undoStack.length > 0;
|
|
112
|
+
}
|
|
113
|
+
get canRedo() {
|
|
114
|
+
return this.#redoStack.length > 0;
|
|
115
|
+
}
|
|
116
|
+
markSaved() {
|
|
117
|
+
this.#lastSavedSource = this.#source;
|
|
118
|
+
}
|
|
119
|
+
/** Replace document source — used by controlled embedders and demo file load. */
|
|
120
|
+
setSource(source, opts) {
|
|
121
|
+
const { fileName, resetHistory = true, syncBaseline = true, selection = { anchor: 0, focus: 0 } } = opts ?? {};
|
|
122
|
+
this.#error = null;
|
|
123
|
+
if (resetHistory) {
|
|
124
|
+
this.#undoStack = [];
|
|
125
|
+
this.#redoStack = [];
|
|
126
|
+
this.#typingSessionBlockIndex = null;
|
|
127
|
+
this.#dirtyBlockIds.clear();
|
|
128
|
+
}
|
|
129
|
+
if (fileName !== undefined) {
|
|
130
|
+
this.#fileName = fileName;
|
|
131
|
+
}
|
|
132
|
+
if (syncBaseline) {
|
|
133
|
+
this.#lastSavedSource = source;
|
|
134
|
+
}
|
|
135
|
+
this.#suppressSourceNotify = true;
|
|
136
|
+
try {
|
|
137
|
+
this.#applySourceAndSelection(normalizeEmptySource(source), selection);
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
this.#suppressSourceNotify = false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Subscribe to source mutations (not fired during silent {@link setSource}). Returns unsubscribe. */
|
|
144
|
+
onSourceChange(listener) {
|
|
145
|
+
this.#sourceChangeListeners.add(listener);
|
|
146
|
+
return () => {
|
|
147
|
+
this.#sourceChangeListeners.delete(listener);
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
commitSourceEdit(result, dirtyBlockIndices, focusAfter) {
|
|
151
|
+
if (this.#readonly)
|
|
152
|
+
return false;
|
|
153
|
+
if (!result.ok) {
|
|
154
|
+
this.#error = result.error;
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
this.#error = null;
|
|
158
|
+
this.#undoStack.push(this.#captureHistorySnapshot());
|
|
159
|
+
if (this.#undoStack.length > EDITOR_HISTORY_LIMIT) {
|
|
160
|
+
this.#undoStack.shift();
|
|
161
|
+
}
|
|
162
|
+
this.#redoStack = [];
|
|
163
|
+
this.#typingSessionBlockIndex = null;
|
|
164
|
+
if (dirtyBlockIndices?.length) {
|
|
165
|
+
this.#markDirtyByBlockIndices(dirtyBlockIndices);
|
|
166
|
+
}
|
|
167
|
+
this.#applySourceAndSelection(result.source, result.selection, { focusAfter });
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
/** Apply a built transaction through the same undo/history path as {@link commitSourceEdit}. */
|
|
171
|
+
commitTransaction(transaction, dirtyBlockIndices, focusAfter) {
|
|
172
|
+
const applied = applyEditorTransaction(this.#source, transaction);
|
|
173
|
+
return this.commitSourceEdit(applied, dirtyBlockIndices, focusAfter);
|
|
174
|
+
}
|
|
175
|
+
undo() {
|
|
176
|
+
if (this.#readonly)
|
|
177
|
+
return false;
|
|
178
|
+
const snap = this.#undoStack.pop();
|
|
179
|
+
if (!snap)
|
|
180
|
+
return false;
|
|
181
|
+
this.#redoStack.push(this.#captureHistorySnapshot());
|
|
182
|
+
this.#error = null;
|
|
183
|
+
this.#typingSessionBlockIndex = null;
|
|
184
|
+
this.#dirtyBlockIds.clear();
|
|
185
|
+
this.#restoreHistorySnapshot(snap);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
redo() {
|
|
189
|
+
if (this.#readonly)
|
|
190
|
+
return false;
|
|
191
|
+
const snap = this.#redoStack.pop();
|
|
192
|
+
if (!snap)
|
|
193
|
+
return false;
|
|
194
|
+
this.#undoStack.push(this.#captureHistorySnapshot());
|
|
195
|
+
this.#error = null;
|
|
196
|
+
this.#typingSessionBlockIndex = null;
|
|
197
|
+
this.#dirtyBlockIds.clear();
|
|
198
|
+
this.#restoreHistorySnapshot(snap);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
/** One undo step per focused plain-text session (paragraph / heading body). */
|
|
202
|
+
beginPlainEditSession(blockIndex) {
|
|
203
|
+
if (this.#readonly)
|
|
204
|
+
return;
|
|
205
|
+
if (this.#typingSessionBlockIndex === blockIndex)
|
|
206
|
+
return;
|
|
207
|
+
this.#typingSessionBlockIndex = blockIndex;
|
|
208
|
+
this.#undoStack.push(this.#captureHistorySnapshot());
|
|
209
|
+
if (this.#undoStack.length > EDITOR_HISTORY_LIMIT) {
|
|
210
|
+
this.#undoStack.shift();
|
|
211
|
+
}
|
|
212
|
+
this.#redoStack = [];
|
|
213
|
+
}
|
|
214
|
+
commitPlainEditSession() {
|
|
215
|
+
this.#typingSessionBlockIndex = null;
|
|
216
|
+
}
|
|
217
|
+
silentUpdateBlockPlain(blockIndex, plainText, kind, selectionPlainOffset) {
|
|
218
|
+
const r = updateBlockPlainText(this.#source, this.#document, blockIndex, plainText, kind, selectionPlainOffset);
|
|
219
|
+
if (!r.ok) {
|
|
220
|
+
this.#error = r.error;
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
this.#markDirtyByBlockIndices([blockIndex]);
|
|
224
|
+
this.#error = null;
|
|
225
|
+
this.#source = r.source;
|
|
226
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
227
|
+
this.#reparse(r.source, this.#fileName);
|
|
228
|
+
this.#emitSourceChange();
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
commitParagraphInlineDraftAt(blockIndex, inlines, plainCaret) {
|
|
232
|
+
const r = commitParagraphInlineDraft(this.#source, this.#document, blockIndex, inlines, plainCaret);
|
|
233
|
+
if (!r.ok) {
|
|
234
|
+
this.#error = r.error;
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
this.#markDirtyByBlockIndices([blockIndex]);
|
|
238
|
+
this.#error = null;
|
|
239
|
+
this.#source = r.source;
|
|
240
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
241
|
+
this.#reparse(r.source, this.#fileName, {
|
|
242
|
+
kind: 'inlineDraftCommit',
|
|
243
|
+
blockIndex,
|
|
244
|
+
expectedType: 'paragraph'
|
|
245
|
+
});
|
|
246
|
+
this.#emitSourceChange();
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
commitHeadingInlineDraftAt(blockIndex, inlines, plainCaret) {
|
|
250
|
+
const r = commitHeadingInlineDraft(this.#source, this.#document, blockIndex, inlines, plainCaret);
|
|
251
|
+
if (!r.ok) {
|
|
252
|
+
this.#error = r.error;
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
this.#markDirtyByBlockIndices([blockIndex]);
|
|
256
|
+
this.#error = null;
|
|
257
|
+
this.#source = r.source;
|
|
258
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
259
|
+
this.#reparse(r.source, this.#fileName, {
|
|
260
|
+
kind: 'inlineDraftCommit',
|
|
261
|
+
blockIndex,
|
|
262
|
+
expectedType: 'heading'
|
|
263
|
+
});
|
|
264
|
+
this.#emitSourceChange();
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
commitTableCellInlineDraftAt(blockIndex, row, col, inlines, plainCaret) {
|
|
268
|
+
const block = this.#document.blocks[blockIndex];
|
|
269
|
+
const blockId = block?.id;
|
|
270
|
+
const r = commitTableCellInlineDraft(this.#source, this.#document, blockIndex, row, col, inlines, plainCaret);
|
|
271
|
+
if (!r.ok) {
|
|
272
|
+
this.#error = r.error;
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
this.#markDirtyByBlockIndices([blockIndex]);
|
|
276
|
+
this.#error = null;
|
|
277
|
+
this.#source = r.source;
|
|
278
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
279
|
+
if (blockId) {
|
|
280
|
+
this.#documentSelection = {
|
|
281
|
+
blockId,
|
|
282
|
+
tableCell: { row, col },
|
|
283
|
+
plain: { start: plainCaret, end: plainCaret }
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
this.#reparse(r.source, this.#fileName, {
|
|
287
|
+
kind: 'inlineDraftCommit',
|
|
288
|
+
blockIndex,
|
|
289
|
+
expectedType: 'table'
|
|
290
|
+
});
|
|
291
|
+
this.#emitSourceChange();
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
navigateTableCellAt(blockIndex, from, to, inlines, plainCaret) {
|
|
295
|
+
const block = this.#document.blocks[blockIndex];
|
|
296
|
+
const blockId = block?.id;
|
|
297
|
+
this.#tableCellNavGuard = true;
|
|
298
|
+
this.commitPlainEditSession();
|
|
299
|
+
const r = navigateTableCellInDocument(this.#source, this.#document, blockIndex, from, to, inlines, plainCaret);
|
|
300
|
+
if (!r.ok) {
|
|
301
|
+
this.#tableCellNavGuard = false;
|
|
302
|
+
this.#error = r.error;
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
if (!('focusCell' in r) || !('focusPlain' in r))
|
|
306
|
+
return false;
|
|
307
|
+
const ok = this.commitSourceEdit(r, [blockIndex], blockId
|
|
308
|
+
? {
|
|
309
|
+
mode: 'blockId',
|
|
310
|
+
blockId,
|
|
311
|
+
tableCell: r.focusCell,
|
|
312
|
+
plain: { start: r.focusPlain, end: r.focusPlain }
|
|
313
|
+
}
|
|
314
|
+
: undefined);
|
|
315
|
+
queueMicrotask(() => {
|
|
316
|
+
this.#tableCellNavGuard = false;
|
|
317
|
+
});
|
|
318
|
+
return ok;
|
|
319
|
+
}
|
|
320
|
+
appendTableRowAt(blockIndex) {
|
|
321
|
+
this.commitPlainEditSession();
|
|
322
|
+
const block = this.#document.blocks[blockIndex];
|
|
323
|
+
const blockId = block?.id;
|
|
324
|
+
const r = appendTableRowInDocument(this.#source, this.#document, blockIndex);
|
|
325
|
+
if (!r.ok) {
|
|
326
|
+
this.#error = r.error;
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
if (!('focusCell' in r))
|
|
330
|
+
return false;
|
|
331
|
+
return this.commitSourceEdit(r, [blockIndex], blockId
|
|
332
|
+
? {
|
|
333
|
+
mode: 'blockId',
|
|
334
|
+
blockId,
|
|
335
|
+
tableCell: r.focusCell,
|
|
336
|
+
plain: { start: 0, end: 0 }
|
|
337
|
+
}
|
|
338
|
+
: undefined);
|
|
339
|
+
}
|
|
340
|
+
appendTableColumnAt(blockIndex) {
|
|
341
|
+
this.commitPlainEditSession();
|
|
342
|
+
const block = this.#document.blocks[blockIndex];
|
|
343
|
+
const blockId = block?.id;
|
|
344
|
+
const r = appendTableColumnInDocument(this.#source, this.#document, blockIndex);
|
|
345
|
+
if (!r.ok) {
|
|
346
|
+
this.#error = r.error;
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
if (!('focusCell' in r))
|
|
350
|
+
return false;
|
|
351
|
+
return this.commitSourceEdit(r, [blockIndex], blockId
|
|
352
|
+
? {
|
|
353
|
+
mode: 'blockId',
|
|
354
|
+
blockId,
|
|
355
|
+
tableCell: r.focusCell,
|
|
356
|
+
plain: { start: 0, end: 0 }
|
|
357
|
+
}
|
|
358
|
+
: undefined);
|
|
359
|
+
}
|
|
360
|
+
convertBlockToTableAt(blockIndex) {
|
|
361
|
+
this.commitPlainEditSession();
|
|
362
|
+
const blockId = this.#document.blocks[blockIndex]?.id;
|
|
363
|
+
const r = convertBlockToTable(this.#source, this.#document, blockIndex);
|
|
364
|
+
if (!r.ok) {
|
|
365
|
+
this.#error = r.error;
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
return this.commitSourceEdit(r, [blockIndex], blockId
|
|
369
|
+
? {
|
|
370
|
+
mode: 'blockId',
|
|
371
|
+
blockId,
|
|
372
|
+
tableCell: { row: -1, col: 0 },
|
|
373
|
+
plain: { start: 0, end: 0 }
|
|
374
|
+
}
|
|
375
|
+
: undefined);
|
|
376
|
+
}
|
|
377
|
+
commitListItemInlineDraftAt(blockIndex, itemId, inlines, _plainCaret) {
|
|
378
|
+
void _plainCaret;
|
|
379
|
+
const loc = findBlockLocation(this.#document.blocks, itemId);
|
|
380
|
+
if (!loc || loc.block.type !== 'listItem')
|
|
381
|
+
return false;
|
|
382
|
+
loc.block.inlines = inlines.map(cloneInlineNodeDeep);
|
|
383
|
+
if (loc.parent === null) {
|
|
384
|
+
return this.silentReplaceBlockMarkdown(blockIndex, serializeListItem(loc.block, this.#source));
|
|
385
|
+
}
|
|
386
|
+
const top = this.#document.blocks[blockIndex];
|
|
387
|
+
if (top?.type === 'callout') {
|
|
388
|
+
return this.applyCalloutStructMutation(blockIndex, itemId, (blocks) => {
|
|
389
|
+
const inner = findBlockLocation(blocks, itemId);
|
|
390
|
+
if (!inner || inner.block.type !== 'listItem')
|
|
391
|
+
return null;
|
|
392
|
+
inner.block.inlines = inlines.map(cloneInlineNodeDeep);
|
|
393
|
+
return blocks;
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return this.applyListStructMutation(blockIndex, itemId, (blocks) => {
|
|
397
|
+
const inner = findBlockLocation(blocks, itemId);
|
|
398
|
+
if (!inner || inner.block.type !== 'listItem')
|
|
399
|
+
return null;
|
|
400
|
+
inner.block.inlines = inlines.map(cloneInlineNodeDeep);
|
|
401
|
+
return blocks;
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
commitBlockquoteBodyInlineDraftAt(topBlockIndex, quoteBlockId, inlines, _plainCaret) {
|
|
405
|
+
void _plainCaret;
|
|
406
|
+
const top = this.#document.blocks[topBlockIndex];
|
|
407
|
+
if (!top || top.type !== 'blockquote')
|
|
408
|
+
return false;
|
|
409
|
+
const r = commitBlockquoteBodyInlineDraft(this.#source, top, quoteBlockId, inlines);
|
|
410
|
+
if (!r.ok) {
|
|
411
|
+
this.#error = r.error;
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
this.#markDirtyByBlockIndices([topBlockIndex]);
|
|
415
|
+
this.#error = null;
|
|
416
|
+
this.#source = r.source;
|
|
417
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
418
|
+
this.#reparse(r.source, this.#fileName);
|
|
419
|
+
this.#emitSourceChange();
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
commitBlockquoteParagraphInlineDraftAt(topBlockIndex, paragraphId, inlines, _plainCaret) {
|
|
423
|
+
void _plainCaret;
|
|
424
|
+
const top = this.#document.blocks[topBlockIndex];
|
|
425
|
+
if (!top || top.type !== 'blockquote')
|
|
426
|
+
return false;
|
|
427
|
+
const r = commitBlockquoteParagraphInlineDraft(this.#source, top, paragraphId, inlines);
|
|
428
|
+
if (!r.ok) {
|
|
429
|
+
this.#error = r.error;
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
this.#markDirtyByBlockIndices([topBlockIndex]);
|
|
433
|
+
this.#error = null;
|
|
434
|
+
this.#source = r.source;
|
|
435
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
436
|
+
this.#reparse(r.source, this.#fileName);
|
|
437
|
+
this.#emitSourceChange();
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
commitCalloutOpenerDraftAt(topBlockIndex, calloutId, data) {
|
|
441
|
+
const top = this.#document.blocks[topBlockIndex];
|
|
442
|
+
if (!top || top.type !== 'callout')
|
|
443
|
+
return false;
|
|
444
|
+
const r = commitCalloutOpenerDraft(this.#source, top, calloutId, data);
|
|
445
|
+
if (!r.ok) {
|
|
446
|
+
this.#error = r.error;
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
this.#markDirtyByBlockIndices([topBlockIndex]);
|
|
450
|
+
this.#error = null;
|
|
451
|
+
this.#source = r.source;
|
|
452
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
453
|
+
this.#reparse(r.source, this.#fileName);
|
|
454
|
+
this.#emitSourceChange();
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
commitCalloutParagraphInlineDraftAt(topBlockIndex, paragraphId, inlines, _plainCaret) {
|
|
458
|
+
void _plainCaret;
|
|
459
|
+
const top = this.#document.blocks[topBlockIndex];
|
|
460
|
+
if (!top || top.type !== 'callout')
|
|
461
|
+
return false;
|
|
462
|
+
const r = commitCalloutParagraphInlineDraft(this.#source, top, paragraphId, inlines);
|
|
463
|
+
if (!r.ok) {
|
|
464
|
+
this.#error = r.error;
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
this.#markDirtyByBlockIndices([topBlockIndex]);
|
|
468
|
+
this.#error = null;
|
|
469
|
+
this.#source = r.source;
|
|
470
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
471
|
+
this.#reparse(r.source, this.#fileName);
|
|
472
|
+
this.#emitSourceChange();
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
commitCalloutListItemInlineDraftAt(topBlockIndex, itemId, inlines, _plainCaret) {
|
|
476
|
+
void _plainCaret;
|
|
477
|
+
const top = this.#document.blocks[topBlockIndex];
|
|
478
|
+
if (!top || top.type !== 'callout')
|
|
479
|
+
return false;
|
|
480
|
+
const r = commitCalloutListItemInlineDraft(this.#source, top, itemId, inlines);
|
|
481
|
+
if (!r.ok) {
|
|
482
|
+
this.#error = r.error;
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
this.#markDirtyByBlockIndices([topBlockIndex]);
|
|
486
|
+
this.#error = null;
|
|
487
|
+
this.#source = r.source;
|
|
488
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
489
|
+
this.#reparse(r.source, this.#fileName);
|
|
490
|
+
this.#emitSourceChange();
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
/** Ensure an imported opener-only callout has a real empty body line in source. */
|
|
494
|
+
ensureCalloutEmptyBodyAt(blockIndex) {
|
|
495
|
+
const top = this.#document.blocks[blockIndex];
|
|
496
|
+
if (!top || top.type !== 'callout')
|
|
497
|
+
return false;
|
|
498
|
+
if ((top.children?.length ?? 0) > 0)
|
|
499
|
+
return true;
|
|
500
|
+
const built = ensureCalloutEmptyBodyTransaction(this.#source, this.#document, blockIndex);
|
|
501
|
+
if (!built.ok)
|
|
502
|
+
return false;
|
|
503
|
+
return this.commitTransaction(built.transaction, [blockIndex], {
|
|
504
|
+
mode: 'sourceOffset',
|
|
505
|
+
offset: built.transaction.selection.anchor
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
updateBlockPlain(blockIndex, plainText, kind, selectionPlainOffset) {
|
|
509
|
+
return this.commitSourceEdit(updateBlockPlainText(this.#source, this.#document, blockIndex, plainText, kind, selectionPlainOffset), [blockIndex]);
|
|
510
|
+
}
|
|
511
|
+
/** @deprecated Use {@link tryStructuralMarkdownShortcut}. */
|
|
512
|
+
maybeApplyParagraphShortcut(blockIndex, plainText) {
|
|
513
|
+
this.tryStructuralMarkdownShortcut(blockIndex, plainText);
|
|
514
|
+
}
|
|
515
|
+
/** Sole public Enter API — dispatches by block type, commits via transactions, sets post-split focus. */
|
|
516
|
+
enterAt({ blockId, plainOffset, plainText }) {
|
|
517
|
+
this.commitPlainEditSession();
|
|
518
|
+
this.#plainInputSuppressBlockId = blockId;
|
|
519
|
+
const outcome = buildEnterCommand(this.#source, this.#document, blockId, plainOffset, plainText);
|
|
520
|
+
if (!outcome.ok) {
|
|
521
|
+
this.#plainInputSuppressBlockId = null;
|
|
522
|
+
this.#error = outcome.error;
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
this.#error = null;
|
|
526
|
+
const ok = this.commitTransaction(outcome.transaction, [outcome.dirtyTopLevelIndex], outcome.focus);
|
|
527
|
+
queueMicrotask(() => {
|
|
528
|
+
if (this.#plainInputSuppressBlockId === blockId) {
|
|
529
|
+
this.#plainInputSuppressBlockId = null;
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
return ok;
|
|
533
|
+
}
|
|
534
|
+
shouldSuppressPlainInputForBlock(blockId) {
|
|
535
|
+
return this.#plainInputSuppressBlockId === blockId;
|
|
536
|
+
}
|
|
537
|
+
shouldSkipTableCellBlurCommit() {
|
|
538
|
+
return this.#tableCellNavGuard;
|
|
539
|
+
}
|
|
540
|
+
/** Set post-command caret: resolves to {@link DocumentSelection} + one-shot pending focus. */
|
|
541
|
+
setFocusOutcome(target) {
|
|
542
|
+
this.#applyFocusOutcome(target);
|
|
543
|
+
}
|
|
544
|
+
mergeWithPrevious(blockIndex) {
|
|
545
|
+
const b = this.#document.blocks[blockIndex];
|
|
546
|
+
if (isSoleEmptyParagraphDocument(this.#document) &&
|
|
547
|
+
b?.type === 'paragraph' &&
|
|
548
|
+
isDisplayEmptyParagraph(b)) {
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
this.commitPlainEditSession();
|
|
552
|
+
const r = mergeWithPreviousBlock(this.#source, this.#document, blockIndex);
|
|
553
|
+
if (!r.ok)
|
|
554
|
+
return false;
|
|
555
|
+
return this.commitSourceEdit(r, [blockIndex - 1, blockIndex], r.focusAfter);
|
|
556
|
+
}
|
|
557
|
+
/** Line-start `#` / `-` / `1.` shortcut when the pattern is complete (Space, Enter, or blur). */
|
|
558
|
+
tryStructuralMarkdownShortcut(blockIndex, plainText) {
|
|
559
|
+
this.commitPlainEditSession();
|
|
560
|
+
const r = applyStructuralMarkdownShortcut(this.#source, this.#document, blockIndex, plainText);
|
|
561
|
+
if (!r.ok)
|
|
562
|
+
return false;
|
|
563
|
+
return this.commitSourceEdit(r, [blockIndex], r.focusAfter);
|
|
564
|
+
}
|
|
565
|
+
insertEmptyParagraph(blockIndex, after) {
|
|
566
|
+
this.commitPlainEditSession();
|
|
567
|
+
if (this.#document.blocks.length === 0) {
|
|
568
|
+
const edit = insertEmptyParagraphRelative(this.#source, this.#document, 0, after);
|
|
569
|
+
return this.commitSourceEdit(edit, []);
|
|
570
|
+
}
|
|
571
|
+
const edit = insertEmptyParagraphRelative(this.#source, this.#document, blockIndex, after);
|
|
572
|
+
return this.commitSourceEdit(edit, [blockIndex]);
|
|
573
|
+
}
|
|
574
|
+
deleteBlockAt(blockIndex) {
|
|
575
|
+
const b = this.#document.blocks[blockIndex];
|
|
576
|
+
if (isSoleEmptyParagraphDocument(this.#document) &&
|
|
577
|
+
b?.type === 'paragraph' &&
|
|
578
|
+
isDisplayEmptyParagraph(b)) {
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
this.commitPlainEditSession();
|
|
582
|
+
const built = deleteBlockTransaction(this.#source, this.#document, blockIndex);
|
|
583
|
+
if (!built.ok) {
|
|
584
|
+
this.#error = built.error;
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
return this.commitTransaction(built.transaction, [blockIndex]);
|
|
588
|
+
}
|
|
589
|
+
/** Replace one block’s source slice (code fences, lists, blockquotes). */
|
|
590
|
+
replaceBlockMarkdown(blockIndex, markdown) {
|
|
591
|
+
this.commitPlainEditSession();
|
|
592
|
+
const r = replaceBlockMarkdownSlice(this.#source, this.#document, blockIndex, markdown);
|
|
593
|
+
if (!r.ok)
|
|
594
|
+
return false;
|
|
595
|
+
return this.commitSourceEdit(r, [blockIndex]);
|
|
596
|
+
}
|
|
597
|
+
/** Coalesced list/blockquote/code edits within {@link beginPlainEditSession} (no undo frame per keystroke). */
|
|
598
|
+
silentReplaceBlockMarkdown(blockIndex, markdown) {
|
|
599
|
+
const r = replaceBlockMarkdownSlice(this.#source, this.#document, blockIndex, markdown);
|
|
600
|
+
if (!r.ok) {
|
|
601
|
+
this.#error = r.error;
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
this.#markDirtyByBlockIndices([blockIndex]);
|
|
605
|
+
this.#error = null;
|
|
606
|
+
this.#source = r.source;
|
|
607
|
+
this.#selection = clampSelection(r.selection, r.source.length);
|
|
608
|
+
this.#reparse(r.source, this.#fileName);
|
|
609
|
+
this.#emitSourceChange();
|
|
610
|
+
return true;
|
|
611
|
+
}
|
|
612
|
+
applyInlineWrapAt(blockIndex, plainStart, plainEnd, kind, linkHref) {
|
|
613
|
+
this.commitPlainEditSession();
|
|
614
|
+
const r = applyInlineWrap(this.#source, this.#document, blockIndex, plainStart, plainEnd, kind, linkHref);
|
|
615
|
+
if (!r.ok) {
|
|
616
|
+
this.#error = r.error;
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
this.#error = null;
|
|
620
|
+
return this.commitSourceEdit(r, [blockIndex]);
|
|
621
|
+
}
|
|
622
|
+
duplicateBlockAt(blockIndex) {
|
|
623
|
+
this.commitPlainEditSession();
|
|
624
|
+
const built = duplicateBlockTransaction(this.#source, this.#document, blockIndex);
|
|
625
|
+
if (!built.ok) {
|
|
626
|
+
this.#error = built.error;
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
this.#error = null;
|
|
630
|
+
return this.commitTransaction(built.transaction, [blockIndex]);
|
|
631
|
+
}
|
|
632
|
+
moveBlockUpAt(blockIndex) {
|
|
633
|
+
this.commitPlainEditSession();
|
|
634
|
+
const r = moveBlockUp(this.#source, this.#document, blockIndex);
|
|
635
|
+
if (!r.ok)
|
|
636
|
+
return false;
|
|
637
|
+
return this.commitSourceEdit(r, [blockIndex - 1, blockIndex]);
|
|
638
|
+
}
|
|
639
|
+
moveBlockDownAt(blockIndex) {
|
|
640
|
+
this.commitPlainEditSession();
|
|
641
|
+
const r = moveBlockDown(this.#source, this.#document, blockIndex);
|
|
642
|
+
if (!r.ok)
|
|
643
|
+
return false;
|
|
644
|
+
return this.commitSourceEdit(r, [blockIndex, blockIndex + 1]);
|
|
645
|
+
}
|
|
646
|
+
moveBlockToIndex(fromIndex, toIndex) {
|
|
647
|
+
this.commitPlainEditSession();
|
|
648
|
+
const lo = Math.min(fromIndex, toIndex);
|
|
649
|
+
const hi = Math.max(fromIndex, toIndex);
|
|
650
|
+
const affected = Array.from({ length: hi - lo + 1 }, (_, k) => lo + k);
|
|
651
|
+
const r = reorderBlockToIndexInDocument(this.#source, this.#document, fromIndex, toIndex);
|
|
652
|
+
if (!r.ok)
|
|
653
|
+
return false;
|
|
654
|
+
return this.commitSourceEdit(r, affected);
|
|
655
|
+
}
|
|
656
|
+
convertParagraphToHeadingAt(blockIndex, level) {
|
|
657
|
+
this.commitPlainEditSession();
|
|
658
|
+
const block = this.#document.blocks[blockIndex];
|
|
659
|
+
const r = convertParagraphToHeading(this.#source, this.#document, blockIndex, level);
|
|
660
|
+
if (!r.ok)
|
|
661
|
+
return false;
|
|
662
|
+
const plainLength = block?.type === 'paragraph'
|
|
663
|
+
? paragraphBlockToPlainText(block.data).trimEnd().length
|
|
664
|
+
: 0;
|
|
665
|
+
return this.commitSourceEdit(r, [blockIndex], {
|
|
666
|
+
mode: 'sourceOffset',
|
|
667
|
+
offset: block?.sourceRange.start ?? 0,
|
|
668
|
+
plain: { start: plainLength, end: plainLength }
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
convertParagraphToBulletListAt(blockIndex) {
|
|
672
|
+
this.commitPlainEditSession();
|
|
673
|
+
const block = this.#document.blocks[blockIndex];
|
|
674
|
+
if (!block || block.type !== 'paragraph')
|
|
675
|
+
return false;
|
|
676
|
+
const plain = paragraphBlockToPlainText(block.data).trimEnd();
|
|
677
|
+
const markdown = `- ${plain}`;
|
|
678
|
+
const r = replaceBlockMarkdownSlice(this.#source, this.#document, blockIndex, markdown);
|
|
679
|
+
if (!r.ok)
|
|
680
|
+
return false;
|
|
681
|
+
return this.commitSourceEdit(r, [blockIndex], {
|
|
682
|
+
mode: 'sourceOffset',
|
|
683
|
+
offset: block.sourceRange.start,
|
|
684
|
+
plain: { start: plain.length, end: plain.length }
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
convertHeadingToParagraphAt(blockIndex) {
|
|
688
|
+
this.commitPlainEditSession();
|
|
689
|
+
const r = convertHeadingToParagraph(this.#source, this.#document, blockIndex);
|
|
690
|
+
if (!r.ok)
|
|
691
|
+
return false;
|
|
692
|
+
return this.commitSourceEdit(r, [blockIndex]);
|
|
693
|
+
}
|
|
694
|
+
convertHeadingLevelAt(blockIndex, level) {
|
|
695
|
+
this.commitPlainEditSession();
|
|
696
|
+
const r = convertHeadingLevel(this.#source, this.#document, blockIndex, level);
|
|
697
|
+
if (!r.ok)
|
|
698
|
+
return false;
|
|
699
|
+
return this.commitSourceEdit(r, [blockIndex]);
|
|
700
|
+
}
|
|
701
|
+
setSelection(sel) {
|
|
702
|
+
this.#selection = clampSelection(sel, this.#source.length);
|
|
703
|
+
}
|
|
704
|
+
setDocumentSelection(sel) {
|
|
705
|
+
this.#documentSelection = sel;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Caret/selection updates from a focused surface (selectionchange, keyup, input).
|
|
709
|
+
* Ignored while reparsing or another block owns {@link #pendingFocusBlockId}.
|
|
710
|
+
*/
|
|
711
|
+
emitDocumentSelection(sel) {
|
|
712
|
+
if (this.#reparseDepth > 0)
|
|
713
|
+
return;
|
|
714
|
+
if (!this.#selectionAllowedForPending(sel))
|
|
715
|
+
return;
|
|
716
|
+
this.setDocumentSelection(sel);
|
|
717
|
+
}
|
|
718
|
+
/** Focus moved to this surface; ignored while reparsing or another block owns post-split focus. */
|
|
719
|
+
claimDocumentSelection(sel) {
|
|
720
|
+
if (this.#reparseDepth > 0)
|
|
721
|
+
return;
|
|
722
|
+
if (!this.#selectionAllowedForPending(sel))
|
|
723
|
+
return;
|
|
724
|
+
this.setDocumentSelection(sel);
|
|
725
|
+
}
|
|
726
|
+
/** Whether this block (and optional table cell) should receive one-shot programmatic focus. */
|
|
727
|
+
takePendingFocusForBlock(blockId, tableCell, surfaceBlockType) {
|
|
728
|
+
if (this.#pendingFocusBlockId !== blockId)
|
|
729
|
+
return false;
|
|
730
|
+
const pendingCell = this.#pendingFocusTableCell;
|
|
731
|
+
if (pendingCell) {
|
|
732
|
+
if (!tableCell || pendingCell.row !== tableCell.row || pendingCell.col !== tableCell.col) {
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else if (tableCell) {
|
|
737
|
+
return false;
|
|
738
|
+
}
|
|
739
|
+
if (surfaceBlockType) {
|
|
740
|
+
const block = findEditorBlockById(this.#document.blocks, blockId);
|
|
741
|
+
if (!block || block.type !== surfaceBlockType)
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
this.#pendingFocusBlockId = null;
|
|
745
|
+
this.#pendingFocusTableCell = null;
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
clearDocumentSelection(blockId) {
|
|
749
|
+
if (this.#pendingFocusBlurGuardId === blockId)
|
|
750
|
+
return;
|
|
751
|
+
if (this.#documentSelection?.blockId === blockId) {
|
|
752
|
+
this.#documentSelection = null;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
registerInlinePlainFocus(blockIndex, start, end) {
|
|
756
|
+
this.#inlinePlainFocus = { blockIndex, start, end };
|
|
757
|
+
}
|
|
758
|
+
clearInlinePlainFocus(blockIndex) {
|
|
759
|
+
if (this.#inlinePlainFocus?.blockIndex === blockIndex)
|
|
760
|
+
this.#inlinePlainFocus = null;
|
|
761
|
+
}
|
|
762
|
+
getInlinePlainFocus(blockIndex) {
|
|
763
|
+
const block = this.#document.blocks[blockIndex];
|
|
764
|
+
const docSel = this.#documentSelection;
|
|
765
|
+
if (block && docSel?.plain && docSel.blockId === block.id) {
|
|
766
|
+
return { start: docSel.plain.start, end: docSel.plain.end };
|
|
767
|
+
}
|
|
768
|
+
const f = this.#inlinePlainFocus;
|
|
769
|
+
if (!f || f.blockIndex !== blockIndex)
|
|
770
|
+
return null;
|
|
771
|
+
return { start: f.start, end: f.end };
|
|
772
|
+
}
|
|
773
|
+
getDocumentSelectionPlain(blockId) {
|
|
774
|
+
const sel = this.#documentSelection;
|
|
775
|
+
if (!sel || sel.blockId !== blockId || !sel.plain)
|
|
776
|
+
return null;
|
|
777
|
+
return { start: sel.plain.start, end: sel.plain.end };
|
|
778
|
+
}
|
|
779
|
+
#commitNestedStructural(built, blockIndex, opts = {}) {
|
|
780
|
+
if (!built.ok) {
|
|
781
|
+
this.#error = built.error;
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
784
|
+
const prevPlain = opts.preserveBlockId && this.#documentSelection?.blockId === opts.preserveBlockId
|
|
785
|
+
? this.#documentSelection.plain
|
|
786
|
+
: undefined;
|
|
787
|
+
this.commitPlainEditSession();
|
|
788
|
+
this.#error = null;
|
|
789
|
+
const focusAfter = this.#focusOutcomeForNestedStructural(opts, prevPlain);
|
|
790
|
+
return this.commitTransaction(built.transaction, [blockIndex], focusAfter);
|
|
791
|
+
}
|
|
792
|
+
moveListItemSiblingAt(blockIndex, itemId, direction) {
|
|
793
|
+
return this.#commitNestedStructural(moveListItemSiblingTransaction(this.#source, this.#document, blockIndex, itemId, direction), blockIndex, { preserveBlockId: itemId });
|
|
794
|
+
}
|
|
795
|
+
blockTreeDropAt(draggedId, targetId, placement) {
|
|
796
|
+
const loc = findBlockLocation(this.#document.blocks, draggedId);
|
|
797
|
+
const blockIndex = loc?.topLevelIndex ?? 0;
|
|
798
|
+
return this.#commitNestedStructural(blockTreeDropTransaction(this.#source, this.#document, draggedId, targetId, placement), blockIndex, { preserveBlockId: draggedId });
|
|
799
|
+
}
|
|
800
|
+
applyBlockTreeTabReparent(blockId, shift, focusPlain) {
|
|
801
|
+
const loc = findBlockLocation(this.#document.blocks, blockId);
|
|
802
|
+
if (!loc)
|
|
803
|
+
return false;
|
|
804
|
+
const built = tabReparentBlockTransaction(this.#source, this.#document, blockId, shift);
|
|
805
|
+
if (!built.ok)
|
|
806
|
+
return false;
|
|
807
|
+
return this.#commitNestedStructural(built, loc.topLevelIndex, {
|
|
808
|
+
focusBlockId: blockId,
|
|
809
|
+
focusPlain: focusPlain ?? { start: 0, end: 0 }
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
listItemTreeDropAt(blockIndex, draggedId, targetId, placement) {
|
|
813
|
+
return this.blockTreeDropAt(draggedId, targetId, placement);
|
|
814
|
+
}
|
|
815
|
+
deleteListItemAt(blockIndex, itemId) {
|
|
816
|
+
const focusId = siblingFocusIdForListDelete(this.#document.blocks, itemId);
|
|
817
|
+
return this.#commitNestedStructural(deleteListItemTransaction(this.#source, this.#document, blockIndex, itemId, focusId), blockIndex, focusId ? { focusBlockId: focusId, focusPlain: { start: 0, end: 0 } } : {});
|
|
818
|
+
}
|
|
819
|
+
applyListStructMutation(blockIndex, itemId, mutate, opts) {
|
|
820
|
+
const caretBlockId = opts?.focusBlockId ?? opts?.preserveBlockId ?? itemId;
|
|
821
|
+
return this.#commitNestedStructural(listRegionStructMutation(this.#source, this.#document, itemId, mutate, `list-struct:${itemId}`, caretBlockId), blockIndex, opts?.focusBlockId
|
|
822
|
+
? {
|
|
823
|
+
focusBlockId: opts.focusBlockId,
|
|
824
|
+
focusPlain: opts.focusPlain ?? { start: 0, end: 0 }
|
|
825
|
+
}
|
|
826
|
+
: { preserveBlockId: opts?.preserveBlockId ?? itemId });
|
|
827
|
+
}
|
|
828
|
+
applyQuoteStructMutation(blockIndex, quoteBlockId, mutate, opts) {
|
|
829
|
+
const caretBlockId = opts?.focusBlockId ?? quoteBlockId;
|
|
830
|
+
return this.#commitNestedStructural(quoteStructMutationTransaction(this.#source, this.#document, blockIndex, quoteBlockId, mutate, `quote-struct:${quoteBlockId}`, caretBlockId), blockIndex, opts?.focusBlockId
|
|
831
|
+
? { focusBlockId: opts.focusBlockId, focusPlain: { start: 0, end: 0 } }
|
|
832
|
+
: { preserveBlockId: quoteBlockId });
|
|
833
|
+
}
|
|
834
|
+
updateListItemBodyAt(blockIndex, itemId, plain) {
|
|
835
|
+
const loc = findBlockLocation(this.#document.blocks, itemId);
|
|
836
|
+
if (!loc || loc.block.type !== 'listItem')
|
|
837
|
+
return false;
|
|
838
|
+
if (loc.parent === null) {
|
|
839
|
+
setListItemBodyPlain(loc.block, plain);
|
|
840
|
+
return this.silentReplaceBlockMarkdown(blockIndex, serializeListItem(loc.block, this.#source));
|
|
841
|
+
}
|
|
842
|
+
return this.applyListStructMutation(blockIndex, itemId, (blocks) => {
|
|
843
|
+
const inner = findBlockLocation(blocks, itemId);
|
|
844
|
+
if (!inner || inner.block.type !== 'listItem')
|
|
845
|
+
return null;
|
|
846
|
+
setListItemBodyPlain(inner.block, plain);
|
|
847
|
+
return blocks;
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
duplicateListItemAt(blockIndex, itemId) {
|
|
851
|
+
const built = duplicateListItemTransaction(this.#source, this.#document, blockIndex, itemId);
|
|
852
|
+
if (!built.ok) {
|
|
853
|
+
this.#error = built.error;
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
this.commitPlainEditSession();
|
|
857
|
+
this.#error = null;
|
|
858
|
+
const ok = this.commitTransaction(built.transaction, [blockIndex]);
|
|
859
|
+
if (!ok)
|
|
860
|
+
return false;
|
|
861
|
+
const path = findListItemPath(this.#document.blocks, itemId);
|
|
862
|
+
if (path) {
|
|
863
|
+
const nav = resolveListItem(this.#document.blocks, path);
|
|
864
|
+
const dup = nav?.siblings[nav.itemIndex + 1];
|
|
865
|
+
if (dup) {
|
|
866
|
+
this.setFocusOutcome({ mode: 'blockId', blockId: dup.id });
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
return true;
|
|
870
|
+
}
|
|
871
|
+
moveQuoteParagraphSiblingAt(blockIndex, paragraphId, direction) {
|
|
872
|
+
return this.#commitNestedStructural(moveQuoteParagraphSiblingTransaction(this.#source, this.#document, blockIndex, paragraphId, direction), blockIndex, { preserveBlockId: paragraphId });
|
|
873
|
+
}
|
|
874
|
+
quoteParagraphReorderAt(blockIndex, quotePath, fromIndex, toIndex, paragraphId) {
|
|
875
|
+
return this.#commitNestedStructural(quoteParagraphReorderTransaction(this.#source, this.#document, blockIndex, quotePath, fromIndex, toIndex, paragraphId), blockIndex, { preserveBlockId: paragraphId });
|
|
876
|
+
}
|
|
877
|
+
deleteQuoteParagraphAt(blockIndex, paragraphId) {
|
|
878
|
+
const block = this.#document.blocks[blockIndex];
|
|
879
|
+
const focusId = block?.type === 'blockquote' ? siblingFocusIdForQuoteDelete(block, paragraphId) : undefined;
|
|
880
|
+
return this.#commitNestedStructural(deleteQuoteParagraphTransaction(this.#source, this.#document, blockIndex, paragraphId, focusId), blockIndex, focusId ? { focusBlockId: focusId, focusPlain: { start: 0, end: 0 } } : {});
|
|
881
|
+
}
|
|
882
|
+
duplicateQuoteParagraphAt(blockIndex, paragraphId) {
|
|
883
|
+
const built = duplicateQuoteParagraphTransaction(this.#source, this.#document, blockIndex, paragraphId);
|
|
884
|
+
if (!built.ok) {
|
|
885
|
+
this.#error = built.error;
|
|
886
|
+
return false;
|
|
887
|
+
}
|
|
888
|
+
this.commitPlainEditSession();
|
|
889
|
+
this.#error = null;
|
|
890
|
+
const ok = this.commitTransaction(built.transaction, [blockIndex]);
|
|
891
|
+
if (!ok)
|
|
892
|
+
return false;
|
|
893
|
+
return true;
|
|
894
|
+
}
|
|
895
|
+
moveCalloutChildSiblingAt(blockIndex, childId, direction) {
|
|
896
|
+
return this.#commitNestedStructural(moveCalloutChildSiblingTransaction(this.#source, this.#document, blockIndex, childId, direction), blockIndex, { preserveBlockId: childId });
|
|
897
|
+
}
|
|
898
|
+
calloutBodyTreeDropAt(blockIndex, draggedId, targetId, placement) {
|
|
899
|
+
return this.blockTreeDropAt(draggedId, targetId, placement);
|
|
900
|
+
}
|
|
901
|
+
deleteCalloutChildAt(blockIndex, childId) {
|
|
902
|
+
const block = this.#document.blocks[blockIndex];
|
|
903
|
+
const focusId = block?.type === 'callout' ? siblingFocusIdForCalloutDelete(block, childId) : undefined;
|
|
904
|
+
return this.#commitNestedStructural(deleteCalloutChildTransaction(this.#source, this.#document, blockIndex, childId, focusId), blockIndex, focusId ? { focusBlockId: focusId, focusPlain: { start: 0, end: 0 } } : {});
|
|
905
|
+
}
|
|
906
|
+
duplicateCalloutChildAt(blockIndex, childId) {
|
|
907
|
+
const built = duplicateCalloutChildTransaction(this.#source, this.#document, blockIndex, childId);
|
|
908
|
+
if (!built.ok) {
|
|
909
|
+
this.#error = built.error;
|
|
910
|
+
return false;
|
|
911
|
+
}
|
|
912
|
+
this.commitPlainEditSession();
|
|
913
|
+
this.#error = null;
|
|
914
|
+
return this.commitTransaction(built.transaction, [blockIndex]);
|
|
915
|
+
}
|
|
916
|
+
applyCalloutStructMutation(blockIndex, anchorBlockId, mutate, opts) {
|
|
917
|
+
const caretBlockId = opts?.focusBlockId ?? opts?.preserveBlockId ?? anchorBlockId;
|
|
918
|
+
return this.#commitNestedStructural(calloutDocumentStructMutation(this.#source, this.#document, blockIndex, anchorBlockId, mutate, `callout-struct:${anchorBlockId}`, caretBlockId), blockIndex, opts?.focusBlockId
|
|
919
|
+
? {
|
|
920
|
+
focusBlockId: opts.focusBlockId,
|
|
921
|
+
focusPlain: opts.focusPlain ?? { start: 0, end: 0 }
|
|
922
|
+
}
|
|
923
|
+
: { preserveBlockId: opts?.preserveBlockId ?? anchorBlockId });
|
|
924
|
+
}
|
|
925
|
+
applyInlineWrapOnNestedRow(blockIndex, rowBlockId, plainStart, plainEnd, kind, linkHref) {
|
|
926
|
+
this.commitPlainEditSession();
|
|
927
|
+
const block = this.#document.blocks[blockIndex];
|
|
928
|
+
if (!block)
|
|
929
|
+
return false;
|
|
930
|
+
const built = block.type === 'listItem'
|
|
931
|
+
? applyListItemInlineWrapTransaction(this.#source, this.#document, blockIndex, rowBlockId, plainStart, plainEnd, kind, linkHref)
|
|
932
|
+
: block.type === 'blockquote'
|
|
933
|
+
? applyQuoteParagraphInlineWrapTransaction(this.#source, this.#document, blockIndex, rowBlockId, plainStart, plainEnd, kind, linkHref)
|
|
934
|
+
: { ok: false, error: 'Unsupported container block.' };
|
|
935
|
+
return this.#commitNestedStructural(built, blockIndex, {
|
|
936
|
+
preserveBlockId: rowBlockId,
|
|
937
|
+
focusPlain: { start: plainEnd, end: plainEnd }
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
#captureHistorySnapshot() {
|
|
941
|
+
const docSel = this.#documentSelection;
|
|
942
|
+
return {
|
|
943
|
+
source: this.#source,
|
|
944
|
+
selection: { ...this.#selection },
|
|
945
|
+
documentSelection: docSel
|
|
946
|
+
? {
|
|
947
|
+
blockId: docSel.blockId,
|
|
948
|
+
plain: docSel.plain ? { ...docSel.plain } : undefined,
|
|
949
|
+
tableCell: docSel.tableCell ? { ...docSel.tableCell } : undefined
|
|
950
|
+
}
|
|
951
|
+
: null
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
#restoreHistorySnapshot(snap) {
|
|
955
|
+
const selection = clampSelection(snap.selection, snap.source.length);
|
|
956
|
+
const focusAfter = snap.documentSelection
|
|
957
|
+
? {
|
|
958
|
+
mode: 'blockId',
|
|
959
|
+
blockId: snap.documentSelection.blockId,
|
|
960
|
+
plain: snap.documentSelection.plain ?? { start: 0, end: 0 },
|
|
961
|
+
tableCell: snap.documentSelection.tableCell
|
|
962
|
+
}
|
|
963
|
+
: undefined;
|
|
964
|
+
this.#applySourceAndSelection(snap.source, selection, { focusAfter });
|
|
965
|
+
if (snap.documentSelection)
|
|
966
|
+
return;
|
|
967
|
+
const derived = documentSelectionFromSourceOffset(this.#document.blocks, snap.source, selection);
|
|
968
|
+
if (derived) {
|
|
969
|
+
this.setFocusOutcome({
|
|
970
|
+
mode: 'blockId',
|
|
971
|
+
blockId: derived.blockId,
|
|
972
|
+
plain: derived.plain ?? { start: 0, end: 0 }
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
#focusOutcomeForNestedStructural(opts, prevPlain) {
|
|
977
|
+
if (opts.focusBlockId) {
|
|
978
|
+
return {
|
|
979
|
+
mode: 'blockId',
|
|
980
|
+
blockId: opts.focusBlockId,
|
|
981
|
+
plain: opts.focusPlain ?? { start: 0, end: 0 }
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
if (opts.preserveBlockId && findEditorBlockById(this.#document.blocks, opts.preserveBlockId)) {
|
|
985
|
+
const plain = opts.focusPlain ?? prevPlain;
|
|
986
|
+
if (plain) {
|
|
987
|
+
return { mode: 'blockId', blockId: opts.preserveBlockId, plain };
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
return undefined;
|
|
991
|
+
}
|
|
992
|
+
#armPostStructuralFocus(blockId, plain, tableCell) {
|
|
993
|
+
this.#documentSelection = { blockId, plain, tableCell };
|
|
994
|
+
this.#pendingFocusBlockId = blockId;
|
|
995
|
+
this.#pendingFocusTableCell = tableCell ?? null;
|
|
996
|
+
this.#pendingFocusBlurGuardId = blockId;
|
|
997
|
+
queueMicrotask(() => {
|
|
998
|
+
if (this.#pendingFocusBlurGuardId === blockId) {
|
|
999
|
+
this.#pendingFocusBlurGuardId = null;
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
#applyFocusOutcome(target) {
|
|
1004
|
+
const plain = target.plain ?? { start: 0, end: 0 };
|
|
1005
|
+
if (target.mode === 'blockId') {
|
|
1006
|
+
this.#armPostStructuralFocus(target.blockId, plain, target.tableCell);
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
if (target.mode === 'siblingOffset') {
|
|
1010
|
+
const block = blockAtSiblingOffset(this.#document.blocks, target.anchorBlockId, target.offset);
|
|
1011
|
+
if (block) {
|
|
1012
|
+
this.#armPostStructuralFocus(block.id, plain);
|
|
1013
|
+
}
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
const targetId = findEditorBlockIdAtSourceOffset(this.#document.blocks, target.offset);
|
|
1017
|
+
if (targetId) {
|
|
1018
|
+
this.#armPostStructuralFocus(targetId, plain);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
#emitSourceChange() {
|
|
1022
|
+
if (this.#suppressSourceNotify)
|
|
1023
|
+
return;
|
|
1024
|
+
for (const listener of this.#sourceChangeListeners) {
|
|
1025
|
+
listener(this.#source);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
#applySourceAndSelection(source, selection, opts) {
|
|
1029
|
+
const normalized = normalizeEmptySource(source);
|
|
1030
|
+
this.#source = normalized;
|
|
1031
|
+
this.#selection = clampSelection(selection, normalized.length);
|
|
1032
|
+
if (opts?.focusAfter?.mode === 'blockId') {
|
|
1033
|
+
this.#pendingFocusBlurGuardId = opts.focusAfter.blockId;
|
|
1034
|
+
}
|
|
1035
|
+
this.#reparse(normalized, this.#fileName);
|
|
1036
|
+
if (opts?.focusAfter) {
|
|
1037
|
+
this.#applyFocusOutcome(opts.focusAfter);
|
|
1038
|
+
}
|
|
1039
|
+
this.#emitSourceChange();
|
|
1040
|
+
}
|
|
1041
|
+
#reparse(source, fileName, opts = FULL_REPARSE) {
|
|
1042
|
+
this.#reparseDepth++;
|
|
1043
|
+
try {
|
|
1044
|
+
const prevBlocks = this.#document.blocks;
|
|
1045
|
+
const prevReal = prevBlocks.filter((b) => !b.sourceRange.synthetic);
|
|
1046
|
+
let nextReal;
|
|
1047
|
+
let docSource = normalizeEmptySource(source);
|
|
1048
|
+
let docFileName = fileName;
|
|
1049
|
+
if (opts.kind === 'inlineDraftCommit') {
|
|
1050
|
+
const incremental = tryIncrementalReparse(docSource, fileName, this.#document, opts.blockIndex, opts.expectedType);
|
|
1051
|
+
if (incremental.ok) {
|
|
1052
|
+
nextReal = incremental.document.blocks.filter((b) => !b.sourceRange.synthetic);
|
|
1053
|
+
docSource = normalizeEmptySource(incremental.document.source);
|
|
1054
|
+
docFileName = incremental.document.fileName;
|
|
1055
|
+
}
|
|
1056
|
+
else {
|
|
1057
|
+
const docParsed = applyInlineSecondPass(parseMarkdownDocument(docSource, fileName));
|
|
1058
|
+
nextReal = reconcileBlockIds(prevReal, docParsed.blocks);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
const docParsed = applyInlineSecondPass(parseMarkdownDocument(docSource, fileName));
|
|
1063
|
+
nextReal = reconcileBlockIds(prevReal, docParsed.blocks);
|
|
1064
|
+
}
|
|
1065
|
+
this.#document = { source: docSource, fileName: docFileName, blocks: nextReal };
|
|
1066
|
+
this.#blocks = documentBlocksToRenderBlocks(nextReal);
|
|
1067
|
+
this.#pruneDirtyBlockIds(nextReal);
|
|
1068
|
+
this.#restoreDocumentSelection(prevBlocks, nextReal);
|
|
1069
|
+
const stats = sourceLineAndCharacterCount(docSource);
|
|
1070
|
+
this.#sourceLineCount = stats.lineCount;
|
|
1071
|
+
this.#sourceCharacterCount = stats.characterCount;
|
|
1072
|
+
}
|
|
1073
|
+
finally {
|
|
1074
|
+
this.#reparseDepth--;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
#restoreDocumentSelection(prevBlocks, nextBlocks) {
|
|
1078
|
+
const sel = this.#documentSelection;
|
|
1079
|
+
if (!sel)
|
|
1080
|
+
return;
|
|
1081
|
+
if (findEditorBlockById(nextBlocks, sel.blockId))
|
|
1082
|
+
return;
|
|
1083
|
+
const remapped = tryRemapDocumentSelectionBlockId(prevBlocks, nextBlocks, sel.blockId);
|
|
1084
|
+
if (remapped) {
|
|
1085
|
+
this.#documentSelection = { ...sel, blockId: remapped };
|
|
1086
|
+
}
|
|
1087
|
+
else {
|
|
1088
|
+
this.#documentSelection = null;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
#selectionAllowedForPending(sel) {
|
|
1092
|
+
if (!this.#pendingFocusBlockId)
|
|
1093
|
+
return true;
|
|
1094
|
+
if (this.#pendingFocusBlockId !== sel.blockId)
|
|
1095
|
+
return false;
|
|
1096
|
+
const pendingCell = this.#pendingFocusTableCell;
|
|
1097
|
+
if (!pendingCell)
|
|
1098
|
+
return true;
|
|
1099
|
+
if (!sel.tableCell)
|
|
1100
|
+
return false;
|
|
1101
|
+
return pendingCell.row === sel.tableCell.row && pendingCell.col === sel.tableCell.col;
|
|
1102
|
+
}
|
|
1103
|
+
#markDirtyByBlockIndices(indices) {
|
|
1104
|
+
const blocks = this.#document.blocks;
|
|
1105
|
+
for (const i of indices) {
|
|
1106
|
+
const b = blocks[i];
|
|
1107
|
+
if (b && b.sourceRange.start >= 0 && !b.sourceRange.synthetic) {
|
|
1108
|
+
this.#dirtyBlockIds.add(b.id);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
#pruneDirtyBlockIds(merged) {
|
|
1113
|
+
const valid = new SvelteSet(merged.map((b) => b.id));
|
|
1114
|
+
for (const id of this.#dirtyBlockIds) {
|
|
1115
|
+
if (!valid.has(id))
|
|
1116
|
+
this.#dirtyBlockIds.delete(id);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|