use icons::X; use leptos::context::Provider; use leptos::prelude::*; use leptos_ui::clx; use tw_merge::*; use super::button::ButtonSize; use crate::components::hooks::use_random::use_random_id_for; use crate::components::ui::button::{Button, ButtonVariant}; mod components { use super::*; clx! {SheetTitle, h2, "font-bold text-2xl"} clx! {SheetDescription, p, "text-muted-foreground"} clx! {SheetBody, div, "flex flex-col gap-4"} clx! {SheetFooter, footer, "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"} } pub use components::*; /* ========================================================== */ /* ✨ CONTEXT ✨ */ /* ========================================================== */ #[derive(Clone)] pub struct SheetContext { pub target_id: String, } /* ========================================================== */ /* ✨ FUNCTIONS ✨ */ /* ========================================================== */ pub type SheetVariant = ButtonVariant; pub type SheetSize = ButtonSize; #[component] pub fn Sheet(children: Children, #[prop(optional, into)] class: String) -> impl IntoView { let sheet_target_id = use_random_id_for("sheet"); let ctx = SheetContext { target_id: sheet_target_id }; let merged_class = tw_merge!("", class); view! {
{children()}
} } #[component] pub fn SheetTrigger( children: Children, #[prop(optional, into)] class: String, #[prop(default = ButtonVariant::Outline)] variant: ButtonVariant, #[prop(default = ButtonSize::Default)] size: ButtonSize, ) -> impl IntoView { let ctx = expect_context::(); let trigger_id = format!("trigger_{}", ctx.target_id); view! { } } #[component] pub fn SheetClose( children: Children, #[prop(optional, into)] class: String, #[prop(default = ButtonVariant::Outline)] variant: ButtonVariant, #[prop(default = ButtonSize::Default)] size: ButtonSize, ) -> impl IntoView { let ctx = expect_context::(); view! { } } #[component] pub fn SheetContent( children: Children, #[prop(optional, into)] class: String, #[prop(default = SheetDirection::Right)] direction: SheetDirection, #[prop(into, optional)] hide_close_button: Option, ) -> impl IntoView { let ctx = expect_context::(); let backdrop_id = format!("{}_backdrop", ctx.target_id); let target_id_for_script = ctx.target_id.clone(); let backdrop_id_for_script = backdrop_id.clone(); let merged_class = tw_merge!( "fixed z-100 bg-card shadow-lg p-6 transition-transform duration-300 overflow-y-auto overscroll-y-contain", direction.initial_position(), direction.closed_class(), class ); view! {
{children()}
}.into_any() } /* ========================================================== */ /* ✨ ENUM ✨ */ /* ========================================================== */ #[derive(Clone, Copy, strum::AsRefStr, strum::Display)] pub enum SheetDirection { Right, Left, Top, Bottom, } impl SheetDirection { fn closed_class(self) -> &'static str { match self { SheetDirection::Right => "translate-x-full", SheetDirection::Left => "-translate-x-full", SheetDirection::Top => "-translate-y-full", SheetDirection::Bottom => "translate-y-full", } } fn initial_position(self) -> &'static str { match self { SheetDirection::Right => "top-0 right-0 h-full w-[400px]", SheetDirection::Left => "top-0 left-0 h-full w-[400px]", SheetDirection::Top => "top-0 left-0 w-full h-[400px]", SheetDirection::Bottom => "bottom-0 left-0 w-full h-[400px]", } } }