feat: refactor drawer component (#15892)
* Add sheet component * refactor user edit sheet * refactor availbility sheet edit * Remove tremor raw sheet text * remove accidently file commit * fix overflow issue
This commit is contained in:
@@ -105,11 +105,21 @@ module.exports = {
|
||||
spinning: {
|
||||
"100%": { transform: "rotate(360deg)" },
|
||||
},
|
||||
drawerSlideLeftAndFade: {
|
||||
from: { opacity: "0", transform: "translateX(100%)" },
|
||||
to: { opacity: "1", transform: "translateX(0)" },
|
||||
},
|
||||
drawerSlideRightAndFade: {
|
||||
from: { opacity: "1", transform: "translateX(0)" },
|
||||
to: { opacity: "0", transform: "translateX(100%)" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"fade-in-up": "fade-in-up 600ms var(--animation-delay, 0ms) cubic-bezier(.21,1.02,.73,1) forwards",
|
||||
"fade-in-bottom": "fade-in-bottom cubic-bezier(.21,1.02,.73,1) forwards",
|
||||
spinning: "spinning 0.75s linear infinite",
|
||||
drawerSlideLeftAndFade: "drawerSlideLeftAndFade 150ms cubic-bezier(0.16, 1, 0.3, 1)",
|
||||
drawerSlideRightAndFade: "drawerSlideRightAndFade 150ms ease-in",
|
||||
},
|
||||
boxShadow: {
|
||||
dropdown: "0px 2px 6px -1px rgba(0, 0, 0, 0.08)",
|
||||
|
||||
@@ -15,7 +15,10 @@ import {
|
||||
Form,
|
||||
Label,
|
||||
Sheet,
|
||||
SheetBody,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
showToast,
|
||||
@@ -151,22 +154,7 @@ export function AvailabilityEditSheetForm(props: Props & { data: Data; isPending
|
||||
...values,
|
||||
});
|
||||
}}>
|
||||
<SheetContent
|
||||
bottomActions={
|
||||
<>
|
||||
<Button color="secondary" className="w-full justify-center">
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!hasEditPermission || !data.hasDefaultSchedule}
|
||||
className="w-full justify-center"
|
||||
type="submit"
|
||||
loading={updateMutation.isPending}
|
||||
form="availability-form">
|
||||
{t("save")}
|
||||
</Button>
|
||||
</>
|
||||
}>
|
||||
<SheetContent>
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{t("edit_users_availability", {
|
||||
@@ -185,7 +173,7 @@ export function AvailabilityEditSheetForm(props: Props & { data: Data; isPending
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 flex flex-col space-y-4">
|
||||
<SheetBody className="mt-4 flex flex-col space-y-4">
|
||||
<div>
|
||||
<Label className="text-emphasis">
|
||||
<>{t("timezone")}</>
|
||||
@@ -220,7 +208,22 @@ export function AvailabilityEditSheetForm(props: Props & { data: Data; isPending
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SheetBody>
|
||||
<SheetFooter>
|
||||
<SheetClose asChild>
|
||||
<Button color="secondary" className="w-full justify-center">
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
</SheetClose>
|
||||
<Button
|
||||
disabled={!hasEditPermission || !data.hasDefaultSchedule}
|
||||
className="w-full justify-center"
|
||||
type="submit"
|
||||
loading={updateMutation.isPending}
|
||||
form="availability-form">
|
||||
{t("save")}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Form>
|
||||
</Sheet>
|
||||
|
||||
@@ -19,9 +19,13 @@ import {
|
||||
showToast,
|
||||
Avatar,
|
||||
ImageUploader,
|
||||
SheetHeader,
|
||||
SheetBody,
|
||||
SheetFooter,
|
||||
} from "@calcom/ui";
|
||||
|
||||
import type { Action } from "../UserListTable";
|
||||
import { SheetFooterControls } from "./SheetFooterControls";
|
||||
import { useEditMode } from "./store";
|
||||
|
||||
type MembershipOption = {
|
||||
@@ -117,73 +121,83 @@ export function EditForm({
|
||||
const watchTimezone = form.watch("timeZone");
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
id="edit-user-form"
|
||||
handleSubmit={(values) => {
|
||||
setMutationLoading(true);
|
||||
mutation.mutate({
|
||||
userId: selectedUser?.id ?? "",
|
||||
role: values.role,
|
||||
username: values.username,
|
||||
name: values.name,
|
||||
email: values.email,
|
||||
avatar: values.avatar,
|
||||
bio: values.bio,
|
||||
timeZone: values.timeZone,
|
||||
});
|
||||
}}>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="avatar"
|
||||
render={({ field: { value } }) => (
|
||||
<div className="flex items-center">
|
||||
<Avatar alt={`${selectedUser?.name} avatar`} imageSrc={value} size="lg" />
|
||||
<div className="ml-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
id="avatar-upload"
|
||||
buttonMsg={t("change_avatar")}
|
||||
handleAvatarChange={(newAvatar) => {
|
||||
form.setValue("avatar", newAvatar, { shouldDirty: true });
|
||||
}}
|
||||
imageSrc={value || undefined}
|
||||
/>
|
||||
</div>
|
||||
<>
|
||||
<Form
|
||||
form={form}
|
||||
id="edit-user-form"
|
||||
className="flex h-full flex-col"
|
||||
handleSubmit={(values) => {
|
||||
setMutationLoading(true);
|
||||
mutation.mutate({
|
||||
userId: selectedUser?.id ?? "",
|
||||
role: values.role,
|
||||
username: values.username,
|
||||
name: values.name,
|
||||
email: values.email,
|
||||
avatar: values.avatar,
|
||||
bio: values.bio,
|
||||
timeZone: values.timeZone,
|
||||
});
|
||||
}}>
|
||||
<SheetHeader>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="avatar"
|
||||
render={({ field: { value } }) => (
|
||||
<div className="flex items-center">
|
||||
<Avatar alt={`${selectedUser?.name} avatar`} imageSrc={value} size="lg" />
|
||||
<div className="ml-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
id="avatar-upload"
|
||||
buttonMsg={t("change_avatar")}
|
||||
handleAvatarChange={(newAvatar) => {
|
||||
form.setValue("avatar", newAvatar, { shouldDirty: true });
|
||||
}}
|
||||
imageSrc={value || undefined}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<div className="space-between flex flex-col leading-none">
|
||||
<span className="text-emphasis text-lg font-semibold">
|
||||
{selectedUser?.name ?? "Nameless User"}
|
||||
</span>
|
||||
<p className="subtle text-sm font-normal">
|
||||
{domainUrl}/{selectedUser?.username}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<div className="space-between flex flex-col leading-none">
|
||||
<span className="text-emphasis text-lg font-semibold">{selectedUser?.name ?? "Nameless User"}</span>
|
||||
<p className="subtle text-sm font-normal">
|
||||
{domainUrl}/{selectedUser?.username}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 flex flex-col space-y-3">
|
||||
<TextField label={t("username")} {...form.register("username")} />
|
||||
<TextField label={t("name")} {...form.register("name")} />
|
||||
<TextField label={t("email")} {...form.register("email")} />
|
||||
</div>
|
||||
</SheetHeader>
|
||||
<SheetBody className="mt-6 flex h-full flex-col space-y-3">
|
||||
<TextField label={t("username")} {...form.register("username")} />
|
||||
<TextField label={t("name")} {...form.register("name")} />
|
||||
<TextField label={t("email")} {...form.register("email")} />
|
||||
|
||||
<TextAreaField label={t("bio")} {...form.register("bio")} className="min-h-52" />
|
||||
<div>
|
||||
<Label>{t("role")}</Label>
|
||||
<ToggleGroup
|
||||
isFullWidth
|
||||
defaultValue={selectedUser?.role ?? "MEMBER"}
|
||||
value={form.watch("role")}
|
||||
options={membershipOptions}
|
||||
onValueChange={(value: EditSchema["role"]) => {
|
||||
form.setValue("role", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>{t("timezone")}</Label>
|
||||
<TimezoneSelect value={watchTimezone ?? "America/Los_Angeles"} />
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
<TextAreaField label={t("bio")} {...form.register("bio")} className="min-h-52" />
|
||||
<div>
|
||||
<Label>{t("role")}</Label>
|
||||
<ToggleGroup
|
||||
isFullWidth
|
||||
defaultValue={selectedUser?.role ?? "MEMBER"}
|
||||
value={form.watch("role")}
|
||||
options={membershipOptions}
|
||||
onValueChange={(value: EditSchema["role"]) => {
|
||||
form.setValue("role", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>{t("timezone")}</Label>
|
||||
<TimezoneSelect value={watchTimezone ?? "America/Los_Angeles"} />
|
||||
</div>
|
||||
</SheetBody>
|
||||
<SheetFooter>
|
||||
<SheetFooterControls />
|
||||
</SheetFooter>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,19 @@ import { useOrgBranding } from "@calcom/ee/organizations/context/provider";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Avatar, Label, Loader, Sheet, SheetContent, SheetFooter, Skeleton } from "@calcom/ui";
|
||||
import {
|
||||
Avatar,
|
||||
Label,
|
||||
Loader,
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetBody,
|
||||
Skeleton,
|
||||
SheetHeader,
|
||||
SheetDescription,
|
||||
SheetTitle,
|
||||
SheetFooter,
|
||||
} from "@calcom/ui";
|
||||
|
||||
import type { Action, State } from "../UserListTable";
|
||||
import { DisplayInfo } from "./DisplayInfo";
|
||||
@@ -35,32 +47,34 @@ export function EditUserSheet({ state, dispatch }: { state: State; dispatch: Dis
|
||||
setEditMode(false);
|
||||
dispatch({ type: "CLOSE_MODAL" });
|
||||
}}>
|
||||
<SheetContent position="right" size="default">
|
||||
<SheetContent>
|
||||
{!isPending && loadedUser ? (
|
||||
<div className="flex h-full flex-col">
|
||||
<>
|
||||
{!editMode ? (
|
||||
<div className="flex-grow">
|
||||
<div className="mt-4 flex items-center gap-2">
|
||||
<>
|
||||
<SheetHeader>
|
||||
<Avatar
|
||||
asChild
|
||||
className="h-[36px] w-[36px]"
|
||||
alt={`${loadedUser?.name} avatar`}
|
||||
imageSrc={loadedUser.avatarUrl}
|
||||
/>
|
||||
<div className="space-between flex flex-col leading-none">
|
||||
<SheetTitle>
|
||||
<Skeleton loading={isPending} as="p" waitForTranslation={false}>
|
||||
<span className="text-emphasis text-lg font-semibold">
|
||||
{loadedUser?.name ?? "Nameless User"}
|
||||
</span>
|
||||
</Skeleton>
|
||||
</SheetTitle>
|
||||
<SheetDescription>
|
||||
<Skeleton loading={isPending} as="p" waitForTranslation={false}>
|
||||
<p className="subtle text-sm font-normal">
|
||||
{orgBranding?.fullDomain ?? WEBAPP_URL}/{loadedUser?.username}
|
||||
</p>
|
||||
</Skeleton>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 flex flex-col space-y-5">
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<SheetBody className="flex flex-col space-y-5">
|
||||
<DisplayInfo label={t("email")} value={loadedUser?.email ?? ""} displayCopy />
|
||||
<DisplayInfo
|
||||
label={t("bio")}
|
||||
@@ -94,22 +108,22 @@ export function EditUserSheet({ state, dispatch }: { state: State; dispatch: Dis
|
||||
}
|
||||
asBadge={teamNames && teamNames?.length > 0}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SheetBody>
|
||||
<SheetFooter>
|
||||
<SheetFooterControls />
|
||||
</SheetFooter>
|
||||
</>
|
||||
) : (
|
||||
<div className="mb-4 flex-grow">
|
||||
<>
|
||||
<EditForm
|
||||
selectedUser={loadedUser}
|
||||
avatarUrl={loadedUser.avatarUrl ?? avatarURL}
|
||||
domainUrl={orgBranding?.fullDomain ?? WEBAPP_URL}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<SheetFooter className="mt-auto">
|
||||
<SheetFooterControls />
|
||||
</SheetFooter>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
|
||||
@@ -1,215 +1,173 @@
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import * as SheetPrimitives from "@radix-ui/react-dialog";
|
||||
import * as React from "react";
|
||||
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
const Sheet = SheetPrimitive.Root;
|
||||
import { Button } from "../button";
|
||||
|
||||
const SheetTrigger = SheetPrimitive.Trigger;
|
||||
const Sheet = (props: React.ComponentPropsWithoutRef<typeof SheetPrimitives.Root>) => {
|
||||
return <SheetPrimitives.Root {...props} />;
|
||||
};
|
||||
Sheet.displayName = "Sheet";
|
||||
|
||||
const SheetClose = SheetPrimitive.Close;
|
||||
|
||||
const portalVariants = cva("fixed inset-0 z-50 flex", {
|
||||
variants: {
|
||||
position: {
|
||||
top: "items-start",
|
||||
bottom: "items-end",
|
||||
left: "justify-start",
|
||||
right: "justify-end",
|
||||
},
|
||||
},
|
||||
defaultVariants: { position: "right" },
|
||||
const SheetTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitives.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitives.Trigger>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return <SheetPrimitives.Trigger ref={ref} className={classNames(className)} {...props} />;
|
||||
});
|
||||
SheetTrigger.displayName = "Sheet.Trigger";
|
||||
|
||||
interface SheetPortalProps extends SheetPrimitive.DialogPortalProps, VariantProps<typeof portalVariants> {}
|
||||
const SheetClose = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitives.Close>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitives.Close>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return <SheetPrimitives.Close ref={ref} className={classNames(className)} {...props} />;
|
||||
});
|
||||
SheetClose.displayName = "Sheet.Close";
|
||||
|
||||
const SheetPortal = ({ position, className, children, ...props }: SheetPortalProps) => (
|
||||
<SheetPrimitive.Portal className={classNames(className)} {...props}>
|
||||
<div className={portalVariants({ position })}>{children}</div>
|
||||
</SheetPrimitive.Portal>
|
||||
);
|
||||
SheetPortal.displayName = SheetPrimitive.Portal.displayName;
|
||||
const SheetPortal = SheetPrimitives.Portal;
|
||||
|
||||
SheetPortal.displayName = "SheetPortal";
|
||||
|
||||
const SheetOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={classNames(
|
||||
"data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in fixed inset-0 z-50 bg-neutral-800 bg-opacity-70 backdrop-blur-[1px] transition-all duration-100",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
));
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
||||
React.ElementRef<typeof SheetPrimitives.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitives.Overlay>
|
||||
>(({ className, ...props }, forwardedRef) => {
|
||||
return (
|
||||
<SheetPrimitives.Overlay
|
||||
ref={forwardedRef}
|
||||
className={classNames(
|
||||
// base
|
||||
"fixed inset-0 z-50 overflow-y-auto",
|
||||
// background color
|
||||
"bg-black/30",
|
||||
// transition
|
||||
"data-[state=closed]:animate-hide data-[state=open]:animate-dialogOverlayShow",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
style={{
|
||||
animationDuration: "400ms",
|
||||
animationFillMode: "backwards",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const sheetVariants = cva(
|
||||
"fixed z-50 scale-100 gap-4 bg-default m-4 rounded-xl p-6 opacity-100 shadow-lg border border-default flex flex-col ",
|
||||
{
|
||||
variants: {
|
||||
position: {
|
||||
top: "animate-in slide-in-from-top w-full duration-200",
|
||||
bottom: "animate-in slide-in-from-bottom w-full duration-200",
|
||||
left: "animate-in slide-in-from-left h-full duration-200",
|
||||
right: "animate-in slide-in-from-right h-full duration-200",
|
||||
},
|
||||
size: {
|
||||
content: "",
|
||||
default: "",
|
||||
sm: "",
|
||||
lg: "",
|
||||
xl: "",
|
||||
full: "",
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "content",
|
||||
class: "max-h-screen",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "default",
|
||||
class: "h-1/3",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "sm",
|
||||
class: "h-1/4",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "lg",
|
||||
class: "h-1/2",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "xl",
|
||||
class: "h-5/6",
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "full",
|
||||
class: "h-screen",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "content",
|
||||
class: "max-w-screen",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "default",
|
||||
class: "w-[calc(100%-2rem)] lg:w-1/3 max-h-[calc(100vh-2rem)]",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "sm",
|
||||
class: "w-1/4 max-h-[calc(100vh-2rem)]",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "lg",
|
||||
class: "w-1/2 h-[calc(100vh-2rem)]",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "xl",
|
||||
class: "w-5/6 h-[calc(100vh-2rem)]",
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "full",
|
||||
class: "w-screen h-[calc(100vh-2rem)]",
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
position: "right",
|
||||
size: "default",
|
||||
},
|
||||
SheetOverlay.displayName = "SheetOverlay";
|
||||
|
||||
const SheetContent = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitives.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitives.Content>
|
||||
>(({ className, ...props }, forwardedRef) => {
|
||||
return (
|
||||
<SheetPortal>
|
||||
<SheetOverlay>
|
||||
<SheetPrimitives.Content
|
||||
ref={forwardedRef}
|
||||
className={classNames(
|
||||
// base
|
||||
"fixed inset-y-2 mx-auto flex w-[95vw] flex-1 flex-col overflow-y-auto rounded-md border p-4 shadow-lg focus:outline-none max-sm:inset-x-2 sm:inset-y-2 sm:right-2 sm:max-w-lg sm:p-6",
|
||||
// border color
|
||||
"border-subtle",
|
||||
// background color
|
||||
"bg-default",
|
||||
// transition
|
||||
"data-[state=closed]:animate-SheetSlideRightAndFade data-[state=open]:animate-SheetSlideLeftAndFade",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</SheetOverlay>
|
||||
</SheetPortal>
|
||||
);
|
||||
});
|
||||
|
||||
SheetContent.displayName = "SheetContent";
|
||||
|
||||
const SheetHeader = React.forwardRef<HTMLDivElement, React.ComponentPropsWithoutRef<"div">>(
|
||||
({ children, className, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className="border-subtle flex items-start justify-between gap-x-4 border-b pb-2"
|
||||
{...props}>
|
||||
<div className={classNames("mt-1 flex flex-col gap-y-1", className)}>{children}</div>
|
||||
<SheetPrimitives.Close asChild>
|
||||
<Button variant="icon" StartIcon="x" color="minimal" className="aspect-square p-1" />
|
||||
</SheetPrimitives.Close>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export interface DialogContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
VariantProps<typeof sheetVariants> {
|
||||
bottomActions?: React.ReactNode;
|
||||
}
|
||||
|
||||
const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Content>, DialogContentProps>(
|
||||
({ position, size, className, children, bottomActions, ...props }, ref) => (
|
||||
<SheetPortal position={position}>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={classNames(sheetVariants({ position, size }), className)}>
|
||||
<div className="no-scrollbar h-full overflow-y-auto">{children}</div>
|
||||
{bottomActions && (
|
||||
<div className="mt-auto flex justify-end">
|
||||
<div className="flex gap-2">{bottomActions}</div>
|
||||
</div>
|
||||
)}
|
||||
<SheetPrimitive.Close className="focus:ring-emphasis data-[state=open]:bg-deafult absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
|
||||
<Icon name="x" className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
||||
)
|
||||
);
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
||||
|
||||
const SheetHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={classNames("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
|
||||
);
|
||||
SheetHeader.displayName = "SheetHeader";
|
||||
|
||||
const SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={classNames("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
SheetFooter.displayName = "SheetFooter";
|
||||
SheetHeader.displayName = "Sheet.Header";
|
||||
|
||||
const SheetTitle = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={classNames("text-foreground text-lg font-semibold", className)}
|
||||
React.ElementRef<typeof SheetPrimitives.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitives.Title>
|
||||
>(({ className, ...props }, forwardedRef) => (
|
||||
<SheetPrimitives.Title
|
||||
ref={forwardedRef}
|
||||
className={classNames(
|
||||
// base
|
||||
"text-base font-semibold",
|
||||
// text color
|
||||
"text-default",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
||||
|
||||
SheetTitle.displayName = "SheetTitle";
|
||||
|
||||
const SheetBody = React.forwardRef<HTMLDivElement, React.ComponentPropsWithoutRef<"div">>(
|
||||
({ className, ...props }, ref) => {
|
||||
return <div ref={ref} className={classNames("flex-1 overflow-y-auto py-4", className)} {...props} />;
|
||||
}
|
||||
);
|
||||
|
||||
SheetBody.displayName = "Sheet.Body";
|
||||
|
||||
const SheetDescription = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={classNames("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
||||
React.ElementRef<typeof SheetPrimitives.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitives.Description>
|
||||
>(({ className, ...props }, forwardedRef) => {
|
||||
return (
|
||||
<SheetPrimitives.Description
|
||||
ref={forwardedRef}
|
||||
className={classNames("text-default", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
SheetDescription.displayName = "SheetDescription";
|
||||
|
||||
const SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"border-muted x flex flex-col-reverse border-t pt-4 sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
SheetFooter.displayName = "SheetFooter";
|
||||
|
||||
export {
|
||||
Sheet,
|
||||
SheetTrigger,
|
||||
SheetBody,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
};
|
||||
|
||||
@@ -172,6 +172,7 @@ export { WizardLayoutAppDir } from "./layouts/WizardLayoutAppDir";
|
||||
export { DataTable } from "./components/data-table";
|
||||
export {
|
||||
Sheet,
|
||||
SheetBody,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
|
||||
Reference in New Issue
Block a user