@ranimontagna/agent-toolkit 0.1.5 → 0.1.6

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 (27) hide show
  1. package/README.md +42 -8
  2. package/package.json +1 -1
  3. package/skills/frontend/react/react-patterns/LICENSE +21 -0
  4. package/skills/frontend/react/react-patterns/NOTICE.md +11 -0
  5. package/skills/frontend/react/react-patterns/SKILL.md +341 -0
  6. package/skills/frontend/react/react-performance/LICENSE +21 -0
  7. package/skills/frontend/react/react-performance/NOTICE.md +11 -0
  8. package/skills/frontend/react/react-performance/SKILL.md +574 -0
  9. package/skills/frontend/react/react-testing/LICENSE +21 -0
  10. package/skills/frontend/react/react-testing/NOTICE.md +11 -0
  11. package/skills/frontend/react/react-testing/SKILL.md +423 -0
  12. package/skills/frontend/react-native/react-native-expert/LICENSE +21 -0
  13. package/skills/frontend/react-native/react-native-expert/NOTICE.md +11 -0
  14. package/skills/frontend/react-native/react-native-expert/SKILL.md +187 -0
  15. package/skills/frontend/react-native/react-native-expert/references/expo-router.md +187 -0
  16. package/skills/frontend/react-native/react-native-expert/references/list-optimization.md +204 -0
  17. package/skills/frontend/react-native/react-native-expert/references/platform-handling.md +188 -0
  18. package/skills/frontend/react-native/react-native-expert/references/project-structure.md +171 -0
  19. package/skills/frontend/react-native/react-native-expert/references/storage-hooks.md +173 -0
  20. package/skills/frontend/react-native/react-native-unistyles-v3/LICENSE +21 -0
  21. package/skills/frontend/react-native/react-native-unistyles-v3/NOTICE.md +11 -0
  22. package/skills/frontend/react-native/react-native-unistyles-v3/SKILL.md +159 -0
  23. package/skills/frontend/react-native/react-native-unistyles-v3/references/api-reference.md +495 -0
  24. package/skills/frontend/react-native/react-native-unistyles-v3/references/common-issues.md +389 -0
  25. package/skills/frontend/react-native/react-native-unistyles-v3/references/setup-guide.md +217 -0
  26. package/skills/frontend/react-native/react-native-unistyles-v3/references/styling-patterns.md +705 -0
  27. package/skills/frontend/react-native/react-native-unistyles-v3/references/third-party-integration.md +318 -0
@@ -0,0 +1,187 @@
1
+ # Expo Router
2
+
3
+ ## Project Structure
4
+
5
+ ```
6
+ app/
7
+ ├── _layout.tsx # Root layout
8
+ ├── index.tsx # Home (/)
9
+ ├── +not-found.tsx # 404 page
10
+ ├── (tabs)/ # Tab group
11
+ │ ├── _layout.tsx # Tab bar config
12
+ │ ├── index.tsx # First tab
13
+ │ └── profile.tsx # Profile tab
14
+ ├── (auth)/ # Auth group (no tabs)
15
+ │ ├── _layout.tsx
16
+ │ ├── login.tsx
17
+ │ └── register.tsx
18
+ ├── settings/
19
+ │ ├── _layout.tsx # Stack layout
20
+ │ ├── index.tsx # Settings main
21
+ │ └── notifications.tsx
22
+ └── details/[id].tsx # Dynamic route
23
+ ```
24
+
25
+ ## Root Layout
26
+
27
+ ```typescript
28
+ // app/_layout.tsx
29
+ import { Stack } from 'expo-router';
30
+ import { ThemeProvider } from '@react-navigation/native';
31
+
32
+ export default function RootLayout() {
33
+ return (
34
+ <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
35
+ <Stack screenOptions={{ headerShown: false }}>
36
+ <Stack.Screen name="(tabs)" />
37
+ <Stack.Screen name="(auth)" />
38
+ <Stack.Screen
39
+ name="details/[id]"
40
+ options={{ presentation: 'modal' }}
41
+ />
42
+ </Stack>
43
+ </ThemeProvider>
44
+ );
45
+ }
46
+ ```
47
+
48
+ ## Tab Layout
49
+
50
+ ```typescript
51
+ // app/(tabs)/_layout.tsx
52
+ import { Tabs } from 'expo-router';
53
+ import { Ionicons } from '@expo/vector-icons';
54
+
55
+ export default function TabLayout() {
56
+ return (
57
+ <Tabs
58
+ screenOptions={{
59
+ tabBarActiveTintColor: '#007AFF',
60
+ headerShown: true,
61
+ }}
62
+ >
63
+ <Tabs.Screen
64
+ name="index"
65
+ options={{
66
+ title: 'Home',
67
+ tabBarIcon: ({ color, size }) => (
68
+ <Ionicons name="home" color={color} size={size} />
69
+ ),
70
+ }}
71
+ />
72
+ <Tabs.Screen
73
+ name="profile"
74
+ options={{
75
+ title: 'Profile',
76
+ tabBarIcon: ({ color, size }) => (
77
+ <Ionicons name="person" color={color} size={size} />
78
+ ),
79
+ }}
80
+ />
81
+ </Tabs>
82
+ );
83
+ }
84
+ ```
85
+
86
+ ## Navigation
87
+
88
+ ```typescript
89
+ import { router, useLocalSearchParams, Link } from 'expo-router';
90
+
91
+ // Programmatic navigation
92
+ router.push('/details/123'); // Push to stack
93
+ router.replace('/home'); // Replace current
94
+ router.back(); // Go back
95
+ router.canGoBack(); // Check if can go back
96
+
97
+ // With params
98
+ router.push({
99
+ pathname: '/details/[id]',
100
+ params: { id: '123', title: 'Item' },
101
+ });
102
+
103
+ // Link component
104
+ <Link href="/profile" asChild>
105
+ <Pressable>
106
+ <Text>Go to Profile</Text>
107
+ </Pressable>
108
+ </Link>
109
+
110
+ // Reading params
111
+ function DetailsScreen() {
112
+ const { id, title } = useLocalSearchParams<{ id: string; title?: string }>();
113
+ return <Text>Details for {id}</Text>;
114
+ }
115
+ ```
116
+
117
+ ## Protected Routes
118
+
119
+ ```typescript
120
+ // app/(auth)/_layout.tsx
121
+ import { Redirect, Stack } from 'expo-router';
122
+ import { useAuth } from '@/hooks/useAuth';
123
+
124
+ export default function AuthLayout() {
125
+ const { user, isLoading } = useAuth();
126
+
127
+ if (isLoading) {
128
+ return <LoadingScreen />;
129
+ }
130
+
131
+ if (user) {
132
+ return <Redirect href="/(tabs)" />;
133
+ }
134
+
135
+ return <Stack screenOptions={{ headerShown: false }} />;
136
+ }
137
+
138
+ // app/(tabs)/_layout.tsx
139
+ export default function TabLayout() {
140
+ const { user, isLoading } = useAuth();
141
+
142
+ if (isLoading) {
143
+ return <LoadingScreen />;
144
+ }
145
+
146
+ if (!user) {
147
+ return <Redirect href="/(auth)/login" />;
148
+ }
149
+
150
+ return <Tabs>...</Tabs>;
151
+ }
152
+ ```
153
+
154
+ ## Deep Linking
155
+
156
+ ```json
157
+ // app.json
158
+ {
159
+ "expo": {
160
+ "scheme": "myapp",
161
+ "web": {
162
+ "bundler": "metro"
163
+ }
164
+ }
165
+ }
166
+ ```
167
+
168
+ ```typescript
169
+ // Handle: myapp://details/123
170
+ // app/details/[id].tsx handles automatically
171
+ ```
172
+
173
+ ## Quick Reference
174
+
175
+ | Component | Purpose |
176
+ |-----------|---------|
177
+ | `<Stack>` | Stack navigator |
178
+ | `<Tabs>` | Tab navigator |
179
+ | `<Drawer>` | Drawer navigator |
180
+ | `<Link>` | Declarative navigation |
181
+
182
+ | router method | Behavior |
183
+ |---------------|----------|
184
+ | `push()` | Add to stack |
185
+ | `replace()` | Replace current |
186
+ | `back()` | Go back |
187
+ | `dismissAll()` | Dismiss modals |
@@ -0,0 +1,204 @@
1
+ # List Optimization
2
+
3
+ ## Optimized FlatList
4
+
5
+ ```typescript
6
+ import { FlatList, ListRenderItem } from 'react-native';
7
+ import { memo, useCallback } from 'react';
8
+
9
+ interface Item {
10
+ id: string;
11
+ title: string;
12
+ subtitle: string;
13
+ }
14
+
15
+ // Memoized list item
16
+ const ListItem = memo(function ListItem({
17
+ item,
18
+ onPress
19
+ }: {
20
+ item: Item;
21
+ onPress: (id: string) => void;
22
+ }) {
23
+ return (
24
+ <Pressable onPress={() => onPress(item.id)} style={styles.item}>
25
+ <Text style={styles.title}>{item.title}</Text>
26
+ <Text style={styles.subtitle}>{item.subtitle}</Text>
27
+ </Pressable>
28
+ );
29
+ });
30
+
31
+ function OptimizedList({ data }: { data: Item[] }) {
32
+ // Memoize callbacks
33
+ const handlePress = useCallback((id: string) => {
34
+ console.log('Selected:', id);
35
+ }, []);
36
+
37
+ const renderItem: ListRenderItem<Item> = useCallback(
38
+ ({ item }) => <ListItem item={item} onPress={handlePress} />,
39
+ [handlePress]
40
+ );
41
+
42
+ const keyExtractor = useCallback((item: Item) => item.id, []);
43
+
44
+ // Fixed height for getItemLayout
45
+ const getItemLayout = useCallback(
46
+ (_: any, index: number) => ({
47
+ length: ITEM_HEIGHT,
48
+ offset: ITEM_HEIGHT * index,
49
+ index,
50
+ }),
51
+ []
52
+ );
53
+
54
+ return (
55
+ <FlatList
56
+ data={data}
57
+ renderItem={renderItem}
58
+ keyExtractor={keyExtractor}
59
+ getItemLayout={getItemLayout}
60
+ // Performance props
61
+ removeClippedSubviews
62
+ maxToRenderPerBatch={10}
63
+ windowSize={5}
64
+ initialNumToRender={10}
65
+ updateCellsBatchingPeriod={50}
66
+ />
67
+ );
68
+ }
69
+
70
+ const ITEM_HEIGHT = 72;
71
+ ```
72
+
73
+ ## SectionList
74
+
75
+ ```typescript
76
+ import { SectionList } from 'react-native';
77
+
78
+ interface Section {
79
+ title: string;
80
+ data: Item[];
81
+ }
82
+
83
+ function GroupedList({ sections }: { sections: Section[] }) {
84
+ const renderSectionHeader = useCallback(
85
+ ({ section }: { section: Section }) => (
86
+ <View style={styles.sectionHeader}>
87
+ <Text style={styles.sectionTitle}>{section.title}</Text>
88
+ </View>
89
+ ),
90
+ []
91
+ );
92
+
93
+ return (
94
+ <SectionList
95
+ sections={sections}
96
+ renderItem={renderItem}
97
+ renderSectionHeader={renderSectionHeader}
98
+ keyExtractor={keyExtractor}
99
+ stickySectionHeadersEnabled
100
+ />
101
+ );
102
+ }
103
+ ```
104
+
105
+ ## Pull to Refresh
106
+
107
+ ```typescript
108
+ function RefreshableList({ data, onRefresh }: Props) {
109
+ const [refreshing, setRefreshing] = useState(false);
110
+
111
+ const handleRefresh = useCallback(async () => {
112
+ setRefreshing(true);
113
+ await onRefresh();
114
+ setRefreshing(false);
115
+ }, [onRefresh]);
116
+
117
+ return (
118
+ <FlatList
119
+ data={data}
120
+ renderItem={renderItem}
121
+ refreshControl={
122
+ <RefreshControl
123
+ refreshing={refreshing}
124
+ onRefresh={handleRefresh}
125
+ tintColor="#007AFF"
126
+ />
127
+ }
128
+ />
129
+ );
130
+ }
131
+ ```
132
+
133
+ ## Infinite Scroll
134
+
135
+ ```typescript
136
+ function InfiniteList() {
137
+ const [data, setData] = useState<Item[]>([]);
138
+ const [loading, setLoading] = useState(false);
139
+ const [hasMore, setHasMore] = useState(true);
140
+
141
+ const loadMore = useCallback(async () => {
142
+ if (loading || !hasMore) return;
143
+
144
+ setLoading(true);
145
+ const newItems = await fetchMoreItems(data.length);
146
+
147
+ if (newItems.length === 0) {
148
+ setHasMore(false);
149
+ } else {
150
+ setData(prev => [...prev, ...newItems]);
151
+ }
152
+ setLoading(false);
153
+ }, [data.length, loading, hasMore]);
154
+
155
+ const renderFooter = useCallback(() => {
156
+ if (!loading) return null;
157
+ return <ActivityIndicator style={styles.loader} />;
158
+ }, [loading]);
159
+
160
+ return (
161
+ <FlatList
162
+ data={data}
163
+ renderItem={renderItem}
164
+ onEndReached={loadMore}
165
+ onEndReachedThreshold={0.5}
166
+ ListFooterComponent={renderFooter}
167
+ />
168
+ );
169
+ }
170
+ ```
171
+
172
+ ## FlashList (Alternative)
173
+
174
+ ```typescript
175
+ import { FlashList } from '@shopify/flash-list';
176
+
177
+ function FastList({ data }: { data: Item[] }) {
178
+ return (
179
+ <FlashList
180
+ data={data}
181
+ renderItem={renderItem}
182
+ estimatedItemSize={72}
183
+ keyExtractor={keyExtractor}
184
+ />
185
+ );
186
+ }
187
+ ```
188
+
189
+ ## Quick Reference
190
+
191
+ | Prop | Purpose |
192
+ |------|---------|
193
+ | `removeClippedSubviews` | Unmount off-screen items |
194
+ | `maxToRenderPerBatch` | Items per render batch |
195
+ | `windowSize` | Render window multiplier |
196
+ | `initialNumToRender` | Initial items to render |
197
+ | `getItemLayout` | Skip measurement (fixed height) |
198
+
199
+ | Optimization | When |
200
+ |--------------|------|
201
+ | `memo()` | All list items |
202
+ | `useCallback` | renderItem, keyExtractor |
203
+ | `getItemLayout` | Fixed height items |
204
+ | `FlashList` | Very large lists |
@@ -0,0 +1,188 @@
1
+ # Platform Handling
2
+
3
+ ## Platform.select
4
+
5
+ ```typescript
6
+ import { Platform, StyleSheet } from 'react-native';
7
+
8
+ const styles = StyleSheet.create({
9
+ card: {
10
+ padding: 16,
11
+ borderRadius: 12,
12
+ backgroundColor: '#fff',
13
+ ...Platform.select({
14
+ ios: {
15
+ shadowColor: '#000',
16
+ shadowOffset: { width: 0, height: 2 },
17
+ shadowOpacity: 0.1,
18
+ shadowRadius: 8,
19
+ },
20
+ android: {
21
+ elevation: 4,
22
+ },
23
+ }),
24
+ },
25
+ text: {
26
+ fontFamily: Platform.select({
27
+ ios: 'Helvetica Neue',
28
+ android: 'Roboto',
29
+ }),
30
+ },
31
+ });
32
+ ```
33
+
34
+ ## Platform.OS
35
+
36
+ ```typescript
37
+ import { Platform } from 'react-native';
38
+
39
+ function MyComponent() {
40
+ const isIOS = Platform.OS === 'ios';
41
+ const isAndroid = Platform.OS === 'android';
42
+
43
+ return (
44
+ <View>
45
+ {isIOS && <IOSOnlyComponent />}
46
+ <Text>{isAndroid ? 'Android' : 'iOS'}</Text>
47
+ </View>
48
+ );
49
+ }
50
+ ```
51
+
52
+ ## Platform-Specific Files
53
+
54
+ ```
55
+ components/
56
+ ├── Button.tsx # Shared logic
57
+ ├── Button.ios.tsx # iOS-specific
58
+ └── Button.android.tsx # Android-specific
59
+ ```
60
+
61
+ ```typescript
62
+ // Import resolves to correct platform file
63
+ import Button from './components/Button';
64
+ ```
65
+
66
+ ## SafeAreaView
67
+
68
+ ```typescript
69
+ import { SafeAreaView, StyleSheet } from 'react-native';
70
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
71
+
72
+ // Method 1: SafeAreaView component
73
+ function Screen() {
74
+ return (
75
+ <SafeAreaView style={styles.container}>
76
+ <Content />
77
+ </SafeAreaView>
78
+ );
79
+ }
80
+
81
+ // Method 2: useSafeAreaInsets hook (more control)
82
+ function CustomHeader() {
83
+ const insets = useSafeAreaInsets();
84
+
85
+ return (
86
+ <View style={[styles.header, { paddingTop: insets.top }]}>
87
+ <Text>Header</Text>
88
+ </View>
89
+ );
90
+ }
91
+
92
+ // Method 3: SafeAreaProvider context
93
+ import { SafeAreaProvider } from 'react-native-safe-area-context';
94
+
95
+ function App() {
96
+ return (
97
+ <SafeAreaProvider>
98
+ <Navigation />
99
+ </SafeAreaProvider>
100
+ );
101
+ }
102
+ ```
103
+
104
+ ## KeyboardAvoidingView
105
+
106
+ ```typescript
107
+ import { KeyboardAvoidingView, Platform } from 'react-native';
108
+
109
+ function FormScreen() {
110
+ return (
111
+ <KeyboardAvoidingView
112
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
113
+ style={{ flex: 1 }}
114
+ keyboardVerticalOffset={Platform.select({ ios: 88, android: 0 })}
115
+ >
116
+ <ScrollView>
117
+ <TextInput placeholder="Name" />
118
+ <TextInput placeholder="Email" />
119
+ </ScrollView>
120
+ </KeyboardAvoidingView>
121
+ );
122
+ }
123
+ ```
124
+
125
+ ## StatusBar
126
+
127
+ ```typescript
128
+ import { StatusBar, Platform } from 'react-native';
129
+
130
+ function Screen() {
131
+ return (
132
+ <>
133
+ <StatusBar
134
+ barStyle={Platform.OS === 'ios' ? 'dark-content' : 'light-content'}
135
+ backgroundColor={Platform.OS === 'android' ? '#000' : undefined}
136
+ />
137
+ <Content />
138
+ </>
139
+ );
140
+ }
141
+ ```
142
+
143
+ ## Android Back Button
144
+
145
+ ```typescript
146
+ import { useEffect } from 'react';
147
+ import { BackHandler, Platform } from 'react-native';
148
+
149
+ function useBackHandler(handler: () => boolean) {
150
+ useEffect(() => {
151
+ if (Platform.OS !== 'android') return;
152
+
153
+ const subscription = BackHandler.addEventListener(
154
+ 'hardwareBackPress',
155
+ handler
156
+ );
157
+
158
+ return () => subscription.remove();
159
+ }, [handler]);
160
+ }
161
+
162
+ // Usage
163
+ function Screen() {
164
+ useBackHandler(() => {
165
+ if (hasUnsavedChanges) {
166
+ showDiscardAlert();
167
+ return true; // Prevent default back
168
+ }
169
+ return false; // Allow default back
170
+ });
171
+ }
172
+ ```
173
+
174
+ ## Quick Reference
175
+
176
+ | API | Purpose |
177
+ |-----|---------|
178
+ | `Platform.OS` | Get platform ('ios' / 'android') |
179
+ | `Platform.select()` | Platform-specific values |
180
+ | `Platform.Version` | OS version number |
181
+ | `.ios.tsx` / `.android.tsx` | Platform-specific files |
182
+
183
+ | Component | Purpose |
184
+ |-----------|---------|
185
+ | `SafeAreaView` | Avoid notch/home indicator |
186
+ | `KeyboardAvoidingView` | Keyboard handling |
187
+ | `StatusBar` | Status bar styling |
188
+ | `BackHandler` | Android back button |