@codyswann/lisa 2.110.1 → 2.112.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 (193) hide show
  1. package/package.json +1 -1
  2. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  3. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  4. package/plugins/lisa/commands/repair-intake.md +2 -2
  5. package/plugins/lisa/rules/config-resolution.md +2 -2
  6. package/plugins/lisa/skills/repair-intake/SKILL.md +86 -9
  7. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  8. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  9. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa-expo/.mcp.json +3 -3
  12. package/plugins/lisa-expo/THIRD-PARTY-NOTICES.md +57 -0
  13. package/plugins/lisa-expo/commands/e2e-coverage-gaps.md +7 -0
  14. package/plugins/lisa-expo/commands/exploratory-qa.md +2 -2
  15. package/plugins/lisa-expo/skills/add-app-clip/SKILL.md +280 -0
  16. package/plugins/lisa-expo/skills/add-app-clip/agents/openai.yaml +4 -0
  17. package/plugins/lisa-expo/skills/add-app-clip/references/native-module.md +96 -0
  18. package/plugins/lisa-expo/skills/building-native-ui/SKILL.md +321 -0
  19. package/plugins/lisa-expo/skills/building-native-ui/agents/openai.yaml +4 -0
  20. package/plugins/lisa-expo/skills/building-native-ui/references/animations.md +220 -0
  21. package/plugins/lisa-expo/skills/building-native-ui/references/controls.md +272 -0
  22. package/plugins/lisa-expo/skills/building-native-ui/references/form-sheet.md +253 -0
  23. package/plugins/lisa-expo/skills/building-native-ui/references/gradients.md +106 -0
  24. package/plugins/lisa-expo/skills/building-native-ui/references/icons.md +213 -0
  25. package/plugins/lisa-expo/skills/building-native-ui/references/media.md +198 -0
  26. package/plugins/lisa-expo/skills/building-native-ui/references/route-structure.md +229 -0
  27. package/plugins/lisa-expo/skills/building-native-ui/references/search.md +248 -0
  28. package/plugins/lisa-expo/skills/building-native-ui/references/storage.md +121 -0
  29. package/plugins/lisa-expo/skills/building-native-ui/references/tabs.md +433 -0
  30. package/plugins/lisa-expo/skills/building-native-ui/references/toolbar-and-headers.md +284 -0
  31. package/plugins/lisa-expo/skills/building-native-ui/references/visual-effects.md +197 -0
  32. package/plugins/lisa-expo/skills/building-native-ui/references/webgpu-three.md +605 -0
  33. package/plugins/lisa-expo/skills/building-native-ui/references/zoom-transitions.md +158 -0
  34. package/plugins/lisa-expo/skills/e2e-coverage-gaps/SKILL.md +105 -0
  35. package/plugins/lisa-expo/skills/e2e-coverage-gaps/agents/openai.yaml +4 -0
  36. package/plugins/lisa-expo/skills/eas-update-insights/SKILL.md +228 -0
  37. package/plugins/lisa-expo/skills/eas-update-insights/agents/openai.yaml +4 -0
  38. package/plugins/lisa-expo/skills/eas-update-insights/references/channel-insights-schema.md +47 -0
  39. package/plugins/lisa-expo/skills/eas-update-insights/references/update-insights-schema.md +69 -0
  40. package/plugins/lisa-expo/skills/exploratory-qa/SKILL.md +100 -93
  41. package/plugins/lisa-expo/skills/exploratory-qa/agents/openai.yaml +2 -2
  42. package/plugins/lisa-expo/skills/expo-api-routes/SKILL.md +369 -0
  43. package/plugins/lisa-expo/skills/expo-api-routes/agents/openai.yaml +4 -0
  44. package/plugins/lisa-expo/skills/expo-brownfield/SKILL.md +54 -0
  45. package/plugins/lisa-expo/skills/expo-brownfield/agents/openai.yaml +4 -0
  46. package/plugins/lisa-expo/skills/expo-brownfield/references/brownfield-integrated.md +526 -0
  47. package/plugins/lisa-expo/skills/expo-brownfield/references/brownfield-isolated.md +402 -0
  48. package/plugins/lisa-expo/skills/expo-brownfield/references/comparison.md +63 -0
  49. package/plugins/lisa-expo/skills/expo-brownfield/references/troubleshooting.md +88 -0
  50. package/plugins/lisa-expo/skills/expo-cicd-workflows/SKILL.md +92 -0
  51. package/plugins/lisa-expo/skills/expo-cicd-workflows/agents/openai.yaml +4 -0
  52. package/plugins/lisa-expo/skills/expo-cicd-workflows/scripts/fetch.js +113 -0
  53. package/plugins/lisa-expo/skills/expo-cicd-workflows/scripts/package.json +11 -0
  54. package/plugins/lisa-expo/skills/expo-cicd-workflows/scripts/validate.js +85 -0
  55. package/plugins/lisa-expo/skills/expo-deployment/SKILL.md +190 -0
  56. package/plugins/lisa-expo/skills/expo-deployment/agents/openai.yaml +4 -0
  57. package/plugins/lisa-expo/skills/expo-deployment/references/app-store-metadata.md +479 -0
  58. package/plugins/lisa-expo/skills/expo-deployment/references/ios-app-store.md +355 -0
  59. package/plugins/lisa-expo/skills/expo-deployment/references/play-store.md +246 -0
  60. package/plugins/lisa-expo/skills/expo-deployment/references/testflight.md +58 -0
  61. package/plugins/lisa-expo/skills/expo-deployment/references/workflows.md +200 -0
  62. package/plugins/lisa-expo/skills/expo-dev-client/SKILL.md +164 -0
  63. package/plugins/lisa-expo/skills/expo-dev-client/agents/openai.yaml +4 -0
  64. package/plugins/lisa-expo/skills/expo-module/SKILL.md +141 -0
  65. package/plugins/lisa-expo/skills/expo-module/agents/openai.yaml +4 -0
  66. package/plugins/lisa-expo/skills/expo-module/references/config-plugin.md +90 -0
  67. package/plugins/lisa-expo/skills/expo-module/references/create-expo-module.md +206 -0
  68. package/plugins/lisa-expo/skills/expo-module/references/lifecycle.md +127 -0
  69. package/plugins/lisa-expo/skills/expo-module/references/module-config.md +48 -0
  70. package/plugins/lisa-expo/skills/expo-module/references/native-module.md +286 -0
  71. package/plugins/lisa-expo/skills/expo-module/references/native-view.md +171 -0
  72. package/plugins/lisa-expo/skills/expo-tailwind-setup/SKILL.md +480 -0
  73. package/plugins/lisa-expo/skills/expo-tailwind-setup/agents/openai.yaml +4 -0
  74. package/plugins/lisa-expo/skills/expo-ui-jetpack-compose/SKILL.md +40 -0
  75. package/plugins/lisa-expo/skills/expo-ui-jetpack-compose/agents/openai.yaml +4 -0
  76. package/plugins/lisa-expo/skills/expo-ui-swift-ui/SKILL.md +39 -0
  77. package/plugins/lisa-expo/skills/expo-ui-swift-ui/agents/openai.yaml +4 -0
  78. package/plugins/lisa-expo/skills/native-data-fetching/SKILL.md +507 -0
  79. package/plugins/lisa-expo/skills/native-data-fetching/agents/openai.yaml +4 -0
  80. package/plugins/lisa-expo/skills/native-data-fetching/references/expo-router-loaders.md +344 -0
  81. package/plugins/lisa-expo/skills/upgrading-expo/SKILL.md +134 -0
  82. package/plugins/lisa-expo/skills/upgrading-expo/agents/openai.yaml +4 -0
  83. package/plugins/lisa-expo/skills/upgrading-expo/references/expo-av-to-audio.md +132 -0
  84. package/plugins/lisa-expo/skills/upgrading-expo/references/expo-av-to-video.md +160 -0
  85. package/plugins/lisa-expo/skills/upgrading-expo/references/native-tabs.md +124 -0
  86. package/plugins/lisa-expo/skills/upgrading-expo/references/new-architecture.md +79 -0
  87. package/plugins/lisa-expo/skills/upgrading-expo/references/react-19.md +79 -0
  88. package/plugins/lisa-expo/skills/upgrading-expo/references/react-compiler.md +59 -0
  89. package/plugins/lisa-expo/skills/upgrading-expo/references/react-navigation-to-expo-router.md +61 -0
  90. package/plugins/lisa-expo/skills/use-dom/SKILL.md +417 -0
  91. package/plugins/lisa-expo/skills/use-dom/agents/openai.yaml +4 -0
  92. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  94. package/plugins/lisa-harper-fabric/commands/e2e-coverage-gaps.md +7 -0
  95. package/plugins/lisa-harper-fabric/commands/exploratory-qa.md +2 -2
  96. package/plugins/lisa-harper-fabric/skills/e2e-coverage-gaps/SKILL.md +105 -0
  97. package/plugins/lisa-harper-fabric/skills/e2e-coverage-gaps/agents/openai.yaml +4 -0
  98. package/plugins/lisa-harper-fabric/skills/exploratory-qa/SKILL.md +100 -93
  99. package/plugins/lisa-harper-fabric/skills/exploratory-qa/agents/openai.yaml +2 -2
  100. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  101. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  102. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  104. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  105. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  106. package/plugins/lisa-rails/commands/e2e-coverage-gaps.md +7 -0
  107. package/plugins/lisa-rails/commands/exploratory-qa.md +2 -2
  108. package/plugins/lisa-rails/skills/e2e-coverage-gaps/SKILL.md +105 -0
  109. package/plugins/lisa-rails/skills/e2e-coverage-gaps/agents/openai.yaml +4 -0
  110. package/plugins/lisa-rails/skills/exploratory-qa/SKILL.md +100 -93
  111. package/plugins/lisa-rails/skills/exploratory-qa/agents/openai.yaml +2 -2
  112. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  113. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  114. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  115. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  116. package/plugins/lisa-wiki/templates/llm-wiki-contract.md +12 -0
  117. package/plugins/src/base/commands/repair-intake.md +2 -2
  118. package/plugins/src/base/rules/config-resolution.md +2 -2
  119. package/plugins/src/base/skills/repair-intake/SKILL.md +86 -9
  120. package/plugins/src/expo/.mcp.json +3 -3
  121. package/plugins/src/expo/THIRD-PARTY-NOTICES.md +57 -0
  122. package/plugins/src/expo/commands/e2e-coverage-gaps.md +7 -0
  123. package/plugins/src/expo/commands/exploratory-qa.md +2 -2
  124. package/plugins/src/expo/skills/add-app-clip/SKILL.md +280 -0
  125. package/plugins/src/expo/skills/add-app-clip/references/native-module.md +96 -0
  126. package/plugins/src/expo/skills/building-native-ui/SKILL.md +321 -0
  127. package/plugins/src/expo/skills/building-native-ui/references/animations.md +220 -0
  128. package/plugins/src/expo/skills/building-native-ui/references/controls.md +272 -0
  129. package/plugins/src/expo/skills/building-native-ui/references/form-sheet.md +253 -0
  130. package/plugins/src/expo/skills/building-native-ui/references/gradients.md +106 -0
  131. package/plugins/src/expo/skills/building-native-ui/references/icons.md +213 -0
  132. package/plugins/src/expo/skills/building-native-ui/references/media.md +198 -0
  133. package/plugins/src/expo/skills/building-native-ui/references/route-structure.md +229 -0
  134. package/plugins/src/expo/skills/building-native-ui/references/search.md +248 -0
  135. package/plugins/src/expo/skills/building-native-ui/references/storage.md +121 -0
  136. package/plugins/src/expo/skills/building-native-ui/references/tabs.md +433 -0
  137. package/plugins/src/expo/skills/building-native-ui/references/toolbar-and-headers.md +284 -0
  138. package/plugins/src/expo/skills/building-native-ui/references/visual-effects.md +197 -0
  139. package/plugins/src/expo/skills/building-native-ui/references/webgpu-three.md +605 -0
  140. package/plugins/src/expo/skills/building-native-ui/references/zoom-transitions.md +158 -0
  141. package/plugins/src/expo/skills/e2e-coverage-gaps/SKILL.md +105 -0
  142. package/plugins/src/expo/skills/eas-update-insights/SKILL.md +228 -0
  143. package/plugins/src/expo/skills/eas-update-insights/references/channel-insights-schema.md +47 -0
  144. package/plugins/src/expo/skills/eas-update-insights/references/update-insights-schema.md +69 -0
  145. package/plugins/src/expo/skills/exploratory-qa/SKILL.md +100 -93
  146. package/plugins/src/expo/skills/expo-api-routes/SKILL.md +369 -0
  147. package/plugins/src/expo/skills/expo-brownfield/SKILL.md +54 -0
  148. package/plugins/src/expo/skills/expo-brownfield/references/brownfield-integrated.md +526 -0
  149. package/plugins/src/expo/skills/expo-brownfield/references/brownfield-isolated.md +402 -0
  150. package/plugins/src/expo/skills/expo-brownfield/references/comparison.md +63 -0
  151. package/plugins/src/expo/skills/expo-brownfield/references/troubleshooting.md +88 -0
  152. package/plugins/src/expo/skills/expo-cicd-workflows/SKILL.md +92 -0
  153. package/plugins/src/expo/skills/expo-cicd-workflows/scripts/fetch.js +113 -0
  154. package/plugins/src/expo/skills/expo-cicd-workflows/scripts/package.json +11 -0
  155. package/plugins/src/expo/skills/expo-cicd-workflows/scripts/validate.js +85 -0
  156. package/plugins/src/expo/skills/expo-deployment/SKILL.md +190 -0
  157. package/plugins/src/expo/skills/expo-deployment/references/app-store-metadata.md +479 -0
  158. package/plugins/src/expo/skills/expo-deployment/references/ios-app-store.md +355 -0
  159. package/plugins/src/expo/skills/expo-deployment/references/play-store.md +246 -0
  160. package/plugins/src/expo/skills/expo-deployment/references/testflight.md +58 -0
  161. package/plugins/src/expo/skills/expo-deployment/references/workflows.md +200 -0
  162. package/plugins/src/expo/skills/expo-dev-client/SKILL.md +164 -0
  163. package/plugins/src/expo/skills/expo-module/SKILL.md +141 -0
  164. package/plugins/src/expo/skills/expo-module/references/config-plugin.md +90 -0
  165. package/plugins/src/expo/skills/expo-module/references/create-expo-module.md +206 -0
  166. package/plugins/src/expo/skills/expo-module/references/lifecycle.md +127 -0
  167. package/plugins/src/expo/skills/expo-module/references/module-config.md +48 -0
  168. package/plugins/src/expo/skills/expo-module/references/native-module.md +286 -0
  169. package/plugins/src/expo/skills/expo-module/references/native-view.md +171 -0
  170. package/plugins/src/expo/skills/expo-tailwind-setup/SKILL.md +480 -0
  171. package/plugins/src/expo/skills/expo-ui-jetpack-compose/SKILL.md +40 -0
  172. package/plugins/src/expo/skills/expo-ui-swift-ui/SKILL.md +39 -0
  173. package/plugins/src/expo/skills/native-data-fetching/SKILL.md +507 -0
  174. package/plugins/src/expo/skills/native-data-fetching/references/expo-router-loaders.md +344 -0
  175. package/plugins/src/expo/skills/upgrading-expo/SKILL.md +134 -0
  176. package/plugins/src/expo/skills/upgrading-expo/references/expo-av-to-audio.md +132 -0
  177. package/plugins/src/expo/skills/upgrading-expo/references/expo-av-to-video.md +160 -0
  178. package/plugins/src/expo/skills/upgrading-expo/references/native-tabs.md +124 -0
  179. package/plugins/src/expo/skills/upgrading-expo/references/new-architecture.md +79 -0
  180. package/plugins/src/expo/skills/upgrading-expo/references/react-19.md +79 -0
  181. package/plugins/src/expo/skills/upgrading-expo/references/react-compiler.md +59 -0
  182. package/plugins/src/expo/skills/upgrading-expo/references/react-navigation-to-expo-router.md +61 -0
  183. package/plugins/src/expo/skills/use-dom/SKILL.md +417 -0
  184. package/plugins/src/harper-fabric/commands/e2e-coverage-gaps.md +7 -0
  185. package/plugins/src/harper-fabric/commands/exploratory-qa.md +2 -2
  186. package/plugins/src/harper-fabric/skills/e2e-coverage-gaps/SKILL.md +105 -0
  187. package/plugins/src/harper-fabric/skills/exploratory-qa/SKILL.md +100 -93
  188. package/plugins/src/rails/commands/e2e-coverage-gaps.md +7 -0
  189. package/plugins/src/rails/commands/exploratory-qa.md +2 -2
  190. package/plugins/src/rails/skills/e2e-coverage-gaps/SKILL.md +105 -0
  191. package/plugins/src/rails/skills/exploratory-qa/SKILL.md +100 -93
  192. package/plugins/src/wiki/templates/llm-wiki-contract.md +12 -0
  193. package/scripts/generate-codex-plugin-artifacts.mjs +7 -2
@@ -0,0 +1,96 @@
1
+ # Native App Clip detection
2
+
3
+ Create a local Expo module so JS can detect when the app is running inside an App Clip and present the install prompt for the full app.
4
+
5
+ ```sh
6
+ bunx create-expo-module --local
7
+ ```
8
+
9
+ ## Swift module
10
+
11
+ ```swift
12
+ import ExpoModulesCore
13
+ import StoreKit
14
+
15
+ internal class MissingCurrentWindowSceneException: Exception {
16
+ override var reason: String {
17
+ "Cannot determine the current window scene in which to present the App Clip install overlay."
18
+ }
19
+ }
20
+
21
+ internal class MissingContainerURLException: Exception {
22
+ override var reason: String {
23
+ "Cannot determine the container URL."
24
+ }
25
+ }
26
+
27
+ public class AppClipModule: Module {
28
+ private static let isAppClip: Bool = {
29
+ if let infoPlist = Bundle.main.infoDictionary, let _ = infoPlist["NSAppClip"] as? [String: Any] {
30
+ return true
31
+ }
32
+ return false
33
+ }()
34
+
35
+ public func definition() -> ModuleDefinition {
36
+ Name("AppClip")
37
+
38
+ Constant("isAppClip") {
39
+ AppClipModule.isAppClip
40
+ }
41
+
42
+ // Display overlay to advertise full app.
43
+ // https://developer.apple.com/documentation/app_clips/recommending_your_app_to_app_clip_users
44
+ AsyncFunction("prompt") {
45
+ if #available(iOS 16, *) {
46
+ guard let currentScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
47
+ throw MissingCurrentWindowSceneException()
48
+ }
49
+
50
+ let config = SKOverlay.AppClipConfiguration(position: .bottom)
51
+ let overlay = SKOverlay(configuration: config)
52
+ overlay.present(in: currentScene)
53
+ }
54
+ }.runOnQueue(DispatchQueue.main)
55
+ }
56
+ }
57
+ ```
58
+
59
+ ## TypeScript interface
60
+
61
+ ```ts
62
+ import { NativeModule, requireOptionalNativeModule } from "expo";
63
+
64
+ declare class AppClipModule extends NativeModule<{}> {
65
+ prompt(): void;
66
+ isAppClip?: boolean;
67
+ }
68
+
69
+ const AppClipNative = requireOptionalNativeModule<AppClipModule>("AppClip");
70
+
71
+ if (AppClipNative?.isAppClip) {
72
+ navigator.appClip = {
73
+ prompt: AppClipNative.prompt,
74
+ };
75
+ }
76
+
77
+ declare global {
78
+ interface Navigator {
79
+ /**
80
+ * Only available in an App Clip context.
81
+ * @expo
82
+ */
83
+ appClip?: {
84
+ /** Open the SKOverlay */
85
+ prompt: () => void;
86
+ };
87
+ }
88
+ }
89
+
90
+ export {};
91
+ ```
92
+
93
+ ## Usage
94
+
95
+ - Detect App Clip context: `if (navigator.appClip) { ... }`
96
+ - Prompt to install the full app: `navigator.appClip?.prompt()`
@@ -0,0 +1,321 @@
1
+ ---
2
+ name: building-native-ui
3
+ description: Complete guide for building beautiful apps with Expo Router. Covers fundamentals, styling, components, navigation, animations, patterns, and native tabs.
4
+ version: 1.0.1
5
+ license: MIT
6
+ ---
7
+
8
+ # Expo UI Guidelines
9
+
10
+ ## References
11
+
12
+ Consult these resources as needed:
13
+
14
+ ```
15
+ references/
16
+ animations.md Reanimated: entering, exiting, layout, scroll-driven, gestures
17
+ controls.md Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker
18
+ form-sheet.md Form sheets in expo-router: configuration, footers and background interaction.
19
+ gradients.md CSS gradients via experimental_backgroundImage (New Arch only)
20
+ icons.md SF Symbols via expo-image (sf: source), names, animations, weights
21
+ media.md Camera, audio, video, and file saving
22
+ route-structure.md Route conventions, dynamic routes, groups, folder organization
23
+ search.md Search bar with headers, useSearch hook, filtering patterns
24
+ storage.md SQLite, AsyncStorage, SecureStore
25
+ tabs.md NativeTabs, migration from JS tabs, iOS 26 features
26
+ toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only)
27
+ visual-effects.md Blur (expo-blur) and liquid glass (expo-glass-effect)
28
+ webgpu-three.md 3D graphics, games, GPU visualizations with WebGPU and Three.js
29
+ zoom-transitions.md Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+)
30
+ ```
31
+
32
+ ## Running the App
33
+
34
+ **CRITICAL: Always try Expo Go first before creating custom builds.**
35
+
36
+ Most Expo apps work in Expo Go without any custom native code. Before running `npx expo run:ios` or `npx expo run:android`:
37
+
38
+ 1. **Start with Expo Go**: Run `npx expo start` and scan the QR code with Expo Go
39
+ 2. **Check if features work**: Test your app thoroughly in Expo Go
40
+ 3. **Only create custom builds when required** - see below
41
+
42
+ ### When Custom Builds Are Required
43
+
44
+ You need `npx expo run:ios/android` or `eas build` ONLY when using:
45
+
46
+ - **Local Expo modules** (custom native code in `modules/`)
47
+ - **Apple targets** (widgets, app clips, extensions via `@bacons/apple-targets`)
48
+ - **Third-party native modules** not included in Expo Go
49
+ - **Custom native configuration** that can't be expressed in `app.json`
50
+
51
+ ### When Expo Go Works
52
+
53
+ Expo Go supports a huge range of features out of the box:
54
+
55
+ - All `expo-*` packages (camera, location, notifications, etc.)
56
+ - Expo Router navigation
57
+ - Most UI libraries (reanimated, gesture handler, etc.)
58
+ - Push notifications, deep links, and more
59
+
60
+ **If you're unsure, try Expo Go first.** Creating custom builds adds complexity, slower iteration, and requires Xcode/Android Studio setup.
61
+
62
+ ## Code Style
63
+
64
+ - Be cautious of unterminated strings. Ensure nested backticks are escaped; never forget to escape quotes correctly.
65
+ - Always use import statements at the top of the file.
66
+ - Always use kebab-case for file names, e.g. `comment-card.tsx`
67
+ - Always remove old route files when moving or restructuring navigation
68
+ - Never use special characters in file names
69
+ - Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors.
70
+
71
+ ## Routes
72
+
73
+ See `./references/route-structure.md` for detailed route conventions.
74
+
75
+ - Routes belong in the `app` directory.
76
+ - Never co-locate components, types, or utilities in the app directory. This is an anti-pattern.
77
+ - Ensure the app always has a route that matches "/", it may be inside a group route.
78
+
79
+ ## Library Preferences
80
+
81
+ - Never use modules removed from React Native such as Picker, WebView, SafeAreaView, or AsyncStorage
82
+ - Never use legacy expo-permissions
83
+ - `expo-audio` not `expo-av`
84
+ - `expo-video` not `expo-av`
85
+ - `expo-image` with `source="sf:name"` for SF Symbols, not `expo-symbols` or `@expo/vector-icons`
86
+ - `react-native-safe-area-context` not react-native SafeAreaView
87
+ - `process.env.EXPO_OS` not `Platform.OS`
88
+ - `React.use` not `React.useContext`
89
+ - `expo-image` Image component instead of intrinsic element `img`
90
+ - `expo-glass-effect` for liquid glass backdrops
91
+
92
+ ## Responsiveness
93
+
94
+ - Always wrap root component in a scroll view for responsiveness
95
+ - Use `<ScrollView contentInsetAdjustmentBehavior="automatic" />` instead of `<SafeAreaView>` for smarter safe area insets
96
+ - `contentInsetAdjustmentBehavior="automatic"` should be applied to FlatList and SectionList as well
97
+ - Use flexbox instead of Dimensions API
98
+ - ALWAYS prefer `useWindowDimensions` over `Dimensions.get()` to measure screen size
99
+
100
+ ## Behavior
101
+
102
+ - Use expo-haptics conditionally on iOS to make more delightful experiences
103
+ - Use views with built-in haptics like `<Switch />` from React Native and `@react-native-community/datetimepicker`
104
+ - When a route belongs to a Stack, its first child should almost always be a ScrollView with `contentInsetAdjustmentBehavior="automatic"` set
105
+ - When adding a `ScrollView` to the page it should almost always be the first component inside the route component
106
+ - Prefer `headerSearchBarOptions` in Stack.Screen options to add a search bar
107
+ - Use the `<Text selectable />` prop on text containing data that could be copied
108
+ - Consider formatting large numbers like 1.4M or 38k
109
+ - Never use intrinsic elements like 'img' or 'div' unless in a webview or Expo DOM component
110
+
111
+ # Styling
112
+
113
+ Follow Apple Human Interface Guidelines.
114
+
115
+ ## General Styling Rules
116
+
117
+ - Prefer flex gap over margin and padding styles
118
+ - Prefer padding over margin where possible
119
+ - Always account for safe area, either with stack headers, tabs, or ScrollView/FlatList `contentInsetAdjustmentBehavior="automatic"`
120
+ - Ensure both top and bottom safe area insets are accounted for
121
+ - Inline styles not StyleSheet.create unless reusing styles is faster
122
+ - Add entering and exiting animations for state changes
123
+ - Use `{ borderCurve: 'continuous' }` for rounded corners unless creating a capsule shape
124
+ - ALWAYS use a navigation stack title instead of a custom text element on the page
125
+ - When padding a ScrollView, use `contentContainerStyle` padding and gap instead of padding on the ScrollView itself (reduces clipping)
126
+ - CSS and Tailwind are not supported - use inline styles
127
+
128
+ ## Text Styling
129
+
130
+ - Add the `selectable` prop to every `<Text/>` element displaying important data or error messages
131
+ - Counters should use `{ fontVariant: 'tabular-nums' }` for alignment
132
+
133
+ ## Shadows
134
+
135
+ Use CSS `boxShadow` style prop. NEVER use legacy React Native shadow or elevation styles.
136
+
137
+ ```tsx
138
+ <View style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }} />
139
+ ```
140
+
141
+ 'inset' shadows are supported.
142
+
143
+ # Navigation
144
+
145
+ ## Link
146
+
147
+ Use `<Link href="/path" />` from 'expo-router' for navigation between routes.
148
+
149
+ ```tsx
150
+ import { Link } from 'expo-router';
151
+
152
+ // Basic link
153
+ <Link href="/path" />
154
+
155
+ // Wrapping custom components
156
+ <Link href="/path" asChild>
157
+ <Pressable>...</Pressable>
158
+ </Link>
159
+ ```
160
+
161
+ Whenever possible, include a `<Link.Preview>` to follow iOS conventions. Add context menus and previews frequently to enhance navigation.
162
+
163
+ ## Stack
164
+
165
+ - ALWAYS use `_layout.tsx` files to define stacks
166
+ - Use Stack from 'expo-router/stack' for native navigation stacks
167
+
168
+ ### Page Title
169
+
170
+ Set the page title in Stack.Screen options:
171
+
172
+ ```tsx
173
+ <Stack.Screen options={{ title: "Home" }} />
174
+ ```
175
+
176
+ ## Context Menus
177
+
178
+ Add long press context menus to Link components:
179
+
180
+ ```tsx
181
+ import { Link } from "expo-router";
182
+
183
+ <Link href="/settings" asChild>
184
+ <Link.Trigger>
185
+ <Pressable>
186
+ <Card />
187
+ </Pressable>
188
+ </Link.Trigger>
189
+ <Link.Menu>
190
+ <Link.MenuAction
191
+ title="Share"
192
+ icon="square.and.arrow.up"
193
+ onPress={handleSharePress}
194
+ />
195
+ <Link.MenuAction
196
+ title="Block"
197
+ icon="nosign"
198
+ destructive
199
+ onPress={handleBlockPress}
200
+ />
201
+ <Link.Menu title="More" icon="ellipsis">
202
+ <Link.MenuAction title="Copy" icon="doc.on.doc" onPress={() => {}} />
203
+ <Link.MenuAction
204
+ title="Delete"
205
+ icon="trash"
206
+ destructive
207
+ onPress={() => {}}
208
+ />
209
+ </Link.Menu>
210
+ </Link.Menu>
211
+ </Link>;
212
+ ```
213
+
214
+ ## Link Previews
215
+
216
+ Use link previews frequently to enhance navigation:
217
+
218
+ ```tsx
219
+ <Link href="/settings">
220
+ <Link.Trigger>
221
+ <Pressable>
222
+ <Card />
223
+ </Pressable>
224
+ </Link.Trigger>
225
+ <Link.Preview />
226
+ </Link>
227
+ ```
228
+
229
+ Link preview can be used with context menus.
230
+
231
+ ## Modal
232
+
233
+ Present a screen as a modal:
234
+
235
+ ```tsx
236
+ <Stack.Screen name="modal" options={{ presentation: "modal" }} />
237
+ ```
238
+
239
+ Prefer this to building a custom modal component.
240
+
241
+ ## Sheet
242
+
243
+ Present a screen as a dynamic form sheet:
244
+
245
+ ```tsx
246
+ <Stack.Screen
247
+ name="sheet"
248
+ options={{
249
+ presentation: "formSheet",
250
+ sheetGrabberVisible: true,
251
+ sheetAllowedDetents: [0.5, 1.0],
252
+ contentStyle: { backgroundColor: "transparent" },
253
+ }}
254
+ />
255
+ ```
256
+
257
+ - Using `contentStyle: { backgroundColor: "transparent" }` makes the background liquid glass on iOS 26+.
258
+
259
+ ## Common route structure
260
+
261
+ A standard app layout with tabs and stacks inside each tab:
262
+
263
+ ```
264
+ app/
265
+ _layout.tsx — <NativeTabs />
266
+ (index,search)/
267
+ _layout.tsx — <Stack />
268
+ index.tsx — Main list
269
+ search.tsx — Search view
270
+ ```
271
+
272
+ ```tsx
273
+ // app/_layout.tsx
274
+ import { NativeTabs, Icon, Label } from "expo-router/unstable-native-tabs";
275
+ import { Theme } from "../components/theme";
276
+
277
+ export default function Layout() {
278
+ return (
279
+ <Theme>
280
+ <NativeTabs>
281
+ <NativeTabs.Trigger name="(index)">
282
+ <Icon sf="list.dash" />
283
+ <Label>Items</Label>
284
+ </NativeTabs.Trigger>
285
+ <NativeTabs.Trigger name="(search)" role="search" />
286
+ </NativeTabs>
287
+ </Theme>
288
+ );
289
+ }
290
+ ```
291
+
292
+ Create a shared group route so both tabs can push common screens:
293
+
294
+ ```tsx
295
+ // app/(index,search)/_layout.tsx
296
+ import { Stack } from "expo-router/stack";
297
+ import { PlatformColor } from "react-native";
298
+
299
+ export default function Layout({ segment }) {
300
+ const screen = segment.match(/\((.*)\)/)?.[1]!;
301
+ const titles: Record<string, string> = { index: "Items", search: "Search" };
302
+
303
+ return (
304
+ <Stack
305
+ screenOptions={{
306
+ headerTransparent: true,
307
+ headerShadowVisible: false,
308
+ headerLargeTitleShadowVisible: false,
309
+ headerLargeStyle: { backgroundColor: "transparent" },
310
+ headerTitleStyle: { color: PlatformColor("label") },
311
+ headerLargeTitle: true,
312
+ headerBlurEffect: "none",
313
+ headerBackButtonDisplayMode: "minimal",
314
+ }}
315
+ >
316
+ <Stack.Screen name={screen} options={{ title: titles[screen] }} />
317
+ <Stack.Screen name="i/[id]" options={{ headerLargeTitle: false }} />
318
+ </Stack>
319
+ );
320
+ }
321
+ ```
@@ -0,0 +1,4 @@
1
+ display_name: "Building Native UI"
2
+ short_description: "Complete guide for building beautiful apps with Expo Router"
3
+ default_prompt:
4
+ - "Use $building-native-ui: Complete guide for building beautiful apps with Expo Router."
@@ -0,0 +1,220 @@
1
+ # Animations
2
+
3
+ Use Reanimated v4. Avoid React Native's built-in Animated API.
4
+
5
+ ## Entering and Exiting Animations
6
+
7
+ Use Animated.View with entering and exiting animations. Layout animations can animate state changes.
8
+
9
+ ```tsx
10
+ import Animated, {
11
+ FadeIn,
12
+ FadeOut,
13
+ LinearTransition,
14
+ } from "react-native-reanimated";
15
+
16
+ function App() {
17
+ return (
18
+ <Animated.View
19
+ entering={FadeIn}
20
+ exiting={FadeOut}
21
+ layout={LinearTransition}
22
+ />
23
+ );
24
+ }
25
+ ```
26
+
27
+ ## On-Scroll Animations
28
+
29
+ Create high-performance scroll animations using Reanimated's hooks:
30
+
31
+ ```tsx
32
+ import Animated, {
33
+ useAnimatedRef,
34
+ useScrollViewOffset,
35
+ useAnimatedStyle,
36
+ interpolate,
37
+ } from "react-native-reanimated";
38
+
39
+ function Page() {
40
+ const ref = useAnimatedRef();
41
+ const scroll = useScrollViewOffset(ref);
42
+
43
+ const style = useAnimatedStyle(() => ({
44
+ opacity: interpolate(scroll.value, [0, 30], [0, 1], "clamp"),
45
+ }));
46
+
47
+ return (
48
+ <Animated.ScrollView ref={ref}>
49
+ <Animated.View style={style} />
50
+ </Animated.ScrollView>
51
+ );
52
+ }
53
+ ```
54
+
55
+ ## Common Animation Presets
56
+
57
+ ### Entering Animations
58
+
59
+ - `FadeIn`, `FadeInUp`, `FadeInDown`, `FadeInLeft`, `FadeInRight`
60
+ - `SlideInUp`, `SlideInDown`, `SlideInLeft`, `SlideInRight`
61
+ - `ZoomIn`, `ZoomInUp`, `ZoomInDown`
62
+ - `BounceIn`, `BounceInUp`, `BounceInDown`
63
+
64
+ ### Exiting Animations
65
+
66
+ - `FadeOut`, `FadeOutUp`, `FadeOutDown`, `FadeOutLeft`, `FadeOutRight`
67
+ - `SlideOutUp`, `SlideOutDown`, `SlideOutLeft`, `SlideOutRight`
68
+ - `ZoomOut`, `ZoomOutUp`, `ZoomOutDown`
69
+ - `BounceOut`, `BounceOutUp`, `BounceOutDown`
70
+
71
+ ### Layout Animations
72
+
73
+ - `LinearTransition` — Smooth linear interpolation
74
+ - `SequencedTransition` — Sequenced property changes
75
+ - `FadingTransition` — Fade between states
76
+
77
+ ## Customizing Animations
78
+
79
+ ```tsx
80
+ <Animated.View
81
+ entering={FadeInDown.duration(500).delay(200)}
82
+ exiting={FadeOut.duration(300)}
83
+ />
84
+ ```
85
+
86
+ ### Modifiers
87
+
88
+ ```tsx
89
+ // Duration in milliseconds
90
+ FadeIn.duration(300);
91
+
92
+ // Delay before starting
93
+ FadeIn.delay(100);
94
+
95
+ // Spring physics
96
+ FadeIn.springify();
97
+ FadeIn.springify().damping(15).stiffness(100);
98
+
99
+ // Easing curves
100
+ FadeIn.easing(Easing.bezier(0.25, 0.1, 0.25, 1));
101
+
102
+ // Chaining
103
+ FadeInDown.duration(400).delay(200).springify();
104
+ ```
105
+
106
+ ## Shared Value Animations
107
+
108
+ For imperative control over animations:
109
+
110
+ ```tsx
111
+ import {
112
+ useSharedValue,
113
+ withSpring,
114
+ withTiming,
115
+ } from "react-native-reanimated";
116
+
117
+ const offset = useSharedValue(0);
118
+
119
+ // Spring animation
120
+ offset.value = withSpring(100);
121
+
122
+ // Timing animation
123
+ offset.value = withTiming(100, { duration: 300 });
124
+
125
+ // Use in styles
126
+ const style = useAnimatedStyle(() => ({
127
+ transform: [{ translateX: offset.value }],
128
+ }));
129
+ ```
130
+
131
+ ## Gesture Animations
132
+
133
+ Combine with React Native Gesture Handler:
134
+
135
+ ```tsx
136
+ import { Gesture, GestureDetector } from "react-native-gesture-handler";
137
+ import Animated, {
138
+ useSharedValue,
139
+ useAnimatedStyle,
140
+ withSpring,
141
+ } from "react-native-reanimated";
142
+
143
+ function DraggableBox() {
144
+ const translateX = useSharedValue(0);
145
+ const translateY = useSharedValue(0);
146
+
147
+ const gesture = Gesture.Pan()
148
+ .onUpdate((e) => {
149
+ translateX.value = e.translationX;
150
+ translateY.value = e.translationY;
151
+ })
152
+ .onEnd(() => {
153
+ translateX.value = withSpring(0);
154
+ translateY.value = withSpring(0);
155
+ });
156
+
157
+ const style = useAnimatedStyle(() => ({
158
+ transform: [
159
+ { translateX: translateX.value },
160
+ { translateY: translateY.value },
161
+ ],
162
+ }));
163
+
164
+ return (
165
+ <GestureDetector gesture={gesture}>
166
+ <Animated.View style={[styles.box, style]} />
167
+ </GestureDetector>
168
+ );
169
+ }
170
+ ```
171
+
172
+ ## Keyboard Animations
173
+
174
+ Animate with keyboard height changes:
175
+
176
+ ```tsx
177
+ import Animated, {
178
+ useAnimatedKeyboard,
179
+ useAnimatedStyle,
180
+ } from "react-native-reanimated";
181
+
182
+ function KeyboardAwareView() {
183
+ const keyboard = useAnimatedKeyboard();
184
+
185
+ const style = useAnimatedStyle(() => ({
186
+ paddingBottom: keyboard.height.value,
187
+ }));
188
+
189
+ return <Animated.View style={style}>{/* content */}</Animated.View>;
190
+ }
191
+ ```
192
+
193
+ ## Staggered List Animations
194
+
195
+ Animate list items with delays:
196
+
197
+ ```tsx
198
+ {
199
+ items.map((item, index) => (
200
+ <Animated.View
201
+ key={item.id}
202
+ entering={FadeInUp.delay(index * 50)}
203
+ exiting={FadeOutUp}
204
+ >
205
+ <ListItem item={item} />
206
+ </Animated.View>
207
+ ));
208
+ }
209
+ ```
210
+
211
+ ## Best Practices
212
+
213
+ - Add entering and exiting animations for state changes
214
+ - Use layout animations when items are added/removed from lists
215
+ - Use `useAnimatedStyle` for scroll-driven animations
216
+ - Prefer `interpolate` with "clamp" for bounded values
217
+ - You can't pass PlatformColors to reanimated views or styles; use static colors instead
218
+ - Keep animations under 300ms for responsive feel
219
+ - Use spring animations for natural movement
220
+ - Avoid animating layout properties (width, height) when possible — prefer transforms