orbital-base-components 0.1.1

Headless base primitives for Orbital — structure, semantics, and accessibility
Documentation
use leptos::prelude::*;
use orbital_motion::{resolve_presence_motion, MotionSlot, OrbitalPresence, PresenceMotion};

use crate::overlay::{
    backdrop::BaseBackdrop, focus_trap::FocusTrap, open_bind::OpenBind, themed_portal::ThemedPortal,
};
use crate::Handler;

#[derive(Clone, Copy, Default)]
pub struct DialogDismiss {
    pub mask_closeable: bool,
    pub close_on_esc: bool,
}

#[derive(Clone, Copy)]
pub struct DialogInjection {
    pub open: OpenBind,
}

impl DialogInjection {
    pub fn expect_context() -> Self {
        expect_context::<Self>()
    }
}

#[component]
pub fn BaseDialog(
    open: OpenBind,
    #[prop(default = DialogDismiss {
        mask_closeable: true,
        close_on_esc: true,
    })]
    dismiss: DialogDismiss,
    #[prop(optional, into)] class: MaybeProp<String>,
    #[prop(optional)] motion: MotionSlot,
    children: Children,
) -> impl IntoView {
    let on_mask_click = move |_| {
        if dismiss.mask_closeable {
            open.set(false);
        }
    };
    let on_esc = Handler::with(move |_: leptos::ev::KeyboardEvent| {
        if dismiss.close_on_esc {
            open.set(false);
        }
    });
    let open_signal = open.signal();
    let motion = resolve_presence_motion(motion, PresenceMotion::fade());

    provide_context(DialogInjection { open });

    view! {
        <ThemedPortal immediate=open_signal class=class>
            <FocusTrap disabled=!dismiss.close_on_esc active=open_signal on_esc>
                <div
                    class="orbital-dialog"
                    style:display=move || if open.get() { "" } else { "none" }
                >
                    <OrbitalPresence appear=true show=open_signal motion=motion>
                        <BaseBackdrop on_click=Callback::new(on_mask_click) />
                    </OrbitalPresence>
                    {children()}
                </div>
            </FocusTrap>
        </ThemedPortal>
    }
}