use leptos::prelude::*;
use orbital_motion::use_reduced_motion;
use orbital_style::inject_style;
use orbital_theme::use_theme_options;
use crate::context::{GaugeContextProvider, GaugeState};
use crate::engine::resolve_gauge_layout;
use crate::types::effective_skip_animation;
use crate::{
chart_styles, density_modifier_class, ChartMotion, GaugeGeometry, GaugeReferenceArc,
GaugeValueArcMotion,
};
#[component]
pub fn GaugeContainer(
value: Option<f64>,
#[prop(default = 0.0)]
value_min: f64,
#[prop(default = 100.0)]
value_max: f64,
#[prop(default = GaugeGeometry::default())]
geometry: GaugeGeometry,
#[prop(default = 200.0)]
width: f64,
#[prop(default = 200.0)]
height: f64,
#[prop(default = None)]
skip_animation: Option<bool>,
#[prop(default = None)]
motion: Option<ChartMotion>,
#[prop(default = None)]
value_color: Option<String>,
#[prop(default = None)]
aria_value_text: Option<String>,
#[prop(optional, into)]
class: MaybeProp<String>,
#[prop(optional)]
children: Option<Children>,
) -> impl IntoView {
inject_style("orbital-charts", chart_styles());
let theme_options = use_theme_options();
let density_class =
Memo::new(move |_| density_modifier_class(theme_options.get().density).to_string());
let prefers_reduced = use_reduced_motion();
let skip = effective_skip_animation(skip_animation, motion.as_ref(), prefers_reduced.get());
let fill_color =
value_color.unwrap_or_else(|| "var(--orb-color-accent-primary, #2563eb)".into());
let layout = Memo::new(move |_| {
resolve_gauge_layout(width, height, &geometry, value, value_min, value_max)
});
let gauge_state = Memo::new(move |_| GaugeState::from(layout.get()));
let draw_key =
Memo::new(move |_| format!("{value:?}-{value_min}-{value_max}-{width}-{height}"));
let aria_now = value.map(|v| v.to_string());
let aria_min = value_min.to_string();
let aria_max = value_max.to_string();
let fill_signal = fill_color.clone();
let aria_value_text_attr = aria_value_text.clone();
view! {
<GaugeContextProvider state=gauge_state.get()>
<div
class=move || {
let mut classes = vec!["orb-gauge-root".to_string()];
let d = density_class.get();
if !d.is_empty() {
classes.push(d);
}
if let Some(c) = class.get() {
if !c.is_empty() {
classes.push(c);
}
}
classes.join(" ")
}
data-orbital-chart=""
data-orbital-chart-skip-animation=if skip { "true" } else { "false" }
style=format!("width: {width}px; height: {height}px; position: relative;")
role="meter"
aria-valuenow=aria_now
aria-valuemin=aria_min
aria-valuemax=aria_max
aria-valuetext=aria_value_text_attr.unwrap_or_default()
>
<svg
class="orb-chart-svg orb-gauge-svg"
width=width
height=height
viewBox=format!("0 0 {width} {height}")
>
<GaugeReferenceArc layout=layout.get() />
{value.is_some().then(|| {
let layout_snapshot = layout.get();
view! {
<GaugeValueArcMotion
layout=layout_snapshot
fill=fill_signal
skip_animation=skip
draw_key=Signal::derive(move || draw_key.get())
/>
}
})}
{children.map(|c| c())}
</svg>
</div>
</GaugeContextProvider>
}
}