@base-ui/react
Version:
Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.
63 lines (60 loc) • 2.27 kB
JavaScript
const OTP_VALIDATION_CONFIG = {
numeric: {
slotPattern: '\\d{1}',
getRootPattern: length => `\\d{${length}}`,
regexp: /[^\d]/g,
inputMode: 'numeric'
},
alpha: {
slotPattern: '[a-zA-Z]{1}',
getRootPattern: length => `[a-zA-Z]{${length}}`,
regexp: /[^a-zA-Z]/g,
inputMode: 'text'
},
alphanumeric: {
slotPattern: '[a-zA-Z0-9]{1}',
getRootPattern: length => `[a-zA-Z0-9]{${length}}`,
regexp: /[^a-zA-Z0-9]/g,
inputMode: 'text'
}
};
export function getOTPValidationConfig(validationType) {
if (validationType === 'none') {
return null;
}
return OTP_VALIDATION_CONFIG[validationType];
}
export function stripOTPWhitespace(value) {
return (value ?? '').replace(/\s/g, '');
}
/**
* Normalizes user-entered OTP text by stripping whitespace, applying validation or custom
* sanitization, and clamping the final value to the configured slot count.
*/
export function normalizeOTPValue(value, length, validationType, sanitizeValue) {
let sanitizedValue = stripOTPWhitespace(value);
const validation = getOTPValidationConfig(validationType);
if (validation) {
sanitizedValue = sanitizedValue.replace(validation.regexp, '');
} else if (sanitizeValue) {
sanitizedValue = sanitizeValue(sanitizedValue);
}
// Slice by Unicode code points so multi-byte characters do not split across OTP slots.
return Array.from(sanitizedValue).slice(0, Math.max(length, 0)).join('');
}
/**
* Replaces characters starting at the provided slot index, then re-normalizes the final OTP value
* so paste and multi-character edits stay contiguous and length-bounded.
*/
export function replaceOTPValue(currentValue, index, nextValue, length, validationType, sanitizeValue) {
const normalizedValue = normalizeOTPValue(nextValue, length, validationType, sanitizeValue);
const prefix = currentValue.slice(0, index);
const suffix = currentValue.slice(index + normalizedValue.length);
return normalizeOTPValue(`${prefix}${normalizedValue}${suffix}`, length, validationType, sanitizeValue);
}
export function removeOTPCharacter(currentValue, index) {
if (index < 0 || index >= currentValue.length) {
return currentValue;
}
return `${currentValue.slice(0, index)}${currentValue.slice(index + 1)}`;
}