@maskito/react
Version:
The React-specific Maskito's library
65 lines (61 loc) • 2.24 kB
JavaScript
import { MASKITO_DEFAULT_ELEMENT_PREDICATE, Maskito } from '@maskito/core';
import { useLayoutEffect, useEffect, useState, useCallback, useRef } from 'react';
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
function isThenable(x) {
return x && typeof x === 'object' && 'then' in x;
}
/**
* Hook for convenient use of Maskito in React
* @description For controlled inputs use `onInput` event
* @param options options used for creating Maskito
* @param elementPredicate function that can help find nested Input or TextArea
* @returns ref callback to pass it in React Element
* @example
* // To avoid unnecessary hook runs with Maskito recreation pass named variables
* // good example ✅
* useMaskito({ options: maskitoOptions, elementPredicate: maskitoPredicate })
*
* // bad example ❌
* useMaskito({ options: { mask: /^.*$/ }, elementPredicate: () => e.querySelector('input') })
*/
const useMaskito = ({
options = null,
elementPredicate = MASKITO_DEFAULT_ELEMENT_PREDICATE
} = {}) => {
const [hostElement, setHostElement] = useState(null);
const [element, setElement] = useState(null);
const onRefChange = useCallback(node => {
setHostElement(node);
}, []);
const latestPredicateRef = useRef(elementPredicate);
const latestOptionsRef = useRef(options);
latestPredicateRef.current = elementPredicate;
latestOptionsRef.current = options;
useIsomorphicLayoutEffect(() => {
if (!hostElement) {
return;
}
const elementOrPromise = elementPredicate(hostElement);
if (isThenable(elementOrPromise)) {
void elementOrPromise.then(el => {
if (latestPredicateRef.current === elementPredicate && latestOptionsRef.current === options) {
setElement(el);
}
});
} else {
setElement(elementOrPromise);
}
}, [hostElement, elementPredicate, latestPredicateRef, options, latestOptionsRef]);
useIsomorphicLayoutEffect(() => {
if (!element || !options) {
return;
}
const maskedElement = new Maskito(element, options);
return () => {
maskedElement.destroy();
setElement(null);
};
}, [options, element]);
return onRefChange;
};
export { useMaskito };