parent
							
								
									3f36c618b4
								
							
						
					
					
						commit
						89f68c5a50
					
				
				 22 changed files with 3157 additions and 8 deletions
			
			
		| @ -0,0 +1,242 @@ | |||||||
|  | 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'; | ||||||
|  | 
 | ||||||
|  | export const Calendar = ({ | ||||||
|  |   value, | ||||||
|  |   onChange, | ||||||
|  |   onDisabledDayError, | ||||||
|  |   calendarClassName, | ||||||
|  |   calendarTodayClassName, | ||||||
|  |   calendarSelectedDayClassName, | ||||||
|  |   calendarRangeStartClassName, | ||||||
|  |   calendarRangeBetweenClassName, | ||||||
|  |   calendarRangeEndClassName, | ||||||
|  |   disabledDays, | ||||||
|  |   colorPrimary, | ||||||
|  |   colorPrimaryLight, | ||||||
|  |   slideAnimationDuration, | ||||||
|  |   minimumDate, | ||||||
|  |   maximumDate, | ||||||
|  |   selectorStartingYear, | ||||||
|  |   selectorEndingYear, | ||||||
|  |   locale, | ||||||
|  |   shouldHighlightWeekends, | ||||||
|  |   renderFooter, | ||||||
|  |   customDaysClassName, | ||||||
|  |   events, | ||||||
|  | }) => { | ||||||
|  |   const calendarElement = useRef(null); | ||||||
|  |   const [mainState, setMainState] = useState({ | ||||||
|  |     activeDate: null, | ||||||
|  |     monthChangeDirection: '', | ||||||
|  |     isMonthSelectorOpen: false, | ||||||
|  |     isYearSelectorOpen: false, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   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) => ( | ||||||
|  |     <abbr key={weekDay.name} title={weekDay.name} className="Calendar__weekDay"> | ||||||
|  |       {weekDay.short} | ||||||
|  |     </abbr> | ||||||
|  |   )); | ||||||
|  | 
 | ||||||
|  |   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 ( | ||||||
|  |     <div | ||||||
|  |       className={`Calendar -noFocusOutline ${calendarClassName} -${isRtl ? 'rtl' : 'ltr' | ||||||
|  |         }`}
 | ||||||
|  |       role="grid" | ||||||
|  |       style={{ | ||||||
|  |         '--cl-color-primary': colorPrimary, | ||||||
|  |         '--cl-color-primary-light': colorPrimaryLight, | ||||||
|  |         '--animation-duration': slideAnimationDuration, | ||||||
|  |       }} | ||||||
|  |       ref={calendarElement} | ||||||
|  |     > | ||||||
|  |       <Header | ||||||
|  |         maximumDate={maximumDate} | ||||||
|  |         minimumDate={minimumDate} | ||||||
|  |         activeDate={activeDate} | ||||||
|  |         onMonthChange={handleMonthChange} | ||||||
|  |         onMonthSelect={toggleMonthSelector} | ||||||
|  |         onYearSelect={toggleYearSelector} | ||||||
|  |         monthChangeDirection={mainState.monthChangeDirection} | ||||||
|  |         isMonthSelectorOpen={mainState.isMonthSelectorOpen} | ||||||
|  |         isYearSelectorOpen={mainState.isYearSelectorOpen} | ||||||
|  |         locale={locale} | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <MonthSelector | ||||||
|  |         isOpen={mainState.isMonthSelectorOpen} | ||||||
|  |         activeDate={activeDate} | ||||||
|  |         onMonthSelect={selectMonth} | ||||||
|  |         maximumDate={maximumDate} | ||||||
|  |         minimumDate={minimumDate} | ||||||
|  |         locale={locale} | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <YearSelector | ||||||
|  |         isOpen={mainState.isYearSelectorOpen} | ||||||
|  |         activeDate={activeDate} | ||||||
|  |         onYearSelect={selectYear} | ||||||
|  |         selectorStartingYear={selectorStartingYear} | ||||||
|  |         selectorEndingYear={selectorEndingYear} | ||||||
|  |         maximumDate={maximumDate} | ||||||
|  |         minimumDate={minimumDate} | ||||||
|  |         locale={locale} | ||||||
|  |       /> | ||||||
|  | 
 | ||||||
|  |       <div className="Calendar__weekDays">{weekdays}</div> | ||||||
|  | 
 | ||||||
|  |       <DaysList | ||||||
|  |         activeDate={activeDate} | ||||||
|  |         value={value} | ||||||
|  |         monthChangeDirection={mainState.monthChangeDirection} | ||||||
|  |         onSlideChange={updateDate} | ||||||
|  |         disabledDays={disabledDays} | ||||||
|  |         onDisabledDayError={onDisabledDayError} | ||||||
|  |         minimumDate={minimumDate} | ||||||
|  |         maximumDate={maximumDate} | ||||||
|  |         onChange={onChange} | ||||||
|  |         calendarTodayClassName={calendarTodayClassName} | ||||||
|  |         calendarSelectedDayClassName={calendarSelectedDayClassName} | ||||||
|  |         calendarRangeStartClassName={calendarRangeStartClassName} | ||||||
|  |         calendarRangeEndClassName={calendarRangeEndClassName} | ||||||
|  |         calendarRangeBetweenClassName={calendarRangeBetweenClassName} | ||||||
|  |         locale={locale} | ||||||
|  |         shouldHighlightWeekends={shouldHighlightWeekends} | ||||||
|  |         customDaysClassName={customDaysClassName} | ||||||
|  |         events={events} | ||||||
|  |         isQuickSelectorOpen={ | ||||||
|  |           mainState.isYearSelectorOpen || mainState.isMonthSelectorOpen | ||||||
|  |         } | ||||||
|  |       /> | ||||||
|  |       <div className="Calendar__footer">{renderFooter()}</div> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Calendar.defaultProps = { | ||||||
|  |   minimumDate: null, | ||||||
|  |   maximumDate: null, | ||||||
|  |   colorPrimary: '#0eca2d', | ||||||
|  |   colorPrimaryLight: '#cff4d5', | ||||||
|  |   slideAnimationDuration: '0.4s', | ||||||
|  |   calendarClassName: '', | ||||||
|  |   locale: 'en', | ||||||
|  |   value: null, | ||||||
|  |   renderFooter: () => null, | ||||||
|  |   customDaysClassName: [], | ||||||
|  |   events: [ | ||||||
|  |     { | ||||||
|  |       id: 1, | ||||||
|  |       day: 15, | ||||||
|  |       occasions: [ | ||||||
|  |         { | ||||||
|  |           title: 'دی به دین روز، چهارمین جشن دیگان', | ||||||
|  |           dotColor: '#eeffds1', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           title: 'lorem', | ||||||
|  |           dotColor: 'blue' | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|  | 
 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       id: 2, | ||||||
|  |       day: 22, | ||||||
|  |       title: 'مصاحبه کاری', | ||||||
|  |       dotColor: 'red', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       id: 3, | ||||||
|  |       title: 'اجاره خانه', | ||||||
|  |       day: 21, | ||||||
|  |       dotColor: 'blue', | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @ -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); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -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 ( | ||||||
|  |     <div | ||||||
|  |       onFocus={openCalendar} | ||||||
|  |       onBlur={handleBlur} | ||||||
|  |       onKeyUp={handleKeyUp} | ||||||
|  |       className={`DatePicker ${wrapperClassName}`} | ||||||
|  |       role="presentation" | ||||||
|  |     > | ||||||
|  |       <DatePickerInput | ||||||
|  |         ref={inputElement} | ||||||
|  |         formatInputText={formatInputText} | ||||||
|  |         value={value} | ||||||
|  |         inputPlaceholder={inputPlaceholder} | ||||||
|  |         inputClassName={inputClassName} | ||||||
|  |         renderInput={renderInput} | ||||||
|  |         inputName={inputName} | ||||||
|  |         locale={locale} | ||||||
|  |       /> | ||||||
|  |       {isCalendarOpen && ( | ||||||
|  |         <> | ||||||
|  |           <div | ||||||
|  |             ref={calendarContainerElement} | ||||||
|  |             className="DatePicker__calendarContainer" | ||||||
|  |             data-testid="calendar-container" | ||||||
|  |             role="presentation" | ||||||
|  |             onMouseDown={() => { | ||||||
|  |               shouldPreventToggle.current = true; | ||||||
|  |             }} | ||||||
|  |           > | ||||||
|  |             <Calendar | ||||||
|  |               value={value} | ||||||
|  |               onChange={handleCalendarChange} | ||||||
|  |               calendarClassName={calendarClassName} | ||||||
|  |               calendarTodayClassName={calendarTodayClassName} | ||||||
|  |               calendarSelectedDayClassName={calendarSelectedDayClassName} | ||||||
|  |               calendarRangeStartClassName={calendarRangeStartClassName} | ||||||
|  |               calendarRangeBetweenClassName={calendarRangeBetweenClassName} | ||||||
|  |               calendarRangeEndClassName={calendarRangeEndClassName} | ||||||
|  |               disabledDays={disabledDays} | ||||||
|  |               colorPrimary={colorPrimary} | ||||||
|  |               colorPrimaryLight={colorPrimaryLight} | ||||||
|  |               slideAnimationDuration={slideAnimationDuration} | ||||||
|  |               onDisabledDayError={onDisabledDayError} | ||||||
|  |               minimumDate={minimumDate} | ||||||
|  |               maximumDate={maximumDate} | ||||||
|  |               selectorStartingYear={selectorStartingYear} | ||||||
|  |               selectorEndingYear={selectorEndingYear} | ||||||
|  |               locale={locale} | ||||||
|  |               shouldHighlightWeekends={shouldHighlightWeekends} | ||||||
|  |               renderFooter={renderFooter} | ||||||
|  |               customDaysClassName={customDaysClassName} | ||||||
|  |             /> | ||||||
|  |           </div> | ||||||
|  |           <div className="DatePicker__calendarArrow" /> | ||||||
|  |         </> | ||||||
|  |       )} | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | DatePicker.defaultProps = { | ||||||
|  |   wrapperClassName: '', | ||||||
|  |   locale: 'en', | ||||||
|  |   calendarPopperPosition: 'auto', | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default DatePicker; | ||||||
| @ -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 }) || ( | ||||||
|  |           <input | ||||||
|  |             data-testid="datepicker-input" | ||||||
|  |             readOnly | ||||||
|  |             ref={ref} | ||||||
|  |             value={getValue()} | ||||||
|  |             name={inputName} | ||||||
|  |             placeholder={placeholderValue} | ||||||
|  |             className={`DatePicker__input -${isRtl ? 'rtl' : 'ltr'} ${inputClassName}`} | ||||||
|  |             aria-label={placeholderValue} | ||||||
|  |           /> | ||||||
|  |         ) | ||||||
|  |       ); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return render(); | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | DatePickerInput.defaultProps = { | ||||||
|  |   formatInputText: () => '', | ||||||
|  |   renderInput: () => null, | ||||||
|  |   inputPlaceholder: '', | ||||||
|  |   inputClassName: '', | ||||||
|  |   inputName: '', | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default DatePickerInput; | ||||||
| @ -0,0 +1,385 @@ | |||||||
|  | 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, | ||||||
|  | }) => { | ||||||
|  |   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, | ||||||
|  |     }); | ||||||
|  |     const specialDay = (sDay) => { | ||||||
|  |       // let specialDayArray = [];
 | ||||||
|  |       // console.log(sDay);
 | ||||||
|  | 
 | ||||||
|  |       // specialDayArray.push(events[i].day);
 | ||||||
|  |       var eventDate; | ||||||
|  |       for (var i = 0; i < events.length; i++) { | ||||||
|  |         if (sDay == events[i].day) { | ||||||
|  |           
 | ||||||
|  |           return sDay; | ||||||
|  |         
 | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       //  sDay = events[0].day;
 | ||||||
|  |       // return sDay;
 | ||||||
|  |       // console.log(sDay);
 | ||||||
|  | 
 | ||||||
|  |       // console.log(specialDayArray[0])
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <div | ||||||
|  |         style={{ | ||||||
|  |           display: 'flex', | ||||||
|  |           flexDirection: 'column', | ||||||
|  |           alignItems: 'center', | ||||||
|  |         }} | ||||||
|  |         tabIndex={shouldEnableKeyboardNavigation ? '0' : '-1'} | ||||||
|  |         key={id} | ||||||
|  |         className={`Calendar__day -${isRtl ? 'rtl' : 'ltr'} ${additionalClass}`} | ||||||
|  |         onClick={() => { | ||||||
|  |           handleDayPress({ ...dayItem, isDisabled }); | ||||||
|  |           console.log(specialDay(day)); | ||||||
|  |           console.log(day) | ||||||
|  |         }} | ||||||
|  |         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)} | ||||||
|  |         {specialDay(day) == day ?  '.' : null} | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   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 ( | ||||||
|  |         <div | ||||||
|  |           key={String(weekRowIndex)} | ||||||
|  |           className="Calendar__weekRow" | ||||||
|  |           role="row" | ||||||
|  |         > | ||||||
|  |           {eachWeekDays} | ||||||
|  |         </div> | ||||||
|  |       ); | ||||||
|  |     }; | ||||||
|  |     return Array.from(Array(6).keys()).map(renderSingleWeekRow); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   const handleKeyDown = (e) => { | ||||||
|  |     handleKeyboardNavigation(e, { allowVerticalArrows: true }); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <div | ||||||
|  |       ref={calendarSectionWrapper} | ||||||
|  |       className="Calendar__sectionWrapper" | ||||||
|  |       role="presentation" | ||||||
|  |       data-testid="days-section-wrapper" | ||||||
|  |       onKeyDown={handleKeyDown} | ||||||
|  |     > | ||||||
|  |       <div | ||||||
|  |         onAnimationEnd={(e) => { | ||||||
|  |           handleSlideAnimationEnd(e); | ||||||
|  |           onSlideChange(); | ||||||
|  |         }} | ||||||
|  |         className="Calendar__section -shown" | ||||||
|  |         role="rowgroup" | ||||||
|  |       > | ||||||
|  |         {renderMonthDays(true)} | ||||||
|  |       </div> | ||||||
|  |       <div | ||||||
|  |         onAnimationEnd={(e) => { | ||||||
|  |           handleSlideAnimationEnd(e); | ||||||
|  |           onSlideChange(); | ||||||
|  |         }} | ||||||
|  |         className="Calendar__section -hiddenNext" | ||||||
|  |         role="rowgroup" | ||||||
|  |       > | ||||||
|  |         {renderMonthDays(false)} | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | DaysList.defaultProps = { | ||||||
|  |   onChange: () => {}, | ||||||
|  |   onDisabledDayError: () => {}, | ||||||
|  |   disabledDays: [], | ||||||
|  |   calendarTodayClassName: '', | ||||||
|  |   calendarSelectedDayClassName: '', | ||||||
|  |   calendarRangeStartClassName: '', | ||||||
|  |   calendarRangeBetweenClassName: '', | ||||||
|  |   calendarRangeEndClassName: '', | ||||||
|  |   shouldHighlightWeekends: false, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default DaysList; | ||||||
| @ -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 ( | ||||||
|  |       <div | ||||||
|  |         onAnimationEnd={handleSlideAnimationEnd} | ||||||
|  |         className={`Calendar__monthYear ${isInitialActiveChild ? '-shown' : '-hiddenNext'}`} | ||||||
|  |         role="presentation" | ||||||
|  |         key={String(isInitialActiveChild)} | ||||||
|  |         {...hiddenStatus} | ||||||
|  |       > | ||||||
|  |         <button | ||||||
|  |           onClick={onMonthSelect} | ||||||
|  |           type="button" | ||||||
|  |           className="Calendar__monthText" | ||||||
|  |           aria-label={isMonthSelectorOpen ? closeMonthSelector : openMonthSelector} | ||||||
|  |           tabIndex={isActiveMonth ? '0' : '-1'} | ||||||
|  |           {...hiddenStatus} | ||||||
|  |         > | ||||||
|  |           {month} | ||||||
|  |         </button> | ||||||
|  |         <button | ||||||
|  |           onClick={onYearSelect} | ||||||
|  |           type="button" | ||||||
|  |           className="Calendar__yearText" | ||||||
|  |           aria-label={isYearSelectorOpen ? closeYearSelector : openYearSelector} | ||||||
|  |           tabIndex={isActiveMonth ? '0' : '-1'} | ||||||
|  |           {...hiddenStatus} | ||||||
|  |         > | ||||||
|  |           {year} | ||||||
|  |         </button> | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <div ref={headerElement} className="Calendar__header"> | ||||||
|  |       <button | ||||||
|  |         className="Calendar__monthArrowWrapper -right" | ||||||
|  |         onClick={() => { | ||||||
|  |           onMonthChangeTrigger('PREVIOUS'); | ||||||
|  |         }} | ||||||
|  |         aria-label={previousMonth} | ||||||
|  |         type="button" | ||||||
|  |         disabled={isPreviousMonthArrowDisabled} | ||||||
|  |       > | ||||||
|  |         <span className="Calendar__monthArrow" /> | ||||||
|  |       </button> | ||||||
|  |       <div | ||||||
|  |         className="Calendar__monthYearContainer" | ||||||
|  |         ref={monthYearWrapperElement} | ||||||
|  |         data-testid="month-year-container" | ||||||
|  |       > | ||||||
|  |           | ||||||
|  |         {monthYearButtons} | ||||||
|  |       </div> | ||||||
|  |       <button | ||||||
|  |         className="Calendar__monthArrowWrapper -left" | ||||||
|  |         onClick={() => { | ||||||
|  |           onMonthChangeTrigger('NEXT'); | ||||||
|  |         }} | ||||||
|  |         aria-label={nextMonth} | ||||||
|  |         type="button" | ||||||
|  |         disabled={isNextMonthArrowDisabled} | ||||||
|  |       > | ||||||
|  |         <span className="Calendar__monthArrow" /> | ||||||
|  |       </button> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default Header; | ||||||
| @ -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 ( | ||||||
|  |         <li | ||||||
|  |           key={persianMonth} | ||||||
|  |           className={`Calendar__monthSelectorItem ${isSelected ? '-active' : ''}`} | ||||||
|  |         > | ||||||
|  |           <button | ||||||
|  |             tabIndex={isSelected && isOpen ? '0' : '-1'} | ||||||
|  |             onClick={() => { | ||||||
|  |               onMonthSelect(monthNumber); | ||||||
|  |             }} | ||||||
|  |             className="Calendar__monthSelectorItemText" | ||||||
|  |             type="button" | ||||||
|  |             disabled={isAfterMaximumDate || isBeforeMinimumDate} | ||||||
|  |             aria-pressed={isSelected} | ||||||
|  |             data-is-default-selectable={isSelected} | ||||||
|  |           > | ||||||
|  |             {persianMonth} | ||||||
|  |           </button> | ||||||
|  |         </li> | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   return ( | ||||||
|  |     <div | ||||||
|  |       role="presentation" | ||||||
|  |       className="Calendar__monthSelectorAnimationWrapper" | ||||||
|  |       {...(isOpen ? {} : { 'aria-hidden': true })} | ||||||
|  |     > | ||||||
|  |       <div | ||||||
|  |         role="presentation" | ||||||
|  |         data-testid="month-selector-wrapper" | ||||||
|  |         className="Calendar__monthSelectorWrapper" | ||||||
|  |         onKeyDown={handleKeyDown} | ||||||
|  |       > | ||||||
|  |         <ul ref={monthSelector} className="Calendar__monthSelector" data-testid="month-selector"> | ||||||
|  |           {renderMonthSelectorItems()} | ||||||
|  |         </ul> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default MonthSelector; | ||||||
| @ -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 ( | ||||||
|  |         <li key={item} className={`Calendar__yearSelectorItem ${isSelected ? '-active' : ''}`}> | ||||||
|  |           <button | ||||||
|  |             tabIndex={isSelected && isOpen ? '0' : '-1'} | ||||||
|  |             className="Calendar__yearSelectorText" | ||||||
|  |             type="button" | ||||||
|  |             onClick={() => { | ||||||
|  |               onYearSelect(item); | ||||||
|  |             }} | ||||||
|  |             disabled={isAfterMaximumDate || isBeforeMinimumDate} | ||||||
|  |             aria-pressed={isSelected} | ||||||
|  |             data-is-default-selectable={isSelected} | ||||||
|  |           > | ||||||
|  |             {getLanguageDigits(item)} | ||||||
|  |           </button> | ||||||
|  |         </li> | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   const handleKeyDown = e => { | ||||||
|  |     handleKeyboardNavigation(e, { allowVerticalArrows: false }); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <div | ||||||
|  |       className="Calendar__yearSelectorAnimationWrapper" | ||||||
|  |       role="presentation" | ||||||
|  |       {...(isOpen ? {} : { 'aria-hidden': true })} | ||||||
|  |     > | ||||||
|  |       <div | ||||||
|  |         ref={wrapperElement} | ||||||
|  |         className="Calendar__yearSelectorWrapper" | ||||||
|  |         role="presentation" | ||||||
|  |         data-testid="year-selector-wrapper" | ||||||
|  |         onKeyDown={handleKeyDown} | ||||||
|  |       > | ||||||
|  |         <ul ref={yearListElement} className="Calendar__yearSelector" data-testid="year-selector"> | ||||||
|  |           {renderSelectorYears()} | ||||||
|  |         </ul> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | YearSelector.defaultProps = { | ||||||
|  |   selectorStartingYear: 0, | ||||||
|  |   selectorEndingYear: 0, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default YearSelector; | ||||||
| @ -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'; | ||||||
| @ -0,0 +1,3 @@ | |||||||
|  | export { default } from './DatePicker'; | ||||||
|  | export * from './Calendar'; | ||||||
|  | export { default as utils } from './shared/localeUtils'; | ||||||
| @ -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'; | ||||||
| @ -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, | ||||||
|  | }; | ||||||
| @ -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 }; | ||||||
| @ -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; | ||||||
| @ -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; | ||||||
| @ -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; | ||||||
| @ -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 }; | ||||||
| @ -0,0 +1,710 @@ | |||||||
|  | .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); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker, | ||||||
|  |   .range-date-picker * { | ||||||
|  |     margin: 0; | ||||||
|  |     padding: 0; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     direction: ltr; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker, | ||||||
|  |   .range-date-picker.-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; | ||||||
|  |      | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker { | ||||||
|  |     --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 .range-date-picker, | ||||||
|  |   .DatePicker__calendarArrow { | ||||||
|  |     transform: translateY(2.5em); | ||||||
|  |     opacity: 0; | ||||||
|  |     animation: fadeCalendar 0.3s forwards; | ||||||
|  |      | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .DatePicker__calendarContainer.-top .range-date-picker { | ||||||
|  |     transform: translateY(-2.5em); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker.-noFocusOutline *:focus { | ||||||
|  |     outline: none !important; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker > :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); | ||||||
|  |   } | ||||||
|  |   .range-date-picker.-rtl .Calendar__monthArrowWrapper.-left { | ||||||
|  |     transform: rotate(-180deg); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .Calendar__monthArrowWrapper.-right { | ||||||
|  |     transform: rotate(-0deg); | ||||||
|  |      | ||||||
|  |   } | ||||||
|  |   .range-date-picker.-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%); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker.-rtl .Calendar__monthYear.-hiddenNext { | ||||||
|  |     transform: translateX(-150%); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .Calendar__monthYear.-hiddenPrevious { | ||||||
|  |     opacity: 0; | ||||||
|  |     transform: translateX(-150%); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker.-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, | ||||||
|  |   .range-date-picker:not(.-noFocusOutline) .Calendar__monthYear.-shown > *:focus, | ||||||
|  |   .Calendar__monthYear > *.-activeBackground { | ||||||
|  |     background: #f5f5f5; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .Calendar__monthText:hover { | ||||||
|  |     transform: translateX(-0.2em) scale(0.95); | ||||||
|  |   } | ||||||
|  |   .range-date-picker.-rtl .Calendar__monthText:hover { | ||||||
|  |     transform: translateX(0.2em) scale(0.95); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .Calendar__yearText:hover { | ||||||
|  |     transform: translateX(0.2em) scale(0.95); | ||||||
|  |   } | ||||||
|  |   .range-date-picker.-rtl .Calendar__yearText:hover { | ||||||
|  |     transform: translateX(-0.2em) scale(0.95); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .Calendar__monthYear .Calendar__yearText.-hidden { | ||||||
|  |     transform: translateX(50%); | ||||||
|  |     opacity: 0; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker.-rtl .Calendar__monthYear .Calendar__yearText.-hidden { | ||||||
|  |     transform: translateX(-50%); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .Calendar__monthYear .Calendar__monthText.-hidden { | ||||||
|  |     transform: translateX(-50%); | ||||||
|  |     opacity: 0; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker.-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%); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker.-rtl .Calendar__section.-hiddenPrevious { | ||||||
|  |     transform: translateX(90%); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .Calendar__section.-hiddenNext { | ||||||
|  |     opacity: 0.5; | ||||||
|  |     transform: translateX(90%); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker.-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%; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker .Calendar__section .Calendar__weekRow .Calendar__day { | ||||||
|  |     display: block; | ||||||
|  |     width: calc(100% / 7); | ||||||
|  |     text-align: center; | ||||||
|  |     padding: calc(0.25em - 1px); | ||||||
|  |     font-size: 1.6em; | ||||||
|  |     transition: 0.2s; | ||||||
|  |     border: 1px solid transparent; | ||||||
|  |     color: rgba(0, 0, 0, 0.8); | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     cursor: pointer; | ||||||
|  |     border-radius: 7px; | ||||||
|  |      | ||||||
|  |     | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .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; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .range-date-picker .Calendar__section .Calendar__weekRow .Calendar__day:not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween):not(.-selected):hover { | ||||||
|  |      | ||||||
|  |     | ||||||
|  |     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; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .range-date-picker .specialDay span{ | ||||||
|  |     border-bottom: 4px dotted #444444; | ||||||
|  |   } | ||||||
|  |   .range-date-picker .holiday span{ | ||||||
|  |     color:#ff2929; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   @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); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
					Loading…
					
					
				
		Reference in new issue