@@ -65,6 +65,8 @@ export interface TriggerProps {
6565 action ?: ActionType | ActionType [ ] ;
6666 showAction ?: ActionType [ ] ;
6767 hideAction ?: ActionType [ ] ;
68+ /** Temporarily suppress popup visibility without resetting the current open state. */
69+ disabled ?: boolean ;
6870
6971 prefixCls ?: string ;
7072
@@ -159,6 +161,7 @@ export function generateTrigger(
159161 action = 'hover' ,
160162 showAction,
161163 hideAction,
164+ disabled = false ,
162165
163166 // Open
164167 popupVisible,
@@ -319,7 +322,10 @@ export function generateTrigger(
319322 popupVisible ,
320323 ) ;
321324
322- const mergedOpen = internalOpen || false ;
325+ const rawOpen = internalOpen || false ;
326+ const mergedOpen = rawOpen && ! disabled ;
327+
328+ const uniqueOpenRef = React . useRef ( false ) ;
323329
324330 // ========================== Children ==========================
325331 const child = React . useMemo ( ( ) => {
@@ -333,7 +339,11 @@ export function generateTrigger(
333339 const originChildProps = child ?. props || { } ;
334340
335341 // Support ref
336- const isOpen = useEvent ( ( ) => mergedOpen ) ;
342+ const isOpen = useEvent ( ( ) =>
343+ uniqueContext && unique && openUncontrolled && ! parentContext
344+ ? uniqueOpenRef . current && ! disabled
345+ : mergedOpen ,
346+ ) ;
337347
338348 // Extract common options for UniqueProvider
339349 const getUniqueOptions = useEvent ( ( delay : number = 0 ) => ( {
@@ -360,31 +370,35 @@ export function generateTrigger(
360370 onEsc,
361371 } ) ) ;
362372
363- // Handle controlled state changes for UniqueProvider
364- // Only sync to UniqueProvider when it's controlled mode
373+ // Sync controlled state and disabled changes to UniqueProvider
365374 // If there is a parentContext, don't call uniqueContext methods
366375 useLayoutEffect ( ( ) => {
367- if (
368- uniqueContext &&
369- unique &&
370- targetEle &&
371- ! openUncontrolled &&
372- ! parentContext
373- ) {
374- if ( mergedOpen ) {
375- uniqueContext . show ( getUniqueOptions ( mouseEnterDelay ) , isOpen ) ;
376+ if ( uniqueContext && unique && targetEle && ! parentContext ) {
377+ const uniqueOpen = openUncontrolled
378+ ? uniqueOpenRef . current && ! disabled
379+ : mergedOpen ;
380+
381+ if ( uniqueOpen ) {
382+ uniqueContext . show (
383+ getUniqueOptions ( openUncontrolled ? 0 : mouseEnterDelay ) ,
384+ isOpen ,
385+ ) ;
376386 } else {
377- uniqueContext . hide ( mouseLeaveDelay ) ;
387+ uniqueContext . hide ( disabled ? 0 : mouseLeaveDelay ) ;
378388 }
379389 }
380- } , [ mergedOpen , targetEle ] ) ;
390+ } , [ mergedOpen , targetEle , disabled ] ) ;
381391
382- const openRef = React . useRef ( mergedOpen ) ;
383- openRef . current = mergedOpen ;
392+ const openRef = React . useRef ( rawOpen ) ;
393+ openRef . current = rawOpen ;
384394
385395 const internalTriggerOpen = useEvent ( ( nextOpen : boolean ) => {
396+ if ( disabled && nextOpen ) {
397+ return ;
398+ }
399+
386400 flushSync ( ( ) => {
387- if ( mergedOpen !== nextOpen ) {
401+ if ( rawOpen !== nextOpen ) {
388402 setInternalOpen ( nextOpen ) ;
389403 onOpenChange ?.( nextOpen ) ;
390404 onPopupVisibleChange ?.( nextOpen ) ;
@@ -396,6 +410,10 @@ export function generateTrigger(
396410 const delayInvoke = useDelay ( ) ;
397411
398412 const triggerOpen = ( nextOpen : boolean , delay = 0 ) => {
413+ if ( disabled && nextOpen ) {
414+ return ;
415+ }
416+
399417 // If it's controlled mode, always use internal trigger logic
400418 // UniqueProvider will be synced through useLayoutEffect
401419 if ( popupVisible !== undefined ) {
@@ -408,6 +426,8 @@ export function generateTrigger(
408426 // If UniqueContext exists and not controlled, pass delay to Provider instead of handling it internally
409427 // If there is a parentContext, don't call uniqueContext methods
410428 if ( uniqueContext && unique && openUncontrolled && ! parentContext ) {
429+ uniqueOpenRef . current = nextOpen ;
430+
411431 if ( nextOpen ) {
412432 uniqueContext . show ( getUniqueOptions ( delay ) , isOpen ) ;
413433 } else {
@@ -645,7 +665,7 @@ export function generateTrigger(
645665
646666 // Click to hide is special action since click popup element should not hide
647667 const onPopupPointerDown = useWinClick (
648- mergedOpen ,
668+ rawOpen ,
649669 clickToHide || touchToHide ,
650670 targetEle ,
651671 popupEle ,
0 commit comments