Skip to content

fix(common): flush pending resize frame on pointer up - #1161

Closed
pubuzhixing8 wants to merge 1 commit into
developfrom
xingxing/flush-pending-resize-raf
Closed

fix(common): flush pending resize frame on pointer up#1161
pubuzhixing8 wants to merge 1 commit into
developfrom
xingxing/flush-pending-resize-raf

Conversation

@pubuzhixing8

Copy link
Copy Markdown
Collaborator

Summary

  • add a flush API for pending throttleRAF callbacks
  • flush the pending common resize frame before pointer-up cleanup
  • cover synchronous flushing, single execution, and latest-callback behavior

Root Cause

withResize schedules resize work through requestAnimationFrame. If globalPointerUp runs before the pending frame, it clears startPoint and resizeRef; the queued callback then observes empty resize state and drops the user's final pointer move.

Impact

The last resize position is now applied before the resize lifecycle is finalized. This keeps the behavior generic for every consumer of withResize and avoids table-specific state management. This was identified while reviewing #1160.

Verification

  • ./node_modules/.bin/tsc -p packages/core/tsconfig.spec.json --noEmit
  • npm run build:core
  • npm run build:common
  • npm run test:core -- --watch=false --browsers=ChromeHeadlessCI --progress=false --include=packages/core/src/utils/common.spec.ts (blocked during the Angular/esbuild build phase by an esbuild deadlock, exit 134; specs did not start)

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying plait with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2edddef
Status: ✅  Deploy successful!
Preview URL: https://37bcb5a1.plait.pages.dev
Branch Preview URL: https://xingxing-flush-pending-resiz.plait.pages.dev

View logs

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying plait-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2edddef
Status: ✅  Deploy successful!
Preview URL: https://9098909a.plait-docs.pages.dev
Branch Preview URL: https://xingxing-flush-pending-resiz.plait-docs.pages.dev

View logs

@pubuzhixing8
pubuzhixing8 marked this pull request as ready for review July 27, 2026 10:52
@pubuzhixing8
pubuzhixing8 requested a review from nightt5879 July 27, 2026 11:27
@pubuzhixing8

pubuzhixing8 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator Author

Please help me review @nightt5879,I have a question about this PR , we can discuss it on #1162

@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.

The direction looks good overall. I left two inline concerns: one lifecycle issue around flushing a stale resize callback, and one public callback compatibility issue. Once those are handled and the lifecycle case is covered by an integration test, this should be good to go.


board.globalPointerUp = (event: PointerEvent) => {
if (isResizing(board)) {
flushThrottleRAF(board, RESIZE_RAF_KEY);

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.

[P1] Could we avoid flushing after the resize target has been invalidated?

The target can be removed or replaced while the last move is still pending. Flushing here would then run onResize with a stale path, which can update the element that shifted into that path or throw before the resize cleanup runs. I think we need a cancel/invalidation check here, plus a regression test for delete/replace before pointer-up.

value[key] = null;
BOARD_TO_RAF.set(board, value);
PlaitBoard.isAlive(board) && fn();
PlaitBoard.isAlive(board) && task.callback();

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.

[P2] Could we preserve the callback’s original call semantics here?

This used to invoke the callback directly with fn(). Calling it as task.callback() now binds this to the internal task object, which is observable for non-arrow callbacks accepted by this public API. Could we detach the callback before invoking it? The same applies to the flush path below.

@pubuzhixing8

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough review. After reconsidering the scope, I do not think this PR is appropriate to merge at this time.

The original case requires pointerUp to occur before the pending requestAnimationFrame callback. Your lifecycle concern shows that making this generic behavior safe would also require additional invalidation/path-lifecycle handling and regression coverage. That adds meaningful complexity to withResize and the public RAF utility.

At the moment, we do not have a confirmed, user-facing Plait defect showing that this timing issue occurs in practice. It is also difficult for a user to trigger pointerUp within the same RAF window after the final pointerMove. I would prefer not to introduce broad infrastructure for an edge case that is still theoretical.

Therefore, I do not recommend merging this PR. Going forward, I also suggest that we avoid adding similar RAF-flush handling unless there is a concrete, reproducible defect with user impact. This keeps the work focused on verified problems. Thank you again for surfacing the lifecycle and API-compatibility risks.

@nightt5879

Copy link
Copy Markdown
Collaborator

got it, thanks for the clarification. i agree that Iimay have overthought this edge case. we can close this PR for now.

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