use derive_more::Display;
use yew::events::{Event, MouseEvent};
use yew::prelude::*;
#[derive(Clone, Debug, Properties, PartialEq)]
pub struct ButtonsProps {
#[prop_or_default]
pub children: Children,
#[prop_or_default]
pub classes: Classes,
#[prop_or_default]
pub size: Option<ButtonGroupSize>,
}
#[function_component(Buttons)]
pub fn buttons(props: &ButtonsProps) -> Html {
let class = classes!("buttons", props.classes.clone(), props.size.as_ref().map(ToString::to_string));
html! {
<div {class}>
{props.children.clone()}
</div>
}
}
#[derive(Clone, Debug, Display, PartialEq, Eq)]
#[display(fmt = "are-{}")]
pub enum ButtonGroupSize {
#[display(fmt = "small")]
Small,
#[display(fmt = "medium")]
Medium,
#[display(fmt = "large")]
Large,
}
#[derive(Clone, Debug, Properties, PartialEq)]
pub struct ButtonProps {
#[prop_or_default]
pub children: Children,
#[prop_or_default]
pub classes: Classes,
#[prop_or_default]
pub onclick: Callback<MouseEvent>,
#[prop_or_default]
pub loading: bool,
#[prop_or_default]
pub r#static: bool,
#[prop_or_default]
pub disabled: bool,
}
#[function_component(Button)]
pub fn button(props: &ButtonProps) -> Html {
let class = classes!(
"button",
props.classes.clone(),
props.loading.then_some("is-loading"),
props.r#static.then_some("is-static")
);
html! {
<button {class} onclick={props.onclick.clone()} disabled={props.disabled}>
{props.children.clone()}
</button>
}
}
#[cfg(feature = "router")]
mod router {
use super::*;
use serde::Serialize;
use yew_router::components::Link;
use yew_router::Routable;
#[derive(Clone, Properties, PartialEq)]
pub struct ButtonRouterProps<R: Routable + Clone + PartialEq + 'static> {
pub route: R,
#[prop_or_default]
pub children: Children,
#[prop_or_default]
pub classes: Classes,
#[prop_or_default]
pub loading: bool,
#[prop_or_default]
pub r#static: bool,
#[prop_or_default]
pub disabled: bool,
}
pub struct ButtonRouter<R: Routable + Clone + PartialEq + 'static, Q: Clone + PartialEq + Serialize + 'static = ()> {
_route: std::marker::PhantomData<R>,
_query: std::marker::PhantomData<Q>,
}
impl<R: Routable + Clone + PartialEq + 'static, Q: Clone + PartialEq + Serialize + 'static> Component for ButtonRouter<R, Q> {
type Message = ();
type Properties = ButtonRouterProps<R>;
fn create(_ctx: &Context<Self>) -> Self {
Self {
_route: std::marker::PhantomData,
_query: std::marker::PhantomData,
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let loading = ctx.props().loading.then_some("is-loading");
let classes = classes!(ctx.props().classes.clone(), "button", loading);
html! {
<Link<R, Q>
to={ctx.props().route.clone()}
disabled={ctx.props().disabled}
{classes}
children={ctx.props().children.clone()}
/>
}
}
}
pub struct ButtonAnchorRouter<R: Routable + Clone + PartialEq + 'static, Q: Clone + PartialEq + Serialize + 'static = ()> {
_route: std::marker::PhantomData<R>,
_query: std::marker::PhantomData<Q>,
}
impl<R: Routable + Clone + PartialEq + 'static, Q: Clone + PartialEq + Serialize + 'static> Component for ButtonAnchorRouter<R, Q> {
type Message = ();
type Properties = ButtonRouterProps<R>;
fn create(_ctx: &Context<Self>) -> Self {
Self {
_route: std::marker::PhantomData,
_query: std::marker::PhantomData,
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let loading = ctx.props().loading.then_some("is-loading");
let classes = classes!(ctx.props().classes.clone(), "button", loading);
html! {
<Link<R, Q>
to={ctx.props().route.clone()}
disabled={ctx.props().disabled}
{classes}
children={ctx.props().children.clone()}
/>
}
}
}
}
#[cfg(feature = "router")]
pub use router::{ButtonAnchorRouter, ButtonRouter, ButtonRouterProps};
#[derive(Clone, Debug, Properties, PartialEq)]
pub struct ButtonAnchorProps {
#[prop_or_default]
pub children: Children,
#[prop_or_default]
pub classes: Classes,
#[prop_or_default]
pub href: String,
#[prop_or_default]
pub onclick: Callback<MouseEvent>,
#[prop_or_default]
pub loading: bool,
#[prop_or_default]
pub r#static: bool,
#[prop_or_default]
pub disabled: bool,
#[prop_or_default]
pub rel: Option<String>,
#[prop_or_default]
pub target: Option<String>,
}
#[function_component(ButtonAnchor)]
pub fn button_anchor(props: &ButtonAnchorProps) -> Html {
let class = classes!(
"button",
props.classes.clone(),
props.loading.then_some("is-loading"),
props.r#static.then_some("is-static")
);
html! {
<a
{class}
onclick={props.onclick.clone()}
href={props.href.clone()}
rel={props.rel.clone().unwrap_or_default()}
target={props.target.clone().unwrap_or_default()}
disabled={props.disabled}
>
{props.children.clone()}
</a>
}
}
#[derive(Clone, Debug, Properties, PartialEq)]
pub struct ButtonInputSubmitProps {
#[prop_or_default]
pub classes: Classes,
#[prop_or_default]
pub onsubmit: Callback<SubmitEvent>,
#[prop_or_default]
pub loading: bool,
#[prop_or_default]
pub r#static: bool,
#[prop_or_default]
pub disabled: bool,
}
#[function_component(ButtonInputSubmit)]
pub fn button_input_submit(props: &ButtonInputSubmitProps) -> Html {
let class = classes!(
"button",
props.classes.clone(),
props.loading.then_some("is-loading"),
props.r#static.then_some("is-static"),
);
html! {
<input type="submit" {class} onsubmit={props.onsubmit.clone()} disabled={props.disabled} />
}
}
#[derive(Clone, Debug, Properties, PartialEq)]
pub struct ButtonInputResetProps {
#[prop_or_default]
pub classes: Classes,
#[prop_or_default]
pub onreset: Callback<Event>,
#[prop_or_default]
pub loading: bool,
#[prop_or_default]
pub r#static: bool,
#[prop_or_default]
pub disabled: bool,
}
#[function_component(ButtonInputReset)]
pub fn button_input_reset(props: &ButtonInputResetProps) -> Html {
let class = classes!(
"button",
props.classes.clone(),
props.loading.then_some("is-loading"),
props.r#static.then_some("is-static"),
);
html! {
<input type="reset" {class} onreset={props.onreset.clone()} disabled={props.disabled} />
}
}