@viraui/react 2026.10.0 → 2026.11.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +8 -0
- package/dist/catalog.json +12 -0
- package/dist/components/avatar/avatar.d.ts +6 -0
- package/dist/components/avatar/avatar.js +2 -2
- package/dist/components/badge/badge.css +1 -1
- package/dist/components/button/button.css +1 -1
- package/dist/components/dialog/dialog-sheet.d.ts +1 -1
- package/dist/components/gauge/arcs.d.ts +134 -0
- package/dist/components/gauge/arcs.js +145 -0
- package/dist/components/gauge/context.d.ts +134 -0
- package/dist/components/gauge/context.js +83 -0
- package/dist/components/gauge/control.d.ts +107 -0
- package/dist/components/gauge/control.js +223 -0
- package/dist/components/gauge/demos/_shared.d.ts +28 -0
- package/dist/components/gauge/demos/activity-ring.d.ts +9 -0
- package/dist/components/gauge/demos/air-quality.d.ts +9 -0
- package/dist/components/gauge/demos/analog-dial.d.ts +9 -0
- package/dist/components/gauge/demos/battery.d.ts +9 -0
- package/dist/components/gauge/demos/chronograph.d.ts +9 -0
- package/dist/components/gauge/demos/clock.d.ts +9 -0
- package/dist/components/gauge/demos/compass.d.ts +9 -0
- package/dist/components/gauge/demos/data-usage.d.ts +9 -0
- package/dist/components/gauge/demos/dimmer.d.ts +9 -0
- package/dist/components/gauge/demos/fuel.d.ts +9 -0
- package/dist/components/gauge/demos/heart-rate.d.ts +9 -0
- package/dist/components/gauge/demos/internet-speed.d.ts +9 -0
- package/dist/components/gauge/demos/nested-rings.d.ts +11 -0
- package/dist/components/gauge/demos/orrery.d.ts +12 -0
- package/dist/components/gauge/demos/power-meter.d.ts +9 -0
- package/dist/components/gauge/demos/progress-ring.d.ts +9 -0
- package/dist/components/gauge/demos/range.d.ts +10 -0
- package/dist/components/gauge/demos/saas-metric.d.ts +9 -0
- package/dist/components/gauge/demos/segments.d.ts +9 -0
- package/dist/components/gauge/demos/simple.d.ts +9 -0
- package/dist/components/gauge/demos/speed-fuel.d.ts +10 -0
- package/dist/components/gauge/demos/speedometer.d.ts +9 -0
- package/dist/components/gauge/demos/sprint.d.ts +9 -0
- package/dist/components/gauge/demos/sun-path.d.ts +9 -0
- package/dist/components/gauge/demos/system.d.ts +11 -0
- package/dist/components/gauge/demos/tachometer.d.ts +9 -0
- package/dist/components/gauge/demos/temperature.d.ts +9 -0
- package/dist/components/gauge/demos/thermostat.d.ts +9 -0
- package/dist/components/gauge/demos/timer.d.ts +9 -0
- package/dist/components/gauge/demos/volume.d.ts +10 -0
- package/dist/components/gauge/demos/wind.d.ts +9 -0
- package/dist/components/gauge/dot.d.ts +55 -0
- package/dist/components/gauge/dot.js +34 -0
- package/dist/components/gauge/gauge.css +1 -0
- package/dist/components/gauge/gauge.d.ts +84 -0
- package/dist/components/gauge/gauge.js +62 -0
- package/dist/components/gauge/gauge.module.js +24 -0
- package/dist/components/gauge/index.d.ts +15 -0
- package/dist/components/gauge/inset.d.ts +30 -0
- package/dist/components/gauge/inset.js +39 -0
- package/dist/components/gauge/math.d.ts +69 -0
- package/dist/components/gauge/math.js +135 -0
- package/dist/components/gauge/needle.d.ts +81 -0
- package/dist/components/gauge/needle.js +162 -0
- package/dist/components/gauge/scale.d.ts +44 -0
- package/dist/components/gauge/scale.js +21 -0
- package/dist/components/gauge/text.d.ts +79 -0
- package/dist/components/gauge/text.js +42 -0
- package/dist/components/gauge/ticks.d.ts +169 -0
- package/dist/components/gauge/ticks.js +124 -0
- package/dist/components/gauge/tooltip.d.ts +117 -0
- package/dist/components/gauge/tooltip.js +337 -0
- package/dist/components/gauge/transition.d.ts +60 -0
- package/dist/components/gauge/transition.js +129 -0
- package/dist/components/gauge/use-animated-value.d.ts +14 -0
- package/dist/components/gauge/use-animated-value.js +111 -0
- package/dist/components/gauge/utils.d.ts +51 -0
- package/dist/components/gauge/utils.js +80 -0
- package/dist/components/icon-meter/icon-meter.css +1 -0
- package/dist/components/icon-meter/icon-meter.d.ts +62 -0
- package/dist/components/icon-meter/icon-meter.js +105 -0
- package/dist/components/icon-meter/icon-meter.module.js +11 -0
- package/dist/components/icon-meter/index.d.ts +2 -0
- package/dist/components/icon-meter/utils.d.ts +22 -0
- package/dist/components/icon-meter/utils.js +40 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/popover/popover-sheet.d.ts +1 -2
- package/dist/components/stack/stack.d.ts +9 -2
- package/dist/components/tabs/tabs.d.ts +1 -2
- package/dist/index.js +17 -1
- package/dist/internal/chrome-icons/chrome-icons.d.ts +4 -0
- package/dist/internal/chrome-icons/chrome-icons.js +12 -4
- package/dist/node_modules/.pnpm/react-dom@19.3.0_react@19.3.0/node_modules/react-dom/cjs/react-dom.development.js +192 -0
- package/dist/node_modules/.pnpm/react-dom@19.3.0_react@19.3.0/node_modules/react-dom/cjs/react-dom.production.js +156 -0
- package/dist/node_modules/.pnpm/react-dom@19.3.0_react@19.3.0/node_modules/react-dom/index.js +22 -0
- package/dist/preflight.css +1 -1
- package/dist/specs/components/avatar/props.xml +3 -0
- package/dist/specs/components/avatar/usage.xml +1 -0
- package/dist/specs/components/badge/a11y.xml +1 -1
- package/dist/specs/components/button/props.xml +2 -2
- package/dist/specs/components/button/usage.xml +1 -1
- package/dist/specs/components/gauge/a11y.xml +8 -0
- package/dist/specs/components/gauge/meta.xml +38 -0
- package/dist/specs/components/gauge/patterns.xml +1158 -0
- package/dist/specs/components/gauge/props.xml +452 -0
- package/dist/specs/components/gauge/usage.xml +21 -0
- package/dist/specs/components/icon-button/props.xml +2 -2
- package/dist/specs/components/icon-button/usage.xml +1 -1
- package/dist/specs/components/icon-meter/a11y.xml +9 -0
- package/dist/specs/components/icon-meter/meta.xml +21 -0
- package/dist/specs/components/icon-meter/patterns.xml +23 -0
- package/dist/specs/components/icon-meter/props.xml +44 -0
- package/dist/specs/components/icon-meter/usage.xml +13 -0
- package/dist/specs/components/linear-progress/usage.xml +1 -0
- package/dist/specs/components/meter/meta.xml +1 -0
- package/dist/specs/components/meter/props.xml +1 -0
- package/dist/specs/components/meter/usage.xml +1 -0
- package/dist/specs/components/stack/patterns.xml +21 -21
- package/dist/specs/components/stack/props.xml +6 -6
- package/dist/specs/components/stack/usage.xml +4 -2
- package/dist/specs/components/text/patterns.xml +1 -1
- package/dist/specs/components/text/usage.xml +1 -1
- package/dist/specs/components/toggle-button/props.xml +1 -1
- package/dist/specs/components/toggle-button/usage.xml +1 -1
- package/dist/specs/components/toggle-text-button/props.xml +1 -1
- package/dist/specs/foundation/attributes.xml +3 -3
- package/dist/specs/foundation/modules.xml +1 -1
- package/dist/specs/foundation/theme-topics.xml +7 -2
- package/dist/specs/index.xml +21 -1
- package/dist/specs/patterns/compose-layout-first.xml +1 -1
- package/dist/specs/patterns/settings-panel.xml +1 -1
- package/dist/specs/patterns/settings-row.xml +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { GaugeRange } from './context';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
/** A literal number widened, so `value={42}` still takes any number back. */
|
|
4
|
+
type Widen<V> = V extends number ? number : [number, number];
|
|
5
|
+
export type GaugeControlProps<V extends number | GaugeRange = number> = {
|
|
6
|
+
/**
|
|
7
|
+
* A number for one handle, or a `[from, to]` range for two.
|
|
8
|
+
*/
|
|
9
|
+
value: V;
|
|
10
|
+
/**
|
|
11
|
+
* Emits the next value (widened number or tuple).
|
|
12
|
+
*/
|
|
13
|
+
onChange: (value: Widen<V>) => void;
|
|
14
|
+
/**
|
|
15
|
+
* A press on the middle of the face, or Enter, for a dial that is also a
|
|
16
|
+
* switch. Left out, the middle does nothing.
|
|
17
|
+
* @defaultValue undefined
|
|
18
|
+
*/
|
|
19
|
+
onPress?: () => void;
|
|
20
|
+
/**
|
|
21
|
+
* Domain lower bound.
|
|
22
|
+
* @defaultValue 0
|
|
23
|
+
*/
|
|
24
|
+
min?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Domain upper bound.
|
|
27
|
+
* @defaultValue 100
|
|
28
|
+
*/
|
|
29
|
+
max?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Granularity a drag lands on, and the size of an arrow-key step.
|
|
32
|
+
* @defaultValue 1
|
|
33
|
+
*/
|
|
34
|
+
step?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Gauge degrees, matching the gauge drawn inside.
|
|
37
|
+
* @defaultValue 40
|
|
38
|
+
*/
|
|
39
|
+
startAngle?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Gauge degrees, matching the gauge drawn inside.
|
|
42
|
+
* @defaultValue 320
|
|
43
|
+
*/
|
|
44
|
+
endAngle?: number;
|
|
45
|
+
/**
|
|
46
|
+
* The domain is a closed ring, as the gauge's own `wrap`: values carry on
|
|
47
|
+
* round past either end instead of holding there, and a range may run
|
|
48
|
+
* across the seam, its ends in either order.
|
|
49
|
+
* @defaultValue false
|
|
50
|
+
*/
|
|
51
|
+
wrap?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Read to screen readers; every slider needs one. On a range it names the
|
|
54
|
+
* pair, and each thumb gets its own from `thumbLabels`.
|
|
55
|
+
*/
|
|
56
|
+
label: string;
|
|
57
|
+
/**
|
|
58
|
+
* Names for a range's two thumbs. Defaults to the label with "start" and
|
|
59
|
+
* "end" after it.
|
|
60
|
+
* @defaultValue Derived from `label`
|
|
61
|
+
*/
|
|
62
|
+
thumbLabels?: readonly [string, string];
|
|
63
|
+
/**
|
|
64
|
+
* The value as it would be spoken: "21.5 °C" rather than 21.5. A range
|
|
65
|
+
* takes one for each end.
|
|
66
|
+
* @defaultValue undefined
|
|
67
|
+
*/
|
|
68
|
+
valueText?: V extends number ? string : readonly [string, string];
|
|
69
|
+
/**
|
|
70
|
+
* The face turns like a knob: a drag anywhere on it moves the value by as
|
|
71
|
+
* far as the pointer goes round, rather than jumping to where it is. A
|
|
72
|
+
* range turns as a whole, keeping its width.
|
|
73
|
+
* @defaultValue false
|
|
74
|
+
*/
|
|
75
|
+
knob?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Ignores pointer and keyboard input when true.
|
|
78
|
+
* @defaultValue false
|
|
79
|
+
*/
|
|
80
|
+
disabled?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Merged onto the control host.
|
|
83
|
+
* @defaultValue undefined
|
|
84
|
+
*/
|
|
85
|
+
className?: string;
|
|
86
|
+
/**
|
|
87
|
+
* The round `Gauge` tree drawn inside the control.
|
|
88
|
+
* Linear bars belong on `Slider`, not here.
|
|
89
|
+
*/
|
|
90
|
+
children: React.ReactNode;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Makes the square gauge inside it a round slider: drag round the ring to set
|
|
94
|
+
* it, or use the arrow keys, Page Up and Down, Home and End. A drag past either
|
|
95
|
+
* end of the sweep holds there rather than jumping to the other. A press in
|
|
96
|
+
* the middle of the face, or Enter, is left for `onPress`, which a dimmer
|
|
97
|
+
* uses to switch on and off, or, with `knob`, turns the face from where it
|
|
98
|
+
* is. The domain and angles default to `Gauge`'s own.
|
|
99
|
+
*
|
|
100
|
+
* Given a `[from, to]` range it has two thumbs: a press on the ring takes
|
|
101
|
+
* whichever is nearer, and each can be tabbed to and keyed on its own. On an
|
|
102
|
+
* open domain they hold short of passing each other.
|
|
103
|
+
*
|
|
104
|
+
* For a linear range control use `Slider`.
|
|
105
|
+
*/
|
|
106
|
+
export declare const GaugeControl: <V extends number | GaugeRange = number>({ value, onChange, onPress, min, max, step, startAngle, endAngle, wrap, label, thumbLabels, valueText, knob, disabled, className, children, }: GaugeControlProps<V>) => React.JSX.Element;
|
|
107
|
+
export {};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { clsx } from "../../core/clsx.js";
|
|
3
|
+
import { angleToValue, clamp, foldValue, fractionDigits, valueToAngle } from "./math.js";
|
|
4
|
+
import gauge_module_default from "./gauge.module.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
//#region src/components/gauge/control.tsx
|
|
8
|
+
/** How far out from the centre a press starts counting as the ring, as a
|
|
9
|
+
share of the half width. Inside it is the face, left for `onPress`. */
|
|
10
|
+
var FACE = .55;
|
|
11
|
+
/** Too near the centre for the angle under the pointer to mean anything. */
|
|
12
|
+
var HUB = .08;
|
|
13
|
+
/** The gauge angle under a point, measured round the element's centre. */
|
|
14
|
+
var angleAt = (el, x, y) => {
|
|
15
|
+
const box = el.getBoundingClientRect();
|
|
16
|
+
const dx = x - (box.left + box.width / 2);
|
|
17
|
+
const dy = y - (box.top + box.height / 2);
|
|
18
|
+
return {
|
|
19
|
+
angle: ((Math.atan2(dy, dx) * 180 / Math.PI - 90) % 360 + 360) % 360,
|
|
20
|
+
/** How far out from the centre, as a share of the half width. */
|
|
21
|
+
reach: Math.hypot(dx, dy) / (box.width / 2)
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/** Degrees between two angles the short way round. */
|
|
25
|
+
var turnBetween = (a, b) => Math.abs(((a - b) % 360 + 540) % 360 - 180);
|
|
26
|
+
/**
|
|
27
|
+
* Makes the square gauge inside it a round slider: drag round the ring to set
|
|
28
|
+
* it, or use the arrow keys, Page Up and Down, Home and End. A drag past either
|
|
29
|
+
* end of the sweep holds there rather than jumping to the other. A press in
|
|
30
|
+
* the middle of the face, or Enter, is left for `onPress`, which a dimmer
|
|
31
|
+
* uses to switch on and off, or, with `knob`, turns the face from where it
|
|
32
|
+
* is. The domain and angles default to `Gauge`'s own.
|
|
33
|
+
*
|
|
34
|
+
* Given a `[from, to]` range it has two thumbs: a press on the ring takes
|
|
35
|
+
* whichever is nearer, and each can be tabbed to and keyed on its own. On an
|
|
36
|
+
* open domain they hold short of passing each other.
|
|
37
|
+
*
|
|
38
|
+
* For a linear range control use `Slider`.
|
|
39
|
+
*/
|
|
40
|
+
var GaugeControl = ({ value, onChange, onPress, min = 0, max = 100, step = 1, startAngle = 40, endAngle = 320, wrap = false, label, thumbLabels, valueText, knob = false, disabled = false, className, children }) => {
|
|
41
|
+
const range = typeof value !== "number";
|
|
42
|
+
const ends = range ? [...value] : [value];
|
|
43
|
+
const emit = (next) => {
|
|
44
|
+
if (range) {
|
|
45
|
+
const from = next[0];
|
|
46
|
+
const to = next[1];
|
|
47
|
+
if (from === void 0 || to === void 0) return;
|
|
48
|
+
onChange([from, to]);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const single = next[0];
|
|
52
|
+
if (single === void 0) return;
|
|
53
|
+
onChange(single);
|
|
54
|
+
};
|
|
55
|
+
const pressed = React.useRef(false);
|
|
56
|
+
const active = React.useRef(0);
|
|
57
|
+
const turn = React.useRef(null);
|
|
58
|
+
const thumbs = React.useRef([]);
|
|
59
|
+
const lo = Math.min(min, max);
|
|
60
|
+
const hi = Math.max(min, max);
|
|
61
|
+
const digits = Math.max(fractionDigits(step), fractionDigits(lo), fractionDigits(hi));
|
|
62
|
+
const snap = (v) => Math.round(v / step) * step;
|
|
63
|
+
const settle = (v) => {
|
|
64
|
+
const n = Number(v.toFixed(digits));
|
|
65
|
+
return wrap ? foldValue(n, lo, hi) : clamp(n, lo, hi);
|
|
66
|
+
};
|
|
67
|
+
const setEnd = (i, next) => {
|
|
68
|
+
let v = settle(next);
|
|
69
|
+
if (range && !wrap) {
|
|
70
|
+
const other = ends[i === 0 ? 1 : 0];
|
|
71
|
+
if (other === void 0) return;
|
|
72
|
+
v = i === 0 ? Math.min(v, other) : Math.max(v, other);
|
|
73
|
+
}
|
|
74
|
+
emit(ends.map((e, j) => j === i ? v : e));
|
|
75
|
+
};
|
|
76
|
+
const sweep = endAngle - startAngle;
|
|
77
|
+
const positionOf = (v) => valueToAngle(v, min, max, startAngle, endAngle);
|
|
78
|
+
const locate = (el, x, y) => {
|
|
79
|
+
const { angle, reach } = angleAt(el, x, y);
|
|
80
|
+
return {
|
|
81
|
+
at: angle,
|
|
82
|
+
reach
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
const valueAt = (at) => snap(angleToValue(at, min, max, startAngle, endAngle));
|
|
86
|
+
const nearest = (at, under) => {
|
|
87
|
+
if (!range) return 0;
|
|
88
|
+
const distances = ends.map((e) => turnBetween(at, positionOf(e)));
|
|
89
|
+
const a = distances[0] ?? Infinity;
|
|
90
|
+
const b = distances[1] ?? Infinity;
|
|
91
|
+
if (a !== b) return a < b ? 0 : 1;
|
|
92
|
+
return under > (ends[1] ?? under) ? 1 : 0;
|
|
93
|
+
};
|
|
94
|
+
const onPointerDown = (e) => {
|
|
95
|
+
if (disabled) return;
|
|
96
|
+
const el = e.currentTarget;
|
|
97
|
+
const { at, reach } = locate(el, e.clientX, e.clientY);
|
|
98
|
+
const face = reach < FACE;
|
|
99
|
+
if (knob) {
|
|
100
|
+
el.setPointerCapture(e.pointerId);
|
|
101
|
+
turn.current = {
|
|
102
|
+
at,
|
|
103
|
+
base: ends,
|
|
104
|
+
by: 0
|
|
105
|
+
};
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (face) {
|
|
109
|
+
el.setPointerCapture(e.pointerId);
|
|
110
|
+
pressed.current = true;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
el.setPointerCapture(e.pointerId);
|
|
114
|
+
const under = valueAt(at);
|
|
115
|
+
active.current = nearest(at, under);
|
|
116
|
+
if (range) {
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
const thumb = thumbs.current[active.current];
|
|
119
|
+
if (thumb) {
|
|
120
|
+
thumb.dataset.pointer = "";
|
|
121
|
+
thumb.focus({ preventScroll: true });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
setEnd(active.current, under);
|
|
125
|
+
};
|
|
126
|
+
const onPointerMove = (e) => {
|
|
127
|
+
if (!e.currentTarget.hasPointerCapture(e.pointerId)) return;
|
|
128
|
+
if (pressed.current) return;
|
|
129
|
+
const t = turn.current;
|
|
130
|
+
if (t) {
|
|
131
|
+
const { at, reach } = locate(e.currentTarget, e.clientX, e.clientY);
|
|
132
|
+
if (reach < HUB) return;
|
|
133
|
+
const delta = (at - t.at + 540) % 360 - 180;
|
|
134
|
+
let by = t.by + delta / sweep * (max - min);
|
|
135
|
+
if (!wrap) by = clamp(by, lo - Math.min(...t.base), hi - Math.max(...t.base));
|
|
136
|
+
turn.current = {
|
|
137
|
+
...t,
|
|
138
|
+
at,
|
|
139
|
+
by
|
|
140
|
+
};
|
|
141
|
+
emit(t.base.map((v) => settle(v + snap(by))));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const { at } = locate(e.currentTarget, e.clientX, e.clientY);
|
|
145
|
+
setEnd(active.current, valueAt(at));
|
|
146
|
+
};
|
|
147
|
+
const onPointerUp = () => {
|
|
148
|
+
if (pressed.current) onPress?.();
|
|
149
|
+
pressed.current = false;
|
|
150
|
+
turn.current = null;
|
|
151
|
+
};
|
|
152
|
+
const onPointerCancel = () => {
|
|
153
|
+
pressed.current = false;
|
|
154
|
+
turn.current = null;
|
|
155
|
+
};
|
|
156
|
+
const keyDown = (i) => (e) => {
|
|
157
|
+
delete e.currentTarget.dataset.pointer;
|
|
158
|
+
if (disabled) return;
|
|
159
|
+
const v = ends[i];
|
|
160
|
+
if (v === void 0) return;
|
|
161
|
+
const big = (max - min) / 10;
|
|
162
|
+
const moves = {
|
|
163
|
+
ArrowUp: v + step,
|
|
164
|
+
ArrowRight: v + step,
|
|
165
|
+
ArrowDown: v - step,
|
|
166
|
+
ArrowLeft: v - step,
|
|
167
|
+
PageUp: v + big,
|
|
168
|
+
PageDown: v - big,
|
|
169
|
+
Home: min,
|
|
170
|
+
End: max
|
|
171
|
+
};
|
|
172
|
+
if (e.key in moves) {
|
|
173
|
+
e.preventDefault();
|
|
174
|
+
const next = moves[e.key];
|
|
175
|
+
if (next === void 0) return;
|
|
176
|
+
setEnd(i, next);
|
|
177
|
+
} else if ((e.key === "Enter" || e.key === " ") && onPress) {
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
onPress();
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const setThumbRef = (i) => (el) => {
|
|
183
|
+
thumbs.current[i] = el;
|
|
184
|
+
};
|
|
185
|
+
const handleThumbBlur = (e) => {
|
|
186
|
+
delete e.currentTarget.dataset.pointer;
|
|
187
|
+
};
|
|
188
|
+
const slider = (i) => {
|
|
189
|
+
const texts = valueText;
|
|
190
|
+
return {
|
|
191
|
+
role: "slider",
|
|
192
|
+
tabIndex: disabled ? -1 : 0,
|
|
193
|
+
"aria-label": range ? thumbLabels?.[i] ?? `${label} ${i === 0 ? "start" : "end"}` : label,
|
|
194
|
+
"aria-valuemin": range && !wrap && i === 1 ? ends[0] : min,
|
|
195
|
+
"aria-valuemax": range && !wrap && i === 0 ? ends[1] : max,
|
|
196
|
+
"aria-valuenow": ends[i],
|
|
197
|
+
"aria-valuetext": typeof texts === "string" ? texts : texts?.[i],
|
|
198
|
+
"aria-disabled": disabled ? "true" : "false",
|
|
199
|
+
onKeyDown: keyDown(i)
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
203
|
+
...range ? {
|
|
204
|
+
role: "group",
|
|
205
|
+
"aria-label": label
|
|
206
|
+
} : slider(0),
|
|
207
|
+
"data-slot": "gauge-control",
|
|
208
|
+
"data-disabled": disabled ? "true" : "false",
|
|
209
|
+
onPointerDown,
|
|
210
|
+
onPointerMove,
|
|
211
|
+
onPointerUp,
|
|
212
|
+
onPointerCancel,
|
|
213
|
+
className: clsx(gauge_module_default.Control, className),
|
|
214
|
+
children: [children, range && ends.map((_, i) => /* @__PURE__ */ jsx("div", {
|
|
215
|
+
ref: setThumbRef(i),
|
|
216
|
+
...slider(i),
|
|
217
|
+
onBlur: handleThumbBlur,
|
|
218
|
+
className: gauge_module_default.VisuallyHidden
|
|
219
|
+
}, i === 0 ? "start" : "end"))]
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
//#endregion
|
|
223
|
+
export { GaugeControl };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
/** Story/demo dial frame — keep demos square-ish in Storybook. */
|
|
3
|
+
export declare const dialWrap: CSSProperties;
|
|
4
|
+
export declare function DialFrame({ children }: {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}): import('react').JSX.Element;
|
|
7
|
+
export declare const RADIUS = 200;
|
|
8
|
+
/**
|
|
9
|
+
* Upstream template pads use **y-up** fractions of radius (studio
|
|
10
|
+
* `lib/gauge-panels.ts`: `x * RADIUS`, `y: -y * RADIUS`). SVG is y-down.
|
|
11
|
+
* Pass template `{x,y}` verbatim — never negate yourself.
|
|
12
|
+
*/
|
|
13
|
+
export declare const pos: (x: number, y: number, radius?: number) => {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
};
|
|
17
|
+
/** Radial length only (ticks offset, etc.) — no axis flip. */
|
|
18
|
+
export declare const px: (fraction: number, radius?: number) => number;
|
|
19
|
+
/** Map upstream `token("muted")` → contrast (never `--global-muted`). */
|
|
20
|
+
export declare const TOKEN: {
|
|
21
|
+
readonly foreground: "var(--global-foreground)";
|
|
22
|
+
readonly primary: "var(--global-primary)";
|
|
23
|
+
readonly contrast: "var(--global-contrast)";
|
|
24
|
+
readonly muted: "var(--global-muted)";
|
|
25
|
+
readonly background: "var(--global-background)";
|
|
26
|
+
readonly red: "var(--highlight-red)";
|
|
27
|
+
readonly green: "var(--highlight-green)";
|
|
28
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type ActivityRingDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream rings/activity-ring — full-circle move kcal ring. */
|
|
8
|
+
export declare function ActivityRingDemo({ value, min, max, label }: ActivityRingDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type AirQualityDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/air-quality — AQI half-dial with cutoff band + marks. */
|
|
8
|
+
export declare function AirQualityDemo({ value, min, max, label }: AirQualityDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type AnalogDialDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream needles/analog-dial — major/minor ticks, line needle; no track/arc. */
|
|
8
|
+
export declare function AnalogDialDemo({ value, min, max, label }: AnalogDialDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type BatteryDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream rings/battery — EV charge ring; limit notch via invisible zones. */
|
|
8
|
+
export declare function BatteryDemo({ value, min, max, label }: BatteryDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type ChronographDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream composed/chronograph — 60s sweep + 30m register inset above six. */
|
|
8
|
+
export declare function ChronographDemo({ value, min, max, label }: ChronographDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type ClockDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream needles/clock — 12h dial, hour + minute hands; no track/arc. */
|
|
8
|
+
export declare function ClockDemo({ value, min, max, label }: ClockDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type CompassDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream needles/compass — full bezel, compass needle, N/E/S/W labels. */
|
|
8
|
+
export declare function CompassDemo({ value, min, max, label }: CompassDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type DataUsageDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/data-usage — monthly data dial with value tooltip. */
|
|
8
|
+
export declare function DataUsageDemo({ value, min, max, label }: DataUsageDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type DimmerDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/dimmer — broad brightness sweep with grip dot. */
|
|
8
|
+
export declare function DimmerDemo({ value, min, max, label }: DimmerDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type FuelDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream needles/fuel — E/F dial, low-fuel zone, pointer needle; no track/arc. */
|
|
8
|
+
export declare function FuelDemo({ value, min, max, label }: FuelDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type HeartRateDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/heart-rate — zone-coloured arc + cutoff band. */
|
|
8
|
+
export declare function HeartRateDemo({ value, min, max, label }: HeartRateDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type InternetSpeedDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/internet-speed — thick primary arc, minor ticks, download readout. */
|
|
8
|
+
export declare function InternetSpeedDemo({ value, min, max, label }: InternetSpeedDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type NestedRingsDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
exercise?: number;
|
|
4
|
+
stand?: number;
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
label?: string;
|
|
8
|
+
};
|
|
9
|
+
/** Upstream composed/nested-rings — three concentric full-circle rings. */
|
|
10
|
+
export declare function NestedRingsDemo({ value, exercise, stand, min, max, label, }: NestedRingsDemoProps): import('react').JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type OrreryDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
earth?: number;
|
|
4
|
+
venus?: number;
|
|
5
|
+
mercury?: number;
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
label?: string;
|
|
9
|
+
};
|
|
10
|
+
/** Upstream composed/orrery — four orbits + sun hub; stub needle hidden under hub. */
|
|
11
|
+
export declare function OrreryDemo({ value, earth, venus, mercury, min, max, label, }: OrreryDemoProps): import('react').JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type PowerMeterDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream needles/power-meter — half dial about zero; out left, in right. */
|
|
8
|
+
export declare function PowerMeterDemo({ value, min, max, label }: PowerMeterDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type ProgressRingDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream rings/progress-ring — full circle primary fill with %. */
|
|
8
|
+
export declare function ProgressRingDemo({ value, min, max, label }: ProgressRingDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GaugeRange } from '..';
|
|
2
|
+
type RangeDemoProps = {
|
|
3
|
+
value?: GaugeRange;
|
|
4
|
+
min?: number;
|
|
5
|
+
max?: number;
|
|
6
|
+
label?: string;
|
|
7
|
+
};
|
|
8
|
+
/** Upstream arcs/range — comfort band with dots at both ends. */
|
|
9
|
+
export declare function RangeDemo({ value, min, max, label }: RangeDemoProps): import('react').JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type SaasMetricDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/saas-metric — half-ring conversion rate with % unit. */
|
|
8
|
+
export declare function SaasMetricDemo({ value, min, max, label }: SaasMetricDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type SegmentsDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/segments — tick-fill ring, no track/arc. */
|
|
8
|
+
export declare function SegmentsDemo({ value, min, max, label }: SegmentsDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type SimpleDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/simple — track + arc + large centered value. */
|
|
8
|
+
export declare function SimpleDemo({ value, min, max, label }: SimpleDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type SpeedFuelDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
fuel?: number;
|
|
6
|
+
label?: string;
|
|
7
|
+
};
|
|
8
|
+
/** Upstream composed/speed-fuel — speed dial + fuel inset in the bottom gap. */
|
|
9
|
+
export declare function SpeedFuelDemo({ value, min, max, fuel, label, }: SpeedFuelDemoProps): import('react').JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type SpeedometerDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream needles/speedometer — zones, ticks, pointer needle; no track/arc. */
|
|
8
|
+
export declare function SpeedometerDemo({ value, min, max, label }: SpeedometerDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type SprintDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream composed/sprint — empty host places four inset progress rings. */
|
|
8
|
+
export declare function SprintDemo({ value, min, max, label }: SprintDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type SunPathDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/sun-path — daylight half-arc with sun dot on the head. */
|
|
8
|
+
export declare function SunPathDemo({ value, min, max, label }: SunPathDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type SystemDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
mem?: number;
|
|
4
|
+
disk?: number;
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
label?: string;
|
|
8
|
+
};
|
|
9
|
+
/** Upstream composed/system — CPU half dial + MEM/DISK insets in lower half. */
|
|
10
|
+
export declare function SystemDemo({ value, mem, disk, min, max, label }: SystemDemoProps): import('react').JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type TachometerDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream needles/tachometer — redline zones, ticks, pointer needle; no track/arc. */
|
|
8
|
+
export declare function TachometerDemo({ value, min, max, label }: TachometerDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type TemperatureDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/temperature — zone-coloured arc, cutoff band, inward ticks + dot. */
|
|
8
|
+
export declare function TemperatureDemo({ value, min, max, label }: TemperatureDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type ThermostatDemoProps = {
|
|
2
|
+
value?: number;
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Upstream arcs/thermostat — segmented heating band with handle dot. */
|
|
8
|
+
export declare function ThermostatDemo({ value, min, max, label }: ThermostatDemoProps): import('react').JSX.Element;
|
|
9
|
+
export {};
|