@quillmark/svelte 0.26.2 → 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.
- package/NOTICE +4 -4
- package/README.md +26 -8
- package/THEMING.md +40 -4
- package/dist/core/address.d.ts +35 -64
- package/dist/core/address.js +35 -55
- package/dist/core/bloom.d.ts +4 -10
- package/dist/core/bloom.js +14 -27
- package/dist/core/codec/blocks.d.ts +41 -43
- package/dist/core/codec/blocks.js +97 -130
- package/dist/core/codec/code.d.ts +7 -10
- package/dist/core/codec/code.js +37 -46
- package/dist/core/codec/decode.d.ts +19 -23
- package/dist/core/codec/decode.js +76 -111
- package/dist/core/codec/encode.d.ts +11 -15
- package/dist/core/codec/encode.js +60 -67
- package/dist/core/codec/field.d.ts +62 -95
- package/dist/core/codec/field.js +107 -179
- package/dist/core/codec/islands.d.ts +33 -41
- package/dist/core/codec/islands.js +76 -86
- package/dist/core/codec/lists.d.ts +17 -26
- package/dist/core/codec/lists.js +117 -157
- package/dist/core/codec/marks.d.ts +4 -3
- package/dist/core/codec/marks.js +8 -3
- package/dist/core/codec/prose.css +84 -46
- package/dist/core/codec/schema.d.ts +18 -23
- package/dist/core/codec/schema.js +84 -76
- package/dist/core/codec/slash.d.ts +42 -48
- package/dist/core/codec/slash.js +0 -0
- package/dist/core/codec/table-copy.d.ts +4 -3
- package/dist/core/codec/table-copy.js +25 -7
- package/dist/core/codec/table-view.d.ts +12 -12
- package/dist/core/codec/table-view.js +460 -383
- package/dist/core/codec/table.d.ts +94 -61
- package/dist/core/codec/table.js +331 -83
- package/dist/core/codec/tasks.d.ts +6 -0
- package/dist/core/codec/tasks.js +30 -3
- package/dist/core/errors.d.ts +15 -30
- package/dist/core/errors.js +2 -6
- package/dist/core/index.js +7 -12
- package/dist/core/lifecycle.d.ts +7 -16
- package/dist/core/lifecycle.js +10 -21
- package/dist/core/rebind.svelte.d.ts +10 -20
- package/dist/core/rebind.svelte.js +15 -27
- package/dist/core/rungs.d.ts +14 -11
- package/dist/core/rungs.js +17 -19
- package/dist/core/teardown.d.ts +4 -6
- package/dist/core/teardown.js +7 -10
- package/dist/core/theme.css +74 -54
- package/dist/index.js +3 -8
- package/dist/preset/app.css +71 -0
- package/dist/preset/index.css +8 -7
- package/dist/preset/recipes.css +19 -164
- package/dist/preset/scale.css +28 -18
- package/dist/preset/shell.css +157 -0
- package/dist/preview/Preview.svelte +8 -0
- package/dist/preview/bridge.d.ts +18 -22
- package/dist/preview/bridge.js +29 -58
- package/dist/preview/controller.d.ts +21 -29
- package/dist/preview/controller.js +14 -39
- package/dist/preview/geometry.d.ts +13 -34
- package/dist/preview/geometry.js +13 -34
- package/dist/preview/index.js +4 -16
- package/dist/preview/paint.d.ts +3 -3
- package/dist/preview/paint.js +28 -68
- package/dist/preview/strings.d.ts +1 -1
- package/dist/preview/strings.js +2 -14
- package/dist/preview/viewport.js +20 -15
- package/dist/preview/zoom.d.ts +21 -22
- package/dist/preview/zoom.js +53 -30
- package/dist/visual/ArrayField.svelte +77 -16
- package/dist/visual/BooleanField.svelte +28 -15
- package/dist/visual/Card.svelte +66 -51
- package/dist/visual/CardControls.svelte +5 -11
- package/dist/visual/DateField.svelte +20 -4
- package/dist/visual/EnumField.svelte +3 -0
- package/dist/visual/FieldHint.svelte +2 -1
- package/dist/visual/FormatPopover.svelte +82 -15
- package/dist/visual/FormatPopover.svelte.d.ts +4 -0
- package/dist/visual/MatrixAdd.svelte +30 -12
- package/dist/visual/MatrixField.svelte +24 -16
- package/dist/visual/NumberField.svelte +7 -0
- package/dist/visual/ObjectField.svelte +4 -4
- package/dist/visual/ProseField.svelte +0 -5
- package/dist/visual/TipsCard.svelte +11 -10
- package/dist/visual/VariantField.svelte +3 -1
- package/dist/visual/VisualEditorInner.svelte +19 -3
- package/dist/visual/controls.css +7 -2
- package/dist/visual/fonts.d.ts +18 -0
- package/dist/visual/fonts.js +59 -0
- package/dist/visual/icons/nodes.d.ts +0 -5
- package/dist/visual/icons/nodes.js +0 -4
- package/dist/visual/props.d.ts +14 -1
- package/dist/visual/strings.d.ts +7 -0
- package/dist/visual/strings.js +5 -2
- package/dist/visual/structure.d.ts +43 -87
- package/dist/visual/structure.js +42 -83
- package/package.json +2 -2
package/dist/core/codec/lists.js
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
|
-
// List editing: the body leaf's structural commands
|
|
2
|
-
//
|
|
3
|
-
// structural keys lists redefine: Enter (split, take the marker off an empty middle
|
|
4
|
-
// item, give an empty continuation line one, open an empty line above an unnumbered
|
|
5
|
-
// one), Backspace (take an item's marker off, or join a block onto the
|
|
6
|
-
// list above it) and Delete (the marker off at the seam below, and the two lines
|
|
7
|
-
// joined).
|
|
1
|
+
// List editing: the body leaf's structural commands over `prosemirror-schema-list`: Tab
|
|
2
|
+
// indent/outdent and the structural keys Enter, Backspace and Delete.
|
|
8
3
|
//
|
|
9
|
-
// An item's number is its position: no edit writes `start
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
4
|
+
// An item's number is its position: no edit writes `start`, which is what a writer typed (`N. `,
|
|
5
|
+
// `blocks.ts`) or what arrived with a whole list. Taking a marker off keeps the text where it
|
|
6
|
+
// stands as a continuation of the item above, so the items below close up by position. The one
|
|
7
|
+
// split is Backspace at the head of a top-level continuation line, which takes the line out to full
|
|
8
|
+
// width; the tail counts from 1.
|
|
14
9
|
//
|
|
15
|
-
// Cleanup is command-local, never a global pass: a command joins the boundary it opens
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// upstream normalizer keeps it (`tests/codec/list-shapes.test.ts`), and fusing
|
|
21
|
-
// renumbers an imported `1, 2, 1` in a region no edit touched. Reads preserve it; only
|
|
22
|
-
// an edit normalizes.
|
|
10
|
+
// Cleanup is command-local, never a global pass: a command joins the boundary it opens, and two
|
|
11
|
+
// lists of a kind a command leaves touching join (`touching.ts`). A whole-doc normalizer would fuse
|
|
12
|
+
// every adjacent same-type pair, but that boundary is load-bearing: `Container.instance` is how
|
|
13
|
+
// `Content` marks one (`tests/codec/list-shapes.test.ts`), and fusing renumbers an imported `1, 2,
|
|
14
|
+
// 1` in a region no edit touched.
|
|
23
15
|
import { NodeRange } from 'prosemirror-model';
|
|
24
16
|
import { liftListItem, sinkListItem } from 'prosemirror-schema-list';
|
|
25
17
|
import { EditorState, Selection, TextSelection } from 'prosemirror-state';
|
|
@@ -27,12 +19,12 @@ import { canJoin, findWrapping, liftTarget } from 'prosemirror-transform';
|
|
|
27
19
|
import { chainCommands, joinTextblockBackward, joinTextblockForward } from 'prosemirror-commands';
|
|
28
20
|
import { withinNesting } from './nesting.js';
|
|
29
21
|
import { toggleList } from './list-toggle.js';
|
|
30
|
-
import { splitTaskItem } from './tasks.js';
|
|
22
|
+
import { splitTaskItem, toggleTask } from './tasks.js';
|
|
31
23
|
import { joinAll, joinLists, touching } from './touching.js';
|
|
32
|
-
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The caret's enclosing `list_item` when it sits at the very start of that item's first block,
|
|
26
|
+
* where both structural keys branch; `null` otherwise.
|
|
27
|
+
*/
|
|
36
28
|
function atItemStart(state, itemType) {
|
|
37
29
|
const { $from, empty } = state.selection;
|
|
38
30
|
if (!empty || $from.parentOffset !== 0)
|
|
@@ -50,10 +42,8 @@ function atItemStart(state, itemType) {
|
|
|
50
42
|
};
|
|
51
43
|
}
|
|
52
44
|
/**
|
|
53
|
-
* The textblock at the end of `node`:
|
|
54
|
-
*
|
|
55
|
-
* `joinTextblockBackward` walking to the same one. `null` on an atom (an island, a
|
|
56
|
-
* rule), which holds no line to join onto.
|
|
45
|
+
* The textblock at the end of `node`: itself, else its last descendant that is one. `null` on an
|
|
46
|
+
* atom, which holds no line to join onto.
|
|
57
47
|
*/
|
|
58
48
|
function lastBlockIn(node) {
|
|
59
49
|
let last = node ?? null;
|
|
@@ -62,11 +52,8 @@ function lastBlockIn(node) {
|
|
|
62
52
|
return last?.isTextblock ? last : null;
|
|
63
53
|
}
|
|
64
54
|
/**
|
|
65
|
-
* Enter at the head of an unnumbered line that holds text → an empty unnumbered line
|
|
66
|
-
*
|
|
67
|
-
* makes at its head, kept to the line. `splitListItem` would split the item there
|
|
68
|
-
* instead, turning the line's text into the next item and leaving the empty line
|
|
69
|
-
* behind under the marker it had.
|
|
55
|
+
* Enter at the head of an unnumbered line that holds text → an empty unnumbered line above it, the
|
|
56
|
+
* caret staying with the text. `splitListItem` would instead turn the text into the next item.
|
|
70
57
|
*/
|
|
71
58
|
function lineAbove(itemType, paragraph) {
|
|
72
59
|
return (state, dispatch) => {
|
|
@@ -84,28 +71,23 @@ function lineAbove(itemType, paragraph) {
|
|
|
84
71
|
return true;
|
|
85
72
|
};
|
|
86
73
|
}
|
|
87
|
-
/** Whether `item` holds nothing but one empty textblock
|
|
88
|
-
* structure under it. */
|
|
74
|
+
/** Whether `item` holds nothing but one empty textblock. */
|
|
89
75
|
function emptyItem(item) {
|
|
90
76
|
return (item.childCount === 1 && !!item.firstChild?.isTextblock && item.firstChild.content.size === 0);
|
|
91
77
|
}
|
|
92
78
|
/**
|
|
93
|
-
* Take the marker off the item whose first block holds the caret's head, the text
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* item has no item above to continue and lifts out over the list instead.
|
|
79
|
+
* Take the marker off the item whose first block holds the caret's head, the text staying where it
|
|
80
|
+
* stands: a later item's blocks become continuation blocks of the item above, a nested first item's
|
|
81
|
+
* become the parent item's. Nothing splits, so the items below close up by position. A top-level
|
|
82
|
+
* first item lifts out over the list instead.
|
|
98
83
|
*
|
|
99
|
-
* An empty item is spent rather than kept as an empty continuation line, the caret
|
|
100
|
-
*
|
|
101
|
-
* that would join it away is the one a writer meant. `keepEmpty` is Enter's reading,
|
|
102
|
-
* where the empty line is the one about to be typed in.
|
|
84
|
+
* An empty item is spent rather than kept as an empty continuation line, the caret going to the end
|
|
85
|
+
* of what stood above it.
|
|
103
86
|
*
|
|
104
|
-
* Declines where the item
|
|
105
|
-
*
|
|
106
|
-
* stand ahead of no line.
|
|
87
|
+
* Declines where the item is the first block of one with nothing above it in an item
|
|
88
|
+
* (`list_item(ordered_list(…))`, a pasted shape).
|
|
107
89
|
*/
|
|
108
|
-
function markerOff(itemType
|
|
90
|
+
function markerOff(itemType) {
|
|
109
91
|
return (state, dispatch) => {
|
|
110
92
|
const at = atItemStart(state, itemType);
|
|
111
93
|
if (!at)
|
|
@@ -117,7 +99,7 @@ function markerOff(itemType, keepEmpty = false) {
|
|
|
117
99
|
const list = $from.node(-2);
|
|
118
100
|
const itemStart = $from.before(-1);
|
|
119
101
|
const itemEnd = itemStart + item.nodeSize;
|
|
120
|
-
const spend =
|
|
102
|
+
const spend = emptyItem(item);
|
|
121
103
|
const tr = state.tr;
|
|
122
104
|
let into;
|
|
123
105
|
if (at.itemIndex > 0) {
|
|
@@ -149,16 +131,13 @@ function markerOff(itemType, keepEmpty = false) {
|
|
|
149
131
|
};
|
|
150
132
|
}
|
|
151
133
|
/**
|
|
152
|
-
* Backspace at the head of a continuation line in a top-level item → the line out of
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* there and the tail counts from 1, a number that names its position in the list it now
|
|
156
|
-
* is. The press after is the ordinary join onto the list's last line
|
|
134
|
+
* Backspace at the head of a continuation line in a top-level item → the line out of the list to
|
|
135
|
+
* full width, the item's blocks after it: the second rung of the marker coming off. The list splits
|
|
136
|
+
* there and the tail counts from 1. The press after is the ordinary join onto the list's last line
|
|
157
137
|
* ({@link joinOntoList}).
|
|
158
138
|
*
|
|
159
|
-
* Declines where a sub-list stands below the line in its item,
|
|
160
|
-
*
|
|
161
|
-
* ordinary join: there the next rung out is still inside the list.
|
|
139
|
+
* Declines where a sub-list stands below the line in its item, and in a nested item, whose
|
|
140
|
+
* continuation lines keep the ordinary join.
|
|
162
141
|
*/
|
|
163
142
|
function lineOut(itemType) {
|
|
164
143
|
return (state, dispatch) => {
|
|
@@ -194,11 +173,9 @@ function lineOut(itemType) {
|
|
|
194
173
|
};
|
|
195
174
|
}
|
|
196
175
|
/**
|
|
197
|
-
* Shift-Tab → `liftListItem` in a nested list
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* nothing. Leaving the list is Backspace's, one rung a press. Outside every item the
|
|
201
|
-
* key declines.
|
|
176
|
+
* Shift-Tab → `liftListItem` in a nested list. A top-level item has no level above it inside the
|
|
177
|
+
* list: the key is claimed and does nothing, so a press too many while backing out of a sub-list
|
|
178
|
+
* renumbers nothing. Leaving the list is Backspace's. Outside every item the key declines.
|
|
202
179
|
*/
|
|
203
180
|
function outdent(itemType) {
|
|
204
181
|
const lift = liftListItem(itemType);
|
|
@@ -213,29 +190,36 @@ function outdent(itemType) {
|
|
|
213
190
|
};
|
|
214
191
|
}
|
|
215
192
|
/**
|
|
216
|
-
* Enter on an empty item that has items after it → the
|
|
217
|
-
* as
|
|
218
|
-
*
|
|
219
|
-
* last link), and a first item has no item above to continue.
|
|
193
|
+
* Enter on an empty top-level item that has items after it → the line out of the list to full
|
|
194
|
+
* width, as an empty last item leaves it. The list splits there and the tail counts from 1. A
|
|
195
|
+
* nested middle item is `liftListItem`'s, one level a press.
|
|
220
196
|
*/
|
|
221
|
-
function
|
|
222
|
-
const
|
|
223
|
-
return (state, dispatch) => {
|
|
197
|
+
function lineOutOfMiddle(itemType) {
|
|
198
|
+
const lift = liftListItem(itemType);
|
|
199
|
+
return (state, dispatch, view) => {
|
|
224
200
|
const at = atItemStart(state, itemType);
|
|
225
201
|
const { $from } = state.selection;
|
|
226
|
-
if (!at || at.
|
|
202
|
+
if (!at || at.nested || !emptyItem($from.node(-1)))
|
|
227
203
|
return false;
|
|
228
204
|
if (at.itemIndex === $from.node(-2).childCount - 1)
|
|
229
205
|
return false;
|
|
230
|
-
return
|
|
206
|
+
return lift(state, dispatch &&
|
|
207
|
+
((tr) => {
|
|
208
|
+
const $line = tr.selection.$from;
|
|
209
|
+
const tailPos = $line.after();
|
|
210
|
+
const tail = tr.doc.nodeAt(tailPos);
|
|
211
|
+
if (tail?.firstChild?.type === itemType &&
|
|
212
|
+
tail.attrs.start != null &&
|
|
213
|
+
tail.attrs.start !== 1)
|
|
214
|
+
tr.setNodeMarkup(tailPos, null, { ...tail.attrs, start: 1 });
|
|
215
|
+
dispatch(tr);
|
|
216
|
+
}), view);
|
|
231
217
|
};
|
|
232
218
|
}
|
|
233
219
|
/**
|
|
234
|
-
* Enter on an empty continuation line, the last block of an item past its first → the
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
* parent, the exit an empty last item takes. Never `liftListItem`, which would lift the
|
|
238
|
-
* whole item the line continues and take that item's marker with it.
|
|
220
|
+
* Enter on an empty continuation line, the last block of an item past its first → the marker back
|
|
221
|
+
* on: the line becomes an item after the one it continued. In the last item of a list it leaves the
|
|
222
|
+
* list instead. Never `liftListItem`, which would lift the whole item and take its marker.
|
|
239
223
|
*/
|
|
240
224
|
function markerOn(itemType) {
|
|
241
225
|
return (state, dispatch) => {
|
|
@@ -265,18 +249,14 @@ function markerOn(itemType) {
|
|
|
265
249
|
};
|
|
266
250
|
}
|
|
267
251
|
/**
|
|
268
|
-
* Backspace at the head of a block
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* list ({@link liftAtItemStart}) and leaves the key toggling.
|
|
252
|
+
* Backspace at the head of a block right after a list → join its text into the list's last line.
|
|
253
|
+
* The base keymap would wrap the block into a fresh item, undoing the lift ({@link
|
|
254
|
+
* liftAtItemStart}) and leaving the key toggling.
|
|
272
255
|
*
|
|
273
|
-
* Between a fence and prose the text does not join
|
|
274
|
-
*
|
|
275
|
-
* which refuses the same join between siblings). The block moves into the list's last
|
|
276
|
-
* item whole instead, a block of that item under its first.
|
|
256
|
+
* Between a fence and prose the text does not join (`code.ts` refuses the same join between
|
|
257
|
+
* siblings): the block moves into the list's last item whole instead.
|
|
277
258
|
*
|
|
278
|
-
* Either way
|
|
279
|
-
* lists of a kind it leaves touching join (`touching.ts`).
|
|
259
|
+
* Either way two lists of a kind it leaves touching join (`touching.ts`).
|
|
280
260
|
*/
|
|
281
261
|
function joinOntoList(itemType) {
|
|
282
262
|
return (state, dispatch, view) => {
|
|
@@ -306,11 +286,9 @@ function joinOntoList(itemType) {
|
|
|
306
286
|
};
|
|
307
287
|
}
|
|
308
288
|
/**
|
|
309
|
-
* Backspace or Delete over a selection that spans blocks → the base keymap's delete, and
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* is one no edit opened, and stays. Declines wherever the delete opens no seam, the base
|
|
313
|
-
* keymap's answer standing.
|
|
289
|
+
* Backspace or Delete over a selection that spans blocks → the base keymap's delete, and the two
|
|
290
|
+
* lists of a kind it leaves touching joined. A seam that touched before the delete is one no edit
|
|
291
|
+
* opened, and stays. Declines wherever the delete opens no seam.
|
|
314
292
|
*/
|
|
315
293
|
const deleteAcross = (state, dispatch) => {
|
|
316
294
|
const { $from, $to, empty } = state.selection;
|
|
@@ -329,17 +307,14 @@ const deleteAcross = (state, dispatch) => {
|
|
|
329
307
|
dispatch?.(tr.scrollIntoView());
|
|
330
308
|
return true;
|
|
331
309
|
};
|
|
332
|
-
/** The boundaries of every node around `$pos`, and `$pos` itself
|
|
333
|
-
* there can leave two blocks meeting. */
|
|
310
|
+
/** The boundaries of every node around `$pos`, and `$pos` itself. */
|
|
334
311
|
function seamsAround($pos) {
|
|
335
312
|
const seams = [$pos.pos];
|
|
336
313
|
for (let depth = $pos.depth; depth > 0; depth--)
|
|
337
314
|
seams.push($pos.before(depth), $pos.after(depth));
|
|
338
315
|
return seams;
|
|
339
316
|
}
|
|
340
|
-
/** Whether the caret sits inside a `list_item` at any depth
|
|
341
|
-
* inside an item is still an item's, and a caret outside every list is at no seam of
|
|
342
|
-
* one. */
|
|
317
|
+
/** Whether the caret sits inside a `list_item` at any depth. */
|
|
343
318
|
function inItem($pos, itemType) {
|
|
344
319
|
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
345
320
|
if ($pos.node(depth).type === itemType)
|
|
@@ -348,25 +323,19 @@ function inItem($pos, itemType) {
|
|
|
348
323
|
return false;
|
|
349
324
|
}
|
|
350
325
|
/**
|
|
351
|
-
* Delete at the very end of a block inside an item → the item below's marker off and
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
* the same seam stops at the marker, the one place the two keys differ: Backspace edits
|
|
357
|
-
* the block it is pressed in, and Delete the line after the caret.
|
|
358
|
-
*
|
|
359
|
-
* The caret stays where the key was pressed.
|
|
326
|
+
* Delete at the very end of a block inside an item → the item below's marker off and its first line
|
|
327
|
+
* joined onto the caret's. The marker comes off by the Backspace chain's own link (`markerOff`), so
|
|
328
|
+
* the item's other blocks stay under the joined line; the join is `joinTextblockForward`'s.
|
|
329
|
+
* Backspace at the same seam stops at the marker: Backspace edits the block it is pressed in,
|
|
330
|
+
* Delete the line after the caret. The caret stays where the key was pressed.
|
|
360
331
|
*
|
|
361
|
-
* An empty item below is spent,
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* marker comes off, and an empty line above one goes alone.
|
|
332
|
+
* An empty item below is spent, nothing after it joining. An empty item at the caret is the other
|
|
333
|
+
* way round: the item below moves up into it. A fence takes no prose line (`joinOntoList`): across
|
|
334
|
+
* one only the marker comes off.
|
|
365
335
|
*
|
|
366
|
-
* A line above a list is the same seam from outside
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
* keymap's.
|
|
336
|
+
* A line above a list is the same seam from outside: the first item's marker comes off and its line
|
|
337
|
+
* joins the caret's. Declining wherever the Backspace chain does keeps this to the list's own
|
|
338
|
+
* seams.
|
|
370
339
|
*/
|
|
371
340
|
function deleteBelow(itemType, press) {
|
|
372
341
|
const off = markerOff(itemType);
|
|
@@ -415,19 +384,19 @@ function deleteBelow(itemType, press) {
|
|
|
415
384
|
return true;
|
|
416
385
|
};
|
|
417
386
|
}
|
|
418
|
-
/**
|
|
419
|
-
*
|
|
387
|
+
/**
|
|
388
|
+
* A dispatch that keeps the caret where the key was pressed through an edit made at a seam below
|
|
389
|
+
* it.
|
|
390
|
+
*/
|
|
420
391
|
function keepCaret(state, dispatch) {
|
|
421
392
|
const pressed = state.selection.from;
|
|
422
393
|
return (tr) => dispatch(tr.setSelection(TextSelection.create(tr.doc, tr.mapping.map(pressed))));
|
|
423
394
|
}
|
|
424
395
|
/**
|
|
425
|
-
* Tab on an unnumbered line, a block of an item past its first → that line alone the
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
* joining the boundaries it opens (§cleanup). Declined past `MAX_NESTING_DEPTH`, as
|
|
430
|
-
* every sink is.
|
|
396
|
+
* Tab on an unnumbered line, a block of an item past its first → that line alone the first item of
|
|
397
|
+
* a sub-list of its list's kind, as `- ` or `1. ` typed at its head makes it. A sub-list of that
|
|
398
|
+
* kind right above or below takes it in, joining the boundaries the wrap opens. Declined past
|
|
399
|
+
* `MAX_NESTING_DEPTH`.
|
|
431
400
|
*/
|
|
432
401
|
function sinkLine(itemType) {
|
|
433
402
|
return (state, dispatch) => {
|
|
@@ -454,9 +423,10 @@ function sinkLine(itemType) {
|
|
|
454
423
|
return true;
|
|
455
424
|
};
|
|
456
425
|
}
|
|
457
|
-
/**
|
|
458
|
-
*
|
|
459
|
-
*
|
|
426
|
+
/**
|
|
427
|
+
* Tab → `sinkListItem`, declined past `MAX_NESTING_DEPTH` (`nesting.ts`). On a first item the key
|
|
428
|
+
* is claimed and does nothing.
|
|
429
|
+
*/
|
|
460
430
|
function sinkWithin(itemType) {
|
|
461
431
|
const sink = sinkListItem(itemType);
|
|
462
432
|
return (state, dispatch) => {
|
|
@@ -472,11 +442,9 @@ function sinkWithin(itemType) {
|
|
|
472
442
|
};
|
|
473
443
|
}
|
|
474
444
|
/**
|
|
475
|
-
* Tab on a block
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
* unnumbered line. Declined past `MAX_NESTING_DEPTH`, and over a selection that leaves
|
|
479
|
-
* the block.
|
|
445
|
+
* Tab on a block right after a list, outside every item → the block moves into the list's last
|
|
446
|
+
* item, keeping its kind. Declined past `MAX_NESTING_DEPTH`, and over a selection that leaves the
|
|
447
|
+
* block.
|
|
480
448
|
*/
|
|
481
449
|
function sinkIntoList(itemType) {
|
|
482
450
|
return (state, dispatch) => {
|
|
@@ -501,35 +469,26 @@ function sinkIntoList(itemType) {
|
|
|
501
469
|
};
|
|
502
470
|
}
|
|
503
471
|
/**
|
|
504
|
-
* The list bindings for a block-schema leaf: `{}` for the one-line and plain
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
* `Tab` / `Shift-Tab` hold the list link of the body's Tab chain. Surfaces that own
|
|
508
|
-
* Tab more locally under the same rule (`prose/canon/VISUAL_EDITOR.md` §Chrome)
|
|
509
|
-
* prepend a link ahead of these in `keymap.ts`: a `code_block` takes literal
|
|
510
|
-
* indentation (`code.ts`). Where every link declines, the body holds the key
|
|
511
|
-
* (`keymap.ts`).
|
|
472
|
+
* The list bindings for a block-schema leaf: `{}` for the one-line and plain schemas, which declare
|
|
473
|
+
* no list nodes.
|
|
512
474
|
*
|
|
513
|
-
* `
|
|
514
|
-
*
|
|
475
|
+
* `Tab` / `Shift-Tab` hold the list link of the body's Tab chain; surfaces owning Tab more locally
|
|
476
|
+
* prepend a link in `keymap.ts` (`prose/canon/VISUAL_EDITOR.md` §Chrome). `Tab` sinks an unnumbered
|
|
477
|
+
* line alone into a sub-list, any other line its whole item, and a block right after a list into
|
|
478
|
+
* the list's last item. `Mod-Shift-7` / `Mod-Shift-8` are the list toggle (`list-toggle.ts`).
|
|
479
|
+
* `Mod-Enter` ticks the task item around the caret (`toggleTask`).
|
|
515
480
|
*
|
|
516
|
-
* `
|
|
517
|
-
*
|
|
481
|
+
* `Enter` is a chain in precedence order: the empty line above an unnumbered one, an empty top-level
|
|
482
|
+
* middle item out of the list, the marker back on an empty continuation line, `splitListItem` (`splitTaskItem` for
|
|
483
|
+
* tasks), then `liftListItem`. The split link splits a non-empty item, and on an empty last item
|
|
484
|
+
* either splits the wrapping item (a nested one, so Enter lifts one level) or bails so the last
|
|
485
|
+
* link lifts a top-level one to a paragraph.
|
|
518
486
|
*
|
|
519
|
-
* `
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
* nested one, so Enter lifts exactly one level) or bails so the last link lifts a
|
|
525
|
-
* top-level one out to a paragraph. `Backspace` takes an item's marker off at its
|
|
526
|
-
* start, a top-level continuation line out to full width, and joins a block onto the
|
|
527
|
-
* list it stands after, and both keys over a selection spanning blocks join the lists
|
|
528
|
-
* the delete leaves touching. `Delete` is the marker off at the seam below with the two lines
|
|
529
|
-
* joined, never the line out: a forward delete edits the line after the caret, not its
|
|
530
|
-
* indent. An empty line is neither key's here:
|
|
531
|
-
* the block link takes it ahead of this chain (`blocks.ts`), the caret's own line
|
|
532
|
-
* being a nearer fact than the boundary under it.
|
|
487
|
+
* `Backspace` takes an item's marker off at its start, a top-level continuation line out to full
|
|
488
|
+
* width, and joins a block onto the list it follows; over a selection spanning blocks both keys
|
|
489
|
+
* join the lists the delete leaves touching. `Delete` is the marker off at the seam below with the
|
|
490
|
+
* two lines joined, never the line out. An empty line is neither key's here: the block link takes
|
|
491
|
+
* it first (`blocks.ts`).
|
|
533
492
|
*/
|
|
534
493
|
export function listKeymap(schema) {
|
|
535
494
|
const itemType = schema.nodes.list_item;
|
|
@@ -542,7 +501,8 @@ export function listKeymap(schema) {
|
|
|
542
501
|
'Mod-Shift-8': toggleList(false),
|
|
543
502
|
Tab: chainCommands(sinkLine(itemType), sinkWithin(itemType), sinkIntoList(itemType)),
|
|
544
503
|
'Shift-Tab': outdent(itemType),
|
|
545
|
-
Enter:
|
|
504
|
+
'Mod-Enter': toggleTask(itemType),
|
|
505
|
+
Enter: chainCommands(lineAbove(itemType, paragraph), lineOutOfMiddle(itemType), markerOn(itemType), splitTaskItem(itemType), liftListItem(itemType)),
|
|
546
506
|
Backspace: chainCommands(deleteAcross, markerOff(itemType), lineOut(itemType), joinOntoList(itemType)),
|
|
547
507
|
Delete: chainCommands(deleteAcross, deleteBelow(itemType, backspace))
|
|
548
508
|
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { Mark, Schema } from 'prosemirror-model';
|
|
2
2
|
import type { ContentMark, ContentMarkKind } from '@quillmark/wasm';
|
|
3
|
-
/** A PM mark from a content formatting mark, or `null` for an anchor
|
|
3
|
+
/** A PM mark from a content formatting mark, or `null` for an anchor, which no PM mark
|
|
4
|
+
* draws (`field.ts` holds it as a decoration). Exhaustive over
|
|
4
5
|
* the closed mark vocabulary, so a member added upstream is a compile error here rather
|
|
5
6
|
* than an index into a PM mark this schema does not declare. */
|
|
6
7
|
export declare function pmMarkFromContent(schema: Schema, m: ContentMark): Mark | null;
|
|
7
8
|
/**
|
|
8
9
|
* A content mark descriptor from a PM mark (range-free): the `{ type, … }` half
|
|
9
10
|
* of a `ContentMark` / `MarkOp`. `em` collapses to `emph` and a link's `href` rides
|
|
10
|
-
* out as the `url` its payload spells;
|
|
11
|
-
* which is what the cast claims.
|
|
11
|
+
* out as the `url` its payload spells; a font family's `name` is its own, and the
|
|
12
|
+
* other four are their own content name, which is what the cast claims.
|
|
12
13
|
*/
|
|
13
14
|
export declare function contentDescriptorFromPM(mark: Mark): ContentMarkKind;
|
|
14
15
|
/**
|
package/dist/core/codec/marks.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { canonicalJson } from './reconcile.js';
|
|
2
|
-
/** A PM mark from a content formatting mark, or `null` for an anchor
|
|
2
|
+
/** A PM mark from a content formatting mark, or `null` for an anchor, which no PM mark
|
|
3
|
+
* draws (`field.ts` holds it as a decoration). Exhaustive over
|
|
3
4
|
* the closed mark vocabulary, so a member added upstream is a compile error here rather
|
|
4
5
|
* than an index into a PM mark this schema does not declare. */
|
|
5
6
|
export function pmMarkFromContent(schema, m) {
|
|
6
7
|
switch (m.type) {
|
|
7
8
|
case 'anchor':
|
|
8
9
|
return null;
|
|
10
|
+
case 'font_family':
|
|
11
|
+
return schema.marks.font_family.create({ name: m.attrs.name });
|
|
9
12
|
case 'emph':
|
|
10
13
|
return schema.marks.em.create();
|
|
11
14
|
case 'link':
|
|
@@ -24,8 +27,8 @@ export function pmMarkFromContent(schema, m) {
|
|
|
24
27
|
/**
|
|
25
28
|
* A content mark descriptor from a PM mark (range-free): the `{ type, … }` half
|
|
26
29
|
* of a `ContentMark` / `MarkOp`. `em` collapses to `emph` and a link's `href` rides
|
|
27
|
-
* out as the `url` its payload spells;
|
|
28
|
-
* which is what the cast claims.
|
|
30
|
+
* out as the `url` its payload spells; a font family's `name` is its own, and the
|
|
31
|
+
* other four are their own content name, which is what the cast claims.
|
|
29
32
|
*/
|
|
30
33
|
export function contentDescriptorFromPM(mark) {
|
|
31
34
|
const name = mark.type.name;
|
|
@@ -33,6 +36,8 @@ export function contentDescriptorFromPM(mark) {
|
|
|
33
36
|
return { type: 'emph' };
|
|
34
37
|
if (name === 'link')
|
|
35
38
|
return { type: 'link', attrs: { url: mark.attrs.href } };
|
|
39
|
+
if (name === 'font_family')
|
|
40
|
+
return { type: 'font_family', attrs: { name: mark.attrs.name } };
|
|
36
41
|
return { type: name };
|
|
37
42
|
}
|
|
38
43
|
/**
|