@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
|
# Icon Font Libraries
|
|
2
2
|
|
|
3
|
-
PurgeTSS ships with four official icon font families
|
|
3
|
+
PurgeTSS ships with four official icon font families. Alloy projects can use their preconfigured TSS classes; Classic projects can install the same fonts and use `fontFamily` plus Unicode directly or through the optional CommonJS modules.
|
|
4
4
|
|
|
5
5
|
For user-defined fonts (Google Fonts, brand typefaces, community icon libraries like map-icons or microns), see [Custom Fonts](./custom-fonts.md) — those use `build-fonts`, not `icon-library`.
|
|
6
6
|
|
|
@@ -43,7 +43,7 @@ The complete class definitions live in the PurgeTSS `dist/` folder:
|
|
|
43
43
|
|
|
44
44
|
## Installing the icon fonts
|
|
45
45
|
|
|
46
|
-
Run `icon-library` to copy the
|
|
46
|
+
Run `icon-library` to copy the font files to `app/assets/fonts/` (Alloy) or `Resources/fonts/` (Classic). Alloy can then use the icon classes from the table; Classic does not run class resolution.
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
49
|
# All four families
|
|
@@ -56,14 +56,14 @@ $ purgetss il -v=fa,mi,ms,f7
|
|
|
56
56
|
> ℹ️ **INFO — You do not need the `.tss` files in `./purgetss/styles/`**
|
|
57
57
|
> PurgeTSS already knows every official icon class and resolves them at compile time from its own bundled `dist/` files. You do not need `fontawesome.tss`, `materialsymbols.tss`, `materialicons.tss`, or `framework7icons.tss` inside `./purgetss/styles/` for `class="fas fa-home"` (or any other icon class) to work in your XML and controllers. Install the `.ttf` files with `icon-library` and the classes are ready.
|
|
58
58
|
>
|
|
59
|
-
> The resolved classes are written to
|
|
59
|
+
> The resolved Alloy classes are written to generated `app/styles/app.tss`, not `purgetss/styles/utilities.tss`. Classic receives only native fonts and any requested JavaScript module.
|
|
60
60
|
|
|
61
61
|
### Optional flags
|
|
62
62
|
|
|
63
63
|
Two optional flags adjust what `icon-library` copies into your project:
|
|
64
64
|
|
|
65
|
-
- `-s, --styles`:
|
|
66
|
-
- `-m, --module`: copies the matching CommonJS module into
|
|
65
|
+
- `-s, --styles`: Alloy only. Copies the official `.tss` sources into `purgetss/styles/` for reference. Classic skips this output.
|
|
66
|
+
- `-m, --module`: copies the matching CommonJS module into `app/lib/` (Alloy) or `Resources/lib/` (Classic), exposing Unicode strings and stable font-family aliases.
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
69
|
# Add either flag when you want them
|
|
@@ -81,7 +81,34 @@ $ purgetss il -m -s
|
|
|
81
81
|
- `ms`, `materialsymbol` = Material Symbols
|
|
82
82
|
- `f7`, `framework7` = Framework7 Icons
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
### CommonJS modules in Classic
|
|
85
|
+
|
|
86
|
+
Each module exposes its existing icon lookup API plus a `families` object with `families.default`. Direct aliases are also available:
|
|
87
|
+
|
|
88
|
+
| Module | Direct aliases |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `fontawesome` | `solid`, `regular`, `brands` |
|
|
91
|
+
| `materialicons` | `regular`, `outlined`, `round`, `sharp`, `twoTone` |
|
|
92
|
+
| `materialsymbols` | `outlined`, `rounded`, `sharp` |
|
|
93
|
+
| `framework7icons` | `fontFamily` |
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
const fontAwesome = require('lib/fontawesome')
|
|
97
|
+
|
|
98
|
+
const home = Ti.UI.createLabel({
|
|
99
|
+
text: fontAwesome.icons.home,
|
|
100
|
+
font: {
|
|
101
|
+
fontFamily: fontAwesome.solid,
|
|
102
|
+
fontSize: 24
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
All generated modules live under `Resources/lib/`, so use the pattern shown above: include `lib/` in the path and omit both `Resources/` and `.js`. See the centralized [Classic module path table](./classic-projects.md#loading-generated-modules-in-classic) for all four filenames.
|
|
108
|
+
|
|
109
|
+
The direct alias and `families` values agree, for example `fontAwesome.solid === fontAwesome.families.solid`; `families.default` provides the library's default variant.
|
|
110
|
+
|
|
111
|
+
## Using icons in Alloy XML
|
|
85
112
|
|
|
86
113
|
The variant class sets the `fontFamily`. The icon class sets the glyph (`text` / `title`). Apply both together:
|
|
87
114
|
|
|
@@ -12,6 +12,12 @@ Install PurgeTSS globally on your machine using [NPM](https://www.npmjs.com/).
|
|
|
12
12
|
> Node.js 20+ required.
|
|
13
13
|
> PurgeTSS requires Node 20.0.0 or higher.
|
|
14
14
|
|
|
15
|
+
## Alloy vs. Classic Setup
|
|
16
|
+
|
|
17
|
+
The root `purgetss` command, `init`, `create`, `install-dependencies`, `build`, and `watch` belong to the Alloy utility-class lifecycle described below. Do not run them to “set up PurgeTSS” in a Classic project.
|
|
18
|
+
|
|
19
|
+
Classic projects can run compatible standalone commands directly: `brand`, `images`, `semantic`, `shades`, `color-module`, `module`, `icon-library`, and `build-fonts`. Their native outputs go under `Resources/`, and the application does not need an `alloy.jmk` hook or PurgeTSS at compile/runtime. See [Classic Project Support](./classic-projects.md).
|
|
20
|
+
|
|
15
21
|
## XML Validation
|
|
16
22
|
|
|
17
23
|
Before purging, PurgeTSS pre-checks every XML file in your project. One case worth calling out: double dashes (`--`) are not allowed inside XML comments. That restriction comes from the XML spec itself, not from PurgeTSS, but many people only run into it once a tool actually parses the file.
|
|
@@ -44,7 +50,7 @@ Pick whichever of these reads best:
|
|
|
44
50
|
|
|
45
51
|
Any of those approaches keeps the comment readable and produces a document that every XML parser will accept.
|
|
46
52
|
|
|
47
|
-
## Run PurgeTSS the First Time
|
|
53
|
+
## Run PurgeTSS the First Time (Alloy Only)
|
|
48
54
|
|
|
49
55
|
> **INFO**
|
|
50
56
|
> Run `purgetss` once in your project to generate the required files and folders.
|
|
@@ -55,7 +61,11 @@ When you run `purgetss` for the first time in your project, it does the followin
|
|
|
55
61
|
|
|
56
62
|
### 1. Auto-run Hook
|
|
57
63
|
|
|
58
|
-
PurgeTSS adds a task in `alloy.jmk` to run `purgetss` every time you compile your app.
|
|
64
|
+
PurgeTSS adds a task in `alloy.jmk` to run `purgetss` every time you compile your app. This works well with `liveview`.
|
|
65
|
+
|
|
66
|
+
With the default synchronous method, the hook inherits PurgeTSS output so XML validation and other diagnostics appear before Alloy's generic compiler failure. It then prints a final hint to run `purgetss` from the project root and rethrows the error.
|
|
67
|
+
|
|
68
|
+
Current `init` runs update an older active or disabled hook without changing its enabled state. Invoking `watch` normally enables a disabled hook.
|
|
59
69
|
|
|
60
70
|
### 2. `purgetss` Folder
|
|
61
71
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Multi-Density Images
|
|
2
2
|
|
|
3
|
-
The `purgetss images` command
|
|
3
|
+
The `purgetss images` command generates every Titanium density variant of your UI images from one high-resolution source. Alloy and Classic layouts are auto-detected. Since v7.15.0, a normal run follows the enabled platforms in `tiapp.xml`; `--android` and `--ios` are explicit overrides.
|
|
4
4
|
|
|
5
5
|
- **Android**: `res-mdpi`, `res-hdpi`, `res-xhdpi`, `res-xxhdpi`, `res-xxxhdpi` (5 densities)
|
|
6
6
|
- **iPhone**: `@1x`, `@2x`, `@3x` (3 scales via filename suffix)
|
|
@@ -10,7 +10,7 @@ For the terse flag reference, see the [`images` command reference](./cli-command
|
|
|
10
10
|
> **INFO**
|
|
11
11
|
>
|
|
12
12
|
> The `images` command at a glance
|
|
13
|
-
> One source per image in `purgetss/images/`, run `purgetss images`, and every density lands
|
|
13
|
+
> One source per image in `purgetss/images/`, run `purgetss images`, and every density lands under `app/assets/` (Alloy) or `Resources/` (Classic).
|
|
14
14
|
|
|
15
15
|
<!-- TOC-START -->
|
|
16
16
|
## Contents
|
|
@@ -80,11 +80,11 @@ app/assets/
|
|
|
80
80
|
└── primary@3x.svg
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Classic projects output to `
|
|
83
|
+
Classic projects output to `Resources/android/images/res-*/` and `Resources/iphone/images/` — the command auto-detects the layout.
|
|
84
84
|
|
|
85
85
|
## The `purgetss/images/` convention
|
|
86
86
|
|
|
87
|
-
`init` creates `purgetss/images/`
|
|
87
|
+
Alloy `init` creates `purgetss/images/` alongside `fonts/` and `brand/`. In standalone Classic, running `purgetss images` without a positional source establishes the convention folder. Passing an existing external source does not create an empty `purgetss/images/` folder or config file.
|
|
88
88
|
|
|
89
89
|
```text
|
|
90
90
|
purgetss/images/
|
|
@@ -99,7 +99,7 @@ purgetss/images/
|
|
|
99
99
|
|
|
100
100
|
Supported input formats: `.svg`, `.png`, `.jpg`, `.jpeg`, `.webp`, `.gif`.
|
|
101
101
|
|
|
102
|
-
**Subdirectories are preserved in the output.** A file at `purgetss/images/buttons/primary.png` ends up
|
|
102
|
+
**Subdirectories are preserved in the output.** A file at `purgetss/images/buttons/primary.png` ends up under the matching `app/assets/` or `Resources/` platform roots. Organize however makes sense for your project.
|
|
103
103
|
|
|
104
104
|
> **INFO**
|
|
105
105
|
>
|
|
@@ -264,7 +264,7 @@ Raster entries you add by hand survive subsequent runs untouched. For SVGs detec
|
|
|
264
264
|
|
|
265
265
|
```text
|
|
266
266
|
<project>/
|
|
267
|
-
└──
|
|
267
|
+
└── Resources/
|
|
268
268
|
├── android/images/res-*/
|
|
269
269
|
└── iphone/images/
|
|
270
270
|
```
|
|
@@ -329,11 +329,11 @@ purgetss images ./docs/screenshots/home-hero.png
|
|
|
329
329
|
purgetss images /Users/cesar/Design/banner.svg
|
|
330
330
|
```
|
|
331
331
|
|
|
332
|
-
When the source is outside `purgetss/images/`, subdirectory preservation uses the directory of the source file as the root instead.
|
|
332
|
+
When the source is outside `purgetss/images/`, subdirectory preservation uses the directory of the source file as the root instead. Processing that external source in Classic does not bootstrap unrelated PurgeTSS folders or config.
|
|
333
333
|
|
|
334
334
|
## Platform filter
|
|
335
335
|
|
|
336
|
-
By default,
|
|
336
|
+
By default, the command follows `<deployment-targets>` in `tiapp.xml`. Pass a platform flag to override that selection for a targeted run:
|
|
337
337
|
|
|
338
338
|
```bash
|
|
339
339
|
purgetss images --android # Android only (skip iPhone)
|
|
@@ -345,7 +345,7 @@ Useful when:
|
|
|
345
345
|
- You're iterating on an iOS-only screen and don't need to regenerate Android assets every time.
|
|
346
346
|
- You want to tune JPEG quality differently for the two platforms (run the command twice with different flags).
|
|
347
347
|
|
|
348
|
-
The two flags are mutually exclusive.
|
|
348
|
+
The two flags are mutually exclusive. Passing neither means “use the project's enabled targets,” not “always generate both.”
|
|
349
349
|
|
|
350
350
|
## Format conversion
|
|
351
351
|
|
|
@@ -462,7 +462,7 @@ If you only tweaked CSS classes (no image changes), you don't need to re-run `pu
|
|
|
462
462
|
|
|
463
463
|
## Cleaning up
|
|
464
464
|
|
|
465
|
-
`purgetss images` never deletes files. It only creates them. If you remove
|
|
465
|
+
`purgetss images` never deletes files. It only creates them. If you remove a source, generated copies under `app/assets/` (Alloy) or `Resources/` (Classic) stay in place. Remove them manually or with git when you clean up.
|
|
466
466
|
|
|
467
467
|
## Full flag reference
|
|
468
468
|
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# `purgetss.ui` in Titanium Classic
|
|
2
|
+
|
|
3
|
+
Titanium Classic uses the same generated `purgetss.ui` runtime as Alloy, but it does not compile Alloy XML, TSS, utility classes, controllers, or `$.*` references. Configure the runtime with JavaScript objects containing native Titanium properties.
|
|
4
|
+
|
|
5
|
+
<!-- TOC-START -->
|
|
6
|
+
## Contents
|
|
7
|
+
|
|
8
|
+
- [Install and load](#install-and-load)
|
|
9
|
+
- [Public exports](#public-exports)
|
|
10
|
+
- [Quick start](#quick-start)
|
|
11
|
+
- [Animation method contract](#animation-method-contract)
|
|
12
|
+
- [Native animation configuration](#native-animation-configuration)
|
|
13
|
+
- [States and direct children](#states-and-direct-children)
|
|
14
|
+
- [Position helpers](#position-helpers)
|
|
15
|
+
- [Drag and collision configuration](#drag-and-collision-configuration)
|
|
16
|
+
- [Drag lifecycle and cleanup](#drag-lifecycle-and-cleanup)
|
|
17
|
+
- [Layout transitions](#layout-transitions)
|
|
18
|
+
- [Appearance in Classic](#appearance-in-classic)
|
|
19
|
+
- [Runtime utilities](#runtime-utilities)
|
|
20
|
+
- [Related references](#related-references)
|
|
21
|
+
|
|
22
|
+
<!-- TOC-END -->
|
|
23
|
+
|
|
24
|
+
## Install and load
|
|
25
|
+
|
|
26
|
+
Run this from the Classic project root:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
purgetss module
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The command creates `Resources/lib/purgetss.ui.js`. Load it from a file such as `Resources/app.js`:
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
const {
|
|
36
|
+
createAnimation,
|
|
37
|
+
Appearance,
|
|
38
|
+
deviceInfo,
|
|
39
|
+
saveComponent
|
|
40
|
+
} = require('lib/purgetss.ui')
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Use `createAnimation(args)` for ordinary Classic code. It returns a zero-size, touch-disabled `Ti.UI.View` decorated with animation methods. Treat this view as a behavior object; do not add it to the window.
|
|
44
|
+
|
|
45
|
+
## Public exports
|
|
46
|
+
|
|
47
|
+
| Export | Type and return | Contract |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `AnimationProperties` | Constructor returning the decorated animation view | Public, but less clear than the factory in Classic |
|
|
50
|
+
| `createAnimation(args)` | Factory returning the decorated animation view | Preferred Classic entry point |
|
|
51
|
+
| `Appearance` | Singleton object | `init()`, `set()`, `get()`, `toggle()` |
|
|
52
|
+
| `deviceInfo()` | Function returning `undefined` | Logs platform and display information |
|
|
53
|
+
| `saveComponent({ source, directory? })` | Function returning `undefined` | Writes a PNG and invokes the photo-gallery API |
|
|
54
|
+
|
|
55
|
+
## Quick start
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const { createAnimation, Appearance } = require('lib/purgetss.ui')
|
|
59
|
+
|
|
60
|
+
Appearance.init()
|
|
61
|
+
|
|
62
|
+
const window = Ti.UI.createWindow({ backgroundColor: 'surfaceColor' })
|
|
63
|
+
const card = Ti.UI.createView({
|
|
64
|
+
width: 220,
|
|
65
|
+
height: 120,
|
|
66
|
+
backgroundColor: 'accentColor',
|
|
67
|
+
opacity: 0,
|
|
68
|
+
transform: Ti.UI.createMatrix2D().scale(0.92)
|
|
69
|
+
})
|
|
70
|
+
const motion = createAnimation({
|
|
71
|
+
duration: 220,
|
|
72
|
+
curve: Ti.UI.ANIMATION_CURVE_EASE_OUT,
|
|
73
|
+
animationProperties: {
|
|
74
|
+
open: { opacity: 1, scale: 1 },
|
|
75
|
+
close: { opacity: 0, scale: 0.92 }
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
function onCardClick() { motion.play(card) }
|
|
80
|
+
function onWindowOpen() { motion.open(card) }
|
|
81
|
+
function disposeWindow() {
|
|
82
|
+
card.removeEventListener('click', onCardClick)
|
|
83
|
+
window.removeEventListener('open', onWindowOpen)
|
|
84
|
+
window.removeEventListener('close', disposeWindow)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
card.addEventListener('click', onCardClick)
|
|
88
|
+
window.add(card)
|
|
89
|
+
window.addEventListener('open', onWindowOpen)
|
|
90
|
+
window.addEventListener('close', disposeWindow)
|
|
91
|
+
window.open()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`surfaceColor` and `accentColor` are names from `Resources/semantic.colors.json`; see [appearance-module.md#titanium-classic](./appearance-module.md#titanium-classic).
|
|
95
|
+
|
|
96
|
+
## Animation method contract
|
|
97
|
+
|
|
98
|
+
| Method | Signature | Return and callback |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `play` | `play(viewOrViews, callback?)` | `undefined`; callback once per view after its base animation completes |
|
|
101
|
+
| `toggle` | `toggle(viewOrViews, callback?)` | Exact alias of `play` |
|
|
102
|
+
| `apply` | `apply(viewOrViews, callback?)` | `undefined`; synchronous callback once per view |
|
|
103
|
+
| `open` | `open(viewOrViews, callback?)` | `undefined`; forces open state, callback once per view |
|
|
104
|
+
| `close` | `close(viewOrViews, callback?)` | `undefined`; forces close state, callback once per view |
|
|
105
|
+
| `draggable` | `draggable(viewOrViews)` | `undefined` |
|
|
106
|
+
| `undraggable` | `undraggable(viewOrViews)` | `undefined` |
|
|
107
|
+
| `detectCollisions` | `detectCollisions(views, dragCallback?, dropCallback?)` | `undefined` |
|
|
108
|
+
| `sequence` | `sequence(viewOrViews, callback?)` | `undefined`; callback once after the final view |
|
|
109
|
+
| `swap` | `swap(view1, view2)` | `undefined` |
|
|
110
|
+
| `pulse` | `pulse(view, count = 1)` | `undefined` |
|
|
111
|
+
| `shake` | `shake(view, intensity = 10)` | `undefined` |
|
|
112
|
+
| `snapTo` | `snapTo(view, targets)` | Selected target, `null` if none qualifies, or `undefined` for a missing source |
|
|
113
|
+
| `reorder` | `reorder(views, newOrder)` | `undefined` |
|
|
114
|
+
| `transition` | `transition(viewOrViews, layouts)` | `undefined` |
|
|
115
|
+
|
|
116
|
+
`play`, `toggle`, `apply`, `open`, and `close` accept one view or an array. The array callback runs once per view with:
|
|
117
|
+
|
|
118
|
+
- `type`: native completion type, or `'applied'` for `apply`.
|
|
119
|
+
- `bubbles` and `cancelBubble`: selected native primitives.
|
|
120
|
+
- `action`: `'play'` or `'apply'`.
|
|
121
|
+
- `state`: `'open'` or `'close'`.
|
|
122
|
+
- `id` and `targetId`.
|
|
123
|
+
- `index` and `total`.
|
|
124
|
+
- `getTarget()`: returns the affected view.
|
|
125
|
+
|
|
126
|
+
This is a newly constructed object, not the original Titanium event. For array playback, the configured base delay accumulates for successive views. `sequence()` instead waits for each native completion and invokes its callback once after the last view. Passing an empty array to `sequence()` produces no callback.
|
|
127
|
+
|
|
128
|
+
`animationProperties.complete` starts after the active `play`, `toggle`, `open`, or `close` base phase, and is applied immediately after `apply`. The public play callback does not wait for the second top-level `complete` animation.
|
|
129
|
+
|
|
130
|
+
## Native animation configuration
|
|
131
|
+
|
|
132
|
+
Pass native `Ti.UI.Animation` values directly:
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const { createAnimation } = require('lib/purgetss.ui')
|
|
136
|
+
|
|
137
|
+
const motion = createAnimation({
|
|
138
|
+
id: 'cardMotion',
|
|
139
|
+
duration: 240,
|
|
140
|
+
delay: 40,
|
|
141
|
+
curve: Ti.UI.ANIMATION_CURVE_EASE_IN_OUT,
|
|
142
|
+
repeat: 1,
|
|
143
|
+
autoreverse: false,
|
|
144
|
+
opacity: 0.8,
|
|
145
|
+
backgroundColor: '#2563eb',
|
|
146
|
+
scale: 1.05,
|
|
147
|
+
rotate: 4
|
|
148
|
+
})
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The constructor removes `id` from the native animation object. It converts top-level `scale`, `rotate`, and `anchorPoint` into one `Ti.UI.Matrix2D`; it performs the same conversion separately for `animationProperties.open` and `.close`. Helpers such as `pulse`, `shake`, `swap`, `snapTo`, `reorder`, and `transition` can replace or reset that transform.
|
|
152
|
+
|
|
153
|
+
Most helpers spread the base object before their method-specific assignments, so later helper fields win. There is no shared `200ms` timing fallback for position/layout helpers. Only `shake()` computes `(duration ?? 400) / 6`, rounded to the nearest millisecond; `pulse()` supplies a default scale of `1.2`. Both force `ANIMATION_CURVE_EASE_IN_OUT`.
|
|
154
|
+
|
|
155
|
+
Titanium exposes `anchorPoint` differently across platforms. Test pivot-dependent animation on both platforms; in Classic, set the view's iOS anchor point before animation and pass an Android animation anchor point only inside a platform guard.
|
|
156
|
+
|
|
157
|
+
## States and direct children
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
const panelMotion = createAnimation({
|
|
161
|
+
duration: 220,
|
|
162
|
+
animationProperties: {
|
|
163
|
+
open: { opacity: 1, scale: 1 },
|
|
164
|
+
close: { opacity: 0, scale: 0.94 },
|
|
165
|
+
complete: { borderColor: '#22c55e' },
|
|
166
|
+
children: { duration: 160 }
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
titleLabel.animationProperties = {
|
|
171
|
+
child: { delay: 40 },
|
|
172
|
+
open: { opacity: 1, top: 16 },
|
|
173
|
+
close: { opacity: 0, top: 24 },
|
|
174
|
+
complete: { color: '#22c55e' }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
panelMotion.open(panel)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
For a direct child, merge precedence is:
|
|
181
|
+
|
|
182
|
+
1. Parent `animationProperties.children`.
|
|
183
|
+
2. Child `animationProperties.child`.
|
|
184
|
+
3. Child's active `open`, `close`, or `complete` object.
|
|
185
|
+
|
|
186
|
+
Later values win. Nested descendants are not traversed automatically.
|
|
187
|
+
|
|
188
|
+
## Position helpers
|
|
189
|
+
|
|
190
|
+
- `swap()` exchanges two rendered positions, temporarily promotes both views, persists `top`/`left`, and updates private drag origins. It restores stacking from the current draggable registry order, not arbitrary original z-index values.
|
|
191
|
+
- `snapTo()` chooses the nearest target by center distance and returns it immediately. Views must be laid out because it reads `rect`.
|
|
192
|
+
- `reorder()` maps each view to the captured position at `newOrder[index]`. A length mismatch returns without changes.
|
|
193
|
+
- `pulse()` forces autoreverse, the supplied repeat count, and ease-in-out, then resets the transform.
|
|
194
|
+
- `shake()` starts at `-intensity`, animates to `+intensity` through six short phases, and resets the transform.
|
|
195
|
+
|
|
196
|
+
These methods do not expose completion callbacks. Configure duration, delay, and curve on the object passed to `createAnimation()`.
|
|
197
|
+
|
|
198
|
+
## Drag and collision configuration
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
const dragMotion = createAnimation({
|
|
202
|
+
duration: 160,
|
|
203
|
+
bounds: { top: 12, right: 12, bottom: 12, left: 12 },
|
|
204
|
+
draggingType: 'animate',
|
|
205
|
+
draggable: {
|
|
206
|
+
drag: { opacity: 0.7, scale: 1.04 },
|
|
207
|
+
drop: { opacity: 1, scale: 1 }
|
|
208
|
+
},
|
|
209
|
+
animationProperties: {
|
|
210
|
+
keepZIndex: true,
|
|
211
|
+
snap: { back: true, center: true }
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
piece.bounds = { bottom: 40 }
|
|
216
|
+
piece.constraint = 'horizontal'
|
|
217
|
+
piece.draggingType = 'apply'
|
|
218
|
+
piece.draggable = {
|
|
219
|
+
drag: { opacity: 0.5 },
|
|
220
|
+
drop: { opacity: 1 }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
dragMotion.draggable(piece)
|
|
224
|
+
dragMotion.detectCollisions([piece, target], (source, hovered) => {
|
|
225
|
+
target.borderColor = hovered === target ? '#22c55e' : 'transparent'
|
|
226
|
+
}, (source, droppedOn) => {
|
|
227
|
+
Ti.API.info(`${source.id} dropped on ${droppedOn.id}`)
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Runtime precedence and behavior:
|
|
232
|
+
|
|
233
|
+
- Global bounds are the base; `view.bounds` overrides individual edges.
|
|
234
|
+
- Axis restriction comes from `view.constraint`; a constructor-level constraint is not read.
|
|
235
|
+
- Per-view `draggingType` overrides the constructor value.
|
|
236
|
+
- Global and per-view `draggable.drag/drop` objects are merged; view fields win.
|
|
237
|
+
- Every resolved drag/drop property is forwarded, including size, transform, and anchor-point fields.
|
|
238
|
+
- `snap.center` calls `snapTo()` after a valid drop; `snap.back` returns a missed drop to its origin.
|
|
239
|
+
- There is no `snap.magnet` behavior.
|
|
240
|
+
- Collision detection tests the dragged view's center against registered targets. The last non-null hover target is a fallback at release.
|
|
241
|
+
|
|
242
|
+
Call drag/collision setup after the views are attached and laid out. `draggable(array)` assigns each view `zIndex` from its array index before registration. `keepZIndex` only prevents later touch-start promotion; register views individually if their existing z-index values must not be overwritten.
|
|
243
|
+
|
|
244
|
+
## Drag lifecycle and cleanup
|
|
245
|
+
|
|
246
|
+
Register each view once. The current runtime does not deduplicate repeated `draggable()` calls: they create additional listeners and registry entries. One `undraggable()` call removes only the latest stored listener set and the first matching registry entries.
|
|
247
|
+
|
|
248
|
+
`undraggable()` removes the stored `touchstart`, `touchmove`, `touchend`, and global `orientationchange` listeners and most private position/collision fields, but it leaves `_wasDragged`. `detectCollisions()` retains the last non-null callbacks on the animation object; passing `null` does not clear them.
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
let dragReady = false
|
|
252
|
+
|
|
253
|
+
function enableDrag() {
|
|
254
|
+
if (dragReady) return
|
|
255
|
+
dragReady = true
|
|
256
|
+
dragMotion.draggable(piece)
|
|
257
|
+
dragMotion.detectCollisions([piece, target])
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function disposeWindow() {
|
|
261
|
+
dragMotion.undraggable([piece, target])
|
|
262
|
+
window.removeEventListener('open', enableDrag)
|
|
263
|
+
window.removeEventListener('close', disposeWindow)
|
|
264
|
+
dragReady = false
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
window.addEventListener('open', enableDrag)
|
|
268
|
+
window.addEventListener('close', disposeWindow)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Release view, callback, and animation references after close. Application code should not depend on private underscore fields.
|
|
272
|
+
|
|
273
|
+
## Layout transitions
|
|
274
|
+
|
|
275
|
+
`transition(views, layouts)` accepts these layout fields:
|
|
276
|
+
|
|
277
|
+
| Field | Default | Behavior |
|
|
278
|
+
| --- | --- | --- |
|
|
279
|
+
| `translation` | `{ x: 0, y: 0 }` | Matrix translation |
|
|
280
|
+
| `rotate` | `0` | Matrix rotation in degrees |
|
|
281
|
+
| `scale` | `1` | Matrix scale |
|
|
282
|
+
| `zIndex` | unchanged | Assigned before animation |
|
|
283
|
+
| `width`, `height` | unchanged | Optional size animation |
|
|
284
|
+
| `opacity` | unchanged | Optional opacity animation |
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
const layoutMotion = createAnimation({
|
|
288
|
+
duration: 220,
|
|
289
|
+
curve: Ti.UI.ANIMATION_CURVE_EASE_IN_OUT
|
|
290
|
+
})
|
|
291
|
+
const fan = [
|
|
292
|
+
{ translation: { x: -120, y: 20 }, rotate: -15, scale: 0.8, zIndex: 1 },
|
|
293
|
+
{ translation: { x: 0, y: 0 }, rotate: 0, scale: 1, zIndex: 3 },
|
|
294
|
+
{ translation: { x: 120, y: 20 }, rotate: 15, scale: 0.8, zIndex: 2 }
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
layoutMotion.transition([cardA, cardB, cardC], fan)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
A view without a matching layout fades to opacity `0`, receives `zIndex: 0`, and has touch disabled. Extra layouts are ignored. A later matching layout fades a hidden view in and reenables touch. iOS preserves the last transform while hidden; Android resets transform, translation, rotation, and scale. Completion forces `touchEnabled: true` for every matched view, so reapply `false` afterward when a view must remain non-interactive.
|
|
301
|
+
|
|
302
|
+
On Mac Catalyst, use a fixed-size parent rather than `Ti.UI.FILL` for rotated layouts; a resizable parent can distort the matrix.
|
|
303
|
+
|
|
304
|
+
## Appearance in Classic
|
|
305
|
+
|
|
306
|
+
Put semantic colors in `Resources/semantic.colors.json`, use their names directly in native color properties, and call `Appearance.init()` before opening the first window. Classic does not need utility classes, TSS, `purgetss/config.cjs`, or Alloy runtime files. Run a full native build after adding or changing semantic keys; LiveView alone does not rebuild the native catalog.
|
|
307
|
+
|
|
308
|
+
See [appearance-module.md#titanium-classic](./appearance-module.md#titanium-classic) for setup and all four method contracts.
|
|
309
|
+
|
|
310
|
+
## Runtime utilities
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
const { deviceInfo, saveComponent } = require('lib/purgetss.ui')
|
|
314
|
+
|
|
315
|
+
deviceInfo()
|
|
316
|
+
|
|
317
|
+
function savePreview() {
|
|
318
|
+
if (!Ti.Media.hasPhotoGalleryPermissions()) {
|
|
319
|
+
Ti.Media.requestPhotoGalleryPermissions(event => {
|
|
320
|
+
if (event.success) savePreview()
|
|
321
|
+
})
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
saveComponent({
|
|
326
|
+
source: preview,
|
|
327
|
+
directory: Ti.Filesystem.applicationDataDirectory
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
`deviceInfo()` logs values and returns `undefined`. It logs `xdpi` and `ydpi` only on Android. Its tablet flag recognizes iPad only, so Android tablets are currently logged as `isTablet: false` and `isHandheld: true`.
|
|
333
|
+
|
|
334
|
+
`saveComponent()` calls `source.toImage()`, derives an MD5-based `.png` filename, writes it to `directory` (default: `Ti.Filesystem.tempDirectory`), then invokes `Ti.Media.saveToPhotoGallery()`. It returns `undefined` and provides no completion or error callback. Check/request gallery permission before calling it; on iOS, declare the required photo-library add usage description.
|
|
335
|
+
|
|
336
|
+
## Related references
|
|
337
|
+
|
|
338
|
+
- [animation-system.md](./animation-system.md) — Alloy syntax and all animation methods.
|
|
339
|
+
- [animation-advanced.md](./animation-advanced.md) — generated timing classes and runtime rules.
|
|
340
|
+
- [appearance-module.md](./appearance-module.md) — Appearance workflow and API.
|
|
341
|
+
- [classic-projects.md](./classic-projects.md) — commands and capabilities available to Classic projects.
|
|
@@ -8,7 +8,7 @@ For the mode-switching runtime that drives all of this (`Appearance.init()`, `Ap
|
|
|
8
8
|
|
|
9
9
|
> **INFO**
|
|
10
10
|
>
|
|
11
|
-
> Semantic color resolution is a **Titanium** feature, not PurgeTSS magic. Titanium natively reads `semantic.colors.json` (at `app/assets/` on Alloy, `Resources/` on Classic) and resolves any color-accepting property whose value matches a key in that file. PurgeTSS
|
|
11
|
+
> Semantic color resolution is a **Titanium** feature, not PurgeTSS magic. Titanium natively reads `semantic.colors.json` (at `app/assets/` on Alloy, `Resources/` on Classic) and resolves any color-accepting property whose value matches a key in that file. In Alloy, PurgeTSS also generates utility mappings that point at those keys; Classic uses the keys directly. The switching behavior is native in both layouts.
|
|
12
12
|
|
|
13
13
|
<!-- TOC-START -->
|
|
14
14
|
## Contents
|
|
@@ -17,7 +17,7 @@ For the mode-switching runtime that drives all of this (`Appearance.init()`, `Ap
|
|
|
17
17
|
- [Registering in `config.cjs`](#registering-in-configcjs)
|
|
18
18
|
- [Numeric 11-step tonal-inversion palette](#numeric-11-step-tonal-inversion-palette)
|
|
19
19
|
- [The `semantic` CLI command](#the-semantic-cli-command)
|
|
20
|
-
- [Using semantic classes in views](#using-semantic-classes-in-views)
|
|
20
|
+
- [Using semantic classes in Alloy views](#using-semantic-classes-in-alloy-views)
|
|
21
21
|
- [Using semantic colors in controllers](#using-semantic-colors-in-controllers)
|
|
22
22
|
- [Recommended starter palette](#recommended-starter-palette)
|
|
23
23
|
- [Related](#related)
|
|
@@ -235,13 +235,15 @@ One base hex plus a family name produces 11 JSON entries with mirror inversion,
|
|
|
235
235
|
purgetss semantic '#15803d' amazon
|
|
236
236
|
```
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
In Alloy, this:
|
|
239
239
|
|
|
240
240
|
1. Generates `amazon50` through `amazon950` using the same algorithm as the `shades` command.
|
|
241
|
-
2. Writes `semantic.colors.json`
|
|
241
|
+
2. Writes `semantic.colors.json` under `app/assets/` with mirror-by-index values — 50 ↔ 950, 100 ↔ 900, …, 500 as the identical anchor.
|
|
242
242
|
3. Writes the `{ 50: 'amazon50', 100: 'amazon100', ... }` mapping into `config.cjs`.
|
|
243
243
|
4. Strips any prior keys for the `amazon` family before writing — re-runs cleanly replace, never duplicate.
|
|
244
244
|
|
|
245
|
+
In Classic, the same command writes only the native `Resources/semantic.colors.json` entries. It does not create `purgetss/`, `config.cjs`, utility mappings, TSS, `app/`, or an Alloy hook. Use keys such as `amazon50` directly in Titanium color properties.
|
|
246
|
+
|
|
245
247
|
Useful flags:
|
|
246
248
|
|
|
247
249
|
- `--log` (`-l`) — preview the JSON on the console without writing anything.
|
|
@@ -270,7 +272,7 @@ purgetss semantic --single '#000000' overlayColor --alpha 50
|
|
|
270
272
|
|
|
271
273
|
The name is preserved verbatim as the JSON key (camelCase is respected). When `--dark` is omitted, it defaults to the light hex — useful for overlays where alpha is the only variation between modes.
|
|
272
274
|
|
|
273
|
-
|
|
275
|
+
In Alloy, single mode writes **both files** in one shot. The class name is auto-derived from the semantic key by stripping the conventional `Color` suffix and kebab-casing the rest, so `surfaceHighColor` becomes the `surface-high` class. In Classic, it writes only the native JSON entry and code uses the semantic key directly:
|
|
274
276
|
|
|
275
277
|
`./purgetss/config.cjs` (auto-generated)
|
|
276
278
|
```js
|
|
@@ -301,7 +303,7 @@ After the batch above you can use `bg-surface`, `bg-surface-high`, `text-text`,
|
|
|
301
303
|
|
|
302
304
|
Alpha follows the Titanium spec exactly: range `0.0-100.0`, stored as a **string**, wrapped per-mode as `{ color, alpha }`. Without `--alpha`, values stay as bare hex strings. Out-of-range values are rejected before any file is written.
|
|
303
305
|
|
|
304
|
-
## Using semantic classes in views
|
|
306
|
+
## Using semantic classes in Alloy views
|
|
305
307
|
|
|
306
308
|
Once the JSON and the `config.cjs` mapping are in place, you use the semantic classes like any other PurgeTSS utility:
|
|
307
309
|
|
|
@@ -315,6 +317,14 @@ Once the JSON and the `config.cjs` mapping are in place, you use the semantic cl
|
|
|
315
317
|
</Window>
|
|
316
318
|
```
|
|
317
319
|
|
|
320
|
+
Classic has no utility mapping. Use the native semantic key directly:
|
|
321
|
+
|
|
322
|
+
```javascript
|
|
323
|
+
const window = Ti.UI.createWindow({
|
|
324
|
+
backgroundColor: 'surfaceColor'
|
|
325
|
+
})
|
|
326
|
+
```
|
|
327
|
+
|
|
318
328
|
When the appearance changes — whether from `Appearance.set(...)` or a system-level toggle — Titanium resolves each semantic color name to its `light` or `dark` value automatically. No event listeners, no manual repaint.
|
|
319
329
|
|
|
320
330
|
### Opacity modifier auto-derivation
|
|
@@ -440,5 +450,5 @@ Start with these 6-7 colors and add more only when the design requires it. Fewer
|
|
|
440
450
|
## Community-Discovered Patterns
|
|
441
451
|
|
|
442
452
|
- **The `[object Object]` crash is always a missing `DEFAULT`.** Any time a view renders with a mysterious fallback color and the class was something like `bg-surface`, check `config.cjs` first: if `surface` is a nested object without a `DEFAULT` key, PurgeTSS serializes the whole object and emits `[object Object]` as the color value. The fix is either to add `DEFAULT: 'surfaceColor'` inside the nested object or flatten the structure.
|
|
443
|
-
- **Semantic resolution is Titanium-native, not PurgeTSS.** This matters when debugging: if a semantic name doesn't resolve, the problem is usually the `semantic.colors.json` file (wrong filename, wrong key, malformed JSON, or
|
|
453
|
+
- **Semantic resolution is Titanium-native, not PurgeTSS.** This matters when debugging: if a semantic name doesn't resolve, the problem is usually the `semantic.colors.json` file (wrong filename, wrong key, malformed JSON, or wrong location — Alloy expects `app/assets/`, Classic expects `Resources/`). PurgeTSS generates the file in both layouts and an additional utility mapping only in Alloy.
|
|
444
454
|
- **Re-running `purgetss semantic` on the same family is safe.** The CLI strips prior keys for that family from both the JSON and `config.cjs` before writing, so switching between palette and single forms — or changing the base hex — does not leave orphans. Other palettes and manually-defined entries are untouched.
|
|
@@ -8,6 +8,34 @@ When in doubt about whether a class, flag, or config key exists in the user's in
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
## v7.16.2
|
|
12
|
+
- `build-fonts --module` now exports every processed TTF/OTF PostScript name through `families`, including text-only collections; icon CSS additionally populates `icons`. Filename-derived keys such as `poppinsSemiBold` are supported. See [custom-fonts.md](custom-fonts.md).
|
|
13
|
+
- In clean Classic projects, saved `shades` palettes and `color-module` no longer scaffold empty brand, font, or image source folders. `shades` still refreshes an existing generated color module. See [classic-projects.md](classic-projects.md).
|
|
14
|
+
|
|
15
|
+
## v7.16.1
|
|
16
|
+
- Alloy auto-purge hooks now expose PurgeTSS output before Alloy's generic failure, print a command-line diagnostic hint, and migrate older active or disabled hooks without losing their state. See [installation-setup.md](installation-setup.md).
|
|
17
|
+
|
|
18
|
+
## v7.16.0
|
|
19
|
+
- `brand.artworkCornerRadius` and optional `brand.splashCornerRadius` add shared rounding for non-icon artwork; the iOS/Android splash, Feature Graphic, and LaunchLogo pieces also accept `cornerRadius`. Values are 0–50, and unsupported pieces reject the key before writing. Platform-masked and store icon outputs remain unrounded. See [app-branding.md](app-branding.md).
|
|
20
|
+
- Six CLI radius flags provide shared, splash-only, and per-piece one-run overrides. `--appicon-padding` completes the existing `brand.appicon.padding` contract, whose canonical default is `10%`.
|
|
21
|
+
- Branding summaries and `--dry-run` now report effective padding and corner radius for rounded pieces.
|
|
22
|
+
|
|
23
|
+
## v7.15.0
|
|
24
|
+
- Standalone `images`, `semantic`, `shades`, `color-module`, `module`, `icon-library`, and `build-fonts` now support Classic without installing the Alloy hook or utility-class lifecycle. Outputs route to native `Resources/` paths where appropriate. See [classic-projects.md](classic-projects.md).
|
|
25
|
+
- `images` follows `<deployment-targets>` from `tiapp.xml` by default; explicit `--android` / `--ios` override that selection.
|
|
26
|
+
- Classic `semantic` writes only `Resources/semantic.colors.json`; external Classic `images` runs no longer create unrelated empty `purgetss/` or config artifacts.
|
|
27
|
+
- Official icon-font CommonJS modules expose stable `families.default` plus variant aliases. Existing icon lookup APIs remain intact. See [icon-fonts.md](icon-fonts.md).
|
|
28
|
+
|
|
29
|
+
## v7.14.0
|
|
30
|
+
- `brand` became self-contained in standalone Classic projects: it creates the canonical config when missing and adopts a positional logo into `purgetss/brand/logo.{png,svg}` after confirmation when no canonical source exists.
|
|
31
|
+
- Normal `brand` runs follow `tiapp.xml` deployment targets; explicit `--only` remains an intentional override.
|
|
32
|
+
- Classic Android now receives the 11 `Resources/android/images/res-*` splash variants Titanium consumes, even when `ti create` did not seed the directories.
|
|
33
|
+
- Square iOS/store artwork defaults to full-bleed `0%` padding. Android adaptive (`18%`), legacy (`10%`), and splash (`26%`) defaults remain platform-specific.
|
|
34
|
+
- Fixes align `DefaultIcon.png` and `DefaultIcon-ios.png` with `brand.icon.padding` and make the documented legacy padding the actual per-side inset.
|
|
35
|
+
|
|
36
|
+
## v7.13.2
|
|
37
|
+
- `brand --help` padding defaults now come from the same piece table as the pipeline. The help output correctly reports adaptive `18%` and splash `26%`; do not preserve the older “stale help strings” warning.
|
|
38
|
+
|
|
11
39
|
## v7.13.1
|
|
12
40
|
- Four vulnerable transitive dependencies patched (`postcss`, `nanoid`, `brace-expansion`, `uuid`). Lockfile only; no API or class changes.
|
|
13
41
|
|