react-native-reusables
react-native-reusables copied to clipboard
[ BUG ] dialog not working on ios device (overlay only, no content)
Describe the bug
The dialog is working fine on ios simulator, but fails to work correctly on device. The overlay occurs, but then the content doesn't load. I've traced it to animated view. When I remove the entering prop inside the DialogOverlayNative function, it works.
export const Home = () => {
return (
<>
<ScrollView>
<StyledView className="flex-1 p-4">
<StyledView className="mb-4 flex-row flex-wrap gap-2">
<Dialog>
<DialogTrigger>
<Text>Open?</Text>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account and
remove your data from our servers.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
</StyledView>
</StyledView>
</ScrollView>
</>
}
To Reproduce Steps to reproduce the behavior:
{
"dependencies": {
"@expo/vector-icons": "14.0.4",
"@gorhom/bottom-sheet": "5.0.6",
"@hookform/resolvers": "3.9.1",
"@radix-ui/react-checkbox": "1.1.3",
"@radix-ui/react-dialog": "1.1.2",
"@radix-ui/react-label": "2.1.0",
"@radix-ui/react-radio-group": "1.2.1",
"@radix-ui/react-select": "2.1.2",
"@radix-ui/react-separator": "1.1.0",
"@radix-ui/react-slot": "1.1.0",
"@radix-ui/react-tooltip": "1.1.3",
"@react-native-async-storage/async-storage": "1.23.1",
"@react-navigation/native": "^7.0.0",
"@rn-primitives/accordion": "1.1.0",
"@rn-primitives/alert-dialog": "1.1.0",
"@rn-primitives/aspect-ratio": "1.1.0",
"@rn-primitives/avatar": "1.1.0",
"@rn-primitives/checkbox": "1.1.0",
"@rn-primitives/collapsible": "1.1.0",
"@rn-primitives/context-menu": "1.1.0",
"@rn-primitives/dialog": "1.1.0",
"@rn-primitives/dropdown-menu": "1.1.0",
"@rn-primitives/hover-card": "1.1.0",
"@rn-primitives/label": "1.1.0",
"@rn-primitives/menubar": "1.1.0",
"@rn-primitives/navigation-menu": "1.1.0",
"@rn-primitives/portal": "1.1.0",
"@rn-primitives/progress": "1.1.0",
"@rn-primitives/radio-group": "1.1.0",
"@rn-primitives/select": "1.1.0",
"@rn-primitives/separator": "1.1.0",
"@rn-primitives/slot": "1.1.0",
"@rn-primitives/switch": "1.1.0",
"@rn-primitives/table": "1.1.0",
"@rn-primitives/tabs": "1.1.0",
"@rn-primitives/toggle": "1.1.0",
"@rn-primitives/toggle-group": "1.1.0",
"@rn-primitives/tooltip": "1.1.0",
"@rneui/themed": "4.0.0-rc.8",
"@shopify/flash-list": "1.7.1",
"@supabase/supabase-js": "2.46.1",
"@tanstack/react-table": "8.20.5",
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"date-fns": "^4.1.0",
"expo": "52.0.20",
"expo-apple-authentication": "~7.1.3",
"expo-constants": "17.0.3",
"expo-dev-client": "~5.0.8",
"expo-font": "13.0.2",
"expo-haptics": "14.0.1",
"expo-linking": "7.0.3",
"expo-router": "4.0.14",
"expo-splash-screen": "0.29.18",
"expo-status-bar": "2.0.0",
"expo-system-ui": "4.0.6",
"expo-web-browser": "14.0.1",
"lucide-react": "0.456.0",
"lucide-react-native": "0.456.0",
"nativewind": "4.1.23",
"react": "18.3.1",
"react-hook-form": "7.54.1",
"react-native": "0.76.5",
"react-native-calendars": "1.1307.0",
"react-native-gesture-handler": "~2.20.2",
"react-native-modal": "13.0.1",
"react-native-reanimated": "3.16.5",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.1.0",
"react-native-svg": "15.8.0",
"react-native-web": "0.19.13",
"tailwind-merge": "2.5.4",
"tailwindcss": "3.4.17",
"tailwindcss-animate": "1.0.7",
"zod": "3.23.8"
},
}
- running:
cd ios && pod install && cd .. && run eas-build-pre-install && expo prebuild && expo run:ios --configuration Release -d
Expected behavior (as expected)
Screenshots
Platform (please complete the following information):
- Type: Device
- OS: ios 18.1.1
- Browser (if applies) [e.g. chrome, safari]
Additional context (none)
i'm having the same issue here.
removing the fadein allows the modal to appear, however the content isn't selectable. For example:
<Dialog>
<DialogTrigger asChild>
<Button variant="outline" className="rounded-full">
<Text>Level: {filter.levels === 'all' ? 'All' : filter.levels}</Text>
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Select Level</DialogTitle>
</DialogHeader>
<Select
onOpenChange={() => {
console.log('onOpenChange called')
}}
onValueChange={option => {
console.log('onValueChange called')
setFilter({ ...filter, levels: option.value })
}}
value={{ value: filter.levels, label: filter.levels }}
defaultValue={{ value: filter.levels, label: filter.levels }}
>
<SelectTrigger>
<SelectValue placeholder={'select a level'} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem label="All Levels" value="all" />
<SelectItem label="1" value="1" />
<SelectItem label="2" value="2" />
</SelectGroup>
</SelectContent>
</Select>
</DialogContent>
</Dialog>
tapping the select causes the onOpenChange called in the logs, though no DOM change. I haven't had time to do further investigatory work just yet.
okay, this is happening because of the reduceMotion ios setting on my device.
there is an entering prop on the selectPrimitive (as well as other RNR components) that is causing the element not to work.
I haven't been able to get the React Native Reanimated's ReduceMotion.Never property or ReduceMotion() chain to work just yet, either.
Overall, this is a bit of a problem for anyone creating apps using these components for devices using the reduceMotion ios setting, so i think a code change to this library should be encouraged to deal with this
I made it work by using useReducedMotion.
const reduceMotion = useReducedMotion();
Then I had to set undefined on entering, exiting props when reduceMotion is ON.
entering={reduceMotion ? undefined : FadeIn.duration(150)}
exiting={reduceMotion ? undefined : FadeOut.duration(150)}
Below is my working code
import Animated, {
FadeIn,
FadeOut,
useReducedMotion,
} from "react-native-reanimated";
const AlertDialogOverlayNative = React.forwardRef<
AlertDialogPrimitive.OverlayRef,
AlertDialogPrimitive.OverlayProps
>(({ className, children, ...props }, ref) => {
const reduceMotion = useReducedMotion();
return (
<AlertDialogPrimitive.Overlay
style={StyleSheet.absoluteFill}
className={cn(
"z-50 bg-black/80 flex justify-center items-center p-2",
className
)}
{...props}
ref={ref}
asChild
>
<Animated.View
entering={reduceMotion ? undefined : FadeIn.duration(150)}
exiting={reduceMotion ? undefined : FadeOut.duration(150)}
>
{children}
</Animated.View>
</AlertDialogPrimitive.Overlay>
);
});
You can use the <ReducedMotionConfig /> provider https://docs.swmansion.com/react-native-reanimated/docs/device/ReducedMotionConfig/
I'll add it to the root layout soon.
@rwitchell thanks for bringing this up and finding the root cause
Edit: for layout specific animations, you can also chain .reduceMotion(ReduceMotion.System) https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility#reduced-motion-in-layout-animations
i actually also found out, that the dialog is not working on ios with presentation set to fullScreenModal at root layout. when i then triggered a dialog on sub pages, the dialog was not shown because it was behind the full screen modal so basically every page.
export default function RootLayout() {
...
return (
...
<Stack
screenOptions={{
presentation: 'fullScreenModal'
}} />
<PortalHost />
...
Hey @tuke307 , did you try https://rnr-docs.vercel.app/getting-started/common-patterns/#a-portal-component-inside-a-presentation-modal-screen ?
Hey @tuke307 , did you try https://rnr-docs.vercel.app/getting-started/common-patterns/#a-portal-component-inside-a-presentation-modal-screen ?
Actually no, thank you!
@mrzachnugent Are dropdown menu and context menu Native components?
@sujayxaradhya They use View, Pressable, and Text from react-native which are technically native components but they are not made from ios/android UI menus
All components that use a Portal, like the dialog, now have use FullWindowOverlay in the component definition. https://github.com/founded-labs/react-native-reusables/blob/main/packages/registry/src/new-york/components/ui/dialog.tsx