@@ -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 ) => ( {
@@ -371,20 +381,24 @@ export function generateTrigger(
371381 ! openUncontrolled &&
372382 ! parentContext
373383 ) {
374- if ( mergedOpen ) {
384+ if ( rawOpen && ! disabled ) {
375385 uniqueContext . show ( getUniqueOptions ( mouseEnterDelay ) , isOpen ) ;
376386 } else {
377- uniqueContext . hide ( mouseLeaveDelay ) ;
387+ uniqueContext . hide ( disabled ? 0 : mouseLeaveDelay , isOpen ) ;
378388 }
379389 }
380- } , [ mergedOpen , targetEle ] ) ;
390+ } , [ rawOpen , targetEle ] ) ;
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,10 +426,12 @@ 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 {
414- uniqueContext . hide ( delay ) ;
434+ uniqueContext . hide ( delay , isOpen ) ;
415435 }
416436 return ;
417437 }
@@ -421,6 +441,39 @@ export function generateTrigger(
421441 } , delay ) ;
422442 } ;
423443
444+ useLayoutEffect (
445+ ( firstMount ) => {
446+ const uniqueRawOpen = openUncontrolled
447+ ? uniqueOpenRef . current
448+ : rawOpen ;
449+
450+ if (
451+ ! firstMount &&
452+ uniqueContext &&
453+ unique &&
454+ ( disabled || uniqueRawOpen ) &&
455+ ! parentContext
456+ ) {
457+ uniqueContext . setDisabled (
458+ disabled ,
459+ getUniqueOptions ( ) ,
460+ isOpen ,
461+ ! openUncontrolled ,
462+ ) ;
463+ }
464+ } ,
465+ [
466+ disabled ,
467+ getUniqueOptions ,
468+ isOpen ,
469+ openUncontrolled ,
470+ parentContext ,
471+ rawOpen ,
472+ unique ,
473+ uniqueContext ,
474+ ] ,
475+ ) ;
476+
424477 function onEsc ( { top } : Parameters < PortalProps [ 'onEsc' ] > [ 0 ] ) {
425478 if ( top ) {
426479 triggerOpen ( false ) ;
@@ -645,7 +698,7 @@ export function generateTrigger(
645698
646699 // Click to hide is special action since click popup element should not hide
647700 const onPopupPointerDown = useWinClick (
648- mergedOpen ,
701+ rawOpen ,
649702 clickToHide || touchToHide ,
650703 targetEle ,
651704 popupEle ,
0 commit comments