parent
dd3f6da767
commit
e8f1167f93
22 changed files with 5 additions and 3384 deletions
@ -1,245 +0,0 @@ |
|||||||
import React, { useState, useRef, useEffect } from "react"; |
|
||||||
|
|
||||||
import { |
|
||||||
getDateAccordingToMonth, |
|
||||||
shallowClone, |
|
||||||
getValueType, |
|
||||||
} from "./shared/generalUtils"; |
|
||||||
import { |
|
||||||
TYPE_SINGLE_DATE, |
|
||||||
TYPE_RANGE, |
|
||||||
TYPE_MUTLI_DATE, |
|
||||||
} from "./shared/constants"; |
|
||||||
import { useLocaleUtils, useLocaleLanguage } from "./shared/hooks"; |
|
||||||
|
|
||||||
import { Header, MonthSelector, YearSelector, DaysList } from "./components"; |
|
||||||
|
|
||||||
const Calendar = ({ |
|
||||||
value, |
|
||||||
onChange, |
|
||||||
onDisabledDayError, |
|
||||||
calendarClassName, |
|
||||||
calendarTodayClassName, |
|
||||||
calendarSelectedDayClassName, |
|
||||||
calendarRangeStartClassName, |
|
||||||
calendarRangeBetweenClassName, |
|
||||||
calendarRangeEndClassName, |
|
||||||
disabledDays, |
|
||||||
colorPrimary, |
|
||||||
colorPrimaryLight, |
|
||||||
slideAnimationDuration, |
|
||||||
minimumDate, |
|
||||||
maximumDate, |
|
||||||
selectorStartingYear, |
|
||||||
selectorEndingYear, |
|
||||||
locale, |
|
||||||
shouldHighlightWeekends, |
|
||||||
renderFooter, |
|
||||||
customDaysClassName, |
|
||||||
events, |
|
||||||
renderEvents, |
|
||||||
type, |
|
||||||
}) => { |
|
||||||
const calendarElement = useRef(null); |
|
||||||
const [mainState, setMainState] = useState({ |
|
||||||
activeDate: null, |
|
||||||
monthChangeDirection: "", |
|
||||||
isMonthSelectorOpen: false, |
|
||||||
isYearSelectorOpen: false, |
|
||||||
}); |
|
||||||
const [eventInFooter, setEventInFooter] = useState(null); |
|
||||||
useEffect(() => { |
|
||||||
const handleKeyUp = ({ key }) => { |
|
||||||
/* istanbul ignore else */ |
|
||||||
if (key === "Tab") |
|
||||||
calendarElement.current.classList.remove("-noFocusOutline"); |
|
||||||
}; |
|
||||||
calendarElement.current.addEventListener("keyup", handleKeyUp, false); |
|
||||||
return () => { |
|
||||||
// calendarElement.current.removeEventListener('keyup', handleKeyUp, false);
|
|
||||||
}; |
|
||||||
}); |
|
||||||
|
|
||||||
const { getToday } = useLocaleUtils(locale); |
|
||||||
const { weekDays: weekDaysList, isRtl } = useLocaleLanguage(locale); |
|
||||||
const today = getToday(); |
|
||||||
|
|
||||||
const createStateToggler = (property) => () => { |
|
||||||
setMainState({ ...mainState, [property]: !mainState[property] }); |
|
||||||
}; |
|
||||||
|
|
||||||
const toggleMonthSelector = createStateToggler("isMonthSelectorOpen"); |
|
||||||
const toggleYearSelector = createStateToggler("isYearSelectorOpen"); |
|
||||||
|
|
||||||
const getComputedActiveDate = () => { |
|
||||||
const valueType = getValueType(value); |
|
||||||
if (valueType === TYPE_MUTLI_DATE && value.length) |
|
||||||
return shallowClone(value[0]); |
|
||||||
if (valueType === TYPE_SINGLE_DATE && value) return shallowClone(value); |
|
||||||
if (valueType === TYPE_RANGE && value.from) return shallowClone(value.from); |
|
||||||
return shallowClone(today); |
|
||||||
}; |
|
||||||
|
|
||||||
const activeDate = mainState.activeDate |
|
||||||
? shallowClone(mainState.activeDate) |
|
||||||
: getComputedActiveDate(); |
|
||||||
|
|
||||||
const weekdays = weekDaysList.map((weekDay) => ( |
|
||||||
<abbr |
|
||||||
key={weekDay.name} |
|
||||||
title={weekDay.name} |
|
||||||
className={`Calendar__weekDay ${type}`} |
|
||||||
> |
|
||||||
{type == "dashboard" ? weekDay.name : 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 ${type} -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} |
|
||||||
type={type} |
|
||||||
/> |
|
||||||
|
|
||||||
<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 ${type}`}>{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} |
|
||||||
renderFooter={renderFooter} |
|
||||||
renderEvents={renderEvents} |
|
||||||
isQuickSelectorOpen={ |
|
||||||
mainState.isYearSelectorOpen || mainState.isMonthSelectorOpen |
|
||||||
} |
|
||||||
showEvent={(event) => setEventInFooter(event)} |
|
||||||
type={type} |
|
||||||
/> |
|
||||||
<div className="Calendar__footer"> |
|
||||||
<div className={`footer__Events ${type}`}> |
|
||||||
{type == "dashboard" ? ( |
|
||||||
<> |
|
||||||
<div className="text-xl font-black text-blue-400"> |
|
||||||
رویداد ها:{" "} |
|
||||||
</div> |
|
||||||
<p className="text-blue-300 font-sansbold"> |
|
||||||
{eventInFooter |
|
||||||
? eventInFooter |
|
||||||
: "رویدادی در این روز وجود ندارد!"} |
|
||||||
</p> |
|
||||||
</> |
|
||||||
) : ( |
|
||||||
eventInFooter |
|
||||||
)} |
|
||||||
</div> |
|
||||||
{renderFooter()} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
Calendar.defaultProps = { |
|
||||||
minimumDate: null, |
|
||||||
maximumDate: null, |
|
||||||
colorPrimary: "#0eca2d", |
|
||||||
colorPrimaryLight: "#cff4d5", |
|
||||||
slideAnimationDuration: "0.4s", |
|
||||||
calendarClassName: "", |
|
||||||
locale: "en", |
|
||||||
value: null, |
|
||||||
renderFooter: () => null, |
|
||||||
renderEvents: () => null, |
|
||||||
customDaysClassName: [], |
|
||||||
events: [], |
|
||||||
}; |
|
||||||
|
|
||||||
export default Calendar; |
|
@ -1,672 +0,0 @@ |
|||||||
.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); |
|
||||||
} |
|
||||||
} |
|
@ -1,203 +0,0 @@ |
|||||||
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; |
|
@ -1,93 +0,0 @@ |
|||||||
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; |
|
@ -1,399 +0,0 @@ |
|||||||
import React, { useRef, useEffect } from 'react'; |
|
||||||
|
|
||||||
import { |
|
||||||
getSlideDate, |
|
||||||
handleSlideAnimationEnd, |
|
||||||
animateContent, |
|
||||||
} from '../shared/sliderHelpers'; |
|
||||||
import { |
|
||||||
deepCloneObject, |
|
||||||
isSameDay, |
|
||||||
createUniqueRange, |
|
||||||
getValueType, |
|
||||||
} from '../shared/generalUtils'; |
|
||||||
import { |
|
||||||
TYPE_SINGLE_DATE, |
|
||||||
TYPE_RANGE, |
|
||||||
TYPE_MUTLI_DATE, |
|
||||||
} from '../shared/constants'; |
|
||||||
import handleKeyboardNavigation from '../shared/keyboardNavigation'; |
|
||||||
import { useLocaleUtils, useLocaleLanguage } from '../shared/hooks'; |
|
||||||
|
|
||||||
const DaysList = ({ |
|
||||||
activeDate, |
|
||||||
value, |
|
||||||
monthChangeDirection, |
|
||||||
onSlideChange, |
|
||||||
disabledDays, |
|
||||||
onDisabledDayError, |
|
||||||
minimumDate, |
|
||||||
maximumDate, |
|
||||||
onChange, |
|
||||||
locale, |
|
||||||
calendarTodayClassName, |
|
||||||
calendarSelectedDayClassName, |
|
||||||
calendarRangeStartClassName, |
|
||||||
calendarRangeEndClassName, |
|
||||||
calendarRangeBetweenClassName, |
|
||||||
shouldHighlightWeekends, |
|
||||||
isQuickSelectorOpen, |
|
||||||
customDaysClassName, |
|
||||||
events, |
|
||||||
showEvent, |
|
||||||
type |
|
||||||
}) => { |
|
||||||
const calendarSectionWrapper = useRef(null); |
|
||||||
const { isRtl, weekDays: weekDaysList } = useLocaleLanguage(locale); |
|
||||||
const { |
|
||||||
getToday, |
|
||||||
isBeforeDate, |
|
||||||
checkDayInDayRange, |
|
||||||
getMonthFirstWeekday, |
|
||||||
getMonthLength, |
|
||||||
getLanguageDigits, |
|
||||||
getMonthName, |
|
||||||
} = useLocaleUtils(locale); |
|
||||||
const today = getToday(); |
|
||||||
|
|
||||||
useEffect(() => { |
|
||||||
if (!monthChangeDirection) return; |
|
||||||
animateContent({ |
|
||||||
direction: monthChangeDirection, |
|
||||||
parent: calendarSectionWrapper.current, |
|
||||||
}); |
|
||||||
}, [monthChangeDirection]); |
|
||||||
|
|
||||||
const getDayRangeValue = (day) => { |
|
||||||
const clonedDayRange = deepCloneObject(value); |
|
||||||
const dayRangeValue = |
|
||||||
clonedDayRange.from && clonedDayRange.to |
|
||||||
? { from: null, to: null } |
|
||||||
: clonedDayRange; |
|
||||||
const dayRangeProp = !dayRangeValue.from ? 'from' : 'to'; |
|
||||||
dayRangeValue[dayRangeProp] = day; |
|
||||||
const { from, to } = dayRangeValue; |
|
||||||
|
|
||||||
// swap from and to values if from is later than to
|
|
||||||
if (isBeforeDate(dayRangeValue.to, dayRangeValue.from)) { |
|
||||||
dayRangeValue.from = to; |
|
||||||
dayRangeValue.to = from; |
|
||||||
} |
|
||||||
|
|
||||||
const checkIncludingDisabledDay = (disabledDay) => { |
|
||||||
return checkDayInDayRange({ |
|
||||||
day: disabledDay, |
|
||||||
from: dayRangeValue.from, |
|
||||||
to: dayRangeValue.to, |
|
||||||
}); |
|
||||||
}; |
|
||||||
const includingDisabledDay = disabledDays.find(checkIncludingDisabledDay); |
|
||||||
if (includingDisabledDay) { |
|
||||||
onDisabledDayError(includingDisabledDay); |
|
||||||
return value; |
|
||||||
} |
|
||||||
|
|
||||||
return dayRangeValue; |
|
||||||
}; |
|
||||||
|
|
||||||
const getMultiDateValue = (day) => { |
|
||||||
const isAlreadyExisting = value.some((valueDay) => |
|
||||||
isSameDay(valueDay, day) |
|
||||||
); |
|
||||||
const addedToValue = [...value, day]; |
|
||||||
const removedFromValue = value.filter( |
|
||||||
(valueDay) => !isSameDay(valueDay, day) |
|
||||||
); |
|
||||||
return isAlreadyExisting ? removedFromValue : addedToValue; |
|
||||||
}; |
|
||||||
|
|
||||||
const handleDayClick = (day) => { |
|
||||||
const getNewValue = () => { |
|
||||||
const valueType = getValueType(value); |
|
||||||
switch (valueType) { |
|
||||||
case TYPE_SINGLE_DATE: |
|
||||||
return day; |
|
||||||
case TYPE_RANGE: |
|
||||||
return getDayRangeValue(day); |
|
||||||
case TYPE_MUTLI_DATE: |
|
||||||
return getMultiDateValue(day); |
|
||||||
} |
|
||||||
}; |
|
||||||
const newValue = getNewValue(); |
|
||||||
onChange(newValue); |
|
||||||
}; |
|
||||||
|
|
||||||
const isSingleDateSelected = (day) => { |
|
||||||
const valueType = getValueType(value); |
|
||||||
if (valueType === TYPE_SINGLE_DATE) return isSameDay(day, value); |
|
||||||
if (valueType === TYPE_MUTLI_DATE) |
|
||||||
return value.some((valueDay) => isSameDay(valueDay, day)); |
|
||||||
}; |
|
||||||
|
|
||||||
const getDayStatus = (dayItem) => { |
|
||||||
const isToday = isSameDay(dayItem, today); |
|
||||||
const isSelected = isSingleDateSelected(dayItem); |
|
||||||
const { from: startingDay, to: endingDay } = value || {}; |
|
||||||
const isStartingDayRange = isSameDay(dayItem, startingDay); |
|
||||||
const isEndingDayRange = isSameDay(dayItem, endingDay); |
|
||||||
const isWithinRange = checkDayInDayRange({ |
|
||||||
day: dayItem, |
|
||||||
from: startingDay, |
|
||||||
to: endingDay, |
|
||||||
}); |
|
||||||
return { |
|
||||||
isToday, |
|
||||||
isSelected, |
|
||||||
isStartingDayRange, |
|
||||||
isEndingDayRange, |
|
||||||
isWithinRange, |
|
||||||
}; |
|
||||||
}; |
|
||||||
|
|
||||||
const getDayClassNames = (dayItem) => { |
|
||||||
const { |
|
||||||
isToday, |
|
||||||
isSelected, |
|
||||||
isStartingDayRange, |
|
||||||
isEndingDayRange, |
|
||||||
isWithinRange, |
|
||||||
} = getDayStatus(dayItem); |
|
||||||
const customDayItemClassName = customDaysClassName.find((day) => |
|
||||||
isSameDay(dayItem, day) |
|
||||||
); |
|
||||||
|
|
||||||
const classNames = '' |
|
||||||
.concat(isToday && !isSelected ? ` -today ${calendarTodayClassName}` : '') |
|
||||||
.concat(!dayItem.isStandard ? ' -blank' : '') |
|
||||||
.concat(dayItem.isWeekend && shouldHighlightWeekends ? ' -weekend' : '') |
|
||||||
.concat( |
|
||||||
customDayItemClassName ? ` ${customDayItemClassName.className}` : '' |
|
||||||
) |
|
||||||
.concat(isSelected ? ` -selected ${calendarSelectedDayClassName}` : '') |
|
||||||
.concat( |
|
||||||
isStartingDayRange |
|
||||||
? ` -selectedStart ${calendarRangeStartClassName}` |
|
||||||
: '' |
|
||||||
) |
|
||||||
.concat( |
|
||||||
isEndingDayRange ? ` -selectedEnd ${calendarRangeEndClassName}` : '' |
|
||||||
) |
|
||||||
.concat( |
|
||||||
isWithinRange |
|
||||||
? ` -selectedBetween ${calendarRangeBetweenClassName}` |
|
||||||
: '' |
|
||||||
) |
|
||||||
.concat(dayItem.isDisabled ? ' -disabled' : ''); |
|
||||||
return classNames; |
|
||||||
}; |
|
||||||
|
|
||||||
const getViewMonthDays = (date) => { |
|
||||||
// to match month starting date with the correct weekday label
|
|
||||||
const prependingBlankDays = createUniqueRange( |
|
||||||
getMonthFirstWeekday(date), |
|
||||||
'starting-blank' |
|
||||||
); |
|
||||||
const standardDays = createUniqueRange(getMonthLength(date)).map((day) => ({ |
|
||||||
...day, |
|
||||||
isStandard: true, |
|
||||||
month: date.month, |
|
||||||
year: date.year, |
|
||||||
})); |
|
||||||
const allDays = [...prependingBlankDays, ...standardDays]; |
|
||||||
return allDays; |
|
||||||
}; |
|
||||||
|
|
||||||
const handleDayPress = ({ isDisabled, ...dayItem }) => { |
|
||||||
if (isDisabled) { |
|
||||||
onDisabledDayError(dayItem); // good for showing error messages
|
|
||||||
} else handleDayClick(dayItem); |
|
||||||
}; |
|
||||||
|
|
||||||
const isDayReachableByKeyboard = ({ |
|
||||||
isOnActiveSlide, |
|
||||||
isStandard, |
|
||||||
isSelected, |
|
||||||
isStartingDayRange, |
|
||||||
isToday, |
|
||||||
day, |
|
||||||
}) => { |
|
||||||
if (isQuickSelectorOpen || !isOnActiveSlide || !isStandard) return false; |
|
||||||
if (isSelected || isStartingDayRange || isToday || day === 1) return true; |
|
||||||
}; |
|
||||||
|
|
||||||
const renderEachWeekDays = ( |
|
||||||
{ id, value: day, month, year, isStandard }, |
|
||||||
index |
|
||||||
) => { |
|
||||||
const dayItem = { day, month, year }; |
|
||||||
const isInDisabledDaysRange = disabledDays.some((disabledDay) => |
|
||||||
isSameDay(dayItem, disabledDay) |
|
||||||
); |
|
||||||
const isBeforeMinimumDate = isBeforeDate(dayItem, minimumDate); |
|
||||||
const isAfterMaximumDate = isBeforeDate(maximumDate, dayItem); |
|
||||||
const isNotInValidRange = |
|
||||||
isStandard && (isBeforeMinimumDate || isAfterMaximumDate); |
|
||||||
const isDisabled = isInDisabledDaysRange || isNotInValidRange; |
|
||||||
const isWeekend = weekDaysList.some( |
|
||||||
(weekDayItem, weekDayItemIndex) => |
|
||||||
weekDayItem.isWeekend && weekDayItemIndex === index |
|
||||||
); |
|
||||||
const additionalClass = getDayClassNames({ |
|
||||||
...dayItem, |
|
||||||
isWeekend, |
|
||||||
isStandard, |
|
||||||
isDisabled, |
|
||||||
}); |
|
||||||
const dayLabel = `${weekDaysList[index].name}, ${day} ${getMonthName( |
|
||||||
month |
|
||||||
)} ${year}`;
|
|
||||||
const isOnActiveSlide = month === activeDate.month; |
|
||||||
const dayStatus = getDayStatus(dayItem); |
|
||||||
const { isSelected, isStartingDayRange, isEndingDayRange, isWithinRange } = |
|
||||||
dayStatus; |
|
||||||
const shouldEnableKeyboardNavigation = isDayReachableByKeyboard({ |
|
||||||
...dayItem, |
|
||||||
...dayStatus, |
|
||||||
isOnActiveSlide, |
|
||||||
isStandard, |
|
||||||
}); |
|
||||||
|
|
||||||
// showing Dots Of Events
|
|
||||||
const specialDate = (sDay, sMonth, sYear) => { |
|
||||||
return events.map((e) => { |
|
||||||
if (sDay == e.day && sMonth == e.month && sYear == e.year) { |
|
||||||
return <span key={'dot' + e.id} style={{ |
|
||||||
color: e.color |
|
||||||
}}>.</span>; |
|
||||||
|
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
const showEventDescription = (sDay, sMonth, sYear) => { |
|
||||||
|
|
||||||
return events.map((e) => { |
|
||||||
|
|
||||||
if (sDay == e.day && sMonth == e.month && sYear == e.year) { |
|
||||||
|
|
||||||
return (<div key={'description' + e.id}><p>{e.description}</p></div>) |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
}) |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
return ( |
|
||||||
<div |
|
||||||
style={{ |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'column', |
|
||||||
alignItems: 'center', |
|
||||||
}} |
|
||||||
tabIndex={shouldEnableKeyboardNavigation ? '0' : '-1'} |
|
||||||
key={id} |
|
||||||
className={`Calendar__day ${type} -${isRtl ? 'rtl' : 'ltr'} ${additionalClass}`} |
|
||||||
onClick={() => { |
|
||||||
handleDayPress({ ...dayItem, isDisabled }); |
|
||||||
// console.log(specialDate(day));
|
|
||||||
// console.log(showEventDescription(day))
|
|
||||||
showEvent(showEventDescription(day, month, year)) |
|
||||||
|
|
||||||
}} |
|
||||||
onKeyDown={({ key }) => { |
|
||||||
/* istanbul ignore else */ |
|
||||||
if (key === 'Enter') handleDayPress({ ...dayItem, isDisabled }); |
|
||||||
}} |
|
||||||
aria-disabled={isDisabled} |
|
||||||
aria-label={dayLabel} |
|
||||||
aria-selected={ |
|
||||||
isSelected || isStartingDayRange || isEndingDayRange || isWithinRange |
|
||||||
} |
|
||||||
{...(!isStandard || !isOnActiveSlide || isQuickSelectorOpen |
|
||||||
? { 'aria-hidden': true } |
|
||||||
: {})} |
|
||||||
role="gridcell" |
|
||||||
data-is-default-selectable={shouldEnableKeyboardNavigation} |
|
||||||
> |
|
||||||
<p>{!isStandard ? '' : getLanguageDigits(day)}</p> |
|
||||||
{/* Dots Of Events */} |
|
||||||
<span>{specialDate(day, month, year)}</span> |
|
||||||
</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; |
|
@ -1,205 +0,0 @@ |
|||||||
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, |
|
||||||
type |
|
||||||
}) => { |
|
||||||
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 ${type}`}> |
|
||||||
{type == 'dashboard' ?
|
|
||||||
|
|
||||||
<div |
|
||||||
className={`Calendar__monthYearContainer ${type}`} |
|
||||||
ref={monthYearWrapperElement} |
|
||||||
data-testid="month-year-container" |
|
||||||
> |
|
||||||
|
|
||||||
{monthYearButtons} |
|
||||||
</div> |
|
||||||
: |
|
||||||
<> |
|
||||||
<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; |
|
@ -1,74 +0,0 @@ |
|||||||
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; |
|
@ -1,99 +0,0 @@ |
|||||||
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; |
|
@ -1,4 +0,0 @@ |
|||||||
export { default as Header } from './Header'; |
|
||||||
export { default as MonthSelector } from './MonthSelector'; |
|
||||||
export { default as YearSelector } from './YearSelector'; |
|
||||||
export { default as DaysList } from './DaysList'; |
|
@ -1,3 +0,0 @@ |
|||||||
export { default} from './DatePicker'; |
|
||||||
export * from './Calendar'; |
|
||||||
export { default as utils } from './shared/localeUtils'; |
|
@ -1,104 +0,0 @@ |
|||||||
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'; |
|
@ -1,69 +0,0 @@ |
|||||||
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, |
|
||||||
}; |
|
@ -1,10 +0,0 @@ |
|||||||
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 }; |
|
@ -1,44 +0,0 @@ |
|||||||
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; |
|
@ -1,85 +0,0 @@ |
|||||||
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; |
|
@ -1,61 +0,0 @@ |
|||||||
/* |
|
||||||
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; |
|
@ -1,33 +0,0 @@ |
|||||||
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 }; |
|
@ -1,840 +0,0 @@ |
|||||||
.Calendar *{ |
|
||||||
font-family: 'iranSans'; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker { |
|
||||||
position: relative; |
|
||||||
display: inline-block; |
|
||||||
z-index: 100; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__input { |
|
||||||
background: #fff; |
|
||||||
border: 1px solid rgba(0, 0, 0, 0.4); |
|
||||||
padding: 0.6em 1.2em; |
|
||||||
font-family:'iranSans'; |
|
||||||
text-align: center; |
|
||||||
font-size: 12px; |
|
||||||
border-radius: 7px; |
|
||||||
|
|
||||||
} |
|
||||||
.DatePicker__input:focus{ |
|
||||||
outline:1px solid #06BACE; |
|
||||||
color: #06BACE; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__input.-rtl { |
|
||||||
direction: rtl; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__input::placeholder { |
|
||||||
color: #979797; |
|
||||||
} |
|
||||||
.DatePicker__input:focus::placeholder{ |
|
||||||
color: #06BACE; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__calendarContainer.-top + .DatePicker__calendarArrow { |
|
||||||
top: auto; |
|
||||||
bottom: calc(100% + 10px); |
|
||||||
transform: translateY(-2.5rem) rotate(180deg); |
|
||||||
animation: fadeArrowFlipped 0.3s forwards; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__calendarContainer { |
|
||||||
position: absolute; |
|
||||||
top: calc(100% + 20px); |
|
||||||
left: 50%; |
|
||||||
transform: translateX(-50%); |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__calendarContainer.-top { |
|
||||||
top: auto; |
|
||||||
bottom: calc(100% + 20px); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar, |
|
||||||
.Calendar * { |
|
||||||
margin: 0; |
|
||||||
padding: 0; |
|
||||||
box-sizing: border-box; |
|
||||||
direction: ltr; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar, |
|
||||||
.Calendar.-rtl * { |
|
||||||
direction: rtl; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__calendarArrow { |
|
||||||
position: absolute; |
|
||||||
width: 0; |
|
||||||
height: 0; |
|
||||||
top: calc(100% + 10px); |
|
||||||
left: 0; |
|
||||||
right: 0; |
|
||||||
margin: 0 auto; |
|
||||||
border-style: solid; |
|
||||||
z-index: 10; |
|
||||||
border-width: 0 10px 10px 10px; |
|
||||||
border-color: transparent transparent #fff transparent; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.Calendar { |
|
||||||
--cl-color-black: #444444; |
|
||||||
--cl-color-disabled: #d4d4d4; |
|
||||||
--cl-color-error: #ff2929; |
|
||||||
font-family:'iranSans'; |
|
||||||
font-size: 10px; |
|
||||||
background: rgba(245, 245, 245, 0.53); |
|
||||||
border:1px solid #DBDBDB; |
|
||||||
box-shadow: 0 1em em rgba(0, 0, 0, 0.07); |
|
||||||
border-radius: 1em; |
|
||||||
position: relative; |
|
||||||
user-select: none; |
|
||||||
padding-top: 1.2em; |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
width: 40em; |
|
||||||
z-index: 10; |
|
||||||
max-width: 90vw; |
|
||||||
min-height: 38.7em; |
|
||||||
} |
|
||||||
.Calendar.dashboard{ |
|
||||||
--cl-color-black: #444444; |
|
||||||
--cl-color-disabled: #d4d4d4; |
|
||||||
--cl-color-error: #ff2929; |
|
||||||
font-family:'iranSans'; |
|
||||||
font-size: 10px; |
|
||||||
background: rgba(255, 255, 255, 1); |
|
||||||
border:1px solid #EDF2FB; |
|
||||||
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: 50em; |
|
||||||
z-index: 10; |
|
||||||
max-width: 90vw; |
|
||||||
min-height: 38.7em; |
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker .Calendar, |
|
||||||
.DatePicker__calendarArrow { |
|
||||||
transform: translateY(2.5em); |
|
||||||
opacity: 0; |
|
||||||
animation: fadeCalendar 0.3s forwards; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.DatePicker__calendarContainer.-top .Calendar { |
|
||||||
transform: translateY(-2.5em); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar.-noFocusOutline *:focus { |
|
||||||
outline: none !important; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar > :not(.Calendar__footer) button { |
|
||||||
font-family: inherit; |
|
||||||
background: transparent; |
|
||||||
cursor: pointer; |
|
||||||
-webkit-tap-highlight-color: transparent; |
|
||||||
outline: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__header { |
|
||||||
display: flex; |
|
||||||
color: var(--cl-color-black); |
|
||||||
padding: 2em 2.9em; |
|
||||||
align-items: center; |
|
||||||
overflow: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthArrowWrapper { |
|
||||||
line-height: 0; |
|
||||||
font-size: 1em; |
|
||||||
padding: 3px; |
|
||||||
position: relative; |
|
||||||
border: none; |
|
||||||
z-index: 1; |
|
||||||
opacity: 1; |
|
||||||
transition: 0.2s; |
|
||||||
background-color: #06BACE; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthArrowWrapper:focus { |
|
||||||
outline: 1px dashed rgba(0, 0, 0, 0.4); |
|
||||||
outline-offset: 2px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthArrowWrapper:disabled, |
|
||||||
.Calendar__monthArrowWrapper.-hidden { |
|
||||||
opacity: 0; |
|
||||||
pointer-events: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthArrowWrapper.-left { |
|
||||||
transform: rotate(180deg); |
|
||||||
} |
|
||||||
.Calendar.-rtl .Calendar__monthArrowWrapper.-left { |
|
||||||
transform: rotate(-180deg); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthArrowWrapper.-right { |
|
||||||
transform: rotate(-0deg); |
|
||||||
|
|
||||||
} |
|
||||||
.Calendar.-rtl .Calendar__monthArrowWrapper.-right { |
|
||||||
transform: rotate(0deg); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthArrowWrapper:active .Calendar__monthArrow { |
|
||||||
transform: scale(0.7); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthArrow { |
|
||||||
border-radius: 7px; |
|
||||||
padding: 12px; |
|
||||||
transition: var(--animation-duration) transform; |
|
||||||
pointer-events: none; |
|
||||||
background-repeat: no-repeat; |
|
||||||
display: block; |
|
||||||
width: 0.7em; |
|
||||||
height: 0.7em; |
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='15' height='15' viewBox='0 0 50 80' xml:space='preserve'%3E%3Cpolyline fill='none' stroke='%23FFFFFF' stroke-width='15' stroke-linecap='round' stroke-linejoin='round' points=' 0.375,0.375 45.63,38.087 0.375,75.8 '/%3E%3C/svg%3E"); background-size: 100% 100%; |
|
||||||
background-color: #06BACE; |
|
||||||
background-size: 10px; |
|
||||||
background-position: center; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYearContainer { |
|
||||||
flex: 1; |
|
||||||
position: relative; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear { |
|
||||||
font-size: 2em; |
|
||||||
font-weight: 500; |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
position: absolute; |
|
||||||
top: 0; |
|
||||||
bottom: 0; |
|
||||||
left: 50%; |
|
||||||
will-change: transform, opacity; |
|
||||||
backface-visibility: hidden; |
|
||||||
transform: translateZ(0); |
|
||||||
transition: var(--animation-duration); |
|
||||||
line-height: 1; |
|
||||||
color:#246E8A; |
|
||||||
} |
|
||||||
.Calendar__monthYear.dashboard { |
|
||||||
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:#65A9FF; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
.Calendar__monthYear.-hiddenNext { |
|
||||||
opacity: 0; |
|
||||||
transform: translateX(50%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar.-rtl .Calendar__monthYear.-hiddenNext { |
|
||||||
transform: translateX(-150%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear.-hiddenPrevious { |
|
||||||
opacity: 0; |
|
||||||
transform: translateX(-150%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar.-rtl .Calendar__monthYear.-hiddenPrevious { |
|
||||||
transform: translateX(50%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear.-shown { |
|
||||||
opacity: 1; |
|
||||||
margin-top: auto; |
|
||||||
margin-bottom: auto; |
|
||||||
transform: translateX(-50%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear.-shownAnimated { |
|
||||||
animation: var(--animation-duration) fadeTextToCenter forwards; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear > * { |
|
||||||
padding: 0.2em 0.5em; |
|
||||||
border: 1px solid transparent; |
|
||||||
transition: var(--animation-duration); |
|
||||||
font-size: 1.05em; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
transform: translateX(0) scale(0.95); |
|
||||||
will-change: transform; |
|
||||||
border-radius: 5px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear:not(.-shown) > *, |
|
||||||
.Calendar__monthYear > *.-hidden { |
|
||||||
cursor: default; |
|
||||||
pointer-events: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthText { |
|
||||||
margin-left: -0.3em; |
|
||||||
} |
|
||||||
.Calendar__yearText:last-child { |
|
||||||
margin-right: -0.3em; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear.-shown > *:hover, |
|
||||||
.Calendar:not(.-noFocusOutline) .Calendar__monthYear.-shown > *:focus, |
|
||||||
.Calendar__monthYear > *.-activeBackground { |
|
||||||
background: #f5f5f5; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthText:hover { |
|
||||||
transform: translateX(-0.2em) scale(0.95); |
|
||||||
} |
|
||||||
.Calendar.-rtl .Calendar__monthText:hover { |
|
||||||
transform: translateX(0.2em) scale(0.95); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearText:hover { |
|
||||||
transform: translateX(0.2em) scale(0.95); |
|
||||||
} |
|
||||||
.Calendar.-rtl .Calendar__yearText:hover { |
|
||||||
transform: translateX(-0.2em) scale(0.95); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear .Calendar__yearText.-hidden { |
|
||||||
transform: translateX(50%); |
|
||||||
opacity: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar.-rtl .Calendar__monthYear .Calendar__yearText.-hidden { |
|
||||||
transform: translateX(-50%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear .Calendar__monthText.-hidden { |
|
||||||
transform: translateX(-50%); |
|
||||||
opacity: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar.-rtl .Calendar__monthYear .Calendar__monthText.-hidden { |
|
||||||
transform: translateX(50%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthYear:not(.-shown) > * { |
|
||||||
pointer-events: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorAnimationWrapper, |
|
||||||
.Calendar__yearSelectorAnimationWrapper { |
|
||||||
position: absolute; |
|
||||||
width: 100%; |
|
||||||
height: 80%; |
|
||||||
bottom: 0; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
overflow: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorWrapper { |
|
||||||
width: 100%; |
|
||||||
height: 100%; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelector { |
|
||||||
padding: 0 2.5em; |
|
||||||
align-content: center; |
|
||||||
padding-bottom: 2em; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelector, |
|
||||||
.Calendar__yearSelector { |
|
||||||
display: flex; |
|
||||||
flex-wrap: wrap; |
|
||||||
position: relative; |
|
||||||
z-index: 2; |
|
||||||
background-color: #fff; |
|
||||||
transform: translateY(-150%); |
|
||||||
will-change: transform; |
|
||||||
transition: 0.6s; |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorWrapper { |
|
||||||
width: 100%; |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorWrapper::after, |
|
||||||
.Calendar__yearSelectorWrapper::before { |
|
||||||
content: ''; |
|
||||||
width: 100%; |
|
||||||
height: 5em; |
|
||||||
position: absolute; |
|
||||||
left: 0; |
|
||||||
opacity: 0; |
|
||||||
transition: 0.4s; |
|
||||||
transition-delay: 0.2s; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorWrapper::after { |
|
||||||
background-image: linear-gradient(to bottom, #fff, #fff 10%, rgba(245, 245, 245, 0)); |
|
||||||
top: -0.1em; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorWrapper::before { |
|
||||||
background-image: linear-gradient(to top, #fff, #fff 10%, rgba(245, 245, 245, 0)); |
|
||||||
bottom: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorWrapper.-faded::after, |
|
||||||
.Calendar__yearSelectorWrapper.-faded::before { |
|
||||||
opacity: 1; |
|
||||||
z-index: 3; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelector { |
|
||||||
align-content: flex-start; |
|
||||||
scrollbar-width: 0; |
|
||||||
overflow: scroll; |
|
||||||
position: relative; |
|
||||||
width: 100%; |
|
||||||
padding: 5em 2em; |
|
||||||
-ms-overflow-style: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelector::-webkit-scrollbar { |
|
||||||
display: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorItem { |
|
||||||
width: 25%; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorItem:not(:nth-child(-n + 4)) { |
|
||||||
margin-top: 1.5em; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorText { |
|
||||||
border: none; |
|
||||||
font-size: 1.4em; |
|
||||||
min-width: 85%; |
|
||||||
padding: 0.2em 0.5em; |
|
||||||
border-radius: 5px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelector.-open, |
|
||||||
.Calendar__yearSelector.-open { |
|
||||||
transform: translateY(0); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__yearSelectorText:focus, |
|
||||||
.Calendar__monthSelectorItemText:focus { |
|
||||||
outline: 1px dashed rgba(0, 0, 0, 0.4); |
|
||||||
outline-offset: 2px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorItem { |
|
||||||
width: calc(100% / 3); |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorItem:not(:nth-child(-n + 3)) { |
|
||||||
margin-top: 2em; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorItemText { |
|
||||||
border: none; |
|
||||||
padding: 0.4em 0.4em; |
|
||||||
border-radius: 8.5px; |
|
||||||
font-size: 1.3em; |
|
||||||
min-width: 70%; |
|
||||||
transition: 0.3s; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorItem:not(.-active) .Calendar__monthSelectorItemText:not(:disabled):hover, |
|
||||||
.Calendar__yearSelectorItem:not(.-active) .Calendar__yearSelectorText:not(:disabled):hover { |
|
||||||
background: #f5f5f5; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorItemText:disabled, |
|
||||||
.Calendar__yearSelectorText:disabled { |
|
||||||
opacity: 0.5; |
|
||||||
cursor: default; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__monthSelectorItem.-active .Calendar__monthSelectorItemText, |
|
||||||
.Calendar__yearSelectorItem.-active .Calendar__yearSelectorText { |
|
||||||
background-color: #006C94; |
|
||||||
color: #fff; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__weekDays { |
|
||||||
display: flex; |
|
||||||
justify-content: space-between; |
|
||||||
color: var(--cl-color-disabled); |
|
||||||
font-size: 1.2em; |
|
||||||
margin-bottom: 0.7em; |
|
||||||
padding: 0 2.6em; |
|
||||||
position: relative; |
|
||||||
} |
|
||||||
.Calendar__weekDays.dashboard { |
|
||||||
display: flex; |
|
||||||
justify-content: space-between; |
|
||||||
color: var(--cl-color-disabled); |
|
||||||
font-size: 1.2em; |
|
||||||
margin-bottom: 0.7em; |
|
||||||
padding: 0.75em 2.6em; |
|
||||||
position: relative; |
|
||||||
background-color: #EDF2FB; |
|
||||||
} |
|
||||||
|
|
||||||
.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.dashboard{ |
|
||||||
color:#A2B4CB; |
|
||||||
} |
|
||||||
.Calendar__weekDay[title]{ |
|
||||||
text-decoration: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__sectionWrapper { |
|
||||||
position: relative; |
|
||||||
min-height: 25.8em; |
|
||||||
overflow: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__section { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
padding: 0 3.2em; |
|
||||||
position: absolute; |
|
||||||
color: var(--cl-color-black); |
|
||||||
top: 0; |
|
||||||
padding-top: 0.5em; |
|
||||||
left: 0; |
|
||||||
width: 100%; |
|
||||||
will-change: transform, opacity; |
|
||||||
transform: translateZ(0); |
|
||||||
backface-visibility: hidden; |
|
||||||
transition: var(--animation-duration); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__section.-hiddenPrevious { |
|
||||||
opacity: 0.5; |
|
||||||
transform: translateX(-90%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar.-rtl .Calendar__section.-hiddenPrevious { |
|
||||||
transform: translateX(90%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__section.-hiddenNext { |
|
||||||
opacity: 0.5; |
|
||||||
transform: translateX(90%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar.-rtl .Calendar__section.-hiddenNext { |
|
||||||
transform: translateX(-90%); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__section.-shown { |
|
||||||
opacity: 1; |
|
||||||
transform: translateX(0); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__section.-shownAnimated { |
|
||||||
animation: var(--animation-duration) FadeContentToCenter forwards; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__weekRow { |
|
||||||
display: flex; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day { |
|
||||||
width: calc(100% / 7 - 6px); |
|
||||||
text-align: center; |
|
||||||
padding: calc(0.25em - 1px); |
|
||||||
font-size: 1.6em; |
|
||||||
border-radius: 7px; |
|
||||||
transition: 0.2s; |
|
||||||
border: 1px solid transparent; |
|
||||||
margin:3px; |
|
||||||
color: rgba(0, 0, 0, 0.8); |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
|
|
||||||
cursor: pointer; |
|
||||||
vertical-align: middle; |
|
||||||
background-color: #F3F3F3; |
|
||||||
color:#06BACE; |
|
||||||
|
|
||||||
} |
|
||||||
.Calendar__day.dashboard { |
|
||||||
width: calc(100% / 7 - 6px); |
|
||||||
text-align: center; |
|
||||||
padding: calc(0.25em - 1px); |
|
||||||
font-size: 1.6em; |
|
||||||
border-radius: 7px; |
|
||||||
transition: 0.2s; |
|
||||||
border: 1px solid transparent; |
|
||||||
margin:3px; |
|
||||||
color: rgba(0, 0, 0, 0.8); |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
|
|
||||||
cursor: pointer; |
|
||||||
vertical-align: middle; |
|
||||||
background-color: transparent; |
|
||||||
color:#00253A; |
|
||||||
|
|
||||||
} |
|
||||||
.Calendar__day span{ |
|
||||||
padding: -10px; |
|
||||||
margin-top: -30px; |
|
||||||
font-size: 28px; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day:focus { |
|
||||||
outline: 1px dashed rgba(0, 0, 0, 0.4); |
|
||||||
outline-offset: 2px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-ltr { |
|
||||||
min-height: 2.6em; |
|
||||||
font-size: 1.45em; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-rtl { |
|
||||||
font-size: 1.55em; |
|
||||||
height: 2.45em; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day:not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween):not(.-selected):hover { |
|
||||||
|
|
||||||
background-color: #DAFBFF; |
|
||||||
color: #06BACE; |
|
||||||
border:1px solid #06BACE; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-selected, |
|
||||||
.Calendar__day.-selectedStart, |
|
||||||
.Calendar__day.-selectedEnd { |
|
||||||
background: #006C94; |
|
||||||
color: #fff; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-ltr.-selectedStart { |
|
||||||
border-radius: 0; |
|
||||||
border-top-left-radius: 7px; |
|
||||||
border-bottom-left-radius: 7px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-rtl.-selectedStart { |
|
||||||
border-radius: 0; |
|
||||||
border-top-right-radius: 7px; |
|
||||||
border-bottom-right-radius: 7px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-selectedBetween { |
|
||||||
background:rgba(0, 108, 148, 0.07); |
|
||||||
|
|
||||||
border-radius: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-ltr.-selectedEnd { |
|
||||||
border-radius: 0; |
|
||||||
border-top-right-radius: 7px; |
|
||||||
border-bottom-right-radius: 7px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-rtl.-selectedEnd { |
|
||||||
border-radius: 0; |
|
||||||
border-top-left-radius: 7px; |
|
||||||
border-bottom-left-radius: 7px; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-weekend:not(.-selected):not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween) { |
|
||||||
color: var(--cl-color-error); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-weekend.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after { |
|
||||||
background: var(--cl-color-error); |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-disabled { |
|
||||||
color: var(--cl-color-disabled) !important; |
|
||||||
background: transparent !important; |
|
||||||
cursor: default !important; |
|
||||||
} |
|
||||||
.Calendar__day.-selected { |
|
||||||
|
|
||||||
} |
|
||||||
.Calendar__day.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween) { |
|
||||||
font-weight: 600; |
|
||||||
color: var(--cl-color-black); |
|
||||||
color: #000; |
|
||||||
position: relative; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after { |
|
||||||
content: ''; |
|
||||||
position: absolute; |
|
||||||
bottom: 0.2em; |
|
||||||
display: block; |
|
||||||
width: 0.6em; |
|
||||||
height: 1px; |
|
||||||
background: #000; |
|
||||||
left: 50%; |
|
||||||
opacity: 0.5; |
|
||||||
transform: translateX(-50%); |
|
||||||
transition: 0.2s; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-today:hover:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after { |
|
||||||
opacity: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__day.-blank { |
|
||||||
color: transparent; |
|
||||||
cursor: default; |
|
||||||
pointer-events: none; |
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__footer { |
|
||||||
position: relative; |
|
||||||
z-index: 1; |
|
||||||
} |
|
||||||
.Calendar__footer .footer__Events{ |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
align-items: center; |
|
||||||
font-size: 12px; |
|
||||||
font-family: 'IranSans'; |
|
||||||
padding: 3px; |
|
||||||
} |
|
||||||
.Calendar__footer .footer__Events.dashboard{ |
|
||||||
display: flex; |
|
||||||
justify-content: start; |
|
||||||
width: 100%; |
|
||||||
align-items: flex-start; |
|
||||||
font-size: 12px; |
|
||||||
font-family: 'IranSans'; |
|
||||||
margin-top: 10px; |
|
||||||
padding: 1em 2em; |
|
||||||
border-top: 1px solid #EDF2FB; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.Calendar__footer .footer__Events.dashboard p{ |
|
||||||
|
|
||||||
font-size: 15px; |
|
||||||
margin:2.5px 0px |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.Calendar .holiday span{ |
|
||||||
color:#ff2929; |
|
||||||
} |
|
||||||
.Calendar .DayNumDiv{ |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
} |
|
||||||
.Calendar .DayNumDiv span{ |
|
||||||
margin: 0; |
|
||||||
padding: 0; |
|
||||||
margin-bottom: -5px; |
|
||||||
} |
|
||||||
.Calendar .DayNumDiv .eventDots{ |
|
||||||
margin-top: -10px; |
|
||||||
font-size: 20px; |
|
||||||
} |
|
||||||
.GoToTodayButton{ |
|
||||||
background-color: #006C94; |
|
||||||
padding: 7.5px; |
|
||||||
font-size: 12px; |
|
||||||
color:white; |
|
||||||
font-family: 'iranSans'; |
|
||||||
border-radius: 50%; |
|
||||||
float: left; |
|
||||||
margin: 15px; |
|
||||||
|
|
||||||
} |
|
||||||
@keyframes fadeCalendar { |
|
||||||
from { |
|
||||||
opacity: 0; |
|
||||||
} |
|
||||||
|
|
||||||
to { |
|
||||||
opacity: 1; |
|
||||||
transform: translateY(0); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@keyframes fadeArrowFlipped { |
|
||||||
from { |
|
||||||
opacity: 0; |
|
||||||
} |
|
||||||
|
|
||||||
to { |
|
||||||
opacity: 1; |
|
||||||
transform: translateY(0) rotate(180deg); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@keyframes fadeTextToCenter { |
|
||||||
to { |
|
||||||
opacity: 1; |
|
||||||
transform: translateX(-50%); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@keyframes FadeContentToCenter { |
|
||||||
to { |
|
||||||
opacity: 1; |
|
||||||
transform: translateX(0); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,126 +0,0 @@ |
|||||||
import React, { useState } from "react"; |
|
||||||
import "./index.css"; |
|
||||||
import Calendar from "./CalendarComponents/Calendar"; |
|
||||||
import { utils } from "./CalendarComponents"; |
|
||||||
|
|
||||||
import "./index.css"; |
|
||||||
|
|
||||||
const SimpleCalendar = () => { |
|
||||||
const [selectedDay, setSelectedDay] = useState(null); |
|
||||||
const [type, setType] = useState("dashboard"); |
|
||||||
const list = { |
|
||||||
default: ( |
|
||||||
<Calendar |
|
||||||
value={selectedDay} |
|
||||||
onChange={setSelectedDay} |
|
||||||
shouldHighlightWeekends |
|
||||||
renderFooter={() => ( |
|
||||||
<center> |
|
||||||
<button |
|
||||||
className="GoToTodayButton" |
|
||||||
onClick={() => setSelectedDay(utils("fa").getToday())} |
|
||||||
> |
|
||||||
{" "} |
|
||||||
امروز{" "} |
|
||||||
</button> |
|
||||||
</center> |
|
||||||
)} |
|
||||||
locale="fa" |
|
||||||
events={eventsList} |
|
||||||
/> |
|
||||||
), |
|
||||||
dashboard: ( |
|
||||||
<Calendar |
|
||||||
value={selectedDay} |
|
||||||
onChange={setSelectedDay} |
|
||||||
shouldHighlightWeekends |
|
||||||
locale="fa" |
|
||||||
events={eventsList} |
|
||||||
type="dashboard" |
|
||||||
/> |
|
||||||
), |
|
||||||
}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<div className="flex flex-col items-center justify-center w-full my-2"> |
|
||||||
{/* <Calendar |
|
||||||
value={selectedDay} |
|
||||||
onChange={setSelectedDay} |
|
||||||
shouldHighlightWeekends |
|
||||||
renderFooter={() => <center><button className="GoToTodayButton" onClick={() => setSelectedDay(utils('fa').getToday())}> امروز </button></center>} |
|
||||||
locale="fa" |
|
||||||
events={eventsList} |
|
||||||
type='dashboard' |
|
||||||
/> */} |
|
||||||
|
|
||||||
<select |
|
||||||
className="mb-10 w-32 bg-gray-200" |
|
||||||
onChange={(e) => setType(e.target.value)} |
|
||||||
> |
|
||||||
{Object.keys(list).map((option, index) => ( |
|
||||||
<option key={index}>{option}</option> |
|
||||||
))} |
|
||||||
</select> |
|
||||||
{list[type]} |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
const eventsList = [ |
|
||||||
{ |
|
||||||
id: 2, |
|
||||||
description: "تست 2", |
|
||||||
type: "global", |
|
||||||
isHoliday: true, |
|
||||||
date: "2022-01-04T00:00:00.000Z", |
|
||||||
year: 1400, |
|
||||||
month: 10, |
|
||||||
day: 2, |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 4, |
|
||||||
description: "تست 4", |
|
||||||
type: "global", |
|
||||||
isHoliday: true, |
|
||||||
date: "2022-01-12T00:00:00.000Z", |
|
||||||
year: 1400, |
|
||||||
month: 10, |
|
||||||
day: 1, |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 1, |
|
||||||
description: "تست کاربر 1", |
|
||||||
type: "userDefined", |
|
||||||
userId: "5", |
|
||||||
date: "2022-01-12T00:00:00.000Z", |
|
||||||
categoryId: 1, |
|
||||||
year: 1400, |
|
||||||
month: 10, |
|
||||||
day: 3, |
|
||||||
color: "blue", |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 4, |
|
||||||
description: "تست کاربر 4", |
|
||||||
type: "userDefined", |
|
||||||
userId: "5", |
|
||||||
date: "2022-01-08T00:00:00.000Z", |
|
||||||
categoryId: 3, |
|
||||||
year: 1400, |
|
||||||
month: 11, |
|
||||||
day: 6, |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 5, |
|
||||||
description: "تست کاربر 5", |
|
||||||
type: "userDefined", |
|
||||||
userId: "5", |
|
||||||
date: "2022-01-12T00:00:00.000Z", |
|
||||||
categoryId: 1, |
|
||||||
year: 1400, |
|
||||||
month: 10, |
|
||||||
day: 3, |
|
||||||
}, |
|
||||||
]; |
|
||||||
|
|
||||||
export default SimpleCalendar; |
|
Loading…
Reference in new issue