@maccesar/titools 2.10.0 → 3.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 (99) hide show
  1. package/AGENTS-VERCEL-RESEARCH.md +23 -12
  2. package/README.md +81 -182
  3. package/agents/ti-pro.md +8 -14
  4. package/lib/cleanup.js +13 -0
  5. package/lib/commands/skills.js +2 -1
  6. package/lib/commands/update.js +4 -1
  7. package/lib/config.js +9 -11
  8. package/lib/platform.js +1 -1
  9. package/package.json +2 -3
  10. package/skills/purgetss/SKILL.md +12 -0
  11. package/skills/purgetss/references/animation-advanced.md +0 -9
  12. package/skills/purgetss/references/app-branding.md +20 -0
  13. package/skills/purgetss/references/appearance-module.md +85 -27
  14. package/skills/purgetss/references/apply-directive.md +60 -0
  15. package/skills/purgetss/references/arbitrary-values.md +41 -0
  16. package/skills/purgetss/references/cli-commands.md +52 -17
  17. package/skills/purgetss/references/custom-rules.md +36 -19
  18. package/skills/purgetss/references/customization-deep-dive.md +37 -15
  19. package/skills/purgetss/references/grid-layout.md +45 -26
  20. package/skills/purgetss/references/icon-fonts.md +27 -25
  21. package/skills/purgetss/references/installation-setup.md +28 -2
  22. package/skills/purgetss/references/ios-large-titles.md +31 -15
  23. package/skills/purgetss/references/multi-density-images.md +57 -0
  24. package/skills/purgetss/references/opacity-modifier.md +11 -2
  25. package/skills/purgetss/references/semantic-colors.md +44 -1
  26. package/skills/purgetss/references/tikit-components.md +1 -3
  27. package/skills/alloy-guides/SKILL.md +0 -190
  28. package/skills/alloy-guides/references/CLI_TASKS.md +0 -233
  29. package/skills/alloy-guides/references/CONCEPTS.md +0 -171
  30. package/skills/alloy-guides/references/CONTROLLERS.md +0 -279
  31. package/skills/alloy-guides/references/MODELS.md +0 -1214
  32. package/skills/alloy-guides/references/PURGETSS.md +0 -46
  33. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +0 -235
  34. package/skills/alloy-guides/references/VIEWS_STYLES.md +0 -375
  35. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
  36. package/skills/alloy-guides/references/VIEWS_XML.md +0 -581
  37. package/skills/alloy-guides/references/WIDGETS.md +0 -160
  38. package/skills/alloy-howtos/SKILL.md +0 -181
  39. package/skills/alloy-howtos/references/best_practices.md +0 -121
  40. package/skills/alloy-howtos/references/cli_reference.md +0 -230
  41. package/skills/alloy-howtos/references/config_files.md +0 -158
  42. package/skills/alloy-howtos/references/custom_tags.md +0 -148
  43. package/skills/alloy-howtos/references/debugging_troubleshooting.md +0 -78
  44. package/skills/alloy-howtos/references/samples.md +0 -156
  45. package/skills/ti-api/SKILL.md +0 -109
  46. package/skills/ti-api/references/api-android.md +0 -675
  47. package/skills/ti-api/references/api-app-platform.md +0 -636
  48. package/skills/ti-api/references/api-core.md +0 -764
  49. package/skills/ti-api/references/api-data-network.md +0 -641
  50. package/skills/ti-api/references/api-media.md +0 -655
  51. package/skills/ti-api/references/api-modules-ble-bluetooth.md +0 -657
  52. package/skills/ti-api/references/api-modules-coremotion-urlsession.md +0 -411
  53. package/skills/ti-api/references/api-modules-map.md +0 -632
  54. package/skills/ti-api/references/api-modules-nfc.md +0 -725
  55. package/skills/ti-api/references/api-modules-social-misc.md +0 -526
  56. package/skills/ti-api/references/api-services.md +0 -700
  57. package/skills/ti-api/references/api-ui-android.md +0 -499
  58. package/skills/ti-api/references/api-ui-extras.md +0 -702
  59. package/skills/ti-api/references/api-ui-ios-animator.md +0 -378
  60. package/skills/ti-api/references/api-ui-ios.md +0 -756
  61. package/skills/ti-api/references/api-ui-lists.md +0 -581
  62. package/skills/ti-api/references/api-ui-text-input.md +0 -607
  63. package/skills/ti-api/references/api-ui-views.md +0 -572
  64. package/skills/ti-api/references/api-ui-windows-navigation.md +0 -676
  65. package/skills/ti-api/references/api-xml-global.md +0 -743
  66. package/skills/ti-guides/SKILL.md +0 -75
  67. package/skills/ti-guides/references/advanced-data-and-images.md +0 -155
  68. package/skills/ti-guides/references/android-manifest.md +0 -97
  69. package/skills/ti-guides/references/app-distribution.md +0 -373
  70. package/skills/ti-guides/references/application-frameworks.md +0 -366
  71. package/skills/ti-guides/references/cli-reference.md +0 -700
  72. package/skills/ti-guides/references/coding-best-practices.md +0 -150
  73. package/skills/ti-guides/references/commonjs-advanced.md +0 -279
  74. package/skills/ti-guides/references/hello-world.md +0 -99
  75. package/skills/ti-guides/references/hyperloop-native-access.md +0 -458
  76. package/skills/ti-guides/references/javascript-primer.md +0 -402
  77. package/skills/ti-guides/references/reserved-words.md +0 -36
  78. package/skills/ti-guides/references/resources.md +0 -172
  79. package/skills/ti-guides/references/style-and-conventions.md +0 -104
  80. package/skills/ti-guides/references/tiapp-config.md +0 -655
  81. package/skills/ti-howtos/SKILL.md +0 -143
  82. package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -609
  83. package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
  84. package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
  85. package/skills/ti-howtos/references/cross-platform-development.md +0 -358
  86. package/skills/ti-howtos/references/debugging-profiling.md +0 -473
  87. package/skills/ti-howtos/references/extending-titanium.md +0 -684
  88. package/skills/ti-howtos/references/google-maps-v2.md +0 -172
  89. package/skills/ti-howtos/references/ios-map-kit.md +0 -149
  90. package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -595
  91. package/skills/ti-howtos/references/local-data-sources.md +0 -310
  92. package/skills/ti-howtos/references/location-and-maps.md +0 -267
  93. package/skills/ti-howtos/references/media-apis.md +0 -268
  94. package/skills/ti-howtos/references/notification-services.md +0 -539
  95. package/skills/ti-howtos/references/remote-data-sources.md +0 -339
  96. package/skills/ti-howtos/references/tutorials.md +0 -552
  97. package/skills/ti-howtos/references/using-modules.md +0 -182
  98. package/skills/ti-howtos/references/web-content-integration.md +0 -288
  99. package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -125
@@ -35,15 +35,7 @@ module.exports = {
35
35
  }
36
36
  },
37
37
  brand: {
38
- logos: {
39
- // Optional overrides. If omitted, PurgeTSS auto-discovers files from purgetss/brand/:
40
- // primary: './docs/logo.svg',
41
- // androidLauncher: './docs/app-icon.svg',
42
- // androidSplash: './docs/splash.svg',
43
- // monochrome: './docs/logo-mono.svg',
44
- // iosDark: './docs/logo-dark.svg',
45
- // iosTinted: './docs/logo-tinted.svg'
46
- },
38
+ logos: {}, // empty = auto-discovers from purgetss/brand/
47
39
  padding: {
48
40
  ios: '4%', // iOS aesthetic padding. Range 2-8%.
49
41
  androidLegacy: '10%', // legacy ic_launcher.png padding %
@@ -53,15 +45,14 @@ module.exports = {
53
45
  splash: false, // also generate splash_icon.png × 5
54
46
  notification: false // also generate ic_stat_notify.png × 5
55
47
  },
48
+ ios: {
49
+ dark: true, // generate DefaultIcon-Dark.png
50
+ tinted: true, // generate DefaultIcon-Tinted.png
51
+ darkBackground: null // null = transparent per Apple HIG
52
+ },
56
53
  colors: {
57
54
  background: '#FFFFFF' // Android adaptive bg + iOS/marketplace flatten
58
55
  },
59
- // Optional iOS overrides:
60
- // ios: {
61
- // dark: false, // skip DefaultIcon-Dark.png
62
- // tinted: false, // skip DefaultIcon-Tinted.png
63
- // darkBackground: '#111' // opaque dark bg for DefaultIcon-Dark.png (null = transparent per Apple HIG)
64
- // },
65
56
  confirmOverwrites: true // prompt before overwriting files (set false to skip)
66
57
  },
67
58
  images: {
@@ -85,6 +76,37 @@ The config file has four main sections: `purge`, `brand`, `images`, and `theme`.
85
76
 
86
77
  `brand:` and `images:` configure the matching CLI commands — see [CLI Commands: `brand`](./cli-commands.md#brand-command) and [CLI Commands: `images`](./cli-commands.md#images-command) for the full option lists. The rest of this page covers `purge` and `theme`.
87
78
 
79
+ For `brand`, the structure is grouped by purpose (introduced in v7.7.0, refined since):
80
+
81
+ - `logos`: optional path overrides when you do not want to rely on `purgetss/brand/` auto-discovery
82
+ - `padding`: visual sizing for iOS, Android legacy, and Android adaptive icons
83
+ - `android`: Android-only optional outputs such as `splash_icon.png` and notification icons
84
+ - `ios`: iOS-only variant toggles (`dark`, `tinted`) and the optional `darkBackground` color
85
+ - `colors`: shared color settings such as the adaptive background and iOS flatten color
86
+
87
+ For the property-by-property reference, see [Configurable Properties](./configurable-properties.md).
88
+
89
+ ### Overriding logo paths
90
+
91
+ By default, PurgeTSS auto-discovers logo files from `purgetss/brand/`. If you want to use custom paths, add them to `brand.logos`:
92
+
93
+ ```javascript
94
+ module.exports = {
95
+ brand: {
96
+ logos: {
97
+ primary: './my-logos/main.svg', // overrides auto-discovered logo.svg
98
+ androidLauncher: './my-logos/icon.svg', // overrides auto-discovered logo-icon.svg
99
+ androidSplash: './my-logos/splash.svg', // overrides auto-discovered logo-splash.svg
100
+ monochrome: './my-logos/mono.svg', // overrides auto-discovered logo-mono.svg
101
+ iosDark: './my-logos/dark.svg', // overrides auto-discovered logo-dark.svg
102
+ iosTinted: './my-logos/tinted.svg' // overrides auto-discovered logo-tinted.svg
103
+ }
104
+ }
105
+ };
106
+ ```
107
+
108
+ You only need to override the ones you're using. Missing overrides still auto-discover from `purgetss/brand/`.
109
+
88
110
  ### `purge` Section
89
111
 
90
112
  The `purge` section controls how PurgeTSS removes unused classes or keeps the ones you want.
@@ -23,6 +23,9 @@ The snippet below shows the simplest layout. From there, you can mix columns and
23
23
  </Alloy>
24
24
  ```
25
25
 
26
+ > **Visual Reference**
27
+ > The official PurgeTSS docs ship a screenshot at `images/grid-system-example.png` (in the docs source repo) that visualizes how columns, rows, and spans render in a real Alloy view. Consult it when you need a quick mental model of the layout primitives — it is not embedded here, only referenced.
28
+
26
29
  ## Column Grid
27
30
 
28
31
  ### `grid-cols-{n}`
@@ -49,21 +52,7 @@ If a view uses `.row-span-3`, you can add three more views of the same height to
49
52
 
50
53
  ## Available Utilities
51
54
 
52
- These are the available utilities to control the grid.
53
-
54
- ### Gutter Utilities
55
-
56
- - `gap-{size}`: Change the gap between rows and columns.
57
- - `gap-x-{size}` and `gap-y-{size}`: Change the gap between rows and columns independently.
58
- - `gap-{side}-{size}`: Change the gap on a specific side (t=top, r=right, b=bottom, l=left).
59
-
60
- ### Column Span Utilities
61
-
62
- - `col-span-{n}`: Make an element span `n` columns.
63
-
64
- ### Row Span Utilities
65
-
66
- - `row-span-{n}`: Make an element span `n` rows.
55
+ The official source organizes the grid utilities into these categories. The structure below mirrors the official rewrite so you can map directly between this reference and the upstream docs.
67
56
 
68
57
  ### Direction Utilities
69
58
 
@@ -78,18 +67,48 @@ These are the available utilities to control the grid.
78
67
 
79
68
  - `grid-rows-{n}`: Create grids with `n` equally sized rows.
80
69
 
70
+ ### Column Span Utilities
71
+
72
+ - `col-span-{n}`: Make an element span `n` columns inside a 12-column grid.
73
+
74
+ ### Row Span Utilities
75
+
76
+ - `row-span-{n}`: Make an element span `n` rows inside a 12-row grid.
77
+
78
+ ### Gutter Utilities
79
+
80
+ - `gap-{size}`: Change the gap between rows and columns.
81
+ - `gap-x-{size}` and `gap-y-{size}`: Change the gap between rows and columns independently.
82
+ - `gap-{side}-{size}`: Change the gap on a specific side (`t`=top, `r`=right, `b`=bottom, `l`=left).
83
+
81
84
  ### Row Placement Utilities
82
85
 
83
- Control horizontal alignment of elements within a row:
86
+ Control horizontal placement of children inside a row:
84
87
 
85
- | Class | Effect |
86
- | --- | --- |
87
- | `start` | Align to the start of the row |
88
- | `end` | Align to the end of the row |
89
- | `center` | Align to the center of the row |
88
+ | Class | Effect |
89
+ | -------- | --------------------------------- |
90
+ | `start` | Align to the start of the row |
91
+ | `end` | Align to the end of the row |
92
+ | `center` | Align to the center of the row |
90
93
 
91
94
  These apply to child views inside a `grid-cols-*` container and control horizontal placement within the grid cell.
92
95
 
96
+ ## Row Placement Use Cases
97
+
98
+ Combining `row-span-{n}` with `grid-rows-{n}` lets you describe how an element occupies vertical space inside a grid column. The table below covers the most common combinations a Titanium UI tends to need. Every entry is verified against the `grid-rows-{n}` and `row-span-{n}` utilities described in the official source.
99
+
100
+ | Pattern | Example classes | Result |
101
+ | ---------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------- |
102
+ | Full-height column item | `grid-rows-1` + `row-span-1` | One element fills the entire vertical space of the column. |
103
+ | Two equal stacked items | `grid-rows-2` + two children no span | Two views stack vertically, each taking 50% of the column height. |
104
+ | Tall hero on top, short footer at bottom | `grid-rows-12` + `row-span-9`, `row-span-3` | Hero takes 75% of the column height, footer takes 25%. |
105
+ | 3-6-3 vertical split | `grid-rows-12` + `row-span-3`, `row-span-6`, `row-span-3` | Header / body / footer split. Mirrors the 3-6-3 horizontal split shown for `col-span-{n}`. |
106
+ | Sidebar that spans every row | `grid-rows-4` + child with `row-span-4` | Element occupies the full height of a 4-row column. Useful for vertical separators or full-height nav. |
107
+ | Two short rows above a tall row | `grid-rows-12` + `row-span-3`, `row-span-3`, `row-span-6` | Two preview cards above a larger detail panel. |
108
+
109
+ > **Note**
110
+ > Just like `col-span-{n}`, the spans you write must add up to the value declared in `grid-rows-{n}` for the layout to fill the column without leftover space.
111
+
93
112
  ## Community-Discovered Patterns
94
113
 
95
114
  The following notes come from community experience using the PurgeTSS grid system in Titanium projects. They clarify how the grid relates to Titanium's layout engine (not CSS Grid) and offer common use cases for row placement.
@@ -99,8 +118,8 @@ The following notes come from community experience using the PurgeTSS grid syste
99
118
 
100
119
  ### Common Use Cases for Row Placement
101
120
 
102
- | Class | Use case |
103
- | --- | --- |
104
- | `start` | Left-aligned content |
105
- | `end` | Right-aligned buttons or labels |
106
- | `center` | Centered content blocks |
121
+ | Class | Use case |
122
+ | -------- | --------------------------------- |
123
+ | `start` | Left-aligned content |
124
+ | `end` | Right-aligned buttons or labels |
125
+ | `center` | Centered content blocks |
@@ -1,20 +1,21 @@
1
1
  # Icon Font Libraries
2
2
 
3
- > **Official Icon Fonts for PurgeTSS**
4
- > Previous versions of PurgeTSS included several icon font libraries such as Bootstrap Icons, Boxicons, LineIcons, and Tabler Icons. The list was reduced to keep maintenance manageable.
3
+ > ℹ️ **INFO — Official Icon Fonts for PurgeTSS**
5
4
  >
6
- > These are the official icon fonts supported by PurgeTSS:
5
+ > Older versions of PurgeTSS bundled additional icon font libraries — Bootstrap Icons, Boxicons, LineIcons, and Tabler Icons among them. **Those libraries have been deprecated and removed from the official distribution** to keep maintenance under control. They are still usable, but you must rebuild them yourself with `build-fonts` (see below).
6
+ >
7
+ > The icon fonts officially supported and shipped by PurgeTSS today are:
7
8
  >
8
9
  > - [Font Awesome 7 Free](https://fontawesome.com) (upgrade with `purgetss il -v=fa`)
9
- > - [Framework7](https://framework7.io/icons/)
10
+ > - [Framework 7](https://framework7.io/icons/)
10
11
  > - [Material Icons](https://fonts.google.com/icons?icon.set=Material+Icons)
11
12
  > - [Material Symbols](https://fonts.google.com/icons?icon.set=Material+Symbols)
12
13
 
13
- For the official install flow for those vendors, see [CLI Commands](./cli-commands.md#icon-library-command).
14
+ For the official install flow for the supported vendors, see [CLI Commands](./cli-commands.md#icon-library-command).
14
15
 
15
16
  ## Recreate Removed Libraries
16
17
 
17
- You can recreate removed libraries using the `build-fonts` command.
18
+ You can recreate any deprecated library using the `build-fonts` command.
18
19
 
19
20
  ### 1. Download the Libraries
20
21
 
@@ -29,7 +30,7 @@ Start by downloading the libraries from their official websites:
29
30
 
30
31
  Put the desired libraries in the `./purgetss/fonts` folder.
31
32
 
32
- > **INFO**
33
+ > ℹ️ **INFO**
33
34
  > Copy the TrueType or OpenType font files and the `.css` file.
34
35
 
35
36
  ```bash
@@ -67,14 +68,14 @@ The `build-fonts` command generates `./purgetss/styles/fonts.tss` with Unicode c
67
68
  /* To use your Icon Fonts in Buttons AND Labels each class sets 'text' and 'title' properties */
68
69
 
69
70
  /* boxicons.css */
70
- '.bxl-meta': { text: '\uef27', title: '\uef27' }
71
- '.bx-lemon': { text: '\uef28', title: '\uef28' }
72
- '.bxs-lemon': { text: '\uef29', title: '\uef29' }
71
+ '.bxl-meta': { text: '', title: '' }
72
+ '.bx-lemon': { text: '', title: '' }
73
+ /* ... */
73
74
 
74
75
  /* lineicons.css */
75
- '.lni-500px': { text: '\uea03', title: '\uea03' }
76
- '.lni-add-files': { text: '\uea01', title: '\uea01' }
77
- '.lni-adobe': { text: '\uea06', title: '\uea06' }
76
+ '.lni-500px': { text: '', title: '' }
77
+ '.lni-add-files': { text: '', title: '' }
78
+ /* ... */
78
79
  ```
79
80
 
80
81
  ### Rename the Style Rule Name
@@ -116,15 +117,15 @@ When you use the `--modules` option, it generates a `./app/lib/purgetss.fonts.js
116
117
  const icons = {
117
118
  /* boxicons */
118
119
  boxicons: {
119
- bxlMeta: '\uef27',
120
- bxLemon: '\uef28',
121
- bxsLemon: '\uef29'
120
+ bxlMeta: '',
121
+ bxLemon: ''
122
+ /* ... */
122
123
  },
123
124
  /* lineicons */
124
125
  lni: {
125
- '500px': '\uea03',
126
- addFiles: '\uea01',
127
- adobe: '\uea06'
126
+ '500px': '',
127
+ addFiles: ''
128
+ /* ... */
128
129
  }
129
130
  };
130
131
  exports.icons = icons;
@@ -147,9 +148,9 @@ New group prefix: `li`
147
148
  `./purgetss/styles/fonts.tss`
148
149
  ```tss
149
150
  /* lineicons/li.css */
150
- '.li-zoom-out': { text: '\uea02', title: '\uea02' }
151
- '.li-zoom-in': { text: '\uea03', title: '\uea03' }
152
- '.li-zip': { text: '\uea04', title: '\uea04' }
151
+ '.li-zoom-out': { text: '', title: '' }
152
+ '.li-zoom-in': { text: '', title: '' }
153
+ /* ... */
153
154
  ```
154
155
 
155
156
  `./app/lib/purgetss.fonts.js`
@@ -163,12 +164,13 @@ const icons = {
163
164
  exports.icons = icons;
164
165
  ```
165
166
 
166
- > **DANGER**
167
- > Make sure the new prefix remains unique to avoid conflicts with other class prefixes.
167
+ > 🛑 **DANGER**
168
+ >
169
+ > Make sure the new prefix stays unique so it does not collide with other class prefixes. A duplicate prefix will silently overwrite earlier rules in the generated `fonts.tss`, leaving you with icons that render the wrong glyph at runtime.
168
170
 
169
171
  ## Community-Discovered Patterns
170
172
 
171
173
  The following note reflects community experience working with icon fonts that depend on multiple glyphs per icon.
172
174
 
173
- > **Font Awesome Duotone**
175
+ > 🛑 **DANGER — Font Awesome Duotone**
174
176
  > Titanium cannot render Font Awesome duotone icons correctly because each icon uses two glyphs. If you work with Font Awesome Pro, avoid documenting duotone as supported.
@@ -14,9 +14,35 @@ Install PurgeTSS globally on your machine using [NPM](https://www.npmjs.com/).
14
14
 
15
15
  ## XML Validation
16
16
 
17
- PurgeTSS v7.5.3 added XML validation that flags any `--` (double-dash) sequence inside XML comments. Titanium's XML parser treats `--` in comments as invalid, and PurgeTSS now detects those sequences before they break the compile step.
17
+ 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.
18
18
 
19
- If you see a validation warning from PurgeTSS pointing at a view file, replace the offending comment with an alternative marker (for example, `//` or `==`) and re-run the build.
19
+ ### Bad comment example
20
+
21
+ ```xml
22
+ <!-- Options: --flag or --value -->
23
+ ```
24
+
25
+ The `--flag` inside that comment is illegal. PurgeTSS stops with a pointer to the offending line:
26
+
27
+ ```text
28
+ XML comment contains illegal "--" sequence ("--flag")
29
+ Fix: Replace "--" with an em dash or reword the comment to avoid double dashes
30
+ ```
31
+
32
+ ### Why it fails
33
+
34
+ Per the XML 1.0 specification, the two-character sequence `--` is reserved as the close-comment indicator (`-->`). It cannot appear anywhere inside a comment body, even mid-string. Any conforming XML parser will reject the document, so catching it up front is more helpful than a confusing TSS output later.
35
+
36
+ ### How to fix
37
+
38
+ Pick whichever of these reads best:
39
+
40
+ - Replace `--` with a single Unicode em dash (`—`) so the sequence is no longer two ASCII hyphens.
41
+ - Spell out the dashes (for example, write `dash-dash flag` instead of `--flag`).
42
+ - Move the option list outside the comment — for instance, into a sibling `<!-- Options -->` header followed by documentation in your README or `config.cjs` notes.
43
+ - Rephrase so the two dashes simply do not sit next to each other.
44
+
45
+ Any of those approaches keeps the comment readable and produces a document that every XML parser will accept.
20
46
 
21
47
  ## Run PurgeTSS the First Time
22
48
 
@@ -2,13 +2,25 @@
2
2
 
3
3
  Enabling Large Titles on a Window is not a single-property change. When you pair `largeTitleEnabled` with a `ScrollView` inside a `NavigationWindow` or `TabGroup`, **three interdependent iOS Window properties** must work together — otherwise you get either content hidden behind the nav bar or a visible rendering delay when the window opens.
4
4
 
5
- | Property | Value | Why it matters |
6
- | --- | --- | --- |
7
- | `autoAdjustScrollViewInsets` | `true` | iOS automatically adjusts the ScrollView content insets so content starts below the nav bar instead of behind it. |
8
- | `extendEdges` | `[Ti.UI.EXTEND_EDGE_ALL]` | Content extends under the nav/tab bars, producing the translucent blur effect Large Titles depend on. |
9
- | `largeTitleEnabled` | `true` | Shows the large title that collapses to the standard nav bar title as the user scrolls. |
5
+ ## The problem
6
+
7
+ Setting `largeTitleEnabled: true` in isolation looks like it should be enough — Apple's docs suggest a single switch. In practice, omitting the two companion properties produces three distinct visual bugs that are easy to attribute to "iOS being weird" but really come from the layout engine not having enough information:
8
+
9
+ 1. **Content overlaps behind the nav bar.** The ScrollView starts at `y=0`, hidden under the translucent navigation bar. Users see the top of the list cut off and assume content is missing. This happens when `largeTitleEnabled` is set but `autoAdjustScrollViewInsets` is not.
10
+ 2. **The large title flashes / renders with a delay.** On window open, the nav bar region paints empty for a frame or two, then the title pops in. With all three properties present, iOS has the layout it needs *before* the first paint, so the title is there from frame zero. Without `extendEdges`, there is a measurable shadow flash as the system recomputes the layout.
11
+ 3. **Collapse glitches on scroll.** The large title shrinks to standard size as the user scrolls down — that is the whole point. But if `extendEdges` is missing, the collapse animation can stutter or skip frames because iOS has to recompute the safe-area inset for every scroll event instead of treating the nav bar as part of the content area.
12
+
13
+ The fix is not to pick the "right" property. It is to set all three together.
10
14
 
11
- Using only `largeTitleEnabled` causes the nav bar region to render empty for a moment before the title draws. Using `extendEdges` without `autoAdjustScrollViewInsets` pushes content behind the nav bar without compensating the ScrollView insets. All three must be present.
15
+ ## The solution: 3 interdependent properties
16
+
17
+ | Property | Value | What it does |
18
+ | ---------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
19
+ | `autoAdjustScrollViewInsets` | `true` | iOS automatically adjusts the ScrollView content insets so content starts below the nav bar instead of behind it. Without this, the ScrollView's first item sits hidden behind the translucent nav bar. |
20
+ | `extendEdges` | `[Ti.UI.EXTEND_EDGE_ALL]` | Content extends under the nav and tab bars, producing the translucent blur/refraction effect Large Titles depend on. Skipping this causes the shadow flash on open and stutters the collapse animation. |
21
+ | `largeTitleEnabled` | `true` | Shows the oversized title in the navigation bar that collapses to standard size as the user scrolls. This is the master switch — the other two are required for it to render correctly. |
22
+
23
+ Without `autoAdjustScrollViewInsets`, `extendEdges` pushes the content behind the nav bar without compensating the ScrollView insets. Without `extendEdges` + `autoAdjustScrollViewInsets`, using only `largeTitleEnabled` causes the large title to render with a visible delay: the empty nav bar area appears first, then the title draws. With all three properties, iOS calculates the layout before displaying the window.
12
24
 
13
25
  ## iOS-only — use the `ios:` modifier
14
26
 
@@ -39,7 +51,7 @@ Generated style in `./purgetss/styles/utilities.tss`:
39
51
 
40
52
  Individual windows now only need to override `largeTitleDisplayMode` when they want different collapse behavior (e.g. detail windows).
41
53
 
42
- > **Why an `ios:` block and not an inline `ios:` prefix?** `auto-adjust-scroll-view-insets` and `extend-edges-all` are platform-specific classes — they only exist with `[platform=ios]` suffix in `utilities.tss`. The `ios:` block ensures PurgeTSS resolves the platform-suffixed version. See [apply-directive.md](apply-directive.md) → "Platform-Specific Classes".
54
+ > **Why an `ios:` block and not an inline `ios:` prefix?** `auto-adjust-scroll-view-insets` and `extend-edges-all` are platform-specific classes — they only exist with `[platform=ios]` suffix in `utilities.tss`. The `ios:` block ensures PurgeTSS resolves the platform-suffixed version. See [apply-directive.md](./apply-directive.md) → "Platform-Specific Classes".
43
55
 
44
56
  ## NavigationWindow example
45
57
 
@@ -77,15 +89,15 @@ On iOS, `TabGroup` wraps each `Tab`'s Window in an **implicit NavigationWindow**
77
89
  </Alloy>
78
90
  ```
79
91
 
80
- ## Controlling the collapse behavior: `largeTitleDisplayMode`
92
+ ## Controlling large title display
81
93
 
82
- `largeTitleDisplayMode` controls how the title behaves in the navigation stack:
94
+ `largeTitleDisplayMode` controls how the title behaves in the navigation stack — whether it stays large, always shrinks to standard size, or follows the previous window. Combine the three base properties (which make Large Titles render correctly at all) with `largeTitleDisplayMode` per window to get the per-screen behavior you want.
83
95
 
84
- | Mode | Constant | Behavior |
85
- | --- | --- | --- |
86
- | Automatic | `Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_AUTOMATIC` | Inherits from previous window; collapses on scroll. |
87
- | Always | `Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_ALWAYS` | Title stays large regardless of scroll position. |
88
- | Never | `Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_NEVER` | Always uses the standard (small) title size. |
96
+ | Mode | Constant | Behavior |
97
+ | --------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
98
+ | Automatic | `Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_AUTOMATIC` | Inherits the display mode from the previous window in the navigation stack and collapses on scroll. The default. |
99
+ | Always | `Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_ALWAYS` | Title stays large regardless of scroll position. Useful for top-level screens that should never collapse. |
100
+ | Never | `Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_NEVER` | Always uses the standard (small) title size. The right choice for detail windows pushed via `openWindow()`. |
89
101
 
90
102
  ### Detail windows: use `large-title-display-mode-never`
91
103
 
@@ -126,6 +138,10 @@ Sizing the content height to `Ti.UI.SIZE` is what lets iOS determine whether the
126
138
  | `content-w-screen` | `contentWidth` | `Ti.UI.FILL` |
127
139
  | `content-h-auto` | `contentHeight` | `Ti.UI.SIZE` |
128
140
 
141
+ > 💡 **TIP**
142
+ >
143
+ > Set the three base properties (`autoAdjustScrollViewInsets`, `extendEdges`, `largeTitleEnabled`) as global defaults in `config.cjs`, then override `largeTitleDisplayMode` per window only when needed.
144
+
129
145
  ## Community-Discovered Patterns
130
146
 
131
147
  ### TabGroup implicit-NavigationWindow wrapping
@@ -138,4 +154,4 @@ When `theme.Window.ios.apply` sets `large-title-enabled` as a default, every pus
138
154
 
139
155
  ### Cross-reference
140
156
 
141
- The three-property pairing (`autoAdjustScrollViewInsets` + `extendEdges` + `largeTitleEnabled`) is also documented as a reusable global-defaults recipe in [apply-directive.md](apply-directive.md) under *Community-Discovered Patterns → Global Window defaults for Large Titles + ScrollView (iOS)*. Prefer that recipe over per-window repetition whenever the whole app uses Large Titles.
157
+ The three-property pairing (`autoAdjustScrollViewInsets` + `extendEdges` + `largeTitleEnabled`) is also documented as a reusable global-defaults recipe in [apply-directive.md](./apply-directive.md) under *Community-Discovered Patterns → Global Window defaults for Large Titles + ScrollView (iOS)*. Prefer that recipe over per-window repetition whenever the whole app uses Large Titles.
@@ -101,6 +101,62 @@ Recommended sizes for common UI elements (in source pixels, assumed 4×):
101
101
  - **List-row thumbnail**: at least `320×320`
102
102
  - **Button background**: match the intended display size × 4
103
103
 
104
+ ## Pinning the output width with `--width`
105
+
106
+ The 4× master convention works well for raster sources (`.png`, `.jpg`, `.webp`) because the file's pixel dimensions usually reflect the intended 4× size. **SVGs are different.** Their logical size comes from the `viewBox`, and vector editors (Affinity Designer, Illustrator, Figma exports) frequently emit viewBoxes in points or with disproportionate values — a logo can ship with `viewBox="0 0 29559 13542"` and `purgetss images` would happily scale every density from that base, producing files far too large for any UI surface.
107
+
108
+ `--width <n>` (added in PurgeTSS v7.8.0) is the escape hatch: it pins the **`mdpi` / `@1x`** output width to exactly `n` pixels, then derives every other density from that base. Height stays proportional to the source aspect ratio — you only specify width.
109
+
110
+ ```bash
111
+ purgetss images logo.svg --width 256
112
+ ```
113
+
114
+ ### Multiplier table
115
+
116
+ The pinned width drives the scale for every density:
117
+
118
+ | Scale | Multiplier | Width if `--width 256` |
119
+ | --- | --- | --- |
120
+ | `mdpi` / `@1x` | ×1 | 256 |
121
+ | `hdpi` | ×1.5 | 384 |
122
+ | `xhdpi` / `@2x` | ×2 | 512 |
123
+ | `xxhdpi` / `@3x` | ×3 | 768 |
124
+ | `xxxhdpi` | ×4 | 1024 |
125
+
126
+ ### Validation
127
+
128
+ `--width` accepts integers in `[1, 8192]`. Out-of-range values are rejected immediately and the command exits without writing anything:
129
+
130
+ ```bash
131
+ purgetss images logo.svg --width 0
132
+ # Invalid --width '0'. Must be an integer between 1 and 8192.
133
+
134
+ purgetss images logo.svg --width 9000
135
+ # Invalid --width '9000'. Must be an integer between 1 and 8192.
136
+
137
+ purgetss images logo.svg --width abc
138
+ # Invalid --width 'NaN'. Must be an integer between 1 and 8192.
139
+ ```
140
+
141
+ The upper bound of `8192` exists because `--width 8192` already produces a `xxxhdpi` output of 32 768 px — that's Sharp's render ceiling and well beyond anything a Titanium UI needs.
142
+
143
+ ### The hint message for unflagged SVGs
144
+
145
+ Whenever you run `purgetss images` against an SVG **without** `--width`, PurgeTSS prints a one-time hint:
146
+
147
+ ```text
148
+ ⚠ SVG source detected without --width. Output sizes will be derived from
149
+ each SVG's viewBox (treated as a 4× master).
150
+ For SVGs from vector editors with disproportionate viewBoxes, pass
151
+ --width <n> (e.g. --width 256) to pin the @1x/mdpi width.
152
+ ```
153
+
154
+ This is a hint, **not an error**. The legacy 4×-from-viewBox behavior still runs in the same invocation. If your SVG has a sensible viewBox (`300×150` for a 300px-wide logo at 1×, etc.), the default is fine. If the viewBox is in points or noticeably larger than expected, re-run with `--width <n>` for predictable scaling.
155
+
156
+ ### Why CLI-only (no `images:` config equivalent)
157
+
158
+ `--width` deliberately has **no matching property** in the `images:` block of `purgetss/config.cjs`. The reason: width is a **per-asset** decision, not a project-wide setting. A hero illustration, an inline icon, and a logo each need different widths — pinning a single value globally would make most outputs wrong. Project-wide settings like `quality` or `format` belong in `config.cjs`; per-invocation values like `--width` only make sense as CLI flags passed against the specific source you're regenerating.
159
+
104
160
  ## The `images:` config section
105
161
 
106
162
  On the first run, `purgetss images` injects an `images:` block into your existing `purgetss/config.cjs` (between `brand:` and `theme:`) with these defaults:
@@ -291,6 +347,7 @@ If you only tweaked CSS classes (no image changes), you don't need to re-run `pu
291
347
  | --- | --- |
292
348
  | `--format <ext>` | Convert all outputs to: `webp`, `jpeg`, `png`, `avif`, `gif`, `tiff`. Default: keep source format. |
293
349
  | `--quality <n>` | Quality `0–100` for lossy formats. Default `85`. |
350
+ | `--width <n>` | (v7.8.0) Pin `mdpi` / `@1x` output width to `n` pixels; `[1, 8192]`. Other densities derive from this base (×1.5 / ×2 / ×3 / ×4). Most useful for SVG sources with non-standard viewBoxes. CLI-only — no `config.cjs` equivalent because width is per-asset. |
294
351
 
295
352
  **Project & output**
296
353
 
@@ -53,8 +53,17 @@ module.exports = {
53
53
  '.bg-primary': { backgroundColor: '#ce10cc' }
54
54
  ```
55
55
 
56
- > **CAUTION -- Semantic Colors**
57
- > Semantic colors cannot be modified with the opacity modifier because they are defined as an object with light and dark values.
56
+ ## Semantic colors
57
+
58
+ Since v7.9.0, opacity modifiers also work on classes that resolve to a semantic color. Any class mapped to a semantic color entry can use `/<percent>` syntax.
59
+
60
+ ```xml
61
+ <View class="bg-surface/65" />
62
+ ```
63
+
64
+ PurgeTSS detects that `bg-surface` maps to the semantic name `surfaceColor`, then derives a new semantic key (`surfaceColor_65`) with the original `light` and `dark` hex values plus the requested alpha for both modes. It writes that key back to `semantic.colors.json` and emits the rule against the derived key. Light/Dark switching still works.
65
+
66
+ See [Semantic colors — Opacity modifier auto-derivation](./semantic-colors.md#opacity-modifier-auto-derivation) for the full mechanics.
58
67
 
59
68
  ## Community-Discovered Patterns
60
69
 
@@ -302,6 +302,48 @@ Once the JSON and the `config.cjs` mapping are in place, you use the semantic cl
302
302
 
303
303
  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.
304
304
 
305
+ ### Opacity modifier auto-derivation
306
+
307
+ As of PurgeTSS v7.9.0, you can apply the `/N` opacity modifier to **any class that resolves to a semantic name** in `semantic.colors.json`, and PurgeTSS will derive a new semantic key with that alpha pre-applied for both `light` and `dark` modes. This works for `bg-*`, `text-*`, `border-*`, and any other color-accepting utility whose class is mapped through `theme.extend.colors` in `config.cjs`.
308
+
309
+ ```xml
310
+ <View class="bg-surface/65" />
311
+ <Label class="text-on-surface/80" text="Subtle" />
312
+ <View class="border border-accent/40" />
313
+ ```
314
+
315
+ On the next `purgetss build` (or plain `purgetss`) run, the toolchain executes a three-step flow:
316
+
317
+ 1. **Detects the mapping** — PurgeTSS sees that, for example, `bg-surface` is mapped to the semantic name `surfaceColor` via `config.cjs`.
318
+ 2. **Derives a new key** — it adds `surfaceColor_65` (naming convention: `<originalKey>_<alphaPercent>`, underscore + integer percent) to `semantic.colors.json`, copying the original hex values for both modes and tagging each with `alpha: "65"`:
319
+
320
+ ```json
321
+ "surfaceColor_65": {
322
+ "light": { "color": "#F9FAFB", "alpha": "65" },
323
+ "dark": { "color": "#0f172a", "alpha": "65" }
324
+ }
325
+ ```
326
+
327
+ 3. **Emits the rule against the derived key** — for example, `'.bg-surface/65': { backgroundColor: 'surfaceColor_65' }`. Light/Dark switching keeps working because Titanium handles the lookup like any other semantic color. The same flow runs for opacity inside an `apply:` string in `config.cjs`.
328
+
329
+ #### Idempotency and the `Conflict` error
330
+
331
+ Re-runs are idempotent: existing derived keys are reused, never duplicated. If you manually edit a derived key with values that disagree with what PurgeTSS would generate (different base color, different alpha, different shape), the next build halts with a `Conflict` error instead of silently overwriting your edits — you have to either revert the manual change or remove the derived key so it can be regenerated cleanly.
332
+
333
+ > **DANGER**
334
+ >
335
+ > **Native rebuild required for new alpha entries**
336
+ >
337
+ > `semantic.colors.json` is read at **native build time**, not at runtime. The first time a brand-new opacity variant is auto-derived (a class like `bg-surface/65` you've never used before), the running app **will not see it** until the next full Titanium build. Liveview hot-reload alone does **not** refresh `semantic.colors.json` for the running app — only the native binary does.
338
+ >
339
+ > In practice: after introducing a new opacity class, run `purgetss build` once, then start a fresh native build (`appc run` / `ti build`) before resuming your usual Liveview cycle. Subsequent runs of the *same* `/N` value reuse the existing derived key and need no extra rebuild.
340
+
341
+ #### Constraints
342
+
343
+ - **Alpha range**: integer `0–100`, matching the standard opacity modifier syntax. Values outside this range are rejected.
344
+ - **Base key must exist**: the semantic name behind the class (`surfaceColor` in the example) must already exist in `semantic.colors.json`. If it doesn't, PurgeTSS emits a warning for direct XML usage or throws an Error for `apply:` directives, with three concrete suggestions in the message.
345
+ - **Naming is fixed**: the derived key is always `<originalKey>_<alphaPercent>` — underscore + integer percent. This mirrors the `/65` you typed and stays quote-free in `config.cjs` if you ever need to reference it manually.
346
+
305
347
  ## Using semantic colors in controllers
306
348
 
307
349
  Semantic colors also work from JavaScript. Three patterns cover the cases you'll hit.
@@ -368,10 +410,11 @@ A minimal semantic palette that covers most app surfaces:
368
410
  | Cards / elevated | `surfaceHighColor` | `#FFFFFF` | `#1e293b` | `bg-surface-high` |
369
411
  | Primary text | `textColor` | `#111827` | `#f1f5f9` | `text-on-surface` |
370
412
  | Secondary text | `textSecondaryColor` | `#6B7280` | `#94a3b8` | `text-on-surface-variant` |
413
+ | Muted text | `textMutedColor` | `#9CA3AF` | `#64748b` | `text-muted` |
371
414
  | Borders / dividers | `borderColor` | `#E5E7EB` | `#334155` | `bg-border` |
372
415
  | Accent | `accentColor` | `#3B82F6` | `#60a5fa` | `text-accent`, `bg-accent` |
373
416
 
374
- Start with these 5-6 colors and add more only when the design requires it. Fewer semantic colors means easier maintenance.
417
+ Start with these 6-7 colors and add more only when the design requires it. Fewer semantic colors means easier maintenance.
375
418
 
376
419
  ## Related
377
420
 
@@ -316,9 +316,7 @@ Colors: `black`, `dark`, `light`, and `white` themes that affect background and
316
316
 
317
317
  Use this for code examples. Set `copy="true"` to add a copy button.
318
318
 
319
- > **Community-Discovered PatternPro tip**
320
- >
321
- > For best results, install a monospaced font (like Fira Code or JetBrains Mono) and configure `font-mono` in your PurgeTSS config.
319
+ **Pro tiprecommended monospace fonts:** For best results, install a monospaced font (like Fira Code or JetBrains Mono) and configure `font-mono` in your PurgeTSS config. (Source: official tikit docs, `tikit.md` line ~390.)
322
320
 
323
321
  **Localization:** The copy button uses `L('copy', 'Copy')` for its title and `L('code_copied', 'Code copied!')` for the confirmation message. Add these keys to your `strings.xml` files for translation.
324
322