/src/fragments/DatePickerRange.react.js

https://github.com/plotly/dash-core-components · JavaScript · 199 lines · 174 code · 23 blank · 2 comment · 32 complexity · 971127b331d10f41fcdfcf95551ffd61 MD5 · raw file

  1. import 'react-dates/initialize';
  2. import {DateRangePicker} from 'react-dates';
  3. import React, {Component} from 'react';
  4. import uniqid from 'uniqid';
  5. import {propTypes, defaultProps} from '../components/DatePickerRange.react';
  6. import convertToMoment from '../utils/convertToMoment';
  7. export default class DatePickerRange extends Component {
  8. constructor(props) {
  9. super(props);
  10. this.propsToState = this.propsToState.bind(this);
  11. this.onDatesChange = this.onDatesChange.bind(this);
  12. this.isOutsideRange = this.isOutsideRange.bind(this);
  13. this.state = {
  14. focused: false,
  15. start_date_id: props.start_date_id || uniqid(),
  16. end_date_id: props.end_date_id || uniqid(),
  17. };
  18. }
  19. propsToState(newProps, force = false) {
  20. const state = {};
  21. if (force || newProps.start_date !== this.props.start_date) {
  22. state.start_date = newProps.start_date;
  23. }
  24. if (force || newProps.end_date !== this.props.end_date) {
  25. state.end_date = newProps.end_date;
  26. }
  27. if (Object.keys(state).length) {
  28. this.setState(state);
  29. }
  30. }
  31. UNSAFE_componentWillReceiveProps(newProps) {
  32. this.propsToState(newProps);
  33. }
  34. UNSAFE_componentWillMount() {
  35. this.propsToState(this.props, true);
  36. }
  37. onDatesChange({startDate: start_date, endDate: end_date}) {
  38. const {setProps, updatemode, clearable} = this.props;
  39. const oldMomentDates = convertToMoment(this.state, [
  40. 'start_date',
  41. 'end_date',
  42. ]);
  43. if (start_date && !start_date.isSame(oldMomentDates.start_date)) {
  44. if (updatemode === 'singledate') {
  45. setProps({start_date: start_date.format('YYYY-MM-DD')});
  46. } else {
  47. this.setState({start_date: start_date.format('YYYY-MM-DD')});
  48. }
  49. }
  50. if (end_date && !end_date.isSame(oldMomentDates.end_date)) {
  51. if (updatemode === 'singledate') {
  52. setProps({end_date: end_date.format('YYYY-MM-DD')});
  53. } else if (updatemode === 'bothdates') {
  54. setProps({
  55. start_date: this.state.start_date,
  56. end_date: end_date.format('YYYY-MM-DD'),
  57. });
  58. }
  59. }
  60. if (
  61. clearable &&
  62. !start_date &&
  63. !end_date &&
  64. (oldMomentDates.start_date !== start_date ||
  65. oldMomentDates.end_date !== end_date)
  66. ) {
  67. setProps({start_date: null, end_date: null});
  68. }
  69. }
  70. isOutsideRange(date) {
  71. const {min_date_allowed, max_date_allowed} = this.props;
  72. return (
  73. (min_date_allowed && date.isBefore(min_date_allowed)) ||
  74. (max_date_allowed && date.isAfter(max_date_allowed))
  75. );
  76. }
  77. render() {
  78. const {focusedInput} = this.state;
  79. const {
  80. calendar_orientation,
  81. clearable,
  82. day_size,
  83. disabled,
  84. display_format,
  85. end_date_placeholder_text,
  86. first_day_of_week,
  87. is_RTL,
  88. minimum_nights,
  89. month_format,
  90. number_of_months_shown,
  91. reopen_calendar_on_clear,
  92. show_outside_days,
  93. start_date_placeholder_text,
  94. stay_open_on_select,
  95. with_full_screen_portal,
  96. with_portal,
  97. loading_state,
  98. id,
  99. style,
  100. className,
  101. start_date_id,
  102. end_date_id,
  103. } = this.props;
  104. const {initial_visible_month} = convertToMoment(this.props, [
  105. 'initial_visible_month',
  106. ]);
  107. const {start_date, end_date} = convertToMoment(this.state, [
  108. 'start_date',
  109. 'end_date',
  110. ]);
  111. const verticalFlag = calendar_orientation !== 'vertical';
  112. const DatePickerWrapperStyles = {
  113. position: 'relative',
  114. display: 'inline-block',
  115. ...style,
  116. };
  117. // the height in px of the top part of the calendar (that holds
  118. // the name of the month)
  119. const baselineHeight = 145;
  120. return (
  121. <div
  122. id={id}
  123. style={DatePickerWrapperStyles}
  124. className={className}
  125. data-dash-is-loading={
  126. (loading_state && loading_state.is_loading) || undefined
  127. }
  128. >
  129. <DateRangePicker
  130. daySize={day_size}
  131. disabled={disabled}
  132. displayFormat={display_format}
  133. enableOutsideDays={show_outside_days}
  134. endDate={end_date}
  135. endDatePlaceholderText={end_date_placeholder_text}
  136. firstDayOfWeek={first_day_of_week}
  137. focusedInput={focusedInput}
  138. initialVisibleMonth={() => {
  139. if (initial_visible_month) {
  140. return initial_visible_month;
  141. } else if (end_date && focusedInput === 'endDate') {
  142. return end_date;
  143. } else if (start_date && focusedInput === 'startDate') {
  144. return start_date;
  145. }
  146. return start_date;
  147. }}
  148. isOutsideRange={this.isOutsideRange}
  149. isRTL={is_RTL}
  150. keepOpenOnDateSelect={stay_open_on_select}
  151. minimumNights={minimum_nights}
  152. monthFormat={month_format}
  153. numberOfMonths={number_of_months_shown}
  154. onDatesChange={this.onDatesChange}
  155. onFocusChange={focusedInput =>
  156. this.setState({focusedInput})
  157. }
  158. orientation={calendar_orientation}
  159. reopenPickerOnClearDates={reopen_calendar_on_clear}
  160. showClearDates={clearable}
  161. startDate={start_date}
  162. startDatePlaceholderText={start_date_placeholder_text}
  163. withFullScreenPortal={
  164. with_full_screen_portal && verticalFlag
  165. }
  166. withPortal={with_portal && verticalFlag}
  167. startDateId={start_date_id || this.state.start_date_id}
  168. endDateId={end_date_id || this.state.end_date_id}
  169. verticalHeight={baselineHeight + day_size * 6 + 'px'}
  170. />
  171. </div>
  172. );
  173. }
  174. }
  175. DatePickerRange.propTypes = propTypes;
  176. DatePickerRange.defaultProps = defaultProps;