@rc-component/trigger 3.5.2 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/index.css +35 -0
- package/assets/index.less +48 -0
- package/es/Popup/index.d.ts +3 -0
- package/es/Popup/index.js +18 -37
- package/es/UniqueProvider/FloatBg.d.ts +21 -0
- package/es/UniqueProvider/FloatBg.js +62 -0
- package/es/UniqueProvider/MotionContent.d.ts +11 -0
- package/es/UniqueProvider/MotionContent.js +32 -0
- package/es/UniqueProvider/index.d.ts +6 -0
- package/es/UniqueProvider/index.js +144 -0
- package/es/UniqueProvider/useTargetState.d.ts +16 -0
- package/es/UniqueProvider/useTargetState.js +55 -0
- package/es/context.d.ts +27 -0
- package/es/context.js +8 -1
- package/es/hooks/useDelay.d.ts +1 -0
- package/es/hooks/useDelay.js +28 -0
- package/es/hooks/useOffsetStyle.d.ts +3 -0
- package/es/hooks/useOffsetStyle.js +35 -0
- package/es/index.d.ts +5 -0
- package/es/index.js +73 -18
- package/lib/Popup/index.d.ts +3 -0
- package/lib/Popup/index.js +18 -37
- package/lib/UniqueProvider/FloatBg.d.ts +21 -0
- package/lib/UniqueProvider/FloatBg.js +69 -0
- package/lib/UniqueProvider/MotionContent.d.ts +11 -0
- package/lib/UniqueProvider/MotionContent.js +41 -0
- package/lib/UniqueProvider/index.d.ts +6 -0
- package/lib/UniqueProvider/index.js +153 -0
- package/lib/UniqueProvider/useTargetState.d.ts +16 -0
- package/lib/UniqueProvider/useTargetState.js +62 -0
- package/lib/context.d.ts +27 -0
- package/lib/context.js +5 -2
- package/lib/hooks/useDelay.d.ts +1 -0
- package/lib/hooks/useDelay.js +36 -0
- package/lib/hooks/useOffsetStyle.d.ts +3 -0
- package/lib/hooks/useOffsetStyle.js +41 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +79 -18
- package/package.json +1 -1
package/assets/index.css
CHANGED
|
@@ -62,6 +62,41 @@
|
|
|
62
62
|
opacity: 0;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
+
.rc-trigger-popup-float-bg {
|
|
66
|
+
position: absolute;
|
|
67
|
+
z-index: 0;
|
|
68
|
+
box-sizing: border-box;
|
|
69
|
+
border: 1px solid red;
|
|
70
|
+
background: green;
|
|
71
|
+
}
|
|
72
|
+
.rc-trigger-popup-float-bg-hidden {
|
|
73
|
+
display: none;
|
|
74
|
+
}
|
|
75
|
+
.rc-trigger-popup-float-bg-visible {
|
|
76
|
+
transition: all 0.1s;
|
|
77
|
+
}
|
|
78
|
+
.rc-trigger-popup-unique-controlled {
|
|
79
|
+
border-color: rgba(0, 0, 0, 0.01) !important;
|
|
80
|
+
background: transparent !important;
|
|
81
|
+
z-index: 1;
|
|
82
|
+
}
|
|
83
|
+
.rc-trigger-popup-motion-content-fade-appear {
|
|
84
|
+
opacity: 0;
|
|
85
|
+
animation-duration: 0.3s;
|
|
86
|
+
animation-fill-mode: both;
|
|
87
|
+
animation-timing-function: cubic-bezier(0.55, 0, 0.55, 0.2);
|
|
88
|
+
}
|
|
89
|
+
.rc-trigger-popup-motion-content-fade-appear.rc-trigger-popup-motion-content-fade-appear-active {
|
|
90
|
+
animation-name: rcTriggerFadeIn;
|
|
91
|
+
}
|
|
92
|
+
@keyframes rcTriggerFadeIn {
|
|
93
|
+
0% {
|
|
94
|
+
opacity: 0;
|
|
95
|
+
}
|
|
96
|
+
100% {
|
|
97
|
+
opacity: 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
65
100
|
.rc-trigger-popup-mask {
|
|
66
101
|
position: fixed;
|
|
67
102
|
top: 0;
|
package/assets/index.less
CHANGED
|
@@ -73,6 +73,54 @@
|
|
|
73
73
|
opacity: 0;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
// =============== Float BG ===============
|
|
78
|
+
&-float-bg {
|
|
79
|
+
position: absolute;
|
|
80
|
+
z-index: 0;
|
|
81
|
+
box-sizing: border-box;
|
|
82
|
+
border: 1px solid red;
|
|
83
|
+
background: green;
|
|
84
|
+
|
|
85
|
+
&-hidden {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&-visible {
|
|
90
|
+
transition: all 0.1s;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Debug
|
|
95
|
+
&-unique-controlled {
|
|
96
|
+
border-color: rgba(0, 0, 0, 0.01) !important;
|
|
97
|
+
background: transparent !important;
|
|
98
|
+
z-index: 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Motion Content
|
|
102
|
+
&-motion-content {
|
|
103
|
+
// Fade motion
|
|
104
|
+
&-fade-appear {
|
|
105
|
+
opacity: 0;
|
|
106
|
+
animation-duration: 0.3s;
|
|
107
|
+
animation-fill-mode: both;
|
|
108
|
+
animation-timing-function: cubic-bezier(0.55, 0, 0.55, 0.2);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&-fade-appear&-fade-appear-active {
|
|
112
|
+
animation-name: rcTriggerFadeIn;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@keyframes rcTriggerFadeIn {
|
|
116
|
+
0% {
|
|
117
|
+
opacity: 0;
|
|
118
|
+
}
|
|
119
|
+
100% {
|
|
120
|
+
opacity: 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
76
124
|
}
|
|
77
125
|
|
|
78
126
|
@import './index/Mask';
|
package/es/Popup/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CSSMotionProps } from '@rc-component/motion';
|
|
2
|
+
import { type ResizeObserverProps } from '@rc-component/resize-observer';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
import type { TriggerProps } from '../';
|
|
4
5
|
import type { AlignType, ArrowPos, ArrowTypeOuter } from '../interface';
|
|
@@ -36,6 +37,7 @@ export interface PopupProps {
|
|
|
36
37
|
getPopupContainer?: TriggerProps['getPopupContainer'];
|
|
37
38
|
autoDestroy?: boolean;
|
|
38
39
|
portal: React.ComponentType<any>;
|
|
40
|
+
children?: React.ReactElement;
|
|
39
41
|
ready: boolean;
|
|
40
42
|
offsetX: number;
|
|
41
43
|
offsetY: number;
|
|
@@ -46,6 +48,7 @@ export interface PopupProps {
|
|
|
46
48
|
stretch?: string;
|
|
47
49
|
targetWidth?: number;
|
|
48
50
|
targetHeight?: number;
|
|
51
|
+
onResize?: ResizeObserverProps['onResize'];
|
|
49
52
|
mobile?: MobileConfig;
|
|
50
53
|
}
|
|
51
54
|
declare const Popup: React.ForwardRefExoticComponent<PopupProps & React.RefAttributes<HTMLDivElement>>;
|
package/es/Popup/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import * as React from 'react';
|
|
|
8
8
|
import Arrow from "./Arrow";
|
|
9
9
|
import Mask from "./Mask";
|
|
10
10
|
import PopupContent from "./PopupContent";
|
|
11
|
+
import useOffsetStyle from "../hooks/useOffsetStyle";
|
|
12
|
+
import { useEvent } from '@rc-component/util';
|
|
11
13
|
const Popup = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
12
14
|
const {
|
|
13
15
|
popup,
|
|
@@ -38,6 +40,7 @@ const Popup = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
38
40
|
getPopupContainer,
|
|
39
41
|
autoDestroy,
|
|
40
42
|
portal: Portal,
|
|
43
|
+
children,
|
|
41
44
|
zIndex,
|
|
42
45
|
onMouseEnter,
|
|
43
46
|
onMouseLeave,
|
|
@@ -50,11 +53,13 @@ const Popup = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
50
53
|
offsetB,
|
|
51
54
|
onAlign,
|
|
52
55
|
onPrepare,
|
|
56
|
+
// Resize
|
|
57
|
+
onResize,
|
|
53
58
|
stretch,
|
|
54
59
|
targetWidth,
|
|
55
60
|
targetHeight
|
|
56
61
|
} = props;
|
|
57
|
-
const
|
|
62
|
+
const popupContent = typeof popup === 'function' ? popup() : popup;
|
|
58
63
|
|
|
59
64
|
// We can not remove holder only when motion finished.
|
|
60
65
|
const isNodeVisible = open || keepDom;
|
|
@@ -81,44 +86,20 @@ const Popup = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
81
86
|
}
|
|
82
87
|
}, [show, getPopupContainerNeedParams, target]);
|
|
83
88
|
|
|
89
|
+
// ========================= Resize =========================
|
|
90
|
+
const onInternalResize = useEvent((size, ele) => {
|
|
91
|
+
onResize?.(size, ele);
|
|
92
|
+
onAlign();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// ========================= Styles =========================
|
|
96
|
+
const offsetStyle = useOffsetStyle(isMobile, ready, open, align, offsetR, offsetB, offsetX, offsetY);
|
|
97
|
+
|
|
84
98
|
// ========================= Render =========================
|
|
85
99
|
if (!show) {
|
|
86
100
|
return null;
|
|
87
101
|
}
|
|
88
102
|
|
|
89
|
-
// >>>>> Offset
|
|
90
|
-
const AUTO = 'auto';
|
|
91
|
-
const offsetStyle = isMobile ? {} : {
|
|
92
|
-
left: '-1000vw',
|
|
93
|
-
top: '-1000vh',
|
|
94
|
-
right: AUTO,
|
|
95
|
-
bottom: AUTO
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// Set align style
|
|
99
|
-
if (!isMobile && (ready || !open)) {
|
|
100
|
-
const {
|
|
101
|
-
points
|
|
102
|
-
} = align;
|
|
103
|
-
const dynamicInset = align.dynamicInset || align._experimental?.dynamicInset;
|
|
104
|
-
const alignRight = dynamicInset && points[0][1] === 'r';
|
|
105
|
-
const alignBottom = dynamicInset && points[0][0] === 'b';
|
|
106
|
-
if (alignRight) {
|
|
107
|
-
offsetStyle.right = offsetR;
|
|
108
|
-
offsetStyle.left = AUTO;
|
|
109
|
-
} else {
|
|
110
|
-
offsetStyle.left = offsetX;
|
|
111
|
-
offsetStyle.right = AUTO;
|
|
112
|
-
}
|
|
113
|
-
if (alignBottom) {
|
|
114
|
-
offsetStyle.bottom = offsetB;
|
|
115
|
-
offsetStyle.top = AUTO;
|
|
116
|
-
} else {
|
|
117
|
-
offsetStyle.top = offsetY;
|
|
118
|
-
offsetStyle.bottom = AUTO;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
103
|
// >>>>> Misc
|
|
123
104
|
const miscStyle = {};
|
|
124
105
|
if (stretch) {
|
|
@@ -148,7 +129,7 @@ const Popup = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
148
129
|
motion: mergedMaskMotion,
|
|
149
130
|
mobile: isMobile
|
|
150
131
|
}), /*#__PURE__*/React.createElement(ResizeObserver, {
|
|
151
|
-
onResize:
|
|
132
|
+
onResize: onInternalResize,
|
|
152
133
|
disabled: !open
|
|
153
134
|
}, resizeObserverRef => {
|
|
154
135
|
return /*#__PURE__*/React.createElement(CSSMotion, _extends({
|
|
@@ -198,9 +179,9 @@ const Popup = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
198
179
|
align: align
|
|
199
180
|
}), /*#__PURE__*/React.createElement(PopupContent, {
|
|
200
181
|
cache: !open && !fresh
|
|
201
|
-
},
|
|
182
|
+
}, popupContent));
|
|
202
183
|
});
|
|
203
|
-
}));
|
|
184
|
+
}), children);
|
|
204
185
|
});
|
|
205
186
|
if (process.env.NODE_ENV !== 'production') {
|
|
206
187
|
Popup.displayName = 'Popup';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { CSSMotionProps } from '@rc-component/motion';
|
|
3
|
+
import type { AlignType } from '../interface';
|
|
4
|
+
export interface FloatBgProps {
|
|
5
|
+
prefixCls: string;
|
|
6
|
+
isMobile: boolean;
|
|
7
|
+
ready: boolean;
|
|
8
|
+
open: boolean;
|
|
9
|
+
align: AlignType;
|
|
10
|
+
offsetR: number;
|
|
11
|
+
offsetB: number;
|
|
12
|
+
offsetX: number;
|
|
13
|
+
offsetY: number;
|
|
14
|
+
popupSize?: {
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
};
|
|
18
|
+
motion?: CSSMotionProps;
|
|
19
|
+
}
|
|
20
|
+
declare const FloatBg: (props: FloatBgProps) => React.JSX.Element;
|
|
21
|
+
export default FloatBg;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import useOffsetStyle from "../hooks/useOffsetStyle";
|
|
4
|
+
import classNames from 'classnames';
|
|
5
|
+
import CSSMotion from '@rc-component/motion';
|
|
6
|
+
const FloatBg = props => {
|
|
7
|
+
const {
|
|
8
|
+
prefixCls,
|
|
9
|
+
isMobile,
|
|
10
|
+
ready,
|
|
11
|
+
open,
|
|
12
|
+
align,
|
|
13
|
+
offsetR,
|
|
14
|
+
offsetB,
|
|
15
|
+
offsetX,
|
|
16
|
+
offsetY,
|
|
17
|
+
popupSize,
|
|
18
|
+
motion
|
|
19
|
+
} = props;
|
|
20
|
+
const floatBgCls = `${prefixCls}-float-bg`;
|
|
21
|
+
const [motionVisible, setMotionVisible] = React.useState(false);
|
|
22
|
+
|
|
23
|
+
// ========================= Styles =========================
|
|
24
|
+
const offsetStyle = useOffsetStyle(isMobile, ready, open, align, offsetR, offsetB, offsetX, offsetY);
|
|
25
|
+
|
|
26
|
+
// Apply popup size if available
|
|
27
|
+
const sizeStyle = {};
|
|
28
|
+
if (popupSize) {
|
|
29
|
+
sizeStyle.width = popupSize.width;
|
|
30
|
+
sizeStyle.height = popupSize.height;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ========================= Render =========================
|
|
34
|
+
return /*#__PURE__*/React.createElement(CSSMotion, _extends({
|
|
35
|
+
motionAppear: true,
|
|
36
|
+
motionEnter: true,
|
|
37
|
+
motionLeave: true,
|
|
38
|
+
removeOnLeave: false,
|
|
39
|
+
leavedClassName: `${floatBgCls}-hidden`
|
|
40
|
+
}, motion, {
|
|
41
|
+
visible: open,
|
|
42
|
+
onVisibleChanged: nextVisible => {
|
|
43
|
+
setMotionVisible(nextVisible);
|
|
44
|
+
}
|
|
45
|
+
}), ({
|
|
46
|
+
className: motionClassName,
|
|
47
|
+
style: motionStyle
|
|
48
|
+
}) => {
|
|
49
|
+
const cls = classNames(floatBgCls, motionClassName, {
|
|
50
|
+
[`${floatBgCls}-visible`]: motionVisible
|
|
51
|
+
});
|
|
52
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
53
|
+
className: cls,
|
|
54
|
+
style: {
|
|
55
|
+
...offsetStyle,
|
|
56
|
+
...sizeStyle,
|
|
57
|
+
...motionStyle
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
export default FloatBg;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { TriggerProps } from '..';
|
|
3
|
+
export interface MotionContentProps {
|
|
4
|
+
prefixCls: string;
|
|
5
|
+
children: TriggerProps['popup'];
|
|
6
|
+
}
|
|
7
|
+
declare const MotionContent: {
|
|
8
|
+
(props: MotionContentProps): React.JSX.Element;
|
|
9
|
+
displayName: string;
|
|
10
|
+
};
|
|
11
|
+
export default MotionContent;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import CSSMotion from '@rc-component/motion';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
const MotionContent = props => {
|
|
5
|
+
const {
|
|
6
|
+
prefixCls,
|
|
7
|
+
children
|
|
8
|
+
} = props;
|
|
9
|
+
const childNode = typeof children === 'function' ? children() : children;
|
|
10
|
+
|
|
11
|
+
// motion name: `${prefixCls}-motion-content-fade`, apply in index.less
|
|
12
|
+
const motionName = `${prefixCls}-motion-content-fade`;
|
|
13
|
+
return /*#__PURE__*/React.createElement(CSSMotion, {
|
|
14
|
+
motionAppear: true,
|
|
15
|
+
motionLeave: false,
|
|
16
|
+
visible: true,
|
|
17
|
+
motionName: motionName
|
|
18
|
+
}, ({
|
|
19
|
+
className: motionClassName,
|
|
20
|
+
style: motionStyle
|
|
21
|
+
}) => {
|
|
22
|
+
const cls = classNames(`${prefixCls}-motion-content`, motionClassName);
|
|
23
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
24
|
+
className: cls,
|
|
25
|
+
style: motionStyle
|
|
26
|
+
}, childNode);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
30
|
+
MotionContent.displayName = 'MotionContent';
|
|
31
|
+
}
|
|
32
|
+
export default MotionContent;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import Portal from '@rc-component/portal';
|
|
3
|
+
import TriggerContext, { UniqueContext } from "../context";
|
|
4
|
+
import useDelay from "../hooks/useDelay";
|
|
5
|
+
import useAlign from "../hooks/useAlign";
|
|
6
|
+
import Popup from "../Popup";
|
|
7
|
+
import { useEvent } from '@rc-component/util';
|
|
8
|
+
import useTargetState from "./useTargetState";
|
|
9
|
+
import { isDOM } from "@rc-component/util/es/Dom/findDOMNode";
|
|
10
|
+
import FloatBg from "./FloatBg";
|
|
11
|
+
import classNames from 'classnames';
|
|
12
|
+
import MotionContent from "./MotionContent";
|
|
13
|
+
const UniqueProvider = ({
|
|
14
|
+
children
|
|
15
|
+
}) => {
|
|
16
|
+
const [trigger, open, options, onTargetVisibleChanged] = useTargetState();
|
|
17
|
+
|
|
18
|
+
// =========================== Popup ============================
|
|
19
|
+
const [popupEle, setPopupEle] = React.useState(null);
|
|
20
|
+
const [popupSize, setPopupSize] = React.useState(null);
|
|
21
|
+
|
|
22
|
+
// Used for forwardRef popup. Not use internal
|
|
23
|
+
const externalPopupRef = React.useRef(null);
|
|
24
|
+
const setPopupRef = useEvent(node => {
|
|
25
|
+
externalPopupRef.current = node;
|
|
26
|
+
if (isDOM(node) && popupEle !== node) {
|
|
27
|
+
setPopupEle(node);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ========================== Register ==========================
|
|
32
|
+
const [popupId, setPopupId] = React.useState(0);
|
|
33
|
+
const delayInvoke = useDelay();
|
|
34
|
+
const show = useEvent(showOptions => {
|
|
35
|
+
delayInvoke(() => {
|
|
36
|
+
if (showOptions.id !== options?.id) {
|
|
37
|
+
setPopupId(i => i + 1);
|
|
38
|
+
}
|
|
39
|
+
trigger(showOptions);
|
|
40
|
+
}, showOptions.delay);
|
|
41
|
+
});
|
|
42
|
+
const hide = delay => {
|
|
43
|
+
delayInvoke(() => {
|
|
44
|
+
trigger(false);
|
|
45
|
+
// Don't clear target, currentNode, options immediately, wait until animation completes
|
|
46
|
+
}, delay);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Callback after animation completes
|
|
50
|
+
const onVisibleChanged = useEvent(visible => {
|
|
51
|
+
// Call useTargetState callback to handle animation state
|
|
52
|
+
onTargetVisibleChanged(visible);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// =========================== Align ============================
|
|
56
|
+
const [ready, offsetX, offsetY, offsetR, offsetB, arrowX, arrowY,
|
|
57
|
+
|
|
58
|
+
// scaleX - not used in UniqueProvider
|
|
59
|
+
,,
|
|
60
|
+
// scaleY - not used in UniqueProvider
|
|
61
|
+
alignInfo, onAlign] = useAlign(open, popupEle, options?.target, options?.popupPlacement, options?.builtinPlacements || {}, options?.popupAlign, undefined,
|
|
62
|
+
// onPopupAlign
|
|
63
|
+
false // isMobile
|
|
64
|
+
);
|
|
65
|
+
const contextValue = React.useMemo(() => ({
|
|
66
|
+
show,
|
|
67
|
+
hide
|
|
68
|
+
}), []);
|
|
69
|
+
|
|
70
|
+
// =========================== Motion ===========================
|
|
71
|
+
const onPrepare = useEvent(() => {
|
|
72
|
+
onAlign();
|
|
73
|
+
return Promise.resolve();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// ======================== Trigger Context =====================
|
|
77
|
+
const subPopupElements = React.useRef({});
|
|
78
|
+
const parentContext = React.useContext(TriggerContext);
|
|
79
|
+
const triggerContextValue = React.useMemo(() => ({
|
|
80
|
+
registerSubPopup: (id, subPopupEle) => {
|
|
81
|
+
subPopupElements.current[id] = subPopupEle;
|
|
82
|
+
parentContext?.registerSubPopup(id, subPopupEle);
|
|
83
|
+
}
|
|
84
|
+
}), [parentContext]);
|
|
85
|
+
|
|
86
|
+
// =========================== Render ===========================
|
|
87
|
+
const prefixCls = options?.prefixCls;
|
|
88
|
+
return /*#__PURE__*/React.createElement(UniqueContext.Provider, {
|
|
89
|
+
value: contextValue
|
|
90
|
+
}, children, options && /*#__PURE__*/React.createElement(TriggerContext.Provider, {
|
|
91
|
+
value: triggerContextValue
|
|
92
|
+
}, /*#__PURE__*/React.createElement(Popup, {
|
|
93
|
+
ref: setPopupRef,
|
|
94
|
+
portal: Portal,
|
|
95
|
+
prefixCls: prefixCls,
|
|
96
|
+
popup: /*#__PURE__*/React.createElement(MotionContent, {
|
|
97
|
+
prefixCls: prefixCls,
|
|
98
|
+
key: popupId
|
|
99
|
+
}, options.popup),
|
|
100
|
+
className: classNames(options.popupClassName, `${prefixCls}-unique-controlled`),
|
|
101
|
+
style: options.popupStyle,
|
|
102
|
+
target: options.target,
|
|
103
|
+
open: open,
|
|
104
|
+
keepDom: true,
|
|
105
|
+
fresh: true,
|
|
106
|
+
autoDestroy: false,
|
|
107
|
+
onVisibleChanged: onVisibleChanged,
|
|
108
|
+
ready: ready,
|
|
109
|
+
offsetX: offsetX,
|
|
110
|
+
offsetY: offsetY,
|
|
111
|
+
offsetR: offsetR,
|
|
112
|
+
offsetB: offsetB,
|
|
113
|
+
onAlign: onAlign,
|
|
114
|
+
onPrepare: onPrepare,
|
|
115
|
+
onResize: size => setPopupSize({
|
|
116
|
+
width: size.offsetWidth,
|
|
117
|
+
height: size.offsetHeight
|
|
118
|
+
}),
|
|
119
|
+
arrowPos: {
|
|
120
|
+
x: arrowX,
|
|
121
|
+
y: arrowY
|
|
122
|
+
},
|
|
123
|
+
align: alignInfo,
|
|
124
|
+
zIndex: options.zIndex,
|
|
125
|
+
mask: options.mask,
|
|
126
|
+
arrow: options.arrow,
|
|
127
|
+
motion: options.popupMotion,
|
|
128
|
+
maskMotion: options.maskMotion
|
|
129
|
+
// getPopupContainer={options.getPopupContainer}
|
|
130
|
+
}, /*#__PURE__*/React.createElement(FloatBg, {
|
|
131
|
+
prefixCls: prefixCls,
|
|
132
|
+
isMobile: false,
|
|
133
|
+
ready: ready,
|
|
134
|
+
open: open,
|
|
135
|
+
align: alignInfo,
|
|
136
|
+
offsetR: offsetR,
|
|
137
|
+
offsetB: offsetB,
|
|
138
|
+
offsetX: offsetX,
|
|
139
|
+
offsetY: offsetY,
|
|
140
|
+
popupSize: popupSize,
|
|
141
|
+
motion: options.popupMotion
|
|
142
|
+
}))));
|
|
143
|
+
};
|
|
144
|
+
export default UniqueProvider;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UniqueShowOptions } from '../context';
|
|
2
|
+
/**
|
|
3
|
+
* Control the state of popup bind target:
|
|
4
|
+
* 1. When set `target`. Do show the popup.
|
|
5
|
+
* 2. When `target` is removed. Do hide the popup.
|
|
6
|
+
* 3. When `target` change to another one:
|
|
7
|
+
* a. We wait motion finish of previous popup.
|
|
8
|
+
* b. Then we set new target and show the popup.
|
|
9
|
+
* 4. During appear/enter animation, cache new options and apply after animation completes.
|
|
10
|
+
*/
|
|
11
|
+
export default function useTargetState(): [
|
|
12
|
+
trigger: (options: UniqueShowOptions | false) => void,
|
|
13
|
+
open: boolean,
|
|
14
|
+
cacheOptions: UniqueShowOptions | null,
|
|
15
|
+
onVisibleChanged: (visible: boolean) => void
|
|
16
|
+
];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useEvent } from '@rc-component/util';
|
|
3
|
+
/**
|
|
4
|
+
* Control the state of popup bind target:
|
|
5
|
+
* 1. When set `target`. Do show the popup.
|
|
6
|
+
* 2. When `target` is removed. Do hide the popup.
|
|
7
|
+
* 3. When `target` change to another one:
|
|
8
|
+
* a. We wait motion finish of previous popup.
|
|
9
|
+
* b. Then we set new target and show the popup.
|
|
10
|
+
* 4. During appear/enter animation, cache new options and apply after animation completes.
|
|
11
|
+
*/
|
|
12
|
+
export default function useTargetState() {
|
|
13
|
+
const [options, setOptions] = React.useState(null);
|
|
14
|
+
const [open, setOpen] = React.useState(false);
|
|
15
|
+
const [isAnimating, setIsAnimating] = React.useState(false);
|
|
16
|
+
const pendingOptionsRef = React.useRef(null);
|
|
17
|
+
const trigger = useEvent(nextOptions => {
|
|
18
|
+
if (nextOptions === false) {
|
|
19
|
+
// Clear pending options when hiding
|
|
20
|
+
pendingOptionsRef.current = null;
|
|
21
|
+
setOpen(false);
|
|
22
|
+
} else {
|
|
23
|
+
if (isAnimating && open) {
|
|
24
|
+
// If animating (appear or enter), cache new options
|
|
25
|
+
pendingOptionsRef.current = nextOptions;
|
|
26
|
+
} else {
|
|
27
|
+
setOpen(true);
|
|
28
|
+
// Set new options
|
|
29
|
+
setOptions(nextOptions);
|
|
30
|
+
pendingOptionsRef.current = null;
|
|
31
|
+
|
|
32
|
+
// Only mark as animating when transitioning from closed to open
|
|
33
|
+
if (!open) {
|
|
34
|
+
setIsAnimating(true);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const onVisibleChanged = useEvent(visible => {
|
|
40
|
+
if (visible) {
|
|
41
|
+
// Animation enter completed, check if there are pending options
|
|
42
|
+
setIsAnimating(false);
|
|
43
|
+
if (pendingOptionsRef.current) {
|
|
44
|
+
// Apply pending options
|
|
45
|
+
setOptions(pendingOptionsRef.current);
|
|
46
|
+
pendingOptionsRef.current = null;
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
// Animation leave completed
|
|
50
|
+
setIsAnimating(false);
|
|
51
|
+
pendingOptionsRef.current = null;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return [trigger, open, options, onVisibleChanged];
|
|
55
|
+
}
|
package/es/context.d.ts
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { CSSMotionProps } from '@rc-component/motion';
|
|
3
|
+
import type { TriggerProps } from './index';
|
|
4
|
+
import type { AlignType, ArrowTypeOuter, BuildInPlacements } from './interface';
|
|
2
5
|
export interface TriggerContextProps {
|
|
3
6
|
registerSubPopup: (id: string, node: HTMLElement) => void;
|
|
4
7
|
}
|
|
5
8
|
declare const TriggerContext: React.Context<TriggerContextProps>;
|
|
6
9
|
export default TriggerContext;
|
|
10
|
+
export interface UniqueShowOptions {
|
|
11
|
+
id: string;
|
|
12
|
+
popup: TriggerProps['popup'];
|
|
13
|
+
target: HTMLElement;
|
|
14
|
+
delay: number;
|
|
15
|
+
prefixCls?: string;
|
|
16
|
+
popupClassName?: string;
|
|
17
|
+
popupStyle?: React.CSSProperties;
|
|
18
|
+
popupPlacement?: string;
|
|
19
|
+
builtinPlacements?: BuildInPlacements;
|
|
20
|
+
popupAlign?: AlignType;
|
|
21
|
+
zIndex?: number;
|
|
22
|
+
mask?: boolean;
|
|
23
|
+
maskClosable?: boolean;
|
|
24
|
+
popupMotion?: CSSMotionProps;
|
|
25
|
+
maskMotion?: CSSMotionProps;
|
|
26
|
+
arrow?: ArrowTypeOuter;
|
|
27
|
+
getPopupContainer?: TriggerProps['getPopupContainer'];
|
|
28
|
+
}
|
|
29
|
+
export interface UniqueContextProps {
|
|
30
|
+
show: (options: UniqueShowOptions) => void;
|
|
31
|
+
hide: (delay: number) => void;
|
|
32
|
+
}
|
|
33
|
+
export declare const UniqueContext: React.Context<UniqueContextProps>;
|
package/es/context.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
// ===================== Nest =====================
|
|
4
|
+
|
|
2
5
|
const TriggerContext = /*#__PURE__*/React.createContext(null);
|
|
3
|
-
export default TriggerContext;
|
|
6
|
+
export default TriggerContext;
|
|
7
|
+
|
|
8
|
+
// ==================== Unique ====================
|
|
9
|
+
|
|
10
|
+
export const UniqueContext = /*#__PURE__*/React.createContext(null);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function useDelay(): (callback: VoidFunction, delay: number) => void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export default function useDelay() {
|
|
3
|
+
const delayRef = React.useRef(null);
|
|
4
|
+
const clearDelay = () => {
|
|
5
|
+
if (delayRef.current) {
|
|
6
|
+
clearTimeout(delayRef.current);
|
|
7
|
+
delayRef.current = null;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const delayInvoke = (callback, delay) => {
|
|
11
|
+
clearDelay();
|
|
12
|
+
if (delay === 0) {
|
|
13
|
+
callback();
|
|
14
|
+
} else {
|
|
15
|
+
delayRef.current = setTimeout(() => {
|
|
16
|
+
callback();
|
|
17
|
+
}, delay * 1000);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Clean up on unmount
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
return () => {
|
|
24
|
+
clearDelay();
|
|
25
|
+
};
|
|
26
|
+
}, []);
|
|
27
|
+
return delayInvoke;
|
|
28
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { AlignType } from '../interface';
|
|
3
|
+
export default function useOffsetStyle(isMobile: boolean, ready: boolean, open: boolean, align: AlignType, offsetR: number, offsetB: number, offsetX: number, offsetY: number): React.CSSProperties;
|