@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.155 → 2.0.0-next.156

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 (67) hide show
  1. package/LICENSE-AGPL.txt +661 -0
  2. package/LICENSE-APACHE.txt +177 -0
  3. package/LICENSE.txt +35 -0
  4. package/bundle/openbridge-webcomponents.bundle.js +3500 -3275
  5. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  6. package/custom-elements.json +193 -31
  7. package/dist/automation/transmitter/transmitter-shared.d.ts +11 -0
  8. package/dist/automation/transmitter/transmitter-shared.d.ts.map +1 -0
  9. package/dist/automation/transmitter/transmitter-shared.js +16 -0
  10. package/dist/automation/transmitter/transmitter-shared.js.map +1 -0
  11. package/dist/automation/transmitter/transmitter.css.js +12 -1
  12. package/dist/automation/transmitter/transmitter.css.js.map +1 -1
  13. package/dist/automation/transmitter/transmitter.d.ts +9 -10
  14. package/dist/automation/transmitter/transmitter.d.ts.map +1 -1
  15. package/dist/automation/transmitter/transmitter.js +12 -15
  16. package/dist/automation/transmitter/transmitter.js.map +1 -1
  17. package/dist/automation/transmitter-button/transmitter-button.css.js +18 -42
  18. package/dist/automation/transmitter-button/transmitter-button.css.js.map +1 -1
  19. package/dist/automation/transmitter-button/transmitter-button.d.ts +31 -21
  20. package/dist/automation/transmitter-button/transmitter-button.d.ts.map +1 -1
  21. package/dist/automation/transmitter-button/transmitter-button.js +37 -39
  22. package/dist/automation/transmitter-button/transmitter-button.js.map +1 -1
  23. package/dist/automation/transmitter-stack/transmitter-stack.css.js +144 -0
  24. package/dist/automation/transmitter-stack/transmitter-stack.css.js.map +1 -0
  25. package/dist/automation/transmitter-stack/transmitter-stack.d.ts +93 -0
  26. package/dist/automation/transmitter-stack/transmitter-stack.d.ts.map +1 -0
  27. package/dist/automation/transmitter-stack/transmitter-stack.js +97 -0
  28. package/dist/automation/transmitter-stack/transmitter-stack.js.map +1 -0
  29. package/dist/building-blocks/readout-block/readout-block.d.ts +1 -1
  30. package/dist/building-blocks/readout-block/readout-block.js.map +1 -1
  31. package/dist/components/textarea-field/textarea-field.css.js +0 -2
  32. package/dist/components/textarea-field/textarea-field.css.js.map +1 -1
  33. package/dist/components/textbox/textbox.d.ts +1 -1
  34. package/dist/components/textbox/textbox.js.map +1 -1
  35. package/dist/navigation-instruments/readout/readout.d.ts +1 -1
  36. package/dist/navigation-instruments/readout/readout.js.map +1 -1
  37. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +1 -0
  38. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
  39. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +1 -1
  40. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  41. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +3 -0
  42. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  43. package/package.json +6 -3
  44. package/script/prepare-full-bundle.ts +5 -0
  45. package/src/automation/transmitter/transmitter-shared.ts +16 -0
  46. package/src/automation/transmitter/transmitter.css +3 -71
  47. package/src/automation/transmitter/transmitter.stories.ts +13 -1
  48. package/src/automation/transmitter/transmitter.ts +19 -16
  49. package/src/automation/transmitter-button/transmitter-button.css +11 -36
  50. package/src/automation/transmitter-button/transmitter-button.stories.ts +3 -1
  51. package/src/automation/transmitter-button/transmitter-button.ts +62 -66
  52. package/src/automation/transmitter-stack/transmitter-stack.css +56 -0
  53. package/src/automation/transmitter-stack/transmitter-stack.spec.ts +210 -0
  54. package/src/automation/transmitter-stack/transmitter-stack.stories.ts +149 -0
  55. package/src/automation/transmitter-stack/transmitter-stack.ts +172 -0
  56. package/src/building-blocks/readout-block/readout-block.stories.ts +1 -1
  57. package/src/building-blocks/readout-block/readout-block.ts +1 -1
  58. package/src/components/textarea-field/textarea-field.css +1 -8
  59. package/src/components/textbox/textbox.stories.ts +1 -1
  60. package/src/components/textbox/textbox.ts +1 -1
  61. package/src/mixins/transmitter.css +90 -0
  62. package/src/mixins/visually-hidden.css +10 -0
  63. package/src/navigation-instruments/readout/readout.stories.ts +1 -1
  64. package/src/navigation-instruments/readout/readout.ts +1 -1
  65. package/src/navigation-instruments/readout-list-item/readout-list-item.css +1 -0
  66. package/src/navigation-instruments/readout-list-item/readout-list-item.stories.ts +1 -1
  67. 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', 'beta'],
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
- * @beta
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
- clip: rect(0 0 0 0);
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', 'beta'],
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
- * @beta
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
+ }
@@ -0,0 +1,10 @@
1
+ /* Removes content from view while keeping it in the accessibility tree. */
2
+ @define-mixin visually-hidden {
3
+ clip: rect(0 0 0 0);
4
+ clip-path: inset(50%);
5
+ height: 1px;
6
+ overflow: hidden;
7
+ position: absolute;
8
+ white-space: nowrap;
9
+ width: 1px;
10
+ }
@@ -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', 'beta'],
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
- * @beta
307
+ * @stable
308
308
  */
309
309
  @customElement('obc-readout')
310
310
  export class ObcReadout extends LitElement {
@@ -130,6 +130,7 @@ obc-readout-block {
130
130
  }
131
131
 
132
132
  .value-area {
133
+ margin-inline-start: auto; /* right-aligns a label-less row's value, which has no label container to push it */
133
134
  display: inline-flex;
134
135
  align-items: flex-end;
135
136
  justify-content: flex-end;
@@ -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', 'beta'],
349
+ tags: ['autodocs', '6.0'],
350
350
  component: 'obc-readout-list-item',
351
351
  decorators: [centeredCanvasDecorator],
352
352
  render: (args) =>
@@ -364,7 +364,7 @@ export interface ReadoutSrcOptions extends ReadoutBlockState {
364
364
  * @slot setpoint-icon - Overrides the default setpoint icon.
365
365
  * @slot advice-icon - Overrides the default advice icon.
366
366
  * @fires click - Fired when the item is activated. Only fired when `clickable` is set; otherwise the item renders as a non-interactive `<div>`.
367
- * @beta
367
+ * @stable
368
368
  */
369
369
  @customElement('obc-readout-list-item')
370
370
  export class ObcReadoutListItem extends LitElement {
@@ -943,11 +943,21 @@ export class ObcReadoutListItem extends LitElement {
943
943
  `;
944
944
  }
945
945
 
946
- private renderLabelContainer(): TemplateResult {
946
+ private renderLabelContainer(): TemplateResult | typeof nothing {
947
947
  const stacking = this.resolvedStacking;
948
948
  const showLeadingUnit =
949
949
  stacking === ReadoutListItemStacking.leadingUnit && Boolean(this.unit);
950
950
  const showLeadingSrc = this.hasLeadingSrc && Boolean(this.src);
951
+ // An empty container would still take the content gap, so a label-less
952
+ // row (the transmitter chip) could not hug its value.
953
+ if (
954
+ !this.hasLeadingIcon &&
955
+ !this.label &&
956
+ !showLeadingUnit &&
957
+ !showLeadingSrc
958
+ ) {
959
+ return nothing;
960
+ }
951
961
 
952
962
  return html`
953
963
  <div class="label-container" part="label-container">