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

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 (38) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +252 -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/compass-sector/compass-sector.css.js +10 -0
  15. package/dist/navigation-instruments/compass-sector/compass-sector.css.js.map +1 -1
  16. package/dist/navigation-instruments/readout/readout-formatters.d.ts +61 -0
  17. package/dist/navigation-instruments/readout/readout-formatters.d.ts.map +1 -1
  18. package/dist/navigation-instruments/readout/readout-formatters.js +35 -2
  19. package/dist/navigation-instruments/readout/readout-formatters.js.map +1 -1
  20. package/dist/navigation-instruments/readout/readout.d.ts +19 -2
  21. package/dist/navigation-instruments/readout/readout.d.ts.map +1 -1
  22. package/dist/navigation-instruments/readout/readout.js +18 -4
  23. package/dist/navigation-instruments/readout/readout.js.map +1 -1
  24. package/dist/navigation-instruments/readout-list/readout-list.d.ts.map +1 -1
  25. package/dist/navigation-instruments/readout-list/readout-list.js +6 -3
  26. package/dist/navigation-instruments/readout-list/readout-list.js.map +1 -1
  27. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +19 -2
  28. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  29. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +18 -4
  30. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  31. package/dist/navigation-instruments/thruster/thruster.d.ts.map +1 -1
  32. package/dist/navigation-instruments/thruster/thruster.js +1 -0
  33. package/dist/navigation-instruments/thruster/thruster.js.map +1 -1
  34. package/dist/navigation-instruments/watch/watch.css.js +4 -0
  35. package/dist/navigation-instruments/watch/watch.css.js.map +1 -1
  36. package/dist/navigation-instruments/watch-flat/watch-flat.css.js +4 -0
  37. package/dist/navigation-instruments/watch-flat/watch-flat.css.js.map +1 -1
  38. 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);
@@ -52500,6 +52599,10 @@ const compentStyle$15 = i$7`* {
52500
52599
  overflow: hidden;
52501
52600
  }
52502
52601
 
52602
+ svg {
52603
+ display: block;
52604
+ }
52605
+
52503
52606
  .label {
52504
52607
  font-family: var(--global-typography-font-family);
52505
52608
  font-weight: var(--global-typography-ui-body-font-weight);
@@ -57317,6 +57420,34 @@ const READOUT_VALUE_TYPES = Object.values(ReadoutValueType);
57317
57420
  function isReadoutValueType(value) {
57318
57421
  return typeof value === "string" && READOUT_VALUE_TYPES.includes(value);
57319
57422
  }
57423
+ const READOUT_MAX_DIGITS = 100;
57424
+ function effectiveFractionDigits(fractionDigits) {
57425
+ if (fractionDigits === null || fractionDigits === void 0) {
57426
+ return 0;
57427
+ }
57428
+ return Number.isNaN(fractionDigits) ? 0 : Math.trunc(fractionDigits);
57429
+ }
57430
+ function assertReadoutFractionDigits(tagName, fractionDigits) {
57431
+ const digits = effectiveFractionDigits(fractionDigits);
57432
+ if (Number.isFinite(digits) && digits >= 0 && digits <= READOUT_MAX_DIGITS) {
57433
+ return;
57434
+ }
57435
+ throw new RangeError(
57436
+ // `String`, not `JSON.stringify`: the latter serialises `Infinity` and
57437
+ // `NaN` to `null`, hiding the very value being rejected.
57438
+ `<${tagName}>: fractionDigits must be between 0 and ${READOUT_MAX_DIGITS} (got ${String(fractionDigits)}).`
57439
+ );
57440
+ }
57441
+ function resolveReadoutDigitCount(count) {
57442
+ const digits = Math.trunc(count ?? 0);
57443
+ if (Number.isNaN(digits) || digits <= 0) {
57444
+ return 0;
57445
+ }
57446
+ return Math.min(digits, READOUT_MAX_DIGITS);
57447
+ }
57448
+ function isReadoutDigitCountMissing(count) {
57449
+ return count === null || count === void 0 || Number.isNaN(count);
57450
+ }
57320
57451
  function isBlank(value) {
57321
57452
  return value.trim() === "";
57322
57453
  }
@@ -57361,9 +57492,10 @@ const READOUT_UNAVAILABLE_DASH = "‒";
57361
57492
  function dashedGenerator({
57362
57493
  showZeroPadding,
57363
57494
  minValueLength,
57364
- fractionDigits
57495
+ fractionDigits: rawFractionDigits
57365
57496
  }) {
57366
57497
  const visibleDigits = showZeroPadding ? Math.max(minValueLength, 1) : 1;
57498
+ const fractionDigits = Number.isNaN(rawFractionDigits) ? 0 : rawFractionDigits;
57367
57499
  if (fractionDigits < 1) {
57368
57500
  return READOUT_UNAVAILABLE_DASH.repeat(visibleDigits);
57369
57501
  }
@@ -57371,7 +57503,7 @@ function dashedGenerator({
57371
57503
  return READOUT_UNAVAILABLE_DASH.repeat(Math.max(integerDigits, 1)) + "." + READOUT_UNAVAILABLE_DASH.repeat(fractionDigits);
57372
57504
  }
57373
57505
  function formatNumericValue(value, options) {
57374
- if (value === void 0 || !Number.isFinite(value)) {
57506
+ if (value === void 0 || !Number.isFinite(value) || Number.isNaN(options.fractionDigits)) {
57375
57507
  return dashedGenerator(options);
57376
57508
  }
57377
57509
  return value.toFixed(options.fractionDigits);
@@ -57456,23 +57588,46 @@ let ObcReadoutBlock = class extends i$4 {
57456
57588
  return ObcTextboxSize.s;
57457
57589
  }
57458
57590
  }
57591
+ /**
57592
+ * `maxDigits` bounded to a usable count. Every width calculation below goes
57593
+ * through this rather than the raw property, so an `Infinity` (or absurdly
57594
+ * large) value cannot reach `String.prototype.repeat`.
57595
+ */
57596
+ get resolvedMaxDigits() {
57597
+ return resolveReadoutDigitCount(this.maxDigits);
57598
+ }
57599
+ /**
57600
+ * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
57601
+ * The reading then renders as the unavailable dash rather than silently
57602
+ * formatting with a default the author never chose — a critical `0.4`
57603
+ * formatted with a failed `fractionDigits` would otherwise print as a
57604
+ * plausible-looking `0`. A missing `maxDigits` dashes too, for consistency:
57605
+ * either knob arriving broken means the row's configuration cannot be
57606
+ * trusted.
57607
+ */
57608
+ get digitCountsMissing() {
57609
+ return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits);
57610
+ }
57459
57611
  get numericFormatOptions() {
57460
57612
  return {
57461
57613
  // The unavailable placeholder stays short (`\u2012.\u2012\u2012`) rather than
57462
57614
  // spelling out every reserved digit position — `maxDigits` already
57463
57615
  // reserves the width, so it simply sits at the right edge of it.
57464
57616
  showZeroPadding: false,
57465
- minValueLength: this.maxDigits,
57466
- fractionDigits: this.fractionDigits
57617
+ minValueLength: this.resolvedMaxDigits,
57618
+ // A missing precision shapes the placeholder as zero fraction digits (a
57619
+ // single dash) — and keeps a runtime `undefined`/`null` out of the
57620
+ // options object, which is typed `number` throughout the formatters.
57621
+ fractionDigits: isReadoutDigitCountMissing(this.fractionDigits) ? 0 : this.fractionDigits
57467
57622
  };
57468
57623
  }
57469
57624
  /** Widest possible value string for width reservation (e.g. `"000.0"`). */
57470
57625
  get reserverText() {
57471
- const maxDigits = this.maxDigits;
57626
+ const maxDigits = this.resolvedMaxDigits;
57472
57627
  if (maxDigits <= 0) {
57473
57628
  return "";
57474
57629
  }
57475
- const integer = "0".repeat(Math.max(maxDigits, 1));
57630
+ const integer = "0".repeat(maxDigits);
57476
57631
  return this.fractionDigits > 0 ? `${integer}.${"0".repeat(this.fractionDigits)}` : integer;
57477
57632
  }
57478
57633
  /**
@@ -57536,18 +57691,16 @@ let ObcReadoutBlock = class extends i$4 {
57536
57691
  willUpdate(changed) {
57537
57692
  super.willUpdate(changed);
57538
57693
  assertReadoutValueType("obc-readout-block", this.value, this.valueType);
57694
+ assertReadoutFractionDigits("obc-readout-block", this.fractionDigits);
57539
57695
  }
57540
57696
  render() {
57541
57697
  const valueSize = this.resolvedValueSize;
57542
57698
  const formatOptions = this.numericFormatOptions;
57543
57699
  const isTextMode = this.valueType === ReadoutValueType.text;
57544
- const valueForFormat = resolveReadoutNumericValue(
57545
- this.value,
57546
- this.valueType
57547
- );
57700
+ const valueForFormat = this.digitCountsMissing ? void 0 : resolveReadoutNumericValue(this.value, this.valueType);
57548
57701
  const textValue = resolveReadoutTextValue(this.value, this.valueType);
57549
57702
  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);
57703
+ const hintCount = this.off || isTextMode || !this.hintedZeros || valueForFormat === void 0 || valueForFormat < 0 ? 0 : Math.max(this.resolvedMaxDigits - readoutFormattedInteger(text), 0);
57551
57704
  const hinted = hintCount > 0 ? "0".repeat(hintCount) : "";
57552
57705
  const reserver = isTextMode ? this.spaceReserver ?? "" : this.hintedZeros ? this.reserverText : this.widerReserver(this.spaceReserver, this.reserverText);
57553
57706
  const block = b`
@@ -59167,7 +59320,17 @@ let ObcReadoutListItem = class extends i$4 {
59167
59320
  return this.fractionDigits ?? 0;
59168
59321
  }
59169
59322
  get resolvedMaxDigits() {
59170
- return this.maxDigits ?? 0;
59323
+ return resolveReadoutDigitCount(this.maxDigits);
59324
+ }
59325
+ /**
59326
+ * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
59327
+ * The raw knobs are forwarded to the blocks, which render the reading as
59328
+ * the unavailable dash (see `obc-readout-block.digitCountsMissing`); this
59329
+ * getter only keeps the setpoint comparison in agreement with what is
59330
+ * displayed.
59331
+ */
59332
+ get digitCountsMissing() {
59333
+ return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits);
59171
59334
  }
59172
59335
  get resolvedClickable() {
59173
59336
  const clickable = this.clickable;
@@ -59189,6 +59352,9 @@ let ObcReadoutListItem = class extends i$4 {
59189
59352
  if (!this.hasSetpoint) {
59190
59353
  return false;
59191
59354
  }
59355
+ if (this.digitCountsMissing) {
59356
+ return false;
59357
+ }
59192
59358
  return isDisplayedAtSetpoint(
59193
59359
  resolveReadoutNumericValue(this.value, this.valueType) ?? null,
59194
59360
  this.setpoint,
@@ -59290,8 +59456,8 @@ let ObcReadoutListItem = class extends i$4 {
59290
59456
  .weight=${config.weight}
59291
59457
  .hasDegree=${config.hasDegree ?? false}
59292
59458
  .hasIcon=${config.hasIcon ?? false}
59293
- .fractionDigits=${this.resolvedFractionDigits}
59294
- .maxDigits=${this.resolvedMaxDigits}
59459
+ .fractionDigits=${this.fractionDigits}
59460
+ .maxDigits=${this.maxDigits}
59295
59461
  .hintedZeros=${config.hintedZeros}
59296
59462
  .spaceReserver=${config.spaceReserver}
59297
59463
  .off=${config.off ?? false}
@@ -59588,6 +59754,7 @@ let ObcReadoutListItem = class extends i$4 {
59588
59754
  willUpdate(changed) {
59589
59755
  super.willUpdate(changed);
59590
59756
  assertReadoutValueType("obc-readout-list-item", this.value, this.valueType);
59757
+ assertReadoutFractionDigits("obc-readout-list-item", this.fractionDigits);
59591
59758
  }
59592
59759
  updated(changed) {
59593
59760
  super.updated(changed);
@@ -64375,7 +64542,17 @@ let ObcReadout = class extends i$4 {
64375
64542
  return this.fractionDigits ?? 0;
64376
64543
  }
64377
64544
  get resolvedMaxDigits() {
64378
- return this.maxDigits ?? 0;
64545
+ return resolveReadoutDigitCount(this.maxDigits);
64546
+ }
64547
+ /**
64548
+ * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
64549
+ * The raw knobs are forwarded to the blocks, which render the reading as
64550
+ * the unavailable dash (see `obc-readout-block.digitCountsMissing`); this
64551
+ * getter only keeps the setpoint comparison in agreement with what is
64552
+ * displayed.
64553
+ */
64554
+ get digitCountsMissing() {
64555
+ return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits);
64379
64556
  }
64380
64557
  get hasSrc() {
64381
64558
  return this.src !== void 0 && this.src.trim() !== "";
@@ -64387,6 +64564,9 @@ let ObcReadout = class extends i$4 {
64387
64564
  if (!this.hasSetpoint) {
64388
64565
  return false;
64389
64566
  }
64567
+ if (this.digitCountsMissing) {
64568
+ return false;
64569
+ }
64390
64570
  return isDisplayedAtSetpoint(
64391
64571
  resolveReadoutNumericValue(this.value, this.valueType) ?? null,
64392
64572
  this.setpoint,
@@ -64497,8 +64677,8 @@ let ObcReadout = class extends i$4 {
64497
64677
  .weight=${config.weight}
64498
64678
  .hasDegree=${config.hasDegree ?? false}
64499
64679
  .hasIcon=${config.hasIcon ?? false}
64500
- .fractionDigits=${this.resolvedFractionDigits}
64501
- .maxDigits=${this.resolvedMaxDigits}
64680
+ .fractionDigits=${this.fractionDigits}
64681
+ .maxDigits=${this.maxDigits}
64502
64682
  .hintedZeros=${config.hintedZeros}
64503
64683
  .spaceReserver=${config.spaceReserver}
64504
64684
  .off=${config.off ?? false}
@@ -64971,6 +65151,7 @@ let ObcReadout = class extends i$4 {
64971
65151
  willUpdate(changed) {
64972
65152
  super.willUpdate(changed);
64973
65153
  assertReadoutValueType("obc-readout", this.value, this.valueType);
65154
+ assertReadoutFractionDigits("obc-readout", this.fractionDigits);
64974
65155
  }
64975
65156
  updated(changed) {
64976
65157
  super.updated(changed);
@@ -209868,6 +210049,7 @@ ObcThruster.styles = i$7`
209868
210049
  }
209869
210050
 
209870
210051
  .container > svg {
210052
+ display: block;
209871
210053
  height: 100%;
209872
210054
  width: 100%;
209873
210055
  }
@@ -211331,6 +211513,10 @@ const compentStyle$a = i$7`* {
211331
211513
  box-sizing: border-box;
211332
211514
  }
211333
211515
 
211516
+ svg {
211517
+ display: block;
211518
+ }
211519
+
211334
211520
  .label {
211335
211521
  font-family: var(--global-typography-font-family);
211336
211522
  font-weight: var(--global-typography-ui-body-font-weight);
@@ -212494,6 +212680,16 @@ const componentStyle$h = i$7`* {
212494
212680
  display: block;
212495
212681
  width: 100%;
212496
212682
  height: 100%;
212683
+ /* Clips the rotated overlay <svg transform="rotate(...)">, whose corners
212684
+ swing outside the host and leak arc pixels in wide layouts (same
212685
+ protection obc-watch has had since #994). Known trade-off: the HDG/COG
212686
+ arrow apexes previously painted 1-2px past the host's top edge and are
212687
+ now shaved flat at the box edge — imperceptible at normal viewing.
212688
+ TODO(designer): if the shave is unwanted, the frame needs headroom so
212689
+ the arrow tips fit inside the box — see "Host clipping & the arrow-apex
212690
+ shave" in docs/agents/watch-radial-instruments.md before changing
212691
+ (interacts with the #1021/#1049 label-reserve geometry). */
212692
+ overflow: hidden;
212497
212693
  }
212498
212694
  `;
212499
212695
  function hdgVectorArt(colorName) {
@@ -227720,9 +227916,12 @@ let ObcReadoutList = class extends i$4 {
227720
227916
  if (hasNumericBlock) {
227721
227917
  maxFractionDigits = Math.max(
227722
227918
  maxFractionDigits,
227723
- item.fractionDigits ?? 0
227919
+ resolveReadoutDigitCount(item.fractionDigits)
227920
+ );
227921
+ maxIntegerDigits = Math.max(
227922
+ maxIntegerDigits,
227923
+ resolveReadoutDigitCount(item.maxDigits)
227724
227924
  );
227725
- maxIntegerDigits = Math.max(maxIntegerDigits, item.maxDigits ?? 0);
227726
227925
  }
227727
227926
  maxIntegerDigits = Math.max(
227728
227927
  maxIntegerDigits,