✨(frontend) add find and replace feature to the editor - #2570
Conversation
|
Size Change: +49.7 kB (+1.14%) Total Size: 4.41 MB 📦 View Changed
|
2be7e1e to
4252f8d
Compare
4252f8d to
dd91d96
Compare
|
@CodeRabbit review |
✅ Action performedReview finished.
|
WalkthroughThe editor now supports TipTap find-and-replace with keyboard activation, match navigation, selected-text prefilling, single replacement, replacement of all matches, active-result scrolling, and custom highlighting. The floating bar renders the find-and-replace panel when it is open. The change adds dependency resolutions and end-to-end coverage. It also updates modal icon properties, skeleton spacing, the viewport test setup, and the unreleased changelog. Estimated code review effort: 4 (Complex) | ~45 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Tools execution failed with the following error: Failed to run tools: 14 UNAVAILABLE: read ECONNRESET Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/frontend/apps/impress/src/features/skeletons/components/DocEditorSkeleton.tsx (1)
102-102: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRestore responsive horizontal padding for the skeleton core.
Line 102 removes the responsive state. Line 113 then applies
54pxhorizontal padding on every viewport.SkeletonEditorCoreis used on the editor path, which has mobile-specific padding rules. (raw.githubusercontent.com)On mobile, the loading skeleton can become narrower than the loaded editor and cause a layout shift. Restore the desktop/mobile split used by the header.
Proposed fix
export const SkeletonEditorCore = ({ isFadingOut, $css, ...props }: SkeletonEditorCoreProps) => { + const { isDesktop } = useResponsiveStore(); return ( ... - $padding={{ horizontal: '54px', top: '45px' }} + $padding={{ + horizontal: isDesktop ? '54px' : 'base', + top: '45px', + }}Also applies to: 113-113
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/frontend/apps/impress/src/features/skeletons/components/DocEditorSkeleton.tsx` at line 102, Restore the responsive horizontal padding behavior in the DocEditorSkeleton render, specifically for SkeletonEditorCore: use the same desktop/mobile split as the header so mobile matches the editor’s mobile padding instead of applying 54px at every viewport.Source: MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts`:
- Around line 668-675: Update the editor selection flow around the “Find in
document” textbox: after pressing Escape, wait for that textbox to be hidden,
then locate “World” within the existing editor scope using an exact text match
before calling selectText(). Keep the subsequent Ctrl+f assertion unchanged.
In `@src/frontend/apps/impress/src/components/modal/ButtonCloseModal.tsx`:
- Around line 2-8: Update ButtonCloseModalProps.iconProps to use the rendered
CloseIcon SVG component’s props, preferably ComponentProps<typeof CloseIcon> or
React.SVGProps<SVGSVGElement>, after verifying the installed declaration. Remove
the unrelated IconProps type so iconProps exposes only valid SVG properties
while preserving the existing CloseIcon rendering behavior.
In
`@src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx`:
- Line 238: Update the searchDebounceMs configuration in BlockNoteEditor to use
a non-zero debounce interval, preserving the default 250 ms or another measured
positive value, so setSearchTerm does not trigger rescanning and redecorating on
every keystroke.
In
`@src/frontend/apps/impress/src/features/docs/doc-find-replace/components/FindReplace.tsx`:
- Around line 16-26: Update the styled Input focus styles to add a visible
:focus-visible indicator instead of leaving keyboard focus unmarked after
outline removal. Apply the same focus-visible treatment to the replace input’s
styled component as well.
- Around line 104-107: Update the counterLabel logic near hasMatches in
FindReplace so both matched and empty states use the same localized translation
key and consistent separator spacing, allowing translators to control the format
while preserving the 0/0 and active-match values.
In
`@src/frontend/apps/impress/src/features/docs/doc-header/components/DocFloatingBar.tsx`:
- Line 15: Update the useFindReplaceStore call in DocFloatingBar to use a
selector that reads only isOpen, while preserving the existing isFindReplaceOpen
value and behavior.
---
Outside diff comments:
In
`@src/frontend/apps/impress/src/features/skeletons/components/DocEditorSkeleton.tsx`:
- Line 102: Restore the responsive horizontal padding behavior in the
DocEditorSkeleton render, specifically for SkeletonEditorCore: use the same
desktop/mobile split as the header so mobile matches the editor’s mobile padding
instead of applying 54px at every viewport.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b0f48590-9aec-47c6-9b64-800bd028da36
⛔ Files ignored due to path filters (4)
src/frontend/apps/impress/src/assets/icons/ui-kit/arrow-down.svgis excluded by!**/*.svgsrc/frontend/apps/impress/src/assets/icons/ui-kit/arrow-squarepath.svgis excluded by!**/*.svgsrc/frontend/apps/impress/src/assets/icons/ui-kit/arrow-up.svgis excluded by!**/*.svgsrc/frontend/yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (14)
CHANGELOG.mdsrc/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.tssrc/frontend/apps/impress/package.jsonsrc/frontend/apps/impress/src/components/modal/ButtonCloseModal.tsxsrc/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsxsrc/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsxsrc/frontend/apps/impress/src/features/docs/doc-find-replace/components/FindReplace.tsxsrc/frontend/apps/impress/src/features/docs/doc-find-replace/hooks/useFindReplace.tssrc/frontend/apps/impress/src/features/docs/doc-find-replace/hooks/useFindReplaceShortcut.tsxsrc/frontend/apps/impress/src/features/docs/doc-find-replace/stores/useFindReplaceStore.tsxsrc/frontend/apps/impress/src/features/docs/doc-find-replace/styles.tsxsrc/frontend/apps/impress/src/features/docs/doc-header/components/DocFloatingBar.tsxsrc/frontend/apps/impress/src/features/skeletons/components/DocEditorSkeleton.tsxsrc/frontend/package.json
We have added a new feature to the editor that allows users to find and replace text within their documents. This feature enhances the editing experience by providing a convenient way to search for specific words or phrases and replace them with new content.
dd91d96 to
f42f8b5
Compare
Ovgodd
left a comment
There was a problem hiding this comment.
nice feature, I like it !
just some things in term of accessibility
| <Card | ||
| role="dialog" | ||
| aria-label={t('Find and replace')} |
There was a problem hiding this comment.
role="dialog" is a bit confusing here.
This panel is a floating toolbar (no focus trap, Tab can leave it), not a blocking modal. Screen readers announce it as a “dialog”, which sets the wrong expectation. ( user can expect to be in a modal )
we can add instead :
| <Card | |
| role="dialog" | |
| aria-label={t('Find and replace')} | |
| <Card | |
| role="search" | |
| aria-label={t('Find and replace')} |
| <Text | ||
| $size="xs" | ||
| $color="var(--c--contextuals--content--semantic--neutral--tertiary)" | ||
| $css={css` | ||
| white-space: nowrap; | ||
| font-variant-numeric: tabular-nums; | ||
| `} | ||
| > | ||
| {counterLabel} | ||
| </Text> |
There was a problem hiding this comment.
the match counter (1 / 2) is visual only and is not announced by screen readers.
When opening the panel and navigating with Tab, SR reads the find field and buttons, but never the occurrence count and When the query changes and when moving to next/previous match.
Suggestion aligned with DocSearchContent (announce from @react-aria/live-announcer):
| <Text | |
| $size="xs" | |
| $color="var(--c--contextuals--content--semantic--neutral--tertiary)" | |
| $css={css` | |
| white-space: nowrap; | |
| font-variant-numeric: tabular-nums; | |
| `} | |
| > | |
| {counterLabel} | |
| </Text> | |
| <Input | |
| ... | |
| aria-describedby="find-replace-match-count" | |
| /> | |
| <Text | |
| id="find-replace-match-count" | |
| role="status" | |
| $size="xs" | |
| $color="var(--c--contextuals--content--semantic--neutral--tertiary)" | |
| $css={css` | |
| white-space: nowrap; | |
| font-variant-numeric: tabular-nums; | |
| `} | |
| > | |
| {counterLabel} | |
| </Text> |
in detail :
role="status marks an element as a live status region for screen readers. When its content changes (e;g. 0 / 0 > 1 / 2), the SR announces it automatically, without needing focus on that element.
It implies:
polite live region > announces without interrupting the user
atomic > reads the whole text on each update (1 / 2 as a whole, not just the changed digit)
aria-describedby on the Find input points to that counter: when focusing the field, the SR can also announce the match count along with the field label.
And you can use announce from live-announcer like this :
announce(
matchCount === 0
? t('No matches')
: t('{{current}} of {{total}}', {
current: activeIndex + 1,
total: matchCount,
}),
'polite',
);
Nice-to-have: announce after replace / replace all (e.g. “Replaced”, “{{count}} matches replaced).
Purpose
We have added a new feature to the editor that allows users to find and replace text within their documents. This feature enhances the editing experience by providing a convenient way to search for specific words or phrases and replace them with new content.
Demo
Enregistrement.2026-08-11.110746.mp4