dev-api-ui 0.1.7 → 0.1.8

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/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "dev-api-ui",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
+ "private": false,
4
5
  "files": [
5
6
  "ui"
6
7
  ],
@@ -145,7 +145,12 @@ function deltaColor(up: boolean): string {
145
145
 
146
146
  // The shared table / list layout used in both list and search modes
147
147
  function RowTable({ rows, group }: { rows: Row[]; group: string }) {
148
- const slugFor = (r: Row) => r.slug;
148
+ // Derive the route slug from the symbol so it always follows the house lowercase-hyphen
149
+ // convention (EUR/USD → eur-usd), matching every vertical's /<group>/<base>-<quote> routes.
150
+ // The hand-maintained `slug` field shipped un-hyphenated demo values (eurusd) that 404'd on the
151
+ // real hyphenated routes (BUG-3); deriving removes that drift class. Symbols without a slash
152
+ // (energy: PJM-RT) pass through lowercased, matching their existing slugs.
153
+ const slugFor = (r: Row) => r.sym.toLowerCase().replace('/', '-');
149
154
  return (
150
155
  <div
151
156
  style={{
package/ui/format.ts ADDED
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Currency/number formatting helpers backed by Intl.NumberFormat + CLDR.
3
+ * Zero-decimal currencies (JPY, KRW, VND, …) render without fractional digits
4
+ * automatically — no lookup table required.
5
+ */
6
+
7
+ /**
8
+ * Returns the correct maximumFractionDigits for a currency code, or 2 on error.
9
+ * Uses a throw-away Intl.NumberFormat so we never duplicate CLDR data.
10
+ */
11
+ function fractionDigits(currencyCode: string, locale: string): number {
12
+ try {
13
+ return new Intl.NumberFormat(locale, {
14
+ style: 'currency',
15
+ currency: currencyCode,
16
+ }).resolvedOptions().maximumFractionDigits ?? 2;
17
+ } catch {
18
+ return 2;
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Formats `value` as a localised currency string including the symbol/code.
24
+ * Uses Intl.NumberFormat so minor-unit digit count is correct per ISO-4217
25
+ * (JPY → 0 decimals, USD → 2, BHD → 3, etc.).
26
+ * Falls back to a plain number string if `currencyCode` is invalid.
27
+ */
28
+ export function formatCurrencyAmount(
29
+ value: number,
30
+ currencyCode: string,
31
+ locale = 'en-US',
32
+ ): string {
33
+ try {
34
+ return new Intl.NumberFormat(locale, {
35
+ style: 'currency',
36
+ currency: currencyCode,
37
+ }).format(value);
38
+ } catch {
39
+ return new Intl.NumberFormat(locale).format(value);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Formats `value` with the correct decimal precision for `currencyCode` but
45
+ * WITHOUT a currency symbol — for callers that render their own prefix/suffix.
46
+ * Falls back to 2 decimal places if `currencyCode` is invalid.
47
+ */
48
+ export function formatCurrencyNumber(
49
+ value: number,
50
+ currencyCode: string,
51
+ locale = 'en-US',
52
+ ): string {
53
+ const digits = fractionDigits(currencyCode, locale);
54
+ return new Intl.NumberFormat(locale, {
55
+ style: 'decimal',
56
+ minimumFractionDigits: digits,
57
+ maximumFractionDigits: digits,
58
+ }).format(value);
59
+ }
package/ui/index.ts CHANGED
@@ -48,3 +48,6 @@ export { default as StatusMark } from './components/StatusMark';
48
48
  // The illustrative SERIES_DATA blob stays internal (demo-only, not public API).
49
49
  export { getSeriesData } from './data/series';
50
50
  export type { RangeEntry, RelatedEntry, ReadingEntry, SeriesData } from './data/series';
51
+
52
+ // Formatting helpers
53
+ export { formatCurrencyAmount, formatCurrencyNumber } from './format';