@maccesar/titools 2.2.12 → 2.3.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 (98) hide show
  1. package/README.md +255 -713
  2. package/bin/titools.js +1 -1
  3. package/lib/commands/update.js +5 -6
  4. package/lib/config.js +1 -0
  5. package/lib/downloader.js +10 -0
  6. package/package.json +1 -1
  7. package/skills/alloy-guides/SKILL.md +46 -48
  8. package/skills/alloy-guides/references/CONTROLLERS.md +4 -6
  9. package/skills/alloy-guides/references/MODELS.md +340 -184
  10. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +3 -4
  11. package/skills/alloy-guides/references/VIEWS_STYLES.md +44 -46
  12. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +4 -5
  13. package/skills/alloy-guides/references/VIEWS_XML.md +51 -17
  14. package/skills/alloy-guides/references/WIDGETS.md +1 -1
  15. package/skills/alloy-howtos/SKILL.md +12 -13
  16. package/skills/alloy-howtos/references/cli_reference.md +40 -41
  17. package/skills/alloy-howtos/references/samples.md +3 -4
  18. package/skills/purgetss/SKILL.md +369 -356
  19. package/skills/purgetss/references/EXAMPLES.md +24 -25
  20. package/skills/purgetss/references/animation-advanced.md +555 -0
  21. package/skills/purgetss/references/animation-system.md +395 -995
  22. package/skills/purgetss/references/apply-directive.md +111 -141
  23. package/skills/purgetss/references/arbitrary-values.md +206 -480
  24. package/skills/purgetss/references/class-categories.md +277 -0
  25. package/skills/purgetss/references/class-index.md +1 -420
  26. package/skills/purgetss/references/cli-commands.md +446 -556
  27. package/skills/purgetss/references/configurable-properties.md +163 -599
  28. package/skills/purgetss/references/custom-rules.md +33 -76
  29. package/skills/purgetss/references/customization-deep-dive.md +319 -518
  30. package/skills/purgetss/references/dynamic-component-creation.md +33 -37
  31. package/skills/purgetss/references/grid-layout.md +42 -371
  32. package/skills/purgetss/references/icon-fonts.md +82 -475
  33. package/skills/purgetss/references/installation-setup.md +159 -331
  34. package/skills/purgetss/references/migration-guide.md +54 -109
  35. package/skills/purgetss/references/opacity-modifier.md +25 -222
  36. package/skills/purgetss/references/performance-tips.md +2 -2
  37. package/skills/purgetss/references/platform-modifiers.md +21 -407
  38. package/skills/purgetss/references/tikit-components.md +237 -104
  39. package/skills/purgetss/references/titanium-resets.md +20 -21
  40. package/skills/purgetss/references/ui-ux-design.md +171 -1702
  41. package/skills/ti-api/SKILL.md +109 -0
  42. package/skills/ti-api/references/api-android.md +675 -0
  43. package/skills/ti-api/references/api-app-platform.md +636 -0
  44. package/skills/ti-api/references/api-core.md +764 -0
  45. package/skills/ti-api/references/api-data-network.md +641 -0
  46. package/skills/ti-api/references/api-media.md +655 -0
  47. package/skills/ti-api/references/api-modules-ble-bluetooth.md +657 -0
  48. package/skills/ti-api/references/api-modules-coremotion-urlsession.md +411 -0
  49. package/skills/ti-api/references/api-modules-map.md +632 -0
  50. package/skills/ti-api/references/api-modules-nfc.md +725 -0
  51. package/skills/ti-api/references/api-modules-social-misc.md +526 -0
  52. package/skills/ti-api/references/api-services.md +700 -0
  53. package/skills/ti-api/references/api-ui-android.md +499 -0
  54. package/skills/ti-api/references/api-ui-extras.md +702 -0
  55. package/skills/ti-api/references/api-ui-ios-animator.md +378 -0
  56. package/skills/ti-api/references/api-ui-ios.md +756 -0
  57. package/skills/ti-api/references/api-ui-lists.md +581 -0
  58. package/skills/ti-api/references/api-ui-text-input.md +607 -0
  59. package/skills/ti-api/references/api-ui-views.md +572 -0
  60. package/skills/ti-api/references/api-ui-windows-navigation.md +676 -0
  61. package/skills/ti-api/references/api-xml-global.md +743 -0
  62. package/skills/ti-expert/SKILL.md +46 -45
  63. package/skills/ti-expert/references/adaptive-layouts.md +414 -0
  64. package/skills/ti-expert/references/alloy-builtins.md +16 -20
  65. package/skills/ti-expert/references/alloy-structure.md +40 -42
  66. package/skills/ti-expert/references/anti-patterns.md +34 -0
  67. package/skills/ti-expert/references/code-conventions.md +5 -3
  68. package/skills/ti-expert/references/error-handling.md +14 -7
  69. package/skills/ti-expert/references/examples.md +4 -2
  70. package/skills/ti-expert/references/performance-optimization.md +26 -24
  71. package/skills/ti-expert/references/security-device.md +17 -14
  72. package/skills/ti-expert/references/security-fundamentals.md +60 -101
  73. package/skills/ti-expert/references/state-management.md +15 -14
  74. package/skills/ti-expert/references/testing-e2e-ci.md +30 -21
  75. package/skills/ti-expert/references/theming.md +12 -20
  76. package/skills/ti-guides/SKILL.md +13 -17
  77. package/skills/ti-guides/references/advanced-data-and-images.md +30 -10
  78. package/skills/ti-guides/references/application-frameworks.md +3 -3
  79. package/skills/ti-guides/references/coding-best-practices.md +31 -2
  80. package/skills/ti-guides/references/commonjs-advanced.md +46 -4
  81. package/skills/ti-guides/references/hello-world.md +9 -13
  82. package/skills/ti-guides/references/hyperloop-native-access.md +4 -1
  83. package/skills/ti-guides/references/javascript-primer.md +13 -5
  84. package/skills/ti-guides/references/resources.md +0 -2
  85. package/skills/ti-guides/references/style-and-conventions.md +1 -0
  86. package/skills/ti-guides/references/tiapp-config.md +0 -32
  87. package/skills/ti-howtos/SKILL.md +43 -45
  88. package/skills/ti-howtos/references/buffer-codec-streams.md +25 -3
  89. package/skills/ti-howtos/references/debugging-profiling.md +14 -25
  90. package/skills/ti-howtos/references/google-maps-v2.md +3 -3
  91. package/skills/ti-howtos/references/ios-map-kit.md +8 -1
  92. package/skills/ti-howtos/references/notification-services.md +0 -1
  93. package/skills/ti-howtos/references/webpack-build-pipeline.md +3 -0
  94. package/skills/ti-ui/SKILL.md +47 -49
  95. package/skills/ti-ui/references/application-structures.md +3 -2
  96. package/skills/ti-ui/references/orientation.md +17 -9
  97. package/skills/ti-ui/references/platform-ui-ios.md +63 -0
  98. package/skills/ti-ui/references/scrolling-views.md +39 -0
@@ -1,1227 +1,627 @@
1
1
  # PurgeTSS Animation System
2
2
 
3
- The `<Animation>` component (`purgetss.ui`) provides declarative, native 2D Matrix animations and transformations for Titanium.
3
+ ## Introduction
4
4
 
5
- :::info
6
- **PurgeTSS** includes an Animation module to apply simple 2D Matrix animations and transformations to any element, an array of elements, or even to individual children of an element.
7
- :::
5
+ 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.
8
6
 
9
- The Animation object describes the properties of an animation. It represents:
7
+ The Animation object describes an animation in a few ways:
10
8
  - A single-phase animation with an end state
11
9
  - A multi-phase animation using the `open`, `close`, and `complete` modifiers
12
10
  - Global states for children of a View using the `children` modifier
13
11
 
14
- When the `play` method is called on a View, the View is animated from its current state to the state described by the `Animation` object. The properties that can be animated include the view's position, size, colors, transformation matrix, and opacity.
12
+ When you call `play` on a View, it animates from its current state to the state described by the Animation object. You can animate position, size, colors, transformation matrix, and opacity. Control timing with classes like `duration-*` and `delay-*`.
15
13
 
16
- ## Installation
14
+ ### Installation
17
15
 
18
16
  ```bash
19
17
  purgetss module
20
- # or
18
+ # alias:
21
19
  purgetss m
22
20
  ```
23
21
 
24
- Installs `purgetss.ui.js` in `app/lib/`.
25
-
26
- ## Basic Usage
22
+ ### Usage
27
23
 
28
24
  ```xml
29
- <Animation id="myAnimation" module="purgetss.ui" class="opacity-0 duration-200 open:opacity-100" />
25
+ <Animation id="myAnimation" module="purgetss.ui" class="a-set-of-purgetss-classes-and-modifiers" />
30
26
  ```
31
27
 
32
- ```javascript
33
- $.myAnimation.play($.myView)
34
- ```
28
+ You can use any position, size, color, transformation, and opacity classes from `utilities.tss`.
35
29
 
36
- **You can set any position, size, colors, transformation, and opacity classes from `utilities.tss`.**
30
+ ---
31
+
32
+ ## Methods Reference (All 15)
33
+
34
+ | Method | Signature | Description |
35
+ | --- | --- | --- |
36
+ | `play` | `play(views, cb)` | Animate views to Animation object state; toggles open/close on repeated calls |
37
+ | `toggle` | `toggle(views, cb)` | Alias for `play`; toggles between open and close states |
38
+ | `apply` | `apply(views, cb)` | Apply properties instantly without animation |
39
+ | `open` | `open(views, cb)` | Explicitly run the opening animation (no toggle) |
40
+ | `close` | `close(views, cb)` | Explicitly run the closing animation (no toggle) |
41
+ | `draggable` | `draggable(views)` | Make views draggable via touch events |
42
+ | `undraggable` | `undraggable(views)` | Remove draggable behavior and clean up all listeners |
43
+ | `detectCollisions` | `detectCollisions(views, dragCB, dropCB)` | Enable collision detection with hover/drop callbacks |
44
+ | `sequence` | `sequence(views, cb)` | Animate views one after another (sequential, not parallel) |
45
+ | `swap` | `swap(view1, view2)` | Animate two views exchanging positions |
46
+ | `pulse` | `pulse(view, count)` | Scale-up-and-back animation (default count=1) |
47
+ | `shake` | `shake(view, intensity)` | Horizontal shake for feedback (default intensity=10) |
48
+ | `snapTo` | `snapTo(view, targets)` | Snap view to nearest target by center distance; returns matched target or null |
49
+ | `reorder` | `reorder(views, newOrder)` | Animate views to new positions by index mapping |
50
+ | `transition` | `transition(views, layouts)` | Multi-view layout transitions using Matrix2D (translate, rotate, scale) |
51
+
52
+ The `play`, `toggle`, `open`, `close`, `apply`, and `sequence` methods accept an optional callback with an enriched event object.
37
53
 
38
54
  ---
39
55
 
40
- ## Available Methods
56
+ ## Modifiers
41
57
 
42
- | Method | Purpose |
43
- | ---------------- | -------------------------------------------------------- |
44
- | `play`, `toggle` | Animate element(s) or children with Animation properties |
45
- | `open`, `close` | Explicitly manage opening/closing animations |
46
- | `apply` | Apply properties instantly without animation |
47
- | `draggable` | Convert View(s) to draggable elements |
58
+ | Modifier | Purpose |
59
+ | --- | --- |
60
+ | `open:` | Properties applied during open state |
61
+ | `close:` | Properties applied during close state |
62
+ | `complete:` | Additional properties applied after an open animation finishes |
63
+ | `children:` | Global properties for all children of a View |
64
+ | `child:` | Individual properties for specific children |
65
+ | `bounds:` | Drag boundaries within parent |
66
+ | `drag:` | Properties applied while dragging |
67
+ | `drop:` | Properties applied on drop |
48
68
 
49
- ---
69
+ ### Timing and Special Classes
50
70
 
51
- ## The `play` Method
71
+ `delay-*`, `duration-*`, `rotate-*`, `scale-*`, `repeat-*`, `zoom-in-*`, `zoom-out-*`, `drag-apply`, `drag-animate`, `ease-in`, `ease-out`, `ease-linear`, `ease-in-out`, `vertical-constraint`, `horizontal-constraint`.
52
72
 
53
- The `play` method is used to reproduce the animation for a single view or an array of views. You can chain multiple Animation objects with callback functions to create a sequence of animations.
73
+ ---
54
74
 
55
- ### `play(views, [callback])`
75
+ ## The `play` Method
56
76
 
57
- Animates target(s) using defined class properties.
77
+ Runs the animation for a single view or an array of views. Toggles between open and close states on repeated calls.
58
78
 
59
79
  ```javascript
60
80
  $.myAnimation.play($.myView)
61
- $.myAnimation.play([$.view1, $.view2])
62
- $.myAnimation.play($.myView, () => { console.log('done') })
63
81
  ```
64
82
 
65
- **Use cases:**
66
- - One-time animations
67
- - Sequences with callbacks
68
- - Animating multiple views simultaneously
69
-
70
- ### Play Example 1
71
-
72
- Create an Animation element and the view you want to animate, and set the desired properties.
83
+ ### Basic Example
73
84
 
74
- ```xml title="index.xml"
75
- <Alloy>
76
- <Window>
77
- <Animation module="purgetss.ui" id="myAnimation" class="wh-32 bg-green-500 duration-1000" />
78
-
79
- <View id="square" class="wh-16 bg-blue-500" />
80
- </Window>
81
- </Alloy>
85
+ ```xml
86
+ <Animation module="purgetss.ui" id="myAnimation" class="wh-32 bg-green-500 duration-1000" />
87
+ <View id="square" class="wh-16 bg-blue-500" />
82
88
  ```
83
89
 
84
- ```javascript title="index.js"
85
- $.index.open()
86
-
90
+ ```javascript
87
91
  $.myAnimation.play($.square)
92
+ // Blue square animates from 64x64 to 128x128 and changes to green
88
93
  ```
89
94
 
90
- When the `play` method is called, the blue square will go from size 64x64 to 128x128 and change its color to green.
91
-
92
- ### Play Example 2: Complex Animations with States
93
-
94
- ```xml title="index.xml"
95
- <Alloy>
96
- <Window class="keep-screen-on">
97
- <Animation id="changeWidth" class="close:w-28 debug open:w-11/12" module="purgetss.ui" />
98
- <Animation id="changeColor" class="close:bg-blue-700 debug open:bg-purple-500" module="purgetss.ui" />
99
- <Animation id="changeTransparency" class="close:duration-300 open:mt-(null) close:mt-8 open:h-11/12 close:w-14 close:h-14 close:opacity-100 open:w-10/12 open:opacity-50 open:duration-150" module="purgetss.ui" />
100
- <Animation id="changeRetweet" class="close:duration-150 close:-mb-52 open:-mb-16 open:duration-200" module="purgetss.ui" />
101
-
102
- <View class="vertical">
103
- <Button class="ios:mt-16 mt-1 w-48 rounded bg-purple-500 text-purple-50" onClick="squaresFn" title="3 Squares" />
104
- <Button class="mt-2 w-48 rounded bg-purple-500 text-purple-50" onClick="toggleFn" title="Toggle Colors" />
105
- <Button class="mt-2 w-48 rounded bg-purple-500 text-purple-50" onClick="retweetFn" title="Toggle Re-Tweet" />
106
-
107
- <View id="squaresView" class="vertical mt-10 w-screen">
108
- <View class="wh-28 rounded-xl bg-blue-700" />
109
- <View class="wh-28 mt-4 rounded-xl bg-blue-700" />
110
- <View class="wh-28 mt-4 rounded-xl bg-blue-700" />
111
- </View>
112
- </View>
113
-
114
- <View id="blueSquareView" class="mt-8 h-14 w-14 rounded-xl bg-blue-500" onClick="transparencyFn" />
115
-
116
- <View id="retweetView" class="vertical -mb-52 h-48 w-screen rounded-2xl bg-gray-800" onClick="retweetFn">
117
- <View class="mt-4 h-1 w-8 bg-slate-700" />
118
-
119
- <View class="horizontal mx-4 mt-4">
120
- <Label class="fas fa-retweet w-7 text-xl text-slate-500" />
121
- <Label class="ml-2 text-left text-xl text-white" text="Re-Tweet" />
122
- </View>
123
-
124
- <View class="horizontal mx-4 mt-4">
125
- <Label class="fas fa-pencil-alt w-7 text-xl text-slate-500" />
126
- <Label class="ml-2 text-left text-xl text-white" text="Quote Tweet" />
127
- </View>
128
- </View>
129
- </Window>
130
- </Alloy>
131
- ```
132
-
133
- ```javascript title="index.js"
134
- function transparencyFn() {
135
- $.changeTransparency.play($.blueSquareView)
136
- }
137
-
138
- function toggleFn() {
139
- $.changeColor.toggle($.squaresView.children)
140
- }
95
+ ### open/close Modifiers
141
96
 
142
- function squaresFn() {
143
- $.changeWidth.play($.squaresView.children)
144
- }
97
+ Define different states for opening and closing:
145
98
 
146
- function retweetFn() {
147
- $.changeRetweet.play($.retweetView)
148
- }
149
-
150
- $.index.open()
151
- ```
152
-
153
- ### `toggle(views, [callback])`
154
-
155
- Alternates between `open:` and `close:` states.
156
-
157
- ```javascript
158
- $.myAnimation.toggle($.myView)
99
+ ```xml
100
+ <Animation id="changeColor" module="purgetss.ui" class="close:bg-blue-700 open:bg-purple-500" />
159
101
  ```
160
102
 
161
- **Use cases:**
162
- - UI state toggles (show/hide)
163
- - Accordion behavior
164
- - Alternating animations
165
-
166
- ---
103
+ First call applies `open:` properties; next call applies `close:` properties; continues toggling.
167
104
 
168
- ## The `open` and `close` Methods
105
+ ### `complete` Modifier
169
106
 
170
- The `open` and `close` methods provide a clear and straightforward way to manage the opening and closing animations of your views, utilizing the predefined classes with the `open` and `close` modifiers.
107
+ Applies additional properties after an `open` animation finishes:
171
108
 
172
- By using these methods, you can ensure consistent and manageable animation behavior across your application, as opposed to using the `play` or `toggle` methods, which alternate between the `open` and `close` states based on the current state of the view.
109
+ ```xml
110
+ <Animation module="purgetss.ui" id="myAnimationOpen"
111
+ class="open:scale-1 complete:bg-(#008800) complete:scale-100" />
112
+ ```
173
113
 
174
- This explicit control helps in scenarios where the exact state of the view is important for the UI or application logic.
114
+ View scales to `scale-1` (open), then on completion receives `bg-(#008800)` and `scale-100`.
175
115
 
176
- ### `open(views, [callback])`
116
+ ### Animating Arrays
177
117
 
178
- The `open` method triggers the opening animation for the specified views. It uses the properties defined under the classes with the `open` modifier.
118
+ Pass an array or `.children` to animate all views:
179
119
 
180
120
  ```javascript
181
- $.myAnimation.open(views, callback);
121
+ $.myAnimation.play($.squaresView.children)
122
+ $.myAnimation.play([$.view1, $.view2, $.view3])
182
123
  ```
183
124
 
184
- - `views`: The view or array of views to apply the opening animation to.
185
- - `callback`: An optional callback function that gets called when the animation completes.
186
-
187
- #### Open Method Example
188
-
189
- ```xml title="index.xml"
190
- <Alloy>
191
- <Window>
192
- <Animation module="purgetss.ui" id="myAnimation" class="close:opacity-0 open:opacity-100" />
125
+ The callback fires once per view. Use `e.index` and `e.total` to track progress.
193
126
 
194
- <View id="myView" class="opacity-0" />
195
- </Window>
196
- </Alloy>
197
- ```
198
-
199
- ```javascript title="index.js"
200
- $.myAnimation.open($.myView, () => {
201
- console.log('Open animation complete');
202
- });
203
- ```
127
+ ---
204
128
 
205
- In this example, the `myView` element will apply the animation properties defined in the classes with the `open` modifier when the `open` method is called, making the view fully opaque.
129
+ ## Callback Event Object
206
130
 
207
- ### `close(views, [callback])`
131
+ All methods that accept a callback (`play`, `toggle`, `open`, `close`, `apply`, `sequence`) receive an enriched event object:
208
132
 
209
- The `close` method triggers the closing animation for the specified views. It uses the properties defined under the classes with the `close` modifier.
133
+ ```javascript
134
+ $.myAnimation.play($.myView, (e) => {
135
+ console.log(e.action) // 'play'
136
+ console.log(e.state) // 'open' or 'close'
137
+ console.log(e.id) // Animation object ID
138
+ console.log(e.targetId) // ID of the animated view
139
+ })
140
+ ```
141
+
142
+ ### Event Object Properties
143
+
144
+ | Property | Type | Description |
145
+ | --- | --- | --- |
146
+ | `type` | `String` | `'complete'` (for play/open/close) or `'applied'` (for apply) |
147
+ | `bubbles` | `Boolean` | Whether the event bubbles |
148
+ | `cancelBubble` | `Boolean` | Whether bubbling is cancelled |
149
+ | `action` | `String` | `'play'` or `'apply'` |
150
+ | `state` | `String` | `'open'` or `'close'` |
151
+ | `id` | `String` | ID of the Animation object |
152
+ | `targetId` | `String` | ID of the animated view |
153
+ | `index` | `Number` | Position of the view in the array (0-based) |
154
+ | `total` | `Number` | Total number of views in the array |
155
+ | `getTarget()` | `Function` | Returns the animated view object |
156
+
157
+ ### Tracking Array Progress
210
158
 
211
159
  ```javascript
212
- $.myAnimation.close(views, callback);
160
+ $.myAnimation.play([$.card1, $.card2, $.card3], (e) => {
161
+ console.log(`Animated ${e.index + 1} of ${e.total}`)
162
+ if (e.index === e.total - 1) console.log('All animations complete')
163
+ })
213
164
  ```
214
165
 
215
- - `views`: The view or array of views to apply the closing animation to.
216
- - `callback`: An optional callback function that gets called when the animation completes.
217
-
218
- #### Close Method Example
219
-
220
- ```xml title="index.xml"
221
- <Alloy>
222
- <Window>
223
- <Animation module="purgetss.ui" id="myAnimation" class="close:opacity-0 open:opacity-100" />
224
-
225
- <View id="myView" class="opacity-100" />
226
- </Window>
227
- </Alloy>
228
- ```
166
+ Use `getTarget()` to reference the specific view that just finished:
229
167
 
230
- ```javascript title="index.js"
231
- $.myAnimation.close($.myView, () => {
232
- console.log('Close animation complete');
233
- });
168
+ ```javascript
169
+ $.myAnimation.play([$.card1, $.card2, $.card3], (e) => {
170
+ e.getTarget().borderColor = 'green'
171
+ })
234
172
  ```
235
173
 
236
- In this example, the `myView` element will apply the animation properties defined in the classes with the `close` modifier when the `close` method is called, making the view fully transparent.
237
-
238
- :::info
239
- The `open` and `close` methods provide explicit control over animation states, as opposed to `play` or `toggle` which alternate based on current state.
240
- :::
241
-
242
174
  ---
243
175
 
244
176
  ## The `apply` Method
245
177
 
246
- Use the `apply` method when you need to immediately apply the properties and transformations to a view without any animation.
247
-
248
- ### `apply(views)`
249
-
250
- Applies properties instantly without animation (bypasses bridge thread).
178
+ Applies properties instantly without animation. Callback has `action='apply'` and `type='applied'`.
251
179
 
252
180
  ```javascript
253
181
  $.myAnimation.apply($.myView)
254
- ```
255
182
 
256
- **Use cases:**
257
- - Resetting to initial state
258
- - Instant style changes
259
- - Setting up initial positions
260
-
261
- ### Apply Example: TikTok-like Interface
262
-
263
- The `apply` method sets the properties instantly. In this example, the `ScrollableView` is rotated 90 degrees, and its content is counter-rotated -90 degrees to simulate a **TikTok-like** interface.
264
-
265
- ```xml title="index.xml"
266
- <Alloy>
267
- <Window class="exit-on-close-false keep-screen-on">
268
- <Animation module="purgetss.ui" id="rotate" class="platform-wh-inverted rotate-90" />
269
- <Animation module="purgetss.ui" id="counterRotate" class="platform-wh -rotate-90" />
270
-
271
- <ScrollableView id="scrollableView" class="overlay-enabled disable-bounce paging-control-alpha-100 scrolling-enabled show-paging-control paging-control-h-14 paging-control-on-top-false paging-control-transparent page-indicator-(rgba(0,0,0,0.24)) current-page-indicator-(rgba(0,0,0,1))">
272
- <View class="bg-blue-500">
273
- <Label class="text-center" text="View's Content" />
274
- </View>
183
+ $.myAnimation.apply($.myView, (e) => {
184
+ console.log(e.action) // 'apply'
185
+ console.log(e.state) // 'open' or 'close'
186
+ })
187
+ ```
275
188
 
276
- <View class="bg-red-500">
277
- <Label class="text-center" text="View's Content" />
278
- </View>
189
+ ### TikTok-Style Rotation Example
279
190
 
280
- <View class="bg-green-500">
281
- <Label class="text-center" text="View's Content" />
282
- </View>
283
- </ScrollableView>
284
- </Window>
285
- </Alloy>
191
+ ```xml
192
+ <Animation module="purgetss.ui" id="rotate" class="platform-wh-inverted rotate-90" />
193
+ <Animation module="purgetss.ui" id="counterRotate" class="platform-wh -rotate-90" />
194
+ <ScrollableView id="scrollableView" class="overlay-enabled disable-bounce">
195
+ <View class="bg-blue-500"><Label text="Page 1" /></View>
196
+ <View class="bg-red-500"><Label text="Page 2" /></View>
197
+ </ScrollableView>
286
198
  ```
287
199
 
288
- ```javascript title="index.js"
200
+ ```javascript
289
201
  $.rotate.apply($.scrollableView)
290
-
291
202
  $.counterRotate.apply($.scrollableView.views)
292
-
293
203
  $.index.open()
294
204
  ```
295
205
 
296
206
  ---
297
207
 
298
- ## The `draggable` Method
299
-
300
- The `draggable` method allows you to convert any view or an array of views into draggable elements.
208
+ ## The `open` and `close` Methods
301
209
 
302
- - You can set **basic animations** when dragging or dropping elements using the `drag:` and `drop:` modifiers.
303
- - You can `apply` or `animate` the properties either globally or locally using the `drag-apply` or `drag-animate` classes.
304
- - You can also constrain any view using the `horizontal-constraint` or `vertical-constraint` classes.
210
+ Run opening and closing animations explicitly. They do not toggle -- you get direct control.
305
211
 
306
212
  ```javascript
307
- // Calling a draggable method
308
- $.draggableAnimation.draggable('A View or an array of Views')
213
+ $.myAnimation.open(views, callback)
214
+ $.myAnimation.close(views, callback)
309
215
  ```
310
216
 
311
- :::info
312
- **You can create a blank `Animation` object or use an existing one to call the `draggable` method to convert a view or array of views into 'draggable' objects.**
217
+ `open` uses properties under the `open:` modifier; `close` uses `close:` modifier. The callback receives the same enriched event object as `play`.
313
218
 
314
- **When using an Animation object on an array of views, it will handle the zIndex of each draggable element.**
315
- :::
219
+ ### Panel with Zoom-In Effect
316
220
 
317
- ### Draggable Example
318
-
319
- ```xml title="index.xml"
320
- <Alloy>
321
- <Window class="keep-screen-on exit-on-close-false">
322
- <Animation module="purgetss.ui" id="draggableAnimation" />
323
-
324
- <Label text="Draggable Example" class="mt-16 text-center" />
325
-
326
- <View id="red" class="ml-4 h-32 w-32 rounded-lg bg-red-500" />
327
-
328
- <View id="green" class="ml-10 h-32 w-32 rounded-lg bg-green-500" />
329
-
330
- <View id="blue" class="ml-16 h-32 w-32 rounded-lg bg-blue-500" />
331
- </Window>
332
- </Alloy>
221
+ ```xml
222
+ <View id="panel" class="hidden opacity-0" onClick="onOverlayTap">
223
+ <View class="h-screen w-screen bg-(#80000000)" />
224
+ <View id="content" class="zoom-in-110 close:duration-0 open:duration-100 mx-6 rounded-xl bg-slate-800" />
225
+ </View>
226
+ <Animation id="panelAnim" module="purgetss.ui" class="opacity-to-100 duration-75 ease-out" />
333
227
  ```
334
228
 
335
- ```javascript title="index.js"
336
- $.index.open()
229
+ ```javascript
230
+ function showPanel() {
231
+ $.panel.show()
232
+ $.panelAnim.open($.panel)
233
+ }
337
234
 
338
- $.draggableAnimation.draggable([$.red, $.green, $.blue])
235
+ function closePanel() {
236
+ $.panelAnim.close($.panel, () => { $.panel.hide() })
237
+ }
339
238
  ```
340
239
 
341
- ### `drag` and `drop` Modifiers
240
+ Key classes: `zoom-in-110` (pop effect), `opacity-to-100` (fade overlay), `close:duration-0 open:duration-100` (instant close, animated open).
342
241
 
343
- The `drag:` and `drop:` modifiers allow you to set basic animations while dragging and dropping elements.
344
-
345
- - You can set 'global' modifiers in the `Animation` object, or you can set individual modifiers for each view.
346
- - Local modifiers will overwrite any global modifier.
347
-
348
- :::info
349
- To simplify things, we are restricting the types of animations that can be applied while dragging (or dropping).
242
+ ---
350
243
 
351
- **Mainly, we are not applying any `size`, `scale`, or `anchorPoint` transformation.**
352
- :::
244
+ ## The `draggable` Method
353
245
 
354
- #### Drag & Drop Example
246
+ Makes one or more views draggable.
355
247
 
356
- ```xml title="index.xml"
357
- <Alloy>
358
- <Window class="keep-screen-on exit-on-close-false">
359
- <!-- Global set of modifiers -->
360
- <Animation id="draggableAnimation" module="purgetss.ui" class="drag:duration-100 drag:opacity-50 drop:opacity-100" />
248
+ ```javascript
249
+ $.draggableAnimation.draggable([$.red, $.green, $.blue])
250
+ ```
361
251
 
362
- <Label text="Global Modifiers:\ndrag:duration-100 drag:opacity-50 drop:opacity-100" class="mt-16 text-center" />
252
+ A blank or existing Animation object can be reused. When used with an array, zIndex is managed automatically.
363
253
 
364
- <!-- No local modifiers -->
365
- <Label id="red" class="mx-2 ml-4 h-32 w-32 rounded-lg bg-red-500 text-center text-xs text-white" text="No local modifiers" />
254
+ ### `drag:` and `drop:` Modifiers
366
255
 
367
- <!-- drag:bg-green-800 drop:bg-green-500 -->
368
- <Label id="green" class="drag:bg-green-800 drop:bg-green-500 ml-10 h-32 w-32 rounded-lg bg-green-500 text-center text-xs text-white" text="drag:bg-green-800 drop:bg-green-500" />
256
+ - **Global modifiers** on the Animation object apply to all views
257
+ - **Local modifiers** on individual views override globals
258
+ - While dragging, `size`, `scale`, and `anchorPoint` transformations are **not** applied
369
259
 
370
- <!-- drag:opacity-25 -->
371
- <Label id="blue" class="drag:opacity-25 ml-16 h-32 w-32 rounded-lg bg-blue-500 text-center text-xs text-white" text="drag:opacity-25" />
372
- </Window>
373
- </Alloy>
260
+ ```xml
261
+ <Animation id="draggableAnimation" module="purgetss.ui" class="drag:duration-100 drag:opacity-50 drop:opacity-100" />
262
+ <Label id="green" class="drag:bg-green-800 drop:bg-green-500 ml-10 h-32 w-32 rounded-lg bg-green-500" />
374
263
  ```
375
264
 
376
265
  ### `draggingType` Property
377
266
 
378
- To control how `drag:` and `drop:` modifiers are applied, you can use either the `drag-animate` (default) or `drag-apply` class. The `drag-animate` class will animate the properties, while the `drag-apply` class will apply them immediately.
379
-
380
- ```css title="utilities.tss"
381
- /* Component(s): For the Animation Component */
382
- /* Property(ies): draggingType */
383
- .drag-apply { draggingType: 'apply' }
384
- .drag-animate { draggingType: 'animate' }
385
- ```
386
-
387
- #### Dragging Type Example
388
-
389
- In the following example, the `Animation` element sets the global dragging type to `drag-apply`, but the green square overwrites it to `drag-animate`.
267
+ | Class | Behavior |
268
+ | --- | --- |
269
+ | `drag-animate` | Animate properties (default) |
270
+ | `drag-apply` | Apply properties instantly |
390
271
 
391
- ```xml title="index.xml"
392
- <Alloy>
393
- <Window class="keep-screen-on exit-on-close-false">
394
- <!-- Global set of modifiers -->
395
- <Animation id="draggableAnimation" module="purgetss.ui" class="drag-apply drag:duration-500 drag:opacity-50 drop:opacity-100" />
272
+ ### `bounds:` Modifier
396
273
 
397
- <Label text="draggingType Example:\ndrag-apply drag:duration-500 drag:opacity-50 drop:opacity-100" class="mt-16 text-center" />
274
+ Limits movement within the parent. Local on the view or global on the Animation object (local overrides global):
398
275
 
399
- <!-- No local modifiers, will be using the global modifiers -->
400
- <Label id="red" class="ml-4 h-32 w-32 rounded-lg bg-red-500 text-center text-xs text-white" text="No local modifiers" />
401
-
402
- <!-- drag-animate drag:bg-green-800 drop:bg-green-500 -->
403
- <Label id="green" class="drag-animate drag:bg-green-800 drop:bg-green-500 ml-10 h-32 w-32 rounded-lg bg-green-500 text-center text-xs text-white" text="drag-animate drag:bg-green-800 drop:bg-green-500" />
404
-
405
- <!-- drag:opacity-25 -->
406
- <Label id="blue" class="drag:opacity-25 ml-16 h-32 w-32 rounded-lg bg-blue-500 text-center text-xs text-white" text="drag:opacity-25" />
407
- </Window>
408
- </Alloy>
276
+ ```xml
277
+ <View id="card" class="bounds:m-2 bounds:mb-16 mt-8 h-24 w-64" />
278
+ <Animation id="dragAnim" module="purgetss.ui" class="bounds:m-2 bounds:mb-16" />
409
279
  ```
410
280
 
411
- ### `bounds` Modifier
412
-
413
- You can set boundaries in which a view can move within its parent view using the `bounds:` modifier.
414
-
415
- - You can set global boundaries in the Animation object and/or local boundaries for each individual child view.
416
- - Local values will overwrite any global values.
417
-
418
- #### Bounds Example 1: Local Bounds
281
+ ### Constraints
419
282
 
420
- The `card` view has a boundary of `m-4` and a bottom boundary of `mb-16`.
283
+ | Class | Effect |
284
+ | --- | --- |
285
+ | `horizontal-constraint` | Horizontal movement only |
286
+ | `vertical-constraint` | Vertical movement only |
421
287
 
422
- ```xml title="index.xml"
423
- <Alloy>
424
- <Window class="keep-screen-on exit-on-close-false bg-green-50">
425
- <Animation id="draggableAnimation" module="purgetss.ui" />
426
-
427
- <View class="mx-6 mb-6 mt-10 h-screen w-screen rounded-lg bg-green-200">
428
- <View id="card" class="bounds:m-2 bounds:mb-16 mt-8 h-24 w-64 shadow-lg">
429
- <View id="cardInside" class="w-screen rounded-lg border-2 border-purple-700 bg-white">
430
- <ImageView id="theImage" class="rounded-16 prevent-default-image m-4 ml-4 h-16 w-16 bg-gray-50" image="https://randomuser.me/api/portraits/women/17.jpg" />
431
-
432
- <View class="vertical ml-24 w-screen">
433
- <Label class="ml-0 text-sm font-bold text-gray-800" text="Ms. Jane Doe" />
434
- <Label class="ml-0 text-xs font-bold text-gray-400" text="Website Designer" />
435
- </View>
436
- </View>
437
- </View>
438
-
439
- <Label class="bg-(#80000000) mx-2 mb-2 h-12 w-screen rounded-lg text-center text-white" text="Some Element..." />
440
- </View>
441
- </Window>
442
- </Alloy>
443
- ```
444
-
445
- ```javascript title="index.js"
446
- $.index.open()
447
-
448
- $.draggableAnimation.draggable($.card)
449
- ```
288
+ ---
450
289
 
451
- #### Bounds Example 2: Global Bounds
452
-
453
- In this example, the boundaries are set globally in the `draggableAnimation` view. Every card view will use these global values.
454
-
455
- ```xml title="index.xml"
456
- <Alloy>
457
- <Window class="keep-screen-on exit-on-close-false bg-green-50">
458
- <Animation id="draggableAnimation" module="purgetss.ui" class="bounds:m-2 bounds:mb-16" />
459
-
460
- <View class="wh-screen mx-6 mb-6 mt-10 rounded-lg bg-green-200">
461
- <View id="card" class="mt-8 h-24 w-64 shadow-lg">
462
- <View id="cardInside" class="w-screen rounded-lg border-2 border-purple-700 bg-white">
463
- <ImageView id="theImage" class="rounded-16 prevent-default-image wh-16 m-4 bg-gray-50" image="https://randomuser.me/api/portraits/women/17.jpg" />
464
-
465
- <View class="vertical ml-24 w-screen">
466
- <Label class="ml-0 text-sm font-bold text-gray-800" text="Ms. Jane Doe" />
467
- <Label class="ml-0 text-xs font-bold text-gray-400" text="Website Designer" />
468
- </View>
469
- </View>
470
- </View>
471
-
472
- <View id="card2" class="mt-40 h-24 w-64 shadow-lg">
473
- <View id="cardInside" class="w-screen rounded-lg border-2 border-purple-700 bg-white">
474
- <ImageView id="theImage" class="rounded-16 prevent-default-image wh-16 m-4 bg-gray-50" image="https://randomuser.me/api/portraits/women/21.jpg" />
475
-
476
- <View class="vertical ml-24 w-screen">
477
- <Label class="ml-0 text-sm font-bold text-gray-800" text="Ms. Jane Doe" />
478
- <Label class="ml-0 text-xs font-bold text-gray-400" text="Website Designer" />
479
- </View>
480
- </View>
481
- </View>
482
-
483
- <View id="card3" class="mt-72 h-24 w-64 shadow-lg">
484
- <View id="cardInside" class="w-screen rounded-lg border-2 border-purple-700 bg-white">
485
- <ImageView id="theImage" class="rounded-16 prevent-default-image wh-16 m-4 bg-gray-50" image="https://randomuser.me/api/portraits/women/25.jpg" />
486
-
487
- <View class="vertical ml-24 w-screen">
488
- <Label class="ml-0 text-sm font-bold text-gray-800" text="Ms. Jane Doe" />
489
- <Label class="ml-0 text-xs font-bold text-gray-400" text="Website Designer" />
490
- </View>
491
- </View>
492
- </View>
493
-
494
- <Label class="bg-(#80000000) mx-2 mb-2 h-12 w-screen rounded-lg text-center text-white" text="Some Element..." />
495
- </View>
496
- </Window>
497
- </Alloy>
498
- ```
290
+ ## The `undraggable` Method
499
291
 
500
- ```javascript title="index.js"
501
- $.index.open()
292
+ Removes draggable behavior and cleans up all listeners from one or more views.
502
293
 
503
- $.draggableAnimation.draggable([$.card, $.card2, $.card3])
294
+ ```javascript
295
+ $.draggableAnimation.undraggable($.card)
296
+ $.draggableAnimation.undraggable([$.card1, $.card2, $.card3])
504
297
  ```
505
298
 
506
- ### `vertical` and `horizontal` Constraints
299
+ Removes: `touchstart`/`touchend`/`touchmove` listeners, `Ti.Gesture.orientationchange` listener, collision detection registry entries, and internal properties (`_originTop`, `_originLeft`, `_visualTop`, `_visualLeft`, `_collisionEnabled`, `_dragListeners`, `_wasDragged`, `_bouncingBack`).
507
300
 
508
- To add a vertical or horizontal constraint to any `dragging` element, set the `vertical-constraint` or `horizontal-constraint` classes on the view.
301
+ **Use cases:** Lock a piece after correct placement, toggle edit/presentation mode, cleanup on window close (prevents memory leaks from global `orientationchange` listener).
509
302
 
510
- ```css
511
- /* Component(s): Ti.UI.Animation */
512
- /* Property(ies): A custom property to use it with the Animation module */
513
- '.horizontal-constraint': { constraint: 'horizontal' }
514
- '.vertical-constraint': { constraint: 'vertical' }
303
+ ```javascript
304
+ function onClose() {
305
+ $.anim.undraggable(allDraggableViews)
306
+ }
515
307
  ```
516
308
 
517
- #### Constraint Example
518
-
519
- In this example, the `card` view will move only from side to side.
520
-
521
- ```xml title="index.xml"
522
- <Alloy>
523
- <Window class="keep-screen-on exit-on-close-false">
524
- <Animation id="draggableAnimation" module="purgetss.ui" />
525
-
526
- <View id="card" class="horizontal-constraint h-24 w-64 shadow-lg">
527
- <View id="cardInside" class="w-screen rounded-lg border-2 border-purple-700 bg-white">
528
- <ImageView id="theImage" class="rounded-16 wh-16 m-4 ml-4" image="https://randomuser.me/api/portraits/women/17.jpg" />
309
+ ---
529
310
 
530
- <View class="vertical ml-24 w-screen">
531
- <Label class="ml-0 text-sm font-bold text-gray-800" text="Ms. Jane Doe" />
532
- <Label class="ml-0 text-xs font-bold text-gray-400" text="Website Designer" />
533
- </View>
534
- </View>
535
- </View>
536
- </Window>
537
- </Alloy>
538
- ```
311
+ ## The `detectCollisions` Method
539
312
 
540
- ```javascript title="index.js"
541
- $.index.open()
313
+ After calling `draggable()`, enable collision detection based on center-point hit testing.
542
314
 
543
- $.draggableAnimation.draggable($.card)
315
+ ```javascript
316
+ $.myAnimation.draggable(views)
317
+ $.myAnimation.detectCollisions(views, dragCB, dropCB)
544
318
  ```
545
319
 
546
- ---
320
+ ### Parameters
547
321
 
548
- ## State Modifiers
322
+ | Parameter | Type | Description |
323
+ | --- | --- | --- |
324
+ | `views` | `View/Array` | Views to register for collision detection |
325
+ | `dragCB` | `Function(source, target)` | Called during drag; `target` is the view under the drag center, or `null` when leaving |
326
+ | `dropCB` | `Function(source, target)` | Called on drop when a collision target is found |
549
327
 
550
- Define behavior in the `class` attribute:
328
+ ### Snap Classes
551
329
 
552
- ### `open:` and `close:`
330
+ Off by default -- opt-in via classes on the `<Animation>` object:
553
331
 
554
- Properties for opening/closing phases.
332
+ | Class | Behavior |
333
+ | --- | --- |
334
+ | `snap-back` | View returns to origin when dropped **outside** any target |
335
+ | `snap-center` | View auto-centers on target when dropped **on** it (uses `snapTo` internally) |
555
336
 
556
337
  ```xml
557
- <Animation class="close:opacity-0 close:w-28 open:w-11/12 open:opacity-100" />
338
+ <Animation id="myAnim" module="purgetss.ui" class="snap-back snap-center duration-200" />
558
339
  ```
559
340
 
560
- ### `complete:` Modifier
341
+ ### Example
561
342
 
562
- To apply additional properties after an `open` animation is finished, use the `complete` modifier.
343
+ ```javascript
344
+ const views = [$.dropZone, $.card]
345
+ $.myAnimation.draggable(views)
346
+ $.myAnimation.detectCollisions(views,
347
+ (source, target) => {
348
+ if (target) {
349
+ target.borderColor = 'green'
350
+ } else {
351
+ $.dropZone.borderColor = '#9ca3af'
352
+ }
353
+ },
354
+ (source, target) => {
355
+ console.log(`Dropped ${source.id} onto ${target.id}`)
356
+ }
357
+ )
358
+ ```
359
+
360
+ ### Drag-to-Swap Grid
361
+
362
+ Combining `draggable` + `detectCollisions` + `swap`:
563
363
 
564
- ```xml
565
- <Animation class="open:scale-1 complete:bg-(#008800) complete:scale-100" />
364
+ ```javascript
365
+ const cards = [$.c0, $.c1, $.c2, $.c3]
366
+ $.gridAnim.draggable(cards)
367
+
368
+ let lastTarget = null
369
+ $.gridAnim.detectCollisions(cards,
370
+ (source, target) => {
371
+ if (lastTarget && lastTarget !== target) lastTarget.applyProperties({ opacity: 1 })
372
+ if (target) target.applyProperties({ opacity: 0.6 })
373
+ lastTarget = target
374
+ },
375
+ (source, target) => {
376
+ if (target) {
377
+ target.applyProperties({ opacity: 1 })
378
+ $.gridAnim.swap(source, target)
379
+ }
380
+ lastTarget = null
381
+ }
382
+ )
566
383
  ```
567
384
 
568
- :::tip
569
- Use `complete:` for post-animation state - e.g., setting a background color after a fade-in completes.
570
- :::
571
-
572
- #### Complete Example: Wordle Animation
573
-
574
- In the following code, the `open` animation reduces the children of the `letters` view to a size of 1%. After completion, the `complete` modifier will set the background color to green and the scaling back to 100%.
575
-
576
- ```xml title="index.xml"
577
- <Alloy>
578
- <Window title="App Wordle" class="bg-(#181e2d)">
579
- <Animation module="purgetss.ui" id="myAnimationReset" class="bg-transparent" />
580
- <Animation module="purgetss.ui" id="myAnimationOpen" class="open:scale-1 complete:bg-(#008800) complete:scale-100" />
581
-
582
- <View class="vertical">
583
- <View id="letters" class="horizontal">
584
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="T" />
585
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="I" />
586
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="T" />
587
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="A" />
588
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="N" />
589
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="I" />
590
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="U" />
591
- <Label class="wh-10 mx-1 rounded border-white bg-transparent text-center text-white" text="M" />
592
- </View>
593
-
594
- <Button title="Animate" class="mt-8" android:onClick="doAnimate" ios:onSingletap="doAnimate" />
595
- <Button title="Reset" class="mt-4" android:onClick="doReset" ios:onSingletap="doReset" />
596
- </View>
597
- </Window>
598
- </Alloy>
599
- ```
385
+ ---
600
386
 
601
- ```javascript title="index.js"
602
- $.index.open()
387
+ ## The `sequence` Method
603
388
 
604
- function doAnimate() {
605
- $.myAnimationOpen.play($.letters.children)
606
- }
389
+ Animates views one after another. Unlike `play(array)` which runs in parallel, `sequence` waits for each view to complete before starting the next.
607
390
 
608
- function doReset() {
609
- $.myAnimationReset.apply($.letters.children)
610
- }
391
+ ```javascript
392
+ $.myAnimation.sequence(views, callback)
611
393
  ```
612
394
 
613
- ### `children:`
395
+ - The `open`/`close` state is toggled once for the entire sequence
396
+ - Each view fully completes before the next starts
397
+ - The callback fires once after the last view finishes
614
398
 
615
- Applies animation rules globally to ALL children of target View.
399
+ ### Onboarding Reveal Example
616
400
 
617
401
  ```xml
618
- <Animation class="children:opacity-50 complete:opacity-100" />
619
-
620
- <View>
621
- <Label /> <!-- All children affected -->
622
- <View /> <!-- All children affected -->
623
- </View>
402
+ <Animation id="revealAnim" module="purgetss.ui" class="open:opacity-100 close:opacity-0 duration-300" />
403
+ <Label id="title" class="opacity-0 text-2xl font-bold" text="Welcome" />
404
+ <Label id="subtitle" class="opacity-0 mt-2 text-lg text-gray-500" text="To the app" />
405
+ <Button id="cta" class="opacity-0 mt-4 rounded bg-blue-500 text-white" title="Get Started" />
624
406
  ```
625
407
 
626
- ### `child:`
627
-
628
- Targets specific child properties by index (0-based).
629
-
630
- ```xml
631
- <Animation class="child:0:bg-red-500 child:1:bg-blue-500" />
408
+ ```javascript
409
+ $.fadeIn.sequence([$.title, $.subtitle, $.cta], () => {
410
+ console.log('All views animated in sequence')
411
+ })
632
412
 
633
- <View>
634
- <Label /> <!-- Index 0: Red background -->
635
- <View /> <!-- Index 1: Blue background -->
636
- </View>
413
+ // Use close() to force state back before revealing again
414
+ $.revealAnim.close(views)
637
415
  ```
638
416
 
639
417
  ---
640
418
 
641
- ## Complex UI Elements
419
+ ## The `swap` Method
642
420
 
643
- Here is an example of the Animation module with a more complex UI featuring an animated sidebar and expandable card.
421
+ Exchanges positions of two views with animation.
644
422
 
645
- :::tip
646
- To use this example, you'll need to install the FontAwesome fonts in your project by running:
647
- ```bash
648
- purgetss icon-library -v=fa
649
- ```
650
- :::
651
-
652
- ```xml title="index.xml"
653
- <Alloy>
654
- <Window class="exit-on-close-false portrait bg-purple-700">
655
- <Animation id="draggableAnimation" module="purgetss.ui" class="bounds:m-4 bounds:mb-20" />
656
-
657
- <!-- Sidebar -->
658
- <Animation id="sideBarAnimation" module="purgetss.ui" class="close:w-24 duration-150 open:w-72" />
659
- <Animation id="sideBarAnimationChevron" module="purgetss.ui" class="close:rotate-0 duration-150 open:rotate-180" />
660
-
661
- <View id="sideBar" class="ml-2 h-1/2 w-24">
662
- <View class="vertical ios:shadow-lg mr-8 rounded-lg bg-white" ios:onSingletap="doAction" android:onClick="doAction">
663
- <View class="grid-flow-row">
664
- <View class="grid-rows-7 ml-0 w-64">
665
- <View class="horizontal bg-selected-purple-100 items-center" action="home">
666
- <Label class="touch-enabled-false fas fa-home ml-0 h-full w-16 border-transparent bg-transparent text-center text-xl text-purple-700" />
667
- <Label class="touch-enabled-false text-purple-700" text="Home" />
668
- </View>
669
- </View>
670
-
671
- <View class="grid-rows-7 ml-0 w-64">
672
- <View class="horizontal bg-selected-purple-100 items-center" action="profile">
673
- <Label class="touch-enabled-false fas fa-user ml-0 h-full w-16 border-transparent bg-transparent text-center text-xl text-purple-700" />
674
- <Label class="touch-enabled-false text-purple-700" text="Profile" />
675
- </View>
676
- </View>
677
-
678
- <View class="grid-rows-7 ml-0 w-64">
679
- <View class="horizontal bg-selected-purple-100 items-center" action="messages">
680
- <Label class="touch-enabled-false fas fa-comment ml-0 h-full w-16 border-transparent bg-transparent text-center text-xl text-purple-700" />
681
- <Label class="touch-enabled-false text-purple-700" text="Messages" />
682
- </View>
683
- </View>
684
-
685
- <View class="grid-rows-7 ml-0 w-64">
686
- <View class="horizontal bg-selected-purple-100 items-center" action="help">
687
- <Label class="touch-enabled-false fas fa-question-circle ml-0 h-full w-16 border-transparent bg-transparent text-center text-xl text-purple-700" />
688
- <Label class="touch-enabled-false text-purple-700" text="Help" />
689
- </View>
690
- </View>
691
-
692
- <View class="grid-rows-7 ml-0 w-64">
693
- <View class="horizontal bg-selected-purple-100 items-center" action="settings">
694
- <Label class="touch-enabled-false fas fa-cog ml-0 h-full w-16 border-transparent bg-transparent text-center text-xl text-purple-700" />
695
- <Label class="touch-enabled-false text-purple-700" text="Settings" />
696
- </View>
697
- </View>
698
-
699
- <View class="grid-rows-7 ml-0 w-64">
700
- <View class="horizontal bg-selected-purple-100 items-center" action="password">
701
- <Label class="touch-enabled-false fas fa-lock ml-0 h-full w-16 border-transparent bg-transparent text-center text-xl text-purple-700" />
702
- <Label class="touch-enabled-false text-purple-700" text="Password" />
703
- </View>
704
- </View>
705
-
706
- <View class="grid-rows-7 ml-0 w-64">
707
- <View class="horizontal bg-selected-purple-100 items-center" action="sign-out">
708
- <Label class="touch-enabled-false fas fa-sign-out-alt ml-0 h-full w-16 border-transparent bg-transparent text-center text-xl text-purple-700" />
709
- <Label class="touch-enabled-false text-purple-700" text="Sign Out" />
710
- </View>
711
- </View>
712
- </View>
713
- </View>
714
-
715
- <Button id="sideBarChevron" class="fas rounded-10 fa-chevron-right mr-1.5 h-10 w-10 border-4 border-purple-700 bg-white text-xl text-purple-700" ios:onSingletap="sideBarClicked" android:onClick="sideBarClicked" />
716
-
717
- </View>
718
-
719
- <!-- My Card -->
720
- <Animation id="myCardAnimation" module="purgetss.ui" class="open:h-(298) close:h-24 duration-150" />
721
- <Animation id="myCardAnimationChevron" module="purgetss.ui" class="close:rotate-0 duration-150 open:rotate-180" />
722
-
723
- <View id="myCard" class="mr-6 mt-6 h-24 w-8/12 rounded-lg shadow-lg">
724
- <View class="vertical rounded-lg bg-white">
725
- <View class="h-auto w-screen">
726
- <ImageView class="rounded-16 m-4 ml-4 h-16 w-16" image="https://randomuser.me/api/portraits/women/17.jpg" />
727
-
728
- <View class="vertical ml-24 h-auto">
729
- <Label class="ml-0 text-sm font-bold text-gray-800" text="Someone Famous" />
730
- <Label class="ml-0 text-xs font-bold text-gray-400" text="Website Designer" />
731
- </View>
732
- </View>
733
-
734
- <View class="rounded-1 mx-2 h-0.5 w-screen bg-gray-300" />
735
-
736
- <View class="bubble-parent-false mt-2 h-48 w-screen grid-flow-row" ios:onSingletap="doAction" android:onClick="doAction">
737
- <View class="ml-0 w-screen grid-rows-5">
738
- <View class="horizontal bg-selected-purple-100 items-center" action="profile">
739
- <Label class="touch-enabled-false fas fa-user ml-0 h-full w-14 border-transparent bg-transparent text-center text-xl text-purple-700" />
740
- <Label class="touch-enabled-false text-sm text-purple-700" text="Edit Profile" />
741
- </View>
742
- </View>
743
-
744
- <View class="ml-0 w-screen grid-rows-5">
745
- <View class="horizontal bg-selected-purple-100 items-center" action="inbox">
746
- <Label class="touch-enabled-false fas fa-inbox ml-0 h-full w-14 border-transparent bg-transparent text-center text-xl text-purple-700" />
747
- <Label class="touch-enabled-false text-sm text-purple-700" text="Inbox" />
748
- </View>
749
- </View>
750
-
751
- <View class="ml-0 w-screen grid-rows-5">
752
- <View class="horizontal bg-selected-purple-100 items-center" action="settings">
753
- <Label class="touch-enabled-false fas fa-cog ml-0 h-full w-14 border-transparent bg-transparent text-center text-xl text-purple-700" />
754
- <Label class="touch-enabled-false text-sm text-purple-700" text="Settings" />
755
- </View>
756
- </View>
757
-
758
- <View class="ml-0 w-screen grid-rows-5">
759
- <View class="horizontal bg-selected-purple-100 items-center" action="support">
760
- <Label class="touch-enabled-false fas fa-question-circle ml-0 h-full w-14 border-transparent bg-transparent text-center text-xl text-purple-700" />
761
- <Label class="touch-enabled-false text-sm text-purple-700" text="Support" />
762
- </View>
763
- </View>
764
-
765
- <View class="ml-0 w-screen grid-rows-5">
766
- <View class="horizontal bg-selected-purple-100 items-center" action="sign-out">
767
- <Label class="touch-enabled-false fas fa-sign-out-alt ml-0 h-full w-14 border-transparent bg-transparent text-center text-xl text-purple-700" />
768
- <Label class="touch-enabled-false text-sm text-purple-700" text="Sign Out" />
769
- </View>
770
- </View>
771
- </View>
772
- </View>
773
-
774
- <View class="rounded-tl-br-md wh-8 bubble-parent-false mb-0 mr-0 bg-blue-400">
775
- <Button id="myCardChevron" class="fas fa-chevron-down border-transparent bg-transparent text-white" ios:onSingletap="myCardClicked" android:onClick="myCardClicked" />
776
- </View>
777
- </View>
778
-
779
- <Label id="action" class="mx-4 mb-6 h-10 w-screen rounded-lg bg-purple-800 text-sm font-bold text-purple-50" />
780
- </Window>
781
- </Alloy>
423
+ ```javascript
424
+ $.myAnimation.swap(view1, view2)
782
425
  ```
783
426
 
784
- ```javascript title="index.js"
785
- $.index.open()
786
-
787
- $.draggableAnimation.draggable($.myCard)
427
+ **Behavior:**
428
+ - Inherits `duration`, `delay`, `curve` from Animation object. Fallback: **200ms**, **0ms**, **EASE_IN_OUT**
429
+ - Handles iOS transform reset automatically
430
+ - Temporarily elevates z-index; restores after completion
431
+ - Updates `_originLeft`/`_originTop` for subsequent drag operations
432
+ - **Automatic position normalization**: no explicit `top`/`left` needed -- resolved via `view.rect`
433
+ - **Bounce-back safe**: completes any in-progress bounce-back before swapping
788
434
 
789
- function sideBarClicked() {
790
- $.sideBarAnimation.play($.sideBar)
791
- $.sideBarAnimationChevron.play($.sideBarChevron)
792
- }
793
-
794
- function myCardClicked() {
795
- $.myCardAnimation.play($.myCard)
796
- $.myCardAnimationChevron.play($.myCardChevron)
797
- }
435
+ ### Memory Card Game Example
798
436
 
799
- function doAction(event) {
800
- if (event.source.action) {
801
- $.action.text = ` Action: ${event.source.action}`
802
- }
437
+ ```javascript
438
+ let firstCard = null
439
+ function onCardTap({ source }) {
440
+ $.flipAnim.open(source)
441
+ if (!firstCard) { firstCard = source; return }
442
+ if (firstCard.valor === source.valor) {
443
+ firstCard = null
444
+ } else {
445
+ $.gameAnim.swap(firstCard, source)
446
+ setTimeout(() => { $.flipAnim.close([firstCard, source]); firstCard = null }, 500)
447
+ }
803
448
  }
804
449
  ```
805
450
 
806
451
  ---
807
452
 
808
- ## Available Utilities
809
-
810
- Along with the regular utilities like color, widths, and heights, you can set the following utilities on your animations:
811
-
812
- ### anchorPoint
813
-
814
- Coordinate of the view about which to pivot an animation.
815
-
816
- This is specified as a dictionary object with x and y properties, where `{x: 0.5, y: 0.5}` represents the center of whatever is being rotated.
817
-
818
- **Default:** `(0.5, 0.5)`
819
-
820
- ```css
821
- /* Property(ies): anchorPoint */
822
- /* Component(s): Ti.UI.Animation, Ti.UI.View */
823
- '.origin-center': { anchorPoint: { x: 0.5, y: 0.5 } }
824
- '.origin-top': { anchorPoint: { x: 0.5, y: 0 } }
825
- '.origin-top-right': { anchorPoint: { x: 1, y: 0 } }
826
- '.origin-right': { anchorPoint: { x: 0.5, y: 1 } }
827
- '.origin-bottom-right': { anchorPoint: { x: 1, y: 1 } }
828
- '.origin-bottom': { anchorPoint: { x: 0.5, y: 1 } }
829
- '.origin-bottom-left': { anchorPoint: { x: 0, y: 1 } }
830
- '.origin-left': { anchorPoint: { x: 0, y: 0.5 } }
831
- '.origin-top-left': { anchorPoint: { x: 0, y: 0 } }
832
-
833
- /* anchor-point-{position} variant */
834
- '.anchor-point-center': { anchorPoint: { x: 0.5, y: 0.5 } }
835
- '.anchor-point-top': { anchorPoint: { x: 0.5, y: 0 } }
836
- '.anchor-point-top-right': { anchorPoint: { x: 1, y: 0 } }
837
- '.anchor-point-right': { anchorPoint: { x: 0.5, y: 1 } }
838
- '.anchor-point-bottom-right': { anchorPoint: { x: 1, y: 1 } }
839
- '.anchor-point-bottom': { anchorPoint: { x: 0.5, y: 1 } }
840
- '.anchor-point-bottom-left': { anchorPoint: { x: 0, y: 1 } }
841
- '.anchor-point-left': { anchorPoint: { x: 0, y: 0.5 } }
842
- '.anchor-point-top-left': { anchorPoint: { x: 0, y: 0 } }
843
- ```
844
-
845
- ### autoreverse
453
+ ## The `pulse` Method
846
454
 
847
- Specifies if the animation should be replayed in reverse upon completion.
455
+ Scales a view up and back using native `autoreverse` + `repeat`.
848
456
 
849
- **Default:** `false`
850
-
851
- ```css
852
- /* Property: autoreverse */
853
- /* Description: Specifies if the animation should be replayed in reverse upon completion. */
854
- /* Component(s): Ti.UI.Animation */
855
- '.autoreverse': { autoreverse: true }
856
- '.autoreverse-false': { autoreverse: false }
857
- ```
858
-
859
- ### curve
860
-
861
- Animation curve or easing function to apply to the animation.
862
-
863
- This API can be assigned the following constants:
864
-
865
- ```css
866
- /* Property: curve */
867
- /* Description: Animation curve or easing function to apply to the animation. */
868
- /* Component(s): Ti.UI.Animation */
869
- '.curve-animation-ease-in': { curve: Ti.UI.ANIMATION_CURVE_EASE_IN }
870
- '.curve-animation-ease-in-out': { curve: Ti.UI.ANIMATION_CURVE_EASE_IN_OUT }
871
- '.curve-animation-ease-out': { curve: Ti.UI.ANIMATION_CURVE_EASE_OUT }
872
- '.curve-animation-linear': { curve: Ti.UI.ANIMATION_CURVE_LINEAR }
457
+ ```javascript
458
+ $.myAnimation.pulse(view, count)
873
459
  ```
874
460
 
875
- ### delay
876
-
877
- Delay, in milliseconds before starting the animation.
878
-
879
- ```css
880
- /* Property: delay */
881
- /* Description: Delay, in milliseconds before starting the animation. */
882
- /* Component(s): Ti.UI.Animation */
883
- '.delay-0': { delay: 0 }
884
- '.delay-25': { delay: 25 }
885
- '.delay-50': { delay: 50 }
886
- '.delay-75': { delay: 75 }
887
- '.delay-100': { delay: 100 }
888
- '.delay-150': { delay: 150 }
889
- '.delay-200': { delay: 200 }
890
- '.delay-250': { delay: 250 }
891
- '.delay-300': { delay: 300 }
892
- '.delay-350': { delay: 350 }
893
- '.delay-400': { delay: 400 }
894
- '.delay-450': { delay: 450 }
895
- '.delay-500': { delay: 500 }
896
- '.delay-600': { delay: 600 }
897
- '.delay-700': { delay: 700 }
898
- '.delay-800': { delay: 800 }
899
- '.delay-900': { delay: 900 }
900
- '.delay-1000': { delay: 1000 }
901
- '.delay-2000': { delay: 2000 }
902
- '.delay-3000': { delay: 3000 }
903
- '.delay-4000': { delay: 4000 }
904
- '.delay-5000': { delay: 5000 }
905
- ```
461
+ | Parameter | Type | Default | Description |
462
+ | --- | --- | --- | --- |
463
+ | `view` | `View` | -- | The view to pulse |
464
+ | `count` | `Number` | `1` | Number of pulses |
906
465
 
907
- ### duration
908
-
909
- Duration of the animation, in milliseconds.
910
-
911
- ```css
912
- /* Property: duration */
913
- /* Component(s): Ti.UI.Animation */
914
- '.duration-0': { duration: 0 }
915
- '.duration-25': { duration: 25 }
916
- '.duration-50': { duration: 50 }
917
- '.duration-75': { duration: 75 }
918
- '.duration-100': { duration: 100 }
919
- '.duration-150': { duration: 150 }
920
- '.duration-200': { duration: 200 }
921
- '.duration-250': { duration: 250 }
922
- '.duration-300': { duration: 300 }
923
- '.duration-350': { duration: 350 }
924
- '.duration-400': { duration: 400 }
925
- '.duration-450': { duration: 450 }
926
- '.duration-500': { duration: 500 }
927
- '.duration-600': { duration: 600 }
928
- '.duration-700': { duration: 700 }
929
- '.duration-800': { duration: 800 }
930
- '.duration-900': { duration: 900 }
931
- '.duration-1000': { duration: 1000 }
932
- '.duration-2000': { duration: 2000 }
933
- '.duration-3000': { duration: 3000 }
934
- '.duration-4000': { duration: 4000 }
935
- '.duration-5000': { duration: 5000 }
936
- ```
466
+ - Scale from Animation object's `scale` class (e.g., `scale-(1.3)`). Fallback: **1.2x**
467
+ - Duration inherited; full cycle is double (up + back)
468
+ - Always uses `EASE_IN_OUT`; resets transform on completion
937
469
 
938
- ### repeat
939
-
940
- Number of times the animation should be performed.
941
-
942
- If `autoreverse` is true, then one repeat of the animation consists of the animation being played once forward and once backward.
943
-
944
- ```css
945
- /* Property: repeat */
946
- /* Component(s): Ti.UI.Animation */
947
- '.repeat-0': { repeat: 0 }
948
- '.repeat-1': { repeat: 1 }
949
- '.repeat-2': { repeat: 2 }
950
- '.repeat-3': { repeat: 3 }
951
- '.repeat-4': { repeat: 4 }
952
- '.repeat-5': { repeat: 5 }
953
- '.repeat-6': { repeat: 6 }
954
- '.repeat-7': { repeat: 7 }
955
- '.repeat-8': { repeat: 8 }
956
- '.repeat-9': { repeat: 9 }
957
- '.repeat-10': { repeat: 10 }
958
- '.repeat-11': { repeat: 11 }
959
- '.repeat-12': { repeat: 12 }
470
+ ```xml
471
+ <Animation id="pulseAnim" module="purgetss.ui" class="scale-(1.3) autoreverse duration-150" />
960
472
  ```
961
473
 
962
- ### rotate
963
-
964
- Utility to specify the amount of rotation.
965
-
966
- This is specified as the rotation angle in degrees.
967
-
968
- **Default:** `No rotation.`
969
-
970
- ```css
971
- /* Property: rotate */
972
- /* Component(s): MatrixCreationDict, Matrix2DCreationDict */
973
- '.rotate-0': { rotate: 0 }
974
- '.rotate-1': { rotate: 1 }
975
- '.rotate-2': { rotate: 2 }
976
- '.rotate-3': { rotate: 3 }
977
- '.rotate-6': { rotate: 6 }
978
- '.rotate-12': { rotate: 12 }
979
- '.rotate-45': { rotate: 45 }
980
- '.rotate-90': { rotate: 90 }
981
- '.rotate-180': { rotate: 180 }
982
-
983
- /* Property(ies): rotate ( Negative values ) */
984
- /* Component(s): For the Animation Component */
985
- '.-rotate-0': { rotate: 0 }
986
- '.-rotate-1': { rotate: -1 }
987
- '.-rotate-2': { rotate: -2 }
988
- '.-rotate-3': { rotate: -3 }
989
- '.-rotate-6': { rotate: -6 }
990
- '.-rotate-12': { rotate: -12 }
991
- '.-rotate-45': { rotate: -45 }
992
- '.-rotate-90': { rotate: -90 }
993
- '.-rotate-180': { rotate: -180 }
474
+ ```javascript
475
+ $.pulseAnim.pulse($.badge)
476
+ $.pulseAnim.pulse($.badge, 3)
994
477
  ```
995
478
 
996
- ### scale
997
-
998
- Scales the matrix by the specified scaling factor. The same scaling factor is used for both horizontal and vertical scaling.
999
-
1000
- **Default:** `1`
1001
-
1002
- ```css
1003
- /* Property: scale */
1004
- /* Component(s): MatrixCreationDict, Matrix2DCreationDict, Matrix3DCreationDict */
1005
- '.scale-0': { scale: 0 }
1006
- '.scale-1': { scale: 0.01 }
1007
- '.scale-5': { scale: 0.05 }
1008
- '.scale-10': { scale: 0.10 }
1009
- '.scale-25': { scale: 0.25 }
1010
- '.scale-50': { scale: 0.5 }
1011
- '.scale-75': { scale: 0.75 }
1012
- '.scale-90': { scale: 0.9 }
1013
- '.scale-95': { scale: 0.95 }
1014
- '.scale-100': { scale: 1 }
1015
- '.scale-105': { scale: 1.05 }
1016
- '.scale-110': { scale: 1.1 }
1017
- '.scale-125': { scale: 1.25 }
1018
- '.scale-150': { scale: 1.5 }
1019
- ```
479
+ ---
1020
480
 
1021
- ### drag-apply, drag-animate
481
+ ## The `shake` Method
1022
482
 
1023
- To control how `drag:` and `drop:` modifiers are applied, you can use either the `drag-animate` (*default*) or `drag-apply` class. The `drag-animate` class will animate the properties, while the `drag-apply` class will apply them immediately.
483
+ Horizontal shake for error/feedback.
1024
484
 
1025
- ```css
1026
- /* Property(ies): draggingType */
1027
- /* Component(s): For the Animation Component */
1028
- '.drag-apply': { draggingType: 'apply' }
1029
- '.drag-animate': { draggingType: 'animate' }
485
+ ```javascript
486
+ $.myAnimation.shake(view, intensity)
1030
487
  ```
1031
488
 
1032
- ### opacity-to-*, toggle-visible
1033
-
1034
- A special utility to automatically animate the opacity of a view and toggle its visibility.
489
+ | Parameter | Type | Default | Description |
490
+ | --- | --- | --- | --- |
491
+ | `view` | `View` | -- | The view to shake |
492
+ | `intensity` | `Number` | `10` | Horizontal displacement in pixels |
1035
493
 
1036
- ```css
1037
- /* Property(ies): toggle - For the Animation module */
1038
- /* Component(s): Animation */
1039
- '.opacity-to-0': { opacity: 1, animationProperties: { open: { opacity: 0 }, close: { opacity: 1 } } }
1040
- '.opacity-to-100': { opacity: 0, animationProperties: { open: { opacity: 1 }, close: { opacity: 0 } } }
1041
- '.toggle-visible': { animationProperties: { open: { visible: true }, close: { visible: false } } }
1042
- ```
494
+ - `duration`: inherited, divided by 6 for each shake cycle. Fallback: 400ms
495
+ - `delay`: inherited, applied before shake starts
496
+ - `curve`: always `EASE_IN_OUT` (fixed)
497
+ - `autoreverse` and `repeat`: always `true` and `3` (fixed)
1043
498
 
1044
- ### zoom-in-*, zoom-out-*
1045
-
1046
- A special utility to automatically animate the zoom-in and zoom-out of a view.
1047
-
1048
- It will initially set the view's scale to the specified value and then animate it to 1.
1049
-
1050
- ```css
1051
- /* Property(ies): animationProperties - scales the view (in or out) and resets it to 100% when the animation completes */
1052
- /* Component(s): Animation */
1053
- '.zoom-in-0': { animationProperties: { open: { scale: 0 }, complete: { scale: 1 } } }
1054
- '.zoom-in-1': { animationProperties: { open: { scale: 0.01 }, complete: { scale: 1 } } }
1055
- '.zoom-in-5': { animationProperties: { open: { scale: 0.05 }, complete: { scale: 1 } } }
1056
- '.zoom-in-10': { animationProperties: { open: { scale: 0.10 }, complete: { scale: 1 } } }
1057
- '.zoom-in-25': { animationProperties: { open: { scale: 0.25 }, complete: { scale: 1 } } }
1058
- '.zoom-in-50': { animationProperties: { open: { scale: 0.5 }, complete: { scale: 1 } } }
1059
- '.zoom-in-75': { animationProperties: { open: { scale: 0.75 }, complete: { scale: 1 } } }
1060
- '.zoom-in-90': { animationProperties: { open: { scale: 0.9 }, complete: { scale: 1 } } }
1061
- '.zoom-in-95': { animationProperties: { open: { scale: 0.95 }, complete: { scale: 1 } } }
1062
- '.zoom-in-100': { animationProperties: { open: { scale: 1 }, complete: { scale: 1 } } }
1063
- '.zoom-in-105': { animationProperties: { open: { scale: 1.05 }, complete: { scale: 1 } } }
1064
- '.zoom-in-110': { animationProperties: { open: { scale: 1.1 }, complete: { scale: 1 } } }
1065
- '.zoom-in-125': { animationProperties: { open: { scale: 1.25 }, complete: { scale: 1 } } }
1066
- '.zoom-in-150': { animationProperties: { open: { scale: 1.5 }, complete: { scale: 1 } } }
1067
- '.zoom-out-0': { animationProperties: { close: { scale: 0 }, complete: { scale: 1 } } }
1068
- '.zoom-out-1': { animationProperties: { close: { scale: 0.01 }, complete: { scale: 1 } } }
1069
- '.zoom-out-5': { animationProperties: { close: { scale: 0.05 }, complete: { scale: 1 } } }
1070
- '.zoom-out-10': { animationProperties: { close: { scale: 0.10 }, complete: { scale: 1 } } }
1071
- '.zoom-out-25': { animationProperties: { close: { scale: 0.25 }, complete: { scale: 1 } } }
1072
- '.zoom-out-50': { animationProperties: { close: { scale: 0.5 }, complete: { scale: 1 } } }
1073
- '.zoom-out-75': { animationProperties: { close: { scale: 0.75 }, complete: { scale: 1 } } }
1074
- '.zoom-out-90': { animationProperties: { close: { scale: 0.9 }, complete: { scale: 1 } } }
1075
- '.zoom-out-95': { animationProperties: { close: { scale: 0.95 }, complete: { scale: 1 } } }
1076
- '.zoom-out-100': { animationProperties: { close: { scale: 1 }, complete: { scale: 1 } } }
1077
- '.zoom-out-105': { animationProperties: { close: { scale: 1.05 }, complete: { scale: 1 } } }
1078
- '.zoom-out-110': { animationProperties: { close: { scale: 1.1 }, complete: { scale: 1 } } }
1079
- '.zoom-out-125': { animationProperties: { close: { scale: 1.25 }, complete: { scale: 1 } } }
1080
- '.zoom-out-150': { animationProperties: { close: { scale: 1.5 }, complete: { scale: 1 } } }
499
+ ```javascript
500
+ $.errorAnim.shake($.emailField, 5)
501
+ $.emailField.applyProperties({ borderColor: '#ef4444' })
1081
502
  ```
1082
503
 
1083
504
  ---
1084
505
 
1085
- ## Best Practices
1086
-
1087
- ### 1. Use Semantic IDs
506
+ ## The `snapTo` Method
1088
507
 
1089
- ```xml
1090
- <!-- Good -->
1091
- <Animation id="fadeIn" class="close:opacity-0 open:opacity-100" />
1092
- <Animation id="expandCard" class="close:h-20 open:h-40" />
508
+ Snaps a view to the nearest target by center-to-center Euclidean distance. Returns the matched target or `null`.
1093
509
 
1094
- <!-- Avoid -->
1095
- <Animation id="anim1" class="..." />
1096
- <Animation id="anim2" class="..." />
510
+ ```javascript
511
+ const matched = $.myAnimation.snapTo(view, targets)
1097
512
  ```
1098
513
 
1099
- ### 2. Combine Methods for Sequences
514
+ - Inherits `duration`, `delay`, `curve`. Fallback: **200ms**, **0ms**, **EASE_IN_OUT**
515
+ - Handles iOS transform reset; updates `_originLeft`/`_originTop`
516
+ - Automatic position normalization
517
+
518
+ ### Puzzle Game with Collision Detection
1100
519
 
1101
520
  ```javascript
1102
- function playSequence() {
1103
- $.fadeIn.play($.view1, () => {
1104
- $.expandCard.play($.view2)
1105
- })
1106
- }
521
+ $.puzzleAnim.draggable(pieces)
522
+ $.puzzleAnim.detectCollisions(pieces.concat(slots),
523
+ null,
524
+ (source, target) => {
525
+ if (source.valor === target.valor) {
526
+ $.puzzleAnim.undraggable(source)
527
+ source.applyProperties({ opacity: 0.6 })
528
+ }
529
+ }
530
+ )
1107
531
  ```
1108
532
 
1109
- ### 3. Use `complete:` for Post-Animation State
533
+ `snap-center` auto-centers on the slot; `snap-back` returns to origin if dropped outside; `undraggable` locks when correct.
1110
534
 
1111
- ```xml
1112
- <Animation class="complete:scale-100 duration-200 open:scale-110" />
1113
- ```
535
+ ---
1114
536
 
1115
- ### 4. Leverage `children:` for Batch Animations
537
+ ## The `reorder` Method
1116
538
 
1117
- ```xml
1118
- <Animation class="children:opacity-0 complete:opacity-100 duration-300" />
539
+ Animates views to new positions by index mapping. All views animate simultaneously.
1119
540
 
1120
- <View>
1121
- <Label /> <!-- All fade in together -->
1122
- <View /> <!-- All fade in together -->
1123
- </View>
541
+ ```javascript
542
+ $.myAnimation.reorder(views, newOrder)
1124
543
  ```
1125
544
 
1126
- ### 5. Use `toggle` for UI States
545
+ - `newOrder` maps current index to new position: `[2, 1, 0]` reverses, `[1, 2, 0]` rotates
546
+ - Length must match `views` length
547
+ - Inherits `duration`, `delay`, `curve`. Fallback: **200ms**, **0ms**, **EASE_IN_OUT**
548
+ - Automatic position normalization
1127
549
 
1128
550
  ```javascript
1129
- function toggleMenu() {
1130
- $.menuAnimation.toggle($.menuView)
1131
- }
551
+ const tasks = [$.taskHigh, $.taskMedium, $.taskLow]
552
+ $.taskAnim.reorder(tasks, [2, 1, 0]) // reverse order
553
+ $.taskAnim.reorder(tasks, [1, 2, 0]) // rotate
1132
554
  ```
1133
555
 
1134
556
  ---
1135
557
 
1136
- ## Common Patterns
1137
-
1138
- ### Modal Fade In/Out
558
+ ## The `transition` Method
1139
559
 
1140
- ```xml
1141
- <Animation id="modalFade" class="close:opacity-0 open:opacity-100" />
1142
-
1143
- <View id="modalView" class="opacity-0">
1144
- <!-- Modal content -->
1145
- </View>
1146
- ```
560
+ Animates multiple views simultaneously to layout positions defined by `Matrix2D.translate().rotate().scale()`.
1147
561
 
1148
562
  ```javascript
1149
- // Open
1150
- $.modalFade.open($.modalView)
1151
-
1152
- // Close
1153
- $.modalFade.close($.modalView)
563
+ $.myAnimation.transition(views, layouts)
1154
564
  ```
1155
565
 
1156
- ### Slide Up/Down
566
+ ### Layout Object Properties
1157
567
 
1158
- ```xml
1159
- <Animation id="slideUp" class="close:translate-y-full open:translate-y-0" />
1160
- ```
568
+ | Property | Type | Default | Description |
569
+ | --- | --- | --- | --- |
570
+ | `translation` | `Object` | `{x:0, y:0}` | Translation offset in pixels |
571
+ | `rotate` | `Number` | `0` | Rotation in degrees |
572
+ | `scale` | `Number` | `1` | Scale factor |
573
+ | `zIndex` | `Number` | -- | Applied synchronously before animation |
574
+ | `width` | `Number` | -- | Optional width change |
575
+ | `height` | `Number` | -- | Optional height change |
576
+ | `opacity` | `Number` | -- | Optional opacity change |
1161
577
 
1162
- ### Scale on Touch
578
+ ### Behavior
1163
579
 
1164
- ```xml
1165
- <Animation id="cardPop" class="duration-200 open:scale-105" />
580
+ - Inherits `duration`, `delay`, `curve` from Animation object
581
+ - Each view gets a single `Ti.UI.createAnimation()` with combined `Matrix2D` transform
582
+ - All animations launch simultaneously
583
+ - `zIndex` applied synchronously before animation starts
584
+ - **Mismatched lengths**: extra views fade out; extra layouts ignored; faded views fade back in when given a layout entry
1166
585
 
1167
- <View class="w-screen bg-white shadow" onTouchstart="onCardTouch">
1168
- <!-- Card content -->
1169
- </View>
1170
- ```
586
+ ### Reusable Presets
1171
587
 
1172
588
  ```javascript
1173
- function onCardTouch(e) {
1174
- $.cardPop.play(e.source)
1175
- }
589
+ const fanOut = [
590
+ { translation: { x: -120, y: 20 }, rotate: -15, scale: 0.8, zIndex: 1 },
591
+ { translation: { x: 0, y: 0 }, rotate: 0, scale: 1, zIndex: 3 },
592
+ { translation: { x: 120, y: 20 }, rotate: 15, scale: 0.8, zIndex: 2 }
593
+ ]
594
+
595
+ const stack = [
596
+ { translation: { x: -8, y: 16 }, rotate: 0, scale: 0.9, zIndex: 1 },
597
+ { translation: { x: 0, y: 8 }, rotate: 0, scale: 0.95, zIndex: 2 },
598
+ { translation: { x: 8, y: 0 }, rotate: 0, scale: 1, zIndex: 3 }
599
+ ]
600
+
601
+ // Same preset, different view groups
602
+ $.anim.transition(screensA, fanOut)
603
+ $.anim.transition(screensB, fanOut)
1176
604
  ```
1177
605
 
1178
- ### Draggable Element with Bounds
606
+ ### Photo Gallery Example
1179
607
 
1180
608
  ```xml
1181
- <Animation id="draggableCard" class="bounds:m-8" />
1182
-
1183
- <View id="card" class="h-32 w-64 bg-white shadow" />
609
+ <Animation id="galleryAnim" module="purgetss.ui" class="keep-z-index duration-150" />
1184
610
  ```
1185
611
 
1186
612
  ```javascript
1187
- $.draggableCard.draggable($.card)
613
+ const photos = [$.photo1, $.photo2, $.photo3]
614
+ function doFan() { $.galleryAnim.transition(photos, fan) }
615
+ function doStack() { $.galleryAnim.transition(photos, stack) }
616
+ $.galleryAnim.draggable(photos) // photos keep rotation/scale while dragging
1188
617
  ```
1189
618
 
1190
- ---
1191
-
1192
- ## Animation Properties Summary
619
+ `keep-z-index` preserves the layout order during drag.
1193
620
 
1194
- ### State Modifiers
621
+ ### Mac Catalyst Note
1195
622
 
1196
- | Modifier | Purpose | Example |
1197
- | ----------- | ------------------------ | ------------------------------ |
1198
- | `open:` | Opening state properties | `open:opacity-100 open:w-full` |
1199
- | `close:` | Closing state properties | `close:opacity-0 close:h-0` |
1200
- | `complete:` | Post-open state | `complete:bg-green-500` |
1201
- | `children:` | All children affected | `children:opacity-50` |
1202
- | `child:{n}` | Specific child by index | `child:0:bg-red-500` |
1203
- | `drag:` | Dragging state | `drag:opacity-50` |
1204
- | `drop:` | Dropped state | `drop:scale-95` |
1205
- | `bounds:` | Movement limits | `bounds:m-4` |
623
+ On Mac Catalyst, parent containers of transitioned views should use **fixed dimensions** (not `Ti.UI.FILL`). Resizable containers trigger a UIKit re-layout that distorts rotated `Matrix2D` transforms. This does not affect iOS or Android.
1206
624
 
1207
- ### Timing and Special Classes
625
+ ---
1208
626
 
1209
- | Utility | Purpose | Example |
1210
- | --------------------------------------------------- | ----------------------------- | ---------------------------------- |
1211
- | `delay-{ms}` | Delay before animation starts | `delay-300` |
1212
- | `duration-{ms}` | Duration of animation | `duration-500` |
1213
- | `ease-in`, `ease-out`, `ease-linear`, `ease-in-out` | Animation curve | `ease-out` |
1214
- | `rotate-{degrees}` | Rotation | `rotate-45`, `-rotate-90` |
1215
- | `scale-{0-150}` | Scale | `scale-110` |
1216
- | `repeat-{n}` | Repetitions | `repeat-3` |
1217
- | `autoreverse` | Auto-reverse on completion | `autoreverse` |
1218
- | `zoom-in-{0-150}` | Zoom in effect | `zoom-in-125` |
1219
- | `zoom-out-{0-150}` | Zoom out effect | `zoom-out-75` |
1220
- | `drag-apply` | Instant drag properties | `drag-apply` |
1221
- | `drag-animate` | Animated drag properties | `drag-animate` |
1222
- | `horizontal-constraint` | Horizontal movement only | `horizontal-constraint` |
1223
- | `vertical-constraint` | Vertical movement only | `vertical-constraint` |
1224
- | `opacity-to-0` | Fade out | `opacity-to-0` |
1225
- | `opacity-to-100` | Fade in | `opacity-to-100` |
1226
- | `toggle-visible` | Visibility toggle | `toggle-visible` |
1227
- | `origin-*` | Anchor point | `origin-center`, `origin-top-left` |
627
+ For property inheritance, timing/utility classes, utility functions, implementation rules, and complex UI examples, see [animation-advanced.md](./animation-advanced.md).