chore(mobile): upgrade to Expo SDK 56

Bump expo, react, react-native, and all expo-* / react-native-* peers to
the SDK 56 line via expo install --fix, adding expo-splash-screen and
expo-system-ui for config plugins the SDK split out of core. Bump
@bacons/apple-targets, react-native-view-shot, and other native modules
to versions compatible with React Native 0.85 and the new architecture.

Remove @react-navigation/* direct dependencies and route their hooks
through expo-router, which is no longer compatible with react-navigation
as of SDK 56. Fix RN 0.85's removed StyleSheet.absoluteFillObject (use
absoluteFill) and react-native-view-shot 5.x's ViewShotRef type across
call sites. Downgrade eslint-plugin-react-hooks v7's new React Compiler
era rules to warnings pending a dedicated refactor, and repair Jest
fallout from the jest-expo/reanimated/worklets/expo-media-library bumps.

Regenerate the committed ios/ and android/ native projects with
`expo prebuild --clean` (required for @bacons/apple-targets 5.x) against
the production release channel, and document that requirement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jjbruntonandClaude Fable 5 committed 2026-08-31 11:11:37 +01:00
1 parent 8bf93f372b
commit 6bc4e31719
92 files changed
+29132 -35557

No files matched your search

@@ -310,7 +310,7 @@ const styles = StyleSheet.create({
color: colors.textTertiary,
},
lockOverlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
+1 -1
View File
@@ -307,7 +307,7 @@ export const MatchConfetti: React.FC<Props> = ({ visible, onAnimationComplete })
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
zIndex: 1000,
},
particle: {
@@ -344,7 +344,7 @@ export const MatchNotificationModal: React.FC<Props> = ({
const styles = StyleSheet.create({
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.75)',
justifyContent: 'center',
alignItems: 'center',
@@ -377,7 +377,7 @@ const styles = StyleSheet.create({
borderColor: colors.border,
},
flatBackground: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: colors.backgroundLight,
},
// Removed blur/gradient styles
+1 -1
View File
@@ -269,7 +269,7 @@ const styles = StyleSheet.create({
justifyContent: "flex-end",
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.85)",
},
content: {
@@ -101,7 +101,7 @@ const styles = StyleSheet.create({
position: 'relative',
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.05)',
borderRadius: radius.lg,
pointerEvents: 'none',
@@ -115,7 +115,7 @@ const styles = StyleSheet.create({
fontWeight: '700',
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.05)',
borderRadius: radius.lg,
pointerEvents: 'none',
@@ -110,7 +110,7 @@ const styles = StyleSheet.create({
marginTop: 2,
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.05)',
borderRadius: radius.lg,
pointerEvents: 'none',
@@ -90,7 +90,7 @@ const styles = StyleSheet.create({
marginTop: 2,
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.05)',
borderRadius: radius.lg,
pointerEvents: 'none',
@@ -336,7 +336,7 @@ const styles = StyleSheet.create({
zIndex: 1000,
},
backdrop: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.8)',
},
keyboardView: {
@@ -615,7 +615,7 @@ const styles = StyleSheet.create({
borderColor: colors.premium.goldLight,
},
annualBackground: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: colors.premium.goldLight,
opacity: 0.3,
},
@@ -804,7 +804,7 @@ const styles = StyleSheet.create({
// Guest confirm modal
guestConfirmOverlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.8)",
justifyContent: "center",
alignItems: "center",
@@ -131,7 +131,7 @@ const styles = StyleSheet.create({
padding: spacing.lg,
},
backdrop: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.7)",
},
modalContainer: {
@@ -629,7 +629,7 @@ const styles = StyleSheet.create({
justifyContent: "flex-end",
},
backdrop: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.6)",
},
sheetContainer: {
@@ -86,7 +86,7 @@ const styles = StyleSheet.create({
padding: spacing.lg,
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.1)",
},
header: {
@@ -19,7 +19,7 @@ import Animated, {
} from "react-native-reanimated";
import { Ionicons } from "@expo/vector-icons";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import ViewShot from "react-native-view-shot";
import ViewShot, { type ViewShotRef } from "react-native-view-shot";
import * as Sharing from "expo-sharing";
import { colors, typography, spacing, blur } from "../../theme";
import { shareToInstagramStories } from "../../lib/instagramShare";
@@ -50,7 +50,7 @@ export function SharePreviewModal({
const insets = useSafeAreaInsets();
const { width: screenWidth } = useWindowDimensions();
const cardWidth = Math.min(screenWidth - 64, MAX_CARD_WIDTH);
const shareViewRef = useRef<ViewShot>(null);
const shareViewRef = useRef<ViewShotRef>(null);
const [capturedUri, setCapturedUri] = useState<string | null>(null);
const [isCapturing, setIsCapturing] = useState(false);
@@ -308,7 +308,7 @@ export default function MatchesTutorial({ onComplete }: Props) {
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
zIndex: 1000,
},
blur: {
@@ -152,7 +152,7 @@ const styles = StyleSheet.create({
padding: spacing.md,
},
fullScreenContainer: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(13, 13, 26, 0.85)',
alignItems: 'center',
justifyContent: 'center',
@@ -118,7 +118,7 @@ const styles = StyleSheet.create({
overflow: 'hidden',
},
glowContainer: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
},
edgeGlowTop: {
position: 'absolute',
+1 -2
View File
@@ -1,7 +1,6 @@
import { useState, useEffect, useCallback, useRef } from "react";
import { View, StyleSheet, KeyboardAvoidingView, Platform, Alert } from "react-native";
import { useLocalSearchParams, useRouter } from "expo-router";
import { useFocusEffect, useIsFocused } from "@react-navigation/native";
import { useLocalSearchParams, useRouter, useFocusEffect, useIsFocused } from "expo-router";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { LinearGradient } from "expo-linear-gradient";
import Animated, { FadeInDown } from "react-native-reanimated";
@@ -159,7 +159,7 @@ const styles = StyleSheet.create({
justifyContent: "flex-end",
},
backdrop: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.6)",
},
sheetContainer: {
@@ -203,13 +203,13 @@ const styles = StyleSheet.create({
marginTop: spacing.xs,
},
loadingOverlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.3)',
},
playOverlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
justifyContent: 'center',
alignItems: 'center',
},
@@ -220,7 +220,7 @@ const styles = StyleSheet.create({
},
// ...
inputFieldBorder: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
borderRadius: radius.xl,
borderWidth: 1,
borderColor: colors.border,
@@ -790,7 +790,7 @@ const styles = StyleSheet.create({
height: '100%',
},
photoLoadingOverlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.3)',
justifyContent: 'center',
alignItems: 'center',
@@ -179,7 +179,7 @@ const styles = StyleSheet.create({
justifyContent: "flex-end",
},
backdrop: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.6)",
},
sheetContainer: {
@@ -125,7 +125,7 @@ const styles = StyleSheet.create({
backgroundColor: 'rgba(0, 0, 0, 0.2)',
},
thumbnail: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
},
iconContainer: {
width: 64,
@@ -136,7 +136,7 @@ const styles = StyleSheet.create({
alignItems: 'center',
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useState } from "react";
import { ActivityIndicator, Pressable, RefreshControl, ScrollView, StyleSheet, Text, View } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useIsFocused } from "@react-navigation/native";
import { useIsFocused } from "expo-router";
import Animated, { FadeIn } from "react-native-reanimated";
import { GradientBackground } from "../../components/ui";
import { Paywall } from "../../components/paywall";
@@ -7,8 +7,7 @@ import {
Alert,
useWindowDimensions,
} from 'react-native';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { useIsFocused } from '@react-navigation/native';
import { useLocalSearchParams, useRouter, useIsFocused } from 'expo-router';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons';
import * as Haptics from 'expo-haptics';
@@ -21,7 +21,7 @@ import Animated, {
} from 'react-native-reanimated';
import { Ionicons } from '@expo/vector-icons';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import ViewShot from 'react-native-view-shot';
import ViewShot, { type ViewShotRef } from 'react-native-view-shot';
import * as Sharing from 'expo-sharing';
import * as FileSystem from 'expo-file-system/legacy';
import { colors, gradients, radius, typography, spacing, blur } from '../../../theme';
@@ -44,7 +44,7 @@ export function DrawingShareModal({
const insets = useSafeAreaInsets();
const { width: screenWidth } = useWindowDimensions();
const cardWidth = Math.min(screenWidth - 64, MAX_CARD_WIDTH);
const shareViewRef = useRef<ViewShot>(null);
const shareViewRef = useRef<ViewShotRef>(null);
const [capturedUri, setCapturedUri] = useState<string | null>(null);
const [isCapturing, setIsCapturing] = useState(false);
@@ -239,7 +239,7 @@ const styles = StyleSheet.create({
overflow: 'hidden',
},
proBorderGradient: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
opacity: 0.3,
},
proCardInner: {
@@ -330,7 +330,7 @@ const styles = StyleSheet.create({
overflow: 'hidden',
},
freeBorderGradient: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
},
freeHeader: {
@@ -51,7 +51,7 @@ const styles = StyleSheet.create({
justifyContent: "space-between",
},
overlay: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
backgroundColor: "rgba(0, 0, 0, 0.08)",
},
content: {
@@ -13,7 +13,7 @@ import { BlurView } from "expo-blur";
import Animated, { FadeIn, FadeOut, SlideInDown, SlideOutDown } from "react-native-reanimated";
import { Ionicons } from "@expo/vector-icons";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import ViewShot from "react-native-view-shot";
import ViewShot, { type ViewShotRef } from "react-native-view-shot";
import * as Sharing from "expo-sharing";
import { colors, spacing, typography, blur } from "../../../theme";
import { shareToInstagramStories } from "../../../lib/instagramShare";
@@ -32,7 +32,7 @@ export function QuizShareModal({ visible, onClose, scorePercent }: QuizShareModa
const insets = useSafeAreaInsets();
const { width: screenWidth } = useWindowDimensions();
const cardWidth = Math.min(screenWidth - 64, MAX_CARD_WIDTH);
const shareViewRef = useRef<ViewShot>(null);
const shareViewRef = useRef<ViewShotRef>(null);
const [capturedUri, setCapturedUri] = useState<string | null>(null);
const [isCapturing, setIsCapturing] = useState(false);
@@ -225,7 +225,7 @@ const styles = StyleSheet.create({
overflow: 'hidden',
},
premiumButtonGradient: {
...StyleSheet.absoluteFillObject,
...StyleSheet.absoluteFill,
},
premiumButtonContent: {
flexDirection: 'row',
+5 -2
View File
@@ -50,8 +50,6 @@ jest.mock('@supabase/supabase-js', () => {
};
});
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper', () => ({}), { virtual: true });
jest.mock('react-native-reanimated', () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Reanimated = require('react-native-reanimated/mock');
@@ -103,6 +101,11 @@ jest.mock('expo-image-picker', () => ({
},
}));
jest.mock('expo-media-library', () => ({
usePermissions: jest.fn(() => [{ granted: true }, jest.fn(async () => ({ granted: true }))]),
createAssetAsync: jest.fn(async () => ({ id: 'mock-asset-id' })),
}));
jest.mock('expo-file-system/legacy', () => ({
readAsStringAsync: jest.fn(async () => ''),
EncodingType: {