design-system-next 2.8.1 → 2.9.1
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 +9266 -9121
- 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/banner/banner.ts +20 -0
- package/src/components/banner/banner.vue +28 -0
- package/src/components/banner/use-banner.ts +96 -0
- package/src/components/calendar/calendar.ts +4 -31
- package/src/components/calendar/calendar.vue +186 -223
- package/src/components/calendar/use-calendar.ts +72 -38
- package/src/components/calendar-cell/use-calendar-cell.ts +0 -1
- package/src/components/list/use-list.ts +10 -6
- 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 +164 -165
- 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 +31 -26
- package/src/components/snackbar/snack/snack.vue +6 -1
- package/src/components/stepper/step/step.ts +8 -0
- package/src/components/stepper/step/step.vue +3 -1
- package/src/components/stepper/step/use-step.ts +22 -10
- package/src/components/stepper/stepper.ts +9 -0
- package/src/components/stepper/stepper.vue +1 -0
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { computed, SetupContext, toRefs, ref, watch } from 'vue';
|
|
2
2
|
import dayjs from 'dayjs';
|
|
3
|
+
import isBetween from 'dayjs/plugin/isBetween';
|
|
3
4
|
import classNames from 'classnames';
|
|
5
|
+
import { useInfiniteScroll } from '@vueuse/core';
|
|
4
6
|
import { useVModel } from '@vueuse/core';
|
|
5
7
|
|
|
8
|
+
dayjs.extend(isBetween);
|
|
9
|
+
|
|
6
10
|
import type { CalendarPropTypes, CalendarEmitTypes, SelectedShift } from './calendar';
|
|
7
11
|
|
|
8
12
|
export const useCalendar = (props: CalendarPropTypes, emit: SetupContext<CalendarEmitTypes>['emit']) => {
|
|
9
|
-
const { initialDate,
|
|
13
|
+
const { initialDate, hideAddButton } = toRefs(props);
|
|
10
14
|
|
|
11
15
|
const state = {
|
|
12
16
|
dateFormat: ref('YYYY-MM-DD'),
|
|
@@ -21,13 +25,20 @@ export const useCalendar = (props: CalendarPropTypes, emit: SetupContext<Calenda
|
|
|
21
25
|
isHover: ref<boolean>(false),
|
|
22
26
|
hoveredCell: ref<number>(),
|
|
23
27
|
employeeId: ref<number>(),
|
|
28
|
+
sort: ref<string>(''),
|
|
29
|
+
tableBodyRef: ref<HTMLElement | null>(null),
|
|
24
30
|
};
|
|
25
31
|
|
|
26
32
|
const searchEmployee = useVModel(props, 'search', emit);
|
|
27
33
|
const selectedCell = useVModel(props, 'selectedCell', emit);
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
34
|
+
|
|
35
|
+
const getSortIcon = computed(() => {
|
|
36
|
+
if (!state.sort.value) {
|
|
37
|
+
return 'ph:caret-up-down-light';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return state.sort.value === 'asc' ? 'ph:arrow-up' : 'ph:arrow-down';
|
|
41
|
+
});
|
|
31
42
|
|
|
32
43
|
const startDate = computed(() => state.currentDate.value.startOf('week'));
|
|
33
44
|
|
|
@@ -63,64 +74,81 @@ export const useCalendar = (props: CalendarPropTypes, emit: SetupContext<Calenda
|
|
|
63
74
|
state.currentDate.value = state.currentDate.value.add(1, 'week');
|
|
64
75
|
};
|
|
65
76
|
|
|
77
|
+
const getFirstAndLastDayOfWeek = () => {
|
|
78
|
+
if (!state.currentDate.value) return;
|
|
79
|
+
|
|
80
|
+
const firstDayOfWeek = state.currentDate.value.startOf('week');
|
|
81
|
+
const lastDayOfWeek = state.currentDate.value.endOf('week');
|
|
82
|
+
|
|
83
|
+
emit('update:firstLastDayOfWeek', {
|
|
84
|
+
firstDay: firstDayOfWeek.format(state.dateFormat.value),
|
|
85
|
+
lastDay: lastDayOfWeek.format(state.dateFormat.value),
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
66
89
|
const goToToday = () => {
|
|
67
|
-
|
|
90
|
+
const today = dayjs();
|
|
91
|
+
const currentWeekStart = state.currentDate.value.startOf('week');
|
|
92
|
+
const currentWeekEnd = state.currentDate.value.endOf('week');
|
|
93
|
+
|
|
94
|
+
// Only update if today is not within the current week
|
|
95
|
+
if (!today.isBetween(currentWeekStart, currentWeekEnd, 'day', '[]')) {
|
|
96
|
+
state.currentDate.value = today;
|
|
97
|
+
}
|
|
68
98
|
};
|
|
69
99
|
|
|
70
|
-
const
|
|
100
|
+
const onCellClick = (selected: SelectedShift) => {
|
|
71
101
|
selectedCell.value = selected;
|
|
102
|
+
emit('onCellClick', selected);
|
|
72
103
|
};
|
|
73
104
|
|
|
74
105
|
const handleHover = (isHover: boolean, index: number, employeeId: number) => {
|
|
75
106
|
state.isHover.value = isHover;
|
|
76
|
-
state.hoveredCell.value = isHover ? index :
|
|
107
|
+
state.hoveredCell.value = isHover ? index : undefined;
|
|
77
108
|
state.employeeId.value = employeeId;
|
|
78
109
|
};
|
|
79
110
|
|
|
80
111
|
const showAddShift = (index: number, employeeId: number) => {
|
|
81
|
-
return
|
|
112
|
+
return (
|
|
113
|
+
state.hoveredCell.value === index &&
|
|
114
|
+
state.isHover.value &&
|
|
115
|
+
state.employeeId.value === employeeId &&
|
|
116
|
+
!hideAddButton.value
|
|
117
|
+
);
|
|
82
118
|
};
|
|
83
119
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
state.selectedCompany.value = foundCompany?.text ?? '';
|
|
88
|
-
selectedCompany.value = selected;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (filter === 'department') {
|
|
92
|
-
const foundCompany = departmentOptions.value.find((item) => item.value === selected);
|
|
93
|
-
state.selectedDepartment.value = foundCompany?.text ?? '';
|
|
94
|
-
selectedDepartment.value = selected;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (filter === 'branch') {
|
|
98
|
-
const foundCompany = branchOptions.value.find((item) => item.value === selected);
|
|
99
|
-
state.selectedBranch.value = foundCompany?.text ?? '';
|
|
100
|
-
selectedBranch.value = selected;
|
|
101
|
-
}
|
|
120
|
+
const handleSorting = () => {
|
|
121
|
+
state.sort.value = state.sort.value === 'desc' ? 'asc' : 'desc';
|
|
122
|
+
emit('update:sort', state.sort.value);
|
|
102
123
|
};
|
|
103
124
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
125
|
+
useInfiniteScroll(
|
|
126
|
+
state.tableBodyRef,
|
|
127
|
+
() => {
|
|
128
|
+
emit('loadMore');
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
distance: 50,
|
|
132
|
+
direction: 'bottom',
|
|
133
|
+
},
|
|
134
|
+
);
|
|
108
135
|
|
|
109
136
|
const getCalendarClasses = computed(() => {
|
|
110
137
|
const borderClasses = classNames(' spr-border spr-border-color-weak spr-border-solid');
|
|
111
138
|
const headerWrapper = classNames(
|
|
112
|
-
'spr-bg-color-weak spr-flex spr-w-full spr-items-center spr-justify-between spr-
|
|
139
|
+
'spr-bg-color-weak spr-flex spr-w-full spr-items-center spr-justify-between spr-p-size-spacing-sm',
|
|
113
140
|
);
|
|
114
141
|
|
|
115
142
|
const contentWrapper = classNames('spr-divide-color-weak spr-divide-x-0 spr-divide-y spr-divide-solid');
|
|
116
|
-
const calendarFilter = classNames('spr-grid spr-grid-cols-4 spr-gap-size-spacing-2xs spr-p-size-spacing-xs');
|
|
117
143
|
const calendarTable = classNames(
|
|
118
|
-
'spr-table spr-w-full spr-table-fixed spr-border-collapse spr-border-spacing-0 spr-
|
|
144
|
+
' spr-overflow-y-auto spr-h-full spr-table spr-w-full spr-table-fixed spr-border-collapse spr-border-spacing-0 spr-rounded-border',
|
|
119
145
|
);
|
|
120
146
|
const tableHeaderEmployeeName = classNames(
|
|
121
|
-
'spr-
|
|
147
|
+
'spr-sticky spr-left-0 spr-z-20 spr-background-color spr-body-xs-regular-medium spr-p-size-spacing-xs spr-text-left spr-overflow-hidden spr-h-full',
|
|
148
|
+
);
|
|
149
|
+
const tableHeader = classNames(
|
|
150
|
+
'spr-background-color spr-border-x-0 spr-border-y-0 spr-border-l spr-p-size-spacing-sm spr-text-center',
|
|
122
151
|
);
|
|
123
|
-
const tableHeader = classNames('spr-border-x-0 spr-border-y spr-border-l spr-p-size-spacing-sm spr-text-center');
|
|
124
152
|
const headerContent = classNames(
|
|
125
153
|
'spr-flex spr-flex-row spr-w-full spr-items-center spr-gap-size-spacing-3xs lg:spr-flex-col spr-overflow-hidden',
|
|
126
154
|
);
|
|
@@ -128,11 +156,16 @@ export const useCalendar = (props: CalendarPropTypes, emit: SetupContext<Calenda
|
|
|
128
156
|
'spr-font-size-400 spr-line-height-500 spr-letter-spacing-dense spr-flex spr-h-size-spacing-md spr-w-size-spacing-md spr-items-center spr-justify-center spr-rounded-full spr-font-main spr-font-normal',
|
|
129
157
|
);
|
|
130
158
|
|
|
159
|
+
getFirstAndLastDayOfWeek();
|
|
160
|
+
|
|
161
|
+
watch(state.searchTerm, (value, oldValue) => {
|
|
162
|
+
if (value === oldValue) return; // Prevent unnecessary updates
|
|
163
|
+
searchEmployee.value = value;
|
|
164
|
+
});
|
|
131
165
|
return {
|
|
132
166
|
borderClasses,
|
|
133
167
|
headerWrapper,
|
|
134
168
|
contentWrapper,
|
|
135
|
-
calendarFilter,
|
|
136
169
|
calendarTable,
|
|
137
170
|
tableHeaderEmployeeName,
|
|
138
171
|
tableHeader,
|
|
@@ -145,16 +178,17 @@ export const useCalendar = (props: CalendarPropTypes, emit: SetupContext<Calenda
|
|
|
145
178
|
weekDates,
|
|
146
179
|
weekRangeDisplay,
|
|
147
180
|
getCalendarClasses,
|
|
181
|
+
getSortIcon,
|
|
148
182
|
|
|
149
183
|
formatDate,
|
|
150
184
|
isToday,
|
|
151
185
|
prevWeek,
|
|
152
186
|
nextWeek,
|
|
153
187
|
goToToday,
|
|
154
|
-
|
|
188
|
+
onCellClick,
|
|
155
189
|
handleHover,
|
|
156
190
|
showAddShift,
|
|
157
|
-
|
|
191
|
+
handleSorting,
|
|
158
192
|
|
|
159
193
|
...state,
|
|
160
194
|
};
|
|
@@ -358,13 +358,17 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
|
|
|
358
358
|
};
|
|
359
359
|
// #endregion - Helper Methods
|
|
360
360
|
|
|
361
|
-
watch(
|
|
362
|
-
|
|
363
|
-
|
|
361
|
+
watch(
|
|
362
|
+
menuList,
|
|
363
|
+
() => {
|
|
364
|
+
localizedMenuList.value = [];
|
|
365
|
+
groupedMenuList.value = [];
|
|
364
366
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
367
|
+
setMenuList();
|
|
368
|
+
setPreSelectedItems();
|
|
369
|
+
},
|
|
370
|
+
{ deep: true },
|
|
371
|
+
);
|
|
368
372
|
|
|
369
373
|
onMounted(() => {
|
|
370
374
|
setMenuList();
|
|
@@ -30,7 +30,7 @@ export const selectLadderizedPropTypes = {
|
|
|
30
30
|
type: Array as PropType<string[]>,
|
|
31
31
|
default: () => [],
|
|
32
32
|
},
|
|
33
|
-
|
|
33
|
+
options: {
|
|
34
34
|
type: Array as PropType<MenuListType[]>,
|
|
35
35
|
required: true,
|
|
36
36
|
default: () => [],
|
|
@@ -59,11 +59,11 @@ export const selectLadderizedPropTypes = {
|
|
|
59
59
|
type: Boolean,
|
|
60
60
|
default: false,
|
|
61
61
|
},
|
|
62
|
-
|
|
62
|
+
searchableOptions: {
|
|
63
63
|
type: Boolean,
|
|
64
64
|
default: false,
|
|
65
65
|
},
|
|
66
|
-
|
|
66
|
+
searchableOptionsPlaceholder: {
|
|
67
67
|
type: String,
|
|
68
68
|
default: 'Search...',
|
|
69
69
|
},
|
|
@@ -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="spr-cursor-pointer"
|
|
@@ -57,15 +57,15 @@
|
|
|
57
57
|
ref="ladderizedSelectRef"
|
|
58
58
|
class="spr-grid spr-max-h-[300px] spr-gap-0.5 spr-overflow-y-auto spr-overflow-x-hidden"
|
|
59
59
|
>
|
|
60
|
-
<template v-if="
|
|
60
|
+
<template v-if="ladderizedSelectOptions.length > 0">
|
|
61
61
|
<spr-ladderized-list
|
|
62
62
|
v-model="ladderizedSelectModel"
|
|
63
63
|
:ladderized="true"
|
|
64
|
-
:menu-list="
|
|
64
|
+
:menu-list="ladderizedSelectOptions"
|
|
65
65
|
:menu-level="ladderizedSelectModel.length"
|
|
66
66
|
:remove-current-level-in-back-label="props.removeCurrentLevelInBackLabel"
|
|
67
|
-
:searchable-menu="props.
|
|
68
|
-
:searchable-menu-placeholder="props.
|
|
67
|
+
:searchable-menu="props.searchableOptions"
|
|
68
|
+
:searchable-menu-placeholder="props.searchableOptionsPlaceholder"
|
|
69
69
|
@update:model-value="handleSelectedLadderizedItem"
|
|
70
70
|
/>
|
|
71
71
|
</template>
|
|
@@ -99,13 +99,13 @@ const {
|
|
|
99
99
|
ladderizedClasses,
|
|
100
100
|
ladderizedSelectPopperState,
|
|
101
101
|
ladderizedSelectRef,
|
|
102
|
-
|
|
102
|
+
ladderizedSelectOptions,
|
|
103
103
|
isLadderizedSelectPopperDisabled,
|
|
104
104
|
ladderizedSelectModel,
|
|
105
105
|
inputText,
|
|
106
106
|
handleSelectedLadderizedItem,
|
|
107
107
|
handleSearch,
|
|
108
108
|
handleClear,
|
|
109
|
-
|
|
109
|
+
handleOptionsToggle,
|
|
110
110
|
} = useSelectLadderized(props, emit);
|
|
111
111
|
</script>
|
|
@@ -1,165 +1,164 @@
|
|
|
1
|
-
import { ref, computed, watch } from 'vue';
|
|
2
|
-
import { useDebounceFn, onClickOutside } from '@vueuse/core';
|
|
3
|
-
|
|
4
|
-
import type { SelectLadderizedPropTypes } from './select-ladderized';
|
|
5
|
-
|
|
6
|
-
import type { MenuListType } from '@/components/list/list';
|
|
7
|
-
|
|
8
|
-
export const useSelectLadderized = (
|
|
9
|
-
props: SelectLadderizedPropTypes,
|
|
10
|
-
emit: (event: string, ...args: unknown[]) => void,
|
|
11
|
-
) => {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
() =>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
};
|
|
1
|
+
import { ref, toRefs, computed, watch } from 'vue';
|
|
2
|
+
import { useVModel, useDebounceFn, onClickOutside } from '@vueuse/core';
|
|
3
|
+
|
|
4
|
+
import type { SelectLadderizedPropTypes } from './select-ladderized';
|
|
5
|
+
|
|
6
|
+
import type { MenuListType } from '@/components/list/list';
|
|
7
|
+
|
|
8
|
+
export const useSelectLadderized = (
|
|
9
|
+
props: SelectLadderizedPropTypes,
|
|
10
|
+
emit: (event: string, ...args: unknown[]) => void,
|
|
11
|
+
) => {
|
|
12
|
+
const { options, disabled } = toRefs(props);
|
|
13
|
+
|
|
14
|
+
const ladderizedClasses = computed(() => ({
|
|
15
|
+
baseClasses: 'spr-flex spr-flex-col spr-gap-size-spacing-4xs',
|
|
16
|
+
labelClasses: 'spr-body-sm-regular spr-text-color-strong spr-block',
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
// Popper Variables
|
|
20
|
+
const ladderizedSelectPopperState = ref(false);
|
|
21
|
+
const ladderizedSelectRef = ref(null);
|
|
22
|
+
const isLadderizedSelectPopperDisabled = computed(() => disabled.value);
|
|
23
|
+
|
|
24
|
+
// Ladderized Select Model
|
|
25
|
+
const ladderizedSelectModel = useVModel(props, 'modelValue', emit);
|
|
26
|
+
const ladderizedSelectOptions = computed(() => options.value);
|
|
27
|
+
|
|
28
|
+
// Input Variables
|
|
29
|
+
const inputText = ref<string>('');
|
|
30
|
+
const isSearching = ref(false);
|
|
31
|
+
const wasCleared = ref(false);
|
|
32
|
+
|
|
33
|
+
const isLeafNode = (item: MenuListType): boolean => {
|
|
34
|
+
return !item.sublevel || item.sublevel.length === 0;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Helper to find the path to a selected value in the menu tree
|
|
38
|
+
const findPathToValue = (items: MenuListType[], value: string | number, path: string[] = []): string[] | null => {
|
|
39
|
+
for (const item of items) {
|
|
40
|
+
const newPath = [...path, item.text];
|
|
41
|
+
|
|
42
|
+
if (item.value === value) {
|
|
43
|
+
return newPath;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (item.sublevel) {
|
|
47
|
+
const result = findPathToValue(item.sublevel, value, newPath);
|
|
48
|
+
|
|
49
|
+
if (result) return result;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handleSelectedLadderizedItem = (selectedItems: string[], selectedItem?: MenuListType) => {
|
|
57
|
+
wasCleared.value = false;
|
|
58
|
+
ladderizedSelectModel.value = selectedItems;
|
|
59
|
+
|
|
60
|
+
let itemToCheck = selectedItem;
|
|
61
|
+
|
|
62
|
+
// Fallback: if selectedItem is not provided, try to find it from the value
|
|
63
|
+
if (!itemToCheck && selectedItems.length > 0) {
|
|
64
|
+
const findItemByValue = (items: MenuListType[], value: string | number): MenuListType | undefined => {
|
|
65
|
+
for (const item of items) {
|
|
66
|
+
if (item.value === value) return item;
|
|
67
|
+
|
|
68
|
+
if (item.sublevel) {
|
|
69
|
+
const found = findItemByValue(item.sublevel, value);
|
|
70
|
+
|
|
71
|
+
if (found) return found;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return undefined;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
itemToCheck = findItemByValue(ladderizedSelectOptions.value, selectedItems[selectedItems.length - 1]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (itemToCheck) {
|
|
82
|
+
const path = findPathToValue(ladderizedSelectOptions.value, itemToCheck.value);
|
|
83
|
+
|
|
84
|
+
inputText.value = path ? path.join(' > ') : itemToCheck.text || '';
|
|
85
|
+
|
|
86
|
+
if (isLeafNode(itemToCheck)) {
|
|
87
|
+
ladderizedSelectPopperState.value = false;
|
|
88
|
+
}
|
|
89
|
+
} else if (selectedItems.length === 0 && !wasCleared.value) {
|
|
90
|
+
inputText.value = '';
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const handleSearch = () => {
|
|
95
|
+
isSearching.value = true;
|
|
96
|
+
|
|
97
|
+
debouncedEmitSearch();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const debouncedEmitSearch = useDebounceFn(() => {
|
|
101
|
+
// Optionally emit search event here if needed
|
|
102
|
+
}, 300);
|
|
103
|
+
|
|
104
|
+
const handleClear = () => {
|
|
105
|
+
wasCleared.value = true;
|
|
106
|
+
|
|
107
|
+
inputText.value = '';
|
|
108
|
+
|
|
109
|
+
emit('update:modelValue', []);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const handleOptionsToggle = () => {
|
|
113
|
+
ladderizedSelectPopperState.value = true;
|
|
114
|
+
|
|
115
|
+
isSearching.value = false;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Watch for changes in modelValue to update inputText
|
|
119
|
+
watch(
|
|
120
|
+
() => ladderizedSelectModel.value,
|
|
121
|
+
(newVal) => {
|
|
122
|
+
if (wasCleared.value) {
|
|
123
|
+
inputText.value = '';
|
|
124
|
+
wasCleared.value = false;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (Array.isArray(newVal) && newVal.length > 0) {
|
|
129
|
+
// Treat the array as a single path for ladderized select
|
|
130
|
+
let currentLevel = ladderizedSelectOptions.value;
|
|
131
|
+
|
|
132
|
+
const pathTexts: string[] = [];
|
|
133
|
+
|
|
134
|
+
for (const value of newVal) {
|
|
135
|
+
const found = currentLevel.find((item) => item.value === value);
|
|
136
|
+
if (!found) break;
|
|
137
|
+
pathTexts.push(found.text);
|
|
138
|
+
currentLevel = found.sublevel || [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
inputText.value = pathTexts.join(' > ');
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
{ immediate: true },
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
onClickOutside(ladderizedSelectRef, () => {
|
|
148
|
+
ladderizedSelectPopperState.value = false;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
ladderizedClasses,
|
|
153
|
+
ladderizedSelectPopperState,
|
|
154
|
+
ladderizedSelectRef,
|
|
155
|
+
ladderizedSelectOptions,
|
|
156
|
+
isLadderizedSelectPopperDisabled,
|
|
157
|
+
ladderizedSelectModel,
|
|
158
|
+
inputText,
|
|
159
|
+
handleSelectedLadderizedItem,
|
|
160
|
+
handleSearch,
|
|
161
|
+
handleClear,
|
|
162
|
+
handleOptionsToggle,
|
|
163
|
+
};
|
|
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>;
|