UNPKG

react-easy-input

Version:

A react input component that has simple validation and masking

278 lines (241 loc) 8.33 kB
// Generated by CoffeeScript 2.3.1 var Input, Invalid, React, converterModule, converters, get, invalidModule, isInvalid, resetCursor, set; React = require("react"); converterModule = require("./converters"); invalidModule = require('./Invalid'); get = invalidModule.get; set = invalidModule.set; // TODO/Extra // add some props // required, invalidClass, validateImmediately(show red on empty required fields onload), validateOnblur (show red only after/not during field editing) // add more converters // numeric, integer, decimal, percent // EVENTUALLY // add masking, mask=[/[^@]+/,"@",/\d/,"."] // re-exports converters = converterModule.converters; module.exports.converters = converters; Invalid = invalidModule.Invalid; module.exports.Invalid = Invalid; isInvalid = invalidModule.isInvalid; module.exports.isInvalid = isInvalid; // helper function resetCursor = function(thisFromInput) { var inputSelectionStart, moveCursor; if (get(thisFromInput, ["refs", "input", "selectionStart"], "")) { inputSelectionStart = thisFromInput.refs.input.selectionStart; } moveCursor = function() { var cursorPos; cursorPos = get(thisFromInput, ["refs", "input", "selectionStart"], ""); if (cursorPos) { if (inputSelectionStart) { thisFromInput.refs.input.selectionStart = inputSelectionStart; return thisFromInput.refs.input.selectionEnd = inputSelectionStart; } } }; return setTimeout(moveCursor, 0); }; Input = class Input extends React.Component { constructor(props) { super(props); this.hasCompletedTheInitialFilter = false; } render() { var classAdd, className, converter, displayInvalid, each, expectedProps, i, incomingFilter, initialValue, invalidStyle, len, linkTo, newProps, outgoingFilter, props, ref, value, valueIsInvalid; props = this.props; // extract values from props expectedProps = []; expectedProps.push("invalidStyle"); if (props.invalidStyle) { invalidStyle = props.invalidStyle; } else { invalidStyle = null; } expectedProps.push("linkTo"); if (props.linkTo) { linkTo = props.linkTo; } else { linkTo = null; } expectedProps.push("className"); if (props.className) { className = props.className; } else { className = "easy-input"; } expectedProps.push("classAdd"); if (props.classAdd) { classAdd = props.classAdd; } else { classAdd = ""; } expectedProps.push("incomingFilter"); if (props.incomingFilter) { incomingFilter = props.incomingFilter; } else { incomingFilter = null; } expectedProps.push("outgoingFilter"); if (props.outgoingFilter) { outgoingFilter = props.outgoingFilter; } else { outgoingFilter = null; } expectedProps.push("value"); if (props.value) { value = props.value; } else { value = null; } // create a mutable version of props newProps = {}; ref = Object.keys(props); for (i = 0, len = ref.length; i < len; i++) { each = ref[i]; if (!expectedProps.includes(each)) { newProps[each] = props[each]; } } // retrieve converters if (converters[newProps.type]) { converter = converters[newProps.type]; } else { converter = {}; } if (!outgoingFilter) { outgoingFilter = converter.outgoingFilter; } if (!incomingFilter) { incomingFilter = converter.incomingFilter; } // FIXME, wrap the incomingFilter to make sure it always receives non-Invalid() values // calculate value if (newProps.this && linkTo) { // retrieve the actual value from the component's state newProps.value = get(newProps.this.state, linkTo, ""); } // Check the initial value if (incomingFilter && !this.hasCompletedTheInitialFilter) { initialValue = newProps.value; newProps.value = incomingFilter(newProps.value); this.hasCompletedTheInitialFilter = true; if (initialValue !== newProps.value) { // if the initial value is different, call the onchange if (newProps.onChange) { newProps.onChange({ target: { value: newProps.value } }); } } } // preserve the validity/un-validityness valueIsInvalid = isInvalid(newProps.value); //FIXME, there could be a better solution than this // always run outgoing filters if (outgoingFilter) { newProps.value = outgoingFilter(newProps.value); } // always convert null values to "" (otherwise react will complain) if (newProps.value === null || newProps.value === void 0) { newProps.value = ""; } if (valueIsInvalid) { newProps.value = new Invalid(newProps.value); } // Compute onChange if (!newProps.onChange) { // first reset the cursor, then handle the change newProps.onChange = (e) => { var copyOfState, newValue; newValue = e.target.value; resetCursor(this); // if there is a converter function, then run the function before it returns to state // for example convert "True" into the boolean: true, // or convert the string "Jan 12 2017" to dateTime(1,12,2017) if (incomingFilter) { newValue = incomingFilter(newValue); } // create a copy of state instead of mutating the original copyOfState = Object.assign(newProps.this.state); invalidModule.set(copyOfState, linkTo, newValue); return props.this.setState(copyOfState); }; } else { newProps.onChange = (e) => { var newValue; e.persist(); // react will destroy e if we don't tell it to persist newValue = e.target.value; resetCursor(this); // if there is a converter function, then run the function before it returns to state // for example convert "True" into the boolean: true, // or convert the string "Jan 12 2017" to dateTime(1,12,2017) if (incomingFilter) { newValue = incomingFilter(newValue); } return props.onChange({ target: { value: newValue } }); }; } // Calculate styling/css class // add additional classes newProps.className = className + " " + classAdd; displayInvalid = false; // if 'invalid' prop was set to something (true/false) if (typeof newProps.invalid === 'bool') { // and if 'invalid' is true if (newProps.invalid === true) { // then display it displayInvalid = true; } // if 'invalid' is false, dont add error class // if 'invalid' prop was not set, but the state value is indeed invalid, then displayInvalid } else if (isInvalid(newProps.value)) { // then display it displayInvalid = true; } if (displayInvalid === true) { // add the error css class className = "easy-input-error " + className; // check if there is an invalid style if (invalidStyle) { // if there is one then attach it newProps.style = invalidStyle; } } // set a reference for fixing the cursor jump newProps.ref = "input"; // return the react input component return React.createElement('input', newProps, null); } }; module.exports.Input = Input; // validate onblur instructions (implement in next few versions) // onChange={ // (e)=>{ // var val = e.target.value // e.persist() // setTimeout(() => { // e.target.onblur = () => { // console.log(`val is:`,val) // var matches = val.match(/^.+@.+\..+$/) // console.log(`val.match(/\\d+/) is:`,val.match(/\d+/)) // if (!matches) { // console.log(`doesnt match`) // e.target.setCustomValidity("Needs to be a number") // e.target.classList.add('input-err') // // this.refs.form.reportValidity() // } else { // console.log(`matches`) // } // } // }, 0); // this.setState({Nums:val}) // } // } // />