Skip to content

fix(Pagination): make changeAction interruptible with optimistic page state#3131

Merged
cixzhang merged 5 commits into
mainfrom
navi/fix/button-pagination-interruptible-actions
Jun 26, 2026
Merged

fix(Pagination): make changeAction interruptible with optimistic page state#3131
cixzhang merged 5 commits into
mainfrom
navi/fix/button-pagination-interruptible-actions

Conversation

@cixzhang

Copy link
Copy Markdown
Contributor

Summary

Follow-up to the ToggleButton pressedChangeAction work (#3056), applying the same review learnings to the other components with change-style actions:

  • useOptimistic for state: a click mid-flight should reflect the in-progress value, not the stale prop.
  • Interruptible transitions, no re-entry guard: re-clicking a state transition is new intent and should interrupt, not be dropped.
  • Support synchronous handlers that suspend (e.g. a router navigation), not just promises.

I audited every component with an action prop. Most (Switch, CheckboxInput, Selector, MultiSelector, date/time inputs, CheckboxList) already follow this pattern. Two stood out — handled differently here because they're semantically different.

Pagination — made interruptible (the real fix)

Pagination's changeAction had a re-entry guard (if (isDisabled || isPending) return) and didn't track the page optimistically. This is exactly the interruptible-navigation case: clicking next again while a page load is in flight was a no-op.

Now:

  • The page is tracked with useOptimistic, so the indicator, active page, range text, and prev/next enablement reflect the page being navigated to while the action is pending.
  • onChange + changeAction run inside an interruptible transition. Rapid prev/next clicks advance through pages (each click derives its target from the optimistic page) instead of being dropped.
  • A synchronous handler that suspends also drives the pending state.
  • No API change — page/onChange/changeAction signatures are unchanged.

Button — guard kept on purpose, now documented

Button's clickAction is not a state transition — it's a fire-once command (submit/save/pay). A re-click is a duplicate submit, not new intent, so the actionInFlightRef guard is correct and should stay.

This matters because neither isPending nor useOptimistic dedupes a same-tick double-click (neither commits synchronously), so removing the ref would let a fast double-click fire clickAction twice. I verified this empirically. So instead of changing behavior, this adds a comment explaining why the guard exists (so it isn't "fixed" later by analogy to the toggle pattern) plus a regression test asserting a fast double-click fires clickAction only once.

Test plan

  • Pagination: 5 new tests — onChange→changeAction ordering, optimistic page while pending, interruption on rapid next-clicks (1→2→3), synchronous action, and disabled no-op. Full suite (48 tests) passes.
  • Button: 1 new regression test — fast double-click fires clickAction once. Full suite (27 tests) passes.
  • @astryxdesign/core typecheck, ESLint, repo sync check, and changeset check all pass.

… state

Pagination's changeAction now runs in a transition and tracks the page
optimistically, matching ToggleButton. The controls reflect the page being
navigated to while the action is pending, and rapid prev/next clicks advance
through pages (interrupting the in-flight transition) instead of being dropped
by a re-entry guard. A synchronous handler that suspends also drives the
pending state.

Button's clickAction keeps its single-fire guard — a re-click there is a
duplicate submit, not new intent — and now documents why, with a regression
test asserting a fast double-click fires clickAction only once.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jun 25, 2026
@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview, Comment Jun 26, 2026 10:24pm

Request Review

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

🚀 Vercel Preview Deployment

Status ✅ Deployed
Preview Open Preview
Commit 5a0d86b
Inspect Vercel Dashboard
Workflow View Logs

No authentication required — anyone with the link can view the preview.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

No new or modified components detected.

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.6KB 0B

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

github-actions Bot added a commit that referenced this pull request Jun 25, 2026
…s synchronously

Moving onChange into the transition deferred the consumer's page-state
update (e.g. the Table pagination plugin's row slicing) to a low-priority
transition commit, racing assertions under parallel CI workers. Call
onChange urgently before starting the transition; the optimistic indicator
and changeAction still run inside it, preserving interruptibility.
github-actions Bot added a commit that referenced this pull request Jun 26, 2026
github-actions Bot added a commit that referenced this pull request Jun 26, 2026
Condense the rationale comments added with the interruptible-action work to
match the sibling ToggleButton style — explain why, not every mechanism.
No logic changes.
github-actions Bot added a commit that referenced this pull request Jun 26, 2026
Comment thread packages/core/src/Button/Button.tsx Outdated
Condense the interruptible-action rationale comments to the why, dropping
mechanism narration. No logic changes.
github-actions Bot added a commit that referenced this pull request Jun 26, 2026
@cixzhang cixzhang merged commit 129bf0e into main Jun 26, 2026
15 checks passed
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 Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants