thaw/src/button/mod.rs

266 lines
9.5 KiB
Rust
Raw Normal View History

mod button_group;
2023-03-31 13:02:44 +08:00
mod theme;
2023-10-07 21:41:03 +08:00
#[cfg(not(feature = "ssr"))]
use crate::utils::dyn_classes;
2023-11-02 10:16:31 +08:00
use crate::{
components::{OptionComp, Wave, WaveRef},
2023-11-02 10:16:31 +08:00
icon::*,
theme::*,
utils::{mount_style, ssr_class, ComponentRef},
2023-11-02 10:16:31 +08:00
};
pub use button_group::ButtonGroup;
2023-03-28 12:37:24 +08:00
use leptos::*;
2023-03-31 13:02:44 +08:00
pub use theme::ButtonTheme;
2023-04-12 17:48:11 +08:00
#[derive(Default, PartialEq, Clone, Copy)]
2023-10-08 14:01:24 +08:00
pub enum ButtonVariant {
2023-03-31 13:02:44 +08:00
#[default]
2023-10-16 21:15:43 +08:00
Primary,
Solid,
Text,
Link,
2023-03-31 13:02:44 +08:00
}
2023-04-04 15:55:14 +08:00
#[derive(Default, Clone)]
2023-03-31 13:02:44 +08:00
pub enum ButtonColor {
#[default]
2023-10-16 21:15:43 +08:00
Primary,
Success,
Warning,
Error,
2023-03-31 13:02:44 +08:00
}
2023-03-28 12:37:24 +08:00
2023-04-04 15:55:14 +08:00
impl ButtonColor {
fn theme_color(&self, theme: &Theme) -> String {
2023-04-04 15:55:14 +08:00
match self {
2023-10-16 21:15:43 +08:00
ButtonColor::Primary => theme.common.color_primary.clone(),
ButtonColor::Success => theme.common.color_success.clone(),
ButtonColor::Warning => theme.common.color_warning.clone(),
ButtonColor::Error => theme.common.color_error.clone(),
2023-04-04 15:55:14 +08:00
}
}
fn theme_color_hover(&self, theme: &Theme) -> String {
2023-09-17 23:10:33 +08:00
match self {
2023-10-16 21:15:43 +08:00
ButtonColor::Primary => theme.common.color_primary_hover.clone(),
ButtonColor::Success => theme.common.color_success_hover.clone(),
ButtonColor::Warning => theme.common.color_warning_hover.clone(),
ButtonColor::Error => theme.common.color_error_hover.clone(),
2023-09-17 23:10:33 +08:00
}
}
2023-10-04 22:25:12 +08:00
fn theme_color_active(&self, theme: &Theme) -> String {
2023-10-04 22:25:12 +08:00
match self {
2023-10-16 21:15:43 +08:00
ButtonColor::Primary => theme.common.color_primary_active.clone(),
ButtonColor::Success => theme.common.color_success_active.clone(),
ButtonColor::Warning => theme.common.color_warning_active.clone(),
ButtonColor::Error => theme.common.color_error_active.clone(),
2023-10-04 22:25:12 +08:00
}
}
2023-04-04 15:55:14 +08:00
}
2023-12-10 13:54:10 +08:00
#[derive(Default, Clone)]
pub enum ButtonSize {
Tiny,
Small,
#[default]
Medium,
Large,
}
impl ButtonSize {
fn theme_font_size(&self, theme: &Theme) -> String {
match self {
ButtonSize::Tiny => theme.common.font_size_tiny.clone(),
ButtonSize::Small => theme.common.font_size_small.clone(),
ButtonSize::Medium => theme.common.font_size_medium.clone(),
ButtonSize::Large => theme.common.font_size_large.clone(),
}
}
fn theme_height(&self, theme: &Theme) -> String {
match self {
ButtonSize::Tiny => theme.common.height_tiny.clone(),
ButtonSize::Small => theme.common.height_small.clone(),
ButtonSize::Medium => theme.common.height_medium.clone(),
ButtonSize::Large => theme.common.height_large.clone(),
}
}
fn theme_padding(&self, theme: &Theme) -> String {
match self {
ButtonSize::Tiny => theme.button.padding_tiny.clone(),
ButtonSize::Small => theme.button.padding_small.clone(),
ButtonSize::Medium => theme.button.padding_medium.clone(),
ButtonSize::Large => theme.button.padding_large.clone(),
}
}
}
2023-03-28 12:37:24 +08:00
#[component]
2023-03-31 13:02:44 +08:00
pub fn Button(
2023-06-07 23:42:04 +08:00
#[prop(optional, into)] style: MaybeSignal<String>,
#[prop(optional, into)] class: MaybeSignal<String>,
2023-10-08 14:01:24 +08:00
#[prop(optional, into)] variant: MaybeSignal<ButtonVariant>,
2023-03-31 13:02:44 +08:00
#[prop(optional, into)] color: MaybeSignal<ButtonColor>,
2023-12-10 13:54:10 +08:00
#[prop(optional, into)] size: MaybeSignal<ButtonSize>,
2023-05-08 23:53:54 +08:00
#[prop(optional, into)] round: MaybeSignal<bool>,
2023-12-11 16:33:50 +08:00
#[prop(optional, into)] circle: MaybeSignal<bool>,
2023-06-09 22:24:39 +08:00
#[prop(optional, into)] icon: Option<Icon>,
#[prop(optional, into)] loading: MaybeSignal<bool>,
#[prop(optional, into)] disabled: MaybeSignal<bool>,
#[prop(optional, into)] on_click: Option<Callback<ev::MouseEvent>>,
#[prop(optional)] children: Option<Children>,
2023-03-31 13:02:44 +08:00
) -> impl IntoView {
2023-08-29 09:11:22 +08:00
let theme = use_theme(Theme::light);
let css_vars = create_memo(move |_| {
2023-04-12 17:48:11 +08:00
let mut css_vars = String::new();
2023-10-26 18:03:24 +08:00
theme.with(|theme| {
2023-10-26 23:24:16 +08:00
let bg_color = color.get().theme_color(theme);
css_vars.push_str(&format!(
"--thaw-font-color-disabled: {};",
theme.button.color_text_disabled
));
2023-12-10 13:54:10 +08:00
css_vars.push_str(&format!(
"--thaw-font-size: {};",
size.get().theme_font_size(theme)
));
css_vars.push_str(&format!(
"--thaw-height: {};",
size.get().theme_height(theme)
));
css_vars.push_str(&format!(
"--thaw-padding: {};",
size.get().theme_padding(theme)
));
match variant.get() {
ButtonVariant::Primary => {
let bg_color_hover = color.get().theme_color_hover(theme);
let bg_color_active = color.get().theme_color_active(theme);
css_vars.push_str(&format!("--thaw-background-color: {bg_color};"));
css_vars.push_str(&format!("--thaw-background-color-hover: {bg_color_hover};"));
css_vars.push_str(&format!(
"--thaw-background-color-active: {bg_color_active};"
));
css_vars.push_str("--thaw-font-color: #fff;");
css_vars.push_str(&format!("--thaw-border-color: {bg_color};"));
css_vars.push_str(&format!("--thaw-border-color-hover: {bg_color};"));
css_vars.push_str(&format!("--thaw-ripple-color: {bg_color};"));
css_vars.push_str(&format!(
"--thaw-background-color-disabled: {};",
theme.button.color_background_disabled
));
css_vars.push_str(&format!(
"--thaw-border-color-disabled: {};",
theme.button.color_border_disabled
));
}
ButtonVariant::Solid => {
css_vars.push_str(&format!("--thaw-font-color-hover: {bg_color};"));
css_vars.push_str(&format!(
"--thaw-border-color: {};",
theme.button.border_color_solid
));
css_vars.push_str(&format!("--thaw-border-color-hover: {bg_color};"));
css_vars.push_str(&format!("--thaw-ripple-color: {bg_color};"));
css_vars.push_str(&format!(
"--thaw-border-color-disabled: {};",
theme.button.color_border_disabled
));
}
ButtonVariant::Text => {
css_vars.push_str(&format!("--thaw-font-color-hover: {bg_color};"));
css_vars.push_str(&format!(
"--thaw-background-color-hover: {};",
theme.button.color_text_hover
));
css_vars.push_str(&format!(
"--thaw-background-color-active: {};",
theme.button.color_text_active
));
css_vars.push_str("--thaw-ripple-color: #0000;");
}
ButtonVariant::Link => {
css_vars.push_str(&format!("--thaw-font-color-hover: {bg_color};"));
css_vars.push_str("--thaw-ripple-color: #0000;");
}
2023-10-26 18:03:24 +08:00
}
});
2023-04-12 12:47:31 +08:00
2023-04-12 17:48:11 +08:00
css_vars
});
2023-10-07 21:41:03 +08:00
mount_style("button", include_str!("./button.css"));
2023-04-04 15:55:14 +08:00
2023-05-15 12:52:03 +08:00
let icon_style = if children.is_some() {
2023-05-08 23:53:54 +08:00
"margin-right: 6px"
} else {
""
};
let disabled = create_memo(move |_| {
if loading.get() {
return true;
}
disabled.get()
});
2023-11-02 10:16:31 +08:00
let wave_ref = ComponentRef::<WaveRef>::default();
let on_click = move |event| {
if disabled.get() {
return;
}
2023-11-02 10:16:31 +08:00
if let Some(wave_ref) = wave_ref.get_untracked() {
wave_ref.play();
}
let Some(callback) = on_click.as_ref() else {
return;
};
callback.call(event);
};
let ssr_class = ssr_class(&class);
2023-10-07 21:41:03 +08:00
view! {
2023-04-12 12:47:31 +08:00
<button
class=ssr_class
use:dyn_classes=class
2023-11-05 16:03:58 +08:00
class:thaw-button=true
class=("thaw-button--solid", move || variant.get() == ButtonVariant::Solid)
2023-11-05 16:03:58 +08:00
class=("thaw-button--text", move || variant.get() == ButtonVariant::Text)
class=("thaw-button--link", move || variant.get() == ButtonVariant::Link)
class=("thaw-button--round", move || round.get())
2023-12-11 16:33:50 +08:00
class=("thaw-button--circle", move || circle.get())
2023-11-05 16:03:58 +08:00
class=("thaw-button--disabled", move || disabled.get())
2023-06-07 23:42:04 +08:00
style=move || format!("{}{}", css_vars.get(), style.get())
disabled=move || disabled.get()
on:click=on_click
2023-10-08 09:28:13 +08:00
>
2023-11-02 10:16:31 +08:00
<Wave comp_ref=wave_ref/>
2023-10-08 09:28:13 +08:00
{move || {
if loading.get() {
view! {
<Icon
icon=Icon::from(AiIcon::AiLoadingOutlined)
style=format!(
2023-11-05 16:03:58 +08:00
"animation: thawLoadingCircle 1s infinite linear;{icon_style}",
2023-10-08 09:28:13 +08:00
)
/>
}
2023-10-08 09:28:13 +08:00
.into()
} else if let Some(icon) = icon {
view! { <Icon icon=icon style=icon_style/> }.into()
} else {
None
}
2023-10-08 09:28:13 +08:00
}}
<OptionComp value=children let:children>
{children()}
</OptionComp>
2023-03-28 12:37:24 +08:00
</button>
}
}