@maccesar/titools 4.3.0 → 4.4.2
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 +15 -12
- package/package.json +1 -1
- package/skills/purgetss/SKILL.md +4 -9
- package/skills/ti-api/references/api-core.md +24 -69
- package/skills/ti-api/references/api-data-network.md +18 -63
- package/skills/ti-api/references/api-media.md +15 -49
- package/skills/ti-api/references/api-modules-coremotion-urlsession.md +6 -20
- package/skills/ti-api/references/api-modules-map.md +17 -40
- package/skills/ti-api/references/api-modules-nfc.md +23 -56
- package/skills/ti-api/references/api-ui-android.md +16 -37
- package/skills/ti-api/references/api-ui-extras.md +28 -72
- package/skills/ti-api/references/api-ui-lists.md +14 -35
- package/skills/ti-api/references/api-ui-text-input.md +13 -39
- package/skills/ti-api/references/api-ui-windows-navigation.md +17 -43
- package/skills/ti-api/references/api-xml-global.md +25 -60
- package/skills/ti-expert/SKILL.md +35 -5
- package/skills/ti-expert/references/adaptive-layouts.md +15 -43
- package/skills/ti-expert/references/alloy-builtins.md +8 -22
- package/skills/ti-expert/references/alloy-structure.md +34 -18
- package/skills/ti-expert/references/anti-patterns.md +18 -39
- package/skills/ti-expert/references/code-conventions.md +5 -3
- package/skills/ti-expert/references/controller-patterns.md +31 -26
- package/skills/ti-expert/references/examples.md +41 -21
- package/skills/ti-expert/references/feedback-migration.md +143 -0
- package/skills/ti-expert/references/feedback-surfaces.md +111 -0
- package/skills/ti-expert/references/feedback-widget-contracts.md +175 -0
- package/skills/ti-expert/references/file-type-association.md +265 -0
- package/skills/ti-expert/references/migration-patterns.md +37 -25
- package/skills/ti-expert/references/security-device.md +58 -56
- package/skills/ti-expert/references/sharing.md +227 -0
- package/skills/ti-expert/references/state-management.md +5 -5
- package/skills/ti-expert/references/theming.md +109 -392
- package/skills/ti-guides/references/coding-best-practices.md +1 -2
- package/skills/ti-guides/references/style-and-conventions.md +1 -2
- package/skills/ti-howtos/references/debugging-profiling.md +1 -2
- package/skills/ti-howtos/references/location-and-maps.md +1 -2
- package/skills/ti-howtos/references/using-modules.md +1 -2
- package/skills/ti-howtos/references/web-content-integration.md +1 -2
- package/skills/ti-howtos/references/webpack-build-pipeline.md +1 -2
- package/skills/ti-ui/references/listviews-and-performance.md +5 -10
- package/skills/ti-ui/references/orientation.md +1 -2
|
@@ -1,448 +1,165 @@
|
|
|
1
|
-
# Theming
|
|
1
|
+
# Theming and dark mode
|
|
2
|
+
|
|
3
|
+
Choose the styling path from the project, not from personal memory. Semantic roles are the shared contract; PurgeTSS or standard Alloy materializes them.
|
|
2
4
|
|
|
3
|
-
<!-- TOC-START -->
|
|
4
5
|
## Contents
|
|
5
6
|
|
|
6
|
-
- [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- [Step 4: respond to theme changes in controllers](#step-4-respond-to-theme-changes-in-controllers)
|
|
15
|
-
- [System dark mode detection](#system-dark-mode-detection)
|
|
16
|
-
- [iOS 13+ / Android 10+](#ios-13-android-10)
|
|
17
|
-
- [Semantic colors (Cross-Platform)](#semantic-colors-cross-platform)
|
|
18
|
-
- [Reusable style classes pattern](#reusable-style-classes-pattern)
|
|
19
|
-
- [Using style classes in views](#using-style-classes-in-views)
|
|
7
|
+
- [Decision path](#decision-path)
|
|
8
|
+
- [Semantic color contract](#semantic-color-contract)
|
|
9
|
+
- [PurgeTSS projects](#purgetss-projects)
|
|
10
|
+
- [Standard Alloy projects](#standard-alloy-projects)
|
|
11
|
+
- [Alloy build-time themes](#alloy-build-time-themes)
|
|
12
|
+
- [Runtime custom themes](#runtime-custom-themes)
|
|
13
|
+
- [Component rules](#component-rules)
|
|
14
|
+
- [Verification](#verification)
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
## Decision path
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
1. Detect `purgetss/` or `purgetss/config.cjs`.
|
|
19
|
+
2. If detected, invoke the `purgetss` skill before writing any class or style.
|
|
20
|
+
3. If not detected, use standard Alloy TSS and Titanium semantic colors.
|
|
21
|
+
4. Use `Alloy.Globals` for a runtime palette only when the product requires custom themes beyond the semantic light/dark/system model.
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
Do not mix these paths accidentally. In particular, never teach a PurgeTSS project to maintain the generated `app/styles/app.tss` by hand.
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
## Semantic color contract
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
│ └── dark/ # Dark theme
|
|
39
|
-
│ ├── styles/
|
|
40
|
-
│ │ └── app.tss # Dark overrides
|
|
41
|
-
│ └── assets/
|
|
42
|
-
│ └── images/
|
|
43
|
-
│ └── logo.png # Dark version of logo
|
|
44
|
-
├── styles/
|
|
45
|
-
│ └── app.tss # Base styles (used when no theme active)
|
|
46
|
-
├── config.json
|
|
47
|
-
```
|
|
27
|
+
Name colors by purpose rather than appearance. A practical design-system contract includes:
|
|
28
|
+
|
|
29
|
+
- app background and elevated surface;
|
|
30
|
+
- primary and secondary text;
|
|
31
|
+
- border/divider;
|
|
32
|
+
- accent and text on accent;
|
|
33
|
+
- modal overlay;
|
|
34
|
+
- success, warning, error, and their readable foreground colors;
|
|
35
|
+
- disabled surface/text where needed.
|
|
48
36
|
|
|
49
|
-
|
|
37
|
+
Define light and dark values in:
|
|
50
38
|
|
|
51
|
-
|
|
39
|
+
- Alloy: `app/assets/semantic.colors.json`
|
|
40
|
+
- Classic: `Resources/semantic.colors.json`
|
|
41
|
+
|
|
42
|
+
Example:
|
|
52
43
|
|
|
53
44
|
```json
|
|
54
45
|
{
|
|
55
|
-
"
|
|
56
|
-
"
|
|
46
|
+
"surfaceColor": {
|
|
47
|
+
"light": "#FFFFFF",
|
|
48
|
+
"dark": "#1E293B"
|
|
57
49
|
},
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
> **⚠️ Theme is compile-time only**
|
|
65
|
-
> Alloy themes are applied at **build time**. You cannot switch themes at runtime using this system alone. For runtime switching, use the Dynamic Theming approach below.
|
|
66
|
-
|
|
67
|
-
### Theme cascade
|
|
68
|
-
|
|
69
|
-
When a theme is active, Alloy merges files in this order:
|
|
70
|
-
1. `app/styles/app.tss` (base)
|
|
71
|
-
2. `app/themes/<theme>/styles/app.tss` (theme override)
|
|
72
|
-
3. `app/styles/<controller>.tss` (controller-specific)
|
|
73
|
-
4. `app/themes/<theme>/styles/<controller>.tss` (theme + controller override)
|
|
74
|
-
|
|
75
|
-
Theme files **merge** with base files , you only need to include properties you want to override.
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Dynamic theming with Alloy.Globals
|
|
80
|
-
|
|
81
|
-
For runtime theme switching (including Dark Mode), use `Alloy.Globals` as a centralized color palette.
|
|
82
|
-
|
|
83
|
-
### Step 1: define color palette
|
|
84
|
-
|
|
85
|
-
```javascript
|
|
86
|
-
// alloy.js
|
|
87
|
-
const themes = {
|
|
88
|
-
light: {
|
|
89
|
-
bg: '#ffffff',
|
|
90
|
-
bgSecondary: '#f3f4f6',
|
|
91
|
-
text: '#111827',
|
|
92
|
-
textSecondary: '#6b7280',
|
|
93
|
-
primary: '#2563eb',
|
|
94
|
-
primaryText: '#ffffff',
|
|
95
|
-
border: '#e5e7eb',
|
|
96
|
-
card: '#ffffff',
|
|
97
|
-
danger: '#ef4444',
|
|
98
|
-
success: '#22c55e'
|
|
50
|
+
"textColor": {
|
|
51
|
+
"light": "#111827",
|
|
52
|
+
"dark": "#F1F5F9"
|
|
99
53
|
},
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
text: '#f9fafb',
|
|
104
|
-
textSecondary: '#9ca3af',
|
|
105
|
-
primary: '#3b82f6',
|
|
106
|
-
primaryText: '#ffffff',
|
|
107
|
-
border: '#374151',
|
|
108
|
-
card: '#1f2937',
|
|
109
|
-
danger: '#f87171',
|
|
110
|
-
success: '#4ade80'
|
|
54
|
+
"overlayColor": {
|
|
55
|
+
"light": "#00000080",
|
|
56
|
+
"dark": "#000000CC"
|
|
111
57
|
}
|
|
112
58
|
}
|
|
113
|
-
|
|
114
|
-
// Load saved preference or default to light
|
|
115
|
-
const savedTheme = Ti.App.Properties.getString('app:theme', 'light')
|
|
116
|
-
Alloy.Globals.theme = themes[savedTheme]
|
|
117
|
-
Alloy.Globals.themeName = savedTheme
|
|
118
59
|
```
|
|
119
60
|
|
|
120
|
-
|
|
61
|
+
Titanium resolves a semantic color name when a color-accepting property uses that name. Keep component APIs tone-based (`neutral`, `success`, `warning`, `error`) and map tones to semantic roles inside the visual layer. Do not pass raw brand hex values through business controllers.
|
|
121
62
|
|
|
122
|
-
|
|
123
|
-
/* app.tss - Global base styles using theme colors */
|
|
124
|
-
"Window": {
|
|
125
|
-
backgroundColor: Alloy.Globals.theme.bg
|
|
126
|
-
}
|
|
63
|
+
## PurgeTSS projects
|
|
127
64
|
|
|
128
|
-
|
|
129
|
-
color: Alloy.Globals.theme.text
|
|
130
|
-
}
|
|
65
|
+
The `purgetss` skill is the source of truth for supported classes, configuration, appearance behavior, and commands. Apply these integration rules:
|
|
131
66
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
67
|
+
- Map semantic color names under `theme.extend.colors` in `purgetss/config.cjs`.
|
|
68
|
+
- Use verified utility classes in Alloy XML.
|
|
69
|
+
- Configure `options.widgets: true` when Widgets contain utility classes.
|
|
70
|
+
- Prefer `config.cjs` for reusable custom rules.
|
|
71
|
+
- Treat `app/styles/app.tss` as generated output and never edit it.
|
|
72
|
+
- Keep only truly specific properties in Widget/controller TSS when no verified utility exists.
|
|
73
|
+
- Use the PurgeTSS Appearance module for light/dark/system selection instead of creating a competing mode service.
|
|
74
|
+
- Read the current PurgeTSS references before naming any utility. Similarity to Tailwind is not evidence that a class exists.
|
|
138
75
|
|
|
139
|
-
|
|
140
|
-
backgroundColor: Alloy.Globals.theme.primary,
|
|
141
|
-
color: Alloy.Globals.theme.primaryText,
|
|
142
|
-
height: 48,
|
|
143
|
-
borderRadius: 8,
|
|
144
|
-
font: { fontWeight: 'bold' }
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
".text-secondary": {
|
|
148
|
-
color: Alloy.Globals.theme.textSecondary
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
".bg-secondary": {
|
|
152
|
-
backgroundColor: Alloy.Globals.theme.bgSecondary
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Step 3: theme switching service
|
|
76
|
+
Conceptual mapping only; verify the actual PurgeTSS syntax before use:
|
|
157
77
|
|
|
158
78
|
```javascript
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
getCurrentTheme() {
|
|
169
|
-
return Alloy.Globals.themeName
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
setTheme(name) {
|
|
173
|
-
if (!themes[name]) return
|
|
174
|
-
|
|
175
|
-
Alloy.Globals.theme = themes[name]
|
|
176
|
-
Alloy.Globals.themeName = name
|
|
177
|
-
Ti.App.Properties.setString('app:theme', name)
|
|
178
|
-
|
|
179
|
-
// Notify all listeners
|
|
180
|
-
EventBus.trigger('theme:changed', { theme: name })
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
toggle() {
|
|
184
|
-
const next = Alloy.Globals.themeName === 'light' ? 'dark' : 'light'
|
|
185
|
-
this.setTheme(next)
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
// Follow system Dark Mode (iOS 13+, Android 10+)
|
|
189
|
-
followSystem() {
|
|
190
|
-
if (Ti.UI.semanticColorType !== undefined) {
|
|
191
|
-
const isDark = Ti.UI.semanticColorType === Ti.UI.SEMANTIC_COLOR_TYPE_DARK
|
|
192
|
-
this.setTheme(isDark ? 'dark' : 'light')
|
|
79
|
+
// purgetss/config.cjs
|
|
80
|
+
module.exports = {
|
|
81
|
+
theme: {
|
|
82
|
+
extend: {
|
|
83
|
+
colors: {
|
|
84
|
+
surface: 'surfaceColor',
|
|
85
|
+
'on-surface': 'textColor',
|
|
86
|
+
overlay: 'overlayColor'
|
|
87
|
+
}
|
|
193
88
|
}
|
|
194
89
|
}
|
|
195
90
|
}
|
|
196
91
|
```
|
|
197
92
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
> **⚠️ Theme change requires UI rebuild**
|
|
201
|
-
> Since TSS is applied at controller creation time, changing `Alloy.Globals.theme` does NOT retroactively update already-rendered views. You must manually update visible elements or restart the root controller.
|
|
202
|
-
|
|
203
|
-
**Approach A: Rebuild root controller (simplest)**
|
|
204
|
-
|
|
205
|
-
```javascript
|
|
206
|
-
// controllers/settings.js
|
|
207
|
-
const { ThemeService } = require('services/themeService')
|
|
208
|
-
|
|
209
|
-
function onToggleTheme() {
|
|
210
|
-
ThemeService.toggle()
|
|
211
|
-
|
|
212
|
-
// Restart app from root controller
|
|
213
|
-
const root = Alloy.createController('index')
|
|
214
|
-
root.getView().open()
|
|
215
|
-
|
|
216
|
-
// Close current window tree
|
|
217
|
-
$.getView().close()
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
**Approach B: Update visible elements in-place (smoother)**
|
|
222
|
-
|
|
223
|
-
```javascript
|
|
224
|
-
// controllers/settings.js
|
|
225
|
-
const EventBus = require('services/eventBus')
|
|
226
|
-
const { ThemeService } = require('services/themeService')
|
|
227
|
-
|
|
228
|
-
function init() {
|
|
229
|
-
EventBus.on('theme:changed', applyTheme)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function applyTheme() {
|
|
233
|
-
const t = Alloy.Globals.theme
|
|
234
|
-
|
|
235
|
-
$.settingsWindow.applyProperties({ backgroundColor: t.bg })
|
|
236
|
-
$.titleLabel.applyProperties({ color: t.text })
|
|
237
|
-
$.themeToggle.applyProperties({ backgroundColor: t.bgSecondary })
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function onToggleTheme() {
|
|
241
|
-
ThemeService.toggle()
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function cleanup() {
|
|
245
|
-
EventBus.off('theme:changed', applyTheme)
|
|
246
|
-
$.destroy()
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
$.cleanup = cleanup
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
## System dark mode detection
|
|
255
|
-
|
|
256
|
-
### iOS 13+ / Android 10+
|
|
257
|
-
|
|
258
|
-
```javascript
|
|
259
|
-
// lib/services/themeService.js (add to existing service)
|
|
260
|
-
|
|
261
|
-
exports.ThemeService = {
|
|
262
|
-
// ... existing methods ...
|
|
263
|
-
|
|
264
|
-
// Initialize system theme listener
|
|
265
|
-
initSystemListener() {
|
|
266
|
-
// Detect current system theme at startup
|
|
267
|
-
this.followSystem()
|
|
268
|
-
|
|
269
|
-
// Re-check on resume (user may have changed system Dark Mode while app was backgrounded)
|
|
270
|
-
// Note: Titanium does not fire a dedicated dark-mode-change event.
|
|
271
|
-
// `Ti.UI.semanticColorType` is the correct way to check the current setting.
|
|
272
|
-
Ti.App.addEventListener('resumed', () => {
|
|
273
|
-
this.followSystem()
|
|
274
|
-
})
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
### Semantic colors (Cross-Platform)
|
|
93
|
+
After generation, inspect the final `app.tss` section for unused or unsupported classes. A clean build that still lists a new unsupported class is not complete.
|
|
280
94
|
|
|
281
|
-
|
|
95
|
+
## Standard Alloy projects
|
|
282
96
|
|
|
283
|
-
|
|
284
|
-
- **Classic apps**: `Resources/semantic.colors.json`
|
|
285
|
-
- **Alloy apps**: `app/assets/semantic.colors.json`
|
|
97
|
+
Without PurgeTSS:
|
|
286
98
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
"alpha": "50"
|
|
293
|
-
},
|
|
294
|
-
"light": "#ff1f1f"
|
|
295
|
-
},
|
|
296
|
-
"backgroundColor": {
|
|
297
|
-
"dark": "#1a1a2e",
|
|
298
|
-
"light": "#ffffff"
|
|
299
|
-
},
|
|
300
|
-
"primaryColor": {
|
|
301
|
-
"dark": {
|
|
302
|
-
"color": "#4ade80",
|
|
303
|
-
"alpha": "100"
|
|
304
|
-
},
|
|
305
|
-
"light": {
|
|
306
|
-
"color": "#22c55e",
|
|
307
|
-
"alpha": "100"
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
```
|
|
99
|
+
- keep global selectors in manually maintained `app/styles/app.tss`;
|
|
100
|
+
- keep screen-specific selectors in `app/styles/<controller>.tss`;
|
|
101
|
+
- keep Widget-specific properties in `app/widgets/<id>/styles/widget.tss`;
|
|
102
|
+
- reference semantic color names from TSS or controller properties;
|
|
103
|
+
- use platform and form-factor modifiers for platform-specific properties.
|
|
312
104
|
|
|
313
|
-
|
|
105
|
+
Example:
|
|
314
106
|
|
|
315
107
|
```tss
|
|
316
|
-
|
|
317
|
-
"
|
|
318
|
-
color: Ti.UI.fetchSemanticColor('textColor')
|
|
108
|
+
"Window": {
|
|
109
|
+
backgroundColor: "backgroundColor"
|
|
319
110
|
}
|
|
320
111
|
|
|
321
|
-
"
|
|
322
|
-
backgroundColor:
|
|
112
|
+
".card": {
|
|
113
|
+
backgroundColor: "surfaceColor",
|
|
114
|
+
borderColor: "borderColor",
|
|
115
|
+
borderWidth: 1
|
|
323
116
|
}
|
|
324
|
-
```
|
|
325
117
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
$.container.backgroundColor = 'backgroundColor';
|
|
118
|
+
".bodyText": {
|
|
119
|
+
color: "textColor"
|
|
120
|
+
}
|
|
330
121
|
```
|
|
331
122
|
|
|
332
|
-
|
|
333
|
-
- On iOS 13+ it uses the native system method that checks the user's system-wide Dark Mode setting
|
|
334
|
-
- On all other platforms it checks `Ti.UI.semanticColorType` and returns the correct color variant
|
|
335
|
-
- Alpha can be set from 0.0-100.0 (integer or float)
|
|
336
|
-
- Light values can use hex with alpha via ARGB/AARRGGBB format
|
|
123
|
+
Do not copy a large utility system into manual TSS. Create only the small set of selectors the app actually uses.
|
|
337
124
|
|
|
338
|
-
|
|
339
|
-
> - **Semantic Colors**: Built-in Dark Mode support, automatic switching, simpler setup. Works cross-platform.
|
|
340
|
-
> - **Alloy.Globals palette**: More control over when/how themes switch, easier to add custom themes beyond light/dark, runtime theme changes with UI rebuild.
|
|
125
|
+
## Alloy build-time themes
|
|
341
126
|
|
|
342
|
-
|
|
127
|
+
Alloy's `app/themes/<name>/` folders can override views, styles, and assets at build time. Select a theme through `app/config.json`. This is appropriate for separate branded builds or compile-time variants.
|
|
343
128
|
|
|
344
|
-
|
|
129
|
+
Do not describe an Alloy build-time theme as runtime light/dark switching. Semantic colors are the default for appearance changes while the app runs.
|
|
345
130
|
|
|
346
|
-
|
|
131
|
+
## Runtime custom themes
|
|
347
132
|
|
|
348
|
-
|
|
349
|
-
/* app.tss - Design System */
|
|
350
|
-
|
|
351
|
-
/* === Layout === */
|
|
352
|
-
".row": { layout: 'horizontal', width: Ti.UI.FILL, height: Ti.UI.SIZE }
|
|
353
|
-
".col": { layout: 'vertical', width: Ti.UI.FILL, height: Ti.UI.SIZE }
|
|
354
|
-
".centered": { width: Ti.UI.SIZE, height: Ti.UI.SIZE }
|
|
355
|
-
|
|
356
|
-
/* === Cards === */
|
|
357
|
-
".card": {
|
|
358
|
-
backgroundColor: Alloy.Globals.theme.card,
|
|
359
|
-
borderRadius: 12,
|
|
360
|
-
borderWidth: 1,
|
|
361
|
-
borderColor: Alloy.Globals.theme.border,
|
|
362
|
-
width: Ti.UI.FILL,
|
|
363
|
-
height: Ti.UI.SIZE
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/* === Buttons === */
|
|
367
|
-
".btn-primary": {
|
|
368
|
-
backgroundColor: Alloy.Globals.theme.primary,
|
|
369
|
-
color: Alloy.Globals.theme.primaryText,
|
|
370
|
-
height: 48,
|
|
371
|
-
width: Ti.UI.FILL,
|
|
372
|
-
borderRadius: 8,
|
|
373
|
-
font: { fontSize: 16, fontWeight: 'bold' }
|
|
374
|
-
}
|
|
133
|
+
Use a centralized runtime palette or theme service only when semantic light/dark/system colors cannot model the requirement, such as multiple user selectable brand themes.
|
|
375
134
|
|
|
376
|
-
|
|
377
|
-
backgroundColor: 'transparent',
|
|
378
|
-
color: Alloy.Globals.theme.primary,
|
|
379
|
-
height: 48,
|
|
380
|
-
width: Ti.UI.FILL,
|
|
381
|
-
borderRadius: 8,
|
|
382
|
-
borderWidth: 1,
|
|
383
|
-
borderColor: Alloy.Globals.theme.primary,
|
|
384
|
-
font: { fontSize: 16, fontWeight: 'bold' }
|
|
385
|
-
}
|
|
135
|
+
If that exception applies:
|
|
386
136
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
borderRadius: 8,
|
|
393
|
-
font: { fontSize: 16, fontWeight: 'bold' }
|
|
394
|
-
}
|
|
137
|
+
- keep the selected theme in one service;
|
|
138
|
+
- expose semantic roles, not control IDs;
|
|
139
|
+
- document how already-created proxies receive updates;
|
|
140
|
+
- remove all listeners in controller cleanup;
|
|
141
|
+
- avoid rebuilding the entire window tree unless the app has measured and accepted that tradeoff.
|
|
395
142
|
|
|
396
|
-
|
|
397
|
-
".text-title": { font: { fontSize: 24, fontWeight: 'bold' }, color: Alloy.Globals.theme.text }
|
|
398
|
-
".text-subtitle": { font: { fontSize: 18, fontWeight: 'semibold' }, color: Alloy.Globals.theme.text }
|
|
399
|
-
".text-body": { font: { fontSize: 16 }, color: Alloy.Globals.theme.text }
|
|
400
|
-
".text-caption": { font: { fontSize: 14 }, color: Alloy.Globals.theme.textSecondary }
|
|
401
|
-
".text-small": { font: { fontSize: 12 }, color: Alloy.Globals.theme.textSecondary }
|
|
402
|
-
|
|
403
|
-
/* === Inputs === */
|
|
404
|
-
".input": {
|
|
405
|
-
height: 48,
|
|
406
|
-
width: Ti.UI.FILL,
|
|
407
|
-
borderRadius: 8,
|
|
408
|
-
borderWidth: 1,
|
|
409
|
-
borderColor: Alloy.Globals.theme.border,
|
|
410
|
-
backgroundColor: Alloy.Globals.theme.bg,
|
|
411
|
-
color: Alloy.Globals.theme.text,
|
|
412
|
-
paddingLeft: 12,
|
|
413
|
-
font: { fontSize: 16 }
|
|
414
|
-
}
|
|
143
|
+
`Alloy.Globals` is a legacy/advanced interoperability option, not the first recommendation for ordinary dark mode.
|
|
415
144
|
|
|
416
|
-
|
|
417
|
-
".mt-sm": { top: 8 }
|
|
418
|
-
".mt-md": { top: 16 }
|
|
419
|
-
".mt-lg": { top: 24 }
|
|
420
|
-
".mt-xl": { top: 32 }
|
|
421
|
-
".mx-md": { left: 16, right: 16 }
|
|
422
|
-
".mx-lg": { left: 24, right: 24 }
|
|
423
|
-
```
|
|
145
|
+
## Component rules
|
|
424
146
|
|
|
425
|
-
|
|
147
|
+
- Components consume semantic roles owned by the host app.
|
|
148
|
+
- Widgets own anatomy and behavior, not the product palette.
|
|
149
|
+
- Localized strings and business callbacks come from the host.
|
|
150
|
+
- Destructive styling must remain distinguishable in both appearances.
|
|
151
|
+
- Overlays, focus indicators, disabled states, and text must retain usable contrast in light, dark, and system modes.
|
|
152
|
+
- Do not create separate light/dark controller branches when a semantic color can express the difference.
|
|
426
153
|
|
|
427
|
-
|
|
428
|
-
<Alloy>
|
|
429
|
-
<Window>
|
|
430
|
-
<View class="col mx-md">
|
|
431
|
-
<Label class="text-title mt-lg" text="L('settings')" />
|
|
154
|
+
## Verification
|
|
432
155
|
|
|
433
|
-
|
|
434
|
-
<Label class="text-body mx-md mt-md" text="L('appearance')" />
|
|
435
|
-
<Button class="btn-secondary mx-md mt-md" title="L('toggle_theme')" onClick="onToggleTheme" />
|
|
436
|
-
</View>
|
|
156
|
+
For every supported platform and form factor:
|
|
437
157
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
158
|
+
1. test light, dark, and follow-system modes;
|
|
159
|
+
2. change appearance while the relevant window remains open;
|
|
160
|
+
3. inspect dialogs, sheets, Snackbars, disabled controls, and overlays;
|
|
161
|
+
4. test localized long text and accessibility focus;
|
|
162
|
+
5. run PurgeTSS generation when detected and resolve unsupported classes;
|
|
163
|
+
6. compile and build both platform targets before claiming completion.
|
|
443
164
|
|
|
444
|
-
|
|
445
|
-
- Consistent spacing and typography across the entire app
|
|
446
|
-
- Theme-aware colors that change with `Alloy.Globals.theme`
|
|
447
|
-
- Clean XML views without inline styles
|
|
448
|
-
- A single place to update design decisions (`app.tss`)
|
|
165
|
+
For exact PurgeTSS behavior, load its current `semantic-colors.md` and `appearance-module.md` references. For Titanium property availability, verify against the current `ti-api` skill.
|
|
@@ -66,8 +66,7 @@ if (isAndroid) { /* Android path */ } else { /* iOS path */ }
|
|
|
66
66
|
- Avoid extending the `Ti` namespace. Three reasons:
|
|
67
67
|
1. Ti objects are proxies to native OS components — your extensions may conflict with native functionality.
|
|
68
68
|
2. Arrays stored on the namespace may be immutable; objects may be null unexpectedly.
|
|
69
|
-
3. There is no guarantee properties persist across SDK versions.
|
|
70
|
-
Use your own namespace or CommonJS module instead of modifying `Ti`.
|
|
69
|
+
3. There is no guarantee properties persist across SDK versions. Use your own namespace or CommonJS module instead of modifying `Ti`.
|
|
71
70
|
|
|
72
71
|
## 5. App architecture recommendations
|
|
73
72
|
|
|
@@ -46,8 +46,7 @@ else
|
|
|
46
46
|
const fullName = firstName + ' ' + lastName
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
Return statement placement:
|
|
50
|
-
Do not put `return` on its own line followed by an object literal. JavaScript will insert a semicolon automatically and return `undefined`.
|
|
49
|
+
Return statement placement: Do not put `return` on its own line followed by an object literal. JavaScript will insert a semicolon automatically and return `undefined`.
|
|
51
50
|
```javascript
|
|
52
51
|
// Wrong
|
|
53
52
|
return
|
|
@@ -382,8 +382,7 @@ Android Studio (GUI): Tools → Device Manager → Create Device.
|
|
|
382
382
|
|
|
383
383
|
### Modifying emulators
|
|
384
384
|
|
|
385
|
-
Increase disk space:
|
|
386
|
-
Edit `~/.android/avd/<NAME>.avd/config.ini`:
|
|
385
|
+
Increase disk space: Edit `~/.android/avd/<NAME>.avd/config.ini`:
|
|
387
386
|
```
|
|
388
387
|
disk.dataPartition.size=1024m
|
|
389
388
|
```
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
## 1. GPS position tracking
|
|
4
4
|
|
|
5
5
|
### FusedLocationProvider (Android)
|
|
6
|
-
Since TiSDK 7.1.0, Titanium supports `FusedLocationProvider` for significant battery savings.
|
|
7
|
-
Requirement: include the `ti.playservices` module in your project.
|
|
6
|
+
Since TiSDK 7.1.0, Titanium supports `FusedLocationProvider` for significant battery savings. Requirement: include the `ti.playservices` module in your project.
|
|
8
7
|
|
|
9
8
|
### Accuracy configuration
|
|
10
9
|
|
|
@@ -25,8 +25,7 @@ Community modules:
|
|
|
25
25
|
- From Zero To App list: https://fromzerotoapp.com/modules/
|
|
26
26
|
- Curated list of modules maintained by Michael Gangolf
|
|
27
27
|
|
|
28
|
-
Marketplace:
|
|
29
|
-
The original Appcelerator Marketplace is no longer available. Find community modules on GitHub and npm. A curated list is at https://fromzerotoapp.com/modules/.
|
|
28
|
+
Marketplace: The original Appcelerator Marketplace is no longer available. Find community modules on GitHub and npm. A curated list is at https://fromzerotoapp.com/modules/.
|
|
30
29
|
|
|
31
30
|
### Pre-installed modules
|
|
32
31
|
Some modules ship with the SDK and do not need separate installation: `ti.map`, `ti.identity`, `ti.webdialog`, `ti.applesignin`.
|
|
@@ -53,8 +53,7 @@ Example:
|
|
|
53
53
|
When you `import { func } from '@/utils'`, Webpack picks the correct version for the build target.
|
|
54
54
|
|
|
55
55
|
## 5. Diagnostic web UI
|
|
56
|
-
Webpack includes a web interface to analyze builds and asset sizes.
|
|
57
|
-
Default URL: `http://localhost:1732/webpack/latest/web`
|
|
56
|
+
Webpack includes a web interface to analyze builds and asset sizes. Default URL: `http://localhost:1732/webpack/latest/web`
|
|
58
57
|
|
|
59
58
|
## 6. Project plugins
|
|
60
59
|
Webpack support is powered by plugins chosen based on project type:
|
|
@@ -202,8 +202,7 @@ The following views can be used as child elements in custom templates: ActivityI
|
|
|
202
202
|
|
|
203
203
|
### Binding syntax
|
|
204
204
|
|
|
205
|
-
XML (Alloy): `bindId:property="value"`
|
|
206
|
-
JavaScript: `{ bindId: { property: value } }`
|
|
205
|
+
XML (Alloy): `bindId:property="value"` JavaScript: `{ bindId: { property: value } }`
|
|
207
206
|
|
|
208
207
|
### Programmatic binding with custom templates
|
|
209
208
|
|
|
@@ -741,14 +740,10 @@ $.myList.cacheSize = 3; // Default
|
|
|
741
740
|
|
|
742
741
|
### Common issues
|
|
743
742
|
|
|
744
|
-
Problem: Jerky scrolling
|
|
745
|
-
Solution: Remove `Ti.UI.SIZE` from templates
|
|
743
|
+
Problem: Jerky scrolling Solution: Remove `Ti.UI.SIZE` from templates
|
|
746
744
|
|
|
747
|
-
Problem: Data changes not visible
|
|
748
|
-
Solution: Use `updateItemAt()` instead of modifying views
|
|
745
|
+
Problem: Data changes not visible Solution: Use `updateItemAt()` instead of modifying views
|
|
749
746
|
|
|
750
|
-
Problem: Event not firing on template element
|
|
751
|
-
Solution: Check `bindId` in event handler
|
|
747
|
+
Problem: Event not firing on template element Solution: Check `bindId` in event handler
|
|
752
748
|
|
|
753
|
-
Problem: Wrong item updated
|
|
754
|
-
Solution: Use `e.section.getItemAt(e.itemIndex)` not a global reference
|
|
749
|
+
Problem: Wrong item updated Solution: Use `e.section.getItemAt(e.itemIndex)` not a global reference
|