diff --git a/demo_markdown/docs/radio/mod.md b/demo_markdown/docs/radio/mod.md index 6eb9c3b..87d5b84 100644 --- a/demo_markdown/docs/radio/mod.md +++ b/demo_markdown/docs/radio/mod.md @@ -8,10 +8,45 @@ view! { } ``` +### Group + +```rust demo +let value = create_rw_signal(None); + +view! { + <RadioGroup value> + <RadioItem key="a"> + "Apple" + </RadioItem> + <RadioItem key="o"> + "Orange" + </RadioItem> + </RadioGroup> + <div style="margin-top: 1rem"> + "value: " {move || format!("{:?}", value.get())} + </div> +} +``` + ### Radio Props | Name | Type | Default | Description | | -------- | ----------------------------------- | -------------------- | ---------------------------------------- | | class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the radio element. | | value | `Model<bool>` | `false` | Checked value. | -| children | `Children` | | Radio's content. | +| children | `Option<Children>` | `None` | Radio's content. | + +### RadioGroup Props + +| Name | Type | Default | Description | +| -------- | ----------------------- | -------------------- | ---------------------------------- | +| value | `Model<Option<String>>` | `Default::default()` | Sets the value of the radio group. | +| children | `Children` | | RadioGroup's content. | + +### RadioItem Props + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the radio element. | +| key | `String` | | The key of the radio to be used in a radio group. | +| children | `Option<Children>` | `None` | Radio's content. | diff --git a/thaw/src/radio/mod.rs b/thaw/src/radio/mod.rs index 124205e..8ee46fc 100644 --- a/thaw/src/radio/mod.rs +++ b/thaw/src/radio/mod.rs @@ -1,3 +1,9 @@ +mod radio_group; +mod radio_item; + +pub use radio_group::RadioGroup; +pub use radio_item::RadioItem; + use crate::{ theme::use_theme, utils::{class_list::class_list, mount_style, Model, OptionalProp}, @@ -9,7 +15,7 @@ use leptos::*; pub fn Radio( #[prop(optional, into)] value: Model<bool>, #[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>, - children: Children, + #[prop(optional)] children: Option<Children>, ) -> impl IntoView { let theme = use_theme(Theme::light); mount_style("radio", include_str!("./radio.css")); @@ -36,7 +42,9 @@ pub fn Radio( > <input class="thaw-radio__input" type="radio" prop:value=move || value.get()/> <div class="thaw-radio__dot"></div> - <div class="thaw-radio__label">{children()}</div> + <div class="thaw-radio__label"> + {children.map(|children| children())} + </div> </div> } } diff --git a/thaw/src/radio/radio_group.rs b/thaw/src/radio/radio_group.rs new file mode 100644 index 0000000..0efd55b --- /dev/null +++ b/thaw/src/radio/radio_group.rs @@ -0,0 +1,17 @@ +use crate::utils::Model; +use leptos::*; + +#[component] +pub fn RadioGroup( + #[prop(optional, into)] value: Model<Option<String>>, + children: Children, +) -> impl IntoView { + view! { <Provider value=RadioGroupInjection(value) children/> } +} + +#[derive(Clone)] +pub(crate) struct RadioGroupInjection(pub Model<Option<String>>); + +pub(crate) fn use_radio_group() -> RadioGroupInjection { + expect_context() +} diff --git a/thaw/src/radio/radio_item.rs b/thaw/src/radio/radio_item.rs new file mode 100644 index 0000000..0a393e8 --- /dev/null +++ b/thaw/src/radio/radio_item.rs @@ -0,0 +1,44 @@ +use crate::{ + radio::{radio_group::use_radio_group, Radio}, + utils::OptionalProp, +}; +use leptos::*; + +#[component] +pub fn RadioItem( + #[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>, + #[prop(into)] key: String, + #[prop(optional)] children: Option<Children>, +) -> impl IntoView { + let radio_group_value = use_radio_group().0; + let checked = RwSignal::new(false); + let item_key = store_value(key); + + let is_checked = Memo::new(move |_| { + radio_group_value.with(|value| item_key.with_value(|key| value.as_ref() == Some(key))) + }); + + Effect::new(move |prev| { + let checked = checked.get(); + if prev.is_some() { + if !is_checked.get_untracked() { + radio_group_value.set(Some(item_key.get_value())) + } + } + + checked + }); + + if let Some(children) = children { + view! { + <Radio class value=(is_checked, checked.write_only())> + {children()} + </Radio> + } + } else { + view! { + <Radio class value=(is_checked, checked.write_only())> + </Radio> + } + } +}