@v-c/select 1.0.7 → 1.0.9

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.
@@ -115,7 +115,7 @@ const BaseSelect = /* @__PURE__ */ (0, vue.defineComponent)((props, { expose, at
115
115
  return props.notFoundContent ?? "Not Found";
116
116
  });
117
117
  const emptyListContent = (0, vue.computed)(() => !props?.notFoundContent && props.emptyOptions);
118
- const [mergedOpen, triggerOpen] = require_useOpen.default(open, (openVal) => {
118
+ const [mergedOpen, triggerOpen, lockOptions] = require_useOpen.default(open, (openVal) => {
119
119
  props.onPopupVisibleChange?.(openVal);
120
120
  }, (nextOpen) => {
121
121
  return props.disabled || emptyListContent.value ? false : nextOpen;
@@ -202,6 +202,9 @@ const BaseSelect = /* @__PURE__ */ (0, vue.defineComponent)((props, { expose, at
202
202
  const onInputBlur = () => {
203
203
  keyLockRef.value = false;
204
204
  };
205
+ const getSelectElements = () => [(0, _v_c_util_dist_Dom_findDOMNode.getDOM)(containerRef), triggerRef.value?.getPopupElement?.()];
206
+ require_useSelectTriggerControl.default(getSelectElements, mergedOpen, triggerOpen, (0, vue.computed)(() => !!mergedComponents.value.root));
207
+ const internalMouseDownRef = (0, vue.shallowRef)(false);
205
208
  const onInternalFocus = (event) => {
206
209
  focused.value = true;
207
210
  if (!disabled.value) {
@@ -209,27 +212,31 @@ const BaseSelect = /* @__PURE__ */ (0, vue.defineComponent)((props, { expose, at
209
212
  props?.onFocus?.(event);
210
213
  }
211
214
  };
215
+ const onRootBlur = () => {
216
+ if (mergedOpen.value && !internalMouseDownRef.value) triggerOpen(false, { cancelFun: () => require_useSelectTriggerControl.isInside(getSelectElements(), document.activeElement) });
217
+ };
212
218
  const onInternalBlur = (event) => {
213
219
  focused.value = false;
214
220
  if (mergedSearchValue.value) {
215
221
  if (mode.value === "tags") props?.onSearch?.(mergedSearchValue.value, { source: "submit" });
216
222
  else if (mode.value === "multiple") props?.onSearch?.("", { source: "blur" });
217
223
  }
218
- if (!disabled.value) {
219
- triggerOpen(false, { lazy: true });
220
- props?.onBlur?.(event);
221
- }
224
+ onRootBlur();
225
+ if (!disabled.value) props?.onBlur?.(event);
222
226
  };
223
227
  const onInternalMouseDown = (event) => {
224
228
  const { target } = event;
225
- if ((triggerRef?.value?.getPopupElement?.())?.contains?.(target) && triggerOpen) triggerOpen(true, { ignoreNext: true });
229
+ if ((triggerRef?.value?.getPopupElement?.())?.contains?.(target) && triggerOpen) triggerOpen(true);
226
230
  props?.onMouseDown?.(event);
231
+ internalMouseDownRef.value = true;
232
+ require_useOpen.macroTask(() => {
233
+ internalMouseDownRef.value = false;
234
+ });
227
235
  };
228
236
  const forceState = (0, vue.shallowRef)({});
229
237
  function onPopupMouseEnter() {
230
238
  forceState.value = {};
231
239
  }
232
- require_useSelectTriggerControl.default(() => [(0, _v_c_util_dist_Dom_findDOMNode.getDOM)(containerRef), triggerRef.value?.getPopupElement?.()], mergedOpen, triggerOpen, (0, vue.computed)(() => !!mergedComponents.value.root));
233
240
  require_useBaseProps.useBaseSelectProvider((0, vue.computed)(() => {
234
241
  return {
235
242
  ...props,
@@ -237,7 +244,8 @@ const BaseSelect = /* @__PURE__ */ (0, vue.defineComponent)((props, { expose, at
237
244
  open: mergedOpen.value,
238
245
  triggerOpen: mergedOpen.value,
239
246
  toggleOpen: triggerOpen,
240
- multiple: multiple.value
247
+ multiple: multiple.value,
248
+ lockOptions: lockOptions.value
241
249
  };
242
250
  }));
243
251
  const onClearMouseDown = () => {
@@ -334,7 +342,8 @@ const BaseSelect = /* @__PURE__ */ (0, vue.defineComponent)((props, { expose, at
334
342
  "empty": emptyOptions,
335
343
  "onPopupVisibleChange": onTriggerVisibleChange,
336
344
  "onPopupMouseEnter": onPopupMouseEnter,
337
- "onPopupMouseDown": onInternalMouseDown
345
+ "onPopupMouseDown": onInternalMouseDown,
346
+ "onPopupBlur": onRootBlur
338
347
  }, _isSlot(renderNode) ? renderNode : { default: () => [_renderNode] });
339
348
  return (0, vue.createVNode)(vue.Fragment, null, [(0, vue.createVNode)(require_Polite.default, {
340
349
  "visible": focused.value && !mergedOpen.value,
@@ -3,8 +3,8 @@ import { getSeparatedContent, isValidCount } from "../utils/valueUtil.js";
3
3
  import { useAllowClear } from "../hooks/useAllowClear.js";
4
4
  import useComponents from "../hooks/useComponents.js";
5
5
  import useLock from "../hooks/useLock.js";
6
- import useOpen from "../hooks/useOpen.js";
7
- import useSelectTriggerControl from "../hooks/useSelectTriggerControl.js";
6
+ import useOpen, { macroTask } from "../hooks/useOpen.js";
7
+ import useSelectTriggerControl, { isInside } from "../hooks/useSelectTriggerControl.js";
8
8
  import "../hooks/index.js";
9
9
  import SelectInput_default from "../SelectInput/index.js";
10
10
  import SelectTrigger_default from "../SelectTrigger.js";
@@ -107,7 +107,7 @@ const BaseSelect = /* @__PURE__ */ defineComponent((props, { expose, attrs }) =>
107
107
  return props.notFoundContent ?? "Not Found";
108
108
  });
109
109
  const emptyListContent = computed(() => !props?.notFoundContent && props.emptyOptions);
110
- const [mergedOpen, triggerOpen] = useOpen(open, (openVal) => {
110
+ const [mergedOpen, triggerOpen, lockOptions] = useOpen(open, (openVal) => {
111
111
  props.onPopupVisibleChange?.(openVal);
112
112
  }, (nextOpen) => {
113
113
  return props.disabled || emptyListContent.value ? false : nextOpen;
@@ -194,6 +194,9 @@ const BaseSelect = /* @__PURE__ */ defineComponent((props, { expose, attrs }) =>
194
194
  const onInputBlur = () => {
195
195
  keyLockRef.value = false;
196
196
  };
197
+ const getSelectElements = () => [getDOM(containerRef), triggerRef.value?.getPopupElement?.()];
198
+ useSelectTriggerControl(getSelectElements, mergedOpen, triggerOpen, computed(() => !!mergedComponents.value.root));
199
+ const internalMouseDownRef = shallowRef(false);
197
200
  const onInternalFocus = (event) => {
198
201
  focused.value = true;
199
202
  if (!disabled.value) {
@@ -201,27 +204,31 @@ const BaseSelect = /* @__PURE__ */ defineComponent((props, { expose, attrs }) =>
201
204
  props?.onFocus?.(event);
202
205
  }
203
206
  };
207
+ const onRootBlur = () => {
208
+ if (mergedOpen.value && !internalMouseDownRef.value) triggerOpen(false, { cancelFun: () => isInside(getSelectElements(), document.activeElement) });
209
+ };
204
210
  const onInternalBlur = (event) => {
205
211
  focused.value = false;
206
212
  if (mergedSearchValue.value) {
207
213
  if (mode.value === "tags") props?.onSearch?.(mergedSearchValue.value, { source: "submit" });
208
214
  else if (mode.value === "multiple") props?.onSearch?.("", { source: "blur" });
209
215
  }
210
- if (!disabled.value) {
211
- triggerOpen(false, { lazy: true });
212
- props?.onBlur?.(event);
213
- }
216
+ onRootBlur();
217
+ if (!disabled.value) props?.onBlur?.(event);
214
218
  };
215
219
  const onInternalMouseDown = (event) => {
216
220
  const { target } = event;
217
- if ((triggerRef?.value?.getPopupElement?.())?.contains?.(target) && triggerOpen) triggerOpen(true, { ignoreNext: true });
221
+ if ((triggerRef?.value?.getPopupElement?.())?.contains?.(target) && triggerOpen) triggerOpen(true);
218
222
  props?.onMouseDown?.(event);
223
+ internalMouseDownRef.value = true;
224
+ macroTask(() => {
225
+ internalMouseDownRef.value = false;
226
+ });
219
227
  };
220
228
  const forceState = shallowRef({});
221
229
  function onPopupMouseEnter() {
222
230
  forceState.value = {};
223
231
  }
224
- useSelectTriggerControl(() => [getDOM(containerRef), triggerRef.value?.getPopupElement?.()], mergedOpen, triggerOpen, computed(() => !!mergedComponents.value.root));
225
232
  useBaseSelectProvider(computed(() => {
226
233
  return {
227
234
  ...props,
@@ -229,7 +236,8 @@ const BaseSelect = /* @__PURE__ */ defineComponent((props, { expose, attrs }) =>
229
236
  open: mergedOpen.value,
230
237
  triggerOpen: mergedOpen.value,
231
238
  toggleOpen: triggerOpen,
232
- multiple: multiple.value
239
+ multiple: multiple.value,
240
+ lockOptions: lockOptions.value
233
241
  };
234
242
  }));
235
243
  const onClearMouseDown = () => {
@@ -326,7 +334,8 @@ const BaseSelect = /* @__PURE__ */ defineComponent((props, { expose, attrs }) =>
326
334
  "empty": emptyOptions,
327
335
  "onPopupVisibleChange": onTriggerVisibleChange,
328
336
  "onPopupMouseEnter": onPopupMouseEnter,
329
- "onPopupMouseDown": onInternalMouseDown
337
+ "onPopupMouseDown": onInternalMouseDown,
338
+ "onPopupBlur": onRootBlur
330
339
  }, _isSlot(renderNode) ? renderNode : { default: () => [_renderNode] });
331
340
  return createVNode(Fragment, null, [createVNode(Polite_default, {
332
341
  "visible": focused.value && !mergedOpen.value,
@@ -25,7 +25,7 @@ var SingleContent = /* @__PURE__ */ (0, vue.defineComponent)((props, { expose })
25
25
  const optionProps = (0, vue.computed)(() => {
26
26
  let restProps = {
27
27
  class: `${selectInputContext.value?.prefixCls}-content-value`,
28
- style: { visibility: mergedSearchValue.value ? "hidden" : "visible" }
28
+ style: mergedSearchValue.value ? { visibility: "hidden" } : {}
29
29
  };
30
30
  if (displayValue.value && selectContext.value?.flattenOptions) {
31
31
  const option = selectContext.value.flattenOptions.find((opt) => opt.value === displayValue.value?.value);
@@ -20,7 +20,7 @@ var SingleContent_default = /* @__PURE__ */ defineComponent((props, { expose })
20
20
  const optionProps = computed(() => {
21
21
  let restProps = {
22
22
  class: `${selectInputContext.value?.prefixCls}-content-value`,
23
- style: { visibility: mergedSearchValue.value ? "hidden" : "visible" }
23
+ style: mergedSearchValue.value ? { visibility: "hidden" } : {}
24
24
  };
25
25
  if (displayValue.value && selectContext.value?.flattenOptions) {
26
26
  const option = selectContext.value.flattenOptions.find((opt) => opt.value === displayValue.value?.value);
@@ -64,7 +64,7 @@ var SelectInput = /* @__PURE__ */ (0, vue.defineComponent)((props, { attrs, expo
64
64
  _v_c_util_dist_KeyCode.default.LEFT,
65
65
  _v_c_util_dist_KeyCode.default.RIGHT
66
66
  ].includes(keyCode)) return;
67
- if (require_keyUtil.isValidateOpenKey(keyCode)) toggleOpen.value?.(true);
67
+ if (!(event.ctrlKey || event.altKey || event.metaKey) && require_keyUtil.isValidateOpenKey(keyCode)) toggleOpen.value?.(true);
68
68
  };
69
69
  expose({
70
70
  focus: (options) => {
@@ -77,7 +77,9 @@ var SelectInput = /* @__PURE__ */ (0, vue.defineComponent)((props, { attrs, expo
77
77
  });
78
78
  const onInternalMouseDown = (event) => {
79
79
  if (!disabled.value) {
80
- if (event.target !== (0, _v_c_util_dist_Dom_findDOMNode.getDOM)(inputRef.value?.input)) event.preventDefault();
80
+ const inputDOM = (0, _v_c_util_dist_Dom_findDOMNode.getDOM)(inputRef.value?.input);
81
+ event._ori_target = inputDOM;
82
+ if (inputDOM && event.target !== inputDOM && !inputDOM.contains(event.target)) event.preventDefault();
81
83
  const shouldPreventClose = triggerOpen.value && !multiple.value && (mode.value === "combobox" || showSearch.value);
82
84
  if (!event._select_lazy) {
83
85
  inputRef.value?.input?.focus();
@@ -86,10 +88,6 @@ var SelectInput = /* @__PURE__ */ (0, vue.defineComponent)((props, { attrs, expo
86
88
  }
87
89
  props?.onMouseDown?.(event);
88
90
  };
89
- const onInternalBlur = (event) => {
90
- toggleOpen.value?.(false);
91
- props?.onBlur?.(event);
92
- };
93
91
  require_context.useSelectInputProvider((0, vue.computed)(() => ({
94
92
  ...props,
95
93
  onInputKeyDown: onInternalInputKeyDown
@@ -100,6 +98,8 @@ var SelectInput = /* @__PURE__ */ (0, vue.defineComponent)((props, { attrs, expo
100
98
  ...attrs,
101
99
  onFocus: props.onFocus,
102
100
  onBlur: props.onBlur,
101
+ onFocusin: props.onFocus,
102
+ onFocusout: props.onBlur,
103
103
  onKeydown: props.onKeyDown,
104
104
  onKeyup: props.onKeyUp,
105
105
  onMousedown: props.onMouseDown
@@ -118,8 +118,8 @@ var SelectInput = /* @__PURE__ */ (0, vue.defineComponent)((props, { attrs, expo
118
118
  "onMousedown": onInternalMouseDown,
119
119
  "onKeydown": props.onKeyDown,
120
120
  "onKeyup": props.onKeyUp,
121
- "onFocus": props.onFocus,
122
- "onBlur": onInternalBlur
121
+ "onFocusin": props.onFocus,
122
+ "onFocusout": props.onBlur
123
123
  }), [
124
124
  (0, vue.createVNode)(require_Affix.default, {
125
125
  "class": (0, _v_c_util.clsx)(`${prefixCls.value}-prefix`, classNamesConfig.value?.prefix),
@@ -57,7 +57,7 @@ var SelectInput_default = /* @__PURE__ */ defineComponent((props, { attrs, expos
57
57
  KeyCode.LEFT,
58
58
  KeyCode.RIGHT
59
59
  ].includes(keyCode)) return;
60
- if (isValidateOpenKey(keyCode)) toggleOpen.value?.(true);
60
+ if (!(event.ctrlKey || event.altKey || event.metaKey) && isValidateOpenKey(keyCode)) toggleOpen.value?.(true);
61
61
  };
62
62
  expose({
63
63
  focus: (options) => {
@@ -70,7 +70,9 @@ var SelectInput_default = /* @__PURE__ */ defineComponent((props, { attrs, expos
70
70
  });
71
71
  const onInternalMouseDown = (event) => {
72
72
  if (!disabled.value) {
73
- if (event.target !== getDOM(inputRef.value?.input)) event.preventDefault();
73
+ const inputDOM = getDOM(inputRef.value?.input);
74
+ event._ori_target = inputDOM;
75
+ if (inputDOM && event.target !== inputDOM && !inputDOM.contains(event.target)) event.preventDefault();
74
76
  const shouldPreventClose = triggerOpen.value && !multiple.value && (mode.value === "combobox" || showSearch.value);
75
77
  if (!event._select_lazy) {
76
78
  inputRef.value?.input?.focus();
@@ -79,10 +81,6 @@ var SelectInput_default = /* @__PURE__ */ defineComponent((props, { attrs, expos
79
81
  }
80
82
  props?.onMouseDown?.(event);
81
83
  };
82
- const onInternalBlur = (event) => {
83
- toggleOpen.value?.(false);
84
- props?.onBlur?.(event);
85
- };
86
84
  useSelectInputProvider(computed(() => ({
87
85
  ...props,
88
86
  onInputKeyDown: onInternalInputKeyDown
@@ -93,6 +91,8 @@ var SelectInput_default = /* @__PURE__ */ defineComponent((props, { attrs, expos
93
91
  ...attrs,
94
92
  onFocus: props.onFocus,
95
93
  onBlur: props.onBlur,
94
+ onFocusin: props.onFocus,
95
+ onFocusout: props.onBlur,
96
96
  onKeydown: props.onKeyDown,
97
97
  onKeyup: props.onKeyUp,
98
98
  onMousedown: props.onMouseDown
@@ -111,8 +111,8 @@ var SelectInput_default = /* @__PURE__ */ defineComponent((props, { attrs, expos
111
111
  "onMousedown": onInternalMouseDown,
112
112
  "onKeydown": props.onKeyDown,
113
113
  "onKeyup": props.onKeyUp,
114
- "onFocus": props.onFocus,
115
- "onBlur": onInternalBlur
114
+ "onFocusin": props.onFocus,
115
+ "onFocusout": props.onBlur
116
116
  }), [
117
117
  createVNode(Affix_default, {
118
118
  "class": clsx(`${prefixCls.value}-prefix`, classNamesConfig.value?.prefix),
@@ -60,7 +60,7 @@ var SelectTrigger = /* @__PURE__ */ (0, vue.defineComponent)((props, { slots, at
60
60
  const triggerPopupRef = (0, vue.shallowRef)();
61
61
  expose({ getPopupElement: () => triggerPopupRef.value?.popupElement });
62
62
  return () => {
63
- const { prefixCls, popupElement, popupRender, animation, transitionName, popupStyle, popupMatchSelectWidth, onPopupVisibleChange, placement, direction = "ltr", builtinPlacements, onPopupMouseEnter, onPopupMouseDown, popupAlign, visible, getPopupContainer, popupClassName, empty, ...restProps } = props;
63
+ const { prefixCls, popupElement, popupRender, animation, transitionName, popupStyle, popupMatchSelectWidth, onPopupVisibleChange, placement, direction = "ltr", builtinPlacements, onPopupMouseEnter, onPopupMouseDown, onPopupBlur, popupAlign, visible, getPopupContainer, popupClassName, empty, ...restProps } = props;
64
64
  let popupNode = popupElement;
65
65
  if (popupRender) popupNode = popupRender(popupElement);
66
66
  const popupPrefixCls = `${prefixCls}-dropdown`;
@@ -74,8 +74,9 @@ var SelectTrigger = /* @__PURE__ */ (0, vue.defineComponent)((props, { slots, at
74
74
  "builtinPlacements": mergedBuiltinPlacements.value,
75
75
  "prefixCls": popupPrefixCls,
76
76
  "popup": (0, vue.createVNode)("div", {
77
+ "onMouseenter": onPopupMouseEnter,
77
78
  "onMousedown": onPopupMouseDown,
78
- "onMouseenter": onPopupMouseEnter
79
+ "onBlur": onPopupBlur
79
80
  }, [popupNode]),
80
81
  "ref": triggerPopupRef,
81
82
  "stretch": stretch.value,
@@ -183,6 +184,11 @@ var SelectTrigger = /* @__PURE__ */ (0, vue.defineComponent)((props, { slots, at
183
184
  type: Function,
184
185
  required: true,
185
186
  default: void 0
187
+ },
188
+ onPopupBlur: {
189
+ type: Function,
190
+ required: false,
191
+ default: void 0
186
192
  }
187
193
  }, { direction: "ltr" }),
188
194
  name: "SelectTrigger",
@@ -21,6 +21,7 @@ export interface SelectTriggerProps {
21
21
  onPopupVisibleChange?: ((visible: boolean) => void) | null;
22
22
  onPopupMouseEnter: () => void;
23
23
  onPopupMouseDown: (event: MouseEvent) => void;
24
+ onPopupBlur?: (event: FocusEvent) => void;
24
25
  }
25
26
  declare const SelectTrigger: import('vue').DefineSetupFnComponent<SelectTriggerProps, {}, {}, SelectTriggerProps & {}, import('vue').PublicProps>;
26
27
  export default SelectTrigger;
@@ -54,7 +54,7 @@ var SelectTrigger_default = /* @__PURE__ */ defineComponent((props, { slots, att
54
54
  const triggerPopupRef = shallowRef();
55
55
  expose({ getPopupElement: () => triggerPopupRef.value?.popupElement });
56
56
  return () => {
57
- const { prefixCls, popupElement, popupRender, animation, transitionName, popupStyle, popupMatchSelectWidth, onPopupVisibleChange, placement, direction = "ltr", builtinPlacements, onPopupMouseEnter, onPopupMouseDown, popupAlign, visible, getPopupContainer, popupClassName, empty, ...restProps } = props;
57
+ const { prefixCls, popupElement, popupRender, animation, transitionName, popupStyle, popupMatchSelectWidth, onPopupVisibleChange, placement, direction = "ltr", builtinPlacements, onPopupMouseEnter, onPopupMouseDown, onPopupBlur, popupAlign, visible, getPopupContainer, popupClassName, empty, ...restProps } = props;
58
58
  let popupNode = popupElement;
59
59
  if (popupRender) popupNode = popupRender(popupElement);
60
60
  const popupPrefixCls = `${prefixCls}-dropdown`;
@@ -68,8 +68,9 @@ var SelectTrigger_default = /* @__PURE__ */ defineComponent((props, { slots, att
68
68
  "builtinPlacements": mergedBuiltinPlacements.value,
69
69
  "prefixCls": popupPrefixCls,
70
70
  "popup": createVNode("div", {
71
+ "onMouseenter": onPopupMouseEnter,
71
72
  "onMousedown": onPopupMouseDown,
72
- "onMouseenter": onPopupMouseEnter
73
+ "onBlur": onPopupBlur
73
74
  }, [popupNode]),
74
75
  "ref": triggerPopupRef,
75
76
  "stretch": stretch.value,
@@ -177,6 +178,11 @@ var SelectTrigger_default = /* @__PURE__ */ defineComponent((props, { slots, att
177
178
  type: Function,
178
179
  required: true,
179
180
  default: void 0
181
+ },
182
+ onPopupBlur: {
183
+ type: Function,
184
+ required: false,
185
+ default: void 0
180
186
  }
181
187
  }, { direction: "ltr" }),
182
188
  name: "SelectTrigger",
@@ -5,6 +5,7 @@ export interface BaseSelectContextProps extends BaseSelectProps {
5
5
  multiple: boolean;
6
6
  toggleOpen: (open?: boolean) => void;
7
7
  role?: string;
8
+ lockOptions: boolean;
8
9
  }
9
10
  export declare function useBaseSelectProvider(context: Ref<BaseSelectContextProps>): void;
10
11
  export default function useBaseProps(): Ref<BaseSelectContextProps | null>;
@@ -27,36 +27,37 @@ function useOpen(propOpen, onOpen, postOpen) {
27
27
  (0, vue.watch)(propOpen, () => {
28
28
  stateOpen.value = propOpen.value;
29
29
  });
30
+ const lock = (0, vue.shallowRef)(false);
30
31
  const ssrSafeOpen = (0, vue.computed)(() => rendered.value ? stateOpen.value : false);
31
32
  const mergedOpen = (0, vue.computed)(() => postOpen(ssrSafeOpen.value));
32
33
  const taskIdRef = (0, vue.shallowRef)(0);
33
- const taskLockRef = (0, vue.shallowRef)(false);
34
34
  const triggerEvent = (nextOpen) => {
35
35
  if (onOpen && mergedOpen.value !== nextOpen) onOpen(nextOpen);
36
36
  if (propOpen.value !== void 0) return;
37
37
  stateOpen.value = nextOpen;
38
38
  };
39
39
  const toggleOpen = (nextOpen, config = {}) => {
40
- const { ignoreNext = false, lazy = false } = config;
40
+ const { cancelFun } = config;
41
41
  taskIdRef.value += 1;
42
42
  const id = taskIdRef.value;
43
43
  const nextOpenVal = typeof nextOpen === "boolean" ? nextOpen : !mergedOpen.value;
44
- if (nextOpenVal !== lazy) {
45
- if (!taskLockRef.value) {
44
+ lock.value = !nextOpenVal;
45
+ function triggerUpdate() {
46
+ if (id === taskIdRef.value && !cancelFun?.()) {
46
47
  triggerEvent(nextOpenVal);
47
- if (ignoreNext) {
48
- taskLockRef.value = ignoreNext;
49
- macroTask(() => {
50
- taskLockRef.value = false;
51
- }, 2);
52
- }
48
+ lock.value = false;
53
49
  }
54
- return;
55
50
  }
56
- macroTask(() => {
57
- if (id === taskIdRef.value && !taskLockRef.value) triggerEvent(nextOpenVal);
51
+ if (nextOpenVal) triggerUpdate();
52
+ else macroTask(() => {
53
+ triggerUpdate();
58
54
  });
59
55
  };
60
- return [mergedOpen, toggleOpen];
56
+ return [
57
+ mergedOpen,
58
+ toggleOpen,
59
+ lock
60
+ ];
61
61
  }
62
62
  exports.default = useOpen;
63
+ exports.macroTask = macroTask;
@@ -1,11 +1,11 @@
1
1
  import { Ref } from 'vue';
2
+ export declare function macroTask(fn: VoidFunction, times?: number): void;
2
3
  /**
3
4
  * Trigger by latest open call, if nextOpen is undefined, means toggle.
4
5
  * ignoreNext will skip next call in the macro task queue.
5
6
  */
6
7
  export type TriggerOpenType = (nextOpen?: boolean, config?: {
7
- ignoreNext?: boolean;
8
- lazy?: boolean;
8
+ cancelFun?: () => boolean;
9
9
  }) => void;
10
10
  /**
11
11
  * When `open` is controlled, follow the controlled value;
@@ -16,4 +16,4 @@ export type TriggerOpenType = (nextOpen?: boolean, config?: {
16
16
  * SSR handling: During SSR, `open` is always false to avoid Portal issues.
17
17
  * On client-side hydration, it syncs with the actual open state.
18
18
  */
19
- export default function useOpen(propOpen: Ref<boolean>, onOpen: (nextOpen: boolean) => void, postOpen: (nextOpen: boolean) => boolean): readonly [import('vue').ComputedRef<boolean>, TriggerOpenType];
19
+ export default function useOpen(propOpen: Ref<boolean>, onOpen: (nextOpen: boolean) => void, postOpen: (nextOpen: boolean) => boolean): readonly [import('vue').ComputedRef<boolean>, TriggerOpenType, import('vue').ShallowRef<boolean, boolean>];
@@ -22,36 +22,36 @@ function useOpen(propOpen, onOpen, postOpen) {
22
22
  watch(propOpen, () => {
23
23
  stateOpen.value = propOpen.value;
24
24
  });
25
+ const lock = shallowRef(false);
25
26
  const ssrSafeOpen = computed(() => rendered.value ? stateOpen.value : false);
26
27
  const mergedOpen = computed(() => postOpen(ssrSafeOpen.value));
27
28
  const taskIdRef = shallowRef(0);
28
- const taskLockRef = shallowRef(false);
29
29
  const triggerEvent = (nextOpen) => {
30
30
  if (onOpen && mergedOpen.value !== nextOpen) onOpen(nextOpen);
31
31
  if (propOpen.value !== void 0) return;
32
32
  stateOpen.value = nextOpen;
33
33
  };
34
34
  const toggleOpen = (nextOpen, config = {}) => {
35
- const { ignoreNext = false, lazy = false } = config;
35
+ const { cancelFun } = config;
36
36
  taskIdRef.value += 1;
37
37
  const id = taskIdRef.value;
38
38
  const nextOpenVal = typeof nextOpen === "boolean" ? nextOpen : !mergedOpen.value;
39
- if (nextOpenVal !== lazy) {
40
- if (!taskLockRef.value) {
39
+ lock.value = !nextOpenVal;
40
+ function triggerUpdate() {
41
+ if (id === taskIdRef.value && !cancelFun?.()) {
41
42
  triggerEvent(nextOpenVal);
42
- if (ignoreNext) {
43
- taskLockRef.value = ignoreNext;
44
- macroTask(() => {
45
- taskLockRef.value = false;
46
- }, 2);
47
- }
43
+ lock.value = false;
48
44
  }
49
- return;
50
45
  }
51
- macroTask(() => {
52
- if (id === taskIdRef.value && !taskLockRef.value) triggerEvent(nextOpenVal);
46
+ if (nextOpenVal) triggerUpdate();
47
+ else macroTask(() => {
48
+ triggerUpdate();
53
49
  });
54
50
  };
55
- return [mergedOpen, toggleOpen];
51
+ return [
52
+ mergedOpen,
53
+ toggleOpen,
54
+ lock
55
+ ];
56
56
  }
57
- export { useOpen as default };
57
+ export { useOpen as default, macroTask };
@@ -4,12 +4,16 @@ Object.defineProperties(exports, {
4
4
  });
5
5
  const require_rolldown_runtime = require("../_virtual/rolldown_runtime.cjs");
6
6
  let vue = require("vue");
7
+ function isInside(elements, target) {
8
+ return elements.filter((element) => element).some((element) => element.contains(target) || element === target);
9
+ }
7
10
  function useSelectTriggerControl(elements, open, triggerOpen, customizedTrigger) {
8
11
  const onGlobalMouseDown = (event) => {
9
12
  if (customizedTrigger.value) return;
10
13
  let target = event.target;
11
14
  if (target.shadowRoot && event.composed) target = event.composedPath()[0] || target;
12
- if (open.value && elements().filter((element) => element).every((element) => !element.contains(target) && element !== target)) triggerOpen(false);
15
+ if (event._ori_target) target = event._ori_target;
16
+ if (open.value && !isInside(elements(), target)) triggerOpen(false);
13
17
  };
14
18
  (0, vue.onMounted)(() => {
15
19
  window.addEventListener("mousedown", onGlobalMouseDown);
@@ -19,3 +23,4 @@ function useSelectTriggerControl(elements, open, triggerOpen, customizedTrigger)
19
23
  });
20
24
  }
21
25
  exports.default = useSelectTriggerControl;
26
+ exports.isInside = isInside;
@@ -1,2 +1,4 @@
1
1
  import { Ref } from 'vue';
2
- export default function useSelectTriggerControl(elements: () => (HTMLElement | SVGElement | undefined)[], open: Ref<boolean>, triggerOpen: (open: boolean) => void, customizedTrigger: Ref<boolean>): void;
2
+ import { TriggerOpenType } from './useOpen';
3
+ export declare function isInside(elements: (HTMLElement | SVGElement | undefined)[], target: HTMLElement): boolean;
4
+ export default function useSelectTriggerControl(elements: () => (HTMLElement | SVGElement | undefined)[], open: Ref<boolean>, triggerOpen: TriggerOpenType, customizedTrigger: Ref<boolean>): void;
@@ -1,10 +1,14 @@
1
1
  import { onMounted, onUnmounted } from "vue";
2
+ function isInside(elements, target) {
3
+ return elements.filter((element) => element).some((element) => element.contains(target) || element === target);
4
+ }
2
5
  function useSelectTriggerControl(elements, open, triggerOpen, customizedTrigger) {
3
6
  const onGlobalMouseDown = (event) => {
4
7
  if (customizedTrigger.value) return;
5
8
  let target = event.target;
6
9
  if (target.shadowRoot && event.composed) target = event.composedPath()[0] || target;
7
- if (open.value && elements().filter((element) => element).every((element) => !element.contains(target) && element !== target)) triggerOpen(false);
10
+ if (event._ori_target) target = event._ori_target;
11
+ if (open.value && !isInside(elements(), target)) triggerOpen(false);
8
12
  };
9
13
  onMounted(() => {
10
14
  window.addEventListener("mousedown", onGlobalMouseDown);
@@ -13,4 +17,4 @@ function useSelectTriggerControl(elements, open, triggerOpen, customizedTrigger)
13
17
  });
14
18
  });
15
19
  }
16
- export { useSelectTriggerControl as default };
20
+ export { useSelectTriggerControl as default, isInside };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@v-c/select",
3
3
  "type": "module",
4
- "version": "1.0.7",
4
+ "version": "1.0.9",
5
5
  "description": "",
6
6
  "author": "",
7
7
  "license": "MIT",
@@ -29,10 +29,10 @@
29
29
  "vue": "^3.0.0"
30
30
  },
31
31
  "dependencies": {
32
- "@v-c/overflow": "^1.0.1",
33
- "@v-c/trigger": "^1.0.5",
34
- "@v-c/virtual-list": "^1.0.4",
35
- "@v-c/util": "^1.0.8"
32
+ "@v-c/overflow": "^1.0.3",
33
+ "@v-c/trigger": "^1.0.6",
34
+ "@v-c/util": "^1.0.9",
35
+ "@v-c/virtual-list": "^1.0.5"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "vite build",