feat: checkbox checked

This commit is contained in:
luoxiao 2024-05-21 17:25:22 +08:00
parent ec351e7ba1
commit be91dcbf6a
5 changed files with 60 additions and 33 deletions

View file

@ -1,10 +1,10 @@
# Checkbox # Checkbox
```rust demo ```rust demo
let value = create_rw_signal(false); let checked = RwSignal::new(false);
view! { view! {
<Checkbox value>"Click"</Checkbox> <Checkbox checked>"Click"</Checkbox>
<Checkbox /> <Checkbox />
} }
``` ```
@ -14,13 +14,13 @@ view! {
```rust demo ```rust demo
use std::collections::HashSet; use std::collections::HashSet;
let value = create_rw_signal(HashSet::new()); let value = RwSignal::new(HashSet::new());
view! { view! {
<CheckboxGroup value> <CheckboxGroup value>
<CheckboxItem label="apple" key="a"/> <CheckboxItem label="apple" value="a"/>
<CheckboxItem label="b" key="b"/> <CheckboxItem label="b" value="b"/>
<CheckboxItem label="c" key="c"/> <CheckboxItem label="c" value="c"/>
</CheckboxGroup> </CheckboxGroup>
<div style="margin-top: 1rem">"value: " {move || format!("{:?}", value.get())}</div> <div style="margin-top: 1rem">"value: " {move || format!("{:?}", value.get())}</div>
} }

View file

@ -106,4 +106,5 @@
font-family: var(--fontFamilyBase); font-family: var(--fontFamilyBase);
font-size: var(--fontSizeBase300); font-size: var(--fontSizeBase300);
color: inherit; color: inherit;
cursor: inherit;
} }

View file

@ -7,12 +7,20 @@ pub fn CheckboxGroup(
#[prop(optional, into)] value: Model<HashSet<String>>, #[prop(optional, into)] value: Model<HashSet<String>>,
children: Children, children: Children,
) -> impl IntoView { ) -> impl IntoView {
view! { <Provider value=CheckboxGroupInjection(value) children/> } view! {
<Provider value=CheckboxGroupInjection(value)>
<div class="thaw-checkbox-group" role="group">
{children()}
</div>
</Provider>
}
} }
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct CheckboxGroupInjection(pub Model<HashSet<String>>); pub(crate) struct CheckboxGroupInjection(pub Model<HashSet<String>>);
pub(crate) fn use_checkbox_group() -> CheckboxGroupInjection { impl CheckboxGroupInjection {
pub fn use_() -> Self {
expect_context() expect_context()
} }
}

View file

@ -1,4 +1,4 @@
use crate::checkbox::{checkbox_group::use_checkbox_group, Checkbox}; use super::{checkbox_group::CheckboxGroupInjection, Checkbox};
use leptos::*; use leptos::*;
use thaw_utils::OptionalProp; use thaw_utils::OptionalProp;
@ -6,39 +6,39 @@ use thaw_utils::OptionalProp;
pub fn CheckboxItem( pub fn CheckboxItem(
#[prop(optional, into)] label: Option<String>, #[prop(optional, into)] label: Option<String>,
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>, #[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
#[prop(into)] key: String, #[prop(into)] value: String,
) -> impl IntoView { ) -> impl IntoView {
let checkbox_group_value = use_checkbox_group().0; let group_value = CheckboxGroupInjection::use_().0;
let checked = RwSignal::new(false); let checked = RwSignal::new(false);
let item_key = StoredValue::new(key); let item_value = StoredValue::new(value);
let is_checked = Memo::new(move |_| { let is_checked = Memo::new(move |_| {
checkbox_group_value.with(|value| item_key.with_value(|key| value.contains(key))) group_value.with(|group_value| item_value.with_value(|value| group_value.contains(value)))
}); });
Effect::new(move |_| { Effect::new(move |_| {
checked.track(); checked.track();
if is_checked.get_untracked() { if is_checked.get_untracked() {
checkbox_group_value.update(move |value| { group_value.update(move |group_value| {
item_key.with_value(|key| { item_value.with_value(|value| {
value.remove(key); group_value.remove(value);
}); });
}); });
} else if checked.get_untracked() { } else if checked.get_untracked() {
checkbox_group_value.update(move |value| { group_value.update(move |group_value| {
value.insert(item_key.get_value()); group_value.insert(item_value.get_value());
}); });
} }
}); });
if let Some(label) = label { if let Some(label) = label {
view! { view! {
<Checkbox class value=(is_checked, checked.write_only())> <Checkbox class checked=(is_checked, checked.write_only())>
{label} {label}
</Checkbox> </Checkbox>
} }
} else { } else {
view! { <Checkbox class value=(is_checked, checked.write_only())/> } view! { <Checkbox class checked=(is_checked, checked.write_only())/> }
} }
} }

View file

@ -4,38 +4,56 @@ mod checkbox_item;
pub use checkbox_group::CheckboxGroup; pub use checkbox_group::CheckboxGroup;
pub use checkbox_item::CheckboxItem; pub use checkbox_item::CheckboxItem;
use crate::icon::*;
use leptos::*; use leptos::*;
use thaw_components::*; use thaw_components::*;
use thaw_utils::{class_list, mount_style, Model, OptionalProp}; use thaw_utils::{class_list, mount_style, Model, OptionalProp};
#[component] #[component]
pub fn Checkbox( pub fn Checkbox(
#[prop(optional, into)] value: Model<bool>, #[prop(optional, into)] checked: Model<bool>,
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>, #[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
#[prop(optional)] children: Option<Children>, #[prop(optional)] children: Option<Children>,
) -> impl IntoView { ) -> impl IntoView {
mount_style("checkbox", include_str!("./checkbox.css")); mount_style("checkbox", include_str!("./checkbox.css"));
let id = uuid::Uuid::new_v4().to_string();
let input_ref = NodeRef::<html::Input>::new();
let on_change = move |_| {
let input = input_ref.get_untracked().unwrap();
checked.set(input.checked())
};
view! { view! {
<div <div
class=class_list![ class=class_list![
"thaw-checkbox", ("thaw-checkbox--checked", move || value.get()), class.map(| c | "thaw-checkbox", ("thaw-checkbox--checked", move || checked.get()), class.map(| c |
move || c.get()) move || c.get())
] ]
on:click=move |_| value.set(!value.get_untracked())
> >
<input class="thaw-checkbox__input" type="checkbox"/> <input
class="thaw-checkbox__input"
type="checkbox"
id=id.clone()
checked=checked.get_untracked()
ref=input_ref
on:change=on_change
/>
<div class="thaw-checkbox__indicator"> <div class="thaw-checkbox__indicator">
<If cond=value.signal()> {
<Then slot> move || if checked.get() {
<Icon icon=icondata_ai::AiCheckOutlined style="color: white"/> view! {
</Then> <svg fill="currentColor" aria-hidden="true" width="12" height="12" viewBox="0 0 12 12" style="display: inline;line-height: 0">
</If> <path d="M9.76 3.2c.3.29.32.76.04 1.06l-4.25 4.5a.75.75 0 0 1-1.08.02L2.22 6.53a.75.75 0 0 1 1.06-1.06l1.7 1.7L8.7 3.24a.75.75 0 0 1 1.06-.04Z" fill="currentColor"></path>
</svg>
}.into()
} else {
None
}
}
</div> </div>
<OptionComp value=children let:children> <OptionComp value=children let:children>
<label class="thaw-checkbox__label">{children()}</label> <label class="thaw-checkbox__label" for=id>{children()}</label>
</OptionComp> </OptionComp>
</div> </div>
} }