v-uixy 1.9.1 → 1.9.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.
- package/package.json +1 -1
- package/templates/components/Chart/Chart.component.vue +895 -222
- package/templates/components/Chart/Chart.types.ts +7 -0
- package/templates/components/Modal/Modal.component.vue +8 -1
- package/templates/components/Modal/Modal.styles.ts +1 -1
- package/templates/components/PieChart/PieChart.component.vue +515 -152
- package/templates/components/PieChart/PieChart.types.ts +7 -1
- package/templates/components/Select/Select.component.vue +58 -32
- package/templates/components/Select/Select.styles.ts +37 -12
- package/templates/components/Select/Select.types.ts +4 -0
- package/templates/components/Select/SelectTreeItem.vue +11 -3
- package/templates/components/Select/composables/useSelect.composable.ts +244 -122
- package/templates/components/Select/index.ts +2 -0
- package/templates/components/Sheet/Sheet.component.vue +4 -2
- package/templates/components/index.ts +8 -1
- package/templates/components.json +4 -4
- package/templates/composables/useGpuAcceleration.ts +79 -0
- package/templates/composables/useOverlayLayer.ts +86 -31
- package/templates/composables/usePosition.ts +1 -1
|
@@ -15,8 +15,8 @@ const getValue = (option: UixySelectOptionType): string =>
|
|
|
15
15
|
option.value ?? option.label;
|
|
16
16
|
|
|
17
17
|
const collectLeafValues = (option: UixySelectOptionType): string[] => {
|
|
18
|
-
if (!option.children
|
|
19
|
-
|
|
18
|
+
if (!option.children?.length) return [getValue(option)];
|
|
19
|
+
|
|
20
20
|
return option.children.flatMap(collectLeafValues);
|
|
21
21
|
};
|
|
22
22
|
|
|
@@ -24,16 +24,23 @@ const findInTree = (
|
|
|
24
24
|
options: UixySelectOptionType[],
|
|
25
25
|
value: string,
|
|
26
26
|
): UixySelectOptionType | null => {
|
|
27
|
-
for (const
|
|
28
|
-
if (getValue(
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
for (const option of options) {
|
|
28
|
+
if (getValue(option) === value) return option;
|
|
29
|
+
|
|
30
|
+
if (option.children?.length) {
|
|
31
|
+
const found = findInTree(option.children, value);
|
|
32
|
+
|
|
31
33
|
if (found) return found;
|
|
32
34
|
}
|
|
33
35
|
}
|
|
36
|
+
|
|
34
37
|
return null;
|
|
35
38
|
};
|
|
36
39
|
|
|
40
|
+
const isNotNull = (
|
|
41
|
+
option: UixySelectOptionType | null,
|
|
42
|
+
): option is UixySelectOptionType => option !== null;
|
|
43
|
+
|
|
37
44
|
export const useSelect = <T extends string | string[]>(
|
|
38
45
|
props: UixySelectProps,
|
|
39
46
|
model: Ref<T>,
|
|
@@ -46,39 +53,43 @@ export const useSelect = <T extends string | string[]>(
|
|
|
46
53
|
const lastScrollAt = ref(0);
|
|
47
54
|
const expandedItems = ref<string[]>([]);
|
|
48
55
|
|
|
56
|
+
const selectedValues = computed<string[]>(() =>
|
|
57
|
+
Array.isArray(model.value) ? (model.value as string[]) : [],
|
|
58
|
+
);
|
|
59
|
+
|
|
49
60
|
const filterTreeOptions = (
|
|
50
61
|
items: UixySelectOptionType[],
|
|
51
62
|
searchTerm: string,
|
|
52
63
|
): UixySelectOptionType[] => {
|
|
53
64
|
if (!searchTerm) return items;
|
|
54
|
-
|
|
65
|
+
|
|
66
|
+
const normalizedSearch = normalizeForSearch(searchTerm);
|
|
67
|
+
|
|
55
68
|
const filterNode = (
|
|
56
69
|
node: UixySelectOptionType,
|
|
57
70
|
): UixySelectOptionType | null => {
|
|
58
|
-
const matches = normalizeForSearch(node.label).includes(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return { ...node, children: filteredChildren };
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
71
|
+
const matches = normalizeForSearch(node.label).includes(normalizedSearch);
|
|
72
|
+
const filteredChildren = (node.children ?? [])
|
|
73
|
+
.map(filterNode)
|
|
74
|
+
.filter(isNotNull);
|
|
75
|
+
|
|
76
|
+
if (!matches && filteredChildren.length === 0) return null;
|
|
77
|
+
|
|
78
|
+
return { ...node, children: filteredChildren };
|
|
69
79
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
.filter((n): n is UixySelectOptionType => n !== null);
|
|
80
|
+
|
|
81
|
+
return items.map(filterNode).filter(isNotNull);
|
|
73
82
|
};
|
|
74
83
|
|
|
75
84
|
const filteredOptions = computed(() => {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
const options = props.options ?? [];
|
|
86
|
+
|
|
87
|
+
if (props.tree) return filterTreeOptions(options, search.value);
|
|
88
|
+
|
|
89
|
+
const normalizedSearch = normalizeForSearch(search.value);
|
|
90
|
+
|
|
91
|
+
return options.filter((option) =>
|
|
92
|
+
normalizeForSearch(option.label).includes(normalizedSearch),
|
|
82
93
|
);
|
|
83
94
|
});
|
|
84
95
|
|
|
@@ -87,133 +98,221 @@ export const useSelect = <T extends string | string[]>(
|
|
|
87
98
|
searchTerm: string,
|
|
88
99
|
): string[] => {
|
|
89
100
|
if (!searchTerm) return [];
|
|
101
|
+
|
|
90
102
|
const lowerSearch = searchTerm.toLowerCase();
|
|
91
103
|
const parentsToExpand: string[] = [];
|
|
104
|
+
|
|
92
105
|
const checkNode = (node: UixySelectOptionType): boolean => {
|
|
93
106
|
const nodeMatches = node.label.toLowerCase().includes(lowerSearch);
|
|
94
107
|
let hasMatchingDescendant = false;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
108
|
+
|
|
109
|
+
for (const child of node.children ?? []) {
|
|
110
|
+
if (checkNode(child)) hasMatchingDescendant = true;
|
|
99
111
|
}
|
|
112
|
+
|
|
100
113
|
if (hasMatchingDescendant) parentsToExpand.push(getValue(node));
|
|
114
|
+
|
|
101
115
|
return nodeMatches || hasMatchingDescendant;
|
|
102
116
|
};
|
|
117
|
+
|
|
103
118
|
for (const item of items) checkNode(item);
|
|
119
|
+
|
|
104
120
|
return parentsToExpand;
|
|
105
121
|
};
|
|
106
122
|
|
|
107
123
|
const effectiveExpandedItems = computed(() => {
|
|
108
124
|
if (!search.value) return expandedItems.value;
|
|
125
|
+
|
|
109
126
|
const autoExpanded = collectParentsWithMatchingDescendants(
|
|
110
127
|
props.options,
|
|
111
128
|
search.value,
|
|
112
129
|
);
|
|
130
|
+
|
|
113
131
|
return Array.from(new Set([...expandedItems.value, ...autoExpanded]));
|
|
114
132
|
});
|
|
115
133
|
|
|
116
134
|
const toggleExpand = (value: string) => {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
135
|
+
const index = expandedItems.value.indexOf(value);
|
|
136
|
+
|
|
137
|
+
if (index >= 0) {
|
|
138
|
+
expandedItems.value.splice(index, 1);
|
|
139
|
+
} else {
|
|
140
|
+
expandedItems.value.push(value);
|
|
141
|
+
}
|
|
120
142
|
};
|
|
121
143
|
|
|
122
144
|
const isSelected = (option: UixySelectOptionType): boolean => {
|
|
123
|
-
const v = getValue(option);
|
|
124
145
|
if (props.tree && props.multiple && option.children?.length) {
|
|
125
146
|
const leaves = collectLeafValues(option);
|
|
126
|
-
|
|
127
|
-
return
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
leaves.length > 0 &&
|
|
150
|
+
leaves.every((leaf) => selectedValues.value.includes(leaf))
|
|
151
|
+
);
|
|
128
152
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
153
|
+
|
|
154
|
+
const value = getValue(option);
|
|
155
|
+
|
|
156
|
+
if (Array.isArray(model.value)) return selectedValues.value.includes(value);
|
|
157
|
+
|
|
158
|
+
return (model.value as string) === value;
|
|
132
159
|
};
|
|
133
160
|
|
|
134
161
|
const isPartiallySelected = (option: UixySelectOptionType): boolean => {
|
|
135
|
-
if (!props.tree || !props.multiple || !option.children?.length)
|
|
162
|
+
if (!props.tree || !props.multiple || !option.children?.length) {
|
|
136
163
|
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
137
166
|
const leaves = collectLeafValues(option);
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
167
|
+
const selectedCount = leaves.filter((leaf) =>
|
|
168
|
+
selectedValues.value.includes(leaf),
|
|
169
|
+
).length;
|
|
170
|
+
|
|
171
|
+
return selectedCount > 0 && selectedCount < leaves.length;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const minSelected = computed(() => {
|
|
175
|
+
if (!props.multiple) return props.deselectable ? 0 : 1;
|
|
176
|
+
|
|
177
|
+
const min = Math.max(props.min ?? 0, 0);
|
|
178
|
+
|
|
179
|
+
return props.deselectable ? min : Math.max(min, 1);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const hasMax = computed(
|
|
183
|
+
() => !!props.multiple && typeof props.max === "number",
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const isAtMax = computed(
|
|
187
|
+
() => hasMax.value && selectedValues.value.length >= props.max!,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const canReplace = computed(
|
|
191
|
+
() => props.maxBehavior === "replace" && props.max !== 0,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const isBlocked = (option: UixySelectOptionType): boolean => {
|
|
195
|
+
if (!hasMax.value || canReplace.value || isSelected(option)) return false;
|
|
196
|
+
|
|
197
|
+
const prev = selectedValues.value;
|
|
198
|
+
const values =
|
|
199
|
+
props.tree && option.children?.length
|
|
200
|
+
? collectLeafValues(option)
|
|
201
|
+
: [getValue(option)];
|
|
202
|
+
const added = values.filter((v) => !prev.includes(v)).length;
|
|
203
|
+
|
|
204
|
+
return prev.length + added > props.max!;
|
|
141
205
|
};
|
|
142
206
|
|
|
143
207
|
const setMultiValues = (next: string[]) => {
|
|
144
208
|
(model.value as string[]) = next;
|
|
145
209
|
};
|
|
146
210
|
|
|
147
|
-
const toggleMultiValue = (v: string) => {
|
|
148
|
-
const prev =
|
|
211
|
+
const toggleMultiValue = (v: string): boolean => {
|
|
212
|
+
const prev = selectedValues.value;
|
|
213
|
+
|
|
149
214
|
if (prev.includes(v)) {
|
|
215
|
+
if (prev.length <= minSelected.value) return false;
|
|
216
|
+
|
|
150
217
|
setMultiValues(prev.filter((item) => item !== v));
|
|
151
|
-
|
|
218
|
+
|
|
219
|
+
return true;
|
|
152
220
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return;
|
|
221
|
+
|
|
222
|
+
if (hasMax.value && prev.length >= props.max!) {
|
|
223
|
+
if (!canReplace.value) return false;
|
|
224
|
+
|
|
225
|
+
setMultiValues([...prev.slice(prev.length - props.max! + 1), v]);
|
|
226
|
+
|
|
227
|
+
return true;
|
|
156
228
|
}
|
|
229
|
+
|
|
157
230
|
setMultiValues([...prev, v]);
|
|
231
|
+
|
|
232
|
+
return true;
|
|
158
233
|
};
|
|
159
234
|
|
|
160
|
-
const cascadeMultiTree = (option: UixySelectOptionType) => {
|
|
235
|
+
const cascadeMultiTree = (option: UixySelectOptionType): boolean => {
|
|
161
236
|
const leaves = collectLeafValues(option);
|
|
162
|
-
const prev =
|
|
163
|
-
const allSelected = leaves.every((
|
|
237
|
+
const prev = selectedValues.value;
|
|
238
|
+
const allSelected = leaves.every((leaf) => prev.includes(leaf));
|
|
239
|
+
|
|
164
240
|
if (allSelected) {
|
|
165
|
-
|
|
166
|
-
|
|
241
|
+
const next = prev.filter((v) => !leaves.includes(v));
|
|
242
|
+
|
|
243
|
+
if (next.length < minSelected.value) return false;
|
|
244
|
+
|
|
245
|
+
setMultiValues(next);
|
|
246
|
+
|
|
247
|
+
return true;
|
|
167
248
|
}
|
|
249
|
+
|
|
168
250
|
const merged = Array.from(new Set([...prev, ...leaves]));
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return;
|
|
251
|
+
|
|
252
|
+
if (hasMax.value && merged.length > props.max!) {
|
|
253
|
+
if (!canReplace.value) return false;
|
|
254
|
+
|
|
255
|
+
setMultiValues(merged.slice(merged.length - props.max!));
|
|
256
|
+
|
|
257
|
+
return true;
|
|
172
258
|
}
|
|
259
|
+
|
|
173
260
|
setMultiValues(merged);
|
|
261
|
+
|
|
262
|
+
return true;
|
|
174
263
|
};
|
|
175
264
|
|
|
176
|
-
const applyChange = (v: string) => {
|
|
265
|
+
const applyChange = (v: string): boolean => {
|
|
177
266
|
if (!props.multiple) {
|
|
178
267
|
(model.value as string) = v;
|
|
179
|
-
|
|
268
|
+
|
|
269
|
+
return true;
|
|
180
270
|
}
|
|
271
|
+
|
|
181
272
|
if (props.tree) {
|
|
182
273
|
const node = findInTree(props.options, v);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
274
|
+
|
|
275
|
+
if (node?.children?.length) return cascadeMultiTree(node);
|
|
187
276
|
}
|
|
188
|
-
|
|
277
|
+
|
|
278
|
+
return toggleMultiValue(v);
|
|
189
279
|
};
|
|
190
280
|
|
|
191
281
|
const handleClick = (value: string) => {
|
|
192
|
-
applyChange(value);
|
|
282
|
+
if (!applyChange(value)) return;
|
|
283
|
+
|
|
193
284
|
emit("change", value);
|
|
285
|
+
|
|
194
286
|
if (props.clearSearchOnSelect) search.value = "";
|
|
195
287
|
if (!props.multiple) open.value = false;
|
|
196
288
|
};
|
|
197
289
|
|
|
198
290
|
const handleClickSelectedOption = (item: string) => {
|
|
199
|
-
applyChange(item);
|
|
291
|
+
if (!applyChange(item)) return;
|
|
292
|
+
|
|
200
293
|
emit("change", item);
|
|
201
294
|
};
|
|
202
295
|
|
|
203
296
|
const handleDeselect = () => {
|
|
297
|
+
if (minSelected.value > 0) return;
|
|
298
|
+
|
|
204
299
|
(model.value as string) = "";
|
|
205
300
|
};
|
|
206
301
|
|
|
207
302
|
const getLabel = (value: string): string => {
|
|
208
303
|
if (!value) return "";
|
|
304
|
+
|
|
209
305
|
return findInTree(props.options, value)?.label ?? value;
|
|
210
306
|
};
|
|
211
307
|
|
|
212
308
|
const customAddVisible = computed(() => {
|
|
213
309
|
if (!props.allowCustom || !search.value) return false;
|
|
310
|
+
if (isAtMax.value && !canReplace.value) return false;
|
|
311
|
+
|
|
214
312
|
const lowerSearch = search.value.toLowerCase();
|
|
313
|
+
|
|
215
314
|
return !filteredOptions.value.some(
|
|
216
|
-
(
|
|
315
|
+
(option) => option.label.toLowerCase() === lowerSearch,
|
|
217
316
|
);
|
|
218
317
|
});
|
|
219
318
|
|
|
@@ -222,61 +321,79 @@ export const useSelect = <T extends string | string[]>(
|
|
|
222
321
|
};
|
|
223
322
|
|
|
224
323
|
const handleOpen = (e?: MouseEvent) => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
)
|
|
229
|
-
|
|
324
|
+
const isBadgeClick =
|
|
325
|
+
!!e && "badge" in (e.target as HTMLDivElement).dataset;
|
|
326
|
+
|
|
327
|
+
if (props.disabled || isBadgeClick) return;
|
|
328
|
+
|
|
230
329
|
open.value = !open.value;
|
|
231
330
|
};
|
|
232
331
|
|
|
233
332
|
const handleKeydownSelect = (e: KeyboardEvent) => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (key === "ArrowDown" || key === "Enter" || key === " ") {
|
|
333
|
+
if (e.key === "Tab") return;
|
|
334
|
+
|
|
335
|
+
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
|
|
237
336
|
e.preventDefault();
|
|
337
|
+
|
|
238
338
|
open.value = !open.value;
|
|
239
339
|
}
|
|
240
340
|
};
|
|
241
341
|
|
|
342
|
+
const getFocusableOptions = (): HTMLElement[] => {
|
|
343
|
+
const container = dropdownRef?.value ?? refOptions.value;
|
|
344
|
+
|
|
345
|
+
if (!container) return [];
|
|
346
|
+
|
|
347
|
+
const elements = container.querySelectorAll<HTMLElement>(
|
|
348
|
+
"[select-dropdown] input, [select-dropdown] li",
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
return Array.from(elements).filter(
|
|
352
|
+
(el) =>
|
|
353
|
+
el.tabIndex >= 0 &&
|
|
354
|
+
el.getAttribute("aria-disabled") !== "true" &&
|
|
355
|
+
!el.hasAttribute("disabled"),
|
|
356
|
+
);
|
|
357
|
+
};
|
|
358
|
+
|
|
242
359
|
const handleKeydownOption = (
|
|
243
360
|
e: KeyboardEvent,
|
|
244
361
|
option: UixySelectOptionType,
|
|
245
362
|
) => {
|
|
246
|
-
const
|
|
247
|
-
|
|
363
|
+
const isSelectKey = e.key === "Enter" || e.key === " ";
|
|
364
|
+
|
|
365
|
+
if (isSelectKey && !option.disabled) {
|
|
248
366
|
e.preventDefault();
|
|
367
|
+
|
|
249
368
|
return handleClick(getValue(option));
|
|
250
369
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const focusables =
|
|
255
|
-
|
|
256
|
-
"[select-dropdown] input, [select-dropdown] li",
|
|
257
|
-
),
|
|
258
|
-
).filter(
|
|
259
|
-
(el) =>
|
|
260
|
-
el.tabIndex >= 0 &&
|
|
261
|
-
el.getAttribute("aria-disabled") !== "true" &&
|
|
262
|
-
!el.hasAttribute("disabled"),
|
|
263
|
-
);
|
|
370
|
+
|
|
371
|
+
if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
|
|
372
|
+
|
|
373
|
+
const focusables = getFocusableOptions();
|
|
374
|
+
|
|
264
375
|
if (!focusables.length) return;
|
|
265
|
-
|
|
266
|
-
let index = currentEl ? focusables.indexOf(currentEl) : -1;
|
|
376
|
+
|
|
267
377
|
e.preventDefault();
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
focusables
|
|
378
|
+
|
|
379
|
+
const current = e.currentTarget as HTMLElement | null;
|
|
380
|
+
const currentIndex = current ? focusables.indexOf(current) : -1;
|
|
381
|
+
const step = e.key === "ArrowDown" ? 1 : -1;
|
|
382
|
+
const nextIndex =
|
|
383
|
+
(currentIndex + step + focusables.length) % focusables.length;
|
|
384
|
+
|
|
385
|
+
focusables[nextIndex]?.focus();
|
|
271
386
|
};
|
|
272
387
|
|
|
273
388
|
const handleClickOutside = (e: MouseEvent) => {
|
|
274
389
|
if (Date.now() - lastScrollAt.value < 250) return;
|
|
275
|
-
|
|
390
|
+
|
|
391
|
+
const target = e.target as HTMLElement;
|
|
392
|
+
|
|
276
393
|
if (refOptions.value?.contains(target)) return;
|
|
277
394
|
if (dropdownRef?.value?.contains(target)) return;
|
|
278
|
-
|
|
279
|
-
|
|
395
|
+
if (target.closest?.("[select-dropdown]")) return;
|
|
396
|
+
|
|
280
397
|
open.value = false;
|
|
281
398
|
};
|
|
282
399
|
|
|
@@ -284,34 +401,34 @@ export const useSelect = <T extends string | string[]>(
|
|
|
284
401
|
lastScrollAt.value = Date.now();
|
|
285
402
|
};
|
|
286
403
|
|
|
404
|
+
const addWindowListeners = () => {
|
|
405
|
+
window.addEventListener("click", handleClickOutside);
|
|
406
|
+
window.addEventListener("scroll", markScroll, true);
|
|
407
|
+
window.addEventListener("wheel", markScroll, { passive: true });
|
|
408
|
+
window.addEventListener("touchmove", markScroll, { passive: true });
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
const removeWindowListeners = () => {
|
|
412
|
+
window.removeEventListener("click", handleClickOutside);
|
|
413
|
+
window.removeEventListener("scroll", markScroll, true);
|
|
414
|
+
window.removeEventListener("wheel", markScroll);
|
|
415
|
+
window.removeEventListener("touchmove", markScroll);
|
|
416
|
+
};
|
|
417
|
+
|
|
287
418
|
watch(
|
|
288
419
|
() => open.value,
|
|
289
|
-
(isOpen,
|
|
290
|
-
if (!isOpen)
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
requestAnimationFrame(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
window.addEventListener("wheel", markScroll, { passive: true });
|
|
298
|
-
window.addEventListener("touchmove", markScroll, { passive: true });
|
|
299
|
-
});
|
|
300
|
-
onWatcherCleanup(() => {
|
|
301
|
-
window.removeEventListener("click", handleClickOutside);
|
|
302
|
-
window.removeEventListener("scroll", markScroll, true);
|
|
303
|
-
window.removeEventListener("wheel", markScroll as any);
|
|
304
|
-
window.removeEventListener("touchmove", markScroll as any);
|
|
305
|
-
});
|
|
420
|
+
(isOpen, wasOpen) => {
|
|
421
|
+
if (!isOpen) expandedItems.value = [];
|
|
422
|
+
|
|
423
|
+
if (wasOpen) return;
|
|
424
|
+
|
|
425
|
+
requestAnimationFrame(addWindowListeners);
|
|
426
|
+
|
|
427
|
+
onWatcherCleanup(removeWindowListeners);
|
|
306
428
|
},
|
|
307
429
|
);
|
|
308
430
|
|
|
309
|
-
onUnmounted(
|
|
310
|
-
window.removeEventListener("click", handleClickOutside);
|
|
311
|
-
window.removeEventListener("scroll", markScroll, true);
|
|
312
|
-
window.removeEventListener("wheel", markScroll as any);
|
|
313
|
-
window.removeEventListener("touchmove", markScroll as any);
|
|
314
|
-
});
|
|
431
|
+
onUnmounted(removeWindowListeners);
|
|
315
432
|
|
|
316
433
|
return {
|
|
317
434
|
open,
|
|
@@ -321,8 +438,13 @@ export const useSelect = <T extends string | string[]>(
|
|
|
321
438
|
expandedItems,
|
|
322
439
|
effectiveExpandedItems,
|
|
323
440
|
customAddVisible,
|
|
441
|
+
selectedValues,
|
|
442
|
+
hasMax,
|
|
443
|
+
isAtMax,
|
|
444
|
+
minSelected,
|
|
324
445
|
isSelected,
|
|
325
446
|
isPartiallySelected,
|
|
447
|
+
isBlocked,
|
|
326
448
|
getLabel,
|
|
327
449
|
toggleExpand,
|
|
328
450
|
handleOpen,
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type UixySelectOptionType,
|
|
5
5
|
type UixySingleSelectProps,
|
|
6
6
|
type UixyMultipleSelectProps,
|
|
7
|
+
type UixySelectMaxBehavior,
|
|
7
8
|
} from "./Select.types";
|
|
8
9
|
|
|
9
10
|
export {
|
|
@@ -12,4 +13,5 @@ export {
|
|
|
12
13
|
type UixySelectOptionType,
|
|
13
14
|
type UixySingleSelectProps,
|
|
14
15
|
type UixyMultipleSelectProps,
|
|
16
|
+
type UixySelectMaxBehavior,
|
|
15
17
|
};
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
:style="{ zIndex }"
|
|
12
12
|
data-uixy-overlay
|
|
13
13
|
@click.self="handleClick"
|
|
14
|
-
class="fixed left-0 top-0 size-full bg-white/5 backdrop-blur-[2px] dark:bg-gray-900/5"
|
|
14
|
+
class="fixed left-0 top-0 size-full bg-white/5 [html[data-uixy-gpu=on]_&]:backdrop-blur-[2px] dark:bg-gray-900/5"
|
|
15
15
|
/>
|
|
16
16
|
<motion.div
|
|
17
17
|
initial="initial"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
<script setup lang="ts">
|
|
38
38
|
import { AnimatePresence, motion } from "motion-v";
|
|
39
39
|
import { useScale } from "../Scale";
|
|
40
|
-
import { useOverlayLayer } from "~/composables";
|
|
40
|
+
import { useOverlayLayer, useGpuAcceleration } from "~/composables";
|
|
41
41
|
import type { UixySheetProps } from "./Sheet.types";
|
|
42
42
|
import { sheetStyles } from "./Sheet.styles";
|
|
43
43
|
|
|
@@ -72,6 +72,8 @@
|
|
|
72
72
|
|
|
73
73
|
const { zIndex, acquire, release } = useOverlayLayer();
|
|
74
74
|
|
|
75
|
+
useGpuAcceleration();
|
|
76
|
+
|
|
75
77
|
const open = defineModel<boolean>();
|
|
76
78
|
|
|
77
79
|
const handleClick = () => {
|
|
@@ -2,11 +2,17 @@ export * from "./Accordion";
|
|
|
2
2
|
export * from "./Alert";
|
|
3
3
|
export * from "./Avatar";
|
|
4
4
|
export * from "./Badge";
|
|
5
|
+
export * from "./Breadcrumb";
|
|
5
6
|
export * from "./Button";
|
|
6
7
|
export * from "./Calendar";
|
|
7
8
|
export * from "./Card";
|
|
9
|
+
export * from "./Chart";
|
|
8
10
|
export * from "./Checkbox";
|
|
11
|
+
export * from "./ColorPicker";
|
|
9
12
|
export * from "./Command";
|
|
13
|
+
export * from "./DatePicker";
|
|
14
|
+
export * from "./DateRangePicker";
|
|
15
|
+
export * from "./FileUpload";
|
|
10
16
|
export * from "./Icon";
|
|
11
17
|
export * from "./IconButton";
|
|
12
18
|
export * from "./Input";
|
|
@@ -18,12 +24,14 @@ export * from "./PieChart";
|
|
|
18
24
|
export * from "./Popover";
|
|
19
25
|
export * from "./Radio";
|
|
20
26
|
export * from "./Scale";
|
|
27
|
+
export * from "./SegmentedControl";
|
|
21
28
|
export * from "./Select";
|
|
22
29
|
export * from "./Separator";
|
|
23
30
|
export * from "./Sheet";
|
|
24
31
|
export * from "./Skeleton";
|
|
25
32
|
export * from "./Slider";
|
|
26
33
|
export * from "./Switch";
|
|
34
|
+
export * from "./Table";
|
|
27
35
|
export * from "./TableOfContents";
|
|
28
36
|
export * from "./Tabs";
|
|
29
37
|
export * from "./Textarea";
|
|
@@ -32,4 +40,3 @@ export * from "./TimePicker";
|
|
|
32
40
|
export * from "./Toast";
|
|
33
41
|
export * from "./Toggle";
|
|
34
42
|
export * from "./Tooltip";
|
|
35
|
-
export * from "./ColorPicker";
|
|
@@ -130,12 +130,12 @@
|
|
|
130
130
|
"name": "Modal",
|
|
131
131
|
"related-components": [],
|
|
132
132
|
"packages": ["motion-v"],
|
|
133
|
-
"composables": ["useOverlayLayer"]
|
|
133
|
+
"composables": ["useOverlayLayer", "useGpuAcceleration"]
|
|
134
134
|
},
|
|
135
135
|
{
|
|
136
136
|
"name": "PieChart",
|
|
137
137
|
"related-components": [],
|
|
138
|
-
"packages": [
|
|
138
|
+
"packages": [],
|
|
139
139
|
"composables": []
|
|
140
140
|
},
|
|
141
141
|
{
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
"name": "Sheet",
|
|
179
179
|
"related-components": ["Scale"],
|
|
180
180
|
"packages": ["motion-v"],
|
|
181
|
-
"composables": ["useOverlayLayer"]
|
|
181
|
+
"composables": ["useOverlayLayer", "useGpuAcceleration"]
|
|
182
182
|
},
|
|
183
183
|
{
|
|
184
184
|
"name": "Skeleton",
|
|
@@ -213,7 +213,7 @@
|
|
|
213
213
|
{
|
|
214
214
|
"name": "Tabs",
|
|
215
215
|
"related-components": [],
|
|
216
|
-
"packages": ["motion-v"],
|
|
216
|
+
"packages": ["motion-v", "uuid"],
|
|
217
217
|
"composables": []
|
|
218
218
|
},
|
|
219
219
|
{
|