diff --git a/README.md b/README.md index 9c967856a..dea8a7012 100644 --- a/README.md +++ b/README.md @@ -51,28 +51,24 @@ var Example = React.createClass({ ## Configuration -The default Datepicker can be initialised by: +The most basic use of the DatePicker can be described with: ```js - + ``` -This included the Datepicker with its default functionality. To use more functionality you can pass extra props to the Datepicker to enable them. +See [here](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) for a full list of props that may be passed to the component. Examples are given on the [main website](https://hacker0x01.github.io/react-datepicker). + +### Localization + +The date picker relies on [moment.js internationalization](http://momentjs.com/docs/#/i18n/) to localize its display components. By default, the date picker will use the locale globally set in moment, which is English. Locales can be changed in the following ways: + +- **Globally** by calling `moment.locale(lang)` +- **Picker-specific** by providing the `locale` prop -- Change date format by passing a different date format in the props: `dateFormat: “YYYY/MM/DD”` -- Add placeholder text: `placeholderText: 'Click to select a date'` (Defaults to the selected date when no placeholder text is added) -- Give users a predefined date range: `minDate: moment()` & `maxDate: moment().add(5, 'days')` (this gives users the ability to select a date between today and 5 days in the future) -- Exclude a set of dates from those that are selectable: `excludeDates: [ moment(), moment('2015-01-01') ]` (prevent users from selecting today or Jan 1st, 2015) -- Include a set of dates from those that are selectable: `includeDates: [ moment(), moment(‘2015-01-01’) ]` (allow users selecting only today or Jan 1st, 2015) -- Set custom moment.js instance (could have defined custom locale settings): `moment: require('./foo/moment')` -- Set custom locale settings for locale: `locale: 'cs'` -- Set date format for calendar: `dateFormatCalendar: 'YYYY/MM/DD'` -- Set custom weekdays (for locale days): `weekdays: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So']` -- Set custom calendar week start day: `weekStart: '0'` would start the week on Sunday +Locales can be further configured in moment with various [customization options](http://momentjs.com/docs/#/customization/). -More information about the different ways to customise available at https://hacker0x01.github.io/react-datepicker. +_As of version 0.23, the `weekdays` and `weekStart` DatePicker props have been removed. Instead, they can be configured with the `weekdaysMin` and `week.dow` moment locale customization options._ ## Compatibility diff --git a/docs-site/src/example_components.jsx b/docs-site/src/example_components.jsx index 9864ebbfb..a0b5470d0 100644 --- a/docs-site/src/example_components.jsx +++ b/docs-site/src/example_components.jsx @@ -8,14 +8,13 @@ import CustomDateFormat from "./examples/custom_date_format"; import CustomClassName from "./examples/custom_class_name"; import PlaceholderText from "./examples/placeholder_text"; import SpecificDateRange from "./examples/specific_date_range"; -import CustomStartDate from "./examples/custom_start_date"; +import Locale from "./examples/locale"; import ExcludeDates from "./examples/exclude_dates"; import IncludeDates from "./examples/include_dates"; import FilterDates from "./examples/filter_dates"; import Disabled from "./examples/disabled"; import ClearInput from "./examples/clear_input"; import OnBlurCallbacks from "./examples/on_blur_callbacks"; -import Weekdays from "./examples/weekdays"; import Placement from "./examples/placement"; import DateRange from "./examples/date_range"; import TabIndex from "./examples/tab_index"; @@ -65,8 +64,8 @@ export default React.createClass({ component: }, { - title: "Custom week start day", - component: + title: "Locale", + component: }, { title: "Exclude dates", @@ -96,10 +95,6 @@ export default React.createClass({ title: "onBlur callbacks in console", component: }, - { - title: "Custom weekdays", - component: - }, { title: "Configure Popover Placement", component: diff --git a/docs-site/src/examples/custom_start_date.jsx b/docs-site/src/examples/locale.jsx similarity index 79% rename from docs-site/src/examples/custom_start_date.jsx rename to docs-site/src/examples/locale.jsx index e9449fff1..7cafae367 100644 --- a/docs-site/src/examples/custom_start_date.jsx +++ b/docs-site/src/examples/locale.jsx @@ -24,16 +24,16 @@ export default React.createClass({ {"     {"selected={this.state.startDate}"}
    {"onChange={this.handleChange}"}
-     {"weekStart='0'"}
-     {"placeholderText='I start on Sunday!' />"} +     {"locale='en-gb'"}
+     {"placeholderText='Weeks start on Monday' />"}
+ locale="en-gb" + placeholderText="Weeks start on Monday" />
; } diff --git a/docs-site/src/examples/weekdays.jsx b/docs-site/src/examples/weekdays.jsx deleted file mode 100644 index 518d8e99e..000000000 --- a/docs-site/src/examples/weekdays.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import DatePicker from "react-datepicker"; -import moment from "moment"; - -export default React.createClass({ - displayName: "Weekdays", - - getInitialState() { - return { - startDate: moment() - }; - }, - - handleChange(date) { - this.setState({ - startDate: date - }); - }, - - render() { - return
-
-        
-          {"
-              {"selected={this.state.startDate}"}
-     {"onChange={this.handleChange}"}
-     {"weekdays: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So']"} -
-
-
- -
-
; - } -}); diff --git a/src/calendar.jsx b/src/calendar.jsx index ae7850ae5..49a79d88c 100644 --- a/src/calendar.jsx +++ b/src/calendar.jsx @@ -20,8 +20,7 @@ var Calendar = React.createClass({ mixins: [require("react-onclickoutside")], propTypes: { - weekdays: React.PropTypes.array.isRequired, - locale: React.PropTypes.string.isRequired, + locale: React.PropTypes.string, moment: React.PropTypes.func.isRequired, dateFormat: React.PropTypes.string.isRequired, onSelect: React.PropTypes.func.isRequired, @@ -33,7 +32,6 @@ var Calendar = React.createClass({ excludeDates: React.PropTypes.array, includeDates: React.PropTypes.array, filterDate: React.PropTypes.func, - weekStart: React.PropTypes.string.isRequired, showYearDropdown: React.PropTypes.bool }, @@ -43,38 +41,20 @@ var Calendar = React.createClass({ getInitialState() { return { - date: getDateInView(this.props) + date: this.localizeMoment(getDateInView(this.props)) }; }, - getDefaultProps() { - return { - weekStart: "1" - }; - }, - - componentWillMount() { - this.initializeMomentLocale(); - }, - componentWillReceiveProps(nextProps) { if (nextProps.selected && !isSameDay(nextProps.selected, this.props.selected)) { this.setState({ - date: nextProps.selected + date: this.localizeMoment(nextProps.selected) }); } }, - initializeMomentLocale() { - var weekdays = this.props.weekdays.slice(0); - weekdays = weekdays.concat(weekdays.splice(0, this.props.weekStart)); - - this.props.moment.locale(this.props.locale, { - week: { - dow: this.props.weekStart - }, - weekdaysMin: weekdays - }); + localizeMoment(date) { + return date.clone().locale(this.props.locale || this.props.moment.locale()); }, increaseMonth() { @@ -100,8 +80,14 @@ var Calendar = React.createClass({ }, header() { - return this.props.moment.weekdaysMin().map(function(day, key) { - return
{day}
; + const startOfWeek = this.state.date.clone().startOf("week"); + return [0, 1, 2, 3, 4, 5, 6].map(offset => { + const day = startOfWeek.clone().add(offset, "days"); + return ( +
+ {day.localeData().weekdaysMin(day)} +
+ ); }); }, diff --git a/src/date_input.jsx b/src/date_input.jsx index 44bd9d956..817843f26 100644 --- a/src/date_input.jsx +++ b/src/date_input.jsx @@ -8,6 +8,7 @@ var DateInput = React.createClass({ propTypes: { date: React.PropTypes.object, + locale: React.PropTypes.string, minDate: React.PropTypes.object, maxDate: React.PropTypes.object, excludeDates: React.PropTypes.array, @@ -50,7 +51,9 @@ var DateInput = React.createClass({ }, safeDateFormat(date) { - return !!date ? date.format(this.props.dateFormat) : null; + return date && date.clone() + .locale(this.props.locale || moment.locale()) + .format(this.props.dateFormat); }, handleKeyDown(event) { diff --git a/src/datepicker.jsx b/src/datepicker.jsx index 0131e30c5..1f3048021 100644 --- a/src/datepicker.jsx +++ b/src/datepicker.jsx @@ -13,7 +13,6 @@ var DatePicker = React.createClass({ propTypes: { selected: React.PropTypes.object, - weekdays: React.PropTypes.arrayOf(React.PropTypes.string), locale: React.PropTypes.string, dateFormatCalendar: React.PropTypes.string, disabled: React.PropTypes.bool, @@ -22,7 +21,6 @@ var DatePicker = React.createClass({ popoverTargetAttachment: React.PropTypes.string, popoverTargetOffset: React.PropTypes.string, tetherConstraints: React.PropTypes.array, - weekStart: React.PropTypes.string, showYearDropdown: React.PropTypes.bool, onChange: React.PropTypes.func.isRequired, onBlur: React.PropTypes.func, @@ -34,8 +32,6 @@ var DatePicker = React.createClass({ getDefaultProps() { return { - weekdays: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], - locale: "en", dateFormatCalendar: "MMMM YYYY", onChange() {}, disabled: false, @@ -110,7 +106,6 @@ var DatePicker = React.createClass({ } return ; }, @@ -151,6 +145,7 @@ var DatePicker = React.createClass({ id={this.props.id} name={this.props.name} date={this.props.selected} + locale={this.props.locale} minDate={this.props.minDate} maxDate={this.props.maxDate} excludeDates={this.props.excludeDates} diff --git a/src/day.jsx b/src/day.jsx index 22a665250..458031351 100644 --- a/src/day.jsx +++ b/src/day.jsx @@ -44,8 +44,8 @@ var Day = React.createClass({ }, isWeekend() { - const weekday = this.props.day.weekday(); - return weekday === 5 || weekday === 6; + const weekday = this.props.day.day(); + return weekday === 0 || weekday === 6; }, isOutsideMonth() { diff --git a/test/calendar_test.js b/test/calendar_test.js index a0df30698..adf11dfc4 100644 --- a/test/calendar_test.js +++ b/test/calendar_test.js @@ -5,12 +5,12 @@ import Calendar from "../src/calendar"; import YearDropdown from "../src/year_dropdown"; describe("Calendar", function() { + var dateFormat = "MMMM YYYY"; + function getCalendar(extraProps) { return {}} onClickOutside={() => {}} hideCalendar={() => {}} @@ -73,4 +73,44 @@ describe("Calendar", function() { expect(todayButton).to.exist; expect(todayButton.textContent).to.equal("Vandaag"); }); + + describe("localization", function() { + function testLocale(calendar, selected, locale) { + var localized = selected.clone().locale(locale); + + var calendarText = TestUtils.findRenderedDOMComponentWithClass(calendar, "datepicker__current-month"); + expect(calendarText.textContent).to.equal(localized.format(dateFormat)); + + var firstDateOfWeek = localized.clone().startOf("week"); + var firstWeekDayMin = firstDateOfWeek.localeData().weekdaysMin(firstDateOfWeek); + var firstHeader = TestUtils.scryRenderedDOMComponentsWithClass(calendar, "datepicker__day")[0]; + expect(firstHeader.textContent).to.equal(firstWeekDayMin); + } + + it("should use the globally-defined locale by default", function() { + var selected = moment(); + var calendar = TestUtils.renderIntoDocument(getCalendar({ selected })); + testLocale(calendar, selected, moment.locale()); + }); + + it("should use the locale specified as a prop", function() { + var locale = "fr"; + var selected = moment().locale(locale); + var calendar = TestUtils.renderIntoDocument(getCalendar({ selected, locale })); + testLocale(calendar, selected, locale); + }); + + it("should override the locale of the date with the globally-defined locale", function() { + var selected = moment().locale("fr"); + var calendar = TestUtils.renderIntoDocument(getCalendar({ selected })); + testLocale(calendar, selected, moment.locale()); + }); + + it("should override the locale of the date with the locale prop", function() { + var locale = "fr"; + var selected = moment(); + var calendar = TestUtils.renderIntoDocument(getCalendar({ selected, locale })); + testLocale(calendar, selected, locale); + }); + }); }); diff --git a/test/date_input_test.js b/test/date_input_test.js index ed7ddcade..921210ce7 100644 --- a/test/date_input_test.js +++ b/test/date_input_test.js @@ -191,4 +191,48 @@ describe("DateInput", function() { expect(inputNode.value).to.equal(""); }); }); + + describe("localization", function() { + var dateFormat = "LL"; + + function testLocale(dateInput, date, locale) { + var localized = date.clone().locale(locale); + var inputNode = dateInput.refs.input; + expect(inputNode.value).to.equal(localized.format(dateFormat)); + } + + it("should use the globally-defined locale by default", function() { + var date = moment(); + var dateInput = TestUtils.renderIntoDocument( + + ); + testLocale(dateInput, date, moment.locale()); + }); + + it("should use the locale specified as a prop", function() { + var locale = "fr"; + var date = moment().locale(locale); + var dateInput = TestUtils.renderIntoDocument( + + ); + testLocale(dateInput, date, locale); + }); + + it("should override the locale of the date with the globally-defined locale", function() { + var date = moment().locale("fr"); + var dateInput = TestUtils.renderIntoDocument( + + ); + testLocale(dateInput, date, moment.locale()); + }); + + it("should override the locale of the date with the locale prop", function() { + var locale = "fr"; + var date = moment(); + var dateInput = TestUtils.renderIntoDocument( + + ); + testLocale(dateInput, date, locale); + }); + }); });