Sheet
Extends the Dialog component to display content that complements the main screen of an application.
Installation
bash npx @moe/cli add sheet Install the following dependency:
npx expo install @rn-primitives/dialogCopy/paste the following code to @/components/ui/sheet.tsx
import * as SheetPrimitive from "@rn-primitives/dialog";
import * as React from "react";
import { Platform, StyleSheet, View, type ViewStyle } from "react-native";
import Animated, {
SlideInRight,
SlideOutRight,
FadeIn,
FadeOut,
} from "react-native-reanimated";
import { X } from "@/lib/icons/X";
import { cn } from "@/lib/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => {
return (
<SheetPrimitive.Overlay
style={StyleSheet.absoluteFill}
className={cn(
"z-50 bg-black/80 flex justify-center items-center p-2",
props.open
? "web:animate-in web:fade-in-0"
: "web:animate-out web:fade-out-0",
className,
)}
{...props}
ref={ref}
>
<Animated.View
entering={FadeIn.duration(150)}
exiting={FadeOut.duration(150)}
/>
</SheetPrimitive.Overlay>
);
});
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> & {
portalHost?: string;
side?: "top" | "bottom" | "left" | "right";
}
>(({ className, children, portalHost, side = "right", ...props }, ref) => {
return (
<SheetPortal hostName={portalHost}>
<SheetOverlay>
<SheetPrimitive.Content
ref={ref}
className={cn(
"z-50 gap-4 border-l border-border bg-background p-6 shadow-lg web:cursor-default absolute h-full w-3/4 sm:max-w-sm",
side === "right" && "right-0 top-0 border-l",
side === "bottom" && "bottom-0 left-0 right-0 border-t h-auto",
props.open
? "web:animate-in web:fade-in-0 web:slide-in-from-right"
: "web:animate-out web:fade-out-0 web:slide-out-to-right",
className,
)}
{...props}
>
{children}
<SheetPrimitive.Close
className={
"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"
}
>
<X size={18} className="text-muted-foreground" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetOverlay>
</SheetPortal>
);
});
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.ComponentPropsWithoutRef<typeof View>) => (
<View
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.ComponentPropsWithoutRef<typeof View>) => (
<View
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetOverlay,
SheetPortal,
SheetTitle,
SheetTrigger,
};Usage
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@moe/registry/ui/sheet";
export function SheetDemo() {
return (
<Sheet>
<SheetTrigger>Open</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
);
}