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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) 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 +3502 -3298
  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.css.js +2 -23
  36. package/dist/navigation-instruments/readout/readout.css.js.map +1 -1
  37. package/dist/navigation-instruments/readout/readout.d.ts +1 -1
  38. package/dist/navigation-instruments/readout/readout.js.map +1 -1
  39. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +1 -0
  40. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
  41. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +1 -1
  42. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  43. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +3 -0
  44. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  45. package/package.json +6 -3
  46. package/script/prepare-full-bundle.ts +5 -0
  47. package/src/automation/transmitter/transmitter-shared.ts +16 -0
  48. package/src/automation/transmitter/transmitter.css +3 -71
  49. package/src/automation/transmitter/transmitter.stories.ts +13 -1
  50. package/src/automation/transmitter/transmitter.ts +19 -16
  51. package/src/automation/transmitter-button/transmitter-button.css +11 -36
  52. package/src/automation/transmitter-button/transmitter-button.stories.ts +3 -1
  53. package/src/automation/transmitter-button/transmitter-button.ts +62 -66
  54. package/src/automation/transmitter-stack/transmitter-stack.css +56 -0
  55. package/src/automation/transmitter-stack/transmitter-stack.spec.ts +210 -0
  56. package/src/automation/transmitter-stack/transmitter-stack.stories.ts +149 -0
  57. package/src/automation/transmitter-stack/transmitter-stack.ts +172 -0
  58. package/src/building-blocks/readout-block/readout-block.stories.ts +1 -1
  59. package/src/building-blocks/readout-block/readout-block.ts +1 -1
  60. package/src/components/textarea-field/textarea-field.css +1 -8
  61. package/src/components/textbox/textbox.stories.ts +1 -1
  62. package/src/components/textbox/textbox.ts +1 -1
  63. package/src/mixins/transmitter.css +90 -0
  64. package/src/mixins/visually-hidden.css +10 -0
  65. package/src/navigation-instruments/readout/readout.css +2 -22
  66. package/src/navigation-instruments/readout/readout.spec.ts +74 -1
  67. package/src/navigation-instruments/readout/readout.stories.ts +1 -1
  68. package/src/navigation-instruments/readout/readout.ts +1 -1
  69. package/src/navigation-instruments/readout-list-item/readout-list-item.css +1 -0
  70. package/src/navigation-instruments/readout-list-item/readout-list-item.stories.ts +1 -1
  71. package/src/navigation-instruments/readout-list-item/readout-list-item.ts +12 -2
@@ -3891,7 +3891,7 @@
3891
3891
  {
3892
3892
  "kind": "variable",
3893
3893
  "name": "ObcTransmitterButton",
3894
- "default": "class extends LitElement { constructor() { super(...arguments); this.variant = \"value\"; this.size = \"regular\"; this.unit = \"\"; this.fractionDigits = 1; this.maxDigits = 0; this.hintedZeros = false; this.hasSignSpacer = false; this.hasIcon = false; this.hasAdvice = false; this.hasSetPoint = false; this.label = \"\"; } get isTag() { return this.variant === \"tag\"; } renderBlock(variant, value) { return html`<obc-readout-block .variant=${variant} .value=${value ?? null} .size=${readoutSizeBySize[this.size]} .fractionDigits=${this.fractionDigits} .maxDigits=${this.maxDigits} .hintedZeros=${this.hintedZeros} .hasSignSpacer=${this.hasSignSpacer} ></obc-readout-block>`; } renderAdvice() { if (!this.hasAdvice) { return nothing; } return this.renderBlock(ReadoutBlockVariant.advice, this.adviceValue); } renderSetpoint() { if (!this.hasSetPoint) { return nothing; } return this.renderBlock(ReadoutBlockVariant.setpoint, this.setpointValue); } renderContent() { if (this.isTag) { return html`<span class=\"label\">${this.label}</span>`; } return html` ${this.renderAdvice()} ${this.renderSetpoint()} <div class=\"value-container\"> ${this.hasIcon ? html`<div class=\"icon\"><slot name=\"icon\"></slot></div>` : nothing} ${this.renderBlock(ReadoutBlockVariant.value, this.value)} ${this.unit ? html`<span class=\"unit\">${this.unit}</span>` : nothing} </div> `; } render() { return html` <button type=\"button\" class=\"button ${this.variant} size-${this.size}\"> <div part=\"button\" class=${classMap({ \"visible-wrapper\": true, tag: this.isTag })} > ${this.renderContent()} </div> </button> `; } }"
3894
+ "default": "class extends LitElement { constructor() { super(...arguments); this.variant = \"value\"; this.size = \"regular\"; this.unit = \"\"; this.fractionDigits = 1; this.maxDigits = 0; this.hintedZeros = false; this.hasSignSpacer = false; this.hasDegree = false; this.hasIcon = false; this.hasAdvice = false; this.hasSetPoint = false; this.label = \"\"; this.idTag = \"\"; } get isTag() { return this.variant === \"tag\"; } renderReading() { const format = { hintedZeros: this.hintedZeros, hasSignSpacer: this.hasSignSpacer }; return html` <obc-readout-list-item .size=${readoutSizeBySize[this.size]} .value=${this.value ?? null} .unit=${this.unit} .hasDegree=${this.hasDegree} .fractionDigits=${this.fractionDigits} .maxDigits=${this.maxDigits} .valueOptions=${{ ...format, hasIcon: this.hasIcon }} .hasSetpoint=${this.hasSetPoint} .setpoint=${this.setpointValue ?? void 0} .setpointOptions=${format} .hasAdvice=${this.hasAdvice} .advice=${this.adviceValue ?? void 0} .adviceOptions=${format} > ${this.hasIcon ? html`<slot name=\"icon\" slot=\"value-icon\"></slot>` : nothing} </obc-readout-list-item> `; } render() { return html` <button type=\"button\" class=\"button ${this.variant} size-${this.size}\"> <div part=\"button\" class=${classMap({ \"visible-wrapper\": true, tag: this.isTag })} > ${this.isTag ? html`<span class=\"label\">${this.label}</span>` : this.renderReading()} </div> ${this.idTag ? html`<span class=\"visually-hidden\">${this.idTag}</span>` : nothing} </button> `; } }"
3895
3895
  }
3896
3896
  ],
3897
3897
  "exports": [
@@ -3921,6 +3921,27 @@
3921
3921
  }
3922
3922
  ]
3923
3923
  },
3924
+ {
3925
+ "kind": "javascript-module",
3926
+ "path": "dist/automation/transmitter-stack/transmitter-stack.js",
3927
+ "declarations": [
3928
+ {
3929
+ "kind": "variable",
3930
+ "name": "ObcTransmitterStack",
3931
+ "default": "class extends LitElement { constructor() { super(...arguments); this.orientation = TransmitterOrientation.bottom; this.lineType = void 0; this.values = []; } handleValueClick(index, value) { this.dispatchEvent( new CustomEvent(\"value-click\", { detail: { index, value }, bubbles: true, composed: true }) ); } renderValue(entry, index, hasIdTags) { return html` <div class=\"cell\" part=\"cell\"> <obc-transmitter-button class=\"segment\" .variant=${TransmitterButtonVariant.value} .value=${entry.value} .unit=${entry.unit ?? \"\"} .fractionDigits=${\"fractionDigits\" in entry ? entry.fractionDigits ?? NaN : 1} .maxDigits=${\"maxDigits\" in entry ? entry.maxDigits ?? NaN : 0} .hintedZeros=${entry.hintedZeros ?? false} .hasSignSpacer=${entry.hasSignSpacer ?? false} .hasDegree=${entry.hasDegree ?? false} .hasIcon=${Boolean(entry.iconSlotName)} .idTag=${entry.idTag ?? \"\"} @click=${() => this.handleValueClick(index, entry)} > ${entry.iconSlotName ? html`<slot name=${entry.iconSlotName} slot=\"icon\"></slot>` : nothing} </obc-transmitter-button> ${hasIdTags ? html`<div class=\"id-tag\" aria-hidden=\"true\"> ${entry.idTag ?? \"\"} </div>` : nothing} </div> `; } render() { if (this.values.length === 0) { return nothing; } const hasIdTags = this.values.some((entry) => Boolean(entry.idTag)); return html` <div class=${classMap({ transmitter: true, [`orientation-${this.orientation}`]: true })} style=\"--offset: ${transmitterLeaderOffset(this.lineType)}px;\" > <div class=\"values\" part=\"values\"> ${this.values.map( (entry, index) => this.renderValue(entry, index, hasIdTags) )} </div> </div> `; } }"
3932
+ }
3933
+ ],
3934
+ "exports": [
3935
+ {
3936
+ "kind": "js",
3937
+ "name": "ObcTransmitterStack",
3938
+ "declaration": {
3939
+ "name": "ObcTransmitterStack",
3940
+ "module": "dist/automation/transmitter-stack/transmitter-stack.js"
3941
+ }
3942
+ }
3943
+ ]
3944
+ },
3924
3945
  {
3925
3946
  "kind": "javascript-module",
3926
3947
  "path": "dist/automation/transmitter/transmitter.js",
@@ -3928,7 +3949,7 @@
3928
3949
  {
3929
3950
  "kind": "variable",
3930
3951
  "name": "ObcTransmitter",
3931
- "default": "class extends LitElement { constructor() { super(...arguments); this.orientation = \"bottom\"; this.type = \"value\"; this.lineType = void 0; this.unit = \"\"; this.fractionDigits = 1; this.maxDigits = 0; this.hintedZeros = false; this.hasSignSpacer = false; this.size = TransmitterButtonSize.regular; this.hasIcon = false; this.hasAdvice = false; this.hasAlert = false; this.hasSetPoint = false; this.tag = \"\"; this.idTag = \"\"; this.data = [[], []]; } get hasGraph() { return this.type === \"horizontal-graph\" || this.type === \"vertical-graph\"; } get lineOffset() { return this.lineType === void 0 ? 0 : lineWidth(this.lineType) / 2; } renderButton() { const isIndicator = this.type === \"indicator\"; return html` <obc-transmitter-button class=\"chip\" .variant=${isIndicator ? TransmitterButtonVariant.tag : TransmitterButtonVariant.value} .size=${this.size} .value=${this.value} .unit=${this.unit} .fractionDigits=${this.fractionDigits} .maxDigits=${this.maxDigits} .hintedZeros=${this.hintedZeros} .hasSignSpacer=${this.hasSignSpacer} .hasIcon=${this.hasIcon} .hasAdvice=${this.hasAdvice} .adviceValue=${this.adviceValue} .hasSetPoint=${this.hasSetPoint} .setpointValue=${this.setpointValue} .label=${this.tag} > <slot name=\"icon\" slot=\"icon\"></slot> </obc-transmitter-button> `; } renderGraph() { if (!this.hasGraph) { return nothing; } const layout = { size: ObcIndicatorGraphSize.small, fill: true }; return html` <div class=\"graph-box\"> <obc-indicator-graph .data=${this.data} .layout=${layout}> </obc-indicator-graph> </div> `; } renderLabel() { if (!this.idTag) { return nothing; } return html`<div class=\"id-tag\">${this.idTag}</div>`; } renderContent() { return html` <div class=\"content\"> <div class=\"body\">${this.renderButton()} ${this.renderGraph()}</div> ${this.renderLabel()} </div> `; } render() { const content = this.hasAlert ? html` <obc-alert-frame class=\"alert-frame\" .type=${ObcAlertFrameType.Regular} .wrapContent=${true} > ${this.renderContent()} </obc-alert-frame> ` : this.renderContent(); return html` <div class=${classMap({ transmitter: true, \"has-alert\": this.hasAlert, [`orientation-${this.orientation}`]: true, [`type-${this.type}`]: true })} style=\"--offset: ${this.lineOffset}px;\" > ${content} </div> `; } }"
3952
+ "default": "class extends LitElement { constructor() { super(...arguments); this.orientation = TransmitterOrientation.bottom; this.type = \"value\"; this.lineType = void 0; this.unit = \"\"; this.fractionDigits = 1; this.maxDigits = 0; this.hintedZeros = false; this.hasSignSpacer = false; this.hasDegree = false; this.size = TransmitterButtonSize.regular; this.hasIcon = false; this.hasAdvice = false; this.hasAlert = false; this.hasSetPoint = false; this.tag = \"\"; this.idTag = \"\"; this.data = [[], []]; } get hasGraph() { return this.type === \"horizontal-graph\" || this.type === \"vertical-graph\"; } renderButton() { const isIndicator = this.type === \"indicator\"; return html` <obc-transmitter-button class=\"chip\" .variant=${isIndicator ? TransmitterButtonVariant.tag : TransmitterButtonVariant.value} .size=${this.size} .value=${this.value} .unit=${this.unit} .fractionDigits=${this.fractionDigits} .maxDigits=${this.maxDigits} .hintedZeros=${this.hintedZeros} .hasSignSpacer=${this.hasSignSpacer} .hasDegree=${this.hasDegree} .hasIcon=${this.hasIcon} .hasAdvice=${this.hasAdvice} .adviceValue=${this.adviceValue} .hasSetPoint=${this.hasSetPoint} .setpointValue=${this.setpointValue} .label=${this.tag} .idTag=${this.idTag} > <slot name=\"icon\" slot=\"icon\"></slot> </obc-transmitter-button> `; } renderGraph() { if (!this.hasGraph) { return nothing; } const layout = { size: ObcIndicatorGraphSize.small, fill: true }; return html` <div class=\"graph-box\"> <obc-indicator-graph .data=${this.data} .layout=${layout}> </obc-indicator-graph> </div> `; } renderLabel() { if (!this.idTag) { return nothing; } return html`<div class=\"id-tag\" aria-hidden=\"true\">${this.idTag}</div>`; } renderContent() { return html` <div class=\"content\"> <div class=\"body\">${this.renderButton()} ${this.renderGraph()}</div> ${this.renderLabel()} </div> `; } render() { const content = this.hasAlert ? html` <obc-alert-frame class=\"alert-frame\" .type=${ObcAlertFrameType.Regular} .wrapContent=${true} > ${this.renderContent()} </obc-alert-frame> ` : this.renderContent(); return html` <div class=${classMap({ transmitter: true, \"has-alert\": this.hasAlert, [`orientation-${this.orientation}`]: true, [`type-${this.type}`]: true })} style=\"--offset: ${transmitterLeaderOffset(this.lineType)}px;\" > ${content} </div> `; } }"
3932
3953
  }
3933
3954
  ],
3934
3955
  "exports": [
@@ -3955,6 +3976,14 @@
3955
3976
  "name": "TransmitterType",
3956
3977
  "module": "dist/automation/transmitter/transmitter.js"
3957
3978
  }
3979
+ },
3980
+ {
3981
+ "kind": "js",
3982
+ "name": "transmitterLeaderOffset",
3983
+ "declaration": {
3984
+ "name": "transmitterLeaderOffset",
3985
+ "module": "dist/automation/transmitter/transmitter.js"
3986
+ }
3958
3987
  }
3959
3988
  ]
3960
3989
  },
@@ -10270,7 +10299,7 @@
10270
10299
  {
10271
10300
  "kind": "variable",
10272
10301
  "name": "ObcReadoutListItem",
10273
- "default": "class extends LitElement { constructor() { super(...arguments); this.hasValue = true; this.value = null; this.valueType = ReadoutValueType.number; this.off = false; this.offText = \"OFF\"; this.hasSetpoint = false; this.hasAdvice = false; this.clickable = false; this.hasLeadingIcon = false; this.hasDegree = false; this.hasDegreeSpacer = false; this.fractionDigits = 0; this.maxDigits = 0; this.alert = false; this.showDebugOverlay = false; this.deferredSetpointHidePhase = ReadoutBlockHidePhase.none; this.hasCompletedFirstUpdate = false; } get resolvedSize() { return this.size ?? ReadoutListItemSize.small; } get resolvedStacking() { return this.stacking ?? \"trailing-unit\"; } /** Both leading-src stackings move the source into the label stack. */ get hasLeadingSrc() { const stacking = this.resolvedStacking; return stacking === \"leading-src\" || stacking === \"leading-src-inline\"; } get resolvedPriority() { return this.priority ?? \"regular\"; } /** * Whether a unit box follows the value: a unit, or a reserver alone — the * blank reserved column keeps a unit-less row aligned with its neighbours. */ get hasTrailingUnitBox() { return this.resolvedStacking !== \"leading-unit\" && (Boolean(this.unit) || Boolean(this.unitOptions?.spaceReserver)); } get resolvedFractionDigits() { return this.fractionDigits ?? 0; } get resolvedMaxDigits() { return resolveReadoutDigitCount(this.maxDigits); } /** * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`). * The raw knobs are forwarded to the blocks, which render the reading as * the unavailable dash (see `obc-readout-block.digitCountsMissing`); this * getter only keeps the setpoint comparison in agreement with what is * displayed. */ get digitCountsMissing() { return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits); } get resolvedClickable() { const clickable = this.clickable; if (!clickable) { return false; } if (clickable === true) { return { border: \"squared\" /* squared */ }; } return { border: clickable.border ?? \"squared\" /* squared */ }; } get isAtSetpoint() { if (!this.hasSetpoint) { return false; } if (this.digitCountsMissing) { return false; } return isDisplayedAtSetpoint( resolveReadoutNumericValue(this.value, this.valueType) ?? null, this.setpoint, this.numericFormatOptions(this.resolvedMaxDigits) ); } get resolvedSetpointInteraction() { return this.setpointOptions?.interaction ?? \"always-visible\"; } get isFlipFlop() { return this.resolvedSetpointInteraction === \"flip-flop\"; } get isEqualSize() { return this.resolvedSetpointInteraction === \"equal-size\"; } get isPopUp() { return this.resolvedSetpointInteraction === \"pop-up\"; } get setpointTouching() { return this.setpointOptions?.touching ?? false; } /** * The setpoint is rendered \"emphasised\" (primary size + SemiBold weight) when * it is the focus of attention: while actively adjusting (`touching`), or while * a flip-flop has the value away from the setpoint. Otherwise it is a secondary * (smaller, regular-weight) reference next to the value. */ get isSetpointEmphasized() { if (!this.hasSetpoint) { return false; } if (this.setpointTouching) { return true; } return this.isFlipFlop && !this.isAtSetpoint; } /** * The row's enhanced (in-command) colour state, applied uniformly to BOTH the * value and the setpoint — they are always either both neutral or both enhanced * (never a blue setpoint next to a grey value). Driven by `priority` only; * `valueOptions.weight` changes weight, not colour. */ get rowEnhanced() { return this.resolvedPriority === \"enhanced\"; } /** Primary value-typography size for the current density tier. */ get primarySize() { return readoutPrimarySize(this.resolvedSize); } /** Secondary (de-emphasised) value-typography size for the current density tier. */ get secondarySize() { return readoutSecondarySize(this.resolvedSize); } get valueSize() { return readoutValueSize({ primary: this.primarySize, secondary: this.secondarySize, setpointEmphasized: this.isSetpointEmphasized, equalSize: this.isEqualSize }); } get setpointSize() { return readoutSetpointSize({ primary: this.primarySize, secondary: this.secondarySize, emphasized: this.isSetpointEmphasized, equalSize: this.isEqualSize }); } /** Value font weight passes straight to obc-textbox; regular when unset. Colour is separate. */ get valueWeight() { return this.valueOptions?.weight ?? ObcTextboxFontWeight.regular; } /** Label size: `xs` for dense list rows unless overridden (see {@link ReadoutLabelOptions}). */ get labelSize() { return this.labelOptions?.size ?? ObcTextboxSize.xs; } /** * Label weight: SemiBold only for enhanced (in-command) rows, regular * otherwise — the designer reduced the amount of semibold in the interface * (Figma 6.1 review). */ get labelWeight() { return this.rowEnhanced ? ObcTextboxFontWeight.semibold : ObcTextboxFontWeight.regular; } /** Setpoint is SemiBold only while emphasised, otherwise regular weight. */ get setpointWeight() { return readoutSetpointWeight(this.isSetpointEmphasized); } numericFormatOptions(maxDigits) { return readoutNumericFormatOptions(maxDigits, this.resolvedFractionDigits); } /** classMap fragment for a block / source carrying per-block data quality. */ dataQualityClasses(dataQuality) { return readoutDataQualityClasses(dataQuality); } /** * Forward the matching list-item icon slot into the block's single `icon` * slot. The variant's default marker lives in `obc-readout-block` and shows * when nothing is assigned here (an empty forwarded slot flattens to nothing). */ renderForwardedIcon(variant) { if (variant === ReadoutBlockVariant.setpoint) { return html`<slot name=\"setpoint-icon\" slot=\"icon\"></slot>`; } if (variant === ReadoutBlockVariant.advice) { return html`<slot name=\"advice-icon\" slot=\"icon\"></slot>`; } return html`<slot name=\"value-icon\" slot=\"icon\"></slot>`; } renderBlock(config) { return html` <obc-readout-block exportparts=\"block, block-content, block-text, block-icon, degree\" .variant=${config.variant} .value=${config.value ?? null} .valueType=${config.valueType ?? ReadoutValueType.number} .size=${this.resolvedSize} .valueSize=${config.valueSize} .enhanced=${config.enhanced} .weight=${config.weight} .hasDegree=${config.hasDegree ?? false} .hasIcon=${config.hasIcon ?? false} .fractionDigits=${this.fractionDigits} .maxDigits=${this.maxDigits} .hintedZeros=${config.hintedZeros} .hasSignSpacer=${config.hasSignSpacer ?? false} .spaceReserver=${config.spaceReserver} .off=${config.off ?? false} .offText=${this.offText} .touching=${config.touching ?? false} .hidePhase=${config.hidePhase ?? ReadoutBlockHidePhase.none} .dataQuality=${config.dataQuality} .alert=${config.alert ?? false} .category=${config.category ?? ReadoutAdviceCategory.regular} .active=${config.active ?? false} > ${this.renderForwardedIcon(config.variant)} </obc-readout-block> `; } /** * A cap-height `°` column whose width scales with the value size. Used after * the value (as the value↔unit boundary, via {@link renderValueUnitGap}) and * inside the setpoint / advice blocks. `inherit` makes the glyph take the * surrounding block's colour (setpoint/advice); otherwise it uses the value * colour, optionally `enhanced`. */ renderDegreeGlyph(size, opts = {}) { return html` <span class=${classMap({ \"degree-column\": true, [`degree-${size}`]: true, \"tone-enhanced\": !opts.inherit && Boolean(opts.enhanced), \"degree-inherit\": Boolean(opts.inherit) })} part=\"degree\" > <obc-textbox class=\"degree-glyph\" .size=${size} alignment=\"center\" >°</obc-textbox > </span> `; } /** * The gap rendered between the value digits and the unit. * * - `hasDegree`: a cap-height `°` column whose width scales with the value * size (the `°` replaces the default gap). * - otherwise: the default 2px gap (only when a trailing unit follows). * * `hasDegreeSpacer` deliberately does NOT add anything here — it keeps the 2px * gap and instead widens the unit column via {@link renderDegreeSpacer} (a * spacer AFTER the unit). That way a non-degree row's value digits stay * aligned with degree rows (degree column width = spacer width + 2px gap) * while its unit shifts left. Mirrors Figma `1:2920` (spacer) / `1:2970` * (degree). * * TODO(designer): cross-size alignment is deferred. Degree rows of different * value sizes have different `°` column widths (6/8/12px), so their value digit * edges stagger by `degree-width`. For degree rows of mixed sizes you cannot * align the value digit edges AND keep the unit column aligned — resolving it * needs a design decision (a constant degree reserve, which widens the smaller * rows' `°`, OR pinning the value edge and letting the unit column stagger). */ renderValueUnitGap() { if (!this.hasValue) { return nothing; } if ((this.hasDegree ?? false) && !this.off) { return this.renderDegreeGlyph(this.valueSize, { enhanced: this.rowEnhanced }); } if (this.hasTrailingUnitBox) { return html`<span class=\"value-unit-gap\" aria-hidden=\"true\"></span>`; } return nothing; } /** * A spacer rendered AFTER the unit when `hasDegreeSpacer` is set on a * non-degree row. Its width (`degree-compensation-padding`) = the degree * column width minus the 2px gap, so the row's value digits align with degree * rows in the same column while its unit shifts left. See * {@link renderValueUnitGap}. */ renderDegreeSpacer() { const hasDegree = this.hasDegree ?? false; const hasDegreeSpacer = this.hasDegreeSpacer ?? false; if (hasDegree || !hasDegreeSpacer) { return nothing; } return html`<span class=\"degree-spacer\" part=\"degree-spacer\" aria-hidden=\"true\" ></span>`; } renderTextbox(role, text, reserver, state2) { const weight = role === \"label\" ? this.labelWeight : ObcTextboxFontWeight.regular; const size = role === \"label\" ? this.labelSize : ObcTextboxSize.xs; const box = html` <obc-textbox class=${classMap({ [role]: true, ...this.dataQualityClasses(state2?.dataQuality) })} part=${role} .size=${size} .fontWeight=${weight} alignment=\"left\" > ${text} ${reserver ? html`<span slot=\"length\">${reserver}</span>` : nothing} </obc-textbox> `; return wrapWithAlertFrame(state2?.alert ?? false, box); } renderValueCluster() { const popUpAtSetpoint = this.isPopUp && this.isAtSetpoint && !this.setpointTouching; const setpointHidePhase = resolveSetpointHidePhase( popUpAtSetpoint, this.deferredSetpointHidePhase ); return html` <div class=\"value-cluster\" part=\"value-cluster\"> ${this.hasAdvice ? this.renderBlock({ variant: ReadoutBlockVariant.advice, value: this.advice, valueSize: this.secondarySize, enhanced: false, weight: ObcTextboxFontWeight.regular, hintedZeros: this.adviceOptions?.hintedZeros ?? false, hasSignSpacer: this.adviceOptions?.hasSignSpacer ?? false, spaceReserver: this.adviceOptions?.spaceReserver, hasDegree: this.hasDegree ?? false, dataQuality: this.adviceOptions?.dataQuality, alert: this.adviceOptions?.alert, category: this.adviceOptions?.category, active: this.adviceOptions?.active }) : nothing} ${this.hasSetpoint ? this.renderBlock({ variant: ReadoutBlockVariant.setpoint, value: this.setpoint, valueSize: this.setpointSize, // Value and setpoint share the enhanced colour state (both neutral // or both enhanced); the setpoint is bold only while emphasised. enhanced: this.rowEnhanced, weight: this.setpointWeight, hintedZeros: this.setpointOptions?.hintedZeros ?? false, hasSignSpacer: this.setpointOptions?.hasSignSpacer ?? false, spaceReserver: this.setpointOptions?.spaceReserver, hasDegree: this.hasDegree ?? false, touching: this.setpointTouching, hidePhase: setpointHidePhase, dataQuality: this.setpointOptions?.dataQuality, alert: this.setpointOptions?.alert }) : nothing} ${this.renderValueReading()} </div> `; } /** * The value reading: the value block, its degree column and the trailing unit * grouped in one relatively-positioned wrapper so the value alert frame AND the * value data-quality chip can wrap value + degree + unit together (Figma * 58:10120). * * Moving the degree / unit into this wrapper (the new last child of * `.value-cluster`) preserves every existing gap, so the underlying content * stays column-aligned with or without the frame / chip. Both the value alert * (overlay) and the value data-quality chip are applied here — NOT inside * `obc-readout-block` — so they extend over the unit; setpoint/advice keep their * own block-level frame and chip. The chip uses `outline` (not `border`), so it * never shifts the value's width / column alignment. */ renderValueReading() { return html` <div class=${classMap({ \"value-reading\": true, ...this.dataQualityClasses(this.valueOptions?.dataQuality) })} part=\"value-reading\" > ${this.hasValue ? this.renderBlock({ variant: ReadoutBlockVariant.value, value: this.value, valueType: this.valueType, valueSize: this.valueSize, enhanced: this.rowEnhanced, weight: this.valueWeight, hintedZeros: this.valueOptions?.hintedZeros ?? false, hasSignSpacer: this.valueOptions?.hasSignSpacer ?? false, spaceReserver: this.valueOptions?.spaceReserver, off: this.off, hasIcon: this.valueOptions?.hasIcon ?? false }) : nothing} ${this.renderValueUnitGap()} <div class=\"unit-area\" part=\"unit-area\"> ${this.renderTrailingUnit()} ${this.renderDegreeSpacer()} </div> ${this.renderValueAlertOverlay()} </div> `; } /** * The value alert frame, drawn as a pure overlay around the value reading * (value + degree + unit). It reserves no space — the `obc-alert-frame` sits in * an absolutely-positioned box offset outward (see `.value-alert-overlay` in * the CSS) so its stroke is centred on the 4px/2px padding line and toggling it * never shifts content or row height. Renders only when `valueOptions.alert` is * a config object. */ renderValueAlertOverlay() { const alert = this.valueOptions?.alert; if (typeof alert !== \"object\" || alert === null) { return nothing; } const thickness = alert.thickness ?? ObcAlertFrameThickness.Small; return html` <div class=\"value-alert-overlay\" aria-hidden=\"true\"> <obc-alert-frame part=\"value-alert-frame\" .type=${alert.type ?? ObcAlertFrameType.Regular} .thickness=${thickness} .status=${alert.status ?? AlertType.Alarm} .mode=${alert.mode ?? ObcAlertFrameMode.ackedActive} .flashingSpeed=${alert.flashingSpeed ?? FlashingSpeed.Default} .showIcon=${alert.showIcon ?? false} .showAlertCategoryIcon=${alert.showAlertCategoryIcon ?? true} .wrapContent=${false} .fullWidth=${false} ></obc-alert-frame> </div> `; } renderLabelContainer() { const stacking = this.resolvedStacking; const showLeadingUnit = stacking === \"leading-unit\" && Boolean(this.unit); const showLeadingSrc = this.hasLeadingSrc && Boolean(this.src); return html` <div class=\"label-container\" part=\"label-container\"> ${this.hasLeadingIcon ? html`<span class=\"leading-icon\" aria-hidden=\"true\" ><slot name=\"leading-icon\"></slot ></span>` : nothing} <div class=\"label-stack\" part=\"label-stack\"> ${this.label ? this.renderTextbox( \"label\", this.label, this.labelOptions?.spaceReserver ) : nothing} ${showLeadingUnit ? this.renderTextbox( \"unit\", this.unit ?? \"\", this.unitOptions?.spaceReserver ) : nothing} ${showLeadingSrc ? this.renderSourceBlock() : nothing} </div> </div> `; } renderTrailingUnit() { if (!this.hasTrailingUnitBox) { return nothing; } return this.renderTextbox( \"unit\", this.unit ?? \"\", this.unitOptions?.spaceReserver ); } /** * The source text plus its optional state chip and deviation line. The * plain (regular, no-deviation) case renders the bare textbox; a state or a * deviation wraps it in the `.source-block` stack. */ renderSourceBlock() { const state2 = this.srcOptions?.state ?? \"regular\"; const deviation = this.srcOptions?.deviation; const hasDeviation = deviation !== void 0 && Number.isFinite(deviation); const box = this.renderTextbox( \"source\", this.src ?? \"\", this.srcOptions?.spaceReserver, this.srcOptions ); if (state2 === \"regular\" && !hasDeviation) { return box; } return html` <div class=${classMap({ \"source-block\": true, [`source-state-${state2}`]: state2 !== \"regular\" /* regular */ })} part=\"source-block\" > ${box} ${hasDeviation ? html`<span class=\"source-deviation\"> <obi-delta aria-hidden=\"true\"></obi-delta> <obc-textbox class=\"source-deviation-value\" .size=${ObcTextboxSize.xs} .tabularNums=${true} alignment=\"left\" >${deviation}</obc-textbox > </span>` : nothing} </div> `; } renderTrailingSource() { if (this.hasLeadingSrc || !this.src) { return nothing; } return html` <div class=\"divider\" part=\"divider\" aria-hidden=\"true\"></div> ${this.renderSourceBlock()} `; } renderContent() { return html` <div class=\"content\" part=\"content\"> ${this.renderLabelContainer()} <div class=\"value-area\" part=\"value-area\"> ${this.renderValueCluster()} </div> ${this.renderTrailingSource()} </div> `; } willUpdate(changed) { super.willUpdate(changed); assertReadoutValueType(\"obc-readout-list-item\", this.value, this.valueType); assertReadoutFractionDigits(\"obc-readout-list-item\", this.fractionDigits); } updated(changed) { super.updated(changed); const firstUpdate = !this.hasCompletedFirstUpdate; this.hasCompletedFirstUpdate = true; if (!this.isPopUp || this.setpointTouching) { this.clearDeferredSetpointHide(); return; } const shouldHide = this.hasSetpoint && this.isAtSetpoint; if (firstUpdate) { this.deferredSetpointHidePhase = shouldHide ? ReadoutBlockHidePhase.hidden : ReadoutBlockHidePhase.none; return; } if (!shouldHide) { this.clearDeferredSetpointHide(); return; } if (this.deferredSetpointHidePhase !== ReadoutBlockHidePhase.none) { return; } this.deferredSetpointHidePhase = ReadoutBlockHidePhase.hiding; window.clearTimeout(this.deferredSetpointHideTimer); this.deferredSetpointHideTimer = window.setTimeout(() => { this.deferredSetpointHidePhase = ReadoutBlockHidePhase.hidden; this.deferredSetpointHideTimer = void 0; }, 100); } clearDeferredSetpointHide() { if (this.deferredSetpointHidePhase !== ReadoutBlockHidePhase.none) { this.deferredSetpointHidePhase = ReadoutBlockHidePhase.none; } window.clearTimeout(this.deferredSetpointHideTimer); this.deferredSetpointHideTimer = void 0; } disconnectedCallback() { window.clearTimeout(this.deferredSetpointHideTimer); this.deferredSetpointHideTimer = void 0; if (this.deferredSetpointHidePhase === ReadoutBlockHidePhase.hiding) { this.deferredSetpointHidePhase = ReadoutBlockHidePhase.hidden; } super.disconnectedCallback(); } render() { const clickable = this.resolvedClickable; const dataQuality = this.dataQuality; const classes = classMap({ root: true, [`size-${this.resolvedSize}`]: true, [`stacking-${this.resolvedStacking}`]: true, [`priority-${this.resolvedPriority}`]: true, \"data-low-integrity\": dataQuality === ReadoutListItemDataQuality.lowIntegrity, \"data-invalid\": dataQuality === ReadoutListItemDataQuality.invalid, \"flip-flop\": this.isFlipFlop, clickable: Boolean(clickable), [`border-${clickable ? clickable.border : \"squared\"}`]: Boolean(clickable) }); const surface = html`<div class=\"surface\" part=\"surface\"> ${this.renderContent()} </div>`; const root = clickable ? html`<button class=${classes} part=\"root\" type=\"button\"> ${surface} </button>` : html`<div class=${classes} part=\"root\">${surface}</div>`; const alert = this.alert === true ? {} : this.alert; return wrapWithAlertFrame(alert, root, true); } }"
10302
+ "default": "class extends LitElement { constructor() { super(...arguments); this.hasValue = true; this.value = null; this.valueType = ReadoutValueType.number; this.off = false; this.offText = \"OFF\"; this.hasSetpoint = false; this.hasAdvice = false; this.clickable = false; this.hasLeadingIcon = false; this.hasDegree = false; this.hasDegreeSpacer = false; this.fractionDigits = 0; this.maxDigits = 0; this.alert = false; this.showDebugOverlay = false; this.deferredSetpointHidePhase = ReadoutBlockHidePhase.none; this.hasCompletedFirstUpdate = false; } get resolvedSize() { return this.size ?? ReadoutListItemSize.small; } get resolvedStacking() { return this.stacking ?? \"trailing-unit\"; } /** Both leading-src stackings move the source into the label stack. */ get hasLeadingSrc() { const stacking = this.resolvedStacking; return stacking === \"leading-src\" || stacking === \"leading-src-inline\"; } get resolvedPriority() { return this.priority ?? \"regular\"; } /** * Whether a unit box follows the value: a unit, or a reserver alone — the * blank reserved column keeps a unit-less row aligned with its neighbours. */ get hasTrailingUnitBox() { return this.resolvedStacking !== \"leading-unit\" && (Boolean(this.unit) || Boolean(this.unitOptions?.spaceReserver)); } get resolvedFractionDigits() { return this.fractionDigits ?? 0; } get resolvedMaxDigits() { return resolveReadoutDigitCount(this.maxDigits); } /** * Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`). * The raw knobs are forwarded to the blocks, which render the reading as * the unavailable dash (see `obc-readout-block.digitCountsMissing`); this * getter only keeps the setpoint comparison in agreement with what is * displayed. */ get digitCountsMissing() { return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits); } get resolvedClickable() { const clickable = this.clickable; if (!clickable) { return false; } if (clickable === true) { return { border: \"squared\" /* squared */ }; } return { border: clickable.border ?? \"squared\" /* squared */ }; } get isAtSetpoint() { if (!this.hasSetpoint) { return false; } if (this.digitCountsMissing) { return false; } return isDisplayedAtSetpoint( resolveReadoutNumericValue(this.value, this.valueType) ?? null, this.setpoint, this.numericFormatOptions(this.resolvedMaxDigits) ); } get resolvedSetpointInteraction() { return this.setpointOptions?.interaction ?? \"always-visible\"; } get isFlipFlop() { return this.resolvedSetpointInteraction === \"flip-flop\"; } get isEqualSize() { return this.resolvedSetpointInteraction === \"equal-size\"; } get isPopUp() { return this.resolvedSetpointInteraction === \"pop-up\"; } get setpointTouching() { return this.setpointOptions?.touching ?? false; } /** * The setpoint is rendered \"emphasised\" (primary size + SemiBold weight) when * it is the focus of attention: while actively adjusting (`touching`), or while * a flip-flop has the value away from the setpoint. Otherwise it is a secondary * (smaller, regular-weight) reference next to the value. */ get isSetpointEmphasized() { if (!this.hasSetpoint) { return false; } if (this.setpointTouching) { return true; } return this.isFlipFlop && !this.isAtSetpoint; } /** * The row's enhanced (in-command) colour state, applied uniformly to BOTH the * value and the setpoint — they are always either both neutral or both enhanced * (never a blue setpoint next to a grey value). Driven by `priority` only; * `valueOptions.weight` changes weight, not colour. */ get rowEnhanced() { return this.resolvedPriority === \"enhanced\"; } /** Primary value-typography size for the current density tier. */ get primarySize() { return readoutPrimarySize(this.resolvedSize); } /** Secondary (de-emphasised) value-typography size for the current density tier. */ get secondarySize() { return readoutSecondarySize(this.resolvedSize); } get valueSize() { return readoutValueSize({ primary: this.primarySize, secondary: this.secondarySize, setpointEmphasized: this.isSetpointEmphasized, equalSize: this.isEqualSize }); } get setpointSize() { return readoutSetpointSize({ primary: this.primarySize, secondary: this.secondarySize, emphasized: this.isSetpointEmphasized, equalSize: this.isEqualSize }); } /** Value font weight passes straight to obc-textbox; regular when unset. Colour is separate. */ get valueWeight() { return this.valueOptions?.weight ?? ObcTextboxFontWeight.regular; } /** Label size: `xs` for dense list rows unless overridden (see {@link ReadoutLabelOptions}). */ get labelSize() { return this.labelOptions?.size ?? ObcTextboxSize.xs; } /** * Label weight: SemiBold only for enhanced (in-command) rows, regular * otherwise — the designer reduced the amount of semibold in the interface * (Figma 6.1 review). */ get labelWeight() { return this.rowEnhanced ? ObcTextboxFontWeight.semibold : ObcTextboxFontWeight.regular; } /** Setpoint is SemiBold only while emphasised, otherwise regular weight. */ get setpointWeight() { return readoutSetpointWeight(this.isSetpointEmphasized); } numericFormatOptions(maxDigits) { return readoutNumericFormatOptions(maxDigits, this.resolvedFractionDigits); } /** classMap fragment for a block / source carrying per-block data quality. */ dataQualityClasses(dataQuality) { return readoutDataQualityClasses(dataQuality); } /** * Forward the matching list-item icon slot into the block's single `icon` * slot. The variant's default marker lives in `obc-readout-block` and shows * when nothing is assigned here (an empty forwarded slot flattens to nothing). */ renderForwardedIcon(variant) { if (variant === ReadoutBlockVariant.setpoint) { return html`<slot name=\"setpoint-icon\" slot=\"icon\"></slot>`; } if (variant === ReadoutBlockVariant.advice) { return html`<slot name=\"advice-icon\" slot=\"icon\"></slot>`; } return html`<slot name=\"value-icon\" slot=\"icon\"></slot>`; } renderBlock(config) { return html` <obc-readout-block exportparts=\"block, block-content, block-text, block-icon, degree\" .variant=${config.variant} .value=${config.value ?? null} .valueType=${config.valueType ?? ReadoutValueType.number} .size=${this.resolvedSize} .valueSize=${config.valueSize} .enhanced=${config.enhanced} .weight=${config.weight} .hasDegree=${config.hasDegree ?? false} .hasIcon=${config.hasIcon ?? false} .fractionDigits=${this.fractionDigits} .maxDigits=${this.maxDigits} .hintedZeros=${config.hintedZeros} .hasSignSpacer=${config.hasSignSpacer ?? false} .spaceReserver=${config.spaceReserver} .off=${config.off ?? false} .offText=${this.offText} .touching=${config.touching ?? false} .hidePhase=${config.hidePhase ?? ReadoutBlockHidePhase.none} .dataQuality=${config.dataQuality} .alert=${config.alert ?? false} .category=${config.category ?? ReadoutAdviceCategory.regular} .active=${config.active ?? false} > ${this.renderForwardedIcon(config.variant)} </obc-readout-block> `; } /** * A cap-height `°` column whose width scales with the value size. Used after * the value (as the value↔unit boundary, via {@link renderValueUnitGap}) and * inside the setpoint / advice blocks. `inherit` makes the glyph take the * surrounding block's colour (setpoint/advice); otherwise it uses the value * colour, optionally `enhanced`. */ renderDegreeGlyph(size, opts = {}) { return html` <span class=${classMap({ \"degree-column\": true, [`degree-${size}`]: true, \"tone-enhanced\": !opts.inherit && Boolean(opts.enhanced), \"degree-inherit\": Boolean(opts.inherit) })} part=\"degree\" > <obc-textbox class=\"degree-glyph\" .size=${size} alignment=\"center\" >°</obc-textbox > </span> `; } /** * The gap rendered between the value digits and the unit. * * - `hasDegree`: a cap-height `°` column whose width scales with the value * size (the `°` replaces the default gap). * - otherwise: the default 2px gap (only when a trailing unit follows). * * `hasDegreeSpacer` deliberately does NOT add anything here — it keeps the 2px * gap and instead widens the unit column via {@link renderDegreeSpacer} (a * spacer AFTER the unit). That way a non-degree row's value digits stay * aligned with degree rows (degree column width = spacer width + 2px gap) * while its unit shifts left. Mirrors Figma `1:2920` (spacer) / `1:2970` * (degree). * * TODO(designer): cross-size alignment is deferred. Degree rows of different * value sizes have different `°` column widths (6/8/12px), so their value digit * edges stagger by `degree-width`. For degree rows of mixed sizes you cannot * align the value digit edges AND keep the unit column aligned — resolving it * needs a design decision (a constant degree reserve, which widens the smaller * rows' `°`, OR pinning the value edge and letting the unit column stagger). */ renderValueUnitGap() { if (!this.hasValue) { return nothing; } if ((this.hasDegree ?? false) && !this.off) { return this.renderDegreeGlyph(this.valueSize, { enhanced: this.rowEnhanced }); } if (this.hasTrailingUnitBox) { return html`<span class=\"value-unit-gap\" aria-hidden=\"true\"></span>`; } return nothing; } /** * A spacer rendered AFTER the unit when `hasDegreeSpacer` is set on a * non-degree row. Its width (`degree-compensation-padding`) = the degree * column width minus the 2px gap, so the row's value digits align with degree * rows in the same column while its unit shifts left. See * {@link renderValueUnitGap}. */ renderDegreeSpacer() { const hasDegree = this.hasDegree ?? false; const hasDegreeSpacer = this.hasDegreeSpacer ?? false; if (hasDegree || !hasDegreeSpacer) { return nothing; } return html`<span class=\"degree-spacer\" part=\"degree-spacer\" aria-hidden=\"true\" ></span>`; } renderTextbox(role, text, reserver, state2) { const weight = role === \"label\" ? this.labelWeight : ObcTextboxFontWeight.regular; const size = role === \"label\" ? this.labelSize : ObcTextboxSize.xs; const box = html` <obc-textbox class=${classMap({ [role]: true, ...this.dataQualityClasses(state2?.dataQuality) })} part=${role} .size=${size} .fontWeight=${weight} alignment=\"left\" > ${text} ${reserver ? html`<span slot=\"length\">${reserver}</span>` : nothing} </obc-textbox> `; return wrapWithAlertFrame(state2?.alert ?? false, box); } renderValueCluster() { const popUpAtSetpoint = this.isPopUp && this.isAtSetpoint && !this.setpointTouching; const setpointHidePhase = resolveSetpointHidePhase( popUpAtSetpoint, this.deferredSetpointHidePhase ); return html` <div class=\"value-cluster\" part=\"value-cluster\"> ${this.hasAdvice ? this.renderBlock({ variant: ReadoutBlockVariant.advice, value: this.advice, valueSize: this.secondarySize, enhanced: false, weight: ObcTextboxFontWeight.regular, hintedZeros: this.adviceOptions?.hintedZeros ?? false, hasSignSpacer: this.adviceOptions?.hasSignSpacer ?? false, spaceReserver: this.adviceOptions?.spaceReserver, hasDegree: this.hasDegree ?? false, dataQuality: this.adviceOptions?.dataQuality, alert: this.adviceOptions?.alert, category: this.adviceOptions?.category, active: this.adviceOptions?.active }) : nothing} ${this.hasSetpoint ? this.renderBlock({ variant: ReadoutBlockVariant.setpoint, value: this.setpoint, valueSize: this.setpointSize, // Value and setpoint share the enhanced colour state (both neutral // or both enhanced); the setpoint is bold only while emphasised. enhanced: this.rowEnhanced, weight: this.setpointWeight, hintedZeros: this.setpointOptions?.hintedZeros ?? false, hasSignSpacer: this.setpointOptions?.hasSignSpacer ?? false, spaceReserver: this.setpointOptions?.spaceReserver, hasDegree: this.hasDegree ?? false, touching: this.setpointTouching, hidePhase: setpointHidePhase, dataQuality: this.setpointOptions?.dataQuality, alert: this.setpointOptions?.alert }) : nothing} ${this.renderValueReading()} </div> `; } /** * The value reading: the value block, its degree column and the trailing unit * grouped in one relatively-positioned wrapper so the value alert frame AND the * value data-quality chip can wrap value + degree + unit together (Figma * 58:10120). * * Moving the degree / unit into this wrapper (the new last child of * `.value-cluster`) preserves every existing gap, so the underlying content * stays column-aligned with or without the frame / chip. Both the value alert * (overlay) and the value data-quality chip are applied here — NOT inside * `obc-readout-block` — so they extend over the unit; setpoint/advice keep their * own block-level frame and chip. The chip uses `outline` (not `border`), so it * never shifts the value's width / column alignment. */ renderValueReading() { return html` <div class=${classMap({ \"value-reading\": true, ...this.dataQualityClasses(this.valueOptions?.dataQuality) })} part=\"value-reading\" > ${this.hasValue ? this.renderBlock({ variant: ReadoutBlockVariant.value, value: this.value, valueType: this.valueType, valueSize: this.valueSize, enhanced: this.rowEnhanced, weight: this.valueWeight, hintedZeros: this.valueOptions?.hintedZeros ?? false, hasSignSpacer: this.valueOptions?.hasSignSpacer ?? false, spaceReserver: this.valueOptions?.spaceReserver, off: this.off, hasIcon: this.valueOptions?.hasIcon ?? false }) : nothing} ${this.renderValueUnitGap()} <div class=\"unit-area\" part=\"unit-area\"> ${this.renderTrailingUnit()} ${this.renderDegreeSpacer()} </div> ${this.renderValueAlertOverlay()} </div> `; } /** * The value alert frame, drawn as a pure overlay around the value reading * (value + degree + unit). It reserves no space — the `obc-alert-frame` sits in * an absolutely-positioned box offset outward (see `.value-alert-overlay` in * the CSS) so its stroke is centred on the 4px/2px padding line and toggling it * never shifts content or row height. Renders only when `valueOptions.alert` is * a config object. */ renderValueAlertOverlay() { const alert = this.valueOptions?.alert; if (typeof alert !== \"object\" || alert === null) { return nothing; } const thickness = alert.thickness ?? ObcAlertFrameThickness.Small; return html` <div class=\"value-alert-overlay\" aria-hidden=\"true\"> <obc-alert-frame part=\"value-alert-frame\" .type=${alert.type ?? ObcAlertFrameType.Regular} .thickness=${thickness} .status=${alert.status ?? AlertType.Alarm} .mode=${alert.mode ?? ObcAlertFrameMode.ackedActive} .flashingSpeed=${alert.flashingSpeed ?? FlashingSpeed.Default} .showIcon=${alert.showIcon ?? false} .showAlertCategoryIcon=${alert.showAlertCategoryIcon ?? true} .wrapContent=${false} .fullWidth=${false} ></obc-alert-frame> </div> `; } renderLabelContainer() { const stacking = this.resolvedStacking; const showLeadingUnit = stacking === \"leading-unit\" && Boolean(this.unit); const showLeadingSrc = this.hasLeadingSrc && Boolean(this.src); if (!this.hasLeadingIcon && !this.label && !showLeadingUnit && !showLeadingSrc) { return nothing; } return html` <div class=\"label-container\" part=\"label-container\"> ${this.hasLeadingIcon ? html`<span class=\"leading-icon\" aria-hidden=\"true\" ><slot name=\"leading-icon\"></slot ></span>` : nothing} <div class=\"label-stack\" part=\"label-stack\"> ${this.label ? this.renderTextbox( \"label\", this.label, this.labelOptions?.spaceReserver ) : nothing} ${showLeadingUnit ? this.renderTextbox( \"unit\", this.unit ?? \"\", this.unitOptions?.spaceReserver ) : nothing} ${showLeadingSrc ? this.renderSourceBlock() : nothing} </div> </div> `; } renderTrailingUnit() { if (!this.hasTrailingUnitBox) { return nothing; } return this.renderTextbox( \"unit\", this.unit ?? \"\", this.unitOptions?.spaceReserver ); } /** * The source text plus its optional state chip and deviation line. The * plain (regular, no-deviation) case renders the bare textbox; a state or a * deviation wraps it in the `.source-block` stack. */ renderSourceBlock() { const state2 = this.srcOptions?.state ?? \"regular\"; const deviation = this.srcOptions?.deviation; const hasDeviation = deviation !== void 0 && Number.isFinite(deviation); const box = this.renderTextbox( \"source\", this.src ?? \"\", this.srcOptions?.spaceReserver, this.srcOptions ); if (state2 === \"regular\" && !hasDeviation) { return box; } return html` <div class=${classMap({ \"source-block\": true, [`source-state-${state2}`]: state2 !== \"regular\" /* regular */ })} part=\"source-block\" > ${box} ${hasDeviation ? html`<span class=\"source-deviation\"> <obi-delta aria-hidden=\"true\"></obi-delta> <obc-textbox class=\"source-deviation-value\" .size=${ObcTextboxSize.xs} .tabularNums=${true} alignment=\"left\" >${deviation}</obc-textbox > </span>` : nothing} </div> `; } renderTrailingSource() { if (this.hasLeadingSrc || !this.src) { return nothing; } return html` <div class=\"divider\" part=\"divider\" aria-hidden=\"true\"></div> ${this.renderSourceBlock()} `; } renderContent() { return html` <div class=\"content\" part=\"content\"> ${this.renderLabelContainer()} <div class=\"value-area\" part=\"value-area\"> ${this.renderValueCluster()} </div> ${this.renderTrailingSource()} </div> `; } willUpdate(changed) { super.willUpdate(changed); assertReadoutValueType(\"obc-readout-list-item\", this.value, this.valueType); assertReadoutFractionDigits(\"obc-readout-list-item\", this.fractionDigits); } updated(changed) { super.updated(changed); const firstUpdate = !this.hasCompletedFirstUpdate; this.hasCompletedFirstUpdate = true; if (!this.isPopUp || this.setpointTouching) { this.clearDeferredSetpointHide(); return; } const shouldHide = this.hasSetpoint && this.isAtSetpoint; if (firstUpdate) { this.deferredSetpointHidePhase = shouldHide ? ReadoutBlockHidePhase.hidden : ReadoutBlockHidePhase.none; return; } if (!shouldHide) { this.clearDeferredSetpointHide(); return; } if (this.deferredSetpointHidePhase !== ReadoutBlockHidePhase.none) { return; } this.deferredSetpointHidePhase = ReadoutBlockHidePhase.hiding; window.clearTimeout(this.deferredSetpointHideTimer); this.deferredSetpointHideTimer = window.setTimeout(() => { this.deferredSetpointHidePhase = ReadoutBlockHidePhase.hidden; this.deferredSetpointHideTimer = void 0; }, 100); } clearDeferredSetpointHide() { if (this.deferredSetpointHidePhase !== ReadoutBlockHidePhase.none) { this.deferredSetpointHidePhase = ReadoutBlockHidePhase.none; } window.clearTimeout(this.deferredSetpointHideTimer); this.deferredSetpointHideTimer = void 0; } disconnectedCallback() { window.clearTimeout(this.deferredSetpointHideTimer); this.deferredSetpointHideTimer = void 0; if (this.deferredSetpointHidePhase === ReadoutBlockHidePhase.hiding) { this.deferredSetpointHidePhase = ReadoutBlockHidePhase.hidden; } super.disconnectedCallback(); } render() { const clickable = this.resolvedClickable; const dataQuality = this.dataQuality; const classes = classMap({ root: true, [`size-${this.resolvedSize}`]: true, [`stacking-${this.resolvedStacking}`]: true, [`priority-${this.resolvedPriority}`]: true, \"data-low-integrity\": dataQuality === ReadoutListItemDataQuality.lowIntegrity, \"data-invalid\": dataQuality === ReadoutListItemDataQuality.invalid, \"flip-flop\": this.isFlipFlop, clickable: Boolean(clickable), [`border-${clickable ? clickable.border : \"squared\"}`]: Boolean(clickable) }); const surface = html`<div class=\"surface\" part=\"surface\"> ${this.renderContent()} </div>`; const root = clickable ? html`<button class=${classes} part=\"root\" type=\"button\"> ${surface} </button>` : html`<div class=${classes} part=\"root\">${surface}</div>`; const alert = this.alert === true ? {} : this.alert; return wrapWithAlertFrame(alert, root, true); } }"
10274
10303
  }
10275
10304
  ],
10276
10305
  "exports": [
@@ -39658,7 +39687,7 @@
39658
39687
  "declarations": [
39659
39688
  {
39660
39689
  "kind": "class",
39661
- "description": "`<obc-transmitter-button>` – The pressable readout chip used as the core of a\ntransmitter on a process diagram.\n\nThe value content (leading icon, optional advice and setpoint segments,\nvalue, unit) is laid out inline. The value, advice and setpoint segments all\nshare one numeric format, so they support fixed-width values and muted\nleading zeros identically. The leading icon is slotted so the consumer\nprovides the type-specific content.\n\n### Features / Variants\n- **`value`** – white, bordered box showing an icon, value and unit. Opt into a\n leading advice segment with `hasAdvice`/`adviceValue` and a setpoint segment\n with `hasSetPoint`/`setpointValue`.\n- **`tag`** – a static rounded pill showing a short identifier (e.g. `TT`)\n from the `label` property, with no live value.\n- **`size`** – `regular`, `medium` or `large`, scaling the value text, the icon\n glyph and the advice/setpoint segments. The unit stays at a fixed size across\n all sizes.\n- **Formatting** – `fractionDigits` sets the decimal precision, `maxDigits`\n reserves a number of integer digits, and `hintedZeros` renders the reserved\n leading positions as muted zeros (e.g. `0012.3`). The sign never consumes\n a reserved position (`-0012.3`), so a negative value is one character\n wider than a positive one; `hasSignSpacer` reserves the sign column so\n the width does not change across zero. All three segments share this\n formatting — it is `obc-readout-block`'s.\n- **Missing values** – `value`, `adviceValue` and `setpointValue` each render\n dashes when they are `NaN`, `null` or `undefined`; with `hintedZeros` the\n dashes fill the whole reserved width (e.g. `---.-`).\n\n### Usage Guidelines\nUse as a building block for `<obc-transmitter>`; it is the part that carries\nthe measured value or the tag identifier. Slot in the type-specific icon; the\nadvice and setpoint segments are value-driven and read-only.\n\n### Slots\n| Slot Name | Conditions | Purpose |\n|-----------|-------------------------------|--------------------------------|\n| icon | `value` variant and `hasIcon` | Leading icon beside the value. |",
39690
+ "description": "`<obc-transmitter-button>` – The pressable readout chip at the core of a\ntransmitter: a bordered button around one reading.\n\nThe reading is a label-less `<obc-readout-list-item>` (the Figma \"automation\nvalue\"): leading icon, optional advice and setpoint, value, optional degree\nand unit, all rendered by the readout family. The leading icon is slotted so\nthe consumer provides the type-specific content.\n\n### Features / Variants\n- **`value`** – bordered chip showing an icon, value and unit. Opt into a\n leading advice segment with `hasAdvice`/`adviceValue`, a setpoint segment\n with `hasSetPoint`/`setpointValue`, and a degree column before the unit\n with `hasDegree`.\n- **`tag`** – a static rounded pill showing a short identifier (e.g. `TT`)\n from the `label` property, with no live value.\n- **`size`** – `regular`, `medium` or `large`, the list item's `small`,\n `medium` and `large` tiers: the value text, the icon and the advice/setpoint\n segments scale, the unit stays extra small.\n- **Formatting** – `fractionDigits` sets the decimal precision, `maxDigits`\n reserves a number of integer digits, and `hintedZeros` renders the reserved\n leading positions as muted zeros (e.g. `0012.3`). The sign never consumes\n a reserved position (`-0012.3`), so a negative value is one character\n wider than a positive one; `hasSignSpacer` reserves the sign column so\n the width does not change across zero. All three segments share this\n formatting — it is `obc-readout-block`'s.\n- **Missing values** – `value`, `adviceValue` and `setpointValue` each render\n dashes when they are `NaN`, `null` or `undefined`; with `hintedZeros` the\n dashes fill the whole reserved width (e.g. `---.-`).\n\n### Usage Guidelines\nUse as a building block for `<obc-transmitter>` and `<obc-transmitter-stack>`;\nit is the part that carries the measured value or the tag identifier. Slot in\nthe type-specific icon; the advice and setpoint segments are value-driven and\nread-only.\n\n**TODO(designer):** the hit area is the visible chip, 24 px high at `regular`:\nat the WCAG 2.5.8 floor of 24 px, below the 48 px touch-target token. A\n48 px target would overlap the id tag, the leader line and neighbouring\n`<obc-transmitter-stack>` segments, so the size needs a design decision.\n\n### Slots\n| Slot Name | Conditions | Purpose |\n|-----------|-------------------------------|--------------------------------|\n| icon | `value` variant and `hasIcon` | Leading icon beside the value. |",
39662
39691
  "name": "ObcTransmitterButton",
39663
39692
  "slots": [
39664
39693
  {
@@ -39730,6 +39759,15 @@
39730
39759
  "default": "false",
39731
39760
  "description": "Reserve a minus-sign column on every segment, filled by the real sign only while a value is negative, so the width does not change across zero."
39732
39761
  },
39762
+ {
39763
+ "kind": "field",
39764
+ "name": "hasDegree",
39765
+ "type": {
39766
+ "text": "boolean"
39767
+ },
39768
+ "default": "false",
39769
+ "description": "Show a degree column between the value and the unit (e.g. `12.3°` then `C`)."
39770
+ },
39733
39771
  {
39734
39772
  "kind": "field",
39735
39773
  "name": "hasIcon",
@@ -39779,6 +39817,15 @@
39779
39817
  "default": "''",
39780
39818
  "description": "Short tag identifier shown in the `tag` variant (e.g. `TT`)."
39781
39819
  },
39820
+ {
39821
+ "kind": "field",
39822
+ "name": "idTag",
39823
+ "type": {
39824
+ "text": "string"
39825
+ },
39826
+ "default": "''",
39827
+ "description": "Identifier appended to the button's accessible name only (e.g. `#0001`); the parent transmitter draws the visible tag outside the button, where it cannot join the name."
39828
+ },
39782
39829
  {
39783
39830
  "kind": "field",
39784
39831
  "name": "isTag",
@@ -39787,37 +39834,120 @@
39787
39834
  },
39788
39835
  {
39789
39836
  "kind": "method",
39790
- "name": "renderBlock",
39837
+ "name": "renderReading",
39838
+ "privacy": "private"
39839
+ },
39840
+ {
39841
+ "kind": "method",
39842
+ "name": "render"
39843
+ },
39844
+ {
39845
+ "kind": "field",
39846
+ "name": "styles",
39847
+ "static": true
39848
+ }
39849
+ ],
39850
+ "superclass": {
39851
+ "name": "LitElement",
39852
+ "package": "lit"
39853
+ },
39854
+ "customElement": true
39855
+ }
39856
+ ],
39857
+ "exports": [
39858
+ {
39859
+ "kind": "js",
39860
+ "name": "ObcTransmitterButton",
39861
+ "declaration": {
39862
+ "name": "ObcTransmitterButton",
39863
+ "module": "src/automation/transmitter-button/transmitter-button.ts"
39864
+ }
39865
+ }
39866
+ ]
39867
+ },
39868
+ {
39869
+ "kind": "javascript-module",
39870
+ "path": "src/automation/transmitter-stack/transmitter-stack.ts",
39871
+ "declarations": [
39872
+ {
39873
+ "kind": "class",
39874
+ "description": "`<obc-transmitter-stack>` – Several transmitter readings side by side in one\njoined chip, attached to a line by a single leader line.\n\nEach entry of `values` renders an `<obc-transmitter-button>` segment with its\nown icon, value, unit and id tag. The segments take equal widths, set by the\nwidest reading, and share their borders. Positioning and the leader line\nfollow `<obc-transmitter>`.\n\n### Features / Variants\n- **`orientation`** – `top`, `right`, `bottom`, `left`; the edge the leader\n line attaches to. `top` places the id tags above the chip.\n- **Values** – `value` and `unit` per segment. `idTag` adds a label row under\n every segment once any value has one, so the chip stays aligned.\n- **Formatting** – per value `fractionDigits` (default `1`), `maxDigits`\n (default `0`), `hintedZeros`, `hasSignSpacer` and `hasDegree`, formatted like\n `<obc-transmitter-button>`. An omitted key takes its default; a key set to\n `null`, `undefined` or `NaN` renders the reading as the unavailable dash.\n- **Icons** – `iconSlotName` projects the light-DOM element with that slot\n name as the segment's icon; names must be unique within the stack. The\n name is chosen per value, so it carries no `@slot` tag (the wrapper\n generator needs literal names).\n- **Accessible name** – each segment is a native button named by its\n reading, unit and `idTag`; the visible tag is hidden from assistive\n technology so it is not read twice.\n- **Empty** – with no `values` nothing renders, leader line included.\n\n### Usage Guidelines\nUse when one source reports several readings that share one leader line. For\na single reading, a tag pill or a trend graph, use `<obc-transmitter>`. Each\nsegment's hit area is `<obc-transmitter-button>`'s chip (24 px high), below\nthe 48 px touch-target token; see its design note.\n\n### Slots\n| Slot Name | Conditions | Purpose |\n|------------------|---------------------------------|-------------------------------|\n| `<iconSlotName>` | a value declares `iconSlotName` | Icon in that value's segment. |",
39875
+ "name": "ObcTransmitterStack",
39876
+ "members": [
39877
+ {
39878
+ "kind": "field",
39879
+ "name": "orientation",
39880
+ "type": {
39881
+ "text": "TransmitterOrientation"
39882
+ },
39883
+ "description": "Edge of the chip the leader line attaches to."
39884
+ },
39885
+ {
39886
+ "kind": "field",
39887
+ "name": "lineType",
39888
+ "type": {
39889
+ "text": "LineType | undefined"
39890
+ },
39891
+ "default": "undefined",
39892
+ "description": "Line the transmitter sits on; offsets the leader line by half its stroke."
39893
+ },
39894
+ {
39895
+ "kind": "field",
39896
+ "name": "values",
39897
+ "type": {
39898
+ "text": "TransmitterStackValue[]"
39899
+ },
39900
+ "default": "[]",
39901
+ "description": "One segment per entry, in order."
39902
+ },
39903
+ {
39904
+ "kind": "method",
39905
+ "name": "handleValueClick",
39791
39906
  "privacy": "private",
39907
+ "return": {
39908
+ "type": {
39909
+ "text": "void"
39910
+ }
39911
+ },
39792
39912
  "parameters": [
39793
39913
  {
39794
- "name": "variant",
39914
+ "name": "index",
39795
39915
  "type": {
39796
- "text": "ReadoutBlockVariant"
39916
+ "text": "number"
39797
39917
  }
39798
39918
  },
39799
39919
  {
39800
39920
  "name": "value",
39801
39921
  "type": {
39802
- "text": "number | null | undefined"
39922
+ "text": "TransmitterStackValue"
39803
39923
  }
39804
39924
  }
39805
39925
  ]
39806
39926
  },
39807
39927
  {
39808
39928
  "kind": "method",
39809
- "name": "renderAdvice",
39810
- "privacy": "private"
39811
- },
39812
- {
39813
- "kind": "method",
39814
- "name": "renderSetpoint",
39815
- "privacy": "private"
39816
- },
39817
- {
39818
- "kind": "method",
39819
- "name": "renderContent",
39820
- "privacy": "private"
39929
+ "name": "renderValue",
39930
+ "privacy": "private",
39931
+ "parameters": [
39932
+ {
39933
+ "name": "entry",
39934
+ "type": {
39935
+ "text": "TransmitterStackValue"
39936
+ }
39937
+ },
39938
+ {
39939
+ "name": "index",
39940
+ "type": {
39941
+ "text": "number"
39942
+ }
39943
+ },
39944
+ {
39945
+ "name": "hasIdTags",
39946
+ "type": {
39947
+ "text": "boolean"
39948
+ }
39949
+ }
39950
+ ]
39821
39951
  },
39822
39952
  {
39823
39953
  "kind": "method",
@@ -39829,6 +39959,19 @@
39829
39959
  "static": true
39830
39960
  }
39831
39961
  ],
39962
+ "events": [
39963
+ {
39964
+ "name": "value-click",
39965
+ "type": {
39966
+ "text": "CustomEvent<TransmitterStackValueClickDetail>"
39967
+ },
39968
+ "description": "Fired when a segment is activated, with its value and index."
39969
+ },
39970
+ {
39971
+ "description": "Fired when any segment is clicked; `value-click` tells which.",
39972
+ "name": "click"
39973
+ }
39974
+ ],
39832
39975
  "superclass": {
39833
39976
  "name": "LitElement",
39834
39977
  "package": "lit"
@@ -39839,10 +39982,10 @@
39839
39982
  "exports": [
39840
39983
  {
39841
39984
  "kind": "js",
39842
- "name": "ObcTransmitterButton",
39985
+ "name": "ObcTransmitterStack",
39843
39986
  "declaration": {
39844
- "name": "ObcTransmitterButton",
39845
- "module": "src/automation/transmitter-button/transmitter-button.ts"
39987
+ "name": "ObcTransmitterStack",
39988
+ "module": "src/automation/transmitter-stack/transmitter-stack.ts"
39846
39989
  }
39847
39990
  }
39848
39991
  ]
@@ -39853,7 +39996,7 @@
39853
39996
  "declarations": [
39854
39997
  {
39855
39998
  "kind": "class",
39856
- "description": "`<obc-transmitter>` – A readout label that attaches to a line on a process\ndiagram via a leader line, showing a measured value, a tag identifier, or a\nvalue paired with a trend graph.\n\nPositioning (orientation + leader line) follows `<obc-automation-readout>`.\nThe value chip is an `<obc-transmitter-button>` and the trend is an\n`<obc-indicator-graph>` with its area fill enabled.\n\n### Features / Variants\n- **`type`** – `indicator` (tag pill), `value` (icon/value/unit), or value\n paired with a `horizontal-graph` (beside) or `vertical-graph` (below).\n- **`orientation`** – `top`, `right`, `bottom`, `left`; controls which edge\n the leader line attaches to.\n- **Segments** – opt into a leading advice segment with `hasAdvice`/\n `adviceValue` and a setpoint segment with `hasSetPoint`/`setpointValue`;\n both are read-only and shown in the value chip for non-`indicator` types.\n- **`hasAlert`** – wraps the whole transmitter in an alarm `<obc-alert-frame>`.\n- **Formatting** – `fractionDigits`, `maxDigits`, `hintedZeros` and\n `hasSignSpacer` are forwarded to the value chip to control decimal\n precision, muted leading-zero padding (e.g. `0012.3`) and the sign\n column. The advice and setpoint segments reuse the same formatting.\n `value`, `adviceValue` and `setpointValue` render dashes when they are\n `NaN`, `null` or `undefined`.\n\n### Slots\n| Slot Name | Conditions | Purpose |\n|-----------|-------------------------|---------------------------------|\n| icon | value/graph + `hasIcon` | Leading icon in the value chip. |",
39999
+ "description": "`<obc-transmitter>` – A readout label that attaches to a line via a leader\nline, showing a measured value, a tag identifier, or a value paired with a\ntrend graph.\n\nPositioning (orientation + leader line) follows `<obc-automation-readout>`.\nThe value chip is an `<obc-transmitter-button>` and the trend is an\n`<obc-indicator-graph>` with its area fill enabled.\n\n### Features / Variants\n- **`type`** – `indicator` (tag pill), `value` (icon/value/unit), or value\n paired with a `horizontal-graph` (beside) or `vertical-graph` (below).\n- **`orientation`** – `top`, `right`, `bottom`, `left`; controls which edge\n the leader line attaches to.\n- **Segments** – opt into a leading advice segment with `hasAdvice`/\n `adviceValue` and a setpoint segment with `hasSetPoint`/`setpointValue`;\n both are read-only and shown in the value chip for non-`indicator` types.\n- **`hasAlert`** – wraps the whole transmitter in an alarm `<obc-alert-frame>`.\n- **Formatting** – `fractionDigits`, `maxDigits`, `hintedZeros` and\n `hasSignSpacer` are forwarded to the value chip to control decimal\n precision, muted leading-zero padding (e.g. `0012.3`) and the sign\n column. The advice and setpoint segments reuse the same formatting.\n `hasDegree` adds a degree column between the value and the unit.\n `value`, `adviceValue` and `setpointValue` render dashes when they are\n `NaN`, `null` or `undefined`.\n\n### Slots\n| Slot Name | Conditions | Purpose |\n|-----------|-------------------------|---------------------------------|\n| icon | value/graph + `hasIcon` | Leading icon in the value chip. |",
39857
40000
  "name": "ObcTransmitter",
39858
40001
  "slots": [
39859
40002
  {
@@ -39933,6 +40076,15 @@
39933
40076
  "default": "false",
39934
40077
  "description": "Reserve a minus-sign column on every segment, filled by the real sign only while a value is negative, so the chip's width does not change across zero."
39935
40078
  },
40079
+ {
40080
+ "kind": "field",
40081
+ "name": "hasDegree",
40082
+ "type": {
40083
+ "text": "boolean"
40084
+ },
40085
+ "default": "false",
40086
+ "description": "Show a degree column between the value and the unit (e.g. `12.3°` then `C`)."
40087
+ },
39936
40088
  {
39937
40089
  "kind": "field",
39938
40090
  "name": "size",
@@ -40022,12 +40174,6 @@
40022
40174
  "privacy": "private",
40023
40175
  "readonly": true
40024
40176
  },
40025
- {
40026
- "kind": "field",
40027
- "name": "lineOffset",
40028
- "privacy": "private",
40029
- "readonly": true
40030
- },
40031
40177
  {
40032
40178
  "kind": "method",
40033
40179
  "name": "renderButton",
@@ -40066,6 +40212,22 @@
40066
40212
  }
40067
40213
  ],
40068
40214
  "exports": [
40215
+ {
40216
+ "kind": "js",
40217
+ "name": "TransmitterOrientation",
40218
+ "declaration": {
40219
+ "name": "TransmitterOrientation",
40220
+ "module": "./transmitter-shared.js"
40221
+ }
40222
+ },
40223
+ {
40224
+ "kind": "js",
40225
+ "name": "transmitterLeaderOffset",
40226
+ "declaration": {
40227
+ "name": "transmitterLeaderOffset",
40228
+ "module": "./transmitter-shared.js"
40229
+ }
40230
+ },
40069
40231
  {
40070
40232
  "kind": "js",
40071
40233
  "name": "ObcTransmitter",
@@ -87641,7 +87803,7 @@
87641
87803
  "privacy": "private",
87642
87804
  "return": {
87643
87805
  "type": {
87644
- "text": "TemplateResult"
87806
+ "text": "TemplateResult | typeof nothing"
87645
87807
  }
87646
87808
  }
87647
87809
  },
@@ -0,0 +1,11 @@
1
+ import { LineType } from '../index.js';
2
+ /** Edge of a transmitter's chip that the leader line attaches to. */
3
+ export declare enum TransmitterOrientation {
4
+ top = "top",
5
+ right = "right",
6
+ bottom = "bottom",
7
+ left = "left"
8
+ }
9
+ /** Half the line's stroke width, so the leader line starts on the line's edge. */
10
+ export declare function transmitterLeaderOffset(lineType: LineType | undefined): number;
11
+ //# sourceMappingURL=transmitter-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transmitter-shared.d.ts","sourceRoot":"","sources":["../../../src/automation/transmitter/transmitter-shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AAEhD,qEAAqE;AACrE,oBAAY,sBAAsB;IAChC,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAED,kFAAkF;AAClF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAC7B,MAAM,CAER"}
@@ -0,0 +1,16 @@
1
+ import { lineWidth } from "../index.js";
2
+ var TransmitterOrientation = /* @__PURE__ */ ((TransmitterOrientation2) => {
3
+ TransmitterOrientation2["top"] = "top";
4
+ TransmitterOrientation2["right"] = "right";
5
+ TransmitterOrientation2["bottom"] = "bottom";
6
+ TransmitterOrientation2["left"] = "left";
7
+ return TransmitterOrientation2;
8
+ })(TransmitterOrientation || {});
9
+ function transmitterLeaderOffset(lineType) {
10
+ return lineType === void 0 ? 0 : lineWidth(lineType) / 2;
11
+ }
12
+ export {
13
+ TransmitterOrientation,
14
+ transmitterLeaderOffset
15
+ };
16
+ //# sourceMappingURL=transmitter-shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transmitter-shared.js","sources":["../../../src/automation/transmitter/transmitter-shared.ts"],"sourcesContent":["import {LineType, lineWidth} from '../index.js';\n\n/** Edge of a transmitter's chip that the leader line attaches to. */\nexport enum TransmitterOrientation {\n top = 'top',\n right = 'right',\n bottom = 'bottom',\n left = 'left',\n}\n\n/** Half the line's stroke width, so the leader line starts on the line's edge. */\nexport function transmitterLeaderOffset(\n lineType: LineType | undefined\n): number {\n return lineType === undefined ? 0 : lineWidth(lineType) / 2;\n}\n"],"names":["TransmitterOrientation"],"mappings":";AAGO,IAAK,2CAAAA,4BAAL;AACLA,0BAAA,KAAA,IAAM;AACNA,0BAAA,OAAA,IAAQ;AACRA,0BAAA,QAAA,IAAS;AACTA,0BAAA,MAAA,IAAO;AAJG,SAAAA;AAAA,GAAA,0BAAA,CAAA,CAAA;AAQL,SAAS,wBACd,UACQ;AACR,SAAO,aAAa,SAAY,IAAI,UAAU,QAAQ,IAAI;AAC5D;"}
@@ -74,7 +74,19 @@ const componentStyle = css`* {
74
74
  left: -4px;
75
75
  }
76
76
 
77
+ /* Left/right anchor on the chip row's middle (Figma 25656:45233), so the id
78
+ tag hangs below out of flow; its parent must be the containing block. */
79
+
80
+ .transmitter:is(.orientation-left,.orientation-right):not(.has-alert) .id-tag {
81
+ position: absolute;
82
+ top: calc(100% + 2px);
83
+ left: 50%;
84
+ transform: translateX(-50%);
85
+ white-space: nowrap;
86
+ }
87
+
77
88
  .content {
89
+ position: relative; /* containing block for the left/right id tag (transmitter-leader) */
78
90
  display: flex;
79
91
  flex-direction: column;
80
92
  align-items: center;
@@ -141,7 +153,6 @@ const componentStyle = css`* {
141
153
  }
142
154
 
143
155
  .id-tag {
144
- color: var(--element-neutral-color);
145
156
  color: var(--element-neutral-color);
146
157
  font-variant-numeric: lining-nums tabular-nums;
147
158
  font-feature-settings: "ss04" on;
@@ -1 +1 @@
1
- {"version":3,"file":"transmitter.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"transmitter.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,15 +1,11 @@
1
1
  import { LitElement } from 'lit';
2
2
  import { LineType } from '../index.js';
3
+ import { TransmitterOrientation } from './transmitter-shared.js';
3
4
  import { TransmitterButtonSize } from '../transmitter-button/transmitter-button.js';
4
5
  import '../transmitter-button/transmitter-button.js';
5
6
  import '../../navigation-instruments/indicator-graph/indicator-graph.js';
6
7
  import '../../components/alert-frame/alert-frame.js';
7
- export declare enum TransmitterOrientation {
8
- top = "top",
9
- right = "right",
10
- bottom = "bottom",
11
- left = "left"
12
- }
8
+ export { TransmitterOrientation, transmitterLeaderOffset, } from './transmitter-shared.js';
13
9
  export declare enum TransmitterType {
14
10
  indicator = "indicator",
15
11
  value = "value",
@@ -17,9 +13,9 @@ export declare enum TransmitterType {
17
13
  verticalGraph = "vertical-graph"
18
14
  }
19
15
  /**
20
- * `<obc-transmitter>` – A readout label that attaches to a line on a process
21
- * diagram via a leader line, showing a measured value, a tag identifier, or a
22
- * value paired with a trend graph.
16
+ * `<obc-transmitter>` – A readout label that attaches to a line via a leader
17
+ * line, showing a measured value, a tag identifier, or a value paired with a
18
+ * trend graph.
23
19
  *
24
20
  * Positioning (orientation + leader line) follows `<obc-automation-readout>`.
25
21
  * The value chip is an `<obc-transmitter-button>` and the trend is an
@@ -38,6 +34,7 @@ export declare enum TransmitterType {
38
34
  * `hasSignSpacer` are forwarded to the value chip to control decimal
39
35
  * precision, muted leading-zero padding (e.g. `0012.3`) and the sign
40
36
  * column. The advice and setpoint segments reuse the same formatting.
37
+ * `hasDegree` adds a degree column between the value and the unit.
41
38
  * `value`, `adviceValue` and `setpointValue` render dashes when they are
42
39
  * `NaN`, `null` or `undefined`.
43
40
  *
@@ -50,6 +47,7 @@ export declare enum TransmitterType {
50
47
  * @property hasSignSpacer - Reserve a minus-sign column on every segment, filled by the real sign
51
48
  * only while a value is negative, so the chip's width does not change
52
49
  * across zero.
50
+ * @property hasDegree - Show a degree column between the value and the unit (e.g. `12.3°` then `C`).
53
51
  * @property hasAlert - Wrap the transmitter in an `<obc-alert-frame>` (alarm) when true.
54
52
  * @property adviceValue - Advisory value shown in the leading advice segment when `hasAdvice`.
55
53
  * @property setpointValue - Target value shown in the setpoint segment when `hasSetPoint`.
@@ -72,6 +70,8 @@ export declare class ObcTransmitter extends LitElement {
72
70
  hintedZeros: boolean;
73
71
  /** Reserve a minus-sign column on every segment, filled by the real sign only while a value is negative, so the chip's width does not change across zero. */
74
72
  hasSignSpacer: boolean;
73
+ /** Show a degree column between the value and the unit (e.g. `12.3°` then `C`). */
74
+ hasDegree: boolean;
75
75
  size: TransmitterButtonSize;
76
76
  hasIcon: boolean;
77
77
  hasAdvice: boolean;
@@ -89,7 +89,6 @@ export declare class ObcTransmitter extends LitElement {
89
89
  /** Trend data for the graph types: `[xValues, yValues]`. */
90
90
  data: [number[], number[]];
91
91
  private get hasGraph();
92
- private get lineOffset();
93
92
  private renderButton;
94
93
  private renderGraph;
95
94
  private renderLabel;
@@ -1 +1 @@
1
- {"version":3,"file":"transmitter.d.ts","sourceRoot":"","sources":["../../../src/automation/transmitter/transmitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,KAAK,CAAC;AAKzD,OAAO,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,qBAAqB,EAEtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,6CAA6C,CAAC;AAKrD,OAAO,iEAAiE,CAAC;AAEzE,OAAO,6CAA6C,CAAC;AAErD,oBAAY,sBAAsB;IAChC,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAED,oBAAY,eAAe;IACzB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,eAAe,qBAAqB;IACpC,aAAa,mBAAmB;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,qBACa,cAAe,SAAQ,UAAU;IAClB,WAAW,EAAE,sBAAsB,CAC7B;IACN,IAAI,EAAE,eAAe,CAAyB;IAC9C,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAa;IAE3C,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,SAAM;IACV,cAAc,SAAK;IAEnB,SAAS,SAAK;IAEb,WAAW,UAAS;IACpB,aAAa,UAAS;IACvB,IAAI,EAAE,qBAAqB,CACrB;IACL,OAAO,UAAS;IAChB,SAAS,UAAS;IAElB,QAAQ,UAAS;IAElB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,WAAW,UAAS;IAErB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B,GAAG,SAAM;IAET,KAAK,SAAM;IAEZ,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAY;IAE/D,OAAO,KAAK,QAAQ,GAKnB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,aAAa;IASZ,MAAM;IA4Bf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,cAAc,CAAC;KACnC;CACF"}
1
+ {"version":3,"file":"transmitter.d.ts","sourceRoot":"","sources":["../../../src/automation/transmitter/transmitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,KAAK,CAAC;AAKzD,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AACrC,OAAO,EACL,sBAAsB,EAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,qBAAqB,EAEtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,6CAA6C,CAAC;AAKrD,OAAO,iEAAiE,CAAC;AAEzE,OAAO,6CAA6C,CAAC;AAErD,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAEjC,oBAAY,eAAe;IACzB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,eAAe,qBAAqB;IACpC,aAAa,mBAAmB;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,qBACa,cAAe,SAAQ,UAAU;IAClB,WAAW,EAAE,sBAAsB,CAC7B;IACN,IAAI,EAAE,eAAe,CAAyB;IAC9C,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAa;IAE3C,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,SAAM;IACV,cAAc,SAAK;IAEnB,SAAS,SAAK;IAEb,WAAW,UAAS;IACpB,aAAa,UAAS;IACtB,SAAS,UAAS;IACnB,IAAI,EAAE,qBAAqB,CACrB;IACL,OAAO,UAAS;IAChB,SAAS,UAAS;IAElB,QAAQ,UAAS;IAElB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,WAAW,UAAS;IAErB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B,GAAG,SAAM;IAET,KAAK,SAAM;IAEZ,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAY;IAE/D,OAAO,KAAK,QAAQ,GAKnB;IAED,OAAO,CAAC,YAAY;IA6BpB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,aAAa;IASZ,MAAM;IA4Bf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,cAAc,CAAC;KACnC;CACF"}