diff --git a/src/App.css b/src/App.css
index a1dc8bc..84ca00a 100644
--- a/src/App.css
+++ b/src/App.css
@@ -3,5 +3,5 @@ body{
}
*{
- font-family: iranSansX;
+ font-family: 'iranSans';
}
\ No newline at end of file
diff --git a/src/components/Calendar/CalendarComponents/Calendar.js b/src/components/Calendar/CalendarComponents/Calendar.js
new file mode 100644
index 0000000..cbcf0f8
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/Calendar.js
@@ -0,0 +1,222 @@
+import React, { useState, useRef, useEffect } from 'react';
+
+import {
+ getDateAccordingToMonth,
+ shallowClone,
+ getValueType,
+} from './shared/generalUtils';
+import {
+ TYPE_SINGLE_DATE,
+ TYPE_RANGE,
+ TYPE_MUTLI_DATE,
+} from './shared/constants';
+import { useLocaleUtils, useLocaleLanguage } from './shared/hooks';
+
+import { Header, MonthSelector, YearSelector, DaysList } from './components';
+
+ const Calendar = ({
+ value,
+ onChange,
+ onDisabledDayError,
+ calendarClassName,
+ calendarTodayClassName,
+ calendarSelectedDayClassName,
+ calendarRangeStartClassName,
+ calendarRangeBetweenClassName,
+ calendarRangeEndClassName,
+ disabledDays,
+ colorPrimary,
+ colorPrimaryLight,
+ slideAnimationDuration,
+ minimumDate,
+ maximumDate,
+ selectorStartingYear,
+ selectorEndingYear,
+ locale,
+ shouldHighlightWeekends,
+ renderFooter,
+ customDaysClassName,
+ events,
+ renderEvents,
+}) => {
+ const calendarElement = useRef(null);
+ const [mainState, setMainState] = useState({
+ activeDate: null,
+ monthChangeDirection: '',
+ isMonthSelectorOpen: false,
+ isYearSelectorOpen: false,
+ });
+ const [eventInFooter, setEventInFooter] = useState(null);
+ useEffect(() => {
+ const handleKeyUp = ({ key }) => {
+ /* istanbul ignore else */
+ if (key === 'Tab')
+ calendarElement.current.classList.remove('-noFocusOutline');
+ };
+ calendarElement.current.addEventListener('keyup', handleKeyUp, false);
+ return () => {
+ // calendarElement.current.removeEventListener('keyup', handleKeyUp, false);
+ };
+ });
+
+ const { getToday } = useLocaleUtils(locale);
+ const { weekDays: weekDaysList, isRtl } = useLocaleLanguage(locale);
+ const today = getToday();
+
+ const createStateToggler = (property) => () => {
+ setMainState({ ...mainState, [property]: !mainState[property] });
+ };
+
+ const toggleMonthSelector = createStateToggler('isMonthSelectorOpen');
+ const toggleYearSelector = createStateToggler('isYearSelectorOpen');
+
+ const getComputedActiveDate = () => {
+ const valueType = getValueType(value);
+ if (valueType === TYPE_MUTLI_DATE && value.length)
+ return shallowClone(value[0]);
+ if (valueType === TYPE_SINGLE_DATE && value) return shallowClone(value);
+ if (valueType === TYPE_RANGE && value.from) return shallowClone(value.from);
+ return shallowClone(today);
+ };
+
+ const activeDate = mainState.activeDate
+ ? shallowClone(mainState.activeDate)
+ : getComputedActiveDate();
+
+ const weekdays = weekDaysList.map((weekDay) => (
+
+ {weekDay.short}
+
+ ));
+
+ const handleMonthChange = (direction) => {
+ setMainState({
+ ...mainState,
+ monthChangeDirection: direction,
+ });
+ };
+
+ const updateDate = () => {
+ setMainState({
+ ...mainState,
+ activeDate: getDateAccordingToMonth(
+ activeDate,
+ mainState.monthChangeDirection
+ ),
+ monthChangeDirection: '',
+ });
+ };
+
+ const selectMonth = (newMonthNumber) => {
+ setMainState({
+ ...mainState,
+ activeDate: { ...activeDate, month: newMonthNumber },
+ isMonthSelectorOpen: false,
+ });
+ };
+
+ const selectYear = (year) => {
+ setMainState({
+ ...mainState,
+ activeDate: { ...activeDate, year },
+ isYearSelectorOpen: false,
+ });
+ };
+
+ return (
+
+
+
+
+
+
+
+
{weekdays}
+
+
setEventInFooter(event)}
+ />
+
+
{eventInFooter}
+ {renderFooter()}
+
+ );
+};
+
+Calendar.defaultProps = {
+ minimumDate: null,
+ maximumDate: null,
+ colorPrimary: '#0eca2d',
+ colorPrimaryLight: '#cff4d5',
+ slideAnimationDuration: '0.4s',
+ calendarClassName: '',
+ locale: 'en',
+ value: null,
+ renderFooter: () => null,
+ renderEvents : () => null,
+ customDaysClassName: [],
+ events: [],
+};
+
+
+export default Calendar;
\ No newline at end of file
diff --git a/src/components/Calendar/CalendarComponents/DatePicker.css b/src/components/Calendar/CalendarComponents/DatePicker.css
new file mode 100644
index 0000000..c7010fb
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/DatePicker.css
@@ -0,0 +1,672 @@
+.DatePicker {
+ position: relative;
+ display: inline-block;
+ z-index: 100;
+}
+
+.DatePicker__input {
+ background: #fff;
+ border: 1px solid #ddd;
+ padding: 0.4em 0.8em;
+ font-family: inherit;
+ text-align: center;
+ font-size: 12px;
+}
+
+.DatePicker__input.-rtl {
+ direction: rtl;
+}
+
+.DatePicker__input::placeholder {
+ color: #979797;
+}
+
+.DatePicker__calendarContainer.-top + .DatePicker__calendarArrow {
+ top: auto;
+ bottom: calc(100% + 10px);
+ transform: translateY(-2.5rem) rotate(180deg);
+ animation: fadeArrowFlipped 0.3s forwards;
+}
+
+.DatePicker__calendarContainer {
+ position: absolute;
+ top: calc(100% + 20px);
+ left: 50%;
+ transform: translateX(-50%);
+}
+
+.DatePicker__calendarContainer.-top {
+ top: auto;
+ bottom: calc(100% + 20px);
+}
+
+.Calendar,
+.Calendar * {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ direction: ltr;
+}
+
+.Calendar,
+.Calendar.-rtl * {
+ direction: rtl;
+}
+
+.DatePicker__calendarArrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ top: calc(100% + 10px);
+ left: 0;
+ right: 0;
+ margin: 0 auto;
+ border-style: solid;
+ z-index: 10;
+ border-width: 0 10px 10px 10px;
+ border-color: transparent transparent #fff transparent;
+}
+
+.Calendar {
+ --cl-color-black: #444444;
+ --cl-color-disabled: #d4d4d4;
+ --cl-color-error: #ff2929;
+ font-size: 10px;
+ background: #fff;
+ box-shadow: 0 1em 4em rgba(0, 0, 0, 0.07);
+ border-radius: 1em;
+ position: relative;
+ user-select: none;
+ padding-top: 1.2em;
+ display: flex;
+ flex-direction: column;
+ width: 33em;
+ z-index: 10;
+ max-width: 90vw;
+ min-height: 36.7em;
+}
+
+.DatePicker .Calendar,
+.DatePicker__calendarArrow {
+ transform: translateY(2.5em);
+ opacity: 0;
+ animation: fadeCalendar 0.3s forwards;
+}
+
+.DatePicker__calendarContainer.-top .Calendar {
+ transform: translateY(-2.5em);
+}
+
+.Calendar.-noFocusOutline *:focus {
+ outline: none !important;
+}
+
+.Calendar > :not(.Calendar__footer) button {
+ font-family: inherit;
+ background: transparent;
+ cursor: pointer;
+ -webkit-tap-highlight-color: transparent;
+ outline: none;
+}
+
+.Calendar__header {
+ display: flex;
+ color: var(--cl-color-black);
+ padding: 2em 2.9em;
+ align-items: center;
+ overflow: hidden;
+}
+
+.Calendar__monthArrowWrapper {
+ line-height: 0;
+ font-size: 1em;
+ padding: 3px;
+ position: relative;
+ border: none;
+ z-index: 1;
+ opacity: 1;
+ transition: 0.2s;
+}
+
+.Calendar__monthArrowWrapper:focus {
+ outline: 1px dashed rgba(0, 0, 0, 0.4);
+ outline-offset: 2px;
+}
+
+.Calendar__monthArrowWrapper:disabled,
+.Calendar__monthArrowWrapper.-hidden {
+ opacity: 0;
+ pointer-events: none;
+}
+
+.Calendar__monthArrowWrapper.-left {
+ transform: rotate(90deg);
+}
+.Calendar.-rtl .Calendar__monthArrowWrapper.-left {
+ transform: rotate(-90deg);
+}
+
+.Calendar__monthArrowWrapper.-right {
+ transform: rotate(-90deg);
+}
+.Calendar.-rtl .Calendar__monthArrowWrapper.-right {
+ transform: rotate(90deg);
+}
+
+.Calendar__monthArrowWrapper:active .Calendar__monthArrow {
+ transform: scale(0.7);
+}
+
+.Calendar__monthArrow {
+ border-radius: 50%;
+ transition: var(--animation-duration) transform;
+ pointer-events: none;
+ background-repeat: no-repeat;
+ display: block;
+ width: 1.7em;
+ height: 1.7em;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg class='nc-icon-wrapper' fill='%23000000'%3E%3Cdefs stroke='none'%3E%3C/defs%3E%3Cpath class='cls-1' d='M12 23.25V.75' fill='none' stroke='%23000000' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5px'%3E%3C/path%3E%3Cpath class='cls-2' d='M22.5 11.25L12 .75 1.5 11.25' fill='none' stroke='%23000000' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5px' fill-rule='evenodd'%3E%3C/path%3E%3C/g%3E%3C/svg%3E");
+ background-size: 100% 100%;
+}
+
+.Calendar__monthYearContainer {
+ flex: 1;
+ position: relative;
+}
+
+.Calendar__monthYear {
+ font-size: 1.6em;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 50%;
+ will-change: transform, opacity;
+ backface-visibility: hidden;
+ transform: translateZ(0);
+ transition: var(--animation-duration);
+ line-height: 1;
+}
+
+.Calendar__monthYear.-hiddenNext {
+ opacity: 0;
+ transform: translateX(50%);
+}
+
+.Calendar.-rtl .Calendar__monthYear.-hiddenNext {
+ transform: translateX(-150%);
+}
+
+.Calendar__monthYear.-hiddenPrevious {
+ opacity: 0;
+ transform: translateX(-150%);
+}
+
+.Calendar.-rtl .Calendar__monthYear.-hiddenPrevious {
+ transform: translateX(50%);
+}
+
+.Calendar__monthYear.-shown {
+ opacity: 1;
+ margin-top: auto;
+ margin-bottom: auto;
+ transform: translateX(-50%);
+}
+
+.Calendar__monthYear.-shownAnimated {
+ animation: var(--animation-duration) fadeTextToCenter forwards;
+}
+
+.Calendar__monthYear > * {
+ padding: 0.2em 0.5em;
+ border: 1px solid transparent;
+ transition: var(--animation-duration);
+ font-size: 1.05em;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transform: translateX(0) scale(0.95);
+ will-change: transform;
+ border-radius: 5px;
+}
+
+.Calendar__monthYear:not(.-shown) > *,
+.Calendar__monthYear > *.-hidden {
+ cursor: default;
+ pointer-events: none;
+}
+
+.Calendar__monthText {
+ margin-left: -0.3em;
+}
+.Calendar__yearText:last-child {
+ margin-right: -0.3em;
+}
+
+.Calendar__monthYear.-shown > *:hover,
+.Calendar:not(.-noFocusOutline) .Calendar__monthYear.-shown > *:focus,
+.Calendar__monthYear > *.-activeBackground {
+ background: #f5f5f5;
+}
+
+.Calendar__monthText:hover {
+ transform: translateX(-0.2em) scale(0.95);
+}
+.Calendar.-rtl .Calendar__monthText:hover {
+ transform: translateX(0.2em) scale(0.95);
+}
+
+.Calendar__yearText:hover {
+ transform: translateX(0.2em) scale(0.95);
+}
+.Calendar.-rtl .Calendar__yearText:hover {
+ transform: translateX(-0.2em) scale(0.95);
+}
+
+.Calendar__monthYear .Calendar__yearText.-hidden {
+ transform: translateX(50%);
+ opacity: 0;
+}
+
+.Calendar.-rtl .Calendar__monthYear .Calendar__yearText.-hidden {
+ transform: translateX(-50%);
+}
+
+.Calendar__monthYear .Calendar__monthText.-hidden {
+ transform: translateX(-50%);
+ opacity: 0;
+}
+
+.Calendar.-rtl .Calendar__monthYear .Calendar__monthText.-hidden {
+ transform: translateX(50%);
+}
+
+.Calendar__monthYear:not(.-shown) > * {
+ pointer-events: none;
+}
+
+.Calendar__monthSelectorAnimationWrapper,
+.Calendar__yearSelectorAnimationWrapper {
+ position: absolute;
+ width: 100%;
+ height: 80%;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+}
+
+.Calendar__monthSelectorWrapper {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.Calendar__monthSelector {
+ padding: 0 2.5em;
+ align-content: center;
+ padding-bottom: 2em;
+}
+
+.Calendar__monthSelector,
+.Calendar__yearSelector {
+ display: flex;
+ flex-wrap: wrap;
+ position: relative;
+ z-index: 2;
+ background-color: #fff;
+ transform: translateY(-150%);
+ will-change: transform;
+ transition: 0.6s;
+ height: 100%;
+}
+
+.Calendar__yearSelectorWrapper {
+ width: 100%;
+ height: 100%;
+}
+
+.Calendar__yearSelectorWrapper::after,
+.Calendar__yearSelectorWrapper::before {
+ content: '';
+ width: 100%;
+ height: 5em;
+ position: absolute;
+ left: 0;
+ opacity: 0;
+ transition: 0.4s;
+ transition-delay: 0.2s;
+}
+
+.Calendar__yearSelectorWrapper::after {
+ background-image: linear-gradient(to bottom, #fff, #fff 10%, rgba(245, 245, 245, 0));
+ top: -0.1em;
+}
+
+.Calendar__yearSelectorWrapper::before {
+ background-image: linear-gradient(to top, #fff, #fff 10%, rgba(245, 245, 245, 0));
+ bottom: 0;
+}
+
+.Calendar__yearSelectorWrapper.-faded::after,
+.Calendar__yearSelectorWrapper.-faded::before {
+ opacity: 1;
+ z-index: 3;
+}
+
+.Calendar__yearSelector {
+ align-content: flex-start;
+ scrollbar-width: 0;
+ overflow: scroll;
+ position: relative;
+ width: 100%;
+ padding: 5em 2em;
+ -ms-overflow-style: none;
+}
+
+.Calendar__yearSelector::-webkit-scrollbar {
+ display: none;
+}
+
+.Calendar__yearSelectorItem {
+ width: 25%;
+ display: flex;
+ justify-content: center;
+}
+
+.Calendar__yearSelectorItem:not(:nth-child(-n + 4)) {
+ margin-top: 1.5em;
+}
+
+.Calendar__yearSelectorText {
+ border: none;
+ font-size: 1.4em;
+ min-width: 85%;
+ padding: 0.2em 0.5em;
+ border-radius: 8.5px;
+}
+
+.Calendar__monthSelector.-open,
+.Calendar__yearSelector.-open {
+ transform: translateY(0);
+}
+
+.Calendar__yearSelectorText:focus,
+.Calendar__monthSelectorItemText:focus {
+ outline: 1px dashed rgba(0, 0, 0, 0.4);
+ outline-offset: 2px;
+}
+
+.Calendar__monthSelectorItem {
+ width: calc(100% / 3);
+ display: flex;
+ justify-content: center;
+}
+
+.Calendar__monthSelectorItem:not(:nth-child(-n + 3)) {
+ margin-top: 2em;
+}
+
+.Calendar__monthSelectorItemText {
+ border: none;
+ padding: 0.4em 0.4em;
+ border-radius: 8.5px;
+ font-size: 1.3em;
+ min-width: 70%;
+ transition: 0.3s;
+}
+
+.Calendar__monthSelectorItem:not(.-active) .Calendar__monthSelectorItemText:not(:disabled):hover,
+.Calendar__yearSelectorItem:not(.-active) .Calendar__yearSelectorText:not(:disabled):hover {
+ background: #f5f5f5;
+}
+
+.Calendar__monthSelectorItemText:disabled,
+.Calendar__yearSelectorText:disabled {
+ opacity: 0.5;
+ cursor: default;
+}
+
+.Calendar__monthSelectorItem.-active .Calendar__monthSelectorItemText,
+.Calendar__yearSelectorItem.-active .Calendar__yearSelectorText {
+ background-color: var(--cl-color-primary);
+ color: #fff;
+}
+
+.Calendar__weekDays {
+ display: flex;
+ justify-content: space-between;
+ color: var(--cl-color-disabled);
+ font-size: 1.2em;
+ margin-bottom: 0.7em;
+ padding: 0 2.6em;
+ position: relative;
+}
+
+.Calendar__weekDay {
+ display: block;
+ width: calc(100% / 7);
+ text-align: center;
+ text-decoration: none;
+}
+
+.Calendar__sectionWrapper {
+ position: relative;
+ min-height: 25.8em;
+ overflow: hidden;
+}
+
+.Calendar__section {
+ display: flex;
+ flex-direction: column;
+ padding: 0 3.2em;
+ position: absolute;
+ color: var(--cl-color-black);
+ top: 0;
+ padding-top: 0.5em;
+ left: 0;
+ width: 100%;
+ will-change: transform, opacity;
+ transform: translateZ(0);
+ backface-visibility: hidden;
+ transition: var(--animation-duration);
+}
+
+.Calendar__section.-hiddenPrevious {
+ opacity: 0.5;
+ transform: translateX(-90%);
+}
+
+.Calendar.-rtl .Calendar__section.-hiddenPrevious {
+ transform: translateX(90%);
+}
+
+.Calendar__section.-hiddenNext {
+ opacity: 0.5;
+ transform: translateX(90%);
+}
+
+.Calendar.-rtl .Calendar__section.-hiddenNext {
+ transform: translateX(-90%);
+}
+
+.Calendar__section.-shown {
+ opacity: 1;
+ transform: translateX(0);
+}
+
+.Calendar__section.-shownAnimated {
+ animation: var(--animation-duration) FadeContentToCenter forwards;
+}
+
+.Calendar__weekRow {
+ display: flex;
+ width: 100%;
+}
+
+.Calendar__day {
+ display: block;
+ width: calc(100% / 7);
+ text-align: center;
+ padding: calc(0.25em - 1px) 0;
+ font-size: 1.6em;
+ border-radius: 50%;
+ transition: 0.2s;
+ border: 1px solid transparent;
+ margin-bottom: 0.3em;
+ color: rgba(0, 0, 0, 0.8);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+}
+
+.Calendar__day:focus {
+ outline: 1px dashed rgba(0, 0, 0, 0.4);
+ outline-offset: 2px;
+}
+
+.Calendar__day.-ltr {
+ min-height: 2.6em;
+ font-size: 1.45em;
+}
+
+.Calendar__day.-rtl {
+ font-size: 1.55em;
+ height: 2.45em;
+}
+
+.Calendar__day:not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween):not(.-selected):hover {
+ background: #eaeaea;
+ border-radius: 50%;
+ color: var(--cl-color-black);
+ border-color: transparent;
+}
+
+.Calendar__day.-selected,
+.Calendar__day.-selectedStart,
+.Calendar__day.-selectedEnd {
+ background: var(--cl-color-primary);
+ color: #fff;
+}
+
+.Calendar__day.-ltr.-selectedStart {
+ border-radius: 0;
+ border-top-left-radius: 100em;
+ border-bottom-left-radius: 100em;
+}
+
+.Calendar__day.-rtl.-selectedStart {
+ border-radius: 0;
+ border-top-right-radius: 100em;
+ border-bottom-right-radius: 100em;
+}
+
+.Calendar__day.-selectedBetween {
+ background: var(--cl-color-primary-light);
+ color: var(--cl-color-primary);
+ border-radius: 0;
+}
+
+.Calendar__day.-ltr.-selectedEnd {
+ border-top-right-radius: 100em;
+ border-bottom-right-radius: 100em;
+}
+
+.Calendar__day.-rtl.-selectedEnd {
+ border-top-left-radius: 100em;
+ border-bottom-left-radius: 100em;
+}
+
+.Calendar__day.-weekend:not(.-selected):not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween) {
+ color: var(--cl-color-error);
+}
+
+.Calendar__day.-weekend.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after {
+ background: var(--cl-color-error);
+}
+
+.Calendar__day.-disabled {
+ color: var(--cl-color-disabled) !important;
+ background: transparent !important;
+ cursor: default !important;
+}
+.Calendar__day.-selected {
+ border-radius: 50%;
+}
+.Calendar__day.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween) {
+ font-weight: 600;
+ color: var(--cl-color-black);
+ color: #000;
+ position: relative;
+}
+
+.Calendar__day.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after {
+ content: '';
+ position: absolute;
+ bottom: 0.2em;
+ display: block;
+ width: 0.6em;
+ height: 1px;
+ background: #000;
+ left: 50%;
+ opacity: 0.5;
+ transform: translateX(-50%);
+ transition: 0.2s;
+}
+
+.Calendar__day.-today:hover:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after {
+ opacity: 0;
+}
+
+.Calendar__day.-blank {
+ color: transparent;
+ cursor: default;
+ pointer-events: none;
+}
+
+.Calendar__footer {
+ position: relative;
+ z-index: 1;
+}
+
+@keyframes fadeCalendar {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeArrowFlipped {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0) rotate(180deg);
+ }
+}
+
+@keyframes fadeTextToCenter {
+ to {
+ opacity: 1;
+ transform: translateX(-50%);
+ }
+}
+
+@keyframes FadeContentToCenter {
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
diff --git a/src/components/Calendar/CalendarComponents/DatePicker.js b/src/components/Calendar/CalendarComponents/DatePicker.js
new file mode 100644
index 0000000..6f81669
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/DatePicker.js
@@ -0,0 +1,203 @@
+import React, { useState, useEffect, useRef, useLayoutEffect } from 'react';
+
+import Calendar from './Calendar';
+import DatePickerInput from './DatePickerInput';
+import { getValueType } from './shared/generalUtils';
+import { TYPE_SINGLE_DATE, TYPE_MUTLI_DATE, TYPE_RANGE } from './shared/constants';
+
+const DatePicker = ({
+ value,
+ onChange,
+ formatInputText,
+ inputPlaceholder,
+ inputClassName,
+ inputName,
+ renderInput,
+ wrapperClassName,
+ calendarClassName,
+ calendarTodayClassName,
+ calendarSelectedDayClassName,
+ calendarRangeStartClassName,
+ calendarRangeBetweenClassName,
+ calendarRangeEndClassName,
+ calendarPopperPosition,
+ disabledDays,
+ onDisabledDayError,
+ colorPrimary,
+ colorPrimaryLight,
+ slideAnimationDuration,
+ minimumDate,
+ maximumDate,
+ selectorStartingYear,
+ selectorEndingYear,
+ locale,
+ shouldHighlightWeekends,
+ renderFooter,
+ customDaysClassName,
+}) => {
+ const calendarContainerElement = useRef(null);
+ const inputElement = useRef(null);
+ const shouldPreventToggle = useRef(false);
+ const [isCalendarOpen, setCalendarVisiblity] = useState(false);
+
+ useEffect(() => {
+ const handleBlur = () => {
+ setCalendarVisiblity(false);
+ };
+ window.addEventListener('blur', handleBlur, false);
+ return () => {
+ window.removeEventListener('blur', handleBlur, false);
+ };
+ }, []);
+
+ // handle input focus/blur
+ useEffect(() => {
+ const valueType = getValueType(value);
+ if (valueType === TYPE_MUTLI_DATE) return; // no need to close the calendar
+ const shouldCloseCalendar =
+ valueType === TYPE_SINGLE_DATE ? !isCalendarOpen : !isCalendarOpen && value.from && value.to;
+ if (shouldCloseCalendar) inputElement.current.blur();
+ }, [value, isCalendarOpen]);
+
+ const handleBlur = e => {
+ e.persist();
+ if (!isCalendarOpen) return;
+ const isInnerElementFocused = calendarContainerElement.current.contains(e.relatedTarget);
+ if (shouldPreventToggle.current) {
+ shouldPreventToggle.current = false;
+ inputElement.current.focus();
+ } else if (isInnerElementFocused && e.relatedTarget) {
+ e.relatedTarget.focus();
+ } else {
+ setCalendarVisiblity(false);
+ }
+ };
+
+ const openCalendar = () => {
+ if (!shouldPreventToggle.current) setCalendarVisiblity(true);
+ };
+
+ // Keep the calendar in the screen bounds if input is near the window edges
+ useLayoutEffect(() => {
+ if (!isCalendarOpen) return;
+ const { left, width, height, top } = calendarContainerElement.current.getBoundingClientRect();
+ const { clientWidth, clientHeight } = document.documentElement;
+ const isOverflowingFromRight = left + width > clientWidth;
+ const isOverflowingFromLeft = left < 0;
+ const isOverflowingFromBottom = top + height > clientHeight;
+
+ const getLeftStyle = () => {
+ const overflowFromRightDistance = left + width - clientWidth;
+
+ if (!isOverflowingFromRight && !isOverflowingFromLeft) return;
+ const overflowFromLeftDistance = Math.abs(left);
+ const rightPosition = isOverflowingFromLeft ? overflowFromLeftDistance : 0;
+
+ const leftStyle = isOverflowingFromRight
+ ? `calc(50% - ${overflowFromRightDistance}px)`
+ : `calc(50% + ${rightPosition}px)`;
+ return leftStyle;
+ };
+
+ calendarContainerElement.current.style.left = getLeftStyle();
+ if (
+ (calendarPopperPosition === 'auto' && isOverflowingFromBottom) ||
+ calendarPopperPosition === 'top'
+ ) {
+ calendarContainerElement.current.classList.add('-top');
+ }
+ }, [isCalendarOpen]);
+
+ const handleCalendarChange = newValue => {
+ const valueType = getValueType(value);
+ onChange(newValue);
+ if (valueType === TYPE_SINGLE_DATE) setCalendarVisiblity(false);
+ else if (valueType === TYPE_RANGE && newValue.from && newValue.to) setCalendarVisiblity(false);
+ };
+
+ const handleKeyUp = ({ key }) => {
+ switch (key) {
+ case 'Enter':
+ setCalendarVisiblity(true);
+ break;
+ case 'Escape':
+ setCalendarVisiblity(false);
+ shouldPreventToggle.current = true;
+ break;
+ }
+ };
+
+ useEffect(() => {
+ if (!isCalendarOpen && shouldPreventToggle.current) {
+ inputElement.current.focus();
+ shouldPreventToggle.current = false;
+ }
+ }, [shouldPreventToggle, isCalendarOpen]);
+
+ return (
+
+
+ {isCalendarOpen && (
+ <>
+
{
+ shouldPreventToggle.current = true;
+ }}
+ >
+
+
+
+ >
+ )}
+
+ );
+};
+
+DatePicker.defaultProps = {
+ wrapperClassName: '',
+ locale: 'en',
+ calendarPopperPosition: 'auto',
+};
+
+export default DatePicker;
diff --git a/src/components/Calendar/CalendarComponents/DatePickerInput.js b/src/components/Calendar/CalendarComponents/DatePickerInput.js
new file mode 100644
index 0000000..30d3ee7
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/DatePickerInput.js
@@ -0,0 +1,93 @@
+import React from 'react';
+
+import { useLocaleUtils, useLocaleLanguage } from './shared/hooks';
+import { putZero, getValueType } from './shared/generalUtils';
+import { TYPE_SINGLE_DATE, TYPE_RANGE, TYPE_MUTLI_DATE } from './shared/constants';
+
+const DatePickerInput = React.forwardRef(
+ (
+ { value, inputPlaceholder, inputClassName, inputName, formatInputText, renderInput, locale },
+ ref,
+ ) => {
+ const { getLanguageDigits } = useLocaleUtils(locale);
+ const {
+ from: fromWord,
+ to: toWord,
+ yearLetterSkip,
+ digitSeparator,
+ defaultPlaceholder,
+ isRtl,
+ } = useLocaleLanguage(locale);
+
+ const getSingleDayValue = () => {
+ if (!value) return '';
+ const year = getLanguageDigits(value.year);
+ const month = getLanguageDigits(putZero(value.month));
+ const day = getLanguageDigits(putZero(value.day));
+ return `${year}/${month}/${day}`;
+ };
+
+ const getDayRangeValue = () => {
+ if (!value.from || !value.to) return '';
+ const { from, to } = value;
+ const fromText = `${getLanguageDigits(putZero(from.year))
+ .toString()
+ .slice(yearLetterSkip)}/${getLanguageDigits(putZero(from.month))}/${getLanguageDigits(
+ putZero(from.day),
+ )}`;
+ const toText = `${getLanguageDigits(putZero(to.year))
+ .toString()
+ .slice(yearLetterSkip)}/${getLanguageDigits(putZero(to.month))}/${getLanguageDigits(
+ putZero(to.day),
+ )}`;
+ return `${fromWord} ${fromText} ${toWord} ${toText}`;
+ };
+
+ const getMultiDateValue = () => {
+ return value.map(date => getLanguageDigits(date.day)).join(`${digitSeparator} `);
+ };
+
+ const getValue = () => {
+ if (formatInputText()) return formatInputText();
+ const valueType = getValueType(value);
+ switch (valueType) {
+ case TYPE_SINGLE_DATE:
+ return getSingleDayValue();
+ case TYPE_RANGE:
+ return getDayRangeValue();
+ case TYPE_MUTLI_DATE:
+ return getMultiDateValue();
+ }
+ };
+
+ const placeholderValue = inputPlaceholder || defaultPlaceholder;
+ const render = () => {
+ return (
+ renderInput({ ref }) || (
+
+ )
+ );
+ };
+
+ return render();
+ },
+);
+
+DatePickerInput.defaultProps = {
+ formatInputText: () => '',
+ renderInput: () => null,
+ inputPlaceholder: '',
+ inputClassName: '',
+ inputName: '',
+};
+
+export default DatePickerInput;
diff --git a/src/components/Calendar/CalendarComponents/components/DaysList.js b/src/components/Calendar/CalendarComponents/components/DaysList.js
new file mode 100644
index 0000000..531ce18
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/components/DaysList.js
@@ -0,0 +1,398 @@
+import React, { useRef, useEffect } from 'react';
+
+import {
+ getSlideDate,
+ handleSlideAnimationEnd,
+ animateContent,
+} from '../shared/sliderHelpers';
+import {
+ deepCloneObject,
+ isSameDay,
+ createUniqueRange,
+ getValueType,
+} from '../shared/generalUtils';
+import {
+ TYPE_SINGLE_DATE,
+ TYPE_RANGE,
+ TYPE_MUTLI_DATE,
+} from '../shared/constants';
+import handleKeyboardNavigation from '../shared/keyboardNavigation';
+import { useLocaleUtils, useLocaleLanguage } from '../shared/hooks';
+
+const DaysList = ({
+ activeDate,
+ value,
+ monthChangeDirection,
+ onSlideChange,
+ disabledDays,
+ onDisabledDayError,
+ minimumDate,
+ maximumDate,
+ onChange,
+ locale,
+ calendarTodayClassName,
+ calendarSelectedDayClassName,
+ calendarRangeStartClassName,
+ calendarRangeEndClassName,
+ calendarRangeBetweenClassName,
+ shouldHighlightWeekends,
+ isQuickSelectorOpen,
+ customDaysClassName,
+ events,
+ showEvent,
+}) => {
+ const calendarSectionWrapper = useRef(null);
+ const { isRtl, weekDays: weekDaysList } = useLocaleLanguage(locale);
+ const {
+ getToday,
+ isBeforeDate,
+ checkDayInDayRange,
+ getMonthFirstWeekday,
+ getMonthLength,
+ getLanguageDigits,
+ getMonthName,
+ } = useLocaleUtils(locale);
+ const today = getToday();
+
+ useEffect(() => {
+ if (!monthChangeDirection) return;
+ animateContent({
+ direction: monthChangeDirection,
+ parent: calendarSectionWrapper.current,
+ });
+ }, [monthChangeDirection]);
+
+ const getDayRangeValue = (day) => {
+ const clonedDayRange = deepCloneObject(value);
+ const dayRangeValue =
+ clonedDayRange.from && clonedDayRange.to
+ ? { from: null, to: null }
+ : clonedDayRange;
+ const dayRangeProp = !dayRangeValue.from ? 'from' : 'to';
+ dayRangeValue[dayRangeProp] = day;
+ const { from, to } = dayRangeValue;
+
+ // swap from and to values if from is later than to
+ if (isBeforeDate(dayRangeValue.to, dayRangeValue.from)) {
+ dayRangeValue.from = to;
+ dayRangeValue.to = from;
+ }
+
+ const checkIncludingDisabledDay = (disabledDay) => {
+ return checkDayInDayRange({
+ day: disabledDay,
+ from: dayRangeValue.from,
+ to: dayRangeValue.to,
+ });
+ };
+ const includingDisabledDay = disabledDays.find(checkIncludingDisabledDay);
+ if (includingDisabledDay) {
+ onDisabledDayError(includingDisabledDay);
+ return value;
+ }
+
+ return dayRangeValue;
+ };
+
+ const getMultiDateValue = (day) => {
+ const isAlreadyExisting = value.some((valueDay) =>
+ isSameDay(valueDay, day)
+ );
+ const addedToValue = [...value, day];
+ const removedFromValue = value.filter(
+ (valueDay) => !isSameDay(valueDay, day)
+ );
+ return isAlreadyExisting ? removedFromValue : addedToValue;
+ };
+
+ const handleDayClick = (day) => {
+ const getNewValue = () => {
+ const valueType = getValueType(value);
+ switch (valueType) {
+ case TYPE_SINGLE_DATE:
+ return day;
+ case TYPE_RANGE:
+ return getDayRangeValue(day);
+ case TYPE_MUTLI_DATE:
+ return getMultiDateValue(day);
+ }
+ };
+ const newValue = getNewValue();
+ onChange(newValue);
+ };
+
+ const isSingleDateSelected = (day) => {
+ const valueType = getValueType(value);
+ if (valueType === TYPE_SINGLE_DATE) return isSameDay(day, value);
+ if (valueType === TYPE_MUTLI_DATE)
+ return value.some((valueDay) => isSameDay(valueDay, day));
+ };
+
+ const getDayStatus = (dayItem) => {
+ const isToday = isSameDay(dayItem, today);
+ const isSelected = isSingleDateSelected(dayItem);
+ const { from: startingDay, to: endingDay } = value || {};
+ const isStartingDayRange = isSameDay(dayItem, startingDay);
+ const isEndingDayRange = isSameDay(dayItem, endingDay);
+ const isWithinRange = checkDayInDayRange({
+ day: dayItem,
+ from: startingDay,
+ to: endingDay,
+ });
+ return {
+ isToday,
+ isSelected,
+ isStartingDayRange,
+ isEndingDayRange,
+ isWithinRange,
+ };
+ };
+
+ const getDayClassNames = (dayItem) => {
+ const {
+ isToday,
+ isSelected,
+ isStartingDayRange,
+ isEndingDayRange,
+ isWithinRange,
+ } = getDayStatus(dayItem);
+ const customDayItemClassName = customDaysClassName.find((day) =>
+ isSameDay(dayItem, day)
+ );
+
+ const classNames = ''
+ .concat(isToday && !isSelected ? ` -today ${calendarTodayClassName}` : '')
+ .concat(!dayItem.isStandard ? ' -blank' : '')
+ .concat(dayItem.isWeekend && shouldHighlightWeekends ? ' -weekend' : '')
+ .concat(
+ customDayItemClassName ? ` ${customDayItemClassName.className}` : ''
+ )
+ .concat(isSelected ? ` -selected ${calendarSelectedDayClassName}` : '')
+ .concat(
+ isStartingDayRange
+ ? ` -selectedStart ${calendarRangeStartClassName}`
+ : ''
+ )
+ .concat(
+ isEndingDayRange ? ` -selectedEnd ${calendarRangeEndClassName}` : ''
+ )
+ .concat(
+ isWithinRange
+ ? ` -selectedBetween ${calendarRangeBetweenClassName}`
+ : ''
+ )
+ .concat(dayItem.isDisabled ? ' -disabled' : '');
+ return classNames;
+ };
+
+ const getViewMonthDays = (date) => {
+ // to match month starting date with the correct weekday label
+ const prependingBlankDays = createUniqueRange(
+ getMonthFirstWeekday(date),
+ 'starting-blank'
+ );
+ const standardDays = createUniqueRange(getMonthLength(date)).map((day) => ({
+ ...day,
+ isStandard: true,
+ month: date.month,
+ year: date.year,
+ }));
+ const allDays = [...prependingBlankDays, ...standardDays];
+ return allDays;
+ };
+
+ const handleDayPress = ({ isDisabled, ...dayItem }) => {
+ if (isDisabled) {
+ onDisabledDayError(dayItem); // good for showing error messages
+ } else handleDayClick(dayItem);
+ };
+
+ const isDayReachableByKeyboard = ({
+ isOnActiveSlide,
+ isStandard,
+ isSelected,
+ isStartingDayRange,
+ isToday,
+ day,
+ }) => {
+ if (isQuickSelectorOpen || !isOnActiveSlide || !isStandard) return false;
+ if (isSelected || isStartingDayRange || isToday || day === 1) return true;
+ };
+
+ const renderEachWeekDays = (
+ { id, value: day, month, year, isStandard },
+ index
+ ) => {
+ const dayItem = { day, month, year };
+ const isInDisabledDaysRange = disabledDays.some((disabledDay) =>
+ isSameDay(dayItem, disabledDay)
+ );
+ const isBeforeMinimumDate = isBeforeDate(dayItem, minimumDate);
+ const isAfterMaximumDate = isBeforeDate(maximumDate, dayItem);
+ const isNotInValidRange =
+ isStandard && (isBeforeMinimumDate || isAfterMaximumDate);
+ const isDisabled = isInDisabledDaysRange || isNotInValidRange;
+ const isWeekend = weekDaysList.some(
+ (weekDayItem, weekDayItemIndex) =>
+ weekDayItem.isWeekend && weekDayItemIndex === index
+ );
+ const additionalClass = getDayClassNames({
+ ...dayItem,
+ isWeekend,
+ isStandard,
+ isDisabled,
+ });
+ const dayLabel = `${weekDaysList[index].name}, ${day} ${getMonthName(
+ month
+ )} ${year}`;
+ const isOnActiveSlide = month === activeDate.month;
+ const dayStatus = getDayStatus(dayItem);
+ const { isSelected, isStartingDayRange, isEndingDayRange, isWithinRange } =
+ dayStatus;
+ const shouldEnableKeyboardNavigation = isDayReachableByKeyboard({
+ ...dayItem,
+ ...dayStatus,
+ isOnActiveSlide,
+ isStandard,
+ });
+
+ // showing Dots Of Events
+ const specialDate = (sDay, sMonth, sYear) => {
+ return events.map((e) => {
+ if (sDay == e.day && sMonth == e.month && sYear == e.year) {
+ return .;
+
+ }
+ })
+
+ };
+
+ const showEventDescription = (sDay, sMonth, sYear) => {
+
+ return events.map((e) => {
+
+ if (sDay == e.day && sMonth == e.month && sYear == e.year) {
+
+ return ()
+
+ }
+
+ })
+
+
+ }
+ return (
+ {
+ handleDayPress({ ...dayItem, isDisabled });
+ // console.log(specialDate(day));
+ // console.log(showEventDescription(day))
+ showEvent(showEventDescription(day, month, year))
+
+ }}
+ onKeyDown={({ key }) => {
+ /* istanbul ignore else */
+ if (key === 'Enter') handleDayPress({ ...dayItem, isDisabled });
+ }}
+ aria-disabled={isDisabled}
+ aria-label={dayLabel}
+ aria-selected={
+ isSelected || isStartingDayRange || isEndingDayRange || isWithinRange
+ }
+ {...(!isStandard || !isOnActiveSlide || isQuickSelectorOpen
+ ? { 'aria-hidden': true }
+ : {})}
+ role="gridcell"
+ data-is-default-selectable={shouldEnableKeyboardNavigation}
+ >
+ {!isStandard ? '' : getLanguageDigits(day)}
+ {/* Dots Of Events */}
+ {specialDate(day, month, year)}
+
+ );
+ };
+
+ const renderMonthDays = (isInitialActiveChild) => {
+ const date = getSlideDate({
+ activeDate,
+ isInitialActiveChild,
+ monthChangeDirection,
+ parent: calendarSectionWrapper.current,
+ });
+ const allDays = getViewMonthDays(date);
+ const renderSingleWeekRow = (weekRowIndex) => {
+ const eachWeekDays = allDays
+ .slice(weekRowIndex * 7, weekRowIndex * 7 + 7)
+ .map(renderEachWeekDays);
+ return (
+
+ {eachWeekDays}
+
+ );
+ };
+ return Array.from(Array(6).keys()).map(renderSingleWeekRow);
+ };
+
+ const handleKeyDown = (e) => {
+ handleKeyboardNavigation(e, { allowVerticalArrows: true });
+ };
+
+ return (
+
+
{
+ handleSlideAnimationEnd(e);
+ onSlideChange();
+ }}
+ className="Calendar__section -shown"
+ role="rowgroup"
+ >
+ {renderMonthDays(true)}
+
+
{
+ handleSlideAnimationEnd(e);
+ onSlideChange();
+ }}
+ className="Calendar__section -hiddenNext"
+ role="rowgroup"
+ >
+ {renderMonthDays(false)}
+
+
+ );
+};
+
+DaysList.defaultProps = {
+ onChange: () => { },
+ onDisabledDayError: () => { },
+ disabledDays: [],
+ calendarTodayClassName: '',
+ calendarSelectedDayClassName: '',
+ calendarRangeStartClassName: '',
+ calendarRangeBetweenClassName: '',
+ calendarRangeEndClassName: '',
+ shouldHighlightWeekends: false,
+};
+
+export default DaysList;
diff --git a/src/components/Calendar/CalendarComponents/components/Header.js b/src/components/Calendar/CalendarComponents/components/Header.js
new file mode 100644
index 0000000..2091185
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/components/Header.js
@@ -0,0 +1,189 @@
+import React, { useEffect, useRef } from 'react';
+
+import { isSameDay } from '../shared/generalUtils';
+import { getSlideDate, animateContent, handleSlideAnimationEnd } from '../shared/sliderHelpers';
+import { useLocaleUtils, useLocaleLanguage } from '../shared/hooks';
+
+const Header = ({
+ maximumDate,
+ minimumDate,
+ onMonthChange,
+ activeDate,
+ monthChangeDirection,
+ onMonthSelect,
+ onYearSelect,
+ isMonthSelectorOpen,
+ isYearSelectorOpen,
+ locale,
+}) => {
+ const headerElement = useRef(null);
+ const monthYearWrapperElement = useRef(null);
+
+ const { getMonthName, isBeforeDate, getLanguageDigits } = useLocaleUtils(locale);
+ const {
+ isRtl,
+ nextMonth,
+ previousMonth,
+ openMonthSelector,
+ closeMonthSelector,
+ openYearSelector,
+ closeYearSelector,
+ } = useLocaleLanguage(locale);
+
+ useEffect(() => {
+ if (!monthChangeDirection) return;
+ animateContent({
+ direction: monthChangeDirection,
+ parent: monthYearWrapperElement.current,
+ });
+ }, [monthChangeDirection]);
+
+ useEffect(() => {
+ const isOpen = isMonthSelectorOpen || isYearSelectorOpen;
+ const monthText = headerElement.current.querySelector(
+ '.Calendar__monthYear.-shown .Calendar__monthText',
+ );
+ const yearText = monthText.nextSibling;
+ const hasActiveBackground = element => element.classList.contains('-activeBackground');
+ const isInitialRender =
+ !isOpen && !hasActiveBackground(monthText) && !hasActiveBackground(yearText);
+ if (isInitialRender) return;
+
+ const arrows = [...headerElement.current.querySelectorAll('.Calendar__monthArrowWrapper')];
+ const hasMonthSelectorToggled = isMonthSelectorOpen || hasActiveBackground(monthText);
+ const primaryElement = hasMonthSelectorToggled ? monthText : yearText;
+ const secondaryElement = hasMonthSelectorToggled ? yearText : monthText;
+
+ let translateXDirection = hasMonthSelectorToggled ? 1 : -1;
+ if (isRtl) translateXDirection *= -1;
+ const scale = !isOpen ? 0.95 : 1;
+ const translateX = !isOpen ? 0 : `${(translateXDirection * secondaryElement.offsetWidth) / 2}`;
+ if (!isOpen) {
+ secondaryElement.removeAttribute('aria-hidden');
+ } else {
+ secondaryElement.setAttribute('aria-hidden', true);
+ }
+ secondaryElement.setAttribute('tabindex', isOpen ? '-1' : '0');
+ secondaryElement.style.transform = '';
+ primaryElement.style.transform = `scale(${scale}) ${
+ translateX ? `translateX(${translateX}px)` : ''
+ }`;
+ primaryElement.classList.toggle('-activeBackground');
+ secondaryElement.classList.toggle('-hidden');
+ arrows.forEach(arrow => {
+ const isHidden = arrow.classList.contains('-hidden');
+ arrow.classList.toggle('-hidden');
+ if (isHidden) {
+ arrow.removeAttribute('aria-hidden');
+ arrow.setAttribute('tabindex', '0');
+ } else {
+ arrow.setAttribute('aria-hidden', true);
+ arrow.setAttribute('tabindex', '-1');
+ }
+ });
+ }, [isMonthSelectorOpen, isYearSelectorOpen]);
+
+ const getMonthYearText = isInitialActiveChild => {
+ const date = getSlideDate({
+ isInitialActiveChild,
+ monthChangeDirection,
+ activeDate,
+ parent: monthYearWrapperElement.current,
+ });
+ const year = getLanguageDigits(date.year);
+ const month = getMonthName(date.month);
+ return { month, year };
+ };
+
+ const isNextMonthArrowDisabled =
+ maximumDate &&
+ isBeforeDate(maximumDate, { ...activeDate, month: activeDate.month + 1, day: 1 });
+ const isPreviousMonthArrowDisabled =
+ minimumDate &&
+ (isBeforeDate({ ...activeDate, day: 1 }, minimumDate) ||
+ isSameDay(minimumDate, { ...activeDate, day: 1 }));
+
+ const onMonthChangeTrigger = direction => {
+ const isMonthChanging = Array.from(monthYearWrapperElement.current.children).some(child =>
+ child.classList.contains('-shownAnimated'),
+ );
+ if (isMonthChanging) return;
+ onMonthChange(direction);
+ };
+
+ // first button text is the one who shows the current month and year(initial active child)
+ const monthYearButtons = [true, false].map(isInitialActiveChild => {
+ const { month, year } = getMonthYearText(isInitialActiveChild);
+ const isActiveMonth = month === getMonthName(activeDate.month);
+ const hiddenStatus = {
+ ...(isActiveMonth ? {} : { 'aria-hidden': true }),
+ };
+ return (
+
+
+
+
+ );
+ });
+
+ return (
+
+
+
+
+ {monthYearButtons}
+
+
+
+ );
+};
+
+export default Header;
diff --git a/src/components/Calendar/CalendarComponents/components/MonthSelector.js b/src/components/Calendar/CalendarComponents/components/MonthSelector.js
new file mode 100644
index 0000000..aafbd2c
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/components/MonthSelector.js
@@ -0,0 +1,74 @@
+import React, { useRef, useEffect } from 'react';
+
+import { isSameDay } from '../shared/generalUtils';
+import handleKeyboardNavigation from '../shared/keyboardNavigation';
+import { useLocaleUtils, useLocaleLanguage } from '../shared/hooks';
+
+const MonthSelector = ({ activeDate, maximumDate, minimumDate, onMonthSelect, isOpen, locale }) => {
+ const monthSelector = useRef(null);
+
+ useEffect(() => {
+ const classToggleMethod = isOpen ? 'add' : 'remove';
+ monthSelector.current.classList[classToggleMethod]('-open');
+ }, [isOpen]);
+
+ const { getMonthNumber, isBeforeDate } = useLocaleUtils(locale);
+ const { months: monthsList } = useLocaleLanguage(locale);
+
+ const handleKeyDown = e => {
+ handleKeyboardNavigation(e, { allowVerticalArrows: false });
+ };
+
+ const renderMonthSelectorItems = () =>
+ monthsList.map(persianMonth => {
+ const monthNumber = getMonthNumber(persianMonth);
+ const monthDate = { day: 1, month: monthNumber, year: activeDate.year };
+ const isAfterMaximumDate =
+ maximumDate && isBeforeDate(maximumDate, { ...monthDate, month: monthNumber });
+ const isBeforeMinimumDate =
+ minimumDate &&
+ (isBeforeDate({ ...monthDate, month: monthNumber + 1 }, minimumDate) ||
+ isSameDay({ ...monthDate, month: monthNumber + 1 }, minimumDate));
+ const isSelected = monthNumber === activeDate.month;
+ return (
+
+
+
+ );
+ });
+ return (
+
+
+
+ {renderMonthSelectorItems()}
+
+
+
+ );
+};
+
+export default MonthSelector;
diff --git a/src/components/Calendar/CalendarComponents/components/YearSelector.js b/src/components/Calendar/CalendarComponents/components/YearSelector.js
new file mode 100644
index 0000000..115bad6
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/components/YearSelector.js
@@ -0,0 +1,99 @@
+import React, { useRef, useEffect } from 'react';
+
+import { MINIMUM_SELECTABLE_YEAR_SUBTRACT, MAXIMUM_SELECTABLE_YEAR_SUM } from '../shared/constants';
+import handleKeyboardNavigation from '../shared/keyboardNavigation';
+import { useLocaleUtils } from '../shared/hooks';
+
+const YearSelector = ({
+ isOpen,
+ activeDate,
+ onYearSelect,
+ selectorStartingYear,
+ selectorEndingYear,
+ maximumDate,
+ minimumDate,
+ locale,
+}) => {
+ const wrapperElement = useRef(null);
+ const yearListElement = useRef(null);
+
+ const { getLanguageDigits, getToday } = useLocaleUtils(locale);
+ const startingYearValue =
+ selectorStartingYear || getToday().year - MINIMUM_SELECTABLE_YEAR_SUBTRACT;
+ const endingYearValue = selectorEndingYear || getToday().year + MAXIMUM_SELECTABLE_YEAR_SUM;
+ const allYears = [];
+ for (let i = startingYearValue; i <= endingYearValue; i += 1) {
+ allYears.push(i);
+ }
+ useEffect(() => {
+ const classToggleMethod = isOpen ? 'add' : 'remove';
+ const activeSelectorYear = wrapperElement.current.querySelector(
+ '.Calendar__yearSelectorItem.-active',
+ );
+ if (!activeSelectorYear) {
+ throw new RangeError(
+ `Provided value for year is out of selectable year range. You're probably using a wrong locale prop value or your provided value's locale is different from the date picker locale. Try changing the 'locale' prop or the value you've provided.`,
+ );
+ }
+ wrapperElement.current.classList[classToggleMethod]('-faded');
+ yearListElement.current.scrollTop =
+ activeSelectorYear.offsetTop - activeSelectorYear.offsetHeight * 5;
+ yearListElement.current.classList[classToggleMethod]('-open');
+ }, [isOpen]);
+
+ const renderSelectorYears = () => {
+ return allYears.map(item => {
+ const isAfterMaximumDate = maximumDate && item > maximumDate.year;
+ const isBeforeMinimumDate = minimumDate && item < minimumDate.year;
+ const isSelected = activeDate.year === item;
+ return (
+
+
+
+ );
+ });
+ };
+
+ const handleKeyDown = e => {
+ handleKeyboardNavigation(e, { allowVerticalArrows: false });
+ };
+
+ return (
+
+
+
+ {renderSelectorYears()}
+
+
+
+ );
+};
+
+YearSelector.defaultProps = {
+ selectorStartingYear: 0,
+ selectorEndingYear: 0,
+};
+
+export default YearSelector;
diff --git a/src/components/Calendar/CalendarComponents/components/index.js b/src/components/Calendar/CalendarComponents/components/index.js
new file mode 100644
index 0000000..7cc422f
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/components/index.js
@@ -0,0 +1,4 @@
+export { default as Header } from './Header';
+export { default as MonthSelector } from './MonthSelector';
+export { default as YearSelector } from './YearSelector';
+export { default as DaysList } from './DaysList';
diff --git a/src/components/Calendar/CalendarComponents/index.js b/src/components/Calendar/CalendarComponents/index.js
new file mode 100644
index 0000000..a983b77
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/index.js
@@ -0,0 +1,3 @@
+export { default} from './DatePicker';
+export * from './Calendar';
+export { default as utils } from './shared/localeUtils';
diff --git a/src/components/Calendar/CalendarComponents/shared/constants.js b/src/components/Calendar/CalendarComponents/shared/constants.js
new file mode 100644
index 0000000..bceb3a1
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/shared/constants.js
@@ -0,0 +1,104 @@
+export const PERSIAN_NUMBERS = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
+
+export const PERSIAN_MONTHS = [
+ 'فروردین',
+ 'اردیبهشت',
+ 'خرداد',
+ 'تیر',
+ 'مرداد',
+ 'شهریور',
+ 'مهر',
+ 'آبان',
+ 'آذر',
+ 'دی',
+ 'بهمن',
+ 'اسفند',
+];
+
+export const GREGORIAN_MONTHS = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+];
+
+export const PERSIAN_WEEK_DAYS = [
+ {
+ name: 'شنبه',
+ short: 'ش',
+ },
+ {
+ name: 'یکشنبه',
+ short: 'ی',
+ },
+ {
+ name: 'دوشنبه',
+ short: 'د',
+ },
+ {
+ name: 'سه شنبه',
+ short: 'س',
+ },
+ {
+ name: 'چهارشنبه',
+ short: 'چ',
+ },
+ {
+ name: 'پنجشنبه',
+ short: 'پ',
+ },
+ {
+ name: 'جمعه',
+ short: 'ج',
+ isWeekend: true,
+ },
+];
+
+export const GREGORIAN_WEEK_DAYS = [
+ {
+ name: 'Sunday',
+ short: 'S',
+ isWeekend: true,
+ },
+ {
+ name: 'Monday',
+ short: 'M',
+ },
+ {
+ name: 'Tuesday',
+ short: 'T',
+ },
+ {
+ name: 'Wednesday',
+ short: 'W',
+ },
+ {
+ name: 'Thursday',
+ short: 'T',
+ },
+ {
+ name: 'Friday',
+ short: 'F',
+ },
+ {
+ name: 'Saturday',
+ short: 'S',
+ isWeekend: true,
+ },
+];
+
+export const MINIMUM_SELECTABLE_YEAR_SUBTRACT = 100;
+
+export const MAXIMUM_SELECTABLE_YEAR_SUM = 50;
+
+export const TYPE_SINGLE_DATE = 'SINGLE_DATE';
+export const TYPE_RANGE = 'RANGE';
+export const TYPE_MUTLI_DATE = 'MUTLI_DATE';
diff --git a/src/components/Calendar/CalendarComponents/shared/generalUtils.js b/src/components/Calendar/CalendarComponents/shared/generalUtils.js
new file mode 100644
index 0000000..fd379b6
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/shared/generalUtils.js
@@ -0,0 +1,69 @@
+import { TYPE_SINGLE_DATE, TYPE_RANGE, TYPE_MUTLI_DATE } from './constants';
+
+/*
+ These utility functions don't depend on locale of the date picker(Persian or Gregorian)
+*/
+
+const createUniqueRange = (number, startingId) =>
+ Array.from(Array(number).keys()).map(key => ({
+ value: key + 1,
+ id: `${startingId}-${key}`,
+ }));
+
+const isSameDay = (day1, day2) => {
+ if (!day1 || !day2) return false;
+ return day1.day === day2.day && day1.month === day2.month && day1.year === day2.year;
+};
+
+const putZero = number => (number.toString().length === 1 ? `0${number}` : number);
+
+const toExtendedDay = date => [date.year, date.month, date.day];
+
+const shallowClone = value => ({ ...value });
+
+const deepCloneObject = obj =>
+ JSON.parse(JSON.stringify(obj, (key, value) => (typeof value === 'undefined' ? null : value)));
+
+const getDateAccordingToMonth = (date, direction) => {
+ const toSum = direction === 'NEXT' ? 1 : -1;
+ let newMonthIndex = date.month + toSum;
+ let newYear = date.year;
+ if (newMonthIndex < 1) {
+ newMonthIndex = 12;
+ newYear -= 1;
+ }
+ if (newMonthIndex > 12) {
+ newMonthIndex = 1;
+ newYear += 1;
+ }
+ const newDate = { year: newYear, month: newMonthIndex, day: 1 };
+ return newDate;
+};
+
+const hasProperty = (object, propertyName) =>
+ Object.prototype.hasOwnProperty.call(object || {}, propertyName);
+
+const getValueType = value => {
+ if (Array.isArray(value)) return TYPE_MUTLI_DATE;
+ if (hasProperty(value, 'from') && hasProperty(value, 'to')) return TYPE_RANGE;
+ if (
+ !value ||
+ (hasProperty(value, 'year') && hasProperty(value, 'month') && hasProperty(value, 'day'))
+ ) {
+ return TYPE_SINGLE_DATE;
+ }
+ throw new TypeError(
+ `The passed value is malformed! Please make sure you're using one of the valid value types for date picker.`,
+ );
+};
+
+export {
+ createUniqueRange,
+ isSameDay,
+ putZero,
+ toExtendedDay,
+ shallowClone,
+ deepCloneObject,
+ getDateAccordingToMonth,
+ getValueType,
+};
diff --git a/src/components/Calendar/CalendarComponents/shared/hooks.js b/src/components/Calendar/CalendarComponents/shared/hooks.js
new file mode 100644
index 0000000..1656e5b
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/shared/hooks.js
@@ -0,0 +1,10 @@
+import { useMemo } from 'react';
+
+import utils from './localeUtils';
+import getLanguageText from './localeLanguages';
+
+const useLocaleUtils = locale => useMemo(() => utils(locale), [locale]);
+
+const useLocaleLanguage = locale => useMemo(() => getLanguageText(locale), [locale]);
+
+export { useLocaleUtils, useLocaleLanguage };
diff --git a/src/components/Calendar/CalendarComponents/shared/keyboardNavigation.js b/src/components/Calendar/CalendarComponents/shared/keyboardNavigation.js
new file mode 100644
index 0000000..f72d0ae
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/shared/keyboardNavigation.js
@@ -0,0 +1,44 @@
+const handleArrowKeys = (e, { allowVerticalArrows }) => {
+ const { activeElement } = document;
+ const getNthChildSafe = (element, index) => (element ? element.children[index] : null);
+ const getStandardItem = item => item && (item.hasAttribute('aria-hidden') ? null : item);
+ const { nextSibling: nextRow, previousSibling: previousRow } = activeElement.parentElement;
+ const nextSibling = getStandardItem(activeElement.nextSibling || getNthChildSafe(nextRow, 0));
+ const previousRowLength = previousRow ? previousRow.children.length - 1 : 0;
+ const previousSibling = getStandardItem(
+ activeElement.previousSibling || getNthChildSafe(previousRow, previousRowLength),
+ );
+ const getVerticalSibling = row =>
+ getNthChildSafe(row, Array.from(activeElement.parentElement.children).indexOf(activeElement));
+ const downSibling = getStandardItem(getVerticalSibling(nextRow));
+ const upSibling = getStandardItem(getVerticalSibling(previousRow));
+ const isDefaultSelectable = activeElement.dataset.isDefaultSelectable === 'true';
+
+ if (!isDefaultSelectable) activeElement.tabIndex = '-1';
+ const focusIfAvailable = element => {
+ e.preventDefault();
+ /* istanbul ignore else */
+ if (element) {
+ element.setAttribute('tabindex', '0');
+ element.focus();
+ }
+ };
+ switch (e.key) {
+ case 'ArrowRight':
+ focusIfAvailable(nextSibling);
+ break;
+ case 'ArrowLeft':
+ focusIfAvailable(previousSibling);
+ break;
+ case 'ArrowDown':
+ /* istanbul ignore else */
+ if (allowVerticalArrows) focusIfAvailable(downSibling);
+ break;
+ case 'ArrowUp':
+ /* istanbul ignore else */
+ if (allowVerticalArrows) focusIfAvailable(upSibling);
+ break;
+ }
+};
+
+export default handleArrowKeys;
diff --git a/src/components/Calendar/CalendarComponents/shared/localeLanguages.js b/src/components/Calendar/CalendarComponents/shared/localeLanguages.js
new file mode 100644
index 0000000..806b1f5
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/shared/localeLanguages.js
@@ -0,0 +1,85 @@
+import jalaali from 'jalaali-js';
+
+import {
+ GREGORIAN_MONTHS,
+ PERSIAN_MONTHS,
+ GREGORIAN_WEEK_DAYS,
+ PERSIAN_WEEK_DAYS,
+ PERSIAN_NUMBERS,
+} from './constants';
+import { toExtendedDay } from './generalUtils';
+
+const localeLanguages = {
+ en: {
+ months: GREGORIAN_MONTHS,
+ weekDays: GREGORIAN_WEEK_DAYS,
+ weekStartingIndex: 0,
+ getToday(gregorainTodayObject) {
+ return gregorainTodayObject;
+ },
+ toNativeDate(date) {
+ return new Date(date.year, date.month - 1, date.day);
+ },
+ getMonthLength(date) {
+ return new Date(date.year, date.month, 0).getDate();
+ },
+ transformDigit(digit) {
+ return digit;
+ },
+ nextMonth: 'Next Month',
+ previousMonth: 'Previous Month',
+ openMonthSelector: 'Open Month Selector',
+ openYearSelector: 'Open Year Selector',
+ closeMonthSelector: 'Close Month Selector',
+ closeYearSelector: 'Close Year Selector',
+ from: 'from',
+ to: 'to',
+ defaultPlaceholder: 'Select...',
+ digitSeparator: ',',
+ yearLetterSkip: 0,
+ isRtl: false,
+ },
+ fa: {
+ months: PERSIAN_MONTHS,
+ weekDays: PERSIAN_WEEK_DAYS,
+ weekStartingIndex: 1,
+ getToday({ year, month, day }) {
+ const { jy, jm, jd } = jalaali.toJalaali(year, month, day);
+ return { year: jy, month: jm, day: jd };
+ },
+ toNativeDate(date) {
+ const gregorian = jalaali.toGregorian(...toExtendedDay(date));
+ return new Date(gregorian.gy, gregorian.gm - 1, gregorian.gd);
+ },
+ getMonthLength(date) {
+ return jalaali.jalaaliMonthLength(date.year, date.month);
+ },
+ transformDigit(digit) {
+ return digit
+ .toString()
+ .split('')
+ .map(letter => PERSIAN_NUMBERS[Number(letter)])
+ .join('');
+ },
+ nextMonth: 'ماه بعد',
+ previousMonth: 'ماه قبل',
+ openMonthSelector: 'نمایش انتخابگر ماه',
+ openYearSelector: 'نمایش انتخابگر سال',
+ closeMonthSelector: 'بستن انتخابگر ماه',
+ closeYearSelector: 'بستن انتخابگر ماه',
+ from: 'از',
+ to: 'تا',
+ defaultPlaceholder: 'انتخاب...',
+ digitSeparator: '،',
+ yearLetterSkip: -2,
+ isRtl: true,
+ },
+};
+
+const getLocaleDetails = locale => {
+ if (typeof locale === 'string') return localeLanguages[locale];
+ return locale;
+};
+
+export { localeLanguages };
+export default getLocaleDetails;
diff --git a/src/components/Calendar/CalendarComponents/shared/localeUtils.js b/src/components/Calendar/CalendarComponents/shared/localeUtils.js
new file mode 100644
index 0000000..1055f94
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/shared/localeUtils.js
@@ -0,0 +1,61 @@
+/*
+ These utility functions highly depend on locale of the date picker(Persian or Gregorian)
+*/
+
+import getLocaleDetails from './localeLanguages';
+
+const utils = (locale = 'en') => {
+ const {
+ months: monthsList,
+ getToday: localeGetToday,
+ toNativeDate,
+ getMonthLength,
+ weekStartingIndex,
+ transformDigit: getLanguageDigits,
+ } = typeof locale === 'string' ? getLocaleDetails(locale) : locale;
+
+ const getToday = () => {
+ const todayDate = new Date();
+ const year = todayDate.getFullYear();
+ const month = todayDate.getMonth() + 1;
+ const day = todayDate.getDate();
+ return localeGetToday({ year, month, day });
+ };
+
+ const getMonthName = month => monthsList[month - 1];
+
+ const getMonthNumber = monthName => monthsList.indexOf(monthName) + 1;
+
+ const getMonthFirstWeekday = date => {
+ const gregorianDate = toNativeDate({ ...date, day: 1 });
+ const weekday = gregorianDate.getDay();
+ const dayIndex = weekday + weekStartingIndex;
+ return dayIndex % 7;
+ };
+
+ const isBeforeDate = (day1, day2) => {
+ if (!day1 || !day2) return false;
+ return toNativeDate(day1) < toNativeDate(day2);
+ };
+
+ const checkDayInDayRange = ({ day, from, to }) => {
+ if (!day || !from || !to) return false;
+ const nativeDay = toNativeDate(day);
+ const nativeFrom = toNativeDate(from);
+ const nativeTo = toNativeDate(to);
+ return nativeDay > nativeFrom && nativeDay < nativeTo;
+ };
+
+ return {
+ getToday,
+ getMonthName,
+ getMonthNumber,
+ getMonthLength,
+ getMonthFirstWeekday,
+ isBeforeDate,
+ checkDayInDayRange,
+ getLanguageDigits,
+ };
+};
+
+export default utils;
diff --git a/src/components/Calendar/CalendarComponents/shared/sliderHelpers.js b/src/components/Calendar/CalendarComponents/shared/sliderHelpers.js
new file mode 100644
index 0000000..524e49a
--- /dev/null
+++ b/src/components/Calendar/CalendarComponents/shared/sliderHelpers.js
@@ -0,0 +1,33 @@
+import { getDateAccordingToMonth } from './generalUtils';
+
+const getSlideDate = ({ parent, isInitialActiveChild, activeDate, monthChangeDirection }) => {
+ if (!parent) {
+ return isInitialActiveChild ? activeDate : getDateAccordingToMonth(activeDate, 'NEXT');
+ }
+ const child = parent.children[isInitialActiveChild ? 0 : 1];
+ const isActiveSlide =
+ child.classList.contains('-shown') || child.classList.contains('-shownAnimated'); // check -shownAnimated for Safari bug
+ return isActiveSlide ? activeDate : getDateAccordingToMonth(activeDate, monthChangeDirection);
+};
+
+const animateContent = ({ parent, direction }) => {
+ const wrapperChildren = Array.from(parent.children);
+ const shownItem = wrapperChildren.find(child => child.classList.contains('-shown'));
+ const hiddenItem = wrapperChildren.find(child => child !== shownItem);
+ const baseClass = shownItem.classList[0];
+ const isNextMonth = direction === 'NEXT';
+ const getAnimationClass = value => (value ? '-hiddenNext' : '-hiddenPrevious');
+ hiddenItem.style.transition = 'none';
+ shownItem.style.transition = '';
+ shownItem.className = `${baseClass} ${getAnimationClass(!isNextMonth)}`;
+ hiddenItem.className = `${baseClass} ${getAnimationClass(isNextMonth)}`;
+ hiddenItem.classList.add('-shownAnimated');
+};
+
+const handleSlideAnimationEnd = ({ target }) => {
+ target.classList.remove('-hiddenNext');
+ target.classList.remove('-hiddenPrevious');
+ target.classList.replace('-shownAnimated', '-shown');
+};
+
+export { animateContent, getSlideDate, handleSlideAnimationEnd };
diff --git a/src/components/Calendar/index.css b/src/components/Calendar/index.css
index b27a926..a1681c8 100644
--- a/src/components/Calendar/index.css
+++ b/src/components/Calendar/index.css
@@ -1,3 +1,7 @@
+.Calendar *{
+ font-family: 'iranSans';
+}
+
.DatePicker {
position: relative;
display: inline-block;
@@ -537,23 +541,29 @@
}
.Calendar__day {
- display: block;
- width: calc(100% / 7);
+ width: calc(100% / 7 - 6px);
text-align: center;
padding: calc(0.25em - 1px);
font-size: 1.6em;
border-radius: 7px;
transition: 0.2s;
border: 1px solid transparent;
- margin:0.2em;
+ margin:3px;
color: rgba(0, 0, 0, 0.8);
display: flex;
- justify-content: center;
align-items: center;
+
cursor: pointer;
+ vertical-align: middle;
background-color: #F3F3F3;
color:#06BACE;
+ }
+ .Calendar__day span{
+ padding: -10px;
+ margin-top: -30px;
+ font-size: 28px;
+
}
.Calendar__day:focus {
@@ -666,7 +676,42 @@
position: relative;
z-index: 1;
}
-
+ .Calendar__footer .footer__Events{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ font-size: 12px;
+ font-family: 'IranSans';
+ padding: 3px;
+ }
+
+ .Calendar .holiday span{
+ color:#ff2929;
+ }
+ .Calendar .DayNumDiv{
+ display: flex;
+ flex-direction: column;
+ }
+ .Calendar .DayNumDiv span{
+ margin: 0;
+ padding: 0;
+ margin-bottom: -5px;
+ }
+ .Calendar .DayNumDiv .eventDots{
+ margin-top: -10px;
+ font-size: 20px;
+ }
+ .GoToTodayButton{
+ background-color: #006C94;
+ padding: 7.5px;
+ font-size: 12px;
+ color:white;
+ font-family: 'iranSans';
+ border-radius: 50%;
+ float: left;
+ margin: 15px;
+
+ }
@keyframes fadeCalendar {
from {
opacity: 0;
diff --git a/src/components/Calendar/index.js b/src/components/Calendar/index.js
index 08e03e4..bba8cf4 100644
--- a/src/components/Calendar/index.js
+++ b/src/components/Calendar/index.js
@@ -1,28 +1,84 @@
import React, { useState } from "react";
import './index.css';
-import {Calendar, utils} from "react-modern-calendar-datepicker";
+import Calendar from "./CalendarComponents/Calendar";
+import { utils } from "./CalendarComponents";
import './index.css';
-const SimpleCalendar = () =>{
+const SimpleCalendar = () => {
const [selectedDay, setSelectedDay] = useState(null);
- const gotoToday = () =>{
- setSelectedDay(utils('fa').getToday());
- }
- return(
+
+ return (
-
- }
- locale="fa" // add this
- />
+
+ }
+ locale="fa"
+ events={eventsList}
+ />
);
};
+const eventsList = [
+ {
+ id: 2,
+ description: "تست 2",
+ type: "global",
+ isHoliday: true,
+ date: "2022-01-04T00:00:00.000Z",
+ year: 1400,
+ month: 10,
+ day: 2
+ },
+ {
+ id: 4,
+ description: "تست 4",
+ type: "global",
+ isHoliday: true,
+ date: "2022-01-12T00:00:00.000Z",
+ year: 1400,
+ month: 10,
+ day: 1
+ },
+ {
+ id: 1,
+ description: "تست کاربر 1",
+ type: "userDefined",
+ userId: "5",
+ date: "2022-01-12T00:00:00.000Z",
+ categoryId: 1,
+ year: 1400,
+ month: 10,
+ day: 3,
+ color: 'blue'
+ },
+ {
+ id: 4,
+ description: "تست کاربر 4",
+ type: "userDefined",
+ userId: "5",
+ date: "2022-01-08T00:00:00.000Z",
+ categoryId: 3,
+ year: 1400,
+ month: 11,
+ day: 6
+ },
+ {
+ id: 5,
+ description: "تست کاربر 5",
+ type: "userDefined",
+ userId: "5",
+ date: "2022-01-12T00:00:00.000Z",
+ categoryId: 1,
+ year: 1400,
+ month: 10,
+ day: 3
+ }
+];
export default SimpleCalendar;
\ No newline at end of file
diff --git a/src/components/Comments/index.js b/src/components/Comments/index.js
index a9e37bb..0314108 100644
--- a/src/components/Comments/index.js
+++ b/src/components/Comments/index.js
@@ -47,7 +47,7 @@ export const Comments = ({ comments }) => {
- fuck
+ Stars
{comment.status === true && (
<>
diff --git a/src/components/RangeDatePicker/index.css b/src/components/RangeDatePicker/index.css
new file mode 100644
index 0000000..a1681c8
--- /dev/null
+++ b/src/components/RangeDatePicker/index.css
@@ -0,0 +1,750 @@
+.Calendar *{
+ font-family: 'iranSans';
+}
+
+.DatePicker {
+ position: relative;
+ display: inline-block;
+ z-index: 100;
+ }
+
+ .DatePicker__input {
+ background: #fff;
+ border: 1px solid rgba(0, 0, 0, 0.4);
+ padding: 0.6em 1.2em;
+ font-family:'iranSans';
+ text-align: center;
+ font-size: 12px;
+ border-radius: 7px;
+
+ }
+ .DatePicker__input:focus{
+ outline:1px solid #06BACE;
+ color: #06BACE;
+ }
+
+ .DatePicker__input.-rtl {
+ direction: rtl;
+ }
+
+ .DatePicker__input::placeholder {
+ color: #979797;
+ }
+ .DatePicker__input:focus::placeholder{
+ color: #06BACE;
+ }
+
+ .DatePicker__calendarContainer.-top + .DatePicker__calendarArrow {
+ top: auto;
+ bottom: calc(100% + 10px);
+ transform: translateY(-2.5rem) rotate(180deg);
+ animation: fadeArrowFlipped 0.3s forwards;
+ }
+
+ .DatePicker__calendarContainer {
+ position: absolute;
+ top: calc(100% + 20px);
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ .DatePicker__calendarContainer.-top {
+ top: auto;
+ bottom: calc(100% + 20px);
+ }
+
+ .Calendar,
+ .Calendar * {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ direction: ltr;
+ }
+
+ .Calendar,
+ .Calendar.-rtl * {
+ direction: rtl;
+ }
+
+ .DatePicker__calendarArrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ top: calc(100% + 10px);
+ left: 0;
+ right: 0;
+ margin: 0 auto;
+ border-style: solid;
+ z-index: 10;
+ border-width: 0 10px 10px 10px;
+ border-color: transparent transparent #fff transparent;
+
+ }
+
+ .Calendar {
+ --cl-color-black: #444444;
+ --cl-color-disabled: #d4d4d4;
+ --cl-color-error: #ff2929;
+ font-family:'iranSans';
+ font-size: 10px;
+ background: rgba(245, 245, 245, 0.53);
+ border:1px solid #DBDBDB;
+ box-shadow: 0 1em em rgba(0, 0, 0, 0.07);
+ border-radius: 1em;
+ position: relative;
+ user-select: none;
+ padding-top: 1.2em;
+ display: flex;
+ flex-direction: column;
+ width: 40em;
+ z-index: 10;
+ max-width: 90vw;
+ min-height: 38.7em;
+ }
+
+ .DatePicker .Calendar,
+ .DatePicker__calendarArrow {
+ transform: translateY(2.5em);
+ opacity: 0;
+ animation: fadeCalendar 0.3s forwards;
+
+ }
+
+ .DatePicker__calendarContainer.-top .Calendar {
+ transform: translateY(-2.5em);
+ }
+
+ .Calendar.-noFocusOutline *:focus {
+ outline: none !important;
+ }
+
+ .Calendar > :not(.Calendar__footer) button {
+ font-family: inherit;
+ background: transparent;
+ cursor: pointer;
+ -webkit-tap-highlight-color: transparent;
+ outline: none;
+ }
+
+ .Calendar__header {
+ display: flex;
+ color: var(--cl-color-black);
+ padding: 2em 2.9em;
+ align-items: center;
+ overflow: hidden;
+ }
+
+ .Calendar__monthArrowWrapper {
+ line-height: 0;
+ font-size: 1em;
+ padding: 3px;
+ position: relative;
+ border: none;
+ z-index: 1;
+ opacity: 1;
+ transition: 0.2s;
+ background-color: #06BACE;
+ }
+
+ .Calendar__monthArrowWrapper:focus {
+ outline: 1px dashed rgba(0, 0, 0, 0.4);
+ outline-offset: 2px;
+ }
+
+ .Calendar__monthArrowWrapper:disabled,
+ .Calendar__monthArrowWrapper.-hidden {
+ opacity: 0;
+ pointer-events: none;
+ }
+
+ .Calendar__monthArrowWrapper.-left {
+ transform: rotate(180deg);
+ }
+ .Calendar.-rtl .Calendar__monthArrowWrapper.-left {
+ transform: rotate(-180deg);
+ }
+
+ .Calendar__monthArrowWrapper.-right {
+ transform: rotate(-0deg);
+
+ }
+ .Calendar.-rtl .Calendar__monthArrowWrapper.-right {
+ transform: rotate(0deg);
+ }
+
+ .Calendar__monthArrowWrapper:active .Calendar__monthArrow {
+ transform: scale(0.7);
+ }
+
+ .Calendar__monthArrow {
+ border-radius: 7px;
+ padding: 12px;
+ transition: var(--animation-duration) transform;
+ pointer-events: none;
+ background-repeat: no-repeat;
+ display: block;
+ width: 0.7em;
+ height: 0.7em;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='15' height='15' viewBox='0 0 50 80' xml:space='preserve'%3E%3Cpolyline fill='none' stroke='%23FFFFFF' stroke-width='15' stroke-linecap='round' stroke-linejoin='round' points=' 0.375,0.375 45.63,38.087 0.375,75.8 '/%3E%3C/svg%3E"); background-size: 100% 100%;
+ background-color: #06BACE;
+ background-size: 10px;
+ background-position: center;
+ }
+
+ .Calendar__monthYearContainer {
+ flex: 1;
+ position: relative;
+ }
+
+ .Calendar__monthYear {
+ font-size: 2em;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 50%;
+ will-change: transform, opacity;
+ backface-visibility: hidden;
+ transform: translateZ(0);
+ transition: var(--animation-duration);
+ line-height: 1;
+ color:#246E8A;
+ }
+
+ .Calendar__monthYear.-hiddenNext {
+ opacity: 0;
+ transform: translateX(50%);
+ }
+
+ .Calendar.-rtl .Calendar__monthYear.-hiddenNext {
+ transform: translateX(-150%);
+ }
+
+ .Calendar__monthYear.-hiddenPrevious {
+ opacity: 0;
+ transform: translateX(-150%);
+ }
+
+ .Calendar.-rtl .Calendar__monthYear.-hiddenPrevious {
+ transform: translateX(50%);
+ }
+
+ .Calendar__monthYear.-shown {
+ opacity: 1;
+ margin-top: auto;
+ margin-bottom: auto;
+ transform: translateX(-50%);
+ }
+
+ .Calendar__monthYear.-shownAnimated {
+ animation: var(--animation-duration) fadeTextToCenter forwards;
+ }
+
+ .Calendar__monthYear > * {
+ padding: 0.2em 0.5em;
+ border: 1px solid transparent;
+ transition: var(--animation-duration);
+ font-size: 1.05em;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transform: translateX(0) scale(0.95);
+ will-change: transform;
+ border-radius: 5px;
+ }
+
+ .Calendar__monthYear:not(.-shown) > *,
+ .Calendar__monthYear > *.-hidden {
+ cursor: default;
+ pointer-events: none;
+ }
+
+ .Calendar__monthText {
+ margin-left: -0.3em;
+ }
+ .Calendar__yearText:last-child {
+ margin-right: -0.3em;
+ }
+
+ .Calendar__monthYear.-shown > *:hover,
+ .Calendar:not(.-noFocusOutline) .Calendar__monthYear.-shown > *:focus,
+ .Calendar__monthYear > *.-activeBackground {
+ background: #f5f5f5;
+ }
+
+ .Calendar__monthText:hover {
+ transform: translateX(-0.2em) scale(0.95);
+ }
+ .Calendar.-rtl .Calendar__monthText:hover {
+ transform: translateX(0.2em) scale(0.95);
+ }
+
+ .Calendar__yearText:hover {
+ transform: translateX(0.2em) scale(0.95);
+ }
+ .Calendar.-rtl .Calendar__yearText:hover {
+ transform: translateX(-0.2em) scale(0.95);
+ }
+
+ .Calendar__monthYear .Calendar__yearText.-hidden {
+ transform: translateX(50%);
+ opacity: 0;
+ }
+
+ .Calendar.-rtl .Calendar__monthYear .Calendar__yearText.-hidden {
+ transform: translateX(-50%);
+ }
+
+ .Calendar__monthYear .Calendar__monthText.-hidden {
+ transform: translateX(-50%);
+ opacity: 0;
+ }
+
+ .Calendar.-rtl .Calendar__monthYear .Calendar__monthText.-hidden {
+ transform: translateX(50%);
+ }
+
+ .Calendar__monthYear:not(.-shown) > * {
+ pointer-events: none;
+ }
+
+ .Calendar__monthSelectorAnimationWrapper,
+ .Calendar__yearSelectorAnimationWrapper {
+ position: absolute;
+ width: 100%;
+ height: 80%;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+ }
+
+ .Calendar__monthSelectorWrapper {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .Calendar__monthSelector {
+ padding: 0 2.5em;
+ align-content: center;
+ padding-bottom: 2em;
+ }
+
+ .Calendar__monthSelector,
+ .Calendar__yearSelector {
+ display: flex;
+ flex-wrap: wrap;
+ position: relative;
+ z-index: 2;
+ background-color: #fff;
+ transform: translateY(-150%);
+ will-change: transform;
+ transition: 0.6s;
+ height: 100%;
+ }
+
+ .Calendar__yearSelectorWrapper {
+ width: 100%;
+ height: 100%;
+ }
+
+ .Calendar__yearSelectorWrapper::after,
+ .Calendar__yearSelectorWrapper::before {
+ content: '';
+ width: 100%;
+ height: 5em;
+ position: absolute;
+ left: 0;
+ opacity: 0;
+ transition: 0.4s;
+ transition-delay: 0.2s;
+ }
+
+ .Calendar__yearSelectorWrapper::after {
+ background-image: linear-gradient(to bottom, #fff, #fff 10%, rgba(245, 245, 245, 0));
+ top: -0.1em;
+ }
+
+ .Calendar__yearSelectorWrapper::before {
+ background-image: linear-gradient(to top, #fff, #fff 10%, rgba(245, 245, 245, 0));
+ bottom: 0;
+ }
+
+ .Calendar__yearSelectorWrapper.-faded::after,
+ .Calendar__yearSelectorWrapper.-faded::before {
+ opacity: 1;
+ z-index: 3;
+ }
+
+ .Calendar__yearSelector {
+ align-content: flex-start;
+ scrollbar-width: 0;
+ overflow: scroll;
+ position: relative;
+ width: 100%;
+ padding: 5em 2em;
+ -ms-overflow-style: none;
+ }
+
+ .Calendar__yearSelector::-webkit-scrollbar {
+ display: none;
+ }
+
+ .Calendar__yearSelectorItem {
+ width: 25%;
+ display: flex;
+ justify-content: center;
+ }
+
+ .Calendar__yearSelectorItem:not(:nth-child(-n + 4)) {
+ margin-top: 1.5em;
+ }
+
+ .Calendar__yearSelectorText {
+ border: none;
+ font-size: 1.4em;
+ min-width: 85%;
+ padding: 0.2em 0.5em;
+ border-radius: 5px;
+ }
+
+ .Calendar__monthSelector.-open,
+ .Calendar__yearSelector.-open {
+ transform: translateY(0);
+ }
+
+ .Calendar__yearSelectorText:focus,
+ .Calendar__monthSelectorItemText:focus {
+ outline: 1px dashed rgba(0, 0, 0, 0.4);
+ outline-offset: 2px;
+ }
+
+ .Calendar__monthSelectorItem {
+ width: calc(100% / 3);
+ display: flex;
+ justify-content: center;
+ }
+
+ .Calendar__monthSelectorItem:not(:nth-child(-n + 3)) {
+ margin-top: 2em;
+ }
+
+ .Calendar__monthSelectorItemText {
+ border: none;
+ padding: 0.4em 0.4em;
+ border-radius: 8.5px;
+ font-size: 1.3em;
+ min-width: 70%;
+ transition: 0.3s;
+ }
+
+ .Calendar__monthSelectorItem:not(.-active) .Calendar__monthSelectorItemText:not(:disabled):hover,
+ .Calendar__yearSelectorItem:not(.-active) .Calendar__yearSelectorText:not(:disabled):hover {
+ background: #f5f5f5;
+ }
+
+ .Calendar__monthSelectorItemText:disabled,
+ .Calendar__yearSelectorText:disabled {
+ opacity: 0.5;
+ cursor: default;
+ }
+
+ .Calendar__monthSelectorItem.-active .Calendar__monthSelectorItemText,
+ .Calendar__yearSelectorItem.-active .Calendar__yearSelectorText {
+ background-color: #006C94;
+ color: #fff;
+ }
+
+ .Calendar__weekDays {
+ display: flex;
+ justify-content: space-between;
+ color: var(--cl-color-disabled);
+ font-size: 1.2em;
+ margin-bottom: 0.7em;
+ padding: 0 2.6em;
+ position: relative;
+ }
+
+ .Calendar__weekDay {
+ display: block;
+ width: calc(100% / 7);
+
+ text-align: center;
+ text-decoration: none;
+ border: 0px;
+ color: #06BACE;
+ margin:0.2em;
+ white-space: nowrap;
+ }
+ .Calendar__weekDay[title]{
+ text-decoration: none;
+ }
+
+ .Calendar__sectionWrapper {
+ position: relative;
+ min-height: 25.8em;
+ overflow: hidden;
+ }
+
+ .Calendar__section {
+ display: flex;
+ flex-direction: column;
+ padding: 0 3.2em;
+ position: absolute;
+ color: var(--cl-color-black);
+ top: 0;
+ padding-top: 0.5em;
+ left: 0;
+ width: 100%;
+ will-change: transform, opacity;
+ transform: translateZ(0);
+ backface-visibility: hidden;
+ transition: var(--animation-duration);
+ }
+
+ .Calendar__section.-hiddenPrevious {
+ opacity: 0.5;
+ transform: translateX(-90%);
+ }
+
+ .Calendar.-rtl .Calendar__section.-hiddenPrevious {
+ transform: translateX(90%);
+ }
+
+ .Calendar__section.-hiddenNext {
+ opacity: 0.5;
+ transform: translateX(90%);
+ }
+
+ .Calendar.-rtl .Calendar__section.-hiddenNext {
+ transform: translateX(-90%);
+ }
+
+ .Calendar__section.-shown {
+ opacity: 1;
+ transform: translateX(0);
+ }
+
+ .Calendar__section.-shownAnimated {
+ animation: var(--animation-duration) FadeContentToCenter forwards;
+ }
+
+ .Calendar__weekRow {
+ display: flex;
+ width: 100%;
+ }
+
+ .Calendar__day {
+ width: calc(100% / 7 - 6px);
+ text-align: center;
+ padding: calc(0.25em - 1px);
+ font-size: 1.6em;
+ border-radius: 7px;
+ transition: 0.2s;
+ border: 1px solid transparent;
+ margin:3px;
+ color: rgba(0, 0, 0, 0.8);
+ display: flex;
+ align-items: center;
+
+ cursor: pointer;
+ vertical-align: middle;
+ background-color: #F3F3F3;
+ color:#06BACE;
+
+ }
+ .Calendar__day span{
+ padding: -10px;
+ margin-top: -30px;
+ font-size: 28px;
+
+ }
+
+ .Calendar__day:focus {
+ outline: 1px dashed rgba(0, 0, 0, 0.4);
+ outline-offset: 2px;
+ }
+
+ .Calendar__day.-ltr {
+ min-height: 2.6em;
+ font-size: 1.45em;
+ }
+
+ .Calendar__day.-rtl {
+ font-size: 1.55em;
+ height: 2.45em;
+ }
+
+ .Calendar__day:not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween):not(.-selected):hover {
+
+ background-color: #DAFBFF;
+ color: #06BACE;
+ border:1px solid #06BACE;
+ }
+
+ .Calendar__day.-selected,
+ .Calendar__day.-selectedStart,
+ .Calendar__day.-selectedEnd {
+ background: #006C94;
+ color: #fff;
+ }
+
+ .Calendar__day.-ltr.-selectedStart {
+ border-radius: 0;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ }
+
+ .Calendar__day.-rtl.-selectedStart {
+ border-radius: 0;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+ }
+
+ .Calendar__day.-selectedBetween {
+ background:rgba(0, 108, 148, 0.07);
+
+ border-radius: 0;
+ }
+
+ .Calendar__day.-ltr.-selectedEnd {
+ border-radius: 0;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+ }
+
+ .Calendar__day.-rtl.-selectedEnd {
+ border-radius: 0;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ }
+
+ .Calendar__day.-weekend:not(.-selected):not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween) {
+ color: var(--cl-color-error);
+ }
+
+ .Calendar__day.-weekend.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after {
+ background: var(--cl-color-error);
+ }
+
+ .Calendar__day.-disabled {
+ color: var(--cl-color-disabled) !important;
+ background: transparent !important;
+ cursor: default !important;
+ }
+ .Calendar__day.-selected {
+
+ }
+ .Calendar__day.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween) {
+ font-weight: 600;
+ color: var(--cl-color-black);
+ color: #000;
+ position: relative;
+ }
+
+ .Calendar__day.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after {
+ content: '';
+ position: absolute;
+ bottom: 0.2em;
+ display: block;
+ width: 0.6em;
+ height: 1px;
+ background: #000;
+ left: 50%;
+ opacity: 0.5;
+ transform: translateX(-50%);
+ transition: 0.2s;
+ }
+
+ .Calendar__day.-today:hover:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after {
+ opacity: 0;
+ }
+
+ .Calendar__day.-blank {
+ color: transparent;
+ cursor: default;
+ pointer-events: none;
+ }
+
+ .Calendar__footer {
+ position: relative;
+ z-index: 1;
+ }
+ .Calendar__footer .footer__Events{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ font-size: 12px;
+ font-family: 'IranSans';
+ padding: 3px;
+ }
+
+ .Calendar .holiday span{
+ color:#ff2929;
+ }
+ .Calendar .DayNumDiv{
+ display: flex;
+ flex-direction: column;
+ }
+ .Calendar .DayNumDiv span{
+ margin: 0;
+ padding: 0;
+ margin-bottom: -5px;
+ }
+ .Calendar .DayNumDiv .eventDots{
+ margin-top: -10px;
+ font-size: 20px;
+ }
+ .GoToTodayButton{
+ background-color: #006C94;
+ padding: 7.5px;
+ font-size: 12px;
+ color:white;
+ font-family: 'iranSans';
+ border-radius: 50%;
+ float: left;
+ margin: 15px;
+
+ }
+ @keyframes fadeCalendar {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ @keyframes fadeArrowFlipped {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0) rotate(180deg);
+ }
+ }
+
+ @keyframes fadeTextToCenter {
+ to {
+ opacity: 1;
+ transform: translateX(-50%);
+ }
+ }
+
+ @keyframes FadeContentToCenter {
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ }
+
\ No newline at end of file
diff --git a/src/components/RangeDatePicker/index.js b/src/components/RangeDatePicker/index.js
index 1c9dbc6..483a6fd 100644
--- a/src/components/RangeDatePicker/index.js
+++ b/src/components/RangeDatePicker/index.js
@@ -1,6 +1,6 @@
import React, { useState } from "react";
-import "../Calendar/index.css";
-import DatePicker from "react-modern-calendar-datepicker";
+import "./index.css";
+import DatePicker from "../Calendar/CalendarComponents";
const RangeDatePicker = () => {
const [selectedDayRange, setSelectedDayRange] = useState({
@@ -15,6 +15,7 @@ const RangeDatePicker = () => {
inputPlaceholder="یک بازه زمانی انتخاب کنید"
shouldHighlightWeekends
locale='fa'
+
/>
);
};
diff --git a/src/components/SidebarCategoryHover/index.js b/src/components/SidebarCategoryHover/index.js
index 1c82ed8..72c9731 100644
--- a/src/components/SidebarCategoryHover/index.js
+++ b/src/components/SidebarCategoryHover/index.js
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import category from "./data";
-import List from "./List";
+import List from "./list";
import _ from "lodash";
export default function SidebarCategoryHover() {
diff --git a/src/components/SimpleDatePicker/index.js b/src/components/SimpleDatePicker/index.js
index bfef5af..25c00f8 100644
--- a/src/components/SimpleDatePicker/index.js
+++ b/src/components/SimpleDatePicker/index.js
@@ -1,5 +1,6 @@
import React, { useState } from 'react';
-import DatePicker, {utils} from "react-modern-calendar-datepicker";
+import DatePicker from "../Calendar/CalendarComponents";
+import { utils } from "../Calendar/CalendarComponents";
import '../Calendar/index.css';
const SimpleDatePicker = (props) =>{
const [selectedDay, setSelectedDay] = useState(null);