@mt-gloss/utils 0.1.65 → 0.1.67

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/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { isStatusModeEnabled, v1_1_status_mode, V1_1_STATUS_MODE_ENV, isEdgeHoverResizeEnabled, v1_1_edge_hover_resize, V1_1_EDGE_HOVER_RESIZE_ENV } from './lib/featureFlags';
2
2
  export type { PresetDefinition, MarketPreset, DateRange, MarketEvent } from './lib/types';
3
- export { formatValue, getValueFontSize } from './lib/formatValue';
4
- export type { FormatValueOptions, FormattedValue } from './lib/formatValue';
3
+ export { formatValue, getValueFontSize, pickMetricTier } from './lib/formatValue';
4
+ export type { FormatValueOptions, FormattedValue, MetricTier, PickMetricTierResult } from './lib/formatValue';
5
5
  export { formatTrend } from './lib/formatTrend';
6
6
  export type { TrendDirection, FormattedTrend } from './lib/formatTrend';
7
7
  export { formatDateRange, formatMarketDates, isMarketActive, isSameDay, isInRange, generateMarketId } from './lib/dateHelpers';
package/index.js CHANGED
@@ -1,109 +1,132 @@
1
- import { D as v, y as F, P as I, n as O, o as U, R as V, T as b, d as A, t as N, f as Y, b as G, k as z, l as k, c as H, h as Z, x, g as B, q as C, j as K, m as X, u as j, i as q, v as W, p as J, a as Q, r as w, s as ee, e as te, w as ne } from "./formatting-dHqp6ksD.js";
2
- const l = "NEXT_PUBLIC_V1_1_STATUS_MODE";
1
+ import { D as U, y as N, P as v, n as A, o as O, R as V, T as G, d as Y, t as x, f as z, b as k, k as w, l as H, c as B, h as C, x as Z, g as K, q as X, j, m as q, u as W, i as J, v as Q, p as tt, a as et, r as nt, s as rt, e as at, w as st } from "./formatting-dHqp6ksD.js";
2
+ const g = "NEXT_PUBLIC_V1_1_STATUS_MODE";
3
3
  function _() {
4
- return typeof globalThis < "u" && globalThis.__GLOSS_FLAGS__?.v1_1_status_mode === !0 ? !0 : typeof process < "u" && process.env ? process.env[l] === "true" : !1;
4
+ return typeof globalThis < "u" && globalThis.__GLOSS_FLAGS__?.v1_1_status_mode === !0 ? !0 : typeof process < "u" && process.env ? process.env[g] === "true" : !1;
5
5
  }
6
6
  const $ = {
7
- env: l,
7
+ env: g,
8
8
  check: _
9
- }, f = "NEXT_PUBLIC_V1_1_EDGE_HOVER_RESIZE";
9
+ }, m = "NEXT_PUBLIC_V1_1_EDGE_HOVER_RESIZE";
10
10
  function D() {
11
- return typeof globalThis < "u" && globalThis.__GLOSS_FLAGS__?.v1_1_edge_hover_resize === !0 ? !0 : typeof process < "u" && process.env ? process.env[f] === "true" : !1;
11
+ return typeof globalThis < "u" && globalThis.__GLOSS_FLAGS__?.v1_1_edge_hover_resize === !0 ? !0 : typeof process < "u" && process.env ? process.env[m] === "true" : !1;
12
12
  }
13
13
  const S = {
14
- env: f,
14
+ env: m,
15
15
  check: D
16
16
  };
17
- function m(e, { prefix: t = "", suffix: n = "", abbreviated: a = !0, kThreshold: s = 1e3 } = {}) {
18
- if (e == null) {
19
- const c = t ? `${t} —${n}` : `—${n}`;
20
- return { display: c.trim(), full: c.trim(), length: c.trim().length };
17
+ function d(t, { prefix: e = "", suffix: n = "", abbreviated: a = !0, kThreshold: s = 1e3 } = {}) {
18
+ if (t == null) {
19
+ const l = e ? `${e} —${n}` : `—${n}`;
20
+ return { display: l.trim(), full: l.trim(), length: l.trim().length };
21
21
  }
22
- const r = typeof e == "number" ? e : parseFloat(String(e).replace(/,/g, ""));
22
+ const r = typeof t == "number" ? t : parseFloat(String(t).replace(/,/g, ""));
23
23
  if (isNaN(r)) {
24
- const u = `${t}${e}${n}`;
24
+ const u = `${e}${t}${n}`;
25
25
  return { display: u, full: u, length: u.length };
26
26
  }
27
27
  let o;
28
28
  a !== !1 && Math.abs(r) >= 1e6 ? o = (r / 1e6).toFixed(1).replace(/\.0$/, "") + "M" : a !== !1 && Math.abs(r) >= s ? o = (r / 1e3).toFixed(1).replace(/\.0$/, "") + "K" : o = r.toLocaleString("en-US");
29
- const i = `${t}${o}${n}`, g = `${t}${r.toLocaleString("en-US")}${n}`;
30
- return { display: i, full: g, length: i.length };
29
+ const i = `${e}${o}${n}`, c = `${e}${r.toLocaleString("en-US")}${n}`;
30
+ return { display: i, full: c, length: i.length };
31
31
  }
32
- function h(e, t) {
33
- return (t ?? 1) >= 2 ? e <= 4 || e <= 6 ? 30 : e <= 8 ? 24 : 20 : e <= 5 ? 28 : e <= 8 ? 20 : 17;
32
+ function E(t, e) {
33
+ return (e ?? 1) >= 2 ? t <= 4 || t <= 6 ? 30 : t <= 8 ? 24 : 20 : t <= 5 ? 28 : t <= 8 ? 20 : 17;
34
34
  }
35
- function E(e) {
36
- if (e == null || e === 0)
35
+ const f = {
36
+ 1: 5,
37
+ // "$2.7K", "12K", "$5", "100%"
38
+ 2: 8,
39
+ // "$2,720", "$12.5K"
40
+ 3: 12
41
+ // "$1,234,567"
42
+ };
43
+ function h(t) {
44
+ return t <= 1 ? f[1] : t >= 3 ? f[3] : f[t] ?? f[1];
45
+ }
46
+ function p(t, e = {}, n = 1) {
47
+ const a = h(n), s = e.prefix ?? "", r = e.suffix ?? "", o = typeof t == "number" ? t : parseFloat(String(t ?? "").replace(/,/g, ""));
48
+ if (t != null && !Number.isNaN(o)) {
49
+ const c = `${s}${o.toLocaleString("en-US", { minimumFractionDigits: Number.isInteger(o) ? 0 : 2, maximumFractionDigits: 2 })}${r}`;
50
+ if (c.length <= a) return { formatted: c, tier: "wide", length: c.length };
51
+ const u = `${s}${Math.round(o).toLocaleString("en-US")}${r}`;
52
+ if (u.length <= a) return { formatted: u, tier: "medium", length: u.length };
53
+ }
54
+ const i = d(t, { ...e, abbreviated: !0 });
55
+ return i.display.length <= a ? { formatted: i.display, tier: "narrow", length: i.display.length } : { formatted: i.display, tier: "very-narrow", length: i.display.length };
56
+ }
57
+ function T(t) {
58
+ if (t == null || t === 0)
37
59
  return { text: "0%", direction: "flat" };
38
- const t = e > 0 ? "up" : e < 0 ? "down" : "flat", n = Math.abs(e);
39
- return { text: n >= 3 ? `${Math.round(n)}%` : `${n.toFixed(1)}%`, direction: t };
60
+ const e = t > 0 ? "up" : t < 0 ? "down" : "flat", n = Math.abs(t);
61
+ return { text: n >= 3 ? `${Math.round(n)}%` : `${n.toFixed(1)}%`, direction: e };
40
62
  }
41
- function d(e, t) {
42
- if (!e || !t) return "";
43
- const n = e.toLocaleDateString("en-US", { month: "short" }), a = t.toLocaleDateString("en-US", { month: "short" }), s = e.getDate(), r = t.getDate(), o = e.getFullYear(), i = t.getFullYear();
44
- return e.getTime() === t.getTime() || n === a && s === r && o === i ? `${n} ${s}, ${o}` : n === a && o === i ? `${n} ${s}–${r}` : o === i ? `${n} ${s} – ${a} ${r}` : `${n} ${s}, ${o} – ${a} ${r}, ${i}`;
63
+ function y(t, e) {
64
+ if (!t || !e) return "";
65
+ const n = t.toLocaleDateString("en-US", { month: "short" }), a = e.toLocaleDateString("en-US", { month: "short" }), s = t.getDate(), r = e.getDate(), o = t.getFullYear(), i = e.getFullYear();
66
+ return t.getTime() === e.getTime() || n === a && s === r && o === i ? `${n} ${s}, ${o}` : n === a && o === i ? `${n} ${s}–${r}` : o === i ? `${n} ${s} – ${a} ${r}` : `${n} ${s}, ${o} – ${a} ${r}, ${i}`;
45
67
  }
46
- function p(e, t) {
47
- const n = e.toLocaleDateString("en-US", { month: "short" }), a = t.toLocaleDateString("en-US", { month: "short" }), s = e.getDate(), r = t.getDate();
68
+ function M(t, e) {
69
+ const n = t.toLocaleDateString("en-US", { month: "short" }), a = e.toLocaleDateString("en-US", { month: "short" }), s = t.getDate(), r = e.getDate();
48
70
  return n === a ? `${n} ${s}–${r}` : `${n} ${s} – ${a} ${r}`;
49
71
  }
50
- function T(e, t = /* @__PURE__ */ new Date()) {
51
- return !e?.startDate || !e?.endDate ? !1 : t >= e.startDate && t <= e.endDate;
72
+ function R(t, e = /* @__PURE__ */ new Date()) {
73
+ return !t?.startDate || !t?.endDate ? !1 : e >= t.startDate && e <= t.endDate;
52
74
  }
53
- function P(e, t) {
54
- return !e || !t ? !1 : e.getFullYear() === t.getFullYear() && e.getMonth() === t.getMonth() && e.getDate() === t.getDate();
75
+ function P(t, e) {
76
+ return !t || !e ? !1 : t.getFullYear() === e.getFullYear() && t.getMonth() === e.getMonth() && t.getDate() === e.getDate();
55
77
  }
56
- function R(e, t, n) {
57
- if (!e || !t || !n) return !1;
58
- const a = e.getTime(), s = t.getTime(), r = n.getTime();
78
+ function F(t, e, n) {
79
+ if (!t || !e || !n) return !1;
80
+ const a = t.getTime(), s = e.getTime(), r = n.getTime();
59
81
  return a >= Math.min(s, r) && a <= Math.max(s, r);
60
82
  }
61
- function M() {
83
+ function L() {
62
84
  return `custom-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
63
85
  }
64
86
  export {
65
- v as DEFAULT_MARKET_PRESETS,
66
- F as DEFAULT_PINNED,
67
- I as PERIOD_OPTIONS,
68
- O as PRESET_ID_MAP,
69
- U as PRESET_ID_REVERSE_MAP,
87
+ U as DEFAULT_MARKET_PRESETS,
88
+ N as DEFAULT_PINNED,
89
+ v as PERIOD_OPTIONS,
90
+ A as PRESET_ID_MAP,
91
+ O as PRESET_ID_REVERSE_MAP,
70
92
  V as ROLLING_OPTIONS,
71
- b as TODAY_PRESET,
72
- f as V1_1_EDGE_HOVER_RESIZE_ENV,
73
- l as V1_1_STATUS_MODE_ENV,
74
- A as detectPreset,
75
- N as findPreset,
76
- d as formatDateRange,
77
- Y as formatDateRangeSmart,
78
- G as formatDateRangeWithPreset,
79
- z as formatDuration,
80
- p as formatMarketDates,
81
- k as formatPreset,
82
- H as formatShortYear,
83
- Z as formatSingleDate,
84
- E as formatTrend,
85
- m as formatValue,
86
- M as generateMarketId,
87
- x as getAllPresets,
88
- B as getDateRangeDisplayInfo,
89
- C as getDateRangeForPreset,
90
- K as getDurationDays,
91
- X as getPresetDateRange,
92
- j as getPresetLabel,
93
- h as getValueFontSize,
93
+ G as TODAY_PRESET,
94
+ m as V1_1_EDGE_HOVER_RESIZE_ENV,
95
+ g as V1_1_STATUS_MODE_ENV,
96
+ Y as detectPreset,
97
+ x as findPreset,
98
+ y as formatDateRange,
99
+ z as formatDateRangeSmart,
100
+ k as formatDateRangeWithPreset,
101
+ w as formatDuration,
102
+ M as formatMarketDates,
103
+ H as formatPreset,
104
+ B as formatShortYear,
105
+ C as formatSingleDate,
106
+ T as formatTrend,
107
+ d as formatValue,
108
+ L as generateMarketId,
109
+ Z as getAllPresets,
110
+ K as getDateRangeDisplayInfo,
111
+ X as getDateRangeForPreset,
112
+ j as getDurationDays,
113
+ q as getPresetDateRange,
114
+ W as getPresetLabel,
115
+ E as getValueFontSize,
94
116
  D as isEdgeHoverResizeEnabled,
95
- R as isInRange,
96
- T as isMarketActive,
117
+ F as isInRange,
118
+ R as isMarketActive,
97
119
  P as isSameDay,
98
120
  _ as isStatusModeEnabled,
99
- q as isValidDateRangeFormat,
100
- W as normalizePresetId,
101
- J as parseDateRange,
102
- Q as resolveEvent,
103
- w as resolvePreset,
104
- ee as smartDateFormat,
105
- te as stripLeadingZeros,
106
- ne as toUppercasePresetId,
121
+ J as isValidDateRangeFormat,
122
+ Q as normalizePresetId,
123
+ tt as parseDateRange,
124
+ p as pickMetricTier,
125
+ et as resolveEvent,
126
+ nt as resolvePreset,
127
+ rt as smartDateFormat,
128
+ at as stripLeadingZeros,
129
+ st as toUppercasePresetId,
107
130
  S as v1_1_edge_hover_resize,
108
131
  $ as v1_1_status_mode
109
132
  };
@@ -37,4 +37,34 @@ export declare function formatValue(raw: number | string | null | undefined, { p
37
37
  * ```
38
38
  */
39
39
  export declare function getValueFontSize(length: number, colSpan?: number | null): number;
40
+ export type MetricTier = 'wide' | 'medium' | 'narrow' | 'very-narrow';
41
+ export interface PickMetricTierResult {
42
+ /** The display string at the chosen tier (e.g. `$2.7K`). */
43
+ formatted: string;
44
+ /** Which tier of the ladder produced `formatted`. Drives data-tier in MetricCard. */
45
+ tier: MetricTier;
46
+ /** `formatted.length`, for downstream `getValueFontSize`. */
47
+ length: number;
48
+ }
49
+ /**
50
+ * Walk Wide → Medium → Narrow → VeryNarrow and return the first format whose
51
+ * length fits CHAR_BUDGETS[colSpan]. Synchronous, prop-driven, content-aware.
52
+ *
53
+ * - Wide: full locale string with decimals (e.g. `$2,720.00`)
54
+ * - Medium: full locale string, no decimals (e.g. `$2,720`)
55
+ * - Narrow: alpha-suffix abbreviated (e.g. `$2.7K`)
56
+ * - VeryNarrow: alpha-suffix abbreviated; the SCSS title-clamp toggle
57
+ * fires on this tier even if VeryNarrow's string === Narrow's
58
+ *
59
+ * NOT a measurement loop. NO ResizeObserver. NO getBoundingClientRect.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * import { pickMetricTier } from '@mt-gloss/utils';
64
+ *
65
+ * const r = pickMetricTier(2720, { prefix: '$' }, 1);
66
+ * // r.tier === 'narrow', r.formatted === '$2.7K'
67
+ * ```
68
+ */
69
+ export declare function pickMetricTier(value: number | string | null | undefined, options?: FormatValueOptions, colSpan?: number): PickMetricTierResult;
40
70
  //# sourceMappingURL=formatValue.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mt-gloss/utils",
3
- "version": "0.1.65",
3
+ "version": "0.1.67",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "restricted"