Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions projects/core/.visual/progress-gauge.dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions projects/core/.visual/progress-gauge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions projects/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,18 @@
"types": "./dist/progress-bar/define.d.ts",
"default": "./dist/progress-bar/define.js"
},
"./progress-gauge": {
"types": "./dist/progress-gauge/index.d.ts",
"default": "./dist/progress-gauge/index.js"
},
"./progress-gauge/index.js": {
"types": "./dist/progress-gauge/index.d.ts",
"default": "./dist/progress-gauge/index.js"
},
"./progress-gauge/define.js": {
"types": "./dist/progress-gauge/define.d.ts",
"default": "./dist/progress-gauge/define.js"
},
"./progress-ring": {
"types": "./dist/progress-ring/index.d.ts",
"default": "./dist/progress-ring/index.js"
Expand Down
2 changes: 2 additions & 0 deletions projects/core/src/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import '@nvidia-elements/core/panel/define.js';
import '@nvidia-elements/core/password/define.js';
import '@nvidia-elements/core/preferences-input/define.js';
import '@nvidia-elements/core/progress-bar/define.js';
import '@nvidia-elements/core/progress-gauge/define.js';
import '@nvidia-elements/core/progress-ring/define.js';
import '@nvidia-elements/core/progressive-filter-chip/define.js';
import '@nvidia-elements/core/pulse/define.js';
Expand Down Expand Up @@ -115,6 +116,7 @@ export * from '@nvidia-elements/core/panel';
export * from '@nvidia-elements/core/password';
export * from '@nvidia-elements/core/preferences-input';
export * from '@nvidia-elements/core/progress-bar';
export * from '@nvidia-elements/core/progress-gauge';
export * from '@nvidia-elements/core/progress-ring';
export * from '@nvidia-elements/core/progressive-filter-chip';
export * from '@nvidia-elements/core/pulse';
Expand Down
3 changes: 2 additions & 1 deletion projects/core/src/index.test.lighthouse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('lighthouse report', () => {
expect(report.scores.performance).toBe(100);
expect(report.scores.accessibility).toBe(100);
expect(report.scores.bestPractices).toBe(100);
expect(report.payload.javascript.requests['index.js'].kb).toBeLessThan(130.5);
expect(report.payload.javascript.requests['index.js'].kb).toBeLessThan(132);

// if sudden drop in size, check vite bundle config and bundle demo to ensure side effects are properly preserved
expect(report.payload.javascript.requests['index.js'].kb).toBeGreaterThan(120);
Expand Down Expand Up @@ -62,6 +62,7 @@ describe('lighthouse report', () => {
import '@nvidia-elements/core/password/define.js';
import '@nvidia-elements/core/preferences-input/define.js';
import '@nvidia-elements/core/progress-bar/define.js';
import '@nvidia-elements/core/progress-gauge/define.js';
import '@nvidia-elements/core/progress-ring/define.js';
import '@nvidia-elements/core/progressive-filter-chip/define.js';
import '@nvidia-elements/core/radio/define.js';
Expand Down
13 changes: 13 additions & 0 deletions projects/core/src/progress-gauge/define.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { define } from '@nvidia-elements/core/internal';
import { ProgressGauge } from '@nvidia-elements/core/progress-gauge';

define(ProgressGauge);

declare global {
interface HTMLElementTagNameMap {
'nve-progress-gauge': ProgressGauge;
}
}
4 changes: 4 additions & 0 deletions projects/core/src/progress-gauge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

export * from './progress-gauge.js';
134 changes: 134 additions & 0 deletions projects/core/src/progress-gauge/progress-gauge.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
/* SPDX-License-Identifier: Apache-2.0 */

:host {
--color: var(--nve-sys-text-emphasis-color);
--background: var(--nve-sys-interaction-background);
--accent-color: var(--nve-sys-interaction-color);
--gauge-width: 12px;
--font-size: var(--nve-ref-font-size-400);
--gap: var(--nve-ref-space-xs);
--width: 128px;
--height: var(--width);
--_animation-duration: var(--nve-ref-animation-duration-250);

display: inline-block;
position: relative;
width: var(--width);
height: var(--height);
container-type: inline-size;
contain: content;
text-box: trim-both cap alphabetic;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

:host([size='sm']) {
--font-size: var(--nve-ref-font-size-300);
--width: 96px;
}

:host([size='lg']) {
--font-size: var(--nve-ref-font-size-500);
--width: 160px;
}

[internal-host] {
display: grid;
place-items: center;
position: relative;
height: 100%;
}

:host([container='half']) {
--height: calc(var(--width) / 2);
}

:host([container='half']) [internal-host] {
place-items: end center;
}

svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
overflow: visible;
}

path {
fill: none;
stroke-linecap: round;
stroke-width: var(--gauge-width);
}

path.background {
stroke: var(--background);
}

path.gauge {
animation: gauge-progress-in var(--_animation-duration) var(--nve-ref-animation-easing-100);
stroke: var(--accent-color);
stroke-dasharray: var(--_progress) 100;
transition: stroke-dasharray var(--_animation-duration) var(--nve-ref-animation-easing-100);
will-change: stroke-dasharray;
}

path.gauge[empty] {
animation: none;
stroke-linecap: butt;
}

slot {
display: flex;
flex-direction: column;
place-items: center;
justify-content: center;
height: 100%;
gap: var(--gap);
color: var(--color);
font-size: var(--font-size);
font-weight: var(--nve-ref-font-weight-medium);
}

:host([container='half']) slot {
transform: translateY(10cqw);
}

::slotted(*) {
color: var(--color);
font-size: var(--font-size);
}
Comment on lines +96 to +99

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not override all consumer slotted typography.

::slotted(*) forces the same color and font-size onto every top-level child. That breaks multi-line content like projects/core/src/progress-gauge/progress-gauge.examples.ts Lines 110-113, where the secondary GPU label is explicitly marked nve-text="body sm muted" but will still render with the primary gauge text styling. Let the slot provide defaults via inheritance instead of restyling every assigned node.

Proposed fix
-::slotted(*) {
-  color: var(--color);
-  font-size: var(--font-size);
-}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
::slotted(*) {
color: var(--color);
font-size: var(--font-size);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@projects/core/src/progress-gauge/progress-gauge.css` around lines 96 - 99,
The `::slotted(*)` rule in `progress-gauge.css` is overriding every assigned
child’s typography, including consumer-provided styles like the muted secondary
label in the progress gauge example. Remove the blanket `color` and `font-size`
application from the slot styling and let slotted content inherit defaults
instead, keeping any necessary styling scoped to the gauge’s internal elements
rather than all top-level slotted nodes.


:host([status='success']) {
--accent-color: var(--nve-sys-support-success-emphasis-color);
--background: var(--nve-sys-support-success-muted-color);
}

:host([status='warning']) {
--accent-color: var(--nve-sys-support-warning-emphasis-color);
--background: var(--nve-sys-support-warning-muted-color);
}

:host([status='danger']) {
--accent-color: var(--nve-sys-support-danger-emphasis-color);
--background: var(--nve-sys-support-danger-muted-color);
}

:host([status='accent']) {
--accent-color: var(--nve-sys-accent-secondary-background);
}

@media (prefers-reduced-motion: reduce) {
:host {
--_animation-duration: 0s;
}
}

@keyframes gauge-progress-in {
from {
stroke-dasharray: 0 100;
}

to {
stroke-dasharray: var(--_progress) 100;
}
}
136 changes: 136 additions & 0 deletions projects/core/src/progress-gauge/progress-gauge.examples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { html } from 'lit';
import '@nvidia-elements/core/progress-gauge/define.js';

export default {
title: 'Elements/Progress Gauge',
component: 'nve-progress-gauge',
};

/**
* @summary 270-degree progress gauges for displaying system resource usage.
*/
export const Default = {
render: () => html`
<div nve-layout="row gap:sm">
<nve-progress-gauge value="50">50%</nve-progress-gauge>
<nve-progress-gauge status="accent" value="66">66%</nve-progress-gauge>
</div>
`};

/**
* @summary Container variants compare the default 270-degree gauge with the compact half gauge for telemetry layouts with tighter vertical space.
* @tags test-case
*/
export const Container = {
render: () => html`
<div nve-layout="row gap:sm align:vertical-center">
<nve-progress-gauge status="accent" value="66">66%</nve-progress-gauge>
<nve-progress-gauge container="half" status="accent" value="66">66%</nve-progress-gauge>
</div>
`};

/**
* @summary Gauges with values from 0% to 100% for displaying system resource usage.
* @tags test-case
*/
export const Values = {
render: () => html`
<div nve-layout="row gap:sm">
<nve-progress-gauge value="0">0%</nve-progress-gauge>
<nve-progress-gauge value="33">33%</nve-progress-gauge>
<nve-progress-gauge value="66">66%</nve-progress-gauge>
<nve-progress-gauge value="100">100%</nve-progress-gauge>
</div>
`};

/**
* @summary Progress gauges with custom max values for mission checkpoints, validation clips, and map tile processing.
* @tags test-case
*/
export const Max = {
render: () => html`
<div nve-layout="row gap:sm">
<nve-progress-gauge status="accent" max="20" value="5">5/20</nve-progress-gauge>
<nve-progress-gauge max="20" value="10">10/20</nve-progress-gauge>
<nve-progress-gauge max="20" value="15">15/20</nve-progress-gauge>
</div>
`};

/**
* @summary Progress gauges with accent, success, warning, and danger colors for autonomous system health and readiness signals.
* @tags test-case
*/
export const Status = {
render: () => html`
<div nve-layout="row gap:sm">
<nve-progress-gauge value="50">50%</nve-progress-gauge>
<nve-progress-gauge status="accent" value="75">75%</nve-progress-gauge>
<nve-progress-gauge status="success" value="75">75%</nve-progress-gauge>
<nve-progress-gauge status="warning" value="75">2.1m</nve-progress-gauge>
<nve-progress-gauge status="danger" value="75">0Hz</nve-progress-gauge>
</div>
`};

/**
* @summary Small progress gauge paired with route-solve text for compact autonomous vehicle task rows.
* @tags test-case
*/
export const WithText = {
render: () => html`
<div nve-layout="row gap:xs align:vertical-center" nve-text="medium">
<nve-progress-gauge status="accent" size="sm" value="50" aria-labelledby="route-solve-label">2.4s</nve-progress-gauge>
<span id="route-solve-label">Route solve</span>
</div>
`};

/**
* @summary Progress gauges in small, medium, and large sizes for dense robotics and autonomous vehicle dashboards.
* @tags test-case
*/
export const Sizing = {
render: () => html`
<div nve-layout="row gap:sm">
<nve-progress-gauge size="sm" value="50">30Hz</nve-progress-gauge>
<nve-progress-gauge size="md" value="50">12Hz</nve-progress-gauge>
<nve-progress-gauge size="lg" value="50">84%</nve-progress-gauge>
</div>
`};

/**
* @summary Use for displaying real-time system load and performance metrics.
* @tags pattern
*/
export const Dynamic = {
render: () => html`
<div nve-layout="row gap:sm">
<progress-gauge-dynamic-example style="display: contents">
<nve-progress-gauge status="success" value="0">
<span>0%</span>
<span nve-text="body sm muted">GPU</span>
</nve-progress-gauge>
</progress-gauge-dynamic-example>
</div>
<script type="module">
if (!customElements.get('progress-gauge-dynamic-example')) {
customElements.define('progress-gauge-dynamic-example', class extends HTMLElement {
connectedCallback() {
const gauge = this.querySelector('nve-progress-gauge');
const valueElement = gauge.querySelector('span');
this.timer = setInterval(() => {
const value = Math.floor(Math.random() * 101);
gauge.value = value;
gauge.status = value >= 80 ? 'danger' : value >= 60 ? 'warning' : 'success';
valueElement.textContent = value + '%';
}, 1500);
}

disconnectedCallback() {
clearInterval(this.timer);
}
});
}
</script>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
`};
33 changes: 33 additions & 0 deletions projects/core/src/progress-gauge/progress-gauge.test.axe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { html } from 'lit';
import { describe, expect, it, beforeEach, afterEach } from 'vitest';
import { createFixture, removeFixture, elementIsStable } from '@internals/testing';
import { runAxe } from '@internals/testing/axe';
import { ProgressGauge } from '@nvidia-elements/core/progress-gauge';
import '@nvidia-elements/core/progress-gauge/define.js';

describe(ProgressGauge.metadata.tag, () => {
let fixture: HTMLElement;

beforeEach(async () => {
fixture = await createFixture(html`
<nve-progress-gauge aria-label="progress" value="0"></nve-progress-gauge>
<nve-progress-gauge aria-label="progress" value="50"></nve-progress-gauge>
<nve-progress-gauge aria-label="progress" status="warning" value="75"></nve-progress-gauge>
<nve-progress-gauge aria-label="progress" container="half" status="success" value="100"></nve-progress-gauge>
`);
const elements = Array.from(fixture.querySelectorAll(ProgressGauge.metadata.tag)) as ProgressGauge[];
await Promise.all(elements.map(gauge => elementIsStable(gauge)));
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

afterEach(() => {
removeFixture(fixture);
});

it('should pass axe check', async () => {
const results = await runAxe([ProgressGauge.metadata.tag]);
expect(results.violations.length).toBe(0);
});
});
Loading