@maccesar/titools 2.0.7 → 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.
Files changed (132) hide show
  1. package/{AGENTS-TEMPLATE.md → AGENTS-VERCEL-RESEARCH.md} +16 -18
  2. package/README.md +250 -168
  3. package/agents/{ti-researcher.md → ti-pro.md} +10 -10
  4. package/bin/titools.js +16 -12
  5. package/lib/cleanup.js +95 -0
  6. package/lib/commands/agents.js +146 -70
  7. package/lib/commands/skills.js +349 -0
  8. package/lib/commands/uninstall.js +189 -154
  9. package/lib/commands/update.js +104 -21
  10. package/lib/config.js +26 -20
  11. package/lib/downloader.js +1 -1
  12. package/lib/installer.js +37 -97
  13. package/lib/platform.js +9 -5
  14. package/lib/prompts/checkboxCancel.js +264 -0
  15. package/lib/prompts/selectCancel.js +204 -0
  16. package/lib/symlink.js +19 -7
  17. package/lib/utils.js +17 -17
  18. package/package.json +10 -10
  19. package/skills/alloy-guides/SKILL.md +8 -30
  20. package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
  21. package/skills/alloy-guides/references/CONCEPTS.md +5 -25
  22. package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
  23. package/skills/alloy-guides/references/MODELS.md +40 -10
  24. package/skills/alloy-guides/references/PURGETSS.md +1 -11
  25. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
  26. package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
  27. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
  28. package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
  29. package/skills/alloy-guides/references/WIDGETS.md +1 -17
  30. package/skills/alloy-howtos/SKILL.md +1 -22
  31. package/skills/alloy-howtos/references/best_practices.md +0 -17
  32. package/skills/alloy-howtos/references/cli_reference.md +1 -23
  33. package/skills/alloy-howtos/references/config_files.md +86 -15
  34. package/skills/alloy-howtos/references/custom_tags.md +14 -13
  35. package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
  36. package/skills/alloy-howtos/references/samples.md +4 -14
  37. package/skills/purgetss/SKILL.md +11 -37
  38. package/skills/purgetss/references/EXAMPLES.md +106 -17
  39. package/skills/purgetss/references/animation-system.md +0 -67
  40. package/skills/purgetss/references/apply-directive.md +0 -18
  41. package/skills/purgetss/references/arbitrary-values.md +0 -25
  42. package/skills/purgetss/references/class-index.md +0 -46
  43. package/skills/purgetss/references/cli-commands.md +0 -41
  44. package/skills/purgetss/references/configurable-properties.md +0 -55
  45. package/skills/purgetss/references/custom-rules.md +0 -14
  46. package/skills/purgetss/references/customization-deep-dive.md +0 -49
  47. package/skills/purgetss/references/dynamic-component-creation.md +56 -37
  48. package/skills/purgetss/references/grid-layout.md +0 -32
  49. package/skills/purgetss/references/icon-fonts.md +0 -50
  50. package/skills/purgetss/references/installation-setup.md +61 -32
  51. package/skills/purgetss/references/migration-guide.md +127 -0
  52. package/skills/purgetss/references/opacity-modifier.md +0 -34
  53. package/skills/purgetss/references/performance-tips.md +261 -0
  54. package/skills/purgetss/references/platform-modifiers.md +0 -46
  55. package/skills/purgetss/references/smart-mappings.md +0 -12
  56. package/skills/purgetss/references/tikit-components.md +393 -0
  57. package/skills/purgetss/references/titanium-resets.md +1 -27
  58. package/skills/purgetss/references/ui-ux-design.md +467 -117
  59. package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
  60. package/skills/ti-expert/references/alloy-builtins.md +387 -0
  61. package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
  62. package/skills/ti-expert/references/anti-patterns.md +90 -0
  63. package/skills/ti-expert/references/cli-expert.md +109 -0
  64. package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
  65. package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
  66. package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
  67. package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
  68. package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
  69. package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
  70. package/skills/ti-expert/references/performance-listview.md +251 -0
  71. package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
  72. package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
  73. package/skills/ti-expert/references/security-fundamentals.md +284 -0
  74. package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
  75. package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
  76. package/skills/ti-expert/references/testing-unit.md +433 -0
  77. package/skills/ti-expert/references/theming.md +394 -0
  78. package/skills/ti-guides/SKILL.md +1 -14
  79. package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
  80. package/skills/ti-guides/references/app-distribution.md +48 -10
  81. package/skills/ti-guides/references/application-frameworks.md +9 -2
  82. package/skills/ti-guides/references/cli-reference.md +338 -82
  83. package/skills/ti-guides/references/coding-best-practices.md +14 -4
  84. package/skills/ti-guides/references/commonjs-advanced.md +103 -6
  85. package/skills/ti-guides/references/hello-world.md +5 -2
  86. package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
  87. package/skills/ti-guides/references/javascript-primer.md +4 -3
  88. package/skills/ti-guides/references/resources.md +0 -1
  89. package/skills/ti-guides/references/style-and-conventions.md +57 -9
  90. package/skills/ti-guides/references/tiapp-config.md +48 -6
  91. package/skills/ti-howtos/SKILL.md +2 -27
  92. package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
  93. package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
  94. package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
  95. package/skills/ti-howtos/references/cross-platform-development.md +68 -37
  96. package/skills/ti-howtos/references/debugging-profiling.md +8 -53
  97. package/skills/ti-howtos/references/extending-titanium.md +12 -51
  98. package/skills/ti-howtos/references/google-maps-v2.md +30 -29
  99. package/skills/ti-howtos/references/ios-map-kit.md +19 -25
  100. package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
  101. package/skills/ti-howtos/references/local-data-sources.md +45 -37
  102. package/skills/ti-howtos/references/location-and-maps.md +47 -28
  103. package/skills/ti-howtos/references/media-apis.md +84 -27
  104. package/skills/ti-howtos/references/notification-services.md +40 -89
  105. package/skills/ti-howtos/references/remote-data-sources.md +21 -36
  106. package/skills/ti-howtos/references/tutorials.md +79 -39
  107. package/skills/ti-howtos/references/using-modules.md +4 -30
  108. package/skills/ti-howtos/references/web-content-integration.md +28 -45
  109. package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
  110. package/skills/ti-ui/SKILL.md +1 -21
  111. package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
  112. package/skills/ti-ui/references/animation-and-matrices.md +0 -47
  113. package/skills/ti-ui/references/application-structures.md +0 -46
  114. package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
  115. package/skills/ti-ui/references/event-handling.md +32 -40
  116. package/skills/ti-ui/references/gestures.md +0 -40
  117. package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
  118. package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
  119. package/skills/ti-ui/references/listviews-and-performance.md +187 -73
  120. package/skills/ti-ui/references/orientation.md +57 -71
  121. package/skills/ti-ui/references/platform-ui-android.md +114 -48
  122. package/skills/ti-ui/references/platform-ui-ios.md +63 -38
  123. package/skills/ti-ui/references/scrolling-views.md +14 -23
  124. package/skills/ti-ui/references/tableviews.md +6 -56
  125. package/lib/commands/install.js +0 -188
  126. package/skills/alloy-expert/references/anti-patterns.md +0 -133
  127. package/skills/alloy-expert/references/testing.md +0 -872
  128. package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
  129. package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
  130. package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
  131. /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
  132. /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
@@ -2,123 +2,6 @@
2
2
 
3
3
  A comprehensive guide to building beautiful, accessible, and performant mobile UIs using Titanium SDK and PurgeTSS utility classes.
4
4
 
5
- ## Table of Contents
6
-
7
- - [UI/UX Design Patterns for Titanium SDK with PurgeTSS](#uiux-design-patterns-for-titanium-sdk-with-purgetss)
8
- - [Table of Contents](#table-of-contents)
9
- - [1. Common UI Components](#1-common-ui-components)
10
- - [Cards](#cards)
11
- - [Elevated Card](#elevated-card)
12
- - [Outlined Card](#outlined-card)
13
- - [Card with Image Overlay](#card-with-image-overlay)
14
- - [Horizontal Card](#horizontal-card)
15
- - [Lists](#lists)
16
- - [Simple List Item](#simple-list-item)
17
- - [List with Avatar](#list-with-avatar)
18
- - [List with Actions](#list-with-actions)
19
- - [List with Dividers](#list-with-dividers)
20
- - [ListView with Custom Template](#listview-with-custom-template)
21
- - [Forms](#forms)
22
- - [Text Input](#text-input)
23
- - [Text Area](#text-area)
24
- - [Password Input](#password-input)
25
- - [Select/Dropdown (using Picker)](#selectdropdown-using-picker)
26
- - [Switch Toggle](#switch-toggle)
27
- - [Slider](#slider)
28
- - [Form with Validation States](#form-with-validation-states)
29
- - [Form Section](#form-section)
30
- - [Buttons](#buttons)
31
- - [Primary Button](#primary-button)
32
- - [Secondary Button](#secondary-button)
33
- - [Outline Button](#outline-button)
34
- - [Text Button](#text-button)
35
- - [Icon Button](#icon-button)
36
- - [Floating Action Button (FAB)](#floating-action-button-fab)
37
- - [Button with Icon](#button-with-icon)
38
- - [Button Group](#button-group)
39
- - [Button Sizes](#button-sizes)
40
- - [Navigation Bars](#navigation-bars)
41
- - [Top Navigation Bar with Title](#top-navigation-bar-with-title)
42
- - [Navigation Bar with Actions](#navigation-bar-with-actions)
43
- - [Tab Bar (Bottom)](#tab-bar-bottom)
44
- - [Segment Control](#segment-control)
45
- - [Breadcrumb Navigation](#breadcrumb-navigation)
46
- - [Modals and Dialogs](#modals-and-dialogs)
47
- - [Alert Dialog](#alert-dialog)
48
- - [Full Screen Modal (iOS)](#full-screen-modal-ios)
49
- - [Bottom Sheet (Android-style)](#bottom-sheet-android-style)
50
- - [Toasts and Snackbars](#toasts-and-snackbars)
51
- - [Simple Toast](#simple-toast)
52
- - [Custom Snackbar](#custom-snackbar)
53
- - [Success Toast](#success-toast)
54
- - [Error Toast](#error-toast)
55
- - [2. Layout Patterns](#2-layout-patterns)
56
- - [Screen Structure](#screen-structure)
57
- - [Standard Screen Layout](#standard-screen-layout)
58
- - [Tab Bar Screen Structure](#tab-bar-screen-structure)
59
- - [Spacing System](#spacing-system)
60
- - [Margin Examples](#margin-examples)
61
- - [Padding Examples](#padding-examples)
62
- - [Gap (Spacing between children)](#gap-spacing-between-children)
63
- - [Responsive Patterns](#responsive-patterns)
64
- - [Responsive Grid](#responsive-grid)
65
- - [Adaptive Layout (Tablet vs Phone)](#adaptive-layout-tablet-vs-phone)
66
- - [Percentage-Based Widths](#percentage-based-widths)
67
- - [3. Typography](#3-typography)
68
- - [Font Scales](#font-scales)
69
- - [Typography Examples](#typography-examples)
70
- - [Font Weights](#font-weights)
71
- - [Text Alignment and Truncation](#text-alignment-and-truncation)
72
- - [Text Alignment](#text-alignment)
73
- - [Text Truncation](#text-truncation)
74
- - [Text Transformations](#text-transformations)
75
- - [4. Colors and Themes](#4-colors-and-themes)
76
- - [Semantic Color Naming](#semantic-color-naming)
77
- - [Primary Colors](#primary-colors)
78
- - [Semantic Colors](#semantic-colors)
79
- - [Dark Mode Considerations](#dark-mode-considerations)
80
- - [Platform-Specific Colors](#platform-specific-colors)
81
- - [iOS System Colors](#ios-system-colors)
82
- - [Material Design Colors](#material-design-colors)
83
- - [5. Icons](#5-icons)
84
- - [Font Awesome 7 Icon Fonts](#font-awesome-7-icon-fonts)
85
- - [Icon Sizing and Alignment](#icon-sizing-and-alignment)
86
- - [Icon Sizes](#icon-sizes)
87
- - [Icon Colors](#icon-colors)
88
- - [Icon with Text Patterns](#icon-with-text-patterns)
89
- - [Icon with Label](#icon-with-label)
90
- - [Circular Icon Button](#circular-icon-button)
91
- - [Header with Icon Buttons](#header-with-icon-buttons)
92
- - [Icon Badge](#icon-badge)
93
- - [Icon Group](#icon-group)
94
- - [6. Accessibility](#6-accessibility)
95
- - [Accessibility Labels](#accessibility-labels)
96
- - [Touch Target Sizes](#touch-target-sizes)
97
- - [Color Contrast](#color-contrast)
98
- - [Screen Reader Support](#screen-reader-support)
99
- - [7. Performance Best Practices](#7-performance-best-practices)
100
- - [ListView Performance](#listview-performance)
101
- - [View Recycling](#view-recycling)
102
- - [Batch Updates](#batch-updates)
103
- - [Minimize Template Count](#minimize-template-count)
104
- - [8. Platform-Specific Patterns](#8-platform-specific-patterns)
105
- - [iOS Patterns](#ios-patterns)
106
- - [Navigation Window](#navigation-window)
107
- - [Tab Bar](#tab-bar)
108
- - [iOS Swipe Actions](#ios-swipe-actions)
109
- - [Android Patterns](#android-patterns)
110
- - [Action Bar](#action-bar)
111
- - [Back Button Handling](#back-button-handling)
112
- - [Material Design Theme](#material-design-theme)
113
- - [Notifications](#notifications)
114
- - [Quick Reference Card](#quick-reference-card)
115
- - [Common PurgeTSS Classes](#common-purgetss-classes)
116
- - [Platform Modifiers](#platform-modifiers)
117
- - [Best Practices Summary](#best-practices-summary)
118
- - [Additional Resources](#additional-resources)
119
-
120
- ---
121
-
122
5
  ## 1. Common UI Components
123
6
 
124
7
  ### Cards
@@ -1468,6 +1351,473 @@ Ti.Android.NotificationManager.notify(1, notification)
1468
1351
 
1469
1352
  ---
1470
1353
 
1354
+ ## 8. Complete UI Patterns with Controllers
1355
+
1356
+ These patterns demonstrate real-world UI implementations with both XML views and their corresponding controller JavaScript code.
1357
+
1358
+ ### Loading State Pattern (Skeleton)
1359
+
1360
+ Show skeleton screens while loading data, then transition to content or error states.
1361
+
1362
+ ```xml
1363
+ <View id="loadingState" class="wh-screen vertical">
1364
+ <View class="mx-4 mt-4 h-20 w-screen animate-pulse rounded-lg bg-gray-200" />
1365
+ <View class="mx-4 mt-4 h-4 w-8/12 animate-pulse rounded bg-gray-200" />
1366
+ <View class="mx-4 mt-2 h-4 w-6/12 animate-pulse rounded bg-gray-200" />
1367
+ </View>
1368
+
1369
+ <View id="contentState" class="wh-screen hidden">
1370
+ <!-- Actual content goes here -->
1371
+ <Label class="mx-4 my-4 text-lg font-semibold text-gray-800" text="Content loaded!" />
1372
+ </View>
1373
+
1374
+ <View id="errorState" class="wh-screen vertical hidden">
1375
+ <Label class="fa-solid fa-exclamation-circle mt-20 text-6xl text-gray-400" />
1376
+ <Label class="mt-4 text-lg text-gray-500" text="L('error_loading')" />
1377
+ <Button class="bg-primary mt-4 h-10 rounded-lg px-6 text-white" title="L('retry')" onClick="loadData" />
1378
+ </View>
1379
+ ```
1380
+
1381
+ ```javascript
1382
+ // Controller
1383
+ function setState(state) {
1384
+ const states = ['loadingState', 'contentState', 'errorState']
1385
+ states.forEach(s => { $[s].visible = s === state })
1386
+ }
1387
+
1388
+ async function loadData() {
1389
+ setState('loadingState')
1390
+ try {
1391
+ const data = await api.fetchData()
1392
+ renderContent(data)
1393
+ setState('contentState')
1394
+ } catch (error) {
1395
+ setState('errorState')
1396
+ }
1397
+ }
1398
+
1399
+ // Initial load
1400
+ loadData()
1401
+ ```
1402
+
1403
+ ### Pull-to-Refresh Pattern
1404
+
1405
+ Enable users to refresh content by pulling down on a ListView.
1406
+
1407
+ ```xml
1408
+ <ListView id="listView" class="wh-screen">
1409
+ <RefreshControl id="refreshControl" onRefresh="onRefresh" />
1410
+ <ListSection id="section" />
1411
+ </ListView>
1412
+ ```
1413
+
1414
+ ```javascript
1415
+ // Controller
1416
+ let isRefreshing = false
1417
+
1418
+ async function onRefresh() {
1419
+ if (isRefreshing) return
1420
+ isRefreshing = true
1421
+ try {
1422
+ const data = await api.fetchLatest()
1423
+ renderItems(data)
1424
+ } catch (error) {
1425
+ showError(error.message)
1426
+ } finally {
1427
+ $.refreshControl.endRefreshing()
1428
+ isRefreshing = false
1429
+ }
1430
+ }
1431
+
1432
+ function renderItems(data) {
1433
+ const items = data.map(item => ({
1434
+ properties: { itemId: item.id },
1435
+ title: { text: item.name }
1436
+ }))
1437
+ $.section.setItems(items)
1438
+ }
1439
+ ```
1440
+
1441
+ ### SearchBar with ListView
1442
+
1443
+ Implement debounced search with real-time filtering.
1444
+
1445
+ ```xml
1446
+ <Window class="bg-gray-50">
1447
+ <SearchBar id="searchBar" class="w-screen" hintText="L('search_contacts')" showCancel="true" onChange="onSearchChange" onCancel="onSearchCancel" />
1448
+ <ListView id="listView" class="wh-screen" top="50">
1449
+ <Templates>
1450
+ <ItemTemplate name="contact" height="64">
1451
+ <View class="horizontal h-16 w-screen bg-white">
1452
+ <Label bindId="avatar" class="fa-solid fa-user-circle ml-4 text-3xl text-gray-400" />
1453
+ <View class="vertical ml-3">
1454
+ <Label bindId="name" class="text-base font-semibold" />
1455
+ <Label bindId="phone" class="text-sm text-gray-500" />
1456
+ </View>
1457
+ </View>
1458
+ </ItemTemplate>
1459
+ </Templates>
1460
+ <ListSection id="section" />
1461
+ </ListView>
1462
+ </Window>
1463
+ ```
1464
+
1465
+ ```javascript
1466
+ // Controller
1467
+ let allContacts = []
1468
+ let searchTimeout = null
1469
+
1470
+ function onSearchChange(e) {
1471
+ clearTimeout(searchTimeout)
1472
+ searchTimeout = setTimeout(() => {
1473
+ filterContacts(e.value)
1474
+ }, 300)
1475
+ }
1476
+
1477
+ function onSearchCancel() {
1478
+ $.searchBar.value = ''
1479
+ filterContacts('')
1480
+ }
1481
+
1482
+ function filterContacts(query) {
1483
+ const q = query.toLowerCase().trim()
1484
+ const filtered = q
1485
+ ? allContacts.filter(c => c.name.toLowerCase().includes(q) || c.phone.includes(q))
1486
+ : allContacts
1487
+ renderContacts(filtered)
1488
+ }
1489
+
1490
+ function renderContacts(contacts) {
1491
+ $.section.items = contacts.map(c => ({
1492
+ template: 'contact',
1493
+ properties: { itemId: c.id },
1494
+ name: { text: c.name },
1495
+ phone: { text: c.phone }
1496
+ }))
1497
+ }
1498
+
1499
+ function cleanup() {
1500
+ clearTimeout(searchTimeout)
1501
+ $.destroy()
1502
+ }
1503
+
1504
+ $.cleanup = cleanup
1505
+
1506
+ // Load initial data
1507
+ async function loadContacts() {
1508
+ try {
1509
+ allContacts = await api.fetchContacts()
1510
+ renderContacts(allContacts)
1511
+ } catch (error) {
1512
+ Ti.UI.createAlertDialog({
1513
+ title: L('error'),
1514
+ message: error.message
1515
+ }).show()
1516
+ }
1517
+ }
1518
+
1519
+ loadContacts()
1520
+ ```
1521
+
1522
+ ### Complete CRUD with ListView
1523
+
1524
+ Full product list with create, read, update, and delete operations.
1525
+
1526
+ ```xml
1527
+ <Window class="bg-gray-50">
1528
+ <ListView id="listView" class="wh-screen">
1529
+ <RefreshControl id="refresh" onRefresh="onRefresh" />
1530
+ <Templates>
1531
+ <ItemTemplate name="product" height="80">
1532
+ <View class="horizontal mb-2 h-20 w-screen bg-white">
1533
+ <ImageView bindId="image" class="wh-16 ml-3 rounded-lg" />
1534
+ <View class="vertical ml-3 w-auto">
1535
+ <Label bindId="name" class="text-base font-semibold" />
1536
+ <Label bindId="price" class="text-sm text-green-600" />
1537
+ <Label bindId="stock" class="text-xs text-gray-400" />
1538
+ </View>
1539
+ </View>
1540
+ </ItemTemplate>
1541
+ </Templates>
1542
+ <ListSection id="section" dataCollection="products">
1543
+ <ListItem template="product" image:image="{imageUrl}" name:text="{name}" price:text="${price}" stock:text="{stock} in stock" />
1544
+ </ListSection>
1545
+ </ListView>
1546
+
1547
+ <Button id="addBtn" class="bg-primary rounded-full-14 absolute bottom-6 right-6 shadow-lg" onClick="onAddProduct">
1548
+ <Label class="fa-solid fa-plus text-xl text-white" />
1549
+ </Button>
1550
+ </Window>
1551
+ ```
1552
+
1553
+ ```javascript
1554
+ // Controller
1555
+ const productService = require('/services/productService')
1556
+
1557
+ // Handle item click
1558
+ function onItemClick(e) {
1559
+ const item = e.section.getItemAt(e.itemIndex)
1560
+ const productId = item.properties.itemId
1561
+
1562
+ const detailWin = Alloy.createController('productDetail', { id: productId }).getView()
1563
+ detailWin.open()
1564
+ }
1565
+
1566
+ // Refresh data
1567
+ async function onRefresh() {
1568
+ try {
1569
+ const products = await productService.fetchAll()
1570
+ Alloy.Collections.products.reset(products)
1571
+ } catch (error) {
1572
+ showError(error.message)
1573
+ } finally {
1574
+ $.refresh.endRefreshing()
1575
+ }
1576
+ }
1577
+
1578
+ // Add new product
1579
+ function onAddProduct() {
1580
+ const formWin = Alloy.createController('productForm', { mode: 'create' }).getView()
1581
+ formWin.open({ modal: true })
1582
+ }
1583
+
1584
+ // Show error message
1585
+ function showError(message) {
1586
+ Ti.UI.createAlertDialog({
1587
+ title: L('error'),
1588
+ message: message
1589
+ }).show()
1590
+ }
1591
+
1592
+ // Event listeners
1593
+ $.listView.addEventListener('itemclick', onItemClick)
1594
+
1595
+ // Cleanup
1596
+ function cleanup() {
1597
+ $.listView.removeEventListener('itemclick', onItemClick)
1598
+ $.destroy()
1599
+ }
1600
+
1601
+ $.cleanup = cleanup
1602
+
1603
+ // Load initial data
1604
+ onRefresh()
1605
+ ```
1606
+
1607
+ ### Form with Real-Time Validation
1608
+
1609
+ Registration form with field-level validation and error feedback.
1610
+
1611
+ ```xml
1612
+ <Window class="bg-gray-50">
1613
+ <ScrollView class="wh-screen">
1614
+ <View class="vertical">
1615
+ <Label class="mx-4 mb-6 mt-6 text-2xl font-bold text-gray-800" text="L('create_account')" />
1616
+
1617
+ <!-- Name Field -->
1618
+ <View class="mb-4">
1619
+ <Label id="nameLabel" class="mx-4 mb-2 text-sm font-medium text-gray-700" text="L('full_name')" />
1620
+ <TextField id="nameField" class="border-(1) return-key-type-next mx-4 mt-1 h-12 w-screen rounded-lg border-gray-300 px-3" hintText="L('enter_name')" onChange="validateName" />
1621
+ <Label id="nameError" class="mx-4 mt-1 hidden text-xs text-red-500" />
1622
+ </View>
1623
+
1624
+ <!-- Email Field -->
1625
+ <View class="mb-4">
1626
+ <Label id="emailLabel" class="mx-4 mb-2 text-sm font-medium text-gray-700" text="L('email')" />
1627
+ <TextField id="emailField" class="border-(1) return-key-type-next mx-4 mt-1 h-12 w-screen rounded-lg border-gray-300 px-3" keyboardType="Ti.UI.KEYBOARD_TYPE_EMAIL" autocapitalization="Ti.UI.TEXT_AUTOCAPITALIZATION_NONE" hintText="L('enter_email')" onChange="validateEmail" />
1628
+ <Label id="emailError" class="mx-4 mt-1 hidden text-xs text-red-500" />
1629
+ </View>
1630
+
1631
+ <!-- Password Field -->
1632
+ <View class="mb-4">
1633
+ <Label id="passwordLabel" class="mx-4 mb-2 text-sm font-medium text-gray-700" text="L('password')" />
1634
+ <TextField id="passwordField" class="border-(1) return-key-type-done mx-4 mt-1 h-12 w-screen rounded-lg border-gray-300 px-3" passwordMask="true" hintText="L('enter_password')" onChange="validatePassword" />
1635
+ <Label id="passwordError" class="mx-4 mt-1 hidden text-xs text-red-500" />
1636
+ </View>
1637
+
1638
+ <!-- Terms Switch -->
1639
+ <View class="horizontal mx-4 mb-6">
1640
+ <Switch id="termsSwitch" onChange="validateTerms" />
1641
+ <Label class="ml-3 text-sm text-gray-700" text="L('agree_to_terms')" />
1642
+ </View>
1643
+
1644
+ <!-- Submit Button -->
1645
+ <Button id="submitBtn" class="bg-primary mx-4 h-12 rounded-lg text-base font-semibold text-white" title="L('create_account')" onClick="onSubmit" enabled="false" />
1646
+ </View>
1647
+ </ScrollView>
1648
+ </Window>
1649
+ ```
1650
+
1651
+ ```javascript
1652
+ // Controller
1653
+ const validationState = {
1654
+ name: false,
1655
+ email: false,
1656
+ password: false,
1657
+ terms: false
1658
+ }
1659
+
1660
+ function validateName(e) {
1661
+ const value = e.value.trim()
1662
+ const isValid = value.length >= 2
1663
+
1664
+ if (!isValid && value.length > 0) {
1665
+ $.nameError.text = L('name_too_short')
1666
+ $.nameError.visible = true
1667
+ $.nameField.borderColor = '#EF4444'
1668
+ $.nameLabel.color = '#EF4444'
1669
+ } else {
1670
+ $.nameError.visible = false
1671
+ $.nameField.borderColor = isValid ? '#10B981' : '#D1D5DB'
1672
+ $.nameLabel.color = isValid ? '#10B981' : '#374151'
1673
+ }
1674
+
1675
+ validationState.name = isValid
1676
+ updateSubmitButton()
1677
+ }
1678
+
1679
+ function validateEmail(e) {
1680
+ const value = e.value.trim()
1681
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
1682
+ const isValid = emailRegex.test(value)
1683
+
1684
+ if (!isValid && value.length > 0) {
1685
+ $.emailError.text = L('invalid_email')
1686
+ $.emailError.visible = true
1687
+ $.emailField.borderColor = '#EF4444'
1688
+ $.emailLabel.color = '#EF4444'
1689
+ } else {
1690
+ $.emailError.visible = false
1691
+ $.emailField.borderColor = isValid ? '#10B981' : '#D1D5DB'
1692
+ $.emailLabel.color = isValid ? '#10B981' : '#374151'
1693
+ }
1694
+
1695
+ validationState.email = isValid
1696
+ updateSubmitButton()
1697
+ }
1698
+
1699
+ function validatePassword(e) {
1700
+ const value = e.value
1701
+ const isValid = value.length >= 8
1702
+
1703
+ if (!isValid && value.length > 0) {
1704
+ $.passwordError.text = L('password_too_short')
1705
+ $.passwordError.visible = true
1706
+ $.passwordField.borderColor = '#EF4444'
1707
+ $.passwordLabel.color = '#EF4444'
1708
+ } else {
1709
+ $.passwordError.visible = false
1710
+ $.passwordField.borderColor = isValid ? '#10B981' : '#D1D5DB'
1711
+ $.passwordLabel.color = isValid ? '#10B981' : '#374151'
1712
+ }
1713
+
1714
+ validationState.password = isValid
1715
+ updateSubmitButton()
1716
+ }
1717
+
1718
+ function validateTerms(e) {
1719
+ validationState.terms = e.value
1720
+ updateSubmitButton()
1721
+ }
1722
+
1723
+ function updateSubmitButton() {
1724
+ const allValid = Object.values(validationState).every(v => v === true)
1725
+ $.submitBtn.enabled = allValid
1726
+ $.submitBtn.opacity = allValid ? 1.0 : 0.5
1727
+ }
1728
+
1729
+ async function onSubmit() {
1730
+ if (!$.submitBtn.enabled) return
1731
+
1732
+ $.submitBtn.enabled = false
1733
+ $.submitBtn.title = L('creating_account')
1734
+
1735
+ try {
1736
+ const userData = {
1737
+ name: $.nameField.value.trim(),
1738
+ email: $.emailField.value.trim(),
1739
+ password: $.passwordField.value
1740
+ }
1741
+
1742
+ await api.createAccount(userData)
1743
+
1744
+ Ti.UI.createAlertDialog({
1745
+ title: L('success'),
1746
+ message: L('account_created')
1747
+ }).show()
1748
+
1749
+ $.getView().close()
1750
+ } catch (error) {
1751
+ Ti.UI.createAlertDialog({
1752
+ title: L('error'),
1753
+ message: error.message
1754
+ }).show()
1755
+ $.submitBtn.enabled = true
1756
+ $.submitBtn.title = L('create_account')
1757
+ }
1758
+ }
1759
+ ```
1760
+
1761
+ ### TabGroup Pattern
1762
+
1763
+ Standard tab-based navigation with separate screens.
1764
+
1765
+ ```xml
1766
+ <!-- index.xml -->
1767
+ <TabGroup id="tabGroup" class="tabs-bg-white active-tint-blue-500">
1768
+ <Tab title="L('home')" icon="/images/icons/home.png">
1769
+ <Require src="tabs/home" />
1770
+ </Tab>
1771
+
1772
+ <Tab title="L('search')" icon="/images/icons/search.png">
1773
+ <Require src="tabs/search" />
1774
+ </Tab>
1775
+
1776
+ <Tab title="L('favorites')" icon="/images/icons/heart.png">
1777
+ <Require src="tabs/favorites" />
1778
+ </Tab>
1779
+
1780
+ <Tab title="L('profile')" icon="/images/icons/user.png">
1781
+ <Require src="tabs/profile" />
1782
+ </Tab>
1783
+ </TabGroup>
1784
+ ```
1785
+
1786
+ ```javascript
1787
+ // index.js
1788
+ $.tabGroup.open()
1789
+
1790
+ function cleanup() {
1791
+ $.destroy()
1792
+ }
1793
+
1794
+ $.cleanup = cleanup
1795
+ ```
1796
+
1797
+ ```xml
1798
+ <!-- tabs/home.xml -->
1799
+ <Window class="bg-gray-50">
1800
+ <ScrollView class="wh-screen">
1801
+ <View class="vertical">
1802
+ <Label class="mx-4 my-4 text-2xl font-bold text-gray-800" text="L('home')" />
1803
+ <!-- Home content -->
1804
+ </View>
1805
+ </ScrollView>
1806
+ </Window>
1807
+ ```
1808
+
1809
+ ```xml
1810
+ <!-- tabs/search.xml -->
1811
+ <Window class="bg-gray-50">
1812
+ <SearchBar id="searchBar" class="w-screen" hintText="L('search')" />
1813
+ <ListView id="results" class="wh-screen" top="50">
1814
+ <ListSection id="section" />
1815
+ </ListView>
1816
+ </Window>
1817
+ ```
1818
+
1819
+ ---
1820
+
1471
1821
  ## Quick Reference Card
1472
1822
 
1473
1823
  ### Common PurgeTSS Classes