thaw 0.4.8

An easy to use leptos component library
Documentation
mod date_panel;
mod month_panel;
mod year_panel;

use chrono::NaiveDate;
use date_panel::DatePanel;
use leptos::{html, prelude::*};
use month_panel::MonthPanel;
use thaw_utils::{now_date, ArcOneCallback, ComponentRef};
use year_panel::YearPanel;

#[component]
pub fn Panel(
    selected_date: RwSignal<Option<NaiveDate>>,
    date_picker_ref: NodeRef<html::Div>,
    #[prop(into)] close_panel: ArcOneCallback<Option<NaiveDate>>,
    #[prop(optional)] comp_ref: ComponentRef<PanelRef>,
) -> impl IntoView {
    let panel_ref = NodeRef::<html::Div>::new();
    #[cfg(any(feature = "csr", feature = "hydrate"))]
    {
        use leptos::wasm_bindgen::__rt::IntoJsResult;
        let close_panel = close_panel.clone();
        let handle = window_event_listener(leptos::ev::click, move |ev| {
            let el = ev.target();
            let mut el: Option<web_sys::Element> =
                el.into_js_result().map_or(None, |el| Some(el.into()));
            let body = document().body().unwrap();
            loop {
                let Some(current_el) = el else {
                    return;
                };
                if current_el == *body {
                    break;
                };
                if panel_ref.get().is_none() {
                    return;
                }
                let panel_el = panel_ref.get_untracked().unwrap();
                let date_picker_el = date_picker_ref.get_untracked().unwrap();
                if current_el == **panel_el || current_el == **date_picker_el {
                    return;
                }
                el = current_el.parent_element();
            }
            close_panel(None);
        });
        on_cleanup(move || handle.remove());
    }
    #[cfg(not(any(feature = "csr", feature = "hydrate")))]
    {
        _ = date_picker_ref;
        _ = panel_ref;
    }
    let panel_variant = RwSignal::new(PanelVariant::Date);
    let show_date = RwSignal::new(selected_date.get_untracked().unwrap_or(now_date()));
    comp_ref.load(PanelRef {
        show_date,
        variant: panel_variant,
    });

    view! {
        <div class="thaw-date-picker-panel" node_ref=panel_ref on:mousedown=|e| e.prevent_default()>

            {move || {
                match panel_variant.get() {
                    PanelVariant::Date => {
                        let close_panel = close_panel.clone();
                        view! {
                            <DatePanel value=selected_date show_date close_panel panel_variant />
                        }
                            .into_any()
                    }
                    PanelVariant::Month => {
                        view! { <MonthPanel date_panel_show_date=show_date panel_variant /> }
                            .into_any()
                    }
                    PanelVariant::Year => {
                        view! { <YearPanel date_panel_show_date=show_date panel_variant /> }
                            .into_any()
                    }
                }
            }}
        </div>
    }
}

#[derive(Clone)]
pub struct PanelRef {
    show_date: RwSignal<NaiveDate>,
    variant: RwSignal<PanelVariant>,
}

impl PanelRef {
    pub fn init_panel(&self, show_date: NaiveDate) {
        self.show_date.set(show_date);
        self.variant.set(PanelVariant::Date);
    }
}

#[derive(Default, Clone)]
pub enum PanelVariant {
    #[default]
    Date,
    Month,
    Year,
}