renusify 2.5.1 → 3.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.
Files changed (212) hide show
  1. package/components/app/index.vue +74 -22
  2. package/components/app/toast/index.vue +76 -71
  3. package/components/app/toast/toast.vue +62 -44
  4. package/components/avatar/index.vue +208 -84
  5. package/components/button/buttonConfirm.vue +53 -26
  6. package/components/button/buttonGroup.js +0 -2
  7. package/components/button/buttonGroup.vue +310 -62
  8. package/components/button/index.vue +584 -100
  9. package/components/calendar/index.js +0 -2
  10. package/components/calendar/index.vue +326 -262
  11. package/components/calendar/month.vue +64 -55
  12. package/components/calendar/year.vue +30 -25
  13. package/components/card/index.vue +139 -59
  14. package/components/codeEditor/highlightCss.vue +38 -39
  15. package/components/codeEditor/highlightHtml.vue +64 -64
  16. package/components/codeEditor/highlightJs.vue +37 -38
  17. package/components/codeEditor/index.vue +129 -79
  18. package/components/codeEditor/run.vue +225 -39
  19. package/components/codeEditor/useCodeFormatter.js +150 -0
  20. package/components/confirm/index.vue +140 -81
  21. package/components/container/col.vue +5 -4
  22. package/components/container/divider.vue +28 -19
  23. package/components/container/index.vue +34 -15
  24. package/components/container/row.vue +26 -9
  25. package/components/container/spacer.vue +2 -4
  26. package/components/container/style.scss +3 -0
  27. package/components/content/index.vue +49 -32
  28. package/components/cropper/index.vue +401 -244
  29. package/components/float/index.vue +542 -415
  30. package/components/form/addressInput/index.vue +184 -109
  31. package/components/form/camInput/index.vue +370 -244
  32. package/components/form/checkInput/index.vue +138 -71
  33. package/components/form/checkboxInput/index.vue +87 -47
  34. package/components/form/colorInput/Alpha.vue +81 -83
  35. package/components/form/colorInput/Hue.vue +91 -68
  36. package/components/form/colorInput/Preview.vue +43 -47
  37. package/components/form/colorInput/Saturation.vue +101 -86
  38. package/components/form/colorInput/index.vue +72 -40
  39. package/components/form/colorInput/picker.vue +111 -106
  40. package/components/form/colorInput/useColor.js +153 -0
  41. package/components/form/dateInput/index.vue +691 -356
  42. package/components/form/dateInput/month.vue +63 -54
  43. package/components/form/dateInput/year.vue +35 -25
  44. package/components/form/fileInput/index.js +0 -1
  45. package/components/form/fileInput/index.vue +263 -106
  46. package/components/form/fileInput/single.vue +323 -164
  47. package/components/form/groupInput/index.vue +199 -101
  48. package/components/form/index.vue +189 -83
  49. package/components/form/input/index.vue +416 -377
  50. package/components/form/jsonInput/JsonView.vue +54 -56
  51. package/components/form/jsonInput/index.vue +247 -165
  52. package/components/form/maskInput/index.vue +252 -132
  53. package/components/form/numberInput/index.js +0 -1
  54. package/components/form/numberInput/index.vue +226 -117
  55. package/components/form/passwordInput/index.js +2 -1
  56. package/components/form/passwordInput/index.vue +269 -102
  57. package/components/form/radioInput/index.vue +143 -72
  58. package/components/form/rangeInput/index.vue +280 -167
  59. package/components/form/ratingInput/index.vue +57 -57
  60. package/components/form/selectInput/index.js +1 -3
  61. package/components/form/selectInput/index.vue +584 -296
  62. package/components/form/switchInput/index.vue +73 -59
  63. package/components/form/telInput/index.js +0 -1
  64. package/components/form/telInput/index.vue +238 -135
  65. package/components/form/textArea/index.vue +72 -35
  66. package/components/form/textEditor/index.vue +739 -0
  67. package/components/form/{text-editor → textEditor}/style.scss +8 -16
  68. package/components/form/textInput/index.vue +54 -32
  69. package/components/form/timeInput/index.vue +83 -56
  70. package/components/form/timeInput/range.vue +116 -95
  71. package/components/form/timeInput/timepicker.vue +382 -449
  72. package/components/form/uniqueInput/index.vue +105 -48
  73. package/components/form/unitInput/index.vue +139 -84
  74. package/components/formCreator/index.js +0 -1
  75. package/components/formCreator/index.vue +314 -148
  76. package/components/highlight/index.vue +41 -25
  77. package/components/highlight/style.scss +2 -2
  78. package/components/highlight/{mixin.js → useHighlight.js} +181 -160
  79. package/components/icon/index.vue +79 -33
  80. package/components/img/index.vue +249 -147
  81. package/components/img/preview.vue +180 -198
  82. package/components/img/svgImg.vue +42 -39
  83. package/components/index.js +5 -20
  84. package/components/infinite/index.js +1 -2
  85. package/components/infinite/index.vue +248 -66
  86. package/components/map/index.vue +428 -261
  87. package/components/map/route.vue +794 -487
  88. package/components/map/select.vue +118 -58
  89. package/components/menu/index.vue +201 -91
  90. package/components/meta/meta.js +26 -3
  91. package/components/modal/index.vue +383 -158
  92. package/components/notify/index.vue +204 -86
  93. package/components/notify/notification.vue +38 -55
  94. package/components/progress/circle.vue +189 -70
  95. package/components/progress/line.vue +266 -46
  96. package/components/searchBox/index.js +1 -3
  97. package/components/searchBox/index.vue +194 -101
  98. package/components/skeleton/index.vue +45 -20
  99. package/components/slider/index.vue +318 -156
  100. package/components/swiper/index.vue +254 -106
  101. package/components/table/crud/footer.vue +77 -53
  102. package/components/table/crud/header.vue +71 -72
  103. package/components/table/crud/index.vue +631 -401
  104. package/components/table/index.vue +721 -278
  105. package/components/timeAgo/index.vue +145 -96
  106. package/components/tour/index.vue +338 -235
  107. package/components/tree/index.vue +235 -89
  108. package/components/tree/tree-element.vue +107 -106
  109. package/directive/animate/index.js +77 -0
  110. package/directive/clickOutSide/index.js +98 -0
  111. package/directive/drag/index.js +153 -0
  112. package/directive/index.js +11 -13
  113. package/directive/intersect/index.js +263 -0
  114. package/directive/mask/index.js +67 -0
  115. package/directive/parallax/index.js +78 -0
  116. package/directive/ripple/index.js +14 -0
  117. package/directive/scroll/index.js +244 -0
  118. package/directive/sortable/index.js +274 -0
  119. package/directive/title/index.js +75 -0
  120. package/directive/touch/index.js +268 -0
  121. package/index.js +10 -8
  122. package/package.json +5 -2
  123. package/plugins/validation/Validate.js +88 -79
  124. package/scripts/generate-docs.mjs +226 -0
  125. package/scripts/menu.mjs +240 -0
  126. package/scripts/parser.mjs +1086 -0
  127. package/style/_index.scss +7 -0
  128. package/style/app.scss +13 -65
  129. package/style/colors.scss +5 -22
  130. package/style/functions/index.scss +8 -0
  131. package/style/mixins/index.scss +17 -5
  132. package/style/variables/base.scss +154 -175
  133. package/style/variables/color.scss +0 -12
  134. package/style/variables/utilities.scss +0 -180
  135. package/tools/helper.js +0 -8
  136. package/tools/icons.js +6 -1
  137. package/tools/root.js +71 -0
  138. package/components/app/style.scss +0 -41
  139. package/components/app/toast/style.scss +0 -20
  140. package/components/avatar/style.scss +0 -32
  141. package/components/bar/bottomNav.js +0 -1
  142. package/components/bar/bottomNav.vue +0 -28
  143. package/components/bar/bottomNavigationCircle.js +0 -2
  144. package/components/bar/bottomNavigationCircle.vue +0 -99
  145. package/components/bar/scss/bottomNav.scss +0 -67
  146. package/components/bar/scss/toolbar.scss +0 -174
  147. package/components/bar/toolbar/index.js +0 -8
  148. package/components/bar/toolbar/index.vue +0 -35
  149. package/components/bar/toolbar/laptop.vue +0 -33
  150. package/components/bar/toolbar/menuChilds.vue +0 -41
  151. package/components/bar/toolbar/menuLaptop.vue +0 -41
  152. package/components/bar/toolbar/menuMob.vue +0 -39
  153. package/components/bar/toolbar/mixin.js +0 -43
  154. package/components/bar/toolbar/mobile.vue +0 -34
  155. package/components/breadcrumb/bredcrumbItem.vue +0 -39
  156. package/components/breadcrumb/index.js +0 -3
  157. package/components/breadcrumb/index.vue +0 -71
  158. package/components/breadcrumb/style.scss +0 -51
  159. package/components/button/style.scss +0 -411
  160. package/components/card/style.scss +0 -86
  161. package/components/chart/chart.js +0 -1
  162. package/components/chart/chart.vue +0 -69
  163. package/components/chart/worldMap.js +0 -2
  164. package/components/chart/worldMap.vue +0 -1112
  165. package/components/chat/MessageList.vue +0 -163
  166. package/components/chat/chatInput.vue +0 -150
  167. package/components/chat/chatMsg.vue +0 -276
  168. package/components/chat/index.js +0 -11
  169. package/components/chat/index.vue +0 -113
  170. package/components/chip/index.js +0 -3
  171. package/components/chip/index.vue +0 -77
  172. package/components/chip/style.scss +0 -199
  173. package/components/codeEditor/mixin.js +0 -145
  174. package/components/countdown/index.js +0 -1
  175. package/components/countdown/index.vue +0 -105
  176. package/components/form/colorInput/mixin.js +0 -132
  177. package/components/form/fileInput/file.js +0 -148
  178. package/components/form/telInput/assets/flags.png +0 -0
  179. package/components/form/telInput/assets/flags@2x.png +0 -0
  180. package/components/form/text-editor/index.vue +0 -710
  181. package/components/icon/style.scss +0 -17
  182. package/components/infinite/div.js +0 -6
  183. package/components/infinite/div.vue +0 -193
  184. package/components/infinite/page.js +0 -3
  185. package/components/infinite/page.vue +0 -105
  186. package/components/list/index.js +0 -3
  187. package/components/list/index.vue +0 -122
  188. package/components/list/style.scss +0 -66
  189. package/components/message/index.js +0 -4
  190. package/components/message/index.vue +0 -40
  191. package/components/modal/style.scss +0 -146
  192. package/components/nestable/NestableItem.vue +0 -307
  193. package/components/nestable/editable.js +0 -44
  194. package/components/nestable/index.js +0 -1
  195. package/components/nestable/index.vue +0 -226
  196. package/components/nestable/methods.js +0 -416
  197. package/components/progress/style.scss +0 -229
  198. package/components/table/style.scss +0 -338
  199. package/components/tabs/index.js +0 -3
  200. package/components/tabs/index.vue +0 -151
  201. package/components/timeline/index.js +0 -6
  202. package/components/timeline/index.vue +0 -76
  203. package/directive/resize/index.js +0 -30
  204. package/directive/skeleton/index.js +0 -27
  205. package/directive/skeleton/style.scss +0 -37
  206. package/plugins/request/Request.js +0 -68
  207. package/style/animation.scss +0 -94
  208. package/style/style.scss +0 -8
  209. package/tools/rootable.js +0 -75
  210. /package/components/form/{text-editor → textEditor}/index.js +0 -0
  211. /package/components/form/{text-editor → textEditor}/preview.js +0 -0
  212. /package/components/form/{text-editor → textEditor}/preview.vue +0 -0
@@ -1,458 +1,585 @@
1
1
  <template>
2
2
  <div :class="classes">
3
3
  <div ref="float" :class="{'in-zoom':inZoom}" class="float-container">
4
- <slot :ease="ease" :move="moveTo" :pause="pause" :resume="resume" :transform="transform"
4
+ <!-- Main slot for content with transformation controls. Provides scoped methods and state
5
+ @example
6
+ <div class="color-one" style="height: 300px;width: 400px">content</div>
7
+ -->
8
+ <slot :ease="ease"
9
+ :move="moveTo"
10
+ :pause="pause"
11
+ :resume="resume"
12
+ :transform="transform"
5
13
  :zoom="zoomAbs"></slot>
6
14
  </div>
7
15
  </div>
8
16
  </template>
9
- <script>
10
- export default {
11
- name: 'r-float',
12
- props: {
13
- bordered: Boolean,
14
- disableZoom: Boolean,
15
- disableMove: Boolean,
16
- trnsfrmOrigin: Object,
17
- zoom: {type: Number, default: 1},
18
- maxZoom: {
19
- type: Number,
20
- default: 10
21
- },
22
- minZoom: {
23
- type: Number,
24
- default: .1
25
- }
17
+ <script setup>
18
+ import {ref, computed, onMounted, onBeforeUnmount, inject} from 'vue'
19
+
20
+ const props = defineProps({
21
+ /**
22
+ * Adds border to the float container
23
+ * @type {Boolean}
24
+ */
25
+ bordered: Boolean,
26
+
27
+ /**
28
+ * Disables zoom functionality
29
+ * @type {Boolean}
30
+ */
31
+ disableZoom: Boolean,
32
+
33
+ /**
34
+ * Disables move/drag functionality
35
+ * @type {Boolean}
36
+ */
37
+ disableMove: Boolean,
38
+
39
+ /**
40
+ * Custom transform origin point (0-1 values)
41
+ * @type {Object}
42
+ * @property {Number} x - X coordinate (0-1)
43
+ * @property {Number} y - Y coordinate (0-1)
44
+ */
45
+ trnsfrmOrigin: Object,
46
+
47
+ /**
48
+ * Initial zoom level
49
+ * @type {Number}
50
+ * @default 1
51
+ */
52
+ zoom: {type: Number, default: 1},
53
+
54
+ /**
55
+ * Maximum zoom level
56
+ * @type {Number}
57
+ * @default 10
58
+ */
59
+ maxZoom: {
60
+ type: Number,
61
+ default: 10
26
62
  },
27
- emits: ['move', 'zoom'],
28
- data() {
29
- return {
30
- started: Date.now(),
31
- transform: {
32
- x: 0,
33
- y: 0,
34
- scale: this.zoom
35
- },
36
- inZoom: false,
37
- paused: false,
38
- storedCTMResult: {x: 0, y: 0},
39
- isDirty: false,
40
- lastTouchEndTime: 0,
41
- lastSingleFingerOffset: null,
42
- touchInProgress: false,
43
- multiTouch: false,
44
- mouseX: 0,
45
- mouseY: 0,
46
- pinchZoomLength: 0,
47
- frameAnimation: null
63
+
64
+ /**
65
+ * Minimum zoom level
66
+ * @type {Number}
67
+ * @default 0.1
68
+ */
69
+ minZoom: {
70
+ type: Number,
71
+ default: .1
72
+ }
73
+ })
74
+
75
+ const emit = defineEmits([
76
+ /**
77
+ * Emitted when content is moved
78
+ * @param {Array} movement - [dx, dy] movement delta
79
+ */
80
+ 'move',
81
+
82
+ /**
83
+ * Emitted when zoom level changes
84
+ * @param {Array} zoomData - [clientX, clientY, ratio] zoom parameters
85
+ */
86
+ 'zoom'
87
+ ])
88
+
89
+ const {$r} = inject('renusify')
90
+
91
+ const transform = ref({
92
+ x: 0,
93
+ y: 0,
94
+ scale: props.zoom
95
+ })
96
+ const inZoom = ref(false)
97
+ const paused = ref(false)
98
+ const storedCTMResult = ref({x: 0, y: 0})
99
+ const isDirty = ref(false)
100
+ const lastTouchEndTime = ref(0)
101
+ const lastSingleFingerOffset = ref(null)
102
+ const touchInProgress = ref(false)
103
+ const multiTouch = ref(false)
104
+ const mouseX = ref(0)
105
+ const mouseY = ref(0)
106
+ const pinchZoomLength = ref(0)
107
+ const frameAnimation = ref(null)
108
+ const float = ref(null)
109
+
110
+ const classes = computed(() => {
111
+ return {
112
+ 'float-bordered': props.bordered,
113
+ [`${$r.prefix}float`]: true
114
+ }
115
+ })
116
+
117
+ const domElement = computed(() => float.value)
118
+
119
+ const owner = computed(() => domElement.value?.parentElement)
120
+
121
+ const transformOrigin = computed(() => {
122
+ if (!props.trnsfrmOrigin || !isNumber(props.trnsfrmOrigin.x) || !isNumber(props.trnsfrmOrigin.y)) {
123
+ return null
124
+ }
125
+ return props.trnsfrmOrigin
126
+ })
127
+
128
+ const getTransformOriginOffset = computed(() => {
129
+ if (!owner.value || !transformOrigin.value) return {x: 0, y: 0}
130
+
131
+ let ownerRect = owner.value.getBoundingClientRect()
132
+ return {
133
+ x: ownerRect.width * transformOrigin.value.x,
134
+ y: ownerRect.height * transformOrigin.value.y
135
+ }
136
+ })
137
+
138
+ const midPoint = computed(() => {
139
+ if (!owner.value) return {x: 0, y: 0}
140
+
141
+ let ownerRect = owner.value.getBoundingClientRect()
142
+ return {
143
+ x: ownerRect.width / 2,
144
+ y: ownerRect.height / 2
145
+ }
146
+ })
147
+
148
+ const builder = () => {
149
+ if (!domElement.value || !owner.value) return
150
+
151
+ domElement.value.scrollTop = 0
152
+ owner.value.setAttribute('tabindex', 0)
153
+ listenForEvents()
154
+ zoomAbs(transform.value.x, transform.value.y, transform.value.scale)
155
+ }
156
+
157
+ const applyTransform = () => {
158
+ if (!domElement.value) return
159
+
160
+ isDirty.value = false
161
+ domElement.value.style.transformOrigin = '0 0 0'
162
+ domElement.value.style.transform = 'matrix(' +
163
+ transform.value.scale + ', 0, 0, ' +
164
+ transform.value.scale + ', ' +
165
+ transform.value.x + ', ' + transform.value.y + ')'
166
+ frameAnimation.value = 0
167
+ }
168
+
169
+ /**
170
+ * Pauses all interaction events
171
+ */
172
+ const pause = () => {
173
+ releaseEvents()
174
+ paused.value = true
175
+ }
176
+
177
+ /**
178
+ * Resumes interaction events
179
+ */
180
+ const resume = () => {
181
+ if (paused.value) {
182
+ listenForEvents()
183
+ paused.value = false
184
+ }
185
+ }
186
+
187
+ const listenForEvents = () => {
188
+ if (!owner.value) return
189
+
190
+ owner.value.addEventListener('mousedown', onMouseDown, {passive: false})
191
+ owner.value.addEventListener('dblclick', onDoubleClick, {passive: false})
192
+ owner.value.addEventListener('touchstart', onTouch, {passive: false})
193
+ owner.value.addEventListener('keydown', onKeyDown, {passive: false})
194
+ owner.value.addEventListener('wheel', onMouseWheel, {passive: false})
195
+ makeDirty()
196
+ }
197
+
198
+ const transformToScreen = (x, y) => {
199
+ storedCTMResult.value.x = x
200
+ storedCTMResult.value.y = y
201
+ return storedCTMResult.value
202
+ }
203
+
204
+ /**
205
+ * Moves the content by specified delta
206
+ * @param {Number} dx - X-axis movement delta
207
+ * @param {Number} dy - Y-axis movement delta
208
+ */
209
+ const moveTo = (dx, dy) => {
210
+ if (props.disableMove) return
211
+ transform.value.x += dx
212
+ transform.value.y += dy
213
+ emit('move', [dx, dy])
214
+ makeDirty()
215
+ }
216
+
217
+ const makeDirty = () => {
218
+ isDirty.value = true
219
+ frameAnimation.value = window.requestAnimationFrame(frame)
220
+ }
221
+
222
+ /**
223
+ * Triggers zoom ease animation
224
+ */
225
+ const ease = () => {
226
+ inZoom.value = true
227
+ setTimeout(() => {
228
+ inZoom.value = false
229
+ }, 500)
230
+ }
231
+
232
+ /**
233
+ * Zooms by ratio from specific point
234
+ * @param {Number} clientX - X coordinate to zoom from
235
+ * @param {Number} clientY - Y coordinate to zoom from
236
+ * @param {Number} ratio - Zoom ratio
237
+ * @param {Boolean} easeFlag - Whether to trigger ease animation
238
+ */
239
+ const zoomByRatio = (clientX, clientY, ratio, easeFlag = false) => {
240
+ if (props.disableZoom) return
241
+ if (easeFlag) ease()
242
+ if (isNaN(clientX) || isNaN(clientY) || isNaN(ratio)) {
243
+ throw new Error('zoom requires valid numbers')
244
+ }
245
+
246
+ let newScale = transform.value.scale * ratio
247
+
248
+ if (newScale < props.minZoom) {
249
+ if (transform.value.scale === props.minZoom) return
250
+ ratio = props.minZoom / transform.value.scale
251
+ }
252
+ if (newScale > props.maxZoom) {
253
+ if (transform.value.scale === props.maxZoom) return
254
+ ratio = props.maxZoom / transform.value.scale
255
+ }
256
+
257
+ let size = transformToScreen(clientX, clientY)
258
+
259
+ transform.value.x = size.x - ratio * (size.x - transform.value.x)
260
+ transform.value.y = size.y - ratio * (size.y - transform.value.y)
261
+
262
+ transform.value.scale *= ratio
263
+
264
+ emit('zoom', [clientX, clientY, ratio])
265
+
266
+ makeDirty()
267
+ }
268
+
269
+ /**
270
+ * Zooms to absolute level from specific point
271
+ * @param {Number} clientX - X coordinate to zoom from
272
+ * @param {Number} clientY - Y coordinate to zoom from
273
+ * @param {Number} zoomLevel - Target zoom level
274
+ */
275
+ const zoomAbs = (clientX, clientY, zoomLevel) => {
276
+ let ratio = zoomLevel / transform.value.scale
277
+ zoomByRatio(clientX, clientY, ratio)
278
+ }
279
+
280
+ const frame = () => {
281
+ if (isDirty.value) applyTransform()
282
+ }
283
+
284
+ const onKeyDown = (e) => {
285
+ let x = 0,
286
+ y = 0,
287
+ z = 0
288
+ if (e.keyCode === 38) {
289
+ y = -1 // up
290
+ } else if (e.keyCode === 40) {
291
+ y = 1 // down
292
+ } else if (e.keyCode === 37) {
293
+ x = -1 // left
294
+ } else if (e.keyCode === 39) {
295
+ x = 1 // right
296
+ } else if (e.keyCode === 189 || e.keyCode === 109) {
297
+ // DASH or SUBTRACT
298
+ z = 1 // `-` - zoom out
299
+ } else if (e.keyCode === 187 || e.keyCode === 107) {
300
+ // EQUAL SIGN or ADD
301
+ z = -1 // `=` - zoom in
302
+ }
303
+
304
+ if (x || y) {
305
+ e.preventDefault()
306
+ e.stopPropagation()
307
+
308
+ if (!owner.value) return
309
+
310
+ let clientRect = owner.value.getBoundingClientRect()
311
+ let offset = Math.min(clientRect.width, clientRect.height)
312
+ let moveSpeedRatio = 0.05
313
+ let dx = offset * moveSpeedRatio * x
314
+ let dy = offset * moveSpeedRatio * y
315
+
316
+ moveTo(dx, dy)
317
+ }
318
+
319
+ if (z) {
320
+ let scaleMultiplier = getScaleMultiplier(z * 100)
321
+ let offset = transformOrigin.value ? getTransformOriginOffset.value : midPoint.value
322
+ zoomByRatio(offset.x, offset.y, scaleMultiplier)
323
+ }
324
+ }
325
+
326
+ const onTouch = (e) => {
327
+ if (e.touches.length === 1) {
328
+ return handleSingleFingerTouch(e, e.touches[0])
329
+ } else if (e.touches.length === 2) {
330
+ pinchZoomLength.value = getPinchZoomLength(e.touches[0], e.touches[1])
331
+ multiTouch.value = true
332
+ startTouchListenerIfNeeded()
333
+ }
334
+ }
335
+
336
+ const handleSingleFingerTouch = (e) => {
337
+ let touch = e.touches[0]
338
+ let offset = getOffsetXY(touch)
339
+ lastSingleFingerOffset.value = offset
340
+ let point = transformToScreen(offset.x, offset.y)
341
+ mouseX.value = point.x
342
+ mouseY.value = point.y
343
+
344
+ startTouchListenerIfNeeded()
345
+ }
346
+
347
+ const startTouchListenerIfNeeded = () => {
348
+ if (touchInProgress.value) {
349
+ return
350
+ }
351
+
352
+ touchInProgress.value = true
353
+ document.addEventListener('touchmove', handleTouchMove, {passive: false})
354
+ document.addEventListener('touchend', handleTouchEnd)
355
+ document.addEventListener('touchcancel', handleTouchEnd)
356
+ }
357
+
358
+ const handleTouchMove = (e) => {
359
+ e.stopPropagation()
360
+ e.preventDefault()
361
+ if (e.touches.length === 1) {
362
+ let touch = e.touches[0]
363
+ let offset = getOffsetXY(touch)
364
+ let point = transformToScreen(offset.x, offset.y)
365
+
366
+ let dx = point.x - mouseX.value
367
+ let dy = point.y - mouseY.value
368
+
369
+ mouseX.value = point.x
370
+ mouseY.value = point.y
371
+ moveTo(dx, dy)
372
+ } else if (e.touches.length === 2) {
373
+ multiTouch.value = true
374
+ let t1 = e.touches[0]
375
+ let t2 = e.touches[1]
376
+ let currentPinchLength = getPinchZoomLength(t1, t2)
377
+
378
+ let scaleMultiplier = 1 + (currentPinchLength / pinchZoomLength.value - 1)
379
+
380
+ let firstTouchPoint = getOffsetXY(t1)
381
+ let secondTouchPoint = getOffsetXY(t2)
382
+ mouseX.value = (firstTouchPoint.x + secondTouchPoint.x) / 2
383
+ mouseY.value = (firstTouchPoint.y + secondTouchPoint.y) / 2
384
+ if (transformOrigin.value) {
385
+ let offset = getTransformOriginOffset.value
386
+ mouseX.value = offset.x
387
+ mouseY.value = offset.y
48
388
  }
49
- },
50
- mounted() {
51
- this.builder()
52
- },
53
- computed: {
54
- classes() {
55
- let a = {
56
- 'float-bordered': this.bordered
389
+
390
+ zoomByRatio(mouseX.value, mouseY.value, scaleMultiplier)
391
+
392
+ pinchZoomLength.value = currentPinchLength
393
+ }
394
+ }
395
+
396
+ const handleTouchEnd = (e) => {
397
+ if (e.touches.length > 0) {
398
+ let offset = getOffsetXY(e.touches[0])
399
+ let point = transformToScreen(offset.x, offset.y)
400
+ mouseX.value = point.x
401
+ mouseY.value = point.y
402
+ } else {
403
+ let now = new Date()
404
+ if (now - lastTouchEndTime.value < 300) {
405
+ if (transformOrigin.value) {
406
+ let offset = getTransformOriginOffset.value
407
+ zoomByRatio(offset.x, offset.y, transform.value.scale)
408
+ } else {
409
+ zoomByRatio(lastSingleFingerOffset.value.x, lastSingleFingerOffset.value.y, transform.value.scale)
57
410
  }
58
- a[`${this.$r.prefix}float`] = true
59
- return a
60
- },
61
- domElement() {
62
- return this.$refs.float
63
- },
64
- owner() {
65
- return this.domElement.parentElement;
66
- },
67
- transformOrigin() {
68
- if (!this.trnsfrmOrigin || !this.isNumber(this.trnsfrmOrigin.x) || !this.isNumber(this.trnsfrmOrigin.y)) return;
69
-
70
- return this.trnsfrmOrigin;
71
- },
72
- getTransformOriginOffset() {
73
- let ownerRect = this.owner.getBoundingClientRect();
74
- return {
75
- x: ownerRect.width * this.transformOrigin.x,
76
- y: ownerRect.height * this.transformOrigin.y
77
- };
78
- },
79
- midPoint() {
80
- let ownerRect = this.owner.getBoundingClientRect();
81
- return {
82
- x: ownerRect.width / 2,
83
- y: ownerRect.height / 2
84
- };
85
- },
86
- getBBox() {
87
- return {
88
- left: 0,
89
- top: 0,
90
- width: this.domElement.clientWidth,
91
- height: this.domElement.clientHeight
92
- };
93
411
  }
94
- },
95
- methods: {
96
- builder() {
97
- this.domElement.scrollTop = 0;
98
- this.owner.setAttribute('tabindex', 0);
99
- this.listenForEvents();
100
- this.zoomAbs(this.transform.x, this.transform.y, this.transform.scale);
101
- },
102
- applyTransform() {
103
- this.isDirty = false;
104
- this.domElement.style.transformOrigin = '0 0 0';
105
- this.domElement.style.transform = 'matrix(' +
106
- this.transform.scale + ', 0, 0, ' +
107
- this.transform.scale + ', ' +
108
- this.transform.x + ', ' + this.transform.y + ')';
109
- this.frameAnimation = 0;
110
- },
111
- pause() {
112
- this.releaseEvents();
113
- this.paused = true;
114
- },
115
- resume() {
116
- if (this.paused) {
117
- this.listenForEvents();
118
- this.paused = false;
119
- }
120
- },
121
- listenForEvents() {
122
- this.owner.addEventListener('mousedown', this.onMouseDown, {passive: false});
123
- this.owner.addEventListener('dblclick', this.onDoubleClick, {passive: false});
124
- this.owner.addEventListener('touchstart', this.onTouch, {passive: false});
125
- this.owner.addEventListener('keydown', this.onKeyDown, {passive: false});
126
- this.owner.addEventListener('wheel', this.onMouseWheel, {passive: false});
127
- this.makeDirty();
128
- },
129
- transformToScreen(x, y) {
130
- this.storedCTMResult.x = x;
131
- this.storedCTMResult.y = y;
132
- return this.storedCTMResult;
133
- },
134
- moveTo(dx, dy) {
135
- if (this.disableMove) return;
136
- this.transform.x += dx;
137
- this.transform.y += dy;
138
- this.$emit('move', [dx, dy])
139
- this.makeDirty();
140
- },
141
- makeDirty() {
142
- this.isDirty = true;
143
- this.frameAnimation = window.requestAnimationFrame(this.frame);
144
- },
145
- ease() {
146
- this.inZoom = true
147
- setTimeout(() => {
148
- this.inZoom = false
149
- }, 500)
150
- },
151
- zoomByRatio(clientX, clientY, ratio, ease = false) {
152
- if (this.disableZoom) return;
153
- if (ease) this.ease();
154
- if (this.isNaN(clientX) || this.isNaN(clientY) || this.isNaN(ratio)) {
155
- throw new Error('zoom requires valid numbers');
156
- }
157
412
 
158
- let newScale = this.transform.scale * ratio;
413
+ lastTouchEndTime.value = now
414
+ releaseTouches()
415
+ }
416
+ }
159
417
 
160
- if (newScale < this.minZoom) {
161
- if (this.transform.scale === this.minZoom) return;
418
+ const getPinchZoomLength = (finger1, finger2) => {
419
+ let dx = finger1.clientX - finger2.clientX
420
+ let dy = finger1.clientY - finger2.clientY
421
+ return Math.sqrt(dx * dx + dy * dy)
422
+ }
162
423
 
163
- ratio = this.minZoom / this.transform.scale;
164
- }
165
- if (newScale > this.maxZoom) {
166
- if (this.transform.scale === this.maxZoom) return;
424
+ const onDoubleClick = (e) => {
425
+ e.preventDefault()
426
+ e.stopPropagation()
427
+ let offset = getOffsetXY(e)
428
+ if (transformOrigin.value) {
429
+ offset = getTransformOriginOffset.value
430
+ }
431
+ let scaleMultiplier = getScaleMultiplier(-1000)
432
+ zoomByRatio(offset.x, offset.y, scaleMultiplier, true)
433
+ }
167
434
 
168
- ratio = this.maxZoom / this.transform.scale;
169
- }
435
+ const onMouseDown = (e) => {
436
+ if (touchInProgress.value) {
437
+ e.stopPropagation()
438
+ return false
439
+ }
440
+ let isLeftButton = (e.button === 1 && window.event !== null) || e.button === 0
441
+ if (!isLeftButton) return
170
442
 
171
- let size = this.transformToScreen(clientX, clientY);
172
-
173
- this.transform.x = size.x - ratio * (size.x - this.transform.x);
174
- this.transform.y = size.y - ratio * (size.y - this.transform.y);
175
-
176
- this.transform.scale *= ratio;
177
-
178
- this.$emit('zoom', [clientX, clientY, ratio]);
179
-
180
- this.makeDirty();
181
- },
182
- zoomAbs(clientX, clientY, zoomLevel) {
183
- let ratio = zoomLevel / this.transform.scale;
184
- this.zoomByRatio(clientX, clientY, ratio);
185
- },
186
- frame() {
187
- if (this.isDirty) this.applyTransform();
188
- },
189
- onKeyDown(e) {
190
- let x = 0,
191
- y = 0,
192
- z = 0;
193
- if (e.keyCode === 38) {
194
- y = -1; // up
195
- } else if (e.keyCode === 40) {
196
- y = 1; // down
197
- } else if (e.keyCode === 37) {
198
- x = -1; // left
199
- } else if (e.keyCode === 39) {
200
- x = 1; // right
201
- } else if (e.keyCode === 189 || e.keyCode === 109) {
202
- // DASH or SUBTRACT
203
- z = 1; // `-` - zoom out
204
- } else if (e.keyCode === 187 || e.keyCode === 107) {
205
- // EQUAL SIGN or ADD
206
- z = -1; // `=` - zoom in (equal sign on US layout is under `+`)
207
- }
443
+ let offset = getOffsetXY(e)
444
+ let point = transformToScreen(offset.x, offset.y)
445
+ mouseX.value = point.x
446
+ mouseY.value = point.y
208
447
 
209
- if (x || y) {
210
- e.preventDefault();
211
- e.stopPropagation();
448
+ document.addEventListener('mousemove', onMouseMove)
449
+ document.addEventListener('mouseup', onMouseUp)
212
450
 
213
- let clientRect = this.owner.getBoundingClientRect();
451
+ return false
452
+ }
214
453
 
215
- let offset = Math.min(clientRect.width, clientRect.height);
216
- let moveSpeedRatio = 0.05;
217
- let dx = offset * moveSpeedRatio * x;
218
- let dy = offset * moveSpeedRatio * y;
454
+ const onMouseMove = (e) => {
455
+ if (touchInProgress.value) return
219
456
 
220
- this.moveTo(dx, dy);
221
- }
457
+ let offset = getOffsetXY(e)
458
+ let point = transformToScreen(offset.x, offset.y)
459
+ let dx = point.x - mouseX.value
460
+ let dy = point.y - mouseY.value
222
461
 
223
- if (z) {
224
- let scaleMultiplier = this.getScaleMultiplier(z * 100);
225
- let offset = this.transformOrigin ? this.getTransformOriginOffset : this.midPoint;
226
- this.zoomByRatio(offset.x, offset.y, scaleMultiplier);
227
- }
228
- },
229
- onTouch(e) {
230
- if (e.touches.length === 1) {
231
- return this.handleSingleFingerTouch(e, e.touches[0]);
232
- } else if (e.touches.length === 2) {
233
- // handleTouchMove() will care about pinch zoom.
234
- this.pinchZoomLength = this.getPinchZoomLength(e.touches[0], e.touches[1]);
235
- this.multiTouch = true;
236
- this.startTouchListenerIfNeeded();
237
- }
238
- },
239
- handleSingleFingerTouch(e) {
240
- let touch = e.touches[0];
241
- let offset = this.getOffsetXY(touch);
242
- this.lastSingleFingerOffset = offset;
243
- let point = this.transformToScreen(offset.x, offset.y);
244
- this.mouseX = point.x;
245
- this.mouseY = point.y;
246
-
247
- this.startTouchListenerIfNeeded();
248
- },
249
- startTouchListenerIfNeeded() {
250
- if (this.touchInProgress) {
251
- return;
252
- }
462
+ mouseX.value = point.x
463
+ mouseY.value = point.y
464
+ moveTo(dx, dy)
465
+ }
253
466
 
254
- this.touchInProgress = true;
255
- document.addEventListener('touchmove', this.handleTouchMove, {passive: false});
256
- document.addEventListener('touchend', this.handleTouchEnd);
257
- document.addEventListener('touchcancel', this.handleTouchEnd);
258
- },
259
- handleTouchMove(e) {
260
- e.stopPropagation();
261
- e.preventDefault();
262
- if (e.touches.length === 1) {
263
- let touch = e.touches[0];
264
-
265
- let offset = this.getOffsetXY(touch);
266
- let point = this.transformToScreen(offset.x, offset.y);
267
-
268
- let dx = point.x - this.mouseX;
269
- let dy = point.y - this.mouseY;
270
-
271
- this.mouseX = point.x;
272
- this.mouseY = point.y;
273
- this.moveTo(dx, dy);
274
- } else if (e.touches.length === 2) {
275
- // it's a zoom, let's find direction
276
- this.multiTouch = true;
277
- let t1 = e.touches[0];
278
- let t2 = e.touches[1];
279
- let currentPinchLength = this.getPinchZoomLength(t1, t2);
280
-
281
- let scaleMultiplier =
282
- 1 + (currentPinchLength / this.pinchZoomLength - 1);
283
-
284
- let firstTouchPoint = this.getOffsetXY(t1);
285
- let secondTouchPoint = this.getOffsetXY(t2);
286
- this.mouseX = (firstTouchPoint.x + secondTouchPoint.x) / 2;
287
- this.mouseY = (firstTouchPoint.y + secondTouchPoint.y) / 2;
288
- if (this.transformOrigin) {
289
- let offset = this.getTransformOriginOffset;
290
- this.mouseX = offset.x;
291
- this.mouseY = offset.y;
292
- }
293
-
294
- this.zoomByRatio(this.mouseX, this.mouseY, scaleMultiplier);
295
-
296
- this.pinchZoomLength = currentPinchLength;
297
- }
298
- },
299
- handleTouchEnd(e) {
300
- if (e.touches.length > 0) {
301
- let offset = this.getOffsetXY(e.touches[0]);
302
- let point = this.transformToScreen(offset.x, offset.y);
303
- this.mouseX = point.x;
304
- this.mouseY = point.y;
305
- } else {
306
- let now = new Date();
307
- if (now - this.lastTouchEndTime < 300) {
308
- if (this.transformOrigin) {
309
- let offset = this.getTransformOriginOffset;
310
- this.zoomByRatio(offset.x, offset.y, this.transform.scale);
311
- } else {
312
- // We want untransformed x/y here.
313
- this.zoomByRatio(this.lastSingleFingerOffset.x, this.lastSingleFingerOffset.y, this.transform.scale);
314
- }
315
- }
316
-
317
- this.lastTouchEndTime = now;
318
- this.releaseTouches();
319
- }
320
- },
321
- getPinchZoomLength(finger1, finger2) {
322
- let dx = finger1.clientX - finger2.clientX;
323
- let dy = finger1.clientY - finger2.clientY;
324
- return Math.sqrt(dx * dx + dy * dy);
325
- },
326
- onDoubleClick(e) {
327
- e.preventDefault()
328
- e.stopPropagation()
329
- let offset = this.getOffsetXY(e);
330
- if (this.transformOrigin) {
331
- offset = this.getTransformOriginOffset;
332
- }
333
- let scaleMultiplier = this.getScaleMultiplier(-1000);
334
- this.zoomByRatio(offset.x, offset.y, scaleMultiplier, true);
335
- },
336
- onMouseDown(e) {
337
- if (this.touchInProgress) {
338
- e.stopPropagation();
339
- return false;
340
- }
341
- let isLeftButton =
342
- (e.button === 1 && window.event !== null) || e.button === 0;
343
- if (!isLeftButton) return;
344
-
345
- let offset = this.getOffsetXY(e);
346
- let point = this.transformToScreen(offset.x, offset.y);
347
- this.mouseX = point.x;
348
- this.mouseY = point.y;
349
-
350
- document.addEventListener('mousemove', this.onMouseMove);
351
- document.addEventListener('mouseup', this.onMouseUp);
352
-
353
- return false;
354
- },
355
- onMouseMove(e) {
356
- if (this.touchInProgress) return;
357
-
358
- let offset = this.getOffsetXY(e);
359
- let point = this.transformToScreen(offset.x, offset.y);
360
- let dx = point.x - this.mouseX;
361
- let dy = point.y - this.mouseY;
362
-
363
- this.mouseX = point.x;
364
- this.mouseY = point.y;
365
- this.moveTo(dx, dy);
366
- },
367
- onMouseUp() {
368
- this.releaseDocumentMouse();
369
- },
370
- onMouseWheel(e) {
371
- let delta = e.deltaY;
372
- if (e.deltaMode > 0) delta *= 100;
373
-
374
- let scaleMultiplier = this.getScaleMultiplier(delta);
375
-
376
- if (scaleMultiplier !== 1) {
377
- let offset = this.transformOrigin
378
- ? this.getTransformOriginOffset
379
- : this.getOffsetXY(e);
380
- this.zoomByRatio(offset.x, offset.y, scaleMultiplier);
381
- e.preventDefault();
382
- }
383
- },
384
- getOffsetXY(e) {
385
- let offsetX, offsetY;
386
- let ownerRect = this.owner.getBoundingClientRect();
387
- offsetX = e.clientX - ownerRect.left;
388
- offsetY = e.clientY - ownerRect.top;
389
-
390
- return {x: offsetX, y: offsetY};
391
- },
392
- getScaleMultiplier(delta) {
393
- let sign = Math.sign(delta);
394
- let deltaAdjustedSpeed = Math.min(0.25, Math.abs(delta / 128));
395
- return 1 - sign * deltaAdjustedSpeed;
396
- },
397
- isNumber(x) {
398
- return Number.isFinite(x);
399
- },
400
- isNaN(value) {
401
- if (Number.isNaN) {
402
- return Number.isNaN(value);
403
- }
467
+ const onMouseUp = () => {
468
+ releaseDocumentMouse()
469
+ }
404
470
 
405
- return value !== value;
406
- },
407
- releaseEvents() {
408
- this.owner.removeEventListener('wheel', this.onMouseWheel);
409
- this.owner.removeEventListener('mousedown', this.onMouseDown);
410
- this.owner.removeEventListener('keydown', this.onKeyDown);
411
- this.owner.removeEventListener('dblclick', this.onDoubleClick);
412
- this.owner.removeEventListener('touchstart', this.onTouch);
413
-
414
- if (this.frameAnimation) {
415
- window.cancelAnimationFrame(this.frameAnimation);
416
- this.frameAnimation = 0;
417
- }
471
+ const onMouseWheel = (e) => {
472
+ let delta = e.deltaY
473
+ if (e.deltaMode > 0) delta *= 100
418
474
 
475
+ let scaleMultiplier = getScaleMultiplier(delta)
419
476
 
420
- this.releaseDocumentMouse();
421
- this.releaseTouches();
422
- },
423
- releaseDocumentMouse() {
424
- document.removeEventListener('mousemove', this.onMouseMove);
425
- document.removeEventListener('mouseup', this.onMouseUp);
426
- },
427
- releaseTouches() {
428
- document.removeEventListener('touchmove', this.handleTouchMove);
429
- document.removeEventListener('touchend', this.handleTouchEnd);
430
- document.removeEventListener('touchcancel', this.handleTouchEnd);
431
- this.multiTouch = false;
432
- this.touchInProgress = false;
433
- },
434
- },
435
- beforeUnmount() {
436
- this.releaseEvents();
477
+ if (scaleMultiplier !== 1) {
478
+ let offset = transformOrigin.value
479
+ ? getTransformOriginOffset.value
480
+ : getOffsetXY(e)
481
+ zoomByRatio(offset.x, offset.y, scaleMultiplier)
482
+ e.preventDefault()
483
+ }
484
+ }
485
+
486
+ const getOffsetXY = (e) => {
487
+ let offsetX, offsetY
488
+ if (!owner.value) return {x: 0, y: 0}
489
+
490
+ let ownerRect = owner.value.getBoundingClientRect()
491
+ offsetX = e.clientX - ownerRect.left
492
+ offsetY = e.clientY - ownerRect.top
493
+
494
+ return {x: offsetX, y: offsetY}
495
+ }
496
+
497
+ const getScaleMultiplier = (delta) => {
498
+ let sign = Math.sign(delta)
499
+ let deltaAdjustedSpeed = Math.min(0.25, Math.abs(delta / 128))
500
+ return 1 - sign * deltaAdjustedSpeed
501
+ }
502
+
503
+ const isNumber = (x) => {
504
+ return Number.isFinite(x)
505
+ }
506
+
507
+ const releaseEvents = () => {
508
+ if (!owner.value) return
509
+
510
+ owner.value.removeEventListener('wheel', onMouseWheel)
511
+ owner.value.removeEventListener('mousedown', onMouseDown)
512
+ owner.value.removeEventListener('keydown', onKeyDown)
513
+ owner.value.removeEventListener('dblclick', onDoubleClick)
514
+ owner.value.removeEventListener('touchstart', onTouch)
515
+
516
+ if (frameAnimation.value) {
517
+ window.cancelAnimationFrame(frameAnimation.value)
518
+ frameAnimation.value = 0
437
519
  }
520
+
521
+ releaseDocumentMouse()
522
+ releaseTouches()
523
+ }
524
+
525
+ const releaseDocumentMouse = () => {
526
+ document.removeEventListener('mousemove', onMouseMove)
527
+ document.removeEventListener('mouseup', onMouseUp)
528
+ }
529
+
530
+ const releaseTouches = () => {
531
+ document.removeEventListener('touchmove', handleTouchMove)
532
+ document.removeEventListener('touchend', handleTouchEnd)
533
+ document.removeEventListener('touchcancel', handleTouchEnd)
534
+ multiTouch.value = false
535
+ touchInProgress.value = false
438
536
  }
537
+
538
+ onMounted(() => {
539
+ builder()
540
+ })
541
+
542
+ onBeforeUnmount(() => {
543
+ releaseEvents()
544
+ })
545
+
546
+ defineExpose({
547
+ /** Pauses all interaction events */
548
+ pause,
549
+ /** Resumes interaction events */
550
+ resume,
551
+ /**
552
+ * Moves the content by specified delta
553
+ * @param {Number} dx - X-axis movement delta
554
+ * @param {Number} dy - Y-axis movement delta
555
+ */
556
+ moveTo,
557
+ /**
558
+ * Zooms by ratio from specific point
559
+ * @param {Number} clientX - X coordinate to zoom from
560
+ * @param {Number} clientY - Y coordinate to zoom from
561
+ * @param {Number} ratio - Zoom ratio
562
+ * @param {Boolean} easeFlag - Whether to trigger ease animation
563
+ */
564
+ zoomByRatio
565
+ })
439
566
  </script>
440
567
  <style lang="scss">
441
568
  @use "sass:map";
442
- @use "../../style/variables/base";
569
+ @use "../../style" as *;
443
570
 
444
571
 
445
- .#{base.$prefix}float {
572
+ .#{$prefix}float {
446
573
  width: 100%;
447
574
  max-width: 100%;
448
575
  max-height: 100vh;
449
576
  height: 100%;
450
577
  overflow: hidden;
451
578
  outline: none;
452
- border-radius: map.get(base.$borders, 'sm');
579
+ border-radius: map.get($borders, 'sm');
453
580
 
454
581
  &.float-bordered {
455
- border: 1px solid #3a3e3a;
582
+ border: 1px solid var(--color-border);
456
583
  }
457
584
 
458
585
  .float-container {