@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.152 → 2.0.0-next.153

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.
Files changed (90) hide show
  1. package/.storybook/vitest.setup.ts +1 -1
  2. package/bundle/openbridge-webcomponents.bundle.js +4717 -4485
  3. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  4. package/custom-elements.json +374 -52
  5. package/dist/alert-severity.d.ts +19 -1
  6. package/dist/alert-severity.d.ts.map +1 -1
  7. package/dist/alert-severity.js +48 -2
  8. package/dist/alert-severity.js.map +1 -1
  9. package/dist/components/alert-button/alert-button.css.js +7 -1513
  10. package/dist/components/alert-button/alert-button.css.js.map +1 -1
  11. package/dist/components/alert-button/alert-button.d.ts +40 -96
  12. package/dist/components/alert-button/alert-button.d.ts.map +1 -1
  13. package/dist/components/alert-button/alert-button.js +40 -107
  14. package/dist/components/alert-button/alert-button.js.map +1 -1
  15. package/dist/components/alert-button-item/alert-button-item.css.js +1570 -0
  16. package/dist/components/alert-button-item/alert-button-item.css.js.map +1 -0
  17. package/dist/components/alert-button-item/alert-button-item.d.ts +134 -0
  18. package/dist/components/alert-button-item/alert-button-item.d.ts.map +1 -0
  19. package/dist/components/alert-button-item/alert-button-item.js +210 -0
  20. package/dist/components/alert-button-item/alert-button-item.js.map +1 -0
  21. package/dist/components/alert-counter-item/alert-counter-item.css.js +25 -0
  22. package/dist/components/alert-counter-item/alert-counter-item.css.js.map +1 -0
  23. package/dist/components/alert-counter-item/alert-counter-item.d.ts +77 -0
  24. package/dist/components/alert-counter-item/alert-counter-item.d.ts.map +1 -0
  25. package/dist/components/alert-counter-item/alert-counter-item.js +87 -0
  26. package/dist/components/alert-counter-item/alert-counter-item.js.map +1 -0
  27. package/dist/components/alert-frame/alert-frame.css.js +23 -27
  28. package/dist/components/alert-frame/alert-frame.css.js.map +1 -1
  29. package/dist/components/alert-frame/alert-frame.d.ts +7 -6
  30. package/dist/components/alert-frame/alert-frame.d.ts.map +1 -1
  31. package/dist/components/alert-frame/alert-frame.js +6 -9
  32. package/dist/components/alert-frame/alert-frame.js.map +1 -1
  33. package/dist/components/tree-navigation-item/tree-navigation-item.d.ts +7 -34
  34. package/dist/components/tree-navigation-item/tree-navigation-item.d.ts.map +1 -1
  35. package/dist/components/tree-navigation-item/tree-navigation-item.js +3 -32
  36. package/dist/components/tree-navigation-item/tree-navigation-item.js.map +1 -1
  37. package/dist/generated/locales/es-419.d.ts +11 -3
  38. package/dist/generated/locales/es-419.d.ts.map +1 -1
  39. package/dist/generated/locales/es-419.js +11 -3
  40. package/dist/generated/locales/es-419.js.map +1 -1
  41. package/dist/generated/locales/fi-FI.d.ts +8 -0
  42. package/dist/generated/locales/fi-FI.d.ts.map +1 -1
  43. package/dist/generated/locales/fi-FI.js +8 -0
  44. package/dist/generated/locales/fi-FI.js.map +1 -1
  45. package/dist/navigation-instruments/readout/readout.css.js +4 -29
  46. package/dist/navigation-instruments/readout/readout.css.js.map +1 -1
  47. package/dist/navigation-instruments/readout/readout.d.ts.map +1 -1
  48. package/dist/navigation-instruments/readout/readout.js +1 -9
  49. package/dist/navigation-instruments/readout/readout.js.map +1 -1
  50. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +5 -34
  51. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
  52. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  53. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +1 -9
  54. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  55. package/dist/palettes/blinking.d.ts +6 -2
  56. package/dist/palettes/blinking.d.ts.map +1 -1
  57. package/dist/palettes/blinking.js +6 -2
  58. package/dist/palettes/blinking.js.map +1 -1
  59. package/dist/types.d.ts +15 -0
  60. package/dist/types.d.ts.map +1 -1
  61. package/dist/types.js.map +1 -1
  62. package/package.json +1 -1
  63. package/src/alert-severity.spec.ts +81 -2
  64. package/src/alert-severity.ts +74 -0
  65. package/src/components/alert-button/alert-button.css +7 -196
  66. package/src/components/alert-button/alert-button.spec.ts +119 -68
  67. package/src/components/alert-button/alert-button.stories.ts +24 -0
  68. package/src/components/alert-button/alert-button.ts +49 -211
  69. package/src/components/alert-button-item/alert-button-item.css +242 -0
  70. package/src/components/alert-button-item/alert-button-item.spec.ts +299 -0
  71. package/src/components/alert-button-item/alert-button-item.stories.ts +178 -0
  72. package/src/components/alert-button-item/alert-button-item.ts +289 -0
  73. package/src/components/alert-counter-item/alert-counter-item.css +15 -0
  74. package/src/components/alert-counter-item/alert-counter-item.spec.ts +91 -0
  75. package/src/components/alert-counter-item/alert-counter-item.stories.ts +66 -0
  76. package/src/components/alert-counter-item/alert-counter-item.ts +128 -0
  77. package/src/components/alert-frame/alert-frame.css +23 -27
  78. package/src/components/alert-frame/alert-frame.spec.ts +19 -1
  79. package/src/components/alert-frame/alert-frame.stories.ts +47 -0
  80. package/src/components/alert-frame/alert-frame.ts +16 -17
  81. package/src/components/tree-navigation-item/tree-navigation-item.ts +10 -60
  82. package/src/generated/locales/es-419.ts +11 -3
  83. package/src/generated/locales/fi-FI.ts +8 -0
  84. package/src/navigation-instruments/readout/readout.css +4 -29
  85. package/src/navigation-instruments/readout/readout.ts +1 -9
  86. package/src/navigation-instruments/readout-list-item/readout-list-item.css +5 -33
  87. package/src/navigation-instruments/readout-list-item/readout-list-item.ts +1 -9
  88. package/src/palettes/blinking.spec.ts +38 -23
  89. package/src/palettes/blinking.ts +12 -4
  90. package/src/types.ts +16 -0
@@ -0,0 +1,299 @@
1
+ import {describe, expect, it} from 'vitest';
2
+ import {render} from 'vitest-browser-lit';
3
+ import {userEvent} from '@vitest/browser/context';
4
+ import {html} from 'lit';
5
+ import './alert-button-item.js';
6
+ import {ObcAlertButtonItem, ObcAlertButtonType} from './alert-button-item.js';
7
+ import type {ObcAlertCounterItem} from '../alert-counter-item/alert-counter-item.js';
8
+ import {AlertType, FlashingSpeed, type AlertCounts} from '../../types.js';
9
+
10
+ type ItemProps = Partial<
11
+ Pick<
12
+ ObcAlertButtonItem,
13
+ | 'type'
14
+ | 'alertType'
15
+ | 'nAlerts'
16
+ | 'counter'
17
+ | 'globalCounter'
18
+ | 'counts'
19
+ | 'shelvedCount'
20
+ | 'blinking'
21
+ | 'flashingSpeed'
22
+ >
23
+ >;
24
+
25
+ const SEVERITY_COUNTS: AlertCounts = {
26
+ countAlarm: 2,
27
+ countWarning: 4,
28
+ countCaution: 6,
29
+ };
30
+
31
+ async function setup(props: ItemProps = {}) {
32
+ const screen = render(
33
+ html`<obc-alert-button-item
34
+ .type=${props.type ?? ObcAlertButtonType.Normal}
35
+ .alertType=${'alertType' in props ? props.alertType : AlertType.Alarm}
36
+ .nAlerts=${props.nAlerts ?? 3}
37
+ .counter=${props.counter ?? true}
38
+ .globalCounter=${props.globalCounter ?? false}
39
+ .counts=${props.counts ?? {}}
40
+ .shelvedCount=${props.shelvedCount ?? 0}
41
+ .blinking=${props.blinking ?? false}
42
+ .flashingSpeed=${props.flashingSpeed ?? FlashingSpeed.Default}
43
+ ></obc-alert-button-item>`
44
+ );
45
+ const el = screen.container.querySelector(
46
+ 'obc-alert-button-item'
47
+ ) as ObcAlertButtonItem;
48
+ await el.updateComplete;
49
+ return el;
50
+ }
51
+
52
+ function durations(el: HTMLElement): number[] {
53
+ return el
54
+ .getAnimations()
55
+ .map((a) => (a.effect as KeyframeEffect).getTiming().duration as number);
56
+ }
57
+
58
+ function button(el: ObcAlertButtonItem): HTMLButtonElement {
59
+ return el.shadowRoot!.querySelector('button')!;
60
+ }
61
+
62
+ describe('obc-alert-button-item flashing lifecycle', () => {
63
+ it('flashes fast for a blinking alarm with alerts', async () => {
64
+ const el = await setup({blinking: true});
65
+
66
+ expect(durations(el)).toEqual([800]);
67
+ expect(button(el).classList.contains('flash-fast')).toBe(true);
68
+ });
69
+
70
+ it('flashes slow for a warning and never for caution', async () => {
71
+ expect(
72
+ durations(await setup({blinking: true, alertType: AlertType.Warning}))
73
+ ).toEqual([1600]);
74
+ expect(
75
+ durations(await setup({blinking: true, alertType: AlertType.Caution}))
76
+ ).toEqual([]);
77
+ });
78
+
79
+ it('keeps blinking as the gate', async () => {
80
+ expect(durations(await setup({blinking: false}))).toEqual([]);
81
+ expect(durations(await setup({blinking: true, nAlerts: 0}))).toEqual([]);
82
+ });
83
+
84
+ it('honours an explicit flashingSpeed', async () => {
85
+ expect(
86
+ durations(
87
+ await setup({blinking: true, flashingSpeed: FlashingSpeed.VerySlow})
88
+ )
89
+ ).toEqual([3200]);
90
+ expect(
91
+ durations(
92
+ await setup({blinking: true, flashingSpeed: FlashingSpeed.Fixed})
93
+ )
94
+ ).toEqual([]);
95
+ });
96
+
97
+ it('cancels the animation on disconnect', async () => {
98
+ const el = await setup({blinking: true});
99
+
100
+ el.parentElement!.removeChild(el);
101
+
102
+ expect(el.getAnimations()).toHaveLength(0);
103
+ });
104
+
105
+ it('resumes flashing after disconnect and reconnect', async () => {
106
+ const el = await setup({blinking: true});
107
+ const parent = el.parentElement!;
108
+
109
+ parent.removeChild(el);
110
+ expect(el.getAnimations()).toHaveLength(0);
111
+
112
+ // Reconnect without touching any property. firstUpdated() will not run
113
+ // again, so this only passes if the controller re-syncs on connect.
114
+ parent.appendChild(el);
115
+ await el.updateComplete;
116
+
117
+ expect(durations(el)).toEqual([800]);
118
+ });
119
+
120
+ it('does not accumulate animations across repeated updates', async () => {
121
+ const el = await setup({blinking: true});
122
+
123
+ el.fillHeight = true;
124
+ await el.updateComplete;
125
+ el.counter = false;
126
+ await el.updateComplete;
127
+
128
+ expect(el.getAnimations()).toHaveLength(1);
129
+ });
130
+ });
131
+
132
+ describe('obc-alert-button-item counter', () => {
133
+ it('shows the count next to the bell', async () => {
134
+ const el = await setup();
135
+
136
+ expect(
137
+ el.shadowRoot!.querySelector('.visible-wrapper .count')!.textContent
138
+ ).toBe('3');
139
+ });
140
+
141
+ it('hides the count when flat, without alerts or with counter off', async () => {
142
+ for (const props of [
143
+ {type: ObcAlertButtonType.Flat},
144
+ {nAlerts: 0},
145
+ {counter: false},
146
+ ]) {
147
+ expect(
148
+ (await setup(props)).shadowRoot!.querySelector('.count')
149
+ ).toBeNull();
150
+ }
151
+ });
152
+ });
153
+
154
+ describe('obc-alert-button-item global counter', () => {
155
+ it('renders the severity badges, then the bell and the total', async () => {
156
+ const el = await setup({
157
+ globalCounter: true,
158
+ nAlerts: 12,
159
+ counts: SEVERITY_COUNTS,
160
+ shelvedCount: 9,
161
+ });
162
+ const counter = el.shadowRoot!.querySelector(
163
+ 'obc-alert-counter-item'
164
+ ) as ObcAlertCounterItem;
165
+
166
+ expect(counter.counts).toEqual(SEVERITY_COUNTS);
167
+ expect(counter.shelvedCount).toBe(9);
168
+ expect(
169
+ el.shadowRoot!.querySelector('.visible-wrapper obi-alerts-active')
170
+ ).not.toBeNull();
171
+ expect(
172
+ el.shadowRoot!.querySelector('.visible-wrapper .count')!.textContent
173
+ ).toBe('12');
174
+ });
175
+
176
+ it('uses the normal style whatever the type', async () => {
177
+ const el = await setup({
178
+ globalCounter: true,
179
+ type: ObcAlertButtonType.Enhanced,
180
+ nAlerts: 12,
181
+ counts: SEVERITY_COUNTS,
182
+ });
183
+
184
+ expect(button(el).classList.contains('type-normal')).toBe(true);
185
+ });
186
+
187
+ it('never flashes', async () => {
188
+ const el = await setup({
189
+ globalCounter: true,
190
+ blinking: true,
191
+ nAlerts: 12,
192
+ counts: SEVERITY_COUNTS,
193
+ });
194
+
195
+ expect(durations(el)).toEqual([]);
196
+ });
197
+
198
+ it('leaves the counter item and the total out when nothing is counted', async () => {
199
+ const el = await setup({globalCounter: true, nAlerts: 0, counts: {}});
200
+
201
+ expect(el.shadowRoot!.querySelector('obc-alert-counter-item')).toBeNull();
202
+ expect(el.shadowRoot!.querySelector('.count')).toBeNull();
203
+ });
204
+ });
205
+
206
+ describe('obc-alert-button-item accessibility', () => {
207
+ it('names the alerts, the count and the severity', async () => {
208
+ expect(button(await setup()).getAttribute('aria-label')).toBe(
209
+ 'Alerts, 3, Alarm'
210
+ );
211
+ expect(
212
+ button(await setup({nAlerts: 0, alertType: undefined})).getAttribute(
213
+ 'aria-label'
214
+ )
215
+ ).toBe('Alerts');
216
+ });
217
+
218
+ it('adds the global counter breakdown', async () => {
219
+ const el = await setup({
220
+ globalCounter: true,
221
+ nAlerts: 12,
222
+ counts: SEVERITY_COUNTS,
223
+ });
224
+
225
+ expect(button(el).getAttribute('aria-label')).toBe(
226
+ 'Alerts, 12, 2 Alarm, 4 Warning, 6 Caution'
227
+ );
228
+ });
229
+
230
+ it('names the badges the global counter shows without a total', async () => {
231
+ const el = await setup({
232
+ globalCounter: true,
233
+ nAlerts: 0,
234
+ counts: SEVERITY_COUNTS,
235
+ });
236
+
237
+ expect(button(el).getAttribute('aria-label')).toBe(
238
+ 'Alerts, 2 Alarm, 4 Warning, 6 Caution'
239
+ );
240
+ });
241
+
242
+ it('follows a host aria-label set after the first render', async () => {
243
+ const el = await setup();
244
+
245
+ el.setAttribute('aria-label', 'Engine alerts');
246
+ await el.updateComplete;
247
+
248
+ expect(button(el).getAttribute('aria-label')).toBe('Engine alerts');
249
+ });
250
+
251
+ it('does not submit an enclosing form', async () => {
252
+ let submitted = 0;
253
+ const screen = render(
254
+ html`<form
255
+ @submit=${(event: Event) => {
256
+ event.preventDefault();
257
+ submitted++;
258
+ }}
259
+ >
260
+ <obc-alert-button-item .nAlerts=${3}></obc-alert-button-item>
261
+ </form>`
262
+ );
263
+ const el = screen.container.querySelector(
264
+ 'obc-alert-button-item'
265
+ ) as ObcAlertButtonItem;
266
+ await el.updateComplete;
267
+
268
+ button(el).click();
269
+
270
+ expect(submitted).toBe(0);
271
+ });
272
+
273
+ it('forwards an aria-label set on the host', async () => {
274
+ const screen = render(
275
+ html`<obc-alert-button-item
276
+ aria-label="Engine alerts"
277
+ .nAlerts=${3}
278
+ ></obc-alert-button-item>`
279
+ );
280
+ const el = screen.container.querySelector(
281
+ 'obc-alert-button-item'
282
+ ) as ObcAlertButtonItem;
283
+ await el.updateComplete;
284
+
285
+ expect(button(el).getAttribute('aria-label')).toBe('Engine alerts');
286
+ });
287
+
288
+ it('activates with Enter and Space', async () => {
289
+ const el = await setup();
290
+ let clicks = 0;
291
+ el.addEventListener('click', () => clicks++);
292
+
293
+ button(el).focus();
294
+ await userEvent.keyboard('{Enter}');
295
+ await userEvent.keyboard(' ');
296
+
297
+ expect(clicks).toBe(2);
298
+ });
299
+ });
@@ -0,0 +1,178 @@
1
+ import type {Meta, StoryObj} from '@storybook/web-components-vite';
2
+ import {html} from 'lit';
3
+ import {ObcAlertButtonItem, ObcAlertButtonType} from './alert-button-item.js';
4
+ import './alert-button-item.js';
5
+ import {AlertType, FlashingSpeed, type AlertCounts} from '../../types.js';
6
+
7
+ type ItemArgs = Pick<
8
+ ObcAlertButtonItem,
9
+ | 'type'
10
+ | 'alertType'
11
+ | 'nAlerts'
12
+ | 'counter'
13
+ | 'globalCounter'
14
+ | 'counts'
15
+ | 'shelvedCount'
16
+ | 'blinking'
17
+ | 'flashingSpeed'
18
+ | 'fillHeight'
19
+ >;
20
+
21
+ const SEVERITY_COUNTS: AlertCounts = {
22
+ countAlarm: 2,
23
+ countWarning: 4,
24
+ countCaution: 6,
25
+ };
26
+
27
+ // Storybook drops the args whose `@availableWhen` gate is off, so every
28
+ // binding falls back to the element default.
29
+ const renderItem = (args: Partial<ItemArgs>) =>
30
+ html`<obc-alert-button-item
31
+ .type=${args.type ?? ObcAlertButtonType.Normal}
32
+ .alertType=${args.alertType}
33
+ .nAlerts=${args.nAlerts ?? 0}
34
+ .counter=${args.counter ?? false}
35
+ .globalCounter=${args.globalCounter ?? false}
36
+ .counts=${args.counts ?? {}}
37
+ .shelvedCount=${args.shelvedCount ?? 0}
38
+ .blinking=${args.blinking ?? false}
39
+ .flashingSpeed=${args.flashingSpeed ?? FlashingSpeed.Default}
40
+ .fillHeight=${args.fillHeight ?? false}
41
+ ></obc-alert-button-item>`;
42
+
43
+ const meta: Meta<ItemArgs> = {
44
+ title: 'Application Components/Alerts/Alert Button Item',
45
+ tags: ['autodocs', '6.1', 'experimental'],
46
+ component: 'obc-alert-button-item',
47
+ args: {
48
+ type: ObcAlertButtonType.Normal,
49
+ alertType: AlertType.Alarm,
50
+ nAlerts: 3,
51
+ counter: true,
52
+ globalCounter: false,
53
+ blinking: false,
54
+ },
55
+ argTypes: {
56
+ type: {
57
+ control: {type: 'inline-radio'},
58
+ options: Object.values(ObcAlertButtonType),
59
+ },
60
+ alertType: {control: {type: 'select'}, options: Object.values(AlertType)},
61
+ nAlerts: {control: {type: 'number', min: 0}},
62
+ counts: {control: {type: 'object'}},
63
+ shelvedCount: {control: {type: 'number', min: 0}},
64
+ flashingSpeed: {
65
+ control: {type: 'select'},
66
+ options: Object.values(FlashingSpeed),
67
+ },
68
+ },
69
+ render: (args) => renderItem(args),
70
+ } satisfies Meta<ItemArgs>;
71
+
72
+ export default meta;
73
+ type Story = StoryObj<ItemArgs>;
74
+
75
+ export const Default: Story = {};
76
+
77
+ export const WithoutCounter: Story = {
78
+ args: {counter: false},
79
+ };
80
+
81
+ export const Flat: Story = {
82
+ args: {type: ObcAlertButtonType.Flat},
83
+ };
84
+
85
+ export const Enhanced: Story = {
86
+ args: {type: ObcAlertButtonType.Enhanced},
87
+ };
88
+
89
+ export const NoAlerts: Story = {
90
+ args: {nAlerts: 0, alertType: undefined},
91
+ };
92
+
93
+ export const Blinking: Story = {
94
+ args: {blinking: true},
95
+ };
96
+
97
+ export const EnabledVariants: Story = {
98
+ render: () =>
99
+ html`<div style="display:flex;gap:24px;align-items:center">
100
+ ${renderItem({type: ObcAlertButtonType.Flat})}
101
+ ${renderItem({type: ObcAlertButtonType.Normal})}
102
+ ${[AlertType.Caution, AlertType.Warning, AlertType.Alarm].map(
103
+ (alertType) =>
104
+ [
105
+ ObcAlertButtonType.Flat,
106
+ ObcAlertButtonType.Normal,
107
+ ObcAlertButtonType.Enhanced,
108
+ ].map((type) =>
109
+ renderItem({type, alertType, nAlerts: 3, counter: true})
110
+ )
111
+ )}
112
+ ${renderItem({globalCounter: true, nAlerts: 12, counts: SEVERITY_COUNTS})}
113
+ </div>`,
114
+ parameters: {
115
+ docs: {
116
+ description: {
117
+ story:
118
+ 'The Enabled row of the Figma Alert button item: flat and normal without alerts; flat, normal and enhanced for caution, warning and alarm; the global counter.',
119
+ },
120
+ },
121
+ },
122
+ };
123
+
124
+ export const LevelSeverities: Story = {
125
+ render: () =>
126
+ html`<div style="display:flex;gap:24px;align-items:center">
127
+ ${[
128
+ AlertType.LevelCritical,
129
+ AlertType.LevelHigh,
130
+ AlertType.LevelMedium,
131
+ AlertType.LevelLow,
132
+ AlertType.LevelDiagnostic,
133
+ ].map((alertType) =>
134
+ [ObcAlertButtonType.Normal, ObcAlertButtonType.Enhanced].map((type) =>
135
+ renderItem({type, alertType, nAlerts: 3, counter: true})
136
+ )
137
+ )}
138
+ </div>`,
139
+ };
140
+
141
+ export const GlobalCounter: Story = {
142
+ args: {globalCounter: true, nAlerts: 12, counts: SEVERITY_COUNTS},
143
+ };
144
+
145
+ export const GlobalCounterWithShelved: Story = {
146
+ args: {
147
+ globalCounter: true,
148
+ nAlerts: 12,
149
+ counts: SEVERITY_COUNTS,
150
+ shelvedCount: 9,
151
+ },
152
+ };
153
+
154
+ export const GlobalCounterLevelSeverities: Story = {
155
+ args: {
156
+ globalCounter: true,
157
+ nAlerts: 23,
158
+ counts: {
159
+ countLevelCritical: 1,
160
+ countLevelHigh: 9,
161
+ countLevelMedium: 4,
162
+ countLevelLow: 2,
163
+ countLevelDiagnostic: 7,
164
+ },
165
+ },
166
+ };
167
+
168
+ export const FillHeight: Story = {
169
+ render: () =>
170
+ html`<div style="display:flex;height:56px">
171
+ ${renderItem({
172
+ alertType: AlertType.Alarm,
173
+ nAlerts: 3,
174
+ counter: true,
175
+ fillHeight: true,
176
+ })}
177
+ </div>`,
178
+ };