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