@voithos-labs/aragonite 0.10.2 → 0.10.4
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 +6 -21
- package/THIRD-PARTY-NOTICES.md +25 -0
- package/dist/a11y-strings.d.ts +19 -0
- package/dist/a11y-strings.js +19 -0
- package/dist/action-contracts.d.ts +7 -1
- package/dist/ambient/ambient-dom.js +5 -1
- package/dist/block-component.d.ts +14 -0
- package/dist/components/BlockDragHandle.svelte +37 -24
- package/dist/components/BlockHost.svelte +18 -11
- package/dist/components/Editor.svelte +434 -198
- package/dist/components/Editor.svelte.d.ts +1 -1
- package/dist/components/SelectionOverlay.svelte +25 -17
- package/dist/components/SelectionOverlay.svelte.d.ts +1 -1
- package/dist/components/TailInsert.svelte +107 -0
- package/dist/components/TailInsert.svelte.d.ts +17 -0
- package/dist/components/block-content-selector.d.ts +6 -2
- package/dist/components/block-content-selector.js +6 -2
- package/dist/components/blocks/ThematicBreakBlock.svelte +19 -6
- package/dist/components/blocks/ThematicBreakBlock.svelte.d.ts +1 -0
- package/dist/components/blocks/code/CodeBlock.svelte +211 -30
- package/dist/components/blocks/code/CodeBlockRail.svelte +704 -0
- package/dist/components/blocks/code/CodeBlockRail.svelte.d.ts +26 -0
- package/dist/components/blocks/code/code-bootstrap.js +16 -0
- package/dist/components/blocks/code/code-context-actions.d.ts +1 -0
- package/dist/components/blocks/code/code-context-actions.js +24 -0
- package/dist/components/blocks/code/code-fence-exit.d.ts +15 -0
- package/dist/components/blocks/code/code-fence-exit.js +26 -0
- package/dist/components/blocks/code/code-languages.d.ts +6 -0
- package/dist/components/blocks/code/code-languages.js +22 -3
- package/dist/components/blocks/code/code-renderer.js +11 -0
- package/dist/components/blocks/directive/DirectiveContainerBlock.svelte +1 -1
- package/dist/components/blocks/editable-leaf.d.ts +37 -6
- package/dist/components/blocks/editable-leaf.js +248 -30
- package/dist/components/blocks/editable-surface.d.ts +9 -0
- package/dist/components/blocks/editable-surface.js +22 -3
- package/dist/components/blocks/list/ListBlock.svelte +1 -0
- package/dist/components/blocks/list/ListItemBlock.svelte +14 -5
- package/dist/components/blocks/list/ListItemBlock.svelte.d.ts +2 -0
- package/dist/components/blocks/list/task-checkbox.d.ts +2 -0
- package/dist/components/blocks/list/task-checkbox.js +11 -2
- package/dist/components/blocks/surface-wiring.svelte.d.ts +4 -0
- package/dist/components/blocks/surface-wiring.svelte.js +8 -1
- package/dist/components/blocks/table/TableActionMenu.svelte +210 -86
- package/dist/components/blocks/table/TableActionMenu.svelte.d.ts +5 -0
- package/dist/components/blocks/table/TableBlock.svelte +205 -186
- package/dist/components/blocks/table/TableBlock.svelte.d.ts +1 -0
- package/dist/components/blocks/table/TableCellBlock.svelte +87 -22
- package/dist/components/blocks/table/TableRowBlock.svelte +4 -18
- package/dist/components/blocks/table/TableRowBlock.svelte.d.ts +0 -5
- package/dist/components/blocks/table/cell-clipboard.d.ts +10 -0
- package/dist/components/blocks/table/cell-clipboard.js +34 -1
- package/dist/components/blocks/table/cell-keydown-plan.d.ts +1 -1
- package/dist/components/blocks/table/cell-keydown-plan.js +3 -1
- package/dist/components/blocks/table/table-cell-paste.js +2 -1
- package/dist/components/blocks/table/table-menu-model.d.ts +35 -8
- package/dist/components/blocks/table/table-menu-model.js +36 -17
- package/dist/components/blocks/text/TextEditableBlock.svelte +58 -11
- package/dist/components/blocks/text/click-snap-guard.d.ts +3 -0
- package/dist/components/blocks/text/click-snap-guard.js +8 -0
- package/dist/components/blocks/text/delimiter-autopair.d.ts +71 -0
- package/dist/components/blocks/text/delimiter-autopair.js +216 -0
- package/dist/components/blocks/text/edge-policy-dispatch.d.ts +4 -0
- package/dist/components/blocks/text/edge-policy-dispatch.js +89 -20
- package/dist/components/blocks/text/live-selection-edit.d.ts +5 -5
- package/dist/components/blocks/text/live-selection-edit.js +37 -7
- package/dist/components/blocks/text/text-clipboard.js +2 -2
- package/dist/components/blocks/text/text-keydown.d.ts +7 -1
- package/dist/components/blocks/text/text-keydown.js +11 -1
- package/dist/components/blocks/text/text-render.d.ts +1 -1
- package/dist/components/blocks/text/text-render.js +3 -1
- package/dist/components/blocks/text/widget-interaction.d.ts +3 -0
- package/dist/components/blocks/text/widget-interaction.js +181 -37
- package/dist/components/drag-handle.d.ts +41 -0
- package/dist/components/drag-handle.js +134 -0
- package/dist/components/editor-root-focus.d.ts +19 -0
- package/dist/components/editor-root-focus.js +67 -0
- package/dist/components/editor-root-geometry.d.ts +39 -0
- package/dist/components/editor-root-geometry.js +91 -0
- package/dist/components/editor-root-keydown.d.ts +1 -1
- package/dist/components/editor-root-keydown.js +12 -3
- package/dist/components/editor-root-listeners.d.ts +3 -6
- package/dist/components/editor-root-listeners.js +3 -24
- package/dist/components/editor-root-mode-flip.d.ts +36 -0
- package/dist/components/editor-root-mode-flip.js +92 -0
- package/dist/components/image/ImageOverlayHost.svelte +14 -6
- package/dist/components/image/ImageProperties.svelte +512 -70
- package/dist/components/image/ImageProperties.svelte.d.ts +6 -1
- package/dist/components/image/ImageResizeHandles.svelte +67 -34
- package/dist/components/image/image-crop.d.ts +39 -0
- package/dist/components/image/image-crop.js +74 -0
- package/dist/components/image/image-edit-commit.d.ts +1 -0
- package/dist/components/image/image-edit-commit.js +21 -5
- package/dist/components/image/image-source-bytes.js +10 -3
- package/dist/components/image/image-widget-editing.js +1 -0
- package/dist/components/image/widget-dom.js +5 -1
- package/dist/components/link-card/link-card-commit.js +1 -1
- package/dist/components/lrd-map-gate.js +1 -1
- package/dist/components/menu/BlockMenu.svelte +315 -0
- package/dist/components/menu/BlockMenu.svelte.d.ts +34 -0
- package/dist/components/menu/MenuIcon.svelte +153 -0
- package/dist/components/menu/MenuIcon.svelte.d.ts +51 -0
- package/dist/components/menu/SelectionToolbar.svelte +385 -0
- package/dist/components/menu/SelectionToolbar.svelte.d.ts +16 -0
- package/dist/components/menu/clipboard-actions.d.ts +12 -0
- package/dist/components/menu/clipboard-actions.js +42 -0
- package/dist/components/menu/default-context-actions.d.ts +15 -0
- package/dist/components/menu/default-context-actions.js +76 -0
- package/dist/components/menu/flyout-placement.d.ts +6 -0
- package/dist/components/menu/flyout-placement.js +25 -0
- package/dist/core/inline/format-toggle.d.ts +12 -4
- package/dist/core/inline/format-toggle.js +94 -40
- package/dist/core/inline/image-dimensions.d.ts +3 -0
- package/dist/core/inline/image-dimensions.js +46 -10
- package/dist/core/inline/inline-widgets.d.ts +19 -0
- package/dist/core/inline/inline-widgets.js +5 -0
- package/dist/core/inline/scan/brackets.js +1 -0
- package/dist/core/inline/scan/plugin-syntax.d.ts +8 -0
- package/dist/core/inline/scan/plugin-syntax.js +15 -1
- package/dist/core/inline/transparency.js +3 -3
- package/dist/core/inline-render.d.ts +6 -0
- package/dist/core/inline-render.js +32 -0
- package/dist/core/nodes.d.ts +14 -0
- package/dist/cursor/edge-affinity.js +2 -1
- package/dist/cursor/height-oracle.d.ts +2 -3
- package/dist/cursor/height-oracle.js +0 -1
- package/dist/cursor/overlay-remeasure.js +8 -0
- package/dist/cursor/reveal-source.js +7 -2
- package/dist/cursor/scroll-hold.d.ts +10 -0
- package/dist/cursor/scroll-hold.js +22 -0
- package/dist/cursor/scrollport.d.ts +9 -0
- package/dist/cursor/scrollport.js +30 -1
- package/dist/cursor/visual-lines.d.ts +5 -4
- package/dist/cursor/visual-lines.js +56 -11
- package/dist/cursor/widget-edge-snap.d.ts +28 -0
- package/dist/cursor/widget-edge-snap.js +38 -0
- package/dist/cursor/widget-offset.d.ts +9 -0
- package/dist/cursor/widget-offset.js +71 -4
- package/dist/debug/interaction-trace.d.ts +4 -0
- package/dist/debug/interaction-trace.js +15 -0
- package/dist/decorations/decoration-state.svelte.js +1 -1
- package/dist/decorations/reserved-attrs.js +1 -0
- package/dist/editor-actions/ancestry-folds.d.ts +2 -2
- package/dist/editor-actions/ancestry-folds.js +1 -1
- package/dist/editor-actions/block-edit-scope.js +1 -1
- package/dist/editor-actions/commit/text-batch.d.ts +3 -2
- package/dist/editor-actions/commit/text-batch.js +1 -1
- package/dist/editor-actions/commit/undo-controller.js +4 -2
- package/dist/editor-actions/container-edit.js +2 -1
- package/dist/editor-actions/enter-completion.d.ts +2 -0
- package/dist/editor-actions/enter-completion.js +23 -2
- package/dist/editor-actions/focus/focus-dispatch.js +7 -4
- package/dist/editor-actions/focus/focus-landing.d.ts +10 -1
- package/dist/editor-actions/focus/focus-landing.js +20 -6
- package/dist/editor-actions/inline-range-commit.js +1 -1
- package/dist/editor-actions/plugin/container.d.ts +7 -0
- package/dist/editor-actions/plugin/container.js +3 -1
- package/dist/editor-actions/reorder-action.js +19 -10
- package/dist/editor-actions/reorder-drag.js +29 -1
- package/dist/editor-actions/replacement-focus.d.ts +1 -1
- package/dist/editor-actions/replacement-focus.js +1 -1
- package/dist/editor-actions/search-replace.js +1 -1
- package/dist/editor-actions/table-context.d.ts +4 -1
- package/dist/editor-actions/table-context.js +57 -1
- package/dist/editor-events.d.ts +3 -0
- package/dist/editor-keys.d.ts +33 -0
- package/dist/editor-props.d.ts +24 -12
- package/dist/index.d.ts +1 -1
- package/dist/plugin.d.ts +7 -0
- package/dist/plugin.js +16 -0
- package/dist/plugins/latex/BlockMath.svelte +264 -29
- package/dist/plugins/latex/BlockMath.svelte.d.ts +2 -0
- package/dist/plugins/latex/index.d.ts +2 -1
- package/dist/plugins/latex/latex-kind.js +60 -10
- package/dist/plugins/latex/math-completion.js +4 -1
- package/dist/plugins/latex/math-layout.d.ts +15 -0
- package/dist/plugins/latex/math-layout.js +13 -0
- package/dist/plugins/latex/math-source.d.ts +19 -0
- package/dist/plugins/latex/math-source.js +103 -0
- package/dist/plugins/latex/register.d.ts +11 -2
- package/dist/plugins/latex/register.js +3 -1
- package/dist/plugins/latex/renderer.d.ts +3 -3
- package/dist/plugins/latex/renderer.js +13 -6
- package/dist/plugins/mermaid/MermaidBlock.svelte +19 -9
- package/dist/plugins/parrot/ParrotBlock.svelte +3 -1
- package/dist/reactivity/list-windowing.svelte.d.ts +8 -8
- package/dist/reactivity/list-windowing.svelte.js +75 -30
- package/dist/schema/block-completions.d.ts +8 -0
- package/dist/schema/block-completions.js +11 -0
- package/dist/schema/commands.d.ts +9 -5
- package/dist/schema/commands.js +12 -7
- package/dist/schema/context-actions.d.ts +31 -0
- package/dist/schema/context-actions.js +23 -0
- package/dist/schema/fenced-code-raw.js +31 -1
- package/dist/schema/operations.d.ts +8 -1
- package/dist/schema/reserved-chords.js +37 -4
- package/dist/schema/table-cell-raw.d.ts +1 -1
- package/dist/schema/table-cell-raw.js +1 -1
- package/dist/selection/block-hit-test.js +3 -2
- package/dist/selection/char-endpoint-snap.js +1 -1
- package/dist/selection/clipboard-text.js +6 -1
- package/dist/selection/covered-block.d.ts +10 -0
- package/dist/selection/covered-block.js +24 -0
- package/dist/selection/cross-block/dispatch.d.ts +3 -0
- package/dist/selection/cross-block/dispatch.js +13 -1
- package/dist/selection/cross-block/format-range.d.ts +1 -1
- package/dist/selection/cross-block/format-range.js +4 -15
- package/dist/selection/cross-block/format-toggle.js +1 -1
- package/dist/selection/cross-block/keydown.js +3 -29
- package/dist/selection/cross-block/ops.js +1 -1
- package/dist/selection/cross-block/paste.js +31 -35
- package/dist/selection/cross-block/type-replace.d.ts +3 -2
- package/dist/selection/cross-block/type-replace.js +52 -13
- package/dist/selection/dead-space-caret.d.ts +13 -0
- package/dist/selection/dead-space-caret.js +57 -1
- package/dist/selection/drag-pointer.d.ts +26 -2
- package/dist/selection/drag-pointer.js +103 -2
- package/dist/selection/gap-caret.js +1 -1
- package/dist/selection/keyboard-extend.d.ts +3 -2
- package/dist/selection/keyboard-extend.js +4 -3
- package/dist/selection/multi-click.d.ts +42 -0
- package/dist/selection/multi-click.js +203 -0
- package/dist/selection/native-bridge.d.ts +3 -0
- package/dist/selection/native-bridge.js +31 -2
- package/dist/selection/path-lookup.d.ts +10 -2
- package/dist/selection/path-lookup.js +11 -4
- package/dist/selection/pointer-gesture.d.ts +9 -0
- package/dist/selection/pointer-gesture.js +11 -0
- package/dist/selection/primitives.d.ts +7 -0
- package/dist/selection/primitives.js +19 -1
- package/dist/selection/range-delete-ceremony.js +4 -2
- package/dist/selection/range-delete-chrome.js +2 -1
- package/dist/selection/range-delete-table-coverage.js +2 -1
- package/dist/selection/range-delete-table.js +3 -2
- package/dist/selection/range-delete.d.ts +4 -0
- package/dist/selection/range-delete.js +31 -3
- package/dist/selection/selection-drop.d.ts +34 -0
- package/dist/selection/selection-drop.js +253 -0
- package/dist/selection/selection-restore.js +1 -1
- package/dist/selection/selection-state.svelte.d.ts +6 -0
- package/dist/selection/selection-state.svelte.js +36 -1
- package/dist/selection/table-endpoint-snap.js +1 -1
- package/dist/selection/table-rect-extend.js +1 -1
- package/dist/styles/editor-theme.css +75 -31
- package/dist/styles/editor.css +268 -18
- package/dist/testing/container-conformance.js +2 -2
- package/dist/testing/inline-conformance.js +2 -1
- package/dist/tree-operations/blockquote.js +1 -1
- package/dist/tree-operations/chain-rebuild.d.ts +63 -0
- package/dist/tree-operations/chain-rebuild.js +142 -0
- package/dist/tree-operations/children.d.ts +1 -1
- package/dist/tree-operations/children.js +1 -1
- package/dist/tree-operations/cleanup.js +1 -1
- package/dist/tree-operations/content-write.d.ts +50 -0
- package/dist/tree-operations/content-write.js +263 -0
- package/dist/tree-operations/index.d.ts +8 -3
- package/dist/tree-operations/index.js +6 -2
- package/dist/tree-operations/list/exit-replacement.js +1 -1
- package/dist/tree-operations/list/unwrap-merge.js +3 -3
- package/dist/tree-operations/node-ops.d.ts +17 -234
- package/dist/tree-operations/node-ops.js +47 -1113
- package/dist/tree-operations/node-primitives.d.ts +75 -0
- package/dist/tree-operations/node-primitives.js +117 -0
- package/dist/tree-operations/paste/apply.js +1 -1
- package/dist/tree-operations/paste/body-write.d.ts +1 -1
- package/dist/tree-operations/paste/body-write.js +2 -2
- package/dist/tree-operations/paste/container-match.js +4 -2
- package/dist/tree-operations/paste/dispatch.js +2 -1
- package/dist/tree-operations/paste/find-enclosing-list.js +1 -1
- package/dist/tree-operations/paste/focus-target.d.ts +1 -1
- package/dist/tree-operations/paste/list-absorb.js +1 -1
- package/dist/tree-operations/paste/list-break-out.js +1 -1
- package/dist/tree-operations/paste/parent-scope.js +1 -1
- package/dist/tree-operations/paste/paste-replacement.js +1 -1
- package/dist/tree-operations/paste/replace-block-at-parent.d.ts +3 -1
- package/dist/tree-operations/paste/replace-block-at-parent.js +5 -2
- package/dist/tree-operations/paste/replacement-parse.d.ts +17 -0
- package/dist/tree-operations/paste/replacement-parse.js +22 -0
- package/dist/tree-operations/path-mutate.d.ts +1 -1
- package/dist/tree-operations/path-mutate.js +2 -1
- package/dist/tree-operations/reorder-unit.js +1 -1
- package/dist/tree-operations/reorder.d.ts +5 -2
- package/dist/tree-operations/reorder.js +55 -2
- package/dist/tree-operations/settle.d.ts +105 -0
- package/dist/tree-operations/settle.js +660 -0
- package/dist/tree-operations/table-grid-clipboard.d.ts +21 -0
- package/dist/tree-operations/table-grid-clipboard.js +90 -0
- package/dist/tree-operations/unshare.d.ts +15 -77
- package/dist/tree-operations/unshare.js +15 -166
- package/docs/guide/consumer-guide.md +136 -104
- package/docs/guide/plugin-api.md +73 -29
- package/docs/guide/plugin-guide.md +55 -23
- package/package.json +9 -7
- package/dist/components/blocks/code/CodeLanguageChip.svelte +0 -127
- package/dist/components/blocks/code/CodeLanguageChip.svelte.d.ts +0 -14
- package/dist/components/blocks/table/TableGrip.svelte +0 -91
- package/dist/components/blocks/table/TableGrip.svelte.d.ts +0 -8
- package/dist/components/blocks/table/table-drop-target.d.ts +0 -1
- package/dist/components/blocks/table/table-drop-target.js +0 -16
- package/dist/components/blocks/table/table-reorder-drag.d.ts +0 -78
- package/dist/components/blocks/table/table-reorder-drag.js +0 -97
|
@@ -18,9 +18,15 @@ import { createMarkerCompletion } from './marker-completion';
|
|
|
18
18
|
import { resolveEdgeDeletion } from './construct-edge-delete';
|
|
19
19
|
import { hidesStructuralSuffix } from './hidden-suffix';
|
|
20
20
|
import { resolveEdgeSeat } from './edge-seat';
|
|
21
|
-
import {
|
|
21
|
+
import { replaceRangeRaw } from './live-selection-edit';
|
|
22
22
|
import { resolveMarkedInsertion } from './pending-mark-insert';
|
|
23
23
|
import { widgetAtCursor } from './widget-adjacency';
|
|
24
|
+
import { resolveDelimiterAutoPair } from './delimiter-autopair';
|
|
25
|
+
import { soleProseReparse } from './screen-diff';
|
|
26
|
+
/** Whether `line` still reloads as `node`'s kind, the auto-pair resolver's guard. */
|
|
27
|
+
export function keepsBlockKind(node, line) {
|
|
28
|
+
return soleProseReparse(line + trailingLineEnding(node.raw))?.block.kind === node.kind;
|
|
29
|
+
}
|
|
24
30
|
const REPLACE_ISLAND_POLICY = {
|
|
25
31
|
onEdge: 'select',
|
|
26
32
|
deleteGranularity: 'select-then-delete'
|
|
@@ -34,6 +40,11 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
34
40
|
reason: 'an explicit instruction about the very next byte, so it outranks every classification below, which decide by where the caret happens to be',
|
|
35
41
|
claims: handlePendingMarks
|
|
36
42
|
},
|
|
43
|
+
{
|
|
44
|
+
id: 'transitional-hard-break',
|
|
45
|
+
reason: 'a hard break at the end of a block has no following line yet, so its own position is where the next byte starts that line',
|
|
46
|
+
claims: handleTransitionalHardBreak
|
|
47
|
+
},
|
|
37
48
|
{
|
|
38
49
|
id: 'cst-widget',
|
|
39
50
|
reason: 'a key aimed at an atomic construct is the widget branch’s before any byte rule',
|
|
@@ -101,6 +112,12 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
101
112
|
const d = display();
|
|
102
113
|
writeDisplay(d.slice(0, start) + insert + d.slice(end), start + insert.length, source, caretBefore);
|
|
103
114
|
}
|
|
115
|
+
/** The range this surface holds, or null at a caret. A key aimed at one edits the RANGE: the
|
|
116
|
+
* caret the arms read is only its start. */
|
|
117
|
+
function heldRange() {
|
|
118
|
+
const selection = deps.getRawSelection();
|
|
119
|
+
return selection && selection.start < selection.end ? selection : null;
|
|
120
|
+
}
|
|
104
121
|
// ── The seams the arms below defer to ────────────────────────────────────
|
|
105
122
|
/**
|
|
106
123
|
* The rung a range rewrite can be asked about. Past the reading cut a surface revealing no
|
|
@@ -139,6 +156,20 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
139
156
|
return null;
|
|
140
157
|
return resolveEdgeSeat(caret, inlinesOf(deps.node), deps.getEdgeAffinity(), deps.node.raw, screenVisibilityOf(el), typed);
|
|
141
158
|
}
|
|
159
|
+
/** A printable byte an arm claimed because the engine drops it at an element-level caret. Over
|
|
160
|
+
* a held range it REPLACES through the join seam, the road a mid-block range takes; at a caret
|
|
161
|
+
* the seat answers which side of an unpainted run it lands on. */
|
|
162
|
+
function writeTypedByte(el, caretOffset, typed, source) {
|
|
163
|
+
const range = heldRange();
|
|
164
|
+
if (range) {
|
|
165
|
+
const edit = replaceRangeRaw(deps.node, range, typed, joinSeamMode(el), deps.linkRef, deps.getAmbientPrefix?.() ?? '');
|
|
166
|
+
void deps.blockEdit.updateBlockContent(deps.index, edit.raw, range.start, edit.caret);
|
|
167
|
+
deps.setPendingCursor(edit.caret, source, edit.raw);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const seatedAt = typingSeatAt(el, caretOffset, typed)?.offset ?? caretOffset;
|
|
171
|
+
editDisplay(seatedAt, seatedAt, typed, source, caretOffset);
|
|
172
|
+
}
|
|
142
173
|
// ── CST inline widget ────────────────────────────────────────────────────
|
|
143
174
|
function handleCstWidget(e, caretOffset) {
|
|
144
175
|
if (deps.isRevealing())
|
|
@@ -152,9 +183,11 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
152
183
|
const widgetAt = widgetAtCursor(caretOffset, inlinesOf(node), node.raw, direction);
|
|
153
184
|
if (!widgetAt)
|
|
154
185
|
return false;
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
186
|
+
// Below the bail: every keystroke in every prose block reaches the line above.
|
|
187
|
+
const range = heldRange();
|
|
188
|
+
// Unchorded, and at a CARET: a modifier makes the key a word-scoped platform command, and
|
|
189
|
+
// a held range is an edit of the range, not an entry into the construct beside its start.
|
|
190
|
+
const plainEdgeKey = !e.shiftKey && !hasModifier(e) && !range;
|
|
158
191
|
const enterFromRight = plainEdgeKey && widgetAt.atRight && (e.key === 'ArrowLeft' || e.key === 'Backspace');
|
|
159
192
|
const enterFromLeft = plainEdgeKey && !widgetAt.atRight && (e.key === 'ArrowRight' || e.key === 'Delete');
|
|
160
193
|
if (enterFromRight || enterFromLeft) {
|
|
@@ -189,14 +222,7 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
189
222
|
!deps.isReading()) {
|
|
190
223
|
e.preventDefault();
|
|
191
224
|
deps.setSnapTarget(null);
|
|
192
|
-
|
|
193
|
-
// This branch owns only the fact that the engine drops the key beside a widget; which
|
|
194
|
-
// side of an unpainted run the byte belongs on is still the seat's answer.
|
|
195
|
-
const seatedAt = typingSeatAt(el, caretOffset, typed)?.offset ?? caretOffset;
|
|
196
|
-
const newRaw = node.raw.slice(0, seatedAt) + typed + node.raw.slice(seatedAt);
|
|
197
|
-
const postEdit = seatedAt + typed.length;
|
|
198
|
-
void deps.blockEdit.updateBlockContent(deps.index, newRaw, caretOffset, postEdit);
|
|
199
|
-
deps.setPendingCursor(postEdit, 'widget', newRaw);
|
|
225
|
+
writeTypedByte(el, caretOffset, e.key, 'widget');
|
|
200
226
|
return true;
|
|
201
227
|
}
|
|
202
228
|
return false;
|
|
@@ -243,8 +269,8 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
243
269
|
// Second press: the native selection already wraps a replace island, so delete its
|
|
244
270
|
// whole hidden range through the CST as one undo entry.
|
|
245
271
|
if (isDestructive) {
|
|
246
|
-
const selection =
|
|
247
|
-
if (selection
|
|
272
|
+
const selection = heldRange();
|
|
273
|
+
if (selection) {
|
|
248
274
|
const selected = islands.find((i) => islandPolicy(i).onEdge === 'select' &&
|
|
249
275
|
i.start === selection.start &&
|
|
250
276
|
i.end === selection.end);
|
|
@@ -301,7 +327,7 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
301
327
|
// branch in e2e, so it is unit-pinned instead.
|
|
302
328
|
if (isTyping && !caretIsInTextContent(el, window.getSelection())) {
|
|
303
329
|
e.preventDefault();
|
|
304
|
-
|
|
330
|
+
writeTypedByte(el, caretOffset, e.key, 'island');
|
|
305
331
|
return true;
|
|
306
332
|
}
|
|
307
333
|
return false;
|
|
@@ -326,11 +352,11 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
326
352
|
if (!touchesAmbient)
|
|
327
353
|
return false;
|
|
328
354
|
e.preventDefault();
|
|
329
|
-
const range =
|
|
330
|
-
if (range
|
|
355
|
+
const range = heldRange();
|
|
356
|
+
if (range) {
|
|
331
357
|
// Consumed at KEYDOWN, so no `beforeinput` carries this range to the shared seam: the arm
|
|
332
358
|
// asks it here, or a literal splice prints the runs the cut stranded (live-mode.md § 4.5).
|
|
333
|
-
const edit =
|
|
359
|
+
const edit = replaceRangeRaw(deps.node, range, '', joinSeamMode(el), deps.linkRef, deps.getAmbientPrefix?.() ?? '');
|
|
334
360
|
void deps.blockEdit.updateBlockContent(deps.index, edit.raw, range.start, edit.caret);
|
|
335
361
|
deps.setPendingCursor(edit.caret, 'ambient-delete');
|
|
336
362
|
}
|
|
@@ -389,6 +415,35 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
389
415
|
return true;
|
|
390
416
|
}
|
|
391
417
|
// ── Pending marks (the toggle seat) ────────────────────────────────────────
|
|
418
|
+
/**
|
|
419
|
+
* The byte that completes a hard break made at the END of a block. `insertHardBreak` writes
|
|
420
|
+
* `\\` plus the block's ending there, but that ending IS the block's trailing one, so the
|
|
421
|
+
* display stops at the backslash and the caret has nowhere to sit past it. The next
|
|
422
|
+
* printable key is what supplies the following line: it lands AFTER the break rather than
|
|
423
|
+
* between the backslash and its newline, where it would read as content and undo the break.
|
|
424
|
+
*/
|
|
425
|
+
function handleTransitionalHardBreak(e, caretOffset) {
|
|
426
|
+
if (deps.isReading())
|
|
427
|
+
return false;
|
|
428
|
+
if (!isPlainTypingKey(e) || caretOffset === null || hasSelectionHelper())
|
|
429
|
+
return false;
|
|
430
|
+
const d = display();
|
|
431
|
+
// Only at the very end, and only when the block's last byte is the break's backslash.
|
|
432
|
+
if (caretOffset !== d.length || !d.endsWith('\\'))
|
|
433
|
+
return false;
|
|
434
|
+
// An escaped backslash (`\\\\`) is content, not a break.
|
|
435
|
+
if (d.endsWith('\\\\'))
|
|
436
|
+
return false;
|
|
437
|
+
// Backslash before ASCII punctuation is an escape (`\|`, `\*`), never a break's backslash.
|
|
438
|
+
if (/^[!-/:-@[-`{-~]$/.test(e.key))
|
|
439
|
+
return false;
|
|
440
|
+
const ending = trailingLineEnding(deps.node.raw);
|
|
441
|
+
e.preventDefault();
|
|
442
|
+
deps.setSnapTarget(null);
|
|
443
|
+
const next = d + ending + e.key;
|
|
444
|
+
writeDisplay(next, next.length, 'transitional-hard-break', caretOffset);
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
392
447
|
/**
|
|
393
448
|
* A printable key while a collapsed-caret toggle has marks pending. Marks are the newer
|
|
394
449
|
* instruction about the same bytes, so they outrank the arrival side the seat below reads
|
|
@@ -442,14 +497,28 @@ export function createEdgePolicyDispatch(deps) {
|
|
|
442
497
|
function handleConstructSeat(e, caretOffset) {
|
|
443
498
|
if (!isPlainTypingKey(e) || caretOffset === null || hasSelectionHelper())
|
|
444
499
|
return false;
|
|
500
|
+
// A delimiter typed over its own closer is the auto-pair's step-over, which the beforeinput
|
|
501
|
+
// arm owns (delimiter-autopair.ts); seated outside the run it would be typed instead.
|
|
502
|
+
const content = getContentRange(deps.node);
|
|
503
|
+
const autoPair = resolveDelimiterAutoPair(display(), content, caretOffset, e.key);
|
|
504
|
+
if (autoPair?.kind === 'step-over')
|
|
505
|
+
return false;
|
|
445
506
|
const el = deps.getEl();
|
|
446
507
|
const seat = el && typingSeatAt(el, caretOffset, e.key);
|
|
447
508
|
if (!seat)
|
|
448
509
|
return false;
|
|
449
510
|
e.preventDefault();
|
|
450
511
|
deps.setSnapTarget(null);
|
|
451
|
-
// The
|
|
452
|
-
//
|
|
512
|
+
// The seat decides WHERE the byte lands; what a delimiter keystroke writes there is still
|
|
513
|
+
// the auto-pair's answer, or a byte seated past a run would arrive without its twin. The
|
|
514
|
+
// kind rides the trace: it names the construct whose hidden edge the caret sat at.
|
|
515
|
+
const paired = resolveDelimiterAutoPair(display(), content, seat.offset, e.key, (line) => keepsBlockKind(deps.node, line));
|
|
516
|
+
if (paired && paired.kind !== 'step-over') {
|
|
517
|
+
writeDisplay(paired.text, paired.caret, `seat:${seat.kind}`, caretOffset);
|
|
518
|
+
if (paired.kind === 'close')
|
|
519
|
+
deps.noteOutside?.();
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
453
522
|
editDisplay(seat.offset, seat.offset, e.key, `seat:${seat.kind}`, caretOffset);
|
|
454
523
|
return true;
|
|
455
524
|
}
|
|
@@ -59,10 +59,10 @@ export declare function resolveSelectionEdit(node: NodeView, selection: {
|
|
|
59
59
|
start: number;
|
|
60
60
|
end: number;
|
|
61
61
|
}, typed: string, presentationMode: PresentationMode | undefined, linkRef: InlineResolverRef | undefined, ambientPrefix?: string): SelectionEdit | null;
|
|
62
|
-
/** The
|
|
63
|
-
*
|
|
64
|
-
* home, so no arm
|
|
65
|
-
export declare function
|
|
62
|
+
/** The rewrite of `[start, end)` to `typed` a gesture the surface consumed installs, where a
|
|
63
|
+
* delete is the empty one. The seam's cleaned bytes where it has them, else the literal display
|
|
64
|
+
* splice with the caret past the insert: the fallback's one home, so no arm can drift. */
|
|
65
|
+
export declare function replaceRangeRaw(node: NodeView, range: {
|
|
66
66
|
start: number;
|
|
67
67
|
end: number;
|
|
68
|
-
}, presentationMode: PresentationMode | undefined, linkRef: InlineResolverRef | undefined, ambientPrefix: string): SelectionEdit;
|
|
68
|
+
}, typed: string, presentationMode: PresentationMode | undefined, linkRef: InlineResolverRef | undefined, ambientPrefix: string): SelectionEdit;
|
|
@@ -19,6 +19,8 @@ export function resolveLiveRangeEdit(e, node, cursor, presentationMode, linkRef,
|
|
|
19
19
|
if (!range)
|
|
20
20
|
return null;
|
|
21
21
|
const insert = replacementText(e);
|
|
22
|
+
if (range.start === range.end)
|
|
23
|
+
return parkedCaretInsertion(node, cursor, range.start, insert);
|
|
22
24
|
const edit = resolveSelectionEdit(node, range, insert ?? '', presentationMode, linkRef, ambientPrefix);
|
|
23
25
|
if (!edit)
|
|
24
26
|
return null;
|
|
@@ -26,6 +28,31 @@ export function resolveLiveRangeEdit(e, node, cursor, presentationMode, linkRef,
|
|
|
26
28
|
? { kind: 'swallow' }
|
|
27
29
|
: { kind: 'rewrite', range, raw: edit.raw, caret: edit.caret };
|
|
28
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* A collapsed insertion has no seam to clean, but Chromium inserts at its canonical spelling of
|
|
33
|
+
* the caret's pixel, UPSTREAM across a hidden run, while the DOM caret may sit where a commit
|
|
34
|
+
* parked it, past that run (after a `)` just typed). A target behind the caret is that
|
|
35
|
+
* canonicalization, and the byte belongs where the caret is, the side the keydown seat settled. A
|
|
36
|
+
* target at or past the caret is the engine landing the byte itself, which a split's reopened run
|
|
37
|
+
* relies on: parked at its start, the byte goes inside.
|
|
38
|
+
*/
|
|
39
|
+
function parkedCaretInsertion(node, cursor, engineTarget, insert) {
|
|
40
|
+
if (!insert)
|
|
41
|
+
return null;
|
|
42
|
+
const selection = window.getSelection();
|
|
43
|
+
if (!selection || selection.rangeCount === 0 || !selection.isCollapsed)
|
|
44
|
+
return null;
|
|
45
|
+
const caret = cursor.rawRangeOf(selection.getRangeAt(0))?.start ?? null;
|
|
46
|
+
if (caret === null || engineTarget >= caret)
|
|
47
|
+
return null;
|
|
48
|
+
const display = trimTrailingLineEnding(node.raw);
|
|
49
|
+
return {
|
|
50
|
+
kind: 'rewrite',
|
|
51
|
+
range: { start: caret, end: caret },
|
|
52
|
+
raw: display.slice(0, caret) + insert + display.slice(caret) + trailingLineEnding(node.raw),
|
|
53
|
+
caret: caret + insert.length
|
|
54
|
+
};
|
|
55
|
+
}
|
|
29
56
|
/**
|
|
30
57
|
* The whole surface arm around {@link resolveLiveRangeEdit}: stand down while a source reveal has
|
|
31
58
|
* outrun the CST, resolve, preventDefault what the seam owns, then swallow or hand the rewrite to
|
|
@@ -75,17 +102,20 @@ export function resolveSelectionEdit(node, selection, typed, presentationMode, l
|
|
|
75
102
|
caret: joined.seam + typed.length
|
|
76
103
|
};
|
|
77
104
|
}
|
|
78
|
-
/** The
|
|
79
|
-
*
|
|
80
|
-
* home, so no arm
|
|
81
|
-
export function
|
|
82
|
-
const cleaned = resolveSelectionEdit(node, range,
|
|
105
|
+
/** The rewrite of `[start, end)` to `typed` a gesture the surface consumed installs, where a
|
|
106
|
+
* delete is the empty one. The seam's cleaned bytes where it has them, else the literal display
|
|
107
|
+
* splice with the caret past the insert: the fallback's one home, so no arm can drift. */
|
|
108
|
+
export function replaceRangeRaw(node, range, typed, presentationMode, linkRef, ambientPrefix) {
|
|
109
|
+
const cleaned = resolveSelectionEdit(node, range, typed, presentationMode, linkRef, ambientPrefix);
|
|
83
110
|
if (cleaned)
|
|
84
111
|
return cleaned;
|
|
85
112
|
const display = trimTrailingLineEnding(node.raw);
|
|
86
113
|
return {
|
|
87
|
-
raw: display.slice(0, range.start) +
|
|
88
|
-
|
|
114
|
+
raw: display.slice(0, range.start) +
|
|
115
|
+
typed +
|
|
116
|
+
display.slice(range.end) +
|
|
117
|
+
trailingLineEnding(node.raw),
|
|
118
|
+
caret: range.start + typed.length
|
|
89
119
|
};
|
|
90
120
|
}
|
|
91
121
|
// ── Reading the event ────────────────────────────────────────────────────────
|
|
@@ -6,7 +6,7 @@ import { resolvedInlineContent } from '../../../core/inline/inline-cache';
|
|
|
6
6
|
import { isInlineWidget } from '../../../core/inline/inline-widgets';
|
|
7
7
|
import { createClipboardHandlers } from '../editable-surface';
|
|
8
8
|
import { pasteDispatch } from '../../../tree-operations/paste/dispatch';
|
|
9
|
-
import {
|
|
9
|
+
import { replaceRangeRaw } from './live-selection-edit';
|
|
10
10
|
export function createTextClipboard(deps) {
|
|
11
11
|
function getSelectedTextFromRaw() {
|
|
12
12
|
const offsets = deps.cursor.getRawSelection();
|
|
@@ -77,7 +77,7 @@ export function createTextClipboard(deps) {
|
|
|
77
77
|
return;
|
|
78
78
|
// A cut is a delete, so it crosses the same join seam: in live the range can span
|
|
79
79
|
// delimiter runs the reader never saw, and a raw splice would print them.
|
|
80
|
-
const edit =
|
|
80
|
+
const edit = replaceRangeRaw(deps.node, selOffsets, '', deps.getPresentationMode(), deps.linkRef, deps.getAmbientPrefix());
|
|
81
81
|
void deps.blockEdit.updateBlockContent(deps.index, edit.raw, selOffsets.start);
|
|
82
82
|
deps.setPendingCursor(edit.caret);
|
|
83
83
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pure raw/caret transforms for TextEditableBlock
|
|
2
|
+
* Pure raw/caret transforms for TextEditableBlock's structural gestures — heading-level
|
|
3
3
|
* swap, demotion to prose, hard-break insertion, literal-tab insertion. The component
|
|
4
4
|
* owns the plumbing; these own the string math.
|
|
5
5
|
*/
|
|
@@ -21,6 +21,12 @@ export declare function dropStructuralPrefix(raw: string, contentStart: number,
|
|
|
21
21
|
/** Drop everything past `contentEnd` but the block's own trailing line ending — the setext
|
|
22
22
|
* underline, which sits after every caret the content range admits. */
|
|
23
23
|
export declare function dropStructuralSuffix(raw: string, contentEnd: number, preEditOffset: number): TextEditResult;
|
|
24
|
+
/**
|
|
25
|
+
* An ATX heading left with no text is a marker standing over nothing: unfocused it paints
|
|
26
|
+
* nothing (the chrome-only stamp is focus-scoped), so the block would survive invisibly and
|
|
27
|
+
* resurface as a `#` on the next click. On blur it becomes the empty paragraph it looks like.
|
|
28
|
+
*/
|
|
29
|
+
export declare function demoteEmptyAtxHeading(raw: string, content: ContentRange): TextEditResult | null;
|
|
24
30
|
/**
|
|
25
31
|
* Re-mark the block's CONTENT with an ATX prefix for `level`, replacing whatever structural bytes
|
|
26
32
|
* the current kind keeps — the same content range {@link demoteToParagraph} reads, so an indented
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pure raw/caret transforms for TextEditableBlock
|
|
2
|
+
* Pure raw/caret transforms for TextEditableBlock's structural gestures — heading-level
|
|
3
3
|
* swap, demotion to prose, hard-break insertion, literal-tab insertion. The component
|
|
4
4
|
* owns the plumbing; these own the string math.
|
|
5
5
|
*/
|
|
@@ -33,6 +33,16 @@ export function dropStructuralSuffix(raw, contentEnd, preEditOffset) {
|
|
|
33
33
|
caretOffset: Math.min(preEditOffset, contentEnd)
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* An ATX heading left with no text is a marker standing over nothing: unfocused it paints
|
|
38
|
+
* nothing (the chrome-only stamp is focus-scoped), so the block would survive invisibly and
|
|
39
|
+
* resurface as a `#` on the next click. On blur it becomes the empty paragraph it looks like.
|
|
40
|
+
*/
|
|
41
|
+
export function demoteEmptyAtxHeading(raw, content) {
|
|
42
|
+
if (content.start === 0 || content.end > content.start)
|
|
43
|
+
return null;
|
|
44
|
+
return demoteToParagraph(raw, content, 0);
|
|
45
|
+
}
|
|
36
46
|
/**
|
|
37
47
|
* Re-mark the block's CONTENT with an ATX prefix for `level`, replacing whatever structural bytes
|
|
38
48
|
* the current kind keeps — the same content range {@link demoteToParagraph} reads, so an indented
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { AmbientPrefix } from '../../../block-component';
|
|
8
8
|
import type { DocumentView, NodeView } from '../../../core/node-views';
|
|
9
|
-
import type
|
|
9
|
+
import { type PresentationMode } from '../../../presentation-mode';
|
|
10
10
|
import type { ResolveImageUrl, ResolveLinkUrl } from '../../../editor-keys';
|
|
11
11
|
import type { LinkReferenceResolver } from '../../../core/inline/link-reference-resolver';
|
|
12
12
|
import { type ImageLoadPolicy } from '../../../core/inline-render';
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* factory owns the imperative inline-DOM construction and carries a live caret across
|
|
5
5
|
* a decoration-driven rebuild the edit path's pending restore doesn't cover.
|
|
6
6
|
*/
|
|
7
|
+
import { hidesMarkers } from '../../../presentation-mode';
|
|
7
8
|
import { buildAmbientSpan } from '../../../ambient/ambient-dom';
|
|
8
9
|
import { computeInlineContent, contentLengthOf, getContentRange, isProseKind } from '../../../core/inline';
|
|
9
10
|
import { renderInlineNodes } from '../../../core/inline-render';
|
|
@@ -90,7 +91,8 @@ export function createTextRender(deps) {
|
|
|
90
91
|
buildPortalWidget,
|
|
91
92
|
// Attribute-only stamps for the construct-reveal trigger, mode-gated so the
|
|
92
93
|
// other modes' DOM stays byte-identical.
|
|
93
|
-
tagConstructMarkers: deps.presentationMode === 'preview-inline'
|
|
94
|
+
tagConstructMarkers: deps.presentationMode === 'preview-inline',
|
|
95
|
+
pendingBreakSeat: hidesMarkers(deps.presentationMode)
|
|
94
96
|
}));
|
|
95
97
|
return frag;
|
|
96
98
|
}
|
|
@@ -69,6 +69,9 @@ export interface WidgetInteraction {
|
|
|
69
69
|
/** Snap a click that landed outside any text node to the nearest widget edge, or open a
|
|
70
70
|
* reveal-source widget it hit. */
|
|
71
71
|
snapClickToWidgetEdge(clickX: number | null, clickY: number | null, press?: WidgetPress): void;
|
|
72
|
+
/** A caret restored strictly inside a reveal-source widget — a formula that just closed
|
|
73
|
+
* around it — opens that source there instead of being pushed past the island. */
|
|
74
|
+
revealInterior(offset: number): boolean;
|
|
72
75
|
/** A reveal-source widget currently shows its editable `$…$` source. */
|
|
73
76
|
isRevealing(): boolean;
|
|
74
77
|
/** Escape (cancel to rendered) while source is shown. Enter is deliberately NOT
|