Skip to content

Commit

Permalink
feat: Button adds loading prop
Browse files Browse the repository at this point in the history
  • Loading branch information
luoxiaozero committed Nov 19, 2024
1 parent e4e7976 commit 6932667
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 8 deletions.
6 changes: 6 additions & 0 deletions thaw/src/button/button/button.css
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
font-weight: var(--fontWeightRegular);
}

.thaw-button--small.thaw-button--loading,
.thaw-button--small.thaw-button--icon {
padding: 1px var(--spacingHorizontalS);
}
Expand All @@ -124,6 +125,7 @@
font-weight: var(--fontWeightSemibold);
}

.thaw-button--large.thaw-button--loading,
.thaw-button--large.thaw-button--icon {
padding: 7px var(--spacingHorizontalL);
}
Expand Down Expand Up @@ -164,6 +166,10 @@
font-size: 24px;
}

.thaw-button--loading:hover {
cursor: wait;
}

.thaw-button--disabled:hover:active,
.thaw-button--disabled:hover,
.thaw-button--disabled {
Expand Down
37 changes: 30 additions & 7 deletions thaw/src/button/button/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ mod types;

pub use types::*;

use crate::icon::Icon;
use leptos::{either::Either, ev, prelude::*};
use crate::{Icon, Spinner};
use leptos::{
either::{Either, EitherOf3},
ev,
prelude::*,
};
use thaw_utils::{class_list, mount_style, BoxOneCallback};

//TODO loading prop
Expand Down Expand Up @@ -36,6 +40,9 @@ pub fn Button(
/// When set, allows the button to be focusable even when it has been disabled.
#[prop(optional, into)]
disabled_focusable: MaybeSignal<bool>,
/// Whether the button shows the loading status.
#[prop(optional, into)]
loading: MaybeSignal<bool>,
#[prop(optional, into)] on_click: Option<BoxOneCallback<ev::MouseEvent>>,
#[prop(optional)] children: Option<Children>,
) -> impl IntoView {
Expand All @@ -44,11 +51,21 @@ pub fn Button(
let none_children = children.is_none();
let only_icon = Memo::new(move |_| icon.with(|i| i.is_some()) && none_children);
let btn_disabled = Memo::new(move |_| disabled.get() || disabled_focusable.get());
let aria_disabled = move || {
if loading.get() || disabled_focusable.get() {
return Some("true");
} else {
return None;
}
};

let on_click = move |e| {
if btn_disabled.get_untracked() {
return;
}
if loading.get_untracked() {
return;
}

let Some(on_click) = on_click.as_ref() else {
return;
Expand All @@ -64,22 +81,28 @@ pub fn Button(
("thaw-button--block", move || block.get()),
("thaw-button--only-icon", only_icon),
("thaw-button--icon", move || icon.with(|i| i.is_some())),
("thaw-button--loading", move || loading.get()),
move || format!("thaw-button--{}", size.get().as_str()),
move || format!("thaw-button--{}", appearance.get().as_str()),
move || format!("thaw-button--{}", shape.get().as_str()),
class
]
type=move || button_type.get().map(|t| t.as_str())
disabled=move || disabled.get().then_some("")
aria-disabled=move || disabled_focusable.get().then_some("true")
aria-disabled=aria_disabled
on:click=on_click
>
{move || {
let icon = icon.get();
if let Some(icon) = icon {
Either::Left(view! { <Icon icon=icon class="thaw-button__icon" /> })
if loading.get() {
EitherOf3::A(view! {
<span class="thaw-button__icon">
<Spinner size=MaybeSignal::derive(move || size.get().into())/>
</span>
})
} else if let Some(icon) = icon.get() {
EitherOf3::B(view! { <Icon icon=icon class="thaw-button__icon" /> })
} else {
Either::Right(())
EitherOf3::C(())
}
}}
{if let Some(children) = children {
Expand Down
14 changes: 13 additions & 1 deletion thaw/src/button/button/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::SpinnerSize;

#[derive(Default, PartialEq, Clone, Copy)]
pub enum ButtonAppearance {
/// Gives emphasis to the button in such a way that it indicates a secondary action.
Expand Down Expand Up @@ -40,7 +42,7 @@ impl ButtonShape {
}
}

#[derive(Default, PartialEq, Clone)]
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub enum ButtonSize {
Small,
#[default]
Expand All @@ -58,6 +60,16 @@ impl ButtonSize {
}
}

impl From<ButtonSize> for SpinnerSize {
fn from(value: ButtonSize) -> Self {
match value {
ButtonSize::Small => Self::Tiny,
ButtonSize::Medium => Self::Tiny,
ButtonSize::Large => Self::ExtraSmall,
}
}
}

/// The default behavior of the button.
///
/// [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#type)
Expand Down
33 changes: 33 additions & 0 deletions thaw/src/button/docs/mod.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,38 @@ view! {
}
```

### Loading

```rust demo
let loading = RwSignal::new(false);
let on_click = move |_| {
loading.set(true);
set_timeout(
move || {
loading.set(false);
},
std::time::Duration::from_secs(5),
);
};

view! {
<Space>
<Button loading on_click icon=icondata::AiCloseOutlined>
"Start loading"
</Button>
<Button loading on_click>
"Start loading"
</Button>
<Button loading on_click size=ButtonSize::Small>
"Start loading"
</Button>
<Button loading on_click size=ButtonSize::Large>
"Start loading"
</Button>
</Space>
}
```

### Block

```rust demo
Expand Down Expand Up @@ -173,6 +205,7 @@ view! {
| icon | `MaybeProp<icondata_core::Icon>` | `None` | The icon of the button. |
| disabled | `MaybeSignal<bool>` | `false` | Whether the button is disabled. |
| disabled_focusable | `MaybeSignal<bool>` | `false` | When set, allows the button to be focusable even when it has been disabled. |
| loading | `MaybeSignal<bool>` | `false` | Whether the button shows the loading status. |
| on_click | `Option<BoxOneCallback<ev::MouseEvent>>` | `None` | Listen for button click events. |
| children | `Option<Children>` | | |

Expand Down

0 comments on commit 6932667

Please sign in to comment.