@m3ui-vue/m3ui-vue 0.3.1 → 0.4.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/README.md +219 -59
- package/dist/{MMenuItem-C6RwHl-l.js → MMenuItem-FyttjOj_.js} +399 -207
- package/dist/MMenuItem-FyttjOj_.js.map +1 -0
- package/dist/components/MAutocomplete.vue.d.ts +2 -0
- package/dist/components/MBox.vue.d.ts +2 -2
- package/dist/components/MButton.vue.d.ts +4 -0
- package/dist/components/MButtonGroup.vue.d.ts +28 -0
- package/dist/components/MCarousel.vue.d.ts +21 -12
- package/dist/components/MColorPickerModal.vue.d.ts +18 -0
- package/dist/components/MDataTable.vue.d.ts +1 -1
- package/dist/components/MDatePickerModal.vue.d.ts +21 -0
- package/dist/components/MDateRangePickerModal.vue.d.ts +24 -0
- package/dist/components/MDialog.vue.d.ts +9 -1
- package/dist/components/MExpansionPanel.vue.d.ts +3 -2
- package/dist/components/MFab.vue.d.ts +14 -2
- package/dist/components/MFlex.vue.d.ts +2 -2
- package/dist/components/MIconButton.vue.d.ts +4 -2
- package/dist/components/MInfiniteScroll.vue.d.ts +1 -1
- package/dist/components/MList.vue.d.ts +2 -0
- package/dist/components/MLoadingOverlay.vue.d.ts +1 -1
- package/dist/components/MMenu.vue.d.ts +3 -1
- package/dist/components/MMenuItem.vue.d.ts +14 -3
- package/dist/components/MMultiAutocomplete.vue.d.ts +2 -0
- package/dist/components/MMultiSelect.vue.d.ts +2 -0
- package/dist/components/MNavigationDrawer.vue.d.ts +1 -1
- package/dist/components/MNotificationHost.vue.d.ts +3 -0
- package/dist/components/MSelect.vue.d.ts +2 -0
- package/dist/components/MSlider.vue.d.ts +15 -4
- package/dist/components/MSplitButton.vue.d.ts +39 -0
- package/dist/components/MSplitter.vue.d.ts +1 -1
- package/dist/components/MStack.vue.d.ts +2 -2
- package/dist/components/MTable.vue.d.ts +1 -1
- package/dist/components/MTimePickerModal.vue.d.ts +21 -0
- package/dist/components/MToolbar.vue.d.ts +30 -0
- package/dist/components/MTooltip.vue.d.ts +8 -2
- package/dist/components/MWindow.vue.d.ts +2 -2
- package/dist/composables/useDevice.d.ts +3 -0
- package/dist/composables/useNotification.d.ts +64 -0
- package/dist/composables/useToast.d.ts +8 -0
- package/dist/index.d.ts +12 -0
- package/dist/m3ui-vue.css +1 -1
- package/dist/m3ui.js +5222 -2994
- package/dist/m3ui.js.map +1 -1
- package/dist/rich-text-editor.js +10 -10
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/MAutocomplete.vue +109 -13
- package/src/components/MButton.vue +38 -16
- package/src/components/MButtonGroup.vue +158 -0
- package/src/components/MCarousel.vue +223 -101
- package/src/components/MColorPicker.vue +1 -4
- package/src/components/MColorPickerModal.vue +276 -0
- package/src/components/MDatePicker.vue +1 -4
- package/src/components/MDatePickerModal.vue +265 -0
- package/src/components/MDateRangePicker.vue +1 -4
- package/src/components/MDateRangePickerModal.vue +264 -0
- package/src/components/MDialog.vue +38 -1
- package/src/components/MExpansionPanel.vue +10 -32
- package/src/components/MFab.vue +92 -11
- package/src/components/MIconButton.vue +36 -6
- package/src/components/MList.vue +6 -3
- package/src/components/MListItem.vue +9 -3
- package/src/components/MMenu.vue +10 -5
- package/src/components/MMenuItem.vue +93 -10
- package/src/components/MMultiAutocomplete.vue +105 -10
- package/src/components/MMultiSelect.vue +106 -13
- package/src/components/MNotificationHost.vue +163 -0
- package/src/components/MSelect.vue +99 -16
- package/src/components/MSlider.vue +367 -134
- package/src/components/MSnackbar.vue +3 -0
- package/src/components/MSplitButton.vue +240 -0
- package/src/components/MTabs.vue +82 -39
- package/src/components/MTagInput.vue +11 -1
- package/src/components/MTimePicker.vue +1 -4
- package/src/components/MTimePickerModal.vue +458 -0
- package/src/components/MToolbar.vue +75 -0
- package/src/components/MTooltip.vue +60 -10
- package/src/components/_MContextMenuPanel.vue +2 -2
- package/src/composables/useDevice.ts +29 -0
- package/src/composables/useNotification.ts +93 -0
- package/src/composables/useToast.ts +42 -5
- package/src/index.ts +12 -0
- package/dist/MMenuItem-C6RwHl-l.js.map +0 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useNotification } from '../composables/useNotification'
|
|
4
|
+
import MIcon from './MIcon.vue'
|
|
5
|
+
import MSpinner from './MSpinner.vue'
|
|
6
|
+
|
|
7
|
+
const { notifications, position, dismiss } = useNotification()
|
|
8
|
+
|
|
9
|
+
const isTop = computed(() => position.value.startsWith('top'))
|
|
10
|
+
|
|
11
|
+
const containerClass = computed(() => {
|
|
12
|
+
const base = 'pointer-events-none fixed z-[300] flex flex-col'
|
|
13
|
+
switch (position.value) {
|
|
14
|
+
case 'top-left': return `${base} top-4 left-4 items-start`
|
|
15
|
+
case 'top-center': return `${base} top-4 left-1/2 -translate-x-1/2 items-center`
|
|
16
|
+
case 'top-right': return `${base} top-4 right-4 items-end`
|
|
17
|
+
case 'bottom-left': return `${base} bottom-4 left-4 items-start`
|
|
18
|
+
case 'bottom-right': return `${base} bottom-4 right-4 items-end`
|
|
19
|
+
default: return `${base} bottom-4 left-1/2 -translate-x-1/2 items-center`
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const variantStyles: Record<string, { bg: string; icon: string; iconName: string }> = {
|
|
24
|
+
info: {
|
|
25
|
+
bg: 'bg-inverse-surface text-inverse-on-surface',
|
|
26
|
+
icon: 'text-inverse-on-surface/70',
|
|
27
|
+
iconName: 'info',
|
|
28
|
+
},
|
|
29
|
+
success: {
|
|
30
|
+
bg: 'bg-inverse-surface text-inverse-on-surface',
|
|
31
|
+
icon: 'text-[#4ade80]',
|
|
32
|
+
iconName: 'check_circle',
|
|
33
|
+
},
|
|
34
|
+
warning: {
|
|
35
|
+
bg: 'bg-inverse-surface text-inverse-on-surface',
|
|
36
|
+
icon: 'text-[#fcd34d]',
|
|
37
|
+
iconName: 'warning',
|
|
38
|
+
},
|
|
39
|
+
error: {
|
|
40
|
+
bg: 'bg-inverse-surface text-inverse-on-surface',
|
|
41
|
+
icon: 'text-[#f87171]',
|
|
42
|
+
iconName: 'error',
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const getStyle = (variant: string) => variantStyles[variant] ?? variantStyles.info!
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<div :class="containerClass">
|
|
51
|
+
<TransitionGroup :name="isTop ? 'm3-notif-top' : 'm3-notif-bot'">
|
|
52
|
+
<div v-for="n in notifications" :key="n.id" class="notif-row w-full min-w-56 max-w-sm">
|
|
53
|
+
<div
|
|
54
|
+
class="notif-inner pointer-events-auto flex items-center gap-2.5 rounded px-4 py-3 shadow-elevation-2"
|
|
55
|
+
:class="getStyle(n.variant).bg"
|
|
56
|
+
>
|
|
57
|
+
<MSpinner v-if="n.loading" :size="18" class="shrink-0" />
|
|
58
|
+
<MIcon
|
|
59
|
+
v-else
|
|
60
|
+
:name="n.icon ?? getStyle(n.variant).iconName"
|
|
61
|
+
:size="18"
|
|
62
|
+
class="shrink-0"
|
|
63
|
+
:class="getStyle(n.variant).icon"
|
|
64
|
+
/>
|
|
65
|
+
<p class="flex-1 text-body-medium leading-snug">{{ n.message }}</p>
|
|
66
|
+
<div class="flex shrink-0 items-center gap-1">
|
|
67
|
+
<button
|
|
68
|
+
v-if="n.action"
|
|
69
|
+
type="button"
|
|
70
|
+
class="cursor-pointer rounded px-2 py-1 text-label-medium font-semibold text-inverse-primary transition-colors hover:bg-inverse-on-surface/10"
|
|
71
|
+
@click="n.action!.onClick(); dismiss(n.id)"
|
|
72
|
+
>
|
|
73
|
+
{{ n.action.label }}
|
|
74
|
+
</button>
|
|
75
|
+
<button
|
|
76
|
+
v-if="n.closable !== false"
|
|
77
|
+
type="button"
|
|
78
|
+
class="flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md text-inverse-on-surface/50 transition-colors hover:bg-inverse-on-surface/10"
|
|
79
|
+
@click="dismiss(n.id)"
|
|
80
|
+
>
|
|
81
|
+
<MIcon name="close" :size="16" />
|
|
82
|
+
</button>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</TransitionGroup>
|
|
87
|
+
</div>
|
|
88
|
+
</template>
|
|
89
|
+
|
|
90
|
+
<style scoped>
|
|
91
|
+
.notif-row {
|
|
92
|
+
display: grid;
|
|
93
|
+
grid-template-rows: 1fr;
|
|
94
|
+
padding-bottom: 6px;
|
|
95
|
+
}
|
|
96
|
+
.notif-row > .notif-inner {
|
|
97
|
+
min-height: 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.m3-notif-bot-enter-active {
|
|
101
|
+
transition: grid-template-rows 200ms ease, padding-bottom 200ms ease;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
}
|
|
104
|
+
.m3-notif-bot-enter-active > .notif-inner {
|
|
105
|
+
transition: opacity 150ms ease, transform 200ms ease;
|
|
106
|
+
}
|
|
107
|
+
.m3-notif-bot-enter-from {
|
|
108
|
+
grid-template-rows: 0fr;
|
|
109
|
+
padding-bottom: 0;
|
|
110
|
+
}
|
|
111
|
+
.m3-notif-bot-enter-from > .notif-inner {
|
|
112
|
+
opacity: 0;
|
|
113
|
+
transform: translateY(12px) scale(0.95);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.m3-notif-bot-leave-active {
|
|
117
|
+
transition: grid-template-rows 250ms ease, padding-bottom 250ms ease;
|
|
118
|
+
overflow: hidden;
|
|
119
|
+
}
|
|
120
|
+
.m3-notif-bot-leave-active > .notif-inner {
|
|
121
|
+
transition: opacity 150ms ease, transform 150ms ease;
|
|
122
|
+
}
|
|
123
|
+
.m3-notif-bot-leave-to {
|
|
124
|
+
grid-template-rows: 0fr;
|
|
125
|
+
padding-bottom: 0;
|
|
126
|
+
}
|
|
127
|
+
.m3-notif-bot-leave-to > .notif-inner {
|
|
128
|
+
opacity: 0;
|
|
129
|
+
transform: scale(0.93);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.m3-notif-top-enter-active {
|
|
133
|
+
transition: grid-template-rows 200ms ease, padding-bottom 200ms ease;
|
|
134
|
+
overflow: hidden;
|
|
135
|
+
}
|
|
136
|
+
.m3-notif-top-enter-active > .notif-inner {
|
|
137
|
+
transition: opacity 150ms ease, transform 200ms ease;
|
|
138
|
+
}
|
|
139
|
+
.m3-notif-top-enter-from {
|
|
140
|
+
grid-template-rows: 0fr;
|
|
141
|
+
padding-bottom: 0;
|
|
142
|
+
}
|
|
143
|
+
.m3-notif-top-enter-from > .notif-inner {
|
|
144
|
+
opacity: 0;
|
|
145
|
+
transform: translateY(-12px) scale(0.95);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.m3-notif-top-leave-active {
|
|
149
|
+
transition: grid-template-rows 250ms ease, padding-bottom 250ms ease;
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
}
|
|
152
|
+
.m3-notif-top-leave-active > .notif-inner {
|
|
153
|
+
transition: opacity 150ms ease, transform 150ms ease;
|
|
154
|
+
}
|
|
155
|
+
.m3-notif-top-leave-to {
|
|
156
|
+
grid-template-rows: 0fr;
|
|
157
|
+
padding-bottom: 0;
|
|
158
|
+
}
|
|
159
|
+
.m3-notif-top-leave-to > .notif-inner {
|
|
160
|
+
opacity: 0;
|
|
161
|
+
transform: scale(0.93);
|
|
162
|
+
}
|
|
163
|
+
</style>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, useId, onMounted, onUnmounted } from 'vue'
|
|
2
|
+
import { computed, ref, useId, onMounted, onUnmounted, watch } from 'vue'
|
|
3
3
|
import MIcon from './MIcon.vue'
|
|
4
|
+
import MIconButton from './MIconButton.vue'
|
|
4
5
|
import { useFieldBg } from '../composables/useFieldBg'
|
|
6
|
+
import { useLocale } from '../composables/useLocale'
|
|
5
7
|
|
|
6
8
|
export interface SelectOption {
|
|
7
9
|
label: string
|
|
@@ -16,6 +18,7 @@ const props = withDefaults(
|
|
|
16
18
|
label?: string
|
|
17
19
|
placeholder?: string
|
|
18
20
|
variant?: 'filled' | 'outlined'
|
|
21
|
+
mode?: 'docked' | 'modal'
|
|
19
22
|
disabled?: boolean
|
|
20
23
|
error?: string
|
|
21
24
|
hint?: string
|
|
@@ -27,6 +30,7 @@ const props = withDefaults(
|
|
|
27
30
|
{
|
|
28
31
|
modelValue: undefined,
|
|
29
32
|
variant: 'filled',
|
|
33
|
+
mode: 'docked',
|
|
30
34
|
disabled: false,
|
|
31
35
|
required: false,
|
|
32
36
|
clearable: false,
|
|
@@ -35,8 +39,10 @@ const props = withDefaults(
|
|
|
35
39
|
|
|
36
40
|
const emit = defineEmits<{ 'update:modelValue': [unknown] }>()
|
|
37
41
|
|
|
42
|
+
const locale = useLocale()
|
|
38
43
|
const id = useId()
|
|
39
44
|
const open = ref(false)
|
|
45
|
+
const modalOpen = ref(false)
|
|
40
46
|
const fieldEl = ref<HTMLElement | null>(null)
|
|
41
47
|
const { resolvedFieldBg } = useFieldBg(fieldEl, () => props.fieldBg)
|
|
42
48
|
const dropdownEl = ref<HTMLElement | null>(null)
|
|
@@ -68,6 +74,10 @@ function computeDropPos() {
|
|
|
68
74
|
|
|
69
75
|
function toggle() {
|
|
70
76
|
if (props.disabled) return
|
|
77
|
+
if (props.mode === 'modal') {
|
|
78
|
+
modalOpen.value = !modalOpen.value
|
|
79
|
+
return
|
|
80
|
+
}
|
|
71
81
|
if (!open.value) computeDropPos()
|
|
72
82
|
open.value = !open.value
|
|
73
83
|
}
|
|
@@ -76,6 +86,7 @@ function select(opt: SelectOption) {
|
|
|
76
86
|
if (opt.disabled) return
|
|
77
87
|
emit('update:modelValue', opt.value)
|
|
78
88
|
open.value = false
|
|
89
|
+
modalOpen.value = false
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
function onOutsideClick(e: MouseEvent) {
|
|
@@ -85,23 +96,14 @@ function onOutsideClick(e: MouseEvent) {
|
|
|
85
96
|
|
|
86
97
|
function onScroll(e: Event) {
|
|
87
98
|
if (!open.value) return
|
|
88
|
-
// Scrolling inside the dropdown list itself — do nothing
|
|
89
99
|
if (dropdownEl.value?.contains(e.target as Node)) return
|
|
90
|
-
|
|
91
|
-
if (!fieldEl.value) return
|
|
92
|
-
const rect = fieldEl.value.getBoundingClientRect()
|
|
93
|
-
// Only close if the trigger has scrolled completely out of the viewport
|
|
94
|
-
if (rect.bottom < 0 || rect.top > window.innerHeight) {
|
|
95
|
-
open.value = false
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
computeDropPos()
|
|
100
|
+
open.value = false
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
function onKeydown(e: KeyboardEvent) {
|
|
102
|
-
if (e.key === 'Escape') { open.value = false; return }
|
|
104
|
+
if (e.key === 'Escape') { open.value = false; modalOpen.value = false; return }
|
|
103
105
|
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); return }
|
|
104
|
-
if (!open.value) return
|
|
106
|
+
if (!open.value && !modalOpen.value) return
|
|
105
107
|
const opts = props.options.filter((o) => !o.disabled)
|
|
106
108
|
const idx = opts.findIndex((o) => eq(o.value, props.modelValue))
|
|
107
109
|
if (e.key === 'ArrowDown') {
|
|
@@ -116,6 +118,16 @@ function onKeydown(e: KeyboardEvent) {
|
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
|
|
121
|
+
watch(modalOpen, (v) => {
|
|
122
|
+
if (v) {
|
|
123
|
+
document.body.style.overflow = 'hidden'
|
|
124
|
+
} else {
|
|
125
|
+
document.body.style.overflow = ''
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
function closeModal() { modalOpen.value = false }
|
|
130
|
+
|
|
119
131
|
onMounted(() => {
|
|
120
132
|
document.addEventListener('mousedown', onOutsideClick)
|
|
121
133
|
window.addEventListener('scroll', onScroll, true)
|
|
@@ -123,6 +135,7 @@ onMounted(() => {
|
|
|
123
135
|
onUnmounted(() => {
|
|
124
136
|
document.removeEventListener('mousedown', onOutsideClick)
|
|
125
137
|
window.removeEventListener('scroll', onScroll, true)
|
|
138
|
+
document.body.style.overflow = ''
|
|
126
139
|
})
|
|
127
140
|
|
|
128
141
|
const triggerClasses = computed(() => {
|
|
@@ -226,9 +239,10 @@ const labelClasses = computed(() => {
|
|
|
226
239
|
<!-- Arrow icon -->
|
|
227
240
|
<div class="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 flex h-6 items-center">
|
|
228
241
|
<MIcon
|
|
229
|
-
|
|
242
|
+
name="arrow_drop_down"
|
|
230
243
|
:size="24"
|
|
231
244
|
class="text-on-surface-variant transition-transform duration-200"
|
|
245
|
+
:class="open || modalOpen ? 'rotate-180' : ''"
|
|
232
246
|
/>
|
|
233
247
|
</div>
|
|
234
248
|
</div>
|
|
@@ -237,7 +251,7 @@ const labelClasses = computed(() => {
|
|
|
237
251
|
<p v-else-if="hint" class="px-4 text-body-small text-on-surface-variant">{{ hint }}</p>
|
|
238
252
|
</div>
|
|
239
253
|
|
|
240
|
-
<!--
|
|
254
|
+
<!-- Docked dropdown -->
|
|
241
255
|
<Teleport to="body">
|
|
242
256
|
<Transition
|
|
243
257
|
enter-active-class="transition-[opacity,transform] duration-150"
|
|
@@ -248,7 +262,7 @@ const labelClasses = computed(() => {
|
|
|
248
262
|
leave-to-class="opacity-0 -translate-y-1 scale-[0.98]"
|
|
249
263
|
>
|
|
250
264
|
<div
|
|
251
|
-
v-if="open"
|
|
265
|
+
v-if="open && mode === 'docked'"
|
|
252
266
|
ref="dropdownEl"
|
|
253
267
|
class="fixed z-500 max-h-60 overflow-auto rounded-sm bg-surface-container py-1 shadow-elevation-2"
|
|
254
268
|
:style="dropPos"
|
|
@@ -282,5 +296,74 @@ const labelClasses = computed(() => {
|
|
|
282
296
|
</p>
|
|
283
297
|
</div>
|
|
284
298
|
</Transition>
|
|
299
|
+
|
|
300
|
+
<!-- Modal -->
|
|
301
|
+
<Transition name="m3-select-modal">
|
|
302
|
+
<div
|
|
303
|
+
v-if="modalOpen && mode === 'modal'"
|
|
304
|
+
class="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4"
|
|
305
|
+
@click.self="closeModal"
|
|
306
|
+
>
|
|
307
|
+
<div class="select-modal-box flex max-h-[80vh] w-full max-w-sm flex-col overflow-hidden rounded-[28px] bg-surface-container-high shadow-elevation-3">
|
|
308
|
+
<!-- Header -->
|
|
309
|
+
<div class="flex items-center justify-between px-6 pt-6 pb-4">
|
|
310
|
+
<h2 class="text-headline-small text-on-surface">{{ label || placeholder }}</h2>
|
|
311
|
+
<MIconButton icon="close" :label="locale.close" @click="closeModal" />
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<div class="h-px bg-outline-variant" />
|
|
315
|
+
|
|
316
|
+
<!-- Options list -->
|
|
317
|
+
<div class="flex-1 overflow-y-auto py-2">
|
|
318
|
+
<div
|
|
319
|
+
v-for="(opt, i) in options"
|
|
320
|
+
:key="i"
|
|
321
|
+
class="flex cursor-pointer items-center gap-4 px-6 py-3.5 text-body-large transition-colors"
|
|
322
|
+
:class="[
|
|
323
|
+
opt.disabled
|
|
324
|
+
? 'cursor-not-allowed opacity-38 text-on-surface'
|
|
325
|
+
: 'text-on-surface hover:bg-on-surface/8',
|
|
326
|
+
eq(opt.value, modelValue) ? 'bg-primary/8' : '',
|
|
327
|
+
]"
|
|
328
|
+
@click="select(opt)"
|
|
329
|
+
>
|
|
330
|
+
<MIcon
|
|
331
|
+
:name="eq(opt.value, modelValue) ? 'radio_button_checked' : 'radio_button_unchecked'"
|
|
332
|
+
:size="20"
|
|
333
|
+
:class="eq(opt.value, modelValue) ? 'text-primary' : 'text-on-surface-variant'"
|
|
334
|
+
/>
|
|
335
|
+
<span :class="eq(opt.value, modelValue) ? 'text-primary font-medium' : ''">
|
|
336
|
+
{{ opt.label }}
|
|
337
|
+
</span>
|
|
338
|
+
</div>
|
|
339
|
+
<p
|
|
340
|
+
v-if="!options.length"
|
|
341
|
+
class="px-6 py-4 text-center text-body-medium text-on-surface-variant"
|
|
342
|
+
>
|
|
343
|
+
Sin opciones
|
|
344
|
+
</p>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
</Transition>
|
|
285
349
|
</Teleport>
|
|
286
350
|
</template>
|
|
351
|
+
|
|
352
|
+
<style scoped>
|
|
353
|
+
.m3-select-modal-enter-active,
|
|
354
|
+
.m3-select-modal-leave-active {
|
|
355
|
+
transition: opacity 0.15s ease;
|
|
356
|
+
}
|
|
357
|
+
.m3-select-modal-enter-from,
|
|
358
|
+
.m3-select-modal-leave-to {
|
|
359
|
+
opacity: 0;
|
|
360
|
+
}
|
|
361
|
+
.m3-select-modal-enter-active .select-modal-box,
|
|
362
|
+
.m3-select-modal-leave-active .select-modal-box {
|
|
363
|
+
transition: transform 0.15s ease;
|
|
364
|
+
}
|
|
365
|
+
.m3-select-modal-enter-from .select-modal-box,
|
|
366
|
+
.m3-select-modal-leave-to .select-modal-box {
|
|
367
|
+
transform: scale(0.95);
|
|
368
|
+
}
|
|
369
|
+
</style>
|