diff --git a/README.md b/README.md index 43a151d..5b9a336 100644 --- a/README.md +++ b/README.md @@ -24,28 +24,7 @@ yarn add react-native-text-input-mask # Installation
- For RN >= 0.61 - -#### iOS - -1. Add following lines to your target in `Podfile` -``` -use_frameworks! -pod 'RNInputMask', :path => '../node_modules/react-native-text-input-mask/ios/InputMask' -``` -2. Run following command -```bash -cd ios && pod install -``` - -#### Android - -No need to do anything. - -
- -
- For RN = 0.60.* + For RN >= 0.60 #### iOS diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..bbed0c9 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,18 @@ +import React, { ForwardRefExoticComponent, PropsWithoutRef, RefAttributes} from "react"; +import { TextInputProps, TextInput } from "react-native"; + +export type onChangeTextMask = ( + formatted?: string, + extracted?: string +) => void; + +export interface TextInputMaskProps + extends Omit { + maskDefaultValue?: boolean; + mask?: string; + onChangeText?: onChangeTextMask; +} + +declare const TextInputMask : ForwardRefExoticComponent & RefAttributes>; + +export default TextInputMask; \ No newline at end of file diff --git a/index.js b/index.js index 408edad..dfbef9a 100644 --- a/index.js +++ b/index.js @@ -1,71 +1,108 @@ -import React, { Component } from 'react' +import React, { useEffect, useRef, useImperativeHandle, useCallback } from "react"; import { TextInput, findNodeHandle, NativeModules, Platform -} from 'react-native' +} from "react-native"; -const mask = NativeModules.RNTextInputMask.mask -const unmask = NativeModules.RNTextInputMask.unmask -const setMask = NativeModules.RNTextInputMask.setMask -export { mask, unmask, setMask } +const mask = NativeModules.RNTextInputMask.mask; +const unmask = NativeModules.RNTextInputMask.unmask; +const setMask = NativeModules.RNTextInputMask.setMask; +export { mask, unmask, setMask }; -export default class TextInputMask extends Component { - static defaultProps = { - maskDefaultValue: true, - } +function TextInputMask(props, ref){ + const inputRef = useRef(); + const prevMask = useRef(props.mask) + const prevValue = useRef(props.value) + const masked = useRef(false); + const isMounted = useRef(false); - masked = false + const setNativeMask = useCallback( + (newInputMask)=>{ + inputRef.current && setMask(findNodeHandle(inputRef.current), newInputMask); + },[inputRef.current]); - componentDidMount() { - if (this.props.maskDefaultValue && - this.props.mask && - this.props.value) { - mask(this.props.mask, '' + this.props.value, text => - this.input && this.input.setNativeProps({ text }), - ) - } + const setNativeTextMask = useCallback((value, inputMask)=>{ + inputMask && mask( + inputMask, + "" + value, + text =>{ + inputRef.current && inputRef.current.setNativeProps({ text }); + prevValue.current = ""+ value; + } + ); + },[inputRef.current, prevValue.current]); - if (this.props.mask && !this.masked) { - this.masked = true - setMask(findNodeHandle(this.input), this.props.mask) + const onChangeText = useCallback(masked => { + if(masked === prevValue.current) return; + if (props.mask) { + const _unmasked = unmask(props.mask, masked, unmasked => { + props.onChangeText && props.onChangeText(masked, unmasked); + }); + } else { + props.onChangeText && props.onChangeText(masked); + } + },[props.onChangeText,prevValue.current]) + + useImperativeHandle(ref,()=>({ + isFocused : ()=>{ + return inputRef.current && inputRef.current.isFocused() + }, + focus: ()=>{ + return inputRef.current && inputRef.current.focus(); + }, + blur : ()=>{ + return inputRef.current && inputRef.current.blur(); + }, + clear: ()=>{ + return inputRef.current && inputRef.current.clear(); + }, + setNativeProps : ({ mask: inputMask, text, ...nativeProps})=>{ + if( (inputMask || props.mask) && (text || props.value)) setNativeTextMask(text || props.value, inputMask || props.mask); + if(inputMask !== props.mask) setNativeMask(inputMask); + return Object.keys(nativeProps).length && inputRef.current && inputRef.current.setNativeProps(nativeProps) } - } - - componentWillReceiveProps(nextProps) { - if (nextProps.mask && (this.props.value !== nextProps.value)) { - mask(this.props.mask, '' + nextProps.value, text => - this.input && this.input.setNativeProps({ text }) - ); + })); + + useEffect(() => { + if (props.maskDefaultValue && props.mask && props.value) setNativeTextMask(props.value, props.mask) + if (props.mask && !masked.current) { + setNativeMask(props.mask); + masked.current = true; } - - if (this.props.mask !== nextProps.mask) { - setMask(findNodeHandle(this.input), nextProps.mask) + isMounted.current = true; + return ()=>{ + isMounted.current = false } + }, []); + + // Check if value change + if(props.value !== prevValue.current){ + isMounted.current && setNativeTextMask(props.value,props.mask); + } + //Check if mask change + if(props.mask !== prevMask.current){ + isMounted.current && setNativeMask(props.mask); + prevMask.current = props.mask; } - render() { - return ( { - this.input = ref - if (typeof this.props.refInput === 'function') { - this.props.refInput(ref) - } - }} - multiline={this.props.mask && Platform.OS === 'ios' ? false : this.props.multiline} - onChangeText={masked => { - if (this.props.mask) { - const _unmasked = unmask(this.props.mask, masked, unmasked => { - this.props.onChangeText && this.props.onChangeText(masked, unmasked) - }) - } else { - this.props.onChangeText && this.props.onChangeText(masked) - } - }} - />); - } + multiline={props.mask && Platform.OS === "ios" ? false : props.multiline} + onChangeText={onChangeText} + /> + ); } + +TextInputMask = React.forwardRef(TextInputMask); + +TextInputMask.defaultProps = { + maskDefaultValue: true +}; + +export default React.memo(TextInputMask,(prevProps,nextProps)=>prevProps.mask === nextProps.mask && prevProps.value === nextProps.value); diff --git a/package.json b/package.json index ca59f9d..eb03c92 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-text-input-mask", - "version": "2.0.0", + "version": "2.0.1", "description": "Text input mask for React Native.", "main": "index.js", "repository": {