Skip to content

[lexical-website][lexical-y] Bug Fix: Stop a format, comment or link from spreading to the end of the document after an undo or delete races an edit inside it - #9505

Merged
zurfyx merged 3 commits into
mainfrom
zurfyx/y-undo-member-closer
Oct 29, 2026

Conversation

@zurfyx

@zurfyx zurfyx commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Note

Stack, part 4 of 10. Based on #9522 (zurfyx/y-keep-chars-at-format-boundary). Review only this PR's own commits.

The @lexical/y fixes touch the same writer, cursor, reader and binding internals, so they are one linear stack: each PR is based on the one below it, each conflict is resolved once, in the PR whose change causes it, and every CI run tests the real combination.

Merge order: bottom first, #9509 → #9523 → #9522 → #9505 → #9508 → #9502 → #9504 → #9527 → #9507 → #9510. With squash merges, rebase the next PR onto main before merging it (git rebase --onto main <old base branch>).

The stack
# PR Branch Base
1 #9509 zurfyx/update-error-rollback main
2 #9523 zurfyx/write-before-unread-change #9509
3 #9522 zurfyx/y-keep-chars-at-format-boundary #9523
4 #9505 (this PR) zurfyx/y-undo-member-closer #9522
5 #9508 zurfyx/y-initial-state-binding #9505
6 #9502 zurfyx/y-reorder-intent #9508
7 #9504 zurfyx/y-preserve-unknown-attrs #9502
8 #9527 zurfyx/y-move-keeps-unknown-fields #9504
9 #9507 zurfyx/y-composition-holdback #9527
10 #9510 zurfyx/y-incremental-read-marks #9507

Follow-ups for after the stack (not in it):

Description

In @lexical/y, a format, comment or link could spread to the end of the
document when a collaborator edited inside it while it was undone, or while
another peer deleted text at its end. All of these converge on main, on
every client and in a fresh read:

  • A makes "t56z t57z" italic and undoes it while B types plain text after
    "t56z": everything after B's text, the next paragraph included, turns
    italic.
  • B comments "t32z t33z", where a comment of another member of the same
    set ends, and undoes it while A types after "t33z": the removed comment
    covers the rest of the document.
  • B bolds "t6z t7z t8z" and undoes it while A removes bold from "t7z":
    " t8z t9z" and the next paragraph turn bold. A removal from the whole
    range, then its undo, does the same.
  • A undoes bold or a comment while B pastes a list or paragraphs inside it;
    B undoes a link while A makes text across the link's start italic.
  • B pastes inside a comment while C, offline for a long time, deletes text
    at the comment's end: once C is back, the comment covers words far after
    it.

The cause is shared. The client that edits inside the range restates the
value there: the write cursor restores the old value after the text it
inserts or at the end of the range it formats, and an undo brings back the
format items its change deleted. That restated run ended at the closer of
the change that opened the run. When that change is undone, its opener and
its closer are deleted; a concurrent delete can also drop the closer (it
keeps a bounded number of the format items it leaves). Either way the
restatement runs on to the end of the document.

This change adds one rule, for every stored inline kind (text formats,
styles, NodeState and its set members, links): a run that a client
restates ends with an item of that client's own.

  • Cursor, format rule 5 (also used after inserted text): where a restore
    restates a value whose run another client's change opened (following
    restores back to the run's opener), and the item that ends the restored
    run is that change's own end of the run, the writer puts a null right
    after that end. If the change is undone, or a delete drops that end, the
    null ends the restored run there. It goes after the end, not before it,
    so text a collaborator types at the end of the run at the same time stays
    inside the run. A null by which a change made text inside the run plain
    is not such an end, so undoing that change still brings the value back.
  • YBinding#closeRestoredRuns, the undo path: a format item an undo brings
    back gets a null of the undoer's own right after the end its original
    change gave it, where that end is gone. This generalizes the guard added
    for Bug: [lexical-y] Concurrent undo racing a collaborator's change of the same range can spread a format or comment to the end of the document #9493. The editor reads those nulls as part of the undo, with the
    selection the undo puts back, so the undoer's editor matches a fresh read.

The stored layout does not change, and nothing more is written where no
other client's change is involved. The restored value can still stay on
the part of the range after the collaborator's edit, and an undone link
stays on its own text when a collaborator's format change rewrote the
link's textFormat (both documented in y.md); neither reaches past the
range any more.

Restack (October 29)

Rebased onto #9522 with no conflicts (it was based on a main one commit older). Left for the "seen of Yjs" follow-up in the stack notes above: the run-opener scans this PR adds (liveItemBefore, runOpener, restatedEnd) read raw deletedness, so inside #9523's unread window they see the unread change's items; not reproduced as a wrong result.

Fixed after a randomized soak test of the whole stack:

  • L1B-1: a comment could spread to the end of the document when a user undoes text typed right after a word two comments cover while a collaborator pastes over that text. The paste's delete tidied the run ends left after the deleted text and kept only the typist's null, which the undo then deleted. The delete now also keeps the last end of the same value another client wrote before it, so each client's undo leaves the other's end in place (L1B-1: in regressions/Formats.test.ts, 4 client-id orders, comments from one client and from two).

Changeset

.changeset/lexical-y-undo-run-end.md: [fix] for @lexical/y, with a
Verify: paragraph.

Test plan

New regressions in
packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts: each
case in both client orders, with comment variants (another member of the
set, three comments, comment and bold), the selection an undo puts back
(direct and inside an editor update), and a matrix of bold or a comment
removed (by undo or by the opposite change) while a collaborator types,
presses Enter, pastes paragraphs or a list, or deletes inside the range.

Before

On main (0cd7448):

$ npx vitest --project unit --no-watch packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts
 Test Files  1 failed (1)
      Tests  38 failed | 146 passed | 4 expected fail (188)

AssertionError: expected '"t56z t85z" " t57z t59z t60z"[I] / "t…' to be '"t56z t85z" " t57z"[I] " t59z t60z" /…' // Object.is equality
Expected: ""t56z t85z" " t57z"[I] " t59z t60z" / "t78z t79z""
Received: ""t56z t85z" " t57z t59z t60z"[I] / "t78z t79z"[I]"

AssertionError: expected '"t5z t6z t7z" " t8z t9z"[B] / "tail l…' to be '"t5z t6z t7z" " t8z"[B] " t9z" / "tai…' // Object.is equality
Expected: ""t5z t6z t7z" " t8z"[B] " t9z" / "tail line""
Received: ""t5z t6z t7z" " t8z t9z"[B] / "tail line"[B]"

AssertionError: expected 't7z t8z t9z / tail line' to be 't7z t8z t9z / ' // Object.is equality

AssertionError: expected [ ' t57z t59z t60z', 't78z t79z' ] to deeply equal []

After

$ npx vitest --project unit --no-watch packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts
 Test Files  1 passed (1)
      Tests  184 passed | 4 expected fail (188)

$ npx vitest --project unit --no-watch --maxWorkers=6 packages/lexical-y
 Test Files  148 passed | 2 skipped (150)
      Tests  4983 passed | 16 expected fail | 2 skipped (5001)

$ pnpm run ci-check
Changeset check passed: 5 pending changeset(s) valid.
Found 0 errors

Randomized collaborative sessions with formats, comments and undo (a local
soak harness, not committed), compared with main: concurrent undo sessions
112 -> 107 failing of 4000 (none new), sequential undo sessions 200 -> 199
of 4000 (none new), format sessions and the format growth probes
unchanged. An undo-vs-comment fuzz spread in 9 of 300 seeds on main and in
0 of 1000 with this change. A replay of the 4-hour session where a peer
returned after 81 minutes offline no longer spreads the comment (main: 4
untouched words get it). Long sessions store about 2.5% more format items.
Browser e2e was not run.

@vercel

vercel Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
lexical Ready Ready Preview Oct 29, 2026 6:14pm UTC
lexical-playground Ready Ready Preview Oct 29, 2026 6:14pm UTC

Request Review

@zurfyx
zurfyx requested a review from etrepum as a code owner October 29, 2026 00:14
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 29, 2026
@pkg-pr-new

pkg-pr-new Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
lexical

npm i https://pkg.pr.new/lexical@9505

@lexical/a11y

npm i https://pkg.pr.new/@lexical/a11y@9505

@lexical/clipboard

npm i https://pkg.pr.new/@lexical/clipboard@9505

@lexical/code

npm i https://pkg.pr.new/@lexical/code@9505

@lexical/code-core

npm i https://pkg.pr.new/@lexical/code-core@9505

@lexical/code-prism

npm i https://pkg.pr.new/@lexical/code-prism@9505

@lexical/code-shiki

npm i https://pkg.pr.new/@lexical/code-shiki@9505

@lexical/compiler

npm i https://pkg.pr.new/@lexical/compiler@9505

@lexical/devtools-core

npm i https://pkg.pr.new/@lexical/devtools-core@9505

@lexical/dragon

npm i https://pkg.pr.new/@lexical/dragon@9505

@lexical/eslint-plugin

npm i https://pkg.pr.new/@lexical/eslint-plugin@9505

@lexical/extension

npm i https://pkg.pr.new/@lexical/extension@9505

@lexical/fast-check

npm i https://pkg.pr.new/@lexical/fast-check@9505

@lexical/file

npm i https://pkg.pr.new/@lexical/file@9505

@lexical/hashtag

npm i https://pkg.pr.new/@lexical/hashtag@9505

@lexical/headless

npm i https://pkg.pr.new/@lexical/headless@9505

@lexical/history

npm i https://pkg.pr.new/@lexical/history@9505

@lexical/html

npm i https://pkg.pr.new/@lexical/html@9505

@lexical/internal

npm i https://pkg.pr.new/@lexical/internal@9505

@lexical/link

npm i https://pkg.pr.new/@lexical/link@9505

@lexical/list

npm i https://pkg.pr.new/@lexical/list@9505

@lexical/mark

npm i https://pkg.pr.new/@lexical/mark@9505

@lexical/markdown

npm i https://pkg.pr.new/@lexical/markdown@9505

@lexical/mdast

npm i https://pkg.pr.new/@lexical/mdast@9505

@lexical/offset

npm i https://pkg.pr.new/@lexical/offset@9505

@lexical/overflow

npm i https://pkg.pr.new/@lexical/overflow@9505

@lexical/plain-text

npm i https://pkg.pr.new/@lexical/plain-text@9505

@lexical/react

npm i https://pkg.pr.new/@lexical/react@9505

@lexical/rich-text

npm i https://pkg.pr.new/@lexical/rich-text@9505

@lexical/selection

npm i https://pkg.pr.new/@lexical/selection@9505

@lexical/table

npm i https://pkg.pr.new/@lexical/table@9505

@lexical/tailwind

npm i https://pkg.pr.new/@lexical/tailwind@9505

@lexical/text

npm i https://pkg.pr.new/@lexical/text@9505

@lexical/utils

npm i https://pkg.pr.new/@lexical/utils@9505

@lexical/y

npm i https://pkg.pr.new/@lexical/y@9505

@lexical/yjs

npm i https://pkg.pr.new/@lexical/yjs@9505

commit: 603812b

@zurfyx
zurfyx force-pushed the zurfyx/y-undo-member-closer branch from 008e924 to 091a734 Compare October 29, 2026 01:03
@zurfyx zurfyx changed the title [lexical-website][lexical-y] Bug Fix: Stop an undone format, comment or link from spreading to the end of the document [lexical-website][lexical-y] Bug Fix: Stop a format, comment or link from spreading to the end of the document after an undo or delete races an edit inside it Oct 29, 2026
@zurfyx
zurfyx force-pushed the zurfyx/y-undo-member-closer branch from 49ea400 to 45c9c15 Compare October 29, 2026 05:32
@zurfyx
zurfyx changed the base branch from main to zurfyx/y-keep-chars-at-format-boundary October 29, 2026 05:33
@zurfyx
zurfyx force-pushed the zurfyx/y-keep-chars-at-format-boundary branch 2 times, most recently from eabc52e to f45dfa2 Compare October 29, 2026 17:54
…from spreading to the end of the document after an undo or delete races an edit inside it

## Description

In `@lexical/y`, a format, comment or link could spread to the end of the
document when a collaborator edited inside it while it was undone, or while
another peer deleted text at its end. All of these converge on main, on
every client and in a fresh read:

- A makes "t56z t57z" italic and undoes it while B types plain text after
  "t56z": everything after B's text, the next paragraph included, turns
  italic.
- B comments "t32z t33z", where a comment of another member of the same
  set ends, and undoes it while A types after "t33z": the removed comment
  covers the rest of the document.
- B bolds "t6z t7z t8z" and undoes it while A removes bold from "t7z":
  " t8z t9z" and the next paragraph turn bold. A removal from the whole
  range, then its undo, does the same.
- A undoes bold or a comment while B pastes a list or paragraphs inside it;
  B undoes a link while A makes text across the link's start italic.
- B pastes inside a comment while C, offline for a long time, deletes text
  at the comment's end: once C is back, the comment covers words far after
  it.

The cause is shared. The client that edits inside the range restates the
value there: the write cursor restores the old value after the text it
inserts or at the end of the range it formats, and an undo brings back the
format items its change deleted. That restated run ended at the closer of
the change that opened the run. When that change is undone, its opener and
its closer are deleted; a concurrent delete can also drop the closer (it
keeps a bounded number of the format items it leaves). Either way the
restatement runs on to the end of the document.

This change adds one rule, for every stored inline kind (text formats,
styles, NodeState and its set members, links): a run that a client
restates ends with an item of that client's own.

- `Cursor`, format rule 5 (also used after inserted text): where a restore
  restates a value whose run another client's change opened (following
  restores back to the run's opener), and the item that ends the restored
  run is that change's own end of the run, the writer puts a null right
  after that end. If the change is undone, or a delete drops that end, the
  null ends the restored run there. It goes after the end, not before it,
  so text a collaborator types at the end of the run at the same time stays
  inside the run. A null by which a change made text inside the run plain
  is not such an end, so undoing that change still brings the value back.
- `YBinding#closeRestoredRuns`, the undo path: a format item an undo brings
  back gets a null of the undoer's own right after the end its original
  change gave it, where that end is gone. This generalizes the guard added
  for #9493. The editor reads those nulls as part of the undo, with the
  selection the undo puts back, so the undoer's editor matches a fresh read.

The stored layout does not change, and nothing more is written where no
other client's change is involved. The restored value can still stay on
the part of the range after the collaborator's edit, and an undone link
stays on its own text when a collaborator's format change rewrote the
link's textFormat (both documented in y.md); neither reaches past the
range any more.

## Changeset

`.changeset/lexical-y-undo-run-end.md`: `[fix]` for `@lexical/y`, with a
`Verify:` paragraph.

## Test plan

New regressions in
`packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts`: each
case in both client orders, with comment variants (another member of the
set, three comments, comment and bold), the selection an undo puts back
(direct and inside an editor update), and a matrix of bold or a comment
removed (by undo or by the opposite change) while a collaborator types,
presses Enter, pastes paragraphs or a list, or deletes inside the range.

### Before

On main (0cd7448):

```
$ npx vitest --project unit --no-watch packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts
 Test Files  1 failed (1)
      Tests  38 failed | 146 passed | 4 expected fail (188)

AssertionError: expected '"t56z t85z" " t57z t59z t60z"[I] / "t…' to be '"t56z t85z" " t57z"[I] " t59z t60z" /…' // Object.is equality
Expected: ""t56z t85z" " t57z"[I] " t59z t60z" / "t78z t79z""
Received: ""t56z t85z" " t57z t59z t60z"[I] / "t78z t79z"[I]"

AssertionError: expected '"t5z t6z t7z" " t8z t9z"[B] / "tail l…' to be '"t5z t6z t7z" " t8z"[B] " t9z" / "tai…' // Object.is equality
Expected: ""t5z t6z t7z" " t8z"[B] " t9z" / "tail line""
Received: ""t5z t6z t7z" " t8z t9z"[B] / "tail line"[B]"

AssertionError: expected 't7z t8z t9z / tail line' to be 't7z t8z t9z / ' // Object.is equality

AssertionError: expected [ ' t57z t59z t60z', 't78z t79z' ] to deeply equal []
```

### After

```
$ npx vitest --project unit --no-watch packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts
 Test Files  1 passed (1)
      Tests  184 passed | 4 expected fail (188)

$ npx vitest --project unit --no-watch --maxWorkers=6 packages/lexical-y
 Test Files  148 passed | 2 skipped (150)
      Tests  4983 passed | 16 expected fail | 2 skipped (5001)

$ pnpm run ci-check
Changeset check passed: 5 pending changeset(s) valid.
Found 0 errors
```

Randomized collaborative sessions with formats, comments and undo (a local
soak harness, not committed), compared with main: concurrent undo sessions
112 -> 107 failing of 4000 (none new), sequential undo sessions 200 -> 199
of 4000 (none new), format sessions and the format growth probes
unchanged. An undo-vs-comment fuzz spread in 9 of 300 seeds on main and in
0 of 1000 with this change. A replay of the 4-hour session where a peer
returned after 81 minutes offline no longer spreads the comment (main: 4
untouched words get it). Long sessions store about 2.5% more format items.
Browser e2e was not run.
…it reuses another client's change end

## Description

A follow-up to the rule above, for runs a write opens itself. When a write
closes the run it opens (its range's value, or inserted text's) by reusing
an item already there, and that item is another client's change end, the
undo of that change takes the run's end away. With links only, on the
previous commit:

- B links "t2z t3z t4z" while C links "t3z" with the same URL. Then B undoes
  its link while C links "t2z t3z t4z" again. C's link over " t4z" closed
  on B's closer, and once B's undo removed it, the link covered t3z to t9z
  and the whole next paragraph, on every client and in a fresh read.

The write now puts a null of its own right after such a reused end
(`Cursor#insertNegatedFormats`, rule 5): the run ends where the write ended
it, whatever happens to the other change.

## Test plan

New regression in
`packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts`, three
clients in both orders.

### Before

On the previous commit (091a734):

```
$ npx vitest --project unit --no-watch packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts -t "C links"
     × S7-26: B links "t2z t3z t4z" ‖ C links "t3z"; then B undoes it ‖ C links "t2z t3z t4z" (ids 1,2,3)
     × S7-26: B links "t2z t3z t4z" ‖ C links "t3z"; then B undoes it ‖ C links "t2z t3z t4z" (ids 3,2,1)
Expected: "t3z t4z / "
Received: "t3z t4z t5z t6z t7z t8z t9z / tail line"
 Test Files  1 failed (1)
      Tests  2 failed | 188 skipped (190)
```

### After

```
$ npx vitest --project unit --no-watch --maxWorkers=6 packages/lexical-y
 Test Files  148 passed | 2 skipped (150)
      Tests  4985 passed | 16 expected fail | 2 skipped (5003)

$ pnpm run ci-check
Changeset check passed: 5 pending changeset(s) valid.
Found 0 errors
```

The local soak lanes are unchanged from the previous commit (no new
failures). The undo-vs-comment fuzz stays at 0 of 1000. Long sessions store
about 0.5% more format items than the previous commit. Browser e2e was not
run.
…ce plain text typed after a word two comments cover

## Description

In `@lexical/y`, a comment could spread to the end of the document. A comments "t1z", and a second comment covers it too (from A or another client); J types plain text right after "t1z"; then J undoes the typing while C pastes over J's text. On every client and in a fresh read, the first comment then covered the rest of the line and every paragraph after it. With one comment, or with a manual delete instead of the undo, it did not happen.

J's typing ends each comment with a null of J's own written right after the end the comment's author wrote, so that the comment ends even where the author's end goes. C's paste deletes J's text, and the delete collapses the format items it leaves after that text. Of the two nulls that end the first comment there, it kept only the last one, J's, as the one that gives the content after the run its value; J's concurrent undo deleted that null, and nothing ended the comment any more.

With this change, where the delete keeps a key's last item, it also keeps the last item before it of that key with the same value (no other value between them) that another client wrote. Each client's undo deletes its own items only, so a run's end and the null another client wrote right after it each keep ending the run where the other's writer removes theirs. It keeps at most one more item per key, and only where two clients ended the same value at the same place.

## Test plan

New test in `packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts`, for four client id orders, with the two comments from one client and from two: A comments "t1z", the second comment covers it, J types " t1011z" right after it, then J undoes the typing while C pastes "t1013z" over "t1011z". The comments end after the word on every client and in a fresh read (C's text, now right after "t1z" inside both comments' runs, takes both comments).

`./node_modules/.bin/vitest --run --project unit packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts -t "L1B-1" --reporter=verbose`

### Before

```
× regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from one client (ids 1,2,3,4) 223ms
× regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from two clients (ids 1,2,3,4) 78ms
(the same for ids 4,3,2,1, 2,4,1,3 and 3,1,4,2)
AssertionError: expected '"t1zt1013z"[c12+c4] " t2"[c4] / "t3z"…' to be '"t1zt1013z"[c12+c4] " t2" / "t3z"' // Object.is equality
Expected: ""t1zt1013z"[c12+c4] " t2" / "t3z""
Received: ""t1zt1013z"[c12+c4] " t2"[c4] / "t3z"[c4]"
Tests  8 failed | 190 skipped (198)
```

### After

```
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from one client (ids 1,2,3,4) 256ms
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from two clients (ids 1,2,3,4) 88ms
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from one client (ids 4,3,2,1) 93ms
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from two clients (ids 4,3,2,1) 87ms
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from one client (ids 2,4,1,3) 85ms
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from two clients (ids 2,4,1,3) 80ms
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from one client (ids 3,1,4,2) 80ms
✓ regressions/Formats.test.ts > L1B-1: undo of plain text typed after a word two comments cover ‖ a paste over that text > L1B-1: the comments end after the word, from two clients (ids 3,1,4,2) 89ms
Tests  8 passed | 190 skipped (198)
```

The other tests in `regressions/Formats.test.ts`, the S7-10, S7-20, S7-24, S7-26 and S7-33 cases included, pass unchanged.

```
$ pnpm exec vitest run --project unit --maxWorkers=8 <every unit test file of packages/lexical-y and packages/lexical/src>
Test Files  240 passed | 2 skipped (242)
Tests  7180 passed | 14 expected fail | 2 skipped (7196)
```

`tsc`, `tsc-test`, `tsc-scripts`, `tsc-extension`, `tsc-website`, `flow`, `eslint`, `prettier` and the changeset check pass on the repository's files.
@zurfyx
zurfyx force-pushed the zurfyx/y-undo-member-closer branch from e3bc5a3 to 603812b Compare October 29, 2026 18:12
@zurfyx
zurfyx changed the base branch from zurfyx/y-keep-chars-at-format-boundary to main October 29, 2026 18:12
@zurfyx
zurfyx added this pull request to the merge queue Oct 29, 2026
Merged via the queue into main with commit ad07eb7 Oct 29, 2026
57 of 65 checks passed

This branch was successfully deployed

2 active deployments
Preview – lexical — 603812b7 Deployed Oct 29, 2026 by vercel[bot]
Preview – lexical-playground — 603812b7 Deployed Oct 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants