@quillmark/svelte 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/NOTICE +4 -4
  2. package/README.md +26 -8
  3. package/THEMING.md +10 -8
  4. package/dist/core/address.d.ts +35 -64
  5. package/dist/core/address.js +35 -55
  6. package/dist/core/bloom.d.ts +4 -10
  7. package/dist/core/bloom.js +14 -27
  8. package/dist/core/codec/blocks.d.ts +41 -43
  9. package/dist/core/codec/blocks.js +97 -130
  10. package/dist/core/codec/code.d.ts +7 -10
  11. package/dist/core/codec/code.js +37 -46
  12. package/dist/core/codec/decode.d.ts +19 -23
  13. package/dist/core/codec/decode.js +76 -111
  14. package/dist/core/codec/encode.d.ts +11 -15
  15. package/dist/core/codec/encode.js +60 -67
  16. package/dist/core/codec/field.d.ts +62 -95
  17. package/dist/core/codec/field.js +107 -179
  18. package/dist/core/codec/islands.d.ts +33 -41
  19. package/dist/core/codec/islands.js +76 -86
  20. package/dist/core/codec/lists.d.ts +17 -26
  21. package/dist/core/codec/lists.js +117 -157
  22. package/dist/core/codec/marks.d.ts +4 -3
  23. package/dist/core/codec/marks.js +8 -3
  24. package/dist/core/codec/prose.css +84 -46
  25. package/dist/core/codec/schema.d.ts +18 -23
  26. package/dist/core/codec/schema.js +84 -76
  27. package/dist/core/codec/slash.d.ts +42 -48
  28. package/dist/core/codec/slash.js +0 -0
  29. package/dist/core/codec/table-copy.d.ts +4 -3
  30. package/dist/core/codec/table-copy.js +25 -7
  31. package/dist/core/codec/table-view.d.ts +12 -12
  32. package/dist/core/codec/table-view.js +460 -383
  33. package/dist/core/codec/table.d.ts +94 -61
  34. package/dist/core/codec/table.js +331 -83
  35. package/dist/core/codec/tasks.d.ts +6 -0
  36. package/dist/core/codec/tasks.js +30 -3
  37. package/dist/core/errors.d.ts +15 -30
  38. package/dist/core/errors.js +2 -6
  39. package/dist/core/index.js +7 -12
  40. package/dist/core/lifecycle.d.ts +7 -16
  41. package/dist/core/lifecycle.js +10 -21
  42. package/dist/core/rebind.svelte.d.ts +10 -20
  43. package/dist/core/rebind.svelte.js +15 -27
  44. package/dist/core/rungs.d.ts +14 -11
  45. package/dist/core/rungs.js +17 -19
  46. package/dist/core/teardown.d.ts +4 -6
  47. package/dist/core/teardown.js +7 -10
  48. package/dist/core/theme.css +74 -54
  49. package/dist/index.js +3 -8
  50. package/dist/preset/app.css +3 -1
  51. package/dist/preset/index.css +6 -8
  52. package/dist/preset/recipes.css +12 -15
  53. package/dist/preset/scale.css +18 -17
  54. package/dist/preset/shell.css +10 -0
  55. package/dist/preview/bridge.d.ts +18 -22
  56. package/dist/preview/bridge.js +29 -58
  57. package/dist/preview/controller.d.ts +21 -29
  58. package/dist/preview/controller.js +14 -39
  59. package/dist/preview/geometry.d.ts +13 -34
  60. package/dist/preview/geometry.js +13 -34
  61. package/dist/preview/index.js +4 -16
  62. package/dist/preview/paint.d.ts +3 -3
  63. package/dist/preview/paint.js +28 -68
  64. package/dist/preview/strings.d.ts +1 -1
  65. package/dist/preview/strings.js +2 -14
  66. package/dist/preview/zoom.d.ts +18 -23
  67. package/dist/preview/zoom.js +28 -27
  68. package/dist/visual/ArrayField.svelte +77 -16
  69. package/dist/visual/BooleanField.svelte +27 -14
  70. package/dist/visual/Card.svelte +61 -48
  71. package/dist/visual/CardControls.svelte +5 -11
  72. package/dist/visual/DateField.svelte +20 -4
  73. package/dist/visual/EnumField.svelte +3 -0
  74. package/dist/visual/FieldHint.svelte +2 -1
  75. package/dist/visual/FormatPopover.svelte +82 -15
  76. package/dist/visual/FormatPopover.svelte.d.ts +4 -0
  77. package/dist/visual/MatrixAdd.svelte +30 -12
  78. package/dist/visual/MatrixField.svelte +24 -16
  79. package/dist/visual/NumberField.svelte +7 -0
  80. package/dist/visual/ObjectField.svelte +4 -4
  81. package/dist/visual/ProseField.svelte +0 -5
  82. package/dist/visual/TipsCard.svelte +11 -10
  83. package/dist/visual/VariantField.svelte +3 -1
  84. package/dist/visual/VisualEditorInner.svelte +19 -3
  85. package/dist/visual/controls.css +7 -2
  86. package/dist/visual/fonts.d.ts +18 -0
  87. package/dist/visual/fonts.js +59 -0
  88. package/dist/visual/icons/nodes.d.ts +0 -5
  89. package/dist/visual/icons/nodes.js +0 -4
  90. package/dist/visual/props.d.ts +14 -1
  91. package/dist/visual/strings.d.ts +7 -0
  92. package/dist/visual/strings.js +5 -2
  93. package/dist/visual/structure.d.ts +43 -87
  94. package/dist/visual/structure.js +42 -83
  95. package/package.json +2 -2
@@ -1,35 +1,28 @@
1
- // Islands: the `U+FFFC` slot + `ContentIsland` entry ↔ a PM leaf node. Every slot sits
2
- // in a `para` line; the island's type says which node it is, a `table` a block alone on
3
- // its line and every other type inline. The node carries `id`, `islandType` and `props`
4
- // verbatim.
1
+ // Islands: the `U+FFFC` slot + `ContentIsland` entry ↔ a PM leaf node. Every slot sits in a `para`
2
+ // line; the island's type says which node it is, a `table` a block alone on its line and every
3
+ // other type inline. The node carries `id`, `islandType` and `props` verbatim.
5
4
  //
6
- // A props-aware consumer reads the shape straight off the boundary:
7
- // `ContentIsland.props` is the typed union (`TableProps` for `table`, `ImageProps` for
8
- // `image`, …; DOCUMENT_MODEL §Stability seams), so the codec
9
- // reads it rather than hand-rolling a shape. `type` is a closed set, so a
10
- // discriminant check narrows it; `props` still crosses the DOM as opaque JSON,
11
- // which is what §`tablePropsOfNode` guards.
5
+ // `ContentIsland.props` is the typed union at the boundary (DOCUMENT_MODEL §Stability seams), so a
6
+ // discriminant check narrows it; `props` still crosses the DOM as opaque JSON, which
7
+ // §`tablePropsOfNode` guards.
12
8
  import { Fragment, Slice } from 'prosemirror-model';
13
9
  import { Plugin } from 'prosemirror-state';
14
10
  import { storableUrl } from './urls.js';
15
11
  /** The `U+FFFC` object-replacement char that occupies one island slot in `text`. */
16
12
  export const ISLAND_SLOT = '';
17
- // The three island node attributes carry the content entry verbatim: `id` is the
18
- // stable identity (rebases like an anchor), `islandType` the discriminator, and `props`
19
- // the payload the codec preserves byte-for-byte across a round-trip. `islandType` and
20
- // `props` declare no default: a node standing for an island holds one, so the pair is
21
- // supplied at every `create`.
13
+ // The three island node attributes carry the content entry verbatim: `id` is the stable identity
14
+ // (rebases like an anchor), `islandType` the discriminator, `props` the payload preserved
15
+ // byte-for-byte. `islandType` and `props` declare no default: a node standing for an island holds
16
+ // one.
22
17
  const islandAttrs = {
23
18
  id: { default: '' },
24
19
  islandType: {},
25
20
  props: {}
26
21
  };
27
- // All three attributes cross the DOM: a copy and a paste inside one body run the document
28
- // through `toDOM`/`parseDOM` (CODEC §"Markdown at the edges"), and an island is a leaf
29
- // whose tags alone say only `[table]`. `props` crosses as JSON, the form the payload has
30
- // at the boundary. The names are `data-qm-*` like every other carrier's, and the id is
31
- // what the rule requires: an island is a leaf, so a rule reading a tag someone else
32
- // chose would swallow that element's whole subtree.
22
+ // All three attributes cross the DOM, since a copy and a paste inside one body run the document
23
+ // through `toDOM`/`parseDOM` (CODEC §"Markdown at the edges") and an island's tags alone say only
24
+ // `[table]`. `props` crosses as JSON. The names are `data-qm-*`, and the id is required: an island
25
+ // is a leaf, so a rule reading someone else's tag would swallow that element's whole subtree.
33
26
  /** The DOM an island node writes and reads back, for either spec. */
34
27
  function islandDOM(node) {
35
28
  return {
@@ -38,11 +31,12 @@ function islandDOM(node) {
38
31
  'data-qm-island-props': JSON.stringify(node.attrs.props ?? null)
39
32
  };
40
33
  }
41
- /** The island types the content model names, each with whether its markup is a block,
42
- * which decides the node its slot decodes to, and whether a leaf edits it. A `Record`
43
- * over the boundary's own union, so a member added upstream is a missing key here
44
- * rather than a silent refusal at the one door with no decode behind it. A footnote and
45
- * an equation are read, not edited (CODEC §Decode): a leaf holding one is held. */
34
+ /**
35
+ * The island types the content model names, each with whether its markup is a block (deciding the
36
+ * node its slot decodes to) and whether a leaf edits it. A `Record` over the boundary's union, so a
37
+ * member added upstream is a missing key here. A footnote and an equation are read, not edited
38
+ * (CODEC §Decode): a leaf holding one is held.
39
+ */
46
40
  const ISLANDS = {
47
41
  table: { block: true, edited: true },
48
42
  image: { block: false, edited: true },
@@ -57,12 +51,12 @@ export function isBlockIsland(type) {
57
51
  export function isEditedIsland(type) {
58
52
  return ISLANDS[type].edited;
59
53
  }
60
- /** An island node's attributes off that DOM, or `false` where the id is absent or the
61
- * type is one no leaf edits — a name the vocabulary does not hold, or a footnote or an
62
- * equation, which no gesture mints — so the element's text arrives as text. A `props`
63
- * that is not the JSON written above reads as `null`, and one of the wrong shape is
64
- * `undefined` at its reader (§`tablePropsOfNode`): the entry survives as an island of
65
- * its type rather than taking the paste down with it. */
54
+ /**
55
+ * An island node's attributes off that DOM, or `false` where the id is absent or the type is one no
56
+ * leaf edits (an unknown name, a footnote, an equation), so the element's text arrives as text. A
57
+ * `props` that is not the JSON written above reads as `null`, one of the wrong shape `undefined` at
58
+ * its reader (§`tablePropsOfNode`): the entry survives as an island of its type.
59
+ */
66
60
  function islandAttrsFromDOM(el) {
67
61
  const id = el.getAttribute('data-qm-island-id');
68
62
  // Asserted off an untrusted attribute and checked against the set on the next line.
@@ -79,16 +73,17 @@ function islandAttrsFromDOM(el) {
79
73
  }
80
74
  return { id, islandType: type, props: storableProps(type, props) };
81
75
  }
82
- /** `props` with the one key the authored lane refuses made storable: an `image`'s `url`
83
- * carrying a line ending, which `IslandOp` and `overwrite` throw on. The rest crosses
84
- * opaque, as it did on the way out. */
76
+ /**
77
+ * `props` with the one key the authored lane refuses made storable: an `image`'s `url` carrying a
78
+ * line ending, which `IslandOp` and `overwrite` throw on.
79
+ */
85
80
  function storableProps(type, props) {
86
81
  if (type !== 'image' || typeof props !== 'object' || props === null)
87
82
  return props;
88
83
  const url = props.url;
89
84
  return typeof url === 'string' ? { ...props, url: storableUrl(url) } : props;
90
85
  }
91
- /** Block island node (a table): a `U+FFFC` slot alone on its `para` line. Atom, unselectable content. */
86
+ /** Block island node (a table): a `U+FFFC` slot alone on its `para` line. Atom. */
92
87
  export const islandBlockSpec = {
93
88
  group: 'block',
94
89
  atom: true,
@@ -97,8 +92,7 @@ export const islandBlockSpec = {
97
92
  parseDOM: [{ tag: 'div[data-qm-island]', getAttrs: (el) => islandAttrsFromDOM(el) }],
98
93
  toDOM: (node) => ['div', islandDOM(node), `[${node.attrs.islandType || 'island'}]`]
99
94
  };
100
- /** Inline island node (an image, a footnote, an equation): a `U+FFFC` slot inside a
101
- * `para` line. */
95
+ /** Inline island node (an image, a footnote, an equation): a `U+FFFC` slot inside a `para` line. */
102
96
  export const islandInlineSpec = {
103
97
  group: 'inline',
104
98
  inline: true,
@@ -108,9 +102,10 @@ export const islandInlineSpec = {
108
102
  parseDOM: [{ tag: 'span[data-qm-island]', getAttrs: (el) => islandAttrsFromDOM(el) }],
109
103
  toDOM: inlineIslandDOM
110
104
  };
111
- /** An inline island's DOM: a footnote its reference mark, whose number `prose.css` draws
112
- * in reading order and whose note is its title, an equation its TeX between the dollars
113
- * that write it, and an image its tag. */
105
+ /**
106
+ * An inline island's DOM: a footnote its reference mark (number drawn by `prose.css`, note as
107
+ * title), an equation its TeX between dollars, an image its tag.
108
+ */
114
109
  function inlineIslandDOM(node) {
115
110
  const attrs = node.attrs;
116
111
  const dom = islandDOM(node);
@@ -123,11 +118,12 @@ function inlineIslandDOM(node) {
123
118
  }
124
119
  return ['span', dom, `[${attrs.islandType || 'island'}]`];
125
120
  }
126
- /** Build a content island entry from a PM island node's attrs (block or inline). The
127
- * cast pairs a closed `type` with a `props` that crossed the DOM as opaque JSON. The
128
- * store is lenient about a table's shape — it fills what it can and keeps the rest —
129
- * so a payload the arm does not hold is stored rather than refused, and `undefined` at
130
- * its reader is what the surface draws the placeholder for (§`tablePropsOfNode`). */
121
+ /**
122
+ * Build a content island entry from a PM island node's attrs. The cast pairs a closed `type` with a
123
+ * `props` that crossed the DOM as opaque JSON. The store is lenient about a table's shape, so a
124
+ * payload the arm does not hold is stored, and `undefined` at its reader draws the placeholder
125
+ * (§`tablePropsOfNode`).
126
+ */
131
127
  export function islandEntryFromNode(attrs) {
132
128
  return {
133
129
  id: attrs.id,
@@ -135,9 +131,10 @@ export function islandEntryFromNode(attrs) {
135
131
  props: attrs.props
136
132
  };
137
133
  }
138
- /** The `TableProps` shape, over a value that reached the node off the DOM rather than
139
- * out of a decode: the rectangle every reader indexes (`table.ts`), down to the `text`
140
- * a row's emptiness is read off. */
134
+ /**
135
+ * The `TableProps` shape over a value that reached the node off the DOM: the rectangle every reader
136
+ * indexes (`table.ts`), down to the `text` a row's emptiness is read off.
137
+ */
141
138
  function isTableProps(props) {
142
139
  if (typeof props !== 'object' || props === null)
143
140
  return false;
@@ -146,32 +143,30 @@ function isTableProps(props) {
146
143
  v.every((c) => typeof c === 'object' && c !== null && typeof c.text === 'string');
147
144
  return (cells(header) && Array.isArray(aligns) && Array.isArray(rows) && rows.every((row) => cells(row)));
148
145
  }
149
- /** A node's `TableProps`, or `undefined` for any other island and for a payload of the
150
- * wrong shape: the boundary's own guard over the entry the node carries, so a `props`
151
- * that crossed the DOM is read once here rather than at each reader. The type says
152
- * which reader, the shape says whether it can read; every caller draws the placeholder
153
- * for `undefined` (`table-view.ts` §`render`). */
146
+ /**
147
+ * A node's `TableProps`, or `undefined` for any other island and for a payload of the wrong shape:
148
+ * the boundary's guard, so a `props` that crossed the DOM is read once here. Every caller draws the
149
+ * placeholder for `undefined` (`table-view.ts` §`render`).
150
+ */
154
151
  export function tablePropsOfNode(node) {
155
152
  const attrs = node.attrs;
156
153
  return attrs.islandType === 'table' && isTableProps(attrs.props) ? attrs.props : undefined;
157
154
  }
158
155
  /**
159
- * A minter over one document: the positional `isl-{n}` sequence continued past the
160
- * highest id the field already holds, handing out consecutive ids, so a caller placing
161
- * several islands at once keeps one minter for the lot. A minted id is this tier's to
162
- * produce and it is part of the document's canonical bytes (CODEC §Islands), so it is a
163
- * counter over the projection in hand — never a UUID, never a clock reading, and never a
164
- * re-numbering of the ids already there, which are identities.
156
+ * A minter over one document: the positional `isl-{n}` sequence continued past the highest id the
157
+ * field holds, so a caller placing several islands keeps one minter. A minted id is part of the
158
+ * document's canonical bytes (CODEC §Islands): a counter over the projection in hand, never a UUID
159
+ * or clock reading, and never a re-numbering of existing ids.
165
160
  *
166
- * Reads the PM doc rather than the stored content because that is what the caller (an
167
- * insert command, a paste) holds and what the commit will project: an id minted against
168
- * a stale content could collide with one the same transaction places.
161
+ * Reads the PM doc rather than stored content because that is what the caller holds and the commit
162
+ * will project; a stale content could collide with an id the same transaction places.
169
163
  */
170
164
  export function islandMinter(doc) {
171
165
  return islandState(doc).mint;
172
166
  }
173
- /** The ids a document holds and the minter continuing past them, off one sweep: both
174
- * are the same walk under the same predicate, and the paste pass wants both. */
167
+ /**
168
+ * The ids a document holds and the minter continuing past them, off one sweep for the paste pass.
169
+ */
175
170
  function islandState(doc) {
176
171
  const held = new Set();
177
172
  let next = 0;
@@ -187,20 +182,19 @@ function islandState(doc) {
187
182
  });
188
183
  return { held, mint: () => `isl-${next++}` };
189
184
  }
190
- /** The next island id for a field: one draw from {@link islandMinter}, which is what a
191
- * command placing exactly one island wants. */
185
+ /** The next island id for a field: one draw from {@link islandMinter}. */
192
186
  export function mintIslandId(doc) {
193
187
  return islandMinter(doc)();
194
188
  }
195
- /** Either island node: the test the sweep and the paste pass share, so a third island
196
- * shape is one arm rather than two. */
189
+ /** Either island node: the test the sweep and the paste pass share. */
197
190
  function isIsland(node) {
198
191
  return node.type.name === 'island_block' || node.type.name === 'island_inline';
199
192
  }
200
- /** `fragment` with every island whose id is empty or already `taken` minted afresh, or
201
- * `null` where none was: an untouched paste stays the slice it arrived as. Every
202
- * surviving id joins the set, so a slice carrying one id twice comes apart in the same
203
- * pass. */
193
+ /**
194
+ * `fragment` with every island whose id is empty or already `taken` minted afresh, or `null` where
195
+ * none was, so an untouched paste stays the slice it arrived as. Every surviving id joins the set,
196
+ * so a slice carrying one id twice comes apart in the same pass.
197
+ */
204
198
  function remintIslands(fragment, taken, mint) {
205
199
  const out = [];
206
200
  let changed = false;
@@ -224,22 +218,18 @@ function remintIslands(fragment, taken, mint) {
224
218
  return changed ? Fragment.fromArray(out) : null;
225
219
  }
226
220
  /**
227
- * The paste's island pass: an id the field already holds is re-minted on the way in, and
228
- * an island arriving with none, a table read off foreign markup (`table-paste.ts`), takes
229
- * its first.
221
+ * The paste's island pass: an id the field already holds is re-minted on the way in, and an island
222
+ * arriving with none (a table read off foreign markup, `table-paste.ts`) takes its first.
230
223
  *
231
- * An id is an identity in the content and unique across the field, so two islands
232
- * wearing one is a projection the store has no shape for. A copy rather than a cut is
233
- * where that arrives, and a paste out of a second field is the other; a cut pasted back
234
- * collides with nothing and keeps the identity it had.
224
+ * Ids are unique across the field, so two islands wearing one is a projection the store has no
225
+ * shape for. That arrives by a copy or a paste from a second field; a cut pasted back collides with
226
+ * nothing and keeps its identity.
235
227
  *
236
- * The test is the document as it stands, which a drag moving a selection over an island
237
- * reads one too many: the original is still there when the slice is transformed and gone
238
- * when it lands, so that island arrives under a fresh id. A fresh id costs it nothing a
239
- * duplicate would cost the whole field.
228
+ * The test is the document as it stands, so a drag moving a selection over an island sees the
229
+ * original still there and mints a fresh id for the arrival, which costs nothing next to a
230
+ * duplicate.
240
231
  *
241
- * A plugin prop rather than a view option: the leaf mounts the codec's plugin stack, and
242
- * which nodes carry an identity is the codec's to know.
232
+ * A plugin prop rather than a view option: which nodes carry an identity is the codec's to know.
243
233
  */
244
234
  export function islandPastePlugin() {
245
235
  return new Plugin({
@@ -1,34 +1,25 @@
1
1
  import type { Schema } from 'prosemirror-model';
2
2
  import type { Command } from 'prosemirror-state';
3
3
  /**
4
- * The list bindings for a block-schema leaf: `{}` for the one-line and plain
5
- * schemas, which declare no list nodes.
4
+ * The list bindings for a block-schema leaf: `{}` for the one-line and plain schemas, which declare
5
+ * no list nodes.
6
6
  *
7
- * `Tab` / `Shift-Tab` hold the list link of the body's Tab chain. Surfaces that own
8
- * Tab more locally under the same rule (`prose/canon/VISUAL_EDITOR.md` §Chrome)
9
- * prepend a link ahead of these in `keymap.ts`: a `code_block` takes literal
10
- * indentation (`code.ts`). Where every link declines, the body holds the key
11
- * (`keymap.ts`).
7
+ * `Tab` / `Shift-Tab` hold the list link of the body's Tab chain; surfaces owning Tab more locally
8
+ * prepend a link in `keymap.ts` (`prose/canon/VISUAL_EDITOR.md` §Chrome). `Tab` sinks an unnumbered
9
+ * line alone into a sub-list, any other line its whole item, and a block right after a list into
10
+ * the list's last item. `Mod-Shift-7` / `Mod-Shift-8` are the list toggle (`list-toggle.ts`).
11
+ * `Mod-Enter` ticks the task item around the caret (`toggleTask`).
12
12
  *
13
- * `Mod-Shift-7` / `Mod-Shift-8` are the list toggle (`list-toggle.ts`), numbering or
14
- * bulleting the selection's lines or taking their markers off.
13
+ * `Enter` is a chain in precedence order: the empty line above an unnumbered one, an empty top-level
14
+ * middle item out of the list, the marker back on an empty continuation line, `splitListItem` (`splitTaskItem` for
15
+ * tasks), then `liftListItem`. The split link splits a non-empty item, and on an empty last item
16
+ * either splits the wrapping item (a nested one, so Enter lifts one level) or bails so the last
17
+ * link lifts a top-level one to a paragraph.
15
18
  *
16
- * `Tab` sinks an unnumbered line alone into a sub-list, any other line its whole item,
17
- * and a block right after a list into the list's last item.
18
- *
19
- * `Enter` is a chain in precedence order: the empty line above an unnumbered one, the
20
- * marker off an empty middle item and back on an empty continuation line, then `splitListItem`
21
- * (`splitTaskItem`, which leaves a task item's new half an open task), then
22
- * `liftListItem`. The split link carries two behaviors of its own: it splits a
23
- * non-empty item, and on an empty last item it either splits the wrapping item (a
24
- * nested one, so Enter lifts exactly one level) or bails so the last link lifts a
25
- * top-level one out to a paragraph. `Backspace` takes an item's marker off at its
26
- * start, a top-level continuation line out to full width, and joins a block onto the
27
- * list it stands after, and both keys over a selection spanning blocks join the lists
28
- * the delete leaves touching. `Delete` is the marker off at the seam below with the two lines
29
- * joined, never the line out: a forward delete edits the line after the caret, not its
30
- * indent. An empty line is neither key's here:
31
- * the block link takes it ahead of this chain (`blocks.ts`), the caret's own line
32
- * being a nearer fact than the boundary under it.
19
+ * `Backspace` takes an item's marker off at its start, a top-level continuation line out to full
20
+ * width, and joins a block onto the list it follows; over a selection spanning blocks both keys
21
+ * join the lists the delete leaves touching. `Delete` is the marker off at the seam below with the
22
+ * two lines joined, never the line out. An empty line is neither key's here: the block link takes
23
+ * it first (`blocks.ts`).
33
24
  */
34
25
  export declare function listKeymap(schema: Schema): Record<string, Command>;