use hikari_palette::classes::{ClassesBuilder, RadioClass};
use tairitsu_hooks::ReactiveSignal;
use crate::prelude::*;
use crate::styled::StyledComponent;
#[derive(Clone)]
pub struct RadioContext {
pub name: String,
pub selected_value: ReactiveSignal<String>,
pub on_change: EventHandler<String>,
pub disabled: bool,
}
#[define_props]
pub struct RadioButtonProps {
pub value: String,
pub children: Element,
#[default(false)]
pub disabled: bool,
#[default(String::new())]
pub class: String,
pub on_change: Option<EventHandler<String>>,
}
#[component]
pub fn RadioButton(props: RadioButtonProps) -> Element {
let ctx = use_context::<RadioContext>().expect("RadioContext not found");
let ctx = ctx.get();
let is_checked = *ctx.selected_value.read() == props.value;
let disabled = props.disabled || ctx.disabled;
let radio_name = ctx.name.to_string();
let on_change = ctx.on_change.clone();
let radio_classes = ClassesBuilder::new()
.add_typed(RadioClass::Label)
.add(&props.class)
.build();
let handle_change = {
let value = props.value.clone();
let on_change = props.on_change;
let group_on_change = ctx.on_change.clone();
let group_selected_value = ctx.selected_value.clone();
move |_| {
group_selected_value.set(value.clone());
group_on_change.call(value.clone());
if let Some(handler) = on_change.as_ref() {
handler.call(value.clone());
}
}
};
rsx! {
label { class: radio_classes,
input {
r#type: "radio",
name: radio_name,
value: "{props.value}",
checked: is_checked,
disabled,
onchange: handle_change,
}
div { class: "hi-radio-indicator",
div { class: "hi-radio-dot" }
}
span { class: "hi-radio-text", {props.children} }
}
}
}
#[define_props]
pub struct RadioGroupProps {
pub name: String,
pub value: String,
pub on_change: Option<EventHandler<String>>,
#[default(false)]
pub disabled: bool,
pub children: Element,
#[default(String::new())]
pub class: String,
pub direction: RadioDirection,
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub enum RadioDirection {
#[default]
Vertical,
Horizontal,
}
#[component]
pub fn RadioGroup(props: RadioGroupProps) -> Element {
let selected_value = use_signal(|| props.value.clone());
let name = props.name.clone();
let disabled = props.disabled;
let on_change = props
.on_change
.clone()
.unwrap_or_else(|| EventHandler::new(|_| {}));
let _ctx = use_context_provider(move || RadioContext {
name,
selected_value,
on_change,
disabled,
});
let direction_class = match props.direction {
RadioDirection::Vertical => RadioClass::RadioGroupVertical,
RadioDirection::Horizontal => RadioClass::RadioGroupHorizontal,
};
let group_classes = ClassesBuilder::new()
.add_typed(RadioClass::RadioGroup)
.add_typed(direction_class)
.add(&props.class)
.build();
rsx! {
div { class: group_classes, {props.children} }
}
}
pub struct RadioGroupComponent;
impl StyledComponent for RadioGroupComponent {
fn styles() -> &'static str {
include_str!(concat!(env!("OUT_DIR"), "/styles/radio.css"))
}
fn name() -> &'static str {
"radio_group"
}
}