+
+
+ {
+ setCalendarContainerClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setBaseDayClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setDisabledClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setTodayClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setSelectedClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setSelectedStartClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setSelectedFullClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setSelectedEndClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setRangeClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setBtnClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setBtnActiveClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setBtnDisabledClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setBtnFullRoundClassName(e.target.value);
+ }}
+ />
+
+
+
+ {
+ setBtnContainerClassName(e.target.value);
+ }}
+ />
+
+
@@ -424,7 +633,7 @@ export default function Playground() {
}}
/>
-
+
diff --git a/src/components/Calendar/Days.tsx b/src/components/Calendar/Days.tsx
index 43f0b9b6..4a3f296f 100644
--- a/src/components/Calendar/Days.tsx
+++ b/src/components/Calendar/Days.tsx
@@ -1,10 +1,16 @@
import dayjs from "dayjs";
import isBetween from "dayjs/plugin/isBetween";
-import React, { useCallback, useContext } from "react";
+import React, { useCallback, useContext, useMemo } from "react";
import { BG_COLOR, TEXT_COLOR } from "../../constants";
import DatepickerContext from "../../contexts/DatepickerContext";
-import { formatDate, nextMonth, previousMonth, classNames as cn } from "../../helpers";
+import {
+ formatDate,
+ nextMonth,
+ previousMonth,
+ classNames as cn,
+ classNameOverloader
+} from "../../helpers";
import { Period } from "../../types";
dayjs.extend(isBetween);
@@ -38,20 +44,69 @@ const Days: React.FC
= ({
changeDayHover,
minDate,
maxDate,
- disabledDates
+ disabledDates,
+ baseDayClassName,
+ disabledClassName,
+ selectedClassName,
+ selectedStartClassName,
+ selectedFullClassName,
+ selectedEndClassName,
+ rangeClassName,
+ todayClassName
} = useContext(DatepickerContext);
+ const baseDayClassNameOverload = useMemo(() => {
+ const defaultBaseDayClassName =
+ "flex items-center justify-center w-12 h-12 md:w-10 md:h-10";
+ return classNameOverloader(defaultBaseDayClassName, baseDayClassName);
+ }, [baseDayClassName]);
+
+ const rangeClassNameOverload = useMemo(() => {
+ const defaultRangeClassName = `${BG_COLOR["100"][primaryColor]} dark:bg-white/10`;
+ return classNameOverloader(defaultRangeClassName, rangeClassName);
+ }, [rangeClassName, primaryColor]);
+
+ const selectedClassNameOverload = useMemo(() => {
+ const defaultSelectedClassName = `text-white font-medium ${BG_COLOR["500"][primaryColor]}`;
+ return classNameOverloader(defaultSelectedClassName, selectedClassName);
+ }, [selectedClassName, primaryColor]);
+
+ const selectedStartClassNameOverload = useMemo(() => {
+ const defaultSelectedStartClassName = "rounded-l-full";
+ return classNameOverloader(defaultSelectedStartClassName, selectedStartClassName);
+ }, [selectedStartClassName]);
+
+ const selectedFullClassNameOverload = useMemo(() => {
+ const defaultSelectedFullClassName = "rounded-full";
+ return classNameOverloader(defaultSelectedFullClassName, selectedFullClassName);
+ }, [selectedFullClassName]);
+
+ const selectedEndClassNameOverload = useMemo(() => {
+ const defaultSelectedEndClassName = "rounded-r-full";
+ return classNameOverloader(defaultSelectedEndClassName, selectedEndClassName);
+ }, [selectedEndClassName]);
+
+ const disabledClassNameOverload = useMemo(() => {
+ const defaultDisabledClassName = "line-through";
+ return classNameOverloader(defaultDisabledClassName, disabledClassName);
+ }, [disabledClassName]);
+
+ const todayClassNameOverload = useMemo(() => {
+ const defaultTodayClassName =
+ TEXT_COLOR["500"][primaryColor as keyof (typeof TEXT_COLOR)["500"]];
+ return classNameOverloader(defaultTodayClassName, todayClassName);
+ }, [todayClassName, primaryColor]);
+
// 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)))
- return TEXT_COLOR["500"][primaryColor as keyof (typeof TEXT_COLOR)["500"]];
+ if (formatDate(dayjs()) === formatDate(dayjs(itemDate))) return todayClassNameOverload;
return "";
},
- [calendarData.date, primaryColor]
+ [calendarData.date, todayClassNameOverload]
);
const activeDateData = useCallback(
@@ -60,18 +115,18 @@ const Days: React.FC = ({
let className = "";
if (dayjs(fullDay).isSame(period.start) && dayjs(fullDay).isSame(period.end)) {
- className = ` ${BG_COLOR["500"][primaryColor]} text-white font-medium rounded-full`;
+ className = ` ${selectedClassNameOverload} ${selectedFullClassNameOverload}`;
} else if (dayjs(fullDay).isSame(period.start)) {
- className = ` ${BG_COLOR["500"][primaryColor]} text-white font-medium ${
+ className = ` ${selectedClassNameOverload} ${
dayjs(fullDay).isSame(dayHover) && !period.end
- ? "rounded-full"
- : "rounded-l-full"
+ ? selectedFullClassNameOverload
+ : selectedStartClassNameOverload
}`;
} else if (dayjs(fullDay).isSame(period.end)) {
- className = ` ${BG_COLOR["500"][primaryColor]} text-white font-medium ${
+ className = ` ${selectedClassNameOverload} ${
dayjs(fullDay).isSame(dayHover) && !period.start
- ? "rounded-full"
- : "rounded-r-full"
+ ? selectedFullClassNameOverload
+ : selectedEndClassNameOverload
}`;
}
@@ -80,7 +135,16 @@ const Days: React.FC = ({
className: className
};
},
- [calendarData.date, dayHover, period.end, period.start, primaryColor]
+ [
+ calendarData.date,
+ dayHover,
+ period.end,
+ period.start,
+ selectedClassNameOverload,
+ selectedEndClassNameOverload,
+ selectedFullClassNameOverload,
+ selectedStartClassNameOverload
+ ]
);
const hoverClassByDay = useCallback(
@@ -92,9 +156,7 @@ const Days: React.FC = ({
if (period.start && period.end) {
if (dayjs(fullDay).isBetween(period.start, period.end, "day", "[)")) {
- return ` ${BG_COLOR["100"][primaryColor]} ${currentDateClass(
- day
- )} dark:bg-white/10`;
+ return ` ${rangeClassNameOverload} ${currentDateClass(day)}`;
}
}
@@ -103,27 +165,33 @@ const Days: React.FC = ({
}
if (period.start && dayjs(fullDay).isBetween(period.start, dayHover, "day", "[)")) {
- className = ` ${BG_COLOR["100"][primaryColor]} ${currentDateClass(
- day
- )} dark:bg-white/10`;
+ className = ` ${rangeClassNameOverload} ${currentDateClass(day)}`;
}
if (period.end && dayjs(fullDay).isBetween(dayHover, period.end, "day", "[)")) {
- className = ` ${BG_COLOR["100"][primaryColor]} ${currentDateClass(
- day
- )} dark:bg-white/10`;
+ className = ` ${rangeClassNameOverload} ${currentDateClass(day)}`;
}
if (dayHover === fullDay) {
- const bgColor = BG_COLOR["500"][primaryColor];
- className = ` transition-all duration-500 text-white font-medium ${bgColor} ${
- period.start ? "rounded-r-full" : "rounded-l-full"
+ console.log(period.start);
+ className = ` ${selectedClassNameOverload} transition-all duration-500 ${
+ period.start ? selectedEndClassNameOverload : selectedStartClassNameOverload
}`;
}
return className;
},
- [calendarData.date, currentDateClass, dayHover, period.end, period.start, primaryColor]
+ [
+ calendarData.date,
+ currentDateClass,
+ dayHover,
+ period.end,
+ period.start,
+ rangeClassNameOverload,
+ selectedClassNameOverload,
+ selectedStartClassNameOverload,
+ selectedEndClassNameOverload
+ ]
);
const isDateTooEarly = useCallback(
@@ -205,19 +273,28 @@ const Days: React.FC = ({
const buttonClass = useCallback(
(day: number, 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(
- baseClass,
+ baseDayClassNameOverload,
!activeDateData(day).active
? hoverClassByDay(day)
: activeDateData(day).className,
- isDateDisabled(day, type) && "line-through"
+ isDateDisabled(day, type) && disabledClassNameOverload
);
}
- return cn(baseClass, isDateDisabled(day, type) && "line-through", "text-gray-400");
+ return cn(
+ baseDayClassNameOverload,
+ isDateDisabled(day, type) && disabledClassNameOverload,
+ "text-gray-400"
+ );
},
- [activeDateData, hoverClassByDay, isDateDisabled]
+ [
+ activeDateData,
+ hoverClassByDay,
+ isDateDisabled,
+ disabledClassNameOverload,
+ baseDayClassNameOverload
+ ]
);
const checkIfHoverPeriodContainsDisabledPeriod = useCallback(
diff --git a/src/components/Calendar/index.tsx b/src/components/Calendar/index.tsx
index 4a374375..aa12d0ba 100644
--- a/src/components/Calendar/index.tsx
+++ b/src/components/Calendar/index.tsx
@@ -4,6 +4,7 @@ import React, { useCallback, useContext, useEffect, useMemo, useState } from "re
import { CALENDAR_SIZE, DATE_FORMAT } from "../../constants";
import DatepickerContext from "../../contexts/DatepickerContext";
import {
+ classNameOverloader,
formatDate,
getDaysInMonth,
getFirstDayInMonth,
@@ -59,7 +60,8 @@ const Calendar: React.FC = ({
asSingle,
i18n,
startWeekOn,
- input
+ input,
+ btnContainerClassName
} = useContext(DatepickerContext);
loadLanguageModule(i18n);
@@ -241,9 +243,16 @@ const Calendar: React.FC = ({
[maxDate]
);
+ const btnContainerClassNameOverride = useMemo(() => {
+ const defaultBtnContainerClassName =
+ "flex items-center space-x-1.5 border border-gray-300 dark:border-gray-700 rounded-md px-2 py-1.5";
+ console.log(btnContainerClassName);
+ return classNameOverloader(defaultBtnContainerClassName, btnContainerClassName);
+ }, [btnContainerClassName]);
+
return (
-
+
{!showMonths && !showYears && (
diff --git a/src/components/Datepicker.tsx b/src/components/Datepicker.tsx
index 54e90b78..22028056 100644
--- a/src/components/Datepicker.tsx
+++ b/src/components/Datepicker.tsx
@@ -7,7 +7,7 @@ import Input from "../components/Input";
import Shortcuts from "../components/Shortcuts";
import { COLORS, DATE_FORMAT, DEFAULT_COLOR, LANGUAGE } from "../constants";
import DatepickerContext from "../contexts/DatepickerContext";
-import { formatDate, nextMonth, previousMonth } from "../helpers";
+import { classNameOverloader, formatDate, nextMonth, previousMonth } from "../helpers";
import useOnClickOutside from "../hooks";
import { Period, DatepickerType, ColorKeys } from "../types";
@@ -30,6 +30,20 @@ const Datepicker: React.FC = ({
inputClassName = null,
containerClassName = null,
toggleClassName = null,
+ baseDayClassName = null,
+ calendarContainerClassName = null,
+ disabledClassName = null,
+ todayClassName = null,
+ selectedClassName = null,
+ selectedStartClassName = null,
+ selectedFullClassName = null,
+ selectedEndClassName = null,
+ rangeClassName = null,
+ btnClassName = null,
+ btnActiveClassName = null,
+ btnDisabledClassName = null,
+ btnFullRoundClassName = null,
+ btnContainerClassName = null,
toggleIcon = undefined,
displayFormat = DATE_FORMAT,
readOnly = false,
@@ -269,6 +283,19 @@ const Datepicker: React.FC = ({
inputClassName,
containerClassName,
toggleClassName,
+ baseDayClassName,
+ disabledClassName,
+ selectedStartClassName,
+ selectedFullClassName,
+ selectedEndClassName,
+ selectedClassName,
+ rangeClassName,
+ btnClassName,
+ btnActiveClassName,
+ btnDisabledClassName,
+ btnFullRoundClassName,
+ btnContainerClassName,
+ todayClassName,
toggleIcon,
readOnly,
displayFormat,
@@ -302,6 +329,19 @@ const Datepicker: React.FC = ({
inputClassName,
containerClassName,
toggleClassName,
+ baseDayClassName,
+ disabledClassName,
+ selectedStartClassName,
+ selectedFullClassName,
+ selectedEndClassName,
+ selectedClassName,
+ rangeClassName,
+ btnClassName,
+ btnActiveClassName,
+ btnDisabledClassName,
+ btnFullRoundClassName,
+ btnContainerClassName,
+ todayClassName,
toggleIcon,
readOnly,
displayFormat,
@@ -320,13 +360,15 @@ const Datepicker: React.FC = ({
const containerClassNameOverload = useMemo(() => {
const defaultContainerClassName = "relative w-full text-gray-700";
- return typeof containerClassName === "function"
- ? containerClassName(defaultContainerClassName)
- : typeof containerClassName === "string" && containerClassName !== ""
- ? containerClassName
- : defaultContainerClassName;
+ return classNameOverloader(defaultContainerClassName, containerClassName);
}, [containerClassName]);
+ const calendarContainerClassNameOverload = useMemo(() => {
+ const defaultCalendarContainerClassName =
+ "mt-2.5 shadow-sm border border-gray-300 px-1 py-0.5 bg-white dark:bg-slate-800 dark:text-white dark:border-slate-600 rounded-lg";
+ return classNameOverloader(defaultCalendarContainerClassName, calendarContainerClassName);
+ }, [calendarContainerClassName]);
+
return (
@@ -338,7 +380,7 @@ const Datepicker: React.FC
= ({
>
-
+
{showShortcuts &&
}
diff --git a/src/components/Input.tsx b/src/components/Input.tsx
index 38fc856e..5ef393c0 100644
--- a/src/components/Input.tsx
+++ b/src/components/Input.tsx
@@ -3,7 +3,7 @@ import React, { useCallback, useContext, useEffect, useRef } from "react";
import { BORDER_COLOR, DATE_FORMAT, RING_COLOR } from "../constants";
import DatepickerContext from "../contexts/DatepickerContext";
-import { dateIsValid, parseFormattedDate } from "../helpers";
+import { classNameOverloader, dateIsValid, parseFormattedDate } from "../helpers";
import ToggleButton from "./ToggleButton";
@@ -57,11 +57,7 @@ const Input: React.FC
= (e: Props) => {
const defaultInputClassName = `relative transition-all duration-300 py-2.5 pl-4 pr-14 w-full border-gray-300 dark:bg-slate-800 dark:text-white/80 dark:border-slate-600 rounded-lg tracking-wide font-light text-sm placeholder-gray-400 bg-white focus:ring disabled:opacity-40 disabled:cursor-not-allowed ${border} ${ring}`;
- return typeof inputClassName === "function"
- ? inputClassName(defaultInputClassName)
- : typeof inputClassName === "string" && inputClassName !== ""
- ? inputClassName
- : defaultInputClassName;
+ return classNameOverloader(defaultInputClassName, inputClassName);
}, [inputRef, classNames, primaryColor, inputClassName]);
const handleInputChange = useCallback(
@@ -155,11 +151,7 @@ const Input: React.FC = (e: Props) => {
const defaultToggleClassName =
"absolute right-0 h-full px-3 text-gray-400 focus:outline-none disabled:opacity-40 disabled:cursor-not-allowed";
- return typeof toggleClassName === "function"
- ? toggleClassName(defaultToggleClassName)
- : typeof toggleClassName === "string" && toggleClassName !== ""
- ? toggleClassName
- : defaultToggleClassName;
+ return classNameOverloader(defaultToggleClassName, toggleClassName);
}, [toggleClassName, buttonRef, classNames]);
// UseEffects && UseLayoutEffect
diff --git a/src/components/utils.tsx b/src/components/utils.tsx
index 6bdb31a7..49d61f9d 100644
--- a/src/components/utils.tsx
+++ b/src/components/utils.tsx
@@ -1,8 +1,10 @@
-import React, { useCallback, useContext } from "react";
+import React, { useCallback, useContext, useMemo } from "react";
import { BG_COLOR, BORDER_COLOR, BUTTON_COLOR, RING_COLOR } from "../constants";
import DatepickerContext from "../contexts/DatepickerContext";
+import { classNameOverloader } from "helpers";
+
interface IconProps {
className: string;
}
@@ -176,24 +178,53 @@ export const RoundedButton: React.FC