Skip to content

Commit 1f37244

Browse files
authored
fix(Popup): nested content can not closed (#4023)
1 parent f074fd1 commit 1f37244

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-8
lines changed

packages/components/popup/Popup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ const Popup = forwardRef<PopupInstanceFunctions, PopupProps>((originalProps, ref
100100
[placement],
101101
);
102102

103-
const { triggerElementIsString, handleMouseLeave, getTriggerElement, getTriggerNode } = useTrigger({
103+
const { triggerElementIsString, getTriggerElement, getTriggerNode, getPopupProps } = useTrigger({
104104
triggerElement,
105105
content,
106106
disabled,
@@ -232,7 +232,7 @@ const Popup = forwardRef<PopupInstanceFunctions, PopupProps>((originalProps, ref
232232
className={classNames(`${classPrefix}-popup`, overlayClassName)}
233233
{...attributes.popper}
234234
onClick={(e) => props.onOverlayClick?.({ e })}
235-
onMouseLeave={handleMouseLeave}
235+
{...getPopupProps()}
236236
>
237237
<div
238238
ref={contentRef}

packages/components/popup/hooks/useTrigger.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default function useTrigger({ triggerElement, content, disabled, trigger,
1212
const triggerElementIsString = typeof triggerElement === 'string';
1313

1414
const triggerRef = useRef<HTMLElement>(null);
15+
const hasPopupMouseDown = useRef(false);
1516
const visibleTimer = useRef(null);
1617

1718
// 禁用和无内容时不展示
@@ -55,6 +56,13 @@ export default function useTrigger({ triggerElement, content, disabled, trigger,
5556
}
5657
};
5758

59+
const handlePopupMouseDown = () => {
60+
hasPopupMouseDown.current = true;
61+
requestAnimationFrame(() => {
62+
hasPopupMouseDown.current = false;
63+
});
64+
};
65+
5866
useEffect(() => clearTimeout(visibleTimer.current), []);
5967

6068
useEffect(() => {
@@ -163,16 +171,18 @@ export default function useTrigger({ triggerElement, content, disabled, trigger,
163171
if (!shouldToggle) return;
164172

165173
const handleDocumentClick = (e: any) => {
166-
const element = getTriggerElement();
167-
if (element?.contains?.(e.target) || e.target?.closest?.(`.${classPrefix}-popup`)) return;
168-
visible && onVisibleChange(false, { e, trigger: 'document' });
174+
if (!visible || getTriggerElement()?.contains?.(e.target) || hasPopupMouseDown.current) return;
175+
onVisibleChange(false, { e, trigger: 'document' });
169176
};
170177

171178
on(document, 'mousedown', handleDocumentClick);
172179
on(document, 'touchend', handleDocumentClick, { passive: true });
180+
173181
return () => {
174-
off(document, 'mousedown', handleDocumentClick);
175-
off(document, 'touchend', handleDocumentClick, { passive: true });
182+
requestAnimationFrame(() => {
183+
off(document, 'mousedown', handleDocumentClick);
184+
off(document, 'touchend', handleDocumentClick, { passive: true });
185+
});
176186
};
177187
}, [classPrefix, shouldToggle, visible, onVisibleChange, getTriggerElement]);
178188

@@ -204,10 +214,18 @@ export default function useTrigger({ triggerElement, content, disabled, trigger,
204214
);
205215
}
206216

217+
function getPopupProps() {
218+
return {
219+
onMouseLeave: handleMouseLeave,
220+
onMouseDown: handlePopupMouseDown,
221+
onTouchEnd: handlePopupMouseDown,
222+
};
223+
}
224+
207225
return {
208226
triggerElementIsString,
209-
handleMouseLeave,
210227
getTriggerElement,
211228
getTriggerNode,
229+
getPopupProps,
212230
};
213231
}

0 commit comments

Comments
 (0)