UNPKG

@hackplan/polaris

Version:

Shopify’s product component library

158 lines (157 loc) 7.57 kB
import React from 'react'; import { ArrowLeftMinor, ArrowRightMinor } from '@shopify/polaris-icons'; import { Months, isDateAfter, isDateBefore, getNextDisplayYear, getNextDisplayMonth, getPreviousDisplayYear, getPreviousDisplayMonth, Weekdays, isSameDay, } from '@shopify/javascript-utilities/dates'; import { withAppProvider } from '../AppProvider'; import Button from '../Button'; import { monthName } from './utilities'; import { Month } from './components'; import styles from './DatePicker.scss'; export { Months }; export class DatePicker extends React.PureComponent { constructor() { super(...arguments); this.state = { hoverDate: undefined, focusDate: undefined, }; this.handleFocus = (date) => { this.setState({ focusDate: date }); }; this.resetFocus = () => { this.setState({ focusDate: undefined }); }; this.handleKeyUp = (event) => { const { key } = event; const { selected, disableDatesBefore, disableDatesAfter } = this.props; const { focusDate } = this.state; const range = deriveRange(selected); const focusedDate = focusDate || (range && range.start); if (focusedDate == null) { return; } if (key === 'ArrowUp') { const previousWeek = new Date(focusedDate); previousWeek.setDate(focusedDate.getDate() - 7); if (!(disableDatesBefore && isDateBefore(previousWeek, disableDatesBefore))) { this.setFocusDateAndHandleMonthChange(previousWeek); } } if (key === 'ArrowDown') { const nextWeek = new Date(focusedDate); nextWeek.setDate(focusedDate.getDate() + 7); if (!(disableDatesAfter && isDateAfter(nextWeek, disableDatesAfter))) { this.setFocusDateAndHandleMonthChange(nextWeek); } } if (key === 'ArrowRight') { const tomorrow = new Date(focusedDate); tomorrow.setDate(focusedDate.getDate() + 1); if (!(disableDatesAfter && isDateAfter(tomorrow, disableDatesAfter))) { this.setFocusDateAndHandleMonthChange(tomorrow); } } if (key === 'ArrowLeft') { const yesterday = new Date(focusedDate); yesterday.setDate(focusedDate.getDate() - 1); if (!(disableDatesBefore && isDateBefore(yesterday, disableDatesBefore))) { this.setFocusDateAndHandleMonthChange(yesterday); } } }; this.setFocusDateAndHandleMonthChange = (date) => { const { onMonthChange } = this.props; if (onMonthChange) { onMonthChange(date.getMonth(), date.getFullYear()); } this.setState({ hoverDate: date, focusDate: date, }); }; this.handleDateSelection = (range) => { const { end } = range; const { onChange = noop } = this.props; this.setState({ hoverDate: end, focusDate: new Date(end) }, () => onChange(range)); }; this.handleMonthChangeClick = (month, year) => { const { onMonthChange } = this.props; if (!onMonthChange) { return; } this.setState({ focusDate: undefined, }); onMonthChange(month, year); }; this.handleHover = (date) => { this.setState({ hoverDate: date, }); }; } componentDidUpdate(prevProps) { const selectedPropDidChange = !isSameSelectedDate(prevProps.selected, this.props.selected); if (selectedPropDidChange) { this.resetFocus(); } } render() { const { id, selected, month, year, allowRange, multiMonth, disableDatesBefore, disableDatesAfter, weekStartsOn = Weekdays.Sunday, polaris: { intl }, } = this.props; const { hoverDate, focusDate } = this.state; const showNextYear = getNextDisplayYear(month, year); const showNextMonth = getNextDisplayMonth(month); const showNextToNextYear = getNextDisplayYear(showNextMonth, showNextYear); const showNextToNextMonth = getNextDisplayMonth(showNextMonth); const showPreviousYear = getPreviousDisplayYear(month, year); const showPreviousMonth = getPreviousDisplayMonth(month); const previousMonthName = intl.translate(`Polaris.DatePicker.months.${monthName(showPreviousMonth)}`); const nextMonth = multiMonth ? intl.translate(`Polaris.DatePicker.months.${monthName(showNextToNextMonth)}`) : intl.translate(`Polaris.DatePicker.months.${monthName(showNextMonth)}`); const nextYear = multiMonth ? showNextToNextYear : showNextYear; const secondDatePicker = multiMonth ? (<Month onFocus={this.handleFocus} focusedDate={focusDate} month={showNextMonth} year={showNextYear} selected={deriveRange(selected)} hoverDate={hoverDate} onChange={this.handleDateSelection} onHover={this.handleHover} disableDatesBefore={disableDatesBefore} disableDatesAfter={disableDatesAfter} allowRange={allowRange} weekStartsOn={weekStartsOn}/>) : null; return (<div id={id} className={styles.DatePicker} onKeyDown={handleKeyDown} onKeyUp={this.handleKeyUp}> <div className={styles.Header}> <Button plain icon={ArrowLeftMinor} accessibilityLabel={intl.translate('Polaris.DatePicker.previousMonth', { previousMonthName, showPreviousYear, })} onClick={this.handleMonthChangeClick.bind(null, showPreviousMonth, showPreviousYear)}/> <Button plain icon={ArrowRightMinor} accessibilityLabel={intl.translate('Polaris.DatePicker.nextMonth', { nextMonth, nextYear, })} onClick={this.handleMonthChangeClick.bind(null, showNextMonth, showNextYear)}/> </div> <div className={styles.MonthContainer}> <Month onFocus={this.handleFocus} focusedDate={focusDate} month={month} year={year} selected={deriveRange(selected)} hoverDate={hoverDate} onChange={this.handleDateSelection} onHover={this.handleHover} disableDatesBefore={disableDatesBefore} disableDatesAfter={disableDatesAfter} allowRange={allowRange} weekStartsOn={weekStartsOn}/> {secondDatePicker} </div> </div>); } } function noop() { } function handleKeyDown(event) { const { key } = event; if (key === 'ArrowUp' || key === 'ArrowDown' || key === 'ArrowLeft' || key === 'ArrowRight') { event.preventDefault(); event.stopPropagation(); } } function isSameSelectedDate(previousDate, currentDate) { if (previousDate == null || currentDate == null) { return previousDate == null && currentDate == null; } if (previousDate instanceof Date || currentDate instanceof Date) { return (previousDate instanceof Date && currentDate instanceof Date && isSameDay(previousDate, currentDate)); } return (isSameDay(previousDate.start, currentDate.start) && isSameDay(previousDate.end, currentDate.end)); } function deriveRange(selected) { return selected instanceof Date ? { start: selected, end: selected } : selected; } export default withAppProvider()(DatePicker);