edytor 5.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.
Files changed (75) hide show
  1. package/README.md +2 -2
  2. package/dist/cloudflare/room/context.d.ts +62 -74
  3. package/dist/crdt/doc/history.js +2 -3
  4. package/dist/crdt/doc/ops.d.ts +81 -0
  5. package/dist/crdt/doc/ops.js +1898 -0
  6. package/dist/crdt/edytor-doc.d.ts +156 -156
  7. package/dist/crdt/edytor-doc.js +14 -42
  8. package/dist/crdt/flow.d.ts +4 -46
  9. package/dist/crdt/flow.js +2 -262
  10. package/dist/crdt/index.d.ts +62 -74
  11. package/dist/crdt/operations.d.ts +1 -1
  12. package/dist/crdt/placement/resolve.d.ts +1 -1
  13. package/dist/crdt/protocols/awareness.js +46 -81
  14. package/dist/crdt/providers/index.d.ts +10 -22
  15. package/dist/crdt/providers/indexeddb.d.ts +6 -10
  16. package/dist/crdt/providers/indexeddb.js +10 -16
  17. package/dist/crdt/providers/room.d.ts +11 -0
  18. package/dist/crdt/providers/room.js +26 -12
  19. package/dist/crdt/providers/websocket.d.ts +6 -12
  20. package/dist/crdt/providers/websocket.js +8 -15
  21. package/dist/crdt/rangeDelete.d.ts +2 -47
  22. package/dist/crdt/rangeDelete.js +1 -169
  23. package/dist/crdt/text/index/build.d.ts +125 -0
  24. package/dist/crdt/text/index/build.js +2895 -0
  25. package/dist/crdt/text/index/shared.d.ts +2 -6
  26. package/dist/crdt/text/index/shared.js +2 -5
  27. package/dist/crdt/text/model.js +2 -3
  28. package/dist/crdt/text/runs.d.ts +9 -12
  29. package/dist/crdt/text/runs.js +2 -165
  30. package/dist/events/domTextOffset.d.ts +2 -0
  31. package/dist/events/domTextOffset.js +8 -0
  32. package/dist/export/forms.d.ts +50 -50
  33. package/dist/plugins/richtext/RichTextPlugin.svelte +63 -61
  34. package/dist/plugins/richtext/richTextOperations.js +26 -32
  35. package/dist/selection/selection.utils.js +5 -8
  36. package/dist/session/handles.js +3 -7
  37. package/dist/surface/observer.svelte.js +15 -30
  38. package/dist/surface/projector.svelte.js +2 -2
  39. package/dist/utils.d.ts +5 -0
  40. package/dist/utils.js +7 -0
  41. package/package.json +1 -1
  42. package/dist/crdt/doc/capability.d.ts +0 -56
  43. package/dist/crdt/doc/capability.js +0 -207
  44. package/dist/crdt/doc/content.d.ts +0 -16
  45. package/dist/crdt/doc/content.js +0 -77
  46. package/dist/crdt/doc/delete.d.ts +0 -15
  47. package/dist/crdt/doc/delete.js +0 -84
  48. package/dist/crdt/doc/layout.d.ts +0 -9
  49. package/dist/crdt/doc/layout.js +0 -178
  50. package/dist/crdt/doc/meta.d.ts +0 -19
  51. package/dist/crdt/doc/meta.js +0 -198
  52. package/dist/crdt/doc/moves.d.ts +0 -21
  53. package/dist/crdt/doc/moves.js +0 -274
  54. package/dist/crdt/doc/split-merge.d.ts +0 -10
  55. package/dist/crdt/doc/split-merge.js +0 -179
  56. package/dist/crdt/doc/steps.d.ts +0 -65
  57. package/dist/crdt/doc/steps.js +0 -311
  58. package/dist/crdt/text/index/cache.d.ts +0 -16
  59. package/dist/crdt/text/index/cache.js +0 -175
  60. package/dist/crdt/text/index/claims.d.ts +0 -18
  61. package/dist/crdt/text/index/claims.js +0 -203
  62. package/dist/crdt/text/index/fold.d.ts +0 -21
  63. package/dist/crdt/text/index/fold.js +0 -656
  64. package/dist/crdt/text/index/layout.d.ts +0 -22
  65. package/dist/crdt/text/index/layout.js +0 -258
  66. package/dist/crdt/text/index/placement.d.ts +0 -47
  67. package/dist/crdt/text/index/placement.js +0 -738
  68. package/dist/crdt/text/index/records.d.ts +0 -13
  69. package/dist/crdt/text/index/records.js +0 -139
  70. package/dist/crdt/text/index/report.d.ts +0 -18
  71. package/dist/crdt/text/index/report.js +0 -337
  72. package/dist/crdt/text/index/state.d.ts +0 -197
  73. package/dist/crdt/text/index/state.js +0 -116
  74. package/dist/crdt/text/index/streams.d.ts +0 -25
  75. package/dist/crdt/text/index/streams.js +0 -248
@@ -1,7 +1,7 @@
1
1
  import type { EngineNode } from '../../engine-api.js';
2
2
  import type { BlockId, BlockRec } from '../../placement/model.js';
3
3
  import type { ContentRun, DisplayRoles } from '../runs.js';
4
- import type { SelfChecks } from './state.js';
4
+ import type { IndexFacts, SelfChecks } from './build.js';
5
5
  /**
6
6
  * The facet name of a block's registry entry itself (inserted or removed) —
7
7
  * every other facet is named by the block attr it entered through.
@@ -65,12 +65,8 @@ export declare const sameShape: (roles: DisplayRoles, a: string, b: string) => b
65
65
  */
66
66
  export declare const indexChecks: {
67
67
  on: boolean;
68
- of?: (ix: never) => SelfChecks;
68
+ of?: (facts: IndexFacts) => SelfChecks;
69
69
  };
70
- /** `ix`'s checker ({@link indexChecks}), built on its first check. */
71
- export declare const checksOf: (ix: {
72
- checks: SelfChecks | null;
73
- }) => SelfChecks;
74
70
  /** Add `value` to `key`'s set in `index`. */
75
71
  export declare const addTo: <K, V>(index: Map<K, Set<V>>, key: K, value: V) => void;
76
72
  /** Remove `value` from `key`'s set in `index` (the set goes once empty). */
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { cloneJsonSafe } from '../../../utils/json.js';
7
7
  import { CONTENT, DATA, DATA_LEAF_PREFIX, ID, LAST_CHANGED_ATTR, TYPE } from '../../schema.js';
8
+ import { getOr } from '../../../utils.js';
8
9
  /**
9
10
  * The facet name of a block's registry entry itself (inserted or removed) —
10
11
  * every other facet is named by the block attr it entered through.
@@ -93,13 +94,9 @@ export const sameShape = (roles, a, b) => {
93
94
  * difference; after every report, the published tree.
94
95
  */
95
96
  export const indexChecks = { on: false };
96
- /** `ix`'s checker ({@link indexChecks}), built on its first check. */
97
- export const checksOf = (ix) => (ix.checks ??= indexChecks.of(ix));
98
97
  /** Add `value` to `key`'s set in `index`. */
99
98
  export const addTo = (index, key, value) => {
100
- let set = index.get(key);
101
- if (set === undefined)
102
- index.set(key, (set = new Set()));
99
+ const set = getOr(index, key, () => new Set());
103
100
  set.add(value);
104
101
  };
105
102
  /** Remove `value` from `key`'s set in `index` (the set goes once empty). */
@@ -7,6 +7,7 @@ import { fitMarks, writeMarks } from './marks.js';
7
7
  import { nodeStart } from './items.js';
8
8
  import { readRange } from './ranges.js';
9
9
  import { claimsIn, delimiters, displayOf, locate, ownedLength, pieces, placeText, rangesOf, removedKeys, scanText } from './streams.js';
10
+ import { getOr } from '../../utils.js';
10
11
  export { isBoundary, isClaimItem, isRowMark, nodeStart } from './items.js';
11
12
  export { canonKey, deepFreeze, inlineItemOf, protectItems, readRange } from './ranges.js';
12
13
  export { byId, claimsIn, delimiters, displayOf, locate, ownedLength, pieces, placeText, removedKeys, scanText } from './streams.js';
@@ -107,9 +108,7 @@ export const readSegs = (segs, stats) => {
107
108
  const out = [];
108
109
  const cursors = new Map();
109
110
  for (const seg of segs) {
110
- let cur = cursors.get(seg.text);
111
- if (cur === undefined)
112
- cursors.set(seg.text, (cur = openRangeCursor(seg.text)));
111
+ const cur = getOr(cursors, seg.text, () => openRangeCursor(seg.text));
113
112
  readRange(cur, seg.i0, seg.i1, stats, out);
114
113
  }
115
114
  return out;
@@ -53,17 +53,16 @@
53
53
  * advancing the published tree in place (after a whole rebuild, the
54
54
  * reachable tree is compared).
55
55
  *
56
- * The index is built from parts under `index/`, each over the shared state
57
- * (`index/state.ts`) and the parts before it: the claim graph
58
- * (`claims.ts`), the stream table and each block's claims (`streams.ts`),
59
- * the layout rules (`layout.ts`), placements and the
60
- * children index (`placement.ts`), block records (`records.ts`), the run
61
- * cache (`cache.ts`), the fold (`fold.ts`), the change report
62
- * (`report.ts`); the self-checks a test lane installs are `indexChecks`. This module declares the
63
- * index's types and wires the parts into the doc's one index.
56
+ * The index is one closure (`index/build.ts`) over its state: the claim
57
+ * graph, the stream table and each block's claims, the layout rules,
58
+ * placements and the children index, block records, the run cache, the fold
59
+ * and the change report; the self-checks a test lane installs are
60
+ * `indexChecks`. This module declares the index's types.
64
61
  */
65
- import type { EngineApi, EngineDoc } from '../engine-api.js';
62
+ import type { EngineApi } from '../engine-api.js';
66
63
  import type { BlockId, ContentItem, ModelView, ProjectedBlock } from '../placement/model.js';
64
+ import { indexOf } from './index/build.js';
65
+ export { indexOf };
67
66
  export { CONTENT_ATTR, ENTRY_FACET, SEQ_FACET, indexChecks } from './index/shared.js';
68
67
  /**
69
68
  * One visible run of a block — the maintained form of `ContentItem`.
@@ -257,9 +256,7 @@ export type DisplayRoles = {
257
256
  of: (type: string | null) => KindRole;
258
257
  declared: () => DeclaredKinds;
259
258
  };
260
- /** The doc's index — built on first use, torn down when the doc is destroyed. */
261
- export declare const indexOf: (doc: EngineDoc) => RunView;
262
259
  /** The index binding (the public binding's `runs`): {@link indexOf}. */
263
260
  export declare const bindRuns: (_Y: EngineApi) => {
264
- attach: (doc: EngineDoc) => RunView;
261
+ attach: (doc: import("../engine-api.js").EngineDoc) => RunView;
265
262
  };
@@ -1,168 +1,5 @@
1
- import { isNodeLike } from '../schema.js';
2
- import { cloneJsonSafe } from '../../utils/json.js';
3
- import { indexState } from './index/state.js';
4
- import { indexClaims } from './index/claims.js';
5
- import { indexStreams } from './index/streams.js';
6
- import { indexLayout } from './index/layout.js';
7
- import { indexPlacement } from './index/placement.js';
8
- import { indexRecords } from './index/records.js';
9
- import { indexCache } from './index/cache.js';
10
- import { indexFold } from './index/fold.js';
11
- import { indexReporter } from './index/report.js';
1
+ import { indexOf } from './index/build.js';
2
+ export { indexOf };
12
3
  export { CONTENT_ATTR, ENTRY_FACET, SEQ_FACET, indexChecks } from './index/shared.js';
13
- /** One index per engine doc, shared by every binding (the doc's lifetime). */
14
- const indexes = new WeakMap();
15
- /** The doc's index — built on first use, torn down when the doc is destroyed. */
16
- export const indexOf = (doc) => {
17
- let index = indexes.get(doc);
18
- if (index === undefined)
19
- indexes.set(doc, (index = buildView(doc)));
20
- return index;
21
- };
22
4
  /** The index binding (the public binding's `runs`): {@link indexOf}. */
23
5
  export const bindRuns = (_Y) => ({ attach: indexOf });
24
- const buildView = (doc) => {
25
- // The index's parts, each over the state and the parts before it (`index/*`).
26
- const ix0 = indexState(doc);
27
- const ix1 = Object.assign(ix0, indexClaims(ix0));
28
- const ix2 = Object.assign(ix1, indexStreams(ix1));
29
- const ix4 = Object.assign(ix2, indexLayout(ix2));
30
- const ix5 = Object.assign(ix4, indexPlacement(ix4));
31
- const ix6 = Object.assign(ix5, indexRecords(ix5));
32
- const ix7 = Object.assign(ix6, indexCache(ix6));
33
- const ix8 = Object.assign(ix7, indexFold(ix7));
34
- const ix = Object.assign(ix8, indexReporter(ix8));
35
- const { registry, blocks, rows, homeOfText, shells, placementsMap, frames, displays, ownShim, ensurePlacements, typeOf, order, rebuildTable, scanRow, applyReclaims, updateBlockRec, syncIncarnations, intern, debug, runs, settle, syncPending, syncAll, openTx, onCommit, committed, itemsOf, projectBlock, publish, onUpdate, onReport, hasSubscribers } = ix;
36
- const ctx = {
37
- blocks,
38
- own: ownShim,
39
- get placements() {
40
- ensurePlacements();
41
- return placementsMap;
42
- },
43
- get kids() {
44
- ensurePlacements();
45
- return ix.kidsMap;
46
- },
47
- get order() {
48
- ensurePlacements();
49
- return order();
50
- },
51
- // The publication boundary shares THIS interner, so a payload
52
- // emitted by `project()`/`contentItems()` is `===` the runs' one.
53
- intern,
54
- displays,
55
- accepted: (id) => {
56
- ensurePlacements();
57
- return ix.rejected.has(id) ? null : (ix.edges.get(id) ?? null);
58
- }
59
- };
60
- // ── initial scan: index every existing block ────────────────────
61
- registry.forEachAttr((v, id) => {
62
- if (!isNodeLike(v))
63
- return;
64
- updateBlockRec(id);
65
- for (const b of [id, ...syncIncarnations(id)]) {
66
- const row = scanRow(b);
67
- if (row !== undefined) {
68
- rows.set(b, row);
69
- homeOfText.set(row.text, b);
70
- }
71
- }
72
- });
73
- rebuildTable(new Set());
74
- applyReclaims(null);
75
- settle(shells, null);
76
- // Every commit folds once, before the document's `afterTransaction` listeners.
77
- doc.on('commit', onCommit);
78
- /** Derived state lives exactly as long as the doc. */
79
- const teardown = () => {
80
- doc.off('commit', onCommit);
81
- doc.off('destroy', teardown);
82
- doc.off('update', onUpdate);
83
- indexes.delete(doc);
84
- };
85
- doc.on('destroy', teardown);
86
- // ── public surface ───────────────────────────────────────────────
87
- const view = {
88
- version: () => {
89
- syncAll();
90
- return ix.version;
91
- },
92
- runs,
93
- contentItems: (b) => {
94
- syncAll();
95
- return blocks.get(b)?.deleted === false ? itemsOf(b) : [];
96
- },
97
- // Inline atoms always carry `data` (`{}` when absent) — the public
98
- // `JSONInlineBlock` shape of `edytor.value`.
99
- contentJSON: (b) => runs(b).map((r) => r.kind === 'text'
100
- ? { text: r.text, ...(r.marks !== undefined && { marks: cloneJsonSafe(r.marks) }) }
101
- : { id: r.id, type: r.type, data: r.data === undefined ? {} : cloneJsonSafe(r.data) }),
102
- view: (tr) => {
103
- syncAll();
104
- if (tr !== undefined && !committed.has(tr))
105
- syncPending(tr);
106
- return ctx;
107
- },
108
- displayType: (id) => {
109
- if (ix.roles === null)
110
- return undefined;
111
- syncAll();
112
- ensurePlacements();
113
- const shown = blocks.has(id) ? typeOf(id) : undefined;
114
- return shown === blocks.get(id)?.type ? undefined : shown;
115
- },
116
- dissolved: (id) => {
117
- syncAll();
118
- ensurePlacements();
119
- return ix.dissolved.has(id);
120
- },
121
- project: (root) => {
122
- syncAll();
123
- ensurePlacements();
124
- return root === undefined
125
- ? (ix.kidsMap.get(null) ?? []).map((k) => projectBlock(k.id))
126
- : [projectBlock(root)];
127
- },
128
- roles: (next) => {
129
- ix.roles = next;
130
- ix.placementFull = true;
131
- ix.version++;
132
- // No commit carries a role change: report it now (not inside a
133
- // transaction, whose commit reports it), so every view follows.
134
- if (hasSubscribers() && !openTx())
135
- publish(null, false);
136
- },
137
- track: () => {
138
- syncAll();
139
- const f = { touched: new Map(), wrote: false };
140
- frames.add(f);
141
- return {
142
- end: () => {
143
- syncAll();
144
- frames.delete(f);
145
- return f;
146
- },
147
- quiet: (write) => {
148
- syncAll();
149
- const g = { touched: new Map(), wrote: false };
150
- frames.delete(f);
151
- frames.add(g);
152
- try {
153
- write();
154
- syncAll();
155
- }
156
- finally {
157
- frames.delete(g);
158
- frames.add(f);
159
- f.wrote ||= g.wrote;
160
- }
161
- }
162
- };
163
- },
164
- onReport,
165
- debug
166
- };
167
- return view;
168
- };
@@ -10,3 +10,5 @@
10
10
  * through its child index); a disconnected one keeps its offset.
11
11
  */
12
12
  export declare const getTextContentOffsetAtPoint: (textNode: Node, node: Node, offset: number) => number;
13
+ /** `element`'s text nodes in document order: the leaves the offsets above count. */
14
+ export declare const textLeaves: (element: Node) => CharacterData[];
@@ -22,3 +22,11 @@ export const getTextContentOffsetAtPoint = (textNode, node, offset) => {
22
22
  range.setEnd(node, at);
23
23
  return range.toString().length;
24
24
  };
25
+ /** `element`'s text nodes in document order: the leaves the offsets above count. */
26
+ export const textLeaves = (element) => {
27
+ const walker = (element.ownerDocument ?? document).createTreeWalker(element, NodeFilter.SHOW_TEXT);
28
+ const leaves = [];
29
+ while (walker.nextNode())
30
+ leaves.push(walker.currentNode);
31
+ return leaves;
32
+ };