@sfinterface/numbers 0.2.0 → 0.2.2
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 +8 -7
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
Numbers that move the way they should. A React component from **The San Francisco Interface**.
|
|
8
8
|
|
|
9
|
-
<img src="https://
|
|
9
|
+
<img src="https://raw.githubusercontent.com/wherescz/sfinterface-numbers/main/tags.svg" alt="MIT · 13 kB · No dependencies · React 18 and 19 · TypeScript · SSR ready">
|
|
10
10
|
|
|
11
11
|
<br>
|
|
12
12
|
<br>
|
|
13
13
|
<br>
|
|
14
14
|
|
|
15
|
-
<img src="https://
|
|
15
|
+
<img src="https://raw.githubusercontent.com/wherescz/sfinterface-numbers/main/preview-gif.gif" width="1920" alt="A number rolling from 1,204 to 1,251">
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
@@ -35,8 +35,8 @@ Each column is a strip of digits behind a window. Changing the value turns only
|
|
|
35
35
|
the columns whose digit actually moved, and the box grows or shrinks to fit what
|
|
36
36
|
it now says.
|
|
37
37
|
|
|
38
|
-
Face, size, weight, colour and tracking are inherited
|
|
39
|
-
motion and geometry and nothing else
|
|
38
|
+
Face, size, weight, colour and tracking are inherited. The stylesheet describes
|
|
39
|
+
motion and geometry and nothing else, so a readout in a heading is the heading's
|
|
40
40
|
type.
|
|
41
41
|
|
|
42
42
|
The digits are `aria-hidden`; one formatted string sits behind them, so a screen
|
|
@@ -102,7 +102,7 @@ into an even, eased ramp with no knee in it.
|
|
|
102
102
|
| prop | type | default |
|
|
103
103
|
| --- | --- | --- |
|
|
104
104
|
| `value` | `number` | required |
|
|
105
|
-
| `format` | `Intl.NumberFormatOptions` |
|
|
105
|
+
| `format` | `Intl.NumberFormatOptions` | none |
|
|
106
106
|
| `locale` | `string \| string[]` | the runtime's |
|
|
107
107
|
| `transition` | `"roll" \| "tick" \| "blur" \| "flip" \| "scale"` | `"roll"` |
|
|
108
108
|
| `trend` | `"auto" \| "up" \| "down"` | `"auto"` |
|
|
@@ -118,7 +118,7 @@ Everything else is spread onto the root `<span>`.
|
|
|
118
118
|
|
|
119
119
|
## Theming
|
|
120
120
|
|
|
121
|
-
Every value is a custom property
|
|
121
|
+
Every value is a custom property. Set one on `:root`, on a wrapper, or inline.
|
|
122
122
|
|
|
123
123
|
| token | default | |
|
|
124
124
|
| --- | --- | --- |
|
|
@@ -154,7 +154,8 @@ number changes, and nothing animates.
|
|
|
154
154
|
## Requirements
|
|
155
155
|
|
|
156
156
|
React 18 or 19. No dependencies, types bundled. It renders on the server with
|
|
157
|
-
the formatted value already in the markup
|
|
157
|
+
the formatted value already in the markup, so there is no empty box and nothing
|
|
158
|
+
to guard.
|
|
158
159
|
|
|
159
160
|
<br>
|
|
160
161
|
|
package/dist/index.cjs
CHANGED
|
@@ -63,6 +63,7 @@ function mergeRefs(...refs) {
|
|
|
63
63
|
|
|
64
64
|
// src/Numbers.tsx
|
|
65
65
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
66
|
+
var useSeated = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
66
67
|
var CYCLE = 10;
|
|
67
68
|
var HOME = CYCLE;
|
|
68
69
|
var CELLS = Array.from({ length: CYCLE * 3 }, (_, i) => i % CYCLE);
|
|
@@ -143,7 +144,7 @@ var Numbers = React.forwardRef(function Numbers2({ value, locale, format, transi
|
|
|
143
144
|
React.useEffect(() => () => {
|
|
144
145
|
if (outgoingTimer.current) clearTimeout(outgoingTimer.current);
|
|
145
146
|
}, []);
|
|
146
|
-
|
|
147
|
+
useSeated(() => {
|
|
147
148
|
const rowEl = row.current;
|
|
148
149
|
const hostEl = host.current;
|
|
149
150
|
if (!rowEl || !hostEl) return;
|
|
@@ -256,7 +257,7 @@ var Numbers = React.forwardRef(function Numbers2({ value, locale, format, transi
|
|
|
256
257
|
}).catch(() => {
|
|
257
258
|
});
|
|
258
259
|
}, [cells, value, trend, blur, duration, transition]);
|
|
259
|
-
|
|
260
|
+
useSeated(() => {
|
|
260
261
|
const rowEl = row.current;
|
|
261
262
|
if (!rowEl || leaving.length === 0 || reduced()) return;
|
|
262
263
|
const cs = getComputedStyle(rowEl);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Numbers.tsx","../src/utils/cx.ts","../src/utils/refs.ts"],"sourcesContent":["export { Numbers, type NumbersProps, type NumbersTransition } from \"./Numbers\";\n","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 softness?: 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, softness, 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 if (softness !== undefined) knobs[\"--sfi-numbers-softness\"] = `${softness}`;\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Numbers.tsx","../src/utils/cx.ts","../src/utils/refs.ts"],"sourcesContent":["export { Numbers, type NumbersProps, type NumbersTransition } from \"./Numbers\";\n","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 softness?: number;\n duration?: number;\n label?: string;\n}\n\nconst useSeated = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\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, softness, 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 useSeated(() => {\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 useSeated(() => {\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 if (softness !== undefined) knobs[\"--sfi-numbers-softness\"] = `${softness}`;\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;;;ACEhB,SAAS,MAAM,QAA8B;AAClD,MAAI,MAAM;AACV,aAAW,SAAS,QAAQ;AAC1B,QAAI,CAAC,SAAS,UAAU,EAAG;AAC3B,UAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,GAAG,GAAG,KAAK,IAAI,OAAO,KAAK;AAC/D,QAAI,KAAM,QAAO,MAAM,MAAM,OAAO;AAAA,EACtC;AACA,SAAO;AACT;;;ACRO,SAAS,UAAa,KAAyB,OAAuB;AAC3E,MAAI,CAAC,IAAK;AACV,MAAI,OAAO,QAAQ,WAAY,KAAI,KAAK;AAAA,MACnC,CAAC,IAA8B,UAAU;AAChD;AAEO,SAAS,aAAgB,MAA4D;AAC1F,SAAO,CAAC,UAAU;AAChB,eAAW,OAAO,KAAM,WAAU,KAAK,KAAK;AAAA,EAC9C;AACF;;;AFsTM;AA/SN,IAAM,YAAY,OAAO,WAAW,cAAoB,kBAAkB;AAE1E,IAAM,QAAQ;AACd,IAAM,OAAO;AAEb,IAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM,IAAI,KAAK;AAEnE,SAAS,WAAW,QAAgC,QAAgC;AAClF,MAAI,SAAS,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAC9D,MAAI;AACF,UAAM,kBAAkB,IAAI,KAAK,aAAa,QAAQ,MAAM,EAAE,gBAAgB,EAAE;AAChF,UAAM,QAAQ,IAAI,KAAK,aAAa,QAAQ,EAAE,iBAAiB,aAAa,MAAM,CAAC;AACnF,aAAS,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM,MAAM,OAAO,CAAC,CAAC;AAAA,EAClE,QAAQ;AAAA,EACR;AACA,SAAO,EAAE,QAAQ,OAAO,IAAI,IAAI,OAAO,IAAI,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACxE;AAMA,SAAS,SACP,OACA,QACA,QACA,OACQ;AACR,QAAM,QAAQ,IAAI,KAAK,aAAa,QAAQ,MAAM,EAAE,cAAc,KAAK;AACvE,MAAI,WAAW;AACf,aAAW,QAAQ,MAAO,KAAI,KAAK,SAAS,UAAW,aAAY,KAAK,MAAM;AAE9E,QAAM,MAAc,CAAC;AACrB,MAAI,OAAO;AACX,MAAI,WAAW;AACf,MAAI,QAAQ;AACZ,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,WAAW;AAC3B,iBAAW,SAAS,KAAK,OAAO;AAC9B,YAAI,KAAK,EAAE,KAAK,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,SAAS,OAAO,MAAM,IAAI,KAAK,KAAK,EAAE,CAAC;AACxF,gBAAQ;AAAA,MACV;AAAA,IACF,WAAW,KAAK,SAAS,YAAY;AACnC,iBAAW,SAAS,KAAK,OAAO;AAC9B,oBAAY;AACZ,YAAI,KAAK,EAAE,KAAK,IAAI,QAAQ,IAAI,MAAM,SAAS,OAAO,MAAM,IAAI,KAAK,KAAK,EAAE,CAAC;AAAA,MAC/E;AAAA,IACF,WAAW,KAAK,SAAS,SAAS;AAChC,UAAI,KAAK,EAAE,KAAK,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,QAAQ,MAAM,KAAK,MAAM,CAAC;AAAA,IAC7E,OAAO;AACL,eAAS;AAET,UAAI,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,QAAQ,MAAM,KAAK,MAAM,CAAC;AAAA,IAC1E;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,KAAK,MAAc,IAAY,KAAqB;AAC3D,MAAI,SAAS,GAAI,QAAO;AACxB,QAAM,YAAY,KAAK,QAAQ,MAAM,QAAQ,SAAS;AACtD,SAAO,MAAM;AACf;AAEA,SAAS,GAAG,OAAe,UAA0B;AACnD,QAAM,IAAI,WAAW,KAAK;AAC1B,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,MAAM,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,MAAM,KAAK,EAAE,SAAS,IAAI,IAAI,IAAI,MAAO;AACjF;AAEA,SAAS,GAAG,OAAe,UAAkB,UAA0B;AACrE,QAAM,IAAI,WAAW,KAAK;AAC1B,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,MAAM,SAAS,IAAI,IAAI,IAAI,WAAW;AAC/C;AAEA,IAAM,UAAU,MACd,OAAO,WAAW,eAAe,CAAC,CAAC,OAAO,aAAa,kCAAkC,EAAE;AAEtF,IAAM,UAAgB,iBAA0C,SAASA,SAC9E,EAAE,OAAO,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,QAAQ,OAAO,MAAM,MAAM,UAAU,UAAU,OAAO,WAAW,GAAG,MAAM,GAChI,KACA;AACA,QAAM,WAAiB,cAAQ,MAAM,WAAW,QAAQ,MAAM,GAAG,CAAC,QAAQ,MAAM,CAAC;AACjF,QAAM,QAAc;AAAA,IAClB,MAAM,SAAS,OAAO,QAAQ,QAAQ,SAAS,KAAK;AAAA,IACpD,CAAC,OAAO,QAAQ,QAAQ,QAAQ;AAAA,EAClC;AACA,QAAM,OAAa,cAAQ,MAAM,IAAI,KAAK,aAAa,QAAQ,MAAM,EAAE,OAAO,KAAK,GAAG,CAAC,OAAO,QAAQ,MAAM,CAAC;AAE7G,QAAM,OAAa,aAA+B,IAAI;AACtD,QAAM,MAAY,aAA+B,IAAI;AAErD,QAAM,QAAc,aAAO,oBAAI,IAAkB,CAAC;AAClD,QAAM,QAAc,aAAO,oBAAI,IAAoB,CAAC;AACpD,QAAM,WAAiB,aAAO,KAAK;AAEnC,QAAM,YAAkB,aAAsB,IAAI;AAClD,QAAM,WAAiB,aAAyB,IAAI;AAEpD,QAAM,CAAC,SAAS,UAAU,IAAU,eAAyC,CAAC,CAAC;AAE/E,QAAM,UAAgB,aAAe,CAAC;AAEtC,QAAM,OAAa,aAAO,oBAAI,IAAY,CAAC;AAE3C,QAAM,CAAC,UAAU,WAAW,IAAU,eAA8B,MAAM,oBAAI,IAAI,CAAC;AACnF,QAAM,gBAAsB,aAA6C,IAAI;AAE7E,QAAM,CAAC,YAAY,aAAa,IAAU,eAAS,CAAC;AACpD,EAAM,gBAAU,MAAM,MAAM;AAC1B,QAAI,cAAc,QAAS,cAAa,cAAc,OAAO;AAAA,EAC/D,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,UAAM,QAAQ,IAAI;AAClB,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,SAAS,CAAC,OAAQ;AAEvB,UAAM,OAAO,SAAS;AACtB,aAAS,UAAU;AACnB,UAAM,QAAQ,QAAQ;AAEtB,UAAM,KAAK,iBAAiB,KAAK;AACjC,UAAM,WAAW,WAAW,GAAG,QAAQ,KAAK;AAE5C,UAAM,OAAO,YAAY,GAAG,GAAG,iBAAiB,oBAAoB,GAAG,GAAG;AAC1E,UAAM,QAAQ,GAAG,GAAG,iBAAiB,cAAc,GAAG,GAAG;AACzD,UAAM,OAAO,GAAG,iBAAiB,YAAY,EAAE,KAAK,KAAK;AACzD,UAAM,UAAU,GAAG,GAAG,iBAAiB,oBAAoB,GAAG,UAAU,WAAW,GAAG;AAEtF,UAAM,MAAc,UAAU,OAAO,IAAI,UAAU,SAAS,KAAK,SAAS,OAAO,IAAI;AACrF,YAAQ,UAAU;AAElB,UAAM,YAAY,oBAAI,IAAoB;AAC1C,UAAM,OAAO,IAAI,IAAI,MAAM,OAAO;AAClC,UAAM,UAAU,oBAAI,IAAoB;AAExC,UAAM,iBAA8B,aAAa,EAAE,QAAQ,CAAC,OAAO;AACjE,YAAM,MAAM,GAAG,QAAQ;AACvB,YAAM,OAAO,GAAG;AAChB,gBAAU,IAAI,KAAK,IAAI;AACvB,WAAK,OAAO,GAAG;AAEf,YAAM,MAAM,MAAM,QAAQ,IAAI,GAAG;AACjC,YAAM,SAAS,MAAM,QAAQ,IAAI,GAAG;AAEpC,UAAI,QAAQ,QAAW;AACrB,YAAI,CAAC,SAAS,MAAM,QAAQ,OAAO,EAAG,IAAG,aAAa,iBAAiB,EAAE;AACzE;AAAA,MACF;AACA,SAAG,gBAAgB,eAAe;AAClC,UAAI,MAAO;AAEX,YAAM,KAAK,MAAM;AACjB,UAAI,KAAK,IAAI,EAAE,KAAK,GAAG;AACrB,WAAG,QAAQ,CAAC,EAAE,WAAW,cAAc,EAAE,MAAM,GAAG,EAAE,WAAW,gBAAgB,CAAC,GAAG;AAAA,UACjF,UAAU;AAAA,UACV,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAEA,YAAM,QAAQ,GAAG,QAAQ;AACzB,UAAI,UAAU,UAAa,CAAC,UAAU,OAAO,SAAS,QAAS;AAC/D,UAAI,OAAO,KAAK,MAAM,OAAO,MAAO;AAEpC,UAAI,eAAe,QAAQ;AACzB,gBAAQ,IAAI,KAAK,OAAO,KAAK;AAC7B;AAAA,MACF;AAEA,YAAM,QAAQ,KAAK,OAAO,OAAO,OAAO,KAAK,GAAG,GAAG;AACnD,UAAI,UAAU,EAAG;AAEjB,YAAM,QAAQ,GAAG,cAA2B,oBAAoB;AAChE,YAAM,OAAO,OAAO;AACpB,UAAI,CAAC,SAAS,CAAC,KAAM;AACrB,YAAM,SAAS,KAAK,sBAAsB,EAAE;AAC5C,UAAI,CAAC,OAAQ;AAEb,YAAMC,UAAS,OAAO,OAAO,SAAS;AACtC,YAAM,UAAU,MAAM;AAAA,QACpB,CAAC,EAAE,WAAW,cAAc,CAACA,MAAK,MAAM,GAAG,EAAE,WAAW,cAAc,EAAEA,SAAQ,QAAQ,OAAO,MAAM,CAAC;AAAA,QACtG,EAAE,UAAU,MAAM,QAAQ,KAAK;AAAA,MACjC;AAEA,SAAG,aAAa,gBAAgB,EAAE;AAClC,cAAQ,SAAS,KAAK,MAAM,GAAG,gBAAgB,cAAc,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAE9E,UAAI,QAAQ,UAAU,GAAG;AACvB,cAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC,IAAI;AACjD,WAAG;AAAA,UACD;AAAA,YACE,EAAE,QAAQ,aAAa,QAAQ,EAAE;AAAA,YACjC,EAAE,QAAQ,QAAQ,MAAM,QAAQ,CAAC,CAAC,OAAO,QAAQ,KAAK;AAAA,YACtD,EAAE,QAAQ,aAAa,QAAQ,KAAK;AAAA,YACpC,EAAE,QAAQ,aAAa,QAAQ,EAAE;AAAA,UACnC;AAAA,UACA,EAAE,UAAU,MAAM,QAAQ,SAAS;AAAA,QACrC;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,KAAK,QAAQ,CAAC,OAAO;AACvB,YAAM,SAAyC,CAAC;AAChD,WAAK,QAAQ,CAAC,MAAM,QAAQ;AAC1B,cAAM,OAAO,MAAM,QAAQ,IAAI,GAAG;AAClC,YAAI,SAAS,OAAW,QAAO,KAAK,EAAE,MAAM,MAAM,KAAK,CAAC;AAAA,MAC1D,CAAC;AACD,UAAI,OAAO,OAAQ,YAAW,CAAC,YAAY,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC;AAAA,IACpE;AAEA,UAAM,UAAU,IAAI,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;AAC7D,UAAM,UAAU;AAEhB,QAAI,QAAQ,QAAQ,CAAC,OAAO;AAC1B,aAAO,MAAM,YAAY,qBAAqB,OAAO,GAAG,CAAC;AACzD,kBAAY,OAAO;AACnB,oBAAc,CAAC,MAAM,IAAI,CAAC;AAC1B,UAAI,cAAc,QAAS,cAAa,cAAc,OAAO;AAC7D,oBAAc,UAAU,WAAW,MAAM;AACvC,sBAAc,UAAU;AACxB,oBAAY,oBAAI,IAAI,CAAC;AAAA,MACvB,GAAG,OAAO,EAAE;AAAA,IACd;AAEA,UAAM,UAAU,SAAS;AACzB,UAAM,SAAS,UAAU,OAAO,sBAAsB,EAAE,QAAQ;AAChE,QAAI,SAAS;AACX,cAAQ,OAAO;AACf,eAAS,UAAU;AAAA,IACrB;AACA,UAAM,MAAM,MAAM;AAClB,UAAM,QAAQ,UAAU,UAAU;AAClC,cAAU,UAAU;AACpB,QAAI,UAAU,QAAQ,KAAK,IAAI,QAAQ,GAAG,IAAI,OAAO,MAAO;AAE5D,UAAM,OAAO,OAAO,QAAQ,CAAC,EAAE,OAAO,GAAG,KAAK,KAAK,GAAG,EAAE,OAAO,GAAG,GAAG,KAAK,CAAC,GAAG;AAAA,MAC5E,UAAU;AAAA,MACV,QAAQ;AAAA,IACV,CAAC;AACD,aAAS,UAAU;AACnB,SAAK,SACF,KAAK,MAAM;AACV,UAAI,SAAS,YAAY,KAAM,UAAS,UAAU;AAAA,IACpD,CAAC,EACA,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB,GAAG,CAAC,OAAO,OAAO,OAAO,MAAM,UAAU,UAAU,CAAC;AAEpD,YAAU,MAAM;AACd,UAAM,QAAQ,IAAI;AAClB,QAAI,CAAC,SAAS,QAAQ,WAAW,KAAK,QAAQ,EAAG;AAEjD,UAAM,KAAK,iBAAiB,KAAK;AACjC,UAAM,WAAW,WAAW,GAAG,QAAQ,KAAK;AAC5C,UAAM,QAAQ,GAAG,GAAG,iBAAiB,oBAAoB,GAAG,GAAG;AAC/D,UAAM,OAAO,GAAG,iBAAiB,YAAY,EAAE,KAAK,KAAK;AACzD,UAAM,UAAU,GAAG,GAAG,iBAAiB,oBAAoB,GAAG,UAAU,WAAW,GAAG;AACtF,UAAM,MAAM,QAAQ;AAEpB,UAAM,iBAA8B,cAAc,EAAE,QAAQ,CAAC,OAAO;AAClE,YAAM,MAAM,GAAG,QAAQ;AACvB,UAAI,KAAK,QAAQ,IAAI,GAAG,EAAG;AAC3B,WAAK,QAAQ,IAAI,GAAG;AACpB,YAAM,QAAQ,GAAG,cAA2B,oBAAoB;AAChE,YAAM,OAAO,OAAO;AACpB,UAAI,CAAC,SAAS,CAAC,KAAM;AACrB,YAAM,SAAS,KAAK,sBAAsB,EAAE;AAC5C,UAAI,CAAC,OAAQ;AAEb,YAAM,SAAS,OAAO,OAAO,GAAG,QAAQ,SAAS,CAAC,KAAK;AACvD,YAAM;AAAA,QACJ,CAAC,EAAE,WAAW,cAAc,CAAC,KAAK,MAAM,GAAG,EAAE,WAAW,cAAc,EAAE,QAAQ,MAAM,IAAI,OAAO,MAAM,CAAC;AAAA,QACxG,EAAE,UAAU,OAAO,QAAQ,KAAK;AAAA,MAClC;AACA,UAAI,QAAQ,UAAU,GAAG;AACvB,WAAG,QAAQ,CAAC,EAAE,QAAQ,YAAY,GAAG,EAAE,QAAQ,QAAQ,QAAQ,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG;AAAA,UACjF,UAAU;AAAA,UACV,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,MAAM,UAAU,CAAC;AAE9B,QAAM,UAAgB,cAAQ,MAAM,UAAU,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC;AAE/D,QAAM,QAAgC,CAAC;AACvC,MAAI,aAAa,OAAW,OAAM,oBAAoB,IAAI,GAAG,QAAQ;AACrE,MAAI,SAAS,OAAW,OAAM,oBAAoB,IAAI,GAAG,IAAI;AAC7D,MAAI,aAAa,OAAW,OAAM,wBAAwB,IAAI,GAAG,QAAQ;AACzE,QAAM,QAAQ,OAAO,KAAK,KAAK,EAAE,SAC5B,EAAE,GAAG,OAAO,GAAG,MAAM,MAAM,IAC5B,MAAM;AAEV,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,GAAG,eAAe,SAAS;AAAA,MACtC,mBAAiB,eAAe,SAAS,SAAY;AAAA,MACpD,GAAG;AAAA,MACJ;AAAA,MAGA;AAAA,oDAAC,UAAK,WAAU,oBAAoB,mBAAS,MAAK;AAAA,QAClD,6CAAC,UAAK,WAAU,mBAAkB,KAAK,KAAK,eAAY,QACrD;AAAA,gBAAM,IAAI,CAAC,SACV;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA,QAAQ,SAAS;AAAA,cACjB;AAAA,cACA,MAAM,KAAK,SAAS,UAAU,SAAS,IAAI,KAAK,GAAG,IAAI;AAAA,cACvD;AAAA;AAAA,YALK,KAAK;AAAA,UAMZ,CACD;AAAA,UACA,QAAQ,IAAI,CAAC,UACZ;AAAA,YAAC;AAAA;AAAA,cAEC,MAAM,MAAM;AAAA,cACZ,QAAQ,SAAS;AAAA,cACjB;AAAA,cACA;AAAA,cACA,SAAO;AAAA,cACP,MAAM,MAAM;AAAA,cACZ,QAAQ,MAAM;AACZ,qBAAK,QAAQ,OAAO,MAAM,KAAK,GAAG;AAClC,2BAAW,CAAC,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,KAAK,QAAQ,MAAM,KAAK,GAAG,CAAC;AAAA,cAC9E;AAAA;AAAA,YAVK,WAAW,MAAM,KAAK,GAAG;AAAA,UAWhC,CACD;AAAA,WACH;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;AAED,IAAM,KAAK,CAAC,WAAmB,EAAE,oBAAoB,OAAO,MAAM;AAElE,SAAS,MAAM;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,QAAM,WAAW,UACb;AAAA,IACE,gBAAgB;AAAA,IAChB,cAAc,KAAK;AAAA,IACnB,OAAO,EAAE,KAAK;AAAA,IACd,gBAAgB;AAAA,EAClB,IACA;AAAA,IACE,aAAa,KAAK;AAAA,IAClB,gBAAgB,CAAC,UACf,MAAM,cAAc,gBAAgB,eAAe;AAAA,EACvD;AAEJ,MAAI,KAAK,SAAS,QAAQ;AACxB,WACE,4CAAC,UAAK,WAAU,oBAAoB,GAAG,UACpC,eAAK,MACR;AAAA,EAEJ;AAEA,QAAM,WAAW,SAAS,UAAa,SAAS,KAAK;AAErD,SACE,4CAAC,UAAK,WAAU,oBAAmB,cAAY,KAAK,OAAQ,GAAG,UAE7D,sDAAC,UAAK,WAAU,sBACb,yBAAe,SACd,4CAAC,UAAK,WAAU,qBAAoB,OAAO,GAAG,KAAK,KAAK,GACrD,gBAAM,IAAI,CAAC,GAAG,MACb,4CAAC,UAAK,WAAU,oBACb,iBAAO,CAAC,KAD6B,CAExC,CACD,GACH,IAEA,4EACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QAEV,WAAS,WAAW,KAAK;AAAA,QAGxB,iBAAO,KAAK,KAAK;AAAA;AAAA,MAFb,MAAM,KAAK,KAAK,IAAI,WAAW,aAAa,MAAM;AAAA,IAGzD;AAAA,IACC,WACC,4CAAC,UAAK,WAAU,oBAAmB,YAAS,IACzC,iBAAO,IAAc,KAD4B,OAAO,IAAI,IAAI,UAAU,EAE7E,IACE;AAAA,KACN,GAEJ,GACF;AAEJ;","names":["Numbers","start"]}
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ function mergeRefs(...refs) {
|
|
|
28
28
|
|
|
29
29
|
// src/Numbers.tsx
|
|
30
30
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
31
|
+
var useSeated = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
31
32
|
var CYCLE = 10;
|
|
32
33
|
var HOME = CYCLE;
|
|
33
34
|
var CELLS = Array.from({ length: CYCLE * 3 }, (_, i) => i % CYCLE);
|
|
@@ -108,7 +109,7 @@ var Numbers = React.forwardRef(function Numbers2({ value, locale, format, transi
|
|
|
108
109
|
React.useEffect(() => () => {
|
|
109
110
|
if (outgoingTimer.current) clearTimeout(outgoingTimer.current);
|
|
110
111
|
}, []);
|
|
111
|
-
|
|
112
|
+
useSeated(() => {
|
|
112
113
|
const rowEl = row.current;
|
|
113
114
|
const hostEl = host.current;
|
|
114
115
|
if (!rowEl || !hostEl) return;
|
|
@@ -221,7 +222,7 @@ var Numbers = React.forwardRef(function Numbers2({ value, locale, format, transi
|
|
|
221
222
|
}).catch(() => {
|
|
222
223
|
});
|
|
223
224
|
}, [cells, value, trend, blur, duration, transition]);
|
|
224
|
-
|
|
225
|
+
useSeated(() => {
|
|
225
226
|
const rowEl = row.current;
|
|
226
227
|
if (!rowEl || leaving.length === 0 || reduced()) return;
|
|
227
228
|
const cs = getComputedStyle(rowEl);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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 softness?: 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, softness, 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 if (softness !== undefined) knobs[\"--sfi-numbers-softness\"] = `${softness}`;\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"]}
|
|
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 softness?: number;\n duration?: number;\n label?: string;\n}\n\nconst useSeated = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\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, softness, 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 useSeated(() => {\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 useSeated(() => {\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 if (softness !== undefined) knobs[\"--sfi-numbers-softness\"] = `${softness}`;\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"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sfinterface/numbers",
|
|
3
3
|
"author": "cz",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"description": "Numbers that move the way they should. A React component from The San Francisco Interface.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
},
|
|
55
55
|
"repository": {
|
|
56
56
|
"type": "git",
|
|
57
|
-
"url": "git+https://github.com/wherescz/
|
|
57
|
+
"url": "git+https://github.com/wherescz/sfinterface-numbers.git"
|
|
58
58
|
},
|
|
59
|
-
"homepage": "https://github.com/wherescz/
|
|
59
|
+
"homepage": "https://github.com/wherescz/sfinterface-numbers",
|
|
60
60
|
"bugs": {
|
|
61
|
-
"url": "https://github.com/wherescz/
|
|
61
|
+
"url": "https://github.com/wherescz/sfinterface-numbers/issues"
|
|
62
62
|
}
|
|
63
63
|
}
|