@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
package/src/parts/contextmenu.ts
CHANGED
|
@@ -2,20 +2,24 @@ import {css, html, nothing} from 'lit'
|
|
|
2
2
|
import {customElement, property, state} from 'lit/decorators.js'
|
|
3
3
|
import {DocksElement} from "./element";
|
|
4
4
|
import {
|
|
5
|
-
CommandContribution,
|
|
6
5
|
Contribution,
|
|
7
6
|
ContributionChangeEvent,
|
|
8
7
|
contributionRegistry,
|
|
9
|
-
getContributionDisabled,
|
|
10
|
-
HTMLContribution,
|
|
11
|
-
getContributionVisible,
|
|
12
8
|
TOPIC_CONTRIBUTEIONS_CHANGED
|
|
13
9
|
} from "../core/contributionregistry";
|
|
14
|
-
import {unsafeHTML} from "lit/directives/unsafe-html.js";
|
|
15
10
|
import {subscribe} from "../core/events";
|
|
16
11
|
import {closeSiblingSubmenus} from "../core/dropdown-menu-utils";
|
|
17
12
|
import {createRef, ref} from "lit/directives/ref.js";
|
|
18
|
-
import
|
|
13
|
+
import {renderDropdownContribution, handleDropdownWaSelect} from "../core/dropdown-item";
|
|
14
|
+
|
|
15
|
+
interface VirtualPopupAnchor {
|
|
16
|
+
getBoundingClientRect(): DOMRect;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface WaPopupElement extends HTMLElement {
|
|
20
|
+
anchor?: Element | string | VirtualPopupAnchor;
|
|
21
|
+
reposition(): void;
|
|
22
|
+
}
|
|
19
23
|
|
|
20
24
|
@customElement('docks-contextmenu')
|
|
21
25
|
export class DocksContextMenu extends DocksElement {
|
|
@@ -31,10 +35,15 @@ export class DocksContextMenu extends DocksElement {
|
|
|
31
35
|
@state()
|
|
32
36
|
private isOpen: boolean = false;
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
private menuPosition: { x: number; y: number } = { x: 0, y: 0 };
|
|
39
|
+
|
|
40
|
+
private readonly virtualAnchor: VirtualPopupAnchor = {
|
|
41
|
+
getBoundingClientRect: () => {
|
|
42
|
+
const { x, y } = this.menuPosition;
|
|
43
|
+
return new DOMRect(x, y, 0, 0);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
36
46
|
|
|
37
|
-
private anchorRef = createRef<HTMLElement>();
|
|
38
47
|
private dropdownRef = createRef<HTMLElement>();
|
|
39
48
|
|
|
40
49
|
private boundHandleDocumentPointerDown = this.handleDocumentPointerDown.bind(this);
|
|
@@ -225,43 +234,38 @@ export class DocksContextMenu extends DocksElement {
|
|
|
225
234
|
await this.updateComplete;
|
|
226
235
|
}
|
|
227
236
|
|
|
228
|
-
this.
|
|
237
|
+
this.menuPosition = position;
|
|
229
238
|
this.isOpen = true;
|
|
230
239
|
await this.updateComplete;
|
|
240
|
+
this.syncVirtualPopupAnchor();
|
|
231
241
|
document.addEventListener('pointerdown', this.boundHandleDocumentPointerDown, { capture: true });
|
|
232
242
|
return true;
|
|
233
243
|
}
|
|
234
244
|
|
|
245
|
+
/** Points wa-dropdown's internal wa-popup at the pointer via a VirtualElement anchor. */
|
|
246
|
+
private syncVirtualPopupAnchor(): void {
|
|
247
|
+
const dropdown = this.dropdownRef.value;
|
|
248
|
+
const popup = dropdown?.shadowRoot?.querySelector('wa-popup') as WaPopupElement | null;
|
|
249
|
+
if (!popup) return;
|
|
250
|
+
popup.anchor = this.virtualAnchor;
|
|
251
|
+
popup.reposition();
|
|
252
|
+
}
|
|
253
|
+
|
|
235
254
|
private onClose() {
|
|
236
255
|
if (!this.isOpen) return;
|
|
237
256
|
this.isOpen = false;
|
|
238
257
|
document.removeEventListener('pointerdown', this.boundHandleDocumentPointerDown, { capture: true });
|
|
239
258
|
}
|
|
240
259
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return nothing;
|
|
246
|
-
}
|
|
247
|
-
const disabled = getContributionDisabled(commandContribution);
|
|
248
|
-
return html`
|
|
249
|
-
<docks-command
|
|
250
|
-
cmd="${commandContribution.command}"
|
|
251
|
-
icon="${commandContribution.icon ?? ''}"
|
|
252
|
-
.params=${commandContribution.params ?? {}}
|
|
253
|
-
?disabled="${disabled}">
|
|
254
|
-
${commandContribution.label}
|
|
255
|
-
</docks-command>
|
|
256
|
-
`;
|
|
257
|
-
} else if ("component" in contribution) {
|
|
258
|
-
const contents = (contribution as HTMLContribution).component;
|
|
259
|
-
if (contents instanceof Function) {
|
|
260
|
-
return contents();
|
|
261
|
-
}
|
|
262
|
-
return unsafeHTML(contents);
|
|
260
|
+
protected updated(changedProperties: Map<string, unknown>): void {
|
|
261
|
+
super.updated(changedProperties);
|
|
262
|
+
if (changedProperties.has('isOpen') && this.isOpen) {
|
|
263
|
+
this.syncVirtualPopupAnchor();
|
|
263
264
|
}
|
|
264
|
-
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private renderContribution(contribution: Contribution) {
|
|
268
|
+
return renderDropdownContribution(contribution);
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
render() {
|
|
@@ -272,18 +276,9 @@ export class DocksContextMenu extends DocksElement {
|
|
|
272
276
|
${ref(this.dropdownRef)}
|
|
273
277
|
?open=${this.isOpen}
|
|
274
278
|
@submenu-opening=${this.handleSubmenuOpening}
|
|
279
|
+
@wa-select=${handleDropdownWaSelect}
|
|
275
280
|
@wa-after-hide=${this.onClose}>
|
|
276
|
-
|
|
277
|
-
<div
|
|
278
|
-
slot="trigger"
|
|
279
|
-
${ref(this.anchorRef)}
|
|
280
|
-
style="position: fixed;
|
|
281
|
-
left: ${this.position.x}px;
|
|
282
|
-
top: ${this.position.y}px;
|
|
283
|
-
width: 1px;
|
|
284
|
-
height: 1px;
|
|
285
|
-
pointer-events: none;">
|
|
286
|
-
</div>
|
|
281
|
+
<span slot="trigger" hidden aria-hidden="true"></span>
|
|
287
282
|
|
|
288
283
|
${partContent}
|
|
289
284
|
${this.contributions.map(c => this.renderContribution(c))}
|
package/src/parts/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import "../externals/webawesome"
|
|
2
|
+
import { installOpenDropdownNativeContextMenuGuard } from "../core/dropdown-menu-utils";
|
|
2
3
|
import "./toolbar"
|
|
3
4
|
import "./contextmenu"
|
|
4
5
|
import "./tabs"
|
|
5
|
-
import "./resizable-grid"
|
|
6
|
+
import "./resizable-grid"
|
|
7
|
+
|
|
8
|
+
installOpenDropdownNativeContextMenuGuard();
|
package/src/parts/part.ts
CHANGED
|
@@ -21,6 +21,10 @@ export abstract class DocksPart extends DocksContainer {
|
|
|
21
21
|
@property({ type: Boolean, attribute: false })
|
|
22
22
|
public isEditor: boolean = false;
|
|
23
23
|
|
|
24
|
+
/** Compact layout for dialog/tab embedding (no fill-height shell or nested scroll). */
|
|
25
|
+
@property({ type: Boolean, reflect: true })
|
|
26
|
+
embedded = false;
|
|
27
|
+
|
|
24
28
|
protected commandStack?: CommandStack;
|
|
25
29
|
|
|
26
30
|
public getCommandStack(): CommandStack | undefined {
|
|
@@ -135,11 +139,13 @@ export abstract class DocksPart extends DocksContainer {
|
|
|
135
139
|
return nothing;
|
|
136
140
|
}
|
|
137
141
|
|
|
142
|
+
/** Part-level toolbar contributions (`toolbar:${partId}`). */
|
|
138
143
|
private getToolbarTarget(): string | undefined {
|
|
139
144
|
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
140
145
|
return contributionKey ? `toolbar:${contributionKey}` : undefined;
|
|
141
146
|
}
|
|
142
147
|
|
|
148
|
+
/** Part-level context-menu contributions (`contextmenu:${partId}`). */
|
|
143
149
|
private getContextMenuTarget(): string | undefined {
|
|
144
150
|
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
145
151
|
return contributionKey ? `contextmenu:${contributionKey}` : undefined;
|
|
@@ -292,6 +298,26 @@ export abstract class DocksPart extends DocksContainer {
|
|
|
292
298
|
min-height: 100%;
|
|
293
299
|
}
|
|
294
300
|
|
|
301
|
+
:host([embedded]) {
|
|
302
|
+
height: auto;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
:host([embedded]) .part-shell {
|
|
306
|
+
height: auto;
|
|
307
|
+
overflow: visible;
|
|
308
|
+
grid-template-rows: auto;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
:host([embedded]) .part-content {
|
|
312
|
+
overflow: visible;
|
|
313
|
+
min-height: 0;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
:host([embedded]) .part-content-inner {
|
|
317
|
+
height: auto;
|
|
318
|
+
min-height: 0;
|
|
319
|
+
}
|
|
320
|
+
|
|
295
321
|
.part-toolbar {
|
|
296
322
|
min-height: 0;
|
|
297
323
|
}
|
|
@@ -46,10 +46,10 @@ export class DocksResizableGrid extends DocksElement {
|
|
|
46
46
|
} | null = null;
|
|
47
47
|
|
|
48
48
|
private resizeOverlay: HTMLDivElement | null = null;
|
|
49
|
-
private childrenLoaded = false;
|
|
50
49
|
private childStylesApplied = false;
|
|
51
50
|
private mutationObserver?: MutationObserver;
|
|
52
|
-
private
|
|
51
|
+
private refreshScheduled = false;
|
|
52
|
+
private layoutGeneration = 0;
|
|
53
53
|
|
|
54
54
|
createRenderRoot() {
|
|
55
55
|
// intentionally disabling shadow DOM for the resizable grid
|
|
@@ -59,87 +59,162 @@ export class DocksResizableGrid extends DocksElement {
|
|
|
59
59
|
// ============= Lifecycle Methods =============
|
|
60
60
|
|
|
61
61
|
protected doBeforeUI() {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Also try to load immediately
|
|
74
|
-
this.loadChildren();
|
|
62
|
+
this.mutationObserver = new MutationObserver(() => {
|
|
63
|
+
this.scheduleRefreshGridLayout();
|
|
64
|
+
});
|
|
65
|
+
this.mutationObserver.observe(this, { childList: true, subtree: false });
|
|
66
|
+
this.scheduleRefreshGridLayout();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private scheduleRefreshGridLayout() {
|
|
70
|
+
if (this.refreshScheduled) {
|
|
71
|
+
return;
|
|
75
72
|
}
|
|
73
|
+
this.refreshScheduled = true;
|
|
74
|
+
queueMicrotask(() => {
|
|
75
|
+
this.refreshScheduled = false;
|
|
76
|
+
void this.refreshGridLayout();
|
|
77
|
+
});
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
private
|
|
79
|
-
|
|
80
|
-
child =>
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
private getGridChildrenFromDom(): HTMLElement[] {
|
|
81
|
+
return Array.from(this.children).filter(
|
|
82
|
+
(child) =>
|
|
83
|
+
child.tagName !== 'STYLE' &&
|
|
84
|
+
child.tagName !== 'SCRIPT' &&
|
|
85
|
+
!child.classList.contains('resize-handle'),
|
|
83
86
|
) as HTMLElement[];
|
|
87
|
+
}
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
private static isNestedResizableGrid(child: HTMLElement): boolean {
|
|
90
|
+
return child.tagName.toLowerCase() === 'docks-resizable-grid';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private applyChildLayoutStyles(): void {
|
|
94
|
+
this.gridChildren.forEach((child, index) => {
|
|
95
|
+
child.style.overflow = 'hidden';
|
|
96
|
+
child.style.height = '100%';
|
|
97
|
+
child.style.width = '100%';
|
|
98
|
+
child.style.gridColumn = this.orientation === 'horizontal' ? `${index * 2 + 1}` : '1';
|
|
99
|
+
child.style.gridRow = this.orientation === 'vertical' ? `${index * 2 + 1}` : '1';
|
|
100
|
+
if (!DocksResizableGrid.isNestedResizableGrid(child)) {
|
|
101
|
+
child.style.display = 'flex';
|
|
102
|
+
child.style.flexDirection = 'column';
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private resolveGridSizes(childCount: number): string[] {
|
|
108
|
+
const parsedSizes = this.sizes?.split(',').map((s) => s.trim()).filter(Boolean) ?? [];
|
|
109
|
+
if (parsedSizes.length === childCount) {
|
|
110
|
+
return parsedSizes;
|
|
111
|
+
}
|
|
112
|
+
const equalSize = `${100 / childCount}%`;
|
|
113
|
+
return Array.from({ length: childCount }, () => equalSize);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private resolvePersistedSizes(persisted: unknown, childCount: number): string[] | null {
|
|
117
|
+
if (!persisted || typeof persisted !== 'object') {
|
|
118
|
+
return null;
|
|
87
119
|
}
|
|
88
120
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
121
|
+
const record = persisted as {
|
|
122
|
+
sizes?: unknown;
|
|
123
|
+
sizesByCount?: Record<string, unknown>;
|
|
124
|
+
};
|
|
125
|
+
const byCount = record.sizesByCount?.[String(childCount)];
|
|
126
|
+
if (Array.isArray(byCount) && byCount.length === childCount && byCount.every((size) => typeof size === 'string')) {
|
|
127
|
+
return byCount;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (Array.isArray(record.sizes) && record.sizes.length === childCount && record.sizes.every((size) => typeof size === 'string')) {
|
|
131
|
+
return record.sizes;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private async refreshGridLayout() {
|
|
138
|
+
const generation = ++this.layoutGeneration;
|
|
139
|
+
const potentialChildren = this.getGridChildrenFromDom();
|
|
140
|
+
if (potentialChildren.length === 0) {
|
|
141
|
+
this.gridChildren = [];
|
|
142
|
+
this.gridSizes = [];
|
|
143
|
+
this.childStylesApplied = false;
|
|
144
|
+
this.requestUpdate();
|
|
145
|
+
return;
|
|
94
146
|
}
|
|
95
147
|
|
|
96
|
-
|
|
148
|
+
const countChanged = potentialChildren.length !== this.gridChildren.length;
|
|
149
|
+
const identityChanged = countChanged
|
|
150
|
+
|| potentialChildren.some((child, index) => child !== this.gridChildren[index]);
|
|
97
151
|
this.gridChildren = potentialChildren;
|
|
98
152
|
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
const persisted = await this.getDialogSetting();
|
|
103
|
-
if (persisted && Array.isArray(persisted.sizes) && persisted.sizes.length === this.gridChildren.length) {
|
|
104
|
-
this.gridSizes = persisted.sizes;
|
|
105
|
-
this.requestUpdate();
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
153
|
+
const persisted = await this.getDialogSetting();
|
|
154
|
+
if (generation !== this.layoutGeneration) {
|
|
155
|
+
return;
|
|
108
156
|
}
|
|
109
157
|
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
158
|
+
const restoredSizes = this.resolvePersistedSizes(persisted, this.gridChildren.length);
|
|
159
|
+
if (restoredSizes) {
|
|
160
|
+
const sizesChanged = restoredSizes.join('|') !== this.gridSizes.join('|');
|
|
161
|
+
this.gridSizes = restoredSizes;
|
|
162
|
+
if (identityChanged || sizesChanged) {
|
|
163
|
+
this.childStylesApplied = false;
|
|
164
|
+
}
|
|
165
|
+
this.requestUpdate();
|
|
166
|
+
return;
|
|
116
167
|
}
|
|
117
168
|
|
|
169
|
+
const nextSizes = this.resolveGridSizes(this.gridChildren.length);
|
|
170
|
+
const sizesChanged = nextSizes.join('|') !== this.gridSizes.join('|');
|
|
171
|
+
this.gridSizes = nextSizes;
|
|
172
|
+
|
|
173
|
+
if (identityChanged || sizesChanged) {
|
|
174
|
+
this.childStylesApplied = false;
|
|
175
|
+
}
|
|
118
176
|
this.requestUpdate();
|
|
119
177
|
}
|
|
120
178
|
|
|
179
|
+
protected doInitUI() {
|
|
180
|
+
this.scheduleRefreshGridLayout();
|
|
181
|
+
}
|
|
182
|
+
|
|
121
183
|
private async saveSizes() {
|
|
122
184
|
if (this.gridSizes.length === 0) {
|
|
123
185
|
return;
|
|
124
186
|
}
|
|
125
187
|
|
|
188
|
+
const persisted = await this.getDialogSetting();
|
|
189
|
+
const existingByCount = persisted && typeof persisted === 'object'
|
|
190
|
+
? (persisted as { sizesByCount?: Record<string, string[]> }).sizesByCount ?? {}
|
|
191
|
+
: {};
|
|
192
|
+
|
|
126
193
|
await this.setDialogSetting({
|
|
127
194
|
sizes: this.gridSizes,
|
|
128
|
-
|
|
195
|
+
sizesByCount: {
|
|
196
|
+
...existingByCount,
|
|
197
|
+
[String(this.gridSizes.length)]: this.gridSizes,
|
|
198
|
+
},
|
|
199
|
+
orientation: this.orientation,
|
|
129
200
|
});
|
|
130
201
|
}
|
|
131
202
|
|
|
132
203
|
updated(changedProperties: Map<string, any>) {
|
|
133
204
|
super.updated(changedProperties);
|
|
134
|
-
|
|
205
|
+
|
|
206
|
+
if (changedProperties.has('sizes')) {
|
|
207
|
+
this.scheduleRefreshGridLayout();
|
|
208
|
+
}
|
|
209
|
+
|
|
135
210
|
// Only apply child styles once when children are first loaded
|
|
136
211
|
// This prevents interfering with nested resizable grids during resize operations
|
|
137
|
-
if (
|
|
212
|
+
if (!this.childStylesApplied && this.gridChildren.length > 0) {
|
|
138
213
|
this.childStylesApplied = true;
|
|
139
|
-
|
|
214
|
+
|
|
140
215
|
/**
|
|
141
216
|
* Direct style manipulation is intentionally used here.
|
|
142
|
-
*
|
|
217
|
+
*
|
|
143
218
|
* Reasoning:
|
|
144
219
|
* - Grid positioning (gridColumn/gridRow) must be computed dynamically based on
|
|
145
220
|
* the number of children and orientation at runtime
|
|
@@ -149,16 +224,9 @@ export class DocksResizableGrid extends DocksElement {
|
|
|
149
224
|
* (e.g., child at index 0 → column 1, index 1 → column 3, etc.)
|
|
150
225
|
* - This is a layout container whose primary job is to programmatically position
|
|
151
226
|
* its children within a CSS grid system
|
|
227
|
+
* - Nested resizable grids manage their own display mode and must not receive flex
|
|
152
228
|
*/
|
|
153
|
-
this.
|
|
154
|
-
child.style.overflow = 'hidden';
|
|
155
|
-
child.style.height = '100%';
|
|
156
|
-
child.style.width = '100%';
|
|
157
|
-
child.style.gridColumn = this.orientation === 'horizontal' ? `${index * 2 + 1}` : '1';
|
|
158
|
-
child.style.gridRow = this.orientation === 'vertical' ? `${index * 2 + 1}` : '1';
|
|
159
|
-
child.style.display = 'flex';
|
|
160
|
-
child.style.flexDirection = 'column';
|
|
161
|
-
});
|
|
229
|
+
this.applyChildLayoutStyles();
|
|
162
230
|
}
|
|
163
231
|
}
|
|
164
232
|
|
package/src/parts/tabs.ts
CHANGED
|
@@ -45,6 +45,14 @@ export class DocksTabs extends DocksContainer {
|
|
|
45
45
|
@property({ type: Boolean, reflect: true, attribute: 'hide-tabs' })
|
|
46
46
|
hideTabs: boolean = false;
|
|
47
47
|
|
|
48
|
+
/** Size to tab content instead of filling the parent height (e.g. About dialog). */
|
|
49
|
+
@property({ type: Boolean, reflect: true, attribute: 'fit-content' })
|
|
50
|
+
fitContent: boolean = false;
|
|
51
|
+
|
|
52
|
+
/** Fill a fixed-height parent; tab body scrolls instead of resizing the container. */
|
|
53
|
+
@property({ type: Boolean, reflect: true, attribute: 'fill-height' })
|
|
54
|
+
fillHeight: boolean = false;
|
|
55
|
+
|
|
48
56
|
/** Tab and nav-toolbar control sizing (`s` | `m` | `l`). */
|
|
49
57
|
@property({ reflect: true, attribute: 'item-size' })
|
|
50
58
|
itemSize: 's' | 'm' | 'l' = 'm';
|
|
@@ -129,6 +137,12 @@ export class DocksTabs extends DocksContainer {
|
|
|
129
137
|
return this.tabGroup.value.getAttribute("active");
|
|
130
138
|
}
|
|
131
139
|
|
|
140
|
+
public getTabPart(tabName: string): DocksPart | null {
|
|
141
|
+
const tabPanel = this.getTabPanel(tabName);
|
|
142
|
+
if (!tabPanel) return null;
|
|
143
|
+
return this.getPartFromPanel(tabPanel);
|
|
144
|
+
}
|
|
145
|
+
|
|
132
146
|
open(contribution: TabContribution): void {
|
|
133
147
|
const existing = this.contributions.find(c => c.name === contribution.name);
|
|
134
148
|
if (existing) {
|
|
@@ -472,6 +486,95 @@ export class DocksTabs extends DocksContainer {
|
|
|
472
486
|
width: 100%;
|
|
473
487
|
}
|
|
474
488
|
|
|
489
|
+
:host([fit-content]) {
|
|
490
|
+
display: flex;
|
|
491
|
+
flex-direction: column;
|
|
492
|
+
height: auto;
|
|
493
|
+
max-height: 100%;
|
|
494
|
+
min-height: 0;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
:host([fit-content]) wa-tab-group {
|
|
498
|
+
display: flex;
|
|
499
|
+
flex-direction: column;
|
|
500
|
+
flex: 1 1 auto;
|
|
501
|
+
min-height: 0;
|
|
502
|
+
height: auto;
|
|
503
|
+
max-height: 100%;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
:host([fit-content]) wa-tab-group::part(base) {
|
|
507
|
+
display: flex;
|
|
508
|
+
flex-direction: column;
|
|
509
|
+
flex: 1 1 auto;
|
|
510
|
+
min-height: 0;
|
|
511
|
+
max-height: 100%;
|
|
512
|
+
height: auto;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
:host([fit-content]) wa-tab-group::part(body) {
|
|
516
|
+
flex: 1 1 auto;
|
|
517
|
+
min-height: 0;
|
|
518
|
+
height: auto;
|
|
519
|
+
overflow-x: hidden;
|
|
520
|
+
overflow-y: auto;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
:host([fit-content]) wa-tab-panel[active] {
|
|
524
|
+
display: block;
|
|
525
|
+
height: auto;
|
|
526
|
+
overflow: visible;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
:host([fit-content]) wa-tab-panel > * {
|
|
530
|
+
height: auto;
|
|
531
|
+
min-height: 0;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
:host([fill-height]) {
|
|
535
|
+
display: flex;
|
|
536
|
+
flex-direction: column;
|
|
537
|
+
height: 100%;
|
|
538
|
+
min-height: 0;
|
|
539
|
+
max-height: 100%;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
:host([fill-height]) wa-tab-group {
|
|
543
|
+
display: flex;
|
|
544
|
+
flex-direction: column;
|
|
545
|
+
flex: 1 1 auto;
|
|
546
|
+
min-height: 0;
|
|
547
|
+
height: 100%;
|
|
548
|
+
max-height: 100%;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
:host([fill-height]) wa-tab-group::part(base) {
|
|
552
|
+
display: flex;
|
|
553
|
+
flex-direction: column;
|
|
554
|
+
flex: 1 1 auto;
|
|
555
|
+
min-height: 0;
|
|
556
|
+
max-height: 100%;
|
|
557
|
+
height: 100%;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
:host([fill-height]) wa-tab-group::part(body) {
|
|
561
|
+
flex: 1 1 auto;
|
|
562
|
+
min-height: 0;
|
|
563
|
+
overflow-x: hidden;
|
|
564
|
+
overflow-y: auto;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
:host([fill-height]) wa-tab-panel[active] {
|
|
568
|
+
display: block;
|
|
569
|
+
height: auto;
|
|
570
|
+
overflow: visible;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
:host([fill-height]) wa-tab-panel > * {
|
|
574
|
+
height: auto;
|
|
575
|
+
min-height: 0;
|
|
576
|
+
}
|
|
577
|
+
|
|
475
578
|
wa-tab-group {
|
|
476
579
|
height: 100%;
|
|
477
580
|
width: 100%;
|