@rc-component/select 1.3.2 → 1.3.3

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.
@@ -9,7 +9,7 @@ import useSelectTriggerControl, { isInside } from "../hooks/useSelectTriggerCont
9
9
  import SelectTrigger from "../SelectTrigger";
10
10
  import { getSeparatedContent, isValidCount } from "../utils/valueUtil";
11
11
  import Polite from "./Polite";
12
- import useOpen, { macroTask } from "../hooks/useOpen";
12
+ import useOpen from "../hooks/useOpen";
13
13
  import { useEvent } from '@rc-component/util';
14
14
  import SelectInput from "../SelectInput";
15
15
  import useComponents from "../hooks/useComponents";
@@ -309,11 +309,12 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
309
309
  }
310
310
  };
311
311
  const onRootBlur = () => {
312
- macroTask(() => {
313
- if (!isInside(getSelectElements(), document.activeElement)) {
314
- triggerOpen(false);
315
- }
316
- });
312
+ // Delay close should check the activeElement
313
+ if (mergedOpen) {
314
+ triggerOpen(false, {
315
+ cancelFun: () => isInside(getSelectElements(), document.activeElement)
316
+ });
317
+ }
317
318
  };
318
319
  const onInternalBlur = event => {
319
320
  setFocused(false);
@@ -335,7 +336,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
335
336
  onBlur?.(event);
336
337
  }
337
338
  };
338
- const onInternalMouseDown = (event, ...restArgs) => {
339
+ const onRootMouseDown = (event, ...restArgs) => {
339
340
  const {
340
341
  target
341
342
  } = event;
@@ -344,9 +345,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
344
345
  // We should give focus back to selector if clicked item is not focusable
345
346
  if (popupElement?.contains(target) && triggerOpen) {
346
347
  // Tell `open` not to close since it's safe in the popup
347
- triggerOpen(true, {
348
- ignoreNext: true
349
- });
348
+ triggerOpen(true);
350
349
  }
351
350
  onMouseDown?.(event, ...restArgs);
352
351
  };
@@ -474,7 +473,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
474
473
  tokenWithEnter: tokenWithEnter
475
474
  // Open
476
475
  ,
477
- onMouseDown: onInternalMouseDown
476
+ onMouseDown: onRootMouseDown
478
477
  // Components
479
478
  ,
480
479
  components: mergedComponents
@@ -499,7 +498,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
499
498
  empty: emptyOptions,
500
499
  onPopupVisibleChange: onTriggerVisibleChange,
501
500
  onPopupMouseEnter: onPopupMouseEnter,
502
- onPopupMouseDown: onInternalMouseDown,
501
+ onPopupMouseDown: onRootMouseDown,
503
502
  onPopupBlur: onRootBlur
504
503
  }, renderNode);
505
504
  return /*#__PURE__*/React.createElement(BaseSelectContext.Provider, {
@@ -105,12 +105,13 @@ export default /*#__PURE__*/React.forwardRef(function SelectInput(props, ref) {
105
105
  // ====================== Open ======================
106
106
  const onInternalMouseDown = useEvent(event => {
107
107
  if (!disabled) {
108
+ const inputDOM = getDOM(inputRef.current);
109
+
108
110
  // https://github.com/ant-design/ant-design/issues/56002
109
111
  // Tell `useSelectTriggerControl` to ignore this event
110
112
  // When icon is dynamic render, the parentNode will miss
111
113
  // so we need to mark the event directly
112
- event.nativeEvent._ignore_global_close = true;
113
- const inputDOM = getDOM(inputRef.current);
114
+ event.nativeEvent._ori_target = inputDOM;
114
115
  if (inputDOM && event.target !== inputDOM && !inputDOM.contains(event.target)) {
115
116
  event.preventDefault();
116
117
  }
@@ -1,11 +1,10 @@
1
1
  export declare const macroTask: (fn: VoidFunction, times?: number) => void;
2
2
  /**
3
3
  * Trigger by latest open call, if nextOpen is undefined, means toggle.
4
- * ignoreNext will skip next call in the macro task queue.
4
+ * `weak` means this call can be ignored if previous call exists.
5
5
  */
6
6
  export type TriggerOpenType = (nextOpen?: boolean, config?: {
7
- ignoreNext?: boolean;
8
- lazy?: boolean;
7
+ cancelFun?: () => boolean;
9
8
  }) => void;
10
9
  /**
11
10
  * When `open` is controlled, follow the controlled value;
@@ -17,7 +17,7 @@ export const macroTask = (fn, times = 1) => {
17
17
 
18
18
  /**
19
19
  * Trigger by latest open call, if nextOpen is undefined, means toggle.
20
- * ignoreNext will skip next call in the macro task queue.
20
+ * `weak` means this call can be ignored if previous call exists.
21
21
  */
22
22
 
23
23
  /**
@@ -41,7 +41,6 @@ export default function useOpen(propOpen, onOpen, postOpen) {
41
41
  const ssrSafeOpen = rendered ? stateOpen : false;
42
42
  const mergedOpen = postOpen(ssrSafeOpen);
43
43
  const taskIdRef = useRef(0);
44
- const taskLockRef = useRef(false);
45
44
  const triggerEvent = useEvent(nextOpen => {
46
45
  if (onOpen && mergedOpen !== nextOpen) {
47
46
  onOpen(nextOpen);
@@ -50,32 +49,29 @@ export default function useOpen(propOpen, onOpen, postOpen) {
50
49
  });
51
50
  const toggleOpen = useEvent((nextOpen, config = {}) => {
52
51
  const {
53
- ignoreNext = false
52
+ cancelFun
54
53
  } = config;
55
54
  taskIdRef.current += 1;
56
55
  const id = taskIdRef.current;
57
56
  const nextOpenVal = typeof nextOpen === 'boolean' ? nextOpen : !mergedOpen;
58
-
59
- // Since `mergedOpen` is post-processed, we need to check if the value really changed
60
- if (nextOpenVal) {
61
- if (!taskLockRef.current) {
57
+ function triggerUpdate() {
58
+ if (
59
+ // Always check if id is match
60
+ id === taskIdRef.current &&
61
+ // Check if need to cancel
62
+ !cancelFun?.()) {
62
63
  triggerEvent(nextOpenVal);
63
-
64
- // Lock if needed
65
- if (ignoreNext) {
66
- taskLockRef.current = ignoreNext;
67
- macroTask(() => {
68
- taskLockRef.current = false;
69
- }, 3);
70
- }
71
64
  }
72
- return;
73
65
  }
74
- macroTask(() => {
75
- if (id === taskIdRef.current && !taskLockRef.current) {
76
- triggerEvent(nextOpenVal);
77
- }
78
- });
66
+
67
+ // Weak update can be ignored
68
+ if (nextOpenVal) {
69
+ triggerUpdate();
70
+ } else {
71
+ macroTask(() => {
72
+ triggerUpdate();
73
+ });
74
+ }
79
75
  });
80
76
  return [mergedOpen, toggleOpen];
81
77
  }
@@ -1,2 +1,3 @@
1
+ import type { TriggerOpenType } from './useOpen';
1
2
  export declare function isInside(elements: (HTMLElement | SVGElement | undefined)[], target: HTMLElement): boolean;
2
- export default function useSelectTriggerControl(elements: () => (HTMLElement | SVGElement | undefined)[], open: boolean, triggerOpen: (open: boolean) => void, customizedTrigger: boolean): void;
3
+ export default function useSelectTriggerControl(elements: () => (HTMLElement | SVGElement | undefined)[], open: boolean, triggerOpen: TriggerOpenType, customizedTrigger: boolean): void;
@@ -13,9 +13,12 @@ export default function useSelectTriggerControl(elements, open, triggerOpen, cus
13
13
  if (target.shadowRoot && event.composed) {
14
14
  target = event.composedPath()[0] || target;
15
15
  }
16
+ if (event._ori_target) {
17
+ target = event._ori_target;
18
+ }
16
19
  if (open &&
17
20
  // Marked by SelectInput mouseDown event
18
- !event._ignore_global_close && !isInside(elements(), target)) {
21
+ !isInside(elements(), target)) {
19
22
  // Should trigger close
20
23
  triggerOpen(false);
21
24
  }
@@ -14,7 +14,7 @@ var _useSelectTriggerControl = _interopRequireWildcard(require("../hooks/useSele
14
14
  var _SelectTrigger = _interopRequireDefault(require("../SelectTrigger"));
15
15
  var _valueUtil = require("../utils/valueUtil");
16
16
  var _Polite = _interopRequireDefault(require("./Polite"));
17
- var _useOpen = _interopRequireWildcard(require("../hooks/useOpen"));
17
+ var _useOpen = _interopRequireDefault(require("../hooks/useOpen"));
18
18
  var _util = require("@rc-component/util");
19
19
  var _SelectInput = _interopRequireDefault(require("../SelectInput"));
20
20
  var _useComponents = _interopRequireDefault(require("../hooks/useComponents"));
@@ -318,11 +318,12 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
318
318
  }
319
319
  };
320
320
  const onRootBlur = () => {
321
- (0, _useOpen.macroTask)(() => {
322
- if (!(0, _useSelectTriggerControl.isInside)(getSelectElements(), document.activeElement)) {
323
- triggerOpen(false);
324
- }
325
- });
321
+ // Delay close should check the activeElement
322
+ if (mergedOpen) {
323
+ triggerOpen(false, {
324
+ cancelFun: () => (0, _useSelectTriggerControl.isInside)(getSelectElements(), document.activeElement)
325
+ });
326
+ }
326
327
  };
327
328
  const onInternalBlur = event => {
328
329
  setFocused(false);
@@ -344,7 +345,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
344
345
  onBlur?.(event);
345
346
  }
346
347
  };
347
- const onInternalMouseDown = (event, ...restArgs) => {
348
+ const onRootMouseDown = (event, ...restArgs) => {
348
349
  const {
349
350
  target
350
351
  } = event;
@@ -353,9 +354,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
353
354
  // We should give focus back to selector if clicked item is not focusable
354
355
  if (popupElement?.contains(target) && triggerOpen) {
355
356
  // Tell `open` not to close since it's safe in the popup
356
- triggerOpen(true, {
357
- ignoreNext: true
358
- });
357
+ triggerOpen(true);
359
358
  }
360
359
  onMouseDown?.(event, ...restArgs);
361
360
  };
@@ -483,7 +482,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
483
482
  tokenWithEnter: tokenWithEnter
484
483
  // Open
485
484
  ,
486
- onMouseDown: onInternalMouseDown
485
+ onMouseDown: onRootMouseDown
487
486
  // Components
488
487
  ,
489
488
  components: mergedComponents
@@ -508,7 +507,7 @@ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
508
507
  empty: emptyOptions,
509
508
  onPopupVisibleChange: onTriggerVisibleChange,
510
509
  onPopupMouseEnter: onPopupMouseEnter,
511
- onPopupMouseDown: onInternalMouseDown,
510
+ onPopupMouseDown: onRootMouseDown,
512
511
  onPopupBlur: onRootBlur
513
512
  }, renderNode);
514
513
  return /*#__PURE__*/React.createElement(_useBaseProps.BaseSelectContext.Provider, {
@@ -114,12 +114,13 @@ var _default = exports.default = /*#__PURE__*/React.forwardRef(function SelectIn
114
114
  // ====================== Open ======================
115
115
  const onInternalMouseDown = (0, _util.useEvent)(event => {
116
116
  if (!disabled) {
117
+ const inputDOM = (0, _findDOMNode.getDOM)(inputRef.current);
118
+
117
119
  // https://github.com/ant-design/ant-design/issues/56002
118
120
  // Tell `useSelectTriggerControl` to ignore this event
119
121
  // When icon is dynamic render, the parentNode will miss
120
122
  // so we need to mark the event directly
121
- event.nativeEvent._ignore_global_close = true;
122
- const inputDOM = (0, _findDOMNode.getDOM)(inputRef.current);
123
+ event.nativeEvent._ori_target = inputDOM;
123
124
  if (inputDOM && event.target !== inputDOM && !inputDOM.contains(event.target)) {
124
125
  event.preventDefault();
125
126
  }
@@ -1,11 +1,10 @@
1
1
  export declare const macroTask: (fn: VoidFunction, times?: number) => void;
2
2
  /**
3
3
  * Trigger by latest open call, if nextOpen is undefined, means toggle.
4
- * ignoreNext will skip next call in the macro task queue.
4
+ * `weak` means this call can be ignored if previous call exists.
5
5
  */
6
6
  export type TriggerOpenType = (nextOpen?: boolean, config?: {
7
- ignoreNext?: boolean;
8
- lazy?: boolean;
7
+ cancelFun?: () => boolean;
9
8
  }) => void;
10
9
  /**
11
10
  * When `open` is controlled, follow the controlled value;
@@ -24,7 +24,7 @@ const macroTask = (fn, times = 1) => {
24
24
 
25
25
  /**
26
26
  * Trigger by latest open call, if nextOpen is undefined, means toggle.
27
- * ignoreNext will skip next call in the macro task queue.
27
+ * `weak` means this call can be ignored if previous call exists.
28
28
  */
29
29
  exports.macroTask = macroTask;
30
30
  /**
@@ -48,7 +48,6 @@ function useOpen(propOpen, onOpen, postOpen) {
48
48
  const ssrSafeOpen = rendered ? stateOpen : false;
49
49
  const mergedOpen = postOpen(ssrSafeOpen);
50
50
  const taskIdRef = (0, _react.useRef)(0);
51
- const taskLockRef = (0, _react.useRef)(false);
52
51
  const triggerEvent = (0, _util.useEvent)(nextOpen => {
53
52
  if (onOpen && mergedOpen !== nextOpen) {
54
53
  onOpen(nextOpen);
@@ -57,32 +56,29 @@ function useOpen(propOpen, onOpen, postOpen) {
57
56
  });
58
57
  const toggleOpen = (0, _util.useEvent)((nextOpen, config = {}) => {
59
58
  const {
60
- ignoreNext = false
59
+ cancelFun
61
60
  } = config;
62
61
  taskIdRef.current += 1;
63
62
  const id = taskIdRef.current;
64
63
  const nextOpenVal = typeof nextOpen === 'boolean' ? nextOpen : !mergedOpen;
65
-
66
- // Since `mergedOpen` is post-processed, we need to check if the value really changed
67
- if (nextOpenVal) {
68
- if (!taskLockRef.current) {
64
+ function triggerUpdate() {
65
+ if (
66
+ // Always check if id is match
67
+ id === taskIdRef.current &&
68
+ // Check if need to cancel
69
+ !cancelFun?.()) {
69
70
  triggerEvent(nextOpenVal);
70
-
71
- // Lock if needed
72
- if (ignoreNext) {
73
- taskLockRef.current = ignoreNext;
74
- macroTask(() => {
75
- taskLockRef.current = false;
76
- }, 3);
77
- }
78
71
  }
79
- return;
80
72
  }
81
- macroTask(() => {
82
- if (id === taskIdRef.current && !taskLockRef.current) {
83
- triggerEvent(nextOpenVal);
84
- }
85
- });
73
+
74
+ // Weak update can be ignored
75
+ if (nextOpenVal) {
76
+ triggerUpdate();
77
+ } else {
78
+ macroTask(() => {
79
+ triggerUpdate();
80
+ });
81
+ }
86
82
  });
87
83
  return [mergedOpen, toggleOpen];
88
84
  }
@@ -1,2 +1,3 @@
1
+ import type { TriggerOpenType } from './useOpen';
1
2
  export declare function isInside(elements: (HTMLElement | SVGElement | undefined)[], target: HTMLElement): boolean;
2
- export default function useSelectTriggerControl(elements: () => (HTMLElement | SVGElement | undefined)[], open: boolean, triggerOpen: (open: boolean) => void, customizedTrigger: boolean): void;
3
+ export default function useSelectTriggerControl(elements: () => (HTMLElement | SVGElement | undefined)[], open: boolean, triggerOpen: TriggerOpenType, customizedTrigger: boolean): void;
@@ -22,9 +22,12 @@ function useSelectTriggerControl(elements, open, triggerOpen, customizedTrigger)
22
22
  if (target.shadowRoot && event.composed) {
23
23
  target = event.composedPath()[0] || target;
24
24
  }
25
+ if (event._ori_target) {
26
+ target = event._ori_target;
27
+ }
25
28
  if (open &&
26
29
  // Marked by SelectInput mouseDown event
27
- !event._ignore_global_close && !isInside(elements(), target)) {
30
+ !isInside(elements(), target)) {
28
31
  // Should trigger close
29
32
  triggerOpen(false);
30
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rc-component/select",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "React Select",
5
5
  "engines": {
6
6
  "node": ">=8.x"