Skip to content

fix: save file caption/name on every keystroke instead of on close#2575

Open
YousefED wants to merge 1 commit intomainfrom
fix/instant-save-caption-filename
Open

fix: save file caption/name on every keystroke instead of on close#2575
YousefED wants to merge 1 commit intomainfrom
fix/instant-save-caption-filename

Conversation

@YousefED
Copy link
Collaborator

@YousefED YousefED commented Mar 18, 2026

Summary

File caption and rename inputs now save instantly on every keystroke, so changes are never lost regardless of how the popover closes.

Rationale

Previously, caption/name values were stored in local state and only saved to the block on Enter. This meant clicking outside the popover (which unmounts the formatting toolbar) would discard the input. Enter also didn't close the popover.

Changes

  • FileCaptionButton and FileRenameButton: removed local editing state and useEffect sync; handleChange now calls editor.updateBlock directly
  • Input reads value from block.props.caption/block.props.name instead of local state
  • Popover is now controlled (open/onOpenChange) so Enter can close it
  • Enter closes the popover; Escape closes via the popover's built-in behavior

Impact

No API changes. All three UI packages (mantine, ariakit, shadcn) work without modification.

Testing

Manual testing: verified Enter closes popover, Escape closes popover, clicking outside preserves content.

Checklist

  • Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass.
  • The documentation has been updated to reflect the new feature

Additional Notes

Closes #2568
Closes #2567

Summary by CodeRabbit

  • Refactor
    • Streamlined internal state management for file caption and rename editing functionality, improving code efficiency and maintainability while preserving existing behavior.

Previously, caption/name values were stored in local state and only
saved to the block on Enter. Clicking outside the popover discarded
input, and Enter didn't close the popover.

Now handleChange calls editor.updateBlock directly, input reads from
block props, and the popover is controlled so Enter closes it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

📝 Walkthrough

Walkthrough

Refactored FileCaptionButton and FileRenameButton from local state management with useEffect to controlled popover state, binding input values directly to block properties and adding Enter-key handlers to close the popover without triggering composition.

Changes

Cohort / File(s) Summary
Controlled Popover Refactor
packages/react/src/components/FormattingToolbar/DefaultButtons/FileCaptionButton.tsx, packages/react/src/components/FormattingToolbar/DefaultButtons/FileRenameButton.tsx
Removed local state variables (currentEditingCaption/currentEditingName) and useEffect initialization; replaced with controlled popover state; input values now bound directly to block.props.caption/name; added handleKeyDown to close popover on Enter when not composing; trigger button now toggles popoverOpen state.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~13 minutes

Poem

🐰 With popover now in control we stay,
The Enter key works just right,
No caption lost when we click away,
The legend shines both bold and bright! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: saving file caption/name on every keystroke instead of waiting for popover close.
Description check ✅ Passed The description covers all major sections from the template: summary, rationale, changes, impact, testing, and checklist. All critical information is present and well-documented.
Linked Issues check ✅ Passed The PR directly addresses both linked issues: #2568 (Enter closes popover) and #2567 (clicking outside preserves content via instant keystroke saves).
Out of Scope Changes check ✅ Passed All changes are tightly scoped to the two target files and directly address the linked issues; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/instant-save-caption-filename
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.

Add a .trivyignore file to your project to customize which findings Trivy reports.

@vercel
Copy link

vercel bot commented Mar 18, 2026

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

Project Deployment Actions Updated (UTC)
blocknote Ready Ready Preview Mar 18, 2026 6:40pm
blocknote-website Ready Ready Preview Mar 18, 2026 6:40pm

Request Review

@YousefED
Copy link
Collaborator Author

@virgile-dev does this behavior better match your expectations?

Would you expect similar for the edit link toolbar?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/react/src/components/FormattingToolbar/DefaultButtons/FileCaptionButton.tsx`:
- Line 61: popoverOpen state is not reset when the selected file block changes,
causing the popover to persist/reopen incorrectly; add a useEffect that watches
the block identity (e.g., block or block.id) and calls setPopoverOpen(false)
whenever the block changes or becomes undefined to ensure the popover closes on
block switches; update FileCaptionButton to use this effect alongside the
existing popover state and handlers so changes at lines around the block usage
(references to popoverOpen, setPopoverOpen, and block) reliably reset the UI.

In
`@packages/react/src/components/FormattingToolbar/DefaultButtons/FileRenameButton.tsx`:
- Line 61: In FileRenameButton, ensure the popoverOpen state is reset whenever
the selected block identity changes: add a useEffect that watches the selected
block (e.g., selectedBlock or selectedBlockId prop) and calls
setPopoverOpen(false) when that value changes so the rename popover cannot
persist across different block selections; update any paths where render returns
null to rely on this reset.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f2d3325-79d5-41c1-8dc0-70f9e54156e6

📥 Commits

Reviewing files that changed from the base of the PR and between 0e94795 and 60d7870.

📒 Files selected for processing (2)
  • packages/react/src/components/FormattingToolbar/DefaultButtons/FileCaptionButton.tsx
  • packages/react/src/components/FormattingToolbar/DefaultButtons/FileRenameButton.tsx

}
setCurrentEditingCaption(block.props.caption);
}, [block]);
const [popoverOpen, setPopoverOpen] = useState(false);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reset popover state when the selected block changes.

popoverOpen (Line 61) survives renders where block is undefined (Line 88), so this popover can reopen unexpectedly when a file block is selected again. Please reset popoverOpen when block identity changes.

Suggested fix
 import {
   ChangeEvent,
   KeyboardEvent,
   useCallback,
+  useEffect,
   useState,
 } from "react";
@@
   const [popoverOpen, setPopoverOpen] = useState(false);
+
+  useEffect(() => {
+    setPopoverOpen(false);
+  }, [block?.id]);

Also applies to: 88-90, 93-96

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/react/src/components/FormattingToolbar/DefaultButtons/FileCaptionButton.tsx`
at line 61, popoverOpen state is not reset when the selected file block changes,
causing the popover to persist/reopen incorrectly; add a useEffect that watches
the block identity (e.g., block or block.id) and calls setPopoverOpen(false)
whenever the block changes or becomes undefined to ensure the popover closes on
block switches; update FileCaptionButton to use this effect alongside the
existing popover state and handlers so changes at lines around the block usage
(references to popoverOpen, setPopoverOpen, and block) reliably reset the UI.


setCurrentEditingName(block.props.name);
}, [block]);
const [popoverOpen, setPopoverOpen] = useState(false);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reset popover state when the selected block changes.

Same issue here: popoverOpen can persist while render returns null (Line 88), which may auto-open the rename popover when a file block is selected later. Reset state on block identity changes.

Suggested fix
 import {
   ChangeEvent,
   KeyboardEvent,
   useCallback,
+  useEffect,
   useState,
 } from "react";
@@
   const [popoverOpen, setPopoverOpen] = useState(false);
+
+  useEffect(() => {
+    setPopoverOpen(false);
+  }, [block?.id]);

Also applies to: 88-90, 93-96

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/react/src/components/FormattingToolbar/DefaultButtons/FileRenameButton.tsx`
at line 61, In FileRenameButton, ensure the popoverOpen state is reset whenever
the selected block identity changes: add a useEffect that watches the selected
block (e.g., selectedBlock or selectedBlockId prop) and calls
setPopoverOpen(false) when that value changes so the rename popover cannot
persist across different block selections; update any paths where render returns
null to rely on this reset.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 18, 2026

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@2575

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@2575

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@2575

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@2575

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@2575

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@2575

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@2575

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@2575

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@2575

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@2575

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@2575

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@2575

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@2575

commit: 60d7870

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.

Hitting enter doesn't close the legend input Clicking outside of the legend input doesn't save

1 participant