From a521a1ad7217780df64c4f3ac4bb882f7f360723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 7 Nov 2025 14:35:46 +0800 Subject: [PATCH 1/2] fix: not trigger scroll when init --- src/DropdownMenu.tsx | 10 ++++++---- src/KeywordTrigger.tsx | 8 +++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/DropdownMenu.tsx b/src/DropdownMenu.tsx index 33d033b..8993216 100644 --- a/src/DropdownMenu.tsx +++ b/src/DropdownMenu.tsx @@ -1,4 +1,4 @@ -import Menu, { MenuItem, MenuRef } from '@rc-component/menu'; +import Menu, { MenuItem, type MenuRef } from '@rc-component/menu'; import React, { useEffect, useRef } from 'react'; import MentionsContext from './MentionsContext'; import type { DataDrivenOptionProps } from './Mentions'; @@ -6,6 +6,7 @@ import type { DataDrivenOptionProps } from './Mentions'; export interface DropdownMenuProps { prefixCls?: string; options: DataDrivenOptionProps[]; + opened: boolean; } /** @@ -23,24 +24,25 @@ function DropdownMenu(props: DropdownMenuProps) { onScroll, } = React.useContext(MentionsContext); - const { prefixCls, options } = props; + const { prefixCls, options, opened } = props; const activeOption = options[activeIndex] || {}; const menuRef = useRef(null); // Monitor the changes in ActiveIndex and scroll to the visible area if there are any changes useEffect(() => { - if (activeIndex === -1 || !menuRef.current) { + if (activeIndex === -1 || !menuRef.current || !opened) { return; } const activeItem = menuRef.current?.findItem?.({ key: activeOption.key }); + if (activeItem) { activeItem.scrollIntoView({ block: 'nearest', inline: 'nearest', }); } - }, [activeIndex, activeOption.key]); + }, [activeIndex, activeOption.key, opened]); return ( = props => { } = props; const dropdownPrefix = `${prefixCls}-dropdown`; + const [opened, setOpened] = React.useState(false); const dropdownElement = ( - + ); const dropdownPlacement = useMemo(() => { @@ -95,6 +100,7 @@ const KeywordTrigger: FC = props => { getPopupContainer={getPopupContainer} popupClassName={popupClassName} popupStyle={popupStyle} + afterOpenChange={setOpened} > {children} From 799b9f5b2975c6c886cc18d15eb3f6e9beead7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 7 Nov 2025 15:52:15 +0800 Subject: [PATCH 2/2] test: update test case --- tests/DropdownMenu.spec.tsx | 49 ++++++++----------------------------- 1 file changed, 10 insertions(+), 39 deletions(-) diff --git a/tests/DropdownMenu.spec.tsx b/tests/DropdownMenu.spec.tsx index aba9331..8d88603 100644 --- a/tests/DropdownMenu.spec.tsx +++ b/tests/DropdownMenu.spec.tsx @@ -19,7 +19,7 @@ describe('DropdownMenu', () => { jest.useRealTimers(); }); - it('should scroll into view when navigating with keyboard', () => { + it('should scroll into view when navigating with keyboard', async () => { // Setup component with UnstableContext for testing dropdown behavior const { container } = render( @@ -32,51 +32,22 @@ describe('DropdownMenu', () => { .spyOn(HTMLElement.prototype, 'scrollIntoView') .mockImplementation(jest.fn()); - const textarea = container.querySelector('textarea')!; + // Trigger should not scroll + simulateInput(container, '@'); + expect(scrollIntoViewMock).not.toHaveBeenCalled(); - act(() => { - // First trigger the measuring state by typing @ - simulateInput(container, '@'); - jest.runAllTimers(); - }); - - // Verify we're in measuring state - expectMeasuring(container, true); - - act(() => { - // Press ArrowDown multiple times to make options overflow the visible area - for (let i = 0; i < 10; i++) { - fireEvent.keyDown(textarea, { - keyCode: KeyCode.DOWN, - which: KeyCode.DOWN, - }); - } - jest.runAllTimers(); - }); + for (let i = 0; i < 10; i++) { + await act(async () => { + jest.advanceTimersByTime(1000); + await Promise.resolve(); + }); + } // Verify if scrollIntoView was called expect(scrollIntoViewMock).toHaveBeenCalledWith({ block: 'nearest', inline: 'nearest', }); - scrollIntoViewMock.mockClear(); - - act(() => { - // Press ArrowUp to verify scrolling up - for (let i = 0; i < 5; i++) { - fireEvent.keyDown(textarea, { - keyCode: KeyCode.UP, - which: KeyCode.UP, - }); - } - jest.runAllTimers(); - }); - - // Verify if scrollIntoView was called again - expect(scrollIntoViewMock).toHaveBeenCalledWith({ - block: 'nearest', - inline: 'nearest', - }); scrollIntoViewMock.mockRestore(); });