edytor 3.0.0 → 5.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 +23 -12
- package/dist/cloudflare/DocumentRoom.js +10 -6
- 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 +139 -129
- package/dist/cloudflare/room/context.js +11 -4
- 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.d.ts +6 -3
- package/dist/cloudflare/room/purge.js +45 -19
- 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/room/updates.d.ts +3 -4
- package/dist/cloudflare/room/updates.js +6 -8
- 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 +34 -12
- package/dist/crdt/attribution/attribution.js +59 -21
- package/dist/crdt/attribution/block.d.ts +3 -3
- package/dist/crdt/attribution/block.js +7 -8
- package/dist/crdt/attribution/index.d.ts +1 -1
- package/dist/crdt/attribution/index.js +1 -1
- package/dist/crdt/data.d.ts +62 -31
- package/dist/crdt/data.js +211 -103
- package/dist/crdt/doc/capability.js +9 -13
- package/dist/crdt/doc/delete.d.ts +1 -1
- package/dist/crdt/doc/delete.js +13 -30
- package/dist/crdt/doc/funnel.d.ts +1 -1
- package/dist/crdt/doc/funnel.js +34 -26
- package/dist/crdt/doc/gate.d.ts +3 -3
- package/dist/crdt/doc/history.d.ts +31 -9
- package/dist/crdt/doc/history.js +204 -73
- package/dist/crdt/doc/layout.js +16 -27
- package/dist/crdt/doc/meta.js +17 -23
- package/dist/crdt/doc/moves.d.ts +1 -1
- package/dist/crdt/doc/moves.js +52 -32
- package/dist/crdt/doc/reads.d.ts +2 -2
- package/dist/crdt/doc/reads.js +20 -30
- package/dist/crdt/doc/seed.js +2 -2
- package/dist/crdt/doc/split-merge.js +12 -15
- package/dist/crdt/doc/steps.d.ts +25 -13
- package/dist/crdt/doc/steps.js +55 -125
- package/dist/crdt/doc/suggest.d.ts +167 -0
- package/dist/crdt/doc/suggest.js +579 -0
- package/dist/crdt/doc/types.d.ts +21 -9
- package/dist/crdt/document.d.ts +26 -6
- package/dist/crdt/document.js +40 -15
- package/dist/crdt/edytor-doc.d.ts +410 -390
- package/dist/crdt/edytor-doc.js +143 -95
- package/dist/crdt/engine-api.d.ts +39 -1
- package/dist/crdt/engine.d.ts +2 -2
- package/dist/crdt/engine.js +4 -5
- package/dist/crdt/flow.d.ts +2 -2
- package/dist/crdt/flow.js +29 -37
- package/dist/crdt/index.d.ts +134 -127
- package/dist/crdt/index.js +4 -1
- package/dist/crdt/operations.d.ts +12 -3
- package/dist/crdt/parts.d.ts +43 -0
- package/dist/crdt/parts.js +44 -0
- package/dist/crdt/placement/display.d.ts +6 -31
- package/dist/crdt/placement/display.js +41 -146
- package/dist/crdt/placement/keys.d.ts +63 -0
- package/dist/crdt/placement/keys.js +95 -0
- package/dist/crdt/placement/model.d.ts +119 -118
- package/dist/crdt/placement/model.js +242 -142
- package/dist/crdt/placement/resolve.d.ts +123 -35
- package/dist/crdt/placement/resolve.js +188 -153
- package/dist/crdt/placement/slots.d.ts +134 -0
- package/dist/crdt/placement/slots.js +152 -0
- 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/comments.d.ts +16 -1
- package/dist/crdt/protocols/comments.js +9 -1
- package/dist/crdt/providers/index.d.ts +6 -4
- package/dist/crdt/providers/index.js +3 -1
- package/dist/crdt/providers/room.d.ts +16 -2
- package/dist/crdt/providers/room.js +64 -17
- package/dist/crdt/providers/websocket.d.ts +6 -4
- package/dist/crdt/providers/websocket.js +14 -7
- package/dist/crdt/purge.d.ts +24 -9
- package/dist/crdt/purge.js +266 -126
- package/dist/crdt/restore.d.ts +4 -3
- package/dist/crdt/restore.js +27 -34
- package/dist/crdt/schema.d.ts +30 -21
- package/dist/crdt/schema.js +39 -23
- package/dist/crdt/storage.d.ts +1 -1
- package/dist/crdt/storage.js +1 -1
- package/dist/crdt/structs.d.ts +17 -15
- package/dist/crdt/structs.js +10 -22
- package/dist/crdt/text/index/cache.js +4 -0
- package/dist/crdt/text/index/claims.js +13 -23
- package/dist/crdt/text/index/fold.d.ts +2 -3
- package/dist/crdt/text/index/fold.js +194 -44
- package/dist/crdt/text/index/layout.d.ts +2 -4
- package/dist/crdt/text/index/layout.js +14 -30
- package/dist/crdt/text/index/placement.d.ts +26 -18
- package/dist/crdt/text/index/placement.js +420 -157
- package/dist/crdt/text/index/records.d.ts +3 -3
- package/dist/crdt/text/index/records.js +24 -31
- package/dist/crdt/text/index/shared.d.ts +11 -3
- package/dist/crdt/text/index/shared.js +29 -17
- package/dist/crdt/text/index/state.d.ts +21 -17
- package/dist/crdt/text/index/state.js +15 -17
- package/dist/crdt/text/index/streams.d.ts +10 -5
- package/dist/crdt/text/index/streams.js +78 -27
- package/dist/crdt/text/items.d.ts +10 -3
- package/dist/crdt/text/items.js +7 -0
- package/dist/crdt/text/model.d.ts +87 -62
- package/dist/crdt/text/model.js +91 -169
- package/dist/crdt/text/ranges.d.ts +1 -1
- package/dist/crdt/text/ranges.js +3 -3
- package/dist/crdt/text/rows.d.ts +13 -7
- package/dist/crdt/text/rows.js +24 -7
- package/dist/crdt/text/runs.d.ts +51 -42
- package/dist/crdt/text/runs.js +24 -7
- package/dist/crdt/text/streams.d.ts +26 -13
- package/dist/crdt/text/streams.js +41 -14
- package/dist/crdt/vendor/yjs/UPSTREAM.md +651 -21
- package/dist/crdt/vendor/yjs/dts/global.d.ts +2 -0
- package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
- package/dist/crdt/vendor/yjs/dts/structs/AbstractStruct.d.ts +7 -0
- package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +197 -10
- package/dist/crdt/vendor/yjs/dts/utils/Doc.d.ts +6 -3
- package/dist/crdt/vendor/yjs/dts/utils/StructStore.d.ts +5 -18
- package/dist/crdt/vendor/yjs/dts/utils/Transaction.d.ts +15 -1
- package/dist/crdt/vendor/yjs/dts/utils/UpdateDecoder.d.ts +14 -6
- package/dist/crdt/vendor/yjs/dts/utils/UpdateEncoder.d.ts +33 -6
- package/dist/crdt/vendor/yjs/dts/utils/ids.d.ts +1 -65
- package/dist/crdt/vendor/yjs/dts/utils/marks.d.ts +6 -1
- package/dist/crdt/vendor/yjs/dts/ynode.d.ts +54 -7
- package/dist/crdt/vendor/yjs/global.d.ts +2 -0
- package/dist/crdt/vendor/yjs/src/index.js +1 -1
- package/dist/crdt/vendor/yjs/src/structs/AbstractStruct.js +10 -0
- package/dist/crdt/vendor/yjs/src/structs/Item.js +649 -51
- package/dist/crdt/vendor/yjs/src/utils/BlockSet.js +18 -9
- package/dist/crdt/vendor/yjs/src/utils/Doc.js +5 -3
- package/dist/crdt/vendor/yjs/src/utils/StructStore.js +5 -0
- package/dist/crdt/vendor/yjs/src/utils/Transaction.js +36 -13
- package/dist/crdt/vendor/yjs/src/utils/UpdateDecoder.js +88 -18
- package/dist/crdt/vendor/yjs/src/utils/UpdateEncoder.js +119 -32
- package/dist/crdt/vendor/yjs/src/utils/encoding.js +13 -1
- package/dist/crdt/vendor/yjs/src/utils/ids.js +7 -7
- package/dist/crdt/vendor/yjs/src/utils/marks.js +193 -8
- package/dist/crdt/vendor/yjs/src/utils/redo.js +1 -1
- package/dist/crdt/vendor/yjs/src/utils/transaction-helpers.js +1 -1
- package/dist/crdt/vendor/yjs/src/utils/updates.js +3 -3
- package/dist/crdt/vendor/yjs/src/ynode.js +199 -12
- package/dist/edytor.svelte.d.ts +1 -1
- package/dist/edytor.svelte.js +103 -75
- package/dist/events/beforeInputCommands.d.ts +2 -2
- package/dist/events/beforeInputCommands.js +2 -2
- 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/events/onPageHide.d.ts +3 -0
- package/dist/events/onPageHide.js +16 -0
- package/dist/export/forms.d.ts +50 -50
- 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/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 +28 -3
- 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 +11 -37
- 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 +130 -83
- package/dist/surface/pin.svelte.d.ts +9 -9
- package/dist/surface/pin.svelte.js +15 -22
- package/dist/surface/projector.svelte.d.ts +15 -3
- package/dist/surface/projector.svelte.js +67 -22
- package/dist/text/text.svelte.js +14 -19
- package/dist/themes/notion.css +29 -0
- package/package.json +4 -2
- package/dist/crdt/placement/rank.d.ts +0 -87
- package/dist/crdt/placement/rank.js +0 -332
- package/dist/crdt/placement/source.d.ts +0 -43
- package/dist/crdt/placement/source.js +0 -66
- package/dist/crdt/text/delete-index.d.ts +0 -129
- package/dist/crdt/text/delete-index.js +0 -365
- package/dist/crdt/text/deletes.d.ts +0 -76
- package/dist/crdt/text/deletes.js +0 -362
- package/dist/crdt/text/index/anchored.d.ts +0 -17
- package/dist/crdt/text/index/anchored.js +0 -197
package/dist/crdt/doc/steps.d.ts
CHANGED
|
@@ -1,28 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The step writers every prepared op composes: the plan itself, moves (a
|
|
3
|
+
* move's place and side), type steps and the kind a block shows where it
|
|
4
|
+
* lands (`settle`), the containers and layouts a write leaves empty
|
|
5
|
+
* (`emptying`, `dissolving`), delete and merge steps, and display spans of a
|
|
6
|
+
* block's content.
|
|
7
|
+
*/
|
|
1
8
|
import { TYPE } from '../schema.js';
|
|
2
9
|
import { type BlockId, type ContentItem } from '../placement/model.js';
|
|
3
10
|
import type { Plan, PlanStep } from './types.js';
|
|
4
11
|
import type { DocBase, DocReads } from './reads.js';
|
|
5
12
|
import type { DocCapability } from './capability.js';
|
|
6
13
|
/** What the step writers read: the reads and the structural capability. */
|
|
14
|
+
/**
|
|
15
|
+
* A record's order among the records standing at one block, for the
|
|
16
|
+
* engine's sort of two records at one origin (fork patch YP22): what a split
|
|
17
|
+
* of a list around a block writes there — a new head list holding the items
|
|
18
|
+
* before it (`head`), new blocks placed after the items before it, which
|
|
19
|
+
* stay (`kept`), a head holding those items and the block (`with`), the
|
|
20
|
+
* block itself leaving (`self`), new blocks after it (`after`) — in the
|
|
21
|
+
* order every serial run of the gestures gives (`del.merge.container`).
|
|
22
|
+
*/
|
|
23
|
+
export declare const PART: {
|
|
24
|
+
readonly head: 0;
|
|
25
|
+
readonly kept: 1;
|
|
26
|
+
readonly with: 2;
|
|
27
|
+
readonly self: 3;
|
|
28
|
+
readonly after: 4;
|
|
29
|
+
};
|
|
7
30
|
export type StepsContext = DocBase & DocReads & DocCapability;
|
|
8
31
|
/** The step writers of one facade. */
|
|
9
32
|
export declare const planSteps: (c: StepsContext) => {
|
|
10
33
|
REFUSED: import("./types.js").OpResult;
|
|
11
|
-
HEAD: number;
|
|
12
|
-
KEPT: number;
|
|
13
|
-
WITH: number;
|
|
14
|
-
SELF: number;
|
|
15
|
-
AFTER: number;
|
|
16
34
|
plan: (ids: readonly BlockId[], writes: PlanStep[]) => Plan;
|
|
17
|
-
|
|
18
|
-
moveTo: (ids: BlockId[], parent: BlockId | null, index: number, ranks: string[]) => PlanStep[];
|
|
35
|
+
moveTo: (ids: BlockId[], parent: BlockId | null, index: number, side?: 0 | 1, at?: BlockId, part?: number) => PlanStep[];
|
|
19
36
|
move: (ids: BlockId[], parent: BlockId | null, index: number) => PlanStep[];
|
|
20
|
-
|
|
21
|
-
at: BlockId;
|
|
22
|
-
part: readonly number[];
|
|
23
|
-
}[]) => string[];
|
|
24
|
-
pieceRanks: (id: BlockId, at: number, count: number) => string[];
|
|
25
|
-
leaving: (outer: BlockId, after: boolean, ids: readonly BlockId[]) => string[];
|
|
37
|
+
leaving: (after: boolean) => 0 | 1;
|
|
26
38
|
attr: (id: BlockId, key: typeof TYPE, value: string) => PlanStep[];
|
|
27
39
|
leavingIsland: (island: BlockId, kind: string | undefined, to: string) => string | undefined;
|
|
28
40
|
settledKind: (from: BlockId | null, kid: BlockId, parent: BlockId | null) => string | undefined;
|
package/dist/crdt/doc/steps.js
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The step writers every prepared op composes: the plan itself,
|
|
3
|
-
* move's
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* The step writers every prepared op composes: the plan itself, moves (a
|
|
3
|
+
* move's place and side), type steps and the kind a block shows where it
|
|
4
|
+
* lands (`settle`), the containers and layouts a write leaves empty
|
|
5
|
+
* (`emptying`, `dissolving`), delete and merge steps, and display spans of a
|
|
6
|
+
* block's content.
|
|
7
7
|
*/
|
|
8
|
-
import { randOf } from '../rand.js';
|
|
9
8
|
import { TYPE } from '../schema.js';
|
|
10
|
-
import { blockNodeOf
|
|
9
|
+
import { blockNodeOf } from '../placement/model.js';
|
|
11
10
|
import { REFUSED, effectOf } from './plan.js';
|
|
11
|
+
/** What the step writers read: the reads and the structural capability. */
|
|
12
|
+
/**
|
|
13
|
+
* A record's order among the records standing at one block, for the
|
|
14
|
+
* engine's sort of two records at one origin (fork patch YP22): what a split
|
|
15
|
+
* of a list around a block writes there — a new head list holding the items
|
|
16
|
+
* before it (`head`), new blocks placed after the items before it, which
|
|
17
|
+
* stay (`kept`), a head holding those items and the block (`with`), the
|
|
18
|
+
* block itself leaving (`self`), new blocks after it (`after`) — in the
|
|
19
|
+
* order every serial run of the gestures gives (`del.merge.container`).
|
|
20
|
+
*/
|
|
21
|
+
export const PART = { head: 0, kept: 1, with: 2, self: 3, after: 4 };
|
|
12
22
|
/** The step writers of one facade. */
|
|
13
23
|
export const planSteps = (c) => {
|
|
14
|
-
const { doc, runsView, roles,
|
|
24
|
+
const { doc, runsView, roles, view, blockTypeOf, childrenIds, positionOf, ancestorsOf, isLines, isIsland, itemKindOf, isLayout, displayLength, contentItems, live, isContainer, fitted, emptiable, defaultChild } = c;
|
|
15
25
|
// ── prepared ops ─────────────────────────────────────────────
|
|
16
26
|
// Every op is `prepare` (pure: `refused`, or a plan of named steps plus
|
|
17
27
|
// its effect summary, against the current version) then `apply(plan)`;
|
|
@@ -19,124 +29,52 @@ export const planSteps = (c) => {
|
|
|
19
29
|
// whole command before any write and a refusal refuses before one.
|
|
20
30
|
// Each prepare normalizes its inputs once, here at ingress: ids
|
|
21
31
|
// and strings as the wire would deliver them, payloads cloned.
|
|
22
|
-
/** `exitRanks` parts, in their order at one block. */
|
|
23
|
-
const [HEAD, KEPT, WITH, SELF, AFTER] = [0, 1, 2, 3, 5];
|
|
24
32
|
const plan = (ids, writes) => ({
|
|
25
33
|
ids,
|
|
26
34
|
writes,
|
|
27
35
|
effect: effectOf(writes),
|
|
28
36
|
version: runsView.version()
|
|
29
37
|
});
|
|
30
|
-
/** This client's next clock: what its source ranks are tied by (`sourceRank`). */
|
|
31
|
-
const clock = () => doc.store?.getClock(doc.clientID) ?? 0;
|
|
32
|
-
/**
|
|
33
|
-
* `count` ranks at `index` among `parent`'s children, the moving
|
|
34
|
-
* `exclude` left out. `run`: new blocks, which extend this client's run
|
|
35
|
-
* after a block it ranked (`order.insert.run`); a move never does
|
|
36
|
-
* (the rank-growth guard).
|
|
37
|
-
*/
|
|
38
|
-
const ranksFor = (parent, index, count, exclude = [], run = false) => {
|
|
39
|
-
const v = view();
|
|
40
|
-
const all = v.kids.get(parent) ?? [];
|
|
41
|
-
// The moving blocks' own slots left out: index → the list's index past them.
|
|
42
|
-
const gone = exclude
|
|
43
|
-
.map((id) => positionInView(v, id))
|
|
44
|
-
.filter((p) => p !== null && p.parent === parent)
|
|
45
|
-
.map((p) => p.index)
|
|
46
|
-
.sort((a, b) => a - b);
|
|
47
|
-
const raw = (i) => {
|
|
48
|
-
for (const g of gone)
|
|
49
|
-
if (g <= i)
|
|
50
|
-
i++;
|
|
51
|
-
return i;
|
|
52
|
-
};
|
|
53
|
-
const at = Math.max(0, Math.min(index, all.length - gone.length));
|
|
54
|
-
const pair = [at > 0 ? all[raw(at - 1)] : undefined, all[raw(at)]];
|
|
55
|
-
return ranksAt(pair, 1, count, doc.clientID, randOf(doc), run);
|
|
56
|
-
};
|
|
57
38
|
/**
|
|
58
|
-
* Move `ids` to `
|
|
39
|
+
* Move `ids` to display index `index` among `parent`'s children (the
|
|
40
|
+
* slot hooks see). `side`: the move record's class among the items of
|
|
41
|
+
* its origin (`placement/slots.ts`) — `0`, the blocks stand after what
|
|
42
|
+
* precedes them (a move; blocks leaving a block for the gap after it:
|
|
43
|
+
* its children, a list's last items); `1`, before what follows them
|
|
44
|
+
* (blocks leaving a block for the gap before it: a list's first item
|
|
45
|
+
* lifted out). In one gap every serial order of the gestures puts a
|
|
46
|
+
* split's pieces first, then the after-records, then the before-records
|
|
47
|
+
* (`del.merge.container`), which the engine's sort gives whatever the
|
|
48
|
+
* client ids.
|
|
59
49
|
* Every planned move carries the type steps that keep what the moved
|
|
60
50
|
* blocks show: one displayed out of an island as another kind than its
|
|
61
51
|
* stored one (`displayType`) gets that kind written, so leaving the
|
|
62
52
|
* island's slot never brings the island's child kind back.
|
|
53
|
+
* `at`, `part`: the block the record stands at and its order among the
|
|
54
|
+
* records standing there, for the engine's sort of two records at one
|
|
55
|
+
* origin (`PART`; by default the first moved block, as itself).
|
|
63
56
|
*/
|
|
64
|
-
const moveTo = (ids, parent, index,
|
|
57
|
+
const moveTo = (ids, parent, index, side = 0, at, part) => ids.length === 0
|
|
65
58
|
? []
|
|
66
59
|
: [
|
|
67
|
-
{
|
|
60
|
+
{
|
|
61
|
+
op: 'moveBlocks',
|
|
62
|
+
ids,
|
|
63
|
+
parent,
|
|
64
|
+
index,
|
|
65
|
+
...(side === 1 && { side }),
|
|
66
|
+
...(at !== undefined && { at }),
|
|
67
|
+
...(part !== undefined && { part })
|
|
68
|
+
},
|
|
68
69
|
...ids.flatMap((id) => {
|
|
69
70
|
const shown = runsView.displayType(id);
|
|
70
71
|
return shown === undefined ? [] : attr(id, TYPE, shown);
|
|
71
72
|
})
|
|
72
73
|
];
|
|
73
74
|
/** Move `ids` to `index` among `parent`'s children. */
|
|
74
|
-
const move = (ids, parent, index) => moveTo(ids, parent, index
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
* right after it), in the order they come from (`sourceRank`):
|
|
78
|
-
* two peers that split or lift out of the same list at once keep the
|
|
79
|
-
* text in its order, whatever their client ids. Each part names the
|
|
80
|
-
* block in `outer` it stands at (`at`; one that shows no text of its
|
|
81
|
-
* own, a list, stands at its first item) and its `part` there:
|
|
82
|
-
* - `HEAD`: a new list holding the items before `at`;
|
|
83
|
-
* - `KEPT`, index: a block placed after the items before `at`, which
|
|
84
|
-
* stay (a divider inserted after an item: a peer's head that takes
|
|
85
|
-
* them sorts before it);
|
|
86
|
-
* - `WITH`: a new list holding the items before `at` and `at` (`keep`);
|
|
87
|
-
* - `SELF`: `at` itself leaving (`SELF + 1` when it stands at its first item);
|
|
88
|
-
* - `AFTER`, index: a block placed after it.
|
|
89
|
-
* A degenerate gap ranks them as any insert.
|
|
90
|
-
*/
|
|
91
|
-
const exitRanks = (outer, after, parts) => {
|
|
92
|
-
const { kids } = view();
|
|
93
|
-
const { parent, index } = positionOf(outer);
|
|
94
|
-
const sibs = kids.get(parent) ?? [];
|
|
95
|
-
const gap = after ? index + 1 : index;
|
|
96
|
-
const ranks = [];
|
|
97
|
-
for (let { at, part } of parts) {
|
|
98
|
-
const own = at;
|
|
99
|
-
while (!rendersContent(at) && childrenIds(at).length > 0)
|
|
100
|
-
at = childrenIds(at)[0];
|
|
101
|
-
if (part[0] === SELF && at !== own)
|
|
102
|
-
part = [SELF + 1];
|
|
103
|
-
const path = [];
|
|
104
|
-
for (let c = at; c !== outer; c = positionOf(c).parent) {
|
|
105
|
-
const pos = positionOf(c);
|
|
106
|
-
path.unshift(kids.get(pos.parent)[pos.index].rank);
|
|
107
|
-
}
|
|
108
|
-
const side = after ? SOURCE_SIDE.after : SOURCE_SIDE.before;
|
|
109
|
-
const rank = sourceRank(sibs[gap - 1]?.rank, sibs[gap]?.rank, side, path, part, doc.clientID, clock());
|
|
110
|
-
if (rank === null)
|
|
111
|
-
return ranksFor(parent, gap, parts.length);
|
|
112
|
-
ranks.push(rank);
|
|
113
|
-
}
|
|
114
|
-
return ranks;
|
|
115
|
-
};
|
|
116
|
-
/**
|
|
117
|
-
* Ranks for the `count` blocks a split of `id` at `at` puts right after
|
|
118
|
-
* it (Enter, a paste of several lines), by where it splits
|
|
119
|
-
* (SW12-crdt-1, SW12-crdt-4): two peers splitting one block at once
|
|
120
|
-
* keep its pieces in text order, whatever their client ids. Counted
|
|
121
|
-
* from the end — the text after the split point, most first — so a
|
|
122
|
-
* peer's own edit before its split point (typing, then Enter; a paste
|
|
123
|
-
* over a selection) does not move it; an unseen edit after
|
|
124
|
-
* it does (the residual, in the delete contract).
|
|
125
|
-
*/
|
|
126
|
-
const pieceRanks = (id, at, count) => {
|
|
127
|
-
const { parent, index } = positionOf(id);
|
|
128
|
-
const sibs = view().kids.get(parent) ?? [];
|
|
129
|
-
const ranks = [];
|
|
130
|
-
for (let i = 0; i < count; i++) {
|
|
131
|
-
const rank = sourceRank(sibs[index]?.rank, sibs[index + 1]?.rank, SOURCE_SIDE.pieces, [], [at - displayLength(id), i], doc.clientID, clock());
|
|
132
|
-
if (rank === null)
|
|
133
|
-
return ranksFor(parent, index + 1, count);
|
|
134
|
-
ranks.push(rank);
|
|
135
|
-
}
|
|
136
|
-
return ranks;
|
|
137
|
-
};
|
|
138
|
-
/** `exitRanks` for `ids` themselves leaving `outer`. */
|
|
139
|
-
const leaving = (outer, after, ids) => exitRanks(outer, after, ids.map((at) => ({ at, part: [SELF] })));
|
|
75
|
+
const move = (ids, parent, index) => moveTo(ids, parent, index);
|
|
76
|
+
/** The side of blocks leaving a block for the gap right after it (`after`) or right before it. */
|
|
77
|
+
const leaving = (after) => (after ? 0 : 1);
|
|
140
78
|
/**
|
|
141
79
|
* A type step, planned only when the kind differs (the one same-value
|
|
142
80
|
* guard). A kind counts as the same only when the block is stored and
|
|
@@ -176,9 +114,9 @@ export const planSteps = (c) => {
|
|
|
176
114
|
* default kind, any other child keeps its kind (as `typeOf`).
|
|
177
115
|
*/
|
|
178
116
|
const leavingIsland = (island, kind, to) => {
|
|
179
|
-
if (
|
|
117
|
+
if (roles.of(to).rendersContent || (kind !== undefined && !roles.of(kind).rendersContent))
|
|
180
118
|
return to;
|
|
181
|
-
return
|
|
119
|
+
return isLines(island) ? defaultChild(null) : kind;
|
|
182
120
|
};
|
|
183
121
|
const settledKind = (from, kid, parent) => {
|
|
184
122
|
let kind = blockTypeOf(kid);
|
|
@@ -191,7 +129,7 @@ export const planSteps = (c) => {
|
|
|
191
129
|
// column's default child is the document's: it holds no items of its own.
|
|
192
130
|
const outer = kind !== defaultChild(null) &&
|
|
193
131
|
within.some((a) => isContainer(a) && defaultChild(a) === kind);
|
|
194
|
-
if (!outer &&
|
|
132
|
+
if (!outer && roles.of(to).rendersContent)
|
|
195
133
|
kind = to;
|
|
196
134
|
}
|
|
197
135
|
return fitted(parent, kind);
|
|
@@ -241,10 +179,10 @@ export const planSteps = (c) => {
|
|
|
241
179
|
* with one item or none — `gone` (blocks the plan removes) and
|
|
242
180
|
* `leaving` (blocks it moves) no longer count, an item `writes` move or
|
|
243
181
|
* insert into it does. With one left, the layout and that item are
|
|
244
|
-
* deleted and the item's children moved
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
182
|
+
* deleted and the item's children moved right after the layout, where
|
|
183
|
+
* `layout.single` shows them, as the kind they show there (`settle`);
|
|
184
|
+
* with none, the layout is deleted. One plan with the write that caused
|
|
185
|
+
* it.
|
|
248
186
|
*/
|
|
249
187
|
const dissolving = (gone, leaving, writes) => {
|
|
250
188
|
const away = new Set([...gone, ...leaving]);
|
|
@@ -269,17 +207,17 @@ export const planSteps = (c) => {
|
|
|
269
207
|
const items = slots.filter((k) => !away.has(k.id) && blockTypeOf(k.id) === item);
|
|
270
208
|
if (items.length + arriving > 1)
|
|
271
209
|
continue;
|
|
272
|
-
const { parent
|
|
273
|
-
const rank = kids.get(parent)[index].rank;
|
|
210
|
+
const { parent } = positionOf(layout);
|
|
274
211
|
const last = items[0];
|
|
275
212
|
if (last === undefined) {
|
|
276
213
|
out.push(deleting(layout, [layout]));
|
|
277
214
|
continue;
|
|
278
215
|
}
|
|
216
|
+
// Its blocks keep their home slots: the read shows them in the layout's
|
|
217
|
+
// slot (`layout.single`), settled for its parent.
|
|
279
218
|
const moved = (kids.get(last.id) ?? []).filter((k) => !away.has(k.id));
|
|
280
219
|
const ids = moved.map((k) => k.id);
|
|
281
|
-
|
|
282
|
-
out.push(...moveTo(ids, parent, index + 1, ranks), ...settle(last.id, ids, parent), deleting(layout, [layout, last.id]));
|
|
220
|
+
out.push(...settle(last.id, ids, parent), deleting(layout, [layout, last.id]));
|
|
283
221
|
}
|
|
284
222
|
return out;
|
|
285
223
|
};
|
|
@@ -349,17 +287,9 @@ export const planSteps = (c) => {
|
|
|
349
287
|
const emptied = (leaving, writes, kept) => emptyingAll(leaving.map((id) => positionOf(id).parent), leaving, writes, kept);
|
|
350
288
|
return {
|
|
351
289
|
REFUSED,
|
|
352
|
-
HEAD,
|
|
353
|
-
KEPT,
|
|
354
|
-
WITH,
|
|
355
|
-
SELF,
|
|
356
|
-
AFTER,
|
|
357
290
|
plan,
|
|
358
|
-
ranksFor,
|
|
359
291
|
moveTo,
|
|
360
292
|
move,
|
|
361
|
-
exitRanks,
|
|
362
|
-
pieceRanks,
|
|
363
293
|
leaving,
|
|
364
294
|
attr,
|
|
365
295
|
leavingIsland,
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared suggestions (`docs/archive/shared-suggestions/design.md`, the
|
|
3
|
+
* `sugg.*` rows of `docs/editor-delete-contract.md`): a suggestion lives in
|
|
4
|
+
* the document, so every replica, the room and a reload see it.
|
|
5
|
+
*
|
|
6
|
+
* - A suggestion is a record node under the root `suggest`, written by its
|
|
7
|
+
* **writer**: a client id minted for a suggesting session, bound to its
|
|
8
|
+
* author with its first write like any replica. The record's own item
|
|
9
|
+
* opens the writer's clocks it owns, up to the writer's next record; its
|
|
10
|
+
* creation is in no history step, so no undo or redo moves them.
|
|
11
|
+
* - **An insertion** is the writer's own text and blocks: a shown unit or
|
|
12
|
+
* block of the writer, in the record's clocks, not settled, is pending.
|
|
13
|
+
* - **A deletion** writes nothing to the text: the writer's id list (fork
|
|
14
|
+
* patch YP31, a hold record that holds nothing inside a nested node) in
|
|
15
|
+
* the record names the units; a shown one, not settled, is pending. A
|
|
16
|
+
* block deletion is the same id list naming the block's node.
|
|
17
|
+
* - Nothing else is suggested: a move, a merge, a retype, a data change or
|
|
18
|
+
* a format is refused (written directly on its author's own pending
|
|
19
|
+
* block).
|
|
20
|
+
* - **A decision** writes only what changes, one engine call over the
|
|
21
|
+
* change's ids (`YNode#hold`): the text that goes is the reviewer's hold
|
|
22
|
+
* (fork patch YP20, the root records list), the text that stays a settled
|
|
23
|
+
* id list written by the reviewer into the record (its client is the
|
|
24
|
+
* decider).
|
|
25
|
+
*
|
|
26
|
+
* What is pending is a function of the replicated state (items, records,
|
|
27
|
+
* settled ranges), so replicas converge in any delivery order. It is read
|
|
28
|
+
* again after any write, from the blocks the records' writers and
|
|
29
|
+
* proposals are in: a document with no suggestion pays nothing.
|
|
30
|
+
*
|
|
31
|
+
* The part is built over a document by {@link suggestionsOf} (the shared
|
|
32
|
+
* suggestions plugin, the room, a bare document on a server): once built,
|
|
33
|
+
* the document's `toJSON()` leaves its pending suggestions out. A document
|
|
34
|
+
* no one built it over reads its suggestions' content as plain content.
|
|
35
|
+
*/
|
|
36
|
+
import type { EngineDoc } from '../engine-api.js';
|
|
37
|
+
import { type BlockId } from '../placement/model.js';
|
|
38
|
+
import type { DocAnchor, EdytorDocConfig, OpResult, Prepared } from './types.js';
|
|
39
|
+
import type { DocBase, DocReads } from './reads.js';
|
|
40
|
+
import type { JSONDoc } from '../../utils/json.js';
|
|
41
|
+
import type { EdytorDocument } from '../document.js';
|
|
42
|
+
/** One change of a suggestion, as a reviewer sees it. */
|
|
43
|
+
export type SuggestedChange = {
|
|
44
|
+
/** The suggestion it is part of (its record's id). */
|
|
45
|
+
readonly suggestion: string;
|
|
46
|
+
/**
|
|
47
|
+
* `insert`: a run of text it inserts; `delete`: a run it proposes to
|
|
48
|
+
* delete; `block`: a block it inserts, its text with it; `split`: the
|
|
49
|
+
* block its split makes; `remove`: a block it proposes to delete.
|
|
50
|
+
*/
|
|
51
|
+
readonly kind: 'insert' | 'delete' | 'block' | 'split' | 'remove';
|
|
52
|
+
/** The block it is in or about. */
|
|
53
|
+
readonly block: BlockId;
|
|
54
|
+
/** Its run, in the block's display offsets (a block's: the whole block). */
|
|
55
|
+
readonly offset: number;
|
|
56
|
+
readonly length: number;
|
|
57
|
+
readonly text: string;
|
|
58
|
+
};
|
|
59
|
+
/** A suggestion the document holds. */
|
|
60
|
+
export type SuggestionRecord = {
|
|
61
|
+
readonly id: string;
|
|
62
|
+
/** Its author (its writer's actor), `undefined` until the binding arrives. */
|
|
63
|
+
readonly by: string | undefined;
|
|
64
|
+
/** The agent that wrote it for its author (`'ai'`), when one did. */
|
|
65
|
+
readonly via: string | undefined;
|
|
66
|
+
readonly label: string | undefined;
|
|
67
|
+
/** When it was opened (ms since the epoch). */
|
|
68
|
+
readonly at: number;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* One part of a decision: an id list written into suggestion `into`'s
|
|
72
|
+
* record (settled: it stays) or, `into` null, the decider's hold of the
|
|
73
|
+
* text that goes (fork patch YP20, the root records list): one engine
|
|
74
|
+
* call either way (`YNode#hold`); or a document operation's calls (their
|
|
75
|
+
* arguments read when it runs).
|
|
76
|
+
*/
|
|
77
|
+
export type DecisionPart = {
|
|
78
|
+
into: string | null;
|
|
79
|
+
ids: number[];
|
|
80
|
+
blocks?: BlockId[];
|
|
81
|
+
} | {
|
|
82
|
+
op: string;
|
|
83
|
+
calls: () => unknown[][];
|
|
84
|
+
};
|
|
85
|
+
/** What the part reads of its document beyond the facade: the facade's `part` (`edytor-doc.ts`). */
|
|
86
|
+
export type SuggestContext = DocBase & DocReads & {
|
|
87
|
+
config: EdytorDocConfig;
|
|
88
|
+
/** A facade over another doc, with `config`. */
|
|
89
|
+
create: (doc: EngineDoc, config: EdytorDocConfig) => SuggestFacade;
|
|
90
|
+
/** Its changes no index fact shows: counted in the facade's `version`. */
|
|
91
|
+
v: number;
|
|
92
|
+
/** The export `toJSON()` gives unless asked for the suggestions. */
|
|
93
|
+
base: (() => JSONDoc | undefined) | undefined;
|
|
94
|
+
};
|
|
95
|
+
/** The facade the part is built over: its `part`, and the operations it writes through. */
|
|
96
|
+
export type SuggestFacade = {
|
|
97
|
+
part: SuggestContext;
|
|
98
|
+
toJSON: (options?: {
|
|
99
|
+
suggestions?: boolean;
|
|
100
|
+
}) => JSONDoc;
|
|
101
|
+
dispose: () => void;
|
|
102
|
+
apply: (p: Prepared, quiet?: boolean) => OpResult;
|
|
103
|
+
transact: <R>(fn: () => R) => R;
|
|
104
|
+
anchorAt: (id: BlockId, offset: number, affinity?: 'left' | 'right') => DocAnchor | null;
|
|
105
|
+
resolveAnchor: (anchor: DocAnchor) => {
|
|
106
|
+
blockId: BlockId;
|
|
107
|
+
offset: number;
|
|
108
|
+
} | null;
|
|
109
|
+
/** Its operations by name (`f[op](…args)`). */
|
|
110
|
+
[op: string]: unknown;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* The shared suggestions of the document `facade` is over, built once:
|
|
114
|
+
* from then on, its `toJSON()` leaves the pending ones out (`sugg.json.base`).
|
|
115
|
+
*/
|
|
116
|
+
export declare const suggestionsOf: (facade: SuggestFacade) => DocSuggest;
|
|
117
|
+
/**
|
|
118
|
+
* Build the shared suggestions over `document`, a document read without a
|
|
119
|
+
* view (on a server, in a worker): its `toJSON()` leaves the pending ones
|
|
120
|
+
* out from then on, as a view's with the shared suggestions plugin does. A
|
|
121
|
+
* document no one built them over reads their content as plain content.
|
|
122
|
+
*/
|
|
123
|
+
export declare const adoptSharedSuggestions: (document: EdytorDocument) => void;
|
|
124
|
+
/** The document's shared suggestions ({@link suggestionsOf}), built over facade `f`. */
|
|
125
|
+
declare const docSuggest: (f: SuggestFacade) => {
|
|
126
|
+
/** A fresh writer this replica writes suggestions under. */
|
|
127
|
+
writer: () => number;
|
|
128
|
+
/** The writers this replica minted (a history tags their steps, `StackItem.writer`). */
|
|
129
|
+
writers: Set<number>;
|
|
130
|
+
open: (options?: {
|
|
131
|
+
id?: string;
|
|
132
|
+
writer?: number;
|
|
133
|
+
via?: string;
|
|
134
|
+
label?: string;
|
|
135
|
+
at?: number;
|
|
136
|
+
}) => string;
|
|
137
|
+
apply: (id: string | null, p: Prepared, w?: number) => {
|
|
138
|
+
result: OpResult;
|
|
139
|
+
id?: string;
|
|
140
|
+
at?: {
|
|
141
|
+
block: BlockId;
|
|
142
|
+
offset: number;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
decide: (changes: readonly SuggestedChange[], accept: boolean) => DecisionPart[];
|
|
146
|
+
run: (parts: readonly DecisionPart[], exec?: (op: string, args: unknown[]) => unknown, w?: number) => void;
|
|
147
|
+
/** The suggestions the document holds, oldest first. */
|
|
148
|
+
records: () => SuggestionRecord[];
|
|
149
|
+
/** Whether the document holds any suggestion record. */
|
|
150
|
+
any: () => boolean;
|
|
151
|
+
/** Every pending change, in document order. */
|
|
152
|
+
changes: () => SuggestedChange[];
|
|
153
|
+
/** The pending changes of block `b` (`[]`: none). */
|
|
154
|
+
at: (b: BlockId) => readonly SuggestedChange[];
|
|
155
|
+
/** Bumped by every change of the records. */
|
|
156
|
+
version: () => number;
|
|
157
|
+
/** Be told of every change of the records. Returns the unsubscribe. */
|
|
158
|
+
onChange: (f: () => void) => () => undefined;
|
|
159
|
+
/** @internal The work done (blocks read, units walked): the scaling rows count it. */
|
|
160
|
+
debug: {
|
|
161
|
+
computes: number;
|
|
162
|
+
units: number;
|
|
163
|
+
};
|
|
164
|
+
dispose: () => void;
|
|
165
|
+
};
|
|
166
|
+
export type DocSuggest = ReturnType<typeof docSuggest>;
|
|
167
|
+
export {};
|