diff --git a/src/DayPicker.js b/src/DayPicker.js index db130cad6f..f799618ccf 100644 --- a/src/DayPicker.js +++ b/src/DayPicker.js @@ -10,7 +10,7 @@ import * as DateUtils from './DateUtils'; import * as LocaleUtils from './LocaleUtils'; import keys from './keys'; -import DayPickerPropTypes from './PropTypes'; +import DayPickerPropTypes, { ModifierPropType } from './PropTypes'; export default class DayPicker extends Component { static VERSION = '4.0.0'; @@ -18,8 +18,16 @@ export default class DayPicker extends Component { static propTypes = { initialMonth: PropTypes.instanceOf(Date), numberOfMonths: PropTypes.number, - selectedDays: PropTypes.func, - disabledDays: PropTypes.func, + + selectedDays: PropTypes.oneOfType([ + ModifierPropType, + PropTypes.arrayOf(ModifierPropType), + ]), + + disabledDays: PropTypes.oneOfType([ + ModifierPropType, + PropTypes.arrayOf(ModifierPropType), + ]), modifiers: PropTypes.object, diff --git a/src/Helpers.js b/src/Helpers.js index 9050891ef8..0c93e921b3 100644 --- a/src/Helpers.js +++ b/src/Helpers.js @@ -1,5 +1,5 @@ -import { clone } from './DateUtils'; +import { clone, isSameDay, isDayInRange } from './DateUtils'; import { getFirstDayOfWeek } from './LocaleUtils'; export function cancelEvent(e) { @@ -52,10 +52,55 @@ export function getFirstDayOfWeekFromProps(props) { return 0; } -export function getModifiersForDay(d, modifierFunctions = {}) { - return Object.keys(modifierFunctions).reduce((modifiers, modifier) => { - const func = modifierFunctions[modifier]; - if (func(d)) { +export function isRangeOfDates(value) { + return value && typeof value === 'object' && value.from && value.to; +} + +export function getModifiersForDay(d, modifiersObj = {}) { + return Object.keys(modifiersObj).reduce((modifiers, modifier) => { + const value = modifiersObj[modifier]; + if (!value) { + return modifiers; + } + if (value instanceof Date && isSameDay(d, value)) { + // modifier's value is a date + modifiers.push(modifier); + } else if (value instanceof Array) { + // modifier's value is an array + if (value.some((day) => { + if (!day) { + return false; + } + if (day instanceof Date) { + // this value of the array is a date + return isSameDay(d, day); + } + if (isRangeOfDates(day)) { + // this value of the array is a range + const range = day; + return isDayInRange(d, range); + } + if (typeof day === 'object' && day.after) { + return d > day.after; + } + if (typeof day === 'object' && day.before) { + return d < day.before; + } + return false; + })) { + modifiers.push(modifier); + } + } else if (isRangeOfDates(value) && isDayInRange(d, value)) { + // modifier's value is a range + modifiers.push(modifier); + } else if (typeof value === 'object' && value.after && d > value.after) { + // modifier's value has an after date + modifiers.push(modifier); + } else if (typeof value === 'object' && value.before && d < value.before) { + // modifier's value has an after date + modifiers.push(modifier); + } else if (typeof value === 'function' && value(d)) { + // modifier's value is a function modifiers.push(modifier); } return modifiers; diff --git a/src/PropTypes.js b/src/PropTypes.js index 5a3eb7e4b3..c07c13727c 100644 --- a/src/PropTypes.js +++ b/src/PropTypes.js @@ -1,10 +1,30 @@ import { PropTypes } from 'react'; -export default { +const PrimitiveTypes = { localeUtils: PropTypes.shape({ formatMonthTitle: PropTypes.func, formatWeekdayShort: PropTypes.func, formatWeekdayLong: PropTypes.func, getFirstDayOfWeek: PropTypes.func, }), + range: PropTypes.shape({ + from: PropTypes.instanceOf(Date), + to: PropTypes.instanceOf(Date), + }), + after: PropTypes.shape({ + after: PropTypes.instanceOf(Date), + }), + before: PropTypes.shape({ + before: PropTypes.instanceOf(Date), + }), }; + +export const ModifierPropType = PropTypes.oneOfType([ + PrimitiveTypes.after, + PrimitiveTypes.before, + PrimitiveTypes.range, + PropTypes.func, + PropTypes.array, +]); + +export default PrimitiveTypes; diff --git a/test/Helpers.js b/test/Helpers.js index c354f65234..db48929122 100644 --- a/test/Helpers.js +++ b/test/Helpers.js @@ -88,7 +88,110 @@ describe('Helpers', () => { expect(modifiers.indexOf('maybe')).to.equal(-1); expect(modifiers.indexOf('no')).to.equal(-1); }); - it('works without passing modifiers', () => { + it('accepts a single day', () => { + const modifiers = Helpers.getModifiersForDay( + new Date(2015, 8, 19), + { foo: new Date(2015, 8, 19) }, + ); + expect(modifiers).to.have.length(1); + expect(modifiers.indexOf('foo')).to.equal(0); + }); + it('accepts an array of days', () => { + const modifiersObj = { + foo: [ + new Date(2015, 8, 19), + new Date(2015, 8, 20), + new Date(2015, 8, 21), + ], + bar: [ + new Date(2015, 8, 19), + new Date(2015, 8, 20), + ], + }; + const modifiers1 = Helpers.getModifiersForDay(new Date(2015, 8, 19), modifiersObj); + expect(modifiers1).to.have.length(2); + expect(modifiers1.indexOf('foo')).to.be.above(-1); + expect(modifiers1.indexOf('bar')).to.be.above(-1); + + const modifiers2 = Helpers.getModifiersForDay(new Date(2015, 8, 20), modifiersObj); + expect(modifiers2).to.have.length(2); + expect(modifiers2.indexOf('foo')).to.be.above(-1); + expect(modifiers2.indexOf('bar')).to.be.above(-1); + + const modifiers3 = Helpers.getModifiersForDay(new Date(2015, 8, 21), modifiersObj); + expect(modifiers3).to.have.length(1); + expect(modifiers3.indexOf('foo')).to.equal(0); + expect(modifiers3.indexOf('bar')).to.equal(-1); + }); + it('accepts a single range of days', () => { + const range = { + foo: { + from: new Date(2015, 8, 18), + to: new Date(2015, 8, 20), + }, + }; + const modifiers1 = Helpers.getModifiersForDay(new Date(2015, 8, 19), range); + expect(modifiers1).to.have.length(1); + expect(modifiers1.indexOf('foo')).to.equal(0); + const modifiers2 = Helpers.getModifiersForDay(new Date(2015, 8, 17), range); + expect(modifiers2).to.have.length(0); + }); + it('accepts multiple ranges of days', () => { + const ranges = { + foo: [{ + from: new Date(2015, 8, 18), + to: new Date(2015, 8, 20), + }, { + from: new Date(2015, 9, 18), + to: new Date(2015, 9, 20), + }], + }; + const modifiers1 = Helpers.getModifiersForDay(new Date(2015, 8, 19), ranges); + expect(modifiers1.indexOf('foo')).to.equal(0); + const modifiers2 = Helpers.getModifiersForDay(new Date(2015, 9, 18), ranges); + expect(modifiers2.indexOf('foo')).to.equal(0); + }); + it('accepts an "after" modifier', () => { + const afterModifier = { + foo: { + after: new Date(2015, 8, 18), + }, + }; + const modifiers = Helpers.getModifiersForDay(new Date(2015, 8, 19), afterModifier); + expect(modifiers).to.have.length(1); + expect(modifiers.indexOf('foo')).to.equal(0); + }); + it('accepts an "after" modifier in an array of days', () => { + const afterModifier = { + foo: [ + { after: new Date(2015, 8, 18) }, + ], + }; + const modifiers = Helpers.getModifiersForDay(new Date(2015, 8, 19), afterModifier); + expect(modifiers).to.have.length(1); + expect(modifiers.indexOf('foo')).to.equal(0); + }); + it('accepts a "before" modifier', () => { + const afterModifier = { + foo: { + before: new Date(2015, 8, 15), + }, + }; + const modifiers = Helpers.getModifiersForDay(new Date(2015, 8, 10), afterModifier); + expect(modifiers).to.have.length(1); + expect(modifiers.indexOf('foo')).to.equal(0); + }); + it('accepts a "before" modifier in an array of days', () => { + const afterModifier = { + foo: [ + { before: new Date(2015, 8, 15) }, + ], + }; + const modifiers = Helpers.getModifiersForDay(new Date(2015, 8, 10), afterModifier); + expect(modifiers).to.have.length(1); + expect(modifiers.indexOf('foo')).to.equal(0); + }); + it('works even without modifiers', () => { const modifiers = Helpers.getModifiersForDay(new Date(2015, 8, 19)); expect(modifiers).to.have.length(0); });