Число, у которого каждая цифра живёт своей жизнью. Когда значение меняется, одинаковые цифры не пропадают, а перелетают на свои новые позиции, лишние исчезают, недостающие появляются, и всё это на одной пружинной анимации.
Ширина блока измеряется и анимируется отдельно, поэтому соседний текст не прыгает. Разделители разрядов берутся из выбранной локали, а до и после числа можно поставить знак валюты, процент или единицу измерения.
Скопируйте эти файлы в components/number-layout-flow/:
Общие помощники положите в lib/ проекта:
Проверьте алиас путей. Импорты в коде выше записаны как @/components/... и @/lib/.... Нужен алиас "@/*" на папку, где лежат components/ и lib/, в tsconfig.json — или поправьте импорты под свои пути.
import { useState } from "react";
import { NumberLayoutFlow } from "@/components/number-layout-flow/number-layout-flow";
export function Balance() {
const [value, setValue] = useState(19348.43);
return (
<button type="button" onClick={() => setValue(Math.round(Math.random() * 100000) / 100)}>
<NumberLayoutFlow value={value} prefix="₽" locale="ru-RU" className="text-6xl" />
</button>
);
}valueОтображаемое число
Тип number
prefix?Текст перед числом
Тип string·По умолчанию ""
suffix?Текст после числа
Тип string·По умолчанию ""
format?Тип значения для вашей логики, на вывод не влияет
Тип "number" | "decimal" | "currency"
locale?Локаль для разделителей разрядов
Тип string·По умолчанию "en-US"
minimumFractionDigits?Минимум знаков после запятой
Тип number·По умолчанию 0
maximumFractionDigits?Максимум знаков после запятой
Тип number·По умолчанию 2
fontSize?Размер числа в пикселях
Тип number
color?Цвет числа, по умолчанию цвет темы
Тип string
stiffness?Жёсткость пружины
Тип number·По умолчанию 400
damping?Затухание пружины
Тип number·По умолчанию 35
className?Классы корневого блока
Тип string·По умолчанию ""