use web_sys::EventTarget;
use yew::prelude::*;
use gloo_events::EventListenerOptions;
use gloo_utils::body;
#[derive(Default, Clone, PartialEq, Eq)]
pub enum ModalSize {
ExtraLarge,
Large,
#[default]
Normal,
Small,
}
pub struct Modal {
#[allow(dead_code)]
on_hide: OnHide,
}
pub struct ModalHeader { }
pub struct ModalBody { }
pub struct ModalFooter { }
#[derive(Properties, Clone, PartialEq)]
pub struct ModalFooterProps {
#[prop_or_default]
pub children: Children
}
impl Component for ModalFooter {
type Message = ();
type Properties = ModalFooterProps;
fn create(_ctx: &Context<Self>) -> Self {
Self {}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let props = ctx.props();
html! {
<div class="modal-footer">
{ for props.children.iter() }
</div>
}
}
}
#[derive(Properties, Clone, PartialEq)]
pub struct ModalHeaderProps {
#[prop_or_default]
pub title: String,
#[prop_or_default]
pub id: String,
}
impl Component for ModalHeader {
type Message = ();
type Properties = ModalHeaderProps;
fn create(_ctx: &Context<Self>) -> Self {
Self {}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let props = ctx.props();
html! {
<div class="modal-header">
<h5 class="modal-title" id={format!("#{}", props.id.clone())}>{props.title.clone()}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
}
}
}
#[derive(Properties, Clone, PartialEq)]
pub struct ModalBodyProps {
#[prop_or_default]
pub children: Children
}
impl Component for ModalBody {
type Message = ();
type Properties = ModalBodyProps;
fn create(_ctx: &Context<Self>) -> Self {
Self {}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let props = ctx.props();
html! {
<div class="modal-body">
{ for props.children.iter() }
</div>
}
}
}
pub struct OnHide {
#[allow(dead_code)]
listener: Option<gloo_events::EventListener>,
}
impl OnHide {
pub fn new(target: &EventTarget, callback: Option<Callback<Event>>) -> Self {
let Some(callback) = callback else {
return Self { listener: None };
};
let listener = {
let option = EventListenerOptions::enable_prevent_default();
Some(gloo_events::EventListener::new_with_options(target, "hide.bs.modal", option, move |_event| {
callback.emit(_event.clone());
}))
};
Self { listener }
}
}
#[derive(Properties, Clone, PartialEq)]
pub struct ModalProps {
#[prop_or_default]
pub title: String,
#[prop_or_default]
pub id: String,
#[prop_or_default]
pub children: Children,
#[prop_or_default]
pub size: ModalSize,
#[prop_or_default]
pub on_hide: Option<Callback<Event>>,
}
impl Component for Modal {
type Message = ();
type Properties = ModalProps;
fn create(_ctx: &Context<Self>) -> Self {
let body = body();
Self { on_hide: OnHide::new(
&body,
_ctx.props().on_hide.clone(),
)}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let props = ctx.props();
let mut dialog_classes = Classes::new();
dialog_classes.push("modal-dialog");
match props.size {
ModalSize::ExtraLarge => dialog_classes.push("modal-xl"),
ModalSize::Large => dialog_classes.push("modal-lg"),
ModalSize::Small => dialog_classes.push("modal-sm"),
_ => (),
}
html! {
<div class="modal" tabindex="-1" id={props.id.clone()}>
<div class={dialog_classes}>
<div class="modal-content">
{ for props.children.iter() }
</div>
</div>
</div>
}
}
}