@oicl/openbridge-webcomponents 2.0.0-next.121 → 2.0.0-next.122
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 +233 -53
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +66 -17
- package/dist/automation/automation-tank/automation-tank.css.js +94 -14
- package/dist/automation/automation-tank/automation-tank.css.js.map +1 -1
- package/dist/automation/automation-tank/automation-tank.d.ts +53 -5
- package/dist/automation/automation-tank/automation-tank.d.ts.map +1 -1
- package/dist/automation/automation-tank/automation-tank.js +39 -20
- package/dist/automation/automation-tank/automation-tank.js.map +1 -1
- package/dist/building-blocks/readout-block/readout-block.d.ts +27 -1
- package/dist/building-blocks/readout-block/readout-block.d.ts.map +1 -1
- package/dist/building-blocks/readout-block/readout-block.js +31 -10
- package/dist/building-blocks/readout-block/readout-block.js.map +1 -1
- package/dist/navigation-instruments/readout/readout-formatters.d.ts +61 -0
- package/dist/navigation-instruments/readout/readout-formatters.d.ts.map +1 -1
- package/dist/navigation-instruments/readout/readout-formatters.js +35 -2
- package/dist/navigation-instruments/readout/readout-formatters.js.map +1 -1
- package/dist/navigation-instruments/readout/readout.d.ts +19 -2
- package/dist/navigation-instruments/readout/readout.d.ts.map +1 -1
- package/dist/navigation-instruments/readout/readout.js +18 -4
- package/dist/navigation-instruments/readout/readout.js.map +1 -1
- package/dist/navigation-instruments/readout-list/readout-list.d.ts.map +1 -1
- package/dist/navigation-instruments/readout-list/readout-list.js +6 -3
- package/dist/navigation-instruments/readout-list/readout-list.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +19 -2
- 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 +18 -4
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
- package/package.json +1 -1
|
@@ -14,6 +14,67 @@ export declare enum ReadoutValueType {
|
|
|
14
14
|
}
|
|
15
15
|
/** Whether `value` is one of the supported {@link ReadoutValueType} values. */
|
|
16
16
|
export declare function isReadoutValueType(value: unknown): value is ReadoutValueType;
|
|
17
|
+
/**
|
|
18
|
+
* The largest `fractionDigits` `Number.prototype.toFixed` accepts. Reused as the
|
|
19
|
+
* `maxDigits` ceiling so the two bounds stay symmetric — a wider reserve than
|
|
20
|
+
* this is meaningless anyway, and an unbounded one builds a huge string.
|
|
21
|
+
*/
|
|
22
|
+
export declare const READOUT_MAX_DIGITS = 100;
|
|
23
|
+
/**
|
|
24
|
+
* Throws when `fractionDigits` is outside the range `toFixed` accepts.
|
|
25
|
+
*
|
|
26
|
+
* It is a public property that reaches `Number.prototype.toFixed` unchanged, so
|
|
27
|
+
* `-1`, `101` or `Infinity` already throw a bare
|
|
28
|
+
* `RangeError: toFixed() digits argument must be between 0 and 100` from inside
|
|
29
|
+
* the update cycle. This replaces that with an error naming the component and
|
|
30
|
+
* the offending value.
|
|
31
|
+
*
|
|
32
|
+
* Deliberately not clamped: `fractionDigits` sets the PRECISION of a reading, so
|
|
33
|
+
* quietly turning `-1` into `0` would drop decimals from a displayed value
|
|
34
|
+
* without telling anyone. It is a configuration mistake, fixable only in code —
|
|
35
|
+
* the same class as a bad `valueType`, and treated the same way.
|
|
36
|
+
*
|
|
37
|
+
* Values `toFixed` itself tolerates are left alone: `NaN` reads as `0`, and a
|
|
38
|
+
* fractional count truncates (`2.7` → `2`).
|
|
39
|
+
*/
|
|
40
|
+
export declare function assertReadoutFractionDigits(tagName: string, fractionDigits: number | null | undefined): void;
|
|
41
|
+
/**
|
|
42
|
+
* A digit count used for WIDTH RESERVATION, normalised to a non-negative integer
|
|
43
|
+
* no greater than {@link READOUT_MAX_DIGITS}.
|
|
44
|
+
*
|
|
45
|
+
* Deliberately named for the role rather than for `maxDigits`: both `maxDigits`
|
|
46
|
+
* and the fraction count `obc-readout-list` reserves with are the same kind of
|
|
47
|
+
* input — a count handed to `String.prototype.repeat` — and must be bounded the
|
|
48
|
+
* same way. `fractionDigits` as a FORMAT input is a different contract and is
|
|
49
|
+
* rejected instead; see {@link assertReadoutFractionDigits}.
|
|
50
|
+
*
|
|
51
|
+
* Clamped rather than rejected because it only reserves width, so bounding it
|
|
52
|
+
* changes no reading's meaning, and the surrounding code already absorbs bad
|
|
53
|
+
* values silently (`Math.max(count, 1)`, `NaN` repeating to `''`). What is not
|
|
54
|
+
* absorbed is `Infinity`, which throws out of `String.prototype.repeat`, and a
|
|
55
|
+
* large finite count, which builds a reserver string long enough to matter —
|
|
56
|
+
* both are capped here.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveReadoutDigitCount(count: number | null | undefined): number;
|
|
59
|
+
/**
|
|
60
|
+
* Whether a digit-count knob failed to arrive as a number: `null`, `undefined`
|
|
61
|
+
* or `NaN`.
|
|
62
|
+
*
|
|
63
|
+
* A missing knob renders the READING unavailable (the dash) rather than
|
|
64
|
+
* silently formatting with a default the author never chose. `fractionDigits`
|
|
65
|
+
* is typically written by the consuming system, and a runtime failure there
|
|
66
|
+
* produces exactly these values — formatting with `0` instead would print a
|
|
67
|
+
* critical `0.4` as a plausible-looking `0`, which an operator cannot tell
|
|
68
|
+
* apart from a healthy reading. The dash makes the failure visible.
|
|
69
|
+
*
|
|
70
|
+
* This is a third contract besides throw and clamp: a finite out-of-range
|
|
71
|
+
* `fractionDigits` is a programmer error and throws
|
|
72
|
+
* ({@link assertReadoutFractionDigits}); a finite out-of-range `maxDigits` is
|
|
73
|
+
* width-only and clamps ({@link resolveReadoutDigitCount}); a knob that never
|
|
74
|
+
* arrived is a runtime data condition and dashes the reading, the same class
|
|
75
|
+
* as a `NaN` value.
|
|
76
|
+
*/
|
|
77
|
+
export declare function isReadoutDigitCountMissing(count: number | null | undefined): boolean;
|
|
17
78
|
/**
|
|
18
79
|
* Throws when `valueType` is not a supported value, or when `value` is text but
|
|
19
80
|
* `valueType` is `number`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readout-formatters.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/readout/readout-formatters.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,2BAA2B,GAAG;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,oBAAY,gBAAgB;IAC1B,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAID,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,SAAS,EAAE,gBAAgB,GAC1B,IAAI,CAyBN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,SAAS,EAAE,gBAAgB,GAC1B,MAAM,GAAG,SAAS,CAgBpB;AAED,+EAA+E;AAC/E,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,SAAS,EAAE,gBAAgB,GAC1B,MAAM,GAAG,SAAS,CAUpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"readout-formatters.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/readout/readout-formatters.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,2BAA2B,GAAG;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,oBAAY,gBAAgB;IAC1B,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAID,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAkBtC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACxC,IAAI,CAWN;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,CAQR;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,OAAO,CAET;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,SAAS,EAAE,gBAAgB,GAC1B,IAAI,CAyBN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,SAAS,EAAE,gBAAgB,GAC1B,MAAM,GAAG,SAAS,CAgBpB;AAED,+EAA+E;AAC/E,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,SAAS,EAAE,gBAAgB,GAC1B,MAAM,GAAG,SAAS,CAUpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,WAAW,CAAC;AAuCjD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,2BAA2B,GACnC,MAAM,CAmBR;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CASjE;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,EAAC,eAAe,EAAE,cAAc,EAAE,cAAc,EAAC,EAAE,2BAA2B,GAC7E,MAAM,CAeR"}
|
|
@@ -7,6 +7,34 @@ const READOUT_VALUE_TYPES = Object.values(ReadoutValueType);
|
|
|
7
7
|
function isReadoutValueType(value) {
|
|
8
8
|
return typeof value === "string" && READOUT_VALUE_TYPES.includes(value);
|
|
9
9
|
}
|
|
10
|
+
const READOUT_MAX_DIGITS = 100;
|
|
11
|
+
function effectiveFractionDigits(fractionDigits) {
|
|
12
|
+
if (fractionDigits === null || fractionDigits === void 0) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
return Number.isNaN(fractionDigits) ? 0 : Math.trunc(fractionDigits);
|
|
16
|
+
}
|
|
17
|
+
function assertReadoutFractionDigits(tagName, fractionDigits) {
|
|
18
|
+
const digits = effectiveFractionDigits(fractionDigits);
|
|
19
|
+
if (Number.isFinite(digits) && digits >= 0 && digits <= READOUT_MAX_DIGITS) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
throw new RangeError(
|
|
23
|
+
// `String`, not `JSON.stringify`: the latter serialises `Infinity` and
|
|
24
|
+
// `NaN` to `null`, hiding the very value being rejected.
|
|
25
|
+
`<${tagName}>: fractionDigits must be between 0 and ${READOUT_MAX_DIGITS} (got ${String(fractionDigits)}).`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function resolveReadoutDigitCount(count) {
|
|
29
|
+
const digits = Math.trunc(count ?? 0);
|
|
30
|
+
if (Number.isNaN(digits) || digits <= 0) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
return Math.min(digits, READOUT_MAX_DIGITS);
|
|
34
|
+
}
|
|
35
|
+
function isReadoutDigitCountMissing(count) {
|
|
36
|
+
return count === null || count === void 0 || Number.isNaN(count);
|
|
37
|
+
}
|
|
10
38
|
function isBlank(value) {
|
|
11
39
|
return value.trim() === "";
|
|
12
40
|
}
|
|
@@ -51,9 +79,10 @@ const READOUT_UNAVAILABLE_DASH = "‒";
|
|
|
51
79
|
function dashedGenerator({
|
|
52
80
|
showZeroPadding,
|
|
53
81
|
minValueLength,
|
|
54
|
-
fractionDigits
|
|
82
|
+
fractionDigits: rawFractionDigits
|
|
55
83
|
}) {
|
|
56
84
|
const visibleDigits = showZeroPadding ? Math.max(minValueLength, 1) : 1;
|
|
85
|
+
const fractionDigits = Number.isNaN(rawFractionDigits) ? 0 : rawFractionDigits;
|
|
57
86
|
if (fractionDigits < 1) {
|
|
58
87
|
return READOUT_UNAVAILABLE_DASH.repeat(visibleDigits);
|
|
59
88
|
}
|
|
@@ -61,7 +90,7 @@ function dashedGenerator({
|
|
|
61
90
|
return READOUT_UNAVAILABLE_DASH.repeat(Math.max(integerDigits, 1)) + "." + READOUT_UNAVAILABLE_DASH.repeat(fractionDigits);
|
|
62
91
|
}
|
|
63
92
|
function formatNumericValue(value, options) {
|
|
64
|
-
if (value === void 0 || !Number.isFinite(value)) {
|
|
93
|
+
if (value === void 0 || !Number.isFinite(value) || Number.isNaN(options.fractionDigits)) {
|
|
65
94
|
return dashedGenerator(options);
|
|
66
95
|
}
|
|
67
96
|
return value.toFixed(options.fractionDigits);
|
|
@@ -90,13 +119,17 @@ function getHintZeros(value, { showZeroPadding, minValueLength, fractionDigits }
|
|
|
90
119
|
return "";
|
|
91
120
|
}
|
|
92
121
|
export {
|
|
122
|
+
READOUT_MAX_DIGITS,
|
|
93
123
|
READOUT_UNAVAILABLE_DASH,
|
|
94
124
|
ReadoutValueType,
|
|
125
|
+
assertReadoutFractionDigits,
|
|
95
126
|
assertReadoutValueType,
|
|
96
127
|
formatNumericValue,
|
|
97
128
|
getHintZeros,
|
|
129
|
+
isReadoutDigitCountMissing,
|
|
98
130
|
isReadoutValueType,
|
|
99
131
|
readoutFormattedInteger,
|
|
132
|
+
resolveReadoutDigitCount,
|
|
100
133
|
resolveReadoutNumericValue,
|
|
101
134
|
resolveReadoutTextValue
|
|
102
135
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readout-formatters.js","sources":["../../../src/navigation-instruments/readout/readout-formatters.ts"],"sourcesContent":["export type ReadoutNumericFormatOptions = {\n showZeroPadding: boolean;\n minValueLength: number;\n fractionDigits: number;\n};\n\n/**\n * How a readout's `value` is interpreted.\n * - `number`: formatted via `fractionDigits` / `maxDigits`.\n * - `text`: rendered verbatim, with the numeric format options ignored.\n */\nexport enum ReadoutValueType {\n number = 'number',\n text = 'text',\n}\n\nconst READOUT_VALUE_TYPES: readonly string[] = Object.values(ReadoutValueType);\n\n/** Whether `value` is one of the supported {@link ReadoutValueType} values. */\nexport function isReadoutValueType(value: unknown): value is ReadoutValueType {\n return typeof value === 'string' && READOUT_VALUE_TYPES.includes(value);\n}\n\nfunction isBlank(value: string): boolean {\n return value.trim() === '';\n}\n\n/**\n * Throws when `valueType` is not a supported value, or when `value` is text but\n * `valueType` is `number`.\n *\n * `valueType` is validated first because an attribute carries an unchecked\n * string: a typo such as `valuetype=\"strng\"` matches neither mode, so every\n * mode check falls through and the readout silently renders the unavailable\n * dash — the opposite of the loud failure this contract exists to give.\n * `undefined`/`null` are allowed and mean \"use the default\".\n *\n * Attributes are always strings, so a numeric-looking string (`value=\"10.12\"`)\n * is accepted and parsed. Blank strings resolve to the unavailable dash rather\n * than throwing — `value=\"${maybeUndefined}\"` is a common template shape, and\n * `Number('')` is `0`, a silently wrong reading.\n */\nexport function assertReadoutValueType(\n tagName: string,\n value: number | string | null | undefined,\n valueType: ReadoutValueType\n): void {\n // `undefined`/`null` mean \"use the default\", matching how the components and\n // the resolvers treat an unset `valueType`.\n const resolved = valueType ?? ReadoutValueType.number;\n if (!isReadoutValueType(resolved)) {\n throw new TypeError(\n `<${tagName}>: valueType must be ` +\n `${READOUT_VALUE_TYPES.map((t) => `\"${t}\"`).join(' or ')} ` +\n `(got ${JSON.stringify(valueType)}).`\n );\n }\n if (\n resolved !== ReadoutValueType.number ||\n typeof value !== 'string' ||\n isBlank(value)\n ) {\n return;\n }\n if (Number.isFinite(Number(value))) {\n return;\n }\n throw new TypeError(\n `<${tagName}>: value must be a number when valueType is \"number\" ` +\n `(got ${JSON.stringify(value)}). Set valueType=\"text\" to render text.`\n );\n}\n\n/**\n * The value as a number, or `undefined` when it is text / unavailable.\n *\n * A non-finite number (`NaN`, `±Infinity`) counts as unavailable and renders the\n * dash, the same as `null`. `NaN` is a runtime data condition — a sensor\n * dropout, a `0/0`, a bad parse — not a programmer error, so it must not throw;\n * and `value.toFixed()` would otherwise render the literal text `\"NaN\"` /\n * `\"Infinity\"` in place of a reading. This also makes the number path agree with\n * the string path below, which has always resolved a non-finite string to\n * `undefined` — before this, `<obc-readout value=\"NaN\">` rendered a dash while\n * `.value=${NaN}` rendered `\"NaN\"`.\n */\nexport function resolveReadoutNumericValue(\n value: number | string | null | undefined,\n valueType: ReadoutValueType\n): number | undefined {\n if (\n valueType === ReadoutValueType.text ||\n value === null ||\n value === undefined\n ) {\n return undefined;\n }\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value : undefined;\n }\n if (isBlank(value)) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\n/** The value as display text, or `undefined` when not in text mode / blank. */\nexport function resolveReadoutTextValue(\n value: number | string | null | undefined,\n valueType: ReadoutValueType\n): string | undefined {\n if (\n valueType !== ReadoutValueType.text ||\n value === null ||\n value === undefined\n ) {\n return undefined;\n }\n const text = typeof value === 'number' ? String(value) : value;\n return isBlank(text) ? undefined : text;\n}\n\n/**\n * The character used for an unavailable (\"no reading\") value.\n *\n * U+2012 FIGURE DASH, not the ASCII hyphen-minus: it is defined to be the same\n * width as a digit, so the placeholder lines up with the reading it stands in\n * for. Measured in Noto Sans with tabular figures at `size=\"m\"` — digit 13.02px,\n * U+2012 13.02px, U+002D 7.02px, en dash 11.02px, em dash 22.02px. With a\n * hyphen, `-.--` sat 46% narrow per character and its decimal point missed the\n * reading's; with U+2012 the point and every fraction position align exactly.\n */\nexport const READOUT_UNAVAILABLE_DASH = '\\u2012';\n\n/**\n * The unavailable (\"no reading\") text: a single integer dash plus one dash per\n * fraction digit — `\\u2012` at `fractionDigits` 0, `\\u2012.\\u2012\\u2012` at 2.\n *\n * Deliberately NOT filled out to `maxDigits`: the placeholder stays short and\n * sits at the right edge of the reserved width, rather than spelling out every\n * reserved digit position. `maxDigits` still reserves the width, so nothing\n * shifts when a reading arrives.\n */\nfunction dashedGenerator({\n showZeroPadding,\n minValueLength,\n fractionDigits,\n}: ReadoutNumericFormatOptions): string {\n const visibleDigits = showZeroPadding ? Math.max(minValueLength, 1) : 1;\n\n if (fractionDigits < 1) {\n return READOUT_UNAVAILABLE_DASH.repeat(visibleDigits);\n }\n\n const integerDigits = visibleDigits - fractionDigits;\n\n return (\n READOUT_UNAVAILABLE_DASH.repeat(Math.max(integerDigits, 1)) +\n '.' +\n READOUT_UNAVAILABLE_DASH.repeat(fractionDigits)\n );\n}\n\nexport function formatNumericValue(\n value: number | undefined,\n options: ReadoutNumericFormatOptions\n): string {\n // Non-finite counts as unavailable here too, not only in\n // `resolveReadoutNumericValue`. Every caller normalises today, but this\n // function is exported, and `NaN.toFixed()` would put the literal text\n // \"NaN\" where a reading belongs — the exact failure this change removes.\n if (value === undefined || !Number.isFinite(value)) {\n return dashedGenerator(options);\n }\n\n return value.toFixed(options.fractionDigits);\n}\n\nexport function readoutFormattedInteger(valueText: string): number {\n const t = valueText.trim();\n if (!t) {\n return 0;\n }\n\n const rest = t.startsWith('-') ? t.slice(1) : t;\n const dot = rest.indexOf('.');\n return dot === -1 ? rest.length : dot;\n}\n\nexport function getHintZeros(\n value: number | undefined,\n {showZeroPadding, minValueLength, fractionDigits}: ReadoutNumericFormatOptions\n): string {\n const formattedValue = formatNumericValue(value, {\n showZeroPadding,\n minValueLength,\n fractionDigits,\n });\n const dotLength = fractionDigits > 0 ? 1 : 0;\n const integerLength = formattedValue.length - dotLength;\n const hintedDigits = Math.max(minValueLength - integerLength, 0);\n\n if (hintedDigits > 0) {\n return '0'.repeat(hintedDigits);\n }\n\n return '';\n}\n"],"names":["ReadoutValueType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"readout-formatters.js","sources":["../../../src/navigation-instruments/readout/readout-formatters.ts"],"sourcesContent":["export type ReadoutNumericFormatOptions = {\n showZeroPadding: boolean;\n minValueLength: number;\n fractionDigits: number;\n};\n\n/**\n * How a readout's `value` is interpreted.\n * - `number`: formatted via `fractionDigits` / `maxDigits`.\n * - `text`: rendered verbatim, with the numeric format options ignored.\n */\nexport enum ReadoutValueType {\n number = 'number',\n text = 'text',\n}\n\nconst READOUT_VALUE_TYPES: readonly string[] = Object.values(ReadoutValueType);\n\n/** Whether `value` is one of the supported {@link ReadoutValueType} values. */\nexport function isReadoutValueType(value: unknown): value is ReadoutValueType {\n return typeof value === 'string' && READOUT_VALUE_TYPES.includes(value);\n}\n\n/**\n * The largest `fractionDigits` `Number.prototype.toFixed` accepts. Reused as the\n * `maxDigits` ceiling so the two bounds stay symmetric — a wider reserve than\n * this is meaningless anyway, and an unbounded one builds a huge string.\n */\nexport const READOUT_MAX_DIGITS = 100;\n\n/**\n * `fractionDigits` as `toFixed` will actually read it: `NaN` and an unset value\n * count as 0, and a fractional count truncates.\n */\nfunction effectiveFractionDigits(\n fractionDigits: number | null | undefined\n): number {\n // `toFixed(undefined)` behaves as `toFixed(0)`, and the components read\n // `fractionDigits ?? 0`, so an unset value must not be rejected here — the\n // assertion has to accept exactly what the runtime accepts.\n if (fractionDigits === null || fractionDigits === undefined) {\n return 0;\n }\n return Number.isNaN(fractionDigits) ? 0 : Math.trunc(fractionDigits);\n}\n\n/**\n * Throws when `fractionDigits` is outside the range `toFixed` accepts.\n *\n * It is a public property that reaches `Number.prototype.toFixed` unchanged, so\n * `-1`, `101` or `Infinity` already throw a bare\n * `RangeError: toFixed() digits argument must be between 0 and 100` from inside\n * the update cycle. This replaces that with an error naming the component and\n * the offending value.\n *\n * Deliberately not clamped: `fractionDigits` sets the PRECISION of a reading, so\n * quietly turning `-1` into `0` would drop decimals from a displayed value\n * without telling anyone. It is a configuration mistake, fixable only in code —\n * the same class as a bad `valueType`, and treated the same way.\n *\n * Values `toFixed` itself tolerates are left alone: `NaN` reads as `0`, and a\n * fractional count truncates (`2.7` → `2`).\n */\nexport function assertReadoutFractionDigits(\n tagName: string,\n fractionDigits: number | null | undefined\n): void {\n const digits = effectiveFractionDigits(fractionDigits);\n if (Number.isFinite(digits) && digits >= 0 && digits <= READOUT_MAX_DIGITS) {\n return;\n }\n throw new RangeError(\n // `String`, not `JSON.stringify`: the latter serialises `Infinity` and\n // `NaN` to `null`, hiding the very value being rejected.\n `<${tagName}>: fractionDigits must be between 0 and ${READOUT_MAX_DIGITS} ` +\n `(got ${String(fractionDigits)}).`\n );\n}\n\n/**\n * A digit count used for WIDTH RESERVATION, normalised to a non-negative integer\n * no greater than {@link READOUT_MAX_DIGITS}.\n *\n * Deliberately named for the role rather than for `maxDigits`: both `maxDigits`\n * and the fraction count `obc-readout-list` reserves with are the same kind of\n * input — a count handed to `String.prototype.repeat` — and must be bounded the\n * same way. `fractionDigits` as a FORMAT input is a different contract and is\n * rejected instead; see {@link assertReadoutFractionDigits}.\n *\n * Clamped rather than rejected because it only reserves width, so bounding it\n * changes no reading's meaning, and the surrounding code already absorbs bad\n * values silently (`Math.max(count, 1)`, `NaN` repeating to `''`). What is not\n * absorbed is `Infinity`, which throws out of `String.prototype.repeat`, and a\n * large finite count, which builds a reserver string long enough to matter —\n * both are capped here.\n */\nexport function resolveReadoutDigitCount(\n count: number | null | undefined\n): number {\n const digits = Math.trunc(count ?? 0);\n if (Number.isNaN(digits) || digits <= 0) {\n // Matches what the existing guards already do with these: reserve nothing.\n return 0;\n }\n // `Infinity` lands on the cap — \"as wide as possible\" — rather than throwing.\n return Math.min(digits, READOUT_MAX_DIGITS);\n}\n\n/**\n * Whether a digit-count knob failed to arrive as a number: `null`, `undefined`\n * or `NaN`.\n *\n * A missing knob renders the READING unavailable (the dash) rather than\n * silently formatting with a default the author never chose. `fractionDigits`\n * is typically written by the consuming system, and a runtime failure there\n * produces exactly these values — formatting with `0` instead would print a\n * critical `0.4` as a plausible-looking `0`, which an operator cannot tell\n * apart from a healthy reading. The dash makes the failure visible.\n *\n * This is a third contract besides throw and clamp: a finite out-of-range\n * `fractionDigits` is a programmer error and throws\n * ({@link assertReadoutFractionDigits}); a finite out-of-range `maxDigits` is\n * width-only and clamps ({@link resolveReadoutDigitCount}); a knob that never\n * arrived is a runtime data condition and dashes the reading, the same class\n * as a `NaN` value.\n */\nexport function isReadoutDigitCountMissing(\n count: number | null | undefined\n): boolean {\n return count === null || count === undefined || Number.isNaN(count);\n}\n\nfunction isBlank(value: string): boolean {\n return value.trim() === '';\n}\n\n/**\n * Throws when `valueType` is not a supported value, or when `value` is text but\n * `valueType` is `number`.\n *\n * `valueType` is validated first because an attribute carries an unchecked\n * string: a typo such as `valuetype=\"strng\"` matches neither mode, so every\n * mode check falls through and the readout silently renders the unavailable\n * dash — the opposite of the loud failure this contract exists to give.\n * `undefined`/`null` are allowed and mean \"use the default\".\n *\n * Attributes are always strings, so a numeric-looking string (`value=\"10.12\"`)\n * is accepted and parsed. Blank strings resolve to the unavailable dash rather\n * than throwing — `value=\"${maybeUndefined}\"` is a common template shape, and\n * `Number('')` is `0`, a silently wrong reading.\n */\nexport function assertReadoutValueType(\n tagName: string,\n value: number | string | null | undefined,\n valueType: ReadoutValueType\n): void {\n // `undefined`/`null` mean \"use the default\", matching how the components and\n // the resolvers treat an unset `valueType`.\n const resolved = valueType ?? ReadoutValueType.number;\n if (!isReadoutValueType(resolved)) {\n throw new TypeError(\n `<${tagName}>: valueType must be ` +\n `${READOUT_VALUE_TYPES.map((t) => `\"${t}\"`).join(' or ')} ` +\n `(got ${JSON.stringify(valueType)}).`\n );\n }\n if (\n resolved !== ReadoutValueType.number ||\n typeof value !== 'string' ||\n isBlank(value)\n ) {\n return;\n }\n if (Number.isFinite(Number(value))) {\n return;\n }\n throw new TypeError(\n `<${tagName}>: value must be a number when valueType is \"number\" ` +\n `(got ${JSON.stringify(value)}). Set valueType=\"text\" to render text.`\n );\n}\n\n/**\n * The value as a number, or `undefined` when it is text / unavailable.\n *\n * A non-finite number (`NaN`, `±Infinity`) counts as unavailable and renders the\n * dash, the same as `null`. `NaN` is a runtime data condition — a sensor\n * dropout, a `0/0`, a bad parse — not a programmer error, so it must not throw;\n * and `value.toFixed()` would otherwise render the literal text `\"NaN\"` /\n * `\"Infinity\"` in place of a reading. This also makes the number path agree with\n * the string path below, which has always resolved a non-finite string to\n * `undefined` — before this, `<obc-readout value=\"NaN\">` rendered a dash while\n * `.value=${NaN}` rendered `\"NaN\"`.\n */\nexport function resolveReadoutNumericValue(\n value: number | string | null | undefined,\n valueType: ReadoutValueType\n): number | undefined {\n if (\n valueType === ReadoutValueType.text ||\n value === null ||\n value === undefined\n ) {\n return undefined;\n }\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value : undefined;\n }\n if (isBlank(value)) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\n/** The value as display text, or `undefined` when not in text mode / blank. */\nexport function resolveReadoutTextValue(\n value: number | string | null | undefined,\n valueType: ReadoutValueType\n): string | undefined {\n if (\n valueType !== ReadoutValueType.text ||\n value === null ||\n value === undefined\n ) {\n return undefined;\n }\n const text = typeof value === 'number' ? String(value) : value;\n return isBlank(text) ? undefined : text;\n}\n\n/**\n * The character used for an unavailable (\"no reading\") value.\n *\n * U+2012 FIGURE DASH, not the ASCII hyphen-minus: it is defined to be the same\n * width as a digit, so the placeholder lines up with the reading it stands in\n * for. Measured in Noto Sans with tabular figures at `size=\"m\"` — digit 13.02px,\n * U+2012 13.02px, U+002D 7.02px, en dash 11.02px, em dash 22.02px. With a\n * hyphen, `-.--` sat 46% narrow per character and its decimal point missed the\n * reading's; with U+2012 the point and every fraction position align exactly.\n */\nexport const READOUT_UNAVAILABLE_DASH = '\\u2012';\n\n/**\n * The unavailable (\"no reading\") text: a single integer dash plus one dash per\n * fraction digit — `\\u2012` at `fractionDigits` 0, `\\u2012.\\u2012\\u2012` at 2.\n *\n * Deliberately NOT filled out to `maxDigits`: the placeholder stays short and\n * sits at the right edge of the reserved width, rather than spelling out every\n * reserved digit position. `maxDigits` still reserves the width, so nothing\n * shifts when a reading arrives.\n */\nfunction dashedGenerator({\n showZeroPadding,\n minValueLength,\n fractionDigits: rawFractionDigits,\n}: ReadoutNumericFormatOptions): string {\n const visibleDigits = showZeroPadding ? Math.max(minValueLength, 1) : 1;\n\n // A missing precision shapes the placeholder as zero fraction digits — a\n // single dash. Without this, `NaN < 1` is false, both `repeat(NaN)` calls\n // below produce the empty string, and the placeholder degenerates to a\n // lone `\".\"`.\n const fractionDigits = Number.isNaN(rawFractionDigits)\n ? 0\n : rawFractionDigits;\n\n if (fractionDigits < 1) {\n return READOUT_UNAVAILABLE_DASH.repeat(visibleDigits);\n }\n\n const integerDigits = visibleDigits - fractionDigits;\n\n return (\n READOUT_UNAVAILABLE_DASH.repeat(Math.max(integerDigits, 1)) +\n '.' +\n READOUT_UNAVAILABLE_DASH.repeat(fractionDigits)\n );\n}\n\nexport function formatNumericValue(\n value: number | undefined,\n options: ReadoutNumericFormatOptions\n): string {\n // Non-finite counts as unavailable here too, not only in\n // `resolveReadoutNumericValue`. Every caller normalises today, but this\n // function is exported, and `NaN.toFixed()` would put the literal text\n // \"NaN\" where a reading belongs — the exact failure this change removes.\n //\n // A missing precision (`NaN` fractionDigits) is the same class of failure\n // from the other operand: `value.toFixed(NaN)` silently formats with zero\n // decimals, printing a critical `0.4` as a plausible-looking `0`. The\n // reading is untrustworthy without its precision, so it dashes too.\n if (\n value === undefined ||\n !Number.isFinite(value) ||\n Number.isNaN(options.fractionDigits)\n ) {\n return dashedGenerator(options);\n }\n\n return value.toFixed(options.fractionDigits);\n}\n\nexport function readoutFormattedInteger(valueText: string): number {\n const t = valueText.trim();\n if (!t) {\n return 0;\n }\n\n const rest = t.startsWith('-') ? t.slice(1) : t;\n const dot = rest.indexOf('.');\n return dot === -1 ? rest.length : dot;\n}\n\nexport function getHintZeros(\n value: number | undefined,\n {showZeroPadding, minValueLength, fractionDigits}: ReadoutNumericFormatOptions\n): string {\n const formattedValue = formatNumericValue(value, {\n showZeroPadding,\n minValueLength,\n fractionDigits,\n });\n const dotLength = fractionDigits > 0 ? 1 : 0;\n const integerLength = formattedValue.length - dotLength;\n const hintedDigits = Math.max(minValueLength - integerLength, 0);\n\n if (hintedDigits > 0) {\n return '0'.repeat(hintedDigits);\n }\n\n return '';\n}\n"],"names":["ReadoutValueType"],"mappings":"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"}
|
|
@@ -211,13 +211,22 @@ export declare class ObcReadout extends LitElement {
|
|
|
211
211
|
hasDegreeSpacer: boolean;
|
|
212
212
|
/**
|
|
213
213
|
* Also formats the numeric setpoint / advice blocks, which stay numeric
|
|
214
|
-
* even when the value is text.
|
|
214
|
+
* even when the value is text. Must be between 0 and 100 — the range
|
|
215
|
+
* `Number.prototype.toFixed` accepts; outside it throws a `RangeError`.
|
|
216
|
+
* A fractional count truncates (`2.7` → `2`). A count that never arrived
|
|
217
|
+
* (`NaN`, `null` or unset) renders the reading as the unavailable dash —
|
|
218
|
+
* formatting with a precision the author never chose would let a critical
|
|
219
|
+
* `0.4` pass for a healthy `0`.
|
|
215
220
|
* @availableWhen valueType==number || hasSetpoint==true || hasAdvice==true
|
|
216
221
|
*/
|
|
217
222
|
fractionDigits: number;
|
|
218
223
|
/**
|
|
219
224
|
* Also formats the numeric setpoint / advice blocks, which stay numeric
|
|
220
|
-
* even when the value is text.
|
|
225
|
+
* even when the value is text. Bounded before use: a fractional count
|
|
226
|
+
* truncates (`2.7` → `2`), anything above 100 — including `Infinity` —
|
|
227
|
+
* caps at 100, and a negative count reserves nothing. A count that never
|
|
228
|
+
* arrived (`NaN`, `null` or unset) renders the reading as the unavailable
|
|
229
|
+
* dash, consistent with `fractionDigits`.
|
|
221
230
|
* @availableWhen valueType==number || hasSetpoint==true || hasAdvice==true
|
|
222
231
|
*/
|
|
223
232
|
maxDigits: number;
|
|
@@ -255,6 +264,14 @@ export declare class ObcReadout extends LitElement {
|
|
|
255
264
|
private get isHorizontal();
|
|
256
265
|
private get resolvedFractionDigits();
|
|
257
266
|
private get resolvedMaxDigits();
|
|
267
|
+
/**
|
|
268
|
+
* Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
|
|
269
|
+
* The raw knobs are forwarded to the blocks, which render the reading as
|
|
270
|
+
* the unavailable dash (see `obc-readout-block.digitCountsMissing`); this
|
|
271
|
+
* getter only keeps the setpoint comparison in agreement with what is
|
|
272
|
+
* displayed.
|
|
273
|
+
*/
|
|
274
|
+
private get digitCountsMissing();
|
|
258
275
|
private get hasSrc();
|
|
259
276
|
private get resolvedSourceInteraction();
|
|
260
277
|
private get isAtSetpoint();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readout.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/readout/readout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAgD,MAAM,KAAK,CAAC;AAK9E,OAAO,qCAAqC,CAAC;AAK7C,OAAO,sDAAsD,CAAC;AAC9D,OAAO,EAEL,gBAAgB,EAChB,uBAAuB,EAExB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EACL,kCAAkC,EAElC,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACvB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AACrC,OAAO,
|
|
1
|
+
{"version":3,"file":"readout.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/readout/readout.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { ObcTextboxFontWeight, ObcTextboxSize } from "../../components/textbox/t
|
|
|
7
7
|
import { ReadoutBlockHidePhase, ReadoutBlockSize, ReadoutBlockVariant, ReadoutBlockDataQuality } from "../../building-blocks/readout-block/readout-block.js";
|
|
8
8
|
import { ReadoutListItemSetpointInteraction } from "../readout-list-item/readout-list-item.js";
|
|
9
9
|
import { Priority } from "../types.js";
|
|
10
|
-
import { ReadoutValueType, resolveReadoutNumericValue, assertReadoutValueType } from "./readout-formatters.js";
|
|
10
|
+
import { ReadoutValueType, resolveReadoutDigitCount, isReadoutDigitCountMissing, resolveReadoutNumericValue, assertReadoutValueType, assertReadoutFractionDigits } from "./readout-formatters.js";
|
|
11
11
|
import { isDisplayedAtSetpoint, readoutPrimarySize, readoutSecondarySize, readoutSetpointWeight, readoutNumericFormatOptions, readoutDataQualityClasses, resolveSetpointHidePhase } from "./readout-shared.js";
|
|
12
12
|
import { wrapWithAlertFrame, ObcAlertFrameThickness, ObcAlertFrameType, ObcAlertFrameMode } from "../../components/alert-frame/alert-frame.js";
|
|
13
13
|
import { AlertType } from "../../types.js";
|
|
@@ -118,7 +118,17 @@ let ObcReadout = class extends LitElement {
|
|
|
118
118
|
return this.fractionDigits ?? 0;
|
|
119
119
|
}
|
|
120
120
|
get resolvedMaxDigits() {
|
|
121
|
-
return this.maxDigits
|
|
121
|
+
return resolveReadoutDigitCount(this.maxDigits);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Whether a digit knob failed to arrive (`NaN` / `null` / `undefined`).
|
|
125
|
+
* The raw knobs are forwarded to the blocks, which render the reading as
|
|
126
|
+
* the unavailable dash (see `obc-readout-block.digitCountsMissing`); this
|
|
127
|
+
* getter only keeps the setpoint comparison in agreement with what is
|
|
128
|
+
* displayed.
|
|
129
|
+
*/
|
|
130
|
+
get digitCountsMissing() {
|
|
131
|
+
return isReadoutDigitCountMissing(this.fractionDigits) || isReadoutDigitCountMissing(this.maxDigits);
|
|
122
132
|
}
|
|
123
133
|
get hasSrc() {
|
|
124
134
|
return this.src !== void 0 && this.src.trim() !== "";
|
|
@@ -130,6 +140,9 @@ let ObcReadout = class extends LitElement {
|
|
|
130
140
|
if (!this.hasSetpoint) {
|
|
131
141
|
return false;
|
|
132
142
|
}
|
|
143
|
+
if (this.digitCountsMissing) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
133
146
|
return isDisplayedAtSetpoint(
|
|
134
147
|
resolveReadoutNumericValue(this.value, this.valueType) ?? null,
|
|
135
148
|
this.setpoint,
|
|
@@ -240,8 +253,8 @@ let ObcReadout = class extends LitElement {
|
|
|
240
253
|
.weight=${config.weight}
|
|
241
254
|
.hasDegree=${config.hasDegree ?? false}
|
|
242
255
|
.hasIcon=${config.hasIcon ?? false}
|
|
243
|
-
.fractionDigits=${this.
|
|
244
|
-
.maxDigits=${this.
|
|
256
|
+
.fractionDigits=${this.fractionDigits}
|
|
257
|
+
.maxDigits=${this.maxDigits}
|
|
245
258
|
.hintedZeros=${config.hintedZeros}
|
|
246
259
|
.spaceReserver=${config.spaceReserver}
|
|
247
260
|
.off=${config.off ?? false}
|
|
@@ -714,6 +727,7 @@ let ObcReadout = class extends LitElement {
|
|
|
714
727
|
willUpdate(changed) {
|
|
715
728
|
super.willUpdate(changed);
|
|
716
729
|
assertReadoutValueType("obc-readout", this.value, this.valueType);
|
|
730
|
+
assertReadoutFractionDigits("obc-readout", this.fractionDigits);
|
|
717
731
|
}
|
|
718
732
|
updated(changed) {
|
|
719
733
|
super.updated(changed);
|