@nvidia-elements/core 2.8.1 → 2.10.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.
Files changed (273) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +3 -7
  3. package/dist/accordion/accordion.d.ts +4 -4
  4. package/dist/accordion/accordion2.js +4 -4
  5. package/dist/alert/alert-group.d.ts +1 -1
  6. package/dist/alert/alert-group2.js +1 -1
  7. package/dist/alert/alert.d.ts +1 -1
  8. package/dist/alert/alert2.js +1 -1
  9. package/dist/avatar/avatar-group.d.ts +1 -1
  10. package/dist/avatar/avatar-group2.js +1 -1
  11. package/dist/avatar/avatar.d.ts +1 -1
  12. package/dist/avatar/avatar2.js +1 -1
  13. package/dist/badge/badge.d.ts +1 -1
  14. package/dist/badge/badge2.js +1 -1
  15. package/dist/breadcrumb/breadcrumb.d.ts +2 -1
  16. package/dist/breadcrumb/breadcrumb2.js +1 -1
  17. package/dist/breadcrumb/breadcrumb2.js.map +1 -1
  18. package/dist/bundle.d.ts +2 -0
  19. package/dist/bundles/index.d.ts +212 -1
  20. package/dist/bundles/index.js +6 -6
  21. package/dist/button/button.d.ts +1 -1
  22. package/dist/button/button2.js +1 -1
  23. package/dist/button-group/button-group.d.ts +1 -1
  24. package/dist/button-group/button-group2.js +1 -1
  25. package/dist/card/card.d.ts +4 -4
  26. package/dist/card/card2.js +4 -4
  27. package/dist/chat-message/chat-message.d.ts +1 -1
  28. package/dist/chat-message/chat-message2.js +1 -1
  29. package/dist/checkbox/checkbox-group2.js +1 -1
  30. package/dist/checkbox/checkbox2.js +1 -1
  31. package/dist/color/color.d.ts +1 -1
  32. package/dist/color/color2.js +1 -1
  33. package/dist/combobox/combobox.d.ts +2 -2
  34. package/dist/combobox/combobox2.js +1 -1
  35. package/dist/copy-button/copy-button.d.ts +1 -1
  36. package/dist/copy-button/copy-button2.js +1 -1
  37. package/dist/custom-elements-jsx.d.ts +125 -16
  38. package/dist/custom-elements-vue.d.ts +123 -16
  39. package/dist/custom-elements.json +3827 -1126
  40. package/dist/data.html.json +98 -4
  41. package/dist/date/date.d.ts +1 -1
  42. package/dist/date/date2.js +1 -1
  43. package/dist/datetime/datetime.d.ts +1 -1
  44. package/dist/datetime/datetime2.js +1 -1
  45. package/dist/dialog/dialog-footer.d.ts +1 -1
  46. package/dist/dialog/dialog-footer2.js +1 -1
  47. package/dist/dialog/dialog-header.d.ts +1 -1
  48. package/dist/dialog/dialog-header2.js +1 -1
  49. package/dist/dialog/dialog.d.ts +1 -1
  50. package/dist/dialog/dialog2.js +1 -1
  51. package/dist/divider/divider.d.ts +1 -1
  52. package/dist/divider/divider2.js +1 -1
  53. package/dist/dot/dot.d.ts +1 -1
  54. package/dist/dot/dot2.js +1 -1
  55. package/dist/drawer/drawer-content.d.ts +1 -1
  56. package/dist/drawer/drawer-content2.js +1 -1
  57. package/dist/drawer/drawer-footer.d.ts +1 -1
  58. package/dist/drawer/drawer-footer2.js +1 -1
  59. package/dist/drawer/drawer-header.d.ts +1 -1
  60. package/dist/drawer/drawer-header2.js +1 -1
  61. package/dist/drawer/drawer.d.ts +1 -1
  62. package/dist/drawer/drawer2.js +1 -1
  63. package/dist/dropdown/dropdown-footer.d.ts +1 -1
  64. package/dist/dropdown/dropdown-footer2.js +1 -1
  65. package/dist/dropdown/dropdown-header.d.ts +1 -1
  66. package/dist/dropdown/dropdown-header2.js +1 -1
  67. package/dist/dropdown/dropdown.d.ts +1 -1
  68. package/dist/dropdown/dropdown2.js +1 -1
  69. package/dist/dropdown-group/dropdown-group.d.ts +1 -1
  70. package/dist/dropdown-group/dropdown-group.js +1 -1
  71. package/dist/dropzone/dropzone.d.ts +1 -1
  72. package/dist/dropzone/dropzone2.js +1 -1
  73. package/dist/file/file2.js +1 -1
  74. package/dist/format-bytes/format-bytes.d.ts +1 -1
  75. package/dist/format-bytes/format-bytes2.js +1 -1
  76. package/dist/format-datetime/format-datetime.d.ts +1 -1
  77. package/dist/format-datetime/format-datetime2.js +1 -1
  78. package/dist/format-number/format-number.d.ts +1 -1
  79. package/dist/format-number/format-number2.js +1 -1
  80. package/dist/format-relative-time/format-relative-time.d.ts +1 -1
  81. package/dist/format-relative-time/format-relative-time2.js +1 -1
  82. package/dist/format-truncate/format-truncate2.js +1 -1
  83. package/dist/forms/control/control2.js +1 -1
  84. package/dist/forms/control-group/control-group.d.ts +3 -1
  85. package/dist/forms/control-group/control-group2.js +1 -1
  86. package/dist/forms/control-group/control-group2.js.map +1 -1
  87. package/dist/forms/control-message/control-message.d.ts +1 -1
  88. package/dist/forms/control-message/control-message2.js +1 -1
  89. package/dist/gauge/gauge.d.ts +1 -1
  90. package/dist/gauge/gauge2.js +1 -1
  91. package/dist/grid/cell/cell.d.ts +1 -1
  92. package/dist/grid/cell/cell2.js +1 -1
  93. package/dist/grid/column/column.d.ts +1 -1
  94. package/dist/grid/column/column2.js +1 -1
  95. package/dist/grid/footer/footer.d.ts +1 -1
  96. package/dist/grid/footer/footer2.js +1 -1
  97. package/dist/grid/grid.d.ts +3 -1
  98. package/dist/grid/grid2.js +1 -1
  99. package/dist/grid/grid2.js.map +1 -1
  100. package/dist/grid/header/header.d.ts +1 -1
  101. package/dist/grid/header/header2.js +1 -1
  102. package/dist/grid/placeholder/placeholder.d.ts +1 -1
  103. package/dist/grid/placeholder/placeholder2.js +1 -1
  104. package/dist/grid/row/row.d.ts +1 -1
  105. package/dist/grid/row/row2.js +1 -1
  106. package/dist/icon/icon.d.ts +1 -1
  107. package/dist/icon/icon2.js +2 -2
  108. package/dist/icon-button/icon-button.d.ts +1 -1
  109. package/dist/icon-button/icon-button2.js +1 -1
  110. package/dist/index.js +1 -1
  111. package/dist/input/input-group2.js +1 -1
  112. package/dist/input/input2.js +1 -1
  113. package/dist/internal/controllers/gesture.controller.d.ts +122 -42
  114. package/dist/internal/controllers/gesture.controller.examples.js.map +1 -1
  115. package/dist/internal/controllers/gesture.controller.examples.json +2 -2
  116. package/dist/internal/controllers/gesture.controller.js +300 -159
  117. package/dist/internal/controllers/gesture.controller.js.map +1 -1
  118. package/dist/internal/controllers/key-state.controller.d.ts +18 -0
  119. package/dist/internal/controllers/key-state.controller.js +84 -0
  120. package/dist/internal/controllers/key-state.controller.js.map +1 -0
  121. package/dist/internal/controllers/keynav-list.controller.js.map +1 -1
  122. package/dist/internal/controllers/keynav-spatial.controller.d.ts +4 -1
  123. package/dist/internal/controllers/keynav-spatial.controller.js +7 -6
  124. package/dist/internal/controllers/keynav-spatial.controller.js.map +1 -1
  125. package/dist/internal/index.d.ts +2 -0
  126. package/dist/internal/index.js +29 -27
  127. package/dist/internal/services/global.service.js +1 -1
  128. package/dist/internal/utils/dom.d.ts +4 -1
  129. package/dist/internal/utils/dom.js +42 -38
  130. package/dist/internal/utils/dom.js.map +1 -1
  131. package/dist/internal/utils/focus.d.ts +2 -0
  132. package/dist/internal/utils/focus.js +14 -7
  133. package/dist/internal/utils/focus.js.map +1 -1
  134. package/dist/internal/utils/numeric.d.ts +3 -0
  135. package/dist/internal/utils/numeric.js +14 -0
  136. package/dist/internal/utils/numeric.js.map +1 -0
  137. package/dist/logo/logo.d.ts +1 -1
  138. package/dist/logo/logo2.js +1 -1
  139. package/dist/menu/menu-item.d.ts +1 -1
  140. package/dist/menu/menu-item2.js +1 -1
  141. package/dist/menu/menu.d.ts +1 -1
  142. package/dist/menu/menu2.js +1 -1
  143. package/dist/month/month.d.ts +1 -1
  144. package/dist/month/month2.js +1 -1
  145. package/dist/notification/notification-group.d.ts +1 -1
  146. package/dist/notification/notification-group2.js +1 -1
  147. package/dist/notification/notification.d.ts +1 -1
  148. package/dist/notification/notification2.js +1 -1
  149. package/dist/page/page-panel/page-panel-content.d.ts +1 -1
  150. package/dist/page/page-panel/page-panel-content2.js +1 -1
  151. package/dist/page/page-panel/page-panel-footer.d.ts +1 -1
  152. package/dist/page/page-panel/page-panel-footer2.js +1 -1
  153. package/dist/page/page-panel/page-panel-header.d.ts +1 -1
  154. package/dist/page/page-panel/page-panel-header2.js +1 -1
  155. package/dist/page/page-panel/page-panel.d.ts +1 -1
  156. package/dist/page/page-panel/page-panel2.js +1 -1
  157. package/dist/page/page.d.ts +1 -1
  158. package/dist/page/page2.js +1 -1
  159. package/dist/page-header/page-header.d.ts +1 -1
  160. package/dist/page-header/page-header2.js +1 -1
  161. package/dist/page-loader/page-loader.d.ts +1 -1
  162. package/dist/page-loader/page-loader2.js +1 -1
  163. package/dist/pagination/pagination.d.ts +1 -1
  164. package/dist/pagination/pagination2.js +1 -1
  165. package/dist/panel/panel.d.ts +4 -4
  166. package/dist/panel/panel2.js +4 -4
  167. package/dist/password/password.d.ts +1 -1
  168. package/dist/password/password2.js +1 -1
  169. package/dist/preferences-input/preferences-input.d.ts +1 -1
  170. package/dist/preferences-input/preferences-input2.js +1 -1
  171. package/dist/progress-bar/progress-bar.d.ts +1 -1
  172. package/dist/progress-bar/progress-bar2.js +1 -1
  173. package/dist/progress-ring/progress-ring.d.ts +1 -1
  174. package/dist/progress-ring/progress-ring2.js +1 -1
  175. package/dist/progressive-filter-chip/progressive-filter-chip.d.ts +1 -1
  176. package/dist/progressive-filter-chip/progressive-filter-chip2.js +1 -1
  177. package/dist/pulse/pulse.d.ts +1 -1
  178. package/dist/pulse/pulse2.js +1 -1
  179. package/dist/radio/radio-group2.js +1 -1
  180. package/dist/radio/radio2.js +1 -1
  181. package/dist/range/range.d.ts +1 -1
  182. package/dist/range/range2.js +1 -1
  183. package/dist/resize-handle/resize-handle.d.ts +1 -1
  184. package/dist/resize-handle/resize-handle2.js +6 -10
  185. package/dist/resize-handle/resize-handle2.js.map +1 -1
  186. package/dist/search/search.d.ts +1 -1
  187. package/dist/search/search2.js +1 -1
  188. package/dist/select/select.d.ts +2 -2
  189. package/dist/select/select2.js +1 -1
  190. package/dist/skeleton/skeleton.d.ts +1 -1
  191. package/dist/skeleton/skeleton2.js +1 -1
  192. package/dist/sort-button/sort-button.d.ts +1 -1
  193. package/dist/sort-button/sort-button2.js +1 -1
  194. package/dist/sparkline/sparkline.d.ts +1 -1
  195. package/dist/sparkline/sparkline2.js +1 -1
  196. package/dist/star-rating/star-rating.d.ts +1 -1
  197. package/dist/star-rating/star-rating2.js +1 -1
  198. package/dist/steps/steps.d.ts +2 -2
  199. package/dist/steps/steps2.js +2 -2
  200. package/dist/switch/switch-group2.js +1 -1
  201. package/dist/switch/switch2.js +1 -1
  202. package/dist/tabs/tabs-group.d.ts +1 -1
  203. package/dist/tabs/tabs-group2.js +1 -1
  204. package/dist/tabs/tabs.d.ts +2 -2
  205. package/dist/tabs/tabs2.js +2 -2
  206. package/dist/tag/tag.d.ts +1 -1
  207. package/dist/tag/tag2.js +1 -1
  208. package/dist/textarea/textarea.d.ts +2 -2
  209. package/dist/textarea/textarea2.js +1 -1
  210. package/dist/time/time.d.ts +1 -1
  211. package/dist/time/time2.js +1 -1
  212. package/dist/toast/toast.d.ts +1 -1
  213. package/dist/toast/toast2.js +1 -1
  214. package/dist/toggletip/toggletip-footer.d.ts +1 -1
  215. package/dist/toggletip/toggletip-footer2.js +1 -1
  216. package/dist/toggletip/toggletip-header.d.ts +1 -1
  217. package/dist/toggletip/toggletip-header2.js +1 -1
  218. package/dist/toggletip/toggletip.d.ts +1 -1
  219. package/dist/toggletip/toggletip2.js +1 -1
  220. package/dist/toolbar/toolbar.d.ts +1 -1
  221. package/dist/toolbar/toolbar2.js +1 -1
  222. package/dist/tooltip/tooltip.d.ts +1 -1
  223. package/dist/tooltip/tooltip2.js +1 -1
  224. package/dist/tree/tree-node.d.ts +2 -2
  225. package/dist/tree/tree-node2.js +1 -1
  226. package/dist/tree/tree-node2.js.map +1 -1
  227. package/dist/tree/tree.d.ts +2 -1
  228. package/dist/tree/tree2.js +1 -1
  229. package/dist/tree/tree2.js.map +1 -1
  230. package/dist/viewport/define.d.ts +7 -0
  231. package/dist/viewport/define.js +7 -0
  232. package/dist/viewport/define.js.map +1 -0
  233. package/dist/viewport/index.d.ts +3 -0
  234. package/dist/viewport/index.js +3 -0
  235. package/dist/viewport/viewport-animation.controller.d.ts +21 -0
  236. package/dist/viewport/viewport-animation.controller.js +93 -0
  237. package/dist/viewport/viewport-animation.controller.js.map +1 -0
  238. package/dist/viewport/viewport-autofit.controller.d.ts +18 -0
  239. package/dist/viewport/viewport-autofit.controller.js +105 -0
  240. package/dist/viewport/viewport-autofit.controller.js.map +1 -0
  241. package/dist/viewport/viewport-fitting.utils.d.ts +36 -0
  242. package/dist/viewport/viewport-fitting.utils.js +35 -0
  243. package/dist/viewport/viewport-fitting.utils.js.map +1 -0
  244. package/dist/viewport/viewport-gesture-navigation.controller.d.ts +29 -0
  245. package/dist/viewport/viewport-gesture-navigation.controller.js +311 -0
  246. package/dist/viewport/viewport-gesture-navigation.controller.js.map +1 -0
  247. package/dist/viewport/viewport-gridlines.d.ts +38 -0
  248. package/dist/viewport/viewport-gridlines.js +6 -0
  249. package/dist/viewport/viewport-gridlines.js.map +1 -0
  250. package/dist/viewport/viewport-gridlines.utils.d.ts +11 -0
  251. package/dist/viewport/viewport-gridlines.utils.js +54 -0
  252. package/dist/viewport/viewport-gridlines.utils.js.map +1 -0
  253. package/dist/viewport/viewport-gridlines2.js +154 -0
  254. package/dist/viewport/viewport-gridlines2.js.map +1 -0
  255. package/dist/viewport/viewport-navigation.controller.d.ts +27 -0
  256. package/dist/viewport/viewport-navigation.controller.js +142 -0
  257. package/dist/viewport/viewport-navigation.controller.js.map +1 -0
  258. package/dist/viewport/viewport-navigation.types.d.ts +9 -0
  259. package/dist/viewport/viewport-projection.utils.d.ts +7 -0
  260. package/dist/viewport/viewport-projection.utils.js +25 -0
  261. package/dist/viewport/viewport-projection.utils.js.map +1 -0
  262. package/dist/viewport/viewport.d.ts +92 -0
  263. package/dist/viewport/viewport.examples.js +6 -0
  264. package/dist/viewport/viewport.examples.js.map +1 -0
  265. package/dist/viewport/viewport.examples.json +60 -0
  266. package/dist/viewport/viewport.js +6 -0
  267. package/dist/viewport/viewport.js.map +1 -0
  268. package/dist/viewport/viewport.types.d.ts +66 -0
  269. package/dist/viewport/viewport2.js +375 -0
  270. package/dist/viewport/viewport2.js.map +1 -0
  271. package/dist/week/week.d.ts +1 -1
  272. package/dist/week/week2.js +1 -1
  273. package/package.json +19 -4
@@ -0,0 +1,154 @@
1
+ import { hostAttr as e } from "../internal/decorators/host-attr.js";
2
+ import { useStyles as t } from "../internal/styles/index.js";
3
+ import { finiteOr as n, positiveFiniteOr as r } from "../internal/utils/numeric.js";
4
+ import i from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
5
+ import { Viewport as a } from "./viewport2.js";
6
+ import o from "./viewport-gridlines.js";
7
+ import { createGridlineCoverage as s, gridlineCoverageNeedsUpdate as c, selectGridlineInterval as l } from "./viewport-gridlines.utils.js";
8
+ import { LitElement as u, html as d, nothing as f } from "lit";
9
+ import { property as p } from "lit/decorators/property.js";
10
+ import { styleMap as m } from "lit/directives/style-map.js";
11
+ //#region src/viewport/viewport-gridlines.ts
12
+ var h = 10, g = 64, _ = class extends u {
13
+ constructor(...e) {
14
+ super(...e), this.slot = "background", this.accessibilityHidden = "true", this.#e = h, this.#t = 0, this.#n = 0, this.#r = g, this.#s = () => {
15
+ let e = this.#i;
16
+ e && (this.style.setProperty("--_scale", `${e.scale}`), this.#l());
17
+ }, this.#c = () => {
18
+ this.#l({ forceCoverage: !0 });
19
+ };
20
+ }
21
+ static {
22
+ this.styles = t([o]);
23
+ }
24
+ static {
25
+ this.metadata = {
26
+ tag: "nve-viewport-gridlines",
27
+ version: "2.10.0"
28
+ };
29
+ }
30
+ #e;
31
+ #t;
32
+ #n;
33
+ #r;
34
+ #i;
35
+ #a;
36
+ #o;
37
+ get step() {
38
+ return this.#e;
39
+ }
40
+ set step(e) {
41
+ let t = r(e, h);
42
+ if (t === this.#e) return;
43
+ let n = this.#e;
44
+ this.#e = t, this.requestUpdate("step", n);
45
+ }
46
+ get originX() {
47
+ return this.#t;
48
+ }
49
+ set originX(e) {
50
+ let t = n(e, 0);
51
+ if (t === this.#t) return;
52
+ let r = this.#t;
53
+ this.#t = t, this.requestUpdate("originX", r);
54
+ }
55
+ get originY() {
56
+ return this.#n;
57
+ }
58
+ set originY(e) {
59
+ let t = n(e, 0);
60
+ if (t === this.#n) return;
61
+ let r = this.#n;
62
+ this.#n = t, this.requestUpdate("originY", r);
63
+ }
64
+ get targetSpacing() {
65
+ return this.#r;
66
+ }
67
+ set targetSpacing(e) {
68
+ let t = r(e, g);
69
+ if (t === this.#r) return;
70
+ let n = this.#r;
71
+ this.#r = t, this.requestUpdate("targetSpacing", n);
72
+ }
73
+ connectedCallback() {
74
+ super.connectedCallback();
75
+ let e = this.parentElement?.closest(a.metadata.tag);
76
+ !(e instanceof a) || e !== this.parentElement || (this.#i = e, this.style.setProperty("--_scale", `${e.scale}`), this.#i.addEventListener("viewportchange", this.#s), typeof ResizeObserver < "u" && (this.#a = new ResizeObserver(this.#c), this.#a.observe(e)), this.#u({
77
+ forceCoverage: !0,
78
+ resetInterval: !0
79
+ }));
80
+ }
81
+ disconnectedCallback() {
82
+ this.#i && this.#i.removeEventListener("viewportchange", this.#s), this.#a?.disconnect(), this.#a = void 0, this.#i = void 0, this.#o = void 0, super.disconnectedCallback();
83
+ }
84
+ willUpdate(e) {
85
+ super.willUpdate(e), (e.has("step") || e.has("targetSpacing")) && this.#u({
86
+ forceCoverage: !0,
87
+ resetInterval: !0
88
+ });
89
+ }
90
+ render() {
91
+ let e = this.#o;
92
+ if (!e) return f;
93
+ let { coverage: t, interval: n } = e;
94
+ return d`<svg internal-host aria-hidden="true" focusable="false" preserveAspectRatio="none" style="${m(y(t))}" viewBox="${t.x} ${t.y} ${t.width} ${t.height}"><defs><pattern data-gridline-pattern id="gridlines" x="${this.#t}" y="${this.#n}" width="${n}" height="${n}" patternUnits="userSpaceOnUse"><path d="M ${n} 0 H 0 V ${n}"></path></pattern></defs><rect x="${t.x}" y="${t.y}" width="${t.width}" height="${t.height}" fill="url(#gridlines)"></rect></svg>`;
95
+ }
96
+ #s;
97
+ #c;
98
+ #l(e = {}) {
99
+ this.#u(e) && this.requestUpdate();
100
+ }
101
+ #u(e = {}) {
102
+ let t = this.#i;
103
+ if (!t) return !1;
104
+ let n = t.getVisibleRect();
105
+ if (n.width <= 0 || n.height <= 0) return !1;
106
+ let r = l({
107
+ current: e.resetInterval ? void 0 : this.#o?.interval,
108
+ scale: t.scale,
109
+ step: this.#e,
110
+ targetSpacing: this.#r
111
+ }), i = v({
112
+ forceCoverage: e.forceCoverage === !0,
113
+ interval: r,
114
+ previous: this.#o,
115
+ visible: n
116
+ });
117
+ return i ? (this.#o = i, !0) : !1;
118
+ }
119
+ };
120
+ i([e()], _.prototype, "slot", void 0), i([e({ attribute: "aria-hidden" })], _.prototype, "accessibilityHidden", void 0), i([p({
121
+ type: Number,
122
+ reflect: !0
123
+ })], _.prototype, "step", null), i([p({
124
+ type: Number,
125
+ attribute: "origin-x",
126
+ reflect: !0
127
+ })], _.prototype, "originX", null), i([p({
128
+ type: Number,
129
+ attribute: "origin-y",
130
+ reflect: !0
131
+ })], _.prototype, "originY", null), i([p({
132
+ type: Number,
133
+ attribute: "target-spacing",
134
+ reflect: !0
135
+ })], _.prototype, "targetSpacing", null);
136
+ function v({ forceCoverage: e, interval: t, previous: n, visible: r }) {
137
+ let i = e || c(n?.coverage, r), a = t !== n?.interval;
138
+ if (!(!i && !a)) return {
139
+ coverage: i || !n ? s(r) : n.coverage,
140
+ interval: t
141
+ };
142
+ }
143
+ function y(e) {
144
+ return {
145
+ height: `${e.height}px`,
146
+ left: `${e.x}px`,
147
+ top: `${e.y}px`,
148
+ width: `${e.width}px`
149
+ };
150
+ }
151
+ //#endregion
152
+ export { _ as ViewportGridlines };
153
+
154
+ //# sourceMappingURL=viewport-gridlines2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-gridlines2.js","names":[],"sources":["../../src/viewport/viewport-gridlines.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { html, LitElement, nothing, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators/property.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { finiteOr, hostAttr, positiveFiniteOr, useStyles } from '@nvidia-elements/core/internal';\nimport styles from './viewport-gridlines.css?inline';\nimport {\n createGridlineCoverage,\n gridlineCoverageNeedsUpdate,\n selectGridlineInterval\n} from './viewport-gridlines.utils.js';\nimport { Viewport } from './viewport.js';\nimport type { ViewportRect } from './viewport.types.js';\n\nconst DEFAULT_STEP = 10;\nconst DEFAULT_TARGET_SPACING = 64;\n\ninterface GridlineProjection {\n readonly coverage: ViewportRect;\n readonly interval: number;\n}\n\ninterface ProjectionSyncOptions {\n readonly forceCoverage?: boolean;\n readonly resetInterval?: boolean;\n}\n\n/**\n * @element nve-viewport-gridlines\n * @description Renders origin-stable, zoom-adaptive gridlines behind viewport content.\n * @documentation https://nvidia.github.io/elements/docs/elements/viewport/\n * @since 0.0.0\n * @entrypoint \\@nvidia-elements/core/viewport\n * @cssprop --color - Sets the gridline stroke color.\n * @cssprop --line-width - Sets the approximate stroke width in CSS pixels.\n */\nexport class ViewportGridlines extends LitElement {\n static styles = useStyles([styles]);\n\n static readonly metadata = {\n tag: 'nve-viewport-gridlines',\n version: '0.0.0'\n };\n\n /** @private */\n @hostAttr() slot = 'background';\n\n /** @private */\n @hostAttr({ attribute: 'aria-hidden' }) protected accessibilityHidden = 'true';\n\n #step = DEFAULT_STEP;\n #originX = 0;\n #originY = 0;\n #targetSpacing = DEFAULT_TARGET_SPACING;\n #viewport?: Viewport;\n #resizeObserver?: ResizeObserver;\n #projection?: GridlineProjection;\n\n /** Smallest gridline interval in content-space units. */\n @property({ type: Number, reflect: true })\n get step(): number {\n return this.#step;\n }\n\n set step(value: number) {\n const next = positiveFiniteOr(value, DEFAULT_STEP);\n if (next === this.#step) return;\n const previous = this.#step;\n this.#step = next;\n this.requestUpdate('step', previous);\n }\n\n /** Content-space x coordinate of the grid origin. */\n @property({ type: Number, attribute: 'origin-x', reflect: true })\n get originX(): number {\n return this.#originX;\n }\n\n set originX(value: number) {\n const next = finiteOr(value, 0);\n if (next === this.#originX) return;\n const previous = this.#originX;\n this.#originX = next;\n this.requestUpdate('originX', previous);\n }\n\n /** Content-space y coordinate of the grid origin. */\n @property({ type: Number, attribute: 'origin-y', reflect: true })\n get originY(): number {\n return this.#originY;\n }\n\n set originY(value: number) {\n const next = finiteOr(value, 0);\n if (next === this.#originY) return;\n const previous = this.#originY;\n this.#originY = next;\n this.requestUpdate('originY', previous);\n }\n\n /** Target on-screen separation used to choose the adaptive gridline interval, in CSS pixels. */\n @property({ type: Number, attribute: 'target-spacing', reflect: true })\n get targetSpacing(): number {\n return this.#targetSpacing;\n }\n\n set targetSpacing(value: number) {\n const next = positiveFiniteOr(value, DEFAULT_TARGET_SPACING);\n if (next === this.#targetSpacing) return;\n const previous = this.#targetSpacing;\n this.#targetSpacing = next;\n this.requestUpdate('targetSpacing', previous);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n const viewport = this.parentElement?.closest(Viewport.metadata.tag);\n if (!(viewport instanceof Viewport) || viewport !== this.parentElement) return;\n this.#viewport = viewport;\n this.style.setProperty('--_scale', `${viewport.scale}`);\n this.#viewport.addEventListener('viewportchange', this.#handleViewportChange);\n if (typeof ResizeObserver !== 'undefined') {\n this.#resizeObserver = new ResizeObserver(this.#handleViewportResize);\n this.#resizeObserver.observe(viewport);\n }\n this.#updateProjection({ forceCoverage: true, resetInterval: true });\n }\n\n disconnectedCallback(): void {\n if (this.#viewport) {\n this.#viewport.removeEventListener('viewportchange', this.#handleViewportChange);\n }\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = undefined;\n this.#viewport = undefined;\n this.#projection = undefined;\n super.disconnectedCallback();\n }\n\n protected willUpdate(changed: PropertyValues<this>): void {\n super.willUpdate(changed);\n if (changed.has('step') || changed.has('targetSpacing')) {\n this.#updateProjection({ forceCoverage: true, resetInterval: true });\n }\n }\n\n render() {\n const projection = this.#projection;\n if (!projection) return nothing;\n const { coverage, interval } = projection;\n return html`\n <svg\n internal-host\n aria-hidden=\"true\"\n focusable=\"false\"\n preserveAspectRatio=\"none\"\n style=${styleMap(coverageStyles(coverage))}\n viewBox=\"${coverage.x} ${coverage.y} ${coverage.width} ${coverage.height}\"\n >\n <defs>\n <pattern\n data-gridline-pattern\n id=\"gridlines\"\n x=${this.#originX}\n y=${this.#originY}\n width=${interval}\n height=${interval}\n patternUnits=\"userSpaceOnUse\"\n >\n <path d=\"M ${interval} 0 H 0 V ${interval}\"></path>\n </pattern>\n </defs>\n <rect\n x=${coverage.x}\n y=${coverage.y}\n width=${coverage.width}\n height=${coverage.height}\n fill=\"url(#gridlines)\"\n ></rect>\n </svg>\n `;\n }\n\n #handleViewportChange = (): void => {\n const viewport = this.#viewport;\n if (!viewport) return;\n this.style.setProperty('--_scale', `${viewport.scale}`);\n this.#requestProjectionUpdate();\n };\n\n #handleViewportResize = (): void => {\n this.#requestProjectionUpdate({ forceCoverage: true });\n };\n\n #requestProjectionUpdate(options: ProjectionSyncOptions = {}): void {\n if (this.#updateProjection(options)) this.requestUpdate();\n }\n\n #updateProjection(options: ProjectionSyncOptions = {}): boolean {\n const viewport = this.#viewport;\n if (!viewport) return false;\n const visible = viewport.getVisibleRect();\n if (visible.width <= 0 || visible.height <= 0) return false;\n const interval = selectGridlineInterval({\n current: options.resetInterval ? undefined : this.#projection?.interval,\n scale: viewport.scale,\n step: this.#step,\n targetSpacing: this.#targetSpacing\n });\n const projection = nextProjection({\n forceCoverage: options.forceCoverage === true,\n interval,\n previous: this.#projection,\n visible\n });\n if (!projection) return false;\n this.#projection = projection;\n return true;\n }\n}\n\nfunction nextProjection({\n forceCoverage,\n interval,\n previous,\n visible\n}: {\n forceCoverage: boolean;\n interval: number;\n previous?: GridlineProjection;\n visible: ViewportRect;\n}): GridlineProjection | undefined {\n const coverageChanged = forceCoverage || gridlineCoverageNeedsUpdate(previous?.coverage, visible);\n const intervalChanged = interval !== previous?.interval;\n if (!coverageChanged && !intervalChanged) return undefined;\n const coverage = coverageChanged || !previous ? createGridlineCoverage(visible) : previous.coverage;\n return { coverage, interval };\n}\n\nfunction coverageStyles(coverage: ViewportRect): Record<string, string> {\n return {\n height: `${coverage.height}px`,\n left: `${coverage.x}px`,\n top: `${coverage.y}px`,\n width: `${coverage.width}px`\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { ReactiveController, ReactiveControllerHost } from 'lit';
2
+ import type { ViewportAnimationOptions, ViewportPanBehavior, ViewportPoint, ViewportTransform } from './viewport.types.js';
3
+ import type { ViewportNavigationEventDelegate, ViewportZoomAction } from './viewport-navigation.types.js';
4
+ type ViewportNavigationHost = HTMLElement & ReactiveControllerHost & {
5
+ readonly behaviorPan: ViewportPanBehavior;
6
+ readonly behaviorZoom: boolean;
7
+ };
8
+ export interface ViewportNavigationDelegate {
9
+ readonly animateTo: (target: Partial<ViewportTransform>, options?: ViewportAnimationOptions) => void;
10
+ readonly commitTransform: (next: ViewportTransform) => boolean;
11
+ readonly cancelAnimation: () => void;
12
+ readonly consumeAutoFit: () => void;
13
+ readonly events: ViewportNavigationEventDelegate;
14
+ readonly getTransform: () => ViewportTransform;
15
+ readonly getZoomTarget: (action: ViewportZoomAction) => ViewportTransform | undefined;
16
+ readonly rebasePointerSessions: () => void;
17
+ readonly viewportToClient: (viewportX: number, viewportY: number) => ViewportPoint;
18
+ }
19
+ /** Coordinates the viewport's opt-in keyboard and Invoker navigation behavior. */
20
+ export declare class ViewportNavigationController implements ReactiveController {
21
+ #private;
22
+ constructor(host: ViewportNavigationHost, delegate: ViewportNavigationDelegate);
23
+ hostConnected(): void;
24
+ hostDisconnected(): void;
25
+ hostUpdated(): void;
26
+ }
27
+ export {};
@@ -0,0 +1,142 @@
1
+ import { isImmediateRootActiveElement as e } from "../internal/utils/focus.js";
2
+ import { KeyNavigationSpatialController as t } from "../internal/controllers/keynav-spatial.controller.js";
3
+ import { contentPointFromViewport as n } from "./viewport-projection.utils.js";
4
+ //#region src/viewport/viewport-navigation.controller.ts
5
+ var r = 20, i = 100, a = class {
6
+ #e;
7
+ #t;
8
+ #n = !1;
9
+ constructor(e, n) {
10
+ this.#e = e, this.#t = n, e.addController(this), new t(e, { isEnabled: () => !!e.behaviorPan || e.behaviorZoom });
11
+ }
12
+ hostConnected() {
13
+ this.#e.addEventListener("nve-key", this.#i), this.#e.addEventListener("command", this.#r), this.#e.addEventListener("keydown", this.#o), this.#u(!!this.#e.behaviorPan || this.#e.behaviorZoom);
14
+ }
15
+ hostDisconnected() {
16
+ this.#e.removeEventListener("nve-key", this.#i), this.#e.removeEventListener("command", this.#r), this.#e.removeEventListener("keydown", this.#o);
17
+ }
18
+ hostUpdated() {
19
+ this.#u(!!this.#e.behaviorPan || this.#e.behaviorZoom);
20
+ }
21
+ #r = (e) => {
22
+ let t = this.#e.behaviorPan ? o(e.command) : void 0;
23
+ if (t) {
24
+ this.#a(e, {
25
+ direction: t,
26
+ source: "command",
27
+ viewportPixelStep: r
28
+ });
29
+ return;
30
+ }
31
+ if (!this.#e.behaviorZoom) return;
32
+ let n = s(e.command);
33
+ if (!n) return;
34
+ let i = this.#t.getZoomTarget(n);
35
+ i && this.#s(e, i, "command");
36
+ };
37
+ #i = (e) => {
38
+ let t = e.detail;
39
+ if (t.kind === "direction") {
40
+ if (!this.#l(t.event)) return;
41
+ t.event.preventDefault(), this.#a(t.event, {
42
+ direction: c(t.key),
43
+ source: "keyboard",
44
+ viewportPixelStep: t.shiftKey ? i : r
45
+ });
46
+ } else if (this.#c(t.event)) {
47
+ t.event.preventDefault();
48
+ let e = t.key === "-" ? "out" : "in", n = this.#t.getZoomTarget(e);
49
+ n && this.#s(t.event, n, "keyboard");
50
+ }
51
+ };
52
+ #a(e, t) {
53
+ this.#t.consumeAutoFit(), this.#t.cancelAnimation();
54
+ let n = this.#t.getTransform(), r = t.viewportPixelStep / n.scale, i = {
55
+ scale: n.scale,
56
+ x: n.x + t.direction.horizontal * r,
57
+ y: n.y + t.direction.vertical * r
58
+ }, a = {
59
+ event: e,
60
+ next: i,
61
+ source: t.source,
62
+ start: n
63
+ };
64
+ this.#t.events.dispatchPan(a) && this.#t.commitTransform(i) && this.#t.rebasePointerSessions();
65
+ }
66
+ #o = (e) => {
67
+ if (!this.#c(e) || !e.ctrlKey && !e.metaKey) return;
68
+ let t = e.key === "0" ? "reset" : e.key === "1" ? "fit" : void 0;
69
+ if (!t) return;
70
+ let n = this.#t.getZoomTarget(t);
71
+ n && (e.preventDefault(), this.#s(e, n, "keyboard"));
72
+ };
73
+ #s(e, t, r) {
74
+ this.#t.consumeAutoFit();
75
+ let i = this.#t.getTransform(), a = {
76
+ x: this.#e.clientWidth / 2,
77
+ y: this.#e.clientHeight / 2
78
+ }, o = this.#t.viewportToClient(a.x, a.y), s = {
79
+ anchor: n(a.x, a.y, i),
80
+ clientX: o.x,
81
+ clientY: o.y,
82
+ event: e,
83
+ factor: t.scale / i.scale,
84
+ next: t,
85
+ source: r,
86
+ start: i
87
+ };
88
+ this.#t.events.dispatchZoom(s) && this.#t.animateTo(t);
89
+ }
90
+ #c(t) {
91
+ return this.#e.behaviorZoom && e(this.#e) && t.composedPath()[0] === this.#e;
92
+ }
93
+ #l(t) {
94
+ return !!this.#e.behaviorPan && e(this.#e) && t.composedPath()[0] === this.#e && !t.ctrlKey && !t.metaKey && !t.altKey;
95
+ }
96
+ #u(e) {
97
+ e ? this.#e.hasAttribute("tabindex") || (this.#e.tabIndex = 0, this.#n = !0) : (this.#n && this.#e.getAttribute("tabindex") === "0" && this.#e.removeAttribute("tabindex"), this.#n = !1);
98
+ }
99
+ };
100
+ function o(e) {
101
+ if (e === "--pan-left") return {
102
+ horizontal: -1,
103
+ vertical: 0
104
+ };
105
+ if (e === "--pan-right") return {
106
+ horizontal: 1,
107
+ vertical: 0
108
+ };
109
+ if (e === "--pan-up") return {
110
+ horizontal: 0,
111
+ vertical: -1
112
+ };
113
+ if (e === "--pan-down") return {
114
+ horizontal: 0,
115
+ vertical: 1
116
+ };
117
+ }
118
+ function s(e) {
119
+ if (e === "--zoom-in") return "in";
120
+ if (e === "--zoom-out") return "out";
121
+ if (e === "--zoom-reset") return "reset";
122
+ if (e === "--zoom-to-fit") return "fit";
123
+ }
124
+ function c(e) {
125
+ return e === "ArrowLeft" ? {
126
+ horizontal: -1,
127
+ vertical: 0
128
+ } : e === "ArrowRight" ? {
129
+ horizontal: 1,
130
+ vertical: 0
131
+ } : e === "ArrowUp" ? {
132
+ horizontal: 0,
133
+ vertical: -1
134
+ } : {
135
+ horizontal: 0,
136
+ vertical: 1
137
+ };
138
+ }
139
+ //#endregion
140
+ export { a as ViewportNavigationController };
141
+
142
+ //# sourceMappingURL=viewport-navigation.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-navigation.controller.js","names":[],"sources":["../../src/viewport/viewport-navigation.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';\nimport {\n isImmediateRootActiveElement,\n KeyNavigationSpatialController,\n type SpatialKeyCommand\n} from '@nvidia-elements/core/internal';\nimport type {\n ViewportAnimationOptions,\n ViewportDiscretePanDetail,\n ViewportPanBehavior,\n ViewportPoint,\n ViewportTransform,\n ViewportZoomDetail\n} from './viewport.types.js';\nimport type { ViewportNavigationEventDelegate, ViewportZoomAction } from './viewport-navigation.types.js';\nimport { contentPointFromViewport } from './viewport-projection.utils.js';\n\nconst KEYBOARD_PAN_STEP = 20;\nconst KEYBOARD_PAN_LARGE_STEP = 100;\n\ninterface PanDirection {\n readonly horizontal: -1 | 0 | 1;\n readonly vertical: -1 | 0 | 1;\n}\n\ninterface DiscretePanRequest {\n readonly direction: PanDirection;\n readonly source: 'command' | 'keyboard';\n readonly viewportPixelStep: number;\n}\n\ntype ViewportNavigationHost = HTMLElement &\n ReactiveControllerHost & {\n readonly behaviorPan: ViewportPanBehavior;\n readonly behaviorZoom: boolean;\n };\n\nexport interface ViewportNavigationDelegate {\n readonly animateTo: (target: Partial<ViewportTransform>, options?: ViewportAnimationOptions) => void;\n readonly commitTransform: (next: ViewportTransform) => boolean;\n readonly cancelAnimation: () => void;\n readonly consumeAutoFit: () => void;\n readonly events: ViewportNavigationEventDelegate;\n readonly getTransform: () => ViewportTransform;\n readonly getZoomTarget: (action: ViewportZoomAction) => ViewportTransform | undefined;\n readonly rebasePointerSessions: () => void;\n readonly viewportToClient: (viewportX: number, viewportY: number) => ViewportPoint;\n}\n\n/** Coordinates the viewport's opt-in keyboard and Invoker navigation behavior. */\nexport class ViewportNavigationController implements ReactiveController {\n readonly #host: ViewportNavigationHost;\n readonly #delegate: ViewportNavigationDelegate;\n #managesTabIndex = false;\n\n constructor(host: ViewportNavigationHost, delegate: ViewportNavigationDelegate) {\n this.#host = host;\n this.#delegate = delegate;\n host.addController(this);\n new KeyNavigationSpatialController(host, { isEnabled: () => Boolean(host.behaviorPan) || host.behaviorZoom });\n }\n\n hostConnected(): void {\n this.#host.addEventListener('nve-key', this.#handleSpatialKey as EventListener);\n this.#host.addEventListener('command', this.#handleCommand as EventListener);\n this.#host.addEventListener('keydown', this.#handleViewportKeyDown as EventListener);\n this.#syncFocusability(Boolean(this.#host.behaviorPan) || this.#host.behaviorZoom);\n }\n\n hostDisconnected(): void {\n this.#host.removeEventListener('nve-key', this.#handleSpatialKey as EventListener);\n this.#host.removeEventListener('command', this.#handleCommand as EventListener);\n this.#host.removeEventListener('keydown', this.#handleViewportKeyDown as EventListener);\n }\n\n hostUpdated(): void {\n this.#syncFocusability(Boolean(this.#host.behaviorPan) || this.#host.behaviorZoom);\n }\n\n #handleCommand = (event: CommandEvent): void => {\n const panDirection = this.#host.behaviorPan ? commandPanDirection(event.command) : undefined;\n if (panDirection) {\n this.#requestDiscretePan(event, {\n direction: panDirection,\n source: 'command',\n viewportPixelStep: KEYBOARD_PAN_STEP\n });\n return;\n }\n if (!this.#host.behaviorZoom) return;\n const action = commandZoomAction(event.command);\n if (!action) return;\n const next = this.#delegate.getZoomTarget(action);\n if (next) this.#requestZoom(event, next, 'command');\n };\n\n #handleSpatialKey = (event: CustomEvent<SpatialKeyCommand>): void => {\n const command = event.detail;\n if (command.kind === 'direction') {\n if (!this.#acceptsKeyboardPan(command.event)) return;\n command.event.preventDefault();\n this.#requestDiscretePan(command.event, {\n direction: keyboardPanDirection(command.key),\n source: 'keyboard',\n viewportPixelStep: command.shiftKey ? KEYBOARD_PAN_LARGE_STEP : KEYBOARD_PAN_STEP\n });\n } else if (this.#acceptsKeyboardZoom(command.event)) {\n command.event.preventDefault();\n const action = command.key === '-' ? 'out' : 'in';\n const next = this.#delegate.getZoomTarget(action);\n if (next) this.#requestZoom(command.event, next, 'keyboard');\n }\n };\n\n #requestDiscretePan(event: CommandEvent | KeyboardEvent, request: DiscretePanRequest): void {\n this.#delegate.consumeAutoFit();\n this.#delegate.cancelAnimation();\n const start = this.#delegate.getTransform();\n const contentStep = request.viewportPixelStep / start.scale;\n const next = {\n scale: start.scale,\n x: start.x + request.direction.horizontal * contentStep,\n y: start.y + request.direction.vertical * contentStep\n };\n const detail: ViewportDiscretePanDetail = { event, next, source: request.source, start };\n if (this.#delegate.events.dispatchPan(detail) && this.#delegate.commitTransform(next)) {\n this.#delegate.rebasePointerSessions();\n }\n }\n\n #handleViewportKeyDown = (event: KeyboardEvent): void => {\n if (!this.#acceptsKeyboardZoom(event) || (!event.ctrlKey && !event.metaKey)) return;\n const action = event.key === '0' ? 'reset' : event.key === '1' ? 'fit' : undefined;\n if (!action) return;\n const next = this.#delegate.getZoomTarget(action);\n if (!next) return;\n event.preventDefault();\n this.#requestZoom(event, next, 'keyboard');\n };\n\n #requestZoom(event: CommandEvent | KeyboardEvent, next: ViewportTransform, source: 'command' | 'keyboard'): void {\n this.#delegate.consumeAutoFit();\n const start = this.#delegate.getTransform();\n const viewport = { x: this.#host.clientWidth / 2, y: this.#host.clientHeight / 2 };\n const client = this.#delegate.viewportToClient(viewport.x, viewport.y);\n const detail: ViewportZoomDetail = {\n anchor: contentPointFromViewport(viewport.x, viewport.y, start),\n clientX: client.x,\n clientY: client.y,\n event,\n factor: next.scale / start.scale,\n next,\n source,\n start\n };\n if (this.#delegate.events.dispatchZoom(detail)) this.#delegate.animateTo(next);\n }\n\n #acceptsKeyboardZoom(event: KeyboardEvent): boolean {\n return (\n this.#host.behaviorZoom && isImmediateRootActiveElement(this.#host) && event.composedPath()[0] === this.#host\n );\n }\n\n #acceptsKeyboardPan(event: KeyboardEvent): boolean {\n return (\n Boolean(this.#host.behaviorPan) &&\n isImmediateRootActiveElement(this.#host) &&\n event.composedPath()[0] === this.#host &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey\n );\n }\n\n #syncFocusability(behaviorEnabled: boolean): void {\n if (!behaviorEnabled) {\n if (this.#managesTabIndex && this.#host.getAttribute('tabindex') === '0') this.#host.removeAttribute('tabindex');\n this.#managesTabIndex = false;\n } else if (!this.#host.hasAttribute('tabindex')) {\n this.#host.tabIndex = 0;\n this.#managesTabIndex = true;\n }\n }\n}\n\nfunction commandPanDirection(command: string): PanDirection | undefined {\n if (command === '--pan-left') return { horizontal: -1, vertical: 0 };\n if (command === '--pan-right') return { horizontal: 1, vertical: 0 };\n if (command === '--pan-up') return { horizontal: 0, vertical: -1 };\n if (command === '--pan-down') return { horizontal: 0, vertical: 1 };\n return undefined;\n}\n\nfunction commandZoomAction(command: string): ViewportZoomAction | undefined {\n if (command === '--zoom-in') return 'in';\n if (command === '--zoom-out') return 'out';\n if (command === '--zoom-reset') return 'reset';\n if (command === '--zoom-to-fit') return 'fit';\n return undefined;\n}\n\nfunction keyboardPanDirection(key: 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'ArrowUp'): PanDirection {\n if (key === 'ArrowLeft') return { horizontal: -1, vertical: 0 };\n if (key === 'ArrowRight') return { horizontal: 1, vertical: 0 };\n if (key === 'ArrowUp') return { horizontal: 0, vertical: -1 };\n return { horizontal: 0, vertical: 1 };\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ViewportPanDetail, ViewportPanEndDetail, ViewportPointerPanDetail, ViewportZoomDetail } from './viewport.types.js';
2
+ export type ViewportZoomAction = 'fit' | 'in' | 'out' | 'reset';
3
+ /** Dispatches public viewport navigation events on behalf of navigation controllers. */
4
+ export interface ViewportNavigationEventDelegate {
5
+ readonly dispatchPanStart: (detail: ViewportPointerPanDetail) => boolean;
6
+ readonly dispatchPan: (detail: ViewportPanDetail) => boolean;
7
+ readonly dispatchPanEnd: (detail: ViewportPanEndDetail) => void;
8
+ readonly dispatchZoom: (detail: ViewportZoomDetail) => boolean;
9
+ }
@@ -0,0 +1,7 @@
1
+ import type { ViewportPoint, ViewportTransform } from './viewport.types.js';
2
+ export declare function anchoredTransform(anchor: ViewportPoint, viewport: ViewportPoint, scale: number): ViewportTransform;
3
+ export declare function contentPointFromViewport(viewportX: number, viewportY: number, transform: ViewportTransform): ViewportPoint;
4
+ export declare function centeredScaleTransform(scale: number, transform: ViewportTransform, viewportSize: {
5
+ width: number;
6
+ height: number;
7
+ }): ViewportTransform;
@@ -0,0 +1,25 @@
1
+ //#region src/viewport/viewport-projection.utils.ts
2
+ function e(e, t, n) {
3
+ return {
4
+ scale: n,
5
+ x: e.x - t.x / n,
6
+ y: e.y - t.y / n
7
+ };
8
+ }
9
+ function t(e, t, n) {
10
+ return {
11
+ x: e / n.scale + n.x,
12
+ y: t / n.scale + n.y
13
+ };
14
+ }
15
+ function n(n, r, i) {
16
+ let a = {
17
+ x: i.width / 2,
18
+ y: i.height / 2
19
+ };
20
+ return e(t(a.x, a.y, r), a, n);
21
+ }
22
+ //#endregion
23
+ export { e as anchoredTransform, n as centeredScaleTransform, t as contentPointFromViewport };
24
+
25
+ //# sourceMappingURL=viewport-projection.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-projection.utils.js","names":[],"sources":["../../src/viewport/viewport-projection.utils.ts"],"sourcesContent":["// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ViewportPoint, ViewportTransform } from './viewport.types.js';\n\nexport function anchoredTransform(anchor: ViewportPoint, viewport: ViewportPoint, scale: number): ViewportTransform {\n return {\n scale,\n x: anchor.x - viewport.x / scale,\n y: anchor.y - viewport.y / scale\n };\n}\n\nexport function contentPointFromViewport(\n viewportX: number,\n viewportY: number,\n transform: ViewportTransform\n): ViewportPoint {\n return {\n x: viewportX / transform.scale + transform.x,\n y: viewportY / transform.scale + transform.y\n };\n}\n\nexport function centeredScaleTransform(\n scale: number,\n transform: ViewportTransform,\n viewportSize: { width: number; height: number }\n): ViewportTransform {\n const viewport = { x: viewportSize.width / 2, y: viewportSize.height / 2 };\n return anchoredTransform(contentPointFromViewport(viewport.x, viewport.y, transform), viewport, scale);\n}\n"],"mappings":";AAKA,SAAgB,EAAkB,GAAuB,GAAyB,GAAkC;CAClH,OAAO;EACL;EACA,GAAG,EAAO,IAAI,EAAS,IAAI;EAC3B,GAAG,EAAO,IAAI,EAAS,IAAI;CAC7B;AACF;AAEA,SAAgB,EACd,GACA,GACA,GACe;CACf,OAAO;EACL,GAAG,IAAY,EAAU,QAAQ,EAAU;EAC3C,GAAG,IAAY,EAAU,QAAQ,EAAU;CAC7C;AACF;AAEA,SAAgB,EACd,GACA,GACA,GACmB;CACnB,IAAM,IAAW;EAAE,GAAG,EAAa,QAAQ;EAAG,GAAG,EAAa,SAAS;CAAE;CACzE,OAAO,EAAkB,EAAyB,EAAS,GAAG,EAAS,GAAG,CAAS,GAAG,GAAU,CAAK;AACvG"}
@@ -0,0 +1,92 @@
1
+ import { LitElement, type PropertyValues } from 'lit';
2
+ import type { ViewportAnimationOptions, ViewportPanBehavior, ViewportPoint, ViewportRect, ViewportRevealOptions, ViewportTransform } from './viewport.types.js';
3
+ /**
4
+ * @element nve-viewport
5
+ * @description A viewport provides a spatial surface for arbitrary content, with optional pan and zoom navigation.
6
+ * @documentation https://nvidia.github.io/elements/docs/elements/viewport/
7
+ * @since 0.0.0
8
+ * @entrypoint \@nvidia-elements/core/viewport
9
+ * @slot - Content positioned in the viewport's infinite content space.
10
+ * @slot background - Custom content rendered behind viewport content and excluded from content fitting
11
+ * @event panstart - Dispatched when pointer movement crosses the pan threshold. Cancel to disable built-in pointer panning for the sequence.
12
+ * @event pan - Dispatched when pointer, wheel, keyboard, or command input requests a pan. Cancel to skip the proposed transform mutation.
13
+ * @event panend - Dispatched when a pointer pan ends, including its terminal reason.
14
+ * @event zoom - Dispatched when wheel, pinch, or command input requests a scale change. Cancel to skip the proposed transform mutation.
15
+ * @event viewportchange - Dispatched once after a render that commits one or more viewport transform changes.
16
+ * @cssprop --background - Background color of the fixed viewport area.
17
+ * @cssprop --min-height
18
+ * @cssprop --pan-cursor - Cursor shown over a background eligible for primary-pointer panning.
19
+ * @cssprop --panning-cursor - Cursor shown while a pointer pan is active.
20
+ * @command --pan-left - With behavior-pan enabled, pans left by one discrete step.
21
+ * @command --pan-right - With behavior-pan enabled, pans right by one discrete step.
22
+ * @command --pan-up - With behavior-pan enabled, pans up by one discrete step.
23
+ * @command --pan-down - With behavior-pan enabled, pans down by one discrete step.
24
+ * @command --zoom-in - With behavior-zoom enabled, animates to the next permitted scale step.
25
+ * @command --zoom-out - With behavior-zoom enabled, animates to the previous permitted scale step.
26
+ * @command --zoom-reset - With behavior-zoom enabled, animates to 100% scale.
27
+ * @command --zoom-to-fit - With behavior-zoom enabled, animates to fit direct default-slot element boxes.
28
+ * @stable false
29
+ */
30
+ export declare class Viewport extends LitElement {
31
+ #private;
32
+ static styles: import("lit").CSSResult[];
33
+ static readonly metadata: {
34
+ tag: string;
35
+ version: string;
36
+ };
37
+ /** @private */
38
+ _internals: ElementInternals;
39
+ private internalHost;
40
+ constructor();
41
+ /** Horizontal content-space coordinate at the viewport origin. */
42
+ get x(): number;
43
+ set x(value: number);
44
+ /** Vertical content-space coordinate at the viewport origin. */
45
+ get y(): number;
46
+ set y(value: number);
47
+ /** Content-to-viewport CSS-pixel scale. */
48
+ get scale(): number;
49
+ set scale(value: number);
50
+ /** Inclusive lower scale limit. */
51
+ get minScale(): number;
52
+ set minScale(value: number);
53
+ /** Inclusive upper scale limit. */
54
+ get maxScale(): number;
55
+ set maxScale(value: number);
56
+ /** Enables panning by pointer, focused wheel, focused keyboard, and Invoker commands; requires Space for primary-pointer dragging when set to space. */
57
+ get behaviorPan(): ViewportPanBehavior;
58
+ set behaviorPan(value: ViewportPanBehavior | null | undefined);
59
+ /** Enables zooming by pinch, focused modified wheel, focused keyboard, and Invoker commands. */
60
+ behaviorZoom: boolean;
61
+ /** Fits measurable direct default-slot content once after initial layout. */
62
+ autoFit: boolean;
63
+ /** Default uniform CSS-pixel inset reserved around bounds when fitting content. */
64
+ get fitInset(): number;
65
+ set fitInset(value: number);
66
+ /** CSS-pixel pointer movement required before a pointer pan begins. */
67
+ get dragThreshold(): number;
68
+ set dragThreshold(value: number);
69
+ connectedCallback(): void;
70
+ disconnectedCallback(): void;
71
+ protected updated(changed: PropertyValues<this>): void;
72
+ render(): import("lit-html").TemplateResult<1>;
73
+ /** Converts a content-space point to viewport CSS pixels. */
74
+ toViewportCoords(contentX: number, contentY: number): ViewportPoint;
75
+ /** Converts a viewport CSS-pixel point to content space. */
76
+ toContentCoords(viewportX: number, viewportY: number): ViewportPoint;
77
+ /** Returns the current content-space origin and CSS-pixel scale. */
78
+ getTransform(): ViewportTransform;
79
+ /** Returns the visible content-space rectangle. */
80
+ getVisibleRect(): ViewportRect;
81
+ /** Animates the viewport to the requested partial transform. */
82
+ animateTo(target: Partial<ViewportTransform>, options?: ViewportAnimationOptions): void;
83
+ /** Centers or fits a content-space region within the viewport. */
84
+ reveal(region: {
85
+ x: number;
86
+ y: number;
87
+ width?: number;
88
+ height?: number;
89
+ }, options?: ViewportRevealOptions): void;
90
+ /** Fits the union of direct default-slot element boxes within the viewport. */
91
+ fitContents(options?: ViewportRevealOptions): void;
92
+ }
@@ -0,0 +1,6 @@
1
+ //#region src/viewport/viewport.examples.ts
2
+ var e = "";
3
+ //#endregion
4
+ export { e as default };
5
+
6
+ //# sourceMappingURL=viewport.examples.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport.examples.js","names":[],"sources":["../../src/viewport/viewport.examples.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 '@nvidia-elements/core/alert/define.js';\nimport '@nvidia-elements/core/button/define.js';\nimport '@nvidia-elements/core/button-group/define.js';\nimport '@nvidia-elements/core/card/define.js';\nimport '@nvidia-elements/core/input/define.js';\nimport '@nvidia-elements/core/toolbar/define.js';\nimport '@nvidia-elements/core/viewport/define.js';\n\nexport default {\n title: 'Elements/Viewport',\n component: 'nve-viewport'\n};\n\n/**\n * @summary Enable direct pan and zoom with auto-fit and adaptive gridlines to navigate positioned content.\n */\nexport const Default = {\n render: () => html`\n <nve-viewport autofit fit-inset=\"24\" behavior-pan behavior-zoom style=\"height: 420px\">\n <nve-viewport-gridlines></nve-viewport-gridlines>\n\n <svg\n role=\"img\"\n aria-label=\"Three geometric forms in a spatial field\"\n width=\"710\"\n height=\"410\"\n viewBox=\"0 0 710 410\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"100\" cy=\"300\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"250\" y=\"0\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 600 190 L 710 300 L 600 410 L 490 300 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n </svg>\n </nve-viewport>\n `\n};\n\n/**\n * @summary Place custom content in the background slot to provide a spatial reference without affecting content fitting.\n */\nexport const Background = {\n render: () => html`\n <nve-viewport autofit fit-inset=\"24\" behavior-pan behavior-zoom style=\"height: 420px\">\n <svg\n slot=\"background\"\n aria-hidden=\"true\"\n width=\"20480\"\n height=\"20480\"\n viewBox=\"-10240 -10240 20480 20480\"\n style=\"position: absolute; left: -10240px; top: -10240px\"\n >\n <defs>\n <pattern id=\"viewport-background-dots\" width=\"100\" height=\"100\" patternUnits=\"userSpaceOnUse\">\n <circle cx=\"2\" cy=\"2\" r=\"2\" fill=\"var(--nve-ref-border-color-emphasis)\"></circle>\n </pattern>\n </defs>\n <rect x=\"-10240\" y=\"-10240\" width=\"20480\" height=\"20480\" fill=\"url(#viewport-background-dots)\"></rect>\n </svg>\n\n <svg\n role=\"img\"\n aria-label=\"Three geometric forms in a spatial field\"\n width=\"710\"\n height=\"410\"\n viewBox=\"0 0 710 410\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"100\" cy=\"300\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"250\" y=\"0\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 600 190 L 710 300 L 600 410 L 490 300 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n </svg>\n </nve-viewport>\n `\n};\n\n/**\n * @summary Place native and Elements controls inside a viewport without losing their standard interactions.\n */\nexport const InteractiveContent = {\n render: () => html`\n <nve-viewport x=\"-20\" y=\"-20\" scale=\"0.9\" behavior-pan behavior-zoom style=\"height: 420px\">\n <nve-viewport-gridlines step=\"20\" target-spacing=\"72\"></nve-viewport-gridlines>\n\n <nve-card style=\"position: absolute; left: 280px; top: 110px; width: 300px\">\n <nve-card-header>\n <h2 nve-text=\"heading sm bold\">Viewport content</h2>\n </nve-card-header>\n <nve-card-content>\n <nve-input>\n <label>Label</label>\n <input value=\"Editable value\" />\n </nve-input>\n </nve-card-content>\n </nve-card>\n </nve-viewport>\n `\n};\n\n/**\n * @summary Configure panning to require Space when application content needs to handle its own drag interactions.\n */\nexport const PanWithSpace = {\n render: () => html`\n <style>\n #viewport-space-pan-card {\n cursor: var(--drag-cursor, auto);\n }\n\n #viewport-space-pan-card:hover {\n --drag-cursor: grab;\n }\n\n #viewport-space-pan-card[data-dragging] {\n --background: var(--nve-sys-layer-overlay-background);\n --box-shadow: var(--nve-ref-shadow-300);\n --drag-cursor: grabbing;\n }\n </style>\n\n <div nve-layout=\"column align:horizontal-stretch\" style=\"height: 420px\">\n <nve-alert-group status=\"accent\">\n <nve-alert>\n <p nve-text=\"body sm medium\">\n Pan the viewport with <kbd nve-text=\"code\">Space</kbd>, or using the middle mouse button.\n </p>\n </nve-alert>\n </nve-alert-group>\n\n <nve-viewport\n id=\"viewport-space-pan-demo\"\n behavior-pan=\"space\"\n behavior-zoom\n style=\"flex: 1; --min-height: 0\"\n >\n <nve-viewport-gridlines step=\"20\"></nve-viewport-gridlines>\n\n <nve-card\n id=\"viewport-space-pan-card\"\n data-draggable-card\n data-card-drag-handle\n style=\"position: absolute; left: 290px; top: 120px; width: 300px\"\n >\n <nve-card-header>\n <h2 nve-text=\"heading sm bold\">Drag this card</h2>\n </nve-card-header>\n <nve-card-content>\n <p nve-text=\"body relaxed\" nve-layout=\"pad:md\" style=\"text-align: center\">Application-defined dragging remains independent in this mode.</p>\n </nve-card-content>\n </nve-card>\n </nve-viewport>\n </div>\n\n <script type=\"module\">\n const viewport = document.querySelector('#viewport-space-pan-demo');\n const handles = viewport.querySelectorAll('[data-card-drag-handle]');\n\n handles.forEach(handle => {\n const card = handle.closest('[data-draggable-card]');\n let pointerId;\n let startClientX;\n let startClientY;\n let startLeft;\n let startTop;\n\n const finishDrag = event => {\n if (event.pointerId !== pointerId) return;\n pointerId = undefined;\n card.removeAttribute('data-dragging');\n };\n\n handle.addEventListener('pointerdown', event => {\n if (\n (event.pointerType !== 'mouse' && event.pointerType !== 'pen') ||\n event.button !== 0 ||\n event.defaultPrevented\n ) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n pointerId = event.pointerId;\n startClientX = event.clientX;\n startClientY = event.clientY;\n startLeft = Number.parseFloat(card.style.left);\n startTop = Number.parseFloat(card.style.top);\n card.setAttribute('data-dragging', '');\n handle.setPointerCapture(pointerId);\n });\n\n handle.addEventListener('pointermove', event => {\n if (event.pointerId !== pointerId) return;\n\n card.style.left = startLeft + (event.clientX - startClientX) / viewport.scale + 'px';\n card.style.top = startTop + (event.clientY - startClientY) / viewport.scale + 'px';\n event.preventDefault();\n });\n\n handle.addEventListener('pointerup', finishDrag);\n handle.addEventListener('pointercancel', finishDrag);\n handle.addEventListener('lostpointercapture', finishDrag);\n });\n </script>\n `\n};\n\n/**\n * @summary Use external controls with `commandfor` to invoke viewport pan, zoom, reset, and fit commands.\n */\nexport const Commands = {\n render: () => html`\n <div nve-layout=\"column align:horizontal-stretch\" style=\"height: 420px\">\n <nve-toolbar aria-label=\"Viewport navigation controls\">\n <nve-button commandfor=\"viewport-command-demo\" command=\"--pan-left\" aria-label=\"Pan left\">←</nve-button>\n <nve-button commandfor=\"viewport-command-demo\" command=\"--pan-up\" aria-label=\"Pan up\">↑</nve-button>\n <nve-button commandfor=\"viewport-command-demo\" command=\"--pan-down\" aria-label=\"Pan down\">↓</nve-button>\n <nve-button commandfor=\"viewport-command-demo\" command=\"--pan-right\" aria-label=\"Pan right\">→</nve-button>\n <nve-button slot=\"suffix\" commandfor=\"viewport-command-demo\" command=\"--zoom-out\" aria-label=\"Zoom out\">−</nve-button>\n <nve-button slot=\"suffix\" commandfor=\"viewport-command-demo\" command=\"--zoom-reset\">100%</nve-button>\n <nve-button slot=\"suffix\" commandfor=\"viewport-command-demo\" command=\"--zoom-in\" aria-label=\"Zoom in\">+</nve-button>\n <nve-button slot=\"suffix\" commandfor=\"viewport-command-demo\" command=\"--zoom-to-fit\">Fit</nve-button>\n </nve-toolbar>\n\n <nve-viewport\n id=\"viewport-command-demo\"\n autofit\n fit-inset=\"24\"\n behavior-pan\n behavior-zoom\n style=\"flex: 1; --min-height: 0\"\n >\n <nve-viewport-gridlines></nve-viewport-gridlines>\n\n <svg\n role=\"img\"\n aria-label=\"Three geometric forms in a spatial field\"\n width=\"710\"\n height=\"410\"\n viewBox=\"0 0 710 410\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"100\" cy=\"300\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"250\" y=\"0\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 600 190 L 710 300 L 600 410 L 490 300 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n </svg>\n </nve-viewport>\n </div>\n `\n};\n\n/**\n * @summary Viewport navigation helpers let application logic animate specific content regions into view.\n */\nexport const Reveal = {\n render: () => html`\n <div nve-layout=\"column gap:sm align:horizontal-stretch\" style=\"height: 420px\">\n <div nve-layout=\"row align:center\">\n <nve-button-group container=\"rounded\" behavior-select=\"single\" aria-label=\"Navigate to workflow region\">\n <nve-button data-viewport-region=\"viewport-region-ingest\">Ingest</nve-button>\n <nve-button data-viewport-region=\"viewport-region-train\">Train</nve-button>\n <nve-button data-viewport-region=\"viewport-region-deploy\">Deploy</nve-button>\n </nve-button-group>\n </div>\n\n <nve-viewport id=\"viewport-reveal-demo\" autofit fit-inset=\"24\" style=\"flex: 1; --min-height: 0\">\n <nve-viewport-gridlines step=\"40\"></nve-viewport-gridlines>\n\n <svg\n aria-hidden=\"true\"\n width=\"500\"\n height=\"320\"\n viewBox=\"0 0 500 320\"\n style=\"position: absolute; left: 380px; top: 144px\"\n >\n <path\n d=\"M 0 0 C 50 0 50 160 100 160 M 400 160 C 450 160 450 320 500 320\"\n fill=\"none\"\n stroke=\"var(--nve-ref-border-color-emphasis)\"\n stroke-width=\"4\"\n ></path>\n </svg>\n\n <nve-card id=\"viewport-region-ingest\" style=\"position: absolute; left: 80px; top: 80px; width: 320px\">\n <nve-card-header><h2 nve-text=\"heading sm bold\">Ingest</h2></nve-card-header>\n <nve-card-content>\n <p nve-text=\"body\" nve-layout=\"pad:md\" style=\"text-align: center\">Validate and prepare the dataset.</p>\n </nve-card-content>\n </nve-card>\n <nve-card id=\"viewport-region-train\" style=\"position: absolute; left: 480px; top: 240px; width: 320px\">\n <nve-card-header><h2 nve-text=\"heading sm bold\">Train</h2></nve-card-header>\n <nve-card-content>\n <p nve-text=\"body\" nve-layout=\"pad:md\" style=\"text-align: center\">Run and compare model experiments.</p>\n </nve-card-content>\n </nve-card>\n <nve-card id=\"viewport-region-deploy\" style=\"position: absolute; left: 880px; top: 400px; width: 320px\">\n <nve-card-header><h2 nve-text=\"heading sm bold\">Deploy</h2></nve-card-header>\n <nve-card-content>\n <p nve-text=\"body\" nve-layout=\"pad:md\" style=\"text-align: center\">Promote the selected model.</p>\n </nve-card-content>\n </nve-card>\n </nve-viewport>\n </div>\n\n <script type=\"module\">\n const viewport = document.querySelector('#viewport-reveal-demo');\n const buttons = Array.from(document.querySelectorAll('[data-viewport-region]'));\n const framing = 80;\n\n buttons.forEach(button => {\n button.addEventListener('click', () => {\n const region = viewport.querySelector('#' + button.dataset.viewportRegion);\n viewport.reveal(\n {\n x: region.offsetLeft - framing,\n y: region.offsetTop - framing,\n width: region.offsetWidth + framing * 2,\n height: region.offsetHeight + framing * 2\n },\n { animated: true, duration: 500 }\n );\n });\n });\n </script>\n `\n};\n"],"mappings":";AAGA,IAAA,IAAS"}