{ "name": "responsive-dialog", "type": "registry:ui", "files": [ { "path": "ui/responsive-dialog.tsx", "type": "registry:ui", "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { useAsRef } from \"@/registry/bases/base/hooks/use-as-ref\";\nimport { useIsomorphicLayoutEffect } from \"@/registry/bases/base/hooks/use-isomorphic-layout-effect\";\nimport { useLazyRef } from \"@/registry/bases/base/hooks/use-lazy-ref\";\nimport { useIsMobile } from \"@/registry/bases/base/hooks/use-mobile\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n} from \"@/registry/bases/base/ui/dialog\";\nimport {\n Drawer,\n DrawerClose,\n DrawerContent,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerOverlay,\n DrawerPortal,\n DrawerTitle,\n DrawerTrigger,\n} from \"@/registry/bases/base/ui/drawer\";\n\nconst ROOT_NAME = \"ResponsiveDialog\";\n\ninterface StoreState {\n open: boolean;\n isMobile: boolean;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => StoreState;\n setState: (key: K, value: StoreState[K]) => void;\n notify: () => void;\n}\n\nconst StoreContext = React.createContext(null);\n\nfunction useStore(\n selector: (state: StoreState) => T,\n ogStore?: Store | null,\n): T {\n const contextStore = React.useContext(StoreContext);\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`useStore\\` must be used within \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(\n () => selector(store.getState()),\n [store, selector],\n );\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface ResponsiveDialogProps extends React.ComponentProps {\n breakpoint?: number;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n modal?: boolean;\n}\n\nfunction ResponsiveDialog({\n breakpoint = 768,\n open: openProp,\n defaultOpen = false,\n onOpenChange: onOpenChangeProp,\n ...props\n}: ResponsiveDialogProps) {\n const isMobile = useIsMobile(breakpoint);\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef(() => ({\n open: openProp ?? defaultOpen,\n isMobile,\n }));\n\n const onOpenChangeRef = useAsRef(onOpenChangeProp);\n\n const store = React.useMemo(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, value) => {\n if (Object.is(stateRef.current[key], value)) return;\n\n if (key === \"open\" && typeof value === \"boolean\") {\n stateRef.current.open = value;\n onOpenChangeRef.current?.(value);\n } else {\n stateRef.current[key] = value;\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n },\n };\n }, [listenersRef, stateRef, onOpenChangeRef]);\n\n if (stateRef.current.isMobile !== isMobile) {\n stateRef.current.isMobile = isMobile;\n }\n\n const open = useStore((state) => state.open, store);\n\n useIsomorphicLayoutEffect(() => {\n if (openProp !== undefined) {\n store.setState(\"open\", openProp);\n }\n }, [openProp]);\n\n const onOpenChange = React.useCallback(\n (value: boolean) => {\n store.setState(\"open\", value);\n },\n [store],\n );\n\n if (isMobile) {\n return (\n \n \n \n );\n }\n\n return (\n \n \n \n );\n}\n\ninterface ResponsiveDialogTriggerProps extends React.ComponentProps<\"button\"> {\n render?: React.ComponentProps[\"render\"];\n}\n\nfunction ResponsiveDialogTrigger({\n render,\n children,\n ...props\n}: ResponsiveDialogTriggerProps) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return render && React.isValidElement(render) ? (\n \n {render}\n \n ) : (\n \n {children}\n \n );\n }\n\n return render ? (\n \n ) : (\n \n {children}\n \n );\n}\n\ninterface ResponsiveDialogCloseProps extends React.ComponentProps<\"button\"> {\n render?: React.ComponentProps[\"render\"];\n}\n\nfunction ResponsiveDialogClose({\n render,\n children,\n ...props\n}: ResponsiveDialogCloseProps) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return render && React.isValidElement(render) ? (\n \n {render}\n \n ) : (\n \n {children}\n \n );\n }\n\n return render ? (\n \n ) : (\n \n {children}\n \n );\n}\n\ninterface ResponsiveDialogPortalProps\n extends React.ComponentProps {\n container?: HTMLElement | null;\n}\n\nfunction ResponsiveDialogPortal({\n children,\n container,\n}: ResponsiveDialogPortalProps) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return (\n \n {children}\n \n );\n }\n\n return (\n \n {children}\n \n );\n}\n\ninterface ResponsiveDialogOverlayProps\n extends Omit, \"className\"> {\n className?: string;\n}\n\nfunction ResponsiveDialogOverlay({\n forceRender,\n render,\n ...props\n}: ResponsiveDialogOverlayProps) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return (\n \n );\n }\n\n return (\n \n );\n}\n\nfunction ResponsiveDialogContent({\n className,\n showCloseButton,\n ...props\n}: React.ComponentProps) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return (\n \n );\n }\n\n return (\n \n );\n}\n\nfunction ResponsiveDialogHeader({\n ...props\n}: React.ComponentProps) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return ;\n }\n\n return ;\n}\n\nfunction ResponsiveDialogFooter({\n showCloseButton,\n ...props\n}: React.ComponentProps) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return ;\n }\n\n return (\n \n );\n}\n\nfunction ResponsiveDialogTitle({ ...props }: React.ComponentProps<\"h2\">) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return ;\n }\n\n return ;\n}\n\nfunction ResponsiveDialogDescription({ ...props }: React.ComponentProps<\"p\">) {\n const isMobile = useStore((state) => state.isMobile);\n\n if (isMobile) {\n return ;\n }\n\n return ;\n}\n\nexport {\n ResponsiveDialog,\n ResponsiveDialogClose,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogOverlay,\n ResponsiveDialogPortal,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n};\n", "target": "" } ], "registryDependencies": [ "dialog", "drawer", "@diceui/use-as-ref", "@diceui/use-isomorphic-layout-effect", "@diceui/use-lazy-ref", "@diceui/use-mobile" ], "dependencies": [ "vaul" ] }