@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.155 → 2.0.0-next.157
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/LICENSE-AGPL.txt +661 -0
- package/LICENSE-APACHE.txt +177 -0
- package/LICENSE.txt +35 -0
- package/bundle/openbridge-webcomponents.bundle.js +3502 -3298
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +193 -31
- package/dist/automation/transmitter/transmitter-shared.d.ts +11 -0
- package/dist/automation/transmitter/transmitter-shared.d.ts.map +1 -0
- package/dist/automation/transmitter/transmitter-shared.js +16 -0
- package/dist/automation/transmitter/transmitter-shared.js.map +1 -0
- package/dist/automation/transmitter/transmitter.css.js +12 -1
- package/dist/automation/transmitter/transmitter.css.js.map +1 -1
- package/dist/automation/transmitter/transmitter.d.ts +9 -10
- package/dist/automation/transmitter/transmitter.d.ts.map +1 -1
- package/dist/automation/transmitter/transmitter.js +12 -15
- package/dist/automation/transmitter/transmitter.js.map +1 -1
- package/dist/automation/transmitter-button/transmitter-button.css.js +18 -42
- package/dist/automation/transmitter-button/transmitter-button.css.js.map +1 -1
- package/dist/automation/transmitter-button/transmitter-button.d.ts +31 -21
- package/dist/automation/transmitter-button/transmitter-button.d.ts.map +1 -1
- package/dist/automation/transmitter-button/transmitter-button.js +37 -39
- package/dist/automation/transmitter-button/transmitter-button.js.map +1 -1
- package/dist/automation/transmitter-stack/transmitter-stack.css.js +144 -0
- package/dist/automation/transmitter-stack/transmitter-stack.css.js.map +1 -0
- package/dist/automation/transmitter-stack/transmitter-stack.d.ts +93 -0
- package/dist/automation/transmitter-stack/transmitter-stack.d.ts.map +1 -0
- package/dist/automation/transmitter-stack/transmitter-stack.js +97 -0
- package/dist/automation/transmitter-stack/transmitter-stack.js.map +1 -0
- package/dist/building-blocks/readout-block/readout-block.d.ts +1 -1
- package/dist/building-blocks/readout-block/readout-block.js.map +1 -1
- package/dist/components/textarea-field/textarea-field.css.js +0 -2
- package/dist/components/textarea-field/textarea-field.css.js.map +1 -1
- package/dist/components/textbox/textbox.d.ts +1 -1
- package/dist/components/textbox/textbox.js.map +1 -1
- package/dist/navigation-instruments/readout/readout.css.js +2 -23
- package/dist/navigation-instruments/readout/readout.css.js.map +1 -1
- package/dist/navigation-instruments/readout/readout.d.ts +1 -1
- package/dist/navigation-instruments/readout/readout.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +1 -0
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js +3 -0
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
- package/package.json +6 -3
- package/script/prepare-full-bundle.ts +5 -0
- package/src/automation/transmitter/transmitter-shared.ts +16 -0
- package/src/automation/transmitter/transmitter.css +3 -71
- package/src/automation/transmitter/transmitter.stories.ts +13 -1
- package/src/automation/transmitter/transmitter.ts +19 -16
- package/src/automation/transmitter-button/transmitter-button.css +11 -36
- package/src/automation/transmitter-button/transmitter-button.stories.ts +3 -1
- package/src/automation/transmitter-button/transmitter-button.ts +62 -66
- package/src/automation/transmitter-stack/transmitter-stack.css +56 -0
- package/src/automation/transmitter-stack/transmitter-stack.spec.ts +210 -0
- package/src/automation/transmitter-stack/transmitter-stack.stories.ts +149 -0
- package/src/automation/transmitter-stack/transmitter-stack.ts +172 -0
- package/src/building-blocks/readout-block/readout-block.stories.ts +1 -1
- package/src/building-blocks/readout-block/readout-block.ts +1 -1
- package/src/components/textarea-field/textarea-field.css +1 -8
- package/src/components/textbox/textbox.stories.ts +1 -1
- package/src/components/textbox/textbox.ts +1 -1
- package/src/mixins/transmitter.css +90 -0
- package/src/mixins/visually-hidden.css +10 -0
- package/src/navigation-instruments/readout/readout.css +2 -22
- package/src/navigation-instruments/readout/readout.spec.ts +74 -1
- package/src/navigation-instruments/readout/readout.stories.ts +1 -1
- package/src/navigation-instruments/readout/readout.ts +1 -1
- package/src/navigation-instruments/readout-list-item/readout-list-item.css +1 -0
- package/src/navigation-instruments/readout-list-item/readout-list-item.stories.ts +1 -1
- package/src/navigation-instruments/readout-list-item/readout-list-item.ts +12 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
|
+
import {html} from 'lit';
|
|
3
|
+
import {
|
|
4
|
+
ObcTransmitterStack,
|
|
5
|
+
type TransmitterStackValue,
|
|
6
|
+
} from './transmitter-stack.js';
|
|
7
|
+
import './transmitter-stack.js';
|
|
8
|
+
import {TransmitterOrientation} from '../transmitter/transmitter.js';
|
|
9
|
+
import {crossDecorator} from '../../storybook-util.js';
|
|
10
|
+
import '../../icons/icon-temperature-air.js';
|
|
11
|
+
import '../../icons/icon-pressure.js';
|
|
12
|
+
import '../../icons/icon-placeholder.js';
|
|
13
|
+
import '../horizontal-line/horizontal-line.js';
|
|
14
|
+
import {LineMedium, LineType} from '../index.js';
|
|
15
|
+
|
|
16
|
+
const designValues: TransmitterStackValue[] = [
|
|
17
|
+
{
|
|
18
|
+
value: 12.3,
|
|
19
|
+
unit: 'C',
|
|
20
|
+
hasDegree: true,
|
|
21
|
+
idTag: '#0000',
|
|
22
|
+
iconSlotName: 'temperature',
|
|
23
|
+
},
|
|
24
|
+
{value: 12.3, unit: 'mVs', idTag: '#0000', iconSlotName: 'pressure'},
|
|
25
|
+
{value: 12.3, unit: 'm', idTag: '#0000', iconSlotName: 'level'},
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const meta: Meta<typeof ObcTransmitterStack> = {
|
|
29
|
+
title: 'Automation/Transmitter/Transmitter Stack',
|
|
30
|
+
tags: ['autodocs', 'experimental'],
|
|
31
|
+
component: 'obc-transmitter-stack',
|
|
32
|
+
decorators: [crossDecorator],
|
|
33
|
+
args: {
|
|
34
|
+
orientation: TransmitterOrientation.bottom,
|
|
35
|
+
lineType: LineType.fluid,
|
|
36
|
+
values: designValues,
|
|
37
|
+
},
|
|
38
|
+
argTypes: {
|
|
39
|
+
orientation: {
|
|
40
|
+
options: [
|
|
41
|
+
TransmitterOrientation.top,
|
|
42
|
+
TransmitterOrientation.right,
|
|
43
|
+
TransmitterOrientation.bottom,
|
|
44
|
+
TransmitterOrientation.left,
|
|
45
|
+
],
|
|
46
|
+
control: {type: 'radio'},
|
|
47
|
+
},
|
|
48
|
+
lineType: {
|
|
49
|
+
options: [
|
|
50
|
+
LineType.air,
|
|
51
|
+
LineType.connector,
|
|
52
|
+
LineType.electric,
|
|
53
|
+
LineType.fluid,
|
|
54
|
+
],
|
|
55
|
+
control: {type: 'radio'},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
} satisfies Meta<ObcTransmitterStack>;
|
|
59
|
+
|
|
60
|
+
export default meta;
|
|
61
|
+
type Story = StoryObj<ObcTransmitterStack>;
|
|
62
|
+
|
|
63
|
+
function renderComponent(args: ObcTransmitterStack) {
|
|
64
|
+
return html`
|
|
65
|
+
<obc-transmitter-stack
|
|
66
|
+
.orientation=${args.orientation}
|
|
67
|
+
.lineType=${args.lineType}
|
|
68
|
+
.values=${args.values}
|
|
69
|
+
>
|
|
70
|
+
<obi-temperature-air slot="temperature"></obi-temperature-air>
|
|
71
|
+
<obi-pressure slot="pressure"></obi-pressure>
|
|
72
|
+
<obi-placeholder slot="level"></obi-placeholder>
|
|
73
|
+
</obc-transmitter-stack>
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const Bottom: Story = {
|
|
78
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const Top: Story = {
|
|
82
|
+
args: {orientation: TransmitterOrientation.top},
|
|
83
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const Left: Story = {
|
|
87
|
+
args: {orientation: TransmitterOrientation.left},
|
|
88
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const Right: Story = {
|
|
92
|
+
args: {orientation: TransmitterOrientation.right},
|
|
93
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const WithoutIdTags: Story = {
|
|
97
|
+
args: {
|
|
98
|
+
values: designValues.map((entry) => ({...entry, idTag: undefined})),
|
|
99
|
+
},
|
|
100
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const MixedIdTags: Story = {
|
|
104
|
+
args: {
|
|
105
|
+
values: designValues.map((entry, index) => ({
|
|
106
|
+
...entry,
|
|
107
|
+
idTag: index === 0 ? '#0000' : undefined,
|
|
108
|
+
})),
|
|
109
|
+
},
|
|
110
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const MissingValues: Story = {
|
|
114
|
+
args: {
|
|
115
|
+
values: [
|
|
116
|
+
{...designValues[0], value: null, maxDigits: 3, hintedZeros: true},
|
|
117
|
+
{...designValues[1], value: NaN},
|
|
118
|
+
designValues[2],
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
render: (args) => renderComponent(args as ObcTransmitterStack),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const UsageWithPipe: Story = {
|
|
125
|
+
render: (args) => html`
|
|
126
|
+
<style>
|
|
127
|
+
.canvas {
|
|
128
|
+
position: relative;
|
|
129
|
+
width: 400px;
|
|
130
|
+
height: 400px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#line-bottom {
|
|
134
|
+
position: absolute;
|
|
135
|
+
top: 0;
|
|
136
|
+
left: calc(-2.5 * 24px);
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
139
|
+
<div class="canvas">
|
|
140
|
+
${renderComponent(args as ObcTransmitterStack)}
|
|
141
|
+
<obc-horizontal-line
|
|
142
|
+
.medium=${LineMedium.water}
|
|
143
|
+
.lineType=${args.lineType || LineType.fluid}
|
|
144
|
+
length="5"
|
|
145
|
+
id="line-bottom"
|
|
146
|
+
></obc-horizontal-line>
|
|
147
|
+
</div>
|
|
148
|
+
`,
|
|
149
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import {LitElement, html, nothing, unsafeCSS} from 'lit';
|
|
2
|
+
import {property} from 'lit/decorators.js';
|
|
3
|
+
import {classMap} from 'lit/directives/class-map.js';
|
|
4
|
+
import componentStyle from './transmitter-stack.css?inline';
|
|
5
|
+
import {customElement} from '../../decorator.js';
|
|
6
|
+
import {LineType} from '../index.js';
|
|
7
|
+
import {
|
|
8
|
+
TransmitterOrientation,
|
|
9
|
+
transmitterLeaderOffset,
|
|
10
|
+
} from '../transmitter/transmitter-shared.js';
|
|
11
|
+
import {TransmitterButtonVariant} from '../transmitter-button/transmitter-button.js';
|
|
12
|
+
import '../transmitter-button/transmitter-button.js';
|
|
13
|
+
|
|
14
|
+
/** One reading of a transmitter stack. */
|
|
15
|
+
export interface TransmitterStackValue {
|
|
16
|
+
/** The reading; `null` or `NaN` renders the unavailable dash. */
|
|
17
|
+
value: number | null;
|
|
18
|
+
unit?: string;
|
|
19
|
+
/** Identifier shown under the segment (above it for `top`) and read as part of its name. */
|
|
20
|
+
idTag?: string;
|
|
21
|
+
/** Decimal precision; `1` when the key is omitted. */
|
|
22
|
+
fractionDigits?: number;
|
|
23
|
+
/** Integer digits to reserve; `0` when the key is omitted. */
|
|
24
|
+
maxDigits?: number;
|
|
25
|
+
hintedZeros?: boolean;
|
|
26
|
+
hasSignSpacer?: boolean;
|
|
27
|
+
/** Show a degree column between the value and the unit (e.g. `12.3°` then `C`). */
|
|
28
|
+
hasDegree?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Name of the light-DOM slot projected as this segment's icon. Unique within
|
|
31
|
+
* the stack: an element is projected once, so a repeated name leaves later
|
|
32
|
+
* segments with an empty icon.
|
|
33
|
+
*/
|
|
34
|
+
iconSlotName?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TransmitterStackValueClickDetail {
|
|
38
|
+
index: number;
|
|
39
|
+
value: TransmitterStackValue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `<obc-transmitter-stack>` – Several transmitter readings side by side in one
|
|
44
|
+
* joined chip, attached to a line by a single leader line.
|
|
45
|
+
*
|
|
46
|
+
* Each entry of `values` renders an `<obc-transmitter-button>` segment with its
|
|
47
|
+
* own icon, value, unit and id tag. The segments take equal widths, set by the
|
|
48
|
+
* widest reading, and share their borders. Positioning and the leader line
|
|
49
|
+
* follow `<obc-transmitter>`.
|
|
50
|
+
*
|
|
51
|
+
* ### Features / Variants
|
|
52
|
+
* - **`orientation`** – `top`, `right`, `bottom`, `left`; the edge the leader
|
|
53
|
+
* line attaches to. `top` places the id tags above the chip.
|
|
54
|
+
* - **Values** – `value` and `unit` per segment. `idTag` adds a label row under
|
|
55
|
+
* every segment once any value has one, so the chip stays aligned.
|
|
56
|
+
* - **Formatting** – per value `fractionDigits` (default `1`), `maxDigits`
|
|
57
|
+
* (default `0`), `hintedZeros`, `hasSignSpacer` and `hasDegree`, formatted like
|
|
58
|
+
* `<obc-transmitter-button>`. An omitted key takes its default; a key set to
|
|
59
|
+
* `null`, `undefined` or `NaN` renders the reading as the unavailable dash.
|
|
60
|
+
* - **Icons** – `iconSlotName` projects the light-DOM element with that slot
|
|
61
|
+
* name as the segment's icon; names must be unique within the stack. The
|
|
62
|
+
* name is chosen per value, so it carries no `@slot` tag (the wrapper
|
|
63
|
+
* generator needs literal names).
|
|
64
|
+
* - **Accessible name** – each segment is a native button named by its
|
|
65
|
+
* reading, unit and `idTag`; the visible tag is hidden from assistive
|
|
66
|
+
* technology so it is not read twice.
|
|
67
|
+
* - **Empty** – with no `values` nothing renders, leader line included.
|
|
68
|
+
*
|
|
69
|
+
* ### Usage Guidelines
|
|
70
|
+
* Use when one source reports several readings that share one leader line. For
|
|
71
|
+
* a single reading, a tag pill or a trend graph, use `<obc-transmitter>`. Each
|
|
72
|
+
* segment's hit area is `<obc-transmitter-button>`'s chip (24 px high), below
|
|
73
|
+
* the 48 px touch-target token; see its design note.
|
|
74
|
+
*
|
|
75
|
+
* ### Slots
|
|
76
|
+
* | Slot Name | Conditions | Purpose |
|
|
77
|
+
* |------------------|---------------------------------|-------------------------------|
|
|
78
|
+
* | `<iconSlotName>` | a value declares `iconSlotName` | Icon in that value's segment. |
|
|
79
|
+
*
|
|
80
|
+
* @property orientation - Edge of the chip the leader line attaches to.
|
|
81
|
+
* @property lineType - Line the transmitter sits on; offsets the leader line by half its stroke.
|
|
82
|
+
* @property values - One segment per entry, in order.
|
|
83
|
+
* @fires {CustomEvent<TransmitterStackValueClickDetail>} value-click - Fired when a segment is activated, with its value and index.
|
|
84
|
+
* @fires click - Fired when any segment is clicked; `value-click` tells which.
|
|
85
|
+
* @experimental
|
|
86
|
+
*/
|
|
87
|
+
@customElement('obc-transmitter-stack')
|
|
88
|
+
export class ObcTransmitterStack extends LitElement {
|
|
89
|
+
@property({type: String}) orientation: TransmitterOrientation =
|
|
90
|
+
TransmitterOrientation.bottom;
|
|
91
|
+
@property({type: String}) lineType: LineType | undefined = undefined;
|
|
92
|
+
@property({type: Array}) values: TransmitterStackValue[] = [];
|
|
93
|
+
|
|
94
|
+
private handleValueClick(index: number, value: TransmitterStackValue): void {
|
|
95
|
+
this.dispatchEvent(
|
|
96
|
+
new CustomEvent<TransmitterStackValueClickDetail>('value-click', {
|
|
97
|
+
detail: {index, value},
|
|
98
|
+
bubbles: true,
|
|
99
|
+
composed: true,
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private renderValue(
|
|
105
|
+
entry: TransmitterStackValue,
|
|
106
|
+
index: number,
|
|
107
|
+
hasIdTags: boolean
|
|
108
|
+
) {
|
|
109
|
+
// `in`, not `??` alone: a key that is present but empty is a failed
|
|
110
|
+
// runtime write and must reach the block as missing (NaN renders the dash,
|
|
111
|
+
// readout-components.md § 2).
|
|
112
|
+
return html`
|
|
113
|
+
<div class="cell" part="cell">
|
|
114
|
+
<obc-transmitter-button
|
|
115
|
+
class="segment"
|
|
116
|
+
.variant=${TransmitterButtonVariant.value}
|
|
117
|
+
.value=${entry.value}
|
|
118
|
+
.unit=${entry.unit ?? ''}
|
|
119
|
+
.fractionDigits=${'fractionDigits' in entry
|
|
120
|
+
? (entry.fractionDigits ?? NaN)
|
|
121
|
+
: 1}
|
|
122
|
+
.maxDigits=${'maxDigits' in entry ? (entry.maxDigits ?? NaN) : 0}
|
|
123
|
+
.hintedZeros=${entry.hintedZeros ?? false}
|
|
124
|
+
.hasSignSpacer=${entry.hasSignSpacer ?? false}
|
|
125
|
+
.hasDegree=${entry.hasDegree ?? false}
|
|
126
|
+
.hasIcon=${Boolean(entry.iconSlotName)}
|
|
127
|
+
.idTag=${entry.idTag ?? ''}
|
|
128
|
+
@click=${() => this.handleValueClick(index, entry)}
|
|
129
|
+
>
|
|
130
|
+
${entry.iconSlotName
|
|
131
|
+
? html`<slot name=${entry.iconSlotName} slot="icon"></slot>`
|
|
132
|
+
: nothing}
|
|
133
|
+
</obc-transmitter-button>
|
|
134
|
+
${hasIdTags
|
|
135
|
+
? html`<div class="id-tag" aria-hidden="true">
|
|
136
|
+
${entry.idTag ?? ''}
|
|
137
|
+
</div>`
|
|
138
|
+
: nothing}
|
|
139
|
+
</div>
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
override render() {
|
|
144
|
+
if (this.values.length === 0) {
|
|
145
|
+
return nothing;
|
|
146
|
+
}
|
|
147
|
+
const hasIdTags = this.values.some((entry) => Boolean(entry.idTag));
|
|
148
|
+
return html`
|
|
149
|
+
<div
|
|
150
|
+
class=${classMap({
|
|
151
|
+
transmitter: true,
|
|
152
|
+
[`orientation-${this.orientation}`]: true,
|
|
153
|
+
})}
|
|
154
|
+
style="--offset: ${transmitterLeaderOffset(this.lineType)}px;"
|
|
155
|
+
>
|
|
156
|
+
<div class="values" part="values">
|
|
157
|
+
${this.values.map((entry, index) =>
|
|
158
|
+
this.renderValue(entry, index, hasIdTags)
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static override styles = unsafeCSS(componentStyle);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
declare global {
|
|
169
|
+
interface HTMLElementTagNameMap {
|
|
170
|
+
'obc-transmitter-stack': ObcTransmitterStack;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -122,7 +122,7 @@ function renderShowcase(cards: ShowcaseCard[]) {
|
|
|
122
122
|
|
|
123
123
|
const meta = {
|
|
124
124
|
title: 'Building Blocks/Readout Block',
|
|
125
|
-
tags: ['autodocs', '6.0'
|
|
125
|
+
tags: ['autodocs', '6.0'],
|
|
126
126
|
component: 'obc-readout-block',
|
|
127
127
|
decorators: [themedDecorator],
|
|
128
128
|
parameters: {
|
|
@@ -201,7 +201,7 @@ export enum ReadoutBlockHidePhase {
|
|
|
201
201
|
* @csspart block-text - The `obc-textbox` rendering the number.
|
|
202
202
|
* @csspart block-icon - The leading marker-icon container.
|
|
203
203
|
* @csspart degree - The trailing degree-glyph column.
|
|
204
|
-
* @
|
|
204
|
+
* @stable
|
|
205
205
|
*/
|
|
206
206
|
@customElement('obc-readout-block')
|
|
207
207
|
export class ObcReadoutBlock extends LitElement {
|
|
@@ -325,13 +325,6 @@ obc-audio-recording-item {
|
|
|
325
325
|
--on-normal-neutral-color: var(--element-inactive-color);
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
-
/* Visually hidden but accessible to screen readers */
|
|
329
328
|
.visually-hidden {
|
|
330
|
-
|
|
331
|
-
clip-path: inset(50%);
|
|
332
|
-
height: 1px;
|
|
333
|
-
overflow: hidden;
|
|
334
|
-
position: absolute;
|
|
335
|
-
white-space: nowrap;
|
|
336
|
-
width: 1px;
|
|
329
|
+
@mixin visually-hidden;
|
|
337
330
|
}
|
|
@@ -15,7 +15,7 @@ interface TextboxStoryArgs extends Partial<ObcTextbox> {
|
|
|
15
15
|
|
|
16
16
|
const meta: Meta<TextboxStoryArgs> = {
|
|
17
17
|
title: 'Building Blocks/Textbox',
|
|
18
|
-
tags: ['autodocs', '6.0'
|
|
18
|
+
tags: ['autodocs', '6.0'],
|
|
19
19
|
component: 'obc-textbox',
|
|
20
20
|
args: {
|
|
21
21
|
size: ObcTextboxSize.m,
|
|
@@ -66,7 +66,7 @@ export enum ObcTextboxFontWeight {
|
|
|
66
66
|
*
|
|
67
67
|
* @slot - The visible text content.
|
|
68
68
|
* @slot length - Reserves a minimum width based on its content width.
|
|
69
|
-
* @
|
|
69
|
+
* @stable
|
|
70
70
|
*/
|
|
71
71
|
@customElement('obc-textbox')
|
|
72
72
|
export class ObcTextbox extends LitElement {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* obc-transmitter and obc-transmitter-stack attach to a line the same way;
|
|
2
|
+
what they share lives here. */
|
|
3
|
+
|
|
4
|
+
/* Leader line and anchor transform. Apply on the element that carries the
|
|
5
|
+
`orientation-*` class and `--offset` (half the line's stroke width). */
|
|
6
|
+
@define-mixin transmitter-leader {
|
|
7
|
+
position: relative;
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
width: fit-content;
|
|
12
|
+
|
|
13
|
+
&.orientation-bottom {
|
|
14
|
+
padding-top: 8px;
|
|
15
|
+
top: calc(1px + var(--offset));
|
|
16
|
+
transform: translateX(-50%);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&.orientation-top {
|
|
20
|
+
padding-bottom: 8px;
|
|
21
|
+
transform: translate(-50%, calc(-100% - 1px - var(--offset)));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&.orientation-left {
|
|
25
|
+
padding-right: 8px;
|
|
26
|
+
transform: translate(calc(-100% - 4px - var(--offset)), -50%);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.orientation-right {
|
|
30
|
+
padding-left: 8px;
|
|
31
|
+
transform: translateY(-50%);
|
|
32
|
+
right: calc(-4px - var(--offset));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&::before {
|
|
36
|
+
content: "";
|
|
37
|
+
display: block;
|
|
38
|
+
position: absolute;
|
|
39
|
+
border: var(--normal-enabled-border-color) solid 1px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&.orientation-bottom::before,
|
|
43
|
+
&.orientation-top::before {
|
|
44
|
+
width: 0;
|
|
45
|
+
height: 8px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.orientation-bottom::before {
|
|
49
|
+
top: -1px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&.orientation-top::before {
|
|
53
|
+
bottom: -1px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&.orientation-left::before,
|
|
57
|
+
&.orientation-right::before {
|
|
58
|
+
height: 0;
|
|
59
|
+
width: 8px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&.orientation-left::before {
|
|
63
|
+
right: -4px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&.orientation-right::before {
|
|
67
|
+
left: -4px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Left/right anchor on the chip row's middle (Figma 25656:45233), so the id
|
|
71
|
+
tag hangs below out of flow; its parent must be the containing block. */
|
|
72
|
+
&:is(.orientation-left, .orientation-right):not(.has-alert) .id-tag {
|
|
73
|
+
position: absolute;
|
|
74
|
+
top: calc(100% + 2px);
|
|
75
|
+
left: 50%;
|
|
76
|
+
transform: translateX(-50%);
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@define-mixin transmitter-id-tag {
|
|
82
|
+
color: var(--element-neutral-color);
|
|
83
|
+
font-variant-numeric: lining-nums tabular-nums;
|
|
84
|
+
font-feature-settings: "ss04" on;
|
|
85
|
+
font-family: var(--global-typography-font-family);
|
|
86
|
+
font-size: var(--global-typography-instrument-label-font-size);
|
|
87
|
+
font-style: normal;
|
|
88
|
+
font-weight: 570;
|
|
89
|
+
line-height: var(--global-typography-instrument-label-line-height);
|
|
90
|
+
}
|
|
@@ -16,13 +16,13 @@ obc-readout-block {
|
|
|
16
16
|
/* ---------- Root ----------
|
|
17
17
|
* The root is an inline flex column (vertical) or row (horizontal). Private
|
|
18
18
|
* `--_readout-*` variables are resolved per layout × size tier below; every
|
|
19
|
-
* layout rule reads only the private variables.
|
|
19
|
+
* layout rule reads only the private variables. A readout is as tall as its
|
|
20
|
+
* rows: the design's container-min-height tokens are not applied (#1252). */
|
|
20
21
|
.readout {
|
|
21
22
|
display: inline-flex;
|
|
22
23
|
position: relative;
|
|
23
24
|
padding-inline: var(--_readout-pad-h);
|
|
24
25
|
padding-block: var(--_readout-pad-v);
|
|
25
|
-
min-block-size: var(--_readout-min-height, auto);
|
|
26
26
|
border-radius: var(--global-border-radius-border-radius-base);
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -532,14 +532,8 @@ obc-readout-block {
|
|
|
532
532
|
--_readout-value-pad-v: var(
|
|
533
533
|
--instrument-components-readout-group-vertical-regular-value-container-padding-vertical
|
|
534
534
|
);
|
|
535
|
-
--_readout-min-height: var(
|
|
536
|
-
--instrument-components-readout-group-vertical-regular-container-min-height
|
|
537
|
-
);
|
|
538
535
|
}
|
|
539
536
|
|
|
540
|
-
/* The medium tiers set no `--_readout-min-height`: Figma defines the
|
|
541
|
-
* container-min-height token only for the regular and enhanced tiers, so
|
|
542
|
-
* medium readouts intentionally fall back to `min-block-size: auto`. */
|
|
543
537
|
.readout.direction-vertical.stacking-inline.size-medium {
|
|
544
538
|
--_readout-pad-h: var(
|
|
545
539
|
--instrument-components-readout-group-vertical-medium-container-padding-horizontal
|
|
@@ -574,9 +568,6 @@ obc-readout-block {
|
|
|
574
568
|
--_readout-value-pad-v: var(
|
|
575
569
|
--instrument-components-readout-group-vertical-enhanced-vertical-value-container-padding-vertical
|
|
576
570
|
);
|
|
577
|
-
--_readout-min-height: var(
|
|
578
|
-
--instrument-components-readout-group-vertical-enhanced-container-min-height
|
|
579
|
-
);
|
|
580
571
|
}
|
|
581
572
|
|
|
582
573
|
/* Stack (vertical, stacked meta) */
|
|
@@ -596,9 +587,6 @@ obc-readout-block {
|
|
|
596
587
|
--_readout-value-pad-v: var(
|
|
597
588
|
--instrument-components-readout-stack-regular-value-container-padding-vertical
|
|
598
589
|
);
|
|
599
|
-
--_readout-min-height: var(
|
|
600
|
-
--instrument-components-readout-stack-regular-container-min-height
|
|
601
|
-
);
|
|
602
590
|
}
|
|
603
591
|
|
|
604
592
|
.readout.direction-vertical.stacking-stacked.size-medium {
|
|
@@ -635,9 +623,6 @@ obc-readout-block {
|
|
|
635
623
|
--_readout-value-pad-v: var(
|
|
636
624
|
--instrument-components-readout-stack-enhanced-vertical-value-container-padding-vertical
|
|
637
625
|
);
|
|
638
|
-
--_readout-min-height: var(
|
|
639
|
-
--instrument-components-readout-stack-enhanced-container-min-height
|
|
640
|
-
);
|
|
641
626
|
}
|
|
642
627
|
|
|
643
628
|
/* Group horizontal */
|
|
@@ -659,8 +644,6 @@ obc-readout-block {
|
|
|
659
644
|
--_readout-divider-pad: var(
|
|
660
645
|
--instrument-components-readout-group-horizontal-regular-divider-padding
|
|
661
646
|
);
|
|
662
|
-
/* TODO(designer): verify; must also hold when only a unit is present */
|
|
663
|
-
--_readout-min-height: auto;
|
|
664
647
|
}
|
|
665
648
|
|
|
666
649
|
.readout.direction-horizontal.size-medium {
|
|
@@ -701,9 +684,6 @@ obc-readout-block {
|
|
|
701
684
|
--_readout-divider-pad: var(
|
|
702
685
|
--instrument-components-readout-group-horizontal-enhanced-divider-padding
|
|
703
686
|
);
|
|
704
|
-
--_readout-min-height: var(
|
|
705
|
-
--instrument-components-readout-group-horizontal-enhanced-container-min-height
|
|
706
|
-
);
|
|
707
687
|
}
|
|
708
688
|
|
|
709
689
|
/* ---------- Debug overlay ----------
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import {afterEach, describe, expect, it, vi} from 'vitest';
|
|
2
|
+
import {render} from 'vitest-browser-lit';
|
|
3
|
+
import {html, type TemplateResult} from 'lit';
|
|
4
|
+
import '../../main.css';
|
|
2
5
|
import './readout.js';
|
|
3
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
ReadoutDirection,
|
|
8
|
+
ReadoutSize,
|
|
9
|
+
ReadoutStacking,
|
|
10
|
+
type ObcReadout,
|
|
11
|
+
} from './readout.js';
|
|
4
12
|
|
|
5
13
|
/**
|
|
6
14
|
* A horizontal readout given a `size` other than `large` warns once per
|
|
@@ -60,3 +68,68 @@ describe('obc-readout horizontal size warning', () => {
|
|
|
60
68
|
expect(warn).toHaveBeenCalledTimes(2);
|
|
61
69
|
});
|
|
62
70
|
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A readout is exactly as tall as its rows — the padding plus the value
|
|
74
|
+
* cluster and the meta zone. No tier applies the design file's
|
|
75
|
+
* container-min-height token (#1252). Measured over every vertical tier and
|
|
76
|
+
* both stackings: in the large tiers the content already exceeds the token,
|
|
77
|
+
* so a reintroduced minimum would stay invisible there.
|
|
78
|
+
*/
|
|
79
|
+
describe('obc-readout height', () => {
|
|
80
|
+
const SIZES = [ReadoutSize.small, ReadoutSize.medium, ReadoutSize.large];
|
|
81
|
+
const STACKINGS = [ReadoutStacking.inline, ReadoutStacking.stacked];
|
|
82
|
+
|
|
83
|
+
async function mount(template: TemplateResult) {
|
|
84
|
+
const screen = render(template);
|
|
85
|
+
const el = screen.container.querySelector('obc-readout') as ObcReadout;
|
|
86
|
+
await el.updateComplete;
|
|
87
|
+
return el.shadowRoot!.querySelector('.readout') as HTMLElement;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The height a column flex root has when nothing but its rows sizes it. */
|
|
91
|
+
function contentHeight(root: HTMLElement): number {
|
|
92
|
+
const {paddingTop, paddingBottom} = getComputedStyle(root);
|
|
93
|
+
const rows = Array.from(root.children).reduce(
|
|
94
|
+
(sum, row) => sum + row.getBoundingClientRect().height,
|
|
95
|
+
0
|
|
96
|
+
);
|
|
97
|
+
return rows + parseFloat(paddingTop) + parseFloat(paddingBottom);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const size of SIZES) {
|
|
101
|
+
for (const stacking of STACKINGS) {
|
|
102
|
+
it(`hugs its rows: ${size} / ${stacking}`, async () => {
|
|
103
|
+
const root = await mount(
|
|
104
|
+
html`<obc-readout
|
|
105
|
+
.size=${size}
|
|
106
|
+
.stacking=${stacking}
|
|
107
|
+
.value=${123}
|
|
108
|
+
label="SOG"
|
|
109
|
+
unit="kn"
|
|
110
|
+
></obc-readout>`
|
|
111
|
+
);
|
|
112
|
+
expect(root.getBoundingClientRect().height).toBeCloseTo(
|
|
113
|
+
contentHeight(root),
|
|
114
|
+
0
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
it('hugs its rows: small / stacked, meta zone only', async () => {
|
|
121
|
+
const root = await mount(
|
|
122
|
+
html`<obc-readout
|
|
123
|
+
.size=${ReadoutSize.small}
|
|
124
|
+
.stacking=${ReadoutStacking.stacked}
|
|
125
|
+
.hasValue=${false}
|
|
126
|
+
label="Angle"
|
|
127
|
+
unit="DEG"
|
|
128
|
+
></obc-readout>`
|
|
129
|
+
);
|
|
130
|
+
expect(root.getBoundingClientRect().height).toBeCloseTo(
|
|
131
|
+
contentHeight(root),
|
|
132
|
+
0
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -367,7 +367,7 @@ function argsToOptions(args: ReadoutStoryArgs): StoryOptions {
|
|
|
367
367
|
|
|
368
368
|
const meta = {
|
|
369
369
|
title: 'Instruments/Readout',
|
|
370
|
-
tags: ['autodocs', '6.0'
|
|
370
|
+
tags: ['autodocs', '6.0'],
|
|
371
371
|
component: 'obc-readout',
|
|
372
372
|
decorators: [centeredCanvasDecorator],
|
|
373
373
|
render: (args) =>
|
|
@@ -304,7 +304,7 @@ export interface ReadoutSourceOptions extends ReadoutSrcOptions {
|
|
|
304
304
|
* @slot src-picker-content - Provides the source picker context menu content.
|
|
305
305
|
* @fires {CustomEvent<{value: string, label?: string}>} source-change - Fired when a source picker option is selected.
|
|
306
306
|
* @fires {CustomEvent<{src: string}>} source-flyout-click - Fired when the source row is clicked while `srcOptions.interaction == 'flyout'`.
|
|
307
|
-
* @
|
|
307
|
+
* @stable
|
|
308
308
|
*/
|
|
309
309
|
@customElement('obc-readout')
|
|
310
310
|
export class ObcReadout extends LitElement {
|
|
@@ -346,7 +346,7 @@ function argsToOptions(args: ReadoutListItemStoryArgs): StoryOptions {
|
|
|
346
346
|
|
|
347
347
|
const meta = {
|
|
348
348
|
title: 'Instruments/Readout List Item',
|
|
349
|
-
tags: ['autodocs', '6.0'
|
|
349
|
+
tags: ['autodocs', '6.0'],
|
|
350
350
|
component: 'obc-readout-list-item',
|
|
351
351
|
decorators: [centeredCanvasDecorator],
|
|
352
352
|
render: (args) =>
|