Added selection-aware word count plugin for koenig-lexical#29431
Added selection-aware word count plugin for koenig-lexical#29431kevinfengcs88 wants to merge 1 commit into
Conversation
ref TryGhost/Koenig#1976 - reopens the Koenig PR above against this repo, as suggested when the Koenig monorepo was merged in and archived - reports the word count of the current selection so the editor UI can show "X of Y words" while text is selected - reuses the same countWords util as WordCountPlugin so selection counts stay consistent with the document total - selections in nested editors (image captions, callouts) work through the same context-ref pattern WordCountPlugin uses in KoenigNestedComposer
WalkthroughAdds selection-based word counting for main and nested Lexical editors. The new plugin tracks non-collapsed selections, combines nested editor counts, throttles updates, and cleans up stale entries. Composer context and nested composer wiring expose the functionality, while the demo displays selection and total word counts. The plugin is publicly exported, and Playwright tests cover selection states, whitespace, partial words, nested editors, and select-all behavior. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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.
🧹 Nitpick comments (2)
koenig/koenig-lexical/src/components/KoenigComposer.tsx (1)
115-130: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winConsider memoizing the context value.
The provider
valueobject is a new literal on every render, so every consumer (including all nested composers/plugins) re-renders wheneverKoenigComposerre-renders. This diff adds 3 more fields on top of an existing unmemoized object; wrapping it inuseMemowould limit unnecessary re-renders across the composer tree.🤖 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 `@koenig/koenig-lexical/src/components/KoenigComposer.tsx` around lines 115 - 130, Memoize the context value object passed to KoenigComposerContext.Provider using useMemo, including all listed fields and their dependencies, so consumers only re-render when a context value actually changes.koenig/koenig-lexical/src/plugins/SelectionWordCountPlugin.tsx (1)
14-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRelies on Lexical's internal
_parentEditorfield.
editor._parentEditoris explicitly annotated@internalin Lexical's own type definitions (confirmed via Lexical'sLexicalEditor.d.ts), so this isn't a documented public API and could change across Lexical upgrades without a semver-relevant note. Worth confirming there isn't a supported way to distinguish the "top-level" editor from nested ones (e.g. an explicitisNested/composer-provided flag threaded fromKoenigComposer/KoenigNestedComposer), and if not, at least leaving a comment noting the dependency on Lexical internals for future maintainers.Also applies to: 85-87
🤖 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 `@koenig/koenig-lexical/src/plugins/SelectionWordCountPlugin.tsx` around lines 14 - 25, Replace the direct _parentEditor check in the SelectionWordCountPlugin effect with a supported top-level-versus-nested composer signal, threaded from KoenigComposer/KoenigNestedComposer if available. If no public signal exists, retain the check but add a concise comment documenting its reliance on Lexical’s internal field and upgrade risk.
🤖 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.
Nitpick comments:
In `@koenig/koenig-lexical/src/components/KoenigComposer.tsx`:
- Around line 115-130: Memoize the context value object passed to
KoenigComposerContext.Provider using useMemo, including all listed fields and
their dependencies, so consumers only re-render when a context value actually
changes.
In `@koenig/koenig-lexical/src/plugins/SelectionWordCountPlugin.tsx`:
- Around line 14-25: Replace the direct _parentEditor check in the
SelectionWordCountPlugin effect with a supported top-level-versus-nested
composer signal, threaded from KoenigComposer/KoenigNestedComposer if available.
If no public signal exists, retain the check but add a concise comment
documenting its reliance on Lexical’s internal field and upgrade risk.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 937456f5-ceb1-4c38-a8fb-71caebed2c5e
📒 Files selected for processing (7)
koenig/koenig-lexical/demo/DemoApp.tsxkoenig/koenig-lexical/demo/components/WordCount.tsxkoenig/koenig-lexical/src/components/KoenigComposer.tsxkoenig/koenig-lexical/src/components/KoenigNestedComposer.tsxkoenig/koenig-lexical/src/index.tskoenig/koenig-lexical/src/plugins/SelectionWordCountPlugin.tsxkoenig/koenig-lexical/test/e2e/plugins/SelectionWordCountPlugin.test.ts
Reopens TryGhost/Koenig#1976 against this repo, as suggested in its closing comment after the Koenig monorepo was merged in.
Adds a headless
SelectionWordCountPluginthat shows the word count of the current selection.countWordsutil asWordCountPlugin, so selection counts should stay consistent with the document totalWordCountPluginuses inKoenigNestedComposerVideo demo (this is the same video from the old PR that was opened against the archived Koenig repo):
ghost_koenig_word_counter.mp4