yew-full-calendar 0.1.1

Yew component for fullcalendar
Documentation
use web_sys::HtmlElement;
use yew::prelude::*;

use wasm_bindgen::JsCast;

#[derive(Properties, PartialEq)]
pub struct Props {
    pub calendar_id: AttrValue,
    #[prop_or_default]
    pub calendar_options: crate::options::Options,
    // pub events: UseStateHandle<Vec<FullCalendarEvent<T>>>,
    #[prop_or_default]
    pub on_event_click: Option<Callback<crate::bindings::EventClickInfo>>,
    #[prop_or_default]
    pub on_date_select: Option<Callback<crate::bindings::SelectionInfo>>,
    #[prop_or_default]
    pub on_calendar_created: Option<Callback<crate::bindings::Calendar>>,
    #[prop_or_default]
    pub on_dates_set: Option<Callback<crate::bindings::DateSetEvent>>,
    #[prop_or_default]
    pub class: Classes,
}

#[function_component(FullCalendarComponent)]
pub fn calendar_component(props: &Props) -> Html {
    let calendar_ref = use_node_ref();
    let calendar_state = use_mut_ref(|| None::<crate::bindings::Calendar>);

    // Initialize calendar
    {
        let calendar_ref = calendar_ref.clone();
        // let events = props.events.clone();
        let on_calendar_created = props.on_calendar_created.clone();
        let on_event_click = props.on_event_click.clone();
        let on_date_select = props.on_date_select.clone();
        let on_view_changed = props.on_dates_set.clone();
        let options = props.calendar_options.clone();

        use_effect_with((), move |()| {
            let calendar_created = on_calendar_created.clone();
            let event_click = on_event_click.clone();
            let date_select = on_date_select.clone();
            let view_changed = on_view_changed.clone();
            let Some(el) = calendar_ref.cast::<HtmlElement>() else {
                return;
            };

            let el_clone = el.clone();
            let calendar_instance = calendar_state.clone();
            let initialize = move |_: web_sys::wasm_bindgen::JsValue| {
                if let Some(cal) = calendar_instance.borrow().as_ref() {
                    cal.update_size();
                    return;
                }
                let options = {
                    let mut opt = options.clone();

                    // Add event click handler if callback provided
                    if let Some(event_cb) = event_click.clone() {
                        opt = opt.with_event_click(
                            move |event_value: crate::bindings::EventClickInfo| {
                                event_cb.emit(event_value);
                            },
                        );
                    }

                    // // Add date selection handler if callback provided
                    if let Some(select_cb) = date_select.clone() {
                        opt =
                            opt.with_select(move |select_info: crate::bindings::SelectionInfo| {
                                select_cb.emit(select_info);
                            });
                    }

                    // Add view change handler if callback provided
                    if let Some(view_cb) = view_changed.clone() {
                        opt = opt.with_date_set(move |date_set: crate::bindings::DateSetEvent| {
                            view_cb.emit(date_set);
                        });
                    }
                    opt
                };
                let Ok(options) = options.build() else {
                    return;
                };

                let cal = crate::bindings::Calendar::new(&el_clone, options);
                cal.render();
                calendar_instance.borrow_mut().replace(cal.clone());
                if let Some(cb) = calendar_created.clone() {
                    cb.emit(cal);
                }
            };
            let Ok(observer) =
                web_sys::ResizeObserver::new(
                    &web_sys::wasm_bindgen::closure::Closure::<
                        dyn FnMut(web_sys::wasm_bindgen::JsValue),
                    >::new(initialize)
                    .into_js_value()
                    .unchecked_into(),
                )
            else {
                return;
            };
            observer.observe(&el);
        });
    }

    html! {
            <div
                class={props.class.clone()}
                ref={calendar_ref}
            />
    }
}