@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.136 → 2.0.0-next.138
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/bundle/openbridge-webcomponents.bundle.js +11640 -10983
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +921 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.css.js +12 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.css.js.map +1 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.d.ts +33 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.d.ts.map +1 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.js +58 -0
- package/dist/automation/hydraulic-check-valve/hydraulic-check-valve.js.map +1 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.d.ts +77 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.d.ts.map +1 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.js +74 -0
- package/dist/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.js.map +1 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.d.ts +74 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.d.ts.map +1 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.js +60 -0
- package/dist/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.js.map +1 -0
- package/dist/automation/shuffle-button/shuffle-button-base.d.ts +67 -0
- package/dist/automation/shuffle-button/shuffle-button-base.d.ts.map +1 -0
- package/dist/automation/shuffle-button/shuffle-button-base.js +126 -0
- package/dist/automation/shuffle-button/shuffle-button-base.js.map +1 -0
- package/dist/automation/shuffle-button/shuffle-button.css.js +219 -0
- package/dist/automation/shuffle-button/shuffle-button.css.js.map +1 -0
- package/dist/automation/shuffle-button/shuffle-layout.d.ts +9 -0
- package/dist/automation/shuffle-button/shuffle-layout.d.ts.map +1 -0
- package/dist/automation/shuffle-button/shuffle-layout.js +16 -0
- package/dist/automation/shuffle-button/shuffle-layout.js.map +1 -0
- package/dist/components/alert-subsystem-counter/alert-subsystem-counter.css.js +113 -0
- package/dist/components/alert-subsystem-counter/alert-subsystem-counter.css.js.map +1 -0
- package/dist/components/alert-subsystem-counter/alert-subsystem-counter.d.ts +104 -0
- package/dist/components/alert-subsystem-counter/alert-subsystem-counter.d.ts.map +1 -0
- package/dist/components/alert-subsystem-counter/alert-subsystem-counter.js +79 -0
- package/dist/components/alert-subsystem-counter/alert-subsystem-counter.js.map +1 -0
- package/package.json +1 -1
- package/src/automation/hydraulic-check-valve/hydraulic-check-valve.css +3 -0
- package/src/automation/hydraulic-check-valve/hydraulic-check-valve.stories.ts +18 -0
- package/src/automation/hydraulic-check-valve/hydraulic-check-valve.ts +60 -0
- package/src/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.stories.ts +72 -0
- package/src/automation/hydraulic-valve-4-3/hydraulic-valve-4-3.ts +108 -0
- package/src/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.stories.ts +60 -0
- package/src/automation/hydraulic-valve-x-2/hydraulic-valve-x-2.ts +101 -0
- package/src/automation/shuffle-button/shuffle-button-base.ts +170 -0
- package/src/automation/shuffle-button/shuffle-button.css +136 -0
- package/src/automation/shuffle-button/shuffle-layout.spec.ts +44 -0
- package/src/automation/shuffle-button/shuffle-layout.ts +21 -0
- package/src/components/alert-subsystem-counter/alert-subsystem-counter.css +82 -0
- package/src/components/alert-subsystem-counter/alert-subsystem-counter.stories.ts +308 -0
- package/src/components/alert-subsystem-counter/alert-subsystem-counter.ts +137 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* ---- Slot grid ----
|
|
6
|
+
* The box is (2n-1) touch-target slots; the selected thumb always sits in the
|
|
7
|
+
* center slot, so the box never changes size with the selection. */
|
|
8
|
+
.shuffle {
|
|
9
|
+
--shuffle-slot-size: var(--global-size-spacing-touch-target-min);
|
|
10
|
+
--_shuffle-slot-count: 1;
|
|
11
|
+
--_shuffle-window-offset: 0;
|
|
12
|
+
position: relative; /* containing block for the sliding .window */
|
|
13
|
+
width: calc(var(--_shuffle-slot-count) * var(--shuffle-slot-size));
|
|
14
|
+
height: var(--shuffle-slot-size);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.shuffle.vertical {
|
|
18
|
+
width: var(--shuffle-slot-size);
|
|
19
|
+
height: calc(var(--_shuffle-slot-count) * var(--shuffle-slot-size));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* The window holds the n thumbs in logical order and slides by whole slots so
|
|
23
|
+
* the selected one lands in the center; the box above stays put. */
|
|
24
|
+
.window {
|
|
25
|
+
position: absolute; /* slides inside the fixed-size .shuffle box */
|
|
26
|
+
top: 0;
|
|
27
|
+
left: 0;
|
|
28
|
+
display: flex;
|
|
29
|
+
transform: translateX(
|
|
30
|
+
calc(var(--_shuffle-window-offset) * var(--shuffle-slot-size))
|
|
31
|
+
);
|
|
32
|
+
transition: transform 100ms ease-out; /* TODO(designer): Figma is WIP and specifies no motion */
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.shuffle.vertical .window {
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
transform: translateY(
|
|
38
|
+
calc(var(--_shuffle-window-offset) * var(--shuffle-slot-size))
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@media (prefers-reduced-motion: reduce) {
|
|
43
|
+
.window {
|
|
44
|
+
transition: none;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* The track is inset to the visual target height so it aligns with the thumbs'
|
|
49
|
+
* visible wrappers, not with the touch slots. */
|
|
50
|
+
.track {
|
|
51
|
+
@mixin style style=indent noClick=true;
|
|
52
|
+
position: absolute;
|
|
53
|
+
inset: calc(
|
|
54
|
+
(
|
|
55
|
+
var(--shuffle-slot-size) -
|
|
56
|
+
var(--global-size-spacing-visual-target-min)
|
|
57
|
+
) /
|
|
58
|
+
2
|
|
59
|
+
)
|
|
60
|
+
0;
|
|
61
|
+
border-radius: var(--global-border-radius-border-radius-base);
|
|
62
|
+
box-sizing: border-box; /* the mixin border must not grow the track past the slots */
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.shuffle.vertical .track {
|
|
66
|
+
inset: 0
|
|
67
|
+
calc(
|
|
68
|
+
(
|
|
69
|
+
var(--shuffle-slot-size) -
|
|
70
|
+
var(--global-size-spacing-visual-target-min)
|
|
71
|
+
) /
|
|
72
|
+
2
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* ---- Thumbs ----
|
|
77
|
+
* Two-layer pattern: the button is the touch target and focus-ring layer, the
|
|
78
|
+
* .visible-wrapper is the visual target. */
|
|
79
|
+
.thumb {
|
|
80
|
+
position: relative;
|
|
81
|
+
width: var(--shuffle-slot-size);
|
|
82
|
+
height: var(--shuffle-slot-size);
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
flex-shrink: 0; /* a slot never shrinks below the touch target */
|
|
87
|
+
padding: 0;
|
|
88
|
+
margin: 0;
|
|
89
|
+
border: none;
|
|
90
|
+
background: none;
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
button.thumb {
|
|
95
|
+
@mixin style style=flat visibleWrapperClass=.visible-wrapper;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.visible-wrapper {
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
width: 100%;
|
|
103
|
+
height: var(--global-size-spacing-visual-target-min);
|
|
104
|
+
box-sizing: border-box;
|
|
105
|
+
border-radius: var(--global-border-radius-border-radius-base);
|
|
106
|
+
color: var(--automation-device-secondary-color);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.thumb.selected {
|
|
110
|
+
cursor: default; /* clicking the selected position is a no-op */
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.thumb.selected .visible-wrapper {
|
|
114
|
+
background-color: var(--automation-pipe-primary-color);
|
|
115
|
+
border: 1px solid var(--automation-pipe-tertiary-color);
|
|
116
|
+
color: var(--automation-device-tertiary-color);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.shuffle.vertical .visible-wrapper {
|
|
120
|
+
width: var(--global-size-spacing-visual-target-min);
|
|
121
|
+
height: 100%;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.icon-container {
|
|
125
|
+
width: var(--global-size-spacing-icon-icon-size-regular);
|
|
126
|
+
height: var(--global-size-spacing-icon-icon-size-regular);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.shuffle.vertical .icon-container {
|
|
130
|
+
transform: rotate(-90deg); /* symbols are drawn for horizontal flow */
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.icon-container > * {
|
|
134
|
+
width: 100%;
|
|
135
|
+
height: 100%;
|
|
136
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {describe, expect, it} from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
clampPosition,
|
|
4
|
+
shuffleSlotCount,
|
|
5
|
+
shuffleWindowOffset,
|
|
6
|
+
} from './shuffle-layout.js';
|
|
7
|
+
|
|
8
|
+
describe('shuffleSlotCount', () => {
|
|
9
|
+
it('is 2n-1 so the selected thumb can sit center with all options on one side', () => {
|
|
10
|
+
expect(shuffleSlotCount(1)).toBe(1);
|
|
11
|
+
expect(shuffleSlotCount(2)).toBe(3);
|
|
12
|
+
expect(shuffleSlotCount(3)).toBe(5);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('clampPosition', () => {
|
|
17
|
+
it('passes through valid positions', () => {
|
|
18
|
+
expect(clampPosition(3, 0)).toBe(0);
|
|
19
|
+
expect(clampPosition(3, 2)).toBe(2);
|
|
20
|
+
});
|
|
21
|
+
it('clamps out-of-range and rounds non-integers', () => {
|
|
22
|
+
expect(clampPosition(3, -1)).toBe(0);
|
|
23
|
+
expect(clampPosition(3, 7)).toBe(2);
|
|
24
|
+
expect(clampPosition(3, 1.4)).toBe(1);
|
|
25
|
+
});
|
|
26
|
+
it('falls back to position 0 for NaN', () => {
|
|
27
|
+
expect(clampPosition(3, Number.NaN)).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('shuffleWindowOffset', () => {
|
|
32
|
+
it('offsets the window so the selected thumb lands in the center slot', () => {
|
|
33
|
+
expect(shuffleWindowOffset(3, 0)).toBe(2);
|
|
34
|
+
expect(shuffleWindowOffset(3, 1)).toBe(1);
|
|
35
|
+
expect(shuffleWindowOffset(3, 2)).toBe(0);
|
|
36
|
+
expect(shuffleWindowOffset(2, 0)).toBe(1);
|
|
37
|
+
expect(shuffleWindowOffset(2, 1)).toBe(0);
|
|
38
|
+
expect(shuffleWindowOffset(1, 0)).toBe(0);
|
|
39
|
+
});
|
|
40
|
+
it('clamps invalid selections', () => {
|
|
41
|
+
expect(shuffleWindowOffset(3, 9)).toBe(0);
|
|
42
|
+
expect(shuffleWindowOffset(3, -4)).toBe(2);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure layout math for the shuffle-button mechanism: a selector whose selected
|
|
3
|
+
* thumb always occupies the fixed center slot of a (2n-1)-slot row while the
|
|
4
|
+
* remaining option thumbs keep their logical order on either side.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function clampPosition(positionCount: number, position: number): number {
|
|
8
|
+
const rounded = Number.isNaN(position) ? 0 : Math.round(position);
|
|
9
|
+
return Math.min(Math.max(rounded, 0), positionCount - 1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function shuffleSlotCount(positionCount: number): number {
|
|
13
|
+
return 2 * positionCount - 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function shuffleWindowOffset(
|
|
17
|
+
positionCount: number,
|
|
18
|
+
selectedPosition: number
|
|
19
|
+
): number {
|
|
20
|
+
return positionCount - 1 - clampPosition(positionCount, selectedPosition);
|
|
21
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.frame {
|
|
6
|
+
box-sizing: border-box; /* the host width is the frame width, border included */
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
gap: 8px;
|
|
10
|
+
padding: 8px;
|
|
11
|
+
border-radius: 6px;
|
|
12
|
+
background: var(--container-section-color);
|
|
13
|
+
border: 1px solid var(--border-outline-color);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.frame.orientation-vertical {
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
align-items: stretch;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.leading-container {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex: 1 0 0; /* takes the width the badges leave over, so the label can truncate */
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: 4px;
|
|
26
|
+
min-width: 0; /* lets the label shrink below its text width */
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.icon {
|
|
30
|
+
flex-shrink: 0;
|
|
31
|
+
width: var(--global-size-spacing-icon-icon-size-regular);
|
|
32
|
+
height: var(--global-size-spacing-icon-icon-size-regular);
|
|
33
|
+
color: var(--on-indent-neutral-color);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.icon.no-icon {
|
|
37
|
+
display: none; /* collapses the flex gap too, so an iconless counter has no leading hole */
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.label {
|
|
41
|
+
@mixin font-body;
|
|
42
|
+
flex: 1 0 0;
|
|
43
|
+
min-width: 0; /* required for text-overflow to kick in inside a flex item */
|
|
44
|
+
padding-left: 4px;
|
|
45
|
+
color: var(--element-inactive-color);
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
white-space: nowrap;
|
|
48
|
+
text-overflow: ellipsis;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.frame.has-alert .label {
|
|
52
|
+
@mixin font-body-active;
|
|
53
|
+
color: var(--on-indent-active-color);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.trailing-container {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-shrink: 0; /* badges keep their size; the label is what gives way */
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 4px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.frame.orientation-horizontal .trailing-container {
|
|
64
|
+
justify-content: flex-end;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.frame.orientation-vertical .trailing-container {
|
|
68
|
+
align-self: flex-start; /* hugs its content under the label instead of stretching across the frame */
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.frame:not(.has-alert) .trailing-container {
|
|
72
|
+
justify-content: center;
|
|
73
|
+
/* same row height as the large badges it stands in for */
|
|
74
|
+
height: var(--ui-components-badge-min-size-large);
|
|
75
|
+
padding: 0 8px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.empty {
|
|
79
|
+
@mixin font-label;
|
|
80
|
+
color: var(--element-inactive-color);
|
|
81
|
+
white-space: nowrap;
|
|
82
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
|
+
import {html, nothing, type TemplateResult} from 'lit';
|
|
3
|
+
import {ifDefined} from 'lit/directives/if-defined.js';
|
|
4
|
+
import {
|
|
5
|
+
ObcAlertSubsystemCounter,
|
|
6
|
+
ObcAlertSubsystemCounterOrientation,
|
|
7
|
+
} from './alert-subsystem-counter.js';
|
|
8
|
+
import './alert-subsystem-counter.js';
|
|
9
|
+
import '../badge/badge.js';
|
|
10
|
+
import {BadgeType, BadgeVariant} from '../badge/badge.js';
|
|
11
|
+
import '../../icons/icon-placeholder.js';
|
|
12
|
+
|
|
13
|
+
const badges = html`
|
|
14
|
+
<obc-badge slot="badges" size="large" type="alarm" .number=${9}></obc-badge>
|
|
15
|
+
<obc-badge slot="badges" size="large" type="warning" .number=${4}></obc-badge>
|
|
16
|
+
<obc-badge slot="badges" size="large" type="caution" .number=${2}></obc-badge>
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const levelBadges = html`
|
|
20
|
+
<obc-badge
|
|
21
|
+
slot="badges"
|
|
22
|
+
size="large"
|
|
23
|
+
type=${BadgeType.levelCritical}
|
|
24
|
+
.number=${1}
|
|
25
|
+
></obc-badge>
|
|
26
|
+
<obc-badge
|
|
27
|
+
slot="badges"
|
|
28
|
+
size="large"
|
|
29
|
+
type=${BadgeType.levelHigh}
|
|
30
|
+
.number=${9}
|
|
31
|
+
></obc-badge>
|
|
32
|
+
<obc-badge
|
|
33
|
+
slot="badges"
|
|
34
|
+
size="large"
|
|
35
|
+
type=${BadgeType.levelMedium}
|
|
36
|
+
.number=${4}
|
|
37
|
+
></obc-badge>
|
|
38
|
+
<obc-badge
|
|
39
|
+
slot="badges"
|
|
40
|
+
size="large"
|
|
41
|
+
type=${BadgeType.levelLow}
|
|
42
|
+
.number=${2}
|
|
43
|
+
></obc-badge>
|
|
44
|
+
<obc-badge
|
|
45
|
+
slot="badges"
|
|
46
|
+
size="large"
|
|
47
|
+
type=${BadgeType.levelDiagnostic}
|
|
48
|
+
.number=${7}
|
|
49
|
+
></obc-badge>
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const iconBadges = html`
|
|
53
|
+
<obc-badge
|
|
54
|
+
slot="badges"
|
|
55
|
+
size="large"
|
|
56
|
+
type="alarm"
|
|
57
|
+
variant=${BadgeVariant.flat}
|
|
58
|
+
showIcon
|
|
59
|
+
.number=${9}
|
|
60
|
+
></obc-badge>
|
|
61
|
+
<obc-badge
|
|
62
|
+
slot="badges"
|
|
63
|
+
size="large"
|
|
64
|
+
type="warning"
|
|
65
|
+
variant=${BadgeVariant.flat}
|
|
66
|
+
showIcon
|
|
67
|
+
.number=${4}
|
|
68
|
+
></obc-badge>
|
|
69
|
+
<obc-badge
|
|
70
|
+
slot="badges"
|
|
71
|
+
size="large"
|
|
72
|
+
type="caution"
|
|
73
|
+
variant=${BadgeVariant.flat}
|
|
74
|
+
showIcon
|
|
75
|
+
.number=${2}
|
|
76
|
+
></obc-badge>
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
type CounterArgs = Pick<
|
|
80
|
+
ObcAlertSubsystemCounter,
|
|
81
|
+
'label' | 'orientation' | 'hasAlert' | 'emptyText'
|
|
82
|
+
>;
|
|
83
|
+
|
|
84
|
+
// `emptyText` is gated on `hasAlert==false`, so Storybook drops it from the
|
|
85
|
+
// args while `hasAlert` is on; attribute bindings with `ifDefined` leave the
|
|
86
|
+
// element's own default in place instead of writing `undefined` into it.
|
|
87
|
+
const renderCounter = (
|
|
88
|
+
args: CounterArgs,
|
|
89
|
+
options: {width?: string; withIcon?: boolean; badges?: TemplateResult} = {}
|
|
90
|
+
) =>
|
|
91
|
+
html`<div style="width:${options.width ?? '191px'}">
|
|
92
|
+
<obc-alert-subsystem-counter
|
|
93
|
+
label=${ifDefined(args.label)}
|
|
94
|
+
.orientation=${args.orientation}
|
|
95
|
+
.hasAlert=${args.hasAlert}
|
|
96
|
+
emptytext=${ifDefined(args.emptyText)}
|
|
97
|
+
>
|
|
98
|
+
${options.withIcon === false
|
|
99
|
+
? nothing
|
|
100
|
+
: html`<obi-placeholder slot="icon"></obi-placeholder>`}
|
|
101
|
+
${options.badges ?? badges}
|
|
102
|
+
</obc-alert-subsystem-counter>
|
|
103
|
+
</div>`;
|
|
104
|
+
|
|
105
|
+
const meta: Meta<typeof ObcAlertSubsystemCounter> = {
|
|
106
|
+
title: 'Application Components/Alerts/Alert Subsystem Counter',
|
|
107
|
+
tags: ['6.0', 'beta'],
|
|
108
|
+
component: 'obc-alert-subsystem-counter',
|
|
109
|
+
args: {
|
|
110
|
+
label: 'Label',
|
|
111
|
+
orientation: ObcAlertSubsystemCounterOrientation.Horizontal,
|
|
112
|
+
hasAlert: true,
|
|
113
|
+
emptyText: 'No alerts',
|
|
114
|
+
},
|
|
115
|
+
argTypes: {
|
|
116
|
+
orientation: {
|
|
117
|
+
control: {type: 'inline-radio'},
|
|
118
|
+
options: Object.values(ObcAlertSubsystemCounterOrientation),
|
|
119
|
+
},
|
|
120
|
+
hasAlert: {control: {type: 'boolean'}},
|
|
121
|
+
label: {control: {type: 'text'}},
|
|
122
|
+
emptyText: {control: {type: 'text'}},
|
|
123
|
+
},
|
|
124
|
+
render: (args) => renderCounter(args),
|
|
125
|
+
} satisfies Meta<ObcAlertSubsystemCounter>;
|
|
126
|
+
|
|
127
|
+
export default meta;
|
|
128
|
+
type Story = StoryObj<ObcAlertSubsystemCounter>;
|
|
129
|
+
|
|
130
|
+
export const Default: Story = {};
|
|
131
|
+
|
|
132
|
+
export const Abbreviation: Story = {
|
|
133
|
+
args: {label: 'ABC'},
|
|
134
|
+
render: (args) => renderCounter(args, {width: '172px'}),
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const NoAlerts: Story = {
|
|
138
|
+
args: {hasAlert: false},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const Vertical: Story = {
|
|
142
|
+
args: {orientation: ObcAlertSubsystemCounterOrientation.Vertical},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const VerticalNoAlerts: Story = {
|
|
146
|
+
args: {
|
|
147
|
+
orientation: ObcAlertSubsystemCounterOrientation.Vertical,
|
|
148
|
+
hasAlert: false,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export const AbbreviationVertical: Story = {
|
|
153
|
+
args: {
|
|
154
|
+
label: 'ABC',
|
|
155
|
+
orientation: ObcAlertSubsystemCounterOrientation.Vertical,
|
|
156
|
+
},
|
|
157
|
+
render: (args) => renderCounter(args, {width: 'fit-content'}),
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const WithoutIcon: Story = {
|
|
161
|
+
render: (args) => renderCounter(args, {withIcon: false}),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const LongLabel: Story = {
|
|
165
|
+
args: {label: 'Auxiliary cooling water system'},
|
|
166
|
+
parameters: {
|
|
167
|
+
docs: {
|
|
168
|
+
description: {
|
|
169
|
+
story:
|
|
170
|
+
'The label is the only element that gives way: it truncates with an ellipsis while the icon and badges keep their size.',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const LevelSeverities: Story = {
|
|
177
|
+
render: (args) =>
|
|
178
|
+
renderCounter(args, {width: 'fit-content', badges: levelBadges}),
|
|
179
|
+
parameters: {
|
|
180
|
+
docs: {
|
|
181
|
+
description: {
|
|
182
|
+
story:
|
|
183
|
+
'The badge `type` accepts the whole `AlertType` vocabulary, including the `level-*` family. Slot them highest severity first, in `ALERT_SEVERITY_PRIORITY` order.',
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export const WithBadgeIcons: Story = {
|
|
190
|
+
render: (args) =>
|
|
191
|
+
renderCounter(args, {width: 'fit-content', badges: iconBadges}),
|
|
192
|
+
parameters: {
|
|
193
|
+
docs: {
|
|
194
|
+
description: {
|
|
195
|
+
story:
|
|
196
|
+
'Any `obc-badge` configuration works in the `badges` slot — here the `flat` variant with `showIcon` so each count carries its severity symbol.',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
type OverviewEntry = {
|
|
203
|
+
label: string;
|
|
204
|
+
hasAlert: boolean;
|
|
205
|
+
badges?: TemplateResult;
|
|
206
|
+
withIcon?: boolean;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const overview: OverviewEntry[] = [
|
|
210
|
+
{
|
|
211
|
+
label: 'Propulsion',
|
|
212
|
+
hasAlert: true,
|
|
213
|
+
badges: html`<obc-badge
|
|
214
|
+
slot="badges"
|
|
215
|
+
size="large"
|
|
216
|
+
type="alarm"
|
|
217
|
+
.number=${2}
|
|
218
|
+
></obc-badge>
|
|
219
|
+
<obc-badge
|
|
220
|
+
slot="badges"
|
|
221
|
+
size="large"
|
|
222
|
+
type="warning"
|
|
223
|
+
.number=${1}
|
|
224
|
+
></obc-badge>`,
|
|
225
|
+
},
|
|
226
|
+
{label: 'Navigation', hasAlert: false},
|
|
227
|
+
{
|
|
228
|
+
label: 'Power',
|
|
229
|
+
hasAlert: true,
|
|
230
|
+
badges: html`<obc-badge
|
|
231
|
+
slot="badges"
|
|
232
|
+
size="large"
|
|
233
|
+
type="caution"
|
|
234
|
+
.number=${3}
|
|
235
|
+
></obc-badge>`,
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
label: 'HVAC',
|
|
239
|
+
hasAlert: true,
|
|
240
|
+
badges: html`<obc-badge
|
|
241
|
+
slot="badges"
|
|
242
|
+
size="large"
|
|
243
|
+
type=${BadgeType.levelHigh}
|
|
244
|
+
.number=${9}
|
|
245
|
+
></obc-badge>
|
|
246
|
+
<obc-badge
|
|
247
|
+
slot="badges"
|
|
248
|
+
size="large"
|
|
249
|
+
type=${BadgeType.levelMedium}
|
|
250
|
+
.number=${4}
|
|
251
|
+
></obc-badge>
|
|
252
|
+
<obc-badge
|
|
253
|
+
slot="badges"
|
|
254
|
+
size="large"
|
|
255
|
+
type=${BadgeType.levelLow}
|
|
256
|
+
.number=${2}
|
|
257
|
+
></obc-badge>`,
|
|
258
|
+
},
|
|
259
|
+
{label: 'Cargo', hasAlert: false, withIcon: false},
|
|
260
|
+
{
|
|
261
|
+
label: 'Fire detection',
|
|
262
|
+
hasAlert: true,
|
|
263
|
+
withIcon: false,
|
|
264
|
+
badges: html`<obc-badge
|
|
265
|
+
slot="badges"
|
|
266
|
+
size="large"
|
|
267
|
+
type="alarm"
|
|
268
|
+
.number=${12}
|
|
269
|
+
></obc-badge>`,
|
|
270
|
+
},
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
export const Overview: Story = {
|
|
274
|
+
render: (args) =>
|
|
275
|
+
html`<div
|
|
276
|
+
style="display:grid;grid-template-columns:repeat(2, 240px);gap:8px"
|
|
277
|
+
>
|
|
278
|
+
${overview.map((entry) =>
|
|
279
|
+
renderCounter(
|
|
280
|
+
{...args, label: entry.label, hasAlert: entry.hasAlert},
|
|
281
|
+
{width: '240px', withIcon: entry.withIcon, badges: entry.badges}
|
|
282
|
+
)
|
|
283
|
+
)}
|
|
284
|
+
</div>`,
|
|
285
|
+
parameters: {
|
|
286
|
+
docs: {
|
|
287
|
+
description: {
|
|
288
|
+
story:
|
|
289
|
+
'A status overview composes one counter per subsystem in a grid. Counters with and without alerts, with and without icons, and with different badge families share one row height.',
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export const OverviewVertical: Story = {
|
|
296
|
+
args: {orientation: ObcAlertSubsystemCounterOrientation.Vertical},
|
|
297
|
+
render: (args) =>
|
|
298
|
+
html`<div
|
|
299
|
+
style="display:grid;grid-template-columns:repeat(3, 120px);gap:8px;align-items:stretch"
|
|
300
|
+
>
|
|
301
|
+
${overview.map((entry) =>
|
|
302
|
+
renderCounter(
|
|
303
|
+
{...args, label: entry.label, hasAlert: entry.hasAlert},
|
|
304
|
+
{width: '120px', withIcon: entry.withIcon, badges: entry.badges}
|
|
305
|
+
)
|
|
306
|
+
)}
|
|
307
|
+
</div>`,
|
|
308
|
+
};
|