use crate::{id::Id, prelude::*};
use derive_rich::Rich;
use savory::prelude::*;
use savory_style::prelude::*;
use std::borrow::Cow;
pub enum Msg {
DesignSystem(DesignSystem),
Focus(bool),
MouseOver(bool),
Disable(bool),
}
#[derive(Rich, Element)]
pub struct Button {
#[rich(read)]
#[element(config)]
id: Option<Id>,
design_system: DesignSystem,
#[rich(read)]
#[element(config)]
text: Option<Cow<'static, str>>,
#[rich(read)]
#[element(config)]
icon: Option<Svg<Msg>>,
#[rich(read(copy, rename = is_disabled))]
#[element(config(default), data_lens(copy))]
disabled: bool,
#[rich(read(copy, rename = is_focused))]
#[element(data_lens(copy))]
focused: bool,
#[rich(read(copy, rename = is_mouse_over))]
#[element(data_lens(copy))]
mouse_over: bool,
#[rich(read(copy))]
#[element(config, data_lens(copy))]
color: Option<palette::Hsl>,
#[rich(read(copy))]
#[element(config, data_lens(copy))]
text_color: Option<palette::Hsl>,
#[rich(read(copy))]
#[element(config(default = "ActionType::Default"), data_lens(copy))]
action_type: ActionType,
#[rich(read(copy))]
#[element(config(default = "Kind::Default"), data_lens(copy))]
kind: Kind,
#[rich(read(copy, rename = is_ghost))]
#[element(config(default, no_pub), data_lens(copy))]
ghost: bool,
}
#[derive(Debug, Copy, Eq, PartialEq, Clone)]
pub enum ActionType {
Default,
Suggested,
Destructive,
}
#[derive(Debug, Copy, Eq, PartialEq, Clone)]
pub enum Kind {
Default,
Dashed,
TextButton,
LinkButton,
}
impl Element for Button {
type Message = Msg;
type Config = Config;
fn init(config: Self::Config, orders: &mut impl Orders<Msg>) -> Self {
orders.subscribe(|ds: DesignSystemChanged| Msg::DesignSystem(ds.0));
Button {
id: config.id,
design_system: DesignSystem::default(),
text: config.text,
icon: config.icon,
disabled: config.disabled,
focused: false,
mouse_over: false,
color: config.color,
text_color: config.text_color,
action_type: config.action_type,
kind: config.kind,
ghost: config.ghost,
}
}
fn update(&mut self, msg: Msg, _: &mut impl Orders<Msg>) {
match msg {
Msg::DesignSystem(val) => self.design_system = val,
Msg::MouseOver(val) => self.mouse_over = val,
Msg::Focus(val) => self.focused = val,
Msg::Disable(val) => self.disabled = val,
}
}
}
impl View<Node<Msg>> for Button {
fn view(&self) -> Node<Msg> {
let style = self.design_system.button(self.data_lens());
html::button()
.class("button")
.try_id(self.id.clone())
.disabled(self.disabled)
.style(style)
.on_focus(|_| Msg::Focus(true))
.on_blur(|_| Msg::Focus(false))
.on_mouse_over(|_| Msg::MouseOver(true))
.on_mouse_leave(|_| Msg::MouseOver(false))
.try_push(self.icon.as_ref().map(|el| el.view()))
.try_push(self.text.clone())
}
}
impl Config {
pub fn suggestion(mut self) -> Self {
self.action_type = ActionType::Suggested;
self
}
pub fn destructive(mut self) -> Self {
self.action_type = ActionType::Destructive;
self
}
pub fn dashed(mut self) -> Self {
self.kind = Kind::Dashed;
self
}
pub fn text_button(mut self) -> Self {
self.kind = Kind::TextButton;
self
}
pub fn link_button(mut self) -> Self {
self.kind = Kind::LinkButton;
self
}
pub fn ghost(mut self) -> Self {
self.ghost = true;
self
}
}