UNPKG

react-imask

Version:
163 lines (159 loc) 6.13 kB
import React from 'react'; import PropTypes from 'prop-types'; import IMask from 'imask/esm/imask'; const MASK_PROPS = { // common mask: PropTypes.oneOfType([PropTypes.array, PropTypes.func, PropTypes.string, PropTypes.instanceOf(RegExp), PropTypes.oneOf([Date, Number, IMask.Masked]), PropTypes.instanceOf(IMask.Masked)]), value: PropTypes.any, unmask: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['typed'])]), prepare: PropTypes.func, prepareChar: PropTypes.func, validate: PropTypes.func, commit: PropTypes.func, overwrite: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['shift'])]), eager: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['append', 'remove'])]), skipInvalid: PropTypes.bool, // events onAccept: PropTypes.func, onComplete: PropTypes.func, // pattern placeholderChar: PropTypes.string, displayChar: PropTypes.string, lazy: PropTypes.bool, definitions: PropTypes.object, blocks: PropTypes.object, // enum enum: PropTypes.arrayOf(PropTypes.string), // range maxLength: PropTypes.number, from: PropTypes.number, to: PropTypes.number, // date pattern: PropTypes.string, format: PropTypes.func, parse: PropTypes.func, autofix: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['pad'])]), // number radix: PropTypes.string, thousandsSeparator: PropTypes.string, mapToRadix: PropTypes.arrayOf(PropTypes.string), scale: PropTypes.number, normalizeZeros: PropTypes.bool, padFractionalZeros: PropTypes.bool, min: PropTypes.oneOfType([PropTypes.number, PropTypes.instanceOf(Date)]), max: PropTypes.oneOfType([PropTypes.number, PropTypes.instanceOf(Date)]), // dynamic dispatch: PropTypes.func, // ref inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.object })]) }; const MASK_PROPS_NAMES = Object.keys(MASK_PROPS).filter(p => p !== 'value'); const NON_MASK_OPTIONS_NAMES = ['value', 'unmask', 'onAccept', 'onComplete', 'inputRef']; const MASK_OPTIONS_NAMES = MASK_PROPS_NAMES.filter(pName => NON_MASK_OPTIONS_NAMES.indexOf(pName) < 0); function IMaskMixin(ComposedComponent) { var _Class; const MaskedComponent = (_Class = class MaskedComponent extends React.Component { constructor(props) { super(props); this._inputRef = this._inputRef.bind(this); } componentDidMount() { if (!this.props.mask) return; this.initMask(); } componentDidUpdate() { const props = this.props; const maskOptions = this._extractMaskOptionsFromProps(props); if (maskOptions.mask) { if (this.maskRef) { this.maskRef.updateOptions(maskOptions); // TODO fix if ('value' in props && props.value !== undefined) this.maskValue = props.value; } else { this.initMask(maskOptions); } } else { this.destroyMask(); if ('value' in props && props.value !== undefined) { var _this$element; if ((_this$element = this.element) != null && _this$element.isContentEditable && this.element.tagName !== 'INPUT' && this.element.tagName !== 'TEXTAREA') this.element.textContent = props.value;else this.element.value = props.value; } } } componentWillUnmount() { this.destroyMask(); } _inputRef(el) { this.element = el; if (this.props.inputRef) { if (Object.prototype.hasOwnProperty.call(this.props.inputRef, 'current')) this.props.inputRef.current = el;else this.props.inputRef(el); } } initMask(maskOptions) { if (maskOptions === void 0) { maskOptions = this._extractMaskOptionsFromProps(this.props); } this.maskRef = IMask(this.element, maskOptions).on('accept', this._onAccept.bind(this)).on('complete', this._onComplete.bind(this)); if ('value' in this.props && this.props.value !== undefined) this.maskValue = this.props.value; } destroyMask() { if (this.maskRef) { this.maskRef.destroy(); delete this.maskRef; } } _extractMaskOptionsFromProps(props) { const { ...cloneProps } = props; // keep only mask options Object.keys(cloneProps).filter(prop => MASK_OPTIONS_NAMES.indexOf(prop) < 0).forEach(nonMaskProp => { delete cloneProps[nonMaskProp]; }); return cloneProps; } _extractNonMaskProps(props) { const { ...cloneProps } = props; MASK_PROPS_NAMES.forEach(maskProp => { if (maskProp !== 'maxLength') delete cloneProps[maskProp]; }); if (!('defaultValue' in cloneProps)) cloneProps.defaultValue = props.mask ? '' : cloneProps.value; delete cloneProps.value; return cloneProps; } get maskValue() { if (!this.maskRef) return ''; if (this.props.unmask === 'typed') return this.maskRef.typedValue; if (this.props.unmask) return this.maskRef.unmaskedValue; return this.maskRef.value; } set maskValue(value) { if (!this.maskRef) return; value = value == null && this.props.unmask !== 'typed' ? '' : value; if (this.props.unmask === 'typed') this.maskRef.typedValue = value;else if (this.props.unmask) this.maskRef.unmaskedValue = value;else this.maskRef.value = value; } _onAccept(e) { if (this.props.onAccept && this.maskRef) this.props.onAccept(this.maskValue, this.maskRef, e); } _onComplete(e) { if (this.props.onComplete && this.maskRef) this.props.onComplete(this.maskValue, this.maskRef, e); } render() { return React.createElement(ComposedComponent, { ...this._extractNonMaskProps(this.props), inputRef: this._inputRef }); } }, _Class.displayName = void 0, _Class.propTypes = void 0, _Class); const nestedComponentName = ComposedComponent.displayName || ComposedComponent.name || 'Component'; MaskedComponent.displayName = "IMask(" + nestedComponentName + ")"; MaskedComponent.propTypes = MASK_PROPS; return React.forwardRef((props, ref) => React.createElement(MaskedComponent, { ...props, ref })); } export { IMaskMixin as default };