(
+ options?.defaultDate !== null,
+ );
+ const selectedMonth = selectedDate.getMonth();
+ const selectedYear = selectedDate.getFullYear();
- const getFormattedDate = (date: Date | number, formatOptions?: Intl.DateTimeFormatOptions | undefined | null) => formatDate(options?.language ? options?.language : "en", date, formatOptions)
+ const changeSelectedDate = (
+ action: 'prev' | 'next' | 'date' | 'today',
+ date: Date,
+ ) => {
+ if (options?.maxDate && date > options.maxDate) {
+ return;
+ }
+ if (options?.minDate && date < options.minDate) {
+ return;
+ }
+ if (options?.disabledDates && options.disabledDates.indexOf(date) >= 0) {
+ return;
+ }
+ setSelectedDate(date);
+ setShowSelectedDate(true);
+ if (options?.autoHide && view === 'days' && action === 'date') {
+ setShow(false);
+ }
+ if (onChange) {
+ onChange(date);
+ }
+ };
- return (
-
- {children}
-
- )
-}
+ const getFormattedDate = (
+ date: Date | number,
+ formatOptions?: Intl.DateTimeFormatOptions | undefined | null,
+ ) =>
+ formatDate(
+ options?.language ? options?.language : 'en',
+ date,
+ formatOptions,
+ );
+
+ return (
+
+ {children}
+
+ );
+};
-export default DatePickerProvider
+export default DatePickerProvider;
diff --git a/src/Components/Views/Days.tsx b/src/Components/Views/Days.tsx
index 03e5909..4614fa3 100644
--- a/src/Components/Views/Days.tsx
+++ b/src/Components/Views/Days.tsx
@@ -1,60 +1,87 @@
-import React, { useContext } from "react"
-import { addDays } from "../../Utils/date"
-import { DatePickerContext } from "../DatePickerProvider"
-import { twMerge } from "tailwind-merge"
+import clsx from 'clsx';
+import React, { useContext } from 'react';
+import { addDays } from '../../Utils/date';
+import { DatePickerContext } from '../DatePickerProvider';
interface IDaysProps {
- start: number
+ start: number;
}
const Days = ({ start }: IDaysProps) => {
- const { selectedDate, changeSelectedDate, showSelectedDate, getFormattedDate, options } = useContext(DatePickerContext)
-
- const startOfWeek = (new Date(start).getDay() + 6) % 7;
- const weekDays = options.weekDays || [];
- const sortedWeekDays = weekDays.slice(startOfWeek).concat(weekDays.slice(0, startOfWeek));
+ const {
+ selectedDate,
+ changeSelectedDate,
+ showSelectedDate,
+ getFormattedDate,
+ options,
+ } = useContext(DatePickerContext);
- return (
- <>
-
- {sortedWeekDays.map((day, index) => (
-
- {day}
-
- ))}
-
-
- {[...Array(42)].map((_date, index) => {
- const current = addDays(start, index)
- const day = getFormattedDate(current, { day: "numeric" })
- const month = getFormattedDate(current, { month: "long" })
- const year = getFormattedDate(current, { year: "numeric" })
- return (
-
0 && getFormattedDate(selectedDate) === getFormattedDate(current)
- ? twMerge("bg-blue-700 text-white hover:bg-blue-600", options?.theme?.selected)
- : ""
- } ${
- month == getFormattedDate(selectedDate, { month: "long" }) && year == getFormattedDate(selectedDate, { year: "numeric" })
- ? twMerge("text-gray-900", options?.theme?.text)
- : twMerge("text-gray-500", options?.theme?.disabledText)
- } ${(options?.minDate && new Date(current) < options?.minDate) || (options?.disabledDates && options.disabledDates.indexOf(new Date(current)) >= 0) ? twMerge("text-gray-500", options?.theme?.disabledText) : ""} ${
- (options?.maxDate && new Date(current) > options?.maxDate) || (options?.disabledDates && options.disabledDates.indexOf(new Date(current)) >= 0) ? twMerge("text-gray-500", options?.theme?.disabledText) : ""
- }
+ const startOfWeek = (new Date(start).getDay() + 6) % 7;
+ const weekDays = options.weekDays || [];
+ const sortedWeekDays = weekDays
+ .slice(startOfWeek)
+ .concat(weekDays.slice(0, startOfWeek));
+
+ return (
+ <>
+
+ {sortedWeekDays.map((day, index) => (
+
+ {day}
+
+ ))}
+
+
+ {[...Array(42)].map((_date, index) => {
+ const current = addDays(start, index);
+ const day = getFormattedDate(current, { day: 'numeric' });
+ const month = getFormattedDate(current, { month: 'long' });
+ const year = getFormattedDate(current, { year: 'numeric' });
+ return (
+ 0 &&
+ getFormattedDate(selectedDate) === getFormattedDate(current)
+ ? clsx(
+ 'bg-blue-700 text-white hover:bg-blue-600',
+ options?.theme?.selected,
+ )
+ : ''
+ } ${
+ month == getFormattedDate(selectedDate, { month: 'long' }) &&
+ year == getFormattedDate(selectedDate, { year: 'numeric' })
+ ? clsx('text-gray-900', options?.theme?.text)
+ : clsx('text-gray-500', options?.theme?.disabledText)
+ } ${
+ (options?.minDate && new Date(current) < options?.minDate) ||
+ (options?.disabledDates &&
+ options.disabledDates.indexOf(new Date(current)) >= 0)
+ ? clsx('text-gray-500', options?.theme?.disabledText)
+ : ''
+ } ${
+ (options?.maxDate && new Date(current) > options?.maxDate) ||
+ (options?.disabledDates &&
+ options.disabledDates.indexOf(new Date(current)) >= 0)
+ ? clsx('text-gray-500', options?.theme?.disabledText)
+ : ''
+ }
`}
- onClick={() => {
- changeSelectedDate("date", new Date(current))
- }}
- >
- {day}
-
- )
- })}
-
- >
- )
-}
+ onClick={() => {
+ changeSelectedDate('date', new Date(current));
+ }}
+ >
+ {day}
+
+ );
+ })}
+
+ >
+ );
+};
-export default Days
+export default Days;
diff --git a/src/Components/Views/Decades.tsx b/src/Components/Views/Decades.tsx
index 7455272..ff0bb0d 100644
--- a/src/Components/Views/Decades.tsx
+++ b/src/Components/Views/Decades.tsx
@@ -1,37 +1,96 @@
-import React, { useContext } from "react"
-import { addYears, startOfYearPeriod } from "../../Utils/date"
-import { DatePickerContext } from "../DatePickerProvider"
-import { twMerge } from "tailwind-merge"
+import clsx from 'clsx';
+import React, { useContext } from 'react';
+import { addYears, startOfYearPeriod } from '../../Utils/date';
+import { DatePickerContext } from '../DatePickerProvider';
const Decades = () => {
- const { selectedDate, showSelectedDate, changeSelectedDate, setView, getFormattedDate, options } = useContext(DatePickerContext)
- return (
-
- {[...Array(12)].map((_year, index) => {
- const first = startOfYearPeriod(selectedDate, 100)
- const year = first - 10 + index * 10
- return (
- 0 && Number(getFormattedDate(selectedDate, { year: "numeric" })) === year
- ? twMerge("bg-blue-700 text-white hover:bg-blue-600", options?.theme?.selected)
- : ""
- } ${index == 0 || index == 11 ? twMerge("text-gray-500", options?.theme?.disabledText) : twMerge("text-gray-900", options?.theme?.text)}
- ${options?.minDate && year < Number(getFormattedDate(options?.minDate, { year: "numeric" })) ? twMerge("text-gray-500", options?.theme?.disabledText) : ""}
- ${options?.maxDate && year > Number(getFormattedDate(options?.maxDate, { year: "numeric" })) ? twMerge("text-gray-500", options?.theme?.disabledText) : ""}
- `}
- onClick={() => {
- changeSelectedDate("date", new Date(addYears(selectedDate, year - selectedDate.getFullYear())))
- setView("years")
- }}
- >
- {year}
-
- )
- })}
-
- )
-}
-
-export default Decades
+ const {
+ selectedDate,
+ showSelectedDate,
+ changeSelectedDate,
+ setView,
+ getFormattedDate,
+ options,
+ } = useContext(DatePickerContext);
+
+ const isDecadeDisabled = (year: number) => {
+ const { minDate, maxDate } = options;
+
+ if (
+ minDate &&
+ year < Number(getFormattedDate(minDate, { year: 'numeric' }))
+ ) {
+ return true;
+ }
+
+ if (
+ maxDate &&
+ year > Number(getFormattedDate(maxDate, { year: 'numeric' }))
+ ) {
+ return true;
+ }
+
+ return false;
+ };
+
+ const first = startOfYearPeriod(selectedDate, 100);
+
+ return (
+
+ {[...Array(12)].map((_year, index) => {
+ const year = first - 10 + index * 10;
+ const disabled = isDecadeDisabled(year) || index === 0 || index === 11;
+
+ const selectedClass = clsx(
+ 'bg-blue-700 text-white hover:bg-blue-600',
+ options?.theme?.selected,
+ );
+
+ const enabledClass = clsx(
+ 'cursor-pointer text-gray-900 hover:bg-gray-100 dark:text-white dark:hover:bg-gray-600',
+ options?.theme?.text,
+ );
+
+ const disabledClass = clsx(
+ 'cursor-not-allowed text-gray-500',
+ options?.theme?.disabledText,
+ );
+
+ return (
+ 0 &&
+ Number(
+ getFormattedDate(selectedDate, { year: 'numeric' }),
+ ) === year &&
+ !disabled,
+ },
+ )}
+ onClick={() => {
+ if (!disabled) {
+ changeSelectedDate(
+ 'date',
+ new Date(
+ addYears(selectedDate, year - selectedDate.getFullYear()),
+ ),
+ );
+ setView('years');
+ }
+ }}
+ >
+ {year}
+
+ );
+ })}
+
+ );
+};
+
+export default Decades;
diff --git a/src/Components/Views/Months.tsx b/src/Components/Views/Months.tsx
index ca46af9..c03af48 100644
--- a/src/Components/Views/Months.tsx
+++ b/src/Components/Views/Months.tsx
@@ -1,33 +1,96 @@
-import React, { useContext } from "react"
-import { addMonths } from "../../Utils/date"
-import { DatePickerContext } from "../DatePickerProvider"
-import { twMerge } from "tailwind-merge"
+import clsx from 'clsx';
+import React, { useContext } from 'react';
+import { addMonths } from '../../Utils/date';
+import { DatePickerContext } from '../DatePickerProvider';
const Months = () => {
- const { selectedDate, showSelectedDate, changeSelectedDate, getFormattedDate, setView, options } = useContext(DatePickerContext)
- return (
-
- {[...Array(12)].map((_month, index) => {
- const month = getFormattedDate(new Date(selectedDate.getFullYear(), index), { month: "short" })
- return (
- 0 && getFormattedDate(selectedDate, { month: "short" }) === month
- ? twMerge("bg-blue-700 text-white hover:bg-blue-600", options?.theme?.selected)
- : ""
- } ${twMerge(options?.theme?.text)}`}
- onClick={() => {
- changeSelectedDate("date", new Date(addMonths(selectedDate, index - selectedDate.getMonth())))
- setView("days")
- }}
- >
- {month}
-
- )
- })}
-
- )
-}
-
-export default Months
+ const {
+ selectedDate,
+ showSelectedDate,
+ changeSelectedDate,
+ getFormattedDate,
+ setView,
+ options,
+ } = useContext(DatePickerContext);
+
+ const isMonthDisabled = (monthIndex: number) => {
+ const { minDate, maxDate } = options;
+ const currentYear = selectedDate.getFullYear();
+ const monthDate = new Date(currentYear, monthIndex, 1);
+
+ if (
+ minDate &&
+ monthDate < new Date(minDate.getFullYear(), minDate.getMonth(), 1)
+ ) {
+ return true;
+ }
+
+ if (
+ maxDate &&
+ monthDate > new Date(maxDate.getFullYear(), maxDate.getMonth(), 1)
+ ) {
+ return true;
+ }
+
+ return false;
+ };
+
+ return (
+
+ {[...Array(12)].map((_month, index) => {
+ const month = getFormattedDate(
+ new Date(selectedDate.getFullYear(), index),
+ { month: 'short' },
+ );
+ const disabled = isMonthDisabled(index);
+ const selectedClass = clsx(
+ 'bg-blue-700 text-white hover:bg-blue-600',
+ options?.theme?.selected,
+ );
+
+ const enabledClass = clsx(
+ 'cursor-pointer text-gray-900 hover:bg-gray-100 dark:text-white dark:hover:bg-gray-600',
+ options?.theme?.text,
+ );
+
+ const disabledClass = clsx(
+ 'cursor-not-allowed text-gray-500',
+ options?.theme?.disabledText,
+ );
+ return (
+ 0 &&
+ getFormattedDate(selectedDate, { month: 'short' }) ===
+ month &&
+ !disabled,
+ },
+ )}
+ onClick={() => {
+ if (!disabled) {
+ changeSelectedDate(
+ 'date',
+ new Date(
+ addMonths(selectedDate, index - selectedDate.getMonth()),
+ ),
+ );
+ setView('days');
+ }
+ }}
+ >
+ {month}
+
+ );
+ })}
+
+ );
+};
+
+export default Months;
diff --git a/src/Components/Views/Years.tsx b/src/Components/Views/Years.tsx
index 39e92b0..0cbcde6 100644
--- a/src/Components/Views/Years.tsx
+++ b/src/Components/Views/Years.tsx
@@ -1,34 +1,90 @@
-import React, { useContext } from "react"
-import { addYears, startOfYearPeriod } from "../../Utils/date"
-import { DatePickerContext } from "../DatePickerProvider"
-import { twMerge } from "tailwind-merge"
+import clsx from 'clsx';
+import React, { useContext } from 'react';
+import { addYears, startOfYearPeriod } from '../../Utils/date';
+import { DatePickerContext } from '../DatePickerProvider';
const Years = () => {
- const { selectedDate, showSelectedDate, changeSelectedDate, setView, getFormattedDate, options } = useContext(DatePickerContext)
- return (
-
- {[...Array(12)].map((_year, index) => {
- const first = startOfYearPeriod(selectedDate, 10)
- const year = first - 1 + index * 1
- return (
- 0 && Number(getFormattedDate(selectedDate, { year: "numeric" })) === year
- ? twMerge("bg-blue-700 text-white hover:bg-blue-600", options?.theme?.selected)
- : ""
- } ${index == 0 || index == 11 ? twMerge("text-gray-500", options?.theme?.disabledText) : twMerge("text-gray-900", options?.theme?.text)}`}
- onClick={() => {
- changeSelectedDate("date", new Date(addYears(selectedDate, year - selectedDate.getFullYear())))
- setView("months")
- }}
- >
- {year}
-
- )
- })}
-
- )
-}
-
-export default Years
+ const {
+ selectedDate,
+ showSelectedDate,
+ changeSelectedDate,
+ setView,
+ getFormattedDate,
+ options,
+ } = useContext(DatePickerContext);
+
+ const isYearDisabled = (year: number) => {
+ const { maxDate, minDate } = options;
+
+ if (minDate && year < minDate.getFullYear()) {
+ return true;
+ }
+
+ if (maxDate && year > maxDate.getFullYear()) {
+ return true;
+ }
+
+ return false;
+ };
+
+ const first = startOfYearPeriod(selectedDate, 10);
+
+ return (
+
+ {[...Array(12)].map((_year, index) => {
+ const year = first - 1 + index * 1;
+ const disabled = isYearDisabled(year);
+
+ const selectedClass = clsx(
+ 'bg-blue-700 text-white hover:bg-blue-600',
+ options?.theme?.selected,
+ );
+
+ const enabledClass = clsx(
+ 'cursor-pointer text-gray-900 hover:bg-gray-100 dark:text-white dark:hover:bg-gray-600',
+ options?.theme?.text,
+ );
+
+ const disabledClass = clsx(
+ 'cursor-not-allowed text-gray-500',
+ options?.theme?.disabledText,
+ );
+
+ return (
+ 0 &&
+ Number(
+ getFormattedDate(selectedDate, { year: 'numeric' }),
+ ) === year &&
+ !disabled,
+ },
+ )}
+ onClick={() => {
+ if (!disabled && index !== 0 && index !== 11) {
+ changeSelectedDate(
+ 'date',
+ new Date(
+ addYears(selectedDate, year - selectedDate.getFullYear()),
+ ),
+ );
+ setView('months');
+ }
+ }}
+ >
+ {year}
+
+ );
+ })}
+
+ );
+};
+
+export default Years;
diff --git a/src/Utils/date.ts b/src/Utils/date.ts
index 2840634..acc4474 100644
--- a/src/Utils/date.ts
+++ b/src/Utils/date.ts
@@ -1,72 +1,99 @@
-import { Views } from "../Components/DatePickerProvider"
+import { Views } from '../Components/DatePickerProvider';
-export const firstDateOfMonth = (selectedYear: number, selectedMonth: number, date: number): number => {
- const newDate = new Date(0)
- newDate.setFullYear(selectedYear, selectedMonth, date)
- return newDate.setHours(0, 0, 0, 0)
-}
+export const firstDateOfMonth = (
+ selectedYear: number,
+ selectedMonth: number,
+ date: number,
+): number => {
+ const newDate = new Date(0);
+ newDate.setFullYear(selectedYear, selectedMonth, date);
+ return newDate.setHours(0, 0, 0, 0);
+};
export const addDays = (date: number, amount: number): number => {
- const newDate = new Date(date)
- return newDate.setDate(newDate.getDate() + amount)
-}
+ const newDate = new Date(date);
+ return newDate.setDate(newDate.getDate() + amount);
+};
export const dayDiff = (day: number, from: number): number => {
- return (day - from + 7) % 7
-}
+ return (day - from + 7) % 7;
+};
-export const dayOfTheWeekOf = (baseDate: number, dayOfWeek: number, weekStart: number = 0): number => {
- const baseDay = new Date(baseDate).getDay()
- return addDays(baseDate, dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart))
-}
+export const dayOfTheWeekOf = (
+ baseDate: number,
+ dayOfWeek: number,
+ weekStart: number = 0,
+): number => {
+ const baseDay = new Date(baseDate).getDay();
+ return addDays(
+ baseDate,
+ dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart),
+ );
+};
export const addMonths = (date: Date, amount: number): number => {
- const newDate = date
- const monthsToSet = newDate.getMonth() + amount
- let expectedMonth = monthsToSet % 12
- if (expectedMonth < 0) {
- expectedMonth += 12
- }
+ // NOTE: THE FIX FOR THE TAILWIND-DATEPICKER-REACT LIB
+ // BEFORE IT WAS USING THE DATE DIRECTLY
+ const newDate = new Date(date.getTime());
+ const monthsToSet = newDate.getMonth() + amount;
+ let expectedMonth = monthsToSet % 12;
+ if (expectedMonth < 0) {
+ expectedMonth += 12;
+ }
- const time = newDate.setMonth(monthsToSet)
- return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time
-}
+ const time = newDate.setMonth(monthsToSet);
+ return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time;
+};
export const addYears = (date: Date, amount: number): number => {
- const newDate = date
- const expectedMonth = newDate.getMonth()
- const time = newDate.setFullYear(newDate.getFullYear() + amount)
- return expectedMonth === 1 && newDate.getMonth() === 2 ? newDate.setDate(0) : time
-}
+ // NOTE: THE FIX FOR THE TAILWIND-DATEPICKER-REACT LIB
+ // BEFORE IT WAS USING THE DATE DIRECTLY
+ const newDate = new Date(date.getTime());
+ const expectedMonth = newDate.getMonth();
+ const time = newDate.setFullYear(newDate.getFullYear() + amount);
+ return expectedMonth === 1 && newDate.getMonth() === 2
+ ? newDate.setDate(0)
+ : time;
+};
-export const getFormattedDate = (language: string, date: Date | number, options?: Intl.DateTimeFormatOptions | null | undefined): string => {
- let defaultOptions: Intl.DateTimeFormatOptions = {
- day: "numeric",
- month: "long",
- year: "numeric",
- }
-
- if (options) defaultOptions = options
+export const getFormattedDate = (
+ language: string,
+ date: Date | number,
+ options?: Intl.DateTimeFormatOptions | null | undefined,
+): string => {
+ let defaultOptions: Intl.DateTimeFormatOptions = {
+ day: 'numeric',
+ month: 'long',
+ year: 'numeric',
+ };
- return new Intl.DateTimeFormat(language, defaultOptions).format(date)
-}
+ if (options) {
+ defaultOptions = options;
+ }
-export const goToPrevNext = (view: Views, date: Date, direction: number): number => {
- switch (view) {
- case "days":
- return addMonths(date, direction)
- case "months":
- return addYears(date, direction)
- case "years":
- return addYears(date, direction * 10)
- case "decades":
- return addYears(date, direction * 100)
- default:
- return addYears(date, direction * 10)
- }
-}
+ return new Intl.DateTimeFormat(language, defaultOptions).format(date);
+};
+
+export const goToPrevNext = (
+ view: Views,
+ date: Date,
+ direction: number,
+): number => {
+ switch (view) {
+ case 'days':
+ return addMonths(date, direction);
+ case 'months':
+ return addYears(date, direction);
+ case 'years':
+ return addYears(date, direction * 10);
+ case 'decades':
+ return addYears(date, direction * 100);
+ default:
+ return addYears(date, direction * 10);
+ }
+};
export const startOfYearPeriod = (date: Date, years: number): number => {
- const year = date.getFullYear()
- return Math.floor(year / years) * years
-}
+ const year = date.getFullYear();
+ return Math.floor(year / years) * years;
+};
diff --git a/yarn.lock b/yarn.lock
index 76f58a3..84e06c5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -211,6 +211,11 @@ chokidar@^3.5.2:
optionalDependencies:
fsevents "~2.3.2"
+clsx@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
+ integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
+
commander@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
@@ -444,11 +449,6 @@ supports-color@^5.5.0:
dependencies:
has-flag "^3.0.0"
-tailwind-merge@^1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-1.6.1.tgz#36bd3a63f59860354432a0a7b7ebd04a14141035"
- integrity sha512-wC/tta/BxpmE/4Qc7WX0OK+ajhetgpJZ+IfQMpUBOv4nWjlxQKbq/FBkcZDX7fVGq2RJBnWa3WzsPz5mUe+g7g==
-
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"