@oicl/openbridge-webcomponents 2.0.0-next.87 → 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.
- package/bundle/openbridge-webcomponents.bundle.js +17409 -16824
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +755 -44
- package/dist/building-blocks/readout-block/readout-block.css.js +229 -0
- package/dist/building-blocks/readout-block/readout-block.css.js.map +1 -0
- package/dist/building-blocks/readout-block/readout-block.d.ts +146 -0
- package/dist/building-blocks/readout-block/readout-block.d.ts.map +1 -0
- package/dist/building-blocks/readout-block/readout-block.js +273 -0
- package/dist/building-blocks/readout-block/readout-block.js.map +1 -0
- package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js +58 -32
- package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js.map +1 -1
- package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts +28 -0
- package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts.map +1 -1
- package/dist/navigation-instruments/gauge-radial/gauge-radial.js +25 -2
- package/dist/navigation-instruments/gauge-radial/gauge-radial.js.map +1 -1
- package/dist/navigation-instruments/readout-list/readout-list.css.js +24 -0
- package/dist/navigation-instruments/readout-list/readout-list.css.js.map +1 -0
- package/dist/navigation-instruments/readout-list/readout-list.d.ts +70 -0
- package/dist/navigation-instruments/readout-list/readout-list.d.ts.map +1 -0
- package/dist/navigation-instruments/readout-list/readout-list.js +154 -0
- package/dist/navigation-instruments/readout-list/readout-list.js.map +1 -0
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +80 -145
- 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 +25 -26
- 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 +66 -118
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
- 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":"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"}
|
|
@@ -9,48 +9,74 @@ const componentStyle = css`* {
|
|
|
9
9
|
height: 100%;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
.gauge-radial-root {
|
|
13
|
+
/* Readout vertical placement per layout (% of the cropped box), tuned to the
|
|
14
|
+
watch geometry — re-check if the ring radii or the 448 box change. Which
|
|
15
|
+
layout uses which is in renderReadouts(). */
|
|
16
|
+
--readout-meta-top: 72%;
|
|
17
|
+
--readout-meta-top-needle: 63%;
|
|
18
|
+
--readout-meta-top-180: 60%;
|
|
19
|
+
|
|
20
|
+
position: relative;
|
|
21
|
+
|
|
22
|
+
/* The dial is the largest box of its sector's aspect ratio that fits inside
|
|
23
|
+
*both* the available width and height of the (full-size) host. \`width: auto\`
|
|
24
|
+
stretches the block to the host width, then \`aspect-ratio\` + \`max-height\`
|
|
25
|
+
transfer the constraint back, shrinking it to fit a short host too — see
|
|
26
|
+
issue #992. The host always fills its container, so the gauge can be
|
|
27
|
+
positioned within the leftover space via the alignment classes below. */
|
|
24
28
|
width: auto;
|
|
25
29
|
height: auto;
|
|
26
30
|
max-width: 100%;
|
|
27
31
|
max-height: 100%;
|
|
28
32
|
aspect-ratio: 1;
|
|
33
|
+
|
|
34
|
+
/* Defaults (centered both ways); overridden by the halign-* / valign-*
|
|
35
|
+
classes. Horizontal alignment uses auto margins (which reference the host
|
|
36
|
+
width); vertical alignment uses a relative \`top\` offset (which references
|
|
37
|
+
the definite host height) plus a self-sized \`translateY\`. */
|
|
38
|
+
margin-left: auto;
|
|
39
|
+
margin-right: auto;
|
|
40
|
+
top: 50%;
|
|
41
|
+
transform: translateY(-50%);
|
|
42
|
+
|
|
43
|
+
/* 448 / 251 = the 180° crop's aspect (448 wide × 448·(1 − 44%) tall); keep in
|
|
44
|
+
sync with \`sectorClips\` bottom=44 in gauge-radial.ts. */
|
|
29
45
|
}
|
|
30
46
|
|
|
31
|
-
|
|
32
|
-
|
|
47
|
+
.gauge-radial-root.sector-180 {
|
|
48
|
+
aspect-ratio: 448 / 251;
|
|
49
|
+
}
|
|
33
50
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
max-height: 100%;
|
|
39
|
-
aspect-ratio: 448 / 251;
|
|
40
|
-
}
|
|
51
|
+
.gauge-radial-root.halign-left {
|
|
52
|
+
margin-left: 0;
|
|
53
|
+
margin-right: auto;
|
|
54
|
+
}
|
|
41
55
|
|
|
42
|
-
.gauge-radial-root {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
--readout-meta-top: 72%;
|
|
47
|
-
--readout-meta-top-needle: 63%;
|
|
48
|
-
--readout-meta-top-180: 60%;
|
|
56
|
+
.gauge-radial-root.halign-center {
|
|
57
|
+
margin-left: auto;
|
|
58
|
+
margin-right: auto;
|
|
59
|
+
}
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
61
|
+
.gauge-radial-root.halign-right {
|
|
62
|
+
margin-left: auto;
|
|
63
|
+
margin-right: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.gauge-radial-root.valign-top {
|
|
67
|
+
top: 0;
|
|
68
|
+
transform: translateY(0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.gauge-radial-root.valign-center {
|
|
72
|
+
top: 50%;
|
|
73
|
+
transform: translateY(-50%);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.gauge-radial-root.valign-bottom {
|
|
77
|
+
top: 100%;
|
|
78
|
+
transform: translateY(-100%);
|
|
79
|
+
}
|
|
54
80
|
|
|
55
81
|
.gauge-radial-root .gauge-readout-value {
|
|
56
82
|
position: absolute;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gauge-radial.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gauge-radial.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -14,6 +14,16 @@ export declare enum GaugeRadialSector {
|
|
|
14
14
|
deg90Left = "90-left",
|
|
15
15
|
deg90Right = "90-right"
|
|
16
16
|
}
|
|
17
|
+
export declare enum GaugeRadialHorizontalAlignment {
|
|
18
|
+
left = "left",
|
|
19
|
+
center = "center",
|
|
20
|
+
right = "right"
|
|
21
|
+
}
|
|
22
|
+
export declare enum GaugeRadialVerticalAlignment {
|
|
23
|
+
top = "top",
|
|
24
|
+
center = "center",
|
|
25
|
+
bottom = "bottom"
|
|
26
|
+
}
|
|
17
27
|
export interface GaugeRadialAdvice {
|
|
18
28
|
minValue: number;
|
|
19
29
|
maxValue: number;
|
|
@@ -46,6 +56,12 @@ declare const ObcGaugeRadial_base: (new (...args: any[]) => import('../../svghel
|
|
|
46
56
|
* - **Advice zones**: Pass an array of {@link GaugeRadialAdvice} objects to
|
|
47
57
|
* render caution/alert arcs on the gauge. Not shown on the `90-left` /
|
|
48
58
|
* `90-right` sectors.
|
|
59
|
+
* - **Alignment**: The host always fills its container and the dial shrinks to
|
|
60
|
+
* fit the smaller of the available width/height, so a short, wide (or tall,
|
|
61
|
+
* narrow) container leaves slack on one axis. `horizontalAlignment`
|
|
62
|
+
* (`left` | `center` | `right`) and `verticalAlignment`
|
|
63
|
+
* (`top` | `center` | `bottom`) position the dial within that slack; both
|
|
64
|
+
* default to `center`.
|
|
49
65
|
*
|
|
50
66
|
* ## Usage Guidelines
|
|
51
67
|
*
|
|
@@ -107,6 +123,18 @@ export declare class ObcGaugeRadial extends ObcGaugeRadial_base {
|
|
|
107
123
|
/** Caution/alert arcs. Ignored on `sector: 90-left` / `90-right`. */
|
|
108
124
|
advices: GaugeRadialAdvice[];
|
|
109
125
|
sector: GaugeRadialSector;
|
|
126
|
+
/**
|
|
127
|
+
* Horizontal placement of the dial when the host is wider than the dial
|
|
128
|
+
* (e.g. a short, wide container shrinks the dial to fit the height, leaving
|
|
129
|
+
* horizontal slack). Default `center`.
|
|
130
|
+
*/
|
|
131
|
+
horizontalAlignment: GaugeRadialHorizontalAlignment;
|
|
132
|
+
/**
|
|
133
|
+
* Vertical placement of the dial when the host is taller than the dial
|
|
134
|
+
* (e.g. a tall, narrow container shrinks the dial to fit the width, leaving
|
|
135
|
+
* vertical slack). Default `center`.
|
|
136
|
+
*/
|
|
137
|
+
verticalAlignment: GaugeRadialVerticalAlignment;
|
|
110
138
|
/**
|
|
111
139
|
* When `true`, shows the centre `<obc-readout>`(s) with the current value
|
|
112
140
|
* (and optional `label`/`unit`). Layout depends on `sector` and `type`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gauge-radial.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/gauge-radial/gauge-radial.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA4B,KAAK,cAAc,EAAC,MAAM,KAAK,CAAC;AAK9E,OAAO,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AAEtD,OAAO,8DAA8D,CAAC;AACtE,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAOnD,oBAAY,kBAAkB;IAC5B,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;AAED,oBAAY,iBAAiB;IAC3B,MAAM,QAAQ;IACd,MAAM,QAAQ;IACd,SAAS,YAAY;IACrB,UAAU,aAAa;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;;AAED
|
|
1
|
+
{"version":3,"file":"gauge-radial.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/gauge-radial/gauge-radial.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA4B,KAAK,cAAc,EAAC,MAAM,KAAK,CAAC;AAK9E,OAAO,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AAEtD,OAAO,8DAA8D,CAAC;AACtE,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAOnD,oBAAY,kBAAkB;IAC5B,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;AAED,oBAAY,iBAAiB;IAC3B,MAAM,QAAQ;IACd,MAAM,QAAQ;IACd,SAAS,YAAY;IACrB,UAAU,aAAa;CACxB;AAED,oBAAY,8BAA8B;IACxC,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,KAAK,UAAU;CAChB;AAED,oBAAY,4BAA4B;IACtC,GAAG,QAAQ;IACX,MAAM,WAAW;IACjB,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,qBACa,cAAe,SAAQ,mBAAyB;IACjC,KAAK,SAAK;IACV,QAAQ,SAAO;IACf,QAAQ,SAAK;IACZ,UAAU,EAAE,OAAO,CAAS;IAC7B,uBAAuB,SAAM;IAC7B,yBAAyB,SAAM;IACzD;;;OAGG;IACuB,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAC1D;IACc,KAAK,EAAE,eAAe,CAA0B;IAChD,QAAQ,EAAE,QAAQ,CAAoB;IACtC,IAAI,EAAE,kBAAkB,CACtB;IACD,eAAe,EAAE,OAAO,CAAS;IAClC,aAAa,EAAE,aAAa,CAC9B;IACxB,qEAAqE;IAC1B,OAAO,EAAE,iBAAiB,EAAE,CAAM;IACpC,MAAM,EAAE,iBAAiB,CACvC;IAC3B;;;;OAIG;IAEH,mBAAmB,EAAE,8BAA8B,CACX;IACxC;;;;OAIG;IACuB,iBAAiB,EAAE,4BAA4B,CACnC;IACtC;;;;OAIG;IACwB,UAAU,UAAS;IACpB,KAAK,SAAM;IACX,IAAI,SAAM;IACV,cAAc,SAAK;IAE7C,OAAO,KAAK,YAAY,GAYvB;IAED;;;;;OAKG;IACH,OAAO,KAAK,WAAW,GAiBtB;IAED,OAAO,KAAK,UAAU,GAKrB;IAID,QAAQ,GAAI,GAAG,MAAM,KAAG,MAAM,CAQ5B;IAEF,oEAAoE;IACpE,OAAO,CAAC,aAAa;IA4BrB,OAAO,CAAC,cAAc;IAiDb,MAAM;IAkDf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF"}
|
|
@@ -32,6 +32,18 @@ var GaugeRadialSector = /* @__PURE__ */ ((GaugeRadialSector2) => {
|
|
|
32
32
|
GaugeRadialSector2["deg90Right"] = "90-right";
|
|
33
33
|
return GaugeRadialSector2;
|
|
34
34
|
})(GaugeRadialSector || {});
|
|
35
|
+
var GaugeRadialHorizontalAlignment = /* @__PURE__ */ ((GaugeRadialHorizontalAlignment2) => {
|
|
36
|
+
GaugeRadialHorizontalAlignment2["left"] = "left";
|
|
37
|
+
GaugeRadialHorizontalAlignment2["center"] = "center";
|
|
38
|
+
GaugeRadialHorizontalAlignment2["right"] = "right";
|
|
39
|
+
return GaugeRadialHorizontalAlignment2;
|
|
40
|
+
})(GaugeRadialHorizontalAlignment || {});
|
|
41
|
+
var GaugeRadialVerticalAlignment = /* @__PURE__ */ ((GaugeRadialVerticalAlignment2) => {
|
|
42
|
+
GaugeRadialVerticalAlignment2["top"] = "top";
|
|
43
|
+
GaugeRadialVerticalAlignment2["center"] = "center";
|
|
44
|
+
GaugeRadialVerticalAlignment2["bottom"] = "bottom";
|
|
45
|
+
return GaugeRadialVerticalAlignment2;
|
|
46
|
+
})(GaugeRadialVerticalAlignment || {});
|
|
35
47
|
let ObcGaugeRadial = class extends SetpointMixin(LitElement) {
|
|
36
48
|
constructor() {
|
|
37
49
|
super(...arguments);
|
|
@@ -49,6 +61,8 @@ let ObcGaugeRadial = class extends SetpointMixin(LitElement) {
|
|
|
49
61
|
this.tickmarkStyle = TickmarkStyle.regular;
|
|
50
62
|
this.advices = [];
|
|
51
63
|
this.sector = "270";
|
|
64
|
+
this.horizontalAlignment = "center";
|
|
65
|
+
this.verticalAlignment = "center";
|
|
52
66
|
this.hasReadout = false;
|
|
53
67
|
this.label = "";
|
|
54
68
|
this.unit = "";
|
|
@@ -164,8 +178,9 @@ let ObcGaugeRadial = class extends SetpointMixin(LitElement) {
|
|
|
164
178
|
"type-needle": this.type === "needle",
|
|
165
179
|
"sector-180": this.sector === "180",
|
|
166
180
|
"sector-90-left": this.sector === "90-left",
|
|
167
|
-
"sector-90-right": this.sector === "90-right"
|
|
168
|
-
|
|
181
|
+
"sector-90-right": this.sector === "90-right",
|
|
182
|
+
[`halign-${this.horizontalAlignment}`]: true,
|
|
183
|
+
[`valign-${this.verticalAlignment}`]: true
|
|
169
184
|
})}
|
|
170
185
|
>
|
|
171
186
|
<obc-instrument-radial
|
|
@@ -247,6 +262,12 @@ __decorateClass([
|
|
|
247
262
|
__decorateClass([
|
|
248
263
|
property({ type: String, reflect: true })
|
|
249
264
|
], ObcGaugeRadial.prototype, "sector", 2);
|
|
265
|
+
__decorateClass([
|
|
266
|
+
property({ type: String })
|
|
267
|
+
], ObcGaugeRadial.prototype, "horizontalAlignment", 2);
|
|
268
|
+
__decorateClass([
|
|
269
|
+
property({ type: String })
|
|
270
|
+
], ObcGaugeRadial.prototype, "verticalAlignment", 2);
|
|
250
271
|
__decorateClass([
|
|
251
272
|
property({ type: Boolean })
|
|
252
273
|
], ObcGaugeRadial.prototype, "hasReadout", 2);
|
|
@@ -263,7 +284,9 @@ ObcGaugeRadial = __decorateClass([
|
|
|
263
284
|
customElement("obc-gauge-radial")
|
|
264
285
|
], ObcGaugeRadial);
|
|
265
286
|
export {
|
|
287
|
+
GaugeRadialHorizontalAlignment,
|
|
266
288
|
GaugeRadialSector,
|
|
289
|
+
GaugeRadialVerticalAlignment,
|
|
267
290
|
ObcGaugeRadial,
|
|
268
291
|
ObcGaugeRadialType
|
|
269
292
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gauge-radial.js","sources":["../../../src/navigation-instruments/gauge-radial/gauge-radial.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS, type TemplateResult} from 'lit';\nimport {classMap} from 'lit/directives/class-map.js';\nimport componentStyle from './gauge-radial.css?inline';\nimport {customElement} from '../../decorator.js';\nimport {property} from 'lit/decorators.js';\nimport {AdviceType} from '../watch/advice.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport '../../building-blocks/instrument-radial/instrument-radial.js';\nimport {TickmarkStyle} from '../watch/tickmark.js';\nimport {renderInstrumentReadout} from '../readout/instrument-readout.js';\nimport {\n ReadoutStackVerticalAlignment,\n ReadoutVariant,\n} from '../readout/readout.js';\n\nexport enum ObcGaugeRadialType {\n filled = 'filled',\n bar = 'bar',\n needle = 'needle',\n}\n\nexport enum GaugeRadialSector {\n deg270 = '270',\n deg180 = '180',\n deg90Left = '90-left',\n deg90Right = '90-right',\n}\n\nexport interface GaugeRadialAdvice {\n minValue: number;\n maxValue: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-gauge-radial>` — Configurable radial gauge for generic numeric values.\n *\n * `ObcGaugeRadial` is a thin wrapper around `<obc-instrument-radial>` that adds\n * domain-independent value-to-angle mapping with automatic range handling for\n * both positive-only and bipolar (negative-to-positive) scales. It inherits a\n * full setpoint property bundle from {@link SetpointMixin}, including\n * auto at-setpoint detection, dual-marker adjustment preview, and deadband\n * tuning — no manual wiring required.\n *\n * ## Features\n *\n * - **Three display types**: `filled` (solid arc), `bar` (thinner arc), and\n * `needle` (pointer indicator) via the `type` property.\n * - **Sector sweep**: `sector` selects the arc span (`270`, `180`, `90-left`, or `90-right`).\n * The configured `minValue..maxValue` always spans the full sector. For the\n * centered sectors (`270`, `180`) a symmetric range places `0` at 12 o'clock;\n * for `90-left`/`90-right` the range midpoint sits at the middle of the quadrant.\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin` and forwarded to the inner\n * `<obc-instrument-radial>`.\n * - **Advice zones**: Pass an array of {@link GaugeRadialAdvice} objects to\n * render caution/alert arcs on the gauge. Not shown on the `90-left` /\n * `90-right` sectors.\n *\n * ## Usage Guidelines\n *\n * - Set `minValue` / `maxValue` to define the scale range.\n * - Use `priority` to switch between regular and enhanced color palettes.\n * - Provide `primaryTickmarkInterval` and `secondaryTickmarkInterval` to\n * control tickmark density.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\n * - Enable `hasReadout` with optional `label` and `unit`. Layout depends on `sector`\n * and `type`: **270** filled/bar — value at center + a label-only `meta` row in\n * the bottom gap (two separate readouts); **180** filled/bar — a single centered\n * stack (value + label/unit) at the bottom; **270** needle — bottom stack;\n * **180** needle — no readout; **90-left** / **90-right** filled/bar — corner\n * readout in a square host; **90** needle — no readout.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - Keep domain-specific logic (units, formatting) in the parent view; this\n * component is intentionally unit-agnostic.\n *\n * ## Example\n *\n * ```html\n * <obc-gauge-radial\n * value=\"42\"\n * minValue=\"0\"\n * maxValue=\"100\"\n * type=\"filled\"\n * priority=\"enhanced\"\n * showLabels\n * primaryTickmarkInterval=\"25\"\n * secondaryTickmarkInterval=\"5\"\n * setpoint=\"60\"\n * ></obc-gauge-radial>\n * ```\n *\n * @element obc-gauge-radial\n * @typedef {import('./gauge-radial.js').GaugeRadialAdvice} GaugeRadialAdvice\n */\n@customElement('obc-gauge-radial')\nexport class ObcGaugeRadial extends SetpointMixin(LitElement) {\n @property({type: Number}) value = 0;\n @property({type: Number}) maxValue = 100;\n @property({type: Number}) minValue = 0;\n @property({type: Boolean}) showLabels: boolean = false;\n @property({type: Number}) primaryTickmarkInterval = 50;\n @property({type: Number}) secondaryTickmarkInterval = 10;\n /**\n * Interval for tertiary tickmarks in value units.\n * When undefined or <= 0, no tertiary tickmarks are shown.\n */\n @property({type: Number}) tertiaryTickmarkInterval: number | undefined =\n undefined;\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) type: ObcGaugeRadialType =\n ObcGaugeRadialType.filled;\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n /** Caution/alert arcs. Ignored on `sector: 90-left` / `90-right`. */\n @property({type: Array, attribute: false}) advices: GaugeRadialAdvice[] = [];\n @property({type: String, reflect: true}) sector: GaugeRadialSector =\n GaugeRadialSector.deg270;\n /**\n * When `true`, shows the centre `<obc-readout>`(s) with the current value\n * (and optional `label`/`unit`). Layout depends on `sector` and `type`.\n * Default `false`.\n */\n @property({type: Boolean}) hasReadout = false;\n @property({type: String}) label = '';\n @property({type: String}) unit = '';\n @property({type: Number}) fractionDigits = 0;\n\n private get sectorAngles(): {sweep: number; start: number} {\n switch (this.sector) {\n case GaugeRadialSector.deg180:\n return {sweep: 180, start: -90};\n case GaugeRadialSector.deg90Left:\n return {sweep: 90, start: -90};\n case GaugeRadialSector.deg90Right:\n return {sweep: 90, start: 0};\n case GaugeRadialSector.deg270:\n default:\n return {sweep: 270, start: -135};\n }\n }\n\n /**\n * Per-edge crop (%) of the shared, origin-centered 448 SVG box each sector\n * shows. All sectors render at the same natural scale, so the dial stays the\n * same size; the sector only windows a different part (270 whole, 180 wide,\n * 90 a quadrant).\n */\n private get sectorClips(): {\n top: number;\n bottom: number;\n left: number;\n right: number;\n } {\n switch (this.sector) {\n case GaugeRadialSector.deg180:\n return {top: 0, bottom: 44, left: 0, right: 0};\n case GaugeRadialSector.deg90Left:\n return {top: 0, bottom: 45, left: 0, right: 45};\n case GaugeRadialSector.deg90Right:\n return {top: 0, bottom: 45, left: 45, right: 0};\n case GaugeRadialSector.deg270:\n default:\n return {top: 0, bottom: 0, left: 0, right: 0};\n }\n }\n\n private get isSector90(): boolean {\n return (\n this.sector === GaugeRadialSector.deg90Left ||\n this.sector === GaugeRadialSector.deg90Right\n );\n }\n\n // Arrow form so `this` binds when passed as `.getAngle=${this.getAngle}`\n // to <obc-instrument-radial>. Do not convert to a method.\n getAngle = (v: number): number => {\n const {sweep, start} = this.sectorAngles;\n const span = this.maxValue - this.minValue;\n if (!Number.isFinite(span) || span <= 0) {\n return start;\n }\n\n return ((v - this.minValue) / span) * sweep + start;\n };\n\n /** Renders one gauge readout; `withMeta`/`labelOnly` pick parts. */\n private renderReadout({\n className,\n variant,\n alignment = ReadoutStackVerticalAlignment.vertical,\n withMeta = true,\n labelOnly = false,\n }: {\n className: string;\n variant: ReadoutVariant;\n alignment?: ReadoutStackVerticalAlignment;\n withMeta?: boolean;\n labelOnly?: boolean;\n }): TemplateResult {\n // `labelOnly` already means \"no value\", so derive it instead of passing both.\n const withValue = !labelOnly;\n return renderInstrumentReadout({\n className,\n variant,\n alignment,\n labelOnly,\n value: withValue ? this.value : undefined,\n valuePriority: withValue ? this.priority : undefined,\n fractionDigits: this.fractionDigits,\n label: withMeta ? this.label : '',\n unit: withMeta ? this.unit : '',\n });\n }\n\n private renderReadouts() {\n if (!this.hasReadout) {\n return nothing;\n }\n\n const isNeedle = this.type === ObcGaugeRadialType.needle;\n const is90 = this.isSector90;\n const is180 = this.sector === GaugeRadialSector.deg180;\n\n if (isNeedle && (is180 || is90)) {\n return nothing;\n }\n\n // 90 filled/bar: enhanced corner readout (bold value + label/unit).\n if (is90) {\n return this.renderReadout({\n className: 'gauge-readout-meta',\n variant: ReadoutVariant.enhanced,\n });\n }\n\n // 270 needle and 180 filled/bar: centered stack (value weight follows `priority`).\n if (isNeedle || is180) {\n return this.renderReadout({\n className: 'gauge-readout-meta',\n variant: ReadoutVariant.stack,\n alignment: ReadoutStackVerticalAlignment.center,\n });\n }\n\n // 270 filled/bar: the value sits at the circle center and the label/unit row\n // lower in the bottom gap, so they are two separately-positioned readouts.\n return html`\n ${this.renderReadout({\n className: 'gauge-readout-value',\n variant: ReadoutVariant.enhanced,\n withMeta: false,\n })}\n ${this.label || this.unit\n ? this.renderReadout({\n className: 'gauge-readout-meta',\n variant: ReadoutVariant.stack,\n alignment: ReadoutStackVerticalAlignment.center,\n labelOnly: true,\n })\n : nothing}\n `;\n }\n\n override render() {\n const clips = this.sectorClips;\n return html`\n <div\n class=${classMap({\n 'gauge-radial-root': true,\n 'type-needle': this.type === ObcGaugeRadialType.needle,\n 'sector-180': this.sector === GaugeRadialSector.deg180,\n 'sector-90-left': this.sector === GaugeRadialSector.deg90Left,\n 'sector-90-right': this.sector === GaugeRadialSector.deg90Right,\n })}\n >\n <obc-instrument-radial\n .value=${this.value}\n .state=${this.state}\n .priority=${this.priority}\n .setpoint=${this.setpoint}\n .newSetpoint=${this.newSetpoint}\n .setpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .touching=${this.touching}\n .autoAtSetpoint=${this.autoAtSetpoint}\n .autoAtSetpointDeadband=${this.autoAtSetpointDeadband}\n .animateSetpoint=${this.animateSetpoint}\n .maxValue=${this.maxValue}\n .minValue=${this.minValue}\n .getAngle=${this.getAngle}\n .showLabels=${this.showLabels}\n .primaryTickmarkInterval=${this.primaryTickmarkInterval}\n .secondaryTickmarkInterval=${this.secondaryTickmarkInterval}\n .tertiaryTickmarkInterval=${this.tertiaryTickmarkInterval}\n .type=${this.type}\n .needleType=${this.type}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .advices=${this.isSector90 ? [] : this.advices}\n .clipTop=${clips.top}\n .clipBottom=${clips.bottom}\n .clipLeft=${clips.left}\n .clipRight=${clips.right}\n .endLabelsMaxMin=${this.sector === GaugeRadialSector.deg180}\n >\n </obc-instrument-radial>\n ${this.renderReadouts()}\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-gauge-radial': ObcGaugeRadial;\n }\n}\n"],"names":["ObcGaugeRadialType","GaugeRadialSector"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gauge-radial.js","sources":["../../../src/navigation-instruments/gauge-radial/gauge-radial.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS, type TemplateResult} from 'lit';\nimport {classMap} from 'lit/directives/class-map.js';\nimport componentStyle from './gauge-radial.css?inline';\nimport {customElement} from '../../decorator.js';\nimport {property} from 'lit/decorators.js';\nimport {AdviceType} from '../watch/advice.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport '../../building-blocks/instrument-radial/instrument-radial.js';\nimport {TickmarkStyle} from '../watch/tickmark.js';\nimport {renderInstrumentReadout} from '../readout/instrument-readout.js';\nimport {\n ReadoutStackVerticalAlignment,\n ReadoutVariant,\n} from '../readout/readout.js';\n\nexport enum ObcGaugeRadialType {\n filled = 'filled',\n bar = 'bar',\n needle = 'needle',\n}\n\nexport enum GaugeRadialSector {\n deg270 = '270',\n deg180 = '180',\n deg90Left = '90-left',\n deg90Right = '90-right',\n}\n\nexport enum GaugeRadialHorizontalAlignment {\n left = 'left',\n center = 'center',\n right = 'right',\n}\n\nexport enum GaugeRadialVerticalAlignment {\n top = 'top',\n center = 'center',\n bottom = 'bottom',\n}\n\nexport interface GaugeRadialAdvice {\n minValue: number;\n maxValue: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-gauge-radial>` — Configurable radial gauge for generic numeric values.\n *\n * `ObcGaugeRadial` is a thin wrapper around `<obc-instrument-radial>` that adds\n * domain-independent value-to-angle mapping with automatic range handling for\n * both positive-only and bipolar (negative-to-positive) scales. It inherits a\n * full setpoint property bundle from {@link SetpointMixin}, including\n * auto at-setpoint detection, dual-marker adjustment preview, and deadband\n * tuning — no manual wiring required.\n *\n * ## Features\n *\n * - **Three display types**: `filled` (solid arc), `bar` (thinner arc), and\n * `needle` (pointer indicator) via the `type` property.\n * - **Sector sweep**: `sector` selects the arc span (`270`, `180`, `90-left`, or `90-right`).\n * The configured `minValue..maxValue` always spans the full sector. For the\n * centered sectors (`270`, `180`) a symmetric range places `0` at 12 o'clock;\n * for `90-left`/`90-right` the range midpoint sits at the middle of the quadrant.\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin` and forwarded to the inner\n * `<obc-instrument-radial>`.\n * - **Advice zones**: Pass an array of {@link GaugeRadialAdvice} objects to\n * render caution/alert arcs on the gauge. Not shown on the `90-left` /\n * `90-right` sectors.\n * - **Alignment**: The host always fills its container and the dial shrinks to\n * fit the smaller of the available width/height, so a short, wide (or tall,\n * narrow) container leaves slack on one axis. `horizontalAlignment`\n * (`left` | `center` | `right`) and `verticalAlignment`\n * (`top` | `center` | `bottom`) position the dial within that slack; both\n * default to `center`.\n *\n * ## Usage Guidelines\n *\n * - Set `minValue` / `maxValue` to define the scale range.\n * - Use `priority` to switch between regular and enhanced color palettes.\n * - Provide `primaryTickmarkInterval` and `secondaryTickmarkInterval` to\n * control tickmark density.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\n * - Enable `hasReadout` with optional `label` and `unit`. Layout depends on `sector`\n * and `type`: **270** filled/bar — value at center + a label-only `meta` row in\n * the bottom gap (two separate readouts); **180** filled/bar — a single centered\n * stack (value + label/unit) at the bottom; **270** needle — bottom stack;\n * **180** needle — no readout; **90-left** / **90-right** filled/bar — corner\n * readout in a square host; **90** needle — no readout.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - Keep domain-specific logic (units, formatting) in the parent view; this\n * component is intentionally unit-agnostic.\n *\n * ## Example\n *\n * ```html\n * <obc-gauge-radial\n * value=\"42\"\n * minValue=\"0\"\n * maxValue=\"100\"\n * type=\"filled\"\n * priority=\"enhanced\"\n * showLabels\n * primaryTickmarkInterval=\"25\"\n * secondaryTickmarkInterval=\"5\"\n * setpoint=\"60\"\n * ></obc-gauge-radial>\n * ```\n *\n * @element obc-gauge-radial\n * @typedef {import('./gauge-radial.js').GaugeRadialAdvice} GaugeRadialAdvice\n */\n@customElement('obc-gauge-radial')\nexport class ObcGaugeRadial extends SetpointMixin(LitElement) {\n @property({type: Number}) value = 0;\n @property({type: Number}) maxValue = 100;\n @property({type: Number}) minValue = 0;\n @property({type: Boolean}) showLabels: boolean = false;\n @property({type: Number}) primaryTickmarkInterval = 50;\n @property({type: Number}) secondaryTickmarkInterval = 10;\n /**\n * Interval for tertiary tickmarks in value units.\n * When undefined or <= 0, no tertiary tickmarks are shown.\n */\n @property({type: Number}) tertiaryTickmarkInterval: number | undefined =\n undefined;\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) type: ObcGaugeRadialType =\n ObcGaugeRadialType.filled;\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n /** Caution/alert arcs. Ignored on `sector: 90-left` / `90-right`. */\n @property({type: Array, attribute: false}) advices: GaugeRadialAdvice[] = [];\n @property({type: String, reflect: true}) sector: GaugeRadialSector =\n GaugeRadialSector.deg270;\n /**\n * Horizontal placement of the dial when the host is wider than the dial\n * (e.g. a short, wide container shrinks the dial to fit the height, leaving\n * horizontal slack). Default `center`.\n */\n @property({type: String})\n horizontalAlignment: GaugeRadialHorizontalAlignment =\n GaugeRadialHorizontalAlignment.center;\n /**\n * Vertical placement of the dial when the host is taller than the dial\n * (e.g. a tall, narrow container shrinks the dial to fit the width, leaving\n * vertical slack). Default `center`.\n */\n @property({type: String}) verticalAlignment: GaugeRadialVerticalAlignment =\n GaugeRadialVerticalAlignment.center;\n /**\n * When `true`, shows the centre `<obc-readout>`(s) with the current value\n * (and optional `label`/`unit`). Layout depends on `sector` and `type`.\n * Default `false`.\n */\n @property({type: Boolean}) hasReadout = false;\n @property({type: String}) label = '';\n @property({type: String}) unit = '';\n @property({type: Number}) fractionDigits = 0;\n\n private get sectorAngles(): {sweep: number; start: number} {\n switch (this.sector) {\n case GaugeRadialSector.deg180:\n return {sweep: 180, start: -90};\n case GaugeRadialSector.deg90Left:\n return {sweep: 90, start: -90};\n case GaugeRadialSector.deg90Right:\n return {sweep: 90, start: 0};\n case GaugeRadialSector.deg270:\n default:\n return {sweep: 270, start: -135};\n }\n }\n\n /**\n * Per-edge crop (%) of the shared, origin-centered 448 SVG box each sector\n * shows. All sectors render at the same natural scale, so the dial stays the\n * same size; the sector only windows a different part (270 whole, 180 wide,\n * 90 a quadrant).\n */\n private get sectorClips(): {\n top: number;\n bottom: number;\n left: number;\n right: number;\n } {\n switch (this.sector) {\n case GaugeRadialSector.deg180:\n return {top: 0, bottom: 44, left: 0, right: 0};\n case GaugeRadialSector.deg90Left:\n return {top: 0, bottom: 45, left: 0, right: 45};\n case GaugeRadialSector.deg90Right:\n return {top: 0, bottom: 45, left: 45, right: 0};\n case GaugeRadialSector.deg270:\n default:\n return {top: 0, bottom: 0, left: 0, right: 0};\n }\n }\n\n private get isSector90(): boolean {\n return (\n this.sector === GaugeRadialSector.deg90Left ||\n this.sector === GaugeRadialSector.deg90Right\n );\n }\n\n // Arrow form so `this` binds when passed as `.getAngle=${this.getAngle}`\n // to <obc-instrument-radial>. Do not convert to a method.\n getAngle = (v: number): number => {\n const {sweep, start} = this.sectorAngles;\n const span = this.maxValue - this.minValue;\n if (!Number.isFinite(span) || span <= 0) {\n return start;\n }\n\n return ((v - this.minValue) / span) * sweep + start;\n };\n\n /** Renders one gauge readout; `withMeta`/`labelOnly` pick parts. */\n private renderReadout({\n className,\n variant,\n alignment = ReadoutStackVerticalAlignment.vertical,\n withMeta = true,\n labelOnly = false,\n }: {\n className: string;\n variant: ReadoutVariant;\n alignment?: ReadoutStackVerticalAlignment;\n withMeta?: boolean;\n labelOnly?: boolean;\n }): TemplateResult {\n // `labelOnly` already means \"no value\", so derive it instead of passing both.\n const withValue = !labelOnly;\n return renderInstrumentReadout({\n className,\n variant,\n alignment,\n labelOnly,\n value: withValue ? this.value : undefined,\n valuePriority: withValue ? this.priority : undefined,\n fractionDigits: this.fractionDigits,\n label: withMeta ? this.label : '',\n unit: withMeta ? this.unit : '',\n });\n }\n\n private renderReadouts() {\n if (!this.hasReadout) {\n return nothing;\n }\n\n const isNeedle = this.type === ObcGaugeRadialType.needle;\n const is90 = this.isSector90;\n const is180 = this.sector === GaugeRadialSector.deg180;\n\n if (isNeedle && (is180 || is90)) {\n return nothing;\n }\n\n // 90 filled/bar: enhanced corner readout (bold value + label/unit).\n if (is90) {\n return this.renderReadout({\n className: 'gauge-readout-meta',\n variant: ReadoutVariant.enhanced,\n });\n }\n\n // 270 needle and 180 filled/bar: centered stack (value weight follows `priority`).\n if (isNeedle || is180) {\n return this.renderReadout({\n className: 'gauge-readout-meta',\n variant: ReadoutVariant.stack,\n alignment: ReadoutStackVerticalAlignment.center,\n });\n }\n\n // 270 filled/bar: the value sits at the circle center and the label/unit row\n // lower in the bottom gap, so they are two separately-positioned readouts.\n return html`\n ${this.renderReadout({\n className: 'gauge-readout-value',\n variant: ReadoutVariant.enhanced,\n withMeta: false,\n })}\n ${this.label || this.unit\n ? this.renderReadout({\n className: 'gauge-readout-meta',\n variant: ReadoutVariant.stack,\n alignment: ReadoutStackVerticalAlignment.center,\n labelOnly: true,\n })\n : nothing}\n `;\n }\n\n override render() {\n const clips = this.sectorClips;\n return html`\n <div\n class=${classMap({\n 'gauge-radial-root': true,\n 'type-needle': this.type === ObcGaugeRadialType.needle,\n 'sector-180': this.sector === GaugeRadialSector.deg180,\n 'sector-90-left': this.sector === GaugeRadialSector.deg90Left,\n 'sector-90-right': this.sector === GaugeRadialSector.deg90Right,\n [`halign-${this.horizontalAlignment}`]: true,\n [`valign-${this.verticalAlignment}`]: true,\n })}\n >\n <obc-instrument-radial\n .value=${this.value}\n .state=${this.state}\n .priority=${this.priority}\n .setpoint=${this.setpoint}\n .newSetpoint=${this.newSetpoint}\n .setpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .touching=${this.touching}\n .autoAtSetpoint=${this.autoAtSetpoint}\n .autoAtSetpointDeadband=${this.autoAtSetpointDeadband}\n .animateSetpoint=${this.animateSetpoint}\n .maxValue=${this.maxValue}\n .minValue=${this.minValue}\n .getAngle=${this.getAngle}\n .showLabels=${this.showLabels}\n .primaryTickmarkInterval=${this.primaryTickmarkInterval}\n .secondaryTickmarkInterval=${this.secondaryTickmarkInterval}\n .tertiaryTickmarkInterval=${this.tertiaryTickmarkInterval}\n .type=${this.type}\n .needleType=${this.type}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .advices=${this.isSector90 ? [] : this.advices}\n .clipTop=${clips.top}\n .clipBottom=${clips.bottom}\n .clipLeft=${clips.left}\n .clipRight=${clips.right}\n .endLabelsMaxMin=${this.sector === GaugeRadialSector.deg180}\n >\n </obc-instrument-radial>\n ${this.renderReadouts()}\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-gauge-radial': ObcGaugeRadial;\n }\n}\n"],"names":["ObcGaugeRadialType","GaugeRadialSector","GaugeRadialHorizontalAlignment","GaugeRadialVerticalAlignment"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgBO,IAAK,uCAAAA,wBAAL;AACLA,sBAAA,QAAA,IAAS;AACTA,sBAAA,KAAA,IAAM;AACNA,sBAAA,QAAA,IAAS;AAHC,SAAAA;AAAA,GAAA,sBAAA,CAAA,CAAA;AAML,IAAK,sCAAAC,uBAAL;AACLA,qBAAA,QAAA,IAAS;AACTA,qBAAA,QAAA,IAAS;AACTA,qBAAA,WAAA,IAAY;AACZA,qBAAA,YAAA,IAAa;AAJH,SAAAA;AAAA,GAAA,qBAAA,CAAA,CAAA;AAOL,IAAK,mDAAAC,oCAAL;AACLA,kCAAA,MAAA,IAAO;AACPA,kCAAA,QAAA,IAAS;AACTA,kCAAA,OAAA,IAAQ;AAHE,SAAAA;AAAA,GAAA,kCAAA,CAAA,CAAA;AAML,IAAK,iDAAAC,kCAAL;AACLA,gCAAA,KAAA,IAAM;AACNA,gCAAA,QAAA,IAAS;AACTA,gCAAA,QAAA,IAAS;AAHC,SAAAA;AAAA,GAAA,gCAAA,CAAA,CAAA;AAsFL,IAAM,iBAAN,cAA6B,cAAc,UAAU,EAAE;AAAA,EAAvD,cAAA;AAAA,UAAA,GAAA,SAAA;AACqB,SAAA,QAAQ;AACR,SAAA,WAAW;AACX,SAAA,WAAW;AACV,SAAA,aAAsB;AACvB,SAAA,0BAA0B;AAC1B,SAAA,4BAA4B;AAK5B,SAAA,2BACxB;AACwB,SAAA,QAAyB,gBAAgB;AACzC,SAAA,WAAqB,SAAS;AAC9B,SAAA,OACxB;AACyB,SAAA,kBAA2B;AAC5B,SAAA,gBACxB,cAAc;AAE2B,SAAA,UAA+B,CAAA;AACjC,SAAA,SACvC;AAOF,SAAA,sBACE;AAMwB,SAAA,oBACxB;AAMyB,SAAA,aAAa;AACd,SAAA,QAAQ;AACR,SAAA,OAAO;AACP,SAAA,iBAAiB;AAkD3C,SAAA,WAAW,CAAC,MAAsB;AAChC,YAAM,EAAC,OAAO,MAAA,IAAS,KAAK;AAC5B,YAAM,OAAO,KAAK,WAAW,KAAK;AAClC,UAAI,CAAC,OAAO,SAAS,IAAI,KAAK,QAAQ,GAAG;AACvC,eAAO;AAAA,MACT;AAEA,cAAS,IAAI,KAAK,YAAY,OAAQ,QAAQ;AAAA,IAChD;AAAA,EAAA;AAAA,EAxDA,IAAY,eAA+C;AACzD,YAAQ,KAAK,QAAA;AAAA,MACX,KAAK;AACH,eAAO,EAAC,OAAO,KAAK,OAAO,IAAA;AAAA,MAC7B,KAAK;AACH,eAAO,EAAC,OAAO,IAAI,OAAO,IAAA;AAAA,MAC5B,KAAK;AACH,eAAO,EAAC,OAAO,IAAI,OAAO,EAAA;AAAA,MAC5B,KAAK;AAAA,MACL;AACE,eAAO,EAAC,OAAO,KAAK,OAAO,KAAA;AAAA,IAAI;AAAA,EAErC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAY,cAKV;AACA,YAAQ,KAAK,QAAA;AAAA,MACX,KAAK;AACH,eAAO,EAAC,KAAK,GAAG,QAAQ,IAAI,MAAM,GAAG,OAAO,EAAA;AAAA,MAC9C,KAAK;AACH,eAAO,EAAC,KAAK,GAAG,QAAQ,IAAI,MAAM,GAAG,OAAO,GAAA;AAAA,MAC9C,KAAK;AACH,eAAO,EAAC,KAAK,GAAG,QAAQ,IAAI,MAAM,IAAI,OAAO,EAAA;AAAA,MAC/C,KAAK;AAAA,MACL;AACE,eAAO,EAAC,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,EAAA;AAAA,IAAC;AAAA,EAElD;AAAA,EAEA,IAAY,aAAsB;AAChC,WACE,KAAK,WAAW,aAChB,KAAK,WAAW;AAAA,EAEpB;AAAA;AAAA,EAeQ,cAAc;AAAA,IACpB;AAAA,IACA;AAAA,IACA,YAAY,8BAA8B;AAAA,IAC1C,WAAW;AAAA,IACX,YAAY;AAAA,EAAA,GAOK;AAEjB,UAAM,YAAY,CAAC;AACnB,WAAO,wBAAwB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,YAAY,KAAK,QAAQ;AAAA,MAChC,eAAe,YAAY,KAAK,WAAW;AAAA,MAC3C,gBAAgB,KAAK;AAAA,MACrB,OAAO,WAAW,KAAK,QAAQ;AAAA,MAC/B,MAAM,WAAW,KAAK,OAAO;AAAA,IAAA,CAC9B;AAAA,EACH;AAAA,EAEQ,iBAAiB;AACvB,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,KAAK,SAAS;AAC/B,UAAM,OAAO,KAAK;AAClB,UAAM,QAAQ,KAAK,WAAW;AAE9B,QAAI,aAAa,SAAS,OAAO;AAC/B,aAAO;AAAA,IACT;AAGA,QAAI,MAAM;AACR,aAAO,KAAK,cAAc;AAAA,QACxB,WAAW;AAAA,QACX,SAAS,eAAe;AAAA,MAAA,CACzB;AAAA,IACH;AAGA,QAAI,YAAY,OAAO;AACrB,aAAO,KAAK,cAAc;AAAA,QACxB,WAAW;AAAA,QACX,SAAS,eAAe;AAAA,QACxB,WAAW,8BAA8B;AAAA,MAAA,CAC1C;AAAA,IACH;AAIA,WAAO;AAAA,QACH,KAAK,cAAc;AAAA,MACnB,WAAW;AAAA,MACX,SAAS,eAAe;AAAA,MACxB,UAAU;AAAA,IAAA,CACX,CAAC;AAAA,QACA,KAAK,SAAS,KAAK,OACjB,KAAK,cAAc;AAAA,MACjB,WAAW;AAAA,MACX,SAAS,eAAe;AAAA,MACxB,WAAW,8BAA8B;AAAA,MACzC,WAAW;AAAA,IAAA,CACZ,IACD,OAAO;AAAA;AAAA,EAEf;AAAA,EAES,SAAS;AAChB,UAAM,QAAQ,KAAK;AACnB,WAAO;AAAA;AAAA,gBAEK,SAAS;AAAA,MACf,qBAAqB;AAAA,MACrB,eAAe,KAAK,SAAS;AAAA,MAC7B,cAAc,KAAK,WAAW;AAAA,MAC9B,kBAAkB,KAAK,WAAW;AAAA,MAClC,mBAAmB,KAAK,WAAW;AAAA,MACnC,CAAC,UAAU,KAAK,mBAAmB,EAAE,GAAG;AAAA,MACxC,CAAC,UAAU,KAAK,iBAAiB,EAAE,GAAG;AAAA,IAAA,CACvC,CAAC;AAAA;AAAA;AAAA,mBAGS,KAAK,KAAK;AAAA,mBACV,KAAK,KAAK;AAAA,sBACP,KAAK,QAAQ;AAAA,sBACb,KAAK,QAAQ;AAAA,yBACV,KAAK,WAAW;AAAA,oCACL,KAAK,sBAAsB;AAAA,8BACjC,KAAK,gBAAgB;AAAA,sBAC7B,KAAK,QAAQ;AAAA,4BACP,KAAK,cAAc;AAAA,oCACX,KAAK,sBAAsB;AAAA,6BAClC,KAAK,eAAe;AAAA,sBAC3B,KAAK,QAAQ;AAAA,sBACb,KAAK,QAAQ;AAAA,sBACb,KAAK,QAAQ;AAAA,wBACX,KAAK,UAAU;AAAA,qCACF,KAAK,uBAAuB;AAAA,uCAC1B,KAAK,yBAAyB;AAAA,sCAC/B,KAAK,wBAAwB;AAAA,kBACjD,KAAK,IAAI;AAAA,wBACH,KAAK,IAAI;AAAA,6BACJ,KAAK,eAAe;AAAA,2BACtB,KAAK,aAAa;AAAA,qBACxB,KAAK,aAAa,CAAA,IAAK,KAAK,OAAO;AAAA,qBACnC,MAAM,GAAG;AAAA,wBACN,MAAM,MAAM;AAAA,sBACd,MAAM,IAAI;AAAA,uBACT,MAAM,KAAK;AAAA,6BACL,KAAK,WAAW,KAAA;AAAA;AAAA;AAAA,UAGnC,KAAK,gBAAgB;AAAA;AAAA;AAAA,EAG7B;AAGF;AA5Oa,eA2OK,SAAS,UAAU,cAAc;AA1OvB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GADb,eACe,WAAA,SAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAFb,eAEe,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAHb,eAGe,WAAA,YAAA,CAAA;AACC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAJd,eAIgB,WAAA,cAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GALb,eAKe,WAAA,2BAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GANb,eAMe,WAAA,6BAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAXb,eAWe,WAAA,4BAAA,CAAA;AAEA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAbb,eAae,WAAA,SAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAdb,eAce,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAfb,eAee,WAAA,QAAA,CAAA;AAEC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAjBd,eAiBgB,WAAA,mBAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAlBb,eAkBe,WAAA,iBAAA,CAAA;AAGiB,gBAAA;AAAA,EAA1C,SAAS,EAAC,MAAM,OAAO,WAAW,OAAM;AAAA,GArB9B,eAqBgC,WAAA,WAAA,CAAA;AACF,gBAAA;AAAA,EAAxC,SAAS,EAAC,MAAM,QAAQ,SAAS,MAAK;AAAA,GAtB5B,eAsB8B,WAAA,UAAA,CAAA;AAQzC,gBAAA;AAAA,EADC,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA7Bb,eA8BX,WAAA,uBAAA,CAAA;AAO0B,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GArCb,eAqCe,WAAA,qBAAA,CAAA;AAOC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA5Cd,eA4CgB,WAAA,cAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA7Cb,eA6Ce,WAAA,SAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA9Cb,eA8Ce,WAAA,QAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA/Cb,eA+Ce,WAAA,kBAAA,CAAA;AA/Cf,iBAAN,gBAAA;AAAA,EADN,cAAc,kBAAkB;AAAA,GACpB,cAAA;"}
|
|
@@ -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
|