@jk-core/components 0.1.16 → 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.
Files changed (53) hide show
  1. package/dist/index.d.ts +2 -4
  2. package/dist/index.js +661 -1026
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.umd.cjs +7 -15
  5. package/dist/index.umd.cjs.map +1 -1
  6. package/dist/src/index.d.ts +4 -0
  7. package/dist/vite.config.d.ts +2 -0
  8. package/package.json +24 -21
  9. package/src/Calendar/Calendar.module.scss +213 -0
  10. package/src/Calendar/RangeCalendar.tsx +125 -0
  11. package/src/Calendar/ScrollCalendar.module.scss +214 -0
  12. package/src/Calendar/ScrollCalendar.tsx +124 -0
  13. package/src/Calendar/SingleCalendar.tsx +121 -0
  14. package/src/Calendar/components/DateLabel/DateLabel.module.scss +89 -0
  15. package/src/Calendar/components/DateLabel/index.tsx +91 -0
  16. package/src/Calendar/components/DayTile/DayTile.module.scss +117 -0
  17. package/src/Calendar/components/DayTile/index.tsx +100 -0
  18. package/src/Calendar/components/MonthTile/MonthTile.module.scss +59 -0
  19. package/src/Calendar/components/MonthTile/index.tsx +50 -0
  20. package/src/Calendar/components/ViewSelector/ViewSelector.module.scss +48 -0
  21. package/src/Calendar/components/ViewSelector/index.tsx +49 -0
  22. package/src/Calendar/components/YearTile/YearTile.module.scss +86 -0
  23. package/src/Calendar/components/YearTile/index.tsx +65 -0
  24. package/src/Calendar/hooks/useCalendarNav.ts +80 -0
  25. package/src/Calendar/hooks/useDateSelect.ts +54 -0
  26. package/src/Calendar/index.scss +189 -0
  27. package/src/Calendar/index.tsx +66 -0
  28. package/src/Calendar/type.ts +3 -0
  29. package/src/Calendar/utils/getWeeksInMonth.ts +45 -0
  30. package/src/Calendar/utils/isInRange.ts +8 -0
  31. package/src/Calendar/utils/isSameDay.ts +21 -0
  32. package/src/assets/arrow.svg +12 -0
  33. package/src/assets/close.svg +16 -0
  34. package/src/assets/drop-arrow.svg +3 -0
  35. package/src/index.tsx +5 -0
  36. package/src/styles/mediaQuery.scss +22 -0
  37. package/src/svg.d.ts +4 -0
  38. package/src/vite-env.d.ts +2 -0
  39. /package/dist/{Calendar → src/Calendar}/RangeCalendar.d.ts +0 -0
  40. /package/dist/{Calendar → src/Calendar}/ScrollCalendar.d.ts +0 -0
  41. /package/dist/{Calendar → src/Calendar}/SingleCalendar.d.ts +0 -0
  42. /package/dist/{Calendar → src/Calendar}/components/DateLabel/index.d.ts +0 -0
  43. /package/dist/{Calendar → src/Calendar}/components/DayTile/index.d.ts +0 -0
  44. /package/dist/{Calendar → src/Calendar}/components/MonthTile/index.d.ts +0 -0
  45. /package/dist/{Calendar → src/Calendar}/components/ViewSelector/index.d.ts +0 -0
  46. /package/dist/{Calendar → src/Calendar}/components/YearTile/index.d.ts +0 -0
  47. /package/dist/{Calendar → src/Calendar}/hooks/useCalendarNav.d.ts +0 -0
  48. /package/dist/{Calendar → src/Calendar}/hooks/useDateSelect.d.ts +0 -0
  49. /package/dist/{Calendar → src/Calendar}/index.d.ts +0 -0
  50. /package/dist/{Calendar → src/Calendar}/type.d.ts +0 -0
  51. /package/dist/{Calendar → src/Calendar}/utils/getWeeksInMonth.d.ts +0 -0
  52. /package/dist/{Calendar → src/Calendar}/utils/isInRange.d.ts +0 -0
  53. /package/dist/{Calendar → src/Calendar}/utils/isSameDay.d.ts +0 -0
@@ -0,0 +1,124 @@
1
+ import { cn } from '@jk-core/utils';
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { useIntersectionObserver } from '@jk-core/hooks';
4
+ import DayTile from './components/DayTile';
5
+ import styles from './Calendar.module.scss';
6
+ import DateLabel from './components/DateLabel';
7
+ import getWeeksInMonth from './utils/getWeeksInMonth';
8
+ import { CalendarRange } from './type';
9
+
10
+ interface CalendarProps {
11
+ className?: string;
12
+ date: CalendarRange;
13
+ onChange:(date:CalendarRange)=>void;
14
+ min: Date;
15
+ max: Date;
16
+ }
17
+
18
+ export default function ScrollCalendar({
19
+ className = '', date: selectedDate = [null, null], onChange,
20
+ min, max,
21
+ }: CalendarProps) {
22
+ const maxCount = new Date().getMonth() - min.getMonth()
23
+ + 12 * (new Date().getFullYear() - min.getFullYear());
24
+ const scrollRef = useRef<HTMLDivElement>(null);
25
+ const targetRef = useRef<HTMLDivElement>(null);
26
+ const [viewDate, setViewDate] = useState<Date>(selectedDate?.[0] || new Date());
27
+ const [hoverDate, setHoverDate] = useState<Date | null>(null);
28
+ const [calendarCount, setCalendarCount] = useState(Array.from({
29
+ length: Math.abs(viewDate.getMonth() - new Date().getMonth()
30
+ + (12 * (viewDate.getFullYear() - new Date().getFullYear() - 1))),
31
+ }).map((_, idx) => idx));
32
+
33
+ const onDayClick = (day: Date, maintenance = false) => {
34
+ if (!maintenance) setViewDate(day);
35
+ if (!selectedDate[0] || (!!selectedDate[0] && !!selectedDate[1])) {
36
+ onChange([day, null]);
37
+ }
38
+ if (!!selectedDate[0] && !selectedDate[1]) {
39
+ if (day < selectedDate[0]) {
40
+ onChange([day, null]);
41
+ } else {
42
+ onChange([selectedDate[0], day]);
43
+ }
44
+ }
45
+ };
46
+
47
+ const handleDateChange = (count: number) => {
48
+ const newDate = new Date();
49
+ newDate.setMonth(newDate.getMonth() - count);
50
+ return newDate;
51
+ };
52
+
53
+ useEffect(() => {
54
+ if (viewDate > max) {
55
+ setViewDate(max);
56
+ }
57
+ if (viewDate < min) {
58
+ setViewDate(min);
59
+ }
60
+ }, [viewDate, max, min]);
61
+
62
+ useEffect(() => {
63
+ scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });
64
+ }, []);
65
+
66
+ useIntersectionObserver({
67
+ target: targetRef as React.RefObject<HTMLDivElement>,
68
+ parent: scrollRef as React.RefObject<HTMLDivElement>,
69
+ callback: () => {
70
+ if (maxCount < calendarCount.length) return;
71
+ const length = maxCount - (calendarCount.length - 1) > 12
72
+ ? 12 : maxCount - (calendarCount.length - 1);
73
+ setCalendarCount((prev) => [...prev,
74
+ ...Array.from({ length }).map((_, i) => prev.length + i)]);
75
+ },
76
+ options: { threshold: 0.1 },
77
+ });
78
+
79
+ return (
80
+ <div className={cn({
81
+ [styles.calendar]: true,
82
+ [styles['calendar--range']]: true,
83
+ [styles['calendar--scroll']]: true,
84
+ [className]: !!className,
85
+ })}
86
+ >
87
+ {/* 일/월/년 선택 버튼 */}
88
+ <div className={styles.calendar__scroll} ref={scrollRef}>
89
+ {calendarCount.map((count) => (
90
+ <div
91
+ className={styles['calendar__scroll--wrapper']}
92
+ key={count}
93
+ ref={(maxCount > (calendarCount.length - 1)
94
+ && count === calendarCount.length - 2) ? targetRef : null}
95
+ >
96
+ <DateLabel
97
+ viewDate={handleDateChange(count)}
98
+ method="day"
99
+ onArrowClick={() => { }}
100
+ disabled={() => false}
101
+ hideArrow="all"
102
+ range
103
+ />
104
+ <DayTile
105
+ style={{ height: 'auto', minHeight: 'auto' }}
106
+ hoverDate={hoverDate}
107
+ setHoverDate={(day) => setHoverDate(day)}
108
+ selectedDate={selectedDate}
109
+ weeksInMonth={getWeeksInMonth(handleDateChange(count))}
110
+ handleDayClick={onDayClick}
111
+ hideAfter
112
+ hideBefore
113
+ max={max}
114
+ min={min}
115
+ range
116
+ scroll
117
+ />
118
+ </div>
119
+ ))}
120
+
121
+ </div>
122
+ </div>
123
+ );
124
+ }
@@ -0,0 +1,121 @@
1
+ /* eslint-disable react/no-array-index-key */
2
+ import { useEffect, useState } from 'react';
3
+ import { cn } from '@jk-core/utils';
4
+ import CloseIcon from '../assets/close.svg';
5
+ import { CalendarView } from './type';
6
+ import getWeeksInMonth from './utils/getWeeksInMonth';
7
+ import DayTile from './components/DayTile';
8
+ import MonthTile from './components/MonthTile';
9
+ import YearTile from './components/YearTile';
10
+ import useCalendarNav from './hooks/useCalendarNav';
11
+ import useDateSelect from './hooks/useDateSelect';
12
+ import styles from './Calendar.module.scss';
13
+ import ViewSelector from './components/ViewSelector';
14
+ import './index.scss';
15
+ import DateLabel from './components/DateLabel';
16
+
17
+ interface CalendarProps {
18
+ className?: string;
19
+ date?: Date;
20
+ view?: CalendarView;
21
+ setView?: (view:CalendarView)=>void;
22
+ tileContent?: (date: Date | undefined, view: CalendarView) => React.ReactNode;
23
+ onChange?:(date:Date)=>void;
24
+ min?: Date;
25
+ max?: Date;
26
+ onClose?: () => void;
27
+ viewSelector?: boolean;
28
+ }
29
+
30
+ export default function SingleCalendar({
31
+ className = '', date: selectedDate, view, setView = () => { }, tileContent, onChange = () => { }, onClose, viewSelector = true,
32
+ min = new Date(2000, 0, 1), max = new Date(2099, 11, 31),
33
+ }: CalendarProps) {
34
+ const [viewDate, setViewDate] = useState<Date>(selectedDate || new Date());
35
+ const [method, setMethod] = useState<CalendarView>(view || 'day');
36
+ const [selectMode, setSelectMode] = useState<CalendarView>(view || 'day');
37
+ const weeksInMonth = getWeeksInMonth(viewDate);
38
+ const { onDayClick, onMonthClick, onYearClick } = useDateSelect({
39
+ viewDate,
40
+ setViewDate: (data) => setViewDate(data),
41
+ onChange,
42
+ setSelectMode,
43
+ method,
44
+ setView,
45
+ });
46
+ const { disabled, onArrowClick } = useCalendarNav({
47
+ method, selectMode, viewDate, setDate: setViewDate, min, max,
48
+ });
49
+
50
+ const selectView = (value: CalendarView) => {
51
+ setMethod(value);
52
+ setSelectMode(value);
53
+ };
54
+
55
+ useEffect(() => {
56
+ if (viewDate > max) {
57
+ setViewDate(max);
58
+ }
59
+ if (viewDate < min) {
60
+ setViewDate(min);
61
+ }
62
+ }, [viewDate, max, min]);
63
+
64
+ return (
65
+ <div className={cn({
66
+ [styles.calendar]: true,
67
+ [className]: !!className,
68
+ })}
69
+ >
70
+ <div className={styles.calendar__close}>
71
+ {onClose && (
72
+ <CloseIcon onClick={onClose} />
73
+ )}
74
+ </div>
75
+ {/* 일/월/년 선택 버튼 */}
76
+ {viewSelector && (
77
+ <ViewSelector method={method} selectView={selectView} />
78
+ )}
79
+ <DateLabel
80
+ viewDate={viewDate}
81
+ method={method}
82
+ onArrowClick={onArrowClick}
83
+ disabled={disabled}
84
+ selectMode={selectMode}
85
+ setSelectMode={setSelectMode}
86
+ />
87
+
88
+ {(method === 'day' && selectMode === 'day') && (
89
+ <DayTile
90
+ selectedDate={[selectedDate, null]}
91
+ weeksInMonth={weeksInMonth}
92
+ handleDayClick={onDayClick}
93
+ tileContent={() => (tileContent ? tileContent(selectedDate, method) : null)}
94
+ max={max}
95
+ min={min}
96
+ />
97
+ )}
98
+
99
+ {((method === 'month' || selectMode === 'month') && selectMode !== 'year') && (
100
+ <MonthTile
101
+ selectedDate={selectedDate}
102
+ viewDate={viewDate}
103
+ handleMonthClick={onMonthClick}
104
+ tileContent={tileContent}
105
+ max={max}
106
+ min={min}
107
+ />
108
+ )}
109
+
110
+ {(method === 'year' || selectMode === 'year') && (
111
+ <YearTile
112
+ selectedDate={selectedDate}
113
+ onClick={onYearClick}
114
+ tileContent={tileContent}
115
+ max={max}
116
+ min={min}
117
+ />
118
+ )}
119
+ </div>
120
+ );
121
+ }
@@ -0,0 +1,89 @@
1
+ @use "../../../styles/mediaQuery.scss" as media;
2
+
3
+ .nav {
4
+ height: 60px;
5
+ display: flex;
6
+ justify-content: space-between;
7
+ align-items: center;
8
+ padding: 0 5px;
9
+ border-bottom: 1px solid var(--calendar-G-30);
10
+ font-size: 1.3em;
11
+ font-weight: 400;
12
+
13
+ &--range {
14
+ border-bottom: none;
15
+ }
16
+
17
+ &--left {
18
+ padding-left: 40px;
19
+ justify-content: flex-start;
20
+ }
21
+
22
+ &__button {
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ width: 40px;
27
+ height: 40px;
28
+ padding: 10px;
29
+ border-radius: 100%;
30
+
31
+ svg {
32
+ width: 100%;
33
+ height: 100%;
34
+ fill: var(--calendar-G-60);
35
+ }
36
+
37
+ &:hover {
38
+ @include media.pc {
39
+ background-color: var(--calendar-G-10);
40
+ }
41
+ }
42
+
43
+ &:active {
44
+ background-color: var(--calendar-G-30);
45
+ }
46
+
47
+ &:disabled {
48
+ cursor: not-allowed;
49
+ background-color: transparent;
50
+
51
+ svg {
52
+ fill: var(--calendar-G-40);
53
+ }
54
+ }
55
+ }
56
+
57
+ &__label {
58
+ flex: 1 0;
59
+ display: flex;
60
+ align-items: center;
61
+ justify-content: space-around;
62
+ font-size: 1.1em;
63
+ font-weight: 400;
64
+
65
+ &--left {
66
+ text-align: left;
67
+ justify-content: flex-start;
68
+ }
69
+
70
+ &--date {
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ border-radius: 5px;
75
+ padding: 5px 10px;
76
+ font-weight: 400;
77
+ font-size: 1em;
78
+
79
+ svg {
80
+ width: 15px;
81
+ height: 15px;
82
+ }
83
+ }
84
+
85
+ &--date-selected {
86
+ background-color: var(--calendar-S-10);
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,91 @@
1
+ import { cn } from '@jk-core/utils';
2
+ import { CalendarView } from 'Calendar/type';
3
+ import ArrowIcon from 'assets/arrow.svg';
4
+ import DropIcon from 'assets/drop-arrow.svg';
5
+ import styles from './DateLabel.module.scss';
6
+
7
+ interface DateLabelProps {
8
+ viewDate: Date;
9
+ onArrowClick: (direction: 'prev' | 'next') => void;
10
+ disabled: (direction: 'prev' | 'next') => boolean;
11
+ method: CalendarView;
12
+ selectMode?: CalendarView;
13
+ setSelectMode?: (mode: CalendarView) => void;
14
+ hideArrow?: 'prev' | 'next' | 'all' | null;
15
+ range?: boolean;
16
+ }
17
+
18
+ export default function DateLabel({
19
+ viewDate, onArrowClick, disabled, method, selectMode = 'day', setSelectMode = () => { }, hideArrow = null, range = false,
20
+ }: DateLabelProps) {
21
+ return (
22
+ <div className={cn({
23
+ [styles.nav]: true,
24
+ [styles['nav--range']]: range,
25
+ [styles['nav--left']]: hideArrow === 'all',
26
+ })}
27
+ >
28
+ {hideArrow !== 'all' && (
29
+ <button
30
+ className={styles.nav__button}
31
+ type="button"
32
+ onClick={() => onArrowClick('prev')}
33
+ disabled={disabled('prev') || hideArrow === 'prev'}
34
+ >
35
+ {hideArrow !== 'prev' && <ArrowIcon />}
36
+ </button>
37
+ )}
38
+ {range ? (
39
+ <div className={cn({
40
+ [styles.nav__label]: true,
41
+ [styles['nav__label--left']]: hideArrow === 'all',
42
+ })}
43
+ >
44
+ {`${viewDate.getFullYear()}년 ${viewDate.getMonth() + 1}월`}
45
+ </div>
46
+ ) : (
47
+ <div className={cn({
48
+ [styles.nav__label]: true,
49
+ [styles['nav__label--left']]: hideArrow === 'all',
50
+ })}
51
+ >
52
+ {method === 'year' && '연도 선택'}
53
+ {method !== 'year' && (
54
+ <button
55
+ className={cn({
56
+ [styles['nav__label--date']]: true,
57
+ [styles['nav__label--date-selected']]: selectMode === 'year',
58
+ })}
59
+ type="button"
60
+ onClick={() => setSelectMode('year')}
61
+ >
62
+ {`${viewDate.getFullYear()}년`}<DropIcon />
63
+ </button>
64
+ )}
65
+ {method === 'day' && (
66
+ <button
67
+ className={cn({
68
+ [styles['nav__label--date']]: true,
69
+ [styles['nav__label--date-selected']]: selectMode === 'month',
70
+ })}
71
+ type="button"
72
+ onClick={() => setSelectMode('month')}
73
+ >
74
+ {`${viewDate.getMonth() + 1}월`}<DropIcon />
75
+ </button>
76
+ )}
77
+ </div>
78
+ )}
79
+ {hideArrow !== 'all' && (
80
+ <button
81
+ className={styles.nav__button}
82
+ type="button"
83
+ onClick={() => onArrowClick('next')}
84
+ disabled={disabled('next') || hideArrow === 'next'}
85
+ >
86
+ {hideArrow !== 'next' && <ArrowIcon style={{ transform: 'rotate(180deg)' }} />}
87
+ </button>
88
+ )}
89
+ </div>
90
+ );
91
+ }
@@ -0,0 +1,117 @@
1
+ @use "../../../styles/mediaQuery.scss" as media;
2
+
3
+ .day-tile {
4
+ width: 100%;
5
+ min-height: 310px;
6
+ padding: 5px;
7
+ box-sizing: border-box;
8
+
9
+ &--content {
10
+ display: flex;
11
+ justify-content: center;
12
+ align-items: center;
13
+ flex-direction: column;
14
+ border-radius: 40px;
15
+ border: none;
16
+ font-weight: 400;
17
+ font-size: 1em;
18
+ }
19
+
20
+ &--selected {
21
+ width: 100%;
22
+ height: 100%;
23
+ background-color: var(--calendar-P-50) !important;
24
+ color: var(--calendar-white) !important;
25
+ font-weight: 500;
26
+ padding: 0;
27
+ }
28
+
29
+ &__range {
30
+ flex: 1 0;
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ gap: 10%;
35
+ font-size: 1.1em;
36
+ font-weight: 400;
37
+ }
38
+
39
+ &__tile {
40
+ display: flex;
41
+ flex-direction: column;
42
+ justify-content: space-between;
43
+ gap: 5px;
44
+ }
45
+
46
+ &__weeks {
47
+ display: flex;
48
+ justify-content: space-between;
49
+ font-weight: 400;
50
+ font-size: 1em;
51
+
52
+ &--date {
53
+ flex: 1 0;
54
+ display: flex;
55
+ justify-content: center;
56
+ align-items: center;
57
+ min-width: 40px;
58
+ padding: 5px 0;
59
+ }
60
+ }
61
+
62
+ &__week {
63
+ display: flex;
64
+ justify-content: space-between;
65
+ }
66
+
67
+ &__day {
68
+ width: 100%;
69
+ min-width: 40px;
70
+ min-height: 40px;
71
+ padding: 0;
72
+ border: none;
73
+ color: var(--calendar-G-80);
74
+
75
+ &:disabled {
76
+ color: var(--calendar-G-40) !important;
77
+ background-color: transparent !important;
78
+ cursor: default;
79
+ }
80
+
81
+ &--today {
82
+ color: var(--calendar-P-50);
83
+ font-weight: 500;
84
+ }
85
+
86
+ &--selected-first {
87
+ border-radius: 40px 0 0 40px !important;
88
+ background-color: var(--calendar-P-5);
89
+ }
90
+
91
+ &--selected-last {
92
+ border-radius: 0 40px 40px 0 !important;
93
+ background-color: var(--calendar-P-5);
94
+ }
95
+
96
+ &--before {
97
+ color: var(--calendar-G-40) !important;
98
+ background-color: transparent !important;
99
+ }
100
+
101
+ &--tile {
102
+ border-radius: 10px;
103
+ gap: 5px;
104
+ }
105
+
106
+ &--range {
107
+ background-color: var(--calendar-P-5);
108
+ border-radius: 0;
109
+ }
110
+
111
+ &--hide-before,
112
+ &--hide-after {
113
+ opacity: 0;
114
+ pointer-events: none;
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,100 @@
1
+ /* eslint-disable react/no-array-index-key */
2
+ import isSameDay from 'Calendar/utils/isSameDay';
3
+ import { cn } from '@jk-core/utils';
4
+ import { CalendarRange } from 'Calendar/type';
5
+ import isInRange from 'Calendar/utils/isInRange';
6
+ import styles from './DayTile.module.scss';
7
+
8
+ const WEEKS = ['일', '월', '화', '수', '목', '금', '토'];
9
+
10
+ interface Props {
11
+ hoverDate?:Date | null,
12
+ setHoverDate?:(date:Date | null)=>void,
13
+ selectedDate?: CalendarRange;
14
+ weeksInMonth: {
15
+ thisMonth: string;
16
+ date: Date;
17
+ }[][];
18
+ tileContent?: () => React.ReactNode;
19
+ handleDayClick: (day: Date) => void;
20
+ max?: Date;
21
+ min?: Date;
22
+ hideBefore?: boolean;
23
+ hideAfter?: boolean;
24
+ range?: boolean;
25
+ scroll?: boolean;
26
+ style?: React.CSSProperties;
27
+ }
28
+ export default function DayTile({
29
+ selectedDate, weeksInMonth, tileContent, handleDayClick, range = false,
30
+ max, min, hideBefore = false, hideAfter = false, style, scroll,
31
+ hoverDate, setHoverDate = () => { },
32
+ }: Props) {
33
+ return (
34
+ <div className={styles['day-tile']} style={style}>
35
+ <div className={styles['day-tile__weeks']}>
36
+ {WEEKS.map((week) => (<div className={styles['day-tile__weeks--date']} key={week}>{week}</div>))}
37
+ </div>
38
+
39
+ <div className={styles['day-tile__tile']}>
40
+ {weeksInMonth.map((week, index) => (
41
+ <div key={index} className={styles['day-tile__week']}>
42
+ {week.map((day, idx) => (
43
+ <button
44
+ className={cn({
45
+ [styles['day-tile__day']]: true,
46
+ [styles['day-tile__day--today']]: isSameDay(day.date, new Date()),
47
+ [styles['day-tile__day--selected-first']]: !!selectedDate && isSameDay(day.date, selectedDate[0] || null) && range
48
+ && ((!!selectedDate[1]
49
+ || ((!scroll && hoverDate != null && !!selectedDate[0])
50
+ && hoverDate > selectedDate[0]))),
51
+ [styles['day-tile__day--selected-last']]: (!!selectedDate && isSameDay(day.date, selectedDate[1] || null) && range)
52
+ || (!scroll && !selectedDate?.[1] && isSameDay(day.date, hoverDate || null)),
53
+ [styles['day-tile__day--before']]: day.thisMonth !== 'this',
54
+ [styles['day-tile__day--hide-before']]: hideBefore && day.thisMonth === 'before',
55
+ [styles['day-tile__day--hide-after']]: hideAfter && day.thisMonth === 'after',
56
+ [styles['day-tile__day--tile']]: !!(tileContent && tileContent()),
57
+ [styles['day-tile__day--range']]: isInRange(day.date, selectedDate) || (!!selectedDate?.[0] && (isInRange(day.date, [selectedDate[0], hoverDate]))),
58
+ })}
59
+ type="button"
60
+ disabled={(min && day.date < min) || (max && day.date > max)}
61
+ key={idx}
62
+ onMouseOver={() => {
63
+ if (!selectedDate?.[1] && !((min && day.date < min) || (max && day.date > max))) {
64
+ setHoverDate(new Date(
65
+ day.date.getFullYear(),
66
+ day.date.getMonth(),
67
+ day.date.getDate(),
68
+ ));
69
+ }
70
+ }}
71
+ onFocus={() => {
72
+ if (!selectedDate?.[1] && !((min && day.date < min) || (max && day.date > max))) {
73
+ setHoverDate(new Date(
74
+ day.date.getFullYear(),
75
+ day.date.getMonth(),
76
+ day.date.getDate(),
77
+ ));
78
+ }
79
+ }}
80
+ onMouseLeave={() => {
81
+ if (hoverDate) setHoverDate(null);
82
+ }}
83
+ onClick={() => handleDayClick(day.date)}
84
+ >
85
+ <div className={cn({
86
+ [styles['day-tile--content']]: true,
87
+ [styles['day-tile--selected']]: !!selectedDate && (isSameDay(day.date, selectedDate[0] || null) || isSameDay(day.date, selectedDate[1] || null) || isSameDay(day.date, hoverDate || null)),
88
+ })}
89
+ >
90
+ {day.date.getDate()}
91
+ {tileContent && tileContent()}
92
+ </div>
93
+ </button>
94
+ ))}
95
+ </div>
96
+ ))}
97
+ </div>
98
+ </div>
99
+ );
100
+ }
@@ -0,0 +1,59 @@
1
+ @use "../../../styles/mediaQuery.scss" as media;
2
+
3
+ .month-tile {
4
+ position: relative;
5
+ min-height: 310px;
6
+ padding: 5px;
7
+ display: grid;
8
+ grid-template-columns: repeat(3, 1fr);
9
+ grid-template-rows: repeat(4, 1fr);
10
+ gap: 5px;
11
+
12
+ &__month {
13
+ display: flex;
14
+ flex-direction: column;
15
+ justify-content: center;
16
+ align-items: center;
17
+ padding: 5px;
18
+ border-radius: 10px;
19
+ color: var(--calendar-G-80);
20
+
21
+ svg {
22
+ width: 15px;
23
+ height: 15px;
24
+ cursor: pointer;
25
+ }
26
+
27
+ &:hover {
28
+ @include media.pc {
29
+ background-color: var(--calendar-G-5);
30
+ }
31
+ }
32
+
33
+ &:active {
34
+ background-color: var(--calendar-G-10);
35
+ }
36
+
37
+ &:disabled {
38
+ color: var(--calendar-G-40) !important;
39
+ background-color: transparent !important;
40
+ cursor: default;
41
+ border-radius: 0 !important;
42
+ }
43
+
44
+ &--selected {
45
+ background-color: var(--calendar-P-50) !important;
46
+ color: var(--calendar-white) !important;
47
+ }
48
+
49
+ &--today {
50
+ color: var(--calendar-P-50);
51
+ font-weight: 600;
52
+ }
53
+
54
+ &--tile {
55
+ justify-content: flex-start;
56
+ gap: 5px;
57
+ }
58
+ }
59
+ }