vuetify
Version:
Vue Material Component Framework
164 lines (162 loc) • 4.3 kB
JavaScript
// Utilities
import { computed } from 'vue';
import { isObject, propsFactory } from "../../util/index.js"; // Types
export const makeMaskProps = propsFactory({
mask: [String, Object]
}, '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) {
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)
};
});
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 isValid(text) {
if (!text) return false;
return unmaskText(text) === unmaskText(maskText(text));
}
function isComplete(text) {
if (!text) return false;
const maskedText = maskText(text);
return maskedText.length === mask.value.length && isValid(text);
}
return {
isValid,
isComplete,
mask: maskText,
unmask: unmaskText
};
}
//# sourceMappingURL=mask.js.map