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.
Files changed (147) hide show
  1. package/README.md +2 -2
  2. package/dist/block/block.svelte.js +6 -21
  3. package/dist/block/inlineBlock.svelte.js +4 -6
  4. package/dist/clipboard/moveText.js +6 -8
  5. package/dist/cloudflare/DocumentRoom.d.ts +10 -3
  6. package/dist/cloudflare/index.d.ts +1 -1
  7. package/dist/cloudflare/room/access.d.ts +8 -3
  8. package/dist/cloudflare/room/access.js +44 -20
  9. package/dist/cloudflare/room/admission.js +28 -5
  10. package/dist/cloudflare/room/comments.js +28 -1
  11. package/dist/cloudflare/room/context.d.ts +115 -106
  12. package/dist/cloudflare/room/context.js +10 -3
  13. package/dist/cloudflare/room/forged.d.ts +14 -0
  14. package/dist/cloudflare/room/forged.js +30 -2
  15. package/dist/cloudflare/room/frames.d.ts +4 -0
  16. package/dist/cloudflare/room/frames.js +5 -1
  17. package/dist/cloudflare/room/purge.js +2 -1
  18. package/dist/cloudflare/room/replicas.d.ts +4 -2
  19. package/dist/cloudflare/room/replicas.js +8 -3
  20. package/dist/cloudflare/room/suggest.d.ts +7 -0
  21. package/dist/cloudflare/room/suggest.js +143 -0
  22. package/dist/cloudflare/routeDocumentSocket.d.ts +10 -1
  23. package/dist/cloudflare/routeDocumentSocket.js +5 -3
  24. package/dist/components/Content.svelte +9 -1
  25. package/dist/crdt/anchors.js +3 -2
  26. package/dist/crdt/attribution/attribution.d.ts +3 -0
  27. package/dist/crdt/attribution/attribution.js +3 -3
  28. package/dist/crdt/doc/capability.js +9 -13
  29. package/dist/crdt/doc/funnel.d.ts +1 -1
  30. package/dist/crdt/doc/funnel.js +5 -2
  31. package/dist/crdt/doc/gate.d.ts +1 -1
  32. package/dist/crdt/doc/history.d.ts +6 -0
  33. package/dist/crdt/doc/history.js +77 -56
  34. package/dist/crdt/doc/layout.js +5 -5
  35. package/dist/crdt/doc/meta.js +6 -7
  36. package/dist/crdt/doc/reads.d.ts +2 -2
  37. package/dist/crdt/doc/reads.js +18 -28
  38. package/dist/crdt/doc/steps.js +4 -4
  39. package/dist/crdt/doc/suggest.d.ts +167 -0
  40. package/dist/crdt/doc/suggest.js +579 -0
  41. package/dist/crdt/document.d.ts +10 -1
  42. package/dist/crdt/document.js +19 -11
  43. package/dist/crdt/edytor-doc.d.ts +355 -333
  44. package/dist/crdt/edytor-doc.js +125 -82
  45. package/dist/crdt/engine-api.d.ts +8 -2
  46. package/dist/crdt/engine.d.ts +2 -1
  47. package/dist/crdt/engine.js +3 -1
  48. package/dist/crdt/flow.d.ts +1 -1
  49. package/dist/crdt/flow.js +4 -10
  50. package/dist/crdt/index.d.ts +111 -105
  51. package/dist/crdt/index.js +3 -0
  52. package/dist/crdt/operations.d.ts +12 -3
  53. package/dist/crdt/parts.d.ts +43 -0
  54. package/dist/crdt/parts.js +44 -0
  55. package/dist/crdt/placement/display.d.ts +1 -1
  56. package/dist/crdt/placement/display.js +3 -3
  57. package/dist/crdt/placement/keys.d.ts +5 -0
  58. package/dist/crdt/placement/keys.js +5 -0
  59. package/dist/crdt/placement/resolve.js +2 -1
  60. package/dist/crdt/protocol.d.ts +1 -1
  61. package/dist/crdt/protocol.js +1 -1
  62. package/dist/crdt/protocols/auth.d.ts +11 -1
  63. package/dist/crdt/protocols/auth.js +17 -1
  64. package/dist/crdt/protocols/comments.d.ts +16 -1
  65. package/dist/crdt/protocols/comments.js +9 -1
  66. package/dist/crdt/providers/index.d.ts +6 -4
  67. package/dist/crdt/providers/index.js +3 -1
  68. package/dist/crdt/providers/websocket.d.ts +6 -4
  69. package/dist/crdt/providers/websocket.js +9 -4
  70. package/dist/crdt/purge.d.ts +7 -1
  71. package/dist/crdt/purge.js +32 -2
  72. package/dist/crdt/restore.d.ts +2 -1
  73. package/dist/crdt/restore.js +9 -0
  74. package/dist/crdt/schema.d.ts +9 -1
  75. package/dist/crdt/schema.js +13 -3
  76. package/dist/crdt/structs.d.ts +2 -0
  77. package/dist/crdt/structs.js +2 -0
  78. package/dist/crdt/text/index/claims.js +1 -23
  79. package/dist/crdt/text/index/layout.d.ts +2 -4
  80. package/dist/crdt/text/index/layout.js +9 -22
  81. package/dist/crdt/text/index/placement.js +21 -24
  82. package/dist/crdt/text/index/shared.js +17 -14
  83. package/dist/crdt/text/model.d.ts +10 -0
  84. package/dist/crdt/text/model.js +8 -1
  85. package/dist/crdt/text/runs.d.ts +34 -30
  86. package/dist/crdt/vendor/yjs/UPSTREAM.md +83 -0
  87. package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
  88. package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +6 -3
  89. package/dist/crdt/vendor/yjs/dts/ynode.d.ts +13 -2
  90. package/dist/crdt/vendor/yjs/src/index.js +1 -1
  91. package/dist/crdt/vendor/yjs/src/structs/Item.js +44 -5
  92. package/dist/crdt/vendor/yjs/src/ynode.js +29 -7
  93. package/dist/edytor.svelte.d.ts +1 -1
  94. package/dist/edytor.svelte.js +100 -75
  95. package/dist/events/beforeInputCommands.d.ts +2 -2
  96. package/dist/events/nativeInteractiveControl.d.ts +11 -1
  97. package/dist/events/nativeInteractiveControl.js +41 -1
  98. package/dist/events/onBeforeInput.js +3 -3
  99. package/dist/events/onFocus.js +9 -11
  100. package/dist/export/forms.d.ts +25 -25
  101. package/dist/index.d.ts +4 -2
  102. package/dist/index.js +1 -1
  103. package/dist/labels.d.ts +8 -0
  104. package/dist/labels.js +6 -1
  105. package/dist/plugins/comments/CommentsController.svelte.d.ts +5 -1
  106. package/dist/plugins/comments/CommentsController.svelte.js +14 -4
  107. package/dist/plugins/find/search.js +2 -2
  108. package/dist/plugins/index.d.ts +1 -0
  109. package/dist/plugins/index.js +1 -0
  110. package/dist/plugins/suggestions/SuggestionBars.svelte +40 -23
  111. package/dist/plugins/suggestions/SuggestionBars.svelte.d.ts +3 -1
  112. package/dist/plugins/suggestions/SuggestionRuns.svelte +77 -0
  113. package/dist/plugins/suggestions/SuggestionRuns.svelte.d.ts +9 -0
  114. package/dist/plugins/suggestions/shared.svelte.d.ts +58 -0
  115. package/dist/plugins/suggestions/shared.svelte.js +421 -0
  116. package/dist/plugins/suggestions/suggestionsPlugin.d.ts +15 -4
  117. package/dist/selection/domSelection.d.ts +2 -0
  118. package/dist/selection/domSelection.js +6 -2
  119. package/dist/selection/pointer.svelte.js +75 -48
  120. package/dist/selection/replaceSelection.js +2 -6
  121. package/dist/selection/selection.svelte.d.ts +3 -3
  122. package/dist/selection/selection.svelte.js +39 -32
  123. package/dist/selection/selection.utils.d.ts +14 -0
  124. package/dist/selection/selection.utils.js +28 -3
  125. package/dist/session/commands.js +21 -11
  126. package/dist/session/composition.svelte.d.ts +5 -3
  127. package/dist/session/composition.svelte.js +21 -17
  128. package/dist/session/handles.d.ts +4 -17
  129. package/dist/session/handles.js +11 -37
  130. package/dist/session/navigation.js +6 -9
  131. package/dist/session/selection.d.ts +11 -5
  132. package/dist/session/selection.js +14 -48
  133. package/dist/session/suggestions.svelte.d.ts +38 -9
  134. package/dist/session/suggestions.svelte.js +37 -18
  135. package/dist/session/virtual.d.ts +1 -1
  136. package/dist/surface/attributes.d.ts +5 -0
  137. package/dist/surface/attributes.js +2 -2
  138. package/dist/surface/cells.d.ts +2 -26
  139. package/dist/surface/cells.js +2 -33
  140. package/dist/surface/observer.svelte.d.ts +6 -1
  141. package/dist/surface/observer.svelte.js +128 -81
  142. package/dist/surface/pin.svelte.d.ts +9 -9
  143. package/dist/surface/pin.svelte.js +15 -22
  144. package/dist/surface/projector.svelte.js +8 -14
  145. package/dist/text/text.svelte.js +14 -19
  146. package/dist/themes/notion.css +29 -0
  147. package/package.json +3 -1
@@ -105,7 +105,7 @@ export const docFacade = (Y, layers) => {
105
105
  // per-doc (WeakMap-keyed), so facades on the same doc share it.
106
106
  const BA = bindBlockAttribution(Y);
107
107
  const { init, seed } = bindSeed(Y, BA);
108
- return (doc, config = {}) => {
108
+ const create = (doc, config = {}) => {
109
109
  adoptRules(doc);
110
110
  setMarkEdges(doc, config.markEdge ?? (() => undefined));
111
111
  const roleOf = config.roleOf ?? (() => undefined);
@@ -123,21 +123,42 @@ export const docFacade = (Y, layers) => {
123
123
  // A layout displays only its items — its
124
124
  // `defaultChild` kind — and only two or more (`layout.*`). A table
125
125
  // displays only its rows and a row only its cells (`table.*`).
126
+ let kinds = new Map();
127
+ let declared;
126
128
  const roles = {
127
- childless: (type) => roleOf(type)?.void === true,
128
- island: (type) => roleOf(type)?.island === true,
129
- container: (type) => !rendersContentOf(type) && roleOf(type)?.void !== true && roleOf(type)?.island !== true,
130
- rendersContent: (type) => rendersContentOf(type),
131
- defaultChild: (type) => (type !== null ? defaultChildOf(type) : undefined) ?? defaultType,
132
- line: (type) => {
133
- const role = roleOf(type);
134
- return role?.island === true && role.lines === true ? defaultChildOf(type) : undefined;
129
+ of: (type) => {
130
+ let k = kinds.get(type);
131
+ if (k === undefined) {
132
+ const role = type === null ? undefined : roleOf(type);
133
+ const own = type === null ? undefined : defaultChildOf(type);
134
+ const renders = type === null || rendersContentOf(type);
135
+ kinds.set(type, (k = {
136
+ childless: role?.void === true,
137
+ island: role?.island === true,
138
+ container: !renders && role?.void !== true && role?.island !== true,
139
+ rendersContent: renders,
140
+ child: own ?? defaultType,
141
+ line: role?.island === true && role.lines === true ? own : undefined,
142
+ layout: role?.layout === true ? own : undefined,
143
+ table: role?.table === true ? own : undefined
144
+ }));
145
+ }
146
+ return k;
135
147
  },
136
- lineKinds: () => [...(config.kinds?.() ?? [])].flatMap((type) => roles.line(type) ?? []),
137
- layout: (type) => (roleOf(type)?.layout === true ? defaultChildOf(type) : undefined),
138
- layoutKinds: () => [...(config.kinds?.() ?? [])].filter((type) => roles.layout(type) !== undefined),
139
- table: (type) => (roleOf(type)?.table === true ? defaultChildOf(type) : undefined),
140
- tableKinds: () => [...(config.kinds?.() ?? [])].filter((type) => roles.table(type) !== undefined)
148
+ declared: () => {
149
+ if (declared === undefined) {
150
+ const all = [...(config.kinds?.() ?? [])].map(roles.of);
151
+ const rows = new Map(all.flatMap((k) => (k.table ? [[k.table, roles.of(k.table).child]] : [])));
152
+ declared = {
153
+ lines: new Set(all.flatMap((k) => k.line ?? [])),
154
+ layouts: [...(config.kinds?.() ?? [])].filter((t) => roles.of(t).layout !== undefined),
155
+ items: new Set(all.flatMap((k) => k.layout ?? [])),
156
+ rows,
157
+ cells: new Set(rows.values())
158
+ };
159
+ }
160
+ return declared;
161
+ }
141
162
  };
142
163
  if (config.roleOf)
143
164
  runsView.roles(roles);
@@ -159,52 +180,51 @@ export const docFacade = (Y, layers) => {
159
180
  const { anchorAt, followUndo, resolveAnchor } = docAnchors(reads);
160
181
  const steps = { ...shape, ...planSteps(shape) };
161
182
  const { plan } = steps;
162
- // The prepared op families (`OpsContext`: the reads, capability and step writers).
163
- const { insertBlocks, moveBlocks, unNestBlocks, unNestBlock, landingOf, liftOut, duplicateBlock } = moveOps(steps);
164
- const { besideAt, placeBeside, wrapInLayout } = layoutOps(steps);
165
- const { splitBlock, mergeBlocks, mergeBackward, mergeForward } = splitMergeOps(steps);
166
- const { deleteBlocks, deleteBlock } = deleteOps(steps);
167
- const { dataSteps, replaceData, setBlockType, patchData, setBlock } = metaOps(steps);
168
- const { insertText, deleteText, formatRange, clearMarks, insertInline, removeInline } = contentOps(steps);
183
+ // The prepared op families (`OpsContext`: the reads, capability and step
184
+ // writers): every op they answer is a document write, but for the reads
185
+ // and step writers taken out here.
186
+ const { landingOf, ...moves } = moveOps(steps);
187
+ const { besideAt, ...layouts } = layoutOps(steps);
188
+ const { dataSteps, replaceData, ...metas } = metaOps(steps);
189
+ const deletes = deleteOps(steps);
169
190
  /** What range deletion and flow placement compose: the step writers and the ops. */
170
- const ops = { ...steps, insertBlocks, deleteBlocks, dataSteps, replaceData };
191
+ const ops = { ...steps, ...moves, ...deletes, dataSteps, replaceData };
171
192
  /** Every document op, prepared — `apply(prepare.op(…))` is the op. */
172
193
  const prepare = {
173
- insertBlocks,
174
- moveBlocks,
194
+ ...moves,
195
+ ...layouts,
196
+ ...splitMergeOps(steps),
197
+ ...deletes,
198
+ ...metas,
199
+ ...contentOps(steps),
175
200
  /**
176
201
  * Move `id` to the last position under `parent` — under a container
177
202
  * it is no item of, under its last item (`nestParent`: Tab after a list).
178
203
  */
179
204
  nestBlock: (id, parent) => {
180
205
  const at = nestParent([ref(id)], ref(parent));
181
- return moveBlocks([id], { parent: at, index: childrenIds(at).length });
206
+ return moves.moveBlocks([id], { parent: at, index: childrenIds(at).length });
182
207
  },
183
- unNestBlock,
184
- unNestBlocks,
185
- liftOut,
186
- placeBeside,
187
- wrapInLayout,
188
- splitBlock,
189
- mergeBlocks,
190
- mergeBackward,
191
- mergeForward,
192
- deleteBlock,
193
- setBlock,
194
- setBlockType,
195
- patchData,
196
- duplicateBlock,
197
- insertText,
198
- deleteText,
199
- formatRange,
200
- clearMarks,
201
- insertInline,
202
- removeInline,
203
208
  /** Delete a block selection — one plan; only the members leave (`deleteBlocks` above). */
204
- deleteBlocks: (ids) => deleteBlocks(ids),
209
+ deleteBlocks: (ids) => deletes.deleteBlocks(ids),
205
210
  ...rangeDeleteOps(ops),
206
211
  ...flowOps(ops)
207
212
  };
213
+ /**
214
+ * What a part built over this document reads beyond the facade (the
215
+ * shared suggestions, `doc/suggest.ts`): the reads, a facade over
216
+ * another doc (`create`, with this `config`);
217
+ * `v` counts its changes no index fact shows (in `version`), and
218
+ * `base`, when set, is the export `toJSON()` gives unless asked for
219
+ * the suggestions.
220
+ */
221
+ const part = {
222
+ ...reads,
223
+ config,
224
+ create: create,
225
+ v: 0,
226
+ base: undefined
227
+ };
208
228
  /**
209
229
  * Plans prepared at one version, as one plan (refused if any part is;
210
230
  * stamped with the oldest part's version, so `apply` refuses a stale
@@ -226,7 +246,11 @@ export const docFacade = (Y, layers) => {
226
246
  * omitted when empty): the one serializer, {@link blockJSON}, over the
227
247
  * root's visible children.
228
248
  */
229
- const toJSON = () => {
249
+ const toJSON = (options) => {
250
+ // A part's export first (the shared suggestions': without the pending ones, `sugg.json.base`).
251
+ const base = !options?.suggestions && part.base?.();
252
+ if (base)
253
+ return base;
230
254
  const data = docData();
231
255
  const children = childrenIds(null).map(blockJSON);
232
256
  return Object.keys(data).length > 0
@@ -236,32 +260,17 @@ export const docFacade = (Y, layers) => {
236
260
  // ── facade object ─────────────────────────────────────────────────
237
261
  /** A read taking an id first: the id normalizes at ingress. */
238
262
  const byRef = (f) => (id, ...rest) => f(ref(id), ...rest);
239
- const facade = {
240
- // lifecycle
241
- init: (opts) => write(() => init(doc, opts)),
242
- /** Apply the deterministic seed of `value` and the document's `data` — the document's seed decision. */
243
- seed: (value, data) => write(() => seed(doc, value, defaultType, data)),
244
- isInitialized: () => isInitialized(doc),
245
- /** Replicated `meta.v` schema version (the module-level read, bound). */
246
- schemaVersion: () => schemaVersion(doc),
247
- /**
248
- * The schema gate for this doc — throws {@link SchemaMismatchError}
249
- * on unversioned-content or unsupported-version state. Consumers
250
- * (`Edytor.sync()`, packed consumers) call it before trusting
251
- * a synced doc.
252
- */
253
- checkSchema: () => checkSchema(doc),
254
- assertSchema: () => assertSchema(doc),
255
- dispose,
256
- createUndoManager,
263
+ /**
264
+ * The public operations (`DocumentOperations`), each name once: what
265
+ * an `EdytorDocument` forwards. The facade has them and the internal
266
+ * members below.
267
+ */
268
+ const api = {
257
269
  // reads — every id argument normalizes at ingress
258
270
  project: () => project(doc),
259
271
  toJSON,
260
272
  blockJSON: byRef(blockJSON),
261
273
  childrenIds: byRef(childrenIds),
262
- /** Visible children of `parent` with their ranks, in `(rank, id)` order. */
263
- childSlots: (parent) => view().kids.get(parent) ?? [],
264
- slotOf: byRef(slotOf),
265
274
  positionOf: byRef(positionOf),
266
275
  pathOf: byRef(pathOf),
267
276
  parentOf: byRef((id) => positionOf(id)?.parent ?? null),
@@ -279,8 +288,6 @@ export const docFacade = (Y, layers) => {
279
288
  * O(1) per call; live-replicated (remote values read the same).
280
289
  */
281
290
  blockAttribution: byRef((id) => blockAttributionOf(doc, id)),
282
- crdtId: byRef((id) => crdtId(doc, id)),
283
- resolveBlock: byRef((id) => resolveBlock(doc, id)),
284
291
  displayLength: byRef(displayLength),
285
292
  contentItems: byRef(contentItems),
286
293
  hasBlock: byRef(hasBlock),
@@ -292,10 +299,6 @@ export const docFacade = (Y, layers) => {
292
299
  // caret anchors — backing-text-bound selection endpoints
293
300
  anchorAt: byRef(anchorAt),
294
301
  resolveAnchor,
295
- followUndo,
296
- // roles
297
- /** Re-read the roles after `roleOf` answers differently (roles adopted later). */
298
- rolesChanged: () => runsView.roles(roles),
299
302
  isVoid: byRef(isVoid),
300
303
  isIsland: byRef(isIsland),
301
304
  isLines: byRef(isLines),
@@ -331,10 +334,8 @@ export const docFacade = (Y, layers) => {
331
334
  nestParent: (ids, parent) => nestParent(ids.map(ref), ref(parent)),
332
335
  /** Where a block of `kind` at `id`'s place lands, and the containers it leaves (`liftOut`). */
333
336
  landingOf: (id, kind, after) => landingOf(ref(id), ref(kind), after),
334
- defaultChild: byRef(defaultChild),
335
337
  // maintained runs (bound to this doc)
336
338
  runs: byRef(runsView.runs),
337
- contentJSON: byRef(runsView.contentJSON),
338
339
  // events
339
340
  onChange,
340
341
  // every op — each returns an {@link OpResult}; `apply(prepare.op(…))`
@@ -347,10 +348,6 @@ export const docFacade = (Y, layers) => {
347
348
  // transactions (composed ops already run in one; expose for callers
348
349
  // that batch several ops into one undo step / one event)
349
350
  transact: (fn, origin) => write(() => doc.transact(fn, origin)),
350
- // escape hatch for the history and debugging — the bound engine layers.
351
- model: layers.model,
352
- text: layers.text,
353
- runsView,
354
351
  // ── model-state version ─────────────────────────────
355
352
  /**
356
353
  * The index version — bumps on every fold that changed derived
@@ -359,11 +356,57 @@ export const docFacade = (Y, layers) => {
359
356
  * post-write state — this is the read-your-writes contract.
360
357
  */
361
358
  get version() {
362
- return runsView.version();
359
+ // A part's change may show in no index fact (a suggestion's decision).
360
+ return runsView.version() + part.v;
363
361
  }
364
362
  };
365
- return facade;
363
+ const internal = {
364
+ // lifecycle
365
+ init: (opts) => write(() => init(doc, opts)),
366
+ /** Apply the deterministic seed of `value` and the document's `data` — the document's seed decision. */
367
+ seed: (value, data) => write(() => seed(doc, value, defaultType, data)),
368
+ isInitialized: () => isInitialized(doc),
369
+ /** Replicated `meta.v` schema version (the module-level read, bound). */
370
+ schemaVersion: () => schemaVersion(doc),
371
+ /**
372
+ * The schema gate for this doc — throws {@link SchemaMismatchError}
373
+ * on unversioned-content or unsupported-version state. Consumers
374
+ * (`Edytor.sync()`, packed consumers) call it before trusting
375
+ * a synced doc.
376
+ */
377
+ checkSchema: () => checkSchema(doc),
378
+ assertSchema: () => assertSchema(doc),
379
+ dispose,
380
+ createUndoManager,
381
+ /** @internal What a part built over the document reads and writes (`doc/suggest.ts`). */
382
+ part,
383
+ /** Visible children of `parent` with their ranks, in `(rank, id)` order. */
384
+ childSlots: (parent) => view().kids.get(parent) ?? [],
385
+ slotOf: byRef(slotOf),
386
+ crdtId: byRef((id) => crdtId(doc, id)),
387
+ resolveBlock: byRef((id) => resolveBlock(doc, id)),
388
+ followUndo,
389
+ // roles
390
+ /** Re-read the roles after `roleOf` answers differently (roles adopted later). */
391
+ rolesChanged: (place = true) => {
392
+ kinds = new Map();
393
+ declared = undefined;
394
+ if (place)
395
+ runsView.roles(roles);
396
+ },
397
+ defaultChild: byRef(defaultChild),
398
+ contentJSON: byRef(runsView.contentJSON),
399
+ // escape hatch for the history and debugging — the bound engine layers.
400
+ model: layers.model,
401
+ text: layers.text,
402
+ runsView,
403
+ /** The public members' names (`EdytorDocument` forwards them). */
404
+ api: api
405
+ };
406
+ // The public members joined as they are (the `version` getter stays one).
407
+ return Object.defineProperties(internal, Object.getOwnPropertyDescriptors(api));
366
408
  };
409
+ return create;
367
410
  };
368
411
  /**
369
412
  * Bind the assembled model to a concrete engine surface. `Y` must be the
@@ -78,9 +78,15 @@ export interface EngineNode {
78
78
  * Delete `length` live units at `index`. With `into` (the document's
79
79
  * records list), they are held by one record appended there instead (a
80
80
  * delete its writer can take back), except those `fresh` names, which are
81
- * removed.
81
+ * removed. With `propose` (a suggestion's delete), each
82
+ * unit is sorted: `1` held as above (its author's own), `2` proposed (an
83
+ * id list appended to `propose.into`) or `3` stepped over; proposed and
84
+ * stepped-over units read gone until the engine's `unhide`.
82
85
  */
83
- delete(index: number, length?: number, into?: EngineNode | null, fresh?: unknown): void;
86
+ delete(index: number, length?: number, into?: EngineNode | null, fresh?: unknown, propose?: {
87
+ into: EngineNode;
88
+ sort: (client: number, clock: number) => number;
89
+ } | null): void;
84
90
  /** Append one hold record of `ids` (`client, clock, len` triples) to this records list: they read as deleted while it lives. */
85
91
  hold(ids: number[]): void;
86
92
  /**
@@ -30,6 +30,7 @@ export type EngineSymbol =
30
30
  | 'followRedone'
31
31
  | 'isParentOf'
32
32
  | 'mergeIdSets'
33
- | 'createID';
33
+ | 'createID'
34
+ | 'unhide';
34
35
 
35
36
  export declare const Y: Pick<typeof V, EngineSymbol>;
@@ -45,5 +45,7 @@ export const Y = {
45
45
  followRedone: V.followRedone,
46
46
  isParentOf: V.isParentOf,
47
47
  mergeIdSets: V.mergeIdSets,
48
- createID: V.createID
48
+ createID: V.createID,
49
+ // a suggestion's proposed deletion reads gone until its plan ends (fork patch YP32)
50
+ unhide: V.unhide
49
51
  };
@@ -82,7 +82,7 @@ export type FlowContext = OpsContext & Pick<MoveOps, 'insertBlocks'> & Pick<Dele
82
82
  * paragraph (`doc.empty.virtual`) place the caret by it.
83
83
  */
84
84
  export declare const placedEnd: (roleOf: (kind: string) => {
85
- void: boolean;
85
+ childless: boolean;
86
86
  rendersContent: boolean;
87
87
  }) => (s: BlockSpec) => DocPosition | undefined;
88
88
  /** `insertFlow`, prepared. */
package/dist/crdt/flow.js CHANGED
@@ -14,7 +14,7 @@ const lengthOf = (l) => (l.content ?? []).reduce((n, i) => n + (i.kind === 'text
14
14
  export const placedEnd = (roleOf) => {
15
15
  const endOf = (s) => {
16
16
  const role = roleOf(s.type);
17
- if (role.rendersContent && !role.void)
17
+ if (role.rendersContent && !role.childless)
18
18
  return { block: s.id, offset: lengthOf(s) };
19
19
  for (const kid of [...(s.children ?? [])].reverse()) {
20
20
  const at = endOf(kid);
@@ -27,15 +27,9 @@ export const placedEnd = (roleOf) => {
27
27
  };
28
28
  /** `insertFlow`, prepared. */
29
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
- });
30
+ const roleOf = c.roles.of;
37
31
  /** What a kind is in a table: the table, its row or its cell. */
38
- const tableKind = (kind) => c.roles.table(kind) !== undefined
32
+ const tableKind = (kind) => roleOf(kind).table !== undefined
39
33
  ? 'table'
40
34
  : c.isRowKind(kind)
41
35
  ? 'row'
@@ -150,7 +144,7 @@ export const flowOps = (c) => {
150
144
  const apart = (l, under) => {
151
145
  const kind = l.type && fit(under, l.type);
152
146
  const role = kind ? roleOf(kind) : undefined;
153
- return !!role && (!role.rendersContent || role.void || role.island);
147
+ return !!role && (!role.rendersContent || role.childless || role.island);
154
148
  };
155
149
  // At the end of a container's header whose body shows, what follows the caret
156
150
  // leads its children and the body stays, as Enter opens a first child