@sigmaott/base-library-next 2.2.6 → 2.2.7

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.
Files changed (63) hide show
  1. package/.npmrc +3 -0
  2. package/locales/en.yaml +289 -289
  3. package/locales/vi.yaml +294 -294
  4. package/nuxt.config.ts +18 -18
  5. package/package.json +32 -33
  6. package/public/routes.json +33 -33
  7. package/src/api/axios.ts +3 -3
  8. package/src/api/index.ts +86 -86
  9. package/src/api-client-library/.openapi-generator/FILES +20 -20
  10. package/src/api-client-library/.openapi-generator-ignore +23 -23
  11. package/src/api-client-library/api/health-api.ts +119 -119
  12. package/src/api-client-library/api/presets-api.ts +599 -599
  13. package/src/api-client-library/api/profiles-api.ts +676 -676
  14. package/src/api-client-library/api.ts +20 -20
  15. package/src/api-client-library/base.ts +72 -72
  16. package/src/api-client-library/common.ts +150 -150
  17. package/src/api-client-library/configuration.ts +101 -101
  18. package/src/api-client-library/git_push.sh +57 -57
  19. package/src/api-client-library/index.ts +18 -18
  20. package/src/api-client-library/models/create-preset-dto.ts +223 -223
  21. package/src/api-client-library/models/create-profile-dto.ts +45 -45
  22. package/src/api-client-library/models/health-controller-get-health200-response-info-value.ts +32 -32
  23. package/src/api-client-library/models/health-controller-get-health200-response.ts +51 -51
  24. package/src/api-client-library/models/health-controller-get-health503-response.ts +51 -51
  25. package/src/api-client-library/models/index.ts +7 -7
  26. package/src/api-client-library/models/update-preset-dto.ts +223 -223
  27. package/src/api-client-library/models/update-profile-dto.ts +45 -45
  28. package/src/components/MediaSelection.vue +40 -40
  29. package/src/components/PresetModify.vue +154 -154
  30. package/src/components/PresetTable.vue +114 -114
  31. package/src/components/ProfileAllList.vue +137 -137
  32. package/src/components/ProfileFormModal.vue +79 -79
  33. package/src/components/ProfileModify.vue +152 -152
  34. package/src/components/ProfileTable.vue +68 -68
  35. package/src/components/WatermarkDraggableItem.vue +88 -88
  36. package/src/components/channel/ConfigWatermarkItem.vue +239 -239
  37. package/src/components/channel/WatermarkPreview.vue +19 -19
  38. package/src/components/common/Vue3DraggableResizable/Container.vue +71 -71
  39. package/src/components/common/Vue3DraggableResizable/index.vue +1327 -1327
  40. package/src/components/common/Vue3DraggableResizable/utils/dom.js +63 -63
  41. package/src/components/common/Vue3DraggableResizable/utils/fns.js +37 -37
  42. package/src/components/common/VueDraggableResizable/dom.js +63 -63
  43. package/src/components/common/VueDraggableResizable/fns.js +37 -37
  44. package/src/components/common/VueDraggableResizable/index.vue +958 -958
  45. package/src/components/preset/ConfigItem.vue +956 -956
  46. package/src/components/profile/ConfigItem.vue +765 -765
  47. package/src/components/profile/TableColumns.vue +137 -137
  48. package/src/components/shared/AudioInfoViewer.vue +101 -101
  49. package/src/components/shared/MediaInfoViewer.vue +249 -249
  50. package/src/components/shared/MediaInfoViewerSmall.vue +111 -105
  51. package/src/components/shared/PopoverProfile.vue +17 -17
  52. package/src/components/shared/VideoInfoViewer.vue +136 -136
  53. package/src/components/shared/fileSizeFilter.ts +26 -26
  54. package/src/composables/preset.ts +141 -141
  55. package/src/public/build-time.json +1 -1
  56. package/src/public/favicon.svg +15 -15
  57. package/src/public/logo.svg +9 -9
  58. package/src/public/routes.json +86 -86
  59. package/src/utils/common.ts +175 -175
  60. package/src/utils/config.ts +19 -19
  61. package/src/utils/preset.ts +353 -353
  62. package/src/utils/profile.ts +30 -30
  63. package/tsconfig.json +3 -3
@@ -1,1327 +1,1327 @@
1
- <script setup>
2
- import { computed, inject, onMounted, ref, useSlots, watch } from 'vue'
3
- import {
4
- addEvent,
5
- getComputedSize,
6
- matchesSelectorToParentElements,
7
- removeEvent,
8
- } from './utils/dom'
9
- import {
10
- computeHeight,
11
- computeWidth,
12
- restrictToBounds,
13
- snapToGrid,
14
- } from './utils/fns'
15
-
16
- const props = defineProps({
17
- draggable: {
18
- type: Boolean,
19
- default: true,
20
- },
21
- resizable: {
22
- type: Boolean,
23
- default: true,
24
- },
25
- x: {
26
- type: Number,
27
- default: 0,
28
- },
29
- y: {
30
- type: Number,
31
- default: 0,
32
- },
33
- z: {
34
- type: [String, Number],
35
- default: 'auto',
36
- validator: val => (typeof val === 'string' ? val === 'auto' : val >= 0),
37
- },
38
- w: {
39
- type: [Number, String],
40
- // default: 200,
41
- validator: (val) => {
42
- if (typeof val === 'number')
43
- return val > 0
44
-
45
- return val === 'auto'
46
- },
47
- },
48
- h: {
49
- type: [Number, String],
50
- // default: 200,
51
- validator: (val) => {
52
- if (typeof val === 'number')
53
- return val > 0
54
-
55
- return val === 'auto'
56
- },
57
- },
58
- minWidth: {
59
- type: Number,
60
- default: 0,
61
- validator: val => val >= 0,
62
- },
63
- minHeight: {
64
- type: Number,
65
- default: 0,
66
- validator: val => val >= 0,
67
- },
68
- maxWidth: {
69
- type: Number,
70
- default: null,
71
- validator: val => val >= 0,
72
- },
73
- maxHeight: {
74
- type: Number,
75
- default: null,
76
- validator: val => val >= 0,
77
- },
78
- active: {
79
- type: Boolean,
80
- default: false,
81
- },
82
- preventDeactivation: {
83
- type: Boolean,
84
- default: false,
85
- },
86
- activeOnHover: {
87
- type: Boolean,
88
- default: false,
89
- },
90
- disableUserSelect: {
91
- type: Boolean,
92
- default: true,
93
- },
94
- enableNativeDrag: {
95
- type: Boolean,
96
- default: false,
97
- },
98
- lockAspectRatio: {
99
- type: Boolean,
100
- default: false,
101
- },
102
- handlesType: {
103
- type: String,
104
- default: 'handles',
105
- validator: val => ['handles', 'borders', 'custom'].includes(val),
106
- },
107
- handles: {
108
- type: Array,
109
- default: () => ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'],
110
- validator: (val) => {
111
- const s = new Set(['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'])
112
- return new Set(val.filter(h => s.has(h))).size === val.length
113
- },
114
- },
115
- handlesSize: {
116
- type: Number,
117
- default: 10,
118
- },
119
- handlesBorder: {
120
- type: String,
121
- default: '0.5px solid #bbb',
122
- },
123
- dragHandle: {
124
- type: String,
125
- default: null,
126
- },
127
- dragCancel: {
128
- type: String,
129
- default: null,
130
- },
131
- axis: {
132
- type: String,
133
- default: 'both',
134
- validator: val => ['x', 'y', 'both'].includes(val),
135
- },
136
- grid: {
137
- type: Array,
138
- // default: () => [1, 1],
139
- validator: val =>
140
- Array.isArray(val)
141
- && typeof val[0] === 'number'
142
- && typeof val[1] === 'number',
143
- },
144
- showGrid: {
145
- type: [Boolean, String],
146
- default: false,
147
- validator: val => [true, false, 'x', 'y', 'both'].includes(val),
148
- },
149
- gridColor: {
150
- type: String,
151
- default: 'rgba(0, 0, 0, 0.1)',
152
- },
153
- parent: {
154
- type: [Boolean, String],
155
- default: false,
156
- },
157
- scale: {
158
- type: [Number, Array],
159
- default: 1,
160
- validator: (val) => {
161
- if (typeof val === 'number')
162
- return val > 0
163
-
164
- return val.length === 2 && val[0] > 0 && val[1] > 0
165
- },
166
- },
167
- className: {
168
- type: String,
169
- default: 'drv',
170
- },
171
- classNameDraggable: {
172
- type: String,
173
- default: 'drv-draggable',
174
- },
175
- classNameResizable: {
176
- type: String,
177
- default: 'drv-resizable',
178
- },
179
- classNameDragging: {
180
- type: String,
181
- default: 'drv-dragging',
182
- },
183
- classNameResizing: {
184
- type: String,
185
- default: 'drv-resizing',
186
- },
187
- classNameActive: {
188
- type: String,
189
- default: 'drv-active',
190
- },
191
- classNameHandle: {
192
- type: String,
193
- default: 'drv-handle',
194
- },
195
- onDragStart: {
196
- type: Function,
197
- default: () => true,
198
- },
199
- onDrag: {
200
- type: Function,
201
- default: () => true,
202
- },
203
- onResizeStart: {
204
- type: Function,
205
- default: () => true,
206
- },
207
- onResize: {
208
- type: Function,
209
- default: () => true,
210
- },
211
- })
212
-
213
- const emit = defineEmits([
214
- 'update:x',
215
- 'update:y',
216
- 'update:w',
217
- 'update:h',
218
- 'update:active',
219
- 'resizing',
220
- 'resizestop',
221
- 'dragging',
222
- 'dragstop',
223
- 'activated',
224
- 'deactivated',
225
- ])
226
-
227
- const events = {
228
- mouse: {
229
- start: 'mousedown',
230
- move: 'mousemove',
231
- stop: 'mouseup',
232
- },
233
-
234
- touch: {
235
- start: 'touchstart',
236
- move: 'touchmove',
237
- stop: 'touchend',
238
- },
239
- }
240
-
241
- const userSelectNone = {
242
- userSelect: 'none',
243
- MozUserSelect: 'none',
244
- WebkitUserSelect: 'none',
245
- MsUserSelect: 'none',
246
- }
247
-
248
- const userSelectAuto = {
249
- userSelect: 'auto',
250
- MozUserSelect: 'auto',
251
- WebkitUserSelect: 'auto',
252
- MsUserSelect: 'auto',
253
- }
254
-
255
- let eventsFor = events.mouse
256
-
257
- const el = ref(null)
258
- const parentEl = ref(null)
259
- const noProps = ref({ h: 'auto', w: 'auto', active: false, x: 0, y: 0 })
260
- const slots = useSlots()
261
-
262
- const width = computed({
263
- get() {
264
- return props.w || noProps.value.w
265
- },
266
- set(value) {
267
- emit('update:w', value)
268
- noProps.value.w = value
269
- },
270
- })
271
-
272
- const height = computed({
273
- get() {
274
- return props.h || noProps.value.h
275
- },
276
- set(value) {
277
- emit('update:h', value)
278
- noProps.value.h = value
279
- },
280
- })
281
-
282
- const left = computed({
283
- get() {
284
- return props.x || noProps.value.x
285
- },
286
-
287
- set(value) {
288
- emit('update:x', value)
289
- noProps.value.x = value
290
- },
291
- })
292
-
293
- const top = computed({
294
- get() {
295
- return props.y || noProps.value.y
296
- },
297
- set(value) {
298
- emit('update:y', value)
299
- noProps.value.y = value
300
- },
301
- })
302
-
303
- const right = ref(null)
304
- const bottom = ref(null)
305
-
306
- const active = computed({
307
- get() {
308
- return props.active || noProps.value.active
309
- },
310
- set(value) {
311
- emit('update:active', value)
312
- noProps.value.active = value
313
- },
314
- })
315
- const handlesSize = computed(() => `${props.handlesSize}px`)
316
- const handlesHalfSize = computed(() => `${props.handlesSize / 2}px`)
317
- const handlesBorder = computed(() => props.handlesBorder)
318
-
319
- const widthTouched = ref(false)
320
- const heightTouched = ref(false)
321
-
322
- const aspectFactor = ref(null)
323
-
324
- const parentWidth = ref(null)
325
- const parentHeight = ref(null)
326
-
327
- const handle = ref(null)
328
- const resizing = ref(false)
329
- const dragging = ref(false)
330
- const dragEnable = ref(false)
331
- const resizeEnable = ref(false)
332
- const mouseClickPosition = ref(null)
333
- const bounds = ref(null)
334
-
335
- const style = computed(() => {
336
- return {
337
- transform: `translate(${left.value}px, ${top.value}px)`,
338
- width: computedWidth.value,
339
- height: computedHeight.value,
340
- zIndex: props.z,
341
- ...(dragging.value && props.disableUserSelect
342
- ? userSelectNone
343
- : userSelectAuto),
344
- }
345
- })
346
-
347
- const containerClass = inject('drvContainerClass', {})
348
-
349
- const parent = computed(() => {
350
- return containerClass.value ? `.${containerClass.value}` : props.parent
351
- })
352
-
353
- const containerGrid = inject('drvContainerGrid', {})
354
-
355
- const grid = computed(() => {
356
- if (!containerGrid || !containerGrid.value)
357
- return props.grid || [1, 1]
358
-
359
- return props.grid ? props.grid : containerGrid.value
360
- })
361
-
362
- const parentGridBackgroundStyle = computed(() => {
363
- const axisBg = {
364
- x: `linear-gradient(-90deg, ${props.gridColor} 1px, transparent 1px) 0px 0px / ${grid.value[0]}px ${grid.value[0]}px`,
365
- y: `linear-gradient(0deg, ${props.gridColor} 1px, transparent 1px) 0px 0px / ${grid.value[1]}px ${grid.value[1]}px`,
366
- }
367
-
368
- if (props.showGrid === 'x' || props.showGrid === 'y')
369
- return axisBg[props.showGrid]
370
-
371
- return props.showGrid ? `${axisBg.x}, ${axisBg.y}` : null
372
- })
373
-
374
- const actualHandles = computed(() => {
375
- if (!props.resizable)
376
- return []
377
-
378
- return props.handles
379
- })
380
-
381
- const computedWidth = computed(() => {
382
- if (width.value === 'auto') {
383
- if (!widthTouched.value)
384
- return 'auto'
385
- }
386
-
387
- return `${width.value}px`
388
- })
389
-
390
- const computedHeight = computed(() => {
391
- if (height.value === 'auto') {
392
- if (!heightTouched.value)
393
- return 'auto'
394
- }
395
-
396
- return `${height.value}px`
397
- })
398
- const minW = ref(props.minWidth)
399
- const minH = ref(props.minHeight)
400
- const maxW = ref(props.maxWidth)
401
- const maxH = ref(props.maxHeight)
402
-
403
- const resizingOnX = computed(() => {
404
- return (
405
- Boolean(handle.value)
406
- && (handle.value.includes('l') || handle.value.includes('r'))
407
- )
408
- })
409
-
410
- const resizingOnY = computed(() => {
411
- return (
412
- Boolean(handle.value)
413
- && (handle.value.includes('t') || handle.value.includes('b'))
414
- )
415
- })
416
-
417
- // const isCornerHandle = computed(() => {
418
- // return (
419
- // Boolean(handle.value) && ['tl', 'tr', 'br', 'bl'].includes(handle.value)
420
- // )
421
- // })
422
-
423
- // methods
424
- function resetBoundsAndMouseState() {
425
- mouseClickPosition.value = {
426
- mouseX: 0,
427
- mouseY: 0,
428
- x: 0,
429
- y: 0,
430
- w: 0,
431
- h: 0,
432
- }
433
-
434
- bounds.value = {
435
- minLeft: null,
436
- maxLeft: null,
437
- minRight: null,
438
- maxRight: null,
439
- minTop: null,
440
- maxTop: null,
441
- minBottom: null,
442
- maxBottom: null,
443
- }
444
- }
445
-
446
- function checkParentSize() {
447
- if (parent.value) {
448
- const [newParentWidth, newParentHeight] = getParentSize()
449
-
450
- parentWidth.value = newParentWidth
451
- parentHeight.value = newParentHeight
452
-
453
- right.value = parentWidth.value - width.value - left.value
454
- bottom.value = parentHeight.value - height.value - top.value
455
- }
456
- }
457
-
458
- function getParentSize() {
459
- if (parent.value) {
460
- const parentElement
461
- = typeof parent.value === 'string'
462
- ? el.value.closest(parent.value)
463
- : el.value.parentNode
464
- parentEl.value = parentElement
465
- const style = window.getComputedStyle(parentElement, null)
466
- return [
467
- parseInt(style.getPropertyValue('width'), 10),
468
- parseInt(style.getPropertyValue('height'), 10),
469
- ]
470
- }
471
-
472
- return [null, null]
473
- }
474
-
475
- function showParentGrid() {
476
- if (parent.value && props.showGrid) {
477
- if (!parentEl.value) {
478
- const parent
479
- = typeof parent.value === 'string'
480
- ? el.value.closest(parent.value)
481
- : el.value.parentNode
482
- parentEl.value = parent
483
- }
484
-
485
- parentEl.value.style.background = parentGridBackgroundStyle.value
486
- }
487
- }
488
-
489
- function elementTouchDown(e) {
490
- eventsFor = events.touch
491
- elementDown(e)
492
- }
493
-
494
- function elementMouseDown(e) {
495
- eventsFor = events.mouse
496
- elementDown(e)
497
- }
498
-
499
- function elementDown(e) {
500
- if (e instanceof MouseEvent && e.which !== 1)
501
- return
502
-
503
- const target = e.target || e.srcElement
504
-
505
- if (el.value.contains(target)) {
506
- if (props.onDragStart(e) === false)
507
- return
508
-
509
- if (
510
- (props.dragHandle
511
- && !matchesSelectorToParentElements(target, props.dragHandle, el.value))
512
- || (props.dragCancel
513
- && matchesSelectorToParentElements(target, props.dragCancel, el.value))
514
- ) {
515
- dragging.value = false
516
- return
517
- }
518
-
519
- if (!active.value) {
520
- active.value = true
521
- emit('activated')
522
- // emit('update:active', true)
523
- }
524
-
525
- if (props.draggable)
526
- dragEnable.value = true
527
-
528
- mouseClickPosition.value.mouseX = e.touches ? e.touches[0].pageX : e.pageX
529
- mouseClickPosition.value.mouseY = e.touches ? e.touches[0].pageY : e.pageY
530
- mouseClickPosition.value.left = left.value
531
- mouseClickPosition.value.right = right.value
532
- mouseClickPosition.value.top = top.value
533
- mouseClickPosition.value.bottom = bottom.value
534
-
535
- if (parent.value)
536
- bounds.value = calcDragLimits()
537
-
538
- addEvent(document.documentElement, eventsFor.move, move)
539
- addEvent(document.documentElement, eventsFor.stop, handleUp)
540
- }
541
- }
542
-
543
- function calcDragLimits() {
544
- return {
545
- minLeft: left.value % grid.value[0],
546
- maxLeft:
547
- Math.floor(
548
- (parentWidth.value - width.value - left.value) / grid.value[0],
549
- )
550
- * grid.value[0]
551
- + left.value,
552
-
553
- minRight: right.value % grid.value[0],
554
- maxRight:
555
- Math.floor(
556
- (parentWidth.value - width.value - right.value) / grid.value[0],
557
- )
558
- * grid.value[0]
559
- + right.value,
560
-
561
- minTop: top.value % grid.value[1],
562
- maxTop:
563
- Math.floor(
564
- (parentHeight.value - height.value - top.value) / grid.value[1],
565
- )
566
- * grid.value[1]
567
- + top.value,
568
- minBottom: bottom.value % grid.value[1],
569
- maxBottom:
570
- Math.floor(
571
- (parentHeight.value - height.value - bottom.value) / grid.value[1],
572
- )
573
- * grid.value[1]
574
- + bottom.value,
575
- }
576
- }
577
-
578
- function deselect(e) {
579
- const target = e.target || e.srcElement
580
-
581
- const regex = new RegExp(`${props.className}-([trmbl]{2})`, '')
582
- if (
583
- !el.value
584
- || (!el.value.contains(target) && !regex.test(target.className))
585
- ) {
586
- if (active.value && !props.preventDeactivation) {
587
- active.value = false
588
- emit('deactivated')
589
- // emit('update:active', false)
590
- }
591
-
592
- removeEvent(document.documentElement, eventsFor.move, handleResize)
593
- }
594
-
595
- resetBoundsAndMouseState()
596
- }
597
-
598
- function handleTouchDown(handle, e) {
599
- eventsFor = events.touch
600
- handleDown(handle, e)
601
- }
602
-
603
- function handleDown(handleEl, e) {
604
- if (e instanceof MouseEvent && e.which !== 1)
605
- return
606
-
607
- if (props.onResizeStart(handleEl, e) === false)
608
- return
609
-
610
- if (e.stopPropagation)
611
- e.stopPropagation()
612
-
613
- // Here we avoid a dangerous recursion by faking
614
-
615
- // corner handles as middle handles
616
-
617
- if (props.lockAspectRatio && !handleEl.includes('m'))
618
- handle.value = `m${handleEl.substring(1)}`
619
- else
620
- handle.value = handleEl
621
-
622
- resizeEnable.value = true
623
-
624
- mouseClickPosition.value.mouseX = e.touches ? e.touches[0].pageX : e.pageX
625
- mouseClickPosition.value.mouseY = e.touches ? e.touches[0].pageY : e.pageY
626
- mouseClickPosition.value.left = left.value
627
- mouseClickPosition.value.right = right.value
628
- mouseClickPosition.value.top = top.value
629
- mouseClickPosition.value.bottom = bottom.value
630
-
631
- bounds.value = calcResizeLimits()
632
-
633
- addEvent(document.documentElement, eventsFor.move, handleResize)
634
- addEvent(document.documentElement, eventsFor.stop, handleUp)
635
- }
636
-
637
- function calcResizeLimits() {
638
- const [gridX, gridY] = grid.value
639
-
640
- if (props.lockAspectRatio) {
641
- if (minW.value / minH.value > aspectFactor.value)
642
- minH.value = minW.value / aspectFactor.value
643
- else
644
- minW.value = aspectFactor.value * minH.value
645
-
646
- if (maxW.value && maxH.value) {
647
- maxW.value = Math.min(maxW.value, aspectFactor.value * maxH.value)
648
- maxH.value = Math.min(maxH.value, maxW.value / aspectFactor.value)
649
- }
650
- else if (maxW.value) {
651
- maxH.value = maxW.value / aspectFactor.value
652
- }
653
- else if (maxH.value) {
654
- maxW.value = aspectFactor.value * maxH.value
655
- }
656
- }
657
-
658
- maxW.value = maxW.value - (maxW.value % gridX)
659
- maxH.value = maxH.value - (maxH.value % gridY)
660
-
661
- const limits = {
662
- minLeft: null,
663
- maxLeft: null,
664
- minTop: null,
665
- maxTop: null,
666
- minRight: null,
667
- maxRight: null,
668
- minBottom: null,
669
- maxBottom: null,
670
- }
671
-
672
- if (parent.value) {
673
- limits.minLeft = left.value % gridX
674
- limits.maxLeft
675
- = left.value + Math.floor((width.value - minW.value) / gridX) * gridX
676
- limits.minTop = top.value % gridY
677
- limits.maxTop
678
- = top.value + Math.floor((height.value - minH.value) / gridY) * gridY
679
- limits.minRight = right.value % gridX
680
- limits.maxRight
681
- = right.value + Math.floor((width.value - minW.value) / gridX) * gridX
682
- limits.minBottom = bottom.value % gridY
683
- limits.maxBottom
684
- = bottom.value + Math.floor((height.value - minH.value) / gridY) * gridY
685
-
686
- if (maxW.value) {
687
- limits.minLeft = Math.max(
688
- limits.minLeft,
689
- parentWidth.value - right.value - maxW.value,
690
- )
691
-
692
- limits.minRight = Math.max(
693
- limits.minRight,
694
- parentWidth.value - left.value - maxW.value,
695
- )
696
- }
697
-
698
- if (maxH.value) {
699
- limits.minTop = Math.max(
700
- limits.minTop,
701
- parentHeight.value - bottom.value - maxH.value,
702
- )
703
-
704
- limits.minBottom = Math.max(
705
- limits.minBottom,
706
- parentHeight.value - top.value - maxH.value,
707
- )
708
- }
709
-
710
- if (props.lockAspectRatio) {
711
- limits.minLeft = Math.max(
712
- limits.minLeft,
713
- left.value - top.value * aspectFactor.value,
714
- )
715
- limits.minTop = Math.max(
716
- limits.minTop,
717
- top.value - left.value / aspectFactor.value,
718
- )
719
- limits.minRight = Math.max(
720
- limits.minRight,
721
- right.value - bottom.value * aspectFactor.value,
722
- )
723
- limits.minBottom = Math.max(
724
- limits.minBottom,
725
- bottom.value - right.value / aspectFactor.value,
726
- )
727
- }
728
- }
729
- else {
730
- limits.minLeft = null
731
- limits.maxLeft
732
- = left.value + Math.floor((width.value - minW.value) / gridX) * gridX
733
- limits.minTop = null
734
- limits.maxTop
735
- = top.value + Math.floor((height.value - minH.value) / gridY) * gridY
736
- limits.minRight = null
737
- limits.maxRight
738
- = right.value + Math.floor((width.value - minW.value) / gridX) * gridX
739
- limits.minBottom = null
740
- limits.maxBottom
741
- = bottom.value + Math.floor((height.value - minH.value) / gridY) * gridY
742
-
743
- if (maxW.value) {
744
- limits.minLeft = -(right.value + maxW.value)
745
- limits.minRight = -(left.value + maxW.value)
746
- }
747
-
748
- if (maxH.value) {
749
- limits.minTop = -(bottom.value + maxH.value)
750
- limits.minBottom = -(top.value + maxH.value)
751
- }
752
-
753
- if (props.lockAspectRatio && maxW.value && maxH.value) {
754
- limits.minLeft = Math.min(limits.minLeft, -(right.value + maxW.value))
755
- limits.minTop = Math.min(limits.minTop, -(maxH.value + bottom.value))
756
- limits.minRight = Math.min(limits.minRight, -left.value - maxW.value)
757
- limits.minBottom = Math.min(limits.minBottom, -top.value - maxH.value)
758
- }
759
- }
760
-
761
- return limits
762
- }
763
-
764
- function move(e) {
765
- if (resizing.value)
766
- handleResize(e)
767
- else if (dragEnable.value)
768
- handleDrag(e)
769
- }
770
- function handleDrag(e) {
771
- const tmpDeltaX
772
- = props.axis && props.axis !== 'y'
773
- ? mouseClickPosition.value.mouseX
774
- - (e.touches ? e.touches[0].pageX : e.pageX)
775
- : 0
776
-
777
- const tmpDeltaY
778
- = props.axis && props.axis !== 'x'
779
- ? mouseClickPosition.value.mouseY
780
- - (e.touches ? e.touches[0].pageY : e.pageY)
781
- : 0
782
-
783
- const [deltaX, deltaY] = snapToGrid(
784
- grid.value,
785
- tmpDeltaX,
786
- tmpDeltaY,
787
- props.scale,
788
- )
789
-
790
- const leftPx = restrictToBounds(
791
- mouseClickPosition.value.left - deltaX,
792
- bounds.value.minLeft,
793
- bounds.value.maxLeft,
794
- )
795
-
796
- const topPx = restrictToBounds(
797
- mouseClickPosition.value.top - deltaY,
798
- bounds.value.minTop,
799
- bounds.value.maxTop,
800
- )
801
-
802
- if (props.onDrag(left, top) === false)
803
- return
804
-
805
- const rightPx = restrictToBounds(
806
- mouseClickPosition.value.right + deltaX,
807
- bounds.value.minRight,
808
- bounds.value.maxRight,
809
- )
810
-
811
- const bottomPx = restrictToBounds(
812
- mouseClickPosition.value.bottom + deltaY,
813
- bounds.value.minBottom,
814
- bounds.value.maxBottom,
815
- )
816
-
817
- left.value = leftPx
818
- top.value = topPx
819
- right.value = rightPx
820
- bottom.value = bottomPx
821
-
822
- emit('dragging', left.value, top.value)
823
-
824
- dragging.value = true
825
- }
826
-
827
- function moveHorizontally(val) {
828
- // should calculate with scale 1.
829
-
830
- const [deltaX] = snapToGrid(grid.value, val, top.value, 1)
831
-
832
- const leftPx = restrictToBounds(
833
- deltaX,
834
- bounds.value.minLeft,
835
- bounds.value.maxLeft,
836
- )
837
-
838
- left.value = leftPx
839
- right.value = parentWidth.value - width.value - leftPx
840
- }
841
-
842
- function moveVertically(val) {
843
- // should calculate with scale 1.
844
-
845
- const [, deltaY] = snapToGrid(grid.value, left.value, val, 1)
846
-
847
- const topPx = restrictToBounds(
848
- deltaY,
849
- bounds.value.minTop,
850
- bounds.value.maxTop,
851
- )
852
-
853
- top.value = topPx
854
- bottom.value = parentHeight.value - height.value - topPx
855
- }
856
-
857
- function handleResize(e) {
858
- let leftPx = left.value
859
- let topPx = top.value
860
- let rightPx = right.value
861
- let bottomPx = bottom.value
862
-
863
- // const lockAspectRatio = props.lockAspectRatio
864
-
865
- const tmpDeltaX
866
- = mouseClickPosition.value.mouseX - (e.touches ? e.touches[0].pageX : e.pageX)
867
-
868
- const tmpDeltaY
869
- = mouseClickPosition.value.mouseY - (e.touches ? e.touches[0].pageY : e.pageY)
870
-
871
- if (!widthTouched.value && tmpDeltaX)
872
- widthTouched.value = true
873
-
874
- if (!heightTouched.value && tmpDeltaY)
875
- heightTouched.value = true
876
-
877
- const [deltaX, deltaY] = snapToGrid(
878
- grid.value,
879
- tmpDeltaX,
880
- tmpDeltaY,
881
- props.scale,
882
- )
883
-
884
- if (handle.value.includes('b')) {
885
- bottomPx = restrictToBounds(
886
- mouseClickPosition.value.bottom + deltaY,
887
- bounds.value.minBottom,
888
- bounds.value.maxBottom,
889
- )
890
-
891
- if (props.lockAspectRatio && resizingOnY)
892
- rightPx = right.value - (bottom.value - bottomPx) * aspectFactor.value
893
- }
894
- else if (handle.value.includes('t')) {
895
- topPx = restrictToBounds(
896
- mouseClickPosition.value.top - deltaY,
897
- bounds.value.minTop,
898
- bounds.value.maxTop,
899
- )
900
-
901
- if (props.lockAspectRatio && resizingOnY)
902
- leftPx = left.value - (top.value - topPx) * aspectFactor.value
903
- }
904
-
905
- if (handle.value.includes('r')) {
906
- rightPx = restrictToBounds(
907
- mouseClickPosition.value.right + deltaX,
908
- bounds.value.minRight,
909
- bounds.value.maxRight,
910
- )
911
-
912
- if (props.lockAspectRatio && resizingOnX)
913
- bottomPx = bottom.value - (right.value - rightPx) / aspectFactor.value
914
- }
915
- else if (handle.value.includes('l')) {
916
- leftPx = restrictToBounds(
917
- mouseClickPosition.value.left - deltaX,
918
- bounds.value.minLeft,
919
- bounds.value.maxLeft,
920
- )
921
-
922
- if (props.lockAspectRatio && resizingOnX)
923
- topPx = top.value - (left.value - leftPx) / aspectFactor.value
924
- }
925
-
926
- const widthPx = computeWidth(parentWidth.value, leftPx, rightPx)
927
-
928
- const heightPx = computeHeight(parentHeight.value, topPx, bottomPx)
929
-
930
- if (
931
- props.onResize(handle.value, leftPx, topPx, widthPx, heightPx) === false
932
- )
933
- return
934
-
935
- left.value = leftPx
936
- top.value = topPx
937
- right.value = rightPx
938
- bottom.value = bottomPx
939
- width.value = widthPx
940
- height.value = heightPx
941
-
942
- emit('resizing', left.value, top.value, width.value, height.value)
943
-
944
- resizing.value = true
945
- }
946
-
947
- function changeWidth(val) {
948
- // should calculate with scale 1.
949
-
950
- const [newWidth] = snapToGrid(grid.value, val, 0, 1)
951
-
952
- const rightPx = restrictToBounds(
953
- parentWidth.value - newWidth - left.value,
954
- bounds.value.minRight,
955
- bounds.value.maxRight,
956
- )
957
-
958
- let bottomPx = bottom.value
959
-
960
- if (props.lockAspectRatio)
961
- bottomPx = bottom.value - (right.value - rightPx) / aspectFactor.value
962
-
963
- const widthPx = computeWidth(parentWidth.value, left.value, rightPx)
964
- const heightPx = computeHeight(parentHeight.value, top.value, bottomPx)
965
-
966
- right.value = rightPx
967
- bottom.value = bottomPx
968
- width.value = widthPx
969
- height.value = heightPx
970
- }
971
-
972
- function changeHeight(val) {
973
- // should calculate with scale 1.
974
-
975
- const [, newHeight] = snapToGrid(grid.value, 0, val, 1)
976
-
977
- const bottomPx = restrictToBounds(
978
- parentHeight.value - newHeight - top.value,
979
- bounds.value.minBottom,
980
- bounds.value.maxBottom,
981
- )
982
-
983
- let rightPx = right.value
984
-
985
- if (props.lockAspectRatio)
986
- rightPx = right.value - (bottom.value - bottomPx) * aspectFactor.value
987
-
988
- const widthPx = computeWidth(parentWidth.value, left.value, rightPx)
989
-
990
- const heightPx = computeHeight(parentHeight.value, top.value, bottomPx)
991
-
992
- right.value = rightPx
993
- bottom.value = bottomPx
994
- width.value = widthPx
995
- height.value = heightPx
996
- }
997
-
998
- function handleUp() {
999
- handle.value = null
1000
-
1001
- resetBoundsAndMouseState()
1002
-
1003
- dragEnable.value = false
1004
- resizeEnable.value = false
1005
-
1006
- if (resizing.value) {
1007
- resizing.value = false
1008
-
1009
- emit('resizestop', left.value, top.value, width.value, height.value)
1010
- }
1011
-
1012
- if (dragging.value) {
1013
- dragging.value = false
1014
-
1015
- emit('dragstop', left.value, top.value)
1016
- }
1017
-
1018
- removeEvent(document.documentElement, eventsFor.move, handleResize)
1019
- }
1020
-
1021
- function elementMouseOver() {
1022
- if (props.activeOnHover)
1023
- active.value = true
1024
- }
1025
- function elementMouseLeave() {
1026
- if (props.activeOnHover && !dragging.value)
1027
- active.value = false
1028
- }
1029
-
1030
- onMounted(() => {
1031
- resetBoundsAndMouseState()
1032
-
1033
- if (!props.enableNativeDrag)
1034
- el.value.ondragstart = () => false
1035
-
1036
- const [parentWidthPx, parentHeightPx] = getParentSize()
1037
-
1038
- parentWidth.value = parentWidthPx
1039
- parentHeight.value = parentHeightPx
1040
-
1041
- const [widthPx, heightPx] = getComputedSize(el.value)
1042
-
1043
- aspectFactor.value
1044
- = (width.value !== 'auto' ? width.value : widthPx)
1045
- / (height.value !== 'auto' ? height.value : heightPx)
1046
-
1047
- width.value = width.value !== 'auto' ? width.value : widthPx
1048
- height.value = height.value !== 'auto' ? height.value : heightPx
1049
- right.value = parentWidth.value - width.value - left.value
1050
- bottom.value = parentHeight.value - height.value - top.value
1051
-
1052
- if (active.value)
1053
- emit('activated')
1054
-
1055
- if (props.showGrid)
1056
- showParentGrid()
1057
-
1058
- addEvent(document.documentElement, 'mousedown', deselect)
1059
- addEvent(document.documentElement, 'touchend touchcancel', deselect)
1060
- addEvent(window, 'resize', checkParentSize)
1061
-
1062
- nextTick(() => {
1063
- checkParentSize()
1064
- })
1065
- })
1066
-
1067
- watch(
1068
- () => props.x,
1069
- (val) => {
1070
- if (resizing.value || dragging.value)
1071
- return
1072
-
1073
- if (parent.value)
1074
- bounds.value = calcDragLimits()
1075
-
1076
- moveHorizontally(val)
1077
- },
1078
- )
1079
-
1080
- watch(
1081
- () => props.y,
1082
- (val) => {
1083
- if (resizing.value || dragging.value)
1084
- return
1085
-
1086
- if (parent.value)
1087
- bounds.value = calcDragLimits()
1088
-
1089
- moveVertically(val)
1090
- },
1091
- )
1092
-
1093
- watch(
1094
- () => props.lockAspectRatio,
1095
- (val) => {
1096
- if (val)
1097
- aspectFactor.value = width.value / height.value
1098
- else
1099
- aspectFactor.value = undefined
1100
- },
1101
- )
1102
-
1103
- watch(
1104
- () => props.w,
1105
- (val) => {
1106
- if (resizing.value || dragging.value)
1107
- return
1108
-
1109
- if (parent.value)
1110
- bounds.value = calcResizeLimits()
1111
-
1112
- changeWidth(val)
1113
- },
1114
- )
1115
-
1116
- watch(
1117
- () => props.h,
1118
- (val) => {
1119
- if (resizing.value || dragging.value)
1120
- return
1121
-
1122
- if (parent.value)
1123
- bounds.value = calcResizeLimits()
1124
-
1125
- changeHeight(val)
1126
- },
1127
- )
1128
-
1129
- watch(
1130
- () => props.showGrid,
1131
- () => {
1132
- showParentGrid()
1133
- },
1134
- )
1135
-
1136
- watch(
1137
- () => props.grid,
1138
- () => {
1139
- showParentGrid()
1140
- },
1141
- )
1142
- </script>
1143
-
1144
- <template>
1145
- <div
1146
- ref="el"
1147
- :style="style"
1148
- :class="[
1149
- {
1150
- [classNameActive]: active,
1151
- [classNameDragging]: dragging,
1152
- [classNameResizing]: resizing,
1153
- [classNameDraggable]: draggable,
1154
- [classNameResizable]: resizable,
1155
- },
1156
- className,
1157
- ]"
1158
- @mousedown="elementMouseDown"
1159
- @touchstart="elementTouchDown"
1160
- @mouseover="elementMouseOver"
1161
- @mouseleave="elementMouseLeave"
1162
- >
1163
- <div :class="`drv-${handlesType}`">
1164
- <div
1165
- v-for="handleEl in actualHandles"
1166
- :key="handleEl"
1167
- :class="[
1168
- classNameHandle,
1169
- `${classNameHandle}-${handleEl}`,
1170
- classNameHandle !== 'drv-handle' ? 'drv-handle' : '',
1171
- classNameHandle !== 'drv-handle' ? `drv-handle` + `-${handleEl}` : '',
1172
- ]"
1173
- :style="{
1174
- display: active ? 'block' : 'none',
1175
- }"
1176
- @mousedown.stop.prevent="handleDown(handleEl, $event)"
1177
- @touchstart.stop.prevent="handleTouchDown(handleEl, $event)"
1178
- >
1179
- <slot
1180
- v-if="slots[`handle-${handleEl}`]"
1181
- :name="`handle-${handleEl}`"
1182
- />
1183
- <slot v-if="!slots[`handle-${handleEl}`]" name="handle" />
1184
- </div>
1185
- </div>
1186
- <slot />
1187
- </div>
1188
- </template>
1189
-
1190
- <style>
1191
- .drv {
1192
- touch-action: none;
1193
- position: absolute;
1194
- box-sizing: border-box;
1195
- border: 1px dashed gray;
1196
- }
1197
-
1198
- .drv-handles .drv-handle {
1199
- box-sizing: border-box;
1200
- position: absolute;
1201
- min-width: v-bind(handlesSize);
1202
- min-height: v-bind(handlesSize);
1203
- border: v-bind(handlesBorder);
1204
- }
1205
-
1206
- .drv-handles .drv-handle-tl {
1207
- transform: translate(-100%, -100%);
1208
- top: 0;
1209
- left: 0;
1210
- cursor: nw-resize;
1211
- }
1212
-
1213
- .drv-handles .drv-handle-tm {
1214
- transform: translate(-50%, -100%);
1215
- top: 0;
1216
- left: 50%;
1217
- cursor: n-resize;
1218
- }
1219
-
1220
- .drv-handles .drv-handle-tr {
1221
- transform: translate(100%, -100%);
1222
- top: 0;
1223
- right: 0;
1224
- cursor: ne-resize;
1225
- }
1226
-
1227
- .drv-handles .drv-handle-ml {
1228
- transform: translate(-100%, -50%);
1229
- top: 50%;
1230
- left: 0;
1231
- cursor: w-resize;
1232
- }
1233
-
1234
- .drv-handles .drv-handle-mr {
1235
- transform: translate(100%, -50%);
1236
- top: 50%;
1237
- right: 0;
1238
- cursor: e-resize;
1239
- }
1240
-
1241
- .drv-handles .drv-handle-bl {
1242
- transform: translate(-100%, 100%);
1243
- bottom: 0;
1244
- left: 0;
1245
- cursor: sw-resize;
1246
- }
1247
-
1248
- .drv-handles .drv-handle-bm {
1249
- transform: translate(-50%, 100%);
1250
- bottom: 0;
1251
- left: 50%;
1252
- cursor: s-resize;
1253
- }
1254
-
1255
- .drv-handles .drv-handle-br {
1256
- transform: translate(100%, 100%);
1257
- bottom: 0;
1258
- right: 0;
1259
- cursor: se-resize;
1260
- }
1261
-
1262
- .drv-borders .drv-handle {
1263
- box-sizing: border-box;
1264
- position: absolute;
1265
- min-width: v-bind(handlesSize);
1266
- min-height: v-bind(handlesSize);
1267
- }
1268
-
1269
- .drv-borders .drv-handle-tl {
1270
- transform: translate(-50%, -50%);
1271
- top: 0;
1272
- left: 0;
1273
- cursor: nw-resize;
1274
- }
1275
- .drv-borders .drv-handle-tm {
1276
- transform: translate(0, -50%);
1277
- left: v-bind(handlesHalfSize);
1278
- width: calc(100% - v-bind(handlesSize));
1279
- top: 0;
1280
- cursor: n-resize;
1281
- }
1282
-
1283
- .drv-borders .drv-handle-tr {
1284
- transform: translate(50%, -50%);
1285
- top: 0;
1286
- right: 0;
1287
- cursor: ne-resize;
1288
- }
1289
-
1290
- .drv-borders .drv-handle-ml {
1291
- transform: translate(-50%, 0);
1292
- top: v-bind(handlesHalfSize);
1293
- height: calc(100% - v-bind(handlesSize));
1294
- left: 0;
1295
- cursor: w-resize;
1296
- }
1297
-
1298
- .drv-borders .drv-handle-bl {
1299
- transform: translate(-50%, 50%);
1300
- bottom: 0;
1301
- left: 0;
1302
- cursor: sw-resize;
1303
- }
1304
-
1305
- .drv-borders .drv-handle-bm {
1306
- transform: translate(0, 50%);
1307
- left: v-bind(handlesHalfSize);
1308
- width: calc(100% - v-bind(handlesSize));
1309
- bottom: 0;
1310
- cursor: s-resize;
1311
- }
1312
-
1313
- .drv-borders .drv-handle-br {
1314
- transform: translate(50%, 50%);
1315
- bottom: 0;
1316
- right: 0;
1317
- cursor: se-resize;
1318
- }
1319
-
1320
- .drv-borders .drv-handle-mr {
1321
- transform: translate(50%, 0);
1322
- top: v-bind(handlesHalfSize);
1323
- height: calc(100% - v-bind(handlesSize));
1324
- right: 0;
1325
- cursor: e-resize;
1326
- }
1327
- </style>
1
+ <script setup>
2
+ import { computed, inject, onMounted, ref, useSlots, watch } from 'vue'
3
+ import {
4
+ addEvent,
5
+ getComputedSize,
6
+ matchesSelectorToParentElements,
7
+ removeEvent,
8
+ } from './utils/dom'
9
+ import {
10
+ computeHeight,
11
+ computeWidth,
12
+ restrictToBounds,
13
+ snapToGrid,
14
+ } from './utils/fns'
15
+
16
+ const props = defineProps({
17
+ draggable: {
18
+ type: Boolean,
19
+ default: true,
20
+ },
21
+ resizable: {
22
+ type: Boolean,
23
+ default: true,
24
+ },
25
+ x: {
26
+ type: Number,
27
+ default: 0,
28
+ },
29
+ y: {
30
+ type: Number,
31
+ default: 0,
32
+ },
33
+ z: {
34
+ type: [String, Number],
35
+ default: 'auto',
36
+ validator: val => (typeof val === 'string' ? val === 'auto' : val >= 0),
37
+ },
38
+ w: {
39
+ type: [Number, String],
40
+ // default: 200,
41
+ validator: (val) => {
42
+ if (typeof val === 'number')
43
+ return val > 0
44
+
45
+ return val === 'auto'
46
+ },
47
+ },
48
+ h: {
49
+ type: [Number, String],
50
+ // default: 200,
51
+ validator: (val) => {
52
+ if (typeof val === 'number')
53
+ return val > 0
54
+
55
+ return val === 'auto'
56
+ },
57
+ },
58
+ minWidth: {
59
+ type: Number,
60
+ default: 0,
61
+ validator: val => val >= 0,
62
+ },
63
+ minHeight: {
64
+ type: Number,
65
+ default: 0,
66
+ validator: val => val >= 0,
67
+ },
68
+ maxWidth: {
69
+ type: Number,
70
+ default: null,
71
+ validator: val => val >= 0,
72
+ },
73
+ maxHeight: {
74
+ type: Number,
75
+ default: null,
76
+ validator: val => val >= 0,
77
+ },
78
+ active: {
79
+ type: Boolean,
80
+ default: false,
81
+ },
82
+ preventDeactivation: {
83
+ type: Boolean,
84
+ default: false,
85
+ },
86
+ activeOnHover: {
87
+ type: Boolean,
88
+ default: false,
89
+ },
90
+ disableUserSelect: {
91
+ type: Boolean,
92
+ default: true,
93
+ },
94
+ enableNativeDrag: {
95
+ type: Boolean,
96
+ default: false,
97
+ },
98
+ lockAspectRatio: {
99
+ type: Boolean,
100
+ default: false,
101
+ },
102
+ handlesType: {
103
+ type: String,
104
+ default: 'handles',
105
+ validator: val => ['handles', 'borders', 'custom'].includes(val),
106
+ },
107
+ handles: {
108
+ type: Array,
109
+ default: () => ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'],
110
+ validator: (val) => {
111
+ const s = new Set(['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'])
112
+ return new Set(val.filter(h => s.has(h))).size === val.length
113
+ },
114
+ },
115
+ handlesSize: {
116
+ type: Number,
117
+ default: 10,
118
+ },
119
+ handlesBorder: {
120
+ type: String,
121
+ default: '0.5px solid #bbb',
122
+ },
123
+ dragHandle: {
124
+ type: String,
125
+ default: null,
126
+ },
127
+ dragCancel: {
128
+ type: String,
129
+ default: null,
130
+ },
131
+ axis: {
132
+ type: String,
133
+ default: 'both',
134
+ validator: val => ['x', 'y', 'both'].includes(val),
135
+ },
136
+ grid: {
137
+ type: Array,
138
+ // default: () => [1, 1],
139
+ validator: val =>
140
+ Array.isArray(val)
141
+ && typeof val[0] === 'number'
142
+ && typeof val[1] === 'number',
143
+ },
144
+ showGrid: {
145
+ type: [Boolean, String],
146
+ default: false,
147
+ validator: val => [true, false, 'x', 'y', 'both'].includes(val),
148
+ },
149
+ gridColor: {
150
+ type: String,
151
+ default: 'rgba(0, 0, 0, 0.1)',
152
+ },
153
+ parent: {
154
+ type: [Boolean, String],
155
+ default: false,
156
+ },
157
+ scale: {
158
+ type: [Number, Array],
159
+ default: 1,
160
+ validator: (val) => {
161
+ if (typeof val === 'number')
162
+ return val > 0
163
+
164
+ return val.length === 2 && val[0] > 0 && val[1] > 0
165
+ },
166
+ },
167
+ className: {
168
+ type: String,
169
+ default: 'drv',
170
+ },
171
+ classNameDraggable: {
172
+ type: String,
173
+ default: 'drv-draggable',
174
+ },
175
+ classNameResizable: {
176
+ type: String,
177
+ default: 'drv-resizable',
178
+ },
179
+ classNameDragging: {
180
+ type: String,
181
+ default: 'drv-dragging',
182
+ },
183
+ classNameResizing: {
184
+ type: String,
185
+ default: 'drv-resizing',
186
+ },
187
+ classNameActive: {
188
+ type: String,
189
+ default: 'drv-active',
190
+ },
191
+ classNameHandle: {
192
+ type: String,
193
+ default: 'drv-handle',
194
+ },
195
+ onDragStart: {
196
+ type: Function,
197
+ default: () => true,
198
+ },
199
+ onDrag: {
200
+ type: Function,
201
+ default: () => true,
202
+ },
203
+ onResizeStart: {
204
+ type: Function,
205
+ default: () => true,
206
+ },
207
+ onResize: {
208
+ type: Function,
209
+ default: () => true,
210
+ },
211
+ })
212
+
213
+ const emit = defineEmits([
214
+ 'update:x',
215
+ 'update:y',
216
+ 'update:w',
217
+ 'update:h',
218
+ 'update:active',
219
+ 'resizing',
220
+ 'resizestop',
221
+ 'dragging',
222
+ 'dragstop',
223
+ 'activated',
224
+ 'deactivated',
225
+ ])
226
+
227
+ const events = {
228
+ mouse: {
229
+ start: 'mousedown',
230
+ move: 'mousemove',
231
+ stop: 'mouseup',
232
+ },
233
+
234
+ touch: {
235
+ start: 'touchstart',
236
+ move: 'touchmove',
237
+ stop: 'touchend',
238
+ },
239
+ }
240
+
241
+ const userSelectNone = {
242
+ userSelect: 'none',
243
+ MozUserSelect: 'none',
244
+ WebkitUserSelect: 'none',
245
+ MsUserSelect: 'none',
246
+ }
247
+
248
+ const userSelectAuto = {
249
+ userSelect: 'auto',
250
+ MozUserSelect: 'auto',
251
+ WebkitUserSelect: 'auto',
252
+ MsUserSelect: 'auto',
253
+ }
254
+
255
+ let eventsFor = events.mouse
256
+
257
+ const el = ref(null)
258
+ const parentEl = ref(null)
259
+ const noProps = ref({ h: 'auto', w: 'auto', active: false, x: 0, y: 0 })
260
+ const slots = useSlots()
261
+
262
+ const width = computed({
263
+ get() {
264
+ return props.w || noProps.value.w
265
+ },
266
+ set(value) {
267
+ emit('update:w', value)
268
+ noProps.value.w = value
269
+ },
270
+ })
271
+
272
+ const height = computed({
273
+ get() {
274
+ return props.h || noProps.value.h
275
+ },
276
+ set(value) {
277
+ emit('update:h', value)
278
+ noProps.value.h = value
279
+ },
280
+ })
281
+
282
+ const left = computed({
283
+ get() {
284
+ return props.x || noProps.value.x
285
+ },
286
+
287
+ set(value) {
288
+ emit('update:x', value)
289
+ noProps.value.x = value
290
+ },
291
+ })
292
+
293
+ const top = computed({
294
+ get() {
295
+ return props.y || noProps.value.y
296
+ },
297
+ set(value) {
298
+ emit('update:y', value)
299
+ noProps.value.y = value
300
+ },
301
+ })
302
+
303
+ const right = ref(null)
304
+ const bottom = ref(null)
305
+
306
+ const active = computed({
307
+ get() {
308
+ return props.active || noProps.value.active
309
+ },
310
+ set(value) {
311
+ emit('update:active', value)
312
+ noProps.value.active = value
313
+ },
314
+ })
315
+ const handlesSize = computed(() => `${props.handlesSize}px`)
316
+ const handlesHalfSize = computed(() => `${props.handlesSize / 2}px`)
317
+ const handlesBorder = computed(() => props.handlesBorder)
318
+
319
+ const widthTouched = ref(false)
320
+ const heightTouched = ref(false)
321
+
322
+ const aspectFactor = ref(null)
323
+
324
+ const parentWidth = ref(null)
325
+ const parentHeight = ref(null)
326
+
327
+ const handle = ref(null)
328
+ const resizing = ref(false)
329
+ const dragging = ref(false)
330
+ const dragEnable = ref(false)
331
+ const resizeEnable = ref(false)
332
+ const mouseClickPosition = ref(null)
333
+ const bounds = ref(null)
334
+
335
+ const style = computed(() => {
336
+ return {
337
+ transform: `translate(${left.value}px, ${top.value}px)`,
338
+ width: computedWidth.value,
339
+ height: computedHeight.value,
340
+ zIndex: props.z,
341
+ ...(dragging.value && props.disableUserSelect
342
+ ? userSelectNone
343
+ : userSelectAuto),
344
+ }
345
+ })
346
+
347
+ const containerClass = inject('drvContainerClass', {})
348
+
349
+ const parent = computed(() => {
350
+ return containerClass.value ? `.${containerClass.value}` : props.parent
351
+ })
352
+
353
+ const containerGrid = inject('drvContainerGrid', {})
354
+
355
+ const grid = computed(() => {
356
+ if (!containerGrid || !containerGrid.value)
357
+ return props.grid || [1, 1]
358
+
359
+ return props.grid ? props.grid : containerGrid.value
360
+ })
361
+
362
+ const parentGridBackgroundStyle = computed(() => {
363
+ const axisBg = {
364
+ x: `linear-gradient(-90deg, ${props.gridColor} 1px, transparent 1px) 0px 0px / ${grid.value[0]}px ${grid.value[0]}px`,
365
+ y: `linear-gradient(0deg, ${props.gridColor} 1px, transparent 1px) 0px 0px / ${grid.value[1]}px ${grid.value[1]}px`,
366
+ }
367
+
368
+ if (props.showGrid === 'x' || props.showGrid === 'y')
369
+ return axisBg[props.showGrid]
370
+
371
+ return props.showGrid ? `${axisBg.x}, ${axisBg.y}` : null
372
+ })
373
+
374
+ const actualHandles = computed(() => {
375
+ if (!props.resizable)
376
+ return []
377
+
378
+ return props.handles
379
+ })
380
+
381
+ const computedWidth = computed(() => {
382
+ if (width.value === 'auto') {
383
+ if (!widthTouched.value)
384
+ return 'auto'
385
+ }
386
+
387
+ return `${width.value}px`
388
+ })
389
+
390
+ const computedHeight = computed(() => {
391
+ if (height.value === 'auto') {
392
+ if (!heightTouched.value)
393
+ return 'auto'
394
+ }
395
+
396
+ return `${height.value}px`
397
+ })
398
+ const minW = ref(props.minWidth)
399
+ const minH = ref(props.minHeight)
400
+ const maxW = ref(props.maxWidth)
401
+ const maxH = ref(props.maxHeight)
402
+
403
+ const resizingOnX = computed(() => {
404
+ return (
405
+ Boolean(handle.value)
406
+ && (handle.value.includes('l') || handle.value.includes('r'))
407
+ )
408
+ })
409
+
410
+ const resizingOnY = computed(() => {
411
+ return (
412
+ Boolean(handle.value)
413
+ && (handle.value.includes('t') || handle.value.includes('b'))
414
+ )
415
+ })
416
+
417
+ // const isCornerHandle = computed(() => {
418
+ // return (
419
+ // Boolean(handle.value) && ['tl', 'tr', 'br', 'bl'].includes(handle.value)
420
+ // )
421
+ // })
422
+
423
+ // methods
424
+ function resetBoundsAndMouseState() {
425
+ mouseClickPosition.value = {
426
+ mouseX: 0,
427
+ mouseY: 0,
428
+ x: 0,
429
+ y: 0,
430
+ w: 0,
431
+ h: 0,
432
+ }
433
+
434
+ bounds.value = {
435
+ minLeft: null,
436
+ maxLeft: null,
437
+ minRight: null,
438
+ maxRight: null,
439
+ minTop: null,
440
+ maxTop: null,
441
+ minBottom: null,
442
+ maxBottom: null,
443
+ }
444
+ }
445
+
446
+ function checkParentSize() {
447
+ if (parent.value) {
448
+ const [newParentWidth, newParentHeight] = getParentSize()
449
+
450
+ parentWidth.value = newParentWidth
451
+ parentHeight.value = newParentHeight
452
+
453
+ right.value = parentWidth.value - width.value - left.value
454
+ bottom.value = parentHeight.value - height.value - top.value
455
+ }
456
+ }
457
+
458
+ function getParentSize() {
459
+ if (parent.value) {
460
+ const parentElement
461
+ = typeof parent.value === 'string'
462
+ ? el.value.closest(parent.value)
463
+ : el.value.parentNode
464
+ parentEl.value = parentElement
465
+ const style = window.getComputedStyle(parentElement, null)
466
+ return [
467
+ parseInt(style.getPropertyValue('width'), 10),
468
+ parseInt(style.getPropertyValue('height'), 10),
469
+ ]
470
+ }
471
+
472
+ return [null, null]
473
+ }
474
+
475
+ function showParentGrid() {
476
+ if (parent.value && props.showGrid) {
477
+ if (!parentEl.value) {
478
+ const parent
479
+ = typeof parent.value === 'string'
480
+ ? el.value.closest(parent.value)
481
+ : el.value.parentNode
482
+ parentEl.value = parent
483
+ }
484
+
485
+ parentEl.value.style.background = parentGridBackgroundStyle.value
486
+ }
487
+ }
488
+
489
+ function elementTouchDown(e) {
490
+ eventsFor = events.touch
491
+ elementDown(e)
492
+ }
493
+
494
+ function elementMouseDown(e) {
495
+ eventsFor = events.mouse
496
+ elementDown(e)
497
+ }
498
+
499
+ function elementDown(e) {
500
+ if (e instanceof MouseEvent && e.which !== 1)
501
+ return
502
+
503
+ const target = e.target || e.srcElement
504
+
505
+ if (el.value.contains(target)) {
506
+ if (props.onDragStart(e) === false)
507
+ return
508
+
509
+ if (
510
+ (props.dragHandle
511
+ && !matchesSelectorToParentElements(target, props.dragHandle, el.value))
512
+ || (props.dragCancel
513
+ && matchesSelectorToParentElements(target, props.dragCancel, el.value))
514
+ ) {
515
+ dragging.value = false
516
+ return
517
+ }
518
+
519
+ if (!active.value) {
520
+ active.value = true
521
+ emit('activated')
522
+ // emit('update:active', true)
523
+ }
524
+
525
+ if (props.draggable)
526
+ dragEnable.value = true
527
+
528
+ mouseClickPosition.value.mouseX = e.touches ? e.touches[0].pageX : e.pageX
529
+ mouseClickPosition.value.mouseY = e.touches ? e.touches[0].pageY : e.pageY
530
+ mouseClickPosition.value.left = left.value
531
+ mouseClickPosition.value.right = right.value
532
+ mouseClickPosition.value.top = top.value
533
+ mouseClickPosition.value.bottom = bottom.value
534
+
535
+ if (parent.value)
536
+ bounds.value = calcDragLimits()
537
+
538
+ addEvent(document.documentElement, eventsFor.move, move)
539
+ addEvent(document.documentElement, eventsFor.stop, handleUp)
540
+ }
541
+ }
542
+
543
+ function calcDragLimits() {
544
+ return {
545
+ minLeft: left.value % grid.value[0],
546
+ maxLeft:
547
+ Math.floor(
548
+ (parentWidth.value - width.value - left.value) / grid.value[0],
549
+ )
550
+ * grid.value[0]
551
+ + left.value,
552
+
553
+ minRight: right.value % grid.value[0],
554
+ maxRight:
555
+ Math.floor(
556
+ (parentWidth.value - width.value - right.value) / grid.value[0],
557
+ )
558
+ * grid.value[0]
559
+ + right.value,
560
+
561
+ minTop: top.value % grid.value[1],
562
+ maxTop:
563
+ Math.floor(
564
+ (parentHeight.value - height.value - top.value) / grid.value[1],
565
+ )
566
+ * grid.value[1]
567
+ + top.value,
568
+ minBottom: bottom.value % grid.value[1],
569
+ maxBottom:
570
+ Math.floor(
571
+ (parentHeight.value - height.value - bottom.value) / grid.value[1],
572
+ )
573
+ * grid.value[1]
574
+ + bottom.value,
575
+ }
576
+ }
577
+
578
+ function deselect(e) {
579
+ const target = e.target || e.srcElement
580
+
581
+ const regex = new RegExp(`${props.className}-([trmbl]{2})`, '')
582
+ if (
583
+ !el.value
584
+ || (!el.value.contains(target) && !regex.test(target.className))
585
+ ) {
586
+ if (active.value && !props.preventDeactivation) {
587
+ active.value = false
588
+ emit('deactivated')
589
+ // emit('update:active', false)
590
+ }
591
+
592
+ removeEvent(document.documentElement, eventsFor.move, handleResize)
593
+ }
594
+
595
+ resetBoundsAndMouseState()
596
+ }
597
+
598
+ function handleTouchDown(handle, e) {
599
+ eventsFor = events.touch
600
+ handleDown(handle, e)
601
+ }
602
+
603
+ function handleDown(handleEl, e) {
604
+ if (e instanceof MouseEvent && e.which !== 1)
605
+ return
606
+
607
+ if (props.onResizeStart(handleEl, e) === false)
608
+ return
609
+
610
+ if (e.stopPropagation)
611
+ e.stopPropagation()
612
+
613
+ // Here we avoid a dangerous recursion by faking
614
+
615
+ // corner handles as middle handles
616
+
617
+ if (props.lockAspectRatio && !handleEl.includes('m'))
618
+ handle.value = `m${handleEl.substring(1)}`
619
+ else
620
+ handle.value = handleEl
621
+
622
+ resizeEnable.value = true
623
+
624
+ mouseClickPosition.value.mouseX = e.touches ? e.touches[0].pageX : e.pageX
625
+ mouseClickPosition.value.mouseY = e.touches ? e.touches[0].pageY : e.pageY
626
+ mouseClickPosition.value.left = left.value
627
+ mouseClickPosition.value.right = right.value
628
+ mouseClickPosition.value.top = top.value
629
+ mouseClickPosition.value.bottom = bottom.value
630
+
631
+ bounds.value = calcResizeLimits()
632
+
633
+ addEvent(document.documentElement, eventsFor.move, handleResize)
634
+ addEvent(document.documentElement, eventsFor.stop, handleUp)
635
+ }
636
+
637
+ function calcResizeLimits() {
638
+ const [gridX, gridY] = grid.value
639
+
640
+ if (props.lockAspectRatio) {
641
+ if (minW.value / minH.value > aspectFactor.value)
642
+ minH.value = minW.value / aspectFactor.value
643
+ else
644
+ minW.value = aspectFactor.value * minH.value
645
+
646
+ if (maxW.value && maxH.value) {
647
+ maxW.value = Math.min(maxW.value, aspectFactor.value * maxH.value)
648
+ maxH.value = Math.min(maxH.value, maxW.value / aspectFactor.value)
649
+ }
650
+ else if (maxW.value) {
651
+ maxH.value = maxW.value / aspectFactor.value
652
+ }
653
+ else if (maxH.value) {
654
+ maxW.value = aspectFactor.value * maxH.value
655
+ }
656
+ }
657
+
658
+ maxW.value = maxW.value - (maxW.value % gridX)
659
+ maxH.value = maxH.value - (maxH.value % gridY)
660
+
661
+ const limits = {
662
+ minLeft: null,
663
+ maxLeft: null,
664
+ minTop: null,
665
+ maxTop: null,
666
+ minRight: null,
667
+ maxRight: null,
668
+ minBottom: null,
669
+ maxBottom: null,
670
+ }
671
+
672
+ if (parent.value) {
673
+ limits.minLeft = left.value % gridX
674
+ limits.maxLeft
675
+ = left.value + Math.floor((width.value - minW.value) / gridX) * gridX
676
+ limits.minTop = top.value % gridY
677
+ limits.maxTop
678
+ = top.value + Math.floor((height.value - minH.value) / gridY) * gridY
679
+ limits.minRight = right.value % gridX
680
+ limits.maxRight
681
+ = right.value + Math.floor((width.value - minW.value) / gridX) * gridX
682
+ limits.minBottom = bottom.value % gridY
683
+ limits.maxBottom
684
+ = bottom.value + Math.floor((height.value - minH.value) / gridY) * gridY
685
+
686
+ if (maxW.value) {
687
+ limits.minLeft = Math.max(
688
+ limits.minLeft,
689
+ parentWidth.value - right.value - maxW.value,
690
+ )
691
+
692
+ limits.minRight = Math.max(
693
+ limits.minRight,
694
+ parentWidth.value - left.value - maxW.value,
695
+ )
696
+ }
697
+
698
+ if (maxH.value) {
699
+ limits.minTop = Math.max(
700
+ limits.minTop,
701
+ parentHeight.value - bottom.value - maxH.value,
702
+ )
703
+
704
+ limits.minBottom = Math.max(
705
+ limits.minBottom,
706
+ parentHeight.value - top.value - maxH.value,
707
+ )
708
+ }
709
+
710
+ if (props.lockAspectRatio) {
711
+ limits.minLeft = Math.max(
712
+ limits.minLeft,
713
+ left.value - top.value * aspectFactor.value,
714
+ )
715
+ limits.minTop = Math.max(
716
+ limits.minTop,
717
+ top.value - left.value / aspectFactor.value,
718
+ )
719
+ limits.minRight = Math.max(
720
+ limits.minRight,
721
+ right.value - bottom.value * aspectFactor.value,
722
+ )
723
+ limits.minBottom = Math.max(
724
+ limits.minBottom,
725
+ bottom.value - right.value / aspectFactor.value,
726
+ )
727
+ }
728
+ }
729
+ else {
730
+ limits.minLeft = null
731
+ limits.maxLeft
732
+ = left.value + Math.floor((width.value - minW.value) / gridX) * gridX
733
+ limits.minTop = null
734
+ limits.maxTop
735
+ = top.value + Math.floor((height.value - minH.value) / gridY) * gridY
736
+ limits.minRight = null
737
+ limits.maxRight
738
+ = right.value + Math.floor((width.value - minW.value) / gridX) * gridX
739
+ limits.minBottom = null
740
+ limits.maxBottom
741
+ = bottom.value + Math.floor((height.value - minH.value) / gridY) * gridY
742
+
743
+ if (maxW.value) {
744
+ limits.minLeft = -(right.value + maxW.value)
745
+ limits.minRight = -(left.value + maxW.value)
746
+ }
747
+
748
+ if (maxH.value) {
749
+ limits.minTop = -(bottom.value + maxH.value)
750
+ limits.minBottom = -(top.value + maxH.value)
751
+ }
752
+
753
+ if (props.lockAspectRatio && maxW.value && maxH.value) {
754
+ limits.minLeft = Math.min(limits.minLeft, -(right.value + maxW.value))
755
+ limits.minTop = Math.min(limits.minTop, -(maxH.value + bottom.value))
756
+ limits.minRight = Math.min(limits.minRight, -left.value - maxW.value)
757
+ limits.minBottom = Math.min(limits.minBottom, -top.value - maxH.value)
758
+ }
759
+ }
760
+
761
+ return limits
762
+ }
763
+
764
+ function move(e) {
765
+ if (resizing.value)
766
+ handleResize(e)
767
+ else if (dragEnable.value)
768
+ handleDrag(e)
769
+ }
770
+ function handleDrag(e) {
771
+ const tmpDeltaX
772
+ = props.axis && props.axis !== 'y'
773
+ ? mouseClickPosition.value.mouseX
774
+ - (e.touches ? e.touches[0].pageX : e.pageX)
775
+ : 0
776
+
777
+ const tmpDeltaY
778
+ = props.axis && props.axis !== 'x'
779
+ ? mouseClickPosition.value.mouseY
780
+ - (e.touches ? e.touches[0].pageY : e.pageY)
781
+ : 0
782
+
783
+ const [deltaX, deltaY] = snapToGrid(
784
+ grid.value,
785
+ tmpDeltaX,
786
+ tmpDeltaY,
787
+ props.scale,
788
+ )
789
+
790
+ const leftPx = restrictToBounds(
791
+ mouseClickPosition.value.left - deltaX,
792
+ bounds.value.minLeft,
793
+ bounds.value.maxLeft,
794
+ )
795
+
796
+ const topPx = restrictToBounds(
797
+ mouseClickPosition.value.top - deltaY,
798
+ bounds.value.minTop,
799
+ bounds.value.maxTop,
800
+ )
801
+
802
+ if (props.onDrag(left, top) === false)
803
+ return
804
+
805
+ const rightPx = restrictToBounds(
806
+ mouseClickPosition.value.right + deltaX,
807
+ bounds.value.minRight,
808
+ bounds.value.maxRight,
809
+ )
810
+
811
+ const bottomPx = restrictToBounds(
812
+ mouseClickPosition.value.bottom + deltaY,
813
+ bounds.value.minBottom,
814
+ bounds.value.maxBottom,
815
+ )
816
+
817
+ left.value = leftPx
818
+ top.value = topPx
819
+ right.value = rightPx
820
+ bottom.value = bottomPx
821
+
822
+ emit('dragging', left.value, top.value)
823
+
824
+ dragging.value = true
825
+ }
826
+
827
+ function moveHorizontally(val) {
828
+ // should calculate with scale 1.
829
+
830
+ const [deltaX] = snapToGrid(grid.value, val, top.value, 1)
831
+
832
+ const leftPx = restrictToBounds(
833
+ deltaX,
834
+ bounds.value.minLeft,
835
+ bounds.value.maxLeft,
836
+ )
837
+
838
+ left.value = leftPx
839
+ right.value = parentWidth.value - width.value - leftPx
840
+ }
841
+
842
+ function moveVertically(val) {
843
+ // should calculate with scale 1.
844
+
845
+ const [, deltaY] = snapToGrid(grid.value, left.value, val, 1)
846
+
847
+ const topPx = restrictToBounds(
848
+ deltaY,
849
+ bounds.value.minTop,
850
+ bounds.value.maxTop,
851
+ )
852
+
853
+ top.value = topPx
854
+ bottom.value = parentHeight.value - height.value - topPx
855
+ }
856
+
857
+ function handleResize(e) {
858
+ let leftPx = left.value
859
+ let topPx = top.value
860
+ let rightPx = right.value
861
+ let bottomPx = bottom.value
862
+
863
+ // const lockAspectRatio = props.lockAspectRatio
864
+
865
+ const tmpDeltaX
866
+ = mouseClickPosition.value.mouseX - (e.touches ? e.touches[0].pageX : e.pageX)
867
+
868
+ const tmpDeltaY
869
+ = mouseClickPosition.value.mouseY - (e.touches ? e.touches[0].pageY : e.pageY)
870
+
871
+ if (!widthTouched.value && tmpDeltaX)
872
+ widthTouched.value = true
873
+
874
+ if (!heightTouched.value && tmpDeltaY)
875
+ heightTouched.value = true
876
+
877
+ const [deltaX, deltaY] = snapToGrid(
878
+ grid.value,
879
+ tmpDeltaX,
880
+ tmpDeltaY,
881
+ props.scale,
882
+ )
883
+
884
+ if (handle.value.includes('b')) {
885
+ bottomPx = restrictToBounds(
886
+ mouseClickPosition.value.bottom + deltaY,
887
+ bounds.value.minBottom,
888
+ bounds.value.maxBottom,
889
+ )
890
+
891
+ if (props.lockAspectRatio && resizingOnY)
892
+ rightPx = right.value - (bottom.value - bottomPx) * aspectFactor.value
893
+ }
894
+ else if (handle.value.includes('t')) {
895
+ topPx = restrictToBounds(
896
+ mouseClickPosition.value.top - deltaY,
897
+ bounds.value.minTop,
898
+ bounds.value.maxTop,
899
+ )
900
+
901
+ if (props.lockAspectRatio && resizingOnY)
902
+ leftPx = left.value - (top.value - topPx) * aspectFactor.value
903
+ }
904
+
905
+ if (handle.value.includes('r')) {
906
+ rightPx = restrictToBounds(
907
+ mouseClickPosition.value.right + deltaX,
908
+ bounds.value.minRight,
909
+ bounds.value.maxRight,
910
+ )
911
+
912
+ if (props.lockAspectRatio && resizingOnX)
913
+ bottomPx = bottom.value - (right.value - rightPx) / aspectFactor.value
914
+ }
915
+ else if (handle.value.includes('l')) {
916
+ leftPx = restrictToBounds(
917
+ mouseClickPosition.value.left - deltaX,
918
+ bounds.value.minLeft,
919
+ bounds.value.maxLeft,
920
+ )
921
+
922
+ if (props.lockAspectRatio && resizingOnX)
923
+ topPx = top.value - (left.value - leftPx) / aspectFactor.value
924
+ }
925
+
926
+ const widthPx = computeWidth(parentWidth.value, leftPx, rightPx)
927
+
928
+ const heightPx = computeHeight(parentHeight.value, topPx, bottomPx)
929
+
930
+ if (
931
+ props.onResize(handle.value, leftPx, topPx, widthPx, heightPx) === false
932
+ )
933
+ return
934
+
935
+ left.value = leftPx
936
+ top.value = topPx
937
+ right.value = rightPx
938
+ bottom.value = bottomPx
939
+ width.value = widthPx
940
+ height.value = heightPx
941
+
942
+ emit('resizing', left.value, top.value, width.value, height.value)
943
+
944
+ resizing.value = true
945
+ }
946
+
947
+ function changeWidth(val) {
948
+ // should calculate with scale 1.
949
+
950
+ const [newWidth] = snapToGrid(grid.value, val, 0, 1)
951
+
952
+ const rightPx = restrictToBounds(
953
+ parentWidth.value - newWidth - left.value,
954
+ bounds.value.minRight,
955
+ bounds.value.maxRight,
956
+ )
957
+
958
+ let bottomPx = bottom.value
959
+
960
+ if (props.lockAspectRatio)
961
+ bottomPx = bottom.value - (right.value - rightPx) / aspectFactor.value
962
+
963
+ const widthPx = computeWidth(parentWidth.value, left.value, rightPx)
964
+ const heightPx = computeHeight(parentHeight.value, top.value, bottomPx)
965
+
966
+ right.value = rightPx
967
+ bottom.value = bottomPx
968
+ width.value = widthPx
969
+ height.value = heightPx
970
+ }
971
+
972
+ function changeHeight(val) {
973
+ // should calculate with scale 1.
974
+
975
+ const [, newHeight] = snapToGrid(grid.value, 0, val, 1)
976
+
977
+ const bottomPx = restrictToBounds(
978
+ parentHeight.value - newHeight - top.value,
979
+ bounds.value.minBottom,
980
+ bounds.value.maxBottom,
981
+ )
982
+
983
+ let rightPx = right.value
984
+
985
+ if (props.lockAspectRatio)
986
+ rightPx = right.value - (bottom.value - bottomPx) * aspectFactor.value
987
+
988
+ const widthPx = computeWidth(parentWidth.value, left.value, rightPx)
989
+
990
+ const heightPx = computeHeight(parentHeight.value, top.value, bottomPx)
991
+
992
+ right.value = rightPx
993
+ bottom.value = bottomPx
994
+ width.value = widthPx
995
+ height.value = heightPx
996
+ }
997
+
998
+ function handleUp() {
999
+ handle.value = null
1000
+
1001
+ resetBoundsAndMouseState()
1002
+
1003
+ dragEnable.value = false
1004
+ resizeEnable.value = false
1005
+
1006
+ if (resizing.value) {
1007
+ resizing.value = false
1008
+
1009
+ emit('resizestop', left.value, top.value, width.value, height.value)
1010
+ }
1011
+
1012
+ if (dragging.value) {
1013
+ dragging.value = false
1014
+
1015
+ emit('dragstop', left.value, top.value)
1016
+ }
1017
+
1018
+ removeEvent(document.documentElement, eventsFor.move, handleResize)
1019
+ }
1020
+
1021
+ function elementMouseOver() {
1022
+ if (props.activeOnHover)
1023
+ active.value = true
1024
+ }
1025
+ function elementMouseLeave() {
1026
+ if (props.activeOnHover && !dragging.value)
1027
+ active.value = false
1028
+ }
1029
+
1030
+ onMounted(() => {
1031
+ resetBoundsAndMouseState()
1032
+
1033
+ if (!props.enableNativeDrag)
1034
+ el.value.ondragstart = () => false
1035
+
1036
+ const [parentWidthPx, parentHeightPx] = getParentSize()
1037
+
1038
+ parentWidth.value = parentWidthPx
1039
+ parentHeight.value = parentHeightPx
1040
+
1041
+ const [widthPx, heightPx] = getComputedSize(el.value)
1042
+
1043
+ aspectFactor.value
1044
+ = (width.value !== 'auto' ? width.value : widthPx)
1045
+ / (height.value !== 'auto' ? height.value : heightPx)
1046
+
1047
+ width.value = width.value !== 'auto' ? width.value : widthPx
1048
+ height.value = height.value !== 'auto' ? height.value : heightPx
1049
+ right.value = parentWidth.value - width.value - left.value
1050
+ bottom.value = parentHeight.value - height.value - top.value
1051
+
1052
+ if (active.value)
1053
+ emit('activated')
1054
+
1055
+ if (props.showGrid)
1056
+ showParentGrid()
1057
+
1058
+ addEvent(document.documentElement, 'mousedown', deselect)
1059
+ addEvent(document.documentElement, 'touchend touchcancel', deselect)
1060
+ addEvent(window, 'resize', checkParentSize)
1061
+
1062
+ nextTick(() => {
1063
+ checkParentSize()
1064
+ })
1065
+ })
1066
+
1067
+ watch(
1068
+ () => props.x,
1069
+ (val) => {
1070
+ if (resizing.value || dragging.value)
1071
+ return
1072
+
1073
+ if (parent.value)
1074
+ bounds.value = calcDragLimits()
1075
+
1076
+ moveHorizontally(val)
1077
+ },
1078
+ )
1079
+
1080
+ watch(
1081
+ () => props.y,
1082
+ (val) => {
1083
+ if (resizing.value || dragging.value)
1084
+ return
1085
+
1086
+ if (parent.value)
1087
+ bounds.value = calcDragLimits()
1088
+
1089
+ moveVertically(val)
1090
+ },
1091
+ )
1092
+
1093
+ watch(
1094
+ () => props.lockAspectRatio,
1095
+ (val) => {
1096
+ if (val)
1097
+ aspectFactor.value = width.value / height.value
1098
+ else
1099
+ aspectFactor.value = undefined
1100
+ },
1101
+ )
1102
+
1103
+ watch(
1104
+ () => props.w,
1105
+ (val) => {
1106
+ if (resizing.value || dragging.value)
1107
+ return
1108
+
1109
+ if (parent.value)
1110
+ bounds.value = calcResizeLimits()
1111
+
1112
+ changeWidth(val)
1113
+ },
1114
+ )
1115
+
1116
+ watch(
1117
+ () => props.h,
1118
+ (val) => {
1119
+ if (resizing.value || dragging.value)
1120
+ return
1121
+
1122
+ if (parent.value)
1123
+ bounds.value = calcResizeLimits()
1124
+
1125
+ changeHeight(val)
1126
+ },
1127
+ )
1128
+
1129
+ watch(
1130
+ () => props.showGrid,
1131
+ () => {
1132
+ showParentGrid()
1133
+ },
1134
+ )
1135
+
1136
+ watch(
1137
+ () => props.grid,
1138
+ () => {
1139
+ showParentGrid()
1140
+ },
1141
+ )
1142
+ </script>
1143
+
1144
+ <template>
1145
+ <div
1146
+ ref="el"
1147
+ :style="style"
1148
+ :class="[
1149
+ {
1150
+ [classNameActive]: active,
1151
+ [classNameDragging]: dragging,
1152
+ [classNameResizing]: resizing,
1153
+ [classNameDraggable]: draggable,
1154
+ [classNameResizable]: resizable,
1155
+ },
1156
+ className,
1157
+ ]"
1158
+ @mousedown="elementMouseDown"
1159
+ @touchstart="elementTouchDown"
1160
+ @mouseover="elementMouseOver"
1161
+ @mouseleave="elementMouseLeave"
1162
+ >
1163
+ <div :class="`drv-${handlesType}`">
1164
+ <div
1165
+ v-for="handleEl in actualHandles"
1166
+ :key="handleEl"
1167
+ :class="[
1168
+ classNameHandle,
1169
+ `${classNameHandle}-${handleEl}`,
1170
+ classNameHandle !== 'drv-handle' ? 'drv-handle' : '',
1171
+ classNameHandle !== 'drv-handle' ? `drv-handle` + `-${handleEl}` : '',
1172
+ ]"
1173
+ :style="{
1174
+ display: active ? 'block' : 'none',
1175
+ }"
1176
+ @mousedown.stop.prevent="handleDown(handleEl, $event)"
1177
+ @touchstart.stop.prevent="handleTouchDown(handleEl, $event)"
1178
+ >
1179
+ <slot
1180
+ v-if="slots[`handle-${handleEl}`]"
1181
+ :name="`handle-${handleEl}`"
1182
+ />
1183
+ <slot v-if="!slots[`handle-${handleEl}`]" name="handle" />
1184
+ </div>
1185
+ </div>
1186
+ <slot />
1187
+ </div>
1188
+ </template>
1189
+
1190
+ <style>
1191
+ .drv {
1192
+ touch-action: none;
1193
+ position: absolute;
1194
+ box-sizing: border-box;
1195
+ border: 1px dashed gray;
1196
+ }
1197
+
1198
+ .drv-handles .drv-handle {
1199
+ box-sizing: border-box;
1200
+ position: absolute;
1201
+ min-width: v-bind(handlesSize);
1202
+ min-height: v-bind(handlesSize);
1203
+ border: v-bind(handlesBorder);
1204
+ }
1205
+
1206
+ .drv-handles .drv-handle-tl {
1207
+ transform: translate(-100%, -100%);
1208
+ top: 0;
1209
+ left: 0;
1210
+ cursor: nw-resize;
1211
+ }
1212
+
1213
+ .drv-handles .drv-handle-tm {
1214
+ transform: translate(-50%, -100%);
1215
+ top: 0;
1216
+ left: 50%;
1217
+ cursor: n-resize;
1218
+ }
1219
+
1220
+ .drv-handles .drv-handle-tr {
1221
+ transform: translate(100%, -100%);
1222
+ top: 0;
1223
+ right: 0;
1224
+ cursor: ne-resize;
1225
+ }
1226
+
1227
+ .drv-handles .drv-handle-ml {
1228
+ transform: translate(-100%, -50%);
1229
+ top: 50%;
1230
+ left: 0;
1231
+ cursor: w-resize;
1232
+ }
1233
+
1234
+ .drv-handles .drv-handle-mr {
1235
+ transform: translate(100%, -50%);
1236
+ top: 50%;
1237
+ right: 0;
1238
+ cursor: e-resize;
1239
+ }
1240
+
1241
+ .drv-handles .drv-handle-bl {
1242
+ transform: translate(-100%, 100%);
1243
+ bottom: 0;
1244
+ left: 0;
1245
+ cursor: sw-resize;
1246
+ }
1247
+
1248
+ .drv-handles .drv-handle-bm {
1249
+ transform: translate(-50%, 100%);
1250
+ bottom: 0;
1251
+ left: 50%;
1252
+ cursor: s-resize;
1253
+ }
1254
+
1255
+ .drv-handles .drv-handle-br {
1256
+ transform: translate(100%, 100%);
1257
+ bottom: 0;
1258
+ right: 0;
1259
+ cursor: se-resize;
1260
+ }
1261
+
1262
+ .drv-borders .drv-handle {
1263
+ box-sizing: border-box;
1264
+ position: absolute;
1265
+ min-width: v-bind(handlesSize);
1266
+ min-height: v-bind(handlesSize);
1267
+ }
1268
+
1269
+ .drv-borders .drv-handle-tl {
1270
+ transform: translate(-50%, -50%);
1271
+ top: 0;
1272
+ left: 0;
1273
+ cursor: nw-resize;
1274
+ }
1275
+ .drv-borders .drv-handle-tm {
1276
+ transform: translate(0, -50%);
1277
+ left: v-bind(handlesHalfSize);
1278
+ width: calc(100% - v-bind(handlesSize));
1279
+ top: 0;
1280
+ cursor: n-resize;
1281
+ }
1282
+
1283
+ .drv-borders .drv-handle-tr {
1284
+ transform: translate(50%, -50%);
1285
+ top: 0;
1286
+ right: 0;
1287
+ cursor: ne-resize;
1288
+ }
1289
+
1290
+ .drv-borders .drv-handle-ml {
1291
+ transform: translate(-50%, 0);
1292
+ top: v-bind(handlesHalfSize);
1293
+ height: calc(100% - v-bind(handlesSize));
1294
+ left: 0;
1295
+ cursor: w-resize;
1296
+ }
1297
+
1298
+ .drv-borders .drv-handle-bl {
1299
+ transform: translate(-50%, 50%);
1300
+ bottom: 0;
1301
+ left: 0;
1302
+ cursor: sw-resize;
1303
+ }
1304
+
1305
+ .drv-borders .drv-handle-bm {
1306
+ transform: translate(0, 50%);
1307
+ left: v-bind(handlesHalfSize);
1308
+ width: calc(100% - v-bind(handlesSize));
1309
+ bottom: 0;
1310
+ cursor: s-resize;
1311
+ }
1312
+
1313
+ .drv-borders .drv-handle-br {
1314
+ transform: translate(50%, 50%);
1315
+ bottom: 0;
1316
+ right: 0;
1317
+ cursor: se-resize;
1318
+ }
1319
+
1320
+ .drv-borders .drv-handle-mr {
1321
+ transform: translate(50%, 0);
1322
+ top: v-bind(handlesHalfSize);
1323
+ height: calc(100% - v-bind(handlesSize));
1324
+ right: 0;
1325
+ cursor: e-resize;
1326
+ }
1327
+ </style>