@jk-core/components 0.1.15 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -4
- package/dist/index.js +665 -1030
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +8 -16
- package/dist/index.umd.cjs.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/vite.config.d.ts +2 -0
- package/package.json +24 -21
- package/src/Calendar/Calendar.module.scss +213 -0
- package/src/Calendar/RangeCalendar.tsx +125 -0
- package/src/Calendar/ScrollCalendar.module.scss +214 -0
- package/src/Calendar/ScrollCalendar.tsx +124 -0
- package/src/Calendar/SingleCalendar.tsx +121 -0
- package/src/Calendar/components/DateLabel/DateLabel.module.scss +89 -0
- package/src/Calendar/components/DateLabel/index.tsx +91 -0
- package/src/Calendar/components/DayTile/DayTile.module.scss +117 -0
- package/src/Calendar/components/DayTile/index.tsx +100 -0
- package/src/Calendar/components/MonthTile/MonthTile.module.scss +59 -0
- package/src/Calendar/components/MonthTile/index.tsx +50 -0
- package/src/Calendar/components/ViewSelector/ViewSelector.module.scss +48 -0
- package/src/Calendar/components/ViewSelector/index.tsx +49 -0
- package/src/Calendar/components/YearTile/YearTile.module.scss +86 -0
- package/src/Calendar/components/YearTile/index.tsx +65 -0
- package/src/Calendar/hooks/useCalendarNav.ts +80 -0
- package/src/Calendar/hooks/useDateSelect.ts +54 -0
- package/src/Calendar/index.scss +189 -0
- package/src/Calendar/index.tsx +66 -0
- package/src/Calendar/type.ts +3 -0
- package/src/Calendar/utils/getWeeksInMonth.ts +45 -0
- package/src/Calendar/utils/isInRange.ts +8 -0
- package/src/Calendar/utils/isSameDay.ts +21 -0
- package/src/assets/arrow.svg +12 -0
- package/src/assets/close.svg +16 -0
- package/src/assets/drop-arrow.svg +3 -0
- package/src/index.tsx +5 -0
- package/src/styles/mediaQuery.scss +22 -0
- package/src/svg.d.ts +4 -0
- package/src/vite-env.d.ts +2 -0
- /package/dist/{Calendar → src/Calendar}/RangeCalendar.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/ScrollCalendar.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/SingleCalendar.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/components/DateLabel/index.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/components/DayTile/index.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/components/MonthTile/index.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/components/ViewSelector/index.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/components/YearTile/index.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/hooks/useCalendarNav.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/hooks/useDateSelect.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/index.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/type.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/utils/getWeeksInMonth.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/utils/isInRange.d.ts +0 -0
- /package/dist/{Calendar → src/Calendar}/utils/isSameDay.d.ts +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { cn } from '@jk-core/utils';
|
|
2
|
+
import isSameDay from '../../utils/isSameDay';
|
|
3
|
+
import { CalendarView } from '../../type';
|
|
4
|
+
import styles from './MonthTile.module.scss';
|
|
5
|
+
|
|
6
|
+
const MONTHS = Array.from({ length: 12 }, (_, i) => i);
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
selectedDate?: Date;
|
|
10
|
+
viewDate: Date;
|
|
11
|
+
handleMonthClick: (month: number) => void;
|
|
12
|
+
tileContent?: (date: Date, view:CalendarView) => React.ReactNode;
|
|
13
|
+
max: Date;
|
|
14
|
+
min: Date;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function MonthTile({
|
|
18
|
+
selectedDate, viewDate, handleMonthClick, tileContent = () => false,
|
|
19
|
+
max, min,
|
|
20
|
+
}: Props) {
|
|
21
|
+
const isDisabled = (month: number) => {
|
|
22
|
+
const monthDate = new Date(viewDate.getFullYear(), month, 1);
|
|
23
|
+
|
|
24
|
+
return monthDate > new Date(max.getFullYear(), max.getMonth(), 1)
|
|
25
|
+
|| monthDate < new Date(min.getFullYear(), min.getMonth(), 1);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className={styles['month-tile']}>
|
|
30
|
+
{MONTHS.map((month) => (
|
|
31
|
+
<button
|
|
32
|
+
className={cn({
|
|
33
|
+
[styles['month-tile__month']]: true,
|
|
34
|
+
[styles['month-tile__month--selected']]: !!selectedDate && isSameDay(selectedDate, new Date(viewDate.getFullYear(), month), 'month'),
|
|
35
|
+
[styles['month-tile__month--today']]: isSameDay(new Date(viewDate.getFullYear(), month), new Date(), 'month'),
|
|
36
|
+
[styles['month-tile__month--tile']]: !!tileContent(new Date(viewDate.getFullYear(), month - 1, 1), 'month'),
|
|
37
|
+
})}
|
|
38
|
+
type="button"
|
|
39
|
+
key={month}
|
|
40
|
+
onClick={() => handleMonthClick(month)}
|
|
41
|
+
disabled={isDisabled(month)}
|
|
42
|
+
>
|
|
43
|
+
<span>{`${month + 1}월`}</span>
|
|
44
|
+
{!!tileContent(new Date(viewDate.getFullYear(), month - 1, 1), 'month')
|
|
45
|
+
&& tileContent(new Date(viewDate.getFullYear(), month - 1, 1), 'month')}
|
|
46
|
+
</button>
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
.view {
|
|
2
|
+
position: relative;
|
|
3
|
+
margin: 0 auto;
|
|
4
|
+
width: 90%;
|
|
5
|
+
display: flex;
|
|
6
|
+
justify-content: space-between;
|
|
7
|
+
align-items: center;
|
|
8
|
+
background-color: var(--calendar-S-10);
|
|
9
|
+
color: var(--calendar-black);
|
|
10
|
+
border-radius: 10px;
|
|
11
|
+
|
|
12
|
+
&__block {
|
|
13
|
+
position: absolute;
|
|
14
|
+
background-color: var(--calendar-white);
|
|
15
|
+
left: 0;
|
|
16
|
+
height: 100%;
|
|
17
|
+
border: 2px solid var(--calendar-G-30);
|
|
18
|
+
width: 33.3%;
|
|
19
|
+
border-radius: 10px;
|
|
20
|
+
transition: 0.3s;
|
|
21
|
+
|
|
22
|
+
&--second {
|
|
23
|
+
left: 33%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&--last {
|
|
27
|
+
left: 66.6%;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&__selector {
|
|
32
|
+
position: relative;
|
|
33
|
+
height: 40px;
|
|
34
|
+
flex: 1 0;
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
color: var(--calendar-G-60);
|
|
39
|
+
font-size: 1em;
|
|
40
|
+
font-weight: 400;
|
|
41
|
+
|
|
42
|
+
&--selected {
|
|
43
|
+
color: var(--calendar-G-80);
|
|
44
|
+
font-size: 1em;
|
|
45
|
+
font-weight: 600;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { cn } from '@jk-core/utils';
|
|
2
|
+
import { CalendarView } from 'Calendar/type';
|
|
3
|
+
import styles from './ViewSelector.module.scss';
|
|
4
|
+
|
|
5
|
+
interface ViewSelectorProps {
|
|
6
|
+
method: CalendarView;
|
|
7
|
+
selectView: (value: CalendarView) => void;
|
|
8
|
+
}
|
|
9
|
+
export default function ViewSelector({ method, selectView }:ViewSelectorProps) {
|
|
10
|
+
return (
|
|
11
|
+
<div className={styles.view}>
|
|
12
|
+
<div className={
|
|
13
|
+
cn({
|
|
14
|
+
[styles.view__block]: true,
|
|
15
|
+
[styles['view__block--second']]: method === 'month',
|
|
16
|
+
[styles['view__block--last']]: method === 'year',
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
/>
|
|
20
|
+
<button
|
|
21
|
+
className={cn({
|
|
22
|
+
[styles.view__selector]: true,
|
|
23
|
+
[styles['view__selector--selected']]: method === 'day',
|
|
24
|
+
})}
|
|
25
|
+
type="button"
|
|
26
|
+
onClick={() => selectView('day')}
|
|
27
|
+
>일
|
|
28
|
+
</button>
|
|
29
|
+
<button
|
|
30
|
+
className={cn({
|
|
31
|
+
[styles.view__selector]: true,
|
|
32
|
+
[styles['view__selector--selected']]: method === 'month',
|
|
33
|
+
})}
|
|
34
|
+
type="button"
|
|
35
|
+
onClick={() => selectView('month')}
|
|
36
|
+
>월
|
|
37
|
+
</button>
|
|
38
|
+
<button
|
|
39
|
+
className={cn({
|
|
40
|
+
[styles.view__selector]: true,
|
|
41
|
+
[styles['view__selector--selected']]: method === 'year',
|
|
42
|
+
})}
|
|
43
|
+
type="button"
|
|
44
|
+
onClick={() => selectView('year')}
|
|
45
|
+
>년
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
@use "../../../styles/mediaQuery.scss" as media;
|
|
2
|
+
|
|
3
|
+
.year-tile {
|
|
4
|
+
position: relative;
|
|
5
|
+
min-height: 310px;
|
|
6
|
+
padding: 5px;
|
|
7
|
+
position: relative;
|
|
8
|
+
height: 310px;
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
align-items: center;
|
|
12
|
+
overflow: auto;
|
|
13
|
+
gap: 10px;
|
|
14
|
+
|
|
15
|
+
&::-webkit-scrollbar {
|
|
16
|
+
display: none;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&__blank {
|
|
20
|
+
height: calc(50% - 40px);
|
|
21
|
+
flex-shrink: 0;
|
|
22
|
+
|
|
23
|
+
&:last-child {
|
|
24
|
+
height: 50%;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&__year {
|
|
29
|
+
min-width: 50%;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
min-height: 40px;
|
|
35
|
+
border-radius: 6px;
|
|
36
|
+
flex-shrink: 0;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
font-weight: 400;
|
|
39
|
+
font-size: 1.2em;
|
|
40
|
+
color: var(--calendar-G-80);
|
|
41
|
+
|
|
42
|
+
&:hover {
|
|
43
|
+
@include media.pc {
|
|
44
|
+
background-color: var(--calendar-P-5);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&:active {
|
|
49
|
+
background-color: var(--calendar-P-10);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&--border {
|
|
53
|
+
border: 1px solid var(--calendar-G-30);
|
|
54
|
+
background-color: var(--calendar-P-5);
|
|
55
|
+
|
|
56
|
+
&:hover {
|
|
57
|
+
@include media.pc {
|
|
58
|
+
background-color: var(--calendar-P-10);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&--year {
|
|
64
|
+
height: 40px;
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
&--selected {
|
|
71
|
+
color: var(--calendar-white);
|
|
72
|
+
background-color: var(--calendar-P-50) !important;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&--tile {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
min-height: 40px;
|
|
80
|
+
color: var(--calendar-G-80);
|
|
81
|
+
width: 100%;
|
|
82
|
+
background-color: var(--calendar-white);
|
|
83
|
+
border-top: var(--calendar-P-50);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { cn } from '@jk-core/utils';
|
|
3
|
+
import { CalendarView } from '../../type';
|
|
4
|
+
import styles from './YearTile.module.scss';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
selectedDate?: Date;
|
|
8
|
+
onClick: (year: number) => void;
|
|
9
|
+
tileContent?: (date: Date, view:CalendarView) => React.ReactNode;
|
|
10
|
+
max: Date;
|
|
11
|
+
min: Date;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function YearTile({
|
|
15
|
+
selectedDate, onClick,
|
|
16
|
+
tileContent = () => false,
|
|
17
|
+
max, min,
|
|
18
|
+
}: Props) {
|
|
19
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
20
|
+
const selectedRef = useRef<HTMLButtonElement>(null);
|
|
21
|
+
const YEARS = Array.from(
|
|
22
|
+
{ length: max.getFullYear() - min.getFullYear() + 1 },
|
|
23
|
+
(_, i) => min.getFullYear() + i,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const selectedElement = selectedRef.current;
|
|
28
|
+
const wrapperElement = wrapperRef.current;
|
|
29
|
+
if (!selectedElement || !wrapperElement) return;
|
|
30
|
+
|
|
31
|
+
const { clientHeight } = wrapperElement;
|
|
32
|
+
const { offsetTop, clientHeight: selectedHeight } = selectedElement;
|
|
33
|
+
|
|
34
|
+
wrapperElement.scrollTo({
|
|
35
|
+
top: offsetTop - clientHeight / 2 + selectedHeight,
|
|
36
|
+
});
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className={styles['year-tile']} ref={wrapperRef}>
|
|
41
|
+
<div className={styles['year-tile__blank']} />
|
|
42
|
+
{YEARS.map((year) => (
|
|
43
|
+
<button
|
|
44
|
+
className={cn({
|
|
45
|
+
[styles['year-tile__year']]: true,
|
|
46
|
+
[styles['year-tile__year--selected']]: !!selectedDate && selectedDate.getFullYear() === year,
|
|
47
|
+
[styles['year-tile__year--border']]: !!tileContent(new Date(year, 1, 1), 'year'),
|
|
48
|
+
})}
|
|
49
|
+
key={year}
|
|
50
|
+
type="button"
|
|
51
|
+
ref={!!selectedDate && selectedDate.getFullYear() === year ? selectedRef : null}
|
|
52
|
+
onClick={() => onClick(year)}
|
|
53
|
+
>
|
|
54
|
+
<span className={styles['yearTile__year--year']}>{year}</span>
|
|
55
|
+
{tileContent(new Date(year, 1, 1), 'year') && (
|
|
56
|
+
<div className={styles['yearTile__year--tile']}>
|
|
57
|
+
{tileContent(new Date(year, 1, 1), 'year')}
|
|
58
|
+
</div>
|
|
59
|
+
)}
|
|
60
|
+
</button>
|
|
61
|
+
))}
|
|
62
|
+
<div className={styles['year-tile__blank']} />
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { CalendarView } from '../type';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
method: CalendarView;
|
|
5
|
+
selectMode: CalendarView;
|
|
6
|
+
viewDate: Date;
|
|
7
|
+
setDate:(date: Date) => void;
|
|
8
|
+
min: Date;
|
|
9
|
+
max: Date;
|
|
10
|
+
}
|
|
11
|
+
const useCalendarNav = ({
|
|
12
|
+
method, selectMode, viewDate, setDate, min, max,
|
|
13
|
+
}:Props) => {
|
|
14
|
+
const disabled = (direction: 'prev' | 'next') => {
|
|
15
|
+
if (selectMode === 'year' || method !== selectMode) return true;
|
|
16
|
+
|
|
17
|
+
if (method === 'day') {
|
|
18
|
+
if (direction === 'prev') {
|
|
19
|
+
const prevMonth = new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1);
|
|
20
|
+
return prevMonth < min;
|
|
21
|
+
}
|
|
22
|
+
const nextMonth = new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1);
|
|
23
|
+
return nextMonth > max;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (method === 'month') {
|
|
27
|
+
if (direction === 'prev') {
|
|
28
|
+
const prevYear = new Date(viewDate.getFullYear() - 1, viewDate.getMonth(), 1);
|
|
29
|
+
return prevYear < min;
|
|
30
|
+
}
|
|
31
|
+
const nextYear = new Date(viewDate.getFullYear() + 1, viewDate.getMonth(), 1);
|
|
32
|
+
return nextYear > max;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (method === 'year') {
|
|
36
|
+
if (direction === 'prev') {
|
|
37
|
+
const prevDecade = new Date(viewDate.getFullYear() - 10, viewDate.getMonth(), 1);
|
|
38
|
+
return prevDecade < min;
|
|
39
|
+
}
|
|
40
|
+
const nextDecade = new Date(viewDate.getFullYear() + 10, viewDate.getMonth(), 1);
|
|
41
|
+
return nextDecade > max;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return false;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const onArrowClick = (direction: 'prev' | 'next') => {
|
|
48
|
+
const offset = direction === 'prev' ? -1 : 1;
|
|
49
|
+
const minDate = new Date(2000, 0, 1);
|
|
50
|
+
const maxDate = new Date(2099, 11, 31);
|
|
51
|
+
|
|
52
|
+
if (method === 'day') {
|
|
53
|
+
const newDate = new Date(viewDate.getFullYear(), viewDate.getMonth() + offset, 1);
|
|
54
|
+
|
|
55
|
+
if (newDate >= minDate && newDate <= maxDate) {
|
|
56
|
+
setDate(newDate);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (method === 'month') {
|
|
61
|
+
const newDate = new Date(viewDate.getFullYear() + offset, viewDate.getMonth(), 1);
|
|
62
|
+
|
|
63
|
+
if (newDate >= minDate && newDate <= maxDate) {
|
|
64
|
+
setDate(newDate);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (method === 'year') {
|
|
69
|
+
const newDate = new Date(viewDate.getFullYear() + offset * 10, viewDate.getMonth(), 1);
|
|
70
|
+
|
|
71
|
+
if (newDate >= minDate && newDate <= maxDate) {
|
|
72
|
+
setDate(newDate);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return { disabled, onArrowClick };
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default useCalendarNav;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { CalendarView } from '../type';
|
|
2
|
+
|
|
3
|
+
interface UseDateSelectProps {
|
|
4
|
+
viewDate: Date;
|
|
5
|
+
setViewDate: (date: Date) => void;
|
|
6
|
+
method: CalendarView;
|
|
7
|
+
setSelectMode:(mode:CalendarView) => void;
|
|
8
|
+
onChange: (date: Date) => void;
|
|
9
|
+
setView:(view:CalendarView)=>void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const useDateSelect = ({
|
|
13
|
+
viewDate, setViewDate, onChange, setSelectMode, method, setView,
|
|
14
|
+
}: UseDateSelectProps) => {
|
|
15
|
+
const min = new Date(2000, 0, 1);
|
|
16
|
+
const max = new Date(2099, 11, 31);
|
|
17
|
+
|
|
18
|
+
const onDayClick = (day: Date) => {
|
|
19
|
+
if (day < min || day > max) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setViewDate(day);
|
|
24
|
+
setView('day');
|
|
25
|
+
onChange(day);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const onMonthClick = (month:number) => {
|
|
29
|
+
const newDate = new Date(viewDate.getFullYear(), month, 1);
|
|
30
|
+
|
|
31
|
+
setViewDate(newDate);
|
|
32
|
+
|
|
33
|
+
if (method !== 'month') setSelectMode(method);
|
|
34
|
+
if (method === 'month') {
|
|
35
|
+
setView('month');
|
|
36
|
+
onChange(newDate);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const onYearClick = (year:number) => {
|
|
41
|
+
const newDate = new Date(year, 0, 1);
|
|
42
|
+
|
|
43
|
+
setViewDate(newDate);
|
|
44
|
+
if (method !== 'year') setSelectMode(method);
|
|
45
|
+
if (method === 'year') {
|
|
46
|
+
setView('year');
|
|
47
|
+
onChange(newDate);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return { onDayClick, onMonthClick, onYearClick };
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default useDateSelect;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
button {
|
|
2
|
+
border: none;
|
|
3
|
+
background-color: transparent;
|
|
4
|
+
user-select: none;
|
|
5
|
+
-webkit-user-select: none;
|
|
6
|
+
-moz-user-select: none;
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
-webkit-tap-highlight-color: transparent; // 모바일 터치 하이라이트 색상 제거
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body:not([data-theme="dark"]) {
|
|
12
|
+
--calendar-white: #ffffff;
|
|
13
|
+
--calendar-black: #000000;
|
|
14
|
+
--calendar-P-5: #eff5ff;
|
|
15
|
+
--calendar-P-10: #d3e1fb;
|
|
16
|
+
--calendar-P-20: #a7c4f7;
|
|
17
|
+
--calendar-P-30: #7ca6f3;
|
|
18
|
+
--calendar-P-40: #5089ef;
|
|
19
|
+
--calendar-P-50: #246beb;
|
|
20
|
+
--calendar-P-60: #1d56bc;
|
|
21
|
+
--calendar-P-70: #16408d;
|
|
22
|
+
--calendar-P-90: #07152f;
|
|
23
|
+
--calendar-P-100: #000000;
|
|
24
|
+
--calendar-S-5: #edf1f5;
|
|
25
|
+
--calendar-S-10: #cdd7e4;
|
|
26
|
+
--calendar-S-20: #b4c4d6;
|
|
27
|
+
--calendar-S-30: #99b0cb;
|
|
28
|
+
--calendar-S-40: #2a5c96;
|
|
29
|
+
--calendar-S-50: #003675;
|
|
30
|
+
--calendar-S-60: #002b5e;
|
|
31
|
+
--calendar-S-70: #002036;
|
|
32
|
+
--calendar-S-80: #00162f;
|
|
33
|
+
--calendar-S-90: #000b17;
|
|
34
|
+
--calendar-G-5: #f8f8f8;
|
|
35
|
+
--calendar-G-10: #f0f0f0;
|
|
36
|
+
--calendar-G-20: #e4e4e4;
|
|
37
|
+
--calendar-G-30: #d8d8d8;
|
|
38
|
+
--calendar-G-40: #c6c6c6;
|
|
39
|
+
--calendar-G-50: #8e8e8e;
|
|
40
|
+
--calendar-G-60: #717171;
|
|
41
|
+
--calendar-G-70: #555555;
|
|
42
|
+
--calendar-G-80: #2d2d2d;
|
|
43
|
+
--calendar-G-90: #1d1d1d;
|
|
44
|
+
--calendar-Point-5: #fdf2f3;
|
|
45
|
+
--calendar-Point-10: #f8d6d8;
|
|
46
|
+
--calendar-Point-20: #f5a3a8;
|
|
47
|
+
--calendar-Point-30: #f1747c;
|
|
48
|
+
--calendar-Point-40: #ec4651;
|
|
49
|
+
--calendar-Point-50: #e71825;
|
|
50
|
+
--calendar-Point-60: #b9131e;
|
|
51
|
+
--calendar-Point-70: #8b0e16;
|
|
52
|
+
--calendar-Point-80: #5c0a0f;
|
|
53
|
+
--calendar-Point-90: #2e0507;
|
|
54
|
+
--calendar-Warning-5: #fff8e9;
|
|
55
|
+
--calendar-Warning-10: #ffeac1;
|
|
56
|
+
--calendar-Warning-20: #ffe2a7;
|
|
57
|
+
--calendar-Warning-30: #ffd47c;
|
|
58
|
+
--calendar-Warning-40: #ffc550;
|
|
59
|
+
--calendar-Warning-50: #ffb724;
|
|
60
|
+
--calendar-Warning-60: #98690a;
|
|
61
|
+
--calendar-Warning-70: #66490e;
|
|
62
|
+
--calendar-Warning-80: #4d370b;
|
|
63
|
+
--calendar-Warning-90: #332507;
|
|
64
|
+
--calendar-Success-5: #eef7f0;
|
|
65
|
+
--calendar-Success-10: #cee9d4;
|
|
66
|
+
--calendar-Success-20: #b2dcbb;
|
|
67
|
+
--calendar-Success-30: #8cca99;
|
|
68
|
+
--calendar-Success-40: #33a14b;
|
|
69
|
+
--calendar-Success-50: #008a1e;
|
|
70
|
+
--calendar-Success-60: #006e18;
|
|
71
|
+
--calendar-Success-70: #005312;
|
|
72
|
+
--calendar-Success-80: #00370c;
|
|
73
|
+
--calendar-Success-90: #002207;
|
|
74
|
+
--calendar-Info-5: #e9f0ff;
|
|
75
|
+
--calendar-Info-10: #d4e1ff;
|
|
76
|
+
--calendar-Info-20: #a9c3ff;
|
|
77
|
+
--calendar-Info-30: #7da4ff;
|
|
78
|
+
--calendar-Info-40: #5286ff;
|
|
79
|
+
--calendar-Info-50: #2768ff;
|
|
80
|
+
--calendar-Info-60: #1f53cc;
|
|
81
|
+
--calendar-Info-70: #173e99;
|
|
82
|
+
--calendar-Info-80: #0c1f4d;
|
|
83
|
+
--calendar-Info-90: #040a1a;
|
|
84
|
+
--calendar-Red: #e40000;
|
|
85
|
+
--calendar-Red2: #ffe4e4;
|
|
86
|
+
--calendar-Green: #2fb400;
|
|
87
|
+
--calendar-Green-2: #d7ffe0;
|
|
88
|
+
--calendar-Orange: #ff8800;
|
|
89
|
+
--calendar-Orange-5: #ffead1;
|
|
90
|
+
--calendar-Orange-10: #ffdacc;
|
|
91
|
+
--calendar-Orange-30: #ff8f66;
|
|
92
|
+
--calendar-Orange-40: #ff6a33;
|
|
93
|
+
--calendar-Orange-50: #ff4500;
|
|
94
|
+
--calendar-Orange-60: #d53209;
|
|
95
|
+
--calendar-Orange-70: #992900;
|
|
96
|
+
--calendar-Orange-80: #661c00;
|
|
97
|
+
--calendar-Orange-90: #330e00;
|
|
98
|
+
--Calendar-Background: #ffffff;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
body[data-theme="dark"] {
|
|
102
|
+
--calendar-white: #000000;
|
|
103
|
+
--calendar-black: #ffffff;
|
|
104
|
+
--calendar-P-90: #eff5ff;
|
|
105
|
+
--calendar-P-80: #d3e1fb;
|
|
106
|
+
--calendar-P-70: #a7c4f7;
|
|
107
|
+
--calendar-P-60: #7ca6f3;
|
|
108
|
+
--calendar-P-50: #5089ef;
|
|
109
|
+
--calendar-P-40: #246beb;
|
|
110
|
+
--calendar-P-30: #225fc9;
|
|
111
|
+
--calendar-P-20: #1e53b4;
|
|
112
|
+
--calendar-P-10: #1b4ba3;
|
|
113
|
+
--calendar-P-5: #0f2b5f;
|
|
114
|
+
--calendar-S-90: #edf1f5;
|
|
115
|
+
--calendar-S-80: #cdd7e4;
|
|
116
|
+
--calendar-S-70: #b4c4d6;
|
|
117
|
+
--calendar-S-60: #99b0cb;
|
|
118
|
+
--calendar-S-50: #2a5c96;
|
|
119
|
+
--calendar-S-40: #003675;
|
|
120
|
+
--calendar-S-30: #002b5e;
|
|
121
|
+
--calendar-S-20: #002036;
|
|
122
|
+
--calendar-S-10: #00162f;
|
|
123
|
+
--calendar-S-5: #000b17;
|
|
124
|
+
--calendar-G-90: #f8f8f8;
|
|
125
|
+
--calendar-G-80: #f0f0f0;
|
|
126
|
+
--calendar-G-70: #e4e4e4;
|
|
127
|
+
--calendar-G-60: #d8d8d8;
|
|
128
|
+
--calendar-G-50: #c6c6c6;
|
|
129
|
+
--calendar-G-40: #8e8e8e;
|
|
130
|
+
--calendar-G-30: #717171;
|
|
131
|
+
--calendar-G-20: #555555;
|
|
132
|
+
--calendar-G-10: #2d2d2d;
|
|
133
|
+
--calendar-G-5: #1d1d1d;
|
|
134
|
+
--calendar-Point-5: #fdf2f3;
|
|
135
|
+
--calendar-Point-10: #f8d6d8;
|
|
136
|
+
--calendar-Point-20: #f5a3a8;
|
|
137
|
+
--calendar-Point-30: #f1747c;
|
|
138
|
+
--calendar-Point-40: #ec4651;
|
|
139
|
+
--calendar-Point-50: #e71825;
|
|
140
|
+
--calendar-Point-60: #b9131e;
|
|
141
|
+
--calendar-Point-70: #8b0e16;
|
|
142
|
+
--calendar-Point-80: #5c0a0f;
|
|
143
|
+
--calendar-Point-90: #2e0507;
|
|
144
|
+
--calendar-Warning-5: #fff8e9;
|
|
145
|
+
--calendar-Warning-10: #ffeac1;
|
|
146
|
+
--calendar-Warning-20: #ffe2a7;
|
|
147
|
+
--calendar-Warning-30: #ffd47c;
|
|
148
|
+
--calendar-Warning-40: #ffc550;
|
|
149
|
+
--calendar-Warning-50: #ffb724;
|
|
150
|
+
--calendar-Warning-60: #98690a;
|
|
151
|
+
--calendar-Warning-70: #66490e;
|
|
152
|
+
--calendar-Warning-80: #4d370b;
|
|
153
|
+
--calendar-Warning-90: #332507;
|
|
154
|
+
--calendar-Success-5: #eef7f0;
|
|
155
|
+
--calendar-Success-10: #cee9d4;
|
|
156
|
+
--calendar-Success-20: #b2dcbb;
|
|
157
|
+
--calendar-Success-30: #8cca99;
|
|
158
|
+
--calendar-Success-40: #33a14b;
|
|
159
|
+
--calendar-Success-50: #008a1e;
|
|
160
|
+
--calendar-Success-60: #006e18;
|
|
161
|
+
--calendar-Success-70: #005312;
|
|
162
|
+
--calendar-Success-80: #00370c;
|
|
163
|
+
--calendar-Success-90: #002207;
|
|
164
|
+
--calendar-Info-5: #e9f0ff;
|
|
165
|
+
--calendar-Info-10: #d4e1ff;
|
|
166
|
+
--calendar-Info-20: #a9c3ff;
|
|
167
|
+
--calendar-Info-30: #7da4ff;
|
|
168
|
+
--calendar-Info-40: #5286ff;
|
|
169
|
+
--calendar-Info-50: #2768ff;
|
|
170
|
+
--calendar-Info-60: #1f53cc;
|
|
171
|
+
--calendar-Info-70: #173e99;
|
|
172
|
+
--calendar-Info-80: #0c1f4d;
|
|
173
|
+
--calendar-Info-90: #040a1a;
|
|
174
|
+
--calendar-Red: #e40000;
|
|
175
|
+
--calendar-Red2: #ffe4e4;
|
|
176
|
+
--calendar-Green: #2fb400;
|
|
177
|
+
--calendar-Green-2: #d7ffe0;
|
|
178
|
+
--calendar-Orange: #ff8800;
|
|
179
|
+
--calendar-Orange-5: #ffead1;
|
|
180
|
+
--calendar-Orange-10: #ffdacc;
|
|
181
|
+
--calendar-Orange-30: #ff8f66;
|
|
182
|
+
--calendar-Orange-40: #ff6a33;
|
|
183
|
+
--calendar-Orange-50: #ff4500;
|
|
184
|
+
--calendar-Orange-60: #d53209;
|
|
185
|
+
--calendar-Orange-70: #992900;
|
|
186
|
+
--calendar-Orange-80: #661c00;
|
|
187
|
+
--calendar-Orange-90: #330e00;
|
|
188
|
+
--Calendar-Background: #ffffff;
|
|
189
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* eslint-disable react/no-array-index-key */
|
|
2
|
+
import { CalendarRange, CalendarView } from './type';
|
|
3
|
+
import RangeCalendar from './RangeCalendar';
|
|
4
|
+
import SingleCalendar from './SingleCalendar';
|
|
5
|
+
import ScrollCalendar from './ScrollCalendar';
|
|
6
|
+
|
|
7
|
+
import './index.scss';
|
|
8
|
+
|
|
9
|
+
interface CalendarProps {
|
|
10
|
+
className?: string;
|
|
11
|
+
date?: Date | CalendarRange;
|
|
12
|
+
view?: CalendarView;
|
|
13
|
+
setView?: (view:CalendarView)=>void;
|
|
14
|
+
tileContent?: (date: Date | undefined, view: CalendarView) => React.ReactNode;
|
|
15
|
+
onChange?:(date:Date | CalendarRange)=>void;
|
|
16
|
+
min?: Date;
|
|
17
|
+
max?: Date;
|
|
18
|
+
onClose?: () => void;
|
|
19
|
+
viewSelector?: boolean;
|
|
20
|
+
selectRange?: boolean;
|
|
21
|
+
scroll?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default function Calendar({
|
|
25
|
+
className = '', date: selectedDate, view, setView = () => { }, tileContent, onChange = () => { }, onClose, viewSelector = true,
|
|
26
|
+
min = new Date('2000-01-01'), max = new Date('2099-11-31'), selectRange = false, scroll = false,
|
|
27
|
+
}: CalendarProps) {
|
|
28
|
+
if (scroll) {
|
|
29
|
+
return (
|
|
30
|
+
<ScrollCalendar
|
|
31
|
+
className={className}
|
|
32
|
+
date={selectedDate as CalendarRange}
|
|
33
|
+
onChange={onChange}
|
|
34
|
+
min={min}
|
|
35
|
+
max={max}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
if (selectRange) {
|
|
40
|
+
return (
|
|
41
|
+
<RangeCalendar
|
|
42
|
+
className={className}
|
|
43
|
+
date={selectedDate as CalendarRange}
|
|
44
|
+
onChange={onChange}
|
|
45
|
+
min={min}
|
|
46
|
+
max={max}
|
|
47
|
+
onClose={onClose}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<SingleCalendar
|
|
54
|
+
className={className}
|
|
55
|
+
date={selectedDate as Date}
|
|
56
|
+
view={view}
|
|
57
|
+
setView={setView}
|
|
58
|
+
tileContent={tileContent}
|
|
59
|
+
onChange={onChange}
|
|
60
|
+
min={min}
|
|
61
|
+
max={max}
|
|
62
|
+
onClose={onClose}
|
|
63
|
+
viewSelector={viewSelector}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|