vuetify
Version:
Vue Material Component Framework
183 lines (181 loc) • 5 kB
JavaScript
// Utilities
import { computed, shallowRef } from 'vue';
import { isObject, propsFactory } from "../util/index.js"; // Types
export const makeMaskProps = propsFactory({
mask: [String, Object],
returnMaskedValue: Boolean
}, 'mask');
export const defaultDelimiters = /[-!$%^&*()_+|~=`{}[\]:";'<>?,./\\ ]/;
const presets = {
'credit-card': '#### - #### - #### - ####',
date: '##/##/####',
'date-time': '##/##/#### ##:##',
'iso-date': '####-##-##',
'iso-date-time': '####-##-## ##:##',
phone: '(###) ### - ####',
social: '###-##-####',
time: '##:##',
'time-with-seconds': '##:##:##'
};
export function isMaskDelimiter(char) {
return char ? defaultDelimiters.test(char) : false;
}
const defaultTokens = {
'#': {
pattern: /[0-9]/
},
A: {
pattern: /[A-Z]/i,
convert: v => v.toUpperCase()
},
a: {
pattern: /[a-z]/i,
convert: v => v.toLowerCase()
},
N: {
pattern: /[0-9A-Z]/i,
convert: v => v.toUpperCase()
},
n: {
pattern: /[0-9a-z]/i,
convert: v => v.toLowerCase()
},
X: {
pattern: defaultDelimiters
}
};
export function useMask(props, inputRef) {
const mask = computed(() => {
if (typeof props.mask === 'string') {
if (props.mask in presets) return presets[props.mask];
return props.mask;
}
return props.mask?.mask ?? '';
});
const tokens = computed(() => {
return {
...defaultTokens,
...(isObject(props.mask) ? props.mask.tokens : null)
};
});
const selection = shallowRef(0);
const lazySelection = shallowRef(0);
function isMask(char) {
return char in tokens.value;
}
function maskValidates(mask, char) {
if (char == null || !isMask(mask)) return false;
const item = tokens.value[mask];
if (item.pattern) return item.pattern.test(char);
return item.test(char);
}
function convert(mask, char) {
const item = tokens.value[mask];
return item.convert ? item.convert(char) : char;
}
function maskText(text) {
const trimmedText = text?.trim().replace(/\s+/g, ' ');
if (trimmedText == null) return '';
if (!mask.value.length || !trimmedText.length) return trimmedText;
let textIndex = 0;
let maskIndex = 0;
let newText = '';
while (maskIndex < mask.value.length) {
const mchar = mask.value[maskIndex];
const tchar = trimmedText[textIndex];
// Escaped character in mask, the next mask character is inserted
if (mchar === '\\') {
newText += mask.value[maskIndex + 1];
maskIndex += 2;
continue;
}
if (!isMask(mchar)) {
newText += mchar;
if (tchar === mchar) {
textIndex++;
}
} else if (maskValidates(mchar, tchar)) {
newText += convert(mchar, tchar);
textIndex++;
} else {
break;
}
maskIndex++;
}
return newText;
}
function unmaskText(text) {
if (text == null) return null;
if (!mask.value.length || !text.length) return text;
let textIndex = 0;
let maskIndex = 0;
let newText = '';
while (true) {
const mchar = mask.value[maskIndex];
const tchar = text[textIndex];
if (tchar == null) break;
if (mchar == null) {
newText += tchar;
textIndex++;
continue;
}
// Escaped character in mask, skip the next input character
if (mchar === '\\') {
if (tchar === mask.value[maskIndex + 1]) {
textIndex++;
}
maskIndex += 2;
continue;
}
if (maskValidates(mchar, tchar)) {
// masked char
newText += tchar;
textIndex++;
maskIndex++;
continue;
} else if (mchar !== tchar) {
// input doesn't match mask, skip forward until it does
while (true) {
const mchar = mask.value[maskIndex++];
if (mchar == null || maskValidates(mchar, tchar)) break;
}
continue;
}
textIndex++;
maskIndex++;
}
return newText;
}
function setCaretPosition(newSelection) {
selection.value = newSelection;
inputRef.value && inputRef.value.setSelectionRange(selection.value, selection.value);
}
function resetSelections() {
if (!inputRef.value?.selectionEnd) return;
selection.value = inputRef.value.selectionEnd;
lazySelection.value = 0;
for (let index = 0; index < selection.value; index++) {
isMaskDelimiter(inputRef.value.value[index]) || lazySelection.value++;
}
}
function updateRange() {
if (!inputRef.value) return;
resetSelections();
let selection = 0;
const newValue = inputRef.value.value;
if (newValue) {
for (let index = 0; index < newValue.length; index++) {
if (lazySelection.value <= 0) break;
isMaskDelimiter(newValue[index]) || lazySelection.value--;
selection++;
}
}
setCaretPosition(selection);
}
return {
updateRange,
maskText,
unmaskText
};
}
//# sourceMappingURL=mask.js.map