feat(forms): add useMaskedField and useMaskedInput composables for input masking
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Default {@link maskFromTemplate} tokens: `#` → digit, `A` → letter,
|
||||
* `*` → letter or digit. Every other template character is a fixed literal.
|
||||
*/
|
||||
export const DEFAULT_MASK_TOKENS: Readonly<Record<string, RegExp>> = {
|
||||
'#': /\d/,
|
||||
A: /[a-z]/i,
|
||||
'*': /[a-z0-9]/i,
|
||||
};
|
||||
|
||||
// Compiled-mask cache for the default-token path. Function masks (phone/card)
|
||||
// re-resolve the same template several times per keystroke; caching collapses
|
||||
// each repeat to a Map hit instead of rebuilding a 12-17 element array.
|
||||
const TEMPLATE_CACHE = new Map<string, ReadonlyArray<RegExp | string>>();
|
||||
|
||||
function compileTemplate(template: string, tokens: Readonly<Record<string, RegExp>>): Array<RegExp | string> {
|
||||
const mask: Array<RegExp | string> = [];
|
||||
|
||||
for (const char of template)
|
||||
mask.push(tokens[char] ?? char);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name maskFromTemplate
|
||||
* @category Forms
|
||||
* @description Compile a human-readable template into a mask array. Token
|
||||
* characters become matcher slots; everything else becomes a fixed literal. With
|
||||
* the default tokens the compiled array is cached and shared (frozen) per
|
||||
* template string; pass a custom `tokens` map to opt out.
|
||||
*
|
||||
* @param {string} template e.g. `'+1 (###) ###-####'`
|
||||
* @param {Record<string, RegExp>} [tokens=DEFAULT_MASK_TOKENS] Token → matcher map
|
||||
* @returns {ReadonlyArray<RegExp | string>} The compiled mask expression
|
||||
*
|
||||
* @example
|
||||
* maskFromTemplate('##/##/####'); // [/\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/]
|
||||
*
|
||||
* @since 0.0.17
|
||||
*/
|
||||
export function maskFromTemplate(
|
||||
template: string,
|
||||
tokens: Readonly<Record<string, RegExp>> = DEFAULT_MASK_TOKENS,
|
||||
): ReadonlyArray<RegExp | string> {
|
||||
if (tokens !== DEFAULT_MASK_TOKENS)
|
||||
return compileTemplate(template, tokens);
|
||||
|
||||
const cached = TEMPLATE_CACHE.get(template);
|
||||
if (cached)
|
||||
return cached;
|
||||
|
||||
const compiled = Object.freeze(compileTemplate(template, tokens));
|
||||
TEMPLATE_CACHE.set(template, compiled);
|
||||
|
||||
return compiled;
|
||||
}
|
||||
Reference in New Issue
Block a user