design-system-next 2.7.43 → 2.7.44
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/dist/design-system-next.js +3711 -3319
- package/dist/design-system-next.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/dist/package.json.d.ts +1 -1
- package/package.json +1 -1
- package/src/assets/styles/tailwind.css +21 -1
- package/src/components/input/input.ts +6 -2
- package/src/components/input/input.vue +11 -6
- package/src/components/input/use-input.ts +33 -3
- package/src/components/select/select-laderrized/select-laderrized.ts +122 -0
- package/src/components/select/select-laderrized/select-laderrized.vue +110 -0
- package/src/components/select/select-laderrized/use-select-laderrized.ts +499 -0
- package/src/components/select/select-multiple/select-multiple.ts +122 -0
- package/src/components/select/select-multiple/select-multiple.vue +110 -0
- package/src/components/select/select-multiple/use-select-multiple.ts +499 -0
- package/src/components/select/select.ts +105 -0
- package/src/components/select/select.vue +90 -0
- package/src/components/select/use-select.ts +445 -0
- package/src/examples/select-number-multi-select.vue +71 -0
- package/src/components/dropdown/__tests__/dropdown-fixes.spec.ts +0 -106
- package/src/components/dropdown/__tests__/dropdown-value-types.spec.ts +0 -213
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div></div>
|
|
3
|
+
</template>
|
|
4
|
+
<!-- <template>
|
|
5
|
+
<Menu
|
|
6
|
+
:shown="selectPopperState"
|
|
7
|
+
aria-id="select-wrapper"
|
|
8
|
+
distance="4"
|
|
9
|
+
:placement="props.placement"
|
|
10
|
+
:triggers="[]"
|
|
11
|
+
:popper-hide-triggers="[]"
|
|
12
|
+
:auto-hide="false"
|
|
13
|
+
:disabled="isSelectPopperDisabled"
|
|
14
|
+
:container="`#${props.id}`"
|
|
15
|
+
:strategy="
|
|
16
|
+
props.popperStrategy === 'fixed' || props.popperStrategy === 'absolute' ? props.popperStrategy : 'absolute'
|
|
17
|
+
"
|
|
18
|
+
:delay="0"
|
|
19
|
+
:style="{
|
|
20
|
+
position: props.wrapperPosition,
|
|
21
|
+
width: props.width,
|
|
22
|
+
}"
|
|
23
|
+
>
|
|
24
|
+
<div @click="selectPopperState = true">
|
|
25
|
+
{{ selectedListItems }}
|
|
26
|
+
|
|
27
|
+
<spr-input
|
|
28
|
+
v-model="inputText"
|
|
29
|
+
label="Select Numbers"
|
|
30
|
+
:placeholder="props.placeholder"
|
|
31
|
+
:readonly="props.readonly"
|
|
32
|
+
:disabled="props.disabled"
|
|
33
|
+
autocomplete="off"
|
|
34
|
+
/>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div
|
|
38
|
+
:id="props.id"
|
|
39
|
+
:style="{
|
|
40
|
+
width: props.popperWidth,
|
|
41
|
+
}"
|
|
42
|
+
></div>
|
|
43
|
+
|
|
44
|
+
<template #popper>
|
|
45
|
+
<div
|
|
46
|
+
ref="selectRef"
|
|
47
|
+
:class="[
|
|
48
|
+
(!props.ladderized || isLadderizedSearch) && 'spr-p-2',
|
|
49
|
+
'spr-grid spr-max-h-[300px] spr-gap-0.5 spr-overflow-y-auto spr-overflow-x-hidden',
|
|
50
|
+
]"
|
|
51
|
+
>
|
|
52
|
+
<template v-if="selectMenuList.length > 0">
|
|
53
|
+
<spr-list
|
|
54
|
+
v-if="!props.ladderized || isLadderizedSearch"
|
|
55
|
+
v-model="selectedListItems"
|
|
56
|
+
:menu-list="selectMenuList"
|
|
57
|
+
:group-items-by="props.groupItemsBy"
|
|
58
|
+
:multi-select="props.multiSelect"
|
|
59
|
+
:pre-selected-items="selectValue"
|
|
60
|
+
@update:model-value="handleSelectedItem"
|
|
61
|
+
/>
|
|
62
|
+
<spr-ladderized-list
|
|
63
|
+
v-else
|
|
64
|
+
v-model="selectValue"
|
|
65
|
+
:ladderized="props.ladderized"
|
|
66
|
+
:menu-list="selectMenuList"
|
|
67
|
+
:remove-current-level-in-back-label="removeCurrentLevelInBackLabel"
|
|
68
|
+
@update:model-value="handleSelectedLadderizedItem"
|
|
69
|
+
/>
|
|
70
|
+
</template>
|
|
71
|
+
<template v-else>
|
|
72
|
+
<div class="spr-flex spr-items-center spr-justify-center spr-p-2 spr-text-center">
|
|
73
|
+
<span class="spr-body-sm-regular spr-m-0">No results found</span>
|
|
74
|
+
</div>
|
|
75
|
+
</template>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
</Menu>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
<script lang="ts" setup>
|
|
82
|
+
import { Menu } from 'floating-vue';
|
|
83
|
+
|
|
84
|
+
import 'floating-vue/dist/style.css';
|
|
85
|
+
|
|
86
|
+
import SprInput from '../../input/input.vue';
|
|
87
|
+
import SprList from '../../list/list.vue';
|
|
88
|
+
import SprLadderizedList from '../../list/ladderized-list/ladderized-list.vue';
|
|
89
|
+
|
|
90
|
+
import { selectPropTypes, selectEmitTypes } from './select-multiple';
|
|
91
|
+
|
|
92
|
+
import { useSelect } from './use-select-multiple';
|
|
93
|
+
|
|
94
|
+
const props = defineProps(selectPropTypes);
|
|
95
|
+
const emit = defineEmits(selectEmitTypes);
|
|
96
|
+
|
|
97
|
+
const {
|
|
98
|
+
selectPopperState,
|
|
99
|
+
selectRef,
|
|
100
|
+
selectMenuList,
|
|
101
|
+
isSelectPopperDisabled,
|
|
102
|
+
selectedListItems,
|
|
103
|
+
handleSelectedItem,
|
|
104
|
+
handleSelectedLadderizedItem,
|
|
105
|
+
selectValue,
|
|
106
|
+
removeCurrentLevelInBackLabel,
|
|
107
|
+
isLadderizedSearch,
|
|
108
|
+
inputText,
|
|
109
|
+
} = useSelect(props, emit);
|
|
110
|
+
</script> -->
|
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
// import { ref, toRefs, computed, onMounted, watch } from 'vue';
|
|
2
|
+
// import { onClickOutside, useInfiniteScroll, useVModel } from '@vueuse/core';
|
|
3
|
+
|
|
4
|
+
// import type { SetupContext } from 'vue';
|
|
5
|
+
// import type { SelectPropTypes, SelectEmitTypes } from './select-multiple';
|
|
6
|
+
// import type { MenuListType } from '../list/list';
|
|
7
|
+
|
|
8
|
+
// export const useSelect = (props: SelectPropTypes, emit: SetupContext<SelectEmitTypes>['emit']) => {
|
|
9
|
+
// const {
|
|
10
|
+
// menuList,
|
|
11
|
+
// searchString,
|
|
12
|
+
// disabled,
|
|
13
|
+
// multiSelect,
|
|
14
|
+
// removeCurrentLevelInBackLabel,
|
|
15
|
+
// ladderized,
|
|
16
|
+
// textField,
|
|
17
|
+
// valueField,
|
|
18
|
+
// } = toRefs(props);
|
|
19
|
+
|
|
20
|
+
// // Select component ref variables
|
|
21
|
+
// const selectValue = useVModel(props, 'modelValue', emit); // v-model value of Select component
|
|
22
|
+
// const selectRef = ref<HTMLDivElement | null>(null);
|
|
23
|
+
// const inputText = ref(''); // v-model value of Input component
|
|
24
|
+
|
|
25
|
+
// // List component ref variables
|
|
26
|
+
// const selectedListItems = ref<MenuListType[]>([]); // v-model value of the list component
|
|
27
|
+
// const selectMenuList = ref<MenuListType[]>([]); // menu list for the list component
|
|
28
|
+
|
|
29
|
+
// // Normalized value for internal use - always an array
|
|
30
|
+
// const normalizedValue = computed(() => {
|
|
31
|
+
// // If already an array, use it
|
|
32
|
+
// if (Array.isArray(selectValue.value)) {
|
|
33
|
+
// return selectValue.value;
|
|
34
|
+
// }
|
|
35
|
+
// // If not an array but has a value, make it a single-item array
|
|
36
|
+
// if (selectValue.value !== undefined && selectValue.value !== null) {
|
|
37
|
+
// return [selectValue.value];
|
|
38
|
+
// }
|
|
39
|
+
// // Default empty array
|
|
40
|
+
// return [];
|
|
41
|
+
// });
|
|
42
|
+
|
|
43
|
+
// // Compatibility layer for pre-selected items (List component expects string[] format)
|
|
44
|
+
// const compatPreSelectedItems = computed(() => {
|
|
45
|
+
// // For ladderized Select with search, handle the special format
|
|
46
|
+
// if (props.ladderized && Array.isArray(selectValue.value) && selectValue.value.length === 2) {
|
|
47
|
+
// // We return only the second value from the [subvalue, value] format which is the actual selected value
|
|
48
|
+
// return [selectValue.value[1]?.toString() || ''];
|
|
49
|
+
// }
|
|
50
|
+
|
|
51
|
+
// // For regular arrays (multi-select)
|
|
52
|
+
// if (Array.isArray(selectValue.value)) {
|
|
53
|
+
// return selectValue.value.map((item) => {
|
|
54
|
+
// if (item === undefined || item === null) return '';
|
|
55
|
+
|
|
56
|
+
// // For numbers, preserve the original number value instead of converting to string
|
|
57
|
+
// if (typeof item === 'number') return item;
|
|
58
|
+
|
|
59
|
+
// // For objects, pass the original object reference
|
|
60
|
+
// // This is key for proper multi-select of objects
|
|
61
|
+
// if (typeof item === 'object') return item;
|
|
62
|
+
|
|
63
|
+
// // For strings, pass as is
|
|
64
|
+
// return item.toString();
|
|
65
|
+
// });
|
|
66
|
+
// }
|
|
67
|
+
|
|
68
|
+
// // For single values (single-select)
|
|
69
|
+
// return selectValue.value !== undefined && selectValue.value !== null
|
|
70
|
+
// ? [
|
|
71
|
+
// typeof selectValue.value === 'object'
|
|
72
|
+
// ? // Pass object reference directly instead of stringifying
|
|
73
|
+
// selectValue.value
|
|
74
|
+
// : // For numbers, preserve the original number value
|
|
75
|
+
// typeof selectValue.value === 'number'
|
|
76
|
+
// ? selectValue.value
|
|
77
|
+
// : selectValue.value.toString(),
|
|
78
|
+
// ]
|
|
79
|
+
// : [];
|
|
80
|
+
// });
|
|
81
|
+
|
|
82
|
+
// // Popper state
|
|
83
|
+
// const selectPopperState = ref<boolean>(false);
|
|
84
|
+
// const isSelectPopperDisabled = computed(() => disabled.value);
|
|
85
|
+
|
|
86
|
+
// const isLadderizedSearch = computed(
|
|
87
|
+
// () => ladderized.value && searchString.value !== '' && normalizedValue.value.length === 0,
|
|
88
|
+
// );
|
|
89
|
+
|
|
90
|
+
// const processMenuList = () => {
|
|
91
|
+
// // Handle empty array or non-array values
|
|
92
|
+
// if (!menuList.value || !Array.isArray(menuList.value) || menuList.value.length === 0) {
|
|
93
|
+
// selectMenuList.value = [];
|
|
94
|
+
// return;
|
|
95
|
+
// }
|
|
96
|
+
|
|
97
|
+
// // If ladderized is true and menu list items already conform to MenuListType, don't transform
|
|
98
|
+
// if (ladderized.value) {
|
|
99
|
+
// // Verify the items have the required structure for ladderized lists
|
|
100
|
+
// const allValid = menuList.value.every(
|
|
101
|
+
// (item) => typeof item === 'object' && item !== null && 'text' in item && 'value' in item,
|
|
102
|
+
// );
|
|
103
|
+
|
|
104
|
+
// if (allValid) {
|
|
105
|
+
// selectMenuList.value = menuList.value as MenuListType[];
|
|
106
|
+
// } else {
|
|
107
|
+
// console.warn('Ladderized Select requires menu items in {text, value} format');
|
|
108
|
+
// selectMenuList.value = [];
|
|
109
|
+
// }
|
|
110
|
+
// return;
|
|
111
|
+
// }
|
|
112
|
+
|
|
113
|
+
// const firstItem = menuList.value[0];
|
|
114
|
+
|
|
115
|
+
// // Handle array of strings
|
|
116
|
+
// if (typeof firstItem === 'string') {
|
|
117
|
+
// selectMenuList.value = (menuList.value as string[]).map((item) => ({
|
|
118
|
+
// text: item,
|
|
119
|
+
// value: item,
|
|
120
|
+
// }));
|
|
121
|
+
// return;
|
|
122
|
+
// }
|
|
123
|
+
|
|
124
|
+
// // Handle array of numbers
|
|
125
|
+
// if (typeof firstItem === 'number') {
|
|
126
|
+
// selectMenuList.value = (menuList.value as number[]).map((item) => ({
|
|
127
|
+
// text: item.toString(),
|
|
128
|
+
// value: item, // Keep the value as a number instead of converting to string
|
|
129
|
+
// }));
|
|
130
|
+
// return;
|
|
131
|
+
// }
|
|
132
|
+
|
|
133
|
+
// // Handle array of objects with dynamic attributes
|
|
134
|
+
// if (typeof firstItem === 'object' && firstItem !== null) {
|
|
135
|
+
// // Check if it's already in MenuListType format
|
|
136
|
+
// if ('text' in firstItem && 'value' in firstItem) {
|
|
137
|
+
// selectMenuList.value = menuList.value as MenuListType[];
|
|
138
|
+
// return;
|
|
139
|
+
// }
|
|
140
|
+
|
|
141
|
+
// // Transform to MenuListType format using textField and valueField
|
|
142
|
+
// selectMenuList.value = (menuList.value as Record<string, unknown>[]).map((item) => {
|
|
143
|
+
// const displayText = item[textField.value] || 'Unnamed';
|
|
144
|
+
// // Use the specified value field if available, otherwise use the entire object
|
|
145
|
+
// const itemValue = valueField.value && item[valueField.value] !== undefined ? item[valueField.value] : item;
|
|
146
|
+
|
|
147
|
+
// return {
|
|
148
|
+
// text: displayText,
|
|
149
|
+
// value: typeof itemValue === 'object' ? JSON.stringify(itemValue) : itemValue.toString(),
|
|
150
|
+
// _originalObject: item, // Store the original object for reference
|
|
151
|
+
// };
|
|
152
|
+
// });
|
|
153
|
+
// return;
|
|
154
|
+
// }
|
|
155
|
+
|
|
156
|
+
// // Default fallback
|
|
157
|
+
// selectMenuList.value = menuList.value as MenuListType[];
|
|
158
|
+
// };
|
|
159
|
+
|
|
160
|
+
// watch(menuList, () => {
|
|
161
|
+
// processMenuList();
|
|
162
|
+
// });
|
|
163
|
+
|
|
164
|
+
// const handleSearch = () => {
|
|
165
|
+
// if (menuList.value && menuList.value.length === 0) {
|
|
166
|
+
// return;
|
|
167
|
+
// }
|
|
168
|
+
|
|
169
|
+
// if (!multiSelect.value) {
|
|
170
|
+
// singleSelectSearch();
|
|
171
|
+
// } else {
|
|
172
|
+
// // Process menu list for searching
|
|
173
|
+
// processMenuList();
|
|
174
|
+
|
|
175
|
+
// // Handle multi-select search - filter based on search string
|
|
176
|
+
// if (searchString.value.trim() !== '') {
|
|
177
|
+
// selectMenuList.value = getFilteredMenuList(selectMenuList.value);
|
|
178
|
+
// }
|
|
179
|
+
// }
|
|
180
|
+
// };
|
|
181
|
+
|
|
182
|
+
// const singleSelectSearch = () => {
|
|
183
|
+
// if (props.ladderized) {
|
|
184
|
+
// ladderizedSearch();
|
|
185
|
+
// } else {
|
|
186
|
+
// basicSearch();
|
|
187
|
+
// }
|
|
188
|
+
// };
|
|
189
|
+
|
|
190
|
+
// const basicSearch = () => {
|
|
191
|
+
// // Process menu list first
|
|
192
|
+
// processMenuList();
|
|
193
|
+
|
|
194
|
+
// // Then filter based on search string
|
|
195
|
+
// if (searchString.value.trim() !== '') {
|
|
196
|
+
// selectMenuList.value = getFilteredMenuList(selectMenuList.value);
|
|
197
|
+
// }
|
|
198
|
+
// };
|
|
199
|
+
|
|
200
|
+
// const ladderizedSearch = () => {
|
|
201
|
+
// //revert to initial list if search string is empty or selectValue is not empty
|
|
202
|
+
// if (searchString.value === '' || normalizedValue.value.length > 0) {
|
|
203
|
+
// selectMenuList.value = [...menuList.value] as MenuListType[];
|
|
204
|
+
// return;
|
|
205
|
+
// }
|
|
206
|
+
|
|
207
|
+
// const menuListSubLevels = getAllSublevelItems(menuList.value as MenuListType[]);
|
|
208
|
+
|
|
209
|
+
// const filteredMenuList = getFilteredMenuList(menuList.value as MenuListType[]);
|
|
210
|
+
// const filteredMenuListSubLevels = getFilteredMenuList(menuListSubLevels);
|
|
211
|
+
|
|
212
|
+
// if (filteredMenuList.length > 0) {
|
|
213
|
+
// //if there is a match at the top level of the menuList
|
|
214
|
+
// selectMenuList.value = getAllSublevelItems(filteredMenuList);
|
|
215
|
+
// } else if (filteredMenuListSubLevels.length > 0) {
|
|
216
|
+
// //if there is a match at the 2nd level (sublevel of a menuList item) of the menuList
|
|
217
|
+
// selectMenuList.value = filteredMenuListSubLevels;
|
|
218
|
+
// } else {
|
|
219
|
+
// selectMenuList.value = [];
|
|
220
|
+
// }
|
|
221
|
+
// };
|
|
222
|
+
|
|
223
|
+
// // compile sublevel items from menuList to a single array
|
|
224
|
+
// // and add text and value of the parent item to all sublevel items as subtext and subvalue
|
|
225
|
+
// const getAllSublevelItems = (menuList: MenuListType[]) => {
|
|
226
|
+
// return menuList.reduce<MenuListType[]>((currentValue, currentItem) => {
|
|
227
|
+
// if (currentItem.sublevel) {
|
|
228
|
+
// const mappedSublevel = currentItem.sublevel.map((sublevelItem: MenuListType) => ({
|
|
229
|
+
// ...sublevelItem, //text and value of a sublevel item
|
|
230
|
+
// subtext: currentItem.text, // text of parent of a sublevel item
|
|
231
|
+
// subvalue: typeof currentItem.value === 'string' ? currentItem.value : String(currentItem.value), // value of parent of a sublevel item as string
|
|
232
|
+
// }));
|
|
233
|
+
|
|
234
|
+
// return [...currentValue, ...mappedSublevel];
|
|
235
|
+
// }
|
|
236
|
+
|
|
237
|
+
// return currentValue;
|
|
238
|
+
// }, [] as MenuListType[]);
|
|
239
|
+
// };
|
|
240
|
+
|
|
241
|
+
// // filter list based on search string and menuList/sublevel texts
|
|
242
|
+
// const getFilteredMenuList = (list: MenuListType[]) => {
|
|
243
|
+
// return list.filter((item: MenuListType) => {
|
|
244
|
+
// const searchTerm = searchString.value.toLowerCase().trim();
|
|
245
|
+
// return item.text.toLowerCase().includes(searchTerm);
|
|
246
|
+
// });
|
|
247
|
+
// };
|
|
248
|
+
|
|
249
|
+
// watch(searchString, () => {
|
|
250
|
+
// handleSearch();
|
|
251
|
+
// });
|
|
252
|
+
|
|
253
|
+
// onClickOutside(selectRef, () => {
|
|
254
|
+
// selectPopperState.value = false;
|
|
255
|
+
// });
|
|
256
|
+
|
|
257
|
+
// useInfiniteScroll(
|
|
258
|
+
// selectRef,
|
|
259
|
+
// () => {
|
|
260
|
+
// emit('infinite-scroll-trigger', true);
|
|
261
|
+
// },
|
|
262
|
+
// { distance: 10 },
|
|
263
|
+
// );
|
|
264
|
+
|
|
265
|
+
// // Handle selected item for simple list component
|
|
266
|
+
// const handleSelectedItem = (selectedItems: MenuListType[]) => {
|
|
267
|
+
// if (!props.ladderized) {
|
|
268
|
+
// // Determine the type of value to emit based on the original data type and multiSelect
|
|
269
|
+
// if (multiSelect.value) {
|
|
270
|
+
// // For multi-select, always return an array
|
|
271
|
+
// const values = selectedItems.map((item) => {
|
|
272
|
+
// // If we stored the original object, use it
|
|
273
|
+
// if ('_originalObject' in item) {
|
|
274
|
+
// return item._originalObject;
|
|
275
|
+
// }
|
|
276
|
+
|
|
277
|
+
// // For simple types, handle value type conversion properly
|
|
278
|
+
// const val = item.value;
|
|
279
|
+
|
|
280
|
+
// // If it's already a number, keep it as a number
|
|
281
|
+
// if (typeof val === 'number') {
|
|
282
|
+
// return val;
|
|
283
|
+
// }
|
|
284
|
+
|
|
285
|
+
// // For strings that look like numbers, convert them
|
|
286
|
+
// if (typeof val === 'string' && !isNaN(Number(val)) && val.trim() !== '') {
|
|
287
|
+
// // Only convert if it looks like a proper number format
|
|
288
|
+
// if (/^-?\d+(\.\d+)?$/.test(val)) {
|
|
289
|
+
// return Number(val);
|
|
290
|
+
// }
|
|
291
|
+
// }
|
|
292
|
+
|
|
293
|
+
// // Return the original value for all other cases
|
|
294
|
+
// return val;
|
|
295
|
+
// });
|
|
296
|
+
|
|
297
|
+
// selectValue.value = values as (string | number | Record<string, unknown>)[];
|
|
298
|
+
// } else {
|
|
299
|
+
// // For single-select
|
|
300
|
+
// if (selectedItems.length === 0) {
|
|
301
|
+
// selectValue.value = props.multiSelect ? [] : '';
|
|
302
|
+
// return;
|
|
303
|
+
// }
|
|
304
|
+
|
|
305
|
+
// const item = selectedItems[0];
|
|
306
|
+
|
|
307
|
+
// // If we stored the original object, use it
|
|
308
|
+
// if ('_originalObject' in item) {
|
|
309
|
+
// selectValue.value = item._originalObject as Record<string, unknown>;
|
|
310
|
+
// } else {
|
|
311
|
+
// // For simple types, return the value (try to convert number strings to numbers)
|
|
312
|
+
// const val = item.value;
|
|
313
|
+
// if (typeof val === 'string' && !isNaN(Number(val)) && val.trim() !== '') {
|
|
314
|
+
// selectValue.value = Number(val);
|
|
315
|
+
// } else {
|
|
316
|
+
// selectValue.value = val;
|
|
317
|
+
// }
|
|
318
|
+
// }
|
|
319
|
+
// }
|
|
320
|
+
// } else if (props.ladderized) {
|
|
321
|
+
// if (props.searchString !== '') {
|
|
322
|
+
// // generate select value if ladderized with search string
|
|
323
|
+
// const subvalue = selectedItems[0]?.subvalue;
|
|
324
|
+
// const value = selectedItems[0]?.value;
|
|
325
|
+
// if (subvalue !== undefined && value !== undefined) {
|
|
326
|
+
// selectValue.value = [subvalue, value] as [string, string | number];
|
|
327
|
+
// }
|
|
328
|
+
// } else {
|
|
329
|
+
// // For regular ladderized select selection without search
|
|
330
|
+
// if (selectedItems.length > 0) {
|
|
331
|
+
// const item = selectedItems[0];
|
|
332
|
+
// // Use the value directly for ladderized items
|
|
333
|
+
// if (item && item.value) {
|
|
334
|
+
// selectValue.value = item.value;
|
|
335
|
+
// }
|
|
336
|
+
// }
|
|
337
|
+
// }
|
|
338
|
+
// }
|
|
339
|
+
|
|
340
|
+
// // Always close select for single selection, regardless of value type
|
|
341
|
+
// if (!multiSelect.value) {
|
|
342
|
+
// setTimeout(() => {
|
|
343
|
+
// selectPopperState.value = false;
|
|
344
|
+
// }, 10);
|
|
345
|
+
// }
|
|
346
|
+
// };
|
|
347
|
+
|
|
348
|
+
// // Handle selected item for ladderized list component
|
|
349
|
+
// const handleSelectedLadderizedItem = (selectedItems: string[]) => {
|
|
350
|
+
// // Update the model value with the selected ladderized items
|
|
351
|
+
// if (selectedItems.length > 0) {
|
|
352
|
+
// selectValue.value = selectedItems;
|
|
353
|
+
// }
|
|
354
|
+
|
|
355
|
+
// // If item is from last sublevel, close the select
|
|
356
|
+
// if (checkIfItemFromLastSublevel(selectedItems)) {
|
|
357
|
+
// selectPopperState.value = false;
|
|
358
|
+
// }
|
|
359
|
+
// };
|
|
360
|
+
|
|
361
|
+
// const checkIfItemFromLastSublevel = (selectedItems: string[]) => {
|
|
362
|
+
// let selectedItemsObject = selectMenuList.value;
|
|
363
|
+
|
|
364
|
+
// // Traverse to the last item in the selectedItems array
|
|
365
|
+
// selectedItems.forEach((selectedItem) => {
|
|
366
|
+
// selectedItemsObject = selectedItemsObject.find((item) => selectedItem === item.value)?.sublevel ?? [];
|
|
367
|
+
// });
|
|
368
|
+
|
|
369
|
+
// // If there is a sublevel, return false
|
|
370
|
+
// if (selectedItemsObject.length > 0) {
|
|
371
|
+
// return false;
|
|
372
|
+
// }
|
|
373
|
+
|
|
374
|
+
// return true;
|
|
375
|
+
// };
|
|
376
|
+
|
|
377
|
+
// // Update selected items when model value changes externally
|
|
378
|
+
// const updateSelectedItemsFromValue = () => {
|
|
379
|
+
// if (!selectMenuList.value.length) return;
|
|
380
|
+
|
|
381
|
+
// const values = normalizedValue.value;
|
|
382
|
+
// if (!values || !values.length) {
|
|
383
|
+
// selectedListItems.value = [];
|
|
384
|
+
// return;
|
|
385
|
+
// }
|
|
386
|
+
|
|
387
|
+
// // Store both original values and string versions for flexible matching
|
|
388
|
+
// const valueData = values.map((val) => {
|
|
389
|
+
// if (val === undefined || val === null) return { original: '', string: '' };
|
|
390
|
+
|
|
391
|
+
// // For objects, use JSON string representation
|
|
392
|
+
// if (typeof val === 'object') {
|
|
393
|
+
// return {
|
|
394
|
+
// original: val,
|
|
395
|
+
// string: JSON.stringify(val),
|
|
396
|
+
// isObject: true,
|
|
397
|
+
// id: 'id' in val ? val.id : undefined,
|
|
398
|
+
// };
|
|
399
|
+
// }
|
|
400
|
+
|
|
401
|
+
// // For numbers and strings, keep original and string versions
|
|
402
|
+
// return {
|
|
403
|
+
// original: val,
|
|
404
|
+
// string: val.toString(),
|
|
405
|
+
// isObject: false,
|
|
406
|
+
// };
|
|
407
|
+
// });
|
|
408
|
+
|
|
409
|
+
// // Extract just string values for comparison
|
|
410
|
+
// const valueStrings = valueData.map((v) => v.string);
|
|
411
|
+
|
|
412
|
+
// if (props.ladderized) {
|
|
413
|
+
// // Special handling for ladderized selects
|
|
414
|
+
// if (Array.isArray(selectValue.value) && selectValue.value.length === 2) {
|
|
415
|
+
// // Handle [subvalue, value] format used in ladderized selects with search
|
|
416
|
+
// const subvalue = selectValue.value[0]?.toString() || '';
|
|
417
|
+
// const value = selectValue.value[1]?.toString() || '';
|
|
418
|
+
|
|
419
|
+
// selectedListItems.value = selectMenuList.value.filter((item) => {
|
|
420
|
+
// return item.value === value && (!item.subvalue || item.subvalue === subvalue);
|
|
421
|
+
// });
|
|
422
|
+
// } else {
|
|
423
|
+
// // Regular ladderized select value
|
|
424
|
+
// selectedListItems.value = selectMenuList.value.filter((item) => {
|
|
425
|
+
// // Convert both to strings for comparison or check direct equality for numbers
|
|
426
|
+
// if (typeof item.value === 'number') {
|
|
427
|
+
// return valueData.some((v) => v.original === item.value || v.string === String(item.value));
|
|
428
|
+
// } else {
|
|
429
|
+
// return valueStrings.includes(String(item.value));
|
|
430
|
+
// }
|
|
431
|
+
// });
|
|
432
|
+
// }
|
|
433
|
+
// } else {
|
|
434
|
+
// // Regular Select value
|
|
435
|
+
// selectedListItems.value = selectMenuList.value.filter((item) => {
|
|
436
|
+
// // Handle objects with _originalObject property
|
|
437
|
+
// if ('_originalObject' in item && item._originalObject) {
|
|
438
|
+
// return valueData.some((v) => {
|
|
439
|
+
// // If both are objects, compare by JSON string or by ID
|
|
440
|
+
// if (v.isObject && typeof v.original === 'object') {
|
|
441
|
+
// const originalObj = item._originalObject as Record<string, unknown>;
|
|
442
|
+
|
|
443
|
+
// // First try direct equality comparison
|
|
444
|
+
// if (v.original === originalObj) return true;
|
|
445
|
+
|
|
446
|
+
// // Try JSON string comparison
|
|
447
|
+
// const itemJson = JSON.stringify(originalObj);
|
|
448
|
+
// if (v.string === itemJson) return true;
|
|
449
|
+
|
|
450
|
+
// // Try ID-based comparison if both have ID fields
|
|
451
|
+
// if (v.id !== undefined && 'id' in originalObj) {
|
|
452
|
+
// return v.id === originalObj.id;
|
|
453
|
+
// }
|
|
454
|
+
// }
|
|
455
|
+
// return false;
|
|
456
|
+
// });
|
|
457
|
+
// }
|
|
458
|
+
|
|
459
|
+
// // Handle both numeric and string values correctly
|
|
460
|
+
// if (typeof item.value === 'number') {
|
|
461
|
+
// return valueData.some((v) => v.original === item.value || v.string === String(item.value));
|
|
462
|
+
// } else {
|
|
463
|
+
// return valueStrings.includes(String(item.value));
|
|
464
|
+
// }
|
|
465
|
+
// });
|
|
466
|
+
// }
|
|
467
|
+
// };
|
|
468
|
+
|
|
469
|
+
// watch(selectValue, () => {
|
|
470
|
+
// updateSelectedItemsFromValue();
|
|
471
|
+
// });
|
|
472
|
+
|
|
473
|
+
// watch(selectMenuList, () => {
|
|
474
|
+
// updateSelectedItemsFromValue();
|
|
475
|
+
// });
|
|
476
|
+
|
|
477
|
+
// onMounted(() => {
|
|
478
|
+
// processMenuList();
|
|
479
|
+
|
|
480
|
+
// // Set initial selected items based on model value
|
|
481
|
+
// if (normalizedValue.value.length > 0) {
|
|
482
|
+
// updateSelectedItemsFromValue();
|
|
483
|
+
// }
|
|
484
|
+
// });
|
|
485
|
+
|
|
486
|
+
// return {
|
|
487
|
+
// selectPopperState,
|
|
488
|
+
// selectRef,
|
|
489
|
+
// inputText,
|
|
490
|
+
// selectMenuList,
|
|
491
|
+
// isSelectPopperDisabled,
|
|
492
|
+
// selectedListItems,
|
|
493
|
+
// handleSelectedItem,
|
|
494
|
+
// handleSelectedLadderizedItem,
|
|
495
|
+
// selectValue: compatPreSelectedItems, // Use compatible format for lists
|
|
496
|
+
// removeCurrentLevelInBackLabel,
|
|
497
|
+
// isLadderizedSearch,
|
|
498
|
+
// };
|
|
499
|
+
// };
|