Skip to content

Commit

Permalink
[New] DayPickerSingleDateController: add allowUnselect prop that …
Browse files Browse the repository at this point in the history
…allows controlling whether unselecting selected days is possible
  • Loading branch information
joaopsrleal authored and ljharb committed Nov 11, 2020
1 parent 185de16 commit 6c2cb61
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 3 deletions.
2 changes: 2 additions & 0 deletions examples/DayPickerSingleDateControllerWrapper.jsx
Expand Up @@ -19,6 +19,7 @@ const propTypes = forbidExtraProps({
initialDate: momentPropTypes.momentObj,
showInput: PropTypes.bool,

allowUnselect: PropTypes.bool,
keepOpenOnDateSelect: PropTypes.bool,
isOutsideRange: PropTypes.func,
isDayBlocked: PropTypes.func,
Expand Down Expand Up @@ -56,6 +57,7 @@ const defaultProps = {
showInput: false,

// day presentation and interaction related props
allowUnselect: false,
renderCalendarDay: undefined,
renderDayContents: null,
isDayBlocked: () => false,
Expand Down
16 changes: 13 additions & 3 deletions src/components/DayPickerSingleDateController.jsx
Expand Up @@ -34,12 +34,18 @@ import {
import DayPicker from './DayPicker';
import getPooledMoment from '../utils/getPooledMoment';

// Default value of the date property. Represents the state
// when there is no date selected.
// TODO: use null
const DATE_UNSET_VALUE = undefined;

const propTypes = forbidExtraProps({
date: momentPropTypes.momentObj,
minDate: momentPropTypes.momentObj,
maxDate: momentPropTypes.momentObj,
onDateChange: PropTypes.func,

allowUnselect: PropTypes.bool,
focused: PropTypes.bool,
onFocusChange: PropTypes.func,
onClose: PropTypes.func,
Expand Down Expand Up @@ -102,11 +108,12 @@ const propTypes = forbidExtraProps({
});

const defaultProps = {
date: undefined, // TODO: use null
date: DATE_UNSET_VALUE,
minDate: null,
maxDate: null,
onDateChange() {},

allowUnselect: false,
focused: false,
onFocusChange() {},
onClose() {},
Expand Down Expand Up @@ -352,16 +359,19 @@ export default class DayPickerSingleDateController extends React.PureComponent {
if (e) e.preventDefault();
if (this.isBlocked(day)) return;
const {
allowUnselect,
onDateChange,
keepOpenOnDateSelect,
onFocusChange,
onClose,
} = this.props;

onDateChange(day);
const clickedDay = allowUnselect && this.isSelected(day) ? DATE_UNSET_VALUE : day;

onDateChange(clickedDay);
if (!keepOpenOnDateSelect) {
onFocusChange({ focused: false });
onClose({ date: day });
onClose({ date: clickedDay });
}
}

Expand Down
8 changes: 8 additions & 0 deletions stories/DayPickerSingleDateController.js
Expand Up @@ -145,6 +145,14 @@ storiesOf('DayPickerSingleDateController', module)
onNextMonthClick={action('DayPickerSingleDateController::onNextMonthClick')}
/>
)))
.add('with day unselection', withInfo()(() => (
<DayPickerSingleDateControllerWrapper
onOutsideClick={action('DayPickerSingleDateController::onOutsideClick')}
onPrevMonthClick={action('DayPickerSingleDateController::onPrevMonthClick')}
onNextMonthClick={action('DayPickerSingleDateController::onNextMonthClick')}
allowUnselect
/>
)))
.add('with custom input', withInfo()(() => (
<DayPickerSingleDateControllerWrapper
onOutsideClick={action('DayPickerSingleDateController::onOutsideClick')}
Expand Down
34 changes: 34 additions & 0 deletions test/components/DayPickerSingleDateController_spec.jsx
Expand Up @@ -539,6 +539,40 @@ describe('DayPickerSingleDateController', () => {
expect(onDateChangeStub.callCount).to.equal(1);
});

it('props.onDateChange receives undefined when day selected', () => {
const date = moment();
const onDateChangeStub = sinon.stub();
const wrapper = shallow((
<DayPickerSingleDateController
onDateChange={onDateChangeStub}
onFocusChange={() => {}}
date={date}
allowUnselect
/>
));
// Click same day as the provided date.
wrapper.instance().onDayClick(date);
expect(onDateChangeStub.callCount).to.equal(1);
expect(onDateChangeStub.getCall(0).args[0]).to.equal(undefined);
});

it('props.onDateChange receives day when allowUnselect is disabled', () => {
const date = moment();
const onDateChangeStub = sinon.stub();
const wrapper = shallow((
<DayPickerSingleDateController
onDateChange={onDateChangeStub}
onFocusChange={() => {}}
date={date}
allowUnselect={false}
/>
));
// Click same day as the provided date.
wrapper.instance().onDayClick(date);
expect(onDateChangeStub.callCount).to.equal(1);
expect(onDateChangeStub.getCall(0).args[0]).to.equal(date);
});

describe('props.keepOpenOnDateSelect is false', () => {
it('props.onFocusChange is called', () => {
const onFocusChangeStub = sinon.stub();
Expand Down

0 comments on commit 6c2cb61

Please sign in to comment.