@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.
Files changed (39) hide show
  1. package/assets/index.css +35 -0
  2. package/assets/index.less +48 -0
  3. package/es/Popup/index.d.ts +3 -0
  4. package/es/Popup/index.js +18 -37
  5. package/es/UniqueProvider/FloatBg.d.ts +21 -0
  6. package/es/UniqueProvider/FloatBg.js +62 -0
  7. package/es/UniqueProvider/MotionContent.d.ts +11 -0
  8. package/es/UniqueProvider/MotionContent.js +32 -0
  9. package/es/UniqueProvider/index.d.ts +6 -0
  10. package/es/UniqueProvider/index.js +144 -0
  11. package/es/UniqueProvider/useTargetState.d.ts +16 -0
  12. package/es/UniqueProvider/useTargetState.js +55 -0
  13. package/es/context.d.ts +27 -0
  14. package/es/context.js +8 -1
  15. package/es/hooks/useDelay.d.ts +1 -0
  16. package/es/hooks/useDelay.js +28 -0
  17. package/es/hooks/useOffsetStyle.d.ts +3 -0
  18. package/es/hooks/useOffsetStyle.js +35 -0
  19. package/es/index.d.ts +5 -0
  20. package/es/index.js +73 -18
  21. package/lib/Popup/index.d.ts +3 -0
  22. package/lib/Popup/index.js +18 -37
  23. package/lib/UniqueProvider/FloatBg.d.ts +21 -0
  24. package/lib/UniqueProvider/FloatBg.js +69 -0
  25. package/lib/UniqueProvider/MotionContent.d.ts +11 -0
  26. package/lib/UniqueProvider/MotionContent.js +41 -0
  27. package/lib/UniqueProvider/index.d.ts +6 -0
  28. package/lib/UniqueProvider/index.js +153 -0
  29. package/lib/UniqueProvider/useTargetState.d.ts +16 -0
  30. package/lib/UniqueProvider/useTargetState.js +62 -0
  31. package/lib/context.d.ts +27 -0
  32. package/lib/context.js +5 -2
  33. package/lib/hooks/useDelay.d.ts +1 -0
  34. package/lib/hooks/useDelay.js +36 -0
  35. package/lib/hooks/useOffsetStyle.d.ts +3 -0
  36. package/lib/hooks/useOffsetStyle.js +41 -0
  37. package/lib/index.d.ts +5 -0
  38. package/lib/index.js +79 -18
  39. package/package.json +1 -1
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = useTargetState;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _util = require("@rc-component/util");
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ /**
11
+ * Control the state of popup bind target:
12
+ * 1. When set `target`. Do show the popup.
13
+ * 2. When `target` is removed. Do hide the popup.
14
+ * 3. When `target` change to another one:
15
+ * a. We wait motion finish of previous popup.
16
+ * b. Then we set new target and show the popup.
17
+ * 4. During appear/enter animation, cache new options and apply after animation completes.
18
+ */
19
+ function useTargetState() {
20
+ const [options, setOptions] = _react.default.useState(null);
21
+ const [open, setOpen] = _react.default.useState(false);
22
+ const [isAnimating, setIsAnimating] = _react.default.useState(false);
23
+ const pendingOptionsRef = _react.default.useRef(null);
24
+ const trigger = (0, _util.useEvent)(nextOptions => {
25
+ if (nextOptions === false) {
26
+ // Clear pending options when hiding
27
+ pendingOptionsRef.current = null;
28
+ setOpen(false);
29
+ } else {
30
+ if (isAnimating && open) {
31
+ // If animating (appear or enter), cache new options
32
+ pendingOptionsRef.current = nextOptions;
33
+ } else {
34
+ setOpen(true);
35
+ // Set new options
36
+ setOptions(nextOptions);
37
+ pendingOptionsRef.current = null;
38
+
39
+ // Only mark as animating when transitioning from closed to open
40
+ if (!open) {
41
+ setIsAnimating(true);
42
+ }
43
+ }
44
+ }
45
+ });
46
+ const onVisibleChanged = (0, _util.useEvent)(visible => {
47
+ if (visible) {
48
+ // Animation enter completed, check if there are pending options
49
+ setIsAnimating(false);
50
+ if (pendingOptionsRef.current) {
51
+ // Apply pending options
52
+ setOptions(pendingOptionsRef.current);
53
+ pendingOptionsRef.current = null;
54
+ }
55
+ } else {
56
+ // Animation leave completed
57
+ setIsAnimating(false);
58
+ pendingOptionsRef.current = null;
59
+ }
60
+ });
61
+ return [trigger, open, options, onVisibleChanged];
62
+ }
package/lib/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/lib/context.js CHANGED
@@ -3,9 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.default = exports.UniqueContext = void 0;
7
7
  var React = _interopRequireWildcard(require("react"));
8
8
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
9
9
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
10
+ // ===================== Nest =====================
11
+
10
12
  const TriggerContext = /*#__PURE__*/React.createContext(null);
11
- var _default = exports.default = TriggerContext;
13
+ var _default = exports.default = TriggerContext; // ==================== Unique ====================
14
+ const UniqueContext = exports.UniqueContext = /*#__PURE__*/React.createContext(null);
@@ -0,0 +1 @@
1
+ export default function useDelay(): (callback: VoidFunction, delay: number) => void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = useDelay;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
9
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
10
+ function useDelay() {
11
+ const delayRef = React.useRef(null);
12
+ const clearDelay = () => {
13
+ if (delayRef.current) {
14
+ clearTimeout(delayRef.current);
15
+ delayRef.current = null;
16
+ }
17
+ };
18
+ const delayInvoke = (callback, delay) => {
19
+ clearDelay();
20
+ if (delay === 0) {
21
+ callback();
22
+ } else {
23
+ delayRef.current = setTimeout(() => {
24
+ callback();
25
+ }, delay * 1000);
26
+ }
27
+ };
28
+
29
+ // Clean up on unmount
30
+ React.useEffect(() => {
31
+ return () => {
32
+ clearDelay();
33
+ };
34
+ }, []);
35
+ return delayInvoke;
36
+ }
@@ -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;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = useOffsetStyle;
7
+ function useOffsetStyle(isMobile, ready, open, align, offsetR, offsetB, offsetX, offsetY) {
8
+ // >>>>> Offset
9
+ const AUTO = 'auto';
10
+ const offsetStyle = isMobile ? {} : {
11
+ left: '-1000vw',
12
+ top: '-1000vh',
13
+ right: AUTO,
14
+ bottom: AUTO
15
+ };
16
+
17
+ // Set align style
18
+ if (!isMobile && (ready || !open)) {
19
+ const {
20
+ points
21
+ } = align;
22
+ const dynamicInset = align.dynamicInset || align._experimental?.dynamicInset;
23
+ const alignRight = dynamicInset && points[0][1] === 'r';
24
+ const alignBottom = dynamicInset && points[0][0] === 'b';
25
+ if (alignRight) {
26
+ offsetStyle.right = offsetR;
27
+ offsetStyle.left = AUTO;
28
+ } else {
29
+ offsetStyle.left = offsetX;
30
+ offsetStyle.right = AUTO;
31
+ }
32
+ if (alignBottom) {
33
+ offsetStyle.bottom = offsetB;
34
+ offsetStyle.top = AUTO;
35
+ } else {
36
+ offsetStyle.top = offsetY;
37
+ offsetStyle.bottom = AUTO;
38
+ }
39
+ }
40
+ return offsetStyle;
41
+ }
package/lib/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import * as React from 'react';
3
3
  import { type MobileConfig } from './Popup';
4
4
  import type { ActionType, AlignType, ArrowTypeOuter, BuildInPlacements } from './interface';
5
5
  export type { ActionType, AlignType, ArrowTypeOuter as ArrowType, BuildInPlacements, };
6
+ export { default as UniqueProvider } from './UniqueProvider';
6
7
  export interface TriggerRef {
7
8
  nativeElement: HTMLElement;
8
9
  popupElement: HTMLDivElement;
@@ -53,6 +54,10 @@ export interface TriggerProps {
53
54
  * Set `fresh` to `false` will always keep update.
54
55
  */
55
56
  fresh?: boolean;
57
+ /**
58
+ * Config with UniqueProvider to shared the floating popup.
59
+ */
60
+ unique?: boolean;
56
61
  arrow?: boolean | ArrowTypeOuter;
57
62
  /**
58
63
  * @private Bump fixed position at bottom in mobile.
package/lib/index.js CHANGED
@@ -3,6 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ Object.defineProperty(exports, "UniqueProvider", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _UniqueProvider.default;
10
+ }
11
+ });
6
12
  exports.default = void 0;
7
13
  exports.generateTrigger = generateTrigger;
8
14
  var _portal = _interopRequireDefault(require("@rc-component/portal"));
@@ -15,12 +21,14 @@ var _useId = _interopRequireDefault(require("@rc-component/util/lib/hooks/useId"
15
21
  var _useLayoutEffect = _interopRequireDefault(require("@rc-component/util/lib/hooks/useLayoutEffect"));
16
22
  var React = _interopRequireWildcard(require("react"));
17
23
  var _Popup = _interopRequireDefault(require("./Popup"));
18
- var _context = _interopRequireDefault(require("./context"));
24
+ var _context = _interopRequireWildcard(require("./context"));
19
25
  var _useAction = _interopRequireDefault(require("./hooks/useAction"));
20
26
  var _useAlign = _interopRequireDefault(require("./hooks/useAlign"));
27
+ var _useDelay = _interopRequireDefault(require("./hooks/useDelay"));
21
28
  var _useWatch = _interopRequireDefault(require("./hooks/useWatch"));
22
29
  var _useWinClick = _interopRequireDefault(require("./hooks/useWinClick"));
23
30
  var _util = require("./util");
31
+ var _UniqueProvider = _interopRequireDefault(require("./UniqueProvider"));
24
32
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
25
33
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
26
34
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -69,6 +77,7 @@ function generateTrigger(PortalComponent = _portal.default) {
69
77
  stretch,
70
78
  getPopupClassNameFromAlign,
71
79
  fresh,
80
+ unique,
72
81
  alignPoint,
73
82
  onPopupClick,
74
83
  onPopupAlign,
@@ -82,6 +91,7 @@ function generateTrigger(PortalComponent = _portal.default) {
82
91
  ...restProps
83
92
  } = props;
84
93
  const mergedAutoDestroy = autoDestroy || false;
94
+ const openUncontrolled = popupVisible === undefined;
85
95
 
86
96
  // =========================== Mobile ===========================
87
97
  const isMobile = !!mobile;
@@ -98,6 +108,9 @@ function generateTrigger(PortalComponent = _portal.default) {
98
108
  };
99
109
  }, [parentContext]);
100
110
 
111
+ // ======================== UniqueContext =========================
112
+ const uniqueContext = React.useContext(_context.UniqueContext);
113
+
101
114
  // =========================== Popup ============================
102
115
  const id = (0, _useId.default)();
103
116
  const [popupEle, setPopupEle] = React.useState(null);
@@ -134,6 +147,12 @@ function generateTrigger(PortalComponent = _portal.default) {
134
147
  return childDOM?.contains(ele) || (0, _shadow.getShadowRoot)(childDOM)?.host === ele || ele === childDOM || popupEle?.contains(ele) || (0, _shadow.getShadowRoot)(popupEle)?.host === ele || ele === popupEle || Object.values(subPopupElements.current).some(subPopupEle => subPopupEle?.contains(ele) || ele === subPopupEle);
135
148
  });
136
149
 
150
+ // =========================== Arrow ============================
151
+ const innerArrow = arrow ? {
152
+ // true and Object likely
153
+ ...(arrow !== true ? arrow : {})
154
+ } : null;
155
+
137
156
  // ============================ Open ============================
138
157
  const [internalOpen, setInternalOpen] = React.useState(defaultPopupVisible || false);
139
158
 
@@ -142,13 +161,49 @@ function generateTrigger(PortalComponent = _portal.default) {
142
161
 
143
162
  // We use effect sync here in case `popupVisible` back to `undefined`
144
163
  const setMergedOpen = (0, _useEvent.default)(nextOpen => {
145
- if (popupVisible === undefined) {
164
+ if (openUncontrolled) {
146
165
  setInternalOpen(nextOpen);
147
166
  }
148
167
  });
149
168
  (0, _useLayoutEffect.default)(() => {
150
169
  setInternalOpen(popupVisible || false);
151
170
  }, [popupVisible]);
171
+
172
+ // Extract common options for UniqueProvider
173
+ const getUniqueOptions = (0, _useEvent.default)((delay = 0) => ({
174
+ popup,
175
+ target: targetEle,
176
+ delay,
177
+ prefixCls,
178
+ popupClassName,
179
+ popupStyle,
180
+ popupPlacement,
181
+ builtinPlacements,
182
+ popupAlign,
183
+ zIndex,
184
+ mask,
185
+ maskClosable,
186
+ popupMotion,
187
+ maskMotion,
188
+ arrow: innerArrow,
189
+ getPopupContainer,
190
+ id
191
+ }));
192
+
193
+ // Handle controlled state changes for UniqueProvider
194
+ // Only sync to UniqueProvider when it's controlled mode
195
+ // If there is a parentContext, don't call uniqueContext methods
196
+ (0, _useLayoutEffect.default)(() => {
197
+ if (uniqueContext && unique && targetEle && !openUncontrolled && !parentContext) {
198
+ if (mergedOpen) {
199
+ Promise.resolve().then(() => {
200
+ uniqueContext.show(getUniqueOptions(0));
201
+ });
202
+ } else {
203
+ uniqueContext.hide(0);
204
+ }
205
+ }
206
+ }, [mergedOpen, targetEle]);
152
207
  const openRef = React.useRef(mergedOpen);
153
208
  openRef.current = mergedOpen;
154
209
  const lastTriggerRef = React.useRef([]);
@@ -167,21 +222,31 @@ function generateTrigger(PortalComponent = _portal.default) {
167
222
  });
168
223
 
169
224
  // Trigger for delay
170
- const delayRef = React.useRef(null);
171
- const clearDelay = () => {
172
- clearTimeout(delayRef.current);
173
- };
225
+ const delayInvoke = (0, _useDelay.default)();
174
226
  const triggerOpen = (nextOpen, delay = 0) => {
175
- clearDelay();
176
- if (delay === 0) {
177
- internalTriggerOpen(nextOpen);
178
- } else {
179
- delayRef.current = setTimeout(() => {
227
+ // If it's controlled mode, always use internal trigger logic
228
+ // UniqueProvider will be synced through useLayoutEffect
229
+ if (popupVisible !== undefined) {
230
+ delayInvoke(() => {
180
231
  internalTriggerOpen(nextOpen);
181
- }, delay * 1000);
232
+ }, delay);
233
+ return;
182
234
  }
235
+
236
+ // If UniqueContext exists and not controlled, pass delay to Provider instead of handling it internally
237
+ // If there is a parentContext, don't call uniqueContext methods
238
+ if (uniqueContext && unique && openUncontrolled && !parentContext) {
239
+ if (nextOpen) {
240
+ uniqueContext.show(getUniqueOptions(delay));
241
+ } else {
242
+ uniqueContext.hide(delay);
243
+ }
244
+ return;
245
+ }
246
+ delayInvoke(() => {
247
+ internalTriggerOpen(nextOpen);
248
+ }, delay);
183
249
  };
184
- React.useEffect(() => clearDelay, []);
185
250
 
186
251
  // ========================== Motion ============================
187
252
  const [inMotion, setInMotion] = React.useState(false);
@@ -417,10 +482,6 @@ function generateTrigger(PortalComponent = _portal.default) {
417
482
  x: arrowX,
418
483
  y: arrowY
419
484
  };
420
- const innerArrow = arrow ? {
421
- // true and Object likely
422
- ...(arrow !== true ? arrow : {})
423
- } : null;
424
485
 
425
486
  // Child Node
426
487
  const triggerNode = /*#__PURE__*/React.cloneElement(child, {
@@ -433,7 +494,7 @@ function generateTrigger(PortalComponent = _portal.default) {
433
494
  disabled: !mergedOpen,
434
495
  ref: setTargetRef,
435
496
  onResize: onTargetResize
436
- }, triggerNode), rendedRef.current && /*#__PURE__*/React.createElement(_context.default.Provider, {
497
+ }, triggerNode), rendedRef.current && (!uniqueContext || !unique) && /*#__PURE__*/React.createElement(_context.default.Provider, {
437
498
  value: context
438
499
  }, /*#__PURE__*/React.createElement(_Popup.default, {
439
500
  portal: PortalComponent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rc-component/trigger",
3
- "version": "3.5.2",
3
+ "version": "3.6.1",
4
4
  "description": "base abstract trigger component for react",
5
5
  "engines": {
6
6
  "node": ">=8.x"