Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2.x] Hover callback, activeStartDate internal override... #282

Open
wants to merge 7 commits into
base: v2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ 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` 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()`|
|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"`|
Expand All @@ -110,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.|`"‹"`|<ul><li>String: `"‹"`</li><li>React element: `<PreviousIcon />`</li></ul>|
|prev2AriaLabel|`aria-label` attribute of the "previous on higher level" button on the navigation pane.|n/a|`"Jump backwards"`|
Expand Down
4 changes: 4 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ declare module "react-calendar" {
formatMonth?: FormatterCallback;
formatMonthYear?: FormatterCallback;
formatShortWeekday?: FormatterCallback;
hover?: Date | null
keepUsingActiveStartDate?: boolean
locale?: string;
maxDate?: Date;
maxDetail?: Detail;
Expand All @@ -35,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;
Expand Down
29 changes: 24 additions & 5 deletions src/Calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const getDetailValueArray = (value, minDate, maxDate, maxDetail) => {
const getActiveStartDate = (props) => {
const {
activeStartDate,
keepUsingActiveStartDate,
maxDate,
maxDetail,
minDate,
Expand All @@ -144,11 +145,14 @@ const getActiveStartDate = (props) => {
} = props;

const rangeType = getView(view, minDetail, maxDetail);
const valueFrom = (

const valueFrom = keepUsingActiveStartDate ? (
activeStartDate
|| getDetailValueFrom(value, minDate, maxDate, maxDetail)
) : (
getDetailValueFrom(value, minDate, maxDate, maxDetail)
|| activeStartDate
|| new Date()
);
) || new Date();
return getBegin(rangeType, valueFrom);
};

Expand Down Expand Up @@ -353,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 });
}

Expand All @@ -377,15 +386,16 @@ export default class Calendar extends Component {
tileClassName,
tileContent,
tileDisabled,
hover,
} = this.props;
const {
activeStartDate, hover, value, view,
activeStartDate, hover: hoverFromState, value, view,
} = this.state;
const { onMouseOver, valueType } = this;

const commonProps = {
activeStartDate,
hover,
hover: selectRange ? hover || hoverFromState : null,
locale,
maxDate,
minDate,
Expand Down Expand Up @@ -541,6 +551,8 @@ export default class Calendar extends Component {
}

Calendar.defaultProps = {
hover: undefined,
keepUsingActiveStartDate: false,
maxDetail: 'month',
minDetail: 'century',
returnValue: 'start',
Expand All @@ -556,6 +568,11 @@ Calendar.propTypes = {
formatMonth: PropTypes.func,
formatMonthYear: PropTypes.func,
formatShortWeekday: PropTypes.func,
hover: PropTypes.oneOfType([
PropTypes.instanceOf(Date),
PropTypes.oneOf([null]),
]),
keepUsingActiveStartDate: PropTypes.bool,
locale: PropTypes.string,
maxDate: isMaxDate,
maxDetail: PropTypes.oneOf(allViews),
Expand All @@ -576,6 +593,8 @@ Calendar.propTypes = {
onClickYear: PropTypes.func,
onDrillDown: PropTypes.func,
onDrillUp: PropTypes.func,
onMouseOutTile: PropTypes.func,
onMouseOverTile: PropTypes.func,
prev2AriaLabel: PropTypes.string,
prev2Label: PropTypes.node,
prevAriaLabel: PropTypes.string,
Expand Down
45 changes: 45 additions & 0 deletions src/__tests__/Calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<Calendar activeStartDate={activeStartDate} keepUsingActiveStartDate view="month" />
);

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(
<Calendar
Expand All @@ -511,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(
<Calendar
onMouseOutTile={onOut}
onMouseOverTile={onOver}
selectRange
view="month"
/>
);
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(
<Calendar
Expand Down