@jk-core/components 1.0.2 → 1.1.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 (86) hide show
  1. package/dist/index.js +1275 -732
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.umd.cjs +5 -5
  4. package/dist/index.umd.cjs.map +1 -1
  5. package/dist/src/Calendar/components/DateLabel/index.d.ts +1 -1
  6. package/dist/src/Calendar/components/DayTile/index.d.ts +1 -1
  7. package/dist/src/Calendar/components/ViewSelector/index.d.ts +1 -1
  8. package/dist/src/common/Accordion/index.d.ts +12 -0
  9. package/dist/src/common/Breadcrumbs/index.d.ts +40 -0
  10. package/dist/src/common/Button/index.d.ts +27 -0
  11. package/dist/src/common/Card/index.d.ts +6 -0
  12. package/dist/src/common/DropDown/List.d.ts +10 -0
  13. package/dist/src/common/DropDown/index.d.ts +29 -0
  14. package/dist/src/common/Pagination/index.d.ts +16 -0
  15. package/dist/src/common/SegmentButton/index.d.ts +26 -0
  16. package/dist/src/common/Skeleton/index.d.ts +28 -0
  17. package/dist/src/common/SwitchButton/index.d.ts +19 -0
  18. package/dist/src/index.d.ts +10 -1
  19. package/dist/src/utils/ts/allowDecimal.d.ts +1 -0
  20. package/dist/src/utils/ts/autoHypen.d.ts +1 -0
  21. package/dist/src/utils/ts/calculateMax.d.ts +9 -0
  22. package/dist/src/utils/ts/checkIsMobilePlatform.d.ts +2 -0
  23. package/dist/src/utils/ts/formatFileSize.d.ts +4 -0
  24. package/dist/src/utils/ts/formatMoney.d.ts +2 -0
  25. package/dist/src/utils/ts/gradientRatio.d.ts +19 -0
  26. package/dist/src/utils/ts/kiloToMega.d.ts +6 -0
  27. package/dist/src/utils/ts/maskingPhone.d.ts +2 -0
  28. package/dist/src/utils/ts/toQueryString.d.ts +5 -0
  29. package/dist/src/utils/ts/valueAsNumber.d.ts +12 -0
  30. package/package.json +33 -25
  31. package/src/Calendar/RangeCalendar.tsx +5 -5
  32. package/src/Calendar/ScrollCalendar.tsx +3 -3
  33. package/src/Calendar/SingleCalendar.tsx +15 -15
  34. package/src/Calendar/components/DateLabel/index.tsx +19 -19
  35. package/src/Calendar/components/DayTile/index.tsx +4 -4
  36. package/src/Calendar/components/MonthTile/index.tsx +2 -2
  37. package/src/Calendar/components/ViewSelector/index.tsx +7 -7
  38. package/src/Calendar/components/YearTile/YearTile.module.scss +0 -1
  39. package/src/Calendar/components/YearTile/index.tsx +1 -1
  40. package/src/Calendar/index.tsx +3 -3
  41. package/src/Calendar/utils/isInRange.ts +1 -1
  42. package/src/common/Accordion/Accordion.module.scss +52 -0
  43. package/src/common/Accordion/arrow-down.svg +3 -0
  44. package/src/common/Accordion/arrow-up.svg +3 -0
  45. package/src/common/Accordion/index.tsx +55 -0
  46. package/src/common/Breadcrumbs/Breadcrumbs.module.scss +45 -0
  47. package/src/common/Breadcrumbs/home.svg +5 -0
  48. package/src/common/Breadcrumbs/index.tsx +82 -0
  49. package/src/common/Button/Button.module.scss +130 -0
  50. package/src/common/Button/index.tsx +60 -0
  51. package/src/common/Card/Card.module.scss +27 -0
  52. package/src/common/Card/index.tsx +19 -0
  53. package/src/common/DropDown/DropDown.module.scss +135 -0
  54. package/src/common/DropDown/List.tsx +157 -0
  55. package/src/common/DropDown/arrow-down.svg +3 -0
  56. package/src/common/DropDown/index.tsx +104 -0
  57. package/src/common/DropDown/search.svg +4 -0
  58. package/src/common/Pagination/Pagination.module.scss +177 -0
  59. package/src/common/Pagination/arrow-left.svg +12 -0
  60. package/src/common/Pagination/arrow-right.svg +12 -0
  61. package/src/common/Pagination/index.tsx +141 -0
  62. package/src/common/SegmentButton/SegmentButton.module.scss +44 -0
  63. package/src/common/SegmentButton/index.tsx +66 -0
  64. package/src/common/Skeleton/Skeleton.module.scss +80 -0
  65. package/src/common/Skeleton/index.tsx +48 -0
  66. package/src/common/SwitchButton/SwitchButton.module.scss +65 -0
  67. package/src/common/SwitchButton/index.tsx +56 -0
  68. package/src/index.scss +1 -0
  69. package/src/index.tsx +17 -1
  70. package/src/styles/color.scss +94 -0
  71. package/src/styles/font-face.scss +18 -0
  72. package/src/styles/font.scss +49 -0
  73. package/src/styles/scrollbar.scss +71 -0
  74. package/src/svg.d.ts +4 -2
  75. package/src/utils/styles/mediaQuery.scss +22 -0
  76. package/src/utils/ts/allowDecimal.ts +5 -0
  77. package/src/utils/ts/autoHypen.ts +33 -0
  78. package/src/utils/ts/calculateMax.ts +24 -0
  79. package/src/utils/ts/checkIsMobilePlatform.ts +15 -0
  80. package/src/utils/ts/formatFileSize.ts +16 -0
  81. package/src/utils/ts/formatMoney.ts +16 -0
  82. package/src/utils/ts/gradientRatio.ts +61 -0
  83. package/src/utils/ts/kiloToMega.ts +30 -0
  84. package/src/utils/ts/maskingPhone.ts +9 -0
  85. package/src/utils/ts/toQueryString.ts +7 -0
  86. package/src/utils/ts/valueAsNumber.ts +16 -0
@@ -0,0 +1,66 @@
1
+ import { useState } from 'react';
2
+ import { cn } from '@jk-core/utils';
3
+ import styles from './SegmentButton.module.scss';
4
+
5
+ interface SegmentButtonProps {
6
+ /**
7
+ * 세그먼트 버튼의 너비를 지정합니다. 기본값은 'auto'입니다.
8
+ * 만약 stretch가 true로 설정되면, 너비는 'auto'로 설정됩니다.
9
+ */
10
+ width?: string;
11
+ /**
12
+ * 세그먼트 버튼이 전체 너비를 차지하도록 설정합니다.
13
+ * true로 설정하면 버튼이 부모 요소의 너비를 채웁니다.
14
+ */
15
+ stretch?: boolean;
16
+ /**
17
+ * 세그먼트 버튼의 옵션을 설정합니다.
18
+ * 각 옵션은 텍스트와 클릭 이벤트 핸들러를 포함합니다.
19
+ */
20
+ option:Array<{ text: string; onClick: () => void }>;
21
+ }
22
+
23
+ /**
24
+ * 세그먼트 버튼 컴포넌트는 여러 개의 버튼을 세그먼트 형태로 표시합니다.
25
+ * 각 버튼은 클릭 시 지정된 함수를 실행합니다.
26
+ */
27
+ export default function SegmentButton({ width, stretch, option }: SegmentButtonProps) {
28
+ const [selected, setSelected] = useState(0);
29
+
30
+ return (
31
+ <div
32
+ className={styles.segment}
33
+ style={{
34
+ width: stretch ? '100%' : undefined,
35
+ gridTemplateColumns: `repeat(${option.length},1fr)`,
36
+ }}
37
+ >
38
+ <div
39
+ className={styles['segment--selector']}
40
+ style={{
41
+ width: `${100 / option.length}%`,
42
+ left: `${(selected * 100) / option.length}%`,
43
+ }}
44
+ />
45
+ {option.map((item, index) => (
46
+ <button
47
+ className={cn({
48
+ [styles.button]: true,
49
+ [styles['button--selected']]: index === selected,
50
+ })}
51
+ key={item.text}
52
+ type="button"
53
+ style={{ width: stretch ? 'auto' : (width || 'auto') }}
54
+ onClick={() => {
55
+ setSelected(index);
56
+ item.onClick();
57
+ }}
58
+ >
59
+ <div>
60
+ {item.text}
61
+ </div>
62
+ </button>
63
+ ))}
64
+ </div>
65
+ );
66
+ }
@@ -0,0 +1,80 @@
1
+ $color: #eeeeee;
2
+ $shadow: #e5e5e5;
3
+
4
+ @keyframes skeleton-blink {
5
+ 0% {
6
+ left: -100%;
7
+ }
8
+ 99.9% {
9
+ left: 100%;
10
+ }
11
+ 100% {
12
+ left: -100%;
13
+ }
14
+ }
15
+
16
+ @keyframes skeleton-glow {
17
+ 0% {
18
+ background-color: $color;
19
+ }
20
+ 50% {
21
+ background-color: $shadow;
22
+ }
23
+ 100% {
24
+ background-color: $color;
25
+ }
26
+ }
27
+
28
+ .skeleton-circle {
29
+ width: 100%;
30
+ height: 100%;
31
+ position: relative;
32
+ background-color: $color;
33
+ border-radius: 100%;
34
+ overflow: hidden;
35
+ flex-shrink: 0;
36
+ }
37
+
38
+ .skeleton-round {
39
+ width: 100%;
40
+ height: 100%;
41
+ position: relative;
42
+ background-color: $color;
43
+ border-radius: 10px;
44
+ overflow: hidden;
45
+ flex-shrink: 0;
46
+ }
47
+
48
+ .skeleton-rectangle {
49
+ width: 100%;
50
+ height: 100%;
51
+ position: relative;
52
+ background-color: $color;
53
+ flex-shrink: 0;
54
+ overflow: hidden;
55
+ }
56
+
57
+ .skeleton--glow {
58
+ &::before {
59
+ content: "";
60
+ position: absolute;
61
+ top: 0;
62
+ width: 100%;
63
+ height: 100%;
64
+ left: 0;
65
+ animation: skeleton-glow 2s infinite;
66
+ }
67
+ }
68
+
69
+ .skeleton--blink {
70
+ &::before {
71
+ content: "";
72
+ position: absolute;
73
+ top: 0;
74
+ left: -100%;
75
+ width: 100%;
76
+ height: 100%;
77
+ background: linear-gradient(to right, transparent, $shadow, transparent);
78
+ animation: skeleton-blink 3s infinite;
79
+ }
80
+ }
@@ -0,0 +1,48 @@
1
+ import styles from './Skeleton.module.scss';
2
+
3
+ interface SkeletonProps {
4
+ /**
5
+ * 스켈레톤의 모양을 지정합니다. 'circle', 'rectangle', 'round' 중 하나를 선택할 수 있습니다.
6
+ * 기본값은 'rectangle'입니다.
7
+ */
8
+ shape?: 'circle' | 'rectangle' | 'round';
9
+ /**
10
+ * 스켈레톤의 너비를 지정합니다. 기본값은 '100%'입니다.
11
+ * 'auto'로 설정하면 콘텐츠에 맞게 자동으로 조정됩니다.
12
+ */
13
+ width?: string | number;
14
+ /**
15
+ * 스켈레톤의 높이를 지정합니다. 기본값은 '20px'입니다.
16
+ * 'auto'로 설정하면 콘텐츠에 맞게 자동으로 조정됩니다.
17
+ */
18
+ height?: string | number;
19
+ /**
20
+ * 스켈레톤 애니메이션 효과를 지정합니다. 'glow' 또는 'blink' 중 하나를 선택할 수 있습니다.
21
+ * 기본값은 'glow'입니다.
22
+ */
23
+ animation?: 'glow' | 'blink';
24
+ }
25
+
26
+ /**
27
+ * 스켈레톤 컴포넌트는 로딩 상태를 나타내기 위해 사용됩니다.
28
+ * 다양한 모양과 크기를 지원하며, 애니메이션 효과를 적용할 수 있습니다.
29
+ */
30
+ export default function Skeleton({ shape, width, height, animation = 'glow' }: SkeletonProps) {
31
+ const animationClass = animation === 'glow' ? styles['skeleton--glow'] : styles['skeleton--blink'];
32
+
33
+ if (shape === 'circle') {
34
+ return (
35
+ <div className={`${styles['skeleton-circle']} ${animationClass}`} style={{ width, height }} />
36
+ );
37
+ }
38
+
39
+ if (shape === 'round') {
40
+ return (
41
+ <div className={`${styles['skeleton-round']} ${animationClass}`} style={{ width, height }} />
42
+ );
43
+ }
44
+
45
+ return (
46
+ <div className={`${styles['skeleton-rectangle']} ${animationClass}`} style={{ width, height }} />
47
+ );
48
+ }
@@ -0,0 +1,65 @@
1
+ $main: #246beb;
2
+ $main-shadow: #113475;
3
+ $background: #eeeeee;
4
+ $shadow: #bcbcbc;
5
+
6
+ .button {
7
+ display: flex;
8
+ align-items: center;
9
+ height: 20px;
10
+ border: none;
11
+ background-color: transparent;
12
+ margin: 0 5px;
13
+ cursor: pointer;
14
+ }
15
+
16
+ .switch {
17
+ position: relative;
18
+ display: flex;
19
+ align-items: center;
20
+ width: 50px;
21
+ height: 25px;
22
+ border-radius: 100px;
23
+ background-color: $background;
24
+ box-shadow: inset 0 0 3px 1px $shadow;
25
+ transition: background-color 0.2s;
26
+
27
+ &__off {
28
+ background-color: $main;
29
+ border-color: $main;
30
+ box-shadow: inset 0 0 3px 1px $main-shadow;
31
+ }
32
+
33
+ &__button {
34
+ position: absolute;
35
+ width: 25px;
36
+ height: 25px;
37
+ border-radius: 100px;
38
+ transition: 0.2s;
39
+ padding: 2px;
40
+ overflow: hidden;
41
+
42
+ &--circle {
43
+ width: 100%;
44
+ height: 100%;
45
+ background-color: #ffffff;
46
+ border-radius: 100%;
47
+ box-shadow: 0 0 5px 1px $shadow;
48
+ }
49
+
50
+ &--circle-on {
51
+ box-shadow: none;
52
+ }
53
+
54
+ &--off {
55
+ left: 0px;
56
+ transition: 0.2s;
57
+ }
58
+
59
+ &--on {
60
+ left: 25px;
61
+ transition: 0.2s;
62
+ border-color: $main;
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,56 @@
1
+ import { useState } from 'react';
2
+ import { cn } from '@jk-core/utils';
3
+ import styles from './SwitchButton.module.scss';
4
+
5
+ interface SwitchButtonProps {
6
+ /**
7
+ * 스위치 버튼의 상태를 나타냅니다.
8
+ * true이면 스위치가 켜진 상태, false이면 꺼진 상태입니다.
9
+ * 기본값은 false로 설정되어 있습니다.
10
+ */
11
+ checked?: boolean,
12
+ /**
13
+ * 스위치 버튼의 상태가 변경될 때 호출되는 함수입니다.
14
+ */
15
+ onChange?: (value: boolean) => void
16
+ }
17
+
18
+ /**
19
+ * SwitchButton 컴포넌트
20
+ * 스위치 버튼을 표시하며, 클릭 시 상태가 변경됩니다.
21
+ * checked 속성으로 초기 상태를 설정할 수 있으며, onChange 함수를 통해 상태 변경을 처리할 수 있습니다.
22
+ */
23
+ export default function SwitchButton({ checked = false, onChange = () => { } }: SwitchButtonProps) {
24
+ const [isChecked, setIsChecked] = useState(checked);
25
+
26
+ return (
27
+ <button
28
+ className={styles.button}
29
+ type="button"
30
+ onClick={() => {
31
+ setIsChecked(!isChecked);
32
+ onChange(!isChecked);
33
+ }}
34
+ >
35
+ <div
36
+ className={cn({
37
+ [styles.switch]: true,
38
+ [styles.switch__off]: checked,
39
+ })}
40
+ >
41
+ <div className={cn({
42
+ [styles.switch__button]: true,
43
+ [styles['switch__button--off']]: !checked,
44
+ [styles['switch__button--on']]: checked,
45
+ })}
46
+ >
47
+ <div className={cn({
48
+ [styles['switch__button--circle']]: true,
49
+ [styles['switch__button--circle-on']]: checked,
50
+ })}
51
+ />
52
+ </div>
53
+ </div>
54
+ </button>
55
+ );
56
+ }
package/src/index.scss ADDED
@@ -0,0 +1 @@
1
+ @forward "@/styles/color";
package/src/index.tsx CHANGED
@@ -1,5 +1,21 @@
1
+ import Breadcrumbs, { BreadcrumbsItem } from '@/common/Breadcrumbs';
2
+ import { Button } from '@/common/Button';
3
+ import Pagination from '@/common/Pagination';
4
+ import Skeleton from '@/common/Skeleton';
5
+ import SwitchButton from '@/common/SwitchButton';
1
6
  import Calendar from './Calendar';
2
7
  import { CalendarRange, CalendarView } from './Calendar/type';
8
+ import Accordion from './common/Accordion';
9
+ import Card from './common/Card';
10
+ import DropDown from './common/DropDown';
11
+ import SegmentButton from './common/SegmentButton';
12
+
13
+ export {
14
+ Calendar, Accordion, Breadcrumbs, Button,
15
+ Pagination, Skeleton, SwitchButton,
16
+ Card, DropDown, SegmentButton, BreadcrumbsItem,
17
+ };
3
18
 
4
- export { Calendar };
5
19
  export type { CalendarView, CalendarRange };
20
+
21
+ import './index.scss';
@@ -0,0 +1,94 @@
1
+ :root {
2
+ --white: #ffffff;
3
+ --black: #000000;
4
+ --P-5: #eff5ff;
5
+ --P-10: #d3e1fb;
6
+ --P-20: #a7c4f7;
7
+ --P-30: #7ca6f3;
8
+ --P-40: #5089ef;
9
+ --P-50: #246beb;
10
+ --P-60: #1d56bc;
11
+ --P-70: #16408d;
12
+ --P-90: #07152f;
13
+ --P-100: #000000;
14
+ --S-5: #edf1f5;
15
+ --S-10: #cdd7e4;
16
+ --S-20: #b4c4d6;
17
+ --S-30: #99b0cb;
18
+ --S-40: #6B96C7;
19
+ --S-50: #346FB2;
20
+ --S-60: #1C589C;
21
+ --S-70: #063a74;
22
+ --S-80: #00162f;
23
+ --S-90: #000b17;
24
+ --G-5: #f8f8f8;
25
+ --G-10: #f0f0f0;
26
+ --G-20: #e4e4e4;
27
+ --G-30: #d8d8d8;
28
+ --G-40: #c6c6c6;
29
+ --G-50: #8e8e8e;
30
+ --G-60: #717171;
31
+ --G-70: #555555;
32
+ --G-80: #2d2d2d;
33
+ --G-90: #1d1d1d;
34
+ --Point-5: #fdf2f3;
35
+ --Point-10: #f8d6d8;
36
+ --Point-20: #f5a3a8;
37
+ --Point-30: #f1747c;
38
+ --Point-40: #ec4651;
39
+ --Point-50: #e71825;
40
+ --Point-60: #b9131e;
41
+ --Point-70: #8b0e16;
42
+ --Point-80: #5c0a0f;
43
+ --Point-90: #2e0507;
44
+ --Warning-5: #fff8e9;
45
+ --Warning-10: #ffeac1;
46
+ --Warning-20: #ffe2a7;
47
+ --Warning-30: #ffd47c;
48
+ --Warning-40: #ffc550;
49
+ --Warning-50: #ffb724;
50
+ --Warning-60: #98690a;
51
+ --Warning-70: #66490e;
52
+ --Warning-80: #4d370b;
53
+ --Warning-90: #332507;
54
+ --Success-5: #eef7f0;
55
+ --Success-10: #cee9d4;
56
+ --Success-20: #b2dcbb;
57
+ --Success-30: #8cca99;
58
+ --Success-40: #33a14b;
59
+ --Success-50: #008a1e;
60
+ --Success-60: #006e18;
61
+ --Success-70: #005312;
62
+ --Success-80: #00370c;
63
+ --Success-90: #002207;
64
+ --Info-5: #e9f0ff;
65
+ --Info-10: #d4e1ff;
66
+ --Info-20: #a9c3ff;
67
+ --Info-30: #7da4ff;
68
+ --Info-40: #5286ff;
69
+ --Info-50: #2768ff;
70
+ --Info-60: #1f53cc;
71
+ --Info-70: #173e99;
72
+ --Info-80: #0c1f4d;
73
+ --Info-90: #040a1a;
74
+ --Red: #e40000;
75
+ --Red2: #ffe4e4;
76
+ --Green: #2fb400;
77
+ --Green-2: #d7ffe0;
78
+ --Orange: #ff8800;
79
+ --Orange-5: #ffead1;
80
+ --Orange-10: #ffdacc;
81
+ --Orange-30: #ff8f66;
82
+ --Orange-40: #ff6a33;
83
+ --Orange-50: #ff4500;
84
+ --Orange-60: #d53209;
85
+ --Orange-70: #992900;
86
+ --Orange-80: #661c00;
87
+ --Orange-90: #330e00;
88
+ --Modal-Shadow: #0000005a;
89
+ --Modal-Background: #6666663a;
90
+ --loading: #6666663a;
91
+ --loading-color: #ffffff;
92
+ --loading-shadow: #00000033;
93
+ --loading-spinner: #222222;
94
+ }
@@ -0,0 +1,18 @@
1
+ @use "sass:string";
2
+
3
+ @mixin font-face($font-name, $src, $weight: normal, $style: normal) {
4
+ @font-face {
5
+ font-family: $font-name;
6
+ src: url($src);
7
+ font-style: $style;
8
+ font-weight: $weight;
9
+ font-display: swap;
10
+ }
11
+ }
12
+
13
+ @include font-face("Pretendard", "/fonts/Pretendard/Pretendard-Regular.woff2", 400);
14
+ @include font-face("Pretendard", "/fonts/Pretendard/Pretendard-Medium.woff2", 500);
15
+ @include font-face("Pretendard", "/fonts/Pretendard/Pretendard-SemiBold.woff2", 600);
16
+ @include font-face("Pretendard", "/fonts/Pretendard/Pretendard-Bold.woff2", 700);
17
+ @include font-face("Pretendard", "/fonts/Pretendard/Pretendard-ExtraBold.woff2", 800);
18
+ @include font-face("Pretendard", "/fonts/Pretendard/Pretendard-Black.woff2", 900);
@@ -0,0 +1,49 @@
1
+ @use "/src/utils/styles/mediaQuery.scss" as media;
2
+ @use "sass:math";
3
+
4
+ @mixin font($weight, $size) {
5
+ font-weight: $weight;
6
+ font-size: $size;
7
+ }
8
+
9
+ // 반응형 폰트 mixin
10
+ // nesting 규칙에 의해 폰트는 항상 코드의 가장 마지막에 위치해야 한다.
11
+
12
+ @mixin B-($i) {
13
+ font-weight: 700;
14
+ font-size: #{$i}rem;
15
+
16
+ @include media.tablet {
17
+ font-size: #{math.round($i * 0.9)}px;
18
+ }
19
+
20
+ @include media.mobile {
21
+ font-size: #{math.round($i * 0.8)}px;
22
+ }
23
+ }
24
+
25
+ @mixin Semi-($i) {
26
+ font-weight: 600;
27
+ font-size: #{$i}rem;
28
+
29
+ @include media.tablet {
30
+ font-size: #{math.round($i * 0.9)}px;
31
+ }
32
+
33
+ @include media.mobile {
34
+ font-size: #{math.round($i * 0.8)}px;
35
+ }
36
+ }
37
+
38
+ @mixin R-($i) {
39
+ font-weight: 400;
40
+ font-size: #{$i}rem;
41
+
42
+ @include media.tablet {
43
+ font-size: #{math.round($i * 0.9)}px;
44
+ }
45
+
46
+ @include media.mobile {
47
+ font-size: #{math.round($i * 0.8)}px;
48
+ }
49
+ }
@@ -0,0 +1,71 @@
1
+ @use "@/utils/styles/mediaQuery.scss" as mixinMedia;
2
+
3
+ @mixin custom-scrollbar($background: var(--G-10), $color: #c6c6c6) {
4
+ &::-webkit-scrollbar {
5
+ width: 8px;
6
+ height: 8px;
7
+ }
8
+
9
+ &::-webkit-scrollbar-thumb {
10
+ background-color: $color;
11
+ border-radius: 100px;
12
+
13
+ &:hover {
14
+ background: $color;
15
+ }
16
+
17
+ @include mixinMedia.tablet {
18
+ border: none;
19
+ }
20
+ }
21
+
22
+ &::-webkit-scrollbar-track {
23
+ background-color: $background;
24
+ border-radius: 100px;
25
+ }
26
+
27
+ &::-webkit-scrollbar-corner {
28
+ background: $background;
29
+ }
30
+ }
31
+
32
+ @mixin global-scrollbar() {
33
+ &::-webkit-scrollbar {
34
+ width: 12px;
35
+ height: 12px;
36
+
37
+ @include mixinMedia.tablet {
38
+ width: 8px;
39
+ height: 8px;
40
+ }
41
+
42
+ @include mixinMedia.mobile {
43
+ width: 6px;
44
+ height: 6px;
45
+ }
46
+ }
47
+
48
+ &::-webkit-scrollbar-thumb {
49
+ background-clip: padding-box;
50
+ border: 2px solid transparent;
51
+ background-color: #c6c6c6;
52
+ border-radius: 100px;
53
+ cursor: pointer;
54
+
55
+ &:hover {
56
+ background: #aeaeae;
57
+ }
58
+
59
+ @include mixinMedia.tablet {
60
+ border: none;
61
+ }
62
+ }
63
+
64
+ &::-webkit-scrollbar-track {
65
+ background-color: var(--G-10);
66
+ }
67
+
68
+ &::-webkit-scrollbar-corner {
69
+ background: var(--G-10);
70
+ }
71
+ }
package/src/svg.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ // svg를 ReactComponent처럼 사용하기 위해 선언
1
2
  declare module '*.svg' {
2
- const content: React.FC<React.SVGProps<SVGElement>>;
3
- export default content;
3
+ import { HTMLAttributes } from 'react';
4
+
5
+ export default React.Component<HTMLAttributes<HTMLDivElement>>;
4
6
  }
@@ -0,0 +1,22 @@
1
+ // 스크롤바 너비 14px 추가
2
+ $pc: 1396px;
3
+ $tablet: 1395px;
4
+ $mobile: 774px;
5
+
6
+ @mixin pc {
7
+ @media (min-width: $pc) {
8
+ @content;
9
+ }
10
+ }
11
+
12
+ @mixin tablet {
13
+ @media (max-width: $tablet) {
14
+ @content;
15
+ }
16
+ }
17
+
18
+ @mixin mobile {
19
+ @media (max-width: $mobile) {
20
+ @content;
21
+ }
22
+ }
@@ -0,0 +1,5 @@
1
+ export const allowDecimal = (val: number) => {
2
+ const str = val.toString();
3
+ const decimal = str.split('.')[1];
4
+ return !decimal || decimal.length <= 2;
5
+ };
@@ -0,0 +1,33 @@
1
+ export default function AutoHypen(input:string) {
2
+ const value = input.replace(/[^0-9]/g, '');
3
+
4
+ const result = [];
5
+ let restNumber = '';
6
+
7
+ // 지역번호와 나머지 번호로 나누기
8
+ if (value.startsWith('02')) {
9
+ // 서울 02 지역번호
10
+ result.push(value.substr(0, 2));
11
+ restNumber = value.substring(2);
12
+ } else if (value.startsWith('1')) {
13
+ // 지역 번호가 없는 경우
14
+ // 1xxx-yyyy
15
+ restNumber = value;
16
+ } else {
17
+ // 나머지 3자리 지역번호
18
+ // 0xx-yyyy-zzzz
19
+ result.push(value.substr(0, 3));
20
+ restNumber = value.substring(3);
21
+ }
22
+
23
+ if (restNumber.length === 7) {
24
+ // 7자리만 남았을 때는 xxx-yyyy
25
+ result.push(restNumber.substring(0, 3));
26
+ result.push(restNumber.substring(3));
27
+ } else {
28
+ result.push(restNumber.substring(0, 4));
29
+ result.push(restNumber.substring(4));
30
+ }
31
+
32
+ return (result.filter((val) => val).join('-'));
33
+ }
@@ -0,0 +1,24 @@
1
+ import { isDefined } from '@jk-core/utils';
2
+
3
+ /**
4
+ * unit으로 나누어떨어지면서,
5
+ * a가 양수라면, a보다 크되 가장 작은 정수.
6
+ * a가 음수라면, a보다 작되 가장 큰 정수를 반환.
7
+ * 절댓값이 threshold에 미치지못한다면, 그대로 반환.
8
+ * @param {*} value
9
+ * @param {*} unit
10
+ */
11
+ export const calculateMax = (
12
+ value?: number,
13
+ threshold: number = 10,
14
+ unit: number = 10,
15
+ ) => {
16
+ if (!isDefined(value)) return value;
17
+ if (unit === 0 || Math.abs(value) < threshold) return value;
18
+ if (value > 0) {
19
+ return Math.ceil(value / unit) * unit;
20
+ } if (value < 0) {
21
+ return Math.floor(value / unit) * unit;
22
+ }
23
+ return value;
24
+ };
@@ -0,0 +1,15 @@
1
+ const checkIsMobile = () => {
2
+ const { userAgent } = navigator;
3
+
4
+ if (userAgent.match(/Android/i) || userAgent.match(/iPhone|iPad|iPod/i)) {
5
+ return true;
6
+ }
7
+
8
+ if (userAgent.match(/Windows/i) || userAgent.match(/Macintosh/i)) {
9
+ return false;
10
+ }
11
+
12
+ return true;
13
+ };
14
+
15
+ export default checkIsMobile;