@sfinterface/numbers 0.1.0
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/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/index.cjs +379 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +343 -0
- package/dist/index.js.map +1 -0
- package/dist/numbers.css +333 -0
- package/package.json +63 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/Numbers.tsx
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
// src/utils/cx.ts
|
|
7
|
+
function cx(...values) {
|
|
8
|
+
let out = "";
|
|
9
|
+
for (const value of values) {
|
|
10
|
+
if (!value && value !== 0) continue;
|
|
11
|
+
const part = Array.isArray(value) ? cx(...value) : String(value);
|
|
12
|
+
if (part) out += out ? " " + part : part;
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/utils/refs.ts
|
|
18
|
+
function assignRef(ref, value) {
|
|
19
|
+
if (!ref) return;
|
|
20
|
+
if (typeof ref === "function") ref(value);
|
|
21
|
+
else ref.current = value;
|
|
22
|
+
}
|
|
23
|
+
function mergeRefs(...refs) {
|
|
24
|
+
return (value) => {
|
|
25
|
+
for (const ref of refs) assignRef(ref, value);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/Numbers.tsx
|
|
30
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
31
|
+
var CYCLE = 10;
|
|
32
|
+
var HOME = CYCLE;
|
|
33
|
+
var CELLS = Array.from({ length: CYCLE * 3 }, (_, i) => i % CYCLE);
|
|
34
|
+
function numeralsOf(locale, format) {
|
|
35
|
+
let glyphs = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
|
|
36
|
+
try {
|
|
37
|
+
const numberingSystem = new Intl.NumberFormat(locale, format).resolvedOptions().numberingSystem;
|
|
38
|
+
const plain = new Intl.NumberFormat(locale, { numberingSystem, useGrouping: false });
|
|
39
|
+
glyphs = Array.from({ length: CYCLE }, (_, i) => plain.format(i));
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
return { glyphs, index: new Map(glyphs.map((glyph, i) => [glyph, i])) };
|
|
43
|
+
}
|
|
44
|
+
function cellsFor(value, locale, format, index) {
|
|
45
|
+
const parts = new Intl.NumberFormat(locale, format).formatToParts(value);
|
|
46
|
+
let integers = 0;
|
|
47
|
+
for (const part of parts) if (part.type === "integer") integers += part.value.length;
|
|
48
|
+
const out = [];
|
|
49
|
+
let seen = 0;
|
|
50
|
+
let fraction = 0;
|
|
51
|
+
let marks = 0;
|
|
52
|
+
for (const part of parts) {
|
|
53
|
+
if (part.type === "integer") {
|
|
54
|
+
for (const glyph of part.value) {
|
|
55
|
+
out.push({ key: `d${integers - 1 - seen}`, kind: "digit", digit: index.get(glyph) ?? 0 });
|
|
56
|
+
seen += 1;
|
|
57
|
+
}
|
|
58
|
+
} else if (part.type === "fraction") {
|
|
59
|
+
for (const glyph of part.value) {
|
|
60
|
+
fraction += 1;
|
|
61
|
+
out.push({ key: `f${fraction}`, kind: "digit", digit: index.get(glyph) ?? 0 });
|
|
62
|
+
}
|
|
63
|
+
} else if (part.type === "group") {
|
|
64
|
+
out.push({ key: `g${integers - 1 - seen}`, kind: "mark", text: part.value });
|
|
65
|
+
} else {
|
|
66
|
+
marks += 1;
|
|
67
|
+
out.push({ key: `${part.type}${marks}`, kind: "mark", text: part.value });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
function turn(from, to, dir) {
|
|
73
|
+
if (from === to) return 0;
|
|
74
|
+
const forward = ((to - from) * dir % CYCLE + CYCLE) % CYCLE;
|
|
75
|
+
return dir * forward;
|
|
76
|
+
}
|
|
77
|
+
function ms(value, fallback) {
|
|
78
|
+
const n = parseFloat(value);
|
|
79
|
+
if (!Number.isFinite(n)) return fallback;
|
|
80
|
+
return value.trim().endsWith("s") && !value.trim().endsWith("ms") ? n * 1e3 : n;
|
|
81
|
+
}
|
|
82
|
+
function px(value, fontSize, fallback) {
|
|
83
|
+
const n = parseFloat(value);
|
|
84
|
+
if (!Number.isFinite(n)) return fallback;
|
|
85
|
+
return value.includes("em") ? n * fontSize : n;
|
|
86
|
+
}
|
|
87
|
+
var reduced = () => typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
88
|
+
var Numbers = React.forwardRef(function Numbers2({ value, locale, format, transition = "roll", trend = "auto", blur = true, fade, duration, label, className, ...props }, ref) {
|
|
89
|
+
const numerals = React.useMemo(() => numeralsOf(locale, format), [locale, format]);
|
|
90
|
+
const cells = React.useMemo(
|
|
91
|
+
() => cellsFor(value, locale, format, numerals.index),
|
|
92
|
+
[value, locale, format, numerals]
|
|
93
|
+
);
|
|
94
|
+
const text = React.useMemo(() => new Intl.NumberFormat(locale, format).format(value), [value, locale, format]);
|
|
95
|
+
const host = React.useRef(null);
|
|
96
|
+
const row = React.useRef(null);
|
|
97
|
+
const shown = React.useRef(/* @__PURE__ */ new Map());
|
|
98
|
+
const seats = React.useRef(/* @__PURE__ */ new Map());
|
|
99
|
+
const previous = React.useRef(value);
|
|
100
|
+
const widthSeat = React.useRef(null);
|
|
101
|
+
const widthRun = React.useRef(null);
|
|
102
|
+
const [leaving, setLeaving] = React.useState([]);
|
|
103
|
+
const heading = React.useRef(1);
|
|
104
|
+
const spun = React.useRef(/* @__PURE__ */ new Set());
|
|
105
|
+
const [outgoing, setOutgoing] = React.useState(() => /* @__PURE__ */ new Map());
|
|
106
|
+
const outgoingTimer = React.useRef(null);
|
|
107
|
+
const [generation, setGeneration] = React.useState(0);
|
|
108
|
+
React.useEffect(() => () => {
|
|
109
|
+
if (outgoingTimer.current) clearTimeout(outgoingTimer.current);
|
|
110
|
+
}, []);
|
|
111
|
+
React.useLayoutEffect(() => {
|
|
112
|
+
const rowEl = row.current;
|
|
113
|
+
const hostEl = host.current;
|
|
114
|
+
if (!rowEl || !hostEl) return;
|
|
115
|
+
const from = previous.current;
|
|
116
|
+
previous.current = value;
|
|
117
|
+
const still = reduced();
|
|
118
|
+
const cs = getComputedStyle(rowEl);
|
|
119
|
+
const fontSize = parseFloat(cs.fontSize) || 16;
|
|
120
|
+
const roll = duration ?? ms(cs.getPropertyValue("--sfi-numbers-roll"), 520);
|
|
121
|
+
const shift = ms(cs.getPropertyValue("--sfi-settle"), 240);
|
|
122
|
+
const ease = cs.getPropertyValue("--sfi-ease").trim() || "ease";
|
|
123
|
+
const deepest = px(cs.getPropertyValue("--sfi-numbers-blur"), fontSize, fontSize * 0.1);
|
|
124
|
+
const dir = trend === "up" ? 1 : trend === "down" ? -1 : value >= from ? 1 : -1;
|
|
125
|
+
heading.current = dir;
|
|
126
|
+
const nextSeats = /* @__PURE__ */ new Map();
|
|
127
|
+
const gone = new Map(shown.current);
|
|
128
|
+
const swapped = /* @__PURE__ */ new Map();
|
|
129
|
+
rowEl.querySelectorAll("[data-cell]").forEach((el) => {
|
|
130
|
+
const key = el.dataset.cell;
|
|
131
|
+
const seat = el.offsetLeft;
|
|
132
|
+
nextSeats.set(key, seat);
|
|
133
|
+
gone.delete(key);
|
|
134
|
+
const was = seats.current.get(key);
|
|
135
|
+
const before = shown.current.get(key);
|
|
136
|
+
if (was === void 0) {
|
|
137
|
+
if (!still && seats.current.size > 0) el.setAttribute("data-arriving", "");
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
el.removeAttribute("data-arriving");
|
|
141
|
+
if (still) return;
|
|
142
|
+
const dx = was - seat;
|
|
143
|
+
if (Math.abs(dx) >= 1) {
|
|
144
|
+
el.animate([{ transform: `translateX(${dx}px)` }, { transform: "translateX(0)" }], {
|
|
145
|
+
duration: shift,
|
|
146
|
+
easing: ease
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const digit = el.dataset.digit;
|
|
150
|
+
if (digit === void 0 || !before || before.kind !== "digit") return;
|
|
151
|
+
if (Number(digit) === before.digit) return;
|
|
152
|
+
if (transition !== "roll") {
|
|
153
|
+
swapped.set(key, before.digit);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const steps = turn(before.digit, Number(digit), dir);
|
|
157
|
+
if (steps === 0) return;
|
|
158
|
+
const strip = el.querySelector(".sfi-numbers-strip");
|
|
159
|
+
const cell = strip?.firstElementChild;
|
|
160
|
+
if (!strip || !cell) return;
|
|
161
|
+
const height = cell.getBoundingClientRect().height;
|
|
162
|
+
if (!height) return;
|
|
163
|
+
const start2 = (HOME + before.digit) * height;
|
|
164
|
+
const turning = strip.animate(
|
|
165
|
+
[{ transform: `translateY(${-start2}px)` }, { transform: `translateY(${-(start2 + steps * height)}px)` }],
|
|
166
|
+
{ duration: roll, easing: ease }
|
|
167
|
+
);
|
|
168
|
+
el.setAttribute("data-turning", "");
|
|
169
|
+
turning.finished.then(() => el.removeAttribute("data-turning")).catch(() => {
|
|
170
|
+
});
|
|
171
|
+
if (blur && deepest > 0) {
|
|
172
|
+
const depth = Math.min(1, Math.abs(steps) / 4) * deepest;
|
|
173
|
+
el.animate(
|
|
174
|
+
[
|
|
175
|
+
{ filter: "blur(0px)", offset: 0 },
|
|
176
|
+
{ filter: `blur(${depth.toFixed(2)}px)`, offset: 0.15 },
|
|
177
|
+
{ filter: "blur(0px)", offset: 0.62 },
|
|
178
|
+
{ filter: "blur(0px)", offset: 1 }
|
|
179
|
+
],
|
|
180
|
+
{ duration: roll, easing: "linear" }
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
if (gone.size && !still) {
|
|
185
|
+
const ghosts = [];
|
|
186
|
+
gone.forEach((cell, key) => {
|
|
187
|
+
const seat = seats.current.get(key);
|
|
188
|
+
if (seat !== void 0) ghosts.push({ cell, left: seat });
|
|
189
|
+
});
|
|
190
|
+
if (ghosts.length) setLeaving((current) => [...current, ...ghosts]);
|
|
191
|
+
}
|
|
192
|
+
shown.current = new Map(cells.map((cell) => [cell.key, cell]));
|
|
193
|
+
seats.current = nextSeats;
|
|
194
|
+
if (swapped.size && !still) {
|
|
195
|
+
hostEl.style.setProperty("--sfi-numbers-dir", String(dir));
|
|
196
|
+
setOutgoing(swapped);
|
|
197
|
+
setGeneration((n) => n + 1);
|
|
198
|
+
if (outgoingTimer.current) clearTimeout(outgoingTimer.current);
|
|
199
|
+
outgoingTimer.current = setTimeout(() => {
|
|
200
|
+
outgoingTimer.current = null;
|
|
201
|
+
setOutgoing(/* @__PURE__ */ new Map());
|
|
202
|
+
}, roll + 40);
|
|
203
|
+
}
|
|
204
|
+
const running = widthRun.current;
|
|
205
|
+
const visual = running ? hostEl.getBoundingClientRect().width : null;
|
|
206
|
+
if (running) {
|
|
207
|
+
running.cancel();
|
|
208
|
+
widthRun.current = null;
|
|
209
|
+
}
|
|
210
|
+
const now = rowEl.offsetWidth;
|
|
211
|
+
const start = visual ?? widthSeat.current;
|
|
212
|
+
widthSeat.current = now;
|
|
213
|
+
if (start === null || Math.abs(start - now) < 0.5 || still) return;
|
|
214
|
+
const grow = hostEl.animate([{ width: `${start}px` }, { width: `${now}px` }], {
|
|
215
|
+
duration: shift,
|
|
216
|
+
easing: ease
|
|
217
|
+
});
|
|
218
|
+
widthRun.current = grow;
|
|
219
|
+
grow.finished.then(() => {
|
|
220
|
+
if (widthRun.current === grow) widthRun.current = null;
|
|
221
|
+
}).catch(() => {
|
|
222
|
+
});
|
|
223
|
+
}, [cells, value, trend, blur, duration, transition]);
|
|
224
|
+
React.useLayoutEffect(() => {
|
|
225
|
+
const rowEl = row.current;
|
|
226
|
+
if (!rowEl || leaving.length === 0 || reduced()) return;
|
|
227
|
+
const cs = getComputedStyle(rowEl);
|
|
228
|
+
const fontSize = parseFloat(cs.fontSize) || 16;
|
|
229
|
+
const going = ms(cs.getPropertyValue("--sfi-numbers-exit"), 240);
|
|
230
|
+
const ease = cs.getPropertyValue("--sfi-ease").trim() || "ease";
|
|
231
|
+
const deepest = px(cs.getPropertyValue("--sfi-numbers-blur"), fontSize, fontSize * 0.1);
|
|
232
|
+
const dir = heading.current;
|
|
233
|
+
rowEl.querySelectorAll("[data-ghost]").forEach((el) => {
|
|
234
|
+
const key = el.dataset.ghost;
|
|
235
|
+
if (spun.current.has(key)) return;
|
|
236
|
+
spun.current.add(key);
|
|
237
|
+
const strip = el.querySelector(".sfi-numbers-strip");
|
|
238
|
+
const cell = strip?.firstElementChild;
|
|
239
|
+
if (!strip || !cell) return;
|
|
240
|
+
const height = cell.getBoundingClientRect().height;
|
|
241
|
+
if (!height) return;
|
|
242
|
+
const start = (HOME + Number(el.dataset.digit ?? 0)) * height;
|
|
243
|
+
strip.animate(
|
|
244
|
+
[{ transform: `translateY(${-start}px)` }, { transform: `translateY(${-(start + dir * 3 * height)}px)` }],
|
|
245
|
+
{ duration: going, easing: ease }
|
|
246
|
+
);
|
|
247
|
+
if (blur && deepest > 0) {
|
|
248
|
+
el.animate([{ filter: "blur(0px)" }, { filter: `blur(${deepest.toFixed(2)}px)` }], {
|
|
249
|
+
duration: going,
|
|
250
|
+
easing: ease
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}, [leaving, blur, transition]);
|
|
255
|
+
const setHost = React.useMemo(() => mergeRefs(ref, host), [ref]);
|
|
256
|
+
const knobs = {};
|
|
257
|
+
if (duration !== void 0) knobs["--sfi-numbers-roll"] = `${duration}ms`;
|
|
258
|
+
if (fade !== void 0) knobs["--sfi-numbers-fade"] = `${fade}`;
|
|
259
|
+
const style = Object.keys(knobs).length ? { ...knobs, ...props.style } : props.style;
|
|
260
|
+
return /* @__PURE__ */ jsxs(
|
|
261
|
+
"span",
|
|
262
|
+
{
|
|
263
|
+
ref: setHost,
|
|
264
|
+
className: cx("sfi-numbers", className),
|
|
265
|
+
"data-transition": transition === "roll" ? void 0 : transition,
|
|
266
|
+
...props,
|
|
267
|
+
style,
|
|
268
|
+
children: [
|
|
269
|
+
/* @__PURE__ */ jsx("span", { className: "sfi-numbers-said", children: label ?? text }),
|
|
270
|
+
/* @__PURE__ */ jsxs("span", { className: "sfi-numbers-row", ref: row, "aria-hidden": "true", children: [
|
|
271
|
+
cells.map((cell) => /* @__PURE__ */ jsx(
|
|
272
|
+
Piece,
|
|
273
|
+
{
|
|
274
|
+
cell,
|
|
275
|
+
glyphs: numerals.glyphs,
|
|
276
|
+
transition,
|
|
277
|
+
from: cell.kind === "digit" ? outgoing.get(cell.key) : void 0,
|
|
278
|
+
generation
|
|
279
|
+
},
|
|
280
|
+
cell.key
|
|
281
|
+
)),
|
|
282
|
+
leaving.map((ghost) => /* @__PURE__ */ jsx(
|
|
283
|
+
Piece,
|
|
284
|
+
{
|
|
285
|
+
cell: ghost.cell,
|
|
286
|
+
glyphs: numerals.glyphs,
|
|
287
|
+
transition,
|
|
288
|
+
generation,
|
|
289
|
+
leaving: true,
|
|
290
|
+
left: ghost.left,
|
|
291
|
+
onDone: () => {
|
|
292
|
+
spun.current.delete(ghost.cell.key);
|
|
293
|
+
setLeaving((current) => current.filter((x) => x.cell.key !== ghost.cell.key));
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
`leaving:${ghost.cell.key}`
|
|
297
|
+
))
|
|
298
|
+
] })
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
var at = (digit) => ({ "--sfi-numbers-at": HOME + digit });
|
|
304
|
+
function Piece({
|
|
305
|
+
cell,
|
|
306
|
+
glyphs,
|
|
307
|
+
transition,
|
|
308
|
+
from,
|
|
309
|
+
generation,
|
|
310
|
+
leaving,
|
|
311
|
+
left,
|
|
312
|
+
onDone
|
|
313
|
+
}) {
|
|
314
|
+
const identity = leaving ? {
|
|
315
|
+
"data-leaving": "",
|
|
316
|
+
"data-ghost": cell.key,
|
|
317
|
+
style: { left },
|
|
318
|
+
onAnimationEnd: onDone
|
|
319
|
+
} : {
|
|
320
|
+
"data-cell": cell.key,
|
|
321
|
+
onAnimationEnd: (event) => event.currentTarget.removeAttribute("data-arriving")
|
|
322
|
+
};
|
|
323
|
+
if (cell.kind === "mark") {
|
|
324
|
+
return /* @__PURE__ */ jsx("span", { className: "sfi-numbers-mark", ...identity, children: cell.text });
|
|
325
|
+
}
|
|
326
|
+
const swapping = from !== void 0 && from !== cell.digit;
|
|
327
|
+
return /* @__PURE__ */ jsx("span", { className: "sfi-numbers-slot", "data-digit": cell.digit, ...identity, children: /* @__PURE__ */ jsx("span", { className: "sfi-numbers-window", children: transition === "roll" ? /* @__PURE__ */ jsx("span", { className: "sfi-numbers-strip", style: at(cell.digit), children: CELLS.map((n, i) => /* @__PURE__ */ jsx("span", { className: "sfi-numbers-cell", children: glyphs[n] }, i)) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
328
|
+
/* @__PURE__ */ jsx(
|
|
329
|
+
"span",
|
|
330
|
+
{
|
|
331
|
+
className: "sfi-numbers-face",
|
|
332
|
+
"data-in": swapping ? "" : void 0,
|
|
333
|
+
children: glyphs[cell.digit]
|
|
334
|
+
},
|
|
335
|
+
`in:${cell.digit}:${swapping ? generation : "rest"}`
|
|
336
|
+
),
|
|
337
|
+
swapping ? /* @__PURE__ */ jsx("span", { className: "sfi-numbers-face", "data-out": "", children: glyphs[from] }, `out:${from}:${generation}`) : null
|
|
338
|
+
] }) }) });
|
|
339
|
+
}
|
|
340
|
+
export {
|
|
341
|
+
Numbers
|
|
342
|
+
};
|
|
343
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Numbers.tsx","../src/utils/cx.ts","../src/utils/refs.ts"],"sourcesContent":["import * as React from \"react\";\nimport { cx } from \"./utils/cx\";\nimport { mergeRefs } from \"./utils/refs\";\n\nexport type NumbersTransition = \"roll\" | \"tick\" | \"blur\" | \"flip\" | \"scale\";\n\nexport interface NumbersProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n value: number;\n locale?: string | string[];\n format?: Intl.NumberFormatOptions;\n trend?: \"auto\" | \"up\" | \"down\";\n transition?: NumbersTransition;\n blur?: boolean;\n fade?: number;\n duration?: number;\n label?: string;\n}\n\nconst CYCLE = 10;\nconst HOME = CYCLE;\n\nconst CELLS = Array.from({ length: CYCLE * 3 }, (_, i) => i % CYCLE);\n\nfunction numeralsOf(locale: NumbersProps[\"locale\"], format: NumbersProps[\"format\"]) {\n let glyphs = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"];\n try {\n const numberingSystem = new Intl.NumberFormat(locale, format).resolvedOptions().numberingSystem;\n const plain = new Intl.NumberFormat(locale, { numberingSystem, useGrouping: false });\n glyphs = Array.from({ length: CYCLE }, (_, i) => plain.format(i));\n } catch {\n }\n return { glyphs, index: new Map(glyphs.map((glyph, i) => [glyph, i])) };\n}\n\ntype Cell =\n | { key: string; kind: \"digit\"; digit: number }\n | { key: string; kind: \"mark\"; text: string };\n\nfunction cellsFor(\n value: number,\n locale: NumbersProps[\"locale\"],\n format: NumbersProps[\"format\"],\n index: Map<string, number>,\n): Cell[] {\n const parts = new Intl.NumberFormat(locale, format).formatToParts(value);\n let integers = 0;\n for (const part of parts) if (part.type === \"integer\") integers += part.value.length;\n\n const out: Cell[] = [];\n let seen = 0;\n let fraction = 0;\n let marks = 0;\n for (const part of parts) {\n if (part.type === \"integer\") {\n for (const glyph of part.value) {\n out.push({ key: `d${integers - 1 - seen}`, kind: \"digit\", digit: index.get(glyph) ?? 0 });\n seen += 1;\n }\n } else if (part.type === \"fraction\") {\n for (const glyph of part.value) {\n fraction += 1;\n out.push({ key: `f${fraction}`, kind: \"digit\", digit: index.get(glyph) ?? 0 });\n }\n } else if (part.type === \"group\") {\n out.push({ key: `g${integers - 1 - seen}`, kind: \"mark\", text: part.value });\n } else {\n marks += 1;\n\n out.push({ key: `${part.type}${marks}`, kind: \"mark\", text: part.value });\n }\n }\n return out;\n}\n\nfunction turn(from: number, to: number, dir: 1 | -1): number {\n if (from === to) return 0;\n const forward = ((to - from) * dir % CYCLE + CYCLE) % CYCLE;\n return dir * forward;\n}\n\nfunction ms(value: string, fallback: number): number {\n const n = parseFloat(value);\n if (!Number.isFinite(n)) return fallback;\n return value.trim().endsWith(\"s\") && !value.trim().endsWith(\"ms\") ? n * 1000 : n;\n}\n\nfunction px(value: string, fontSize: number, fallback: number): number {\n const n = parseFloat(value);\n if (!Number.isFinite(n)) return fallback;\n return value.includes(\"em\") ? n * fontSize : n;\n}\n\nconst reduced = () =>\n typeof window !== \"undefined\" && !!window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches;\n\nexport const Numbers = React.forwardRef<HTMLSpanElement, NumbersProps>(function Numbers(\n { value, locale, format, transition = \"roll\", trend = \"auto\", blur = true, fade, duration, label, className, ...props },\n ref,\n) {\n const numerals = React.useMemo(() => numeralsOf(locale, format), [locale, format]);\n const cells = React.useMemo(\n () => cellsFor(value, locale, format, numerals.index),\n [value, locale, format, numerals],\n );\n const text = React.useMemo(() => new Intl.NumberFormat(locale, format).format(value), [value, locale, format]);\n\n const host = React.useRef<HTMLSpanElement | null>(null);\n const row = React.useRef<HTMLSpanElement | null>(null);\n\n const shown = React.useRef(new Map<string, Cell>());\n const seats = React.useRef(new Map<string, number>());\n const previous = React.useRef(value);\n\n const widthSeat = React.useRef<number | null>(null);\n const widthRun = React.useRef<Animation | null>(null);\n\n const [leaving, setLeaving] = React.useState<{ cell: Cell; left: number }[]>([]);\n\n const heading = React.useRef<1 | -1>(1);\n\n const spun = React.useRef(new Set<string>());\n\n const [outgoing, setOutgoing] = React.useState<Map<string, number>>(() => new Map());\n const outgoingTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const [generation, setGeneration] = React.useState(0);\n React.useEffect(() => () => {\n if (outgoingTimer.current) clearTimeout(outgoingTimer.current);\n }, []);\n\n React.useLayoutEffect(() => {\n const rowEl = row.current;\n const hostEl = host.current;\n if (!rowEl || !hostEl) return;\n\n const from = previous.current;\n previous.current = value;\n const still = reduced();\n\n const cs = getComputedStyle(rowEl);\n const fontSize = parseFloat(cs.fontSize) || 16;\n\n const roll = duration ?? ms(cs.getPropertyValue(\"--sfi-numbers-roll\"), 520);\n const shift = ms(cs.getPropertyValue(\"--sfi-settle\"), 240);\n const ease = cs.getPropertyValue(\"--sfi-ease\").trim() || \"ease\";\n const deepest = px(cs.getPropertyValue(\"--sfi-numbers-blur\"), fontSize, fontSize * 0.1);\n\n const dir: 1 | -1 = trend === \"up\" ? 1 : trend === \"down\" ? -1 : value >= from ? 1 : -1;\n heading.current = dir;\n\n const nextSeats = new Map<string, number>();\n const gone = new Map(shown.current);\n const swapped = new Map<string, number>();\n\n rowEl.querySelectorAll<HTMLElement>(\"[data-cell]\").forEach((el) => {\n const key = el.dataset.cell as string;\n const seat = el.offsetLeft;\n nextSeats.set(key, seat);\n gone.delete(key);\n\n const was = seats.current.get(key);\n const before = shown.current.get(key);\n\n if (was === undefined) {\n if (!still && seats.current.size > 0) el.setAttribute(\"data-arriving\", \"\");\n return;\n }\n el.removeAttribute(\"data-arriving\");\n if (still) return;\n\n const dx = was - seat;\n if (Math.abs(dx) >= 1) {\n el.animate([{ transform: `translateX(${dx}px)` }, { transform: \"translateX(0)\" }], {\n duration: shift,\n easing: ease,\n });\n }\n\n const digit = el.dataset.digit;\n if (digit === undefined || !before || before.kind !== \"digit\") return;\n if (Number(digit) === before.digit) return;\n\n if (transition !== \"roll\") {\n swapped.set(key, before.digit);\n return;\n }\n\n const steps = turn(before.digit, Number(digit), dir);\n if (steps === 0) return;\n\n const strip = el.querySelector<HTMLElement>(\".sfi-numbers-strip\");\n const cell = strip?.firstElementChild;\n if (!strip || !cell) return;\n const height = cell.getBoundingClientRect().height;\n if (!height) return;\n\n const start = (HOME + before.digit) * height;\n const turning = strip.animate(\n [{ transform: `translateY(${-start}px)` }, { transform: `translateY(${-(start + steps * height)}px)` }],\n { duration: roll, easing: ease },\n );\n\n el.setAttribute(\"data-turning\", \"\");\n turning.finished.then(() => el.removeAttribute(\"data-turning\")).catch(() => {});\n\n if (blur && deepest > 0) {\n const depth = Math.min(1, Math.abs(steps) / 4) * deepest;\n el.animate(\n [\n { filter: \"blur(0px)\", offset: 0 },\n { filter: `blur(${depth.toFixed(2)}px)`, offset: 0.15 },\n { filter: \"blur(0px)\", offset: 0.62 },\n { filter: \"blur(0px)\", offset: 1 },\n ],\n { duration: roll, easing: \"linear\" },\n );\n }\n });\n\n if (gone.size && !still) {\n const ghosts: { cell: Cell; left: number }[] = [];\n gone.forEach((cell, key) => {\n const seat = seats.current.get(key);\n if (seat !== undefined) ghosts.push({ cell, left: seat });\n });\n if (ghosts.length) setLeaving((current) => [...current, ...ghosts]);\n }\n\n shown.current = new Map(cells.map((cell) => [cell.key, cell]));\n seats.current = nextSeats;\n\n if (swapped.size && !still) {\n hostEl.style.setProperty(\"--sfi-numbers-dir\", String(dir));\n setOutgoing(swapped);\n setGeneration((n) => n + 1);\n if (outgoingTimer.current) clearTimeout(outgoingTimer.current);\n outgoingTimer.current = setTimeout(() => {\n outgoingTimer.current = null;\n setOutgoing(new Map());\n }, roll + 40);\n }\n\n const running = widthRun.current;\n const visual = running ? hostEl.getBoundingClientRect().width : null;\n if (running) {\n running.cancel();\n widthRun.current = null;\n }\n const now = rowEl.offsetWidth;\n const start = visual ?? widthSeat.current;\n widthSeat.current = now;\n if (start === null || Math.abs(start - now) < 0.5 || still) return;\n\n const grow = hostEl.animate([{ width: `${start}px` }, { width: `${now}px` }], {\n duration: shift,\n easing: ease,\n });\n widthRun.current = grow;\n grow.finished\n .then(() => {\n if (widthRun.current === grow) widthRun.current = null;\n })\n .catch(() => {});\n }, [cells, value, trend, blur, duration, transition]);\n\n React.useLayoutEffect(() => {\n const rowEl = row.current;\n if (!rowEl || leaving.length === 0 || reduced()) return;\n\n const cs = getComputedStyle(rowEl);\n const fontSize = parseFloat(cs.fontSize) || 16;\n const going = ms(cs.getPropertyValue(\"--sfi-numbers-exit\"), 240);\n const ease = cs.getPropertyValue(\"--sfi-ease\").trim() || \"ease\";\n const deepest = px(cs.getPropertyValue(\"--sfi-numbers-blur\"), fontSize, fontSize * 0.1);\n const dir = heading.current;\n\n rowEl.querySelectorAll<HTMLElement>(\"[data-ghost]\").forEach((el) => {\n const key = el.dataset.ghost as string;\n if (spun.current.has(key)) return;\n spun.current.add(key);\n const strip = el.querySelector<HTMLElement>(\".sfi-numbers-strip\");\n const cell = strip?.firstElementChild;\n if (!strip || !cell) return;\n const height = cell.getBoundingClientRect().height;\n if (!height) return;\n\n const start = (HOME + Number(el.dataset.digit ?? 0)) * height;\n strip.animate(\n [{ transform: `translateY(${-start}px)` }, { transform: `translateY(${-(start + dir * 3 * height)}px)` }],\n { duration: going, easing: ease },\n );\n if (blur && deepest > 0) {\n el.animate([{ filter: \"blur(0px)\" }, { filter: `blur(${deepest.toFixed(2)}px)` }], {\n duration: going,\n easing: ease,\n });\n }\n });\n }, [leaving, blur, transition]);\n\n const setHost = React.useMemo(() => mergeRefs(ref, host), [ref]);\n\n const knobs: Record<string, string> = {};\n if (duration !== undefined) knobs[\"--sfi-numbers-roll\"] = `${duration}ms`;\n if (fade !== undefined) knobs[\"--sfi-numbers-fade\"] = `${fade}`;\n const style = Object.keys(knobs).length\n ? ({ ...knobs, ...props.style } as React.CSSProperties)\n : props.style;\n\n return (\n <span\n ref={setHost}\n className={cx(\"sfi-numbers\", className)}\n data-transition={transition === \"roll\" ? undefined : transition}\n {...props}\n style={style}\n >\n\n <span className=\"sfi-numbers-said\">{label ?? text}</span>\n <span className=\"sfi-numbers-row\" ref={row} aria-hidden=\"true\">\n {cells.map((cell) => (\n <Piece\n key={cell.key}\n cell={cell}\n glyphs={numerals.glyphs}\n transition={transition}\n from={cell.kind === \"digit\" ? outgoing.get(cell.key) : undefined}\n generation={generation}\n />\n ))}\n {leaving.map((ghost) => (\n <Piece\n key={`leaving:${ghost.cell.key}`}\n cell={ghost.cell}\n glyphs={numerals.glyphs}\n transition={transition}\n generation={generation}\n leaving\n left={ghost.left}\n onDone={() => {\n spun.current.delete(ghost.cell.key);\n setLeaving((current) => current.filter((x) => x.cell.key !== ghost.cell.key));\n }}\n />\n ))}\n </span>\n </span>\n );\n});\n\nconst at = (digit: number) => ({ \"--sfi-numbers-at\": HOME + digit }) as React.CSSProperties;\n\nfunction Piece({\n cell,\n glyphs,\n transition,\n from,\n generation,\n leaving,\n left,\n onDone,\n}: {\n cell: Cell;\n glyphs: string[];\n transition: NumbersTransition;\n from?: number;\n generation: number;\n leaving?: boolean;\n left?: number;\n onDone?: () => void;\n}) {\n const identity = leaving\n ? {\n \"data-leaving\": \"\",\n \"data-ghost\": cell.key,\n style: { left } as React.CSSProperties,\n onAnimationEnd: onDone,\n }\n : {\n \"data-cell\": cell.key,\n onAnimationEnd: (event: React.AnimationEvent<HTMLElement>) =>\n event.currentTarget.removeAttribute(\"data-arriving\"),\n };\n\n if (cell.kind === \"mark\") {\n return (\n <span className=\"sfi-numbers-mark\" {...identity}>\n {cell.text}\n </span>\n );\n }\n\n const swapping = from !== undefined && from !== cell.digit;\n\n return (\n <span className=\"sfi-numbers-slot\" data-digit={cell.digit} {...identity}>\n\n <span className=\"sfi-numbers-window\">\n {transition === \"roll\" ? (\n <span className=\"sfi-numbers-strip\" style={at(cell.digit)}>\n {CELLS.map((n, i) => (\n <span className=\"sfi-numbers-cell\" key={i}>\n {glyphs[n]}\n </span>\n ))}\n </span>\n ) : (\n <>\n <span\n className=\"sfi-numbers-face\"\n\n data-in={swapping ? \"\" : undefined}\n key={`in:${cell.digit}:${swapping ? generation : \"rest\"}`}\n >\n {glyphs[cell.digit]}\n </span>\n {swapping ? (\n <span className=\"sfi-numbers-face\" data-out=\"\" key={`out:${from}:${generation}`}>\n {glyphs[from as number]}\n </span>\n ) : null}\n </>\n )}\n </span>\n </span>\n );\n}\n","export type ClassValue = string | number | null | undefined | false | ClassValue[];\n\nexport function cx(...values: ClassValue[]): string {\n let out = \"\";\n for (const value of values) {\n if (!value && value !== 0) continue;\n const part = Array.isArray(value) ? cx(...value) : String(value);\n if (part) out += out ? \" \" + part : part;\n }\n return out;\n}\n","import type { Ref } from \"react\";\n\nexport function assignRef<T>(ref: Ref<T> | undefined, value: T | null): void {\n if (!ref) return;\n if (typeof ref === \"function\") ref(value);\n else (ref as { current: T | null }).current = value;\n}\n\nexport function mergeRefs<T>(...refs: Array<Ref<T> | undefined>): (value: T | null) => void {\n return (value) => {\n for (const ref of refs) assignRef(ref, value);\n };\n}\n"],"mappings":"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","names":["Numbers","start"]}
|