design-system-next 2.8.1 → 2.8.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/dist/design-system-next.js +4072 -4156
- 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/components/select/select-ladderized/select-ladderized.ts +3 -3
- package/src/components/select/select-ladderized/select-ladderized.vue +7 -7
- package/src/components/select/select-ladderized/use-select-ladderized.ts +13 -14
- package/src/components/select/select-multiple/select-multiple.ts +1 -12
- package/src/components/select/select-multiple/select-multiple.vue +17 -72
- package/src/components/select/select-multiple/use-select-multiple.ts +52 -86
- package/src/components/select/select.ts +2 -2
- package/src/components/select/select.vue +12 -12
- package/src/components/select/use-select.ts +26 -25
- package/src/components/snackbar/snack/snack.vue +6 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ref, computed, watch } from 'vue';
|
|
2
|
-
import { useDebounceFn, onClickOutside } from '@vueuse/core';
|
|
1
|
+
import { ref, toRefs, computed, watch } from 'vue';
|
|
2
|
+
import { useVModel, useDebounceFn, onClickOutside } from '@vueuse/core';
|
|
3
3
|
|
|
4
4
|
import type { SelectLadderizedPropTypes } from './select-ladderized';
|
|
5
5
|
|
|
@@ -9,6 +9,8 @@ export const useSelectLadderized = (
|
|
|
9
9
|
props: SelectLadderizedPropTypes,
|
|
10
10
|
emit: (event: string, ...args: unknown[]) => void,
|
|
11
11
|
) => {
|
|
12
|
+
const { options, disabled } = toRefs(props);
|
|
13
|
+
|
|
12
14
|
const ladderizedClasses = computed(() => ({
|
|
13
15
|
baseClasses: 'spr-flex spr-flex-col spr-gap-size-spacing-4xs',
|
|
14
16
|
labelClasses: 'spr-body-sm-regular spr-text-color-strong spr-block',
|
|
@@ -17,14 +19,11 @@ export const useSelectLadderized = (
|
|
|
17
19
|
// Popper Variables
|
|
18
20
|
const ladderizedSelectPopperState = ref(false);
|
|
19
21
|
const ladderizedSelectRef = ref(null);
|
|
20
|
-
const isLadderizedSelectPopperDisabled = computed(() =>
|
|
22
|
+
const isLadderizedSelectPopperDisabled = computed(() => disabled.value);
|
|
21
23
|
|
|
22
24
|
// Ladderized Select Model
|
|
23
|
-
const ladderizedSelectModel =
|
|
24
|
-
|
|
25
|
-
set: (val) => emit('update:modelValue', val),
|
|
26
|
-
});
|
|
27
|
-
const ladderizedSelectMenuList = computed(() => props.menuList);
|
|
25
|
+
const ladderizedSelectModel = useVModel(props, 'modelValue', emit);
|
|
26
|
+
const ladderizedSelectOptions = computed(() => options.value);
|
|
28
27
|
|
|
29
28
|
// Input Variables
|
|
30
29
|
const inputText = ref<string>('');
|
|
@@ -76,11 +75,11 @@ export const useSelectLadderized = (
|
|
|
76
75
|
return undefined;
|
|
77
76
|
};
|
|
78
77
|
|
|
79
|
-
itemToCheck = findItemByValue(
|
|
78
|
+
itemToCheck = findItemByValue(ladderizedSelectOptions.value, selectedItems[selectedItems.length - 1]);
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
if (itemToCheck) {
|
|
83
|
-
const path = findPathToValue(
|
|
82
|
+
const path = findPathToValue(ladderizedSelectOptions.value, itemToCheck.value);
|
|
84
83
|
|
|
85
84
|
inputText.value = path ? path.join(' > ') : itemToCheck.text || '';
|
|
86
85
|
|
|
@@ -110,7 +109,7 @@ export const useSelectLadderized = (
|
|
|
110
109
|
emit('update:modelValue', []);
|
|
111
110
|
};
|
|
112
111
|
|
|
113
|
-
const
|
|
112
|
+
const handleOptionsToggle = () => {
|
|
114
113
|
ladderizedSelectPopperState.value = true;
|
|
115
114
|
|
|
116
115
|
isSearching.value = false;
|
|
@@ -128,7 +127,7 @@ export const useSelectLadderized = (
|
|
|
128
127
|
|
|
129
128
|
if (Array.isArray(newVal) && newVal.length > 0) {
|
|
130
129
|
// Treat the array as a single path for ladderized select
|
|
131
|
-
let currentLevel =
|
|
130
|
+
let currentLevel = ladderizedSelectOptions.value;
|
|
132
131
|
|
|
133
132
|
const pathTexts: string[] = [];
|
|
134
133
|
|
|
@@ -153,13 +152,13 @@ export const useSelectLadderized = (
|
|
|
153
152
|
ladderizedClasses,
|
|
154
153
|
ladderizedSelectPopperState,
|
|
155
154
|
ladderizedSelectRef,
|
|
156
|
-
|
|
155
|
+
ladderizedSelectOptions,
|
|
157
156
|
isLadderizedSelectPopperDisabled,
|
|
158
157
|
ladderizedSelectModel,
|
|
159
158
|
inputText,
|
|
160
159
|
handleSelectedLadderizedItem,
|
|
161
160
|
handleSearch,
|
|
162
161
|
handleClear,
|
|
163
|
-
|
|
162
|
+
handleOptionsToggle,
|
|
164
163
|
};
|
|
165
164
|
};
|
|
@@ -36,7 +36,7 @@ export const multiSelectPropTypes = {
|
|
|
36
36
|
>,
|
|
37
37
|
default: () => [],
|
|
38
38
|
},
|
|
39
|
-
|
|
39
|
+
options: {
|
|
40
40
|
type: Array as PropType<MenuListType[] | string[] | Record<string, unknown>[]>,
|
|
41
41
|
required: true,
|
|
42
42
|
default: [],
|
|
@@ -110,22 +110,11 @@ export const multiSelectPropTypes = {
|
|
|
110
110
|
type: Boolean,
|
|
111
111
|
default: false,
|
|
112
112
|
},
|
|
113
|
-
searchable: {
|
|
114
|
-
type: Boolean,
|
|
115
|
-
default: false,
|
|
116
|
-
},
|
|
117
|
-
disabledLocalSearch: {
|
|
118
|
-
type: Boolean,
|
|
119
|
-
default: false,
|
|
120
|
-
},
|
|
121
113
|
};
|
|
122
114
|
|
|
123
115
|
export const multiSelectEmitTypes = {
|
|
124
116
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
125
117
|
'update:modelValue': (_value: unknown) => true,
|
|
126
|
-
|
|
127
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
128
|
-
'search-string': (_search: string | number) => true,
|
|
129
118
|
};
|
|
130
119
|
|
|
131
120
|
export type MultiSelectPropTypes = ExtractPropTypes<typeof multiSelectPropTypes>;
|
|
@@ -23,20 +23,19 @@
|
|
|
23
23
|
width: props.width,
|
|
24
24
|
}"
|
|
25
25
|
>
|
|
26
|
-
<div @click="
|
|
26
|
+
<div @click="handleOptionsToggle">
|
|
27
27
|
<spr-input
|
|
28
28
|
v-model="inputText"
|
|
29
29
|
:class="{
|
|
30
|
-
'spr-cursor-pointer':
|
|
30
|
+
'spr-cursor-pointer': true,
|
|
31
31
|
}"
|
|
32
32
|
:placeholder="props.placeholder"
|
|
33
|
-
:readonly="
|
|
33
|
+
:readonly="true"
|
|
34
34
|
:disabled="props.disabled"
|
|
35
35
|
autocomplete="off"
|
|
36
36
|
:helper-text="props.helperText"
|
|
37
37
|
:helper-icon="props.helperIcon"
|
|
38
38
|
:display-helper="props.displayHelper"
|
|
39
|
-
@keyup="handleSearch"
|
|
40
39
|
>
|
|
41
40
|
<template #icon>
|
|
42
41
|
<div class="spr-flex spr-items-center spr-gap-1">
|
|
@@ -59,76 +58,25 @@
|
|
|
59
58
|
}"
|
|
60
59
|
></div>
|
|
61
60
|
|
|
62
|
-
<select
|
|
63
|
-
:id="`${props.id}-multiple-select`"
|
|
64
|
-
tabindex="-1"
|
|
65
|
-
aria-hidden="true"
|
|
66
|
-
data-qa="multi-select-hidden"
|
|
67
|
-
multiple
|
|
68
|
-
hidden
|
|
69
|
-
>
|
|
70
|
-
<option v-for="item in multiSelectedListItems" :key="item.value" :value="item.value" selected>
|
|
71
|
-
{{ item.text }}
|
|
72
|
-
</option>
|
|
73
|
-
</select>
|
|
74
|
-
|
|
75
61
|
<template #popper>
|
|
76
62
|
<div
|
|
77
63
|
ref="multiSelectRef"
|
|
78
64
|
class="spr-grid spr-max-h-[300px] spr-gap-0.5 spr-overflow-y-auto spr-overflow-x-hidden spr-p-2"
|
|
79
65
|
>
|
|
80
|
-
<template v-if="
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
@update:model-value="handleMultiSelectedItem"
|
|
90
|
-
/>
|
|
91
|
-
</template>
|
|
92
|
-
<template v-else>
|
|
93
|
-
<div class="spr-flex spr-items-center spr-justify-center spr-p-2 spr-text-center">
|
|
94
|
-
<span class="spr-body-sm-regular spr-m-0">No results found</span>
|
|
95
|
-
</div>
|
|
96
|
-
</template>
|
|
97
|
-
</template>
|
|
98
|
-
<template v-else>
|
|
99
|
-
<template v-if="multiSelectMenuList.length > 0">
|
|
100
|
-
<spr-list
|
|
101
|
-
v-model="multiSelectedListItems"
|
|
102
|
-
:menu-list="multiSelectMenuList"
|
|
103
|
-
:group-items-by="props.groupItemsBy"
|
|
104
|
-
:pre-selected-items="Array.isArray(multiSelectModel) ? multiSelectModel.flat() : [multiSelectModel]"
|
|
105
|
-
multi-select
|
|
106
|
-
@update:model-value="handleMultiSelectedItem"
|
|
107
|
-
/>
|
|
108
|
-
</template>
|
|
109
|
-
<template v-else>
|
|
110
|
-
<div class="spr-flex spr-items-center spr-justify-center spr-p-2 spr-text-center">
|
|
111
|
-
<span class="spr-body-sm-regular spr-m-0">No results found</span>
|
|
112
|
-
</div>
|
|
113
|
-
</template>
|
|
114
|
-
</template>
|
|
66
|
+
<template v-if="multiSelectOptions.length > 0">
|
|
67
|
+
<spr-list
|
|
68
|
+
v-model="multiSelectedListItems"
|
|
69
|
+
:menu-list="multiSelectOptions"
|
|
70
|
+
:group-items-by="props.groupItemsBy"
|
|
71
|
+
:pre-selected-items="Array.isArray(multiSelectModel) ? multiSelectModel.flat() : [multiSelectModel]"
|
|
72
|
+
multi-select
|
|
73
|
+
@update:model-value="handleMultiSelectedItem"
|
|
74
|
+
/>
|
|
115
75
|
</template>
|
|
116
76
|
<template v-else>
|
|
117
|
-
<
|
|
118
|
-
<spr-
|
|
119
|
-
|
|
120
|
-
:menu-list="multiSelectMenuList"
|
|
121
|
-
:group-items-by="props.groupItemsBy"
|
|
122
|
-
:pre-selected-items="Array.isArray(multiSelectModel) ? multiSelectModel.flat() : [multiSelectModel]"
|
|
123
|
-
multi-select
|
|
124
|
-
@update:model-value="handleMultiSelectedItem"
|
|
125
|
-
/>
|
|
126
|
-
</template>
|
|
127
|
-
<template v-else>
|
|
128
|
-
<div class="spr-flex spr-items-center spr-justify-center spr-p-2 spr-text-center">
|
|
129
|
-
<span class="spr-body-sm-regular spr-m-0">No results found</span>
|
|
130
|
-
</div>
|
|
131
|
-
</template>
|
|
77
|
+
<div class="spr-flex spr-items-center spr-justify-center spr-p-2 spr-text-center">
|
|
78
|
+
<span class="spr-body-sm-regular spr-m-0">No results found</span>
|
|
79
|
+
</div>
|
|
132
80
|
</template>
|
|
133
81
|
</div>
|
|
134
82
|
</template>
|
|
@@ -157,15 +105,12 @@ const {
|
|
|
157
105
|
multiSelectPopperState,
|
|
158
106
|
multiSelectRef,
|
|
159
107
|
multiSelectModel,
|
|
160
|
-
|
|
161
|
-
filteredMultiSelectMenuList,
|
|
108
|
+
multiSelectOptions,
|
|
162
109
|
multiSelectedListItems,
|
|
163
110
|
inputText,
|
|
164
111
|
isMultiSelectPopperDisabled,
|
|
165
|
-
isSearching,
|
|
166
112
|
handleMultiSelectedItem,
|
|
167
|
-
handleSearch,
|
|
168
113
|
handleClear,
|
|
169
|
-
|
|
114
|
+
handleOptionsToggle,
|
|
170
115
|
} = useMultiSelect(props, emit);
|
|
171
116
|
</script>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, toRefs, computed, ComputedRef, onMounted, watch } from 'vue';
|
|
2
|
-
import { onClickOutside, useVModel
|
|
2
|
+
import { onClickOutside, useVModel } from '@vueuse/core';
|
|
3
3
|
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ interface MultiSelectClasses {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<MultiSelectEmitTypes>['emit']) => {
|
|
16
|
-
const { displayText,
|
|
16
|
+
const { displayText, options, disabled, textField, valueField } = toRefs(props);
|
|
17
17
|
|
|
18
18
|
const multiSelectClasses: ComputedRef<MultiSelectClasses> = computed(() => {
|
|
19
19
|
const baseClasses = classNames('spr-flex spr-flex-col spr-gap-size-spacing-4xs');
|
|
@@ -34,20 +34,11 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
34
34
|
|
|
35
35
|
const multiSelectModel = useVModel(props, 'modelValue', emit);
|
|
36
36
|
const multiSelectedListItems = ref<MenuListType[]>([]);
|
|
37
|
-
const
|
|
37
|
+
const multiSelectOptions = ref<MenuListType[]>([]);
|
|
38
38
|
const hasUserSelected = ref(false);
|
|
39
39
|
|
|
40
40
|
const inputText = ref<string | number>('');
|
|
41
41
|
const inputTextBackup = ref<string | number>('');
|
|
42
|
-
const isSearching = ref<boolean>(false);
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Opens the multi-select dropdown menu and resets the searching state.
|
|
46
|
-
*/
|
|
47
|
-
const handleMenuToggle = () => {
|
|
48
|
-
multiSelectPopperState.value = true;
|
|
49
|
-
isSearching.value = false;
|
|
50
|
-
};
|
|
51
42
|
|
|
52
43
|
/**
|
|
53
44
|
* Returns the normalized value of the model as an array for internal use.
|
|
@@ -65,19 +56,19 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
65
56
|
});
|
|
66
57
|
|
|
67
58
|
/**
|
|
68
|
-
* Processes the
|
|
59
|
+
* Processes the options prop and normalizes it into MenuListType[] for the multi-select.
|
|
69
60
|
*/
|
|
70
|
-
const
|
|
71
|
-
if (!
|
|
72
|
-
|
|
61
|
+
const processOptions = () => {
|
|
62
|
+
if (!options.value || !Array.isArray(options.value) || options.value.length === 0) {
|
|
63
|
+
multiSelectOptions.value = [];
|
|
73
64
|
|
|
74
65
|
return;
|
|
75
66
|
}
|
|
76
67
|
|
|
77
|
-
const firstItem =
|
|
68
|
+
const firstItem = options.value[0];
|
|
78
69
|
|
|
79
70
|
if (typeof firstItem === 'string') {
|
|
80
|
-
|
|
71
|
+
multiSelectOptions.value = (options.value as string[]).map((item) => ({
|
|
81
72
|
text: item,
|
|
82
73
|
value: item,
|
|
83
74
|
}));
|
|
@@ -86,7 +77,7 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
86
77
|
}
|
|
87
78
|
|
|
88
79
|
if (typeof firstItem === 'number') {
|
|
89
|
-
|
|
80
|
+
multiSelectOptions.value = (options.value as Array<number | string | Record<string, unknown>>)
|
|
90
81
|
.filter((item): item is number => typeof item === 'number')
|
|
91
82
|
.map((item) => ({
|
|
92
83
|
text: item.toString(),
|
|
@@ -98,12 +89,12 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
98
89
|
|
|
99
90
|
if (typeof firstItem === 'object' && firstItem !== null) {
|
|
100
91
|
if ('text' in firstItem && 'value' in firstItem) {
|
|
101
|
-
|
|
92
|
+
multiSelectOptions.value = options.value as MenuListType[];
|
|
102
93
|
|
|
103
94
|
return;
|
|
104
95
|
}
|
|
105
96
|
|
|
106
|
-
|
|
97
|
+
multiSelectOptions.value = (options.value as Record<string, unknown>[]).map((item) => {
|
|
107
98
|
const displayText = item[textField.value] !== undefined ? String(item[textField.value]) : 'Unnamed';
|
|
108
99
|
|
|
109
100
|
let itemValue = valueField.value && item[valueField.value] !== undefined ? item[valueField.value] : item;
|
|
@@ -120,53 +111,18 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
120
111
|
return;
|
|
121
112
|
}
|
|
122
113
|
|
|
123
|
-
|
|
114
|
+
multiSelectOptions.value = options.value as MenuListType[];
|
|
124
115
|
};
|
|
125
116
|
|
|
126
117
|
/**
|
|
127
|
-
*
|
|
118
|
+
* Opens the multi-select options.
|
|
128
119
|
*/
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
return multiSelectMenuList.value;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const query = inputText.value.toString().toLowerCase().trim();
|
|
135
|
-
|
|
136
|
-
if (!query) return multiSelectMenuList.value;
|
|
137
|
-
|
|
138
|
-
return multiSelectMenuList.value.filter((item) => item.text?.toString().toLowerCase().includes(query));
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Handles the search input and emits the search-string event (debounced).
|
|
143
|
-
*/
|
|
144
|
-
const handleSearch = () => {
|
|
145
|
-
isSearching.value = true;
|
|
146
|
-
|
|
147
|
-
debouncedEmitSearch();
|
|
120
|
+
const handleOptionsToggle = () => {
|
|
121
|
+
multiSelectPopperState.value = true;
|
|
148
122
|
};
|
|
149
123
|
|
|
150
124
|
/**
|
|
151
|
-
*
|
|
152
|
-
*/
|
|
153
|
-
const debouncedEmitSearch = useDebounceFn(() => {
|
|
154
|
-
emit('search-string', inputText.value);
|
|
155
|
-
}, 300);
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Handles closing the dropdown when clicking outside, restoring input text if searching.
|
|
159
|
-
*/
|
|
160
|
-
onClickOutside(multiSelectRef, () => {
|
|
161
|
-
multiSelectPopperState.value = false;
|
|
162
|
-
if (isSearching.value) {
|
|
163
|
-
inputText.value = inputTextBackup.value;
|
|
164
|
-
}
|
|
165
|
-
isSearching.value = false;
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Handles selection changes from the dropdown and updates the model value.
|
|
125
|
+
* Handles selection changes from the multi-select and updates the model value.
|
|
170
126
|
* Converts stringified objects back to objects if needed.
|
|
171
127
|
*/
|
|
172
128
|
const handleMultiSelectedItem = (multiSelectedItems: MenuListType[]) => {
|
|
@@ -178,21 +134,27 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
178
134
|
return item.value;
|
|
179
135
|
}
|
|
180
136
|
}
|
|
137
|
+
|
|
181
138
|
return item.value;
|
|
182
139
|
});
|
|
183
140
|
|
|
184
141
|
hasUserSelected.value = true;
|
|
185
142
|
multiSelectModel.value = selectedValues;
|
|
186
143
|
multiSelectPopperState.value = true;
|
|
187
|
-
inputTextBackup.value =
|
|
144
|
+
inputTextBackup.value =
|
|
145
|
+
multiSelectedItems.length > 3
|
|
146
|
+
? `${multiSelectedItems.length} items selected`
|
|
147
|
+
: multiSelectedItems.map((item) => item.text).join(', ');
|
|
148
|
+
|
|
149
|
+
updateMultiSelectedItemsFromValue();
|
|
188
150
|
};
|
|
189
151
|
|
|
190
152
|
/**
|
|
191
|
-
* Updates the selected items in the
|
|
153
|
+
* Updates the selected items in the multi-select based on the current model value.
|
|
192
154
|
* Handles stringified objects and updates the input text accordingly.
|
|
193
155
|
*/
|
|
194
156
|
const updateMultiSelectedItemsFromValue = () => {
|
|
195
|
-
if (!
|
|
157
|
+
if (!multiSelectOptions.value.length) return;
|
|
196
158
|
|
|
197
159
|
const values = normalizedValue.value;
|
|
198
160
|
|
|
@@ -204,7 +166,7 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
204
166
|
return;
|
|
205
167
|
}
|
|
206
168
|
|
|
207
|
-
multiSelectedListItems.value =
|
|
169
|
+
multiSelectedListItems.value = multiSelectOptions.value.filter((item) => {
|
|
208
170
|
return values.some((val) => {
|
|
209
171
|
let itemVal = item.value;
|
|
210
172
|
let valToCompare = val;
|
|
@@ -233,30 +195,28 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
233
195
|
});
|
|
234
196
|
});
|
|
235
197
|
|
|
236
|
-
if (
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
198
|
+
if (multiSelectedListItems.value.length > 3) {
|
|
199
|
+
inputText.value = `${multiSelectedListItems.value.length} items selected`;
|
|
200
|
+
} else {
|
|
201
|
+
inputText.value = multiSelectedListItems.value.map((item) => item.text).join(', ');
|
|
202
|
+
}
|
|
242
203
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
204
|
+
// Always update backup to match inputText after update
|
|
205
|
+
inputTextBackup.value = inputText.value;
|
|
206
|
+
|
|
207
|
+
if (displayText.value && !hasUserSelected.value && (!inputText.value || inputText.value === '')) {
|
|
208
|
+
inputText.value = displayText.value;
|
|
209
|
+
inputTextBackup.value = displayText.value;
|
|
249
210
|
}
|
|
250
211
|
};
|
|
251
212
|
|
|
252
213
|
/**
|
|
253
|
-
* Clears the selection and input text, and closes the
|
|
214
|
+
* Clears the selection and input text, and closes the multi-select.
|
|
254
215
|
*/
|
|
255
216
|
const handleClear = () => {
|
|
256
217
|
emit('update:modelValue', []);
|
|
257
218
|
|
|
258
219
|
inputText.value = '';
|
|
259
|
-
|
|
260
220
|
multiSelectPopperState.value = false;
|
|
261
221
|
};
|
|
262
222
|
|
|
@@ -264,12 +224,21 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
264
224
|
updateMultiSelectedItemsFromValue();
|
|
265
225
|
});
|
|
266
226
|
|
|
267
|
-
watch(
|
|
227
|
+
watch(multiSelectOptions, () => {
|
|
228
|
+
updateMultiSelectedItemsFromValue();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Handles closing the multi-select when clicking outside.
|
|
233
|
+
*/
|
|
234
|
+
onClickOutside(multiSelectRef, () => {
|
|
235
|
+
multiSelectPopperState.value = false;
|
|
236
|
+
|
|
268
237
|
updateMultiSelectedItemsFromValue();
|
|
269
238
|
});
|
|
270
239
|
|
|
271
240
|
onMounted(() => {
|
|
272
|
-
|
|
241
|
+
processOptions();
|
|
273
242
|
|
|
274
243
|
if (normalizedValue.value.length > 0) {
|
|
275
244
|
updateMultiSelectedItemsFromValue();
|
|
@@ -284,15 +253,12 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
|
|
|
284
253
|
multiSelectPopperState,
|
|
285
254
|
multiSelectRef,
|
|
286
255
|
multiSelectModel,
|
|
287
|
-
|
|
288
|
-
filteredMultiSelectMenuList,
|
|
256
|
+
multiSelectOptions,
|
|
289
257
|
multiSelectedListItems,
|
|
290
258
|
inputText,
|
|
291
259
|
isMultiSelectPopperDisabled,
|
|
292
|
-
isSearching,
|
|
293
260
|
handleMultiSelectedItem,
|
|
294
|
-
handleSearch,
|
|
295
261
|
handleClear,
|
|
296
|
-
|
|
262
|
+
handleOptionsToggle,
|
|
297
263
|
};
|
|
298
264
|
};
|
|
@@ -34,9 +34,9 @@ export const selectPropTypes = {
|
|
|
34
34
|
type: [String, Number, Object, Array] as PropType<
|
|
35
35
|
string | number | Record<string, unknown> | (string | number | Record<string, unknown>)[]
|
|
36
36
|
>,
|
|
37
|
-
default:
|
|
37
|
+
default: '',
|
|
38
38
|
},
|
|
39
|
-
|
|
39
|
+
options: {
|
|
40
40
|
type: Array as PropType<MenuListType[] | string[] | Record<string, unknown>[]>,
|
|
41
41
|
required: true,
|
|
42
42
|
default: [],
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
width: props.width,
|
|
24
24
|
}"
|
|
25
25
|
>
|
|
26
|
-
<div @click="
|
|
26
|
+
<div @click="handleOptionsToggle">
|
|
27
27
|
<spr-input
|
|
28
28
|
v-model="inputText"
|
|
29
29
|
:class="{
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
</spr-input>
|
|
53
53
|
|
|
54
54
|
<select
|
|
55
|
-
v-if="
|
|
55
|
+
v-if="selectOptions && selectOptions.length"
|
|
56
56
|
:value="Array.isArray(selectModel) ? selectModel[0] : selectModel"
|
|
57
57
|
data-testid="qa-hidden-select"
|
|
58
58
|
tabindex="-1"
|
|
59
59
|
aria-hidden="true"
|
|
60
60
|
hidden
|
|
61
61
|
>
|
|
62
|
-
<option v-for="item in
|
|
62
|
+
<option v-for="item in selectOptions" :key="item.value" :value="item.value">
|
|
63
63
|
{{ item.text }}
|
|
64
64
|
</option>
|
|
65
65
|
</select>
|
|
@@ -79,10 +79,10 @@
|
|
|
79
79
|
>
|
|
80
80
|
<template v-if="isSearching">
|
|
81
81
|
<template v-if="!props.disabledLocalSearch">
|
|
82
|
-
<template v-if="
|
|
82
|
+
<template v-if="filteredSelectOptions.length > 0">
|
|
83
83
|
<spr-list
|
|
84
84
|
v-model="selectedListItems"
|
|
85
|
-
:menu-list="
|
|
85
|
+
:menu-list="filteredSelectOptions"
|
|
86
86
|
:group-items-by="props.groupItemsBy"
|
|
87
87
|
:pre-selected-items="Array.isArray(selectModel) ? selectModel.flat() : [selectModel]"
|
|
88
88
|
@update:model-value="handleSelectedItem"
|
|
@@ -95,10 +95,10 @@
|
|
|
95
95
|
</template>
|
|
96
96
|
</template>
|
|
97
97
|
<template v-else>
|
|
98
|
-
<template v-if="
|
|
98
|
+
<template v-if="selectOptions.length > 0">
|
|
99
99
|
<spr-list
|
|
100
100
|
v-model="selectedListItems"
|
|
101
|
-
:menu-list="
|
|
101
|
+
:menu-list="selectOptions"
|
|
102
102
|
:group-items-by="props.groupItemsBy"
|
|
103
103
|
:pre-selected-items="Array.isArray(selectModel) ? selectModel.flat() : [selectModel]"
|
|
104
104
|
@update:model-value="handleSelectedItem"
|
|
@@ -112,10 +112,10 @@
|
|
|
112
112
|
</template>
|
|
113
113
|
</template>
|
|
114
114
|
<template v-else>
|
|
115
|
-
<template v-if="
|
|
115
|
+
<template v-if="selectOptions.length > 0">
|
|
116
116
|
<spr-list
|
|
117
117
|
v-model="selectedListItems"
|
|
118
|
-
:menu-list="
|
|
118
|
+
:menu-list="selectOptions"
|
|
119
119
|
:group-items-by="props.groupItemsBy"
|
|
120
120
|
:pre-selected-items="Array.isArray(selectModel) ? selectModel.flat() : [selectModel]"
|
|
121
121
|
@update:model-value="handleSelectedItem"
|
|
@@ -154,8 +154,8 @@ const {
|
|
|
154
154
|
selectPopperState,
|
|
155
155
|
selectRef,
|
|
156
156
|
selectModel,
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
selectOptions,
|
|
158
|
+
filteredSelectOptions,
|
|
159
159
|
selectedListItems,
|
|
160
160
|
inputText,
|
|
161
161
|
isSelectPopperDisabled,
|
|
@@ -163,6 +163,6 @@ const {
|
|
|
163
163
|
handleSelectedItem,
|
|
164
164
|
handleSearch,
|
|
165
165
|
handleClear,
|
|
166
|
-
|
|
166
|
+
handleOptionsToggle,
|
|
167
167
|
} = useSelect(props, emit);
|
|
168
168
|
</script>
|