Skip to content

Wave mention bug#2015

Merged
simo6529 merged 4 commits intomainfrom
wave-mention-bug
Feb 27, 2026
Merged

Wave mention bug#2015
simo6529 merged 4 commits intomainfrom
wave-mention-bug

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Feb 27, 2026

Summary by CodeRabbit

  • Tests

    • Added comprehensive tests for wave mentions: options building, open/close state, node creation, sanitized payload emission, typeahead positioning, selection, and event/observer cleanup.
  • Refactor

    • Improved typeahead menu positioning using dynamic space calculations with robust resize/scroll/observer handling.
  • Chore

    • Added an optional anchor element prop to the typeahead menu to improve placement accuracy.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 27, 2026

📝 Walkthrough

Walkthrough

Replaces external-store positioning with local useState/useEffect and ResizeObserver in WaveMentionsTypeaheadMenu, adds an anchorElement prop, updates WaveMentionsPlugin to pass the anchor, and adds comprehensive tests for positioning, selection, and node creation/emission.

Changes

Cohort / File(s) Summary
Typeahead Menu Component
components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.tsx
Replaced useSyncExternalStore subscription with internal position state and updatePosition logic that reads anchorElement and window dimensions; added useEffect to attach ResizeObserver/resize/scroll listeners and improved cleanup. API now accepts anchorElement: HTMLElement.
Plugin Usage Update
components/drops/create/lexical/plugins/waves/WaveMentionsPlugin.tsx
Passes anchorElementRef.current into WaveMentionsTypeaheadMenu via new anchorElement prop.
Typeahead Menu Tests
__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx
Adds tests mocking getBoundingClientRect and ResizeObserver to assert top/bottom positioning, verifies highlight/select behavior on clicks, confirms recalculation on resize/scroll, and ensures proper listener cleanup.
Plugin Tests
__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsPlugin.test.tsx
Adds integration-style tests that mock Lexical context, typeahead props, wave search hook, and node factory; verifies options building, open-state exposure, node creation/replace/select behavior, sanitized payload emission, and menu close after selection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • ragnep
  • prxt6529

Poem

🐰 I measured the anchor with whiskered care,
Resize and scroll danced through the air,
I nudged the menu to top or to bottom,
Tests tapped their paws — no layout forgotten,
A wave mention placed — hop, click, and cheer!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Wave mention bug' is vague and does not convey what bug is being fixed or what changes are made. It lacks specificity about the actual problem or solution. Revise the title to be more descriptive, such as 'Fix wave mention positioning in typeahead menu' or similar, that explains the specific bug being addressed.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wave-mention-bug

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.

❤️ Share

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

Copy link
Copy Markdown

@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: 1

🧹 Nitpick comments (1)
__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx (1)

14-24: Make viewport-dependent positioning tests deterministic.

These assertions rely on ambient window.innerHeight; pinning it in setup will reduce flakiness across test environments.

💡 Suggested patch
 describe("WaveMentionsTypeaheadMenu", () => {
+  const originalInnerHeight = window.innerHeight;
   const baseRect = {
@@
   beforeEach(() => {
+    Object.defineProperty(window, "innerHeight", {
+      configurable: true,
+      value: 800,
+    });
     getBoundingClientRectMock = jest
       .spyOn(HTMLElement.prototype, "getBoundingClientRect")
       .mockReturnValue(baseRect as DOMRect);
   });
 
   afterEach(() => {
+    Object.defineProperty(window, "innerHeight", {
+      configurable: true,
+      value: originalInnerHeight,
+    });
     getBoundingClientRectMock.mockRestore();
     jest.clearAllMocks();
   });

Also applies to: 54-59

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

In
`@__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx`
around lines 14 - 24, Tests use viewport-dependent values via baseRect and rely
on window.innerHeight, causing flakiness; make them deterministic by pinning
window.innerHeight to a fixed value in the test setup and restoring it
afterwards. Add a beforeEach or beforeAll that sets window.innerHeight =
<fixedNumber> (e.g., 800) before tests that use baseRect (and the related
assertions around lines 54-59), and an afterEach/afterAll that restores the
original innerHeight to avoid side effects. Ensure the change targets the test
file WaveMentionsTypeaheadMenu.test.tsx and affects both occurrences of
baseRect-based assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.tsx`:
- Around line 26-34: The current position calculation uses the
already-positioned menu's bounding rect (variable element/getBoundingClientRect)
which biases measurements by the menu height; change it to measure the anchor's
geometry instead: obtain the anchor's bounding rect (e.g.,
anchorElement.getBoundingClientRect() or the selection/anchor node rect) and
compute spaceAbove = anchorRect.top and spaceBelow = window.innerHeight -
anchorRect.bottom, then pick nextPosition ("top"|"bottom") from those values and
call setPosition as before (keep the setPosition(current => current ===
nextPosition ? current : nextPosition) logic). Ensure you reference the anchor
element/rect rather than the menu element/rect when computing
spaceAbove/spaceBelow.

---

Nitpick comments:
In
`@__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx`:
- Around line 14-24: Tests use viewport-dependent values via baseRect and rely
on window.innerHeight, causing flakiness; make them deterministic by pinning
window.innerHeight to a fixed value in the test setup and restoring it
afterwards. Add a beforeEach or beforeAll that sets window.innerHeight =
<fixedNumber> (e.g., 800) before tests that use baseRect (and the related
assertions around lines 54-59), and an afterEach/afterAll that restores the
original innerHeight to avoid side effects. Ensure the change targets the test
file WaveMentionsTypeaheadMenu.test.tsx and affects both occurrences of
baseRect-based assertions.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9475e86 and deb6d5f.

📒 Files selected for processing (3)
  • __tests__/components/drops/create/lexical/plugins/waves/WaveMentionsPlugin.test.tsx
  • __tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx
  • components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.tsx

Comment thread components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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: 1

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

Inline comments:
In `@components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.tsx`:
- Around line 60-75: The menu position only updates on window resize and menu
element resize, so scrolling or anchor movement leaves it stale; modify the
effect that sets up updatePosition (including the win.addEventListener("resize",
updatePosition) block and ResizeObserver usage) to also listen for scroll events
(e.g., window.addEventListener("scroll", updatePosition) with passive option)
and to observe the anchorElement with ResizeObserver in addition to
menuRef.current so changes to the anchor's size/position trigger updatePosition;
also ensure cleanup removes the scroll listener and disconnects the
ResizeObserver and still calls cancelInitialUpdate and
win.removeEventListener("resize", updatePosition) to fully tear down
(references: updatePosition, menuRef.current, anchorElement, ResizeObserver,
cancelInitialUpdate).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deb6d5f and f6b3759.

📒 Files selected for processing (2)
  • components/drops/create/lexical/plugins/waves/WaveMentionsPlugin.tsx
  • components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.tsx

Signed-off-by: Simo <simo@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Feb 27, 2026

Quality Gate Passed Quality Gate passed

Issues
0 New issues
4 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx (1)

168-188: Tighten cleanup assertions to verify the exact listener references.

expect.any(Function) can still pass if cleanup removes a different callback. Capture the listener passed to addEventListener and assert the same reference is removed.

Suggested test hardening
+      const resizeAddCall = addListenerSpy.mock.calls.find(
+        ([type]) => type === "resize"
+      );
+      const scrollAddCall = addListenerSpy.mock.calls.find(
+        ([type]) => type === "scroll"
+      );
+      const resizeHandler = resizeAddCall?.[1] as EventListener;
+      const scrollHandler = scrollAddCall?.[1] as EventListener;
+
       expect(addListenerSpy).toHaveBeenCalledWith(
         "resize",
         expect.any(Function)
       );
       expect(addListenerSpy).toHaveBeenCalledWith(
         "scroll",
         expect.any(Function),
         { passive: true }
       );
       expect(observe).toHaveBeenCalledWith(anchorElement);

       unmount();

-      expect(removeListenerSpy).toHaveBeenCalledWith(
-        "resize",
-        expect.any(Function)
-      );
-      expect(removeListenerSpy).toHaveBeenCalledWith(
-        "scroll",
-        expect.any(Function)
-      );
+      expect(removeListenerSpy).toHaveBeenCalledWith("resize", resizeHandler);
+      expect(removeListenerSpy).toHaveBeenCalledWith("scroll", scrollHandler);
       expect(disconnect).toHaveBeenCalledTimes(1);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx`
around lines 168 - 188, The cleanup assertions use expect.any(Function) which
can mask mismatched callbacks; change the test to capture the actual listener
functions passed to addListenerSpy (inspect addListenerSpy.mock.calls to find
the "resize" and "scroll" callback references after mounting) and then assert
that removeListenerSpy was called with those same function references (use the
captured resize and scroll callback variables) instead of expect.any(Function);
keep the observe/assert and unmount sequence the same so you verify
observe(anchorElement) and then unmount triggers removeListenerSpy calledWith
the exact previously captured functions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@__tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx`:
- Around line 168-188: The cleanup assertions use expect.any(Function) which can
mask mismatched callbacks; change the test to capture the actual listener
functions passed to addListenerSpy (inspect addListenerSpy.mock.calls to find
the "resize" and "scroll" callback references after mounting) and then assert
that removeListenerSpy was called with those same function references (use the
captured resize and scroll callback variables) instead of expect.any(Function);
keep the observe/assert and unmount sequence the same so you verify
observe(anchorElement) and then unmount triggers removeListenerSpy calledWith
the exact previously captured functions.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6b3759 and 0d467de.

📒 Files selected for processing (2)
  • __tests__/components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.test.tsx
  • components/drops/create/lexical/plugins/waves/WaveMentionsTypeaheadMenu.tsx

@simo6529 simo6529 merged commit de8f5b9 into main Feb 27, 2026
7 checks passed
@simo6529 simo6529 deleted the wave-mention-bug branch February 27, 2026 18:42
@coderabbitai coderabbitai Bot mentioned this pull request Mar 2, 2026
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.

2 participants