@jk-core/components 1.1.17 → 1.1.19

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 (91) hide show
  1. package/README.md +73 -73
  2. package/dist/index.js +1299 -997
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.umd.cjs +8 -8
  5. package/dist/index.umd.cjs.map +1 -1
  6. package/dist/src/common/Carousel/index.d.ts +15 -0
  7. package/dist/src/common/RollingBanner/index.d.ts +11 -0
  8. package/dist/src/index.d.ts +3 -1
  9. package/dist/src/utils/ts/formatMoney.d.ts +1 -1
  10. package/package.json +99 -99
  11. package/src/Calendar/Calendar.module.scss +213 -213
  12. package/src/Calendar/RangeCalendar.tsx +125 -125
  13. package/src/Calendar/ScrollCalendar.module.scss +214 -214
  14. package/src/Calendar/ScrollCalendar.tsx +124 -124
  15. package/src/Calendar/SingleCalendar.tsx +121 -121
  16. package/src/Calendar/components/DateLabel/DateLabel.module.scss +89 -89
  17. package/src/Calendar/components/DateLabel/index.tsx +91 -91
  18. package/src/Calendar/components/DayTile/DayTile.module.scss +117 -117
  19. package/src/Calendar/components/DayTile/index.tsx +108 -108
  20. package/src/Calendar/components/MonthTile/MonthTile.module.scss +59 -59
  21. package/src/Calendar/components/MonthTile/index.tsx +50 -50
  22. package/src/Calendar/components/ViewSelector/ViewSelector.module.scss +48 -48
  23. package/src/Calendar/components/ViewSelector/index.tsx +49 -49
  24. package/src/Calendar/components/YearTile/YearTile.module.scss +85 -85
  25. package/src/Calendar/components/YearTile/index.tsx +65 -65
  26. package/src/Calendar/hooks/useCalendarNav.ts +83 -83
  27. package/src/Calendar/hooks/useDateSelect.ts +54 -54
  28. package/src/Calendar/index.scss +189 -189
  29. package/src/Calendar/index.tsx +66 -66
  30. package/src/Calendar/type.ts +3 -3
  31. package/src/Calendar/utils/getWeeksInMonth.ts +45 -45
  32. package/src/Calendar/utils/isInRange.ts +8 -8
  33. package/src/Calendar/utils/isSameDay.ts +21 -21
  34. package/src/assets/arrow.svg +11 -11
  35. package/src/assets/close.svg +15 -15
  36. package/src/assets/drop-arrow.svg +3 -3
  37. package/src/common/Accordion/Accordion.module.scss +53 -53
  38. package/src/common/Accordion/arrow-down.svg +3 -3
  39. package/src/common/Accordion/arrow-up.svg +3 -3
  40. package/src/common/Accordion/index.tsx +54 -54
  41. package/src/common/Breadcrumbs/Breadcrumbs.module.scss +46 -46
  42. package/src/common/Breadcrumbs/home.svg +5 -5
  43. package/src/common/Breadcrumbs/index.tsx +82 -82
  44. package/src/common/Button/Button.module.scss +127 -127
  45. package/src/common/Button/index.tsx +60 -60
  46. package/src/common/Card/Card.module.scss +28 -28
  47. package/src/common/Card/index.tsx +19 -19
  48. package/src/common/Carousel/Carousel.module.scss +222 -0
  49. package/src/common/Carousel/index.tsx +411 -0
  50. package/src/common/Divider/Divider.module.scss +101 -101
  51. package/src/common/Divider/index.tsx +24 -24
  52. package/src/common/DropDown/DropDown.module.scss +135 -135
  53. package/src/common/DropDown/List.tsx +156 -156
  54. package/src/common/DropDown/arrow-down.svg +3 -3
  55. package/src/common/DropDown/index.tsx +108 -108
  56. package/src/common/DropDown/search.svg +4 -4
  57. package/src/common/Pagination/Pagination.module.scss +210 -210
  58. package/src/common/Pagination/arrow-left.svg +11 -11
  59. package/src/common/Pagination/arrow-right.svg +11 -11
  60. package/src/common/Pagination/index.tsx +156 -156
  61. package/src/common/RollingBanner/RollingBanner.module.scss +126 -0
  62. package/src/common/RollingBanner/index.tsx +140 -0
  63. package/src/common/SegmentButton/SegmentButton.module.scss +46 -45
  64. package/src/common/SegmentButton/index.tsx +79 -79
  65. package/src/common/Skeleton/Skeleton.module.scss +80 -80
  66. package/src/common/Skeleton/index.tsx +47 -47
  67. package/src/common/SwitchButton/SwitchButton.module.scss +65 -65
  68. package/src/common/SwitchButton/index.tsx +57 -57
  69. package/src/common/Table/Table.module.scss +70 -70
  70. package/src/common/Table/index.tsx +128 -128
  71. package/src/index.scss +1 -1
  72. package/src/index.tsx +24 -22
  73. package/src/styles/color.scss +346 -346
  74. package/src/styles/font-face.scss +18 -18
  75. package/src/styles/font.scss +49 -49
  76. package/src/styles/mediaQuery.scss +22 -22
  77. package/src/styles/scrollbar.scss +71 -71
  78. package/src/svg.d.ts +6 -6
  79. package/src/utils/styles/mediaQuery.scss +22 -22
  80. package/src/utils/ts/allowDecimal.ts +4 -4
  81. package/src/utils/ts/autoHypen.ts +33 -33
  82. package/src/utils/ts/calculateMax.ts +24 -24
  83. package/src/utils/ts/checkIsMobilePlatform.ts +15 -15
  84. package/src/utils/ts/formatFileSize.ts +16 -16
  85. package/src/utils/ts/formatMoney.ts +16 -16
  86. package/src/utils/ts/gradientRatio.ts +61 -61
  87. package/src/utils/ts/kiloToMega.ts +30 -30
  88. package/src/utils/ts/maskingPhone.ts +8 -8
  89. package/src/utils/ts/toQueryString.ts +7 -7
  90. package/src/utils/ts/valueAsNumber.ts +15 -15
  91. package/src/vite-env.d.ts +2 -2
@@ -1,135 +1,135 @@
1
- @use "@/styles/scrollbar.scss" as scrollbar;
2
-
3
- .wrapper {
4
- position: relative;
5
- width: fit-content;
6
- }
7
-
8
- .title {
9
- width: 180px;
10
- height: 50px;
11
- display: flex;
12
- align-items: center;
13
- justify-content: space-between;
14
- background-color: var(--white);
15
- border: 1px solid #ccc;
16
- border-radius: 5px;
17
- padding: 10px;
18
- font-size: 16px;
19
- cursor: pointer;
20
- }
21
-
22
- .icon {
23
- width: 15px;
24
- height: 15px;
25
- stroke: var(--G-60);
26
- transition: transform 0.25s;
27
-
28
- &--up {
29
- transform: rotate(180deg);
30
- }
31
- }
32
-
33
- .list-portal {
34
- display: contents;
35
- }
36
-
37
- .list-wrapper {
38
- height: 0;
39
- position: absolute;
40
- isolation: isolate;
41
- background-color: var(--white);
42
- transition: height 0.25s;
43
- overflow: hidden;
44
- border: 1px solid var(--G-30);
45
- z-index: 10000;
46
-
47
- &--up {
48
- border-radius: 0 0 5px 5px;
49
- box-shadow: 0 2px 10px 4px rgba(0, 0, 0, 0.2);
50
- }
51
-
52
- &--down {
53
- border-radius: 5px 5px 0 0;
54
- box-shadow: 0 -2px 10px 2px rgba(0, 0, 0, 0.2);
55
- }
56
- }
57
-
58
- .list {
59
- position: relative;
60
- display: flex;
61
- flex-direction: column;
62
- overflow-y: scroll;
63
- max-height: 300px;
64
-
65
- @include scrollbar.custom-scrollbar($background: var(--G-10), $color: var(--G-50));
66
-
67
- &__search {
68
- position: sticky;
69
- top: 0;
70
- width: 100%;
71
- height: 40px;
72
- flex-shrink: 0;
73
- display: flex;
74
- align-items: center;
75
- gap: 5px;
76
- border: none;
77
- border-bottom: 1px solid var(--G-20);
78
- font-size: 16px;
79
- outline: none;
80
- box-sizing: border-box;
81
- padding: 8px;
82
- border-radius: 5px 5px 0 0;
83
- background-color: var(--white);
84
-
85
- &:focus-within {
86
- outline: 2px solid var(--P-20);
87
- outline-offset: -2px;
88
- }
89
-
90
- & > svg {
91
- width: 11px;
92
- height: 11px;
93
- flex-shrink: 0;
94
- }
95
-
96
- & > input {
97
- border: none;
98
- outline: none;
99
- background-color: transparent;
100
- }
101
- }
102
-
103
- &__item {
104
- min-height: 50px;
105
- padding: 8px;
106
-
107
- & + & {
108
- border-top: 1px solid var(--G-20);
109
- }
110
-
111
- &:hover {
112
- background-color: var(--G-5);
113
- }
114
-
115
- &--selected {
116
- background-color: var(--G-20);
117
- font-weight: 600;
118
-
119
- &:hover {
120
- background-color: var(--G-20);
121
- }
122
- }
123
- }
124
-
125
- &__empty {
126
- height: 50px;
127
- display: flex;
128
- align-items: center;
129
- justify-content: center;
130
- padding: 10px;
131
- text-align: center;
132
- color: var(--G-50);
133
- font-size: 16px;
134
- }
135
- }
1
+ @use "@/styles/scrollbar.scss" as scrollbar;
2
+
3
+ .wrapper {
4
+ position: relative;
5
+ width: fit-content;
6
+ }
7
+
8
+ .title {
9
+ width: 180px;
10
+ height: 50px;
11
+ display: flex;
12
+ align-items: center;
13
+ justify-content: space-between;
14
+ background-color: var(--white);
15
+ border: 1px solid #ccc;
16
+ border-radius: 5px;
17
+ padding: 10px;
18
+ font-size: 16px;
19
+ cursor: pointer;
20
+ }
21
+
22
+ .icon {
23
+ width: 15px;
24
+ height: 15px;
25
+ stroke: var(--G-60);
26
+ transition: transform 0.25s;
27
+
28
+ &--up {
29
+ transform: rotate(180deg);
30
+ }
31
+ }
32
+
33
+ .list-portal {
34
+ display: contents;
35
+ }
36
+
37
+ .list-wrapper {
38
+ height: 0;
39
+ position: absolute;
40
+ isolation: isolate;
41
+ background-color: var(--white);
42
+ transition: height 0.25s;
43
+ overflow: hidden;
44
+ border: 1px solid var(--G-30);
45
+ z-index: 10000;
46
+
47
+ &--up {
48
+ border-radius: 0 0 5px 5px;
49
+ box-shadow: 0 2px 10px 4px rgba(0, 0, 0, 0.2);
50
+ }
51
+
52
+ &--down {
53
+ border-radius: 5px 5px 0 0;
54
+ box-shadow: 0 -2px 10px 2px rgba(0, 0, 0, 0.2);
55
+ }
56
+ }
57
+
58
+ .list {
59
+ position: relative;
60
+ display: flex;
61
+ flex-direction: column;
62
+ overflow-y: scroll;
63
+ max-height: 300px;
64
+
65
+ @include scrollbar.custom-scrollbar($background: var(--G-10), $color: var(--G-50));
66
+
67
+ &__search {
68
+ position: sticky;
69
+ top: 0;
70
+ width: 100%;
71
+ height: 40px;
72
+ flex-shrink: 0;
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 5px;
76
+ border: none;
77
+ border-bottom: 1px solid var(--G-20);
78
+ font-size: 16px;
79
+ outline: none;
80
+ box-sizing: border-box;
81
+ padding: 8px;
82
+ border-radius: 5px 5px 0 0;
83
+ background-color: var(--white);
84
+
85
+ &:focus-within {
86
+ outline: 2px solid var(--P-20);
87
+ outline-offset: -2px;
88
+ }
89
+
90
+ & > svg {
91
+ width: 11px;
92
+ height: 11px;
93
+ flex-shrink: 0;
94
+ }
95
+
96
+ & > input {
97
+ border: none;
98
+ outline: none;
99
+ background-color: transparent;
100
+ }
101
+ }
102
+
103
+ &__item {
104
+ min-height: 50px;
105
+ padding: 8px;
106
+
107
+ & + & {
108
+ border-top: 1px solid var(--G-20);
109
+ }
110
+
111
+ &:hover {
112
+ background-color: var(--G-5);
113
+ }
114
+
115
+ &--selected {
116
+ background-color: var(--G-20);
117
+ font-weight: 600;
118
+
119
+ &:hover {
120
+ background-color: var(--G-20);
121
+ }
122
+ }
123
+ }
124
+
125
+ &__empty {
126
+ height: 50px;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ padding: 10px;
131
+ text-align: center;
132
+ color: var(--G-50);
133
+ font-size: 16px;
134
+ }
135
+ }
@@ -1,157 +1,157 @@
1
- import { useEffect, useMemo, useRef, useState } from 'react';
2
- import { cn } from '@jk-core/utils';
3
- import styles from './DropDown.module.scss';
4
- import SearchIcon from './search.svg';
5
-
6
- interface ListProps {
7
- selectedItem?: string;
8
- list: string[];
9
- filteredList: string[];
10
- parent: React.RefObject<HTMLDivElement | null>;
11
- onSelect: (item: string, index: number) => void;
12
- setFilteredList?: React.Dispatch<React.SetStateAction<string[]>>
13
- ;
14
- }
15
-
16
- interface Position {
17
- top?: number;
18
- left?: number;
19
- bottom?: number;
20
- height: number;
21
- }
22
-
23
- export default function List({ parent, selectedItem, list, filteredList, onSelect, setFilteredList }: ListProps) {
24
- const listHeight = useMemo(() => {
25
- if (setFilteredList) {
26
- return Math.min((filteredList.length * 50) + 40, 300);
27
- }
28
- return Math.min(list.length * 50, 300);
29
- }, [filteredList.length, list.length, setFilteredList]);
30
-
31
- const listRef = useRef<HTMLDivElement>(null);
32
- const [position, setPosition] = useState<Position>(() => {
33
- if (!parent || !parent.current) {
34
- return { top: 0, left: 0, bottom: 0, height: 0 };
35
- }
36
- const rect = parent.current.getBoundingClientRect();
37
-
38
- const spaceBelow = window.innerHeight - rect.bottom;
39
- const spaceAbove = rect.top;
40
- if (spaceBelow < listHeight && spaceAbove > listHeight) {
41
- // 위에 열림: bottom 사용, top은 undefined
42
- return {
43
- top: undefined,
44
- left: rect.left + window.scrollX,
45
- bottom: window.innerHeight - rect.top - window.scrollY,
46
- height: 0,
47
- };
48
- }
49
- // 아래에 열림: top 사용, bottom은 undefined
50
- return {
51
- top: rect.bottom + window.scrollY,
52
- left: rect.left + window.scrollX,
53
- bottom: undefined,
54
- height: 0,
55
- scroll: window.scrollY,
56
- };
57
- });
58
-
59
- useEffect(() => {
60
- function updatePosition() {
61
- setPosition(prev => ({
62
- ...prev,
63
- height: listHeight,
64
- }));
65
- }
66
-
67
- updatePosition();
68
-
69
- window.addEventListener('resize', updatePosition);
70
-
71
- return () => {
72
- window.removeEventListener('resize', updatePosition);
73
- };
74
- }, [listHeight]);
75
-
76
- useEffect(() => {
77
- const handleScroll = () => {
78
- if (!parent || !parent.current) return;
79
- const rect = parent.current.getBoundingClientRect();
80
- const spaceBelow = window.innerHeight - rect.bottom;
81
- const spaceAbove = rect.top;
82
- if (spaceBelow < listHeight && spaceAbove > listHeight) {
83
- // 위에 열림
84
- setPosition({
85
- top: undefined,
86
- left: rect.left + window.scrollX,
87
- bottom: window.innerHeight - rect.top - window.scrollY,
88
- height: listHeight,
89
- });
90
- } else {
91
- // 아래에 열림
92
- setPosition({
93
- top: rect.bottom + window.scrollY,
94
- left: rect.left + window.scrollX,
95
- bottom: undefined,
96
- height: listHeight,
97
- });
98
- }
99
- };
100
-
101
- window.addEventListener('scroll', handleScroll, true);
102
- window.addEventListener('resize', handleScroll, true);
103
-
104
- return () => {
105
- window.removeEventListener('scroll', handleScroll, true);
106
- window.removeEventListener('resize', handleScroll, true);
107
- };
108
- }, [listHeight, parent, position.height]);
109
-
110
- return (
111
- <div
112
- className={cn({
113
- [styles['list-wrapper']]: true,
114
- [styles['list-wrapper--up']]: position.bottom === undefined,
115
- [styles['list-wrapper--down']]: position.top === undefined,
116
- })}
117
- style={{
118
- width: parent?.current?.offsetWidth,
119
- height: position.height,
120
- top: position.top,
121
- left: position.left,
122
- bottom: position.bottom,
123
- }}
124
- >
125
- <div className={styles.list} ref={listRef}>
126
- {setFilteredList && (
127
- <label className={styles.list__search}>
128
- <SearchIcon />
129
- <input
130
- type="text"
131
- placeholder="검색"
132
- onChange={(e) => setFilteredList(list.filter((item) => item.includes(e.target.value)))}
133
- />
134
- </label>
135
- )}
136
- {filteredList.length === 0 && (
137
- <div className={styles.list__empty}>
138
- 검색 결과가 없습니다.
139
- </div>
140
- )}
141
- {filteredList.map((item, index) => (
142
- <button
143
- className={cn({
144
- [styles.list__item]: true,
145
- [styles['list__item--selected']]: item === selectedItem,
146
- })}
147
- type="button"
148
- key={item + index}
149
- onClick={() => onSelect(item, index)}
150
- >
151
- {item}
152
- </button>
153
- ))}
154
- </div>
155
- </div>
156
- );
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
+ import { cn } from '@jk-core/utils';
3
+ import styles from './DropDown.module.scss';
4
+ import SearchIcon from './search.svg';
5
+
6
+ interface ListProps {
7
+ selectedItem?: string;
8
+ list: string[];
9
+ filteredList: string[];
10
+ parent: React.RefObject<HTMLDivElement | null>;
11
+ onSelect: (item: string, index: number) => void;
12
+ setFilteredList?: React.Dispatch<React.SetStateAction<string[]>>
13
+ ;
14
+ }
15
+
16
+ interface Position {
17
+ top?: number;
18
+ left?: number;
19
+ bottom?: number;
20
+ height: number;
21
+ }
22
+
23
+ export default function List({ parent, selectedItem, list, filteredList, onSelect, setFilteredList }: ListProps) {
24
+ const listHeight = useMemo(() => {
25
+ if (setFilteredList) {
26
+ return Math.min((filteredList.length * 50) + 40, 300);
27
+ }
28
+ return Math.min(list.length * 50, 300);
29
+ }, [filteredList.length, list.length, setFilteredList]);
30
+
31
+ const listRef = useRef<HTMLDivElement>(null);
32
+ const [position, setPosition] = useState<Position>(() => {
33
+ if (!parent || !parent.current) {
34
+ return { top: 0, left: 0, bottom: 0, height: 0 };
35
+ }
36
+ const rect = parent.current.getBoundingClientRect();
37
+
38
+ const spaceBelow = window.innerHeight - rect.bottom;
39
+ const spaceAbove = rect.top;
40
+ if (spaceBelow < listHeight && spaceAbove > listHeight) {
41
+ // 위에 열림: bottom 사용, top은 undefined
42
+ return {
43
+ top: undefined,
44
+ left: rect.left + window.scrollX,
45
+ bottom: window.innerHeight - rect.top - window.scrollY,
46
+ height: 0,
47
+ };
48
+ }
49
+ // 아래에 열림: top 사용, bottom은 undefined
50
+ return {
51
+ top: rect.bottom + window.scrollY,
52
+ left: rect.left + window.scrollX,
53
+ bottom: undefined,
54
+ height: 0,
55
+ scroll: window.scrollY,
56
+ };
57
+ });
58
+
59
+ useEffect(() => {
60
+ function updatePosition() {
61
+ setPosition(prev => ({
62
+ ...prev,
63
+ height: listHeight,
64
+ }));
65
+ }
66
+
67
+ updatePosition();
68
+
69
+ window.addEventListener('resize', updatePosition);
70
+
71
+ return () => {
72
+ window.removeEventListener('resize', updatePosition);
73
+ };
74
+ }, [listHeight]);
75
+
76
+ useEffect(() => {
77
+ const handleScroll = () => {
78
+ if (!parent || !parent.current) return;
79
+ const rect = parent.current.getBoundingClientRect();
80
+ const spaceBelow = window.innerHeight - rect.bottom;
81
+ const spaceAbove = rect.top;
82
+ if (spaceBelow < listHeight && spaceAbove > listHeight) {
83
+ // 위에 열림
84
+ setPosition({
85
+ top: undefined,
86
+ left: rect.left + window.scrollX,
87
+ bottom: window.innerHeight - rect.top - window.scrollY,
88
+ height: listHeight,
89
+ });
90
+ } else {
91
+ // 아래에 열림
92
+ setPosition({
93
+ top: rect.bottom + window.scrollY,
94
+ left: rect.left + window.scrollX,
95
+ bottom: undefined,
96
+ height: listHeight,
97
+ });
98
+ }
99
+ };
100
+
101
+ window.addEventListener('scroll', handleScroll, true);
102
+ window.addEventListener('resize', handleScroll, true);
103
+
104
+ return () => {
105
+ window.removeEventListener('scroll', handleScroll, true);
106
+ window.removeEventListener('resize', handleScroll, true);
107
+ };
108
+ }, [listHeight, parent, position.height]);
109
+
110
+ return (
111
+ <div
112
+ className={cn({
113
+ [styles['list-wrapper']]: true,
114
+ [styles['list-wrapper--up']]: position.bottom === undefined,
115
+ [styles['list-wrapper--down']]: position.top === undefined,
116
+ })}
117
+ style={{
118
+ width: parent?.current?.offsetWidth,
119
+ height: position.height,
120
+ top: position.top,
121
+ left: position.left,
122
+ bottom: position.bottom,
123
+ }}
124
+ >
125
+ <div className={styles.list} ref={listRef}>
126
+ {setFilteredList && (
127
+ <label className={styles.list__search}>
128
+ <SearchIcon />
129
+ <input
130
+ type="text"
131
+ placeholder="검색"
132
+ onChange={(e) => setFilteredList(list.filter((item) => item.includes(e.target.value)))}
133
+ />
134
+ </label>
135
+ )}
136
+ {filteredList.length === 0 && (
137
+ <div className={styles.list__empty}>
138
+ 검색 결과가 없습니다.
139
+ </div>
140
+ )}
141
+ {filteredList.map((item, index) => (
142
+ <button
143
+ className={cn({
144
+ [styles.list__item]: true,
145
+ [styles['list__item--selected']]: item === selectedItem,
146
+ })}
147
+ type="button"
148
+ key={item + index}
149
+ onClick={() => onSelect(item, index)}
150
+ >
151
+ {item}
152
+ </button>
153
+ ))}
154
+ </div>
155
+ </div>
156
+ );
157
157
  }
@@ -1,3 +1,3 @@
1
- <svg width="12" height="9" viewBox="0 0 12 9" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M1 1.5L6 7L11 1.5" stroke-width="1.4" stroke-linecap="round"/>
3
- </svg>
1
+ <svg width="12" height="9" viewBox="0 0 12 9" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M1 1.5L6 7L11 1.5" stroke-width="1.4" stroke-linecap="round"/>
3
+ </svg>