react-native-reusables icon indicating copy to clipboard operation
react-native-reusables copied to clipboard

[ BUG ] dialog not working on ios device (overlay only, no content)

Open rwitchell opened this issue 10 months ago • 8 comments

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"
  },
}
  1. running: cd ios && pod install && cd .. && run eas-build-pre-install && expo prebuild && expo run:ios --configuration Release -d

Expected behavior (as expected)

Screenshots

Image

Platform (please complete the following information):

  • Type: Device
  • OS: ios 18.1.1
  • Browser (if applies) [e.g. chrome, safari]

Additional context (none)

rwitchell avatar Jan 30 '25 10:01 rwitchell

i'm having the same issue here.

mAmineSouissi avatar Jan 31 '25 21:01 mAmineSouissi

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.

rwitchell avatar Feb 01 '25 22:02 rwitchell

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

rwitchell avatar Feb 02 '25 03:02 rwitchell

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>
  );
});

bbaterdene-gh avatar Feb 05 '25 13:02 bbaterdene-gh

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

mrzachnugent avatar Feb 05 '25 13:02 mrzachnugent

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 />
...

tuke307 avatar Feb 16 '25 22:02 tuke307

Hey @tuke307 , did you try https://rnr-docs.vercel.app/getting-started/common-patterns/#a-portal-component-inside-a-presentation-modal-screen ?

mrzachnugent avatar Feb 17 '25 02:02 mrzachnugent

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!

tuke307 avatar Feb 17 '25 07:02 tuke307

@mrzachnugent Are dropdown menu and context menu Native components?

sujayxaradhya avatar Jul 22 '25 18:07 sujayxaradhya

@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

mrzachnugent avatar Aug 22 '25 17:08 mrzachnugent

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

mrzachnugent avatar Aug 22 '25 17:08 mrzachnugent