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