@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.72 → 2.0.0-next.73

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.
@@ -70183,7 +70183,7 @@
70183
70183
  "declarations": [
70184
70184
  {
70185
70185
  "kind": "class",
70186
- "description": "`<obc-integration-vessel-menu>` – A menu to be shown when selecting a obc-integration-button from a obc-integration-bar.",
70186
+ "description": "`<obc-integration-vessel-menu>` – A menu to be shown when selecting a obc-integration-button from a obc-integration-bar.\n\n## Sizing\n\nThe menu hugs its content and never reserves more space than its slotted\nsections need; it deliberately does not impose a height of its own. Sizing is\nowned by the consumer, since only the consumer knows how large the menu may\ngrow in a given layout.\n\nFrom a web components perspective, drive the size from the host element and\nthe slotted light-DOM nodes — not from component properties:\n\n- **Bound the whole menu** by giving the host element a definite `height`. The\n menu fills that height and the alert list scrolls within the remaining space\n while the footer and content keep their size. This is the recommended\n approach. (A `max-height` alone will not bound the list — the internal\n scroll needs a definite height to resolve against.)\n- **Size sections independently** (advanced) by sizing the slotted nodes\n directly — e.g. a fixed-height `content` element, or a capped, scrollable\n wrapper around the `alarms` items.\n- **Leave it unbounded** to let the menu grow with its content.",
70187
70187
  "name": "ObcIntegrationVesselMenu",
70188
70188
  "slots": [
70189
70189
  {
@@ -70202,24 +70202,27 @@
70202
70202
  "members": [
70203
70203
  {
70204
70204
  "kind": "field",
70205
- "name": "hideAlarmList",
70205
+ "name": "hasActions",
70206
70206
  "type": {
70207
70207
  "text": "boolean"
70208
70208
  },
70209
- "default": "false",
70210
- "description": "Hide the alarm list, ensuring it doesn't take space (display: none).",
70211
- "attribute": "hideAlarmList"
70212
- }
70213
- ],
70214
- "attributes": [
70209
+ "default": "true"
70210
+ },
70215
70211
  {
70216
- "name": "hideAlarmList",
70212
+ "kind": "field",
70213
+ "name": "hasAlertList",
70217
70214
  "type": {
70218
70215
  "text": "boolean"
70219
70216
  },
70220
- "default": "false",
70221
- "description": "Hide the alarm list, ensuring it doesn't take space (display: none).",
70222
- "fieldName": "hideAlarmList"
70217
+ "default": "true"
70218
+ },
70219
+ {
70220
+ "kind": "field",
70221
+ "name": "hasContent",
70222
+ "type": {
70223
+ "text": "boolean"
70224
+ },
70225
+ "default": "true"
70223
70226
  }
70224
70227
  ],
70225
70228
  "superclass": {
@@ -8,6 +8,10 @@ const componentStyle = css`
8
8
  box-sizing: border-box;
9
9
  }
10
10
 
11
+ :host {
12
+ display: block;
13
+ }
14
+
11
15
  .wrapper {
12
16
  border-color: var(--integration-normal-enabled-border-color);
13
17
  background-color: var(--integration-normal-enabled-background-color);
@@ -18,6 +22,7 @@ const componentStyle = css`
18
22
  display: flex;
19
23
  flex-direction: column;
20
24
  align-items: center;
25
+ height: 100%;
21
26
  background: var(--container-global-color);
22
27
  border-radius: var(
23
28
  --app-components-integration-system-dropdown-menu-border-radius
@@ -44,6 +49,10 @@ const componentStyle = css`
44
49
  border-radius: 12px;
45
50
  }
46
51
 
52
+ .footer-container.hidden {
53
+ display: none;
54
+ }
55
+
47
56
  .content-area {
48
57
  display: flex;
49
58
  flex-direction: column;
@@ -53,6 +62,10 @@ const componentStyle = css`
53
62
  border-radius: 8px;
54
63
  }
55
64
 
65
+ .content-area.hidden {
66
+ display: none;
67
+ }
68
+
56
69
  .footer-container slot[name="buttons"]::slotted(*) {
57
70
  display: flex;
58
71
  flex: 1 1 0px;
@@ -67,7 +80,8 @@ const componentStyle = css`
67
80
  gap: var(--app-components-integration-system-menu-action-spacing);
68
81
  }
69
82
 
70
- .buttons-slot {
83
+ .buttons-slot,
84
+ .content-slot {
71
85
  display: contents;
72
86
  }
73
87
 
@@ -81,12 +95,13 @@ const componentStyle = css`
81
95
  border-radius: 8px;
82
96
  }
83
97
 
84
- .content-container.hidealarmlist {
98
+ .content-container.hidden {
85
99
  display: none;
86
100
  }
87
101
 
88
102
  .alertlist {
89
103
  width: 100%;
104
+ height: 100%;
90
105
  }
91
106
 
92
107
  .leading-icon {
@@ -1 +1 @@
1
- {"version":3,"file":"integration-vessel-menu.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"integration-vessel-menu.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,17 +2,39 @@ import { LitElement } from 'lit';
2
2
  import '../../components/button/button.js';
3
3
  import '../../components/icon-button/icon-button.js';
4
4
  import '../../icons/icon-placeholder.js';
5
+ import '../../icons/icon-unacknowledged.js';
5
6
  import '../../building-blocks/alert-list/alert-list.js';
6
7
  /**
7
8
  * `<obc-integration-vessel-menu>` – A menu to be shown when selecting a obc-integration-button from a obc-integration-bar.
8
9
  *
10
+ * ## Sizing
11
+ *
12
+ * The menu hugs its content and never reserves more space than its slotted
13
+ * sections need; it deliberately does not impose a height of its own. Sizing is
14
+ * owned by the consumer, since only the consumer knows how large the menu may
15
+ * grow in a given layout.
16
+ *
17
+ * From a web components perspective, drive the size from the host element and
18
+ * the slotted light-DOM nodes — not from component properties:
19
+ *
20
+ * - **Bound the whole menu** by giving the host element a definite `height`. The
21
+ * menu fills that height and the alert list scrolls within the remaining space
22
+ * while the footer and content keep their size. This is the recommended
23
+ * approach. (A `max-height` alone will not bound the list — the internal
24
+ * scroll needs a definite height to resolve against.)
25
+ * - **Size sections independently** (advanced) by sizing the slotted nodes
26
+ * directly — e.g. a fixed-height `content` element, or a capped, scrollable
27
+ * wrapper around the `alarms` items.
28
+ * - **Leave it unbounded** to let the menu grow with its content.
29
+ *
9
30
  * @slot buttons - Buttons shown in the footer.
10
31
  * @slot content - Main content shown in the content area.
11
32
  * @slot alarms - Alarm items rendered inside the alert list.
12
33
  */
13
34
  export declare class ObcIntegrationVesselMenu extends LitElement {
14
- /** Hide the alarm list, ensuring it doesn't take space (display: none). */
15
- hideAlarmList: boolean;
35
+ hasActions: boolean;
36
+ hasAlertList: boolean;
37
+ hasContent: boolean;
16
38
  protected render(): import('lit-html').TemplateResult<1>;
17
39
  static styles: import('lit').CSSResult;
18
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"integration-vessel-menu.d.ts","sourceRoot":"","sources":["../../../src/integration-systems/integration-vessel-menu/integration-vessel-menu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAkB,MAAM,KAAK,CAAC;AAMhD,OAAO,mCAAmC,CAAC;AAC3C,OAAO,6CAA6C,CAAC;AACrD,OAAO,iCAAiC,CAAC;AACzC,OAAO,gDAAgD,CAAC;AAExD;;;;;;GAMG;AAEH,qBACa,wBAAyB,SAAQ,UAAU;IACtD,2EAA2E;IAChD,aAAa,UAAS;cAE9B,MAAM;IA2BzB,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,6BAA6B,EAAE,wBAAwB,CAAC;KACzD;CACF"}
1
+ {"version":3,"file":"integration-vessel-menu.d.ts","sourceRoot":"","sources":["../../../src/integration-systems/integration-vessel-menu/integration-vessel-menu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAkB,MAAM,KAAK,CAAC;AAMhD,OAAO,mCAAmC,CAAC;AAC3C,OAAO,6CAA6C,CAAC;AACrD,OAAO,iCAAiC,CAAC;AACzC,OAAO,oCAAoC,CAAC;AAC5C,OAAO,gDAAgD,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,qBACa,wBAAyB,SAAQ,UAAU;IACT,UAAU,UAAQ;IAClB,YAAY,UAAQ;IACpB,UAAU,UAAQ;cAE5C,MAAM;IAuCzB,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,6BAA6B,EAAE,wBAAwB,CAAC;KACzD;CACF"}
@@ -6,6 +6,7 @@ import componentStyle from "./integration-vessel-menu.css.js";
6
6
  import "../../components/button/button.js";
7
7
  import "../../components/icon-button/icon-button.js";
8
8
  import "../../icons/icon-placeholder.js";
9
+ import "../../icons/icon-unacknowledged.js";
9
10
  import "../../building-blocks/alert-list/alert-list.js";
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -20,29 +21,43 @@ var __decorateClass = (decorators, target, key, kind) => {
20
21
  let ObcIntegrationVesselMenu = class extends LitElement {
21
22
  constructor() {
22
23
  super(...arguments);
23
- this.hideAlarmList = false;
24
+ this.hasActions = true;
25
+ this.hasAlertList = true;
26
+ this.hasContent = true;
24
27
  }
25
28
  render() {
26
29
  return html`
27
- <div
28
- class=${classMap({
29
- wrapper: true
30
+ <div class="wrapper">
31
+ <div
32
+ class=${classMap({
33
+ "footer-container": true,
34
+ hidden: !this.hasActions
30
35
  })}
31
- >
32
- <div class="footer-container">
36
+ >
33
37
  <slot name="buttons" class="buttons-slot"></slot>
34
38
  </div>
35
- <div class="content-area">
36
- <slot name="content"></slot>
39
+ <div
40
+ class=${classMap({
41
+ "content-area": true,
42
+ hidden: !this.hasContent
43
+ })}
44
+ >
45
+ <slot name="content" class="content-slot"></slot>
37
46
  </div>
38
47
  <div
39
48
  class=${classMap({
40
49
  "content-container": true,
41
- hidealarmlist: this.hideAlarmList
50
+ hidden: !this.hasAlertList
42
51
  })}
43
52
  >
44
53
  <obc-alert-list class="alertlist"
45
54
  ><slot name="alarms"></slot>
55
+ <div slot="empty-icon">
56
+ <obi-unacknowledged></obi-unacknowledged>
57
+ </div>
58
+ <div slot="empty-title">
59
+ <span>No alerts</span>
60
+ </div>
46
61
  </obc-alert-list>
47
62
  </div>
48
63
  </div>
@@ -51,8 +66,14 @@ let ObcIntegrationVesselMenu = class extends LitElement {
51
66
  };
52
67
  ObcIntegrationVesselMenu.styles = unsafeCSS(componentStyle);
53
68
  __decorateClass([
54
- property({ type: Boolean })
55
- ], ObcIntegrationVesselMenu.prototype, "hideAlarmList", 2);
69
+ property({ type: Boolean, attribute: false })
70
+ ], ObcIntegrationVesselMenu.prototype, "hasActions", 2);
71
+ __decorateClass([
72
+ property({ type: Boolean, attribute: false })
73
+ ], ObcIntegrationVesselMenu.prototype, "hasAlertList", 2);
74
+ __decorateClass([
75
+ property({ type: Boolean, attribute: false })
76
+ ], ObcIntegrationVesselMenu.prototype, "hasContent", 2);
56
77
  ObcIntegrationVesselMenu = __decorateClass([
57
78
  customElement("obc-integration-vessel-menu")
58
79
  ], ObcIntegrationVesselMenu);
@@ -1 +1 @@
1
- {"version":3,"file":"integration-vessel-menu.js","sources":["../../../src/integration-systems/integration-vessel-menu/integration-vessel-menu.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './integration-vessel-menu.css?inline';\n\nimport '../../components/button/button.js';\nimport '../../components/icon-button/icon-button.js';\nimport '../../icons/icon-placeholder.js';\nimport '../../building-blocks/alert-list/alert-list.js';\n\n/**\n * `<obc-integration-vessel-menu>` – A menu to be shown when selecting a obc-integration-button from a obc-integration-bar.\n *\n * @slot buttons - Buttons shown in the footer.\n * @slot content - Main content shown in the content area.\n * @slot alarms - Alarm items rendered inside the alert list.\n */\n\n@customElement('obc-integration-vessel-menu')\nexport class ObcIntegrationVesselMenu extends LitElement {\n /** Hide the alarm list, ensuring it doesn't take space (display: none). */\n @property({type: Boolean}) hideAlarmList = false;\n\n protected override render() {\n return html`\n <div\n class=${classMap({\n wrapper: true,\n })}\n >\n <div class=\"footer-container\">\n <slot name=\"buttons\" class=\"buttons-slot\"></slot>\n </div>\n <div class=\"content-area\">\n <slot name=\"content\"></slot>\n </div>\n <div\n class=${classMap({\n 'content-container': true,\n hidealarmlist: this.hideAlarmList,\n })}\n >\n <obc-alert-list class=\"alertlist\"\n ><slot name=\"alarms\"></slot>\n </obc-alert-list>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-integration-vessel-menu': ObcIntegrationVesselMenu;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAoBO,IAAM,2BAAN,cAAuC,WAAW;AAAA,EAAlD,cAAA;AAAA,UAAA,GAAA,SAAA;AAEsB,SAAA,gBAAgB;AAAA,EAAA;AAAA,EAExB,SAAS;AAC1B,WAAO;AAAA;AAAA,gBAEK,SAAS;AAAA,MACf,SAAS;AAAA,IAAA,CACV,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBASQ,SAAS;AAAA,MACf,qBAAqB;AAAA,MACrB,eAAe,KAAK;AAAA,IAAA,CACrB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQV;AAGF;AAhCa,yBA+BK,SAAS,UAAU,cAAc;AA7BtB,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAFd,yBAEgB,WAAA,iBAAA,CAAA;AAFhB,2BAAN,gBAAA;AAAA,EADN,cAAc,6BAA6B;AAAA,GAC/B,wBAAA;"}
1
+ {"version":3,"file":"integration-vessel-menu.js","sources":["../../../src/integration-systems/integration-vessel-menu/integration-vessel-menu.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './integration-vessel-menu.css?inline';\n\nimport '../../components/button/button.js';\nimport '../../components/icon-button/icon-button.js';\nimport '../../icons/icon-placeholder.js';\nimport '../../icons/icon-unacknowledged.js';\nimport '../../building-blocks/alert-list/alert-list.js';\n\n/**\n * `<obc-integration-vessel-menu>` – A menu to be shown when selecting a obc-integration-button from a obc-integration-bar.\n *\n * ## Sizing\n *\n * The menu hugs its content and never reserves more space than its slotted\n * sections need; it deliberately does not impose a height of its own. Sizing is\n * owned by the consumer, since only the consumer knows how large the menu may\n * grow in a given layout.\n *\n * From a web components perspective, drive the size from the host element and\n * the slotted light-DOM nodes — not from component properties:\n *\n * - **Bound the whole menu** by giving the host element a definite `height`. The\n * menu fills that height and the alert list scrolls within the remaining space\n * while the footer and content keep their size. This is the recommended\n * approach. (A `max-height` alone will not bound the list — the internal\n * scroll needs a definite height to resolve against.)\n * - **Size sections independently** (advanced) by sizing the slotted nodes\n * directly — e.g. a fixed-height `content` element, or a capped, scrollable\n * wrapper around the `alarms` items.\n * - **Leave it unbounded** to let the menu grow with its content.\n *\n * @slot buttons - Buttons shown in the footer.\n * @slot content - Main content shown in the content area.\n * @slot alarms - Alarm items rendered inside the alert list.\n */\n\n@customElement('obc-integration-vessel-menu')\nexport class ObcIntegrationVesselMenu extends LitElement {\n @property({type: Boolean, attribute: false}) hasActions = true;\n @property({type: Boolean, attribute: false}) hasAlertList = true;\n @property({type: Boolean, attribute: false}) hasContent = true;\n\n protected override render() {\n return html`\n <div class=\"wrapper\">\n <div\n class=${classMap({\n 'footer-container': true,\n hidden: !this.hasActions,\n })}\n >\n <slot name=\"buttons\" class=\"buttons-slot\"></slot>\n </div>\n <div\n class=${classMap({\n 'content-area': true,\n hidden: !this.hasContent,\n })}\n >\n <slot name=\"content\" class=\"content-slot\"></slot>\n </div>\n <div\n class=${classMap({\n 'content-container': true,\n hidden: !this.hasAlertList,\n })}\n >\n <obc-alert-list class=\"alertlist\"\n ><slot name=\"alarms\"></slot>\n <div slot=\"empty-icon\">\n <obi-unacknowledged></obi-unacknowledged>\n </div>\n <div slot=\"empty-title\">\n <span>No alerts</span>\n </div>\n </obc-alert-list>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-integration-vessel-menu': ObcIntegrationVesselMenu;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAyCO,IAAM,2BAAN,cAAuC,WAAW;AAAA,EAAlD,cAAA;AAAA,UAAA,GAAA,SAAA;AACwC,SAAA,aAAa;AACb,SAAA,eAAe;AACf,SAAA,aAAa;AAAA,EAAA;AAAA,EAEvC,SAAS;AAC1B,WAAO;AAAA;AAAA;AAAA,kBAGO,SAAS;AAAA,MACf,oBAAoB;AAAA,MACpB,QAAQ,CAAC,KAAK;AAAA,IAAA,CACf,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,kBAKM,SAAS;AAAA,MACf,gBAAgB;AAAA,MAChB,QAAQ,CAAC,KAAK;AAAA,IAAA,CACf,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,kBAKM,SAAS;AAAA,MACf,qBAAqB;AAAA,MACrB,QAAQ,CAAC,KAAK;AAAA,IAAA,CACf,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcV;AAGF;AA7Ca,yBA4CK,SAAS,UAAU,cAAc;AA3CJ,gBAAA;AAAA,EAA5C,SAAS,EAAC,MAAM,SAAS,WAAW,OAAM;AAAA,GADhC,yBACkC,WAAA,cAAA,CAAA;AACA,gBAAA;AAAA,EAA5C,SAAS,EAAC,MAAM,SAAS,WAAW,OAAM;AAAA,GAFhC,yBAEkC,WAAA,gBAAA,CAAA;AACA,gBAAA;AAAA,EAA5C,SAAS,EAAC,MAAM,SAAS,WAAW,OAAM;AAAA,GAHhC,yBAGkC,WAAA,cAAA,CAAA;AAHlC,2BAAN,gBAAA;AAAA,EADN,cAAc,6BAA6B;AAAA,GAC/B,wBAAA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oicl/openbridge-webcomponents-full-bundle",
3
- "version": "2.0.0-next.72",
3
+ "version": "2.0.0-next.73",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -2,11 +2,16 @@
2
2
  box-sizing: border-box;
3
3
  }
4
4
 
5
+ :host {
6
+ display: block;
7
+ }
8
+
5
9
  .wrapper {
6
10
  @mixin style style=integration-normal noClick=true;
7
11
  display: flex;
8
12
  flex-direction: column;
9
13
  align-items: center;
14
+ height: 100%;
10
15
  background: var(--container-global-color);
11
16
  border-radius: var(
12
17
  --app-components-integration-system-dropdown-menu-border-radius
@@ -31,6 +36,9 @@
31
36
  border-top: 1px solid var(--border-divider-color);
32
37
  background: var(--container-global-color);
33
38
  border-radius: 12px;
39
+ &.hidden {
40
+ display: none;
41
+ }
34
42
  }
35
43
 
36
44
  .content-area {
@@ -40,6 +48,9 @@
40
48
  gap: 8px;
41
49
  align-self: stretch;
42
50
  border-radius: 8px;
51
+ &.hidden {
52
+ display: none;
53
+ }
43
54
  }
44
55
 
45
56
  .footer-container slot[name="buttons"]::slotted(*) {
@@ -56,7 +67,8 @@
56
67
  gap: var(--app-components-integration-system-menu-action-spacing);
57
68
  }
58
69
 
59
- .buttons-slot {
70
+ .buttons-slot,
71
+ .content-slot {
60
72
  display: contents;
61
73
  }
62
74
 
@@ -68,13 +80,14 @@
68
80
  min-height: 0;
69
81
  flex: 1;
70
82
  border-radius: 8px;
71
- &.hidealarmlist {
83
+ &.hidden {
72
84
  display: none;
73
85
  }
74
86
  }
75
87
 
76
88
  .alertlist {
77
89
  width: 100%;
90
+ height: 100%;
78
91
  }
79
92
 
80
93
  .leading-icon {
@@ -102,31 +102,46 @@ const renderAlarms = () => html`
102
102
  </obc-alert-menu-item>
103
103
  `;
104
104
 
105
+ const renderButtons = () => html`
106
+ <obc-button slot="buttons" ?fullWidth=${true}>Action 1</obc-button>
107
+ <obc-button slot="buttons" ?fullWidth=${true}>Ac. 2</obc-button>
108
+ <obc-button slot="buttons" ?fullWidth=${true}>Action number 3</obc-button>
109
+ `;
110
+
111
+ const renderContent = () => html`
112
+ <div slot="content" style="padding: 16px;">
113
+ <p style="margin: 0;">Content area</p>
114
+ </div>
115
+ `;
116
+
105
117
  const meta: Meta<ObcIntegrationVesselMenu> = {
106
118
  title: 'Integration Systems/Integration Vessel Menu',
107
119
  component: 'obc-integration-vessel-menu',
108
120
  tags: ['alpha'],
109
- args: {hideAlarmList: false},
121
+ args: {hasActions: true, hasAlertList: true, hasContent: true},
110
122
  argTypes: {
111
- hideAlarmList: {
123
+ hasActions: {
124
+ control: 'boolean',
125
+ },
126
+ hasAlertList: {
127
+ control: 'boolean',
128
+ },
129
+ hasContent: {
112
130
  control: 'boolean',
113
131
  },
114
132
  },
115
133
  parameters: {
116
134
  layout: 'centered',
117
135
  },
118
- decorators: [
119
- (story) => html`
120
- <div style="height: 400px; display: flex;">${story()}</div>
121
- `,
122
- ],
123
136
  };
124
137
 
125
138
  export default meta;
126
139
  type Story = StoryObj<ObcIntegrationVesselMenu>;
127
140
 
128
141
  interface IntegrationVesselMenuArgs {
129
- hideAlarmList: boolean;
142
+ hasActions: boolean;
143
+ hasAlertList: boolean;
144
+ hasContent: boolean;
130
145
  }
131
146
 
132
147
  type IntegrationVesselMenuTemplate = (
@@ -134,69 +149,23 @@ type IntegrationVesselMenuTemplate = (
134
149
  ) => ReturnType<typeof html>;
135
150
 
136
151
  const template: IntegrationVesselMenuTemplate = (args) => html`
137
- <obc-integration-vessel-menu .hideAlarmList=${args.hideAlarmList}>
138
- <div slot="content" style="padding: 24px;">
139
- <div style="width: 496px; height: 256;">
140
- <p>Content area</p>
141
- </div>
142
- </div>
143
- <obc-button
144
- slot="buttons"
145
- @click=${() => console.log('Button 1 clicked')}
146
- ?fullWidth=${true}
147
- >
148
- <div>Action 1</div>
149
- </obc-button>
150
- <obc-button
151
- slot="buttons"
152
- @click=${() => console.log('Button 2 clicked')}
153
- ?fullWidth=${true}
154
- >
155
- Ac. 2
156
- </obc-button>
157
- <obc-button
158
- slot="buttons"
159
- @click=${() => console.log('Button 3 clicked')}
160
- ?fullWidth=${true}
161
- >
162
- Action number 3
163
- </obc-button>
164
-
165
- ${renderAlarms()}
166
- </obc-integration-vessel-menu>
167
- `;
168
-
169
- const templateWithoutAlarms: IntegrationVesselMenuTemplate = (args) => html`
170
- <obc-integration-vessel-menu .hideAlarmList=${args.hideAlarmList}>
171
- <obc-button
172
- slot="buttons"
173
- @click=${() => console.log('Button 1 clicked')}
174
- ?fullWidth=${true}
175
- >
176
- Action 1
177
- </obc-button>
178
- <obc-button
179
- slot="buttons"
180
- @click=${() => console.log('Button 2 clicked')}
181
- ?fullWidth=${true}
182
- >
183
- Ac. 2
184
- </obc-button>
185
- <obc-button
186
- slot="buttons"
187
- @click=${() => console.log('Button 3 clicked')}
188
- ?fullWidth=${true}
189
- >
190
- Action number 3
191
- </obc-button>
192
- <div slot="content" style="padding: 24px;">
193
- <p>Add content here</p>
194
- </div>
152
+ <obc-integration-vessel-menu
153
+ style="width: 400px;"
154
+ .hasActions=${args.hasActions}
155
+ .hasAlertList=${args.hasAlertList}
156
+ .hasContent=${args.hasContent}
157
+ >
158
+ ${renderButtons()} ${renderContent()} ${renderAlarms()}
195
159
  </obc-integration-vessel-menu>
196
160
  `;
197
161
 
198
162
  const templateWrappedButtons: IntegrationVesselMenuTemplate = (args) => html`
199
- <obc-integration-vessel-menu .hideAlarmList=${args.hideAlarmList}>
163
+ <obc-integration-vessel-menu
164
+ style="width: 600px; height: 400px;"
165
+ .hasActions=${args.hasActions}
166
+ .hasAlertList=${args.hasAlertList}
167
+ .hasContent=${args.hasContent}
168
+ >
200
169
  <div slot="buttons">
201
170
  <div style="display: contents;">
202
171
  <obc-button ?fullWidth=${true}>Open</obc-button>
@@ -218,15 +187,76 @@ export const Default: Story = {
218
187
  render: template,
219
188
  };
220
189
 
221
- export const WithoutAlarms: Story = {
222
- render: templateWithoutAlarms,
190
+ export const NoActions: Story = {
191
+ render: template,
192
+ args: {hasActions: false},
193
+ };
194
+
195
+ export const NoContent: Story = {
196
+ render: template,
197
+ args: {hasContent: false},
198
+ };
199
+
200
+ export const NoAlertList: Story = {
201
+ render: template,
202
+ args: {hasAlertList: false},
223
203
  };
224
204
 
225
- export const WithoutAlarmsHideEmptyAlarmList: Story = {
226
- render: templateWithoutAlarms,
227
- args: {hideAlarmList: true},
205
+ // Recommended bounded usage: the consumer caps the menu by setting a height on
206
+ // the host element. The menu fills that height and the alert list scrolls within
207
+ // the remaining space automatically — no per-slot sizing required.
208
+ const templateConstrained: IntegrationVesselMenuTemplate = (args) => html`
209
+ <obc-integration-vessel-menu
210
+ style="width: 400px; height: 500px;"
211
+ .hasActions=${args.hasActions}
212
+ .hasAlertList=${args.hasAlertList}
213
+ .hasContent=${args.hasContent}
214
+ >
215
+ ${renderButtons()} ${renderContent()} ${renderAlarms()}
216
+ </obc-integration-vessel-menu>
217
+ `;
218
+
219
+ export const Constrained: Story = {
220
+ render: templateConstrained,
221
+ };
222
+
223
+ // Without consumer bounding, tall content grows the whole menu unbounded.
224
+ const templateLongContent: IntegrationVesselMenuTemplate = (args) => html`
225
+ <obc-integration-vessel-menu
226
+ style="width: 400px;"
227
+ .hasActions=${args.hasActions}
228
+ .hasAlertList=${args.hasAlertList}
229
+ .hasContent=${args.hasContent}
230
+ >
231
+ ${renderButtons()}
232
+ <div slot="content" style="padding: 16px;">
233
+ <div style="height: 600px;">
234
+ <p style="margin: 0;">Tall content with no height cap</p>
235
+ </div>
236
+ </div>
237
+ </obc-integration-vessel-menu>
238
+ `;
239
+
240
+ export const LongContentOverflow: Story = {
241
+ render: templateLongContent,
242
+ args: {hasAlertList: false},
228
243
  };
229
244
 
230
245
  export const WithButtonsWrappedInDivWithoutStyling: Story = {
231
246
  render: templateWrappedButtons,
232
247
  };
248
+
249
+ const templateNoAlerts: IntegrationVesselMenuTemplate = (args) => html`
250
+ <obc-integration-vessel-menu
251
+ style="width: 400px;"
252
+ .hasActions=${args.hasActions}
253
+ .hasAlertList=${args.hasAlertList}
254
+ .hasContent=${args.hasContent}
255
+ >
256
+ ${renderButtons()} ${renderContent()}
257
+ </obc-integration-vessel-menu>
258
+ `;
259
+
260
+ export const NoAlerts: Story = {
261
+ render: templateNoAlerts,
262
+ };
@@ -7,11 +7,32 @@ import componentStyle from './integration-vessel-menu.css?inline';
7
7
  import '../../components/button/button.js';
8
8
  import '../../components/icon-button/icon-button.js';
9
9
  import '../../icons/icon-placeholder.js';
10
+ import '../../icons/icon-unacknowledged.js';
10
11
  import '../../building-blocks/alert-list/alert-list.js';
11
12
 
12
13
  /**
13
14
  * `<obc-integration-vessel-menu>` – A menu to be shown when selecting a obc-integration-button from a obc-integration-bar.
14
15
  *
16
+ * ## Sizing
17
+ *
18
+ * The menu hugs its content and never reserves more space than its slotted
19
+ * sections need; it deliberately does not impose a height of its own. Sizing is
20
+ * owned by the consumer, since only the consumer knows how large the menu may
21
+ * grow in a given layout.
22
+ *
23
+ * From a web components perspective, drive the size from the host element and
24
+ * the slotted light-DOM nodes — not from component properties:
25
+ *
26
+ * - **Bound the whole menu** by giving the host element a definite `height`. The
27
+ * menu fills that height and the alert list scrolls within the remaining space
28
+ * while the footer and content keep their size. This is the recommended
29
+ * approach. (A `max-height` alone will not bound the list — the internal
30
+ * scroll needs a definite height to resolve against.)
31
+ * - **Size sections independently** (advanced) by sizing the slotted nodes
32
+ * directly — e.g. a fixed-height `content` element, or a capped, scrollable
33
+ * wrapper around the `alarms` items.
34
+ * - **Leave it unbounded** to let the menu grow with its content.
35
+ *
15
36
  * @slot buttons - Buttons shown in the footer.
16
37
  * @slot content - Main content shown in the content area.
17
38
  * @slot alarms - Alarm items rendered inside the alert list.
@@ -19,30 +40,43 @@ import '../../building-blocks/alert-list/alert-list.js';
19
40
 
20
41
  @customElement('obc-integration-vessel-menu')
21
42
  export class ObcIntegrationVesselMenu extends LitElement {
22
- /** Hide the alarm list, ensuring it doesn't take space (display: none). */
23
- @property({type: Boolean}) hideAlarmList = false;
43
+ @property({type: Boolean, attribute: false}) hasActions = true;
44
+ @property({type: Boolean, attribute: false}) hasAlertList = true;
45
+ @property({type: Boolean, attribute: false}) hasContent = true;
24
46
 
25
47
  protected override render() {
26
48
  return html`
27
- <div
28
- class=${classMap({
29
- wrapper: true,
30
- })}
31
- >
32
- <div class="footer-container">
49
+ <div class="wrapper">
50
+ <div
51
+ class=${classMap({
52
+ 'footer-container': true,
53
+ hidden: !this.hasActions,
54
+ })}
55
+ >
33
56
  <slot name="buttons" class="buttons-slot"></slot>
34
57
  </div>
35
- <div class="content-area">
36
- <slot name="content"></slot>
58
+ <div
59
+ class=${classMap({
60
+ 'content-area': true,
61
+ hidden: !this.hasContent,
62
+ })}
63
+ >
64
+ <slot name="content" class="content-slot"></slot>
37
65
  </div>
38
66
  <div
39
67
  class=${classMap({
40
68
  'content-container': true,
41
- hidealarmlist: this.hideAlarmList,
69
+ hidden: !this.hasAlertList,
42
70
  })}
43
71
  >
44
72
  <obc-alert-list class="alertlist"
45
73
  ><slot name="alarms"></slot>
74
+ <div slot="empty-icon">
75
+ <obi-unacknowledged></obi-unacknowledged>
76
+ </div>
77
+ <div slot="empty-title">
78
+ <span>No alerts</span>
79
+ </div>
46
80
  </obc-alert-list>
47
81
  </div>
48
82
  </div>