diff --git a/index.d.ts b/index.d.ts index e24041c4..c82a1192 100644 --- a/index.d.ts +++ b/index.d.ts @@ -26,6 +26,7 @@ declare module "react-nice-dates" { maximumDate?: Date; modifiers?: Modifiers; modifiersClassNames?: ModifiersClassNames; + monthFormat?: string; weekdayFormat?: string; } diff --git a/src/Calendar.js b/src/Calendar.js index 3150f534..cb2abd7a 100644 --- a/src/Calendar.js +++ b/src/Calendar.js @@ -17,6 +17,7 @@ export default function Calendar({ onMonthChange, onDayHover, onDayClick, + monthFormat, weekdayFormat, touchDragEnabled }) { @@ -34,6 +35,7 @@ export default function Calendar({ minimumDate={minimumDate} maximumDate={maximumDate} month={month} + monthFormat={monthFormat} onMonthChange={setMonth} /> @@ -63,6 +65,7 @@ Calendar.propTypes = { onMonthChange: func, onDayHover: func, onDayClick: func, + monthFormat: string, weekdayFormat: string, touchDragEnabled: bool } diff --git a/src/CalendarNavigation.js b/src/CalendarNavigation.js index c077641c..38e983c1 100644 --- a/src/CalendarNavigation.js +++ b/src/CalendarNavigation.js @@ -1,9 +1,16 @@ import React from 'react' -import { func, instanceOf, object } from 'prop-types' +import { func, instanceOf, object, string } from 'prop-types' import classNames from 'classnames' import { addMonths, getYear, startOfMonth, subMonths, format, isSameMonth } from 'date-fns' -export default function CalendarNavigation({ locale, month, minimumDate, maximumDate, onMonthChange }) { +export default function CalendarNavigation({ + locale, + month, + minimumDate, + maximumDate, + monthFormat: receivedMonthFormat, + onMonthChange +}) { const handlePrevious = event => { onMonthChange(startOfMonth(subMonths(month, 1))) event.preventDefault() @@ -14,6 +21,8 @@ export default function CalendarNavigation({ locale, month, minimumDate, maximum event.preventDefault() } + const monthFormat = receivedMonthFormat || (getYear(month) === getYear(new Date()) ? 'LLLL' : 'LLLL yyyy'); + return (
- - {format(month, getYear(month) === getYear(new Date()) ? 'LLLL' : 'LLLL yyyy', { locale })} + + {format(month, monthFormat, { locale })} @@ -94,6 +96,7 @@ DatePicker.propTypes = { maximumDate: instanceOf(Date), modifiers: objectOf(func), modifiersClassNames: objectOf(string), + monthFormat: string, weekdayFormat: string, touchDragEnabled: bool } diff --git a/src/DatePickerCalendar.js b/src/DatePickerCalendar.js index aec742ae..4d7c0307 100644 --- a/src/DatePickerCalendar.js +++ b/src/DatePickerCalendar.js @@ -15,6 +15,7 @@ export default function DatePickerCalendar({ maximumDate, modifiers: receivedModifiers, modifiersClassNames, + monthFormat, weekdayFormat, touchDragEnabled }) { @@ -36,6 +37,7 @@ export default function DatePickerCalendar({ maximumDate={maximumDate} modifiers={modifiers} modifiersClassNames={modifiersClassNames} + monthFormat={monthFormat} weekdayFormat={weekdayFormat} touchDragEnabled={touchDragEnabled} /> @@ -52,6 +54,7 @@ DatePickerCalendar.propTypes = { maximumDate: instanceOf(Date), modifiers: objectOf(func), modifiersClassNames: objectOf(string), + monthFormat: string, weekdayFormat: string, touchDragEnabled: bool } diff --git a/website/examples/FormatsExample.js b/website/examples/FormatsExample.js new file mode 100644 index 00000000..d8bae829 --- /dev/null +++ b/website/examples/FormatsExample.js @@ -0,0 +1,61 @@ +import React, { useState } from 'react' +import { enUS } from 'date-fns/locale' +import { DatePicker } from '../../src' +import Example from './Example' + +const code = ` +import React, { useState } from 'react' +import { enUS } from 'date-fns/locale' +import { DatePicker } from 'react-nice-dates' +import 'react-nice-dates/build/style.css' + +export default function LocalesExample() { + const [date, setDate] = useState() + + return ( +
+

Month format:

+ + + {({ inputProps, focused }) => ( + + )} + + +

Weekday format:

+ + + {({ inputProps, focused }) => ( + + )} + +
+ ) +} +`; + +export default function FormatsExample() { + const [date, setDate] = useState() + + return ( + +

Month format:

+ + + {({ inputProps, focused }) => ( + + )} + + +
+ +

Weekday format:

+ + + {({ inputProps, focused }) => ( + + )} + +
+ ) +} diff --git a/website/examples/MonthReactElementExample.js b/website/examples/MonthReactElementExample.js new file mode 100644 index 00000000..4c879e9c --- /dev/null +++ b/website/examples/MonthReactElementExample.js @@ -0,0 +1,139 @@ +import React, { useEffect, useState } from 'react' +import { format, setYear, subDays, addYears } from 'date-fns' +import { enUS } from 'date-fns/locale' +import { DatePicker } from '../../src' +import Example from './Example' + +const code = ` +import React, { useEffect, useState } from 'react' +import { format, setYear, subDays, addYears } from 'date-fns' +import { enUS } from 'date-fns/locale' +import { DatePicker } from 'react-nice-dates' +import 'react-nice-dates/build/style.css' + +export default function LocalesExample() { + const [date, setDate] = useState() + + return ( +
+

Month format as React component:

+ + { + const [selectedYear, setSelectedYear] = useState(format(currentMonth, 'y')); + + useEffect(() => { + setSelectedYear(format(currentMonth, 'y')) + }, [currentMonth]) + + const handleInputBlur = () => { + if (selectedYear.match(/^\d{4}$/)) { + onMonthChange(setYear(currentMonth, selectedYear)) + } else { + setSelectedYear(format(currentMonth, 'y')) + } + } + + const handleInputChange = evt => { + if (evt.target.value.match(/^\d{4}$/)) { + onMonthChange(setYear(currentMonth, evt.target.value)) + } + setSelectedYear(evt.target.value) + } + + return ( + <> + {format(currentMonth, 'MMMM')} + {' '} + + +
+ + + {minimumDate && \`min date: \${format(minimumDate, 'yyyy/MM/dd', {locale: enUS})}\`} + {' '} + {maximumDate && \`max date: \${format(maximumDate, 'yyyy/MM/dd', {locale: enUS})}\`} + + + ) + }} + > + {({ inputProps, focused }) => ( + + )} +
+
+ ) +} +`; + +export default function MonthReactElementExample() { + const [date, setDate] = useState() + + return ( + +

Month format as React component:

+ + { + const [selectedYear, setSelectedYear] = useState(format(currentMonth, 'y')); + + useEffect(() => { + setSelectedYear(format(currentMonth, 'y')) + }, [currentMonth]) + + const handleInputBlur = () => { + if (selectedYear.match(/^\d{4}$/)) { + onMonthChange(setYear(currentMonth, selectedYear)) + } else { + setSelectedYear(format(currentMonth, 'y')) + } + } + + const handleInputChange = evt => { + if (evt.target.value.match(/^\d{4}$/)) { + onMonthChange(setYear(currentMonth, evt.target.value)) + } + setSelectedYear(evt.target.value) + } + + return ( + <> + {format(currentMonth, 'MMMM')} + {' '} + + +
+ + + {minimumDate && `min date: ${format(minimumDate, 'yyyy/MM/dd', {locale: enUS})}`} + {' '} + {maximumDate && `max date: ${format(maximumDate, 'yyyy/MM/dd', {locale: enUS})}`} + + + ) + }} + > + {({ inputProps, focused }) => ( + + )} +
+
+ ) +} diff --git a/website/index.js b/website/index.js index 1e3e7f04..ae121b10 100644 --- a/website/index.js +++ b/website/index.js @@ -7,6 +7,7 @@ import DateRangePickerCalendarExample from './examples/DateRangePickerCalendarEx import StandaloneInputExample from './examples/StandaloneInputExample' import DatePickerCalendarWithInputExample from './examples/DatePickerCalendarWithInputExample' import ModifiersExample from './examples/ModifiersExample' +import FormatsExample from './examples/FormatsExample' import LocalesExample from './examples/LocalesExample' import CalendarExample from './examples/CalendarExample' import CodeBlock from './CodeBlock' @@ -140,11 +141,20 @@ function App() { -

Localization

+

Dates format

As you might have noticed, React Nice Dates relies of the awesome date-fns{' '} - library as a peer dependency. All components require a locale prop, which must be a{' '} + library as a peer dependency. Thanks to it you can configure format of visible dates. +

+ + + +

Localization

+ +

+ As mentioned above, React Nice Dates is using under the hood date-fns. + All components require a locale prop, which must be a{' '} date-fns locale object of your desired language.

@@ -233,6 +243,7 @@ minimumDate: instanceOf(Date), // See Calendar props maximumDate: instanceOf(Date), // See Calendar props modifiers: objectOf(func), modifiersClassNames: objectOf(string), +monthFormat: string, // See Calendar props weekdayFormat: string, // See Calendar props touchDragEnabled: bool // See Calendar props `} /> @@ -272,6 +283,7 @@ minimumLength: number, // See DateRangePickerCalendar props maximumLength: number, // See DateRangePickerCalendar props modifiers: objectOf(func), modifiersClassNames: objectOf(string), +monthFormat: string, // See Calendar props weekdayFormat: string, // See Calendar props touchDragEnabled: bool // See Calendar props `} /> @@ -308,6 +320,7 @@ minimumDate: instanceOf(Date), // See Calendar props maximumDate: instanceOf(Date), // See Calendar props modifiers: objectOf(func), modifiersClassNames: objectOf(string), +monthFormat: string, // See Calendar props weekdayFormat: string, // See Calendar props touchDragEnabled: bool // See Calendar props`} /> @@ -333,6 +346,7 @@ minimumLength: number, // Minimum range selection length, defaults to 0 maximumLength: number, // Maximum range selection length, defaults to null modifiers: objectOf(func), modifiersClassNames: objectOf(string), +monthFormat: string, // See Calendar props weekdayFormat: string, // See Calendar props touchDragEnabled: bool // See Calendar props `} /> @@ -349,6 +363,7 @@ maximumDate: instanceOf(Date), // Days after maximumDate will be disabled modifiers: objectOf(func), modifiersClassNames: objectOf(string), month: instanceOf(Date), // Optional: Turns current month into a controlled prop +monthFormat: string, // Optional: allows month name to be dynamically formatted (ex. "GGGG yyyy, MMMM") onMonthChange: func, // Optional: Turns current month into a controlled prop onDayHover: func, onDayClick: func,