@maccesar/titools 5.0.0 → 5.1.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 (41) hide show
  1. package/README.md +26 -3
  2. package/package.json +1 -1
  3. package/skills/purgetss/SKILL.md +27 -24
  4. package/skills/purgetss/references/EXAMPLES.md +52 -41
  5. package/skills/purgetss/references/adopting-purgetss.md +137 -0
  6. package/skills/purgetss/references/animation-advanced.md +18 -5
  7. package/skills/purgetss/references/animation-system.md +21 -9
  8. package/skills/purgetss/references/app-branding.md +36 -97
  9. package/skills/purgetss/references/appearance-module.md +70 -5
  10. package/skills/purgetss/references/apply-directive.md +14 -6
  11. package/skills/purgetss/references/arbitrary-values.md +59 -23
  12. package/skills/purgetss/references/brand-padding-geometry.md +105 -0
  13. package/skills/purgetss/references/class-categories.md +684 -272
  14. package/skills/purgetss/references/class-index-properties.md +713 -607
  15. package/skills/purgetss/references/class-index.md +149 -84
  16. package/skills/purgetss/references/classic-projects.md +3 -3
  17. package/skills/purgetss/references/cli-commands.md +27 -213
  18. package/skills/purgetss/references/color-commands.md +218 -0
  19. package/skills/purgetss/references/configurable-properties.md +17 -2
  20. package/skills/purgetss/references/custom-fonts.md +21 -16
  21. package/skills/purgetss/references/custom-rules.md +7 -7
  22. package/skills/purgetss/references/customization-deep-dive.md +14 -11
  23. package/skills/purgetss/references/dynamic-component-creation.md +104 -61
  24. package/skills/purgetss/references/grid-layout.md +21 -24
  25. package/skills/purgetss/references/icon-fonts.md +37 -20
  26. package/skills/purgetss/references/installation-setup.md +1 -1
  27. package/skills/purgetss/references/ios-large-titles.md +12 -11
  28. package/skills/purgetss/references/migration-guide.md +101 -10
  29. package/skills/purgetss/references/multi-density-images.md +44 -24
  30. package/skills/purgetss/references/opacity-modifier.md +1 -1
  31. package/skills/purgetss/references/performance-tips.md +5 -4
  32. package/skills/purgetss/references/platform-modifiers.md +2 -2
  33. package/skills/purgetss/references/purgetss-ui-classic.md +21 -5
  34. package/skills/purgetss/references/semantic-colors.md +20 -13
  35. package/skills/purgetss/references/smart-mappings.md +8 -7
  36. package/skills/purgetss/references/svg-pipeline.md +21 -13
  37. package/skills/purgetss/references/tikit-components.md +2 -2
  38. package/skills/purgetss/references/titanium-resets.md +27 -17
  39. package/skills/purgetss/references/ui-ux-design.md +38 -26
  40. package/skills/purgetss/references/values-and-units.md +1 -2
  41. package/skills/purgetss/references/version-history.md +32 -4
@@ -84,7 +84,7 @@ After running `purgetss build-fonts` with the Bevan and Dancing Script example a
84
84
  `./purgetss/styles/fonts.tss`
85
85
  ```css
86
86
  // Fonts TSS file generated with PurgeTSS
87
- // https://purgetss.com/docs/customization/custom-fonts
87
+ // https://purgetss.com/docs/commands#build-fonts-command
88
88
 
89
89
  '.bevan-italic': { font: { fontFamily: 'Bevan-Italic' } }
90
90
  '.bevan-regular': { font: { fontFamily: 'Bevan-Regular' } }
@@ -95,11 +95,13 @@ After running `purgetss build-fonts` with the Bevan and Dancing Script example a
95
95
  '.dancingscript-semibold': { font: { fontFamily: 'DancingScript-SemiBold' } }
96
96
  ```
97
97
 
98
+ The generated file also places a `/** … */` metadata comment (full name, version, vendor, license) before each font class; it is omitted from these excerpts.
99
+
98
100
  You can now use these classes on any Titanium component with a `font` property: Labels, Buttons, TextFields, TextAreas, ListItems, TableViewRows, and ActivityIndicators.
99
101
 
100
102
  ### Renaming the class
101
103
 
102
- To use a shorter or different class name, rename the font file. For example:
104
+ By default the class name is the lowercased PostScript name, so renaming the font file alone changes nothing. The file name drives the class only with `-f, --font-class-from-filename`. For example, rename the files:
103
105
 
104
106
  `./purgetss/fonts/`
105
107
  ```bash
@@ -112,7 +114,7 @@ purgetss
112
114
  └─ Script-SemiBold.ttf
113
115
  ```
114
116
 
115
- Running `build-fonts` produces:
117
+ Running `purgetss build-fonts -f` produces:
116
118
 
117
119
  `./purgetss/styles/fonts.tss`
118
120
  ```css
@@ -149,29 +151,29 @@ After `purgetss build-fonts`, the generated `fonts.tss` includes the family clas
149
151
  `./purgetss/styles/fonts.tss`
150
152
  ```css
151
153
  // Fonts TSS file generated with PurgeTSS
152
- // https://purgetss.com/docs/customization/custom-fonts
154
+ // https://purgetss.com/docs/commands#build-fonts-command
153
155
 
154
156
  '.map-icons': { font: { fontFamily: 'map-icons' } }
155
157
  '.microns': { font: { fontFamily: 'microns' } }
156
158
 
157
- /* Unicode Characters */
158
- /* To use your Icon Fonts in Buttons AND Labels each class sets 'text' and 'title' properties */
159
+ // Unicode Characters
160
+ // To use your Icon Fonts in Buttons AND Labels each class sets 'text' and 'title' properties
159
161
 
160
- /* map-icons/map-icons.css */
162
+ // map-icons/map-icons.css
161
163
  '.map-icon-abseiling': { text: '\ue800', title: '\ue800' }
162
164
  '.map-icon-accounting': { text: '\ue801', title: '\ue801' }
163
165
  '.map-icon-airport': { text: '\ue802', title: '\ue802' }
164
166
  '.map-icon-amusement-park': { text: '\ue803', title: '\ue803' }
165
167
  '.map-icon-aquarium': { text: '\ue804', title: '\ue804' }
166
- /* ... */
168
+ // ...
167
169
 
168
- /* microns/microns.css */
170
+ // microns/microns.css
169
171
  '.mu-arrow-left': { text: '\ue700', title: '\ue700' }
170
172
  '.mu-arrow-right': { text: '\ue701', title: '\ue701' }
171
173
  '.mu-arrow-up': { text: '\ue702', title: '\ue702' }
172
174
  '.mu-arrow-down': { text: '\ue703', title: '\ue703' }
173
175
  '.mu-left': { text: '\ue704', title: '\ue704' }
174
- /* ... */
176
+ // ...
175
177
  ```
176
178
 
177
179
  ## Options
@@ -192,6 +194,10 @@ $ purgetss bf -m
192
194
 
193
195
  The module is generated for text-only font collections too. By default, every TTF/OTF contributes a camel-cased PostScript-name key to `families`; with `--font-class-from-filename`, that key comes from the filename instead. Icon CSS can add a shorter family alias and a nested `icons` map. Both singular and plural export names remain available.
194
196
 
197
+ Once `purgetss.fonts.js` exists, later `build-fonts` runs regenerate it even without `--module`; if no font or icon data remains, the file is deleted.
198
+
199
+ The module also appends the `getIcon`, `setText`, `setTitle`, `getRandomKey`, and `getRandomValue` helpers. They look up top-level `icons` keys, which in this module are library prefixes, so read a glyph directly as `icons.<prefix>.<name>`.
200
+
195
201
  `app/lib/purgetss.fonts.js` (Alloy) or `Resources/lib/purgetss.fonts.js` (Classic)
196
202
  ```javascript
197
203
  const icons = {
@@ -264,25 +270,24 @@ purgetss
264
270
 
265
271
  `./purgetss/styles/fonts.tss`
266
272
  ```css
267
- /* "fontFamily" classes use the font's filename */
268
273
  '.map': { font: { fontFamily: 'map-icons' } }
269
274
  '.mic': { font: { fontFamily: 'microns' } }
270
275
 
271
- /* map-icons/mp.css */
276
+ // map-icons/mp.css
272
277
  '.mp-abseiling': { text: '\ue800', title: '\ue800' }
273
278
  '.mp-accounting': { text: '\ue801', title: '\ue801' }
274
279
  '.mp-airport': { text: '\ue802', title: '\ue802' }
275
280
  '.mp-amusement-park': { text: '\ue803', title: '\ue803' }
276
281
  '.mp-aquarium': { text: '\ue804', title: '\ue804' }
277
- /* ... */
282
+ // ...
278
283
 
279
- /* microns/mc.css */
284
+ // microns/mc.css
280
285
  '.mc-arrow-left': { text: '\ue700', title: '\ue700' }
281
286
  '.mc-arrow-right': { text: '\ue701', title: '\ue701' }
282
287
  '.mc-arrow-up': { text: '\ue702', title: '\ue702' }
283
288
  '.mc-arrow-down': { text: '\ue703', title: '\ue703' }
284
289
  '.mc-left': { text: '\ue704', title: '\ue704' }
285
- /* ... */
290
+ // ...
286
291
  ```
287
292
 
288
293
  `app/lib/purgetss.fonts.js` (Alloy) or `Resources/lib/purgetss.fonts.js` (Classic)
@@ -338,4 +343,4 @@ The following notes reflect community experience with `build-fonts` against real
338
343
  > Titanium cannot render Font Awesome duotone icons because each icon uses two glyphs. If you work with Font Awesome Pro, avoid documenting duotone as supported.
339
344
 
340
345
  > **💡 Use `--module` to set `text`/`title` from JavaScript**
341
- > Hardcoding `` in a controller is brittle. The `-m` flag generates a `purgetss.fonts.js` you can `require()` and reference by friendly name: `label.text = icons.fa.home`. Combine with `families` to set `font.fontFamily` programmatically.
346
+ > Hardcoding `'\uf015'` in a controller is brittle. The `-m` flag generates a `purgetss.fonts.js` you can `require()` and reference by friendly name: `label.text = icons.fa.home`. Combine with `families` to set `font.fontFamily` programmatically.
@@ -20,8 +20,8 @@ Whether you want to style a Ti Element (a markup element such as `Label`), a cus
20
20
  >
21
21
  > 1. **Audit current usage.** Set `purge.options.missing` to `true` in `config.cjs`. PurgeTSS will append a list of missing classes at the end of `app.tss` after the next compile — every entry is a class name you still need to migrate.
22
22
  > 2. **Rename selectors.** Convert every `.myCustomClassName` to `.my-custom-class-name` in both XML markup and `config.cjs`. The old camelCase names will not match anymore.
23
- > 3. **Convert config to `.cjs`.** If your project still uses `purgetss.config.js` or a CommonJS-style file with the old layout, rename the file to `config.cjs` and ensure it sits in `./purgetss/`. The single export must be `module.exports = { theme: { ... } }`.
24
- > 4. **Re-run `purgetss build`.** Verify the missing-classes list at the end of `app.tss` is empty before turning `missing` back off.
23
+ > 3. **Let PurgeTSS rename the config.** If the project still has `./purgetss/config.js`, the next PurgeTSS run renames it to `./purgetss/config.cjs` automatically. If both files exist, PurgeTSS reads only `config.cjs` and leaves `config.js` untouched, so merge any settings it holds into `config.cjs` and delete it.
24
+ > 4. **Re-run `purgetss`** (or build the Alloy project, which runs it through the auto-purge hook). Verify the missing-classes list at the end of `app.tss` is empty before turning `missing` back off. `purgetss build` only regenerates `utilities.tss`; it does not write `app.tss`.
25
25
  >
26
26
  > Skipping any of these steps tends to surface as silently dropped styles at runtime — the app compiles, but selectors no longer match.
27
27
 
@@ -43,7 +43,7 @@ The way you write property values determines how PurgeTSS emits them in the gene
43
43
  - For `spacing` values you can mix unit types. Each unit follows a specific conversion rule:
44
44
  - `%`, `px`, `cm`, and `in` are passed through to TSS without conversion.
45
45
  - `em` and `rem` values are converted with the formula `value * 16` (so `1rem` becomes `16`).
46
- - `dp` removes the unit and keeps the numeric value as-is, since Titanium treats unit-less numeric values as density-independent pixels by default.
46
+ - `dp` removes the unit and keeps the numeric value as-is. Titanium resolves unit-less numbers with `ti.ui.defaultunit` in `tiapp.xml` (the Alloy template default is `dp`).
47
47
 
48
48
  ## `config.cjs` File Example
49
49
 
@@ -100,21 +100,21 @@ module.exports = {
100
100
  PurgeTSS reads `config.cjs` and emits a single `utilities.tss` file that Alloy then merges with the rest of the project's styling. The file below shows what the example above generates — note how block keys translate into TSS query suffixes (`[platform=android]`, `[formFactor=tablet]`, `[if=...]`).
101
101
 
102
102
  ```tss
103
- /* Property: TextField */
104
- /* Description: A single line text field. */
103
+ // Property: TextField
104
+ // Description: A single line text field.
105
105
  'TextField': { top: 10, left: 20, right: 20, bottom: 0 }
106
106
  'TextField[if=Alloy.Globals.iPhoneX]': { bottom: Alloy.CFG.iPhoneXNotchSize }
107
107
  'TextField[platform=android]': { touchFeedback: true }
108
108
 
109
- /* Custom Classes */
109
+ // Custom Classes
110
110
  '#main-banner': { width: '300px', height: '80px' }
111
111
  '#main-banner[platform=ios]': { clipMode: Ti.UI.iOS.CLIP_MODE_DISABLED }
112
-
113
112
  '.gallery': { height: Ti.UI.SIZE }
114
113
  '.gallery[platform=ios]': { clipMode: Ti.UI.iOS.CLIP_MODE_ENABLED }
115
114
  '.gallery[platform=android]': { hiddenBehavior: Ti.UI.HIDDEN_BEHAVIOR_GONE }
116
115
  '.gallery[formFactor=handheld]': { width: '250px' }
117
116
  '.gallery[formFactor=tablet]': { width: '500px' }
117
+ // End of Custom Classes
118
118
  ```
119
119
 
120
120
  ## Community-Discovered Patterns
@@ -36,10 +36,11 @@ purgetss init
36
36
  This creates a `./purgetss/config.cjs` file with the default sections:
37
37
 
38
38
  ```javascript
39
+ // ./purgetss/config.cjs
39
40
  module.exports = {
40
41
  purge: {
41
42
  mode: 'all',
42
- method: 'sync', // How to execute the auto-purging task: sync or async
43
+ method: 'sync', // set how to execute auto-purging: sync or async
43
44
 
44
45
  // These options are passed directly to PurgeTSS
45
46
  options: {
@@ -50,14 +51,17 @@ module.exports = {
50
51
  }
51
52
  },
52
53
  brand: {
53
- background: '#FFFFFF', // inherited by every piece that doesn't set its own
54
- artworkCornerRadius: '0%', // rounded non-icon artwork: splashes, Feature Graphic and LaunchLogo
55
- confirmOverwrites: true, // prompt before overwriting files (set false to skip)
56
- optimize: false, // true = quantize the generated PNGs to a palette (lossy, ~71% smaller)
54
+ // Opaque fallback fill; configurable, not required to be white by either platform.
55
+ background: '#FFFFFF', // inherited by pieces that use an opaque background canvas
56
+ artworkCornerRadius: '0%', // rounded non-icon artwork: splashes, Feature Graphic and LaunchLogo (0-50)
57
+ confirmOverwrites: true, // prompt before overwriting files (set false to skip)
58
+ optimize: false, // true = quantize the generated PNGs to a palette (lossy, ~71% smaller)
57
59
 
58
60
  // One block per piece. Artwork comes from purgetss/brand/logo-<piece>.{svg,png};
59
61
  // these keys are for numbers, colors and activation. Padding is never inherited.
60
- // Only iosSplash, androidSplash, featureGraphic and launchLogo accept cornerRadius.
62
+ // iosSplash, androidSplash, featureGraphic and launchLogo accept cornerRadius.
63
+ // Store and launcher icons stay square for platform masking.
64
+ // iOS/store icons are full-bleed by default; increase padding only for logo artwork.
61
65
  icon: { padding: '0%' }, // DefaultIcon.png + DefaultIcon-ios.png
62
66
  dark: { background: null }, // DefaultIcon-Dark.png
63
67
  tinted: {}, // DefaultIcon-Tinted.png
@@ -86,18 +90,17 @@ module.exports = {
86
90
  autoSync: true, // false = SVG pipeline computes dims but doesn't write to images.files
87
91
  confirmOverwrites: true, // prompt before overwriting files (set false to skip)
88
92
  files: [] // per-file overrides: [{ filename: 'images/<sub>/<name>.<ext>', width, height? }]
89
- // Note: --width (v7.8.0) and --opacity / --padding / --output (v7.10.0) are CLI-only
90
- // by design — those decisions are per-asset, not project-wide. Since v7.17.0
91
- // writing any of them here aborts the run instead of being ignored.
92
93
  },
93
94
  theme: {
94
95
  extend: {}
95
96
  }
96
- };
97
+ }
97
98
  ```
98
99
 
99
100
  `init` also creates empty `purgetss/fonts/`, `purgetss/brand/`, and `purgetss/images/` folders on first run, so you can see where each kind of asset goes.
100
101
 
102
+ `--width` (v7.8.0) and `--opacity` / `--padding` / `--output` (v7.10.0) are CLI-only flags of `purgetss images`, by design: those decisions are per-asset, not project-wide. Since v7.17.0 the `images:` section rejects unknown keys, so writing any of them in `config.cjs` aborts the run instead of being ignored.
103
+
101
104
  Every section is optional. Only add what you want to change. Anything missing falls back to the defaults.
102
105
 
103
106
  ## Structure
@@ -533,7 +536,7 @@ module.exports = {
533
536
  This generates classes like `bg-regal-blue` in addition to all of Tailwind's default colors.
534
537
 
535
538
  > **ℹ️ INFO**
536
- > You can use the `shades` command to generate a range of shades for a color and add them to `config.cjs`. See [CLI Commands](./cli-commands.md#shades-command).
539
+ > You can use the `shades` command to generate a range of shades for a color and add them to `config.cjs`. See [Color Commands](./color-commands.md#shades-command).
537
540
 
538
541
  ## Customize Spacing
539
542
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **SCOPE NOTE**
4
4
  >
5
- > This reference covers dynamic component creation using **Alloy's `$.UI.create()` helper** and **`Alloy.createStyle()` + `applyProperties()`**, both combined with PurgeTSS utility classes. It is an Alloy + PurgeTSS integration guide, **not** documentation for the `purgetss.ui` native module (see [animation-system.md](./animation-system.md) and [animation-advanced.md](./animation-advanced.md) for Alloy animation usage, or [purgetss-ui-classic.md](./purgetss-ui-classic.md) for the generated Classic runtime).
5
+ > This reference covers dynamic component creation using **Alloy's `$.UI.create()` helper** and **`$.createStyle()` + `applyProperties()`**, both combined with PurgeTSS utility classes. It is an Alloy + PurgeTSS integration guide, **not** documentation for the `purgetss.ui` native module (see [animation-system.md](./animation-system.md) and [animation-advanced.md](./animation-advanced.md) for Alloy animation usage, or [purgetss-ui-classic.md](./purgetss-ui-classic.md) for the generated Classic runtime).
6
6
  >
7
7
  > For general Alloy controller and view patterns, refer to the `alloy-guides` and `alloy-howtos` skills.
8
8
 
@@ -12,11 +12,11 @@
12
12
  - [Community-Discovered Patterns](#community-discovered-patterns)
13
13
  - [Overview](#overview)
14
14
  - [Method 1: `$.UI.create()` (Recommended)](#method-1-uicreate-recommended)
15
- - [Method 2: `Alloy.createStyle()` + `applyProperties()`](#method-2-alloycreatestyle--applyproperties)
15
+ - [Method 2: `$.createStyle()` + `applyProperties()`](#method-2-createstyle--applyproperties)
16
16
  - [Comparison: Which Method to Use?](#comparison-which-method-to-use)
17
17
  - [Real-World Examples](#real-world-examples)
18
18
  - [Important Notes](#important-notes)
19
- - [Dynamic Styling with `classes` Property](#dynamic-styling-with-classes-property)
19
+ - [Changing Classes at Runtime](#changing-classes-at-runtime)
20
20
  - [Anti-Patterns to Avoid](#anti-patterns-to-avoid)
21
21
  - [Summary](#summary)
22
22
 
@@ -31,11 +31,11 @@ The guidance in this file reflects patterns that PurgeTSS users have converged o
31
31
  When creating components dynamically in Controllers (not declaratively in XML), PurgeTSS provides two methods to apply utility classes:
32
32
 
33
33
  1. **`$.UI.create()`** - Create components with PurgeTSS classes (Recommended)
34
- 2. **`Alloy.createStyle()` + `applyProperties()`** - Apply PurgeTSS styles to existing components
34
+ 2. **`$.createStyle()` + `applyProperties()`** - Apply PurgeTSS styles to existing components
35
35
 
36
36
  > **BEST PRACTICE**
37
37
  >
38
- > Always prefer `$.UI.create()` for dynamic components — it's cleaner, more readable, and PurgeTSS will process the classes automatically during build.
38
+ > Always prefer `$.UI.create()` for dynamic components — it's cleaner, more readable, and PurgeTSS picks up the classes during build as long as they are written as literals under a `classes:` key in a controller (see [What the Class Scanner Collects](#what-the-class-scanner-collects)).
39
39
 
40
40
  ---
41
41
 
@@ -62,7 +62,7 @@ $.UI.create('ComponentType', {
62
62
  function createThemeCard(themeName, themeTitle, imagePath) {
63
63
  return $.UI.create('View', {
64
64
  // View properties
65
- title: themeTitle, // Add title for TTS support
65
+ accessibilityLabel: themeTitle, // Read by VoiceOver/TalkBack (Ti.UI.View has no `title` property)
66
66
 
67
67
  // PurgeTSS utility classes
68
68
  classes: [
@@ -102,7 +102,7 @@ classes: ['w-screen', 'h-auto', 'bg-white', 'rounded-lg']
102
102
  classes: 'w-screen h-auto bg-white rounded-lg'
103
103
 
104
104
  // Option 3: Mix arbitrary values with predefined classes
105
- classes: ['w-(100px)', 'h-auto', 'bg-(#ff0000)', 'rounded-lg']
105
+ classes: ['w-(100)', 'h-auto', 'bg-(#ff0000)', 'rounded-lg']
106
106
  ```
107
107
 
108
108
  ### Platform Modifiers in Dynamic Components
@@ -123,7 +123,7 @@ classes: [
123
123
  // Arbitrary values use parentheses notation
124
124
  classes: [
125
125
  'w-(160)', // Custom width
126
- 'h-(200px)', // Custom height with unit
126
+ 'h-(12.5rem)', // Custom height with a unit (not px: a px suffix stops the build)
127
127
  'bg-(#3b82f6)', // Custom hex color
128
128
  'm-(10dp)', // Custom margin with unit
129
129
  'border-(2)' // Custom border width
@@ -157,21 +157,21 @@ function createListItem(text, icon) {
157
157
 
158
158
  ---
159
159
 
160
- ## Method 2: `Alloy.createStyle()` + `applyProperties()`
160
+ ## Method 2: `$.createStyle()` + `applyProperties()`
161
161
 
162
162
  ### When to Use This Method
163
163
 
164
- Use `Alloy.createStyle()` when you need to:
164
+ Use the controller's `createStyle()` method when you need to:
165
165
  - Apply PurgeTSS styles to an **existing component** (created without `$.UI.create()`)
166
- - Modify styles dynamically after component creation
167
- - Apply styles from a different view/controller
166
+ - Build a style dictionary once and apply it to several components
167
+ - Style a view of another controller (`Alloy.createController('dialog').createStyle(...)`, as in the Alloy dynamic styles guide)
168
168
 
169
169
  ### Basic Syntax
170
170
 
171
171
  ```javascript
172
172
  // Create style object
173
- const style = Alloy.createStyle('viewName', {
174
- apiName: 'Ti.UI.View',
173
+ const style = $.createStyle({
174
+ apiName: 'View',
175
175
  classes: 'bg-white rounded-lg'
176
176
  })
177
177
 
@@ -185,8 +185,8 @@ $.myView.applyProperties(style)
185
185
  // controllers/form/validation.js
186
186
  function showError(inputField, errorMessage) {
187
187
  // Create error style
188
- const errorStyle = Alloy.createStyle('index', {
189
- apiName: 'Ti.UI.TextField',
188
+ const errorStyle = $.createStyle({
189
+ apiName: 'TextField',
190
190
  classes: ['border-2', 'border-red-500', 'bg-red-50']
191
191
  })
192
192
 
@@ -196,8 +196,8 @@ function showError(inputField, errorMessage) {
196
196
 
197
197
  function clearError(inputField) {
198
198
  // Create normal style
199
- const normalStyle = Alloy.createStyle('index', {
200
- apiName: 'Ti.UI.TextField',
199
+ const normalStyle = $.createStyle({
200
+ apiName: 'TextField',
201
201
  classes: ['border-1', 'border-gray-300', 'bg-white']
202
202
  })
203
203
 
@@ -210,10 +210,11 @@ function clearError(inputField) {
210
210
 
211
211
  ```javascript
212
212
  // String format
213
- Alloy.createStyle('index', { classes: 'bg-white rounded-lg' })
213
+ $.createStyle({ apiName: 'View', classes: 'bg-white rounded-lg' })
214
214
 
215
215
  // Array format
216
- Alloy.createStyle('index', {
216
+ $.createStyle({
217
+ apiName: 'Label',
217
218
  classes: ['bg-white', 'rounded-lg', 'text-center']
218
219
  })
219
220
  ```
@@ -225,8 +226,8 @@ Alloy.createStyle('index', {
225
226
  | Scenario | Recommended Method | Example |
226
227
  | ------------------------------- | ------------------------------------------- | ------------------------------------------------ |
227
228
  | **Creating new components** | `$.UI.create()` | `$.UI.create('View', { classes: ['bg-white'] })` |
228
- | **Styling existing components** | `Alloy.createStyle()` + `applyProperties()` | `view.applyProperties(Alloy.createStyle(...))` |
229
- | **Dynamic style changes** | `Alloy.createStyle()` + `applyProperties()` | Form validation, theme switching |
229
+ | **Styling existing components** | `$.createStyle()` + `applyProperties()` | `view.applyProperties($.createStyle(...))` |
230
+ | **Swapping classes at runtime** | `$.addClass()` / `$.removeClass()` / `$.resetClass()` | Form validation, active/inactive states |
230
231
  | **Component factories** | `$.UI.create()` | Reusable component creators |
231
232
 
232
233
  ---
@@ -236,21 +237,19 @@ Alloy.createStyle('index', {
236
237
  ### Example 1: Dynamic Form Fields
237
238
 
238
239
  ```javascript
239
- // lib/factories/formFactory.js
240
- exports.createFormField = function(fieldType, options) {
241
- const baseClasses = ['w-screen', 'h-12', 'mx-4', 'border-gray-300', 'border-(1)', 'rounded-lg']
242
-
240
+ // controllers/form.js
241
+ function createFormField(fieldType, options) {
243
242
  switch (fieldType) {
244
243
  case 'text':
245
244
  return $.UI.create('TextField', {
246
245
  hintText: options.hint,
247
- classes: [...baseClasses, 'bg-white', 'px-4']
246
+ classes: ['w-screen', 'h-12', 'mx-4', 'border-gray-300', 'border-(1)', 'rounded-lg', 'bg-white', 'px-4']
248
247
  })
249
248
 
250
249
  case 'textarea':
251
250
  return $.UI.create('TextArea', {
252
251
  hintText: options.hint,
253
- classes: [...baseClasses, 'h-24', 'bg-white', 'px-4']
252
+ classes: ['w-screen', 'h-24', 'mx-4', 'border-gray-300', 'border-(1)', 'rounded-lg', 'bg-white', 'px-4']
254
253
  })
255
254
 
256
255
  case 'button':
@@ -262,6 +261,12 @@ exports.createFormField = function(fieldType, options) {
262
261
  }
263
262
  ```
264
263
 
264
+ > **NOTE — Keep factories in controllers, with literal class lists**
265
+ >
266
+ > - `$` is the controller instance, so `$.UI.create()` is not available in a plain `app/lib/` CommonJS module, and PurgeTSS does not scan `app/lib/` for classes.
267
+ > - Each class list is written out in full under `classes:`. A shared `baseClasses` array spread into `classes: [...baseClasses, ...]` is invisible to the scanner: spread elements are skipped and the array itself is not under a `classes:` key, so those classes would be purged from `app.tss`.
268
+ > - `px-4` sets `padding`, which exists only on `Ti.UI.TextField`, `Ti.UI.TextArea` (Android and iOS) and `Ti.UI.Android.CardView` (apidoc 13_4_1_GA). The `// padding - Android Only` comment in `utilities.tss` is inaccurate for the two text inputs.
269
+
265
270
  ### Example 2: Dynamic List Items
266
271
 
267
272
  ```javascript
@@ -306,12 +311,12 @@ function createProductCard(product) {
306
311
  function applyTheme(theme) {
307
312
  const themes = {
308
313
  light: {
309
- window: Alloy.createStyle('index', { classes: 'bg-white' }),
310
- text: Alloy.createStyle('index', { classes: 'text-gray-900' })
314
+ window: $.createStyle({ apiName: 'Window', classes: 'bg-white' }),
315
+ text: $.createStyle({ apiName: 'Label', classes: 'text-gray-900' })
311
316
  },
312
317
  dark: {
313
- window: Alloy.createStyle('index', { classes: 'bg-gray-900' }),
314
- text: Alloy.createStyle('index', { classes: 'text-gray-100' })
318
+ window: $.createStyle({ apiName: 'Window', classes: 'bg-gray-900' }),
319
+ text: $.createStyle({ apiName: 'Label', classes: 'text-gray-100' })
315
320
  }
316
321
  }
317
322
 
@@ -325,13 +330,19 @@ function applyTheme(theme) {
325
330
  ```javascript
326
331
  // controllers/dashboard/grid.js
327
332
  function createIconGrid(items) {
333
+ // `grid` goes on the container; `grid-cols-4` (width: 25%) goes on each cell
328
334
  const grid = $.UI.create('View', {
329
- classes: ['w-screen', 'grid-cols-4', 'gap-4']
335
+ classes: ['grid']
330
336
  })
331
337
 
332
338
  items.forEach(item => {
339
+ const cell = $.UI.create('View', {
340
+ classes: ['grid-cols-4']
341
+ })
342
+
343
+ // Optional gutter: `gap-*` sets margins, so it goes on an inner view
333
344
  const icon = $.UI.create('View', {
334
- classes: ['vertical']
345
+ classes: ['gap-1', 'vertical']
335
346
  })
336
347
 
337
348
  const iconView = $.UI.create('Label', {
@@ -346,7 +357,8 @@ function createIconGrid(items) {
346
357
 
347
358
  icon.add(iconView)
348
359
  icon.add(label)
349
- grid.add(icon)
360
+ cell.add(icon)
361
+ grid.add(cell)
350
362
  })
351
363
 
352
364
  return grid
@@ -361,13 +373,39 @@ function createIconGrid(items) {
361
373
 
362
374
  > **NOTE — HOW IT WORKS**
363
375
  >
364
- > When you use `$.UI.create()` or `Alloy.createStyle()` with classes:
376
+ > When you use `$.UI.create()` or `$.createStyle()` with classes:
365
377
  >
366
378
  > 1. PurgeTSS scans your controllers for these class references
367
379
  > 2. It adds the classes to the generated `app.tss`
368
380
  > 3. At runtime, Alloy applies the styles to your components
369
381
  >
370
- > This means you get the full PurgeTSS utility surface even with dynamic components.
382
+ > This works only for classes the scanner can see (next section). Anything else is purged from `app.tss` and silently does nothing at runtime.
383
+
384
+ ### What the Class Scanner Collects
385
+
386
+ PurgeTSS parses every file in `app/controllers/**/*.js`, plus `app/widgets/**/controllers/*.js` when `purge.options.widgets` is `true`. Files in `app/lib/` are not scanned.
387
+
388
+ It collects class names only from these shapes:
389
+
390
+ | Shape | Example |
391
+ | --- | --- |
392
+ | Value of a `classes:` or `apply:` property | `classes: ['bg-white', 'rounded-lg']`, `classes: 'bg-white rounded-lg'` |
393
+ | Second argument of any `*Class(target, value)` call, or `resetClass(target, value)` | `$.addClass($.label, 'text-red-500')` |
394
+
395
+ Inside those, it reads string literals, template literals without `${}`, array elements, and both branches of a ternary (`isActive ? 'text-green-500' : 'text-red-500'`).
396
+
397
+ It does not see classes held in a variable, built by concatenation or interpolation (`` `bg-${color}-500` ``), added with `.push()`, or spread from another array (`[...baseClasses]`). For classes that must be built dynamically, list them in `purge.options.safelist` in `purgetss/config.cjs`, which keeps them no matter the purge mode (see the PurgeTSS configuring guide, `options.safelist`):
398
+
399
+ ```javascript
400
+ // purgetss/config.cjs
401
+ module.exports = {
402
+ purge: {
403
+ options: {
404
+ safelist: ['bg-red-500', 'bg-green-500', 'bg-blue-500']
405
+ }
406
+ }
407
+ }
408
+ ```
371
409
 
372
410
  ### Class Verification
373
411
 
@@ -378,7 +416,10 @@ Just like with XML views, always verify classes exist before using them:
378
416
  classes: ['w-screen', 'h-auto', 'bg-white', 'rounded-lg']
379
417
 
380
418
  // WRONG - These classes don't exist
381
- classes: ['flex-row', 'justify-center', 'p-4'] // No flexbox, no p-* on View
419
+ classes: ['flex-row', 'justify-center'] // No flexbox in Titanium
420
+
421
+ // NO EFFECT - `p-4` exists, but it sets `padding`, which only TextField, TextArea and Android CardView have
422
+ $.UI.create('View', { classes: ['p-4'] }) // Use margins on the children instead
382
423
  ```
383
424
 
384
425
  See [Class Index](class-index.md) for available classes.
@@ -394,7 +435,7 @@ classes: [
394
435
  'bg-white'
395
436
  ]
396
437
 
397
- // Avoid: Conditional logic in controllers
438
+ // Avoid: Conditional logic in controllers (the scanner does not see `.push()`, so classes added only this way are purged)
398
439
  if (OS_IOS) {
399
440
  classes.push('mx-4')
400
441
  } else {
@@ -404,20 +445,24 @@ if (OS_IOS) {
404
445
 
405
446
  ---
406
447
 
407
- ## Dynamic Styling with `classes` Property
448
+ ## Changing Classes at Runtime
408
449
 
409
- You can change PurgeTSS classes dynamically at runtime using the `classes` property in `applyProperties()`:
450
+ `applyProperties({ classes: [...] })` does not restyle a view: it only sets a `classes` property on the proxy. To change the classes of a view that already exists, use the controller's `addClass`, `removeClass` and `resetClass` methods (Alloy dynamic styles guide). Pass the view, then the classes as an array or space-separated string, and optionally inline properties as a third argument:
410
451
 
411
452
  ```javascript
412
453
  // Toggle status styling dynamically
413
454
  function setStatus(isActive) {
414
- $.statusLabel.applyProperties({
415
- classes: isActive ? ['text-green-500'] : ['text-red-500'],
455
+ $.removeClass($.statusLabel, isActive ? 'text-red-500' : 'text-green-500')
456
+ $.addClass($.statusLabel, isActive ? 'text-green-500' : 'text-red-500', {
416
457
  text: isActive ? L('active') : L('inactive')
417
458
  })
418
459
  }
419
460
  ```
420
461
 
462
+ - `resetClass(view, classes)` replaces every class on the view, including the ones set in XML, so pass the full list.
463
+ - Enable autostyle (`<Alloy autoStyle="true">` in the view, or `autoStyle: true` in `config.json`) so removing a class also reverts its properties. Without it, a removed class leaves its values on the view.
464
+ - The PurgeTSS scanner reads the second argument of these calls, including both branches of a ternary.
465
+
421
466
  ### Conditional Styling Based on State
422
467
 
423
468
  ```javascript
@@ -452,9 +497,9 @@ function setState(state) {
452
497
  }
453
498
  ```
454
499
 
455
- > **NOTE — When to use `classes` vs `applyProperties`**
500
+ > **NOTE — When to use `addClass`/`removeClass` vs `applyProperties`**
456
501
  >
457
- > - Use `classes` when you want to swap entire style sets (e.g., active/inactive states)
502
+ > - Use `addClass`/`removeClass`/`resetClass` when you want to swap entire style sets (e.g., active/inactive states)
458
503
  > - Use `applyProperties` with direct values when changing individual properties (e.g., text, enabled)
459
504
  > - Combine both for complex state changes
460
505
 
@@ -483,33 +528,30 @@ const view = $.UI.create('View', {
483
528
  })
484
529
  ```
485
530
 
486
- ### Don't mix inline styles and classes
531
+ ### Mixing inline properties and classes: keep inline values for runtime data
532
+
533
+ Alloy supports inline properties next to `classes`, and inline properties take precedence over class styles. Use them for values only known at runtime, and keep static styling in classes so it stays consistent with the rest of the app:
487
534
 
488
535
  ```javascript
489
- // CONFUSING - Mix of styles and classes
536
+ // Avoid - a static value that a class already covers
490
537
  const view = $.UI.create('View', {
491
- backgroundColor: '#ffffff', // Manual style
492
- classes: ['w-screen', 'rounded-lg'] // PurgeTSS classes
538
+ backgroundColor: '#ffffff', // Same as `bg-white`
539
+ classes: ['w-screen', 'rounded-lg']
493
540
  })
494
541
  ```
495
542
 
496
- ### Use only classes (or only styles)
497
-
498
543
  ```javascript
499
544
  // CORRECT - Pure PurgeTSS
500
545
  const view = $.UI.create('View', {
501
546
  classes: ['w-screen', 'h-auto', 'bg-white', 'rounded-lg']
502
547
  })
503
548
 
504
- // OR for truly dynamic/runtime-only values
505
- const view = Ti.UI.createView({
506
- backgroundColor: dynamicColor, // Runtime value
507
- width: calculatedWidth
508
- })
509
- // Then apply PurgeTSS classes
510
- view.applyProperties(Alloy.createStyle('index', {
549
+ // CORRECT - Runtime values inline, static styling as classes
550
+ const view = $.UI.create('View', {
551
+ backgroundColor: dynamicColor, // Runtime value, overrides any class color
552
+ width: calculatedWidth,
511
553
  classes: ['rounded-lg', 'm-4']
512
- }))
554
+ })
513
555
  ```
514
556
 
515
557
  ---
@@ -519,8 +561,9 @@ view.applyProperties(Alloy.createStyle('index', {
519
561
  | Method | Use Case | Syntax |
520
562
  | ------------------------- | --------------------------- | ---------------------------------------------------- |
521
563
  | **`$.UI.create()`** | Creating new components | `$.UI.create('View', { classes: ['bg-white'] })` |
522
- | **`Alloy.createStyle()`** | Styling existing components | `Alloy.createStyle('view', { classes: 'bg-white' })` |
564
+ | **`$.createStyle()`** | Styling existing components | `$.createStyle({ apiName: 'View', classes: 'bg-white' })` |
523
565
  | **`applyProperties()`** | Apply style to component | `component.applyProperties(style)` |
566
+ | **`$.addClass()` / `$.removeClass()` / `$.resetClass()`** | Swapping classes at runtime | `$.addClass($.label, 'text-red-500')` |
524
567
 
525
568
  > **NOTE — REMEMBER**
526
569
  >
@@ -531,4 +574,4 @@ view.applyProperties(Alloy.createStyle('index', {
531
574
  > - All layout classes (`horizontal`, `vertical`)
532
575
  > - All typography classes (`text-*`, `font-*`)
533
576
  > - Platform modifiers (`ios:*`, `android:*`)
534
- > - Arbitrary values (`w-(100px)`, `bg-(#ff0000)`)
577
+ > - Arbitrary values (`w-(100)`, `bg-(#ff0000)`)