Skip to content

Commit 2493b96

Browse files
authored
Merge pull request #3 from wojtekmaj/react-17
Implement compatibility with React 17
2 parents 6190d1f + 47a083b commit 2493b96

File tree

6 files changed

+141
-99
lines changed

6 files changed

+141
-99
lines changed

.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"no-restricted-globals": "off",
1919
"prefer-destructuring": "warn",
2020
"prefer-spread": "warn",
21-
"react/require-default-props": "off"
21+
"react/require-default-props": "off",
22+
"react/sort-comp": "off"
2223
}
2324
}

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@
4444
"lodash.once": "^4.1.1",
4545
"merge-class-names": "^1.1.1",
4646
"prop-types": "^15.6.0",
47-
"react-calendar": "^2.13.4",
47+
"react-calendar": "^2.14.0",
4848
"react-clock": "^2.2.1",
49-
"react-date-picker": "^6.9.1",
50-
"react-time-picker": "^2.3.1"
49+
"react-date-picker": "^6.10.0",
50+
"react-lifecycles-compat": "^1.1.0",
51+
"react-time-picker": "^2.4.0"
5152
},
5253
"devDependencies": {
5354
"babel-cli": "^6.26.0",

src/DateTimeInput.jsx

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { Component } from 'react';
1+
import React, { PureComponent } from 'react';
22
import PropTypes from 'prop-types';
3+
import polyfill from 'react-lifecycles-compat';
34

45
import DayInput from 'react-date-picker/dist/DateInput/DayInput';
56
import MonthInput from 'react-date-picker/dist/DateInput/MonthInput';
@@ -13,11 +14,11 @@ import NativeInput from './DateTimeInput/NativeInput';
1314
import { formatDate, formatTime } from './shared/dateFormatter';
1415
import {
1516
getDay,
16-
getMonth,
17-
getYear,
1817
getHours,
1918
getMinutes,
19+
getMonth,
2020
getSeconds,
21+
getYear,
2122
} from './shared/dates';
2223
import { isMaxDate, isMinDate } from './shared/propTypes';
2324

@@ -64,41 +65,52 @@ const removeUnwantedCharacters = str => str
6465
))
6566
.join('');
6667

67-
export default class DateTimeInput extends Component {
68-
state = {
69-
year: null,
70-
month: null,
71-
day: null,
72-
hour: null,
73-
minute: null,
74-
second: null,
75-
}
68+
export default class DateTimeInput extends PureComponent {
69+
static getDerivedStateFromProps(nextProps, prevState) {
70+
const nextState = {};
7671

77-
componentWillMount() {
78-
this.updateValues();
79-
}
80-
81-
componentWillReceiveProps(nextProps) {
82-
const { value: nextValue } = nextProps;
83-
const { value } = this.props;
72+
/**
73+
* If isWidgetOpen flag has changed, we have to update it.
74+
* It's saved in state purely for use in getDerivedStateFromProps.
75+
*/
76+
if (nextProps.isWidgetOpen !== prevState.isWidgetOpen) {
77+
nextState.isWidgetOpen = nextProps.isWidgetOpen;
78+
}
8479

80+
/**
81+
* If the next value is different from the current one (with an exception of situation in
82+
* which values provided are limited by minDate and maxDate so that the dates are the same),
83+
* get a new one.
84+
*/
85+
const nextValue = nextProps.value;
8586
if (
86-
// Toggling clock visibility resets values
87-
(nextProps.isWidgetOpen !== this.props.isWidgetOpen) ||
88-
datesAreDifferent(nextValue, value)
87+
// Toggling calendar visibility resets values
88+
nextState.isCalendarOpen || // Flag was toggled
89+
datesAreDifferent(nextValue, prevState.value)
8990
) {
90-
this.updateValues(nextProps);
91+
if (nextValue) {
92+
nextState.year = getYear(nextValue);
93+
nextState.month = getMonth(nextValue);
94+
nextState.day = getDay(nextValue);
95+
nextState.hour = getHours(nextValue);
96+
nextState.minute = getMinutes(nextValue);
97+
nextState.second = getSeconds(nextValue);
98+
} else {
99+
nextState.year = null;
100+
nextState.month = null;
101+
nextState.day = null;
102+
nextState.hour = null;
103+
nextState.minute = null;
104+
nextState.second = null;
105+
}
106+
nextState.value = nextValue;
91107
}
92-
}
93108

94-
/**
95-
* Returns value type that can be returned with currently applied settings.
96-
*/
97-
get valueType() {
98-
const { maxDetail } = this.props;
99-
return maxDetail;
109+
return nextState;
100110
}
101111

112+
state = {};
113+
102114
// eslint-disable-next-line class-methods-use-this
103115
get dateDivider() {
104116
const { locale } = this.props;
@@ -168,17 +180,11 @@ export default class DateTimeInput extends Component {
168180
};
169181
}
170182

171-
updateValues(props = this.props) {
172-
const { value } = props;
173-
174-
this.setState({
175-
year: value ? getYear(value) : null,
176-
month: value ? getMonth(value) : null,
177-
day: value ? getDay(value) : null,
178-
hour: value ? getHours(value) : null,
179-
minute: value ? getMinutes(value) : null,
180-
second: value ? getSeconds(value) : null,
181-
});
183+
/**
184+
* Returns value type that can be returned with currently applied settings.
185+
*/
186+
get valueType() {
187+
return this.props.maxDetail;
182188
}
183189

184190
onKeyDown = (event) => {
@@ -471,3 +477,5 @@ DateTimeInput.propTypes = {
471477
PropTypes.instanceOf(Date),
472478
]),
473479
};
480+
481+
polyfill(DateTimeInput);

src/DateTimePicker.jsx

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,24 @@ import { isMaxDate, isMinDate } from './shared/propTypes';
1313
const allViews = ['hour', 'minute', 'second'];
1414

1515
export default class DateTimePicker extends PureComponent {
16-
state = {
17-
isCalendarOpen: this.props.isCalendarOpen,
18-
isClockOpen: this.props.isClockOpen,
16+
static getDerivedStateFromProps(nextProps, prevState) {
17+
const nextState = {};
18+
19+
if (nextProps.isCalendarOpen !== prevState.propsIsCalendarOpen) {
20+
nextState.isCalendarOpen = nextProps.isCalendarOpen;
21+
nextState.propsIsCalendarOpen = nextProps.isCalendarOpen;
22+
}
23+
24+
if (nextProps.isClockOpen !== prevState.propsIsClockOpen) {
25+
nextState.isClockOpen = nextProps.isClockOpen;
26+
nextState.propsIsClockOpen = nextProps.isClockOpen;
27+
}
28+
29+
return nextState;
1930
}
2031

32+
state = {};
33+
2134
componentDidMount() {
2235
document.addEventListener('mousedown', this.onClick);
2336
}
@@ -26,53 +39,12 @@ export default class DateTimePicker extends PureComponent {
2639
document.removeEventListener('mousedown', this.onClick);
2740
}
2841

29-
componentWillReceiveProps(nextProps) {
30-
const { props } = this;
31-
32-
if (nextProps.isCalendarOpen !== props.isCalendarOpen) {
33-
this.setState({ isCalendarOpen: nextProps.isCalendarOpen });
34-
}
35-
36-
if (nextProps.isClockOpen !== props.isClockOpen) {
37-
this.setState({ isClockOpen: nextProps.isClockOpen });
38-
}
39-
}
40-
4142
onClick = (event) => {
4243
if (this.wrapper && !this.wrapper.contains(event.target)) {
4344
this.closeWidgets();
4445
}
4546
}
4647

47-
openClock = () => {
48-
this.setState({
49-
isCalendarOpen: false,
50-
isClockOpen: true,
51-
});
52-
}
53-
54-
closeWidgets = () => {
55-
this.setState({
56-
isCalendarOpen: false,
57-
isClockOpen: false,
58-
});
59-
}
60-
61-
openCalendar = () => {
62-
this.setState({
63-
isCalendarOpen: true,
64-
isClockOpen: false,
65-
});
66-
}
67-
68-
closeCalendar = () => {
69-
this.setState({ isCalendarOpen: false });
70-
}
71-
72-
toggleCalendar = () => {
73-
this.setState(prevState => ({ isCalendarOpen: !prevState.isCalendarOpen }));
74-
}
75-
7648
onDateChange = (value, closeWidgets = true) => {
7749
const { value: prevValue } = this.props;
7850

@@ -123,6 +95,35 @@ export default class DateTimePicker extends PureComponent {
12395
}
12496
}
12597

98+
openClock = () => {
99+
this.setState({
100+
isCalendarOpen: false,
101+
isClockOpen: true,
102+
});
103+
}
104+
105+
closeWidgets = () => {
106+
this.setState({
107+
isCalendarOpen: false,
108+
isClockOpen: false,
109+
});
110+
}
111+
112+
openCalendar = () => {
113+
this.setState({
114+
isCalendarOpen: true,
115+
isClockOpen: false,
116+
});
117+
}
118+
119+
closeCalendar = () => {
120+
this.setState({ isCalendarOpen: false });
121+
}
122+
123+
toggleCalendar = () => {
124+
this.setState(prevState => ({ isCalendarOpen: !prevState.isCalendarOpen }));
125+
}
126+
126127
stopPropagation = event => event.stopPropagation()
127128

128129
clear = () => this.onChange(null);

src/__tests__/DateTimeInput.jsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,30 @@ describe('DateTimeInput', () => {
102102
expect(customInputs.at(5).getDOMNode().value).toBe('0');
103103
});
104104

105+
it('clears the value correctly', () => {
106+
const date = new Date(2017, 8, 30, 22, 17, 0);
107+
108+
const component = mount(
109+
<DateTimeInput
110+
maxDetail="second"
111+
value={date}
112+
/>
113+
);
114+
115+
component.setProps({ value: null });
116+
117+
const nativeInput = component.find('input[type="datetime-local"]');
118+
const customInputs = component.find('input[type="number"]');
119+
120+
expect(nativeInput.getDOMNode().value).toBe('');
121+
expect(customInputs.at(0).getDOMNode().value).toBe('');
122+
expect(customInputs.at(1).getDOMNode().value).toBe('');
123+
expect(customInputs.at(2).getDOMNode().value).toBe('');
124+
expect(customInputs.at(3).getDOMNode().value).toBe('');
125+
expect(customInputs.at(4).getDOMNode().value).toBe('');
126+
expect(customInputs.at(5).getDOMNode().value).toBe('');
127+
});
128+
105129
it('renders custom inputs in a proper order (en-US)', () => {
106130
const component = mount(
107131
<DateTimeInput

yarn.lock

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3683,13 +3683,14 @@ rc@^1.1.7:
36833683
minimist "^1.2.0"
36843684
strip-json-comments "~2.0.1"
36853685

3686-
react-calendar@^2.13.4:
3687-
version "2.13.4"
3688-
resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-2.13.4.tgz#8bda746ed6d1fbe29c539bc875adbd103871665f"
3686+
react-calendar@^2.14.0:
3687+
version "2.14.0"
3688+
resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-2.14.0.tgz#03ffce0d6e64052e552aaafdd142d1764ed88b45"
36893689
dependencies:
36903690
lodash.once "^4.1.1"
36913691
merge-class-names "^1.1.1"
36923692
prop-types "^15.6.0"
3693+
react-lifecycles-compat "^1.1.0"
36933694

36943695
react-clock@^2.2.1:
36953696
version "2.2.1"
@@ -3698,15 +3699,16 @@ react-clock@^2.2.1:
36983699
merge-class-names "^1.1.1"
36993700
prop-types "^15.6.0"
37003701

3701-
react-date-picker@^6.9.1:
3702-
version "6.9.1"
3703-
resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-6.9.1.tgz#99b3e9b4d2ea28074c39cf9cd9d5fefe0568044b"
3702+
react-date-picker@^6.10.0:
3703+
version "6.10.0"
3704+
resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-6.10.0.tgz#2108e34a11f0b1f6b641fe7772d07de12039fcc2"
37043705
dependencies:
37053706
detect-element-overflow "^1.1.1"
37063707
lodash.once "^4.1.1"
37073708
merge-class-names "^1.1.1"
37083709
prop-types "^15.6.0"
3709-
react-calendar "^2.13.4"
3710+
react-calendar "^2.14.0"
3711+
react-lifecycles-compat "^1.1.0"
37103712

37113713
react-dom@^16.3.0:
37123714
version "16.3.0"
@@ -3717,6 +3719,10 @@ react-dom@^16.3.0:
37173719
object-assign "^4.1.1"
37183720
prop-types "^15.6.0"
37193721

3722+
react-lifecycles-compat@^1.1.0:
3723+
version "1.1.0"
3724+
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-1.1.0.tgz#6641d0709bd5505329b5c90322147ef2d343485c"
3725+
37203726
react-reconciler@^0.7.0:
37213727
version "0.7.0"
37223728
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.7.0.tgz#9614894103e5f138deeeb5eabaf3ee80eb1d026d"
@@ -3734,15 +3740,16 @@ react-test-renderer@^16.0.0-0:
37343740
object-assign "^4.1.1"
37353741
prop-types "^15.6.0"
37363742

3737-
react-time-picker@^2.3.1:
3738-
version "2.3.1"
3739-
resolved "https://registry.yarnpkg.com/react-time-picker/-/react-time-picker-2.3.1.tgz#4d09f6e860b108f68bde4679cb2fc3e33d475d3a"
3743+
react-time-picker@^2.4.0:
3744+
version "2.4.0"
3745+
resolved "https://registry.yarnpkg.com/react-time-picker/-/react-time-picker-2.4.0.tgz#66c66848713c0a385484da560334de2b5708ff58"
37403746
dependencies:
37413747
detect-element-overflow "^1.1.1"
37423748
lodash.once "^4.1.1"
37433749
merge-class-names "^1.1.1"
37443750
prop-types "^15.6.0"
37453751
react-clock "^2.2.1"
3752+
react-lifecycles-compat "^1.1.0"
37463753

37473754
react@^16.3.0:
37483755
version "16.3.0"

0 commit comments

Comments
 (0)