This commit is contained in:
tommy
2025-11-07 15:09:10 +08:00
parent 0ae1ef29d5
commit dddab92102

View File

@@ -26,9 +26,7 @@ pub fn Select(
#[props(optional)] on_change: Option<EventHandler<String>>, #[props(optional)] on_change: Option<EventHandler<String>>,
) -> Element { ) -> Element {
let mut open = use_signal(|| false); let mut open = use_signal(|| false);
let current = use_signal(move || selected.clone()); let mut current = use_signal(move || selected.clone());
let on_change_handler = on_change.clone();
let trigger_id = id.unwrap_or_default();
let mut container_ref = use_signal(|| None as Option<Rc<MountedData>>); let mut container_ref = use_signal(|| None as Option<Rc<MountedData>>);
use_effect(move || { use_effect(move || {
@@ -60,28 +58,54 @@ pub fn Select(
onmounted: move |event| { onmounted: move |event| {
container_ref.set(Some(event.data())); container_ref.set(Some(event.data()));
}, },
onblur: { onblur: move |_| {
let mut open_signal = open.clone(); open.set(false);
move |_| {
open_signal.set(false);
}
}, },
SelectTrigger {
id: id.clone(),
open: open(),
disabled,
display_text,
on_toggle: move |_| {
if !disabled {
open.set(!open());
}
}
}
if open() {
SelectContent {
options: options.clone(),
selected_value,
on_select: move |value: String| {
current.set(Some(value.clone()));
if let Some(callback) = on_change.as_ref() {
callback.call(value);
}
open.set(false);
}
}
}
}
}
}
#[component]
fn SelectTrigger(
#[props(into, default)] id: Option<String>,
open: bool,
disabled: bool,
#[props(into)] display_text: String,
on_toggle: EventHandler<()>,
) -> Element {
rsx! {
button { button {
class: "ui-select-trigger", class: "ui-select-trigger",
"data-open": if open() { "true" } else { "false" }, "data-open": if open { "true" } else { "false" },
disabled, disabled,
id: trigger_id.clone(), id: id.unwrap_or_default(),
"aria-haspopup": "listbox", "aria-haspopup": "listbox",
"aria-expanded": if open() { "true" } else { "false" }, "aria-expanded": if open { "true" } else { "false" },
onclick: { onclick: move |_| on_toggle.call(()),
let mut open_signal = open.clone();
move |_| {
if !disabled {
let new_state = !open_signal();
open_signal.set(new_state);
}
}
},
span { "{display_text}" } span { "{display_text}" }
span { span {
class: "ui-select-icon", class: "ui-select-icon",
@@ -100,37 +124,48 @@ pub fn Select(
} }
} }
} }
if open() { }
}
#[component]
fn SelectContent(
options: Vec<SelectOption>,
selected_value: Option<String>,
on_select: EventHandler<String>,
) -> Element {
rsx! {
div { div {
class: "ui-select-content", class: "ui-select-content",
div { div {
class: "ui-select-list", class: "ui-select-list",
for option in options.iter().cloned() { for option in options {
{ {
let is_active = selected_value let is_active = selected_value.as_ref().map(|v| v == &option.value).unwrap_or(false);
.as_ref() rsx! {
.map(|value| value == &option.value) SelectItem {
.unwrap_or(false); option,
is_active,
on_select
}
}
}
}
}
}
}
}
#[component]
fn SelectItem(option: SelectOption, is_active: bool, on_select: EventHandler<String>) -> Element {
let value = option.value.clone(); let value = option.value.clone();
let handler = on_change_handler.clone();
let mut open_signal = open.clone();
let mut current_signal = current.clone();
rsx! { rsx! {
button { button {
class: "ui-select-item", class: "ui-select-item",
"data-state": if is_active { "active" } else { "inactive" }, "data-state": if is_active { "active" } else { "inactive" },
onmousedown: { onmousedown: move |event| {
let value = value.clone();
let handler = handler.clone();
move |event| {
event.prevent_default(); event.prevent_default();
current_signal.set(Some(value.clone())); on_select.call(value.clone());
if let Some(callback) = handler.clone() {
callback.call(value.clone());
}
open_signal.set(false);
}
}, },
span { "{option.label}" } span { "{option.label}" }
if is_active { if is_active {
@@ -141,11 +176,4 @@ pub fn Select(
} }
} }
} }
}
}
}
}
}
}
}
} }