UNPKG

@energma/input-mask-react

Version:

A React component for input mask with dynamic formatting. Fully compatible with React and Next.js.

161 lines (160 loc) 4.85 kB
import { jsx as S } from "react/jsx-runtime"; import { forwardRef as R, useRef as A, useState as F, useMemo as I } from "react"; const P = (t, p) => { const a = []; for (let f = 0; f < t.length; f++) t[f] !== p && a.push(f); return a; }, b = (t, p) => { switch (p) { case "numbers": return /\d/.test(t); case "letters": return /[a-zA-Z]/.test(t); case "mixed": default: return /[a-zA-Z0-9]/.test(t); } }, V = (t, p, a, f) => { let g = "", c = 0; for (let s = 0; s < p.length; s++) a.includes(s) ? g += p[s] : c < t.length ? (g += t[c], c++) : g += f; return g; }, M = (t, p, a) => { let f = 0, g = 0; for (let c = 0; c < p.length; c++) if (a.includes(c)) f++; else if (g < t.length) g++, f++; else break; return f; }, Z = R( ({ schema: t, value: p = "", onChange: a, placeholder: f, ...g }, c) => { const s = A(null), [u, k] = F(p), [B, x] = F(!1), m = I( () => P(t.mask, t.symbol), [t.mask] ), D = (e = t.mask, n = 0) => { if (!t.mask) return { formatted: "", newCursorPos: 0 }; let i = e.split(""), r = n; const o = e[n - 1] || ""; if (n > t.mask.length || n < 0) return { formatted: e.slice(0, t.mask.length), newCursorPos: n }; if (n >= 0 && !b(o, t.type)) return { formatted: u, newCursorPos: n - 1 }; for (let l = 0; l <= n; l++) if (m.includes(r - 1)) { const d = i[r - 1]; i[r - 1] = t.mask[r - 1], i[r] = d; } else i[l] = e[l], n == m.filter((d) => d == n)[0] && r++; for (let l = n; l <= t.mask.length; l++) u[l] && u[l] !== t.symbol ? i[l] = u[l] : i[l] = t.mask[l]; return { formatted: i.join(""), newCursorPos: r }; }; return /* @__PURE__ */ S( "input", { ...g, ref: (e) => { typeof c == "function" ? c(e) : c && (c.current = e), s.current = e; }, value: u, onChange: (e) => { e.stopPropagation(), e.preventDefault(); const n = e.target, i = e.nativeEvent, r = n.value, o = n.selectionStart || 0, l = i.inputType === "insertFromPaste"; let d, v; if (l) { const y = Array.from(r).filter((w) => b(w, t.type)).join(""); d = V( y, t.mask, m, t.symbol ), k(d), a == null || a({ ...e, target: { ...e.target, value: d } }), v = M( y, t.mask, m ), requestAnimationFrame(() => { s.current && s.current.setSelectionRange(v, v); }); } else { const { formatted: y, newCursorPos: w } = D( r, o ); k(y), a == null || a({ ...e, target: { ...e.target, value: y } }), requestAnimationFrame(() => { s.current && s.current.setSelectionRange(w, w); }); } }, onKeyDown: (e) => { var i, r; const n = ((i = s.current) == null ? void 0 : i.selectionStart) ?? 0; if (e.ctrlKey && e.key === "a") { if (e.preventDefault(), s.current) { const o = u.length; s.current.setSelectionRange(0, o); } return; } if (e.key === "Backspace" && n === 0 && ((r = s.current) == null ? void 0 : r.selectionEnd) === u.length) { e.preventDefault(), k(""); return; } if (e.key === "Backspace" && (e.preventDefault(), n > 0)) { let o = n - 1; for (; o > 0 && m.includes(o); ) o--; const l = u.substring(0, o) + t.mask[o] + u.substring(o + 1); k(l), requestAnimationFrame(() => { var d; (d = s.current) == null || d.setSelectionRange(o, o); }); } }, onKeyUp: () => { }, onFocus: (e) => { e.stopPropagation(), e.preventDefault(), x(!0); let n = -1; const i = u.length; for (let r = 0; r < t.mask.length; r++) if (t.mask[r] === t.symbol && (!u[r] || u[r] === t.symbol)) { n = r; break; } requestAnimationFrame(() => { s.current && n !== -1 ? s.current.setSelectionRange( n, n ) : s.current.setSelectionRange(i, i); }); }, onBlur: (e) => { e.stopPropagation(), e.preventDefault(), x(!1), u === t.mask && k(""); }, placeholder: f } ); } ); export { Z as MaskedInput };