@preference-sl/pref-viewer 2.11.0-beta.8 → 2.11.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/package.json +61 -50
- package/src/babylonjs-animation-controller.js +58 -76
- package/src/babylonjs-animation-opening-menu.js +189 -154
- package/src/babylonjs-animation-opening.js +67 -36
- package/src/babylonjs-controller.js +233 -113
- package/src/file-storage.js +11 -2
- package/src/index.js +18 -866
- package/src/panzoom-controller.js +92 -55
- package/src/pref-viewer-2d.js +15 -3
- package/src/pref-viewer-3d-data.js +3 -2
- package/src/pref-viewer-3d.js +11 -4
- package/src/pref-viewer-dialog.js +71 -46
- package/src/pref-viewer-task.js +1 -1
- package/src/pref-viewer.js +934 -0
- package/src/styles.js +334 -0
- package/src/svg-resolver.js +23 -0
|
@@ -1,59 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Explicitly target the ESM bundle so esbuild (platform=node) picks up the default export.
|
|
2
|
+
import Panzoom from "@panzoom/panzoom/dist/panzoom.es.js";
|
|
3
3
|
/**
|
|
4
|
-
* PanzoomController - Encapsulates
|
|
4
|
+
* PanzoomController - Encapsulates logic for managing pan and zoom interactions on a DOM element using the Panzoom library.
|
|
5
|
+
*
|
|
6
|
+
* Summary:
|
|
7
|
+
* Provides a high-level API to enable, disable, and control pan/zoom interactions for SVG or other DOM content.
|
|
8
|
+
* Manages event listeners for mouse, keyboard, and touch interactions, and tracks the current pan/zoom state.
|
|
9
|
+
* Supports zooming in/out, panning, resetting, and mouse wheel zoom, with customizable options and callbacks.
|
|
5
10
|
*
|
|
6
|
-
* Responsibilities:
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* - Tracks the current pan/zoom state
|
|
10
|
-
* - Supports
|
|
11
|
+
* Key Responsibilities:
|
|
12
|
+
* - Initializes and manages a Panzoom instance for a wrapper element.
|
|
13
|
+
* - Handles enabling/disabling pan/zoom and related event listeners.
|
|
14
|
+
* - Tracks and exposes the current pan/zoom state.
|
|
15
|
+
* - Supports keyboard shortcuts, mouse wheel zoom, and context menu prevention.
|
|
16
|
+
* - Provides methods for panning, zooming, and resetting the view.
|
|
17
|
+
* - Invokes a callback when the pan/zoom state changes.
|
|
11
18
|
*
|
|
12
19
|
* Usage:
|
|
13
|
-
* - Instantiate
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
16
|
-
* -
|
|
20
|
+
* - Instantiate: const controller = new PanzoomController(wrapperElement, options, stateChangeCallback);
|
|
21
|
+
* - Enable pan/zoom: controller.enable();
|
|
22
|
+
* - Enable events: controller.enableEvents();
|
|
23
|
+
* - Control view: controller.pan(x, y), controller.zoomIn(), controller.zoomOut(), controller.reset();
|
|
24
|
+
* - Disable pan/zoom and events: controller.disable(), controller.disableEvents();
|
|
17
25
|
*
|
|
18
26
|
* Constructor Parameters:
|
|
19
|
-
* -
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
27
|
+
* - wrapper (HTMLElement): The DOM element to apply pan/zoom interactions to.
|
|
28
|
+
* - options (object): Configuration options for Panzoom (e.g., minScale, maxScale, step).
|
|
29
|
+
* - changedCallback (function): Optional callback invoked when the pan/zoom state changes.
|
|
22
30
|
*
|
|
23
31
|
* Public Methods:
|
|
24
|
-
* -
|
|
25
|
-
* -
|
|
26
|
-
* -
|
|
27
|
-
* -
|
|
28
|
-
* -
|
|
29
|
-
* -
|
|
30
|
-
* -
|
|
31
|
-
* -
|
|
32
|
+
* - enable(): Enables the Panzoom instance and initializes it if not already enabled.
|
|
33
|
+
* - disable(): Disables the Panzoom instance and removes all event listeners.
|
|
34
|
+
* - enableEvents(): Attaches all required event listeners for interactions.
|
|
35
|
+
* - disableEvents(): Removes all previously attached event listeners.
|
|
36
|
+
* - pan(x, y): Pans the view to the specified coordinates.
|
|
37
|
+
* - reset(): Resets pan and zoom to fit the entire content within the available space.
|
|
38
|
+
* - zoomIn(focal?): Zooms in by one step, optionally centered on a focal point.
|
|
39
|
+
* - zoomOut(focal?): Zooms out by one step, optionally centered on a focal point.
|
|
32
40
|
*
|
|
33
41
|
* Getters:
|
|
34
|
-
* -
|
|
35
|
-
* -
|
|
42
|
+
* - panzoom: Returns the current Panzoom instance or null if not initialized.
|
|
43
|
+
* - state: Returns the current pan/zoom state (moved, scaled, maximized, minimized).
|
|
36
44
|
*
|
|
37
45
|
* Private Methods:
|
|
38
|
-
* -
|
|
39
|
-
* -
|
|
40
|
-
* -
|
|
41
|
-
* -
|
|
42
|
-
* -
|
|
43
|
-
* -
|
|
44
|
-
* -
|
|
45
|
-
* -
|
|
46
|
-
* -
|
|
47
|
-
* -
|
|
48
|
-
* -
|
|
46
|
+
* - #bindHandlers(): Pre-binds reusable event handlers to preserve stable references.
|
|
47
|
+
* - #checkPanzoomState(transform): Updates the internal state and invokes the state change callback.
|
|
48
|
+
* - #resetTransform(): Resets the transform applied to the wrapper element.
|
|
49
|
+
* - #setFocus(): Sets focus on the parent element to enable keyboard interactions.
|
|
50
|
+
* - #onPanzoomStart(e): Handles the start of a pan/zoom interaction.
|
|
51
|
+
* - #onPanzoomChange(e): Handles changes in pan/zoom state.
|
|
52
|
+
* - #onPanzoomEnd(e): Handles the end of a pan/zoom interaction.
|
|
53
|
+
* - #onZoomWithWheel(e): Handles zoom interactions via the mouse wheel.
|
|
54
|
+
* - #enableMouseWheelZoom(): Enables zooming with the mouse wheel.
|
|
55
|
+
* - #disableMouseWheelZoom(): Disables zooming with the mouse wheel.
|
|
56
|
+
* - #getDistanceBetweenPoints(point1, point2): Calculates the Euclidean distance between two points.
|
|
57
|
+
* - #getPointFromEvent(e): Extracts client coordinates from a mouse or touch event.
|
|
49
58
|
*
|
|
50
59
|
* Notes:
|
|
51
60
|
* - Designed to work with the Panzoom library for managing pan/zoom interactions.
|
|
52
|
-
* -
|
|
61
|
+
* - Encapsulates all pan/zoom logic in a single class for clean separation of concerns.
|
|
53
62
|
* - Can be extended or customized by overriding methods or providing additional options.
|
|
54
63
|
*/
|
|
55
64
|
export default class PanzoomController {
|
|
56
|
-
#changedCallback = null;
|
|
57
65
|
#interactionOptions = {
|
|
58
66
|
clickThreshold: 6, // Threshold to avoid false clicks on elements when panning or zooming
|
|
59
67
|
};
|
|
@@ -79,11 +87,40 @@ export default class PanzoomController {
|
|
|
79
87
|
minimized: false,
|
|
80
88
|
};
|
|
81
89
|
#wrapper = null;
|
|
82
|
-
|
|
90
|
+
|
|
91
|
+
#changedCallback = null;
|
|
92
|
+
#handlers = {
|
|
93
|
+
panzoomStart: null,
|
|
94
|
+
panzoomChange: null,
|
|
95
|
+
panzoomEnd: null,
|
|
96
|
+
keyUp: null,
|
|
97
|
+
focus: null,
|
|
98
|
+
blur: null,
|
|
99
|
+
contextMenu: null,
|
|
100
|
+
wheel: null,
|
|
101
|
+
};
|
|
102
|
+
|
|
83
103
|
constructor(wrapper = null, options = {}, changedCallback = null) {
|
|
84
104
|
this.#wrapper = wrapper;
|
|
85
105
|
Object.assign(this.#options, options);
|
|
86
106
|
this.#changedCallback = changedCallback;
|
|
107
|
+
this.#bindHandlers();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Pre-binds reusable event handlers to preserve stable references.
|
|
112
|
+
* @private
|
|
113
|
+
* @returns {void}
|
|
114
|
+
*/
|
|
115
|
+
#bindHandlers() {
|
|
116
|
+
this.#handlers.panzoomStart = this.#onPanzoomStart.bind(this);
|
|
117
|
+
this.#handlers.panzoomChange = this.#onPanzoomChange.bind(this);
|
|
118
|
+
this.#handlers.panzoomEnd = this.#onPanzoomEnd.bind(this);
|
|
119
|
+
this.#handlers.keyUp = this.#onKeyUp.bind(this);
|
|
120
|
+
this.#handlers.focus = this.#enableMouseWheelZoom.bind(this);
|
|
121
|
+
this.#handlers.blur = this.#disableMouseWheelZoom.bind(this);
|
|
122
|
+
this.#handlers.contextMenu = this.#onContextMenu.bind(this);
|
|
123
|
+
this.#handlers.wheel = this.#onZoomWithWheel.bind(this);
|
|
87
124
|
}
|
|
88
125
|
|
|
89
126
|
/**
|
|
@@ -294,7 +331,7 @@ export default class PanzoomController {
|
|
|
294
331
|
if (!this.#panzoom) {
|
|
295
332
|
return;
|
|
296
333
|
}
|
|
297
|
-
this.#wrapper.parentElement.removeEventListener("wheel", this.#
|
|
334
|
+
this.#wrapper.parentElement.removeEventListener("wheel", this.#handlers.wheel);
|
|
298
335
|
}
|
|
299
336
|
|
|
300
337
|
/**
|
|
@@ -309,7 +346,7 @@ export default class PanzoomController {
|
|
|
309
346
|
return;
|
|
310
347
|
}
|
|
311
348
|
this.#disableMouseWheelZoom();
|
|
312
|
-
this.#wrapper.parentElement.addEventListener("wheel", this.#
|
|
349
|
+
this.#wrapper.parentElement.addEventListener("wheel", this.#handlers.wheel);
|
|
313
350
|
}
|
|
314
351
|
|
|
315
352
|
/**
|
|
@@ -363,13 +400,13 @@ export default class PanzoomController {
|
|
|
363
400
|
|
|
364
401
|
this.disableEvents();
|
|
365
402
|
|
|
366
|
-
this.#wrapper.addEventListener("panzoomstart", this.#
|
|
367
|
-
this.#wrapper.addEventListener("panzoomchange", this.#
|
|
368
|
-
this.#wrapper.addEventListener("panzoomend", this.#
|
|
369
|
-
this.#wrapper.parentElement.addEventListener("keyup", this.#
|
|
370
|
-
this.#wrapper.parentElement.addEventListener("focus", this.#
|
|
371
|
-
this.#wrapper.parentElement.addEventListener("blur", this.#
|
|
372
|
-
this.#wrapper.parentElement.addEventListener("contextmenu", this.#
|
|
403
|
+
this.#wrapper.addEventListener("panzoomstart", this.#handlers.panzoomStart);
|
|
404
|
+
this.#wrapper.addEventListener("panzoomchange", this.#handlers.panzoomChange);
|
|
405
|
+
this.#wrapper.addEventListener("panzoomend", this.#handlers.panzoomEnd);
|
|
406
|
+
this.#wrapper.parentElement.addEventListener("keyup", this.#handlers.keyUp);
|
|
407
|
+
this.#wrapper.parentElement.addEventListener("focus", this.#handlers.focus, true);
|
|
408
|
+
this.#wrapper.parentElement.addEventListener("blur", this.#handlers.blur, true);
|
|
409
|
+
this.#wrapper.parentElement.addEventListener("contextmenu", this.#handlers.contextMenu);
|
|
373
410
|
this.#wrapper.parentElement.setAttribute("tabindex", 0);
|
|
374
411
|
this.#setFocus();
|
|
375
412
|
}
|
|
@@ -385,13 +422,13 @@ export default class PanzoomController {
|
|
|
385
422
|
return;
|
|
386
423
|
}
|
|
387
424
|
this.#wrapper.parentElement.removeAttribute("tabindex");
|
|
388
|
-
this.#wrapper.removeEventListener("panzoomstart", this.#
|
|
389
|
-
this.#wrapper.removeEventListener("panzoomchange", this.#
|
|
390
|
-
this.#wrapper.removeEventListener("panzoomend", this.#
|
|
391
|
-
this.#wrapper.parentElement.removeEventListener("keyup", this.#
|
|
392
|
-
this.#wrapper.parentElement.removeEventListener("focus", this.#
|
|
393
|
-
this.#wrapper.parentElement.removeEventListener("blur", this.#
|
|
394
|
-
this.#wrapper.parentElement.removeEventListener("contextmenu", this.#
|
|
425
|
+
this.#wrapper.removeEventListener("panzoomstart", this.#handlers.panzoomStart);
|
|
426
|
+
this.#wrapper.removeEventListener("panzoomchange", this.#handlers.panzoomChange);
|
|
427
|
+
this.#wrapper.removeEventListener("panzoomend", this.#handlers.panzoomEnd);
|
|
428
|
+
this.#wrapper.parentElement.removeEventListener("keyup", this.#handlers.keyUp);
|
|
429
|
+
this.#wrapper.parentElement.removeEventListener("focus", this.#handlers.focus);
|
|
430
|
+
this.#wrapper.parentElement.removeEventListener("blur", this.#handlers.blur);
|
|
431
|
+
this.#wrapper.parentElement.removeEventListener("contextmenu", this.#handlers.contextMenu);
|
|
395
432
|
}
|
|
396
433
|
|
|
397
434
|
/**
|
package/src/pref-viewer-2d.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import SVGResolver from "./svg-resolver.js";
|
|
2
2
|
import PanzoomController from "./panzoom-controller.js";
|
|
3
|
+
import { PrefViewer2DStyles } from "./styles.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* PrefViewer2D - Custom element for rendering and interacting with 2D SVG content.
|
|
@@ -46,7 +47,7 @@ import PanzoomController from "./panzoom-controller.js";
|
|
|
46
47
|
* Notes on extensibility
|
|
47
48
|
* - Modeled for easy addition of other input sources or interaction modes (e.g., selection callbacks).
|
|
48
49
|
*/
|
|
49
|
-
export class PrefViewer2D extends HTMLElement {
|
|
50
|
+
export default class PrefViewer2D extends HTMLElement {
|
|
50
51
|
// State flags
|
|
51
52
|
#isInitialized = false;
|
|
52
53
|
#isLoaded = false;
|
|
@@ -68,6 +69,10 @@ export class PrefViewer2D extends HTMLElement {
|
|
|
68
69
|
#wrapper = null; // Panzoom element
|
|
69
70
|
#panzoomController = null; // PanzoomController instance
|
|
70
71
|
|
|
72
|
+
#handlers = {
|
|
73
|
+
onPanzoomChanged: null,
|
|
74
|
+
};
|
|
75
|
+
|
|
71
76
|
/**
|
|
72
77
|
* Create a new instance of the 2D viewer component.
|
|
73
78
|
* The constructor only calls super(); heavy initialization happens in connectedCallback.
|
|
@@ -114,6 +119,7 @@ export class PrefViewer2D extends HTMLElement {
|
|
|
114
119
|
/**
|
|
115
120
|
* Called when the element is inserted into the DOM.
|
|
116
121
|
* Sets up DOM nodes, initial visibility and starts loading the SVG if provided.
|
|
122
|
+
* @public
|
|
117
123
|
* @returns {void}
|
|
118
124
|
*/
|
|
119
125
|
connectedCallback() {
|
|
@@ -127,6 +133,7 @@ export class PrefViewer2D extends HTMLElement {
|
|
|
127
133
|
/**
|
|
128
134
|
* Called when the element is removed from the DOM.
|
|
129
135
|
* Disables the PanzoomController to clean up event listeners and resources.
|
|
136
|
+
* @public
|
|
130
137
|
* @returns {void}
|
|
131
138
|
*/
|
|
132
139
|
disconnectedCallback() {
|
|
@@ -143,8 +150,9 @@ export class PrefViewer2D extends HTMLElement {
|
|
|
143
150
|
#createDOMElements() {
|
|
144
151
|
this.#wrapper = document.createElement("div");
|
|
145
152
|
this.append(this.#wrapper);
|
|
153
|
+
|
|
146
154
|
const style = document.createElement("style");
|
|
147
|
-
style.textContent =
|
|
155
|
+
style.textContent = PrefViewer2DStyles;
|
|
148
156
|
this.append(style);
|
|
149
157
|
}
|
|
150
158
|
|
|
@@ -166,7 +174,8 @@ export class PrefViewer2D extends HTMLElement {
|
|
|
166
174
|
* @returns {void}
|
|
167
175
|
*/
|
|
168
176
|
#initializePanzoom() {
|
|
169
|
-
this.#
|
|
177
|
+
this.#handlers.onPanzoomChanged = this.#onPanzoomChanged.bind(this);
|
|
178
|
+
this.#panzoomController = new PanzoomController(this.#wrapper, undefined, this.#handlers.onPanzoomChanged);
|
|
170
179
|
}
|
|
171
180
|
|
|
172
181
|
/**
|
|
@@ -349,6 +358,9 @@ export class PrefViewer2D extends HTMLElement {
|
|
|
349
358
|
* - Resolves to { success: true, error: null } when the SVG was accepted and the component has started rendering.
|
|
350
359
|
*/
|
|
351
360
|
async load(svgConfig) {
|
|
361
|
+
if (!this.#svgResolver) {
|
|
362
|
+
this.#svgResolver = new SVGResolver(this.#svg);
|
|
363
|
+
}
|
|
352
364
|
if (!svgConfig || !(await this.#svgResolver.getSVG(svgConfig))) {
|
|
353
365
|
const errorDetail = this.#onError();
|
|
354
366
|
return { success: false, ...errorDetail };
|
|
@@ -46,7 +46,7 @@ export class ContainerData {
|
|
|
46
46
|
this.update.pending = true;
|
|
47
47
|
this.update.storage = storage;
|
|
48
48
|
this.update.success = false;
|
|
49
|
-
this.update.show = show !== undefined ? show : this.update.show;
|
|
49
|
+
this.update.show = show !== undefined ? show : this.update.show !== null ? this.update.show : this.show;
|
|
50
50
|
}
|
|
51
51
|
setPendingCacheData(size = 0, timeStamp = null) {
|
|
52
52
|
this.update.size = size;
|
|
@@ -62,7 +62,7 @@ export class ContainerData {
|
|
|
62
62
|
return this.visible === true;
|
|
63
63
|
}
|
|
64
64
|
get mustBeShown() {
|
|
65
|
-
return this.show === true;
|
|
65
|
+
return this.update.show !== null ? this.update.show === true : this.show === true;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -152,6 +152,7 @@ export class CameraData {
|
|
|
152
152
|
if (success) {
|
|
153
153
|
this.update.success = true;
|
|
154
154
|
this.value = this.update.value;
|
|
155
|
+
this.locked = this.update.locked;
|
|
155
156
|
} else {
|
|
156
157
|
this.update.success = false;
|
|
157
158
|
}
|
package/src/pref-viewer-3d.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CameraData, ContainerData, MaterialData } from "./pref-viewer-3d-data.js";
|
|
2
2
|
import BabylonJSController from "./babylonjs-controller.js";
|
|
3
|
+
import { PrefViewer3DStyles } from "./styles.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* PrefViewer3D - Custom Web Component for interactive 3D visualization and configuration.
|
|
@@ -56,7 +57,7 @@ import BabylonJSController from "./babylonjs-controller.js";
|
|
|
56
57
|
* - Designed for extensibility and integration in product configurators and visualization tools.
|
|
57
58
|
* - All resource management and rendering operations are performed asynchronously for performance.
|
|
58
59
|
*/
|
|
59
|
-
export class PrefViewer3D extends HTMLElement {
|
|
60
|
+
export default class PrefViewer3D extends HTMLElement {
|
|
60
61
|
// State flags
|
|
61
62
|
#isInitialized = false;
|
|
62
63
|
#isLoaded = false;
|
|
@@ -129,6 +130,7 @@ export class PrefViewer3D extends HTMLElement {
|
|
|
129
130
|
* Called when the element is added to the DOM.
|
|
130
131
|
* Creates the DOM structure, sets initial visibility, initializes component data, and sets up the BabylonJSController.
|
|
131
132
|
* Performs heavy initialization tasks required for the 3D viewer.
|
|
133
|
+
* @public
|
|
132
134
|
* @returns {void}
|
|
133
135
|
*/
|
|
134
136
|
connectedCallback() {
|
|
@@ -136,11 +138,13 @@ export class PrefViewer3D extends HTMLElement {
|
|
|
136
138
|
this.#setInitialVisibility();
|
|
137
139
|
this.#initializeData();
|
|
138
140
|
this.#initializeBabylonJS();
|
|
141
|
+
this.#isInitialized = true;
|
|
139
142
|
}
|
|
140
143
|
|
|
141
144
|
/**
|
|
142
145
|
* Called when the element is removed from the DOM.
|
|
143
146
|
* Disables the BabylonJSController to clean up resources and event listeners associated with the 3D viewer.
|
|
147
|
+
* @public
|
|
144
148
|
* @returns {void}
|
|
145
149
|
*/
|
|
146
150
|
disconnectedCallback() {
|
|
@@ -157,10 +161,12 @@ export class PrefViewer3D extends HTMLElement {
|
|
|
157
161
|
#createDOMElements() {
|
|
158
162
|
this.#wrapper = document.createElement("div");
|
|
159
163
|
this.append(this.#wrapper);
|
|
164
|
+
|
|
160
165
|
this.#canvas = document.createElement("canvas");
|
|
161
166
|
this.#wrapper.appendChild(this.#canvas);
|
|
167
|
+
|
|
162
168
|
const style = document.createElement("style");
|
|
163
|
-
style.textContent =
|
|
169
|
+
style.textContent = PrefViewer3DStyles;
|
|
164
170
|
this.append(style);
|
|
165
171
|
}
|
|
166
172
|
|
|
@@ -418,7 +424,7 @@ export class PrefViewer3D extends HTMLElement {
|
|
|
418
424
|
tried: toSetDetail,
|
|
419
425
|
success: settedDetail,
|
|
420
426
|
};
|
|
421
|
-
|
|
427
|
+
|
|
422
428
|
const customEventOptions = {
|
|
423
429
|
bubbles: true,
|
|
424
430
|
cancelable: true,
|
|
@@ -460,6 +466,7 @@ export class PrefViewer3D extends HTMLElement {
|
|
|
460
466
|
show() {
|
|
461
467
|
this.#isVisible = true;
|
|
462
468
|
this.setAttribute("visible", "true");
|
|
469
|
+
this.#canvas.focus();
|
|
463
470
|
}
|
|
464
471
|
|
|
465
472
|
/**
|
|
@@ -697,4 +704,4 @@ export class PrefViewer3D extends HTMLElement {
|
|
|
697
704
|
get isVisible() {
|
|
698
705
|
return this.#isVisible;
|
|
699
706
|
}
|
|
700
|
-
}
|
|
707
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { PrefViewerDialogStyles } from "./styles.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* PrefViewerDialog - Custom Web Component for displaying modal dialogs in PrefViewer.
|
|
3
5
|
*
|
|
@@ -9,19 +11,26 @@
|
|
|
9
11
|
*
|
|
10
12
|
* Usage:
|
|
11
13
|
* - Use as a custom HTML element: <pref-viewer-dialog></pref-viewer-dialog>
|
|
12
|
-
* - Call open(content) to display the dialog with
|
|
14
|
+
* - Call open(title, content, footer) to display the dialog with a header, content, and footer.
|
|
13
15
|
* - Call close() to hide and remove the dialog.
|
|
14
16
|
*
|
|
15
17
|
* Methods:
|
|
16
18
|
* - constructor(): Initializes the custom element.
|
|
17
19
|
* - connectedCallback(): Called when the element is added to the DOM; sets up DOM and styles.
|
|
18
20
|
* - disconnectedCallback(): Called when the element is removed from the DOM; cleans up resources.
|
|
19
|
-
* - open(content): Displays the dialog and
|
|
21
|
+
* - open(title, content, footer): Displays the dialog and sets its header, content, and footer.
|
|
20
22
|
* - close(): Hides and removes the dialog, refocuses the canvas if available.
|
|
21
23
|
* - #createDOMElements(): Creates the dialog structure and applies styles.
|
|
22
24
|
*/
|
|
23
|
-
export class PrefViewerDialog extends HTMLElement {
|
|
25
|
+
export default class PrefViewerDialog extends HTMLElement {
|
|
24
26
|
#wrapper = null;
|
|
27
|
+
#header = null;
|
|
28
|
+
#content = null;
|
|
29
|
+
#footer = null;
|
|
30
|
+
|
|
31
|
+
#handles = {
|
|
32
|
+
onBackdropClick: null,
|
|
33
|
+
};
|
|
25
34
|
|
|
26
35
|
/**
|
|
27
36
|
* Initializes the custom dialog element.
|
|
@@ -30,13 +39,14 @@ export class PrefViewerDialog extends HTMLElement {
|
|
|
30
39
|
constructor() {
|
|
31
40
|
super();
|
|
32
41
|
}
|
|
33
|
-
|
|
42
|
+
|
|
34
43
|
/**
|
|
35
44
|
* Called when the element is inserted into the DOM.
|
|
36
45
|
* Sets up the dialog's DOM structure and styles.
|
|
37
46
|
* @returns {void}
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
*/
|
|
48
|
+
connectedCallback() {
|
|
49
|
+
this.#handles.onBackdropClick = this.#onBackdropClick.bind(this);
|
|
40
50
|
this.#createDOMElements();
|
|
41
51
|
}
|
|
42
52
|
|
|
@@ -45,7 +55,9 @@ export class PrefViewerDialog extends HTMLElement {
|
|
|
45
55
|
* Cleans up resources and event listeners.
|
|
46
56
|
* @returns {void}
|
|
47
57
|
*/
|
|
48
|
-
disconnectedCallback() {
|
|
58
|
+
disconnectedCallback() {
|
|
59
|
+
this.removeEventListener("click", this.#handles.onBackdropClick);
|
|
60
|
+
}
|
|
49
61
|
|
|
50
62
|
/**
|
|
51
63
|
* Creates the dialog's DOM structure and applies CSS styles.
|
|
@@ -55,51 +67,57 @@ export class PrefViewerDialog extends HTMLElement {
|
|
|
55
67
|
*/
|
|
56
68
|
#createDOMElements() {
|
|
57
69
|
this.#wrapper = document.createElement("div");
|
|
70
|
+
this.#wrapper.classList.add("dialog-wrapper");
|
|
71
|
+
this.#wrapper.innerHTML = `
|
|
72
|
+
<div class="dialog-header"><h3 class="dialog-header-title"></h3></div>
|
|
73
|
+
<div class="dialog-content"></div>
|
|
74
|
+
<div class="dialog-footer"></div>`;
|
|
58
75
|
this.append(this.#wrapper);
|
|
76
|
+
|
|
59
77
|
const style = document.createElement("style");
|
|
60
|
-
style.textContent =
|
|
61
|
-
pref-viewer-dialog {
|
|
62
|
-
display: none;
|
|
63
|
-
}
|
|
64
|
-
pref-viewer-dialog[open] {
|
|
65
|
-
font-family: ui-sans-serif, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
|
66
|
-
width: 100%;
|
|
67
|
-
height: 100%;
|
|
68
|
-
display: flex;
|
|
69
|
-
align-items: center;
|
|
70
|
-
justify-content: center;
|
|
71
|
-
background-color: rgba(0, 0, 0, 0.25);
|
|
72
|
-
position: fixed;
|
|
73
|
-
top: 0;
|
|
74
|
-
left: 0;
|
|
75
|
-
z-index: 1000;
|
|
76
|
-
}
|
|
77
|
-
pref-viewer-dialog > div:first-child {
|
|
78
|
-
display: inline-block;
|
|
79
|
-
background: #fff;
|
|
80
|
-
border-radius: 10px;
|
|
81
|
-
box-shadow: 0 4px 24px rgba(0,0,0,0.25);
|
|
82
|
-
padding: 15px;
|
|
83
|
-
max-width: 90%;
|
|
84
|
-
max-height: 90%;
|
|
85
|
-
overflow: auto;
|
|
86
|
-
}`;
|
|
78
|
+
style.textContent = PrefViewerDialogStyles;
|
|
87
79
|
this.append(style);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
|
|
81
|
+
this.addEventListener("click", this.#handles.onBackdropClick);
|
|
82
|
+
|
|
83
|
+
this.#header = this.#wrapper.querySelector(".dialog-header");
|
|
84
|
+
this.#content = this.#wrapper.querySelector(".dialog-content");
|
|
85
|
+
this.#footer = this.#wrapper.querySelector(".dialog-footer");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#onBackdropClick(event) {
|
|
89
|
+
if (event.target === this) {
|
|
90
|
+
this.close();
|
|
91
|
+
}
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
/**
|
|
96
|
-
* Opens the dialog and
|
|
97
|
-
* @param {
|
|
98
|
-
* @
|
|
95
|
+
* Opens the dialog and sets its header, content, and footer.
|
|
96
|
+
* @param {string} title - The dialog title to display in the header.
|
|
97
|
+
* @param {string} content - The HTML content to display in the dialog body.
|
|
98
|
+
* @param {string} footer - The HTML content to display in the dialog footer (e.g., action buttons).
|
|
99
|
+
* @returns {boolean} True if the dialog was opened, false if no content was provided.
|
|
99
100
|
*/
|
|
100
|
-
open(content) {
|
|
101
|
+
open(title = "", content = "", footer = "") {
|
|
102
|
+
if (this.#wrapper === null || this.#header === null || this.#content === null || this.#footer === null) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if (title === "" && content === "" && footer === "") {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (title === "") {
|
|
110
|
+
this.#header.style.display = "none";
|
|
111
|
+
}
|
|
112
|
+
if (footer === "") {
|
|
113
|
+
this.#footer.style.display = "none";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.#header.querySelector(".dialog-header-title").innerHTML = title;
|
|
117
|
+
this.#content.innerHTML = content;
|
|
118
|
+
this.#footer.innerHTML = footer;
|
|
101
119
|
this.setAttribute("open", "");
|
|
102
|
-
|
|
120
|
+
return true;
|
|
103
121
|
}
|
|
104
122
|
|
|
105
123
|
/**
|
|
@@ -107,15 +125,22 @@ export class PrefViewerDialog extends HTMLElement {
|
|
|
107
125
|
* @returns {void}
|
|
108
126
|
*/
|
|
109
127
|
close() {
|
|
128
|
+
this.removeEventListener("click", this.#handles.onBackdropClick);
|
|
110
129
|
this.removeAttribute("open");
|
|
111
130
|
const parent = this.getRootNode().host;
|
|
112
131
|
if (parent) {
|
|
113
|
-
// Refocus canvas for accessibility
|
|
114
|
-
const canvas = parent.shadowRoot.querySelector("canvas");
|
|
132
|
+
// Refocus 3D canvas or 2D component for accessibility
|
|
133
|
+
const canvas = parent.shadowRoot.querySelector("pref-viewer-3d[visible='true'] canvas");
|
|
115
134
|
if (canvas) {
|
|
116
135
|
canvas.focus();
|
|
136
|
+
} else {
|
|
137
|
+
const component2D = parent.shadowRoot.querySelector("pref-viewer-2d[visible='true']");
|
|
138
|
+
if (component2D) {
|
|
139
|
+
component2D.focus();
|
|
140
|
+
}
|
|
117
141
|
}
|
|
118
142
|
}
|
|
143
|
+
this.#wrapper = this.#header = this.#content = this.#footer = null;
|
|
119
144
|
this.remove();
|
|
120
145
|
}
|
|
121
146
|
}
|
package/src/pref-viewer-task.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* - Validates the type (case-insensitive) and throws a TypeError if invalid.
|
|
19
19
|
* - Freezes the instance to prevent further modification.
|
|
20
20
|
*/
|
|
21
|
-
export class PrefViewerTask {
|
|
21
|
+
export default class PrefViewerTask {
|
|
22
22
|
static Types = Object.freeze({
|
|
23
23
|
Config: "config",
|
|
24
24
|
Drawing: "drawing",
|