design-system-next 1.8.2 → 1.9.2
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 +4434 -4047
- package/dist/design-system-next.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/package.json +1 -1
- package/src/App.vue +9 -671
- package/src/assets/styles/tailwind.css +2 -2
- package/src/components/calendar-cell/use-calendar-cell.ts +1 -1
- package/src/components/checkbox/checkbox.ts +5 -1
- package/src/components/checkbox/checkbox.vue +1 -1
- package/src/components/checkbox/use-checkbox.ts +8 -10
- package/src/components/date-picker/date-picker.ts +8 -1
- package/src/components/date-picker/date-picker.vue +6 -1
- package/src/components/dropdown/dropdown.ts +45 -17
- package/src/components/dropdown/dropdown.vue +35 -27
- package/src/components/dropdown/use-dropdown.ts +38 -87
- package/src/components/input/input.ts +38 -6
- package/src/components/input/input.vue +4 -1
- package/src/components/input/use-input.ts +17 -13
- package/src/components/list/list.ts +34 -0
- package/src/components/list/list.vue +64 -0
- package/src/components/list/use-list.ts +149 -0
- package/src/components/modal/modal.ts +12 -7
- package/src/components/modal/modal.vue +74 -34
- package/src/components/modal/use-modal.ts +69 -35
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="spr-font-main">
|
|
3
|
+
<template v-if="props.groupItemsBy">
|
|
4
|
+
<div class="spr-grid spr-gap-2">
|
|
5
|
+
<div v-for="(items, labelIndex) in groupedMenuList" :key="labelIndex" class="spr-grid spr-gap-0.5">
|
|
6
|
+
<label v-if="labelIndex" class="spr-label-sm-regular spr-text-color-base spr-p-2">
|
|
7
|
+
{{ labelIndex }}
|
|
8
|
+
</label>
|
|
9
|
+
<div
|
|
10
|
+
v-for="(item, itemIndex) in items"
|
|
11
|
+
:key="itemIndex"
|
|
12
|
+
:class="getListItemClasses(item)"
|
|
13
|
+
@click="handleSelectedItem(item)"
|
|
14
|
+
>
|
|
15
|
+
<spr-checkbox v-if="props.multiSelect" :checked="isItemSelected(item)" />
|
|
16
|
+
<div class="spr-flex spr-w-full spr-items-center">
|
|
17
|
+
<span class="spr-text-xs">{{ item.text }}</span>
|
|
18
|
+
</div>
|
|
19
|
+
<Icon
|
|
20
|
+
v-if="isItemSelected(item) && !props.multiSelect"
|
|
21
|
+
class="spr-text-color-brand-base spr-w-[1.39em]"
|
|
22
|
+
icon="ph:check"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
<template v-else>
|
|
29
|
+
<div
|
|
30
|
+
v-for="(item, index) in initialMenuList"
|
|
31
|
+
:key="index"
|
|
32
|
+
:class="getListItemClasses(item)"
|
|
33
|
+
@click="handleSelectedItem(item)"
|
|
34
|
+
>
|
|
35
|
+
<spr-checkbox v-if="props.multiSelect" :checked="isItemSelected(item)" />
|
|
36
|
+
<div class="spr-flex spr-w-full spr-items-center">
|
|
37
|
+
<span class="spr-text-xs">{{ item.text }}</span>
|
|
38
|
+
</div>
|
|
39
|
+
<Icon
|
|
40
|
+
v-if="isItemSelected(item) && !props.multiSelect"
|
|
41
|
+
class="spr-text-color-brand-base spr-w-[1.39em]"
|
|
42
|
+
icon="ph:check"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script lang="ts" setup>
|
|
50
|
+
import { Icon } from '@iconify/vue';
|
|
51
|
+
|
|
52
|
+
import { listPropTypes, listEmitTypes } from './list';
|
|
53
|
+
import { useList } from './use-list';
|
|
54
|
+
|
|
55
|
+
import SprCheckbox from '../checkbox/checkbox.vue';
|
|
56
|
+
|
|
57
|
+
const props = defineProps(listPropTypes);
|
|
58
|
+
const emit = defineEmits(listEmitTypes);
|
|
59
|
+
|
|
60
|
+
const { initialMenuList, groupedMenuList, isItemSelected, getListItemClasses, handleSelectedItem } = useList(
|
|
61
|
+
props,
|
|
62
|
+
emit,
|
|
63
|
+
);
|
|
64
|
+
</script>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { ref, toRefs, computed, ComputedRef, onMounted, watch } from 'vue';
|
|
2
|
+
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
|
|
5
|
+
import type { SetupContext } from 'vue';
|
|
6
|
+
import type { ListPropTypes, ListEmitTypes } from './list';
|
|
7
|
+
|
|
8
|
+
interface ListClasses {
|
|
9
|
+
listItemClasses: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface SelectedItem {
|
|
13
|
+
text: string;
|
|
14
|
+
value: string | number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>['emit']) => {
|
|
18
|
+
const { modelValue, menuList, groupItemsBy, multiSelect } = toRefs(props);
|
|
19
|
+
|
|
20
|
+
const listClasses: ComputedRef<ListClasses> = computed(() => {
|
|
21
|
+
const listItemClasses = classNames(
|
|
22
|
+
'spr-flex spr-cursor-pointer spr-items-center spr-justify-between spr-gap-1.5 spr-rounded-lg spr-p-2',
|
|
23
|
+
'spr-transition spr-duration-150 spr-ease-in-out',
|
|
24
|
+
'hover:spr-background-color-hover',
|
|
25
|
+
'active:spr-background-color-single-active active:spr-scale-[.98]',
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return { listItemClasses };
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const initialMenuList = ref<{ text: string; value: string }[]>([]);
|
|
32
|
+
|
|
33
|
+
const groupedMenuList = ref<{ [key: string]: { text: string; value: string }[] }>({});
|
|
34
|
+
|
|
35
|
+
const selectedItems = ref<SelectedItem[]>([]);
|
|
36
|
+
|
|
37
|
+
// #region - Helper Methods
|
|
38
|
+
const isItemSelected = (item: SelectedItem) => {
|
|
39
|
+
return selectedItems.value.some((selectedItem) => selectedItem.text === item.text);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const setMenuList = () => {
|
|
43
|
+
if (menuList.value && menuList.value.length > 0) {
|
|
44
|
+
initialMenuList.value = menuList.value;
|
|
45
|
+
|
|
46
|
+
if (groupItemsBy?.value) {
|
|
47
|
+
setGroupedMenuList();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const setGroupedMenuList = () => {
|
|
53
|
+
if (!groupItemsBy?.value) return;
|
|
54
|
+
|
|
55
|
+
const groupedItems: { [key: string]: { text: string; value: string }[] } = {};
|
|
56
|
+
|
|
57
|
+
initialMenuList.value.forEach((item) => {
|
|
58
|
+
const firstCharacter = item.text.charAt(0);
|
|
59
|
+
const groupKey = /^\d/.test(firstCharacter) ? '' : firstCharacter.toUpperCase();
|
|
60
|
+
|
|
61
|
+
if (!groupedItems[groupKey]) {
|
|
62
|
+
groupedItems[groupKey] = [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
groupedItems[groupKey].push(item);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const sortedGroupedItems = Object.keys(groupedItems)
|
|
69
|
+
.sort((a, b) => {
|
|
70
|
+
if (a === '') return -1;
|
|
71
|
+
if (b === '') return 1;
|
|
72
|
+
return groupItemsBy.value === 'Z-A' ? b.localeCompare(a) : a.localeCompare(b);
|
|
73
|
+
})
|
|
74
|
+
.reduce((result: { [key: string]: { text: string; value: string }[] }, key) => {
|
|
75
|
+
const sortedItems = groupedItems[key].sort((a, b) => {
|
|
76
|
+
const comparison = a.text.localeCompare(b.text);
|
|
77
|
+
return groupItemsBy.value === 'Z-A' ? -comparison : comparison;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
result[key] = sortedItems;
|
|
81
|
+
|
|
82
|
+
return result;
|
|
83
|
+
}, {});
|
|
84
|
+
|
|
85
|
+
groupedMenuList.value = sortedGroupedItems;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const setPreSelectedItems = () => {
|
|
89
|
+
if (modelValue.value && modelValue.value.length > 0) {
|
|
90
|
+
modelValue.value.forEach((preSelectedItem: string) => {
|
|
91
|
+
const item = initialMenuList.value.find(
|
|
92
|
+
(menuItem) =>
|
|
93
|
+
String(menuItem.text) === String(preSelectedItem) || String(menuItem.value) === String(preSelectedItem),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (item) {
|
|
97
|
+
selectedItems.value.push(item);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const getListItemClasses = (item: SelectedItem) => ({
|
|
104
|
+
[listClasses.value.listItemClasses]: true,
|
|
105
|
+
'spr-background-color-single-active': isItemSelected(item),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const handleSelectedItem = (item: SelectedItem) => {
|
|
109
|
+
if (!multiSelect.value) {
|
|
110
|
+
selectedItems.value = [item];
|
|
111
|
+
|
|
112
|
+
emit('get-selected-item', selectedItems.value[0]);
|
|
113
|
+
} else {
|
|
114
|
+
const index = selectedItems.value.findIndex((selectedItem: SelectedItem) => selectedItem.value === item.value);
|
|
115
|
+
|
|
116
|
+
if (index === -1) {
|
|
117
|
+
selectedItems.value.push(item);
|
|
118
|
+
} else {
|
|
119
|
+
selectedItems.value.splice(index, 1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
emit('get-selected-item', selectedItems.value);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
// #endregion - Helper Methods
|
|
126
|
+
|
|
127
|
+
watch(
|
|
128
|
+
menuList,
|
|
129
|
+
() => {
|
|
130
|
+
setMenuList();
|
|
131
|
+
setPreSelectedItems();
|
|
132
|
+
},
|
|
133
|
+
{ immediate: true },
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
onMounted(() => {
|
|
137
|
+
setMenuList();
|
|
138
|
+
setPreSelectedItems();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
listClasses,
|
|
143
|
+
initialMenuList,
|
|
144
|
+
groupedMenuList,
|
|
145
|
+
isItemSelected,
|
|
146
|
+
getListItemClasses,
|
|
147
|
+
handleSelectedItem,
|
|
148
|
+
};
|
|
149
|
+
};
|
|
@@ -5,16 +5,19 @@ export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<
|
|
|
5
5
|
const MODAL_SIZE = ['sm', 'md', 'lg', 'xl'] as const;
|
|
6
6
|
|
|
7
7
|
export const modalPropTypes = {
|
|
8
|
-
|
|
8
|
+
modelValue: {
|
|
9
9
|
type: Boolean,
|
|
10
10
|
default: false,
|
|
11
11
|
},
|
|
12
|
-
|
|
13
12
|
title: {
|
|
14
13
|
type: String,
|
|
15
14
|
default: '',
|
|
16
15
|
},
|
|
17
|
-
|
|
16
|
+
closeButtonX: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: true,
|
|
19
|
+
},
|
|
20
|
+
contentPadding: {
|
|
18
21
|
type: Boolean,
|
|
19
22
|
default: true,
|
|
20
23
|
},
|
|
@@ -25,16 +28,18 @@ export const modalPropTypes = {
|
|
|
25
28
|
size: {
|
|
26
29
|
type: String as PropType<(typeof MODAL_SIZE)[number]>,
|
|
27
30
|
validator: (value: (typeof MODAL_SIZE)[number]) => MODAL_SIZE.includes(value),
|
|
28
|
-
default: '
|
|
31
|
+
default: 'md',
|
|
29
32
|
},
|
|
30
|
-
|
|
33
|
+
staticBackdrop: {
|
|
31
34
|
type: Boolean,
|
|
32
|
-
default:
|
|
35
|
+
default: false,
|
|
33
36
|
},
|
|
34
37
|
};
|
|
35
38
|
|
|
36
39
|
export type ModalPropTypes = ExtractPropTypes<typeof modalPropTypes>;
|
|
40
|
+
|
|
37
41
|
export const modalEmitTypes = {
|
|
38
|
-
|
|
42
|
+
'update:modelValue': (value: boolean) => value,
|
|
39
43
|
};
|
|
44
|
+
|
|
40
45
|
export type ModalEmitTypes = typeof modalEmitTypes;
|
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
</
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
</div>
|
|
2
|
+
<transition name="backdrop-transition">
|
|
3
|
+
<div v-if="props.modelValue" :class="modalClasses.backdropClasses" @click="handleBackdropClick"></div>
|
|
4
|
+
</transition>
|
|
5
|
+
|
|
6
|
+
<transition name="modal-transition">
|
|
7
|
+
<div v-if="props.modelValue" id="modal" :class="modalClasses.baseClasses">
|
|
8
|
+
<header v-if="$slots.header || title" :class="modalClasses.headerClasses">
|
|
9
|
+
<span v-if="!$slots.header && title">{{ title }}</span>
|
|
10
|
+
|
|
11
|
+
<slot name="header"></slot>
|
|
12
|
+
|
|
13
|
+
<span v-if="props.closeButtonX" :class="modalClasses.headerCloseButtonXClasses" @click="handleCloseModal">
|
|
14
|
+
<Icon icon="ph:x" />
|
|
15
|
+
</span>
|
|
16
|
+
</header>
|
|
17
|
+
|
|
18
|
+
<div :class="modalClasses.contentClasses">
|
|
19
|
+
<slot />
|
|
20
|
+
</div>
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]"
|
|
29
|
-
>
|
|
30
|
-
<slot name="footer" />
|
|
31
|
-
</footer>
|
|
32
|
-
</dialog>
|
|
22
|
+
<footer v-if="$slots.footer" :class="modalClasses.footerClasses">
|
|
23
|
+
<slot name="footer" />
|
|
24
|
+
</footer>
|
|
25
|
+
</div>
|
|
26
|
+
</transition>
|
|
33
27
|
</template>
|
|
34
28
|
|
|
35
29
|
<script lang="ts" setup>
|
|
@@ -41,12 +35,58 @@ import { useModal } from './use-modal';
|
|
|
41
35
|
const props = defineProps(modalPropTypes);
|
|
42
36
|
const emit = defineEmits(modalEmitTypes);
|
|
43
37
|
|
|
44
|
-
const { modalClasses,
|
|
38
|
+
const { modalClasses, handleCloseModal, handleBackdropClick } = useModal(props, emit);
|
|
45
39
|
</script>
|
|
46
40
|
|
|
47
41
|
<style scoped>
|
|
48
|
-
|
|
49
|
-
.
|
|
50
|
-
|
|
42
|
+
.backdrop-transition-enter-active,
|
|
43
|
+
.backdrop-transition-leave-active {
|
|
44
|
+
transition: opacity 150ms ease-in-out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.backdrop-transition-enter-from,
|
|
48
|
+
.backdrop-transition-leave-to {
|
|
49
|
+
opacity: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.modal-transition-enter-active,
|
|
53
|
+
.modal-transition-leave-active {
|
|
54
|
+
transition:
|
|
55
|
+
opacity 150ms ease-in-out,
|
|
56
|
+
transform 150ms ease-in-out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.modal-transition-enter-from,
|
|
60
|
+
.modal-transition-leave-to {
|
|
61
|
+
opacity: 0;
|
|
62
|
+
transform: translateX(-50%) translateY(-50%) scale(0.9);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.modal-transition-enter-to,
|
|
66
|
+
.modal-transition-leave-from {
|
|
67
|
+
opacity: 1;
|
|
68
|
+
transform: translateX(-50%) translateY(-50%) scale(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.bounce-animation {
|
|
72
|
+
animation: bounce 0.5s ease;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@keyframes bounce {
|
|
76
|
+
0% {
|
|
77
|
+
transform: translateX(-50%) translateY(-50%) scale(1);
|
|
78
|
+
}
|
|
79
|
+
30% {
|
|
80
|
+
transform: translateX(-50%) translateY(-50%) scale(1.02);
|
|
81
|
+
}
|
|
82
|
+
50% {
|
|
83
|
+
transform: translateX(-50%) translateY(-50%) scale(0.98);
|
|
84
|
+
}
|
|
85
|
+
70% {
|
|
86
|
+
transform: translateX(-50%) translateY(-50%) scale(1.02);
|
|
87
|
+
}
|
|
88
|
+
100% {
|
|
89
|
+
transform: translateX(-50%) translateY(-50%) scale(1);
|
|
90
|
+
}
|
|
51
91
|
}
|
|
52
92
|
</style>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, toRefs, computed, ComputedRef
|
|
1
|
+
import { ref, toRefs, computed, ComputedRef } from 'vue';
|
|
2
2
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
|
|
@@ -6,62 +6,96 @@ import type { SetupContext } from 'vue';
|
|
|
6
6
|
import type { ModalEmitTypes, ModalPropTypes } from './modal';
|
|
7
7
|
|
|
8
8
|
interface ModalClasses {
|
|
9
|
+
backdropClasses: string;
|
|
9
10
|
baseClasses: string;
|
|
10
|
-
|
|
11
|
+
headerClasses: string;
|
|
12
|
+
headerCloseButtonXClasses: string;
|
|
13
|
+
contentClasses: string;
|
|
14
|
+
footerClasses: string;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export const useModal = (props: ModalPropTypes, emit: SetupContext<ModalEmitTypes>['emit']) => {
|
|
14
|
-
const { size } = toRefs(props);
|
|
15
|
-
|
|
16
|
-
const dialog = ref<HTMLDialogElement | null>(null);
|
|
18
|
+
const { size, contentPadding, staticBackdrop } = toRefs(props);
|
|
17
19
|
|
|
18
20
|
const modalClasses: ComputedRef<ModalClasses> = computed(() => {
|
|
21
|
+
const backdropClasses = classNames(
|
|
22
|
+
'spr-fixed spr-bottom-0 spr-left-0 spr-right-0 spr-top-0 spr-z-[9999999] spr-h-full spr-w-full spr-bg-[#4C5857] spr-opacity-60',
|
|
23
|
+
);
|
|
24
|
+
|
|
19
25
|
const baseClasses = classNames(
|
|
20
|
-
'spr-
|
|
26
|
+
'spr-fixed spr-z-[99999999] spr-left-1/2 spr-top-1/2 spr-transform -spr-translate-x-1/2 -spr-translate-y-1/2',
|
|
27
|
+
'spr-background-color spr-rounded-xl',
|
|
21
28
|
'spr-border spr-border-solid spr-border-color-weak',
|
|
29
|
+
'sm:spr-w-[calc(100%-2rem)] sm:spr-max-w-[calc(100%-2rem)]',
|
|
30
|
+
{
|
|
31
|
+
'spr-w-[360px] spr-max-w-[480px]': size.value === 'sm',
|
|
32
|
+
'spr-w-[480px] spr-max-w-[720px]': size.value === 'md',
|
|
33
|
+
'spr-w-[720px] spr-max-w-[960px]': size.value === 'lg',
|
|
34
|
+
'spr-w-[900px] spr-max-w-[1200px]': size.value === 'xl',
|
|
35
|
+
},
|
|
36
|
+
{ 'bounce-animation': staticBackdropClicked.value },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const headerClasses = classNames(
|
|
40
|
+
'spr-flex spr-items-start spr-justify-between spr-gap-2 spr-px-4 spr-py-3',
|
|
41
|
+
'spr-text-color-strong spr-subheading-xs',
|
|
42
|
+
'spr-border-color-weak spr-border-x-0 spr-border-b spr-border-t-0 spr-border-solid',
|
|
43
|
+
'spr-rounded-tl-xl spr-rounded-tr-xl',
|
|
44
|
+
'sm:spr-p-2',
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const headerCloseButtonXClasses = classNames(
|
|
48
|
+
'spr-text-color-weak spr-subheading-xs spr-mt-0.5 spr-cursor-pointer',
|
|
49
|
+
'spr-transition spr-duration-150 spr-ease-in-out',
|
|
50
|
+
'hover:spr-text-color-base',
|
|
51
|
+
'active:spr-text-color-strong active:spr-scale-75',
|
|
22
52
|
);
|
|
23
53
|
|
|
24
|
-
const
|
|
25
|
-
'spr-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
54
|
+
const contentClasses = classNames(
|
|
55
|
+
'spr-body-sm-regular spr-max-h-[calc(100vh-100px)] spr-overflow-y-auto spr-overflow-x-hidden',
|
|
56
|
+
{
|
|
57
|
+
'spr-p-4 sm:spr-p-2': contentPadding.value,
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const footerClasses = classNames(
|
|
62
|
+
'spr-border-color-weak spr-border-x-0 spr-border-b-0 spr-border-t spr-border-solid',
|
|
63
|
+
'spr-flex spr-w-full spr-items-center spr-px-size-spacing-xs spr-py-size-spacing-2xs',
|
|
64
|
+
'spr-text-color-strong spr-subheading-xs',
|
|
65
|
+
);
|
|
30
66
|
|
|
31
67
|
return {
|
|
68
|
+
backdropClasses,
|
|
32
69
|
baseClasses,
|
|
33
|
-
|
|
70
|
+
headerClasses,
|
|
71
|
+
headerCloseButtonXClasses,
|
|
72
|
+
contentClasses,
|
|
73
|
+
footerClasses,
|
|
34
74
|
};
|
|
35
75
|
});
|
|
36
76
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
77
|
+
const staticBackdropClicked = ref(false);
|
|
78
|
+
|
|
79
|
+
const handleCloseModal = () => {
|
|
80
|
+
emit('update:modelValue', false);
|
|
41
81
|
};
|
|
42
82
|
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
83
|
+
const handleBackdropClick = () => {
|
|
84
|
+
if (!staticBackdrop.value) {
|
|
85
|
+
handleCloseModal();
|
|
86
|
+
} else {
|
|
87
|
+
staticBackdropClicked.value = true;
|
|
88
|
+
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
staticBackdropClicked.value = false;
|
|
91
|
+
}, 500);
|
|
47
92
|
}
|
|
48
93
|
};
|
|
49
94
|
|
|
50
|
-
watch(
|
|
51
|
-
() => props.open,
|
|
52
|
-
(value) => {
|
|
53
|
-
if (value) {
|
|
54
|
-
openModal();
|
|
55
|
-
} else {
|
|
56
|
-
closeModal();
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
);
|
|
60
|
-
|
|
61
95
|
return {
|
|
62
96
|
modalClasses,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
97
|
+
staticBackdropClicked,
|
|
98
|
+
handleCloseModal,
|
|
99
|
+
handleBackdropClick,
|
|
66
100
|
};
|
|
67
101
|
};
|