// One value against its maximum as a 270° dial — CPU, a quota, a queue's fill — with the reading // in its centre and its label under it. A `meter` role carries the value for assistive tech, the // way `Meter` does; the readout is HTML over the svg so it keeps its size on a phone. import type { JSX } from 'solid-js'; import { cx } from '../cx'; import { useUi } from '../theme/context'; import { ChartFrame } from './ChartFrame'; import { chartPercentFormat, cssPercent } from './chart-frame-view'; import styles from './Gauge.module.scss'; import { GAUGE, gaugeArcs } from './gauge-view'; import { meterAria, meterShare } from './meter-view'; import type { Tone } from './variants'; export interface GaugeProps { /** What is measured, already translated: shown under the dial, and the meter's name. */ label: string; value: number; max: number; /** The fill's colour role. Default `accent`; a caller picks `warning`/`danger` by threshold. */ tone?: Tone | undefined; /** The readout, from the value and max. Default: the share as a percentage in the page's locale. */ format?: ((value: number, max: number) => string) | undefined; /** Lands on the root `
`. */ class?: string | undefined; } export function Gauge(props: GaugeProps): JSX.Element { const ui = useUi(); const share = (): number => meterShare(props.value, props.max); const readout = (): string => props.format === undefined ? chartPercentFormat(ui.locale)(share()) : props.format(props.value, props.max); const arcs = () => gaugeArcs(share()); return (
{/* A native paints through per-browser pseudo-elements, so it cannot be drawn from tokens; the role goes on the svg that draws it, as in `Meter`. */} {/* biome-ignore lint/a11y/useSemanticElements: cannot be styled from tokens */} {arcs().fill === '' ? null : } {/* aria-hidden: the meter already speaks this as its value text. */}
); }