@itwin/appui-react 3.4.0-dev.9 → 3.5.0-dev.12

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.
Files changed (131) hide show
  1. package/CHANGELOG.md +43 -1
  2. package/lib/cjs/appui-react/childwindow/ChildWindowManager.d.ts.map +1 -1
  3. package/lib/cjs/appui-react/childwindow/ChildWindowManager.js +4 -5
  4. package/lib/cjs/appui-react/childwindow/ChildWindowManager.js.map +1 -1
  5. package/lib/cjs/appui-react/dialog/DialogManagerBase.d.ts +7 -0
  6. package/lib/cjs/appui-react/dialog/DialogManagerBase.d.ts.map +1 -1
  7. package/lib/cjs/appui-react/dialog/DialogManagerBase.js +23 -0
  8. package/lib/cjs/appui-react/dialog/DialogManagerBase.js.map +1 -1
  9. package/lib/cjs/appui-react/dialog/ModelessDialogManager.d.ts +0 -2
  10. package/lib/cjs/appui-react/dialog/ModelessDialogManager.d.ts.map +1 -1
  11. package/lib/cjs/appui-react/dialog/ModelessDialogManager.js +6 -18
  12. package/lib/cjs/appui-react/dialog/ModelessDialogManager.js.map +1 -1
  13. package/lib/cjs/appui-react/dialog/StandardMessageBox.d.ts.map +1 -1
  14. package/lib/cjs/appui-react/dialog/StandardMessageBox.js +2 -1
  15. package/lib/cjs/appui-react/dialog/StandardMessageBox.js.map +1 -1
  16. package/lib/cjs/appui-react/frontstage/FrontstageDef.d.ts +13 -1
  17. package/lib/cjs/appui-react/frontstage/FrontstageDef.d.ts.map +1 -1
  18. package/lib/cjs/appui-react/frontstage/FrontstageDef.js +140 -96
  19. package/lib/cjs/appui-react/frontstage/FrontstageDef.js.map +1 -1
  20. package/lib/cjs/appui-react/frontstage/FrontstageManager.d.ts +2 -0
  21. package/lib/cjs/appui-react/frontstage/FrontstageManager.d.ts.map +1 -1
  22. package/lib/cjs/appui-react/frontstage/FrontstageManager.js +4 -0
  23. package/lib/cjs/appui-react/frontstage/FrontstageManager.js.map +1 -1
  24. package/lib/cjs/appui-react/imodel-components/category-tree/Categories.json +2 -2
  25. package/lib/cjs/appui-react/imodel-components/models-tree/Hierarchy.GroupedByClass.json +1 -0
  26. package/lib/cjs/appui-react/imodel-components/models-tree/Hierarchy.json +1 -0
  27. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsTree.d.ts +1 -1
  28. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsTree.d.ts.map +1 -1
  29. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsTree.js +11 -8
  30. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsTree.js.map +1 -1
  31. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.d.ts +15 -1
  32. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.d.ts.map +1 -1
  33. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.js +5 -2
  34. package/lib/cjs/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.js.map +1 -1
  35. package/lib/cjs/appui-react/stagepanels/StagePanelDef.d.ts +0 -6
  36. package/lib/cjs/appui-react/stagepanels/StagePanelDef.d.ts.map +1 -1
  37. package/lib/cjs/appui-react/tools/CoreToolDefinitions.d.ts +1 -0
  38. package/lib/cjs/appui-react/tools/CoreToolDefinitions.d.ts.map +1 -1
  39. package/lib/cjs/appui-react/tools/CoreToolDefinitions.js +23 -4
  40. package/lib/cjs/appui-react/tools/CoreToolDefinitions.js.map +1 -1
  41. package/lib/cjs/appui-react/tools/RestoreLayoutTool.d.ts +9 -0
  42. package/lib/cjs/appui-react/tools/RestoreLayoutTool.d.ts.map +1 -1
  43. package/lib/cjs/appui-react/tools/RestoreLayoutTool.js +17 -1
  44. package/lib/cjs/appui-react/tools/RestoreLayoutTool.js.map +1 -1
  45. package/lib/cjs/appui-react/ui-items-provider/StandardNavigationToolsProvider.d.ts.map +1 -1
  46. package/lib/cjs/appui-react/ui-items-provider/StandardNavigationToolsProvider.js +2 -0
  47. package/lib/cjs/appui-react/ui-items-provider/StandardNavigationToolsProvider.js.map +1 -1
  48. package/lib/cjs/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.d.ts +1 -0
  49. package/lib/cjs/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.d.ts.map +1 -1
  50. package/lib/cjs/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.js +2 -0
  51. package/lib/cjs/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.js.map +1 -1
  52. package/lib/cjs/appui-react/widget-panels/FloatingWidget.d.ts +7 -0
  53. package/lib/cjs/appui-react/widget-panels/FloatingWidget.d.ts.map +1 -0
  54. package/lib/cjs/appui-react/widget-panels/FloatingWidget.js +19 -0
  55. package/lib/cjs/appui-react/widget-panels/FloatingWidget.js.map +1 -0
  56. package/lib/cjs/appui-react/widget-panels/Frontstage.d.ts +20 -697
  57. package/lib/cjs/appui-react/widget-panels/Frontstage.d.ts.map +1 -1
  58. package/lib/cjs/appui-react/widget-panels/Frontstage.js +300 -271
  59. package/lib/cjs/appui-react/widget-panels/Frontstage.js.map +1 -1
  60. package/lib/cjs/appui-react/widget-panels/useWidgetDirection.js +1 -1
  61. package/lib/cjs/appui-react/widget-panels/useWidgetDirection.js.map +1 -1
  62. package/lib/cjs/appui-react/widgets/WidgetDef.d.ts +16 -6
  63. package/lib/cjs/appui-react/widgets/WidgetDef.d.ts.map +1 -1
  64. package/lib/cjs/appui-react/widgets/WidgetDef.js +13 -1
  65. package/lib/cjs/appui-react/widgets/WidgetDef.js.map +1 -1
  66. package/lib/esm/appui-react/childwindow/ChildWindowManager.d.ts.map +1 -1
  67. package/lib/esm/appui-react/childwindow/ChildWindowManager.js +4 -5
  68. package/lib/esm/appui-react/childwindow/ChildWindowManager.js.map +1 -1
  69. package/lib/esm/appui-react/dialog/DialogManagerBase.d.ts +7 -0
  70. package/lib/esm/appui-react/dialog/DialogManagerBase.d.ts.map +1 -1
  71. package/lib/esm/appui-react/dialog/DialogManagerBase.js +23 -0
  72. package/lib/esm/appui-react/dialog/DialogManagerBase.js.map +1 -1
  73. package/lib/esm/appui-react/dialog/ModelessDialogManager.d.ts +0 -2
  74. package/lib/esm/appui-react/dialog/ModelessDialogManager.d.ts.map +1 -1
  75. package/lib/esm/appui-react/dialog/ModelessDialogManager.js +6 -18
  76. package/lib/esm/appui-react/dialog/ModelessDialogManager.js.map +1 -1
  77. package/lib/esm/appui-react/dialog/StandardMessageBox.d.ts.map +1 -1
  78. package/lib/esm/appui-react/dialog/StandardMessageBox.js +2 -1
  79. package/lib/esm/appui-react/dialog/StandardMessageBox.js.map +1 -1
  80. package/lib/esm/appui-react/frontstage/FrontstageDef.d.ts +13 -1
  81. package/lib/esm/appui-react/frontstage/FrontstageDef.d.ts.map +1 -1
  82. package/lib/esm/appui-react/frontstage/FrontstageDef.js +142 -98
  83. package/lib/esm/appui-react/frontstage/FrontstageDef.js.map +1 -1
  84. package/lib/esm/appui-react/frontstage/FrontstageManager.d.ts +2 -0
  85. package/lib/esm/appui-react/frontstage/FrontstageManager.d.ts.map +1 -1
  86. package/lib/esm/appui-react/frontstage/FrontstageManager.js +4 -0
  87. package/lib/esm/appui-react/frontstage/FrontstageManager.js.map +1 -1
  88. package/lib/esm/appui-react/imodel-components/category-tree/Categories.json +2 -2
  89. package/lib/esm/appui-react/imodel-components/models-tree/Hierarchy.GroupedByClass.json +1 -0
  90. package/lib/esm/appui-react/imodel-components/models-tree/Hierarchy.json +1 -0
  91. package/lib/esm/appui-react/imodel-components/models-tree/ModelsTree.d.ts +1 -1
  92. package/lib/esm/appui-react/imodel-components/models-tree/ModelsTree.d.ts.map +1 -1
  93. package/lib/esm/appui-react/imodel-components/models-tree/ModelsTree.js +12 -9
  94. package/lib/esm/appui-react/imodel-components/models-tree/ModelsTree.js.map +1 -1
  95. package/lib/esm/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.d.ts +15 -1
  96. package/lib/esm/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.d.ts.map +1 -1
  97. package/lib/esm/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.js +4 -2
  98. package/lib/esm/appui-react/imodel-components/models-tree/ModelsVisibilityHandler.js.map +1 -1
  99. package/lib/esm/appui-react/stagepanels/StagePanelDef.d.ts +0 -6
  100. package/lib/esm/appui-react/stagepanels/StagePanelDef.d.ts.map +1 -1
  101. package/lib/esm/appui-react/tools/CoreToolDefinitions.d.ts +1 -0
  102. package/lib/esm/appui-react/tools/CoreToolDefinitions.d.ts.map +1 -1
  103. package/lib/esm/appui-react/tools/CoreToolDefinitions.js +25 -6
  104. package/lib/esm/appui-react/tools/CoreToolDefinitions.js.map +1 -1
  105. package/lib/esm/appui-react/tools/RestoreLayoutTool.d.ts +9 -0
  106. package/lib/esm/appui-react/tools/RestoreLayoutTool.d.ts.map +1 -1
  107. package/lib/esm/appui-react/tools/RestoreLayoutTool.js +15 -0
  108. package/lib/esm/appui-react/tools/RestoreLayoutTool.js.map +1 -1
  109. package/lib/esm/appui-react/ui-items-provider/StandardNavigationToolsProvider.d.ts.map +1 -1
  110. package/lib/esm/appui-react/ui-items-provider/StandardNavigationToolsProvider.js +2 -0
  111. package/lib/esm/appui-react/ui-items-provider/StandardNavigationToolsProvider.js.map +1 -1
  112. package/lib/esm/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.d.ts +1 -0
  113. package/lib/esm/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.d.ts.map +1 -1
  114. package/lib/esm/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.js +2 -0
  115. package/lib/esm/appui-react/ui-items-provider/StandardNavigationToolsUiItemsProvider.js.map +1 -1
  116. package/lib/esm/appui-react/widget-panels/FloatingWidget.d.ts +7 -0
  117. package/lib/esm/appui-react/widget-panels/FloatingWidget.d.ts.map +1 -0
  118. package/lib/esm/appui-react/widget-panels/FloatingWidget.js +15 -0
  119. package/lib/esm/appui-react/widget-panels/FloatingWidget.js.map +1 -0
  120. package/lib/esm/appui-react/widget-panels/Frontstage.d.ts +20 -697
  121. package/lib/esm/appui-react/widget-panels/Frontstage.d.ts.map +1 -1
  122. package/lib/esm/appui-react/widget-panels/Frontstage.js +291 -265
  123. package/lib/esm/appui-react/widget-panels/Frontstage.js.map +1 -1
  124. package/lib/esm/appui-react/widget-panels/useWidgetDirection.js +2 -2
  125. package/lib/esm/appui-react/widget-panels/useWidgetDirection.js.map +1 -1
  126. package/lib/esm/appui-react/widgets/WidgetDef.d.ts +16 -6
  127. package/lib/esm/appui-react/widgets/WidgetDef.d.ts.map +1 -1
  128. package/lib/esm/appui-react/widgets/WidgetDef.js +13 -1
  129. package/lib/esm/appui-react/widgets/WidgetDef.js.map +1 -1
  130. package/lib/public/locales/en/UiFramework.json +10 -3
  131. package/package.json +37 -35
@@ -8,13 +8,13 @@
8
8
  */
9
9
  // cSpell:ignore popout
10
10
  import "./Frontstage.scss";
11
- import produce, { castDraft } from "immer";
11
+ import produce from "immer";
12
12
  import * as React from "react";
13
13
  import { assert, Logger, ProcessDetector } from "@itwin/core-bentley";
14
14
  import { StagePanelLocation, UiItemsManager, WidgetState } from "@itwin/appui-abstract";
15
- import { Size, UiStateStorageStatus } from "@itwin/core-react";
15
+ import { Rectangle, Size, UiStateStorageStatus } from "@itwin/core-react";
16
16
  import { ToolbarPopupAutoHideContext } from "@itwin/components-react";
17
- import { addPanelWidget, addTab, addWidgetTabToDraftFloatingPanel, addWidgetTabToFloatingPanel, addWidgetTabToPanelSection, convertAllPopupWidgetContainersToFloating, createNineZoneState, createTabsState, createTabState, createWidgetState, findTab, findWidget, floatingWidgetBringToFront, FloatingWidgets, getUniqueId, getWidgetPanelSectionId, isFloatingLocation, isHorizontalPanelSide, isPopoutLocation, NineZone, NineZoneStateReducer, panelSides, removeTab, toolSettingsTabId, WidgetPanels, } from "@itwin/appui-layout-react";
17
+ import { addFloatingWidget, addPanelWidget, addTab, addTabToWidget, convertAllPopupWidgetContainersToFloating, createNineZoneState, floatingWidgetBringToFront, FloatingWidgets, getTabLocation, getUniqueId, getWidgetPanelSectionId, insertPanelWidget, insertTabToWidget, isFloatingTabLocation, isHorizontalPanelSide, isPanelTabLocation, isPopoutTabLocation, NineZone, NineZoneStateReducer, panelSides, removeTab, removeTabFromWidget, toolSettingsTabId, WidgetPanels, } from "@itwin/appui-layout-react";
18
18
  import { useActiveFrontstageDef } from "../frontstage/Frontstage";
19
19
  import { FrontstageManager } from "../frontstage/FrontstageManager";
20
20
  import { StagePanelState } from "../stagepanels/StagePanelDef";
@@ -32,6 +32,7 @@ import { useEscapeSetFocusToHome } from "../hooks/useEscapeSetFocusToHome";
32
32
  import { useSelector } from "react-redux";
33
33
  import { useUiVisibility } from "../hooks/useUiVisibility";
34
34
  import { IModelApp } from "@itwin/core-frontend";
35
+ import { FloatingWidget } from "./FloatingWidget";
35
36
  const panelZoneKeys = ["start", "end"];
36
37
  const WidgetInternals = React.memo(function WidgetInternals() {
37
38
  const activeModalFrontstageInfo = useActiveModalFrontstageInfo();
@@ -171,6 +172,7 @@ export const WidgetPanelsFrontstage = React.memo(function WidgetPanelsFrontstage
171
172
  });
172
173
  const defaultNineZone = createNineZoneState();
173
174
  const tabElement = React.createElement(WidgetPanelsTab, null);
175
+ const floatingWidgetElement = React.createElement(FloatingWidget, null);
174
176
  /** @internal */
175
177
  export function ActiveFrontstageDefProvider({ frontstageDef }) {
176
178
  let nineZone = useNineZoneState(frontstageDef);
@@ -201,7 +203,7 @@ export function ActiveFrontstageDefProvider({ frontstageDef }) {
201
203
  useFrontstageManager(frontstageDef, useToolAsToolSettingsLabel);
202
204
  const handleKeyDown = useEscapeSetFocusToHome();
203
205
  return (React.createElement("div", { className: "uifw-widgetPanels-frontstage", onKeyDown: handleKeyDown, role: "presentation" },
204
- React.createElement(NineZone, { dispatch: dispatch, labels: labels, state: nineZone, tab: tabElement, showWidgetIcon: showWidgetIcon, autoCollapseUnpinnedPanels: autoCollapseUnpinnedPanels, toolSettingsContent: toolSettingsContent, widgetContent: widgetContent, animateDockedToolSettings: animateToolSettings, uiIsVisible: uiIsVisible }, widgetPanelsFrontstage)));
206
+ React.createElement(NineZone, { dispatch: dispatch, labels: labels, state: nineZone, tab: tabElement, floatingWidget: floatingWidgetElement, showWidgetIcon: showWidgetIcon, autoCollapseUnpinnedPanels: autoCollapseUnpinnedPanels, toolSettingsContent: toolSettingsContent, widgetContent: widgetContent, animateDockedToolSettings: animateToolSettings, uiIsVisible: uiIsVisible }, widgetPanelsFrontstage)));
205
207
  }
206
208
  /** @internal */
207
209
  export function useLabels() {
@@ -233,6 +235,7 @@ export function addWidgets(state, widgets, side, widgetId) {
233
235
  canPopout: widget.canPopout,
234
236
  isFloatingStateWindowResizable: widget.isFloatingStateWindowResizable,
235
237
  hideWithUiWhenFloating: !!widget.hideWithUiWhenFloating,
238
+ allowedPanelTargets: widget.allowedPanelTargets,
236
239
  });
237
240
  tabs.push(widget.id);
238
241
  }
@@ -259,7 +262,6 @@ export function appendWidgets(state, widgetDefs, side, preferredWidgetIndex) {
259
262
  const saveTab = state.tabs[widgetDef.id];
260
263
  const preferredPanelWidgetSize = saveTab ? saveTab.preferredPanelWidgetSize : widgetDef.preferredPanelSize;
261
264
  const preferredFloatingWidgetSize = saveTab ? saveTab.preferredFloatingWidgetSize : widgetDef.defaultFloatingSize;
262
- const preferredPopoutWidgetSize = saveTab ? saveTab.preferredPopoutWidgetSize : undefined;
263
265
  // if a defaultFloatingSize is specified then this mean the widget can't determine its intrinsic size and must be explicitly sized
264
266
  const userSized = saveTab ? (saveTab.userSized || !!widgetDef.defaultFloatingSize && !!saveTab.preferredFloatingWidgetSize)
265
267
  : !!widgetDef.defaultFloatingSize;
@@ -269,21 +271,51 @@ export function appendWidgets(state, widgetDefs, side, preferredWidgetIndex) {
269
271
  canPopout: widgetDef.canPopout,
270
272
  preferredPanelWidgetSize,
271
273
  preferredFloatingWidgetSize,
272
- preferredPopoutWidgetSize,
273
274
  userSized,
274
275
  isFloatingStateWindowResizable: widgetDef.isFloatingStateWindowResizable,
275
276
  hideWithUiWhenFloating: !!widgetDef.hideWithUiWhenFloating,
277
+ allowedPanelTargets: widgetDef.allowedPanelTargets,
276
278
  });
277
279
  if (widgetDef.isFloatingStateSupported && widgetDef.defaultState === WidgetState.Floating) {
278
280
  const floatingContainerId = (_a = widgetDef.floatingContainerId) !== null && _a !== void 0 ? _a : getUniqueId();
279
281
  const widgetContainerId = getWidgetId(side, panelZoneKeys[preferredWidgetIndex]);
280
- const homePanelInfo = { side, widgetId: widgetContainerId, widgetIndex: 0 };
282
+ const home = { side, widgetId: widgetContainerId, widgetIndex: 0 };
281
283
  const preferredPosition = widgetDef.defaultFloatingPosition;
282
- state = addWidgetTabToFloatingPanel(state, floatingContainerId, widgetDef.id, homePanelInfo, preferredFloatingWidgetSize, preferredPosition, userSized, widgetDef.isFloatingStateWindowResizable);
284
+ if (floatingContainerId in state.widgets) {
285
+ state = addTabToWidget(state, widgetDef.id, floatingContainerId);
286
+ }
287
+ else {
288
+ const tab = state.tabs[widgetDef.id];
289
+ const size = { height: 200, width: 300, ...tab.preferredFloatingWidgetSize };
290
+ const preferredPoint = preferredPosition !== null && preferredPosition !== void 0 ? preferredPosition : { x: (state.size.width - size.width) / 2, y: (state.size.height - size.height) / 2 };
291
+ const nzBounds = Rectangle.createFromSize(state.size);
292
+ const bounds = Rectangle.createFromSize(size).offset(preferredPoint);
293
+ const containedBounds = bounds.containIn(nzBounds);
294
+ state = addFloatingWidget(state, floatingContainerId, [widgetDef.id], {
295
+ bounds: containedBounds.toProps(),
296
+ home,
297
+ userSized,
298
+ }, {
299
+ isFloatingStateWindowResizable: widgetDef.isFloatingStateWindowResizable,
300
+ });
301
+ }
283
302
  }
284
303
  else {
285
304
  const widgetPanelSectionId = getWidgetPanelSectionId(side, preferredWidgetIndex);
286
- state = addWidgetTabToPanelSection(state, side, widgetPanelSectionId, widgetDef.id);
305
+ if (widgetPanelSectionId in state.widgets) {
306
+ state = addTabToWidget(state, widgetDef.id, widgetPanelSectionId);
307
+ }
308
+ else {
309
+ const panel = state.panels[side];
310
+ if (panel.widgets.length < panel.maxWidgetCount) {
311
+ state = addPanelWidget(state, side, widgetPanelSectionId, [widgetDef.id]);
312
+ }
313
+ else {
314
+ const widgetIndex = Math.min(preferredWidgetIndex, panel.widgets.length - 1);
315
+ const widgetId = panel.widgets[widgetIndex];
316
+ state = addTabToWidget(state, widgetDef.id, widgetId);
317
+ }
318
+ }
287
319
  }
288
320
  }
289
321
  return state;
@@ -329,17 +361,15 @@ export function addMissingWidgets(frontstageDef, initialState) {
329
361
  state = appendWidgets(state, determineNewWidgets((_t = frontstageDef.bottomPanel) === null || _t === void 0 ? void 0 : _t.panelZones.end.widgetDefs, state), "bottom", 1);
330
362
  return state;
331
363
  }
332
- /** Removes widgets with Hidden defaultState. */
333
- function removeHiddenWidgets(state, frontstageDef) {
364
+ /** Hide widgets with Hidden defaultState. */
365
+ function hideWidgets(state, frontstageDef) {
334
366
  const tabs = Object.values(state.tabs);
335
367
  for (const tab of tabs) {
336
368
  const widgetDef = frontstageDef.findWidgetDef(tab.id);
337
369
  if (!widgetDef)
338
370
  continue;
339
371
  if (widgetDef.defaultState === WidgetState.Hidden) {
340
- state = produce(state, (draft) => {
341
- hideWidget(draft, widgetDef);
342
- });
372
+ state = hideWidget(state, widgetDef);
343
373
  }
344
374
  }
345
375
  return state;
@@ -348,16 +378,15 @@ function removeHiddenWidgets(state, frontstageDef) {
348
378
  * @internal
349
379
  */
350
380
  export function removeMissingWidgets(frontstageDef, initialState) {
351
- const state = produce(initialState, (draft) => {
352
- for (const [, tab] of Object.entries(draft.tabs)) {
353
- if (tab.id === toolSettingsTabId)
354
- continue;
355
- const widgetDef = frontstageDef.findWidgetDef(tab.id);
356
- if (widgetDef)
357
- continue;
358
- removeTab(draft, tab.id);
359
- }
360
- });
381
+ let state = initialState;
382
+ for (const [, tab] of Object.entries(state.tabs)) {
383
+ if (tab.id === toolSettingsTabId)
384
+ continue;
385
+ const widgetDef = frontstageDef.findWidgetDef(tab.id);
386
+ if (widgetDef)
387
+ continue;
388
+ state = removeTab(state, tab.id);
389
+ }
361
390
  return state;
362
391
  }
363
392
  function getWidgetLabel(label) {
@@ -508,23 +537,23 @@ export function isFrontstageStateSettingResult(settingsResult) {
508
537
  return false;
509
538
  }
510
539
  /** @internal */
511
- export function initializePanel(nineZone, frontstageDef, panelSide) {
512
- nineZone = addPanelWidgets(nineZone, frontstageDef, panelSide);
540
+ export function initializePanel(state, frontstageDef, panelSide) {
541
+ state = addPanelWidgets(state, frontstageDef, panelSide);
513
542
  const location = toStagePanelLocation(panelSide);
514
543
  const panelDef = frontstageDef.getStagePanelDef(location);
515
- nineZone = produce(nineZone, (draft) => {
544
+ state = produce(state, (draft) => {
516
545
  var _a, _b, _c;
517
546
  const panel = draft.panels[panelSide];
518
547
  panel.minSize = (_a = panelDef === null || panelDef === void 0 ? void 0 : panelDef.minSize) !== null && _a !== void 0 ? _a : panel.minSize;
519
548
  panel.pinned = (_b = panelDef === null || panelDef === void 0 ? void 0 : panelDef.pinned) !== null && _b !== void 0 ? _b : panel.pinned;
520
549
  panel.resizable = (_c = panelDef === null || panelDef === void 0 ? void 0 : panelDef.resizable) !== null && _c !== void 0 ? _c : panel.resizable;
521
550
  if (panelDef === null || panelDef === void 0 ? void 0 : panelDef.maxSizeSpec) {
522
- panel.maxSize = getPanelMaxSize(panelDef.maxSizeSpec, panelSide, nineZone.size);
551
+ panel.maxSize = getPanelMaxSize(panelDef.maxSizeSpec, panelSide, state.size);
523
552
  }
524
553
  const size = panelDef === null || panelDef === void 0 ? void 0 : panelDef.size;
525
554
  panel.size = size === undefined ? size : Math.min(Math.max(size, panel.minSize), panel.maxSize);
526
555
  });
527
- return nineZone;
556
+ return state;
528
557
  }
529
558
  function getPanelMaxSize(maxSizeSpec, panel, nineZoneSize) {
530
559
  if (typeof maxSizeSpec === "number") {
@@ -533,7 +562,7 @@ function getPanelMaxSize(maxSizeSpec, panel, nineZoneSize) {
533
562
  const size = isHorizontalPanelSide(panel) ? nineZoneSize.height : nineZoneSize.width;
534
563
  return maxSizeSpec.percentage / 100 * size;
535
564
  }
536
- const stateVersion = 12; // this needs to be bumped when NineZoneState is changed (to recreate layout).
565
+ const stateVersion = 13; // this needs to be bumped when NineZoneState is changed (to recreate the layout).
537
566
  /** @internal */
538
567
  export function initializeNineZoneState(frontstageDef) {
539
568
  let nineZone = defaultNineZone;
@@ -555,6 +584,7 @@ export function initializeNineZoneState(frontstageDef) {
555
584
  for (const [, panel] of Object.entries(stateDraft.panels)) {
556
585
  const expanded = panel.widgets.find((widgetId) => stateDraft.widgets[widgetId].minimized === false);
557
586
  const firstWidget = panel.widgets.length > 0 ? stateDraft.widgets[panel.widgets[0]] : undefined;
587
+ // istanbul ignore next
558
588
  if (!expanded && firstWidget) {
559
589
  firstWidget.minimized = false;
560
590
  }
@@ -583,7 +613,7 @@ export function initializeNineZoneState(frontstageDef) {
583
613
  }
584
614
  });
585
615
  nineZone = addMissingWidgets(frontstageDef, nineZone);
586
- nineZone = removeHiddenWidgets(nineZone, frontstageDef);
616
+ nineZone = hideWidgets(nineZone, frontstageDef);
587
617
  nineZone = processPopoutWidgets(nineZone, frontstageDef);
588
618
  return nineZone;
589
619
  }
@@ -595,29 +625,33 @@ export function initializeNineZoneState(frontstageDef) {
595
625
  export function restoreNineZoneState(frontstageDef, saved) {
596
626
  let restored = {
597
627
  ...saved,
598
- tabs: createTabsState(),
628
+ tabs: defaultNineZone.tabs,
599
629
  };
600
- restored = produce(restored, (draft) => {
601
- var _a;
602
- for (const [, tab] of Object.entries(saved.tabs)) {
603
- const widgetDef = frontstageDef.findWidgetDef(tab.id);
604
- if (!widgetDef) {
605
- Logger.logInfo(UiFramework.loggerCategory(restoreNineZoneState), "WidgetDef is not found for saved tab.", () => ({
606
- frontstageId: frontstageDef.id,
607
- tabId: tab.id,
608
- }));
609
- removeTab(draft, tab.id);
610
- // let fall through so we preserve preferred sizes of widgets load via UiItemsProvider
611
- }
630
+ for (const [, tab] of Object.entries(saved.tabs)) {
631
+ // Re-add the placeholder tab in order to correctly remove it from the state if WidgetDef is not found.
632
+ restored = addTab(restored, tab.id);
633
+ const widgetDef = frontstageDef.findWidgetDef(tab.id);
634
+ if (!widgetDef) {
635
+ Logger.logInfo(UiFramework.loggerCategory(restoreNineZoneState), "WidgetDef is not found for saved tab.", () => ({
636
+ frontstageId: frontstageDef.id,
637
+ tabId: tab.id,
638
+ }));
639
+ restored = removeTab(restored, tab.id);
640
+ continue;
641
+ }
642
+ restored = produce(restored, (draft) => {
612
643
  draft.tabs[tab.id] = {
613
644
  ...tab,
614
- label: getWidgetLabel((_a = widgetDef === null || widgetDef === void 0 ? void 0 : widgetDef.label) !== null && _a !== void 0 ? _a : "undefined"),
615
- hideWithUiWhenFloating: widgetDef === null || widgetDef === void 0 ? void 0 : widgetDef.hideWithUiWhenFloating,
616
- iconSpec: widgetDef === null || widgetDef === void 0 ? void 0 : widgetDef.iconSpec,
617
- canPopout: widgetDef === null || widgetDef === void 0 ? void 0 : widgetDef.canPopout,
618
- isFloatingStateWindowResizable: widgetDef === null || widgetDef === void 0 ? void 0 : widgetDef.isFloatingStateWindowResizable,
645
+ label: getWidgetLabel(widgetDef.label),
646
+ hideWithUiWhenFloating: widgetDef.hideWithUiWhenFloating,
647
+ iconSpec: widgetDef.iconSpec,
648
+ canPopout: widgetDef.canPopout,
649
+ isFloatingStateWindowResizable: widgetDef.isFloatingStateWindowResizable,
650
+ allowedPanelTargets: widgetDef.allowedPanelTargets,
619
651
  };
620
- }
652
+ });
653
+ }
654
+ restored = produce(restored, (draft) => {
621
655
  // remove center panel section if one is found in left or right panels
622
656
  const oldLeftMiddleIndex = saved.panels.left.widgets.findIndex((value) => value === "leftMiddle");
623
657
  // istanbul ignore next
@@ -656,20 +690,6 @@ export function restoreNineZoneState(frontstageDef, saved) {
656
690
  }
657
691
  return restored;
658
692
  }
659
- /**
660
- * Checks to see whether a widget id is one of our generated uuids
661
- * @param uuid the string value to test
662
- * @returns boolean
663
- */
664
- function isUUID(uuid) {
665
- const s = `${uuid}`;
666
- const result = s.match("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
667
- // istanbul ignore else
668
- if (result === null) {
669
- return false;
670
- }
671
- return true;
672
- }
673
693
  /** Prepares NineZoneState to be saved.
674
694
  * @note Removes toolSettings tab.
675
695
  * @note Removes tab labels and iconSpec.
@@ -684,31 +704,60 @@ export function packNineZoneState(state) {
684
704
  for (const [, tab] of Object.entries(state.tabs)) {
685
705
  if (tab.id === toolSettingsTabId)
686
706
  continue;
687
- // istanbul ignore else
688
- if (isUUID(tab.id))
689
- continue;
690
707
  draft.tabs[tab.id] = {
691
708
  id: tab.id,
692
709
  preferredFloatingWidgetSize: tab.preferredFloatingWidgetSize,
693
- preferredPopoutWidgetSize: tab.preferredPopoutWidgetSize,
694
710
  allowedPanelTargets: tab.allowedPanelTargets,
695
711
  userSized: tab.userSized,
696
712
  };
697
713
  }
698
714
  });
699
- packed = produce(packed, (draft) => {
700
- for (const [, floatingWidget] of Object.entries(state.floatingWidgets.byId)) {
701
- const widgetId = floatingWidget.id;
702
- // istanbul ignore else
703
- if (isUUID(widgetId)) {
704
- const idIndex = draft.floatingWidgets.allIds.indexOf(widgetId);
705
- draft.floatingWidgets.allIds.splice(idIndex, 1);
706
- delete draft.floatingWidgets.byId[widgetId];
707
- delete draft.widgets[widgetId];
715
+ return packed;
716
+ }
717
+ // TODO: clean-up of saved widgets.
718
+ // istanbul ignore next
719
+ function packSavedWidgets(savedWidgets, frontstageDef) {
720
+ for (const widgetDef of frontstageDef.widgetDefs) {
721
+ const id = widgetDef.id;
722
+ const initialWidget = {
723
+ id,
724
+ };
725
+ const widget = produce(initialWidget, (draft) => {
726
+ if (widgetDef.tabLocation) {
727
+ draft.tabLocation = { ...widgetDef.tabLocation };
728
+ }
729
+ if (widgetDef.popoutBounds) {
730
+ draft.popoutBounds = widgetDef.popoutBounds.toProps();
708
731
  }
732
+ });
733
+ if (widget === initialWidget)
734
+ continue;
735
+ savedWidgets = produce(savedWidgets, (draft) => {
736
+ draft.push(widget);
737
+ });
738
+ }
739
+ return savedWidgets;
740
+ }
741
+ // istanbul ignore next
742
+ function restoreSavedWidgets(savedWidgets, frontstage) {
743
+ let i = savedWidgets.length;
744
+ while (i--) {
745
+ const savedWidget = savedWidgets[i];
746
+ const widgetId = savedWidget.id;
747
+ const widgetDef = frontstage.findWidgetDef(widgetId);
748
+ if (!widgetDef)
749
+ continue;
750
+ if (savedWidget.tabLocation) {
751
+ widgetDef.tabLocation = { ...savedWidget.tabLocation };
709
752
  }
710
- });
711
- return packed;
753
+ if (savedWidget.popoutBounds) {
754
+ widgetDef.popoutBounds = Rectangle.create(savedWidget.popoutBounds);
755
+ }
756
+ savedWidgets = produce(savedWidgets, (draft) => {
757
+ draft.splice(i, 1);
758
+ });
759
+ }
760
+ return savedWidgets;
712
761
  }
713
762
  /** @internal */
714
763
  export function isPanelCollapsed(zoneStates, panelStates) {
@@ -716,121 +765,127 @@ export function isPanelCollapsed(zoneStates, panelStates) {
716
765
  const openPanel = panelStates.find((panelState) => panelState === StagePanelState.Open);
717
766
  return !openZone && !openPanel;
718
767
  }
719
- function addRemovedTab(nineZone, widgetDef) {
720
- var _a, _b;
721
- const newTab = createTabState(widgetDef.id, {
722
- label: getWidgetLabel(widgetDef.label),
723
- canPopout: widgetDef.canPopout,
724
- iconSpec: widgetDef.iconSpec,
725
- preferredPanelWidgetSize: widgetDef.preferredPanelSize,
726
- isFloatingStateWindowResizable: widgetDef.isFloatingStateWindowResizable,
727
- hideWithUiWhenFloating: !!widgetDef.hideWithUiWhenFloating,
728
- });
729
- nineZone.tabs[newTab.id] = newTab;
730
- if (widgetDef.tabLocation.widgetId in nineZone.widgets) {
731
- // Add to existing widget (by widget id).
732
- const widgetId = widgetDef.tabLocation.widgetId;
733
- const newTabWidget = nineZone.widgets[widgetId];
734
- newTabWidget.tabs.splice(widgetDef.tabLocation.tabIndex, 0, newTab.id);
768
+ function addHiddenWidget(state, widgetDef) {
769
+ const tabLocation = widgetDef.tabLocation || widgetDef.defaultTabLocation;
770
+ const tabId = widgetDef.id;
771
+ const { widgetId, tabIndex } = tabLocation;
772
+ if (widgetId in state.widgets) {
773
+ // Add to an existing widget (by widget id).
774
+ return insertTabToWidget(state, tabId, widgetId, tabIndex);
735
775
  }
736
- else if (widgetDef.tabLocation.floating) {
737
- const id = widgetDef.tabLocation.widgetId;
738
- if (id in nineZone.floatingWidgets.byId) {
739
- nineZone.floatingWidgets.allIds.push(id);
740
- nineZone.floatingWidgets.byId[id].hidden = false;
741
- addWidgetTabToDraftFloatingPanel(nineZone, (_a = widgetDef.floatingContainerId) !== null && _a !== void 0 ? _a : widgetDef.id, widgetDef.id, nineZone.floatingWidgets.byId[id].home, newTab);
742
- }
743
- else {
744
- const home = { side: widgetDef.tabLocation.side, widgetId: widgetDef.floatingContainerId, widgetIndex: 0 };
745
- addWidgetTabToDraftFloatingPanel(nineZone, (_b = widgetDef.floatingContainerId) !== null && _b !== void 0 ? _b : widgetDef.id, widgetDef.id, home, newTab);
746
- }
776
+ else if (tabLocation.floatingWidget) {
777
+ const floatingWidget = tabLocation.floatingWidget;
778
+ assert(widgetId === floatingWidget.id);
779
+ // Add to a new floating widget.
780
+ const nzBounds = Rectangle.createFromSize(state.size);
781
+ const bounds = Rectangle.create(floatingWidget.bounds).containIn(nzBounds);
782
+ return addFloatingWidget(state, floatingWidget.id, [tabId], {
783
+ ...floatingWidget,
784
+ bounds: bounds.toProps(),
785
+ });
747
786
  }
748
- else {
749
- const newTabPanel = nineZone.panels[widgetDef.tabLocation.side];
750
- if (newTabPanel.maxWidgetCount === newTabPanel.widgets.length) {
751
- // Add to existing panel widget.
752
- const widgetIndex = Math.min(newTabPanel.maxWidgetCount - 1, widgetDef.tabLocation.widgetIndex);
753
- const newTabWidgetId = newTabPanel.widgets[widgetIndex];
754
- const newTabWidget = nineZone.widgets[newTabWidgetId];
755
- newTabWidget.tabs.splice(widgetDef.tabLocation.tabIndex, 0, newTab.id);
756
- }
757
- else {
758
- // Create a new panel widget.
759
- const newWidget = createWidgetState(getUniqueId(), [newTab.id]);
760
- nineZone.widgets[newWidget.id] = castDraft(newWidget);
761
- newTabPanel.widgets.splice(widgetDef.tabLocation.widgetIndex, 0, newWidget.id);
762
- }
787
+ // Add to a panel section.
788
+ const panel = state.panels[tabLocation.side];
789
+ // Add to existing panel section.
790
+ if (panel.widgets.length >= panel.maxWidgetCount) {
791
+ const sectionIndex = Math.min(panel.maxWidgetCount - 1, tabLocation.widgetIndex);
792
+ const sectionId = panel.widgets[sectionIndex];
793
+ return insertTabToWidget(state, tabId, sectionId, tabLocation.tabIndex);
763
794
  }
795
+ // Create a new panel section.
796
+ const newSectionId = getUniqueId();
797
+ return insertPanelWidget(state, panel.side, newSectionId, [tabId], tabLocation.widgetIndex);
764
798
  }
765
799
  /** @internal */
766
- export const setWidgetState = produce((nineZone, widgetDef, state) => {
800
+ export function setWidgetState(state, widgetDef, widgetState) {
767
801
  var _a, _b;
768
- if (state === WidgetState.Open) {
802
+ if (widgetState === WidgetState.Hidden) {
803
+ return hideWidget(state, widgetDef);
804
+ }
805
+ else if (widgetState === WidgetState.Open) {
769
806
  const id = widgetDef.id;
770
- let location = findTab(nineZone, id);
807
+ let location = getTabLocation(state, id);
771
808
  if (!location) {
772
- addRemovedTab(nineZone, widgetDef);
773
- location = findTab(nineZone, id);
774
- assert(!!location);
775
- }
776
- if (!!widgetDef.tabLocation.floating) {
777
- nineZone.floatingWidgets.byId[(_a = widgetDef.floatingContainerId) !== null && _a !== void 0 ? _a : widgetDef.id].hidden = false;
809
+ state = addHiddenWidget(state, widgetDef);
810
+ location = getTabLocation(state, id);
778
811
  }
779
- const widget = nineZone.widgets[location.widgetId];
780
- widget.minimized = false;
781
- widget.activeTabId = id;
782
- // ensure panel containing widget is not collapsed
783
- // istanbul ignore else
784
- if ("side" in location) {
785
- const panel = nineZone.panels[location.side];
786
- panel.collapsed && (panel.collapsed = false);
787
- // istanbul ignore next
788
- if (undefined === panel.size || 0 === panel.size) {
789
- panel.size = (_b = panel.minSize) !== null && _b !== void 0 ? _b : 200;
812
+ return produce(state, (draft) => {
813
+ var _a;
814
+ assert(!!location);
815
+ const widget = draft.widgets[location.widgetId];
816
+ widget.minimized = false;
817
+ widget.activeTabId = id;
818
+ if (isFloatingTabLocation(location)) {
819
+ const floatingWidget = draft.floatingWidgets.byId[location.floatingWidgetId];
820
+ floatingWidget.hidden = false;
821
+ // istanbul ignore else
790
822
  }
791
- }
823
+ else if (isPanelTabLocation(location)) {
824
+ const panel = draft.panels[location.side];
825
+ panel.collapsed = false;
826
+ if (undefined === panel.size || 0 === panel.size) {
827
+ // istanbul ignore next
828
+ panel.size = (_a = panel.minSize) !== null && _a !== void 0 ? _a : 200;
829
+ }
830
+ }
831
+ });
792
832
  }
793
- else if (state === WidgetState.Closed) {
833
+ else if (widgetState === WidgetState.Closed) {
794
834
  const id = widgetDef.id;
795
- let location = findTab(nineZone, id);
835
+ let location = getTabLocation(state, id);
796
836
  if (!location) {
797
- addRemovedTab(nineZone, widgetDef);
798
- location = findTab(nineZone, id);
799
- assert(!!location);
800
- }
801
- if (isFloatingLocation(location)) {
802
- const widget = nineZone.widgets[location.widgetId];
803
- if (id !== widget.activeTabId)
804
- return;
805
- widget.minimized = true;
837
+ state = addHiddenWidget(state, widgetDef);
838
+ location = getTabLocation(state, id);
806
839
  }
840
+ // TODO: should change activeTabId of a widget with multiple tabs.
841
+ return produce(state, (draft) => {
842
+ assert(!!location);
843
+ const widget = draft.widgets[location.widgetId];
844
+ if (isFloatingTabLocation(location)) {
845
+ if (id === widget.activeTabId) {
846
+ widget.minimized = true;
847
+ }
848
+ }
849
+ });
807
850
  }
808
- else if (state === WidgetState.Hidden) {
809
- hideWidget(nineZone, widgetDef);
851
+ else if (widgetState === WidgetState.Floating) {
852
+ const id = widgetDef.id;
853
+ let location = getTabLocation(state, id);
854
+ if (!location) {
855
+ state = addHiddenWidget(state, widgetDef);
856
+ location = getTabLocation(state, id);
857
+ }
858
+ assert(!!location);
859
+ if (isFloatingTabLocation(location))
860
+ return state;
861
+ // Widget is not floating.
862
+ state = removeTabFromWidget(state, id);
863
+ const bounds = (_b = (_a = widgetDef.tabLocation) === null || _a === void 0 ? void 0 : _a.floatingWidget) === null || _b === void 0 ? void 0 : _b.bounds;
864
+ state = addFloatingWidget(state, getUniqueId(), [id], { bounds });
810
865
  }
811
- });
866
+ return state;
867
+ }
812
868
  /** Stores widget location and hides it in the UI. */
813
869
  function hideWidget(state, widgetDef) {
814
- const location = findTab(state, widgetDef.id);
870
+ const location = getTabLocation(state, widgetDef.id);
815
871
  if (!location)
816
- return;
817
- if (isFloatingLocation(location)) {
818
- const widget = state.floatingWidgets.byId[location.widgetId];
872
+ return state;
873
+ // istanbul ignore else
874
+ if (isFloatingTabLocation(location)) {
875
+ const floatingWidget = state.floatingWidgets.byId[location.widgetId];
819
876
  widgetDef.setFloatingContainerId(location.floatingWidgetId);
820
877
  widgetDef.tabLocation = {
821
- side: widget.home.side,
822
- tabIndex: widget.home.widgetIndex,
823
- widgetId: widgetDef.id,
824
- widgetIndex: widget.home.widgetIndex,
825
- floating: true,
878
+ side: floatingWidget.home.side,
879
+ tabIndex: floatingWidget.home.widgetIndex,
880
+ widgetId: floatingWidget.id,
881
+ widgetIndex: floatingWidget.home.widgetIndex,
882
+ floatingWidget,
826
883
  };
827
884
  }
828
- else
829
- // istanbul ignore else
830
- if (!isPopoutLocation(location)) {
885
+ else if (!isPopoutTabLocation(location)) {
831
886
  const widgetId = location.widgetId;
832
- const side = "side" in location ? location.side : "left";
833
- const widgetIndex = "side" in location ? state.panels[side].widgets.indexOf(widgetId) : 0;
887
+ const side = isPanelTabLocation(location) ? location.side : "left";
888
+ const widgetIndex = isPanelTabLocation(location) ? state.panels[side].widgets.indexOf(widgetId) : 0;
834
889
  const tabIndex = state.widgets[location.widgetId].tabs.indexOf(widgetDef.id);
835
890
  widgetDef.tabLocation = {
836
891
  side,
@@ -839,50 +894,53 @@ function hideWidget(state, widgetDef) {
839
894
  widgetIndex,
840
895
  };
841
896
  }
842
- removeTab(state, widgetDef.id);
897
+ return removeTabFromWidget(state, widgetDef.id);
843
898
  }
844
899
  /** @internal */
845
- export const showWidget = produce((nineZone, id) => {
846
- const location = findTab(nineZone, id);
900
+ export function showWidget(state, id) {
901
+ const location = getTabLocation(state, id);
847
902
  if (!location)
848
- return;
849
- const widget = nineZone.widgets[location.widgetId];
850
- if ("side" in location) {
851
- const panel = nineZone.panels[location.side];
852
- panel.collapsed = false;
853
- widget.minimized = false;
903
+ return state;
904
+ state = produce(state, (draft) => {
905
+ const widget = draft.widgets[location.widgetId];
854
906
  widget.activeTabId = id;
855
- return;
907
+ widget.minimized = false;
908
+ if (isPanelTabLocation(location)) {
909
+ const panel = draft.panels[location.side];
910
+ panel.collapsed = false;
911
+ }
912
+ });
913
+ if (isFloatingTabLocation(location)) {
914
+ state = floatingWidgetBringToFront(state, location.floatingWidgetId);
856
915
  }
857
- widget.activeTabId = id;
858
- widget.minimized = false;
859
- isFloatingLocation(location) && floatingWidgetBringToFront(nineZone, location.floatingWidgetId);
860
- });
916
+ return state;
917
+ }
861
918
  /** @internal */
862
- export const expandWidget = produce((nineZone, id) => {
863
- const location = findTab(nineZone, id);
919
+ export function expandWidget(state, id) {
920
+ const location = getTabLocation(state, id);
864
921
  if (!location)
865
- return;
866
- const widget = nineZone.widgets[location.widgetId];
867
- if ("side" in location) {
868
- const panel = nineZone.panels[location.side];
869
- panel.widgets.forEach((wId) => {
870
- const w = nineZone.widgets[wId];
871
- w.minimized = true;
872
- });
922
+ return state;
923
+ return produce(state, (draft) => {
924
+ const widget = draft.widgets[location.widgetId];
925
+ if (isPanelTabLocation(location)) {
926
+ const panel = draft.panels[location.side];
927
+ panel.widgets.forEach((wId) => {
928
+ const w = draft.widgets[wId];
929
+ w.minimized = true;
930
+ });
931
+ }
873
932
  widget.minimized = false;
874
- return;
875
- }
876
- widget.minimized = false;
877
- return;
878
- });
933
+ });
934
+ }
879
935
  /** @internal */
880
- export const setWidgetLabel = produce((nineZone, id, label) => {
881
- if (!(id in nineZone.tabs))
882
- return;
883
- const tab = nineZone.tabs[id];
884
- tab.label = label;
885
- });
936
+ export function setWidgetLabel(state, id, label) {
937
+ if (!(id in state.tabs))
938
+ return state;
939
+ return produce(state, (draft) => {
940
+ const tab = draft.tabs[id];
941
+ tab.label = label;
942
+ });
943
+ }
886
944
  /** @internal */
887
945
  export function useSavedFrontstageState(frontstageDef) {
888
946
  const uiStateStorage = useUiStateStorageHandler();
@@ -903,20 +961,23 @@ export function useSavedFrontstageState(frontstageDef) {
903
961
  }
904
962
  const id = frontstageDef.id;
905
963
  const version = frontstageDef.version;
906
- const settingsResult = await uiStateStorageRef.current.getSetting(FRONTSTAGE_SETTINGS_NAMESPACE, getFrontstageStateSettingName(id));
907
- if (isMountedRef.current) {
908
- if (isFrontstageStateSettingResult(settingsResult) &&
909
- settingsResult.setting.version >= version &&
910
- settingsResult.setting.stateVersion >= stateVersion) {
911
- const restored = restoreNineZoneState(frontstageDef, settingsResult.setting.nineZone);
964
+ const settingResult = await uiStateStorageRef.current.getSetting(FRONTSTAGE_SETTINGS_NAMESPACE, getFrontstageStateSettingName(id));
965
+ if (!isMountedRef.current)
966
+ return;
967
+ if (isFrontstageStateSettingResult(settingResult)) {
968
+ const setting = settingResult.setting;
969
+ if (setting.version >= version && setting.stateVersion >= stateVersion) {
970
+ const restored = restoreNineZoneState(frontstageDef, setting.nineZone);
971
+ const savedWidgets = restoreSavedWidgets(setting.widgets, frontstageDef);
912
972
  let state = addMissingWidgets(frontstageDef, restored);
913
- state = removeHiddenWidgets(state, frontstageDef);
973
+ state = hideWidgets(state, frontstageDef);
914
974
  state = processPopoutWidgets(state, frontstageDef);
915
975
  frontstageDef.nineZoneState = state;
976
+ frontstageDef.savedWidgetDefs = savedWidgets;
916
977
  return;
917
978
  }
918
- frontstageDef.nineZoneState = initializeNineZoneState(frontstageDef);
919
979
  }
980
+ frontstageDef.nineZoneState = initializeNineZoneState(frontstageDef);
920
981
  }
921
982
  fetchFrontstageState(); // eslint-disable-line @typescript-eslint/no-floating-promises
922
983
  }, [frontstageDef]);
@@ -925,16 +986,19 @@ export function useSavedFrontstageState(frontstageDef) {
925
986
  export function useSaveFrontstageSettings(frontstageDef) {
926
987
  const nineZone = useNineZoneState(frontstageDef);
927
988
  const uiSettingsStorage = useUiStateStorageHandler();
928
- // eslint-disable-next-line react-hooks/exhaustive-deps
929
- const saveSetting = React.useCallback(debounce(async (id, version, state) => {
930
- const setting = {
931
- id,
932
- nineZone: packNineZoneState(state),
933
- stateVersion,
934
- version,
935
- };
936
- await uiSettingsStorage.saveSetting(FRONTSTAGE_SETTINGS_NAMESPACE, getFrontstageStateSettingName(id), setting);
937
- }, 1000), [uiSettingsStorage]);
989
+ const saveSetting = React.useMemo(() => {
990
+ return debounce(async (frontstage, state, savedWidgets) => {
991
+ const id = frontstage.id;
992
+ const setting = {
993
+ id,
994
+ version: frontstage.version,
995
+ stateVersion,
996
+ nineZone: packNineZoneState(state),
997
+ widgets: packSavedWidgets(savedWidgets, frontstage),
998
+ };
999
+ await uiSettingsStorage.saveSetting(FRONTSTAGE_SETTINGS_NAMESPACE, getFrontstageStateSettingName(id), setting);
1000
+ }, 1000);
1001
+ }, [uiSettingsStorage]);
938
1002
  React.useEffect(() => {
939
1003
  return () => {
940
1004
  saveSetting.cancel();
@@ -943,7 +1007,8 @@ export function useSaveFrontstageSettings(frontstageDef) {
943
1007
  React.useEffect(() => {
944
1008
  if (!nineZone || nineZone.draggedTab)
945
1009
  return;
946
- saveSetting(frontstageDef.id, frontstageDef.version, nineZone);
1010
+ const savedWidgets = frontstageDef.savedWidgetDefs || [];
1011
+ saveSetting(frontstageDef, nineZone, savedWidgets);
947
1012
  }, [frontstageDef, nineZone, saveSetting]);
948
1013
  }
949
1014
  /** @internal */
@@ -1077,7 +1142,7 @@ export function useItemsManager(frontstageDef) {
1077
1142
  return;
1078
1143
  state = addMissingWidgets(def, state);
1079
1144
  state = removeMissingWidgets(def, state);
1080
- state = removeHiddenWidgets(state, def); // TODO: should only apply to widgets provided by registered provider in onUiProviderRegisteredEvent.
1145
+ state = hideWidgets(state, def); // TODO: should only apply to widgets provided by registered provider in onUiProviderRegisteredEvent.
1081
1146
  def.nineZoneState = state;
1082
1147
  };
1083
1148
  React.useEffect(() => {
@@ -1090,47 +1155,8 @@ export function useItemsManager(frontstageDef) {
1090
1155
  return remove;
1091
1156
  }, [frontstageDef]);
1092
1157
  }
1093
- function tabShownInCurrentWidget(def, state) {
1094
- for (const [, widget] of Object.entries(state.widgets)) {
1095
- const foundTab = widget.tabs.find((tabId) => tabId === def.id);
1096
- // istanbul ignore else
1097
- if (foundTab)
1098
- return true;
1099
- }
1100
- return false;
1101
- }
1102
1158
  // istanbul ignore next
1103
1159
  function determineNewWidgets(defs, state) {
1104
- // if tab for widget.id is not found or the label does not match widget label (label is set to "undefined" when widgetDef is not initially available)
1105
- return (defs || []).filter((def) => !(def.id in state.tabs) || !tabShownInCurrentWidget(def, state));
1106
- }
1107
- /** @internal */
1108
- export async function saveFrontstagePopoutWidgetSizeAndPosition(state, stageId, stageVersion, childWindowId, childWindow) {
1109
- const location = findWidget(state, childWindowId);
1110
- // istanbul ignore else
1111
- if (location) {
1112
- const adjustmentWidth = ProcessDetector.isElectronAppFrontend ? 16 : 0;
1113
- const adjustmentHeight = ProcessDetector.isElectronAppFrontend ? 39 : 0;
1114
- const newState = produce(state, (draft) => {
1115
- const widget = draft.widgets[childWindowId];
1116
- const tab = draft.tabs[widget.activeTabId];
1117
- tab.preferredPopoutWidgetSize = {
1118
- x: childWindow.screenX,
1119
- y: childWindow.screenY,
1120
- width: childWindow.innerWidth + adjustmentWidth,
1121
- height: childWindow.innerHeight + adjustmentHeight,
1122
- };
1123
- });
1124
- const setting = {
1125
- id: stageId,
1126
- nineZone: packNineZoneState(newState),
1127
- stateVersion,
1128
- version: stageVersion,
1129
- };
1130
- await UiFramework.getUiStateStorage().saveSetting(FRONTSTAGE_SETTINGS_NAMESPACE, getFrontstageStateSettingName(stageId), setting);
1131
- return newState;
1132
- }
1133
- // istanbul ignore next
1134
- return state;
1160
+ return (defs || []).filter((def) => !(def.id in state.tabs));
1135
1161
  }
1136
1162
  //# sourceMappingURL=Frontstage.js.map