@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.
Files changed (127) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +8 -0
  2. package/dist/catalog.json +12 -0
  3. package/dist/components/avatar/avatar.d.ts +6 -0
  4. package/dist/components/avatar/avatar.js +2 -2
  5. package/dist/components/badge/badge.css +1 -1
  6. package/dist/components/button/button.css +1 -1
  7. package/dist/components/dialog/dialog-sheet.d.ts +1 -1
  8. package/dist/components/gauge/arcs.d.ts +134 -0
  9. package/dist/components/gauge/arcs.js +145 -0
  10. package/dist/components/gauge/context.d.ts +134 -0
  11. package/dist/components/gauge/context.js +83 -0
  12. package/dist/components/gauge/control.d.ts +107 -0
  13. package/dist/components/gauge/control.js +223 -0
  14. package/dist/components/gauge/demos/_shared.d.ts +28 -0
  15. package/dist/components/gauge/demos/activity-ring.d.ts +9 -0
  16. package/dist/components/gauge/demos/air-quality.d.ts +9 -0
  17. package/dist/components/gauge/demos/analog-dial.d.ts +9 -0
  18. package/dist/components/gauge/demos/battery.d.ts +9 -0
  19. package/dist/components/gauge/demos/chronograph.d.ts +9 -0
  20. package/dist/components/gauge/demos/clock.d.ts +9 -0
  21. package/dist/components/gauge/demos/compass.d.ts +9 -0
  22. package/dist/components/gauge/demos/data-usage.d.ts +9 -0
  23. package/dist/components/gauge/demos/dimmer.d.ts +9 -0
  24. package/dist/components/gauge/demos/fuel.d.ts +9 -0
  25. package/dist/components/gauge/demos/heart-rate.d.ts +9 -0
  26. package/dist/components/gauge/demos/internet-speed.d.ts +9 -0
  27. package/dist/components/gauge/demos/nested-rings.d.ts +11 -0
  28. package/dist/components/gauge/demos/orrery.d.ts +12 -0
  29. package/dist/components/gauge/demos/power-meter.d.ts +9 -0
  30. package/dist/components/gauge/demos/progress-ring.d.ts +9 -0
  31. package/dist/components/gauge/demos/range.d.ts +10 -0
  32. package/dist/components/gauge/demos/saas-metric.d.ts +9 -0
  33. package/dist/components/gauge/demos/segments.d.ts +9 -0
  34. package/dist/components/gauge/demos/simple.d.ts +9 -0
  35. package/dist/components/gauge/demos/speed-fuel.d.ts +10 -0
  36. package/dist/components/gauge/demos/speedometer.d.ts +9 -0
  37. package/dist/components/gauge/demos/sprint.d.ts +9 -0
  38. package/dist/components/gauge/demos/sun-path.d.ts +9 -0
  39. package/dist/components/gauge/demos/system.d.ts +11 -0
  40. package/dist/components/gauge/demos/tachometer.d.ts +9 -0
  41. package/dist/components/gauge/demos/temperature.d.ts +9 -0
  42. package/dist/components/gauge/demos/thermostat.d.ts +9 -0
  43. package/dist/components/gauge/demos/timer.d.ts +9 -0
  44. package/dist/components/gauge/demos/volume.d.ts +10 -0
  45. package/dist/components/gauge/demos/wind.d.ts +9 -0
  46. package/dist/components/gauge/dot.d.ts +55 -0
  47. package/dist/components/gauge/dot.js +34 -0
  48. package/dist/components/gauge/gauge.css +1 -0
  49. package/dist/components/gauge/gauge.d.ts +84 -0
  50. package/dist/components/gauge/gauge.js +62 -0
  51. package/dist/components/gauge/gauge.module.js +24 -0
  52. package/dist/components/gauge/index.d.ts +15 -0
  53. package/dist/components/gauge/inset.d.ts +30 -0
  54. package/dist/components/gauge/inset.js +39 -0
  55. package/dist/components/gauge/math.d.ts +69 -0
  56. package/dist/components/gauge/math.js +135 -0
  57. package/dist/components/gauge/needle.d.ts +81 -0
  58. package/dist/components/gauge/needle.js +162 -0
  59. package/dist/components/gauge/scale.d.ts +44 -0
  60. package/dist/components/gauge/scale.js +21 -0
  61. package/dist/components/gauge/text.d.ts +79 -0
  62. package/dist/components/gauge/text.js +42 -0
  63. package/dist/components/gauge/ticks.d.ts +169 -0
  64. package/dist/components/gauge/ticks.js +124 -0
  65. package/dist/components/gauge/tooltip.d.ts +117 -0
  66. package/dist/components/gauge/tooltip.js +337 -0
  67. package/dist/components/gauge/transition.d.ts +60 -0
  68. package/dist/components/gauge/transition.js +129 -0
  69. package/dist/components/gauge/use-animated-value.d.ts +14 -0
  70. package/dist/components/gauge/use-animated-value.js +111 -0
  71. package/dist/components/gauge/utils.d.ts +51 -0
  72. package/dist/components/gauge/utils.js +80 -0
  73. package/dist/components/icon-meter/icon-meter.css +1 -0
  74. package/dist/components/icon-meter/icon-meter.d.ts +62 -0
  75. package/dist/components/icon-meter/icon-meter.js +105 -0
  76. package/dist/components/icon-meter/icon-meter.module.js +11 -0
  77. package/dist/components/icon-meter/index.d.ts +2 -0
  78. package/dist/components/icon-meter/utils.d.ts +22 -0
  79. package/dist/components/icon-meter/utils.js +40 -0
  80. package/dist/components/index.d.ts +2 -0
  81. package/dist/components/popover/popover-sheet.d.ts +1 -2
  82. package/dist/components/stack/stack.d.ts +9 -2
  83. package/dist/components/tabs/tabs.d.ts +1 -2
  84. package/dist/index.js +17 -1
  85. package/dist/internal/chrome-icons/chrome-icons.d.ts +4 -0
  86. package/dist/internal/chrome-icons/chrome-icons.js +12 -4
  87. 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
  88. 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
  89. package/dist/node_modules/.pnpm/react-dom@19.3.0_react@19.3.0/node_modules/react-dom/index.js +22 -0
  90. package/dist/preflight.css +1 -1
  91. package/dist/specs/components/avatar/props.xml +3 -0
  92. package/dist/specs/components/avatar/usage.xml +1 -0
  93. package/dist/specs/components/badge/a11y.xml +1 -1
  94. package/dist/specs/components/button/props.xml +2 -2
  95. package/dist/specs/components/button/usage.xml +1 -1
  96. package/dist/specs/components/gauge/a11y.xml +8 -0
  97. package/dist/specs/components/gauge/meta.xml +38 -0
  98. package/dist/specs/components/gauge/patterns.xml +1158 -0
  99. package/dist/specs/components/gauge/props.xml +452 -0
  100. package/dist/specs/components/gauge/usage.xml +21 -0
  101. package/dist/specs/components/icon-button/props.xml +2 -2
  102. package/dist/specs/components/icon-button/usage.xml +1 -1
  103. package/dist/specs/components/icon-meter/a11y.xml +9 -0
  104. package/dist/specs/components/icon-meter/meta.xml +21 -0
  105. package/dist/specs/components/icon-meter/patterns.xml +23 -0
  106. package/dist/specs/components/icon-meter/props.xml +44 -0
  107. package/dist/specs/components/icon-meter/usage.xml +13 -0
  108. package/dist/specs/components/linear-progress/usage.xml +1 -0
  109. package/dist/specs/components/meter/meta.xml +1 -0
  110. package/dist/specs/components/meter/props.xml +1 -0
  111. package/dist/specs/components/meter/usage.xml +1 -0
  112. package/dist/specs/components/stack/patterns.xml +21 -21
  113. package/dist/specs/components/stack/props.xml +6 -6
  114. package/dist/specs/components/stack/usage.xml +4 -2
  115. package/dist/specs/components/text/patterns.xml +1 -1
  116. package/dist/specs/components/text/usage.xml +1 -1
  117. package/dist/specs/components/toggle-button/props.xml +1 -1
  118. package/dist/specs/components/toggle-button/usage.xml +1 -1
  119. package/dist/specs/components/toggle-text-button/props.xml +1 -1
  120. package/dist/specs/foundation/attributes.xml +3 -3
  121. package/dist/specs/foundation/modules.xml +1 -1
  122. package/dist/specs/foundation/theme-topics.xml +7 -2
  123. package/dist/specs/index.xml +21 -1
  124. package/dist/specs/patterns/compose-layout-first.xml +1 -1
  125. package/dist/specs/patterns/settings-panel.xml +1 -1
  126. package/dist/specs/patterns/settings-row.xml +1 -1
  127. package/package.json +2 -2
@@ -0,0 +1,9 @@
1
+ type TimerDemoProps = {
2
+ value?: number;
3
+ min?: number;
4
+ max?: number;
5
+ label?: string;
6
+ };
7
+ /** Upstream rings/timer — 60s ring, major/minor ticks, mono sec readout. */
8
+ export declare function TimerDemo({ value, min, max, label }: TimerDemoProps): import('react').JSX.Element;
9
+ export {};
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ type VolumeDemoProps = {
3
+ value?: number;
4
+ min?: number;
5
+ max?: number;
6
+ label?: string;
7
+ };
8
+ /** Upstream arcs/volume — knob face, thin outer scale, grip dot. */
9
+ export declare function VolumeDemo({ value: valueProp, min, max, label }: VolumeDemoProps): React.JSX.Element;
10
+ export {};
@@ -0,0 +1,9 @@
1
+ type WindDemoProps = {
2
+ value?: number;
3
+ min?: number;
4
+ max?: number;
5
+ label?: string;
6
+ };
7
+ /** Upstream needles/wind — arrow vane, compass ticks; fixed speed in hub gap. */
8
+ export declare function WindDemo({ value, min, max, label }: WindDemoProps): import('react').JSX.Element;
9
+ export {};
@@ -0,0 +1,55 @@
1
+ import { GaugeEnd } from './utils';
2
+ import * as React from 'react';
3
+ export type GaugeDotProps = {
4
+ /**
5
+ * Radius of the dot itself, in SVG units.
6
+ * @defaultValue 10
7
+ */
8
+ radius?: number;
9
+ /**
10
+ * Fill colour. Unset uses theme primary.
11
+ * @defaultValue `var(--global-primary)`
12
+ */
13
+ color?: string;
14
+ /**
15
+ * Fill opacity for the dot and optional halo.
16
+ * @defaultValue 1
17
+ */
18
+ opacity?: number;
19
+ /**
20
+ * Offset of the dot's centre from the scale's reference line.
21
+ * @defaultValue 0
22
+ */
23
+ offset?: number;
24
+ /**
25
+ * Sweeps of the scale the dot makes across the domain, as
26
+ * `GaugeNeedle.turns`: two sends it round twice while the value crosses
27
+ * the domain once.
28
+ * @defaultValue 1
29
+ */
30
+ turns?: number;
31
+ /**
32
+ * Width of a ring drawn behind the dot in `haloColor`, so it stands off
33
+ * whatever band it rides. 0 leaves the dot bare.
34
+ * @defaultValue 0
35
+ */
36
+ halo?: number;
37
+ /**
38
+ * Colour of the halo: the surface under the gauge, usually.
39
+ * @defaultValue `var(--global-background)`
40
+ */
41
+ haloColor?: string;
42
+ /**
43
+ * Which end of a range the dot rides. Two dots, one at each end, make
44
+ * the handles of a range.
45
+ * @defaultValue `'to'`
46
+ */
47
+ end?: GaugeEnd;
48
+ };
49
+ /**
50
+ * A disc riding the scale at the current value: the head of a progress ring,
51
+ * a body on its orbit, the handle on a dial or a slider. `GaugeMarks` stands at fixed values
52
+ * and points along the radius; this follows the value the way a needle does,
53
+ * and is round at any size a stroke cap could not reach.
54
+ */
55
+ export declare const GaugeDot: React.FC<GaugeDotProps>;
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import { valueToTurnedAngle } from "./math.js";
3
+ import { useGauge } from "./context.js";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import "react";
6
+ //#region src/components/gauge/dot.tsx
7
+ var PRIMARY = "var(--global-primary)";
8
+ var BACKGROUND = "var(--global-background)";
9
+ /**
10
+ * A disc riding the scale at the current value: the head of a progress ring,
11
+ * a body on its orbit, the handle on a dial or a slider. `GaugeMarks` stands at fixed values
12
+ * and points along the radius; this follows the value the way a needle does,
13
+ * and is round at any size a stroke cap could not reach.
14
+ */
15
+ var GaugeDot = ({ radius = 10, color = PRIMARY, opacity = 1, offset = 0, turns = 1, halo = 0, haloColor = BACKGROUND, end = "to" }) => {
16
+ const gauge = useGauge();
17
+ const position = valueToTurnedAngle(end === "from" ? gauge.from : gauge.value, gauge.min, gauge.max, gauge.scale.start, gauge.scale.end, turns);
18
+ const { x, y } = gauge.scale.point(position, offset);
19
+ return /* @__PURE__ */ jsxs(Fragment, { children: [halo > 0 && /* @__PURE__ */ jsx("circle", {
20
+ cx: x,
21
+ cy: y,
22
+ r: radius + halo,
23
+ fill: haloColor,
24
+ fillOpacity: opacity
25
+ }), /* @__PURE__ */ jsx("circle", {
26
+ cx: x,
27
+ cy: y,
28
+ r: radius,
29
+ fill: color,
30
+ fillOpacity: opacity
31
+ })] });
32
+ };
33
+ //#endregion
34
+ export { GaugeDot };
@@ -0,0 +1 @@
1
+ @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-gauge-aspect-ratio{syntax:"*";inherits:false;initial-value:1}.viraui__gauge-module__Gauge_XrCKK{overflow:visible;color:var(--global-foreground);&[data-fit=square]{inline-size:100%;block-size:100%}&[data-fit=content]{inline-size:100%;max-block-size:100%;aspect-ratio:var(--vui-gauge-aspect-ratio)}}.viraui__gauge-module__Control_33uqc{position:relative;touch-action:none;-webkit-user-select:none;user-select:none;outline:none;cursor:grab;aspect-ratio:1;border-radius:var(--radius-full);&[data-disabled=true]{cursor:default}&:not([data-disabled=true]):active{cursor:grabbing}&:focus-visible,&:has(:focus-visible:not([data-pointer])){outline:var(--outline);outline-offset:var(--outline-offset)}}.viraui__gauge-module__VisuallyHidden_LUbhj{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;&:focus-visible{outline:none}}.viraui__gauge-module__TooltipPositioner_5wZsF{position:absolute;inset-block-start:0;inset-inline-start:0;z-index:50;pointer-events:none}.viraui__gauge-module__Tooltip_BRUR6{box-sizing:border-box;inline-size:max-content;max-inline-size:20rem;padding-block:var(--space-2xs);padding-inline:var(--space-s);border-radius:var(--radius-m);background:var(--global-foreground);color:var(--global-background);font-size:var(--font-scale-body-s);animation:viraui__gauge-module__gauge-tooltip-in_5JTLs var(--duration-fast) var(--easing-entrance);@media (prefers-reduced-motion:reduce){animation:none}}.viraui__gauge-module__TooltipBody_44-M9{display:flex;flex-direction:column;align-items:center;line-height:1.15}.viraui__gauge-module__TooltipLabel_T-Hp5{opacity:.7}.viraui__gauge-module__TooltipValue_gAqRL{font-size:var(--font-scale-body-m);font-weight:600;font-variation-settings:"wght" 600;font-variant-numeric:tabular-nums}.viraui__gauge-module__TooltipUnit_iIW0i{margin-inline-start:var(--space-2xs);font-size:var(--font-scale-body-s);font-weight:500;font-variation-settings:"wght" 500;opacity:.7}@keyframes viraui__gauge-module__gauge-tooltip-in_5JTLs{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}}
@@ -0,0 +1,84 @@
1
+ import { GaugeDomainProps, GaugeRange } from './context';
2
+ import { GaugeTransition } from './transition';
3
+ import * as React from 'react';
4
+ /** See `GaugeProps.fit`. */
5
+ export type GaugeFit = 'square' | 'content';
6
+ export type GaugeProps = Omit<React.ComponentPropsWithRef<'svg'>, 'viewBox'> & GaugeDomainProps & {
7
+ /**
8
+ * Extra room around the reference circle for thick strokes, ticks and labels.
9
+ * @defaultValue 48
10
+ */
11
+ padding?: number;
12
+ /**
13
+ * How the SVG box is sized. `square` boxes the whole circle, so a half gauge
14
+ * reserves the room a full one would. `content` fits the box to the arc's own
15
+ * sweep and sets a matching aspect-ratio via `--vui-gauge-aspect-ratio`, so the
16
+ * dial fills the width it is given. `padding` is still what makes room for ticks,
17
+ * labels and value text, since those are drawn by children the root cannot measure.
18
+ * @defaultValue 'square'
19
+ */
20
+ fit?: GaugeFit;
21
+ /**
22
+ * Accessible name for the meter reading. When omitted, pass `aria-label`
23
+ * (or another naming technique) on the host SVG.
24
+ * @defaultValue undefined — no `aria-label` from this prop
25
+ */
26
+ label?: string;
27
+ /**
28
+ * The reading, or a `[from, to]` range to fill between.
29
+ * @defaultValue Required — no default.
30
+ */
31
+ value: number | GaugeRange;
32
+ /**
33
+ * Lower bound of the domain.
34
+ * @defaultValue 0
35
+ */
36
+ min?: number;
37
+ /**
38
+ * Upper bound of the domain.
39
+ * @defaultValue 100
40
+ */
41
+ max?: number;
42
+ /**
43
+ * Animate towards new values. `true` uses a gentle spring; pass a
44
+ * `GaugeTransition` to tune it or switch to a timed tween.
45
+ * @defaultValue undefined — instant updates
46
+ */
47
+ transition?: GaugeTransition | boolean;
48
+ /**
49
+ * Where the value starts on mount when animating.
50
+ * @defaultValue undefined — starts at the target value
51
+ */
52
+ initialValue?: number | GaugeRange;
53
+ /**
54
+ * Treat the domain as circular (shortest-path animation across the seam).
55
+ * @defaultValue false
56
+ */
57
+ wrap?: boolean;
58
+ /**
59
+ * Gauge degrees, clockwise from six o'clock — sweep start.
60
+ * @defaultValue 40
61
+ */
62
+ startAngle?: number;
63
+ /**
64
+ * Gauge degrees, clockwise from six o'clock — sweep end.
65
+ * @defaultValue 320
66
+ */
67
+ endAngle?: number;
68
+ /**
69
+ * Reference radius in SVG units.
70
+ * @defaultValue 200
71
+ */
72
+ radius?: number;
73
+ /**
74
+ * Turn the whole scale this many degrees clockwise.
75
+ * @defaultValue 0
76
+ */
77
+ rotate?: number;
78
+ };
79
+ /**
80
+ * Root of a composable gauge. Renders an SVG centred on the origin and
81
+ * publishes the value, domain and geometry to any primitive rendered inside.
82
+ * Exposes APG meter semantics on the host; decorative children have no roles.
83
+ */
84
+ export declare const Gauge: React.FC<GaugeProps>;
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import './gauge.css';
3
+ import { clsx } from "../../core/clsx.js";
4
+ import { arcBox } from "./math.js";
5
+ import { GaugeContext, useGaugeContextValue } from "./context.js";
6
+ import gauge_module_default from "./gauge.module.js";
7
+ import { jsx } from "react/jsx-runtime";
8
+ import "react";
9
+ //#region src/components/gauge/gauge.tsx
10
+ /**
11
+ * Root of a composable gauge. Renders an SVG centred on the origin and
12
+ * publishes the value, domain and geometry to any primitive rendered inside.
13
+ * Exposes APG meter semantics on the host; decorative children have no roles.
14
+ */
15
+ var Gauge = ({ value, min, max, startAngle, endAngle, radius, transition, initialValue, wrap, rotate, padding = 48, fit = "square", label, className, style, children, ...otherProps }) => {
16
+ const gauge = useGaugeContextValue({
17
+ value,
18
+ min,
19
+ max,
20
+ startAngle,
21
+ endAngle,
22
+ radius,
23
+ transition,
24
+ initialValue,
25
+ wrap,
26
+ rotate
27
+ });
28
+ const half = gauge.radius + padding;
29
+ const box = fit === "content" ? arcBox(gauge.radius, gauge.startAngle, gauge.endAngle, padding) : {
30
+ x: -half,
31
+ y: -half,
32
+ width: 2 * half,
33
+ height: 2 * half
34
+ };
35
+ const dynamicStyle = {
36
+ ...style,
37
+ ...fit === "content" && { "--vui-gauge-aspect-ratio": `${box.width} / ${box.height}` }
38
+ };
39
+ const meterProps = otherProps["aria-hidden"] === true || otherProps["aria-hidden"] === "true" ? {} : {
40
+ role: "meter",
41
+ ...label != null ? { "aria-label": label } : {},
42
+ "aria-valuemin": gauge.min,
43
+ "aria-valuemax": gauge.max,
44
+ "aria-valuenow": gauge.target,
45
+ ...gauge.range ? { "aria-valuetext": `${gauge.targetFrom} to ${gauge.target}` } : {}
46
+ };
47
+ return /* @__PURE__ */ jsx(GaugeContext.Provider, {
48
+ value: gauge,
49
+ children: /* @__PURE__ */ jsx("svg", {
50
+ ...otherProps,
51
+ viewBox: `${box.x} ${box.y} ${box.width} ${box.height}`,
52
+ preserveAspectRatio: "xMidYMid meet",
53
+ ...meterProps,
54
+ className: clsx(gauge_module_default.Gauge, className),
55
+ "data-fit": fit,
56
+ style: dynamicStyle,
57
+ children
58
+ })
59
+ });
60
+ };
61
+ //#endregion
62
+ export { Gauge };
@@ -0,0 +1,24 @@
1
+ //#region src/components/gauge/gauge.module.css
2
+ var Gauge = "viraui__gauge-module__Gauge_XrCKK";
3
+ var Control = "viraui__gauge-module__Control_33uqc";
4
+ var VisuallyHidden = "viraui__gauge-module__VisuallyHidden_LUbhj";
5
+ var TooltipPositioner = "viraui__gauge-module__TooltipPositioner_5wZsF";
6
+ var Tooltip = "viraui__gauge-module__Tooltip_BRUR6";
7
+ var TooltipBody = "viraui__gauge-module__TooltipBody_44-M9";
8
+ var TooltipLabel = "viraui__gauge-module__TooltipLabel_T-Hp5";
9
+ var TooltipValue = "viraui__gauge-module__TooltipValue_gAqRL";
10
+ var TooltipUnit = "viraui__gauge-module__TooltipUnit_iIW0i";
11
+ var gauge_module_default = {
12
+ Gauge,
13
+ Control,
14
+ VisuallyHidden,
15
+ TooltipPositioner,
16
+ Tooltip,
17
+ "gauge-tooltip-in": "viraui__gauge-module__gauge-tooltip-in_5JTLs",
18
+ TooltipBody,
19
+ TooltipLabel,
20
+ TooltipValue,
21
+ TooltipUnit
22
+ };
23
+ //#endregion
24
+ export { Control, Gauge, Tooltip, TooltipBody, TooltipLabel, TooltipPositioner, TooltipUnit, TooltipValue, VisuallyHidden, gauge_module_default as default };
@@ -0,0 +1,15 @@
1
+ export { Gauge, type GaugeFit, type GaugeProps } from './gauge';
2
+ export { GaugeInset, type GaugeInsetProps } from './inset';
3
+ export { useGauge, useRoundGauge, type GaugeContextValue, type GaugeDomainProps, type GaugeRange, type GaugeReading, type GaugeReadingProps, type GaugeRoundShape, } from './context';
4
+ export { arcScale, type GaugeBox, type GaugePoint, type GaugeScale } from './scale';
5
+ export { GaugeTrack, GaugeArc, GaugeStack, GaugeZones, type GaugeArcProps, type GaugeStackPart, type GaugeStackProps, type GaugeZonesProps, } from './arcs';
6
+ export { GaugeControl, type GaugeControlProps } from './control';
7
+ export { GaugeTicks, GaugeTickFill, GaugeMarks, GaugeTickLabels, type GaugeTicksProps, type GaugeTickFillProps, type GaugeMarksProps, type GaugeTickLabelsProps, } from './ticks';
8
+ export { GaugeText, GaugeValue, type GaugeTextProps, type GaugeValueProps } from './text';
9
+ export { GaugeDot, type GaugeDotProps } from './dot';
10
+ export { GaugeTooltip, type GaugeTooltipPosition, type GaugeTooltipProps, type GaugeTooltipSide } from './tooltip';
11
+ export { GaugeNeedle, GaugeHub, type GaugeNeedleProps, type GaugeHubProps } from './needle';
12
+ export { angleToValue, arcBox, arcPath, clamp, cutValues, degreesToRadians, foldValue, polar, stepValues, valueToAngle, valueToTurnedAngle, } from './math';
13
+ export { clockLabel, clockTime, compassLabel, durationLabel, fadeColor, fontFamily, fontWeight, zoneColor, zoneCutoffs, type FontFamily, type FontWeight, type GaugeEnd, type NeedleStyle, type StrokeCap, type TextAnchor, type ValueColor, type Zone, } from './utils';
14
+ export { DEFAULT_TRANSITION, cubicBezier, easingFunction, resolveTransition, springPhysics, stepSpring, type GaugeEasing, type GaugeSpringTransition, type GaugeTransition, type GaugeTweenTransition, } from './transition';
15
+ export { useAnimatedValue } from './use-animated-value';
@@ -0,0 +1,30 @@
1
+ import { GaugeDomainProps } from './context';
2
+ import * as React from 'react';
3
+ export type GaugeInsetProps = Omit<React.ComponentPropsWithRef<'g'>, 'transform'> & GaugeDomainProps & {
4
+ /**
5
+ * Centre of the inset in the host gauge's SVG units. Positive y is down.
6
+ * @defaultValue 0
7
+ */
8
+ x?: number;
9
+ /**
10
+ * Centre of the inset in the host gauge's SVG units. Positive y is down.
11
+ * @defaultValue 0
12
+ */
13
+ y?: number;
14
+ /**
15
+ * Size relative to the host gauge: 0.3 draws it at a third of the size.
16
+ * @defaultValue 1
17
+ */
18
+ scale?: number;
19
+ };
20
+ /**
21
+ * A whole gauge drawn inside another one: a fuel dial under a speedometer, a
22
+ * second ring inside the first. It takes its own value and domain and sets up
23
+ * the same context `Gauge` does, so every primitive works inside it unchanged.
24
+ *
25
+ * It draws in the host's coordinate system rather than its own viewport, so it
26
+ * needs no `padding` or `fit`; `x`, `y` and `scale` place it, and everything
27
+ * inside — strokes, ticks, text — shrinks with it. Its reference radius stays
28
+ * the host's by default, which makes `scale` the only size to reason about.
29
+ */
30
+ export declare const GaugeInset: React.FC<GaugeInsetProps>;
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { GaugeContext, useGaugeContextValue } from "./context.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import "react";
5
+ //#region src/components/gauge/inset.tsx
6
+ /**
7
+ * A whole gauge drawn inside another one: a fuel dial under a speedometer, a
8
+ * second ring inside the first. It takes its own value and domain and sets up
9
+ * the same context `Gauge` does, so every primitive works inside it unchanged.
10
+ *
11
+ * It draws in the host's coordinate system rather than its own viewport, so it
12
+ * needs no `padding` or `fit`; `x`, `y` and `scale` place it, and everything
13
+ * inside — strokes, ticks, text — shrinks with it. Its reference radius stays
14
+ * the host's by default, which makes `scale` the only size to reason about.
15
+ */
16
+ var GaugeInset = ({ value, min, max, startAngle, endAngle, radius, transition, initialValue, wrap, rotate, x = 0, y = 0, scale = 1, children, ...otherProps }) => {
17
+ const gauge = useGaugeContextValue({
18
+ value,
19
+ min,
20
+ max,
21
+ startAngle,
22
+ endAngle,
23
+ radius,
24
+ transition,
25
+ initialValue,
26
+ wrap,
27
+ rotate
28
+ });
29
+ return /* @__PURE__ */ jsx(GaugeContext.Provider, {
30
+ value: gauge,
31
+ children: /* @__PURE__ */ jsx("g", {
32
+ transform: `translate(${x} ${y}) scale(${scale})`,
33
+ ...otherProps,
34
+ children
35
+ })
36
+ });
37
+ };
38
+ //#endregion
39
+ export { GaugeInset };
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Pure geometry for the gauge primitives.
3
+ *
4
+ * Angles are "gauge degrees": 0 points straight down (six o'clock) and
5
+ * values increase clockwise, so a sweep from 40° to 320° leaves an opening
6
+ * at the bottom. Coordinates are SVG units centred on the gauge origin.
7
+ */
8
+ export declare const clamp: (value: number, min: number, max: number) => number;
9
+ /**
10
+ * Fraction digits needed to write `n` in decimal without scientific notation
11
+ * padding. Used to clean binary float noise after step maths without coarsening
12
+ * a finer `step` (or a fractional bound) than a fixed `toFixed(2)` would.
13
+ */
14
+ export declare const fractionDigits: (n: number) => number;
15
+ /**
16
+ * A value folded back inside [min, max) modulo the span, as on a closed ring:
17
+ * 370° on a compass reads as 10°, and 25 o'clock as 1.
18
+ */
19
+ export declare const foldValue: (value: number, min: number, max: number) => number;
20
+ export declare const degreesToRadians: (degrees: number) => number;
21
+ /**
22
+ * Point on a circle of `radius` at a gauge angle. Coordinates are rounded so
23
+ * server and client render identical attributes and hydration stays clean.
24
+ */
25
+ export declare const polar: (radius: number, angle: number) => {
26
+ x: number;
27
+ y: number;
28
+ };
29
+ /** Linear map of a value in [min, max] onto the arc [startAngle, endAngle]. */
30
+ export declare const valueToAngle: (value: number, min: number, max: number, startAngle: number, endAngle: number) => number;
31
+ /**
32
+ * Angle for a value that wraps the arc more than once. A single turn maps the
33
+ * domain onto the sweep exactly as `valueToAngle` does; past that each turn
34
+ * runs the sweep again from its start, which is how a clock's minute hand
35
+ * gets round twelve times while the hour hand goes round once.
36
+ */
37
+ export declare const valueToTurnedAngle: (value: number, min: number, max: number, startAngle: number, endAngle: number, turns: number) => number;
38
+ /**
39
+ * SVG path for an arc of `radius` from `from` to `to` gauge degrees. Sweeps
40
+ * over 180° are split so a single `A` command never has to disambiguate a
41
+ * large arc, which also makes a full 360° circle render correctly.
42
+ */
43
+ export declare const arcPath: (radius: number, from: number, to: number) => string;
44
+ /**
45
+ * Tight bounding box of an arc sweep, inflated by `padding`. Takes the two
46
+ * endpoints, every quarter turn the sweep crosses, and the origin, so a gauge
47
+ * that pivots a needle keeps its hub inside the box. A sweep that closes on
48
+ * itself crosses all four quarters and lands back on the full square.
49
+ */
50
+ export declare const arcBox: (radius: number, from: number, to: number, padding?: number) => {
51
+ x: number;
52
+ y: number;
53
+ width: number;
54
+ height: number;
55
+ };
56
+ /** Evenly spaced values across the domain, inclusive of both ends. */
57
+ export declare const stepValues: (min: number, max: number, intervals: number) => number[];
58
+ /**
59
+ * The cutoffs that split the domain into `segments` equal parts: the values
60
+ * between the segments, none at the two ends. Ten glasses of water make nine
61
+ * cuts.
62
+ */
63
+ export declare const cutValues: (min: number, max: number, segments: number) => number[];
64
+ /**
65
+ * Inverse of `valueToAngle`: the domain value under a gauge angle. An angle
66
+ * in the opening outside the sweep goes to whichever end is nearer, so a
67
+ * pointer dragged past an end holds there rather than jumping to the other.
68
+ */
69
+ export declare const angleToValue: (angle: number, min: number, max: number, startAngle: number, endAngle: number) => number;
@@ -0,0 +1,135 @@
1
+ //#region src/components/gauge/math.ts
2
+ /**
3
+ * Pure geometry for the gauge primitives.
4
+ *
5
+ * Angles are "gauge degrees": 0 points straight down (six o'clock) and
6
+ * values increase clockwise, so a sweep from 40° to 320° leaves an opening
7
+ * at the bottom. Coordinates are SVG units centred on the gauge origin.
8
+ */
9
+ var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
10
+ /**
11
+ * Fraction digits needed to write `n` in decimal without scientific notation
12
+ * padding. Used to clean binary float noise after step maths without coarsening
13
+ * a finer `step` (or a fractional bound) than a fixed `toFixed(2)` would.
14
+ */
15
+ var fractionDigits = (n) => {
16
+ if (!Number.isFinite(n)) return 0;
17
+ const s = Math.abs(n).toString().toLowerCase();
18
+ if (s.includes("e")) {
19
+ const [coeff = "0", exp = "0"] = s.split("e");
20
+ return Math.max(0, (coeff.split(".")[1] ?? "").length - Number(exp));
21
+ }
22
+ const dot = s.indexOf(".");
23
+ return dot === -1 ? 0 : s.length - dot - 1;
24
+ };
25
+ /**
26
+ * A value folded back inside [min, max) modulo the span, as on a closed ring:
27
+ * 370° on a compass reads as 10°, and 25 o'clock as 1.
28
+ */
29
+ var foldValue = (value, min, max) => {
30
+ const lo = Math.min(min, max);
31
+ const span = Math.abs(max - min);
32
+ return span === 0 ? lo : lo + ((value - lo) % span + span) % span;
33
+ };
34
+ var degreesToRadians = (degrees) => degrees * Math.PI / 180;
35
+ var round = (n) => Math.round(n * 1e3) / 1e3;
36
+ /**
37
+ * Point on a circle of `radius` at a gauge angle. Coordinates are rounded so
38
+ * server and client render identical attributes and hydration stays clean.
39
+ */
40
+ var polar = (radius, angle) => {
41
+ const theta = degreesToRadians(angle + 90);
42
+ return {
43
+ x: round(radius * Math.cos(theta)),
44
+ y: round(radius * Math.sin(theta))
45
+ };
46
+ };
47
+ /** Linear map of a value in [min, max] onto the arc [startAngle, endAngle]. */
48
+ var valueToAngle = (value, min, max, startAngle, endAngle) => {
49
+ const span = max - min;
50
+ return startAngle + (span === 0 ? 0 : (clamp(value, min, max) - min) / span) * (endAngle - startAngle);
51
+ };
52
+ /**
53
+ * Angle for a value that wraps the arc more than once. A single turn maps the
54
+ * domain onto the sweep exactly as `valueToAngle` does; past that each turn
55
+ * runs the sweep again from its start, which is how a clock's minute hand
56
+ * gets round twelve times while the hour hand goes round once.
57
+ */
58
+ var valueToTurnedAngle = (value, min, max, startAngle, endAngle, turns) => {
59
+ if (turns === 1) return valueToAngle(value, min, max, startAngle, endAngle);
60
+ const span = max - min;
61
+ return startAngle + (span === 0 ? 0 : (value - min) / span) * turns % 1 * (endAngle - startAngle);
62
+ };
63
+ var fmt = (n) => Number(n.toFixed(3)).toString();
64
+ /**
65
+ * SVG path for an arc of `radius` from `from` to `to` gauge degrees. Sweeps
66
+ * over 180° are split so a single `A` command never has to disambiguate a
67
+ * large arc, which also makes a full 360° circle render correctly.
68
+ */
69
+ var arcPath = (radius, from, to) => {
70
+ const sweep = Math.min(to - from, 360);
71
+ if (sweep <= 0 || radius <= 0) return "";
72
+ const pieces = Math.max(1, Math.ceil(sweep / 180));
73
+ const step = sweep / pieces;
74
+ const start = polar(radius, from);
75
+ const parts = [`M ${fmt(start.x)} ${fmt(start.y)}`];
76
+ for (let i = 1; i <= pieces; i += 1) {
77
+ const p = polar(radius, from + step * i);
78
+ parts.push(`A ${fmt(radius)} ${fmt(radius)} 0 0 1 ${fmt(p.x)} ${fmt(p.y)}`);
79
+ }
80
+ return parts.join(" ");
81
+ };
82
+ /**
83
+ * Tight bounding box of an arc sweep, inflated by `padding`. Takes the two
84
+ * endpoints, every quarter turn the sweep crosses, and the origin, so a gauge
85
+ * that pivots a needle keeps its hub inside the box. A sweep that closes on
86
+ * itself crosses all four quarters and lands back on the full square.
87
+ */
88
+ var arcBox = (radius, from, to, padding = 0) => {
89
+ const end = from + clamp(to - from, 0, 360);
90
+ const points = [
91
+ {
92
+ x: 0,
93
+ y: 0
94
+ },
95
+ polar(radius, from),
96
+ polar(radius, end)
97
+ ];
98
+ for (let a = Math.ceil(from / 90) * 90; a <= end; a += 90) points.push(polar(radius, a));
99
+ const xs = points.map((p) => p.x);
100
+ const ys = points.map((p) => p.y);
101
+ const x = round(Math.min(...xs) - padding);
102
+ const y = round(Math.min(...ys) - padding);
103
+ return {
104
+ x,
105
+ y,
106
+ width: round(Math.max(...xs) + padding - x),
107
+ height: round(Math.max(...ys) + padding - y)
108
+ };
109
+ };
110
+ /** Evenly spaced values across the domain, inclusive of both ends. */
111
+ var stepValues = (min, max, intervals) => {
112
+ const n = Math.max(1, Math.round(intervals));
113
+ return Array.from({ length: n + 1 }, (_, i) => min + (max - min) * i / n);
114
+ };
115
+ /**
116
+ * The cutoffs that split the domain into `segments` equal parts: the values
117
+ * between the segments, none at the two ends. Ten glasses of water make nine
118
+ * cuts.
119
+ */
120
+ var cutValues = (min, max, segments) => stepValues(min, max, segments).slice(1, -1);
121
+ /**
122
+ * Inverse of `valueToAngle`: the domain value under a gauge angle. An angle
123
+ * in the opening outside the sweep goes to whichever end is nearer, so a
124
+ * pointer dragged past an end holds there rather than jumping to the other.
125
+ */
126
+ var angleToValue = (angle, min, max, startAngle, endAngle) => {
127
+ let a = angle;
128
+ while (a < startAngle) a += 360;
129
+ while (a >= startAngle + 360) a -= 360;
130
+ if (a > endAngle) a = a - endAngle < startAngle + 360 - a ? endAngle : startAngle;
131
+ const sweep = endAngle - startAngle;
132
+ return min + (sweep === 0 ? 0 : (a - startAngle) / sweep) * (max - min);
133
+ };
134
+ //#endregion
135
+ export { angleToValue, arcBox, arcPath, clamp, cutValues, degreesToRadians, foldValue, fractionDigits, polar, stepValues, valueToAngle, valueToTurnedAngle };
@@ -0,0 +1,81 @@
1
+ import { GaugeEnd, NeedleStyle } from './utils';
2
+ import * as React from 'react';
3
+ export type GaugeNeedleProps = {
4
+ /**
5
+ * Needle shape. `line` is a stroke with round ends, `pointer` a tapered
6
+ * blade that is widest at the centre and ends in a rounded tip, and
7
+ * `compass` a lozenge whose two halves can take different colours. `arrow`
8
+ * is a shaft ending in a triangular arrowhead, sized from the width, for
9
+ * wind or flow direction. Named `kind` (not `style`) so React's CSS
10
+ * `style` prop stays available as an object.
11
+ * @defaultValue `'line'`
12
+ */
13
+ kind?: NeedleStyle;
14
+ /**
15
+ * Length as a fraction of the reference radius.
16
+ * @defaultValue 0.85
17
+ */
18
+ length?: number;
19
+ /**
20
+ * Stroke width for `line`; width at the centre for the filled styles.
21
+ * @defaultValue 6
22
+ */
23
+ width?: number;
24
+ /**
25
+ * Fill/stroke colour. Unset uses theme primary.
26
+ * @defaultValue `var(--global-primary)`
27
+ */
28
+ color?: string;
29
+ /**
30
+ * How far the needle extends behind the centre, in SVG units.
31
+ * @defaultValue 30
32
+ */
33
+ tail?: number;
34
+ /**
35
+ * Colour of the tail half of a `pointer`, `compass` or `arrow`. Defaults to `color`.
36
+ * @defaultValue same as `color`
37
+ */
38
+ tailColor?: string;
39
+ /**
40
+ * Radius of a disc drawn at the end of the tail in `tailColor`, like the
41
+ * counterweight on a wind vane. 0 leaves the tail plain.
42
+ * @defaultValue 0
43
+ */
44
+ tailDot?: number;
45
+ /**
46
+ * Sweeps of the arc the needle makes across the domain. A clock's minute
47
+ * hand turns 12 times while the hour hand turns once.
48
+ * @defaultValue 1
49
+ */
50
+ turns?: number;
51
+ /**
52
+ * Radius of a clear circle around the centre, in SVG units, that splits the
53
+ * needle in two so a readout can sit between the halves. 0 draws it whole.
54
+ * @defaultValue 0
55
+ */
56
+ gap?: number;
57
+ /**
58
+ * Which end of a range the needle points at.
59
+ * @defaultValue `'to'`
60
+ */
61
+ end?: GaugeEnd;
62
+ };
63
+ /**
64
+ * A needle pointing at the current value. Add a `GaugeHub` for the pivot, or
65
+ * a `gap` to clear the centre for a readout instead.
66
+ */
67
+ export declare const GaugeNeedle: React.FC<GaugeNeedleProps>;
68
+ export type GaugeHubProps = {
69
+ /**
70
+ * Hub disc radius in SVG units. `0` hides the hub.
71
+ * @defaultValue 12
72
+ */
73
+ radius?: number;
74
+ /**
75
+ * Fill colour. Unset uses theme foreground.
76
+ * @defaultValue `var(--global-foreground)`
77
+ */
78
+ color?: string;
79
+ };
80
+ /** The pivot disc at the centre, drawn once however many needles there are. */
81
+ export declare const GaugeHub: React.FC<GaugeHubProps>;