react-calendar
Advanced tools
Comparing version 3.1.0 to 3.2.0
{ | ||
"name": "react-calendar", | ||
"version": "3.1.0", | ||
"version": "3.2.0", | ||
"description": "Ultimate calendar for your React app.", | ||
@@ -8,8 +8,11 @@ "main": "dist/umd/index.js", | ||
"source": "src/index.js", | ||
"sideEffects": false, | ||
"sideEffects": [ | ||
"*.css", | ||
"*.less" | ||
], | ||
"scripts": { | ||
"build": "yarn build-js-all && yarn copy-styles && yarn build-styles", | ||
"build-js-all": "yarn build-js-esm && yarn build-js-umd", | ||
"build-js-esm": "cross-env BABEL_ENV=production-esm babel src -d dist/esm --ignore **/*.spec.js,**/*.spec.jsx", | ||
"build-js-umd": "cross-env BABEL_ENV=production-umd babel src -d dist/umd --ignore **/*.spec.js,**/*.spec.jsx", | ||
"build-js-esm": "cross-env BABEL_ENV=production-esm babel src -d dist/esm --ignore \"**/*.spec.js,**/*.spec.jsx\"", | ||
"build-js-umd": "cross-env BABEL_ENV=production-umd babel src -d dist/umd --ignore \"**/*.spec.js,**/*.spec.jsx\"", | ||
"build-styles": "lessc ./dist/Calendar.less ./dist/Calendar.css", | ||
@@ -92,8 +95,8 @@ "clean": "rimraf dist", | ||
"enzyme-adapter-react-16": "^1.14.0", | ||
"eslint": "^6.1.0", | ||
"eslint-config-airbnb": "^18.0.0", | ||
"eslint-plugin-import": "^2.18.2", | ||
"eslint-plugin-jsx-a11y": "^6.2.3", | ||
"eslint-plugin-react": "^7.14.3", | ||
"eslint-plugin-react-hooks": "^2.5.0", | ||
"eslint": "~7.2.0", | ||
"eslint-config-airbnb": "^18.2.0", | ||
"eslint-plugin-import": "^2.21.2", | ||
"eslint-plugin-jsx-a11y": "^6.3.0", | ||
"eslint-plugin-react": "^7.20.0", | ||
"eslint-plugin-react-hooks": "^4.0.0", | ||
"jest": "^26.0.0", | ||
@@ -119,3 +122,4 @@ "less": "^3.8.1", | ||
"url": "https://github.com/wojtekmaj/react-calendar.git" | ||
} | ||
} | ||
}, | ||
"funding": "https://github.com/wojtekmaj/react-calendar?sponsor=1" | ||
} |
@@ -1,2 +0,2 @@ | ||
[![npm](https://img.shields.io/npm/v/react-calendar.svg)](https://www.npmjs.com/package/react-calendar) ![downloads](https://img.shields.io/npm/dt/react-calendar.svg) ![build](https://travis-ci.com/wojtekmaj/react-calendar.svg?branch=master) ![dependencies](https://img.shields.io/david/wojtekmaj/react-calendar.svg) ![dev dependencies](https://img.shields.io/david/dev/wojtekmaj/react-calendar.svg) [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest) | ||
[![npm](https://img.shields.io/npm/v/react-calendar.svg)](https://www.npmjs.com/package/react-calendar) ![downloads](https://img.shields.io/npm/dt/react-calendar.svg) [![build](https://travis-ci.com/wojtekmaj/react-calendar.svg?branch=master)](https://travis-ci.com/wojtekmaj/react-calendar) ![dependencies](https://img.shields.io/david/wojtekmaj/react-calendar.svg) ![dev dependencies](https://img.shields.io/david/dev/wojtekmaj/react-calendar.svg) [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest) | ||
@@ -23,3 +23,3 @@ # React-Calendar | ||
Minimal demo page is included in sample directory. | ||
A minimal demo page can be found in `sample` directory. | ||
@@ -55,26 +55,20 @@ [Online demo](http://projects.wojtekmaj.pl/react-calendar/) is also available! | ||
```js | ||
import React, { Component } from 'react'; | ||
import React, { useState } from 'react'; | ||
import Calendar from 'react-calendar'; | ||
class MyApp extends Component { | ||
state = { | ||
date: new Date(), | ||
} | ||
function MyApp() { | ||
const [value, onChange] = useState(new Date()); | ||
onChange = date => this.setState({ date }) | ||
render() { | ||
return ( | ||
<div> | ||
<Calendar | ||
onChange={this.onChange} | ||
value={this.state.date} | ||
/> | ||
</div> | ||
); | ||
} | ||
return ( | ||
<div> | ||
<Calendar | ||
onChange={onChange} | ||
value={value} | ||
/> | ||
</div> | ||
); | ||
} | ||
``` | ||
Check the [sample directory](https://github.com/wojtekmaj/react-calendar/tree/master/sample) in this repository for a full working example. For more examples and more advanced use cases, check [Recipes](https://github.com/wojtekmaj/react-calendar/wiki/Recipes) in React-Calendar Wiki. | ||
Check the [sample directory](https://github.com/wojtekmaj/react-calendar/tree/master/sample) in this repository for a full working example. For more examples and more advanced use cases, check [Recipes](https://github.com/wojtekmaj/react-calendar/wiki/Recipes) in [React-Calendar Wiki](https://github.com/wojtekmaj/react-calendar/wiki). | ||
@@ -113,2 +107,3 @@ ### Custom styling | ||
|formatYear|Function called to override default formatting of year in the top navigation section. Can be used to use your own formatting function.|(default formatter)|`(locale, date) => formatDate(date, 'YYYY')`| | ||
|inputRef|A prop that behaves like [ref](https://reactjs.org/docs/refs-and-the-dom.html), but it's passed to main `<div>` rendered by `<Calendar>` component.|n/a|<ul><li>Function:<br />`(ref) => { this.myCalendar = ref; }`</li><li>Ref created using `React.createRef`:<br />`this.ref = React.createRef();`<br />…<br />`inputRef={this.ref}`</li><li>Ref created using `React.useRef`:<br />`const ref = React.useRef();`<br />…<br />`inputRef={ref}`</li></ul>| | ||
|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"`| | ||
@@ -125,5 +120,5 @@ |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()`| | ||
|next2Label|Content of the "next on higher level" button on the navigation pane. Setting the value explicitly to null will hide the icon.|`"»"`|<ul><li>String: `"»"`</li><li>React element: `<DoubleNextIcon />`</li></ul>| | ||
|onActiveStartDateChange|Function called when the user navigates from one view to another using previous/next button.|n/a|`({ activeStartDate, view }) => alert('Changed view to: ', activeStartDate, view)`| | ||
|onActiveStartDateChange|Function called when the user navigates from one view to another using previous/next button.|n/a|`({ activeStartDate, value, view }) => alert('Changed view to: ', activeStartDate, view)`| | ||
|onChange|Function called when the user clicks an item (day on month view, month on year view and so on) on the most detailed view available.|n/a|`(value, event) => alert('New date is: ', value)`| | ||
|onViewChange|Function called when the user navigates from one view to another using drill up button or by clicking a tile.|n/a|`({ activeStartDate, view }) => alert('New view is: ', view)`| | ||
|onViewChange|Function called when the user navigates from one view to another using drill up button or by clicking a tile.|n/a|`({ activeStartDate, value, view }) => alert('New view is: ', view)`| | ||
|onClickDay|Function called when the user clicks a day.|n/a|`(value, event) => alert('Clicked day: ', value)`| | ||
@@ -170,2 +165,6 @@ |onClickDecade|Function called when the user clicks a decade.|n/a|`(value, event) => alert('Clicked decade: ', value)`| | ||
## Useful links | ||
* [React-Calendar Wiki](https://github.com/wojtekmaj/react-calendar/wiki) | ||
## License | ||
@@ -172,0 +171,0 @@ |
@@ -15,3 +15,3 @@ import React, { Component } from 'react'; | ||
import { | ||
isCalendarType, isClassName, isMaxDate, isMinDate, isValue, isView, | ||
isCalendarType, isClassName, isMaxDate, isMinDate, isRef, isValue, isView, | ||
} from './shared/propTypes'; | ||
@@ -248,3 +248,3 @@ import { between } from './shared/utils'; | ||
setStateAndCallCallbacks = (nextState, callback) => { | ||
setStateAndCallCallbacks = (nextState, event, callback) => { | ||
const { | ||
@@ -271,2 +271,3 @@ activeStartDate: previousActiveStartDate, | ||
activeStartDate: nextState.activeStartDate || this.activeStartDate, | ||
value: nextState.value || this.value, | ||
view: nextState.view || this.view, | ||
@@ -306,8 +307,8 @@ }; | ||
if (!isSingleValue) { | ||
onChange(nextState.value); | ||
onChange(nextState.value, event); | ||
} else if (allowPartialRange) { | ||
onChange([nextState.value]); | ||
onChange([nextState.value], event); | ||
} | ||
} else { | ||
onChange(nextState.value); | ||
onChange(nextState.value, event); | ||
} | ||
@@ -343,3 +344,3 @@ } | ||
view: nextView, | ||
}, onDrillDown); | ||
}, undefined, onDrillDown); | ||
} | ||
@@ -361,3 +362,3 @@ | ||
view: nextView, | ||
}, onDrillUp); | ||
}, undefined, onDrillUp); | ||
} | ||
@@ -392,6 +393,8 @@ | ||
event.persist(); | ||
this.setStateAndCallCallbacks({ | ||
activeStartDate: nextActiveStartDate, | ||
value: nextValue, | ||
}); | ||
}, event); | ||
} | ||
@@ -601,3 +604,8 @@ | ||
render() { | ||
const { className, selectRange, showDoubleView } = this.props; | ||
const { | ||
className, | ||
inputRef, | ||
selectRange, | ||
showDoubleView, | ||
} = this.props; | ||
const { onMouseLeave, value } = this; | ||
@@ -614,2 +622,3 @@ const valueArray = [].concat(value); | ||
)} | ||
ref={inputRef} | ||
> | ||
@@ -657,2 +666,3 @@ {this.renderNavigation()} | ||
formatYear: PropTypes.func, | ||
inputRef: isRef, | ||
locale: PropTypes.string, | ||
@@ -659,0 +669,0 @@ maxDate: isMaxDate, |
@@ -9,3 +9,30 @@ import React from 'react'; | ||
const event = document.createEvent('MouseEvent'); | ||
event.initEvent('click', true, true); | ||
event.persist = () => {}; | ||
describe('Calendar', () => { | ||
it('applies className to its wrapper when given a string', () => { | ||
const className = 'testClassName'; | ||
const component = shallow( | ||
<Calendar className={className} />, | ||
); | ||
const wrapperClassName = component.find('.react-calendar').prop('className'); | ||
expect(wrapperClassName.includes(className)).toBe(true); | ||
}); | ||
it('passes container element to inputRef properly', () => { | ||
const inputRef = jest.fn(); | ||
mount( | ||
<Calendar inputRef={inputRef} />, | ||
); | ||
expect(inputRef).toHaveBeenCalled(); | ||
expect(inputRef.mock.calls[0][0]).toBeInstanceOf(HTMLElement); | ||
}); | ||
it('renders Navigation by default', () => { | ||
@@ -102,3 +129,3 @@ const component = shallow( | ||
component.instance().onChange(newValue); | ||
component.instance().onChange(newValue, event); | ||
@@ -519,2 +546,3 @@ expect(component.instance().activeStartDate).toEqual(newActiveStartDate); | ||
it('calls onActiveStartDateChange on activeStartDate initial set', () => { | ||
const value = new Date(2019, 0, 15); | ||
const newActiveStartDate = new Date(2018, 0, 1); | ||
@@ -525,2 +553,3 @@ const onActiveStartDateChange = jest.fn(); | ||
onActiveStartDateChange={onActiveStartDateChange} | ||
value={value} | ||
view="year" | ||
@@ -534,2 +563,3 @@ />, | ||
activeStartDate: newActiveStartDate, | ||
value, | ||
view: 'year', | ||
@@ -540,2 +570,3 @@ }); | ||
it('calls onActiveStartDateChange on activeStartDate change', () => { | ||
const value = new Date(2019, 0, 15); | ||
const activeStartDate = new Date(2017, 0, 1); | ||
@@ -548,2 +579,3 @@ const newActiveStartDate = new Date(2018, 0, 1); | ||
onActiveStartDateChange={onActiveStartDateChange} | ||
value={value} | ||
view="year" | ||
@@ -557,2 +589,3 @@ />, | ||
activeStartDate: newActiveStartDate, | ||
value, | ||
view: 'year', | ||
@@ -578,2 +611,19 @@ }); | ||
}); | ||
it('does not call onActiveStartDateChange on activeStartDate change if value is the same as previously inherited', () => { | ||
const value = new Date(2017, 0, 1); | ||
const newActiveStartDate = new Date(2017, 0, 1); | ||
const onActiveStartDateChange = jest.fn(); | ||
const component = shallow( | ||
<Calendar | ||
onActiveStartDateChange={onActiveStartDateChange} | ||
value={value} | ||
view="year" | ||
/>, | ||
); | ||
component.instance().setActiveStartDate(newActiveStartDate); | ||
expect(onActiveStartDateChange).not.toHaveBeenCalled(); | ||
}); | ||
}); | ||
@@ -583,2 +633,3 @@ | ||
it('calls onViewChange on view initial set', () => { | ||
const value = new Date(2019, 0, 15); | ||
const activeStartDate = new Date(2017, 0, 1); | ||
@@ -591,2 +642,3 @@ const newView = 'year'; | ||
onViewChange={onViewChange} | ||
value={value} | ||
/>, | ||
@@ -599,2 +651,3 @@ ); | ||
activeStartDate, | ||
value, | ||
view: newView, | ||
@@ -605,2 +658,3 @@ }); | ||
it('calls onViewChange on view change', () => { | ||
const value = new Date(2019, 0, 15); | ||
const activeStartDate = new Date(2017, 0, 1); | ||
@@ -614,2 +668,3 @@ const view = 'year'; | ||
onViewChange={onViewChange} | ||
value={value} | ||
view={view} | ||
@@ -623,2 +678,3 @@ />, | ||
activeStartDate, | ||
value, | ||
view: newView, | ||
@@ -629,3 +685,2 @@ }); | ||
it('does not call onViewChange on view change if value is the same as before', () => { | ||
const activeStartDate = new Date(2017, 0, 1); | ||
const view = 'year'; | ||
@@ -636,3 +691,2 @@ const newView = 'year'; | ||
<Calendar | ||
activeStartDate={activeStartDate} | ||
onViewChange={onViewChange} | ||
@@ -659,5 +713,5 @@ view={view} | ||
component.instance().onChange(new Date(2017, 0, 1)); | ||
component.instance().onChange(new Date(2017, 0, 1), event); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1)); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1), event); | ||
}); | ||
@@ -675,5 +729,5 @@ | ||
component.instance().onChange(new Date(2017, 0, 1)); | ||
component.instance().onChange(new Date(2017, 0, 1), event); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1)); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1), event); | ||
}); | ||
@@ -691,5 +745,5 @@ | ||
component.instance().onChange(new Date(2017, 0, 1)); | ||
component.instance().onChange(new Date(2017, 0, 1), event); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 23, 59, 59, 999)); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 23, 59, 59, 999), event); | ||
}); | ||
@@ -707,3 +761,3 @@ | ||
component.instance().onChange(new Date(2017, 0, 1)); | ||
component.instance().onChange(new Date(2017, 0, 1), event); | ||
@@ -713,3 +767,3 @@ expect(onChange).toHaveBeenCalledWith([ | ||
new Date(2017, 0, 1, 23, 59, 59, 999), | ||
]); | ||
], event); | ||
}); | ||
@@ -728,5 +782,5 @@ | ||
component.instance().onChange(new Date(2017, 0, 1)); | ||
component.instance().onChange(new Date(2017, 0, 1), event); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 12)); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 12), event); | ||
}); | ||
@@ -745,5 +799,5 @@ | ||
component.instance().onChange(new Date(2017, 0, 2)); | ||
component.instance().onChange(new Date(2017, 0, 2), event); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 12)); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 12), event); | ||
}); | ||
@@ -762,5 +816,5 @@ | ||
component.instance().onChange(new Date(2017, 0, 1)); | ||
component.instance().onChange(new Date(2017, 0, 1), event); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 2, 12)); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 2, 12), event); | ||
}); | ||
@@ -779,5 +833,5 @@ | ||
component.instance().onChange(new Date(2017, 0, 2)); | ||
component.instance().onChange(new Date(2017, 0, 2), event); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 12)); | ||
expect(onChange).toHaveBeenCalledWith(new Date(2017, 0, 1, 12), event); | ||
}); | ||
@@ -795,3 +849,3 @@ | ||
component.instance().onChange(new Date(2018, 0, 1)); | ||
component.instance().onChange(new Date(2018, 0, 1), event); | ||
@@ -812,3 +866,3 @@ expect(onChange).not.toHaveBeenCalled(); | ||
component.instance().onChange(new Date(2018, 0, 1)); | ||
component.instance().onChange(new Date(2018, 0, 1), event); | ||
@@ -829,3 +883,3 @@ expect(onChange).not.toHaveBeenCalled(); | ||
component.instance().onChange(new Date(2018, 0, 1)); | ||
component.instance().onChange(new Date(2018, 0, 1), event); | ||
@@ -835,3 +889,3 @@ expect(onChange).toHaveBeenCalledTimes(1); | ||
new Date(2018, 0, 1), | ||
]); | ||
], event); | ||
}); | ||
@@ -849,4 +903,4 @@ | ||
component.instance().onChange(new Date(2018, 0, 1)); | ||
component.instance().onChange(new Date(2018, 6, 1)); | ||
component.instance().onChange(new Date(2018, 0, 1), event); | ||
component.instance().onChange(new Date(2018, 6, 1), event); | ||
@@ -857,3 +911,3 @@ expect(onChange).toHaveBeenCalledTimes(1); | ||
new Date(2018, 6, 1, 23, 59, 59, 999), | ||
]); | ||
], event); | ||
}); | ||
@@ -871,4 +925,4 @@ | ||
component.instance().onChange(new Date(2018, 6, 1)); | ||
component.instance().onChange(new Date(2018, 0, 1)); | ||
component.instance().onChange(new Date(2018, 6, 1), event); | ||
component.instance().onChange(new Date(2018, 0, 1), event); | ||
@@ -879,3 +933,3 @@ expect(onChange).toHaveBeenCalledTimes(1); | ||
new Date(2018, 6, 1, 23, 59, 59, 999), | ||
]); | ||
], event); | ||
}); | ||
@@ -882,0 +936,0 @@ }); |
@@ -171,21 +171,25 @@ import React from 'react'; | ||
)} | ||
<button | ||
aria-label={prevAriaLabel} | ||
className={`${className}__arrow ${className}__prev-button`} | ||
disabled={prevButtonDisabled} | ||
onClick={onClickPrevious} | ||
type="button" | ||
> | ||
{prevLabel} | ||
</button> | ||
{prevLabel !== null && ( | ||
<button | ||
aria-label={prevAriaLabel} | ||
className={`${className}__arrow ${className}__prev-button`} | ||
disabled={prevButtonDisabled} | ||
onClick={onClickPrevious} | ||
type="button" | ||
> | ||
{prevLabel} | ||
</button> | ||
)} | ||
{renderButton()} | ||
<button | ||
aria-label={nextAriaLabel} | ||
className={`${className}__arrow ${className}__next-button`} | ||
disabled={nextButtonDisabled} | ||
onClick={onClickNext} | ||
type="button" | ||
> | ||
{nextLabel} | ||
</button> | ||
{nextLabel !== null && ( | ||
<button | ||
aria-label={nextAriaLabel} | ||
className={`${className}__arrow ${className}__next-button`} | ||
disabled={nextButtonDisabled} | ||
onClick={onClickNext} | ||
type="button" | ||
> | ||
{nextLabel} | ||
</button> | ||
)} | ||
{next2Label !== null && shouldShowPrevNext2Buttons && ( | ||
@@ -217,9 +221,9 @@ <button | ||
next2AriaLabel: PropTypes.string, | ||
next2Label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), | ||
next2Label: PropTypes.node, | ||
nextAriaLabel: PropTypes.string, | ||
nextLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), | ||
nextLabel: PropTypes.node, | ||
prev2AriaLabel: PropTypes.string, | ||
prev2Label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), | ||
prev2Label: PropTypes.node, | ||
prevAriaLabel: PropTypes.string, | ||
prevLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), | ||
prevLabel: PropTypes.node, | ||
setActiveStartDate: PropTypes.func.isRequired, | ||
@@ -226,0 +230,0 @@ showDoubleView: PropTypes.bool, |
@@ -10,2 +10,7 @@ import PropTypes from 'prop-types'; | ||
export const isClassName = PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.arrayOf(PropTypes.string), | ||
]); | ||
export const isMinDate = (props, propName, componentName) => { | ||
@@ -51,2 +56,9 @@ const { [propName]: minDate } = props; | ||
export const isRef = PropTypes.oneOfType([ | ||
PropTypes.func, | ||
PropTypes.shape({ | ||
current: PropTypes.any, | ||
}), | ||
]); | ||
export const isValue = PropTypes.oneOfType([ | ||
@@ -59,7 +71,2 @@ PropTypes.instanceOf(Date), | ||
export const isClassName = PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.arrayOf(PropTypes.string), | ||
]); | ||
export const isView = (props, propName, componentName) => { | ||
@@ -66,0 +73,0 @@ const { [propName]: view } = props; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
462953
10643
203