@mt-gloss/utils 0.1.150 → 0.1.152
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 +3 -0
- package/index.js +139 -99
- package/lib/color.d.ts +26 -0
- package/lib/cssAnimation.d.ts +36 -0
- package/lib/toLocalCalendarDate.d.ts +36 -0
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -4,8 +4,11 @@ export { formatValue, getValueFontSize, pickMetricTier } from './lib/formatValue
|
|
|
4
4
|
export type { FormatValueOptions, FormattedValue, MetricTier, PickMetricTierResult } from './lib/formatValue';
|
|
5
5
|
export { formatCurrency } from './lib/formatCurrency';
|
|
6
6
|
export type { FormatCurrencyOptions } from './lib/formatCurrency';
|
|
7
|
+
export { hexToRgba, lerpHex } from './lib/color';
|
|
8
|
+
export { getTransitionStyle, interpolate, parseNumericValue } from './lib/cssAnimation';
|
|
7
9
|
export { daysBetween } from './lib/daysBetween';
|
|
8
10
|
export type { DaysBetweenOptions, DaysBetweenRounding } from './lib/daysBetween';
|
|
11
|
+
export { toLocalCalendarDate } from './lib/toLocalCalendarDate';
|
|
9
12
|
export { formatTrend } from './lib/formatTrend';
|
|
10
13
|
export type { TrendDirection, FormattedTrend } from './lib/formatTrend';
|
|
11
14
|
export { formatDateRange, formatMarketDates, isMarketActive, isSameDay, isInRange, generateMarketId } from './lib/dateHelpers';
|
package/index.js
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
const
|
|
3
|
-
function
|
|
4
|
-
return typeof globalThis < "u" && globalThis.__GLOSS_FLAGS__?.v1_1_status_mode === !0 ? !0 : typeof process < "u" && process.env ? process.env[
|
|
5
|
-
}
|
|
6
|
-
const $ = {
|
|
7
|
-
env: g,
|
|
8
|
-
check: d
|
|
9
|
-
}, m = "NEXT_PUBLIC_V1_1_EDGE_HOVER_RESIZE";
|
|
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[m] === "true" : !1;
|
|
1
|
+
import { D as G, y as z, P as H, n as k, o as B, R as Z, T as j, d as K, t as X, f as q, b as W, k as J, l as Q, c as tt, h as et, x as nt, g as rt, q as at, j as ot, m as st, u as it, i as ut, v as ct, p as lt, a as ft, r as gt, s as mt, e as dt, w as ht } from "./formatting-dHqp6ksD.js";
|
|
2
|
+
const m = "NEXT_PUBLIC_V1_1_STATUS_MODE";
|
|
3
|
+
function h() {
|
|
4
|
+
return typeof globalThis < "u" && globalThis.__GLOSS_FLAGS__?.v1_1_status_mode === !0 ? !0 : typeof process < "u" && process.env ? process.env[m] === "true" : !1;
|
|
12
5
|
}
|
|
13
6
|
const p = {
|
|
14
7
|
env: m,
|
|
15
|
-
check:
|
|
8
|
+
check: h
|
|
9
|
+
}, d = "NEXT_PUBLIC_V1_1_EDGE_HOVER_RESIZE";
|
|
10
|
+
function $() {
|
|
11
|
+
return typeof globalThis < "u" && globalThis.__GLOSS_FLAGS__?.v1_1_edge_hover_resize === !0 ? !0 : typeof process < "u" && process.env ? process.env[d] === "true" : !1;
|
|
12
|
+
}
|
|
13
|
+
const M = {
|
|
14
|
+
env: d,
|
|
15
|
+
check: $
|
|
16
16
|
};
|
|
17
|
-
function
|
|
17
|
+
function D(t, { prefix: e = "", suffix: n = "", abbreviated: r = !0, kThreshold: o = 1e3 } = {}) {
|
|
18
18
|
if (t == null) {
|
|
19
|
-
const
|
|
20
|
-
return { display:
|
|
19
|
+
const l = e ? `${e} —${n}` : `—${n}`;
|
|
20
|
+
return { display: l.trim(), full: l.trim(), length: l.trim().length };
|
|
21
21
|
}
|
|
22
|
-
const
|
|
23
|
-
if (isNaN(
|
|
22
|
+
const a = typeof t == "number" ? t : parseFloat(String(t).replace(/,/g, ""));
|
|
23
|
+
if (isNaN(a)) {
|
|
24
24
|
const u = `${e}${t}${n}`;
|
|
25
25
|
return { display: u, full: u, length: u.length };
|
|
26
26
|
}
|
|
27
27
|
let s;
|
|
28
|
-
|
|
29
|
-
const i = `${e}${s}${n}`,
|
|
30
|
-
return { display: i, full:
|
|
28
|
+
r !== !1 && Math.abs(a) >= 1e6 ? s = (a / 1e6).toFixed(1).replace(/\.0$/, "") + "M" : r !== !1 && Math.abs(a) >= o ? s = (a / 1e3).toFixed(1).replace(/\.0$/, "") + "K" : s = a.toLocaleString("en-US");
|
|
29
|
+
const i = `${e}${s}${n}`, c = `${e}${a.toLocaleString("en-US")}${n}`;
|
|
30
|
+
return { display: i, full: c, length: i.length };
|
|
31
31
|
}
|
|
32
32
|
function E(t, e) {
|
|
33
33
|
return (e ?? 1) >= 2 ? t <= 4 || t <= 6 ? 30 : t <= 8 ? 24 : 20 : t <= 5 ? 28 : t <= 8 ? 20 : 17;
|
|
34
34
|
}
|
|
35
|
-
const
|
|
35
|
+
const f = {
|
|
36
36
|
1: 5,
|
|
37
37
|
// "$2.7K", "12K", "$5", "100%"
|
|
38
38
|
2: 8,
|
|
@@ -40,111 +40,151 @@ const l = {
|
|
|
40
40
|
3: 12
|
|
41
41
|
// "$1,234,567"
|
|
42
42
|
};
|
|
43
|
-
function
|
|
44
|
-
return t <= 1 ?
|
|
43
|
+
function _(t) {
|
|
44
|
+
return t <= 1 ? f[1] : t >= 3 ? f[3] : f[t] ?? f[1];
|
|
45
45
|
}
|
|
46
|
-
function
|
|
47
|
-
const
|
|
46
|
+
function T(t, e = {}, n = 1) {
|
|
47
|
+
const r = _(n), o = e.prefix ?? "", a = e.suffix ?? "", s = typeof t == "number" ? t : parseFloat(String(t ?? "").replace(/,/g, ""));
|
|
48
48
|
if (t != null && !Number.isNaN(s)) {
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
const u = `${
|
|
52
|
-
if (u.length <=
|
|
49
|
+
const c = `${o}${s.toLocaleString("en-US", { minimumFractionDigits: Number.isInteger(s) ? 0 : 2, maximumFractionDigits: 2 })}${a}`;
|
|
50
|
+
if (c.length <= r) return { formatted: c, tier: "wide", length: c.length };
|
|
51
|
+
const u = `${o}${Math.round(s).toLocaleString("en-US")}${a}`;
|
|
52
|
+
if (u.length <= r) return { formatted: u, tier: "medium", length: u.length };
|
|
53
53
|
}
|
|
54
|
-
const i =
|
|
55
|
-
return i.display.length <=
|
|
54
|
+
const i = D(t, { ...e, abbreviated: !0 });
|
|
55
|
+
return i.display.length <= r ? { formatted: i.display, tier: "narrow", length: i.display.length } : { formatted: i.display, tier: "very-narrow", length: i.display.length };
|
|
56
56
|
}
|
|
57
|
-
function y(t, { notation: e = "standard", fractionDigits: n, currency:
|
|
58
|
-
const
|
|
57
|
+
function y(t, { notation: e = "standard", fractionDigits: n, currency: r = "USD" } = {}) {
|
|
58
|
+
const o = { style: "currency", currency: r };
|
|
59
59
|
if (e === "compact")
|
|
60
|
-
|
|
60
|
+
o.notation = "compact", o.compactDisplay = "short", n !== void 0 && (o.minimumFractionDigits = n, o.maximumFractionDigits = n);
|
|
61
61
|
else {
|
|
62
|
-
const
|
|
63
|
-
|
|
62
|
+
const a = n ?? 2;
|
|
63
|
+
o.minimumFractionDigits = a, o.maximumFractionDigits = a;
|
|
64
64
|
}
|
|
65
|
-
return new Intl.NumberFormat("en-US",
|
|
65
|
+
return new Intl.NumberFormat("en-US", o).format(t);
|
|
66
|
+
}
|
|
67
|
+
function g(t) {
|
|
68
|
+
const e = t.replace("#", "");
|
|
69
|
+
return [
|
|
70
|
+
parseInt(e.slice(0, 2), 16),
|
|
71
|
+
parseInt(e.slice(2, 4), 16),
|
|
72
|
+
parseInt(e.slice(4, 6), 16)
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
function b(t, e) {
|
|
76
|
+
const n = t.replace("#", "");
|
|
77
|
+
if (!/^[0-9a-fA-F]{6}$/.test(n))
|
|
78
|
+
return `rgba(0,0,0,${e})`;
|
|
79
|
+
const [r, o, a] = g(t);
|
|
80
|
+
return `rgba(${r},${o},${a},${e})`;
|
|
81
|
+
}
|
|
82
|
+
function F(t, e, n) {
|
|
83
|
+
const r = Math.max(0, Math.min(1, n)), [o, a, s] = g(t), [i, c, u] = g(e);
|
|
84
|
+
return `rgb(${Math.round(o + (i - o) * r)}, ${Math.round(a + (c - a) * r)}, ${Math.round(
|
|
85
|
+
s + (u - s) * r
|
|
86
|
+
)})`;
|
|
87
|
+
}
|
|
88
|
+
function R(t, e = 200, n = "cubic-bezier(0, 0, 0.2, 1)") {
|
|
89
|
+
return t.map((r) => `${r} ${e}ms ${n}`).join(", ");
|
|
90
|
+
}
|
|
91
|
+
function P(t, e, n) {
|
|
92
|
+
return t + (e - t) * n;
|
|
93
|
+
}
|
|
94
|
+
function I(t) {
|
|
95
|
+
const e = t.match(/^([-\d.]+)(.*)$/);
|
|
96
|
+
return e ? { value: parseFloat(e[1]), unit: e[2] || "" } : { value: 0, unit: "" };
|
|
66
97
|
}
|
|
67
98
|
const S = 1e3 * 60 * 60 * 24;
|
|
68
|
-
function
|
|
69
|
-
const { rounding:
|
|
70
|
-
let
|
|
71
|
-
return
|
|
99
|
+
function L(t, e, n = {}) {
|
|
100
|
+
const { rounding: r = "round", inclusive: o = !1, min: a, absolute: s = !0 } = n, i = e.getTime() - t.getTime(), u = (s ? Math.abs(i) : i) / S;
|
|
101
|
+
let l = r === "ceil" ? Math.ceil(u) : r === "floor" ? Math.floor(u) : r === "round" ? Math.round(u) : u;
|
|
102
|
+
return o && (l += 1), a !== void 0 && (l = Math.max(l, a)), l;
|
|
103
|
+
}
|
|
104
|
+
function U(t) {
|
|
105
|
+
return new Date(t.getUTCFullYear(), t.getUTCMonth(), t.getUTCDate());
|
|
72
106
|
}
|
|
73
|
-
function
|
|
107
|
+
function v(t) {
|
|
74
108
|
if (t == null || t === 0)
|
|
75
109
|
return { text: "0%", direction: "flat" };
|
|
76
110
|
const e = t > 0 ? "up" : t < 0 ? "down" : "flat", n = Math.abs(t);
|
|
77
111
|
return { text: n >= 3 ? `${Math.round(n)}%` : `${n.toFixed(1)}%`, direction: e };
|
|
78
112
|
}
|
|
79
|
-
function
|
|
113
|
+
function N(t, e) {
|
|
80
114
|
if (!t || !e) return "";
|
|
81
|
-
const n = t.toLocaleDateString("en-US", { month: "short" }),
|
|
82
|
-
return t.getTime() === e.getTime() || n ===
|
|
115
|
+
const n = t.toLocaleDateString("en-US", { month: "short" }), r = e.toLocaleDateString("en-US", { month: "short" }), o = t.getDate(), a = e.getDate(), s = t.getFullYear(), i = e.getFullYear();
|
|
116
|
+
return t.getTime() === e.getTime() || n === r && o === a && s === i ? `${n} ${o}, ${s}` : n === r && s === i ? `${n} ${o}–${a}` : s === i ? `${n} ${o} – ${r} ${a}` : `${n} ${o}, ${s} – ${r} ${a}, ${i}`;
|
|
83
117
|
}
|
|
84
|
-
function
|
|
85
|
-
const n = t.toLocaleDateString("en-US", { month: "short" }),
|
|
86
|
-
return n ===
|
|
118
|
+
function A(t, e) {
|
|
119
|
+
const n = t.toLocaleDateString("en-US", { month: "short" }), r = e.toLocaleDateString("en-US", { month: "short" }), o = t.getDate(), a = e.getDate();
|
|
120
|
+
return n === r ? `${n} ${o}–${a}` : `${n} ${o} – ${r} ${a}`;
|
|
87
121
|
}
|
|
88
|
-
function
|
|
122
|
+
function V(t, e = /* @__PURE__ */ new Date()) {
|
|
89
123
|
return !t?.startDate || !t?.endDate ? !1 : e >= t.startDate && e <= t.endDate;
|
|
90
124
|
}
|
|
91
|
-
function
|
|
125
|
+
function x(t, e) {
|
|
92
126
|
return !t || !e ? !1 : t.getFullYear() === e.getFullYear() && t.getMonth() === e.getMonth() && t.getDate() === e.getDate();
|
|
93
127
|
}
|
|
94
|
-
function
|
|
128
|
+
function O(t, e, n) {
|
|
95
129
|
if (!t || !e || !n) return !1;
|
|
96
|
-
const
|
|
97
|
-
return
|
|
130
|
+
const r = t.getTime(), o = e.getTime(), a = n.getTime();
|
|
131
|
+
return r >= Math.min(o, a) && r <= Math.max(o, a);
|
|
98
132
|
}
|
|
99
|
-
function
|
|
133
|
+
function Y() {
|
|
100
134
|
return `custom-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
101
135
|
}
|
|
102
136
|
export {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
137
|
+
G as DEFAULT_MARKET_PRESETS,
|
|
138
|
+
z as DEFAULT_PINNED,
|
|
139
|
+
H as PERIOD_OPTIONS,
|
|
140
|
+
k as PRESET_ID_MAP,
|
|
141
|
+
B as PRESET_ID_REVERSE_MAP,
|
|
142
|
+
Z as ROLLING_OPTIONS,
|
|
143
|
+
j as TODAY_PRESET,
|
|
144
|
+
d as V1_1_EDGE_HOVER_RESIZE_ENV,
|
|
145
|
+
m as V1_1_STATUS_MODE_ENV,
|
|
146
|
+
L as daysBetween,
|
|
147
|
+
K as detectPreset,
|
|
148
|
+
X as findPreset,
|
|
115
149
|
y as formatCurrency,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
N as formatDateRange,
|
|
151
|
+
q as formatDateRangeSmart,
|
|
152
|
+
W as formatDateRangeWithPreset,
|
|
153
|
+
J as formatDuration,
|
|
154
|
+
A as formatMarketDates,
|
|
155
|
+
Q as formatPreset,
|
|
156
|
+
tt as formatShortYear,
|
|
157
|
+
et as formatSingleDate,
|
|
158
|
+
v as formatTrend,
|
|
159
|
+
D as formatValue,
|
|
160
|
+
Y as generateMarketId,
|
|
161
|
+
nt as getAllPresets,
|
|
162
|
+
rt as getDateRangeDisplayInfo,
|
|
163
|
+
at as getDateRangeForPreset,
|
|
164
|
+
ot as getDurationDays,
|
|
165
|
+
st as getPresetDateRange,
|
|
166
|
+
it as getPresetLabel,
|
|
167
|
+
R as getTransitionStyle,
|
|
133
168
|
E as getValueFontSize,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
169
|
+
b as hexToRgba,
|
|
170
|
+
P as interpolate,
|
|
171
|
+
$ as isEdgeHoverResizeEnabled,
|
|
172
|
+
O as isInRange,
|
|
173
|
+
V as isMarketActive,
|
|
174
|
+
x as isSameDay,
|
|
175
|
+
h as isStatusModeEnabled,
|
|
176
|
+
ut as isValidDateRangeFormat,
|
|
177
|
+
F as lerpHex,
|
|
178
|
+
ct as normalizePresetId,
|
|
179
|
+
lt as parseDateRange,
|
|
180
|
+
I as parseNumericValue,
|
|
181
|
+
T as pickMetricTier,
|
|
182
|
+
ft as resolveEvent,
|
|
183
|
+
gt as resolvePreset,
|
|
184
|
+
mt as smartDateFormat,
|
|
185
|
+
dt as stripLeadingZeros,
|
|
186
|
+
U as toLocalCalendarDate,
|
|
187
|
+
ht as toUppercasePresetId,
|
|
188
|
+
M as v1_1_edge_hover_resize,
|
|
189
|
+
p as v1_1_status_mode
|
|
150
190
|
};
|
package/lib/color.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a 6-digit hex color to an `rgba(r,g,b,a)` string.
|
|
3
|
+
*
|
|
4
|
+
* Guards against malformed input: a value that is not exactly 6 hex digits
|
|
5
|
+
* (after stripping a leading `#`) returns a safe transparent fallback
|
|
6
|
+
* `rgba(0,0,0,${alpha})` rather than throwing. Callers should pre-resolve
|
|
7
|
+
* semantic color names to hex before calling.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { hexToRgba } from '@mt-gloss/utils';
|
|
11
|
+
* hexToRgba('#10b981', 0.2) // 'rgba(16,185,129,0.2)'
|
|
12
|
+
* hexToRgba('nope', 0.5) // 'rgba(0,0,0,0.5)'
|
|
13
|
+
*/
|
|
14
|
+
export declare function hexToRgba(hex: string, alpha: number): string;
|
|
15
|
+
/**
|
|
16
|
+
* Linearly interpolate between two `#rrggbb` hex colors, returning `rgb(r, g, b)`.
|
|
17
|
+
*
|
|
18
|
+
* `t` is clamped to `[0, 1]`; `t = 0` yields `from`, `t = 1` yields `to`.
|
|
19
|
+
* Channels are rounded to the nearest integer.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* import { lerpHex } from '@mt-gloss/utils';
|
|
23
|
+
* lerpHex('#000000', '#ffffff', 0.5) // 'rgb(128, 128, 128)'
|
|
24
|
+
*/
|
|
25
|
+
export declare function lerpHex(from: string, to: string, t: number): string;
|
|
26
|
+
//# sourceMappingURL=color.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a CSS `transition` shorthand from a list of properties.
|
|
3
|
+
*
|
|
4
|
+
* Defaults (`200ms`, `cubic-bezier(0, 0, 0.2, 1)`) are inlined literals rather
|
|
5
|
+
* than `@mt-gloss/tokens` reads: `utils` is a leaf package and must not depend
|
|
6
|
+
* on `tokens`. The values mirror the `durations.normal` / `easings.easeOut`
|
|
7
|
+
* design tokens; callers that need a tokenized curve pass it explicitly.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { getTransitionStyle } from '@mt-gloss/utils';
|
|
11
|
+
* getTransitionStyle(['opacity', 'transform']) // 'opacity 200ms cubic-bezier(0, 0, 0.2, 1), transform 200ms cubic-bezier(0, 0, 0.2, 1)'
|
|
12
|
+
* getTransitionStyle(['width'], 300, 'linear') // 'width 300ms linear'
|
|
13
|
+
*/
|
|
14
|
+
export declare function getTransitionStyle(properties: string[], duration?: number, easing?: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Linearly interpolate between two numbers by `progress` (0–1, unclamped).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { interpolate } from '@mt-gloss/utils';
|
|
20
|
+
* interpolate(0, 100, 0.25) // 25
|
|
21
|
+
*/
|
|
22
|
+
export declare function interpolate(from: number, to: number, progress: number): number;
|
|
23
|
+
/**
|
|
24
|
+
* Parse a CSS dimension string (e.g. `"8px"`) into its numeric value and unit.
|
|
25
|
+
* Unparseable input yields `{ value: 0, unit: '' }`.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* import { parseNumericValue } from '@mt-gloss/utils';
|
|
29
|
+
* parseNumericValue('8px') // { value: 8, unit: 'px' }
|
|
30
|
+
* parseNumericValue('1.5e') // { value: 1.5, unit: 'e' }
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseNumericValue(value: string): {
|
|
33
|
+
value: number;
|
|
34
|
+
unit: string;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=cssAnimation.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-project a date onto **local midnight of its UTC calendar date**.
|
|
3
|
+
*
|
|
4
|
+
* Order dates arrive from the BFF as date-only ISO strings (e.g. `"2026-03-09"`).
|
|
5
|
+
* `new Date("2026-03-09")` parses this as **UTC midnight**, which in timezones
|
|
6
|
+
* west of UTC falls on the *previous* local calendar day (e.g. March 8 at
|
|
7
|
+
* 19:00 EST). To bucket an order by its intended calendar day regardless of the
|
|
8
|
+
* viewer's timezone, both the dashboard's table filter and its chart grouping
|
|
9
|
+
* extract the date's **UTC** year/month/day and rebuild a `Date` at **local**
|
|
10
|
+
* midnight of those components. Doing this on both surfaces guarantees the
|
|
11
|
+
* table filter (which uses local-midnight boundaries) and the chart's UTC
|
|
12
|
+
* date-grouping agree on which day an order belongs to.
|
|
13
|
+
*
|
|
14
|
+
* Regress this and table totals silently disagree with chart bars: the only
|
|
15
|
+
* orders affected are those whose date sits on a UTC-vs-local day boundary, so
|
|
16
|
+
* nothing throws — the two surfaces just stop matching.
|
|
17
|
+
*
|
|
18
|
+
* Purity note: the input `Date` only needs to carry the right instant; this
|
|
19
|
+
* helper reads its UTC Y/M/D and nothing else. String parsing and null handling
|
|
20
|
+
* stay with the caller — one consumer coerces with `new Date(str)`, another with
|
|
21
|
+
* date-fns `parseISO` — and both delegate the projection here.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { toLocalCalendarDate } from '@mt-gloss/utils';
|
|
26
|
+
*
|
|
27
|
+
* // A date-only ISO string parses as UTC midnight; the helper re-keys it to
|
|
28
|
+
* // local midnight of the SAME calendar date — timezone-independent.
|
|
29
|
+
* const d = toLocalCalendarDate(new Date('2026-03-09'));
|
|
30
|
+
* d.getFullYear(); // 2026
|
|
31
|
+
* d.getMonth(); // 2 (March, 0-indexed)
|
|
32
|
+
* d.getDate(); // 9 — never the 8th, even west of UTC
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function toLocalCalendarDate(date: Date): Date;
|
|
36
|
+
//# sourceMappingURL=toLocalCalendarDate.d.ts.map
|