fc_dioxus/components/
slider.rs1use crate::{
4 core::{
5 assets,
6 attrs::{availability_attributes, component_attributes},
7 measure::{custom_property, CustomProperty},
8 },
9 prelude::*,
10 theme::use_stylesheets,
11};
12const BEM: Bem = Bem::new("fc-slider");
13
14#[must_use]
24pub fn slider_percent(value: f64, min: f64, max: f64) -> Percent {
25 let span = max - min;
26 if span > 0.0 {
27 Percent::new((value - min) / span * 100.0)
28 } else {
29 Percent::new(0.0)
30 }
31}
32
33#[component]
37pub fn Slider(
38 label: AccessibleName,
39 #[props(default = 0.0)] min: f64,
40 #[props(default = 100.0)] max: f64,
41 #[props(default = 1.0)] step: f64,
42 #[props(default)] value: Option<ReadSignal<f64>>,
43 #[props(default)] default_value: f64,
44 #[props(default)] oninput: Option<EventHandler<f64>>,
45 #[props(default)]
47 show_value: bool,
48 #[props(default)]
50 marks: Vec<String>,
51 #[props(default)] invalid: bool,
52 #[props(default)] availability: Availability,
53 #[props(default)] class: Option<String>,
54 #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
55) -> Element {
56 let state = use_controllable(value, || default_value, oninput);
57 let id = use_id();
58 let current = state.get();
59 let attributes = component_attributes(
60 attributes,
61 ClassList::new(BEM.block()).extend(class.as_deref()),
62 &[],
63 );
64 let mut input = availability_attributes(&availability);
65 input.push(custom_property(
66 CustomProperty::SliderPct,
67 format!("{}%", slider_percent(current, min, max)),
68 ));
69 rsx! {
70 if use_stylesheets() { document::Stylesheet { href: assets::COMPONENTS_SLIDER_CSS } }
71 div { ..attributes,
72 input { class: BEM.element("input"), r#type: "range", id: "{id}", min: "{min}", max: "{max}", step: "{step}",
73 value: "{current}", aria_label: label.to_string(), aria_invalid: invalid.then_some("true"),
74 oninput: move |event| if let Ok(value) = event.value().parse::<f64>() { state.set(value); },
75 ..input,
76 }
77 if show_value { output { class: BEM.element("value"), ..crate::spread![Attribute::new("for", id.to_string(), None, false)], "{current}" } }
78 if !marks.is_empty() {
79 ol { class: BEM.element("marks"), aria_hidden: "true",
80 for mark in marks { li { "{mark}" } }
81 }
82 }
83 }
84 }
85}