@team-monolith/cds 0.4.0 → 0.4.3

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 (88) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +2 -0
  3. package/package.json +5 -1
  4. package/public/favicon.ico +0 -0
  5. package/public/index.html +0 -43
  6. package/public/logo192.png +0 -0
  7. package/public/logo512.png +0 -0
  8. package/public/manifest.json +0 -25
  9. package/public/robots.txt +0 -3
  10. package/src/App.tsx +0 -7
  11. package/src/cds/CodleDesignSystemProvider.tsx +0 -93
  12. package/src/cds/README.md +0 -23
  13. package/src/cds/components/AlertDialog/AlertDialog.tsx +0 -101
  14. package/src/cds/components/AlertDialog/AlertDialogActions.tsx +0 -34
  15. package/src/cds/components/AlertDialog/AlertDialogContent.tsx +0 -36
  16. package/src/cds/components/AlertDialog/AlertDialogTitle.tsx +0 -63
  17. package/src/cds/components/AlertDialog/index.tsx +0 -4
  18. package/src/cds/components/Banner.tsx +0 -176
  19. package/src/cds/components/Button.tsx +0 -256
  20. package/src/cds/components/CheckboxInput.tsx +0 -270
  21. package/src/cds/components/Input.tsx +0 -171
  22. package/src/cds/components/InputBase.tsx +0 -226
  23. package/src/cds/components/Pagination.tsx +0 -99
  24. package/src/cds/components/PinInput.tsx +0 -322
  25. package/src/cds/components/RadioInput.tsx +0 -226
  26. package/src/cds/components/SquareButton.tsx +0 -229
  27. package/src/cds/components/Switch.tsx +0 -129
  28. package/src/cds/components/Tag.tsx +0 -155
  29. package/src/cds/components/Tooltip.tsx +0 -104
  30. package/src/cds/foundation/color.ts +0 -83
  31. package/src/cds/foundation/shadows.ts +0 -17
  32. package/src/cds/icons/Arrows/index.ts +0 -2
  33. package/src/cds/icons/Media/index.ts +0 -2
  34. package/src/cds/icons/System/index.ts +0 -2
  35. package/src/cds/icons/arrows.tsx +0 -116
  36. package/src/cds/icons/brand.tsx +0 -13
  37. package/src/cds/icons/design.tsx +0 -15
  38. package/src/cds/icons/map.tsx +0 -14
  39. package/src/cds/icons/system.tsx +0 -143
  40. package/src/cds/index.ts +0 -64
  41. package/src/cds/patterns/Card/Card.tsx +0 -294
  42. package/src/cds/patterns/Card/class-icon.svg +0 -28
  43. package/src/cds/patterns/Card/index.tsx +0 -2
  44. package/src/cds/patterns/Card/material-icon.svg +0 -25
  45. package/src/cds/patterns/Card/problem-icon.svg +0 -25
  46. package/src/cds/patterns/Card/thumbnail/sample.png +0 -0
  47. package/src/cds/patterns/Dialog/Dialog.tsx +0 -57
  48. package/src/cds/patterns/Dialog/DialogContent.tsx +0 -28
  49. package/src/cds/patterns/Dialog/DialogNavigation.tsx +0 -29
  50. package/src/cds/patterns/Dialog/DialogNavigationContext.tsx +0 -9
  51. package/src/cds/patterns/Dialog/DialogNavigationItem.tsx +0 -42
  52. package/src/cds/patterns/Dialog/DialogPanel.tsx +0 -40
  53. package/src/cds/patterns/Dialog/DialogPanels.tsx +0 -24
  54. package/src/cds/patterns/Dialog/DialogPanelsContext.tsx +0 -9
  55. package/src/cds/patterns/Dialog/DialogTitle.tsx +0 -55
  56. package/src/cds/patterns/Dialog/index.tsx +0 -7
  57. package/src/cds/patterns/Dropdown/Dropdown.tsx +0 -111
  58. package/src/cds/patterns/Dropdown/DropdownItem.tsx +0 -203
  59. package/src/cds/patterns/Dropdown/DropdownMenu.tsx +0 -176
  60. package/src/cds/patterns/Dropdown/index.tsx +0 -2
  61. package/src/cds/patterns/EmptyState/EmptyState.tsx +0 -91
  62. package/src/cds/patterns/EmptyState/empty-state-icon.svg +0 -36
  63. package/src/cds/patterns/EmptyState/index.tsx +0 -2
  64. package/src/cds/patterns/Navigation/NavigationContext.tsx +0 -9
  65. package/src/cds/patterns/Navigation/NavigationHorizontal.tsx +0 -32
  66. package/src/cds/patterns/Navigation/NavigationItem.tsx +0 -36
  67. package/src/cds/patterns/Navigation/NavigationVertical.tsx +0 -39
  68. package/src/cds/patterns/Navigation/index.tsx +0 -3
  69. package/src/cds/patterns/SegmentedControl/SegmentedControlButton.tsx +0 -55
  70. package/src/cds/patterns/SegmentedControl/SegmentedControlGroup.tsx +0 -81
  71. package/src/cds/patterns/SegmentedControl/SegmentedControlGroupPropsContext.tsx +0 -9
  72. package/src/cds/patterns/SegmentedControl/SegmentedControlSquareButton.tsx +0 -51
  73. package/src/cds/patterns/SegmentedControl/index.ts +0 -3
  74. package/src/cds/patterns/Table/Table.tsx +0 -62
  75. package/src/cds/patterns/Table/TableBody.tsx +0 -30
  76. package/src/cds/patterns/Table/TableCell.tsx +0 -253
  77. package/src/cds/patterns/Table/TableHead.tsx +0 -30
  78. package/src/cds/patterns/Table/TablePropsContext.tsx +0 -9
  79. package/src/cds/patterns/Table/TableRow.tsx +0 -70
  80. package/src/cds/patterns/Table/TableVariantContext.tsx +0 -9
  81. package/src/cds/patterns/Table/index.tsx +0 -15
  82. package/src/cds/utils/hover.tsx +0 -24
  83. package/src/cds/utils/reset.tsx +0 -19
  84. package/src/cds/utils/zIndex.tsx +0 -3
  85. package/src/index.tsx +0 -10
  86. package/tsconfig.json +0 -22
  87. /package/{src/cds → @types}/emotion.d.ts +0 -0
  88. /package/{src/cds → @types}/svg.d.ts +0 -0
@@ -1,226 +0,0 @@
1
- import { Theme, css } from "@emotion/react";
2
- import styled from "@emotion/styled";
3
- import { InputHTMLAttributes } from "react";
4
- import { CloseCircleFillIcon } from "../icons/system";
5
- import { RESET_BUTTON } from "../utils/reset";
6
-
7
- export type InputBaseColor =
8
- | "default"
9
- | "activePrimary"
10
- | "activeDanger"
11
- | "activeSuccess";
12
-
13
- export type InputBaseSize = "large" | "medium" | "small";
14
-
15
- export interface InputBaseProps {
16
- className?: string;
17
- // component?: React.ElementType; Input은 component를 받지 않습니다.
18
-
19
- /** 컴포넌트 색상 */
20
- color: InputBaseColor;
21
-
22
- /** 컴포넌트 크기 */
23
- size: InputBaseSize;
24
-
25
- /** 입력되기 전 Input 컴포넌트에 노출될 문자열 */
26
- placeholder?: string;
27
-
28
- /** 비활성화 여부 */
29
- disabled?: boolean;
30
-
31
- /** Input 컴포넌트 내의 좌측 영역에 노출될 아이콘 */
32
- startIcon?: React.ReactNode;
33
-
34
- /** Input 컴포넌트 내의 좌측 영역에 노출될 텍스트.
35
- * `startIcon` 보다 우측에 노출됩니다. */
36
- startLabel?: string;
37
-
38
- /** Input 컴포넌트 내의 우측 영역에 노출될 텍스트.
39
- * `endIcon` 보다 좌측에 노출됩니다. */
40
- endLabel?: string;
41
-
42
- /** Input 컴포넌트 내의 우측 영역에 노출될 아이콘 */
43
- endIcon?: React.ReactNode;
44
-
45
- /** HTML input 태그에 전달될 ref */
46
- inputRef?: React.LegacyRef<HTMLInputElement>;
47
-
48
- /** HTML input 태그에 전달될 props */
49
- inputProps?: InputHTMLAttributes<HTMLInputElement>;
50
-
51
- /** true일 경우, Input이 상위 요소의 전체 길이를 차지하게 됩니다. */
52
- fullWidth?: boolean;
53
-
54
- /** 값이 변경될때 호출될 콜백 함수 */
55
- onChange?: React.ChangeEventHandler<HTMLInputElement>;
56
-
57
- /**
58
- * Clear Button을 클릭했을 때의 콜백 함수.
59
- * 설정하면, Input 컴포넌트 내의 우측 영역에 Clear Button이 노출됩니다.
60
- */
61
- onClear?: () => void;
62
-
63
- /** input의 value의 초기값 (UnControlled Component) */
64
- defaultValue?: any;
65
-
66
- /** input의 value (Controlled Component) */
67
- value?: any;
68
- }
69
-
70
- const COLOR_TO_INPUT_STYLES = (
71
- theme: Theme,
72
- color: InputBaseColor,
73
- disabled: boolean
74
- ) => {
75
- if (disabled) {
76
- return css`
77
- border: none;
78
- background: ${theme.color.foreground.neutralBaseDisabled};
79
- color: ${theme.color.background.neutralAlt};
80
- `;
81
- }
82
- return {
83
- default: css`
84
- border: none;
85
- background: ${theme.color.background.neutralAlt};
86
- color: ${theme.color.foreground.neutralBase};
87
- `,
88
- activePrimary: css`
89
- border: 2px solid ${theme.color.foreground.primary};
90
- background: ${theme.color.background.neutralBase};
91
- color: ${theme.color.foreground.neutralBase};
92
- `,
93
- activeDanger: css`
94
- border: 2px solid ${theme.color.foreground.danger};
95
- background: ${theme.color.background.neutralBase};
96
- color: ${theme.color.foreground.neutralBase};
97
- `,
98
- activeSuccess: css`
99
- border: 2px solid ${theme.color.foreground.success};
100
- background: ${theme.color.background.neutralBase};
101
- color: ${theme.color.foreground.neutralBase};
102
- `,
103
- }[color];
104
- };
105
-
106
- const SIZE_TO_STYLES = (size: InputBaseSize) =>
107
- ({
108
- small: css`
109
- padding-top: 8px;
110
- padding-bottom: 8px;
111
- width: 300px;
112
- height: 36px;
113
- `,
114
- medium: css`
115
- padding-top: 12px;
116
- padding-bottom: 12px;
117
- width: 375px;
118
- height: 48px;
119
- `,
120
- large: css`
121
- padding-top: 14px;
122
- padding-bottom: 14px;
123
- width: 375px;
124
- height: 56px;
125
- `,
126
- }[size]);
127
-
128
- export function InputBase(props: InputBaseProps): React.ReactElement {
129
- const {
130
- className,
131
- color,
132
- size,
133
- placeholder,
134
- disabled = false,
135
- startIcon,
136
- startLabel,
137
- endLabel,
138
- endIcon,
139
- inputProps,
140
- inputRef,
141
- fullWidth = false,
142
- onChange,
143
- onClear,
144
- defaultValue,
145
- value,
146
- } = props;
147
-
148
- return (
149
- <InputContainer
150
- className={className}
151
- disabled={disabled}
152
- color={color}
153
- inputSize={size}
154
- fullWidth={fullWidth}
155
- >
156
- {startIcon}
157
- {startLabel && <span>{startLabel}</span>}
158
- <StyledInput
159
- {...inputProps}
160
- ref={inputRef}
161
- onChange={onChange}
162
- placeholder={placeholder}
163
- disabled={disabled}
164
- defaultValue={defaultValue}
165
- value={value}
166
- />
167
- {endLabel && <span>{endLabel}</span>}
168
- {endIcon}
169
- {onClear && (
170
- <ClearButton onClick={onClear} disabled={disabled} tabIndex={-1}>
171
- <CloseCircleFillIcon />
172
- </ClearButton>
173
- )}
174
- </InputContainer>
175
- );
176
- }
177
-
178
- const InputContainer = styled.div<{
179
- color: InputBaseColor;
180
- inputSize: InputBaseSize;
181
- disabled: boolean;
182
- fullWidth: boolean;
183
- }>(
184
- ({ theme, color, inputSize, disabled, fullWidth }) => css`
185
- display: flex;
186
- align-items: center;
187
- gap: 16px;
188
-
189
- box-sizing: border-box;
190
- padding: 14px 16px;
191
- border-radius: 8px;
192
- ${COLOR_TO_INPUT_STYLES(theme, color, disabled)}
193
- ${SIZE_TO_STYLES(inputSize)}
194
- ${fullWidth && `width: inherit;`} // InputWrapper의 width를 따릅니다.
195
- `
196
- );
197
-
198
- const StyledInput = styled.input(
199
- ({ theme }) => css`
200
- appearance: none;
201
- flex: 1;
202
- min-width: 0;
203
- border: none;
204
- padding: 0;
205
- background-color: transparent;
206
- font: inherit;
207
- color: currentColor;
208
-
209
- &:focus-visible {
210
- outline: none;
211
- }
212
- &::placeholder {
213
- color: ${theme.color.foreground.neutralBaseDisabled};
214
- }
215
- `
216
- );
217
-
218
- const ClearButton = styled.button`
219
- ${RESET_BUTTON}
220
- color: currentColor;
221
- &:not(:disabled) {
222
- cursor: pointer;
223
- }
224
- display: flex;
225
- align-items: center;
226
- `;
@@ -1,99 +0,0 @@
1
- /** @jsxImportSource @emotion/react */
2
- import { css } from "@emotion/react";
3
- import * as React from "react";
4
- import styled from "@emotion/styled";
5
- import { Pagination as MuiPagination } from "@mui/material";
6
- import { HOVER } from "../utils/hover";
7
-
8
- export interface PaginationProps {
9
- className?: string;
10
- // component: React.ElementType; // 불필요한 dom 중첩을 막기 위해 사용하지 않습니다.
11
- /** 시작과 끝에 오는 페이지의 수 */
12
- boundaryCount?: number;
13
- /** 전체 페이지의 수 */
14
- count?: number;
15
- /** 기본 페이지 (UnControlled) */
16
- defaultPage?: number;
17
- /** 비활성화 여부 */
18
- disabled?: boolean;
19
- /** 다음 페이지로 이동하는 버튼 숨김여부 */
20
- hideNextButton?: boolean;
21
- /** 이전 페이지로 이동하는 버튼 숨김여부 */
22
- hidePrevButton?: boolean;
23
- /** 페이지가 변경되었을 때 콜백함수 */
24
- onChange?: (event: React.ChangeEvent<unknown>, page: number) => void;
25
- /** 현재 페이지 전후로 나타나는 페이지의 수 */
26
- siblingCount?: number;
27
- /** 현재 페이지 */
28
- page: number;
29
- }
30
-
31
- /**
32
- * [피그마](https://www.figma.com/file/yhrRFizzmhPoHdw9FbYow2/Codle-PD-Kit---Components?type=design&node-id=35-798&t=6OdVgm0hiYaq5PFw-0)
33
- */
34
- const Pagination = React.forwardRef<any, PaginationProps>(
35
- (props, ref): React.ReactElement => (
36
- <StyledPagination siblingCount={2} shape="rounded" {...props} ref={ref} />
37
- ));
38
-
39
- const StyledPagination = styled(MuiPagination)(
40
- ({ theme }) => css`
41
- &.MuiPagination-root {
42
- & .MuiPagination-ul {
43
- li {
44
- width: 32px;
45
- height: 32px;
46
- margin-left: 4px;
47
- margin-right: 4px;
48
- button {
49
- padding: 0;
50
- margin: 0;
51
- }
52
- }
53
- }
54
- & .MuiPaginationItem-root {
55
- ${HOVER(css`
56
- background-color: ${theme.color.background.neutralAlt};
57
- `)}
58
- }
59
- & .MuiPaginationItem-text {
60
- display: flex;
61
- flex-direction: column;
62
- align-items: center;
63
- text-align: center;
64
- border-radius: 8px;
65
- color: ${theme.color.foreground.neutralBase};
66
- font-weight: 400;
67
- font-size: 14px;
68
- line-height: 24px;
69
- padding: 1px 7px;
70
- margin: 0;
71
- }
72
- & .Mui-selected {
73
- border: 2px solid ${theme.color.background.primary};
74
- background-color: transparent;
75
- color: ${theme.color.background.primary};
76
- font-weight: 700;
77
- ${HOVER(css`
78
- background-color: transparent;
79
- `)}
80
- }
81
- & .Mui-disabled {
82
- background-color: transparent;
83
- color: ${theme.color.foreground.neutralBaseDisabled};
84
- }
85
- & .Mui-disabled.Mui-selected {
86
- border: 2px solid ${theme.color.background.primaryDisabled};
87
- background-color: transparent;
88
- color: ${theme.color.background.primaryDisabled};
89
- }
90
- & .MuiPaginationItem-ellipsis {
91
- ${HOVER(css`
92
- background-color: transparent;
93
- `)}
94
- }
95
- }
96
- `
97
- );
98
-
99
- export default Pagination;
@@ -1,322 +0,0 @@
1
- /** @jsxImportSource @emotion/react */
2
- import { Theme, css } from "@emotion/react";
3
- import styled from "@emotion/styled";
4
- import React, { useRef, useState } from "react";
5
- import { InputBase } from "./InputBase";
6
-
7
- export type PinInputColor =
8
- | "default"
9
- | "activePrimary"
10
- | "activeDanger"
11
- | "activeSuccess";
12
-
13
- export type PinInputSize = "large" | "medium" | "small";
14
-
15
- export interface PinInputProps {
16
- className?: string;
17
- // component?: React.ElementType; Input은 component를 받지 않습니다.
18
-
19
- /** `true` 값일 때 첫번째 Input에 자동으로 포커싱합니다. */
20
- autoFocus?: boolean;
21
-
22
- /** 컴포넌트 크기 */
23
- size: PinInputSize;
24
-
25
- /** 입력되기 전 PinInput 컴포넌트에 노출될 문자열 */
26
- placeholder?: string;
27
-
28
- /** Input 컴포넌트 상단에 노출될 문자열 */
29
- label?: string;
30
-
31
- /** Input 컴포넌트 하단에 노출될 문자열 */
32
- hintText?: string;
33
-
34
- /** hint 영역 좌측에 노출될 아이콘 */
35
- hintIcon?: React.ReactNode;
36
-
37
- /** 비활성화 여부 */
38
- disabled?: boolean;
39
-
40
- /** 에러 상태 여부 */
41
- error?: boolean;
42
-
43
- /** 성공 상태 여부 */
44
- positive?: boolean;
45
-
46
- /** 값이 변경될때 호출될 콜백 함수 */
47
- onChange: (e: {
48
- values: string[];
49
- event: React.ChangeEvent<HTMLInputElement>;
50
- }) => void;
51
-
52
- /** PinInput의 value (Controlled Component) */
53
- values: string[];
54
- }
55
-
56
- const SIZE_TO_STYLES = (size: PinInputSize) =>
57
- ({
58
- small: css`
59
- width: 36px;
60
- `,
61
- medium: css`
62
- width: 48px;
63
- `,
64
- large: css`
65
- width: 56px;
66
- `,
67
- }[size]);
68
-
69
- const COLOR_TO_HINT_STYLES = (
70
- theme: Theme,
71
- color: PinInputColor,
72
- disabled: boolean
73
- ) =>
74
- disabled
75
- ? css`
76
- color: ${theme.color.foreground.neutralBaseDisabled};
77
- `
78
- : {
79
- default: css`
80
- color: ${theme.color.foreground.neutralBaseDisabled};
81
- `,
82
- activePrimary: css`
83
- color: ${theme.color.foreground.neutralBaseDisabled};
84
- `,
85
- activeDanger: css`
86
- color: ${theme.color.foreground.danger};
87
- `,
88
- activeSuccess: css`
89
- color: ${theme.color.foreground.success};
90
- `,
91
- }[color];
92
-
93
- const SIZE_TO_FONT_STYLES = (size: PinInputSize) =>
94
- ({
95
- small: css`
96
- font-size: 14px;
97
- line-height: 20px;
98
- svg {
99
- width: 16px;
100
- height: 16px;
101
- }
102
- `,
103
- medium: css`
104
- font-size: 16px;
105
- line-height: 24px;
106
- svg {
107
- width: 16px;
108
- height: 16px;
109
- }
110
- `,
111
- large: css`
112
- font-size: 18px;
113
- line-height: 28px;
114
- svg {
115
- width: 18px;
116
- height: 18px;
117
- }
118
- `,
119
- }[size]);
120
-
121
- /** i번째 값을 value로 바꾸는 setState Wrapper 함수 */
122
- function updateFocus(
123
- value: boolean,
124
- i: number,
125
- setFocus: React.Dispatch<React.SetStateAction<boolean[]>>
126
- ) {
127
- setFocus((prevFocus) => {
128
- const newFocus = prevFocus.slice();
129
- newFocus[i] = value;
130
- return newFocus;
131
- });
132
- }
133
-
134
- /**
135
- * [피그마](https://www.figma.com/file/yhrRFizzmhPoHdw9FbYow2/Codle-PD-Kit---Components?type=design&node-id=26-11031&t=n7a8XP4k8R2TGmiO-0)
136
- */
137
- const PinInput = React.forwardRef<any, PinInputProps>(
138
- (props, ref): React.ReactElement => {
139
- const {
140
- className,
141
- autoFocus,
142
- size,
143
- placeholder,
144
- label,
145
- hintText,
146
- hintIcon,
147
- disabled = false,
148
- error,
149
- positive,
150
- onChange,
151
- values,
152
- ...other
153
- } = props;
154
-
155
- return (
156
- <PinInputWrapper className={className} size={size} ref={ref} {...other}>
157
- {label ? (
158
- <Label disabled={disabled}>
159
- {label} <PinInputComponent {...props} />
160
- </Label>
161
- ) : (
162
- <PinInputComponent {...props} />
163
- )}
164
- {hintText && (
165
- <Hint
166
- color={
167
- error ? "activeDanger" : positive ? "activeSuccess" : "default"
168
- }
169
- disabled={disabled}
170
- >
171
- {hintIcon}
172
- {hintText}
173
- </Hint>
174
- )}
175
- </PinInputWrapper>
176
- );
177
- }
178
- );
179
-
180
- function PinInputComponent(props: PinInputProps) {
181
- const {
182
- autoFocus,
183
- size,
184
- placeholder,
185
- disabled = false,
186
- error,
187
- positive,
188
- onChange,
189
- values,
190
- } = props;
191
-
192
- const [focus, setFocus] = useState<boolean[]>([]);
193
- const refs = useRef<(HTMLInputElement | null)[]>([]);
194
-
195
- return (
196
- <PinInputContainer>
197
- {values.map((value, i) => (
198
- <SqaureInput
199
- key={i}
200
- color={
201
- error
202
- ? "activeDanger"
203
- : positive
204
- ? "activeSuccess"
205
- : focus[i]
206
- ? "activePrimary"
207
- : "default"
208
- }
209
- inputRef={(element) => {
210
- refs.current[i] = element;
211
- }}
212
- onChange={(event) => {
213
- const eventValue = event.target.value;
214
-
215
- if (eventValue.length > 2) {
216
- // 복붙으로 입력을 입력한 경우
217
- if (
218
- eventValue.length === values.length &&
219
- eventValue.match(/^[0-9]+$/)
220
- ) {
221
- onChange({ values: eventValue.split(""), event });
222
- }
223
- return;
224
- }
225
-
226
- // 값을 지웠을 때
227
- if (eventValue === "") {
228
- const newValues = values.slice();
229
- newValues[i] = "";
230
- onChange({ values: newValues, event });
231
- return;
232
- }
233
-
234
- // 원래 값이 있었고, 새 값을 입력했을 때
235
- // 입력 완료된 값(2자리)으로부터 새로 입력한 숫자를 추출한다.
236
- const currentValue = values[i];
237
- let newValue = eventValue;
238
- if (currentValue[0] === eventValue[0]) {
239
- // 예) 이전 값: '2', 입력된 상태: '23' 인 경우
240
- newValue = eventValue[1]; // 뒷 자리가 새로 입력된 숫자
241
- } else if (currentValue[0] === eventValue[1]) {
242
- // 예) 이전 값: '2', 입력된 상태: '32' 인 경우
243
- newValue = eventValue[0]; // 앞 자리가 새로 입력된 숫자
244
- }
245
-
246
- // 새로 입력된 값이 숫자일때만 onChange를 실행
247
- if (newValue.match(/^[0-9]$/)) {
248
- const newValues = values.slice();
249
- newValues[i] = newValue;
250
- onChange({ values: newValues, event });
251
- // 자동으로 다음 input으로 포커스 이동시킴.
252
- if (i < values.length - 1) {
253
- refs.current[i + 1]?.focus();
254
- }
255
- }
256
- }}
257
- placeholder={focus[i] ? "" : placeholder}
258
- disabled={disabled}
259
- size={size}
260
- inputProps={{
261
- autoFocus: autoFocus ? i === 0 : false,
262
- onBlur: () => updateFocus(false, i, setFocus),
263
- onFocus: () => updateFocus(true, i, setFocus),
264
- onKeyDown: (e) => {
265
- // Backspace 키로 이전 input으로의 포커스 이동
266
- if (e.key === "Backspace" && values[i] === "" && i > 0) {
267
- refs.current[i - 1]?.focus();
268
- }
269
- },
270
- }}
271
- fullWidth={true}
272
- value={value}
273
- />
274
- ))}
275
- </PinInputContainer>
276
- );
277
- }
278
-
279
- const PinInputWrapper = styled.span<{ size: PinInputSize }>`
280
- display: inline-flex;
281
- flex-direction: column;
282
- gap: 8px;
283
- ${({ size }) => SIZE_TO_FONT_STYLES(size)}
284
- `;
285
-
286
- const PinInputContainer = styled.span`
287
- display: inline-flex;
288
- gap: 8px;
289
- `;
290
-
291
- const SqaureInput = styled(InputBase)<{ size: PinInputSize }>`
292
- ${({ size }) => SIZE_TO_STYLES(size)}
293
- padding: 0;
294
- input {
295
- text-align: center;
296
- }
297
- `;
298
-
299
- const Hint = styled.div<{
300
- color: PinInputColor;
301
- disabled: boolean;
302
- }>(
303
- ({ theme, color, disabled }) => css`
304
- display: flex;
305
- align-items: center;
306
- gap: 4px;
307
- ${COLOR_TO_HINT_STYLES(theme, color, disabled)};
308
- `
309
- );
310
-
311
- const Label = styled.label<{ disabled: boolean }>`
312
- display: flex;
313
- flex-direction: column;
314
- gap: 8px;
315
- ${({ theme, disabled }) =>
316
- disabled &&
317
- css`
318
- color: ${theme.color.foreground.neutralBaseDisabled};
319
- `}
320
- `;
321
-
322
- export default PinInput;