@maccesar/titools 4.17.1 → 4.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -8
- package/commands/ti-audit.md +1 -1
- package/package.json +1 -1
- package/skills/purgetss/SKILL.md +45 -22
- package/skills/purgetss/references/animation-advanced.md +93 -226
- package/skills/purgetss/references/animation-system.md +26 -17
- package/skills/purgetss/references/app-branding.md +53 -26
- package/skills/purgetss/references/appearance-module.md +63 -9
- package/skills/purgetss/references/class-categories.md +2 -2
- package/skills/purgetss/references/class-index.md +1 -1
- package/skills/purgetss/references/classic-projects.md +115 -0
- package/skills/purgetss/references/cli-commands.md +71 -74
- package/skills/purgetss/references/custom-fonts.md +57 -8
- package/skills/purgetss/references/customization-deep-dive.md +12 -7
- package/skills/purgetss/references/dynamic-component-creation.md +1 -1
- package/skills/purgetss/references/icon-fonts.md +33 -6
- package/skills/purgetss/references/installation-setup.md +12 -2
- package/skills/purgetss/references/multi-density-images.md +10 -10
- package/skills/purgetss/references/purgetss-ui-classic.md +341 -0
- package/skills/purgetss/references/semantic-colors.md +17 -7
- package/skills/purgetss/references/version-history.md +28 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PurgeTSS Animation -- Advanced Reference
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Runtime property forwarding, timing/utility classes, utility functions, implementation rules, and complex UI examples.
|
|
4
4
|
|
|
5
5
|
For core animation methods (play, toggle, apply, open, close, draggable, undraggable, detectCollisions, sequence, swap, pulse, shake, snapTo, reorder, transition), see [animation-system.md](./animation-system.md).
|
|
6
6
|
|
|
@@ -9,18 +9,42 @@ For core animation methods (play, toggle, apply, open, close, draggable, undragg
|
|
|
9
9
|
<!-- TOC-START -->
|
|
10
10
|
## Contents
|
|
11
11
|
|
|
12
|
-
- [Property
|
|
12
|
+
- [Runtime Property Forwarding](#runtime-property-forwarding)
|
|
13
|
+
- [Forwarding and Overrides](#forwarding-and-overrides)
|
|
13
14
|
- [Timing and Utility Classes](#timing-and-utility-classes)
|
|
15
|
+
- [anchorPoint / origin-* Classes](#anchorpoint--origin--classes)
|
|
16
|
+
- [autoreverse](#autoreverse)
|
|
17
|
+
- [Curve Classes](#curve-classes)
|
|
18
|
+
- [delay-*](#delay-)
|
|
19
|
+
- [duration-*](#duration-)
|
|
20
|
+
- [repeat-*](#repeat-)
|
|
21
|
+
- [rotate-* and -rotate-*](#rotate--and--rotate-)
|
|
22
|
+
- [scale-*](#scale-)
|
|
23
|
+
- [Snap Classes](#snap-classes)
|
|
24
|
+
- [keep-z-index](#keep-z-index)
|
|
25
|
+
- [Drag Type](#drag-type)
|
|
26
|
+
- [Opacity and Visibility Utilities](#opacity-and-visibility-utilities)
|
|
27
|
+
- [zoom-in-* / zoom-out-*](#zoom-in---zoom-out-)
|
|
14
28
|
- [Utility Functions](#utility-functions)
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
29
|
+
- [deviceInfo()](#deviceinfo)
|
|
30
|
+
- [saveComponent({ source, directory })](#savecomponent-source-directory-)
|
|
31
|
+
- [Runtime Implementation Rules](#runtime-implementation-rules)
|
|
32
|
+
- [Transform conversion](#transform-conversion)
|
|
33
|
+
- [State and children](#state-and-children)
|
|
34
|
+
- [Arrays and callbacks](#arrays-and-callbacks)
|
|
35
|
+
- [Position and drag state](#position-and-drag-state)
|
|
36
|
+
- [Android position consolidation](#android-position-consolidation)
|
|
37
|
+
- [Transition state](#transition-state)
|
|
38
|
+
- [Cleanup limitations](#cleanup-limitations)
|
|
17
39
|
- [Complex UI Example](#complex-ui-example)
|
|
40
|
+
- [XML](#xml)
|
|
41
|
+
- [Controller](#controller)
|
|
18
42
|
|
|
19
43
|
<!-- TOC-END -->
|
|
20
44
|
|
|
21
|
-
## Property
|
|
45
|
+
## Runtime Property Forwarding
|
|
22
46
|
|
|
23
|
-
|
|
47
|
+
The constructor keeps the resolved `<Animation>` properties as its base object. Most helpers spread that object into `Ti.UI.createAnimation()` before adding their own fields. This forwards native values such as `duration`, `delay`, `curve`, `opacity`, or `backgroundColor`, but it does not guarantee that every Titanium property is meaningful for every helper.
|
|
24
48
|
|
|
25
49
|
When you declare an Animation object with utility classes:
|
|
26
50
|
|
|
@@ -28,38 +52,22 @@ When you declare an Animation object with utility classes:
|
|
|
28
52
|
<Animation id="myAnim" module="purgetss.ui" class="duration-150 delay-100 curve-animation-ease-out" />
|
|
29
53
|
```
|
|
30
54
|
|
|
31
|
-
|
|
55
|
+
In Classic, the equivalent values are passed directly to `createAnimation()`; see [purgetss-ui-classic.md](./purgetss-ui-classic.md).
|
|
32
56
|
|
|
33
|
-
###
|
|
57
|
+
### Forwarding and Overrides
|
|
34
58
|
|
|
35
|
-
|
|
|
36
|
-
| --- |
|
|
37
|
-
| `
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- **--** = not applicable to this method
|
|
46
|
-
- **fixed** = uses internal fixed values (`shake`: `autoreverse: true`, `repeat: 3`, `curve: EASE_IN_OUT`; `pulse`: `autoreverse: true`, `curve: EASE_IN_OUT`)
|
|
47
|
-
- **param** = controlled by method parameter (`pulse` `count` sets the repeat value)
|
|
48
|
-
- **(div6)** = `shake` divides the inherited duration by 6 for each oscillation cycle
|
|
49
|
-
|
|
50
|
-
### Fallback Defaults
|
|
51
|
-
|
|
52
|
-
When a property is not set on the Animation object and no explicit parameter is passed:
|
|
53
|
-
|
|
54
|
-
| Property | `swap` / `reorder` / `snapTo` | `shake` |
|
|
55
|
-
| --- | :---: | :---: |
|
|
56
|
-
| `duration` | 200ms | 400ms |
|
|
57
|
-
| `delay` | 0ms | 0ms |
|
|
58
|
-
| `curve` | `EASE_IN_OUT` | `EASE_IN_OUT` (fixed) |
|
|
59
|
-
|
|
60
|
-
### Explicit Parameters Take Precedence
|
|
59
|
+
| Method | Forwarded base values | Forced or computed values |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `play` / `toggle` / `open` / `close` | Base object plus active state | Active-state transform |
|
|
62
|
+
| `apply` | Base object plus active state | Applies immediately rather than creating native motion |
|
|
63
|
+
| `sequence` | Same state values as `play` | Serial start order |
|
|
64
|
+
| `swap` | Base object | Destination position; source identity transform |
|
|
65
|
+
| `pulse` | Base object | Transform fallback, `autoreverse`, `repeat`, and curve |
|
|
66
|
+
| `shake` | Non-overridden base values | Transform, divided duration, `autoreverse`, `repeat`, and curve |
|
|
67
|
+
| `snapTo` / `reorder` | Base object | Destination position and identity transform |
|
|
68
|
+
| `transition` | Base object | Combined layout transform and optional size/opacity |
|
|
61
69
|
|
|
62
|
-
|
|
70
|
+
Method-specific assignments are appended after the spread and therefore win on duplicate keys. The method parameters are feature-specific rather than alternative timing values:
|
|
63
71
|
|
|
64
72
|
```javascript
|
|
65
73
|
// All timing controlled by the Animation object's classes
|
|
@@ -70,6 +78,8 @@ $.myAnim.snapTo($.card, targets)
|
|
|
70
78
|
$.myAnim.transition(views, fanOutLayout)
|
|
71
79
|
```
|
|
72
80
|
|
|
81
|
+
There is no shared `200ms`/`0ms`/`EASE_IN_OUT` fallback for `swap`, `snapTo`, `reorder`, or `transition`. Configure timing on the Animation object when predictable visible motion matters. Only `shake` computes `(duration ?? 400) / 6`; `pulse` supplies a default scale of `1.2`. Both helpers force ease-in-out.
|
|
82
|
+
|
|
73
83
|
---
|
|
74
84
|
|
|
75
85
|
## Timing and Utility Classes
|
|
@@ -182,12 +192,12 @@ Control how draggable views behave when dropped. All are **off by default**.
|
|
|
182
192
|
| `snap-back-false` | `{ animationProperties: { snap: { back: false } } }` | Disables snap-back |
|
|
183
193
|
| `snap-center` | `{ animationProperties: { snap: { center: true } } }` | Auto-centers on target |
|
|
184
194
|
| `snap-center-false` | `{ animationProperties: { snap: { center: false } } }` | Disables snap-center |
|
|
185
|
-
|
|
186
|
-
|
|
195
|
+
|
|
196
|
+
Generated utility inventories may still contain `snap-magnet` names, but the current `purgetss.ui` runtime never reads `animationProperties.snap.magnet`. Do not use or recommend those classes as working drag behavior.
|
|
187
197
|
|
|
188
198
|
### keep-z-index
|
|
189
199
|
|
|
190
|
-
Prevents the drag system from
|
|
200
|
+
Prevents the drag system from promoting the active view on touch start. It does not prevent `draggable(array)` from first assigning each view `zIndex` from its array position, and `swap()` restores z-order from the current draggable registry rather than arbitrary original values.
|
|
191
201
|
|
|
192
202
|
```css
|
|
193
203
|
'.keep-z-index': { animationProperties: { keepZIndex: true } }
|
|
@@ -234,236 +244,93 @@ The module exports helper functions alongside the Animation component:
|
|
|
234
244
|
|
|
235
245
|
### deviceInfo()
|
|
236
246
|
|
|
237
|
-
Logs
|
|
247
|
+
Logs platform and display information and returns `undefined`. It includes `xdpi` and `ydpi` only on Android. Its tablet flag currently recognizes iPad only, so Android tablets are reported as handheld.
|
|
238
248
|
|
|
239
249
|
```javascript
|
|
240
250
|
const { deviceInfo } = require('purgetss.ui')
|
|
241
251
|
deviceInfo()
|
|
242
252
|
```
|
|
243
253
|
|
|
254
|
+
Classic loads the generated file with `require('lib/purgetss.ui')`.
|
|
255
|
+
|
|
244
256
|
### saveComponent({ source, directory })
|
|
245
257
|
|
|
246
|
-
|
|
258
|
+
Calls `source.toImage()`, creates an MD5-based PNG filename, writes it to `directory` (default: `Ti.Filesystem.tempDirectory`), and then invokes `Ti.Media.saveToPhotoGallery()`. It returns `undefined` and has no completion or error callback.
|
|
247
259
|
|
|
248
260
|
```javascript
|
|
249
261
|
const { saveComponent } = require('purgetss.ui')
|
|
250
|
-
saveComponent({ source: $.myView, directory:
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
## Implementation Rules
|
|
256
|
-
|
|
257
|
-
Rules that every method in the Animation module must follow. They keep behavior consistent with the declarative model of PurgeTSS.
|
|
258
|
-
|
|
259
|
-
### Rule 1: Inherit from the `<Animation />` object via `...args`
|
|
260
|
-
|
|
261
|
-
Every method MUST inherit all properties from the Animation object by spreading `args`. Never cherry-pick individual properties.
|
|
262
|
-
|
|
263
|
-
The `<Animation />` object is the single source of truth for animation behavior. When a developer declares:
|
|
264
|
-
|
|
265
|
-
```xml
|
|
266
|
-
<Animation id="myAnim" module="purgetss.ui" class="curve-animation-ease-out opacity-50 delay-100 duration-300" />
|
|
262
|
+
saveComponent({ source: $.myView, directory: Ti.Filesystem.applicationDataDirectory })
|
|
267
263
|
```
|
|
268
264
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
```javascript
|
|
272
|
-
// CORRECT -- inherits everything, method-specific props override
|
|
273
|
-
view.animate({ ...args, left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D() })
|
|
274
|
-
|
|
275
|
-
// WRONG -- cherry-picks individual properties, breaks if new ones are added
|
|
276
|
-
view.animate({ duration: args.duration, delay: args.delay, left: destLeft, top: destTop })
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
This is the same pattern used by the core `playView` function:
|
|
280
|
-
|
|
281
|
-
```javascript
|
|
282
|
-
const animation = Ti.UI.createAnimation(args)
|
|
283
|
-
view.animate(animation)
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
If a developer adds `opacity-50` to their `<Animation>`, they expect ALL methods to animate opacity, not just `play`.
|
|
287
|
-
|
|
288
|
-
### Rule 2: Override by position, not by exclusion
|
|
289
|
-
|
|
290
|
-
If a method needs fixed values for specific properties, they go AFTER `...args` to override. Never filter or exclude properties from args.
|
|
265
|
+
Check or request photo-gallery permission before calling it. On iOS, declare the photo-library add usage description required by Titanium. Classic uses `require('lib/purgetss.ui')`; see [purgetss-ui-classic.md#runtime-utilities](./purgetss-ui-classic.md#runtime-utilities).
|
|
291
266
|
|
|
292
|
-
|
|
293
|
-
// CORRECT -- shake: inherits everything, then overrides what it needs
|
|
294
|
-
view.animate({
|
|
295
|
-
...args,
|
|
296
|
-
transform: Ti.UI.createMatrix2D().translate(intensity, 0),
|
|
297
|
-
duration: Math.round((args.duration ?? 400) / 6),
|
|
298
|
-
autoreverse: true,
|
|
299
|
-
repeat: 3,
|
|
300
|
-
curve: Ti.UI.ANIMATION_CURVE_EASE_IN_OUT
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
// WRONG -- filters args, only picks what it thinks it needs
|
|
304
|
-
view.animate({
|
|
305
|
-
duration: args.duration,
|
|
306
|
-
transform: Ti.UI.createMatrix2D().translate(intensity, 0),
|
|
307
|
-
autoreverse: true,
|
|
308
|
-
repeat: 3
|
|
309
|
-
})
|
|
310
|
-
```
|
|
267
|
+
---
|
|
311
268
|
|
|
312
|
-
|
|
269
|
+
## Runtime Implementation Rules
|
|
313
270
|
|
|
314
|
-
|
|
315
|
-
// If args = { duration: 300, opacity: 0.5, curve: EASE_OUT }
|
|
316
|
-
view.animate({
|
|
317
|
-
...args, // duration: 300, opacity: 0.5, curve: EASE_OUT
|
|
318
|
-
duration: 50, // overrides to 50
|
|
319
|
-
curve: EASE_IN // overrides to EASE_IN
|
|
320
|
-
})
|
|
321
|
-
// Result: { duration: 50, opacity: 0.5, curve: EASE_IN }
|
|
322
|
-
// opacity 0.5 is preserved from args -- not lost by filtering
|
|
323
|
-
```
|
|
271
|
+
These are observable rules of the generated module. Use them to diagnose surprising output; they are not a template or promise for future extension methods.
|
|
324
272
|
|
|
325
|
-
###
|
|
273
|
+
### Transform conversion
|
|
326
274
|
|
|
327
|
-
|
|
275
|
+
At construction time, top-level `scale`, `rotate`, and `anchorPoint` are converted into one `Ti.UI.Matrix2D` and removed from the base object. Separate matrices are prepared for `animationProperties.open` and `.close`. `pulse`, `shake`, `swap`, `snapTo`, `reorder`, and `transition` may replace or reset that transform, so a position helper does not promise to preserve it.
|
|
328
276
|
|
|
329
|
-
|
|
330
|
-
// CORRECT -- only method-specific parameters
|
|
331
|
-
animationView.swap = (view1, view2) => {
|
|
332
|
-
animationView.reorder = (views, newOrder) => {
|
|
333
|
-
animationView.shake = (view, intensity = 10) => {
|
|
334
|
-
animationView.snapTo = (view, targets) => {
|
|
335
|
-
animationView.pulse = (view, count = 1) => {
|
|
336
|
-
|
|
337
|
-
// WRONG -- timing parameters belong in the <Animation /> object
|
|
338
|
-
animationView.swap = (view1, view2, duration) => {
|
|
339
|
-
animationView.shake = (view, intensity, duration) => {
|
|
340
|
-
```
|
|
277
|
+
### State and children
|
|
341
278
|
|
|
342
|
-
|
|
279
|
+
`play()`, `toggle()`, `apply()`, and `sequence()` toggle internal open/close state. `open()` and `close()` set it explicitly. The active state is merged into the current base object when `animationProperties` exists.
|
|
343
280
|
|
|
344
|
-
|
|
345
|
-
<!-- Fast swap -->
|
|
346
|
-
<Animation id="fastSwap" module="purgetss.ui" class="duration-75" />
|
|
281
|
+
After a top-level `play`, `toggle`, `open`, or `close`, `animationProperties.complete` starts as a second animation. `apply()` applies `complete` immediately. The public callback belongs to the base play/apply operation; it does not wait for the second top-level `complete` animation.
|
|
347
282
|
|
|
348
|
-
|
|
349
|
-
<Animation id="slowSwap" module="purgetss.ui" class="delay-200 duration-500" />
|
|
350
|
-
```
|
|
283
|
+
For each direct child with an active state, merge precedence is:
|
|
351
284
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
$.slowSwap.swap($.card1, $.card2)
|
|
356
|
-
```
|
|
285
|
+
1. Parent `animationProperties.children`.
|
|
286
|
+
2. Child `animationProperties.child`.
|
|
287
|
+
3. Child `animationProperties.open`, `.close`, or `.complete`.
|
|
357
288
|
|
|
358
|
-
|
|
289
|
+
Later objects win. Only direct children of the target are considered.
|
|
359
290
|
|
|
360
|
-
|
|
291
|
+
### Arrays and callbacks
|
|
361
292
|
|
|
362
|
-
|
|
363
|
-
// CORRECT -- consolidates after animation
|
|
364
|
-
view.animate({
|
|
365
|
-
...args, left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D()
|
|
366
|
-
}, () => {
|
|
367
|
-
view.applyProperties({ left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D() })
|
|
368
|
-
})
|
|
369
|
-
|
|
370
|
-
// WRONG -- animation ends but view's actual properties are stale
|
|
371
|
-
view.animate({
|
|
372
|
-
...args, left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D()
|
|
373
|
-
})
|
|
374
|
-
```
|
|
293
|
+
`play()`, `open()`, `close()`, and `apply()` accept one view or an array. Array callbacks run once per view and include `index`, `total`, and `getTarget()`. The configured base delay accumulates for successive views. `sequence()` waits for each native completion and invokes its callback once after the final view; an empty array never invokes it.
|
|
375
294
|
|
|
376
|
-
|
|
295
|
+
The callback is a new object containing selected native primitives plus PurgeTSS metadata. It is not the original Titanium event.
|
|
377
296
|
|
|
378
|
-
###
|
|
297
|
+
### Position and drag state
|
|
379
298
|
|
|
380
|
-
|
|
299
|
+
`swap()`, `snapTo()`, and `reorder()` persist destinations with `applyProperties()` and update private origin fields. They fall back to rendered `rect` coordinates, so call them only after layout.
|
|
381
300
|
|
|
382
|
-
|
|
383
|
-
// CORRECT -- updates origin tracking
|
|
384
|
-
view.animate({
|
|
385
|
-
...args, left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D()
|
|
386
|
-
}, () => {
|
|
387
|
-
view.applyProperties({ left: destLeft, top: destTop, transform: Ti.UI.createMatrix2D() })
|
|
388
|
-
})
|
|
389
|
-
|
|
390
|
-
view._originTop = destTop
|
|
391
|
-
view._originLeft = destLeft
|
|
392
|
-
```
|
|
301
|
+
Drag precedence is precise:
|
|
393
302
|
|
|
394
|
-
|
|
395
|
-
-
|
|
396
|
-
- `
|
|
397
|
-
- `
|
|
398
|
-
-
|
|
303
|
+
- Constructor bounds are the base; `view.bounds` overrides individual edges.
|
|
304
|
+
- Axis restriction comes only from `view.constraint`.
|
|
305
|
+
- `view.draggingType` overrides constructor `draggingType`.
|
|
306
|
+
- Constructor `draggable.drag/drop` is merged with `view.draggable.drag/drop`; view properties win.
|
|
307
|
+
- Every resolved drag/drop property is forwarded to Titanium.
|
|
308
|
+
- `snap.center` invokes `snapTo()` after a valid drop; `snap.back` returns a missed drop to its captured origin.
|
|
309
|
+
- No `snap.magnet` behavior exists.
|
|
399
310
|
|
|
400
|
-
|
|
311
|
+
Collision detection uses the dragged view's center. On release, the last non-null hover target is a fallback when the final hit test returns `null`.
|
|
401
312
|
|
|
402
|
-
|
|
313
|
+
`draggable(array)` immediately assigns each view `zIndex` from its array index. `keepZIndex` only disables later touch-start promotion. `swap()` restores z-order by the current draggable-registry order, not by arbitrary values present before registration.
|
|
403
314
|
|
|
404
|
-
|
|
405
|
-
if (!params.isIOS) {
|
|
406
|
-
draggableView.applyProperties({
|
|
407
|
-
top: draggableView._visualTop ?? draggableView.top,
|
|
408
|
-
left: draggableView._visualLeft ?? draggableView.left
|
|
409
|
-
})
|
|
410
|
-
}
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
This applies to both the snap path and the bounce-back path in `onTouchEnd`. iOS does not need this because drag uses synchronous `transform.translate()`.
|
|
315
|
+
### Android position consolidation
|
|
414
316
|
|
|
415
|
-
|
|
317
|
+
Android drag uses zero-duration native animations. At touch end, when translation state exists, the runtime consolidates `translation`, `rotate`, `scale`, and an equivalent `Matrix2D` before collision, snap, or drop callbacks. It does not consolidate only `top` and `left`. iOS uses synchronous property application for standard dragging and a separate transformed-view path.
|
|
416
318
|
|
|
417
|
-
###
|
|
418
|
-
|
|
419
|
-
Every internal property added to views MUST be cleaned up in `undraggable`:
|
|
420
|
-
|
|
421
|
-
| Property | Set by | Purpose |
|
|
422
|
-
| --- | --- | --- |
|
|
423
|
-
| `_originTop` / `_originLeft` | `swap`, `reorder`, `snapTo`, `onTouchStart` | Logical position tracking |
|
|
424
|
-
| `_visualTop` / `_visualLeft` | `handleTouchMove` | Visual position during drag |
|
|
425
|
-
| `_dragListeners` | `makeViewsDraggable` | Touch event listener references |
|
|
426
|
-
| `_collisionEnabled` | `detectCollisions` | Collision detection flag |
|
|
427
|
-
| `_wasDragged` | `onTouchStart` / `handleTouchMove` | Drag detection flag |
|
|
428
|
-
| `_bouncingBack` | `onTouchEnd` (bounce-back) | Prevents origin capture during mid-animation; `swap` cancels it before animating |
|
|
319
|
+
### Transition state
|
|
429
320
|
|
|
430
|
-
|
|
321
|
+
`transition()` builds one matrix per view from translation, rotation, and scale, applies a supplied `zIndex` before animation, and can animate width, height, and opacity.
|
|
431
322
|
|
|
432
|
-
|
|
433
|
-
animationView.undraggable = (_views) => {
|
|
434
|
-
const arr = Array.isArray(_views) ? _views : [_views]
|
|
435
|
-
arr.forEach(view => {
|
|
436
|
-
// ... existing cleanup ...
|
|
437
|
-
delete view._newProperty // ADD cleanup for any new internal property
|
|
438
|
-
})
|
|
439
|
-
}
|
|
440
|
-
```
|
|
323
|
+
Without a matching layout, a view fades out, receives `zIndex: 0`, and has touch disabled. iOS preserves its last transform; Android resets transform, translation, rotation, and scale. A later layout fades the view back in. Completion forces `touchEnabled: true` for every matched view, so reapply `false` for intentionally non-interactive views.
|
|
441
324
|
|
|
442
|
-
|
|
325
|
+
### Cleanup limitations
|
|
443
326
|
|
|
444
|
-
|
|
327
|
+
`undraggable()` removes the latest stored touch/orientation listeners, the first matching draggable and collision registrations, and most private drag state. Current limitations require application discipline:
|
|
445
328
|
|
|
446
|
-
|
|
329
|
+
- `draggable()` does not deduplicate. Repeated registration creates extra listeners and entries that one cleanup call cannot fully remove.
|
|
330
|
+
- `_wasDragged` remains on the view after `undraggable()`.
|
|
331
|
+
- `detectCollisions()` retains non-null callbacks on the animation object; passing `null` later does not clear them.
|
|
447
332
|
|
|
448
|
-
|
|
449
|
-
animationView.newMethod = (view, specificParam = defaultValue) => {
|
|
450
|
-
if (params.debug) { console.log('') }
|
|
451
|
-
logger('`newMethod` method called on: ' + params.id)
|
|
452
|
-
if (!view) { return notFound() }
|
|
453
|
-
|
|
454
|
-
view.animate({
|
|
455
|
-
...args, // Rule 1: inherit all from <Animation />
|
|
456
|
-
specificProp: computedValue, // Rule 2: override AFTER ...args
|
|
457
|
-
}, () => {
|
|
458
|
-
view.applyProperties({ ... }) // Rule 4: consolidate state
|
|
459
|
-
})
|
|
460
|
-
|
|
461
|
-
view._originTop = newTop // Rule 5: track position (if applicable)
|
|
462
|
-
view._originLeft = newLeft
|
|
463
|
-
}
|
|
464
|
-
// Rule 3: no timing params in signature
|
|
465
|
-
// Rule 7: add cleanup to undraggable (if new internal state)
|
|
466
|
-
```
|
|
333
|
+
Register each view once. On window close, call `undraggable()` for draggable views and registered collision targets, remove application-owned listeners, and release callbacks and animation references that are no longer needed. Do not make application code depend on private underscore fields.
|
|
467
334
|
|
|
468
335
|
---
|
|
469
336
|
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
|
|
28
28
|
PurgeTSS includes an Animation module for 2D Matrix animations and transformations. It works on single elements, arrays of elements, or individual children of an element.
|
|
29
29
|
|
|
30
|
+
The XML and `$.*` examples in this file are for Alloy. Titanium Classic uses the same generated runtime through JavaScript objects; see [purgetss-ui-classic.md](./purgetss-ui-classic.md) for the Classic installation path, factory API, method contracts, and lifecycle rules.
|
|
31
|
+
|
|
30
32
|
The Animation object describes an animation in a few ways:
|
|
31
33
|
- A single-phase animation with an end state
|
|
32
34
|
- A multi-phase animation using the `open`, `close`, and `complete` modifiers
|
|
@@ -62,13 +64,13 @@ You can use any position, size, color, transformation, and opacity classes from
|
|
|
62
64
|
| `open` | `open(views, cb)` | Explicitly run the opening animation (no toggle) |
|
|
63
65
|
| `close` | `close(views, cb)` | Explicitly run the closing animation (no toggle) |
|
|
64
66
|
| `draggable` | `draggable(views)` | Make views draggable via touch events |
|
|
65
|
-
| `undraggable` | `undraggable(views)` | Remove
|
|
67
|
+
| `undraggable` | `undraggable(views)` | Remove the module-owned drag listeners and most private drag state |
|
|
66
68
|
| `detectCollisions` | `detectCollisions(views, dragCB, dropCB)` | Enable collision detection with hover/drop callbacks |
|
|
67
69
|
| `sequence` | `sequence(views, cb)` | Animate views one after another (sequential, not parallel) |
|
|
68
70
|
| `swap` | `swap(view1, view2)` | Animate two views exchanging positions |
|
|
69
71
|
| `pulse` | `pulse(view, count)` | Scale-up-and-back animation (default count=1) |
|
|
70
72
|
| `shake` | `shake(view, intensity)` | Horizontal shake for feedback (default intensity=10) |
|
|
71
|
-
| `snapTo` | `snapTo(view, targets)` | Snap
|
|
73
|
+
| `snapTo` | `snapTo(view, targets)` | Snap to the nearest target; returns it immediately, `null` if none qualifies, or `undefined` for a missing source |
|
|
72
74
|
| `reorder` | `reorder(views, newOrder)` | Animate views to new positions by index mapping |
|
|
73
75
|
| `transition` | `transition(views, layouts)` | Multi-view layout transitions using Matrix2D (translate, rotate, scale) |
|
|
74
76
|
|
|
@@ -82,7 +84,7 @@ The `play`, `toggle`, `open`, `close`, `apply`, and `sequence` methods accept an
|
|
|
82
84
|
| --- | --- |
|
|
83
85
|
| `open:` | Properties applied during open state |
|
|
84
86
|
| `close:` | Properties applied during close state |
|
|
85
|
-
| `complete:` | Additional properties applied after
|
|
87
|
+
| `complete:` | Additional properties applied after the active `play`/`toggle`/`open`/`close` state, or immediately after `apply` |
|
|
86
88
|
| `children:` | Global properties for all children of a View |
|
|
87
89
|
| `child:` | Individual properties for specific children |
|
|
88
90
|
| `bounds:` | Drag boundaries within parent |
|
|
@@ -127,7 +129,7 @@ First call applies `open:` properties; next call applies `close:` properties; co
|
|
|
127
129
|
|
|
128
130
|
### `complete` Modifier
|
|
129
131
|
|
|
130
|
-
Applies additional properties after
|
|
132
|
+
Applies additional properties after the active state finishes. With `play`, `toggle`, `open`, or `close`, it starts a second native animation; with `apply`, it is applied immediately:
|
|
131
133
|
|
|
132
134
|
```xml
|
|
133
135
|
<Animation module="purgetss.ui" id="myAnimationOpen"
|
|
@@ -147,6 +149,8 @@ $.myAnimation.play([$.view1, $.view2, $.view3])
|
|
|
147
149
|
|
|
148
150
|
The callback fires once per view. Use `e.index` and `e.total` to track progress.
|
|
149
151
|
|
|
152
|
+
Array playback starts all views without waiting for the previous completion. The configured base delay is increased cumulatively for each successive view. Use `sequence()` when each view must finish before the next begins.
|
|
153
|
+
|
|
150
154
|
---
|
|
151
155
|
|
|
152
156
|
## Callback Event Object
|
|
@@ -278,7 +282,7 @@ A blank or existing Animation object can be reused. When used with an array, zIn
|
|
|
278
282
|
|
|
279
283
|
- **Global modifiers** on the Animation object apply to all views
|
|
280
284
|
- **Local modifiers** on individual views override globals
|
|
281
|
-
-
|
|
285
|
+
- All properties in the resolved `drag` or `drop` object are forwarded to Titanium, including size, transform, and anchor-point properties
|
|
282
286
|
|
|
283
287
|
```xml
|
|
284
288
|
<Animation id="draggableAnimation" module="purgetss.ui" class="drag:duration-100 drag:opacity-50 drop:opacity-100" />
|
|
@@ -312,14 +316,16 @@ Limits movement within the parent. Local on the view or global on the Animation
|
|
|
312
316
|
|
|
313
317
|
## The `undraggable` Method
|
|
314
318
|
|
|
315
|
-
Removes
|
|
319
|
+
Removes the current module-owned draggable behavior from one or more views.
|
|
316
320
|
|
|
317
321
|
```javascript
|
|
318
322
|
$.draggableAnimation.undraggable($.card)
|
|
319
323
|
$.draggableAnimation.undraggable([$.card1, $.card2, $.card3])
|
|
320
324
|
```
|
|
321
325
|
|
|
322
|
-
|
|
326
|
+
It removes the stored `touchstart`/`touchend`/`touchmove` listeners, the stored `Ti.Gesture.orientationchange` listener, the first matching draggable/collision registry entries, and most private position/collision fields. The current runtime does **not** delete `_wasDragged`.
|
|
327
|
+
|
|
328
|
+
Register each view only once. `draggable()` does not deduplicate registrations: repeated calls add listeners and registry entries, while one `undraggable()` call removes only the latest stored listener set and the first matching entries. `detectCollisions()` also retains the last non-null callbacks on the Animation object; passing `null` later does not clear them.
|
|
323
329
|
|
|
324
330
|
**Use cases:** Lock a piece after correct placement, toggle edit/presentation mode, cleanup on window close (prevents memory leaks from global `orientationchange` listener).
|
|
325
331
|
|
|
@@ -418,6 +424,7 @@ $.myAnimation.sequence(views, callback)
|
|
|
418
424
|
- The `open`/`close` state is toggled once for the entire sequence
|
|
419
425
|
- Each view fully completes before the next starts
|
|
420
426
|
- The callback fires once after the last view finishes
|
|
427
|
+
- An empty array starts nothing and does not invoke the callback
|
|
421
428
|
|
|
422
429
|
### Onboarding Reveal Example
|
|
423
430
|
|
|
@@ -448,9 +455,9 @@ $.myAnimation.swap(view1, view2)
|
|
|
448
455
|
```
|
|
449
456
|
|
|
450
457
|
**Behavior:**
|
|
451
|
-
-
|
|
452
|
-
-
|
|
453
|
-
- Temporarily elevates z-index;
|
|
458
|
+
- Forwards the Animation object's native properties; there is no shared duration, delay, or curve fallback
|
|
459
|
+
- Resets the source transform while persisting the exchanged positions
|
|
460
|
+
- Temporarily elevates z-index; then assigns z-index from the current draggable-registry order rather than restoring arbitrary original values
|
|
454
461
|
- Updates `_originLeft`/`_originTop` for subsequent drag operations
|
|
455
462
|
- **Automatic position normalization**: no explicit `top`/`left` needed -- resolved via `view.rect`
|
|
456
463
|
- **Bounce-back safe**: completes any in-progress bounce-back before swapping
|
|
@@ -514,7 +521,7 @@ $.myAnimation.shake(view, intensity)
|
|
|
514
521
|
| `view` | `View` | -- | The view to shake |
|
|
515
522
|
| `intensity` | `Number` | `10` | Horizontal displacement in pixels |
|
|
516
523
|
|
|
517
|
-
- `duration`: inherited, divided by 6 for each shake
|
|
524
|
+
- `duration`: inherited, or `400ms` when absent, then divided by 6 for each shake phase
|
|
518
525
|
- `delay`: inherited, applied before shake starts
|
|
519
526
|
- `curve`: always `EASE_IN_OUT` (fixed)
|
|
520
527
|
- `autoreverse` and `repeat`: always `true` and `3` (fixed)
|
|
@@ -528,14 +535,14 @@ $.emailField.applyProperties({ borderColor: '#ef4444' })
|
|
|
528
535
|
|
|
529
536
|
## The `snapTo` Method
|
|
530
537
|
|
|
531
|
-
Snaps a view to the nearest target by center-to-center Euclidean distance.
|
|
538
|
+
Snaps a view to the nearest target by center-to-center Euclidean distance. It returns the matched target immediately, `null` when no target can be selected, or `undefined` for a missing source; the return does not mean the animation has completed.
|
|
532
539
|
|
|
533
540
|
```javascript
|
|
534
541
|
const matched = $.myAnimation.snapTo(view, targets)
|
|
535
542
|
```
|
|
536
543
|
|
|
537
|
-
-
|
|
538
|
-
-
|
|
544
|
+
- Forwards the Animation object's native properties; there is no shared duration, delay, or curve fallback
|
|
545
|
+
- Resets the moved view's transform and updates `_originLeft`/`_originTop`
|
|
539
546
|
- Automatic position normalization
|
|
540
547
|
|
|
541
548
|
### Puzzle Game with Collision Detection
|
|
@@ -567,7 +574,7 @@ $.myAnimation.reorder(views, newOrder)
|
|
|
567
574
|
|
|
568
575
|
- `newOrder` maps current index to new position: `[2, 1, 0]` reverses, `[1, 2, 0]` rotates
|
|
569
576
|
- Length must match `views` length
|
|
570
|
-
-
|
|
577
|
+
- Forwards the Animation object's native properties; there is no shared duration, delay, or curve fallback
|
|
571
578
|
- Automatic position normalization
|
|
572
579
|
|
|
573
580
|
```javascript
|
|
@@ -604,7 +611,9 @@ $.myAnimation.transition(views, layouts)
|
|
|
604
611
|
- Each view gets a single `Ti.UI.createAnimation()` with combined `Matrix2D` transform
|
|
605
612
|
- All animations launch simultaneously
|
|
606
613
|
- `zIndex` applied synchronously before animation starts
|
|
607
|
-
- **Mismatched lengths**: extra views fade
|
|
614
|
+
- **Mismatched lengths**: extra views fade to opacity `0`, receive `zIndex: 0`, and have touch disabled; extra layouts are ignored; hidden views fade back in and regain touch when later given a layout entry
|
|
615
|
+
- iOS preserves the last transform of a hidden view. Android resets its transform, translation, rotation, and scale
|
|
616
|
+
- A matched layout's completion handler forces `touchEnabled: true`; reapply `false` afterward for a view that must remain non-interactive
|
|
608
617
|
|
|
609
618
|
### Reusable Presets
|
|
610
619
|
|
|
@@ -639,7 +648,7 @@ function doStack() { $.galleryAnim.transition(photos, stack) }
|
|
|
639
648
|
$.galleryAnim.draggable(photos) // photos keep rotation/scale while dragging
|
|
640
649
|
```
|
|
641
650
|
|
|
642
|
-
`keep-z-index`
|
|
651
|
+
`keep-z-index` prevents touch-start promotion during drag. It does not prevent `draggable(array)` from first assigning each view `zIndex` from its array index.
|
|
643
652
|
|
|
644
653
|
### Mac Catalyst Note
|
|
645
654
|
|