@jk-core/components 0.0.63 → 0.0.65

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 (33) hide show
  1. package/dist/index.js +399 -471
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.umd.cjs +19 -10
  4. package/dist/index.umd.cjs.map +1 -1
  5. package/dist/main.d.ts +1 -0
  6. package/dist/style.css +402 -1
  7. package/dist/style.css.map +1 -0
  8. package/package.json +10 -5
  9. package/src/Calendar/{Calendar.module.scss → scss/_calendar.scss} +9 -0
  10. package/src/Calendar/scss/_tile.scss +214 -0
  11. package/src/Calendar/scss/main.scss +3 -0
  12. package/src/Calendar/components/DayTile/DayTile.module.scss +0 -79
  13. package/src/Calendar/components/DayTile/index.tsx +0 -52
  14. package/src/Calendar/components/MonthTile/MonthTile.module.scss +0 -44
  15. package/src/Calendar/components/MonthTile/index.tsx +0 -38
  16. package/src/Calendar/components/YearTile/YearTile.module.scss +0 -85
  17. package/src/Calendar/components/YearTile/index.tsx +0 -60
  18. package/src/Calendar/components/mixin.module.scss +0 -5
  19. package/src/Calendar/hooks/useCalendarNav.ts +0 -80
  20. package/src/Calendar/hooks/useDateSelect.ts +0 -47
  21. package/src/Calendar/index.tsx +0 -167
  22. package/src/Calendar/style.css +0 -4
  23. package/src/Calendar/type.ts +0 -6
  24. package/src/Calendar/utils/getWeeksInMonth.ts +0 -45
  25. package/src/Calendar/utils/isInRange.ts +0 -8
  26. package/src/Calendar/utils/isSameDay.ts +0 -21
  27. package/src/assets/close.svg +0 -16
  28. package/src/assets/drop-arrow.svg +0 -3
  29. package/src/index.tsx +0 -3
  30. package/src/styles/mediaQuery.scss +0 -22
  31. package/src/svg.d.ts +0 -6
  32. package/src/vite-env.d.ts +0 -1
  33. /package/src/{styles/color.scss → Calendar/scss/_variables.scss} +0 -0
@@ -1,79 +0,0 @@
1
- @use "../mixin.module.scss" as mixin;
2
- @use "../../../styles/mediaQuery.scss" as media;
3
-
4
- .body {
5
- @include mixin.body;
6
-
7
- &__tile {
8
- display: flex;
9
- flex-direction: column;
10
- justify-content: space-between;
11
- gap: 5px;
12
- }
13
-
14
- &__weeks {
15
- display: flex;
16
- justify-content: space-between;
17
- font-weight: 400;
18
- font-size: 1em;
19
-
20
- &--date {
21
- flex: 1 0;
22
- display: flex;
23
- justify-content: center;
24
- align-items: center;
25
- min-width: 40px;
26
- padding: 5px 0;
27
- }
28
- }
29
-
30
- &__week {
31
- display: flex;
32
- justify-content: space-between;
33
- }
34
-
35
- &__day {
36
- display: flex;
37
- justify-content: center;
38
- align-items: center;
39
- flex-direction: column;
40
- width: 100%;
41
- min-width: 40px;
42
- min-height: 40px;
43
- border-radius: 100%;
44
- padding: 5px;
45
- border: none;
46
- font-weight: 400;
47
- font-size: 1em;
48
-
49
- &:hover {
50
- @include media.pc {
51
- background-color: var(--G-5);
52
- }
53
- }
54
-
55
- &:active {
56
- background-color: var(--G-10);
57
- }
58
-
59
- &--today {
60
- color: var(--P-50);
61
- font-weight: 600;
62
- }
63
-
64
- &--selected {
65
- background-color: var(--P-50) !important;
66
- color: var(--white) !important;
67
- font-weight: 600;
68
- }
69
-
70
- &--before {
71
- color: var(--G-40);
72
- }
73
-
74
- &--tile {
75
- border-radius: 10px;
76
- gap: 5px;
77
- }
78
- }
79
- }
@@ -1,52 +0,0 @@
1
- /* eslint-disable max-len */
2
- /* eslint-disable react/no-array-index-key */
3
- import { cn } from '@jk-core/utils';
4
- import isSameDay from '../../utils/isSameDay';
5
- import styles from './DayTile.module.scss';
6
-
7
- const WEEKS = ['일', '월', '화', '수', '목', '금', '토'];
8
-
9
- interface Props {
10
- selectedDate?: Date;
11
- weeksInMonth: {
12
- thisMonth: boolean;
13
- date: Date;
14
- }[][];
15
- tileContent?: () => React.ReactNode;
16
- handleDayClick: (day: Date) => void;
17
- }
18
- export default function DayTile({
19
- selectedDate, weeksInMonth, tileContent, handleDayClick,
20
- }: Props) {
21
- return (
22
- <div className={styles.body}>
23
- <div className={styles.body__weeks}>
24
- {WEEKS.map((week) => (<div className={styles['body__weeks--date']} key={week}>{week}</div>))}
25
- </div>
26
-
27
- <div className={styles.body__tile}>
28
- {weeksInMonth.map((week, index) => (
29
- <div key={index} className={styles.body__week}>
30
- {week.map((day, idx) => (
31
- <button
32
- className={cn({
33
- [styles.body__day]: true,
34
- [styles['body__day--today']]: isSameDay(day.date, new Date()),
35
- [styles['body__day--selected']]: !!selectedDate && isSameDay(day.date, selectedDate),
36
- [styles['body__day--before']]: !day.thisMonth,
37
- [styles['body__day--tile']]: !!(tileContent && tileContent()),
38
- })}
39
- type="button"
40
- key={idx}
41
- onClick={() => handleDayClick(day.date)}
42
- >
43
- {day.date.getDate()}
44
- {tileContent && tileContent()}
45
- </button>
46
- ))}
47
- </div>
48
- ))}
49
- </div>
50
- </div>
51
- );
52
- }
@@ -1,44 +0,0 @@
1
- @use "../mixin.module.scss" as mixin;
2
-
3
- .body {
4
- display: grid;
5
- grid-template-columns: repeat(3, 1fr);
6
- grid-template-rows: repeat(4, 1fr);
7
- gap: 5px;
8
-
9
- @include mixin.body;
10
-
11
- &__month {
12
- display: flex;
13
- flex-direction: column;
14
- justify-content: center;
15
- align-items: center;
16
- padding: 5px;
17
- border-radius: 10px;
18
-
19
- svg {
20
- width: 15px;
21
- height: 15px;
22
- cursor: pointer;
23
- }
24
-
25
- &:active {
26
- background-color: var(--G-10);
27
- }
28
-
29
- &--selected {
30
- background-color: var(--P-50) !important;
31
- color: var(--white) !important;
32
- }
33
-
34
- &--today {
35
- color: var(--P-50);
36
- font-weight: 600;
37
- }
38
-
39
- &--tile {
40
- justify-content: flex-start;
41
- gap: 5px;
42
- }
43
- }
44
- }
@@ -1,38 +0,0 @@
1
- import { cn } from '@jk-core/utils';
2
- import styles from './MonthTile.module.scss';
3
- import isSameDay from '../../utils/isSameDay';
4
- import { CalendarView } from '../../type';
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
- }
14
- export default function MonthTile({
15
- selectedDate, viewDate, handleMonthClick, tileContent = () => false,
16
- }: Props) {
17
- return (
18
- <div className={styles.body}>
19
- {MONTHS.map((month) => (
20
- <button
21
- className={cn({
22
- [styles.body__month]: true,
23
- [styles['body__month--selected']]: !!selectedDate && isSameDay(selectedDate, new Date(viewDate.getFullYear(), month), 'month'),
24
- [styles['body__month--today']]: isSameDay(new Date(viewDate.getFullYear(), month), new Date(), 'month'),
25
- [styles['body__month--tile']]: !!tileContent(new Date(viewDate.getFullYear(), month - 1, 1), 'month'),
26
- })}
27
- type="button"
28
- key={month}
29
- onClick={() => handleMonthClick(month)}
30
- >
31
- <span>{`${month + 1}월`}</span>
32
- {!!tileContent(new Date(viewDate.getFullYear(), month - 1, 1), 'month')
33
- && tileContent(new Date(viewDate.getFullYear(), month - 1, 1), 'month')}
34
- </button>
35
- ))}
36
- </div>
37
- );
38
- }
@@ -1,85 +0,0 @@
1
- @use "../mixin.module.scss" as mixin;
2
- @use "../../../styles/mediaQuery.scss" as media;
3
-
4
- .body {
5
- @include mixin.body;
6
-
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
-
41
- &:hover {
42
- @include media.pc {
43
- background-color: var(--P-5);
44
- }
45
- }
46
-
47
- &:active {
48
- background-color: var(--P-10);
49
- }
50
-
51
- &--border {
52
- border: 1px solid var(--G-30);
53
- background-color: var(--P-5);
54
-
55
- &:hover {
56
- @include media.pc {
57
- background-color: var(--P-10);
58
- }
59
- }
60
- }
61
-
62
- &--year {
63
- height: 40px;
64
- display: flex;
65
- align-items: center;
66
- justify-content: center;
67
- }
68
-
69
- &--selected {
70
- color: var(--white);
71
- background-color: var(--P-50) !important;
72
- }
73
-
74
- &--tile {
75
- display: flex;
76
- align-items: center;
77
- justify-content: center;
78
- min-height: 40px;
79
- color: var(--G-80);
80
- width: 100%;
81
- background-color: var(--white);
82
- border-top: var(--P-50);
83
- }
84
- }
85
- }
@@ -1,60 +0,0 @@
1
- import { cn } from '@jk-core/utils';
2
- import { useEffect, useRef } from 'react';
3
- import styles from './YearTile.module.scss';
4
- import { CalendarView } from '../../type';
5
-
6
- interface Props {
7
- selectedDate?: Date;
8
- onClick: (year: number) => void;
9
- tileContent?: (date: Date, view:CalendarView) => React.ReactNode;
10
- }
11
-
12
- const YEARS = Array.from({ length: 100 }, (_, i) => i + 2000);
13
-
14
- export default function YearTile({
15
- selectedDate, onClick,
16
- tileContent = () => false,
17
- }: Props) {
18
- const wrapperRef = useRef<HTMLDivElement>(null);
19
- const selectedRef = useRef<HTMLButtonElement>(null);
20
-
21
- useEffect(() => {
22
- const selectedElement = selectedRef.current;
23
- const wrapperElement = wrapperRef.current;
24
- if (!selectedElement || !wrapperElement) return;
25
-
26
- const { clientHeight } = wrapperElement;
27
- const { offsetTop, clientHeight: selectedHeight } = selectedElement;
28
-
29
- wrapperElement.scrollTo({
30
- top: offsetTop - clientHeight / 2 + selectedHeight,
31
- });
32
- }, []);
33
-
34
- return (
35
- <div className={styles.body} ref={wrapperRef}>
36
- <div className={styles.body__blank} />
37
- {YEARS.map((year) => (
38
- <button
39
- className={cn({
40
- [styles.body__year]: true,
41
- [styles['body__year--selected']]: !!selectedDate && selectedDate.getFullYear() === year,
42
- [styles['body__year--border']]: !!tileContent(new Date(year, 1, 1), 'year'),
43
- })}
44
- key={year}
45
- type="button"
46
- ref={!!selectedDate && selectedDate.getFullYear() === year ? selectedRef : null}
47
- onClick={() => onClick(year)}
48
- >
49
- <span className={styles['body__year--year']}>{year}</span>
50
- {tileContent(new Date(year, 1, 1), 'year') && (
51
- <div className={styles['body__year--tile']}>
52
- {tileContent(new Date(year, 1, 1), 'year')}
53
- </div>
54
- )}
55
- </button>
56
- ))}
57
- <div className={styles.body__blank} />
58
- </div>
59
- );
60
- }
@@ -1,5 +0,0 @@
1
- @mixin body {
2
- min-height: 310px;
3
- padding: 5px;
4
- background-color: var(--white);
5
- }
@@ -1,80 +0,0 @@
1
- import { CalendarView } from '../type';
2
-
3
- interface Props {
4
- method: CalendarView;
5
- selectMode: CalendarView;
6
- date: Date;
7
- setDate:(date: Date) => void;
8
- min: Date;
9
- max: Date;
10
- }
11
- const useCalendarNav = ({
12
- method, selectMode, date, 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(date.getFullYear(), date.getMonth() - 1, 1);
20
- return prevMonth < min;
21
- }
22
- const nextMonth = new Date(date.getFullYear(), date.getMonth() + 1, 1);
23
- return nextMonth > max;
24
- }
25
-
26
- if (method === 'month') {
27
- if (direction === 'prev') {
28
- const prevYear = new Date(date.getFullYear() - 1, date.getMonth(), 1);
29
- return prevYear < min;
30
- }
31
- const nextYear = new Date(date.getFullYear() + 1, date.getMonth(), 1);
32
- return nextYear > max;
33
- }
34
-
35
- if (method === 'year') {
36
- if (direction === 'prev') {
37
- const prevDecade = new Date(date.getFullYear() - 10, date.getMonth(), 1);
38
- return prevDecade < min;
39
- }
40
- const nextDecade = new Date(date.getFullYear() + 10, date.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(date.getFullYear(), date.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(date.getFullYear() + offset, date.getMonth(), 1);
62
-
63
- if (newDate >= minDate && newDate <= maxDate) {
64
- setDate(newDate);
65
- }
66
- }
67
-
68
- if (method === 'year') {
69
- const newDate = new Date(date.getFullYear() + offset * 10, date.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;
@@ -1,47 +0,0 @@
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
-
10
- }
11
-
12
- const useDateSelect = ({
13
- viewDate, setViewDate, onChange, setSelectMode, method,
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
- onChange(day);
25
- };
26
-
27
- const onMonthClick = (month:number) => {
28
- const newDate = new Date(viewDate.getFullYear(), month, 1);
29
-
30
- setViewDate(newDate);
31
-
32
- if (method !== 'month') setSelectMode(method);
33
- if (method === 'month') onChange(newDate);
34
- };
35
-
36
- const onYearClick = (year:number) => {
37
- const newDate = new Date(year, 0, 1);
38
-
39
- setViewDate(newDate);
40
- if (method !== 'year') setSelectMode(method);
41
- if (method === 'year') onChange(newDate);
42
- };
43
-
44
- return { onDayClick, onMonthClick, onYearClick };
45
- };
46
-
47
- export default useDateSelect;
@@ -1,167 +0,0 @@
1
- /* eslint-disable react/no-array-index-key */
2
- import { useState } from 'react';
3
- import { cn } from '@jk-core/utils';
4
- import CloseIcon from '../assets/close.svg';
5
- import DropIcon from '../assets/drop-arrow.svg';
6
- import styles from './Calendar.module.scss';
7
- import { CalendarView } from './type';
8
- import getWeeksInMonth from './utils/getWeeksInMonth';
9
- import DayTile from './components/DayTile';
10
- import MonthTile from './components/MonthTile';
11
- import YearTile from './components/YearTile';
12
- import useCalendarNav from './hooks/useCalendarNav';
13
- import useDateSelect from './hooks/useDateSelect';
14
-
15
- import './style.css';
16
- import '../styles/color.scss';
17
-
18
- interface CalendarProps {
19
- date?: Date;
20
- view?: CalendarView;
21
- tileContent?: (date: Date | undefined, view: CalendarView) => React.ReactNode;
22
- onChange?:(date:Date)=>void;
23
- min?: Date;
24
- max?: Date;
25
- onClose?:()=>void;
26
- }
27
-
28
- export default function Calendar({
29
- date: selectedDate, view, tileContent, onChange = () => { }, onClose,
30
- min = new Date(2000, 0, 1), max = new Date(2099, 11, 31),
31
- }:CalendarProps) {
32
- const [viewDate, setViewDate] = useState<Date>(selectedDate || new Date());
33
- const [method, setMethod] = useState<CalendarView>(view || 'day');
34
- const [selectMode, setSelectMode] = useState<CalendarView>('day');
35
- const weeksInMonth = getWeeksInMonth(viewDate);
36
- const { onDayClick, onMonthClick, onYearClick } = useDateSelect({
37
- viewDate,
38
- setViewDate: (data) => setViewDate(data),
39
- onChange,
40
- setSelectMode,
41
- method,
42
- });
43
- const { disabled, onArrowClick } = useCalendarNav({
44
- method, selectMode, date: viewDate, setDate: setViewDate, min, max,
45
- });
46
-
47
- return (
48
- <div className={styles.calendar}>
49
- <div className={styles.calendar__close}>
50
- {onClose
51
- && (
52
- <CloseIcon onClick={onClose} />
53
- )}
54
- </div>
55
- {/* 일/월/년 선택 버튼 */}
56
- <div className={styles.view}>
57
- <div className={cn({
58
- [styles.view__block]: true,
59
- [styles['view__block--second']]: method === 'month',
60
- [styles['view__block--last']]: method === 'year',
61
- })}
62
- />
63
- <button
64
- className={cn({
65
- [styles.view__selector]: true,
66
- [styles['view__selector--selected']]: method === 'day',
67
- })}
68
- type="button"
69
- onClick={() => { setMethod('day'); setSelectMode('day'); }}
70
- >일
71
- </button>
72
- <button
73
- className={cn({
74
- [styles.view__selector]: true,
75
- [styles['view__selector--selected']]: method === 'month',
76
- })}
77
- type="button"
78
- onClick={() => { setMethod('month'); setSelectMode('month'); }}
79
- >월
80
- </button>
81
- <button
82
- className={cn({
83
- [styles.view__selector]: true,
84
- [styles['view__selector--selected']]: method === 'year',
85
- })}
86
- type="button"
87
- onClick={() => { setMethod('year'); setSelectMode('year'); }}
88
- >년
89
- </button>
90
- </div>
91
-
92
- <div className={styles.nav}>
93
- <button
94
- className={styles.nav__button}
95
- type="button"
96
- onClick={() => onArrowClick('prev')}
97
- disabled={disabled('prev')}
98
- >
99
- ◀︎
100
- </button>
101
- <div className={styles.nav__label}>
102
- {method === 'year' && '연도 선택'}
103
- {method !== 'year' && (
104
- <button
105
- className={cn({
106
- [styles['nav__label--date']]: true,
107
- [styles['nav__label--date-selected']]: selectMode === 'year',
108
- })}
109
- type="button"
110
- onClick={() => setSelectMode('year')}
111
- >
112
- {`${viewDate.getFullYear()}년`}<DropIcon />
113
- </button>
114
- )}
115
- {method === 'day' && (
116
- <button
117
- className={cn({
118
- [styles['nav__label--date']]: true,
119
- [styles['nav__label--date-selected']]: selectMode === 'month',
120
- })}
121
- type="button"
122
- onClick={() => setSelectMode('month')}
123
- >
124
- {`${viewDate.getMonth() + 1}월`}<DropIcon />
125
- </button>
126
- )}
127
- </div>
128
- <button
129
- className={styles.nav__button}
130
- type="button"
131
- onClick={() => onArrowClick('next')}
132
- disabled={disabled('next')}
133
- >►
134
- </button>
135
- </div>
136
-
137
- {(method === 'day' && selectMode === 'day') && (
138
- <DayTile
139
- selectedDate={selectedDate}
140
- weeksInMonth={weeksInMonth}
141
- // selectRange={selectRange}
142
- // selectedRange={selectedRange}
143
- handleDayClick={onDayClick}
144
- tileContent={() => (tileContent ? tileContent(selectedDate, method) : null)}
145
- />
146
- )}
147
-
148
- {((method === 'month' || selectMode === 'month') && selectMode !== 'year') && (
149
- <MonthTile
150
- selectedDate={selectedDate}
151
- viewDate={viewDate}
152
- handleMonthClick={onMonthClick}
153
- tileContent={tileContent}
154
-
155
- />
156
- )}
157
-
158
- {(method === 'year' || selectMode === 'year') && (
159
- <YearTile
160
- selectedDate={selectedDate}
161
- onClick={onYearClick}
162
- tileContent={tileContent}
163
- />
164
- )}
165
- </div>
166
- );
167
- }
@@ -1,4 +0,0 @@
1
- body {
2
- --Calendar-Background: #ffffff;
3
- --Calendar-Test: #ffffff;
4
- }
@@ -1,6 +0,0 @@
1
- export type CalendarView = 'day' | 'month' | 'year';
2
-
3
- export interface CalendarRange {
4
- start: Date | null;
5
- end: Date | null;
6
- }