@skyservice-developers/vue-dev-kit 1.0.0
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 +212 -0
- package/dist/style.css +1 -0
- package/dist/vue-dev-kit.cjs +1 -0
- package/dist/vue-dev-kit.js +1812 -0
- package/package.json +55 -0
- package/src/components/Dialog.vue +101 -0
- package/src/components/DialogModal.vue +411 -0
- package/src/components/DialogNext.vue +401 -0
- package/src/components/Header.vue +175 -0
- package/src/components/Modal.vue +234 -0
- package/src/components/index.js +7 -0
- package/src/index.js +7 -0
- package/src/types/index.d.ts +43 -0
- package/src/utils/index.js +1 -0
- package/src/utils/webviewCheck.js +46 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Teleport to="body">
|
|
3
|
+
<transition name="modal-fade">
|
|
4
|
+
<div v-if="modelValue" class="sky-modal-overlay" @click.self="handleOverlayClick">
|
|
5
|
+
<div class="sky-modal" :style="modalStyle">
|
|
6
|
+
<div class="sky-modal-header">
|
|
7
|
+
<button class="sky-modal-back" @click="close" :title="closeTitle">
|
|
8
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
9
|
+
<path d="M19 12H5M12 19l-7-7 7-7" stroke-linecap="round" stroke-linejoin="round"/>
|
|
10
|
+
</svg>
|
|
11
|
+
</button>
|
|
12
|
+
<div class="sky-modal-title-wrapper">
|
|
13
|
+
<h4 class="sky-modal-title">{{ title }}</h4>
|
|
14
|
+
<div v-if="subtitle" class="sky-modal-subtitle">{{ subtitle }}</div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="sky-modal-body">
|
|
19
|
+
<slot></slot>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div v-if="$slots.footer" class="sky-modal-footer">
|
|
23
|
+
<slot name="footer"></slot>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</transition>
|
|
28
|
+
</Teleport>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup>
|
|
32
|
+
import { computed, watch, onMounted, onUnmounted } from 'vue'
|
|
33
|
+
|
|
34
|
+
const props = defineProps({
|
|
35
|
+
modelValue: {
|
|
36
|
+
type: Boolean,
|
|
37
|
+
default: false
|
|
38
|
+
},
|
|
39
|
+
title: {
|
|
40
|
+
type: String,
|
|
41
|
+
default: ''
|
|
42
|
+
},
|
|
43
|
+
subtitle: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: ''
|
|
46
|
+
},
|
|
47
|
+
closeTitle: {
|
|
48
|
+
type: String,
|
|
49
|
+
default: 'Закрити'
|
|
50
|
+
},
|
|
51
|
+
closeOnOverlay: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: true
|
|
54
|
+
},
|
|
55
|
+
closeOnEsc: {
|
|
56
|
+
type: Boolean,
|
|
57
|
+
default: true
|
|
58
|
+
},
|
|
59
|
+
width: {
|
|
60
|
+
type: String,
|
|
61
|
+
default: '100%'
|
|
62
|
+
},
|
|
63
|
+
height: {
|
|
64
|
+
type: String,
|
|
65
|
+
default: '100%'
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const emit = defineEmits(['update:modelValue', 'close'])
|
|
70
|
+
|
|
71
|
+
const modalStyle = computed(() => ({
|
|
72
|
+
width: props.width,
|
|
73
|
+
height: props.height
|
|
74
|
+
}))
|
|
75
|
+
|
|
76
|
+
const close = () => {
|
|
77
|
+
emit('update:modelValue', false)
|
|
78
|
+
emit('close')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const handleOverlayClick = () => {
|
|
82
|
+
if (props.closeOnOverlay) {
|
|
83
|
+
close()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const handleKeydown = (e) => {
|
|
88
|
+
if (e.key === 'Escape' && props.closeOnEsc && props.modelValue) {
|
|
89
|
+
close()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
watch(() => props.modelValue, (value) => {
|
|
94
|
+
if (value) {
|
|
95
|
+
document.body.style.overflow = 'hidden'
|
|
96
|
+
} else {
|
|
97
|
+
document.body.style.overflow = ''
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
onMounted(() => {
|
|
102
|
+
document.addEventListener('keydown', handleKeydown)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
onUnmounted(() => {
|
|
106
|
+
document.removeEventListener('keydown', handleKeydown)
|
|
107
|
+
document.body.style.overflow = ''
|
|
108
|
+
})
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<style scoped>
|
|
112
|
+
.sky-modal-overlay {
|
|
113
|
+
position: fixed;
|
|
114
|
+
top: 0;
|
|
115
|
+
left: 0;
|
|
116
|
+
width: 100%;
|
|
117
|
+
height: 100%;
|
|
118
|
+
background: rgba(0, 0, 0, 0.6);
|
|
119
|
+
backdrop-filter: blur(2px);
|
|
120
|
+
z-index: var(--sky-modal-z-index, 9998);
|
|
121
|
+
display: flex;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
align-items: center;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.sky-modal {
|
|
127
|
+
background: var(--sky-modal-bg, white);
|
|
128
|
+
border-radius: var(--sky-modal-radius, 0);
|
|
129
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.24);
|
|
130
|
+
display: flex;
|
|
131
|
+
flex-direction: column;
|
|
132
|
+
max-width: 100%;
|
|
133
|
+
max-height: 100%;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.sky-modal-header {
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
padding: var(--sky-modal-header-padding, 10px 14px);
|
|
140
|
+
border-bottom: 1px solid var(--sky-modal-border-color, #dee2e6);
|
|
141
|
+
flex-shrink: 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.sky-modal-back {
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
width: 40px;
|
|
149
|
+
height: 40px;
|
|
150
|
+
padding: 0;
|
|
151
|
+
background: transparent;
|
|
152
|
+
border: none;
|
|
153
|
+
cursor: pointer;
|
|
154
|
+
border-radius: 6px;
|
|
155
|
+
transition: background-color 0.2s;
|
|
156
|
+
color: var(--sky-modal-back-color, #374151);
|
|
157
|
+
margin-right: 12px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.sky-modal-back:hover {
|
|
161
|
+
background-color: var(--sky-modal-back-hover-bg, #f8f9fa);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.sky-modal-title-wrapper {
|
|
165
|
+
flex: 1;
|
|
166
|
+
min-width: 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.sky-modal-title {
|
|
170
|
+
margin: 0;
|
|
171
|
+
font-size: var(--sky-modal-title-size, 18px);
|
|
172
|
+
font-weight: var(--sky-modal-title-weight, 500);
|
|
173
|
+
color: var(--sky-modal-title-color, #252525);
|
|
174
|
+
line-height: 1.4;
|
|
175
|
+
white-space: nowrap;
|
|
176
|
+
overflow: hidden;
|
|
177
|
+
text-overflow: ellipsis;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.sky-modal-subtitle {
|
|
181
|
+
font-size: var(--sky-modal-subtitle-size, 14px);
|
|
182
|
+
color: var(--sky-modal-subtitle-color, #6c757d);
|
|
183
|
+
white-space: nowrap;
|
|
184
|
+
overflow: hidden;
|
|
185
|
+
text-overflow: ellipsis;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.sky-modal-body {
|
|
189
|
+
flex: 1;
|
|
190
|
+
overflow-y: auto;
|
|
191
|
+
overflow-x: hidden;
|
|
192
|
+
padding: var(--sky-modal-body-padding, 14px);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.sky-modal-footer {
|
|
196
|
+
padding: var(--sky-modal-footer-padding, 10px 14px);
|
|
197
|
+
border-top: 1px solid var(--sky-modal-border-color, #dee2e6);
|
|
198
|
+
display: flex;
|
|
199
|
+
justify-content: flex-end;
|
|
200
|
+
gap: 10px;
|
|
201
|
+
flex-shrink: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* Animations */
|
|
205
|
+
.modal-fade-enter-active,
|
|
206
|
+
.modal-fade-leave-active {
|
|
207
|
+
transition: opacity 0.3s ease;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.modal-fade-enter-active .sky-modal,
|
|
211
|
+
.modal-fade-leave-active .sky-modal {
|
|
212
|
+
transition: transform 0.3s ease;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.modal-fade-enter-from,
|
|
216
|
+
.modal-fade-leave-to {
|
|
217
|
+
opacity: 0;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.modal-fade-enter-from .sky-modal {
|
|
221
|
+
transform: translateY(-20px);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.modal-fade-leave-to .sky-modal {
|
|
225
|
+
transform: translateY(20px);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Responsive */
|
|
229
|
+
@media (min-width: 768px) {
|
|
230
|
+
.sky-modal {
|
|
231
|
+
border-radius: var(--sky-modal-radius, 8px);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
</style>
|
package/src/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { DefineComponent } from 'vue'
|
|
2
|
+
|
|
3
|
+
// ============ Components ============
|
|
4
|
+
|
|
5
|
+
export interface HeaderProps {
|
|
6
|
+
title?: string
|
|
7
|
+
subtitle?: string
|
|
8
|
+
showBackButton?: boolean
|
|
9
|
+
backButtonTitle?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface HeaderSlots {
|
|
13
|
+
'default'?: () => any
|
|
14
|
+
'title'?: () => any
|
|
15
|
+
'subtitle'?: () => any
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare const Header: DefineComponent<HeaderProps>
|
|
19
|
+
|
|
20
|
+
// Dialog component
|
|
21
|
+
export interface DialogProps {
|
|
22
|
+
modelValue?: boolean
|
|
23
|
+
title?: string
|
|
24
|
+
subtitle?: string
|
|
25
|
+
zIndex?: number | string
|
|
26
|
+
closeText?: string
|
|
27
|
+
enableAnimation?: boolean
|
|
28
|
+
closeOnEsc?: boolean
|
|
29
|
+
mode?: 'next' | 'classic' | null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface DialogSlots {
|
|
33
|
+
'default'?: () => any
|
|
34
|
+
'buttons'?: () => any
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface DialogEmits {
|
|
38
|
+
'update:modelValue': (value: boolean) => void
|
|
39
|
+
'close': () => void
|
|
40
|
+
'save': () => void
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export declare const Dialog: DefineComponent<DialogProps>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { webviewCheck, isIosWebview, isAndroidWebview, isCefWebview, isWebview } from './webviewCheck'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import parser from 'ua-parser-js'
|
|
2
|
+
|
|
3
|
+
export function webviewCheck() {
|
|
4
|
+
// Check iOS webview
|
|
5
|
+
if (window.webkit != null) {
|
|
6
|
+
if (window.webkit.messageHandlers !== 'undefined') {
|
|
7
|
+
try {
|
|
8
|
+
var ua = parser(navigator.userAgent)
|
|
9
|
+
if (ua.browser.name === 'WebKit') {
|
|
10
|
+
return 'ios_webview'
|
|
11
|
+
}
|
|
12
|
+
} catch (err) {
|
|
13
|
+
console.error(err)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check Android webview
|
|
19
|
+
if (typeof Android !== 'undefined') {
|
|
20
|
+
return 'android_webview'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Check CEF webview
|
|
24
|
+
if (typeof window.cefQuery !== 'undefined') {
|
|
25
|
+
return 'cef_webview'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return 'browser'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function isIosWebview() {
|
|
32
|
+
return webviewCheck() === 'ios_webview'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isAndroidWebview() {
|
|
36
|
+
return webviewCheck() === 'android_webview'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isCefWebview() {
|
|
40
|
+
return webviewCheck() === 'cef_webview'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isWebview() {
|
|
44
|
+
const check = webviewCheck()
|
|
45
|
+
return check !== 'browser'
|
|
46
|
+
}
|