Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions skills/react-native-components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Stitch to React Native Components Skill

Converts Stitch designs into modular React Native components with platform-aware styling, performance best practices, and automated validation.

## Install

```bash
npx skills add google-labs-code/stitch-skills --skill react-native-components --global
```

## Example Prompt

```text
Convert my Dashboard screen in my Fitness Stitch Project to a React Native component system.
```

## Skill Structure

This repository follows the **Agent Skills** open standard. Each skill is self-contained with its own logic, validation scripts, and design tokens.

```text
skills/react-native-components/
├── SKILL.md — Core instructions & workflow
├── README.md — This file
├── scripts/ — Networking & validation
├── resources/ — Style guides & API references
└── examples/ — Gold-standard code samples
```

## How it Works

When activated, the agent follows a high-fidelity engineering pipeline:

1. **Retrieval**: Uses a system-level `curl` script to bypass TLS/SNI issues on Google Cloud Storage.
2. **Mapping**: Cross-references Stitch metadata with the local `style-guide.json` to ensure token consistency.
3. **Conversion**: Maps HTML/CSS primitives to React Native equivalents (`<div>` → `<View>`, `<span>` → `<Text>`, etc.).
4. **Generation**: Scaffolds components using native primitives with `StyleSheet.create()` styling.
5. **Platform Handling**: Applies `Platform.select()` for iOS/Android differences, safe area wrapping, and keyboard handling.
6. **Audit**: Performs a final self-correction check against the architecture checklist.

## Works With

- **`stitch-design` skill**: Generate and refine designs before converting to React Native components.
- **`design-md` skill**: Extract the design system for consistent theming across screens.
- **`stitch-loop` skill**: Autonomous multi-screen generation with React Native output.

## Learn More

See [SKILL.md](./SKILL.md) for complete instructions.
108 changes: 108 additions & 0 deletions skills/react-native-components/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
name: react-native-components
description: Converts Stitch designs into modular React Native components with platform-aware styling, performance best practices, and automated validation.
allowed-tools:
- "stitch*:*"
- "Bash"
- "Read"
- "Write"
- "web_fetch"
---

# Stitch to React Native Components

You are a mobile engineer focused on transforming Stitch designs into clean, performant React Native code. You follow a modular approach, handle platform-specific concerns, and use automated tools to ensure code quality.

## Retrieval and Networking
1. **Namespace discovery**: Run `list_tools` to find the Stitch MCP prefix. Use this prefix (e.g., `stitch:`) for all subsequent calls.
2. **Metadata fetch**: Call `[prefix]:get_screen` to retrieve the design JSON.
3. **Check for existing designs**: Before downloading, check if `.stitch/designs/{page}.html` and `.stitch/designs/{page}.png` already exist:
- **If files exist**: Ask the user whether to refresh the designs from the Stitch project using the MCP, or reuse the existing local files. Only re-download if the user confirms.
- **If files do not exist**: Proceed to step 4.
4. **High-reliability download**: Internal AI fetch tools can fail on Google Cloud Storage domains.
- **HTML**: `bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" ".stitch/designs/{page}.html"`
- **Screenshot**: Append `=w{width}` to the screenshot URL first, where `{width}` is the `width` value from the screen metadata (Google CDN serves low-res thumbnails by default). Then run: `bash scripts/fetch-stitch.sh "[screenshot.downloadUrl]=w{width}" ".stitch/designs/{page}.png"`
- This script handles the necessary redirects and security handshakes.
5. **Visual audit**: Review the downloaded screenshot (`.stitch/designs/{page}.png`) to confirm design intent and layout details.

## Architectural Rules
* **Modular components**: Break the design into independent files under `src/components/`. Avoid large, single-file outputs.
* **Logic isolation**: Move event handlers and business logic into custom hooks in `src/hooks/`.
* **Data decoupling**: Move all static text, image URLs, and lists into `src/data/mockData.ts`.
* **Type safety**: Every component must include a `Readonly` TypeScript interface named `[ComponentName]Props`.
* **Project specific**: Focus on the target project's needs and constraints. Leave Google license headers out of the generated React Native components.
* **Native primitives**: Use React Native core components (`View`, `Text`, `Image`, `ScrollView`, `FlatList`, `Pressable`, `TextInput`) instead of HTML elements.
* **Style mapping**:
* Extract the design tokens from the Stitch HTML `<head>`.
* Sync these values with `resources/style-guide.json`.
* Use `StyleSheet.create()` with theme-mapped values instead of arbitrary inline styles.

## Platform-Specific Guidelines
* **Platform handling**: Use `Platform.select()` or `Platform.OS` conditionals for iOS/Android differences.
* **Safe areas**: Wrap top-level screens with `SafeAreaView` from `react-native-safe-area-context`.
* **Keyboard handling**: Use `KeyboardAvoidingView` with `behavior` set to `padding` on iOS and `height` on Android for screens with text inputs.
* **Touch targets**: Ensure all interactive elements have a minimum touch target of 44×44 points.
* **Status bar**: Account for status bar height differences across platforms.

## Performance Best Practices
* **FlatList over ScrollView**: Use `FlatList` or `SectionList` for dynamic lists to enable virtualization.
* **Memoization**: Apply `React.memo()` to pure display components and `useMemo`/`useCallback` for expensive computations and callbacks.
* **Image optimization**: Use `resizeMode` and provide explicit `width`/`height` props on `Image` components.
* **Avoid anonymous functions**: Do not pass anonymous arrow functions directly to `onPress` or `renderItem` — extract them to named functions or use `useCallback`.

## Styling Approach
* **StyleSheet.create()**: Define all styles using `StyleSheet.create()` at the bottom of each component file.
* **Theme tokens**: Reference design tokens from `resources/style-guide.json` for colors, spacing, and typography.
* **No hardcoded values**: Never use raw hex colors or magic numbers — map everything to theme constants.
* **NativeWind support**: If the project uses NativeWind (Tailwind CSS for React Native), use `className` props instead of `StyleSheet`. Check the project's configuration before deciding.
* **Dark mode**: Support dark mode via `useColorScheme()` hook or theme provider pattern.

## Execution Steps
1. **Environment setup**: Verify the React Native project structure exists. If starting from scratch, ensure `package.json` includes `react-native` and `typescript` dependencies.
2. **Data layer**: Create `src/data/mockData.ts` based on the design content.
3. **Theme setup**: Create or update `src/theme/tokens.ts` with colors, spacing, and typography from the Stitch design.
4. **Component drafting**: Use `resources/component-template.tsx` as a base. Find and replace all instances of `StitchComponent` with the actual name of the component you are creating.
5. **Application wiring**: Update the project entry point or navigation to render the new components.
6. **Quality check**:
* Verify the output against the `resources/architecture-checklist.md`.
* Ensure all components use native primitives (no `<div>`, `<span>`, `<p>` elements).
* Check that platform-specific code is properly handled.
* Start the dev server with `npx react-native start` or `npx expo start` to verify the live result.

## Stitch HTML to React Native Mapping

When converting Stitch designs (which output HTML/CSS), apply these mappings:

| HTML Element | React Native Equivalent |
|:---|:---|
| `<div>` | `<View>` |
| `<span>`, `<p>`, `<h1>`–`<h6>` | `<Text>` (with appropriate styles) |
| `<img>` | `<Image>` |
| `<button>`, `<a>` | `<Pressable>` or `<TouchableOpacity>` |
| `<input>` | `<TextInput>` |
| `<ul>` / `<li>` (dynamic) | `<FlatList>` |
| `<ul>` / `<li>` (static) | `<View>` + mapped `<Text>` |
| `<svg>` | `react-native-svg` or icon library |
| `overflow: scroll` | `<ScrollView>` |

### CSS to StyleSheet Mapping

| CSS Property | React Native Style |
|:---|:---|
| `display: flex` | Default (all Views are flex) |
| `flex-direction: row` | `flexDirection: 'row'` |
| `justify-content` | `justifyContent` |
| `align-items` | `alignItems` |
| `padding: 16px` | `padding: 16` (unitless) |
| `border-radius: 8px` | `borderRadius: 8` |
| `background-color` | `backgroundColor` |
| `font-size: 16px` | `fontSize: 16` |
| `font-weight: bold` | `fontWeight: 'bold'` |
| `box-shadow` | `shadowColor`, `shadowOffset`, `shadowOpacity`, `shadowRadius` (iOS) / `elevation` (Android) |
| `opacity` | `opacity` |

## Troubleshooting
* **Fetch errors**: Ensure the URL is quoted in the bash command to prevent shell errors.
* **Style errors**: React Native does not support all CSS properties. Remove unsupported properties like `box-shadow` (use platform-specific shadow props instead).
* **Text nesting**: All text content in React Native must be wrapped in `<Text>` components. Raw strings inside `<View>` will cause crashes.
* **Image source**: Use `source={{ uri: '...' }}` for remote images and `source={require('...')}` for local assets.
158 changes: 158 additions & 0 deletions skills/react-native-components/examples/gold-standard-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/**
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import React from 'react';
import { View, Text, Image, Pressable, StyleSheet } from 'react-native';
// Note for Agent: Ensure src/data/mockData.ts is created before generating this component.
// import { cardData } from '../data/mockData';

/**
* Gold Standard: ActivityCard (React Native)
* This file serves as the definitive reference for the agent.
*/
interface ActivityCardProps {
readonly id: string;
readonly username: string;
readonly action: 'MERGED' | 'COMMIT';
readonly timestamp: string;
readonly avatarUrl: string;
readonly repoName: string;
}

export const ActivityCard: React.FC<ActivityCardProps> = React.memo(({
username,
action,
timestamp,
avatarUrl,
repoName,
}) => {
const isMerged = action === 'MERGED';

return (
<View style={styles.container}>
<View style={styles.leftSection}>
<Image
source={{ uri: avatarUrl }}
style={styles.avatar}
accessibilityLabel={`Avatar for ${username}`}
/>

<View style={styles.infoSection}>
<Pressable accessibilityRole="link">
<Text style={styles.username}>{username}</Text>
</Pressable>

<View style={[
styles.badge,
isMerged ? styles.badgeMerged : styles.badgeCommit,
]}>
<Text style={[
styles.badgeText,
isMerged ? styles.badgeTextMerged : styles.badgeTextCommit,
]}>
{action}
</Text>
</View>

<Text style={styles.inText}>in</Text>

<Pressable accessibilityRole="link">
<Text style={styles.repoName}>{repoName}</Text>
</Pressable>
</View>
</View>

<View>
<Text style={styles.timestamp}>{timestamp}</Text>
</View>
</View>
);
});

ActivityCard.displayName = 'ActivityCard';

const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: 16,
borderRadius: 8,
backgroundColor: '#1A1A1A',
padding: 16,
minHeight: 56,
},
leftSection: {
flexDirection: 'row',
alignItems: 'center',
gap: 16,
flex: 1,
overflow: 'hidden',
},
avatar: {
width: 40,
height: 40,
borderRadius: 20,
},
infoSection: {
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
columnGap: 8,
rowGap: 4,
},
username: {
fontWeight: '600',
color: '#19e66f',
fontSize: 14,
},
badge: {
paddingHorizontal: 8,
paddingVertical: 2,
borderRadius: 9999,
},
badgeMerged: {
backgroundColor: 'rgba(138, 43, 226, 0.3)',
},
badgeCommit: {
backgroundColor: 'rgba(25, 230, 111, 0.3)',
},
badgeText: {
fontSize: 12,
fontWeight: '600',
},
badgeTextMerged: {
color: '#D0A9F5',
},
badgeTextCommit: {
color: '#19e66f',
},
inText: {
color: 'rgba(255, 255, 255, 0.6)',
fontSize: 14,
},
repoName: {
color: '#19e66f',
fontSize: 14,
},
timestamp: {
fontSize: 14,
fontWeight: '400',
color: 'rgba(255, 255, 255, 0.5)',
},
});

export default ActivityCard;
33 changes: 33 additions & 0 deletions skills/react-native-components/resources/architecture-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Architecture Quality Gate — React Native

### Structural integrity
- [ ] Logic extracted to custom hooks in `src/hooks/`.
- [ ] No monolithic files; strictly modular component decomposition.
- [ ] All static text/URLs moved to `src/data/mockData.ts`.

### Type safety and syntax
- [ ] Props use `Readonly<T>` interfaces.
- [ ] File is syntactically valid TypeScript (no red squiggles).
- [ ] Placeholders from templates (e.g., `StitchComponent`) have been replaced with actual names.

### Native primitives
- [ ] Only React Native primitives used (`View`, `Text`, `Image`, `Pressable`, etc.).
- [ ] No HTML elements (`<div>`, `<span>`, `<p>`, `<button>`, `<img>`).
- [ ] All text content wrapped in `<Text>` components.
- [ ] Dynamic lists use `FlatList` or `SectionList` instead of mapped `ScrollView`.

### Styling and theming
- [ ] All styles defined via `StyleSheet.create()` (or `className` if NativeWind is configured).
- [ ] No hardcoded hex values; use theme-mapped constants from `style-guide.json`.
- [ ] Dark mode supported via `useColorScheme()` or theme provider.

### Platform handling
- [ ] iOS/Android differences handled via `Platform.select()` or `Platform.OS`.
- [ ] Screens wrapped with `SafeAreaView` where appropriate.
- [ ] Forms use `KeyboardAvoidingView` with correct `behavior` per platform.
- [ ] All interactive elements have minimum 44×44 point touch targets.

### Performance
- [ ] Pure display components wrapped with `React.memo()`.
- [ ] No anonymous arrow functions in `onPress` or `renderItem` props.
- [ ] Images specify explicit dimensions and `resizeMode`.
43 changes: 43 additions & 0 deletions skills/react-native-components/resources/component-template.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import React from 'react';
import { View, StyleSheet } from 'react-native';

// Use a valid identifier like 'StitchComponent' as the placeholder
interface StitchComponentProps {
readonly children?: React.ReactNode;
readonly style?: object;
}

export const StitchComponent: React.FC<StitchComponentProps> = ({
children,
style,
}) => {
return (
<View style={[styles.container, style]}>
{children}
</View>
);
};

const styles = StyleSheet.create({
container: {
position: 'relative',
},
});

export default StitchComponent;
Loading