@neatui/vue 4.2.0 → 4.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neatui/vue",
3
- "version": "4.2.0",
3
+ "version": "4.2.2",
4
4
  "description": "basic component ui",
5
5
  "main": "./src/index.ts",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "@fekit/scrollto": "^3.0.3",
35
35
  "@fekit/toast": "^2.7.2",
36
36
  "@fekit/utils": "^6.0.0",
37
- "@neatui/css": "^4.2.0",
37
+ "@neatui/css": "^4.2.2",
38
38
  "@rollup/plugin-commonjs": "^26.0.1",
39
39
  "@rollup/plugin-node-resolve": "^15.2.3",
40
40
  "@vue/compiler-sfc": "^3.4.30",
@@ -107,7 +107,8 @@
107
107
  const topId = stack[stack.length - 1];
108
108
  if (!topId) return;
109
109
  const layer = _tasks[topId];
110
- if (!layer || layer.view !== 3 || layer.escClose === false) return;
110
+ // 禁止 ESC:显式 escClose=false,或禁止暗层关闭时同步禁 ESC
111
+ if (!layer || layer.view !== 3 || layer.escClose === false || layer.darkClickClose === false) return;
111
112
  layer.hide();
112
113
  ev.preventDefault();
113
114
  };
@@ -333,6 +334,14 @@
333
334
  { immediate: true },
334
335
  );
335
336
 
337
+ watch(
338
+ () => props.darkClickClose,
339
+ (darkClickClose) => {
340
+ if (_tasks[props.id]) _tasks[props.id].darkClickClose = darkClickClose;
341
+ },
342
+ { immediate: true },
343
+ );
344
+
336
345
  // 回调合集
337
346
  const on: any = {
338
347
  show: [],
@@ -426,7 +435,7 @@
426
435
  console.error('Layer 有重复 id', id);
427
436
  }
428
437
  if (id) {
429
- _tasks[id] = { init, show, hide, open, none, view: state.view, escClose: props.escClose };
438
+ _tasks[id] = { init, show, hide, open, none, view: state.view, escClose: props.escClose, darkClickClose: props.darkClickClose };
430
439
  ensureEscapeListener();
431
440
  } else {
432
441
  console.error('Layer 必须填写全局统一的 id');
@@ -60,6 +60,7 @@
60
60
  import { reactive, ref, computed, watch, nextTick } from 'vue';
61
61
  import Input from './Input.vue';
62
62
  import { IFollowView } from '../basic';
63
+ import { matchOptionSearch } from './optionSearch';
63
64
  const ifollow: any = ref(null);
64
65
 
65
66
  const emits = defineEmits(['update:modelValue']);
@@ -177,7 +178,7 @@
177
178
  filter: computed(() => {
178
179
  if (state.search) {
179
180
  return props.options?.filter((item: any) => {
180
- return item.label?.includes(state.search);
181
+ return matchOptionSearch(item, state.search);
181
182
  });
182
183
  } else {
183
184
  return props.options;
@@ -46,6 +46,7 @@
46
46
  import { reactive, ref, computed } from 'vue';
47
47
  import Input from './Input.vue';
48
48
  import { IFollowView } from '../basic';
49
+ import { matchOptionSearch } from './optionSearch';
49
50
  const ifollow: any = ref(null);
50
51
 
51
52
  const emits = defineEmits(['update:modelValue', 'change', 'request', 'onshow', 'onhide']);
@@ -118,7 +119,7 @@
118
119
  filter: computed(() => {
119
120
  if (state.search) {
120
121
  return props.options?.filter((item) => {
121
- return item.label?.includes(state.search);
122
+ return matchOptionSearch(item, state.search);
122
123
  });
123
124
  } else {
124
125
  return props.options;
@@ -50,6 +50,7 @@
50
50
  import { reactive, ref, computed } from 'vue';
51
51
  import Input from './Input.vue';
52
52
  import { IFollowView } from '../basic';
53
+ import { matchOptionSearch } from './optionSearch';
53
54
  const ifollow: any = ref(null);
54
55
  console.warn('「SearchSelect」 即将废弃,建议使用「Select」 设置参数search为true,示例:<Select v-model="value" :search="true" />');
55
56
  const emits = defineEmits(['update:modelValue', 'change', 'onshow', 'onhide']);
@@ -161,7 +162,7 @@
161
162
  filter: computed(() => {
162
163
  if (state.search) {
163
164
  return props.options?.filter((item: any) => {
164
- return item.label?.includes(state.search);
165
+ return matchOptionSearch(item, state.search);
165
166
  });
166
167
  } else {
167
168
  return props.options;
@@ -68,6 +68,7 @@
68
68
  import { reactive, ref, computed, watch, nextTick } from 'vue';
69
69
  import Input from './Input.vue';
70
70
  import { IFollowView } from '../basic';
71
+ import { matchOptionSearch } from './optionSearch';
71
72
  const ifollow: any = ref(null);
72
73
  const customInputRef: any = ref(null);
73
74
 
@@ -246,7 +247,7 @@
246
247
 
247
248
  if (state.search) {
248
249
  filteredOptions = filteredOptions.filter((item: any) => {
249
- return item.label?.includes(state.search);
250
+ return matchOptionSearch(item, state.search);
250
251
  });
251
252
  }
252
253
 
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 选项搜索:匹配 label / value,以及选项对象上可遍历的全部字段(含嵌套)
3
+ * 大小写不敏感
4
+ */
5
+ export const matchOptionSearch = (item: any, keyword: unknown): boolean => {
6
+ const q = String(keyword ?? '')
7
+ .trim()
8
+ .toLowerCase();
9
+ if (!q) return true;
10
+ if (item == null) return false;
11
+
12
+ if (typeof item !== 'object') {
13
+ return String(item).toLowerCase().includes(q);
14
+ }
15
+
16
+ const seen = new WeakSet<object>();
17
+ const walk = (val: any): boolean => {
18
+ if (val == null) return false;
19
+ const t = typeof val;
20
+ if (t === 'string' || t === 'number' || t === 'boolean' || t === 'bigint') {
21
+ return String(val).toLowerCase().includes(q);
22
+ }
23
+ if (t !== 'object') return false;
24
+ if (seen.has(val)) return false;
25
+ seen.add(val);
26
+ if (Array.isArray(val)) return val.some(walk);
27
+ return Object.values(val).some(walk);
28
+ };
29
+
30
+ return walk(item);
31
+ };