stitch-kit 1.5.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 (98) hide show
  1. package/AGENTS.md +139 -0
  2. package/CHANGELOG.md +86 -0
  3. package/README.md +167 -0
  4. package/agents/stitch-kit.md +93 -0
  5. package/bin/stitch-kit.mjs +430 -0
  6. package/docs/architecture.md +118 -0
  7. package/docs/color-prompt-guide.md +119 -0
  8. package/docs/mcp-naming-convention.md +64 -0
  9. package/docs/mcp-schemas/README.md +130 -0
  10. package/docs/mcp-schemas/apply_design_system.json +36 -0
  11. package/docs/mcp-schemas/create_design_system.json +78 -0
  12. package/docs/mcp-schemas/create_project.json +290 -0
  13. package/docs/mcp-schemas/delete_project.json +20 -0
  14. package/docs/mcp-schemas/edit_screens.json +46 -0
  15. package/docs/mcp-schemas/generate_screen_from_text.json +242 -0
  16. package/docs/mcp-schemas/generate_variants.json +77 -0
  17. package/docs/mcp-schemas/get_project.json +137 -0
  18. package/docs/mcp-schemas/get_screen.json +92 -0
  19. package/docs/mcp-schemas/list_design_systems.json +32 -0
  20. package/docs/mcp-schemas/list_projects.json +136 -0
  21. package/docs/mcp-schemas/list_screens.json +56 -0
  22. package/docs/mcp-schemas/update_design_system.json +32 -0
  23. package/docs/mcp-schemas/upload_screens_from_images.json +52 -0
  24. package/docs/prd-to-stitch-workflow.md +137 -0
  25. package/docs/skills-index.md +108 -0
  26. package/docs/tailwind-reference.md +207 -0
  27. package/package.json +41 -0
  28. package/skills/stitch-a11y/SKILL.md +428 -0
  29. package/skills/stitch-a11y/resources/audit-checklist.md +102 -0
  30. package/skills/stitch-animate/SKILL.md +371 -0
  31. package/skills/stitch-animate/resources/animation-patterns.md +248 -0
  32. package/skills/stitch-design-md/SKILL.md +215 -0
  33. package/skills/stitch-design-md/examples/DESIGN.md +54 -0
  34. package/skills/stitch-design-md/examples/usage.md +67 -0
  35. package/skills/stitch-design-md/scripts/fetch-stitch.sh +35 -0
  36. package/skills/stitch-design-system/SKILL.md +314 -0
  37. package/skills/stitch-design-system/resources/tokens-template.css +237 -0
  38. package/skills/stitch-html-components/SKILL.md +344 -0
  39. package/skills/stitch-html-components/resources/architecture-checklist.md +74 -0
  40. package/skills/stitch-html-components/scripts/fetch-stitch.sh +45 -0
  41. package/skills/stitch-loop/SKILL.md +183 -0
  42. package/skills/stitch-loop/examples/SITE.md +39 -0
  43. package/skills/stitch-loop/examples/next-prompt.md +24 -0
  44. package/skills/stitch-loop/examples/usage.md +77 -0
  45. package/skills/stitch-mcp-apply-design-system/SKILL.md +82 -0
  46. package/skills/stitch-mcp-create-design-system/SKILL.md +117 -0
  47. package/skills/stitch-mcp-create-project/SKILL.md +77 -0
  48. package/skills/stitch-mcp-delete-project/SKILL.md +62 -0
  49. package/skills/stitch-mcp-edit-screens/SKILL.md +121 -0
  50. package/skills/stitch-mcp-generate-screen-from-text/SKILL.md +102 -0
  51. package/skills/stitch-mcp-generate-screen-from-text/examples/desktop.md +53 -0
  52. package/skills/stitch-mcp-generate-screen-from-text/examples/mobile.md +71 -0
  53. package/skills/stitch-mcp-generate-variants/SKILL.md +124 -0
  54. package/skills/stitch-mcp-get-project/SKILL.md +67 -0
  55. package/skills/stitch-mcp-get-screen/SKILL.md +117 -0
  56. package/skills/stitch-mcp-get-screen/scripts/fetch-stitch.sh +35 -0
  57. package/skills/stitch-mcp-list-design-systems/SKILL.md +84 -0
  58. package/skills/stitch-mcp-list-projects/SKILL.md +77 -0
  59. package/skills/stitch-mcp-list-screens/SKILL.md +69 -0
  60. package/skills/stitch-mcp-update-design-system/SKILL.md +82 -0
  61. package/skills/stitch-mcp-upload-screens-from-images/SKILL.md +95 -0
  62. package/skills/stitch-mcp-upload-screens-from-images/scripts/encode-image.sh +43 -0
  63. package/skills/stitch-nextjs-components/SKILL.md +181 -0
  64. package/skills/stitch-nextjs-components/resources/architecture-checklist.md +65 -0
  65. package/skills/stitch-nextjs-components/resources/component-template.tsx +101 -0
  66. package/skills/stitch-nextjs-components/scripts/fetch-stitch.sh +45 -0
  67. package/skills/stitch-orchestrator/SKILL.md +337 -0
  68. package/skills/stitch-orchestrator/examples/workflow.md +173 -0
  69. package/skills/stitch-react-components/SKILL.md +236 -0
  70. package/skills/stitch-react-components/references/tailwind-to-react.md +117 -0
  71. package/skills/stitch-react-components/resources/architecture-checklist.md +34 -0
  72. package/skills/stitch-react-components/resources/component-template.tsx +35 -0
  73. package/skills/stitch-react-components/scripts/fetch-stitch.sh +35 -0
  74. package/skills/stitch-react-native-components/SKILL.md +333 -0
  75. package/skills/stitch-react-native-components/resources/architecture-checklist.md +74 -0
  76. package/skills/stitch-react-native-components/resources/component-template.tsx +104 -0
  77. package/skills/stitch-react-native-components/scripts/fetch-stitch.sh +45 -0
  78. package/skills/stitch-remotion/SKILL.md +280 -0
  79. package/skills/stitch-setup/SKILL.md +183 -0
  80. package/skills/stitch-shadcn-ui/SKILL.md +255 -0
  81. package/skills/stitch-skill-creator/SKILL.md +257 -0
  82. package/skills/stitch-skill-creator/references/output-patterns.md +71 -0
  83. package/skills/stitch-skill-creator/scripts/init_stitch_skill.py +229 -0
  84. package/skills/stitch-svelte-components/SKILL.md +282 -0
  85. package/skills/stitch-svelte-components/resources/architecture-checklist.md +62 -0
  86. package/skills/stitch-svelte-components/resources/component-template.svelte +193 -0
  87. package/skills/stitch-svelte-components/scripts/fetch-stitch.sh +36 -0
  88. package/skills/stitch-swiftui-components/SKILL.md +424 -0
  89. package/skills/stitch-swiftui-components/resources/architecture-checklist.md +83 -0
  90. package/skills/stitch-swiftui-components/resources/component-template.swift +131 -0
  91. package/skills/stitch-swiftui-components/resources/layout-mapping.md +155 -0
  92. package/skills/stitch-swiftui-components/scripts/fetch-stitch.sh +45 -0
  93. package/skills/stitch-ued-guide/SKILL.md +124 -0
  94. package/skills/stitch-ui-design-spec-generator/SKILL.md +115 -0
  95. package/skills/stitch-ui-design-spec-generator/examples/usage.md +79 -0
  96. package/skills/stitch-ui-design-variants/SKILL.md +127 -0
  97. package/skills/stitch-ui-prompt-architect/SKILL.md +196 -0
  98. package/skills/stitch-ui-prompt-architect/references/KEYWORDS.md +170 -0
@@ -0,0 +1,333 @@
1
+ ---
2
+ name: stitch-react-native-components
3
+ description: Converts Stitch mobile designs into React Native / Expo components — TypeScript, StyleSheet, Expo Router, dark mode via useColorScheme, and proper touch targets. Cross-platform iOS and Android.
4
+ allowed-tools:
5
+ - "stitch*:*"
6
+ - "Bash"
7
+ - "Read"
8
+ - "Write"
9
+ ---
10
+
11
+ # Stitch → React Native / Expo Components
12
+
13
+ You are a React Native engineer. You convert Stitch mobile designs (deviceType: MOBILE) into cross-platform React Native components using Expo. You work in TypeScript, use `StyleSheet.create` for styles, and follow Expo Router conventions for navigation.
14
+
15
+ ## When to use this skill
16
+
17
+ Use this skill when:
18
+ - The user wants a **native mobile app** (iOS + Android) from a Stitch design
19
+ - The user mentions "React Native", "Expo", "mobile app", "iOS", "Android"
20
+ - The Stitch design was generated with `deviceType: MOBILE`
21
+
22
+ **Note:** For a mobile WebView app (Capacitor, Ionic, PWA), use `stitch-html-components` instead. React Native outputs actual native UI — not web views.
23
+
24
+ ## Prerequisites
25
+
26
+ - Stitch design generated with `deviceType: MOBILE` (desktop designs don't translate well to RN)
27
+ - Target project uses **Expo** (SDK 50+) — not bare React Native
28
+ - `expo-router` for file-based navigation
29
+
30
+ ## Step 1: Retrieve the design
31
+
32
+ Only call this skill for **MOBILE** Stitch designs. If the screenshot shows a desktop layout, stop and tell the user to regenerate with `deviceType: MOBILE` first.
33
+
34
+ 1. `list_tools` → find Stitch prefix
35
+ 2. `[prefix]:get_screen` → fetch design JSON
36
+ 3. Download HTML: `bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/source.html"`
37
+ 4. Check `screenshot.downloadUrl` — verify it's a mobile layout (narrow, vertical)
38
+
39
+ ## Step 2: Project structure
40
+
41
+ ```
42
+ app/
43
+ ├── (tabs)/
44
+ │ ├── _layout.tsx ← Tab navigator
45
+ │ ├── index.tsx ← Home tab
46
+ │ └── [other-tabs].tsx
47
+ ├── _layout.tsx ← Root layout (ThemeProvider, SafeAreaProvider)
48
+ └── modal.tsx ← Modal routes
49
+ src/
50
+ ├── components/ ← Reusable components
51
+ │ └── [Name].tsx
52
+ ├── data/
53
+ │ └── mockData.ts ← Static content — never hardcoded in components
54
+ ├── theme/
55
+ │ ├── tokens.ts ← Design tokens as TypeScript constants
56
+ │ └── useTheme.ts ← Hook to access current theme tokens
57
+ └── types/
58
+ └── index.ts
59
+ ```
60
+
61
+ ## Step 3: The HTML → React Native mapping
62
+
63
+ This is the core of the conversion. Apply these rules systematically:
64
+
65
+ ### Layout mapping
66
+
67
+ | HTML/CSS | → React Native |
68
+ |---|---|
69
+ | `<div style="display:flex; flex-direction:column">` | `<View style={{flexDirection:'column'}}>` |
70
+ | `<div style="display:flex; flex-direction:row">` | `<View style={{flexDirection:'row'}}>` |
71
+ | `<div style="display:grid; grid-template-columns:1fr 1fr">` | `<View style={{flexDirection:'row', flexWrap:'wrap'}}>` with `width:'50%'` children |
72
+ | `overflow-y: scroll` container | `<ScrollView>` |
73
+ | Long lists | `<FlatList data={items} renderItem={...} keyExtractor={...}>` |
74
+ | `position: fixed` bottom nav | `<View style={{position:'absolute', bottom:0, left:0, right:0}}>` |
75
+ | `position: absolute` overlay | `<View style={{position:'absolute', ...}}>` inside a parent with `position:'relative'` |
76
+
77
+ ### Content mapping
78
+
79
+ | HTML | → React Native |
80
+ |---|---|
81
+ | `<p>`, `<span>`, text nodes | `<Text>` |
82
+ | `<h1>` → `<h6>` | `<Text>` with large font size + fontWeight: 'bold' |
83
+ | `<img src="...">` | `<Image source={{uri: '...'}} style={{width:X, height:Y}}>` |
84
+ | `<button>` | `<Pressable>` (preferred) or `<TouchableOpacity>` |
85
+ | `<a>` (navigation) | `<Pressable onPress={() => router.push('/route')}>` |
86
+ | `<input type="text">` | `<TextInput>` |
87
+ | `<input type="password">` | `<TextInput secureTextEntry={true}>` |
88
+ | `<input type="checkbox">` | Custom or `@expo/vector-icons` + `Pressable` |
89
+ | `<select>` / dropdown | `@react-native-picker/picker` or custom modal picker |
90
+ | `<nav>` (tabs) | Expo Router `<Tabs>` layout |
91
+
92
+ ### Spacing mapping
93
+
94
+ React Native uses unitless numbers (dp — density-independent pixels):
95
+
96
+ ```ts
97
+ // Approximate Tailwind → RN
98
+ const spacing = {
99
+ 1: 4, // p-1 = 4dp
100
+ 2: 8, // p-2 = 8dp
101
+ 3: 12,
102
+ 4: 16,
103
+ 5: 20,
104
+ 6: 24,
105
+ 8: 32,
106
+ 10: 40,
107
+ 12: 48,
108
+ 16: 64,
109
+ }
110
+ ```
111
+
112
+ ### Color mapping
113
+
114
+ ```ts
115
+ // src/theme/tokens.ts — extract from Stitch Tailwind config
116
+ export const lightTokens = {
117
+ background: '#FFFFFF', // from --color-background
118
+ surface: '#F4F4F5',
119
+ primary: '#6366F1',
120
+ primaryFg: '#FFFFFF',
121
+ text: '#09090B',
122
+ textMuted: '#71717A',
123
+ border: '#E4E4E7',
124
+ } as const
125
+
126
+ export const darkTokens = {
127
+ background: '#09090B',
128
+ surface: '#18181B',
129
+ primary: '#818CF8', // Lighter shade for dark bg
130
+ primaryFg: '#09090B',
131
+ text: '#FAFAFA',
132
+ textMuted: '#A1A1AA',
133
+ border: '#27272A',
134
+ } as const
135
+
136
+ export type ThemeTokens = typeof lightTokens
137
+ ```
138
+
139
+ ## Step 4: Dark mode with useColorScheme
140
+
141
+ ```tsx
142
+ // src/theme/useTheme.ts
143
+ import { useColorScheme } from 'react-native'
144
+ import { lightTokens, darkTokens, type ThemeTokens } from './tokens'
145
+
146
+ /**
147
+ * Returns the current theme's design tokens.
148
+ * Automatically switches based on system color scheme.
149
+ */
150
+ export function useTheme(): ThemeTokens {
151
+ const scheme = useColorScheme()
152
+ return scheme === 'dark' ? darkTokens : lightTokens
153
+ }
154
+ ```
155
+
156
+ ```tsx
157
+ // Usage in any component
158
+ import { useTheme } from '@/theme/useTheme'
159
+
160
+ export function Card({ title }: { title: string }) {
161
+ const theme = useTheme()
162
+
163
+ return (
164
+ <View style={[styles.card, { backgroundColor: theme.surface, borderColor: theme.border }]}>
165
+ <Text style={[styles.title, { color: theme.text }]}>{title}</Text>
166
+ </View>
167
+ )
168
+ }
169
+
170
+ const styles = StyleSheet.create({
171
+ card: {
172
+ borderRadius: 12,
173
+ borderWidth: 1,
174
+ padding: 16,
175
+ marginBottom: 12,
176
+ },
177
+ title: {
178
+ fontSize: 16,
179
+ fontWeight: '600',
180
+ },
181
+ })
182
+ ```
183
+
184
+ ## Step 5: Safe area and platform considerations
185
+
186
+ ```tsx
187
+ // app/_layout.tsx — root layout
188
+ import { SafeAreaProvider } from 'react-native-safe-area-context'
189
+ import { Stack } from 'expo-router'
190
+
191
+ export default function RootLayout() {
192
+ return (
193
+ <SafeAreaProvider>
194
+ <Stack>
195
+ <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
196
+ </Stack>
197
+ </SafeAreaProvider>
198
+ )
199
+ }
200
+ ```
201
+
202
+ ```tsx
203
+ // In screen components — use safe area insets
204
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
205
+
206
+ export default function HomeScreen() {
207
+ const insets = useSafeAreaInsets()
208
+
209
+ return (
210
+ <View style={{ flex: 1, paddingTop: insets.top, paddingBottom: insets.bottom }}>
211
+ {/* Content */}
212
+ </View>
213
+ )
214
+ }
215
+ ```
216
+
217
+ ## Step 6: Component template
218
+
219
+ ```tsx
220
+ // src/components/StitchComponent.tsx
221
+ import { View, Text, Pressable, StyleSheet } from 'react-native'
222
+ import { useTheme } from '@/theme/useTheme'
223
+
224
+ /**
225
+ * Props for StitchComponent.
226
+ * All data via props — never fetched inside the component.
227
+ */
228
+ interface StitchComponentProps {
229
+ title: string
230
+ description?: string
231
+ onPress?: () => void
232
+ }
233
+
234
+ /**
235
+ * StitchComponent — [describe purpose in one sentence]
236
+ */
237
+ export function StitchComponent({ title, description, onPress }: Readonly<StitchComponentProps>) {
238
+ const theme = useTheme()
239
+
240
+ return (
241
+ <Pressable
242
+ style={({ pressed }) => [
243
+ styles.container,
244
+ {
245
+ backgroundColor: theme.surface,
246
+ borderColor: theme.border,
247
+ opacity: pressed ? 0.8 : 1, // Visual feedback on press
248
+ },
249
+ ]}
250
+ onPress={onPress}
251
+ accessible={true}
252
+ accessibilityRole="button"
253
+ accessibilityLabel={title}
254
+ hitSlop={8} // Increase tap area without changing visual size
255
+ >
256
+ <Text style={[styles.title, { color: theme.text }]}>{title}</Text>
257
+ {description ? (
258
+ <Text style={[styles.description, { color: theme.textMuted }]}>{description}</Text>
259
+ ) : null}
260
+ </Pressable>
261
+ )
262
+ }
263
+
264
+ const styles = StyleSheet.create({
265
+ container: {
266
+ borderRadius: 12,
267
+ borderWidth: 1,
268
+ padding: 16,
269
+ gap: 8,
270
+ // Minimum touch target
271
+ minHeight: 44,
272
+ },
273
+ title: {
274
+ fontSize: 16,
275
+ fontWeight: '600',
276
+ lineHeight: 24,
277
+ },
278
+ description: {
279
+ fontSize: 14,
280
+ lineHeight: 20,
281
+ },
282
+ })
283
+ ```
284
+
285
+ ## Step 7: Accessibility in React Native
286
+
287
+ ```tsx
288
+ // Every interactive element needs these props
289
+ <Pressable
290
+ accessible={true}
291
+ accessibilityRole="button" // "button" | "link" | "text" | "image" | "header" | ...
292
+ accessibilityLabel="Close dialog" // What screen reader announces
293
+ accessibilityHint="Double tap to close the modal" // Optional extra context
294
+ accessibilityState={{ disabled: false, selected: false }}
295
+ >
296
+
297
+ // Images
298
+ <Image
299
+ accessible={true}
300
+ accessibilityLabel="Profile photo of Emma Johnson" // Descriptive alt text
301
+ // OR for decorative:
302
+ accessible={false}
303
+ />
304
+
305
+ // Text hierarchy (screen reader uses accessibilityRole="header" for h1-h6 equivalent)
306
+ <Text accessibilityRole="header" style={styles.pageTitle}>Dashboard</Text>
307
+ ```
308
+
309
+ ## Execution steps
310
+
311
+ 1. **Verify** it's a MOBILE Stitch design
312
+ 2. **Data layer** — create `src/data/mockData.ts` from the static content in the design
313
+ 3. **Tokens** — create `src/theme/tokens.ts` from extracted colors, and `useTheme.ts`
314
+ 4. **Components** — convert each visual section to a component using the mapping rules above
315
+ 5. **Screen** — compose components in the Expo Router screen file (`app/(tabs)/index.tsx`)
316
+ 6. **Verify** — run `npx expo start` and test on both iOS Simulator and Android Emulator
317
+
318
+ ## Troubleshooting
319
+
320
+ | Issue | Fix |
321
+ |-------|-----|
322
+ | `StyleSheet.create` type error | Import `StyleSheet` from `'react-native'` |
323
+ | Text outside `<Text>` error | Every string must be inside `<Text>` — even `{' '}` spaces |
324
+ | Flex layout looks wrong | RN defaults to `flexDirection:'column'` — explicit is safer |
325
+ | Image not showing | Requires explicit `width` and `height` on the style |
326
+ | Keyboard pushes layout up | Use `KeyboardAvoidingView` with `behavior='padding'` on iOS |
327
+ | Bottom safe area overlap | Use `useSafeAreaInsets()` from `react-native-safe-area-context` |
328
+
329
+ ## References
330
+
331
+ - `resources/component-template.tsx` — Boilerplate RN component
332
+ - `resources/architecture-checklist.md` — Pre-ship checklist
333
+ - `scripts/fetch-stitch.sh` — Reliable GCS HTML downloader
@@ -0,0 +1,74 @@
1
+ # React Native Components — Architecture Checklist
2
+
3
+ Run through this checklist before marking the task complete.
4
+
5
+ ## Structure
6
+
7
+ - [ ] Components are in `src/components/` — one file per component
8
+ - [ ] Screen files are in `app/(tabs)/` or `app/` (Expo Router conventions)
9
+ - [ ] Static content is in `src/data/mockData.ts`, not hardcoded in JSX
10
+ - [ ] Shared TypeScript types are in `src/types/index.ts`
11
+ - [ ] Theme tokens are in `src/theme/tokens.ts` with `lightTokens` and `darkTokens`
12
+ - [ ] `useTheme()` hook is in `src/theme/useTheme.ts`
13
+ - [ ] Each component has a `Readonly<ComponentNameProps>` interface
14
+
15
+ ## React Native basics
16
+
17
+ - [ ] Every string is inside a `<Text>` component — no bare strings in JSX
18
+ - [ ] All layout uses `StyleSheet.create` (static values) + inline objects (dynamic theme values)
19
+ - [ ] No hardcoded hex colors in `StyleSheet.create` — theme values go inline
20
+ - [ ] All `<Image>` components have explicit `width` and `height` in their style
21
+ - [ ] `<ScrollView>` is used instead of `overflow-y: scroll` divs
22
+ - [ ] Long lists use `<FlatList>` with `keyExtractor`, not `<ScrollView>` + `map()`
23
+
24
+ ## Touch and interaction
25
+
26
+ - [ ] All interactive elements use `<Pressable>` (not `<TouchableOpacity>` or `<View onPress>`)
27
+ - [ ] `hitSlop={8}` or larger on all small tap targets
28
+ - [ ] Minimum touch target: 44×44 dp (`minHeight: 44, minWidth: 44`)
29
+ - [ ] Press visual feedback: `style={({ pressed }) => [styles.x, { opacity: pressed ? 0.8 : 1 }]}`
30
+ - [ ] No nested `<Pressable>` elements (causes gesture conflicts)
31
+
32
+ ## Safe area and platform
33
+
34
+ - [ ] `<SafeAreaProvider>` wraps the root layout in `app/_layout.tsx`
35
+ - [ ] Screen-level components use `useSafeAreaInsets()` for top/bottom padding
36
+ - [ ] Bottom navigation doesn't overlap home indicator on iPhone
37
+ - [ ] Keyboard handling: `<KeyboardAvoidingView behavior="padding">` on iOS forms
38
+ - [ ] Platform differences (if any) are handled with `Platform.OS === 'ios'`
39
+
40
+ ## TypeScript
41
+
42
+ - [ ] No `any` types
43
+ - [ ] Theme tokens typed as `ThemeTokens` (inferred from `typeof lightTokens`)
44
+ - [ ] All component props use `Readonly<>`
45
+ - [ ] No `@ts-ignore` without explaining why
46
+
47
+ ## Dark mode
48
+
49
+ - [ ] `useTheme()` hook is used in every component that renders colors
50
+ - [ ] No hardcoded `'#FFFFFF'` or `'#000000'` — use `theme.background`, `theme.text`
51
+ - [ ] Tested: toggle device to dark mode — no elements disappear or become unreadable
52
+
53
+ ## Accessibility
54
+
55
+ - [ ] All `<Pressable>` elements have `accessible={true}`, `accessibilityRole`, and `accessibilityLabel`
56
+ - [ ] Decorative `<Image>` elements have `accessible={false}`
57
+ - [ ] Content images have `accessibilityLabel` describing the image
58
+ - [ ] Page titles use `accessibilityRole="header"` on the heading `<Text>`
59
+ - [ ] Related elements grouped with `accessibilityViewIsModal` or `.accessibilityElement(children: .combine)` equivalent
60
+
61
+ ## Performance
62
+
63
+ - [ ] No `console.log` in production code
64
+ - [ ] `StyleSheet.create` used for static styles (hoisted outside render)
65
+ - [ ] `FlatList` used for any list of 10+ items
66
+ - [ ] `useCallback` / `useMemo` used where referential equality matters (event handlers passed to children)
67
+ - [ ] `React.memo` on pure leaf components that receive stable props
68
+
69
+ ## Expo Router
70
+
71
+ - [ ] Navigation uses `router.push('/route')` — no hardcoded `navigation.navigate`
72
+ - [ ] Tab layout uses Expo Router `<Tabs>` — not `react-navigation` directly
73
+ - [ ] Deep link paths match the file structure in `app/`
74
+ - [ ] `app/_layout.tsx` has `<SafeAreaProvider>` and `<Stack>` (or `<Tabs>`)
@@ -0,0 +1,104 @@
1
+ /**
2
+ * StitchComponent.tsx
3
+ *
4
+ * Generated from Stitch design via stitch-react-native-components skill.
5
+ * Replace "StitchComponent" with the actual component name throughout.
6
+ *
7
+ * File location: src/components/StitchComponent.tsx
8
+ */
9
+
10
+ import { StyleSheet, Text, Pressable, View } from 'react-native'
11
+ import { useTheme } from '@/theme/useTheme'
12
+
13
+ // ------------------------------------------------------------
14
+ // Types
15
+ // ------------------------------------------------------------
16
+
17
+ /**
18
+ * Props for StitchComponent.
19
+ * All data via props — never fetched inside the component.
20
+ */
21
+ interface StitchComponentProps {
22
+ /** Primary heading text */
23
+ title: string
24
+ /** Supporting description text — optional */
25
+ description?: string
26
+ /** Callback when the component is pressed */
27
+ onPress?: () => void
28
+ }
29
+
30
+ // ------------------------------------------------------------
31
+ // Component
32
+ // ------------------------------------------------------------
33
+
34
+ /**
35
+ * StitchComponent — [describe purpose in one sentence]
36
+ */
37
+ export function StitchComponent({
38
+ title,
39
+ description,
40
+ onPress,
41
+ }: Readonly<StitchComponentProps>) {
42
+ const theme = useTheme()
43
+
44
+ return (
45
+ <Pressable
46
+ // Visual press feedback via the style callback
47
+ style={({ pressed }) => [
48
+ styles.container,
49
+ {
50
+ backgroundColor: theme.surface,
51
+ borderColor: theme.border,
52
+ opacity: pressed ? 0.8 : 1,
53
+ },
54
+ ]}
55
+ onPress={onPress}
56
+ // Accessibility — required for screen readers
57
+ accessible={true}
58
+ accessibilityRole="button"
59
+ accessibilityLabel={title}
60
+ // Extend tap area without changing visual size
61
+ hitSlop={8}
62
+ >
63
+ {/* Title */}
64
+ <Text style={[styles.title, { color: theme.text }]}>
65
+ {title}
66
+ </Text>
67
+
68
+ {/* Description — only render when provided */}
69
+ {description ? (
70
+ <Text style={[styles.description, { color: theme.textMuted }]}>
71
+ {description}
72
+ </Text>
73
+ ) : null}
74
+ </Pressable>
75
+ )
76
+ }
77
+
78
+ // ------------------------------------------------------------
79
+ // Styles
80
+ // ------------------------------------------------------------
81
+
82
+ /**
83
+ * StyleSheet.create hoists styles outside the render function.
84
+ * Dynamic values (from theme) go inline — static values go here.
85
+ */
86
+ const styles = StyleSheet.create({
87
+ container: {
88
+ borderRadius: 12,
89
+ borderWidth: 1,
90
+ padding: 16,
91
+ gap: 8,
92
+ // Apple HIG / Material minimum touch target
93
+ minHeight: 44,
94
+ },
95
+ title: {
96
+ fontSize: 16,
97
+ fontWeight: '600',
98
+ lineHeight: 24,
99
+ },
100
+ description: {
101
+ fontSize: 14,
102
+ lineHeight: 20,
103
+ },
104
+ })
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env bash
2
+ # fetch-stitch.sh
3
+ # Reliably downloads Stitch HTML from Google Cloud Storage URLs.
4
+ # GCS URLs require redirect handling and specific security handshakes that
5
+ # AI fetch tools often fail on. This script handles both.
6
+ #
7
+ # Usage:
8
+ # bash scripts/fetch-stitch.sh "<url>" "<output-path>"
9
+ #
10
+ # Example:
11
+ # bash scripts/fetch-stitch.sh "$htmlCode_downloadUrl" "temp/source.html"
12
+
13
+ set -euo pipefail
14
+
15
+ URL="${1:?Usage: fetch-stitch.sh <url> <output-path>}"
16
+ OUTPUT="${2:?Usage: fetch-stitch.sh <url> <output-path>}"
17
+
18
+ # Create output directory if it doesn't exist
19
+ mkdir -p "$(dirname "$OUTPUT")"
20
+
21
+ # Use curl with:
22
+ # -L : follow redirects (GCS uses multiple redirect hops)
23
+ # -A : set User-Agent to avoid bot blocking
24
+ # --compressed : handle gzip responses
25
+ # --retry 3 : retry on transient failures
26
+ # --retry-delay 1 : wait 1s between retries
27
+ # --max-time 30 : don't hang forever
28
+ curl -L \
29
+ -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
30
+ --compressed \
31
+ --retry 3 \
32
+ --retry-delay 1 \
33
+ --max-time 30 \
34
+ --silent \
35
+ --show-error \
36
+ --output "$OUTPUT" \
37
+ "$URL"
38
+
39
+ # Verify the download succeeded and is not empty
40
+ if [ ! -s "$OUTPUT" ]; then
41
+ echo "Error: Downloaded file is empty. URL may be expired or invalid." >&2
42
+ exit 1
43
+ fi
44
+
45
+ echo "Downloaded to: $OUTPUT ($(wc -c < "$OUTPUT") bytes)"