@nvidia-elements/core 2.7.3 → 2.8.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/CHANGELOG.md +23 -0
- package/README.md +8 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.139.0 → _@oxc-project_runtime@0.147.0}/helpers/esm/decorate.js +1 -1
- package/dist/accordion/accordion2.js +5 -5
- package/dist/accordion/accordion2.js.map +1 -1
- package/dist/alert/alert-group2.js +2 -2
- package/dist/alert/alert-group2.js.map +1 -1
- package/dist/alert/alert2.js +2 -2
- package/dist/alert/alert2.js.map +1 -1
- package/dist/avatar/avatar-group2.js +1 -1
- package/dist/avatar/avatar-group2.js.map +1 -1
- package/dist/avatar/avatar2.js +2 -2
- package/dist/avatar/avatar2.js.map +1 -1
- package/dist/badge/badge2.js +2 -2
- package/dist/badge/badge2.js.map +1 -1
- package/dist/breadcrumb/breadcrumb2.js +2 -2
- package/dist/breadcrumb/breadcrumb2.js.map +1 -1
- package/dist/bundles/index.d.ts +2 -0
- package/dist/bundles/index.js +6 -6
- package/dist/button/button2.js +2 -2
- package/dist/button/button2.js.map +1 -1
- package/dist/button-group/button-group2.js +2 -2
- package/dist/button-group/button-group2.js.map +1 -1
- package/dist/card/card2.js +5 -5
- package/dist/card/card2.js.map +1 -1
- package/dist/chat-message/chat-message2.js +2 -2
- package/dist/chat-message/chat-message2.js.map +1 -1
- package/dist/checkbox/checkbox-group2.js +2 -2
- package/dist/checkbox/checkbox-group2.js.map +1 -1
- package/dist/checkbox/checkbox2.js +2 -2
- package/dist/checkbox/checkbox2.js.map +1 -1
- package/dist/color/color2.js +2 -2
- package/dist/color/color2.js.map +1 -1
- package/dist/combobox/combobox.examples.js.map +1 -1
- package/dist/combobox/combobox2.js +7 -5
- package/dist/combobox/combobox2.js.map +1 -1
- package/dist/copy-button/copy-button2.js +2 -2
- package/dist/copy-button/copy-button2.js.map +1 -1
- package/dist/custom-elements-jsx.d.ts +2 -0
- package/dist/custom-elements-vue.d.ts +2 -0
- package/dist/custom-elements.json +9 -1
- package/dist/data.html.json +1 -1
- package/dist/date/date2.js +2 -2
- package/dist/date/date2.js.map +1 -1
- package/dist/datetime/datetime2.js +2 -2
- package/dist/datetime/datetime2.js.map +1 -1
- package/dist/dialog/dialog-footer2.js +2 -2
- package/dist/dialog/dialog-footer2.js.map +1 -1
- package/dist/dialog/dialog-header2.js +2 -2
- package/dist/dialog/dialog-header2.js.map +1 -1
- package/dist/dialog/dialog2.js +2 -2
- package/dist/dialog/dialog2.js.map +1 -1
- package/dist/divider/divider2.js +2 -2
- package/dist/divider/divider2.js.map +1 -1
- package/dist/dot/dot2.js +2 -2
- package/dist/dot/dot2.js.map +1 -1
- package/dist/drawer/drawer-content2.js +2 -2
- package/dist/drawer/drawer-content2.js.map +1 -1
- package/dist/drawer/drawer-footer2.js +2 -2
- package/dist/drawer/drawer-footer2.js.map +1 -1
- package/dist/drawer/drawer-header2.js +2 -2
- package/dist/drawer/drawer-header2.js.map +1 -1
- package/dist/drawer/drawer2.js +2 -2
- package/dist/drawer/drawer2.js.map +1 -1
- package/dist/dropdown/dropdown-footer2.js +2 -2
- package/dist/dropdown/dropdown-footer2.js.map +1 -1
- package/dist/dropdown/dropdown-header2.js +2 -2
- package/dist/dropdown/dropdown-header2.js.map +1 -1
- package/dist/dropdown/dropdown2.js +2 -2
- package/dist/dropdown/dropdown2.js.map +1 -1
- package/dist/dropdown-group/dropdown-group.js +2 -2
- package/dist/dropdown-group/dropdown-group.js.map +1 -1
- package/dist/dropzone/dropzone2.js +2 -2
- package/dist/dropzone/dropzone2.js.map +1 -1
- package/dist/file/file2.js +1 -1
- package/dist/file/file2.js.map +1 -1
- package/dist/format-bytes/format-bytes2.js +2 -2
- package/dist/format-bytes/format-bytes2.js.map +1 -1
- package/dist/format-datetime/format-datetime2.js +2 -2
- package/dist/format-datetime/format-datetime2.js.map +1 -1
- package/dist/format-number/format-number2.js +2 -2
- package/dist/format-number/format-number2.js.map +1 -1
- package/dist/format-relative-time/format-relative-time2.js +2 -2
- package/dist/format-relative-time/format-relative-time2.js.map +1 -1
- package/dist/format-truncate/format-truncate2.js +2 -2
- package/dist/format-truncate/format-truncate2.js.map +1 -1
- package/dist/forms/control/control2.js +2 -2
- package/dist/forms/control/control2.js.map +1 -1
- package/dist/forms/control-group/control-group2.js +2 -2
- package/dist/forms/control-group/control-group2.js.map +1 -1
- package/dist/forms/control-message/control-message2.js +2 -2
- package/dist/forms/control-message/control-message2.js.map +1 -1
- package/dist/forms/validation.examples.js.map +1 -1
- package/dist/gauge/gauge2.js +2 -2
- package/dist/gauge/gauge2.js.map +1 -1
- package/dist/grid/cell/cell2.js +1 -1
- package/dist/grid/cell/cell2.js.map +1 -1
- package/dist/grid/column/column2.js +2 -2
- package/dist/grid/column/column2.js.map +1 -1
- package/dist/grid/footer/footer2.js +2 -2
- package/dist/grid/footer/footer2.js.map +1 -1
- package/dist/grid/grid.examples.js.map +1 -1
- package/dist/grid/grid2.js +2 -2
- package/dist/grid/grid2.js.map +1 -1
- package/dist/grid/header/header2.js +2 -2
- package/dist/grid/header/header2.js.map +1 -1
- package/dist/grid/placeholder/placeholder2.js +1 -1
- package/dist/grid/placeholder/placeholder2.js.map +1 -1
- package/dist/grid/row/row2.js +2 -2
- package/dist/grid/row/row2.js.map +1 -1
- package/dist/icon/icon2.js +3 -3
- package/dist/icon/icon2.js.map +1 -1
- package/dist/icon-button/icon-button2.js +2 -2
- package/dist/icon-button/icon-button2.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/input/input-group2.js +1 -1
- package/dist/input/input-group2.js.map +1 -1
- package/dist/input/input2.js +2 -2
- package/dist/input/input2.js.map +1 -1
- package/dist/internal/controllers/audit.controller.js +9 -7
- package/dist/internal/controllers/audit.controller.js.map +1 -1
- package/dist/internal/controllers/gesture.controller.examples.js.map +1 -1
- package/dist/internal/controllers/gesture.controller.js +1 -3
- package/dist/internal/controllers/gesture.controller.js.map +1 -1
- package/dist/internal/controllers/i18n.controller.examples.js.map +1 -1
- package/dist/internal/controllers/i18n.controller.js.map +1 -1
- package/dist/internal/controllers/keynav-grid.controller.js.map +1 -1
- package/dist/internal/controllers/keynav-list.controller.js +1 -4
- package/dist/internal/controllers/keynav-list.controller.js.map +1 -1
- package/dist/internal/controllers/keynav-spatial.controller.js.map +1 -1
- package/dist/internal/controllers/state-scroll.controller.js.map +1 -1
- package/dist/internal/controllers/type-anchor.controller.js.map +1 -1
- package/dist/internal/controllers/type-closable.controller.js.map +1 -1
- package/dist/internal/controllers/type-expandable.controller.js.map +1 -1
- package/dist/internal/controllers/type-native-popover.controller.js.map +1 -1
- package/dist/internal/controllers/type-native-popover.utils.js +2 -2
- package/dist/internal/controllers/type-native-popover.utils.js.map +1 -1
- package/dist/internal/controllers/type-selectable.controller.js.map +1 -1
- package/dist/internal/controllers/type-ssr.controller.js.map +1 -1
- package/dist/internal/services/global.service.js +1 -1
- package/dist/internal/services/global.utils.js.map +1 -1
- package/dist/internal/services/log.service.js.map +1 -1
- package/dist/internal/services/transition.service.js.map +1 -1
- package/dist/internal/utils/dom.js +2 -1
- package/dist/internal/utils/dom.js.map +1 -1
- package/dist/internal/utils/strings.js +1 -1
- package/dist/internal/utils/strings.js.map +1 -1
- package/dist/logo/logo2.js +2 -2
- package/dist/logo/logo2.js.map +1 -1
- package/dist/menu/menu-item2.js +2 -2
- package/dist/menu/menu-item2.js.map +1 -1
- package/dist/menu/menu2.js +2 -2
- package/dist/menu/menu2.js.map +1 -1
- package/dist/month/month2.js +2 -2
- package/dist/month/month2.js.map +1 -1
- package/dist/notification/notification-group2.js +2 -2
- package/dist/notification/notification-group2.js.map +1 -1
- package/dist/notification/notification2.js +2 -2
- package/dist/notification/notification2.js.map +1 -1
- package/dist/page/page-panel/page-panel-content2.js +1 -1
- package/dist/page/page-panel/page-panel-content2.js.map +1 -1
- package/dist/page/page-panel/page-panel-footer2.js +2 -2
- package/dist/page/page-panel/page-panel-footer2.js.map +1 -1
- package/dist/page/page-panel/page-panel-header2.js +2 -2
- package/dist/page/page-panel/page-panel-header2.js.map +1 -1
- package/dist/page/page-panel/page-panel2.js +2 -2
- package/dist/page/page-panel/page-panel2.js.map +1 -1
- package/dist/page/page2.js +2 -2
- package/dist/page/page2.js.map +1 -1
- package/dist/page-header/page-header2.js +1 -1
- package/dist/page-header/page-header2.js.map +1 -1
- package/dist/page-loader/page-loader2.js +2 -2
- package/dist/page-loader/page-loader2.js.map +1 -1
- package/dist/pagination/pagination2.js +2 -2
- package/dist/pagination/pagination2.js.map +1 -1
- package/dist/panel/panel2.js +5 -5
- package/dist/panel/panel2.js.map +1 -1
- package/dist/password/password2.js +2 -2
- package/dist/password/password2.js.map +1 -1
- package/dist/polyfills/index.js +1 -1
- package/dist/polyfills/index.js.map +1 -1
- package/dist/preferences-input/preferences-input2.js +2 -2
- package/dist/preferences-input/preferences-input2.js.map +1 -1
- package/dist/progress-bar/progress-bar2.js +2 -2
- package/dist/progress-bar/progress-bar2.js.map +1 -1
- package/dist/progress-ring/progress-ring2.js +2 -2
- package/dist/progress-ring/progress-ring2.js.map +1 -1
- package/dist/progressive-filter-chip/progressive-filter-chip2.js +2 -2
- package/dist/progressive-filter-chip/progressive-filter-chip2.js.map +1 -1
- package/dist/pulse/pulse2.js +2 -2
- package/dist/pulse/pulse2.js.map +1 -1
- package/dist/radio/radio-group2.js +2 -2
- package/dist/radio/radio-group2.js.map +1 -1
- package/dist/radio/radio2.js +2 -2
- package/dist/radio/radio2.js.map +1 -1
- package/dist/range/range2.js +4 -4
- package/dist/range/range2.js.map +1 -1
- package/dist/resize-handle/resize-handle2.js +2 -2
- package/dist/resize-handle/resize-handle2.js.map +1 -1
- package/dist/search/search2.js +2 -2
- package/dist/search/search2.js.map +1 -1
- package/dist/select/select2.js +2 -2
- package/dist/select/select2.js.map +1 -1
- package/dist/skeleton/skeleton2.js +2 -2
- package/dist/skeleton/skeleton2.js.map +1 -1
- package/dist/sort-button/sort-button2.js +2 -2
- package/dist/sort-button/sort-button2.js.map +1 -1
- package/dist/sparkline/sparkline.utils.js +1 -3
- package/dist/sparkline/sparkline.utils.js.map +1 -1
- package/dist/sparkline/sparkline2.js +8 -6
- package/dist/sparkline/sparkline2.js.map +1 -1
- package/dist/star-rating/star-rating2.js +2 -2
- package/dist/star-rating/star-rating2.js.map +1 -1
- package/dist/steps/steps2.js +3 -3
- package/dist/steps/steps2.js.map +1 -1
- package/dist/switch/switch-group2.js +2 -2
- package/dist/switch/switch-group2.js.map +1 -1
- package/dist/switch/switch2.js +2 -2
- package/dist/switch/switch2.js.map +1 -1
- package/dist/tabs/tabs-group2.js +2 -2
- package/dist/tabs/tabs-group2.js.map +1 -1
- package/dist/tabs/tabs2.js +3 -3
- package/dist/tabs/tabs2.js.map +1 -1
- package/dist/tag/tag.d.ts +2 -0
- package/dist/tag/tag.examples.js.map +1 -1
- package/dist/tag/tag.examples.json +20 -3
- package/dist/tag/tag.js +1 -1
- package/dist/tag/tag.js.map +1 -1
- package/dist/tag/tag2.js +3 -3
- package/dist/tag/tag2.js.map +1 -1
- package/dist/textarea/textarea2.js +1 -1
- package/dist/textarea/textarea2.js.map +1 -1
- package/dist/time/time2.js +2 -2
- package/dist/time/time2.js.map +1 -1
- package/dist/toast/toast2.js +2 -2
- package/dist/toast/toast2.js.map +1 -1
- package/dist/toggletip/toggletip-footer2.js +2 -2
- package/dist/toggletip/toggletip-footer2.js.map +1 -1
- package/dist/toggletip/toggletip-header2.js +2 -2
- package/dist/toggletip/toggletip-header2.js.map +1 -1
- package/dist/toggletip/toggletip2.js +2 -2
- package/dist/toggletip/toggletip2.js.map +1 -1
- package/dist/toolbar/toolbar2.js +2 -2
- package/dist/toolbar/toolbar2.js.map +1 -1
- package/dist/tooltip/tooltip.examples.js.map +1 -1
- package/dist/tooltip/tooltip2.js +2 -2
- package/dist/tooltip/tooltip2.js.map +1 -1
- package/dist/tree/tree-node2.js +2 -2
- package/dist/tree/tree-node2.js.map +1 -1
- package/dist/tree/tree.examples.js.map +1 -1
- package/dist/tree/tree2.js +2 -2
- package/dist/tree/tree2.js.map +1 -1
- package/dist/week/week2.js +2 -2
- package/dist/week/week2.js.map +1 -1
- package/package.json +9 -9
package/dist/icon/icon2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon2.js","names":["#resolvedIconName","#iconString","#asyncRender","#addIconRegistryListener","#removeIconRegistryListener","#render","#iconRegistryEventName","#onIconRegistryUpdate","#renderRequest"],"sources":["../../src/icon/icon.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { PropertyValues } from 'lit';\nimport { html, isServer, LitElement } from 'lit';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { property } from 'lit/decorators/property.js';\nimport { state } from 'lit/decorators/state.js';\nimport type { Size } from '@nvidia-elements/core/internal';\nimport { attachInternals, parseVersion, useStyles } from '@nvidia-elements/core/internal';\nimport type { IconName, IconSVG } from './icons.js';\nimport { ICON_IMPORTS } from './icons.js';\nimport styles from './icon.css?inline';\n\nexport type { IconName, IconSVG } from './icons.js';\n\ndeclare global {\n var _NVE_SSR_ICON_REGISTRY: Record<string, string> | undefined;\n}\n\n/**\n * @element nve-icon\n * @since 0.1.3\n * @entrypoint \\@nvidia-elements/core/icon\n * @description An icon is a graphic symbol designed to visually show the purpose of an interface element.\n * @documentation https://nvidia.github.io/elements/docs/elements/icon/\n * @cssprop --color\n * @cssprop --width\n * @cssprop --height\n * @slot - Custom SVG content to override the named icon\n * @aria https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img\n */\nexport class Icon extends LitElement {\n /**\n * Visual treatment to represent current support status.\n */\n @property({ type: String, reflect: true }) status?: 'warning' | 'danger' | 'success' | 'accent';\n\n /**\n * Controls the bounding box size of the icon given a t-shirt style value.\n */\n @property({ type: String, reflect: true }) size?: Size | 'xs' | 'xl';\n\n /**\n * Sets the direction of the icon. Only supported by expand-panel/collapse-panel (horizontal axis) and arrow/caret/chevron icons (4-directions)\n */\n @property({ type: String, reflect: true }) direction?: 'up' | 'down' | 'left' | 'right';\n\n /**\n * Selects the outline or solid form of the named icon. Solid icons use an optional `-solid` asset and fall back to\n * the outline form when that asset is unavailable.\n */\n @property({ type: String }) appearance?: 'outline' | 'solid';\n\n /**\n * The name of the icon SVG sprite to render.\n */\n @property({ type: String, reflect: true }) name?: IconName;\n\n @state() private svg: string;\n\n static styles = useStyles([styles]);\n\n static readonly metadata = {\n tag: 'nve-icon',\n version: '0.0.0'\n };\n\n static _icons: { [key: string]: IconSVG } = ICON_IMPORTS;\n\n // eslint-disable-next-line no-restricted-syntax\n private static get _iconsRegistry() {\n return this.registeredIcon?._icons ?? Icon._icons;\n }\n\n // eslint-disable-next-line no-restricted-syntax\n private static set _iconsRegistry(icons: { [key: string]: IconSVG }) {\n this.registeredIcon._icons = { ...Icon._iconsRegistry, ...icons };\n }\n\n // eslint-disable-next-line no-restricted-syntax\n private static get registeredIcon() {\n return customElements.get(Icon.metadata.tag) as typeof Icon;\n }\n\n /** @private */\n declare _internals: ElementInternals;\n\n get #resolvedIconName() {\n if (!this.name || this.name.endsWith('.svg') || this.appearance !== 'solid' || this.name.endsWith('-solid')) {\n return this.name;\n }\n\n const solidName = `${this.name}-solid`;\n return Icon._iconsRegistry[solidName] ? solidName : this.name;\n }\n\n get #iconString() {\n const iconName = this.#resolvedIconName;\n return isServer && globalThis._NVE_SSR_ICON_REGISTRY && iconName\n ? globalThis._NVE_SSR_ICON_REGISTRY[iconName]\n : this.svg;\n }\n\n #iconRegistryEventName?: string;\n\n #renderRequest = 0;\n\n #onIconRegistryUpdate = (event: Event) => this.#asyncRender(event as CustomEvent<IconSVG>);\n\n render() {\n return html`\n <div internal-host aria-hidden=\"true\"><slot>${unsafeSVG(this.#iconString)}</slot></div>\n `;\n }\n\n connectedCallback() {\n super.connectedCallback();\n attachInternals(this);\n this._internals.role = 'img';\n this.#addIconRegistryListener();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.#removeIconRegistryListener();\n }\n\n static async add(icons: { [key: string]: IconSVG }) {\n if (globalThis.customElements?.whenDefined) {\n await globalThis.customElements.whenDefined(Icon.metadata.tag);\n Icon._iconsRegistry = icons;\n Object.keys(icons).forEach(name =>\n globalThis?.document?.dispatchEvent(new CustomEvent(`${Icon.metadata.tag}-${name}`, { detail: icons[name] }))\n );\n }\n }\n\n static alias(aliases: { [key: string]: IconName | string }) {\n // whenDefined has no rejection state\n if (globalThis.customElements?.whenDefined) {\n /* eslint-disable @typescript-eslint/no-floating-promises */\n globalThis.customElements.whenDefined(Icon.metadata.tag).then(() => {\n Object.keys(aliases).forEach(alias => {\n Icon._iconsRegistry[alias] = Icon._iconsRegistry[aliases[alias]!]!;\n globalThis?.document?.dispatchEvent(\n new CustomEvent(`${Icon.metadata.tag}-${alias}`, { detail: Icon._iconsRegistry[alias] })\n );\n });\n });\n }\n }\n\n async updated(props: PropertyValues<this>) {\n super.updated(props);\n if (props.has('name') || props.has('appearance')) {\n this.#removeIconRegistryListener();\n this.#addIconRegistryListener();\n }\n await this.#render();\n }\n\n #addIconRegistryListener() {\n const iconName = this.#resolvedIconName;\n if (!this.isConnected || !iconName || this.#iconRegistryEventName) return;\n this.#iconRegistryEventName = `${Icon.metadata.tag}-${iconName}`;\n globalThis.document?.addEventListener(this.#iconRegistryEventName, this.#onIconRegistryUpdate);\n }\n\n #removeIconRegistryListener() {\n if (!this.#iconRegistryEventName) return;\n globalThis.document?.removeEventListener(this.#iconRegistryEventName, this.#onIconRegistryUpdate);\n this.#iconRegistryEventName = undefined;\n }\n\n async #asyncRender(event: CustomEvent<IconSVG>) {\n if (this.isConnected && event.detail && this.svg !== (await event.detail.svg())) {\n this.#render();\n }\n }\n\n async #render() {\n const renderRequest = ++this.#renderRequest;\n const iconName = this.#resolvedIconName;\n if (!iconName) return;\n const svg = await (iconName.endsWith('.svg')\n ? fetch(iconName).then(res => res.text())\n : (Icon._iconsRegistry[iconName]?.svg() ?? Promise.resolve('')));\n if (renderRequest !== this.#renderRequest) return;\n Icon._iconsRegistry[iconName] = { svg: () => svg, ...Icon._iconsRegistry[iconName] };\n this.svg = svg;\n }\n}\n\nexport function mergeIcons(RegisteredIcon: typeof Icon) {\n if (typeof globalThis.customElements?.get === 'function') {\n const registered = parseVersion(RegisteredIcon.metadata.version);\n const current = parseVersion('0.0.0');\n\n // determine if an older icon already registered and if so, merge the icons with the latest svgs\n if (registered.minor <= current.minor && registered.major <= current.major) {\n RegisteredIcon._icons = { ...RegisteredIcon._icons, ...ICON_IMPORTS };\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"icon2.js","names":[],"sources":["../../src/icon/icon.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { PropertyValues } from 'lit';\nimport { html, isServer, LitElement } from 'lit';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { property } from 'lit/decorators/property.js';\nimport { state } from 'lit/decorators/state.js';\nimport type { Size } from '@nvidia-elements/core/internal';\nimport { attachInternals, parseVersion, useStyles } from '@nvidia-elements/core/internal';\nimport type { IconName, IconSVG } from './icons.js';\nimport { ICON_IMPORTS } from './icons.js';\nimport styles from './icon.css?inline';\n\nexport type { IconName, IconSVG } from './icons.js';\n\ndeclare global {\n var _NVE_SSR_ICON_REGISTRY: Record<string, string> | undefined;\n}\n\n/**\n * @element nve-icon\n * @since 0.1.3\n * @entrypoint \\@nvidia-elements/core/icon\n * @description An icon is a graphic symbol designed to visually show the purpose of an interface element.\n * @documentation https://nvidia.github.io/elements/docs/elements/icon/\n * @cssprop --color\n * @cssprop --width\n * @cssprop --height\n * @slot - Custom SVG content to override the named icon\n * @aria https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img\n */\nexport class Icon extends LitElement {\n /**\n * Visual treatment to represent current support status.\n */\n @property({ type: String, reflect: true }) status?: 'warning' | 'danger' | 'success' | 'accent';\n\n /**\n * Controls the bounding box size of the icon given a t-shirt style value.\n */\n @property({ type: String, reflect: true }) size?: Size | 'xs' | 'xl';\n\n /**\n * Sets the direction of the icon. Only supported by expand-panel/collapse-panel (horizontal axis) and arrow/caret/chevron icons (4-directions)\n */\n @property({ type: String, reflect: true }) direction?: 'up' | 'down' | 'left' | 'right';\n\n /**\n * Selects the outline or solid form of the named icon. Solid icons use an optional `-solid` asset and fall back to\n * the outline form when that asset is unavailable.\n */\n @property({ type: String }) appearance?: 'outline' | 'solid';\n\n /**\n * The name of the icon SVG sprite to render.\n */\n @property({ type: String, reflect: true }) name?: IconName;\n\n @state() private svg: string;\n\n static styles = useStyles([styles]);\n\n static readonly metadata = {\n tag: 'nve-icon',\n version: '0.0.0'\n };\n\n static _icons: { [key: string]: IconSVG } = ICON_IMPORTS;\n\n // eslint-disable-next-line no-restricted-syntax\n private static get _iconsRegistry() {\n return this.registeredIcon?._icons ?? Icon._icons;\n }\n\n // eslint-disable-next-line no-restricted-syntax\n private static set _iconsRegistry(icons: { [key: string]: IconSVG }) {\n this.registeredIcon._icons = { ...Icon._iconsRegistry, ...icons };\n }\n\n // eslint-disable-next-line no-restricted-syntax\n private static get registeredIcon() {\n return customElements.get(Icon.metadata.tag) as typeof Icon;\n }\n\n /** @private */\n declare _internals: ElementInternals;\n\n get #resolvedIconName() {\n if (!this.name || this.name.endsWith('.svg') || this.appearance !== 'solid' || this.name.endsWith('-solid')) {\n return this.name;\n }\n\n const solidName = `${this.name}-solid`;\n return Icon._iconsRegistry[solidName] ? solidName : this.name;\n }\n\n get #iconString() {\n const iconName = this.#resolvedIconName;\n return isServer && globalThis._NVE_SSR_ICON_REGISTRY && iconName\n ? globalThis._NVE_SSR_ICON_REGISTRY[iconName]\n : this.svg;\n }\n\n #iconRegistryEventName?: string;\n\n #renderRequest = 0;\n\n #onIconRegistryUpdate = (event: Event) => this.#asyncRender(event as CustomEvent<IconSVG>);\n\n render() {\n return html`\n <div internal-host aria-hidden=\"true\"><slot>${unsafeSVG(this.#iconString)}</slot></div>\n `;\n }\n\n connectedCallback() {\n super.connectedCallback();\n attachInternals(this);\n this._internals.role = 'img';\n this.#addIconRegistryListener();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.#removeIconRegistryListener();\n }\n\n static async add(icons: { [key: string]: IconSVG }) {\n if (globalThis.customElements?.whenDefined) {\n await globalThis.customElements.whenDefined(Icon.metadata.tag);\n Icon._iconsRegistry = icons;\n Object.keys(icons).forEach(name =>\n globalThis?.document?.dispatchEvent(new CustomEvent(`${Icon.metadata.tag}-${name}`, { detail: icons[name] }))\n );\n }\n }\n\n static alias(aliases: { [key: string]: IconName | string }) {\n // whenDefined has no rejection state\n if (globalThis.customElements?.whenDefined) {\n /* eslint-disable @typescript-eslint/no-floating-promises */\n globalThis.customElements.whenDefined(Icon.metadata.tag).then(() => {\n Object.keys(aliases).forEach(alias => {\n Icon._iconsRegistry[alias] = Icon._iconsRegistry[aliases[alias]!]!;\n globalThis?.document?.dispatchEvent(\n new CustomEvent(`${Icon.metadata.tag}-${alias}`, { detail: Icon._iconsRegistry[alias] })\n );\n });\n });\n }\n }\n\n async updated(props: PropertyValues<this>) {\n super.updated(props);\n if (props.has('name') || props.has('appearance')) {\n this.#removeIconRegistryListener();\n this.#addIconRegistryListener();\n }\n await this.#render();\n }\n\n #addIconRegistryListener() {\n const iconName = this.#resolvedIconName;\n if (!this.isConnected || !iconName || this.#iconRegistryEventName) return;\n this.#iconRegistryEventName = `${Icon.metadata.tag}-${iconName}`;\n globalThis.document?.addEventListener(this.#iconRegistryEventName, this.#onIconRegistryUpdate);\n }\n\n #removeIconRegistryListener() {\n if (!this.#iconRegistryEventName) return;\n globalThis.document?.removeEventListener(this.#iconRegistryEventName, this.#onIconRegistryUpdate);\n this.#iconRegistryEventName = undefined;\n }\n\n async #asyncRender(event: CustomEvent<IconSVG>) {\n if (this.isConnected && event.detail && this.svg !== (await event.detail.svg())) {\n this.#render();\n }\n }\n\n async #render() {\n const renderRequest = ++this.#renderRequest;\n const iconName = this.#resolvedIconName;\n if (!iconName) return;\n const svg = await (iconName.endsWith('.svg')\n ? fetch(iconName).then(res => res.text())\n : (Icon._iconsRegistry[iconName]?.svg() ?? Promise.resolve('')));\n if (renderRequest !== this.#renderRequest) return;\n Icon._iconsRegistry[iconName] = { svg: () => svg, ...Icon._iconsRegistry[iconName] };\n this.svg = svg;\n }\n}\n\nexport function mergeIcons(RegisteredIcon: typeof Icon) {\n if (typeof globalThis.customElements?.get === 'function') {\n const registered = parseVersion(RegisteredIcon.metadata.version);\n const current = parseVersion('0.0.0');\n\n // determine if an older icon already registered and if so, merge the icons with the latest svgs\n if (registered.minor <= current.minor && registered.major <= current.major) {\n RegisteredIcon._icons = { ...RegisteredIcon._icons, ...ICON_IMPORTS };\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { removeEmptySlotWhitespace as e } from "../internal/utils/dom.js";
|
|
2
2
|
import { scopedRegistry as t } from "../internal/decorators/scoped-registry.js";
|
|
3
3
|
import { useStyles as n } from "../internal/styles/index.js";
|
|
4
|
-
import r from "../_virtual/_@oxc-project_runtime@0.
|
|
4
|
+
import r from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
|
|
5
5
|
import { Icon as i } from "../icon/icon2.js";
|
|
6
6
|
import { Button as a } from "../button/button2.js";
|
|
7
7
|
import o from "./icon-button.js";
|
|
@@ -15,7 +15,7 @@ var l = class extends a {
|
|
|
15
15
|
static {
|
|
16
16
|
this.metadata = {
|
|
17
17
|
tag: "nve-icon-button",
|
|
18
|
-
version: "2.
|
|
18
|
+
version: "2.8.0"
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
static {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button2.js","names":[],"sources":["../../src/icon-button/icon-button.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { html } from 'lit';\nimport { property } from 'lit/decorators/property.js';\nimport type { Size } from '@nvidia-elements/core/internal';\nimport { removeEmptySlotWhitespace, scopedRegistry, useStyles } from '@nvidia-elements/core/internal';\nimport { Button } from '@nvidia-elements/core/button';\nimport type { IconName } from '@nvidia-elements/core/icon';\nimport { Icon } from '@nvidia-elements/core/icon';\nimport styles from './icon-button.css?inline';\n\n/**\n * @element nve-icon-button\n * @description An icon button is a button that displays only an icon without a visual label.\n * @documentation https://nvidia.github.io/elements/docs/elements/icon-button/\n * @since 0.2.1\n * @entrypoint \\@nvidia-elements/core/icon-button\n * @slot - default slot for custom icons\n * @cssprop --border-radius\n * @cssprop --padding\n * @cssprop --line-height\n * @cssprop --gap\n * @cssprop --height\n * @cssprop --width\n * @cssprop --font-size\n * @cssprop --color\n * @cssprop --background\n * @csspart icon - The icon element\n * @aria https://www.w3.org/WAI/ARIA/apg/patterns/button/\n */\n@scopedRegistry()\nexport class IconButton extends Button {\n /**\n * Sets the icon name, which determines which icon to display.\n */\n @property({ type: String, attribute: 'icon-name' }) iconName: IconName;\n\n /**\n * Sets the direction of the icon.\n * Only supported by expand-panel/collapse-panel (horizontal axis) and arrow/caret/chevron icons (4-directions)\n */\n @property({ type: String, reflect: true }) direction: 'up' | 'down' | 'left' | 'right';\n\n /**\n * Sets size of the icon button.\n */\n @property({ type: String, reflect: true }) size?: Size;\n\n static styles = useStyles([...Button.styles, styles]);\n\n static readonly metadata = {\n tag: 'nve-icon-button',\n version: '0.0.0'\n };\n\n static elementDefinitions = {\n [Icon.metadata.tag]: Icon\n };\n\n render() {\n return html`\n <div internal-host interaction-state focus-within aria-hidden=\"true\">\n <slot @slotchange=${(e: Event) => removeEmptySlotWhitespace(e.target as HTMLSlotElement)}>\n <nve-icon .name=${this.iconName} .direction=${this.direction} .size=${this.size} aria-hidden=\"true\" part=\"icon\"></nve-icon>\n </slot>\n </div>\n <slot name=\"anchor\"></slot>\n `;\n }\n}\n"],"mappings":";;;;;;;;;;AAgCO,
|
|
1
|
+
{"version":3,"file":"icon-button2.js","names":[],"sources":["../../src/icon-button/icon-button.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { html } from 'lit';\nimport { property } from 'lit/decorators/property.js';\nimport type { Size } from '@nvidia-elements/core/internal';\nimport { removeEmptySlotWhitespace, scopedRegistry, useStyles } from '@nvidia-elements/core/internal';\nimport { Button } from '@nvidia-elements/core/button';\nimport type { IconName } from '@nvidia-elements/core/icon';\nimport { Icon } from '@nvidia-elements/core/icon';\nimport styles from './icon-button.css?inline';\n\n/**\n * @element nve-icon-button\n * @description An icon button is a button that displays only an icon without a visual label.\n * @documentation https://nvidia.github.io/elements/docs/elements/icon-button/\n * @since 0.2.1\n * @entrypoint \\@nvidia-elements/core/icon-button\n * @slot - default slot for custom icons\n * @cssprop --border-radius\n * @cssprop --padding\n * @cssprop --line-height\n * @cssprop --gap\n * @cssprop --height\n * @cssprop --width\n * @cssprop --font-size\n * @cssprop --color\n * @cssprop --background\n * @csspart icon - The icon element\n * @aria https://www.w3.org/WAI/ARIA/apg/patterns/button/\n */\n@scopedRegistry()\nexport class IconButton extends Button {\n /**\n * Sets the icon name, which determines which icon to display.\n */\n @property({ type: String, attribute: 'icon-name' }) iconName: IconName;\n\n /**\n * Sets the direction of the icon.\n * Only supported by expand-panel/collapse-panel (horizontal axis) and arrow/caret/chevron icons (4-directions)\n */\n @property({ type: String, reflect: true }) direction: 'up' | 'down' | 'left' | 'right';\n\n /**\n * Sets size of the icon button.\n */\n @property({ type: String, reflect: true }) size?: Size;\n\n static styles = useStyles([...Button.styles, styles]);\n\n static readonly metadata = {\n tag: 'nve-icon-button',\n version: '0.0.0'\n };\n\n static elementDefinitions = {\n [Icon.metadata.tag]: Icon\n };\n\n render() {\n return html`\n <div internal-host interaction-state focus-within aria-hidden=\"true\">\n <slot @slotchange=${(e: Event) => removeEmptySlotWhitespace(e.target as HTMLSlotElement)}>\n <nve-icon .name=${this.iconName} .direction=${this.direction} .size=${this.size} aria-hidden=\"true\" part=\"icon\"></nve-icon>\n </slot>\n </div>\n <slot name=\"anchor\"></slot>\n `;\n }\n}\n"],"mappings":";;;;;;;;;;AAgCO,IAAM,IAAN,cAAyB,EAAO;;EAiBrB,KAAA,SAAA,EAAU,CAAC,GAAG,EAAO,QAAQ,CAAM,CAAC;;;EAEzB,KAAA,WAAA;GACzB,KAAK;GACL,SAAS;EACX;;;EAE4B,KAAA,qBAAA,GACzB,EAAK,SAAS,MAAM,EACvB;;CAEA,SAAS;EACP,OAAO,CAAI,4FAEc,MAAa,EAA0B,EAAE,MAAyB,EAAE,qBACrE,KAAK,SAAS,gBAAc,KAAK,UAAU,WAAS,KAAK,KAAK;CAKxF;AACF;AAlCG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAY,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAMjD,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAKxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAhB1C,IAAA,EAAA,CAAA,EAAe,CAAA,GAAA,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { I18nService as e } from "./internal/services/i18n.service.js";
|
|
|
2
2
|
import { getThemeTokens as t } from "./internal/utils/dom.js";
|
|
3
3
|
import { statusIcons as n } from "./internal/types/index.js";
|
|
4
4
|
//#region src/index.ts
|
|
5
|
-
var r = "2.
|
|
5
|
+
var r = "2.8.0", i = "@nvidia-elements";
|
|
6
6
|
//#endregion
|
|
7
7
|
export { e as I18nService, i as SCOPE, r as VERSION, t as getThemeTokens, n as statusIcons };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-group2.js","names":[],"sources":["../../src/input/input-group.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { CSSResult } from 'lit';\nimport { useStyles, appendRootNodeStyle } from '@nvidia-elements/core/internal';\nimport { ControlGroup } from '@nvidia-elements/core/forms';\nimport globalStyles from './input-group.global.css?inline';\nimport styles from './input-group.css?inline';\n\n/**\n * @element nve-input-group\n * @description Visually combines many related input controls into a unified composite field with shared styling.\n * @documentation https://nvidia.github.io/elements/docs/elements/input-group/\n * @since 0.3.0\n * @entrypoint \\@nvidia-elements/core/input\n * @cssprop --background\n * @cssprop --color\n * @cssprop --border-radius\n * @cssprop --gap\n * @cssprop --border\n * @cssprop --padding\n * @aria https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input\n */\nexport class InputGroup extends ControlGroup {\n static styles: CSSResult[] = useStyles([...ControlGroup.styles, styles]);\n\n static readonly metadata = {\n tag: 'nve-input-group',\n version: '0.0.0'\n };\n\n async connectedCallback() {\n appendRootNodeStyle(this, globalStyles);\n super.connectedCallback();\n await this.updateComplete;\n const controls = Array.from(\n this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])')!.assignedElements()\n );\n controls[0]?.setAttribute('first-control', '');\n controls[controls.length - 1]?.setAttribute('last-control', '');\n }\n}\n"],"mappings":";;;;;;AAuBA,IAAa,IAAb,cAAgC,EAAa;;
|
|
1
|
+
{"version":3,"file":"input-group2.js","names":[],"sources":["../../src/input/input-group.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { CSSResult } from 'lit';\nimport { useStyles, appendRootNodeStyle } from '@nvidia-elements/core/internal';\nimport { ControlGroup } from '@nvidia-elements/core/forms';\nimport globalStyles from './input-group.global.css?inline';\nimport styles from './input-group.css?inline';\n\n/**\n * @element nve-input-group\n * @description Visually combines many related input controls into a unified composite field with shared styling.\n * @documentation https://nvidia.github.io/elements/docs/elements/input-group/\n * @since 0.3.0\n * @entrypoint \\@nvidia-elements/core/input\n * @cssprop --background\n * @cssprop --color\n * @cssprop --border-radius\n * @cssprop --gap\n * @cssprop --border\n * @cssprop --padding\n * @aria https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input\n */\nexport class InputGroup extends ControlGroup {\n static styles: CSSResult[] = useStyles([...ControlGroup.styles, styles]);\n\n static readonly metadata = {\n tag: 'nve-input-group',\n version: '0.0.0'\n };\n\n async connectedCallback() {\n appendRootNodeStyle(this, globalStyles);\n super.connectedCallback();\n await this.updateComplete;\n const controls = Array.from(\n this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])')!.assignedElements()\n );\n controls[0]?.setAttribute('first-control', '');\n controls[controls.length - 1]?.setAttribute('last-control', '');\n }\n}\n"],"mappings":";;;;;;AAuBA,IAAa,IAAb,cAAgC,EAAa;;EACd,KAAA,SAAA,EAAU,CAAC,GAAG,EAAa,QAAQ,CAAM,CAAC;;;EAE5C,KAAA,WAAA;GACzB,KAAK;GACL,SAAS;EACX;;CAEA,MAAM,oBAAoB;EAGxB,AAFA,EAAoB,MAAM,CAAY,GACtC,MAAM,kBAAkB,GACxB,MAAM,KAAK;EACX,IAAM,IAAW,MAAM,KACrB,KAAK,WAAY,cAA+B,kBAAkB,CAAC,CAAE,iBAAiB,CACxF;EAEA,AADA,EAAS,EAAE,EAAE,aAAa,iBAAiB,EAAE,GAC7C,EAAS,EAAS,SAAS,EAAE,EAAE,aAAa,gBAAgB,EAAE;CAChE;AACF"}
|
package/dist/input/input2.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useStyles as e } from "../internal/styles/index.js";
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
|
|
3
3
|
import { Control as n } from "../forms/control/control2.js";
|
|
4
4
|
import r from "./input.js";
|
|
5
5
|
import { property as i } from "lit/decorators/property.js";
|
|
@@ -14,7 +14,7 @@ var a = r, o = class extends n {
|
|
|
14
14
|
static {
|
|
15
15
|
this.metadata = {
|
|
16
16
|
tag: "nve-input",
|
|
17
|
-
version: "2.
|
|
17
|
+
version: "2.8.0"
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
};
|
package/dist/input/input2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input2.js","names":[],"sources":["../../src/input/input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { CSSResult } from 'lit';\nimport { property } from 'lit/decorators/property.js';\nimport type { ContainerElement } from '@nvidia-elements/core/internal';\nimport { useStyles } from '@nvidia-elements/core/internal';\nimport { Control } from '@nvidia-elements/core/forms';\nimport styles from './input.css?inline';\n\nexport const inputStyles = styles;\n\n/**\n * @element nve-input\n * @description An input is a control that enables users to enter text.\n * @documentation https://nvidia.github.io/elements/docs/elements/input/\n * @since 0.3.0\n * @entrypoint \\@nvidia-elements/core/input\n * @cssprop --padding\n * @cssprop --font-size\n * @cssprop --height\n * @cssprop --background\n * @cssprop --border-radius\n * @cssprop --border\n * @cssprop --cursor\n * @cssprop --color\n * @cssprop --font-weight\n * @cssprop --width\n * @cssprop --min-width\n * @cssprop --max-width\n * @cssprop --border-bottom\n * @cssprop --box-shadow\n * @aria https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input\n */\nexport class Input extends Control implements ContainerElement {\n /**\n * Reduces the visual container for a minimal borderless appearance while preserving whitespace bounds.\n * Use when embedding within another container such as a toolbar.\n */\n @property({ type: String, reflect: true }) container?: 'flat';\n\n /**\n * Sets the rounded visual style of the input.\n */\n @property({ type: Boolean, reflect: true }) rounded = false;\n\n static styles: CSSResult[] = useStyles([...Control.styles, styles]);\n\n static readonly metadata = {\n tag: 'nve-input',\n version: '0.0.0'\n };\n}\n"],"mappings":";;;;;;AAUA,IAAa,IAAc,GAwBd,IAAb,cAA2B,EAAoC;;
|
|
1
|
+
{"version":3,"file":"input2.js","names":[],"sources":["../../src/input/input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { CSSResult } from 'lit';\nimport { property } from 'lit/decorators/property.js';\nimport type { ContainerElement } from '@nvidia-elements/core/internal';\nimport { useStyles } from '@nvidia-elements/core/internal';\nimport { Control } from '@nvidia-elements/core/forms';\nimport styles from './input.css?inline';\n\nexport const inputStyles = styles;\n\n/**\n * @element nve-input\n * @description An input is a control that enables users to enter text.\n * @documentation https://nvidia.github.io/elements/docs/elements/input/\n * @since 0.3.0\n * @entrypoint \\@nvidia-elements/core/input\n * @cssprop --padding\n * @cssprop --font-size\n * @cssprop --height\n * @cssprop --background\n * @cssprop --border-radius\n * @cssprop --border\n * @cssprop --cursor\n * @cssprop --color\n * @cssprop --font-weight\n * @cssprop --width\n * @cssprop --min-width\n * @cssprop --max-width\n * @cssprop --border-bottom\n * @cssprop --box-shadow\n * @aria https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input\n */\nexport class Input extends Control implements ContainerElement {\n /**\n * Reduces the visual container for a minimal borderless appearance while preserving whitespace bounds.\n * Use when embedding within another container such as a toolbar.\n */\n @property({ type: String, reflect: true }) container?: 'flat';\n\n /**\n * Sets the rounded visual style of the input.\n */\n @property({ type: Boolean, reflect: true }) rounded = false;\n\n static styles: CSSResult[] = useStyles([...Control.styles, styles]);\n\n static readonly metadata = {\n tag: 'nve-input',\n version: '0.0.0'\n };\n}\n"],"mappings":";;;;;;AAUA,IAAa,IAAc,GAwBd,IAAb,cAA2B,EAAoC;;EAUP,aAAA,KAAA,UAAA;;;EAEzB,KAAA,SAAA,EAAU,CAAC,GAAG,EAAQ,QAAQ,CAAM,CAAC;;;EAEvC,KAAA,WAAA;GACzB,KAAK;GACL,SAAS;EACX;;AACF;AAbG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAKxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA"}
|
|
@@ -32,13 +32,15 @@ var o = class {
|
|
|
32
32
|
e.state.audit[this.host.localName] || this.#o({ [this.host.localName]: { count: 0 } });
|
|
33
33
|
}
|
|
34
34
|
async #i() {
|
|
35
|
-
if (this.options.excessiveInstanceLimit !== void 0)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
if (this.options.excessiveInstanceLimit !== void 0) {
|
|
36
|
+
if (this.#e.count > this.options.excessiveInstanceLimit && !this.#e.excessiveInstanceLimitAudited) {
|
|
37
|
+
let { getExcessiveInstanceLimitWarning: e } = await import("../utils/audit-logs.js");
|
|
38
|
+
i(e(this.#e.count, this.host.localName)), this.#o({ [this.host.localName]: {
|
|
39
|
+
count: this.#e.count + 1,
|
|
40
|
+
excessiveInstanceLimitAudited: !0
|
|
41
|
+
} });
|
|
42
|
+
} else this.#o({ [this.host.localName]: { count: this.#e.count + 1 } });
|
|
43
|
+
}
|
|
42
44
|
}
|
|
43
45
|
#a() {
|
|
44
46
|
this.options.excessiveInstanceLimit && this.#o({ [this.host.localName]: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.controller.js","names":[
|
|
1
|
+
{"version":3,"file":"audit.controller.js","names":[],"sources":["../../../src/internal/controllers/audit.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport { GlobalStateService } from '../services/global.service.js';\nimport { auditSlots, auditParentElement } from '../utils/audit.js';\n\nexport const excessiveInstanceLimit = 50;\n\nexport interface AuditOptions {\n excessiveInstanceLimit?: number;\n alternates?: { name: string; use: string }[];\n}\n\nexport interface AuditMetadata {\n parents?: string[];\n children?: string[];\n disallowedChildren?: string[];\n}\n\ninterface AuditRegistry {\n [key: string]: {\n count?: number;\n excessiveInstanceLimitAudited?: boolean;\n };\n}\n\nasync function log(message: string) {\n const { LogService } = await import('../services/log.service.js');\n LogService.warn(message);\n}\n\nexport function audit<T extends Audit>(options: AuditOptions = {}): ClassDecorator {\n return (target: LegacyDecoratorTarget) =>\n target.addInitializer!((instance: T) => new AuditController(instance, options));\n}\n\nexport type Audit = ReactiveElement;\n\nexport class AuditController<T extends Audit> implements ReactiveController {\n get #hostAuditState() {\n return GlobalStateService.state.audit[this.host.localName] ?? { count: 0 };\n }\n\n get #production() {\n return GlobalStateService.state.env === 'production';\n }\n\n get #hostMetadata() {\n return (this.host.constructor as unknown as { metadata: AuditMetadata }).metadata;\n }\n\n constructor(\n private host: T,\n private options: AuditOptions\n ) {\n if (!this.#production) {\n this.host.addController(this);\n this.#initializeAudit();\n }\n }\n\n async hostConnected() {\n await this.host.updateComplete;\n if (!this.#production) {\n void this.#auditExcessiveInstanceLimit();\n void this.#auditSlots();\n void this.#auditParentElement();\n }\n }\n\n hostDisconnected() {\n this.#cleanupExcessiveInstanceLimit();\n }\n\n #initializeAudit() {\n if (!GlobalStateService.state.audit[this.host.localName]) {\n this.#update({ [this.host.localName]: { count: 0 } });\n }\n }\n\n async #auditExcessiveInstanceLimit() {\n if (this.options.excessiveInstanceLimit !== undefined) {\n if (\n this.#hostAuditState.count! > this.options.excessiveInstanceLimit &&\n !this.#hostAuditState.excessiveInstanceLimitAudited\n ) {\n const { getExcessiveInstanceLimitWarning } = await import('../utils/audit-logs.js');\n void log(getExcessiveInstanceLimitWarning(this.#hostAuditState.count!, this.host.localName));\n this.#update({\n [this.host.localName]: { count: this.#hostAuditState.count! + 1, excessiveInstanceLimitAudited: true }\n });\n } else {\n this.#update({ [this.host.localName]: { count: this.#hostAuditState.count! + 1 } });\n }\n }\n }\n\n #cleanupExcessiveInstanceLimit() {\n if (this.options.excessiveInstanceLimit) {\n this.#update({\n [this.host.localName]: { count: this.#hostAuditState.count! - 1, excessiveInstanceLimitAudited: false }\n });\n }\n }\n\n #update(registry: AuditRegistry) {\n GlobalStateService.dispatch('NVE_ELEMENTS_AUDIT_UPDATE', { audit: registry } as Partial<\n typeof globalThis.NVE_ELEMENTS.state\n >);\n }\n\n async #auditSlots() {\n if (this.#hostMetadata.children || this.#hostMetadata.disallowedChildren) {\n const [invalidElements, validElements] = auditSlots(this.host);\n if (invalidElements.length) {\n const { getInvalidSlottedChildrenWarning } = await import('../utils/audit-logs.js');\n void log(getInvalidSlottedChildrenWarning(this.host.localName, validElements));\n }\n }\n }\n\n async #auditParentElement() {\n if (this.#hostMetadata.parents) {\n const [valid, validParents] = auditParentElement(this.host);\n if (!valid) {\n const { getInvalidParentWarning } = await import('../utils/audit-logs.js');\n void log(getInvalidParentWarning(this.host.localName, validParents.join(', ')));\n }\n }\n }\n}\n"],"mappings":";;;AAQA,IAAa,IAAyB;AAoBtC,eAAe,EAAI,GAAiB;CAClC,IAAM,EAAE,kBAAe,MAAM,OAAO;CACpC,EAAW,KAAK,CAAO;AACzB;AAEA,SAAgB,EAAuB,IAAwB,CAAC,GAAmB;CACjF,QAAQ,MACN,EAAO,gBAAiB,MAAgB,IAAI,EAAgB,GAAU,CAAO,CAAC;AAClF;AAIA,IAAa,IAAb,MAA4E;CAC1E,IAAI,KAAkB;EACpB,OAAO,EAAmB,MAAM,MAAM,KAAK,KAAK,cAAc,EAAE,OAAO,EAAE;CAC3E;CAEA,IAAI,KAAc;EAChB,OAAO,EAAmB,MAAM,QAAQ;CAC1C;CAEA,IAAI,KAAgB;EAClB,OAAQ,KAAK,KAAK,YAAuD;CAC3E;CAEA,YACE,GACA,GACA;EACA,AAHQ,KAAA,OAAA,GACA,KAAA,UAAA,GAEH,KAAK,OACR,KAAK,KAAK,cAAc,IAAI,GAC5B,KAAK,GAAiB;CAE1B;CAEA,MAAM,gBAAgB;EAEpB,AADA,MAAM,KAAK,KAAK,gBACX,KAAK,OACR,KAAU,GAA6B,GACvC,KAAU,GAAY,GACtB,KAAU,GAAoB;CAElC;CAEA,mBAAmB;EACjB,KAAK,GAA+B;CACtC;CAEA,KAAmB;EACjB,AAAK,EAAmB,MAAM,MAAM,KAAK,KAAK,cAC5C,KAAK,GAAQ,GAAG,KAAK,KAAK,YAAY,EAAE,OAAO,EAAE,EAAE,CAAC;CAExD;CAEA,MAAM,KAA+B;EACnC,IAAI,KAAK,QAAQ,2BAA2B,KAAA,GAAW;GACrD,IACE,KAAK,GAAgB,QAAS,KAAK,QAAQ,0BAC3C,CAAC,KAAK,GAAgB,+BACtB;IACA,IAAM,EAAE,wCAAqC,MAAM,OAAO;IAE1D,AADA,EAAS,EAAiC,KAAK,GAAgB,OAAQ,KAAK,KAAK,SAAS,CAAC,GAC3F,KAAK,GAAQ,GACV,KAAK,KAAK,YAAY;KAAE,OAAO,KAAK,GAAgB,QAAS;KAAG,+BAA+B;IAAK,EACvG,CAAC;GACH,OACE,KAAK,GAAQ,GAAG,KAAK,KAAK,YAAY,EAAE,OAAO,KAAK,GAAgB,QAAS,EAAE,EAAE,CAAC;EAEtF;CACF;CAEA,KAAiC;EAC/B,AAAI,KAAK,QAAQ,0BACf,KAAK,GAAQ,GACV,KAAK,KAAK,YAAY;GAAE,OAAO,KAAK,GAAgB,QAAS;GAAG,+BAA+B;EAAM,EACxG,CAAC;CAEL;CAEA,GAAQ,GAAyB;EAC/B,EAAmB,SAAS,6BAA6B,EAAE,OAAO,EAAS,CAE1E;CACH;CAEA,MAAM,KAAc;EAClB,IAAI,KAAK,GAAc,YAAY,KAAK,GAAc,oBAAoB;GACxE,IAAM,CAAC,GAAiB,KAAiB,EAAW,KAAK,IAAI;GAC7D,IAAI,EAAgB,QAAQ;IAC1B,IAAM,EAAE,wCAAqC,MAAM,OAAO;IAC1D,EAAS,EAAiC,KAAK,KAAK,WAAW,CAAa,CAAC;GAC/E;EACF;CACF;CAEA,MAAM,KAAsB;EAC1B,IAAI,KAAK,GAAc,SAAS;GAC9B,IAAM,CAAC,GAAO,KAAgB,EAAmB,KAAK,IAAI;GAC1D,IAAI,CAAC,GAAO;IACV,IAAM,EAAE,+BAA4B,MAAM,OAAO;IACjD,EAAS,EAAwB,KAAK,KAAK,WAAW,EAAa,KAAK,IAAI,CAAC,CAAC;GAChF;EACF;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gesture.controller.examples.js","names":[
|
|
1
|
+
{"version":3,"file":"gesture.controller.examples.js","names":[],"sources":["../../../src/internal/controllers/gesture.controller.examples.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { css, html, LitElement } from 'lit';\nimport { GestureController } from '@nvidia-elements/core/internal';\n\nexport default {\n title: 'Internal/Controllers'\n};\n\nclass GestureDemoElement extends LitElement {\n readonly #gestureController = new GestureController(this, {\n getCapabilities: () => ({ drag: true, pan: false, pinch: false, wheel: false })\n });\n\n static styles = css`\n :host {\n cursor: grab;\n display: grid;\n height: 64px;\n place-items: center;\n width: 64px;\n }\n\n :host([data-active]) {\n cursor: grabbing;\n }\n `;\n\n constructor() {\n super();\n this.#gestureController.target = this;\n }\n\n render() {\n return html`drag`;\n }\n}\n\nif (!customElements.get('gesture-controller-demo-element')) {\n customElements.define('gesture-controller-demo-element', GestureDemoElement);\n}\n\n/**\n * @summary Drag recognition delivered through gesture and unmatched pointer events. Use event details to move content and represent active pointer state.\n * @tags test-case\n */\nexport const Drag = {\n render: () => html`\n<gesture-controller-demo-element></gesture-controller-demo-element>\n<script type=\"module\">\n const element = document.querySelector('gesture-controller-demo-element');\n let x = 0;\n let y = 0;\n\n element.addEventListener('nve-pointer-input', ({ detail }) => {\n if (detail.kind === 'pointerdown') element.dataset.active = '';\n if (detail.kind === 'pointerup' || detail.kind === 'pointercancel') delete element.dataset.active;\n });\n\n element.addEventListener('nve-gesture', ({ detail }) => {\n if (detail.kind !== 'drag') return;\n x += detail.movementX;\n y += detail.movementY;\n element.style.translate = x + 'px ' + y + 'px';\n });\n</script>\n`\n};\n"],"mappings":";AAGA,IAAA,IAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gesture.controller.js","names":["#host","#options","#panPointerIds","#pointerPositions","#target","#removeTargetListeners","#resetGestureState","#addTargetListeners","#connected","#handleEvent","#handleWheel","#handlePointer","#dispatchGesture","#handleClick","#pinch","#dispatchPointerInput","#handlePointerDown","#handlePointerMove","#handlePointerUp","#capturePointer","#startPinchIfNeeded","#handlePointerButtonsReleased","#updatePointerPosition","#handlePanMove","#handlePinch","#getPinchPointerIds","#getPointerDistance"],"sources":["../../../src/internal/controllers/gesture.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nconst GESTURE_EVENT_TYPES = [\n 'auxclick',\n 'click',\n 'contextmenu',\n 'lostpointercapture',\n 'pointercancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'wheel'\n] as const;\n\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface GestureCapabilities {\n readonly drag: boolean;\n readonly pan: boolean;\n readonly pinch: boolean;\n readonly wheel: boolean;\n}\n\ninterface PointerMovementGesture {\n readonly event: PointerEvent;\n readonly movementX: number;\n readonly movementY: number;\n}\n\nexport type Gesture<TPinchContext> =\n | (PointerMovementGesture & { readonly kind: 'drag' })\n | (PointerMovementGesture & { readonly kind: 'pan' })\n | {\n readonly context: TPinchContext;\n readonly event: PointerEvent;\n readonly kind: 'pinch';\n readonly scale: number;\n }\n | {\n readonly deltaPixels: number;\n readonly event: WheelEvent;\n readonly kind: 'wheel';\n };\n\nexport type UnhandledPointerInput =\n | { readonly event: PointerEvent; readonly kind: 'click' }\n | { readonly event: PointerEvent; readonly kind: 'lostpointercapture' }\n | { readonly event: PointerEvent; readonly kind: 'pointercancel' }\n | { readonly event: PointerEvent; readonly kind: 'pointerdown' }\n | { readonly event: PointerEvent; readonly kind: 'pointermove' }\n | { readonly event: PointerEvent; readonly kind: 'pointerup' };\n\nexport interface GestureControllerOptions<TPinchContext = undefined> {\n /** Creates a snapshot of caller state when a pinch begins. Omit this field to disable pinch recognition. */\n readonly createPinchContext?: () => TPinchContext;\n /** Returns the gesture kinds that the controller can recognize for the current input event. */\n readonly getCapabilities: () => GestureCapabilities;\n /** Updates caller state before the controller reads capabilities for a nonignored input event. */\n readonly prepare?: () => void;\n /** Returns whether the controller should skip an input event before preparing or recognizing it. */\n readonly shouldIgnore?: (event: Event) => boolean;\n}\n\ninterface PinchState<TPinchContext> {\n readonly context: TPinchContext;\n readonly distance: number;\n readonly pointerIds: readonly [number, number];\n}\n\ntype GestureHost = EventTarget & ReactiveControllerHost;\n\n/** Recognizes drag, pan, pinch, and wheel input on a dynamically assigned target. */\nexport class GestureController<TPinchContext = undefined> implements ReactiveController {\n readonly #host: GestureHost;\n readonly #options: GestureControllerOptions<TPinchContext>;\n readonly #panPointerIds = new Set<number>();\n readonly #pointerPositions = new Map<number, Point>();\n #connected = false;\n #pinch?: PinchState<TPinchContext>;\n #target?: HTMLElement;\n\n constructor(host: GestureHost, options: GestureControllerOptions<TPinchContext>) {\n this.#host = host;\n this.#options = options;\n host.addController(this);\n }\n\n set target(target: HTMLElement | undefined) {\n if (target === this.#target) return;\n this.#removeTargetListeners();\n this.#resetGestureState();\n this.#target = target;\n this.#addTargetListeners();\n }\n\n hostConnected(): void {\n this.#connected = true;\n this.#addTargetListeners();\n }\n\n hostDisconnected(): void {\n this.#removeTargetListeners();\n this.#resetGestureState();\n this.#connected = false;\n }\n\n #addTargetListeners(): void {\n if (!this.#connected || !this.#target) return;\n for (const type of GESTURE_EVENT_TYPES) this.#target.addEventListener(type, this.#handleEvent, true);\n }\n\n #removeTargetListeners(): void {\n if (!this.#connected || !this.#target) return;\n for (const type of GESTURE_EVENT_TYPES) this.#target.removeEventListener(type, this.#handleEvent, true);\n }\n\n #handleEvent = (event: Event): void => {\n const target = this.#target;\n if (!target || event.currentTarget !== target || this.#options.shouldIgnore?.(event)) return;\n this.#options.prepare?.();\n const capabilities = this.#options.getCapabilities();\n if (event instanceof WheelEvent) {\n this.#handleWheel(event, capabilities);\n } else if (event.type === 'contextmenu') {\n if (capabilities.pan) event.preventDefault();\n } else if (event instanceof PointerEvent) {\n this.#handlePointer(event, capabilities);\n }\n };\n\n #handleWheel(event: WheelEvent, capabilities: GestureCapabilities): void {\n const target = this.#target;\n if (!capabilities.wheel || !target) return;\n this.#dispatchGesture({\n deltaPixels: normalizeWheelDelta(event, target),\n event,\n kind: 'wheel'\n });\n event.preventDefault();\n }\n\n #handlePointer(event: PointerEvent, capabilities: GestureCapabilities): void {\n switch (event.type) {\n case 'auxclick':\n case 'click':\n this.#handleClick(event, capabilities);\n break;\n case 'lostpointercapture':\n this.#pointerPositions.delete(event.pointerId);\n this.#panPointerIds.delete(event.pointerId);\n if (this.#pinch?.pointerIds.includes(event.pointerId)) this.#pinch = undefined;\n this.#dispatchPointerInput({ event, kind: 'lostpointercapture' });\n break;\n case 'pointercancel':\n this.#pointerPositions.delete(event.pointerId);\n this.#panPointerIds.delete(event.pointerId);\n this.#pinch = undefined;\n this.#dispatchPointerInput({ event, kind: 'pointercancel' });\n break;\n case 'pointerdown':\n this.#handlePointerDown(event, capabilities);\n break;\n case 'pointermove':\n this.#handlePointerMove(event, capabilities);\n break;\n case 'pointerup':\n this.#handlePointerUp(event);\n break;\n }\n }\n\n #handleClick(event: PointerEvent, capabilities: GestureCapabilities): void {\n if (event.button === 2 && capabilities.pan) {\n consumePanBoundaryEvent(event);\n } else if (event.type === 'click') {\n this.#dispatchPointerInput({ event, kind: 'click' });\n }\n }\n\n #handlePointerDown(event: PointerEvent, capabilities: GestureCapabilities): void {\n const canPinch = capabilities.pinch && this.#options.createPinchContext !== undefined;\n this.#pointerPositions.set(event.pointerId, { x: event.clientX, y: event.clientY });\n if (event.button === 2 && capabilities.pan) this.#panPointerIds.add(event.pointerId);\n if (hasPointerCapability(capabilities, canPinch)) this.#capturePointer(event.pointerId);\n if (this.#panPointerIds.has(event.pointerId)) {\n consumePanBoundaryEvent(event);\n return;\n }\n if (canPinch) this.#startPinchIfNeeded();\n this.#dispatchPointerInput({ event, kind: 'pointerdown' });\n }\n\n #handlePointerUp(event: PointerEvent): void {\n this.#pointerPositions.delete(event.pointerId);\n const wasPanPointer = this.#panPointerIds.delete(event.pointerId);\n if (this.#pinch?.pointerIds.includes(event.pointerId)) this.#pinch = undefined;\n if (wasPanPointer) {\n consumePanBoundaryEvent(event);\n } else {\n this.#dispatchPointerInput({ event, kind: 'pointerup' });\n }\n }\n\n #handlePointerMove(event: PointerEvent, capabilities: GestureCapabilities): void {\n if (event.buttons === 0) {\n this.#handlePointerButtonsReleased(event);\n return;\n }\n const canPinch = capabilities.pinch && this.#options.createPinchContext !== undefined;\n const movement = this.#updatePointerPosition(event);\n if (!movement || !hasPointerCapability(capabilities, canPinch)) {\n return this.#dispatchPointerInput({ event, kind: 'pointermove' });\n }\n if (this.#handlePanMove(event, movement, capabilities)) return;\n if (this.#pointerPositions.size >= 2 && canPinch && this.#handlePinch(event)) return;\n if (!capabilities.drag) return this.#dispatchPointerInput({ event, kind: 'pointermove' });\n this.#capturePointer(event.pointerId);\n event.preventDefault();\n this.#dispatchGesture({ event, kind: 'drag', movementX: movement.x, movementY: movement.y });\n }\n\n #handlePointerButtonsReleased(event: PointerEvent): void {\n this.#pointerPositions.delete(event.pointerId);\n this.#panPointerIds.delete(event.pointerId);\n this.#pinch = undefined;\n this.#dispatchPointerInput({ event, kind: 'pointermove' });\n }\n\n #handlePanMove(event: PointerEvent, movement: Point, capabilities: GestureCapabilities): boolean {\n if (!capabilities.pan || !this.#panPointerIds.has(event.pointerId)) return false;\n this.#capturePointer(event.pointerId);\n event.preventDefault();\n this.#dispatchGesture({ event, kind: 'pan', movementX: movement.x, movementY: movement.y });\n return true;\n }\n\n #updatePointerPosition(event: PointerEvent): Point | undefined {\n const previous = this.#pointerPositions.get(event.pointerId);\n if (!previous) return undefined;\n this.#pointerPositions.set(event.pointerId, { x: event.clientX, y: event.clientY });\n const movement = { x: event.clientX - previous.x, y: event.clientY - previous.y };\n return movement.x === 0 && movement.y === 0 ? undefined : movement;\n }\n\n #handlePinch(event: PointerEvent): boolean {\n const createPinchContext = this.#options.createPinchContext;\n if (!createPinchContext) return false;\n if (this.#pinch && !this.#pinch.pointerIds.includes(event.pointerId)) return true;\n const pointerIds = this.#pinch?.pointerIds ?? this.#getPinchPointerIds();\n if (!pointerIds) return false;\n const distance = this.#getPointerDistance(pointerIds);\n if (distance === undefined || distance <= 0) return false;\n this.#pinch ??= { context: createPinchContext(), distance, pointerIds };\n this.#capturePointer(event.pointerId);\n event.preventDefault();\n this.#dispatchGesture({\n context: this.#pinch.context,\n event,\n kind: 'pinch',\n scale: distance / this.#pinch.distance\n });\n return true;\n }\n\n #startPinchIfNeeded(): void {\n const createPinchContext = this.#options.createPinchContext;\n if (this.#pointerPositions.size !== 2 || !createPinchContext) return;\n const pointerIds = this.#getPinchPointerIds();\n if (!pointerIds) return;\n const distance = this.#getPointerDistance(pointerIds);\n if (distance !== undefined && distance > 0) {\n this.#pinch = { context: createPinchContext(), distance, pointerIds };\n }\n }\n\n #getPinchPointerIds(): [number, number] | undefined {\n const pointerIds = [...this.#pointerPositions.keys()];\n const first = pointerIds[0];\n const second = pointerIds[1];\n return first === undefined || second === undefined ? undefined : [first, second];\n }\n\n #getPointerDistance(pointerIds: readonly [number, number]): number | undefined {\n const first = this.#pointerPositions.get(pointerIds[0]);\n const second = this.#pointerPositions.get(pointerIds[1]);\n return first && second ? Math.hypot(first.x - second.x, first.y - second.y) : undefined;\n }\n\n #capturePointer(pointerId: number): void {\n try {\n this.#target?.setPointerCapture?.(pointerId);\n } catch {\n // Synthetic test events and browser implementations may not have an active pointer to capture.\n }\n }\n\n #dispatchGesture(gesture: Gesture<TPinchContext>): void {\n this.#host.dispatchEvent(\n new CustomEvent<Gesture<TPinchContext>>('nve-gesture', {\n bubbles: false,\n cancelable: false,\n composed: false,\n detail: gesture\n })\n );\n }\n\n #dispatchPointerInput(input: UnhandledPointerInput): void {\n this.#host.dispatchEvent(\n new CustomEvent<UnhandledPointerInput>('nve-pointer-input', {\n bubbles: false,\n cancelable: false,\n composed: false,\n detail: input\n })\n );\n }\n\n #resetGestureState(): void {\n this.#pointerPositions.clear();\n this.#panPointerIds.clear();\n this.#pinch = undefined;\n }\n}\n\nfunction hasPointerCapability(capabilities: GestureCapabilities, canPinch: boolean): boolean {\n return capabilities.drag || capabilities.pan || canPinch;\n}\n\nfunction consumePanBoundaryEvent(event: Event): void {\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n\nfunction normalizeWheelDelta(event: WheelEvent, target: HTMLElement): number {\n if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) return event.deltaY * 16;\n if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) return event.deltaY * target.getBoundingClientRect().height;\n return event.deltaY;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gesture.controller.js","names":[],"sources":["../../../src/internal/controllers/gesture.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nconst GESTURE_EVENT_TYPES = [\n 'auxclick',\n 'click',\n 'contextmenu',\n 'lostpointercapture',\n 'pointercancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'wheel'\n] as const;\n\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface GestureCapabilities {\n readonly drag: boolean;\n readonly pan: boolean;\n readonly pinch: boolean;\n readonly wheel: boolean;\n}\n\ninterface PointerMovementGesture {\n readonly event: PointerEvent;\n readonly movementX: number;\n readonly movementY: number;\n}\n\nexport type Gesture<TPinchContext> =\n | (PointerMovementGesture & { readonly kind: 'drag' })\n | (PointerMovementGesture & { readonly kind: 'pan' })\n | {\n readonly context: TPinchContext;\n readonly event: PointerEvent;\n readonly kind: 'pinch';\n readonly scale: number;\n }\n | {\n readonly deltaPixels: number;\n readonly event: WheelEvent;\n readonly kind: 'wheel';\n };\n\nexport type UnhandledPointerInput =\n | { readonly event: PointerEvent; readonly kind: 'click' }\n | { readonly event: PointerEvent; readonly kind: 'lostpointercapture' }\n | { readonly event: PointerEvent; readonly kind: 'pointercancel' }\n | { readonly event: PointerEvent; readonly kind: 'pointerdown' }\n | { readonly event: PointerEvent; readonly kind: 'pointermove' }\n | { readonly event: PointerEvent; readonly kind: 'pointerup' };\n\nexport interface GestureControllerOptions<TPinchContext = undefined> {\n /** Creates a snapshot of caller state when a pinch begins. Omit this field to disable pinch recognition. */\n readonly createPinchContext?: () => TPinchContext;\n /** Returns the gesture kinds that the controller can recognize for the current input event. */\n readonly getCapabilities: () => GestureCapabilities;\n /** Updates caller state before the controller reads capabilities for a nonignored input event. */\n readonly prepare?: () => void;\n /** Returns whether the controller should skip an input event before preparing or recognizing it. */\n readonly shouldIgnore?: (event: Event) => boolean;\n}\n\ninterface PinchState<TPinchContext> {\n readonly context: TPinchContext;\n readonly distance: number;\n readonly pointerIds: readonly [number, number];\n}\n\ntype GestureHost = EventTarget & ReactiveControllerHost;\n\n/** Recognizes drag, pan, pinch, and wheel input on a dynamically assigned target. */\nexport class GestureController<TPinchContext = undefined> implements ReactiveController {\n readonly #host: GestureHost;\n readonly #options: GestureControllerOptions<TPinchContext>;\n readonly #panPointerIds = new Set<number>();\n readonly #pointerPositions = new Map<number, Point>();\n #connected = false;\n #pinch?: PinchState<TPinchContext>;\n #target?: HTMLElement;\n\n constructor(host: GestureHost, options: GestureControllerOptions<TPinchContext>) {\n this.#host = host;\n this.#options = options;\n host.addController(this);\n }\n\n set target(target: HTMLElement | undefined) {\n if (target === this.#target) return;\n this.#removeTargetListeners();\n this.#resetGestureState();\n this.#target = target;\n this.#addTargetListeners();\n }\n\n hostConnected(): void {\n this.#connected = true;\n this.#addTargetListeners();\n }\n\n hostDisconnected(): void {\n this.#removeTargetListeners();\n this.#resetGestureState();\n this.#connected = false;\n }\n\n #addTargetListeners(): void {\n if (!this.#connected || !this.#target) return;\n for (const type of GESTURE_EVENT_TYPES) this.#target.addEventListener(type, this.#handleEvent, true);\n }\n\n #removeTargetListeners(): void {\n if (!this.#connected || !this.#target) return;\n for (const type of GESTURE_EVENT_TYPES) this.#target.removeEventListener(type, this.#handleEvent, true);\n }\n\n #handleEvent = (event: Event): void => {\n const target = this.#target;\n if (!target || event.currentTarget !== target || this.#options.shouldIgnore?.(event)) return;\n this.#options.prepare?.();\n const capabilities = this.#options.getCapabilities();\n if (event instanceof WheelEvent) {\n this.#handleWheel(event, capabilities);\n } else if (event.type === 'contextmenu') {\n if (capabilities.pan) event.preventDefault();\n } else if (event instanceof PointerEvent) {\n this.#handlePointer(event, capabilities);\n }\n };\n\n #handleWheel(event: WheelEvent, capabilities: GestureCapabilities): void {\n const target = this.#target;\n if (!capabilities.wheel || !target) return;\n this.#dispatchGesture({\n deltaPixels: normalizeWheelDelta(event, target),\n event,\n kind: 'wheel'\n });\n event.preventDefault();\n }\n\n #handlePointer(event: PointerEvent, capabilities: GestureCapabilities): void {\n switch (event.type) {\n case 'auxclick':\n case 'click':\n this.#handleClick(event, capabilities);\n break;\n case 'lostpointercapture':\n this.#pointerPositions.delete(event.pointerId);\n this.#panPointerIds.delete(event.pointerId);\n if (this.#pinch?.pointerIds.includes(event.pointerId)) this.#pinch = undefined;\n this.#dispatchPointerInput({ event, kind: 'lostpointercapture' });\n break;\n case 'pointercancel':\n this.#pointerPositions.delete(event.pointerId);\n this.#panPointerIds.delete(event.pointerId);\n this.#pinch = undefined;\n this.#dispatchPointerInput({ event, kind: 'pointercancel' });\n break;\n case 'pointerdown':\n this.#handlePointerDown(event, capabilities);\n break;\n case 'pointermove':\n this.#handlePointerMove(event, capabilities);\n break;\n case 'pointerup':\n this.#handlePointerUp(event);\n break;\n }\n }\n\n #handleClick(event: PointerEvent, capabilities: GestureCapabilities): void {\n if (event.button === 2 && capabilities.pan) {\n consumePanBoundaryEvent(event);\n } else if (event.type === 'click') {\n this.#dispatchPointerInput({ event, kind: 'click' });\n }\n }\n\n #handlePointerDown(event: PointerEvent, capabilities: GestureCapabilities): void {\n const canPinch = capabilities.pinch && this.#options.createPinchContext !== undefined;\n this.#pointerPositions.set(event.pointerId, { x: event.clientX, y: event.clientY });\n if (event.button === 2 && capabilities.pan) this.#panPointerIds.add(event.pointerId);\n if (hasPointerCapability(capabilities, canPinch)) this.#capturePointer(event.pointerId);\n if (this.#panPointerIds.has(event.pointerId)) {\n consumePanBoundaryEvent(event);\n return;\n }\n if (canPinch) this.#startPinchIfNeeded();\n this.#dispatchPointerInput({ event, kind: 'pointerdown' });\n }\n\n #handlePointerUp(event: PointerEvent): void {\n this.#pointerPositions.delete(event.pointerId);\n const wasPanPointer = this.#panPointerIds.delete(event.pointerId);\n if (this.#pinch?.pointerIds.includes(event.pointerId)) this.#pinch = undefined;\n if (wasPanPointer) {\n consumePanBoundaryEvent(event);\n } else {\n this.#dispatchPointerInput({ event, kind: 'pointerup' });\n }\n }\n\n #handlePointerMove(event: PointerEvent, capabilities: GestureCapabilities): void {\n if (event.buttons === 0) {\n this.#handlePointerButtonsReleased(event);\n return;\n }\n const canPinch = capabilities.pinch && this.#options.createPinchContext !== undefined;\n const movement = this.#updatePointerPosition(event);\n if (!movement || !hasPointerCapability(capabilities, canPinch)) {\n return this.#dispatchPointerInput({ event, kind: 'pointermove' });\n }\n if (this.#handlePanMove(event, movement, capabilities)) return;\n if (this.#pointerPositions.size >= 2 && canPinch && this.#handlePinch(event)) return;\n if (!capabilities.drag) return this.#dispatchPointerInput({ event, kind: 'pointermove' });\n this.#capturePointer(event.pointerId);\n event.preventDefault();\n this.#dispatchGesture({ event, kind: 'drag', movementX: movement.x, movementY: movement.y });\n }\n\n #handlePointerButtonsReleased(event: PointerEvent): void {\n this.#pointerPositions.delete(event.pointerId);\n this.#panPointerIds.delete(event.pointerId);\n this.#pinch = undefined;\n this.#dispatchPointerInput({ event, kind: 'pointermove' });\n }\n\n #handlePanMove(event: PointerEvent, movement: Point, capabilities: GestureCapabilities): boolean {\n if (!capabilities.pan || !this.#panPointerIds.has(event.pointerId)) return false;\n this.#capturePointer(event.pointerId);\n event.preventDefault();\n this.#dispatchGesture({ event, kind: 'pan', movementX: movement.x, movementY: movement.y });\n return true;\n }\n\n #updatePointerPosition(event: PointerEvent): Point | undefined {\n const previous = this.#pointerPositions.get(event.pointerId);\n if (!previous) return undefined;\n this.#pointerPositions.set(event.pointerId, { x: event.clientX, y: event.clientY });\n const movement = { x: event.clientX - previous.x, y: event.clientY - previous.y };\n return movement.x === 0 && movement.y === 0 ? undefined : movement;\n }\n\n #handlePinch(event: PointerEvent): boolean {\n const createPinchContext = this.#options.createPinchContext;\n if (!createPinchContext) return false;\n if (this.#pinch && !this.#pinch.pointerIds.includes(event.pointerId)) return true;\n const pointerIds = this.#pinch?.pointerIds ?? this.#getPinchPointerIds();\n if (!pointerIds) return false;\n const distance = this.#getPointerDistance(pointerIds);\n if (distance === undefined || distance <= 0) return false;\n this.#pinch ??= { context: createPinchContext(), distance, pointerIds };\n this.#capturePointer(event.pointerId);\n event.preventDefault();\n this.#dispatchGesture({\n context: this.#pinch.context,\n event,\n kind: 'pinch',\n scale: distance / this.#pinch.distance\n });\n return true;\n }\n\n #startPinchIfNeeded(): void {\n const createPinchContext = this.#options.createPinchContext;\n if (this.#pointerPositions.size !== 2 || !createPinchContext) return;\n const pointerIds = this.#getPinchPointerIds();\n if (!pointerIds) return;\n const distance = this.#getPointerDistance(pointerIds);\n if (distance !== undefined && distance > 0) {\n this.#pinch = { context: createPinchContext(), distance, pointerIds };\n }\n }\n\n #getPinchPointerIds(): [number, number] | undefined {\n const pointerIds = [...this.#pointerPositions.keys()];\n const first = pointerIds[0];\n const second = pointerIds[1];\n return first === undefined || second === undefined ? undefined : [first, second];\n }\n\n #getPointerDistance(pointerIds: readonly [number, number]): number | undefined {\n const first = this.#pointerPositions.get(pointerIds[0]);\n const second = this.#pointerPositions.get(pointerIds[1]);\n return first && second ? Math.hypot(first.x - second.x, first.y - second.y) : undefined;\n }\n\n #capturePointer(pointerId: number): void {\n try {\n this.#target?.setPointerCapture?.(pointerId);\n } catch {\n // Synthetic test events and browser implementations may not have an active pointer to capture.\n }\n }\n\n #dispatchGesture(gesture: Gesture<TPinchContext>): void {\n this.#host.dispatchEvent(\n new CustomEvent<Gesture<TPinchContext>>('nve-gesture', {\n bubbles: false,\n cancelable: false,\n composed: false,\n detail: gesture\n })\n );\n }\n\n #dispatchPointerInput(input: UnhandledPointerInput): void {\n this.#host.dispatchEvent(\n new CustomEvent<UnhandledPointerInput>('nve-pointer-input', {\n bubbles: false,\n cancelable: false,\n composed: false,\n detail: input\n })\n );\n }\n\n #resetGestureState(): void {\n this.#pointerPositions.clear();\n this.#panPointerIds.clear();\n this.#pinch = undefined;\n }\n}\n\nfunction hasPointerCapability(capabilities: GestureCapabilities, canPinch: boolean): boolean {\n return capabilities.drag || capabilities.pan || canPinch;\n}\n\nfunction consumePanBoundaryEvent(event: Event): void {\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n\nfunction normalizeWheelDelta(event: WheelEvent, target: HTMLElement): number {\n if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) return event.deltaY * 16;\n if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) return event.deltaY * target.getBoundingClientRect().height;\n return event.deltaY;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.controller.examples.js","names":[
|
|
1
|
+
{"version":3,"file":"i18n.controller.examples.js","names":[],"sources":["../../../src/internal/controllers/i18n.controller.examples.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { html, LitElement } from 'lit';\nimport { property } from 'lit/decorators/property.js';\nimport { I18nController } from '@nvidia-elements/core/internal';\nimport { I18nService } from '@nvidia-elements/core';\nimport '@nvidia-elements/core/card/define.js';\nimport '@nvidia-elements/core/button/define.js';\n\nexport default {\n title: 'Internal/Controllers'\n}\n\nclass I18nItem extends LitElement {\n #i18nController: I18nController<this> = new I18nController<this>(this);\n @property({ type: Object }) i18n = this.#i18nController.i18n;\n\n render() {\n return html`<nve-card><pre style=\"padding: 24px\">${JSON.stringify(this.i18n, null, 2)}</pre></nve-card>`\n }\n}\ncustomElements.get('i18n-item') || customElements.define('i18n-item', I18nItem);\n\nclass I18nDemo extends LitElement {\n render() {\n return html`\n <div nve-layout=\"column gap:md\">\n <div nve-layout=\"row gap:sm\">\n <nve-button @click=${() => this.#english()}>English</nve-button>\n <nve-button @click=${() => this.#french()}>French</nve-button>\n </div>\n \n <div nve-layout=\"grid span-items:6 gap:sm\">\n <i18n-item .i18n=${{ \"close\": \"dismiss task failure warning\" }}></i18n-item>\n <i18n-item></i18n-item>\n </div>\n </div>\n `\n }\n\n createRenderRoot() {\n return this;\n }\n\n #french() {\n I18nService.update({\n close: 'fermer',\n expand: 'étendre',\n sort: 'classer',\n show: 'montrer',\n hide: 'cacher',\n loading: 'bourrage'\n });\n }\n\n #english() {\n I18nService.update({\n close: 'close',\n expand: 'expand',\n sort: 'sort',\n show: 'show',\n hide: 'hide',\n loading: 'loading'\n });\n }\n}\ncustomElements.get('i18n-demo') || customElements.define('i18n-demo', I18nDemo);\n\n/**\n * @summary Internationalization controller with dynamic language switching between English and French.\n * @tags test-case\n */\nexport const I18nControllerDemo = {\n render: () => html`<i18n-demo></i18n-demo>`\n}\n"],"mappings":";AAGA,IAAA,IAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.controller.js","names":[
|
|
1
|
+
{"version":3,"file":"i18n.controller.js","names":[],"sources":["../../../src/internal/controllers/i18n.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport type { I18nStrings } from '../services/i18n.service.js';\nimport { I18nService } from '../services/i18n.service.js';\n\nexport function i18n<T extends I18n>(): ClassDecorator {\n return (target: LegacyDecoratorTarget) => target.addInitializer!((instance: T) => new I18nController(instance));\n}\n\nexport type I18n = ReactiveElement & { i18n: Partial<I18nStrings> & { __set?: boolean } };\n\nexport class I18nController<T extends I18n> implements ReactiveController {\n get i18n(): Partial<I18nStrings & { __set: boolean }> {\n return { ...I18nService.i18n, ...this.host.i18n, __set: false };\n }\n\n #overrides: Partial<I18nStrings> = {};\n\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n hostConnected() {\n globalThis.document.addEventListener('NVE_ELEMENTS_I18N_UPDATE', this.#update);\n }\n\n hostDisconnected() {\n globalThis.document.removeEventListener('NVE_ELEMENTS_I18N_UPDATE', this.#update);\n }\n\n hostUpdate() {\n if (this.host.i18n.__set === undefined) {\n // if the host lacks a set, an override exists; merging before render keeps it in the same update cycle\n this.#overrides = this.host.i18n;\n this.#update();\n }\n }\n\n #update = () => {\n this.host.i18n = { ...I18nService.i18n, ...this.#overrides, __set: true };\n };\n}\n"],"mappings":";;AAQA,SAAgB,IAAuC;CACrD,QAAQ,MAAkC,EAAO,gBAAiB,MAAgB,IAAI,EAAe,CAAQ,CAAC;AAChH;AAIA,IAAa,IAAb,MAA0E;CACxE,IAAI,OAAkD;EACpD,OAAO;GAAE,GAAG,EAAY;GAAM,GAAG,KAAK,KAAK;GAAM,OAAO;EAAM;CAChE;CAEA,KAAmC,CAAC;CAEpC,YAAY,GAAiB;EAC3B,AADkB,KAAA,OAAA,GAClB,KAAK,KAAK,cAAc,IAAI;CAC9B;CAEA,gBAAgB;EACd,WAAW,SAAS,iBAAiB,4BAA4B,KAAK,EAAO;CAC/E;CAEA,mBAAmB;EACjB,WAAW,SAAS,oBAAoB,4BAA4B,KAAK,EAAO;CAClF;CAEA,aAAa;EACX,AAAI,KAAK,KAAK,KAAK,UAAU,KAAA,MAE3B,KAAK,KAAa,KAAK,KAAK,MAC5B,KAAK,GAAQ;CAEjB;CAEA,WAAgB;EACd,KAAK,KAAK,OAAO;GAAE,GAAG,EAAY;GAAM,GAAG,KAAK;GAAY,OAAO;EAAK;CAC1E;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keynav-grid.controller.js","names":["#config","#hostRows","#hostCells","#grid","#onKeyUp","#onKeyDown","#onMouseUp","#observers","#setActiveCell","#updateCellActivation","#keynavCell","#clickCell"],"sources":["../../../src/internal/controllers/keynav-grid.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport { onChildListMutation, throttle } from '../utils/events.js';\nimport { GlobalStateService } from '../services/global.service.js';\nimport { LogService } from '../services/log.service.js';\nimport {\n validKeyNavigationCode,\n isContextMenuClick,\n getFlattenedDOMTree,\n getFlattenedFocusableItems,\n KeynavCode,\n hasInvalidDOMGrid\n} from '../utils/dom.js';\nimport {\n focusElement,\n getActiveElement,\n initializeKeyListItems,\n setActiveKeyListItem,\n isSimpleFocusable\n} from '../utils/focus.js';\n\nexport interface KeynavGridConfig {\n grid?: HTMLElement;\n columnRow?: HTMLElement;\n columns?: NodeListOf<HTMLElement> | HTMLElement[];\n rows: NodeListOf<HTMLElement> | HTMLElement[];\n cells: NodeListOf<HTMLElement> | HTMLElement[];\n}\n\nexport interface KeynavGridElement {\n keynavGridConfig: KeynavGridConfig;\n}\n\n/**\n * https://w3c.github.io/aria-practices/#gridNav_focus\n */\nexport function keyNavigationGrid<T extends ReactiveElement & KeynavGridElement>(): ClassDecorator {\n return (target: LegacyDecoratorTarget) =>\n target.addInitializer!((instance: T) => new KeyNavigationGridController(instance));\n}\n\nexport class KeyNavigationGridController<T extends ReactiveElement & KeynavGridElement> implements ReactiveController {\n #observers: MutationObserver[] = [];\n #grid?: HTMLElement;\n\n get #config() {\n return {\n grid: this.host,\n ...this.host.keynavGridConfig\n };\n }\n\n get #hostRows() {\n const rows = Array.from(this.#config.rows);\n\n if (this.#config.columnRow) {\n rows.unshift(this.#config.columnRow);\n }\n\n return rows;\n }\n\n get #hostCells() {\n return [...Array.from(this.#config.columns ?? []), ...Array.from(this.#config.cells)];\n }\n\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n async hostConnected() {\n await this.host.updateComplete;\n if (!this.host.isConnected) return;\n\n this.#grid = this.#config.grid;\n initializeKeyListItems(this.#hostCells);\n this.#grid.addEventListener('keyup', this.#onKeyUp);\n this.#grid.addEventListener('keydown', this.#onKeyDown);\n this.#grid.addEventListener('mouseup', this.#onMouseUp);\n this.#observers.push(\n onChildListMutation(\n this.host,\n throttle(() => initializeKeyListItems(this.#hostCells), 500)\n )\n );\n }\n\n hostDisconnected() {\n this.#observers.forEach(o => o?.disconnect());\n this.#observers.length = 0;\n this.#grid?.removeEventListener('keyup', this.#onKeyUp);\n this.#grid?.removeEventListener('keydown', this.#onKeyDown);\n this.#grid?.removeEventListener('mouseup', this.#onMouseUp);\n this.#grid = undefined;\n }\n\n #clickCell(e: MouseEvent) {\n if (!isContextMenuClick(e)) {\n const focusedElement = e.composedPath()[0] as HTMLElement;\n const activeCell = this.#hostCells.find(i => i === focusedElement) ? focusedElement : null;\n if (activeCell) {\n this.#setActiveCell(e, activeCell as HTMLElement);\n }\n }\n }\n\n #keynavCell(e: KeyboardEvent) {\n const rows = Array.from(this.#hostRows);\n const cells = Array.from(this.#hostCells);\n\n if (GlobalStateService.state.env !== 'production' && hasInvalidDOMGrid(rows)) {\n LogService.warn('Invalid grid structure, all rows must have the same number of cells');\n return;\n }\n\n if (validKeyNavigationCode(e) && isSimpleFocusable(getActiveElement() as Element)) {\n const { x, y } = getNextKeyGridItem(cells, rows, {\n code: e.code,\n ctrlKey: e.ctrlKey,\n dir: this.host.dir\n });\n\n const nextCell = Array.from(getFlattenedDOMTree(rows[y]!)).filter(c => !!cells.find(i => i === c))[\n x\n ] as HTMLElement;\n this.#setActiveCell(e, nextCell);\n e.preventDefault();\n }\n }\n\n #setActiveCell(e: KeyboardEvent | MouseEvent, activeCell: HTMLElement) {\n setActiveKeyListItem(this.#hostCells, activeCell);\n\n const items = getFlattenedFocusableItems(activeCell);\n const simpleItems = items.filter(i => isSimpleFocusable(i));\n\n if (simpleItems.length === 1 && items.length === 1) {\n focusElement(simpleItems[0]!);\n } else {\n focusElement(activeCell);\n }\n\n const detail = { code: e instanceof KeyboardEvent ? e.code : null, shiftKey: e.shiftKey, activeItem: activeCell };\n activeCell.dispatchEvent(new CustomEvent('nve-key-change', { bubbles: true, composed: true, detail }));\n }\n\n #updateCellActivation(e: KeyboardEvent) {\n const activeCell = Array.from(this.#hostCells).find(i => i.tabIndex === 0) as HTMLElement;\n if (e.code === 'Escape') {\n activeCell?.focus();\n }\n\n if (e.code === 'Enter' && activeCell === e.composedPath()[0]) {\n getFlattenedFocusableItems(activeCell as HTMLElement)[0]?.focus();\n }\n }\n\n #onKeyUp = (e: KeyboardEvent) => this.#updateCellActivation(e);\n\n #onKeyDown = (e: KeyboardEvent) => this.#keynavCell(e);\n\n #onMouseUp = (e: MouseEvent) => this.#clickCell(e);\n}\n\nfunction getGridDelta(code: KeynavCode | string, dir: string): { dx: number; dy: number } | null {\n const start = dir === 'rtl' ? KeynavCode.ArrowRight : KeynavCode.ArrowLeft;\n const end = dir === 'rtl' ? KeynavCode.ArrowLeft : KeynavCode.ArrowRight;\n\n if (code === KeynavCode.ArrowUp) return { dx: 0, dy: -1 };\n if (code === KeynavCode.ArrowDown) return { dx: 0, dy: 1 };\n if (code === start) return { dx: -1, dy: 0 };\n if (code === end) return { dx: 1, dy: 0 };\n if (code === KeynavCode.PageUp) return { dx: 0, dy: -4 };\n if (code === KeynavCode.PageDown) return { dx: 0, dy: 4 };\n return null;\n}\n\nfunction applyGridHomeEnd(\n code: KeynavCode | string,\n position: { x: number; y: number },\n bounds: { columnCount: number; rowCount: number; ctrlKey: boolean }\n) {\n const { x, y } = position;\n const { columnCount, rowCount, ctrlKey } = bounds;\n if (code === KeynavCode.End) {\n return { x: columnCount, y: ctrlKey ? rowCount : y };\n }\n\n if (code === KeynavCode.Home) {\n return { x: 0, y: ctrlKey ? 0 : y };\n }\n\n return { x, y };\n}\n\nexport function getNextKeyGridItem(\n cells: HTMLElement[],\n rows: HTMLElement[],\n config: { code: KeynavCode | string; ctrlKey: boolean; dir: string }\n) {\n const currentCell = cells.find(i => i.tabIndex === 0) as HTMLElement;\n const currentRow = rows.find(r => getFlattenedDOMTree(r).find(c => c === currentCell)) as HTMLElement;\n const currentRowCells = Array.from(getFlattenedDOMTree(currentRow)).filter(c => !!cells.find(i => i === c));\n const rowCount = rows.length - 1;\n const columnCount = currentRowCells.length - 1;\n\n let x = currentRowCells.indexOf(currentCell);\n let y = rows.indexOf(currentRow);\n\n const delta = getGridDelta(config.code, config.dir);\n if (delta) {\n x = Math.max(0, Math.min(columnCount, x + delta.dx));\n y = Math.max(0, Math.min(rowCount, y + delta.dy));\n } else {\n ({ x, y } = applyGridHomeEnd(config.code, { x, y }, { columnCount, rowCount, ctrlKey: config.ctrlKey }));\n }\n\n return { x, y };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"keynav-grid.controller.js","names":[],"sources":["../../../src/internal/controllers/keynav-grid.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport { onChildListMutation, throttle } from '../utils/events.js';\nimport { GlobalStateService } from '../services/global.service.js';\nimport { LogService } from '../services/log.service.js';\nimport {\n validKeyNavigationCode,\n isContextMenuClick,\n getFlattenedDOMTree,\n getFlattenedFocusableItems,\n KeynavCode,\n hasInvalidDOMGrid\n} from '../utils/dom.js';\nimport {\n focusElement,\n getActiveElement,\n initializeKeyListItems,\n setActiveKeyListItem,\n isSimpleFocusable\n} from '../utils/focus.js';\n\nexport interface KeynavGridConfig {\n grid?: HTMLElement;\n columnRow?: HTMLElement;\n columns?: NodeListOf<HTMLElement> | HTMLElement[];\n rows: NodeListOf<HTMLElement> | HTMLElement[];\n cells: NodeListOf<HTMLElement> | HTMLElement[];\n}\n\nexport interface KeynavGridElement {\n keynavGridConfig: KeynavGridConfig;\n}\n\n/**\n * https://w3c.github.io/aria-practices/#gridNav_focus\n */\nexport function keyNavigationGrid<T extends ReactiveElement & KeynavGridElement>(): ClassDecorator {\n return (target: LegacyDecoratorTarget) =>\n target.addInitializer!((instance: T) => new KeyNavigationGridController(instance));\n}\n\nexport class KeyNavigationGridController<T extends ReactiveElement & KeynavGridElement> implements ReactiveController {\n #observers: MutationObserver[] = [];\n #grid?: HTMLElement;\n\n get #config() {\n return {\n grid: this.host,\n ...this.host.keynavGridConfig\n };\n }\n\n get #hostRows() {\n const rows = Array.from(this.#config.rows);\n\n if (this.#config.columnRow) {\n rows.unshift(this.#config.columnRow);\n }\n\n return rows;\n }\n\n get #hostCells() {\n return [...Array.from(this.#config.columns ?? []), ...Array.from(this.#config.cells)];\n }\n\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n async hostConnected() {\n await this.host.updateComplete;\n if (!this.host.isConnected) return;\n\n this.#grid = this.#config.grid;\n initializeKeyListItems(this.#hostCells);\n this.#grid.addEventListener('keyup', this.#onKeyUp);\n this.#grid.addEventListener('keydown', this.#onKeyDown);\n this.#grid.addEventListener('mouseup', this.#onMouseUp);\n this.#observers.push(\n onChildListMutation(\n this.host,\n throttle(() => initializeKeyListItems(this.#hostCells), 500)\n )\n );\n }\n\n hostDisconnected() {\n this.#observers.forEach(o => o?.disconnect());\n this.#observers.length = 0;\n this.#grid?.removeEventListener('keyup', this.#onKeyUp);\n this.#grid?.removeEventListener('keydown', this.#onKeyDown);\n this.#grid?.removeEventListener('mouseup', this.#onMouseUp);\n this.#grid = undefined;\n }\n\n #clickCell(e: MouseEvent) {\n if (!isContextMenuClick(e)) {\n const focusedElement = e.composedPath()[0] as HTMLElement;\n const activeCell = this.#hostCells.find(i => i === focusedElement) ? focusedElement : null;\n if (activeCell) {\n this.#setActiveCell(e, activeCell as HTMLElement);\n }\n }\n }\n\n #keynavCell(e: KeyboardEvent) {\n const rows = Array.from(this.#hostRows);\n const cells = Array.from(this.#hostCells);\n\n if (GlobalStateService.state.env !== 'production' && hasInvalidDOMGrid(rows)) {\n LogService.warn('Invalid grid structure, all rows must have the same number of cells');\n return;\n }\n\n if (validKeyNavigationCode(e) && isSimpleFocusable(getActiveElement() as Element)) {\n const { x, y } = getNextKeyGridItem(cells, rows, {\n code: e.code,\n ctrlKey: e.ctrlKey,\n dir: this.host.dir\n });\n\n const nextCell = Array.from(getFlattenedDOMTree(rows[y]!)).filter(c => !!cells.find(i => i === c))[\n x\n ] as HTMLElement;\n this.#setActiveCell(e, nextCell);\n e.preventDefault();\n }\n }\n\n #setActiveCell(e: KeyboardEvent | MouseEvent, activeCell: HTMLElement) {\n setActiveKeyListItem(this.#hostCells, activeCell);\n\n const items = getFlattenedFocusableItems(activeCell);\n const simpleItems = items.filter(i => isSimpleFocusable(i));\n\n if (simpleItems.length === 1 && items.length === 1) {\n focusElement(simpleItems[0]!);\n } else {\n focusElement(activeCell);\n }\n\n const detail = { code: e instanceof KeyboardEvent ? e.code : null, shiftKey: e.shiftKey, activeItem: activeCell };\n activeCell.dispatchEvent(new CustomEvent('nve-key-change', { bubbles: true, composed: true, detail }));\n }\n\n #updateCellActivation(e: KeyboardEvent) {\n const activeCell = Array.from(this.#hostCells).find(i => i.tabIndex === 0) as HTMLElement;\n if (e.code === 'Escape') {\n activeCell?.focus();\n }\n\n if (e.code === 'Enter' && activeCell === e.composedPath()[0]) {\n getFlattenedFocusableItems(activeCell as HTMLElement)[0]?.focus();\n }\n }\n\n #onKeyUp = (e: KeyboardEvent) => this.#updateCellActivation(e);\n\n #onKeyDown = (e: KeyboardEvent) => this.#keynavCell(e);\n\n #onMouseUp = (e: MouseEvent) => this.#clickCell(e);\n}\n\nfunction getGridDelta(code: KeynavCode | string, dir: string): { dx: number; dy: number } | null {\n const start = dir === 'rtl' ? KeynavCode.ArrowRight : KeynavCode.ArrowLeft;\n const end = dir === 'rtl' ? KeynavCode.ArrowLeft : KeynavCode.ArrowRight;\n\n if (code === KeynavCode.ArrowUp) return { dx: 0, dy: -1 };\n if (code === KeynavCode.ArrowDown) return { dx: 0, dy: 1 };\n if (code === start) return { dx: -1, dy: 0 };\n if (code === end) return { dx: 1, dy: 0 };\n if (code === KeynavCode.PageUp) return { dx: 0, dy: -4 };\n if (code === KeynavCode.PageDown) return { dx: 0, dy: 4 };\n return null;\n}\n\nfunction applyGridHomeEnd(\n code: KeynavCode | string,\n position: { x: number; y: number },\n bounds: { columnCount: number; rowCount: number; ctrlKey: boolean }\n) {\n const { x, y } = position;\n const { columnCount, rowCount, ctrlKey } = bounds;\n if (code === KeynavCode.End) {\n return { x: columnCount, y: ctrlKey ? rowCount : y };\n }\n\n if (code === KeynavCode.Home) {\n return { x: 0, y: ctrlKey ? 0 : y };\n }\n\n return { x, y };\n}\n\nexport function getNextKeyGridItem(\n cells: HTMLElement[],\n rows: HTMLElement[],\n config: { code: KeynavCode | string; ctrlKey: boolean; dir: string }\n) {\n const currentCell = cells.find(i => i.tabIndex === 0) as HTMLElement;\n const currentRow = rows.find(r => getFlattenedDOMTree(r).find(c => c === currentCell)) as HTMLElement;\n const currentRowCells = Array.from(getFlattenedDOMTree(currentRow)).filter(c => !!cells.find(i => i === c));\n const rowCount = rows.length - 1;\n const columnCount = currentRowCells.length - 1;\n\n let x = currentRowCells.indexOf(currentCell);\n let y = rows.indexOf(currentRow);\n\n const delta = getGridDelta(config.code, config.dir);\n if (delta) {\n x = Math.max(0, Math.min(columnCount, x + delta.dx));\n y = Math.max(0, Math.min(rowCount, y + delta.dy));\n } else {\n ({ x, y } = applyGridHomeEnd(config.code, { x, y }, { columnCount, rowCount, ctrlKey: config.ctrlKey }));\n }\n\n return { x, y };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keynav-list.controller.js","names":["#config","#keynavDisabled","#initializeTabIndex","#onPointerUp","#onKeyDown","#getPointerActiveItem","#setActiveItem","#getKeyboardActiveItem","#clickItem","#focusItem"],"sources":["../../../src/internal/controllers/keynav-list.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport { focusElement, initializeKeyListItems, isFocusable, setActiveKeyListItem } from '../utils/focus.js';\nimport { KeynavCode, validKeyNavigationCode } from '../utils/dom.js';\n\nexport interface KeynavListConfig {\n items: NodeListOf<HTMLElement> | HTMLElement[];\n initialItem?: HTMLElement;\n layout?: 'both' | 'horizontal' | 'vertical';\n manageFocus?: boolean;\n manageTabindex?: boolean;\n loop?: boolean;\n dir?: string | null;\n}\n\nexport interface KeynavListElement {\n keynavListConfig: KeynavListConfig;\n}\n\n/** https://webaim.org/techniques/keyboard/ */\nexport function keyNavigationList<T extends ReactiveElement & KeynavListElement>(): ClassDecorator {\n return (target: LegacyDecoratorTarget) =>\n target.addInitializer!((instance: T) => new KeyNavigationListController(instance));\n}\n\nexport class KeyNavigationListController<T extends ReactiveElement & KeynavListElement> implements ReactiveController {\n get #config(): KeynavListConfig & { items: HTMLElement[] } {\n return {\n layout: 'horizontal',\n manageFocus: true,\n manageTabindex: true,\n loop: false,\n dir: this.host.getAttribute('rtl'),\n ...this.host.keynavListConfig,\n items: Array.from(this.host.keynavListConfig.items).filter(\n (i: HTMLElement & { disabled?: boolean }) => !i.disabled\n )\n };\n }\n\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n /** @private attr nve-keynav-disabled is an internal API for advanced use cases only */\n get #keynavDisabled() {\n return this.host.hasAttribute('nve-keynav-disabled');\n }\n\n async hostConnected() {\n await this.host.updateComplete;\n if (!this.host.isConnected) return;\n this.#initializeTabIndex();\n this.host.addEventListener('pointerup', this.#onPointerUp);\n this.host.addEventListener('keydown', this.#onKeyDown);\n }\n\n hostDisconnected() {\n this.host.removeEventListener('pointerup', this.#onPointerUp);\n this.host.removeEventListener('keydown', this.#onKeyDown);\n }\n\n #initializeTabIndex() {\n const { manageFocus, manageTabindex, items, initialItem } = this.#config;\n if (manageFocus && manageTabindex && !this.#keynavDisabled) {\n initializeKeyListItems(items);\n if (initialItem && items.includes(initialItem)) {\n setActiveKeyListItem(items, initialItem);\n }\n }\n }\n\n #clickItem(e: PointerEvent) {\n const item = this.#getPointerActiveItem(e, this.#config.items);\n if (item) {\n this.#setActiveItem(e, item);\n }\n }\n\n #focusItem(e: KeyboardEvent) {\n if (validKeyNavigationCode(e) && !this.#keynavDisabled) {\n const { loop, layout, dir, items } = this.#config;\n const activeItem = this.#getKeyboardActiveItem(e, items);\n if (activeItem) {\n const { next, previous } = getNextKeyListItem(activeItem, Array.from(items), {\n loop,\n layout,\n dir,\n code: e.code as KeynavCode\n });\n\n if (next !== previous) {\n this.#setActiveItem(e, items[next]!, items[previous]);\n }\n }\n }\n }\n\n #getKeyboardActiveItem(e: KeyboardEvent, items: HTMLElement[]) {\n const target = e.composedPath()[0];\n return target instanceof HTMLElement && items.includes(target) ? target : null;\n }\n\n #getPointerActiveItem(e: PointerEvent, items: HTMLElement[]) {\n const path = e.composedPath();\n const itemIndex = path.findIndex(item => item instanceof HTMLElement && items.includes(item));\n const item = path[itemIndex];\n\n if (!(item instanceof HTMLElement)) return null;\n\n const hasFocusableDescendant = path\n .slice(0, itemIndex)\n .some(descendant => descendant instanceof Element && isFocusable(descendant));\n return hasFocusableDescendant ? null : item;\n }\n\n #setActiveItem(e: KeyboardEvent | PointerEvent, activeItem: HTMLElement, previousItem?: HTMLElement) {\n const { manageFocus, manageTabindex, items } = this.#config;\n if (manageFocus) {\n if (manageTabindex) {\n setActiveKeyListItem(items, activeItem);\n }\n\n focusElement(activeItem);\n e.preventDefault();\n }\n\n const detail = {\n activeItem,\n previousItem,\n code: e instanceof KeyboardEvent ? e.code : null,\n metaKey: e.ctrlKey || e.metaKey,\n items\n };\n activeItem.dispatchEvent(new CustomEvent('nve-key-change', { bubbles: true, composed: true, detail }));\n }\n\n #onPointerUp = (e: PointerEvent) => this.#clickItem(e);\n\n #onKeyDown = (e: KeyboardEvent) => this.#focusItem(e);\n}\n\ninterface KeyListConfig {\n code: KeynavCode;\n loop?: boolean;\n layout?: 'horizontal' | 'vertical' | 'both';\n dir: string | null | undefined;\n}\n\nfunction resolveArrowDirection(config: KeyListConfig): 'backward' | 'forward' | null {\n const { code, layout, dir } = config;\n const start = dir === 'rtl' ? KeynavCode.ArrowRight : KeynavCode.ArrowLeft;\n const end = dir === 'rtl' ? KeynavCode.ArrowLeft : KeynavCode.ArrowRight;\n\n if (layout !== 'horizontal') {\n if (code === KeynavCode.ArrowUp) return 'backward';\n if (code === KeynavCode.ArrowDown) return 'forward';\n }\n\n if (layout !== 'vertical') {\n if (code === start) return 'backward';\n if (code === end) return 'forward';\n }\n\n return null;\n}\n\nfunction resolveSpecialKey(code: KeynavCode): 'home' | 'end' | 'pageup' | 'pagedown' | null {\n if (code === KeynavCode.End) return 'end';\n if (code === KeynavCode.Home) return 'home';\n if (code === KeynavCode.PageUp) return 'pageup';\n if (code === KeynavCode.PageDown) return 'pagedown';\n return null;\n}\n\nfunction navigateWithLoop(current: number, step: number, options: { limit: number; loop: boolean | undefined }) {\n const { limit, loop } = options;\n const next = current + step;\n if (next >= 0 && next <= limit) return next;\n return loop ? (step < 0 ? limit : 0) : current;\n}\n\nexport function getNextKeyListItem(item: HTMLElement, items: HTMLElement[], config: KeyListConfig) {\n let next = items.indexOf(item);\n const previous = next;\n const itemCount = items.length - 1;\n const direction = resolveArrowDirection(config);\n\n switch (direction ?? resolveSpecialKey(config.code)) {\n case 'backward':\n next = navigateWithLoop(next, -1, { limit: itemCount, loop: config.loop });\n break;\n case 'forward':\n next = navigateWithLoop(next, 1, { limit: itemCount, loop: config.loop });\n break;\n case 'end':\n next = itemCount;\n break;\n case 'home':\n next = 0;\n break;\n case 'pageup':\n next = Math.max(0, next - 4);\n break;\n case 'pagedown':\n next = Math.min(itemCount, next + 4);\n break;\n case null:\n break;\n }\n\n return { next, previous };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"keynav-list.controller.js","names":[],"sources":["../../../src/internal/controllers/keynav-list.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport { focusElement, initializeKeyListItems, isFocusable, setActiveKeyListItem } from '../utils/focus.js';\nimport { KeynavCode, validKeyNavigationCode } from '../utils/dom.js';\n\nexport interface KeynavListConfig {\n items: NodeListOf<HTMLElement> | HTMLElement[];\n initialItem?: HTMLElement;\n layout?: 'both' | 'horizontal' | 'vertical';\n manageFocus?: boolean;\n manageTabindex?: boolean;\n loop?: boolean;\n dir?: string | null;\n}\n\nexport interface KeynavListElement {\n keynavListConfig: KeynavListConfig;\n}\n\n/** https://webaim.org/techniques/keyboard/ */\nexport function keyNavigationList<T extends ReactiveElement & KeynavListElement>(): ClassDecorator {\n return (target: LegacyDecoratorTarget) =>\n target.addInitializer!((instance: T) => new KeyNavigationListController(instance));\n}\n\nexport class KeyNavigationListController<T extends ReactiveElement & KeynavListElement> implements ReactiveController {\n get #config(): KeynavListConfig & { items: HTMLElement[] } {\n return {\n layout: 'horizontal',\n manageFocus: true,\n manageTabindex: true,\n loop: false,\n dir: this.host.getAttribute('rtl'),\n ...this.host.keynavListConfig,\n items: Array.from(this.host.keynavListConfig.items).filter(\n (i: HTMLElement & { disabled?: boolean }) => !i.disabled\n )\n };\n }\n\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n /** @private attr nve-keynav-disabled is an internal API for advanced use cases only */\n get #keynavDisabled() {\n return this.host.hasAttribute('nve-keynav-disabled');\n }\n\n async hostConnected() {\n await this.host.updateComplete;\n if (!this.host.isConnected) return;\n this.#initializeTabIndex();\n this.host.addEventListener('pointerup', this.#onPointerUp);\n this.host.addEventListener('keydown', this.#onKeyDown);\n }\n\n hostDisconnected() {\n this.host.removeEventListener('pointerup', this.#onPointerUp);\n this.host.removeEventListener('keydown', this.#onKeyDown);\n }\n\n #initializeTabIndex() {\n const { manageFocus, manageTabindex, items, initialItem } = this.#config;\n if (manageFocus && manageTabindex && !this.#keynavDisabled) {\n initializeKeyListItems(items);\n if (initialItem && items.includes(initialItem)) {\n setActiveKeyListItem(items, initialItem);\n }\n }\n }\n\n #clickItem(e: PointerEvent) {\n const item = this.#getPointerActiveItem(e, this.#config.items);\n if (item) {\n this.#setActiveItem(e, item);\n }\n }\n\n #focusItem(e: KeyboardEvent) {\n if (validKeyNavigationCode(e) && !this.#keynavDisabled) {\n const { loop, layout, dir, items } = this.#config;\n const activeItem = this.#getKeyboardActiveItem(e, items);\n if (activeItem) {\n const { next, previous } = getNextKeyListItem(activeItem, Array.from(items), {\n loop,\n layout,\n dir,\n code: e.code as KeynavCode\n });\n\n if (next !== previous) {\n this.#setActiveItem(e, items[next]!, items[previous]);\n }\n }\n }\n }\n\n #getKeyboardActiveItem(e: KeyboardEvent, items: HTMLElement[]) {\n const target = e.composedPath()[0];\n return target instanceof HTMLElement && items.includes(target) ? target : null;\n }\n\n #getPointerActiveItem(e: PointerEvent, items: HTMLElement[]) {\n const path = e.composedPath();\n const itemIndex = path.findIndex(item => item instanceof HTMLElement && items.includes(item));\n const item = path[itemIndex];\n\n if (!(item instanceof HTMLElement)) return null;\n\n const hasFocusableDescendant = path\n .slice(0, itemIndex)\n .some(descendant => descendant instanceof Element && isFocusable(descendant));\n return hasFocusableDescendant ? null : item;\n }\n\n #setActiveItem(e: KeyboardEvent | PointerEvent, activeItem: HTMLElement, previousItem?: HTMLElement) {\n const { manageFocus, manageTabindex, items } = this.#config;\n if (manageFocus) {\n if (manageTabindex) {\n setActiveKeyListItem(items, activeItem);\n }\n\n focusElement(activeItem);\n e.preventDefault();\n }\n\n const detail = {\n activeItem,\n previousItem,\n code: e instanceof KeyboardEvent ? e.code : null,\n metaKey: e.ctrlKey || e.metaKey,\n items\n };\n activeItem.dispatchEvent(new CustomEvent('nve-key-change', { bubbles: true, composed: true, detail }));\n }\n\n #onPointerUp = (e: PointerEvent) => this.#clickItem(e);\n\n #onKeyDown = (e: KeyboardEvent) => this.#focusItem(e);\n}\n\ninterface KeyListConfig {\n code: KeynavCode;\n loop?: boolean;\n layout?: 'horizontal' | 'vertical' | 'both';\n dir: string | null | undefined;\n}\n\nfunction resolveArrowDirection(config: KeyListConfig): 'backward' | 'forward' | null {\n const { code, layout, dir } = config;\n const start = dir === 'rtl' ? KeynavCode.ArrowRight : KeynavCode.ArrowLeft;\n const end = dir === 'rtl' ? KeynavCode.ArrowLeft : KeynavCode.ArrowRight;\n\n if (layout !== 'horizontal') {\n if (code === KeynavCode.ArrowUp) return 'backward';\n if (code === KeynavCode.ArrowDown) return 'forward';\n }\n\n if (layout !== 'vertical') {\n if (code === start) return 'backward';\n if (code === end) return 'forward';\n }\n\n return null;\n}\n\nfunction resolveSpecialKey(code: KeynavCode): 'home' | 'end' | 'pageup' | 'pagedown' | null {\n if (code === KeynavCode.End) return 'end';\n if (code === KeynavCode.Home) return 'home';\n if (code === KeynavCode.PageUp) return 'pageup';\n if (code === KeynavCode.PageDown) return 'pagedown';\n return null;\n}\n\nfunction navigateWithLoop(current: number, step: number, options: { limit: number; loop: boolean | undefined }) {\n const { limit, loop } = options;\n const next = current + step;\n if (next >= 0 && next <= limit) return next;\n return loop ? (step < 0 ? limit : 0) : current;\n}\n\nexport function getNextKeyListItem(item: HTMLElement, items: HTMLElement[], config: KeyListConfig) {\n let next = items.indexOf(item);\n const previous = next;\n const itemCount = items.length - 1;\n const direction = resolveArrowDirection(config);\n\n switch (direction ?? resolveSpecialKey(config.code)) {\n case 'backward':\n next = navigateWithLoop(next, -1, { limit: itemCount, loop: config.loop });\n break;\n case 'forward':\n next = navigateWithLoop(next, 1, { limit: itemCount, loop: config.loop });\n break;\n case 'end':\n next = itemCount;\n break;\n case 'home':\n next = 0;\n break;\n case 'pageup':\n next = Math.max(0, next - 4);\n break;\n case 'pagedown':\n next = Math.min(itemCount, next + 4);\n break;\n case null:\n break;\n }\n\n return { next, previous };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keynav-spatial.controller.js","names":[
|
|
1
|
+
{"version":3,"file":"keynav-spatial.controller.js","names":[],"sources":["../../../src/internal/controllers/keynav-spatial.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveControllerHost } from 'lit';\n\ntype SpatialKeyHost = ReactiveControllerHost & HTMLElement;\n\nexport type SpatialKeyHandling = 'handled' | 'ignored';\n\nexport type SpatialKeyCommand =\n | {\n readonly ctrlKey: boolean;\n readonly event: KeyboardEvent;\n readonly kind: 'direction';\n readonly horizontal: -1 | 0 | 1;\n readonly key: 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'ArrowUp';\n readonly shiftKey: boolean;\n readonly vertical: -1 | 0 | 1;\n }\n | {\n readonly event: KeyboardEvent;\n readonly kind: 'zoom';\n readonly key: '+' | '-' | '=';\n };\n\n/** Converts direct-host keyboard input into spatial direction and zoom commands. */\nexport class KeyNavigationSpatialController implements ReactiveController {\n readonly #host: SpatialKeyHost;\n\n constructor(host: SpatialKeyHost) {\n this.#host = host;\n host.addController(this);\n }\n\n hostConnected(): void {\n this.#host.addEventListener('keydown', this.#handleKeydown);\n }\n\n hostDisconnected(): void {\n this.#host.removeEventListener('keydown', this.#handleKeydown);\n }\n\n #handleKeydown = (event: KeyboardEvent): void => {\n if (event.composedPath()[0] !== this.#host) return;\n const command = getSpatialKeyCommand(event);\n if (!command) return;\n this.#host.dispatchEvent(\n new CustomEvent<SpatialKeyCommand>('nve-key', {\n bubbles: false,\n cancelable: false,\n composed: false,\n detail: command\n })\n );\n };\n}\n\nfunction getSpatialKeyCommand(event: KeyboardEvent): SpatialKeyCommand | undefined {\n switch (event.key) {\n case 'ArrowDown':\n return {\n ctrlKey: event.ctrlKey,\n event,\n horizontal: 0,\n key: event.key,\n kind: 'direction',\n shiftKey: event.shiftKey,\n vertical: -1\n };\n case 'ArrowLeft':\n return {\n ctrlKey: event.ctrlKey,\n event,\n horizontal: -1,\n key: event.key,\n kind: 'direction',\n shiftKey: event.shiftKey,\n vertical: 0\n };\n case 'ArrowRight':\n return {\n ctrlKey: event.ctrlKey,\n event,\n horizontal: 1,\n key: event.key,\n kind: 'direction',\n shiftKey: event.shiftKey,\n vertical: 0\n };\n case 'ArrowUp':\n return {\n ctrlKey: event.ctrlKey,\n event,\n horizontal: 0,\n key: event.key,\n kind: 'direction',\n shiftKey: event.shiftKey,\n vertical: 1\n };\n case '+':\n case '-':\n case '=':\n return { event, key: event.key, kind: 'zoom' };\n default:\n return undefined;\n }\n}\n"],"mappings":";AA0BA,IAAa,IAAb,MAA0E;CACxE;CAEA,YAAY,GAAsB;EAEhC,AADA,KAAK,KAAQ,GACb,EAAK,cAAc,IAAI;CACzB;CAEA,gBAAsB;EACpB,KAAK,GAAM,iBAAiB,WAAW,KAAK,EAAc;CAC5D;CAEA,mBAAyB;EACvB,KAAK,GAAM,oBAAoB,WAAW,KAAK,EAAc;CAC/D;CAEA,MAAkB,MAA+B;EAC/C,IAAI,EAAM,aAAa,CAAC,CAAC,OAAO,KAAK,IAAO;EAC5C,IAAM,IAAU,EAAqB,CAAK;EACrC,KACL,KAAK,GAAM,cACT,IAAI,YAA+B,WAAW;GAC5C,SAAS;GACT,YAAY;GACZ,UAAU;GACV,QAAQ;EACV,CAAC,CACH;CACF;AACF;AAEA,SAAS,EAAqB,GAAqD;CACjF,QAAQ,EAAM,KAAd;EACE,KAAK,aACH,OAAO;GACL,SAAS,EAAM;GACf;GACA,YAAY;GACZ,KAAK,EAAM;GACX,MAAM;GACN,UAAU,EAAM;GAChB,UAAU;EACZ;EACF,KAAK,aACH,OAAO;GACL,SAAS,EAAM;GACf;GACA,YAAY;GACZ,KAAK,EAAM;GACX,MAAM;GACN,UAAU,EAAM;GAChB,UAAU;EACZ;EACF,KAAK,cACH,OAAO;GACL,SAAS,EAAM;GACf;GACA,YAAY;GACZ,KAAK,EAAM;GACX,MAAM;GACN,UAAU,EAAM;GAChB,UAAU;EACZ;EACF,KAAK,WACH,OAAO;GACL,SAAS,EAAM;GACf;GACA,YAAY;GACZ,KAAK,EAAM;GACX,MAAM;GACN,UAAU,EAAM;GAChB,UAAU;EACZ;EACF,KAAK;EACL,KAAK;EACL,KAAK,KACH,OAAO;GAAE;GAAO,KAAK,EAAM;GAAK,MAAM;EAAO;EAC/C,SACE;CACJ;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-scroll.controller.js","names":[
|
|
1
|
+
{"version":3,"file":"state-scroll.controller.js","names":[],"sources":["../../../src/internal/controllers/state-scroll.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport { attachInternals, endOfScrollBox } from '@nvidia-elements/core/internal';\n\n/**\n * Adds active scroll state detection\n */\nexport function stateScroll<T extends Scroll>(): ClassDecorator {\n return (target: LegacyDecoratorTarget) =>\n target.addInitializer!((instance: T) => new StateScrollController(instance));\n}\n\nexport interface StateScrollConfig {\n target?: HTMLElement;\n scrollOffset?: number;\n}\n\nexport type Scroll = ReactiveElement & {\n _internals?: ElementInternals;\n stateScrollConfig?: StateScrollConfig;\n};\n\nexport class StateScrollController<T extends Scroll> implements ReactiveController {\n #activeTarget?: HTMLElement;\n\n get #target(): HTMLElement {\n const target = this.host.stateScrollConfig?.target;\n return target ? target : this.host;\n }\n\n get #offset() {\n return this.host.stateScrollConfig?.scrollOffset ?? 0;\n }\n\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n async hostConnected() {\n await this.host.updateComplete;\n attachInternals(this.host);\n this.#syncTarget();\n }\n\n hostUpdated() {\n this.#syncTarget();\n }\n\n hostDisconnected() {\n this.#removeTargetListeners();\n }\n\n #syncTarget() {\n const target = this.#target;\n if (this.#activeTarget === target) return;\n\n this.#removeTargetListeners();\n this.#activeTarget = target;\n this.#activeTarget.addEventListener('scrollend', this.#onScrollEnd);\n this.#startScroll();\n }\n\n #onScrollEnd = () => {\n this.host._internals!.states.delete('scrolling');\n\n if (this.#activeTarget && endOfScrollBox(this.#activeTarget, this.#offset)) {\n this.host.dispatchEvent(new CustomEvent('scrollboxend', { bubbles: true, composed: true }));\n }\n\n this.#startScroll();\n };\n\n #onScroll = () => {\n this.host._internals!.states.add('scrolling');\n };\n\n #startScroll() {\n this.#activeTarget?.removeEventListener('scroll', this.#onScroll);\n this.#activeTarget?.addEventListener('scroll', this.#onScroll, { once: true });\n }\n\n #removeTargetListeners() {\n this.#activeTarget?.removeEventListener('scroll', this.#onScroll);\n this.#activeTarget?.removeEventListener('scrollend', this.#onScrollEnd);\n this.#activeTarget = undefined;\n }\n}\n"],"mappings":";;;AAUA,SAAgB,IAAgD;CAC9D,QAAQ,MACN,EAAO,gBAAiB,MAAgB,IAAI,EAAsB,CAAQ,CAAC;AAC/E;AAYA,IAAa,IAAb,MAAmF;CACjF;CAEA,IAAI,KAAuB;EAEzB,OADe,KAAK,KAAK,mBAAmB,UACnB,KAAK;CAChC;CAEA,IAAI,KAAU;EACZ,OAAO,KAAK,KAAK,mBAAmB,gBAAgB;CACtD;CAEA,YAAY,GAAiB;EAC3B,AADkB,KAAA,OAAA,GAClB,KAAK,KAAK,cAAc,IAAI;CAC9B;CAEA,MAAM,gBAAgB;EAGpB,AAFA,MAAM,KAAK,KAAK,gBAChB,EAAgB,KAAK,IAAI,GACzB,KAAK,GAAY;CACnB;CAEA,cAAc;EACZ,KAAK,GAAY;CACnB;CAEA,mBAAmB;EACjB,KAAK,GAAuB;CAC9B;CAEA,KAAc;EACZ,IAAM,IAAS,KAAK;EAChB,KAAK,OAAkB,MAE3B,KAAK,GAAuB,GAC5B,KAAK,KAAgB,GACrB,KAAK,GAAc,iBAAiB,aAAa,KAAK,EAAY,GAClE,KAAK,GAAa;CACpB;CAEA,WAAqB;EAOnB,AANA,KAAK,KAAK,WAAY,OAAO,OAAO,WAAW,GAE3C,KAAK,MAAiB,EAAe,KAAK,IAAe,KAAK,EAAO,KACvE,KAAK,KAAK,cAAc,IAAI,YAAY,gBAAgB;GAAE,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC,GAG5F,KAAK,GAAa;CACpB;CAEA,WAAkB;EAChB,KAAK,KAAK,WAAY,OAAO,IAAI,WAAW;CAC9C;CAEA,KAAe;EAEb,AADA,KAAK,IAAe,oBAAoB,UAAU,KAAK,EAAS,GAChE,KAAK,IAAe,iBAAiB,UAAU,KAAK,IAAW,EAAE,MAAM,GAAK,CAAC;CAC/E;CAEA,KAAyB;EAGvB,AAFA,KAAK,IAAe,oBAAoB,UAAU,KAAK,EAAS,GAChE,KAAK,IAAe,oBAAoB,aAAa,KAAK,EAAY,GACtE,KAAK,KAAgB,KAAA;CACvB;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-anchor.controller.js","names":[
|
|
1
|
+
{"version":3,"file":"type-anchor.controller.js","names":[],"sources":["../../../src/internal/controllers/type-anchor.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport type { LegacyDecoratorTarget } from '../types/index.js';\nimport { removeEmptyTextNode } from '../utils/dom.js';\nimport { attachInternals } from '../utils/a11y.js';\n\n/**\n * Adds anchor/link support for interactive custom elements.\n */\nexport function typeAnchor<T extends Anchor>(): ClassDecorator {\n return (target: LegacyDecoratorTarget) => target.addInitializer!((instance: T) => new TypeAnchorController(instance));\n}\n\nexport interface Anchor extends ReactiveElement {\n disabled: boolean;\n readOnly: boolean;\n _internals: ElementInternals;\n}\n\nexport class TypeAnchorController<T extends Anchor> implements ReactiveController {\n get #anchor() {\n return this.#slottedAnchor ? this.#slottedAnchor : this.#parentAnchor;\n }\n\n get #slottedAnchor() {\n // return elements that nest in a slot\n return this.host\n .shadowRoot!.querySelector<HTMLSlotElement>('slot, slot[name=anchor]')\n ?.assignedElements()\n ?.find(e => e?.tagName === 'A');\n }\n\n get #parentAnchor() {\n return this.host.parentElement?.tagName === 'A' ? (this.host.parentElement as HTMLAnchorElement) : null;\n }\n\n get #defaultSlot() {\n return this.host.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n }\n\n get #anchorSlot() {\n return this.host.shadowRoot!.querySelector<HTMLSlotElement>('slot[name=anchor]');\n }\n\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n async hostConnected() {\n attachInternals(this.host);\n await this.host.updateComplete;\n\n this.#updateAnchorSlotAssignment();\n\n if (this.#anchor) {\n this.host.readOnly = true;\n this.host._internals?.states.add('anchor');\n } else {\n this.host._internals?.states.delete('anchor');\n }\n\n if (this.#parentAnchor) {\n this.#parentAnchor.style.textDecoration = 'none';\n this.host.style.cursor = 'pointer';\n }\n\n this.#anchor?.addEventListener('click', e => {\n if (this.host.disabled) {\n e.preventDefault();\n e.stopImmediatePropagation();\n }\n });\n }\n\n #updateAnchorSlotAssignment() {\n if (this.#anchor && this.#anchorSlot) {\n this.#anchor.slot = 'anchor';\n this.#defaultSlot?.assignedNodes().forEach(node => removeEmptyTextNode(node));\n }\n }\n}\n"],"mappings":";;;AAWA,SAAgB,IAA+C;CAC7D,QAAQ,MAAkC,EAAO,gBAAiB,MAAgB,IAAI,EAAqB,CAAQ,CAAC;AACtH;AAQA,IAAa,IAAb,MAAkF;CAChF,IAAI,KAAU;EACZ,OAAO,KAAK,KAAiB,KAAK,KAAiB,KAAK;CAC1D;CAEA,IAAI,KAAiB;EAEnB,OAAO,KAAK,KACT,WAAY,cAA+B,yBAAyB,CAAC,EACpE,iBAAiB,CAAC,EAClB,MAAK,MAAK,GAAG,YAAY,GAAG;CAClC;CAEA,IAAI,KAAgB;EAClB,OAAO,KAAK,KAAK,eAAe,YAAY,MAAO,KAAK,KAAK,gBAAsC;CACrG;CAEA,IAAI,KAAe;EACjB,OAAO,KAAK,KAAK,WAAY,cAA+B,kBAAkB;CAChF;CAEA,IAAI,KAAc;EAChB,OAAO,KAAK,KAAK,WAAY,cAA+B,mBAAmB;CACjF;CAEA,YAAY,GAAiB;EAC3B,AADkB,KAAA,OAAA,GAClB,KAAK,KAAK,cAAc,IAAI;CAC9B;CAEA,MAAM,gBAAgB;EAkBpB,AAjBA,EAAgB,KAAK,IAAI,GACzB,MAAM,KAAK,KAAK,gBAEhB,KAAK,GAA4B,GAE7B,KAAK,MACP,KAAK,KAAK,WAAW,IACrB,KAAK,KAAK,YAAY,OAAO,IAAI,QAAQ,KAEzC,KAAK,KAAK,YAAY,OAAO,OAAO,QAAQ,GAG1C,KAAK,OACP,KAAK,GAAc,MAAM,iBAAiB,QAC1C,KAAK,KAAK,MAAM,SAAS,YAG3B,KAAK,IAAS,iBAAiB,UAAS,MAAK;GAC3C,AAAI,KAAK,KAAK,aACZ,EAAE,eAAe,GACjB,EAAE,yBAAyB;EAE/B,CAAC;CACH;CAEA,KAA8B;EAC5B,AAAI,KAAK,MAAW,KAAK,OACvB,KAAK,GAAQ,OAAO,UACpB,KAAK,IAAc,cAAc,CAAC,CAAC,SAAQ,MAAQ,EAAoB,CAAI,CAAC;CAEhF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-closable.controller.js","names":[
|
|
1
|
+
{"version":3,"file":"type-closable.controller.js","names":[],"sources":["../../../src/internal/controllers/type-closable.controller.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\nimport { attachInternals } from '../utils/a11y.js';\n\nexport type TypeClosable = ReactiveElement & { closable: boolean };\n\n/**\n * Controller for enabling closable behavior for elements.\n */\nexport class TypeClosableController<T extends TypeClosable> implements ReactiveController {\n constructor(private host: T) {\n this.host.addController(this);\n }\n\n hostConnected() {\n attachInternals(this.host);\n\n this.host.addEventListener('command', () => {\n this.host.hidden = true;\n this.#dispatchEvent();\n });\n }\n\n close() {\n if (this.host.closable) {\n this.#dispatchEvent();\n }\n }\n\n #dispatchEvent() {\n this.host.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));\n }\n}\n"],"mappings":";;AAWA,IAAa,IAAb,MAA0F;CACxF,YAAY,GAAiB;EAC3B,AADkB,KAAA,OAAA,GAClB,KAAK,KAAK,cAAc,IAAI;CAC9B;CAEA,gBAAgB;EAGd,AAFA,EAAgB,KAAK,IAAI,GAEzB,KAAK,KAAK,iBAAiB,iBAAiB;GAE1C,AADA,KAAK,KAAK,SAAS,IACnB,KAAK,GAAe;EACtB,CAAC;CACH;CAEA,QAAQ;EACN,AAAI,KAAK,KAAK,YACZ,KAAK,GAAe;CAExB;CAEA,KAAiB;EACf,KAAK,KAAK,cAAc,IAAI,YAAY,SAAS;GAAE,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC;CACrF;AACF"}
|