dioxus_element_plug/components/
slider.rs1use dioxus::prelude::*;
2
3#[derive(Props, Clone, PartialEq)]
5pub struct SliderProps {
6 #[props(default = 0.0)]
8 pub model_value: f64,
9
10 #[props(default = 0.0)]
12 pub min: f64,
13
14 #[props(default = 100.0)]
16 pub max: f64,
17
18 #[props(default = 1.0)]
20 pub step: f64,
21
22 #[props(default = false)]
24 pub disabled: bool,
25
26 #[props(default = false)]
28 pub show_input: bool,
29
30 #[props(default = false)]
32 pub show_stops: bool,
33
34 #[props(default = true)]
36 pub show_tooltip: bool,
37
38 #[props(default = "horizontal".to_string())]
40 pub direction: String,
41
42 #[props(default = false)]
44 pub range: bool,
45
46 #[props(default)]
48 pub format_tooltip: Option<String>,
49
50 #[props(default)]
52 pub on_change: Option<EventHandler<f64>>,
53
54 #[props(default)]
56 pub on_input: Option<EventHandler<f64>>,
57
58 #[props(default)]
60 pub class: Option<String>,
61
62 #[props(default)]
64 pub style: Option<String>,
65}
66
67#[component]
82pub fn Slider(props: SliderProps) -> Element {
83 let mut class_names = vec!["el-slider".to_string()];
84
85 class_names.push(format!("is-{}", props.direction));
86
87 if props.disabled {
88 class_names.push("is-disabled".to_string());
89 }
90
91 if props.show_input {
92 class_names.push("el-slider--with-input".to_string());
93 }
94
95 if let Some(ref custom_class) = props.class {
96 class_names.push(custom_class.clone());
97 }
98
99 let class_string = class_names.join(" ");
100 let style_string = props.style.clone().unwrap_or_default();
101
102 let percentage = if props.max > props.min {
103 ((props.model_value - props.min) / (props.max - props.min) * 100.0).clamp(0.0, 100.0)
104 } else {
105 0.0
106 };
107
108 let bar_style = format!("width: {}%;", percentage);
109 let button_style = format!("left: {}%;", percentage);
110
111 let stops = if props.show_stops && props.step > 0.0 {
112 let mut stops_vec = Vec::new();
113 let mut val = props.min;
114 while val < props.max {
115 let stop_pct = ((val - props.min) / (props.max - props.min) * 100.0).clamp(0.0, 100.0);
116 stops_vec.push(stop_pct);
117 val += props.step;
118 }
119 stops_vec
120 } else {
121 vec![]
122 };
123
124 rsx! {
125 div {
126 class: "{class_string}",
127 style: "{style_string}",
128 role: "slider",
129 aria_valuemin: "{props.min}",
130 aria_valuemax: "{props.max}",
131 aria_valuenow: "{props.model_value}",
132 aria_disabled: "{props.disabled}",
133 div {
134 class: "el-slider__runway",
135 div {
136 class: "el-slider__bar",
137 style: "{bar_style}",
138 }
139 for stop_pct in stops.iter() {
140 div {
141 class: "el-slider__stop",
142 style: "left: {stop_pct}%;",
143 }
144 }
145 div {
146 class: "el-slider__button-wrapper",
147 style: "{button_style}",
148 div {
149 class: "el-slider__button",
150 }
151 if props.show_tooltip {
152 div {
153 class: "el-slider__tooltip",
154 "{props.model_value}"
155 }
156 }
157 }
158 }
159 if props.show_input {
160 div {
161 class: "el-slider__input",
162 input {
163 r#type: "number",
164 value: "{props.model_value}",
165 min: "{props.min}",
166 max: "{props.max}",
167 step: "{props.step}",
168 disabled: props.disabled,
169 onchange: move |e| {
170 if let Some(handler) = props.on_change {
171 if let Ok(val) = e.value().parse::<f64>() {
172 handler.call(val);
173 }
174 }
175 },
176 }
177 }
178 }
179 }
180 }
181}