@signalapp/minimask
Version:
Simple HTML input masking
151 lines (149 loc) • 3.95 kB
JavaScript
// src/getNextInputState.ts
function getNextInputState(formatter, prevValue, prevStart, prevEnd, isDeleting) {
let value = "";
let start = null;
let end = null;
let cursor = 0;
let lastIndex = 0;
for (let token of formatter(prevValue)) {
value += token.char;
if (isDeleting && token.mask) continue;
while (cursor <= token.index) {
if (cursor === prevStart) start ??= lastIndex;
if (cursor === prevEnd) end ??= lastIndex;
cursor += 1;
}
lastIndex = value.length;
}
if (isDeleting && end === null) {
value = value.slice(0, lastIndex);
}
start ??= value.length;
end ??= value.length;
return { value, start, end };
}
// src/formatters/cc-exp.ts
function isDigit(char) {
return /\d/.test(char);
}
function createCreditCardExpirationFormatter() {
return function creditCardExpirationFormatter(input) {
let chars = input.split("");
let index = 0;
let char = chars[index];
function next() {
char = chars[++index];
}
function take() {
if (char == null) throw new Error();
let token = { char, index, mask: false };
next();
return token;
}
if (char == "/") {
return [];
}
while (char != null && !isDigit(char)) {
next();
}
if (char == null) {
return [];
}
let month1 = take();
let month2;
if (month1.char === "0") {
if (char == null || !isDigit(char) || char === "0") {
return [month1];
} else {
month2 = take();
}
} else if (month1.char === "1") {
if (char == null) {
return [month1];
} else if (char === "0" || char === "1" || char === "2") {
month2 = take();
} else {
month2 = month1;
month1 = null;
}
} else {
month2 = month1;
month1 = null;
}
let slashIndex = null;
if (char != null && !isDigit(char)) {
slashIndex = index;
} else {
slashIndex = month2.index;
month1 ??= { char: "0", index: month2.index, mask: false };
}
let year = [];
while (char != null) {
if (isDigit(char)) {
year.push(take());
if (year.length >= 4) {
break;
}
} else {
next();
}
}
if (year.length >= 4) {
year = year.slice(2, 4);
} else {
year = year.slice(0, 2);
}
let tokens = [];
if (month1 != null) tokens.push(month1);
if (month2 != null) tokens.push(month2);
if (month2 != null) {
tokens.push({ char: "/", index: slashIndex, mask: true });
}
return tokens.concat(year);
};
}
// src/minimask.ts
var DELETE_BACKWARD = /* @__PURE__ */ new Set([
"deleteContentBackward",
"deleteWordBackward",
"deleteSoftLineBackward",
"deleteHardLineBackward"
]);
function minimask(input, formatter) {
let history = [input.value];
let historyIndex = 0;
let onInput = (event) => {
const inputType = event.inputType;
if (inputType === "historyUndo") {
historyIndex = Math.max(historyIndex - 1, 0);
input.value = history[historyIndex];
} else if (inputType === "historyRedo") {
historyIndex = Math.min(historyIndex + 1, history.length - 1);
input.value = history[historyIndex];
} else {
let isDeleting = DELETE_BACKWARD.has(inputType);
let { value, start, end } = getNextInputState(
formatter,
input.value,
input.selectionStart ?? 0,
input.selectionEnd ?? 0,
isDeleting
);
input.value = value;
input.setSelectionRange(start, end);
if (value !== history[historyIndex]) {
historyIndex++;
history.splice(historyIndex, Infinity, input.value);
}
}
};
input.addEventListener("input", onInput);
return function unsubscribe() {
input.removeEventListener("input", onInput);
};
}
export {
createCreditCardExpirationFormatter,
minimask
};
//# sourceMappingURL=minimask.js.map