@voithos-labs/aragonite 0.10.2 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/README.md +6 -21
  2. package/THIRD-PARTY-NOTICES.md +25 -0
  3. package/dist/a11y-strings.d.ts +18 -0
  4. package/dist/a11y-strings.js +18 -0
  5. package/dist/action-contracts.d.ts +7 -1
  6. package/dist/ambient/ambient-dom.js +5 -1
  7. package/dist/block-component.d.ts +14 -0
  8. package/dist/components/BlockDragHandle.svelte +35 -24
  9. package/dist/components/BlockHost.svelte +16 -9
  10. package/dist/components/Editor.svelte +381 -198
  11. package/dist/components/Editor.svelte.d.ts +1 -1
  12. package/dist/components/SelectionOverlay.svelte +17 -3
  13. package/dist/components/TailInsert.svelte +107 -0
  14. package/dist/components/TailInsert.svelte.d.ts +17 -0
  15. package/dist/components/block-content-selector.d.ts +6 -2
  16. package/dist/components/block-content-selector.js +6 -2
  17. package/dist/components/blocks/ThematicBreakBlock.svelte +19 -6
  18. package/dist/components/blocks/ThematicBreakBlock.svelte.d.ts +1 -0
  19. package/dist/components/blocks/code/CodeBlock.svelte +211 -30
  20. package/dist/components/blocks/code/CodeBlockRail.svelte +686 -0
  21. package/dist/components/blocks/code/CodeBlockRail.svelte.d.ts +26 -0
  22. package/dist/components/blocks/code/code-bootstrap.js +4 -0
  23. package/dist/components/blocks/code/code-context-actions.d.ts +1 -0
  24. package/dist/components/blocks/code/code-context-actions.js +24 -0
  25. package/dist/components/blocks/code/code-fence-exit.d.ts +15 -0
  26. package/dist/components/blocks/code/code-fence-exit.js +26 -0
  27. package/dist/components/blocks/code/code-languages.d.ts +6 -0
  28. package/dist/components/blocks/code/code-languages.js +11 -0
  29. package/dist/components/blocks/code/code-renderer.js +11 -0
  30. package/dist/components/blocks/directive/DirectiveContainerBlock.svelte +1 -1
  31. package/dist/components/blocks/editable-leaf.d.ts +37 -6
  32. package/dist/components/blocks/editable-leaf.js +243 -29
  33. package/dist/components/blocks/editable-surface.d.ts +9 -0
  34. package/dist/components/blocks/editable-surface.js +22 -3
  35. package/dist/components/blocks/list/ListItemBlock.svelte +3 -3
  36. package/dist/components/blocks/list/task-checkbox.d.ts +2 -0
  37. package/dist/components/blocks/list/task-checkbox.js +11 -2
  38. package/dist/components/blocks/surface-wiring.svelte.d.ts +4 -0
  39. package/dist/components/blocks/surface-wiring.svelte.js +8 -1
  40. package/dist/components/blocks/table/TableActionMenu.svelte +210 -86
  41. package/dist/components/blocks/table/TableActionMenu.svelte.d.ts +5 -0
  42. package/dist/components/blocks/table/TableBlock.svelte +205 -186
  43. package/dist/components/blocks/table/TableBlock.svelte.d.ts +1 -0
  44. package/dist/components/blocks/table/TableCellBlock.svelte +87 -22
  45. package/dist/components/blocks/table/TableRowBlock.svelte +4 -18
  46. package/dist/components/blocks/table/TableRowBlock.svelte.d.ts +0 -5
  47. package/dist/components/blocks/table/cell-clipboard.d.ts +10 -0
  48. package/dist/components/blocks/table/cell-clipboard.js +34 -1
  49. package/dist/components/blocks/table/cell-keydown-plan.d.ts +1 -1
  50. package/dist/components/blocks/table/cell-keydown-plan.js +3 -1
  51. package/dist/components/blocks/table/table-cell-paste.js +2 -1
  52. package/dist/components/blocks/table/table-menu-model.d.ts +35 -8
  53. package/dist/components/blocks/table/table-menu-model.js +36 -17
  54. package/dist/components/blocks/text/TextEditableBlock.svelte +58 -11
  55. package/dist/components/blocks/text/delimiter-autopair.d.ts +71 -0
  56. package/dist/components/blocks/text/delimiter-autopair.js +216 -0
  57. package/dist/components/blocks/text/edge-policy-dispatch.d.ts +4 -0
  58. package/dist/components/blocks/text/edge-policy-dispatch.js +56 -2
  59. package/dist/components/blocks/text/live-selection-edit.js +27 -0
  60. package/dist/components/blocks/text/text-keydown.d.ts +7 -1
  61. package/dist/components/blocks/text/text-keydown.js +11 -1
  62. package/dist/components/blocks/text/text-render.d.ts +1 -1
  63. package/dist/components/blocks/text/text-render.js +3 -1
  64. package/dist/components/blocks/text/widget-interaction.d.ts +3 -0
  65. package/dist/components/blocks/text/widget-interaction.js +144 -22
  66. package/dist/components/drag-handle.d.ts +35 -0
  67. package/dist/components/drag-handle.js +126 -0
  68. package/dist/components/editor-root-focus.d.ts +19 -0
  69. package/dist/components/editor-root-focus.js +67 -0
  70. package/dist/components/editor-root-geometry.d.ts +39 -0
  71. package/dist/components/editor-root-geometry.js +91 -0
  72. package/dist/components/editor-root-keydown.d.ts +1 -1
  73. package/dist/components/editor-root-keydown.js +12 -3
  74. package/dist/components/editor-root-listeners.d.ts +10 -6
  75. package/dist/components/editor-root-listeners.js +23 -22
  76. package/dist/components/editor-root-mode-flip.d.ts +36 -0
  77. package/dist/components/editor-root-mode-flip.js +92 -0
  78. package/dist/components/image/ImageOverlayHost.svelte +14 -6
  79. package/dist/components/image/ImageProperties.svelte +512 -70
  80. package/dist/components/image/ImageProperties.svelte.d.ts +6 -1
  81. package/dist/components/image/ImageResizeHandles.svelte +59 -34
  82. package/dist/components/image/image-crop.d.ts +39 -0
  83. package/dist/components/image/image-crop.js +74 -0
  84. package/dist/components/image/image-edit-commit.d.ts +1 -0
  85. package/dist/components/image/image-edit-commit.js +21 -5
  86. package/dist/components/image/image-source-bytes.js +10 -3
  87. package/dist/components/image/image-widget-editing.js +1 -0
  88. package/dist/components/image/widget-dom.js +5 -1
  89. package/dist/components/link-card/link-card-commit.js +1 -1
  90. package/dist/components/lrd-map-gate.js +1 -1
  91. package/dist/components/menu/BlockMenu.svelte +315 -0
  92. package/dist/components/menu/BlockMenu.svelte.d.ts +34 -0
  93. package/dist/components/menu/MenuIcon.svelte +153 -0
  94. package/dist/components/menu/MenuIcon.svelte.d.ts +51 -0
  95. package/dist/components/menu/clipboard-actions.d.ts +12 -0
  96. package/dist/components/menu/clipboard-actions.js +42 -0
  97. package/dist/components/menu/default-context-actions.d.ts +15 -0
  98. package/dist/components/menu/default-context-actions.js +76 -0
  99. package/dist/components/menu/flyout-placement.d.ts +6 -0
  100. package/dist/components/menu/flyout-placement.js +25 -0
  101. package/dist/core/inline/format-toggle.d.ts +12 -4
  102. package/dist/core/inline/format-toggle.js +94 -40
  103. package/dist/core/inline/image-dimensions.d.ts +3 -0
  104. package/dist/core/inline/image-dimensions.js +46 -10
  105. package/dist/core/inline/inline-widgets.d.ts +11 -0
  106. package/dist/core/inline/scan/brackets.js +1 -0
  107. package/dist/core/inline/scan/plugin-syntax.d.ts +8 -0
  108. package/dist/core/inline/scan/plugin-syntax.js +15 -1
  109. package/dist/core/inline-render.d.ts +6 -0
  110. package/dist/core/inline-render.js +32 -0
  111. package/dist/core/nodes.d.ts +14 -0
  112. package/dist/cursor/edge-affinity.js +2 -1
  113. package/dist/cursor/overlay-remeasure.js +8 -0
  114. package/dist/cursor/reveal-source.js +7 -2
  115. package/dist/cursor/widget-offset.d.ts +6 -0
  116. package/dist/cursor/widget-offset.js +61 -4
  117. package/dist/debug/interaction-trace.d.ts +4 -0
  118. package/dist/debug/interaction-trace.js +15 -0
  119. package/dist/decorations/decoration-state.svelte.js +1 -1
  120. package/dist/editor-actions/ancestry-folds.d.ts +2 -2
  121. package/dist/editor-actions/ancestry-folds.js +1 -1
  122. package/dist/editor-actions/block-edit-scope.js +1 -1
  123. package/dist/editor-actions/commit/text-batch.d.ts +3 -2
  124. package/dist/editor-actions/commit/text-batch.js +1 -1
  125. package/dist/editor-actions/commit/undo-controller.js +4 -2
  126. package/dist/editor-actions/container-edit.js +2 -1
  127. package/dist/editor-actions/enter-completion.d.ts +2 -0
  128. package/dist/editor-actions/enter-completion.js +23 -2
  129. package/dist/editor-actions/inline-range-commit.js +1 -1
  130. package/dist/editor-actions/reorder-action.js +19 -10
  131. package/dist/editor-actions/reorder-drag.js +29 -1
  132. package/dist/editor-actions/replacement-focus.d.ts +1 -1
  133. package/dist/editor-actions/replacement-focus.js +1 -1
  134. package/dist/editor-actions/search-replace.js +1 -1
  135. package/dist/editor-actions/table-context.d.ts +4 -1
  136. package/dist/editor-actions/table-context.js +57 -1
  137. package/dist/editor-events.d.ts +3 -0
  138. package/dist/editor-keys.d.ts +33 -0
  139. package/dist/editor-props.d.ts +21 -12
  140. package/dist/index.d.ts +1 -1
  141. package/dist/plugin.d.ts +6 -0
  142. package/dist/plugin.js +11 -0
  143. package/dist/plugins/latex/BlockMath.svelte +264 -29
  144. package/dist/plugins/latex/BlockMath.svelte.d.ts +2 -0
  145. package/dist/plugins/latex/index.d.ts +2 -1
  146. package/dist/plugins/latex/latex-kind.js +36 -3
  147. package/dist/plugins/latex/math-completion.js +4 -1
  148. package/dist/plugins/latex/math-layout.d.ts +15 -0
  149. package/dist/plugins/latex/math-layout.js +13 -0
  150. package/dist/plugins/latex/math-source.d.ts +19 -0
  151. package/dist/plugins/latex/math-source.js +97 -0
  152. package/dist/plugins/latex/register.d.ts +11 -2
  153. package/dist/plugins/latex/register.js +3 -1
  154. package/dist/plugins/latex/renderer.d.ts +3 -3
  155. package/dist/plugins/latex/renderer.js +13 -6
  156. package/dist/reactivity/list-windowing.svelte.d.ts +8 -8
  157. package/dist/reactivity/list-windowing.svelte.js +49 -24
  158. package/dist/schema/block-completions.d.ts +8 -0
  159. package/dist/schema/block-completions.js +11 -0
  160. package/dist/schema/context-actions.d.ts +31 -0
  161. package/dist/schema/context-actions.js +23 -0
  162. package/dist/schema/fenced-code-raw.js +31 -1
  163. package/dist/schema/operations.d.ts +8 -1
  164. package/dist/schema/reserved-chords.js +25 -4
  165. package/dist/schema/table-cell-raw.d.ts +1 -1
  166. package/dist/schema/table-cell-raw.js +1 -1
  167. package/dist/selection/block-hit-test.js +3 -2
  168. package/dist/selection/char-endpoint-snap.js +1 -1
  169. package/dist/selection/clipboard-text.js +6 -1
  170. package/dist/selection/covered-block.d.ts +10 -0
  171. package/dist/selection/covered-block.js +24 -0
  172. package/dist/selection/cross-block/dispatch.d.ts +3 -0
  173. package/dist/selection/cross-block/dispatch.js +13 -1
  174. package/dist/selection/cross-block/format-range.d.ts +1 -1
  175. package/dist/selection/cross-block/format-range.js +4 -15
  176. package/dist/selection/cross-block/format-toggle.js +1 -1
  177. package/dist/selection/cross-block/keydown.js +1 -1
  178. package/dist/selection/cross-block/ops.js +1 -1
  179. package/dist/selection/cross-block/paste.js +32 -30
  180. package/dist/selection/cross-block/type-replace.d.ts +3 -2
  181. package/dist/selection/cross-block/type-replace.js +62 -13
  182. package/dist/selection/dead-space-caret.d.ts +10 -0
  183. package/dist/selection/dead-space-caret.js +47 -1
  184. package/dist/selection/double-click-trim.d.ts +17 -0
  185. package/dist/selection/double-click-trim.js +57 -0
  186. package/dist/selection/drag-pointer.d.ts +7 -2
  187. package/dist/selection/drag-pointer.js +61 -2
  188. package/dist/selection/gap-caret.js +1 -1
  189. package/dist/selection/keyboard-extend.js +1 -1
  190. package/dist/selection/path-lookup.js +1 -1
  191. package/dist/selection/range-delete-ceremony.js +4 -2
  192. package/dist/selection/range-delete-chrome.js +2 -1
  193. package/dist/selection/range-delete-table-coverage.js +2 -1
  194. package/dist/selection/range-delete-table.js +3 -2
  195. package/dist/selection/range-delete.js +30 -2
  196. package/dist/selection/selection-restore.js +1 -1
  197. package/dist/selection/selection-state.svelte.d.ts +6 -0
  198. package/dist/selection/selection-state.svelte.js +36 -1
  199. package/dist/selection/table-endpoint-snap.js +1 -1
  200. package/dist/selection/table-rect-extend.js +1 -1
  201. package/dist/styles/editor-theme.css +57 -28
  202. package/dist/styles/editor.css +217 -18
  203. package/dist/testing/container-conformance.js +2 -2
  204. package/dist/testing/inline-conformance.js +2 -1
  205. package/dist/tree-operations/blockquote.js +1 -1
  206. package/dist/tree-operations/chain-rebuild.d.ts +63 -0
  207. package/dist/tree-operations/chain-rebuild.js +142 -0
  208. package/dist/tree-operations/children.d.ts +1 -1
  209. package/dist/tree-operations/children.js +1 -1
  210. package/dist/tree-operations/cleanup.js +1 -1
  211. package/dist/tree-operations/content-write.d.ts +50 -0
  212. package/dist/tree-operations/content-write.js +263 -0
  213. package/dist/tree-operations/index.d.ts +8 -3
  214. package/dist/tree-operations/index.js +6 -2
  215. package/dist/tree-operations/list/exit-replacement.js +1 -1
  216. package/dist/tree-operations/list/unwrap-merge.js +3 -3
  217. package/dist/tree-operations/node-ops.d.ts +17 -234
  218. package/dist/tree-operations/node-ops.js +47 -1113
  219. package/dist/tree-operations/node-primitives.d.ts +75 -0
  220. package/dist/tree-operations/node-primitives.js +117 -0
  221. package/dist/tree-operations/paste/apply.js +1 -1
  222. package/dist/tree-operations/paste/body-write.d.ts +1 -1
  223. package/dist/tree-operations/paste/body-write.js +2 -2
  224. package/dist/tree-operations/paste/container-match.js +4 -2
  225. package/dist/tree-operations/paste/dispatch.js +2 -1
  226. package/dist/tree-operations/paste/find-enclosing-list.js +1 -1
  227. package/dist/tree-operations/paste/focus-target.d.ts +1 -1
  228. package/dist/tree-operations/paste/list-absorb.js +1 -1
  229. package/dist/tree-operations/paste/list-break-out.js +1 -1
  230. package/dist/tree-operations/paste/parent-scope.js +1 -1
  231. package/dist/tree-operations/paste/paste-replacement.js +1 -1
  232. package/dist/tree-operations/paste/replace-block-at-parent.js +1 -1
  233. package/dist/tree-operations/path-mutate.d.ts +1 -1
  234. package/dist/tree-operations/path-mutate.js +2 -1
  235. package/dist/tree-operations/reorder-unit.js +1 -1
  236. package/dist/tree-operations/reorder.d.ts +5 -2
  237. package/dist/tree-operations/reorder.js +55 -2
  238. package/dist/tree-operations/settle.d.ts +105 -0
  239. package/dist/tree-operations/settle.js +660 -0
  240. package/dist/tree-operations/table-grid-clipboard.d.ts +21 -0
  241. package/dist/tree-operations/table-grid-clipboard.js +90 -0
  242. package/dist/tree-operations/unshare.d.ts +15 -77
  243. package/dist/tree-operations/unshare.js +15 -166
  244. package/docs/guide/consumer-guide.md +126 -96
  245. package/docs/guide/plugin-api.md +31 -3
  246. package/docs/guide/plugin-guide.md +26 -3
  247. package/package.json +4 -2
  248. package/dist/components/blocks/code/CodeLanguageChip.svelte +0 -127
  249. package/dist/components/blocks/code/CodeLanguageChip.svelte.d.ts +0 -14
  250. package/dist/components/blocks/table/TableGrip.svelte +0 -91
  251. package/dist/components/blocks/table/TableGrip.svelte.d.ts +0 -8
  252. package/dist/components/blocks/table/table-drop-target.d.ts +0 -1
  253. package/dist/components/blocks/table/table-drop-target.js +0 -16
  254. package/dist/components/blocks/table/table-reorder-drag.d.ts +0 -78
  255. package/dist/components/blocks/table/table-reorder-drag.js +0 -97
@@ -5,6 +5,7 @@
5
5
  import { registerLanguage } from './code-languages';
6
6
  import { registerPasteSurface, __removePasteSurfaceForTests } from '../../../tree-operations/paste-surfaces';
7
7
  import { codePasteSurface } from './code-paste-surface';
8
+ import { registerCodeContextActions } from './code-context-actions';
8
9
  import javascript from 'highlight.js/lib/languages/javascript';
9
10
  import typescript from 'highlight.js/lib/languages/typescript';
10
11
  import python from 'highlight.js/lib/languages/python';
@@ -22,6 +23,7 @@ import cpp from 'highlight.js/lib/languages/cpp';
22
23
  import ruby from 'highlight.js/lib/languages/ruby';
23
24
  import markdown from 'highlight.js/lib/languages/markdown';
24
25
  import diff from 'highlight.js/lib/languages/diff';
26
+ import latex from 'highlight.js/lib/languages/latex';
25
27
  let booted = false;
26
28
  export function bootstrapCodeLanguages() {
27
29
  if (booted)
@@ -44,7 +46,9 @@ export function bootstrapCodeLanguages() {
44
46
  registerLanguage('ruby', ruby);
45
47
  registerLanguage('markdown', markdown, ['md']);
46
48
  registerLanguage('diff', diff);
49
+ registerLanguage('latex', latex, ['tex']);
47
50
  registerPasteSurface(codePasteSurface);
51
+ registerCodeContextActions();
48
52
  }
49
53
  /** Test-only: reset the booted flag and unregister the paste surface, so a
50
54
  * re-bootstrap doesn't hit the register-once duplicate throw. */
@@ -0,0 +1 @@
1
+ export declare function registerCodeContextActions(): void;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The code block's context menu: dissolve the fence into plain text. Delete is every block's
3
+ * default row. Registered once from the code bootstrap.
4
+ */
5
+ import { registerBlockContextActions } from '../../../schema/context-actions';
6
+ import { sliceFencedCode } from './code-renderer';
7
+ let registered = false;
8
+ export function registerCodeContextActions() {
9
+ if (registered)
10
+ return;
11
+ registered = true;
12
+ registerBlockContextActions('fencedCode', (node) => [
13
+ {
14
+ id: 'code.dissolve',
15
+ label: 'Dissolve into text',
16
+ icon: 'type',
17
+ run: (ctx) => {
18
+ // The body's lines as prose; the fence lines go. An empty body leaves an empty line.
19
+ const body = sliceFencedCode(node).body.replace(/\r?\n$/, '');
20
+ return ctx.replaceRaw(body + '\n');
21
+ }
22
+ }
23
+ ]);
24
+ }
@@ -21,4 +21,19 @@ export type FenceExitResult = {
21
21
  } | {
22
22
  kind: 'none';
23
23
  };
24
+ export interface TypedFenceExitInput extends FenceExitInput {
25
+ /** The one character the pending `insertText` would write. */
26
+ typed: string;
27
+ }
28
+ /** A typed closer either leaves (taking its own line with it) or is just a byte. */
29
+ export type TypedFenceExitResult = Extract<FenceExitResult, {
30
+ kind: 'exitWithEdit' | 'none';
31
+ }>;
24
32
  export declare function computeFenceExit(input: FenceExitInput): FenceExitResult;
33
+ /**
34
+ * The block's other exit gesture: a closer typed on the body's empty last line. Every other
35
+ * editor reads that run as "done here", and the bytes never land — written, they would be a body
36
+ * line reading as the closer, which the write seam can only answer by growing the fence. A run
37
+ * anywhere else is content, and that escalation keeps its CommonMark meaning.
38
+ */
39
+ export declare function computeTypedFenceExit(input: TypedFenceExitInput): TypedFenceExitResult;
@@ -29,6 +29,32 @@ export function computeFenceExit(input) {
29
29
  }
30
30
  return { kind: 'none' };
31
31
  }
32
+ /**
33
+ * The block's other exit gesture: a closer typed on the body's empty last line. Every other
34
+ * editor reads that run as "done here", and the bytes never land — written, they would be a body
35
+ * line reading as the closer, which the write seam can only answer by growing the fence. A run
36
+ * anywhere else is content, and that escalation keeps its CommonMark meaning.
37
+ */
38
+ export function computeTypedFenceExit(input) {
39
+ const { text, offset, meta, typed } = input;
40
+ const none = { kind: 'none' };
41
+ if (!meta.closed || typed !== meta.fenceMarker)
42
+ return none;
43
+ // The caret must sit at the end of a line that has one below it: the closer's.
44
+ const ending = /^\r?\n/.exec(text.slice(offset));
45
+ if (!ending)
46
+ return none;
47
+ const lineStart = text.lastIndexOf('\n', offset - 1) + 1;
48
+ const run = text.slice(lineStart, offset);
49
+ if (run !== meta.fenceMarker.repeat(run.length) || run.length + 1 < meta.fenceLength)
50
+ return none;
51
+ const below = offset + ending[0].length;
52
+ if (!matchFenceClose(lineAt(text, below), meta.fenceMarker, meta.fenceLength))
53
+ return none;
54
+ // The run's line goes with the exit, as Enter's own empty-line exit takes the blank one.
55
+ return { kind: 'exitWithEdit', newText: text.slice(0, lineStart) + text.slice(below) };
56
+ }
57
+ // ── Internal ────────────────────────────────────────────────────────────────
32
58
  // The one physical line beginning at `start`, without its trailing newline.
33
59
  function lineAt(text, start) {
34
60
  const end = text.indexOf('\n', start);
@@ -11,5 +11,11 @@ export interface LanguageGrammar {
11
11
  export declare function registerLanguage(name: string, definition: LanguageFn, aliasList?: readonly string[]): void;
12
12
  /** Info strings with trailing attributes (`js {1-3}`) resolve on the first token. */
13
13
  export declare function getLanguageGrammar(infoString: string): LanguageGrammar | null;
14
+ /**
15
+ * Every registered grammar name, plus every alias, sorted — what the language picker
16
+ * offers. Aliases are listed as their own entries: a user typing `js` should find it
17
+ * rather than having to know it resolves to `javascript`.
18
+ */
19
+ export declare function listLanguages(): string[];
14
20
  /** Test-only: clear all registered languages. */
15
21
  export declare function __resetRegistryForTests(): void;
@@ -23,6 +23,17 @@ export function getLanguageGrammar(infoString) {
23
23
  const resolvedName = aliases.get(firstToken) ?? firstToken;
24
24
  return grammars.get(resolvedName) ?? null;
25
25
  }
26
+ /**
27
+ * Every registered grammar name, plus every alias, sorted — what the language picker
28
+ * offers. Aliases are listed as their own entries: a user typing `js` should find it
29
+ * rather than having to know it resolves to `javascript`.
30
+ */
31
+ export function listLanguages() {
32
+ const names = new Set(grammars.keys());
33
+ for (const alias of aliases.keys())
34
+ names.add(alias);
35
+ return [...names].sort();
36
+ }
26
37
  /** Test-only: clear all registered languages. */
27
38
  export function __resetRegistryForTests() {
28
39
  grammars.clear();
@@ -217,6 +217,17 @@ export function renderCodeBlock(node) {
217
217
  const bodyText = separatorNewline ? slice.body.slice(0, -1) : slice.body;
218
218
  frag.appendChild(renderOpenerLine(slice, meta.fenceMarker, meta.fenceLength));
219
219
  frag.appendChild(tokenizeBody(bodyText, slice.infoString));
220
+ // An empty last body line ends the body in `\n` with only the (hidden) closer after it.
221
+ // Chromium paints no caret after a trailing `\n` unless something follows, so it
222
+ // canonicalises the seat to BEFORE the newline and the next key lands one byte early —
223
+ // the second line of a code block was untypeable in live mode. A `br` anchors the line
224
+ // without touching textContent; source mode, where the closer line itself follows, hides
225
+ // it in CSS.
226
+ if (separatorNewline && bodyText.endsWith('\n')) {
227
+ const anchor = document.createElement('br');
228
+ anchor.dataset.caretAnchor = 'closer';
229
+ frag.appendChild(anchor);
230
+ }
220
231
  frag.appendChild(renderCloserLine(slice, separatorNewline));
221
232
  assertInvariant('rendered-text-fidelity', () => checkRenderedTextFidelity(frag.textContent ?? '', trimTrailingLineEnding(node.raw)));
222
233
  return frag;
@@ -42,7 +42,7 @@
42
42
  }
43
43
  .directive-marker {
44
44
  display: block;
45
- font-family: var(--font-editor, ui-monospace, monospace);
45
+ font-family: var(--font-code, ui-monospace, monospace);
46
46
  opacity: var(--syntax-marker-dim, 0.65);
47
47
  user-select: none;
48
48
  -webkit-user-select: none;
@@ -1,9 +1,10 @@
1
1
  /**
2
- * The editable-leaf seam a plugin block component builds on: a text-editing block surface with
3
- * native caret/IME/undo/cross-block-selection parity, in one factory so a plugin never touches an
4
- * editor context key. Two modes: `plain` commits per keystroke, `render-primary` reveals its
5
- * source and commits on blur. Call synchronously during init. Contract: plugin-guide § The
6
- * editable leaf.
2
+ * The editable-leaf seam a plugin block component builds on: native caret/IME/undo/selection
3
+ * parity in one factory, so a plugin never touches an editor context key. `plain` commits per
4
+ * keystroke; `render-primary` reveals its source and commits on blur. A painted source
5
+ * (`renderSource`) edits only its own DOM: every byte still enters the CST through
6
+ * `commitReveal`'s one `updateBlockContent`. Call synchronously during init. Contract:
7
+ * plugin-guide § The editable leaf.
7
8
  */
8
9
  import type { BlockEditActions } from '../../action-contracts';
9
10
  import type { StickyColumnDirection } from '../../block-component';
@@ -37,6 +38,28 @@ export interface EditableLeafDeps {
37
38
  * platform treats it as `unknown`; the plugin casts it.
38
39
  */
39
40
  commandHooks?: () => unknown;
41
+ /**
42
+ * Paints the source as DOM instead of one text node — fence lines the mode CSS hides,
43
+ * highlight tokens. Must keep `fragment.textContent === text` (G1.28); the offset walk sees
44
+ * through spans, and hidden marker runs behave as they do in a code block.
45
+ */
46
+ renderSource?(text: string): DocumentFragment;
47
+ /**
48
+ * The surface's text after each edit the leaf applies itself (a painted source's typing,
49
+ * deleting, Enter). A render-primary host keeping a live preview reads this: the CST sees
50
+ * the edit only on blur, and a cancelled `beforeinput` fires no `input` event.
51
+ */
52
+ onSourceEdit?(text: string): void;
53
+ /**
54
+ * A source that is only its own chrome (a `$$$$` with no body line), completed to the shape
55
+ * a caret can sit in, with where the caret goes. Applied as the source is revealed, so the
56
+ * block the user just entered is one they can type into and delete; null leaves the bytes
57
+ * alone. The edit is the reveal's own, committed on blur like any other.
58
+ */
59
+ completeBareSource?(text: string): {
60
+ text: string;
61
+ caret: number;
62
+ } | null;
40
63
  }
41
64
  /**
42
65
  * The one-spread source surface: `<div {...leaf.surfaceProps}>` wires every handler and attribute
@@ -51,6 +74,7 @@ export interface EditableLeafSurfaceProps {
51
74
  role: 'textbox';
52
75
  spellcheck: 'false';
53
76
  oninput: () => void;
77
+ onbeforeinput: (e: InputEvent) => void;
54
78
  onkeydown: (e: KeyboardEvent) => void | Promise<void>;
55
79
  oncopy: (e: ClipboardEvent) => void;
56
80
  oncut: (e: ClipboardEvent) => Promise<void>;
@@ -69,14 +93,21 @@ export interface EditableLeafSurfaceProps {
69
93
  * stand down while the source is up, so the spread may sit on a wrapper the fold keeps.
70
94
  */
71
95
  export interface EditableLeafRenderProps {
72
- /** Reveal-on-click (shift-click extends a selection instead). */
96
+ /** Notes the press; the reveal is the CLICK's (shift-click extends a selection instead). */
73
97
  onpointerdown: (e: PointerEvent) => void;
98
+ /** Reveal on a click that did not drag — a press that moved is a selection, not an entry. */
99
+ onclick: (e: MouseEvent) => void;
74
100
  /** Chord dispatch at this block's kind: the global tier, then its own commands. */
75
101
  onkeydown: (e: KeyboardEvent) => void;
76
102
  }
77
103
  export interface EditableLeaf {
78
104
  /** The block's source minus its trailing line ending — the editable text. */
79
105
  readonly sourceText: string;
106
+ /**
107
+ * Re-run `renderSource` over the surface's CURRENT text with the caret kept, for a host
108
+ * that repaints as the user types (highlighting goes stale otherwise). No-op without it.
109
+ */
110
+ repaintSource(): void;
80
111
  /** The one-spread source surface (attributes + handlers + view/park attachments). */
81
112
  surfaceProps: EditableLeafSurfaceProps;
82
113
  /** render-primary: the one-spread folded surface. */