Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/y-delete-keeps-format-items.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@lexical/y': patch
---

[fix] A delete keeps every format item it leaves, so a comment or format a concurrent write or an undo restores ends where it ended instead of running on

A document now keeps two format items for each formatted run whose text is deleted; see "Deleted formatted text" in the collaboration docs' Limits.

Verify: comment a word, type plain text inside it on one client, and on another client that has not seen it delete the word with its neighbours, then the space after; after syncing (and undoing either edit), the comment covers only what it covered, never the following words or line.
7 changes: 7 additions & 0 deletions .changeset/y-keep-own-format-items.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@lexical/y': patch
---

[fix] An undo puts a format or comment back only where it was, also after a collaborator deleted or retyped around it, with Yjs's default garbage collection

Verify: comment a word on one client, remove the comment on another, undo on the first and then on the second (syncing after each step), with documents made by `createYDoc()`: the comment comes back on that word or nowhere, never over the following paragraphs.
39 changes: 26 additions & 13 deletions packages/lexical-website/docs/collaboration/y.md
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,25 @@ not merge as a user might expect:
undoing it leaves nothing. For comments, keep resolved ids in the text and
mark the threads resolved in your own store instead (see
[Resolving comments](./comments.md#resolving-comments)).
- **Deleted formatted text.** A delete keeps every format item it leaves,
as a collaborator's concurrent edit there and an undo of the delete rely
on them: each formatted run (a format, a comment, a NodeState value)
whose text is deleted leaves its two items (its opener and its closer).
Plain typing and deleting add none, and neither does typing
inside a formatted run. So a document grows with the formatted text
deleted from it, not only with its content: most in a place where
formatted text is typed and deleted over and over, where edits also get
slower (a comment added and its word deleted 3,000 times at one place:
41 ms per edit, against 27 ms when a delete still removed those items).
- **Deleted format items a client can undo.** While a client can undo a
format change, it keeps that change's format items, even after a
collaborator deletes them, so its undo still reads them; it lets them go
when its undo history is cleared or the binding stops. Until the
document reloads, that client's document, and any state it encodes,
holds those deleted items: about 25 bytes each (100 rounds of one client
bolding a word and another clearing it: 2,603 bytes for the first
client's state against 229 for the second). A server or relay that loads
such a state with garbage collection on drops them.
- **Named slots.** A slot holds one node: two collaborators setting the same
slot at once keep one writer's node, and text typed in a slot that a
collaborator replaces or removes at the same time is lost (as with delete
Expand Down Expand Up @@ -1218,11 +1237,7 @@ not merge as a user might expect:
entirely, the undo manager skips that step as changing nothing, and the
same undo also reverts your step before it. When you undo a format change
while a collaborator removes that format and undoes the removal, the text
keeps the format: the collaborator's undo brings it back. A comment or
format can run on past its end when writes two collaborators made inside
it are undone while another client deletes text across its end: it
carries on over the following words, possibly into the next line. No
text is lost. A format a collaborator applies
keeps the format: the collaborator's undo brings it back. A format a collaborator applies
starting right where a run of that format ends, or from inside the run
past its end, can be lost on their text after the run when a client
other than the one that formatted the run, at the same time, removes the
Expand Down Expand Up @@ -1314,12 +1329,9 @@ not merge as a user might expect:
text typed inside it at the same time lands next to it, in an inline
element of its old form. Where text was deleted, the format items it
leaves are kept, so that a collaborator's concurrent edit inside or at
the deleted text keeps its formats, until a later delete at the same
place keeps a few per format key of them; text a collaborator types
inside the earlier deleted text after that, where its format changed
more than once along it, takes the format that text had at its start,
and so does that text where an undo brings it back after another
collaborator's delete there. Two joins at once into the same line both
the deleted text keeps its formats, and an undo of the delete brings the
text back with them (see Deleted formatted text in [Limits](#limits)).
Two joins at once into the same line both
write its type, and Yjs keeps one of them by client id: a heading joined
across a quote to the paragraph after it, while a collaborator joins that
paragraph into the quote, can become a quote.
Expand All @@ -1346,8 +1358,9 @@ reproduces it:
leave the format on text typed next to the range (see Undo above):
[#9560](https://github.com/meta/lexical/issues/9560).
- A comment can spread onto later words when a client types uncommented
text inside it offline while a collaborator's deletes there drop the item
that ended it: [#9564](https://github.com/meta/lexical/issues/9564).
text inside it offline while a collaborator's write removes the item that
ended it (a delete no longer does: it keeps every format item it leaves):
[#9564](https://github.com/meta/lexical/issues/9564).
- Turning a paragraph inside a container that is itself inside a
container (both not shadow roots) into a list removes the outer
container and makes no list, in every `@lexical/y` editor (it runs
Expand Down
Loading
Loading