π File path:
apps/weshipit/pages/plan/2026-W26.md
React Native Roadmap 2026-W26
Week of June 22βJune 28, 2026
Items This Week
| # | Title | Label | Link |
|---|---|---|---|
| 1 | The React Native Rewind: Vercel Eve & Tauri Desktop Shells | π¦ RN | Read |
| 2 | TWIR #287: Reanimated 4.5 β CSS pseudo-selectors on native | π¦ RN | Read |
| 3 | TWIR #287: VisionCamera v5 β real-time frame processing | π¦ RN | Read |
| 4 | TWIR #287: Fragment ref coming to React & React Native (v19.3) | βοΈ REACT | Read |
| 5 | Expo Changelog: Maestro testing β insights, clearer results & faster retries | π§ EXPO | Read |
| 6 | Expo Blog: iOS Widgets & Live Activities stable in Expo SDK 56 | π§ EXPO | Read |
| 7 | React Status #480: Writing Custom Renderers for React (Callstack/RNTL) | βοΈ REACT | Read |
5-Day Action Plan
Β
π¦ Chunk 1 β Implement Reanimated 4.5 CSS Pseudo-selector Animations
Goal: Deliver polished hover, active, and focus interaction states using Reanimated 4.5's new CSS pseudo-selectors, matching the browser experience on native iOS and Android.
Scope:
- Upgrade
react-native-reanimatedto^4.5.0 - Replace
Pressable/onPressIn/onPressOutworkarounds with declarative:hover,:active,:focusCSS animation rules - Implement at least two interactive components (e.g. a primary button and a card) using the new pseudo-selector API
- Verify behaviour on iOS, Android, and Web (Expo)
Out of scope:
- Custom animation orchestration with
useAnimatedStyle - Migration of all existing animations in the codebase
- Gesture-based animations (swipe, drag)
Dependencies: React Native β₯ 0.83, New Architecture enabled, Reanimated 4.x already installed.
Acceptance criteria:
- Pressing a button shows a visible
:activestate with a CSS transition (scale or opacity) - Hovering on web/iPad triggers a
:hoverstate without any JS handler - Focus ring appears on keyboard navigation (web target)
- No regression on existing animations
Estimated effort: S
Β
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Add CSS pseudo-selector animation states (:hover, :active, :focus) to interactive UI components using Reanimated 4.5.
Files to create or modify:
package.jsonβ bumpreact-native-reanimatedto^4.5.0components/ui/Button.tsxβ rewrite interaction states using Reanimated CSS pseudo-selectorscomponents/ui/Card.tsxβ add:hoverand:activestatesapp/(tabs)/index.tsx(or equivalent) β add a demo screen showcasing both components
Step-by-step instructions:
- Run
npx expo install react-native-reanimated@^4.5.0 - In
Button.tsx, importAnimatedfromreact-native-reanimatedand replace thePressablemanual state tracking with a singleAnimatedPressablecomponent using the new CSS-stylestyleprop supporting:activeand:hoverpseudo-selectors. - Define styles using
StyleSheet.createwhere:activereducesscaleto0.97and changesbackgroundColoropacity. - In
Card.tsx, apply:hoverto elevate the shadow and scale to1.02. - Create a simple demo screen to showcase both components.
- Run
npx expo startand test on iOS Simulator, Android Emulator, and Web.
Acceptance criteria checklist:
- Tapping the button triggers a smooth
:activescale/opacity transition - Hovering over a card on Web/iPad shows the elevated shadow state
- No
onPressIn/onPressOutmanual state management remains - Animations run at 60 fps (no JS thread drops)
- Existing Reanimated animations pass a smoke test
π¦ Chunk 2 β Build a VisionCamera v5 Real-time Frame Processor
Goal: Unlock real-time per-frame processing using VisionCamera v5's Frame.hasPixelBuffer / Frame.hasNativeBuffer APIs β enabling use cases like live filters, barcode scanning, or ML inference directly on the camera stream.
Scope:
- Install / confirm
react-native-vision-camera@^5.0.11andreact-native-worklets-core - Create a
useFrameProcessorworklet that reads frame buffer availability viaframe.hasPixelBuffer - Implement a simple real-time overlay (e.g. brightness meter or luma value) drawn from frame data
- Display the processed value reactively in the UI using a shared value
Out of scope:
- ML model integration (TensorFlow, CoreML, ONNX)
- Photo / video capture flow
- Multi-camera capture
Dependencies: Chunk is self-contained. Requires a physical device or simulator with camera support (physical recommended). New Architecture enabled.
Acceptance criteria:
- Camera preview renders with no dropped frames
- A per-frame numeric value (e.g. average brightness) updates in the UI at β₯30 fps
frame.hasPixelBuffercorrectly gates the processing path on iOSframe.hasNativeBuffercorrectly gates the processing path on Android- No JS thread blockage (worklet runs on the camera thread)
Estimated effort: M
Β
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Create a real-time camera frame processor using VisionCamera v5 that reads per-frame pixel data and displays a computed value in the UI.
Files to create or modify:
package.jsonβ ensurereact-native-vision-camera@^5.0.11andreact-native-worklets-coreare installedscreens/CameraScreen.tsxβ main camera screen with live overlayhooks/useFrameBrightnessProcessor.tsβ frame processor worklet logicapp.json/Info.plist/AndroidManifest.xmlβ camera permission configuration
Step-by-step instructions:
- Install:
npx expo install react-native-vision-camera react-native-worklets-core - Add camera permissions in
app.json(iOSNSCameraUsageDescription, AndroidCAMERA). - In
useFrameBrightnessProcessor.ts, create auseFrameProcessorworklet:- Check
frame.hasPixelBuffer(iOS) orframe.hasNativeBuffer(Android) before processing - Compute an average luma value by sampling pixel bytes
- Write the result to a
useSharedValue<number>viarunOnJS
- Check
- In
CameraScreen.tsx, render<Camera>withframeProcessorprop, and display the shared value using anAnimated.Textconnected viauseAnimatedProps. - Test on a physical device for real-time performance.
Acceptance criteria checklist:
- Camera preview renders without lag
- Brightness value updates at β₯30 fps
-
hasPixelBuffer/hasNativeBufferguard prevents crashes on unsupported frames - Worklet runs off the JS thread (verified with Flipper / Xcode Instruments)
- App does not crash on permission denial
π§ Chunk 3 β Implement an iOS Widget with Expo SDK 56
Goal: Ship a production-ready iOS Home Screen widget using the now-stable expo-widget API in Expo SDK 56, surfacing key app data to users without opening the app.
Scope:
- Confirm project is on Expo SDK 56 with
expo-widgetdependency - Create a Small widget variant (2Γ2) displaying a piece of dynamic app data (e.g. today's stats, latest notification)
- Wire up widget data refresh via
WidgetKitbackground tasks through Expo's native bridge - Preview the widget in the iOS Simulator widget gallery
Out of scope:
- Medium/Large widget variants
- Android widgets (different API)
- Live Activities (separate task)
- Custom widget fonts or complex animations
Dependencies: Expo SDK 56, Xcode 16+, physical device or iOS Simulator 18+. EAS Build required for a device build (local Expo Go cannot run widgets).
Acceptance criteria:
- Widget appears in the iOS widget picker under the app name
- Widget displays real data (not placeholder) after the first background refresh
- Tapping the widget deep-links into the correct screen in the app
- Widget preview renders correctly in Xcode widget simulator
Estimated effort: M
Β
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Create a small iOS Home Screen widget using the stable expo-widget API from Expo SDK 56 that displays dynamic app data.
Files to create or modify:
package.jsonβ ensureexpo@^56.0.0andexpo-widgetare installedwidget/SmallWidget.tsxβ widget UI component (SwiftUI-like declarative syntax via Expo Widget API)widget/index.tsβ widget entry point registering the widget familyapp/(tabs)/index.tsxβ trigger widget data refresh on app foregroundeas.jsonβ ensure iOS build profile targets iOS 17+
Step-by-step instructions:
- Run
npx expo install expo-widgetand ensure SDK is^56.0.0. - Create
widget/SmallWidget.tsxusingWidgetView,Text, andLinkfromexpo-widget. - Define a
TimelineEntryinterface with the data shape your widget will display. - Implement a
getTimelinefunction that fetches data from sharedUserDefaults/App Groupand returns an array of entries. - Register the widget in
widget/index.tswithregisterWidget({ families: ['small'], component: SmallWidget }). - In the main app, call
Widget.reloadAll()when relevant data changes. - Build with
eas build --platform ios --profile previewand install on device/simulator.
Acceptance criteria checklist:
- Widget appears in the iOS widget picker
- Small widget renders the correct data shape
- Tapping the widget opens the correct in-app screen
-
Widget.reloadAll()triggers a visible data refresh within 60 seconds - No crash on cold widget load (no app running in background)
π§ Chunk 4 β Configure Maestro E2E Testing with EAS Insights Dashboard
Goal: Set up Maestro end-to-end tests integrated with EAS, and activate the new Insights dashboard to track flaky tests and regressions across the team over time.
Scope:
- Install Maestro CLI and write 2β3 critical user journey flows (e.g. onboarding, login, core action)
- Add an EAS Workflow step that runs Maestro tests on every pull request
- Enable the new EAS Maestro Insights dashboard for the project
- Configure retry policy for flaky tests using the new faster-retry feature
Out of scope:
- Visual regression testing
- Android E2E (focus on iOS first)
- Full coverage of all screens
Dependencies: EAS account with Workflows enabled (Free or paid plan), Maestro CLI installed locally, an existing Expo app buildable with EAS.
Acceptance criteria:
- At least 2 Maestro
.yamlflow files committed to the repo - EAS Workflow triggers Maestro tests on every PR (visible in the EAS dashboard)
- Insights tab shows historical test run data after the first CI run
- Flaky test is identified correctly by the Insights dashboard (can be simulated with a known flaky assertion)
- Tests complete in under 5 minutes per run
Estimated effort: S
Β
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Add Maestro E2E test flows integrated with EAS Workflows and activate the EAS Maestro Insights dashboard for test monitoring.
Files to create or modify:
.maestro/onboarding.yamlβ Maestro flow for the onboarding screen.maestro/login.yamlβ Maestro flow for the login flow.eas/workflows/pr-checks.ymlβ EAS Workflow definition that runs Maestro on PRseas.jsonβ ensure apreviewbuild profile exists for simulator builds
Step-by-step instructions:
- Install Maestro:
curl -Ls "https://get.maestro.mobile.dev" | bash - Create
.maestro/onboarding.yaml: uselaunchApp,assertVisible,tapOn, andassertVisibleto test the onboarding screens. - Create
.maestro/login.yaml: input credentials, tap login, assert the home screen is visible. - In
.eas/workflows/pr-checks.yml, add amaestrojob step pointing to your.maestro/folder, targeting thepreviewbuild artifact. - Set
retries: 2in the EAS Workflow maestro step to leverage the faster-retry feature. - Push a PR and verify the Workflow runs in the EAS dashboard.
- Navigate to EAS β your project β Testing β Insights to verify the dashboard is populated.
Acceptance criteria checklist:
- Both
.yamlflows pass locally withmaestro test .maestro/onboarding.yaml - EAS Workflow triggers automatically on PR creation
- Test results appear in the EAS Insights tab after the first run
- Failed/flaky tests are highlighted with a distinct status
- Total CI time for both flows is under 5 minutes
βοΈ Chunk 5 β Prepare Codebase for Fragment Ref API (React 19.3 / RN canary)
Goal: Refactor at least one composite component to leverage the upcoming <Fragment ref> API (available in React canary), enabling cleaner cross-component DOM/native node access without wrapper <View> nodes.
Scope:
- Upgrade to React 19 canary (
react@canary) in a feature branch - Identify one composite component that currently uses a wrapper
<View>solely to expose a ref - Refactor it to use
<Fragment ref>andFragmentInstanceto access first-level children - Write a unit test verifying ref access via the new API
- Document the pattern in a
docs/fragment-ref.mdfile for the team
Out of scope:
- Migrating all ref-using components
- Production deployment of canary React (exploration only)
- Full feature parity evaluation between React and React Native implementations
Dependencies: This is an exploratory chunk. React 19.3 canary must be installed (npm install react@canary react-dom@canary). No production deployment required.
Acceptance criteria:
- The refactored component renders correctly without the wrapper
<View> ref.currentviaFragmentInstancecorrectly references the first child node- Unit test passes with
@testing-library/react-native docs/fragment-ref.mdclearly explains the before/after pattern- A PR is opened with the exploration, tagged as
[RFC]for team review
Estimated effort: S
Β
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Refactor a composite component to use the upcoming <Fragment ref> API (React 19.3 canary) and document the pattern for the team.
Files to create or modify:
package.jsonβ addreact@canaryoverride in a feature branch onlycomponents/ui/AnimatedList.tsxβ refactor to remove wrapper<View>using Fragment refcomponents/ui/__tests__/AnimatedList.test.tsxβ unit test verifying ref accessdocs/fragment-ref.mdβ documentation of the pattern
Step-by-step instructions:
- Create a new git branch:
git checkout -b explore/fragment-ref - Install React canary:
npm install react@canary react-dom@canary --save-exact - Identify a component that wraps children in a
<View ref={ref}>solely to expose a measurement or layout ref. - Refactor: replace
<View ref={ref}>with<Fragment ref={ref}>. TypeScript: type the ref asReact.RefObject<React.FragmentInstance>. - Access the first child via
ref.current.children[0]for measurements. - Write a test using
renderHook+useRef<React.FragmentInstance>()to assertref.currentis not null after mount. - Create
docs/fragment-ref.mdwith a before/after code example and a note that this targets React 19.3. - Open a PR titled
[RFC] Explore Fragment ref API for component composition.
Acceptance criteria checklist:
- Component renders without the extra wrapper
<View>node -
ref.currentis aFragmentInstanceafter mount -
ref.current.children[0]resolves to the first child native node - Unit test passes with
jest --testPathPattern=AnimatedList -
docs/fragment-ref.mdis committed and explains the pattern clearly - Branch is mergeable with no TypeScript errors