Skip to content

Commit bbd4a1f

Browse files
committed
fix(Popup): triggerElement string not working as CSS selector
1 parent 672e0a3 commit bbd4a1f

File tree

6 files changed

+249
-193
lines changed

6 files changed

+249
-193
lines changed

packages/components/_util/listener.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ import { canUseDocument } from './dom';
22

33
export const on = ((): any => {
44
if (canUseDocument && document.addEventListener) {
5-
return (element: Node, event: string, handler: EventListenerOrEventListenerObject): any => {
5+
return (
6+
element: Node,
7+
event: string,
8+
handler: EventListenerOrEventListenerObject,
9+
options?: AddEventListenerOptions,
10+
): any => {
611
if (element && event && handler) {
7-
element.addEventListener(event, handler, false);
12+
element.addEventListener(event, handler, options ?? false);
813
}
914
};
1015
}
@@ -17,9 +22,14 @@ export const on = ((): any => {
1722

1823
export const off = ((): any => {
1924
if (canUseDocument && document.removeEventListener) {
20-
return (element: Node, event: string, handler: EventListenerOrEventListenerObject): any => {
25+
return (
26+
element: Node,
27+
event: string,
28+
handler: EventListenerOrEventListenerObject,
29+
options?: boolean | EventListenerOptions,
30+
): any => {
2131
if (element && event) {
22-
element.removeEventListener(event, handler, false);
32+
element.removeEventListener(event, handler, options ?? false);
2333
}
2434
};
2535
}

packages/components/_util/ref.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,16 @@ export const getNodeRef: <T = any>(node: React.ReactNode) => React.Ref<T> | null
7070
}
7171
return null;
7272
};
73+
74+
export const mergeRefs =
75+
(...refs: any[]) =>
76+
(instance: any) => {
77+
refs.forEach((ref) => {
78+
if (typeof ref === 'function') {
79+
ref(instance);
80+
} else if (ref && typeof ref === 'object') {
81+
// eslint-disable-next-line no-param-reassign
82+
ref.current = instance;
83+
}
84+
});
85+
};

packages/components/popup/Popup.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import classNames from 'classnames';
33
import { debounce, isFunction } from 'lodash-es';
44
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
55
import { CSSTransition } from 'react-transition-group';
6-
import { getRefDom } from '../_util/ref';
6+
77
import { getCssVarsValue } from '../_util/style';
88
import Portal from '../common/Portal';
99
import useAnimation from '../hooks/useAnimation';
@@ -16,9 +16,10 @@ import usePopper from '../hooks/usePopper';
1616
import useWindowSize from '../hooks/useWindowSize';
1717
import { popupDefaultProps } from './defaultProps';
1818
import useTrigger from './hooks/useTrigger';
19-
import type { TdPopupProps } from './type';
2019
import { getTransitionParams } from './utils/transition';
2120

21+
import type { TdPopupProps } from './type';
22+
2223
export interface PopupProps extends TdPopupProps {
2324
// 是否触发展开收起动画,内部下拉式组件使用
2425
expandAnimation?: boolean;
@@ -72,7 +73,6 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
7273
const [visible, onVisibleChange] = useControlled(props, 'visible', props.onVisibleChange);
7374

7475
const [popupElement, setPopupElement] = useState(null);
75-
const triggerRef = useRef(null); // 记录 trigger 元素
7676
const popupRef = useRef(null); // popup dom 元素,css transition 需要用
7777
const portalRef = useRef(null); // portal dom 元素
7878
const contentRef = useRef(null); // 内容部分
@@ -100,18 +100,20 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
100100
[placement],
101101
);
102102

103-
const { getTriggerNode, getPopupProps, getTriggerDom } = useTrigger({
104-
triggerRef,
103+
const { triggerElementIsString, getTriggerElement, getTriggerNode } = useTrigger({
104+
children,
105+
triggerElement,
105106
content,
106107
disabled,
107108
trigger,
108109
visible,
109110
delay,
110111
onVisibleChange,
111112
});
113+
const triggerEl = getTriggerElement();
112114

113115
const popperOptions = props.popperOptions as Options;
114-
popperRef.current = usePopper(getRefDom(triggerRef), popupElement, {
116+
popperRef.current = usePopper(triggerEl, popupElement, {
115117
placement: popperPlacement,
116118
...popperOptions,
117119
});
@@ -128,8 +130,8 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
128130

129131
const updateTimeRef = useRef(null);
130132
// 监听 trigger 节点或内容变化动态更新 popup 定位
131-
useMutationObserver(getRefDom(triggerRef), () => {
132-
const isDisplayNone = getCssVarsValue('display', getRefDom(triggerRef)) === 'none';
133+
useMutationObserver(triggerEl, () => {
134+
const isDisplayNone = getCssVarsValue('display', triggerEl) === 'none';
133135
if (visible && !isDisplayNone) {
134136
clearTimeout(updateTimeRef.current);
135137
updateTimeRef.current = setTimeout(() => popperRef.current?.update?.(), 0);
@@ -146,11 +148,10 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
146148

147149
// 下拉展开时更新内部滚动条
148150
useEffect(() => {
149-
if (!triggerRef.current) triggerRef.current = getTriggerDom();
150151
if (visible) {
151152
updateScrollTop?.(contentRef.current);
152153
}
153-
}, [visible, updateScrollTop, getTriggerDom]);
154+
}, [visible, updateScrollTop]);
154155

155156
function handleExited() {
156157
!destroyOnClose && popupElement && (popupElement.style.display = 'none');
@@ -175,8 +176,8 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
175176

176177
// 整理浮层样式
177178
function getOverlayStyle(overlayStyle: TdPopupProps['overlayStyle']) {
178-
if (getRefDom(triggerRef) && popupRef.current && typeof overlayStyle === 'function') {
179-
return { ...overlayStyle(getRefDom(triggerRef), popupRef.current) };
179+
if (triggerEl && popupRef.current && typeof overlayStyle === 'function') {
180+
return { ...overlayStyle(triggerEl, popupRef.current) };
180181
}
181182
return { ...overlayStyle };
182183
}
@@ -191,7 +192,7 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
191192
onEnter={handleEnter}
192193
onExited={handleExited}
193194
>
194-
<Portal triggerNode={getRefDom(triggerRef)} attach={popupAttach} ref={portalRef}>
195+
<Portal triggerNode={triggerEl} attach={popupAttach} ref={portalRef}>
195196
<CSSTransition
196197
appear
197198
timeout={0}
@@ -213,7 +214,6 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
213214
style={{ ...styles.popper, zIndex, ...getOverlayStyle(overlayStyle) }}
214215
className={classNames(`${classPrefix}-popup`, overlayClassName)}
215216
{...attributes.popper}
216-
{...getPopupProps()}
217217
onClick={(e) => props.onOverlayClick?.({ e })}
218218
>
219219
<div
@@ -227,6 +227,7 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
227227
)}
228228
style={getOverlayStyle(overlayInnerStyle)}
229229
onScroll={handleScroll}
230+
// {...getPopupProps()}
230231
>
231232
{content}
232233
{showArrow && (
@@ -253,7 +254,7 @@ const Popup = forwardRef<PopupRef, PopupProps>((originalProps, ref) => {
253254

254255
return (
255256
<React.Fragment>
256-
{triggerNode}
257+
{triggerElementIsString ? null : triggerNode}
257258
{overlay}
258259
</React.Fragment>
259260
);

packages/components/popup/PopupPlugin.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
import { createPopper, Instance, Placement, type Options } from '@popperjs/core';
2-
import classNames from 'classnames';
3-
import { isString } from 'lodash-es';
41
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
52
import { CSSTransition } from 'react-transition-group';
3+
import { createPopper, type Instance, type Placement, type Options } from '@popperjs/core';
4+
import classNames from 'classnames';
5+
import { isString } from 'lodash-es';
6+
67
import { getAttach } from '../_util/dom';
78
import { off, on } from '../_util/listener';
89
import { render, unmount } from '../_util/react-render';
9-
import type { TNode } from '../common';
1010
import PluginContainer from '../common/PluginContainer';
1111
import ConfigProvider from '../config-provider';
12+
import useConfig from '../hooks/useConfig';
1213
import useDefaultProps from '../hooks/useDefaultProps';
1314
import { popupDefaultProps } from './defaultProps';
15+
16+
import type { TNode } from '../common';
1417
import type { TdPopupProps } from './type';
1518

1619
export interface PopupPluginApi {
@@ -31,8 +34,6 @@ let overlayInstance: HTMLElement;
3134
let timeout: NodeJS.Timeout;
3235
let triggerEl: HTMLElement;
3336

34-
const componentName = 't-popup';
35-
3637
const triggerType = (triggerProps: string) =>
3738
triggers.reduce(
3839
(map, trigger) => ({
@@ -62,6 +63,9 @@ const Overlay: React.FC<OverlayProps> = (originalProps) => {
6263
renderCallback,
6364
} = props;
6465

66+
const { classPrefix } = useConfig();
67+
const componentName = `${classPrefix}-popup`;
68+
6569
const [visibleState, setVisibleState] = useState(false);
6670
const popperRef = useRef<HTMLDivElement>(null);
6771
const overlayRef = useRef<HTMLDivElement>(null);
@@ -80,7 +84,6 @@ const Overlay: React.FC<OverlayProps> = (originalProps) => {
8084
};
8185
};
8286

83-
// useMemo
8487
const hasTrigger = useMemo(() => triggerType(trigger), [trigger]);
8588
const overlayClasses = useMemo(
8689
() => [
@@ -92,7 +95,7 @@ const Overlay: React.FC<OverlayProps> = (originalProps) => {
9295
},
9396
overlayInnerClassName,
9497
],
95-
[content, overlayInnerClassName, showArrow, disabled],
98+
[componentName, content, showArrow, disabled, overlayInnerClassName],
9699
);
97100

98101
// method

0 commit comments

Comments
 (0)