Skip to content

Commit 304e408

Browse files
aijmartijnrusschen
authored andcommitted
Fix two issues related to uncontrolled components (Hacker0x01#773)
* Revert "Changes to support disabling auto correction of dates (Hacker0x01#769)" This reverts commit a95cd86. * Allow datepicker to be a controlled component Avoid reformatting user input as they type DatePicker now uses plain controlled input instead of partially-controlled, partially-stateful DateInput. Fixes Hacker0x01#560 Hacker0x01#547 Hacker0x01#768 * Add test for preventDefault in onChangeRaw
1 parent bae0b57 commit 304e408

File tree

7 files changed

+95
-656
lines changed

7 files changed

+95
-656
lines changed

docs-site/src/example_components.jsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import hljs from 'highlight.js'
33
import Default from './examples/default'
44
import CodeExampleComponent from './code_example_component'
55

6-
import DisableDateAutoCorrection from './examples/disable_date_auto_correction'
76
import CustomDateFormat from './examples/custom_date_format'
87
import CustomClassName from './examples/custom_class_name'
98
import CustomCalendarClassName from './examples/custom_calendar_class_name'
@@ -184,10 +183,6 @@ export default React.createClass({
184183
{
185184
title: 'Get raw input value on change',
186185
component: <RawChange/>
187-
},
188-
{
189-
title: 'Disable date auto correction',
190-
component: <DisableDateAutoCorrection />
191186
}
192187
],
193188

docs-site/src/examples/disable_date_auto_correction.jsx

Lines changed: 0 additions & 38 deletions
This file was deleted.

src/date_input.jsx

Lines changed: 0 additions & 126 deletions
This file was deleted.

src/date_utils.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,14 @@ export function getEffectiveMaxDate ({ maxDate, includeDates }) {
6464
return maxDate
6565
}
6666
}
67+
68+
export function parseDate (value, { dateFormat, locale }) {
69+
const m = moment(value, dateFormat, locale || moment.locale(), true)
70+
return m.isValid() ? m : null
71+
}
72+
73+
export function safeDateFormat (date, { dateFormat, locale }) {
74+
return date && date.clone()
75+
.locale(locale || moment.locale())
76+
.format(Array.isArray(dateFormat) ? dateFormat[0] : dateFormat) || ''
77+
}

src/datepicker.jsx

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import DateInput from './date_input'
21
import Calendar from './calendar'
32
import React from 'react'
43
import TetherComponent from './tether_component'
54
import classnames from 'classnames'
6-
import {isSameDay, isDayDisabled, isDayInRange, getEffectiveMinDate, getEffectiveMaxDate} from './date_utils'
5+
import { isSameDay, isDayDisabled, isDayInRange, getEffectiveMinDate, getEffectiveMaxDate, parseDate, safeDateFormat } from './date_utils'
76
import moment from 'moment'
87
import onClickOutside from 'react-onclickoutside'
98

@@ -24,13 +23,12 @@ var DatePicker = React.createClass({
2423
children: React.PropTypes.node,
2524
className: React.PropTypes.string,
2625
customInput: React.PropTypes.element,
27-
dateFormat: React.PropTypes.oneOfType([
26+
dateFormat: React.PropTypes.oneOfType([ // eslint-disable-line react/no-unused-prop-types
2827
React.PropTypes.string,
2928
React.PropTypes.array
3029
]),
3130
dateFormatCalendar: React.PropTypes.string,
3231
disabled: React.PropTypes.bool,
33-
disableDateAutoCorrection: React.PropTypes.bool,
3432
disabledKeyboardNavigation: React.PropTypes.bool,
3533
dropdownMode: React.PropTypes.oneOf(['scroll', 'select']).isRequired,
3634
endDate: React.PropTypes.object,
@@ -77,15 +75,16 @@ var DatePicker = React.createClass({
7775
title: React.PropTypes.string,
7876
todayButton: React.PropTypes.string,
7977
utcOffset: React.PropTypes.number,
78+
value: React.PropTypes.string,
8079
withPortal: React.PropTypes.bool
8180
},
8281

8382
getDefaultProps () {
8483
return {
84+
dateFormat: 'L',
8585
dateFormatCalendar: 'MMMM YYYY',
8686
onChange () {},
8787
disabled: false,
88-
disableDateAutoCorrection: false,
8988
disabledKeyboardNavigation: false,
9089
dropdownMode: 'scroll',
9190
onFocus () {},
@@ -184,6 +183,20 @@ var DatePicker = React.createClass({
184183
if (this.props.withPortal) { event.preventDefault() }
185184
},
186185

186+
handleChange (event) {
187+
if (this.props.onChangeRaw) {
188+
this.props.onChangeRaw(event)
189+
if (event.isDefaultPrevented()) {
190+
return
191+
}
192+
}
193+
this.setState({ inputValue: event.target.value })
194+
const date = parseDate(event.target.value, this.props)
195+
if (date || !event.target.value) {
196+
this.setSelected(date, event, true)
197+
}
198+
},
199+
187200
handleSelect (date, event) {
188201
// Preventing onFocus event to fix issue
189202
// https://github.com/Hacker0x01/react-datepicker/issues/628
@@ -197,14 +210,14 @@ var DatePicker = React.createClass({
197210
this.setOpen(false)
198211
},
199212

200-
setSelected (date, event) {
213+
setSelected (date, event, keepInput) {
201214
let changedDate = date
202215

203216
if (changedDate !== null && isDayDisabled(changedDate, this.props)) {
204217
return
205218
}
206219

207-
if (!isSameDay(this.props.selected, changedDate) || this.props.disableDateAutoCorrection) {
220+
if (!isSameDay(this.props.selected, changedDate)) {
208221
if (changedDate !== null) {
209222
if (this.props.selected) {
210223
changedDate = moment(changedDate).set({
@@ -217,11 +230,14 @@ var DatePicker = React.createClass({
217230
preSelection: changedDate
218231
})
219232
}
220-
221233
this.props.onChange(changedDate, event)
222234
}
223235

224236
this.props.onSelect(changedDate, event)
237+
238+
if (!keepInput) {
239+
this.setState({ inputValue: null })
240+
}
225241
},
226242

227243
setPreSelection (date) {
@@ -349,35 +365,33 @@ var DatePicker = React.createClass({
349365
var className = classnames(this.props.className, {
350366
[outsideClickIgnoreClass]: this.state.open
351367
})
352-
return <DateInput
353-
ref="input"
354-
disableDateAutoCorrection={this.props.disableDateAutoCorrection}
355-
id={this.props.id}
356-
name={this.props.name}
357-
autoFocus={this.props.autoFocus}
358-
date={this.props.selected}
359-
locale={this.props.locale}
360-
minDate={this.props.minDate}
361-
maxDate={this.props.maxDate}
362-
excludeDates={this.props.excludeDates}
363-
includeDates={this.props.includeDates}
364-
filterDate={this.props.filterDate}
365-
dateFormat={this.props.dateFormat}
366-
onFocus={this.handleFocus}
367-
onBlur={this.handleBlur}
368-
onClick={this.onInputClick}
369-
onChangeRaw={this.props.onChangeRaw}
370-
onKeyDown={this.onInputKeyDown}
371-
onChangeDate={this.setSelected}
372-
placeholder={this.props.placeholderText}
373-
disabled={this.props.disabled}
374-
autoComplete={this.props.autoComplete}
375-
className={className}
376-
title={this.props.title}
377-
readOnly={this.props.readOnly}
378-
required={this.props.required}
379-
tabIndex={this.props.tabIndex}
380-
customInput={this.props.customInput} />
368+
369+
const customInput = this.props.customInput || <input type="text" />
370+
const inputValue =
371+
typeof this.props.value === 'string' ? this.props.value
372+
: typeof this.state.inputValue === 'string' ? this.state.inputValue
373+
: safeDateFormat(this.props.selected, this.props)
374+
375+
return React.cloneElement(customInput, {
376+
ref: 'input',
377+
value: inputValue,
378+
onBlur: this.handleBlur,
379+
onChange: this.handleChange,
380+
onClick: this.onInputClick,
381+
onFocus: this.handleFocus,
382+
onKeyDown: this.onInputKeyDown,
383+
id: this.props.id,
384+
name: this.props.name,
385+
autoFocus: this.props.autoFocus,
386+
placeholder: this.props.placeholderText,
387+
disabled: this.props.disabled,
388+
autoComplete: this.props.autoComplete,
389+
className: className,
390+
title: this.props.title,
391+
readOnly: this.props.readOnly,
392+
required: this.props.required,
393+
tabIndex: this.props.tabIndex
394+
})
381395
},
382396

383397
renderClearButton () {

0 commit comments

Comments
 (0)