ui icon indicating copy to clipboard operation
ui copied to clipboard

Drawer custom onOpenChange is not working.

Open YouJun-IWON opened this issue 1 year ago • 4 comments

I convert isModalOpen from true to false with zustand, but it doesn't work.

'use client';
import { cn } from '@/utils';
import { useMediaQuery } from '@/hooks/custom/use-media-query';
import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog';
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from '@/components/ui/drawer';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useModal } from '@/hooks/stores/use-modal-store';
import React from 'react';

export function AgendaDetailContentModal() {
  const { isOpen, onClose, type, data } = useModal();
  const { detailContent } = data;
  const isModalOpen = isOpen && type === 'showAgendaDetailContent';
 //  const [open, setOpen] = React.useState(isModalOpen);


 
 // This return not working in the mobile environment. 
 
  return (
    <Drawer open={isModalOpen}  onOpenChange={onClose}>
      <DrawerContent>
        <DrawerHeader className='text-left'>
          <DrawerTitle>Edit profile</DrawerTitle>
          <DrawerDescription>
            Make changes to your profile here. Click save when you're done.
          </DrawerDescription>
        </DrawerHeader>
        <ProfileForm className='px-4' />
        <DrawerFooter className='pt-2'>
          <DrawerClose asChild>
            <Button variant='outline'>Cancel</Button>
          </DrawerClose>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  );
}

function ProfileForm({ className }: React.ComponentProps<'form'>) {
  return <form className={cn('grid items-start gap-4', className)}></form>;
}

This is zustand code.


import { create } from 'zustand';

export type ModalType = 'showAgendaDetailContent';

interface ModalData {
  detailContent?: any;
}

interface ModalStore {
  type: ModalType | null;
  data: ModalData;
  isOpen: boolean;
  onOpen: (type: ModalType, data?: ModalData) => void;
  onClose: () => void;
}

export const useModal = create<ModalStore>((set) => ({
  type: null,
  data: {},
  isOpen: false,
  onOpen: (type, data = {}) => set({ isOpen: true, type, data }),
  onClose: () => set({ type: null, isOpen: false }),
}));

When I checked the console, 'isModalOpen' changed to false as soon as it changed to true. How can i fix this?

From republic of korea

YouJun-IWON avatar Feb 19 '24 02:02 YouJun-IWON

remove the onOpenChange function from the drawer and call onClose function in the cancel button onclick event and that should work fine

pratikthapw avatar Feb 19 '24 03:02 pratikthapw

Any fix to this. I have the exact same Zustand configuration. I made a ModalWrapper which will render Dialog or Drawer responsively but the drawer won't open. Dialog is opening fine:

"use client";

import { useMediaQuery } from "@/helpers/(hooks)/useMediaQuery";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "../ui/dialog";
import {
  Drawer,
  DrawerContent,
  DrawerDescription,
  DrawerHeader,
  DrawerTitle,
} from "../ui/drawer";
import { useModal } from "@/helpers/(store)/ModalStore";

const ModalWrapper = ({
  children,
  open,
  onOpenChange,
  title,
  description,
}: {
  children: React.ReactNode;
  open: boolean;
  onOpenChange: () => void;
  title: string;
  description?: string;
}) => {
  const isDesktop = useMediaQuery("(min-width: 768px)");

  if (isDesktop) {
    return (
      <Dialog open={open} onOpenChange={onOpenChange}>
        <DialogContent className="sm:max-w-[425px]">
          <DialogHeader>
            <DialogTitle>{title}</DialogTitle>
            {description ? (
              <DialogDescription>{description}</DialogDescription>
            ) : null}
          </DialogHeader>
          <div className="py-4">{children}</div>
        </DialogContent>
      </Dialog>
    );
  }

  return (
    <Drawer open={open} onOpenChange={onOpenChange}>
      <DrawerContent>
        <DrawerHeader className="text-left">
          <DrawerTitle>{title}</DrawerTitle>
          <DrawerDescription>{description}</DrawerDescription>
        </DrawerHeader>
        <div className="py-4">{children}</div>
      </DrawerContent>
    </Drawer>
  );
};
export default ModalWrapper;

I am having the same issue. When console logging the isOpen state, it changes to true but immediately back to false. image

AbirSantra avatar May 13 '24 07:05 AbirSantra

remove the onOpenChange function from the drawer and call onClose function in the cancel button onclick event and that should work fine

This works, but it creates an issue wherein, user can click on the backgroup and the drawer won't close. Any solution for this?

naviava avatar May 17 '24 12:05 naviava

I think I found a temporary workaround. You can define a breakpoint variable in your state and when calling your onClose function, just do a check with Date.now() - breakpoint < 100.

onOpen: () =>
    set({ isOpen: true, breakPoint: Date.now() }),
onClose: () => {
    set((state) => {
      if (Date.now() - state.breakPoint < 100) {
        return { isOpen: true };
      }
      return { isOpen: false };
    });
  },

naviava avatar May 17 '24 12:05 naviava

This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.

shadcn avatar Jun 11 '24 23:06 shadcn

Sorry that I comment on a closed issue, but I created a Stackblitz reproducing this issue, https://stackblitz.com/edit/stackblitz-starters-pl9qx5?file=app%2Fpage.tsx.

Not sure if this bug is related to this issue in Vaul: https://github.com/emilkowalski/vaul/pull/291.

desiboli avatar Jun 17 '24 10:06 desiboli

+1, did someone find the solution?

olehmeserenko avatar Jun 26 '24 00:06 olehmeserenko

function, just do a check with Date.now() - breakpoint < 100.

onOpen: () =>
    set({ isOpen: true, breakPoint: Date.now() }),
onClose: () => {
    set((state) => {
      if (Date.now() - state.breakPoint < 100) {
        return { isOpen: true };
      }
      return { isOpen: false };
    });
  },

You saved my day , Thanks alot

viperxeyes avatar Jul 01 '24 14:07 viperxeyes

Guys, these functions (onEscapeKeyDown) are being called but don't know why it is not preventing closing the Drawer, any help?

const [isProcessing, setIsProcessing] = useState<boolean>(true)
<Drawer open={isOpen} onOpenChange={onOpenChange} direction="right">
      <DrawerContent
        onEscapeKeyDown={(e) => isProcessing && e.preventDefault()}
        onInteractOutside={(e) => isProcessing && e.preventDefault()}
        className="h-screen top-0 right-0 left-auto mt-0 w-[40%] rounded-none rounded-tl-2xl rounded-bl-2xl"
      >
      </DrawerContent>
    </Drawer>

Any help would be appreciated.

zahidiqbalnbs avatar Sep 21 '24 10:09 zahidiqbalnbs

I use this workaround if you don't use Zustand:

  const prevOpen = useRef(open);
  useEffect(() => {
    if (prevOpen.current && !open) {
      setTimeout(() => {
        document.body.style.pointerEvents = "auto";
      }, 400);
    }
    prevOpen.current = open;
  }, [open]);

In my case Drawer adds pointer events to the body tag, making it impossible to scroll anymore.

mk0y avatar Oct 20 '24 09:10 mk0y