@sjvair/map-sdk 0.1.0-beta.5 → 0.1.0-beta.6

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/README.md CHANGED
@@ -548,6 +548,16 @@ local sjvair.com stack at `http://localhost:8000`.
548
548
 
549
549
  ## Changes
550
550
 
551
+ ### 0.1.0-beta.6
552
+
553
+ - **A category reading is shown once.** When a feature's value is its category level's code, the
554
+ list row, the tooltip, and the row's accessible name show only the level label. Smoke rows read
555
+ "Smoke, Light" (was "light Light"), burn status "Burning Discouraged", and heat score
556
+ "Moderate" (the 0–4 number is no longer shown). Number scales such as PM2.5 and fire power are
557
+ unchanged, and a category value that matches no level is still shown.
558
+ - **New message key for hosts with their own catalog:** `mapsdk_list_row_level`
559
+ (`"{name}, {level}"`).
560
+
551
561
  ### 0.1.0-beta.5
552
562
 
553
563
  - **Shapes that cover the view are in view.** The feature list and the view summary count a shape
@@ -8,6 +8,7 @@
8
8
  "mapsdk_list_row": "{name}, {value} {units}, {level}",
9
9
  "mapsdk_list_row_no_units": "{name}, {value}, {level}",
10
10
  "mapsdk_list_row_no_value": "{name}, no reading",
11
+ "mapsdk_list_row_level": "{name}, {level}",
11
12
  "mapsdk_list_row_detail": "{name}, {detail}",
12
13
  "mapsdk_list_empty": "Nothing on the map in this view",
13
14
  "mapsdk_selected_count_one": "{count} selected",
@@ -11,11 +11,11 @@
11
11
  rowLabel,
12
12
  levelText,
13
13
  shownLevel,
14
+ shownValue,
14
15
  sortItems,
15
16
  typeaheadIndex,
16
17
  type SortBy
17
18
  } from "./feature-list.js";
18
- import { formatValue as formatNumber } from "./value-format.js";
19
19
 
20
20
  interface Props {
21
21
  map: MapContext;
@@ -267,13 +267,6 @@
267
267
  pick(rows[index], e.shiftKey || e.metaKey || e.ctrlKey);
268
268
  }
269
269
 
270
- function formatValue(row: Row): string {
271
- if (row.value === null) return "";
272
- return typeof row.value === "number"
273
- ? formatNumber(row.value, row.precision, map.format, row.truncate)
274
- : row.value;
275
- }
276
-
277
270
  onDestroy(() => {
278
271
  clearTimeout(typeaheadTimer);
279
272
  clearTimeout(menuSentTimer);
@@ -332,6 +325,7 @@
332
325
  {@const index = range.start + i}
333
326
  {@const level = shownLevel(row)}
334
327
  {@const levelPlace = levelText(row, map.messages)}
328
+ {@const value = shownValue(row, map.format)}
335
329
  {@const isOn = isSelected(row)}
336
330
  <!-- Options aren't focused: the listbox holds focus and handles keys (aria-activedescendant). -->
337
331
  <!-- svelte-ignore a11y_click_events_have_key_events, a11y_interactive_supports_focus -->
@@ -359,7 +353,7 @@
359
353
  </span>
360
354
  <span class="mapsdk-list-name">{row.name}</span>
361
355
  <span class="mapsdk-list-value">
362
- {formatValue(row)}{#if row.units && row.value !== null}&nbsp;{row.units}{/if}
356
+ {value ?? ""}{#if row.units && value !== null}&nbsp;{row.units}{/if}
363
357
  </span>
364
358
  <span class="mapsdk-list-level text-xs">
365
359
  {#if levelPlace.kind !== "detail"}
@@ -3,9 +3,8 @@
3
3
  import type { MessageProvider } from "../data/messages.js";
4
4
  import type { FeatureListItem } from "../core/plugin.js";
5
5
  import { NO_LEVEL } from "../data/scale.js";
6
- import { levelText } from "./feature-list.js";
6
+ import { levelText, shownValue } from "./feature-list.js";
7
7
  import { levelChip } from "./level-chip.js";
8
- import { formatValue } from "./value-format.js";
9
8
 
10
9
  // The generic tooltip body under a feature's name: its value and a chip with its level. Shared
11
10
  // by MapTooltip and by plugins that show it for features they don't list.
@@ -26,13 +25,8 @@
26
25
  const chip = levelChip(level?.color);
27
26
  return chip ? `background:${chip.background};color:${chip.text}` : "";
28
27
  });
29
- const valueText = $derived(
30
- item.value == null
31
- ? null
32
- : typeof item.value === "number"
33
- ? formatValue(item.value, item.precision, format, item.truncate)
34
- : item.value
35
- );
28
+ // A category reading shows only its level chip: its value is the level's code.
29
+ const valueText = $derived(shownValue(item, format));
36
30
  </script>
37
31
 
38
32
  <div class="mapsdk-tooltip-item">
@@ -26,6 +26,11 @@ export declare function inView(items: FeatureListItem[], bounds: Bounds): Featur
26
26
  * label on a neutral swatch.
27
27
  */
28
28
  export declare function shownLevel(item: FeatureListItem): Level | null;
29
+ /**
30
+ * The value as shown, or `null` for none. A category reading, whose value is its level's code
31
+ * (smoke's "light", the heat score's 2), shows no value: its level label already says it.
32
+ */
33
+ export declare function shownValue(item: FeatureListItem, format: FormatProvider): string | null;
29
34
  /** A sorted copy. `value`: highest first, null values and no level last; ties and `name` by name. */
30
35
  export declare function sortItems(items: FeatureListItem[], by: SortBy): FeatureListItem[];
31
36
  /** The first index at or after `from` (wrapping) whose name starts with `query`, any case; -1 if none. */
@@ -29,6 +29,20 @@ export function inView(items, bounds) {
29
29
  export function shownLevel(item) {
30
30
  return item.level !== NO_LEVEL ? item.level : null;
31
31
  }
32
+ /**
33
+ * The value as shown, or `null` for none. A category reading, whose value is its level's code
34
+ * (smoke's "light", the heat score's 2), shows no value: its level label already says it.
35
+ */
36
+ export function shownValue(item, format) {
37
+ if (item.value === null)
38
+ return null;
39
+ const level = shownLevel(item);
40
+ if (level && level.value !== null && level.value === item.value)
41
+ return null;
42
+ return typeof item.value === "number"
43
+ ? formatValue(item.value, item.precision, format, item.truncate)
44
+ : item.value;
45
+ }
32
46
  const collator = new Intl.Collator("en-US");
33
47
  /** A value's sort weight; `null` sorts last. Category values sort by their level's tier. */
34
48
  function weight(item) {
@@ -82,16 +96,18 @@ export function levelText(item, messages) {
82
96
  /** A row's accessible name: name, value, units, and level label (or detail). */
83
97
  export function rowLabel(item, messages, format) {
84
98
  const level = levelText(item, messages);
85
- if (item.value === null) {
99
+ const value = shownValue(item, format);
100
+ if (value === null) {
101
+ // A category reading: its level is its value.
102
+ if (item.value !== null && level.kind === "level")
103
+ return messages("mapsdk_list_row_level", { name: item.name, level: level.text });
86
104
  return level.kind === "detail"
87
105
  ? messages("mapsdk_list_row_detail", { name: item.name, detail: level.text })
88
106
  : messages("mapsdk_list_row_no_value", { name: item.name });
89
107
  }
90
108
  const params = {
91
109
  name: item.name,
92
- value: typeof item.value === "number"
93
- ? formatValue(item.value, item.precision, format, item.truncate)
94
- : item.value,
110
+ value,
95
111
  units: item.units,
96
112
  level: level.text
97
113
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjvair/map-sdk",
3
3
  "description": "Svelte 5 map components for SJVAir air-quality data",
4
- "version": "0.1.0-beta.5",
4
+ "version": "0.1.0-beta.6",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",