@eclipse-docks/core 0.7.110 → 0.7.112

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/src/parts/tabs.ts CHANGED
@@ -44,6 +44,10 @@ export class DocksTabs extends DocksContainer {
44
44
  @property({ type: Boolean, reflect: true, attribute: 'hide-tabs' })
45
45
  hideTabs: boolean = false;
46
46
 
47
+ /** Tab and nav-toolbar control sizing (`small` | `medium` | `large`). */
48
+ @property({ reflect: true, attribute: 'item-size' })
49
+ itemSize: 'small' | 'medium' | 'large' = 'medium';
50
+
47
51
  /** Tab contributions for this container */
48
52
  @state()
49
53
  private contributions: TabContribution[] = [];
@@ -158,6 +162,14 @@ export class DocksTabs extends DocksContainer {
158
162
  await this.tryCloseTab(tabName, true);
159
163
  }
160
164
 
165
+ updateTabLabel(tabName: string, label: string): void {
166
+ const contribution = this.contributions.find((c) => c.name === tabName);
167
+ if (!contribution) return;
168
+ contribution.label = label;
169
+ this.contributions = [...this.contributions];
170
+ this.requestUpdate();
171
+ }
172
+
161
173
  /**
162
174
  * Closes every tab in this group. Returns false if the user cancels a dirty-tab prompt.
163
175
  */
@@ -186,6 +198,11 @@ export class DocksTabs extends DocksContainer {
186
198
  const contribution = this.contributions.find(c => c.name === tabName);
187
199
  if (!contribution) return true;
188
200
 
201
+ if (contribution.beforeClose) {
202
+ const ok = await contribution.beforeClose();
203
+ if (!ok) return false;
204
+ }
205
+
189
206
  this.cleanupTabInstance(tabPanel);
190
207
  this.clearActiveSignalsIfPartInPanel(tabPanel);
191
208
 
@@ -367,6 +384,20 @@ export class DocksTabs extends DocksContainer {
367
384
  return this.placement === "start" || this.placement === "end" ? "vertical" : "horizontal";
368
385
  }
369
386
 
387
+ private renderNavToolbar(navToolbarId: string) {
388
+ if (!this.withToolbar || !navToolbarId) return nothing;
389
+ return html`
390
+ <div class="nav-toolbar-spacer" slot="nav" aria-hidden="true"></div>
391
+ <docks-toolbar
392
+ slot="nav"
393
+ id=${navToolbarId}
394
+ orientation=${this.withToolbarOrientation()}
395
+ align="center"
396
+ size=${this.itemSize}
397
+ ></docks-toolbar>
398
+ `;
399
+ }
400
+
370
401
  private renderEmptyState() {
371
402
  const currentApp = appLoaderService.getCurrentApp();
372
403
  return html`
@@ -389,10 +420,22 @@ export class DocksTabs extends DocksContainer {
389
420
  }
390
421
 
391
422
  render() {
392
- if (this.contributions.length === 0) {
423
+ const containerId = this.containerId ?? this.getAttribute('id');
424
+ const navToolbarId = containerId ? `${containerId}-toolbar` : '';
425
+ const hasToolbar = this.withToolbar && !!navToolbarId;
426
+
427
+ if (this.contributions.length === 0 && !hasToolbar) {
393
428
  return this.renderEmptyState();
394
429
  }
395
- const navToolbarId = this.containerId ? `${this.containerId}-toolbar` : '';
430
+
431
+ if (this.contributions.length === 0) {
432
+ return html`
433
+ <wa-tab-group ${ref(this.tabGroup)} placement=${this.placement}>
434
+ ${this.renderNavToolbar(navToolbarId)}
435
+ </wa-tab-group>
436
+ `;
437
+ }
438
+
396
439
  return html`
397
440
  <wa-tab-group ${ref(this.tabGroup)} placement=${this.placement}>
398
441
  ${repeat(
@@ -417,18 +460,7 @@ export class DocksTabs extends DocksContainer {
417
460
  `;
418
461
  }
419
462
  )}
420
- ${this.withToolbar && navToolbarId
421
- ? html`
422
- <div class="nav-toolbar-spacer" slot="nav" aria-hidden="true"></div>
423
- <docks-toolbar
424
- slot="nav"
425
- id=${navToolbarId}
426
- orientation=${this.withToolbarOrientation()}
427
- align="center"
428
- size="large"
429
- ></docks-toolbar>
430
- `
431
- : nothing}
463
+ ${this.renderNavToolbar(navToolbarId)}
432
464
  </wa-tab-group>
433
465
  `;
434
466
  }
@@ -513,6 +545,17 @@ export class DocksTabs extends DocksContainer {
513
545
 
514
546
  wa-tab::part(base) {
515
547
  padding: 3px 0.5rem;
548
+ font-size: var(--wa-font-size-s);
549
+ }
550
+
551
+ :host([item-size="small"]) wa-tab::part(base) {
552
+ padding: 2px 0.375rem;
553
+ font-size: var(--wa-font-size-xs);
554
+ }
555
+
556
+ :host([item-size="large"]) wa-tab::part(base) {
557
+ padding: var(--wa-space-s) 0.75rem;
558
+ font-size: var(--wa-font-size-m);
516
559
  }
517
560
 
518
561
  :host([icon-only]) wa-tab::part(base) {
@@ -523,15 +566,39 @@ export class DocksTabs extends DocksContainer {
523
566
  padding: var(--wa-space-s);
524
567
  }
525
568
 
569
+ :host([icon-only][item-size="small"]:is([placement="top"], [placement="bottom"])) wa-tab::part(base) {
570
+ padding: var(--wa-space-xs);
571
+ }
572
+
573
+ :host([icon-only][item-size="large"]:is([placement="top"], [placement="bottom"])) wa-tab::part(base) {
574
+ padding: var(--wa-space-m);
575
+ }
576
+
526
577
  :host([icon-only]:is([placement="start"], [placement="end"])) wa-tab::part(base) {
527
578
  padding-inline: 0;
528
579
  padding-block: var(--wa-space-s);
529
580
  }
530
581
 
582
+ :host([icon-only][item-size="small"]:is([placement="start"], [placement="end"])) wa-tab::part(base) {
583
+ padding-block: var(--wa-space-xs);
584
+ }
585
+
586
+ :host([icon-only][item-size="large"]:is([placement="start"], [placement="end"])) wa-tab::part(base) {
587
+ padding-block: var(--wa-space-m);
588
+ }
589
+
531
590
  :host([icon-only]) wa-tab wa-icon {
532
591
  font-size: var(--wa-font-size-l);
533
592
  }
534
593
 
594
+ :host([icon-only][item-size="small"]) wa-tab wa-icon {
595
+ font-size: var(--wa-font-size-m);
596
+ }
597
+
598
+ :host([icon-only][item-size="large"]) wa-tab wa-icon {
599
+ font-size: var(--wa-font-size-xl);
600
+ }
601
+
535
602
  :host([icon-only]:is([placement="start"], [placement="end"])) wa-tab-group::part(nav),
536
603
  :host([icon-only]:is([placement="start"], [placement="end"])) wa-tab-group::part(tabs) {
537
604
  padding: 0;
@@ -18,10 +18,10 @@ interface PackageJson {
18
18
  devDependencies?: Record<string, string>;
19
19
  }
20
20
 
21
- function findPackageVersion(appRoot: string, depName: string): string | null {
22
- const segments = depName.startsWith('@')
23
- ? depName.split('/')
24
- : [depName];
21
+ function packageJsonPath(appRoot: string, packageName: string): string | null {
22
+ const segments = packageName.startsWith('@')
23
+ ? packageName.split('/')
24
+ : [packageName];
25
25
  const relativePath = path.join('node_modules', ...segments, 'package.json');
26
26
  let dir = path.resolve(appRoot);
27
27
  const root = path.parse(dir).root;
@@ -29,13 +29,7 @@ function findPackageVersion(appRoot: string, depName: string): string | null {
29
29
  while (true) {
30
30
  const pkgPath = path.join(dir, relativePath);
31
31
  if (existsSync(pkgPath)) {
32
- try {
33
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as PackageJson;
34
- if (typeof pkg.version === 'string') return pkg.version;
35
- } catch {
36
- // ignore parse errors
37
- }
38
- return null;
32
+ return pkgPath;
39
33
  }
40
34
  if (dir === root) break;
41
35
  dir = path.dirname(dir);
@@ -43,6 +37,22 @@ function findPackageVersion(appRoot: string, depName: string): string | null {
43
37
  return null;
44
38
  }
45
39
 
40
+ function readPackageJson(appRoot: string, packageName: string): PackageJson | null {
41
+ const pkgPath = packageJsonPath(appRoot, packageName);
42
+ if (!pkgPath) return null;
43
+ try {
44
+ return JSON.parse(readFileSync(pkgPath, 'utf8')) as PackageJson;
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+
50
+ function findPackageVersion(appRoot: string, depName: string): string | null {
51
+ const pkg = readPackageJson(appRoot, depName);
52
+ if (typeof pkg?.version === 'string') return pkg.version;
53
+ return null;
54
+ }
55
+
46
56
  function resolveDepVersionsFromPkg(
47
57
  appRoot: string,
48
58
  pkg: PackageJson,
@@ -176,6 +186,51 @@ export function listExtensionSideEffectPackages(
176
186
  return [...first, ...rest];
177
187
  }
178
188
 
189
+ /**
190
+ * Walks extension package.json `dependencies` to collect transitive extension-* packages
191
+ * (e.g. extension-utils → extension-python-runtime → extension-terminal).
192
+ */
193
+ export function collectTransitiveExtensionPackages(
194
+ appRoot: string,
195
+ seeds: string[],
196
+ sideEffects: ExtensionSideEffectsListOptions,
197
+ ): string[] {
198
+ const found = new Set<string>();
199
+ const queue = [...seeds];
200
+ const visited = new Set<string>();
201
+
202
+ while (queue.length > 0) {
203
+ const name = queue.shift()!;
204
+ if (visited.has(name)) continue;
205
+ visited.add(name);
206
+
207
+ const pkg = readPackageJson(appRoot, name);
208
+ if (!pkg?.dependencies) continue;
209
+
210
+ for (const dep of Object.keys(pkg.dependencies)) {
211
+ if (!sideEffects.pattern.test(dep) || sideEffects.exclude.has(dep)) continue;
212
+ found.add(dep);
213
+ queue.push(dep);
214
+ }
215
+ }
216
+
217
+ return [...found];
218
+ }
219
+
220
+ export function resolveExtensionSideEffectPackages(
221
+ appRoot: string,
222
+ dependencies: Record<string, string>,
223
+ sideEffects: ExtensionSideEffectsListOptions,
224
+ ): string[] {
225
+ const direct = listExtensionSideEffectPackages(dependencies, sideEffects);
226
+ const transitive = collectTransitiveExtensionPackages(appRoot, direct, sideEffects);
227
+ const allNames = [...new Set([...direct, ...transitive])];
228
+ return listExtensionSideEffectPackages(
229
+ Object.fromEntries(allNames.map((name) => [name, '*'])),
230
+ sideEffects,
231
+ );
232
+ }
233
+
179
234
  export function resolveDepVersionsPlugin(
180
235
  options?: ResolveDepVersionsPluginOptions,
181
236
  ): Plugin {
@@ -211,7 +266,8 @@ export function resolveDepVersionsPlugin(
211
266
  return;
212
267
  }
213
268
  const info = resolvePackageInfo(appRoot, options);
214
- extensionImportPackages = listExtensionSideEffectPackages(
269
+ extensionImportPackages = resolveExtensionSideEffectPackages(
270
+ appRoot,
215
271
  info?.dependencies ?? {},
216
272
  normalized,
217
273
  );