perspective_viewer/components/form/
number_field.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use web_sys::{HtmlInputElement, InputEvent};
14use yew::{Callback, Properties, TargetCast, function_component, html};
15
16use crate::components::form::optional_field::OptionalField;
17
18#[derive(Properties, Debug, PartialEq, Clone)]
19pub struct NumberFieldProps {
20    pub label: String,
21    pub current_value: Option<f64>,
22    pub default: f64,
23    pub on_change: Callback<Option<f64>>,
24
25    #[prop_or_default]
26    pub disabled: bool,
27
28    #[prop_or_default]
29    pub min: Option<f64>,
30
31    #[prop_or_default]
32    pub max: Option<f64>,
33
34    #[prop_or_default]
35    pub step: Option<f64>,
36}
37
38#[function_component(NumberField)]
39pub fn number_field(props: &NumberFieldProps) -> yew::Html {
40    let parse_number_input = |event: InputEvent| {
41        Some(
42            event
43                .target_unchecked_into::<HtmlInputElement>()
44                .value_as_number(),
45        )
46    };
47
48    let number_input = html! {
49        <input
50            type="number"
51            class="parameter"
52            min={props.min.map(|val| val.to_string())}
53            max={props.max.map(|val| val.to_string())}
54            step={props.step.map(|val| val.to_string())}
55            value={props.current_value.unwrap_or(props.default).to_string()}
56            oninput={props.on_change.reform(parse_number_input)}
57        />
58    };
59
60    html! {
61        <div class="row">
62            <OptionalField
63                label={props.label.clone()}
64                on_check={props.on_change.reform(|_| None)}
65                checked={props.current_value.map(|val| val != props.default).unwrap_or_default()}
66                disabled={props.disabled}
67            >
68                { number_input }
69            </OptionalField>
70        </div>
71    }
72}