@eclipse-docks/core 0.7.126 → 0.7.130
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.js +4 -4
- package/dist/api/services.d.ts +4 -0
- package/dist/api/services.d.ts.map +1 -1
- package/dist/{api-B3RXoez_.js → api-oPg3Bv1S.js} +422 -293
- package/dist/api-oPg3Bv1S.js.map +1 -0
- package/dist/components/attribution.d.ts +1 -0
- package/dist/components/attribution.d.ts.map +1 -1
- package/dist/components/command.d.ts +4 -5
- package/dist/components/command.d.ts.map +1 -1
- package/dist/components/extensions.d.ts +3 -0
- package/dist/components/extensions.d.ts.map +1 -1
- package/dist/components/filebrowser.d.ts.map +1 -1
- package/dist/components/language-selector.d.ts.map +1 -1
- package/dist/components/layout-switcher.d.ts +1 -1
- package/dist/components/layout-switcher.d.ts.map +1 -1
- package/dist/components/npm-packages.d.ts +1 -0
- package/dist/components/npm-packages.d.ts.map +1 -1
- package/dist/components/release-history.d.ts +9 -2
- package/dist/components/release-history.d.ts.map +1 -1
- package/dist/components/tasks.d.ts.map +1 -1
- package/dist/core/apploader.d.ts +2 -9
- package/dist/core/apploader.d.ts.map +1 -1
- package/dist/core/contribution-names.d.ts +0 -2
- package/dist/core/contribution-names.d.ts.map +1 -1
- package/dist/core/contribution-targets.d.ts +1 -0
- package/dist/core/contribution-targets.d.ts.map +1 -1
- package/dist/core/contributionregistry.d.ts +3 -0
- package/dist/core/contributionregistry.d.ts.map +1 -1
- package/dist/core/dialogservice.d.ts +3 -1
- package/dist/core/dialogservice.d.ts.map +1 -1
- package/dist/core/dropdown-item.d.ts +43 -0
- package/dist/core/dropdown-item.d.ts.map +1 -0
- package/dist/core/dropdown-menu-utils.d.ts +5 -0
- package/dist/core/dropdown-menu-utils.d.ts.map +1 -1
- package/dist/core/layout-panels.d.ts +25 -0
- package/dist/core/layout-panels.d.ts.map +1 -0
- package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -1
- package/dist/dialogs/version-info-dialog.d.ts +18 -2
- package/dist/dialogs/version-info-dialog.d.ts.map +1 -1
- package/dist/externals/lit.js +1 -1
- package/dist/externals/webawesome.js +1 -1
- package/dist/index.js +4 -4
- package/dist/layouts/standard-layout.d.ts +9 -1
- package/dist/layouts/standard-layout.d.ts.map +1 -1
- package/dist/parts/contextmenu.d.ts +5 -2
- package/dist/parts/contextmenu.d.ts.map +1 -1
- package/dist/parts/index.d.ts.map +1 -1
- package/dist/parts/index.js +1 -1
- package/dist/parts/part.d.ts +4 -0
- package/dist/parts/part.d.ts.map +1 -1
- package/dist/parts/resizable-grid.d.ts +10 -3
- package/dist/parts/resizable-grid.d.ts.map +1 -1
- package/dist/parts/tabs.d.ts +6 -0
- package/dist/parts/tabs.d.ts.map +1 -1
- package/dist/{parts-CsoNFVTw.js → parts-CAt8aeU8.js} +1361 -975
- package/dist/parts-CAt8aeU8.js.map +1 -0
- package/dist/{webawesome-Y1_HnKa_.js → webawesome-BGXn04Mw.js} +18 -10
- package/dist/webawesome-BGXn04Mw.js.map +1 -0
- package/dist/{widget-DbLusgAH.js → widget-BqQtioK1.js} +11 -5
- package/dist/widget-BqQtioK1.js.map +1 -0
- package/dist/widgets/index.js +1 -1
- package/dist/{widgets-DnnSZhsi.js → widgets-C9V42Mqq.js} +2 -2
- package/dist/{widgets-DnnSZhsi.js.map → widgets-C9V42Mqq.js.map} +1 -1
- package/package.json +1 -1
- package/src/api/services.ts +20 -0
- package/src/commands/filebrowser-contributions.ts +0 -16
- package/src/components/attribution.ts +2 -0
- package/src/components/command.ts +45 -119
- package/src/components/extensions.ts +20 -3
- package/src/components/filebrowser.ts +15 -12
- package/src/components/language-selector.ts +0 -1
- package/src/components/layout-switcher.ts +39 -26
- package/src/components/npm-packages.ts +2 -0
- package/src/components/release-history.ts +29 -40
- package/src/components/tasks.ts +0 -1
- package/src/contributions/default-layout-contributions.ts +7 -43
- package/src/contributions/default-ui-contributions.ts +4 -4
- package/src/core/apploader.ts +7 -54
- package/src/core/contribution-names.ts +0 -3
- package/src/core/contribution-targets.ts +1 -0
- package/src/core/contributionregistry.ts +19 -3
- package/src/core/dialogservice.ts +76 -19
- package/src/core/dropdown-item.ts +187 -0
- package/src/core/dropdown-menu-utils.ts +59 -0
- package/src/core/layout-panels.ts +121 -0
- package/src/dialogs/navigable-info-dialog.ts +5 -2
- package/src/dialogs/version-info-dialog.ts +163 -21
- package/src/icons/icons.txt +4 -2
- package/src/icons/layout-standard-bottom-panel.svg +4 -4
- package/src/icons/layout-standard-full.svg +4 -4
- package/src/icons/layout-standard-left-aux.svg +8 -0
- package/src/icons/layout-standard-left-sidebar.svg +5 -0
- package/src/icons/layout-standard-right-aux.svg +8 -0
- package/src/icons/layout-standard-right-sidebar.svg +5 -0
- package/src/layouts/standard-layout.ts +81 -5
- package/src/parts/contextmenu.ts +39 -44
- package/src/parts/index.ts +4 -1
- package/src/parts/part.ts +26 -0
- package/src/parts/resizable-grid.ts +125 -57
- package/src/parts/tabs.ts +103 -0
- package/dist/api-B3RXoez_.js.map +0 -1
- package/dist/parts-CsoNFVTw.js.map +0 -1
- package/dist/webawesome-Y1_HnKa_.js.map +0 -1
- package/dist/widget-DbLusgAH.js.map +0 -1
- package/src/icons/layout-standard-bottom-sidebar.svg +0 -6
- package/src/icons/layout-standard.svg +0 -6
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { n as defaultLogger, o as rootContext, s as uiContext, t as createLogger } from "./logger-DT0_NW3S.js";
|
|
2
|
-
import {
|
|
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
3
|
import { n as subscribe, t as publish } from "./events-B_ZxkU_G.js";
|
|
4
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-
|
|
5
|
+
import "./webawesome-BGXn04Mw.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$
|
|
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";
|
|
@@ -435,7 +437,7 @@ var esmShService = new class EsmShService {
|
|
|
435
437
|
if (this.isHttpUrl(source)) return source;
|
|
436
438
|
const parsed = this.parseSource(source);
|
|
437
439
|
if (!parsed) {
|
|
438
|
-
logger$
|
|
440
|
+
logger$4.warn(`Could not parse source identifier: ${source}`);
|
|
439
441
|
return source;
|
|
440
442
|
}
|
|
441
443
|
return this.buildEsmShUrl(parsed, options);
|
|
@@ -1080,7 +1082,7 @@ var DocksDialogContent = class extends DocksElement {
|
|
|
1080
1082
|
};
|
|
1081
1083
|
//#endregion
|
|
1082
1084
|
//#region src/core/dialogservice.ts
|
|
1083
|
-
var logger$
|
|
1085
|
+
var logger$3 = createLogger("DialogService");
|
|
1084
1086
|
var DIALOG_CONTRIBUTION_TARGET = "dialogs";
|
|
1085
1087
|
var OK_BUTTON = {
|
|
1086
1088
|
id: "ok",
|
|
@@ -1106,6 +1108,20 @@ function getDialogContainer() {
|
|
|
1106
1108
|
}
|
|
1107
1109
|
return dialogContainer;
|
|
1108
1110
|
}
|
|
1111
|
+
function findWaDialog(root) {
|
|
1112
|
+
if (root instanceof Element && root.tagName.toLowerCase() === "wa-dialog") return root;
|
|
1113
|
+
const children = root instanceof Document || root instanceof DocumentFragment || root instanceof Element ? Array.from(root.children) : root instanceof ShadowRoot ? Array.from(root.children) : [];
|
|
1114
|
+
for (const child of children) {
|
|
1115
|
+
if (child instanceof Element && child.tagName.toLowerCase() === "wa-dialog") return child;
|
|
1116
|
+
if (child instanceof Element && child.shadowRoot) {
|
|
1117
|
+
const nested = findWaDialog(child.shadowRoot);
|
|
1118
|
+
if (nested) return nested;
|
|
1119
|
+
}
|
|
1120
|
+
const nested = findWaDialog(child);
|
|
1121
|
+
if (nested) return nested;
|
|
1122
|
+
}
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1109
1125
|
var DialogService = class {
|
|
1110
1126
|
constructor() {
|
|
1111
1127
|
this.contributions = /* @__PURE__ */ new Map();
|
|
@@ -1126,15 +1142,15 @@ var DialogService = class {
|
|
|
1126
1142
|
this.contributions.clear();
|
|
1127
1143
|
for (const contribution of contributions) {
|
|
1128
1144
|
if (!contribution.id) {
|
|
1129
|
-
logger$
|
|
1145
|
+
logger$3.warn("Dialog contribution missing id, skipping");
|
|
1130
1146
|
continue;
|
|
1131
1147
|
}
|
|
1132
1148
|
if (!contribution.component) {
|
|
1133
|
-
logger$
|
|
1149
|
+
logger$3.warn(`Dialog contribution "${contribution.id}" has no component function, skipping`);
|
|
1134
1150
|
continue;
|
|
1135
1151
|
}
|
|
1136
|
-
if (!contribution.onButton) {
|
|
1137
|
-
logger$
|
|
1152
|
+
if (!contribution.onButton && !contribution.selfContained) {
|
|
1153
|
+
logger$3.warn(`Dialog contribution "${contribution.id}" has no onButton callback, skipping`);
|
|
1138
1154
|
continue;
|
|
1139
1155
|
}
|
|
1140
1156
|
this.contributions.set(contribution.id, contribution);
|
|
@@ -1143,50 +1159,68 @@ var DialogService = class {
|
|
|
1143
1159
|
async open(dialogId, state) {
|
|
1144
1160
|
const contribution = this.contributions.get(dialogId);
|
|
1145
1161
|
if (!contribution) {
|
|
1146
|
-
logger$
|
|
1162
|
+
logger$3.error(`Dialog "${dialogId}" not found`);
|
|
1147
1163
|
throw new Error(`Dialog "${dialogId}" not found`);
|
|
1148
1164
|
}
|
|
1149
1165
|
return new Promise((resolve) => {
|
|
1150
1166
|
const container = getDialogContainer();
|
|
1151
|
-
let
|
|
1167
|
+
let closed = false;
|
|
1152
1168
|
let dialogContentElement = null;
|
|
1153
1169
|
const cleanup = async () => {
|
|
1154
|
-
if (
|
|
1155
|
-
|
|
1170
|
+
if (closed) return;
|
|
1171
|
+
closed = true;
|
|
1156
1172
|
if (dialogContentElement) try {
|
|
1157
1173
|
await dialogContentElement.dispose();
|
|
1158
1174
|
} catch (error) {
|
|
1159
1175
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1160
|
-
logger$
|
|
1176
|
+
logger$3.error(`Error disposing dialog content for "${dialogId}": ${errorMessage}`);
|
|
1161
1177
|
}
|
|
1162
1178
|
try {
|
|
1163
1179
|
const result = dialogContentElement ? dialogContentElement.getResult() : void 0;
|
|
1164
|
-
await contribution.onButton("close", result, stateWithClose);
|
|
1180
|
+
if (contribution.onButton) await contribution.onButton("close", result, stateWithClose);
|
|
1165
1181
|
} catch (error) {
|
|
1166
1182
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1167
|
-
logger$
|
|
1183
|
+
logger$3.error(`Error executing close callback for dialog "${dialogId}": ${errorMessage}`);
|
|
1168
1184
|
}
|
|
1169
1185
|
render(html``, container);
|
|
1170
1186
|
resolve();
|
|
1171
1187
|
};
|
|
1188
|
+
const closeDialog = () => {
|
|
1189
|
+
if (closed) return;
|
|
1190
|
+
const dialog = findWaDialog(container);
|
|
1191
|
+
if (dialog && dialog.open !== false) {
|
|
1192
|
+
dialog.open = false;
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
cleanup();
|
|
1196
|
+
};
|
|
1197
|
+
const handleAfterHide = () => {
|
|
1198
|
+
cleanup();
|
|
1199
|
+
};
|
|
1172
1200
|
const handleButtonClick = async (buttonId) => {
|
|
1201
|
+
if (!contribution.onButton) return;
|
|
1173
1202
|
try {
|
|
1174
1203
|
const result = dialogContentElement ? dialogContentElement.getResult() : void 0;
|
|
1175
|
-
if (await contribution.onButton(buttonId, result, stateWithClose) !== false)
|
|
1204
|
+
if (await contribution.onButton(buttonId, result, stateWithClose) !== false) closeDialog();
|
|
1176
1205
|
} catch (error) {
|
|
1177
1206
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1178
|
-
logger$
|
|
1179
|
-
|
|
1207
|
+
logger$3.error(`Error executing button callback for dialog "${dialogId}": ${errorMessage}`);
|
|
1208
|
+
closeDialog();
|
|
1180
1209
|
}
|
|
1181
1210
|
};
|
|
1182
1211
|
const buttons = contribution.buttons && contribution.buttons.length > 0 ? contribution.buttons : [OK_BUTTON];
|
|
1183
|
-
if (state && typeof state === "object") state.close = cleanup;
|
|
1184
1212
|
const stateWithClose = {
|
|
1185
1213
|
...state,
|
|
1186
|
-
close:
|
|
1214
|
+
close: closeDialog,
|
|
1215
|
+
onAfterHide: handleAfterHide
|
|
1187
1216
|
};
|
|
1188
|
-
|
|
1189
|
-
|
|
1217
|
+
if (state && typeof state === "object") {
|
|
1218
|
+
state.close = closeDialog;
|
|
1219
|
+
state.onAfterHide = handleAfterHide;
|
|
1220
|
+
}
|
|
1221
|
+
const dialogLabel = state && typeof state === "object" && typeof state.label === "string" ? state.label : contribution.label || dialogId;
|
|
1222
|
+
render(contribution.selfContained ? contribution.component(stateWithClose) : html`
|
|
1223
|
+
<wa-dialog label="${dialogLabel}" open @wa-after-hide=${handleAfterHide}>
|
|
1190
1224
|
<style>
|
|
1191
1225
|
.dialog-service-content {
|
|
1192
1226
|
display: flex;
|
|
@@ -1218,13 +1252,14 @@ var DialogService = class {
|
|
|
1218
1252
|
@dialog-cancel=${() => {
|
|
1219
1253
|
const cancelButton = buttons.find((b) => b.id === "cancel");
|
|
1220
1254
|
if (cancelButton) handleButtonClick(cancelButton.id);
|
|
1221
|
-
else
|
|
1255
|
+
else closeDialog();
|
|
1222
1256
|
}}>
|
|
1223
1257
|
${contribution.component(state)}
|
|
1224
1258
|
|
|
1225
1259
|
<div class="dialog-service-footer">
|
|
1226
1260
|
${buttons.map((button) => html`
|
|
1227
1261
|
<wa-button
|
|
1262
|
+
data-dialog-button="${button.id}"
|
|
1228
1263
|
variant="${button.variant || "default"}"
|
|
1229
1264
|
?disabled=${button.disabled}
|
|
1230
1265
|
@click=${() => handleButtonClick(button.id)}
|
|
@@ -1747,7 +1782,7 @@ async function deleteIndexedDbWorkspaceData(directory) {
|
|
|
1747
1782
|
}
|
|
1748
1783
|
//#endregion
|
|
1749
1784
|
//#region src/core/marketplaceregistry.ts
|
|
1750
|
-
var logger$
|
|
1785
|
+
var logger$2 = createLogger("MarketplaceRegistry");
|
|
1751
1786
|
var TOPIC_MARKETPLACE_CHANGED = "events/marketplaceregistry/changed";
|
|
1752
1787
|
var KEY_CATALOG_URLS = "marketplace.catalogUrls";
|
|
1753
1788
|
var MarketplaceRegistry = class {
|
|
@@ -1756,7 +1791,7 @@ var MarketplaceRegistry = class {
|
|
|
1756
1791
|
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
1757
1792
|
this.loadCatalogUrls().then(() => {
|
|
1758
1793
|
this.refreshCatalogs().catch((err) => {
|
|
1759
|
-
logger$
|
|
1794
|
+
logger$2.error(`Failed to refresh catalogs on init: ${err.message}`);
|
|
1760
1795
|
});
|
|
1761
1796
|
});
|
|
1762
1797
|
}
|
|
@@ -1765,7 +1800,7 @@ var MarketplaceRegistry = class {
|
|
|
1765
1800
|
const urls = await appSettings.get(KEY_CATALOG_URLS);
|
|
1766
1801
|
this.catalogUrls = Array.isArray(urls) ? urls : [];
|
|
1767
1802
|
} catch (error) {
|
|
1768
|
-
logger$
|
|
1803
|
+
logger$2.error(`Failed to load catalog URLs: ${error}`);
|
|
1769
1804
|
this.catalogUrls = [];
|
|
1770
1805
|
}
|
|
1771
1806
|
}
|
|
@@ -1779,28 +1814,28 @@ var MarketplaceRegistry = class {
|
|
|
1779
1814
|
async addCatalogUrl(url) {
|
|
1780
1815
|
if (!this.isValidUrl(url)) throw new Error(`Invalid catalog URL: ${url}`);
|
|
1781
1816
|
if (this.catalogUrls.includes(url)) {
|
|
1782
|
-
logger$
|
|
1817
|
+
logger$2.debug(`Catalog URL already exists: ${url}`);
|
|
1783
1818
|
return;
|
|
1784
1819
|
}
|
|
1785
1820
|
this.catalogUrls.push(url);
|
|
1786
1821
|
await this.saveCatalogUrls();
|
|
1787
|
-
logger$
|
|
1822
|
+
logger$2.debug(`Added catalog URL: ${url}`);
|
|
1788
1823
|
try {
|
|
1789
1824
|
await this.refreshCatalogs();
|
|
1790
1825
|
} catch (error) {
|
|
1791
|
-
logger$
|
|
1826
|
+
logger$2.warn(`Failed to refresh catalogs immediately after adding: ${error}`);
|
|
1792
1827
|
}
|
|
1793
1828
|
}
|
|
1794
1829
|
async addCatalogUrls(urls) {
|
|
1795
1830
|
let added = 0;
|
|
1796
1831
|
for (const url of urls) {
|
|
1797
1832
|
if (!this.isValidUrl(url)) {
|
|
1798
|
-
logger$
|
|
1833
|
+
logger$2.warn(`Skipping invalid catalog URL: ${url}`);
|
|
1799
1834
|
continue;
|
|
1800
1835
|
}
|
|
1801
1836
|
if (this.catalogUrls.includes(url)) continue;
|
|
1802
1837
|
this.catalogUrls.push(url);
|
|
1803
|
-
logger$
|
|
1838
|
+
logger$2.debug(`Added catalog URL: ${url}`);
|
|
1804
1839
|
added++;
|
|
1805
1840
|
}
|
|
1806
1841
|
if (added === 0) return;
|
|
@@ -1808,7 +1843,7 @@ var MarketplaceRegistry = class {
|
|
|
1808
1843
|
try {
|
|
1809
1844
|
await this.refreshCatalogs();
|
|
1810
1845
|
} catch (error) {
|
|
1811
|
-
logger$
|
|
1846
|
+
logger$2.warn(`Failed to refresh catalogs after adding URLs: ${error}`);
|
|
1812
1847
|
}
|
|
1813
1848
|
}
|
|
1814
1849
|
async removeCatalogUrl(url) {
|
|
@@ -1816,7 +1851,7 @@ var MarketplaceRegistry = class {
|
|
|
1816
1851
|
if (index === -1) return;
|
|
1817
1852
|
this.catalogUrls.splice(index, 1);
|
|
1818
1853
|
await this.saveCatalogUrls();
|
|
1819
|
-
logger$
|
|
1854
|
+
logger$2.info(`Removed catalog URL: ${url}`);
|
|
1820
1855
|
}
|
|
1821
1856
|
getCatalogUrls() {
|
|
1822
1857
|
return [...this.catalogUrls];
|
|
@@ -1847,7 +1882,7 @@ var MarketplaceRegistry = class {
|
|
|
1847
1882
|
extensions: data.extensions || []
|
|
1848
1883
|
};
|
|
1849
1884
|
} catch (error) {
|
|
1850
|
-
logger$
|
|
1885
|
+
logger$2.error(`Failed to fetch catalog from ${url}: ${error}`);
|
|
1851
1886
|
throw error;
|
|
1852
1887
|
} finally {
|
|
1853
1888
|
this.loadingPromises.delete(url);
|
|
@@ -1858,7 +1893,7 @@ var MarketplaceRegistry = class {
|
|
|
1858
1893
|
}
|
|
1859
1894
|
async refreshCatalogs() {
|
|
1860
1895
|
const promises = this.catalogUrls.map((url) => this.fetchCatalog(url).catch((error) => {
|
|
1861
|
-
logger$
|
|
1896
|
+
logger$2.warn(`Failed to refresh catalog ${url}: ${error.message}`);
|
|
1862
1897
|
return null;
|
|
1863
1898
|
}));
|
|
1864
1899
|
const catalogs = await Promise.allSettled(promises);
|
|
@@ -1878,8 +1913,8 @@ var MarketplaceRegistry = class {
|
|
|
1878
1913
|
});
|
|
1879
1914
|
}
|
|
1880
1915
|
});
|
|
1881
|
-
logger$
|
|
1882
|
-
if (registeredCount > 0) logger$
|
|
1916
|
+
logger$2.debug(`Refreshed ${this.catalogUrls.length} catalogs, ${registeredCount} extensions registered`);
|
|
1917
|
+
if (registeredCount > 0) logger$2.info(`Marketplace: ${registeredCount} new extension(s) available`);
|
|
1883
1918
|
publish(TOPIC_MARKETPLACE_CHANGED, { type: "refreshed" });
|
|
1884
1919
|
}
|
|
1885
1920
|
getMarketplaceExtension(extensionId) {
|
|
@@ -1908,16 +1943,10 @@ rootContext.put("marketplaceRegistry", marketplaceRegistry);
|
|
|
1908
1943
|
* - Application: App-specific code, gs-* components, contributions
|
|
1909
1944
|
* - App Loader: Bridge between framework and application
|
|
1910
1945
|
*/
|
|
1911
|
-
var logger = createLogger("AppLoader");
|
|
1946
|
+
var logger$1 = createLogger("AppLoader");
|
|
1912
1947
|
function getLayoutIdFromApp(app) {
|
|
1913
|
-
|
|
1914
|
-
|
|
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;
|
|
1948
|
+
const layout = app?.layout ?? "standard";
|
|
1949
|
+
return typeof layout === "object" ? layout.id : layout;
|
|
1921
1950
|
}
|
|
1922
1951
|
/**
|
|
1923
1952
|
* Extracts error message from an error object.
|
|
@@ -1946,9 +1975,6 @@ var appLoaderService = new class AppLoaderService {
|
|
|
1946
1975
|
static {
|
|
1947
1976
|
this.PREFERRED_APP_KEY = "preferredAppName";
|
|
1948
1977
|
}
|
|
1949
|
-
static {
|
|
1950
|
-
this.PREFERRED_LAYOUT_KEY = "preferredLayoutId";
|
|
1951
|
-
}
|
|
1952
1978
|
/**
|
|
1953
1979
|
* Register an application with the framework.
|
|
1954
1980
|
* Optionally starts the apploader automatically after registration.
|
|
@@ -1967,7 +1993,8 @@ var appLoaderService = new class AppLoaderService {
|
|
|
1967
1993
|
}
|
|
1968
1994
|
app.name = app.name ?? "app";
|
|
1969
1995
|
app.version = app.version ?? "0.0.0";
|
|
1970
|
-
|
|
1996
|
+
app.layout = app.layout ?? "standard";
|
|
1997
|
+
if (this.apps.has(app.name)) logger$1.warn(`App '${app.name}' is already registered. Overwriting.`);
|
|
1971
1998
|
if (app.marketplaceCatalogUrls?.length) marketplaceRegistry.addCatalogUrls(app.marketplaceCatalogUrls).catch(() => {});
|
|
1972
1999
|
this.apps.set(app.name, app);
|
|
1973
2000
|
if (options?.defaultAppName) this.defaultAppName = options.defaultAppName;
|
|
@@ -1984,13 +2011,13 @@ var appLoaderService = new class AppLoaderService {
|
|
|
1984
2011
|
*/
|
|
1985
2012
|
async start() {
|
|
1986
2013
|
if (this.started) {
|
|
1987
|
-
logger.debug("AppLoader already started");
|
|
2014
|
+
logger$1.debug("AppLoader already started");
|
|
1988
2015
|
return;
|
|
1989
2016
|
}
|
|
1990
2017
|
this.started = true;
|
|
1991
2018
|
const appIdFromUrl = new URLSearchParams(window.location.search).get("appId");
|
|
1992
2019
|
const appIdFromPath = extractAppIdFromPath();
|
|
1993
|
-
if (appIdFromPath) logger.info(`Extracted app ID from current page path: ${appIdFromPath}`);
|
|
2020
|
+
if (appIdFromPath) logger$1.info(`Extracted app ID from current page path: ${appIdFromPath}`);
|
|
1994
2021
|
const appToLoad = await this.selectAppToLoad({
|
|
1995
2022
|
appIdFromUrl,
|
|
1996
2023
|
appIdFromPath
|
|
@@ -2018,10 +2045,10 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2018
2045
|
if (!app) throw new Error(`App '${appName}' not found. Make sure it's registered.`);
|
|
2019
2046
|
this.dispatchLoadProgress("Starting…");
|
|
2020
2047
|
if (this.currentApp) {
|
|
2021
|
-
logger.info(`Disposing current app: ${this.currentApp.name}`);
|
|
2048
|
+
logger$1.info(`Disposing current app: ${this.currentApp.name}`);
|
|
2022
2049
|
if (this.currentApp.dispose) await this.currentApp.dispose();
|
|
2023
2050
|
if (this.currentApp.extensions && this.currentApp.extensions.length > 0) {
|
|
2024
|
-
logger.info(`Disabling ${this.currentApp.extensions.length} extensions...`);
|
|
2051
|
+
logger$1.info(`Disabling ${this.currentApp.extensions.length} extensions...`);
|
|
2025
2052
|
this.currentApp.extensions.forEach((extId) => {
|
|
2026
2053
|
extensionRegistry.disable(extId);
|
|
2027
2054
|
});
|
|
@@ -2037,19 +2064,19 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2037
2064
|
});
|
|
2038
2065
|
}
|
|
2039
2066
|
if (app.contributions) {
|
|
2040
|
-
logger.info("Registering app contributions...");
|
|
2067
|
+
logger$1.info("Registering app contributions...");
|
|
2041
2068
|
if (app.contributions.ui) {
|
|
2042
2069
|
app.contributions.ui.forEach((contribution) => {
|
|
2043
2070
|
const target = contribution.target;
|
|
2044
2071
|
if (target) contributionRegistry.registerContribution(target, contribution);
|
|
2045
2072
|
});
|
|
2046
|
-
logger.info(`Registered ${app.contributions.ui.length} UI contributions`);
|
|
2073
|
+
logger$1.info(`Registered ${app.contributions.ui.length} UI contributions`);
|
|
2047
2074
|
}
|
|
2048
2075
|
if (app.contributions.extensions) {
|
|
2049
2076
|
app.contributions.extensions.forEach((extension) => {
|
|
2050
2077
|
extensionRegistry.registerExtension(extension);
|
|
2051
2078
|
});
|
|
2052
|
-
logger.info(`Registered ${app.contributions.extensions.length} app extensions`);
|
|
2079
|
+
logger$1.info(`Registered ${app.contributions.extensions.length} app extensions`);
|
|
2053
2080
|
}
|
|
2054
2081
|
}
|
|
2055
2082
|
const extensionsSet = new Set(app.extensions || []);
|
|
@@ -2058,19 +2085,18 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2058
2085
|
if (app.extensions.length > 0) {
|
|
2059
2086
|
this.dispatchLoadProgress("Enabling extensions…");
|
|
2060
2087
|
await Promise.all(app.extensions.map((extId) => extensionRegistry.enableAsync(extId).catch((e) => {
|
|
2061
|
-
logger.error(`Failed to load extension ${extId}: ${getErrorMessage(e)}`);
|
|
2088
|
+
logger$1.error(`Failed to load extension ${extId}: ${getErrorMessage(e)}`);
|
|
2062
2089
|
})));
|
|
2063
2090
|
}
|
|
2064
2091
|
this.dispatchLoadProgress("Loading extensions…");
|
|
2065
2092
|
await extensionRegistry.loadEnabledExtensions();
|
|
2066
2093
|
if (app.initialize) {
|
|
2067
2094
|
this.dispatchLoadProgress("Initializing…");
|
|
2068
|
-
logger.info(`Initializing ${app.name}...`);
|
|
2095
|
+
logger$1.info(`Initializing ${app.name}...`);
|
|
2069
2096
|
await app.initialize();
|
|
2070
2097
|
}
|
|
2071
2098
|
this.currentApp = app;
|
|
2072
|
-
logger.info(`App ${app.name} loaded successfully`);
|
|
2073
|
-
this.preferredLayoutId = await this.getPreferredLayoutId();
|
|
2099
|
+
logger$1.info(`App ${app.name} loaded successfully`);
|
|
2074
2100
|
this.updateDocumentMetadata(app);
|
|
2075
2101
|
if (container) {
|
|
2076
2102
|
this.dispatchLoadProgress("Rendering layout…");
|
|
@@ -2103,19 +2129,17 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2103
2129
|
*/
|
|
2104
2130
|
renderApp(container) {
|
|
2105
2131
|
if (!this.currentApp) throw new Error("No app loaded. Call loadApp() first.");
|
|
2106
|
-
const layoutId =
|
|
2132
|
+
const layoutId = getLayoutIdFromApp(this.currentApp);
|
|
2107
2133
|
const layouts = contributionRegistry.getContributions(SYSTEM_LAYOUTS);
|
|
2108
2134
|
let layout = layouts.find((c) => c.id === layoutId);
|
|
2109
2135
|
if (!layout) {
|
|
2110
|
-
logger.warn(`Layout '${layoutId}' not found, falling back to 'standard'`);
|
|
2136
|
+
logger$1.warn(`Layout '${layoutId}' not found, falling back to 'standard'`);
|
|
2111
2137
|
layout = layouts.find((c) => c.id === "standard");
|
|
2112
2138
|
}
|
|
2113
2139
|
if (!layout) throw new Error(`No layout found for layoutId '${layoutId}' and no 'standard' layout registered.`);
|
|
2114
2140
|
const r = layout.component;
|
|
2115
2141
|
let effectiveAttributes = {};
|
|
2116
2142
|
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
2143
|
container.innerHTML = "";
|
|
2120
2144
|
if (typeof r === "string") {
|
|
2121
2145
|
const el = document.createElement(r);
|
|
@@ -2128,7 +2152,7 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2128
2152
|
} else if (typeof r === "function") render(r(), container);
|
|
2129
2153
|
else throw new Error(`Layout '${layout.id}' has invalid component.`);
|
|
2130
2154
|
if (layout.onShow) requestAnimationFrame(() => {
|
|
2131
|
-
Promise.resolve(layout.onShow()).catch((err) => logger.error(`Layout onShow failed for '${layout.id}': ${getErrorMessage(err)}`));
|
|
2155
|
+
Promise.resolve(layout.onShow()).catch((err) => logger$1.error(`Layout onShow failed for '${layout.id}': ${getErrorMessage(err)}`));
|
|
2132
2156
|
});
|
|
2133
2157
|
}
|
|
2134
2158
|
/**
|
|
@@ -2150,7 +2174,7 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2150
2174
|
try {
|
|
2151
2175
|
return await appSettings.get(AppLoaderService.PREFERRED_APP_KEY);
|
|
2152
2176
|
} catch (error) {
|
|
2153
|
-
logger.debug(`Failed to get preferred app ID from settings: ${getErrorMessage(error)}`);
|
|
2177
|
+
logger$1.debug(`Failed to get preferred app ID from settings: ${getErrorMessage(error)}`);
|
|
2154
2178
|
return;
|
|
2155
2179
|
}
|
|
2156
2180
|
}
|
|
@@ -2162,9 +2186,9 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2162
2186
|
try {
|
|
2163
2187
|
await appSettings.set(AppLoaderService.PREFERRED_APP_KEY, appId);
|
|
2164
2188
|
this.defaultAppName = appId;
|
|
2165
|
-
logger.info(`Set preferred app to: ${appId}`);
|
|
2189
|
+
logger$1.info(`Set preferred app to: ${appId}`);
|
|
2166
2190
|
} catch (error) {
|
|
2167
|
-
logger.error(`Failed to persist preferred app: ${getErrorMessage(error)}`);
|
|
2191
|
+
logger$1.error(`Failed to persist preferred app: ${getErrorMessage(error)}`);
|
|
2168
2192
|
throw error;
|
|
2169
2193
|
}
|
|
2170
2194
|
}
|
|
@@ -2172,28 +2196,7 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2172
2196
|
return contributionRegistry.getContributions(SYSTEM_LAYOUTS);
|
|
2173
2197
|
}
|
|
2174
2198
|
getCurrentLayoutId() {
|
|
2175
|
-
return
|
|
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
|
-
}
|
|
2199
|
+
return getLayoutIdFromApp(this.currentApp);
|
|
2197
2200
|
}
|
|
2198
2201
|
/**
|
|
2199
2202
|
* Select which app to load based on priority:
|
|
@@ -2208,26 +2211,26 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2208
2211
|
if (appIdFromUrl) {
|
|
2209
2212
|
const name = this.findAppNameBySegment(appIdFromUrl) ?? appIdFromUrl;
|
|
2210
2213
|
if (this.apps.has(name)) {
|
|
2211
|
-
logger.info(`Loading app specified by URL parameter 'appId': ${name}`);
|
|
2214
|
+
logger$1.info(`Loading app specified by URL parameter 'appId': ${name}`);
|
|
2212
2215
|
return name;
|
|
2213
2216
|
}
|
|
2214
|
-
logger.warn(`App '${appIdFromUrl}' from URL parameter not found`);
|
|
2217
|
+
logger$1.warn(`App '${appIdFromUrl}' from URL parameter not found`);
|
|
2215
2218
|
}
|
|
2216
2219
|
if (appIdFromPath) {
|
|
2217
2220
|
const name = this.findAppNameBySegment(appIdFromPath);
|
|
2218
2221
|
if (name) {
|
|
2219
|
-
logger.info(`Loading app from URL path: ${appIdFromPath}`);
|
|
2222
|
+
logger$1.info(`Loading app from URL path: ${appIdFromPath}`);
|
|
2220
2223
|
return name;
|
|
2221
2224
|
}
|
|
2222
|
-
logger.debug(`App for path '${appIdFromPath}' not found, continuing search`);
|
|
2225
|
+
logger$1.debug(`App for path '${appIdFromPath}' not found, continuing search`);
|
|
2223
2226
|
}
|
|
2224
2227
|
const preferred = await this.getPreferredAppId();
|
|
2225
2228
|
if (preferred && this.apps.has(preferred)) {
|
|
2226
|
-
logger.info(`Loading preferred app from settings: ${preferred}`);
|
|
2229
|
+
logger$1.info(`Loading preferred app from settings: ${preferred}`);
|
|
2227
2230
|
return preferred;
|
|
2228
2231
|
}
|
|
2229
2232
|
if (this.defaultAppName && this.apps.has(this.defaultAppName)) return this.defaultAppName;
|
|
2230
|
-
if (this.defaultAppName) logger.warn(`Default app '${this.defaultAppName}' not found`);
|
|
2233
|
+
if (this.defaultAppName) logger$1.warn(`Default app '${this.defaultAppName}' not found`);
|
|
2231
2234
|
const registeredApps = this.getRegisteredApps();
|
|
2232
2235
|
if (registeredApps.length > 0) return registeredApps[0].name;
|
|
2233
2236
|
}
|
|
@@ -2642,7 +2645,9 @@ var DocksNavigableInfoDialogContent = class DocksNavigableInfoDialogContent exte
|
|
|
2642
2645
|
action.callback();
|
|
2643
2646
|
}
|
|
2644
2647
|
handleClose() {
|
|
2645
|
-
if (this.
|
|
2648
|
+
if (this.resolveCallback) this.resolveCallback();
|
|
2649
|
+
const dialog = this.closest("wa-dialog");
|
|
2650
|
+
if (dialog && dialog.open !== false) dialog.open = false;
|
|
2646
2651
|
}
|
|
2647
2652
|
static {
|
|
2648
2653
|
this.styles = [...DocksDialogContent.styles, css`
|
|
@@ -2983,300 +2988,665 @@ function filebrowserDialog(mode = "either") {
|
|
|
2983
2988
|
});
|
|
2984
2989
|
}
|
|
2985
2990
|
//#endregion
|
|
2986
|
-
//#region src/
|
|
2987
|
-
var
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
var
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
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", "");
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
|
-
render() {
|
|
3021
|
-
const app = appLoaderService.getCurrentApp();
|
|
3022
|
-
return html`
|
|
3023
|
-
<div class="dialog-body">
|
|
3024
|
-
${app?.description ? html`<small>${app.description}</small>` : ""}
|
|
3025
|
-
<docks-tabs id=${ABOUT_TABS}></docks-tabs>
|
|
3026
|
-
</div>
|
|
3027
|
-
`;
|
|
3028
|
-
}
|
|
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
|
-
}
|
|
2991
|
+
//#region src/core/contribution-names.ts
|
|
2992
|
+
var VIEW_FILEBROWSER = "view.filebrowser";
|
|
2993
|
+
var VIEW_LOG_TERMINAL = "view.logTerminal";
|
|
2994
|
+
var TOOLBAR_INFO = "toolbar.info";
|
|
2995
|
+
var TOOLBAR_FAST_VIEWS = "toolbar.fastViews";
|
|
2996
|
+
var TOOLBAR_LANGUAGE_SELECTOR = "toolbar.languageSelector";
|
|
2997
|
+
/** Main toolbar (right): layout picker (`docks-layout-switcher`). */
|
|
2998
|
+
var TOOLBAR_LAYOUT_SWITCHER = "toolbar.layoutSwitcher";
|
|
2999
|
+
/** Main toolbar (right): dark/light theme toggle (`switch_theme`). */
|
|
3000
|
+
var TOOLBAR_THEME_SWITCHER = "toolbar.themeSwitcher";
|
|
3001
|
+
/** Main toolbar (right): document fullscreen toggle (`fullscreen`). */
|
|
3002
|
+
var TOOLBAR_FULLSCREEN = "toolbar.fullscreen";
|
|
3003
|
+
/** Bottom-center toolbar: focused part title / active part indicator (`docks-part-name`). */
|
|
3004
|
+
var TOOLBAR_ACTIVE_PART_NAME = "toolbar.activePartName";
|
|
3005
|
+
/** Bottom-center toolbar: background tasks / progress (`docks-tasks`). */
|
|
3006
|
+
var TOOLBAR_TASKS = "toolbar.tasks";
|
|
3007
|
+
/** Main sidebar header toolbar: open extensions (`open_extensions` command). */
|
|
3008
|
+
var SIDEBAR_TOOLBAR_EXTENSIONS = "sidebar.toolbar.extensions";
|
|
3009
|
+
/** Default file-type → icon mappings on `system.icons`. */
|
|
3010
|
+
var SYSTEM_DEFAULT_FILE_ICONS = "system.icons.default";
|
|
3011
|
+
var ABOUT_TAB_RELEASE = "about.tab.release";
|
|
3012
|
+
var ABOUT_TAB_PACKAGES = "about.tab.packages";
|
|
3013
|
+
var ABOUT_TAB_ATTRIBUTIONS = "about.tab.attributions";
|
|
3014
|
+
var ATTRIBUTION_ECLIPSE_DOCKS = "attribution.eclipse-docks";
|
|
3015
|
+
var CTXMENU_FILEBROWSER_RENAME = "contextmenu.filebrowser.rename";
|
|
3016
|
+
var CTXMENU_FILEBROWSER_DELETE = "contextmenu.filebrowser.delete";
|
|
3042
3017
|
//#endregion
|
|
3043
|
-
//#region src/
|
|
3044
|
-
|
|
3045
|
-
* Parses an icon spec string into `{ library, name }` for use with `wa-icon`.
|
|
3046
|
-
*
|
|
3047
|
-
* Icon specs support an optional icon library prefix followed by the icon name,
|
|
3048
|
-
* separated by whitespace, e.g. `"docks mark-github"`.
|
|
3049
|
-
*
|
|
3050
|
-
* - When the spec contains **no whitespace**, it is treated as the icon name only
|
|
3051
|
-
* and `library` is omitted so the default Web Awesome / Font Awesome library is used.
|
|
3052
|
-
* - When the spec contains **whitespace**, the **last segment** is treated as
|
|
3053
|
-
* the icon name and every prior segment (joined by a single space) becomes `library`.
|
|
3054
|
-
*
|
|
3055
|
-
* Prefer {@link icon} for rendering; use parseIconSpec only when you need the parsed parts.
|
|
3056
|
-
*/
|
|
3057
|
-
function parseIconSpec(spec) {
|
|
3058
|
-
const trimmed = (spec ?? "").trim();
|
|
3059
|
-
if (!trimmed) return { name: "" };
|
|
3060
|
-
const parts = trimmed.split(/\s+/);
|
|
3061
|
-
if (parts.length <= 1) return { name: trimmed };
|
|
3062
|
-
return {
|
|
3063
|
-
name: parts.pop(),
|
|
3064
|
-
library: parts.join(" ")
|
|
3065
|
-
};
|
|
3066
|
-
}
|
|
3067
|
-
/**
|
|
3068
|
-
* Returns a Lit template that renders a `wa-icon` for the given spec.
|
|
3069
|
-
* Use this for all icon rendering so specs (e.g. contribution `icon` fields) stay consistent.
|
|
3070
|
-
* Handles undefined/null/empty spec internally; call sites may pass values directly.
|
|
3071
|
-
*/
|
|
3072
|
-
function icon(spec, options) {
|
|
3073
|
-
const { name: iconName, library } = parseIconSpec(spec ?? "");
|
|
3074
|
-
return html`<wa-icon library=${library ?? nothing} name=${iconName} label=${options?.label ?? nothing} slot=${options?.slot ?? nothing}></wa-icon>`;
|
|
3075
|
-
}
|
|
3018
|
+
//#region src/parts/container.ts
|
|
3019
|
+
var DocksContainer = class extends DocksElement {};
|
|
3076
3020
|
//#endregion
|
|
3077
|
-
//#region src/parts/
|
|
3078
|
-
var
|
|
3079
|
-
function renderButtonGroup(slotName, orientation, contributions, isToolbarItem, contributionCreator) {
|
|
3080
|
-
const label = `Toolbar ${slotName ?? "default"}`;
|
|
3081
|
-
const items = contributions.filter((c) => c.slot === slotName && isToolbarItem(c) && getContributionVisible(c));
|
|
3082
|
-
return html`
|
|
3083
|
-
<wa-button-group orientation=${orientation} label=${label}>
|
|
3084
|
-
${slotName === "start" ? html`<slot name="start"></slot>` : slotName === "end" ? html`<slot name="end"></slot>` : html`<slot></slot>`}
|
|
3085
|
-
${items.map(contributionCreator)}
|
|
3086
|
-
</wa-button-group>
|
|
3087
|
-
`;
|
|
3088
|
-
}
|
|
3089
|
-
var DocksToolbar = class DocksToolbar extends DocksElement {
|
|
3021
|
+
//#region src/parts/part.ts
|
|
3022
|
+
var DocksPart = class DocksPart extends DocksContainer {
|
|
3090
3023
|
constructor(..._args) {
|
|
3091
3024
|
super(..._args);
|
|
3092
|
-
this.
|
|
3093
|
-
this.
|
|
3094
|
-
this.
|
|
3095
|
-
this.
|
|
3096
|
-
this.
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
this.overflowCheckScheduled = false;
|
|
3104
|
-
this.onResize = () => {
|
|
3105
|
-
if (this.resizeDebounceTimer !== null) clearTimeout(this.resizeDebounceTimer);
|
|
3106
|
-
this.resizeDebounceTimer = setTimeout(() => {
|
|
3107
|
-
this.resizeDebounceTimer = null;
|
|
3108
|
-
this.updateCompactFromSpace();
|
|
3109
|
-
}, RESIZE_DEBOUNCE_MS);
|
|
3025
|
+
this.scrollMode = "scroller";
|
|
3026
|
+
this.dirty = false;
|
|
3027
|
+
this.isEditor = false;
|
|
3028
|
+
this.embedded = false;
|
|
3029
|
+
this.onContentContextMenu = async (event) => {
|
|
3030
|
+
const contextMenu = this.renderRoot.querySelector("docks-contextmenu");
|
|
3031
|
+
if (!contextMenu) return;
|
|
3032
|
+
if (await contextMenu.show({
|
|
3033
|
+
x: event.clientX,
|
|
3034
|
+
y: event.clientY
|
|
3035
|
+
}, event)) event.preventDefault();
|
|
3110
3036
|
};
|
|
3111
3037
|
}
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
if (!toolbarItems) return;
|
|
3115
|
-
const trimmed = toolbarItems.scrollWidth > toolbarItems.clientWidth;
|
|
3116
|
-
if (this.compact !== trimmed) this.compact = trimmed;
|
|
3117
|
-
}
|
|
3118
|
-
scheduleOverflowCheck() {
|
|
3119
|
-
if (this.overflowCheckScheduled) return;
|
|
3120
|
-
this.overflowCheckScheduled = true;
|
|
3121
|
-
requestAnimationFrame(() => {
|
|
3122
|
-
this.overflowCheckScheduled = false;
|
|
3123
|
-
this.updateCompactFromSpace();
|
|
3124
|
-
});
|
|
3125
|
-
}
|
|
3126
|
-
connectedCallback() {
|
|
3127
|
-
super.connectedCallback();
|
|
3128
|
-
this.resizeObserver = new ResizeObserver(this.onResize);
|
|
3129
|
-
this.resizeObserver.observe(this);
|
|
3130
|
-
}
|
|
3131
|
-
disconnectedCallback() {
|
|
3132
|
-
this.resizeObserver?.disconnect();
|
|
3133
|
-
this.resizeObserver = null;
|
|
3134
|
-
if (this.resizeDebounceTimer !== null) {
|
|
3135
|
-
clearTimeout(this.resizeDebounceTimer);
|
|
3136
|
-
this.resizeDebounceTimer = null;
|
|
3137
|
-
}
|
|
3138
|
-
super.disconnectedCallback();
|
|
3139
|
-
}
|
|
3140
|
-
updated(changedProperties) {
|
|
3141
|
-
super.updated?.(changedProperties);
|
|
3142
|
-
if (!this.compact) this.scheduleOverflowCheck();
|
|
3143
|
-
}
|
|
3144
|
-
willUpdate(changedProperties) {
|
|
3145
|
-
super.willUpdate?.(changedProperties);
|
|
3146
|
-
if (changedProperties.has("scopeTokens")) this.refreshContributions();
|
|
3147
|
-
}
|
|
3148
|
-
attributeChangedCallback(name, old, value) {
|
|
3149
|
-
super.attributeChangedCallback(name, old, value);
|
|
3150
|
-
if (name === "id" && old !== value) this.refreshContributions();
|
|
3038
|
+
getCommandStack() {
|
|
3039
|
+
return this.commandStack;
|
|
3151
3040
|
}
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3041
|
+
/**
|
|
3042
|
+
* Override this method to provide toolbar content for this part.
|
|
3043
|
+
* This is a lightweight alternative to registering toolbar contributions
|
|
3044
|
+
* for actions that are scoped to this part instance.
|
|
3045
|
+
*
|
|
3046
|
+
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3047
|
+
* The toolbar template is rendered in a different component (docks-toolbar), so direct method
|
|
3048
|
+
* references lose their binding.
|
|
3049
|
+
*
|
|
3050
|
+
* ✅ Correct:
|
|
3051
|
+
* @click=${() => this.myMethod()}
|
|
3052
|
+
* @click=${(e) => this.handleClick(e)}
|
|
3053
|
+
*
|
|
3054
|
+
* ❌ Wrong (this will be bound to the toolbar, not your component):
|
|
3055
|
+
* @click=${this.myMethod}
|
|
3056
|
+
*
|
|
3057
|
+
* Example:
|
|
3058
|
+
* ```typescript
|
|
3059
|
+
* protected renderToolbar() {
|
|
3060
|
+
* return html`
|
|
3061
|
+
* <wa-button @click=${() => this.save()} title="Save">
|
|
3062
|
+
* <wa-icon name="save"></wa-icon>
|
|
3063
|
+
* </wa-button>
|
|
3064
|
+
* `;
|
|
3065
|
+
* }
|
|
3066
|
+
* ```
|
|
3067
|
+
*
|
|
3068
|
+
* @returns TemplateResult with toolbar items, or nothing if no toolbar needed
|
|
3069
|
+
*/
|
|
3070
|
+
renderToolbar() {
|
|
3071
|
+
return nothing;
|
|
3159
3072
|
}
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3073
|
+
/**
|
|
3074
|
+
* Activates the tab that contains this part by walking up the DOM to the first
|
|
3075
|
+
* docks-tabs ancestor and activating the tab panel that contains this part.
|
|
3076
|
+
* Crosses Shadow DOM boundaries (e.g. wa-tab-group) via getRootNode().host.
|
|
3077
|
+
* No-op if this part is not inside a docks-tabs / wa-tab-panel.
|
|
3078
|
+
*/
|
|
3079
|
+
activateContainingTab() {
|
|
3080
|
+
let el = this;
|
|
3081
|
+
let panelName = null;
|
|
3082
|
+
let tabsEl = null;
|
|
3083
|
+
while (el) {
|
|
3084
|
+
const tag = el.tagName?.toLowerCase();
|
|
3085
|
+
if (tag === "wa-tab-panel") panelName = el.getAttribute("name");
|
|
3086
|
+
if (tag === "docks-tabs") {
|
|
3087
|
+
tabsEl = el;
|
|
3088
|
+
break;
|
|
3089
|
+
}
|
|
3090
|
+
const parent = el.parentElement;
|
|
3091
|
+
if (parent) el = parent;
|
|
3092
|
+
else {
|
|
3093
|
+
const root = el.getRootNode();
|
|
3094
|
+
el = root instanceof ShadowRoot ? root.host : null;
|
|
3095
|
+
}
|
|
3165
3096
|
}
|
|
3166
|
-
|
|
3097
|
+
if (tabsEl && panelName != null && panelName !== "") tabsEl.activate(panelName);
|
|
3167
3098
|
}
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3099
|
+
/**
|
|
3100
|
+
* Override this method to provide context menu content for this part.
|
|
3101
|
+
* This is a lightweight alternative to registering context menu contributions
|
|
3102
|
+
* for actions that are scoped to this part instance.
|
|
3103
|
+
*
|
|
3104
|
+
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3105
|
+
* The context menu is rendered in a different component (contextmenu), so direct method
|
|
3106
|
+
* references lose their binding.
|
|
3107
|
+
*
|
|
3108
|
+
* ✅ Correct:
|
|
3109
|
+
* @click=${() => this.myMethod()}
|
|
3110
|
+
* @click=${(e) => this.handleClick(e)}
|
|
3111
|
+
*
|
|
3112
|
+
* ❌ Wrong (this will be bound to the context menu, not your component):
|
|
3113
|
+
* @click=${this.myMethod}
|
|
3114
|
+
*
|
|
3115
|
+
* Example:
|
|
3116
|
+
* ```typescript
|
|
3117
|
+
* protected renderContextMenu() {
|
|
3118
|
+
* return html`
|
|
3119
|
+
* <wa-dropdown-item @click=${() => this.open()}>
|
|
3120
|
+
* <wa-icon name="folder-open"></wa-icon>
|
|
3121
|
+
* Open
|
|
3122
|
+
* </wa-dropdown-item>
|
|
3123
|
+
* <wa-divider></wa-divider>
|
|
3124
|
+
* <wa-dropdown-item @click=${() => this.delete()}>
|
|
3125
|
+
* <wa-icon name="trash"></wa-icon>
|
|
3126
|
+
* Delete
|
|
3127
|
+
* </wa-dropdown-item>
|
|
3128
|
+
* `;
|
|
3129
|
+
* }
|
|
3130
|
+
* ```
|
|
3131
|
+
*
|
|
3132
|
+
* @returns TemplateResult with context menu items, or nothing if no context menu needed
|
|
3133
|
+
*/
|
|
3134
|
+
renderContextMenu() {
|
|
3135
|
+
return nothing;
|
|
3179
3136
|
}
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
if (!id.includes(":")) {
|
|
3183
|
-
this.contributions = specific;
|
|
3184
|
-
return;
|
|
3185
|
-
}
|
|
3186
|
-
const [prefix] = id.split(":");
|
|
3187
|
-
const wildcardId = `${prefix}:*`;
|
|
3188
|
-
const wildcard = contributionRegistry.getContributions(wildcardId);
|
|
3189
|
-
const categoryMatches = [];
|
|
3190
|
-
for (const category of this.scopeTokens) {
|
|
3191
|
-
const categoryId = `${prefix}:${category}`;
|
|
3192
|
-
const matches = contributionRegistry.getContributions(categoryId);
|
|
3193
|
-
categoryMatches.push(...matches);
|
|
3194
|
-
}
|
|
3195
|
-
this.contributions = [
|
|
3196
|
-
...wildcard,
|
|
3197
|
-
...categoryMatches,
|
|
3198
|
-
...specific
|
|
3199
|
-
];
|
|
3137
|
+
renderContent() {
|
|
3138
|
+
return nothing;
|
|
3200
3139
|
}
|
|
3201
|
-
|
|
3202
|
-
|
|
3140
|
+
/** Part-level toolbar contributions (`toolbar:${partId}`). */
|
|
3141
|
+
getToolbarTarget() {
|
|
3142
|
+
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3143
|
+
return contributionKey ? `toolbar:${contributionKey}` : void 0;
|
|
3203
3144
|
}
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
if (
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
}
|
|
3223
|
-
return html`<span>unknown contribution type: ${typeof contribution}</span>`;
|
|
3145
|
+
/** Part-level context-menu contributions (`contextmenu:${partId}`). */
|
|
3146
|
+
getContextMenuTarget() {
|
|
3147
|
+
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3148
|
+
return contributionKey ? `contextmenu:${contributionKey}` : void 0;
|
|
3149
|
+
}
|
|
3150
|
+
syncIsEditorCapability() {
|
|
3151
|
+
const next = this.save !== DocksPart.prototype.save;
|
|
3152
|
+
if (next === this.isEditor) return;
|
|
3153
|
+
this.isEditor = next;
|
|
3154
|
+
}
|
|
3155
|
+
maybeActivateForCoupledEditors() {
|
|
3156
|
+
const coupled = this.tabContribution?.coupledEditors;
|
|
3157
|
+
if (!coupled?.length) return;
|
|
3158
|
+
const active = activeEditorSignal.get();
|
|
3159
|
+
if (!(active instanceof DocksPart)) return;
|
|
3160
|
+
const editorId = active.tabContribution?.editorId;
|
|
3161
|
+
if (!editorId || !coupled.includes(editorId)) return;
|
|
3162
|
+
this.activateContainingTab();
|
|
3224
3163
|
}
|
|
3225
3164
|
render() {
|
|
3226
|
-
const
|
|
3227
|
-
const
|
|
3228
|
-
const
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
const
|
|
3234
|
-
|
|
3165
|
+
const toolbarTarget = this.getToolbarTarget();
|
|
3166
|
+
const contextMenuTarget = this.getContextMenuTarget();
|
|
3167
|
+
const toolbarEnabled = this.tabContribution?.toolbar !== false;
|
|
3168
|
+
const contextMenuEnabled = this.tabContribution?.contextMenu !== false;
|
|
3169
|
+
const scrollMode = this.scrollMode;
|
|
3170
|
+
const scopeTokens = this.isEditor ? ["system.editors", ".system.editors"] : [];
|
|
3171
|
+
const content = this.renderContent();
|
|
3172
|
+
const contentNode = scrollMode === "scroller" ? html`
|
|
3173
|
+
<wa-scroller class="part-content-scroll" orientation="vertical">
|
|
3174
|
+
<div class="part-content-inner">${content}</div>
|
|
3175
|
+
</wa-scroller>
|
|
3176
|
+
` : html`<div class="part-content-inner">${content}</div>`;
|
|
3235
3177
|
return html`
|
|
3236
|
-
<div class="
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3178
|
+
<div class="part-shell">
|
|
3179
|
+
${toolbarEnabled ? html`
|
|
3180
|
+
<docks-toolbar
|
|
3181
|
+
class="part-toolbar"
|
|
3182
|
+
id=${ifDefined(toolbarTarget)}
|
|
3183
|
+
.scopeTokens=${scopeTokens}
|
|
3184
|
+
.partToolbarRenderer=${() => this.renderToolbar()}>
|
|
3185
|
+
</docks-toolbar>
|
|
3186
|
+
` : nothing}
|
|
3187
|
+
<div class="part-content ${scrollMode === "native" ? "native-scroll" : ""}" @contextmenu=${contextMenuEnabled ? this.onContentContextMenu : void 0}>
|
|
3188
|
+
${contentNode}
|
|
3189
|
+
</div>
|
|
3190
|
+
${contextMenuEnabled ? html`
|
|
3191
|
+
<docks-contextmenu
|
|
3192
|
+
id=${ifDefined(contextMenuTarget)}
|
|
3193
|
+
.scopeTokens=${scopeTokens}
|
|
3194
|
+
.partContextMenuRenderer=${() => this.renderContextMenu()}>
|
|
3195
|
+
</docks-contextmenu>
|
|
3196
|
+
` : nothing}
|
|
3245
3197
|
</div>
|
|
3246
3198
|
`;
|
|
3247
3199
|
}
|
|
3200
|
+
updated(_changedProperties) {
|
|
3201
|
+
super.updated(_changedProperties);
|
|
3202
|
+
this.syncIsEditorCapability();
|
|
3203
|
+
if (_changedProperties.has("tabContribution")) this.maybeActivateForCoupledEditors();
|
|
3204
|
+
if (_changedProperties.has("dirty")) {
|
|
3205
|
+
if (_changedProperties.get("dirty") !== void 0) this.dispatchEvent(new CustomEvent("dirty", {
|
|
3206
|
+
detail: this.dirty,
|
|
3207
|
+
bubbles: true
|
|
3208
|
+
}));
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
doClose() {}
|
|
3212
|
+
disconnectedCallback() {
|
|
3213
|
+
super.disconnectedCallback();
|
|
3214
|
+
}
|
|
3215
|
+
close() {
|
|
3216
|
+
this.doClose();
|
|
3217
|
+
}
|
|
3218
|
+
connectedCallback() {
|
|
3219
|
+
super.connectedCallback();
|
|
3220
|
+
this.syncIsEditorCapability();
|
|
3221
|
+
queueMicrotask(() => this.syncIsEditorCapability());
|
|
3222
|
+
this.watch(activeEditorSignal, () => this.maybeActivateForCoupledEditors());
|
|
3223
|
+
}
|
|
3224
|
+
save() {}
|
|
3225
|
+
isDirty() {
|
|
3226
|
+
return this.dirty;
|
|
3227
|
+
}
|
|
3228
|
+
markDirty(dirty) {
|
|
3229
|
+
this.dirty = dirty;
|
|
3230
|
+
partDirtySignal.set(null);
|
|
3231
|
+
partDirtySignal.set(this);
|
|
3232
|
+
activePartSignal.set(null);
|
|
3233
|
+
activePartSignal.set(this);
|
|
3234
|
+
}
|
|
3248
3235
|
static {
|
|
3249
|
-
this.
|
|
3236
|
+
this.baseStyles = css`
|
|
3250
3237
|
:host {
|
|
3251
|
-
display:
|
|
3252
|
-
flex-direction: row;
|
|
3253
|
-
--wa-form-control-padding-inline: var(--wa-space-2xs);
|
|
3238
|
+
display: block;
|
|
3254
3239
|
}
|
|
3255
3240
|
|
|
3256
|
-
|
|
3257
|
-
|
|
3241
|
+
.part-shell {
|
|
3242
|
+
display: grid;
|
|
3243
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
3244
|
+
height: 100%;
|
|
3245
|
+
width: 100%;
|
|
3246
|
+
position: relative;
|
|
3247
|
+
overflow: hidden;
|
|
3258
3248
|
}
|
|
3259
3249
|
|
|
3260
|
-
.
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3250
|
+
.part-content {
|
|
3251
|
+
min-height: 0;
|
|
3252
|
+
overflow: hidden;
|
|
3253
|
+
position: relative;
|
|
3254
|
+
}
|
|
3255
|
+
|
|
3256
|
+
.part-content.native-scroll {
|
|
3257
|
+
overflow: auto;
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
.part-content-scroll {
|
|
3261
|
+
width: 100%;
|
|
3262
|
+
height: 100%;
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
.part-content-inner {
|
|
3266
|
+
height: 100%;
|
|
3267
|
+
min-height: 100%;
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
:host([embedded]) {
|
|
3271
|
+
height: auto;
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3274
|
+
:host([embedded]) .part-shell {
|
|
3275
|
+
height: auto;
|
|
3276
|
+
overflow: visible;
|
|
3277
|
+
grid-template-rows: auto;
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
:host([embedded]) .part-content {
|
|
3281
|
+
overflow: visible;
|
|
3282
|
+
min-height: 0;
|
|
3283
|
+
}
|
|
3284
|
+
|
|
3285
|
+
:host([embedded]) .part-content-inner {
|
|
3286
|
+
height: auto;
|
|
3287
|
+
min-height: 0;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
.part-toolbar {
|
|
3291
|
+
min-height: 0;
|
|
3264
3292
|
}
|
|
3265
3293
|
`;
|
|
3266
3294
|
}
|
|
3295
|
+
static finalizeStyles(styles) {
|
|
3296
|
+
const own = super.finalizeStyles(styles);
|
|
3297
|
+
return [DocksPart.baseStyles, ...own];
|
|
3298
|
+
}
|
|
3267
3299
|
};
|
|
3268
|
-
_decorate([property()],
|
|
3269
|
-
_decorate([property({
|
|
3270
|
-
_decorate([property({
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
_decorate([property({
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3300
|
+
_decorate([property()], DocksPart.prototype, "dirty", void 0);
|
|
3301
|
+
_decorate([property({ attribute: false })], DocksPart.prototype, "tabContribution", void 0);
|
|
3302
|
+
_decorate([property({
|
|
3303
|
+
type: Boolean,
|
|
3304
|
+
attribute: false
|
|
3305
|
+
})], DocksPart.prototype, "isEditor", void 0);
|
|
3306
|
+
_decorate([property({
|
|
3307
|
+
type: Boolean,
|
|
3308
|
+
reflect: true
|
|
3309
|
+
})], DocksPart.prototype, "embedded", void 0);
|
|
3310
|
+
//#endregion
|
|
3311
|
+
//#region src/components/release-history.ts
|
|
3312
|
+
var logger = createLogger("ReleaseHistory");
|
|
3313
|
+
async function loadReleases(releaseHistory) {
|
|
3314
|
+
if (!releaseHistory) return [];
|
|
3315
|
+
if (typeof releaseHistory !== "function") return releaseHistory;
|
|
3316
|
+
try {
|
|
3317
|
+
return await releaseHistory();
|
|
3318
|
+
} catch (error) {
|
|
3319
|
+
logger.error(`Failed to load release history from app: ${error instanceof Error ? error.message : String(error)}`);
|
|
3320
|
+
return [];
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
function semverEqual(a, b) {
|
|
3324
|
+
return a.replace(/^v/i, "") === b.replace(/^v/i, "");
|
|
3325
|
+
}
|
|
3326
|
+
function isNewerThan(releaseTag, currentVersion) {
|
|
3327
|
+
const currentParts = currentVersion.replace(/^v/i, "").split(".").map(Number);
|
|
3328
|
+
const releaseParts = releaseTag.replace(/^v/i, "").split(".").map(Number);
|
|
3329
|
+
for (let i = 0; i < Math.max(currentParts.length, releaseParts.length); i++) {
|
|
3330
|
+
const current = currentParts[i] || 0;
|
|
3331
|
+
const releasePart = releaseParts[i] || 0;
|
|
3332
|
+
if (releasePart > current) return true;
|
|
3333
|
+
if (releasePart < current) return false;
|
|
3334
|
+
}
|
|
3335
|
+
return false;
|
|
3336
|
+
}
|
|
3337
|
+
var DocksReleaseHistory = class DocksReleaseHistory extends DocksPart {
|
|
3338
|
+
constructor(..._args) {
|
|
3339
|
+
super(..._args);
|
|
3340
|
+
this.scrollMode = "none";
|
|
3341
|
+
this.appVersion = "0.0.0";
|
|
3342
|
+
this.releases = [];
|
|
3343
|
+
this.currentReleaseIndex = 0;
|
|
3344
|
+
}
|
|
3345
|
+
static {
|
|
3346
|
+
this.styles = [css`
|
|
3347
|
+
.release-panel {
|
|
3348
|
+
display: flex;
|
|
3349
|
+
flex-direction: column;
|
|
3350
|
+
gap: 0.5rem;
|
|
3351
|
+
padding: 0.75rem;
|
|
3352
|
+
box-sizing: border-box;
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
.release-body {
|
|
3356
|
+
white-space: normal;
|
|
3357
|
+
}
|
|
3358
|
+
`];
|
|
3359
|
+
}
|
|
3360
|
+
doInitUI() {
|
|
3361
|
+
this.load();
|
|
3362
|
+
}
|
|
3363
|
+
async load() {
|
|
3364
|
+
const app = appLoaderService.getCurrentApp();
|
|
3365
|
+
this.appVersion = app?.version ?? "0.0.0";
|
|
3366
|
+
this.releases = await loadReleases(app?.releaseHistory);
|
|
3367
|
+
const currentIndex = this.releases.findIndex((release) => semverEqual(release.tag_name, this.appVersion));
|
|
3368
|
+
this.currentReleaseIndex = currentIndex >= 0 ? currentIndex : 0;
|
|
3369
|
+
this.notifyChanged();
|
|
3370
|
+
}
|
|
3371
|
+
getNavState() {
|
|
3372
|
+
return {
|
|
3373
|
+
hasMultiple: this.releases.length > 1,
|
|
3374
|
+
atOldest: this.currentReleaseIndex >= this.releases.length - 1,
|
|
3375
|
+
atNewest: this.currentReleaseIndex <= 0
|
|
3376
|
+
};
|
|
3377
|
+
}
|
|
3378
|
+
showOlder() {
|
|
3379
|
+
if (this.currentReleaseIndex < this.releases.length - 1) {
|
|
3380
|
+
this.currentReleaseIndex += 1;
|
|
3381
|
+
this.notifyChanged();
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
showNewer() {
|
|
3385
|
+
if (this.currentReleaseIndex > 0) {
|
|
3386
|
+
this.currentReleaseIndex -= 1;
|
|
3387
|
+
this.notifyChanged();
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
notifyChanged() {
|
|
3391
|
+
this.dispatchEvent(new CustomEvent("release-history-changed", {
|
|
3392
|
+
bubbles: true,
|
|
3393
|
+
composed: true
|
|
3394
|
+
}));
|
|
3395
|
+
}
|
|
3396
|
+
renderContent() {
|
|
3397
|
+
const release = this.releases[this.currentReleaseIndex];
|
|
3398
|
+
if (!release) return html`<div class="release-panel">No release history available.</div>`;
|
|
3399
|
+
const isCurrent = semverEqual(release.tag_name, this.appVersion);
|
|
3400
|
+
const showUpdateHint = !isCurrent && isNewerThan(release.tag_name, this.appVersion);
|
|
3401
|
+
const bodyHtml = release.body ? parseMarkdownHtml(release.body) : "";
|
|
3402
|
+
return html`
|
|
3403
|
+
<div class="release-panel">
|
|
3404
|
+
<p>
|
|
3405
|
+
<strong>Version:</strong> ${release.tag_name}${isCurrent ? " (Current)" : ""}
|
|
3406
|
+
</p>
|
|
3407
|
+
<p>
|
|
3408
|
+
<strong>Released:</strong>
|
|
3409
|
+
<wa-format-date
|
|
3410
|
+
.date=${release.published_at}
|
|
3411
|
+
month="short"
|
|
3412
|
+
day="numeric"
|
|
3413
|
+
year="numeric"
|
|
3414
|
+
></wa-format-date>
|
|
3415
|
+
</p>
|
|
3416
|
+
${showUpdateHint ? html`
|
|
3417
|
+
<wa-callout variant="warning">
|
|
3418
|
+
<wa-icon slot="icon" name="triangle-exclamation"></wa-icon>
|
|
3419
|
+
A newer release is available than the version you are running.
|
|
3420
|
+
Use <strong>Update Available</strong> in the toolbar when it appears.
|
|
3421
|
+
</wa-callout>
|
|
3422
|
+
` : ""}
|
|
3423
|
+
${bodyHtml ? html`<div class="release-body">${unsafeHTML(bodyHtml)}</div>` : ""}
|
|
3424
|
+
</div>
|
|
3425
|
+
`;
|
|
3426
|
+
}
|
|
3427
|
+
};
|
|
3428
|
+
_decorate([state()], DocksReleaseHistory.prototype, "appVersion", void 0);
|
|
3429
|
+
_decorate([state()], DocksReleaseHistory.prototype, "releases", void 0);
|
|
3430
|
+
_decorate([state()], DocksReleaseHistory.prototype, "currentReleaseIndex", void 0);
|
|
3431
|
+
DocksReleaseHistory = _decorate([customElement("docks-release-history")], DocksReleaseHistory);
|
|
3432
|
+
//#endregion
|
|
3433
|
+
//#region src/dialogs/version-info-dialog.ts
|
|
3434
|
+
var EMPTY_NAV = {
|
|
3435
|
+
hasMultiple: false,
|
|
3436
|
+
atOldest: true,
|
|
3437
|
+
atNewest: true
|
|
3438
|
+
};
|
|
3439
|
+
var DocksVersionInfoDialog = class DocksVersionInfoDialog extends DocksDialogContent {
|
|
3440
|
+
constructor(..._args) {
|
|
3441
|
+
super(..._args);
|
|
3442
|
+
this.label = "";
|
|
3443
|
+
this.activeTab = null;
|
|
3444
|
+
this.releaseNav = EMPTY_NAV;
|
|
3445
|
+
this.onReleaseHistoryChanged = () => {
|
|
3446
|
+
this.syncReleaseNav();
|
|
3447
|
+
};
|
|
3448
|
+
}
|
|
3449
|
+
static {
|
|
3450
|
+
this.styles = [...DocksDialogContent.styles, css`
|
|
3451
|
+
:host {
|
|
3452
|
+
display: block;
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3455
|
+
wa-dialog {
|
|
3456
|
+
--width: 600px;
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
wa-dialog::part(body) {
|
|
3460
|
+
display: flex;
|
|
3461
|
+
flex-direction: column;
|
|
3462
|
+
min-height: 0;
|
|
3463
|
+
overflow: hidden;
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3466
|
+
.dialog-body {
|
|
3467
|
+
display: flex;
|
|
3468
|
+
flex-direction: column;
|
|
3469
|
+
gap: 0.75rem;
|
|
3470
|
+
min-width: 32rem;
|
|
3471
|
+
height: min(70vh, 36rem);
|
|
3472
|
+
min-height: min(70vh, 36rem);
|
|
3473
|
+
overflow: hidden;
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
.dialog-body docks-tabs {
|
|
3477
|
+
flex: 1 1 auto;
|
|
3478
|
+
min-height: 0;
|
|
3479
|
+
overflow: hidden;
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
.dialog-footer {
|
|
3483
|
+
display: flex;
|
|
3484
|
+
gap: 0.5rem;
|
|
3485
|
+
justify-content: flex-end;
|
|
3486
|
+
width: 100%;
|
|
3487
|
+
}
|
|
3488
|
+
`];
|
|
3489
|
+
}
|
|
3490
|
+
firstUpdated(changed) {
|
|
3491
|
+
super.firstUpdated(changed);
|
|
3492
|
+
this.addEventListener("release-history-changed", this.onReleaseHistoryChanged);
|
|
3493
|
+
this.updateComplete.then(() => {
|
|
3494
|
+
this.attachTabListener();
|
|
3495
|
+
this.syncActiveTab();
|
|
3496
|
+
this.syncReleaseNav();
|
|
3497
|
+
});
|
|
3498
|
+
}
|
|
3499
|
+
disconnectedCallback() {
|
|
3500
|
+
this.removeEventListener("release-history-changed", this.onReleaseHistoryChanged);
|
|
3501
|
+
super.disconnectedCallback();
|
|
3502
|
+
}
|
|
3503
|
+
attachTabListener() {
|
|
3504
|
+
const tabGroup = this.getAboutTabs()?.shadowRoot?.querySelector("wa-tab-group");
|
|
3505
|
+
if (!tabGroup || tabGroup.hasAttribute("data-version-info-listener")) return;
|
|
3506
|
+
tabGroup.setAttribute("data-version-info-listener", "");
|
|
3507
|
+
tabGroup.addEventListener("wa-tab-show", (event) => {
|
|
3508
|
+
const name = event.detail?.name;
|
|
3509
|
+
if (name) this.activeTab = name;
|
|
3510
|
+
});
|
|
3511
|
+
}
|
|
3512
|
+
getAboutTabs() {
|
|
3513
|
+
return this.renderRoot.querySelector("docks-tabs");
|
|
3514
|
+
}
|
|
3515
|
+
getReleaseHistory() {
|
|
3516
|
+
const part = this.getAboutTabs()?.getTabPart(ABOUT_TAB_RELEASE);
|
|
3517
|
+
return part instanceof DocksReleaseHistory ? part : null;
|
|
3518
|
+
}
|
|
3519
|
+
syncActiveTab() {
|
|
3520
|
+
const tabGroup = this.getAboutTabs()?.shadowRoot?.querySelector("wa-tab-group");
|
|
3521
|
+
this.activeTab = tabGroup?.getAttribute("active") || tabGroup?.active || null;
|
|
3522
|
+
}
|
|
3523
|
+
syncReleaseNav() {
|
|
3524
|
+
this.releaseNav = this.getReleaseHistory()?.getNavState() ?? EMPTY_NAV;
|
|
3525
|
+
}
|
|
3526
|
+
handleClose() {
|
|
3527
|
+
const dialog = this.renderRoot.querySelector("wa-dialog");
|
|
3528
|
+
if (dialog && dialog.open !== false) {
|
|
3529
|
+
dialog.open = false;
|
|
3530
|
+
return;
|
|
3531
|
+
}
|
|
3532
|
+
this.close?.();
|
|
3533
|
+
}
|
|
3534
|
+
handleAfterHide() {
|
|
3535
|
+
this.onAfterHide?.();
|
|
3536
|
+
}
|
|
3537
|
+
showOlderRelease() {
|
|
3538
|
+
this.getReleaseHistory()?.showOlder();
|
|
3539
|
+
}
|
|
3540
|
+
showNewerRelease() {
|
|
3541
|
+
this.getReleaseHistory()?.showNewer();
|
|
3542
|
+
}
|
|
3543
|
+
render() {
|
|
3544
|
+
const app = appLoaderService.getCurrentApp();
|
|
3545
|
+
const showReleaseNav = this.activeTab === "about.tab.release" && this.releaseNav.hasMultiple;
|
|
3546
|
+
return html`
|
|
3547
|
+
<wa-dialog
|
|
3548
|
+
label=${this.label}
|
|
3549
|
+
open
|
|
3550
|
+
light-dismiss
|
|
3551
|
+
with-footer
|
|
3552
|
+
@wa-after-hide=${this.handleAfterHide}
|
|
3553
|
+
>
|
|
3554
|
+
<div class="dialog-body">
|
|
3555
|
+
${app?.description ? html`<small>${app.description}</small>` : ""}
|
|
3556
|
+
<docks-tabs id=${ABOUT_TABS} fill-height></docks-tabs>
|
|
3557
|
+
</div>
|
|
3558
|
+
<div slot="footer" class="dialog-footer">
|
|
3559
|
+
${showReleaseNav ? html`
|
|
3560
|
+
<wa-button
|
|
3561
|
+
variant="default"
|
|
3562
|
+
?disabled=${this.releaseNav.atOldest}
|
|
3563
|
+
@click=${this.showOlderRelease}
|
|
3564
|
+
>
|
|
3565
|
+
← Previous
|
|
3566
|
+
</wa-button>
|
|
3567
|
+
<wa-button
|
|
3568
|
+
variant="default"
|
|
3569
|
+
?disabled=${this.releaseNav.atNewest}
|
|
3570
|
+
@click=${this.showNewerRelease}
|
|
3571
|
+
>
|
|
3572
|
+
Next →
|
|
3573
|
+
</wa-button>
|
|
3574
|
+
` : nothing}
|
|
3575
|
+
<wa-button variant="primary" @click=${this.handleClose}>Close</wa-button>
|
|
3576
|
+
</div>
|
|
3577
|
+
</wa-dialog>
|
|
3578
|
+
`;
|
|
3579
|
+
}
|
|
3580
|
+
};
|
|
3581
|
+
_decorate([property({ type: String })], DocksVersionInfoDialog.prototype, "label", void 0);
|
|
3582
|
+
_decorate([property({ attribute: false })], DocksVersionInfoDialog.prototype, "close", void 0);
|
|
3583
|
+
_decorate([property({ attribute: false })], DocksVersionInfoDialog.prototype, "onAfterHide", void 0);
|
|
3584
|
+
_decorate([state()], DocksVersionInfoDialog.prototype, "activeTab", void 0);
|
|
3585
|
+
_decorate([state()], DocksVersionInfoDialog.prototype, "releaseNav", void 0);
|
|
3586
|
+
DocksVersionInfoDialog = _decorate([customElement("docks-version-info-dialog")], DocksVersionInfoDialog);
|
|
3587
|
+
contributionRegistry.registerContribution(DIALOG_CONTRIBUTION_TARGET, {
|
|
3588
|
+
id: "version-info",
|
|
3589
|
+
label: "About",
|
|
3590
|
+
selfContained: true,
|
|
3591
|
+
component: (state) => html`
|
|
3592
|
+
<docks-version-info-dialog
|
|
3593
|
+
.label=${state?.label ?? ""}
|
|
3594
|
+
.close=${state?.close}
|
|
3595
|
+
.onAfterHide=${state?.onAfterHide}
|
|
3596
|
+
></docks-version-info-dialog>
|
|
3597
|
+
`
|
|
3598
|
+
});
|
|
3599
|
+
function versionInfoDialog() {
|
|
3600
|
+
const app = appLoaderService.getCurrentApp();
|
|
3601
|
+
return dialogService.open("version-info", { label: `About ${app?.name ?? ""} - ${app?.version ?? "0.0.0"}` });
|
|
3602
|
+
}
|
|
3278
3603
|
//#endregion
|
|
3279
3604
|
//#region src/core/dropdown-menu-utils.ts
|
|
3605
|
+
function isOpenDropdown(element) {
|
|
3606
|
+
if (element.localName !== "wa-dropdown") return false;
|
|
3607
|
+
const dropdown = element;
|
|
3608
|
+
return dropdown.open === true || dropdown.hasAttribute("open");
|
|
3609
|
+
}
|
|
3610
|
+
function elementsFromEventPath(event) {
|
|
3611
|
+
const fromComposedPath = event.composedPath().filter((node) => node instanceof Element);
|
|
3612
|
+
if (fromComposedPath.length > 0) return fromComposedPath;
|
|
3613
|
+
if (!(event.target instanceof Element)) return [];
|
|
3614
|
+
const path = [];
|
|
3615
|
+
let current = event.target;
|
|
3616
|
+
while (current) {
|
|
3617
|
+
path.push(current);
|
|
3618
|
+
const root = current.getRootNode();
|
|
3619
|
+
if (root instanceof ShadowRoot) {
|
|
3620
|
+
current = root.host;
|
|
3621
|
+
continue;
|
|
3622
|
+
}
|
|
3623
|
+
current = current.parentElement;
|
|
3624
|
+
}
|
|
3625
|
+
return path;
|
|
3626
|
+
}
|
|
3627
|
+
function elementTargetsOpenDropdown(element) {
|
|
3628
|
+
if (isOpenDropdown(element)) return true;
|
|
3629
|
+
if (element.localName !== "wa-dropdown-item") return false;
|
|
3630
|
+
const dropdown = element.closest("wa-dropdown");
|
|
3631
|
+
if (dropdown && isOpenDropdown(dropdown)) return true;
|
|
3632
|
+
const root = element.getRootNode();
|
|
3633
|
+
return root instanceof ShadowRoot && root.host instanceof Element && isOpenDropdown(root.host);
|
|
3634
|
+
}
|
|
3635
|
+
/** True when the event occurred inside a wa-dropdown that is currently open. */
|
|
3636
|
+
function eventTargetsOpenDropdown(event) {
|
|
3637
|
+
return elementsFromEventPath(event).some(elementTargetsOpenDropdown);
|
|
3638
|
+
}
|
|
3639
|
+
/** Prevents the browser context menu on open Docks popup lists (context menus, toolbar dropdowns). */
|
|
3640
|
+
function suppressNativeContextMenuInOpenDropdowns(event) {
|
|
3641
|
+
if (!event.cancelable || !eventTargetsOpenDropdown(event)) return;
|
|
3642
|
+
event.preventDefault();
|
|
3643
|
+
}
|
|
3644
|
+
var openDropdownContextMenuGuardInstalled = false;
|
|
3645
|
+
function installOpenDropdownNativeContextMenuGuard() {
|
|
3646
|
+
if (openDropdownContextMenuGuardInstalled || typeof document === "undefined") return;
|
|
3647
|
+
openDropdownContextMenuGuardInstalled = true;
|
|
3648
|
+
document.addEventListener("contextmenu", suppressNativeContextMenuInOpenDropdowns, { capture: true });
|
|
3649
|
+
}
|
|
3280
3650
|
function visitElementTree(root, visit) {
|
|
3281
3651
|
if (root instanceof Element) {
|
|
3282
3652
|
visit(root);
|
|
@@ -3299,213 +3669,354 @@ function closeSiblingSubmenus(activeItem, menuRoot) {
|
|
|
3299
3669
|
});
|
|
3300
3670
|
}
|
|
3301
3671
|
//#endregion
|
|
3302
|
-
//#region src/
|
|
3303
|
-
|
|
3672
|
+
//#region src/core/icon-utils.ts
|
|
3673
|
+
/**
|
|
3674
|
+
* Parses an icon spec string into `{ library, name }` for use with `wa-icon`.
|
|
3675
|
+
*
|
|
3676
|
+
* Icon specs support an optional icon library prefix followed by the icon name,
|
|
3677
|
+
* separated by whitespace, e.g. `"docks mark-github"`.
|
|
3678
|
+
*
|
|
3679
|
+
* - When the spec contains **no whitespace**, it is treated as the icon name only
|
|
3680
|
+
* and `library` is omitted so the default Web Awesome / Font Awesome library is used.
|
|
3681
|
+
* - When the spec contains **whitespace**, the **last segment** is treated as
|
|
3682
|
+
* the icon name and every prior segment (joined by a single space) becomes `library`.
|
|
3683
|
+
*
|
|
3684
|
+
* Prefer {@link icon} for rendering; use parseIconSpec only when you need the parsed parts.
|
|
3685
|
+
*/
|
|
3686
|
+
function parseIconSpec(spec) {
|
|
3687
|
+
const trimmed = (spec ?? "").trim();
|
|
3688
|
+
if (!trimmed) return { name: "" };
|
|
3689
|
+
const parts = trimmed.split(/\s+/);
|
|
3690
|
+
if (parts.length <= 1) return { name: trimmed };
|
|
3691
|
+
return {
|
|
3692
|
+
name: parts.pop(),
|
|
3693
|
+
library: parts.join(" ")
|
|
3694
|
+
};
|
|
3695
|
+
}
|
|
3696
|
+
/**
|
|
3697
|
+
* Returns a Lit template that renders a `wa-icon` for the given spec.
|
|
3698
|
+
* Use this for all icon rendering so specs (e.g. contribution `icon` fields) stay consistent.
|
|
3699
|
+
* Handles undefined/null/empty spec internally; call sites may pass values directly.
|
|
3700
|
+
*/
|
|
3701
|
+
function icon(spec, options) {
|
|
3702
|
+
const { name: iconName, library } = parseIconSpec(spec ?? "");
|
|
3703
|
+
return html`<wa-icon library=${library ?? nothing} name=${iconName} label=${options?.label ?? nothing} slot=${options?.slot ?? nothing}></wa-icon>`;
|
|
3704
|
+
}
|
|
3705
|
+
//#endregion
|
|
3706
|
+
//#region src/parts/toolbar.ts
|
|
3707
|
+
var RESIZE_DEBOUNCE_MS = 150;
|
|
3708
|
+
function renderButtonGroup(slotName, orientation, contributions, isToolbarItem, contributionCreator) {
|
|
3709
|
+
const label = `Toolbar ${slotName ?? "default"}`;
|
|
3710
|
+
const items = contributions.filter((c) => c.slot === slotName && isToolbarItem(c) && getContributionVisible(c));
|
|
3711
|
+
return html`
|
|
3712
|
+
<wa-button-group orientation=${orientation} label=${label}>
|
|
3713
|
+
${slotName === "start" ? html`<slot name="start"></slot>` : slotName === "end" ? html`<slot name="end"></slot>` : html`<slot></slot>`}
|
|
3714
|
+
${items.map(contributionCreator)}
|
|
3715
|
+
</wa-button-group>
|
|
3716
|
+
`;
|
|
3717
|
+
}
|
|
3718
|
+
var DocksToolbar = class DocksToolbar extends DocksElement {
|
|
3304
3719
|
constructor(..._args) {
|
|
3305
3720
|
super(..._args);
|
|
3306
|
-
this.
|
|
3307
|
-
this.
|
|
3308
|
-
this.
|
|
3309
|
-
this.disabled = false;
|
|
3310
|
-
this.appearance = "plain";
|
|
3311
|
-
this.variant = "neutral";
|
|
3721
|
+
this.position = "start";
|
|
3722
|
+
this.orientation = "horizontal";
|
|
3723
|
+
this.align = "start";
|
|
3312
3724
|
this.size = "s";
|
|
3313
|
-
this.
|
|
3314
|
-
this.
|
|
3315
|
-
this.
|
|
3316
|
-
this.
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
if (this.action) {
|
|
3329
|
-
this.action(event);
|
|
3330
|
-
return;
|
|
3331
|
-
}
|
|
3332
|
-
if (this.cmd) this.executeCommand(this.cmd, this.params);
|
|
3725
|
+
this.scopeTokens = [];
|
|
3726
|
+
this.partToolbarContent = void 0;
|
|
3727
|
+
this.partToolbarRenderer = void 0;
|
|
3728
|
+
this.contributions = [];
|
|
3729
|
+
this.compact = false;
|
|
3730
|
+
this.resizeObserver = null;
|
|
3731
|
+
this.resizeDebounceTimer = null;
|
|
3732
|
+
this.overflowCheckScheduled = false;
|
|
3733
|
+
this.onResize = () => {
|
|
3734
|
+
if (this.resizeDebounceTimer !== null) clearTimeout(this.resizeDebounceTimer);
|
|
3735
|
+
this.resizeDebounceTimer = setTimeout(() => {
|
|
3736
|
+
this.resizeDebounceTimer = null;
|
|
3737
|
+
this.updateCompactFromSpace();
|
|
3738
|
+
}, RESIZE_DEBOUNCE_MS);
|
|
3739
|
+
};
|
|
3333
3740
|
}
|
|
3334
|
-
|
|
3335
|
-
this.
|
|
3741
|
+
updateCompactFromSpace() {
|
|
3742
|
+
const toolbarItems = this.shadowRoot?.querySelector(".toolbar-items");
|
|
3743
|
+
if (!toolbarItems) return;
|
|
3744
|
+
const trimmed = toolbarItems.scrollWidth > toolbarItems.clientWidth;
|
|
3745
|
+
if (this.compact !== trimmed) this.compact = trimmed;
|
|
3336
3746
|
}
|
|
3337
|
-
|
|
3338
|
-
|
|
3747
|
+
scheduleOverflowCheck() {
|
|
3748
|
+
if (this.overflowCheckScheduled) return;
|
|
3749
|
+
this.overflowCheckScheduled = true;
|
|
3750
|
+
requestAnimationFrame(() => {
|
|
3751
|
+
this.overflowCheckScheduled = false;
|
|
3752
|
+
this.updateCompactFromSpace();
|
|
3753
|
+
});
|
|
3339
3754
|
}
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3755
|
+
connectedCallback() {
|
|
3756
|
+
super.connectedCallback();
|
|
3757
|
+
this.resizeObserver = new ResizeObserver(this.onResize);
|
|
3758
|
+
this.resizeObserver.observe(this);
|
|
3344
3759
|
}
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3760
|
+
disconnectedCallback() {
|
|
3761
|
+
this.resizeObserver?.disconnect();
|
|
3762
|
+
this.resizeObserver = null;
|
|
3763
|
+
if (this.resizeDebounceTimer !== null) {
|
|
3764
|
+
clearTimeout(this.resizeDebounceTimer);
|
|
3765
|
+
this.resizeDebounceTimer = null;
|
|
3351
3766
|
}
|
|
3767
|
+
super.disconnectedCallback();
|
|
3768
|
+
}
|
|
3769
|
+
updated(changedProperties) {
|
|
3770
|
+
super.updated?.(changedProperties);
|
|
3771
|
+
if (!this.compact) this.scheduleOverflowCheck();
|
|
3352
3772
|
}
|
|
3353
3773
|
willUpdate(changedProperties) {
|
|
3354
3774
|
super.willUpdate?.(changedProperties);
|
|
3355
|
-
if (
|
|
3775
|
+
if (changedProperties.has("scopeTokens")) this.refreshContributions();
|
|
3356
3776
|
}
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
if (!getContributionVisible(commandContribution)) return nothing;
|
|
3361
|
-
const disabled = getContributionDisabled(commandContribution);
|
|
3362
|
-
return html`
|
|
3363
|
-
<docks-command
|
|
3364
|
-
slot=${slot ?? nothing}
|
|
3365
|
-
cmd="${commandContribution.command}"
|
|
3366
|
-
icon="${commandContribution.icon || ""}"
|
|
3367
|
-
.params=${commandContribution.params || {}}
|
|
3368
|
-
?disabled="${disabled}">
|
|
3369
|
-
${commandContribution.label}
|
|
3370
|
-
</docks-command>
|
|
3371
|
-
`;
|
|
3372
|
-
}
|
|
3373
|
-
if ("component" in contribution) {
|
|
3374
|
-
const contents = contribution.component;
|
|
3375
|
-
if (contents instanceof Function) return contents();
|
|
3376
|
-
return unsafeHTML(contents);
|
|
3377
|
-
}
|
|
3378
|
-
return nothing;
|
|
3777
|
+
attributeChangedCallback(name, old, value) {
|
|
3778
|
+
super.attributeChangedCallback(name, old, value);
|
|
3779
|
+
if (name === "id" && old !== value) this.refreshContributions();
|
|
3379
3780
|
}
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
</wa-
|
|
3444
|
-
`;
|
|
3781
|
+
doBeforeUI() {
|
|
3782
|
+
this.refreshContributions();
|
|
3783
|
+
subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event) => {
|
|
3784
|
+
const id = this.getAttribute("id");
|
|
3785
|
+
if (!id) return;
|
|
3786
|
+
if (this.matchesTarget(id, event.target)) this.refreshContributions();
|
|
3787
|
+
});
|
|
3788
|
+
}
|
|
3789
|
+
refreshContributions() {
|
|
3790
|
+
const id = this.getAttribute("id");
|
|
3791
|
+
if (!id) {
|
|
3792
|
+
this.contributions = [];
|
|
3793
|
+
return;
|
|
3794
|
+
}
|
|
3795
|
+
this.loadContributions(id);
|
|
3796
|
+
}
|
|
3797
|
+
matchesTarget(id, target) {
|
|
3798
|
+
if (target === id) return true;
|
|
3799
|
+
if (!id.includes(":")) return false;
|
|
3800
|
+
const [prefix] = id.split(":");
|
|
3801
|
+
if (target === `${prefix}:*`) return true;
|
|
3802
|
+
const targetParts = target.split(":");
|
|
3803
|
+
if (targetParts.length === 2) {
|
|
3804
|
+
const categoryToken = targetParts[1];
|
|
3805
|
+
if (this.scopeTokens.includes(categoryToken)) return id.startsWith(`${prefix}:`);
|
|
3806
|
+
}
|
|
3807
|
+
return false;
|
|
3808
|
+
}
|
|
3809
|
+
loadContributions(id) {
|
|
3810
|
+
const specific = contributionRegistry.getContributions(id);
|
|
3811
|
+
if (!id.includes(":")) {
|
|
3812
|
+
this.contributions = specific;
|
|
3813
|
+
return;
|
|
3814
|
+
}
|
|
3815
|
+
const [prefix] = id.split(":");
|
|
3816
|
+
const wildcardId = `${prefix}:*`;
|
|
3817
|
+
const wildcard = contributionRegistry.getContributions(wildcardId);
|
|
3818
|
+
const categoryMatches = [];
|
|
3819
|
+
for (const category of this.scopeTokens) {
|
|
3820
|
+
const categoryId = `${prefix}:${category}`;
|
|
3821
|
+
const matches = contributionRegistry.getContributions(categoryId);
|
|
3822
|
+
categoryMatches.push(...matches);
|
|
3823
|
+
}
|
|
3824
|
+
this.contributions = [
|
|
3825
|
+
...wildcard,
|
|
3826
|
+
...categoryMatches,
|
|
3827
|
+
...specific
|
|
3828
|
+
];
|
|
3829
|
+
}
|
|
3830
|
+
isToolbarItem(contribution) {
|
|
3831
|
+
return "command" in contribution || "component" in contribution;
|
|
3832
|
+
}
|
|
3833
|
+
contributionCreator(contribution) {
|
|
3834
|
+
if ("command" in contribution) {
|
|
3835
|
+
const commandContribution = contribution;
|
|
3836
|
+
const showLabel = !this.compact && !!commandContribution.showLabel;
|
|
3837
|
+
return html`
|
|
3838
|
+
<wa-button @click=${() => void this.executeCommand(commandContribution.command, commandContribution.params || {})}
|
|
3839
|
+
title=${commandContribution.label}
|
|
3840
|
+
?disabled="${getContributionDisabled(commandContribution)}"
|
|
3841
|
+
appearance="plain" size=${this.size}>
|
|
3842
|
+
${icon(commandContribution.icon, { label: commandContribution.label })}
|
|
3843
|
+
${showLabel ? commandContribution.label : ""}
|
|
3844
|
+
</wa-button>
|
|
3845
|
+
`;
|
|
3846
|
+
}
|
|
3847
|
+
if ("component" in contribution) {
|
|
3848
|
+
const contents = contribution.component;
|
|
3849
|
+
if (contents instanceof Function) return contents();
|
|
3850
|
+
return unsafeHTML(contents);
|
|
3851
|
+
}
|
|
3852
|
+
return html`<span>unknown contribution type: ${typeof contribution}</span>`;
|
|
3853
|
+
}
|
|
3854
|
+
render() {
|
|
3855
|
+
const partContent = this.partToolbarRenderer ? this.partToolbarRenderer() : this.partToolbarContent ? this.partToolbarContent : "";
|
|
3856
|
+
const flexDir = this.orientation === "vertical" ? "column" : "row";
|
|
3857
|
+
const alignMap = {
|
|
3858
|
+
start: "flex-start",
|
|
3859
|
+
center: "center",
|
|
3860
|
+
end: "flex-end"
|
|
3861
|
+
};
|
|
3862
|
+
const bindCreator = this.contributionCreator.bind(this);
|
|
3863
|
+
const bindIsItem = this.isToolbarItem.bind(this);
|
|
3445
3864
|
return html`
|
|
3446
|
-
<
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
${
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
})}
|
|
3457
|
-
<slot></slot>
|
|
3458
|
-
</wa-button>
|
|
3865
|
+
<div class="toolbar-items" style=${styleMap({
|
|
3866
|
+
"flex-direction": flexDir,
|
|
3867
|
+
"align-items": alignMap[this.align],
|
|
3868
|
+
"justify-content": this.position
|
|
3869
|
+
})}>
|
|
3870
|
+
${renderButtonGroup("start", this.orientation, this.contributions, bindIsItem, bindCreator)}
|
|
3871
|
+
${partContent}
|
|
3872
|
+
${renderButtonGroup(void 0, this.orientation, this.contributions, bindIsItem, bindCreator)}
|
|
3873
|
+
${renderButtonGroup("end", this.orientation, this.contributions, bindIsItem, bindCreator)}
|
|
3874
|
+
</div>
|
|
3459
3875
|
`;
|
|
3460
3876
|
}
|
|
3461
3877
|
static {
|
|
3462
3878
|
this.styles = css`
|
|
3463
3879
|
:host {
|
|
3464
|
-
display:
|
|
3880
|
+
display: flex;
|
|
3881
|
+
flex-direction: row;
|
|
3882
|
+
--wa-form-control-padding-inline: var(--wa-space-2xs);
|
|
3465
3883
|
}
|
|
3466
3884
|
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
padding: 2px 6px;
|
|
3470
|
-
background: var(--wa-color-neutral-15);
|
|
3471
|
-
border: 1px solid var(--wa-color-neutral-25);
|
|
3472
|
-
border-radius: 3px;
|
|
3473
|
-
font-size: 10px;
|
|
3474
|
-
font-family: monospace;
|
|
3475
|
-
opacity: 0.7;
|
|
3885
|
+
:host([orientation="vertical"]) {
|
|
3886
|
+
flex-direction: column;
|
|
3476
3887
|
}
|
|
3477
3888
|
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3889
|
+
.toolbar-items {
|
|
3890
|
+
display: flex;
|
|
3891
|
+
flex: 1;
|
|
3892
|
+
gap: var(--wa-space-2xs);
|
|
3481
3893
|
}
|
|
3482
3894
|
`;
|
|
3483
3895
|
}
|
|
3484
3896
|
};
|
|
3485
|
-
_decorate([property()],
|
|
3486
|
-
_decorate([property({
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
})],
|
|
3490
|
-
_decorate([property()],
|
|
3491
|
-
_decorate([property()],
|
|
3492
|
-
_decorate([
|
|
3493
|
-
_decorate([
|
|
3494
|
-
_decorate([
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3897
|
+
_decorate([property()], DocksToolbar.prototype, "position", void 0);
|
|
3898
|
+
_decorate([property({ reflect: true })], DocksToolbar.prototype, "orientation", void 0);
|
|
3899
|
+
_decorate([property({ reflect: true })], DocksToolbar.prototype, "align", void 0);
|
|
3900
|
+
_decorate([property({ reflect: true })], DocksToolbar.prototype, "size", void 0);
|
|
3901
|
+
_decorate([property({ attribute: false })], DocksToolbar.prototype, "scopeTokens", void 0);
|
|
3902
|
+
_decorate([property({ attribute: false })], DocksToolbar.prototype, "partToolbarContent", void 0);
|
|
3903
|
+
_decorate([property({ attribute: false })], DocksToolbar.prototype, "partToolbarRenderer", void 0);
|
|
3904
|
+
_decorate([state()], DocksToolbar.prototype, "contributions", void 0);
|
|
3905
|
+
_decorate([state()], DocksToolbar.prototype, "compact", void 0);
|
|
3906
|
+
DocksToolbar = _decorate([customElement("docks-toolbar")], DocksToolbar);
|
|
3907
|
+
//#endregion
|
|
3908
|
+
//#region src/core/dropdown-item.ts
|
|
3909
|
+
/**
|
|
3910
|
+
* Shared render helpers for {@link https://webawesome.com/docs/components/dropdown-item | wa-dropdown-item}
|
|
3911
|
+
* rows inside any Docks popup list.
|
|
3912
|
+
*
|
|
3913
|
+
* **Docks surfaces** (distinct UX and contribution targets):
|
|
3914
|
+
* - **Toolbar dropdown** — anchored to a toolbar control (`docks-command`, `docks-toolbar`).
|
|
3915
|
+
* Part-level registry targets use the `toolbar:` prefix (e.g. `toolbar:view.filebrowser`).
|
|
3916
|
+
* - **Context menu** — opened at the pointer (`docks-contextmenu`).
|
|
3917
|
+
* Part-level registry targets use the `contextmenu:` prefix (e.g. `contextmenu:view.filebrowser`).
|
|
3918
|
+
*
|
|
3919
|
+
* A part can expose both surfaces with the same part id but different prefixes, registering
|
|
3920
|
+
* different contributions on each. Feature-scoped targets (e.g. `filebrowser.create`) may also
|
|
3921
|
+
* be referenced explicitly from either surface when several controls share the same item set.
|
|
3922
|
+
*
|
|
3923
|
+
* Command-backed items rely on the parent {@link https://webawesome.com/docs/components/dropdown | wa-dropdown}
|
|
3924
|
+
* `wa-select` event (see {@link handleDropdownWaSelect}) so the popup closes cleanly before
|
|
3925
|
+
* native dialogs such as `showDirectoryPicker` open.
|
|
3926
|
+
*/
|
|
3927
|
+
function parseDropdownItemParams(item) {
|
|
3928
|
+
const raw = item.getAttribute("data-params");
|
|
3929
|
+
if (!raw) return {};
|
|
3930
|
+
try {
|
|
3931
|
+
return JSON.parse(raw);
|
|
3932
|
+
} catch {
|
|
3933
|
+
return {};
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
function getDropdownItemCommand(item) {
|
|
3937
|
+
return item.getAttribute("data-cmd") || item.getAttribute("value") || void 0;
|
|
3938
|
+
}
|
|
3939
|
+
/** Handles `wa-select` from a parent `wa-dropdown` and runs the backing command. */
|
|
3940
|
+
function handleDropdownWaSelect(event) {
|
|
3941
|
+
const item = event.detail?.item;
|
|
3942
|
+
if (!item || item.disabled || item.hasAttribute("disabled")) return;
|
|
3943
|
+
const cmd = getDropdownItemCommand(item);
|
|
3944
|
+
if (!cmd) return;
|
|
3945
|
+
commandRegistry.execute(cmd, commandRegistry.createExecutionContext(parseDropdownItemParams(item)));
|
|
3946
|
+
}
|
|
3947
|
+
function onDropdownActionClick(options) {
|
|
3948
|
+
return (event) => {
|
|
3949
|
+
if (readReactiveBoolean(options.disabled, false)) return;
|
|
3950
|
+
event.stopPropagation();
|
|
3951
|
+
options.action?.(event);
|
|
3952
|
+
};
|
|
3953
|
+
}
|
|
3954
|
+
function keybindingDetails(cmd) {
|
|
3955
|
+
if (!cmd) return nothing;
|
|
3956
|
+
const bindings = keyBindingManager.getKeyBindingsForCommand(cmd);
|
|
3957
|
+
if (bindings.length === 0) return nothing;
|
|
3958
|
+
return html`<span slot="details">${bindings[0]}</span>`;
|
|
3959
|
+
}
|
|
3960
|
+
/** Renders a native {@link https://webawesome.com/docs/components/dropdown-item | wa-dropdown-item}. */
|
|
3961
|
+
function renderDropdownItem(options) {
|
|
3962
|
+
const iconSpec = options.icon ?? "";
|
|
3963
|
+
const paramsJson = options.params && Object.keys(options.params).length > 0 ? JSON.stringify(options.params) : void 0;
|
|
3964
|
+
return html`
|
|
3965
|
+
<wa-dropdown-item
|
|
3966
|
+
slot=${options.slot ?? nothing}
|
|
3967
|
+
variant=${options.variant ?? "default"}
|
|
3968
|
+
value=${options.cmd ?? nothing}
|
|
3969
|
+
data-cmd=${options.cmd ?? nothing}
|
|
3970
|
+
data-params=${paramsJson ?? nothing}
|
|
3971
|
+
?disabled=${readReactiveBoolean(options.disabled, false)}
|
|
3972
|
+
@click=${options.action ? onDropdownActionClick(options) : nothing}>
|
|
3973
|
+
${iconSpec ? icon(iconSpec, {
|
|
3974
|
+
label: options.title ?? options.label,
|
|
3975
|
+
slot: "icon"
|
|
3976
|
+
}) : nothing}
|
|
3977
|
+
${options.label}
|
|
3978
|
+
${keybindingDetails(options.cmd)}
|
|
3979
|
+
</wa-dropdown-item>
|
|
3980
|
+
`;
|
|
3981
|
+
}
|
|
3982
|
+
function renderCommandContribution(contribution, options) {
|
|
3983
|
+
if (!getContributionVisible(contribution)) return nothing;
|
|
3984
|
+
return renderDropdownItem({
|
|
3985
|
+
cmd: contribution.command,
|
|
3986
|
+
icon: contribution.icon,
|
|
3987
|
+
label: contribution.label,
|
|
3988
|
+
params: contribution.params,
|
|
3989
|
+
disabled: contribution.disabled,
|
|
3990
|
+
slot: options?.slot
|
|
3991
|
+
});
|
|
3992
|
+
}
|
|
3993
|
+
function renderDropdownContribution(contribution, options) {
|
|
3994
|
+
if ("command" in contribution) return renderCommandContribution(contribution, options);
|
|
3995
|
+
if ("component" in contribution) {
|
|
3996
|
+
if (!getContributionVisible(contribution)) return nothing;
|
|
3997
|
+
const contents = contribution.component;
|
|
3998
|
+
if (contents instanceof Function) return contents();
|
|
3999
|
+
return html`${unsafeHTML(contents)}`;
|
|
4000
|
+
}
|
|
4001
|
+
return nothing;
|
|
4002
|
+
}
|
|
4003
|
+
/** Renders all visible contributions registered for a contribution target. */
|
|
4004
|
+
function renderDropdownContributions(target, options) {
|
|
4005
|
+
return html`${contributionRegistry.getContributions(target).map((c) => renderDropdownContribution(c, options)).filter((item) => item !== nothing)}`;
|
|
4006
|
+
}
|
|
4007
|
+
/** Renders a {@link wa-dropdown-item} with nested items from a contribution target in {@code slot="submenu"}. */
|
|
4008
|
+
function renderDropdownSubmenu(options) {
|
|
4009
|
+
return html`
|
|
4010
|
+
<wa-dropdown-item ?disabled=${readReactiveBoolean(options.disabled, false)}>
|
|
4011
|
+
${options.icon ? icon(options.icon, {
|
|
4012
|
+
label: options.title ?? options.label,
|
|
4013
|
+
slot: "icon"
|
|
4014
|
+
}) : nothing}
|
|
4015
|
+
${options.label}
|
|
4016
|
+
${renderDropdownContributions(options.contributionTarget, { slot: "submenu" })}
|
|
4017
|
+
</wa-dropdown-item>
|
|
4018
|
+
`;
|
|
4019
|
+
}
|
|
3509
4020
|
//#endregion
|
|
3510
4021
|
//#region src/parts/contextmenu.ts
|
|
3511
4022
|
var DocksContextMenu = class DocksContextMenu extends DocksElement {
|
|
@@ -3515,11 +4026,14 @@ var DocksContextMenu = class DocksContextMenu extends DocksElement {
|
|
|
3515
4026
|
this.partContextMenuRenderer = void 0;
|
|
3516
4027
|
this.contributions = [];
|
|
3517
4028
|
this.isOpen = false;
|
|
3518
|
-
this.
|
|
4029
|
+
this.menuPosition = {
|
|
3519
4030
|
x: 0,
|
|
3520
4031
|
y: 0
|
|
3521
4032
|
};
|
|
3522
|
-
this.
|
|
4033
|
+
this.virtualAnchor = { getBoundingClientRect: () => {
|
|
4034
|
+
const { x, y } = this.menuPosition;
|
|
4035
|
+
return new DOMRect(x, y, 0, 0);
|
|
4036
|
+
} };
|
|
3523
4037
|
this.dropdownRef = createRef();
|
|
3524
4038
|
this.boundHandleDocumentPointerDown = this.handleDocumentPointerDown.bind(this);
|
|
3525
4039
|
this.handleSubmenuOpening = (event) => {
|
|
@@ -3623,410 +4137,128 @@ var DocksContextMenu = class DocksContextMenu extends DocksElement {
|
|
|
3623
4137
|
while (element) {
|
|
3624
4138
|
const shadowRoot = element.shadowRoot;
|
|
3625
4139
|
if (shadowRoot) {
|
|
3626
|
-
const shadowElement = shadowRoot.elementFromPoint(x, y);
|
|
3627
|
-
if (shadowElement && shadowElement !== element) {
|
|
3628
|
-
element = shadowElement;
|
|
3629
|
-
continue;
|
|
3630
|
-
}
|
|
3631
|
-
}
|
|
3632
|
-
break;
|
|
3633
|
-
}
|
|
3634
|
-
return element;
|
|
3635
|
-
}
|
|
3636
|
-
getHostPart() {
|
|
3637
|
-
const root = this.getRootNode();
|
|
3638
|
-
if (root instanceof ShadowRoot && root.host instanceof HTMLElement) return root.host;
|
|
3639
|
-
return null;
|
|
3640
|
-
}
|
|
3641
|
-
/**
|
|
3642
|
-
* Triggers a click on the element under the cursor to update selection before showing context menu.
|
|
3643
|
-
*/
|
|
3644
|
-
triggerClickUnderCursor(mouseEvent) {
|
|
3645
|
-
const elementUnderCursor = this.getElementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
|
|
3646
|
-
if (elementUnderCursor) {
|
|
3647
|
-
const clickEvent = new MouseEvent("click", {
|
|
3648
|
-
bubbles: true,
|
|
3649
|
-
cancelable: true,
|
|
3650
|
-
view: window,
|
|
3651
|
-
clientX: mouseEvent.clientX,
|
|
3652
|
-
clientY: mouseEvent.clientY,
|
|
3653
|
-
screenX: mouseEvent.screenX,
|
|
3654
|
-
screenY: mouseEvent.screenY,
|
|
3655
|
-
button: 0,
|
|
3656
|
-
buttons: 0,
|
|
3657
|
-
detail: 1,
|
|
3658
|
-
which: 1
|
|
3659
|
-
});
|
|
3660
|
-
elementUnderCursor.dispatchEvent(clickEvent);
|
|
3661
|
-
}
|
|
3662
|
-
}
|
|
3663
|
-
/** Opens the menu at `position`. Returns false when there is nothing to show (no thin empty panel). */
|
|
3664
|
-
async show(position, mouseEvent) {
|
|
3665
|
-
if (!this.hasMenuBody()) return false;
|
|
3666
|
-
if (mouseEvent) {
|
|
3667
|
-
this.triggerClickUnderCursor(mouseEvent);
|
|
3668
|
-
await this.getHostPart()?.updateComplete;
|
|
3669
|
-
}
|
|
3670
|
-
if (this.isOpen) {
|
|
3671
|
-
this.isOpen = false;
|
|
3672
|
-
await this.updateComplete;
|
|
3673
|
-
}
|
|
3674
|
-
this.position = position;
|
|
3675
|
-
this.isOpen = true;
|
|
3676
|
-
await this.updateComplete;
|
|
3677
|
-
document.addEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
3678
|
-
return true;
|
|
3679
|
-
}
|
|
3680
|
-
onClose() {
|
|
3681
|
-
if (!this.isOpen) return;
|
|
3682
|
-
this.isOpen = false;
|
|
3683
|
-
document.removeEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
3684
|
-
}
|
|
3685
|
-
renderContribution(contribution) {
|
|
3686
|
-
if ("command" in contribution) {
|
|
3687
|
-
const commandContribution = contribution;
|
|
3688
|
-
if (!getContributionVisible(commandContribution)) return nothing;
|
|
3689
|
-
const disabled = getContributionDisabled(commandContribution);
|
|
3690
|
-
return html`
|
|
3691
|
-
<docks-command
|
|
3692
|
-
cmd="${commandContribution.command}"
|
|
3693
|
-
icon="${commandContribution.icon ?? ""}"
|
|
3694
|
-
.params=${commandContribution.params ?? {}}
|
|
3695
|
-
?disabled="${disabled}">
|
|
3696
|
-
${commandContribution.label}
|
|
3697
|
-
</docks-command>
|
|
3698
|
-
`;
|
|
3699
|
-
} else if ("component" in contribution) {
|
|
3700
|
-
const contents = contribution.component;
|
|
3701
|
-
if (contents instanceof Function) return contents();
|
|
3702
|
-
return unsafeHTML(contents);
|
|
3703
|
-
}
|
|
3704
|
-
return nothing;
|
|
3705
|
-
}
|
|
3706
|
-
render() {
|
|
3707
|
-
const partContent = this.partContextMenuRenderer ? this.partContextMenuRenderer() : nothing;
|
|
3708
|
-
return html`
|
|
3709
|
-
<wa-dropdown
|
|
3710
|
-
${ref(this.dropdownRef)}
|
|
3711
|
-
?open=${this.isOpen}
|
|
3712
|
-
@submenu-opening=${this.handleSubmenuOpening}
|
|
3713
|
-
@wa-after-hide=${this.onClose}>
|
|
3714
|
-
|
|
3715
|
-
<div
|
|
3716
|
-
slot="trigger"
|
|
3717
|
-
${ref(this.anchorRef)}
|
|
3718
|
-
style="position: fixed;
|
|
3719
|
-
left: ${this.position.x}px;
|
|
3720
|
-
top: ${this.position.y}px;
|
|
3721
|
-
width: 1px;
|
|
3722
|
-
height: 1px;
|
|
3723
|
-
pointer-events: none;">
|
|
3724
|
-
</div>
|
|
3725
|
-
|
|
3726
|
-
${partContent}
|
|
3727
|
-
${this.contributions.map((c) => this.renderContribution(c))}
|
|
3728
|
-
</wa-dropdown>
|
|
3729
|
-
`;
|
|
3730
|
-
}
|
|
3731
|
-
static {
|
|
3732
|
-
this.styles = css`
|
|
3733
|
-
:host {
|
|
3734
|
-
position: fixed;
|
|
3735
|
-
top: 0;
|
|
3736
|
-
left: 0;
|
|
3737
|
-
width: 0;
|
|
3738
|
-
height: 0;
|
|
3739
|
-
pointer-events: none;
|
|
3740
|
-
z-index: 10000;
|
|
3741
|
-
}
|
|
3742
|
-
|
|
3743
|
-
wa-dropdown {
|
|
3744
|
-
pointer-events: none;
|
|
3745
|
-
min-width: 200px;
|
|
3746
|
-
}
|
|
3747
|
-
|
|
3748
|
-
wa-dropdown:state(open) {
|
|
3749
|
-
pointer-events: auto;
|
|
3750
|
-
}
|
|
3751
|
-
|
|
3752
|
-
wa-dropdown::part(menu) {
|
|
3753
|
-
min-width: 200px;
|
|
3754
|
-
}
|
|
3755
|
-
`;
|
|
3756
|
-
}
|
|
3757
|
-
};
|
|
3758
|
-
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "scopeTokens", void 0);
|
|
3759
|
-
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "partContextMenuRenderer", void 0);
|
|
3760
|
-
_decorate([state()], DocksContextMenu.prototype, "contributions", void 0);
|
|
3761
|
-
_decorate([state()], DocksContextMenu.prototype, "isOpen", void 0);
|
|
3762
|
-
_decorate([state()], DocksContextMenu.prototype, "position", void 0);
|
|
3763
|
-
DocksContextMenu = _decorate([customElement("docks-contextmenu")], DocksContextMenu);
|
|
3764
|
-
//#endregion
|
|
3765
|
-
//#region src/parts/container.ts
|
|
3766
|
-
var DocksContainer = class extends DocksElement {};
|
|
3767
|
-
//#endregion
|
|
3768
|
-
//#region src/parts/part.ts
|
|
3769
|
-
var DocksPart = class DocksPart extends DocksContainer {
|
|
3770
|
-
constructor(..._args) {
|
|
3771
|
-
super(..._args);
|
|
3772
|
-
this.scrollMode = "scroller";
|
|
3773
|
-
this.dirty = false;
|
|
3774
|
-
this.isEditor = false;
|
|
3775
|
-
this.onContentContextMenu = async (event) => {
|
|
3776
|
-
const contextMenu = this.renderRoot.querySelector("docks-contextmenu");
|
|
3777
|
-
if (!contextMenu) return;
|
|
3778
|
-
if (await contextMenu.show({
|
|
3779
|
-
x: event.clientX,
|
|
3780
|
-
y: event.clientY
|
|
3781
|
-
}, event)) event.preventDefault();
|
|
3782
|
-
};
|
|
3783
|
-
}
|
|
3784
|
-
getCommandStack() {
|
|
3785
|
-
return this.commandStack;
|
|
3786
|
-
}
|
|
3787
|
-
/**
|
|
3788
|
-
* Override this method to provide toolbar content for this part.
|
|
3789
|
-
* This is a lightweight alternative to registering toolbar contributions
|
|
3790
|
-
* for actions that are scoped to this part instance.
|
|
3791
|
-
*
|
|
3792
|
-
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3793
|
-
* The toolbar template is rendered in a different component (docks-toolbar), so direct method
|
|
3794
|
-
* references lose their binding.
|
|
3795
|
-
*
|
|
3796
|
-
* ✅ Correct:
|
|
3797
|
-
* @click=${() => this.myMethod()}
|
|
3798
|
-
* @click=${(e) => this.handleClick(e)}
|
|
3799
|
-
*
|
|
3800
|
-
* ❌ Wrong (this will be bound to the toolbar, not your component):
|
|
3801
|
-
* @click=${this.myMethod}
|
|
3802
|
-
*
|
|
3803
|
-
* Example:
|
|
3804
|
-
* ```typescript
|
|
3805
|
-
* protected renderToolbar() {
|
|
3806
|
-
* return html`
|
|
3807
|
-
* <wa-button @click=${() => this.save()} title="Save">
|
|
3808
|
-
* <wa-icon name="save"></wa-icon>
|
|
3809
|
-
* </wa-button>
|
|
3810
|
-
* `;
|
|
3811
|
-
* }
|
|
3812
|
-
* ```
|
|
3813
|
-
*
|
|
3814
|
-
* @returns TemplateResult with toolbar items, or nothing if no toolbar needed
|
|
3815
|
-
*/
|
|
3816
|
-
renderToolbar() {
|
|
3817
|
-
return nothing;
|
|
3818
|
-
}
|
|
3819
|
-
/**
|
|
3820
|
-
* Activates the tab that contains this part by walking up the DOM to the first
|
|
3821
|
-
* docks-tabs ancestor and activating the tab panel that contains this part.
|
|
3822
|
-
* Crosses Shadow DOM boundaries (e.g. wa-tab-group) via getRootNode().host.
|
|
3823
|
-
* No-op if this part is not inside a docks-tabs / wa-tab-panel.
|
|
3824
|
-
*/
|
|
3825
|
-
activateContainingTab() {
|
|
3826
|
-
let el = this;
|
|
3827
|
-
let panelName = null;
|
|
3828
|
-
let tabsEl = null;
|
|
3829
|
-
while (el) {
|
|
3830
|
-
const tag = el.tagName?.toLowerCase();
|
|
3831
|
-
if (tag === "wa-tab-panel") panelName = el.getAttribute("name");
|
|
3832
|
-
if (tag === "docks-tabs") {
|
|
3833
|
-
tabsEl = el;
|
|
3834
|
-
break;
|
|
3835
|
-
}
|
|
3836
|
-
const parent = el.parentElement;
|
|
3837
|
-
if (parent) el = parent;
|
|
3838
|
-
else {
|
|
3839
|
-
const root = el.getRootNode();
|
|
3840
|
-
el = root instanceof ShadowRoot ? root.host : null;
|
|
3841
|
-
}
|
|
3842
|
-
}
|
|
3843
|
-
if (tabsEl && panelName != null && panelName !== "") tabsEl.activate(panelName);
|
|
3844
|
-
}
|
|
3845
|
-
/**
|
|
3846
|
-
* Override this method to provide context menu content for this part.
|
|
3847
|
-
* This is a lightweight alternative to registering context menu contributions
|
|
3848
|
-
* for actions that are scoped to this part instance.
|
|
3849
|
-
*
|
|
3850
|
-
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3851
|
-
* The context menu is rendered in a different component (contextmenu), so direct method
|
|
3852
|
-
* references lose their binding.
|
|
3853
|
-
*
|
|
3854
|
-
* ✅ Correct:
|
|
3855
|
-
* @click=${() => this.myMethod()}
|
|
3856
|
-
* @click=${(e) => this.handleClick(e)}
|
|
3857
|
-
*
|
|
3858
|
-
* ❌ Wrong (this will be bound to the context menu, not your component):
|
|
3859
|
-
* @click=${this.myMethod}
|
|
3860
|
-
*
|
|
3861
|
-
* Example:
|
|
3862
|
-
* ```typescript
|
|
3863
|
-
* protected renderContextMenu() {
|
|
3864
|
-
* return html`
|
|
3865
|
-
* <wa-dropdown-item @click=${() => this.open()}>
|
|
3866
|
-
* <wa-icon name="folder-open"></wa-icon>
|
|
3867
|
-
* Open
|
|
3868
|
-
* </wa-dropdown-item>
|
|
3869
|
-
* <wa-divider></wa-divider>
|
|
3870
|
-
* <wa-dropdown-item @click=${() => this.delete()}>
|
|
3871
|
-
* <wa-icon name="trash"></wa-icon>
|
|
3872
|
-
* Delete
|
|
3873
|
-
* </wa-dropdown-item>
|
|
3874
|
-
* `;
|
|
3875
|
-
* }
|
|
3876
|
-
* ```
|
|
3877
|
-
*
|
|
3878
|
-
* @returns TemplateResult with context menu items, or nothing if no context menu needed
|
|
3879
|
-
*/
|
|
3880
|
-
renderContextMenu() {
|
|
3881
|
-
return nothing;
|
|
3882
|
-
}
|
|
3883
|
-
renderContent() {
|
|
3884
|
-
return nothing;
|
|
3885
|
-
}
|
|
3886
|
-
getToolbarTarget() {
|
|
3887
|
-
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3888
|
-
return contributionKey ? `toolbar:${contributionKey}` : void 0;
|
|
3889
|
-
}
|
|
3890
|
-
getContextMenuTarget() {
|
|
3891
|
-
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3892
|
-
return contributionKey ? `contextmenu:${contributionKey}` : void 0;
|
|
3893
|
-
}
|
|
3894
|
-
syncIsEditorCapability() {
|
|
3895
|
-
const next = this.save !== DocksPart.prototype.save;
|
|
3896
|
-
if (next === this.isEditor) return;
|
|
3897
|
-
this.isEditor = next;
|
|
3898
|
-
}
|
|
3899
|
-
maybeActivateForCoupledEditors() {
|
|
3900
|
-
const coupled = this.tabContribution?.coupledEditors;
|
|
3901
|
-
if (!coupled?.length) return;
|
|
3902
|
-
const active = activeEditorSignal.get();
|
|
3903
|
-
if (!(active instanceof DocksPart)) return;
|
|
3904
|
-
const editorId = active.tabContribution?.editorId;
|
|
3905
|
-
if (!editorId || !coupled.includes(editorId)) return;
|
|
3906
|
-
this.activateContainingTab();
|
|
3907
|
-
}
|
|
3908
|
-
render() {
|
|
3909
|
-
const toolbarTarget = this.getToolbarTarget();
|
|
3910
|
-
const contextMenuTarget = this.getContextMenuTarget();
|
|
3911
|
-
const toolbarEnabled = this.tabContribution?.toolbar !== false;
|
|
3912
|
-
const contextMenuEnabled = this.tabContribution?.contextMenu !== false;
|
|
3913
|
-
const scrollMode = this.scrollMode;
|
|
3914
|
-
const scopeTokens = this.isEditor ? ["system.editors", ".system.editors"] : [];
|
|
3915
|
-
const content = this.renderContent();
|
|
3916
|
-
const contentNode = scrollMode === "scroller" ? html`
|
|
3917
|
-
<wa-scroller class="part-content-scroll" orientation="vertical">
|
|
3918
|
-
<div class="part-content-inner">${content}</div>
|
|
3919
|
-
</wa-scroller>
|
|
3920
|
-
` : html`<div class="part-content-inner">${content}</div>`;
|
|
3921
|
-
return html`
|
|
3922
|
-
<div class="part-shell">
|
|
3923
|
-
${toolbarEnabled ? html`
|
|
3924
|
-
<docks-toolbar
|
|
3925
|
-
class="part-toolbar"
|
|
3926
|
-
id=${ifDefined(toolbarTarget)}
|
|
3927
|
-
.scopeTokens=${scopeTokens}
|
|
3928
|
-
.partToolbarRenderer=${() => this.renderToolbar()}>
|
|
3929
|
-
</docks-toolbar>
|
|
3930
|
-
` : nothing}
|
|
3931
|
-
<div class="part-content ${scrollMode === "native" ? "native-scroll" : ""}" @contextmenu=${contextMenuEnabled ? this.onContentContextMenu : void 0}>
|
|
3932
|
-
${contentNode}
|
|
3933
|
-
</div>
|
|
3934
|
-
${contextMenuEnabled ? html`
|
|
3935
|
-
<docks-contextmenu
|
|
3936
|
-
id=${ifDefined(contextMenuTarget)}
|
|
3937
|
-
.scopeTokens=${scopeTokens}
|
|
3938
|
-
.partContextMenuRenderer=${() => this.renderContextMenu()}>
|
|
3939
|
-
</docks-contextmenu>
|
|
3940
|
-
` : nothing}
|
|
3941
|
-
</div>
|
|
3942
|
-
`;
|
|
4140
|
+
const shadowElement = shadowRoot.elementFromPoint(x, y);
|
|
4141
|
+
if (shadowElement && shadowElement !== element) {
|
|
4142
|
+
element = shadowElement;
|
|
4143
|
+
continue;
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
break;
|
|
4147
|
+
}
|
|
4148
|
+
return element;
|
|
3943
4149
|
}
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
4150
|
+
getHostPart() {
|
|
4151
|
+
const root = this.getRootNode();
|
|
4152
|
+
if (root instanceof ShadowRoot && root.host instanceof HTMLElement) return root.host;
|
|
4153
|
+
return null;
|
|
4154
|
+
}
|
|
4155
|
+
/**
|
|
4156
|
+
* Triggers a click on the element under the cursor to update selection before showing context menu.
|
|
4157
|
+
*/
|
|
4158
|
+
triggerClickUnderCursor(mouseEvent) {
|
|
4159
|
+
const elementUnderCursor = this.getElementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
|
|
4160
|
+
if (elementUnderCursor) {
|
|
4161
|
+
const clickEvent = new MouseEvent("click", {
|
|
4162
|
+
bubbles: true,
|
|
4163
|
+
cancelable: true,
|
|
4164
|
+
view: window,
|
|
4165
|
+
clientX: mouseEvent.clientX,
|
|
4166
|
+
clientY: mouseEvent.clientY,
|
|
4167
|
+
screenX: mouseEvent.screenX,
|
|
4168
|
+
screenY: mouseEvent.screenY,
|
|
4169
|
+
button: 0,
|
|
4170
|
+
buttons: 0,
|
|
4171
|
+
detail: 1,
|
|
4172
|
+
which: 1
|
|
4173
|
+
});
|
|
4174
|
+
elementUnderCursor.dispatchEvent(clickEvent);
|
|
3953
4175
|
}
|
|
3954
4176
|
}
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
4177
|
+
/** Opens the menu at `position`. Returns false when there is nothing to show (no thin empty panel). */
|
|
4178
|
+
async show(position, mouseEvent) {
|
|
4179
|
+
if (!this.hasMenuBody()) return false;
|
|
4180
|
+
if (mouseEvent) {
|
|
4181
|
+
this.triggerClickUnderCursor(mouseEvent);
|
|
4182
|
+
await this.getHostPart()?.updateComplete;
|
|
4183
|
+
}
|
|
4184
|
+
if (this.isOpen) {
|
|
4185
|
+
this.isOpen = false;
|
|
4186
|
+
await this.updateComplete;
|
|
4187
|
+
}
|
|
4188
|
+
this.menuPosition = position;
|
|
4189
|
+
this.isOpen = true;
|
|
4190
|
+
await this.updateComplete;
|
|
4191
|
+
this.syncVirtualPopupAnchor();
|
|
4192
|
+
document.addEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
4193
|
+
return true;
|
|
3958
4194
|
}
|
|
3959
|
-
|
|
3960
|
-
|
|
4195
|
+
/** Points wa-dropdown's internal wa-popup at the pointer via a VirtualElement anchor. */
|
|
4196
|
+
syncVirtualPopupAnchor() {
|
|
4197
|
+
const popup = this.dropdownRef.value?.shadowRoot?.querySelector("wa-popup");
|
|
4198
|
+
if (!popup) return;
|
|
4199
|
+
popup.anchor = this.virtualAnchor;
|
|
4200
|
+
popup.reposition();
|
|
3961
4201
|
}
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
this.
|
|
3965
|
-
|
|
3966
|
-
this.watch(activeEditorSignal, () => this.maybeActivateForCoupledEditors());
|
|
4202
|
+
onClose() {
|
|
4203
|
+
if (!this.isOpen) return;
|
|
4204
|
+
this.isOpen = false;
|
|
4205
|
+
document.removeEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
3967
4206
|
}
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
4207
|
+
updated(changedProperties) {
|
|
4208
|
+
super.updated(changedProperties);
|
|
4209
|
+
if (changedProperties.has("isOpen") && this.isOpen) this.syncVirtualPopupAnchor();
|
|
3971
4210
|
}
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
4211
|
+
renderContribution(contribution) {
|
|
4212
|
+
return renderDropdownContribution(contribution);
|
|
4213
|
+
}
|
|
4214
|
+
render() {
|
|
4215
|
+
const partContent = this.partContextMenuRenderer ? this.partContextMenuRenderer() : nothing;
|
|
4216
|
+
return html`
|
|
4217
|
+
<wa-dropdown
|
|
4218
|
+
${ref(this.dropdownRef)}
|
|
4219
|
+
?open=${this.isOpen}
|
|
4220
|
+
@submenu-opening=${this.handleSubmenuOpening}
|
|
4221
|
+
@wa-select=${handleDropdownWaSelect}
|
|
4222
|
+
@wa-after-hide=${this.onClose}>
|
|
4223
|
+
<span slot="trigger" hidden aria-hidden="true"></span>
|
|
4224
|
+
|
|
4225
|
+
${partContent}
|
|
4226
|
+
${this.contributions.map((c) => this.renderContribution(c))}
|
|
4227
|
+
</wa-dropdown>
|
|
4228
|
+
`;
|
|
3978
4229
|
}
|
|
3979
4230
|
static {
|
|
3980
|
-
this.
|
|
4231
|
+
this.styles = css`
|
|
3981
4232
|
:host {
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
width: 100%;
|
|
3990
|
-
position: relative;
|
|
3991
|
-
overflow: hidden;
|
|
3992
|
-
}
|
|
3993
|
-
|
|
3994
|
-
.part-content {
|
|
3995
|
-
min-height: 0;
|
|
3996
|
-
overflow: hidden;
|
|
3997
|
-
position: relative;
|
|
3998
|
-
}
|
|
3999
|
-
|
|
4000
|
-
.part-content.native-scroll {
|
|
4001
|
-
overflow: auto;
|
|
4233
|
+
position: fixed;
|
|
4234
|
+
top: 0;
|
|
4235
|
+
left: 0;
|
|
4236
|
+
width: 0;
|
|
4237
|
+
height: 0;
|
|
4238
|
+
pointer-events: none;
|
|
4239
|
+
z-index: 10000;
|
|
4002
4240
|
}
|
|
4003
4241
|
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4242
|
+
wa-dropdown {
|
|
4243
|
+
pointer-events: none;
|
|
4244
|
+
min-width: 200px;
|
|
4007
4245
|
}
|
|
4008
4246
|
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
min-height: 100%;
|
|
4247
|
+
wa-dropdown:state(open) {
|
|
4248
|
+
pointer-events: auto;
|
|
4012
4249
|
}
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
min-
|
|
4250
|
+
|
|
4251
|
+
wa-dropdown::part(menu) {
|
|
4252
|
+
min-width: 200px;
|
|
4016
4253
|
}
|
|
4017
4254
|
`;
|
|
4018
4255
|
}
|
|
4019
|
-
static finalizeStyles(styles) {
|
|
4020
|
-
const own = super.finalizeStyles(styles);
|
|
4021
|
-
return [DocksPart.baseStyles, ...own];
|
|
4022
|
-
}
|
|
4023
4256
|
};
|
|
4024
|
-
_decorate([property()],
|
|
4025
|
-
_decorate([property({ attribute: false })],
|
|
4026
|
-
_decorate([
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
})], DocksPart.prototype, "isEditor", void 0);
|
|
4257
|
+
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "scopeTokens", void 0);
|
|
4258
|
+
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "partContextMenuRenderer", void 0);
|
|
4259
|
+
_decorate([state()], DocksContextMenu.prototype, "contributions", void 0);
|
|
4260
|
+
_decorate([state()], DocksContextMenu.prototype, "isOpen", void 0);
|
|
4261
|
+
DocksContextMenu = _decorate([customElement("docks-contextmenu")], DocksContextMenu);
|
|
4030
4262
|
//#endregion
|
|
4031
4263
|
//#region src/parts/tabs.ts
|
|
4032
4264
|
var _DocksTabs;
|
|
@@ -4040,6 +4272,8 @@ var DocksTabs = class DocksTabs extends DocksContainer {
|
|
|
4040
4272
|
this.iconOnly = false;
|
|
4041
4273
|
this.withToolbar = false;
|
|
4042
4274
|
this.hideTabs = false;
|
|
4275
|
+
this.fitContent = false;
|
|
4276
|
+
this.fillHeight = false;
|
|
4043
4277
|
this.itemSize = "m";
|
|
4044
4278
|
this.contributions = [];
|
|
4045
4279
|
this.tabGroup = createRef();
|
|
@@ -4092,6 +4326,11 @@ var DocksTabs = class DocksTabs extends DocksContainer {
|
|
|
4092
4326
|
if (!this.tabGroup.value) return null;
|
|
4093
4327
|
return this.tabGroup.value.getAttribute("active");
|
|
4094
4328
|
}
|
|
4329
|
+
getTabPart(tabName) {
|
|
4330
|
+
const tabPanel = this.getTabPanel(tabName);
|
|
4331
|
+
if (!tabPanel) return null;
|
|
4332
|
+
return this.getPartFromPanel(tabPanel);
|
|
4333
|
+
}
|
|
4095
4334
|
open(contribution) {
|
|
4096
4335
|
if (this.contributions.find((c) => c.name === contribution.name)) {
|
|
4097
4336
|
this.activate(contribution.name);
|
|
@@ -4341,6 +4580,95 @@ var DocksTabs = class DocksTabs extends DocksContainer {
|
|
|
4341
4580
|
width: 100%;
|
|
4342
4581
|
}
|
|
4343
4582
|
|
|
4583
|
+
:host([fit-content]) {
|
|
4584
|
+
display: flex;
|
|
4585
|
+
flex-direction: column;
|
|
4586
|
+
height: auto;
|
|
4587
|
+
max-height: 100%;
|
|
4588
|
+
min-height: 0;
|
|
4589
|
+
}
|
|
4590
|
+
|
|
4591
|
+
:host([fit-content]) wa-tab-group {
|
|
4592
|
+
display: flex;
|
|
4593
|
+
flex-direction: column;
|
|
4594
|
+
flex: 1 1 auto;
|
|
4595
|
+
min-height: 0;
|
|
4596
|
+
height: auto;
|
|
4597
|
+
max-height: 100%;
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4600
|
+
:host([fit-content]) wa-tab-group::part(base) {
|
|
4601
|
+
display: flex;
|
|
4602
|
+
flex-direction: column;
|
|
4603
|
+
flex: 1 1 auto;
|
|
4604
|
+
min-height: 0;
|
|
4605
|
+
max-height: 100%;
|
|
4606
|
+
height: auto;
|
|
4607
|
+
}
|
|
4608
|
+
|
|
4609
|
+
:host([fit-content]) wa-tab-group::part(body) {
|
|
4610
|
+
flex: 1 1 auto;
|
|
4611
|
+
min-height: 0;
|
|
4612
|
+
height: auto;
|
|
4613
|
+
overflow-x: hidden;
|
|
4614
|
+
overflow-y: auto;
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4617
|
+
:host([fit-content]) wa-tab-panel[active] {
|
|
4618
|
+
display: block;
|
|
4619
|
+
height: auto;
|
|
4620
|
+
overflow: visible;
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
:host([fit-content]) wa-tab-panel > * {
|
|
4624
|
+
height: auto;
|
|
4625
|
+
min-height: 0;
|
|
4626
|
+
}
|
|
4627
|
+
|
|
4628
|
+
:host([fill-height]) {
|
|
4629
|
+
display: flex;
|
|
4630
|
+
flex-direction: column;
|
|
4631
|
+
height: 100%;
|
|
4632
|
+
min-height: 0;
|
|
4633
|
+
max-height: 100%;
|
|
4634
|
+
}
|
|
4635
|
+
|
|
4636
|
+
:host([fill-height]) wa-tab-group {
|
|
4637
|
+
display: flex;
|
|
4638
|
+
flex-direction: column;
|
|
4639
|
+
flex: 1 1 auto;
|
|
4640
|
+
min-height: 0;
|
|
4641
|
+
height: 100%;
|
|
4642
|
+
max-height: 100%;
|
|
4643
|
+
}
|
|
4644
|
+
|
|
4645
|
+
:host([fill-height]) wa-tab-group::part(base) {
|
|
4646
|
+
display: flex;
|
|
4647
|
+
flex-direction: column;
|
|
4648
|
+
flex: 1 1 auto;
|
|
4649
|
+
min-height: 0;
|
|
4650
|
+
max-height: 100%;
|
|
4651
|
+
height: 100%;
|
|
4652
|
+
}
|
|
4653
|
+
|
|
4654
|
+
:host([fill-height]) wa-tab-group::part(body) {
|
|
4655
|
+
flex: 1 1 auto;
|
|
4656
|
+
min-height: 0;
|
|
4657
|
+
overflow-x: hidden;
|
|
4658
|
+
overflow-y: auto;
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4661
|
+
:host([fill-height]) wa-tab-panel[active] {
|
|
4662
|
+
display: block;
|
|
4663
|
+
height: auto;
|
|
4664
|
+
overflow: visible;
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
:host([fill-height]) wa-tab-panel > * {
|
|
4668
|
+
height: auto;
|
|
4669
|
+
min-height: 0;
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4344
4672
|
wa-tab-group {
|
|
4345
4673
|
height: 100%;
|
|
4346
4674
|
width: 100%;
|
|
@@ -4568,6 +4896,16 @@ _decorate([property({
|
|
|
4568
4896
|
reflect: true,
|
|
4569
4897
|
attribute: "hide-tabs"
|
|
4570
4898
|
})], DocksTabs.prototype, "hideTabs", void 0);
|
|
4899
|
+
_decorate([property({
|
|
4900
|
+
type: Boolean,
|
|
4901
|
+
reflect: true,
|
|
4902
|
+
attribute: "fit-content"
|
|
4903
|
+
})], DocksTabs.prototype, "fitContent", void 0);
|
|
4904
|
+
_decorate([property({
|
|
4905
|
+
type: Boolean,
|
|
4906
|
+
reflect: true,
|
|
4907
|
+
attribute: "fill-height"
|
|
4908
|
+
})], DocksTabs.prototype, "fillHeight", void 0);
|
|
4571
4909
|
_decorate([property({
|
|
4572
4910
|
reflect: true,
|
|
4573
4911
|
attribute: "item-size"
|
|
@@ -4607,9 +4945,9 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
|
|
|
4607
4945
|
this.gridChildren = [];
|
|
4608
4946
|
this.resizing = null;
|
|
4609
4947
|
this.resizeOverlay = null;
|
|
4610
|
-
this.childrenLoaded = false;
|
|
4611
4948
|
this.childStylesApplied = false;
|
|
4612
|
-
this.
|
|
4949
|
+
this.refreshScheduled = false;
|
|
4950
|
+
this.layoutGeneration = 0;
|
|
4613
4951
|
this.handleResize = (e) => {
|
|
4614
4952
|
if (!this.resizing) return;
|
|
4615
4953
|
const delta = (this.orientation === "horizontal" ? e.clientX : e.clientY) - this.resizing.startPos;
|
|
@@ -4659,56 +4997,108 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
|
|
|
4659
4997
|
return this;
|
|
4660
4998
|
}
|
|
4661
4999
|
doBeforeUI() {
|
|
4662
|
-
|
|
4663
|
-
this.
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
5000
|
+
this.mutationObserver = new MutationObserver(() => {
|
|
5001
|
+
this.scheduleRefreshGridLayout();
|
|
5002
|
+
});
|
|
5003
|
+
this.mutationObserver.observe(this, {
|
|
5004
|
+
childList: true,
|
|
5005
|
+
subtree: false
|
|
5006
|
+
});
|
|
5007
|
+
this.scheduleRefreshGridLayout();
|
|
5008
|
+
}
|
|
5009
|
+
scheduleRefreshGridLayout() {
|
|
5010
|
+
if (this.refreshScheduled) return;
|
|
5011
|
+
this.refreshScheduled = true;
|
|
5012
|
+
queueMicrotask(() => {
|
|
5013
|
+
this.refreshScheduled = false;
|
|
5014
|
+
this.refreshGridLayout();
|
|
5015
|
+
});
|
|
4672
5016
|
}
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
5017
|
+
getGridChildrenFromDom() {
|
|
5018
|
+
return Array.from(this.children).filter((child) => child.tagName !== "STYLE" && child.tagName !== "SCRIPT" && !child.classList.contains("resize-handle"));
|
|
5019
|
+
}
|
|
5020
|
+
static isNestedResizableGrid(child) {
|
|
5021
|
+
return child.tagName.toLowerCase() === "docks-resizable-grid";
|
|
5022
|
+
}
|
|
5023
|
+
applyChildLayoutStyles() {
|
|
5024
|
+
this.gridChildren.forEach((child, index) => {
|
|
5025
|
+
child.style.overflow = "hidden";
|
|
5026
|
+
child.style.height = "100%";
|
|
5027
|
+
child.style.width = "100%";
|
|
5028
|
+
child.style.gridColumn = this.orientation === "horizontal" ? `${index * 2 + 1}` : "1";
|
|
5029
|
+
child.style.gridRow = this.orientation === "vertical" ? `${index * 2 + 1}` : "1";
|
|
5030
|
+
if (!_DocksResizableGrid.isNestedResizableGrid(child)) {
|
|
5031
|
+
child.style.display = "flex";
|
|
5032
|
+
child.style.flexDirection = "column";
|
|
4689
5033
|
}
|
|
5034
|
+
});
|
|
5035
|
+
}
|
|
5036
|
+
resolveGridSizes(childCount) {
|
|
5037
|
+
const parsedSizes = this.sizes?.split(",").map((s) => s.trim()).filter(Boolean) ?? [];
|
|
5038
|
+
if (parsedSizes.length === childCount) return parsedSizes;
|
|
5039
|
+
const equalSize = `${100 / childCount}%`;
|
|
5040
|
+
return Array.from({ length: childCount }, () => equalSize);
|
|
5041
|
+
}
|
|
5042
|
+
resolvePersistedSizes(persisted, childCount) {
|
|
5043
|
+
if (!persisted || typeof persisted !== "object") return null;
|
|
5044
|
+
const record = persisted;
|
|
5045
|
+
const byCount = record.sizesByCount?.[String(childCount)];
|
|
5046
|
+
if (Array.isArray(byCount) && byCount.length === childCount && byCount.every((size) => typeof size === "string")) return byCount;
|
|
5047
|
+
if (Array.isArray(record.sizes) && record.sizes.length === childCount && record.sizes.every((size) => typeof size === "string")) return record.sizes;
|
|
5048
|
+
return null;
|
|
5049
|
+
}
|
|
5050
|
+
async refreshGridLayout() {
|
|
5051
|
+
const generation = ++this.layoutGeneration;
|
|
5052
|
+
const potentialChildren = this.getGridChildrenFromDom();
|
|
5053
|
+
if (potentialChildren.length === 0) {
|
|
5054
|
+
this.gridChildren = [];
|
|
5055
|
+
this.gridSizes = [];
|
|
5056
|
+
this.childStylesApplied = false;
|
|
5057
|
+
this.requestUpdate();
|
|
5058
|
+
return;
|
|
4690
5059
|
}
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
5060
|
+
const identityChanged = potentialChildren.length !== this.gridChildren.length || potentialChildren.some((child, index) => child !== this.gridChildren[index]);
|
|
5061
|
+
this.gridChildren = potentialChildren;
|
|
5062
|
+
const persisted = await this.getDialogSetting();
|
|
5063
|
+
if (generation !== this.layoutGeneration) return;
|
|
5064
|
+
const restoredSizes = this.resolvePersistedSizes(persisted, this.gridChildren.length);
|
|
5065
|
+
if (restoredSizes) {
|
|
5066
|
+
const sizesChanged = restoredSizes.join("|") !== this.gridSizes.join("|");
|
|
5067
|
+
this.gridSizes = restoredSizes;
|
|
5068
|
+
if (identityChanged || sizesChanged) this.childStylesApplied = false;
|
|
5069
|
+
this.requestUpdate();
|
|
5070
|
+
return;
|
|
4695
5071
|
}
|
|
5072
|
+
const nextSizes = this.resolveGridSizes(this.gridChildren.length);
|
|
5073
|
+
const sizesChanged = nextSizes.join("|") !== this.gridSizes.join("|");
|
|
5074
|
+
this.gridSizes = nextSizes;
|
|
5075
|
+
if (identityChanged || sizesChanged) this.childStylesApplied = false;
|
|
4696
5076
|
this.requestUpdate();
|
|
4697
5077
|
}
|
|
5078
|
+
doInitUI() {
|
|
5079
|
+
this.scheduleRefreshGridLayout();
|
|
5080
|
+
}
|
|
4698
5081
|
async saveSizes() {
|
|
4699
5082
|
if (this.gridSizes.length === 0) return;
|
|
5083
|
+
const persisted = await this.getDialogSetting();
|
|
5084
|
+
const existingByCount = persisted && typeof persisted === "object" ? persisted.sizesByCount ?? {} : {};
|
|
4700
5085
|
await this.setDialogSetting({
|
|
4701
5086
|
sizes: this.gridSizes,
|
|
5087
|
+
sizesByCount: {
|
|
5088
|
+
...existingByCount,
|
|
5089
|
+
[String(this.gridSizes.length)]: this.gridSizes
|
|
5090
|
+
},
|
|
4702
5091
|
orientation: this.orientation
|
|
4703
5092
|
});
|
|
4704
5093
|
}
|
|
4705
5094
|
updated(changedProperties) {
|
|
4706
5095
|
super.updated(changedProperties);
|
|
4707
|
-
if (changedProperties.has("
|
|
5096
|
+
if (changedProperties.has("sizes")) this.scheduleRefreshGridLayout();
|
|
5097
|
+
if (!this.childStylesApplied && this.gridChildren.length > 0) {
|
|
4708
5098
|
this.childStylesApplied = true;
|
|
4709
5099
|
/**
|
|
4710
5100
|
* Direct style manipulation is intentionally used here.
|
|
4711
|
-
*
|
|
5101
|
+
*
|
|
4712
5102
|
* Reasoning:
|
|
4713
5103
|
* - Grid positioning (gridColumn/gridRow) must be computed dynamically based on
|
|
4714
5104
|
* the number of children and orientation at runtime
|
|
@@ -4718,16 +5108,9 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
|
|
|
4718
5108
|
* (e.g., child at index 0 → column 1, index 1 → column 3, etc.)
|
|
4719
5109
|
* - This is a layout container whose primary job is to programmatically position
|
|
4720
5110
|
* its children within a CSS grid system
|
|
5111
|
+
* - Nested resizable grids manage their own display mode and must not receive flex
|
|
4721
5112
|
*/
|
|
4722
|
-
this.
|
|
4723
|
-
child.style.overflow = "hidden";
|
|
4724
|
-
child.style.height = "100%";
|
|
4725
|
-
child.style.width = "100%";
|
|
4726
|
-
child.style.gridColumn = this.orientation === "horizontal" ? `${index * 2 + 1}` : "1";
|
|
4727
|
-
child.style.gridRow = this.orientation === "vertical" ? `${index * 2 + 1}` : "1";
|
|
4728
|
-
child.style.display = "flex";
|
|
4729
|
-
child.style.flexDirection = "column";
|
|
4730
|
-
});
|
|
5113
|
+
this.applyChildLayoutStyles();
|
|
4731
5114
|
}
|
|
4732
5115
|
}
|
|
4733
5116
|
startResize(e, handleIndex) {
|
|
@@ -4843,6 +5226,9 @@ _decorate([state()], DocksResizableGrid.prototype, "gridSizes", void 0);
|
|
|
4843
5226
|
_decorate([state()], DocksResizableGrid.prototype, "gridChildren", void 0);
|
|
4844
5227
|
DocksResizableGrid = _DocksResizableGrid = _decorate([customElement("docks-resizable-grid")], DocksResizableGrid);
|
|
4845
5228
|
//#endregion
|
|
4846
|
-
|
|
5229
|
+
//#region src/parts/index.ts
|
|
5230
|
+
installOpenDropdownNativeContextMenuGuard();
|
|
5231
|
+
//#endregion
|
|
5232
|
+
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 };
|
|
4847
5233
|
|
|
4848
|
-
//# sourceMappingURL=parts-
|
|
5234
|
+
//# sourceMappingURL=parts-CAt8aeU8.js.map
|