@preference-sl/pref-viewer 2.13.0-beta.4 → 2.13.0-beta.6
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 +1 -1
- package/src/babylonjs-animation-controller.js +5 -6
- package/src/babylonjs-controller.js +2 -2
- package/src/localization/translations.js +3 -3
- package/src/pref-viewer-3d-data.js +48 -36
- package/src/pref-viewer-3d.js +27 -3
- package/src/pref-viewer-menu-3d.js +35 -1
- package/src/pref-viewer.js +17 -0
- package/src/styles.js +21 -5
package/package.json
CHANGED
|
@@ -43,11 +43,9 @@ export default class BabylonJSAnimationController {
|
|
|
43
43
|
* @param {AssetContainer|Scene} assetContainer - The Babylon.js asset container or scene instance.
|
|
44
44
|
*/
|
|
45
45
|
constructor(assetContainer) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.#canvas = this.#scene._engine._renderingCanvas;
|
|
50
|
-
}
|
|
46
|
+
this.#scene = assetContainer.scene ? assetContainer.scene : assetContainer;
|
|
47
|
+
this.#assetContainer = assetContainer;
|
|
48
|
+
this.#canvas = this.#scene._engine._renderingCanvas;
|
|
51
49
|
this.#initializeAnimations();
|
|
52
50
|
}
|
|
53
51
|
|
|
@@ -163,7 +161,8 @@ export default class BabylonJSAnimationController {
|
|
|
163
161
|
const RENDERING_GROUP_ID = 0; // MUST be > 0 to render on top of main scene
|
|
164
162
|
|
|
165
163
|
// Use UtilityLayerRenderer for rendering
|
|
166
|
-
const
|
|
164
|
+
const utilityLayer = new UtilityLayerRenderer(this.#scene, undefined, undefined);
|
|
165
|
+
const uScene = utilityLayer.utilityLayerScene;
|
|
167
166
|
|
|
168
167
|
// Cache map: baseMesh -> overlayBaseMesh to reuse for InstancedMeshes
|
|
169
168
|
const baseToOverlayBase = new Map();
|
|
@@ -388,7 +388,7 @@ export default class BabylonJSController {
|
|
|
388
388
|
|
|
389
389
|
let lightsChanged = false;
|
|
390
390
|
|
|
391
|
-
const iblEnabled = this.#settings.iblEnabled && this.#options.ibl
|
|
391
|
+
const iblEnabled = this.#settings.iblEnabled && this.#options.ibl?.cachedUrl !== null;
|
|
392
392
|
|
|
393
393
|
if (iblEnabled) {
|
|
394
394
|
if (hemiLight) {
|
|
@@ -935,7 +935,7 @@ export default class BabylonJSController {
|
|
|
935
935
|
|
|
936
936
|
this.#ensureMeshesReceiveShadows();
|
|
937
937
|
|
|
938
|
-
const iblEnabled = this.#settings.iblEnabled && this.#options.ibl
|
|
938
|
+
const iblEnabled = this.#settings.iblEnabled && this.#options.ibl?.cachedUrl !== null;
|
|
939
939
|
const iblShadowsEnabled = iblEnabled && this.#options.ibl.shadows;
|
|
940
940
|
|
|
941
941
|
if (iblShadowsEnabled) {
|
|
@@ -22,7 +22,7 @@ export const translations = {
|
|
|
22
22
|
helper: "Reduction of ambient light in corners and areas close to surfaces.",
|
|
23
23
|
},
|
|
24
24
|
iblEnabled: {
|
|
25
|
-
label: "IBL",
|
|
25
|
+
label: "Image Based Lighting (IBL)",
|
|
26
26
|
helper: "Uses the HDR environment to light the scene.",
|
|
27
27
|
},
|
|
28
28
|
shadowsEnabled: {
|
|
@@ -68,11 +68,11 @@ export const translations = {
|
|
|
68
68
|
helper: "Suaviza aristas y líneas.",
|
|
69
69
|
},
|
|
70
70
|
ambientOcclusionEnabled: {
|
|
71
|
-
label: "
|
|
71
|
+
label: "Oclusión ambiental",
|
|
72
72
|
helper: "Atenuación de la luz ambiental en rincones y zonas cercanas entre superficies.",
|
|
73
73
|
},
|
|
74
74
|
iblEnabled: {
|
|
75
|
-
label: "IBL",
|
|
75
|
+
label: "Iluminación basada en imagen (IBL)",
|
|
76
76
|
helper: "Usa la imagen HDR de entorno para iluminar la escena.",
|
|
77
77
|
},
|
|
78
78
|
shadowsEnabled: {
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ContainerData - Represents
|
|
2
|
+
* ContainerData - Represents state, cache metadata, and update lifecycle for a 3D asset container
|
|
3
|
+
* (for example: model, environment, or materials).
|
|
3
4
|
*
|
|
4
5
|
* Responsibilities:
|
|
5
|
-
* - Tracks container
|
|
6
|
-
* -
|
|
7
|
-
* - Provides
|
|
6
|
+
* - Tracks persistent container fields (`storage`, `show`, `size`, `timeStamp`, `metadata`, `visible`).
|
|
7
|
+
* - Tracks staged update data in `update` (`pending`, `success`, staged storage/show/cache info).
|
|
8
|
+
* - Provides helpers to stage updates (`setPending`, `setPendingCacheData`, `setPendingWithCurrentStorage`)
|
|
9
|
+
* and commit them (`setSuccess(true)`).
|
|
8
10
|
*
|
|
9
11
|
* Usage:
|
|
10
|
-
* - Instantiate with a name: new ContainerData("model")
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
12
|
+
* - Instantiate with a name: `new ContainerData("model")`.
|
|
13
|
+
* - Stage a reload with `setPending(...)`, optionally seed cache metadata, then finalize with `setSuccess(true)`.
|
|
14
|
+
* - Use `setPendingWithCurrentStorage()` to request a reload from the currently stored source.
|
|
15
|
+
* - Inspect flags via `isPending`, `isSuccess`, `isVisible`, and `mustBeShown`.
|
|
13
16
|
*/
|
|
14
17
|
export class ContainerData {
|
|
15
18
|
constructor(name = "") {
|
|
@@ -88,17 +91,18 @@ export class ContainerData {
|
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
/**
|
|
91
|
-
* MaterialData - Represents
|
|
94
|
+
* MaterialData - Represents a material option plus its update lifecycle in the 3D viewer.
|
|
92
95
|
*
|
|
93
96
|
* Responsibilities:
|
|
94
|
-
* -
|
|
95
|
-
* -
|
|
96
|
-
* -
|
|
97
|
+
* - Stores material identity and targeting info (`name`, `nodeNames`, `nodePrefixes`).
|
|
98
|
+
* - Stores current applied material value (`value`).
|
|
99
|
+
* - Tracks staged material changes in `update` (`pending`, `success`, `value`).
|
|
97
100
|
*
|
|
98
101
|
* Usage:
|
|
99
|
-
* - Instantiate with
|
|
100
|
-
* -
|
|
101
|
-
* -
|
|
102
|
+
* - Instantiate with initial values: `new MaterialData("innerWall", value, nodeNames, nodePrefixes)`.
|
|
103
|
+
* - Stage a change with `setPending(...)`, then commit with `setSuccess(true)`.
|
|
104
|
+
* - Use `setPendingWithCurrent()` to reapply the currently stored material value.
|
|
105
|
+
* - Inspect flags via `isPending` and `isSuccess`.
|
|
102
106
|
*/
|
|
103
107
|
export class MaterialData {
|
|
104
108
|
constructor(name = "", value = null, nodeNames = [], nodePrefixes = []) {
|
|
@@ -146,17 +150,18 @@ export class MaterialData {
|
|
|
146
150
|
}
|
|
147
151
|
|
|
148
152
|
/**
|
|
149
|
-
* CameraData - Represents
|
|
153
|
+
* CameraData - Represents camera selection state and camera-lock behavior for the 3D viewer.
|
|
150
154
|
*
|
|
151
155
|
* Responsibilities:
|
|
152
|
-
* -
|
|
153
|
-
* -
|
|
154
|
-
* - Provides
|
|
156
|
+
* - Stores current camera selection (`value`) and lock state (`locked`).
|
|
157
|
+
* - Tracks staged camera updates in `update` (`pending`, `success`, `value`, `locked`).
|
|
158
|
+
* - Provides helpers to stage (`setPending`, `setPendingWithCurrent`) and commit (`setSuccess(true)`) updates.
|
|
155
159
|
*
|
|
156
160
|
* Usage:
|
|
157
|
-
* - Instantiate with a name and optional value: new CameraData("camera", value, locked)
|
|
158
|
-
* -
|
|
159
|
-
* -
|
|
161
|
+
* - Instantiate with a name and optional value: `new CameraData("camera", value, locked)`.
|
|
162
|
+
* - Stage a camera update with `setPending(value, locked)`.
|
|
163
|
+
* - Pass `null` as value to request an unlocked/default camera behavior.
|
|
164
|
+
* - Inspect flags via `isPending` and `isSuccess`.
|
|
160
165
|
*/
|
|
161
166
|
export class CameraData {
|
|
162
167
|
defaultLocked = true;
|
|
@@ -210,33 +215,40 @@ export class CameraData {
|
|
|
210
215
|
}
|
|
211
216
|
|
|
212
217
|
/**
|
|
213
|
-
* IBLData -
|
|
218
|
+
* IBLData - Stores image-based lighting configuration for HDR environment rendering.
|
|
214
219
|
*
|
|
215
220
|
* Responsibilities:
|
|
216
|
-
* - Stores
|
|
217
|
-
* -
|
|
218
|
-
* - Provides helpers to
|
|
221
|
+
* - Stores source and cache references (`url`, `cachedUrl`) for the HDR environment map.
|
|
222
|
+
* - Stores runtime tuning values (`intensity`, `shadows`) and cache identity (`timeStamp`).
|
|
223
|
+
* - Provides helpers to fully reset IBL state (`reset`) or partially update known fields (`setValues`).
|
|
219
224
|
*
|
|
220
225
|
* Usage:
|
|
221
|
-
* - Instantiate with defaults: `const ibl = new IBLData()
|
|
222
|
-
* - Call `
|
|
223
|
-
* -
|
|
226
|
+
* - Instantiate with defaults: `const ibl = new IBLData();`.
|
|
227
|
+
* - Call `setValues(...)` with only the fields you want to update (undefined preserves current values).
|
|
228
|
+
* - Call `reset()` to clear the current IBL environment and restore default intensity/shadows.
|
|
224
229
|
*/
|
|
225
230
|
export class IBLData {
|
|
226
231
|
defaultIntensity = 1.0;
|
|
227
232
|
defaultShadows = false;
|
|
228
|
-
constructor(url = null, intensity = this.defaultIntensity, shadows = this.defaultShadows, timeStamp = null) {
|
|
229
|
-
this.url = url;
|
|
230
|
-
this.cachedUrl = null;
|
|
231
|
-
this.intensity = intensity;
|
|
232
|
-
this.shadows = shadows;
|
|
233
|
-
this.timeStamp = timeStamp;
|
|
234
|
-
}
|
|
235
|
-
setValues(url, cachedUrl = null, intensity = this.defaultIntensity, shadows = this.defaultShadows, timeStamp = null) {
|
|
233
|
+
constructor(url = null, cachedUrl = null, intensity = this.defaultIntensity, shadows = this.defaultShadows, timeStamp = null) {
|
|
236
234
|
this.url = url;
|
|
237
235
|
this.cachedUrl = cachedUrl;
|
|
238
236
|
this.intensity = intensity;
|
|
239
237
|
this.shadows = shadows;
|
|
240
238
|
this.timeStamp = timeStamp;
|
|
241
239
|
}
|
|
240
|
+
reset() {
|
|
241
|
+
this.url = null
|
|
242
|
+
this.cachedUrl = null;
|
|
243
|
+
this.intensity = this.defaultIntensity;
|
|
244
|
+
this.shadows = this.defaultShadows;
|
|
245
|
+
this.timeStamp = null;
|
|
246
|
+
}
|
|
247
|
+
setValues(url, cachedUrl, intensity, shadows, timeStamp) {
|
|
248
|
+
this.url = url !== undefined ? url : this.url;
|
|
249
|
+
this.cachedUrl = cachedUrl !== undefined ? cachedUrl : this.cachedUrl;
|
|
250
|
+
this.intensity = intensity !== undefined ? intensity : this.intensity;
|
|
251
|
+
this.shadows = shadows !== undefined ? shadows : this.shadows;
|
|
252
|
+
this.timeStamp = timeStamp !== undefined ? timeStamp : this.timeStamp;
|
|
253
|
+
}
|
|
242
254
|
}
|
package/src/pref-viewer-3d.js
CHANGED
|
@@ -323,6 +323,10 @@ export default class PrefViewer3D extends HTMLElement {
|
|
|
323
323
|
/**
|
|
324
324
|
* Resolves incoming IBL settings (HDR URL, timestamp, intensity, shadows) and marks the option as pending when changed.
|
|
325
325
|
* Fetches signed URLs/time stamps when storage keys are provided so the Babylon controller can reload the environment map.
|
|
326
|
+
* If `options.ibl` exists but `options.ibl.url` is undefined (missing), the current IBL URL is kept and not marked as pending.
|
|
327
|
+
* This allows updating other IBL properties (such as intensity or shadows) without requiring a new URL.
|
|
328
|
+
* If `options.ibl.url` is explicitly provided as `null` (or resolves to an unavailable URL), it is treated as a request to
|
|
329
|
+
* clear the current IBL environment, and the IBL state is reset so Babylon can remove the environment map.
|
|
326
330
|
* @private
|
|
327
331
|
* @param {object} options - Options payload that may contain an `ibl` block with url, intensity, or shadow flags.
|
|
328
332
|
* @returns {Promise<boolean>} Resolves to true when any IBL property differs from the cached state, otherwise false.
|
|
@@ -339,14 +343,20 @@ export default class PrefViewer3D extends HTMLElement {
|
|
|
339
343
|
let shadows = undefined;
|
|
340
344
|
let intensity = undefined;
|
|
341
345
|
|
|
342
|
-
if (options.ibl.url) {
|
|
343
|
-
url = options.ibl.url;
|
|
346
|
+
if (typeof options.ibl.url === "string" && options.ibl.url.length > 0) {
|
|
344
347
|
const fileStorage = new FileStorage("PrefViewer", "Files");
|
|
345
348
|
const newURL = await fileStorage.getURL(options.ibl.url);
|
|
346
349
|
if (newURL) {
|
|
350
|
+
url = options.ibl.url;
|
|
347
351
|
cachedUrl = newURL;
|
|
348
352
|
timeStamp = await fileStorage.getTimeStamp(options.ibl.url);
|
|
353
|
+
} else {
|
|
354
|
+
url = null;
|
|
355
|
+
cachedUrl = null;
|
|
349
356
|
}
|
|
357
|
+
} else if (options.ibl.url === null) {
|
|
358
|
+
url = null;
|
|
359
|
+
cachedUrl = null;
|
|
350
360
|
}
|
|
351
361
|
if (options.ibl.shadows !== undefined) {
|
|
352
362
|
shadows = options.ibl.shadows;
|
|
@@ -362,7 +372,11 @@ export default class PrefViewer3D extends HTMLElement {
|
|
|
362
372
|
intensity !== undefined && intensity !== iblState.intensity ||
|
|
363
373
|
intensity === undefined && iblState.intensity !== iblState.defaultIntensity;
|
|
364
374
|
if (needUpdate) {
|
|
365
|
-
|
|
375
|
+
if (url === null || cachedUrl === null) {
|
|
376
|
+
iblState.reset();
|
|
377
|
+
} else {
|
|
378
|
+
iblState.setValues(url, cachedUrl, intensity, shadows, timeStamp);
|
|
379
|
+
}
|
|
366
380
|
}
|
|
367
381
|
|
|
368
382
|
return needUpdate;
|
|
@@ -756,6 +770,16 @@ export default class PrefViewer3D extends HTMLElement {
|
|
|
756
770
|
return this.#babylonJSController.getRenderSettings();
|
|
757
771
|
}
|
|
758
772
|
|
|
773
|
+
/**
|
|
774
|
+
* Reports whether an IBL environment map is currently available (cached URL present).
|
|
775
|
+
* @public
|
|
776
|
+
* @returns {boolean} True when `options.ibl.cachedUrl` exists and is non-empty.
|
|
777
|
+
*/
|
|
778
|
+
isIBLAvailable() {
|
|
779
|
+
const cachedUrl = this.#data?.options?.ibl?.cachedUrl;
|
|
780
|
+
return typeof cachedUrl === "string" ? cachedUrl.length > 0 : Boolean(cachedUrl);
|
|
781
|
+
}
|
|
782
|
+
|
|
759
783
|
/**
|
|
760
784
|
* Applies render settings that require reloading the Babylon.js scene.
|
|
761
785
|
* @public
|
|
@@ -9,6 +9,7 @@ import { DEFAULT_LOCALE, resolveLocale, translate } from "./localization/i18n.js
|
|
|
9
9
|
* - Builds an accessible hover/focus-activated panel with switches for AA, SSAO, IBL, and dynamic shadows.
|
|
10
10
|
* - Caches translated copy in `#texts` and listens for culture changes via the `culture` attribute or `setCulture()`.
|
|
11
11
|
* - Tracks applied vs. draft render settings so pending diffs, button enablement, and status text stay in sync.
|
|
12
|
+
* - Supports per-switch availability (enabled/disabled), preventing interaction and pending diffs for unavailable toggles.
|
|
12
13
|
* - Emits `pref-viewer-menu-3d-apply` whenever the user confirms toggles, allowing PrefViewer/BabylonJSController to persist.
|
|
13
14
|
* - Shows transient status/error messages and per-switch pending states while operations complete.
|
|
14
15
|
*
|
|
@@ -17,6 +18,7 @@ import { DEFAULT_LOCALE, resolveLocale, translate } from "./localization/i18n.js
|
|
|
17
18
|
* - `setApplying(isApplying, hasError?)`: locks the UI and optionally displays errors while async updates run.
|
|
18
19
|
* - `setViewerHover(isHovering)`: opens/closes the panel based on viewer hover state.
|
|
19
20
|
* - `setEnabled(isEnabled)`: hides the menu in 2D mode and clears hover data.
|
|
21
|
+
* - `setSwitchEnabled(settingKey, isEnabled)`: enables/disables a concrete toggle (e.g. IBL) based on runtime availability.
|
|
20
22
|
* - `setCulture(cultureId)`: forces a locale change and re-renders copy from the i18n layer.
|
|
21
23
|
*
|
|
22
24
|
* Lifecycle & Integration:
|
|
@@ -52,6 +54,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
52
54
|
#MENU_SWITCHES = Object.keys(this.#DEFAULT_RENDER_SETTINGS);
|
|
53
55
|
#appliedSettings = { ...this.#DEFAULT_RENDER_SETTINGS };
|
|
54
56
|
#draftSettings = { ...this.#DEFAULT_RENDER_SETTINGS };
|
|
57
|
+
#switchAvailability = {};
|
|
55
58
|
#statusTimeout = null;
|
|
56
59
|
#isApplying = false;
|
|
57
60
|
#isEnabled = true;
|
|
@@ -352,6 +355,9 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
352
355
|
* @returns {void}
|
|
353
356
|
*/
|
|
354
357
|
#handleSwitchChange(event) {
|
|
358
|
+
if (event.currentTarget?.disabled) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
355
361
|
const key = event.currentTarget?.dataset?.setting;
|
|
356
362
|
if (!key) {
|
|
357
363
|
return;
|
|
@@ -388,7 +394,10 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
388
394
|
#updateSwitches() {
|
|
389
395
|
Object.entries(this.#elements.switches).forEach(([key, input]) => {
|
|
390
396
|
if (input) {
|
|
397
|
+
const isEnabled = this.#switchAvailability[key] !== false;
|
|
391
398
|
input.checked = Boolean(this.#draftSettings[key]);
|
|
399
|
+
input.disabled = !isEnabled;
|
|
400
|
+
this.#elements.switchWrappers[key]?.toggleAttribute("data-disabled", !isEnabled);
|
|
392
401
|
}
|
|
393
402
|
});
|
|
394
403
|
}
|
|
@@ -416,7 +425,12 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
416
425
|
* @returns {string[]} Keys currently pending application.
|
|
417
426
|
*/
|
|
418
427
|
#getPendingKeys() {
|
|
419
|
-
return Object.keys(this.#DEFAULT_RENDER_SETTINGS).filter((key) =>
|
|
428
|
+
return Object.keys(this.#DEFAULT_RENDER_SETTINGS).filter((key) => {
|
|
429
|
+
if (this.#elements.switches[key]?.disabled) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
return this.#draftSettings[key] !== this.#appliedSettings[key];
|
|
433
|
+
});
|
|
420
434
|
}
|
|
421
435
|
|
|
422
436
|
/**
|
|
@@ -561,4 +575,24 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
561
575
|
this.#closeMenu();
|
|
562
576
|
}
|
|
563
577
|
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Enables or disables a specific render-setting switch in the menu.
|
|
581
|
+
* @public
|
|
582
|
+
* @param {string} settingKey - Switch key (e.g. "iblEnabled").
|
|
583
|
+
* @param {boolean} [isEnabled=true] - True to allow interaction, false to disable it.
|
|
584
|
+
* @returns {void}
|
|
585
|
+
*/
|
|
586
|
+
setSwitchEnabled(settingKey, isEnabled = true) {
|
|
587
|
+
if (!settingKey || !this.#MENU_SWITCHES.includes(settingKey)) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const enabled = Boolean(isEnabled);
|
|
591
|
+
this.#switchAvailability[settingKey] = enabled;
|
|
592
|
+
if (!enabled) {
|
|
593
|
+
this.#draftSettings[settingKey] = this.#appliedSettings[settingKey];
|
|
594
|
+
}
|
|
595
|
+
this.#updateSwitches();
|
|
596
|
+
this.#updatePendingState();
|
|
597
|
+
}
|
|
564
598
|
}
|
package/src/pref-viewer.js
CHANGED
|
@@ -286,6 +286,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
286
286
|
|
|
287
287
|
this.#wrapper.appendChild(this.#menu3D);
|
|
288
288
|
this.#menu3DSyncSettings();
|
|
289
|
+
this.#menu3DUpdateSwitchAvailability();
|
|
289
290
|
this.#menu3DUpdateAvailability();
|
|
290
291
|
}
|
|
291
292
|
|
|
@@ -372,6 +373,19 @@ export default class PrefViewer extends HTMLElement {
|
|
|
372
373
|
this.#menu3D.setEnabled?.(isMode3D);
|
|
373
374
|
}
|
|
374
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Enables/disables menu switches according to current 3D option availability.
|
|
378
|
+
* @private
|
|
379
|
+
* @returns {void}
|
|
380
|
+
*/
|
|
381
|
+
#menu3DUpdateSwitchAvailability() {
|
|
382
|
+
if (!this.#menu3D) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const iblAvailable = this.#component3D?.isIBLAvailable?.() === true;
|
|
386
|
+
this.#menu3D.setSwitchEnabled?.("iblEnabled", iblAvailable);
|
|
387
|
+
}
|
|
388
|
+
|
|
375
389
|
/**
|
|
376
390
|
* Applies render toggles via PrefViewer3D, showing progress in the menu and resyncing on completion.
|
|
377
391
|
* When no changes occur, the menu is simply refreshed to match the controller snapshot.
|
|
@@ -520,6 +534,9 @@ export default class PrefViewer extends HTMLElement {
|
|
|
520
534
|
#on3DLoaded(detail) {
|
|
521
535
|
this.#isLoaded = true;
|
|
522
536
|
this.#isLoading = false;
|
|
537
|
+
|
|
538
|
+
this.#menu3DSyncSettings();
|
|
539
|
+
this.#menu3DUpdateSwitchAvailability();
|
|
523
540
|
|
|
524
541
|
this.removeAttribute("loading-3d");
|
|
525
542
|
this.setAttribute("loaded-3d", "");
|
package/src/styles.js
CHANGED
|
@@ -234,7 +234,7 @@ export const PrefViewerMenu3DStyles = `
|
|
|
234
234
|
border-bottom: none;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch
|
|
237
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch>.menu-switch-copy {
|
|
238
238
|
display: flex;
|
|
239
239
|
flex-direction: column;
|
|
240
240
|
gap: calc(var(--panel-spacing) / 4);
|
|
@@ -262,14 +262,14 @@ export const PrefViewerMenu3DStyles = `
|
|
|
262
262
|
font-size: var(--font-size-small);
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch
|
|
265
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch>.menu-switch-control {
|
|
266
266
|
position: relative;
|
|
267
267
|
width: var(--switch-control-width);
|
|
268
268
|
min-width: var(--switch-control-width);
|
|
269
269
|
height: var(--switch-control-height);
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch
|
|
272
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch>.menu-switch-control input {
|
|
273
273
|
position: absolute;
|
|
274
274
|
inset: 0;
|
|
275
275
|
margin: 0;
|
|
@@ -277,6 +277,18 @@ export const PrefViewerMenu3DStyles = `
|
|
|
277
277
|
cursor: pointer;
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch[data-disabled]>.menu-switch-copy {
|
|
281
|
+
opacity: 0.6;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch[data-disabled]>.menu-switch-control {
|
|
285
|
+
opacity: 0.4;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch>.menu-switch-control input:disabled {
|
|
289
|
+
cursor: not-allowed;
|
|
290
|
+
}
|
|
291
|
+
|
|
280
292
|
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch .menu-switch-visual {
|
|
281
293
|
position: absolute;
|
|
282
294
|
inset: 0;
|
|
@@ -286,6 +298,10 @@ export const PrefViewerMenu3DStyles = `
|
|
|
286
298
|
cursor: pointer;
|
|
287
299
|
}
|
|
288
300
|
|
|
301
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch>.menu-switch-control input:disabled + .menu-switch-visual {
|
|
302
|
+
cursor: not-allowed;
|
|
303
|
+
}
|
|
304
|
+
|
|
289
305
|
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch .menu-switch-visual::after {
|
|
290
306
|
content: "";
|
|
291
307
|
position: absolute;
|
|
@@ -299,11 +315,11 @@ export const PrefViewerMenu3DStyles = `
|
|
|
299
315
|
transition: transform 0.2s ease;
|
|
300
316
|
}
|
|
301
317
|
|
|
302
|
-
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch
|
|
318
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch>.menu-switch-control input:checked + .menu-switch-visual {
|
|
303
319
|
background: var(--switch-control-bar-checked-color);
|
|
304
320
|
}
|
|
305
321
|
|
|
306
|
-
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch
|
|
322
|
+
pref-viewer-menu-3d>.menu-wrapper>.menu-panel>.menu-switches>.menu-switch>.menu-switch-control input:checked + .menu-switch-visual::after {
|
|
307
323
|
transform: translateX(var(--switch-control-thumb-size));
|
|
308
324
|
}
|
|
309
325
|
|