Skip to content

fix(toolbar): compute button state on first render - #1352

Draft
makhnatkin wants to merge 3 commits into
test/clipboard-stabilityfrom
test/extensions-stability
Draft

makhnatkin wants to merge 3 commits into
test/clipboard-stabilityfrom
test/extensions-stability

Conversation

@makhnatkin

@makhnatkin makhnatkin commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator
  • Toolbar buttons get their real state on the first render. Before this, they appeared enabled until an effect ran after paint.
  • A remounted toolbar no longer shows the Undo and Redo buttons as enabled in a screenshot.
  • The punctuation boundaries test waits for the split preview content before taking the screenshot.
  • The fixed pause before the screenshot is removed.

🤖 Generated with Claude Code

Summary by Sourcery

Render toolbar action states synchronously and make visual-test synchronization content-based.

Bug Fixes:

  • Compute toolbar action states during render so buttons display the correct enabled and active states immediately, including after remounts or editor changes.

Enhancements:

  • Track committed toolbar state snapshots for update events while avoiding stale or abandoned render state.

Tests:

  • Add unit coverage for initial, changed-editor, and event-driven toolbar action state updates.
  • Make the punctuation-boundaries visual test wait for preview content instead of using a fixed delay.

@gravity-ui

gravity-ui Bot commented Oct 9, 2026

Copy link
Copy Markdown

Storybook Deployed

@gravity-ui

gravity-ui Bot commented Oct 9, 2026

Copy link
Copy Markdown

🎭 Playwright Report

@makhnatkin

Copy link
Copy Markdown
Collaborator Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/editor/src/toolbar/hooks.ts" line_range="31" />
<code_context>
-        active: false,
-        enabled: true,
-    });
+    const [state, setState] = useState(() => getActionState(editor, {isActive, isEnable}));
     const stateRef = useLatest(state);

</code_context>
<issue_to_address>
**Toolbar shows stale button state**

When a mounted toolbar receives a different editor or changed action predicates, including a same-length replacement list, `useState` retains the previous state, and a same-length list can pass the `state.length === actions.length` check. The passive effect applies the new state only after paint, so the toolbar briefly shows the prior enabled or active state.

Recompute or reset the action state synchronously when the editor or action inputs change, rather than waiting for the passive effect.

Also at `packages/editor/src/toolbar/hooks.ts:59-61`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread packages/editor/src/toolbar/hooks.ts Outdated
@makhnatkin

Copy link
Copy Markdown
Collaborator Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/editor/src/toolbar/hooks.ts" line_range="36" />
<code_context>
+
+    // Computed during render, so changed props never show the previous state.
+    const state = getActionsState(editor, actions);
+    const latestRef = useLatest({editor, actions, state});

     useEffect(() => {
</code_context>
<issue_to_address>
**Committed toolbar keeps stale state**

When a concurrent render with different editor or action props pauses, then the still-committed editor emits an update matching the work-in-progress state before that render is abandoned, `latestRef.current` exposes the speculative `editor`, `actions`, and `state` to the committed update listener, so `onUpdate` compares the committed editor's update against that snapshot, skips `rerender`, and leaves the toolbar showing stale button state.

Publish the listener snapshot only after the render commits, so abandoned work cannot replace the committed comparison state.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread packages/editor/src/toolbar/hooks.ts Outdated
@makhnatkin

Copy link
Copy Markdown
Collaborator Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Sergey Makhnatkin and others added 2 commits October 10, 2026 02:24
Toolbar buttons rendered as enabled until an effect after paint applied
the real state, so a remounted Undo button could be captured enabled.
The punctuation boundaries visual test now waits for the split preview
content instead of a fixed pause.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Button state is computed during render, so a changed editor or action
list never shows the previous state until an effect runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@makhnatkin
makhnatkin changed the base branch from test/yfm-table-menu to test/clipboard-stability October 9, 2026 23:24
@makhnatkin
makhnatkin force-pushed the test/extensions-stability branch from 2ba3db3 to 8ada4bd Compare October 9, 2026 23:24
@makhnatkin
makhnatkin added this pull request to stack #1347 October 9, 2026 23:25
An abandoned concurrent render could replace the snapshot that the update
listener compares against.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@makhnatkin
makhnatkin force-pushed the test/extensions-stability branch from 8ada4bd to 93800d0 Compare October 9, 2026 23:55

This branch has not been deployed

No deployments
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.

1 participant