@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,8 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { __commonJSMin, __require };
|
package/dist/catalog.json
CHANGED
|
@@ -122,6 +122,12 @@
|
|
|
122
122
|
"summary": "Decorative pointer-driven border highlight on a transparent Surface shell (radius only). Put the visual card as children; a shared rAF tracker paints CSS variables without React re-renders. Memory/CPU-heavy — use sparingly; prefer one focal instance per view.",
|
|
123
123
|
"agentDocs": "./specs/components/glow/meta.xml"
|
|
124
124
|
},
|
|
125
|
+
{
|
|
126
|
+
"id": "gauge",
|
|
127
|
+
"name": "Gauge",
|
|
128
|
+
"summary": "Composable round dial for determinate readings and optional polar slider control, built from SVG parts sharing one domain context. Linear bars stay on Slider.",
|
|
129
|
+
"agentDocs": "./specs/components/gauge/meta.xml"
|
|
130
|
+
},
|
|
125
131
|
{
|
|
126
132
|
"id": "grid",
|
|
127
133
|
"name": "Grid",
|
|
@@ -134,6 +140,12 @@
|
|
|
134
140
|
"summary": "Icon-only button that shares Button visual chrome (--vui-button-* CSS) and requires an accessible name through aria-label or aria-labelledby.",
|
|
135
141
|
"agentDocs": "./specs/components/icon-button/meta.xml"
|
|
136
142
|
},
|
|
143
|
+
{
|
|
144
|
+
"id": "icon-meter",
|
|
145
|
+
"name": "IconMeter",
|
|
146
|
+
"summary": "Display-only discrete icon row for scores and levels (empty / half / full), with APG Meter semantics. Distinct from track Meter, arc Gauge, and LinearProgress.",
|
|
147
|
+
"agentDocs": "./specs/components/icon-meter/meta.xml"
|
|
148
|
+
},
|
|
137
149
|
{
|
|
138
150
|
"id": "linear-progress",
|
|
139
151
|
"name": "LinearProgress",
|
|
@@ -32,6 +32,12 @@ export type AvatarProps = React.ComponentPropsWithRef<'span'> & {
|
|
|
32
32
|
* @defaultValue 's'
|
|
33
33
|
*/
|
|
34
34
|
size?: 'xs' | 's' | 'm' | 'l';
|
|
35
|
+
/**
|
|
36
|
+
* Controls native image lazy-loading on the avatar `<img>`.
|
|
37
|
+
*
|
|
38
|
+
* @defaultValue 'eager'
|
|
39
|
+
*/
|
|
40
|
+
loading?: React.ComponentProps<'img'>['loading'];
|
|
35
41
|
/**
|
|
36
42
|
* Ref forwarded to the rendered avatar root element.
|
|
37
43
|
*
|
|
@@ -11,7 +11,7 @@ var fallbackTextSizeByAvatarSize = {
|
|
|
11
11
|
m: "s",
|
|
12
12
|
l: "2xl"
|
|
13
13
|
};
|
|
14
|
-
var Avatar$1 = ({ alt = "", className, fallback, ref, size = "s", src, ...otherProps }) => {
|
|
14
|
+
var Avatar$1 = ({ alt = "", className, fallback, loading = "eager", ref, size = "s", src, ...otherProps }) => {
|
|
15
15
|
const hasImage = Boolean(src);
|
|
16
16
|
return /* @__PURE__ */ jsxs(Avatar.Root, {
|
|
17
17
|
...otherProps,
|
|
@@ -23,7 +23,7 @@ var Avatar$1 = ({ alt = "", className, fallback, ref, size = "s", src, ...otherP
|
|
|
23
23
|
children: [hasImage ? /* @__PURE__ */ jsx(Avatar.Image, {
|
|
24
24
|
draggable: false,
|
|
25
25
|
decoding: "async",
|
|
26
|
-
loading
|
|
26
|
+
loading,
|
|
27
27
|
alt,
|
|
28
28
|
className: avatar_module_default.Image,
|
|
29
29
|
src
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-badge-size{syntax:"<length>";inherits:true;initial-value:.5rem}@property --vui-badge-color{syntax:"<color>";inherits:true;initial-value:#292929}@property --vui-badge-position-x{syntax:"<length-percentage>";inherits:true;initial-value:100%}@property --vui-badge-position-y{syntax:"<length-percentage>";inherits:true;initial-value:0%}@property --__badge-gap{syntax:"<length>";inherits:true;initial-value:0}@property --__badge-mask-size{syntax:"<length>";inherits:true;initial-value:0}@property --__badge-hole-progress{syntax:"<number>";inherits:true;initial-value:0}@property --__badge-motion-delay{syntax:"<time>";inherits:true;initial-value:.
|
|
1
|
+
@layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-badge-size{syntax:"<length>";inherits:true;initial-value:.5rem}@property --vui-badge-color{syntax:"<color>";inherits:true;initial-value:#292929}@property --vui-badge-position-x{syntax:"<length-percentage>";inherits:true;initial-value:100%}@property --vui-badge-position-y{syntax:"<length-percentage>";inherits:true;initial-value:0%}@property --__badge-gap{syntax:"<length>";inherits:true;initial-value:0}@property --__badge-mask-size{syntax:"<length>";inherits:true;initial-value:0}@property --__badge-hole-progress{syntax:"<number>";inherits:true;initial-value:0}@property --__badge-motion-delay{syntax:"<time>";inherits:true;initial-value:.08s}.viraui__badge-module__Badge_lJqlY{--vui-badge-color:var(--global-primary);--__badge-gap:calc(var(--vui-badge-size) * 0.25);--__badge-mask-size:calc(var(--vui-badge-size) / 2 + var(--__badge-gap));--__badge-motion-delay:calc(var(--duration-fast) * 0.4);position:relative;display:inline-flex;inline-size:max-content;&[data-position=top-end]{--vui-badge-position-x:100%;--vui-badge-position-y:0%}&[data-position=top-start]{--vui-badge-position-x:0%;--vui-badge-position-y:0%}&[data-position=bottom-end]{--vui-badge-position-x:100%;--vui-badge-position-y:100%}&[data-position=bottom-start]{--vui-badge-position-x:0%;--vui-badge-position-y:100%}&>*{outline-offset:-4px}&[data-show=true]{&:after{--__corner-shape:round;content:"";width:var(--vui-badge-size);aspect-ratio:1;display:block;border-radius:100000px;background:var(--vui-badge-color);position:absolute;left:calc(var(--vui-badge-position-x) - min(var(--vui-badge-position-x), var(--vui-badge-size)));top:calc(var(--vui-badge-position-y) - min(var(--vui-badge-position-y), var(--vui-badge-size)));pointer-events:none;transform-origin:center}&:not([data-exit]):after{transform:scale(0);animation:viraui__badge-module__badge-dot-in_SKMx8 var(--duration-fast) var(--easing-entrance) forwards;animation-delay:var(--__badge-motion-delay)}&[data-exit]:after{transform:scale(1);animation:viraui__badge-module__badge-dot-out_vWhcP var(--duration-fast) var(--easing-entrance) forwards}&>*{mask-image:radial-gradient(circle at calc(var(--vui-badge-position-x) - min(var(--vui-badge-position-x), var(--vui-badge-size)) + (var(--vui-badge-size) / 2)) calc(var(--vui-badge-position-y) - min(var(--vui-badge-position-y), var(--vui-badge-size)) + (var(--vui-badge-size) / 2)),#0000 0 calc(var(--__badge-mask-size) * var(--__badge-hole-progress)),red calc(var(--__badge-mask-size) * var(--__badge-hole-progress) + 1px))}&:not([data-exit])>*{animation:viraui__badge-module__badge-hole-in_71iZP var(--duration-fast) var(--easing-entrance) forwards}&[data-exit]>*{--__badge-hole-progress:1;animation:viraui__badge-module__badge-hole-out_JCHCf var(--duration-fast) var(--easing-entrance) forwards;animation-delay:var(--__badge-motion-delay)}@media (prefers-reduced-motion:reduce){&:not([data-exit]):after,&[data-exit]:after{transform:none;animation:none}&:not([data-exit])>*{--__badge-hole-progress:1;animation:none}&[data-exit]>*{--__badge-hole-progress:0;animation:none}}}}@keyframes viraui__badge-module__badge-hole-in_71iZP{0%{--__badge-hole-progress:0}to{--__badge-hole-progress:1}}@keyframes viraui__badge-module__badge-hole-out_JCHCf{0%{--__badge-hole-progress:1}to{--__badge-hole-progress:0}}@keyframes viraui__badge-module__badge-dot-in_SKMx8{0%{transform:scale(0)}to{transform:scale(1)}}@keyframes viraui__badge-module__badge-dot-out_vWhcP{0%{transform:scale(1)}to{transform:scale(0)}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-button-background{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-color{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-height{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-inline{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-block{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-spinner-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-button-icon-size{syntax:"<length>";inherits:true;initial-value:0}@property --vui-button-radius{syntax:"<length-percentage>";inherits:false;initial-value:0}.viraui__button-module__Button_oPhrP{--vui-button-background:var(--global-primary);--vui-button-color:var(--base-1);--vui-button-height:var(--space-2xl);--vui-button-padding-inline:calc(var(--space-s) + var(--space-2xs));--vui-button-padding-block:var(--space-s);--vui-button-icon-size:calc(var(--
|
|
1
|
+
@layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-button-background{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-color{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-height{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-inline{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-block{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-spinner-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-button-icon-size{syntax:"<length>";inherits:true;initial-value:0}@property --vui-button-radius{syntax:"<length-percentage>";inherits:false;initial-value:0}.viraui__button-module__Button_oPhrP{--vui-button-background:var(--global-primary);--vui-button-color:var(--base-1);--vui-button-height:var(--space-2xl);--vui-button-padding-inline:calc(var(--space-s) + var(--space-2xs));--vui-button-padding-block:var(--space-s);--vui-button-icon-size:calc(var(--vui-button-height) * 0.45);--vui-button-spinner-color:currentColor;--vui-button-radius:var(--radius-m);max-block-size:min-content;-webkit-user-select:none;user-select:none;margin-block:0;margin-inline:0;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;min-inline-size:fit-content;min-block-size:round(to-zero,var(--vui-button-height),2px);block-size:round(to-zero,var(--vui-button-height),2px);justify-content:center;text-decoration:none;white-space:nowrap;appearance:button;overflow:hidden;position:relative;padding:var(--vui-button-padding-block) var(--vui-button-padding-inline);font-weight:400;font-variation-settings:"wght" 500;gap:var(--space-s);border:1px solid #0000;background:var(--vui-button-background);color:var(--vui-button-color);font-size:var(--font-scale-body-m);border-radius:var(--vui-button-radius);transition:translate var(--easing-elastic) var(--duration-instant);will-change:translate;&:not(:disabled){background-clip:padding-box}&:not(:disabled,[aria-disabled=true]):active{translate:0 1px}&[data-pill=true]{--__corner-shape:round;border-radius:var(--radius-full)}&[data-size=l]{--vui-button-height:calc(var(--space-2xl) + var(--space-xs));--vui-button-padding-inline:var(--space-m);--vui-button-padding-block:var(--space-s);--vui-button-radius:var(--radius-m)}&[data-size=s]{--vui-button-height:var(--space-xl);--vui-button-padding-inline:var(--space-s);--vui-button-padding-block:var(--space-xs);--vui-button-radius:var(--radius-s);gap:var(--space-xs);font-size:var(--font-scale-body-s)}&[data-variant=primary]{--vui-button-background:var(--global-primary);--vui-button-color:contrast-color(var(--global-primary));&:hover{--vui-button-background:oklab(from var(--global-primary) calc(l + 0.05) a b)}}&[data-variant=secondary]{--vui-button-background:var(--global-contrast);--vui-button-color:var(--global-foreground);background-clip:unset;&:hover{--vui-button-background:oklab(from var(--global-contrast) l a b / calc(alpha + 0.03))}@container root style(--is-light-mode: black){--vui-button-background:oklab(from var(--global-contrast) l a b / 0.1)}}&[data-variant=flat]{--vui-button-background:#0000;--vui-button-color:var(--global-foreground);background-clip:unset;&:hover{--vui-button-background:var(--global-contrast);--vui-button-color:var(--base-7)}}&[data-variant=destructive]{--vui-button-background:oklab(from var(--highlight-red) l a b / 12%);--vui-button-color:var(--highlight-red);outline-color:var(--highlight-red);&:hover{--vui-button-background:oklab(from var(--highlight-red) l a b / 30%)}}&[data-addon-position=start]{flex-direction:row;padding-inline-end:calc(var(--vui-button-padding-inline) * 1.2)}&[data-addon-position=end]{flex-direction:row-reverse;padding-inline-start:calc(var(--vui-button-padding-inline) * 1.2)}&[data-icon-only=true]{gap:0;padding-block:var(--vui-button-padding-block);padding-inline:var(--vui-button-padding-block);inline-size:var(--vui-button-height);min-inline-size:var(--vui-button-height);max-inline-size:var(--vui-button-height);aspect-ratio:1/1}&:disabled,&:disabled:active,&:disabled:hover,&[aria-disabled=true],&[aria-disabled=true]:active,&[aria-disabled=true]:hover{--vui-button-background:var(--global-disabled-background);--vui-button-color:var(--global-disabled-foreground);cursor:not-allowed;box-shadow:none;translate:0}&[data-variant=flat]:is(:disabled,[aria-disabled=true]),&[data-variant=flat]:is(:disabled,[aria-disabled=true]):active,&[data-variant=flat]:is(:disabled,[aria-disabled=true]):hover{--vui-button-background:#0000}&[data-loading=true]:is(:disabled,[data-disabled],[aria-disabled=true]){pointer-events:none;border:0;box-shadow:none;--vui-button-color:var(--base-7)}}.viraui__button-module__Content_w-pX-{display:inline-grid;place-items:center;&[data-loading=true]{opacity:0}&:first-child>svg{block-size:round(to-zero,var(--vui-button-icon-size),2px);inline-size:round(to-zero,var(--vui-button-icon-size),2px);flex-shrink:0}}.viraui__button-module__SpinnerOverlay_vKqw1{position:absolute;inset:0;display:grid;place-content:center;pointer-events:none;color:var(--vui-button-spinner-color)}}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { StrokeCap, Zone } from './utils';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
type ArcStyleProps = {
|
|
4
|
+
/**
|
|
5
|
+
* Stroke width in SVG units.
|
|
6
|
+
* @defaultValue 24
|
|
7
|
+
*/
|
|
8
|
+
width?: number;
|
|
9
|
+
/**
|
|
10
|
+
* Stroke colour. Track defaults to contrast; fill arcs to primary.
|
|
11
|
+
* @defaultValue `var(--global-contrast)` on `GaugeTrack`; `var(--global-primary)` on fill arcs
|
|
12
|
+
*/
|
|
13
|
+
color?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Stroke opacity.
|
|
16
|
+
* @defaultValue 1
|
|
17
|
+
*/
|
|
18
|
+
opacity?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Stroke line cap.
|
|
21
|
+
* @defaultValue `'round'` on track/arc; `'butt'` on stack/zones
|
|
22
|
+
*/
|
|
23
|
+
cap?: StrokeCap;
|
|
24
|
+
/**
|
|
25
|
+
* Offset from the scale's reference line: radial on a dial, across a
|
|
26
|
+
* bar. Positive moves outward, away from the centre or up from a bar.
|
|
27
|
+
* @defaultValue 0
|
|
28
|
+
*/
|
|
29
|
+
offset?: number;
|
|
30
|
+
};
|
|
31
|
+
/** The whole scale as a background: a dial's full sweep, a bar's length. */
|
|
32
|
+
export declare const GaugeTrack: React.FC<ArcStyleProps>;
|
|
33
|
+
export type GaugeArcProps = ArcStyleProps & {
|
|
34
|
+
/**
|
|
35
|
+
* Domain value the arc is anchored at. Defaults to `min`, or to the start
|
|
36
|
+
* of the gauge's range.
|
|
37
|
+
* @defaultValue gauge `from` (min on a single value)
|
|
38
|
+
*/
|
|
39
|
+
from?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Domain value the arc ends at. Defaults to the current value.
|
|
42
|
+
* @defaultValue current gauge `value`
|
|
43
|
+
*/
|
|
44
|
+
to?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Grow the arc back from the end of the sweep instead of forward from its
|
|
47
|
+
* start. The length is the same; only the end it is anchored to changes,
|
|
48
|
+
* which is what a dial filling towards its start needs.
|
|
49
|
+
* @defaultValue false
|
|
50
|
+
*/
|
|
51
|
+
reverse?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Carry the arc on round a closed ring instead of clamping it at the
|
|
54
|
+
* domain: a span from eleven at night to two in the morning crosses the
|
|
55
|
+
* seam in one piece. The arc runs forward from `from` however far past
|
|
56
|
+
* `max` the `to` reaches.
|
|
57
|
+
* @defaultValue false
|
|
58
|
+
*/
|
|
59
|
+
wrap?: boolean;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The filled arc, from `min` (or `from`) up to the current value (or `to`).
|
|
63
|
+
* The ends may arrive either way round: an arc anchored above the value
|
|
64
|
+
* grows back towards it, which is what a dial centred on zero needs. On a
|
|
65
|
+
* gauge showing a range it fills between the two ends, and on a wrapped one
|
|
66
|
+
* runs forward from the start across the seam where the range does.
|
|
67
|
+
*/
|
|
68
|
+
export declare const GaugeArc: React.FC<GaugeArcProps>;
|
|
69
|
+
export type GaugeStackPart = {
|
|
70
|
+
/**
|
|
71
|
+
* Share of the fill. Weighted parts split the value between them.
|
|
72
|
+
* @defaultValue 0 when omitted (fixed `to` parts use cutoff instead)
|
|
73
|
+
*/
|
|
74
|
+
weight?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Fixed upper cutoff in domain units, for parts that stand still while
|
|
77
|
+
* the value sweeps across them. Runs from the end of the part before.
|
|
78
|
+
* @defaultValue derived from weight share of fill
|
|
79
|
+
*/
|
|
80
|
+
to?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Stroke colour for this part.
|
|
83
|
+
*/
|
|
84
|
+
color: string;
|
|
85
|
+
/**
|
|
86
|
+
* Per-part stroke opacity.
|
|
87
|
+
* @defaultValue inherits path paint (undefined)
|
|
88
|
+
*/
|
|
89
|
+
opacity?: number;
|
|
90
|
+
};
|
|
91
|
+
export type GaugeStackProps = Omit<ArcStyleProps, 'color'> & {
|
|
92
|
+
/**
|
|
93
|
+
* Ordered stack segments (weights and/or fixed cutoffs).
|
|
94
|
+
*/
|
|
95
|
+
parts: GaugeStackPart[];
|
|
96
|
+
/**
|
|
97
|
+
* Domain value the stack starts at. Defaults to `min`, or to the start of
|
|
98
|
+
* the gauge's range.
|
|
99
|
+
* @defaultValue gauge `from`
|
|
100
|
+
*/
|
|
101
|
+
from?: number;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* The value arc split into parts that sweep as one. A part with a `weight`
|
|
105
|
+
* takes that share of the fill, so a memory ring keeps wired, app and cache
|
|
106
|
+
* in proportion frame by frame; a part with a fixed `to` runs from the end
|
|
107
|
+
* of the one before and is clipped to the value, so a night of sleep stages
|
|
108
|
+
* draws on in order as the dial sweeps in. Use one kind or the other in a
|
|
109
|
+
* single stack.
|
|
110
|
+
*/
|
|
111
|
+
export declare const GaugeStack: React.FC<GaugeStackProps>;
|
|
112
|
+
export type GaugeZonesProps = Omit<ArcStyleProps, 'color'> & {
|
|
113
|
+
/**
|
|
114
|
+
* Ordered cutoffs. Each zone runs from the previous zone's `to` (or `min`)
|
|
115
|
+
* up to its own `to`; the last zone always extends to `max`.
|
|
116
|
+
*/
|
|
117
|
+
zones: Zone[];
|
|
118
|
+
/**
|
|
119
|
+
* Gap between neighbouring zones, in the scale's units: degrees round a
|
|
120
|
+
* dial, SVG units along a bar.
|
|
121
|
+
* @defaultValue 0
|
|
122
|
+
*/
|
|
123
|
+
gap?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Cap on the two outer ends of the whole band (the start of the first zone
|
|
126
|
+
* and the end of the last). `cap` covers the joints between zones. Defaults
|
|
127
|
+
* to `cap`, so a single value still rounds or squares every end.
|
|
128
|
+
* @defaultValue same as `cap`
|
|
129
|
+
*/
|
|
130
|
+
endCap?: StrokeCap;
|
|
131
|
+
};
|
|
132
|
+
/** Coloured bands marking the cutoffs of the domain. */
|
|
133
|
+
export declare const GaugeZones: React.FC<GaugeZonesProps>;
|
|
134
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { foldValue } from "./math.js";
|
|
3
|
+
import { useGauge } from "./context.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import "react";
|
|
6
|
+
//#region src/components/gauge/arcs.tsx
|
|
7
|
+
var CONTRAST = "var(--global-contrast)";
|
|
8
|
+
var PRIMARY = "var(--global-primary)";
|
|
9
|
+
/** The whole scale as a background: a dial's full sweep, a bar's length. */
|
|
10
|
+
var GaugeTrack = ({ width = 24, color = CONTRAST, opacity = 1, cap = "round", offset = 0 }) => {
|
|
11
|
+
const { scale } = useGauge();
|
|
12
|
+
return /* @__PURE__ */ jsx("path", {
|
|
13
|
+
d: scale.path(scale.start, scale.end, offset),
|
|
14
|
+
fill: "none",
|
|
15
|
+
stroke: color,
|
|
16
|
+
strokeOpacity: opacity,
|
|
17
|
+
strokeWidth: width,
|
|
18
|
+
strokeLinecap: cap
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The filled arc, from `min` (or `from`) up to the current value (or `to`).
|
|
23
|
+
* The ends may arrive either way round: an arc anchored above the value
|
|
24
|
+
* grows back towards it, which is what a dial centred on zero needs. On a
|
|
25
|
+
* gauge showing a range it fills between the two ends, and on a wrapped one
|
|
26
|
+
* runs forward from the start across the seam where the range does.
|
|
27
|
+
*/
|
|
28
|
+
var GaugeArc = ({ width = 24, color = PRIMARY, opacity = 1, cap = "round", offset = 0, from, to, reverse = false, wrap = false }) => {
|
|
29
|
+
const gauge = useGauge();
|
|
30
|
+
const { min, max, value, scale, positionOf } = gauge;
|
|
31
|
+
const tail = from ?? gauge.from;
|
|
32
|
+
let head = to ?? value;
|
|
33
|
+
const forward = gauge.range && gauge.wrap && from === void 0 && to === void 0;
|
|
34
|
+
if (forward) head = tail + foldValue(head - tail, 0, Math.abs(max - min));
|
|
35
|
+
const lo = Math.min(tail, head);
|
|
36
|
+
const hi = Math.max(tail, head);
|
|
37
|
+
let a0;
|
|
38
|
+
let a1;
|
|
39
|
+
if (wrap || forward) {
|
|
40
|
+
const span = max - min;
|
|
41
|
+
if (span <= 0) return null;
|
|
42
|
+
const sweep = scale.end - scale.start;
|
|
43
|
+
const perUnit = sweep / span;
|
|
44
|
+
a0 = scale.start + ((lo - min) % span + span) % span * perUnit;
|
|
45
|
+
a1 = a0 + Math.min((hi - lo) * perUnit, sweep);
|
|
46
|
+
} else [a0, a1] = reverse ? [positionOf(max - (hi - lo)), positionOf(max)] : [positionOf(lo), positionOf(hi)];
|
|
47
|
+
if (a1 <= a0) return null;
|
|
48
|
+
return /* @__PURE__ */ jsx("path", {
|
|
49
|
+
d: scale.path(a0, a1, offset),
|
|
50
|
+
fill: "none",
|
|
51
|
+
stroke: color,
|
|
52
|
+
strokeOpacity: opacity,
|
|
53
|
+
strokeWidth: width,
|
|
54
|
+
strokeLinecap: cap
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The value arc split into parts that sweep as one. A part with a `weight`
|
|
59
|
+
* takes that share of the fill, so a memory ring keeps wired, app and cache
|
|
60
|
+
* in proportion frame by frame; a part with a fixed `to` runs from the end
|
|
61
|
+
* of the one before and is clipped to the value, so a night of sleep stages
|
|
62
|
+
* draws on in order as the dial sweeps in. Use one kind or the other in a
|
|
63
|
+
* single stack.
|
|
64
|
+
*/
|
|
65
|
+
var GaugeStack = ({ parts, width = 24, opacity = 1, cap = "butt", offset = 0, from }) => {
|
|
66
|
+
const gauge = useGauge();
|
|
67
|
+
const { value, scale, positionOf } = gauge;
|
|
68
|
+
if (parts.length === 0) return null;
|
|
69
|
+
const total = parts.reduce((sum, p) => sum + (p.weight ?? 0), 0);
|
|
70
|
+
const start = from ?? gauge.from;
|
|
71
|
+
const fill = value - start;
|
|
72
|
+
const ends = parts.reduce((acc, p) => [...acc, p.to ?? (acc.at(-1) ?? start) + (total > 0 ? fill * (p.weight ?? 0) / total : 0)], []);
|
|
73
|
+
return /* @__PURE__ */ jsx("g", {
|
|
74
|
+
opacity,
|
|
75
|
+
children: parts.map((p, i) => {
|
|
76
|
+
const end = ends[i];
|
|
77
|
+
if (end === void 0) return null;
|
|
78
|
+
const prev = i === 0 ? start : ends[i - 1];
|
|
79
|
+
if (prev === void 0) return null;
|
|
80
|
+
const a0 = positionOf(prev);
|
|
81
|
+
const a1 = positionOf(Math.min(end, value));
|
|
82
|
+
if (a1 <= a0) return null;
|
|
83
|
+
return /* @__PURE__ */ jsx("path", {
|
|
84
|
+
d: scale.path(a0, a1, offset),
|
|
85
|
+
fill: "none",
|
|
86
|
+
stroke: p.color,
|
|
87
|
+
strokeOpacity: p.opacity,
|
|
88
|
+
strokeWidth: width,
|
|
89
|
+
strokeLinecap: cap
|
|
90
|
+
}, end);
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
/** Coloured bands marking the cutoffs of the domain. */
|
|
95
|
+
var GaugeZones = ({ zones, width = 8, opacity = 1, cap = "butt", endCap = cap, offset = 0, gap = 0 }) => {
|
|
96
|
+
const { min, max, scale, positionOf } = useGauge();
|
|
97
|
+
if (zones.length === 0) return null;
|
|
98
|
+
const dot = (position, color, key) => {
|
|
99
|
+
const { x, y } = scale.point(position, offset);
|
|
100
|
+
return /* @__PURE__ */ jsx("circle", {
|
|
101
|
+
cx: x,
|
|
102
|
+
cy: y,
|
|
103
|
+
r: width / 2,
|
|
104
|
+
fill: color
|
|
105
|
+
}, key);
|
|
106
|
+
};
|
|
107
|
+
const segments = zones.reduce((acc, zone, i) => {
|
|
108
|
+
const prev = acc[i - 1];
|
|
109
|
+
const from = i === 0 || !prev ? min : prev.to;
|
|
110
|
+
const to = i === zones.length - 1 ? max : Math.min(Math.max(zone.to, from), max);
|
|
111
|
+
acc.push({
|
|
112
|
+
from,
|
|
113
|
+
to
|
|
114
|
+
});
|
|
115
|
+
return acc;
|
|
116
|
+
}, []);
|
|
117
|
+
return /* @__PURE__ */ jsx("g", {
|
|
118
|
+
opacity,
|
|
119
|
+
children: zones.map((zone, i) => {
|
|
120
|
+
const isFirst = i === 0;
|
|
121
|
+
const isLast = i === zones.length - 1;
|
|
122
|
+
const segment = segments[i];
|
|
123
|
+
if (!segment) return null;
|
|
124
|
+
const { from, to } = segment;
|
|
125
|
+
const a0 = positionOf(from) + (isFirst ? 0 : gap / 2);
|
|
126
|
+
const a1 = positionOf(to) - (isLast ? 0 : gap / 2);
|
|
127
|
+
if (a1 <= a0) return null;
|
|
128
|
+
const startCap = isFirst ? endCap : cap;
|
|
129
|
+
const finishCap = isLast ? endCap : cap;
|
|
130
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
131
|
+
/* @__PURE__ */ jsx("path", {
|
|
132
|
+
d: scale.path(a0, a1, offset),
|
|
133
|
+
fill: "none",
|
|
134
|
+
stroke: zone.color,
|
|
135
|
+
strokeWidth: width,
|
|
136
|
+
strokeLinecap: "butt"
|
|
137
|
+
}),
|
|
138
|
+
startCap === "round" && dot(a0, zone.color, "start"),
|
|
139
|
+
finishCap === "round" && dot(a1, zone.color, "end")
|
|
140
|
+
] }, to);
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
//#endregion
|
|
145
|
+
export { GaugeArc, GaugeStack, GaugeTrack, GaugeZones };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { GaugeScale } from './scale';
|
|
2
|
+
import { GaugeTransition } from './transition';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* A span of the domain rather than a single reading: a forecast's low and
|
|
6
|
+
* high, a target band, a sleep window. Pass it as a gauge's `value` and the
|
|
7
|
+
* arc fills between the two ends.
|
|
8
|
+
*/
|
|
9
|
+
export type GaugeRange = readonly [from: number, to: number];
|
|
10
|
+
/** The reading and domain, the same on every gauge whatever its shape. */
|
|
11
|
+
export type GaugeReading = {
|
|
12
|
+
/**
|
|
13
|
+
* Value being drawn this frame, clamped to the domain. Animated when the
|
|
14
|
+
* gauge has a transition. For a range, its far end.
|
|
15
|
+
*/
|
|
16
|
+
value: number;
|
|
17
|
+
/** Value the gauge is heading for; equals `value` once settled. */
|
|
18
|
+
target: number;
|
|
19
|
+
/**
|
|
20
|
+
* Where a range starts, animated alongside `value`. On a single value it
|
|
21
|
+
* is `min`, so the stretch from here to `value` is the fill either way.
|
|
22
|
+
*/
|
|
23
|
+
from: number;
|
|
24
|
+
/** Where `from` is heading for. */
|
|
25
|
+
targetFrom: number;
|
|
26
|
+
/** Whether the gauge shows a range rather than a single value. */
|
|
27
|
+
range: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Whether the domain is a closed ring, as the root's `wrap` sets. A range
|
|
30
|
+
* on one runs forward from `from` to `value`, across the seam if need be.
|
|
31
|
+
*/
|
|
32
|
+
wrap: boolean;
|
|
33
|
+
min: number;
|
|
34
|
+
max: number;
|
|
35
|
+
};
|
|
36
|
+
/** What a round `Gauge` adds: the angles and radius its scale is bent to. */
|
|
37
|
+
export type GaugeRoundShape = {
|
|
38
|
+
shape: 'round';
|
|
39
|
+
startAngle: number;
|
|
40
|
+
endAngle: number;
|
|
41
|
+
/** Radius of the gauge's reference circle in SVG units. */
|
|
42
|
+
radius: number;
|
|
43
|
+
/** Maps a domain value onto a gauge angle. The same as `positionOf`. */
|
|
44
|
+
angleOf: (value: number) => number;
|
|
45
|
+
};
|
|
46
|
+
export type GaugeContextValue = GaugeReading & GaugeRoundShape & {
|
|
47
|
+
/**
|
|
48
|
+
* The arc the domain is laid out along, which every part that draws
|
|
49
|
+
* along it asks for its geometry.
|
|
50
|
+
*/
|
|
51
|
+
scale: GaugeScale;
|
|
52
|
+
/** Maps a domain value onto a position on the scale. */
|
|
53
|
+
positionOf: (value: number) => number;
|
|
54
|
+
};
|
|
55
|
+
export declare const GaugeContext: React.Context<GaugeContextValue | null>;
|
|
56
|
+
export declare const useGauge: () => GaugeContextValue;
|
|
57
|
+
/**
|
|
58
|
+
* Alias of `useGauge` for parts that historically required a round root
|
|
59
|
+
* (needle). All public gauges are round; linear bars stay on `Slider`.
|
|
60
|
+
*/
|
|
61
|
+
export declare const useRoundGauge: (part: string) => GaugeContextValue;
|
|
62
|
+
/** The reading, domain and animation every gauge root takes. */
|
|
63
|
+
export type GaugeReadingProps = {
|
|
64
|
+
/**
|
|
65
|
+
* The reading, or a `[from, to]` range to fill between. On an open domain
|
|
66
|
+
* the two ends are put in order; on a wrapped one the range runs forward
|
|
67
|
+
* from `from`, so `[22, 6]` on a 24-hour ring is the night, not the day.
|
|
68
|
+
* @defaultValue Required — no default.
|
|
69
|
+
*/
|
|
70
|
+
value: number | GaugeRange;
|
|
71
|
+
/**
|
|
72
|
+
* Lower bound of the domain.
|
|
73
|
+
* @defaultValue 0
|
|
74
|
+
*/
|
|
75
|
+
min?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Upper bound of the domain.
|
|
78
|
+
* @defaultValue 100
|
|
79
|
+
*/
|
|
80
|
+
max?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Animate towards new values. `true` uses a gentle spring; pass a
|
|
83
|
+
* `GaugeTransition` to tune it or switch to a timed tween. Omit for
|
|
84
|
+
* instant updates.
|
|
85
|
+
* @defaultValue undefined — instant updates
|
|
86
|
+
*/
|
|
87
|
+
transition?: GaugeTransition | boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Where the value starts on mount when animating, for a sweep-in effect.
|
|
90
|
+
* A single number starts both ends of a range there, so it opens out.
|
|
91
|
+
* @defaultValue undefined — starts at the target value
|
|
92
|
+
*/
|
|
93
|
+
initialValue?: number | GaugeRange;
|
|
94
|
+
/**
|
|
95
|
+
* Treat the domain as circular, as a compass rose or clock face is: the
|
|
96
|
+
* value is mapped into the domain modulo its span and animates the
|
|
97
|
+
* shortest way round, so a heading crossing north never swings the long
|
|
98
|
+
* way back. Meant for closed rings, where `min` and `max` read the same.
|
|
99
|
+
* @defaultValue false
|
|
100
|
+
*/
|
|
101
|
+
wrap?: boolean;
|
|
102
|
+
};
|
|
103
|
+
/** The domain, geometry and animation a round gauge takes. */
|
|
104
|
+
export type GaugeDomainProps = GaugeReadingProps & {
|
|
105
|
+
/**
|
|
106
|
+
* Gauge degrees, clockwise from six o'clock — sweep start.
|
|
107
|
+
* @defaultValue 40
|
|
108
|
+
*/
|
|
109
|
+
startAngle?: number;
|
|
110
|
+
/**
|
|
111
|
+
* Gauge degrees, clockwise from six o'clock — sweep end.
|
|
112
|
+
* @defaultValue 320
|
|
113
|
+
*/
|
|
114
|
+
endAngle?: number;
|
|
115
|
+
/**
|
|
116
|
+
* Reference radius in SVG units. Every child positions itself against this.
|
|
117
|
+
* @defaultValue 200
|
|
118
|
+
*/
|
|
119
|
+
radius?: number;
|
|
120
|
+
/**
|
|
121
|
+
* Turn the whole scale this many degrees clockwise, the way a compass card
|
|
122
|
+
* turns under a fixed lubber line. Animated by `transition`, always the
|
|
123
|
+
* shortest way round.
|
|
124
|
+
* @defaultValue 0
|
|
125
|
+
*/
|
|
126
|
+
rotate?: number;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* The context a round gauge root publishes to its children. Shared by
|
|
130
|
+
* `Gauge` and `GaugeInset` so a gauge nested inside another animates and
|
|
131
|
+
* maps values exactly like a top-level one, and so the defaults live in one
|
|
132
|
+
* place.
|
|
133
|
+
*/
|
|
134
|
+
export declare const useGaugeContextValue: ({ startAngle, endAngle, radius, rotate, ...domain }: GaugeDomainProps) => GaugeContextValue & GaugeRoundShape;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { clamp, foldValue, valueToAngle } from "./math.js";
|
|
3
|
+
import { arcScale } from "./scale.js";
|
|
4
|
+
import { useAnimatedValue } from "./use-animated-value.js";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
//#region src/components/gauge/context.tsx
|
|
7
|
+
var GaugeContext = React.createContext(null);
|
|
8
|
+
var useGauge = () => {
|
|
9
|
+
const ctx = React.useContext(GaugeContext);
|
|
10
|
+
if (!ctx) throw new Error("Gauge primitives must be rendered inside <Gauge>.");
|
|
11
|
+
return ctx;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Alias of `useGauge` for parts that historically required a round root
|
|
15
|
+
* (needle). All public gauges are round; linear bars stay on `Slider`.
|
|
16
|
+
*/
|
|
17
|
+
var useRoundGauge = (part) => {
|
|
18
|
+
return useGauge();
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Resolves the domain and follows the value: the half of a gauge's context
|
|
22
|
+
* that is the same whatever its shape.
|
|
23
|
+
*/
|
|
24
|
+
var useGaugeReading = ({ value, min = 0, max = 100, transition, initialValue, wrap = false }) => {
|
|
25
|
+
const lo = Math.min(min, max);
|
|
26
|
+
const hi = Math.max(min, max);
|
|
27
|
+
const span = hi - lo;
|
|
28
|
+
const fold = (v) => foldValue(v, lo, hi);
|
|
29
|
+
const settle = wrap ? fold : (v) => clamp(v, lo, hi);
|
|
30
|
+
const range = typeof value !== "number";
|
|
31
|
+
const ends = (pair) => wrap ? [settle(pair[0]), settle(pair[1])] : [settle(Math.min(pair[0], pair[1])), settle(Math.max(pair[0], pair[1]))];
|
|
32
|
+
const [targetFrom, target] = range ? ends(value) : [min, settle(value)];
|
|
33
|
+
let initialFrom;
|
|
34
|
+
let initialTo;
|
|
35
|
+
if (initialValue === void 0) {
|
|
36
|
+
initialFrom = void 0;
|
|
37
|
+
initialTo = void 0;
|
|
38
|
+
} else if (typeof initialValue === "number") {
|
|
39
|
+
initialFrom = settle(initialValue);
|
|
40
|
+
initialTo = settle(initialValue);
|
|
41
|
+
} else if (range) [initialFrom, initialTo] = ends(initialValue);
|
|
42
|
+
else {
|
|
43
|
+
initialFrom = void 0;
|
|
44
|
+
initialTo = settle(initialValue[1]);
|
|
45
|
+
}
|
|
46
|
+
const shown = useAnimatedValue(target, transition, span, initialTo, wrap);
|
|
47
|
+
const shownFrom = useAnimatedValue(targetFrom, transition, span, range ? initialFrom : void 0, wrap);
|
|
48
|
+
return {
|
|
49
|
+
value: wrap ? fold(shown) : shown,
|
|
50
|
+
target,
|
|
51
|
+
from: range && wrap ? fold(shownFrom) : shownFrom,
|
|
52
|
+
targetFrom,
|
|
53
|
+
range,
|
|
54
|
+
wrap,
|
|
55
|
+
min,
|
|
56
|
+
max
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* The context a round gauge root publishes to its children. Shared by
|
|
61
|
+
* `Gauge` and `GaugeInset` so a gauge nested inside another animates and
|
|
62
|
+
* maps values exactly like a top-level one, and so the defaults live in one
|
|
63
|
+
* place.
|
|
64
|
+
*/
|
|
65
|
+
var useGaugeContextValue = ({ startAngle = 40, endAngle = 320, radius = 200, rotate = 0, ...domain }) => {
|
|
66
|
+
const reading = useGaugeReading(domain);
|
|
67
|
+
const turned = useAnimatedValue(rotate, domain.transition, 360, void 0, true);
|
|
68
|
+
const a0 = startAngle + turned;
|
|
69
|
+
const a1 = endAngle + turned;
|
|
70
|
+
const angleOf = (v) => valueToAngle(v, reading.min, reading.max, a0, a1);
|
|
71
|
+
return {
|
|
72
|
+
...reading,
|
|
73
|
+
shape: "round",
|
|
74
|
+
scale: arcScale(radius, a0, a1),
|
|
75
|
+
positionOf: angleOf,
|
|
76
|
+
startAngle: a0,
|
|
77
|
+
endAngle: a1,
|
|
78
|
+
radius,
|
|
79
|
+
angleOf
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
//#endregion
|
|
83
|
+
export { GaugeContext, useGauge, useGaugeContextValue, useRoundGauge };
|