purgetss 7.4.0 → 7.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -71
- package/assets/fonts/FontAwesome7Brands-Regular.ttf +0 -0
- package/assets/fonts/FontAwesome7Free-Regular.ttf +0 -0
- package/assets/fonts/FontAwesome7Free-Solid.ttf +0 -0
- package/dist/fontawesome.js +55 -1
- package/dist/fontawesome.tss +55 -1
- package/dist/purgetss.ui.js +495 -26
- package/dist/utilities.tss +79 -68
- package/experimental/completions2.js +27 -12
- package/lib/templates/fontawesome/free-template.js.cjs +1 -1
- package/lib/templates/fontawesome/free-template.tss +1 -1
- package/lib/templates/purgetss.ui.js.cjs +487 -18
- package/package.json +2 -2
- package/src/core/builders/tailwind-builder.js +1 -0
- package/src/core/builders/tailwind-helpers.js +19 -9
- package/src/fonts/Font Awesome 7 Brands-Regular-400.otf +0 -0
- package/src/fonts/Font Awesome 7 Free-Regular-400.otf +0 -0
- package/src/fonts/Font Awesome 7 Free-Solid-900.otf +0 -0
- package/src/shared/helpers/animation.js +22 -0
- package/src/shared/helpers/utils.js +65 -6
package/dist/purgetss.ui.js
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
|
-
// PurgeTSS v7.
|
|
1
|
+
// PurgeTSS v7.5.1
|
|
2
2
|
// Created by César Estrada
|
|
3
3
|
// https://purgetss.com
|
|
4
4
|
|
|
5
5
|
function Animation(args = {}) {
|
|
6
6
|
const params = {
|
|
7
|
+
// Global
|
|
7
8
|
id: args.id,
|
|
9
|
+
debug: args.debug ?? false,
|
|
10
|
+
isIOS: Ti.Platform.osname === 'iphone' || Ti.Platform.osname === 'ipad',
|
|
11
|
+
|
|
12
|
+
// Play / Toggle / Sequence
|
|
8
13
|
open: false,
|
|
9
|
-
draggables: [],
|
|
10
14
|
playing: false,
|
|
11
15
|
delay: args.delay ?? 0,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
hasTransformation: (args.scale !== undefined || args.rotate !== undefined),
|
|
17
|
+
|
|
18
|
+
// Draggable
|
|
19
|
+
draggables: [],
|
|
20
|
+
|
|
21
|
+
// Collision Detection
|
|
22
|
+
collisionViews: [],
|
|
23
|
+
dragCB: null,
|
|
24
|
+
dropCB: null,
|
|
25
|
+
lastHoverTarget: null,
|
|
26
|
+
lastKnownTarget: null
|
|
15
27
|
}
|
|
16
28
|
|
|
17
29
|
logger('Create Animation View: ' + params.id)
|
|
@@ -42,6 +54,242 @@ function Animation(args = {}) {
|
|
|
42
54
|
makeViewsDraggable(_views)
|
|
43
55
|
}
|
|
44
56
|
|
|
57
|
+
animationView.detectCollisions = (views, _dragCB, _dropCB) => {
|
|
58
|
+
if (params.debug) { console.log('') }
|
|
59
|
+
logger('`detectCollisions` method called on: ' + params.id)
|
|
60
|
+
if (_dragCB) params.dragCB = _dragCB
|
|
61
|
+
if (_dropCB) params.dropCB = _dropCB
|
|
62
|
+
const arr = Array.isArray(views) ? views : [views]
|
|
63
|
+
arr.forEach(view => {
|
|
64
|
+
view._collisionEnabled = true
|
|
65
|
+
if (!params.collisionViews.includes(view)) {
|
|
66
|
+
params.collisionViews.push(view)
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolvePosition(view) {
|
|
72
|
+
if (view._originTop !== undefined) return { top: view._originTop, left: view._originLeft }
|
|
73
|
+
if (view.top !== undefined && view.top !== null && view.left !== undefined && view.left !== null) return { top: view.top, left: view.left }
|
|
74
|
+
const r = view.rect
|
|
75
|
+
return { top: r.y, left: r.x }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function normalizePosition(view) {
|
|
79
|
+
const pos = resolvePosition(view)
|
|
80
|
+
view.applyProperties({ top: pos.top, left: pos.left, right: null, bottom: null })
|
|
81
|
+
view._originTop = pos.top
|
|
82
|
+
view._originLeft = pos.left
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
animationView.swap = (view1, view2) => {
|
|
86
|
+
if (params.debug) { console.log('') }
|
|
87
|
+
logger('`swap` method called on: ' + params.id)
|
|
88
|
+
|
|
89
|
+
// Cancel any pending bounce-back animations
|
|
90
|
+
;[view1, view2].forEach(v => {
|
|
91
|
+
if (v._bouncingBack) {
|
|
92
|
+
logger(` -> cancelling bounce-back for ${v.id} before swap`)
|
|
93
|
+
v.applyProperties({ top: v._originTop, left: v._originLeft, transform: Ti.UI.createMatrix2D() })
|
|
94
|
+
v._bouncingBack = false
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
// Read REAL positions — rect gives actual rendered position, no stale variables
|
|
99
|
+
const targetRect = view2.rect
|
|
100
|
+
const sourceHome = { top: view1._originTop ?? view1.top, left: view1._originLeft ?? view1.left }
|
|
101
|
+
|
|
102
|
+
// Source goes to target's real position, target goes to source's home
|
|
103
|
+
const dest1Top = targetRect.y
|
|
104
|
+
const dest1Left = targetRect.x
|
|
105
|
+
const dest2Top = sourceHome.top
|
|
106
|
+
const dest2Left = sourceHome.left
|
|
107
|
+
|
|
108
|
+
logger(` -> ${view1.id}: home(${sourceHome.top}, ${sourceHome.left}) → dest(${dest1Top}, ${dest1Left})`)
|
|
109
|
+
logger(` -> ${view2.id}: rect(${targetRect.y}, ${targetRect.x}) → dest(${dest2Top}, ${dest2Left})`)
|
|
110
|
+
|
|
111
|
+
const maxZ = params.draggables.length
|
|
112
|
+
view1.zIndex = maxZ + 1
|
|
113
|
+
view2.zIndex = maxZ
|
|
114
|
+
|
|
115
|
+
view1.animate({
|
|
116
|
+
...args, left: dest1Left, top: dest1Top, transform: Ti.UI.createMatrix2D()
|
|
117
|
+
}, () => {
|
|
118
|
+
view1.applyProperties({ left: dest1Left, top: dest1Top, transform: Ti.UI.createMatrix2D() })
|
|
119
|
+
params.draggables.forEach((d, k) => { d.zIndex = k })
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
view2.animate({
|
|
123
|
+
...args, left: dest2Left, top: dest2Top
|
|
124
|
+
}, () => {
|
|
125
|
+
view2.applyProperties({ left: dest2Left, top: dest2Top })
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
view1._originTop = dest1Top
|
|
129
|
+
view1._originLeft = dest1Left
|
|
130
|
+
view2._originTop = dest2Top
|
|
131
|
+
view2._originLeft = dest2Left
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
animationView.sequence = (_views, _cb) => {
|
|
135
|
+
if (params.debug) { console.log('') }
|
|
136
|
+
logger('`sequence` method called on: ' + params.id)
|
|
137
|
+
const views = Array.isArray(_views) ? _views : [_views]
|
|
138
|
+
const total = views.length
|
|
139
|
+
|
|
140
|
+
params.open = !params.open
|
|
141
|
+
chooseAnimationBasedOnState('play')
|
|
142
|
+
|
|
143
|
+
function animateNext(index) {
|
|
144
|
+
if (index >= total) { return }
|
|
145
|
+
const isLast = index === total - 1
|
|
146
|
+
playView(views[index], (e) => {
|
|
147
|
+
if (isLast && typeof _cb === 'function') {
|
|
148
|
+
_cb(e)
|
|
149
|
+
} else {
|
|
150
|
+
animateNext(index + 1)
|
|
151
|
+
}
|
|
152
|
+
}, 'play', index, total)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
animateNext(0)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
animationView.shake = (view, intensity = 10) => {
|
|
159
|
+
if (params.debug) { console.log('') }
|
|
160
|
+
logger('`shake` method called on: ' + params.id)
|
|
161
|
+
if (!view) { return notFound() }
|
|
162
|
+
|
|
163
|
+
view.applyProperties({ transform: Ti.UI.createMatrix2D().translate(-intensity, 0) })
|
|
164
|
+
|
|
165
|
+
view.animate({
|
|
166
|
+
...args,
|
|
167
|
+
transform: Ti.UI.createMatrix2D().translate(intensity, 0),
|
|
168
|
+
duration: Math.round((args.duration ?? 400) / 6),
|
|
169
|
+
autoreverse: true,
|
|
170
|
+
repeat: 3,
|
|
171
|
+
curve: Ti.UI.ANIMATION_CURVE_EASE_IN_OUT
|
|
172
|
+
}, () => {
|
|
173
|
+
view.applyProperties({ transform: Ti.UI.createMatrix2D() })
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
animationView.pulse = (view, count = 1) => {
|
|
178
|
+
if (params.debug) { console.log('') }
|
|
179
|
+
logger('`pulse` method called on: ' + params.id)
|
|
180
|
+
if (!view) { return notFound() }
|
|
181
|
+
|
|
182
|
+
view.animate({
|
|
183
|
+
...args,
|
|
184
|
+
transform: args.transform ?? Ti.UI.createMatrix2D().scale(1.2),
|
|
185
|
+
autoreverse: true,
|
|
186
|
+
repeat: count,
|
|
187
|
+
curve: Ti.UI.ANIMATION_CURVE_EASE_IN_OUT
|
|
188
|
+
}, () => {
|
|
189
|
+
view.applyProperties({ transform: Ti.UI.createMatrix2D() })
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
animationView.snapTo = (view, targets) => {
|
|
194
|
+
if (params.debug) { console.log('') }
|
|
195
|
+
logger('`snapTo` method called on: ' + params.id)
|
|
196
|
+
if (!view) { return notFound() }
|
|
197
|
+
|
|
198
|
+
const arr = Array.isArray(targets) ? targets : [targets]
|
|
199
|
+
const vr = view.rect
|
|
200
|
+
const vcx = (view._visualLeft ?? view.left) + vr.width / 2
|
|
201
|
+
const vcy = (view._visualTop ?? view.top) + vr.height / 2
|
|
202
|
+
|
|
203
|
+
let closest = null
|
|
204
|
+
let minDist = Infinity
|
|
205
|
+
|
|
206
|
+
arr.forEach(target => {
|
|
207
|
+
if (target === view) { return }
|
|
208
|
+
const tr = target.rect
|
|
209
|
+
const tcx = tr.x + tr.width / 2
|
|
210
|
+
const tcy = tr.y + tr.height / 2
|
|
211
|
+
const dist = Math.sqrt((vcx - tcx) ** 2 + (vcy - tcy) ** 2)
|
|
212
|
+
if (dist < minDist) {
|
|
213
|
+
minDist = dist
|
|
214
|
+
closest = target
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
if (!closest) { return null }
|
|
219
|
+
|
|
220
|
+
const cr = closest.rect
|
|
221
|
+
normalizePosition(closest)
|
|
222
|
+
const destLeft = closest._originLeft + (cr.width - vr.width) / 2
|
|
223
|
+
const destTop = closest._originTop + (cr.height - vr.height) / 2
|
|
224
|
+
|
|
225
|
+
view.animate({
|
|
226
|
+
...args, left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D()
|
|
227
|
+
}, () => {
|
|
228
|
+
view.applyProperties({ left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D() })
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
view._originTop = destTop
|
|
232
|
+
view._originLeft = destLeft
|
|
233
|
+
|
|
234
|
+
return closest
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
animationView.reorder = (views, newOrder) => {
|
|
238
|
+
if (params.debug) { console.log('') }
|
|
239
|
+
logger('`reorder` method called on: ' + params.id)
|
|
240
|
+
const arr = Array.isArray(views) ? views : [views]
|
|
241
|
+
if (newOrder.length !== arr.length) { return }
|
|
242
|
+
|
|
243
|
+
arr.forEach(v => normalizePosition(v))
|
|
244
|
+
|
|
245
|
+
const positions = arr.map(v => ({
|
|
246
|
+
left: v._originLeft,
|
|
247
|
+
top: v._originTop
|
|
248
|
+
}))
|
|
249
|
+
|
|
250
|
+
arr.forEach((view, i) => {
|
|
251
|
+
const dest = positions[newOrder[i]]
|
|
252
|
+
|
|
253
|
+
view.animate({
|
|
254
|
+
...args, left: dest.left, top: dest.top, transform: Ti.UI.createMatrix2D()
|
|
255
|
+
}, () => {
|
|
256
|
+
view.applyProperties({ left: dest.left, top: dest.top, transform: Ti.UI.createMatrix2D() })
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
view._originTop = dest.top
|
|
260
|
+
view._originLeft = dest.left
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
animationView.undraggable = (_views) => {
|
|
265
|
+
if (params.debug) { console.log('') }
|
|
266
|
+
logger('`undraggable` method called on: ' + params.id)
|
|
267
|
+
const arr = Array.isArray(_views) ? _views : [_views]
|
|
268
|
+
|
|
269
|
+
arr.forEach(view => {
|
|
270
|
+
if (view._dragListeners) {
|
|
271
|
+
view.removeEventListener('touchstart', view._dragListeners.onTouchStart)
|
|
272
|
+
view.removeEventListener('touchend', view._dragListeners.onTouchEnd)
|
|
273
|
+
view.removeEventListener('touchmove', view._dragListeners.onTouchMove)
|
|
274
|
+
Ti.Gesture.removeEventListener('orientationchange', view._dragListeners.onOrientationChange)
|
|
275
|
+
delete view._dragListeners
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const idx = params.draggables.indexOf(view)
|
|
279
|
+
if (idx !== -1) { params.draggables.splice(idx, 1) }
|
|
280
|
+
|
|
281
|
+
const cIdx = params.collisionViews.indexOf(view)
|
|
282
|
+
if (cIdx !== -1) { params.collisionViews.splice(cIdx, 1) }
|
|
283
|
+
|
|
284
|
+
delete view._originTop
|
|
285
|
+
delete view._originLeft
|
|
286
|
+
delete view._visualTop
|
|
287
|
+
delete view._visualLeft
|
|
288
|
+
delete view._collisionEnabled
|
|
289
|
+
delete view._bouncingBack
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
|
|
45
293
|
animationView.open = (_views, _cb) => {
|
|
46
294
|
if (params.debug) { console.log('') }
|
|
47
295
|
logger('`open` method called on: ' + params.id)
|
|
@@ -54,6 +302,54 @@ function Animation(args = {}) {
|
|
|
54
302
|
mainPlayApplyFn(_views, _cb, 'play', 'close')
|
|
55
303
|
}
|
|
56
304
|
|
|
305
|
+
// Mac Catalyst note: Parent containers of transitioned views should use fixed
|
|
306
|
+
// dimensions (not Ti.UI.FILL). Resizable containers trigger a UIKit re-layout
|
|
307
|
+
// that distorts views with rotated Matrix2D transforms.
|
|
308
|
+
animationView.transition = (views, layouts) => {
|
|
309
|
+
if (params.debug) { console.log('') }
|
|
310
|
+
logger('`transition` method called on: ' + params.id)
|
|
311
|
+
|
|
312
|
+
const arr = Array.isArray(views) ? views : [views]
|
|
313
|
+
|
|
314
|
+
arr.forEach((view, i) => {
|
|
315
|
+
const layout = layouts[i]
|
|
316
|
+
|
|
317
|
+
if (!layout) {
|
|
318
|
+
view.animate(Ti.UI.createAnimation({ ...args, zIndex: 0, opacity: 0 }), () => {
|
|
319
|
+
view.applyProperties({ zIndex: 0, opacity: 0, transform: Ti.UI.createMatrix2D(), translation: { x: 0, y: 0 }, rotate: 0, scale: 1 })
|
|
320
|
+
})
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const tx = layout.translation?.x ?? 0
|
|
325
|
+
const ty = layout.translation?.y ?? 0
|
|
326
|
+
const rotate = layout.rotate ?? 0
|
|
327
|
+
const scale = layout.scale ?? 1
|
|
328
|
+
|
|
329
|
+
const transform = Ti.UI.createMatrix2D().translate(tx, ty).rotate(rotate).scale(scale)
|
|
330
|
+
|
|
331
|
+
const needsFadeIn = view.opacity === 0
|
|
332
|
+
|
|
333
|
+
if (layout.zIndex !== undefined) view.zIndex = layout.zIndex
|
|
334
|
+
|
|
335
|
+
const animation = Ti.UI.createAnimation({
|
|
336
|
+
...args,
|
|
337
|
+
transform
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
if (needsFadeIn) animation.opacity = 1
|
|
341
|
+
if (layout.width !== undefined) animation.width = layout.width
|
|
342
|
+
if (layout.height !== undefined) animation.height = layout.height
|
|
343
|
+
if (layout.opacity !== undefined) animation.opacity = layout.opacity
|
|
344
|
+
|
|
345
|
+
view.animate(animation, () => {
|
|
346
|
+
const props = { transform, translation: { x: tx, y: ty }, rotate, scale, zIndex: layout.zIndex }
|
|
347
|
+
if (needsFadeIn) props.opacity = 1
|
|
348
|
+
view.applyProperties(props)
|
|
349
|
+
})
|
|
350
|
+
})
|
|
351
|
+
}
|
|
352
|
+
|
|
57
353
|
function handleTransformations(args) {
|
|
58
354
|
if ('anchorPoint' in args || 'rotate' in args || 'scale' in args) {
|
|
59
355
|
logger(' -> Creating transform')
|
|
@@ -125,19 +421,113 @@ function Animation(args = {}) {
|
|
|
125
421
|
let offsetX, offsetY
|
|
126
422
|
setBounds(draggableView, args.bounds)
|
|
127
423
|
|
|
128
|
-
|
|
424
|
+
const onTouchStart = (event) => {
|
|
129
425
|
offsetX = event.x
|
|
130
426
|
offsetY = event.y
|
|
427
|
+
draggableView._wasDragged = false
|
|
428
|
+
|
|
429
|
+
// If a bounce-back animation is still running, complete it immediately
|
|
430
|
+
if (draggableView._bouncingBack) {
|
|
431
|
+
logger(` -> completing pending bounce-back for ${draggableView.id}`)
|
|
432
|
+
draggableView.applyProperties({
|
|
433
|
+
top: draggableView._originTop,
|
|
434
|
+
left: draggableView._originLeft,
|
|
435
|
+
transform: Ti.UI.createMatrix2D()
|
|
436
|
+
})
|
|
437
|
+
draggableView._bouncingBack = false
|
|
438
|
+
}
|
|
131
439
|
|
|
132
440
|
updateDraggableZIndex(event)
|
|
133
441
|
checkDraggable(draggableView, 'drag')
|
|
134
|
-
})
|
|
135
442
|
|
|
136
|
-
|
|
443
|
+
if (draggableView._collisionEnabled) {
|
|
444
|
+
if (draggableView._originTop === undefined) {
|
|
445
|
+
draggableView._originTop = draggableView.top
|
|
446
|
+
draggableView._originLeft = draggableView.left
|
|
447
|
+
logger(` -> touchStart origin capture (first): ${draggableView.id} top=${draggableView.top} left=${draggableView.left}`)
|
|
448
|
+
} else {
|
|
449
|
+
logger(` -> touchStart origin kept: ${draggableView.id} origin=(${draggableView._originTop}, ${draggableView._originLeft}) vs top/left=(${draggableView.top}, ${draggableView.left})`)
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
137
453
|
|
|
138
|
-
|
|
454
|
+
const onTouchEnd = () => {
|
|
455
|
+
checkDraggable(draggableView, 'drop')
|
|
139
456
|
|
|
140
|
-
|
|
457
|
+
// Android: consolidate transform after drag so transition reads correct state
|
|
458
|
+
if (!params.isIOS && draggableView.translation) {
|
|
459
|
+
const { translation, rotate, scale } = draggableView
|
|
460
|
+
draggableView.applyProperties({
|
|
461
|
+
translation, rotate, scale,
|
|
462
|
+
transform: Ti.UI.createMatrix2D().translate(translation.x, translation.y).rotate(rotate ?? 0).scale(scale ?? 1)
|
|
463
|
+
})
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (draggableView._collisionEnabled) {
|
|
467
|
+
const directTarget = checkCollision(draggableView)
|
|
468
|
+
const target = directTarget ?? params.lastKnownTarget
|
|
469
|
+
logger(` -> collision check: ${draggableView.id} | direct: ${directTarget?.id ?? 'null'} | lastKnown: ${params.lastKnownTarget?.id ?? 'null'} | final: ${target?.id ?? 'null'}`)
|
|
470
|
+
if (target) {
|
|
471
|
+
// On Android, consolidate drag position before snap to avoid animation conflict
|
|
472
|
+
if (!params.isIOS) {
|
|
473
|
+
draggableView.applyProperties({
|
|
474
|
+
top: draggableView._visualTop ?? draggableView.top,
|
|
475
|
+
left: draggableView._visualLeft ?? draggableView.left
|
|
476
|
+
})
|
|
477
|
+
}
|
|
478
|
+
if (args.animationProperties?.snap?.center) {
|
|
479
|
+
logger(` -> snap-center: ${draggableView.id} to ${target.id}`)
|
|
480
|
+
animationView.snapTo(draggableView, [target])
|
|
481
|
+
}
|
|
482
|
+
if (params.dropCB) {
|
|
483
|
+
logger(` -> dropCB: ${draggableView.id} on ${target.id}`)
|
|
484
|
+
params.dropCB(draggableView, target)
|
|
485
|
+
}
|
|
486
|
+
} else if (!target && args.animationProperties?.snap?.back) {
|
|
487
|
+
logger(` -> bounce-back: ${draggableView.id} to (${draggableView._originTop}, ${draggableView._originLeft})`)
|
|
488
|
+
|
|
489
|
+
// On Android, consolidate drag position before bounce-back to avoid animation conflict
|
|
490
|
+
if (!params.isIOS) {
|
|
491
|
+
draggableView.applyProperties({
|
|
492
|
+
top: draggableView._visualTop ?? draggableView.top,
|
|
493
|
+
left: draggableView._visualLeft ?? draggableView.left
|
|
494
|
+
})
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
draggableView._bouncingBack = true
|
|
498
|
+
|
|
499
|
+
draggableView.animate({
|
|
500
|
+
...args,
|
|
501
|
+
top: draggableView._originTop,
|
|
502
|
+
left: draggableView._originLeft,
|
|
503
|
+
transform: Ti.UI.createMatrix2D()
|
|
504
|
+
}, () => {
|
|
505
|
+
draggableView._bouncingBack = false
|
|
506
|
+
draggableView.applyProperties({
|
|
507
|
+
top: draggableView._originTop,
|
|
508
|
+
left: draggableView._originLeft,
|
|
509
|
+
transform: Ti.UI.createMatrix2D()
|
|
510
|
+
})
|
|
511
|
+
logger(` -> bounce-back complete: ${draggableView.id}`)
|
|
512
|
+
})
|
|
513
|
+
}
|
|
514
|
+
params.lastHoverTarget = null
|
|
515
|
+
params.lastKnownTarget = null
|
|
516
|
+
if (params.dragCB) {
|
|
517
|
+
params.dragCB(draggableView, null)
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const onTouchMove = (event) => handleTouchMove(event, draggableView, offsetX, offsetY)
|
|
523
|
+
const onOrientationChange = () => checkBoundaries(draggableView)
|
|
524
|
+
|
|
525
|
+
draggableView._dragListeners = { onTouchStart, onTouchEnd, onTouchMove, onOrientationChange }
|
|
526
|
+
|
|
527
|
+
draggableView.addEventListener('touchend', onTouchEnd)
|
|
528
|
+
draggableView.addEventListener('touchmove', onTouchMove)
|
|
529
|
+
draggableView.addEventListener('touchstart', onTouchStart)
|
|
530
|
+
Ti.Gesture.addEventListener('orientationchange', onOrientationChange)
|
|
141
531
|
|
|
142
532
|
params.draggables.push(draggableView)
|
|
143
533
|
} else {
|
|
@@ -146,6 +536,7 @@ function Animation(args = {}) {
|
|
|
146
536
|
}
|
|
147
537
|
|
|
148
538
|
function handleTouchMove(event, draggableView, offsetX, offsetY) {
|
|
539
|
+
draggableView._wasDragged = true
|
|
149
540
|
const convertedPoint = draggableView.convertPointToView({ x: event.x, y: event.y }, draggableView.parent)
|
|
150
541
|
let top = Math.round(convertedPoint.y - offsetY)
|
|
151
542
|
let left = Math.round(convertedPoint.x - offsetX)
|
|
@@ -167,11 +558,63 @@ function Animation(args = {}) {
|
|
|
167
558
|
}
|
|
168
559
|
}
|
|
169
560
|
|
|
561
|
+
draggableView._visualTop = top
|
|
562
|
+
draggableView._visualLeft = left
|
|
563
|
+
|
|
170
564
|
if (params.isIOS) {
|
|
171
|
-
const
|
|
172
|
-
|
|
565
|
+
const r = draggableView.rotate ?? 0
|
|
566
|
+
const s = draggableView.scale ?? 1
|
|
567
|
+
|
|
568
|
+
if (r !== 0 || s !== 1) {
|
|
569
|
+
// Delta-based drag for transformed views (preserves rotate/scale)
|
|
570
|
+
const translation = draggableView.translation ?? { x: 0, y: 0 }
|
|
571
|
+
const deltaX = Math.round((event.x - offsetX) * s)
|
|
572
|
+
const deltaY = Math.round((event.y - offsetY) * s)
|
|
573
|
+
translation.x += deltaX
|
|
574
|
+
translation.y += deltaY
|
|
575
|
+
draggableView.applyProperties({
|
|
576
|
+
translation, rotate: r, scale: s,
|
|
577
|
+
transform: Ti.UI.createMatrix2D().translate(translation.x, translation.y).rotate(r).scale(s)
|
|
578
|
+
})
|
|
579
|
+
} else {
|
|
580
|
+
// Standard drag for non-transformed views
|
|
581
|
+
const { x, y } = calculateTranslation(draggableView, draggableView.parent.rect, left, top)
|
|
582
|
+
draggableView.applyProperties({ duration: 0, transform: Ti.UI.createMatrix2D().translate(x, y) })
|
|
583
|
+
}
|
|
173
584
|
} else {
|
|
174
|
-
draggableView.
|
|
585
|
+
const r = draggableView.rotate ?? 0
|
|
586
|
+
const s = draggableView.scale ?? 1
|
|
587
|
+
|
|
588
|
+
if (r !== 0 || s !== 1) {
|
|
589
|
+
// Delta-based drag for transformed views on Android
|
|
590
|
+
const translation = draggableView.translation ?? { x: 0, y: 0 }
|
|
591
|
+
const deltaX = Math.round((event.x - offsetX) * s)
|
|
592
|
+
const deltaY = Math.round((event.y - offsetY) * s)
|
|
593
|
+
translation.x += deltaX
|
|
594
|
+
translation.y += deltaY
|
|
595
|
+
draggableView.animate(Ti.UI.createAnimation({
|
|
596
|
+
transform: Ti.UI.createMatrix2D().translate(translation.x, translation.y).rotate(r).scale(s),
|
|
597
|
+
duration: 0
|
|
598
|
+
}))
|
|
599
|
+
draggableView.translation = translation
|
|
600
|
+
draggableView.rotate = r
|
|
601
|
+
draggableView.scale = s
|
|
602
|
+
} else {
|
|
603
|
+
draggableView.animate(Ti.UI.createAnimation({ top, left, duration: 0 }))
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (draggableView._collisionEnabled && params.dragCB) {
|
|
608
|
+
try {
|
|
609
|
+
const target = checkCollision(draggableView)
|
|
610
|
+
if (target) { params.lastKnownTarget = target }
|
|
611
|
+
if (target !== params.lastHoverTarget) {
|
|
612
|
+
params.lastHoverTarget = target
|
|
613
|
+
params.dragCB(draggableView, target)
|
|
614
|
+
}
|
|
615
|
+
} catch (e) {
|
|
616
|
+
logger(` !! collision error in touchmove: ${e.message}`)
|
|
617
|
+
}
|
|
175
618
|
}
|
|
176
619
|
}
|
|
177
620
|
|
|
@@ -179,15 +622,15 @@ function Animation(args = {}) {
|
|
|
179
622
|
let x = left - parentViewRect.width / 2 + draggableView.rect.width / 2
|
|
180
623
|
let y = top - parentViewRect.height / 2 + draggableView.rect.height / 2
|
|
181
624
|
|
|
182
|
-
if (draggableView.left) {
|
|
625
|
+
if (draggableView.left != null) {
|
|
183
626
|
x = left - draggableView.left
|
|
184
|
-
} else if (draggableView.right) {
|
|
627
|
+
} else if (draggableView.right != null) {
|
|
185
628
|
x = left - (parentViewRect.width - draggableView.right - draggableView.rect.width)
|
|
186
629
|
}
|
|
187
630
|
|
|
188
|
-
if (draggableView.top) {
|
|
631
|
+
if (draggableView.top != null) {
|
|
189
632
|
y = top - draggableView.top
|
|
190
|
-
} else if (draggableView.bottom) {
|
|
633
|
+
} else if (draggableView.bottom != null) {
|
|
191
634
|
y = top - (parentViewRect.height - draggableView.bottom - draggableView.rect.height)
|
|
192
635
|
}
|
|
193
636
|
|
|
@@ -207,8 +650,14 @@ function Animation(args = {}) {
|
|
|
207
650
|
}
|
|
208
651
|
|
|
209
652
|
function updateDraggableZIndex(event) {
|
|
210
|
-
|
|
211
|
-
|
|
653
|
+
if (args.animationProperties?.keepZIndex) return
|
|
654
|
+
|
|
655
|
+
const source = realSourceView(event.source)
|
|
656
|
+
const idx = params.draggables.indexOf(source)
|
|
657
|
+
if (idx !== -1) {
|
|
658
|
+
params.draggables.push(params.draggables.splice(idx, 1)[0])
|
|
659
|
+
params.draggables.forEach((draggable, key) => { draggable.zIndex = key })
|
|
660
|
+
}
|
|
212
661
|
}
|
|
213
662
|
|
|
214
663
|
function realSourceView(_source) {
|
|
@@ -270,6 +719,26 @@ function Animation(args = {}) {
|
|
|
270
719
|
})
|
|
271
720
|
}
|
|
272
721
|
|
|
722
|
+
function checkCollision(draggableView) {
|
|
723
|
+
const top = draggableView._visualTop
|
|
724
|
+
const left = draggableView._visualLeft
|
|
725
|
+
if (left === null || left === undefined || top === null || top === undefined) {
|
|
726
|
+
return null
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
const cy = top + draggableView.rect.height / 2
|
|
730
|
+
const cx = left + draggableView.rect.width / 2
|
|
731
|
+
|
|
732
|
+
for (const other of params.collisionViews) {
|
|
733
|
+
if (other === draggableView) { continue }
|
|
734
|
+
const r = other.rect
|
|
735
|
+
if (cx > r.x && cx < r.x + r.width && cy > r.y && cy < r.y + r.height) {
|
|
736
|
+
return other
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return null
|
|
740
|
+
}
|
|
741
|
+
|
|
273
742
|
function checkDraggable(_view, _action) {
|
|
274
743
|
logger('Check Draggable')
|
|
275
744
|
logger(' -> `' + _action + '`')
|
|
@@ -300,18 +769,18 @@ function Animation(args = {}) {
|
|
|
300
769
|
params.playing = false
|
|
301
770
|
if (typeof _cb === 'function') {
|
|
302
771
|
const enrichedEvent = {
|
|
303
|
-
//
|
|
772
|
+
// Safe properties from the original event
|
|
304
773
|
type: event.type,
|
|
305
774
|
bubbles: event.bubbles,
|
|
306
775
|
cancelBubble: event.cancelBubble,
|
|
307
|
-
//
|
|
776
|
+
// Added properties (primitives only)
|
|
308
777
|
action, // 'play'
|
|
309
778
|
state: params.open ? 'open' : 'close',
|
|
310
779
|
id: params.id,
|
|
311
|
-
targetId: view.id || 'unknown', //
|
|
780
|
+
targetId: view.id || 'unknown', // View ID only, not the object
|
|
312
781
|
index,
|
|
313
782
|
total,
|
|
314
|
-
//
|
|
783
|
+
// Helper method to get the view
|
|
315
784
|
getTarget: () => view
|
|
316
785
|
}
|
|
317
786
|
_cb(enrichedEvent)
|
|
@@ -341,14 +810,14 @@ function Animation(args = {}) {
|
|
|
341
810
|
type: 'applied',
|
|
342
811
|
bubbles: false,
|
|
343
812
|
cancelBubble: false,
|
|
344
|
-
//
|
|
813
|
+
// Added properties (primitives only)
|
|
345
814
|
action, // 'apply'
|
|
346
815
|
state: params.open ? 'open' : 'close',
|
|
347
816
|
id: params.id,
|
|
348
|
-
targetId: view.id || 'unknown', //
|
|
817
|
+
targetId: view.id || 'unknown', // View ID only, not the object
|
|
349
818
|
index,
|
|
350
819
|
total,
|
|
351
|
-
//
|
|
820
|
+
// Helper method to get the view
|
|
352
821
|
getTarget: () => view
|
|
353
822
|
}
|
|
354
823
|
_cb(enrichedEvent)
|