@eclipse-docks/core 0.7.127 → 0.7.132

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 (136) hide show
  1. package/dist/api/index.js +7 -7
  2. package/dist/api/services.d.ts +3 -1
  3. package/dist/api/services.d.ts.map +1 -1
  4. package/dist/{api-Da9zQcfd.js → api-DImisUWV.js} +296 -305
  5. package/dist/api-DImisUWV.js.map +1 -0
  6. package/dist/assets/{js-runtime-worker-DAva_aXx.js.map → js-runtime-worker-X93bOre4.js.map} +1 -1
  7. package/dist/components/attribution.d.ts +1 -0
  8. package/dist/components/attribution.d.ts.map +1 -1
  9. package/dist/components/command.d.ts +0 -1
  10. package/dist/components/command.d.ts.map +1 -1
  11. package/dist/components/extensions.d.ts +3 -0
  12. package/dist/components/extensions.d.ts.map +1 -1
  13. package/dist/components/language-selector.d.ts.map +1 -1
  14. package/dist/components/layout-switcher.d.ts +1 -1
  15. package/dist/components/layout-switcher.d.ts.map +1 -1
  16. package/dist/components/npm-packages.d.ts +1 -0
  17. package/dist/components/npm-packages.d.ts.map +1 -1
  18. package/dist/components/release-history.d.ts +9 -2
  19. package/dist/components/release-history.d.ts.map +1 -1
  20. package/dist/components/tasks.d.ts.map +1 -1
  21. package/dist/core/apploader.d.ts +2 -9
  22. package/dist/core/apploader.d.ts.map +1 -1
  23. package/dist/core/contribution-targets.d.ts +1 -0
  24. package/dist/core/contribution-targets.d.ts.map +1 -1
  25. package/dist/core/dialogservice.d.ts +3 -1
  26. package/dist/core/dialogservice.d.ts.map +1 -1
  27. package/dist/core/dropdown-item.d.ts +8 -0
  28. package/dist/core/dropdown-item.d.ts.map +1 -1
  29. package/dist/core/events.js +1 -1
  30. package/dist/core/layout-panels.d.ts +25 -0
  31. package/dist/core/layout-panels.d.ts.map +1 -0
  32. package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -1
  33. package/dist/dialogs/version-info-dialog.d.ts +18 -2
  34. package/dist/dialogs/version-info-dialog.d.ts.map +1 -1
  35. package/dist/{events-B_ZxkU_G.js → events-BAE5R6TH.js} +1 -1
  36. package/dist/{events-B_ZxkU_G.js.map → events-BAE5R6TH.js.map} +1 -1
  37. package/dist/{extensions.de-Ct1DIybE.js → extensions.de-O6Sx3_t4.js} +1 -1
  38. package/dist/{extensions.de-Ct1DIybE.js.map → extensions.de-O6Sx3_t4.js.map} +1 -1
  39. package/dist/{extensions.en-DRPFtVHT.js → extensions.en-fwqJr8P-.js} +1 -1
  40. package/dist/{extensions.en-DRPFtVHT.js.map → extensions.en-fwqJr8P-.js.map} +1 -1
  41. package/dist/externals/lit.js +1 -1
  42. package/dist/externals/third-party.js.map +1 -1
  43. package/dist/externals/webawesome.js +1 -1
  44. package/dist/{fastviews.de-BFxFslBz.js → fastviews.de-C-B48vwv.js} +1 -1
  45. package/dist/fastviews.de-C-B48vwv.js.map +1 -0
  46. package/dist/{fastviews.en-Cb4J_JXL.js → fastviews.en-BlAxYlHD.js} +1 -1
  47. package/dist/fastviews.en-BlAxYlHD.js.map +1 -0
  48. package/dist/{filebrowser.de-GEf6Eilh.js → filebrowser.de-LWsrI9xj.js} +1 -1
  49. package/dist/{filebrowser.de-GEf6Eilh.js.map → filebrowser.de-LWsrI9xj.js.map} +1 -1
  50. package/dist/{filebrowser.en-o0Ad5f7Z.js → filebrowser.en-C02vpzAs.js} +1 -1
  51. package/dist/{filebrowser.en-o0Ad5f7Z.js.map → filebrowser.en-C02vpzAs.js.map} +1 -1
  52. package/dist/{fs-access-DTXPsV1W.js → fs-access-Cjcg0_Me.js} +27 -25
  53. package/dist/{fs-access-DTXPsV1W.js.map → fs-access-Cjcg0_Me.js.map} +1 -1
  54. package/dist/fs-access-Dp9Fwsxk.js +2 -0
  55. package/dist/index.js +7 -7
  56. package/dist/layouts/standard-layout.d.ts +9 -1
  57. package/dist/layouts/standard-layout.d.ts.map +1 -1
  58. package/dist/{logger-DT0_NW3S.js → logger-CiT0Cc4g.js} +1 -1
  59. package/dist/{logger-DT0_NW3S.js.map → logger-CiT0Cc4g.js.map} +1 -1
  60. package/dist/{logterminal.de-DKp940Ox.js → logterminal.de-BP1FuxHH.js} +1 -1
  61. package/dist/{logterminal.de-DKp940Ox.js.map → logterminal.de-BP1FuxHH.js.map} +1 -1
  62. package/dist/{logterminal.en-Ci2nm0b2.js → logterminal.en-BeDRvTvb.js} +1 -1
  63. package/dist/{logterminal.en-Ci2nm0b2.js.map → logterminal.en-BeDRvTvb.js.map} +1 -1
  64. package/dist/{partname.de-v76uEl0F.js → partname.de-C0I4Wf2X.js} +1 -1
  65. package/dist/{partname.de-v76uEl0F.js.map → partname.de-C0I4Wf2X.js.map} +1 -1
  66. package/dist/{partname.en-By5aAawT.js → partname.en-CIT8z3cY.js} +1 -1
  67. package/dist/{partname.en-By5aAawT.js.map → partname.en-CIT8z3cY.js.map} +1 -1
  68. package/dist/parts/contextmenu.d.ts.map +1 -1
  69. package/dist/parts/index.js +1 -1
  70. package/dist/parts/part.d.ts +2 -0
  71. package/dist/parts/part.d.ts.map +1 -1
  72. package/dist/parts/resizable-grid.d.ts +10 -3
  73. package/dist/parts/resizable-grid.d.ts.map +1 -1
  74. package/dist/parts/tabs.d.ts +6 -0
  75. package/dist/parts/tabs.d.ts.map +1 -1
  76. package/dist/{parts-CRVxaDd-.js → parts-DQRktiiR.js} +1086 -611
  77. package/dist/parts-DQRktiiR.js.map +1 -0
  78. package/dist/{tasks.de-y2xPmQ1k.js → tasks.de-DRvUVugd.js} +1 -1
  79. package/dist/{tasks.de-y2xPmQ1k.js.map → tasks.de-DRvUVugd.js.map} +1 -1
  80. package/dist/{tasks.en-BTbFrxJj.js → tasks.en-dRDildBd.js} +1 -1
  81. package/dist/{tasks.en-BTbFrxJj.js.map → tasks.en-dRDildBd.js.map} +1 -1
  82. package/dist/vite-plugin-app-splash.js.map +1 -1
  83. package/dist/vite-plugin-local-aliases.js +1 -1
  84. package/dist/vite-plugin-local-aliases.js.map +1 -1
  85. package/dist/vite-plugin-resolve-deps.d.ts +6 -3
  86. package/dist/vite-plugin-resolve-deps.d.ts.map +1 -1
  87. package/dist/vite-plugin-resolve-deps.js +17 -15
  88. package/dist/vite-plugin-resolve-deps.js.map +1 -1
  89. package/dist/{webawesome-Y1_HnKa_.js → webawesome-C0Da7hPu.js} +19 -11
  90. package/dist/webawesome-C0Da7hPu.js.map +1 -0
  91. package/dist/{widget-BqQtioK1.js → widget-DUR6wxME.js} +6 -5
  92. package/dist/{widget-BqQtioK1.js.map → widget-DUR6wxME.js.map} +1 -1
  93. package/dist/widgets/index.js +1 -1
  94. package/dist/{widgets-C9V42Mqq.js → widgets-A9XMOA_j.js} +2 -2
  95. package/dist/{widgets-C9V42Mqq.js.map → widgets-A9XMOA_j.js.map} +1 -1
  96. package/package.json +1 -1
  97. package/src/api/services.ts +12 -0
  98. package/src/components/attribution.ts +2 -0
  99. package/src/components/command.ts +2 -8
  100. package/src/components/extensions.ts +20 -3
  101. package/src/components/language-selector.ts +0 -1
  102. package/src/components/layout-switcher.ts +39 -26
  103. package/src/components/npm-packages.ts +2 -0
  104. package/src/components/release-history.ts +29 -40
  105. package/src/components/tasks.ts +0 -1
  106. package/src/contributions/default-layout-contributions.ts +7 -43
  107. package/src/contributions/default-ui-contributions.ts +4 -4
  108. package/src/core/apploader.ts +7 -54
  109. package/src/core/contribution-targets.ts +1 -0
  110. package/src/core/dialogservice.ts +76 -19
  111. package/src/core/dropdown-item.ts +52 -17
  112. package/src/core/extensionregistry.ts +1 -1
  113. package/src/core/layout-panels.ts +121 -0
  114. package/src/dialogs/navigable-info-dialog.ts +5 -2
  115. package/src/dialogs/version-info-dialog.ts +163 -21
  116. package/src/icons/icons.txt +4 -2
  117. package/src/icons/layout-standard-bottom-panel.svg +4 -4
  118. package/src/icons/layout-standard-full.svg +4 -4
  119. package/src/icons/layout-standard-left-aux.svg +8 -0
  120. package/src/icons/layout-standard-left-sidebar.svg +5 -0
  121. package/src/icons/layout-standard-right-aux.svg +8 -0
  122. package/src/icons/layout-standard-right-sidebar.svg +5 -0
  123. package/src/layouts/standard-layout.ts +81 -5
  124. package/src/parts/contextmenu.ts +2 -1
  125. package/src/parts/part.ts +24 -0
  126. package/src/parts/resizable-grid.ts +125 -57
  127. package/src/parts/tabs.ts +103 -0
  128. package/src/vite-plugin-resolve-deps.ts +29 -25
  129. package/dist/api-Da9zQcfd.js.map +0 -1
  130. package/dist/fastviews.de-BFxFslBz.js.map +0 -1
  131. package/dist/fastviews.en-Cb4J_JXL.js.map +0 -1
  132. package/dist/fs-access-CzOh5ot8.js +0 -2
  133. package/dist/parts-CRVxaDd-.js.map +0 -1
  134. package/dist/webawesome-Y1_HnKa_.js.map +0 -1
  135. package/src/icons/layout-standard-bottom-sidebar.svg +0 -6
  136. package/src/icons/layout-standard.svg +0 -6
@@ -1,19 +1,19 @@
1
- import { n as defaultLogger, o as rootContext, s as uiContext, t as createLogger } from "./logger-DT0_NW3S.js";
2
- import { T as toastInfo, _ as getContributionDisabled, a as TOPIC_COMMAND_REGISTERED, f as activeTasksSignal, g as contributionRegistry, h as TOPIC_CONTRIBUTEIONS_CHANGED, l as activeEditorSignal, n as watchSignal, o as commandRegistry, p as partDirtySignal, t as DocksWidget, u as activePartSignal, v as getContributionVisible, w as toastError, x as contributionTargetMappingRegistry, y as readReactiveBoolean } from "./widget-BqQtioK1.js";
3
- import { n as subscribe, t as publish } from "./events-B_ZxkU_G.js";
4
- import { a as File, i as Directory, l as TOPIC_WORKSPACE_CHANGED, m as persistenceService, o as FileContentType, p as workspaceService } from "./fs-access-DTXPsV1W.js";
5
- import "./webawesome-Y1_HnKa_.js";
1
+ import { n as defaultLogger, o as rootContext, s as uiContext, t as createLogger } from "./logger-CiT0Cc4g.js";
2
+ import { T as toastInfo, _ as getContributionDisabled, a as TOPIC_COMMAND_REGISTERED, f as activeTasksSignal, g as contributionRegistry, h as TOPIC_CONTRIBUTEIONS_CHANGED, l as activeEditorSignal, n as watchSignal, o as commandRegistry, p as partDirtySignal, t as DocksWidget, u as activePartSignal, v as getContributionVisible, w as toastError, x as contributionTargetMappingRegistry, y as readReactiveBoolean } from "./widget-DUR6wxME.js";
3
+ import { n as subscribe, t as publish } from "./events-BAE5R6TH.js";
4
+ import { a as File, i as Directory, l as TOPIC_WORKSPACE_CHANGED, m as persistenceService, o as FileContentType, p as workspaceService } from "./fs-access-Cjcg0_Me.js";
5
+ import "./webawesome-C0Da7hPu.js";
6
6
  import { css, html, nothing, render } from "lit";
7
7
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
8
8
  import DOMPurify from "dompurify";
9
9
  import { marked } from "marked";
10
10
  import { customElement, property, state } from "lit/decorators.js";
11
11
  import _decorate from "@oxc-project/runtime/helpers/decorate";
12
+ import { ifDefined } from "lit/directives/if-defined.js";
12
13
  import { styleMap } from "lit/directives/style-map.js";
13
14
  import { createRef, ref } from "lit/directives/ref.js";
14
15
  import { when } from "lit/directives/when.js";
15
16
  import { repeat } from "lit/directives/repeat.js";
16
- import { ifDefined } from "lit/directives/if-defined.js";
17
17
  //#region \0rolldown/runtime.js
18
18
  var __defProp = Object.defineProperty;
19
19
  var __exportAll = (all, no_symbols) => {
@@ -45,6 +45,7 @@ var EDITOR_AREA_MAIN = "editor-area-main";
45
45
  var SIDEBAR_MAIN = "sidebar-main";
46
46
  var SIDEBAR_MAIN_BOTTOM = "sidebar-main-bottom";
47
47
  var SIDEBAR_AUXILIARY = "sidebar-auxiliary";
48
+ var SIDEBAR_AUXILIARY_BOTTOM = "sidebar-auxiliary-bottom";
48
49
  var PANEL_BOTTOM = "panel-bottom";
49
50
  //#endregion
50
51
  //#region src/core/constants.ts
@@ -56,6 +57,7 @@ var constants_exports = /* @__PURE__ */ __exportAll({
56
57
  MouseButton: () => MouseButton,
57
58
  PANEL_BOTTOM: () => PANEL_BOTTOM,
58
59
  SIDEBAR_AUXILIARY: () => SIDEBAR_AUXILIARY,
60
+ SIDEBAR_AUXILIARY_BOTTOM: () => SIDEBAR_AUXILIARY_BOTTOM,
59
61
  SIDEBAR_MAIN: () => SIDEBAR_MAIN,
60
62
  SIDEBAR_MAIN_BOTTOM: () => SIDEBAR_MAIN_BOTTOM,
61
63
  SIDEBAR_MAIN_TOOLBAR: () => SIDEBAR_MAIN_TOOLBAR,
@@ -271,7 +273,7 @@ var taskService = new TaskService();
271
273
  rootContext.put("taskService", taskService);
272
274
  //#endregion
273
275
  //#region src/core/esmsh-service.ts
274
- var logger$3 = createLogger("EsmShService");
276
+ var logger$4 = createLogger("EsmShService");
275
277
  var esmShService = new class EsmShService {
276
278
  static {
277
279
  this.ESM_SH_BASE = "https://esm.sh";
@@ -416,7 +418,6 @@ var esmShService = new class EsmShService {
416
418
  case "pr":
417
419
  url += `/${EsmShService.PR_PREFIX}${source.owner}/${source.repo}`;
418
420
  if (source.commit) url += `@${source.commit}`;
419
- break;
420
421
  }
421
422
  const queryParams = [];
422
423
  if (options?.deps) {
@@ -435,7 +436,7 @@ var esmShService = new class EsmShService {
435
436
  if (this.isHttpUrl(source)) return source;
436
437
  const parsed = this.parseSource(source);
437
438
  if (!parsed) {
438
- logger$3.warn(`Could not parse source identifier: ${source}`);
439
+ logger$4.warn(`Could not parse source identifier: ${source}`);
439
440
  return source;
440
441
  }
441
442
  return this.buildEsmShUrl(parsed, options);
@@ -466,11 +467,13 @@ var esmShService = new class EsmShService {
466
467
  let repo = pathParts[1].replace(/\.git$/, "");
467
468
  let ref;
468
469
  let filePath;
469
- if (pathParts.length > 2) if (pathParts[2] === "blob" || pathParts[2] === "tree") {
470
- ref = pathParts[3] || "main";
471
- if (pathParts[2] === "blob" && pathParts.length > 4) filePath = pathParts.slice(4).join("/");
472
- } else if (pathParts[2] === "commit") ref = pathParts[3];
473
- else filePath = pathParts.slice(2).join("/");
470
+ if (pathParts.length > 2) {
471
+ if (pathParts[2] === "blob" || pathParts[2] === "tree") {
472
+ ref = pathParts[3] || "main";
473
+ if (pathParts[2] === "blob" && pathParts.length > 4) filePath = pathParts.slice(4).join("/");
474
+ } else if (pathParts[2] === "commit") ref = pathParts[3];
475
+ else filePath = pathParts.slice(2).join("/");
476
+ }
474
477
  let ghUrl = `${EsmShService.GITHUB_PREFIX}${owner}/${repo}`;
475
478
  if (ref) ghUrl += `@${ref}`;
476
479
  if (filePath) ghUrl += `/${filePath}`;
@@ -672,10 +675,7 @@ var ExtensionRegistry = class {
672
675
  async ensureExtensionRegistered(extensionId) {
673
676
  if (this.extensions[extensionId]) return;
674
677
  try {
675
- await import(
676
- /* @vite-ignore */
677
- extensionId
678
- );
678
+ await import(extensionId);
679
679
  } catch (error) {
680
680
  defaultLogger.debug(`Could not side-effect import extension package ${extensionId}: ${error}`);
681
681
  }
@@ -1074,13 +1074,16 @@ var DocksDialogContent = class extends DocksElement {
1074
1074
  dispose() {}
1075
1075
  getResult() {}
1076
1076
  renderMessage(message, markdown = false) {
1077
- if (markdown) return html`<div class="dialog-message" style="white-space: normal;">${unsafeHTML(parseMarkdownHtml(message))}</div>`;
1077
+ if (markdown) {
1078
+ const htmlContent = parseMarkdownHtml(message);
1079
+ return html`<div class="dialog-message" style="white-space: normal;">${unsafeHTML(htmlContent)}</div>`;
1080
+ }
1078
1081
  return html`<div class="dialog-message" style="white-space: pre-line;">${message}</div>`;
1079
1082
  }
1080
1083
  };
1081
1084
  //#endregion
1082
1085
  //#region src/core/dialogservice.ts
1083
- var logger$2 = createLogger("DialogService");
1086
+ var logger$3 = createLogger("DialogService");
1084
1087
  var DIALOG_CONTRIBUTION_TARGET = "dialogs";
1085
1088
  var OK_BUTTON = {
1086
1089
  id: "ok",
@@ -1106,6 +1109,20 @@ function getDialogContainer() {
1106
1109
  }
1107
1110
  return dialogContainer;
1108
1111
  }
1112
+ function findWaDialog(root) {
1113
+ if (root instanceof Element && root.tagName.toLowerCase() === "wa-dialog") return root;
1114
+ const children = root instanceof Document || root instanceof DocumentFragment || root instanceof Element ? Array.from(root.children) : root instanceof ShadowRoot ? Array.from(root.children) : [];
1115
+ for (const child of children) {
1116
+ if (child instanceof Element && child.tagName.toLowerCase() === "wa-dialog") return child;
1117
+ if (child instanceof Element && child.shadowRoot) {
1118
+ const nested = findWaDialog(child.shadowRoot);
1119
+ if (nested) return nested;
1120
+ }
1121
+ const nested = findWaDialog(child);
1122
+ if (nested) return nested;
1123
+ }
1124
+ return null;
1125
+ }
1109
1126
  var DialogService = class {
1110
1127
  constructor() {
1111
1128
  this.contributions = /* @__PURE__ */ new Map();
@@ -1126,15 +1143,15 @@ var DialogService = class {
1126
1143
  this.contributions.clear();
1127
1144
  for (const contribution of contributions) {
1128
1145
  if (!contribution.id) {
1129
- logger$2.warn("Dialog contribution missing id, skipping");
1146
+ logger$3.warn("Dialog contribution missing id, skipping");
1130
1147
  continue;
1131
1148
  }
1132
1149
  if (!contribution.component) {
1133
- logger$2.warn(`Dialog contribution "${contribution.id}" has no component function, skipping`);
1150
+ logger$3.warn(`Dialog contribution "${contribution.id}" has no component function, skipping`);
1134
1151
  continue;
1135
1152
  }
1136
- if (!contribution.onButton) {
1137
- logger$2.warn(`Dialog contribution "${contribution.id}" has no onButton callback, skipping`);
1153
+ if (!contribution.onButton && !contribution.selfContained) {
1154
+ logger$3.warn(`Dialog contribution "${contribution.id}" has no onButton callback, skipping`);
1138
1155
  continue;
1139
1156
  }
1140
1157
  this.contributions.set(contribution.id, contribution);
@@ -1143,50 +1160,68 @@ var DialogService = class {
1143
1160
  async open(dialogId, state) {
1144
1161
  const contribution = this.contributions.get(dialogId);
1145
1162
  if (!contribution) {
1146
- logger$2.error(`Dialog "${dialogId}" not found`);
1163
+ logger$3.error(`Dialog "${dialogId}" not found`);
1147
1164
  throw new Error(`Dialog "${dialogId}" not found`);
1148
1165
  }
1149
1166
  return new Promise((resolve) => {
1150
1167
  const container = getDialogContainer();
1151
- let isOpen = true;
1168
+ let closed = false;
1152
1169
  let dialogContentElement = null;
1153
1170
  const cleanup = async () => {
1154
- if (!isOpen) return;
1155
- isOpen = false;
1171
+ if (closed) return;
1172
+ closed = true;
1156
1173
  if (dialogContentElement) try {
1157
1174
  await dialogContentElement.dispose();
1158
1175
  } catch (error) {
1159
1176
  const errorMessage = error instanceof Error ? error.message : String(error);
1160
- logger$2.error(`Error disposing dialog content for "${dialogId}": ${errorMessage}`);
1177
+ logger$3.error(`Error disposing dialog content for "${dialogId}": ${errorMessage}`);
1161
1178
  }
1162
1179
  try {
1163
1180
  const result = dialogContentElement ? dialogContentElement.getResult() : void 0;
1164
- await contribution.onButton("close", result, stateWithClose);
1181
+ if (contribution.onButton) await contribution.onButton("close", result, stateWithClose);
1165
1182
  } catch (error) {
1166
1183
  const errorMessage = error instanceof Error ? error.message : String(error);
1167
- logger$2.error(`Error executing close callback for dialog "${dialogId}": ${errorMessage}`);
1184
+ logger$3.error(`Error executing close callback for dialog "${dialogId}": ${errorMessage}`);
1168
1185
  }
1169
1186
  render(html``, container);
1170
1187
  resolve();
1171
1188
  };
1189
+ const closeDialog = () => {
1190
+ if (closed) return;
1191
+ const dialog = findWaDialog(container);
1192
+ if (dialog && dialog.open !== false) {
1193
+ dialog.open = false;
1194
+ return;
1195
+ }
1196
+ cleanup();
1197
+ };
1198
+ const handleAfterHide = () => {
1199
+ cleanup();
1200
+ };
1172
1201
  const handleButtonClick = async (buttonId) => {
1202
+ if (!contribution.onButton) return;
1173
1203
  try {
1174
1204
  const result = dialogContentElement ? dialogContentElement.getResult() : void 0;
1175
- if (await contribution.onButton(buttonId, result, stateWithClose) !== false) cleanup();
1205
+ if (await contribution.onButton(buttonId, result, stateWithClose) !== false) closeDialog();
1176
1206
  } catch (error) {
1177
1207
  const errorMessage = error instanceof Error ? error.message : String(error);
1178
- logger$2.error(`Error executing button callback for dialog "${dialogId}": ${errorMessage}`);
1179
- cleanup();
1208
+ logger$3.error(`Error executing button callback for dialog "${dialogId}": ${errorMessage}`);
1209
+ closeDialog();
1180
1210
  }
1181
1211
  };
1182
1212
  const buttons = contribution.buttons && contribution.buttons.length > 0 ? contribution.buttons : [OK_BUTTON];
1183
- if (state && typeof state === "object") state.close = cleanup;
1184
1213
  const stateWithClose = {
1185
1214
  ...state,
1186
- close: cleanup
1215
+ close: closeDialog,
1216
+ onAfterHide: handleAfterHide
1187
1217
  };
1188
- render(html`
1189
- <wa-dialog label="${state && typeof state === "object" && typeof state.label === "string" ? state.label : contribution.label || dialogId}" open @wa-request-close=${cleanup}>
1218
+ if (state && typeof state === "object") {
1219
+ state.close = closeDialog;
1220
+ state.onAfterHide = handleAfterHide;
1221
+ }
1222
+ const dialogLabel = state && typeof state === "object" && typeof state.label === "string" ? state.label : contribution.label || dialogId;
1223
+ const template = contribution.selfContained ? contribution.component(stateWithClose) : html`
1224
+ <wa-dialog label="${dialogLabel}" open @wa-after-hide=${handleAfterHide}>
1190
1225
  <style>
1191
1226
  .dialog-service-content {
1192
1227
  display: flex;
@@ -1218,13 +1253,14 @@ var DialogService = class {
1218
1253
  @dialog-cancel=${() => {
1219
1254
  const cancelButton = buttons.find((b) => b.id === "cancel");
1220
1255
  if (cancelButton) handleButtonClick(cancelButton.id);
1221
- else cleanup();
1256
+ else closeDialog();
1222
1257
  }}>
1223
1258
  ${contribution.component(state)}
1224
1259
 
1225
1260
  <div class="dialog-service-footer">
1226
1261
  ${buttons.map((button) => html`
1227
1262
  <wa-button
1263
+ data-dialog-button="${button.id}"
1228
1264
  variant="${button.variant || "default"}"
1229
1265
  ?disabled=${button.disabled}
1230
1266
  @click=${() => handleButtonClick(button.id)}
@@ -1235,7 +1271,8 @@ var DialogService = class {
1235
1271
  </div>
1236
1272
  </div>
1237
1273
  </wa-dialog>
1238
- `, container);
1274
+ `;
1275
+ render(template, container);
1239
1276
  (async () => {
1240
1277
  const allElements = Array.from(container.querySelectorAll("*"));
1241
1278
  for (const element of allElements) if (element instanceof DocksDialogContent) {
@@ -1300,13 +1337,13 @@ workspaceService.registerContribution({
1300
1337
  },
1301
1338
  async connect(_input) {
1302
1339
  const root = await getOPFSRoot();
1303
- const FileSysDirHandleResource = (await import("./fs-access-CzOh5ot8.js")).FileSysDirHandleResource;
1340
+ const FileSysDirHandleResource = (await import("./fs-access-Dp9Fwsxk.js")).FileSysDirHandleResource;
1304
1341
  return new OPFSRootDirectory(new FileSysDirHandleResource(root));
1305
1342
  },
1306
1343
  async restore(data) {
1307
1344
  if (data && typeof data === "object" && data.opfs === true) {
1308
1345
  const root = await getOPFSRoot();
1309
- const FileSysDirHandleResource = (await import("./fs-access-CzOh5ot8.js")).FileSysDirHandleResource;
1346
+ const FileSysDirHandleResource = (await import("./fs-access-Dp9Fwsxk.js")).FileSysDirHandleResource;
1310
1347
  return new OPFSRootDirectory(new FileSysDirHandleResource(root));
1311
1348
  }
1312
1349
  },
@@ -1426,7 +1463,8 @@ async function idbRenameTree(rootId, oldPath, newPath) {
1426
1463
  }
1427
1464
  const key = String(cursor.key);
1428
1465
  if (key === oldPrefix || key.startsWith(oldPrefix + "/")) {
1429
- const newKey = newPrefix + key.slice(oldPrefix.length);
1466
+ const suffix = key.slice(oldPrefix.length);
1467
+ const newKey = newPrefix + suffix;
1430
1468
  const value = cursor.value;
1431
1469
  operations.push(() => {
1432
1470
  cursor.delete();
@@ -1465,9 +1503,10 @@ async function idbListChildrenOfDir(rootId, dirPath) {
1465
1503
  }
1466
1504
  const idx = rest.indexOf("/");
1467
1505
  const childName = idx === -1 ? rest : rest.slice(0, idx);
1468
- if (idx === -1) if (entry.type === "dir") dirNames.add(childName);
1469
- else fileEntries.set(childName, entry);
1470
- else dirNames.add(childName);
1506
+ if (idx === -1) {
1507
+ if (entry.type === "dir") dirNames.add(childName);
1508
+ else fileEntries.set(childName, entry);
1509
+ } else dirNames.add(childName);
1471
1510
  cursor.continue();
1472
1511
  };
1473
1512
  });
@@ -1747,7 +1786,7 @@ async function deleteIndexedDbWorkspaceData(directory) {
1747
1786
  }
1748
1787
  //#endregion
1749
1788
  //#region src/core/marketplaceregistry.ts
1750
- var logger$1 = createLogger("MarketplaceRegistry");
1789
+ var logger$2 = createLogger("MarketplaceRegistry");
1751
1790
  var TOPIC_MARKETPLACE_CHANGED = "events/marketplaceregistry/changed";
1752
1791
  var KEY_CATALOG_URLS = "marketplace.catalogUrls";
1753
1792
  var MarketplaceRegistry = class {
@@ -1756,7 +1795,7 @@ var MarketplaceRegistry = class {
1756
1795
  this.loadingPromises = /* @__PURE__ */ new Map();
1757
1796
  this.loadCatalogUrls().then(() => {
1758
1797
  this.refreshCatalogs().catch((err) => {
1759
- logger$1.error(`Failed to refresh catalogs on init: ${err.message}`);
1798
+ logger$2.error(`Failed to refresh catalogs on init: ${err.message}`);
1760
1799
  });
1761
1800
  });
1762
1801
  }
@@ -1765,7 +1804,7 @@ var MarketplaceRegistry = class {
1765
1804
  const urls = await appSettings.get(KEY_CATALOG_URLS);
1766
1805
  this.catalogUrls = Array.isArray(urls) ? urls : [];
1767
1806
  } catch (error) {
1768
- logger$1.error(`Failed to load catalog URLs: ${error}`);
1807
+ logger$2.error(`Failed to load catalog URLs: ${error}`);
1769
1808
  this.catalogUrls = [];
1770
1809
  }
1771
1810
  }
@@ -1779,28 +1818,28 @@ var MarketplaceRegistry = class {
1779
1818
  async addCatalogUrl(url) {
1780
1819
  if (!this.isValidUrl(url)) throw new Error(`Invalid catalog URL: ${url}`);
1781
1820
  if (this.catalogUrls.includes(url)) {
1782
- logger$1.debug(`Catalog URL already exists: ${url}`);
1821
+ logger$2.debug(`Catalog URL already exists: ${url}`);
1783
1822
  return;
1784
1823
  }
1785
1824
  this.catalogUrls.push(url);
1786
1825
  await this.saveCatalogUrls();
1787
- logger$1.debug(`Added catalog URL: ${url}`);
1826
+ logger$2.debug(`Added catalog URL: ${url}`);
1788
1827
  try {
1789
1828
  await this.refreshCatalogs();
1790
1829
  } catch (error) {
1791
- logger$1.warn(`Failed to refresh catalogs immediately after adding: ${error}`);
1830
+ logger$2.warn(`Failed to refresh catalogs immediately after adding: ${error}`);
1792
1831
  }
1793
1832
  }
1794
1833
  async addCatalogUrls(urls) {
1795
1834
  let added = 0;
1796
1835
  for (const url of urls) {
1797
1836
  if (!this.isValidUrl(url)) {
1798
- logger$1.warn(`Skipping invalid catalog URL: ${url}`);
1837
+ logger$2.warn(`Skipping invalid catalog URL: ${url}`);
1799
1838
  continue;
1800
1839
  }
1801
1840
  if (this.catalogUrls.includes(url)) continue;
1802
1841
  this.catalogUrls.push(url);
1803
- logger$1.debug(`Added catalog URL: ${url}`);
1842
+ logger$2.debug(`Added catalog URL: ${url}`);
1804
1843
  added++;
1805
1844
  }
1806
1845
  if (added === 0) return;
@@ -1808,7 +1847,7 @@ var MarketplaceRegistry = class {
1808
1847
  try {
1809
1848
  await this.refreshCatalogs();
1810
1849
  } catch (error) {
1811
- logger$1.warn(`Failed to refresh catalogs after adding URLs: ${error}`);
1850
+ logger$2.warn(`Failed to refresh catalogs after adding URLs: ${error}`);
1812
1851
  }
1813
1852
  }
1814
1853
  async removeCatalogUrl(url) {
@@ -1816,7 +1855,7 @@ var MarketplaceRegistry = class {
1816
1855
  if (index === -1) return;
1817
1856
  this.catalogUrls.splice(index, 1);
1818
1857
  await this.saveCatalogUrls();
1819
- logger$1.info(`Removed catalog URL: ${url}`);
1858
+ logger$2.info(`Removed catalog URL: ${url}`);
1820
1859
  }
1821
1860
  getCatalogUrls() {
1822
1861
  return [...this.catalogUrls];
@@ -1847,7 +1886,7 @@ var MarketplaceRegistry = class {
1847
1886
  extensions: data.extensions || []
1848
1887
  };
1849
1888
  } catch (error) {
1850
- logger$1.error(`Failed to fetch catalog from ${url}: ${error}`);
1889
+ logger$2.error(`Failed to fetch catalog from ${url}: ${error}`);
1851
1890
  throw error;
1852
1891
  } finally {
1853
1892
  this.loadingPromises.delete(url);
@@ -1858,7 +1897,7 @@ var MarketplaceRegistry = class {
1858
1897
  }
1859
1898
  async refreshCatalogs() {
1860
1899
  const promises = this.catalogUrls.map((url) => this.fetchCatalog(url).catch((error) => {
1861
- logger$1.warn(`Failed to refresh catalog ${url}: ${error.message}`);
1900
+ logger$2.warn(`Failed to refresh catalog ${url}: ${error.message}`);
1862
1901
  return null;
1863
1902
  }));
1864
1903
  const catalogs = await Promise.allSettled(promises);
@@ -1878,8 +1917,8 @@ var MarketplaceRegistry = class {
1878
1917
  });
1879
1918
  }
1880
1919
  });
1881
- logger$1.debug(`Refreshed ${this.catalogUrls.length} catalogs, ${registeredCount} extensions registered`);
1882
- if (registeredCount > 0) logger$1.info(`Marketplace: ${registeredCount} new extension(s) available`);
1920
+ logger$2.debug(`Refreshed ${this.catalogUrls.length} catalogs, ${registeredCount} extensions registered`);
1921
+ if (registeredCount > 0) logger$2.info(`Marketplace: ${registeredCount} new extension(s) available`);
1883
1922
  publish(TOPIC_MARKETPLACE_CHANGED, { type: "refreshed" });
1884
1923
  }
1885
1924
  getMarketplaceExtension(extensionId) {
@@ -1908,16 +1947,10 @@ rootContext.put("marketplaceRegistry", marketplaceRegistry);
1908
1947
  * - Application: App-specific code, gs-* components, contributions
1909
1948
  * - App Loader: Bridge between framework and application
1910
1949
  */
1911
- var logger = createLogger("AppLoader");
1950
+ var logger$1 = createLogger("AppLoader");
1912
1951
  function getLayoutIdFromApp(app) {
1913
- if (!app) return "standard";
1914
- const l = app.layout ?? app.layoutId;
1915
- return typeof l === "object" ? l.id : l ?? "standard";
1916
- }
1917
- function propsToAttributes(props) {
1918
- const out = {};
1919
- for (const [k, v] of Object.entries(props)) out[k] = typeof v === "boolean" ? v ? "true" : "false" : v;
1920
- return out;
1952
+ const layout = app?.layout ?? "standard";
1953
+ return typeof layout === "object" ? layout.id : layout;
1921
1954
  }
1922
1955
  /**
1923
1956
  * Extracts error message from an error object.
@@ -1946,9 +1979,6 @@ var appLoaderService = new class AppLoaderService {
1946
1979
  static {
1947
1980
  this.PREFERRED_APP_KEY = "preferredAppName";
1948
1981
  }
1949
- static {
1950
- this.PREFERRED_LAYOUT_KEY = "preferredLayoutId";
1951
- }
1952
1982
  /**
1953
1983
  * Register an application with the framework.
1954
1984
  * Optionally starts the apploader automatically after registration.
@@ -1967,7 +1997,8 @@ var appLoaderService = new class AppLoaderService {
1967
1997
  }
1968
1998
  app.name = app.name ?? "app";
1969
1999
  app.version = app.version ?? "0.0.0";
1970
- if (this.apps.has(app.name)) logger.warn(`App '${app.name}' is already registered. Overwriting.`);
2000
+ app.layout = app.layout ?? "standard";
2001
+ if (this.apps.has(app.name)) logger$1.warn(`App '${app.name}' is already registered. Overwriting.`);
1971
2002
  if (app.marketplaceCatalogUrls?.length) marketplaceRegistry.addCatalogUrls(app.marketplaceCatalogUrls).catch(() => {});
1972
2003
  this.apps.set(app.name, app);
1973
2004
  if (options?.defaultAppName) this.defaultAppName = options.defaultAppName;
@@ -1984,13 +2015,13 @@ var appLoaderService = new class AppLoaderService {
1984
2015
  */
1985
2016
  async start() {
1986
2017
  if (this.started) {
1987
- logger.debug("AppLoader already started");
2018
+ logger$1.debug("AppLoader already started");
1988
2019
  return;
1989
2020
  }
1990
2021
  this.started = true;
1991
2022
  const appIdFromUrl = new URLSearchParams(window.location.search).get("appId");
1992
2023
  const appIdFromPath = extractAppIdFromPath();
1993
- if (appIdFromPath) logger.info(`Extracted app ID from current page path: ${appIdFromPath}`);
2024
+ if (appIdFromPath) logger$1.info(`Extracted app ID from current page path: ${appIdFromPath}`);
1994
2025
  const appToLoad = await this.selectAppToLoad({
1995
2026
  appIdFromUrl,
1996
2027
  appIdFromPath
@@ -2018,10 +2049,10 @@ var appLoaderService = new class AppLoaderService {
2018
2049
  if (!app) throw new Error(`App '${appName}' not found. Make sure it's registered.`);
2019
2050
  this.dispatchLoadProgress("Starting…");
2020
2051
  if (this.currentApp) {
2021
- logger.info(`Disposing current app: ${this.currentApp.name}`);
2052
+ logger$1.info(`Disposing current app: ${this.currentApp.name}`);
2022
2053
  if (this.currentApp.dispose) await this.currentApp.dispose();
2023
2054
  if (this.currentApp.extensions && this.currentApp.extensions.length > 0) {
2024
- logger.info(`Disabling ${this.currentApp.extensions.length} extensions...`);
2055
+ logger$1.info(`Disabling ${this.currentApp.extensions.length} extensions...`);
2025
2056
  this.currentApp.extensions.forEach((extId) => {
2026
2057
  extensionRegistry.disable(extId);
2027
2058
  });
@@ -2031,25 +2062,28 @@ var appLoaderService = new class AppLoaderService {
2031
2062
  if (app.remaps?.length) {
2032
2063
  const remappedTargets = /* @__PURE__ */ new Set();
2033
2064
  for (const r of app.remaps) for (const t of r.targets) remappedTargets.add(t);
2034
- for (const target of remappedTargets) publish(TOPIC_CONTRIBUTEIONS_CHANGED, {
2035
- target,
2036
- contributions: contributionRegistry.getContributions(target)
2037
- });
2065
+ for (const target of remappedTargets) {
2066
+ const contributions = contributionRegistry.getContributions(target);
2067
+ publish(TOPIC_CONTRIBUTEIONS_CHANGED, {
2068
+ target,
2069
+ contributions
2070
+ });
2071
+ }
2038
2072
  }
2039
2073
  if (app.contributions) {
2040
- logger.info("Registering app contributions...");
2074
+ logger$1.info("Registering app contributions...");
2041
2075
  if (app.contributions.ui) {
2042
2076
  app.contributions.ui.forEach((contribution) => {
2043
2077
  const target = contribution.target;
2044
2078
  if (target) contributionRegistry.registerContribution(target, contribution);
2045
2079
  });
2046
- logger.info(`Registered ${app.contributions.ui.length} UI contributions`);
2080
+ logger$1.info(`Registered ${app.contributions.ui.length} UI contributions`);
2047
2081
  }
2048
2082
  if (app.contributions.extensions) {
2049
2083
  app.contributions.extensions.forEach((extension) => {
2050
2084
  extensionRegistry.registerExtension(extension);
2051
2085
  });
2052
- logger.info(`Registered ${app.contributions.extensions.length} app extensions`);
2086
+ logger$1.info(`Registered ${app.contributions.extensions.length} app extensions`);
2053
2087
  }
2054
2088
  }
2055
2089
  const extensionsSet = new Set(app.extensions || []);
@@ -2058,19 +2092,18 @@ var appLoaderService = new class AppLoaderService {
2058
2092
  if (app.extensions.length > 0) {
2059
2093
  this.dispatchLoadProgress("Enabling extensions…");
2060
2094
  await Promise.all(app.extensions.map((extId) => extensionRegistry.enableAsync(extId).catch((e) => {
2061
- logger.error(`Failed to load extension ${extId}: ${getErrorMessage(e)}`);
2095
+ logger$1.error(`Failed to load extension ${extId}: ${getErrorMessage(e)}`);
2062
2096
  })));
2063
2097
  }
2064
2098
  this.dispatchLoadProgress("Loading extensions…");
2065
2099
  await extensionRegistry.loadEnabledExtensions();
2066
2100
  if (app.initialize) {
2067
2101
  this.dispatchLoadProgress("Initializing…");
2068
- logger.info(`Initializing ${app.name}...`);
2102
+ logger$1.info(`Initializing ${app.name}...`);
2069
2103
  await app.initialize();
2070
2104
  }
2071
2105
  this.currentApp = app;
2072
- logger.info(`App ${app.name} loaded successfully`);
2073
- this.preferredLayoutId = await this.getPreferredLayoutId();
2106
+ logger$1.info(`App ${app.name} loaded successfully`);
2074
2107
  this.updateDocumentMetadata(app);
2075
2108
  if (container) {
2076
2109
  this.dispatchLoadProgress("Rendering layout…");
@@ -2103,19 +2136,17 @@ var appLoaderService = new class AppLoaderService {
2103
2136
  */
2104
2137
  renderApp(container) {
2105
2138
  if (!this.currentApp) throw new Error("No app loaded. Call loadApp() first.");
2106
- const layoutId = this.preferredLayoutId ?? getLayoutIdFromApp(this.currentApp);
2139
+ const layoutId = getLayoutIdFromApp(this.currentApp);
2107
2140
  const layouts = contributionRegistry.getContributions(SYSTEM_LAYOUTS);
2108
2141
  let layout = layouts.find((c) => c.id === layoutId);
2109
2142
  if (!layout) {
2110
- logger.warn(`Layout '${layoutId}' not found, falling back to 'standard'`);
2143
+ logger$1.warn(`Layout '${layoutId}' not found, falling back to 'standard'`);
2111
2144
  layout = layouts.find((c) => c.id === "standard");
2112
2145
  }
2113
2146
  if (!layout) throw new Error(`No layout found for layoutId '${layoutId}' and no 'standard' layout registered.`);
2114
2147
  const r = layout.component;
2115
2148
  let effectiveAttributes = {};
2116
2149
  if (r && typeof r === "object" && "tag" in r && r.attributes) effectiveAttributes = { ...r.attributes };
2117
- const appLayout = this.currentApp?.layout;
2118
- if (typeof appLayout === "object" && appLayout.id === layoutId && appLayout.props) Object.assign(effectiveAttributes, propsToAttributes(appLayout.props));
2119
2150
  container.innerHTML = "";
2120
2151
  if (typeof r === "string") {
2121
2152
  const el = document.createElement(r);
@@ -2128,7 +2159,7 @@ var appLoaderService = new class AppLoaderService {
2128
2159
  } else if (typeof r === "function") render(r(), container);
2129
2160
  else throw new Error(`Layout '${layout.id}' has invalid component.`);
2130
2161
  if (layout.onShow) requestAnimationFrame(() => {
2131
- Promise.resolve(layout.onShow()).catch((err) => logger.error(`Layout onShow failed for '${layout.id}': ${getErrorMessage(err)}`));
2162
+ Promise.resolve(layout.onShow()).catch((err) => logger$1.error(`Layout onShow failed for '${layout.id}': ${getErrorMessage(err)}`));
2132
2163
  });
2133
2164
  }
2134
2165
  /**
@@ -2150,7 +2181,7 @@ var appLoaderService = new class AppLoaderService {
2150
2181
  try {
2151
2182
  return await appSettings.get(AppLoaderService.PREFERRED_APP_KEY);
2152
2183
  } catch (error) {
2153
- logger.debug(`Failed to get preferred app ID from settings: ${getErrorMessage(error)}`);
2184
+ logger$1.debug(`Failed to get preferred app ID from settings: ${getErrorMessage(error)}`);
2154
2185
  return;
2155
2186
  }
2156
2187
  }
@@ -2162,9 +2193,9 @@ var appLoaderService = new class AppLoaderService {
2162
2193
  try {
2163
2194
  await appSettings.set(AppLoaderService.PREFERRED_APP_KEY, appId);
2164
2195
  this.defaultAppName = appId;
2165
- logger.info(`Set preferred app to: ${appId}`);
2196
+ logger$1.info(`Set preferred app to: ${appId}`);
2166
2197
  } catch (error) {
2167
- logger.error(`Failed to persist preferred app: ${getErrorMessage(error)}`);
2198
+ logger$1.error(`Failed to persist preferred app: ${getErrorMessage(error)}`);
2168
2199
  throw error;
2169
2200
  }
2170
2201
  }
@@ -2172,28 +2203,7 @@ var appLoaderService = new class AppLoaderService {
2172
2203
  return contributionRegistry.getContributions(SYSTEM_LAYOUTS);
2173
2204
  }
2174
2205
  getCurrentLayoutId() {
2175
- return this.preferredLayoutId ?? getLayoutIdFromApp(this.currentApp);
2176
- }
2177
- async getPreferredLayoutId() {
2178
- try {
2179
- return await appSettings.get(AppLoaderService.PREFERRED_LAYOUT_KEY);
2180
- } catch (error) {
2181
- logger.debug(`Failed to get preferred layout ID: ${getErrorMessage(error)}`);
2182
- return;
2183
- }
2184
- }
2185
- async setPreferredLayoutId(layoutId) {
2186
- if (!this.getRegisteredLayouts().some((l) => l.id === layoutId)) throw new Error(`Layout '${layoutId}' not found.`);
2187
- try {
2188
- await appSettings.set(AppLoaderService.PREFERRED_LAYOUT_KEY, layoutId);
2189
- this.preferredLayoutId = layoutId;
2190
- logger.info(`Set preferred layout to: ${layoutId}`);
2191
- if (this.currentApp && this.container) this.renderApp(this.container);
2192
- window.dispatchEvent(new CustomEvent("layout-changed", { detail: { layoutId } }));
2193
- } catch (error) {
2194
- logger.error(`Failed to persist preferred layout: ${getErrorMessage(error)}`);
2195
- throw error;
2196
- }
2206
+ return getLayoutIdFromApp(this.currentApp);
2197
2207
  }
2198
2208
  /**
2199
2209
  * Select which app to load based on priority:
@@ -2208,26 +2218,26 @@ var appLoaderService = new class AppLoaderService {
2208
2218
  if (appIdFromUrl) {
2209
2219
  const name = this.findAppNameBySegment(appIdFromUrl) ?? appIdFromUrl;
2210
2220
  if (this.apps.has(name)) {
2211
- logger.info(`Loading app specified by URL parameter 'appId': ${name}`);
2221
+ logger$1.info(`Loading app specified by URL parameter 'appId': ${name}`);
2212
2222
  return name;
2213
2223
  }
2214
- logger.warn(`App '${appIdFromUrl}' from URL parameter not found`);
2224
+ logger$1.warn(`App '${appIdFromUrl}' from URL parameter not found`);
2215
2225
  }
2216
2226
  if (appIdFromPath) {
2217
2227
  const name = this.findAppNameBySegment(appIdFromPath);
2218
2228
  if (name) {
2219
- logger.info(`Loading app from URL path: ${appIdFromPath}`);
2229
+ logger$1.info(`Loading app from URL path: ${appIdFromPath}`);
2220
2230
  return name;
2221
2231
  }
2222
- logger.debug(`App for path '${appIdFromPath}' not found, continuing search`);
2232
+ logger$1.debug(`App for path '${appIdFromPath}' not found, continuing search`);
2223
2233
  }
2224
2234
  const preferred = await this.getPreferredAppId();
2225
2235
  if (preferred && this.apps.has(preferred)) {
2226
- logger.info(`Loading preferred app from settings: ${preferred}`);
2236
+ logger$1.info(`Loading preferred app from settings: ${preferred}`);
2227
2237
  return preferred;
2228
2238
  }
2229
2239
  if (this.defaultAppName && this.apps.has(this.defaultAppName)) return this.defaultAppName;
2230
- if (this.defaultAppName) logger.warn(`Default app '${this.defaultAppName}' not found`);
2240
+ if (this.defaultAppName) logger$1.warn(`Default app '${this.defaultAppName}' not found`);
2231
2241
  const registeredApps = this.getRegisteredApps();
2232
2242
  if (registeredApps.length > 0) return registeredApps[0].name;
2233
2243
  }
@@ -2642,7 +2652,9 @@ var DocksNavigableInfoDialogContent = class DocksNavigableInfoDialogContent exte
2642
2652
  action.callback();
2643
2653
  }
2644
2654
  handleClose() {
2645
- if (this.closest("wa-dialog") && this.resolveCallback) this.resolveCallback();
2655
+ if (this.resolveCallback) this.resolveCallback();
2656
+ const dialog = this.closest("wa-dialog");
2657
+ if (dialog && dialog.open !== false) dialog.open = false;
2646
2658
  }
2647
2659
  static {
2648
2660
  this.styles = [...DocksDialogContent.styles, css`
@@ -2873,7 +2885,8 @@ var DocksFilebrowserDialog = class DocksFilebrowserDialog extends DocksDialogCon
2873
2885
  nodes.sort((a, b) => a.label.localeCompare(b.label));
2874
2886
  this.rootNodes = nodes;
2875
2887
  } catch (e) {
2876
- this.loadError = e instanceof Error ? e.message : String(e);
2888
+ const msg = e instanceof Error ? e.message : String(e);
2889
+ this.loadError = msg;
2877
2890
  this.rootNodes = [];
2878
2891
  } finally {
2879
2892
  this.loading = false;
@@ -2983,77 +2996,633 @@ function filebrowserDialog(mode = "either") {
2983
2996
  });
2984
2997
  }
2985
2998
  //#endregion
2986
- //#region src/dialogs/version-info-dialog.ts
2987
- var CLOSE_PRIMARY = {
2988
- ...CLOSE_BUTTON,
2989
- variant: "primary"
2990
- };
2991
- var DocksVersionInfoDialogContent = class DocksVersionInfoDialogContent extends DocksDialogContent {
2992
- static {
2993
- this.styles = [...DocksDialogContent.styles, css`
2994
- :host {
2995
- display: block;
2996
- }
2997
-
2998
- .dialog-body {
2999
- display: flex;
3000
- flex-direction: column;
3001
- gap: 0.75rem;
3002
- min-width: 32rem;
3003
- height: 600px;
3004
- }
3005
-
3006
- .dialog-body docks-tabs {
3007
- flex: 1;
3008
- min-height: 0;
3009
- }
3010
- `];
2999
+ //#region src/core/contribution-names.ts
3000
+ var VIEW_FILEBROWSER = "view.filebrowser";
3001
+ var VIEW_LOG_TERMINAL = "view.logTerminal";
3002
+ var TOOLBAR_INFO = "toolbar.info";
3003
+ var TOOLBAR_FAST_VIEWS = "toolbar.fastViews";
3004
+ var TOOLBAR_LANGUAGE_SELECTOR = "toolbar.languageSelector";
3005
+ /** Main toolbar (right): layout picker (`docks-layout-switcher`). */
3006
+ var TOOLBAR_LAYOUT_SWITCHER = "toolbar.layoutSwitcher";
3007
+ /** Main toolbar (right): dark/light theme toggle (`switch_theme`). */
3008
+ var TOOLBAR_THEME_SWITCHER = "toolbar.themeSwitcher";
3009
+ /** Main toolbar (right): document fullscreen toggle (`fullscreen`). */
3010
+ var TOOLBAR_FULLSCREEN = "toolbar.fullscreen";
3011
+ /** Bottom-center toolbar: focused part title / active part indicator (`docks-part-name`). */
3012
+ var TOOLBAR_ACTIVE_PART_NAME = "toolbar.activePartName";
3013
+ /** Bottom-center toolbar: background tasks / progress (`docks-tasks`). */
3014
+ var TOOLBAR_TASKS = "toolbar.tasks";
3015
+ /** Main sidebar header toolbar: open extensions (`open_extensions` command). */
3016
+ var SIDEBAR_TOOLBAR_EXTENSIONS = "sidebar.toolbar.extensions";
3017
+ /** Default file-type → icon mappings on `system.icons`. */
3018
+ var SYSTEM_DEFAULT_FILE_ICONS = "system.icons.default";
3019
+ var ABOUT_TAB_RELEASE = "about.tab.release";
3020
+ var ABOUT_TAB_PACKAGES = "about.tab.packages";
3021
+ var ABOUT_TAB_ATTRIBUTIONS = "about.tab.attributions";
3022
+ var ATTRIBUTION_ECLIPSE_DOCKS = "attribution.eclipse-docks";
3023
+ var CTXMENU_FILEBROWSER_RENAME = "contextmenu.filebrowser.rename";
3024
+ var CTXMENU_FILEBROWSER_DELETE = "contextmenu.filebrowser.delete";
3025
+ //#endregion
3026
+ //#region src/parts/container.ts
3027
+ var DocksContainer = class extends DocksElement {};
3028
+ //#endregion
3029
+ //#region src/parts/part.ts
3030
+ var DocksPart = class DocksPart extends DocksContainer {
3031
+ constructor(..._args) {
3032
+ super(..._args);
3033
+ this.scrollMode = "scroller";
3034
+ this.dirty = false;
3035
+ this.isEditor = false;
3036
+ this.embedded = false;
3037
+ this.onContentContextMenu = async (event) => {
3038
+ const contextMenu = this.renderRoot.querySelector("docks-contextmenu");
3039
+ if (!contextMenu) return;
3040
+ if (await contextMenu.show({
3041
+ x: event.clientX,
3042
+ y: event.clientY
3043
+ }, event)) event.preventDefault();
3044
+ };
3011
3045
  }
3012
- firstUpdated(changed) {
3013
- super.firstUpdated(changed);
3014
- const dialog = this.closest("wa-dialog");
3015
- if (dialog) {
3016
- dialog.style.setProperty("--width", "600px");
3017
- dialog.setAttribute("light-dismiss", "");
3046
+ getCommandStack() {
3047
+ return this.commandStack;
3048
+ }
3049
+ /**
3050
+ * Override this method to provide toolbar content for this part.
3051
+ * This is a lightweight alternative to registering toolbar contributions
3052
+ * for actions that are scoped to this part instance.
3053
+ *
3054
+ * IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
3055
+ * The toolbar template is rendered in a different component (docks-toolbar), so direct method
3056
+ * references lose their binding.
3057
+ *
3058
+ * ✅ Correct:
3059
+ * @click=${() => this.myMethod()}
3060
+ * @click=${(e) => this.handleClick(e)}
3061
+ *
3062
+ * ❌ Wrong (this will be bound to the toolbar, not your component):
3063
+ * @click=${this.myMethod}
3064
+ *
3065
+ * Example:
3066
+ * ```typescript
3067
+ * protected renderToolbar() {
3068
+ * return html`
3069
+ * <wa-button @click=${() => this.save()} title="Save">
3070
+ * <wa-icon name="save"></wa-icon>
3071
+ * </wa-button>
3072
+ * `;
3073
+ * }
3074
+ * ```
3075
+ *
3076
+ * @returns TemplateResult with toolbar items, or nothing if no toolbar needed
3077
+ */
3078
+ renderToolbar() {
3079
+ return nothing;
3080
+ }
3081
+ /**
3082
+ * Activates the tab that contains this part by walking up the DOM to the first
3083
+ * docks-tabs ancestor and activating the tab panel that contains this part.
3084
+ * Crosses Shadow DOM boundaries (e.g. wa-tab-group) via getRootNode().host.
3085
+ * No-op if this part is not inside a docks-tabs / wa-tab-panel.
3086
+ */
3087
+ activateContainingTab() {
3088
+ let el = this;
3089
+ let panelName = null;
3090
+ let tabsEl = null;
3091
+ while (el) {
3092
+ const tag = el.tagName?.toLowerCase();
3093
+ if (tag === "wa-tab-panel") panelName = el.getAttribute("name");
3094
+ if (tag === "docks-tabs") {
3095
+ tabsEl = el;
3096
+ break;
3097
+ }
3098
+ const parent = el.parentElement;
3099
+ if (parent) el = parent;
3100
+ else {
3101
+ const root = el.getRootNode();
3102
+ el = root instanceof ShadowRoot ? root.host : null;
3103
+ }
3018
3104
  }
3105
+ if (tabsEl && panelName != null && panelName !== "") tabsEl.activate(panelName);
3106
+ }
3107
+ /**
3108
+ * Override this method to provide context menu content for this part.
3109
+ * This is a lightweight alternative to registering context menu contributions
3110
+ * for actions that are scoped to this part instance.
3111
+ *
3112
+ * IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
3113
+ * The context menu is rendered in a different component (contextmenu), so direct method
3114
+ * references lose their binding.
3115
+ *
3116
+ * ✅ Correct:
3117
+ * @click=${() => this.myMethod()}
3118
+ * @click=${(e) => this.handleClick(e)}
3119
+ *
3120
+ * ❌ Wrong (this will be bound to the context menu, not your component):
3121
+ * @click=${this.myMethod}
3122
+ *
3123
+ * Example:
3124
+ * ```typescript
3125
+ * protected renderContextMenu() {
3126
+ * return html`
3127
+ * <wa-dropdown-item @click=${() => this.open()}>
3128
+ * <wa-icon name="folder-open"></wa-icon>
3129
+ * Open
3130
+ * </wa-dropdown-item>
3131
+ * <wa-divider></wa-divider>
3132
+ * <wa-dropdown-item @click=${() => this.delete()}>
3133
+ * <wa-icon name="trash"></wa-icon>
3134
+ * Delete
3135
+ * </wa-dropdown-item>
3136
+ * `;
3137
+ * }
3138
+ * ```
3139
+ *
3140
+ * @returns TemplateResult with context menu items, or nothing if no context menu needed
3141
+ */
3142
+ renderContextMenu() {
3143
+ return nothing;
3144
+ }
3145
+ renderContent() {
3146
+ return nothing;
3147
+ }
3148
+ /** Part-level toolbar contributions (`toolbar:${partId}`). */
3149
+ getToolbarTarget() {
3150
+ const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
3151
+ return contributionKey ? `toolbar:${contributionKey}` : void 0;
3152
+ }
3153
+ /** Part-level context-menu contributions (`contextmenu:${partId}`). */
3154
+ getContextMenuTarget() {
3155
+ const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
3156
+ return contributionKey ? `contextmenu:${contributionKey}` : void 0;
3157
+ }
3158
+ syncIsEditorCapability() {
3159
+ const next = this.save !== DocksPart.prototype.save;
3160
+ if (next === this.isEditor) return;
3161
+ this.isEditor = next;
3162
+ }
3163
+ maybeActivateForCoupledEditors() {
3164
+ const coupled = this.tabContribution?.coupledEditors;
3165
+ if (!coupled?.length) return;
3166
+ const active = activeEditorSignal.get();
3167
+ if (!(active instanceof DocksPart)) return;
3168
+ const editorId = active.tabContribution?.editorId;
3169
+ if (!editorId || !coupled.includes(editorId)) return;
3170
+ this.activateContainingTab();
3019
3171
  }
3020
3172
  render() {
3021
- const app = appLoaderService.getCurrentApp();
3173
+ const toolbarTarget = this.getToolbarTarget();
3174
+ const contextMenuTarget = this.getContextMenuTarget();
3175
+ const toolbarEnabled = this.tabContribution?.toolbar !== false;
3176
+ const contextMenuEnabled = this.tabContribution?.contextMenu !== false;
3177
+ const scrollMode = this.scrollMode;
3178
+ const scopeTokens = this.isEditor ? ["system.editors", ".system.editors"] : [];
3179
+ const content = this.renderContent();
3180
+ const contentNode = scrollMode === "scroller" ? html`
3181
+ <wa-scroller class="part-content-scroll" orientation="vertical">
3182
+ <div class="part-content-inner">${content}</div>
3183
+ </wa-scroller>
3184
+ ` : html`<div class="part-content-inner">${content}</div>`;
3022
3185
  return html`
3023
- <div class="dialog-body">
3024
- ${app?.description ? html`<small>${app.description}</small>` : ""}
3025
- <docks-tabs id=${ABOUT_TABS}></docks-tabs>
3186
+ <div class="part-shell">
3187
+ ${toolbarEnabled ? html`
3188
+ <docks-toolbar
3189
+ class="part-toolbar"
3190
+ id=${ifDefined(toolbarTarget)}
3191
+ .scopeTokens=${scopeTokens}
3192
+ .partToolbarRenderer=${() => this.renderToolbar()}>
3193
+ </docks-toolbar>
3194
+ ` : nothing}
3195
+ <div class="part-content ${scrollMode === "native" ? "native-scroll" : ""}" @contextmenu=${contextMenuEnabled ? this.onContentContextMenu : void 0}>
3196
+ ${contentNode}
3197
+ </div>
3198
+ ${contextMenuEnabled ? html`
3199
+ <docks-contextmenu
3200
+ id=${ifDefined(contextMenuTarget)}
3201
+ .scopeTokens=${scopeTokens}
3202
+ .partContextMenuRenderer=${() => this.renderContextMenu()}>
3203
+ </docks-contextmenu>
3204
+ ` : nothing}
3026
3205
  </div>
3027
3206
  `;
3028
3207
  }
3029
- };
3030
- DocksVersionInfoDialogContent = _decorate([customElement("docks-version-info-dialog-content")], DocksVersionInfoDialogContent);
3031
- contributionRegistry.registerContribution(DIALOG_CONTRIBUTION_TARGET, {
3032
- id: "version-info",
3033
- label: "About",
3034
- buttons: [CLOSE_PRIMARY],
3035
- component: () => html`<docks-version-info-dialog-content></docks-version-info-dialog-content>`,
3036
- onButton: async () => true
3037
- });
3038
- function versionInfoDialog() {
3039
- const app = appLoaderService.getCurrentApp();
3040
- return dialogService.open("version-info", { label: `About ${app?.name ?? ""} - ${app?.version ?? "0.0.0"}` });
3041
- }
3042
- //#endregion
3043
- //#region src/core/dropdown-menu-utils.ts
3044
- function isOpenDropdown(element) {
3045
- if (element.localName !== "wa-dropdown") return false;
3046
- const dropdown = element;
3047
- return dropdown.open === true || dropdown.hasAttribute("open");
3048
- }
3049
- function elementsFromEventPath(event) {
3050
- const fromComposedPath = event.composedPath().filter((node) => node instanceof Element);
3051
- if (fromComposedPath.length > 0) return fromComposedPath;
3052
- if (!(event.target instanceof Element)) return [];
3053
- const path = [];
3054
- let current = event.target;
3055
- while (current) {
3056
- path.push(current);
3208
+ updated(_changedProperties) {
3209
+ super.updated(_changedProperties);
3210
+ this.syncIsEditorCapability();
3211
+ if (_changedProperties.has("tabContribution")) this.maybeActivateForCoupledEditors();
3212
+ if (_changedProperties.has("dirty")) {
3213
+ if (_changedProperties.get("dirty") !== void 0) this.dispatchEvent(new CustomEvent("dirty", {
3214
+ detail: this.dirty,
3215
+ bubbles: true
3216
+ }));
3217
+ }
3218
+ }
3219
+ doClose() {}
3220
+ disconnectedCallback() {
3221
+ super.disconnectedCallback();
3222
+ }
3223
+ close() {
3224
+ this.doClose();
3225
+ }
3226
+ connectedCallback() {
3227
+ super.connectedCallback();
3228
+ this.syncIsEditorCapability();
3229
+ queueMicrotask(() => this.syncIsEditorCapability());
3230
+ this.watch(activeEditorSignal, () => this.maybeActivateForCoupledEditors());
3231
+ }
3232
+ save() {}
3233
+ isDirty() {
3234
+ return this.dirty;
3235
+ }
3236
+ markDirty(dirty) {
3237
+ this.dirty = dirty;
3238
+ partDirtySignal.set(null);
3239
+ partDirtySignal.set(this);
3240
+ activePartSignal.set(null);
3241
+ activePartSignal.set(this);
3242
+ }
3243
+ static {
3244
+ this.baseStyles = css`
3245
+ :host {
3246
+ display: block;
3247
+ }
3248
+
3249
+ .part-shell {
3250
+ display: grid;
3251
+ grid-template-rows: auto minmax(0, 1fr);
3252
+ height: 100%;
3253
+ width: 100%;
3254
+ position: relative;
3255
+ overflow: hidden;
3256
+ }
3257
+
3258
+ .part-content {
3259
+ min-height: 0;
3260
+ overflow: hidden;
3261
+ position: relative;
3262
+ }
3263
+
3264
+ .part-content.native-scroll {
3265
+ overflow: auto;
3266
+ }
3267
+
3268
+ .part-content-scroll {
3269
+ width: 100%;
3270
+ height: 100%;
3271
+ }
3272
+
3273
+ .part-content-inner {
3274
+ height: 100%;
3275
+ min-height: 100%;
3276
+ }
3277
+
3278
+ :host([embedded]) {
3279
+ height: auto;
3280
+ }
3281
+
3282
+ :host([embedded]) .part-shell {
3283
+ height: auto;
3284
+ overflow: visible;
3285
+ grid-template-rows: auto;
3286
+ }
3287
+
3288
+ :host([embedded]) .part-content {
3289
+ overflow: visible;
3290
+ min-height: 0;
3291
+ }
3292
+
3293
+ :host([embedded]) .part-content-inner {
3294
+ height: auto;
3295
+ min-height: 0;
3296
+ }
3297
+
3298
+ .part-toolbar {
3299
+ min-height: 0;
3300
+ }
3301
+ `;
3302
+ }
3303
+ static finalizeStyles(styles) {
3304
+ const own = super.finalizeStyles(styles);
3305
+ return [DocksPart.baseStyles, ...own];
3306
+ }
3307
+ };
3308
+ _decorate([property()], DocksPart.prototype, "dirty", void 0);
3309
+ _decorate([property({ attribute: false })], DocksPart.prototype, "tabContribution", void 0);
3310
+ _decorate([property({
3311
+ type: Boolean,
3312
+ attribute: false
3313
+ })], DocksPart.prototype, "isEditor", void 0);
3314
+ _decorate([property({
3315
+ type: Boolean,
3316
+ reflect: true
3317
+ })], DocksPart.prototype, "embedded", void 0);
3318
+ //#endregion
3319
+ //#region src/components/release-history.ts
3320
+ var logger = createLogger("ReleaseHistory");
3321
+ async function loadReleases(releaseHistory) {
3322
+ if (!releaseHistory) return [];
3323
+ if (typeof releaseHistory !== "function") return releaseHistory;
3324
+ try {
3325
+ return await releaseHistory();
3326
+ } catch (error) {
3327
+ logger.error(`Failed to load release history from app: ${error instanceof Error ? error.message : String(error)}`);
3328
+ return [];
3329
+ }
3330
+ }
3331
+ function semverEqual(a, b) {
3332
+ return a.replace(/^v/i, "") === b.replace(/^v/i, "");
3333
+ }
3334
+ function isNewerThan(releaseTag, currentVersion) {
3335
+ const currentParts = currentVersion.replace(/^v/i, "").split(".").map(Number);
3336
+ const releaseParts = releaseTag.replace(/^v/i, "").split(".").map(Number);
3337
+ for (let i = 0; i < Math.max(currentParts.length, releaseParts.length); i++) {
3338
+ const current = currentParts[i] || 0;
3339
+ const releasePart = releaseParts[i] || 0;
3340
+ if (releasePart > current) return true;
3341
+ if (releasePart < current) return false;
3342
+ }
3343
+ return false;
3344
+ }
3345
+ var DocksReleaseHistory = class DocksReleaseHistory extends DocksPart {
3346
+ constructor(..._args) {
3347
+ super(..._args);
3348
+ this.scrollMode = "none";
3349
+ this.appVersion = "0.0.0";
3350
+ this.releases = [];
3351
+ this.currentReleaseIndex = 0;
3352
+ }
3353
+ static {
3354
+ this.styles = [css`
3355
+ .release-panel {
3356
+ display: flex;
3357
+ flex-direction: column;
3358
+ gap: 0.5rem;
3359
+ padding: 0.75rem;
3360
+ box-sizing: border-box;
3361
+ }
3362
+
3363
+ .release-body {
3364
+ white-space: normal;
3365
+ }
3366
+ `];
3367
+ }
3368
+ doInitUI() {
3369
+ this.load();
3370
+ }
3371
+ async load() {
3372
+ const app = appLoaderService.getCurrentApp();
3373
+ this.appVersion = app?.version ?? "0.0.0";
3374
+ this.releases = await loadReleases(app?.releaseHistory);
3375
+ const currentIndex = this.releases.findIndex((release) => semverEqual(release.tag_name, this.appVersion));
3376
+ this.currentReleaseIndex = currentIndex >= 0 ? currentIndex : 0;
3377
+ this.notifyChanged();
3378
+ }
3379
+ getNavState() {
3380
+ return {
3381
+ hasMultiple: this.releases.length > 1,
3382
+ atOldest: this.currentReleaseIndex >= this.releases.length - 1,
3383
+ atNewest: this.currentReleaseIndex <= 0
3384
+ };
3385
+ }
3386
+ showOlder() {
3387
+ if (this.currentReleaseIndex < this.releases.length - 1) {
3388
+ this.currentReleaseIndex += 1;
3389
+ this.notifyChanged();
3390
+ }
3391
+ }
3392
+ showNewer() {
3393
+ if (this.currentReleaseIndex > 0) {
3394
+ this.currentReleaseIndex -= 1;
3395
+ this.notifyChanged();
3396
+ }
3397
+ }
3398
+ notifyChanged() {
3399
+ this.dispatchEvent(new CustomEvent("release-history-changed", {
3400
+ bubbles: true,
3401
+ composed: true
3402
+ }));
3403
+ }
3404
+ renderContent() {
3405
+ const release = this.releases[this.currentReleaseIndex];
3406
+ if (!release) return html`<div class="release-panel">No release history available.</div>`;
3407
+ const isCurrent = semverEqual(release.tag_name, this.appVersion);
3408
+ const showUpdateHint = !isCurrent && isNewerThan(release.tag_name, this.appVersion);
3409
+ const bodyHtml = release.body ? parseMarkdownHtml(release.body) : "";
3410
+ return html`
3411
+ <div class="release-panel">
3412
+ <p>
3413
+ <strong>Version:</strong> ${release.tag_name}${isCurrent ? " (Current)" : ""}
3414
+ </p>
3415
+ <p>
3416
+ <strong>Released:</strong>
3417
+ <wa-format-date
3418
+ .date=${release.published_at}
3419
+ month="short"
3420
+ day="numeric"
3421
+ year="numeric"
3422
+ ></wa-format-date>
3423
+ </p>
3424
+ ${showUpdateHint ? html`
3425
+ <wa-callout variant="warning">
3426
+ <wa-icon slot="icon" name="triangle-exclamation"></wa-icon>
3427
+ A newer release is available than the version you are running.
3428
+ Use <strong>Update Available</strong> in the toolbar when it appears.
3429
+ </wa-callout>
3430
+ ` : ""}
3431
+ ${bodyHtml ? html`<div class="release-body">${unsafeHTML(bodyHtml)}</div>` : ""}
3432
+ </div>
3433
+ `;
3434
+ }
3435
+ };
3436
+ _decorate([state()], DocksReleaseHistory.prototype, "appVersion", void 0);
3437
+ _decorate([state()], DocksReleaseHistory.prototype, "releases", void 0);
3438
+ _decorate([state()], DocksReleaseHistory.prototype, "currentReleaseIndex", void 0);
3439
+ DocksReleaseHistory = _decorate([customElement("docks-release-history")], DocksReleaseHistory);
3440
+ //#endregion
3441
+ //#region src/dialogs/version-info-dialog.ts
3442
+ var EMPTY_NAV = {
3443
+ hasMultiple: false,
3444
+ atOldest: true,
3445
+ atNewest: true
3446
+ };
3447
+ var DocksVersionInfoDialog = class DocksVersionInfoDialog extends DocksDialogContent {
3448
+ constructor(..._args) {
3449
+ super(..._args);
3450
+ this.label = "";
3451
+ this.activeTab = null;
3452
+ this.releaseNav = EMPTY_NAV;
3453
+ this.onReleaseHistoryChanged = () => {
3454
+ this.syncReleaseNav();
3455
+ };
3456
+ }
3457
+ static {
3458
+ this.styles = [...DocksDialogContent.styles, css`
3459
+ :host {
3460
+ display: block;
3461
+ }
3462
+
3463
+ wa-dialog {
3464
+ --width: 600px;
3465
+ }
3466
+
3467
+ wa-dialog::part(body) {
3468
+ display: flex;
3469
+ flex-direction: column;
3470
+ min-height: 0;
3471
+ overflow: hidden;
3472
+ }
3473
+
3474
+ .dialog-body {
3475
+ display: flex;
3476
+ flex-direction: column;
3477
+ gap: 0.75rem;
3478
+ min-width: 32rem;
3479
+ height: min(70vh, 36rem);
3480
+ min-height: min(70vh, 36rem);
3481
+ overflow: hidden;
3482
+ }
3483
+
3484
+ .dialog-body docks-tabs {
3485
+ flex: 1 1 auto;
3486
+ min-height: 0;
3487
+ overflow: hidden;
3488
+ }
3489
+
3490
+ .dialog-footer {
3491
+ display: flex;
3492
+ gap: 0.5rem;
3493
+ justify-content: flex-end;
3494
+ width: 100%;
3495
+ }
3496
+ `];
3497
+ }
3498
+ firstUpdated(changed) {
3499
+ super.firstUpdated(changed);
3500
+ this.addEventListener("release-history-changed", this.onReleaseHistoryChanged);
3501
+ this.updateComplete.then(() => {
3502
+ this.attachTabListener();
3503
+ this.syncActiveTab();
3504
+ this.syncReleaseNav();
3505
+ });
3506
+ }
3507
+ disconnectedCallback() {
3508
+ this.removeEventListener("release-history-changed", this.onReleaseHistoryChanged);
3509
+ super.disconnectedCallback();
3510
+ }
3511
+ attachTabListener() {
3512
+ const tabGroup = this.getAboutTabs()?.shadowRoot?.querySelector("wa-tab-group");
3513
+ if (!tabGroup || tabGroup.hasAttribute("data-version-info-listener")) return;
3514
+ tabGroup.setAttribute("data-version-info-listener", "");
3515
+ tabGroup.addEventListener("wa-tab-show", (event) => {
3516
+ const name = event.detail?.name;
3517
+ if (name) this.activeTab = name;
3518
+ });
3519
+ }
3520
+ getAboutTabs() {
3521
+ return this.renderRoot.querySelector("docks-tabs");
3522
+ }
3523
+ getReleaseHistory() {
3524
+ const part = this.getAboutTabs()?.getTabPart(ABOUT_TAB_RELEASE);
3525
+ return part instanceof DocksReleaseHistory ? part : null;
3526
+ }
3527
+ syncActiveTab() {
3528
+ const tabGroup = this.getAboutTabs()?.shadowRoot?.querySelector("wa-tab-group");
3529
+ this.activeTab = tabGroup?.getAttribute("active") || tabGroup?.active || null;
3530
+ }
3531
+ syncReleaseNav() {
3532
+ this.releaseNav = this.getReleaseHistory()?.getNavState() ?? EMPTY_NAV;
3533
+ }
3534
+ handleClose() {
3535
+ const dialog = this.renderRoot.querySelector("wa-dialog");
3536
+ if (dialog && dialog.open !== false) {
3537
+ dialog.open = false;
3538
+ return;
3539
+ }
3540
+ this.close?.();
3541
+ }
3542
+ handleAfterHide() {
3543
+ this.onAfterHide?.();
3544
+ }
3545
+ showOlderRelease() {
3546
+ this.getReleaseHistory()?.showOlder();
3547
+ }
3548
+ showNewerRelease() {
3549
+ this.getReleaseHistory()?.showNewer();
3550
+ }
3551
+ render() {
3552
+ const app = appLoaderService.getCurrentApp();
3553
+ const showReleaseNav = this.activeTab === "about.tab.release" && this.releaseNav.hasMultiple;
3554
+ return html`
3555
+ <wa-dialog
3556
+ label=${this.label}
3557
+ open
3558
+ light-dismiss
3559
+ with-footer
3560
+ @wa-after-hide=${this.handleAfterHide}
3561
+ >
3562
+ <div class="dialog-body">
3563
+ ${app?.description ? html`<small>${app.description}</small>` : ""}
3564
+ <docks-tabs id=${ABOUT_TABS} fill-height></docks-tabs>
3565
+ </div>
3566
+ <div slot="footer" class="dialog-footer">
3567
+ ${showReleaseNav ? html`
3568
+ <wa-button
3569
+ variant="default"
3570
+ ?disabled=${this.releaseNav.atOldest}
3571
+ @click=${this.showOlderRelease}
3572
+ >
3573
+ ← Previous
3574
+ </wa-button>
3575
+ <wa-button
3576
+ variant="default"
3577
+ ?disabled=${this.releaseNav.atNewest}
3578
+ @click=${this.showNewerRelease}
3579
+ >
3580
+ Next →
3581
+ </wa-button>
3582
+ ` : nothing}
3583
+ <wa-button variant="primary" @click=${this.handleClose}>Close</wa-button>
3584
+ </div>
3585
+ </wa-dialog>
3586
+ `;
3587
+ }
3588
+ };
3589
+ _decorate([property({ type: String })], DocksVersionInfoDialog.prototype, "label", void 0);
3590
+ _decorate([property({ attribute: false })], DocksVersionInfoDialog.prototype, "close", void 0);
3591
+ _decorate([property({ attribute: false })], DocksVersionInfoDialog.prototype, "onAfterHide", void 0);
3592
+ _decorate([state()], DocksVersionInfoDialog.prototype, "activeTab", void 0);
3593
+ _decorate([state()], DocksVersionInfoDialog.prototype, "releaseNav", void 0);
3594
+ DocksVersionInfoDialog = _decorate([customElement("docks-version-info-dialog")], DocksVersionInfoDialog);
3595
+ contributionRegistry.registerContribution(DIALOG_CONTRIBUTION_TARGET, {
3596
+ id: "version-info",
3597
+ label: "About",
3598
+ selfContained: true,
3599
+ component: (state) => html`
3600
+ <docks-version-info-dialog
3601
+ .label=${state?.label ?? ""}
3602
+ .close=${state?.close}
3603
+ .onAfterHide=${state?.onAfterHide}
3604
+ ></docks-version-info-dialog>
3605
+ `
3606
+ });
3607
+ function versionInfoDialog() {
3608
+ const app = appLoaderService.getCurrentApp();
3609
+ return dialogService.open("version-info", { label: `About ${app?.name ?? ""} - ${app?.version ?? "0.0.0"}` });
3610
+ }
3611
+ //#endregion
3612
+ //#region src/core/dropdown-menu-utils.ts
3613
+ function isOpenDropdown(element) {
3614
+ if (element.localName !== "wa-dropdown") return false;
3615
+ const dropdown = element;
3616
+ return dropdown.open === true || dropdown.hasAttribute("open");
3617
+ }
3618
+ function elementsFromEventPath(event) {
3619
+ const fromComposedPath = event.composedPath().filter((node) => node instanceof Element);
3620
+ if (fromComposedPath.length > 0) return fromComposedPath;
3621
+ if (!(event.target instanceof Element)) return [];
3622
+ const path = [];
3623
+ let current = event.target;
3624
+ while (current) {
3625
+ path.push(current);
3057
3626
  const root = current.getRootNode();
3058
3627
  if (root instanceof ShadowRoot) {
3059
3628
  current = root.host;
@@ -3147,9 +3716,10 @@ var RESIZE_DEBOUNCE_MS = 150;
3147
3716
  function renderButtonGroup(slotName, orientation, contributions, isToolbarItem, contributionCreator) {
3148
3717
  const label = `Toolbar ${slotName ?? "default"}`;
3149
3718
  const items = contributions.filter((c) => c.slot === slotName && isToolbarItem(c) && getContributionVisible(c));
3719
+ const slotHtml = slotName === "start" ? html`<slot name="start"></slot>` : slotName === "end" ? html`<slot name="end"></slot>` : html`<slot></slot>`;
3150
3720
  return html`
3151
3721
  <wa-button-group orientation=${orientation} label=${label}>
3152
- ${slotName === "start" ? html`<slot name="start"></slot>` : slotName === "end" ? html`<slot name="end"></slot>` : html`<slot></slot>`}
3722
+ ${slotHtml}
3153
3723
  ${items.map(contributionCreator)}
3154
3724
  </wa-button-group>
3155
3725
  `;
@@ -3358,21 +3928,36 @@ DocksToolbar = _decorate([customElement("docks-toolbar")], DocksToolbar);
3358
3928
  * A part can expose both surfaces with the same part id but different prefixes, registering
3359
3929
  * different contributions on each. Feature-scoped targets (e.g. `filebrowser.create`) may also
3360
3930
  * be referenced explicitly from either surface when several controls share the same item set.
3931
+ *
3932
+ * Command-backed items rely on the parent {@link https://webawesome.com/docs/components/dropdown | wa-dropdown}
3933
+ * `wa-select` event (see {@link handleDropdownWaSelect}) so the popup closes cleanly before
3934
+ * native dialogs such as `showDirectoryPicker` open.
3361
3935
  */
3362
- function closeParentDropdown(event) {
3363
- const dropdown = event.target?.closest("wa-dropdown");
3364
- if (dropdown && dropdown.open !== void 0) dropdown.open = false;
3936
+ function parseDropdownItemParams(item) {
3937
+ const raw = item.getAttribute("data-params");
3938
+ if (!raw) return {};
3939
+ try {
3940
+ return JSON.parse(raw);
3941
+ } catch {
3942
+ return {};
3943
+ }
3944
+ }
3945
+ function getDropdownItemCommand(item) {
3946
+ return item.getAttribute("data-cmd") || item.getAttribute("value") || void 0;
3947
+ }
3948
+ /** Handles `wa-select` from a parent `wa-dropdown` and runs the backing command. */
3949
+ function handleDropdownWaSelect(event) {
3950
+ const item = event.detail?.item;
3951
+ if (!item || item.disabled || item.hasAttribute("disabled")) return;
3952
+ const cmd = getDropdownItemCommand(item);
3953
+ if (!cmd) return;
3954
+ commandRegistry.execute(cmd, commandRegistry.createExecutionContext(parseDropdownItemParams(item)));
3365
3955
  }
3366
- function onDropdownItemClick(options) {
3956
+ function onDropdownActionClick(options) {
3367
3957
  return (event) => {
3368
3958
  if (readReactiveBoolean(options.disabled, false)) return;
3369
3959
  event.stopPropagation();
3370
- closeParentDropdown(event);
3371
- if (options.action) {
3372
- options.action(event);
3373
- return;
3374
- }
3375
- if (options.cmd) commandRegistry.execute(options.cmd, commandRegistry.createExecutionContext(options.params ?? {}));
3960
+ options.action?.(event);
3376
3961
  };
3377
3962
  }
3378
3963
  function keybindingDetails(cmd) {
@@ -3384,12 +3969,16 @@ function keybindingDetails(cmd) {
3384
3969
  /** Renders a native {@link https://webawesome.com/docs/components/dropdown-item | wa-dropdown-item}. */
3385
3970
  function renderDropdownItem(options) {
3386
3971
  const iconSpec = options.icon ?? "";
3972
+ const paramsJson = options.params && Object.keys(options.params).length > 0 ? JSON.stringify(options.params) : void 0;
3387
3973
  return html`
3388
3974
  <wa-dropdown-item
3389
3975
  slot=${options.slot ?? nothing}
3390
3976
  variant=${options.variant ?? "default"}
3977
+ value=${options.cmd ?? nothing}
3978
+ data-cmd=${options.cmd ?? nothing}
3979
+ data-params=${paramsJson ?? nothing}
3391
3980
  ?disabled=${readReactiveBoolean(options.disabled, false)}
3392
- @click=${onDropdownItemClick(options)}>
3981
+ @click=${options.action ? onDropdownActionClick(options) : nothing}>
3393
3982
  ${iconSpec ? icon(iconSpec, {
3394
3983
  label: options.title ?? options.label,
3395
3984
  slot: "icon"
@@ -3422,7 +4011,8 @@ function renderDropdownContribution(contribution, options) {
3422
4011
  }
3423
4012
  /** Renders all visible contributions registered for a contribution target. */
3424
4013
  function renderDropdownContributions(target, options) {
3425
- return html`${contributionRegistry.getContributions(target).map((c) => renderDropdownContribution(c, options)).filter((item) => item !== nothing)}`;
4014
+ const items = contributionRegistry.getContributions(target).map((c) => renderDropdownContribution(c, options)).filter((item) => item !== nothing);
4015
+ return html`${items}`;
3426
4016
  }
3427
4017
  /** Renders a {@link wa-dropdown-item} with nested items from a contribution target in {@code slot="submenu"}. */
3428
4018
  function renderDropdownSubmenu(options) {
@@ -3568,384 +4158,117 @@ var DocksContextMenu = class DocksContextMenu extends DocksElement {
3568
4158
  return element;
3569
4159
  }
3570
4160
  getHostPart() {
3571
- const root = this.getRootNode();
3572
- if (root instanceof ShadowRoot && root.host instanceof HTMLElement) return root.host;
3573
- return null;
3574
- }
3575
- /**
3576
- * Triggers a click on the element under the cursor to update selection before showing context menu.
3577
- */
3578
- triggerClickUnderCursor(mouseEvent) {
3579
- const elementUnderCursor = this.getElementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
3580
- if (elementUnderCursor) {
3581
- const clickEvent = new MouseEvent("click", {
3582
- bubbles: true,
3583
- cancelable: true,
3584
- view: window,
3585
- clientX: mouseEvent.clientX,
3586
- clientY: mouseEvent.clientY,
3587
- screenX: mouseEvent.screenX,
3588
- screenY: mouseEvent.screenY,
3589
- button: 0,
3590
- buttons: 0,
3591
- detail: 1,
3592
- which: 1
3593
- });
3594
- elementUnderCursor.dispatchEvent(clickEvent);
3595
- }
3596
- }
3597
- /** Opens the menu at `position`. Returns false when there is nothing to show (no thin empty panel). */
3598
- async show(position, mouseEvent) {
3599
- if (!this.hasMenuBody()) return false;
3600
- if (mouseEvent) {
3601
- this.triggerClickUnderCursor(mouseEvent);
3602
- await this.getHostPart()?.updateComplete;
3603
- }
3604
- if (this.isOpen) {
3605
- this.isOpen = false;
3606
- await this.updateComplete;
3607
- }
3608
- this.menuPosition = position;
3609
- this.isOpen = true;
3610
- await this.updateComplete;
3611
- this.syncVirtualPopupAnchor();
3612
- document.addEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
3613
- return true;
3614
- }
3615
- /** Points wa-dropdown's internal wa-popup at the pointer via a VirtualElement anchor. */
3616
- syncVirtualPopupAnchor() {
3617
- const popup = this.dropdownRef.value?.shadowRoot?.querySelector("wa-popup");
3618
- if (!popup) return;
3619
- popup.anchor = this.virtualAnchor;
3620
- popup.reposition();
3621
- }
3622
- onClose() {
3623
- if (!this.isOpen) return;
3624
- this.isOpen = false;
3625
- document.removeEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
3626
- }
3627
- updated(changedProperties) {
3628
- super.updated(changedProperties);
3629
- if (changedProperties.has("isOpen") && this.isOpen) this.syncVirtualPopupAnchor();
3630
- }
3631
- renderContribution(contribution) {
3632
- return renderDropdownContribution(contribution);
3633
- }
3634
- render() {
3635
- const partContent = this.partContextMenuRenderer ? this.partContextMenuRenderer() : nothing;
3636
- return html`
3637
- <wa-dropdown
3638
- ${ref(this.dropdownRef)}
3639
- ?open=${this.isOpen}
3640
- @submenu-opening=${this.handleSubmenuOpening}
3641
- @wa-after-hide=${this.onClose}>
3642
- <span slot="trigger" hidden aria-hidden="true"></span>
3643
-
3644
- ${partContent}
3645
- ${this.contributions.map((c) => this.renderContribution(c))}
3646
- </wa-dropdown>
3647
- `;
3648
- }
3649
- static {
3650
- this.styles = css`
3651
- :host {
3652
- position: fixed;
3653
- top: 0;
3654
- left: 0;
3655
- width: 0;
3656
- height: 0;
3657
- pointer-events: none;
3658
- z-index: 10000;
3659
- }
3660
-
3661
- wa-dropdown {
3662
- pointer-events: none;
3663
- min-width: 200px;
3664
- }
3665
-
3666
- wa-dropdown:state(open) {
3667
- pointer-events: auto;
3668
- }
3669
-
3670
- wa-dropdown::part(menu) {
3671
- min-width: 200px;
3672
- }
3673
- `;
3674
- }
3675
- };
3676
- _decorate([property({ attribute: false })], DocksContextMenu.prototype, "scopeTokens", void 0);
3677
- _decorate([property({ attribute: false })], DocksContextMenu.prototype, "partContextMenuRenderer", void 0);
3678
- _decorate([state()], DocksContextMenu.prototype, "contributions", void 0);
3679
- _decorate([state()], DocksContextMenu.prototype, "isOpen", void 0);
3680
- DocksContextMenu = _decorate([customElement("docks-contextmenu")], DocksContextMenu);
3681
- //#endregion
3682
- //#region src/parts/container.ts
3683
- var DocksContainer = class extends DocksElement {};
3684
- //#endregion
3685
- //#region src/parts/part.ts
3686
- var DocksPart = class DocksPart extends DocksContainer {
3687
- constructor(..._args) {
3688
- super(..._args);
3689
- this.scrollMode = "scroller";
3690
- this.dirty = false;
3691
- this.isEditor = false;
3692
- this.onContentContextMenu = async (event) => {
3693
- const contextMenu = this.renderRoot.querySelector("docks-contextmenu");
3694
- if (!contextMenu) return;
3695
- if (await contextMenu.show({
3696
- x: event.clientX,
3697
- y: event.clientY
3698
- }, event)) event.preventDefault();
3699
- };
3700
- }
3701
- getCommandStack() {
3702
- return this.commandStack;
3703
- }
3704
- /**
3705
- * Override this method to provide toolbar content for this part.
3706
- * This is a lightweight alternative to registering toolbar contributions
3707
- * for actions that are scoped to this part instance.
3708
- *
3709
- * IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
3710
- * The toolbar template is rendered in a different component (docks-toolbar), so direct method
3711
- * references lose their binding.
3712
- *
3713
- * ✅ Correct:
3714
- * @click=${() => this.myMethod()}
3715
- * @click=${(e) => this.handleClick(e)}
3716
- *
3717
- * ❌ Wrong (this will be bound to the toolbar, not your component):
3718
- * @click=${this.myMethod}
3719
- *
3720
- * Example:
3721
- * ```typescript
3722
- * protected renderToolbar() {
3723
- * return html`
3724
- * <wa-button @click=${() => this.save()} title="Save">
3725
- * <wa-icon name="save"></wa-icon>
3726
- * </wa-button>
3727
- * `;
3728
- * }
3729
- * ```
3730
- *
3731
- * @returns TemplateResult with toolbar items, or nothing if no toolbar needed
3732
- */
3733
- renderToolbar() {
3734
- return nothing;
3735
- }
3736
- /**
3737
- * Activates the tab that contains this part by walking up the DOM to the first
3738
- * docks-tabs ancestor and activating the tab panel that contains this part.
3739
- * Crosses Shadow DOM boundaries (e.g. wa-tab-group) via getRootNode().host.
3740
- * No-op if this part is not inside a docks-tabs / wa-tab-panel.
3741
- */
3742
- activateContainingTab() {
3743
- let el = this;
3744
- let panelName = null;
3745
- let tabsEl = null;
3746
- while (el) {
3747
- const tag = el.tagName?.toLowerCase();
3748
- if (tag === "wa-tab-panel") panelName = el.getAttribute("name");
3749
- if (tag === "docks-tabs") {
3750
- tabsEl = el;
3751
- break;
3752
- }
3753
- const parent = el.parentElement;
3754
- if (parent) el = parent;
3755
- else {
3756
- const root = el.getRootNode();
3757
- el = root instanceof ShadowRoot ? root.host : null;
3758
- }
3759
- }
3760
- if (tabsEl && panelName != null && panelName !== "") tabsEl.activate(panelName);
3761
- }
3762
- /**
3763
- * Override this method to provide context menu content for this part.
3764
- * This is a lightweight alternative to registering context menu contributions
3765
- * for actions that are scoped to this part instance.
3766
- *
3767
- * IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
3768
- * The context menu is rendered in a different component (contextmenu), so direct method
3769
- * references lose their binding.
3770
- *
3771
- * ✅ Correct:
3772
- * @click=${() => this.myMethod()}
3773
- * @click=${(e) => this.handleClick(e)}
3774
- *
3775
- * ❌ Wrong (this will be bound to the context menu, not your component):
3776
- * @click=${this.myMethod}
3777
- *
3778
- * Example:
3779
- * ```typescript
3780
- * protected renderContextMenu() {
3781
- * return html`
3782
- * <wa-dropdown-item @click=${() => this.open()}>
3783
- * <wa-icon name="folder-open"></wa-icon>
3784
- * Open
3785
- * </wa-dropdown-item>
3786
- * <wa-divider></wa-divider>
3787
- * <wa-dropdown-item @click=${() => this.delete()}>
3788
- * <wa-icon name="trash"></wa-icon>
3789
- * Delete
3790
- * </wa-dropdown-item>
3791
- * `;
3792
- * }
3793
- * ```
3794
- *
3795
- * @returns TemplateResult with context menu items, or nothing if no context menu needed
3796
- */
3797
- renderContextMenu() {
3798
- return nothing;
3799
- }
3800
- renderContent() {
3801
- return nothing;
3802
- }
3803
- /** Part-level toolbar contributions (`toolbar:${partId}`). */
3804
- getToolbarTarget() {
3805
- const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
3806
- return contributionKey ? `toolbar:${contributionKey}` : void 0;
3807
- }
3808
- /** Part-level context-menu contributions (`contextmenu:${partId}`). */
3809
- getContextMenuTarget() {
3810
- const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
3811
- return contributionKey ? `contextmenu:${contributionKey}` : void 0;
3812
- }
3813
- syncIsEditorCapability() {
3814
- const next = this.save !== DocksPart.prototype.save;
3815
- if (next === this.isEditor) return;
3816
- this.isEditor = next;
3817
- }
3818
- maybeActivateForCoupledEditors() {
3819
- const coupled = this.tabContribution?.coupledEditors;
3820
- if (!coupled?.length) return;
3821
- const active = activeEditorSignal.get();
3822
- if (!(active instanceof DocksPart)) return;
3823
- const editorId = active.tabContribution?.editorId;
3824
- if (!editorId || !coupled.includes(editorId)) return;
3825
- this.activateContainingTab();
3826
- }
3827
- render() {
3828
- const toolbarTarget = this.getToolbarTarget();
3829
- const contextMenuTarget = this.getContextMenuTarget();
3830
- const toolbarEnabled = this.tabContribution?.toolbar !== false;
3831
- const contextMenuEnabled = this.tabContribution?.contextMenu !== false;
3832
- const scrollMode = this.scrollMode;
3833
- const scopeTokens = this.isEditor ? ["system.editors", ".system.editors"] : [];
3834
- const content = this.renderContent();
3835
- const contentNode = scrollMode === "scroller" ? html`
3836
- <wa-scroller class="part-content-scroll" orientation="vertical">
3837
- <div class="part-content-inner">${content}</div>
3838
- </wa-scroller>
3839
- ` : html`<div class="part-content-inner">${content}</div>`;
3840
- return html`
3841
- <div class="part-shell">
3842
- ${toolbarEnabled ? html`
3843
- <docks-toolbar
3844
- class="part-toolbar"
3845
- id=${ifDefined(toolbarTarget)}
3846
- .scopeTokens=${scopeTokens}
3847
- .partToolbarRenderer=${() => this.renderToolbar()}>
3848
- </docks-toolbar>
3849
- ` : nothing}
3850
- <div class="part-content ${scrollMode === "native" ? "native-scroll" : ""}" @contextmenu=${contextMenuEnabled ? this.onContentContextMenu : void 0}>
3851
- ${contentNode}
3852
- </div>
3853
- ${contextMenuEnabled ? html`
3854
- <docks-contextmenu
3855
- id=${ifDefined(contextMenuTarget)}
3856
- .scopeTokens=${scopeTokens}
3857
- .partContextMenuRenderer=${() => this.renderContextMenu()}>
3858
- </docks-contextmenu>
3859
- ` : nothing}
3860
- </div>
3861
- `;
4161
+ const root = this.getRootNode();
4162
+ if (root instanceof ShadowRoot && root.host instanceof HTMLElement) return root.host;
4163
+ return null;
3862
4164
  }
3863
- updated(_changedProperties) {
3864
- super.updated(_changedProperties);
3865
- this.syncIsEditorCapability();
3866
- if (_changedProperties.has("tabContribution")) this.maybeActivateForCoupledEditors();
3867
- if (_changedProperties.has("dirty")) {
3868
- if (_changedProperties.get("dirty") !== void 0) this.dispatchEvent(new CustomEvent("dirty", {
3869
- detail: this.dirty,
3870
- bubbles: true
3871
- }));
4165
+ /**
4166
+ * Triggers a click on the element under the cursor to update selection before showing context menu.
4167
+ */
4168
+ triggerClickUnderCursor(mouseEvent) {
4169
+ const elementUnderCursor = this.getElementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
4170
+ if (elementUnderCursor) {
4171
+ const clickEvent = new MouseEvent("click", {
4172
+ bubbles: true,
4173
+ cancelable: true,
4174
+ view: window,
4175
+ clientX: mouseEvent.clientX,
4176
+ clientY: mouseEvent.clientY,
4177
+ screenX: mouseEvent.screenX,
4178
+ screenY: mouseEvent.screenY,
4179
+ button: 0,
4180
+ buttons: 0,
4181
+ detail: 1,
4182
+ which: 1
4183
+ });
4184
+ elementUnderCursor.dispatchEvent(clickEvent);
3872
4185
  }
3873
4186
  }
3874
- doClose() {}
3875
- disconnectedCallback() {
3876
- super.disconnectedCallback();
4187
+ /** Opens the menu at `position`. Returns false when there is nothing to show (no thin empty panel). */
4188
+ async show(position, mouseEvent) {
4189
+ if (!this.hasMenuBody()) return false;
4190
+ if (mouseEvent) {
4191
+ this.triggerClickUnderCursor(mouseEvent);
4192
+ await this.getHostPart()?.updateComplete;
4193
+ }
4194
+ if (this.isOpen) {
4195
+ this.isOpen = false;
4196
+ await this.updateComplete;
4197
+ }
4198
+ this.menuPosition = position;
4199
+ this.isOpen = true;
4200
+ await this.updateComplete;
4201
+ this.syncVirtualPopupAnchor();
4202
+ document.addEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
4203
+ return true;
3877
4204
  }
3878
- close() {
3879
- this.doClose();
4205
+ /** Points wa-dropdown's internal wa-popup at the pointer via a VirtualElement anchor. */
4206
+ syncVirtualPopupAnchor() {
4207
+ const popup = this.dropdownRef.value?.shadowRoot?.querySelector("wa-popup");
4208
+ if (!popup) return;
4209
+ popup.anchor = this.virtualAnchor;
4210
+ popup.reposition();
3880
4211
  }
3881
- connectedCallback() {
3882
- super.connectedCallback();
3883
- this.syncIsEditorCapability();
3884
- queueMicrotask(() => this.syncIsEditorCapability());
3885
- this.watch(activeEditorSignal, () => this.maybeActivateForCoupledEditors());
4212
+ onClose() {
4213
+ if (!this.isOpen) return;
4214
+ this.isOpen = false;
4215
+ document.removeEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
3886
4216
  }
3887
- save() {}
3888
- isDirty() {
3889
- return this.dirty;
4217
+ updated(changedProperties) {
4218
+ super.updated(changedProperties);
4219
+ if (changedProperties.has("isOpen") && this.isOpen) this.syncVirtualPopupAnchor();
3890
4220
  }
3891
- markDirty(dirty) {
3892
- this.dirty = dirty;
3893
- partDirtySignal.set(null);
3894
- partDirtySignal.set(this);
3895
- activePartSignal.set(null);
3896
- activePartSignal.set(this);
4221
+ renderContribution(contribution) {
4222
+ return renderDropdownContribution(contribution);
4223
+ }
4224
+ render() {
4225
+ const partContent = this.partContextMenuRenderer ? this.partContextMenuRenderer() : nothing;
4226
+ return html`
4227
+ <wa-dropdown
4228
+ ${ref(this.dropdownRef)}
4229
+ ?open=${this.isOpen}
4230
+ @submenu-opening=${this.handleSubmenuOpening}
4231
+ @wa-select=${handleDropdownWaSelect}
4232
+ @wa-after-hide=${this.onClose}>
4233
+ <span slot="trigger" hidden aria-hidden="true"></span>
4234
+
4235
+ ${partContent}
4236
+ ${this.contributions.map((c) => this.renderContribution(c))}
4237
+ </wa-dropdown>
4238
+ `;
3897
4239
  }
3898
4240
  static {
3899
- this.baseStyles = css`
4241
+ this.styles = css`
3900
4242
  :host {
3901
- display: block;
3902
- }
3903
-
3904
- .part-shell {
3905
- display: grid;
3906
- grid-template-rows: auto minmax(0, 1fr);
3907
- height: 100%;
3908
- width: 100%;
3909
- position: relative;
3910
- overflow: hidden;
3911
- }
3912
-
3913
- .part-content {
3914
- min-height: 0;
3915
- overflow: hidden;
3916
- position: relative;
3917
- }
3918
-
3919
- .part-content.native-scroll {
3920
- overflow: auto;
4243
+ position: fixed;
4244
+ top: 0;
4245
+ left: 0;
4246
+ width: 0;
4247
+ height: 0;
4248
+ pointer-events: none;
4249
+ z-index: 10000;
3921
4250
  }
3922
4251
 
3923
- .part-content-scroll {
3924
- width: 100%;
3925
- height: 100%;
4252
+ wa-dropdown {
4253
+ pointer-events: none;
4254
+ min-width: 200px;
3926
4255
  }
3927
4256
 
3928
- .part-content-inner {
3929
- height: 100%;
3930
- min-height: 100%;
4257
+ wa-dropdown:state(open) {
4258
+ pointer-events: auto;
3931
4259
  }
3932
-
3933
- .part-toolbar {
3934
- min-height: 0;
4260
+
4261
+ wa-dropdown::part(menu) {
4262
+ min-width: 200px;
3935
4263
  }
3936
4264
  `;
3937
4265
  }
3938
- static finalizeStyles(styles) {
3939
- const own = super.finalizeStyles(styles);
3940
- return [DocksPart.baseStyles, ...own];
3941
- }
3942
4266
  };
3943
- _decorate([property()], DocksPart.prototype, "dirty", void 0);
3944
- _decorate([property({ attribute: false })], DocksPart.prototype, "tabContribution", void 0);
3945
- _decorate([property({
3946
- type: Boolean,
3947
- attribute: false
3948
- })], DocksPart.prototype, "isEditor", void 0);
4267
+ _decorate([property({ attribute: false })], DocksContextMenu.prototype, "scopeTokens", void 0);
4268
+ _decorate([property({ attribute: false })], DocksContextMenu.prototype, "partContextMenuRenderer", void 0);
4269
+ _decorate([state()], DocksContextMenu.prototype, "contributions", void 0);
4270
+ _decorate([state()], DocksContextMenu.prototype, "isOpen", void 0);
4271
+ DocksContextMenu = _decorate([customElement("docks-contextmenu")], DocksContextMenu);
3949
4272
  //#endregion
3950
4273
  //#region src/parts/tabs.ts
3951
4274
  var _DocksTabs;
@@ -3959,6 +4282,8 @@ var DocksTabs = class DocksTabs extends DocksContainer {
3959
4282
  this.iconOnly = false;
3960
4283
  this.withToolbar = false;
3961
4284
  this.hideTabs = false;
4285
+ this.fitContent = false;
4286
+ this.fillHeight = false;
3962
4287
  this.itemSize = "m";
3963
4288
  this.contributions = [];
3964
4289
  this.tabGroup = createRef();
@@ -4011,6 +4336,11 @@ var DocksTabs = class DocksTabs extends DocksContainer {
4011
4336
  if (!this.tabGroup.value) return null;
4012
4337
  return this.tabGroup.value.getAttribute("active");
4013
4338
  }
4339
+ getTabPart(tabName) {
4340
+ const tabPanel = this.getTabPanel(tabName);
4341
+ if (!tabPanel) return null;
4342
+ return this.getPartFromPanel(tabPanel);
4343
+ }
4014
4344
  open(contribution) {
4015
4345
  if (this.contributions.find((c) => c.name === contribution.name)) {
4016
4346
  this.activate(contribution.name);
@@ -4260,6 +4590,95 @@ var DocksTabs = class DocksTabs extends DocksContainer {
4260
4590
  width: 100%;
4261
4591
  }
4262
4592
 
4593
+ :host([fit-content]) {
4594
+ display: flex;
4595
+ flex-direction: column;
4596
+ height: auto;
4597
+ max-height: 100%;
4598
+ min-height: 0;
4599
+ }
4600
+
4601
+ :host([fit-content]) wa-tab-group {
4602
+ display: flex;
4603
+ flex-direction: column;
4604
+ flex: 1 1 auto;
4605
+ min-height: 0;
4606
+ height: auto;
4607
+ max-height: 100%;
4608
+ }
4609
+
4610
+ :host([fit-content]) wa-tab-group::part(base) {
4611
+ display: flex;
4612
+ flex-direction: column;
4613
+ flex: 1 1 auto;
4614
+ min-height: 0;
4615
+ max-height: 100%;
4616
+ height: auto;
4617
+ }
4618
+
4619
+ :host([fit-content]) wa-tab-group::part(body) {
4620
+ flex: 1 1 auto;
4621
+ min-height: 0;
4622
+ height: auto;
4623
+ overflow-x: hidden;
4624
+ overflow-y: auto;
4625
+ }
4626
+
4627
+ :host([fit-content]) wa-tab-panel[active] {
4628
+ display: block;
4629
+ height: auto;
4630
+ overflow: visible;
4631
+ }
4632
+
4633
+ :host([fit-content]) wa-tab-panel > * {
4634
+ height: auto;
4635
+ min-height: 0;
4636
+ }
4637
+
4638
+ :host([fill-height]) {
4639
+ display: flex;
4640
+ flex-direction: column;
4641
+ height: 100%;
4642
+ min-height: 0;
4643
+ max-height: 100%;
4644
+ }
4645
+
4646
+ :host([fill-height]) wa-tab-group {
4647
+ display: flex;
4648
+ flex-direction: column;
4649
+ flex: 1 1 auto;
4650
+ min-height: 0;
4651
+ height: 100%;
4652
+ max-height: 100%;
4653
+ }
4654
+
4655
+ :host([fill-height]) wa-tab-group::part(base) {
4656
+ display: flex;
4657
+ flex-direction: column;
4658
+ flex: 1 1 auto;
4659
+ min-height: 0;
4660
+ max-height: 100%;
4661
+ height: 100%;
4662
+ }
4663
+
4664
+ :host([fill-height]) wa-tab-group::part(body) {
4665
+ flex: 1 1 auto;
4666
+ min-height: 0;
4667
+ overflow-x: hidden;
4668
+ overflow-y: auto;
4669
+ }
4670
+
4671
+ :host([fill-height]) wa-tab-panel[active] {
4672
+ display: block;
4673
+ height: auto;
4674
+ overflow: visible;
4675
+ }
4676
+
4677
+ :host([fill-height]) wa-tab-panel > * {
4678
+ height: auto;
4679
+ min-height: 0;
4680
+ }
4681
+
4263
4682
  wa-tab-group {
4264
4683
  height: 100%;
4265
4684
  width: 100%;
@@ -4487,6 +4906,16 @@ _decorate([property({
4487
4906
  reflect: true,
4488
4907
  attribute: "hide-tabs"
4489
4908
  })], DocksTabs.prototype, "hideTabs", void 0);
4909
+ _decorate([property({
4910
+ type: Boolean,
4911
+ reflect: true,
4912
+ attribute: "fit-content"
4913
+ })], DocksTabs.prototype, "fitContent", void 0);
4914
+ _decorate([property({
4915
+ type: Boolean,
4916
+ reflect: true,
4917
+ attribute: "fill-height"
4918
+ })], DocksTabs.prototype, "fillHeight", void 0);
4490
4919
  _decorate([property({
4491
4920
  reflect: true,
4492
4921
  attribute: "item-size"
@@ -4526,9 +4955,9 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
4526
4955
  this.gridChildren = [];
4527
4956
  this.resizing = null;
4528
4957
  this.resizeOverlay = null;
4529
- this.childrenLoaded = false;
4530
4958
  this.childStylesApplied = false;
4531
- this.settingsLoaded = false;
4959
+ this.refreshScheduled = false;
4960
+ this.layoutGeneration = 0;
4532
4961
  this.handleResize = (e) => {
4533
4962
  if (!this.resizing) return;
4534
4963
  const delta = (this.orientation === "horizontal" ? e.clientX : e.clientY) - this.resizing.startPos;
@@ -4578,56 +5007,108 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
4578
5007
  return this;
4579
5008
  }
4580
5009
  doBeforeUI() {
4581
- if (!this.childrenLoaded) {
4582
- this.mutationObserver = new MutationObserver(() => {
4583
- if (!this.childrenLoaded) this.loadChildren();
4584
- });
4585
- this.mutationObserver.observe(this, {
4586
- childList: true,
4587
- subtree: false
4588
- });
4589
- this.loadChildren();
4590
- }
5010
+ this.mutationObserver = new MutationObserver(() => {
5011
+ this.scheduleRefreshGridLayout();
5012
+ });
5013
+ this.mutationObserver.observe(this, {
5014
+ childList: true,
5015
+ subtree: false
5016
+ });
5017
+ this.scheduleRefreshGridLayout();
5018
+ }
5019
+ scheduleRefreshGridLayout() {
5020
+ if (this.refreshScheduled) return;
5021
+ this.refreshScheduled = true;
5022
+ queueMicrotask(() => {
5023
+ this.refreshScheduled = false;
5024
+ this.refreshGridLayout();
5025
+ });
4591
5026
  }
4592
- async loadChildren() {
4593
- const potentialChildren = Array.from(this.children).filter((child) => child.tagName !== "STYLE" && child.tagName !== "SCRIPT" && !child.classList.contains("resize-handle"));
4594
- if (potentialChildren.length === 0) return;
4595
- this.childrenLoaded = true;
4596
- if (this.mutationObserver) {
4597
- this.mutationObserver.disconnect();
4598
- this.mutationObserver = void 0;
4599
- }
4600
- this.gridChildren = potentialChildren;
4601
- if (!this.settingsLoaded) {
4602
- this.settingsLoaded = true;
4603
- const persisted = await this.getDialogSetting();
4604
- if (persisted && Array.isArray(persisted.sizes) && persisted.sizes.length === this.gridChildren.length) {
4605
- this.gridSizes = persisted.sizes;
4606
- this.requestUpdate();
4607
- return;
5027
+ getGridChildrenFromDom() {
5028
+ return Array.from(this.children).filter((child) => child.tagName !== "STYLE" && child.tagName !== "SCRIPT" && !child.classList.contains("resize-handle"));
5029
+ }
5030
+ static isNestedResizableGrid(child) {
5031
+ return child.tagName.toLowerCase() === "docks-resizable-grid";
5032
+ }
5033
+ applyChildLayoutStyles() {
5034
+ this.gridChildren.forEach((child, index) => {
5035
+ child.style.overflow = "hidden";
5036
+ child.style.height = "100%";
5037
+ child.style.width = "100%";
5038
+ child.style.gridColumn = this.orientation === "horizontal" ? `${index * 2 + 1}` : "1";
5039
+ child.style.gridRow = this.orientation === "vertical" ? `${index * 2 + 1}` : "1";
5040
+ if (!_DocksResizableGrid.isNestedResizableGrid(child)) {
5041
+ child.style.display = "flex";
5042
+ child.style.flexDirection = "column";
4608
5043
  }
5044
+ });
5045
+ }
5046
+ resolveGridSizes(childCount) {
5047
+ const parsedSizes = this.sizes?.split(",").map((s) => s.trim()).filter(Boolean) ?? [];
5048
+ if (parsedSizes.length === childCount) return parsedSizes;
5049
+ const equalSize = `${100 / childCount}%`;
5050
+ return Array.from({ length: childCount }, () => equalSize);
5051
+ }
5052
+ resolvePersistedSizes(persisted, childCount) {
5053
+ if (!persisted || typeof persisted !== "object") return null;
5054
+ const record = persisted;
5055
+ const byCount = record.sizesByCount?.[String(childCount)];
5056
+ if (Array.isArray(byCount) && byCount.length === childCount && byCount.every((size) => typeof size === "string")) return byCount;
5057
+ if (Array.isArray(record.sizes) && record.sizes.length === childCount && record.sizes.every((size) => typeof size === "string")) return record.sizes;
5058
+ return null;
5059
+ }
5060
+ async refreshGridLayout() {
5061
+ const generation = ++this.layoutGeneration;
5062
+ const potentialChildren = this.getGridChildrenFromDom();
5063
+ if (potentialChildren.length === 0) {
5064
+ this.gridChildren = [];
5065
+ this.gridSizes = [];
5066
+ this.childStylesApplied = false;
5067
+ this.requestUpdate();
5068
+ return;
4609
5069
  }
4610
- if (this.sizes) this.gridSizes = this.sizes.split(",").map((s) => s.trim());
4611
- else {
4612
- const equalSize = `${100 / this.gridChildren.length}%`;
4613
- this.gridSizes = this.gridChildren.map(() => equalSize);
5070
+ const identityChanged = potentialChildren.length !== this.gridChildren.length || potentialChildren.some((child, index) => child !== this.gridChildren[index]);
5071
+ this.gridChildren = potentialChildren;
5072
+ const persisted = await this.getDialogSetting();
5073
+ if (generation !== this.layoutGeneration) return;
5074
+ const restoredSizes = this.resolvePersistedSizes(persisted, this.gridChildren.length);
5075
+ if (restoredSizes) {
5076
+ const sizesChanged = restoredSizes.join("|") !== this.gridSizes.join("|");
5077
+ this.gridSizes = restoredSizes;
5078
+ if (identityChanged || sizesChanged) this.childStylesApplied = false;
5079
+ this.requestUpdate();
5080
+ return;
4614
5081
  }
5082
+ const nextSizes = this.resolveGridSizes(this.gridChildren.length);
5083
+ const sizesChanged = nextSizes.join("|") !== this.gridSizes.join("|");
5084
+ this.gridSizes = nextSizes;
5085
+ if (identityChanged || sizesChanged) this.childStylesApplied = false;
4615
5086
  this.requestUpdate();
4616
5087
  }
5088
+ doInitUI() {
5089
+ this.scheduleRefreshGridLayout();
5090
+ }
4617
5091
  async saveSizes() {
4618
5092
  if (this.gridSizes.length === 0) return;
5093
+ const persisted = await this.getDialogSetting();
5094
+ const existingByCount = persisted && typeof persisted === "object" ? persisted.sizesByCount ?? {} : {};
4619
5095
  await this.setDialogSetting({
4620
5096
  sizes: this.gridSizes,
5097
+ sizesByCount: {
5098
+ ...existingByCount,
5099
+ [String(this.gridSizes.length)]: this.gridSizes
5100
+ },
4621
5101
  orientation: this.orientation
4622
5102
  });
4623
5103
  }
4624
5104
  updated(changedProperties) {
4625
5105
  super.updated(changedProperties);
4626
- if (changedProperties.has("gridChildren") && !this.childStylesApplied && this.gridChildren.length > 0) {
5106
+ if (changedProperties.has("sizes")) this.scheduleRefreshGridLayout();
5107
+ if (!this.childStylesApplied && this.gridChildren.length > 0) {
4627
5108
  this.childStylesApplied = true;
4628
5109
  /**
4629
5110
  * Direct style manipulation is intentionally used here.
4630
- *
5111
+ *
4631
5112
  * Reasoning:
4632
5113
  * - Grid positioning (gridColumn/gridRow) must be computed dynamically based on
4633
5114
  * the number of children and orientation at runtime
@@ -4637,16 +5118,9 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
4637
5118
  * (e.g., child at index 0 → column 1, index 1 → column 3, etc.)
4638
5119
  * - This is a layout container whose primary job is to programmatically position
4639
5120
  * its children within a CSS grid system
5121
+ * - Nested resizable grids manage their own display mode and must not receive flex
4640
5122
  */
4641
- this.gridChildren.forEach((child, index) => {
4642
- child.style.overflow = "hidden";
4643
- child.style.height = "100%";
4644
- child.style.width = "100%";
4645
- child.style.gridColumn = this.orientation === "horizontal" ? `${index * 2 + 1}` : "1";
4646
- child.style.gridRow = this.orientation === "vertical" ? `${index * 2 + 1}` : "1";
4647
- child.style.display = "flex";
4648
- child.style.flexDirection = "column";
4649
- });
5123
+ this.applyChildLayoutStyles();
4650
5124
  }
4651
5125
  }
4652
5126
  startResize(e, handleIndex) {
@@ -4654,14 +5128,15 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
4654
5128
  if (handleIndex >= this.gridChildren.length - 1) return;
4655
5129
  const startPos = this.orientation === "horizontal" ? e.clientX : e.clientY;
4656
5130
  const containerSize = this.orientation === "horizontal" ? this.offsetWidth : this.offsetHeight;
5131
+ const startSizes = this.gridSizes.map((size) => {
5132
+ if (size.endsWith("%")) return parseFloat(size) / 100 * containerSize;
5133
+ else if (size.endsWith("px")) return parseFloat(size);
5134
+ else return parseFloat(size);
5135
+ });
4657
5136
  this.resizing = {
4658
5137
  handleIndex,
4659
5138
  startPos,
4660
- startSizes: this.gridSizes.map((size) => {
4661
- if (size.endsWith("%")) return parseFloat(size) / 100 * containerSize;
4662
- else if (size.endsWith("px")) return parseFloat(size);
4663
- else return parseFloat(size);
4664
- })
5139
+ startSizes
4665
5140
  };
4666
5141
  this.resizeOverlay = document.createElement("div");
4667
5142
  this.resizeOverlay.style.position = "fixed";
@@ -4765,6 +5240,6 @@ DocksResizableGrid = _DocksResizableGrid = _decorate([customElement("docks-resiz
4765
5240
  //#region src/parts/index.ts
4766
5241
  installOpenDropdownNativeContextMenuGuard();
4767
5242
  //#endregion
4768
- export { taskService as A, SIDEBAR_AUXILIARY as B, DocksElement as C, TOPIC_EXTENSIONS_CHANGED as D, keyBindingManager as E, MouseButton as F, SYSTEM_LAYOUTS as G, SIDEBAR_MAIN_BOTTOM as H, constants_exports as I, TOOLBAR_BOTTOM_CENTER as J, SYSTEM_VIEWS as K, ABOUT_TABS as L, appSettings as M, COMMAND_SAVE as N, extensionRegistry as O, HIDE_DOT_RESOURCE as P, TOOLBAR_MAIN_RIGHT as Q, EDITOR_AREA_MAIN as R, DocksDialogContent as S, sanitizeHtml as T, SIDEBAR_MAIN_TOOLBAR as U, SIDEBAR_MAIN as V, SYSTEM_ATTRIBUTIONS as W, TOOLBAR_MAIN as X, TOOLBAR_BOTTOM_END as Y, TOOLBAR_MAIN_CENTER as Z, validateFormDialogFields as _, renderDropdownContributions as a, deleteIndexedDbWorkspaceData as b, icon as c, filebrowserDialog as d, navigableInfoDialog as f, formDialogRequired as g, formDialog as h, renderDropdownContribution as i, TOPIC_SETTINGS_CHANGED as j, esmShService as k, parseIconSpec as l, infoDialog as m, DocksContainer as n, renderDropdownItem as o, confirmDialog as p, TOOLBAR_BOTTOM as q, renderCommandContribution as r, renderDropdownSubmenu as s, DocksPart as t, versionInfoDialog as u, promptDialog as v, parseMarkdownHtml as w, dialogService as x, appLoaderService as y, PANEL_BOTTOM as z };
5243
+ export { HIDE_DOT_RESOURCE as $, filebrowserDialog as A, dialogService as B, TOOLBAR_INFO as C, TOOLBAR_THEME_SWITCHER as D, TOOLBAR_TASKS as E, formDialogRequired as F, keyBindingManager as G, DocksElement as H, validateFormDialogFields as I, esmShService as J, TOPIC_EXTENSIONS_CHANGED as K, promptDialog as L, confirmDialog as M, infoDialog as N, VIEW_FILEBROWSER as O, formDialog as P, COMMAND_SAVE as Q, appLoaderService as R, TOOLBAR_FULLSCREEN as S, TOOLBAR_LAYOUT_SWITCHER as T, parseMarkdownHtml as U, DocksDialogContent as V, sanitizeHtml as W, TOPIC_SETTINGS_CHANGED as X, taskService as Y, appSettings as Z, CTXMENU_FILEBROWSER_RENAME as _, TOOLBAR_MAIN_CENTER as _t, renderDropdownItem as a, SIDEBAR_AUXILIARY as at, TOOLBAR_ACTIVE_PART_NAME as b, parseIconSpec as c, SIDEBAR_MAIN_BOTTOM as ct, DocksContainer as d, SYSTEM_LAYOUTS as dt, MouseButton as et, ABOUT_TAB_ATTRIBUTIONS as f, SYSTEM_VIEWS as ft, CTXMENU_FILEBROWSER_DELETE as g, TOOLBAR_MAIN as gt, ATTRIBUTION_ECLIPSE_DOCKS as h, TOOLBAR_BOTTOM_END as ht, renderDropdownContributions as i, PANEL_BOTTOM as it, navigableInfoDialog as j, VIEW_LOG_TERMINAL as k, versionInfoDialog as l, SIDEBAR_MAIN_TOOLBAR as lt, ABOUT_TAB_RELEASE as m, TOOLBAR_BOTTOM_CENTER as mt, renderCommandContribution as n, ABOUT_TABS as nt, renderDropdownSubmenu as o, SIDEBAR_AUXILIARY_BOTTOM as ot, ABOUT_TAB_PACKAGES as p, TOOLBAR_BOTTOM as pt, extensionRegistry as q, renderDropdownContribution as r, EDITOR_AREA_MAIN as rt, icon as s, SIDEBAR_MAIN as st, handleDropdownWaSelect as t, constants_exports as tt, DocksPart as u, SYSTEM_ATTRIBUTIONS as ut, SIDEBAR_TOOLBAR_EXTENSIONS as v, TOOLBAR_MAIN_RIGHT as vt, TOOLBAR_LANGUAGE_SELECTOR as w, TOOLBAR_FAST_VIEWS as x, SYSTEM_DEFAULT_FILE_ICONS as y, deleteIndexedDbWorkspaceData as z };
4769
5244
 
4770
- //# sourceMappingURL=parts-CRVxaDd-.js.map
5245
+ //# sourceMappingURL=parts-DQRktiiR.js.map