📁 File path:
apps/weshipit/pages/plan/2026-W28.md
React Native Roadmap 2026-W28
Week of July 6–July 12, 2026
Items This Week
| # | Title | Label | Link |
|---|---|---|---|
| 1 | Zoomable Calendar Grids, On-Device Gemini Nano & Astryx Design System | 🟦 RN | Read |
| 2 | Sign in with Passkeys — Expo | 🟧 EXPO | Read |
| 3 | A Hell of a Time to Be a Builder | 🟧 EXPO | Read |
| 4 | React Status #482 — TypeScript 7.0 & React Navigation 8 | ⚛️ REACT | Read |
| 5 | Nesting Tabs and Drawers with Expo Router | 🟧 EXPO | Read |
| 6 | @react-native-ai/adk — On-Device Android AI via Google ADK | 🟦 RN | Read |
| 7 | Maestro MCP — Let Your Agent Test the App It Just Built | 🟦 RN | Read |
5-Day Action Plan
🟦 Chunk 1 — Implement a Gesture-Driven Calendar with super-calendar
Goal: Add a fully interactive, pinch-to-zoom month/week/day calendar to your React Native app using super-calendar, backed by Reanimated shared values and Legend List virtualisation — so the UI thread never drops a frame while navigating months or dragging events.
Scope:
- Install
super-calendarand its peer deps (react-native-reanimated,react-native-gesture-handler,@legendapp/list) - Replace or supplement an existing date picker / flat calendar view with
<Calendar /> - Configure
onDragEvent,onResizeEvent, andonCreateEventcallbacks - Wire event data from local state or an API
- Use the
onDragEventveto pattern (return false) to lock read-only events
Out of scope: Server-side event persistence, push notification reminders, recurring event recurrence rules, web support.
Dependencies: React Native ≥ 0.73, Reanimated ≥ 3, Gesture Handler ≥ 2. Worklet runtime enabled.
Acceptance criteria:
- Pinch gesture zooms the week/day grid smoothly at 60 fps with no React re-renders visible in Profiler
- Long-press + drag moves a mutable event; dragging a locked event snaps it back
- Month view virtualises correctly — scrolling 12 months back/forward stays under 16 ms frame time
- Calendar renders correctly in both light and dark mode
Estimated effort: M
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Integrate a gesture-driven calendar using super-calendar.
Goal: Add a pinch-to-zoom, gesture-driven month/week/day calendar backed by Reanimated shared values. Zero re-renders during zoom animations.
Files to create/modify:
src/components/Calendar/AppCalendar.tsx— new wrapper componentsrc/screens/CalendarScreen.tsx— consume<AppCalendar />package.json— addsuper-calendar, ensurereact-native-reanimatedandreact-native-gesture-handlerare present
Step-by-step:
npm install super-calendar(check peer deps and install any missing ones).- Wrap your app entry with
<GestureHandlerRootView>if not already done. - Create
AppCalendar.tsxthat renders<Calendar mode="week" />fromsuper-calendar. - Pass an
eventsarray of{ id, title, start, end, color }objects. - Implement
onDragEvent={(event) => { if (event.id === 'locked') return false; updateEvent(event); }}. - Implement
onResizeEventandonCreateEventcallbacks. - Enable the pinch gesture: it is on by default — verify it works on a physical device.
- Confirm with React DevTools Profiler that no React re-renders fire during a pinch gesture.
Acceptance criteria checklist:
- Pinch gesture zooms week grid at 60 fps on a mid-range device
- Dragging an event updates state correctly
- Dragging a locked event returns it to its original position
- Navigating 12 months via swipe stays under 16 ms frame time in Profiler
- No Metro bundler errors on both iOS and Android
🟧 Chunk 2 — Implement Nested Drawer + Bottom Tabs with Expo Router
Goal: Build a production-grade hybrid navigation layout where a drawer navigator wraps bottom tabs in Expo Router using the file-system routing convention — giving users swipe-from-left access to global sections while keeping tab navigation for primary flows.
Scope:
- Create a
(drawer)layout group inapp/containing a(tabs)nested group - Configure
<Drawer>with themed header and gesture handling - Configure
<Tabs>with icons and themed tab bar inside the drawer - Handle dark/light mode theming for both navigators consistently
- Verify swipe-to-open drawer gesture does not conflict with horizontal tab swipes
Out of scope: Deep linking configuration, authentication guards, animations beyond defaults, web routing support.
Dependencies: Expo SDK 57, expo-router ≥ 4, @react-navigation/drawer, react-native-gesture-handler, react-native-reanimated.
Acceptance criteria:
- Swiping from the left edge opens the drawer without triggering a tab swipe
- Navigating between tabs does not close the drawer unexpectedly
- Drawer and tab bar adapt correctly to system light/dark mode
- Deep navigation state is preserved when the drawer is toggled
- No TypeScript errors from route types
Estimated effort: S
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Nested drawer + bottom tabs navigation with Expo Router file-system conventions.
Goal: Create a (drawer)/(tabs) layout where a swipeable drawer wraps themed bottom tabs, following Expo Router's file-system routing pattern.
Files to create/modify:
app/(drawer)/_layout.tsx— Drawer layoutapp/(drawer)/(tabs)/_layout.tsx— Tabs layout nested inside drawerapp/(drawer)/(tabs)/index.tsx— Home tab screenapp/(drawer)/(tabs)/explore.tsx— Second tab screenapp/(drawer)/settings.tsx— Drawer-only screen (not a tab)package.json— ensure@react-navigation/drawer,react-native-gesture-handler,react-native-reanimatedare installed
Step-by-step:
- Install dependencies:
npx expo install @react-navigation/drawer react-native-gesture-handler react-native-reanimated. - Create
app/(drawer)/_layout.tsx:import { Drawer } from 'expo-router/drawer'; export default function DrawerLayout() { return <Drawer screenOptions={{ headerShown: false }} />; } - Create
app/(drawer)/(tabs)/_layout.tsx:import { Tabs } from 'expo-router'; export default function TabsLayout() { return ( <Tabs screenOptions={{ tabBarActiveTintColor: '#6200ee' }}> <Tabs.Screen name="index" options={{ title: 'Home' }} /> <Tabs.Screen name="explore" options={{ title: 'Explore' }} /> </Tabs> ); } - Add
app/(drawer)/settings.tsxas a drawer-only route. - Verify gesture handler root view is at the app root (
app/_layout.tsx). - Test on a physical iOS and Android device: swipe from left to open drawer, swipe horizontally on tabs.
- Enable dark mode on the device and confirm both navigators update their theme.
Acceptance criteria checklist:
- Left swipe opens drawer; tab swipe only activates when not near the left edge
- Tabs render correctly with icons and active color
- Settings screen reachable from drawer but absent from tab bar
- Dark mode applied consistently across drawer header and tab bar
- No TypeScript route type errors (
expo-routertyped routes enabled)
🟦 Chunk 3 — Configure Maestro MCP for AI-Driven E2E Testing
Goal: Connect Claude Code (or another coding agent) to a live iOS simulator or Android emulator via Maestro MCP so the agent can autonomously run, screenshot, and verify flows — and save the resulting YAML as a repeatable regression test.
Scope:
- Install Maestro CLI (
curl -Ls "https://get.maestro.mobile.dev" | bash) - Add Maestro MCP to Claude Code:
claude mcp add maestro -- maestro mcp - Write a first E2E flow (login screen → home tab) in YAML
- Trigger the flow from within a Claude Code session via the MCP tool
- Capture and save a screenshot assertion
Out of scope: CI/CD integration (GitHub Actions), multi-device parallel runs, performance benchmarking, Appium or Detox migration.
Dependencies: Maestro CLI installed locally, iOS Simulator or Android Emulator running, Claude Code ≥ 1.0 (or any MCP-compatible agent).
Acceptance criteria:
maestro mcpstarts without errors and the MCP server is listed in Claude Code- Agent can describe the screen hierarchy by calling the MCP tool
- Agent taps the login button and verifies the home screen appears via screenshot
- The generated YAML flow can be replayed with
maestro test login.yamlindependently - Test pass/fail result is reported back to the agent session
Estimated effort: S
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Configure Maestro MCP so a Claude Code agent can drive and test your app on a live device.
Goal: Give your AI coding agent eyes and hands on the running app — letting it tap, verify screens, and save repeatable E2E tests — using Maestro MCP.
Files to create/modify:
.maestro/login.yaml— first E2E test flowpackage.json(optionally) — add a"test:e2e"script
Step-by-step:
- Install Maestro:
curl -Ls "https://get.maestro.mobile.dev" | bashand verify withmaestro --version. - Start your app on an iOS Simulator or Android Emulator.
- Run
maestro studioto inspect the view hierarchy and find element IDs/text for your login screen. - Create
.maestro/login.yaml:appId: com.yourapp.bundle --- - launchApp - tapOn: 'Email' - inputText: 'test@example.com' - tapOn: 'Password' - inputText: 'password123' - tapOn: 'Sign In' - assertVisible: 'Welcome' - takeScreenshot: login-success - Run
maestro test .maestro/login.yamland confirm it passes. - Add Maestro MCP to Claude Code:
claude mcp add maestro -- maestro mcp. - In a Claude Code session, ask: "Run the Maestro login flow and tell me what you see on screen."
- Confirm the agent calls the MCP tool, drives the simulator, and reports back.
Acceptance criteria checklist:
-
maestro test .maestro/login.yamlpasses end-to-end without manual intervention -
maestro mcpserver appears in Claude Code MCP list - Agent can read the screen hierarchy via MCP and identify UI elements
- Agent-triggered flow produces a screenshot saved to the Maestro output folder
- YAML flow is committed to version control for future CI use
🟦 Chunk 4 — Integrate @react-native-ai/adk for On-Device Android AI
Goal: Implement an on-device AI feature on Android — such as a smart reply, image description, or chat assistant — using @react-native-ai/adk, which wraps Google's Agent Development Kit as a Vercel AI SDK provider, keeping inference fully local with no cloud round-trips.
Scope:
- Install
@react-native-ai/adkand the Vercel AI SDK (aipackage) - Configure the ADK provider pointing to an on-device Gemini Nano model
- Build a simple UI: a text input + response display using
useChatfrom theaipackage - Handle streaming output and display tokens progressively
- Add a loading state and an error boundary
Out of scope: iOS Foundation Models integration (separate package), cloud fallback logic, multi-turn tool calling, model fine-tuning.
Dependencies: Android device with Gemini Nano support (Pixel 6+ or equivalent), @react-native-ai/adk ≥ 0.1, Vercel AI SDK (ai ≥ 4.0), React Native 0.76+.
Acceptance criteria:
- The AI feature works fully offline (airplane mode enabled during test)
- First token appears within 2 seconds of submitting a prompt
- Streaming text renders progressively without layout jank
- Error state shows a user-friendly message if the model is unavailable
- No network requests made during inference (verified in DevTools network tab)
Estimated effort: M
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Add on-device Android AI using @react-native-ai/adk and the Vercel AI SDK.
Goal: Build a local AI chat feature on Android that uses Gemini Nano on-device via Google's ADK, wrapped as a Vercel AI SDK provider — no internet connection required during inference.
Files to create/modify:
src/ai/adk-provider.ts— configure the ADK providersrc/screens/OnDeviceAIScreen.tsx— chat UI usinguseChatpackage.json— add@react-native-ai/adkandai
Step-by-step:
-
Install:
npm install @react-native-ai/adk ai. -
Create
src/ai/adk-provider.ts:import { createADK } from '@react-native-ai/adk'; export const adk = createADK(); export const model = adk('gemini-nano'); -
Create
OnDeviceAIScreen.tsxusing theuseChathook:import { useChat } from 'ai/react'; import { model } from '../ai/adk-provider'; export default function OnDeviceAIScreen() { const { messages, input, handleInputChange, handleSubmit } = useChat({ model }); return ( <View> <FlatList data={messages} renderItem={({ item }) => <Text>{item.content}</Text>} /> <TextInput value={input} onChangeText={handleInputChange} /> <Button title="Send" onPress={handleSubmit} /> </View> ); } -
Enable airplane mode on the Android device.
-
Run the app, type a prompt, and verify inference completes locally.
-
Add a loading indicator while the model is generating.
-
Add an error boundary that catches
ModelUnavailableErrorfrom the ADK.
Acceptance criteria checklist:
- App builds and runs on Android without native compilation errors
- Inference works with airplane mode enabled (fully offline)
- First token appears within 2 seconds on a Pixel 6+
- Text streams progressively as tokens are generated
- Error boundary shows a friendly message if model is not available on device
⚛️ Chunk 5 — Upgrade to TypeScript 7.0 for 10× Faster Type-Checking
Goal: Migrate the project's TypeScript compiler to version 7.0 (the Go-powered tsc) to dramatically reduce type-check time in CI and local development — while keeping the existing TS 6.x programmatic API for tools that depend on it (e.g. ts-jest, ESLint plugins).
Scope:
- Update
typescriptto^7.0inpackage.json - Verify
tsconfig.jsoncompatibility (no removed options) - Run
tsc --noEmitwith the new compiler and fix any new stricter errors - Update CI type-check step to use
tscdirectly (not via a wrapper that requires the programmatic API) - Benchmark build time before/after and document the speedup
Out of scope: Migrating Jest transformer from ts-jest to a native alternative (programmatic API not yet in TS 7), enabling new TS 7 language features, full ESLint TypeScript plugin upgrade.
Dependencies: TypeScript ≥ 7.0, Node.js ≥ 20, no tooling that relies on tsc programmatic API in CI.
Acceptance criteria:
npx tsc --noEmitcompletes without errors using TypeScript 7.0- CI type-check job is at least 3× faster than the TS 6.x baseline (measured in seconds)
- No new type errors introduced (or all new errors are fixed)
- Existing tooling (Metro, Expo, ESLint) still works correctly with the new compiler
package.jsontypescriptversion is pinned to^7.0
Estimated effort: S
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Upgrade TypeScript to version 7.0 for 10× faster type-checking.
Goal: Replace the TypeScript 6.x compiler with the new Go-powered TypeScript 7.0 to slash type-check times in local dev and CI, without breaking Expo or Metro tooling.
Files to create/modify:
package.json— bumptypescriptto^7.0tsconfig.json— remove any options deprecated or removed in TS 7.github/workflows/ci.yml(or equivalent) — update type-check step
Step-by-step:
- Record baseline:
time npx tsc --noEmitwith current TypeScript version. - Run
npm install typescript@^7.0 --save-dev. - Run
npx tsc --noEmitand review any new errors carefully. - Fix strict errors: TS 7 tightens inference in some edge cases — address each error in the codebase.
- Check
tsconfig.jsonfor any removed compiler options (e.g.importsNotUsedAsValueswas removed in 5.5+). - Verify Metro bundler starts:
npx expo startand check for TypeScript-related warnings. - Verify ESLint TypeScript plugin works:
npx eslint . --ext .ts,.tsx. - Update CI workflow to run
tsc --noEmitdirectly (not via ts-jest or ts-node, which need the programmatic API). - Record new time:
time npx tsc --noEmit— document the speedup in a comment intsconfig.json.
Acceptance criteria checklist:
-
npm installsucceeds withtypescript@^7.0 -
npx tsc --noEmitexits 0 with no errors - Type-check time is reduced by ≥ 3× vs TS 6 baseline
-
npx expo startlaunches without TypeScript-related errors - ESLint with
@typescript-eslintruns without crashing - CI pipeline passes on the updated workflow