@oicl/openbridge-webcomponents 2.0.0-next.121 → 2.0.0-next.122

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 (29) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +233 -53
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +66 -17
  4. package/dist/automation/automation-tank/automation-tank.css.js +94 -14
  5. package/dist/automation/automation-tank/automation-tank.css.js.map +1 -1
  6. package/dist/automation/automation-tank/automation-tank.d.ts +53 -5
  7. package/dist/automation/automation-tank/automation-tank.d.ts.map +1 -1
  8. package/dist/automation/automation-tank/automation-tank.js +39 -20
  9. package/dist/automation/automation-tank/automation-tank.js.map +1 -1
  10. package/dist/building-blocks/readout-block/readout-block.d.ts +27 -1
  11. package/dist/building-blocks/readout-block/readout-block.d.ts.map +1 -1
  12. package/dist/building-blocks/readout-block/readout-block.js +31 -10
  13. package/dist/building-blocks/readout-block/readout-block.js.map +1 -1
  14. package/dist/navigation-instruments/readout/readout-formatters.d.ts +61 -0
  15. package/dist/navigation-instruments/readout/readout-formatters.d.ts.map +1 -1
  16. package/dist/navigation-instruments/readout/readout-formatters.js +35 -2
  17. package/dist/navigation-instruments/readout/readout-formatters.js.map +1 -1
  18. package/dist/navigation-instruments/readout/readout.d.ts +19 -2
  19. package/dist/navigation-instruments/readout/readout.d.ts.map +1 -1
  20. package/dist/navigation-instruments/readout/readout.js +18 -4
  21. package/dist/navigation-instruments/readout/readout.js.map +1 -1
  22. package/dist/navigation-instruments/readout-list/readout-list.d.ts.map +1 -1
  23. package/dist/navigation-instruments/readout-list/readout-list.js +6 -3
  24. package/dist/navigation-instruments/readout-list/readout-list.js.map +1 -1
  25. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +19 -2
  26. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  27. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +18 -4
  28. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  29. package/package.json +1 -1
@@ -19087,6 +19087,42 @@ const compentStyle$19 = i$7`* {
19087
19087
  min-height: 0;
19088
19088
  }
19089
19089
 
19090
+ /* Indefinite-axis fallback.
19091
+ *
19092
+ * \`width\`/\`height: 100%\` only resolve when the parent's corresponding axis is
19093
+ * definite. In a flex/grid dashboard slot one axis is very often left to
19094
+ * content — \`align-self: center\` makes the cross axis shrink-to-fit, and a
19095
+ * parent sized with \`min-height\`/\`max-height\` (rather than \`height\`) leaves the
19096
+ * block axis indefinite. In those cases the percentage computes to \`auto\` and
19097
+ * the tank would size to its own content, which includes the chart cell — and
19098
+ * the chart sizes itself from the cell it was measured in. That is a circular
19099
+ * constraint, and it resolves as a collapsed cell, unbounded growth or
19100
+ * pixel-level ringing depending on the loop gain (issue #1121).
19101
+ *
19102
+ * \`aspect-ratio\` supplies the missing axis from the design footprint the
19103
+ * \`point\` variant uses above, so an indefinite axis lands on a definite value
19104
+ * that no longer depends on the tank's own content. It is inert when the parent
19105
+ * makes both axes definite, so the normal "fill my slot" behavior is unchanged.
19106
+ */
19107
+
19108
+ :host([positioning="button"]) {
19109
+ aspect-ratio: 256 / 376;
19110
+ }
19111
+
19112
+ :host([positioning="button"][orientation="horizontal"]) {
19113
+ aspect-ratio: 420 / 256;
19114
+ }
19115
+
19116
+ :host([positioning="button"][compact]),
19117
+ :host([positioning="button"][static]) {
19118
+ aspect-ratio: 170 / 282;
19119
+ }
19120
+
19121
+ :host([positioning="button"][orientation="horizontal"][compact]),
19122
+ :host([positioning="button"][orientation="horizontal"][static]) {
19123
+ aspect-ratio: 244 / 208;
19124
+ }
19125
+
19090
19126
  :host([positioning="button"]) .root {
19091
19127
  position: static;
19092
19128
  top: auto;
@@ -19147,19 +19183,26 @@ const compentStyle$19 = i$7`* {
19147
19183
  display: flex;
19148
19184
  flex-direction: column;
19149
19185
  gap: 4px;
19186
+ }
19187
+
19188
+ /* Interactive (\`clickable\`, the default): the full six-state flat mixin —
19189
+ * enabled, activated, hover, pressed, focus-visible, disabled — painted on
19190
+ * \`.halo\`. */
19191
+
19192
+ .root.clickable {
19150
19193
  cursor: pointer;
19151
19194
  /* prettier-ignore */
19152
19195
  }
19153
19196
 
19154
- .root {
19197
+ .root.clickable {
19155
19198
  cursor: pointer;
19156
19199
  }
19157
19200
 
19158
- .root:focus {
19201
+ .root.clickable:focus {
19159
19202
  outline: none;
19160
19203
  }
19161
19204
 
19162
- .root .halo {
19205
+ .root.clickable .halo {
19163
19206
  border-color: var(--flat-enabled-border-color);
19164
19207
  background-color: var(--flat-enabled-background-color);
19165
19208
  border-width: 1px;
@@ -19169,7 +19212,7 @@ const compentStyle$19 = i$7`* {
19169
19212
  --base-background-color: var(--flat-enabled-background-color);
19170
19213
  }
19171
19214
 
19172
- .root.activated .halo {
19215
+ .root.clickable.activated .halo {
19173
19216
  border-color: var(--flat-activated-border-color);
19174
19217
  background-color: var(--flat-activated-background-color);
19175
19218
  --base-border-color: var(--flat-activated-border-color);
@@ -19178,18 +19221,18 @@ const compentStyle$19 = i$7`* {
19178
19221
 
19179
19222
  @media (hover:hover) {
19180
19223
 
19181
- .root:hover .halo {
19224
+ .root.clickable:hover .halo {
19182
19225
  border-color: color-mix(in srgb, var(--flat-hover-border-color) calc(var(--obc-can-hover) * 100%), var(--base-border-color));
19183
19226
  background-color: color-mix(in srgb, var(--flat-hover-background-color) calc(var(--obc-can-hover) * 100%), var(--base-background-color));
19184
19227
  }
19185
19228
  }
19186
19229
 
19187
- .root:active .halo {
19230
+ .root.clickable:active .halo {
19188
19231
  border-color: var(--flat-pressed-border-color);
19189
19232
  background-color: var(--flat-pressed-background-color);
19190
19233
  }
19191
19234
 
19192
- .root:focus-visible .halo {
19235
+ .root.clickable:focus-visible .halo {
19193
19236
  outline-color: var(--border-focus-color);
19194
19237
  outline-width: var(--global-size-spacing-border-weight-focusframe);
19195
19238
  outline-style: solid;
@@ -19197,28 +19240,50 @@ const compentStyle$19 = i$7`* {
19197
19240
  z-index: 1;
19198
19241
  }
19199
19242
 
19200
- .root:disabled .halo {
19243
+ .root.clickable:disabled .halo {
19201
19244
  border-color: var(--flat-disabled-border-color);
19202
19245
  background-color: var(--flat-disabled-background-color);
19203
19246
  cursor: not-allowed;
19204
19247
  color: var(--on-flat-disabled-color) !important;
19205
19248
  }
19206
19249
 
19207
- .root.disabled .halo {
19250
+ .root.clickable.disabled .halo {
19208
19251
  border-color: var(--flat-disabled-border-color);
19209
19252
  background-color: var(--flat-disabled-background-color);
19210
19253
  cursor: not-allowed;
19211
19254
  color: var(--on-flat-disabled-color) !important;
19212
19255
  }
19213
19256
 
19214
- .root:disabled {
19257
+ .root.clickable:disabled {
19215
19258
  cursor: not-allowed;
19216
19259
  }
19217
19260
 
19218
- .root.disabled {
19261
+ .root.clickable.disabled {
19219
19262
  cursor: not-allowed;
19220
19263
  }
19221
19264
 
19265
+ /* Non-interactive (\`clickable\` is \`false\`, and \`static\`, which is display-only
19266
+ * by definition): the mixin's \`noClick\` variant emits the enabled state ONLY, so
19267
+ * the halo keeps exactly the same resting colors and the same 1px border box
19268
+ * — no layout shift, nothing else in the tank changes — while hover, pressed
19269
+ * and focus-visible disappear. The root is a \`<div>\` in this case, so there is
19270
+ * no focus ring or tab stop to suppress either. Same split as
19271
+ * \`obc-elevated-card\`'s \`.not-clickable\` / \`:not(.not-clickable)\` pair. */
19272
+
19273
+ .root:not(.clickable) {
19274
+ cursor: default;
19275
+ /* prettier-ignore */
19276
+ }
19277
+
19278
+ .root:not(.clickable) .halo {
19279
+ border-color: var(--flat-enabled-border-color);
19280
+ background-color: var(--flat-enabled-background-color);
19281
+ border-width: 1px;
19282
+ border-style: solid;
19283
+ --base-border-color: var(--flat-enabled-border-color);
19284
+ --base-background-color: var(--flat-enabled-background-color);
19285
+ }
19286
+
19222
19287
  .root:focus {
19223
19288
  outline: none;
19224
19289
  }
@@ -19238,11 +19303,13 @@ const compentStyle$19 = i$7`* {
19238
19303
  top: auto;
19239
19304
  }
19240
19305
 
19241
- /* Static is display-only: not focusable (rendered as <div>) and not
19242
- * interactive disable :hover/:active visuals from the flat-mixin rules. */
19306
+ /* Static is display-only, so it never gets the \`.clickable\` class and the
19307
+ * hover/pressed visuals are already gone via the \`noClick\` rule above. Static
19308
+ * additionally refuses pointer events outright — unlike a non-clickable tank,
19309
+ * which still lets clicks reach the host so a consumer can opt into handling
19310
+ * them. */
19243
19311
 
19244
19312
  :host([static]) .root {
19245
- cursor: default;
19246
19313
  pointer-events: none;
19247
19314
  }
19248
19315
 
@@ -19690,9 +19757,22 @@ const compentStyle$19 = i$7`* {
19690
19757
  overflow: hidden;
19691
19758
  }
19692
19759
 
19760
+ /* The renderers are taken out of flow so the cell sizes them, never the other
19761
+ * way round. Both of them derive a pixel size from the box they are measured
19762
+ * in — \`obc-gauge-trend\` publishes an inline \`--chart-height\` computed from its
19763
+ * own measured width, and \`obc-bar-vertical\` writes \`height: 100%; width: auto\`
19764
+ * onto its own host — so while they are in flow the cell's content height is a
19765
+ * function of the cell's own height. Absolute positioning severs that return
19766
+ * path: \`.bar-container\` is \`position: relative\`, so \`inset: 0\` pins the
19767
+ * renderer to the cell the tank's grid/flex layout already decided on, and a
19768
+ * rounding difference between the two can no longer relayout the tank
19769
+ * (issue #1121). */
19770
+
19693
19771
  .bar-container > obc-gauge-trend,
19694
19772
  .bar-container > obc-bar-vertical {
19695
19773
  display: block;
19774
+ position: absolute;
19775
+ inset: 0;
19696
19776
  width: 100%;
19697
19777
  height: 100%;
19698
19778
  }
@@ -37653,6 +37733,7 @@ let ObcAutomationTank = class extends SetpointMixin(i$4) {
37653
37733
  this.compact = false;
37654
37734
  this.positioning = "button";
37655
37735
  this.static = false;
37736
+ this.clickable = true;
37656
37737
  this.activated = false;
37657
37738
  this.tag = "";
37658
37739
  this.chartMode = "bar";
@@ -38188,26 +38269,41 @@ let ObcAutomationTank = class extends SetpointMixin(i$4) {
38188
38269
  const halo = b`
38189
38270
  <div class="halo">${haloContents}${alertFrameOverlay}</div>
38190
38271
  `;
38191
- const rootClasses = e$1({ root: true, activated: this.activated });
38192
- return b`
38193
- ${this.static ? b`<div
38194
- class=${rootClasses}
38195
- role="img"
38196
- aria-label=${this.tag || "Tank"}
38197
- aria-live="polite"
38198
- aria-atomic="true"
38199
- >
38200
- ${halo}
38201
- </div>` : b`<button
38202
- class=${rootClasses}
38203
- type="button"
38204
- aria-label=${this.tag || "Tank"}
38205
- aria-live="polite"
38206
- aria-atomic="true"
38207
- >
38208
- ${halo}
38209
- </button>`}
38210
- `;
38272
+ const isClickable = this.clickable && !this.static;
38273
+ const rootClasses = e$1({
38274
+ root: true,
38275
+ activated: this.activated,
38276
+ clickable: isClickable
38277
+ });
38278
+ if (this.static) {
38279
+ return b`<div
38280
+ class=${rootClasses}
38281
+ role="img"
38282
+ aria-label=${this.tag || "Tank"}
38283
+ aria-live="polite"
38284
+ aria-atomic="true"
38285
+ >
38286
+ ${halo}
38287
+ </div>`;
38288
+ }
38289
+ if (!isClickable) {
38290
+ return b`<div
38291
+ class=${rootClasses}
38292
+ aria-live="polite"
38293
+ aria-atomic="true"
38294
+ >
38295
+ ${halo}
38296
+ </div>`;
38297
+ }
38298
+ return b`<button
38299
+ class=${rootClasses}
38300
+ type="button"
38301
+ aria-label=${this.tag || "Tank"}
38302
+ aria-live="polite"
38303
+ aria-atomic="true"
38304
+ >
38305
+ ${halo}
38306
+ </button>`;
38211
38307
  }
38212
38308
  };
38213
38309
  ObcAutomationTank.styles = r$7(compentStyle$19);
@@ -38238,6 +38334,9 @@ __decorateClass$zk([
38238
38334
  __decorateClass$zk([
38239
38335
  n$3({ type: Boolean, reflect: true })
38240
38336
  ], ObcAutomationTank.prototype, "static", 2);
38337
+ __decorateClass$zk([
38338
+ n$3({ type: Boolean, attribute: false })
38339
+ ], ObcAutomationTank.prototype, "clickable", 2);
38241
38340
  __decorateClass$zk([
38242
38341
  n$3({ type: Boolean })
38243
38342
  ], ObcAutomationTank.prototype, "activated", 2);
@@ -57317,6 +57416,34 @@ const READOUT_VALUE_TYPES = Object.values(ReadoutValueType);
57317
57416
  function isReadoutValueType(value) {
57318
57417
  return typeof value === "string" && READOUT_VALUE_TYPES.includes(value);
57319
57418
  }
57419
+ const READOUT_MAX_DIGITS = 100;
57420
+ function effectiveFractionDigits(fractionDigits) {
57421
+ if (fractionDigits === null || fractionDigits === void 0) {
57422
+ return 0;
57423
+ }
57424
+ return Number.isNaN(fractionDigits) ? 0 : Math.trunc(fractionDigits);
57425
+ }
57426
+ function assertReadoutFractionDigits(tagName, fractionDigits) {
57427
+ const digits = effectiveFractionDigits(fractionDigits);
57428
+ if (Number.isFinite(digits) && digits >= 0 && digits <= READOUT_MAX_DIGITS) {
57429
+ return;
57430
+ }
57431
+ throw new RangeError(
57432
+ // `String`, not `JSON.stringify`: the latter serialises `Infinity` and
57433
+ // `NaN` to `null`, hiding the very value being rejected.
57434
+ `<${tagName}>: fractionDigits must be between 0 and ${READOUT_MAX_DIGITS} (got ${String(fractionDigits)}).`
57435
+ );
57436
+ }
57437
+ function resolveReadoutDigitCount(count) {
57438
+ const digits = Math.trunc(count ?? 0);
57439
+ if (Number.isNaN(digits) || digits <= 0) {
57440
+ return 0;
57441
+ }
57442
+ return Math.min(digits, READOUT_MAX_DIGITS);
57443
+ }
57444
+ function isReadoutDigitCountMissing(count) {
57445
+ return count === null || count === void 0 || Number.isNaN(count);
57446
+ }
57320
57447
  function isBlank(value) {
57321
57448
  return value.trim() === "";
57322
57449
  }
@@ -57361,9 +57488,10 @@ const READOUT_UNAVAILABLE_DASH = "‒";
57361
57488
  function dashedGenerator({
57362
57489
  showZeroPadding,
57363
57490
  minValueLength,
57364
- fractionDigits
57491
+ fractionDigits: rawFractionDigits
57365
57492
  }) {
57366
57493
  const visibleDigits = showZeroPadding ? Math.max(minValueLength, 1) : 1;
57494
+ const fractionDigits = Number.isNaN(rawFractionDigits) ? 0 : rawFractionDigits;
57367
57495
  if (fractionDigits < 1) {
57368
57496
  return READOUT_UNAVAILABLE_DASH.repeat(visibleDigits);
57369
57497
  }
@@ -57371,7 +57499,7 @@ function dashedGenerator({
57371
57499
  return READOUT_UNAVAILABLE_DASH.repeat(Math.max(integerDigits, 1)) + "." + READOUT_UNAVAILABLE_DASH.repeat(fractionDigits);
57372
57500
  }
57373
57501
  function formatNumericValue(value, options) {
57374
- if (value === void 0 || !Number.isFinite(value)) {
57502
+ if (value === void 0 || !Number.isFinite(value) || Number.isNaN(options.fractionDigits)) {
57375
57503
  return dashedGenerator(options);
57376
57504
  }
57377
57505
  return value.toFixed(options.fractionDigits);
@@ -57456,23 +57584,46 @@ let ObcReadoutBlock = class extends i$4 {
57456
57584
  return ObcTextboxSize.s;
57457
57585
  }
57458
57586
  }
57587
+ /**
57588
+ * `maxDigits` bounded to a usable count. Every width calculation below goes
57589
+ * through this rather than the raw property, so an `Infinity` (or absurdly
57590
+ * large) value cannot reach `String.prototype.repeat`.
57591
+ */
57592
+ get resolvedMaxDigits() {
57593
+ return resolveReadoutDigitCount(this.maxDigits);
57594
+ }
57595
+ /**
57596
+ * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
57597
+ * The reading then renders as the unavailable dash rather than silently
57598
+ * formatting with a default the author never chose — a critical `0.4`
57599
+ * formatted with a failed `fractionDigits` would otherwise print as a
57600
+ * plausible-looking `0`. A missing `maxDigits` dashes too, for consistency:
57601
+ * either knob arriving broken means the row's configuration cannot be
57602
+ * trusted.
57603
+ */
57604
+ get digitCountsMissing() {
57605
+ return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits);
57606
+ }
57459
57607
  get numericFormatOptions() {
57460
57608
  return {
57461
57609
  // The unavailable placeholder stays short (`\u2012.\u2012\u2012`) rather than
57462
57610
  // spelling out every reserved digit position — `maxDigits` already
57463
57611
  // reserves the width, so it simply sits at the right edge of it.
57464
57612
  showZeroPadding: false,
57465
- minValueLength: this.maxDigits,
57466
- fractionDigits: this.fractionDigits
57613
+ minValueLength: this.resolvedMaxDigits,
57614
+ // A missing precision shapes the placeholder as zero fraction digits (a
57615
+ // single dash) — and keeps a runtime `undefined`/`null` out of the
57616
+ // options object, which is typed `number` throughout the formatters.
57617
+ fractionDigits: isReadoutDigitCountMissing(this.fractionDigits) ? 0 : this.fractionDigits
57467
57618
  };
57468
57619
  }
57469
57620
  /** Widest possible value string for width reservation (e.g. `"000.0"`). */
57470
57621
  get reserverText() {
57471
- const maxDigits = this.maxDigits;
57622
+ const maxDigits = this.resolvedMaxDigits;
57472
57623
  if (maxDigits <= 0) {
57473
57624
  return "";
57474
57625
  }
57475
- const integer = "0".repeat(Math.max(maxDigits, 1));
57626
+ const integer = "0".repeat(maxDigits);
57476
57627
  return this.fractionDigits > 0 ? `${integer}.${"0".repeat(this.fractionDigits)}` : integer;
57477
57628
  }
57478
57629
  /**
@@ -57536,18 +57687,16 @@ let ObcReadoutBlock = class extends i$4 {
57536
57687
  willUpdate(changed) {
57537
57688
  super.willUpdate(changed);
57538
57689
  assertReadoutValueType("obc-readout-block", this.value, this.valueType);
57690
+ assertReadoutFractionDigits("obc-readout-block", this.fractionDigits);
57539
57691
  }
57540
57692
  render() {
57541
57693
  const valueSize = this.resolvedValueSize;
57542
57694
  const formatOptions = this.numericFormatOptions;
57543
57695
  const isTextMode = this.valueType === ReadoutValueType.text;
57544
- const valueForFormat = resolveReadoutNumericValue(
57545
- this.value,
57546
- this.valueType
57547
- );
57696
+ const valueForFormat = this.digitCountsMissing ? void 0 : resolveReadoutNumericValue(this.value, this.valueType);
57548
57697
  const textValue = resolveReadoutTextValue(this.value, this.valueType);
57549
57698
  const text = this.off ? this.offText : isTextMode ? textValue ?? READOUT_UNAVAILABLE_DASH : formatNumericValue(valueForFormat, formatOptions);
57550
- const hintCount = this.off || isTextMode || !this.hintedZeros || valueForFormat === void 0 || valueForFormat < 0 ? 0 : Math.max(this.maxDigits - readoutFormattedInteger(text), 0);
57699
+ const hintCount = this.off || isTextMode || !this.hintedZeros || valueForFormat === void 0 || valueForFormat < 0 ? 0 : Math.max(this.resolvedMaxDigits - readoutFormattedInteger(text), 0);
57551
57700
  const hinted = hintCount > 0 ? "0".repeat(hintCount) : "";
57552
57701
  const reserver = isTextMode ? this.spaceReserver ?? "" : this.hintedZeros ? this.reserverText : this.widerReserver(this.spaceReserver, this.reserverText);
57553
57702
  const block = b`
@@ -59167,7 +59316,17 @@ let ObcReadoutListItem = class extends i$4 {
59167
59316
  return this.fractionDigits ?? 0;
59168
59317
  }
59169
59318
  get resolvedMaxDigits() {
59170
- return this.maxDigits ?? 0;
59319
+ return resolveReadoutDigitCount(this.maxDigits);
59320
+ }
59321
+ /**
59322
+ * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
59323
+ * The raw knobs are forwarded to the blocks, which render the reading as
59324
+ * the unavailable dash (see `obc-readout-block.digitCountsMissing`); this
59325
+ * getter only keeps the setpoint comparison in agreement with what is
59326
+ * displayed.
59327
+ */
59328
+ get digitCountsMissing() {
59329
+ return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits);
59171
59330
  }
59172
59331
  get resolvedClickable() {
59173
59332
  const clickable = this.clickable;
@@ -59189,6 +59348,9 @@ let ObcReadoutListItem = class extends i$4 {
59189
59348
  if (!this.hasSetpoint) {
59190
59349
  return false;
59191
59350
  }
59351
+ if (this.digitCountsMissing) {
59352
+ return false;
59353
+ }
59192
59354
  return isDisplayedAtSetpoint(
59193
59355
  resolveReadoutNumericValue(this.value, this.valueType) ?? null,
59194
59356
  this.setpoint,
@@ -59290,8 +59452,8 @@ let ObcReadoutListItem = class extends i$4 {
59290
59452
  .weight=${config.weight}
59291
59453
  .hasDegree=${config.hasDegree ?? false}
59292
59454
  .hasIcon=${config.hasIcon ?? false}
59293
- .fractionDigits=${this.resolvedFractionDigits}
59294
- .maxDigits=${this.resolvedMaxDigits}
59455
+ .fractionDigits=${this.fractionDigits}
59456
+ .maxDigits=${this.maxDigits}
59295
59457
  .hintedZeros=${config.hintedZeros}
59296
59458
  .spaceReserver=${config.spaceReserver}
59297
59459
  .off=${config.off ?? false}
@@ -59588,6 +59750,7 @@ let ObcReadoutListItem = class extends i$4 {
59588
59750
  willUpdate(changed) {
59589
59751
  super.willUpdate(changed);
59590
59752
  assertReadoutValueType("obc-readout-list-item", this.value, this.valueType);
59753
+ assertReadoutFractionDigits("obc-readout-list-item", this.fractionDigits);
59591
59754
  }
59592
59755
  updated(changed) {
59593
59756
  super.updated(changed);
@@ -64375,7 +64538,17 @@ let ObcReadout = class extends i$4 {
64375
64538
  return this.fractionDigits ?? 0;
64376
64539
  }
64377
64540
  get resolvedMaxDigits() {
64378
- return this.maxDigits ?? 0;
64541
+ return resolveReadoutDigitCount(this.maxDigits);
64542
+ }
64543
+ /**
64544
+ * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
64545
+ * The raw knobs are forwarded to the blocks, which render the reading as
64546
+ * the unavailable dash (see `obc-readout-block.digitCountsMissing`); this
64547
+ * getter only keeps the setpoint comparison in agreement with what is
64548
+ * displayed.
64549
+ */
64550
+ get digitCountsMissing() {
64551
+ return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits);
64379
64552
  }
64380
64553
  get hasSrc() {
64381
64554
  return this.src !== void 0 && this.src.trim() !== "";
@@ -64387,6 +64560,9 @@ let ObcReadout = class extends i$4 {
64387
64560
  if (!this.hasSetpoint) {
64388
64561
  return false;
64389
64562
  }
64563
+ if (this.digitCountsMissing) {
64564
+ return false;
64565
+ }
64390
64566
  return isDisplayedAtSetpoint(
64391
64567
  resolveReadoutNumericValue(this.value, this.valueType) ?? null,
64392
64568
  this.setpoint,
@@ -64497,8 +64673,8 @@ let ObcReadout = class extends i$4 {
64497
64673
  .weight=${config.weight}
64498
64674
  .hasDegree=${config.hasDegree ?? false}
64499
64675
  .hasIcon=${config.hasIcon ?? false}
64500
- .fractionDigits=${this.resolvedFractionDigits}
64501
- .maxDigits=${this.resolvedMaxDigits}
64676
+ .fractionDigits=${this.fractionDigits}
64677
+ .maxDigits=${this.maxDigits}
64502
64678
  .hintedZeros=${config.hintedZeros}
64503
64679
  .spaceReserver=${config.spaceReserver}
64504
64680
  .off=${config.off ?? false}
@@ -64971,6 +65147,7 @@ let ObcReadout = class extends i$4 {
64971
65147
  willUpdate(changed) {
64972
65148
  super.willUpdate(changed);
64973
65149
  assertReadoutValueType("obc-readout", this.value, this.valueType);
65150
+ assertReadoutFractionDigits("obc-readout", this.fractionDigits);
64974
65151
  }
64975
65152
  updated(changed) {
64976
65153
  super.updated(changed);
@@ -227720,9 +227897,12 @@ let ObcReadoutList = class extends i$4 {
227720
227897
  if (hasNumericBlock) {
227721
227898
  maxFractionDigits = Math.max(
227722
227899
  maxFractionDigits,
227723
- item.fractionDigits ?? 0
227900
+ resolveReadoutDigitCount(item.fractionDigits)
227901
+ );
227902
+ maxIntegerDigits = Math.max(
227903
+ maxIntegerDigits,
227904
+ resolveReadoutDigitCount(item.maxDigits)
227724
227905
  );
227725
- maxIntegerDigits = Math.max(maxIntegerDigits, item.maxDigits ?? 0);
227726
227906
  }
227727
227907
  maxIntegerDigits = Math.max(
227728
227908
  maxIntegerDigits,