design-system-next 2.7.35 → 2.7.37

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.
@@ -36,7 +36,66 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
36
36
 
37
37
  // #region - Helper Methods
38
38
  const isItemSelected = (item: MenuListType) => {
39
- return selectedItems.value.some((selectedItem) => selectedItem.text === item.text);
39
+ // First check standard selection via the selectedItems array
40
+ const directSelected = selectedItems.value.some((selectedItem) => {
41
+ // Compare both text and value properties to handle different value types
42
+ if (selectedItem.text === item.text) return true;
43
+
44
+ // Ensure comparison works for both string and number values
45
+ const selectedItemValue = selectedItem.value;
46
+ const itemValue = item.value;
47
+
48
+ // For primitives, use string comparison to handle number-string comparison properly
49
+ if (typeof selectedItemValue !== 'object' && typeof itemValue !== 'object') {
50
+ return String(selectedItemValue) === String(itemValue);
51
+ }
52
+
53
+ // For objects, use JSON.stringify for comparison (will match for equality)
54
+ if (typeof selectedItemValue === 'object' && selectedItemValue !== null &&
55
+ typeof itemValue === 'object' && itemValue !== null) {
56
+ return JSON.stringify(selectedItemValue) === JSON.stringify(itemValue);
57
+ }
58
+
59
+ return false;
60
+ });
61
+
62
+ if (directSelected) return true;
63
+
64
+ // Additional check for objects stored in _originalObject property
65
+ if ('_originalObject' in item && item._originalObject && preSelectedItems.value?.length) {
66
+ return preSelectedItems.value.some(preSelectedValue => {
67
+ // Direct reference comparison (most accurate)
68
+ if (preSelectedValue === item._originalObject) {
69
+ return true;
70
+ }
71
+
72
+ // If both are objects, compare their serialized forms
73
+ if (typeof preSelectedValue === 'object' && preSelectedValue !== null) {
74
+ const originalObj = item._originalObject as Record<string, unknown>;
75
+
76
+ if (typeof originalObj === 'object') {
77
+ // First try comparing by ID for more reliable object comparison
78
+ if ('id' in preSelectedValue && 'id' in originalObj) {
79
+ return preSelectedValue.id === originalObj.id;
80
+ }
81
+
82
+ // Fallback to full object comparison
83
+ const valString = JSON.stringify(preSelectedValue);
84
+ const itemString = JSON.stringify(originalObj);
85
+ return valString === itemString;
86
+ }
87
+
88
+ // If object has an id field, check if it matches with the item value
89
+ if ('id' in preSelectedValue) {
90
+ return String(item.value).includes(String(preSelectedValue.id));
91
+ }
92
+ }
93
+
94
+ return false;
95
+ });
96
+ }
97
+
98
+ return false;
40
99
  };
41
100
 
42
101
  const setMenuList = () => {
@@ -96,9 +155,57 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
96
155
  if (!preSelectedItems.value?.length) return;
97
156
 
98
157
  const selected = preSelectedItems.value
99
- .map((preSelectedItem: string) =>
100
- localizedMenuList.value.find((menuItem) => String(menuItem.value) === String(preSelectedItem)),
101
- )
158
+ .map((preSelectedItem: string | number | Record<string, unknown>) => {
159
+ // For objects, check for matching _originalObject properties
160
+ if (typeof preSelectedItem === 'object' && preSelectedItem !== null) {
161
+ // Try to find an item with a matching _originalObject
162
+ const objectMatch = localizedMenuList.value.find(menuItem => {
163
+ if (!menuItem._originalObject) return false;
164
+
165
+ // Compare serialized versions for deep equality
166
+ return JSON.stringify(menuItem._originalObject) === JSON.stringify(preSelectedItem);
167
+ });
168
+
169
+ if (objectMatch) return objectMatch;
170
+
171
+ // If no direct object match, try matching on ID if both have it
172
+ if ('id' in preSelectedItem) {
173
+ const idMatch = localizedMenuList.value.find(menuItem => {
174
+ if (menuItem._originalObject && 'id' in menuItem._originalObject) {
175
+ return menuItem._originalObject.id === preSelectedItem.id;
176
+ }
177
+ // Also check if the value field contains a stringified version that includes the id
178
+ return String(menuItem.value).includes(String(preSelectedItem.id));
179
+ });
180
+
181
+ if (idMatch) return idMatch;
182
+ }
183
+ }
184
+
185
+ // First try direct value comparison (for exact matches)
186
+ const directMatch = localizedMenuList.value.find(
187
+ (menuItem) => menuItem.value === preSelectedItem
188
+ );
189
+ if (directMatch) return directMatch;
190
+
191
+ // Special handling for number values in the preSelectedItems array
192
+ if (typeof preSelectedItem === 'number') {
193
+ // Find items that match the number value either directly or as a string
194
+ const numericMatch = localizedMenuList.value.find(
195
+ (menuItem) =>
196
+ // Match if menuItem.value is the same number
197
+ (typeof menuItem.value === 'number' && menuItem.value === preSelectedItem) ||
198
+ // Match if menuItem.value is a string representation of the number
199
+ (typeof menuItem.value === 'string' && menuItem.value === String(preSelectedItem))
200
+ );
201
+ if (numericMatch) return numericMatch;
202
+ }
203
+
204
+ // Then try string comparison for cases where types differ (string vs number)
205
+ return localizedMenuList.value.find(
206
+ (menuItem) => String(menuItem.value) === String(preSelectedItem)
207
+ );
208
+ })
102
209
  .filter(Boolean) as MenuListType[];
103
210
 
104
211
  if (multiSelect.value) {
@@ -108,7 +215,11 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
108
215
 
109
216
  if (
110
217
  firstItem &&
111
- !selectedItems.value.some((selectedItem) => String(selectedItem.value) === String(firstItem.value))
218
+ !selectedItems.value.some((selectedItem) => {
219
+ // Use the same comparison logic as in isItemSelected
220
+ if (selectedItem.text === firstItem.text) return true;
221
+ return String(selectedItem.value) === String(firstItem.value);
222
+ })
112
223
  ) {
113
224
  selectedItems.value = [firstItem];
114
225
  }
@@ -125,17 +236,57 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
125
236
  if(item.disabled) return;
126
237
 
127
238
  if (multiSelect.value) {
128
- const index = selectedItems.value.findIndex((selectedItem: MenuListType) => selectedItem.value === item.value);
239
+ // For multi-select, check if item is already selected
240
+ const index = selectedItems.value.findIndex((selectedItem: MenuListType) => {
241
+ // Compare text values first for simple match
242
+ if (selectedItem.text === item.text) return true;
243
+
244
+ // Compare primitive values with string conversion for compatibility
245
+ if (typeof selectedItem.value !== 'object' && typeof item.value !== 'object') {
246
+ return String(selectedItem.value) === String(item.value);
247
+ }
248
+
249
+ // For objects, compare their JSON string representations
250
+ if (typeof selectedItem.value === 'object' && selectedItem.value !== null &&
251
+ typeof item.value === 'object' && item.value !== null) {
252
+ return JSON.stringify(selectedItem.value) === JSON.stringify(item.value);
253
+ }
254
+
255
+ // Compare _originalObject if available (most reliable for complex objects)
256
+ if ('_originalObject' in selectedItem && selectedItem._originalObject &&
257
+ '_originalObject' in item && item._originalObject) {
258
+
259
+ // Direct reference equality check (fastest)
260
+ if (selectedItem._originalObject === item._originalObject) {
261
+ return true;
262
+ }
263
+
264
+ // ID-based comparison (reliable for objects with IDs)
265
+ const selectedObj = selectedItem._originalObject as Record<string, unknown>;
266
+ const itemObj = item._originalObject as Record<string, unknown>;
267
+
268
+ if ('id' in selectedObj && 'id' in itemObj) {
269
+ return selectedObj.id === itemObj.id;
270
+ }
271
+
272
+ // Full JSON comparison (most comprehensive but slower)
273
+ return JSON.stringify(selectedItem._originalObject) === JSON.stringify(item._originalObject);
274
+ }
275
+
276
+ return false;
277
+ });
129
278
 
130
279
  if (index === -1) {
280
+ // Add item if not already selected
131
281
  selectedItems.value = [...selectedItems.value, item];
132
282
  } else {
283
+ // Remove item if already selected
133
284
  const updatedItems = [...selectedItems.value];
134
-
135
285
  updatedItems.splice(index, 1);
136
286
  selectedItems.value = updatedItems;
137
287
  }
138
288
  } else {
289
+ // For single-select, simply replace the selection
139
290
  selectedItems.value = [item];
140
291
  }
141
292
  };
@@ -0,0 +1,76 @@
1
+ // Example usage of dropdown with primitive number values in multi-select mode
2
+
3
+ <template>
4
+ <div>
5
+ <h2>Multiple Number Values Demo</h2>
6
+ <p>Selected values: {{ displaySelection }}</p>
7
+
8
+ <div class="dropdown-container">
9
+ <spr-dropdown
10
+ id="number-multi-dropdown"
11
+ v-model="selectedNumbers"
12
+ :menu-list="numberOptions"
13
+ multi-select
14
+ @update:model-value="handleSelectedItems"
15
+ >
16
+ <spr-input
17
+ v-model="displayText"
18
+ label="Select Numbers"
19
+ readonly
20
+ placeholder="Select numbers..."
21
+ />
22
+ </spr-dropdown>
23
+ </div>
24
+
25
+ <div class="mt-4">
26
+ <h3>Current selection type:</h3>
27
+ <pre>{{ typeof selectedNumbers[0] }}</pre>
28
+
29
+ <h3>Current selection:</h3>
30
+ {{ selectedNumbers }}
31
+ </div>
32
+ </div>
33
+ </template>
34
+
35
+ <script setup>
36
+ import { ref, computed } from 'vue';
37
+ import SprInput from "@/components/input/input.vue";
38
+ import SprDropdown from "@/components/dropdown/dropdown.vue";
39
+
40
+ // Define number options - raw number values
41
+ const numberOptions = [
42
+ { text: 'One', value: 1 },
43
+ { text: 'Two', value: 2 },
44
+ { text: 'Three', value: 3 },
45
+ { text: 'Four', value: 4 },
46
+ { text: 'Five', value: 5 }
47
+ ];
48
+
49
+ // Track selected numbers
50
+ const selectedNumbers = ref([]);
51
+ const displayText = ref('');
52
+
53
+ // Display the selection summary
54
+ const displaySelection = computed(() => {
55
+ if (selectedNumbers.value.length === 0) {
56
+ return 'None';
57
+ }
58
+ return selectedNumbers.value.join(', ');
59
+ });
60
+
61
+ // Handle selected items and update display text
62
+ const handleSelectedItems = (items) => {
63
+ // For multi-select, update display text to show selected items
64
+ const selectedTexts = items.map(itemValue => {
65
+ // Find corresponding text for each selected value
66
+ const option = numberOptions.find(opt => opt.value === itemValue);
67
+ return option ? option.text : itemValue;
68
+ });
69
+
70
+ // Update the input display text
71
+ displayText.value = selectedTexts.join(', ');
72
+
73
+ console.log('Selected values:', items);
74
+ console.log('Type of first value:', typeof items[0]);
75
+ };
76
+ </script>