From f551a41a5b4ea7bc4b913169a145fe0b61efddb0 Mon Sep 17 00:00:00 2001 From: tommy Date: Wed, 5 Nov 2025 18:40:40 +0800 Subject: [PATCH] Add loading state to Button - Add loading: bool prop to Button - Disable button when loading or disabled - Show spinner and wrap content in a ui-button-content span during loading - Add data-loading and aria-busy attributes for accessibility - Prevent click handlers from firing while loading --- src/components/ui/button.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/ui/button.rs b/src/components/ui/button.rs index e5d6752..50acfd9 100644 --- a/src/components/ui/button.rs +++ b/src/components/ui/button.rs @@ -65,6 +65,7 @@ pub fn Button( #[props(default)] size: ButtonSize, #[props(into, default)] class: Option, #[props(default)] disabled: bool, + #[props(default)] loading: bool, #[props(default = "button".to_string())] #[props(into)] r#type: String, @@ -78,20 +79,36 @@ pub fn Button( } let click_handler = on_click.clone(); + let is_disabled = disabled || loading; rsx! { button { class: classes, - disabled, + disabled: is_disabled, r#type: r#type, "data-variant": variant.as_str(), "data-size": size.as_str(), + "data-loading": if loading { "true" } else { "false" }, + "aria-busy": if loading { "true" } else { "false" }, onclick: move |event| { + if loading { + event.stop_propagation(); + return; + } if let Some(handler) = click_handler.clone() { handler.call(event); } }, - {children} + if loading { + span { + class: "ui-button-spinner", + "aria-hidden": "true", + } + } + span { + class: "ui-button-content", + {children} + } } } }