Files
doormilxpress_astryx/src/components/ds/Drawer.jsx

87 lines
2.9 KiB
JavaScript

import * as React from 'react';
import { cn } from '@/lib/utils';
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet';
/**
* Panel widths.
*
* Each entry states its `max-w` as well as its `w`. The underlying Sheet caps a
* side panel at `sm:max-w-sm` (24rem), so a width alone was silently ignored on
* desktop and every "large" drawer in the app was drawn at phone width — the
* reason detail panels wrapped and scrolled far more than their content needed.
*/
const WIDTHS = {
sm: 'w-full sm:w-80 sm:max-w-[20rem]',
default: 'w-full sm:w-[28rem] sm:max-w-[28rem]',
lg: 'w-full sm:w-[36rem] sm:max-w-[36rem]',
/* A record with a two-column body: 704px on desktop, 768px from `2xl`
(1536px and up), and never the whole screen — the page behind it stays
visible, which is what keeps the drawer a drawer. */
xl: 'w-full sm:w-[44rem] sm:max-w-[44rem] 2xl:w-[48rem] 2xl:max-w-[48rem]',
};
/**
* Drawer — an edge-anchored panel for detail views, filters and mobile nav.
*
* Same header/body/footer contract as Modal, so the two are interchangeable:
* a detail view can be a Drawer on desktop and a bottom sheet on mobile without
* its contents changing.
*/
export function Drawer({
open,
onOpenChange,
title,
description,
icon: Icon,
side = 'right',
size = 'default',
footer,
children,
className,
/** Hides the header for a fully custom panel (the mobile nav does this). */
bare = false,
}) {
const isVertical = side === 'top' || side === 'bottom';
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent
side={side}
className={cn(
'p-0 gap-0 flex flex-col',
isVertical ? 'h-auto max-h-[85vh]' : WIDTHS[size],
className
)}
>
{!bare && (
<SheetHeader className="px-5 sm:px-6 pt-5 pb-4 border-b border-border shrink-0 space-y-0 text-left">
<div className="flex items-start gap-3">
{Icon && (
<span className="grid place-items-center w-9 h-9 rounded-xl bg-krow-blue-tint text-krow-blue shrink-0">
<Icon className="w-4.5 h-4.5" aria-hidden="true" />
</span>
)}
<div className="min-w-0">
<SheetTitle className="text-title font-heading text-ink-1">{title}</SheetTitle>
{description && (
<SheetDescription className="text-body-sm text-ink-3 mt-1">
{description}
</SheetDescription>
)}
</div>
</div>
</SheetHeader>
)}
<div className="flex-1 overflow-y-auto px-5 py-5 sm:px-6">{children}</div>
{footer && (
<div className="px-5 sm:px-6 py-4 border-t border-border bg-surface-subtle shrink-0 flex items-center justify-end gap-2">
{footer}
</div>
)}
</SheetContent>
</Sheet>
);
}