React 数字流输入
零依赖性 React 组件,可以使动画数字输入. 数字动画的输入, 选择和替换一个数字 给您带来流行的桶轮效果 数字花外部 value 改变动能 作为协调的桶轮 滚过每一个数字.
演示
https://hello-mat.com/design-engineering/组件/数字-流量-输入
特征
- 零运行时间依赖关系 ——对等重现的依赖
>= 18什么都没有. - 两个同步输入 a 包括:
contenteditable对于动画显示和隐藏<input>土著形式融合(name, (中文(简体) ),form, (中文(简体) ),required(中文(简体) ). - 受控制或不受控制 ——使用
value或者说defaultValue。 。 。 . - 地方意识格式 - 可选
Intl.NumberFormat千位分隔符和小数语言字符. - 智能编辑 ——取消/重做,复制/剪接/涂装,小数级夹克,最大长度,负数,领先-零处理等.
- 自定义验证 —— 说
isAllowed(value)来拒绝你不喜欢的价值观. - 包括动画 ——数字出行入行入行入行入行入行入行入行入行入行入行出行入行入行入行入行入行入行入行入行入行出行入行入行入行入行入行入行出行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行出行入行出行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行出行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行入行.
- 最小样式自动注入 a 包括:
<style>标签被添加到<head>在第一个挂载时,不需要导入 CSS 。 安全无虞. - 完全输入 ——有TypeScript类型的舰只.
- 测试的很好 ——220+单位和集成试验.
安装
npm install @daformat/react-number-flow-input
yarn add @daformat/react-number-flow-input
pnpm add @daformat/react-number-flow-input
bun add @daformat/react-number-flow-input
deno add npm:@daformat/react-number-flow-input
快开始
import { NumberFlowInput } from "@daformat/react-number-flow-input";
export function Example() {
return (
<NumberFlowInput
defaultValue={1234}
format
onChange={(value) => console.log(value)}
/>
);
}
使用量
无控制
<NumberFlowInput defaultValue={42} onChange={(value) => console.log(value)} />
已控制
import { useState } from "react";
import { NumberFlowInput } from "@daformat/react-number-flow-input";
function Controlled() {
const [value, setValue] = useState<number | undefined>(0);
return <NumberFlowInput value={value} onChange={setValue} />;
}
外部更新到 value 与先前的值相对应,作为相协调的桶轮滚而产生动能。 初始挂载永不动画 .
在外部选择退出动画 value 变化——例如,在程序上恢复一个值或约束一个吵吵的状态源时——通过 animateOnValueChange={false}数字 :
<NumberFlowInput
value={value}
onChange={setValue}
animateOnValueChange={false}
/>
用户打字和 format 编号 : locale 切换仍为动画;只有道具驱动的值刷新.
格式显示
<NumberFlowInput format value={1234567} /> // → "1,234,567"
<NumberFlowInput format locale="de-DE" value={1234567} /> // → "1.234.567"
自定义处理
format 也接受对显示字符串进行全面控制的函数。 回调收到原始显示值( 数字, 可选的线索) -,可选单曲 . 并返回格式化文本:
<NumberFlowInput
defaultValue={1234.5}
format={(raw) => `$ ${raw}`}
onChange={console.log}
/>
// → "$ 1234.5"
召回只用于“ 真实” 值—— 空 / "-" 编号 : "." 编号 : "-." 中间状态绕过它,逐字渲染。 如果您的函数抛出, 组件会返回到一个安全的 locale- 十进制 swap 输出 .
对于正确的光标定位和动画抖动,您的输出应当:
- 使用该地块的小数字符(或
.(a) 如果没有设置地方; - 从原始输入中保留数字顺序.
小数比例和负数
<NumberFlowInput allowNegative decimalScale={2} defaultValue={-1234.5} format />
decimalScale={0} 防止用户输入小数点. decimalScale={n} 夹住分数位数.
语言
<NumberFlowInput locale="fr-FR" defaultValue={1234.5} format />
// Renders "1 234,5" (or the locale's group separator).
本部分接受两者 . 和 locale 的十进制分隔符作为输入符——输入一个解析到显示中 locale 的十进制.
自定义验证
<NumberFlowInput
isAllowed={(value) => value == null || (value >= 0 && value <= 100)}
/>
任何在允许范围以外产生值的按键中键都会被拒绝,并且永远不会达到 onChange。 。 。 .
长度限制
<NumberFlowInput maxLength={6} />
形式整合
组件会隐藏 <input> (屏幕关闭, readonly) 反映当前数值,因此它参与本地格式提交:
<form action="/submit" method="post">
<NumberFlowInput name="price" required min={0} max={9999} defaultValue={0} />
<button type="submit">Save</button>
</form>
name, (中文(简体) ), form, (中文(简体) ), required, (中文(简体) ), min, (中文(简体) ), max, (中文(简体) ), minLength 财务报告和审定财务报表 maxLength 被传送到隐藏输入.
自动聚焦/ 事件
<NumberFlowInput
autoFocus
onFocus={() => console.log("focused")}
onBlur={() => console.log("blurred")}
/>
参考文献
这个 ref 已转交 contenteditable 元素 :
const ref = useRef<HTMLElement>(null);
<NumberFlowInput ref={ref} />;
API 密码
import type {
NumberFlowInputProps,
NumberFlowInputCommonProps,
NumberFlowInputControlledProps,
NumberFlowInputUncontrolledProps,
} from "@daformat/react-number-flow-input";
值道具
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
value | number | string | undefined | —— 说 | 受控值. 接受数字或数字字符串(参见 字符串值) (中文(简体) ). 改变动能为桶轮滚(初始上架除外). |
defaultValue | number | string | —— 说 | 无控制的起始值 。 接受与 value。 。 。 . |
onChange | (value) => void | —— 说 | 使用解析后的数字调用( 或 undefined 中间状态 "", (中文(简体) ), "-", (中文(简体) ), ".", (中文(简体) ), "-.") (中文(简体) ). |
onChangeText | (rawText) => void | —— 说 | 一并起火 onChange 与原始字符串代表(如:. "12345678901234567890.123") (中文(简体) ). 需要保存JavaScript以外的精度时使用此选项 number 看到了吗 精确度。 。 。 . |
animateOnValueChange | boolean | true | 何时 false外部 value 即时更新即时快讯——没有数字卷,没有分隔符幻灯片,没有流动. 键入和 format 编号 : locale 切换仍然动静. |
value财务报告和审定财务报表defaultValue互相排斥 – TypeScript 将执行此功能.
格式化
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
format | boolean | (raw: string) => string | false | true • 分组通过 Intl.NumberFormat函数完全控制输出(见 自定义处理) (中文(简体) ). |
locale | string | Intl.Locale | —— 说 | 用于小数和组分隔符的语言 。 默认为运行时间的地盘 . |
decimalScale | number | —— 说 | 分数的最大数字 . 0 完全禁止小数点. |
autoAddLeadingZero | boolean | false | 转换线索 .5 → 0.5 (和 -.5 → -0.5自动. |
allowNegative | boolean | false | 允许输入线索 - 输入负数. |
编辑限制
| Prop | 类型 | 说明 |
|---|---|---|
maxLength | number | 用户可输入的最大原始长度( 在格式化前计算) . |
minLength | number | 被传送到隐藏的地方 <input> 用于形式验证. |
min编号 :max | number | 被传送到隐藏的地方 <input> 用于形式验证. |
isAllowed | (value: number | null) => bool | 预示着每变一变 返回时 false 拒绝按键. |
DOM / 形式传递
id, (中文(简体) ), name, (中文(简体) ), form, (中文(简体) ), required, (中文(简体) ), placeholder, (中文(简体) ), className, (中文(简体) ), style, (中文(简体) ), onFocus, (中文(简体) ), onBlur, (中文(简体) ), autoFocus。 。 。 . className 财务报告和审定财务报表 style 被应用到根包 <span>。 。 。 .
样式
样式在第一个挂载时向全球注入。 每个选择者被限制到 [data-numberflow-input-root]这样他们就不会泄露到你的应用程序里.
DOM结构(简化后):
<span data-numberflow-input-root class="{className}">
<span data-numberflow-input-wrapper>
<span
role="textbox"
contenteditable="true"
data-numberflow-input-contenteditable
data-placeholder="{placeholder}"
>
<span data-char-index="0" data-flow data-show>1</span>
<span data-char-index="1">,</span>
<!-- ...one span per character... -->
</span>
<input data-numberflow-input-real-input type="text" readonly />
<!-- barrel-wheel overlays are appended here while animating -->
</span>
</span>
您可以针对上述任何数据属性自定义外观 :
[data-numberflow-input-contenteditable] {
font-variant-numeric: tabular-nums;
font-feature-settings: "tnum";
}
[data-numberflow-input-contenteditable]:empty::before {
color: #999; /* placeholder color */
}
动画计时器位于被注入的样式表和使用中 cubic-bezier(.215, .61, .355, 1) (休养出立方. 动画是 0.2s;桶轮滚和宽度动画是 0.4s。 。 。 .
精确度
构件是围绕一个以字符串为基础的内部代表来构建的,所以哪些用户类型是按特征保存的——输入本身内部没有静态圆形. 在你身边 能够 运行到精度损失位于 JavaScript 的边界 number 类型 :
| 边界 | 输了? | 原因 |
|---|---|---|
| 用户打字 — DOM 显示 | 没有 | 每个键盘被应用到字符串中; DOM 更新为 textContent。 。 。 . |
用户打字 onChange(value) | 是的,因为 > Number.MAX_SAFE_INTEGER 或者说 > 15–17 sig. 无花果. | value 实值 parseFloat(rawText); IEEE 754 双倍不能精确代表每个小数. |
| 格式显示, 整数部分 | 是, 对于整数 > Number.MAX_SAFE_INTEGER | 何时 format 上,整数部分通过 Intl.NumberFormat.format(parseFloat(rawText))。 。 。 . |
| 格式显示, 小数部分 | 没有 | 小数部分在Intl格式化后从原始字符串中逐字恢复. |
value 道具-显示 | 继承父方已经计算的数值的精确性 . | 举个例子. 0.1 + 0.2 === 0.30000000000000004 ——该部分完全展现了JS给予的内容. |
defaultValue 道具-显示 | 与上同为相. | —— 说 |
字符串值
为了完成任意精确使用案件的往返旅行, value 财务报告和审定财务报表 defaultValue 还接受a 数字字符串 外加一个 number数字 :
// Preserves trailing zeros that a `number` would drop
<NumberFlowInput value="1.50" onChangeText={setRaw} />
// Preserves integers beyond Number.MAX_SAFE_INTEGER
<NumberFlowInput value="12345678901234567890" onChangeText={setRaw} />
// Currency stored as a string
<NumberFlowInput defaultValue="100.00" format />
字符串通过与用户输入相同的管道进行消毒——只有匹配字符 /^-?\d*\.?\d*$/ 生存下来。 容克字符串崩溃为空值(例如. "$1,234.56" → "1234.56", (中文(简体) ), "abc" → "") (中文(简体) ). 使用 . 作为小数分隔符,无论大小 locale。 。 。 .
onChange总是收到解析number(因此JavaScript精密边界仍然适用于该侧). 配对字符串道具onChangeText如果你的祖国必须保持完全精确.
onChangeText 任意精确值
当您需要输入的精确数字时( BigInt 数学、 货币存储为字符串、 大十进制库等), 请使用 onChangeText 召回——它同时起火 onChange 带有原始字符串代表的字符串:
import { useState } from "react";
import { NumberFlowInput } from "@daformat/react-number-flow-input";
function HugeNumber() {
const [raw, setRaw] = useState("");
return (
<>
<NumberFlowInput onChangeText={setRaw} />
<p>BigInt: {raw === "" ? "—" : BigInt(raw.split(".")[0]).toString()}</p>
</>
);
}
字符串是未格式化的内部代表: 数字,一个可选的线索 -,最多一个 . (总是) .,从小到小 中间州喜欢 "", (中文(简体) ), "-", (中文(简体) ), ".", (中文(简体) ), "-." 如果消费者愿意,他们可以制造它们.
如果你只消费 onChange (典型情况),注意过去的价值 9.007 × 10¹⁵ (安全整数天花板)或有超过~17个显著数字的会圆.
服务器侧渲染
injectStyles() 是服务器上的禁用程序,是客户端上的独家程序。 组件本身只触及里面的 DOM useInsertionEffect 编号 : useEffect,因此在Next.js,Remix和其他SSSR框架中可以做到干净.
浏览器支持
现代常绿浏览器. 需要的浏览器特性 :
Intl.NumberFormat(计:format编号 :locale(中文(简体) )- 网络动画 API(
element.animate(...))——用于枪管轮和位置动画 - 支助科
transition+ 键transform用于流入动画 requestAnimationFrame, (中文(简体) ),ResizeObserver
发展
pnpm install
pnpm test # vitest run
pnpm build --watch # tsc -p tsconfig.build.json
pnpm format # prettier --write .
pnpm lint:js # eslint .
项目布局
src/
├── NumberFlowInput.tsx # The component
├── styles.ts # Injected stylesheet
├── index.ts # Public entry point
└── utils/
├── barrelWheel.ts # Wheel DOM helpers
├── changes.ts # Diffing (typing & replacement)
├── combineRefs.ts # Ref forwarding helper
├── cssEasing.ts # Cubic-bezier tokens
├── formatting.ts # Intl.NumberFormat wrapper
├── moveElementPreservingAnimation.ts
├── textCleaning.ts # Raw text sanitization
└── utils.ts # DOM/measurement helpers
每个管子都有自己的 *.test.ts 文件旁边; 组件级别测试运行于 src/NumberFlowInput.test.tsx。 。 。 .
许可证
零相机 BSD - 随你怎么说.