// NOTE: This file should not be edited
-// see https://nextjs.org/docs/basic-features/typescript for more information.
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/next.config.js b/next.config.js
deleted file mode 100644
index eda88d1a..00000000
--- a/next.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/** @type {import('next').NextConfig} */
-const nextConfig = {
- reactStrictMode: true
-};
-
-module.exports = nextConfig;
diff --git a/next.config.mjs b/next.config.mjs
new file mode 100644
index 00000000..4678774e
--- /dev/null
+++ b/next.config.mjs
@@ -0,0 +1,4 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {};
+
+export default nextConfig;
diff --git a/package.json b/package.json
index ac9c06cf..870c5241 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-tailwindcss-datepicker",
- "version": "1.6.6",
+ "version": "2.0.0",
"description": "A modern React Datepicker using Tailwind CSS 3",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
@@ -9,17 +9,15 @@
"license": "MIT",
"scripts": {
"watch": "rollup -c -w",
- "clean": "rm -rf dist",
- "lint": "eslint --ignore-path .gitignore .",
- "lint:fix": "eslint --ignore-path .gitignore --fix .",
- "pret": "prettier -c .",
- "pret:fix": "prettier --ignore-path .gitignore --config ./.prettierrc --write './**/*.{js,jsx,ts,tsx,css,md,json}'",
- "code-style": "npm run pret && npm run lint",
- "code-style:fix": "npm run pret:fix && npm run pret:fix",
- "build": "npm run code-style && npm run clean && rollup -c",
- "pub": "npm run build && npm publish",
+ "clean": "rm -rf dist .rollup.cache tsconfig.rollup.tsbuildinfo",
+ "lint": "eslint .",
+ "lint:fix": "eslint --fix .",
+ "pret:fix": "prettier --write .",
+ "format": "npm run pret:fix && npm run lint:fix",
+ "build": "npm run lint && npm run clean && rollup -c rollup.config.js --bundleConfigAsCjs",
+ "pub": "npm run build && np --no-tests",
"dev": "next dev -p 8888",
- "prepare": "husky install"
+ "prepare": "husky"
},
"repository": {
"type": "git",
@@ -38,45 +36,51 @@
"tailwind-daterange-picker"
],
"peerDependencies": {
- "dayjs": "^1.11.6",
- "react": "^17.0.2 || ^18.2.0"
+ "dayjs": "^1.11.12",
+ "react": "^17.0.2 || ^18.2.0 || ^19.0.0"
},
"devDependencies": {
- "@rollup/plugin-commonjs": "^24.0.1",
- "@rollup/plugin-node-resolve": "^15.0.1",
- "@rollup/plugin-typescript": "^11.0.0",
- "@tailwindcss/forms": "^0.5.3",
- "@types/node": "18.14.5",
- "@types/react": "^18.0.21",
- "@typescript-eslint/eslint-plugin": "^5.45.0",
- "@typescript-eslint/parser": "^5.45.0",
- "autoprefixer": "^10.4.13",
- "dayjs": "^1.11.7",
- "eslint": "^8.29.0",
- "eslint-config-next": "^13.1.1",
- "eslint-config-prettier": "^8.5.0",
- "eslint-plugin-import": "^2.26.0",
- "eslint-plugin-prettier": "^4.2.1",
- "eslint-plugin-react": "^7.31.11",
- "eslint-plugin-react-hooks": "^4.6.0",
- "husky": "^8.0.0",
- "lint-staged": "^13.2.3",
- "next": "^13.1.1",
- "postcss": "^8.4.19",
- "prettier": "^2.8.0",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "rollup": "^2.77.2",
- "tailwindcss": "^3.2.4",
- "tslib": "^2.4.0",
- "typescript": "^4.8.4"
+ "@rollup/plugin-commonjs": "^28.0.2",
+ "@rollup/plugin-node-resolve": "^16.0.0",
+ "@rollup/plugin-typescript": "^12.1.2",
+ "@tailwindcss/forms": "^0.5.7",
+ "@types/node": "^22.3.0",
+ "@types/react": "^19.0.8",
+ "@typescript-eslint/eslint-plugin": "^8.22.0",
+ "@typescript-eslint/parser": "^8.22.0",
+ "autoprefixer": "^10.4.20",
+ "dayjs": "^1.11.12",
+ "eslint": "^8.57.0",
+ "eslint-config-next": "^15.1.6",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-import": "^2.29.1",
+ "eslint-plugin-prettier": "^5.2.1",
+ "eslint-plugin-react": "^7.35.0",
+ "eslint-plugin-react-hooks": "^5.1.0",
+ "eslint-plugin-react-refresh": "^0.4.18",
+ "husky": "^9.1.4",
+ "lint-staged": "^15.2.9",
+ "next": "^15.1.6",
+ "pinst": "^3.0.0",
+ "postcss": "^8.4.41",
+ "prettier": "^3.3.3",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "rollup": "^4.34.0",
+ "tailwindcss": "^3.4.10",
+ "tslib": "^2.8.1",
+ "typescript": "^5.5.4"
},
"lint-staged": {
"*.{ts,tsx}": [
- "npm run lint"
+ "eslint",
+ "prettier --write"
],
- "*.{ts,tsx,css,scss,md}": [
- "npm run pret:fix"
+ "*.{css,scss,json,md}": [
+ "prettier --write"
]
- }
+ },
+ "files": [
+ "dist"
+ ]
}
diff --git a/pages/_app.js b/pages/_app.js
deleted file mode 100644
index c9bee70c..00000000
--- a/pages/_app.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import "../styles/globals.css";
-
-function MyApp({ Component, pageProps }) {
- return
;
-}
-
-export default MyApp;
diff --git a/rollup.config.js b/rollup.config.js
index 8217c424..ad9af56f 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -2,27 +2,22 @@ import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
-const packageJson = require("./package.json");
-const options = require("./tsconfig.json");
-
module.exports = {
input: "src/index.tsx",
output: [
{
- file: packageJson.main,
+ file: "dist/index.cjs.js",
format: "cjs",
- exports: "auto",
sourcemap: true,
inlineDynamicImports: true
},
{
- file: packageJson.module,
+ file: "dist/index.esm.js",
format: "esm",
- exports: "auto",
sourcemap: true,
inlineDynamicImports: true
}
],
external: ["react", "dayjs"],
- plugins: [resolve(), commonjs(), typescript({ ...options.compilerOptions, jsx: "react" })]
+ plugins: [resolve(), commonjs(), typescript({ tsconfig: "./tsconfig.rollup.json" })]
};
diff --git a/src/components/Calendar/Days.tsx b/src/components/Calendar/Days.tsx
index 43f0b9b6..10a0dbe6 100644
--- a/src/components/Calendar/Days.tsx
+++ b/src/components/Calendar/Days.tsx
@@ -1,34 +1,34 @@
-import dayjs from "dayjs";
-import isBetween from "dayjs/plugin/isBetween";
-import React, { useCallback, useContext } from "react";
+import { useCallback, useContext } from "react";
import { BG_COLOR, TEXT_COLOR } from "../../constants";
import DatepickerContext from "../../contexts/DatepickerContext";
-import { formatDate, nextMonth, previousMonth, classNames as cn } from "../../helpers";
+import { classNames as cn } from "../../helpers";
+import {
+ dateIsAfter,
+ dateIsBefore,
+ dateIsBetween,
+ dateIsSame,
+ dateIsSameOrAfter,
+ dateIsSameOrBefore,
+ isCurrentDay
+} from "../../libs/date";
import { Period } from "../../types";
-dayjs.extend(isBetween);
-
interface Props {
- calendarData: {
- date: dayjs.Dayjs;
- days: {
- previous: number[];
- current: number[];
- next: number[];
- };
+ days: {
+ previous: Date[];
+ current: Date[];
+ next: Date[];
};
- onClickPreviousDays: (day: number) => void;
- onClickDay: (day: number) => void;
- onClickNextDays: (day: number) => void;
+ onClickPreviousDays: (day: Date) => void;
+ onClickDay: (day: Date) => void;
+ onClickNextDays: (day: Date) => void;
}
-const Days: React.FC
= ({
- calendarData,
- onClickPreviousDays,
- onClickDay,
- onClickNextDays
-}) => {
+const Days = (props: Props) => {
+ // Props
+ const { days, onClickPreviousDays, onClickDay, onClickNextDays } = props;
+
// Contexts
const {
primaryColor,
@@ -43,55 +43,50 @@ const Days: React.FC = ({
// Functions
const currentDateClass = useCallback(
- (item: number) => {
- const itemDate = `${calendarData.date.year()}-${calendarData.date.month() + 1}-${
- item >= 10 ? item : "0" + item
- }`;
- if (formatDate(dayjs()) === formatDate(dayjs(itemDate)))
+ (day: Date) => {
+ if (isCurrentDay(day))
return TEXT_COLOR["500"][primaryColor as keyof (typeof TEXT_COLOR)["500"]];
return "";
},
- [calendarData.date, primaryColor]
+ [primaryColor]
);
const activeDateData = useCallback(
- (day: number) => {
- const fullDay = `${calendarData.date.year()}-${calendarData.date.month() + 1}-${day}`;
+ (day: Date) => {
let className = "";
- if (dayjs(fullDay).isSame(period.start) && dayjs(fullDay).isSame(period.end)) {
+ const dayIsSameStart = period.start && dateIsSame(day, period.start, "date");
+ const dayIsSameEnd = period.end && dateIsSame(day, period.end, "date");
+ const dayIsSameHoverDay = dayHover && dateIsSame(day, dayHover, "date");
+
+ if (dayIsSameStart && dayIsSameEnd) {
className = ` ${BG_COLOR["500"][primaryColor]} text-white font-medium rounded-full`;
- } else if (dayjs(fullDay).isSame(period.start)) {
+ } else if (dayIsSameStart) {
className = ` ${BG_COLOR["500"][primaryColor]} text-white font-medium ${
- dayjs(fullDay).isSame(dayHover) && !period.end
- ? "rounded-full"
- : "rounded-l-full"
+ dayIsSameHoverDay && !period.end ? "rounded-full" : "rounded-l-full"
}`;
- } else if (dayjs(fullDay).isSame(period.end)) {
+ } else if (dayIsSameEnd) {
className = ` ${BG_COLOR["500"][primaryColor]} text-white font-medium ${
- dayjs(fullDay).isSame(dayHover) && !period.start
- ? "rounded-full"
- : "rounded-r-full"
+ dayIsSameHoverDay && !period.start ? "rounded-full" : "rounded-r-full"
}`;
}
return {
- active: dayjs(fullDay).isSame(period.start) || dayjs(fullDay).isSame(period.end),
+ active: dayIsSameStart || dayIsSameEnd,
className: className
};
},
- [calendarData.date, dayHover, period.end, period.start, primaryColor]
+ [dayHover, period.end, period.start, primaryColor]
);
const hoverClassByDay = useCallback(
- (day: number) => {
+ (day: Date) => {
let className = currentDateClass(day);
- const fullDay = `${calendarData.date.year()}-${calendarData.date.month() + 1}-${
- day >= 10 ? day : "0" + day
- }`;
if (period.start && period.end) {
- if (dayjs(fullDay).isBetween(period.start, period.end, "day", "[)")) {
+ if (
+ dateIsBetween(day, period.start, period.end, "day", { start: true, end: false })
+ ) {
return ` ${BG_COLOR["100"][primaryColor]} ${currentDateClass(
day
)} dark:bg-white/10`;
@@ -102,19 +97,25 @@ const Days: React.FC = ({
return className;
}
- if (period.start && dayjs(fullDay).isBetween(period.start, dayHover, "day", "[)")) {
+ if (
+ period.start &&
+ dateIsBetween(day, period.start, dayHover, "day", { start: true, end: false })
+ ) {
className = ` ${BG_COLOR["100"][primaryColor]} ${currentDateClass(
day
)} dark:bg-white/10`;
}
- if (period.end && dayjs(fullDay).isBetween(dayHover, period.end, "day", "[)")) {
+ if (
+ period.end &&
+ dateIsBetween(day, dayHover, period.end, "day", { start: true, end: false })
+ ) {
className = ` ${BG_COLOR["100"][primaryColor]} ${currentDateClass(
day
)} dark:bg-white/10`;
}
- if (dayHover === fullDay) {
+ if (dateIsSame(dayHover, day, "date")) {
const bgColor = BG_COLOR["500"][primaryColor];
className = ` transition-all duration-500 text-white font-medium ${bgColor} ${
period.start ? "rounded-r-full" : "rounded-l-full"
@@ -123,61 +124,32 @@ const Days: React.FC = ({
return className;
},
- [calendarData.date, currentDateClass, dayHover, period.end, period.start, primaryColor]
+ [currentDateClass, dayHover, period.end, period.start, primaryColor]
);
const isDateTooEarly = useCallback(
- (day: number, type: "current" | "previous" | "next") => {
- if (!minDate) {
- return false;
- }
- const object = {
- previous: previousMonth(calendarData.date),
- current: calendarData.date,
- next: nextMonth(calendarData.date)
- };
- const newDate = object[type as keyof typeof object];
- const formattedDate = newDate.set("date", day);
- return dayjs(formattedDate).isSame(dayjs(minDate), "day")
- ? false
- : dayjs(formattedDate).isBefore(dayjs(minDate));
+ (day: Date) => {
+ if (!minDate) return false;
+
+ return dateIsBefore(day, minDate, "date");
},
- [calendarData.date, minDate]
+ [minDate]
);
const isDateTooLate = useCallback(
- (day: number, type: "current" | "previous" | "next") => {
- if (!maxDate) {
- return false;
- }
- const object = {
- previous: previousMonth(calendarData.date),
- current: calendarData.date,
- next: nextMonth(calendarData.date)
- };
- const newDate = object[type as keyof typeof object];
- const formattedDate = newDate.set("date", day);
- return dayjs(formattedDate).isSame(dayjs(maxDate), "day")
- ? false
- : dayjs(formattedDate).isAfter(dayjs(maxDate));
+ (day: Date) => {
+ if (!maxDate) return false;
+
+ return dateIsAfter(day, maxDate, "date");
},
- [calendarData.date, maxDate]
+ [maxDate]
);
const isDateDisabled = useCallback(
- (day: number, type: "current" | "previous" | "next") => {
- if (isDateTooEarly(day, type) || isDateTooLate(day, type)) {
+ (day: Date) => {
+ if (isDateTooEarly(day) || isDateTooLate(day)) {
return true;
}
- const object = {
- previous: previousMonth(calendarData.date),
- current: calendarData.date,
- next: nextMonth(calendarData.date)
- };
- const newDate = object[type as keyof typeof object];
- const formattedDate = `${newDate.year()}-${newDate.month() + 1}-${
- day >= 10 ? day : "0" + day
- }`;
if (!disabledDates || (Array.isArray(disabledDates) && !disabledDates.length)) {
return false;
@@ -186,25 +158,24 @@ const Days: React.FC = ({
let matchingCount = 0;
disabledDates?.forEach(dateRange => {
if (
- dayjs(formattedDate).isAfter(dateRange.startDate) &&
- dayjs(formattedDate).isBefore(dateRange.endDate)
- ) {
- matchingCount++;
- }
- if (
- dayjs(formattedDate).isSame(dateRange.startDate) ||
- dayjs(formattedDate).isSame(dateRange.endDate)
+ dateRange.startDate &&
+ dateRange.endDate &&
+ dateIsBetween(day, dateRange.startDate, dateRange.endDate, "date", {
+ start: true,
+ end: true
+ })
) {
matchingCount++;
}
});
+
return matchingCount > 0;
},
- [calendarData.date, isDateTooEarly, isDateTooLate, disabledDates]
+ [isDateTooEarly, isDateTooLate, disabledDates]
);
const buttonClass = useCallback(
- (day: number, type: "current" | "next" | "previous") => {
+ (day: Date, type: "current" | "next" | "previous") => {
const baseClass = "flex items-center justify-center w-12 h-12 lg:w-10 lg:h-10";
if (type === "current") {
return cn(
@@ -212,10 +183,10 @@ const Days: React.FC = ({
!activeDateData(day).active
? hoverClassByDay(day)
: activeDateData(day).className,
- isDateDisabled(day, type) && "line-through"
+ isDateDisabled(day) && "line-through"
);
}
- return cn(baseClass, isDateDisabled(day, type) && "line-through", "text-gray-400");
+ return cn(baseClass, isDateDisabled(day) && "line-through", "text-gray-400");
},
[activeDateData, hoverClassByDay, isDateDisabled]
);
@@ -225,10 +196,11 @@ const Days: React.FC = ({
if (!Array.isArray(disabledDates)) {
return false;
}
+
for (let i = 0; i < disabledDates.length; i++) {
if (
- dayjs(hoverPeriod.start).isBefore(disabledDates[i].startDate) &&
- dayjs(hoverPeriod.end).isAfter(disabledDates[i].endDate)
+ dateIsSameOrBefore(hoverPeriod.start, disabledDates[i].startDate, "date") &&
+ dateIsSameOrAfter(hoverPeriod.end, disabledDates[i].endDate, "date")
) {
return true;
}
@@ -238,27 +210,15 @@ const Days: React.FC = ({
[disabledDates]
);
- const getMetaData = useCallback(() => {
- return {
- previous: previousMonth(calendarData.date),
- current: calendarData.date,
- next: nextMonth(calendarData.date)
- };
- }, [calendarData.date]);
-
const hoverDay = useCallback(
- (day: number, type: string) => {
- const object = getMetaData();
- const newDate = object[type as keyof typeof object];
- const newHover = `${newDate.year()}-${newDate.month() + 1}-${
- day >= 10 ? day : "0" + day
- }`;
-
+ (day: Date) => {
if (period.start && !period.end) {
- const hoverPeriod = { ...period, end: newHover };
- if (dayjs(newHover).isBefore(dayjs(period.start))) {
- hoverPeriod.start = newHover;
+ const hoverPeriod = { ...period, end: day };
+
+ if (dateIsBefore(day, period.start, "date")) {
+ hoverPeriod.start = day;
hoverPeriod.end = period.start;
+
if (!checkIfHoverPeriodContainsDisabledPeriod(hoverPeriod)) {
changePeriod({
start: null,
@@ -266,16 +226,18 @@ const Days: React.FC = ({
});
}
}
+
if (!checkIfHoverPeriodContainsDisabledPeriod(hoverPeriod)) {
- changeDayHover(newHover);
+ changeDayHover(day);
}
}
if (!period.start && period.end) {
- const hoverPeriod = { ...period, start: newHover };
- if (dayjs(newHover).isAfter(dayjs(period.end))) {
+ const hoverPeriod = { ...period, start: day };
+
+ if (dateIsAfter(day, period.end, "date")) {
hoverPeriod.start = period.end;
- hoverPeriod.end = newHover;
+ hoverPeriod.end = day;
if (!checkIfHoverPeriodContainsDisabledPeriod(hoverPeriod)) {
changePeriod({
start: period.end,
@@ -284,21 +246,15 @@ const Days: React.FC = ({
}
}
if (!checkIfHoverPeriodContainsDisabledPeriod(hoverPeriod)) {
- changeDayHover(newHover);
+ changeDayHover(day);
}
}
},
- [
- changeDayHover,
- changePeriod,
- checkIfHoverPeriodContainsDisabledPeriod,
- getMetaData,
- period
- ]
+ [changeDayHover, changePeriod, checkIfHoverPeriodContainsDisabledPeriod, period]
);
const handleClickDay = useCallback(
- (day: number, type: "previous" | "current" | "next") => {
+ (day: Date, type: "previous" | "current" | "next") => {
function continueClick() {
if (type === "previous") {
onClickPreviousDays(day);
@@ -314,16 +270,12 @@ const Days: React.FC = ({
}
if (disabledDates?.length) {
- const object = getMetaData();
- const newDate = object[type as keyof typeof object];
- const clickDay = `${newDate.year()}-${newDate.month() + 1}-${
- day >= 10 ? day : "0" + day
- }`;
+ const daySelectedIsSameHoverDay = dayHover && dateIsSame(day, dayHover, "date");
- if (period.start && !period.end) {
- dayjs(clickDay).isSame(dayHover) && continueClick();
- } else if (!period.start && period.end) {
- dayjs(clickDay).isSame(dayHover) && continueClick();
+ if (period.start && !period.end && daySelectedIsSameHoverDay) {
+ continueClick();
+ } else if (!period.start && period.end && daySelectedIsSameHoverDay) {
+ continueClick();
} else {
continueClick();
}
@@ -334,7 +286,6 @@ const Days: React.FC = ({
[
dayHover,
disabledDates?.length,
- getMetaData,
onClickDay,
onClickNextDays,
onClickPreviousDays,
@@ -345,48 +296,48 @@ const Days: React.FC = ({
return (
- {calendarData.days.previous.map((item, index) => (
+ {days.previous.map((item, index) => (
))}
- {calendarData.days.current.map((item, index) => (
+ {days.current.map((item, index) => (
))}
- {calendarData.days.next.map((item, index) => (
+ {days.next.map((item, index) => (
))}
diff --git a/src/components/Calendar/Months.tsx b/src/components/Calendar/Months.tsx
index ebd1ce94..0ec2aba5 100644
--- a/src/components/Calendar/Months.tsx
+++ b/src/components/Calendar/Months.tsx
@@ -1,19 +1,24 @@
-import dayjs from "dayjs";
-import React, { useContext } from "react";
+import { useContext, useEffect } from "react";
import { MONTHS } from "../../constants";
import DatepickerContext from "../../contexts/DatepickerContext";
-import { loadLanguageModule } from "../../helpers";
-import { RoundedButton } from "../utils";
+import { dateFormat, loadLanguageModule } from "../../libs/date";
+import RoundedButton from "../RoundedButton";
interface Props {
currentMonth: number;
clickMonth: (month: number) => void;
}
-const Months: React.FC = ({ currentMonth, clickMonth }) => {
+const Months = (props: Props) => {
+ const { currentMonth, clickMonth } = props;
+
const { i18n } = useContext(DatepickerContext);
- loadLanguageModule(i18n);
+
+ useEffect(() => {
+ loadLanguageModule(i18n);
+ }, [i18n]);
+
return (
{MONTHS.map(item => (
@@ -25,7 +30,7 @@ const Months: React.FC
= ({ currentMonth, clickMonth }) => {
}}
active={currentMonth === item}
>
- <>{dayjs(`2022-${item}-01`).locale(i18n).format("MMM")}>
+ {dateFormat(new Date(2022, item - 1, 1), "MMM", i18n)}
))}
diff --git a/src/components/Calendar/Week.tsx b/src/components/Calendar/Week.tsx
index 45e957c2..bcb452ff 100644
--- a/src/components/Calendar/Week.tsx
+++ b/src/components/Calendar/Week.tsx
@@ -1,13 +1,17 @@
-import dayjs from "dayjs";
-import React, { useContext, useMemo } from "react";
+import { useContext, useEffect, useMemo } from "react";
import { DAYS } from "../../constants";
import DatepickerContext from "../../contexts/DatepickerContext";
-import { loadLanguageModule, shortString, ucFirst } from "../../helpers";
+import { shortString, ucFirst } from "../../helpers";
+import { dateFormat, loadLanguageModule } from "../../libs/date";
-const Week: React.FC = () => {
+const Week = () => {
const { i18n, startWeekOn } = useContext(DatepickerContext);
- loadLanguageModule(i18n);
+
+ useEffect(() => {
+ loadLanguageModule(i18n);
+ }, [i18n]);
+
const startDateModifier = useMemo(() => {
if (startWeekOn) {
switch (startWeekOn) {
@@ -38,9 +42,11 @@ const Week: React.FC = () => {
{ucFirst(
shortString(
- dayjs(`2022-11-${6 + (item + startDateModifier)}`)
- .locale(i18n)
- .format("ddd")
+ dateFormat(
+ new Date(2022, 10, 6 + item + startDateModifier),
+ "ddd",
+ i18n
+ ) || ""
)
)}
diff --git a/src/components/Calendar/Years.tsx b/src/components/Calendar/Years.tsx
index 0bbef7b5..5980bb25 100644
--- a/src/components/Calendar/Years.tsx
+++ b/src/components/Calendar/Years.tsx
@@ -1,7 +1,7 @@
-import React, { useContext } from "react";
+import { useContext, useMemo } from "react";
import { generateArrayNumber } from "../../helpers";
-import { RoundedButton } from "../utils";
+import RoundedButton from "../RoundedButton";
import DatepickerContext from "contexts/DatepickerContext";
@@ -13,31 +13,40 @@ interface Props {
clickYear: (data: number) => void;
}
-const Years: React.FC = ({ year, currentYear, minYear, maxYear, clickYear }) => {
+const Years = (props: Props) => {
+ const { year, currentYear, minYear, maxYear, clickYear } = props;
+
const { dateLooking } = useContext(DatepickerContext);
- let startDate = 0;
- let endDate = 0;
-
- switch (dateLooking) {
- case "backward":
- startDate = year - 11;
- endDate = year;
- break;
- case "middle":
- startDate = year - 4;
- endDate = year + 7;
- break;
- case "forward":
- default:
- startDate = year;
- endDate = year + 11;
- break;
- }
+ const date = useMemo(() => {
+ let start: number;
+ let end: number;
+
+ switch (dateLooking) {
+ case "backward":
+ start = year - 11;
+ end = year;
+ break;
+ case "middle":
+ start = year - 4;
+ end = year + 7;
+ break;
+ case "forward":
+ default:
+ start = year;
+ end = year + 11;
+ break;
+ }
+
+ return {
+ start,
+ end
+ };
+ }, [dateLooking, year]);
return (
- {generateArrayNumber(startDate, endDate).map((item, index) => (
+ {generateArrayNumber(date.start, date.end).map((item, index) => (
void;
onClickNext: () => void;
changeMonth: (month: number) => void;
changeYear: (year: number) => void;
}
-const Calendar: React.FC = ({
- date,
- minDate,
- maxDate,
- onClickPrevious,
- onClickNext,
- changeMonth,
- changeYear
-}) => {
+const Calendar = (props: Props) => {
+ // Props
+ const { date, minDate, maxDate, onClickPrevious, onClickNext, changeMonth, changeYear } = props;
+
// Contexts
const {
period,
@@ -66,32 +64,15 @@ const Calendar: React.FC = ({
// States
const [showMonths, setShowMonths] = useState(false);
const [showYears, setShowYears] = useState(false);
- const [year, setYear] = useState(date.year());
- // Functions
- const previous = useCallback(() => {
- return getLastDaysInMonth(
- previousMonth(date),
- getNumberOfDay(getFirstDayInMonth(date).ddd, startWeekOn)
- );
- }, [date, startWeekOn]);
-
- const current = useCallback(() => {
- return getDaysInMonth(formatDate(date));
- }, [date]);
-
- const next = useCallback(() => {
- return getFirstDaysInMonth(
- previousMonth(date),
- CALENDAR_SIZE - (previous().length + current().length)
- );
- }, [current, date, previous]);
+ const [year, setYear] = useState(date.getFullYear());
+ // Functions
const hideMonths = useCallback(() => {
- showMonths && setShowMonths(false);
+ if (showMonths) setShowMonths(false);
}, [showMonths]);
const hideYears = useCallback(() => {
- showYears && setShowYears(false);
+ if (showYears) setShowYears(false);
}, [showYears]);
const clickMonth = useCallback(
@@ -115,27 +96,25 @@ const Calendar: React.FC = ({
);
const clickDay = useCallback(
- (day: number, month = date.month() + 1, year = date.year()) => {
- const fullDay = `${year}-${month}-${day}`;
+ (day: Date, after?: () => void) => {
let newStart;
let newEnd = null;
- function chosePeriod(start: string, end: string) {
- const ipt = input?.current;
+ function chosePeriod(start: Date, end: Date) {
changeDatepickerValue(
{
- startDate: dayjs(start).format(DATE_FORMAT),
- endDate: dayjs(end).format(DATE_FORMAT)
+ startDate: start,
+ endDate: end
},
- ipt
+ input
);
+
hideDatepicker();
}
if (period.start && period.end) {
- if (changeDayHover) {
- changeDayHover(null);
- }
+ changeDayHover(null);
+
changePeriod({
start: null,
end: null
@@ -144,30 +123,30 @@ const Calendar: React.FC = ({
if ((!period.start && !period.end) || (period.start && period.end)) {
if (!period.start && !period.end) {
- changeDayHover(fullDay);
+ changeDayHover(day);
}
- newStart = fullDay;
+
+ newStart = day;
+
if (asSingle) {
- newEnd = fullDay;
- chosePeriod(fullDay, fullDay);
+ newEnd = day;
+ if (!showFooter) {
+ chosePeriod(day, day);
+ }
}
} else {
if (period.start && !period.end) {
// start not null
// end null
- const condition =
- dayjs(fullDay).isSame(dayjs(period.start)) ||
- dayjs(fullDay).isAfter(dayjs(period.start));
- newStart = condition ? period.start : fullDay;
- newEnd = condition ? fullDay : period.start;
+ const condition = dateIsSameOrAfter(day, period.start, "date");
+ newStart = condition ? period.start : day;
+ newEnd = condition ? day : period.start;
} else {
// Start null
// End not null
- const condition =
- dayjs(fullDay).isSame(dayjs(period.end)) ||
- dayjs(fullDay).isBefore(dayjs(period.end));
- newStart = condition ? fullDay : period.start;
- newEnd = condition ? period.end : fullDay;
+ const condition = dateIsSameOrBefore(day, period.end, "date");
+ newStart = condition ? day : period.start;
+ newEnd = condition ? period.end : day;
}
if (!showFooter) {
@@ -183,13 +162,18 @@ const Calendar: React.FC = ({
end: newEnd
});
}
+
+ if (after) {
+ setTimeout(() => {
+ after();
+ }, 50);
+ }
},
[
asSingle,
changeDatepickerValue,
changeDayHover,
changePeriod,
- date,
hideDatepicker,
period.end,
period.start,
@@ -199,47 +183,60 @@ const Calendar: React.FC = ({
);
const clickPreviousDays = useCallback(
- (day: number) => {
- const newDate = previousMonth(date);
- clickDay(day, newDate.month() + 1, newDate.year());
- onClickPrevious();
+ (day: Date) => {
+ clickDay(day, () => {
+ onClickPrevious();
+ });
},
- [clickDay, date, onClickPrevious]
+ [clickDay, onClickPrevious]
);
const clickNextDays = useCallback(
- (day: number) => {
- const newDate = nextMonth(date);
- clickDay(day, newDate.month() + 1, newDate.year());
- onClickNext();
+ (day: Date) => {
+ clickDay(day, () => {
+ onClickNext();
+ });
},
- [clickDay, date, onClickNext]
+ [clickDay, onClickNext]
);
// UseEffects & UseLayoutEffect
useEffect(() => {
- setYear(date.year());
+ setYear(date.getFullYear());
}, [date]);
// Variables
const calendarData = useMemo(() => {
+ const firstDateCurrentMonth = firstDayOfMonth(date);
+ const lastDateCurrentMonth = endDayOfMonth(date);
+
+ const startWeekOnIndex = weekDayStringToIndex(startWeekOn || START_WEEK);
+
+ const previous = previousDaysInWeek(firstDateCurrentMonth, startWeekOnIndex);
+ const current = allDaysInMonth(date);
+ const next = nextDaysInWeek(lastDateCurrentMonth, startWeekOnIndex);
+
+ const remainingDaysLength =
+ CALENDAR_SIZE - (previous.length + current.length + next.length);
+
+ if (remainingDaysLength > 0) {
+ const lastNextDate = next[next.length - 1] || current[current.length - 1];
+ next.push(...getNextDates(lastNextDate, remainingDaysLength));
+ }
+
return {
- date: date,
- days: {
- previous: previous(),
- current: current(),
- next: next()
- }
+ previous: previous,
+ current: current,
+ next: next
};
- }, [current, date, next, previous]);
- const minYear = React.useMemo(
- () => (minDate && dayjs(minDate).isValid() ? dayjs(minDate).year() : null),
- [minDate]
- );
- const maxYear = React.useMemo(
- () => (maxDate && dayjs(maxDate).isValid() ? dayjs(maxDate).year() : null),
- [maxDate]
- );
+ }, [date, startWeekOn]);
+
+ const years = useMemo(() => {
+ return {
+ min: minDate && dateIsValid(minDate) ? minDate.getFullYear() : null,
+ max: maxDate && dateIsValid(maxDate) ? maxDate.getFullYear() : null
+ };
+ }, [maxDate, minDate]);
return (
@@ -257,7 +254,7 @@ const Calendar: React.FC
= ({
{
- setYear(year - 12);
+ setYear(year - NUMBER_YEARS_SHOW);
}}
>
@@ -273,7 +270,7 @@ const Calendar: React.FC = ({
hideYears();
}}
>
- <>{calendarData.date.locale(i18n).format("MMM")}>
+ {dateFormat(date, "MMM", i18n)}
@@ -284,7 +281,7 @@ const Calendar: React.FC = ({
hideMonths();
}}
>
- <>{calendarData.date.year()}>
+ <>{date.getFullYear()}>