design-system-next 2.19.0 → 2.19.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.es.js +7872 -7939
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +12 -13
- 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/App.vue +1 -51
- package/src/components/chips/chips.vue +4 -1
- package/src/components/date-picker/{reusable-calendar/reusable-calendar.ts → date-calendar-picker/date-calendar-picker.ts} +4 -4
- package/src/components/date-picker/{reusable-calendar/reusable-calendar.vue → date-calendar-picker/date-calendar-picker.vue} +10 -10
- package/src/components/date-picker/{reusable-calendar/use-reusable-calendar.ts → date-calendar-picker/use-date-calendar-picker.ts} +4 -4
- package/src/components/list/ladderized-list/use-ladderized-list.ts +19 -8
- package/src/components/list/list.ts +0 -4
- package/src/components/list/list.vue +20 -42
- package/src/components/list/use-list.ts +0 -1
- package/src/components/select/select-ladderized/select-ladderized.ts +5 -1
- package/src/components/select/select-ladderized/select-ladderized.vue +3 -1
- package/src/components/select/select-ladderized/use-select-ladderized.ts +17 -4
- package/src/components/select/select-multiple/select-multiple.ts +0 -4
- package/src/components/select/select-multiple/select-multiple.vue +4 -3
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
@click="handleClick"
|
|
9
9
|
@keyup.enter="handleClick"
|
|
10
10
|
>
|
|
11
|
-
<template v-if="
|
|
11
|
+
<template v-if="slots.default">
|
|
12
|
+
<slot />
|
|
13
|
+
</template>
|
|
14
|
+
<template v-else-if="variant === 'tag'">
|
|
12
15
|
<span v-if="hasIcon" class="chips-icon spr-inline-flex spr-items-center spr-leading-[0]">
|
|
13
16
|
<slot name="icon">
|
|
14
17
|
<Icon :icon="getIcon" class="spr-font-size-300" />
|
|
@@ -27,7 +27,7 @@ export type RestDayType = 'su' | 'mo' | 'tu' | 'we' | 'th' | 'fr' | 'sa';
|
|
|
27
27
|
export type DatePickerMode = typeof DATE_PICKER_MODES[number];
|
|
28
28
|
|
|
29
29
|
// Define props with JSDoc comments for documentation
|
|
30
|
-
export const
|
|
30
|
+
export const dateCalendarPickerPropTypes = {
|
|
31
31
|
/**
|
|
32
32
|
* @description The selected date value (v-model)
|
|
33
33
|
*/
|
|
@@ -109,7 +109,7 @@ export const reusableCalendarPropTypes = {
|
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
// Define emits with type validation
|
|
112
|
-
export const
|
|
112
|
+
export const dateCalendarPickerEmitTypes = {
|
|
113
113
|
'update:modelValue': (value: string): value is string => typeof value === 'string',
|
|
114
114
|
'update:month': (month: number): month is number => typeof month === 'number',
|
|
115
115
|
'update:year': (year: number): year is number => typeof year === 'number',
|
|
@@ -117,5 +117,5 @@ export const reusableCalendarEmitTypes = {
|
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
// Export types for use in other files
|
|
120
|
-
export type
|
|
121
|
-
export type
|
|
120
|
+
export type DateCalendarPickerPropTypes = ExtractPropTypes<typeof dateCalendarPickerPropTypes>;
|
|
121
|
+
export type DateCalendarPickerEmitTypes = typeof dateCalendarPickerEmitTypes;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
ref="
|
|
4
|
-
:class="
|
|
3
|
+
ref="dateCalendarPickerRef"
|
|
4
|
+
:class="dateCalendarPickerClasses"
|
|
5
5
|
>
|
|
6
6
|
<div
|
|
7
7
|
:class="[
|
|
@@ -132,13 +132,13 @@ import DatePickerCalendarTab from '../tabs/DatePickerCalendarTab.vue';
|
|
|
132
132
|
import DatePickerMonthTab from '../tabs/DatePickerMonthTab.vue';
|
|
133
133
|
import DatePickerYearTab from '../tabs/DatePickerYearTab.vue';
|
|
134
134
|
|
|
135
|
-
import {
|
|
136
|
-
import {
|
|
135
|
+
import { useDateCalendarPicker } from './use-date-calendar-picker';
|
|
136
|
+
import { dateCalendarPickerEmitTypes, dateCalendarPickerPropTypes } from './date-calendar-picker';
|
|
137
137
|
|
|
138
|
-
const props = defineProps(
|
|
139
|
-
const emit = defineEmits(
|
|
138
|
+
const props = defineProps(dateCalendarPickerPropTypes);
|
|
139
|
+
const emit = defineEmits(dateCalendarPickerEmitTypes);
|
|
140
140
|
|
|
141
|
-
const
|
|
141
|
+
const dateCalendarPickerRef = ref<HTMLElement | null>(null);
|
|
142
142
|
|
|
143
143
|
// Use the composable for all logic
|
|
144
144
|
const {
|
|
@@ -176,12 +176,12 @@ const {
|
|
|
176
176
|
handleMonthTabMonthUpdateWrapper,
|
|
177
177
|
handleYearTabYearUpdateWrapper,
|
|
178
178
|
handleYearTabCurrentPageUpdateWrapper,
|
|
179
|
-
} =
|
|
179
|
+
} = useDateCalendarPicker(props, emit);
|
|
180
180
|
|
|
181
181
|
// Compute CSS classes using classNames utility
|
|
182
|
-
const
|
|
182
|
+
const dateCalendarPickerClasses = computed(() => {
|
|
183
183
|
return classNames(
|
|
184
|
-
'
|
|
184
|
+
'date-calendar-picker-container spr-bg-white spr-rounded-lg spr-shadow-lg spr-border spr-border-solid spr-border-mushroom-200 min-w-[320px]',
|
|
185
185
|
{
|
|
186
186
|
'spr-disabled': props.disabled,
|
|
187
187
|
'spr-readonly': props.readonly,
|
|
@@ -3,11 +3,11 @@ import { toRefs } from 'vue';
|
|
|
3
3
|
import dayjs from 'dayjs';
|
|
4
4
|
|
|
5
5
|
import type { SetupContext } from 'vue';
|
|
6
|
-
import type {
|
|
6
|
+
import type { DateCalendarPickerEmitTypes, DateCalendarPickerPropTypes } from './date-calendar-picker';
|
|
7
7
|
|
|
8
|
-
export const
|
|
9
|
-
props:
|
|
10
|
-
emit: SetupContext<
|
|
8
|
+
export const useDateCalendarPicker = (
|
|
9
|
+
props: DateCalendarPickerPropTypes,
|
|
10
|
+
emit: SetupContext<DateCalendarPickerEmitTypes>['emit']
|
|
11
11
|
) => {
|
|
12
12
|
// Extract reactive props
|
|
13
13
|
const {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { onBeforeMount, ref, toRefs, watch } from 'vue';
|
|
2
|
-
import { useVModel } from '@vueuse/core';
|
|
3
|
-
|
|
2
|
+
import { useVModel, watchDeep } from '@vueuse/core';
|
|
4
3
|
import { LadderizedListPropTypes, LadderizedListEmitTypes } from './ladderized-list';
|
|
5
|
-
|
|
6
4
|
import type { SetupContext } from 'vue';
|
|
7
5
|
import type { MenuListType } from '../list';
|
|
8
6
|
|
|
@@ -21,6 +19,8 @@ export const useLadderizedList = (
|
|
|
21
19
|
const activeList = ref<MenuListType[]>(menuList.value); // List of items to display in the active level
|
|
22
20
|
const searchText = ref('');
|
|
23
21
|
|
|
22
|
+
const modelValueIsCustom = ref(false);
|
|
23
|
+
|
|
24
24
|
// Recursive filter function for ladderized options
|
|
25
25
|
const filterOptionsRecursive = (items: MenuListType[], search: string): MenuListType[] => {
|
|
26
26
|
if (!search) return items;
|
|
@@ -86,6 +86,12 @@ export const useLadderizedList = (
|
|
|
86
86
|
const handleSelectedListItem = (item: MenuListType) => {
|
|
87
87
|
transitionName.value = 'slide-left';
|
|
88
88
|
|
|
89
|
+
if (modelValueIsCustom.value) {
|
|
90
|
+
console.log("Custom");
|
|
91
|
+
ladderizedListOutput.value.shift();
|
|
92
|
+
modelValueIsCustom.value = false;
|
|
93
|
+
};
|
|
94
|
+
|
|
89
95
|
// If searching, reconstruct full path as array of option objects
|
|
90
96
|
if (searchText.value) {
|
|
91
97
|
const path = findOptionPath(menuList.value, String(item.value));
|
|
@@ -111,7 +117,7 @@ export const useLadderizedList = (
|
|
|
111
117
|
replaceItemInOutput(item);
|
|
112
118
|
}
|
|
113
119
|
|
|
114
|
-
if (item.sublevel && item.sublevel.length > 0) updateLevel(item);
|
|
120
|
+
if (item.sublevel && item.sublevel.length > 0) updateLevel(item); // FIXME: This causes activeLevel one less than expected. Currently not critical since most forms are 2 levels deep.
|
|
115
121
|
emit('update:modelValue', ladderizedListOutput.value);
|
|
116
122
|
};
|
|
117
123
|
|
|
@@ -224,9 +230,14 @@ export const useLadderizedList = (
|
|
|
224
230
|
|
|
225
231
|
prevList.value = activeList.value;
|
|
226
232
|
activeList.value = item.sublevel ?? prevList.value;
|
|
227
|
-
activeLevel.value += item.sublevel ? 1 : 0;
|
|
233
|
+
activeLevel.value += item.sublevel ? 1 : 0; // FIXME: This causes activeLevel one less than expected. Currently not critical since most forms are 2 levels deep.
|
|
228
234
|
} else {
|
|
229
|
-
// If no item found,
|
|
235
|
+
// If no item found, rest the values to initial state
|
|
236
|
+
selectedListItem.value = [];
|
|
237
|
+
prevList.value = [];
|
|
238
|
+
activeList.value = menuList.value;
|
|
239
|
+
activeLevel.value = 0;
|
|
240
|
+
modelValueIsCustom.value = true;
|
|
230
241
|
return;
|
|
231
242
|
}
|
|
232
243
|
});
|
|
@@ -241,8 +252,8 @@ export const useLadderizedList = (
|
|
|
241
252
|
};
|
|
242
253
|
|
|
243
254
|
// Watch for modelValue changes and reset selectedListItem if cleared
|
|
244
|
-
|
|
245
|
-
|
|
255
|
+
watchDeep(
|
|
256
|
+
ladderizedListOutput,
|
|
246
257
|
(newVal) => {
|
|
247
258
|
if (!newVal || (Array.isArray(newVal) && newVal.length === 0)) {
|
|
248
259
|
selectedListItem.value = [];
|
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="spr-font-main">
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
v-model="searchText"
|
|
20
|
-
:placeholder="props.searchableMenuPlaceholder"
|
|
21
|
-
autocomplete="off"
|
|
22
|
-
/>
|
|
23
|
-
<span v-if="props.displayListItemSelected" class="spr-label-sm-medium spr-text-color-base spr-block">
|
|
24
|
-
{{ selectedItems.length }} Selected
|
|
25
|
-
</span>
|
|
26
|
-
</div>
|
|
27
|
-
</template>
|
|
3
|
+
<div
|
|
4
|
+
v-if="props.searchableMenu"
|
|
5
|
+
:class="[
|
|
6
|
+
'spr-sticky spr-z-20',
|
|
7
|
+
'spr-grid spr-gap-3 spr-bg-white-50 spr-p-size-spacing-3xs',
|
|
8
|
+
'spr-border-color-weak spr-border spr-border-x-0 spr-border-b spr-border-t-0 spr-border-solid',
|
|
9
|
+
]"
|
|
10
|
+
:style="{
|
|
11
|
+
top:
|
|
12
|
+
typeof props.stickySearchOffset === 'number'
|
|
13
|
+
? props.stickySearchOffset + 'px'
|
|
14
|
+
: String(props.stickySearchOffset),
|
|
15
|
+
}"
|
|
16
|
+
>
|
|
17
|
+
<spr-input-search v-model="searchText" :placeholder="props.searchableMenuPlaceholder" autocomplete="off" />
|
|
18
|
+
</div>
|
|
28
19
|
|
|
29
20
|
<div class="spr-p-size-spacing-3xs">
|
|
30
21
|
<template v-if="props.groupItemsBy">
|
|
@@ -72,16 +63,13 @@
|
|
|
72
63
|
{ 'spr-text-color-disabled': item.disabled },
|
|
73
64
|
]"
|
|
74
65
|
>
|
|
75
|
-
<span class="spr-text-left spr-text-xs"
|
|
76
|
-
{{ item.text }}
|
|
77
|
-
</span>
|
|
66
|
+
<span class="spr-text-left spr-text-xs">{{ item.text }}</span>
|
|
78
67
|
<span
|
|
79
68
|
v-if="item.subtext"
|
|
80
69
|
:class="[
|
|
81
70
|
'spr-body-xs-regular spr-text-color-base spr-text-left',
|
|
82
71
|
{ 'spr-text-color-disabled': item.disabled },
|
|
83
72
|
]"
|
|
84
|
-
style="word-break: break-word"
|
|
85
73
|
>
|
|
86
74
|
{{ item.subtext }}
|
|
87
75
|
</span>
|
|
@@ -165,16 +153,13 @@
|
|
|
165
153
|
{ 'spr-text-color-disabled': item.disabled },
|
|
166
154
|
]"
|
|
167
155
|
>
|
|
168
|
-
<span class="spr-text-left spr-text-xs"
|
|
169
|
-
{{ item.text }}
|
|
170
|
-
</span>
|
|
156
|
+
<span class="spr-text-left spr-text-xs">{{ item.text }}</span>
|
|
171
157
|
<span
|
|
172
158
|
v-if="item.subtext"
|
|
173
159
|
:class="[
|
|
174
160
|
'spr-body-xs-regular spr-text-color-base spr-text-left',
|
|
175
161
|
{ 'spr-text-color-disabled': item.disabled },
|
|
176
162
|
]"
|
|
177
|
-
style="word-break: break-word"
|
|
178
163
|
>
|
|
179
164
|
{{ item.subtext }}
|
|
180
165
|
</span>
|
|
@@ -240,13 +225,6 @@ import { useList } from './use-list';
|
|
|
240
225
|
const props = defineProps(listPropTypes);
|
|
241
226
|
const emit = defineEmits(listEmitTypes);
|
|
242
227
|
|
|
243
|
-
const {
|
|
244
|
-
|
|
245
|
-
searchText,
|
|
246
|
-
localizedMenuList,
|
|
247
|
-
groupedMenuList,
|
|
248
|
-
isItemSelected,
|
|
249
|
-
getListItemClasses,
|
|
250
|
-
handleSelectedItem,
|
|
251
|
-
} = useList(props, emit);
|
|
228
|
+
const { searchText, localizedMenuList, groupedMenuList, isItemSelected, getListItemClasses, handleSelectedItem } =
|
|
229
|
+
useList(props, emit);
|
|
252
230
|
</script>
|
|
@@ -144,12 +144,16 @@ export const selectLadderizedPropTypes = {
|
|
|
144
144
|
type: Boolean,
|
|
145
145
|
default: false,
|
|
146
146
|
},
|
|
147
|
+
writableInputText: {
|
|
148
|
+
type: Boolean,
|
|
149
|
+
default: false,
|
|
150
|
+
}
|
|
147
151
|
};
|
|
148
152
|
|
|
149
153
|
export const selectLadderizedEmitTypes = {
|
|
150
154
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
151
155
|
'update:modelValue': (_value: unknown) => true,
|
|
152
|
-
'popper-state':
|
|
156
|
+
'popper-state': () => true,
|
|
153
157
|
};
|
|
154
158
|
|
|
155
159
|
export type SelectLadderizedEmitFn = (event: string, ...args: unknown[]) => void;
|
|
@@ -37,10 +37,11 @@
|
|
|
37
37
|
:helper-text="props.helperText"
|
|
38
38
|
:helper-icon="props.helperIcon"
|
|
39
39
|
:display-helper="props.displayHelper"
|
|
40
|
-
readonly
|
|
40
|
+
:readonly="!props.writableInputText"
|
|
41
41
|
:active="props.active"
|
|
42
42
|
:disabled="props.disabled"
|
|
43
43
|
:error="props.error"
|
|
44
|
+
@blur="handleInputChange"
|
|
44
45
|
>
|
|
45
46
|
<template #icon>
|
|
46
47
|
<div
|
|
@@ -121,5 +122,6 @@ const {
|
|
|
121
122
|
inputText,
|
|
122
123
|
handleSelectedLadderizedItem,
|
|
123
124
|
handleClear,
|
|
125
|
+
handleInputChange,
|
|
124
126
|
} = useSelectLadderized(props, emit as SelectLadderizedEmitFn);
|
|
125
127
|
</script>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, toRefs, computed, watch } from 'vue';
|
|
2
|
-
import { useVModel, onClickOutside } from '@vueuse/core';
|
|
2
|
+
import { useVModel, onClickOutside, watchDeep } from '@vueuse/core';
|
|
3
3
|
|
|
4
4
|
import type { SelectLadderizedPropTypes } from './select-ladderized';
|
|
5
5
|
|
|
@@ -17,6 +17,7 @@ export const useSelectLadderized = (
|
|
|
17
17
|
supportingLabelClasses: 'spr-body-sm-regular spr-text-color-supporting',
|
|
18
18
|
}));
|
|
19
19
|
|
|
20
|
+
// Wrapper for input field
|
|
20
21
|
const ladderizedSelectState = ref<HTMLDivElement | null>(null);
|
|
21
22
|
|
|
22
23
|
// Popper Variables
|
|
@@ -31,6 +32,7 @@ export const useSelectLadderized = (
|
|
|
31
32
|
// Input Variables
|
|
32
33
|
const inputText = ref<string>('');
|
|
33
34
|
const wasCleared = ref<boolean>(false);
|
|
35
|
+
const isCustomInput = ref<boolean>(false);
|
|
34
36
|
|
|
35
37
|
const isLeafNode = (item: MenuListType): boolean => {
|
|
36
38
|
return !item.sublevel || item.sublevel.length === 0;
|
|
@@ -57,6 +59,7 @@ export const useSelectLadderized = (
|
|
|
57
59
|
|
|
58
60
|
const handleSelectedLadderizedItem = (selectedItems: string[], selectedItem?: MenuListType) => {
|
|
59
61
|
wasCleared.value = false;
|
|
62
|
+
isCustomInput.value = false;
|
|
60
63
|
|
|
61
64
|
// If the selectedItems is a single value (leaf from search), reconstruct the full path
|
|
62
65
|
let fullPath: string[] | null = null;
|
|
@@ -157,15 +160,17 @@ export const useSelectLadderized = (
|
|
|
157
160
|
};
|
|
158
161
|
|
|
159
162
|
// Watch for changes in modelValue to update inputText
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
watchDeep(
|
|
164
|
+
ladderizedSelectModel,
|
|
162
165
|
(newVal) => {
|
|
166
|
+
if (isCustomInput.value) return;
|
|
167
|
+
|
|
163
168
|
if (wasCleared.value) {
|
|
164
169
|
inputText.value = '';
|
|
165
170
|
wasCleared.value = false;
|
|
166
171
|
|
|
167
172
|
return;
|
|
168
|
-
}
|
|
173
|
+
};
|
|
169
174
|
|
|
170
175
|
if (Array.isArray(newVal) && newVal.length > 0) {
|
|
171
176
|
// Treat the array as a single path for ladderized select
|
|
@@ -194,6 +199,13 @@ export const useSelectLadderized = (
|
|
|
194
199
|
emit('popper-state', newState);
|
|
195
200
|
});
|
|
196
201
|
|
|
202
|
+
const handleInputChange = () => {
|
|
203
|
+
if (!props.writableInputText) return;
|
|
204
|
+
wasCleared.value = false;
|
|
205
|
+
isCustomInput.value = true;
|
|
206
|
+
ladderizedSelectModel.value = [inputText.value];
|
|
207
|
+
};
|
|
208
|
+
|
|
197
209
|
// Close only when clicking completely outside both the popper and the trigger wrapper.
|
|
198
210
|
onClickOutside(ladderizedSelectPopperRef, (event) => {
|
|
199
211
|
const triggerWrapper = ladderizedSelectState.value;
|
|
@@ -216,5 +228,6 @@ export const useSelectLadderized = (
|
|
|
216
228
|
inputText,
|
|
217
229
|
handleSelectedLadderizedItem,
|
|
218
230
|
handleClear,
|
|
231
|
+
handleInputChange,
|
|
219
232
|
};
|
|
220
233
|
};
|
|
@@ -49,7 +49,9 @@
|
|
|
49
49
|
class="spr-text-color-supporting spr-px-3"
|
|
50
50
|
:aria-label="`${multiSelectedListItems.length} selected options`"
|
|
51
51
|
>
|
|
52
|
-
{{ multiSelectedListItems.length }} item{{
|
|
52
|
+
{{ multiSelectedListItems.length }} item{{
|
|
53
|
+
multiSelectedListItems.length === 1 ? '' : 's'
|
|
54
|
+
}}
|
|
53
55
|
selected
|
|
54
56
|
</span>
|
|
55
57
|
</template>
|
|
@@ -162,9 +164,8 @@
|
|
|
162
164
|
:loading="props.loading"
|
|
163
165
|
:item-icon="props.itemIcon"
|
|
164
166
|
:lozenge="props.lozenge"
|
|
165
|
-
:display-list-item-selected="props.displayListItemSelected"
|
|
166
|
-
:disabled-local-search="props.disabledLocalSearch"
|
|
167
167
|
multi-select
|
|
168
|
+
:disabled-local-search="props.disabledLocalSearch"
|
|
168
169
|
@update:model-value="handleMultiSelectedItem"
|
|
169
170
|
/>
|
|
170
171
|
</div>
|