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
1 change: 1 addition & 0 deletions knip.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export default {
entry: [
...PACKAGE_FILES,
...SOURCE_INDEX,
...EXAMPLE_ENTRIES,
...TEST_ENTRIES,
...TEST_VARIANT_ENTRIES,
...VITE_CONFIGS,
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 36 additions & 1 deletion projects/internals/metadata/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@
"../../forms/dist/custom-elements.json",
"../../markdown/package.json",
"../../markdown/dist/custom-elements.json",
"../../media/package.json",
"../../media/dist/custom-elements.json",
"../../monaco/package.json",
"../../monaco/dist/custom-elements.json",
"../../patterns/package.json",
Expand Down Expand Up @@ -142,6 +144,10 @@
"script": "../../markdown:build",
"cascade": false
},
{
"script": "../../media:build",
"cascade": false
},
{
"script": "../../monaco:build",
"cascade": false
Expand Down Expand Up @@ -171,6 +177,9 @@
"../../markdown/package.json",
"../../markdown/README.md",
"../../markdown/CHANGELOG.md",
"../../media/package.json",
"../../media/README.md",
"../../media/CHANGELOG.md",
"../../monaco/package.json",
"../../monaco/README.md",
"../../monaco/CHANGELOG.md",
Expand Down Expand Up @@ -212,6 +221,11 @@
"../../markdown/coverage/unit/summary.json",
"../../markdown/coverage/visual/summary.json",
"../../markdown/coverage/ssr/summary.json",
"../../media/coverage/unit/coverage-summary.json",
"../../media/coverage/unit/summary.json",
"../../media/coverage/axe/summary.json",
"../../media/coverage/visual/summary.json",
"../../media/coverage/ssr/summary.json",
"../../monaco/coverage/unit/coverage-summary.json",
"../../monaco/coverage/unit/summary.json",
"../../monaco/coverage/visual/summary.json",
Expand Down Expand Up @@ -259,6 +273,22 @@
"script": "../../markdown:test:coverage",
"cascade": false
},
{
"script": "../../media:test:coverage",
"cascade": false
},
{
"script": "../../media:test:axe",
"cascade": false
},
{
"script": "../../media:test:ssr",
"cascade": false
},
{
"script": "../../media:test:visual",
"cascade": false
},
{
"script": "../../monaco:test:coverage",
"cascade": false
Expand Down Expand Up @@ -291,7 +321,8 @@
"../../monaco/dist/**/*.examples.json",
"../../code/dist/**/*.examples.json",
"../../forms/dist/**/*.examples.json",
"../../markdown/dist/**/*.examples.json"
"../../markdown/dist/**/*.examples.json",
"../../media/dist/**/*.examples.json"
],
"output": [
"static/examples.json"
Expand Down Expand Up @@ -321,6 +352,10 @@
"script": "../../monaco:build",
"cascade": false
},
{
"script": "../../media:build",
"cascade": false
},
{
"script": "../patterns:build",
"cascade": false
Expand Down
8 changes: 7 additions & 1 deletion projects/internals/metadata/src/services/api.service.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { describe, expect, it } from 'vitest';
import MiniSearch from 'minisearch';
import { describe, expect, it, vi } from 'vitest';
import { ApiService } from './api.service.js';

describe('ApiService', () => {
Expand Down Expand Up @@ -41,7 +42,12 @@ describe('ApiService', () => {
});

it('should prioritize exact matches over fuzzy matches', async () => {
const searchSpy = vi.spyOn(MiniSearch.prototype, 'search').mockReturnValue([
{ id: 'nve-button-group', terms: ['button'], queryTerms: ['button'], score: 2, match: {} },
{ id: 'nve-button', terms: ['button'], queryTerms: ['button'], score: 1, match: {} }
]);
const results = await ApiService.search('nve-button');
searchSpy.mockRestore();
Comment thread
coryrylan marked this conversation as resolved.

expect(results[0]?.name).toBe('nve-button');
});
Expand Down
57 changes: 57 additions & 0 deletions projects/internals/metadata/src/tasks/api.utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,65 @@
import { describe, expect, it } from 'vitest';
import { getApi } from './api.utils.js';

type Api = Awaited<ReturnType<typeof getApi>>;
type ApiElement = Api['data']['elements'][number];

function getElement(api: Api, name: string) {
return api.data.elements.find(element => element.name === name);
}

function getMember(element: ApiElement | undefined, name: string) {
return element?.manifest?.members.find(member => member.name === name);
}

function getAttribute(element: ApiElement | undefined, name: string) {
return element?.manifest?.attributes?.find(attribute => attribute.name === name);
}

describe('ApiUtils', () => {
it('should return the api json', async () => {
expect(getApi).toBeDefined();
});
Comment thread
coryrylan marked this conversation as resolved.

it('should include attribute names for inherited button members', async () => {
const api = await getApi();
const button = getElement(api, 'nve-button');

expect(getMember(button, 'pressed')?.attribute).toBe('pressed');
expect(getMember(button, 'readOnly')?.attribute).toBe('readonly');
expect(getMember(button, 'commandForElement')?.attribute).toBe('commandfor');
expect(button?.markdown).toContain('| readOnly (readonly) |');
});

it('should project checkbox and button mixin APIs onto media mute button', async () => {
const api = await getApi();
const muteButton = getElement(api, 'nve-media-mute-button');

expect(getMember(muteButton, 'pressed')?.attribute).toBe('pressed');
expect(getMember(muteButton, 'checked')?.attribute).toBe('checked');
expect(getMember(muteButton, 'readOnly')?.attribute).toBe('readonly');
expect(getMember(muteButton, 'commandForElement')?.attribute).toBe('commandfor');
expect(getAttribute(muteButton, 'commandForElement')).toBeUndefined();
expect(muteButton?.markdown).toContain('| checked |');
});

it('should project slider mixin APIs onto media time range', async () => {
const api = await getApi();
const timeRange = getElement(api, 'nve-media-time-range');

expect(getMember(timeRange, 'min')?.attribute).toBe('min');
expect(getMember(timeRange, 'valueAsNumber')?.attribute).toBeUndefined();
expect(getAttribute(timeRange, 'commandForElement')).toBeUndefined();
expect(timeRange?.markdown).toContain('| valueAsNumber |');
});

it('should project select mixin APIs onto media playback rate select', async () => {
const api = await getApi();
const playbackRateSelect = getElement(api, 'nve-media-playback-rate-select');

expect(getMember(playbackRateSelect, 'selectedIndex')?.attribute).toBeUndefined();
expect(getMember(playbackRateSelect, 'value')?.attribute).toBe('value');
expect(getAttribute(playbackRateSelect, 'commandForElement')).toBeUndefined();
expect(playbackRateSelect?.markdown).toContain('| selectedIndex |');
});
});
1 change: 1 addition & 0 deletions projects/internals/metadata/src/tasks/api.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export async function getApi(): Promise<{
'../../../../themes',
'../../../../code',
'../../../../markdown',
'../../../../media',
'../../../../monaco'
];

Expand Down
4 changes: 2 additions & 2 deletions projects/internals/metadata/static/adoption.json
Git LFS file not shown
4 changes: 2 additions & 2 deletions projects/internals/metadata/static/releases.json
Git LFS file not shown
4 changes: 2 additions & 2 deletions projects/internals/metadata/static/tests.json
Git LFS file not shown
30 changes: 30 additions & 0 deletions projects/internals/tools/src/api/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,43 @@ describe('ApiService', () => {
const result = await ApiService.get({ names: 'nve-button', format: 'markdown' });
expect(typeof result).toBe('string');
expect(result as string).toContain('nve-button');
expect(result as string).toContain('| readOnly (readonly) |');
});

it('should return projected mixin api for directly mixed components', async () => {
const result = await ApiService.get({ names: 'nve-media-mute-button', format: 'markdown' });
expect(typeof result).toBe('string');
expect(result as string).toContain('| pressed |');
expect(result as string).toContain('| checked |');
expect(result as string).toContain('| readOnly (readonly) |');
expect(result as string).toContain('| commandForElement (commandfor) |');
expect(result as string).not.toContain('| commandForElement (commandForElement) |');
});

it('should return json for a single string name', async () => {
const result = (await ApiService.get({ names: 'nve-button', format: 'json' })) as (Element | Attribute)[];
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(1);
expect(result[0].name).toBe('nve-button');

const button = result[0] as Element;
const readOnly = button.manifest?.members.find(member => member.name === 'readOnly');

expect(readOnly?.attribute).toBe('readonly');
});

it('should return json with projected mixin attributes for directly mixed components', async () => {
const result = (await ApiService.get({ names: 'nve-media-mute-button', format: 'json' })) as (
| Element
| Attribute
)[];
const muteButton = result[0] as Element;
const checked = muteButton.manifest?.members.find(member => member.name === 'checked');
const commandForElement = muteButton.manifest?.members.find(member => member.name === 'commandForElement');

expect(checked?.attribute).toBe('checked');
expect(commandForElement?.attribute).toBe('commandfor');
expect(muteButton.manifest?.attributes?.some(attribute => attribute.name === 'commandForElement')).toBe(false);
});

it('should return markdown for an array with one name', async () => {
Expand Down
2 changes: 2 additions & 0 deletions projects/internals/tools/src/playground/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ describe('createImportMap with different frameworks', () => {
expect(importmap.imports['@nvidia-elements/monaco']).toContain('/@nvidia-elements/monaco@latest');
expect(importmap.imports['@nvidia-elements/code']).toContain('/@nvidia-elements/code@latest');
expect(importmap.imports['@nvidia-elements/forms']).toContain('/@nvidia-elements/forms@latest');
expect(importmap.imports['@nvidia-elements/media']).toBe('https://esm.sh/@nvidia-elements/media@latest');
expect(importmap.imports['@nvidia-elements/media/']).toBe('https://esm.sh/@nvidia-elements/media@latest/');
});
});

Expand Down
2 changes: 2 additions & 0 deletions projects/internals/tools/src/playground/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ function createImportMap(framework: 'react' | 'preact' | 'angular' | 'lit' | 'vu
'@nvidia-elements/code/': `${CDN_MODULES_URL}/@nvidia-elements/code@latest/`,
'@nvidia-elements/forms': `${CDN_MODULES_URL}/@nvidia-elements/forms@latest`,
'@nvidia-elements/forms/': `${CDN_MODULES_URL}/@nvidia-elements/forms@latest/`,
'@nvidia-elements/media': `${CDN_MODULES_URL}/@nvidia-elements/media@latest`,
'@nvidia-elements/media/': `${CDN_MODULES_URL}/@nvidia-elements/media@latest/`,
Comment thread
coryrylan marked this conversation as resolved.
...(frameworkImportMap[framework]?.(CDN_MODULES_URL) ?? {})
};

Expand Down
14 changes: 11 additions & 3 deletions projects/lint/src/eslint/rules/no-invalid-invoker-triggers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import noInvalidInvokerTriggers from './no-invalid-invoker-triggers.js';
const rule = noInvalidInvokerTriggers as unknown as JSRuleDefinition;

const validElements =
'nve-button, nve-icon-button, nve-menu-item, nve-sort-button, nve-tabs-item, nve-tag, nve-steps-item, nve-copy-button';
'nve-button, nve-icon-button, nve-menu-item, nve-sort-button, nve-tabs-item, nve-tag, nve-steps-item, nve-copy-button, nve-media-fullscreen-button, nve-media-mute-button, nve-media-pause-button, nve-media-playback-rate-select, nve-media-seek-button, nve-media-time-range, nve-media-volume-range';

describe('noInvalidInvokerTriggers', () => {
let tester: RuleTester;
Expand Down Expand Up @@ -50,7 +50,8 @@ describe('noInvalidInvokerTriggers', () => {
'<nve-tabs-item popovertarget="my-popover">Tab</nve-tabs-item>',
'<nve-tag popovertarget="my-popover">Tag</nve-tag>',
'<nve-steps-item popovertarget="my-popover">Step</nve-steps-item>',
'<nve-copy-button popovertarget="my-popover"></nve-copy-button>'
'<nve-copy-button popovertarget="my-popover"></nve-copy-button>',
'<nve-media-fullscreen-button popovertarget="my-popover"></nve-media-fullscreen-button>'
],
invalid: []
});
Expand All @@ -61,7 +62,14 @@ describe('noInvalidInvokerTriggers', () => {
valid: [
'<nve-button commandfor="my-panel">Toggle</nve-button>',
'<nve-icon-button commandfor="my-panel"></nve-icon-button>',
'<nve-tag commandfor="my-panel">Tag</nve-tag>'
'<nve-tag commandfor="my-panel">Tag</nve-tag>',
'<nve-media-pause-button commandfor="my-player"></nve-media-pause-button>',
'<nve-media-playback-rate-select commandfor="my-player"></nve-media-playback-rate-select>',
'<nve-media-mute-button commandfor="my-player"></nve-media-mute-button>',
'<nve-media-seek-button commandfor="my-player"></nve-media-seek-button>',
'<nve-media-time-range commandfor="my-player"></nve-media-time-range>',
'<nve-media-volume-range commandfor="my-player"></nve-media-volume-range>',
'<nve-media-fullscreen-button commandfor="my-player"></nve-media-fullscreen-button>'
],
invalid: []
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ const BUTTON_TYPE_ELEMENTS = [
'nve-tabs-item',
'nve-tag',
'nve-steps-item',
'nve-copy-button'
'nve-copy-button',
'nve-media-fullscreen-button',
'nve-media-mute-button',
'nve-media-pause-button',
'nve-media-playback-rate-select',
'nve-media-seek-button',
'nve-media-time-range',
'nve-media-volume-range'
Comment thread
coryrylan marked this conversation as resolved.
] as const;

const rule = {
Expand Down
3 changes: 3 additions & 0 deletions projects/media/.visual/media-controller.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/media/.visual/media-controller.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/media/.visual/media-fullscreen-button.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/media/.visual/media-fullscreen-button.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/media/.visual/media-mute-button.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/media/.visual/media-mute-button.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/media/.visual/media-pause-button.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/media/.visual/media-pause-button.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/media/.visual/media-playback-rate-select.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/media/.visual/media-playback-rate-select.png

@coryrylan coryrylan Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

todo: select should have inline style disable like icon button here

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/media/.visual/media-seek-button.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/media/.visual/media-seek-button.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/media/.visual/media-time-range.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/media/.visual/media-time-range.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/media/.visual/media-volume-range.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/media/.visual/media-volume-range.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading