UNPKG

@maskito/react

Version:

The React-specific Maskito's library

65 lines (61 loc) 2.24 kB
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 };