@nvidia-elements/core 2.11.1 → 2.12.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 +13 -0
- package/dist/accordion/accordion2.js +4 -4
- package/dist/alert/alert-group2.js +1 -1
- package/dist/alert/alert2.js +1 -1
- package/dist/avatar/avatar-group2.js +1 -1
- package/dist/avatar/avatar2.js +1 -1
- package/dist/badge/badge2.js +1 -1
- package/dist/breadcrumb/breadcrumb2.js +1 -1
- package/dist/bundles/index.d.ts +8 -2
- package/dist/bundles/index.js +6 -6
- package/dist/button/button2.js +1 -1
- package/dist/button-group/button-group2.js +1 -1
- package/dist/card/card2.js +4 -4
- package/dist/chat-message/chat-message2.js +1 -1
- package/dist/checkbox/checkbox-group2.js +1 -1
- package/dist/checkbox/checkbox2.js +1 -1
- package/dist/color/color2.js +1 -1
- package/dist/combobox/combobox2.js +1 -1
- package/dist/copy-button/copy-button2.js +1 -1
- package/dist/custom-elements-jsx.d.ts +8 -2
- package/dist/custom-elements-vue.d.ts +8 -2
- package/dist/custom-elements.json +64 -3
- package/dist/data.html.json +11 -1
- package/dist/data.snippets.json +18 -18
- package/dist/date/date2.js +1 -1
- package/dist/datetime/datetime2.js +1 -1
- package/dist/dialog/dialog-footer2.js +1 -1
- package/dist/dialog/dialog-header2.js +1 -1
- package/dist/dialog/dialog2.js +1 -1
- package/dist/divider/divider2.js +1 -1
- package/dist/dot/dot2.js +1 -1
- package/dist/drawer/drawer-content2.js +1 -1
- package/dist/drawer/drawer-footer2.js +1 -1
- package/dist/drawer/drawer-header2.js +1 -1
- package/dist/drawer/drawer2.js +1 -1
- package/dist/dropdown/dropdown-footer2.js +1 -1
- package/dist/dropdown/dropdown-header2.js +1 -1
- package/dist/dropdown/dropdown2.js +1 -1
- package/dist/dropdown-group/dropdown-group.js +1 -1
- package/dist/dropzone/dropzone2.js +1 -1
- package/dist/file/file2.js +1 -1
- package/dist/format-bytes/format-bytes2.js +1 -1
- package/dist/format-datetime/format-datetime2.js +1 -1
- package/dist/format-number/format-number2.js +1 -1
- package/dist/format-relative-time/format-relative-time2.js +1 -1
- package/dist/format-truncate/format-truncate2.js +1 -1
- package/dist/forms/control/control2.js +1 -1
- package/dist/forms/control-group/control-group2.js +1 -1
- package/dist/forms/control-message/control-message2.js +1 -1
- package/dist/gauge/gauge2.js +1 -1
- package/dist/grid/cell/cell2.js +1 -1
- package/dist/grid/column/column2.js +1 -1
- package/dist/grid/footer/footer2.js +1 -1
- package/dist/grid/grid2.js +1 -1
- package/dist/grid/header/header2.js +1 -1
- package/dist/grid/placeholder/placeholder2.js +1 -1
- package/dist/grid/row/row2.js +1 -1
- package/dist/icon/icon2.js +2 -2
- package/dist/icon-button/icon-button2.js +1 -1
- package/dist/index.js +1 -1
- package/dist/input/input-group2.js +1 -1
- package/dist/input/input2.js +1 -1
- package/dist/internal/services/global.service.js +1 -1
- package/dist/logo/logo2.js +1 -1
- package/dist/menu/menu-group2.js +1 -1
- package/dist/menu/menu-item2.js +1 -1
- package/dist/menu/menu2.js +1 -1
- package/dist/month/month2.js +1 -1
- package/dist/notification/notification-group2.js +1 -1
- package/dist/notification/notification2.js +1 -1
- package/dist/page/page-panel/page-panel-content2.js +1 -1
- package/dist/page/page-panel/page-panel-footer2.js +1 -1
- package/dist/page/page-panel/page-panel-header2.js +1 -1
- package/dist/page/page-panel/page-panel.d.ts +2 -0
- package/dist/page/page-panel/page-panel.js +1 -1
- package/dist/page/page-panel/page-panel.js.map +1 -1
- package/dist/page/page-panel/page-panel2.js +8 -2
- package/dist/page/page-panel/page-panel2.js.map +1 -1
- package/dist/page/page.examples.js.map +1 -1
- package/dist/page/page.examples.json +11 -0
- package/dist/page/page.js +1 -1
- package/dist/page/page.js.map +1 -1
- package/dist/page/page2.js +1 -1
- package/dist/page-header/page-header2.js +1 -1
- package/dist/page-loader/page-loader2.js +1 -1
- package/dist/pagination/pagination2.js +1 -1
- package/dist/panel/panel2.js +4 -4
- package/dist/password/password2.js +1 -1
- package/dist/preferences-input/preferences-input2.js +1 -1
- package/dist/progress-bar/progress-bar2.js +1 -1
- package/dist/progress-ring/progress-ring2.js +1 -1
- package/dist/progressive-filter-chip/progressive-filter-chip2.js +1 -1
- package/dist/pulse/pulse2.js +1 -1
- package/dist/radio/radio-group2.js +1 -1
- package/dist/radio/radio2.js +1 -1
- package/dist/range/range2.js +1 -1
- package/dist/resize-handle/resize-handle2.js +1 -1
- package/dist/search/search2.js +1 -1
- package/dist/select/select2.js +1 -1
- package/dist/skeleton/skeleton2.js +1 -1
- package/dist/sort-button/sort-button2.js +1 -1
- package/dist/sparkline/sparkline2.js +1 -1
- package/dist/star-rating/star-rating2.js +1 -1
- package/dist/steps/steps2.js +2 -2
- package/dist/switch/switch-group2.js +1 -1
- package/dist/switch/switch2.js +1 -1
- package/dist/tabs/tabs-group2.js +1 -1
- package/dist/tabs/tabs2.js +2 -2
- package/dist/tag/tag2.js +1 -1
- package/dist/textarea/textarea2.js +1 -1
- package/dist/time/time2.js +1 -1
- package/dist/toast/toast2.js +1 -1
- package/dist/toggletip/toggletip-footer2.js +1 -1
- package/dist/toggletip/toggletip-header2.js +1 -1
- package/dist/toggletip/toggletip2.js +1 -1
- package/dist/toolbar/toolbar2.js +1 -1
- package/dist/tooltip/tooltip2.js +1 -1
- package/dist/tree/tree-node2.js +1 -1
- package/dist/tree/tree2.js +1 -1
- package/dist/viewport/viewport-gridlines.d.ts +6 -2
- package/dist/viewport/viewport-gridlines.js +1 -1
- package/dist/viewport/viewport-gridlines.js.map +1 -1
- package/dist/viewport/viewport-gridlines2.js +39 -29
- package/dist/viewport/viewport-gridlines2.js.map +1 -1
- package/dist/viewport/viewport-minimap2.js +1 -1
- package/dist/viewport/viewport.examples.js.map +1 -1
- package/dist/viewport/viewport.examples.json +28 -10
- package/dist/viewport/viewport2.js +1 -1
- package/dist/week/week2.js +1 -1
- package/package.json +1 -1
package/dist/select/select2.js
CHANGED
package/dist/steps/steps2.js
CHANGED
|
@@ -23,7 +23,7 @@ var v = class extends h(d) {
|
|
|
23
23
|
static {
|
|
24
24
|
this.metadata = {
|
|
25
25
|
tag: "nve-steps-item",
|
|
26
|
-
version: "2.
|
|
26
|
+
version: "2.12.0",
|
|
27
27
|
parents: ["nve-steps"]
|
|
28
28
|
};
|
|
29
29
|
}
|
|
@@ -69,7 +69,7 @@ var y = class extends d {
|
|
|
69
69
|
static {
|
|
70
70
|
this.metadata = {
|
|
71
71
|
tag: "nve-steps",
|
|
72
|
-
version: "2.
|
|
72
|
+
version: "2.12.0",
|
|
73
73
|
children: ["nve-steps-item"]
|
|
74
74
|
};
|
|
75
75
|
}
|
package/dist/switch/switch2.js
CHANGED
package/dist/tabs/tabs-group2.js
CHANGED
package/dist/tabs/tabs2.js
CHANGED
|
@@ -20,7 +20,7 @@ var _ = class extends h(f) {
|
|
|
20
20
|
static {
|
|
21
21
|
this.metadata = {
|
|
22
22
|
tag: "nve-tabs-item",
|
|
23
|
-
version: "2.
|
|
23
|
+
version: "2.12.0",
|
|
24
24
|
parents: ["nve-tabs"]
|
|
25
25
|
};
|
|
26
26
|
}
|
|
@@ -53,7 +53,7 @@ var v = class extends f {
|
|
|
53
53
|
static {
|
|
54
54
|
this.metadata = {
|
|
55
55
|
tag: "nve-tabs",
|
|
56
|
-
version: "2.
|
|
56
|
+
version: "2.12.0",
|
|
57
57
|
children: ["nve-tabs-item"]
|
|
58
58
|
};
|
|
59
59
|
}
|
package/dist/tag/tag2.js
CHANGED
package/dist/time/time2.js
CHANGED
package/dist/toast/toast2.js
CHANGED
package/dist/toolbar/toolbar2.js
CHANGED
package/dist/tooltip/tooltip2.js
CHANGED
package/dist/tree/tree-node2.js
CHANGED
package/dist/tree/tree2.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { LitElement, nothing, type PropertyValues } from 'lit';
|
|
2
2
|
/**
|
|
3
3
|
* @element nve-viewport-gridlines
|
|
4
|
-
* @description Renders origin-stable, zoom-adaptive
|
|
4
|
+
* @description Renders origin-stable, zoom-adaptive gridline patterns behind viewport content.
|
|
5
5
|
* @documentation https://nvidia.github.io/elements/docs/elements/viewport/
|
|
6
6
|
* @since 0.0.0
|
|
7
7
|
* @entrypoint \@nvidia-elements/core/viewport
|
|
8
|
-
* @cssprop --color - Sets the gridline
|
|
8
|
+
* @cssprop --color - Sets the gridline pattern color.
|
|
9
9
|
* @cssprop --line-width - Sets the approximate stroke width in CSS pixels.
|
|
10
|
+
* @cssprop --dot-radius - Sets the approximate dot radius in CSS pixels.
|
|
11
|
+
* @cssprop --cross-size - Sets the approximate full width and height of each cross in CSS pixels.
|
|
10
12
|
*/
|
|
11
13
|
export declare class ViewportGridlines extends LitElement {
|
|
12
14
|
#private;
|
|
@@ -19,6 +21,8 @@ export declare class ViewportGridlines extends LitElement {
|
|
|
19
21
|
slot: string;
|
|
20
22
|
/** @private */
|
|
21
23
|
protected accessibilityHidden: string;
|
|
24
|
+
/** Grid pattern to render. */
|
|
25
|
+
pattern: 'lines' | 'dots' | 'crosses';
|
|
22
26
|
/** Smallest gridline interval in content-space units. */
|
|
23
27
|
get step(): number;
|
|
24
28
|
set step(value: number);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/viewport/viewport-gridlines.css?inline
|
|
2
|
-
var e = ":host{--
|
|
2
|
+
var e = ":host{--color: var(--nve-ref-border-color-muted);--line-width: var(--nve-ref-border-width-sm);--dot-radius: var(--nve-ref-size-50);--cross-size: var(--nve-ref-size-200);--_scale: 1;position:absolute;inset:0;contain:none;pointer-events:none;user-select:none}svg{position:absolute;overflow:visible;pointer-events:none}path{fill:none;stroke:var(--color);stroke-width:calc(var(--line-width) / var(--_scale))}circle{fill:var(--color);r:calc(var(--dot-radius) / var(--_scale))}.cross{fill:var(--color)}.cross-horizontal{x:calc(var(--cross-size) / var(--_scale) / -2);y:calc(var(--line-width) / var(--_scale) / -2);width:calc(var(--cross-size) / var(--_scale));height:calc(var(--line-width) / var(--_scale))}.cross-vertical{x:calc(var(--line-width) / var(--_scale) / -2);y:calc(var(--cross-size) / var(--_scale) / -2);width:calc(var(--line-width) / var(--_scale));height:calc(var(--cross-size) / var(--_scale))}";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { e as default };
|
|
5
5
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewport-gridlines.js","names":[],"sources":["../../src/viewport/viewport-gridlines.css?inline"],"sourcesContent":["/* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */\n/* SPDX-License-Identifier: Apache-2.0 */\n\n:host {\n --
|
|
1
|
+
{"version":3,"file":"viewport-gridlines.js","names":[],"sources":["../../src/viewport/viewport-gridlines.css?inline"],"sourcesContent":["/* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */\n/* SPDX-License-Identifier: Apache-2.0 */\n\n:host {\n --color: var(--nve-ref-border-color-muted);\n --line-width: var(--nve-ref-border-width-sm);\n --dot-radius: var(--nve-ref-size-50);\n --cross-size: var(--nve-ref-size-200);\n\n --_scale: 1;\n\n position: absolute;\n inset: 0;\n contain: none;\n pointer-events: none;\n user-select: none;\n}\n\nsvg {\n position: absolute;\n overflow: visible;\n pointer-events: none;\n}\n\npath {\n fill: none;\n stroke: var(--color);\n stroke-width: calc(var(--line-width) / var(--_scale));\n}\n\ncircle {\n fill: var(--color);\n r: calc(var(--dot-radius) / var(--_scale));\n}\n\n.cross {\n fill: var(--color);\n}\n\n.cross-horizontal {\n x: calc(var(--cross-size) / var(--_scale) / -2);\n y: calc(var(--line-width) / var(--_scale) / -2);\n width: calc(var(--cross-size) / var(--_scale));\n height: calc(var(--line-width) / var(--_scale));\n}\n\n.cross-vertical {\n x: calc(var(--line-width) / var(--_scale) / -2);\n y: calc(var(--cross-size) / var(--_scale) / -2);\n width: calc(var(--line-width) / var(--_scale));\n height: calc(var(--cross-size) / var(--_scale));\n}\n"],"mappings":""}
|
|
@@ -5,17 +5,17 @@ import i from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js
|
|
|
5
5
|
import { Viewport as a } from "./viewport2.js";
|
|
6
6
|
import o from "./viewport-gridlines.js";
|
|
7
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
|
|
10
|
-
import { styleMap as
|
|
8
|
+
import { LitElement as u, html as d, nothing as f, svg as p } from "lit";
|
|
9
|
+
import { property as m } from "lit/decorators/property.js";
|
|
10
|
+
import { styleMap as h } from "lit/directives/style-map.js";
|
|
11
11
|
//#region src/viewport/viewport-gridlines.ts
|
|
12
|
-
var
|
|
12
|
+
var g = 10, _ = 64, v = class extends u {
|
|
13
13
|
constructor(...e) {
|
|
14
|
-
super(...e), this.slot = "background", this.accessibilityHidden = "true", this.#e =
|
|
14
|
+
super(...e), this.slot = "background", this.accessibilityHidden = "true", this.#e = g, this.#t = 0, this.#n = 0, this.#r = _, this.pattern = "lines", this.#c = () => {
|
|
15
15
|
let e = this.#i;
|
|
16
|
-
e && (this.style.setProperty("--_scale", `${e.scale}`), this.#
|
|
17
|
-
}, this.#
|
|
18
|
-
this.#
|
|
16
|
+
e && (this.style.setProperty("--_scale", `${e.scale}`), this.#u());
|
|
17
|
+
}, this.#l = () => {
|
|
18
|
+
this.#u({ forceCoverage: !0 });
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
static {
|
|
@@ -24,7 +24,7 @@ var h = 10, g = 64, _ = class extends u {
|
|
|
24
24
|
static {
|
|
25
25
|
this.metadata = {
|
|
26
26
|
tag: "nve-viewport-gridlines",
|
|
27
|
-
version: "2.
|
|
27
|
+
version: "2.12.0"
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
#e;
|
|
@@ -38,7 +38,7 @@ var h = 10, g = 64, _ = class extends u {
|
|
|
38
38
|
return this.#e;
|
|
39
39
|
}
|
|
40
40
|
set step(e) {
|
|
41
|
-
let t = r(e,
|
|
41
|
+
let t = r(e, g);
|
|
42
42
|
if (t === this.#e) return;
|
|
43
43
|
let n = this.#e;
|
|
44
44
|
this.#e = t, this.requestUpdate("step", n);
|
|
@@ -65,7 +65,7 @@ var h = 10, g = 64, _ = class extends u {
|
|
|
65
65
|
return this.#r;
|
|
66
66
|
}
|
|
67
67
|
set targetSpacing(e) {
|
|
68
|
-
let t = r(e,
|
|
68
|
+
let t = r(e, _);
|
|
69
69
|
if (t === this.#r) return;
|
|
70
70
|
let n = this.#r;
|
|
71
71
|
this.#r = t, this.requestUpdate("targetSpacing", n);
|
|
@@ -73,16 +73,16 @@ var h = 10, g = 64, _ = class extends u {
|
|
|
73
73
|
connectedCallback() {
|
|
74
74
|
super.connectedCallback();
|
|
75
75
|
let e = this.parentElement;
|
|
76
|
-
e instanceof a && (this.#i = e, this.style.setProperty("--_scale", `${e.scale}`), this.#i.addEventListener("viewportchange", this.#
|
|
76
|
+
e instanceof a && (this.#i = e, this.style.setProperty("--_scale", `${e.scale}`), this.#i.addEventListener("viewportchange", this.#c), typeof ResizeObserver < "u" && (this.#a = new ResizeObserver(this.#l), this.#a.observe(e)), this.#d({
|
|
77
77
|
forceCoverage: !0,
|
|
78
78
|
resetInterval: !0
|
|
79
79
|
}));
|
|
80
80
|
}
|
|
81
81
|
disconnectedCallback() {
|
|
82
|
-
this.#i && this.#i.removeEventListener("viewportchange", this.#
|
|
82
|
+
this.#i && this.#i.removeEventListener("viewportchange", this.#c), this.#a?.disconnect(), this.#a = void 0, this.#i = void 0, this.#o = void 0, super.disconnectedCallback();
|
|
83
83
|
}
|
|
84
84
|
willUpdate(e) {
|
|
85
|
-
super.willUpdate(e), (e.has("step") || e.has("targetSpacing")) && this.#
|
|
85
|
+
super.willUpdate(e), (e.has("step") || e.has("targetSpacing")) && this.#d({
|
|
86
86
|
forceCoverage: !0,
|
|
87
87
|
resetInterval: !0
|
|
88
88
|
});
|
|
@@ -90,15 +90,22 @@ var h = 10, g = 64, _ = class extends u {
|
|
|
90
90
|
render() {
|
|
91
91
|
let e = this.#o;
|
|
92
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="${
|
|
93
|
+
let { coverage: t, interval: n } = e, r = this.pattern === "dots" || this.pattern === "crosses";
|
|
94
|
+
return d`<svg internal-host aria-hidden="true" focusable="false" preserveAspectRatio="none" style="${h(b(t))}" viewBox="${t.x} ${t.y} ${t.width} ${t.height}"><defs><pattern data-gridline-pattern id="gridlines" x="${this.#t - (r ? n / 2 : 0)}" y="${this.#n - (r ? n / 2 : 0)}" width="${n}" height="${n}" patternUnits="userSpaceOnUse">${this.#s(n)}</pattern></defs><rect x="${t.x}" y="${t.y}" width="${t.width}" height="${t.height}" fill="url(#gridlines)"></rect></svg>`;
|
|
95
95
|
}
|
|
96
|
-
#s
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
#s(e) {
|
|
97
|
+
switch (this.pattern) {
|
|
98
|
+
case "dots": return p`<circle cx="${e / 2}" cy="${e / 2}" r="2"></circle>`;
|
|
99
|
+
case "crosses": return p`<g transform="translate(${e / 2} ${e / 2})"><clipPath id="cross-clip"><rect class="cross-horizontal"></rect><rect class="cross-vertical"></rect></clipPath><rect class="cross" x="${-e / 2}" y="${-e / 2}" width="${e}" height="${e}" clip-path="url(#cross-clip)"></rect></g>`;
|
|
100
|
+
default: return p`<path d="M ${e} 0 H 0 V ${e}"></path>`;
|
|
101
|
+
}
|
|
100
102
|
}
|
|
103
|
+
#c;
|
|
104
|
+
#l;
|
|
101
105
|
#u(e = {}) {
|
|
106
|
+
this.#d(e) && this.requestUpdate();
|
|
107
|
+
}
|
|
108
|
+
#d(e = {}) {
|
|
102
109
|
let t = this.#i;
|
|
103
110
|
if (!t) return !1;
|
|
104
111
|
let n = t.getVisibleRect();
|
|
@@ -108,7 +115,7 @@ var h = 10, g = 64, _ = class extends u {
|
|
|
108
115
|
scale: t.scale,
|
|
109
116
|
step: this.#e,
|
|
110
117
|
targetSpacing: this.#r
|
|
111
|
-
}), i =
|
|
118
|
+
}), i = y({
|
|
112
119
|
forceCoverage: e.forceCoverage === !0,
|
|
113
120
|
interval: r,
|
|
114
121
|
previous: this.#o,
|
|
@@ -117,30 +124,33 @@ var h = 10, g = 64, _ = class extends u {
|
|
|
117
124
|
return i ? (this.#o = i, !0) : !1;
|
|
118
125
|
}
|
|
119
126
|
};
|
|
120
|
-
i([e()],
|
|
127
|
+
i([e()], v.prototype, "slot", void 0), i([e({ attribute: "aria-hidden" })], v.prototype, "accessibilityHidden", void 0), i([m({
|
|
128
|
+
type: String,
|
|
129
|
+
reflect: !0
|
|
130
|
+
})], v.prototype, "pattern", void 0), i([m({
|
|
121
131
|
type: Number,
|
|
122
132
|
reflect: !0
|
|
123
|
-
})],
|
|
133
|
+
})], v.prototype, "step", null), i([m({
|
|
124
134
|
type: Number,
|
|
125
135
|
attribute: "origin-x",
|
|
126
136
|
reflect: !0
|
|
127
|
-
})],
|
|
137
|
+
})], v.prototype, "originX", null), i([m({
|
|
128
138
|
type: Number,
|
|
129
139
|
attribute: "origin-y",
|
|
130
140
|
reflect: !0
|
|
131
|
-
})],
|
|
141
|
+
})], v.prototype, "originY", null), i([m({
|
|
132
142
|
type: Number,
|
|
133
143
|
attribute: "target-spacing",
|
|
134
144
|
reflect: !0
|
|
135
|
-
})],
|
|
136
|
-
function
|
|
145
|
+
})], v.prototype, "targetSpacing", null);
|
|
146
|
+
function y({ forceCoverage: e, interval: t, previous: n, visible: r }) {
|
|
137
147
|
let i = e || c(n?.coverage, r), a = t !== n?.interval;
|
|
138
148
|
if (!(!i && !a)) return {
|
|
139
149
|
coverage: i || !n ? s(r) : n.coverage,
|
|
140
150
|
interval: t
|
|
141
151
|
};
|
|
142
152
|
}
|
|
143
|
-
function
|
|
153
|
+
function b(e) {
|
|
144
154
|
return {
|
|
145
155
|
height: `${e.height}px`,
|
|
146
156
|
left: `${e.x}px`,
|
|
@@ -149,6 +159,6 @@ function y(e) {
|
|
|
149
159
|
};
|
|
150
160
|
}
|
|
151
161
|
//#endregion
|
|
152
|
-
export {
|
|
162
|
+
export { v as ViewportGridlines };
|
|
153
163
|
|
|
154
164
|
//# sourceMappingURL=viewport-gridlines2.js.map
|
|
@@ -1 +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;\n if (!(viewport instanceof Viewport)) 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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"}
|
|
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, svg, 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 gridline patterns 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 pattern color.\n * @cssprop --line-width - Sets the approximate stroke width in CSS pixels.\n * @cssprop --dot-radius - Sets the approximate dot radius in CSS pixels.\n * @cssprop --cross-size - Sets the approximate full width and height of each cross 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 /** Grid pattern to render. */\n @property({ type: String, reflect: true }) pattern: 'lines' | 'dots' | 'crosses' = 'lines';\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;\n if (!(viewport instanceof Viewport)) 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 const centered = this.pattern === 'dots' || this.pattern === 'crosses';\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 - (centered ? interval / 2 : 0)}\n y=${this.#originY - (centered ? interval / 2 : 0)}\n width=${interval}\n height=${interval}\n patternUnits=\"userSpaceOnUse\"\n >\n ${this.#renderPattern(interval)}\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 #renderPattern(interval: number) {\n switch (this.pattern) {\n case 'dots':\n return svg`<circle cx=${interval / 2} cy=${interval / 2} r=\"2\"></circle>`;\n case 'crosses':\n return svg`\n <g transform=\"translate(${interval / 2} ${interval / 2})\">\n <clipPath id=\"cross-clip\">\n <rect class=\"cross-horizontal\"></rect>\n <rect class=\"cross-vertical\"></rect>\n </clipPath>\n <rect\n class=\"cross\"\n x=${-interval / 2}\n y=${-interval / 2}\n width=${interval}\n height=${interval}\n clip-path=\"url(#cross-clip)\"\n ></rect>\n </g>\n `;\n case 'lines':\n default:\n return svg`<path d=\"M ${interval} 0 H 0 V ${interval}\"></path>`;\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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"}
|
|
@@ -1 +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 Auto-fit a bounded SVG with direct pan and zoom; the minimap represents its single content root as one rectangle.\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=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\n </svg>\n\n <nve-viewport-minimap></nve-viewport-minimap>\n </nve-viewport>\n `\n};\n\n/**\n * @summary Provide custom minimap content to replace the automatic bounding boxes with a simplified representation of the viewport content.\n */\nexport const Minimap = {\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=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\n </svg>\n\n <nve-viewport-minimap>\n <svg slot=\"preview\" width=\"900\" height=\"600\" viewBox=\"0 0 900 600\" style=\"position: absolute; left: 0; top: 0\">\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n </svg>\n </nve-viewport-minimap>\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=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\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=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\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 ProgrammaticNavigation = {\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"}
|
|
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 Auto-fit a bounded SVG with direct pan and zoom; the minimap represents its single content root as one rectangle.\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=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\n </svg>\n\n <nve-viewport-minimap></nve-viewport-minimap>\n </nve-viewport>\n `\n};\n\n/**\n * @summary Provide custom minimap content to replace the default bounding boxes with a simplified representation of the viewport content.\n */\nexport const Minimap = {\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=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\n </svg>\n\n <nve-viewport-minimap>\n <svg slot=\"preview\" width=\"900\" height=\"600\" viewBox=\"0 0 900 600\" style=\"position: absolute; left: 0; top: 0\">\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n </svg>\n </nve-viewport-minimap>\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=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\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 ProgrammaticNavigation = {\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\n/**\n * @summary Optionally configure viewport grid lines to use dots instead of lines.\n */\nexport const Dots = {\n render: () => html`\n <nve-viewport autofit fit-inset=\"24\" behavior-pan behavior-zoom style=\"height: 420px\">\n <nve-viewport-gridlines pattern=\"dots\"></nve-viewport-gridlines>\n\n <svg\n role=\"img\"\n aria-label=\"Three geometric forms in a spatial field\"\n width=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\n </svg>\n </nve-viewport>\n `\n};\n\n/**\n * @summary Use crosses as spatial reference points to help users judge positions while keeping the content between them unobstructed.\n */\nexport const Crosses = {\n render: () => html`\n <nve-viewport autofit fit-inset=\"24\" behavior-pan behavior-zoom style=\"height: 420px\">\n <nve-viewport-gridlines pattern=\"crosses\"></nve-viewport-gridlines>\n\n <svg\n role=\"img\"\n aria-label=\"Three geometric forms in a spatial field\"\n width=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\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-triangles\" width=\"200\" height=\"200\" patternUnits=\"userSpaceOnUse\">\n <path d=\"M 0 0 H 200 V 200 M 0 0 L 200 200 M 0 200 L 200 0\" fill=\"none\" stroke=\"var(--nve-ref-border-color-muted)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"></path>\n </pattern>\n </defs>\n <rect x=\"-10240\" y=\"-10240\" width=\"20480\" height=\"20480\" fill=\"url(#viewport-background-triangles)\"></rect>\n </svg>\n\n <svg\n role=\"img\"\n aria-label=\"Three geometric forms in a spatial field\"\n width=\"900\"\n height=\"600\"\n viewBox=\"0 0 900 600\"\n style=\"position: absolute; left: 0; top: 0\"\n >\n <circle cx=\"200\" cy=\"400\" r=\"100\" fill=\"var(--nve-ref-color-green-jade-600)\"></circle>\n <rect x=\"350\" y=\"100\" width=\"200\" height=\"200\" rx=\"50\" fill=\"var(--nve-ref-color-blue-cobalt-600)\"></rect>\n <path d=\"M 700 290 L 810 400 L 700 510 L 590 400 Z\" fill=\"var(--nve-ref-color-purple-lavender-600)\"></path>\n <rect x=\"1\" y=\"1\" width=\"898\" height=\"598\" rx=\"24\" fill=\"none\" stroke=\"var(--nve-ref-border-color-emphasis)\" stroke-width=\"2\" stroke-dasharray=\"32 20\" vector-effect=\"non-scaling-stroke\"></rect>\n </svg>\n </nve-viewport>\n `\n};\n"],"mappings":";AAGA,IAAA,IAAS"}
|