edytor 4.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 +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 +115 -106
- 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/capability.js +9 -13
- 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 +77 -56
- package/dist/crdt/doc/layout.js +5 -5
- package/dist/crdt/doc/meta.js +6 -7
- package/dist/crdt/doc/reads.d.ts +2 -2
- package/dist/crdt/doc/reads.js +18 -28
- package/dist/crdt/doc/steps.js +4 -4
- 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 +355 -333
- package/dist/crdt/edytor-doc.js +125 -82
- 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 +1 -1
- package/dist/crdt/flow.js +4 -10
- package/dist/crdt/index.d.ts +111 -105
- package/dist/crdt/index.js +3 -0
- 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 +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.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/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/websocket.d.ts +6 -4
- package/dist/crdt/providers/websocket.js +9 -4
- package/dist/crdt/purge.d.ts +7 -1
- package/dist/crdt/purge.js +32 -2
- 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/claims.js +1 -23
- package/dist/crdt/text/index/layout.d.ts +2 -4
- package/dist/crdt/text/index/layout.js +9 -22
- package/dist/crdt/text/index/placement.js +21 -24
- package/dist/crdt/text/index/shared.js +17 -14
- package/dist/crdt/text/model.d.ts +10 -0
- package/dist/crdt/text/model.js +8 -1
- package/dist/crdt/text/runs.d.ts +34 -30
- 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/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 +25 -25
- 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 +128 -81
- package/dist/surface/pin.svelte.d.ts +9 -9
- package/dist/surface/pin.svelte.js +15 -22
- package/dist/surface/projector.svelte.js +8 -14
- package/dist/text/text.svelte.js +14 -19
- package/dist/themes/notion.css +29 -0
- package/package.json +3 -1
|
@@ -277,6 +277,16 @@ export declare const insertIntoText: (doc: EngineDoc, blocks: unknown, own: Owne
|
|
|
277
277
|
* that step's undo still changes nothing.
|
|
278
278
|
*/
|
|
279
279
|
export declare const deleteRange: (doc: EngineDoc, blocks: unknown, own: Ownership, b: BlockId, offset: number, length: number) => void;
|
|
280
|
+
/**
|
|
281
|
+
* A suggestion's plan being written on a doc (`doc/suggest.ts`): its text
|
|
282
|
+
* deletes propose (fork patch YP32) into its record, `sort` telling each
|
|
283
|
+
* unit's lot (`1` its author's own: held; `2` proposed; `3` already
|
|
284
|
+
* proposed: stepped over).
|
|
285
|
+
*/
|
|
286
|
+
export declare const proposing: WeakMap<EngineDoc, {
|
|
287
|
+
into: EngineNode;
|
|
288
|
+
sort: (client: number, clock: number) => number;
|
|
289
|
+
}>;
|
|
280
290
|
export declare const formatRangeIn: (doc: EngineDoc, blocks: unknown, own: Ownership, b: BlockId, offset: number, length: number, formats: Record<string, unknown>) => void;
|
|
281
291
|
/**
|
|
282
292
|
* Delete the content of streams `streams` (the room's purge of a
|
package/dist/crdt/text/model.js
CHANGED
|
@@ -198,8 +198,15 @@ export const deleteRange = (doc, blocks, own, b, offset, length) => {
|
|
|
198
198
|
const records = doc.get(TEXT_DELETES_ROOT);
|
|
199
199
|
const fresh = openInserts(doc);
|
|
200
200
|
for (const r of rangesOf(flatten(b, blocks, own), offset, offset + length))
|
|
201
|
-
r.text.delete(r.a, r.b - r.a, records, fresh);
|
|
201
|
+
r.text.delete(r.a, r.b - r.a, records, fresh, proposing.get(doc));
|
|
202
202
|
};
|
|
203
|
+
/**
|
|
204
|
+
* A suggestion's plan being written on a doc (`doc/suggest.ts`): its text
|
|
205
|
+
* deletes propose (fork patch YP32) into its record, `sort` telling each
|
|
206
|
+
* unit's lot (`1` its author's own: held; `2` proposed; `3` already
|
|
207
|
+
* proposed: stepped over).
|
|
208
|
+
*/
|
|
209
|
+
export const proposing = new WeakMap();
|
|
203
210
|
export const formatRangeIn = (doc, blocks, own, b, offset, length, formats) => {
|
|
204
211
|
for (const r of rangesOf(flatten(b, blocks, own), offset, offset + length))
|
|
205
212
|
writeMarks(doc, r.text, r.a, r.b - r.a, formats);
|
package/dist/crdt/text/runs.d.ts
CHANGED
|
@@ -220,38 +220,42 @@ export type RunView = {
|
|
|
220
220
|
debug: RunViewDebug;
|
|
221
221
|
};
|
|
222
222
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* `
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* kind that
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* layout
|
|
234
|
-
* `table`: a table
|
|
235
|
-
* the table's column order (`table.*`).
|
|
223
|
+
* A kind's answers, read once from its role (the one shape the display and
|
|
224
|
+
* every guard read). `childless`: displays no children (a void role) — a
|
|
225
|
+
* child of such a block displays in its slot. `island`: a block promoted
|
|
226
|
+
* out of one displays as `child` of its display parent's kind.
|
|
227
|
+
* `container`: renders no content and is neither void nor an island (a
|
|
228
|
+
* list) — a block promoted out of one follows like one promoted out of an
|
|
229
|
+
* island. `rendersContent`: no block that renders content ever shows as a
|
|
230
|
+
* kind that does not (its text would vanish). `child`: its default child
|
|
231
|
+
* (the document's default kind for the root, `null`). `line`: an island
|
|
232
|
+
* declared `lines` holds only lines of this kind, which hold no children.
|
|
233
|
+
* `layout`: a layout displays only items of this kind, and only two or
|
|
234
|
+
* more (`layout.*`). `table`: a table displays only rows of this kind, a
|
|
235
|
+
* row only its cells, in the table's column order (`table.*`).
|
|
236
236
|
*/
|
|
237
|
+
export type KindRole = {
|
|
238
|
+
childless: boolean;
|
|
239
|
+
island: boolean;
|
|
240
|
+
container: boolean;
|
|
241
|
+
rendersContent: boolean;
|
|
242
|
+
child: string;
|
|
243
|
+
line?: string;
|
|
244
|
+
layout?: string;
|
|
245
|
+
table?: string;
|
|
246
|
+
};
|
|
247
|
+
/** The kinds the roles declare: line kinds, layout kinds and their item kinds, table kinds and their row kinds (→ cell kind). */
|
|
248
|
+
export type DeclaredKinds = {
|
|
249
|
+
lines: ReadonlySet<string>;
|
|
250
|
+
layouts: readonly string[];
|
|
251
|
+
items: ReadonlySet<string>;
|
|
252
|
+
rows: ReadonlyMap<string, string>;
|
|
253
|
+
cells: ReadonlySet<string>;
|
|
254
|
+
};
|
|
255
|
+
/** The role table: each kind's {@link KindRole} and the declared kinds, both read once until the roles change. */
|
|
237
256
|
export type DisplayRoles = {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
container: (type: string) => boolean;
|
|
241
|
-
rendersContent: (type: string) => boolean;
|
|
242
|
-
defaultChild: (parentType: string | null) => string;
|
|
243
|
-
/** The line kind of an island kind declared `lines` (its `defaultChild`), if any. */
|
|
244
|
-
line: (islandType: string) => string | undefined;
|
|
245
|
-
/** Every line kind the roles declare, present in the document or not. */
|
|
246
|
-
lineKinds: () => Iterable<string>;
|
|
247
|
-
/** The item kind of a layout kind (its `defaultChild`), if `type` is one. */
|
|
248
|
-
layout: (type: string) => string | undefined;
|
|
249
|
-
/** Every layout kind the roles declare, present in the document or not. */
|
|
250
|
-
layoutKinds: () => Iterable<string>;
|
|
251
|
-
/** The row kind of a table kind (its `defaultChild`), if `type` is one (`table.*`). */
|
|
252
|
-
table: (type: string) => string | undefined;
|
|
253
|
-
/** Every table kind the roles declare, present in the document or not. */
|
|
254
|
-
tableKinds: () => Iterable<string>;
|
|
257
|
+
of: (type: string | null) => KindRole;
|
|
258
|
+
declared: () => DeclaredKinds;
|
|
255
259
|
};
|
|
256
260
|
/** The doc's index — built on first use, torn down when the doc is destroyed. */
|
|
257
261
|
export declare const indexOf: (doc: EngineDoc) => RunView;
|
|
@@ -1515,6 +1515,89 @@ Oracle: `src/tests/crdt/attribution/first-write-binding.test.ts` (the first
|
|
|
1515
1515
|
local edit's one update carries the binding; a remote update writes none),
|
|
1516
1516
|
the upstream suite.
|
|
1517
1517
|
|
|
1518
|
+
### YP31 — a hold record inside a nested node holds nothing (`src/structs/Item.js`)
|
|
1519
|
+
|
|
1520
|
+
Reason: edytor's shared suggestions keep, inside each suggestion's record
|
|
1521
|
+
node, the id ranges it proposes to delete and the ranges its reviewers
|
|
1522
|
+
settled: lists of `client, clock, len` ranges that must hide nothing until a
|
|
1523
|
+
reviewer accepts. YP20's hold record is exactly that codec (one unit per
|
|
1524
|
+
range, a left id and a length, consecutive records of one writer merging
|
|
1525
|
+
as typed runs do), but it holds whatever it names wherever it integrates.
|
|
1526
|
+
The study's prototype added a sibling content type that held nothing
|
|
1527
|
+
(content ref 14, `ContentPropose`, a `YNode#propose` writer, about 0.3 KB);
|
|
1528
|
+
the rule here keeps one record type and one reader. Design:
|
|
1529
|
+
`docs/archive/shared-suggestions/design.md`. Edytor's schema generation 11
|
|
1530
|
+
is the cutover (no conversion: a generation-10 replica would hold what a
|
|
1531
|
+
proposal names).
|
|
1532
|
+
|
|
1533
|
+
Patch (new code delimited by `// YP31 begin` / `// YP31 end`, edits marked `// YP31`):
|
|
1534
|
+
|
|
1535
|
+
- **`holding(item)`**: a hold record holds what it names iff its item is an
|
|
1536
|
+
entry of a root's sequence (`item.parent._item === null`: the document's
|
|
1537
|
+
records list, `textdel`). `ContentHold#integrate` and `ContentHold#delete`
|
|
1538
|
+
hold and release only then; inside a nested node's sequence the record is
|
|
1539
|
+
a list of ids: it moves no length, waits in no `pendingHolds`, logs
|
|
1540
|
+
nothing in `transaction.holds`, and its delete (an undo, a reviewer's
|
|
1541
|
+
withdrawal, its node's delete) releases nothing. `YNode#hold(ids)` on a
|
|
1542
|
+
nested node appends one such list entry.
|
|
1543
|
+
|
|
1544
|
+
Plain deletes and the root records list (every upstream test, every YP20
|
|
1545
|
+
row) are untouched: no other code path writes a hold record into a nested
|
|
1546
|
+
node.
|
|
1547
|
+
|
|
1548
|
+
Edytor side: a suggestion's record node (root `suggest`) keeps its writer's
|
|
1549
|
+
proposed deletions and its reviewers' settled ranges as such entries
|
|
1550
|
+
(`crdt/doc/suggest.ts`); accepting a deletion writes a real hold record in
|
|
1551
|
+
the root list.
|
|
1552
|
+
|
|
1553
|
+
Oracle: `src/tests/crdt/yp31-id-lists.test.ts` (written, deleted, merged,
|
|
1554
|
+
split, synced, reloaded, received before the items it names, deleted with
|
|
1555
|
+
its node: nothing hidden or released; the root list still holds), the YP20
|
|
1556
|
+
rows and the shared-suggestion rows, the upstream suite unchanged
|
|
1557
|
+
(`encoding.tests.js` still pins 14 content refs).
|
|
1558
|
+
|
|
1559
|
+
### YP32 — a delete that proposes (`src/ynode.js`, `src/structs/Item.js`, `src/index.js`)
|
|
1560
|
+
|
|
1561
|
+
Reason: in suggesting mode a text delete writes nothing to the text: the
|
|
1562
|
+
units that are not the suggestion's author's own pending ones are named by
|
|
1563
|
+
an id list in the suggestion's record (YP31), and they stay shown. The
|
|
1564
|
+
plan that deleted them was prepared with them gone, so edytor carried a
|
|
1565
|
+
layer that re-read each later step's offsets over the units the plan had
|
|
1566
|
+
proposed, batched the steps around every proposal and mapped the caret
|
|
1567
|
+
back (`crdt/doc/suggest.ts` `apply`, about 1.4 KB minified). The fork's
|
|
1568
|
+
delete now proposes, and hides what it proposed until the plan ends: the
|
|
1569
|
+
plan's later steps read the offsets they were prepared with, and an
|
|
1570
|
+
insertion at a proposed deletion lands after it (at the end of the gap,
|
|
1571
|
+
as any insertion lands after deleted items). Design:
|
|
1572
|
+
`docs/archive/suggestions-in-engine/design.md`.
|
|
1573
|
+
|
|
1574
|
+
Patch (new code delimited by `// YP32 begin` / `// YP32 end`, edits marked `// YP32`):
|
|
1575
|
+
|
|
1576
|
+
- **`YNode#delete(index, length, into, fresh, propose)`**: with `propose`
|
|
1577
|
+
(`{ into, sort }`), each live unit the delete reaches is sorted by
|
|
1578
|
+
`sort(client, clock)`: `1` held by the record appended to `into` (the
|
|
1579
|
+
author's own pending text, YP20's path), `2` proposed (one id list
|
|
1580
|
+
appended to `propose.into`, the suggestion's record, which holds nothing
|
|
1581
|
+
there, YP31), `3` stepped over (already proposed). `fresh` units are
|
|
1582
|
+
removed as before. Proposed and stepped-over units are hidden
|
|
1583
|
+
(`hideIds`: a hold without a record, kept in `transaction.hidden`) until
|
|
1584
|
+
`unhide(transaction)`, which edytor calls when the plan is written.
|
|
1585
|
+
`deleteText` splits a run where the sort changes.
|
|
1586
|
+
- **`hideIds`, `unhide`** (`Item.js`, `unhide` exported): YP20's
|
|
1587
|
+
`holdIds` with no record, and its release.
|
|
1588
|
+
|
|
1589
|
+
Plain deletes (every upstream test, every YP20 row) are untouched: without
|
|
1590
|
+
`propose` the sort is not read and every changed path reduces to YP20's.
|
|
1591
|
+
|
|
1592
|
+
Edytor side: `crdt/text/model.ts` `deleteRange` passes the plan's
|
|
1593
|
+
`proposing` context; `crdt/doc/suggest.ts` writes a suggesting plan as one
|
|
1594
|
+
frame, its caret anchored before `unhide` and resolved after.
|
|
1595
|
+
|
|
1596
|
+
Oracle: the shared-suggestion rows (`src/tests/crdt/suggest/`, the random
|
|
1597
|
+
schedules with the index's self-checks on), `suggesting-input.test.tsx`
|
|
1598
|
+
(typing over a selection, a paste, Backspace and Delete over struck text),
|
|
1599
|
+
the YP20 rows, the upstream suite unchanged.
|
|
1600
|
+
|
|
1518
1601
|
## Generated declarations (`dts/`)
|
|
1519
1602
|
|
|
1520
1603
|
`svelte-package` copies JS verbatim but emits no `.d.ts` for JS inputs, so
|
|
@@ -17,4 +17,4 @@ export { idAtIndex, indexOfId } from "./utils/positions.js";
|
|
|
17
17
|
export { findIndexSS, getItemCleanStart, getItemCleanEnd, isKeptReplaced } from "./utils/transaction-helpers.js";
|
|
18
18
|
export { Transaction, transact } from "./utils/Transaction.js";
|
|
19
19
|
export { redoItem, keepItem } from "./utils/redo.js";
|
|
20
|
-
export { Item, followRedone, ContentBinary, ContentDeleted, ContentFormat, ContentAny, ContentString, ContentType, ContentMove } from "./structs/Item.js";
|
|
20
|
+
export { Item, followRedone, ContentBinary, ContentDeleted, ContentFormat, ContentAny, ContentString, ContentType, ContentMove, unhide } from "./structs/Item.js";
|
|
@@ -427,13 +427,14 @@ export class ContentHold {
|
|
|
427
427
|
mergeWith(right: ContentHold): boolean;
|
|
428
428
|
/**
|
|
429
429
|
* @param {Transaction} transaction
|
|
430
|
-
* @param {Item}
|
|
430
|
+
* @param {Item} item
|
|
431
431
|
*/
|
|
432
|
-
integrate(transaction: Transaction,
|
|
432
|
+
integrate(transaction: Transaction, item: Item): void;
|
|
433
433
|
/**
|
|
434
434
|
* @param {Transaction} transaction
|
|
435
|
+
* @param {Item} item
|
|
435
436
|
*/
|
|
436
|
-
delete(transaction: Transaction): void;
|
|
437
|
+
delete(transaction: Transaction, item: Item): void;
|
|
437
438
|
/**
|
|
438
439
|
* @param {Transaction} _tr
|
|
439
440
|
*/
|
|
@@ -449,6 +450,8 @@ export class ContentHold {
|
|
|
449
450
|
*/
|
|
450
451
|
getRef(): 11;
|
|
451
452
|
}
|
|
453
|
+
export function hideIds(tr: Transaction, ids: Array<number>): void;
|
|
454
|
+
export function unhide(tr: Transaction): void;
|
|
452
455
|
export function applyPending(tr: Transaction, clients: Array<number>): void;
|
|
453
456
|
/**
|
|
454
457
|
* A move record: one countable unit at its destination, naming the units
|
|
@@ -25,7 +25,7 @@ export class ItemTextListPosition {
|
|
|
25
25
|
advance(transaction: Transaction, length: number): void;
|
|
26
26
|
}
|
|
27
27
|
export function insertAtGapEndHelper(transaction: Transaction, parent: YNode, index: number, content: import("./structs/Item.js").AbstractContent): void;
|
|
28
|
-
export function deleteText(transaction: Transaction, currPos: ItemTextListPosition, length: number, held?: Array<number> | null, fresh?: import("./utils/ids.js").IdSet | null): ItemTextListPosition;
|
|
28
|
+
export function deleteText(transaction: Transaction, currPos: ItemTextListPosition, length: number, held?: Array<number> | null, fresh?: import("./utils/ids.js").IdSet | null, sort?: ((client: number, clock: number) => number) | null, proposed?: Array<number> | null, hidden?: Array<number> | null): ItemTextListPosition;
|
|
29
29
|
export class ArraySearchMarker {
|
|
30
30
|
/**
|
|
31
31
|
* @param {Item} p
|
|
@@ -193,12 +193,23 @@ export class YNode {
|
|
|
193
193
|
* which an undo of the record takes back), except those `fresh` names (the
|
|
194
194
|
* open undo step's inserts: removed, so that step's undo changes nothing).
|
|
195
195
|
*
|
|
196
|
+
* YP32: with `propose` (a suggestion's delete) each unit is sorted: held
|
|
197
|
+
* by the record in `into` (`1`: its author's own), proposed (`2`: an id
|
|
198
|
+
* list appended to `propose.into`, a suggestion's record, holding nothing)
|
|
199
|
+
* or stepped over (`3`: already proposed); proposed and stepped-over units
|
|
200
|
+
* read gone until `unhide`, so the rest of the plan reads the offsets it
|
|
201
|
+
* was prepared with.
|
|
202
|
+
*
|
|
196
203
|
* @param {number} index Index at which to start deleting elements
|
|
197
204
|
* @param {number} length The number of elements to remove. Defaults to 1.
|
|
198
205
|
* @param {YNode|null} [into]
|
|
199
206
|
* @param {import('./utils/ids.js').IdSet|null} [fresh]
|
|
207
|
+
* @param {{ into: YNode, sort: (client: number, clock: number) => number }|null} [propose]
|
|
200
208
|
*/
|
|
201
|
-
delete(index: number, length?: number, into?: YNode | null, fresh?: import("./utils/ids.js").IdSet | null
|
|
209
|
+
delete(index: number, length?: number, into?: YNode | null, fresh?: import("./utils/ids.js").IdSet | null, propose?: {
|
|
210
|
+
into: YNode;
|
|
211
|
+
sort: (client: number, clock: number) => number;
|
|
212
|
+
} | null): void;
|
|
202
213
|
/**
|
|
203
214
|
* YP20: append to this node (the document's records list) one hold record of
|
|
204
215
|
* the items `ids` names (`client, clock, len` triples): they read as deleted
|
|
@@ -19,7 +19,7 @@ export { RangeCursor } from './utils/RangeCursor.js'
|
|
|
19
19
|
export { YNode as Node } from './ynode.js'
|
|
20
20
|
export { AbstractStruct } from './structs/AbstractStruct.js'
|
|
21
21
|
export { GC } from './structs/GC.js'
|
|
22
|
-
export { Item, followRedone, ContentBinary, ContentDeleted, ContentFormat, ContentAny, ContentString, ContentType, ContentMove } from './structs/Item.js' // YP22: ContentMove
|
|
22
|
+
export { Item, followRedone, ContentBinary, ContentDeleted, ContentFormat, ContentAny, ContentString, ContentType, ContentMove, unhide } from './structs/Item.js' // YP22: ContentMove; YP32: unhide
|
|
23
23
|
export { Skip } from './structs/Skip.js'
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -1134,17 +1134,18 @@ export class ContentHold {
|
|
|
1134
1134
|
|
|
1135
1135
|
/**
|
|
1136
1136
|
* @param {Transaction} transaction
|
|
1137
|
-
* @param {Item}
|
|
1137
|
+
* @param {Item} item
|
|
1138
1138
|
*/
|
|
1139
|
-
integrate (transaction,
|
|
1140
|
-
holdIds(transaction, this.ids, 1)
|
|
1139
|
+
integrate (transaction, item) {
|
|
1140
|
+
if (holding(item)) holdIds(transaction, this.ids, 1) // YP31
|
|
1141
1141
|
}
|
|
1142
1142
|
|
|
1143
1143
|
/**
|
|
1144
1144
|
* @param {Transaction} transaction
|
|
1145
|
+
* @param {Item} item
|
|
1145
1146
|
*/
|
|
1146
|
-
delete (transaction) {
|
|
1147
|
-
holdIds(transaction, this.ids, -1)
|
|
1147
|
+
delete (transaction, item) {
|
|
1148
|
+
if (holding(item)) holdIds(transaction, this.ids, -1) // YP31
|
|
1148
1149
|
}
|
|
1149
1150
|
|
|
1150
1151
|
/**
|
|
@@ -1170,6 +1171,44 @@ export class ContentHold {
|
|
|
1170
1171
|
}
|
|
1171
1172
|
// YP20 end
|
|
1172
1173
|
|
|
1174
|
+
// YP31 begin (edytor fork: id lists — see UPSTREAM.md YP31)
|
|
1175
|
+
/**
|
|
1176
|
+
* Whether the hold record `item` holds what it names: one in a root's
|
|
1177
|
+
* sequence does (the document's records list, YP20); one in a nested node's
|
|
1178
|
+
* sequence is a list of ids, the same codec, that holds nothing.
|
|
1179
|
+
*
|
|
1180
|
+
* @param {Item} item
|
|
1181
|
+
* @return {boolean}
|
|
1182
|
+
*/
|
|
1183
|
+
const holding = item => /** @type {YNode} */ (item.parent)._item === null
|
|
1184
|
+
// YP31 end
|
|
1185
|
+
|
|
1186
|
+
// YP32 begin (edytor fork: a delete that proposes — see UPSTREAM.md YP32)
|
|
1187
|
+
/**
|
|
1188
|
+
* Hide the units `ids` names until `unhide` (a suggestion's proposed
|
|
1189
|
+
* deletion, which the rest of its plan reads gone): a hold without a
|
|
1190
|
+
* record, kept in `tr.hidden`.
|
|
1191
|
+
*
|
|
1192
|
+
* @param {Transaction} tr
|
|
1193
|
+
* @param {Array<number>} ids
|
|
1194
|
+
*/
|
|
1195
|
+
export const hideIds = (tr, ids) => {
|
|
1196
|
+
holdIds(tr, ids, 1)
|
|
1197
|
+
;/** @type {any} */ (tr).hidden = (/** @type {any} */ (tr).hidden ?? []).concat(ids)
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* Show again what `hideIds` hid in `tr`.
|
|
1202
|
+
*
|
|
1203
|
+
* @param {Transaction} tr
|
|
1204
|
+
*/
|
|
1205
|
+
export const unhide = tr => {
|
|
1206
|
+
const hidden = /** @type {any} */ (tr).hidden
|
|
1207
|
+
if (hidden) holdIds(tr, hidden, -1)
|
|
1208
|
+
;/** @type {any} */ (tr).hidden = null
|
|
1209
|
+
}
|
|
1210
|
+
// YP32 end
|
|
1211
|
+
|
|
1173
1212
|
// YP22 begin (edytor fork: move records — see UPSTREAM.md YP22)
|
|
1174
1213
|
/**
|
|
1175
1214
|
* Whether move record `a` beats `b`: the greater `(priority, client, clock)`
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ContentType,
|
|
13
13
|
ContentHold, // YP20
|
|
14
14
|
ContentMove, // YP22
|
|
15
|
+
hideIds, // YP32
|
|
15
16
|
readFormatValue, // YP25
|
|
16
17
|
YXmlFragmentRefID,
|
|
17
18
|
YXmlElementRefID,
|
|
@@ -327,19 +328,24 @@ const holdHelper = (transaction, list, ids) => {
|
|
|
327
328
|
|
|
328
329
|
/**
|
|
329
330
|
* With `held`, the live units are not deleted: their ids go to `held`
|
|
330
|
-
* (`client, clock, len`), except those `fresh` names (YP20).
|
|
331
|
+
* (`client, clock, len`), except those `fresh` names (YP20). YP32: with
|
|
332
|
+
* `sort` (a suggestion's delete), `sort`'s `1` goes to `held`, `2` to
|
|
333
|
+
* `proposed` and `hidden`, `3` to `hidden`.
|
|
331
334
|
*
|
|
332
335
|
* @param {Transaction} transaction
|
|
333
336
|
* @param {ItemTextListPosition} currPos
|
|
334
337
|
* @param {number} length
|
|
335
338
|
* @param {Array<number>|null} [held]
|
|
336
339
|
* @param {import('./utils/ids.js').IdSet|null} [fresh]
|
|
340
|
+
* @param {((client: number, clock: number) => number)|null} [sort] YP32: a suggestion's delete sorts each unit
|
|
341
|
+
* @param {Array<number>|null} [proposed] YP32: the units it proposes
|
|
342
|
+
* @param {Array<number>|null} [hidden] YP32: the units it hides until `unhide`
|
|
337
343
|
* @return {ItemTextListPosition}
|
|
338
344
|
*
|
|
339
345
|
* @private
|
|
340
346
|
* @function
|
|
341
347
|
*/
|
|
342
|
-
export const deleteText = (transaction, currPos, length, held = null, fresh = null) => {
|
|
348
|
+
export const deleteText = (transaction, currPos, length, held = null, fresh = null, sort = null, proposed = null, hidden = null) => {
|
|
343
349
|
const startLength = length
|
|
344
350
|
let kept = 0 // YP20
|
|
345
351
|
while (length > 0 && currPos.right !== null) {
|
|
@@ -347,15 +353,19 @@ export const deleteText = (transaction, currPos, length, held = null, fresh = nu
|
|
|
347
353
|
if (!item.deleted && item.countable) {
|
|
348
354
|
const { client, clock } = item.id
|
|
349
355
|
// YP20: a held run ends where the open step's inserts start or end
|
|
350
|
-
|
|
356
|
+
let n = fresh === null ? math.min(length, item.length) : runEnd(fresh, client, clock, clock + math.min(length, item.length)) - clock
|
|
357
|
+
// YP32: a suggestion's delete sorts each unit — held (`1`), proposed (`2`) or stepped over (`3`)
|
|
358
|
+
const kind = held === null || (fresh !== null && fresh.has(client, clock)) ? 0 : sort === null ? 1 : sort(client, clock)
|
|
359
|
+
if (kind !== 0 && sort !== null) for (let k = 1; k < n; k++) if (sort(client, clock + k) !== kind) n = k
|
|
351
360
|
if (n < item.length) {
|
|
352
361
|
getItemCleanStart(transaction, createID(client, clock + n))
|
|
353
362
|
}
|
|
354
363
|
length -= item.length
|
|
355
|
-
if (
|
|
364
|
+
if (kind === 0) {
|
|
356
365
|
item.delete(transaction)
|
|
357
366
|
} else {
|
|
358
|
-
|
|
367
|
+
if (kind === 2) /** @type {Array<number>} */ (proposed).push(client, clock, item.length)
|
|
368
|
+
;/** @type {Array<number>} */ (kind === 1 ? held : hidden).push(client, clock, item.length)
|
|
359
369
|
kept += item.length
|
|
360
370
|
}
|
|
361
371
|
}
|
|
@@ -993,12 +1003,20 @@ export class YNode {
|
|
|
993
1003
|
* which an undo of the record takes back), except those `fresh` names (the
|
|
994
1004
|
* open undo step's inserts: removed, so that step's undo changes nothing).
|
|
995
1005
|
*
|
|
1006
|
+
* YP32: with `propose` (a suggestion's delete) each unit is sorted: held
|
|
1007
|
+
* by the record in `into` (`1`: its author's own), proposed (`2`: an id
|
|
1008
|
+
* list appended to `propose.into`, a suggestion's record, holding nothing)
|
|
1009
|
+
* or stepped over (`3`: already proposed); proposed and stepped-over units
|
|
1010
|
+
* read gone until `unhide`, so the rest of the plan reads the offsets it
|
|
1011
|
+
* was prepared with.
|
|
1012
|
+
*
|
|
996
1013
|
* @param {number} index Index at which to start deleting elements
|
|
997
1014
|
* @param {number} length The number of elements to remove. Defaults to 1.
|
|
998
1015
|
* @param {YNode|null} [into]
|
|
999
1016
|
* @param {import('./utils/ids.js').IdSet|null} [fresh]
|
|
1017
|
+
* @param {{ into: YNode, sort: (client: number, clock: number) => number }|null} [propose]
|
|
1000
1018
|
*/
|
|
1001
|
-
delete (index, length = 1, into = null, fresh = null) {
|
|
1019
|
+
delete (index, length = 1, into = null, fresh = null, propose = null) {
|
|
1002
1020
|
if (!(length > 0)) return
|
|
1003
1021
|
if (this.doc == null) {
|
|
1004
1022
|
const runs = prelimOf(this).runs
|
|
@@ -1015,13 +1033,17 @@ export class YNode {
|
|
|
1015
1033
|
transact(this.doc, transaction => {
|
|
1016
1034
|
const currPos = cursorAt(transaction, this, index)
|
|
1017
1035
|
const held = into === null ? null : [] // YP20
|
|
1018
|
-
|
|
1036
|
+
const [proposed, hidden] = [[], []] // YP32
|
|
1037
|
+
deleteText(transaction, currPos, length, held, fresh, propose && propose.sort, proposed, hidden)
|
|
1019
1038
|
if (held !== null && held.length > 0) {
|
|
1020
1039
|
// YP20: `deleteText` moved the markers as for a delete; the hold keeps them
|
|
1021
1040
|
const ms = this._searchMarker === null ? null : this._searchMarker.slice()
|
|
1022
1041
|
holdHelper(transaction, /** @type {YNode} */ (into), held)
|
|
1023
1042
|
if (ms !== null && this._searchMarker !== null) this._searchMarker.splice(0, this._searchMarker.length, ...ms)
|
|
1024
1043
|
}
|
|
1044
|
+
// YP32: the proposal, then what it hides until `unhide`
|
|
1045
|
+
if (proposed.length > 0) holdHelper(transaction, /** @type {any} */ (propose).into, proposed)
|
|
1046
|
+
if (hidden.length > 0) hideIds(transaction, hidden)
|
|
1025
1047
|
plantMarker(this, currPos)
|
|
1026
1048
|
})
|
|
1027
1049
|
}
|
package/dist/edytor.svelte.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { Handles } from './session/handles.js';
|
|
|
11
11
|
import { type Awareness, type DocChange, type DocumentActor, type EdytorDocument, type OrderPolicy, type YDoc } from './crdt/index.js';
|
|
12
12
|
import { PresenceWriter, type PresenceOptions } from './collaboration/awarenessSelection.js';
|
|
13
13
|
import { type BlockMoveRequest } from './session/moves.js';
|
|
14
|
-
import {
|
|
14
|
+
import type { DocumentWrites } from './crdt/operations.js';
|
|
15
15
|
import type { Plugin, BlockDefinition, MarkDefinition, InlineBlockDefinition, EditorCommand, Placeholder } from './plugins.js';
|
|
16
16
|
import { type HotKey, type HotKeyCombination } from './session/keymap.js';
|
|
17
17
|
import { Dispatcher } from './session/commands.js';
|