use crate::core::px;
use crate::view::interactivity::ClickHandler;
use crate::view::prelude::*;
use std::rc::Rc;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ButtonVariant {
Primary,
Ghost,
Subtle,
Danger,
}
pub struct Button {
label: String,
variant: ButtonVariant,
style: Style,
id: Option<String>,
on_click: Option<ClickHandler>,
}
impl Button {
pub fn new(label: impl Into<String>) -> Self {
Self { label: label.into(), variant: ButtonVariant::Primary, style: Style::default(), id: None, on_click: None }
}
pub fn variant(mut self, variant: ButtonVariant) -> Self {
self.variant = variant;
self
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut EventContext) + 'static) -> Self {
self.on_click = Some(Rc::new(handler));
self
}
fn palette(&self) -> (Option<Token>, Token, Token, Token) {
match self.variant {
ButtonVariant::Primary => (Some(Token::Accent), Token::AccentText, Token::AccentHover, Token::Accent),
ButtonVariant::Danger => (Some(Token::Danger), Token::DangerText, Token::DangerHover, Token::Danger),
ButtonVariant::Subtle => (Some(Token::ElevatedSurface), Token::Text, Token::Hover, Token::Active),
ButtonVariant::Ghost => (None, Token::Text, Token::Hover, Token::Active),
}
}
}
impl Styled for Button {
fn style(&mut self) -> &mut Style {
&mut self.style
}
}
impl IntoElement for Button {
fn into_element(self) -> AnyElement {
let (background, foreground, hover, active) = self.palette();
let is_subtle = self.variant == ButtonVariant::Subtle;
let handler = self.on_click.clone();
div()
.role(Role::Button)
.label(self.label.clone())
.flex_row()
.items_center()
.justify_center()
.h(px(32.0))
.px_3()
.rounded_md()
.text_sm()
.text_color(foreground)
.when_some(background, |button, color| button.bg(color))
.when(is_subtle, |button| button.border_1().border_color(Token::BorderSubtle))
.hover(|style| style.bg(hover))
.active(|style| style.bg(active))
.when_some(self.id, |button, id| button.id(id))
.when_some(handler, |button, handler| button.cursor_pointer().on_click(move |event, cx| handler(event, cx)))
.refine_style(&self.style)
.child(self.label)
.into_element()
}
}