@oicl/openbridge-webcomponents 2.0.0-next.83 → 2.0.0-next.85

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 (26) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +1223 -493
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +642 -196
  4. package/dist/components/tab-item/tab-item.css.js +8 -1
  5. package/dist/components/tab-item/tab-item.css.js.map +1 -1
  6. package/dist/components/tab-item/tab-item.d.ts +44 -0
  7. package/dist/components/tab-item/tab-item.d.ts.map +1 -1
  8. package/dist/components/tab-item/tab-item.js +44 -25
  9. package/dist/components/tab-item/tab-item.js.map +1 -1
  10. package/dist/components/tab-row/tab-row.d.ts +23 -9
  11. package/dist/components/tab-row/tab-row.d.ts.map +1 -1
  12. package/dist/components/tab-row/tab-row.js +24 -7
  13. package/dist/components/tab-row/tab-row.js.map +1 -1
  14. package/dist/components/textbox/textbox.css.js +29 -5
  15. package/dist/components/textbox/textbox.css.js.map +1 -1
  16. package/dist/components/textbox/textbox.d.ts +5 -0
  17. package/dist/components/textbox/textbox.d.ts.map +1 -1
  18. package/dist/components/textbox/textbox.js +6 -1
  19. package/dist/components/textbox/textbox.js.map +1 -1
  20. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +611 -230
  21. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
  22. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +280 -61
  23. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  24. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +529 -247
  25. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  26. package/package.json +1 -1
@@ -1,11 +1,12 @@
1
1
  import { unsafeCSS, LitElement, nothing, html } from "lit";
2
- import { property } from "lit/decorators.js";
2
+ import { property, state } from "lit/decorators.js";
3
3
  import { classMap } from "lit/directives/class-map.js";
4
4
  import componentStyle from "./readout-list-item.css.js";
5
5
  import { customElement } from "../../decorator.js";
6
- import { ReadoutSetpointSize, ReadoutSetpointValueTypography, ReadoutSetpointMode } from "../readout-setpoint/readout-setpoint.js";
7
- import { Priority } from "../types.js";
6
+ import { ObcTextboxSize, ObcTextboxFontWeight } from "../../components/textbox/textbox.js";
8
7
  import "../../icons/icon-input-right.js";
8
+ import "../../icons/icon-notification-advice.js";
9
+ import { formatNumericValue, getHintZeros } from "../readout/readout-formatters.js";
9
10
  import { wrapWithAlertFrame } from "../../components/alert-frame/alert-frame.js";
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -17,16 +18,10 @@ var __decorateClass = (decorators, target, key, kind) => {
17
18
  if (kind && result) __defProp(target, key, result);
18
19
  return result;
19
20
  };
20
- var ReadoutListItemDataState = /* @__PURE__ */ ((ReadoutListItemDataState2) => {
21
- ReadoutListItemDataState2["none"] = "none";
22
- ReadoutListItemDataState2["lowIntegrity"] = "low-integrity";
23
- ReadoutListItemDataState2["invalid"] = "invalid";
24
- return ReadoutListItemDataState2;
25
- })(ReadoutListItemDataState || {});
26
21
  var ReadoutListItemSize = /* @__PURE__ */ ((ReadoutListItemSize2) => {
27
- ReadoutListItemSize2["base"] = "base";
28
- ReadoutListItemSize2["priority"] = "priority";
29
- ReadoutListItemSize2["enhanced"] = "enhanced";
22
+ ReadoutListItemSize2["small"] = "small";
23
+ ReadoutListItemSize2["medium"] = "medium";
24
+ ReadoutListItemSize2["large"] = "large";
30
25
  return ReadoutListItemSize2;
31
26
  })(ReadoutListItemSize || {});
32
27
  var ReadoutListItemStacking = /* @__PURE__ */ ((ReadoutListItemStacking2) => {
@@ -38,285 +33,539 @@ var ReadoutListItemStacking = /* @__PURE__ */ ((ReadoutListItemStacking2) => {
38
33
  var ReadoutListItemPriority = /* @__PURE__ */ ((ReadoutListItemPriority2) => {
39
34
  ReadoutListItemPriority2["regular"] = "regular";
40
35
  ReadoutListItemPriority2["enhanced"] = "enhanced";
41
- ReadoutListItemPriority2["setpoint"] = "setpoint";
42
- ReadoutListItemPriority2["setpointFlipFlop"] = "setpoint-flip-flop";
43
36
  return ReadoutListItemPriority2;
44
37
  })(ReadoutListItemPriority || {});
38
+ var ReadoutListItemDataQuality = /* @__PURE__ */ ((ReadoutListItemDataQuality2) => {
39
+ ReadoutListItemDataQuality2["lowIntegrity"] = "low-integrity";
40
+ ReadoutListItemDataQuality2["invalid"] = "invalid";
41
+ return ReadoutListItemDataQuality2;
42
+ })(ReadoutListItemDataQuality || {});
43
+ var ReadoutListItemBorder = /* @__PURE__ */ ((ReadoutListItemBorder2) => {
44
+ ReadoutListItemBorder2["squared"] = "squared";
45
+ ReadoutListItemBorder2["round"] = "round";
46
+ ReadoutListItemBorder2["roundCorners"] = "round-corners";
47
+ return ReadoutListItemBorder2;
48
+ })(ReadoutListItemBorder || {});
49
+ var ReadoutListItemSetpointInteraction = /* @__PURE__ */ ((ReadoutListItemSetpointInteraction2) => {
50
+ ReadoutListItemSetpointInteraction2["alwaysVisible"] = "always-visible";
51
+ ReadoutListItemSetpointInteraction2["flipFlop"] = "flip-flop";
52
+ ReadoutListItemSetpointInteraction2["popUp"] = "pop-up";
53
+ return ReadoutListItemSetpointInteraction2;
54
+ })(ReadoutListItemSetpointInteraction || {});
45
55
  let ObcReadoutListItem = class extends LitElement {
46
56
  constructor() {
47
57
  super(...arguments);
48
- this.size = "base";
49
- this.stacking = "trailing-unit";
50
- this.priority = "regular";
51
- this.dataState = "none";
52
- this.alert = false;
53
- this.label = "";
54
- this.unit = "";
55
- this.src = "";
56
- this.value = void 0;
57
- this.setpointValue = void 0;
58
+ this.hasValue = true;
59
+ this.value = null;
60
+ this.off = false;
58
61
  this.hasSetpoint = false;
59
- this.hasDegree = false;
60
- this.hasUnit = false;
61
- this.hasLabel = false;
62
- this.hasSource = false;
62
+ this.hasAdvice = false;
63
+ this.clickable = false;
63
64
  this.hasLeadingIcon = false;
64
- this.hasValueIcon = false;
65
+ this.hasDegree = false;
66
+ this.hasDegreeSpacer = false;
65
67
  this.fractionDigits = 0;
66
- this.showZeroPadding = false;
67
- this.minValueLength = 0;
68
- this.hasHintedZeros = false;
69
- this.labelOnly = false;
70
- }
71
- get resolvedMainValueSize() {
72
- return this.size === "enhanced" ? ReadoutSetpointSize.large : this.size === "priority" ? ReadoutSetpointSize.medium : ReadoutSetpointSize.regular;
73
- }
74
- get resolvedValueSize() {
75
- if (this.priority === "setpoint-flip-flop") {
76
- if (this.size === "priority") {
77
- return ReadoutSetpointSize.small;
78
- }
79
- if (this.size === "enhanced") {
80
- return ReadoutSetpointSize.regular;
81
- }
82
- }
83
- if (this.size === "enhanced") {
84
- return ReadoutSetpointSize.large;
85
- }
86
- return ReadoutSetpointSize.regular;
68
+ this.maxDigits = 0;
69
+ this.alert = false;
70
+ this.deferredSetpointHidePhase = "none";
71
+ this.hasCompletedFirstUpdate = false;
72
+ }
73
+ get resolvedSize() {
74
+ return this.size ?? "small";
87
75
  }
88
- get resolvedValueTypography() {
89
- if (this.priority === "setpoint-flip-flop" && this.resolvedValueSize === ReadoutSetpointSize.small) {
90
- return void 0;
76
+ get resolvedStacking() {
77
+ return this.stacking ?? "trailing-unit";
78
+ }
79
+ get resolvedPriority() {
80
+ return this.priority ?? "regular";
81
+ }
82
+ get resolvedFractionDigits() {
83
+ return this.fractionDigits ?? 0;
84
+ }
85
+ get resolvedMaxDigits() {
86
+ return this.maxDigits ?? 0;
87
+ }
88
+ get resolvedClickable() {
89
+ const clickable = this.clickable;
90
+ if (!clickable) {
91
+ return false;
91
92
  }
92
- if (this.priority === "setpoint-flip-flop" && this.size === "enhanced") {
93
- return ReadoutSetpointValueTypography.regular;
93
+ if (clickable === true) {
94
+ return {
95
+ border: "squared"
96
+ /* squared */
97
+ };
94
98
  }
95
- switch (this.size) {
96
- case "enhanced":
97
- return ReadoutSetpointValueTypography.large;
98
- case "priority":
99
- return ReadoutSetpointValueTypography.medium;
100
- case "base":
101
- default:
102
- return ReadoutSetpointValueTypography.regular;
99
+ return {
100
+ border: clickable.border ?? "squared"
101
+ /* squared */
102
+ };
103
+ }
104
+ get isAtSetpoint() {
105
+ if (!this.hasSetpoint || this.value === null || this.setpoint === void 0) {
106
+ return false;
103
107
  }
108
+ const formatOptions = this.numericFormatOptions(this.resolvedMaxDigits);
109
+ return formatNumericValue(this.value, formatOptions) === formatNumericValue(this.setpoint, formatOptions);
110
+ }
111
+ get resolvedSetpointInteraction() {
112
+ return this.setpointOptions?.interaction ?? "always-visible";
113
+ }
114
+ get isFlipFlop() {
115
+ return this.resolvedSetpointInteraction === "flip-flop";
104
116
  }
105
- get resolvedSetpointSize() {
117
+ get isPopUp() {
118
+ return this.resolvedSetpointInteraction === "pop-up";
119
+ }
120
+ get setpointTouching() {
121
+ return this.setpointOptions?.touching ?? false;
122
+ }
123
+ /**
124
+ * The setpoint is rendered "emphasised" (primary size + SemiBold weight) when
125
+ * it is the focus of attention: while actively adjusting (`touching`), or while
126
+ * a flip-flop has the value away from the setpoint. Otherwise it is a secondary
127
+ * (smaller, regular-weight) reference next to the value.
128
+ */
129
+ get isSetpointEmphasized() {
106
130
  if (!this.hasSetpoint) {
107
- return ReadoutSetpointSize.small;
131
+ return false;
108
132
  }
109
- if (this.priority === "setpoint" || this.priority === "setpoint-flip-flop") {
110
- return this.resolvedMainValueSize;
133
+ if (this.setpointTouching) {
134
+ return true;
111
135
  }
112
- return ReadoutSetpointSize.small;
136
+ return this.isFlipFlop && !this.isAtSetpoint;
113
137
  }
114
- get resolvedActualPriority() {
115
- if (this.priority === "enhanced" || this.priority === "setpoint" && !this.hasSetpoint || this.priority === "setpoint-flip-flop") {
116
- return Priority.enhanced;
117
- }
118
- return Priority.regular;
138
+ /**
139
+ * The row's enhanced (in-command) colour state, applied uniformly to BOTH the
140
+ * value and the setpoint — they are always either both neutral or both enhanced
141
+ * (never a blue setpoint next to a grey value). Driven by `priority` only;
142
+ * `valueOptions.weight` changes weight, not colour.
143
+ */
144
+ get rowEnhanced() {
145
+ return this.resolvedPriority === "enhanced";
119
146
  }
120
- get resolvedActualMode() {
121
- return this.priority === "enhanced" ? ReadoutSetpointMode.setpoint : ReadoutSetpointMode.display;
147
+ /** Primary value-typography size for the current density tier. */
148
+ get primarySize() {
149
+ switch (this.resolvedSize) {
150
+ case "large":
151
+ return ObcTextboxSize.l;
152
+ case "medium":
153
+ return ObcTextboxSize.m;
154
+ default:
155
+ return ObcTextboxSize.s;
156
+ }
122
157
  }
123
- get resolvedSetpointPriority() {
124
- if (!this.hasSetpoint || this.priority === "regular") {
125
- return Priority.regular;
158
+ /** Secondary (de-emphasised) value-typography size for the current density tier. */
159
+ get secondarySize() {
160
+ switch (this.resolvedSize) {
161
+ case "large":
162
+ return ObcTextboxSize.s;
163
+ case "medium":
164
+ return ObcTextboxSize.s;
165
+ default:
166
+ return ObcTextboxSize.xs;
126
167
  }
127
- return Priority.enhanced;
128
168
  }
129
- get resolvedSetpointMode() {
130
- if (this.hasSetpoint && this.priority === "setpoint") {
131
- return ReadoutSetpointMode.setpoint;
169
+ get valueSize() {
170
+ if (this.isSetpointEmphasized) {
171
+ return this.secondarySize;
132
172
  }
133
- return ReadoutSetpointMode.display;
173
+ return this.primarySize;
134
174
  }
135
- get showsTrailingSource() {
136
- return this.hasSource && this.stacking !== "leading-src";
175
+ get setpointSize() {
176
+ return this.isSetpointEmphasized ? this.primarySize : this.secondarySize;
137
177
  }
138
- get stacksLeadingUnitVertically() {
139
- return this.stacking === "leading-unit" && this.size === "enhanced";
178
+ /** Value font weight passes straight to obc-textbox; regular when unset. Colour is separate. */
179
+ get valueWeight() {
180
+ return this.valueOptions?.weight ?? ObcTextboxFontWeight.regular;
140
181
  }
141
- get stacksLeadingSrcVertically() {
142
- return this.stacking === "leading-src" && this.size === "enhanced";
182
+ /** Setpoint is SemiBold only while emphasised, otherwise regular weight. */
183
+ get setpointWeight() {
184
+ return this.isSetpointEmphasized ? ObcTextboxFontWeight.semibold : ObcTextboxFontWeight.regular;
143
185
  }
144
- renderLabelContainer() {
145
- if (!this.hasLabel) {
146
- return nothing;
186
+ numericFormatOptions(maxDigits) {
187
+ return {
188
+ showZeroPadding: false,
189
+ minValueLength: maxDigits,
190
+ fractionDigits: this.resolvedFractionDigits
191
+ };
192
+ }
193
+ /** Widest possible value string for width reservation (e.g. `"000.0"`). */
194
+ get reserverText() {
195
+ const maxDigits = this.resolvedMaxDigits;
196
+ if (maxDigits <= 0) {
197
+ return "";
147
198
  }
148
- const showsLeadingUnit = this.stacking === "leading-unit" && this.hasUnit;
149
- const showsLeadingSrc = this.stacking === "leading-src" && this.hasSource;
150
- if (showsLeadingUnit && !this.stacksLeadingUnitVertically) {
151
- return html`
152
- <div class="label-inline" part="label-inline">
153
- <div class="label" part="label">${this.label}</div>
154
- <div class="unit unit-leading" part="unit-leading">${this.unit}</div>
155
- </div>
156
- `;
199
+ const fractionDigits = this.resolvedFractionDigits;
200
+ const integer = "0".repeat(Math.max(maxDigits, 1));
201
+ return fractionDigits > 0 ? `${integer}.${"0".repeat(fractionDigits)}` : integer;
202
+ }
203
+ /**
204
+ * Effective width reserver for a numeric block: the wider of the explicit
205
+ * `spaceReserver` and the `maxDigits`/`fractionDigits`-derived reserve, so an
206
+ * explicit reserver can never reserve *less* than the formatted value needs.
207
+ * Under tabular-nums the rendered width is proportional to character count, so
208
+ * "wider" compares string length.
209
+ */
210
+ widerReserver(explicit, derived) {
211
+ if (!explicit) {
212
+ return derived;
157
213
  }
158
- if (showsLeadingSrc && !this.stacksLeadingSrcVertically) {
159
- return html`
160
- <div class="label-inline" part="label-inline">
161
- <div class="label" part="label">${this.label}</div>
162
- <div class="source source-inline" part="source-inline">
163
- ${this.src}
164
- </div>
165
- </div>
166
- `;
214
+ if (!derived) {
215
+ return explicit;
167
216
  }
168
- return html`
169
- <div class="label-stack" part="label-stack">
170
- <div class="label" part="label">${this.label}</div>
171
- ${showsLeadingUnit ? html`<div class="unit unit-leading" part="unit-leading">
172
- ${this.unit}
173
- </div>` : nothing}
174
- ${showsLeadingSrc ? html`<div class="source source-inline" part="source-inline">
175
- ${this.src}
176
- </div>` : nothing}
217
+ return explicit.length >= derived.length ? explicit : derived;
218
+ }
219
+ /** classMap fragment for a block / source carrying per-block data quality. */
220
+ dataQualityClasses(dataQuality) {
221
+ return {
222
+ "data-low-integrity": dataQuality === "low-integrity",
223
+ "data-invalid": dataQuality === "invalid"
224
+ /* invalid */
225
+ };
226
+ }
227
+ renderIcon(role) {
228
+ if (role === "value") {
229
+ if (!this.valueOptions?.hasIcon) {
230
+ return nothing;
231
+ }
232
+ return html`<span class="block-icon" aria-hidden="true"
233
+ ><slot name="value-icon"></slot
234
+ ></span>`;
235
+ }
236
+ if (role === "setpoint") {
237
+ return html`<span class="block-icon" aria-hidden="true">
238
+ <slot name="setpoint-icon"><obi-input-right></obi-input-right></slot>
239
+ </span>`;
240
+ }
241
+ return html`<span class="block-icon" aria-hidden="true">
242
+ <slot name="advice-icon"
243
+ ><obi-notification-advice></obi-notification-advice
244
+ ></slot>
245
+ </span>`;
246
+ }
247
+ renderBlock(config) {
248
+ const formatOptions = this.numericFormatOptions(this.resolvedMaxDigits);
249
+ const valueForFormat = config.value ?? void 0;
250
+ const text = config.off ? "OFF" : formatNumericValue(valueForFormat, formatOptions);
251
+ const hinted = config.off || !config.hintedZeros ? "" : getHintZeros(valueForFormat, {
252
+ ...formatOptions,
253
+ minValueLength: formatOptions.minValueLength + formatOptions.fractionDigits
254
+ });
255
+ const reserver = this.widerReserver(
256
+ config.spaceReserver,
257
+ this.reserverText
258
+ );
259
+ const block = html`
260
+ <div
261
+ class=${classMap({
262
+ block: true,
263
+ [`block-${config.role}`]: true,
264
+ "tone-enhanced": config.enhanced,
265
+ ...this.dataQualityClasses(config.dataQuality),
266
+ ...config.extraClasses ?? {}
267
+ })}
268
+ part="block block-${config.role}"
269
+ >
270
+ ${this.renderIcon(config.role)}
271
+ <span class="block-content">
272
+ <obc-textbox
273
+ class="block-text"
274
+ .size=${config.size}
275
+ .fontWeight=${config.weight}
276
+ .tabularNums=${true}
277
+ >
278
+ ${hinted ? html`<span class="hinted-zero" aria-hidden="true"
279
+ >${hinted}</span
280
+ >` : nothing}${text}
281
+ ${reserver ? html`<span slot="length">${reserver}</span>` : nothing}
282
+ </obc-textbox>
283
+ ${config.hasDegree ? this.renderDegreeGlyph(config.size, { inherit: true }) : nothing}
284
+ </span>
177
285
  </div>
178
286
  `;
287
+ return wrapWithAlertFrame(config.alert ?? false, block);
288
+ }
289
+ /**
290
+ * A cap-height `°` column whose width scales with the value size. Used after
291
+ * the value (as the value↔unit boundary, via {@link renderValueUnitGap}) and
292
+ * inside the setpoint / advice blocks. `inherit` makes the glyph take the
293
+ * surrounding block's colour (setpoint/advice); otherwise it uses the value
294
+ * colour, optionally `enhanced`.
295
+ */
296
+ renderDegreeGlyph(size, opts = {}) {
297
+ return html`
298
+ <span
299
+ class=${classMap({
300
+ "degree-column": true,
301
+ [`degree-${size}`]: true,
302
+ "tone-enhanced": !opts.inherit && Boolean(opts.enhanced),
303
+ "degree-inherit": Boolean(opts.inherit)
304
+ })}
305
+ part="degree"
306
+ >
307
+ <obc-textbox class="degree-glyph" .size=${size} alignment="center"
308
+ >°</obc-textbox
309
+ >
310
+ </span>
311
+ `;
179
312
  }
180
- renderValueIconSlot() {
181
- if (!this.hasValueIcon) {
313
+ /**
314
+ * The gap rendered between the value digits and the unit.
315
+ *
316
+ * - `hasDegree`: a cap-height `°` column whose width scales with the value
317
+ * size (the `°` replaces the default gap).
318
+ * - otherwise: the default 2px gap (only when a trailing unit follows).
319
+ *
320
+ * `hasDegreeSpacer` deliberately does NOT add anything here — it keeps the 2px
321
+ * gap and instead widens the unit column via {@link renderDegreeSpacer} (a
322
+ * spacer AFTER the unit). That way a non-degree row's value digits stay
323
+ * aligned with degree rows (degree column width = spacer width + 2px gap)
324
+ * while its unit shifts left. Mirrors Figma `1:2920` (spacer) / `1:2970`
325
+ * (degree).
326
+ *
327
+ * TODO(designer): cross-size alignment is deferred. Degree rows of different
328
+ * value sizes have different `°` column widths (6/8/12px), so their value digit
329
+ * edges stagger by `degree-width`. For degree rows of mixed sizes you cannot
330
+ * align the value digit edges AND keep the unit column aligned — resolving it
331
+ * needs a design decision (a constant degree reserve, which widens the smaller
332
+ * rows' `°`, OR pinning the value edge and letting the unit column stagger).
333
+ */
334
+ renderValueUnitGap() {
335
+ if (!this.hasValue) {
182
336
  return nothing;
183
337
  }
184
- return html`<span class="value-icon" slot="icon" aria-hidden="true">
185
- <slot name="value-icon"></slot>
186
- </span>`;
338
+ const hasTrailingUnit = Boolean(this.unit) && this.resolvedStacking !== "leading-unit";
339
+ if ((this.hasDegree ?? false) && !this.off) {
340
+ return this.renderDegreeGlyph(this.valueSize, {
341
+ enhanced: this.rowEnhanced
342
+ });
343
+ }
344
+ if (hasTrailingUnit) {
345
+ return html`<span class="value-unit-gap" aria-hidden="true"></span>`;
346
+ }
347
+ return nothing;
187
348
  }
188
- renderSetpoint() {
189
- if (!this.hasSetpoint) {
349
+ /**
350
+ * A spacer rendered AFTER the unit when `hasDegreeSpacer` is set on a
351
+ * non-degree row. Its width (`degree-compensation-padding`) = the degree
352
+ * column width minus the 2px gap, so the row's value digits align with degree
353
+ * rows in the same column while its unit shifts left. See
354
+ * {@link renderValueUnitGap}.
355
+ */
356
+ renderDegreeSpacer() {
357
+ const hasDegree = this.hasDegree ?? false;
358
+ const hasDegreeSpacer = this.hasDegreeSpacer ?? false;
359
+ if (hasDegree || !hasDegreeSpacer) {
190
360
  return nothing;
191
361
  }
192
- return html`
193
- <obc-readout-setpoint
194
- .variant=${"setpoint"}
195
- .readoutStyle=${"regular"}
196
- .direction=${"horizontal"}
197
- .size=${this.resolvedSetpointSize}
198
- .priority=${this.resolvedSetpointPriority}
199
- .mode=${this.resolvedSetpointMode}
200
- .hugContent=${true}
201
- .value=${this.setpointValue}
202
- .showZeroPadding=${this.showZeroPadding}
203
- .fractionDigits=${this.fractionDigits}
204
- .minValueLength=${this.minValueLength}
205
- .hasHintedZeros=${this.hasHintedZeros}
206
- .hasDegree=${this.hasDegree}
362
+ return html`<span
363
+ class="degree-spacer"
364
+ part="degree-spacer"
365
+ aria-hidden="true"
366
+ ></span>`;
367
+ }
368
+ renderTextbox(role, text, reserver, state2) {
369
+ const weight = role === "label" ? ObcTextboxFontWeight.semibold : ObcTextboxFontWeight.regular;
370
+ const box = html`
371
+ <obc-textbox
372
+ class=${classMap({
373
+ [role]: true,
374
+ ...this.dataQualityClasses(state2?.dataQuality)
375
+ })}
376
+ part=${role}
377
+ .size=${ObcTextboxSize.xs}
378
+ .fontWeight=${weight}
379
+ alignment="left"
207
380
  >
208
- <obi-input-right slot="icon"></obi-input-right>
209
- </obc-readout-setpoint>
381
+ ${text}
382
+ ${reserver ? html`<span slot="length">${reserver}</span>` : nothing}
383
+ </obc-textbox>
210
384
  `;
385
+ return wrapWithAlertFrame(state2?.alert ?? false, box);
211
386
  }
212
- renderActualValue() {
387
+ renderValueCluster() {
388
+ const popUpAtSetpoint = this.isPopUp && this.isAtSetpoint && !this.setpointTouching;
389
+ const setpointExtraClasses = {
390
+ "is-hiding": popUpAtSetpoint && this.deferredSetpointHidePhase === "hiding",
391
+ "is-hidden": popUpAtSetpoint && this.deferredSetpointHidePhase === "hidden",
392
+ touching: this.setpointTouching
393
+ };
213
394
  return html`
214
- <obc-readout-setpoint
215
- .variant=${"value"}
216
- .readoutStyle=${"regular"}
217
- .direction=${"horizontal"}
218
- .size=${this.resolvedValueSize}
219
- .valueTypography=${this.resolvedValueTypography ?? void 0}
220
- .priority=${this.resolvedActualPriority}
221
- .mode=${this.resolvedActualMode}
222
- .hugContent=${true}
223
- .value=${this.value}
224
- .showZeroPadding=${this.showZeroPadding}
225
- .fractionDigits=${this.fractionDigits}
226
- .minValueLength=${this.minValueLength}
227
- .hasHintedZeros=${this.hasHintedZeros}
228
- .hasDegree=${this.hasDegree}
229
- >
230
- ${this.renderValueIconSlot()}
231
- </obc-readout-setpoint>
395
+ <div class="value-cluster" part="value-cluster">
396
+ ${this.hasAdvice ? this.renderBlock({
397
+ role: "advice",
398
+ value: this.advice,
399
+ size: this.secondarySize,
400
+ enhanced: false,
401
+ weight: ObcTextboxFontWeight.regular,
402
+ hintedZeros: this.adviceOptions?.hintedZeros ?? false,
403
+ spaceReserver: this.adviceOptions?.spaceReserver,
404
+ hasDegree: this.hasDegree ?? false,
405
+ dataQuality: this.adviceOptions?.dataQuality,
406
+ alert: this.adviceOptions?.alert
407
+ }) : nothing}
408
+ ${this.hasSetpoint ? this.renderBlock({
409
+ role: "setpoint",
410
+ value: this.setpoint,
411
+ size: this.setpointSize,
412
+ // Value and setpoint share the enhanced colour state (both neutral
413
+ // or both enhanced); the setpoint is bold only while emphasised.
414
+ enhanced: this.rowEnhanced,
415
+ weight: this.setpointWeight,
416
+ hintedZeros: this.setpointOptions?.hintedZeros ?? false,
417
+ spaceReserver: this.setpointOptions?.spaceReserver,
418
+ hasDegree: this.hasDegree ?? false,
419
+ extraClasses: setpointExtraClasses,
420
+ dataQuality: this.setpointOptions?.dataQuality,
421
+ alert: this.setpointOptions?.alert
422
+ }) : nothing}
423
+ ${this.hasValue ? this.renderBlock({
424
+ role: "value",
425
+ value: this.value,
426
+ size: this.valueSize,
427
+ enhanced: this.rowEnhanced,
428
+ weight: this.valueWeight,
429
+ hintedZeros: this.valueOptions?.hintedZeros ?? false,
430
+ spaceReserver: this.valueOptions?.spaceReserver,
431
+ off: this.off,
432
+ dataQuality: this.valueOptions?.dataQuality,
433
+ alert: this.valueOptions?.alert
434
+ }) : nothing}
435
+ </div>
232
436
  `;
233
437
  }
234
- renderValue() {
438
+ renderLabelContainer() {
439
+ const stacking = this.resolvedStacking;
440
+ const showLeadingUnit = stacking === "leading-unit" && Boolean(this.unit);
441
+ const showLeadingSrc = stacking === "leading-src" && Boolean(this.src);
235
442
  return html`
236
- <div class="value-wrap" part="value-wrap">
237
- ${this.hasSetpoint ? html`<div class="value-cluster" part="value-cluster">
238
- ${this.renderSetpoint()} ${this.renderActualValue()}
239
- </div>` : this.renderActualValue()}
443
+ <div class="label-container" part="label-container">
444
+ ${this.hasLeadingIcon ? html`<span class="leading-icon" aria-hidden="true"
445
+ ><slot name="leading-icon"></slot
446
+ ></span>` : nothing}
447
+ <div class="label-stack" part="label-stack">
448
+ ${this.label ? this.renderTextbox("label", this.label) : nothing}
449
+ ${showLeadingUnit ? this.renderTextbox(
450
+ "unit",
451
+ this.unit ?? "",
452
+ this.unitOptions?.spaceReserver
453
+ ) : nothing}
454
+ ${showLeadingSrc ? this.renderTextbox(
455
+ "source",
456
+ this.src ?? "",
457
+ this.srcOptions?.spaceReserver,
458
+ this.srcOptions
459
+ ) : nothing}
460
+ </div>
240
461
  </div>
241
462
  `;
242
463
  }
243
464
  renderTrailingUnit() {
244
- if (!this.hasUnit || this.stacking === "leading-unit") {
465
+ if (this.resolvedStacking === "leading-unit" || !this.unit) {
245
466
  return nothing;
246
467
  }
247
- return html`<div class="unit unit-trailing" part="unit-trailing">
248
- ${this.unit}
249
- </div>`;
468
+ return this.renderTextbox(
469
+ "unit",
470
+ this.unit,
471
+ this.unitOptions?.spaceReserver
472
+ );
250
473
  }
251
474
  renderTrailingSource() {
252
- if (!this.showsTrailingSource) {
475
+ if (this.resolvedStacking === "leading-src" || !this.src) {
253
476
  return nothing;
254
477
  }
255
478
  return html`
256
479
  <div class="divider" part="divider" aria-hidden="true"></div>
257
- <div class="source source-trailing" part="source-trailing">
258
- ${this.src}
259
- </div>
480
+ ${this.renderTextbox(
481
+ "source",
482
+ this.src,
483
+ this.srcOptions?.spaceReserver,
484
+ this.srcOptions
485
+ )}
260
486
  `;
261
487
  }
262
- render() {
263
- return wrapWithAlertFrame(
264
- this.alert,
265
- html`
266
- <div
267
- class=${classMap({
268
- root: true,
269
- [`size-${this.size}`]: true,
270
- [`stacking-${this.stacking}`]: true,
271
- "priority-enhanced": this.priority === "enhanced",
272
- "priority-setpoint": this.priority === "setpoint",
273
- "priority-setpoint-flip-flop": this.priority === "setpoint-flip-flop",
274
- "data-none": this.dataState === "none",
275
- "data-low-integrity": this.dataState === "low-integrity",
276
- "data-invalid": this.dataState === "invalid",
277
- "has-leading-icon": this.hasLeadingIcon,
278
- "has-value-icon": this.hasValueIcon
279
- })}
280
- part="root"
281
- >
282
- <div class="content" part="content">
283
- <div class="label-container" part="label-container">
284
- ${this.hasLeadingIcon ? html`<span class="leading-icon" aria-hidden="true"
285
- ><slot name="leading-icon"></slot
286
- ></span>` : nothing}
287
- ${this.renderLabelContainer()}
288
- </div>
289
-
290
- ${this.labelOnly ? nothing : html`
291
- <div class="value-container" part="value-container">
292
- ${this.renderValue()} ${this.renderTrailingUnit()}
293
- </div>
294
-
295
- ${this.renderTrailingSource()}
296
- `}
488
+ renderContent() {
489
+ return html`
490
+ <div class="content" part="content">
491
+ ${this.renderLabelContainer()}
492
+ <div class="value-area" part="value-area">
493
+ ${this.renderValueCluster()} ${this.renderValueUnitGap()}
494
+ <div class="unit-area" part="unit-area">
495
+ ${this.renderTrailingUnit()} ${this.renderDegreeSpacer()}
297
496
  </div>
298
497
  </div>
299
- `,
300
- true
301
- );
498
+ ${this.renderTrailingSource()}
499
+ </div>
500
+ `;
501
+ }
502
+ updated(changed) {
503
+ super.updated(changed);
504
+ const firstUpdate = !this.hasCompletedFirstUpdate;
505
+ this.hasCompletedFirstUpdate = true;
506
+ if (!this.isPopUp || this.setpointTouching) {
507
+ this.clearDeferredSetpointHide();
508
+ return;
509
+ }
510
+ const shouldHide = this.hasSetpoint && this.isAtSetpoint;
511
+ if (firstUpdate) {
512
+ this.deferredSetpointHidePhase = shouldHide ? "hidden" : "none";
513
+ return;
514
+ }
515
+ if (!shouldHide) {
516
+ this.clearDeferredSetpointHide();
517
+ return;
518
+ }
519
+ if (this.deferredSetpointHidePhase !== "none") {
520
+ return;
521
+ }
522
+ this.deferredSetpointHidePhase = "hiding";
523
+ window.clearTimeout(this.deferredSetpointHideTimer);
524
+ this.deferredSetpointHideTimer = window.setTimeout(() => {
525
+ this.deferredSetpointHidePhase = "hidden";
526
+ this.deferredSetpointHideTimer = void 0;
527
+ }, 100);
528
+ }
529
+ clearDeferredSetpointHide() {
530
+ if (this.deferredSetpointHidePhase !== "none") {
531
+ this.deferredSetpointHidePhase = "none";
532
+ }
533
+ window.clearTimeout(this.deferredSetpointHideTimer);
534
+ this.deferredSetpointHideTimer = void 0;
535
+ }
536
+ disconnectedCallback() {
537
+ window.clearTimeout(this.deferredSetpointHideTimer);
538
+ this.deferredSetpointHideTimer = void 0;
539
+ if (this.deferredSetpointHidePhase === "hiding") {
540
+ this.deferredSetpointHidePhase = "hidden";
541
+ }
542
+ super.disconnectedCallback();
543
+ }
544
+ render() {
545
+ const clickable = this.resolvedClickable;
546
+ const dataQuality = this.dataQuality;
547
+ const classes = classMap({
548
+ root: true,
549
+ [`size-${this.resolvedSize}`]: true,
550
+ [`stacking-${this.resolvedStacking}`]: true,
551
+ [`priority-${this.resolvedPriority}`]: true,
552
+ "data-low-integrity": dataQuality === "low-integrity",
553
+ "data-invalid": dataQuality === "invalid",
554
+ "flip-flop": this.isFlipFlop,
555
+ clickable: Boolean(clickable),
556
+ [`border-${clickable ? clickable.border : "squared"}`]: Boolean(clickable)
557
+ });
558
+ const surface = html`<div class="surface" part="surface">
559
+ ${this.renderContent()}
560
+ </div>`;
561
+ const root = clickable ? html`<button class=${classes} part="root" type="button">
562
+ ${surface}
563
+ </button>` : html`<div class=${classes} part="root">${surface}</div>`;
564
+ const alert = this.alert === true ? {} : this.alert;
565
+ return wrapWithAlertFrame(alert, root, true);
302
566
  }
303
567
  };
304
568
  ObcReadoutListItem.styles = unsafeCSS(componentStyle);
305
- __decorateClass([
306
- property({ type: String })
307
- ], ObcReadoutListItem.prototype, "size", 2);
308
- __decorateClass([
309
- property({ type: String })
310
- ], ObcReadoutListItem.prototype, "stacking", 2);
311
- __decorateClass([
312
- property({ type: String })
313
- ], ObcReadoutListItem.prototype, "priority", 2);
314
- __decorateClass([
315
- property({ type: String })
316
- ], ObcReadoutListItem.prototype, "dataState", 2);
317
- __decorateClass([
318
- property({ type: Object })
319
- ], ObcReadoutListItem.prototype, "alert", 2);
320
569
  __decorateClass([
321
570
  property({ type: String })
322
571
  ], ObcReadoutListItem.prototype, "label", 2);
@@ -326,55 +575,88 @@ __decorateClass([
326
575
  __decorateClass([
327
576
  property({ type: String })
328
577
  ], ObcReadoutListItem.prototype, "src", 2);
578
+ __decorateClass([
579
+ property({ type: Boolean, attribute: false })
580
+ ], ObcReadoutListItem.prototype, "hasValue", 2);
329
581
  __decorateClass([
330
582
  property({ type: Number })
331
583
  ], ObcReadoutListItem.prototype, "value", 2);
332
584
  __decorateClass([
333
- property({ type: Number })
334
- ], ObcReadoutListItem.prototype, "setpointValue", 2);
585
+ property({ type: Boolean })
586
+ ], ObcReadoutListItem.prototype, "off", 2);
335
587
  __decorateClass([
336
588
  property({ type: Boolean })
337
589
  ], ObcReadoutListItem.prototype, "hasSetpoint", 2);
338
590
  __decorateClass([
339
- property({ type: Boolean })
340
- ], ObcReadoutListItem.prototype, "hasDegree", 2);
591
+ property({ type: Number })
592
+ ], ObcReadoutListItem.prototype, "setpoint", 2);
341
593
  __decorateClass([
342
594
  property({ type: Boolean })
343
- ], ObcReadoutListItem.prototype, "hasUnit", 2);
595
+ ], ObcReadoutListItem.prototype, "hasAdvice", 2);
344
596
  __decorateClass([
345
- property({ type: Boolean })
346
- ], ObcReadoutListItem.prototype, "hasLabel", 2);
597
+ property({ type: Number })
598
+ ], ObcReadoutListItem.prototype, "advice", 2);
347
599
  __decorateClass([
348
- property({ type: Boolean })
349
- ], ObcReadoutListItem.prototype, "hasSource", 2);
600
+ property({ type: String })
601
+ ], ObcReadoutListItem.prototype, "size", 2);
602
+ __decorateClass([
603
+ property({ type: String })
604
+ ], ObcReadoutListItem.prototype, "priority", 2);
605
+ __decorateClass([
606
+ property({ type: String })
607
+ ], ObcReadoutListItem.prototype, "stacking", 2);
608
+ __decorateClass([
609
+ property({ type: Object })
610
+ ], ObcReadoutListItem.prototype, "clickable", 2);
350
611
  __decorateClass([
351
612
  property({ type: Boolean })
352
613
  ], ObcReadoutListItem.prototype, "hasLeadingIcon", 2);
353
614
  __decorateClass([
354
615
  property({ type: Boolean })
355
- ], ObcReadoutListItem.prototype, "hasValueIcon", 2);
616
+ ], ObcReadoutListItem.prototype, "hasDegree", 2);
617
+ __decorateClass([
618
+ property({ type: Boolean })
619
+ ], ObcReadoutListItem.prototype, "hasDegreeSpacer", 2);
356
620
  __decorateClass([
357
621
  property({ type: Number })
358
622
  ], ObcReadoutListItem.prototype, "fractionDigits", 2);
359
- __decorateClass([
360
- property({ type: Boolean })
361
- ], ObcReadoutListItem.prototype, "showZeroPadding", 2);
362
623
  __decorateClass([
363
624
  property({ type: Number })
364
- ], ObcReadoutListItem.prototype, "minValueLength", 2);
625
+ ], ObcReadoutListItem.prototype, "maxDigits", 2);
365
626
  __decorateClass([
366
- property({ type: Boolean })
367
- ], ObcReadoutListItem.prototype, "hasHintedZeros", 2);
627
+ property({ type: String })
628
+ ], ObcReadoutListItem.prototype, "dataQuality", 2);
368
629
  __decorateClass([
369
- property({ type: Boolean })
370
- ], ObcReadoutListItem.prototype, "labelOnly", 2);
630
+ property({ type: Object })
631
+ ], ObcReadoutListItem.prototype, "alert", 2);
632
+ __decorateClass([
633
+ property({ type: Object })
634
+ ], ObcReadoutListItem.prototype, "valueOptions", 2);
635
+ __decorateClass([
636
+ property({ type: Object })
637
+ ], ObcReadoutListItem.prototype, "setpointOptions", 2);
638
+ __decorateClass([
639
+ property({ type: Object })
640
+ ], ObcReadoutListItem.prototype, "adviceOptions", 2);
641
+ __decorateClass([
642
+ property({ type: Object })
643
+ ], ObcReadoutListItem.prototype, "unitOptions", 2);
644
+ __decorateClass([
645
+ property({ type: Object })
646
+ ], ObcReadoutListItem.prototype, "srcOptions", 2);
647
+ __decorateClass([
648
+ state()
649
+ ], ObcReadoutListItem.prototype, "deferredSetpointHidePhase", 2);
371
650
  ObcReadoutListItem = __decorateClass([
372
651
  customElement("obc-readout-list-item")
373
652
  ], ObcReadoutListItem);
374
653
  export {
375
654
  ObcReadoutListItem,
376
- ReadoutListItemDataState,
655
+ ObcTextboxFontWeight,
656
+ ReadoutListItemBorder,
657
+ ReadoutListItemDataQuality,
377
658
  ReadoutListItemPriority,
659
+ ReadoutListItemSetpointInteraction,
378
660
  ReadoutListItemSize,
379
661
  ReadoutListItemStacking
380
662
  };