Skip to content

fix(draw): adjust table cell edge resize#1151

Open
pubuzhixing8 wants to merge 2 commits into
developfrom
codex/table-resize-cell-edges
Open

fix(draw): adjust table cell edge resize#1151
pubuzhixing8 wants to merge 2 commits into
developfrom
codex/table-resize-cell-edges

Conversation

@pubuzhixing8

@pubuzhixing8 pubuzhixing8 commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR reworks the table resize interaction from the older #931 idea against the current develop branch.

The important behavior change is not just a code cleanup. It makes table resize intent explicit:

cell side edge -> resize the corresponding row/column
table corner -> resize the whole table
cell start edge -> resize the row/column from the start side
cell end edge -> resize the row/column from the end side
merged-cell start edge -> resize the first covered row/column
merged-cell end edge -> resize the last covered row/column

Interaction Intent Changes

1. Outer table edges now mean row/column resize, not whole-table resize

Before this change, when a user selected a table and moved the pointer to the right edge of the table, that position could match both:

  • the table right resize handle
  • the last cell right resize handle

The old hit-test path checked the table handle first, so the interaction was often interpreted as whole-table resize.

That meant the user appeared to be dragging the last column edge, but the system treated it as resizing the whole table.

After this change, cell resize handles are checked first. If the pointer hits the right edge of the last cell, the interaction is handled as a column resize.

Before: drag table right edge -> resize the whole table
After:  drag table right edge -> resize the last column

2. Whole-table resize is now reserved for table corners

Before this change, both table side handles and table corner handles could trigger whole-table resize.

That made these two user intents compete with each other:

  • resizing a row/column
  • resizing the whole table

After this change, table-level resize only falls back to corner handles. Side edges are reserved for row/column resize.

Side edge -> row/column resize
Corner    -> whole-table resize

This makes the interaction model mutually exclusive and easier to predict.

3. Start-side row/column resize is now explicit

The previous implementation could already move points[0] through the table-level resize path. For example, when the interaction was handled as a whole-table resize, resizeSnapRef.activePoints plus normalizeShapePoints could produce a new start point.

The gap was in the cell row/column resize path. The old row/column update helpers behaved like end-side updates:

column width changes -> update points[1][0]
row height changes   -> update points[1][1]

That is correct for right/bottom cell edges, but it does not clearly model the user intent when dragging a left/top cell edge.

When a user drags the left edge of the first column, the expected intent is not whole-table resize. The intent is:

move the table left boundary and resize the first column

So the row/column resize path itself needs to know whether the dragged edge is the start side or the end side.

This PR introduces a small ResizeEdge concept:

  • w / n -> start
  • e / s -> end

So the row/column update now matches the dragged cell edge:

left cell edge   -> update points[0][0] while resizing the target column
right cell edge  -> update points[1][0] while resizing the target column
top cell edge    -> update points[0][1] while resizing the target row
bottom cell edge -> update points[1][1] while resizing the target row

The improvement is therefore not first-time support for changing points[0]; it is making start-side row/column resize explicit instead of relying on the table-level resize path.

4. Merged cells resolve the resize target by dragged edge

Merged cells can cover multiple rows or columns.

For example, a cell with colspan=3 covers columns 1, 2, and 3.

The expected interaction is:

drag the left edge  -> resize column 1
drag the right edge -> resize column 3

The old logic mainly followed the cell starting rowId / columnId, which made end-side resize ambiguous for rowspan / colspan cells.

This PR resolves the target row/column from the dragged edge:

start edge -> first row/column covered by the cell
end edge   -> last row/column covered by the cell span

So merged-cell resize now maps to the user visible drag target instead of always leaning on the cell starting row/column.

Implementation Notes

  • hitTest checks cell side handles before table-level handles.
  • table-level fallback only accepts corner handles.
  • ResizeEdge represents whether the dragged cell edge is the start or end side.
  • getResizeTargetRowOrColumnIndex resolves the row/column affected by normal and merged cells.
  • getCurrentRowOrColumnSize derives the current rendered row/column size from the table layout, avoiding fragile inference from cell rectangles.

Verification

  • npm run build:draw

Focused manual checks to run:

  • Resize the right/bottom edge of a normal table cell and verify only the target column/row is updated.
  • Resize the left/top cell edge and verify the target row/column resizes from the start side.
  • Resize a table corner and verify whole-table resize still works.
  • Resize the start/end edge of a merged cell and verify the first/last covered row or column is updated.

Unit tests can be added in a follow-up once the interaction behavior is confirmed.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 12, 2026

Copy link
Copy Markdown

Deploying plait with  Cloudflare Pages  Cloudflare Pages

Latest commit: d682b87
Status: ✅  Deploy successful!
Preview URL: https://4829bea4.plait.pages.dev
Branch Preview URL: https://codex-table-resize-cell-edge.plait.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 12, 2026

Copy link
Copy Markdown

Deploying plait-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: d682b87
Status: ✅  Deploy successful!
Preview URL: https://2cb4e412.plait-docs.pages.dev
Branch Preview URL: https://codex-table-resize-cell-edge.plait-docs.pages.dev

View logs

@pubuzhixing8 pubuzhixing8 force-pushed the codex/table-resize-cell-edges branch from 281b6a4 to 6871efa Compare July 12, 2026 16:18
@pubuzhixing8

Copy link
Copy Markdown
Collaborator Author

@nightt5879 I think this PR is ready for review, help me, please!

@nightt5879 nightt5879 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few edge cases I ran into while testing this.

handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, 0);
const rectangle = RectangleClient.getRectangleByPoints(cells[i].points);
const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, 0);
if (handleRef && !isCornerHandle(board, handleRef.handle)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At grid intersections this helper returns the cell corner first, then we discard it without checking the side handle. That makes the drag fall through instead of resizing the row or column. I can reproduce it on the swimlane edge: dragging there moves the whole swimlane. Could we handle side hits explicitly here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye, thanks! I updated the hit testing to resolve table dividers directly after preserving table corner handles. Grid intersections now choose the nearest divider axis, so side drags no longer fall through to whole swimlane/table movement.

Transforms.setNode(board, { rows, points }, path);

const originRect = RectangleClient.getRectangleByPoints(originPoints);
const targetRect = RectangleClient.getRectangleByPoints(targetPoints);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getRectangleByPoints normalizes reversed points. If the dragged edge crosses the fixed edge, the size becomes positive again, so the edge jumps to the other side and starts growing in reverse. Could we keep a signed delta here, or clamp at MIN_CELL_SIZE?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye, thanks! I replaced the normalized-rectangle delta with a signed pointer delta and clamp the target size at MIN_CELL_SIZE before applying the offset, so crossing the fixed edge no longer flips and grows in reverse.

rectangle = RectangleClient.getRectangleByPoints(cells[i].points);
handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, 0);
const rectangle = RectangleClient.getRectangleByPoints(cells[i].points);
const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, 0);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A shared divider hits both adjacent cells, so this picks whichever cell comes first in cells. addSwimlaneRow/Column(index) can leave cells in a different order from the rows and columns, which means the same divider may resize the opposite side. Should the target be resolved from the row or column indexes instead?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye, thanks! I removed the cell-order-based target selection. Divider hits are now resolved from the row/column divider index: the outer start divider maps to the first row/column start, and internal/end dividers map to the previous row/column end. This keeps the same divider stable regardless of cell order after row/column insertion.

@pubuzhixing8

Copy link
Copy Markdown
Collaborator Author

I am still working on it, because I need to check the new resolution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants