feat: adds ListboxInjection

This commit is contained in:
luoxiao 2024-07-23 18:00:55 +08:00
parent 87a4ef115c
commit 7da18dc9e5
3 changed files with 51 additions and 22 deletions

View file

@ -1,19 +1,23 @@
use super::AutoCompleteInjection; use super::AutoCompleteInjection;
use crate::combobox::listbox::ListboxInjection;
use leptos::prelude::*; use leptos::prelude::*;
#[component] #[component]
pub fn AutoCompleteOption(value: String, children: Children) -> impl IntoView { pub fn AutoCompleteOption(value: String, children: Children) -> impl IntoView {
let auto_complete = AutoCompleteInjection::expect_context(); let auto_complete = AutoCompleteInjection::expect_context();
let listbox = ListboxInjection::expect_context();
let is_selected = Memo::new({ let is_selected = Memo::new({
let value = value.clone(); let value = value.clone();
move |_| auto_complete.is_selected(&value) move |_| auto_complete.is_selected(&value)
}); });
let id = uuid::Uuid::new_v4().to_string(); let id = uuid::Uuid::new_v4().to_string();
auto_complete.insert_option(id.clone(), value.clone());
{ {
auto_complete.insert_option(id.clone(), value.clone());
let id = id.clone(); let id = id.clone();
listbox.trigger();
on_cleanup(move || { on_cleanup(move || {
auto_complete.remove_option(&id); auto_complete.remove_option(&id);
listbox.trigger();
}); });
} }

View file

@ -1,3 +1,4 @@
use super::listbox::ListboxInjection;
use crate::ComboboxInjection; use crate::ComboboxInjection;
use leptos::prelude::*; use leptos::prelude::*;
use thaw_components::{Fallback, If, OptionComp, Then}; use thaw_components::{Fallback, If, OptionComp, Then};
@ -10,6 +11,7 @@ pub fn ComboboxOption(
#[prop(optional)] children: Option<Children>, #[prop(optional)] children: Option<Children>,
) -> impl IntoView { ) -> impl IntoView {
let combobox = ComboboxInjection::expect_context(); let combobox = ComboboxInjection::expect_context();
let listbox = ListboxInjection::expect_context();
let value = StoredValue::new(value.unwrap_or_else(|| text.clone())); let value = StoredValue::new(value.unwrap_or_else(|| text.clone()));
let text = StoredValue::new(text); let text = StoredValue::new(text);
let is_selected = Memo::new(move |_| value.with_value(|value| combobox.is_selected(&value))); let is_selected = Memo::new(move |_| value.with_value(|value| combobox.is_selected(&value)));
@ -26,8 +28,10 @@ pub fn ComboboxOption(
{ {
combobox.insert_option(id.clone(), (value.get_value(), text.get_value())); combobox.insert_option(id.clone(), (value.get_value(), text.get_value()));
let id = id.clone(); let id = id.clone();
listbox.trigger();
on_cleanup(move || { on_cleanup(move || {
combobox.remove_option(&id); combobox.remove_option(&id);
listbox.trigger();
}); });
} }

View file

@ -1,8 +1,7 @@
use std::sync::Arc;
use super::utils::{get_dropdown_action_from_key, DropdownAction}; use super::utils::{get_dropdown_action_from_key, DropdownAction};
use crate::{ConfigInjection, _aria::ActiveDescendantController}; use crate::{ConfigInjection, _aria::ActiveDescendantController};
use leptos::{ev, html, prelude::*}; use leptos::{context::Provider, ev, html, prelude::*};
use std::sync::Arc;
use thaw_components::CSSTransition; use thaw_components::CSSTransition;
use thaw_utils::mount_style; use thaw_utils::mount_style;
use web_sys::{HtmlElement, Node}; use web_sys::{HtmlElement, Node};
@ -18,9 +17,14 @@ pub fn Listbox(
mount_style("listbox", include_str!("./listbox.css")); mount_style("listbox", include_str!("./listbox.css"));
let config_provider = ConfigInjection::expect_context(); let config_provider = ConfigInjection::expect_context();
let effect = RenderEffect::new(move |_| { let trigger = ArcTrigger::new();
if let Some(listbox_el) = listbox_ref.get() { let effect = RenderEffect::new({
set_listbox(listbox_el.into()); let trigger = trigger.clone();
move |_| {
trigger.track();
if let Some(listbox_el) = listbox_ref.get() {
set_listbox(listbox_el.into());
}
} }
}); });
on_cleanup(move || { on_cleanup(move || {
@ -28,23 +32,40 @@ pub fn Listbox(
}); });
view! { view! {
<CSSTransition <Provider value=ListboxInjection(trigger)>
node_ref=listbox_ref <CSSTransition
name="fade-in-scale-up-transition"
appear=open.get_untracked()
show=open
let:display
>
<div
class=format!("thaw-config-provider thaw-listbox {class}")
style=move || display.get().unwrap_or_default()
data-thaw-id=config_provider.id().clone()
node_ref=listbox_ref node_ref=listbox_ref
role="listbox" name="fade-in-scale-up-transition"
appear=open.get_untracked()
show=open
let:display
> >
{children()} <div
</div> class=format!("thaw-config-provider thaw-listbox {class}")
</CSSTransition> style=move || display.get().unwrap_or_default()
data-thaw-id=config_provider.id().clone()
node_ref=listbox_ref
role="listbox"
>
{children()}
</div>
</CSSTransition>
</Provider>
}
}
#[derive(Clone)]
pub(crate) struct ListboxInjection(ArcTrigger);
impl ListboxInjection {
#[inline]
pub fn expect_context() -> Self {
expect_context()
}
#[inline]
pub fn trigger(&self) {
self.0.trigger();
} }
} }