@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.83 → 2.0.0-next.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/openbridge-webcomponents.bundle.js +1223 -493
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +642 -196
- package/dist/components/tab-item/tab-item.css.js +8 -1
- package/dist/components/tab-item/tab-item.css.js.map +1 -1
- package/dist/components/tab-item/tab-item.d.ts +44 -0
- package/dist/components/tab-item/tab-item.d.ts.map +1 -1
- package/dist/components/tab-item/tab-item.js +44 -25
- package/dist/components/tab-item/tab-item.js.map +1 -1
- package/dist/components/tab-row/tab-row.d.ts +23 -9
- package/dist/components/tab-row/tab-row.d.ts.map +1 -1
- package/dist/components/tab-row/tab-row.js +24 -7
- package/dist/components/tab-row/tab-row.js.map +1 -1
- package/dist/components/textbox/textbox.css.js +29 -5
- package/dist/components/textbox/textbox.css.js.map +1 -1
- package/dist/components/textbox/textbox.d.ts +5 -0
- package/dist/components/textbox/textbox.d.ts.map +1 -1
- package/dist/components/textbox/textbox.js +6 -1
- package/dist/components/textbox/textbox.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +611 -230
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +280 -61
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js +529 -247
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
- package/package.json +1 -1
- package/src/components/tab-item/tab-item.css +8 -1
- package/src/components/tab-item/tab-item.stories.ts +30 -0
- package/src/components/tab-item/tab-item.ts +89 -31
- package/src/components/tab-row/tab-row.stories.ts +20 -10
- package/src/components/tab-row/tab-row.ts +54 -19
- package/src/components/textbox/textbox.css +27 -5
- package/src/components/textbox/textbox.ts +6 -0
- package/src/navigation-instruments/readout-list-item/readout-list-item.css +505 -238
- package/src/navigation-instruments/readout-list-item/readout-list-item.stories.ts +1604 -356
- package/src/navigation-instruments/readout-list-item/readout-list-item.ts +792 -295
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readout-list-item.js","sources":["../../../src/navigation-instruments/readout-list-item/readout-list-item.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport componentStyle from './readout-list-item.css?inline';\nimport {customElement} from '../../decorator.js';\nimport {ReadoutSetpointSize} from '../readout-setpoint/readout-setpoint.js';\nimport {ReadoutSetpointValueTypography} from '../readout-setpoint/readout-setpoint.js';\nimport {Priority} from '../types.js';\nimport '../readout-setpoint/readout-setpoint.js';\nimport '../../icons/icon-input-right.js';\nimport {ReadoutSetpointMode} from '../readout-setpoint/readout-setpoint.js';\nimport {\n type AlertFrameConfig,\n wrapWithAlertFrame,\n} from '../../components/alert-frame/alert-frame.js';\n\nexport enum ReadoutListItemDataState {\n none = 'none',\n lowIntegrity = 'low-integrity',\n invalid = 'invalid',\n}\n\nexport enum ReadoutListItemSize {\n base = 'base',\n priority = 'priority',\n enhanced = 'enhanced',\n}\n\nexport enum ReadoutListItemStacking {\n trailingUnit = 'trailing-unit',\n leadingUnit = 'leading-unit',\n leadingSrc = 'leading-src',\n}\n\nexport enum ReadoutListItemPriority {\n regular = 'regular',\n enhanced = 'enhanced',\n setpoint = 'setpoint',\n setpointFlipFlop = 'setpoint-flip-flop',\n}\n\n/**\n * `<obc-readout-list-item>` – A compact inline readout row for lists.\n *\n * Renders a compact label/value/unit composition with a dedicated size scale and stacking modes for unit and source placement. Use it when you need dense, consistent readout rows in tables or lists without bringing in the full `<obc-readout>` segment layout.\n *\n * ### Features\n * - **Sizes:** `base`, `priority`, and `enhanced` typography/padding scales.\n * - **Stacking modes:** `trailing-unit`, `leading-unit`, and `leading-src` control where unit/source appear relative to the label/value.\n * - **Priority styling:** `priority` controls emphasis and setpoint presentation (`regular`, `enhanced`, `setpoint`, `setpoint-flip-flop`).\n * - **Data states:** Supports `dataState` styling for `low-integrity` and `invalid` data quality.\n * - **Alert frame:** Optional `alert` wrapper for caution, warning, alarm, and other alert-frame statuses.\n * - **Formatting:** Supports numeric formatting, fixed-length width templates, hinted zeros, and optional degree suffix (`°`).\n *\n * ### Usage Guidelines\n * Use this component for dense readouts in list contexts. Prefer `<obc-readout>` when you need multi-segment advice/setpoint/source composition, rich layouts, or source picker/flyout behavior.\n *\n * ### Slots\n * | Slot Name | Renders When | Purpose |\n * |---------------|--------------------------|---------|\n * | leading-icon | `hasLeadingIcon` is true | Optional leading icon before the label. |\n * | value-icon | `hasValueIcon` is true | Optional icon next to the value. |\n *\n * @slot leading-icon - Optional leading icon before the label.\n * @slot value-icon - Optional icon next to the value.\n */\n@customElement('obc-readout-list-item')\nexport class ObcReadoutListItem extends LitElement {\n @property({type: String}) size: ReadoutListItemSize =\n ReadoutListItemSize.base;\n @property({type: String})\n stacking: ReadoutListItemStacking = ReadoutListItemStacking.trailingUnit;\n @property({type: String})\n priority: ReadoutListItemPriority = ReadoutListItemPriority.regular;\n @property({type: String})\n dataState: ReadoutListItemDataState = ReadoutListItemDataState.none;\n\n @property({type: Object}) alert: AlertFrameConfig | boolean = false;\n\n @property({type: String}) label = '';\n @property({type: String}) unit = '';\n @property({type: String}) src = '';\n\n @property({type: Number}) value: number | undefined = undefined;\n @property({type: Number}) setpointValue: number | undefined = undefined;\n\n @property({type: Boolean}) hasSetpoint = false;\n\n @property({type: Boolean}) hasDegree = false;\n @property({type: Boolean}) hasUnit = false;\n @property({type: Boolean}) hasLabel = false;\n @property({type: Boolean}) hasSource = false;\n @property({type: Boolean}) hasLeadingIcon = false;\n @property({type: Boolean}) hasValueIcon = false;\n\n @property({type: Number}) fractionDigits = 0;\n @property({type: Boolean}) showZeroPadding = false;\n\n @property({type: Number}) minValueLength = 0;\n @property({type: Boolean}) hasHintedZeros = false;\n\n @property({type: Boolean}) labelOnly = false;\n\n private get resolvedMainValueSize(): ReadoutSetpointSize {\n return this.size === ReadoutListItemSize.enhanced\n ? ReadoutSetpointSize.large\n : this.size === ReadoutListItemSize.priority\n ? ReadoutSetpointSize.medium\n : ReadoutSetpointSize.regular;\n }\n\n private get resolvedValueSize(): ReadoutSetpointSize {\n if (this.priority === ReadoutListItemPriority.setpointFlipFlop) {\n if (this.size === ReadoutListItemSize.priority) {\n return ReadoutSetpointSize.small;\n }\n\n if (this.size === ReadoutListItemSize.enhanced) {\n return ReadoutSetpointSize.regular;\n }\n }\n\n if (this.size === ReadoutListItemSize.enhanced) {\n return ReadoutSetpointSize.large;\n }\n return ReadoutSetpointSize.regular;\n }\n\n private get resolvedValueTypography():\n | ReadoutSetpointValueTypography\n | undefined {\n if (\n this.priority === ReadoutListItemPriority.setpointFlipFlop &&\n this.resolvedValueSize === ReadoutSetpointSize.small\n ) {\n return undefined;\n }\n\n if (\n this.priority === ReadoutListItemPriority.setpointFlipFlop &&\n this.size === ReadoutListItemSize.enhanced\n ) {\n return ReadoutSetpointValueTypography.regular;\n }\n\n switch (this.size) {\n case ReadoutListItemSize.enhanced:\n return ReadoutSetpointValueTypography.large;\n case ReadoutListItemSize.priority:\n return ReadoutSetpointValueTypography.medium;\n case ReadoutListItemSize.base:\n default:\n return ReadoutSetpointValueTypography.regular;\n }\n }\n\n private get resolvedSetpointSize(): ReadoutSetpointSize {\n if (!this.hasSetpoint) {\n return ReadoutSetpointSize.small;\n }\n\n if (\n this.priority === ReadoutListItemPriority.setpoint ||\n this.priority === ReadoutListItemPriority.setpointFlipFlop\n ) {\n return this.resolvedMainValueSize;\n }\n\n return ReadoutSetpointSize.small;\n }\n\n private get resolvedActualPriority(): Priority {\n if (\n this.priority === ReadoutListItemPriority.enhanced ||\n (this.priority === ReadoutListItemPriority.setpoint &&\n !this.hasSetpoint) ||\n this.priority === ReadoutListItemPriority.setpointFlipFlop\n ) {\n return Priority.enhanced;\n }\n\n return Priority.regular;\n }\n\n private get resolvedActualMode(): ReadoutSetpointMode {\n return this.priority === ReadoutListItemPriority.enhanced\n ? ReadoutSetpointMode.setpoint\n : ReadoutSetpointMode.display;\n }\n\n private get resolvedSetpointPriority(): Priority {\n if (\n !this.hasSetpoint ||\n this.priority === ReadoutListItemPriority.regular\n ) {\n return Priority.regular;\n }\n\n return Priority.enhanced;\n }\n\n private get resolvedSetpointMode(): ReadoutSetpointMode {\n if (\n this.hasSetpoint &&\n this.priority === ReadoutListItemPriority.setpoint\n ) {\n return ReadoutSetpointMode.setpoint;\n }\n return ReadoutSetpointMode.display;\n }\n\n private get showsTrailingSource(): boolean {\n return (\n this.hasSource && this.stacking !== ReadoutListItemStacking.leadingSrc\n );\n }\n\n private get stacksLeadingUnitVertically(): boolean {\n return (\n this.stacking === ReadoutListItemStacking.leadingUnit &&\n this.size === ReadoutListItemSize.enhanced\n );\n }\n\n private get stacksLeadingSrcVertically(): boolean {\n return (\n this.stacking === ReadoutListItemStacking.leadingSrc &&\n this.size === ReadoutListItemSize.enhanced\n );\n }\n\n private renderLabelContainer() {\n if (!this.hasLabel) {\n return nothing;\n }\n\n const showsLeadingUnit =\n this.stacking === ReadoutListItemStacking.leadingUnit && this.hasUnit;\n const showsLeadingSrc =\n this.stacking === ReadoutListItemStacking.leadingSrc && this.hasSource;\n\n if (showsLeadingUnit && !this.stacksLeadingUnitVertically) {\n return html`\n <div class=\"label-inline\" part=\"label-inline\">\n <div class=\"label\" part=\"label\">${this.label}</div>\n <div class=\"unit unit-leading\" part=\"unit-leading\">${this.unit}</div>\n </div>\n `;\n }\n\n if (showsLeadingSrc && !this.stacksLeadingSrcVertically) {\n return html`\n <div class=\"label-inline\" part=\"label-inline\">\n <div class=\"label\" part=\"label\">${this.label}</div>\n <div class=\"source source-inline\" part=\"source-inline\">\n ${this.src}\n </div>\n </div>\n `;\n }\n\n return html`\n <div class=\"label-stack\" part=\"label-stack\">\n <div class=\"label\" part=\"label\">${this.label}</div>\n ${showsLeadingUnit\n ? html`<div class=\"unit unit-leading\" part=\"unit-leading\">\n ${this.unit}\n </div>`\n : nothing}\n ${showsLeadingSrc\n ? html`<div class=\"source source-inline\" part=\"source-inline\">\n ${this.src}\n </div>`\n : nothing}\n </div>\n `;\n }\n\n private renderValueIconSlot() {\n if (!this.hasValueIcon) {\n return nothing;\n }\n return html`<span class=\"value-icon\" slot=\"icon\" aria-hidden=\"true\">\n <slot name=\"value-icon\"></slot>\n </span>`;\n }\n\n private renderSetpoint() {\n if (!this.hasSetpoint) {\n return nothing;\n }\n\n return html`\n <obc-readout-setpoint\n .variant=${'setpoint'}\n .readoutStyle=${'regular'}\n .direction=${'horizontal'}\n .size=${this.resolvedSetpointSize}\n .priority=${this.resolvedSetpointPriority}\n .mode=${this.resolvedSetpointMode}\n .hugContent=${true}\n .value=${this.setpointValue}\n .showZeroPadding=${this.showZeroPadding}\n .fractionDigits=${this.fractionDigits}\n .minValueLength=${this.minValueLength}\n .hasHintedZeros=${this.hasHintedZeros}\n .hasDegree=${this.hasDegree}\n >\n <obi-input-right slot=\"icon\"></obi-input-right>\n </obc-readout-setpoint>\n `;\n }\n\n private renderActualValue() {\n return html`\n <obc-readout-setpoint\n .variant=${'value'}\n .readoutStyle=${'regular'}\n .direction=${'horizontal'}\n .size=${this.resolvedValueSize}\n .valueTypography=${this.resolvedValueTypography ?? undefined}\n .priority=${this.resolvedActualPriority}\n .mode=${this.resolvedActualMode}\n .hugContent=${true}\n .value=${this.value}\n .showZeroPadding=${this.showZeroPadding}\n .fractionDigits=${this.fractionDigits}\n .minValueLength=${this.minValueLength}\n .hasHintedZeros=${this.hasHintedZeros}\n .hasDegree=${this.hasDegree}\n >\n ${this.renderValueIconSlot()}\n </obc-readout-setpoint>\n `;\n }\n\n private renderValue() {\n return html`\n <div class=\"value-wrap\" part=\"value-wrap\">\n ${this.hasSetpoint\n ? html`<div class=\"value-cluster\" part=\"value-cluster\">\n ${this.renderSetpoint()} ${this.renderActualValue()}\n </div>`\n : this.renderActualValue()}\n </div>\n `;\n }\n\n private renderTrailingUnit() {\n if (\n !this.hasUnit ||\n this.stacking === ReadoutListItemStacking.leadingUnit\n ) {\n return nothing;\n }\n\n return html`<div class=\"unit unit-trailing\" part=\"unit-trailing\">\n ${this.unit}\n </div>`;\n }\n\n private renderTrailingSource() {\n if (!this.showsTrailingSource) {\n return nothing;\n }\n\n return html`\n <div class=\"divider\" part=\"divider\" aria-hidden=\"true\"></div>\n <div class=\"source source-trailing\" part=\"source-trailing\">\n ${this.src}\n </div>\n `;\n }\n\n override render() {\n return wrapWithAlertFrame(\n this.alert,\n html`\n <div\n class=${classMap({\n root: true,\n [`size-${this.size}`]: true,\n [`stacking-${this.stacking}`]: true,\n 'priority-enhanced':\n this.priority === ReadoutListItemPriority.enhanced,\n 'priority-setpoint':\n this.priority === ReadoutListItemPriority.setpoint,\n 'priority-setpoint-flip-flop':\n this.priority === ReadoutListItemPriority.setpointFlipFlop,\n 'data-none': this.dataState === ReadoutListItemDataState.none,\n 'data-low-integrity':\n this.dataState === ReadoutListItemDataState.lowIntegrity,\n 'data-invalid': this.dataState === ReadoutListItemDataState.invalid,\n 'has-leading-icon': this.hasLeadingIcon,\n 'has-value-icon': this.hasValueIcon,\n })}\n part=\"root\"\n >\n <div class=\"content\" part=\"content\">\n <div class=\"label-container\" part=\"label-container\">\n ${this.hasLeadingIcon\n ? html`<span class=\"leading-icon\" aria-hidden=\"true\"\n ><slot name=\"leading-icon\"></slot\n ></span>`\n : nothing}\n ${this.renderLabelContainer()}\n </div>\n\n ${this.labelOnly\n ? nothing\n : html`\n <div class=\"value-container\" part=\"value-container\">\n ${this.renderValue()} ${this.renderTrailingUnit()}\n </div>\n\n ${this.renderTrailingSource()}\n `}\n </div>\n </div>\n `,\n true\n );\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-readout-list-item': ObcReadoutListItem;\n }\n}\n"],"names":["ReadoutListItemDataState","ReadoutListItemSize","ReadoutListItemStacking","ReadoutListItemPriority"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"readout-list-item.js","sources":["../../../src/navigation-instruments/readout-list-item/readout-list-item.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-list-item.css?inline';\nimport {customElement} from '../../decorator.js';\nimport '../../components/textbox/textbox.js';\nimport {\n ObcTextboxSize,\n ObcTextboxFontWeight,\n} from '../../components/textbox/textbox.js';\nimport '../../icons/icon-input-right.js';\nimport '../../icons/icon-notification-advice.js';\nimport {\n formatNumericValue,\n getHintZeros,\n type ReadoutNumericFormatOptions,\n} from '../readout/readout-formatters.js';\nimport {\n type AlertFrameConfig,\n wrapWithAlertFrame,\n} from '../../components/alert-frame/alert-frame.js';\n\n// The value weight maps straight to obc-textbox's font weights (regular /\n// semibold / bold). Re-exported so consumers can set `valueOptions.weight`\n// without a second import path.\nexport {ObcTextboxFontWeight} from '../../components/textbox/textbox.js';\n\n/**\n * Density/size scale of the readout row.\n * - `small`: regular value typography (smallest, densest).\n * - `medium`: medium value typography.\n * - `large`: large value typography.\n */\nexport enum ReadoutListItemSize {\n small = 'small',\n medium = 'medium',\n large = 'large',\n}\n\n/**\n * Placement of the unit/source relative to the label and value.\n * - `trailing-unit`: unit after the value, source after a trailing divider.\n * - `leading-unit`: unit beside/under the label.\n * - `leading-src`: source beside/under the label (no trailing source).\n */\nexport enum ReadoutListItemStacking {\n trailingUnit = 'trailing-unit',\n leadingUnit = 'leading-unit',\n leadingSrc = 'leading-src',\n}\n\n/**\n * Colour emphasis of the value.\n * - `regular`: neutral.\n * - `enhanced`: accented (in-command) colour.\n */\nexport enum ReadoutListItemPriority {\n regular = 'regular',\n enhanced = 'enhanced',\n}\n\n/**\n * Measurement quality of the value. Orthogonal to the row-level `alert`\n * – a low-integrity or invalid value can also sit inside an alert frame.\n */\nexport enum ReadoutListItemDataQuality {\n lowIntegrity = 'low-integrity',\n invalid = 'invalid',\n}\n\n/**\n * Corner style of the interactive (clickable) surface.\n * - `squared` (default): no rounding (true rectangle).\n * - `round-corners`: larger rounded corners.\n * - `round`: fully rounded (pill).\n */\nexport enum ReadoutListItemBorder {\n squared = 'squared',\n round = 'round',\n roundCorners = 'round-corners',\n}\n\nexport interface ReadoutListItemClickable {\n border?: ReadoutListItemBorder;\n}\n\n/**\n * Per-block state shared by value / setpoint / advice / src. Each is independent\n * of (and nests inside) the row-level `dataQuality` / `alert` props. All\n * combinations are allowed.\n */\nexport interface ReadoutBlockState {\n /** Per-block measurement quality (low-integrity / invalid). */\n dataQuality?: ReadoutListItemDataQuality;\n /** Per-block alert frame; nests inside any row-level alert frame. */\n alert?: false | AlertFrameConfig;\n}\n\nexport interface ReadoutValueOptions extends ReadoutBlockState {\n /** Render the unfilled leading positions as muted zeroes (requires `maxDigits`). */\n hintedZeros?: boolean;\n /**\n * Value font weight — `regular` (default), `semibold`, or `bold` (the\n * obc-textbox weights). Affects weight only; it does NOT change the colour\n * (colour is driven by `priority`).\n */\n weight?: ObcTextboxFontWeight;\n /** Show the `value-icon` slot before the value. */\n hasIcon?: boolean;\n /**\n * Longest value string to reserve width for (e.g. `\"0000.0\"`), so rows align\n * across different value lengths / `fractionDigits` — set the same value on\n * every row. Combined with the `maxDigits`/`fractionDigits`-derived reserve by\n * taking whichever is **wider**, so it never reserves less than the formatted\n * value needs.\n */\n spaceReserver?: string;\n}\n\n/**\n * How the setpoint segment behaves relative to the value.\n * - `always-visible` (default): the setpoint is always shown.\n * - `flip-flop`: value and setpoint swap emphasis (size) as the value reaches\n * the setpoint.\n * - `pop-up`: the setpoint is shown only while the value has not reached it,\n * then fades out (100ms) once value === setpoint.\n */\nexport enum ReadoutListItemSetpointInteraction {\n alwaysVisible = 'always-visible',\n flipFlop = 'flip-flop',\n popUp = 'pop-up',\n}\n\nexport interface ReadoutSetpointOptions extends ReadoutBlockState {\n hintedZeros?: boolean;\n /** How the setpoint behaves relative to the value (default `always-visible`). */\n interaction?: ReadoutListItemSetpointInteraction;\n /**\n * The user is physically interacting with (adjusting) the setpoint — the\n * \"focus\" visual state. Same convention as `touching` on the instrument\n * setpoint marker (`SetpointMixin` / `svghelpers/setpoint.ts`): keeps the\n * setpoint visible and shows the lighter-blue focus triangle.\n */\n touching?: boolean;\n /** Longest value string to reserve width for; see {@link ReadoutValueOptions.spaceReserver}. */\n spaceReserver?: string;\n}\n\nexport interface ReadoutAdviceOptions extends ReadoutBlockState {\n hintedZeros?: boolean;\n /** Longest value string to reserve width for; see {@link ReadoutValueOptions.spaceReserver}. */\n spaceReserver?: string;\n}\n\nexport interface ReadoutReserverOptions {\n /** Longest expected string to reserve width for (aligns multiple rows), e.g. `\"miles\"`. */\n spaceReserver?: string;\n}\n\nexport interface ReadoutSrcOptions extends ReadoutBlockState {\n /** Longest expected source string to reserve width for; see {@link ReadoutReserverOptions.spaceReserver}. */\n spaceReserver?: string;\n}\n\nenum BlockRole {\n value = 'value',\n setpoint = 'setpoint',\n advice = 'advice',\n}\n\n/**\n * `<obc-readout-list-item>` – A compact, dense readout row for lists and tables.\n *\n * Renders a label, an optional source, an optional unit, and up to three\n * cap-height \"readout building blocks\" – advice, setpoint, and value – each a\n * fixed-width-reservable numeric segment. Dynamic data is passed as top-level\n * primitives (`value`, `setpoint`, `advice`, `label`, `unit`, `src`). Global\n * layout/format is configured via top-level props (`size`, `priority`,\n * `stacking`, `hasDegree`, `dataQuality`, `alert`, …) and per-block tweaks via one\n * object per block (`valueOptions`, `setpointOptions`, `adviceOptions`,\n * `unitOptions`, `srcOptions`).\n *\n * ### Features\n * - **Building blocks:** value, optional setpoint, and optional advice segments,\n * each cap-height-aligned and able to reserve a stable width.\n * - **Sizes:** `small`, `medium`, `large` density scales.\n * - **Stacking:** `trailing-unit`, `leading-unit`, `leading-src` placement.\n * - **Priority:** `regular`/`enhanced` colour emphasis; per-value `weight`\n * (`regular`/`semibold`/`bold`) is independent of colour.\n * - **Setpoint flip-flop:** swaps emphasis between value and setpoint as the\n * value reaches the setpoint.\n * - **Data quality:** `low-integrity`/`invalid` styling, combinable with `alert`.\n * - **Alert frame:** optional `alert` wrapper (caution/warning/alarm/level).\n * - **Clickable:** optionally rendered as a focusable button with `squared`,\n * `round-corners`, or `round` corners.\n * - **Formatting:** shared `fractionDigits`, width reservation via `maxDigits`\n * and per-segment `hintedZeros`; a `null` value renders a dash (`-`).\n *\n * ### Usage Guidelines\n * Use for dense readout rows in lists/tables. Prefer `<obc-readout>` for rich\n * multi-segment instrument layouts, source pickers, or flyout behaviour.\n *\n * @experimental This component is the pilot for the new primitives + per-block\n * options Readout API; its API may change in a future release.\n *\n * ### Slots\n * | Slot Name | Renders When | Purpose |\n * |---------------|-------------------------------|------------------------------------------|\n * | leading-icon | `hasLeadingIcon` | Icon before the label. |\n * | value-icon | `valueOptions.hasIcon` | Icon before the value. |\n * | setpoint-icon | `hasSetpoint` | Overrides the default setpoint icon. |\n * | advice-icon | `hasAdvice` | Overrides the default advice icon. |\n *\n * @slot leading-icon - Icon before the label.\n * @slot value-icon - Icon before the value.\n * @slot setpoint-icon - Overrides the default setpoint icon.\n * @slot advice-icon - Overrides the default advice icon.\n */\n@customElement('obc-readout-list-item')\nexport class ObcReadoutListItem extends LitElement {\n // Primitives (dynamic data)\n @property({type: String}) label?: string;\n @property({type: String}) unit?: string;\n @property({type: String}) src?: string;\n\n @property({type: Boolean, attribute: false}) hasValue = true;\n @property({type: Number}) value: number | null = null;\n /** Render the value as the literal \"OFF\" (e.g. equipment powered down). Affects the value only. */\n @property({type: Boolean}) off = false;\n\n @property({type: Boolean}) hasSetpoint = false;\n /** @availableWhen hasSetpoint==true */\n @property({type: Number}) setpoint?: number;\n\n @property({type: Boolean}) hasAdvice = false;\n /** @availableWhen hasAdvice==true */\n @property({type: Number}) advice?: number;\n\n // Global layout/format (each defaults via its `resolved*` getter where useful).\n @property({type: String}) size?: ReadoutListItemSize;\n @property({type: String}) priority?: ReadoutListItemPriority;\n @property({type: String}) stacking?: ReadoutListItemStacking;\n @property({type: Object}) clickable: boolean | ReadoutListItemClickable =\n false;\n @property({type: Boolean}) hasLeadingIcon = false;\n @property({type: Boolean}) hasDegree = false;\n @property({type: Boolean}) hasDegreeSpacer = false;\n @property({type: Number}) fractionDigits = 0;\n @property({type: Number}) maxDigits = 0;\n @property({type: String}) dataQuality?: ReadoutListItemDataQuality;\n // `boolean | …` (not `false | …`): the generated Angular wrapper widens a\n // literal-`false` union to `boolean`, which then won't assign back to a\n // `false`-typed element property. `wrapWithAlertFrame` treats any non-object\n // (incl. `true`) as \"no frame\", so accepting `boolean` is harmless.\n @property({type: Object}) alert: boolean | AlertFrameConfig = false;\n\n // Per-block configuration — one object per block (see the Readout*Options types).\n @property({type: Object}) valueOptions?: ReadoutValueOptions;\n @property({type: Object}) setpointOptions?: ReadoutSetpointOptions;\n @property({type: Object}) adviceOptions?: ReadoutAdviceOptions;\n @property({type: Object}) unitOptions?: ReadoutReserverOptions;\n @property({type: Object}) srcOptions?: ReadoutSrcOptions;\n\n /** Pop-up deferred-hide phase for the setpoint (see {@link updated}). */\n @state() private deferredSetpointHidePhase: 'none' | 'hiding' | 'hidden' =\n 'none';\n private deferredSetpointHideTimer?: number;\n private hasCompletedFirstUpdate = false;\n\n private get resolvedSize(): ReadoutListItemSize {\n return this.size ?? ReadoutListItemSize.small;\n }\n\n private get resolvedStacking(): ReadoutListItemStacking {\n return this.stacking ?? ReadoutListItemStacking.trailingUnit;\n }\n\n private get resolvedPriority(): ReadoutListItemPriority {\n return this.priority ?? ReadoutListItemPriority.regular;\n }\n\n private get resolvedFractionDigits(): number {\n return this.fractionDigits ?? 0;\n }\n\n private get resolvedMaxDigits(): number {\n return this.maxDigits ?? 0;\n }\n\n private get resolvedClickable(): false | Required<ReadoutListItemClickable> {\n const clickable = this.clickable;\n if (!clickable) {\n return false;\n }\n if (clickable === true) {\n return {border: ReadoutListItemBorder.squared};\n }\n return {border: clickable.border ?? ReadoutListItemBorder.squared};\n }\n\n private get isAtSetpoint(): boolean {\n if (\n !this.hasSetpoint ||\n this.value === null ||\n this.setpoint === undefined\n ) {\n return false;\n }\n // Compare what is DISPLAYED (rounded to fractionDigits), not the raw values,\n // so e.g. 29.999 and 30 at fractionDigits=0 both read \"30\" → at setpoint.\n const formatOptions = this.numericFormatOptions(this.resolvedMaxDigits);\n return (\n formatNumericValue(this.value, formatOptions) ===\n formatNumericValue(this.setpoint, formatOptions)\n );\n }\n\n private get resolvedSetpointInteraction(): ReadoutListItemSetpointInteraction {\n return (\n this.setpointOptions?.interaction ??\n ReadoutListItemSetpointInteraction.alwaysVisible\n );\n }\n\n private get isFlipFlop(): boolean {\n return (\n this.resolvedSetpointInteraction ===\n ReadoutListItemSetpointInteraction.flipFlop\n );\n }\n\n private get isPopUp(): boolean {\n return (\n this.resolvedSetpointInteraction ===\n ReadoutListItemSetpointInteraction.popUp\n );\n }\n\n private get setpointTouching(): boolean {\n return this.setpointOptions?.touching ?? false;\n }\n\n /**\n * The setpoint is rendered \"emphasised\" (primary size + SemiBold weight) when\n * it is the focus of attention: while actively adjusting (`touching`), or while\n * a flip-flop has the value away from the setpoint. Otherwise it is a secondary\n * (smaller, regular-weight) reference next to the value.\n */\n private get isSetpointEmphasized(): boolean {\n if (!this.hasSetpoint) {\n return false;\n }\n if (this.setpointTouching) {\n return true;\n }\n return this.isFlipFlop && !this.isAtSetpoint;\n }\n\n /**\n * The row's enhanced (in-command) colour state, applied uniformly to BOTH the\n * value and the setpoint — they are always either both neutral or both enhanced\n * (never a blue setpoint next to a grey value). Driven by `priority` only;\n * `valueOptions.weight` changes weight, not colour.\n */\n private get rowEnhanced(): boolean {\n return this.resolvedPriority === ReadoutListItemPriority.enhanced;\n }\n\n /** Primary value-typography size for the current density tier. */\n private get primarySize(): ObcTextboxSize {\n switch (this.resolvedSize) {\n case ReadoutListItemSize.large:\n return ObcTextboxSize.l;\n case ReadoutListItemSize.medium:\n return ObcTextboxSize.m;\n default:\n return ObcTextboxSize.s;\n }\n }\n\n /** Secondary (de-emphasised) value-typography size for the current density tier. */\n private get secondarySize(): ObcTextboxSize {\n switch (this.resolvedSize) {\n case ReadoutListItemSize.large:\n return ObcTextboxSize.s;\n case ReadoutListItemSize.medium:\n return ObcTextboxSize.s;\n default:\n return ObcTextboxSize.xs;\n }\n }\n\n private get valueSize(): ObcTextboxSize {\n // The value de-emphasises (secondary size) whenever the setpoint is the\n // focus — while actively adjusting (`touching`) or while a flip-flop holds\n // the value away from the setpoint. So \"grab the setpoint\" shrinks the value for\n // the whole adjustment (initiate + move read the same: setpoint big, value\n // small), mirroring the flip-flop convention.\n if (this.isSetpointEmphasized) {\n return this.secondarySize;\n }\n return this.primarySize;\n }\n\n private get setpointSize(): ObcTextboxSize {\n return this.isSetpointEmphasized ? this.primarySize : this.secondarySize;\n }\n\n /** Value font weight passes straight to obc-textbox; regular when unset. Colour is separate. */\n private get valueWeight(): ObcTextboxFontWeight {\n return this.valueOptions?.weight ?? ObcTextboxFontWeight.regular;\n }\n\n /** Setpoint is SemiBold only while emphasised, otherwise regular weight. */\n private get setpointWeight(): ObcTextboxFontWeight {\n return this.isSetpointEmphasized\n ? ObcTextboxFontWeight.semibold\n : ObcTextboxFontWeight.regular;\n }\n\n private numericFormatOptions(maxDigits: number): ReadoutNumericFormatOptions {\n return {\n showZeroPadding: false,\n minValueLength: maxDigits,\n fractionDigits: this.resolvedFractionDigits,\n };\n }\n\n /** Widest possible value string for width reservation (e.g. `\"000.0\"`). */\n private get reserverText(): string {\n const maxDigits = this.resolvedMaxDigits;\n if (maxDigits <= 0) {\n return '';\n }\n const fractionDigits = this.resolvedFractionDigits;\n const integer = '0'.repeat(Math.max(maxDigits, 1));\n return fractionDigits > 0\n ? `${integer}.${'0'.repeat(fractionDigits)}`\n : integer;\n }\n\n /**\n * Effective width reserver for a numeric block: the wider of the explicit\n * `spaceReserver` and the `maxDigits`/`fractionDigits`-derived reserve, so an\n * explicit reserver can never reserve *less* than the formatted value needs.\n * Under tabular-nums the rendered width is proportional to character count, so\n * \"wider\" compares string 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 /** classMap fragment for a block / source carrying per-block data quality. */\n private dataQualityClasses(\n dataQuality: ReadoutListItemDataQuality | undefined\n ): Record<string, boolean> {\n return {\n 'data-low-integrity':\n dataQuality === ReadoutListItemDataQuality.lowIntegrity,\n 'data-invalid': dataQuality === ReadoutListItemDataQuality.invalid,\n };\n }\n\n private renderIcon(role: BlockRole): TemplateResult | typeof nothing {\n if (role === BlockRole.value) {\n if (!this.valueOptions?.hasIcon) {\n return nothing;\n }\n return html`<span class=\"block-icon\" aria-hidden=\"true\"\n ><slot name=\"value-icon\"></slot\n ></span>`;\n }\n if (role === BlockRole.setpoint) {\n return html`<span class=\"block-icon\" aria-hidden=\"true\">\n <slot name=\"setpoint-icon\"><obi-input-right></obi-input-right></slot>\n </span>`;\n }\n return html`<span class=\"block-icon\" aria-hidden=\"true\">\n <slot name=\"advice-icon\"\n ><obi-notification-advice></obi-notification-advice\n ></slot>\n </span>`;\n }\n\n private renderBlock(config: {\n role: BlockRole;\n value: number | null | undefined;\n size: ObcTextboxSize;\n enhanced: boolean;\n weight: ObcTextboxFontWeight;\n hintedZeros: boolean;\n spaceReserver?: string;\n off?: boolean;\n hasDegree?: boolean;\n extraClasses?: Record<string, boolean>;\n dataQuality?: ReadoutListItemDataQuality;\n alert?: false | AlertFrameConfig;\n }): TemplateResult {\n const formatOptions = this.numericFormatOptions(this.resolvedMaxDigits);\n const valueForFormat = config.value ?? undefined;\n const text = config.off\n ? 'OFF'\n : formatNumericValue(valueForFormat, formatOptions);\n // `maxDigits` reserves INTEGER digits only (see `reserverText`), but\n // getHintZeros measures total digits (it subtracts just the decimal point),\n // so pad its target by `fractionDigits` to hint the right number of integer\n // zeros (e.g. value 1.2, maxDigits 3, fractionDigits 1 → \"001.2\", not \"01.2\").\n const hinted =\n config.off || !config.hintedZeros\n ? ''\n : getHintZeros(valueForFormat, {\n ...formatOptions,\n minValueLength:\n formatOptions.minValueLength + formatOptions.fractionDigits,\n });\n const reserver = this.widerReserver(\n config.spaceReserver,\n this.reserverText\n );\n\n const block = html`\n <div\n class=${classMap({\n block: true,\n [`block-${config.role}`]: true,\n 'tone-enhanced': config.enhanced,\n ...this.dataQualityClasses(config.dataQuality),\n ...(config.extraClasses ?? {}),\n })}\n part=\"block block-${config.role}\"\n >\n ${this.renderIcon(config.role)}\n <span class=\"block-content\">\n <obc-textbox\n class=\"block-text\"\n .size=${config.size}\n .fontWeight=${config.weight}\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 ${config.hasDegree\n ? this.renderDegreeGlyph(config.size, {inherit: true})\n : nothing}\n </span>\n </div>\n `;\n return wrapWithAlertFrame(config.alert ?? false, block);\n }\n\n /**\n * A cap-height `°` column whose width scales with the value size. Used after\n * the value (as the value↔unit boundary, via {@link renderValueUnitGap}) and\n * inside the setpoint / advice blocks. `inherit` makes the glyph take the\n * surrounding block's colour (setpoint/advice); otherwise it uses the value\n * colour, optionally `enhanced`.\n */\n private renderDegreeGlyph(\n size: ObcTextboxSize,\n opts: {enhanced?: boolean; inherit?: boolean} = {}\n ): TemplateResult {\n return html`\n <span\n class=${classMap({\n 'degree-column': true,\n [`degree-${size}`]: true,\n 'tone-enhanced': !opts.inherit && Boolean(opts.enhanced),\n 'degree-inherit': Boolean(opts.inherit),\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 /**\n * The gap rendered between the value digits and the unit.\n *\n * - `hasDegree`: a cap-height `°` column whose width scales with the value\n * size (the `°` replaces the default gap).\n * - otherwise: the default 2px gap (only when a trailing unit follows).\n *\n * `hasDegreeSpacer` deliberately does NOT add anything here — it keeps the 2px\n * gap and instead widens the unit column via {@link renderDegreeSpacer} (a\n * spacer AFTER the unit). That way a non-degree row's value digits stay\n * aligned with degree rows (degree column width = spacer width + 2px gap)\n * while its unit shifts left. Mirrors Figma `1:2920` (spacer) / `1:2970`\n * (degree).\n *\n * TODO(designer): cross-size alignment is deferred. Degree rows of different\n * value sizes have different `°` column widths (6/8/12px), so their value digit\n * edges stagger by `degree-width`. For degree rows of mixed sizes you cannot\n * align the value digit edges AND keep the unit column aligned — resolving it\n * needs a design decision (a constant degree reserve, which widens the smaller\n * rows' `°`, OR pinning the value edge and letting the unit column stagger).\n */\n private renderValueUnitGap(): TemplateResult | typeof nothing {\n if (!this.hasValue) {\n return nothing;\n }\n const hasTrailingUnit =\n Boolean(this.unit) &&\n this.resolvedStacking !== ReadoutListItemStacking.leadingUnit;\n\n if ((this.hasDegree ?? false) && !this.off) {\n return this.renderDegreeGlyph(this.valueSize, {\n enhanced: this.rowEnhanced,\n });\n }\n if (hasTrailingUnit) {\n return html`<span class=\"value-unit-gap\" aria-hidden=\"true\"></span>`;\n }\n return nothing;\n }\n\n /**\n * A spacer rendered AFTER the unit when `hasDegreeSpacer` is set on a\n * non-degree row. Its width (`degree-compensation-padding`) = the degree\n * column width minus the 2px gap, so the row's value digits align with degree\n * rows in the same column while its unit shifts left. See\n * {@link renderValueUnitGap}.\n */\n private renderDegreeSpacer(): TemplateResult | typeof nothing {\n const hasDegree = this.hasDegree ?? false;\n const hasDegreeSpacer = this.hasDegreeSpacer ?? false;\n if (hasDegree || !hasDegreeSpacer) {\n return nothing;\n }\n return html`<span\n class=\"degree-spacer\"\n part=\"degree-spacer\"\n aria-hidden=\"true\"\n ></span>`;\n }\n\n private renderTextbox(\n role: 'label' | 'unit' | 'source',\n text: string,\n reserver?: string,\n state?: ReadoutBlockState\n ): TemplateResult {\n const weight =\n role === 'label'\n ? ObcTextboxFontWeight.semibold\n : ObcTextboxFontWeight.regular;\n const box = html`\n <obc-textbox\n class=${classMap({\n [role]: true,\n ...this.dataQualityClasses(state?.dataQuality),\n })}\n part=${role}\n .size=${ObcTextboxSize.xs}\n .fontWeight=${weight}\n alignment=\"left\"\n >\n ${text}\n ${reserver ? html`<span slot=\"length\">${reserver}</span>` : nothing}\n </obc-textbox>\n `;\n return wrapWithAlertFrame(state?.alert ?? false, box);\n }\n\n private renderValueCluster(): TemplateResult {\n const popUpAtSetpoint =\n this.isPopUp && this.isAtSetpoint && !this.setpointTouching;\n const setpointExtraClasses = {\n 'is-hiding':\n popUpAtSetpoint && this.deferredSetpointHidePhase === 'hiding',\n 'is-hidden':\n popUpAtSetpoint && this.deferredSetpointHidePhase === 'hidden',\n touching: this.setpointTouching,\n };\n return html`\n <div class=\"value-cluster\" part=\"value-cluster\">\n ${this.hasAdvice\n ? this.renderBlock({\n role: BlockRole.advice,\n value: this.advice,\n size: this.secondarySize,\n enhanced: false,\n weight: ObcTextboxFontWeight.regular,\n hintedZeros: this.adviceOptions?.hintedZeros ?? false,\n spaceReserver: this.adviceOptions?.spaceReserver,\n hasDegree: this.hasDegree ?? false,\n dataQuality: this.adviceOptions?.dataQuality,\n alert: this.adviceOptions?.alert,\n })\n : nothing}\n ${this.hasSetpoint\n ? this.renderBlock({\n role: BlockRole.setpoint,\n value: this.setpoint,\n size: this.setpointSize,\n // Value and setpoint share the enhanced colour state (both neutral\n // or both enhanced); the setpoint is bold only while emphasised.\n enhanced: this.rowEnhanced,\n weight: this.setpointWeight,\n hintedZeros: this.setpointOptions?.hintedZeros ?? false,\n spaceReserver: this.setpointOptions?.spaceReserver,\n hasDegree: this.hasDegree ?? false,\n extraClasses: setpointExtraClasses,\n dataQuality: this.setpointOptions?.dataQuality,\n alert: this.setpointOptions?.alert,\n })\n : nothing}\n ${this.hasValue\n ? this.renderBlock({\n role: BlockRole.value,\n value: this.value,\n size: this.valueSize,\n enhanced: this.rowEnhanced,\n weight: this.valueWeight,\n hintedZeros: this.valueOptions?.hintedZeros ?? false,\n spaceReserver: this.valueOptions?.spaceReserver,\n off: this.off,\n dataQuality: this.valueOptions?.dataQuality,\n alert: this.valueOptions?.alert,\n })\n : nothing}\n </div>\n `;\n }\n\n private renderLabelContainer(): TemplateResult {\n const stacking = this.resolvedStacking;\n const showLeadingUnit =\n stacking === ReadoutListItemStacking.leadingUnit && Boolean(this.unit);\n const showLeadingSrc =\n stacking === ReadoutListItemStacking.leadingSrc && Boolean(this.src);\n\n return html`\n <div class=\"label-container\" part=\"label-container\">\n ${this.hasLeadingIcon\n ? html`<span class=\"leading-icon\" aria-hidden=\"true\"\n ><slot name=\"leading-icon\"></slot\n ></span>`\n : nothing}\n <div class=\"label-stack\" part=\"label-stack\">\n ${this.label ? this.renderTextbox('label', this.label) : nothing}\n ${showLeadingUnit\n ? this.renderTextbox(\n 'unit',\n this.unit ?? '',\n this.unitOptions?.spaceReserver\n )\n : nothing}\n ${showLeadingSrc\n ? this.renderTextbox(\n 'source',\n this.src ?? '',\n this.srcOptions?.spaceReserver,\n this.srcOptions\n )\n : nothing}\n </div>\n </div>\n `;\n }\n\n private renderTrailingUnit(): TemplateResult | typeof nothing {\n if (\n this.resolvedStacking === ReadoutListItemStacking.leadingUnit ||\n !this.unit\n ) {\n return nothing;\n }\n return this.renderTextbox(\n 'unit',\n this.unit,\n this.unitOptions?.spaceReserver\n );\n }\n\n private renderTrailingSource(): TemplateResult | typeof nothing {\n if (\n this.resolvedStacking === ReadoutListItemStacking.leadingSrc ||\n !this.src\n ) {\n return nothing;\n }\n return html`\n <div class=\"divider\" part=\"divider\" aria-hidden=\"true\"></div>\n ${this.renderTextbox(\n 'source',\n this.src,\n this.srcOptions?.spaceReserver,\n this.srcOptions\n )}\n `;\n }\n\n private renderContent(): TemplateResult {\n return html`\n <div class=\"content\" part=\"content\">\n ${this.renderLabelContainer()}\n <div class=\"value-area\" part=\"value-area\">\n ${this.renderValueCluster()} ${this.renderValueUnitGap()}\n <div class=\"unit-area\" part=\"unit-area\">\n ${this.renderTrailingUnit()} ${this.renderDegreeSpacer()}\n </div>\n </div>\n ${this.renderTrailingSource()}\n </div>\n `;\n }\n\n override updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n\n const firstUpdate = !this.hasCompletedFirstUpdate;\n this.hasCompletedFirstUpdate = true;\n\n // Pop-up: hide the setpoint shortly after the value reaches it. `touching`\n // and the non-pop-up modes keep the setpoint visible.\n if (!this.isPopUp || this.setpointTouching) {\n this.clearDeferredSetpointHide();\n return;\n }\n\n const shouldHide = this.hasSetpoint && this.isAtSetpoint;\n\n if (firstUpdate) {\n // Settle to the resting state on mount without animating.\n this.deferredSetpointHidePhase = shouldHide ? 'hidden' : 'none';\n return;\n }\n\n if (!shouldHide) {\n this.clearDeferredSetpointHide();\n return;\n }\n\n if (this.deferredSetpointHidePhase !== 'none') {\n return;\n }\n\n this.deferredSetpointHidePhase = 'hiding';\n window.clearTimeout(this.deferredSetpointHideTimer);\n this.deferredSetpointHideTimer = window.setTimeout(() => {\n this.deferredSetpointHidePhase = 'hidden';\n this.deferredSetpointHideTimer = undefined;\n }, 100);\n }\n\n private clearDeferredSetpointHide(): void {\n if (this.deferredSetpointHidePhase !== 'none') {\n this.deferredSetpointHidePhase = 'none';\n }\n window.clearTimeout(this.deferredSetpointHideTimer);\n this.deferredSetpointHideTimer = undefined;\n }\n\n override disconnectedCallback(): void {\n window.clearTimeout(this.deferredSetpointHideTimer);\n this.deferredSetpointHideTimer = undefined;\n // Settle a mid-flight hide to its end state. Without this, disconnecting\n // during the 100ms window leaves the phase stuck at 'hiding' (the timer that\n // would advance it to 'hidden' is gone), so a later reconnect never resolves.\n if (this.deferredSetpointHidePhase === 'hiding') {\n this.deferredSetpointHidePhase = 'hidden';\n }\n super.disconnectedCallback();\n }\n\n override render() {\n const clickable = this.resolvedClickable;\n const dataQuality = this.dataQuality;\n const classes = classMap({\n root: true,\n [`size-${this.resolvedSize}`]: true,\n [`stacking-${this.resolvedStacking}`]: true,\n [`priority-${this.resolvedPriority}`]: true,\n 'data-low-integrity':\n dataQuality === ReadoutListItemDataQuality.lowIntegrity,\n 'data-invalid': dataQuality === ReadoutListItemDataQuality.invalid,\n 'flip-flop': this.isFlipFlop,\n clickable: Boolean(clickable),\n [`border-${clickable ? clickable.border : ReadoutListItemBorder.squared}`]:\n Boolean(clickable),\n });\n\n const surface = html`<div class=\"surface\" part=\"surface\">\n ${this.renderContent()}\n </div>`;\n\n // No `aria-label` here: it would override the button's accessible name and\n // hide the dynamic readout text (value / unit / source) from screen readers.\n // The visible content (label + value + unit + source) already forms a\n // complete accessible name; icons/reservers are aria-hidden / visibility-clipped.\n const root = clickable\n ? html`<button class=${classes} part=\"root\" type=\"button\">\n ${surface}\n </button>`\n : html`<div class=${classes} part=\"root\">${surface}</div>`;\n\n // `alert` accepts `boolean` (so the generated Angular wrapper's widened\n // `boolean` type assigns cleanly), but `wrapWithAlertFrame` ignores non-object\n // truthy values. Normalise `true` → a default frame `{}` (like `clickable:\n // true`) so it isn't a silent no-op; `false`/object pass through.\n // fullWidth=true: the row-level alert frame stretches to the readout's full\n // width (PR #1001) rather than hugging it. Per-block / src alert frames keep\n // the default (hug) so they stay inline.\n const alert = this.alert === true ? {} : this.alert;\n return wrapWithAlertFrame(alert, root, true);\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-readout-list-item': ObcReadoutListItem;\n }\n}\n"],"names":["ReadoutListItemSize","ReadoutListItemStacking","ReadoutListItemPriority","ReadoutListItemDataQuality","ReadoutListItemBorder","ReadoutListItemSetpointInteraction","state"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -61,11 +61,18 @@
|
|
|
61
61
|
color: var(--on-flat-disabled-color);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
.badges {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 4px;
|
|
68
|
+
position: relative;
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
.badge {
|
|
65
72
|
position: relative;
|
|
66
73
|
}
|
|
67
74
|
|
|
68
|
-
&:not(.hug) .
|
|
75
|
+
&:not(.hug) .badges {
|
|
69
76
|
right: 0;
|
|
70
77
|
}
|
|
71
78
|
|
|
@@ -28,6 +28,7 @@ const meta: Meta<ObcTabItem> = {
|
|
|
28
28
|
.badgeShowNumber=${args.badgeShowNumber}
|
|
29
29
|
.showLeadingBadgeIcon=${args.showLeadingBadgeIcon}
|
|
30
30
|
.centerContent=${args.centerContent}
|
|
31
|
+
.badges=${args.badges ?? []}
|
|
31
32
|
>
|
|
32
33
|
${args.hasLeadingIcon
|
|
33
34
|
? html`<obi-placeholder slot="leading-icon"></obi-placeholder>`
|
|
@@ -35,6 +36,14 @@ const meta: Meta<ObcTabItem> = {
|
|
|
35
36
|
${args.hasBadge
|
|
36
37
|
? html`<obi-placeholder slot="badge-icon"></obi-placeholder>`
|
|
37
38
|
: null}
|
|
39
|
+
${(args.badges ?? [])
|
|
40
|
+
.filter((badge) => badge.iconSlotName)
|
|
41
|
+
.map(
|
|
42
|
+
(badge) =>
|
|
43
|
+
html`<obi-placeholder
|
|
44
|
+
slot=${badge.iconSlotName!}
|
|
45
|
+
></obi-placeholder>`
|
|
46
|
+
)}
|
|
38
47
|
</obc-tab-item>
|
|
39
48
|
`,
|
|
40
49
|
args: {
|
|
@@ -56,6 +65,7 @@ const meta: Meta<ObcTabItem> = {
|
|
|
56
65
|
badgeShowNumber: true,
|
|
57
66
|
showLeadingBadgeIcon: false,
|
|
58
67
|
centerContent: false,
|
|
68
|
+
badges: [],
|
|
59
69
|
},
|
|
60
70
|
} satisfies Meta<ObcTabItem>;
|
|
61
71
|
|
|
@@ -311,6 +321,26 @@ export const HighBadgeCount = {
|
|
|
311
321
|
title: 'High Alarm Count',
|
|
312
322
|
},
|
|
313
323
|
};
|
|
324
|
+
export const MultipleBadges = {
|
|
325
|
+
args: {
|
|
326
|
+
hug: false,
|
|
327
|
+
hasLeadingIcon: true,
|
|
328
|
+
hasClose: false,
|
|
329
|
+
centerContent: false,
|
|
330
|
+
title: 'Multiple Badges',
|
|
331
|
+
badges: [
|
|
332
|
+
{type: BadgeType.alarm, size: BadgeSize.regular, count: 3},
|
|
333
|
+
{type: BadgeType.warning, size: BadgeSize.regular, count: 12},
|
|
334
|
+
{
|
|
335
|
+
type: BadgeType.notification,
|
|
336
|
+
size: BadgeSize.regular,
|
|
337
|
+
showIcon: true,
|
|
338
|
+
iconSlotName: 'notification-icon',
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
|
|
314
344
|
export const BadgeHideNumber = {
|
|
315
345
|
args: {
|
|
316
346
|
hug: false,
|
|
@@ -8,6 +8,25 @@ import '../../icons/icon-close-google.js';
|
|
|
8
8
|
import '../badge/badge.js';
|
|
9
9
|
import {BadgeSize, BadgeType} from '../badge/badge.js';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for a single badge rendered by `<obc-tab-item>` via the `badges` property.
|
|
13
|
+
*/
|
|
14
|
+
export interface TabItemBadge {
|
|
15
|
+
/** Visual style/type of the badge. See `BadgeType` for available options. */
|
|
16
|
+
type: BadgeType;
|
|
17
|
+
/** Size of the badge. See `BadgeSize` for available options. */
|
|
18
|
+
size: BadgeSize;
|
|
19
|
+
/** The numeric value to display in the badge. */
|
|
20
|
+
count?: number;
|
|
21
|
+
/** Whether to show an icon inside the badge. Default: false. */
|
|
22
|
+
showIcon?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* When set, a `<slot>` with this name is rendered inside the badge so a custom
|
|
25
|
+
* icon can be projected (used for badge types without a built-in icon).
|
|
26
|
+
*/
|
|
27
|
+
iconSlotName?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
/**
|
|
12
31
|
* `<obc-tab-item>` – A selectable tab component for navigation menus and tabbed interfaces.
|
|
13
32
|
*
|
|
@@ -150,6 +169,20 @@ export class ObcTabItem extends LitElement {
|
|
|
150
169
|
@property({type: Boolean, attribute: 'has-divider'}) hasDivider = false;
|
|
151
170
|
|
|
152
171
|
/**
|
|
172
|
+
* One or more badges (count/status) to display on the tab.
|
|
173
|
+
*
|
|
174
|
+
* When this array is non-empty it takes precedence over the deprecated
|
|
175
|
+
* single-badge props (`hasBadge`, `badgeType`, `badgeSize`, `badgeCount`,
|
|
176
|
+
* `badgeShowNumber`, `showLeadingBadgeIcon`). When empty, the deprecated
|
|
177
|
+
* props are used instead (gated by `hasBadge`).
|
|
178
|
+
*
|
|
179
|
+
* Default: []
|
|
180
|
+
*/
|
|
181
|
+
@property({type: Array, attribute: false}) badges: TabItemBadge[] = [];
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @deprecated Use the `badges` array instead.
|
|
185
|
+
*
|
|
153
186
|
* Displays a badge (count/status) on the tab.
|
|
154
187
|
* Configure badge appearance via `badgeCount`, `badgeType`, `badgeSize`, etc.
|
|
155
188
|
*
|
|
@@ -195,6 +228,8 @@ export class ObcTabItem extends LitElement {
|
|
|
195
228
|
@property({type: Boolean}) disabled = false;
|
|
196
229
|
|
|
197
230
|
/**
|
|
231
|
+
* @deprecated Use the `badges` array instead.
|
|
232
|
+
*
|
|
198
233
|
* Type of badge to display (e.g., 'regular', 'alarm', 'warning', etc.).
|
|
199
234
|
* See `BadgeType` enum for available options.
|
|
200
235
|
*
|
|
@@ -204,6 +239,8 @@ export class ObcTabItem extends LitElement {
|
|
|
204
239
|
@property({type: String}) badgeType: string = BadgeType.regular;
|
|
205
240
|
|
|
206
241
|
/**
|
|
242
|
+
* @deprecated Use the `badges` array instead.
|
|
243
|
+
*
|
|
207
244
|
* Size of the badge ('regular' or 'large').
|
|
208
245
|
* See `BadgeSize` enum for available options.
|
|
209
246
|
*
|
|
@@ -213,6 +250,8 @@ export class ObcTabItem extends LitElement {
|
|
|
213
250
|
@property({type: String}) badgeSize: string = BadgeSize.regular;
|
|
214
251
|
|
|
215
252
|
/**
|
|
253
|
+
* @deprecated Use the `badges` array instead.
|
|
254
|
+
*
|
|
216
255
|
* Shows the badge's numeric value. When false, only the badge background is rendered (for status-only badges).
|
|
217
256
|
*
|
|
218
257
|
* Default: true
|
|
@@ -221,6 +260,8 @@ export class ObcTabItem extends LitElement {
|
|
|
221
260
|
@property({type: Boolean, attribute: false}) badgeShowNumber: boolean = true;
|
|
222
261
|
|
|
223
262
|
/**
|
|
263
|
+
* @deprecated Use the `badges` array instead.
|
|
264
|
+
*
|
|
224
265
|
* The numeric value to display in the badge (e.g., count of notifications).
|
|
225
266
|
*
|
|
226
267
|
* Default: 0
|
|
@@ -229,6 +270,8 @@ export class ObcTabItem extends LitElement {
|
|
|
229
270
|
@property({type: Number}) badgeCount = 0;
|
|
230
271
|
|
|
231
272
|
/**
|
|
273
|
+
* @deprecated Use the `badges` array instead.
|
|
274
|
+
*
|
|
232
275
|
* Shows an icon inside the badge.
|
|
233
276
|
* Supply icon content via the `badge-icon` slot.
|
|
234
277
|
*
|
|
@@ -267,7 +310,44 @@ export class ObcTabItem extends LitElement {
|
|
|
267
310
|
}
|
|
268
311
|
}
|
|
269
312
|
|
|
313
|
+
private get effectiveBadges(): TabItemBadge[] {
|
|
314
|
+
if (this.badges.length > 0) {
|
|
315
|
+
return this.badges;
|
|
316
|
+
}
|
|
317
|
+
if (!this.hasBadge) {
|
|
318
|
+
return [];
|
|
319
|
+
}
|
|
320
|
+
return [
|
|
321
|
+
{
|
|
322
|
+
type: (this.badgeType as BadgeType) || BadgeType.regular,
|
|
323
|
+
size: (this.badgeSize as BadgeSize) || BadgeSize.regular,
|
|
324
|
+
count: this.badgeShowNumber ? this.badgeCount : undefined,
|
|
325
|
+
showIcon: this.showLeadingBadgeIcon,
|
|
326
|
+
iconSlotName: this.showLeadingBadgeIcon ? 'badge-icon' : undefined,
|
|
327
|
+
},
|
|
328
|
+
];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private renderBadge(badge: TabItemBadge) {
|
|
332
|
+
return html`
|
|
333
|
+
<obc-badge
|
|
334
|
+
class="badge"
|
|
335
|
+
.number=${badge.count ?? 0}
|
|
336
|
+
.type=${badge.type || BadgeType.regular}
|
|
337
|
+
.size=${badge.size || BadgeSize.regular}
|
|
338
|
+
.showNumber=${badge.count !== undefined}
|
|
339
|
+
.showIcon=${badge.showIcon ?? false}
|
|
340
|
+
>
|
|
341
|
+
${badge.iconSlotName
|
|
342
|
+
? html`<slot name=${badge.iconSlotName} slot="badge-icon"></slot>`
|
|
343
|
+
: nothing}
|
|
344
|
+
</obc-badge>
|
|
345
|
+
`;
|
|
346
|
+
}
|
|
347
|
+
|
|
270
348
|
override render() {
|
|
349
|
+
const badges = this.effectiveBadges;
|
|
350
|
+
const hasBadge = badges.length > 0;
|
|
271
351
|
const wrapperClasses = {
|
|
272
352
|
wrapper: true,
|
|
273
353
|
hug: this.hug,
|
|
@@ -275,7 +355,7 @@ export class ObcTabItem extends LitElement {
|
|
|
275
355
|
'has-leading-icon': this.hasLeadingIcon,
|
|
276
356
|
'has-title': this.hasTitle,
|
|
277
357
|
'has-divider': this.hasDivider && !this.checked,
|
|
278
|
-
'has-badge':
|
|
358
|
+
'has-badge': hasBadge,
|
|
279
359
|
'has-subtitle': this.showSubtitle,
|
|
280
360
|
disabled: this.disabled,
|
|
281
361
|
'center-content': this.centerContent,
|
|
@@ -309,38 +389,16 @@ export class ObcTabItem extends LitElement {
|
|
|
309
389
|
</div>
|
|
310
390
|
`
|
|
311
391
|
: nothing}
|
|
312
|
-
${this.centerContent &&
|
|
313
|
-
? html
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
.number=${this.badgeCount}
|
|
317
|
-
.type=${this.badgeType || BadgeType.regular}
|
|
318
|
-
.size=${this.badgeSize || BadgeSize.regular}
|
|
319
|
-
.showNumber=${this.badgeShowNumber}
|
|
320
|
-
.showIcon=${this.showLeadingBadgeIcon}
|
|
321
|
-
>
|
|
322
|
-
${this.showLeadingBadgeIcon
|
|
323
|
-
? html`<slot name="badge-icon" slot="badge-icon"></slot>`
|
|
324
|
-
: nothing}
|
|
325
|
-
</obc-badge>
|
|
326
|
-
`
|
|
392
|
+
${this.centerContent && hasBadge
|
|
393
|
+
? html`<div class="badges">
|
|
394
|
+
${badges.map((badge) => this.renderBadge(badge))}
|
|
395
|
+
</div>`
|
|
327
396
|
: nothing}
|
|
328
397
|
</div>
|
|
329
|
-
${!this.centerContent &&
|
|
330
|
-
? html
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
.number=${this.badgeCount}
|
|
334
|
-
.type=${this.badgeType || BadgeType.regular}
|
|
335
|
-
.size=${this.badgeSize || BadgeSize.regular}
|
|
336
|
-
.showNumber=${this.badgeShowNumber}
|
|
337
|
-
.showIcon=${this.showLeadingBadgeIcon}
|
|
338
|
-
>
|
|
339
|
-
${this.showLeadingBadgeIcon
|
|
340
|
-
? html`<slot name="badge-icon" slot="badge-icon"></slot>`
|
|
341
|
-
: nothing}
|
|
342
|
-
</obc-badge>
|
|
343
|
-
`
|
|
398
|
+
${!this.centerContent && hasBadge
|
|
399
|
+
? html`<div class="badges">
|
|
400
|
+
${badges.map((badge) => this.renderBadge(badge))}
|
|
401
|
+
</div>`
|
|
344
402
|
: nothing}
|
|
345
403
|
${this.hasClose
|
|
346
404
|
? html`
|
|
@@ -41,6 +41,7 @@ interface TabRowStoryArgs {
|
|
|
41
41
|
hug?: boolean;
|
|
42
42
|
showSubtitle?: boolean;
|
|
43
43
|
hasAddNewTab?: boolean;
|
|
44
|
+
centerContent?: boolean;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
function InteractiveTabRow(args: TabRowStoryArgs) {
|
|
@@ -58,6 +59,7 @@ function InteractiveTabRow(args: TabRowStoryArgs) {
|
|
|
58
59
|
tabRow.hug = args.hug ?? false;
|
|
59
60
|
tabRow.showSubtitle = args.showSubtitle ?? false;
|
|
60
61
|
tabRow.hasAddNewTab = args.hasAddNewTab ?? true;
|
|
62
|
+
tabRow.centerContent = args.centerContent ?? false;
|
|
61
63
|
|
|
62
64
|
tabRow.addEventListener('tab-selected', (e: Event) => {
|
|
63
65
|
const detail = (e as CustomEvent<{id: string}>).detail;
|
|
@@ -109,6 +111,18 @@ export const HugMode: Story = {
|
|
|
109
111
|
render: InteractiveTabRow,
|
|
110
112
|
};
|
|
111
113
|
|
|
114
|
+
export const CenterContent: Story = {
|
|
115
|
+
args: {
|
|
116
|
+
tabs: defaultTabs,
|
|
117
|
+
hug: false,
|
|
118
|
+
hasClose: true,
|
|
119
|
+
hasAddNewTab: true,
|
|
120
|
+
selectedTabId: 'tab2',
|
|
121
|
+
centerContent: true,
|
|
122
|
+
},
|
|
123
|
+
render: InteractiveTabRow,
|
|
124
|
+
};
|
|
125
|
+
|
|
112
126
|
export const NoClose: Story = {
|
|
113
127
|
args: {
|
|
114
128
|
tabs: defaultTabs,
|
|
@@ -148,24 +162,20 @@ export const WithBadges: Story = {
|
|
|
148
162
|
{
|
|
149
163
|
id: 'tab1',
|
|
150
164
|
title: 'Inbox',
|
|
151
|
-
|
|
152
|
-
badgeCount: 12,
|
|
153
|
-
badgeType: BadgeType.notification,
|
|
165
|
+
badges: [{type: BadgeType.warning, size: BadgeSize.regular, count: 12}],
|
|
154
166
|
},
|
|
155
167
|
{
|
|
156
168
|
id: 'tab2',
|
|
157
169
|
title: 'Notifications',
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
170
|
+
badges: [
|
|
171
|
+
{type: BadgeType.alarm, size: BadgeSize.regular, count: 3},
|
|
172
|
+
{type: BadgeType.warning, size: BadgeSize.regular, count: 7},
|
|
173
|
+
],
|
|
161
174
|
},
|
|
162
175
|
{
|
|
163
176
|
id: 'tab3',
|
|
164
177
|
title: 'Updates',
|
|
165
|
-
|
|
166
|
-
badgeCount: 99,
|
|
167
|
-
badgeType: BadgeType.enhance,
|
|
168
|
-
badgeSize: BadgeSize.large,
|
|
178
|
+
badges: [{type: BadgeType.caution, size: BadgeSize.regular, count: 99}],
|
|
169
179
|
},
|
|
170
180
|
{id: 'tab4', title: 'Messages'},
|
|
171
181
|
],
|
|
@@ -3,6 +3,7 @@ import {property} from 'lit/decorators.js';
|
|
|
3
3
|
import {repeat} from 'lit/directives/repeat.js';
|
|
4
4
|
import compentStyle from './tab-row.css?inline';
|
|
5
5
|
import '../tab-item/tab-item.js';
|
|
6
|
+
import type {TabItemBadge} from '../tab-item/tab-item.js';
|
|
6
7
|
import '../icon-button/icon-button.js';
|
|
7
8
|
import '../../icons/icon-placeholder.js';
|
|
8
9
|
import {customElement} from '../../decorator.js';
|
|
@@ -15,11 +16,22 @@ export interface TabData {
|
|
|
15
16
|
subtitle?: string;
|
|
16
17
|
showSubtitle?: boolean;
|
|
17
18
|
hasLeadingIcon?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* One or more badges to display on the tab. When non-empty this takes
|
|
21
|
+
* precedence over the deprecated single-badge fields below.
|
|
22
|
+
*/
|
|
23
|
+
badges?: TabItemBadge[];
|
|
24
|
+
/** @deprecated Use `badges` instead. */
|
|
18
25
|
hasBadge?: boolean;
|
|
26
|
+
/** @deprecated Use `badges` instead. */
|
|
19
27
|
badgeCount?: number;
|
|
28
|
+
/** @deprecated Use `badges` instead. */
|
|
20
29
|
badgeType?: BadgeType;
|
|
30
|
+
/** @deprecated Use `badges` instead. */
|
|
21
31
|
badgeSize?: BadgeSize;
|
|
32
|
+
/** @deprecated Use `badges` instead. */
|
|
22
33
|
badgeShowNumber?: boolean;
|
|
34
|
+
/** @deprecated Use `badges` instead. */
|
|
23
35
|
showLeadingBadgeIcon?: boolean;
|
|
24
36
|
disabled?: boolean;
|
|
25
37
|
}
|
|
@@ -80,8 +92,8 @@ export interface TabData {
|
|
|
80
92
|
*
|
|
81
93
|
* | Slot Name | Renders When... | Purpose |
|
|
82
94
|
* |--------------------------|------------------------------------|------------------------------------------------------|
|
|
83
|
-
* | `tab-<id>-icon`
|
|
84
|
-
* | `tab-<id
|
|
95
|
+
* | `tab-<id>-icon` | If `hasLeadingIcon` is true | Leading icon for a specific tab (replaceable) |
|
|
96
|
+
* | `tab-<id>-<iconSlotName>` | For each badge that declares an `iconSlotName` | Custom icon for a specific tab's badge (replaceable). The deprecated single-badge path uses `tab-<id>-badge-icon`. |
|
|
85
97
|
*
|
|
86
98
|
* ---
|
|
87
99
|
*
|
|
@@ -100,7 +112,7 @@ export interface TabData {
|
|
|
100
112
|
* - If using custom icons, provide them via the appropriate named slot for each tab.
|
|
101
113
|
*
|
|
102
114
|
* @slot tab-<id>-icon - Leading icon slot for each tab (shown when `hasLeadingIcon` is true for that tab)
|
|
103
|
-
* @slot tab-<id
|
|
115
|
+
* @slot tab-<id>-<iconSlotName> - Custom badge icon slot for each tab, one per badge that declares an `iconSlotName`. The deprecated single-badge path uses `tab-<id>-badge-icon`.
|
|
104
116
|
* @fires tab-selected {CustomEvent<{tab: TabData, id: string, index: number}>} Fired when a tab is selected.
|
|
105
117
|
* @fires tab-closed {CustomEvent<{tab: TabData, id: string, index: number}>} Fired when a tab's close button is clicked.
|
|
106
118
|
* @fires add-new-tab {CustomEvent<void>} Fired when the "add new tab" button is clicked.
|
|
@@ -115,12 +127,13 @@ export class ObcTabRow extends LitElement {
|
|
|
115
127
|
* - `subtitle` (string): Contextual text shown below the title when subtitle display is enabled.
|
|
116
128
|
* - `showSubtitle` (boolean): Optional per-tab override for displaying the subtitle.
|
|
117
129
|
* - `hasLeadingIcon` (boolean): Whether to show a leading icon (default: true).
|
|
118
|
-
* - `
|
|
119
|
-
* - `
|
|
120
|
-
* - `
|
|
121
|
-
* - `
|
|
122
|
-
* - `
|
|
123
|
-
* - `
|
|
130
|
+
* - `badges` (TabItemBadge[]): One or more badges to display on the tab. Takes precedence over the deprecated single-badge fields below.
|
|
131
|
+
* - `hasBadge` (boolean, deprecated): Whether to show a badge on the tab.
|
|
132
|
+
* - `badgeCount` (number, deprecated): Number to display in the badge.
|
|
133
|
+
* - `badgeType` (BadgeType, deprecated): Visual style of the badge (e.g., notification, alarm, enhance).
|
|
134
|
+
* - `badgeSize` (BadgeSize, deprecated): Size of the badge (e.g., regular, large).
|
|
135
|
+
* - `badgeShowNumber` (boolean, deprecated): If true, shows the badge number.
|
|
136
|
+
* - `showLeadingBadgeIcon` (boolean, deprecated): If true, shows a badge icon.
|
|
124
137
|
* - `disabled` (boolean): If true, disables the tab.
|
|
125
138
|
*/
|
|
126
139
|
@property({type: Array}) tabs: TabData[] = [];
|
|
@@ -139,6 +152,8 @@ export class ObcTabRow extends LitElement {
|
|
|
139
152
|
*/
|
|
140
153
|
@property({type: Boolean, attribute: 'has-close'}) hasClose = false;
|
|
141
154
|
|
|
155
|
+
@property({type: Boolean}) centerContent = false;
|
|
156
|
+
|
|
142
157
|
/**
|
|
143
158
|
* Enables "hug" mode for a more compact tab layout with reduced padding.
|
|
144
159
|
*
|
|
@@ -203,8 +218,27 @@ export class ObcTabRow extends LitElement {
|
|
|
203
218
|
|
|
204
219
|
private renderTab(tab: TabData, index: number) {
|
|
205
220
|
const isFirst = index === 0;
|
|
221
|
+
const previousTabSelected = this.selectedTabId === this.tabs[index - 1]?.id;
|
|
206
222
|
const isChecked = tab.id === this.selectedTabId;
|
|
207
223
|
const showSubtitle = tab.showSubtitle ?? this.showSubtitle;
|
|
224
|
+
// Forward a light-DOM slot for every distinct `iconSlotName` declared by the
|
|
225
|
+
// tab's badges (new `badges` array), plus the deprecated single badge-icon
|
|
226
|
+
// slot. obc-tab-item renders `<slot name=${iconSlotName} slot="badge-icon">`
|
|
227
|
+
// inside each badge, so obc-tab-row must project matching content into that
|
|
228
|
+
// slot. Slots are namespaced by tab id to stay unique across the row.
|
|
229
|
+
const badgeIconSlots = [
|
|
230
|
+
...new Set(
|
|
231
|
+
(tab.badges ?? [])
|
|
232
|
+
.map((badge) => badge.iconSlotName)
|
|
233
|
+
.filter((slotName): slotName is string => slotName !== undefined)
|
|
234
|
+
),
|
|
235
|
+
];
|
|
236
|
+
if (
|
|
237
|
+
(tab.showLeadingBadgeIcon ?? false) &&
|
|
238
|
+
!badgeIconSlots.includes('badge-icon')
|
|
239
|
+
) {
|
|
240
|
+
badgeIconSlots.push('badge-icon');
|
|
241
|
+
}
|
|
208
242
|
return html`
|
|
209
243
|
<obc-tab-item
|
|
210
244
|
.title=${tab.title}
|
|
@@ -214,11 +248,12 @@ export class ObcTabRow extends LitElement {
|
|
|
214
248
|
.hasClose=${this.hasClose}
|
|
215
249
|
.hasLeadingIcon=${tab.hasLeadingIcon ?? true}
|
|
216
250
|
.hasTitle=${true}
|
|
217
|
-
.hasDivider=${!isFirst}
|
|
251
|
+
.hasDivider=${!isFirst && !previousTabSelected}
|
|
218
252
|
.hug=${this.hug}
|
|
253
|
+
.centerContent=${this.centerContent}
|
|
219
254
|
.disabled=${tab.disabled || false}
|
|
220
|
-
.
|
|
221
|
-
|
|
255
|
+
.badges=${tab.badges ?? []}
|
|
256
|
+
.hasBadge=${tab.hasBadge || false}
|
|
222
257
|
.badgeCount=${tab.badgeCount || 0}
|
|
223
258
|
.badgeType=${tab.badgeType ?? BadgeType.regular}
|
|
224
259
|
.badgeSize=${tab.badgeSize ?? BadgeSize.regular}
|
|
@@ -235,13 +270,13 @@ export class ObcTabRow extends LitElement {
|
|
|
235
270
|
`
|
|
236
271
|
: ''}
|
|
237
272
|
<span slot="title">${tab.title}</span>
|
|
238
|
-
${
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
273
|
+
${badgeIconSlots.map(
|
|
274
|
+
(slotName) => html`
|
|
275
|
+
<slot name="tab-${tab.id}-${slotName}" slot=${slotName}>
|
|
276
|
+
<obi-placeholder></obi-placeholder>
|
|
277
|
+
</slot>
|
|
278
|
+
`
|
|
279
|
+
)}
|
|
245
280
|
</obc-tab-item>
|
|
246
281
|
`;
|
|
247
282
|
}
|