@valentia-ai-skills/framework 1.0.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/README.md +103 -0
- package/bin/cli.js +482 -0
- package/package.json +42 -0
- package/scripts/postinstall.js +18 -0
- package/skills/global/api-design/SKILL.md +248 -0
- package/skills/global/api-design/tests/test-prompts.md +25 -0
- package/skills/global/code-standards/SKILL.md +245 -0
- package/skills/global/code-standards/tests/test-prompts.md +26 -0
- package/skills/global/deployment/SKILL.md +240 -0
- package/skills/global/deployment/tests/test-prompts.md +27 -0
- package/skills/global/documentation/SKILL.md +298 -0
- package/skills/global/documentation/tests/test-prompts.md +26 -0
- package/skills/global/git-workflow/SKILL.md +177 -0
- package/skills/global/git-workflow/tests/test-prompts.md +11 -0
- package/skills/global/security-baseline/SKILL.md +239 -0
- package/skills/global/security-baseline/tests/test-prompts.md +23 -0
- package/skills/global/testing-standards/SKILL.md +257 -0
- package/skills/global/testing-standards/tests/test-prompts.md +25 -0
- package/skills/onboarding/SKILL.md +110 -0
- package/skills/stack/devops/SKILL.md +220 -0
- package/skills/stack/devops/tests/test-prompts.md +29 -0
- package/skills/stack/node-backend/SKILL.md +304 -0
- package/skills/stack/node-backend/tests/test-prompts.md +27 -0
- package/skills/stack/python-backend/SKILL.md +304 -0
- package/skills/stack/python-backend/tests/test-prompts.md +27 -0
- package/skills/stack/react/SKILL.md +251 -0
- package/skills/stack/react/tests/test-prompts.md +26 -0
- package/skills/stack/react-native/SKILL.md +255 -0
- package/skills/stack/react-native/tests/test-prompts.md +26 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-native-patterns
|
|
3
|
+
description: >
|
|
4
|
+
React Native and mobile development patterns for mobile teams. Use this skill
|
|
5
|
+
whenever writing, reviewing, or designing mobile app code using React Native,
|
|
6
|
+
Expo, or related mobile frameworks. Triggers on: "React Native", "mobile app",
|
|
7
|
+
"Expo", "iOS", "Android", "navigation", "react-navigation", "native module",
|
|
8
|
+
"mobile performance", "offline", "push notification", "deep link", "app store",
|
|
9
|
+
"mobile UI", "gesture", "animation", "Reanimated", "AsyncStorage", "MMKV",
|
|
10
|
+
"native bridge", "mobile testing", "Detox", "Appium". Applies to mobile teams.
|
|
11
|
+
version: "1.0.0"
|
|
12
|
+
scope: stack
|
|
13
|
+
stack: react-native
|
|
14
|
+
author: Framework Admin
|
|
15
|
+
last_reviewed: 2026-03-19
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# React Native Patterns
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
Mobile development has unique constraints — performance on constrained devices,
|
|
23
|
+
offline support, platform differences, and app store requirements. These patterns
|
|
24
|
+
extend the React patterns skill with mobile-specific conventions.
|
|
25
|
+
|
|
26
|
+
**Prerequisite**: All rules from `stack/react/SKILL.md` apply to React Native code.
|
|
27
|
+
This skill adds mobile-specific patterns on top.
|
|
28
|
+
|
|
29
|
+
## 1. Project Structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
src/
|
|
33
|
+
components/ # Shared UI components
|
|
34
|
+
ui/ # Design system primitives
|
|
35
|
+
forms/ # Form components
|
|
36
|
+
screens/ # Screen-level components (1:1 with routes)
|
|
37
|
+
home/
|
|
38
|
+
home-screen.tsx
|
|
39
|
+
home-screen.test.tsx
|
|
40
|
+
navigation/ # Navigation configuration
|
|
41
|
+
root-navigator.tsx
|
|
42
|
+
tab-navigator.tsx
|
|
43
|
+
types.ts # Navigation type definitions
|
|
44
|
+
services/ # API clients, business logic
|
|
45
|
+
hooks/ # Shared custom hooks
|
|
46
|
+
stores/ # State management (Zustand)
|
|
47
|
+
utils/ # Pure utility functions
|
|
48
|
+
constants/ # App-wide constants
|
|
49
|
+
types/ # Shared TypeScript types
|
|
50
|
+
assets/ # Images, fonts, animations
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Rules
|
|
54
|
+
- Screens in `screens/` — one directory per screen with co-located tests
|
|
55
|
+
- Navigation config in `navigation/` — typed with React Navigation's TypeScript support
|
|
56
|
+
- Platform-specific files use `.ios.tsx` / `.android.tsx` extension (only when necessary)
|
|
57
|
+
|
|
58
|
+
## 2. Navigation
|
|
59
|
+
|
|
60
|
+
### Type-Safe Navigation
|
|
61
|
+
Always type your navigation params:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
// navigation/types.ts
|
|
65
|
+
export type RootStackParamList = {
|
|
66
|
+
Home: undefined;
|
|
67
|
+
UserProfile: { userId: string };
|
|
68
|
+
Settings: undefined;
|
|
69
|
+
OrderDetails: { orderId: string; fromNotification?: boolean };
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// In a screen:
|
|
73
|
+
type Props = NativeStackScreenProps<RootStackParamList, "UserProfile">;
|
|
74
|
+
|
|
75
|
+
export function UserProfileScreen({ route, navigation }: Props) {
|
|
76
|
+
const { userId } = route.params; // typed!
|
|
77
|
+
// ...
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Rules
|
|
82
|
+
- All navigation params must be typed
|
|
83
|
+
- Use `navigation.navigate` — never `navigation.dispatch` for standard flows
|
|
84
|
+
- Deep links must be handled in navigation config, not in components
|
|
85
|
+
- Always handle the "back" action gracefully
|
|
86
|
+
|
|
87
|
+
## 3. Performance
|
|
88
|
+
|
|
89
|
+
### FlatList Rules (critical)
|
|
90
|
+
```tsx
|
|
91
|
+
// ✅ Good: Optimized FlatList
|
|
92
|
+
<FlatList
|
|
93
|
+
data={items}
|
|
94
|
+
renderItem={renderItem}
|
|
95
|
+
keyExtractor={item => item.id}
|
|
96
|
+
getItemLayout={(data, index) => ({
|
|
97
|
+
length: ITEM_HEIGHT,
|
|
98
|
+
offset: ITEM_HEIGHT * index,
|
|
99
|
+
index,
|
|
100
|
+
})}
|
|
101
|
+
maxToRenderPerBatch={10}
|
|
102
|
+
windowSize={5}
|
|
103
|
+
removeClippedSubviews={true}
|
|
104
|
+
/>
|
|
105
|
+
|
|
106
|
+
// Extract renderItem outside component or use useCallback
|
|
107
|
+
const renderItem = useCallback(({ item }: { item: Product }) => (
|
|
108
|
+
<ProductCard product={item} onPress={handlePress} />
|
|
109
|
+
), [handlePress]);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Rules
|
|
113
|
+
- Always provide `keyExtractor` — never use array index as key
|
|
114
|
+
- Use `getItemLayout` for fixed-height items
|
|
115
|
+
- Extract `renderItem` to prevent re-renders
|
|
116
|
+
- Use `React.memo` on list item components
|
|
117
|
+
- Test with 1000+ items to catch performance issues
|
|
118
|
+
|
|
119
|
+
### Image Optimization
|
|
120
|
+
- Use `react-native-fast-image` for cached image loading
|
|
121
|
+
- Always specify image dimensions (width/height)
|
|
122
|
+
- Use appropriate resolution for device density
|
|
123
|
+
- Lazy load images below the fold
|
|
124
|
+
|
|
125
|
+
### Animation Rules
|
|
126
|
+
- Use `react-native-reanimated` for smooth 60fps animations
|
|
127
|
+
- Run animations on the UI thread (`useAnimatedStyle`, `withTiming`)
|
|
128
|
+
- Never use `Animated` from React Native for complex animations
|
|
129
|
+
- Test animations on low-end Android devices
|
|
130
|
+
|
|
131
|
+
## 4. Offline-First Pattern
|
|
132
|
+
|
|
133
|
+
Mobile apps must handle offline gracefully:
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
// Pattern: Optimistic update with sync queue
|
|
137
|
+
function useOfflineReady<T>(
|
|
138
|
+
queryKey: string[],
|
|
139
|
+
fetcher: () => Promise<T>,
|
|
140
|
+
mutator: (data: T) => Promise<T>,
|
|
141
|
+
) {
|
|
142
|
+
const networkState = useNetworkState();
|
|
143
|
+
|
|
144
|
+
// Read from cache first
|
|
145
|
+
const { data, isLoading } = useQuery({
|
|
146
|
+
queryKey,
|
|
147
|
+
queryFn: fetcher,
|
|
148
|
+
staleTime: 5 * 60 * 1000, // 5 min
|
|
149
|
+
cacheTime: 24 * 60 * 60 * 1000, // 24 hours
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const mutation = useMutation({
|
|
153
|
+
mutationFn: mutator,
|
|
154
|
+
onMutate: async (newData) => {
|
|
155
|
+
// Optimistic update
|
|
156
|
+
queryClient.setQueryData(queryKey, newData);
|
|
157
|
+
},
|
|
158
|
+
onError: (err, newData, context) => {
|
|
159
|
+
// Rollback on failure
|
|
160
|
+
queryClient.setQueryData(queryKey, context?.previous);
|
|
161
|
+
},
|
|
162
|
+
retry: networkState.isConnected ? 3 : false,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return { data, isLoading, mutate: mutation.mutate };
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Rules
|
|
170
|
+
- Cache API responses locally (TanStack Query + MMKV)
|
|
171
|
+
- Show cached data immediately, refresh in background
|
|
172
|
+
- Queue mutations when offline, sync when online
|
|
173
|
+
- Always show clear offline indicator in the UI
|
|
174
|
+
- Test the full offline → online sync flow
|
|
175
|
+
|
|
176
|
+
## 5. Platform-Specific Code
|
|
177
|
+
|
|
178
|
+
### When to Split
|
|
179
|
+
Only use platform-specific files when the UI or behavior fundamentally differs:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
// button.tsx — shared logic (95% of cases)
|
|
183
|
+
// button.ios.tsx — iOS-only implementation
|
|
184
|
+
// button.android.tsx — Android-only implementation
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Prefer Platform.select
|
|
188
|
+
For small differences, use inline platform checks:
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import { Platform, StyleSheet } from "react-native";
|
|
192
|
+
|
|
193
|
+
const styles = StyleSheet.create({
|
|
194
|
+
shadow: Platform.select({
|
|
195
|
+
ios: {
|
|
196
|
+
shadowColor: "#000",
|
|
197
|
+
shadowOffset: { width: 0, height: 2 },
|
|
198
|
+
shadowOpacity: 0.1,
|
|
199
|
+
shadowRadius: 4,
|
|
200
|
+
},
|
|
201
|
+
android: {
|
|
202
|
+
elevation: 4,
|
|
203
|
+
},
|
|
204
|
+
}),
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Rules
|
|
209
|
+
- Default to shared code — split only when genuinely needed
|
|
210
|
+
- Platform checks for: shadows, status bar, haptics, keyboard behavior
|
|
211
|
+
- Test on both platforms before merging
|
|
212
|
+
|
|
213
|
+
## 6. Local Storage
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
// Use MMKV (fast, synchronous) for simple key-value storage
|
|
217
|
+
import { MMKV } from "react-native-mmkv";
|
|
218
|
+
|
|
219
|
+
const storage = new MMKV();
|
|
220
|
+
|
|
221
|
+
// Store
|
|
222
|
+
storage.set("user.token", token);
|
|
223
|
+
storage.set("user.preferences", JSON.stringify(prefs));
|
|
224
|
+
|
|
225
|
+
// Retrieve
|
|
226
|
+
const token = storage.getString("user.token");
|
|
227
|
+
const prefs = JSON.parse(storage.getString("user.preferences") || "{}");
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Rules
|
|
231
|
+
- Use MMKV over AsyncStorage (faster, synchronous)
|
|
232
|
+
- Never store sensitive data in plain storage — use encrypted storage or Keychain
|
|
233
|
+
- Prefix keys by domain: `user.token`, `cache.products`, `settings.theme`
|
|
234
|
+
- Clear storage on logout (except device preferences)
|
|
235
|
+
|
|
236
|
+
## 7. App Lifecycle
|
|
237
|
+
|
|
238
|
+
- Handle app state changes (active, background, inactive)
|
|
239
|
+
- Refresh data when app returns to foreground
|
|
240
|
+
- Save draft state when app goes to background
|
|
241
|
+
- Handle push notification deep links on cold start AND warm start
|
|
242
|
+
|
|
243
|
+
## Checklist
|
|
244
|
+
|
|
245
|
+
Before finalizing mobile code:
|
|
246
|
+
- [ ] All React patterns from stack/react still apply
|
|
247
|
+
- [ ] Navigation params are fully typed
|
|
248
|
+
- [ ] FlatList has keyExtractor, getItemLayout, and memoized renderItem
|
|
249
|
+
- [ ] Images have fixed dimensions and use fast-image
|
|
250
|
+
- [ ] Animations use Reanimated (UI thread)
|
|
251
|
+
- [ ] Offline state handled with cache + sync queue
|
|
252
|
+
- [ ] Platform differences handled minimally
|
|
253
|
+
- [ ] Sensitive data NOT in plain MMKV — use Keychain/encrypted storage
|
|
254
|
+
- [ ] Tested on both iOS and Android
|
|
255
|
+
- [ ] Tested on low-end device for performance
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## Test 1: List Screen
|
|
2
|
+
**Prompt**: "Build a product listing screen with infinite scroll, pull-to-refresh, and a search bar"
|
|
3
|
+
**Expected**:
|
|
4
|
+
- FlatList with keyExtractor, getItemLayout
|
|
5
|
+
- Memoized renderItem
|
|
6
|
+
- Pagination with onEndReached
|
|
7
|
+
- RefreshControl for pull-to-refresh
|
|
8
|
+
- Loading/empty/error states
|
|
9
|
+
|
|
10
|
+
## Test 2: Offline Data Handling
|
|
11
|
+
**Prompt**: "Create a form that saves user profile data, works offline, and syncs when back online"
|
|
12
|
+
**Expected**:
|
|
13
|
+
- Optimistic update pattern
|
|
14
|
+
- MMKV or TanStack Query cache
|
|
15
|
+
- Queue mutations when offline
|
|
16
|
+
- Online/offline UI indicator
|
|
17
|
+
- Sync on reconnection
|
|
18
|
+
|
|
19
|
+
## Test 3: Navigation Setup
|
|
20
|
+
**Prompt**: "Set up navigation for an app with: tab bar (Home, Search, Profile), stack navigation within each tab, and a modal for settings"
|
|
21
|
+
**Expected**:
|
|
22
|
+
- Typed RootStackParamList
|
|
23
|
+
- Tab navigator with nested stack navigators
|
|
24
|
+
- Modal presentation for settings
|
|
25
|
+
- Deep link configuration
|
|
26
|
+
- Type-safe navigation hooks
|