@rc-component/select 1.2.6 → 1.2.7

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