UNPKG

react-widgets-up

Version:

An à la carte set of polished, extensible, and accessible inputs built for React

154 lines (151 loc) 5.46 kB
const _excluded = ["disabled", "readOnly", "placeholder", "innerRef", "min", "max", "localizer", "editing", "parse"]; function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } import activeElement from 'dom-helpers/activeElement'; import canUseDOM from 'dom-helpers/canUseDOM'; import * as React from 'react'; import { createRef } from 'react'; import Input from './Input'; import { mergeRefs } from '@restart/hooks/useMergedRefs'; import { omitUndefined } from './omitUndefined'; let isSign = val => (val || '').trim() === '-'; function isPaddedZeros(str, localizer) { let localeChar = localizer.decimalCharacter(); let [_, decimals] = str.split(localeChar); return !!(decimals && decimals.match(/0+$/)); } function isAtDelimiter(str, localizer) { let localeChar = localizer.decimalCharacter(); let lastIndex = str.length - 1; if (str.length < 1) return false; let char = str[lastIndex]; return !!(char === localeChar && str.indexOf(char) === lastIndex); } const defaultProps = { value: null, editing: false }; class NumberPickerInput extends React.Component { constructor(...args) { super(...args); this.state = {}; this.input = /*#__PURE__*/createRef(); this.handleBlur = event => { let str = this.state.stringValue; let number = this.parseNumber(str); // if number is below the min // we need to flush low values and decimal stops, onBlur means i'm done inputing if (this.isIntermediateValue(number, str)) { if (isNaN(number)) { number = null; } this.props.onChange(number, event); } }; this.handleChange = event => { let { value, onChange } = Object.assign({}, defaultProps, omitUndefined(this.props)); let stringValue = event.target.value, numberValue = this.parseNumber(stringValue); let isIntermediate = this.isIntermediateValue(numberValue, stringValue); if (stringValue == null || stringValue.trim() === '') { this.setStringValue(''); onChange(null, event); return; } // order here matters a lot if (isIntermediate) { this.setStringValue(stringValue); } else if (numberValue !== value) { onChange(numberValue, event); } else if (stringValue != this.state.stringValue) { this.setStringValue(stringValue); } }; } getSnapshotBeforeUpdate({ editing }) { return { reselectText: !editing && this.props.editing && this.isSelectingAllText() }; } static getDerivedStateFromProps(nextProps, prevState) { let { value, editing, localizer } = Object.assign({}, defaultProps, nextProps); let decimal = localizer.decimalCharacter(); const stringValue = value == null || isNaN(value) ? '' : editing ? ('' + value).replace('.', decimal) : localizer.formatNumber(value /*, 'default'*/); if (prevState.lastValueFromProps !== stringValue) return { stringValue, lastValueFromProps: stringValue }; return null; } componentDidUpdate(_, __, { reselectText }) { var _this$input$current; if (reselectText) (_this$input$current = this.input.current) == null || _this$input$current.select(); } // this intermediate state is for when one runs into // the decimal or are typing the number setStringValue(stringValue) { this.setState({ stringValue }); } isIntermediateValue(num, str) { let { localizer, min } = this.props; return !!(num < min || isSign(str) || isAtDelimiter(str, localizer) || isPaddedZeros(str, localizer)); } isSelectingAllText() { const node = canUseDOM && this.input.current; return !!node && activeElement() === node && node.selectionStart === 0 && node.selectionEnd === node.value.length; } parseNumber(strVal) { let { localizer, parse: userParse } = this.props; if (userParse) return userParse(strVal, localizer); return localizer.parseNumber(strVal); } render() { let _defaultProps$omitUnd = Object.assign({}, defaultProps, omitUndefined(this.props)), { disabled, readOnly, placeholder, // eslint-disable-next-line react/prop-types innerRef, min, max // eslint-disable-next-line no-unused-vars } = _defaultProps$omitUnd, props = _objectWithoutPropertiesLoose(_defaultProps$omitUnd, _excluded); let value = this.state.stringValue; return /*#__PURE__*/React.createElement(Input, _extends({}, props, { ref: mergeRefs(innerRef, this.input), inputMode: "numeric", className: "rw-widget-input", onChange: this.handleChange, onBlur: this.handleBlur, "aria-valuenow": value /*HACK*/, "aria-valuemin": isFinite(min) ? min : undefined, "aria-valuemax": isFinite(max) ? max : undefined, disabled: disabled, readOnly: readOnly, placeholder: placeholder, value: value })); } } export default NumberPickerInput;