Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
- ✅ TypeScript support
- ✅ Localization(i18n)
- ✅ Date formatting
- ⬜ Disable specific dates
- ✅ Disable specific dates
- ✅ Minimum Date and Maximum Date
- ⬜ Custom shortcuts

## Documentation
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-tailwindcss-datepicker",
"version": "1.3.3",
"name": "nloomis_react-tailwindcss-datepicker",
"version": "1.9.0",
"description": "A modern React Datepicker using Tailwind CSS 3",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
Expand All @@ -16,6 +16,7 @@
"pret:fix": "prettier -w .",
"format": "prettier --write './**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc",
"build": "npm run pret && npm run lint && npm run clean && rollup -c",
"pub": "npm run build && npm publish",
"dev": "next dev -p 8888"
},
"repository": {
Expand Down
113 changes: 112 additions & 1 deletion pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ export default function Playground() {
const [containerClassName, setContainerClassName] = useState("");
const [displayFormat, setDisplayFormat] = useState("YYYY-MM-DD");
const [readOnly, setReadOnly] = useState(false);
const [startFrom, setStartFrom] = useState("2023-03-01");
const [startFrom, setStartFrom] = useState("2023-01-02");
const [minDate, setMinDate] = useState("");
const [maxDate, setMaxDate] = useState("");
const [disabledDates, setDisabledDates] = useState([]);
const [newDisabledDates, setNewDisabledDates] = useState({ startDate: "", endDate: "" });

return (
<div className="px-4 py-8">
Expand Down Expand Up @@ -58,6 +62,9 @@ export default function Playground() {
containerClassName={containerClassName}
displayFormat={displayFormat}
readOnly={readOnly}
minDate={minDate}
maxDate={maxDate}
disabledDates={disabledDates}
/>
</div>

Expand Down Expand Up @@ -207,6 +214,19 @@ export default function Playground() {
}}
/>
</div>
<div className="mb-2">
<label className="block" htmlFor="minDate">
Minimum Date
</label>
<input
className="rounded border px-4 py-2 w-full border-gray-200"
id="minDate"
value={minDate}
onChange={e => {
setMinDate(e.target.value);
}}
/>
</div>
</div>
<div className="w-full sm:w-1/3 pr-2 flex flex-col">
<div className="mb-2">
Expand Down Expand Up @@ -261,6 +281,97 @@ export default function Playground() {
}}
/>
</div>
<div className="mb-2">
<label className="block" htmlFor="maxDate">
Maximum Date
</label>
<input
className="rounded border px-4 py-2 w-full border-gray-200"
id="maxDate"
value={maxDate}
onChange={e => {
setMaxDate(e.target.value);
}}
/>
</div>
</div>
<div className="w-full grid sm:grid-cols-3">
<div className="sm:col-start-2 sm:col-span-2 p-2 border-t grid grid-cols-2">
<h1 className="mb-2 text-lg font-semibold text-center col-span-3">
Disable Dates
</h1>
<div className="mb-2 sm:col-span-2 mr-2">
<label className="block" htmlFor="startDate">
Start Date
</label>
<input
className="rounded border px-4 py-2 border-gray-200 sm:w-full w-3/4"
id="startDate"
value={newDisabledDates.startDate}
onChange={e => {
setNewDisabledDates(prev => {
return {
...prev,
startDate: e.target.value
};
});
}}
/>
</div>
<div className="mb-2">
<label className="block" htmlFor="endDate">
End Date
</label>
<input
className="rounded border px-4 py-2 border-gray-200 sm:w-full w-3/4"
id="endDate"
value={newDisabledDates.endDate}
onChange={e => {
setNewDisabledDates(prev => {
return {
...prev,
endDate: e.target.value
};
});
}}
/>
</div>
<div className="mb-2 col-span-3">
<button
onClick={() => {
if (
newDisabledDates.startDate !== "" &&
newDisabledDates.endDate !== ""
) {
setDisabledDates(prev => [...prev, newDisabledDates]);
setNewDisabledDates({ startDate: "", endDate: "" });
}
}}
className="w-full bg-black text-white text-lg text-center p-2 rounded-lg"
>
Add
</button>
</div>
<div className="mb-2 grid col-span-3 grid-col-2">
{disabledDates.map((range, index) => (
<div className="mb-2 p-2" key={index}>
<button
className="bg-red-500 text-white text-center rounded-xl p-2"
onClick={() => {
setDisabledDates(
disabledDates.filter(r => r !== range)
);
}}
>
Delete
</button>
<span className="pl-2">
{range.startDate} - {range.endDate}
</span>
</div>
))}
</div>
</div>
</div>
</div>
<div className="flex flex-row flex-wrap items-center justify-center w-full">
Expand Down
122 changes: 110 additions & 12 deletions src/components/Calendar/Days.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import React, { useCallback, useContext } from "react";

import { BG_COLOR } from "../../constants";
import DatepickerContext from "../../contexts/DatepickerContext";
import { formatDate, getTextColorByPrimaryColor, nextMonth, previousMonth } from "../../helpers";
import {
formatDate,
getTextColorByPrimaryColor,
nextMonth,
previousMonth,
classNames as cn
} from "../../helpers";

const isBetween = require("dayjs/plugin/isBetween");
dayjs.extend(isBetween);
Expand All @@ -29,8 +35,16 @@ const Days: React.FC<Props> = ({
onClickNextDays
}) => {
// Contexts
const { primaryColor, period, changePeriod, dayHover, changeDayHover } =
useContext(DatepickerContext);
const {
primaryColor,
period,
changePeriod,
dayHover,
changeDayHover,
minDate,
maxDate,
disabledDates
} = useContext(DatepickerContext);

// Functions
const currentDateClass = useCallback(
Expand Down Expand Up @@ -139,16 +153,97 @@ const Days: React.FC<Props> = ({
[calendarData.date, currentDateClass, dayHover, period.end, period.start, primaryColor]
);

const buttonCass = useCallback(
(day: number) => {
const baseClass = "flex items-center justify-center w-12 h-12 lg:w-10 lg:h-10";
return `${baseClass}${
!activeDateData(day).active
? ` ${hoverClassByDay(day)}`
: activeDateData(day).className
const isDateTooEarly = useCallback(
(day: number, type: string) => {
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 newHover = `${newDate.year()}-${newDate.month() + 1}-${
day >= 10 ? day : "0" + day
}`;
return dayjs(newHover).isSame(dayjs(minDate))
? false
: dayjs(newHover).isBefore(dayjs(minDate));
},
[calendarData.date, minDate]
);

const isDateTooLate = useCallback(
(day: number, type: string) => {
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 newHover = `${newDate.year()}-${newDate.month() + 1}-${
day >= 10 ? day : "0" + day
}`;
return dayjs(newHover).isSame(maxDate)
? false
: dayjs(newHover).isAfter(dayjs(maxDate));
},
[calendarData.date, maxDate]
);

const isDateDisabled = useCallback(
(day: number, type: string) => {
if (isDateTooEarly(day, type) || isDateTooLate(day, type)) {
return true;
}
const object = {
previous: previousMonth(calendarData.date),
current: calendarData.date,
next: nextMonth(calendarData.date)
};
const newDate = object[type as keyof typeof object];
const newHover = `${newDate.year()}-${newDate.month() + 1}-${
day >= 10 ? day : "0" + day
}`;

if (!disabledDates || disabledDates?.length <= 0) {
return false;
}

let matchingCount = 0;
disabledDates?.forEach(dateRange => {
if (
dayjs(newHover).isAfter(dateRange.startDate) &&
dayjs(newHover).isBefore(dateRange.endDate)
) {
matchingCount++;
}
if (
dayjs(newHover).isSame(dateRange.startDate) ||
dayjs(newHover).isSame(dateRange.endDate)
) {
matchingCount++;
}
});
return matchingCount > 0;
},
[calendarData.date, isDateTooEarly, isDateTooLate]
);

const buttonClass = useCallback(
(day: number, type: string) => {
const baseClass = "flex items-center justify-center w-12 h-12 lg:w-10 lg:h-10";
return cn(
baseClass,
!activeDateData(day).active ? hoverClassByDay(day) : activeDateData(day).className,
isDateDisabled(day, type) && "line-through"
);
},
[activeDateData, hoverClassByDay]
[activeDateData, hoverClassByDay, isDateDisabled]
);

const hoverDay = useCallback(
Expand Down Expand Up @@ -192,6 +287,7 @@ const Days: React.FC<Props> = ({
<button
type="button"
key={index}
disabled={isDateDisabled(item, "previous")}
className="flex items-center justify-center text-gray-400 h-12 w-12 lg:w-10 lg:h-10"
onClick={() => onClickPreviousDays(item)}
onMouseOver={() => {
Expand All @@ -206,7 +302,8 @@ const Days: React.FC<Props> = ({
<button
type="button"
key={index}
className={buttonCass(item)}
disabled={isDateDisabled(item, "current")}
className={`${buttonClass(item, "current")}`}
onClick={() => {
onClickDay(item);
}}
Expand All @@ -222,6 +319,7 @@ const Days: React.FC<Props> = ({
<button
type="button"
key={index}
disabled={isDateDisabled(index, "previous")}
className="flex items-center justify-center text-gray-400 h-12 w-12 lg:w-10 lg:h-10"
onClick={() => {
onClickNextDays(item);
Expand Down
8 changes: 4 additions & 4 deletions src/components/Calendar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ const Calendar: React.FC<Props> = ({
);
}, [current, date, previous]);

const hiddeMonths = useCallback(() => {
const hideMonths = useCallback(() => {
if (showMonths) {
setShowMonths(false);
}
}, [showMonths]);

const hiddeYears = useCallback(() => {
const hideYears = useCallback(() => {
if (showYears) {
setShowYears(false);
}
Expand Down Expand Up @@ -254,7 +254,7 @@ const Calendar: React.FC<Props> = ({
<RoundedButton
onClick={() => {
setShowMonths(!showMonths);
hiddeYears();
hideYears();
}}
>
<>{shortString(calendarData.date.locale(i18n).format("MMM"))}</>
Expand All @@ -265,7 +265,7 @@ const Calendar: React.FC<Props> = ({
<RoundedButton
onClick={() => {
setShowYears(!showYears);
hiddeMonths();
hideMonths();
}}
>
<>{calendarData.date.year()}</>
Expand Down
Loading