use topcoat::{
Result,
runtime::Expr,
view::{Attributes, Child, StaticClass, View, class, component, view},
};
const OVERLAY: StaticClass = class!(
"fixed inset-0 z-50 size-full max-h-none max-w-none overflow-hidden",
"bg-black/50 text-foreground open:flex",
);
const FADE: StaticClass = class!(
"opacity-0 open:opacity-100 starting:open:opacity-0",
"[transition:opacity_200ms_ease-out,display_200ms_allow-discrete]",
);
#[component]
pub async fn sheet(
#[into]
open: Expr<bool>,
#[default]
mut attrs: Attributes,
#[default]
child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<dialog
:open=(open)
class=(class!(OVERLAY, FADE, attrs.remove("class")))
(attrs)
>
(child)
</dialog>
})
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[allow(dead_code)]
pub enum SheetSide {
Left,
#[default]
Right,
Top,
Bottom,
}
impl SheetSide {
fn classes(self) -> StaticClass {
match self {
Self::Left => class!("mr-auto h-full w-full max-w-sm border-r"),
Self::Right => class!("ml-auto h-full w-full max-w-sm border-l"),
Self::Top => class!("mb-auto max-h-full w-full border-b"),
Self::Bottom => class!("mt-auto max-h-full w-full border-t"),
}
}
fn motion(self) -> StaticClass {
match self {
Self::Left => class!(
"-translate-x-full in-[[open]]:translate-x-0",
"starting:in-[[open]]:-translate-x-full",
),
Self::Right => class!(
"translate-x-full in-[[open]]:translate-x-0",
"starting:in-[[open]]:translate-x-full",
),
Self::Top => class!(
"-translate-y-full in-[[open]]:translate-y-0",
"starting:in-[[open]]:-translate-y-full",
),
Self::Bottom => class!(
"translate-y-full in-[[open]]:translate-y-0",
"starting:in-[[open]]:translate-y-full",
),
}
}
}
const CONTENT: StaticClass = class!(
"flex flex-col gap-4 overflow-y-auto border-border bg-card p-6",
"text-card-foreground shadow-sm [transition:translate_200ms_ease-out]",
);
#[component]
pub async fn sheet_content(
#[default]
side: SheetSide,
#[default]
mut attrs: Attributes,
#[default]
child: Child<'_>,
) -> Result<impl View> {
Ok(view! {
<div
class=(class!(CONTENT, side.classes(), side.motion(), attrs.remove("class")))
(attrs)
>
(child)
</div>
})
}