edytor 4.0.0 → 6.0.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/README.md +2 -2
- package/dist/block/block.svelte.js +6 -21
- package/dist/block/inlineBlock.svelte.js +4 -6
- package/dist/clipboard/moveText.js +6 -8
- package/dist/cloudflare/DocumentRoom.d.ts +10 -3
- package/dist/cloudflare/index.d.ts +1 -1
- package/dist/cloudflare/room/access.d.ts +8 -3
- package/dist/cloudflare/room/access.js +44 -20
- package/dist/cloudflare/room/admission.js +28 -5
- package/dist/cloudflare/room/comments.js +28 -1
- package/dist/cloudflare/room/context.d.ts +106 -109
- package/dist/cloudflare/room/context.js +10 -3
- package/dist/cloudflare/room/forged.d.ts +14 -0
- package/dist/cloudflare/room/forged.js +30 -2
- package/dist/cloudflare/room/frames.d.ts +4 -0
- package/dist/cloudflare/room/frames.js +5 -1
- package/dist/cloudflare/room/purge.js +2 -1
- package/dist/cloudflare/room/replicas.d.ts +4 -2
- package/dist/cloudflare/room/replicas.js +8 -3
- package/dist/cloudflare/room/suggest.d.ts +7 -0
- package/dist/cloudflare/room/suggest.js +143 -0
- package/dist/cloudflare/routeDocumentSocket.d.ts +10 -1
- package/dist/cloudflare/routeDocumentSocket.js +5 -3
- package/dist/components/Content.svelte +9 -1
- package/dist/crdt/anchors.js +3 -2
- package/dist/crdt/attribution/attribution.d.ts +3 -0
- package/dist/crdt/attribution/attribution.js +3 -3
- package/dist/crdt/doc/funnel.d.ts +1 -1
- package/dist/crdt/doc/funnel.js +5 -2
- package/dist/crdt/doc/gate.d.ts +1 -1
- package/dist/crdt/doc/history.d.ts +6 -0
- package/dist/crdt/doc/history.js +79 -59
- package/dist/crdt/doc/ops.d.ts +81 -0
- package/dist/crdt/doc/ops.js +1898 -0
- package/dist/crdt/doc/reads.d.ts +2 -2
- package/dist/crdt/doc/reads.js +18 -28
- package/dist/crdt/doc/suggest.d.ts +167 -0
- package/dist/crdt/doc/suggest.js +579 -0
- package/dist/crdt/document.d.ts +10 -1
- package/dist/crdt/document.js +19 -11
- package/dist/crdt/edytor-doc.d.ts +294 -272
- package/dist/crdt/edytor-doc.js +123 -108
- package/dist/crdt/engine-api.d.ts +8 -2
- package/dist/crdt/engine.d.ts +2 -1
- package/dist/crdt/engine.js +3 -1
- package/dist/crdt/flow.d.ts +5 -47
- package/dist/crdt/flow.js +3 -269
- package/dist/crdt/index.d.ts +102 -108
- package/dist/crdt/index.js +3 -0
- package/dist/crdt/operations.d.ts +13 -4
- package/dist/crdt/parts.d.ts +43 -0
- package/dist/crdt/parts.js +44 -0
- package/dist/crdt/placement/display.d.ts +1 -1
- package/dist/crdt/placement/display.js +3 -3
- package/dist/crdt/placement/keys.d.ts +5 -0
- package/dist/crdt/placement/keys.js +5 -0
- package/dist/crdt/placement/resolve.d.ts +1 -1
- package/dist/crdt/placement/resolve.js +2 -1
- package/dist/crdt/protocol.d.ts +1 -1
- package/dist/crdt/protocol.js +1 -1
- package/dist/crdt/protocols/auth.d.ts +11 -1
- package/dist/crdt/protocols/auth.js +17 -1
- package/dist/crdt/protocols/awareness.js +46 -81
- package/dist/crdt/protocols/comments.d.ts +16 -1
- package/dist/crdt/protocols/comments.js +9 -1
- package/dist/crdt/providers/index.d.ts +12 -22
- package/dist/crdt/providers/index.js +3 -1
- package/dist/crdt/providers/indexeddb.d.ts +6 -10
- package/dist/crdt/providers/indexeddb.js +10 -16
- package/dist/crdt/providers/room.d.ts +11 -0
- package/dist/crdt/providers/room.js +26 -12
- package/dist/crdt/providers/websocket.d.ts +8 -12
- package/dist/crdt/providers/websocket.js +17 -19
- package/dist/crdt/purge.d.ts +7 -1
- package/dist/crdt/purge.js +32 -2
- package/dist/crdt/rangeDelete.d.ts +2 -47
- package/dist/crdt/rangeDelete.js +1 -169
- package/dist/crdt/restore.d.ts +2 -1
- package/dist/crdt/restore.js +9 -0
- package/dist/crdt/schema.d.ts +9 -1
- package/dist/crdt/schema.js +13 -3
- package/dist/crdt/structs.d.ts +2 -0
- package/dist/crdt/structs.js +2 -0
- package/dist/crdt/text/index/build.d.ts +125 -0
- package/dist/crdt/text/index/build.js +2895 -0
- package/dist/crdt/text/index/shared.d.ts +2 -6
- package/dist/crdt/text/index/shared.js +19 -19
- package/dist/crdt/text/model.d.ts +10 -0
- package/dist/crdt/text/model.js +10 -4
- package/dist/crdt/text/runs.d.ts +43 -42
- package/dist/crdt/text/runs.js +2 -165
- package/dist/crdt/vendor/yjs/UPSTREAM.md +83 -0
- package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
- package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +6 -3
- package/dist/crdt/vendor/yjs/dts/ynode.d.ts +13 -2
- package/dist/crdt/vendor/yjs/src/index.js +1 -1
- package/dist/crdt/vendor/yjs/src/structs/Item.js +44 -5
- package/dist/crdt/vendor/yjs/src/ynode.js +29 -7
- package/dist/edytor.svelte.d.ts +1 -1
- package/dist/edytor.svelte.js +100 -75
- package/dist/events/beforeInputCommands.d.ts +2 -2
- package/dist/events/domTextOffset.d.ts +2 -0
- package/dist/events/domTextOffset.js +8 -0
- package/dist/events/nativeInteractiveControl.d.ts +11 -1
- package/dist/events/nativeInteractiveControl.js +41 -1
- package/dist/events/onBeforeInput.js +3 -3
- package/dist/events/onFocus.js +9 -11
- package/dist/export/forms.d.ts +75 -75
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/labels.d.ts +8 -0
- package/dist/labels.js +6 -1
- package/dist/plugins/comments/CommentsController.svelte.d.ts +5 -1
- package/dist/plugins/comments/CommentsController.svelte.js +14 -4
- package/dist/plugins/find/search.js +2 -2
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +1 -0
- package/dist/plugins/richtext/RichTextPlugin.svelte +63 -61
- package/dist/plugins/richtext/richTextOperations.js +26 -32
- package/dist/plugins/suggestions/SuggestionBars.svelte +40 -23
- package/dist/plugins/suggestions/SuggestionBars.svelte.d.ts +3 -1
- package/dist/plugins/suggestions/SuggestionRuns.svelte +77 -0
- package/dist/plugins/suggestions/SuggestionRuns.svelte.d.ts +9 -0
- package/dist/plugins/suggestions/shared.svelte.d.ts +58 -0
- package/dist/plugins/suggestions/shared.svelte.js +421 -0
- package/dist/plugins/suggestions/suggestionsPlugin.d.ts +15 -4
- package/dist/selection/domSelection.d.ts +2 -0
- package/dist/selection/domSelection.js +6 -2
- package/dist/selection/pointer.svelte.js +75 -48
- package/dist/selection/replaceSelection.js +2 -6
- package/dist/selection/selection.svelte.d.ts +3 -3
- package/dist/selection/selection.svelte.js +39 -32
- package/dist/selection/selection.utils.d.ts +14 -0
- package/dist/selection/selection.utils.js +33 -11
- package/dist/session/commands.js +21 -11
- package/dist/session/composition.svelte.d.ts +5 -3
- package/dist/session/composition.svelte.js +21 -17
- package/dist/session/handles.d.ts +4 -17
- package/dist/session/handles.js +14 -44
- package/dist/session/navigation.js +6 -9
- package/dist/session/selection.d.ts +11 -5
- package/dist/session/selection.js +14 -48
- package/dist/session/suggestions.svelte.d.ts +38 -9
- package/dist/session/suggestions.svelte.js +37 -18
- package/dist/session/virtual.d.ts +1 -1
- package/dist/surface/attributes.d.ts +5 -0
- package/dist/surface/attributes.js +2 -2
- package/dist/surface/cells.d.ts +2 -26
- package/dist/surface/cells.js +2 -33
- package/dist/surface/observer.svelte.d.ts +6 -1
- package/dist/surface/observer.svelte.js +143 -111
- package/dist/surface/pin.svelte.d.ts +9 -9
- package/dist/surface/pin.svelte.js +15 -22
- package/dist/surface/projector.svelte.js +10 -16
- package/dist/text/text.svelte.js +14 -19
- package/dist/themes/notion.css +29 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +7 -0
- package/package.json +3 -1
- package/dist/crdt/doc/capability.d.ts +0 -56
- package/dist/crdt/doc/capability.js +0 -211
- package/dist/crdt/doc/content.d.ts +0 -16
- package/dist/crdt/doc/content.js +0 -77
- package/dist/crdt/doc/delete.d.ts +0 -15
- package/dist/crdt/doc/delete.js +0 -84
- package/dist/crdt/doc/layout.d.ts +0 -9
- package/dist/crdt/doc/layout.js +0 -178
- package/dist/crdt/doc/meta.d.ts +0 -19
- package/dist/crdt/doc/meta.js +0 -199
- package/dist/crdt/doc/moves.d.ts +0 -21
- package/dist/crdt/doc/moves.js +0 -274
- package/dist/crdt/doc/split-merge.d.ts +0 -10
- package/dist/crdt/doc/split-merge.js +0 -179
- package/dist/crdt/doc/steps.d.ts +0 -65
- package/dist/crdt/doc/steps.js +0 -311
- package/dist/crdt/text/index/cache.d.ts +0 -16
- package/dist/crdt/text/index/cache.js +0 -175
- package/dist/crdt/text/index/claims.d.ts +0 -18
- package/dist/crdt/text/index/claims.js +0 -225
- package/dist/crdt/text/index/fold.d.ts +0 -21
- package/dist/crdt/text/index/fold.js +0 -656
- package/dist/crdt/text/index/layout.d.ts +0 -24
- package/dist/crdt/text/index/layout.js +0 -271
- package/dist/crdt/text/index/placement.d.ts +0 -47
- package/dist/crdt/text/index/placement.js +0 -741
- package/dist/crdt/text/index/records.d.ts +0 -13
- package/dist/crdt/text/index/records.js +0 -139
- package/dist/crdt/text/index/report.d.ts +0 -18
- package/dist/crdt/text/index/report.js +0 -337
- package/dist/crdt/text/index/state.d.ts +0 -197
- package/dist/crdt/text/index/state.js +0 -116
- package/dist/crdt/text/index/streams.d.ts +0 -25
- package/dist/crdt/text/index/streams.js +0 -248
package/dist/crdt/flow.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { sanitizeSpec } from '../utils/json.js';
|
|
4
|
-
import { collides } from './placement/model.js';
|
|
5
|
-
import { TYPE } from './schema.js';
|
|
6
|
-
const lengthOf = (l) => (l.content ?? []).reduce((n, i) => n + (i.kind === 'text' ? i.text.length : 1), 0);
|
|
1
|
+
/** The units of a line's content (an atom counts 1). */
|
|
2
|
+
export const lengthOf = (l) => (l.content ?? []).reduce((n, i) => n + (i.kind === 'text' ? i.text.length : 1), 0);
|
|
7
3
|
/**
|
|
8
4
|
* Where the caret ends a placed block: its own content's end when it shows a
|
|
9
5
|
* line (renders its content, no void; a toggle's header, never its body),
|
|
@@ -14,7 +10,7 @@ const lengthOf = (l) => (l.content ?? []).reduce((n, i) => n + (i.kind === 'text
|
|
|
14
10
|
export const placedEnd = (roleOf) => {
|
|
15
11
|
const endOf = (s) => {
|
|
16
12
|
const role = roleOf(s.type);
|
|
17
|
-
if (role.rendersContent && !role.
|
|
13
|
+
if (role.rendersContent && !role.childless)
|
|
18
14
|
return { block: s.id, offset: lengthOf(s) };
|
|
19
15
|
for (const kid of [...(s.children ?? [])].reverse()) {
|
|
20
16
|
const at = endOf(kid);
|
|
@@ -25,265 +21,3 @@ export const placedEnd = (roleOf) => {
|
|
|
25
21
|
};
|
|
26
22
|
return endOf;
|
|
27
23
|
};
|
|
28
|
-
/** `insertFlow`, prepared. */
|
|
29
|
-
export const flowOps = (c) => {
|
|
30
|
-
/** A kind's roles, as placement reads them. */
|
|
31
|
-
const roleOf = (kind) => ({
|
|
32
|
-
void: c.roles.childless(kind),
|
|
33
|
-
island: c.roles.island(kind),
|
|
34
|
-
rendersContent: c.roles.rendersContent(kind),
|
|
35
|
-
layout: c.roles.layout(kind)
|
|
36
|
-
});
|
|
37
|
-
/** What a kind is in a table: the table, its row or its cell. */
|
|
38
|
-
const tableKind = (kind) => c.roles.table(kind) !== undefined
|
|
39
|
-
? 'table'
|
|
40
|
-
: c.isRowKind(kind)
|
|
41
|
-
? 'row'
|
|
42
|
-
: c.isCellKind(kind)
|
|
43
|
-
? 'cell'
|
|
44
|
-
: undefined;
|
|
45
|
-
return {
|
|
46
|
-
insertFlow: (target, flow, view = {}) => {
|
|
47
|
-
// Ingress: a run carries a placeholder kind through the spec sanitizer.
|
|
48
|
-
let lines = flow.lines
|
|
49
|
-
.map((l) => sanitizeSpec({ ...l, type: l.type ?? '' }))
|
|
50
|
-
.map((s) => ({ ...s, type: s.type || undefined }));
|
|
51
|
-
if (lines.length === 0)
|
|
52
|
-
return c.plan([], []);
|
|
53
|
-
// A cell outside a row is its text, a row outside a table its cells (`table.paste`).
|
|
54
|
-
const unbare = (l, holder) => {
|
|
55
|
-
const kind = l.type ? tableKind(l.type) : undefined;
|
|
56
|
-
const kids = (next) => (l.children ?? []).flatMap((kid) => unbare(kid, next));
|
|
57
|
-
if (kind === 'cell' && holder !== 'row')
|
|
58
|
-
return [{ id: l.id, content: l.content }, ...kids(null)];
|
|
59
|
-
if (kind === 'row' && holder !== 'table')
|
|
60
|
-
return kids(null);
|
|
61
|
-
if (!l.children)
|
|
62
|
-
return [l];
|
|
63
|
-
return [{ ...l, children: kids(kind === 'cell' ? null : (kind ?? null)) }];
|
|
64
|
-
};
|
|
65
|
-
lines = lines.flatMap((l) => unbare(l, null));
|
|
66
|
-
/** A line's kind under `parent`: the list's item for its flat item kind, then `fitted`. */
|
|
67
|
-
const fit = (parent, kind) => c.fitted(parent, parent !== null && kind !== undefined && kind === view.itemKind?.(parent)
|
|
68
|
-
? c.defaultChild(parent)
|
|
69
|
-
: kind);
|
|
70
|
-
const specs = (parent, of = lines) => of.map((l) => ({ ...l, type: fit(parent, l.type) ?? c.defaultChild(parent) }));
|
|
71
|
-
const last = () => lines.at(-1);
|
|
72
|
-
/** `l` and its nested lines as runs, each line that shows its own content one run. */
|
|
73
|
-
const plain = (l) => [
|
|
74
|
-
...(!l.type || roleOf(l.type).rendersContent ? [{ id: l.id, content: l.content }] : []),
|
|
75
|
-
...(l.children ?? []).flatMap(plain)
|
|
76
|
-
];
|
|
77
|
-
const endOf = placedEnd(roleOf);
|
|
78
|
-
/**
|
|
79
|
-
* A layout line, here or nested, as its items' lines in reading order, and
|
|
80
|
-
* any other child it holds (`flow.layout`): no layout lands in an item.
|
|
81
|
-
*/
|
|
82
|
-
const unwrap = (l) => {
|
|
83
|
-
const item = l.type ? roleOf(l.type).layout : undefined;
|
|
84
|
-
if (item === undefined)
|
|
85
|
-
return [l.children ? { ...l, children: l.children.flatMap(unwrap) } : l];
|
|
86
|
-
return (l.children ?? []).flatMap((kid) => kid.type === item ? (kid.children ?? []).flatMap(unwrap) : unwrap(kid));
|
|
87
|
-
};
|
|
88
|
-
const intoItem = (parent) => {
|
|
89
|
-
if (parent !== null && c.insideItem(parent))
|
|
90
|
-
lines = lines.flatMap(unwrap);
|
|
91
|
-
};
|
|
92
|
-
/** Whole blocks at a slot, after `pre`; the caret ends the last one's shown content. */
|
|
93
|
-
const atSlot = (dest, pre) => {
|
|
94
|
-
const placed = specs(dest.parent);
|
|
95
|
-
const p = c.insertBlocks(dest, placed);
|
|
96
|
-
const at = endOf(placed.at(-1)) ?? { block: last().id, offset: lengthOf(last()) };
|
|
97
|
-
// The lines are placed while the replaced blocks still show (each step reads the
|
|
98
|
-
// display as it stands), then those go.
|
|
99
|
-
return 'writes' in p ? { ...c.plan(p.ids, [...p.writes, ...pre]), at } : p;
|
|
100
|
-
};
|
|
101
|
-
if ('replace' in target || 'slot' in target) {
|
|
102
|
-
let slot;
|
|
103
|
-
let pre = [];
|
|
104
|
-
if ('slot' in target)
|
|
105
|
-
slot = target.slot;
|
|
106
|
-
else {
|
|
107
|
-
// The lines fill the first block's slot: its parent is never emptied
|
|
108
|
-
// by the delete, so a column keeps its layout (`layout.flow-slot`).
|
|
109
|
-
const at = c.view().order.at;
|
|
110
|
-
const first = target.replace
|
|
111
|
-
.filter((id) => at.has(id))
|
|
112
|
-
.sort((a, b) => at.get(a) - at.get(b))[0];
|
|
113
|
-
const del = c.deleteBlocks(target.replace, false, first === undefined ? undefined : c.positionOf(first)?.parent);
|
|
114
|
-
if (!('writes' in del))
|
|
115
|
-
return del;
|
|
116
|
-
if (first === undefined)
|
|
117
|
-
return c.REFUSED;
|
|
118
|
-
slot = c.positionOf(first);
|
|
119
|
-
pre = [...del.writes];
|
|
120
|
-
}
|
|
121
|
-
intoItem(slot.parent);
|
|
122
|
-
if (lines.length === 0)
|
|
123
|
-
return c.plan([], []);
|
|
124
|
-
// In a code block (selected lines, a slot), the lines are plain lines too (`flow.lines`).
|
|
125
|
-
if (slot.parent !== null && c.isLines(slot.parent)) {
|
|
126
|
-
const shown = lines.flatMap(plain);
|
|
127
|
-
lines = shown.length ? shown : [{ id: lines[0].id, content: [] }];
|
|
128
|
-
}
|
|
129
|
-
return atSlot(slot, pre);
|
|
130
|
-
}
|
|
131
|
-
const B = ref(target.block);
|
|
132
|
-
if (!c.contentTarget(B) || !c.rendersContent(B))
|
|
133
|
-
return c.REFUSED;
|
|
134
|
-
const len = c.displayLength(B);
|
|
135
|
-
const o = Math.max(0, Math.min(target.offset, len));
|
|
136
|
-
const { parent, index } = c.positionOf(B);
|
|
137
|
-
intoItem(B);
|
|
138
|
-
const empty = len === 0 && c.childrenIds(B).length === 0;
|
|
139
|
-
// A line of a lines island (a code line) takes plain lines: every line the flow
|
|
140
|
-
// shows, nested ones included, in order; no block lands in the island (`flow.lines`).
|
|
141
|
-
const inLines = parent !== null && c.isLines(parent);
|
|
142
|
-
if (inLines)
|
|
143
|
-
lines = lines.flatMap(plain);
|
|
144
|
-
// A table's cell is never split: the lines it shows join its text (`table.paste`).
|
|
145
|
-
const cell = c.isTableCell(B);
|
|
146
|
-
if (cell)
|
|
147
|
-
lines = lines.flatMap(plain);
|
|
148
|
-
// A line that joins no text under `under` (`flow.apart`): its kind renders
|
|
149
|
-
// none of its own (a list, a code block), or is a void or an island.
|
|
150
|
-
const apart = (l, under) => {
|
|
151
|
-
const kind = l.type && fit(under, l.type);
|
|
152
|
-
const role = kind ? roleOf(kind) : undefined;
|
|
153
|
-
return !!role && (!role.rendersContent || role.void || role.island);
|
|
154
|
-
};
|
|
155
|
-
// At the end of a container's header whose body shows, what follows the caret
|
|
156
|
-
// leads its children and the body stays, as Enter opens a first child
|
|
157
|
-
// (`flow.header`), unless the first line stands apart and replaces an empty
|
|
158
|
-
// one (`flow.apart`); elsewhere it follows `B` among its siblings.
|
|
159
|
-
const header = view.header?.(B);
|
|
160
|
-
// A closed header shows no children: a line it takes brings none into its hidden
|
|
161
|
-
// body; they follow it, shown (`flow.header`).
|
|
162
|
-
const shut = header === 'closed';
|
|
163
|
-
const inside = o === len && !inLines && !flow.whole && header === true && !(empty && apart(lines[0], B));
|
|
164
|
-
const home = inside ? B : parent;
|
|
165
|
-
if (lines.length === 0)
|
|
166
|
-
return { ...c.plan([B], []), at: { block: B, offset: o } };
|
|
167
|
-
if (flow.whole && !inLines && !cell)
|
|
168
|
-
return atSlot({ parent, index: index + 1 }, empty ? [c.remove(B, [])] : []);
|
|
169
|
-
// A void is never split: its caption takes the lines as one run; nor is a cell.
|
|
170
|
-
const br = { kind: 'text', text: '\n' };
|
|
171
|
-
if (c.isVoid(B) || cell) {
|
|
172
|
-
const content = lines.flatMap((l, i) => [...(i ? [br] : []), ...(l.content ?? [])]);
|
|
173
|
-
lines = [{ id: lines[0].id, content }];
|
|
174
|
-
}
|
|
175
|
-
// So a first line it joins leaves its nested lines as lines of the flow after it.
|
|
176
|
-
if (shut && lines[0].children?.length && !apart(lines[0], home))
|
|
177
|
-
lines = [{ ...lines[0], children: undefined }, ...lines[0].children, ...lines.slice(1)];
|
|
178
|
-
const first = lines[0];
|
|
179
|
-
const [joinsHead, joinsTail] = [
|
|
180
|
-
!apart(first, home),
|
|
181
|
-
lines.length > 1 && !apart(last(), home)
|
|
182
|
-
];
|
|
183
|
-
const all = specs(home);
|
|
184
|
-
const placed = all.slice(joinsHead ? 1 : 0, joinsTail ? -1 : undefined);
|
|
185
|
-
const ids = placed.map((s) => s.id);
|
|
186
|
-
if (collides(c.doc, [
|
|
187
|
-
...(joinsHead ? (first.children ?? []) : []),
|
|
188
|
-
...all.slice(joinsHead ? 1 : 0)
|
|
189
|
-
]))
|
|
190
|
-
return c.REFUSED;
|
|
191
|
-
const writes = [];
|
|
192
|
-
/** A joined line's children lead the block it joins; `moved` follow them. */
|
|
193
|
-
const kids = (to, l, moved = []) => {
|
|
194
|
-
const k = l?.children?.length ?? 0;
|
|
195
|
-
if (k)
|
|
196
|
-
writes.push({ op: 'insertBlocks', parent: to, index: 0, specs: l.children });
|
|
197
|
-
if (moved.length)
|
|
198
|
-
writes.push({ op: 'moveBlocks', ids: moved, parent: to, index: k });
|
|
199
|
-
};
|
|
200
|
-
/**
|
|
201
|
-
* `l` joins `B` at `at`: its content, its kind when `B` shows no text (a header
|
|
202
|
-
* keeps its own, as Enter does), its children first.
|
|
203
|
-
*/
|
|
204
|
-
const join = (l, at) => {
|
|
205
|
-
const end = c.writeContent(writes, B, at, l.content);
|
|
206
|
-
const kind = l.type && fit(parent, l.type);
|
|
207
|
-
if (len === 0 && !header && kind && kind === l.type)
|
|
208
|
-
writes.push(...c.attr(B, TYPE, kind), ...(c.dataSteps(B, c.replaceData(l.data ?? {})) ?? []));
|
|
209
|
-
if (!shut)
|
|
210
|
-
kids(B, l);
|
|
211
|
-
return end;
|
|
212
|
-
};
|
|
213
|
-
/** The placed lines at `at` under `home` (`split`: the tail of the split they come with). */
|
|
214
|
-
const place = (at, split) => {
|
|
215
|
-
if (placed.length)
|
|
216
|
-
writes.push({
|
|
217
|
-
op: 'insertBlocks',
|
|
218
|
-
parent: home,
|
|
219
|
-
index: at,
|
|
220
|
-
specs: placed,
|
|
221
|
-
...(split !== undefined && { split })
|
|
222
|
-
});
|
|
223
|
-
};
|
|
224
|
-
// Under a header, the first line's children, the placed lines and the rest, in order.
|
|
225
|
-
const k = joinsHead ? (first.children?.length ?? 0) : 0;
|
|
226
|
-
const slot = inside ? k : index + 1;
|
|
227
|
-
// Where the placed lines end the caret: after their last shown line (`flow.apart`).
|
|
228
|
-
const end = placed.length ? endOf(placed.at(-1)) : undefined;
|
|
229
|
-
// Nothing before the position and the first line stands apart: the lines go before `B`,
|
|
230
|
-
// which keeps its text and takes a joining last line, or goes when empty and not needed.
|
|
231
|
-
if (!joinsHead && o === 0 && !inside) {
|
|
232
|
-
place(index);
|
|
233
|
-
if (joinsTail) {
|
|
234
|
-
const at = join(last(), 0);
|
|
235
|
-
// A closed header's taken line's nested lines follow it, the caret ending them.
|
|
236
|
-
const after = shut ? specs(parent, last().children ?? []) : [];
|
|
237
|
-
if (after.length) {
|
|
238
|
-
const slot = index + placed.length + 1;
|
|
239
|
-
writes.push({ op: 'insertBlocks', parent, index: slot, specs: after });
|
|
240
|
-
}
|
|
241
|
-
const caret = after.length ? endOf(after.at(-1)) : undefined;
|
|
242
|
-
const touched = [...ids, B, ...after.map((s) => s.id)];
|
|
243
|
-
return { ...c.plan(touched, writes), at: caret ?? { block: B, offset: at } };
|
|
244
|
-
}
|
|
245
|
-
if (empty && end)
|
|
246
|
-
return { ...c.plan(ids, [...writes, c.remove(B, [])]), at: end };
|
|
247
|
-
return { ...c.plan([...ids, B], writes), at: end ?? { block: B, offset: 0 } };
|
|
248
|
-
}
|
|
249
|
-
const head = joinsHead ? join(first, o) : o;
|
|
250
|
-
if (lines.length === 1 && joinsHead)
|
|
251
|
-
return { ...c.plan([B], writes), at: { block: B, offset: head } };
|
|
252
|
-
const moved = inside ? [] : c.childrenIds(B).filter((id) => !view.hidden?.(id));
|
|
253
|
-
// Nothing after the position to keep, and the caret has a line: no split.
|
|
254
|
-
if (!joinsTail && o === len && moved.length === 0 && end) {
|
|
255
|
-
place(slot);
|
|
256
|
-
return { ...c.plan([B, ...ids], writes), at: end };
|
|
257
|
-
}
|
|
258
|
-
// The rest of `B` stays in a shown line: the last line's block when it joins, else
|
|
259
|
-
// a line of `B`'s kind, as Enter makes; one made only for the caret (after a
|
|
260
|
-
// divider at the end) or under a header is a fresh line of its parent's default kind.
|
|
261
|
-
const T = joinsTail ? last().id : freshId('b');
|
|
262
|
-
const lastType = joinsTail && last().type && fit(home, last().type);
|
|
263
|
-
const bare = !joinsTail && o === len && moved.length === 0;
|
|
264
|
-
const tail = lastType
|
|
265
|
-
? { type: lastType, data: last().data }
|
|
266
|
-
: bare || inside
|
|
267
|
-
? { type: c.defaultChild(home), data: {} }
|
|
268
|
-
: { type: c.kindToCopy(B), data: c.blockDataOf(B) };
|
|
269
|
-
// After `B` (under a header: after the first line's children); the placed lines go before it.
|
|
270
|
-
const length = len - o;
|
|
271
|
-
writes.push({
|
|
272
|
-
op: 'splitBlock',
|
|
273
|
-
id: B,
|
|
274
|
-
offset: head,
|
|
275
|
-
length,
|
|
276
|
-
newId: T,
|
|
277
|
-
tail,
|
|
278
|
-
parent: home,
|
|
279
|
-
index: slot
|
|
280
|
-
});
|
|
281
|
-
kids(T, joinsTail ? last() : undefined, moved);
|
|
282
|
-
place(slot, T);
|
|
283
|
-
const at = joinsTail
|
|
284
|
-
? { block: T, offset: c.writeContent(writes, T, 0, last().content) }
|
|
285
|
-
: (end ?? { block: T, offset: 0 });
|
|
286
|
-
return { ...c.plan([B, ...ids, T], writes), at };
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
};
|