@maccesar/titools 2.0.6 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{AGENTS-TEMPLATE.md → AGENTS-VERCEL-RESEARCH.md} +16 -18
- package/README.md +250 -168
- package/agents/{ti-researcher.md → ti-pro.md} +10 -10
- package/bin/titools.js +16 -12
- package/lib/cleanup.js +95 -0
- package/lib/commands/agents.js +146 -70
- package/lib/commands/skills.js +349 -0
- package/lib/commands/uninstall.js +189 -154
- package/lib/commands/update.js +104 -21
- package/lib/config.js +26 -20
- package/lib/downloader.js +1 -1
- package/lib/installer.js +37 -97
- package/lib/platform.js +9 -5
- package/lib/prompts/checkboxCancel.js +264 -0
- package/lib/prompts/selectCancel.js +204 -0
- package/lib/symlink.js +19 -7
- package/lib/utils.js +21 -31
- package/package.json +10 -10
- package/skills/alloy-guides/SKILL.md +8 -30
- package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
- package/skills/alloy-guides/references/CONCEPTS.md +5 -25
- package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
- package/skills/alloy-guides/references/MODELS.md +40 -10
- package/skills/alloy-guides/references/PURGETSS.md +1 -11
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
- package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
- package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
- package/skills/alloy-guides/references/WIDGETS.md +1 -17
- package/skills/alloy-howtos/SKILL.md +1 -22
- package/skills/alloy-howtos/references/best_practices.md +0 -17
- package/skills/alloy-howtos/references/cli_reference.md +1 -23
- package/skills/alloy-howtos/references/config_files.md +86 -15
- package/skills/alloy-howtos/references/custom_tags.md +14 -13
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
- package/skills/alloy-howtos/references/samples.md +4 -14
- package/skills/purgetss/SKILL.md +11 -37
- package/skills/purgetss/references/EXAMPLES.md +106 -17
- package/skills/purgetss/references/animation-system.md +0 -67
- package/skills/purgetss/references/apply-directive.md +0 -18
- package/skills/purgetss/references/arbitrary-values.md +0 -25
- package/skills/purgetss/references/class-index.md +0 -46
- package/skills/purgetss/references/cli-commands.md +0 -41
- package/skills/purgetss/references/configurable-properties.md +0 -55
- package/skills/purgetss/references/custom-rules.md +0 -14
- package/skills/purgetss/references/customization-deep-dive.md +0 -49
- package/skills/purgetss/references/dynamic-component-creation.md +56 -37
- package/skills/purgetss/references/grid-layout.md +0 -32
- package/skills/purgetss/references/icon-fonts.md +0 -50
- package/skills/purgetss/references/installation-setup.md +61 -32
- package/skills/purgetss/references/migration-guide.md +127 -0
- package/skills/purgetss/references/opacity-modifier.md +0 -34
- package/skills/purgetss/references/performance-tips.md +261 -0
- package/skills/purgetss/references/platform-modifiers.md +0 -46
- package/skills/purgetss/references/smart-mappings.md +0 -12
- package/skills/purgetss/references/tikit-components.md +393 -0
- package/skills/purgetss/references/titanium-resets.md +1 -27
- package/skills/purgetss/references/ui-ux-design.md +467 -117
- package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
- package/skills/ti-expert/references/alloy-builtins.md +387 -0
- package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
- package/skills/ti-expert/references/anti-patterns.md +90 -0
- package/skills/ti-expert/references/cli-expert.md +109 -0
- package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
- package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
- package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
- package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
- package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
- package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
- package/skills/ti-expert/references/performance-listview.md +251 -0
- package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
- package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
- package/skills/ti-expert/references/security-fundamentals.md +284 -0
- package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
- package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
- package/skills/ti-expert/references/testing-unit.md +433 -0
- package/skills/ti-expert/references/theming.md +394 -0
- package/skills/ti-guides/SKILL.md +1 -14
- package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
- package/skills/ti-guides/references/app-distribution.md +48 -10
- package/skills/ti-guides/references/application-frameworks.md +9 -2
- package/skills/ti-guides/references/cli-reference.md +338 -82
- package/skills/ti-guides/references/coding-best-practices.md +14 -4
- package/skills/ti-guides/references/commonjs-advanced.md +103 -6
- package/skills/ti-guides/references/hello-world.md +5 -2
- package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
- package/skills/ti-guides/references/javascript-primer.md +4 -3
- package/skills/ti-guides/references/resources.md +0 -1
- package/skills/ti-guides/references/style-and-conventions.md +57 -9
- package/skills/ti-guides/references/tiapp-config.md +48 -6
- package/skills/ti-howtos/SKILL.md +2 -27
- package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
- package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
- package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
- package/skills/ti-howtos/references/cross-platform-development.md +68 -37
- package/skills/ti-howtos/references/debugging-profiling.md +8 -53
- package/skills/ti-howtos/references/extending-titanium.md +12 -51
- package/skills/ti-howtos/references/google-maps-v2.md +30 -29
- package/skills/ti-howtos/references/ios-map-kit.md +19 -25
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
- package/skills/ti-howtos/references/local-data-sources.md +45 -37
- package/skills/ti-howtos/references/location-and-maps.md +47 -28
- package/skills/ti-howtos/references/media-apis.md +84 -27
- package/skills/ti-howtos/references/notification-services.md +40 -89
- package/skills/ti-howtos/references/remote-data-sources.md +21 -36
- package/skills/ti-howtos/references/tutorials.md +79 -39
- package/skills/ti-howtos/references/using-modules.md +4 -30
- package/skills/ti-howtos/references/web-content-integration.md +28 -45
- package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
- package/skills/ti-ui/SKILL.md +1 -21
- package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
- package/skills/ti-ui/references/animation-and-matrices.md +0 -47
- package/skills/ti-ui/references/application-structures.md +0 -46
- package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
- package/skills/ti-ui/references/event-handling.md +32 -40
- package/skills/ti-ui/references/gestures.md +0 -40
- package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
- package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
- package/skills/ti-ui/references/listviews-and-performance.md +187 -73
- package/skills/ti-ui/references/orientation.md +57 -71
- package/skills/ti-ui/references/platform-ui-android.md +114 -48
- package/skills/ti-ui/references/platform-ui-ios.md +63 -38
- package/skills/ti-ui/references/scrolling-views.md +14 -23
- package/skills/ti-ui/references/tableviews.md +6 -56
- package/lib/commands/install.js +0 -188
- package/skills/alloy-expert/references/anti-patterns.md +0 -133
- package/skills/alloy-expert/references/testing.md +0 -872
- package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
- package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
- /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
- /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TSS Styling & Code Conventions
|
|
2
2
|
|
|
3
3
|
## Module System: CommonJS (NOT ES6 modules)
|
|
4
4
|
|
|
@@ -6,11 +6,11 @@ Titanium uses **CommonJS** for modules. Do NOT use ES6 `import`/`export`:
|
|
|
6
6
|
|
|
7
7
|
```javascript
|
|
8
8
|
// CORRECT - CommonJS
|
|
9
|
-
const { Navigation } = require('
|
|
9
|
+
const { Navigation } = require('services/navigation')
|
|
10
10
|
exports.Navigation = { /* ... */ }
|
|
11
11
|
|
|
12
12
|
// WRONG - ES6 modules (won't work in Titanium)
|
|
13
|
-
import { Navigation } from '
|
|
13
|
+
import { Navigation } from 'services/navigation'
|
|
14
14
|
export const Navigation = { /* ... */ }
|
|
15
15
|
```
|
|
16
16
|
|
|
@@ -33,27 +33,176 @@ const users = fetchUsers()
|
|
|
33
33
|
const name = user.name
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
## Styling with
|
|
37
|
-
|
|
36
|
+
## Styling with TSS
|
|
37
|
+
|
|
38
|
+
### TSS File Organization
|
|
39
|
+
|
|
40
|
+
Every controller can have a matching TSS file. Alloy also supports a global `app.tss`.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
app/styles/
|
|
44
|
+
├── app.tss # Global styles (applied to ALL controllers)
|
|
45
|
+
├── index.tss # Styles for index controller only
|
|
46
|
+
└── user/
|
|
47
|
+
├── profile.tss # Styles for user/profile controller
|
|
48
|
+
└── settings.tss
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Style cascade (priority low → high):**
|
|
52
|
+
1. `app.tss` — global base styles
|
|
53
|
+
2. `<controller>.tss` — controller-specific styles
|
|
54
|
+
3. Theme overrides (`app/themes/<name>/styles/`)
|
|
55
|
+
|
|
56
|
+
### Selector Types
|
|
57
|
+
|
|
58
|
+
```tss
|
|
59
|
+
/* Element selector — applies to ALL elements of this type */
|
|
60
|
+
"Label": { color: '#111827', font: { fontSize: 16 } }
|
|
61
|
+
"Window": { backgroundColor: '#ffffff' }
|
|
62
|
+
"TextField": { height: 48, borderRadius: 8 }
|
|
63
|
+
|
|
64
|
+
/* Class selector — reusable, apply via class="..." in XML */
|
|
65
|
+
".card": { borderRadius: 12, backgroundColor: '#fff', borderWidth: 1, borderColor: '#e5e7eb' }
|
|
66
|
+
".btn-primary": { backgroundColor: '#2563eb', color: '#fff', height: 48, borderRadius: 8 }
|
|
67
|
+
".text-secondary": { color: '#6b7280' }
|
|
68
|
+
|
|
69
|
+
/* ID selector — unique to one element */
|
|
70
|
+
"#loginButton": { bottom: 24, left: 16, right: 16 }
|
|
71
|
+
"#headerTitle": { font: { fontSize: 24, fontWeight: 'bold' } }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**When to use each:**
|
|
75
|
+
|
|
76
|
+
| Selector | Use for | Example |
|
|
77
|
+
| ------------------- | --------------------------- | ---------------------- |
|
|
78
|
+
| Element (`"Label"`) | App-wide defaults | Base font, color |
|
|
79
|
+
| Class (`".card"`) | Reusable patterns (3+ uses) | Cards, buttons, inputs |
|
|
80
|
+
| ID (`"#name"`) | Unique element positioning | Specific layout needs |
|
|
81
|
+
|
|
82
|
+
### Class Selectors in XML
|
|
38
83
|
|
|
39
84
|
```xml
|
|
40
|
-
<!--
|
|
41
|
-
<View class="
|
|
42
|
-
<Label class="
|
|
85
|
+
<!-- Combine multiple classes -->
|
|
86
|
+
<View class="card mt-md mx-md">
|
|
87
|
+
<Label class="text-secondary" text="L('subtitle')" />
|
|
88
|
+
<Button class="btn-primary" title="L('action')" />
|
|
43
89
|
</View>
|
|
44
90
|
```
|
|
45
91
|
|
|
46
|
-
|
|
47
|
-
- NO `flex-row`/`flex-col` → Use `horizontal`/`vertical`
|
|
48
|
-
- NO `w-full` → Use `w-screen`
|
|
49
|
-
- NO `p-*` on Views → Use `m-*` on children
|
|
50
|
-
- NO `justify-*`/`items-center` → Use margins/positioning
|
|
92
|
+
Classes defined in `app.tss` are available in every controller. Classes in `<controller>.tss` are only available in that controller.
|
|
51
93
|
|
|
52
|
-
|
|
53
|
-
|
|
94
|
+
### ID + Class Combined
|
|
95
|
+
|
|
96
|
+
When an element has both an ID and classes, properties merge with ID taking priority:
|
|
97
|
+
|
|
98
|
+
```tss
|
|
99
|
+
/* app.tss */
|
|
100
|
+
".btn-primary": { backgroundColor: '#2563eb', color: '#fff', height: 48 }
|
|
101
|
+
|
|
102
|
+
/* user/profile.tss */
|
|
103
|
+
"#saveButton": { bottom: 24, left: 16, right: 16 }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```xml
|
|
107
|
+
<!-- Gets btn-primary styles + saveButton positioning -->
|
|
108
|
+
<Button id="saveButton" class="btn-primary" title="L('save')" />
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Building a Design System in app.tss
|
|
112
|
+
|
|
113
|
+
Define reusable style classes for consistency:
|
|
114
|
+
|
|
115
|
+
```tss
|
|
116
|
+
/* app.tss — Design System */
|
|
117
|
+
|
|
118
|
+
/* === Layout === */
|
|
119
|
+
".row": { layout: 'horizontal', width: Ti.UI.FILL, height: Ti.UI.SIZE }
|
|
120
|
+
".col": { layout: 'vertical', width: Ti.UI.FILL, height: Ti.UI.SIZE }
|
|
121
|
+
|
|
122
|
+
/* === Spacing === */
|
|
123
|
+
".mt-sm": { top: 8 }
|
|
124
|
+
".mt-md": { top: 16 }
|
|
125
|
+
".mt-lg": { top: 24 }
|
|
126
|
+
".mx-md": { left: 16, right: 16 }
|
|
127
|
+
".mx-lg": { left: 24, right: 24 }
|
|
128
|
+
|
|
129
|
+
/* === Typography === */
|
|
130
|
+
".text-title": { font: { fontSize: 24, fontWeight: 'bold' } }
|
|
131
|
+
".text-body": { font: { fontSize: 16 } }
|
|
132
|
+
".text-caption": { font: { fontSize: 14 }, color: '#6b7280' }
|
|
133
|
+
|
|
134
|
+
/* === Components === */
|
|
135
|
+
".card": {
|
|
136
|
+
backgroundColor: '#fff',
|
|
137
|
+
borderRadius: 12,
|
|
138
|
+
borderWidth: 1,
|
|
139
|
+
borderColor: '#e5e7eb',
|
|
140
|
+
width: Ti.UI.FILL,
|
|
141
|
+
height: Ti.UI.SIZE
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
".input": {
|
|
145
|
+
height: 48,
|
|
146
|
+
width: Ti.UI.FILL,
|
|
147
|
+
borderRadius: 8,
|
|
148
|
+
borderWidth: 1,
|
|
149
|
+
borderColor: '#d1d5db',
|
|
150
|
+
backgroundColor: '#fff',
|
|
151
|
+
paddingLeft: 12,
|
|
152
|
+
font: { fontSize: 16 }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
".btn-primary": {
|
|
156
|
+
backgroundColor: '#2563eb',
|
|
157
|
+
color: '#fff',
|
|
158
|
+
height: 48,
|
|
159
|
+
width: Ti.UI.FILL,
|
|
160
|
+
borderRadius: 8,
|
|
161
|
+
font: { fontSize: 16, fontWeight: 'bold' }
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Complete Example
|
|
54
166
|
|
|
55
167
|
```xml
|
|
56
|
-
|
|
168
|
+
<!-- views/feature/list.xml -->
|
|
169
|
+
<View id="container">
|
|
170
|
+
<Label id="welcomeLabel" text="L('welcome')" />
|
|
171
|
+
</View>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```tss
|
|
175
|
+
/* styles/feature/list.tss */
|
|
176
|
+
"#container": {
|
|
177
|
+
layout: 'vertical',
|
|
178
|
+
height: Ti.UI.SIZE,
|
|
179
|
+
width: Ti.UI.FILL,
|
|
180
|
+
backgroundColor: '#f3f4f6'
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
"#welcomeLabel": {
|
|
184
|
+
left: 16,
|
|
185
|
+
right: 16,
|
|
186
|
+
font: { fontSize: 20, fontWeight: 'bold' },
|
|
187
|
+
color: '#2563eb'
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Titanium Layout Rules
|
|
192
|
+
|
|
193
|
+
- Three layout modes: `layout: 'horizontal'`, `layout: 'vertical'`, and composite (default — no `layout` needed)
|
|
194
|
+
- NO padding on container Views — use margins on children instead
|
|
195
|
+
- `width: Ti.UI.FILL` fills available space, `width: Ti.UI.SIZE` wraps content
|
|
196
|
+
- `height: Ti.UI.SIZE` is essential for vertical layouts with dynamic content
|
|
197
|
+
- Use percentage widths (`width: '50%'`) for proportional column layouts
|
|
198
|
+
|
|
199
|
+
## Platform & Device Modifiers
|
|
200
|
+
Use TSS platform modifiers instead of writing conditional logic in controllers.
|
|
201
|
+
|
|
202
|
+
```tss
|
|
203
|
+
"#header[platform=ios]": { top: 40 }
|
|
204
|
+
"#header[platform=android]": { top: 20 }
|
|
205
|
+
"#header[formFactor=tablet]": { top: 80 }
|
|
57
206
|
```
|
|
58
207
|
|
|
59
208
|
## applyProperties() Pattern
|
|
@@ -94,41 +243,23 @@ Use `L()` for all text and always include `accessibilityLabel` for interactive e
|
|
|
94
243
|
|
|
95
244
|
```xml
|
|
96
245
|
<Label text="L('welcome_message')" accessibilityLabel="Welcome Header" />
|
|
97
|
-
<ImageView
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Icon Fonts (PurgeTSS Workflow)
|
|
101
|
-
Integrate icons using classes generated by `purgetss build-fonts`. Classes are mapped to both `text` and `title` properties.
|
|
102
|
-
|
|
103
|
-
```xml
|
|
104
|
-
<Label class="fa-solid fa-envelope mr-2 text-gray-400" />
|
|
105
|
-
<Button class="fas fa-play" title="L('play')" />
|
|
246
|
+
<ImageView image="/images/user.png" accessibilityLabel="User Profile Picture" />
|
|
106
247
|
```
|
|
107
248
|
|
|
108
|
-
##
|
|
109
|
-
Use
|
|
249
|
+
## Percentage-Based Layouts
|
|
250
|
+
Use percentage widths in TSS for responsive column layouts.
|
|
110
251
|
|
|
111
252
|
```xml
|
|
112
|
-
<View
|
|
113
|
-
<View
|
|
114
|
-
<View
|
|
253
|
+
<View id="row">
|
|
254
|
+
<View id="colLeft" />
|
|
255
|
+
<View id="colRight" />
|
|
115
256
|
</View>
|
|
116
257
|
```
|
|
117
258
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
<View class="bg-blue-500" />
|
|
123
|
-
<View class="bg-green-500" />
|
|
124
|
-
</View>
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## Animation Component
|
|
128
|
-
PurgeTSS includes an Animation component (`purgetss.ui`) for 2D Matrix transformations.
|
|
129
|
-
|
|
130
|
-
```xml
|
|
131
|
-
<Animation id="myAnim" module="purgetss.ui" class="close:opacity-0 duration-500 open:opacity-100" />
|
|
259
|
+
```tss
|
|
260
|
+
"#row": { layout: 'horizontal', width: Ti.UI.FILL }
|
|
261
|
+
"#colLeft": { width: '66.66%', backgroundColor: '#ef4444' }
|
|
262
|
+
"#colRight": { width: '33.33%', backgroundColor: '#3b82f6' }
|
|
132
263
|
```
|
|
133
264
|
|
|
134
265
|
## Naming Conventions
|
|
@@ -149,8 +280,10 @@ app/
|
|
|
149
280
|
│ └── helpers/
|
|
150
281
|
│ └── dateHelper.js
|
|
151
282
|
├── views/
|
|
283
|
+
│ ├── index.xml # match controller path exactly
|
|
152
284
|
│ └── user/
|
|
153
|
-
│
|
|
285
|
+
│ ├── profile.xml
|
|
286
|
+
│ └── settings.xml
|
|
154
287
|
```
|
|
155
288
|
|
|
156
289
|
### Variables and Functions
|
|
@@ -227,7 +360,7 @@ exports.updateUser = async function(id, data) { /* ... */ }
|
|
|
227
360
|
exports.deleteUser = async function(id) { /* ... */ }
|
|
228
361
|
|
|
229
362
|
// Usage
|
|
230
|
-
const { getUser, updateUser } = require('
|
|
363
|
+
const { getUser, updateUser } = require('api/userApi')
|
|
231
364
|
```
|
|
232
365
|
|
|
233
366
|
### Default Export (For Classes/Singletons)
|
|
@@ -242,7 +375,7 @@ class Logger {
|
|
|
242
375
|
module.exports = new Logger()
|
|
243
376
|
|
|
244
377
|
// Usage
|
|
245
|
-
const logger = require('
|
|
378
|
+
const logger = require('services/logger')
|
|
246
379
|
```
|
|
247
380
|
|
|
248
381
|
### Mixed Exports
|
|
@@ -263,7 +396,7 @@ exports.Events = {
|
|
|
263
396
|
module.exports = EventBus
|
|
264
397
|
|
|
265
398
|
// Usage
|
|
266
|
-
const EventBus = require('
|
|
399
|
+
const EventBus = require('services/eventBus')
|
|
267
400
|
const { Events } = EventBus
|
|
268
401
|
```
|
|
269
402
|
|
|
@@ -275,7 +408,7 @@ exports.productApi = require('./productApi').productApi
|
|
|
275
408
|
exports.orderApi = require('./orderApi').orderApi
|
|
276
409
|
|
|
277
410
|
// Usage - cleaner imports
|
|
278
|
-
const { userApi, productApi } = require('
|
|
411
|
+
const { userApi, productApi } = require('api')
|
|
279
412
|
```
|
|
280
413
|
|
|
281
414
|
### CommonJS Compatibility
|
|
@@ -1,91 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Alloy Controller Patterns
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Titanium Layout Rules
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<View class="horizontal m-3 w-screen">
|
|
10
|
-
<Label class="fa-solid fa-user-circle text-4xl text-blue-500" />
|
|
11
|
-
<View class="vertical ml-3">
|
|
12
|
-
<Label id="name" class="text-lg font-bold text-gray-900" />
|
|
13
|
-
<Label id="email" class="text-sm text-gray-500" />
|
|
14
|
-
</View>
|
|
15
|
-
</View>
|
|
16
|
-
<Button class="mx-3 mb-3 mt-4 h-10 w-screen rounded-md bg-blue-600 font-medium text-white"
|
|
17
|
-
title="L('view_profile')"
|
|
18
|
-
onClick="onViewProfile"
|
|
19
|
-
/>
|
|
20
|
-
</View>
|
|
21
|
-
</Alloy>
|
|
22
|
-
```
|
|
5
|
+
- Use `layout: 'horizontal'` for left-to-right
|
|
6
|
+
- Use `layout: 'vertical'` for top-to-bottom
|
|
7
|
+
- Omit `layout` for composite (absolute positioning — the default)
|
|
8
|
+
- Use margins on children instead of padding on parent
|
|
23
9
|
|
|
24
|
-
|
|
25
|
-
- Use `horizontal` (not `flex-row`) for left-to-right
|
|
26
|
-
- Use `vertical` (not `flex-col`) for top-to-bottom
|
|
27
|
-
- Omit layout class for composite (absolute positioning)
|
|
28
|
-
- Use `m-*` on children instead of `p-*` on parent
|
|
29
|
-
- Use `border-(1)` with parentheses for arbitrary values
|
|
10
|
+
> For a complete View + TSS + Controller example, see the Quick Start in SKILL.md.
|
|
30
11
|
|
|
31
|
-
## Animation
|
|
12
|
+
## Animation Usage
|
|
32
13
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```xml
|
|
36
|
-
<Animation id="myAnim" module="purgetss.ui" class="close:opacity-0 duration-500 open:opacity-100" />
|
|
37
|
-
```
|
|
14
|
+
Use `Ti.UI.createAnimation()` for UI transitions.
|
|
38
15
|
|
|
39
16
|
```javascript
|
|
40
17
|
// controllers/user/card.js
|
|
41
18
|
function show() {
|
|
42
|
-
$.
|
|
19
|
+
$.container.opacity = 0
|
|
20
|
+
$.container.animate(Ti.UI.createAnimation({
|
|
21
|
+
opacity: 1,
|
|
22
|
+
duration: 500,
|
|
23
|
+
curve: Ti.UI.ANIMATION_CURVE_EASE_OUT
|
|
24
|
+
}))
|
|
43
25
|
}
|
|
44
26
|
|
|
45
|
-
function hide() {
|
|
46
|
-
$.
|
|
47
|
-
|
|
27
|
+
function hide(callback) {
|
|
28
|
+
$.container.animate(Ti.UI.createAnimation({
|
|
29
|
+
opacity: 0,
|
|
30
|
+
duration: 500,
|
|
31
|
+
curve: Ti.UI.ANIMATION_CURVE_EASE_OUT
|
|
32
|
+
}), () => {
|
|
33
|
+
$.container.visible = false
|
|
34
|
+
if (callback) callback()
|
|
48
35
|
})
|
|
49
36
|
}
|
|
50
37
|
```
|
|
51
38
|
|
|
52
|
-
##
|
|
53
|
-
Use the `draggable` method to convert views into draggable elements.
|
|
54
|
-
|
|
55
|
-
```javascript
|
|
56
|
-
$.myAnim.draggable([$.red, $.green, $.blue])
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Dynamic Styling with Classes
|
|
39
|
+
## Dynamic Styling
|
|
60
40
|
|
|
61
|
-
To change styles dynamically, use `
|
|
41
|
+
To change styles dynamically, use `applyProperties()` to batch updates.
|
|
62
42
|
|
|
63
43
|
```javascript
|
|
64
44
|
function setStatus(isActive) {
|
|
65
45
|
$.statusLabel.applyProperties({
|
|
66
|
-
|
|
46
|
+
color: isActive ? '#22c55e' : '#ef4444',
|
|
67
47
|
text: isActive ? L('active') : L('inactive')
|
|
68
48
|
})
|
|
69
49
|
}
|
|
70
50
|
```
|
|
71
51
|
|
|
72
|
-
##
|
|
52
|
+
## Percentage-Based Layouts
|
|
73
53
|
|
|
74
|
-
Use
|
|
54
|
+
Use percentage widths in TSS for responsive column layouts.
|
|
75
55
|
|
|
76
56
|
```xml
|
|
77
|
-
|
|
78
|
-
<View
|
|
79
|
-
<View
|
|
80
|
-
<View class="h-20 w-4/12 bg-blue-100" />
|
|
57
|
+
<View id="row">
|
|
58
|
+
<View id="colLeft" />
|
|
59
|
+
<View id="colRight" />
|
|
81
60
|
</View>
|
|
61
|
+
```
|
|
82
62
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<View class="h-20 bg-green-100" />
|
|
88
|
-
</View>
|
|
63
|
+
```tss
|
|
64
|
+
"#row": { layout: 'horizontal', width: Ti.UI.FILL }
|
|
65
|
+
"#colLeft": { height: 80, width: '66.66%', backgroundColor: '#fee2e2' }
|
|
66
|
+
"#colRight": { height: 80, width: '33.33%', backgroundColor: '#dbeafe' }
|
|
89
67
|
```
|
|
90
68
|
|
|
91
69
|
## Controller Lifecycle Patterns
|
|
@@ -129,27 +107,27 @@ $.cleanup = cleanup
|
|
|
129
107
|
```xml
|
|
130
108
|
<!-- views/user/edit.xml -->
|
|
131
109
|
<Alloy>
|
|
132
|
-
<Window
|
|
133
|
-
<ScrollView
|
|
134
|
-
<View
|
|
135
|
-
<Label
|
|
110
|
+
<Window id="editWindow">
|
|
111
|
+
<ScrollView id="scrollView">
|
|
112
|
+
<View id="formContainer">
|
|
113
|
+
<Label id="nameLabel" text="L('name_label')" />
|
|
136
114
|
<TextField id="nameField"
|
|
137
|
-
class="border-(1) return-key-type-next mx-4 mt-1 h-12 w-screen rounded-lg border-gray-300 bg-gray-50 px-3"
|
|
138
115
|
hintText="L('name_hint')"
|
|
116
|
+
returnKeyType="Ti.UI.RETURNKEY_NEXT"
|
|
139
117
|
onReturn="focusNextField"
|
|
140
118
|
/>
|
|
141
119
|
|
|
142
|
-
<Label
|
|
120
|
+
<Label id="emailLabel" text="L('email_label')" />
|
|
143
121
|
<TextField id="emailField"
|
|
144
|
-
class="border-(1) keyboard-type-email return-key-type-done mx-4 mt-1 h-12 w-screen rounded-lg border-gray-300 bg-gray-50 px-3"
|
|
145
122
|
hintText="L('email_hint')"
|
|
123
|
+
keyboardType="Ti.UI.KEYBOARD_TYPE_EMAIL"
|
|
124
|
+
returnKeyType="Ti.UI.RETURNKEY_DONE"
|
|
146
125
|
onReturn="submitForm"
|
|
147
126
|
/>
|
|
148
127
|
|
|
149
|
-
<Label id="errorLabel"
|
|
128
|
+
<Label id="errorLabel" />
|
|
150
129
|
|
|
151
130
|
<Button id="submitBtn"
|
|
152
|
-
class="bg-primary mx-4 mt-6 h-14 w-screen rounded-xl font-bold text-white"
|
|
153
131
|
title="L('save')"
|
|
154
132
|
onClick="submitForm"
|
|
155
133
|
/>
|
|
@@ -159,10 +137,22 @@ $.cleanup = cleanup
|
|
|
159
137
|
</Alloy>
|
|
160
138
|
```
|
|
161
139
|
|
|
140
|
+
```tss
|
|
141
|
+
/* styles/user/edit.tss */
|
|
142
|
+
"#editWindow": { layout: 'vertical', backgroundColor: '#fff' }
|
|
143
|
+
"#scrollView": { layout: 'vertical', width: Ti.UI.FILL, height: Ti.UI.FILL }
|
|
144
|
+
"#formContainer": { layout: 'vertical', top: 16, height: Ti.UI.SIZE, width: Ti.UI.FILL }
|
|
145
|
+
"Label": { left: 16, font: { fontSize: 14 }, color: '#6b7280' }
|
|
146
|
+
"TextField": { left: 16, right: 16, top: 4, height: 48, borderRadius: 8, borderWidth: 1, borderColor: '#d1d5db', backgroundColor: '#f9fafb', paddingLeft: 12 }
|
|
147
|
+
"#emailLabel": { top: 16 }
|
|
148
|
+
"#errorLabel": { top: 8, color: '#ef4444', visible: false }
|
|
149
|
+
"#submitBtn": { left: 16, right: 16, top: 24, height: 56, borderRadius: 12, backgroundColor: '#2563eb', color: '#fff', font: { fontWeight: 'bold' } }
|
|
150
|
+
```
|
|
151
|
+
|
|
162
152
|
```javascript
|
|
163
153
|
// controllers/user/edit.js
|
|
164
|
-
const { validateEmail, validateRequired } = require('
|
|
165
|
-
const { userService } = require('
|
|
154
|
+
const { validateEmail, validateRequired } = require('helpers/validator')
|
|
155
|
+
const { userService } = require('services/userService')
|
|
166
156
|
|
|
167
157
|
const fields = ['nameField', 'emailField']
|
|
168
158
|
let currentFieldIndex = 0
|
|
@@ -220,26 +210,35 @@ function setLoading(isLoading) {
|
|
|
220
210
|
|
|
221
211
|
```xml
|
|
222
212
|
<!-- Skeleton loading pattern -->
|
|
223
|
-
<View id="loadingState"
|
|
224
|
-
<View
|
|
225
|
-
<View
|
|
226
|
-
<View
|
|
213
|
+
<View id="loadingState">
|
|
214
|
+
<View id="skeleton1" />
|
|
215
|
+
<View id="skeleton2" />
|
|
216
|
+
<View id="skeleton3" />
|
|
227
217
|
</View>
|
|
228
218
|
|
|
229
|
-
<View id="contentState"
|
|
219
|
+
<View id="contentState">
|
|
230
220
|
<!-- Actual content here -->
|
|
231
221
|
</View>
|
|
232
222
|
|
|
233
|
-
<View id="errorState"
|
|
234
|
-
<
|
|
235
|
-
<Label
|
|
236
|
-
<Button
|
|
237
|
-
title="L('retry')"
|
|
238
|
-
onClick="loadData"
|
|
239
|
-
/>
|
|
223
|
+
<View id="errorState">
|
|
224
|
+
<ImageView id="errorIcon" image="/images/error.png" />
|
|
225
|
+
<Label id="errorMsg" text="L('error_loading')" />
|
|
226
|
+
<Button id="retryBtn" title="L('retry')" onClick="loadData" />
|
|
240
227
|
</View>
|
|
241
228
|
```
|
|
242
229
|
|
|
230
|
+
```tss
|
|
231
|
+
"#loadingState": { layout: 'vertical', width: Ti.UI.FILL, height: Ti.UI.FILL }
|
|
232
|
+
"#skeleton1": { left: 16, right: 16, top: 16, height: 80, borderRadius: 8, backgroundColor: '#e5e7eb' }
|
|
233
|
+
"#skeleton2": { left: 16, top: 16, height: 16, width: '66%', borderRadius: 4, backgroundColor: '#e5e7eb' }
|
|
234
|
+
"#skeleton3": { left: 16, top: 8, height: 16, width: '50%', borderRadius: 4, backgroundColor: '#e5e7eb' }
|
|
235
|
+
"#contentState": { width: Ti.UI.FILL, height: Ti.UI.FILL, visible: false }
|
|
236
|
+
"#errorState": { layout: 'vertical', width: Ti.UI.FILL, height: Ti.UI.FILL, visible: false }
|
|
237
|
+
"#errorIcon": { top: 80, width: 64, height: 64 }
|
|
238
|
+
"#errorMsg": { top: 16, font: { fontSize: 18 }, color: '#6b7280' }
|
|
239
|
+
"#retryBtn": { top: 16, height: 40, borderRadius: 8, backgroundColor: '#2563eb', color: '#fff', left: 24, right: 24 }
|
|
240
|
+
```
|
|
241
|
+
|
|
243
242
|
```javascript
|
|
244
243
|
// State management helper
|
|
245
244
|
function setState(state) {
|
|
@@ -331,7 +330,7 @@ function openModal(route, params) {
|
|
|
331
330
|
```xml
|
|
332
331
|
<!-- views/main.xml -->
|
|
333
332
|
<Alloy>
|
|
334
|
-
<TabGroup id="tabGroup"
|
|
333
|
+
<TabGroup id="tabGroup">
|
|
335
334
|
<Tab title="L('home')" icon="/images/tab_home.png">
|
|
336
335
|
<Require src="home/index" />
|
|
337
336
|
</Tab>
|
|
@@ -347,8 +346,8 @@ function openModal(route, params) {
|
|
|
347
346
|
|
|
348
347
|
```javascript
|
|
349
348
|
// controllers/main.js
|
|
350
|
-
// Tab styling is handled in
|
|
351
|
-
//
|
|
349
|
+
// Tab styling is handled in the TSS file:
|
|
350
|
+
// "#tabGroup": { backgroundColor: '#fff', activeTintColor: '#3b82f6' }
|
|
352
351
|
|
|
353
352
|
// Handle tab changes
|
|
354
353
|
$.tabGroup.addEventListener('focus', (e) => {
|
|
@@ -409,21 +408,20 @@ function closeWindow(window, animated = true) {
|
|
|
409
408
|
```xml
|
|
410
409
|
<!-- views/contacts/list.xml -->
|
|
411
410
|
<Alloy>
|
|
412
|
-
<Window
|
|
411
|
+
<Window id="contactsWindow">
|
|
413
412
|
<SearchBar id="searchBar"
|
|
414
|
-
class="w-screen"
|
|
415
413
|
hintText="L('search_contacts')"
|
|
416
414
|
showCancel="true"
|
|
417
415
|
/>
|
|
418
416
|
|
|
419
|
-
<ListView id="listView"
|
|
417
|
+
<ListView id="listView" top="50">
|
|
420
418
|
<Templates>
|
|
421
419
|
<ItemTemplate name="contact" height="64">
|
|
422
|
-
<View
|
|
423
|
-
<
|
|
424
|
-
<View
|
|
425
|
-
<Label bindId="name"
|
|
426
|
-
<Label bindId="phone"
|
|
420
|
+
<View id="contactRow">
|
|
421
|
+
<ImageView bindId="avatar" id="contactAvatar" image="/images/user-circle.png" />
|
|
422
|
+
<View id="contactInfo">
|
|
423
|
+
<Label bindId="name" id="contactName" />
|
|
424
|
+
<Label bindId="phone" id="contactPhone" />
|
|
427
425
|
</View>
|
|
428
426
|
</View>
|
|
429
427
|
</ItemTemplate>
|
|
@@ -435,6 +433,18 @@ function closeWindow(window, animated = true) {
|
|
|
435
433
|
</Alloy>
|
|
436
434
|
```
|
|
437
435
|
|
|
436
|
+
```tss
|
|
437
|
+
/* styles/contacts/list.tss */
|
|
438
|
+
"#contactsWindow": { backgroundColor: '#f9fafb' }
|
|
439
|
+
"#searchBar": { width: Ti.UI.FILL }
|
|
440
|
+
"#listView": { width: Ti.UI.FILL, height: Ti.UI.FILL }
|
|
441
|
+
"#contactRow": { layout: 'horizontal', height: 64, width: Ti.UI.FILL, backgroundColor: '#fff' }
|
|
442
|
+
"#contactAvatar": { left: 16, width: 36, height: 36 }
|
|
443
|
+
"#contactInfo": { layout: 'vertical', left: 12 }
|
|
444
|
+
"#contactName": { font: { fontSize: 16, fontWeight: 'semibold' } }
|
|
445
|
+
"#contactPhone": { font: { fontSize: 14 }, color: '#6b7280' }
|
|
446
|
+
```
|
|
447
|
+
|
|
438
448
|
```javascript
|
|
439
449
|
// controllers/contacts/list.js
|
|
440
450
|
let allContacts = []
|
|
@@ -494,7 +504,7 @@ $.cleanup = cleanup
|
|
|
494
504
|
## Pull-to-Refresh Pattern
|
|
495
505
|
|
|
496
506
|
```xml
|
|
497
|
-
<ListView id="listView"
|
|
507
|
+
<ListView id="listView">
|
|
498
508
|
<RefreshControl id="refreshControl" onRefresh="onRefresh" />
|
|
499
509
|
<ListSection id="section" />
|
|
500
510
|
</ListView>
|