design-system-next 2.12.3 → 2.12.7
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.es.js +6821 -7001
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +12 -12
- package/dist/design-system-next.umd.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/avatar/avatar.ts +8 -1
- package/src/components/avatar/avatar.vue +10 -5
- package/src/components/avatar/use-avatar.ts +14 -3
- package/src/components/calendar/calendar.ts +12 -2
- package/src/components/sidenav/sidenav-menu-links.vue +304 -0
- package/src/components/sidenav/sidenav.ts +7 -6
- package/src/components/sidenav/sidenav.vue +34 -587
- package/src/components/sidenav/use-sidenav.ts +29 -20
- package/src/components/table/table.vue +1 -1
- package/src/components/table/use-table.ts +2 -2
- package/src/components/date-picker/__tests__/date-picker.test.ts +0 -112
- package/src/components/dropdown/__tests__/dropdown-fixes.spec.ts +0 -106
- package/src/components/dropdown/__tests__/dropdown-value-types.spec.ts +0 -213
- package/src/examples/dropdown-number-multi-select.vue +0 -76
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { ref, onMounted } from 'vue';
|
|
2
2
|
|
|
3
3
|
import type { SetupContext } from 'vue';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
SidenavPropTypes,
|
|
6
|
+
SidenavEmitTypes,
|
|
7
|
+
ParentLinkItem,
|
|
8
|
+
NavLinks,
|
|
9
|
+
NavItem,
|
|
10
|
+
MenuLinkItem,
|
|
11
|
+
Attributes,
|
|
12
|
+
} from './sidenav';
|
|
5
13
|
|
|
6
14
|
interface ObjectItem {
|
|
7
15
|
redirect?: {
|
|
@@ -23,16 +31,6 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
23
31
|
const isQuckActionMenuVisible = ref(false);
|
|
24
32
|
const isUserMenuVisible = ref(false);
|
|
25
33
|
|
|
26
|
-
const userProfileError = ref(false);
|
|
27
|
-
|
|
28
|
-
const getUserInitials = (name: string) => {
|
|
29
|
-
const nameArray = name.split(' ');
|
|
30
|
-
|
|
31
|
-
const initials = nameArray[0].charAt(0) + (nameArray[1] ? nameArray[1].charAt(0) : '');
|
|
32
|
-
|
|
33
|
-
return initials.toUpperCase();
|
|
34
|
-
};
|
|
35
|
-
|
|
36
34
|
const handleRedirect = (objectItem: ObjectItem, parentNav: string, menu: string, submenu: string) => {
|
|
37
35
|
if (objectItem && objectItem.redirect) {
|
|
38
36
|
if (objectItem.redirect.openInNewTab) {
|
|
@@ -92,7 +90,7 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
92
90
|
}
|
|
93
91
|
};
|
|
94
92
|
|
|
95
|
-
const groupByGroupId = (items: NavItem[]) => {
|
|
93
|
+
const groupByGroupId = (items: NavItem[]): { parentLinks: ParentLinkItem[] }[] => {
|
|
96
94
|
const groups: Record<string, NavItem[]> = {};
|
|
97
95
|
|
|
98
96
|
items.forEach((item) => {
|
|
@@ -102,7 +100,9 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
102
100
|
groups[item.groupId].push(item);
|
|
103
101
|
});
|
|
104
102
|
|
|
105
|
-
return Object.values(groups).map((group) => ({
|
|
103
|
+
return Object.values(groups).map((group) => ({
|
|
104
|
+
parentLinks: group.map((item) => mapItemToNav(item) as ParentLinkItem),
|
|
105
|
+
}));
|
|
106
106
|
};
|
|
107
107
|
|
|
108
108
|
const mapItemToNav = (item: NavItem): ParentLinkItem | MenuLinkItem => {
|
|
@@ -133,12 +133,12 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
133
133
|
|
|
134
134
|
return {
|
|
135
135
|
title: item.label,
|
|
136
|
-
icon: item.icon
|
|
136
|
+
icon: item.icon ?? '',
|
|
137
137
|
redirect: item.url
|
|
138
138
|
? {
|
|
139
139
|
openInNewTab: item.isNewTab || false,
|
|
140
140
|
isAbsoluteURL: !confirmIfOwnDomain(item.url as string),
|
|
141
|
-
link: navLinkCondition(item),
|
|
141
|
+
link: navLinkCondition(item) ?? '',
|
|
142
142
|
}
|
|
143
143
|
: undefined,
|
|
144
144
|
menuLinks: mapGroupedChildren(groupedChildren, 'menuHeading') as {
|
|
@@ -182,13 +182,23 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
182
182
|
return transformedData;
|
|
183
183
|
};
|
|
184
184
|
|
|
185
|
-
const getLozengeTone = (attr: Attributes)
|
|
186
|
-
if (
|
|
185
|
+
const getLozengeTone = (attr: Attributes) => {
|
|
186
|
+
if (
|
|
187
|
+
typeof attr === 'object' &&
|
|
188
|
+
attr !== null &&
|
|
189
|
+
'tone' in attr &&
|
|
190
|
+
typeof attr.tone === 'string' &&
|
|
191
|
+
['danger', 'information', 'plain', 'pending', 'success', 'neutral', 'caution'].includes(attr.tone)
|
|
192
|
+
) {
|
|
187
193
|
return attr.tone as 'danger' | 'information' | 'plain' | 'pending' | 'success' | 'neutral' | 'caution';
|
|
188
194
|
}
|
|
189
195
|
return 'success'; // Default tone
|
|
190
196
|
};
|
|
191
197
|
|
|
198
|
+
const getLozengeLabel = (attr: Attributes) => {
|
|
199
|
+
return attr.value && typeof attr?.value === 'object' && 'label' in attr.value ? String(attr.value.label) : '';
|
|
200
|
+
};
|
|
201
|
+
|
|
192
202
|
onMounted(async () => {
|
|
193
203
|
if (props.isNavApi) {
|
|
194
204
|
navLinks.value = await transformedNavItems(props.navLinks);
|
|
@@ -202,11 +212,10 @@ export const useSidenav = (props: SidenavPropTypes, emit: SetupContext<SidenavEm
|
|
|
202
212
|
navLinks,
|
|
203
213
|
isQuckActionMenuVisible,
|
|
204
214
|
isUserMenuVisible,
|
|
205
|
-
userProfileError,
|
|
206
|
-
getUserInitials,
|
|
207
215
|
handleRedirect,
|
|
208
216
|
generateId,
|
|
209
217
|
transformedNavItems,
|
|
210
|
-
getLozengeTone
|
|
218
|
+
getLozengeTone,
|
|
219
|
+
getLozengeLabel,
|
|
211
220
|
};
|
|
212
221
|
};
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<table aria-describedby="describe" class="spr-h-full spr-w-full spr-table-fixed" cellspacing="0" cellpadding="0">
|
|
22
22
|
<thead>
|
|
23
23
|
<tr v-if="!(props.removeHeaderOnEmpty && sortedData.length <= 0)">
|
|
24
|
-
<th v-if="props.isMultiSelect" :class="[getTableClasses.multiselectClass, getTableClasses.headerClasses]">
|
|
24
|
+
<th v-if="props.isMultiSelect" :class="[getTableClasses.multiselectClass, getTableClasses.headerClasses(null)]">
|
|
25
25
|
<div class="spr-flex spr-items-center spr-justify-center">
|
|
26
26
|
<spr-checkbox
|
|
27
27
|
label=""
|
|
@@ -96,8 +96,8 @@ export const useTable = (props: TablePropTypes, emit: SetupContext<TableEmitType
|
|
|
96
96
|
'spr-background-color': props.variant === 'white',
|
|
97
97
|
'spr-background-color-surface': props.variant === 'surface',
|
|
98
98
|
});
|
|
99
|
-
const headerClasses = (header: Header) => {
|
|
100
|
-
if (header
|
|
99
|
+
const headerClasses = (header: Header | null) => {
|
|
100
|
+
if (header?.customTailwindClasses){
|
|
101
101
|
return classNames(header.customTailwindClasses);
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { mount } from '@vue/test-utils';
|
|
2
|
-
import { describe, it, expect } from 'vitest';
|
|
3
|
-
import DatePicker from '../date-picker.vue';
|
|
4
|
-
|
|
5
|
-
describe('DatePicker', () => {
|
|
6
|
-
it('should render the component', () => {
|
|
7
|
-
const wrapper = mount(DatePicker, {
|
|
8
|
-
props: {
|
|
9
|
-
id: 'test-date-picker',
|
|
10
|
-
modelValue: '',
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
expect(wrapper.exists()).toBe(true);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should use default date format (MM-DD-YYYY) when no format prop is provided', async () => {
|
|
18
|
-
const wrapper = mount(DatePicker, {
|
|
19
|
-
props: {
|
|
20
|
-
id: 'test-date-picker',
|
|
21
|
-
modelValue: '',
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Simulate user selecting a date
|
|
26
|
-
const dateToSelect = '2023-05-15'; // ISO format
|
|
27
|
-
|
|
28
|
-
// Find the input element and simulate user input
|
|
29
|
-
const input = wrapper.find('input');
|
|
30
|
-
await input.setValue(dateToSelect);
|
|
31
|
-
await input.trigger('change');
|
|
32
|
-
|
|
33
|
-
// Check that the emitted value uses the default format MM-DD-YYYY
|
|
34
|
-
const emittedValue = wrapper.emitted('update:modelValue');
|
|
35
|
-
expect(emittedValue).toBeDefined();
|
|
36
|
-
expect(emittedValue![emittedValue!.length - 1][0]).toMatch(/\d{2}-\d{2}-\d{4}/); // MM-DD-YYYY format
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should format the date according to the specified format prop (YYYY-MM-DD)', async () => {
|
|
40
|
-
const wrapper = mount(DatePicker, {
|
|
41
|
-
props: {
|
|
42
|
-
id: 'test-date-picker',
|
|
43
|
-
modelValue: '',
|
|
44
|
-
format: 'YYYY-MM-DD',
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Simulate user selecting a date
|
|
49
|
-
const dateToSelect = '05/15/2023'; // Different format input
|
|
50
|
-
|
|
51
|
-
// Find the input element and simulate user input
|
|
52
|
-
const input = wrapper.find('input');
|
|
53
|
-
await input.setValue(dateToSelect);
|
|
54
|
-
await input.trigger('change');
|
|
55
|
-
|
|
56
|
-
// Check that the emitted value uses the specified format YYYY-MM-DD
|
|
57
|
-
const emittedValue = wrapper.emitted('update:modelValue');
|
|
58
|
-
expect(emittedValue).toBeDefined();
|
|
59
|
-
expect(emittedValue![emittedValue!.length - 1][0]).toMatch(/\d{4}-\d{2}-\d{2}/); // YYYY-MM-DD format
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should format the date according to the specified format prop (MM/DD/YYYY)', async () => {
|
|
63
|
-
const wrapper = mount(DatePicker, {
|
|
64
|
-
props: {
|
|
65
|
-
id: 'test-date-picker',
|
|
66
|
-
modelValue: '',
|
|
67
|
-
format: 'MM/DD/YYYY',
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// Simulate user selecting a date
|
|
72
|
-
const dateToSelect = '2023-05-15'; // ISO format
|
|
73
|
-
|
|
74
|
-
// Find the input element and simulate user input
|
|
75
|
-
const input = wrapper.find('input');
|
|
76
|
-
await input.setValue(dateToSelect);
|
|
77
|
-
await input.trigger('change');
|
|
78
|
-
|
|
79
|
-
// Check that the emitted value uses the specified format MM/DD/YYYY
|
|
80
|
-
const emittedValue = wrapper.emitted('update:modelValue');
|
|
81
|
-
expect(emittedValue).toBeDefined();
|
|
82
|
-
expect(emittedValue![emittedValue!.length - 1][0]).toMatch(/\d{2}\/\d{2}\/\d{4}/); // MM/DD/YYYY format
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should parse dates correctly with different format (MM/DD/YYYY)', async () => {
|
|
86
|
-
const wrapper = mount(DatePicker, {
|
|
87
|
-
props: {
|
|
88
|
-
id: 'test-date-picker',
|
|
89
|
-
modelValue: '05/15/2023', // Using MM/DD/YYYY format
|
|
90
|
-
format: 'MM/DD/YYYY',
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Check that the component correctly displays the date in the input
|
|
95
|
-
const input = wrapper.find('input');
|
|
96
|
-
expect(input.element.value).toBe('05/15/2023');
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should parse dates correctly with different format (YYYY-MM-DD)', async () => {
|
|
100
|
-
const wrapper = mount(DatePicker, {
|
|
101
|
-
props: {
|
|
102
|
-
id: 'test-date-picker',
|
|
103
|
-
modelValue: '2023-05-15', // Using YYYY-MM-DD format
|
|
104
|
-
format: 'YYYY-MM-DD',
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// Check that the component correctly displays the date in the input
|
|
109
|
-
const input = wrapper.find('input');
|
|
110
|
-
expect(input.element.value).toBe('2023-05-15');
|
|
111
|
-
});
|
|
112
|
-
});
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// Test script for dropdown component
|
|
2
|
-
|
|
3
|
-
import { describe, it, expect } from 'vitest';
|
|
4
|
-
import { ref } from 'vue';
|
|
5
|
-
import { useDropdown } from '../use-dropdown';
|
|
6
|
-
|
|
7
|
-
describe('Dropdown Component Fixes', () => {
|
|
8
|
-
describe('Value handling', () => {
|
|
9
|
-
it('should handle string value selection correctly', () => {
|
|
10
|
-
// Setup single-select dropdown with string value
|
|
11
|
-
const modelValue = ref('');
|
|
12
|
-
const menuList = [
|
|
13
|
-
{ text: 'Apple', value: 'apple' },
|
|
14
|
-
{ text: 'Banana', value: 'banana' }
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
const { handleSelectedItem } = useDropdown({
|
|
18
|
-
id: 'test',
|
|
19
|
-
modelValue,
|
|
20
|
-
menuList
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// Simulate selecting an item
|
|
24
|
-
handleSelectedItem([{ text: 'Apple', value: 'apple' }]);
|
|
25
|
-
|
|
26
|
-
// Verify correct value is set
|
|
27
|
-
expect(modelValue.value).toBe('apple');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should handle multiple selection correctly', () => {
|
|
31
|
-
// Setup multi-select dropdown
|
|
32
|
-
const modelValue = ref([]);
|
|
33
|
-
const menuList = [
|
|
34
|
-
{ text: 'Apple', value: 'apple' },
|
|
35
|
-
{ text: 'Banana', value: 'banana' }
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
const { handleSelectedItem } = useDropdown({
|
|
39
|
-
id: 'test',
|
|
40
|
-
modelValue,
|
|
41
|
-
menuList,
|
|
42
|
-
multiSelect: true
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Simulate selecting multiple items
|
|
46
|
-
handleSelectedItem([
|
|
47
|
-
{ text: 'Apple', value: 'apple' },
|
|
48
|
-
{ text: 'Banana', value: 'banana' }
|
|
49
|
-
]);
|
|
50
|
-
|
|
51
|
-
// Verify correct values are set
|
|
52
|
-
expect(modelValue.value).toEqual(['apple', 'banana']);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe('Ladderized dropdown', () => {
|
|
57
|
-
it('should handle ladderized dropdown selection', () => {
|
|
58
|
-
// Setup ladderized dropdown
|
|
59
|
-
const modelValue = ref([]);
|
|
60
|
-
const menuList = [
|
|
61
|
-
{
|
|
62
|
-
text: 'Lion',
|
|
63
|
-
value: 'lion',
|
|
64
|
-
sublevel: [
|
|
65
|
-
{ text: 'Cub', value: 'cub' }
|
|
66
|
-
]
|
|
67
|
-
}
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
const { handleSelectedItem } = useDropdown({
|
|
71
|
-
id: 'test',
|
|
72
|
-
modelValue,
|
|
73
|
-
menuList,
|
|
74
|
-
ladderized: true
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Simulate selecting an item
|
|
78
|
-
handleSelectedItem([{ text: 'Cub', value: 'cub', subvalue: 'lion' }]);
|
|
79
|
-
|
|
80
|
-
// Verify correct values are set for ladderized dropdown
|
|
81
|
-
expect(modelValue.value).toEqual(['lion', 'cub']);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('Edge cases', () => {
|
|
86
|
-
it('should handle empty selection', () => {
|
|
87
|
-
const modelValue = ref('apple');
|
|
88
|
-
const menuList = [
|
|
89
|
-
{ text: 'Apple', value: 'apple' },
|
|
90
|
-
{ text: 'Banana', value: 'banana' }
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
const { handleSelectedItem } = useDropdown({
|
|
94
|
-
id: 'test',
|
|
95
|
-
modelValue,
|
|
96
|
-
menuList
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// Simulate clearing selection
|
|
100
|
-
handleSelectedItem([]);
|
|
101
|
-
|
|
102
|
-
// Verify value is cleared
|
|
103
|
-
expect(modelValue.value).toBeUndefined();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
});
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { ref } from 'vue';
|
|
3
|
-
import { useDropdown } from '../use-dropdown';
|
|
4
|
-
|
|
5
|
-
describe('Dropdown Value Types', () => {
|
|
6
|
-
describe('Single primitive values', () => {
|
|
7
|
-
it('should handle string values', () => {
|
|
8
|
-
const modelValue = 'apple';
|
|
9
|
-
const menuList = ['apple', 'banana', 'cherry'];
|
|
10
|
-
|
|
11
|
-
const { dropdownMenuList, normalizedValue } = useDropdown({
|
|
12
|
-
id: 'test',
|
|
13
|
-
modelValue,
|
|
14
|
-
menuList
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
expect(normalizedValue.value).toEqual(['apple']);
|
|
18
|
-
expect(dropdownMenuList.value).toEqual([
|
|
19
|
-
{ text: 'apple', value: 'apple' },
|
|
20
|
-
{ text: 'banana', value: 'banana' },
|
|
21
|
-
{ text: 'cherry', value: 'cherry' }
|
|
22
|
-
]);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should handle number values', () => {
|
|
26
|
-
const modelValue = 42;
|
|
27
|
-
const menuList = [42, 55, 67];
|
|
28
|
-
|
|
29
|
-
const { dropdownMenuList, normalizedValue } = useDropdown({
|
|
30
|
-
id: 'test',
|
|
31
|
-
modelValue,
|
|
32
|
-
menuList
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
expect(normalizedValue.value).toEqual([42]);
|
|
36
|
-
expect(dropdownMenuList.value).toEqual([
|
|
37
|
-
{ text: '42', value: '42' },
|
|
38
|
-
{ text: '55', value: '55' },
|
|
39
|
-
{ text: '67', value: '67' }
|
|
40
|
-
]);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('Single object values', () => {
|
|
45
|
-
it('should handle object values', () => {
|
|
46
|
-
const employee = { systemId: 1, firstName: 'John', lastName: 'Doe' };
|
|
47
|
-
const modelValue = employee;
|
|
48
|
-
const menuList = [
|
|
49
|
-
{ systemId: 1, firstName: 'John', lastName: 'Doe' },
|
|
50
|
-
{ systemId: 2, firstName: 'Jane', lastName: 'Smith' }
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
const { dropdownMenuList, normalizedValue } = useDropdown({
|
|
54
|
-
id: 'test',
|
|
55
|
-
modelValue,
|
|
56
|
-
menuList,
|
|
57
|
-
textField: 'firstName',
|
|
58
|
-
valueField: 'systemId'
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
expect(normalizedValue.value).toEqual([employee]);
|
|
62
|
-
expect(dropdownMenuList.value[0].text).toBe('John');
|
|
63
|
-
expect(dropdownMenuList.value[1].text).toBe('Jane');
|
|
64
|
-
expect(dropdownMenuList.value[0].value).toBe('1');
|
|
65
|
-
expect(dropdownMenuList.value[0]._originalObject).toEqual(menuList[0]);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe('Multiple primitive values', () => {
|
|
70
|
-
it('should handle string arrays', () => {
|
|
71
|
-
const modelValue = ['apple', 'banana'];
|
|
72
|
-
const menuList = ['apple', 'banana', 'cherry'];
|
|
73
|
-
|
|
74
|
-
const { dropdownMenuList, normalizedValue } = useDropdown({
|
|
75
|
-
id: 'test',
|
|
76
|
-
modelValue,
|
|
77
|
-
menuList,
|
|
78
|
-
multiSelect: true
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
expect(normalizedValue.value).toEqual(['apple', 'banana']);
|
|
82
|
-
expect(dropdownMenuList.value).toEqual([
|
|
83
|
-
{ text: 'apple', value: 'apple' },
|
|
84
|
-
{ text: 'banana', value: 'banana' },
|
|
85
|
-
{ text: 'cherry', value: 'cherry' }
|
|
86
|
-
]);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should handle number arrays', () => {
|
|
90
|
-
const modelValue = [42, 55];
|
|
91
|
-
const menuList = [42, 55, 67];
|
|
92
|
-
|
|
93
|
-
const { dropdownMenuList, normalizedValue } = useDropdown({
|
|
94
|
-
id: 'test',
|
|
95
|
-
modelValue,
|
|
96
|
-
menuList,
|
|
97
|
-
multiSelect: true
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
expect(normalizedValue.value).toEqual([42, 55]);
|
|
101
|
-
expect(dropdownMenuList.value).toEqual([
|
|
102
|
-
{ text: '42', value: '42' },
|
|
103
|
-
{ text: '55', value: '55' },
|
|
104
|
-
{ text: '67', value: '67' }
|
|
105
|
-
]);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('Multiple object values', () => {
|
|
110
|
-
it('should handle object arrays', () => {
|
|
111
|
-
const employees = [
|
|
112
|
-
{ systemId: 1, firstName: 'John', lastName: 'Doe' },
|
|
113
|
-
{ systemId: 2, firstName: 'Jane', lastName: 'Smith' }
|
|
114
|
-
];
|
|
115
|
-
const modelValue = employees;
|
|
116
|
-
const menuList = [
|
|
117
|
-
{ systemId: 1, firstName: 'John', lastName: 'Doe' },
|
|
118
|
-
{ systemId: 2, firstName: 'Jane', lastName: 'Smith' },
|
|
119
|
-
{ systemId: 3, firstName: 'Mike', lastName: 'Johnson' }
|
|
120
|
-
];
|
|
121
|
-
|
|
122
|
-
const { dropdownMenuList, normalizedValue } = useDropdown({
|
|
123
|
-
id: 'test',
|
|
124
|
-
modelValue,
|
|
125
|
-
menuList,
|
|
126
|
-
textField: 'firstName',
|
|
127
|
-
valueField: 'systemId',
|
|
128
|
-
multiSelect: true
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
expect(normalizedValue.value).toEqual(employees);
|
|
132
|
-
expect(dropdownMenuList.value[0].text).toBe('John');
|
|
133
|
-
expect(dropdownMenuList.value[1].text).toBe('Jane');
|
|
134
|
-
expect(dropdownMenuList.value[0].value).toBe('1');
|
|
135
|
-
expect(dropdownMenuList.value[0]._originalObject).toEqual(menuList[0]);
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
describe('Handle selected items', () => {
|
|
140
|
-
it('should output string for string selection', () => {
|
|
141
|
-
const modelValue = ref(undefined);
|
|
142
|
-
const menuList = ['apple', 'banana', 'cherry'];
|
|
143
|
-
|
|
144
|
-
const { handleSelectedItem } = useDropdown({
|
|
145
|
-
id: 'test',
|
|
146
|
-
modelValue,
|
|
147
|
-
menuList,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
handleSelectedItem([{ text: 'apple', value: 'apple' }]);
|
|
151
|
-
expect(modelValue.value).toBe('apple');
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should output number for number selection', () => {
|
|
155
|
-
const modelValue = ref(undefined);
|
|
156
|
-
const menuList = [42, 55, 67];
|
|
157
|
-
|
|
158
|
-
const { handleSelectedItem } = useDropdown({
|
|
159
|
-
id: 'test',
|
|
160
|
-
modelValue,
|
|
161
|
-
menuList,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
handleSelectedItem([{ text: '42', value: '42' }]);
|
|
165
|
-
expect(modelValue.value).toBe(42);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('should output original object for object selection', () => {
|
|
169
|
-
const modelValue = ref(undefined);
|
|
170
|
-
const employeeObj = { systemId: 1, firstName: 'John', lastName: 'Doe' };
|
|
171
|
-
const menuList = [
|
|
172
|
-
employeeObj,
|
|
173
|
-
{ systemId: 2, firstName: 'Jane', lastName: 'Smith' }
|
|
174
|
-
];
|
|
175
|
-
|
|
176
|
-
const { handleSelectedItem, dropdownMenuList } = useDropdown({
|
|
177
|
-
id: 'test',
|
|
178
|
-
modelValue,
|
|
179
|
-
menuList,
|
|
180
|
-
textField: 'firstName',
|
|
181
|
-
valueField: 'systemId'
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Process menu list first to get _originalObject
|
|
185
|
-
dropdownMenuList.value.forEach(item => {
|
|
186
|
-
if (item.value === '1') {
|
|
187
|
-
handleSelectedItem([item]);
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
expect(modelValue.value).toEqual(employeeObj);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should output array for multi-select', () => {
|
|
195
|
-
const modelValue = ref([]);
|
|
196
|
-
const menuList = ['apple', 'banana', 'cherry'];
|
|
197
|
-
|
|
198
|
-
const { handleSelectedItem } = useDropdown({
|
|
199
|
-
id: 'test',
|
|
200
|
-
modelValue,
|
|
201
|
-
menuList,
|
|
202
|
-
multiSelect: true
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
handleSelectedItem([
|
|
206
|
-
{ text: 'apple', value: 'apple' },
|
|
207
|
-
{ text: 'banana', value: 'banana' }
|
|
208
|
-
]);
|
|
209
|
-
|
|
210
|
-
expect(modelValue.value).toEqual(['apple', 'banana']);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
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>
|