@skyservice-developers/vue-dev-kit 1.0.7 → 1.1.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/package.json CHANGED
@@ -1,22 +1,29 @@
1
1
  {
2
2
  "name": "@skyservice-developers/vue-dev-kit",
3
- "version": "1.0.7",
4
- "description": "Vue 3 developer toolkit - components and helpers",
3
+ "version": "1.1.0",
4
+ "description": "Vue 2 and Vue 3 developer toolkit - components and helpers",
5
5
  "type": "module",
6
- "main": "./dist/vue-dev-kit.cjs",
7
- "module": "./dist/vue-dev-kit.js",
8
- "types": "./src/types/index.d.ts",
6
+ "main": "./dist/vue3/vue-dev-kit.cjs",
7
+ "module": "./dist/vue3/vue-dev-kit.js",
8
+ "types": "./src/shared/types/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "import": "./dist/vue-dev-kit.js",
12
- "require": "./dist/vue-dev-kit.cjs",
13
- "types": "./src/types/index.d.ts"
11
+ "import": "./dist/vue3/vue-dev-kit.js",
12
+ "require": "./dist/vue3/vue-dev-kit.cjs",
13
+ "types": "./src/shared/types/index.d.ts"
14
14
  },
15
- "./style.css": {
16
- "import": "./dist/style.css",
17
- "require": "./dist/style.css",
18
- "default": "./dist/style.css"
19
- }
15
+ "./vue2": {
16
+ "import": "./dist/vue2/vue-dev-kit.js",
17
+ "require": "./dist/vue2/vue-dev-kit.cjs"
18
+ },
19
+ "./vue3": {
20
+ "import": "./dist/vue3/vue-dev-kit.js",
21
+ "require": "./dist/vue3/vue-dev-kit.cjs",
22
+ "types": "./src/shared/types/index.d.ts"
23
+ },
24
+ "./vue2/style.css": "./dist/vue2/style.css",
25
+ "./vue3/style.css": "./dist/vue3/style.css",
26
+ "./style.css": "./dist/vue3/style.css"
20
27
  },
21
28
  "files": [
22
29
  "dist",
@@ -24,24 +31,36 @@
24
31
  ],
25
32
  "scripts": {
26
33
  "dev": "vite",
27
- "build": "vite build",
34
+ "build:vue2": "vite build --config vite.vue2.config.js",
35
+ "build:vue3": "vite build --config vite.vue3.config.js",
36
+ "build": "npm run build:vue2 && npm run build:vue3",
28
37
  "preview": "vite preview",
29
38
  "prepublishOnly": "npm run build",
30
39
  "release": "npm publish --access public"
31
40
  },
32
41
  "peerDependencies": {
33
- "vue": "^3.4.0"
42
+ "vue": "^2.7.0 || ^3.4.0"
43
+ },
44
+ "peerDependenciesMeta": {
45
+ "portal-vue": {
46
+ "optional": true
47
+ }
34
48
  },
35
49
  "dependencies": {
50
+ "portal-vue": "^3.0.0",
36
51
  "ua-parser-js": "^1.0.37"
37
52
  },
38
53
  "devDependencies": {
39
- "@vitejs/plugin-vue": "^5.0.4",
40
- "vite": "^5.1.4",
41
- "vue": "^3.4.21"
54
+ "@vitejs/plugin-vue": "^4.5.2",
55
+ "vite": "^4.5.2",
56
+ "vite-plugin-vue2": "^2.0.3",
57
+ "vue": "^2.7.16",
58
+ "vue-template-compiler": "^2.7.16",
59
+ "vue3": "npm:vue@^3.4.21"
42
60
  },
43
61
  "keywords": [
44
62
  "vue",
63
+ "vue2",
45
64
  "vue3",
46
65
  "components",
47
66
  "toolkit",
@@ -56,5 +75,10 @@
56
75
  "bugs": {
57
76
  "url": "https://github.com/Skyservice-POS/vue-dev-kit/issues"
58
77
  },
59
- "homepage": "https://github.com/Skyservice-POS/vue-dev-kit#readme"
78
+ "homepage": "https://github.com/Skyservice-POS/vue-dev-kit#readme",
79
+ "overrides": {
80
+ "@vitejs/plugin-vue": {
81
+ "vue": "3.4.21"
82
+ }
83
+ }
60
84
  }
package/src/index.js CHANGED
@@ -1,7 +1,9 @@
1
- // Components
2
- import { Header, Dialog } from './components'
1
+ // // Components
3
2
 
4
- export {
5
- Header,
6
- Dialog
7
- }
3
+ export * from './vue3'
4
+ // import { Header, Dialog } from './vue3/components'
5
+
6
+ // export {
7
+ // Header,
8
+ // Dialog
9
+ // }
@@ -0,0 +1 @@
1
+ export * from './utils'
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <portal :to="to">
3
+ <slot />
4
+ </portal>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ props: {
10
+ to: {
11
+ type: String,
12
+ default: 'body',
13
+ },
14
+ },
15
+ }
16
+ </script>
@@ -0,0 +1,111 @@
1
+ <template>
2
+ <component
3
+ :is="dialogComponent"
4
+ v-model="isOpen"
5
+ :title="title"
6
+ :subtitle="subtitle"
7
+ :z-index="zIndex"
8
+ :close-text="closeText"
9
+ :enable-animation="enableAnimation"
10
+ :close-on-esc="closeOnEsc"
11
+ :has-buttons="!!$slots.buttons"
12
+ @close="$emit('close')"
13
+ @save="$emit('save')"
14
+ >
15
+ <slot></slot>
16
+ <template v-if="$slots.buttons" #buttons>
17
+ <slot name="buttons"></slot>
18
+ </template>
19
+ </component>
20
+ </template>
21
+
22
+ <script>
23
+ import DialogModal from './DialogModal.vue'
24
+ import DialogNext from './DialogNext.vue'
25
+
26
+ export default {
27
+ name: 'Dialog',
28
+ components: {
29
+ DialogModal,
30
+ DialogNext
31
+ },
32
+ props: {
33
+ modelValue: {
34
+ type: Boolean,
35
+ default: false
36
+ },
37
+ title: {
38
+ type: String,
39
+ default: ''
40
+ },
41
+ subtitle: {
42
+ type: String,
43
+ default: ''
44
+ },
45
+ zIndex: {
46
+ type: [Number, String],
47
+ default: null
48
+ },
49
+ closeText: {
50
+ type: String,
51
+ default: ''
52
+ },
53
+ enableAnimation: {
54
+ type: Boolean,
55
+ default: true
56
+ },
57
+ closeOnEsc: {
58
+ type: Boolean,
59
+ default: true
60
+ },
61
+ // Force specific mode (overrides URL parameter)
62
+ mode: {
63
+ type: String,
64
+ default: null, // 'next' | 'classic' | null (auto-detect)
65
+ validator: (value) => [null, 'next', 'classic'].includes(value)
66
+ }
67
+ },
68
+ data() {
69
+ return {
70
+ rocketMode: true // default to DialogNext
71
+ }
72
+ },
73
+ computed: {
74
+ isOpen: {
75
+ get() {
76
+ return this.modelValue
77
+ },
78
+ set(value) {
79
+ this.$emit('update:modelValue', value)
80
+ }
81
+ },
82
+ dialogComponent() {
83
+ // If mode is explicitly set, use it
84
+ if (this.mode === 'next') {
85
+ return DialogNext
86
+ }
87
+ if (this.mode === 'classic') {
88
+ return DialogModal
89
+ }
90
+
91
+ // Auto-detect based on URL parameter
92
+ return this.rocketMode ? DialogNext : DialogModal
93
+ }
94
+ },
95
+ mounted() {
96
+ try {
97
+ const urlParams = new URLSearchParams(window.location.search)
98
+ const rocketParam = urlParams.get('rocketMode')
99
+
100
+ if (rocketParam === 'false') {
101
+ this.rocketMode = false
102
+ } else {
103
+ // true or not specified = DialogNext
104
+ this.rocketMode = true
105
+ }
106
+ } catch {
107
+ this.rocketMode = true
108
+ }
109
+ }
110
+ }
111
+ </script>
@@ -0,0 +1,438 @@
1
+ <template>
2
+ <transition :name="enableAnimation ? 'dialog-slide' : ''">
3
+ <div
4
+ v-if="modelValue"
5
+ class="sky-dialogbox sky-dialogbox-classic"
6
+ :style="[zIndex ? { 'z-index': zIndex } : null]"
7
+ >
8
+ <div class="sky-dialog-overlay" :class="{ 'sky-dialog-animate': enableAnimation }">
9
+ <div ref="dialogContent" class="sky-dialog-content">
10
+ <!-- Header -->
11
+ <div class="sky-dialog-title" :class="{ 'sky-dialog-title-with-subtitle': subtitle }">
12
+ {{ title }}
13
+ <span v-if="subtitle" class="sky-dialog-subtitle">{{ subtitle }}</span>
14
+ </div>
15
+
16
+ <button class="sky-dialog-close" :title="closeText" @click="close">
17
+ <svg viewBox="0 0 16 16" width="16" height="16">
18
+ <line x1="1" y1="15" x2="15" y2="1" stroke="currentColor" stroke-width="2" />
19
+ <line x1="1" y1="1" x2="15" y2="15" stroke="currentColor" stroke-width="2" />
20
+ </svg>
21
+ </button>
22
+
23
+ <div class="sky-dialog-clearfix" />
24
+
25
+ <!-- Body -->
26
+ <div
27
+ ref="dialogPaper"
28
+ class="sky-dialog-paper"
29
+ :class="{ 'sky-dialog-paper-no-footer': !showFooter }"
30
+ @touchstart="handleTouchStart"
31
+ @touchend="handleTouchEnd"
32
+ >
33
+ <!-- iOS swipe back area -->
34
+ <div v-if="isIos" class="sky-dialog-swipe-area" />
35
+ <slot></slot>
36
+ </div>
37
+
38
+ <!-- Footer -->
39
+ <div v-if="showFooter" class="sky-dialog-footer" :class="{ 'sky-dialog-footer-animate': enableAnimation }">
40
+ <slot name="buttons"></slot>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </transition>
46
+ </template>
47
+
48
+ <script>
49
+ import { isIosWebview, isAndroidWebview } from '../../shared/utils/webviewCheck'
50
+
51
+ export default {
52
+ name: 'DialogModal',
53
+ props: {
54
+ modelValue: {
55
+ type: Boolean,
56
+ default: false
57
+ },
58
+ title: {
59
+ type: String,
60
+ default: ''
61
+ },
62
+ subtitle: {
63
+ type: String,
64
+ default: ''
65
+ },
66
+ zIndex: {
67
+ type: [Number, String],
68
+ default: null
69
+ },
70
+ closeText: {
71
+ type: String,
72
+ default: 'Закрити'
73
+ },
74
+ enableAnimation: {
75
+ type: Boolean,
76
+ default: true
77
+ },
78
+ closeOnEsc: {
79
+ type: Boolean,
80
+ default: true
81
+ },
82
+ hasButtons: {
83
+ type: Boolean,
84
+ default: null
85
+ }
86
+ },
87
+ data() {
88
+ return {
89
+ touchStartX: 0
90
+ }
91
+ },
92
+ computed: {
93
+ isIos() {
94
+ try {
95
+ return isIosWebview()
96
+ } catch {
97
+ return false
98
+ }
99
+ },
100
+ isAndroid() {
101
+ try {
102
+ return isAndroidWebview()
103
+ } catch {
104
+ return false
105
+ }
106
+ },
107
+ // Determine if footer should be shown
108
+ showFooter() {
109
+ // If hasButtons prop is explicitly set, use it
110
+ if (this.hasButtons !== null) {
111
+ return this.hasButtons
112
+ }
113
+ // Fallback to slot check (for direct usage without Dialog wrapper)
114
+ return !!this.$slots.buttons
115
+ }
116
+ },
117
+ watch: {
118
+ // Body scroll lock
119
+ modelValue(value) {
120
+ if (value) {
121
+ document.body.style.overflow = 'hidden'
122
+ this.$nextTick(() => {
123
+ this.androidFix()
124
+ })
125
+ } else {
126
+ document.body.style.overflow = ''
127
+ }
128
+ }
129
+ },
130
+ mounted() {
131
+ document.addEventListener('keydown', this.handleKeydown)
132
+ window.addEventListener('resize', this.androidFix)
133
+ },
134
+ beforeDestroy() {
135
+ document.removeEventListener('keydown', this.handleKeydown)
136
+ window.removeEventListener('resize', this.androidFix)
137
+ document.body.style.overflow = ''
138
+ },
139
+ methods: {
140
+ close() {
141
+ this.$emit('update:modelValue', false)
142
+ this.$emit('close')
143
+ },
144
+ handleKeydown(e) {
145
+ if (e.key === 'Escape' && this.closeOnEsc && this.modelValue) {
146
+ this.close()
147
+ }
148
+ if (e.key === 'Enter' && this.modelValue) {
149
+ this.$emit('save')
150
+ }
151
+ },
152
+ // Touch handling for iOS swipe back
153
+ handleTouchStart(e) {
154
+ if (e.touches[0].clientX < 35) {
155
+ this.touchStartX = e.touches[0].clientX
156
+ }
157
+ },
158
+ handleTouchEnd(e) {
159
+ if (this.touchStartX > 0 && this.touchStartX < 35) {
160
+ const touchEndX = e.changedTouches[0].clientX
161
+ if (touchEndX - this.touchStartX > 50) {
162
+ this.close()
163
+ }
164
+ }
165
+ this.touchStartX = 0
166
+ },
167
+ // Android notch fix
168
+ androidFix() {
169
+ if (!this.isAndroid || !this.$refs.dialogContent) return
170
+
171
+ try {
172
+ if (typeof Android !== 'undefined' && Android.getDisplayCutoutTop) {
173
+ const cutoutTop = Android.getDisplayCutoutTop()
174
+ if (cutoutTop && window.devicePixelRatio > 1.0) {
175
+ const paddingTop = cutoutTop / window.devicePixelRatio
176
+ this.$refs.dialogContent.style.paddingTop = paddingTop + 'px'
177
+ }
178
+ }
179
+ } catch (err) {
180
+ // Android interface not available
181
+ }
182
+ }
183
+ }
184
+ }
185
+ </script>
186
+
187
+ <style>
188
+ /* Global styles (не scoped через баг з Teleport) */
189
+ .sky-dialogbox-classic {
190
+ display: block;
191
+ position: fixed;
192
+ padding: 0;
193
+ top: 0;
194
+ left: 0;
195
+ width: 100%;
196
+ height: 100%;
197
+ z-index: var(--sky-dialog-z-index, 9998);
198
+ background: rgba(0, 0, 0, 0.6);
199
+ backdrop-filter: blur(2px);
200
+ }
201
+ </style>
202
+
203
+ <style scoped>
204
+ .sky-dialog-overlay {
205
+ display: flex;
206
+ justify-content: center;
207
+ align-items: center;
208
+ position: fixed;
209
+ padding: 0;
210
+ top: 0;
211
+ left: 0;
212
+ width: 100%;
213
+ height: 100%;
214
+ z-index: 9999;
215
+ }
216
+
217
+ .sky-dialog-content {
218
+ background: var(--sky-dialog-bg, white);
219
+ width: 100%;
220
+ height: 100%;
221
+ border-radius: var(--sky-dialog-radius, 5px);
222
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.24);
223
+ }
224
+
225
+ .sky-dialog-title {
226
+ max-width: calc(100% - 80px);
227
+ font-size: var(--sky-dialog-title-size, 13pt);
228
+ padding: 24px;
229
+ padding-right: 0;
230
+ float: left;
231
+ white-space: nowrap;
232
+ overflow: hidden;
233
+ text-overflow: ellipsis;
234
+ color: var(--sky-dialog-title-color, #252525);
235
+ }
236
+
237
+ .sky-dialog-subtitle {
238
+ display: block;
239
+ font-size: var(--sky-dialog-subtitle-size, 12pt);
240
+ line-height: 24px;
241
+ color: var(--sky-dialog-subtitle-color, #6c757d);
242
+ white-space: nowrap;
243
+ overflow: hidden;
244
+ text-overflow: ellipsis;
245
+ }
246
+
247
+ .sky-dialog-close {
248
+ cursor: pointer;
249
+ font-size: 16pt;
250
+ margin: 15px;
251
+ padding: 17px;
252
+ float: right;
253
+ border-radius: 50%;
254
+ width: 50px;
255
+ height: 50px;
256
+ background: transparent;
257
+ border: none;
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ color: var(--sky-dialog-close-color, #333);
262
+ transition: background-color 0.2s;
263
+ }
264
+
265
+ .sky-dialog-close:hover {
266
+ background-color: var(--sky-dialog-close-hover-bg, #f0f0f0);
267
+ }
268
+
269
+ .sky-dialog-clearfix {
270
+ clear: both;
271
+ }
272
+
273
+ .sky-dialog-paper {
274
+ height: 100%;
275
+ overflow-y: auto;
276
+ overflow-x: hidden;
277
+ -webkit-overflow-scrolling: touch;
278
+ position: relative;
279
+ }
280
+
281
+ .sky-dialog-swipe-area {
282
+ position: absolute;
283
+ width: 35px;
284
+ height: 100%;
285
+ left: 0;
286
+ }
287
+
288
+ .sky-dialog-footer {
289
+ padding: 5px 10px;
290
+ display: flex;
291
+ justify-content: center;
292
+ width: 100%;
293
+ transform: translateY(-52px);
294
+ gap: 10px;
295
+ }
296
+
297
+ /* Кнопки в футері: 1 = 100%, 2 = по 50% */
298
+ .sky-dialog-footer > :deep(*) {
299
+ flex: 1;
300
+ min-width: 0;
301
+ }
302
+
303
+ .sky-dialog-footer:has(> :deep(*:only-child)) > :deep(*) {
304
+ max-width: 100%;
305
+ }
306
+
307
+ .sky-dialog-footer:has(> :deep(*:nth-child(2)):not(:has(> :deep(*:nth-child(3))))) > :deep(*) {
308
+ flex: 1 1 50%;
309
+ }
310
+
311
+ /* Desktop */
312
+ @media only screen and (min-width: 1400px) {
313
+ .sky-dialog-content {
314
+ width: 75%;
315
+ margin: 0 auto;
316
+ }
317
+ }
318
+
319
+ /* Tablet and Desktop */
320
+ @media screen and (min-width: 710px) {
321
+ .sky-dialog-paper {
322
+ height: calc(100% - 150px);
323
+ max-height: calc(100% - 150px);
324
+ background-color: #fff;
325
+ margin: 0 10px 60px 10px;
326
+ border-radius: 5px;
327
+ }
328
+
329
+ /* Full height when no footer */
330
+ .sky-dialog-paper-no-footer {
331
+ height: calc(100% - 70px);
332
+ max-height: calc(100% - 70px);
333
+ margin-bottom: 10px;
334
+ }
335
+
336
+ .sky-dialogbox,
337
+ .sky-dialog-overlay {
338
+ padding: 10px;
339
+ }
340
+ }
341
+
342
+ /* Mobile */
343
+ @media screen and (max-width: 709px) {
344
+ .sky-dialog-paper {
345
+ height: calc(100% - 142px);
346
+ max-height: calc(100% - 142px);
347
+ background-color: #fff;
348
+ margin: 0 10px 10px 10px;
349
+ border-radius: 5px;
350
+ max-width: 100vw !important;
351
+ }
352
+
353
+ /* Full height when no footer */
354
+ .sky-dialog-paper-no-footer {
355
+ height: calc(100% - 60px);
356
+ max-height: calc(100% - 60px);
357
+ }
358
+
359
+ .sky-dialog-footer {
360
+ transform: translateY(-6px);
361
+ }
362
+ }
363
+
364
+ @media screen and (max-width: 500px) {
365
+ .sky-dialog-subtitle {
366
+ display: block;
367
+ white-space: nowrap;
368
+ overflow: hidden;
369
+ text-overflow: ellipsis;
370
+ }
371
+
372
+ .sky-dialog-title-with-subtitle {
373
+ padding: 12px 24px !important;
374
+ }
375
+ }
376
+
377
+ @media screen and (max-width: 374px) {
378
+ .sky-dialog-subtitle {
379
+ font-size: 9pt;
380
+ }
381
+ }
382
+
383
+ /* iPhone safe area support */
384
+ @supports (padding-top: env(safe-area-inset-top)) {
385
+ .sky-dialog-paper {
386
+ height: calc(100% - 150px - env(safe-area-inset-top));
387
+ }
388
+
389
+ /* Full height when no footer */
390
+ .sky-dialog-paper-no-footer {
391
+ height: calc(100% - 60px - env(safe-area-inset-top));
392
+ }
393
+
394
+ .sky-dialog-footer {
395
+ padding-bottom: calc(env(safe-area-inset-bottom) + 8px);
396
+ }
397
+ }
398
+
399
+ /* Animations */
400
+ .sky-dialog-animate {
401
+ animation: sky-dialog-slide-in 0.4s ease-in-out;
402
+ }
403
+
404
+ .sky-dialog-footer-animate {
405
+ animation: sky-dialog-footer-in 0.4s ease-in-out;
406
+ }
407
+
408
+ @keyframes sky-dialog-slide-in {
409
+ 0% {
410
+ opacity: 0;
411
+ margin-top: -1600px;
412
+ }
413
+ 100% {
414
+ opacity: 1;
415
+ margin-top: 0;
416
+ }
417
+ }
418
+
419
+ @keyframes sky-dialog-footer-in {
420
+ 0% {
421
+ opacity: 0;
422
+ bottom: -100px;
423
+ }
424
+ 50% {
425
+ opacity: 0.25;
426
+ bottom: -50px;
427
+ }
428
+ 100% {
429
+ opacity: 1;
430
+ bottom: 15px;
431
+ }
432
+ }
433
+
434
+ /* Transition */
435
+ .dialog-slide-leave-active {
436
+ animation: sky-dialog-slide-in 0.4s reverse;
437
+ }
438
+ </style>