Skip to content

Table corrupts when undoing row deletion after remote user deletes a column (collaborative editing) #312

Description

@wbb631094818

Environment

quill-table-up: 2.1.9
quill: 2.x
Collaborative backend: Yjs + y-quill binding

History module configuration

history: {
  delay: 200,
  userOnly: true
}

userOnly: true means remote changes are not recorded into the undo stack, but Quill's History module still calls transform() against each incoming remote delta to adjust the positions of existing undo stack entries.

Steps to Reproduce

User A and User B open the same document collaboratively
User A inserts a 3×3 table (rows: r1/r2/r3, cols: c1/c2/c3)
User A deletes row 2
User B deletes column 2
User A presses Ctrl+Z to undo the row deletion

Expected

Row 2 is restored with 2 cells, matching the current 2-column table structure.

Actual

The table layout corrupts. The restored row contains a cell whose colId attribute is c2, which no longer exists in the table's column list.

Analysis

When User A deletes row 2, the History module records an undo delta containing the 3 cells of row 2, each carrying their original colId attributes (c1, c2, c3).

When User B's delete-column operation arrives as a remote delta, History.transform() is called to adjust the existing undo stack entries. The remote delta carries no information about which colId was deleted — it only encodes byte-position offsets.

transformStack() adjusts the undo stack using Delta.transform(), which correctly shifts positional offsets but cannot update or remove the colId attribute inside the insert ops of the undo delta, because the remote delta carries no column identity information.

As a result, when User A's undo is applied, the restored row inserts a cell with colId = c2 into a table whose column list is now [c1, c3]. The table renderer encounters a colId with no corresponding column definition, causing the layout to corrupt.


I'm not sure if this is a known limitation or something that could be addressed in quill-table-up. Any insight into whether the delete-column operation could carry column identity information in its delta, or whether there's a recommended way to handle this in collaborative scenarios, would be greatly appreciated.

Thank you so much!🙏

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions