| 8 | * @public |
| 9 | */ |
| 10 | export default function casts(node: FormKitNode): void { |
| 11 | if (typeof node.props.number === 'undefined') return |
| 12 | const strict = ['number', 'range', 'hidden'].includes(node.props.type) |
| 13 | node.hook.input((value, next) => { |
| 14 | if (value === '') return next(undefined) |
| 15 | if (typeof value === 'number' && Number.isFinite(value)) { |
| 16 | // Already a number — preserve it (including -0, which parseFloat would |
| 17 | // collapse to 0 via string coercion). |
| 18 | return next(node.props.number === 'integer' ? Math.trunc(value) : value) |
| 19 | } |
| 20 | if ( |
| 21 | strict && |
| 22 | typeof value === 'string' && |
| 23 | (value === '-' || |
| 24 | value === '+' || |
| 25 | value === '-0' || |
| 26 | // A numeric prefix ending in a decimal separator (".", "-.", "5.") |
| 27 | // is an in-progress value — anything else (e.g. "abc.") is not. |
| 28 | /^[-+]?\d*\.$/.test(value)) |
| 29 | ) { |
| 30 | // Transient strings that may become valid numbers as the user types |
| 31 | // are passed through so typing isn't interrupted (#1671, #1262). They |
| 32 | // are normalized to numbers when the input blurs. |
| 33 | return next(value) |
| 34 | } |
| 35 | const numericValue = |
| 36 | node.props.number === 'integer' ? parseInt(value) : parseFloat(value) |
| 37 | if (!Number.isFinite(numericValue)) |
| 38 | return strict ? next(undefined) : next(value) |
| 39 | return next(numericValue) |
| 40 | }) |
| 41 | } |