diff --git a/.claude/skills/expo-skill-eval/references/runtime-matrix.md b/.claude/skills/expo-skill-eval/references/runtime-matrix.md index edcc9b3..aa65f97 100644 --- a/.claude/skills/expo-skill-eval/references/runtime-matrix.md +++ b/.claude/skills/expo-skill-eval/references/runtime-matrix.md @@ -10,7 +10,8 @@ Modes: | Skill | Mode | Platforms | Notes | |-------|------|-----------|-------| -| building-native-ui | expo-go | ios, android | Core target for visual evals. Expo Router + RN primitives all work in Expo Go. Native tabs sections may need a dev build — verify per case. | +| building-native-ui | expo-go | ios, android | Core target for visual evals. RN primitives + styling/controls/media/animations all work in Expo Go. | +| expo-router | expo-go | ios, android | Navigation/routing target: routes, links, native stacks, modals, sheets, headers. Native tabs sections may need a dev build — verify per case. | | expo-tailwind-setup | expo-go | ios, android, web | NativeWind v5 / react-native-css are JS-level; works in Expo Go. Good web candidate too. | | native-data-fetching | expo-go | ios, android | Fetch/React Query/SWR are pure JS. Mock or use stable public endpoints so evals are deterministic. | | use-dom | expo-go | ios, android, web | DOM components run in a webview on native (Expo Go, SDK 52+) and as-is on web. Allow extra settle time for the webview to paint. | diff --git a/README.md b/README.md index bfcb79d..140bab1 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,8 @@ Agents choose the right skill from the task context and each skill's description | Skill | Use it for | | --- | --- | -| `building-native-ui` | Expo Router screens, navigation, styling, animations, native tabs, and app UI patterns. | +| `building-native-ui` | Native-feeling screen styling, semantic colors, controls, icons, media, animations, and visual effects. | +| `expo-router` | Expo Router navigation: file-based routes, links, native stacks, modals, sheets, native tabs, and headers. | | `native-data-fetching` | API calls, React Query, SWR, caching, offline support, and Expo Router data loaders. | | `expo-api-routes` | Expo Router API routes with EAS Hosting. | | `expo-tailwind-setup` | Tailwind CSS v4, `react-native-css`, and NativeWind v5 setup. | diff --git a/plugins/expo/.claude-plugin/plugin.json b/plugins/expo/.claude-plugin/plugin.json index 934048f..535e84b 100644 --- a/plugins/expo/.claude-plugin/plugin.json +++ b/plugins/expo/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "expo", - "version": "1.5.1", + "version": "1.6.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo apps", "author": { "name": "Expo Team", diff --git a/plugins/expo/.codex-plugin/plugin.json b/plugins/expo/.codex-plugin/plugin.json index abae19d..afedcb4 100644 --- a/plugins/expo/.codex-plugin/plugin.json +++ b/plugins/expo/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "expo", - "version": "1.5.1", + "version": "1.6.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo and React Native apps.", "author": { "name": "Expo Team", diff --git a/plugins/expo/.cursor-plugin/plugin.json b/plugins/expo/.cursor-plugin/plugin.json index 99d5fac..0175432 100644 --- a/plugins/expo/.cursor-plugin/plugin.json +++ b/plugins/expo/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "expo", "displayName": "Expo", - "version": "1.5.1", + "version": "1.6.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo and React Native apps.", "author": { "name": "Expo Team", diff --git a/plugins/expo/README.md b/plugins/expo/README.md index 9093104..1ef9ea8 100644 --- a/plugins/expo/README.md +++ b/plugins/expo/README.md @@ -65,10 +65,11 @@ Official AI agent skills from the Expo team for building, deploying, upgrading, ### App Design - **add-app-clip** — Add an iOS App Clip target to an Expo app (AASA, associated domains, TestFlight) -- **building-native-ui** — Build beautiful apps with Expo Router, styling, components, navigation, and animations +- **building-native-ui** — Build beautiful native-feeling screens: styling, semantic colors, controls, icons, media, animations, and visual effects - **expo-api-routes** — Create API routes in Expo Router with EAS Hosting - **expo-brownfield** — Integrate Expo and React Native into existing native iOS or Android apps - **expo-dev-client** — Build and distribute Expo development clients locally or via TestFlight +- **expo-router** — Navigation and routing: file-based routes, links, native stacks, modals, sheets, native tabs, and headers - **expo-tailwind-setup** — Set up Tailwind CSS v4 in Expo with NativeWind v5 - **expo-ui** — Native UI with @expo/ui: universal cross-platform components first, with SwiftUI and Jetpack Compose for platform-specific needs - **native-data-fetching** — Network requests, API calls, caching, and offline support diff --git a/plugins/expo/skills/building-native-ui/SKILL.md b/plugins/expo/skills/building-native-ui/SKILL.md index 4d302ca..44ceb2b 100644 --- a/plugins/expo/skills/building-native-ui/SKILL.md +++ b/plugins/expo/skills/building-native-ui/SKILL.md @@ -1,12 +1,14 @@ --- name: building-native-ui -description: Complete guide for building beautiful apps with Expo Router. Covers fundamentals, styling, components, navigation, animations, patterns, and native tabs. -version: 1.0.1 +description: Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, animations, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill. +version: 1.1.0 license: MIT --- # Expo UI Guidelines +For routes, links, stacks, tabs, modals, sheets, and headers, use the `expo-router` skill. + ## References Consult these resources as needed: @@ -15,18 +17,12 @@ Consult these resources as needed: references/ animations.md Reanimated: entering, exiting, layout, scroll-driven, gestures controls.md Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker - form-sheet.md Form sheets in expo-router: configuration, footers and background interaction. gradients.md CSS gradients via experimental_backgroundImage (New Arch only) icons.md SF Symbols via expo-image (sf: source), names, animations, weights media.md Camera, audio, video, and file saving - route-structure.md Route conventions, dynamic routes, groups, folder organization - search.md Search bar with headers, useSearch hook, filtering patterns storage.md SQLite, AsyncStorage, SecureStore - tabs.md NativeTabs, migration from JS tabs, iOS 26 features - toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only) visual-effects.md Blur (expo-blur) and liquid glass (expo-glass-effect) webgpu-three.md 3D graphics, games, GPU visualizations with WebGPU and Three.js - zoom-transitions.md Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+) ``` ## Running the App @@ -64,18 +60,9 @@ Expo Go supports a huge range of features out of the box: - Be cautious of unterminated strings. Ensure nested backticks are escaped; never forget to escape quotes correctly. - Always use import statements at the top of the file. - Always use kebab-case for file names, e.g. `comment-card.tsx` -- Always remove old route files when moving or restructuring navigation - Never use special characters in file names - Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors. -## Routes - -See `./references/route-structure.md` for detailed route conventions. - -- Routes belong in the `app` directory. -- Never co-locate components, types, or utilities in the app directory. This is an anti-pattern. -- Ensure the app always has a route that matches "/", it may be inside a group route. - ## Library Preferences - Never use modules removed from React Native such as Picker, WebView, SafeAreaView, or AsyncStorage @@ -105,7 +92,6 @@ See `./references/route-structure.md` for detailed route conventions. - Use views with built-in haptics like `` from React Native and `@react-native-community/datetimepicker` - When a route belongs to a Stack, its first child should almost always be a ScrollView with `contentInsetAdjustmentBehavior="automatic"` set - When adding a `ScrollView` to the page it should almost always be the first component inside the route component -- Prefer `headerSearchBarOptions` in Stack.Screen options to add a search bar - Use the `` prop on text containing data that could be copied - Consider formatting large numbers like 1.4M or 38k - Never use intrinsic elements like 'img' or 'div' unless in a webview or Expo DOM component @@ -193,185 +179,3 @@ Use CSS `boxShadow` style prop. NEVER use legacy React Native shadow or elevatio ``` 'inset' shadows are supported. - -# Navigation - -## Link - -Use `` from 'expo-router' for navigation between routes. - -```tsx -import { Link } from 'expo-router'; - -// Basic link - - -// Wrapping custom components - - ... - -``` - -Whenever possible, include a `` to follow iOS conventions. Add context menus and previews frequently to enhance navigation. - -## Stack - -- ALWAYS use `_layout.tsx` files to define stacks -- Use Stack from 'expo-router/stack' for native navigation stacks - -### Page Title - -Set the page title in Stack.Screen options: - -```tsx - -``` - -## Context Menus - -Add long press context menus to Link components: - -```tsx -import { Link } from "expo-router"; - - - - - - - - - - - - {}} /> - {}} - /> - - -; -``` - -## Link Previews - -Use link previews frequently to enhance navigation: - -```tsx - - - - - - - - -``` - -Link preview can be used with context menus. - -## Modal - -Present a screen as a modal: - -```tsx - -``` - -Prefer this to building a custom modal component. - -## Sheet - -Present a screen as a dynamic form sheet: - -```tsx - -``` - -- Using `contentStyle: { backgroundColor: "transparent" }` makes the background liquid glass on iOS 26+. - -## Common route structure - -A standard app layout with tabs and stacks inside each tab: - -``` -app/ - _layout.tsx — - (index,search)/ - _layout.tsx — - index.tsx — Main list - search.tsx — Search view -``` - -```tsx -// app/_layout.tsx -import { NativeTabs } from "expo-router/unstable-native-tabs"; -import { ThemeProvider, DarkTheme, DefaultTheme } from "expo-router/react-navigation"; -import { useColorScheme } from "react-native"; - -export default function Layout() { - const colorScheme = useColorScheme(); - return ( - - - - - Items - - - - - ); -} -``` - -Create a shared group route so both tabs can push common screens: - -```tsx -// app/(index,search)/_layout.tsx -import { Stack } from "expo-router/stack"; -import { colors } from "@/theme/colors"; - -export default function Layout({ segment }) { - const screen = segment.match(/\((.*)\)/)?.[1]!; - const titles: Record = { index: "Items", search: "Search" }; - - return ( - - - - - ); -} -``` diff --git a/plugins/expo/skills/expo-examples/SKILL.md b/plugins/expo/skills/expo-examples/SKILL.md index 8b1cebc..cb22926 100644 --- a/plugins/expo/skills/expo-examples/SKILL.md +++ b/plugins/expo/skills/expo-examples/SKILL.md @@ -89,6 +89,7 @@ When the user already has an app, **add only what the example introduces; never - Tailwind / NativeWind styling → `expo-tailwind-setup` - Native UI components → `building-native-ui` +- Navigation and routing → `expo-router` - Authoring a native module → `expo-module` - Upgrade the SDK before adopting a latest-SDK example → `upgrading-expo` diff --git a/plugins/expo/skills/expo-router/SKILL.md b/plugins/expo/skills/expo-router/SKILL.md new file mode 100644 index 0000000..df98c81 --- /dev/null +++ b/plugins/expo/skills/expo-router/SKILL.md @@ -0,0 +1,230 @@ +--- +name: expo-router +description: Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars. +version: 1.0.0 +license: MIT +--- + +# Expo Router Navigation + +Navigation and routing for Expo Router apps. For screen styling, colors, controls, animations, media, and visual effects, use the `building-native-ui` skill. + +## References + +Consult these resources as needed: + +``` +references/ + route-structure.md Route conventions, dynamic routes, groups, folder organization + tabs.md NativeTabs, migration from JS tabs, iOS 26 features + toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only) + form-sheet.md Form sheets in expo-router: configuration, footers and background interaction. + search.md Search bar with headers, useSearch hook, filtering patterns + zoom-transitions.md Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+) +``` + +## Code Style + +- Always use kebab-case for file names, e.g. `comment-card.tsx` +- Always remove old route files when moving or restructuring navigation +- Never use special characters in file names +- Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors. + +## Routes + +See `./references/route-structure.md` for detailed route conventions. + +- Routes belong in the `app` directory. +- Never co-locate components, types, or utilities in the app directory. This is an anti-pattern. +- Ensure the app always has a route that matches "/", it may be inside a group route. + +## Library Preferences + +- `Color` from `expo-router` for native semantic colors, not raw `PlatformColor` (type-safe, auto-adapts to light/dark). See `building-native-ui` for the full color palette pattern. +- In SDK 56+, never import from `@react-navigation/*` directly — use `expo-router/react-navigation` instead (covers `@react-navigation/native`, `/core`, `/elements`, `/routers`) + +## Behavior + +- Prefer `Stack.SearchBar` to add a search bar to a screen + +# Navigation + +## Link + +Use `` from 'expo-router' for navigation between routes. + +```tsx +import { Link } from 'expo-router'; + +// Basic link + + +// Wrapping custom components + + ... + +``` + +Whenever possible, include a `` to follow iOS conventions. Add context menus and previews frequently to enhance navigation. + +## Stack + +- ALWAYS use `_layout.tsx` files to define stacks +- Use Stack from 'expo-router/stack' for native navigation stacks + +### Page Title + +Set the page title with `Stack.Title`: + +```tsx +Home +``` + +## Context Menus + +Add long press context menus to Link components: + +```tsx +import { Link } from "expo-router"; + + + + + + + + + + + + {}} /> + {}} + /> + + +; +``` + +## Link Previews + +Use link previews frequently to enhance navigation: + +```tsx + + + + + + + + +``` + +Link preview can be used with context menus. + +## Modal + +Present a screen as a modal: + +```tsx + +``` + +Prefer this to building a custom modal component. + +## Sheet + +Present a screen as a dynamic form sheet: + +```tsx + +``` + +- Using `contentStyle: { backgroundColor: "transparent" }` makes the background liquid glass on iOS 26+. + +## Common route structure + +A standard app layout with tabs and stacks inside each tab: + +``` +app/ + _layout.tsx — + (index,search)/ + _layout.tsx — + index.tsx — Main list + search.tsx — Search view +``` + +```tsx +// app/_layout.tsx +import { NativeTabs } from "expo-router/unstable-native-tabs"; +import { ThemeProvider, DarkTheme, DefaultTheme } from "expo-router/react-navigation"; +import { useColorScheme } from "react-native"; + +export default function Layout() { + const colorScheme = useColorScheme(); + return ( + + + + + Items + + + + + ); +} +``` + +Create a shared group route so both tabs can push common screens: + +```tsx +// app/(index,search)/_layout.tsx +import { Stack } from "expo-router/stack"; +import { colors } from "@/theme/colors"; + +export default function Layout({ segment }) { + const screen = segment.match(/\((.*)\)/)?.[1]!; + const titles: Record = { index: "Items", search: "Search" }; + + return ( + + + + + ); +} +``` diff --git a/plugins/expo/skills/expo-router/agents/openai.yaml b/plugins/expo/skills/expo-router/agents/openai.yaml new file mode 100644 index 0000000..a314bc8 --- /dev/null +++ b/plugins/expo/skills/expo-router/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo Router" + short_description: "Navigate and structure Expo Router apps: file-based routes, links, native stacks, modals, sheets, native tabs, headers, and search" + default_prompt: "Use $expo-router to structure file-based routes, wire up navigation with Link previews and context menus, configure native Stack screens, modals, form sheets, NativeTabs, headers, toolbars, and search bars." diff --git a/plugins/expo/skills/building-native-ui/references/form-sheet.md b/plugins/expo/skills/expo-router/references/form-sheet.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/form-sheet.md rename to plugins/expo/skills/expo-router/references/form-sheet.md diff --git a/plugins/expo/skills/building-native-ui/references/route-structure.md b/plugins/expo/skills/expo-router/references/route-structure.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/route-structure.md rename to plugins/expo/skills/expo-router/references/route-structure.md diff --git a/plugins/expo/skills/building-native-ui/references/search.md b/plugins/expo/skills/expo-router/references/search.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/search.md rename to plugins/expo/skills/expo-router/references/search.md diff --git a/plugins/expo/skills/building-native-ui/references/tabs.md b/plugins/expo/skills/expo-router/references/tabs.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/tabs.md rename to plugins/expo/skills/expo-router/references/tabs.md diff --git a/plugins/expo/skills/building-native-ui/references/toolbar-and-headers.md b/plugins/expo/skills/expo-router/references/toolbar-and-headers.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/toolbar-and-headers.md rename to plugins/expo/skills/expo-router/references/toolbar-and-headers.md diff --git a/plugins/expo/skills/building-native-ui/references/zoom-transitions.md b/plugins/expo/skills/expo-router/references/zoom-transitions.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/zoom-transitions.md rename to plugins/expo/skills/expo-router/references/zoom-transitions.md diff --git a/plugins/expo/skills/web-to-native/SKILL.md b/plugins/expo/skills/web-to-native/SKILL.md index 1f3fa40..dd3f3e9 100644 --- a/plugins/expo/skills/web-to-native/SKILL.md +++ b/plugins/expo/skills/web-to-native/SKILL.md @@ -24,7 +24,7 @@ flowchart TD - **Migrate, don't rewrite.** Never big-bang it; every step keeps the app shippable. - **Ship on day one.** The web UI runs in a DOM-component shell (step 3) before anything is nativized — that's the milestone; everything after is polish. - **Strangle by value.** Nativize the hot screens; leave the rest in the webview. Each DOM screen carries a ~2 MB web runtime — reason enough not to ship everything as DOM. -- **Nativize means redesign, not reskin.** A strangled screen should look like Apple/Google shipped it, not the web page reskinned. **Reach for `@expo/ui` first** — it renders real SwiftUI/Compose, so it feels *exactly* like the OS; styled RN primitives are the fallback for custom layouts only. Plus platform navigation (`building-native-ui`: NativeTabs, large titles), liquid glass and native components via `@expo/ui`, and mobile UX (sheets, swipe, haptics). The web→native pattern map is [`./references/native-patterns.md`](./references/native-patterns.md). If it still feels like a website, you ported instead of redesigned. +- **Nativize means redesign, not reskin.** A strangled screen should look like Apple/Google shipped it, not the web page reskinned. **Reach for `@expo/ui` first** — it renders real SwiftUI/Compose, so it feels *exactly* like the OS; styled RN primitives are the fallback for custom layouts only. Plus platform navigation (`expo-router`: NativeTabs, large titles), liquid glass and native components via `@expo/ui`, and mobile UX (sheets, swipe, haptics). The web→native pattern map is [`./references/native-patterns.md`](./references/native-patterns.md). If it still feels like a website, you ported instead of redesigned. - **Verify by running, not compiling.** A clean build proves nothing (a blank webview compiles fine). Run each screen — but judge *content and behavior* against the web original, not pixels (a nativized screen should look more native, not identical). - **Orchestrate, don't reinvent.** Each step routes into an existing skill. The value here is the *order* and the *gotchas* — the idiom-by-idiom mappings live in [`./references/false-friends.md`](./references/false-friends.md). @@ -55,7 +55,7 @@ Bring every screen over as a DOM component (`'use dom'`, per the `use-dom` skill ### 4. Strangle screens to native — by value -Walk `migration-progress.md` top-down. For each screen, *redesign* it native — don't port the web layout. Reach for **`@expo/ui` first** (real SwiftUI/Compose — buttons, lists, sheets, pickers, sliders; [`./references/native-patterns.md`](./references/native-patterns.md) maps which web pattern becomes which native component), then platform navigation (`building-native-ui` — NativeTabs, large titles) and mobile UX (swipe, haptics, momentum/inverted scroll); RN primitives only for custom layouts. Consult [`./references/false-friends.md`](./references/false-friends.md) for each idiom. `@expo/ui` and DOM components both run in **Expo Go** (SDK 56+) — a dev build (the `expo-dev-client` skill) is only needed for *custom* native modules. Verify *content and behavior* against the running web original (the look should become more native), then check it off. One screen per pass, app shippable throughout. It's a loop over a durable worklist, so it can run unattended — hand it to a goal loop ([`./references/run-as-goal.md`](./references/run-as-goal.md)). +Walk `migration-progress.md` top-down. For each screen, *redesign* it native — don't port the web layout. Reach for **`@expo/ui` first** (real SwiftUI/Compose — buttons, lists, sheets, pickers, sliders; [`./references/native-patterns.md`](./references/native-patterns.md) maps which web pattern becomes which native component), then platform navigation (`expo-router` — NativeTabs, large titles) and mobile UX (swipe, haptics, momentum/inverted scroll); RN primitives only for custom layouts. Consult [`./references/false-friends.md`](./references/false-friends.md) for each idiom. `@expo/ui` and DOM components both run in **Expo Go** (SDK 56+) — a dev build (the `expo-dev-client` skill) is only needed for *custom* native modules. Verify *content and behavior* against the running web original (the look should become more native), then check it off. One screen per pass, app shippable throughout. It's a loop over a durable worklist, so it can run unattended — hand it to a goal loop ([`./references/run-as-goal.md`](./references/run-as-goal.md)). ### 5. Wire data, auth, and storage diff --git a/plugins/expo/skills/web-to-native/references/native-patterns.md b/plugins/expo/skills/web-to-native/references/native-patterns.md index 89b5183..6c98279 100644 --- a/plugins/expo/skills/web-to-native/references/native-patterns.md +++ b/plugins/expo/skills/web-to-native/references/native-patterns.md @@ -6,8 +6,8 @@ Disclosed reference for [`web-to-native`](../SKILL.md), step 4. `false-friends.m | Web pattern | Native redesign — reach for first | Why | |---|---|---| -| Top tab bar / nav links | **NativeTabs** — bottom, liquid glass on iOS 26 (`building-native-ui`) | Thumb-reachable, OS-native bar | -| Page header / breadcrumb | **large-title** Stack header + header **search field** (`building-native-ui`) | The native screen frame | +| Top tab bar / nav links | **NativeTabs** — bottom, liquid glass on iOS 26 (`expo-router`) | Thumb-reachable, OS-native bar | +| Page header / breadcrumb | **large-title** Stack header + header **search field** (`expo-router`) | The native screen frame | | In-page tabs / toggle group | **SegmentedControl** — `@expo/ui` (`community/segmented-control`) | Native segmented switch | | Modal / dialog | **BottomSheet** — `@expo/ui` | Sheets *are* the native modal | | `