@preference-sl/pref-viewer 2.16.2 → 2.17.0-beta.1

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.
@@ -1,6 +1,6 @@
1
1
  import PrefViewerTask from "./pref-viewer-task.js";
2
2
  import { PREF_VIEWER_STYLES_STORAGE_KEY, PrefViewerStyles, PrefViewerStyleVariables } from "./styles.js";
3
- import { DEFAULT_LOCALE, resolveLocale, setLocale, SUPPORTED_LOCALES } from "./localization/i18n.js";
3
+ import I18n from "./localization/i18n.js";
4
4
 
5
5
  /**
6
6
  * PrefViewer - Custom Web Component for immersive 2D/3D product visualization with localization, persistence, and download tooling.
@@ -23,13 +23,14 @@ import { DEFAULT_LOCALE, resolveLocale, setLocale, SUPPORTED_LOCALES } from "./l
23
23
  * - Listen for `pref-viewer-initialized`, `pref-viewer-loading`, `pref-viewer-loaded`, `pref-viewer-error`, `pref-viewer-3d-loaded`, `pref-viewer-2d-loaded`, and `pref-viewer-2d-viewport-changed` to integrate with surrounding UX.
24
24
  *
25
25
  * Reactive Attributes:
26
- * - config: Configuration descriptor that can bundle model/scene/materials/drawing/culture hints.
26
+ * - config: Configuration descriptor with assets, culture/styles and optional boolean showRenderMenu/showViewCube flags.
27
27
  * - model / scene / materials / drawing: Independent asset entry points (URLs, Base64, indexed data) for each subsystem.
28
28
  * - options: JSON describing render toggles (AA, SSAO, IBL, shadows), animation menu, highlight, lighting, and misc viewer knobs.
29
- * - culture: Locale identifier (RFC-5646 style) that resolves against `SUPPORTED_LOCALES` before applying.
29
+ * - culture: Locale identifier (RFC-5646 style) that resolves against `I18n.SUPPORTED_LOCALES` before applying.
30
30
  * - mode: Switches between `2d` and `3d`, automatically hiding/showing the relevant subcomponents and menu states.
31
31
  * - show-model / show-scene: Boolean flags to toggle visibility without reloading the underlying resources.
32
32
  * - show-render-menu: Boolean flag to show or hide the render-settings menu (default: true).
33
+ * - show-view-cube: Enables the 3D orientation overlay unless "false"; visible cubes position the render menu below their measured height.
33
34
  * - styles: JSON style overrides. Currently supports `colorPrimary`, persisted in localStorage and exposed as `--pref-viewer-color-primary`.
34
35
  *
35
36
  * Public Methods (selection):
@@ -66,6 +67,7 @@ import { DEFAULT_LOCALE, resolveLocale, setLocale, SUPPORTED_LOCALES } from "./l
66
67
  * - Legacy `scene-*` and `drawing-*` aliases are still emitted alongside their modern equivalents for backward compatibility.
67
68
  *
68
69
  * Notes:
70
+ * - Stores the cube layout handler and subscribes only for active 3D cube layout; open dialogs render above viewer overlays.
69
71
  * - Internally wires PrefViewerMenu3D hover/apply events to PrefViewer3D render settings, ensuring persisted toggles stay in sync with BabylonJSController.
70
72
  * - Cleans up dialogs, listeners, and subcomponents on disconnect to prevent leaks when frameworks mount/unmount the custom element.
71
73
  * - Uses localStorage-backed culture persistence and attribute reflection safeguards to keep templates, menu, and global i18n aligned.
@@ -93,8 +95,8 @@ export default class PrefViewer extends HTMLElement {
93
95
 
94
96
  // Localization/culture management
95
97
  #CULTURE_STORAGE_KEY = "pref-viewer/culture";
96
- #cultureInitial = DEFAULT_LOCALE;
97
- #cultureList = SUPPORTED_LOCALES;
98
+ #cultureInitial = I18n.DEFAULT_LOCALE;
99
+ #cultureList = I18n.SUPPORTED_LOCALES;
98
100
  #culture = "";
99
101
  #cultureSuppressAttribute = false;
100
102
 
@@ -115,11 +117,13 @@ export default class PrefViewer extends HTMLElement {
115
117
  #handlers = {
116
118
  on2DZoomChanged: null,
117
119
  on2DElementClick: null,
120
+ on3DElementClick: null,
118
121
  onMenuApply: null,
119
122
  onViewerHoverStart: null,
120
123
  onViewerHoverEnd: null,
121
124
  on3DSceneLoaded: null,
122
125
  on3DSceneError: null,
126
+ onViewCubeLayout: null,
123
127
  };
124
128
 
125
129
  /**
@@ -132,9 +136,9 @@ export default class PrefViewer extends HTMLElement {
132
136
  this.attachShadow({ mode: "open" });
133
137
  const storedCulture = this.#cultureReadPersisted();
134
138
  if (storedCulture) {
135
- this.#culture = resolveLocale(storedCulture);
139
+ this.#culture = I18n.resolveLocale(storedCulture);
136
140
  } else {
137
- this.#culture = setLocale(this.#cultureInitial);
141
+ this.#culture = I18n.setLocale(this.#cultureInitial);
138
142
  }
139
143
 
140
144
  this.#applyStyles(this.#stylesReadPersisted(), { persist: false, applyCssVariables: false });
@@ -146,21 +150,26 @@ export default class PrefViewer extends HTMLElement {
146
150
  * @returns {string[]} Array of attribute names to observe.
147
151
  */
148
152
  static get observedAttributes() {
149
- return ["config", "culture", "drawing", "materials", "mode", "model", "scene", "options", "show-model", "show-scene", "show-render-menu", "styles"];
153
+ return ["config", "culture", "drawing", "materials", "mode", "model", "scene", "options", "show-model", "show-scene", "show-render-menu", "show-view-cube", "styles"];
150
154
  }
151
155
 
152
156
  /**
153
157
  * Observes changes to specific attributes and triggers corresponding actions.
154
158
  * Loads configuration, drawing, model, scene, materials, or options when their attributes change.
155
159
  * Toggles model or scene visibility when "show-model" or "show-scene" attributes change, recreates the 3D menu when "show-render-menu" changes, and queues style overrides when "styles" changes.
160
+ * "show-view-cube" synchronizes lazy cube activation and conditional layout subscription before forwarding the attribute.
156
161
  * @public
157
162
  * @param {string} name - The name of the changed attribute.
158
- * @param {*} _old - The previous value of the attribute (unused).
159
- * @param {*} value - The new value of the attribute.
163
+ * @param {string|null} _old - The previous attribute value.
164
+ * @param {string|null} value - The new attribute value; null when removed.
160
165
  * @returns {void}
161
166
  */
162
167
  attributeChangedCallback(name, _old, value) {
163
168
  switch (name) {
169
+ case "show-view-cube":
170
+ this.#setViewCubeLayoutSubscription(this.#mode === "3d" && value !== "false");
171
+ this.#component3D?.setAttribute("show-view-cube", value === "false" ? "false" : "true");
172
+ break;
164
173
  case "config":
165
174
  this.loadConfig(value);
166
175
  break;
@@ -227,6 +236,7 @@ export default class PrefViewer extends HTMLElement {
227
236
  /**
228
237
  * Called when the element is inserted into the DOM.
229
238
  * Initializes the 3D and 2D viewer components and starts processing tasks.
239
+ * Restores the primary animation-highlight color after creating the 3D component and menu.
230
240
  * @public
231
241
  * @returns {void|boolean} Returns false if initialization fails; otherwise void.
232
242
  */
@@ -236,6 +246,7 @@ export default class PrefViewer extends HTMLElement {
236
246
  this.#createComponent3D();
237
247
  this.#createComponent2D();
238
248
  this.#createMenu3D();
249
+ this.#applyRenderSettings({ highlightColor: this.#styles.colorPrimary, persist: false });
239
250
 
240
251
  this.setMode(this.getAttribute("mode") ?? this.#mode);
241
252
 
@@ -252,7 +263,8 @@ export default class PrefViewer extends HTMLElement {
252
263
  }
253
264
 
254
265
  /**
255
- * Called when the element is removed from the DOM.
266
+ * Removes stored child/menu/dialog listeners and subcomponents when detached.
267
+ * Unsubscribes the cube layout handler before the 3D component and its overlay are torn down.
256
268
  * @public
257
269
  * @returns {void}
258
270
  */
@@ -270,8 +282,10 @@ export default class PrefViewer extends HTMLElement {
270
282
  this.#component2D.remove();
271
283
  }
272
284
  if (this.#component3D) {
285
+ this.#component3D.removeEventListener("pref-viewer-3d-element-click", this.#handlers.on3DElementClick);
273
286
  this.#component3D.removeEventListener("pref-viewer-3d-loaded", this.#handlers.on3DSceneLoaded);
274
287
  this.#component3D.removeEventListener("pref-viewer-3d-error", this.#handlers.on3DSceneError);
288
+ this.#component3D.removeEventListener("view-cube-layout", this.#handlers.onViewCubeLayout);
275
289
  this.#component3D.remove();
276
290
  }
277
291
  if (this.#menu3D) {
@@ -302,8 +316,7 @@ export default class PrefViewer extends HTMLElement {
302
316
  }
303
317
 
304
318
  /**
305
- * Creates and appends the 2D viewer component to the shadow DOM.
306
- * Sets the "visible" attribute to true by default.
319
+ * Creates and appends the 2D viewer component, initially hidden, to the shadow DOM.
307
320
  * @private
308
321
  * @returns {void}
309
322
  */
@@ -318,14 +331,45 @@ export default class PrefViewer extends HTMLElement {
318
331
  }
319
332
 
320
333
  /**
321
- * Creates and appends the 3D viewer component to the shadow DOM.
322
- * Sets the "visible" attribute to true by default.
334
+ * Subscribes before cube activation so its first layout is received.
335
+ * Removes the subscription and menu overrides when the cube is inactive or the mode is 2D.
336
+ * @private
337
+ * @param {boolean} enabled - Whether cube layout updates are needed.
338
+ * @returns {void}
339
+ */
340
+ #setViewCubeLayoutSubscription(enabled) {
341
+ if (!this.#component3D || !this.#handlers.onViewCubeLayout) {
342
+ return;
343
+ }
344
+ this.#component3D.removeEventListener("view-cube-layout", this.#handlers.onViewCubeLayout);
345
+ if (enabled) {
346
+ this.#component3D.addEventListener("view-cube-layout", this.#handlers.onViewCubeLayout);
347
+ } else {
348
+ this.#wrapper?.style.removeProperty("--pref-viewer-render-menu-top");
349
+ this.#wrapper?.style.removeProperty("--pref-viewer-viewport-height");
350
+ }
351
+ }
352
+ /**
353
+ * Creates and appends the 3D viewer component to the shadow DOM, initially hidden.
354
+ * Forwards show-view-cube, stores its layout handler in #handlers and subscribes before activation
355
+ * so the first measured layout positions the render menu correctly.
323
356
  * @private
324
357
  * @returns {void}
325
358
  */
326
359
  #createComponent3D() {
360
+ this.#handlers.on3DElementClick = this.#on3DElementClick.bind(this);
327
361
  this.#component3D = document.createElement("pref-viewer-3d");
328
362
  this.#component3D.setAttribute("visible", "false");
363
+ this.#component3D.setAttribute("show-view-cube", this.getAttribute("show-view-cube") === "false" ? "false" : "true");
364
+ this.#handlers.onViewCubeLayout = (event) => {
365
+ if (event.detail.offset > 0) {
366
+ this.#wrapper.style.setProperty("--pref-viewer-render-menu-top", `${event.detail.offset}px`);
367
+ } else {
368
+ this.#wrapper.style.removeProperty("--pref-viewer-render-menu-top");
369
+ }
370
+ this.#wrapper.style.setProperty("--pref-viewer-viewport-height", `${event.detail.height}px`);
371
+ };
372
+ this.#setViewCubeLayoutSubscription(this.getAttribute("show-view-cube") !== "false" && (this.getAttribute("mode") ?? this.#mode) === "3d");
329
373
 
330
374
  this.#handlers.on3DSceneLoaded = () => {
331
375
  this.#menu3DSyncSettings();
@@ -334,6 +378,7 @@ export default class PrefViewer extends HTMLElement {
334
378
  this.#handlers.on3DSceneError = () => {
335
379
  this.#menu3D?.setApplying(false, true);
336
380
  };
381
+ this.#component3D.addEventListener("pref-viewer-3d-element-click", this.#handlers.on3DElementClick);
337
382
  this.#component3D.addEventListener("pref-viewer-3d-loaded", this.#handlers.on3DSceneLoaded);
338
383
  this.#component3D.addEventListener("pref-viewer-3d-error", this.#handlers.on3DSceneError);
339
384
  this.#wrapper.appendChild(this.#component3D);
@@ -609,7 +654,8 @@ export default class PrefViewer extends HTMLElement {
609
654
  }
610
655
 
611
656
  /**
612
- * Resolves the requested culture, updates internal/global state, and persists the selection.
657
+ * Resolves culture, updates internal/global state and menu/cube labels, and persists the selection.
658
+ * Refreshes only an existing cube; a culture change does not activate an inactive overlay.
613
659
  * @private
614
660
  * @param {string} [cultureId] - Desired locale to activate.
615
661
  * @param {object} [options] - Extra flags for the update.
@@ -626,15 +672,16 @@ export default class PrefViewer extends HTMLElement {
626
672
  return changed;
627
673
  }
628
674
  const { reflectAttribute = false } = options;
629
- const resolved = resolveLocale(cultureId);
675
+ const resolved = I18n.resolveLocale(cultureId);
630
676
  changed = resolved !== this.#culture;
631
677
  if (reflectAttribute) {
632
678
  this.#cultureReflectAttribute(resolved);
633
679
  }
634
680
  if (changed) {
635
681
  this.#culture = resolved;
636
- setLocale(resolved);
682
+ I18n.setLocale(resolved);
637
683
  this.#menu3D?.setCulture?.(resolved);
684
+ this.#component3D?.refreshViewCube?.();
638
685
  this.#culturePersist(resolved);
639
686
  }
640
687
  return changed;
@@ -739,6 +786,7 @@ export default class PrefViewer extends HTMLElement {
739
786
 
740
787
  this.removeAttribute("loading-3d");
741
788
  this.setAttribute("loaded-3d", "");
789
+ this.#applySelectionStateTo3D();
742
790
 
743
791
  this.#dispatchPrefViewerEvent("pref-viewer-3d-loaded", detail ?? {});
744
792
  this.#dispatchPrefViewerEvent("scene-loaded", detail ?? {}); // Legacy event for backward compatibility
@@ -850,12 +898,23 @@ export default class PrefViewer extends HTMLElement {
850
898
  this.notifyElementClick(event.detail?.ids ?? []);
851
899
  }
852
900
 
901
+ /**
902
+ * Forwards semantic click ids from the encapsulated 3D component through the root event contract.
903
+ * @private
904
+ * @param {CustomEvent<{ids: string[]}>} event - Internal 3D model click event.
905
+ * @returns {void}
906
+ */
907
+ #on3DElementClick(event) {
908
+ event.stopPropagation();
909
+ this.notifyElementClick(event.detail?.ids ?? []);
910
+ }
911
+
853
912
  /**
854
913
  * Handles the custom "pref-viewer-3d-render-settings-change-requested" event emitted by the menu component.
855
914
  * Forwards the requested settings to the render-application pipeline.
856
915
  * @private
857
916
  * @param {CustomEvent} event - Menu event containing the `settings` payload.
858
- * @returns {void}
917
+ * @returns {Promise<void>}
859
918
  */
860
919
  async #onMenuApply(event) {
861
920
  event.stopPropagation();
@@ -867,13 +926,24 @@ export default class PrefViewer extends HTMLElement {
867
926
  }
868
927
 
869
928
  /**
870
- * Processes a configuration object by loading it into the 3D component.
929
+ * Applies optional boolean overlay flags through their attributes, then loads the queued 3D configuration.
930
+ * Explicit flags override the current attributes; omitted/non-boolean values preserve their state.
871
931
  * Dispatches loading events and processes the next task when finished.
872
932
  * @private
873
933
  * @param {object} config - The configuration object to process.
874
- * @returns {void}
934
+ * @param {boolean} [config.showRenderMenu] - Reflects render-menu visibility before loading assets; non-booleans are ignored.
935
+ * @param {boolean} [config.showViewCube] - Reflects cube activation before loading assets; non-booleans are ignored.
936
+ * @returns {Promise<void>} Resolves after the load attempt and advances the task queue.
875
937
  */
876
938
  async #processConfig(config) {
939
+ for (const [property, attribute] of [["showRenderMenu", "show-render-menu"], ["showViewCube", "show-view-cube"]]) {
940
+ if (typeof config[property] === "boolean") {
941
+ const value = String(config[property]);
942
+ if (this.getAttribute(attribute) !== value) {
943
+ this.setAttribute(attribute, value);
944
+ }
945
+ }
946
+ }
877
947
  if (!this.#component3D) {
878
948
  this.#processNextTask();
879
949
  return;
@@ -912,7 +982,7 @@ export default class PrefViewer extends HTMLElement {
912
982
  * Processes the next task when finished.
913
983
  * @private
914
984
  * @param {object} drawing - The drawing object to process.
915
- * @returns {void}
985
+ * @returns {Promise<void>}
916
986
  */
917
987
  async #processDrawing(drawing) {
918
988
  if (!this.#component2D) {
@@ -974,7 +1044,7 @@ export default class PrefViewer extends HTMLElement {
974
1044
  * Dispatches loading events and processes the next task.
975
1045
  * @private
976
1046
  * @param {object} options - The options object to process.
977
- * @returns {void}
1047
+ * @returns {Promise<void>}
978
1048
  */
979
1049
  async #processOptions(options) {
980
1050
  if (!this.#component3D) {
@@ -996,14 +1066,20 @@ export default class PrefViewer extends HTMLElement {
996
1066
  }
997
1067
 
998
1068
  /**
999
- * Processes queued style overrides and advances the task queue.
1069
+ * Applies queued styles and synchronizes animation-opening highlight color without reloading assets.
1070
+ * Waits for render settings/menu synchronization before advancing the task queue.
1000
1071
  * @private
1001
1072
  * @param {object} styles - Style overrides to apply.
1002
- * @returns {void}
1073
+ * @returns {Promise<void>} Resolves after style/highlight synchronization and queue advancement.
1003
1074
  */
1004
- #processStyles(styles) {
1005
- this.#applyStyles(styles);
1006
- this.#processNextTask();
1075
+ async #processStyles(styles) {
1076
+ try {
1077
+ if (this.#applyStyles(styles)) {
1078
+ await this.#applyRenderSettings({ highlightColor: this.#styles.colorPrimary });
1079
+ }
1080
+ } finally {
1081
+ this.#processNextTask();
1082
+ }
1007
1083
  }
1008
1084
 
1009
1085
  /**
@@ -1069,7 +1145,7 @@ export default class PrefViewer extends HTMLElement {
1069
1145
  * Non-string and empty-string results are filtered out.
1070
1146
  * @private
1071
1147
  * @param {Array<string|{id?: string, Id?: string}>} value - Array of id-like items to normalize.
1072
- * @returns {string[]} Deduplicated, non-empty string ids.
1148
+ * @returns {string[]} Non-empty string ids, preserving input order and duplicate occurrences.
1073
1149
  */
1074
1150
  #normalizeIdList(value) {
1075
1151
  if (!Array.isArray(value)) {
@@ -1120,11 +1196,31 @@ export default class PrefViewer extends HTMLElement {
1120
1196
  this.#dispatchPrefViewerEvent("pref-viewer-selection-state-changed", this.getSelectionState());
1121
1197
  }
1122
1198
 
1123
- /** Apply the current semantic snapshot to the 2D renderer when available. */
1199
+ /** Apply the current semantic snapshot to the 2D renderer when available. * @returns {void}
1200
+ */
1124
1201
  #applySelectionStateTo2D() {
1125
1202
  this.#component2D?.applySelectionState?.(this.getSelectionState());
1126
1203
  }
1127
1204
 
1205
+ /**
1206
+ * Applies the current semantic snapshot to the 3D renderer when available.
1207
+ * @private
1208
+ * @returns {void}
1209
+ */
1210
+ #applySelectionStateTo3D() {
1211
+ this.#component3D?.applySelectionState?.(this.getSelectionState());
1212
+ }
1213
+
1214
+ /**
1215
+ * Synchronizes the current semantic selection snapshot with both renderers.
1216
+ * @private
1217
+ * @returns {void}
1218
+ */
1219
+ #applySelectionState() {
1220
+ this.#applySelectionStateTo2D();
1221
+ this.#applySelectionStateTo3D();
1222
+ }
1223
+
1128
1224
  /**
1129
1225
  * Dispatches a `pref-viewer-3d-turnable-changed` event carrying the current turnable snapshot.
1130
1226
  * Called after `startTurnable`, `stopTurnable`, or `toggleTurnable` mutates the internal state.
@@ -1259,10 +1355,15 @@ export default class PrefViewer extends HTMLElement {
1259
1355
 
1260
1356
  /**
1261
1357
  * Loads a configuration object or JSON string and adds it to the task queue.
1262
- * If the config contains a drawing, adds a drawing task as well.
1358
+ * Queues supplied styles/culture before the configuration and a supplied drawing afterward.
1359
+ * Boolean showRenderMenu/showViewCube flags apply when that config task is processed, before its 3D load.
1360
+ * Omitted/non-boolean flags preserve current attributes; equal values do not recreate the menu.
1263
1361
  * @public
1264
- * @param {object|string} config - Configuration object or JSON string.
1265
- * @returns {boolean|void} Returns false if config is invalid; otherwise void.
1362
+ * @param {object|string} config - Configuration object or JSON string; overlay flags apply in queue order.
1363
+ * @param {boolean} [config.showRenderMenu] - Sets show-render-menu when explicitly boolean.
1364
+ * @param {boolean} [config.showViewCube] - Sets show-view-cube when explicitly boolean.
1365
+ * @returns {false|void} Returns false for an absent/falsy payload; otherwise queues the configuration.
1366
+ * @throws {SyntaxError} If a supplied JSON string cannot be parsed.
1266
1367
  */
1267
1368
  loadConfig(config) {
1268
1369
  config = typeof config === "string" ? JSON.parse(config) : config;
@@ -1357,7 +1458,8 @@ export default class PrefViewer extends HTMLElement {
1357
1458
  }
1358
1459
 
1359
1460
  /**
1360
- * Sets the viewer mode to "2d" or "3d" and updates component visibility accordingly.
1461
+ * Sets the viewer mode and component/menu visibility; updates the conditional cube layout subscription
1462
+ * before showing 3D or releasing its overlay in 2D.
1361
1463
  * @public
1362
1464
  * @param {string} [mode=this.#mode] - The mode to set ("2d" or "3d").
1363
1465
  * @returns {void}
@@ -1369,6 +1471,7 @@ export default class PrefViewer extends HTMLElement {
1369
1471
  mode = this.#mode;
1370
1472
  }
1371
1473
  this.#mode = mode;
1474
+ this.#setViewCubeLayoutSubscription(mode === "3d" && this.getAttribute("show-view-cube") !== "false");
1372
1475
  if (mode === "2d") {
1373
1476
  this.#component3D?.hide();
1374
1477
  this.#component2D?.show();
@@ -1401,7 +1504,8 @@ export default class PrefViewer extends HTMLElement {
1401
1504
 
1402
1505
  /**
1403
1506
  * Sets supported PrefViewer style variables from an object or JSON string and adds them to the task queue.
1404
- * Currently supports `colorPrimary`, which updates `PrefViewerStyleVariables.colorPrimary`, applies the host CSS custom property, and persists the value in localStorage.
1507
+ * Currently supports `colorPrimary`, which updates `PrefViewerStyleVariables.colorPrimary`, applies the host CSS custom property,
1508
+ * synchronizes animation-opening highlight color (including active highlights), and persists the value in localStorage.
1405
1509
  * @public
1406
1510
  * @param {object|string} styles - Style overrides object or JSON string.
1407
1511
  * @returns {boolean|void} Returns false if styles are invalid; otherwise void.
@@ -1437,7 +1541,7 @@ export default class PrefViewer extends HTMLElement {
1437
1541
  */
1438
1542
  setSelectableElements(elements = []) {
1439
1543
  this.#selectionState.selectableIds = this.#normalizeIdList(elements);
1440
- this.#applySelectionStateTo2D();
1544
+ this.#applySelectionState();
1441
1545
  this.#emitSelectionStateChanged();
1442
1546
  return this.getSelectionState();
1443
1547
  }
@@ -1452,7 +1556,7 @@ export default class PrefViewer extends HTMLElement {
1452
1556
  const selectedItems = this.#normalizeSelectionItems(elements);
1453
1557
  this.#selectionState.selectedItems = selectedItems;
1454
1558
  this.#selectionState.selectedIds = selectedItems.map((item) => item.id);
1455
- this.#applySelectionStateTo2D();
1559
+ this.#applySelectionState();
1456
1560
  this.#emitSelectionStateChanged();
1457
1561
  return this.getSelectionState();
1458
1562
  }
@@ -1468,7 +1572,7 @@ export default class PrefViewer extends HTMLElement {
1468
1572
  const selectedItems = this.#normalizeSelectionItems(state.selectedItems ?? state.selectedIds ?? state.selected ?? []);
1469
1573
  this.#selectionState.selectedItems = selectedItems;
1470
1574
  this.#selectionState.selectedIds = selectedItems.map((item) => item.id);
1471
- this.#applySelectionStateTo2D();
1575
+ this.#applySelectionState();
1472
1576
  this.#emitSelectionStateChanged();
1473
1577
  return this.getSelectionState();
1474
1578
  }
@@ -1481,7 +1585,7 @@ export default class PrefViewer extends HTMLElement {
1481
1585
  clearSelectedElements() {
1482
1586
  this.#selectionState.selectedIds = [];
1483
1587
  this.#selectionState.selectedItems = [];
1484
- this.#applySelectionStateTo2D();
1588
+ this.#applySelectionState();
1485
1589
  this.#emitSelectionStateChanged();
1486
1590
  return this.getSelectionState();
1487
1591
  }
@@ -1493,7 +1597,7 @@ export default class PrefViewer extends HTMLElement {
1493
1597
  */
1494
1598
  clearSelectableElements() {
1495
1599
  this.#selectionState.selectableIds = [];
1496
- this.#applySelectionStateTo2D();
1600
+ this.#applySelectionState();
1497
1601
  this.#emitSelectionStateChanged();
1498
1602
  return this.getSelectionState();
1499
1603
  }
@@ -1509,7 +1613,7 @@ export default class PrefViewer extends HTMLElement {
1509
1613
  selectedIds: [],
1510
1614
  selectedItems: [],
1511
1615
  };
1512
- this.#applySelectionStateTo2D();
1616
+ this.#applySelectionState();
1513
1617
  this.#emitSelectionStateChanged();
1514
1618
  return this.getSelectionState();
1515
1619
  }
@@ -1575,7 +1679,7 @@ export default class PrefViewer extends HTMLElement {
1575
1679
  * Remove every SVG node previously added through appendSvgNode.
1576
1680
  * @public
1577
1681
  * @returns {void}
1578
- * */
1682
+ */
1579
1683
  removeAppendedSvgNodes() {
1580
1684
  this.#component2D?.removeAppendedSvgNodes?.();
1581
1685
  }
@@ -1635,10 +1739,12 @@ export default class PrefViewer extends HTMLElement {
1635
1739
  * @param {string} title - The dialog title to display in the header.
1636
1740
  * @param {string} content - The HTML content to display in the dialog body.
1637
1741
  * @param {string} footer - The HTML content to display in the dialog footer (e.g., action buttons).
1638
- * @returns {HTMLElement} The created dialog element.
1742
+ * @returns {HTMLElement|null} The dialog element if opening succeeds; otherwise null.
1639
1743
  * @description
1640
1744
  * If a dialog is already open, it is closed before opening the new one.
1641
1745
  * The dialog is appended to the viewer's shadow DOM and returned for further manipulation.
1746
+ * Shared dialog styles place its modal backdrop above the render menu and ViewCube.
1747
+ * Background pointer input is intercepted; backdrop dismissal does not also activate a covered control.
1642
1748
  */
1643
1749
  openDialog(title, content, footer) {
1644
1750
  if (this.#dialog && this.#dialog.hasAttribute("open")) {
@@ -1811,9 +1917,14 @@ export default class PrefViewer extends HTMLElement {
1811
1917
  */
1812
1918
 
1813
1919
  /**
1814
- * Accepts a config object or JSON string and forwards it to `loadConfig()`.
1920
+ * Accepts a config object or JSON string and forwards it to `loadConfig()` in the existing task queue.
1921
+ * Includes optional boolean showRenderMenu/showViewCube flags with the same precedence and omission rules.
1922
+ * Supplied styles/culture and drawing retain the loadConfig ordering.
1815
1923
  * @public
1816
1924
  * @param {object|string} value - Configuration payload or serialized JSON.
1925
+ * @param {boolean} [value.showRenderMenu] - Optional render-menu visibility for an object payload.
1926
+ * @param {boolean} [value.showViewCube] - Optional cube visibility for an object payload.
1927
+ * @throws {SyntaxError} If a supplied JSON string cannot be parsed.
1817
1928
  */
1818
1929
  set config(value) {
1819
1930
  this.loadConfig(value);