@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.115 → 2.0.0-next.116
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 +18 -5
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/dist/building-blocks/readout-block/readout-block.d.ts.map +1 -1
- package/dist/building-blocks/readout-block/readout-block.js +5 -2
- package/dist/building-blocks/readout-block/readout-block.js.map +1 -1
- package/dist/navigation-instruments/readout/readout-formatters.d.ts +23 -1
- package/dist/navigation-instruments/readout/readout-formatters.d.ts.map +1 -1
- package/dist/navigation-instruments/readout/readout-formatters.js +6 -4
- package/dist/navigation-instruments/readout/readout-formatters.js.map +1 -1
- package/dist/navigation-instruments/readout/readout-shared.d.ts.map +1 -1
- package/dist/navigation-instruments/readout/readout-shared.js +9 -0
- package/dist/navigation-instruments/readout/readout-shared.js.map +1 -1
- package/package.json +1 -1
- package/src/building-blocks/readout-block/readout-block.stories.ts +243 -1
- package/src/building-blocks/readout-block/readout-block.ts +5 -1
- package/src/navigation-instruments/readout/readout-formatters.spec.ts +143 -3
- package/src/navigation-instruments/readout/readout-formatters.ts +43 -5
- package/src/navigation-instruments/readout/readout-shared.spec.ts +13 -0
- package/src/navigation-instruments/readout/readout-shared.ts +16 -0
- package/src/navigation-instruments/readout/readout.stories.ts +110 -0
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
assertReadoutValueType,
|
|
18
18
|
resolveReadoutNumericValue,
|
|
19
19
|
resolveReadoutTextValue,
|
|
20
|
+
READOUT_UNAVAILABLE_DASH,
|
|
20
21
|
ReadoutValueType,
|
|
21
22
|
type ReadoutNumericFormatOptions,
|
|
22
23
|
} from '../../navigation-instruments/readout/readout-formatters.js';
|
|
@@ -215,6 +216,9 @@ export class ObcReadoutBlock extends LitElement {
|
|
|
215
216
|
|
|
216
217
|
private get numericFormatOptions(): ReadoutNumericFormatOptions {
|
|
217
218
|
return {
|
|
219
|
+
// The unavailable placeholder stays short (`\u2012.\u2012\u2012`) rather than
|
|
220
|
+
// spelling out every reserved digit position — `maxDigits` already
|
|
221
|
+
// reserves the width, so it simply sits at the right edge of it.
|
|
218
222
|
showZeroPadding: false,
|
|
219
223
|
minValueLength: this.maxDigits,
|
|
220
224
|
fractionDigits: this.fractionDigits,
|
|
@@ -334,7 +338,7 @@ export class ObcReadoutBlock extends LitElement {
|
|
|
334
338
|
const text = this.off
|
|
335
339
|
? this.offText
|
|
336
340
|
: isTextMode
|
|
337
|
-
? (textValue ??
|
|
341
|
+
? (textValue ?? READOUT_UNAVAILABLE_DASH)
|
|
338
342
|
: formatNumericValue(valueForFormat, formatOptions);
|
|
339
343
|
// Hinted zeros pad the INTEGER part up to `maxDigits`, independent of
|
|
340
344
|
// `fractionDigits` (the decimal point and fraction digits never count toward
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
assertReadoutValueType,
|
|
4
4
|
resolveReadoutNumericValue,
|
|
5
5
|
resolveReadoutTextValue,
|
|
6
|
+
formatNumericValue,
|
|
6
7
|
isReadoutValueType,
|
|
7
8
|
ReadoutValueType,
|
|
9
|
+
READOUT_UNAVAILABLE_DASH,
|
|
8
10
|
} from './readout-formatters.js';
|
|
9
11
|
|
|
10
12
|
describe('assertReadoutValueType', () => {
|
|
@@ -181,11 +183,50 @@ describe('resolveReadoutNumericValue', () => {
|
|
|
181
183
|
).toBeUndefined();
|
|
182
184
|
});
|
|
183
185
|
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
+
// A non-finite number is unavailable, not a reading: `toFixed` would render
|
|
187
|
+
// the literal text "NaN" / "Infinity" in place of a value.
|
|
188
|
+
it('is undefined for a non-finite number', () => {
|
|
186
189
|
expect(
|
|
187
190
|
resolveReadoutNumericValue(Number.NaN, ReadoutValueType.number)
|
|
188
|
-
).
|
|
191
|
+
).toBeUndefined();
|
|
192
|
+
expect(
|
|
193
|
+
resolveReadoutNumericValue(
|
|
194
|
+
Number.POSITIVE_INFINITY,
|
|
195
|
+
ReadoutValueType.number
|
|
196
|
+
)
|
|
197
|
+
).toBeUndefined();
|
|
198
|
+
expect(
|
|
199
|
+
resolveReadoutNumericValue(
|
|
200
|
+
Number.NEGATIVE_INFINITY,
|
|
201
|
+
ReadoutValueType.number
|
|
202
|
+
)
|
|
203
|
+
).toBeUndefined();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// `.value=${undefined}` reaches the property uncoerced, so an unset value must
|
|
207
|
+
// read exactly like an explicit `null` — both are "no reading".
|
|
208
|
+
it('treats undefined and null identically', () => {
|
|
209
|
+
expect(resolveReadoutNumericValue(undefined, ReadoutValueType.number)).toBe(
|
|
210
|
+
resolveReadoutNumericValue(null, ReadoutValueType.number)
|
|
211
|
+
);
|
|
212
|
+
expect(resolveReadoutTextValue(undefined, ReadoutValueType.text)).toBe(
|
|
213
|
+
resolveReadoutTextValue(null, ReadoutValueType.text)
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Before this, the same logical input resolved differently depending on how
|
|
218
|
+
// it was bound: `<obc-readout value="NaN">` (attribute → string) gave a dash,
|
|
219
|
+
// while `.value=${NaN}` (property → number) gave the literal text "NaN".
|
|
220
|
+
it('resolves a non-finite value identically as a number and as a string', () => {
|
|
221
|
+
expect(
|
|
222
|
+
resolveReadoutNumericValue(Number.NaN, ReadoutValueType.number)
|
|
223
|
+
).toBe(resolveReadoutNumericValue('NaN', ReadoutValueType.number));
|
|
224
|
+
expect(
|
|
225
|
+
resolveReadoutNumericValue(
|
|
226
|
+
Number.POSITIVE_INFINITY,
|
|
227
|
+
ReadoutValueType.number
|
|
228
|
+
)
|
|
229
|
+
).toBe(resolveReadoutNumericValue('Infinity', ReadoutValueType.number));
|
|
189
230
|
});
|
|
190
231
|
});
|
|
191
232
|
|
|
@@ -227,3 +268,102 @@ describe('resolveReadoutTextValue', () => {
|
|
|
227
268
|
).toBeUndefined();
|
|
228
269
|
});
|
|
229
270
|
});
|
|
271
|
+
|
|
272
|
+
describe('formatNumericValue — unavailable value', () => {
|
|
273
|
+
const opts = (minValueLength: number, fractionDigits: number) => ({
|
|
274
|
+
showZeroPadding: false,
|
|
275
|
+
minValueLength,
|
|
276
|
+
fractionDigits,
|
|
277
|
+
});
|
|
278
|
+
const D = READOUT_UNAVAILABLE_DASH;
|
|
279
|
+
|
|
280
|
+
// U+2012 FIGURE DASH, not the ASCII hyphen. It is defined to be digit-width,
|
|
281
|
+
// so the placeholder's decimal point and fraction positions line up with the
|
|
282
|
+
// reading it replaces; measured in Noto Sans, a digit and U+2012 are both
|
|
283
|
+
// 13.02px while U+002D is 7.02px. `tabular-nums` does not fix this — it
|
|
284
|
+
// equalises figures with each other and leaves punctuation alone.
|
|
285
|
+
it('uses the digit-width figure dash, not a hyphen', () => {
|
|
286
|
+
expect(D).toBe('\u2012');
|
|
287
|
+
expect(formatNumericValue(undefined, opts(0, 0))).not.toContain('-');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Deliberately short: `maxDigits` reserves the width, so the placeholder sits
|
|
291
|
+
// at the right edge of it rather than spelling out every reserved position.
|
|
292
|
+
it('is one integer dash plus one per fraction digit', () => {
|
|
293
|
+
expect(formatNumericValue(undefined, opts(0, 0))).toBe(D);
|
|
294
|
+
expect(formatNumericValue(undefined, opts(0, 2))).toBe(`${D}.${D}${D}`);
|
|
295
|
+
expect(formatNumericValue(undefined, opts(3, 2))).toBe(`${D}.${D}${D}`);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('does not grow with maxDigits', () => {
|
|
299
|
+
expect(formatNumericValue(undefined, opts(4, 3))).toBe(
|
|
300
|
+
formatNumericValue(undefined, opts(0, 3))
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// `formatNumericValue` is exported, so it must hold the line itself rather
|
|
305
|
+
// than trusting every caller to have normalised first — `NaN.toFixed()`
|
|
306
|
+
// would otherwise put the literal text "NaN" where a reading belongs.
|
|
307
|
+
it('treats a non-finite argument as unavailable without normalisation', () => {
|
|
308
|
+
expect(formatNumericValue(Number.NaN, opts(3, 2))).toBe(`${D}.${D}${D}`);
|
|
309
|
+
expect(formatNumericValue(Number.POSITIVE_INFINITY, opts(3, 2))).toBe(
|
|
310
|
+
`${D}.${D}${D}`
|
|
311
|
+
);
|
|
312
|
+
expect(formatNumericValue(Number.NEGATIVE_INFINITY, opts(3, 2))).toBe(
|
|
313
|
+
`${D}.${D}${D}`
|
|
314
|
+
);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('still formats a finite value', () => {
|
|
318
|
+
expect(formatNumericValue(12.3, opts(3, 2))).toBe('12.30');
|
|
319
|
+
expect(formatNumericValue(0, opts(0, 0))).toBe('0');
|
|
320
|
+
expect(formatNumericValue(-4.5, opts(3, 1))).toBe('-4.5');
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// The whole point of routing non-finite numbers through the same path.
|
|
324
|
+
it('renders a non-finite number as the unavailable dash', () => {
|
|
325
|
+
const resolved = resolveReadoutNumericValue(
|
|
326
|
+
Number.NaN,
|
|
327
|
+
ReadoutValueType.number
|
|
328
|
+
);
|
|
329
|
+
expect(formatNumericValue(resolved, opts(4, 1))).toBe(`${D}.${D}`);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// The designer's specification, verbatim:
|
|
334
|
+
// format: 000.00
|
|
335
|
+
// readout: 12.30
|
|
336
|
+
// readout with hinted: 012.30 (hinted colour on the first zero)
|
|
337
|
+
// Not available: -.-- (revised in review from ---.--)
|
|
338
|
+
// `format: 000.00` is maxDigits 3 + fractionDigits 2.
|
|
339
|
+
describe("designer's format specification (000.00)", () => {
|
|
340
|
+
const MAX_DIGITS = 3;
|
|
341
|
+
const FRACTION_DIGITS = 2;
|
|
342
|
+
const opts = {
|
|
343
|
+
showZeroPadding: false,
|
|
344
|
+
minValueLength: MAX_DIGITS,
|
|
345
|
+
fractionDigits: FRACTION_DIGITS,
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
it('renders a reading as 12.30', () => {
|
|
349
|
+
expect(formatNumericValue(12.3, opts)).toBe('12.30');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// The specification's hinted line (`012.30`) is covered by the hinted-zeros
|
|
353
|
+
// change, not here — this PR only owns the unavailable placeholder. The
|
|
354
|
+
// rendered hinted case is still shown in the story for the designer.
|
|
355
|
+
|
|
356
|
+
it('renders an unavailable value as -.-- (short form)', () => {
|
|
357
|
+
expect(formatNumericValue(undefined, opts)).toBe(
|
|
358
|
+
`${READOUT_UNAVAILABLE_DASH}.${READOUT_UNAVAILABLE_DASH}${READOUT_UNAVAILABLE_DASH}`
|
|
359
|
+
);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// The placeholder is deliberately shorter than the reading now; `maxDigits`
|
|
363
|
+
// reserves the width, so it right-aligns inside it instead of filling it.
|
|
364
|
+
it('is shorter than the reading, sitting at the right of the reserve', () => {
|
|
365
|
+
expect(formatNumericValue(undefined, opts).length).toBeLessThan(
|
|
366
|
+
'012.30'.length
|
|
367
|
+
);
|
|
368
|
+
});
|
|
369
|
+
});
|
|
@@ -71,7 +71,18 @@ export function assertReadoutValueType(
|
|
|
71
71
|
);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* The value as a number, or `undefined` when it is text / unavailable.
|
|
76
|
+
*
|
|
77
|
+
* A non-finite number (`NaN`, `±Infinity`) counts as unavailable and renders the
|
|
78
|
+
* dash, the same as `null`. `NaN` is a runtime data condition — a sensor
|
|
79
|
+
* dropout, a `0/0`, a bad parse — not a programmer error, so it must not throw;
|
|
80
|
+
* and `value.toFixed()` would otherwise render the literal text `"NaN"` /
|
|
81
|
+
* `"Infinity"` in place of a reading. This also makes the number path agree with
|
|
82
|
+
* the string path below, which has always resolved a non-finite string to
|
|
83
|
+
* `undefined` — before this, `<obc-readout value="NaN">` rendered a dash while
|
|
84
|
+
* `.value=${NaN}` rendered `"NaN"`.
|
|
85
|
+
*/
|
|
75
86
|
export function resolveReadoutNumericValue(
|
|
76
87
|
value: number | string | null | undefined,
|
|
77
88
|
valueType: ReadoutValueType
|
|
@@ -84,7 +95,7 @@ export function resolveReadoutNumericValue(
|
|
|
84
95
|
return undefined;
|
|
85
96
|
}
|
|
86
97
|
if (typeof value === 'number') {
|
|
87
|
-
return value;
|
|
98
|
+
return Number.isFinite(value) ? value : undefined;
|
|
88
99
|
}
|
|
89
100
|
if (isBlank(value)) {
|
|
90
101
|
return undefined;
|
|
@@ -109,6 +120,27 @@ export function resolveReadoutTextValue(
|
|
|
109
120
|
return isBlank(text) ? undefined : text;
|
|
110
121
|
}
|
|
111
122
|
|
|
123
|
+
/**
|
|
124
|
+
* The character used for an unavailable ("no reading") value.
|
|
125
|
+
*
|
|
126
|
+
* U+2012 FIGURE DASH, not the ASCII hyphen-minus: it is defined to be the same
|
|
127
|
+
* width as a digit, so the placeholder lines up with the reading it stands in
|
|
128
|
+
* for. Measured in Noto Sans with tabular figures at `size="m"` — digit 13.02px,
|
|
129
|
+
* U+2012 13.02px, U+002D 7.02px, en dash 11.02px, em dash 22.02px. With a
|
|
130
|
+
* hyphen, `-.--` sat 46% narrow per character and its decimal point missed the
|
|
131
|
+
* reading's; with U+2012 the point and every fraction position align exactly.
|
|
132
|
+
*/
|
|
133
|
+
export const READOUT_UNAVAILABLE_DASH = '\u2012';
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The unavailable ("no reading") text: a single integer dash plus one dash per
|
|
137
|
+
* fraction digit — `\u2012` at `fractionDigits` 0, `\u2012.\u2012\u2012` at 2.
|
|
138
|
+
*
|
|
139
|
+
* Deliberately NOT filled out to `maxDigits`: the placeholder stays short and
|
|
140
|
+
* sits at the right edge of the reserved width, rather than spelling out every
|
|
141
|
+
* reserved digit position. `maxDigits` still reserves the width, so nothing
|
|
142
|
+
* shifts when a reading arrives.
|
|
143
|
+
*/
|
|
112
144
|
function dashedGenerator({
|
|
113
145
|
showZeroPadding,
|
|
114
146
|
minValueLength,
|
|
@@ -117,13 +149,15 @@ function dashedGenerator({
|
|
|
117
149
|
const visibleDigits = showZeroPadding ? Math.max(minValueLength, 1) : 1;
|
|
118
150
|
|
|
119
151
|
if (fractionDigits < 1) {
|
|
120
|
-
return
|
|
152
|
+
return READOUT_UNAVAILABLE_DASH.repeat(visibleDigits);
|
|
121
153
|
}
|
|
122
154
|
|
|
123
155
|
const integerDigits = visibleDigits - fractionDigits;
|
|
124
156
|
|
|
125
157
|
return (
|
|
126
|
-
|
|
158
|
+
READOUT_UNAVAILABLE_DASH.repeat(Math.max(integerDigits, 1)) +
|
|
159
|
+
'.' +
|
|
160
|
+
READOUT_UNAVAILABLE_DASH.repeat(fractionDigits)
|
|
127
161
|
);
|
|
128
162
|
}
|
|
129
163
|
|
|
@@ -131,7 +165,11 @@ export function formatNumericValue(
|
|
|
131
165
|
value: number | undefined,
|
|
132
166
|
options: ReadoutNumericFormatOptions
|
|
133
167
|
): string {
|
|
134
|
-
|
|
168
|
+
// Non-finite counts as unavailable here too, not only in
|
|
169
|
+
// `resolveReadoutNumericValue`. Every caller normalises today, but this
|
|
170
|
+
// function is exported, and `NaN.toFixed()` would put the literal text
|
|
171
|
+
// "NaN" where a reading belongs — the exact failure this change removes.
|
|
172
|
+
if (value === undefined || !Number.isFinite(value)) {
|
|
135
173
|
return dashedGenerator(options);
|
|
136
174
|
}
|
|
137
175
|
|
|
@@ -58,6 +58,19 @@ describe('isDisplayedAtSetpoint', () => {
|
|
|
58
58
|
isDisplayedAtSetpoint(30, undefined, readoutNumericFormatOptions(0, 0))
|
|
59
59
|
).toBe(false);
|
|
60
60
|
});
|
|
61
|
+
|
|
62
|
+
// Callers normalise `value` but pass `setpoint` raw, so a non-finite setpoint
|
|
63
|
+
// would otherwise be formatted as the literal "NaN" / "Infinity" and compared
|
|
64
|
+
// as a string. An unavailable reading is never "at" a setpoint.
|
|
65
|
+
it('is false when either side is non-finite', () => {
|
|
66
|
+
const format = readoutNumericFormatOptions(0, 0);
|
|
67
|
+
expect(isDisplayedAtSetpoint(30, Number.NaN, format)).toBe(false);
|
|
68
|
+
expect(isDisplayedAtSetpoint(30, Number.POSITIVE_INFINITY, format)).toBe(
|
|
69
|
+
false
|
|
70
|
+
);
|
|
71
|
+
expect(isDisplayedAtSetpoint(Number.NaN, 30, format)).toBe(false);
|
|
72
|
+
expect(isDisplayedAtSetpoint(Number.NaN, Number.NaN, format)).toBe(false);
|
|
73
|
+
});
|
|
61
74
|
});
|
|
62
75
|
|
|
63
76
|
describe('readoutPrimarySize / readoutSecondarySize', () => {
|
|
@@ -47,6 +47,12 @@ export function readoutNumericFormatOptions(
|
|
|
47
47
|
fractionDigits: number
|
|
48
48
|
): ReadoutNumericFormatOptions {
|
|
49
49
|
return {
|
|
50
|
+
// Comparison-only (see `isDisplayedAtSetpoint`), which returns early unless
|
|
51
|
+
// both operands are finite numbers — so `formatNumericValue` never reaches
|
|
52
|
+
// its unavailable-dash branch here and the padding would have no effect.
|
|
53
|
+
// `obc-readout-block` sets it to `false` for rendering as well, since the
|
|
54
|
+
// unavailable placeholder is deliberately short rather than filled out to
|
|
55
|
+
// `maxDigits`. Nothing enables it today.
|
|
50
56
|
showZeroPadding: false,
|
|
51
57
|
minValueLength: maxDigits,
|
|
52
58
|
fractionDigits,
|
|
@@ -66,6 +72,16 @@ export function isDisplayedAtSetpoint(
|
|
|
66
72
|
if (value === null || setpoint === undefined) {
|
|
67
73
|
return false;
|
|
68
74
|
}
|
|
75
|
+
// An unavailable reading is never "at" the setpoint. Callers normalise
|
|
76
|
+
// `value` (via `resolveReadoutNumericValue`) but pass `setpoint` raw, so a
|
|
77
|
+
// non-finite setpoint would otherwise be formatted as the literal "NaN" /
|
|
78
|
+
// "Infinity" and compared as a string. The comparison result happens to be
|
|
79
|
+
// correct either way — a normalised `value` can never also format to "NaN" —
|
|
80
|
+
// but guarding both keeps the two operands symmetric and the invariant below
|
|
81
|
+
// honest.
|
|
82
|
+
if (!Number.isFinite(value) || !Number.isFinite(setpoint)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
69
85
|
return (
|
|
70
86
|
formatNumericValue(value, formatOptions) ===
|
|
71
87
|
formatNumericValue(setpoint, formatOptions)
|
|
@@ -1303,6 +1303,116 @@ export const TextValue: Story = {
|
|
|
1303
1303
|
]),
|
|
1304
1304
|
};
|
|
1305
1305
|
|
|
1306
|
+
/**
|
|
1307
|
+
* **Unavailable values in a full readout — for design review.**
|
|
1308
|
+
*
|
|
1309
|
+
* The same change as `Building Blocks/Readout Block → Unavailable Values`, shown
|
|
1310
|
+
* with a label and unit so the placeholder can be judged in the context an
|
|
1311
|
+
* instrument actually renders.
|
|
1312
|
+
*
|
|
1313
|
+
* - The placeholder stays short (`-.-`) and sits at the right edge of the width
|
|
1314
|
+
* `maxDigits` reserves, rather than spelling out every reserved position.
|
|
1315
|
+
* - The dash is U+2012 FIGURE DASH, which is digit-width, so its decimal point
|
|
1316
|
+
* and fraction positions line up with the reading it replaces. The ASCII
|
|
1317
|
+
* hyphen is 46% narrower and did not align.
|
|
1318
|
+
* - `NaN` / `±Infinity` render the dash instead of the literal text `NaN` /
|
|
1319
|
+
* `Infinity`.
|
|
1320
|
+
*
|
|
1321
|
+
* Each section pairs the placeholder with a live reading under identical
|
|
1322
|
+
* settings, so the two can be compared directly.
|
|
1323
|
+
*/
|
|
1324
|
+
export const UnavailableValues: Story = {
|
|
1325
|
+
render: () =>
|
|
1326
|
+
renderShowcase([
|
|
1327
|
+
{
|
|
1328
|
+
title: 'Unavailable vs. a Reading (maxDigits 4, Fraction 1)',
|
|
1329
|
+
columns: 3,
|
|
1330
|
+
cases: [
|
|
1331
|
+
{
|
|
1332
|
+
label: 'null → dash',
|
|
1333
|
+
config: {
|
|
1334
|
+
label: 'SOG',
|
|
1335
|
+
unit: 'kn',
|
|
1336
|
+
value: null,
|
|
1337
|
+
options: {maxDigits: 4, fractionDigits: 1},
|
|
1338
|
+
},
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
label: 'NaN → dash (was "NaN")',
|
|
1342
|
+
config: {
|
|
1343
|
+
label: 'SOG',
|
|
1344
|
+
unit: 'kn',
|
|
1345
|
+
value: Number.NaN,
|
|
1346
|
+
options: {maxDigits: 4, fractionDigits: 1},
|
|
1347
|
+
},
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
label: 'reading, identical settings',
|
|
1351
|
+
config: {
|
|
1352
|
+
label: 'SOG',
|
|
1353
|
+
unit: 'kn',
|
|
1354
|
+
value: 12.4,
|
|
1355
|
+
options: {maxDigits: 4, fractionDigits: 1},
|
|
1356
|
+
},
|
|
1357
|
+
},
|
|
1358
|
+
],
|
|
1359
|
+
},
|
|
1360
|
+
{
|
|
1361
|
+
// Both cards enable hintedZeros, so the placeholder and the reading are
|
|
1362
|
+
// compared under identical settings here too.
|
|
1363
|
+
title: 'With Hinted Zeros (maxDigits 4, Fraction 1)',
|
|
1364
|
+
columns: 2,
|
|
1365
|
+
cases: [
|
|
1366
|
+
{
|
|
1367
|
+
label: 'null + hinted zeros',
|
|
1368
|
+
config: {
|
|
1369
|
+
label: 'SOG',
|
|
1370
|
+
unit: 'kn',
|
|
1371
|
+
value: null,
|
|
1372
|
+
options: {
|
|
1373
|
+
maxDigits: 4,
|
|
1374
|
+
fractionDigits: 1,
|
|
1375
|
+
value: {hintedZeros: true},
|
|
1376
|
+
},
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
label: 'reading + hinted zeros',
|
|
1381
|
+
config: {
|
|
1382
|
+
label: 'SOG',
|
|
1383
|
+
unit: 'kn',
|
|
1384
|
+
value: 12.4,
|
|
1385
|
+
options: {
|
|
1386
|
+
maxDigits: 4,
|
|
1387
|
+
fractionDigits: 1,
|
|
1388
|
+
value: {hintedZeros: true},
|
|
1389
|
+
},
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
],
|
|
1393
|
+
},
|
|
1394
|
+
{
|
|
1395
|
+
title: 'No maxDigits — Same Placeholder, Narrower Reserve',
|
|
1396
|
+
columns: 2,
|
|
1397
|
+
cases: [
|
|
1398
|
+
{
|
|
1399
|
+
label: 'null',
|
|
1400
|
+
config: {label: 'SOG', unit: 'kn', value: null, options: {}},
|
|
1401
|
+
},
|
|
1402
|
+
{
|
|
1403
|
+
label: 'null / fraction 1',
|
|
1404
|
+
config: {
|
|
1405
|
+
label: 'SOG',
|
|
1406
|
+
unit: 'kn',
|
|
1407
|
+
value: null,
|
|
1408
|
+
options: {fractionDigits: 1},
|
|
1409
|
+
},
|
|
1410
|
+
},
|
|
1411
|
+
],
|
|
1412
|
+
},
|
|
1413
|
+
]),
|
|
1414
|
+
};
|
|
1415
|
+
|
|
1306
1416
|
export const TestCases: Story = {
|
|
1307
1417
|
render: () => {
|
|
1308
1418
|
return html` <style>
|