@eclipse-lyra/core 0.7.8 → 0.7.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eclipse-lyra/core",
3
- "version": "0.7.8",
3
+ "version": "0.7.10",
4
4
  "description": "Eclipse Lyra platform core: registries, services, parts, widgets, and API",
5
5
  "type": "module",
6
6
  "license": "EPL-2.0",
package/src/api/index.ts CHANGED
@@ -27,5 +27,5 @@ export * from './constants';
27
27
  export * from './types';
28
28
 
29
29
  // Re-export AppDefinition for convenience
30
- export type { AppDefinition, AppContributions, ReleaseEntry, ReleaseHistory, RenderDescriptor } from '../core/apploader';
30
+ export type { AppDefinition, AppContributions, LayoutDescriptor, ReleaseEntry, ReleaseHistory, RenderDescriptor } from '../core/apploader';
31
31
 
package/src/api/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // Re-export framework types for app usage
2
- export type { AppDefinition, AppContributions, ReleaseEntry, ReleaseHistory, RenderDescriptor } from '../core/apploader';
2
+ export type { AppDefinition, AppContributions, LayoutDescriptor, ReleaseEntry, ReleaseHistory, RenderDescriptor } from '../core/apploader';
3
3
  export type {
4
4
  Command,
5
5
  Parameter,
@@ -61,6 +61,9 @@ export class LyraLayoutSwitcher extends LyraElement {
61
61
  value="${layout.id}"
62
62
  type="checkbox"
63
63
  ?checked=${layout.id === this.currentLayoutId}>
64
+ ${layout.icon
65
+ ? html`<wa-icon slot="icon" name="${layout.icon}" label="${layout.name}"></wa-icon>`
66
+ : ''}
64
67
  ${layout.name}
65
68
  </wa-dropdown-item>
66
69
  `
@@ -2,9 +2,40 @@ import "../layouts/standard-layout";
2
2
  import { contributionRegistry } from "../core/contributionregistry";
3
3
  import { SYSTEM_LAYOUTS } from "../core/constants";
4
4
 
5
- contributionRegistry.registerContribution(SYSTEM_LAYOUTS, {
6
- id: "standard",
7
- name: "Standard",
8
- label: "Standard",
9
- component: "lyra-standard-layout",
10
- });
5
+ const standardLayouts: Array<{
6
+ id: string;
7
+ name: string;
8
+ label: string;
9
+ icon?: string;
10
+ component: string | { tag: string; attributes?: Record<string, string> };
11
+ }> = [
12
+ { id: "standard", name: "Standard", label: "Standard", icon: "layout", component: "lyra-standard-layout" },
13
+ {
14
+ id: "standard-bottom-panel",
15
+ name: "Standard (bottom panel)",
16
+ label: "Standard (bottom panel)",
17
+ icon: "window-maximize",
18
+ component: { tag: "lyra-standard-layout", attributes: { "show-bottom-panel": "true" } },
19
+ },
20
+ {
21
+ id: "standard-bottom-sidebar",
22
+ name: "Standard (bottom sidebar)",
23
+ label: "Standard (bottom sidebar)",
24
+ icon: "columns",
25
+ component: { tag: "lyra-standard-layout", attributes: { "show-bottom-sidebar": "true" } },
26
+ },
27
+ {
28
+ id: "standard-full",
29
+ name: "Standard (panel + sidebar)",
30
+ label: "Standard (panel + sidebar)",
31
+ icon: "th-large",
32
+ component: {
33
+ tag: "lyra-standard-layout",
34
+ attributes: { "show-bottom-panel": "true", "show-bottom-sidebar": "true" },
35
+ },
36
+ },
37
+ ];
38
+
39
+ for (const layout of standardLayouts) {
40
+ contributionRegistry.registerContribution(SYSTEM_LAYOUTS, layout);
41
+ }
@@ -24,6 +24,23 @@ import { marketplaceRegistry } from "./marketplaceregistry";
24
24
 
25
25
  const logger = createLogger('AppLoader');
26
26
 
27
+ /** Layout reference: layout id string, or id + props to parameterize the layout (e.g. show-bottom-panel). */
28
+ export type LayoutDescriptor = string | { id: string; props?: Record<string, string | boolean> };
29
+
30
+ function getLayoutIdFromApp(app: AppDefinition | undefined): string {
31
+ if (!app) return 'standard';
32
+ const l = app.layout ?? app.layoutId;
33
+ return typeof l === 'object' ? l.id : (l ?? 'standard');
34
+ }
35
+
36
+ function propsToAttributes(props: Record<string, string | boolean>): Record<string, string> {
37
+ const out: Record<string, string> = {};
38
+ for (const [k, v] of Object.entries(props)) {
39
+ out[k] = typeof v === 'boolean' ? (v ? 'true' : 'false') : v;
40
+ }
41
+ return out;
42
+ }
43
+
27
44
  /**
28
45
  * Extracts error message from an error object.
29
46
  */
@@ -172,9 +189,13 @@ export interface AppDefinition {
172
189
  releaseHistory?: ReleaseHistory | (() => ReleaseHistory | Promise<ReleaseHistory>);
173
190
 
174
191
  /**
175
- * Id of a layout registered to the system.layouts contribution slot.
176
- * The app root is always the chosen layout's component. Defaults to 'standard' when omitted.
192
+ * Layout: id (string) or { id, props } to parameterize the layout.
193
+ * App root is the chosen layout's component. Props are merged as attributes when rendering (e.g. show-bottom-panel).
194
+ * Defaults to 'standard' when omitted.
177
195
  */
196
+ layout?: LayoutDescriptor;
197
+
198
+ /** @deprecated Use layout (string or { id, props }) instead. */
178
199
  layoutId?: string;
179
200
 
180
201
  /**
@@ -515,7 +536,7 @@ class AppLoaderService {
515
536
  throw new Error('No app loaded. Call loadApp() first.');
516
537
  }
517
538
 
518
- const layoutId = this.preferredLayoutId ?? this.currentApp.layoutId ?? 'standard';
539
+ const layoutId = this.preferredLayoutId ?? getLayoutIdFromApp(this.currentApp);
519
540
  const layouts = contributionRegistry.getContributions<LayoutContribution>(SYSTEM_LAYOUTS);
520
541
  let layout = layouts.find((c) => c.id === layoutId);
521
542
  if (!layout) {
@@ -527,12 +548,25 @@ class AppLoaderService {
527
548
  }
528
549
 
529
550
  const r = layout.component;
551
+ let effectiveAttributes: Record<string, string> = {};
552
+ if (r && typeof r === 'object' && 'tag' in r && r.attributes) {
553
+ effectiveAttributes = { ...r.attributes };
554
+ }
555
+ const appLayout = this.currentApp?.layout;
556
+ if (typeof appLayout === 'object' && appLayout.id === layoutId && appLayout.props) {
557
+ Object.assign(effectiveAttributes, propsToAttributes(appLayout.props));
558
+ }
559
+
530
560
  container.innerHTML = '';
531
561
  if (typeof r === 'string') {
532
- container.appendChild(document.createElement(r));
562
+ const el = document.createElement(r);
563
+ for (const [key, value] of Object.entries(effectiveAttributes)) {
564
+ el.setAttribute(key, value);
565
+ }
566
+ container.appendChild(el);
533
567
  } else if (r && typeof r === 'object' && 'tag' in r) {
534
568
  const el = document.createElement(r.tag);
535
- for (const [key, value] of Object.entries(r.attributes ?? {})) {
569
+ for (const [key, value] of Object.entries(effectiveAttributes)) {
536
570
  el.setAttribute(key, value);
537
571
  }
538
572
  container.appendChild(el);
@@ -600,7 +634,7 @@ class AppLoaderService {
600
634
  }
601
635
 
602
636
  getCurrentLayoutId(): string {
603
- return this.preferredLayoutId ?? this.currentApp?.layoutId ?? 'standard';
637
+ return this.preferredLayoutId ?? getLayoutIdFromApp(this.currentApp);
604
638
  }
605
639
 
606
640
  async getPreferredLayoutId(): Promise<string | undefined> {
@@ -48,6 +48,8 @@ export interface IconContribution extends Contribution {
48
48
  export interface LayoutContribution extends Contribution {
49
49
  id: string;
50
50
  name: string;
51
+ /** Optional icon name (e.g. Font Awesome) for the layout switcher. */
52
+ icon?: string;
51
53
  component: string | { tag: string; attributes?: Record<string, string> } | (() => TemplateResult);
52
54
  onShow?: () => void | Promise<void>;
53
55
  }