@preference-sl/pref-viewer 2.16.0-beta.10 → 2.16.0-beta.11
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/README.md +125 -102
- package/package.json +1 -1
- package/src/babylonjs-animation-opening.js +11 -5
- package/src/babylonjs-controller.js +337 -60
- package/src/pref-viewer-2d.js +14 -21
- package/src/pref-viewer-3d.js +140 -85
- package/src/pref-viewer-menu-3d.js +84 -40
- package/src/pref-viewer-task.js +7 -2
- package/src/pref-viewer.js +547 -185
- package/src/styles.js +105 -29
|
@@ -10,7 +10,7 @@ import { DEFAULT_LOCALE, resolveLocale, translate } from "./localization/i18n.js
|
|
|
10
10
|
* - A hue slider for the highlight color.
|
|
11
11
|
* - A time-of-day slider with play/pause continuous lighting-cycle animation.
|
|
12
12
|
*
|
|
13
|
-
* Every interaction emits `pref-viewer-
|
|
13
|
+
* Every interaction emits `pref-viewer-3d-render-settings-change-requested` immediately; there is no Apply button or
|
|
14
14
|
* draft/pending state. Switch changes emit the full settings snapshot, while highlight color and
|
|
15
15
|
* lighting changes emit partial payloads to avoid unnecessary scene reloads.
|
|
16
16
|
*
|
|
@@ -19,13 +19,13 @@ import { DEFAULT_LOCALE, resolveLocale, translate } from "./localization/i18n.js
|
|
|
19
19
|
* - `setApplying(isApplying)`: locks interactions while an async apply operation is running.
|
|
20
20
|
* - `setViewerHover(isHovering)`: drives panel visibility from the 3D viewport hover state.
|
|
21
21
|
* - `setEnabled(isEnabled)`: hides the menu when 3D mode is unavailable.
|
|
22
|
-
* - `
|
|
22
|
+
* - `setElementEnabled(settingKey, isEnabled)`: enables/disables a specific switch or slider at runtime.
|
|
23
|
+
* - `setElementVisible(settingKey, isVisible)`: shows/hides a specific switch or slider at runtime.
|
|
23
24
|
* - `setCulture(cultureId)`: switches the display locale.
|
|
24
25
|
*
|
|
25
|
-
* Observed attributes: `culture
|
|
26
|
-
* The illumination attributes are mirrored for compatibility with hosts that still set them declaratively.
|
|
26
|
+
* Observed attributes: `culture`. Runtime render values are synchronized through `setSettings()`.
|
|
27
27
|
*
|
|
28
|
-
* Events emitted: `pref-viewer-
|
|
28
|
+
* Events emitted: `pref-viewer-3d-render-settings-change-requested` - `{ detail: { settings: object } }`.
|
|
29
29
|
*/
|
|
30
30
|
export default class PrefViewerMenu3D extends HTMLElement {
|
|
31
31
|
#elements = {
|
|
@@ -41,6 +41,8 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
41
41
|
lightingSlider: null,
|
|
42
42
|
lightingValue: null,
|
|
43
43
|
panel: null,
|
|
44
|
+
sliders: {},
|
|
45
|
+
sliderWrappers: {},
|
|
44
46
|
subtitle: null,
|
|
45
47
|
switches: {},
|
|
46
48
|
switchCopyNodes: {},
|
|
@@ -65,7 +67,8 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
65
67
|
typeof this.#DEFAULT_RENDER_SETTINGS[key] === "boolean"
|
|
66
68
|
);
|
|
67
69
|
#settings = { ...this.#DEFAULT_RENDER_SETTINGS };
|
|
68
|
-
#
|
|
70
|
+
#elementAvailability = {};
|
|
71
|
+
#elementVisibility = {};
|
|
69
72
|
#isApplying = false;
|
|
70
73
|
#isEnabled = true;
|
|
71
74
|
#isLightingPlaying = false;
|
|
@@ -92,35 +95,22 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
92
95
|
* @returns {string[]} Array of attribute names to observe.
|
|
93
96
|
*/
|
|
94
97
|
static get observedAttributes() {
|
|
95
|
-
return ["culture"
|
|
98
|
+
return ["culture"];
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
/**
|
|
99
102
|
* Reacts to observed attribute mutations and mirrors them into the internal settings/UI state.
|
|
100
103
|
* @public
|
|
101
|
-
* @param {"culture"
|
|
104
|
+
* @param {"culture"} name - Attribute name that changed.
|
|
102
105
|
* @param {string|null} _old - Previous attribute value (unused).
|
|
103
106
|
* @param {string|null} value - New attribute value.
|
|
104
107
|
* @returns {void}
|
|
105
108
|
*/
|
|
106
109
|
attributeChangedCallback(name, _old, value) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const switchEl = this.#elements.switches?.illuminationEnabled;
|
|
112
|
-
if (switchEl) {
|
|
113
|
-
switchEl.checked = this.#settings.illuminationEnabled;
|
|
114
|
-
}
|
|
115
|
-
} else if (name === "illumination-color") {
|
|
116
|
-
this.#settings.illuminationColor = value;
|
|
117
|
-
this.#updateColorPickerPreview(value);
|
|
118
|
-
} else if (name === "lighting-time-of-day") {
|
|
119
|
-
const parsed = Number(value);
|
|
120
|
-
if (Number.isFinite(parsed)) {
|
|
121
|
-
this.#settings.lightingTimeOfDay = this.#clampLightingTime(parsed);
|
|
122
|
-
this.#updateLightingSliderUI(this.#settings.lightingTimeOfDay);
|
|
123
|
-
}
|
|
110
|
+
switch (name) {
|
|
111
|
+
case "culture":
|
|
112
|
+
this.#setCultureInternal(value || DEFAULT_LOCALE);
|
|
113
|
+
break;
|
|
124
114
|
}
|
|
125
115
|
}
|
|
126
116
|
|
|
@@ -171,19 +161,19 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
171
161
|
<div class="menu-switches">
|
|
172
162
|
${this.#MENU_SWITCHES.map((key) => this.#renderSwitchRow(key, this.#texts.features)).join("")}
|
|
173
163
|
</div>
|
|
174
|
-
<div class="menu-color-picker" data-setting="highlightColor">
|
|
164
|
+
<div class="menu-color-picker menu-slider" data-setting="highlightColor">
|
|
175
165
|
<div class="color-slider-row">
|
|
176
166
|
<span class="color-picker-label">${this.#texts.features?.highlightColor?.label || "Highlight Color"}</span>
|
|
177
167
|
<span class="color-preview" style="background-color: ${this.#settings.highlightColor || '#ff6700'}"></span>
|
|
178
168
|
</div>
|
|
179
|
-
<input type="range" class="color-slider" min="0" max="359" value="${PrefViewerMenu3D.#hexToHue(this.#settings.highlightColor || '#ff6700')}">
|
|
169
|
+
<input type="range" data-setting="highlightColor" class="color-slider" min="0" max="359" value="${PrefViewerMenu3D.#hexToHue(this.#settings.highlightColor || '#ff6700')}">
|
|
180
170
|
</div>
|
|
181
|
-
<div class="menu-lighting-slider" data-setting="lightingTimeOfDay">
|
|
171
|
+
<div class="menu-lighting-slider menu-slider" data-setting="lightingTimeOfDay">
|
|
182
172
|
<div class="lighting-slider-row">
|
|
183
|
-
<span class="lighting-slider-label">${this.#texts.features?.lightingTimeOfDay?.label || "Time of day"}</span>
|
|
173
|
+
<span class="lighting-slider-label menu-slider-label">${this.#texts.features?.lightingTimeOfDay?.label || "Time of day"}</span>
|
|
184
174
|
<span class="lighting-slider-value">${PrefViewerMenu3D.#formatLightingTime(this.#settings.lightingTimeOfDay ?? 0.5)}</span>
|
|
185
175
|
</div>
|
|
186
|
-
<input type="range" class="lighting-slider" min="0" max="1000" step="1" value="${Math.round((this.#settings.lightingTimeOfDay ?? 0.5) * 1000)}">
|
|
176
|
+
<input type="range" data-setting="lightingTimeOfDay" class="lighting-slider" min="0" max="1000" step="1" value="${Math.round((this.#settings.lightingTimeOfDay ?? 0.5) * 1000)}">
|
|
187
177
|
<div class="lighting-slider-markers" aria-hidden="true">
|
|
188
178
|
<span class="lighting-slider-start">${this.#texts.features?.lightingTimeOfDay?.startLabel || "Night"}</span>
|
|
189
179
|
<span class="lighting-slider-mid">${this.#texts.features?.lightingTimeOfDay?.midLabel || "Day"}</span>
|
|
@@ -325,7 +315,8 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
325
315
|
this.#elements.panel = this.querySelector(".menu-panel");
|
|
326
316
|
this.#elements.title = this.querySelector(".menu-title");
|
|
327
317
|
this.#elements.subtitle = this.querySelector(".menu-subtitle");
|
|
328
|
-
|
|
318
|
+
|
|
319
|
+
// Cache slider elements
|
|
329
320
|
this.#elements.colorPicker = this.querySelector(".menu-color-picker");
|
|
330
321
|
this.#elements.colorSlider = this.querySelector(".color-slider");
|
|
331
322
|
this.#elements.colorPickerPreview = this.querySelector(".color-preview");
|
|
@@ -337,6 +328,11 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
337
328
|
this.#elements.lightingSliderEnd = this.querySelector(".lighting-slider-end");
|
|
338
329
|
this.#elements.lightingSlider = this.querySelector(".lighting-slider");
|
|
339
330
|
this.#elements.lightingValue = this.querySelector(".lighting-slider-value");
|
|
331
|
+
|
|
332
|
+
this.#elements.sliders["highlightColor"] = this.querySelector("input[data-setting='highlightColor']");
|
|
333
|
+
this.#elements.sliderWrappers["highlightColor"] = this.querySelector(".menu-slider[data-setting='highlightColor']");
|
|
334
|
+
this.#elements.sliders["lightingTimeOfDay"] = this.querySelector("input[data-setting='lightingTimeOfDay']");
|
|
335
|
+
this.#elements.sliderWrappers["lightingTimeOfDay"] = this.querySelector(".menu-slider[data-setting='lightingTimeOfDay']");
|
|
340
336
|
|
|
341
337
|
this.#MENU_SWITCHES.forEach((key) => {
|
|
342
338
|
this.#elements.switches[key] = this.querySelector(`input[data-setting="${key}"]`);
|
|
@@ -668,12 +664,13 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
668
664
|
return;
|
|
669
665
|
}
|
|
670
666
|
const detail = { settings: options.partial ? { ...extraSettings } : { ...this.#settings, ...extraSettings } };
|
|
671
|
-
|
|
667
|
+
const eventOptions = {
|
|
672
668
|
bubbles: true,
|
|
673
669
|
cancelable: true,
|
|
674
670
|
composed: true,
|
|
675
671
|
detail,
|
|
676
|
-
}
|
|
672
|
+
};
|
|
673
|
+
this.dispatchEvent(new CustomEvent("pref-viewer-3d-render-settings-change-requested", eventOptions));
|
|
677
674
|
}
|
|
678
675
|
|
|
679
676
|
/**
|
|
@@ -684,10 +681,29 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
684
681
|
#updateSwitches() {
|
|
685
682
|
Object.entries(this.#elements.switches).forEach(([key, input]) => {
|
|
686
683
|
if (input) {
|
|
687
|
-
const isEnabled = this.#
|
|
684
|
+
const isEnabled = this.#elementAvailability[key] !== false;
|
|
685
|
+
const isVisible = this.#elementVisibility[key] !== false;
|
|
688
686
|
input.checked = Boolean(this.#settings[key]);
|
|
689
687
|
input.disabled = !isEnabled;
|
|
690
688
|
this.#elements.switchWrappers[key]?.toggleAttribute("data-disabled", !isEnabled);
|
|
689
|
+
this.#elements.switchWrappers[key]?.toggleAttribute("data-hidden", !isVisible);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Synchronizes slider states with the current settings snapshot.
|
|
696
|
+
* @private
|
|
697
|
+
* @returns {void}
|
|
698
|
+
*/
|
|
699
|
+
#updateSliders() {
|
|
700
|
+
Object.entries(this.#elements.sliders).forEach(([key, input]) => {
|
|
701
|
+
if (input) {
|
|
702
|
+
const isEnabled = this.#elementAvailability[key] !== false;
|
|
703
|
+
const isVisible = this.#elementVisibility[key] !== false;
|
|
704
|
+
input.disabled = !isEnabled;
|
|
705
|
+
this.#elements.sliderWrappers[key]?.toggleAttribute("data-disabled", !isEnabled);
|
|
706
|
+
this.#elements.sliderWrappers[key]?.toggleAttribute("data-hidden", !isVisible);
|
|
691
707
|
}
|
|
692
708
|
});
|
|
693
709
|
}
|
|
@@ -754,6 +770,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
754
770
|
if (this.#settings.lightingTimeOfDay !== undefined) {
|
|
755
771
|
this.#updateLightingSliderUI(this.#settings.lightingTimeOfDay);
|
|
756
772
|
}
|
|
773
|
+
this.#updateSliders();
|
|
757
774
|
this.#updateLightingPlayButtonUI();
|
|
758
775
|
this.setApplying(false);
|
|
759
776
|
}
|
|
@@ -777,17 +794,44 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
777
794
|
}
|
|
778
795
|
|
|
779
796
|
/**
|
|
780
|
-
* Enables or disables a specific render-setting switch in the menu.
|
|
797
|
+
* Enables or disables a specific render-setting switch or slider in the menu.
|
|
781
798
|
* @public
|
|
782
|
-
* @param {string} settingKey -
|
|
799
|
+
* @param {string} settingKey - Setting key (e.g. "iblEnabled", "highlightColor", or "lightingTimeOfDay").
|
|
783
800
|
* @param {boolean} [isEnabled=true] - True to allow interaction, false to disable it.
|
|
784
801
|
* @returns {void}
|
|
785
802
|
*/
|
|
786
|
-
|
|
787
|
-
if (!settingKey
|
|
803
|
+
setElementEnabled(settingKey, isEnabled = true) {
|
|
804
|
+
if (!settingKey) {
|
|
788
805
|
return;
|
|
789
806
|
}
|
|
790
|
-
|
|
791
|
-
this.#
|
|
807
|
+
|
|
808
|
+
if (this.#MENU_SWITCHES.includes(settingKey)) {
|
|
809
|
+
this.#elementAvailability[settingKey] = Boolean(isEnabled);
|
|
810
|
+
this.#updateSwitches();
|
|
811
|
+
} else if (this.#elements.sliders[settingKey]) {
|
|
812
|
+
this.#elementAvailability[settingKey] = Boolean(isEnabled);
|
|
813
|
+
this.#updateSliders();
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Shows or hides a specific render-setting switch or slider in the menu.
|
|
819
|
+
* @public
|
|
820
|
+
* @param {string} settingKey - Setting key (e.g. "iblEnabled", "highlightColor", or "lightingTimeOfDay").
|
|
821
|
+
* @param {boolean} [isVisible=true] - True to show the switch, false to hide it.
|
|
822
|
+
* @returns {void}
|
|
823
|
+
*/
|
|
824
|
+
setElementVisible(settingKey, isVisible = true) {
|
|
825
|
+
if (!settingKey) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
if (this.#MENU_SWITCHES.includes(settingKey)) {
|
|
830
|
+
this.#elementVisibility[settingKey] = Boolean(isVisible);
|
|
831
|
+
this.#updateSwitches();
|
|
832
|
+
} else if (this.#elements.sliders[settingKey]) {
|
|
833
|
+
this.#elementVisibility[settingKey] = Boolean(isVisible);
|
|
834
|
+
this.#updateSliders();
|
|
835
|
+
}
|
|
792
836
|
}
|
|
793
837
|
}
|
package/src/pref-viewer-task.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* PrefViewerTask - Represents a single task or operation to be processed by the PrefViewer.
|
|
3
3
|
*
|
|
4
4
|
* Responsibilities:
|
|
5
|
-
* - Encapsulates the payload and type of a viewer task (e.g., loading a model, updating materials).
|
|
5
|
+
* - Encapsulates the payload and type of a viewer task (e.g., loading a model, updating materials, applying styles).
|
|
6
6
|
* - Validates the task type against a predefined set of allowed types.
|
|
7
7
|
* - Provides an immutable instance to ensure task integrity.
|
|
8
8
|
*
|
|
@@ -12,13 +12,17 @@
|
|
|
12
12
|
* - Access the payload via the `value` property and the normalized type via the `type` property.
|
|
13
13
|
*
|
|
14
14
|
* Static Properties:
|
|
15
|
-
* - Types: An object containing all allowed task types as string constants.
|
|
15
|
+
* - Types: An object containing all allowed task types as string constants, including `Styles` for queued runtime style overrides.
|
|
16
16
|
*
|
|
17
17
|
* Constructor:
|
|
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
21
|
export default class PrefViewerTask {
|
|
22
|
+
/**
|
|
23
|
+
* Allowed task type constants used by the PrefViewer queue.
|
|
24
|
+
* @type {Readonly<{Config: string, Culture: string, Drawing: string, Environment: string, Materials: string, Model: string, Options: string, Styles: string, Visibility: string}>}
|
|
25
|
+
*/
|
|
22
26
|
static Types = Object.freeze({
|
|
23
27
|
Config: "config",
|
|
24
28
|
Culture: "culture",
|
|
@@ -27,6 +31,7 @@ export default class PrefViewerTask {
|
|
|
27
31
|
Materials: "materials",
|
|
28
32
|
Model: "model",
|
|
29
33
|
Options: "options",
|
|
34
|
+
Styles: "styles",
|
|
30
35
|
Visibility: "visibility",
|
|
31
36
|
});
|
|
32
37
|
|