@uniai-fe/uds-primitives 0.0.13 → 0.0.15

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.
package/dist/styles.css CHANGED
@@ -721,14 +721,18 @@
721
721
  --font-body-medium-line-height: 1.5em;
722
722
  --font-body-medium-letter-spacing: 0px;
723
723
  --font-body-medium-weight: 500;
724
- --font-body-small-size: 15px;
724
+ --font-body-small-size: 16px;
725
725
  --font-body-small-line-height: 1.5em;
726
726
  --font-body-small-letter-spacing: 0px;
727
727
  --font-body-small-weight: 400;
728
- --font-body-xsmall-size: 13px;
728
+ --font-body-xsmall-size: 15px;
729
729
  --font-body-xsmall-line-height: 1.5em;
730
730
  --font-body-xsmall-letter-spacing: 0px;
731
731
  --font-body-xsmall-weight: 400;
732
+ --font-body-xxsmall-size: 13px;
733
+ --font-body-xxsmall-line-height: 1.5em;
734
+ --font-body-xxsmall-letter-spacing: 0px;
735
+ --font-body-xxsmall-weight: 400;
732
736
  }
733
737
  }
734
738
  @layer theme.tokens.typography {
@@ -1928,271 +1932,6 @@ figure.chip {
1928
1932
  height: 100%;
1929
1933
  }
1930
1934
 
1931
- :where(.radix-themes, .theme-root, :root) {
1932
- /* dialog essentials */
1933
- --dialog-overlay-bg: rgba(5, 6, 12, 0.55);
1934
- --dialog-panel-width: 360px;
1935
- --dialog-panel-max-width: calc(100vw - var(--spacing-padding-10) * 2);
1936
- --dialog-panel-bg: var(--color-bg-surface-static-white);
1937
- --dialog-panel-radius: var(--theme-radius-large-1);
1938
- --dialog-panel-shadow: 0px 18px 40px rgba(8, 11, 30, 0.18);
1939
- --dialog-border-color: var(--color-border-standard-cool-gray);
1940
- --dialog-title-color: var(--color-label-strong);
1941
- --dialog-title-font-size: var(--font-heading-xsmall-size);
1942
- --dialog-title-line-height: var(--font-heading-xsmall-line-height);
1943
- --dialog-title-weight: var(--font-heading-xsmall-weight);
1944
- --dialog-body-color: var(--color-label-standard);
1945
- --dialog-body-font-size: var(--font-body-small-size);
1946
- --dialog-body-line-height: var(--font-body-small-line-height);
1947
- --dialog-description-color: var(--color-label-standard);
1948
- --dialog-description-font-size: var(--font-body-small-size);
1949
- --dialog-description-line-height: var(--font-body-small-line-height);
1950
- /* alert(notice) defaults */
1951
- --notice-dialog-section-padding-x: var(--spacing-padding-8);
1952
- --notice-dialog-section-padding-y: var(--spacing-padding-10);
1953
- --notice-dialog-action-height: 52px;
1954
- /* confirm defaults */
1955
- --confirm-dialog-header-padding-x: var(--spacing-padding-6);
1956
- --confirm-dialog-header-padding-y: var(--spacing-padding-7);
1957
- --confirm-dialog-body-padding-x: var(--spacing-padding-6);
1958
- --confirm-dialog-body-padding-y: var(--spacing-padding-7);
1959
- --confirm-dialog-footer-padding-x: var(--spacing-padding-6);
1960
- --confirm-dialog-footer-padding-y: var(--spacing-padding-7);
1961
- --confirm-dialog-actions-gap: var(--spacing-gap-5);
1962
- }
1963
-
1964
- .dialog-overlay {
1965
- position: fixed;
1966
- inset: 0;
1967
- background-color: var(--dialog-overlay-bg);
1968
- opacity: 0;
1969
- transition: opacity 0.2s ease;
1970
- will-change: opacity;
1971
- }
1972
- .dialog-overlay[data-state=open] {
1973
- opacity: 1;
1974
- }
1975
- .dialog-overlay[data-state=closed] {
1976
- opacity: 0;
1977
- pointer-events: none;
1978
- }
1979
-
1980
- @media (prefers-reduced-motion: reduce) {
1981
- .dialog-overlay {
1982
- transition: none;
1983
- }
1984
- }
1985
- .dialog-content {
1986
- position: fixed;
1987
- top: 50%;
1988
- left: 50%;
1989
- transform: translate(-50%, -50%);
1990
- width: min(var(--dialog-panel-width), var(--dialog-panel-max-width));
1991
- max-width: var(--dialog-panel-max-width);
1992
- max-height: calc(100vh - var(--spacing-padding-10) * 2);
1993
- background-color: var(--dialog-panel-bg);
1994
- border-radius: var(--dialog-panel-radius);
1995
- box-shadow: var(--dialog-panel-shadow);
1996
- display: flex;
1997
- flex-direction: column;
1998
- overflow: hidden;
1999
- overflow-y: auto;
2000
- overscroll-behavior: contain;
2001
- outline: none;
2002
- border: none;
2003
- gap: 0;
2004
- opacity: 0;
2005
- transition: opacity 0.2s ease, transform 0.2s ease;
2006
- }
2007
- .dialog-content[data-state=open] {
2008
- opacity: 1;
2009
- transform: translate(-50%, -50%);
2010
- }
2011
- .dialog-content[data-state=closed] {
2012
- opacity: 0;
2013
- transform: translate(-50%, calc(-50% + 12px));
2014
- pointer-events: none;
2015
- }
2016
-
2017
- @media (prefers-reduced-motion: reduce) {
2018
- .dialog-content {
2019
- transition: none;
2020
- }
2021
- }
2022
- .dialog-section {
2023
- padding: 0;
2024
- }
2025
- .dialog-section[data-section=actions] {
2026
- flex-shrink: 0;
2027
- }
2028
-
2029
- .dialog-title {
2030
- margin: 0;
2031
- color: var(--dialog-title-color);
2032
- font-size: var(--dialog-title-font-size);
2033
- line-height: var(--dialog-title-line-height);
2034
- font-weight: var(--dialog-title-weight);
2035
- }
2036
-
2037
- .dialog-description {
2038
- margin: 0;
2039
- color: var(--dialog-description-color);
2040
- font-size: var(--dialog-description-font-size);
2041
- line-height: var(--dialog-description-line-height);
2042
- }
2043
-
2044
- .dialog-button {
2045
- display: flex;
2046
- align-items: center;
2047
- justify-content: center;
2048
- width: 100%;
2049
- border: none;
2050
- border-radius: 0;
2051
- margin: 0;
2052
- padding: 0;
2053
- font-size: var(--font-body-medium-size);
2054
- line-height: var(--font-body-medium-line-height);
2055
- font-weight: var(--font-body-medium-weight);
2056
- cursor: pointer;
2057
- background: transparent;
2058
- color: var(--color-label-strong);
2059
- transition: background-color 0.15s ease, color 0.15s ease;
2060
- }
2061
-
2062
- .dialog-button[data-native-element=true] {
2063
- appearance: none;
2064
- }
2065
-
2066
- .notice-dialog-header,
2067
- .notice-dialog-body {
2068
- padding: var(--notice-dialog-section-padding-y) var(--notice-dialog-section-padding-x);
2069
- }
2070
-
2071
- .notice-dialog-header {
2072
- display: flex;
2073
- flex-direction: column;
2074
- gap: var(--spacing-gap-3);
2075
- text-align: center;
2076
- }
2077
-
2078
- .notice-dialog-body {
2079
- text-align: center;
2080
- }
2081
-
2082
- .notice-dialog-body p {
2083
- margin: 0 0 var(--spacing-gap-2);
2084
- color: var(--dialog-body-color);
2085
- font-size: var(--dialog-body-font-size);
2086
- line-height: 1.5em;
2087
- font-weight: var(--font-body-small-weight);
2088
- word-break: keep-all;
2089
- }
2090
-
2091
- .notice-dialog-body p:last-child {
2092
- margin-bottom: 0;
2093
- }
2094
-
2095
- .notice-dialog-actions {
2096
- border-top: 1px solid var(--dialog-border-color);
2097
- display: flex;
2098
- align-items: stretch;
2099
- flex-direction: row;
2100
- padding: 0;
2101
- gap: 0;
2102
- justify-content: center;
2103
- overflow: hidden;
2104
- --button-min-height: var(--notice-dialog-action-height);
2105
- --button-padding-inline: 0;
2106
- --button-padding-block: 0;
2107
- --button-border-radius: 0;
2108
- }
2109
-
2110
- .notice-dialog-actions > * {
2111
- flex: 1;
2112
- }
2113
-
2114
- .notice-dialog-actions .button {
2115
- display: flex;
2116
- align-items: center;
2117
- justify-content: center;
2118
- width: 100%;
2119
- border: none;
2120
- border-radius: 0;
2121
- margin: 0;
2122
- padding: 0;
2123
- font-size: var(--font-body-medium-size);
2124
- line-height: var(--font-body-medium-line-height);
2125
- font-weight: var(--font-body-medium-weight);
2126
- cursor: pointer;
2127
- background: transparent;
2128
- color: var(--color-label-strong);
2129
- transition: background-color 0.15s ease, color 0.15s ease;
2130
- background-color: var(--color-common-100);
2131
- color: var(--color-primary-default);
2132
- }
2133
- .notice-dialog-actions .button:hover {
2134
- background-color: var(--color-bg-surface-static-cool-gray);
2135
- }
2136
-
2137
- .notice-dialog-actions .button:not(:first-child),
2138
- .notice-dialog-actions [data-native-element=true]:not(:first-child) {
2139
- border-left: 1px solid var(--dialog-border-color);
2140
- }
2141
-
2142
- .confirm-dialog-header {
2143
- padding: var(--confirm-dialog-header-padding-y) var(--confirm-dialog-header-padding-x);
2144
- }
2145
-
2146
- .confirm-dialog-body {
2147
- padding: var(--confirm-dialog-body-padding-y) var(--confirm-dialog-body-padding-x);
2148
- }
2149
-
2150
- .confirm-dialog-header {
2151
- display: flex;
2152
- flex-direction: column;
2153
- gap: var(--spacing-gap-2);
2154
- text-align: center;
2155
- }
2156
-
2157
- .confirm-dialog-body {
2158
- display: flex;
2159
- flex-direction: column;
2160
- align-items: center;
2161
- gap: var(--spacing-gap-2);
2162
- text-align: center;
2163
- }
2164
-
2165
- .confirm-dialog-body p {
2166
- margin: 0;
2167
- color: var(--dialog-body-color);
2168
- font-size: var(--dialog-body-font-size);
2169
- line-height: 1.5em;
2170
- font-weight: var(--font-body-small-weight);
2171
- word-break: keep-all;
2172
- }
2173
-
2174
- .confirm-dialog-description {
2175
- margin: 0;
2176
- color: var(--dialog-body-color);
2177
- font-size: var(--dialog-body-font-size);
2178
- line-height: 1.5em;
2179
- font-weight: var(--font-body-small-weight);
2180
- word-break: keep-all;
2181
- }
2182
-
2183
- .confirm-dialog-actions {
2184
- display: flex;
2185
- align-items: stretch;
2186
- flex-direction: row;
2187
- padding: var(--confirm-dialog-footer-padding-y) var(--confirm-dialog-footer-padding-x);
2188
- gap: var(--confirm-dialog-actions-gap);
2189
- justify-content: center;
2190
- }
2191
-
2192
- .confirm-dialog-actions > * {
2193
- flex: 1;
2194
- }
2195
-
2196
1935
  :where(.radix-themes, .theme-root, :root) {
2197
1936
  --drawer-overlay-bg: rgba(0, 0, 0, 0.44);
2198
1937
  --drawer-surface-bg: var(--color-bg-surface-static-white);
@@ -2734,6 +2473,18 @@ figure.chip {
2734
2473
  color: var(--theme-input-helper-color);
2735
2474
  }
2736
2475
 
2476
+ .email-verification {
2477
+ display: flex;
2478
+ flex-direction: column;
2479
+ gap: var(--spacing-gap-4);
2480
+ }
2481
+
2482
+ .email-verification__countdown {
2483
+ font-size: var(--font-caption-medium-size);
2484
+ line-height: var(--font-caption-medium-line-height);
2485
+ color: var(--theme-input-helper-color);
2486
+ }
2487
+
2737
2488
  /* TODO(label): 스타일을 SOT 토큰 값으로 정의한다. */
2738
2489
  :where(.radix-themes, .theme-root, :root) {
2739
2490
  --theme-navigation-height: 86px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniai-fe/uds-primitives",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "UNIAI Design System; Primitives Components Package",
5
5
  "type": "module",
6
6
  "private": false,
@@ -91,8 +91,8 @@
91
91
  "@uniai-fe/util-functions": "workspace:*",
92
92
  "eslint": "^9.39.2",
93
93
  "prettier": "^3.7.4",
94
- "react-hook-form": "^7.68.0",
95
- "sass": "^1.97.0",
94
+ "react-hook-form": "^7.69.0",
95
+ "sass": "^1.97.1",
96
96
  "typescript": "~5.9.3"
97
97
  }
98
98
  }
@@ -79,9 +79,9 @@ const Text = forwardRef<HTMLInputElement, InputProps>(
79
79
  block = false,
80
80
  left,
81
81
  right,
82
- clearIcon,
83
- successIcon,
84
- errorIcon,
82
+ clear,
83
+ success,
84
+ error,
85
85
  label,
86
86
  helper,
87
87
  hideHelper,
@@ -167,13 +167,13 @@ const Text = forwardRef<HTMLInputElement, InputProps>(
167
167
 
168
168
  const statusSlot = useMemo(() => {
169
169
  if (resolvedState === "success") {
170
- return successIcon ?? defaultStatusIcon;
170
+ return success ?? defaultStatusIcon;
171
171
  }
172
172
  if (resolvedState === "error") {
173
- return errorIcon ?? defaultStatusIcon;
173
+ return error ?? defaultStatusIcon;
174
174
  }
175
175
  return null;
176
- }, [defaultStatusIcon, errorIcon, resolvedState, successIcon]);
176
+ }, [defaultStatusIcon, error, resolvedState, success]);
177
177
 
178
178
  const defaultClearIcon = useMemo(() => {
179
179
  if (visualState === "active") {
@@ -182,7 +182,7 @@ const Text = forwardRef<HTMLInputElement, InputProps>(
182
182
  return null;
183
183
  }, [visualState]);
184
184
 
185
- const effectiveClearIcon = clearIcon ?? defaultClearIcon;
185
+ const effectiveClearIcon = clear ?? defaultClearIcon;
186
186
  const showClearIcon = Boolean(
187
187
  effectiveClearIcon && hasValue && resolvedState !== "disabled",
188
188
  );
@@ -0,0 +1,144 @@
1
+ import type { ChangeEvent, ComponentPropsWithoutRef, ReactNode } from "react";
2
+ import { forwardRef, useCallback, useMemo } from "react";
3
+ import type { InputProps, InputState } from "../../types";
4
+ import { Text } from "./Base";
5
+ import { IdentificationInput } from "./Identification";
6
+
7
+ /**
8
+ * EmailVerificationInput props. 이메일 입력 + 인증 요청/코드 입력 옵션을 정의한다.
9
+ * @property {string} [value] 제어형 값.
10
+ * @property {string} [defaultValue] 비제어 초기값.
11
+ * @property {(value: string) => void} [onValueChange] 값 변경 시 호출.
12
+ * @property {ComponentPropsWithoutRef<"input">["onChange"]} [onChange] native onChange override.
13
+ * @property {() => void} [onRequestCode] 인증 요청 버튼 클릭 시 호출(optional).
14
+ * @property {string} [requestButtonLabel="인증번호 요청"] 인증 요청 버튼 라벨(optional).
15
+ * @property {boolean} [requestButtonDisabled] 인증 요청 버튼 disabled(optional).
16
+ * @property {ReactNode} [countdownText] 인증 제한 시간 안내 텍스트(optional).
17
+ * @property {boolean} [codeVisible] 인증번호 입력 UI 노출 여부(optional).
18
+ * @property {number} [codeLength=6] 인증번호 길이(optional).
19
+ * @property {ReactNode} [codeLabel] 인증번호 입력 label(optional).
20
+ * @property {ReactNode} [codeHelper] 인증번호 helper(optional).
21
+ * @property {InputState} [codeState] 인증번호 입력 상태(optional).
22
+ * @property {(code: string) => void} [onCodeComplete] 인증번호 입력 완료 시 호출(optional).
23
+ */
24
+ export interface EmailVerificationInputProps extends Omit<
25
+ InputProps,
26
+ "type" | "inputMode" | "pattern" | "onChange" | "value" | "defaultValue"
27
+ > {
28
+ value?: string;
29
+ defaultValue?: string;
30
+ onValueChange?: (value: string) => void;
31
+ onChange?: ComponentPropsWithoutRef<"input">["onChange"];
32
+ onRequestCode?: () => void;
33
+ requestButtonLabel?: string;
34
+ requestButtonDisabled?: boolean;
35
+ countdownText?: ReactNode;
36
+ codeVisible?: boolean;
37
+ codeLength?: number;
38
+ codeLabel?: ReactNode;
39
+ codeHelper?: ReactNode;
40
+ codeState?: InputState;
41
+ onCodeComplete?: (code: string) => void;
42
+ }
43
+
44
+ /**
45
+ * 이메일 인증 입력 컴포넌트; 이메일 입력 + 인증요청 버튼 + OneTimeCode 입력을 옵션으로 제공한다.
46
+ * @component
47
+ * @param {EmailVerificationInputProps} props 이메일 인증 props
48
+ * @param {string} [props.value] 제어형 이메일 값
49
+ * @param {string} [props.defaultValue] 비제어 이메일 초기값
50
+ * @param {(value: string) => void} [props.onValueChange] 이메일 변경 콜백
51
+ * @param {ComponentPropsWithoutRef<"input">["onChange"]} [props.onChange] native onChange override
52
+ * @param {() => void} [props.onRequestCode] 인증요청 버튼 클릭 시 호출
53
+ * @param {string} [props.requestButtonLabel] 인증요청 버튼 라벨
54
+ * @param {boolean} [props.requestButtonDisabled] 인증요청 버튼 disabled
55
+ * @param {ReactNode} [props.countdownText] 제한 시간 안내 텍스트
56
+ * @param {boolean} [props.codeVisible] 인증번호 입력 UI 노출 여부
57
+ * @param {number} [props.codeLength] 인증번호 길이
58
+ * @param {ReactNode} [props.codeLabel] 인증번호 label
59
+ * @param {ReactNode} [props.codeHelper] 인증번호 helper
60
+ * @param {InputState} [props.codeState] 인증번호 입력 상태
61
+ * @param {(code: string) => void} [props.onCodeComplete] 인증번호 입력 완료 시 호출
62
+ */
63
+ const EmailVerificationInput = forwardRef<
64
+ HTMLInputElement,
65
+ EmailVerificationInputProps
66
+ >(
67
+ (
68
+ {
69
+ value,
70
+ defaultValue,
71
+ onValueChange,
72
+ onChange,
73
+ onRequestCode,
74
+ requestButtonLabel = "인증번호 요청",
75
+ requestButtonDisabled,
76
+ countdownText,
77
+ codeVisible,
78
+ codeLength = 6,
79
+ codeLabel,
80
+ codeHelper,
81
+ codeState,
82
+ onCodeComplete,
83
+ right,
84
+ ...restProps
85
+ },
86
+ forwardedRef,
87
+ ) => {
88
+ const handleChange = useCallback(
89
+ (event: ChangeEvent<HTMLInputElement>) => {
90
+ onValueChange?.(event.currentTarget.value);
91
+ onChange?.(event);
92
+ },
93
+ [onChange, onValueChange],
94
+ );
95
+
96
+ const actionButton = useMemo(() => {
97
+ if (!onRequestCode) {
98
+ return null;
99
+ }
100
+
101
+ return (
102
+ <button
103
+ type="button"
104
+ className="input-action-button"
105
+ onClick={onRequestCode}
106
+ disabled={requestButtonDisabled}
107
+ >
108
+ {requestButtonLabel}
109
+ </button>
110
+ );
111
+ }, [onRequestCode, requestButtonDisabled, requestButtonLabel]);
112
+
113
+ return (
114
+ <div className="email-verification">
115
+ <Text
116
+ {...restProps}
117
+ ref={forwardedRef}
118
+ type="email"
119
+ inputMode="email"
120
+ value={value}
121
+ defaultValue={defaultValue}
122
+ onChange={handleChange}
123
+ right={right ?? actionButton}
124
+ />
125
+ {countdownText ? (
126
+ <div className="email-verification__countdown">{countdownText}</div>
127
+ ) : null}
128
+ {codeVisible ? (
129
+ <IdentificationInput
130
+ length={codeLength}
131
+ label={codeLabel}
132
+ helper={codeHelper}
133
+ state={codeState}
134
+ onComplete={onCodeComplete}
135
+ />
136
+ ) : null}
137
+ </div>
138
+ );
139
+ },
140
+ );
141
+
142
+ EmailVerificationInput.displayName = "EmailVerificationInput";
143
+
144
+ export { EmailVerificationInput };
@@ -10,9 +10,9 @@ import { Text } from "./Base";
10
10
  * @property {string} [defaultValue] 비제어 초기값(숫자/포맷 모두 허용).
11
11
  * @property {(value: string, digits: string) => void} [onValueChange] 포맷팅 값/숫자만 값을 함께 전달.
12
12
  * @property {ComponentPropsWithoutRef<"input">["onChange"]} [onChange] native onChange override.
13
- * @property {() => void} [onRequestCode] right 슬롯 버튼 클릭 시 호출.
14
- * @property {string} [requestButtonLabel="인증번호 요청"] right 슬롯 버튼 라벨.
15
- * @property {boolean} [requestButtonDisabled] right 슬롯 버튼 disabled 여부.
13
+ * @property {() => void} [onRequestCode] 인증 요청 버튼 클릭 시 호출(optional).
14
+ * @property {string} [requestButtonLabel="인증번호 요청"] 인증 요청 버튼 라벨(optional).
15
+ * @property {boolean} [requestButtonDisabled] 인증 요청 버튼 disabled(optional).
16
16
  */
17
17
  export interface PhoneInputProps extends Omit<
18
18
  InputProps,
@@ -35,10 +35,16 @@ const normalizeDigits = (value?: string) => (value ?? "").replace(/\D/g, "");
35
35
  const formatPhoneNumber = (digits: string) => maskPhone(digits);
36
36
 
37
37
  /**
38
- * PhoneInput — 휴대폰 번호 마스킹과 인증번호 요청 버튼을 제공하는 입력.
38
+ * 휴대폰 번호 입력 컴포넌트; 기본은 마스킹만 제공하고 인증 UI는 optional props로 노출한다.
39
39
  * @component
40
- * @param {PhoneInputProps} props Phone 전용 props.
41
- * 나머지 Text Input 공통 props(priority/size/state/helper 등)도 동일하게 사용할 수 있다.
40
+ * @param {PhoneInputProps} props 휴대폰 입력 props
41
+ * @param {string} [props.value] 제어형 포맷
42
+ * @param {string} [props.defaultValue] 비제어 초기값
43
+ * @param {(value: string, digits: string) => void} [props.onValueChange] 포맷/숫자 변경 콜백
44
+ * @param {ComponentPropsWithoutRef<"input">["onChange"]} [props.onChange] native onChange override
45
+ * @param {() => void} [props.onRequestCode] 인증 요청 버튼 클릭 시 호출
46
+ * @param {string} [props.requestButtonLabel] 인증 요청 버튼 라벨
47
+ * @param {boolean} [props.requestButtonDisabled] 인증 요청 버튼 disabled
42
48
  */
43
49
  const PhoneInput = forwardRef<HTMLInputElement, PhoneInputProps>(
44
50
  (
@@ -2,9 +2,11 @@ export { Text } from "./Base";
2
2
  export { Text as Input } from "./Base";
3
3
  export { PasswordInput } from "./Password";
4
4
  export { PhoneInput } from "./Phone";
5
+ export { EmailVerificationInput } from "./EmailVerification";
5
6
  export { SearchInput } from "./Search";
6
7
  export { IdentificationInput } from "./Identification";
7
8
  export type { InputPasswordProps } from "./Password";
8
9
  export type { PhoneInputProps } from "./Phone";
10
+ export type { EmailVerificationInputProps } from "./EmailVerification";
9
11
  export type { SearchInputProps } from "./Search";
10
12
  export type { IdentificationInputProps } from "./Identification";
@@ -373,3 +373,15 @@
373
373
  font-size: var(--font-label-small-size);
374
374
  color: var(--theme-input-helper-color);
375
375
  }
376
+
377
+ .email-verification {
378
+ display: flex;
379
+ flex-direction: column;
380
+ gap: var(--spacing-gap-4);
381
+ }
382
+
383
+ .email-verification__countdown {
384
+ font-size: var(--font-caption-medium-size);
385
+ line-height: var(--font-caption-medium-line-height);
386
+ color: var(--theme-input-helper-color);
387
+ }
@@ -30,12 +30,12 @@ type NativeInputProps = ComponentPropsWithoutRef<"input">;
30
30
  /**
31
31
  * 좌우 슬롯과 status 아이콘 정의.
32
32
  */
33
- export interface InputSlots {
33
+ export interface InputIcon {
34
34
  left?: ReactNode;
35
35
  right?: ReactNode;
36
- clearIcon?: ReactNode;
37
- successIcon?: ReactNode;
38
- errorIcon?: ReactNode;
36
+ clear?: ReactNode;
37
+ success?: ReactNode;
38
+ error?: ReactNode;
39
39
  }
40
40
 
41
41
  /**
@@ -51,7 +51,7 @@ export interface InputFeedback {
51
51
  * 텍스트 입력의 핵심 props. native input 속성에서 size는 제외하고 left/right 등 슬롯을 별도로 정의한다.
52
52
  */
53
53
  export interface InputProps
54
- extends Omit<NativeInputProps, "size">, InputSlots, InputFeedback {
54
+ extends Omit<NativeInputProps, "size">, InputIcon, InputFeedback {
55
55
  /** semantic color/token 세트 */
56
56
  priority?: InputPriority;
57
57
  /** 높이/타이포 세트 */
package/src/index.scss CHANGED
@@ -8,7 +8,6 @@
8
8
  @use "./components/calendar";
9
9
  @use "./components/checkbox";
10
10
  @use "./components/chip";
11
- @use "./components/dialog";
12
11
  @use "./components/drawer";
13
12
  @use "./components/dropdown";
14
13
  @use "./components/input";
package/src/index.tsx CHANGED
@@ -12,7 +12,6 @@ export * from "./components/radio";
12
12
  export * from "./components/select";
13
13
  export * from "./components/tab";
14
14
  export * from "./components/navigation";
15
- export * from "./components/dialog";
16
15
  export * from "./components/dropdown";
17
16
  export * from "./components/drawer";
18
17
  export * from "./components/scrollbar";
@@ -59,12 +59,12 @@ export interface InputFieldOptions {
59
59
  }
60
60
 
61
61
  /**
62
- * Input Field Config; attr + style + options + props
63
- * @interface InputFieldConfig
62
+ * Input Field Props; attr + style + options + control props
63
+ * @interface InputFieldProps
64
64
  * @template TProps
65
65
  * @template FieldElement
66
66
  */
67
- export interface InputFieldConfig<
67
+ export interface InputFieldProps<
68
68
  TProps extends InputProps = InputProps,
69
69
  FieldElement extends HTMLElement = HTMLInputElement,
70
70
  >