1 | const _excluded = ["disabled", "readOnly", "placeholder", "innerRef", "min", "max", "localizer", "editing"];
|
2 |
|
3 | function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
4 |
|
5 | function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
6 |
|
7 | import activeElement from 'dom-helpers/activeElement';
|
8 | import canUseDOM from 'dom-helpers/canUseDOM';
|
9 | import PropTypes from 'prop-types';
|
10 | import React from 'react';
|
11 | import { findDOMNode } from 'react-dom';
|
12 | import Input from './Input';
|
13 | import * as CustomPropTypes from './PropTypes';
|
14 |
|
15 | let isSign = val => (val || '').trim() === '-';
|
16 |
|
17 | function isPaddedZeros(str, localizer) {
|
18 | let localeChar = localizer.decimalCharacter();
|
19 | let [_, decimals] = str.split(localeChar);
|
20 | return !!(decimals && decimals.match(/0+$/));
|
21 | }
|
22 |
|
23 | function isAtDelimiter(str, localizer) {
|
24 | let localeChar = localizer.decimalCharacter();
|
25 | let lastIndex = str.length - 1;
|
26 | if (str.length < 1) return false;
|
27 | let char = str[lastIndex];
|
28 | return !!(char === localeChar && str.indexOf(char) === lastIndex);
|
29 | }
|
30 |
|
31 | class NumberPickerInput extends React.Component {
|
32 | constructor(...args) {
|
33 | super(...args);
|
34 | this.state = {};
|
35 |
|
36 | this.handleBlur = event => {
|
37 | let str = this.state.stringValue;
|
38 | let number = this.parseNumber(str);
|
39 |
|
40 |
|
41 | if (this.isIntermediateValue(number, str)) {
|
42 | if (isNaN(number)) {
|
43 | number = null;
|
44 | }
|
45 |
|
46 | this.props.onChange(number, event);
|
47 | }
|
48 | };
|
49 |
|
50 | this.handleChange = event => {
|
51 | let {
|
52 | value,
|
53 | onChange
|
54 | } = this.props;
|
55 | let stringValue = event.target.value,
|
56 | numberValue = this.parseNumber(stringValue);
|
57 | let isIntermediate = this.isIntermediateValue(numberValue, stringValue);
|
58 |
|
59 | if (stringValue == null || stringValue.trim() === '') {
|
60 | this.setStringValue('');
|
61 | onChange(null, event);
|
62 | return;
|
63 | }
|
64 |
|
65 |
|
66 | if (isIntermediate) {
|
67 | this.setStringValue(stringValue);
|
68 | } else if (numberValue !== value) {
|
69 | onChange(numberValue, event);
|
70 | } else if (stringValue != this.state.stringValue) {
|
71 | this.setStringValue(stringValue);
|
72 | }
|
73 | };
|
74 | }
|
75 |
|
76 | getSnapshotBeforeUpdate({
|
77 | editing
|
78 | }) {
|
79 | return {
|
80 | reselectText: !editing && this.props.editing && this.isSelectingAllText()
|
81 | };
|
82 | }
|
83 |
|
84 | static getDerivedStateFromProps(nextProps, prevState) {
|
85 | let {
|
86 | value,
|
87 | editing,
|
88 | localizer
|
89 | } = nextProps;
|
90 | let decimal = localizer.decimalCharacter();
|
91 | const stringValue = value == null || isNaN(value) ? '' : editing ? ('' + value).replace('.', decimal) : localizer.formatNumber(value
|
92 |
|
93 | );
|
94 | if (prevState.lastValueFromProps !== stringValue) return {
|
95 | stringValue,
|
96 | lastValueFromProps: stringValue
|
97 | };
|
98 | return null;
|
99 | }
|
100 |
|
101 | componentDidUpdate(_, __, {
|
102 | reselectText
|
103 | }) {
|
104 | if (reselectText) findDOMNode(this).select();
|
105 | }
|
106 |
|
107 |
|
108 |
|
109 | setStringValue(stringValue) {
|
110 | this.setState({
|
111 | stringValue
|
112 | });
|
113 | }
|
114 |
|
115 | isIntermediateValue(num, str) {
|
116 | let {
|
117 | localizer,
|
118 | min
|
119 | } = this.props;
|
120 | return !!(num < min || isSign(str) || isAtDelimiter(str, localizer) || isPaddedZeros(str, localizer));
|
121 | }
|
122 |
|
123 | isSelectingAllText() {
|
124 | const node = canUseDOM && findDOMNode(this);
|
125 | return canUseDOM && activeElement() === node && node.selectionStart === 0 && node.selectionEnd === node.value.length;
|
126 | }
|
127 |
|
128 | parseNumber(strVal) {
|
129 | let {
|
130 | localizer,
|
131 | parse: userParse
|
132 | } = this.props;
|
133 | if (userParse) return userParse(strVal, localizer);
|
134 | return localizer.parseNumber(strVal);
|
135 | }
|
136 |
|
137 | render() {
|
138 | let _this$props = this.props,
|
139 | {
|
140 | disabled,
|
141 | readOnly,
|
142 | placeholder,
|
143 |
|
144 | innerRef,
|
145 | min,
|
146 | max
|
147 | } = _this$props,
|
148 | props = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
149 |
|
150 | let value = this.state.stringValue;
|
151 | return React.createElement(Input, _extends({}, props, {
|
152 | ref: innerRef,
|
153 | inputMode: "numeric",
|
154 | className: "rw-widget-input",
|
155 | onChange: this.handleChange,
|
156 | onBlur: this.handleBlur,
|
157 | "aria-valuenow": value
|
158 |
|
159 | ,
|
160 | "aria-valuemin": isFinite(min) ? min : undefined,
|
161 | "aria-valuemax": isFinite(max) ? max : undefined,
|
162 | disabled: disabled,
|
163 | readOnly: readOnly,
|
164 | placeholder: placeholder,
|
165 | value: value
|
166 | }));
|
167 | }
|
168 |
|
169 | }
|
170 |
|
171 | NumberPickerInput.defaultProps = {
|
172 | value: null,
|
173 | editing: false
|
174 | };
|
175 | NumberPickerInput.propTypes = {
|
176 | value: PropTypes.number,
|
177 | editing: PropTypes.bool,
|
178 | placeholder: PropTypes.string,
|
179 | localizer: PropTypes.object.isRequired,
|
180 | parse: PropTypes.func,
|
181 | min: PropTypes.number,
|
182 | max: PropTypes.number,
|
183 | disabled: CustomPropTypes.disabled,
|
184 | readOnly: CustomPropTypes.disabled,
|
185 | onChange: PropTypes.func.isRequired
|
186 | };
|
187 | export default NumberPickerInput; |
\ | No newline at end of file |