@oicl/openbridge-webcomponents 2.0.0-next.88 → 2.0.0-next.89

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 (22) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +17344 -16794
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +720 -43
  4. package/dist/building-blocks/readout-block/readout-block.css.js +229 -0
  5. package/dist/building-blocks/readout-block/readout-block.css.js.map +1 -0
  6. package/dist/building-blocks/readout-block/readout-block.d.ts +146 -0
  7. package/dist/building-blocks/readout-block/readout-block.d.ts.map +1 -0
  8. package/dist/building-blocks/readout-block/readout-block.js +273 -0
  9. package/dist/building-blocks/readout-block/readout-block.js.map +1 -0
  10. package/dist/navigation-instruments/readout-list/readout-list.css.js +24 -0
  11. package/dist/navigation-instruments/readout-list/readout-list.css.js.map +1 -0
  12. package/dist/navigation-instruments/readout-list/readout-list.d.ts +70 -0
  13. package/dist/navigation-instruments/readout-list/readout-list.d.ts.map +1 -0
  14. package/dist/navigation-instruments/readout-list/readout-list.js +154 -0
  15. package/dist/navigation-instruments/readout-list/readout-list.js.map +1 -0
  16. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +80 -145
  17. package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
  18. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +25 -26
  19. package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
  20. package/dist/navigation-instruments/readout-list-item/readout-list-item.js +66 -118
  21. package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
  22. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readout-block.js","sources":["../../../src/building-blocks/readout-block/readout-block.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS, type TemplateResult} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport componentStyle from './readout-block.css?inline';\nimport {customElement} from '../../decorator.js';\nimport '../../components/textbox/textbox.js';\nimport {\n ObcTextboxSize,\n ObcTextboxFontWeight,\n ObcTextboxAlignment,\n} from '../../components/textbox/textbox.js';\nimport '../../icons/icon-input-right.js';\nimport '../../icons/icon-notification-advice.js';\nimport {\n formatNumericValue,\n readoutFormattedInteger,\n type ReadoutNumericFormatOptions,\n} from '../../navigation-instruments/readout/readout-formatters.js';\nimport {\n type AlertFrameConfig,\n wrapWithAlertFrame,\n} from '../../components/alert-frame/alert-frame.js';\n\n// Re-exported so consumers can configure typography without a second import path.\nexport {\n ObcTextboxSize,\n ObcTextboxFontWeight,\n ObcTextboxAlignment,\n} from '../../components/textbox/textbox.js';\n\n/**\n * Semantic variant of the block. Drives the default marker icon and the\n * colour token; the layout is identical across variants.\n * - `value`: the primary reading (no default marker icon).\n * - `setpoint`: a setpoint reference (default `input-right` marker).\n * - `advice`: an advisory reference (default `notification-advice` marker).\n */\nexport enum ReadoutBlockVariant {\n value = 'value',\n setpoint = 'setpoint',\n advice = 'advice',\n}\n\n/**\n * Density tier of the block — drives icon size, the icon↔number gap, and the\n * degree-column width tier. The number typography size is controlled\n * independently via {@link ObcReadoutBlock.valueSize} so a parent can de-emphasise\n * one block relative to another within the same tier.\n */\nexport enum ReadoutBlockSize {\n small = 'small',\n medium = 'medium',\n large = 'large',\n}\n\n/**\n * Per-block measurement quality, rendered as a non-shifting outline chip.\n * - `low-integrity`: the value is suspect.\n * - `invalid`: the value is invalid.\n */\nexport enum ReadoutBlockDataQuality {\n lowIntegrity = 'low-integrity',\n invalid = 'invalid',\n}\n\n/**\n * Pop-up fade phase for a setpoint block. Driven by the parent's setpoint\n * interaction state machine; only meaningful for `role=\"setpoint\"`.\n */\nexport enum ReadoutBlockHidePhase {\n none = 'none',\n hiding = 'hiding',\n hidden = 'hidden',\n}\n\n/**\n * `<obc-readout-block>` – the most atomic readout primitive: a single\n * cap-height-aligned, width-reservable numeric segment (value / setpoint /\n * advice).\n *\n * It renders one `obc-textbox` number with optional hinted leading zeros, a\n * reservable width, an optional leading marker icon (via the `icon` slot or the\n * role default), an optional trailing degree glyph, an `off`/unavailable text\n * state, per-block data-quality and an optional per-block alert frame.\n *\n * This is a building block used inside `obc-readout-list-item` (and, in a future\n * refactor, inside `obc-readout`); it is not normally used on its own. Colour is\n * inherited from the host context (the parent sets the role colour), so the\n * block stays neutral until placed.\n *\n * @experimental Pilot for the new primitives + per-block options Readout API; the\n * API may change in a future release.\n *\n * @slot icon - Replaces the role's default marker icon.\n *\n * @csspart block - The block container (carries role / tone / data-quality).\n * @csspart block-content - The number + degree group.\n * @csspart block-text - The `obc-textbox` rendering the number.\n * @csspart block-icon - The leading marker-icon container.\n * @csspart degree - The trailing degree-glyph column.\n */\n@customElement('obc-readout-block')\nexport class ObcReadoutBlock extends LitElement {\n /** Semantic variant (value / setpoint / advice). */\n @property({type: String}) variant: ReadoutBlockVariant =\n ReadoutBlockVariant.value;\n\n /** The numeric value; `null`/`undefined` renders a dash. */\n @property({type: Number}) value: number | null = null;\n\n /** Density tier — icon size, gap, degree tier. */\n @property({type: String}) size: ReadoutBlockSize = ReadoutBlockSize.small;\n\n /**\n * Resolved number-typography size. When unset it is derived from `size`\n * (small→s, medium→m, large→l), so a parent that de-emphasises a block (e.g.\n * a secondary setpoint) can pass a smaller size without changing the tier.\n */\n @property({type: String}) valueSize?: ObcTextboxSize;\n\n /** Accent (in-command) colour tone. */\n @property({type: Boolean}) enhanced = false;\n\n /** Number font weight (regular / semibold / bold); colour is independent. */\n @property({type: String}) weight: ObcTextboxFontWeight =\n ObcTextboxFontWeight.regular;\n\n /** Render the trailing cap-height degree glyph (`°`). */\n @property({type: Boolean}) hasDegree = false;\n\n /** Show the leading marker-icon container (always on for setpoint/advice). */\n @property({type: Boolean}) hasIcon = false;\n\n /** Number of fraction digits. */\n @property({type: Number}) fractionDigits = 0;\n\n /** Integer digits to reserve / hint (independent of `fractionDigits`). */\n @property({type: Number}) maxDigits = 0;\n\n /** Render muted leading zeros filling the integer part to `maxDigits`. */\n @property({type: Boolean}) hintedZeros = false;\n\n /** Explicit longest string to reserve width for (e.g. `\"0000.0\"`). */\n @property({type: String}) spaceReserver?: string;\n\n /** Render `offText` instead of a number (e.g. equipment powered down). */\n @property({type: Boolean}) off = false;\n\n /** Text shown when `off` is true. */\n @property({type: String}) offText = 'OFF';\n\n /** Text alignment of the number within its reserved width. */\n @property({type: String}) alignment: ObcTextboxAlignment =\n ObcTextboxAlignment.Right;\n\n /** Per-block measurement quality (outline chip). */\n @property({type: String}) dataQuality?: ReadoutBlockDataQuality;\n\n // `boolean | …` (not `false | …`): the generated Angular wrapper widens a\n // literal-`false` union to `boolean`. `wrapWithAlertFrame` treats any\n // non-object as \"no frame\", so accepting `boolean` is harmless.\n /** Per-block alert frame; nests inside any parent alert frame. */\n @property({type: Object}) alert: boolean | AlertFrameConfig = false;\n\n /** Setpoint focus (touch) state — only meaningful for `role=\"setpoint\"`. */\n @property({type: Boolean}) touching = false;\n\n /** Setpoint pop-up fade phase — only meaningful for `role=\"setpoint\"`. */\n @property({type: String}) hidePhase: ReadoutBlockHidePhase =\n ReadoutBlockHidePhase.none;\n\n @state() private hasAssignedIcon = false;\n\n private get resolvedValueSize(): ObcTextboxSize {\n if (this.valueSize) {\n return this.valueSize;\n }\n switch (this.size) {\n case ReadoutBlockSize.large:\n return ObcTextboxSize.l;\n case ReadoutBlockSize.medium:\n return ObcTextboxSize.m;\n default:\n return ObcTextboxSize.s;\n }\n }\n\n private get numericFormatOptions(): ReadoutNumericFormatOptions {\n return {\n showZeroPadding: false,\n minValueLength: this.maxDigits,\n fractionDigits: this.fractionDigits,\n };\n }\n\n /** Widest possible value string for width reservation (e.g. `\"000.0\"`). */\n private get reserverText(): string {\n const maxDigits = this.maxDigits;\n if (maxDigits <= 0) {\n return '';\n }\n const integer = '0'.repeat(Math.max(maxDigits, 1));\n return this.fractionDigits > 0\n ? `${integer}.${'0'.repeat(this.fractionDigits)}`\n : integer;\n }\n\n /**\n * Effective width reserver: the wider of the explicit `spaceReserver` and the\n * `maxDigits`/`fractionDigits`-derived reserve, so an explicit reserver can\n * never reserve *less* than the formatted value needs. Under tabular-nums the\n * rendered width is proportional to character count, so \"wider\" compares length.\n */\n private widerReserver(explicit: string | undefined, derived: string): string {\n if (!explicit) {\n return derived;\n }\n if (!derived) {\n return explicit;\n }\n return explicit.length >= derived.length ? explicit : derived;\n }\n\n private dataQualityClasses(): Record<string, boolean> {\n return {\n 'data-low-integrity':\n this.dataQuality === ReadoutBlockDataQuality.lowIntegrity,\n 'data-invalid': this.dataQuality === ReadoutBlockDataQuality.invalid,\n };\n }\n\n private onIconSlotChange = (event: Event): void => {\n // `slotchange` fires after the first render once content is (re)assigned,\n // so it covers the initial state without a firstUpdated re-render.\n this.hasAssignedIcon =\n (event.target as HTMLSlotElement).assignedElements({flatten: true})\n .length > 0;\n };\n\n private renderIcon(): TemplateResult | typeof nothing {\n // Value blocks only show an icon when asked; setpoint/advice always reserve\n // their marker. The role default is rendered as a direct child (so it sizes\n // via `.block-icon obi-*`) and hidden once an icon is assigned to the slot —\n // `{flatten: true}` sees through a forwarded-but-empty parent slot, so the\n // default still shows when the consumer overrides nothing.\n const showIcon = this.variant !== ReadoutBlockVariant.value || this.hasIcon;\n if (!showIcon) {\n return nothing;\n }\n let fallback: TemplateResult | typeof nothing = nothing;\n if (this.variant === ReadoutBlockVariant.setpoint) {\n fallback = html`<obi-input-right></obi-input-right>`;\n } else if (this.variant === ReadoutBlockVariant.advice) {\n fallback = html`<obi-notification-advice></obi-notification-advice>`;\n }\n return html`<span class=\"block-icon\" part=\"block-icon\" aria-hidden=\"true\">\n <slot name=\"icon\" @slotchange=${this.onIconSlotChange}></slot>\n ${this.hasAssignedIcon ? nothing : fallback}\n </span>`;\n }\n\n /**\n * A cap-height `°` column whose width scales with the number size. Inherits the\n * block's colour.\n */\n private renderDegreeGlyph(size: ObcTextboxSize): TemplateResult {\n return html`\n <span\n class=${classMap({\n 'degree-column': true,\n [`degree-${size}`]: true,\n 'degree-inherit': true,\n })}\n part=\"degree\"\n >\n <obc-textbox class=\"degree-glyph\" .size=${size} alignment=\"center\"\n >°</obc-textbox\n >\n </span>\n `;\n }\n\n override render() {\n const valueSize = this.resolvedValueSize;\n const formatOptions = this.numericFormatOptions;\n const valueForFormat = this.value ?? undefined;\n const text = this.off\n ? this.offText\n : formatNumericValue(valueForFormat, formatOptions);\n // Hinted zeros pad the INTEGER part up to `maxDigits`, independent of\n // `fractionDigits` (the decimal point and fraction digits never count toward\n // `maxDigits`). Negative / dashed values are not padded. Example: value 1.2,\n // maxDigits 3, fractionDigits 1 → \"001.2\".\n const hintCount =\n this.off ||\n !this.hintedZeros ||\n valueForFormat === undefined ||\n valueForFormat < 0\n ? 0\n : Math.max(this.maxDigits - readoutFormattedInteger(text), 0);\n const hinted = hintCount > 0 ? '0'.repeat(hintCount) : '';\n // Hinted zeros own the width — they already fill to `maxDigits` — so when\n // `hintedZeros` is enabled an explicit `spaceReserver` is ignored (it has\n // higher priority). Otherwise the wider of the explicit reserver and the\n // `maxDigits`-derived reserve wins.\n const reserver = this.hintedZeros\n ? this.reserverText\n : this.widerReserver(this.spaceReserver, this.reserverText);\n\n const block = html`\n <div\n class=${classMap({\n block: true,\n [`block-${this.variant}`]: true,\n [`size-${this.size}`]: true,\n 'tone-enhanced': this.enhanced,\n touching: this.touching,\n 'is-hiding': this.hidePhase === ReadoutBlockHidePhase.hiding,\n 'is-hidden': this.hidePhase === ReadoutBlockHidePhase.hidden,\n ...this.dataQualityClasses(),\n })}\n part=\"block block-${this.variant}\"\n >\n ${this.renderIcon()}\n <span class=\"block-content\" part=\"block-content\">\n <obc-textbox\n class=\"block-text\"\n part=\"block-text\"\n .size=${valueSize}\n .fontWeight=${this.weight}\n .alignment=${this.alignment}\n .tabularNums=${true}\n >\n ${hinted\n ? html`<span class=\"hinted-zero\" aria-hidden=\"true\"\n >${hinted}</span\n >`\n : nothing}${text}\n ${reserver ? html`<span slot=\"length\">${reserver}</span>` : nothing}\n </obc-textbox>\n ${this.hasDegree ? this.renderDegreeGlyph(valueSize) : nothing}\n </span>\n </div>\n `;\n return wrapWithAlertFrame(this.alert ?? false, block);\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-readout-block': ObcReadoutBlock;\n }\n}\n"],"names":["ReadoutBlockVariant","ReadoutBlockSize","ReadoutBlockDataQuality","ReadoutBlockHidePhase"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqCO,IAAK,wCAAAA,yBAAL;AACLA,uBAAA,OAAA,IAAQ;AACRA,uBAAA,UAAA,IAAW;AACXA,uBAAA,QAAA,IAAS;AAHC,SAAAA;AAAA,GAAA,uBAAA,CAAA,CAAA;AAYL,IAAK,qCAAAC,sBAAL;AACLA,oBAAA,OAAA,IAAQ;AACRA,oBAAA,QAAA,IAAS;AACTA,oBAAA,OAAA,IAAQ;AAHE,SAAAA;AAAA,GAAA,oBAAA,CAAA,CAAA;AAWL,IAAK,4CAAAC,6BAAL;AACLA,2BAAA,cAAA,IAAe;AACfA,2BAAA,SAAA,IAAU;AAFA,SAAAA;AAAA,GAAA,2BAAA,CAAA,CAAA;AASL,IAAK,0CAAAC,2BAAL;AACLA,yBAAA,MAAA,IAAO;AACPA,yBAAA,QAAA,IAAS;AACTA,yBAAA,QAAA,IAAS;AAHC,SAAAA;AAAA,GAAA,yBAAA,CAAA,CAAA;AAiCL,IAAM,kBAAN,cAA8B,WAAW;AAAA,EAAzC,cAAA;AAAA,UAAA,GAAA,SAAA;AAEqB,SAAA,UACxB;AAGwB,SAAA,QAAuB;AAGvB,SAAA,OAAyB;AAUxB,SAAA,WAAW;AAGZ,SAAA,SACxB,qBAAqB;AAGI,SAAA,YAAY;AAGZ,SAAA,UAAU;AAGX,SAAA,iBAAiB;AAGjB,SAAA,YAAY;AAGX,SAAA,cAAc;AAMd,SAAA,MAAM;AAGP,SAAA,UAAU;AAGV,SAAA,YACxB,oBAAoB;AASI,SAAA,QAAoC;AAGnC,SAAA,WAAW;AAGZ,SAAA,YACxB;AAEO,SAAQ,kBAAkB;AA4DnC,SAAQ,mBAAmB,CAAC,UAAuB;AAGjD,WAAK,kBACF,MAAM,OAA2B,iBAAiB,EAAC,SAAS,KAAA,CAAK,EAC/D,SAAS;AAAA,IAChB;AAAA,EAAA;AAAA,EAhEA,IAAY,oBAAoC;AAC9C,QAAI,KAAK,WAAW;AAClB,aAAO,KAAK;AAAA,IACd;AACA,YAAQ,KAAK,MAAA;AAAA,MACX,KAAK;AACH,eAAO,eAAe;AAAA,MACxB,KAAK;AACH,eAAO,eAAe;AAAA,MACxB;AACE,eAAO,eAAe;AAAA,IAAA;AAAA,EAE5B;AAAA,EAEA,IAAY,uBAAoD;AAC9D,WAAO;AAAA,MACL,iBAAiB;AAAA,MACjB,gBAAgB,KAAK;AAAA,MACrB,gBAAgB,KAAK;AAAA,IAAA;AAAA,EAEzB;AAAA;AAAA,EAGA,IAAY,eAAuB;AACjC,UAAM,YAAY,KAAK;AACvB,QAAI,aAAa,GAAG;AAClB,aAAO;AAAA,IACT;AACA,UAAM,UAAU,IAAI,OAAO,KAAK,IAAI,WAAW,CAAC,CAAC;AACjD,WAAO,KAAK,iBAAiB,IACzB,GAAG,OAAO,IAAI,IAAI,OAAO,KAAK,cAAc,CAAC,KAC7C;AAAA,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,cAAc,UAA8B,SAAyB;AAC3E,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AACA,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AACA,WAAO,SAAS,UAAU,QAAQ,SAAS,WAAW;AAAA,EACxD;AAAA,EAEQ,qBAA8C;AACpD,WAAO;AAAA,MACL,sBACE,KAAK,gBAAgB;AAAA,MACvB,gBAAgB,KAAK,gBAAgB;AAAA;AAAA,IAAA;AAAA,EAEzC;AAAA,EAUQ,aAA8C;AAMpD,UAAM,WAAW,KAAK,YAAY,WAA6B,KAAK;AACpE,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AACA,QAAI,WAA4C;AAChD,QAAI,KAAK,YAAY,YAA8B;AACjD,iBAAW;AAAA,IACb,WAAW,KAAK,YAAY,UAA4B;AACtD,iBAAW;AAAA,IACb;AACA,WAAO;AAAA,sCAC2B,KAAK,gBAAgB;AAAA,QACnD,KAAK,kBAAkB,UAAU,QAAQ;AAAA;AAAA,EAE/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,MAAsC;AAC9D,WAAO;AAAA;AAAA,gBAEK,SAAS;AAAA,MACf,iBAAiB;AAAA,MACjB,CAAC,UAAU,IAAI,EAAE,GAAG;AAAA,MACpB,kBAAkB;AAAA,IAAA,CACnB,CAAC;AAAA;AAAA;AAAA,kDAGwC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpD;AAAA,EAES,SAAS;AAChB,UAAM,YAAY,KAAK;AACvB,UAAM,gBAAgB,KAAK;AAC3B,UAAM,iBAAiB,KAAK,SAAS;AACrC,UAAM,OAAO,KAAK,MACd,KAAK,UACL,mBAAmB,gBAAgB,aAAa;AAKpD,UAAM,YACJ,KAAK,OACL,CAAC,KAAK,eACN,mBAAmB,UACnB,iBAAiB,IACb,IACA,KAAK,IAAI,KAAK,YAAY,wBAAwB,IAAI,GAAG,CAAC;AAChE,UAAM,SAAS,YAAY,IAAI,IAAI,OAAO,SAAS,IAAI;AAKvD,UAAM,WAAW,KAAK,cAClB,KAAK,eACL,KAAK,cAAc,KAAK,eAAe,KAAK,YAAY;AAE5D,UAAM,QAAQ;AAAA;AAAA,gBAEF,SAAS;AAAA,MACf,OAAO;AAAA,MACP,CAAC,SAAS,KAAK,OAAO,EAAE,GAAG;AAAA,MAC3B,CAAC,QAAQ,KAAK,IAAI,EAAE,GAAG;AAAA,MACvB,iBAAiB,KAAK;AAAA,MACtB,UAAU,KAAK;AAAA,MACf,aAAa,KAAK,cAAc;AAAA,MAChC,aAAa,KAAK,cAAc;AAAA,MAChC,GAAG,KAAK,mBAAA;AAAA,IAAmB,CAC5B,CAAC;AAAA,4BACkB,KAAK,OAAO;AAAA;AAAA,UAE9B,KAAK,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,oBAKP,SAAS;AAAA,0BACH,KAAK,MAAM;AAAA,yBACZ,KAAK,SAAS;AAAA,2BACZ,IAAI;AAAA;AAAA,cAEjB,SACE;AAAA,qBACK,MAAM;AAAA,qBAEX,OAAO,GAAG,IAAI;AAAA,cAChB,WAAW,2BAA2B,QAAQ,YAAY,OAAO;AAAA;AAAA,YAEnE,KAAK,YAAY,KAAK,kBAAkB,SAAS,IAAI,OAAO;AAAA;AAAA;AAAA;AAIpE,WAAO,mBAAmB,KAAK,SAAS,OAAO,KAAK;AAAA,EACtD;AAGF;AAtPa,gBAqPK,SAAS,UAAU,cAAc;AAnPvB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAFb,gBAEe,WAAA,WAAA,CAAA;AAIA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GANb,gBAMe,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GATb,gBASe,WAAA,QAAA,CAAA;AAOA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAhBb,gBAgBe,WAAA,aAAA,CAAA;AAGC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAnBd,gBAmBgB,WAAA,YAAA,CAAA;AAGD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAtBb,gBAsBe,WAAA,UAAA,CAAA;AAIC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA1Bd,gBA0BgB,WAAA,aAAA,CAAA;AAGA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA7Bd,gBA6BgB,WAAA,WAAA,CAAA;AAGD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAhCb,gBAgCe,WAAA,kBAAA,CAAA;AAGA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAnCb,gBAmCe,WAAA,aAAA,CAAA;AAGC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAtCd,gBAsCgB,WAAA,eAAA,CAAA;AAGD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAzCb,gBAyCe,WAAA,iBAAA,CAAA;AAGC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA5Cd,gBA4CgB,WAAA,OAAA,CAAA;AAGD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA/Cb,gBA+Ce,WAAA,WAAA,CAAA;AAGA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAlDb,gBAkDe,WAAA,aAAA,CAAA;AAIA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAtDb,gBAsDe,WAAA,eAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Db,gBA4De,WAAA,SAAA,CAAA;AAGC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA/Dd,gBA+DgB,WAAA,YAAA,CAAA;AAGD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAlEb,gBAkEe,WAAA,aAAA,CAAA;AAGT,gBAAA;AAAA,EAAhB,MAAA;AAAM,GArEI,gBAqEM,WAAA,mBAAA,CAAA;AArEN,kBAAN,gBAAA;AAAA,EADN,cAAc,mBAAmB;AAAA,GACrB,eAAA;"}
@@ -0,0 +1,24 @@
1
+ import { css } from "lit";
2
+ const componentStyle = css`* {
3
+ -webkit-tap-highlight-color: transparent;
4
+ }
5
+
6
+ :host {
7
+ display: block;
8
+ width: 100%;
9
+ }
10
+
11
+ /* Vertical stack of rows. The 4px row gap matches the rich detail rows in
12
+ \`obc-automation-tank\`; override via \`--obc-readout-list-row-gap\`. */
13
+
14
+ .list {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: var(--obc-readout-list-row-gap, 4px);
18
+ width: 100%;
19
+ }
20
+ `;
21
+ export {
22
+ componentStyle as default
23
+ };
24
+ //# sourceMappingURL=readout-list.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readout-list.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,70 @@
1
+ import { LitElement, PropertyValues } from 'lit';
2
+ import '../readout-list-item/readout-list-item.js';
3
+ /**
4
+ * `<obc-readout-list>` – A container that groups `<obc-readout-list-item>` rows
5
+ * and **auto-aligns their columns**.
6
+ *
7
+ * Because each row is its own custom element, cross-row column alignment is not
8
+ * automatic. This container inspects its rows and pushes shared width reservers
9
+ * down so the unit column, the value / setpoint / advice columns and the source
10
+ * column all line up — the same effect the `Readout List Item → ColumnAlignment`
11
+ * story achieves by hand, done for you. Alignment is always on.
12
+ *
13
+ * What it equalizes — derived from each row's data and broadcast to every row, so
14
+ * the widest value / unit / source is never clipped:
15
+ * - **Unit:** the longest `unit` becomes every row's unit space-reserver.
16
+ * - **Value / setpoint / advice:** the widest numeric width (max integer digits +
17
+ * max fraction digits across rows, derived from each row's `maxDigits` /
18
+ * `fractionDigits` / current values) is reserved on every row's numeric blocks.
19
+ * Reserving off digit counts keeps it stable as live values update.
20
+ * - **Source:** the longest `src` becomes every row's source space-reserver.
21
+ * - **Degree:** if any row has a degree, non-degree rows reserve the degree column
22
+ * (`hasDegreeSpacer`) so their digits line up with the degree rows; the spacer is
23
+ * cleared once no degree rows remain.
24
+ *
25
+ * The list **owns** these reservers: it recomputes them from the rows' data on
26
+ * every pass (and clears stale reservers / spacers when rows change), so a
27
+ * `spaceReserver` set directly on a row inside the list is overwritten. Drive the
28
+ * data (`maxDigits` / `fractionDigits` / `unit` / `src`) rather than setting a
29
+ * manual reserver when a row lives in a list.
30
+ *
31
+ * Alignment runs on `slotchange` and on child mutations (added/removed rows and
32
+ * HTML-attribute changes). When rows are updated via JS **properties** only (no
33
+ * attribute/DOM mutation), call {@link align} to recompute.
34
+ *
35
+ * @experimental Pilot for the new primitives + per-block options Readout API; the
36
+ * API may change in a future release.
37
+ *
38
+ * @slot - The `<obc-readout-list-item>` rows.
39
+ *
40
+ * @csspart list - The vertical stack container.
41
+ */
42
+ export declare class ObcReadoutList extends LitElement {
43
+ /**
44
+ * Development aid: outline each row's readout building blocks (red), degree
45
+ * columns (blue) and degree spacer (green) so the reserved column widths are
46
+ * visible. Propagated to every row. Off by default.
47
+ */
48
+ showDebugOverlay: boolean;
49
+ private mutationObserver?;
50
+ protected updated(changed: PropertyValues): void;
51
+ disconnectedCallback(): void;
52
+ /** The `obc-readout-list-item` rows, including those nested in wrapper elements. */
53
+ private get items();
54
+ /**
55
+ * Recompute and apply the shared column reservers across all rows. Call this
56
+ * after updating rows via JS properties only (attribute/DOM changes are picked
57
+ * up automatically).
58
+ */
59
+ align(): void;
60
+ private observeChildren;
61
+ private handleSlotChange;
62
+ render(): import('lit-html').TemplateResult<1>;
63
+ static styles: import('lit').CSSResult;
64
+ }
65
+ declare global {
66
+ interface HTMLElementTagNameMap {
67
+ 'obc-readout-list': ObcReadoutList;
68
+ }
69
+ }
70
+ //# sourceMappingURL=readout-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readout-list.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/readout-list/readout-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAmB,KAAK,cAAc,EAAC,MAAM,KAAK,CAAC;AAIrE,OAAO,2CAA2C,CAAC;AA2BnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBACa,cAAe,SAAQ,UAAU;IAC5C;;;;OAIG;IACuC,gBAAgB,UAAS;IAEnE,OAAO,CAAC,gBAAgB,CAAC,CAAmB;cAEzB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAShD,oBAAoB,IAAI,IAAI;IAMrC,oFAAoF;IACpF,OAAO,KAAK,KAAK,GAQhB;IAED;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAuEb,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,gBAAgB,CAGtB;IAEO,MAAM;IAQf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF"}
@@ -0,0 +1,154 @@
1
+ import { unsafeCSS, LitElement, html } from "lit";
2
+ import { property } from "lit/decorators.js";
3
+ import componentStyle from "./readout-list.css.js";
4
+ import { customElement } from "../../decorator.js";
5
+ import "../readout-list-item/readout-list-item.js";
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __decorateClass = (decorators, target, key, kind) => {
9
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
10
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
11
+ if (decorator = decorators[i])
12
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
13
+ if (kind && result) __defProp(target, key, result);
14
+ return result;
15
+ };
16
+ const ITEM_TAG = "obc-readout-list-item";
17
+ const OBSERVED_ATTRIBUTES = [
18
+ "unit",
19
+ "src",
20
+ "value",
21
+ "setpoint",
22
+ "advice",
23
+ "max-digits",
24
+ "fraction-digits",
25
+ "has-degree",
26
+ "has-setpoint",
27
+ "has-advice"
28
+ ];
29
+ function integerDigitCount(value) {
30
+ if (value === null || value === void 0 || Number.isNaN(value)) {
31
+ return 0;
32
+ }
33
+ return String(Math.trunc(Math.abs(value))).length;
34
+ }
35
+ let ObcReadoutList = class extends LitElement {
36
+ constructor() {
37
+ super(...arguments);
38
+ this.showDebugOverlay = false;
39
+ this.handleSlotChange = () => {
40
+ this.align();
41
+ this.observeChildren();
42
+ };
43
+ }
44
+ updated(changed) {
45
+ super.updated(changed);
46
+ if (changed.has("showDebugOverlay")) {
47
+ this.align();
48
+ }
49
+ }
50
+ disconnectedCallback() {
51
+ this.mutationObserver?.disconnect();
52
+ this.mutationObserver = void 0;
53
+ super.disconnectedCallback();
54
+ }
55
+ /** The `obc-readout-list-item` rows, including those nested in wrapper elements. */
56
+ get items() {
57
+ const slot = this.shadowRoot?.querySelector("slot");
58
+ const assigned = slot?.assignedElements({ flatten: true }) ?? [];
59
+ return assigned.flatMap(
60
+ (el) => el.tagName.toLowerCase() === ITEM_TAG ? [el] : Array.from(el.querySelectorAll(ITEM_TAG))
61
+ );
62
+ }
63
+ /**
64
+ * Recompute and apply the shared column reservers across all rows. Call this
65
+ * after updating rows via JS properties only (attribute/DOM changes are picked
66
+ * up automatically).
67
+ */
68
+ align() {
69
+ const items = this.items;
70
+ if (items.length === 0) {
71
+ return;
72
+ }
73
+ let maxIntegerDigits = 0;
74
+ let maxFractionDigits = 0;
75
+ let longestUnit = "";
76
+ let longestSrc = "";
77
+ let anyDegree = false;
78
+ for (const item of items) {
79
+ maxFractionDigits = Math.max(maxFractionDigits, item.fractionDigits ?? 0);
80
+ maxIntegerDigits = Math.max(
81
+ maxIntegerDigits,
82
+ item.maxDigits ?? 0,
83
+ integerDigitCount(item.value),
84
+ item.hasSetpoint ? integerDigitCount(item.setpoint) : 0,
85
+ item.hasAdvice ? integerDigitCount(item.advice) : 0
86
+ );
87
+ if (item.unit && item.unit.length > longestUnit.length) {
88
+ longestUnit = item.unit;
89
+ }
90
+ if (item.src && item.src.length > longestSrc.length) {
91
+ longestSrc = item.src;
92
+ }
93
+ if (item.hasDegree) {
94
+ anyDegree = true;
95
+ }
96
+ }
97
+ const numericReserver = maxIntegerDigits > 0 ? "0".repeat(maxIntegerDigits) + (maxFractionDigits > 0 ? `.${"0".repeat(maxFractionDigits)}` : "") : void 0;
98
+ this.mutationObserver?.disconnect();
99
+ for (const item of items) {
100
+ item.valueOptions = {
101
+ ...item.valueOptions,
102
+ spaceReserver: numericReserver
103
+ };
104
+ item.setpointOptions = {
105
+ ...item.setpointOptions,
106
+ spaceReserver: numericReserver
107
+ };
108
+ item.adviceOptions = {
109
+ ...item.adviceOptions,
110
+ spaceReserver: numericReserver
111
+ };
112
+ item.unitOptions = {
113
+ ...item.unitOptions,
114
+ spaceReserver: longestUnit || void 0
115
+ };
116
+ item.srcOptions = {
117
+ ...item.srcOptions,
118
+ spaceReserver: longestSrc || void 0
119
+ };
120
+ item.hasDegreeSpacer = anyDegree && !item.hasDegree;
121
+ item.showDebugOverlay = this.showDebugOverlay;
122
+ }
123
+ this.observeChildren();
124
+ }
125
+ observeChildren() {
126
+ if (!this.mutationObserver) {
127
+ this.mutationObserver = new MutationObserver(() => this.align());
128
+ }
129
+ this.mutationObserver.observe(this, {
130
+ childList: true,
131
+ subtree: true,
132
+ attributes: true,
133
+ attributeFilter: OBSERVED_ATTRIBUTES
134
+ });
135
+ }
136
+ render() {
137
+ return html`
138
+ <div class="list" part="list">
139
+ <slot @slotchange=${this.handleSlotChange}></slot>
140
+ </div>
141
+ `;
142
+ }
143
+ };
144
+ ObcReadoutList.styles = unsafeCSS(componentStyle);
145
+ __decorateClass([
146
+ property({ type: Boolean, reflect: true })
147
+ ], ObcReadoutList.prototype, "showDebugOverlay", 2);
148
+ ObcReadoutList = __decorateClass([
149
+ customElement("obc-readout-list")
150
+ ], ObcReadoutList);
151
+ export {
152
+ ObcReadoutList
153
+ };
154
+ //# sourceMappingURL=readout-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readout-list.js","sources":["../../../src/navigation-instruments/readout-list/readout-list.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS, type PropertyValues} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport componentStyle from './readout-list.css?inline';\nimport {customElement} from '../../decorator.js';\nimport '../readout-list-item/readout-list-item.js';\nimport {ObcReadoutListItem} from '../readout-list-item/readout-list-item.js';\n\nconst ITEM_TAG = 'obc-readout-list-item';\n\n/** Child attributes whose change should re-trigger alignment (HTML-attribute usage). */\nconst OBSERVED_ATTRIBUTES = [\n 'unit',\n 'src',\n 'value',\n 'setpoint',\n 'advice',\n 'max-digits',\n 'fraction-digits',\n 'has-degree',\n 'has-setpoint',\n 'has-advice',\n];\n\n/** Integer-digit count of a numeric value (sign and fraction excluded). */\nfunction integerDigitCount(value: number | null | undefined): number {\n if (value === null || value === undefined || Number.isNaN(value)) {\n return 0;\n }\n return String(Math.trunc(Math.abs(value))).length;\n}\n\n/**\n * `<obc-readout-list>` – A container that groups `<obc-readout-list-item>` rows\n * and **auto-aligns their columns**.\n *\n * Because each row is its own custom element, cross-row column alignment is not\n * automatic. This container inspects its rows and pushes shared width reservers\n * down so the unit column, the value / setpoint / advice columns and the source\n * column all line up — the same effect the `Readout List Item → ColumnAlignment`\n * story achieves by hand, done for you. Alignment is always on.\n *\n * What it equalizes — derived from each row's data and broadcast to every row, so\n * the widest value / unit / source is never clipped:\n * - **Unit:** the longest `unit` becomes every row's unit space-reserver.\n * - **Value / setpoint / advice:** the widest numeric width (max integer digits +\n * max fraction digits across rows, derived from each row's `maxDigits` /\n * `fractionDigits` / current values) is reserved on every row's numeric blocks.\n * Reserving off digit counts keeps it stable as live values update.\n * - **Source:** the longest `src` becomes every row's source space-reserver.\n * - **Degree:** if any row has a degree, non-degree rows reserve the degree column\n * (`hasDegreeSpacer`) so their digits line up with the degree rows; the spacer is\n * cleared once no degree rows remain.\n *\n * The list **owns** these reservers: it recomputes them from the rows' data on\n * every pass (and clears stale reservers / spacers when rows change), so a\n * `spaceReserver` set directly on a row inside the list is overwritten. Drive the\n * data (`maxDigits` / `fractionDigits` / `unit` / `src`) rather than setting a\n * manual reserver when a row lives in a list.\n *\n * Alignment runs on `slotchange` and on child mutations (added/removed rows and\n * HTML-attribute changes). When rows are updated via JS **properties** only (no\n * attribute/DOM mutation), call {@link align} to recompute.\n *\n * @experimental Pilot for the new primitives + per-block options Readout API; the\n * API may change in a future release.\n *\n * @slot - The `<obc-readout-list-item>` rows.\n *\n * @csspart list - The vertical stack container.\n */\n@customElement('obc-readout-list')\nexport class ObcReadoutList extends LitElement {\n /**\n * Development aid: outline each row's readout building blocks (red), degree\n * columns (blue) and degree spacer (green) so the reserved column widths are\n * visible. Propagated to every row. Off by default.\n */\n @property({type: Boolean, reflect: true}) showDebugOverlay = false;\n\n private mutationObserver?: MutationObserver;\n\n protected override updated(changed: PropertyValues): void {\n super.updated(changed);\n // A host-property change is not seen by the child MutationObserver, so\n // re-propagate `showDebugOverlay` (and re-align) when it toggles.\n if (changed.has('showDebugOverlay')) {\n this.align();\n }\n }\n\n override disconnectedCallback(): void {\n this.mutationObserver?.disconnect();\n this.mutationObserver = undefined;\n super.disconnectedCallback();\n }\n\n /** The `obc-readout-list-item` rows, including those nested in wrapper elements. */\n private get items(): ObcReadoutListItem[] {\n const slot = this.shadowRoot?.querySelector('slot');\n const assigned = slot?.assignedElements({flatten: true}) ?? [];\n return assigned.flatMap((el) =>\n el.tagName.toLowerCase() === ITEM_TAG\n ? [el as ObcReadoutListItem]\n : Array.from(el.querySelectorAll<ObcReadoutListItem>(ITEM_TAG))\n );\n }\n\n /**\n * Recompute and apply the shared column reservers across all rows. Call this\n * after updating rows via JS properties only (attribute/DOM changes are picked\n * up automatically).\n */\n align(): void {\n const items = this.items;\n if (items.length === 0) {\n return;\n }\n\n let maxIntegerDigits = 0;\n let maxFractionDigits = 0;\n let longestUnit = '';\n let longestSrc = '';\n let anyDegree = false;\n\n for (const item of items) {\n maxFractionDigits = Math.max(maxFractionDigits, item.fractionDigits ?? 0);\n maxIntegerDigits = Math.max(\n maxIntegerDigits,\n item.maxDigits ?? 0,\n integerDigitCount(item.value),\n item.hasSetpoint ? integerDigitCount(item.setpoint) : 0,\n item.hasAdvice ? integerDigitCount(item.advice) : 0\n );\n if (item.unit && item.unit.length > longestUnit.length) {\n longestUnit = item.unit;\n }\n if (item.src && item.src.length > longestSrc.length) {\n longestSrc = item.src;\n }\n if (item.hasDegree) {\n anyDegree = true;\n }\n }\n\n const numericReserver =\n maxIntegerDigits > 0\n ? '0'.repeat(maxIntegerDigits) +\n (maxFractionDigits > 0 ? `.${'0'.repeat(maxFractionDigits)}` : '')\n : undefined;\n\n // Our writes are properties (no reflected attributes), so they do not trigger\n // the MutationObserver; disconnecting around them is belt-and-suspenders.\n this.mutationObserver?.disconnect();\n for (const item of items) {\n // Recompute every reserver / spacer on every pass (do not gate on a value\n // being present), so stale state clears when rows change — e.g. when the\n // last degree row, the last unit, or the last source is removed.\n item.valueOptions = {\n ...item.valueOptions,\n spaceReserver: numericReserver,\n };\n item.setpointOptions = {\n ...item.setpointOptions,\n spaceReserver: numericReserver,\n };\n item.adviceOptions = {\n ...item.adviceOptions,\n spaceReserver: numericReserver,\n };\n item.unitOptions = {\n ...item.unitOptions,\n spaceReserver: longestUnit || undefined,\n };\n item.srcOptions = {\n ...item.srcOptions,\n spaceReserver: longestSrc || undefined,\n };\n item.hasDegreeSpacer = anyDegree && !item.hasDegree;\n item.showDebugOverlay = this.showDebugOverlay;\n }\n this.observeChildren();\n }\n\n private observeChildren(): void {\n if (!this.mutationObserver) {\n this.mutationObserver = new MutationObserver(() => this.align());\n }\n this.mutationObserver.observe(this, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n });\n }\n\n private handleSlotChange = (): void => {\n this.align();\n this.observeChildren();\n };\n\n override render() {\n return html`\n <div class=\"list\" part=\"list\">\n <slot @slotchange=${this.handleSlotChange}></slot>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-readout-list': ObcReadoutList;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -12,6 +12,57 @@ const componentStyle = css`* {
12
12
  width: 100%;
13
13
  }
14
14
 
15
+ /* Bridge the list-item's public colour custom properties onto the block's, so
16
+ consumers keep theming the value / setpoint / advice / hinted-zero colours via
17
+ \`--obc-readout-list-item-*\` even though they now render inside obc-readout-block. */
18
+
19
+ obc-readout-block {
20
+ --obc-readout-block-value-color: var(
21
+ --obc-readout-list-item-value-color,
22
+ var(--element-neutral-color)
23
+ );
24
+ --obc-readout-block-value-enhanced-color: var(
25
+ --obc-readout-list-item-value-enhanced-color,
26
+ var(--element-neutral-enhanced-color)
27
+ );
28
+ --obc-readout-block-setpoint-color: var(
29
+ --obc-readout-list-item-setpoint-color,
30
+ var(--element-neutral-color)
31
+ );
32
+ --obc-readout-block-setpoint-enhanced-color: var(
33
+ --obc-readout-list-item-setpoint-enhanced-color,
34
+ var(--instrument-enhanced-secondary-color)
35
+ );
36
+ --obc-readout-block-setpoint-touching-outline-color: var(
37
+ --obc-readout-list-item-setpoint-touching-outline-color,
38
+ var(--element-neutral-enhanced-color)
39
+ );
40
+ --obc-readout-block-setpoint-touching-color: var(
41
+ --obc-readout-list-item-setpoint-touching-color,
42
+ var(--base-blue-100)
43
+ );
44
+ --obc-readout-block-advice-color: var(
45
+ --obc-readout-list-item-advice-color,
46
+ var(--element-neutral-color)
47
+ );
48
+ --obc-readout-block-hinted-color: var(
49
+ --obc-readout-list-item-hinted-color,
50
+ var(--element-inactive-color)
51
+ );
52
+ }
53
+
54
+ /* Size the consumer-provided block icons forwarded into obc-readout-block's
55
+ \`icon\` slot (the block sizes the forwarded slot element; this sizes the
56
+ consumer's icon to fill it). */
57
+
58
+ ::slotted([slot="value-icon"]),
59
+ ::slotted([slot="setpoint-icon"]),
60
+ ::slotted([slot="advice-icon"]) {
61
+ display: block;
62
+ inline-size: 100%;
63
+ block-size: 100%;
64
+ }
65
+
15
66
  /* ---------- Root / surface ----------
16
67
  * \`.root\` is the touch target (a <button> when clickable, otherwise a <div>).
17
68
  * \`.surface\` is the visible box that carries padding, corner radius, the
@@ -222,129 +273,10 @@ const componentStyle = css`* {
222
273
  align-items: flex-end;
223
274
  }
224
275
 
225
- /* ---------- Readout building block (advice / setpoint / value) ---------- */
226
-
227
- .block {
228
- display: inline-flex;
229
- align-items: flex-end;
230
- }
231
-
232
- /* Number + its (setpoint/advice) degree glyph, hugging with no gap — the
233
- \`.block\` gap only separates the icon from this group. */
234
-
235
- .block-content {
236
- display: inline-flex;
237
- align-items: flex-end;
238
- }
239
-
240
- .block-icon {
241
- display: inline-flex;
242
- align-items: center;
243
- justify-content: center;
244
- flex: none;
245
- color: inherit;
246
- /* Centre the icon against the block's text rather than bottom-aligning it (the
247
- block is flex-end). Matters for the value block, whose text is taller than
248
- the icon, so the value icon lines up with the number like the smaller
249
- setpoint/advice icons do. */
250
- align-self: center;
251
- }
252
-
253
- .block-icon obi-input-right,
254
- .block-icon obi-notification-advice,
255
- .block-icon ::slotted(*) {
256
- display: block;
257
- inline-size: 100%;
258
- block-size: 100%;
259
- }
260
-
261
- .hinted-zero {
262
- color: var(
263
- --obc-readout-list-item-hinted-color,
264
- var(--element-inactive-color)
265
- );
266
- }
267
-
268
- /* ---------- Text colours (overridable via custom properties) ----------
269
- * obc-textbox does not set its own colour, so it inherits these. */
270
-
271
- .block-value {
272
- color: var(--obc-readout-list-item-value-color, var(--element-neutral-color));
273
- }
274
-
275
- .block-value.tone-enhanced {
276
- color: var(
277
- --obc-readout-list-item-value-enhanced-color,
278
- var(--element-neutral-enhanced-color)
279
- );
280
- }
281
-
282
- /* The setpoint shares the value's colour state: neutral by default, enhanced
283
- (blue) only when the row is enhanced — never a blue setpoint next to a grey
284
- value. \`--instrument-enhanced-secondary-color\` is the same #2d548b as the
285
- value's \`--element-neutral-enhanced-color\`. */
286
-
287
- .block-setpoint {
288
- color: var(
289
- --obc-readout-list-item-setpoint-color,
290
- var(--element-neutral-color)
291
- );
292
- /* Flip-flop emphasis + pop-up fade animate at 100ms. */
293
- transition:
294
- opacity 100ms ease,
295
- color 100ms ease;
296
- }
297
-
298
- .block-setpoint.tone-enhanced {
299
- color: var(
300
- --obc-readout-list-item-setpoint-enhanced-color,
301
- var(--instrument-enhanced-secondary-color)
302
- );
303
- }
304
-
305
- /* Pop-up: fade the setpoint out once value === setpoint, keeping its space so
306
- the value stays column-aligned. */
307
-
308
- .block-setpoint.is-hiding {
309
- opacity: 0;
310
- }
311
-
312
- .block-setpoint.is-hidden {
313
- opacity: 0;
314
- visibility: hidden;
315
- }
316
-
317
- /* Touching / focus state: the setpoint triangle takes the marker's focus look — a
318
- pale fill (--base-blue-100) with a dark 1px edge (--element-neutral-enhanced),
319
- mirroring \`svghelpers/setpoint.ts\` focus (fill base-blue-100 + 2px stroke).
320
- The glyph icon is \`fill: currentColor\` and can't take a CSS \`stroke\`, so the
321
- edge is layered drop-shadows. The setpoint number keeps its normal, readable
322
- colour. */
323
-
324
- .block-setpoint.touching {
325
- --_touching-outline: var(
326
- --obc-readout-list-item-setpoint-touching-outline-color,
327
- var(--element-neutral-enhanced-color)
328
- );
329
- }
330
-
331
- .block-setpoint.touching .block-icon {
332
- color: var(
333
- --obc-readout-list-item-setpoint-touching-color,
334
- var(--base-blue-100)
335
- );
336
- filter: drop-shadow(1px 0 0 var(--_touching-outline))
337
- drop-shadow(-1px 0 0 var(--_touching-outline))
338
- drop-shadow(0 1px 0 var(--_touching-outline))
339
- drop-shadow(0 -1px 0 var(--_touching-outline));
340
- }
341
-
342
- .block-advice {
343
- color: var(
344
- --obc-readout-list-item-advice-color,
345
- var(--element-neutral-color)
346
- );
347
- }
276
+ /* The readout building blocks (advice / setpoint / value) now render inside
277
+ \`obc-readout-block\`; their layout / colour / hinted-zero / data-quality CSS
278
+ lives there. The list-item only bridges the public colour vars (see top) and
279
+ keeps the surrounding row layout below. */
348
280
 
349
281
  .label {
350
282
  color: var(
@@ -364,26 +296,22 @@ const componentStyle = css`* {
364
296
  );
365
297
  }
366
298
 
367
- /* ---------- Per-block data quality ----------
299
+ /* ---------- Source data quality ----------
368
300
  * Independent of (and nests inside) the row-level data-quality frame. Uses
369
- * \`outline\` (not \`border\`) so the chip never shifts the block's width — the
370
- * value stays column-aligned across rows. */
301
+ * \`outline\` (not \`border\`) so the chip never shifts the source's width. (The
302
+ * per-block value/setpoint/advice chips live in \`obc-readout-block\`.) */
371
303
 
372
- .block.data-low-integrity,
373
- .block.data-invalid,
374
304
  .source.data-low-integrity,
375
305
  .source.data-invalid {
376
306
  outline: 1px solid;
377
307
  border-radius: var(--global-border-radius-border-radius-check);
378
308
  }
379
309
 
380
- .block.data-low-integrity,
381
310
  .source.data-low-integrity {
382
311
  background: var(--alert-low-integrity-background-color);
383
312
  outline-color: var(--alert-low-integrity-border-color);
384
313
  }
385
314
 
386
- .block.data-invalid,
387
315
  .source.data-invalid {
388
316
  background: var(--alert-invalid-background-color);
389
317
  outline-color: var(--alert-invalid-border-color);
@@ -525,11 +453,6 @@ const componentStyle = css`* {
525
453
  );
526
454
  }
527
455
 
528
- .size-small .block {
529
- gap: var(--instrument-components-readout-new-general-regular-icon-gap);
530
- }
531
-
532
- .size-small .block-icon,
533
456
  .size-small .leading-icon {
534
457
  inline-size: var(
535
458
  --instrument-components-readout-new-general-regular-icon-size
@@ -566,11 +489,6 @@ const componentStyle = css`* {
566
489
  );
567
490
  }
568
491
 
569
- .size-medium .block {
570
- gap: var(--instrument-components-readout-new-general-medium-icon-gap);
571
- }
572
-
573
- .size-medium .block-icon,
574
492
  .size-medium .leading-icon {
575
493
  inline-size: var(
576
494
  --instrument-components-readout-new-general-medium-icon-size
@@ -602,11 +520,6 @@ const componentStyle = css`* {
602
520
  gap: var(--instrument-components-readout-new-list-item-large-value-gap);
603
521
  }
604
522
 
605
- .size-large .block {
606
- gap: var(--instrument-components-readout-new-general-large-icon-gap);
607
- }
608
-
609
- .size-large .block-icon,
610
523
  .size-large .leading-icon {
611
524
  inline-size: var(--instrument-components-readout-new-general-large-icon-size);
612
525
  block-size: var(--instrument-components-readout-new-general-large-icon-size);
@@ -651,6 +564,28 @@ const componentStyle = css`* {
651
564
  );
652
565
  --_obc-readout-list-item-data-border: var(--alert-invalid-border-color);
653
566
  }
567
+
568
+ /* ---------- Debug overlay ----------
569
+ * \`showDebugOverlay\` outlines each readout building block (red), the degree
570
+ * columns (blue) and the degree spacer (green) so reserver widths / alignment
571
+ * are visible. A development aid (mirrors the donut chart's \`showDebugOverlay\`);
572
+ * off by default. */
573
+
574
+ :host([showDebugOverlay]) obc-readout-block::part(block) {
575
+ outline: 1px solid rgba(220, 0, 0, 0.7);
576
+ outline-offset: -1px;
577
+ }
578
+
579
+ :host([showDebugOverlay]) obc-readout-block::part(degree),
580
+ :host([showDebugOverlay]) .degree-column {
581
+ outline: 1px solid rgba(0, 0, 220, 0.7);
582
+ outline-offset: -1px;
583
+ }
584
+
585
+ :host([showDebugOverlay]) .degree-spacer {
586
+ outline: 1px solid rgba(0, 160, 0, 0.8);
587
+ outline-offset: -1px;
588
+ }
654
589
  `;
655
590
  export {
656
591
  componentStyle as default
@@ -1 +1 @@
1
- {"version":3,"file":"readout-list-item.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"readout-list-item.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}