Skip to content

Commit 70e115d

Browse files
committed
feat(core): gauge
Signed-off-by: Cory Rylan <crylan@nvidia.com>
1 parent 0b895ff commit 70e115d

22 files changed

Lines changed: 1439 additions & 10 deletions

File tree

‎config/vale/styles/config/vocabularies/Elements/accept.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ nve-dropdown
239239
nve-dropdown-group
240240
nve-dropzone
241241
nve-file
242+
nve-gauge
242243
nve-grid
243244
nve-icon
244245
nve-icon-button
@@ -358,3 +359,5 @@ spark line
358359
spark lines
359360
Alternatively
360361
misprefixed
362+
indicate
363+
utilization
Lines changed: 3 additions & 0 deletions
Loading

‎projects/core/.visual/gauge.png‎

Lines changed: 3 additions & 0 deletions
Loading

‎projects/core/package.json‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,18 @@
421421
"types": "./dist/forms/define.d.ts",
422422
"default": "./dist/forms/define.js"
423423
},
424+
"./gauge": {
425+
"types": "./dist/gauge/index.d.ts",
426+
"default": "./dist/gauge/index.js"
427+
},
428+
"./gauge/index.js": {
429+
"types": "./dist/gauge/index.d.ts",
430+
"default": "./dist/gauge/index.js"
431+
},
432+
"./gauge/define.js": {
433+
"types": "./dist/gauge/define.d.ts",
434+
"default": "./dist/gauge/define.js"
435+
},
424436
"./grid": {
425437
"types": "./dist/grid/index.d.ts",
426438
"default": "./dist/grid/index.js"

‎projects/core/src/bundle.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import '@nvidia-elements/core/format-datetime/define.js';
3131
import'@nvidia-elements/core/format-number/define.js';
3232
import'@nvidia-elements/core/format-relative-time/define.js';
3333
import'@nvidia-elements/core/forms/define.js';
34+
import'@nvidia-elements/core/gauge/define.js';
3435
import'@nvidia-elements/core/grid/define.js';
3536
import'@nvidia-elements/core/icon/define.js';
3637
import'@nvidia-elements/core/icon-button/define.js';
@@ -99,6 +100,7 @@ export * from '@nvidia-elements/core/format-datetime';
99100
export*from'@nvidia-elements/core/format-number';
100101
export*from'@nvidia-elements/core/format-relative-time';
101102
export*from'@nvidia-elements/core/forms';
103+
export*from'@nvidia-elements/core/gauge';
102104
export*from'@nvidia-elements/core/grid';
103105
export*from'@nvidia-elements/core/icon';
104106
export*from'@nvidia-elements/core/icon-button';

‎projects/core/src/gauge/define.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import{define}from'@nvidia-elements/core/internal';
5+
import{Gauge}from'@nvidia-elements/core/gauge';
6+
7+
define(Gauge);
8+
9+
declare global {
10+
interfaceHTMLElementTagNameMap{
11+
'nve-gauge': Gauge;
12+
}
13+
}

‎projects/core/src/gauge/gauge.css‎

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
2+
/* SPDX-License-Identifier: Apache-2.0 */
3+
4+
:host {
5+
--color: var(--nve-sys-text-emphasis-color);
6+
--background: var(--nve-sys-interaction-background);
7+
--needle-background: var(--nve-sys-interaction-color);
8+
--accent-color: var(--nve-sys-interaction-color);
9+
--thumb-background: var(--accent-color);
10+
--track-background: var(--accent-color);
11+
--track-width: 8px;
12+
--font-size: var(--nve-ref-font-size-400);
13+
--font-weight: var(--nve-ref-font-weight-regular);
14+
--gap: var(--nve-ref-space-xs);
15+
--width: 128px;
16+
--height: calc(var(--width) * 0.8627);
17+
--_animation-duration: var(--nve-ref-animation-duration-250);
18+
--_needle-size: calc(var(--track-width) / 3);
19+
20+
display: inline-block;
21+
position: relative;
22+
width: var(--width);
23+
height: var(--height);
24+
font-weight: var(--font-weight);
25+
container-type: inline-size;
26+
contain: layout;
27+
text-box: trim-both cap alphabetic;
28+
}
29+
30+
.fill-dot-start,
31+
.fill-dot-end {
32+
r:calc(var(--track-width) /2.4);
33+
}
34+
35+
:host([size='sm']) {
36+
--font-size:var(--nve-ref-font-size-300);
37+
--width:96px;
38+
--_needle-size:calc(var(--track-width) /2.25);
39+
40+
.fill-dot-start,
41+
.fill-dot-end {
42+
r:calc(var(--track-width) /1.8);
43+
}
44+
}
45+
46+
:host([size='lg']) {
47+
--font-size:var(--nve-ref-font-size-500);
48+
--width:160px;
49+
--_needle-size:calc(var(--track-width) /3.75);
50+
51+
.fill-dot-start,
52+
.fill-dot-end {
53+
r:calc(var(--track-width) /3);
54+
}
55+
}
56+
57+
[internal-host] {
58+
display: grid;
59+
place-items: center;
60+
position: relative;
61+
height:100%;
62+
}
63+
64+
:host([shape='half']) {
65+
--height:calc(var(--width) *0.5313);
66+
}
67+
68+
:host([shape='half']) [internal-host] {
69+
place-items: end center;
70+
}
71+
72+
svg {
73+
position: absolute;
74+
inset:0;
75+
width:100%;
76+
height:100%;
77+
overflow: visible;
78+
}
79+
80+
path {
81+
fill: none;
82+
stroke: white;
83+
stroke-width:var(--track-width);
84+
vector-effect: non-scaling-stroke;
85+
}
86+
87+
path.background {
88+
stroke-linecap: round;
89+
}
90+
91+
path.gauge {
92+
animation: gauge-progress-in var(--_animation-duration) var(--nve-ref-animation-easing-100);
93+
stroke-linecap: butt;
94+
stroke-dasharray:var(--_dash-progress) var(--_dash-gap);
95+
transition: stroke-dasharray var(--_animation-duration) var(--nve-ref-animation-easing-100);
96+
will-change: stroke-dasharray;
97+
}
98+
99+
.background-surface,
100+
.fill-surface {
101+
inline-size:100%;
102+
block-size:100%;
103+
}
104+
105+
.background-surface {
106+
background:var(--background);
107+
}
108+
109+
.fill-surface {
110+
background:var(--track-background);
111+
}
112+
113+
.fill-dot-start {
114+
fill:var(--track-background);
115+
}
116+
117+
.fill-dot-end {
118+
animation: gauge-dot-in var(--_animation-duration) var(--nve-ref-animation-easing-100);
119+
fill:var(--thumb-background);
120+
transform:rotate(var(--_dot-angle));
121+
transform-box: view-box;
122+
transform-origin:var(--_dot-origin);
123+
transition: transform var(--_animation-duration) var(--nve-ref-animation-easing-100);
124+
will-change: transform;
125+
}
126+
127+
.fill-layer[hidden],
128+
.fill-dot-start[hidden],
129+
.fill-dot-end[hidden],
130+
.needle[hidden] {
131+
display: none;
132+
}
133+
134+
.needle {
135+
animation: gauge-needle-in var(--_animation-duration) var(--nve-ref-animation-easing-100);
136+
transform:rotate(var(--_needle-angle));
137+
transform-box: view-box;
138+
transform-origin:var(--_needle-origin);
139+
transition: transform var(--_animation-duration) var(--nve-ref-animation-easing-100);
140+
will-change: transform;
141+
}
142+
143+
.needle-line {
144+
stroke:var(--needle-background);
145+
stroke-linecap: round;
146+
stroke-width:var(--_needle-size);
147+
}
148+
149+
.needle-hub {
150+
fill:var(--needle-background);
151+
r:var(--_needle-size);
152+
}
153+
154+
slot {
155+
display: flex;
156+
flex-direction: column;
157+
place-items: center;
158+
justify-content: center;
159+
height:100%;
160+
gap:var(--gap);
161+
color:var(--color);
162+
font-size:var(--font-size);
163+
font-weight:var(--nve-ref-font-weight-medium);
164+
padding-block-start:calc(var(--track-width) *2);
165+
text-box: trim-both cap alphabetic;
166+
line-height:1;
167+
width:50%;
168+
font-variant-numeric: tabular-nums;
169+
}
170+
171+
:host([shape='half']) slot {
172+
transform:translateY(1cqh);
173+
}
174+
175+
:host([thumb='needle']) slot {
176+
transform:translateY(1cqh);
177+
justify-content: end;
178+
}
179+
180+
:host([shape='half'][thumb='needle']) slot {
181+
transform:translateY(2cqh);
182+
}
183+
184+
::slotted(*) {
185+
color:var(--color);
186+
font-size:var(--font-size);
187+
}
188+
189+
:host([status='success']) {
190+
--accent-color:var(--nve-sys-support-success-emphasis-color);
191+
--background:var(--nve-sys-support-success-muted-color);
192+
}
193+
194+
:host([status='warning']) {
195+
--accent-color:var(--nve-sys-support-warning-emphasis-color);
196+
--background:var(--nve-sys-support-warning-muted-color);
197+
}
198+
199+
:host([status='danger']) {
200+
--accent-color:var(--nve-sys-support-danger-emphasis-color);
201+
--background:var(--nve-sys-support-danger-muted-color);
202+
}
203+
204+
:host([status='accent']) {
205+
--accent-color:var(--nve-sys-accent-secondary-background);
206+
}
207+
208+
@media (prefers-reduced-motion: reduce) {
209+
:host {
210+
--_animation-duration:0s;
211+
}
212+
}
213+
214+
@keyframes gauge-progress-in {
215+
from {
216+
stroke-dasharray:0var(--_dash-gap);
217+
}
218+
219+
to {
220+
stroke-dasharray:var(--_dash-progress) var(--_dash-gap);
221+
}
222+
}
223+
224+
@keyframes gauge-dot-in {
225+
from {
226+
transform:rotate(var(--_dot-start-angle));
227+
}
228+
229+
to {
230+
transform:rotate(var(--_dot-angle));
231+
}
232+
}
233+
234+
@keyframes gauge-needle-in {
235+
from {
236+
transform:rotate(var(--_needle-start-angle));
237+
}
238+
239+
to {
240+
transform:rotate(var(--_needle-angle));
241+
}
242+
}

0 commit comments

Comments
 (0)