From 253929c37980ba735624d050fe96b3bd6e01d763 Mon Sep 17 00:00:00 2001 From: "Christopher N. KATOYI" Date: Wed, 27 Nov 2019 16:48:08 +0100 Subject: [PATCH 1/7] Add the ability to force Calendar to use activeStartDate --- README.md | 1 + src/Calendar.jsx | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 505db822..339786df 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ Displays a complete, interactive calendar. |formatMonth|Function called to override default formatting of month names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMM')`| |formatMonthYear|Function called to override default formatting of month and year in the top navigation section. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMMM YYYY')`| |formatShortWeekday|Function called to override default formatting of weekday names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'dd')`| +|keepUsingActiveStartDate|Always use the `activeStartDate` as the beginning of the period that should be displayed by default|`false`|`true` or `false` |locale|Locale that should be used by the calendar. Can be any [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag).|User's browser settings|`"hu-HU"`| |maxDate|Maximum date that the user can select. Periods partially overlapped by maxDate will also be selectable, although React-Calendar will ensure that no later date is selected.|n/a|Date: `new Date()`| |maxDetail|The most detailed view that the user shall see. View defined here also becomes the one on which clicking an item will select a date and pass it to onChange. Can be `"month"`, `"year"`, `"decade"` or `"century"`.|`"month"`|`"year"`| diff --git a/src/Calendar.jsx b/src/Calendar.jsx index 542853db..f3a70d1f 100644 --- a/src/Calendar.jsx +++ b/src/Calendar.jsx @@ -135,6 +135,7 @@ const getDetailValueArray = (value, minDate, maxDate, maxDetail) => { const getActiveStartDate = (props) => { const { activeStartDate, + keepUsingActiveStartDate, maxDate, maxDetail, minDate, @@ -144,10 +145,15 @@ const getActiveStartDate = (props) => { } = props; const rangeType = getView(view, minDetail, maxDetail); - const valueFrom = ( + + const valueFrom = keepUsingActiveStartDate ? ( getDetailValueFrom(value, minDate, maxDate, maxDetail) || activeStartDate || new Date() + ) : ( + activeStartDate + || getDetailValueFrom(value, minDate, maxDate, maxDetail) + || new Date() ); return getBegin(rangeType, valueFrom); }; @@ -541,6 +547,7 @@ export default class Calendar extends Component { } Calendar.defaultProps = { + keepUsingActiveStartDate: false, maxDetail: 'month', minDetail: 'century', returnValue: 'start', @@ -553,6 +560,7 @@ Calendar.propTypes = { activeStartDate: PropTypes.instanceOf(Date), calendarType: isCalendarType, className: isClassName, + keepUsingActiveStartDate: PropTypes.bool, formatMonth: PropTypes.func, formatMonthYear: PropTypes.func, formatShortWeekday: PropTypes.func, From 640cee6ebe66eb761a394b6d4a015d2449894353 Mon Sep 17 00:00:00 2001 From: "Christopher N. KATOYI" Date: Wed, 27 Nov 2019 17:05:20 +0100 Subject: [PATCH 2/7] Added the ability to pass what date is curently hovered --- README.md | 1 + src/Calendar.jsx | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 339786df..f3a00614 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ Displays a complete, interactive calendar. |formatMonth|Function called to override default formatting of month names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMM')`| |formatMonthYear|Function called to override default formatting of month and year in the top navigation section. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMMM YYYY')`| |formatShortWeekday|Function called to override default formatting of weekday names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'dd')`| +|hoverFromProps|Date currently hovered, to bypass intern mechanism. If value is undefined, the default behaviour will be set|`undefined`|`Date` or `null` |keepUsingActiveStartDate|Always use the `activeStartDate` as the beginning of the period that should be displayed by default|`false`|`true` or `false` |locale|Locale that should be used by the calendar. Can be any [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag).|User's browser settings|`"hu-HU"`| |maxDate|Maximum date that the user can select. Periods partially overlapped by maxDate will also be selectable, although React-Calendar will ensure that no later date is selected.|n/a|Date: `new Date()`| diff --git a/src/Calendar.jsx b/src/Calendar.jsx index f3a70d1f..b0a51f2e 100644 --- a/src/Calendar.jsx +++ b/src/Calendar.jsx @@ -383,6 +383,7 @@ export default class Calendar extends Component { tileClassName, tileContent, tileDisabled, + hover: hoverFromProps } = this.props; const { activeStartDate, hover, value, view, @@ -391,7 +392,7 @@ export default class Calendar extends Component { const commonProps = { activeStartDate, - hover, + hover: selectRange ? hoverFromProps || hover : null, locale, maxDate, minDate, @@ -547,6 +548,7 @@ export default class Calendar extends Component { } Calendar.defaultProps = { + hoverFromProps: undefined, keepUsingActiveStartDate: false, maxDetail: 'month', minDetail: 'century', @@ -564,6 +566,7 @@ Calendar.propTypes = { formatMonth: PropTypes.func, formatMonthYear: PropTypes.func, formatShortWeekday: PropTypes.func, + hoverFromProps: PropTypes.func, locale: PropTypes.string, maxDate: isMaxDate, maxDetail: PropTypes.oneOf(allViews), @@ -584,6 +587,8 @@ Calendar.propTypes = { onClickYear: PropTypes.func, onDrillDown: PropTypes.func, onDrillUp: PropTypes.func, + onMouseOverTile: PropTypes.func, + onMouseOutTile: PropTypes.func, prev2AriaLabel: PropTypes.string, prev2Label: PropTypes.node, prevAriaLabel: PropTypes.string, From ef5d40f9f44b9935191955ccbb1b47b4a7a6fcd6 Mon Sep 17 00:00:00 2001 From: "Christopher N. KATOYI" Date: Wed, 27 Nov 2019 17:35:30 +0100 Subject: [PATCH 3/7] Lint, test and fix --- README.md | 2 +- src/Calendar.jsx | 24 +++++++++++------------- src/__tests__/Calendar.jsx | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f3a00614..09f87c00 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Displays a complete, interactive calendar. |formatMonth|Function called to override default formatting of month names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMM')`| |formatMonthYear|Function called to override default formatting of month and year in the top navigation section. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMMM YYYY')`| |formatShortWeekday|Function called to override default formatting of weekday names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'dd')`| -|hoverFromProps|Date currently hovered, to bypass intern mechanism. If value is undefined, the default behaviour will be set|`undefined`|`Date` or `null` +|hover|Date currently hovered, to bypass intern mechanism. If value is undefined, the default behaviour will be set|`undefined`|`Date` or `null` |keepUsingActiveStartDate|Always use the `activeStartDate` as the beginning of the period that should be displayed by default|`false`|`true` or `false` |locale|Locale that should be used by the calendar. Can be any [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag).|User's browser settings|`"hu-HU"`| |maxDate|Maximum date that the user can select. Periods partially overlapped by maxDate will also be selectable, although React-Calendar will ensure that no later date is selected.|n/a|Date: `new Date()`| diff --git a/src/Calendar.jsx b/src/Calendar.jsx index b0a51f2e..ed6239ec 100644 --- a/src/Calendar.jsx +++ b/src/Calendar.jsx @@ -147,14 +147,12 @@ const getActiveStartDate = (props) => { const rangeType = getView(view, minDetail, maxDetail); const valueFrom = keepUsingActiveStartDate ? ( - getDetailValueFrom(value, minDate, maxDate, maxDetail) - || activeStartDate - || new Date() - ) : ( activeStartDate || getDetailValueFrom(value, minDate, maxDate, maxDetail) - || new Date() - ); + ) : ( + getDetailValueFrom(value, minDate, maxDate, maxDetail) + || activeStartDate + ) || new Date(); return getBegin(rangeType, valueFrom); }; @@ -383,16 +381,16 @@ export default class Calendar extends Component { tileClassName, tileContent, tileDisabled, - hover: hoverFromProps + hover, } = this.props; const { - activeStartDate, hover, value, view, + activeStartDate, hover: hoverFromState, value, view, } = this.state; const { onMouseOver, valueType } = this; const commonProps = { activeStartDate, - hover: selectRange ? hoverFromProps || hover : null, + hover: selectRange ? hover || hoverFromState : null, locale, maxDate, minDate, @@ -548,7 +546,7 @@ export default class Calendar extends Component { } Calendar.defaultProps = { - hoverFromProps: undefined, + hover: undefined, keepUsingActiveStartDate: false, maxDetail: 'month', minDetail: 'century', @@ -562,11 +560,11 @@ Calendar.propTypes = { activeStartDate: PropTypes.instanceOf(Date), calendarType: isCalendarType, className: isClassName, - keepUsingActiveStartDate: PropTypes.bool, formatMonth: PropTypes.func, formatMonthYear: PropTypes.func, formatShortWeekday: PropTypes.func, - hoverFromProps: PropTypes.func, + hover: PropTypes.func, + keepUsingActiveStartDate: PropTypes.bool, locale: PropTypes.string, maxDate: isMaxDate, maxDetail: PropTypes.oneOf(allViews), @@ -587,8 +585,8 @@ Calendar.propTypes = { onClickYear: PropTypes.func, onDrillDown: PropTypes.func, onDrillUp: PropTypes.func, - onMouseOverTile: PropTypes.func, onMouseOutTile: PropTypes.func, + onMouseOverTile: PropTypes.func, prev2AriaLabel: PropTypes.string, prev2Label: PropTypes.node, prevAriaLabel: PropTypes.string, diff --git a/src/__tests__/Calendar.jsx b/src/__tests__/Calendar.jsx index 6169251b..6c3091de 100644 --- a/src/__tests__/Calendar.jsx +++ b/src/__tests__/Calendar.jsx @@ -498,6 +498,29 @@ describe('Calendar', () => { expect(firstDayTileTimeAbbr).toBe(format(newActiveStartDate)); }); + it('does not changes Calendar view given new value', () => { + const getFirstDayTileLabel = (cmp) => { + const monthView = cmp.find('.react-calendar__month-view'); + const firstDayTile = monthView.find('.react-calendar__tile').first(); + const firstDayTileTimeAbbr = firstDayTile.find('abbr').prop('aria-label'); + return firstDayTileTimeAbbr; + }; + + const activeStartDate = new Date(2017, 0, 1); + const expectedFirstDate = new Date(2016, 11, 26); + const nextValue = new Date(2017, 3, 1); + + const component = mount( + + ); + + expect(getFirstDayTileLabel(component)).toBe(format(expectedFirstDate)); + + component.setProps({ value: nextValue }); + + expect(getFirstDayTileLabel(component)).toBe(format(expectedFirstDate)); + }); + it('displays calendar with custom weekdays formatting', () => { const component = mount( Date: Wed, 27 Nov 2019 17:38:01 +0100 Subject: [PATCH 4/7] Interface for typescript --- index.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.d.ts b/index.d.ts index 676b51a5..6381b588 100644 --- a/index.d.ts +++ b/index.d.ts @@ -16,6 +16,8 @@ declare module "react-calendar" { formatMonth?: FormatterCallback; formatMonthYear?: FormatterCallback; formatShortWeekday?: FormatterCallback; + hover?: Date + keepUsingActiveStartDate?: boolean locale?: string; maxDate?: Date; maxDetail?: Detail; From 41f262d40dc0b069ad79e5772266299c46482ca7 Mon Sep 17 00:00:00 2001 From: "Christopher N. KATOYI" Date: Wed, 27 Nov 2019 18:23:47 +0100 Subject: [PATCH 5/7] In and Out tile callbacks --- README.md | 2 ++ index.d.ts | 2 ++ src/Calendar.jsx | 5 +++++ src/__tests__/Calendar.jsx | 22 ++++++++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/README.md b/README.md index 09f87c00..6c1777f5 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,8 @@ Displays a complete, interactive calendar. |onClickYear|Function called when the user clicks a year.|n/a|`(value) => alert('Clicked year: ', value)`| |onDrillDown|Function called when the user drills down by clicking a tile.|n/a|`({ activeStartDate, view }) => alert('Drilled down to: ', activeStartDate, view)`| |onDrillUp|Function called when the user drills up by clicking drill up button.|n/a|`({ activeStartDate, view }) => alert('Drilled up to: ', activeStartDate, view)`| +|onMouseOutTile|Function called when the user hovers on a tile|n/a|`(value) => alert('Hovered date: ', date)` +|onMouseOverTile|Function called when the user moves out of the tiles|n/a|`() => alert('Out !')` |prevAriaLabel|`aria-label` attribute of the "previous" button on the navigation pane.|n/a|`"Previous"`| |prevLabel|Content of the "previous" button on the navigation pane.|`"‹"`|
  • String: `"‹"`
  • React element: ``
| |prev2AriaLabel|`aria-label` attribute of the "previous on higher level" button on the navigation pane.|n/a|`"Jump backwards"`| diff --git a/index.d.ts b/index.d.ts index 6381b588..0bbcc0ca 100644 --- a/index.d.ts +++ b/index.d.ts @@ -37,6 +37,8 @@ declare module "react-calendar" { onClickYear?: DateCallback; onDrillDown?: ViewCallback; onDrillUp?: ViewCallback; + onMouseOverTile?: DateCallback; + onMouseOutTile?: () => void; prev2AriaLabel?: string; prev2Label?: string | JSX.Element | null; prevAriaLabel?: string; diff --git a/src/Calendar.jsx b/src/Calendar.jsx index ed6239ec..e4dd2284 100644 --- a/src/Calendar.jsx +++ b/src/Calendar.jsx @@ -357,16 +357,21 @@ export default class Calendar extends Component { } onMouseOver = (value) => { + const { onMouseOverTile } = this.props + callIfDefined(onMouseOverTile, value) this.setState((prevState) => { if (prevState.hover && (prevState.hover.getTime() === value.getTime())) { return null; } + return { hover: value }; }); } onMouseLeave = () => { + const { onMouseOutTile } = this.props + callIfDefined(onMouseOutTile) this.setState({ hover: null }); } diff --git a/src/__tests__/Calendar.jsx b/src/__tests__/Calendar.jsx index 6c3091de..5a799502 100644 --- a/src/__tests__/Calendar.jsx +++ b/src/__tests__/Calendar.jsx @@ -534,6 +534,28 @@ describe('Calendar', () => { expect(firstWeekdayTile.text()).toBe('Weekday'); }); + it('calls onTileOver / onTileOut function if provided with the current hovered date', () => { + const onOver = jest.fn(); + const onOut = jest.fn(); + + const component = mount( + + ); + const viewContainer = component.find('.react-calendar__viewContainer') + const monthView = component.find('.react-calendar__month-view'); + const firstDayTile = monthView.find('.react-calendar__tile').first(); + firstDayTile.simulate('mouseover'); + viewContainer.simulate('mouseleave'); + + expect(onOver).toHaveBeenCalledTimes(1); + expect(onOut).toHaveBeenCalledTimes(1); + }); + it('displays calendar with custom month year navigation label', () => { const component = mount( Date: Wed, 27 Nov 2019 18:39:59 +0100 Subject: [PATCH 6/7] Lint & fix Readme --- README.md | 2 +- index.d.ts | 2 +- src/Calendar.jsx | 8 ++++---- src/__tests__/Calendar.jsx | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6c1777f5..27b3fcec 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Displays a complete, interactive calendar. |formatMonth|Function called to override default formatting of month names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMM')`| |formatMonthYear|Function called to override default formatting of month and year in the top navigation section. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'MMMM YYYY')`| |formatShortWeekday|Function called to override default formatting of weekday names. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'dd')`| -|hover|Date currently hovered, to bypass intern mechanism. If value is undefined, the default behaviour will be set|`undefined`|`Date` or `null` +|hover|Date currently hovered, to bypass intern mechanism. If value is undefined, the default behaviour will be set|`undefined`|`Date` or `null` or `undefined` |keepUsingActiveStartDate|Always use the `activeStartDate` as the beginning of the period that should be displayed by default|`false`|`true` or `false` |locale|Locale that should be used by the calendar. Can be any [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag).|User's browser settings|`"hu-HU"`| |maxDate|Maximum date that the user can select. Periods partially overlapped by maxDate will also be selectable, although React-Calendar will ensure that no later date is selected.|n/a|Date: `new Date()`| diff --git a/index.d.ts b/index.d.ts index 0bbcc0ca..b2654649 100644 --- a/index.d.ts +++ b/index.d.ts @@ -16,7 +16,7 @@ declare module "react-calendar" { formatMonth?: FormatterCallback; formatMonthYear?: FormatterCallback; formatShortWeekday?: FormatterCallback; - hover?: Date + hover?: Date | null keepUsingActiveStartDate?: boolean locale?: string; maxDate?: Date; diff --git a/src/Calendar.jsx b/src/Calendar.jsx index e4dd2284..ff1b8737 100644 --- a/src/Calendar.jsx +++ b/src/Calendar.jsx @@ -357,8 +357,8 @@ export default class Calendar extends Component { } onMouseOver = (value) => { - const { onMouseOverTile } = this.props - callIfDefined(onMouseOverTile, value) + const { onMouseOverTile } = this.props; + callIfDefined(onMouseOverTile, value); this.setState((prevState) => { if (prevState.hover && (prevState.hover.getTime() === value.getTime())) { return null; @@ -370,8 +370,8 @@ export default class Calendar extends Component { } onMouseLeave = () => { - const { onMouseOutTile } = this.props - callIfDefined(onMouseOutTile) + const { onMouseOutTile } = this.props; + callIfDefined(onMouseOutTile); this.setState({ hover: null }); } diff --git a/src/__tests__/Calendar.jsx b/src/__tests__/Calendar.jsx index 5a799502..5c57c919 100644 --- a/src/__tests__/Calendar.jsx +++ b/src/__tests__/Calendar.jsx @@ -540,13 +540,13 @@ describe('Calendar', () => { const component = mount( ); - const viewContainer = component.find('.react-calendar__viewContainer') + const viewContainer = component.find('.react-calendar__viewContainer'); const monthView = component.find('.react-calendar__month-view'); const firstDayTile = monthView.find('.react-calendar__tile').first(); firstDayTile.simulate('mouseover'); From bcde5fcf666160cbfa3d6849135f74276bf50b01 Mon Sep 17 00:00:00 2001 From: "Christopher N. KATOYI" Date: Wed, 27 Nov 2019 18:48:51 +0100 Subject: [PATCH 7/7] Fix proptypes --- src/Calendar.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Calendar.jsx b/src/Calendar.jsx index ff1b8737..96edc5eb 100644 --- a/src/Calendar.jsx +++ b/src/Calendar.jsx @@ -568,7 +568,10 @@ Calendar.propTypes = { formatMonth: PropTypes.func, formatMonthYear: PropTypes.func, formatShortWeekday: PropTypes.func, - hover: PropTypes.func, + hover: PropTypes.oneOfType([ + PropTypes.instanceOf(Date), + PropTypes.oneOf([null]), + ]), keepUsingActiveStartDate: PropTypes.bool, locale: PropTypes.string, maxDate: isMaxDate,