react-pin-field
Version:
React component for entering PIN codes
195 lines (194 loc) • 6.18 kB
JavaScript
import { useRef as _, useReducer as R, useMemo as C, useCallback as B, forwardRef as I, useImperativeHandle as O, useEffect as m, createElement as q } from "react";
const k = 8, b = 46;
function E() {
}
function H(s, e) {
return Array.from({ length: e }, (t, u) => u + s);
}
function N(s) {
try {
return (s.webkitMatchesSelector || s.matches).call(s, ":focus");
} catch {
return !1;
}
}
const h = {
length: 5,
format: (s) => s,
formatAriaLabel: (s, e) => `PIN field ${s} of ${e}`,
onChange: E,
onComplete: E
}, V = {
type: "text",
inputMode: "text",
autoCapitalize: "off",
autoCorrect: "off",
autoComplete: "off"
}, Y = {
length: h.length,
format: h.format,
dir: "ltr",
cursor: 0,
values: Array(h.length),
backspace: !1,
composition: !1,
ready: !1,
dirty: !1
};
function $(s, e) {
switch (e.type) {
case "update-props": {
const t = { ...s, ...e.props };
return t.cursor = Math.min(t.cursor, t.length - 1), t.values = t.values.slice(0, t.cursor + 1), t.ready = !0, t;
}
case "start-composition":
return { ...s, dirty: !0, composition: !0 };
case "end-composition": {
const t = { ...s };
e.value ? t.values[e.index] = e.value : delete t.values[e.index];
const u = t.values[e.index] ? 1 : 0;
return t.cursor = Math.min(e.index + u, t.length - 1), t.composition = !1, t.dirty = !0, t;
}
case "handle-change": {
if (s.composition)
break;
const t = { ...s };
if (e.reset && t.values.splice(e.index, t.length), e.value) {
const u = e.value.split("").map(t.format), i = Math.min(t.length - e.index, u.length);
t.values.splice(e.index, i, ...u.slice(0, i)), t.cursor = Math.min(e.index + i, t.length - 1);
} else {
delete t.values[e.index];
const u = t.backspace ? 0 : 1;
t.cursor = Math.max(0, e.index - u);
}
return t.backspace = !1, t.dirty = !0, t;
}
case "handle-key-down": {
const t = e.key === "Backspace" || e.key === "Delete", u = e.code === "Backspace" || e.code === "Delete", i = e.keyCode === k || e.keyCode === b, p = e.which === k || e.which === b;
if (!(t || u || i || p) || s.values[e.index])
break;
{
const c = { ...s };
return c.cursor = Math.max(0, e.index - 1), c.backspace = !0, c.dirty = !0, c;
}
}
}
return s;
}
function z() {
const s = _([]), [e, t] = R($, Y), u = C(() => {
let p = "";
for (let y = 0; y < e.length; y++)
p += y in e.values ? e.values[y] : "";
return p;
}, [e]), i = B(
(p) => {
t({ type: "handle-change", index: 0, value: p, reset: !0 });
},
[t, e.cursor]
);
return C(
() => ({ refs: s, state: e, dispatch: t, value: u, setValue: i }),
[s, e, t, u, i]
);
}
const W = I(
({
length: s = h.length,
format: e = h.format,
formatAriaLabel: t = h.formatAriaLabel,
onChange: u = h.onChange,
onComplete: i = h.onComplete,
handler: p,
autoFocus: y,
...c
}, w) => {
const A = z(), { refs: f, state: r, dispatch: l } = p || A;
O(w, () => f.current, [f]);
function x(n) {
return (o) => {
o && (f.current[n] = o);
};
}
function M(n) {
return (o) => {
const { key: a, code: d, keyCode: g, which: F } = o;
l({ type: "handle-key-down", index: n, key: a, code: d, keyCode: g, which: F });
};
}
function D(n) {
return (o) => {
if (o.nativeEvent instanceof InputEvent) {
const a = o.nativeEvent.data;
l({ type: "handle-change", index: n, value: a });
} else {
const { value: a } = o.target;
l({ type: "handle-change", index: n, value: a, reset: !0 });
}
};
}
function K(n) {
return () => {
l({ type: "start-composition", index: n });
};
}
function L(n) {
return (o) => {
l({ type: "end-composition", index: n, value: o.data });
};
}
if (m(() => {
var o, a;
if (r.ready) return;
const n = ((o = c.dir) == null ? void 0 : o.toLowerCase()) || ((a = document.documentElement.getAttribute("dir")) == null ? void 0 : a.toLowerCase());
l({ type: "update-props", props: { length: s, format: e, dir: n } });
}, [r.ready, l, s, e]), m(() => {
r.ready && s !== r.length && l({ type: "update-props", props: { length: s } });
}, [r.ready, s, r.length, l]), m(() => {
r.ready && e !== r.format && l({ type: "update-props", props: { format: e } });
}, [r.ready, e, r.format, l]), m(() => {
var o, a;
if (!r.ready) return;
const n = ((o = c.dir) == null ? void 0 : o.toLowerCase()) || ((a = document.documentElement.getAttribute("dir")) == null ? void 0 : a.toLowerCase());
n !== r.dir && l({ type: "update-props", props: { dir: n } });
}, [r.ready, c.dir, r.dir, l]), m(() => {
if (!f.current || !r.ready || !r.dirty) return;
let n = !1, o = r.values.length == r.length, a = "";
for (let d = 0; d < r.length; d++) {
const g = d in r.values ? r.values[d] : "";
f.current[d].value = g, n = n || N(f.current[d]), o = o && d in r.values && f.current[d].checkValidity(), a += g;
}
n && f.current[r.cursor].focus(), u && u(a), i && o && i(a);
}, [f, r, u, i]), !r.ready)
return null;
const v = H(0, r.length).map((n) => /* @__PURE__ */ q(
"input",
{
...V,
...c,
key: n,
ref: x(n),
value: n in r.values ? r.values[n] : "",
autoFocus: n === 0 && y,
onKeyDown: M(n),
onChange: D(n),
onCompositionStart: K(n),
onCompositionEnd: L(n),
"aria-label": t(n + 1, r.length),
"aria-required": c.required ? "true" : void 0,
"aria-disabled": c.disabled ? "true" : void 0,
"aria-readonly": c.readOnly ? "true" : void 0
}
));
return r.dir === "rtl" && v.reverse(), v;
}
);
export {
W as default,
V as defaultNativeProps,
h as defaultProps,
Y as defaultState,
$ as reducer,
z as usePinField
};
//# sourceMappingURL=react-pin-field.js.map