diff --git a/docs/examples/point.tsx b/docs/examples/point.tsx index 839092de..bf2fa50f 100644 --- a/docs/examples/point.tsx +++ b/docs/examples/point.tsx @@ -1,7 +1,8 @@ /* eslint no-console:0 */ import React from 'react'; -import Trigger, { ActionType } from '@rc-component/trigger'; +import type { ActionType } from '@rc-component/trigger'; +import Trigger from '@rc-component/trigger'; import '../../assets/index.less'; import './point.less'; diff --git a/src/index.tsx b/src/index.tsx index 18671095..789831d4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -33,6 +33,7 @@ export type { }; import UniqueProvider, { type UniqueProviderProps } from './UniqueProvider'; +import { useControlledState } from '@rc-component/util'; export { UniqueProvider }; export type { UniqueProviderProps }; @@ -303,12 +304,12 @@ export function generateTrigger( : null; // ============================ Open ============================ - const [internalOpen, setInternalOpen] = React.useState( + const [internalOpen, setInternalOpen] = useControlledState( defaultPopupVisible || false, + popupVisible, ); - // Render still use props as first priority - const mergedOpen = popupVisible ?? internalOpen; + const mergedOpen = internalOpen || false; // ========================== Children ========================== const child = React.useMemo(() => { @@ -321,20 +322,9 @@ export function generateTrigger( const originChildProps = child?.props || {}; - // We use effect sync here in case `popupVisible` back to `undefined` - const setMergedOpen = useEvent((nextOpen: boolean) => { - if (openUncontrolled) { - setInternalOpen(nextOpen); - } - }); - // Support ref const isOpen = useEvent(() => mergedOpen); - useLayoutEffect(() => { - setInternalOpen(popupVisible || false); - }, [popupVisible]); - // Extract common options for UniqueProvider const getUniqueOptions = useEvent((delay: number = 0) => ({ popup, @@ -385,7 +375,7 @@ export function generateTrigger( lastTriggerRef.current = []; const internalTriggerOpen = useEvent((nextOpen: boolean) => { - setMergedOpen(nextOpen); + setInternalOpen(nextOpen); // Enter or Pointer will both trigger open state change // We only need take one to avoid duplicated change event trigger diff --git a/tests/basic.test.jsx b/tests/basic.test.jsx index c42f155d..ed320816 100644 --- a/tests/basic.test.jsx +++ b/tests/basic.test.jsx @@ -371,10 +371,7 @@ describe('Trigger.Basic', () => { describe('children renderProps', () => { it('should get current open', () => { const { container } = render( - Hello!} - > + Hello!}> {({ open }) => } , ); @@ -994,6 +991,16 @@ describe('Trigger.Basic', () => { expect(document.querySelector('.rc-trigger-popup-hidden')).toBeTruthy(); }); + it('defaultPopupVisible should work', async () => { + render( + +
+ , + ); + + expect(document.querySelector('.rc-trigger-popup')).toBeTruthy(); + }); + describe('click window to hide', () => { it('should hide', async () => { const onOpenChange = jest.fn();