itube-specs 0.0.363 → 0.0.365
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/components/ui/s-dropdown.vue +65 -86
- package/components/ui/s-notification.vue +71 -76
- package/components/ui/s-popup.vue +117 -113
- package/package.json +1 -1
|
@@ -1,64 +1,63 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
ref="dropdownRef"
|
|
4
|
-
class="s-dropdown"
|
|
5
|
-
:style="`--max-height: ${getMaxHeight}`"
|
|
6
|
-
:class="[
|
|
7
|
-
{ '--top': top },
|
|
8
|
-
{ '--right': right },
|
|
9
|
-
{ '--center': center },
|
|
10
|
-
{ '--open': open },
|
|
11
|
-
{ '--separate': separateLastChild },
|
|
12
|
-
]"
|
|
13
|
-
@mouseleave="mouseHandler(false)"
|
|
14
|
-
@mouseover="mouseHandler(true)"
|
|
15
|
-
>
|
|
2
|
+
<ClientOnly>
|
|
16
3
|
<div
|
|
17
|
-
|
|
18
|
-
|
|
4
|
+
ref="dropdownRef"
|
|
5
|
+
class="s-dropdown"
|
|
6
|
+
:style="`--max-height: ${getMaxHeight}`"
|
|
7
|
+
:class="[
|
|
8
|
+
{'--top': top},
|
|
9
|
+
{'--right': right},
|
|
10
|
+
{'--center': center},
|
|
11
|
+
{'--open': open},
|
|
12
|
+
{'--separate': separateLastChild},
|
|
13
|
+
]"
|
|
14
|
+
@mouseleave="mouseHandler(false)"
|
|
15
|
+
@mouseover="mouseHandler(true)"
|
|
19
16
|
>
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<transition name="s-dropdown" mode="out-in">
|
|
24
|
-
<dialog
|
|
25
|
-
v-if="useVIf ? open && $slots.items : true"
|
|
26
|
-
:style="!useVIf ? { display: (open && $slots.items) ? '' : 'none' } : {}"
|
|
27
|
-
ref="menuRef"
|
|
28
|
-
class="s-dropdown__menu"
|
|
29
|
-
:class="{ '--open': open }"
|
|
30
|
-
@click="close"
|
|
17
|
+
<div
|
|
18
|
+
class="s-dropdown__trigger"
|
|
19
|
+
@click="openDropdown"
|
|
31
20
|
>
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
21
|
+
<slot name="trigger"></slot>
|
|
22
|
+
</div>
|
|
23
|
+
<transition name="s-dropdown" mode="out-in">
|
|
24
|
+
<dialog
|
|
25
|
+
v-if="useVIf ? open && $slots.items : true"
|
|
26
|
+
:style="!useVIf ? { display: (open && $slots.items) ? '' : 'none' } : {}"
|
|
27
|
+
ref="menuRef"
|
|
28
|
+
class="s-dropdown__menu"
|
|
29
|
+
:class="{'--open': open}"
|
|
40
30
|
@click="close"
|
|
41
31
|
>
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
<button
|
|
33
|
+
class="s-dropdown__sheet-close _to-sm"
|
|
34
|
+
type="button"
|
|
35
|
+
@click="close"
|
|
36
|
+
></button>
|
|
37
|
+
<button
|
|
38
|
+
class="s-dropdown__crest _to-sm"
|
|
39
|
+
type="button"
|
|
40
|
+
@click="close"
|
|
41
|
+
>
|
|
42
|
+
<SIcon name="close" size="16"/>
|
|
43
|
+
</button>
|
|
44
|
+
<slot name="header"></slot>
|
|
45
|
+
<div class="s-dropdown__menu-items" v-if="$slots.items">
|
|
46
|
+
<slot name="items" v-bind="'s-dropdown__item'"></slot>
|
|
47
|
+
</div>
|
|
48
|
+
</dialog>
|
|
49
|
+
</transition>
|
|
50
|
+
</div>
|
|
51
|
+
</ClientOnly>
|
|
53
52
|
</template>
|
|
54
53
|
|
|
55
54
|
<script setup lang="ts">
|
|
56
|
-
|
|
55
|
+
// На компоненте обязательно вызывать пропсы слота и вешать слот пропс (className) на непосредственных детей
|
|
57
56
|
import { onClickOutside, useScrollLock } from '@vueuse/core';
|
|
58
57
|
import { isMobile } from '../../runtime';
|
|
59
58
|
import type { CssBreakpoints } from '../../types';
|
|
60
59
|
|
|
61
|
-
const dropdownRef = ref<
|
|
60
|
+
const dropdownRef = ref<HTMLDialogElement | null>(null);
|
|
62
61
|
const menuRef = ref<HTMLDialogElement | null>(null);
|
|
63
62
|
|
|
64
63
|
const props = withDefaults(defineProps<{
|
|
@@ -70,77 +69,57 @@ const props = withDefaults(defineProps<{
|
|
|
70
69
|
openByClick?: boolean;
|
|
71
70
|
useVIf?: boolean;
|
|
72
71
|
}>(), {
|
|
73
|
-
useVIf: false
|
|
72
|
+
useVIf: false
|
|
74
73
|
});
|
|
75
74
|
|
|
76
75
|
const open = ref(false);
|
|
77
76
|
|
|
78
77
|
const breakpoints = useAppConfig().cssBreakpoints as Record<CssBreakpoints, number>;
|
|
79
78
|
|
|
80
|
-
//
|
|
81
|
-
const
|
|
82
|
-
const bodyScrollLocked = useScrollLock(bodyElement);
|
|
79
|
+
// Блокируем скролл body при открытии на мобильных
|
|
80
|
+
const bodyScrollLocked = useScrollLock(document.body);
|
|
83
81
|
|
|
84
|
-
onMounted(() => {
|
|
85
|
-
bodyElement.value = document.body;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Закрытие дропдауна
|
|
89
82
|
function close() {
|
|
90
83
|
open.value = false;
|
|
91
84
|
|
|
92
|
-
if (isMobile(breakpoints).value
|
|
85
|
+
if (isMobile(breakpoints).value) {
|
|
93
86
|
nextTick(() => {
|
|
94
|
-
menuRef.value?.close();
|
|
95
|
-
bodyScrollLocked.value = false;
|
|
87
|
+
menuRef.value?.close?.();
|
|
88
|
+
bodyScrollLocked.value = false; // разблокируем
|
|
96
89
|
});
|
|
97
90
|
}
|
|
98
91
|
}
|
|
99
92
|
|
|
100
|
-
// Открытие по клику или ховеру
|
|
101
93
|
function openDropdown() {
|
|
102
94
|
if (props.openByClick) {
|
|
103
95
|
open.value = !open.value;
|
|
104
96
|
}
|
|
105
97
|
|
|
106
|
-
if (isMobile(breakpoints).value
|
|
98
|
+
if (isMobile(breakpoints).value) {
|
|
107
99
|
open.value = true;
|
|
108
100
|
|
|
109
101
|
nextTick(() => {
|
|
110
102
|
if (menuRef.value?.showModal) {
|
|
111
103
|
menuRef.value.showModal();
|
|
112
|
-
bodyScrollLocked.value = true;
|
|
104
|
+
bodyScrollLocked.value = true; // блокируем
|
|
113
105
|
}
|
|
114
106
|
});
|
|
115
107
|
}
|
|
116
108
|
}
|
|
117
109
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
110
|
+
watch(open, (isOpen) => {
|
|
111
|
+
if (isOpen) {
|
|
112
|
+
onClickOutside(dropdownRef, () => {
|
|
113
|
+
close();
|
|
114
|
+
});
|
|
122
115
|
}
|
|
123
|
-
}
|
|
116
|
+
}, { immediate: true });
|
|
124
117
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
(isOpen) => {
|
|
129
|
-
if (isOpen && process.client && dropdownRef.value) {
|
|
130
|
-
onClickOutside(dropdownRef.value, () => {
|
|
131
|
-
close();
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
{ immediate: true }
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
// Гарантированная разблокировка скролла при уходе со страницы
|
|
139
|
-
onBeforeUnmount(() => {
|
|
140
|
-
if (process.client) {
|
|
141
|
-
bodyScrollLocked.value = false;
|
|
118
|
+
function mouseHandler(event: boolean) {
|
|
119
|
+
if (!isMobile(breakpoints).value && !props.openByClick) {
|
|
120
|
+
open.value = event;
|
|
142
121
|
}
|
|
143
|
-
}
|
|
122
|
+
}
|
|
144
123
|
|
|
145
124
|
const getMaxHeight = computed(() => {
|
|
146
125
|
return props.maxHeight ? `${props.maxHeight}px` : 'none';
|
|
@@ -1,102 +1,97 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
<ClientOnly>
|
|
3
|
+
<dialog
|
|
4
|
+
ref="notification"
|
|
5
|
+
class="s-notification"
|
|
6
|
+
:class="{'--popup': popup}"
|
|
7
|
+
@click="closeByBackdropClick"
|
|
8
|
+
@cancel="close"
|
|
9
|
+
>
|
|
10
|
+
<div class="s-notification__wrapper">
|
|
11
|
+
<header class="s-notification__header">
|
|
12
|
+
<p
|
|
13
|
+
v-if="$slots.title"
|
|
14
|
+
class="s-notification__title"
|
|
15
|
+
>
|
|
16
|
+
<slot name="title"></slot>
|
|
17
|
+
</p>
|
|
18
|
+
<button
|
|
19
|
+
class="s-notification__close"
|
|
20
|
+
type="button"
|
|
21
|
+
title="close"
|
|
22
|
+
aria-label="close"
|
|
23
|
+
@click="close"
|
|
24
|
+
>
|
|
25
|
+
<SIcon class="s-notification__close-icon" name="close" size="16"/>
|
|
26
|
+
</button>
|
|
27
|
+
</header>
|
|
28
|
+
<div class="s-notification__content">
|
|
29
|
+
<slot></slot>
|
|
30
|
+
</div>
|
|
31
|
+
<div
|
|
32
|
+
v-if="$slots.footer"
|
|
33
|
+
class="s-notification__footer"
|
|
20
34
|
>
|
|
21
|
-
<
|
|
22
|
-
</
|
|
23
|
-
</header>
|
|
24
|
-
<div class="s-notification__content">
|
|
25
|
-
<slot></slot>
|
|
35
|
+
<slot name="footer"></slot>
|
|
36
|
+
</div>
|
|
26
37
|
</div>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
</dialog>
|
|
38
|
+
</dialog>
|
|
39
|
+
</ClientOnly>
|
|
32
40
|
</template>
|
|
33
41
|
|
|
34
42
|
<script setup lang="ts">
|
|
35
|
-
import { ref, watch,
|
|
36
|
-
import { useScrollLock } from '@vueuse/core'
|
|
37
|
-
import { onBackdropClick } from '../../runtime'
|
|
43
|
+
import { ref, watch, onBeforeUnmount } from 'vue';
|
|
44
|
+
import { useScrollLock } from '@vueuse/core';
|
|
45
|
+
import { onBackdropClick } from '../../runtime'; // оставляем, если используется где-то ещё
|
|
38
46
|
|
|
39
|
-
const notification = ref<HTMLDialogElement | null>(null)
|
|
47
|
+
const notification = ref<HTMLDialogElement | null>(null);
|
|
40
48
|
|
|
41
49
|
const emit = defineEmits<{
|
|
42
|
-
(
|
|
43
|
-
(
|
|
44
|
-
}>()
|
|
50
|
+
(eventName: 'update:modelValue', value: boolean): void
|
|
51
|
+
(eventName: 'close'): void
|
|
52
|
+
}>();
|
|
45
53
|
|
|
46
54
|
const props = defineProps<{
|
|
47
55
|
modelValue: boolean
|
|
48
56
|
popup?: boolean
|
|
49
|
-
}>()
|
|
50
|
-
|
|
51
|
-
// Создаём элемент ТОЛЬКО на клиенте
|
|
52
|
-
const bodyElement = ref<HTMLElement | null>(null)
|
|
53
|
-
const isBodyScrollLocked = useScrollLock(bodyElement)
|
|
57
|
+
}>();
|
|
54
58
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
})
|
|
59
|
+
// Блокировка скролла тела страницы (body) при открытом модальном окне
|
|
60
|
+
const bodyElement = ref(document.body);
|
|
61
|
+
const isBodyScrollLocked = useScrollLock(bodyElement);
|
|
59
62
|
|
|
60
|
-
// Реактивно управляем открытием/закрытием и блокировкой скролла
|
|
61
63
|
watch(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
|
|
64
|
+
() => props.modelValue,
|
|
65
|
+
(newVal) => {
|
|
66
|
+
if (newVal && props.popup) {
|
|
67
|
+
// Открываем dialog и блокируем скролл
|
|
68
|
+
notification.value?.showModal();
|
|
69
|
+
isBodyScrollLocked.value = true;
|
|
70
|
+
} else if (!newVal && props.popup) {
|
|
71
|
+
// Закрываем и разблокируем
|
|
72
|
+
notification.value?.close();
|
|
73
|
+
isBodyScrollLocked.value = false;
|
|
74
|
+
} else if (newVal && !props.popup) {
|
|
75
|
+
notification.value?.show();
|
|
76
|
+
} else if (!newVal && !props.popup) {
|
|
77
|
+
notification.value?.close();
|
|
76
78
|
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
notification.value.close()
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
{ immediate: true }
|
|
84
|
-
)
|
|
79
|
+
},
|
|
80
|
+
{ immediate: true }
|
|
81
|
+
);
|
|
85
82
|
|
|
86
|
-
//
|
|
83
|
+
// Дополнительная очистка при размонтировании (на всякий случай)
|
|
87
84
|
onBeforeUnmount(() => {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
})
|
|
85
|
+
isBodyScrollLocked.value = false;
|
|
86
|
+
});
|
|
92
87
|
|
|
93
88
|
function close() {
|
|
94
|
-
emit('close')
|
|
95
|
-
emit('update:modelValue', false)
|
|
89
|
+
emit('close');
|
|
90
|
+
emit('update:modelValue', false);
|
|
96
91
|
}
|
|
97
92
|
|
|
98
93
|
function closeByBackdropClick(event: Event) {
|
|
99
|
-
const target = event.target as HTMLDialogElement
|
|
100
|
-
onBackdropClick(target, close)
|
|
94
|
+
const target = event.target as HTMLDialogElement;
|
|
95
|
+
onBackdropClick(target, close);
|
|
101
96
|
}
|
|
102
97
|
</script>
|
|
@@ -1,143 +1,148 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
{
|
|
8
|
-
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<div
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@click="close"
|
|
19
|
-
></button>
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<aside
|
|
23
|
-
v-if="$slots.aside && !isMobile(breakpoints).value"
|
|
24
|
-
class="s-popup__aside"
|
|
25
|
-
>
|
|
26
|
-
<slot name="aside"></slot>
|
|
27
|
-
</aside>
|
|
28
|
-
|
|
29
|
-
<header class="s-popup__header">
|
|
30
|
-
<button
|
|
31
|
-
v-if="back"
|
|
32
|
-
class="s-popup__back"
|
|
33
|
-
type="button"
|
|
34
|
-
@click="$emit('back')"
|
|
2
|
+
<ClientOnly>
|
|
3
|
+
<dialog
|
|
4
|
+
ref="popupRef"
|
|
5
|
+
class="s-popup"
|
|
6
|
+
:class="[
|
|
7
|
+
{'--sheet': sheet},
|
|
8
|
+
{'--transparent-backdrop': transparentBackdrop},
|
|
9
|
+
{'--aside': $slots.aside}
|
|
10
|
+
]"
|
|
11
|
+
@click="closeByBackdropClick"
|
|
12
|
+
@cancel="close"
|
|
13
|
+
>
|
|
14
|
+
<div class="s-popup__wrapper">
|
|
15
|
+
<div
|
|
16
|
+
v-if="sheet"
|
|
17
|
+
class="s-popup__sheet"
|
|
35
18
|
>
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
19
|
+
<button
|
|
20
|
+
class="s-popup__sheet-handler"
|
|
21
|
+
type="button"
|
|
22
|
+
@click="close"
|
|
23
|
+
></button>
|
|
41
24
|
</div>
|
|
42
25
|
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@click="close"
|
|
26
|
+
<aside
|
|
27
|
+
v-if="$slots.aside && !isMobile(breakpoints).value"
|
|
28
|
+
class="s-popup__aside"
|
|
47
29
|
>
|
|
48
|
-
<
|
|
49
|
-
</
|
|
50
|
-
</header>
|
|
30
|
+
<slot name="aside"></slot>
|
|
31
|
+
</aside>
|
|
51
32
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
33
|
+
<header
|
|
34
|
+
class="s-popup__header"
|
|
35
|
+
>
|
|
36
|
+
<button
|
|
37
|
+
v-if="back"
|
|
38
|
+
class="s-popup__back"
|
|
39
|
+
type="button"
|
|
40
|
+
@click="$emit('back')"
|
|
41
|
+
>
|
|
42
|
+
<SIcon name="angle-left" size="24"/>
|
|
43
|
+
</button>
|
|
44
|
+
<div
|
|
45
|
+
v-if="$slots.title"
|
|
46
|
+
class="s-popup__title"
|
|
47
|
+
>
|
|
48
|
+
<slot name="title"></slot>
|
|
49
|
+
</div>
|
|
50
|
+
<button
|
|
51
|
+
class="s-popup__close"
|
|
52
|
+
type="button"
|
|
53
|
+
@click="close"
|
|
54
|
+
>
|
|
55
|
+
<SIcon name="close" size="24"/>
|
|
56
|
+
</button>
|
|
57
|
+
</header>
|
|
58
|
+
<div
|
|
59
|
+
v-if="$slots.fixedContent"
|
|
60
|
+
class="s-popup__subheader"
|
|
61
|
+
>
|
|
62
|
+
<slot name="fixedContent"></slot>
|
|
63
|
+
</div>
|
|
64
|
+
<div
|
|
65
|
+
v-if="$slots.default"
|
|
66
|
+
class="s-popup__content"
|
|
67
|
+
>
|
|
68
|
+
<slot></slot>
|
|
69
|
+
</div>
|
|
70
|
+
<div
|
|
71
|
+
v-if="$slots.footer"
|
|
72
|
+
class="s-popup__footer"
|
|
73
|
+
>
|
|
74
|
+
<slot name="footer"></slot>
|
|
75
|
+
</div>
|
|
62
76
|
</div>
|
|
63
|
-
</div>
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
<transition mode="out-in">
|
|
79
|
+
<SSnackbar
|
|
80
|
+
v-if="snackbarText && isSnackBarInPopup"
|
|
81
|
+
/>
|
|
82
|
+
</transition>
|
|
83
|
+
</dialog>
|
|
84
|
+
</ClientOnly>
|
|
69
85
|
</template>
|
|
70
86
|
|
|
71
87
|
<script setup lang="ts">
|
|
72
|
-
import { ref, watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
|
|
73
|
-
import { useScrollLock } from '@vueuse/core';
|
|
74
88
|
import { onBackdropClick, isMobile } from '../../runtime';
|
|
75
89
|
import type { CssBreakpoints } from '../../types';
|
|
90
|
+
import { useScrollLock } from '@vueuse/core';
|
|
76
91
|
|
|
77
|
-
const
|
|
92
|
+
const { resetSnackbar } = useSnackbar();
|
|
78
93
|
|
|
94
|
+
const breakpoints = useAppConfig().cssBreakpoints as Record<CssBreakpoints, number>;
|
|
95
|
+
const popupRef = ref()
|
|
79
96
|
const emit = defineEmits<{
|
|
80
|
-
(
|
|
81
|
-
(
|
|
82
|
-
(
|
|
83
|
-
}>()
|
|
97
|
+
(eventName: 'update:modelValue', value: boolean): void
|
|
98
|
+
(eventName: 'back'): void
|
|
99
|
+
(eventName: 'close'): void
|
|
100
|
+
}>()
|
|
84
101
|
|
|
85
102
|
const props = defineProps<{
|
|
86
|
-
modelValue: boolean
|
|
87
|
-
back?: boolean
|
|
88
|
-
transparentBackdrop?: boolean
|
|
89
|
-
sheet?: boolean
|
|
90
|
-
title?: string
|
|
91
|
-
notModal?: boolean
|
|
92
|
-
}>()
|
|
93
|
-
|
|
94
|
-
const
|
|
103
|
+
modelValue: boolean
|
|
104
|
+
back?: boolean
|
|
105
|
+
transparentBackdrop?: boolean
|
|
106
|
+
sheet?: boolean
|
|
107
|
+
title?: string
|
|
108
|
+
notModal?: boolean
|
|
109
|
+
}>()
|
|
110
|
+
|
|
111
|
+
const isLocked = useScrollLock(
|
|
112
|
+
typeof document !== 'undefined' ? document.body : null
|
|
113
|
+
);
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
115
|
+
watch(
|
|
116
|
+
() => props.modelValue,
|
|
117
|
+
(newVal) => {
|
|
118
|
+
if (newVal) {
|
|
119
|
+
nextTick(() => {
|
|
120
|
+
isLocked.value = true;
|
|
121
|
+
|
|
122
|
+
if (props.notModal) {
|
|
123
|
+
popupRef.value?.show();
|
|
124
|
+
} else {
|
|
125
|
+
popupRef.value?.showModal();
|
|
126
|
+
}
|
|
127
|
+
popupRef.value?.focus({ preventScroll: true });
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
isLocked.value = false;
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{ immediate: true }
|
|
134
|
+
);
|
|
99
135
|
|
|
100
136
|
onMounted(() => {
|
|
101
|
-
bodyElement.value = document.body;
|
|
102
|
-
|
|
103
|
-
// Включаем режим отображения снакбара внутри попапа
|
|
104
137
|
isSnackBarInPopup.value = true;
|
|
105
138
|
resetSnackbar();
|
|
106
139
|
});
|
|
107
140
|
|
|
108
141
|
onBeforeUnmount(() => {
|
|
109
142
|
isSnackBarInPopup.value = false;
|
|
110
|
-
|
|
111
|
-
isLocked.value = false;
|
|
112
|
-
}
|
|
143
|
+
isLocked.value = false;
|
|
113
144
|
});
|
|
114
145
|
|
|
115
|
-
// Реактивное открытие/закрытие + блокировка скролла
|
|
116
|
-
watch(
|
|
117
|
-
() => props.modelValue,
|
|
118
|
-
async (isOpen) => {
|
|
119
|
-
if (!process.client || !popupRef.value) return;
|
|
120
|
-
|
|
121
|
-
if (isOpen) {
|
|
122
|
-
await nextTick(); // гарантируем, что dialog уже в DOM
|
|
123
|
-
|
|
124
|
-
if (props.notModal) {
|
|
125
|
-
popupRef.value.show();
|
|
126
|
-
} else {
|
|
127
|
-
popupRef.value.showModal();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
popupRef.value.focus({ preventScroll: true });
|
|
131
|
-
isLocked.value = true;
|
|
132
|
-
} else {
|
|
133
|
-
isLocked.value = false;
|
|
134
|
-
// dialog автоматически закрывается при удалении из DOM, но на всякий случай
|
|
135
|
-
popupRef.value.close();
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
{ immediate: true }
|
|
139
|
-
);
|
|
140
|
-
|
|
141
146
|
function close() {
|
|
142
147
|
emit('close');
|
|
143
148
|
emit('update:modelValue', false);
|
|
@@ -148,6 +153,5 @@ function closeByBackdropClick(event: Event) {
|
|
|
148
153
|
onBackdropClick(target, close);
|
|
149
154
|
}
|
|
150
155
|
|
|
151
|
-
|
|
152
|
-
const { snackbarText, isSnackBarInPopup, resetSnackbar } = useSnackbar();
|
|
156
|
+
const { snackbarText, isSnackBarInPopup } = useSnackbar();
|
|
153
157
|
</script>
|