@petnow/ui 5.4.0 → 6.0.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.
@@ -2,37 +2,35 @@
2
2
  import { t as e } from "./TailwindUtil-DiNvXuNl.js";
3
3
  import { CTAButton as t } from "./cta-button.js";
4
4
  import { CancelFilledIcon as n } from "./icons/action/cancel-filled.js";
5
- import { ChevronLeftIcon as r } from "./icons/action/chevron-left.js";
6
- import { i, n as a } from "./fieldStyles-DyZu__hI.js";
7
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
8
- import * as c from "react";
9
- import { cva as l } from "class-variance-authority";
5
+ import { r, t as i } from "./fieldStyles-DXyDrzxD.js";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ import * as s from "react";
10
8
  //#region src/components/text-field/TextField.tsx
11
- var u = c.forwardRef(({ onChange: t, subtitle: r, isRequired: l = !1, assistiveText: u, errorText: d, disabled: f = !1, multiLine: p = !1, className: m, rightElement: h, showCounter: g = !1, value: _, maxLength: v, size: y = "large", ...b }, x) => {
12
- let S = !!d, C = c.useRef(null);
13
- c.useImperativeHandle(x, () => C.current);
14
- let w = c.useCallback(() => {
9
+ var c = s.forwardRef(({ onChange: t, subtitle: c, isRequired: l = !1, assistiveText: u, errorText: d, disabled: f = !1, multiLine: p = !1, className: m, rightElement: h, showCounter: g = !1, value: _, maxLength: v, size: y = "large", ...b }, x) => {
10
+ let S = !!d, C = s.useRef(null);
11
+ s.useImperativeHandle(x, () => C.current);
12
+ let w = s.useCallback(() => {
15
13
  C.current?.focus();
16
14
  }, []), T = (typeof _ == "string" ? _ : "").length, E = b, D = b, O = y === "large" ? "text-title-20-regular" : "text-body-16-regular", k = y === "large" ? "text-title-18-bold" : "text-title-14-bold", A = y === "large" ? "text-body-16-regular" : "text-caption-12-medium";
17
- return /* @__PURE__ */ s("div", {
15
+ return /* @__PURE__ */ o("div", {
18
16
  className: e("flex flex-col gap-2", m),
19
17
  children: [
20
- r && /* @__PURE__ */ s("span", {
18
+ c && /* @__PURE__ */ o("span", {
21
19
  className: e(k, "text-text-base-neutral-5"),
22
- children: [r, l && /* @__PURE__ */ o("span", {
20
+ children: [c, l && /* @__PURE__ */ a("span", {
23
21
  className: "text-text-prominent-accent-1",
24
22
  children: "*"
25
23
  })]
26
24
  }),
27
- /* @__PURE__ */ s("div", {
25
+ /* @__PURE__ */ o("div", {
28
26
  onClick: f ? void 0 : w,
29
- className: e("group overflow-hidden", a({
27
+ className: e("group overflow-hidden", i({
30
28
  size: y,
31
29
  disabled: f,
32
30
  hasError: S
33
31
  }), !f && !S && "focus-within:border-border-base-neutral-4", p && "h-[120px] items-start"),
34
32
  children: [
35
- p ? /* @__PURE__ */ o("textarea", {
33
+ p ? /* @__PURE__ */ a("textarea", {
36
34
  ...D,
37
35
  onChange: t,
38
36
  ref: C,
@@ -40,7 +38,7 @@ var u = c.forwardRef(({ onChange: t, subtitle: r, isRequired: l = !1, assistiveT
40
38
  maxLength: v,
41
39
  disabled: f,
42
40
  className: e("text-text-base-neutral-5 placeholder:text-text-base-neutral-2 h-full min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none", O, "resize-none overflow-y-auto")
43
- }) : /* @__PURE__ */ o("input", {
41
+ }) : /* @__PURE__ */ a("input", {
44
42
  ...E,
45
43
  onChange: t,
46
44
  ref: C,
@@ -49,11 +47,11 @@ var u = c.forwardRef(({ onChange: t, subtitle: r, isRequired: l = !1, assistiveT
49
47
  disabled: f,
50
48
  className: e("text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none", O, "overflow-hidden text-ellipsis whitespace-nowrap")
51
49
  }),
52
- h && /* @__PURE__ */ o("div", {
50
+ h && /* @__PURE__ */ a("div", {
53
51
  className: "shrink-0",
54
52
  children: h
55
53
  }),
56
- /* @__PURE__ */ o("button", {
54
+ /* @__PURE__ */ a("button", {
57
55
  type: "button",
58
56
  onClick: () => t && t({ target: { value: "" } }),
59
57
  tabIndex: -1,
@@ -62,20 +60,20 @@ var u = c.forwardRef(({ onChange: t, subtitle: r, isRequired: l = !1, assistiveT
62
60
  flex: S,
63
61
  "group-focus-within:flex": !f && T > 0
64
62
  }),
65
- children: /* @__PURE__ */ o(n, { className: "text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer" })
63
+ children: /* @__PURE__ */ a(n, { className: "text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer" })
66
64
  })
67
65
  ]
68
66
  }),
69
- (u || d || v && g) && /* @__PURE__ */ s("div", {
67
+ (u || d || v && g) && /* @__PURE__ */ o("div", {
70
68
  className: "flex items-center justify-between gap-2",
71
- children: [(u || d) && /* @__PURE__ */ o("span", {
72
- className: e(A, i({
69
+ children: [(u || d) && /* @__PURE__ */ a("span", {
70
+ className: e(A, r({
73
71
  size: y,
74
72
  hasError: S
75
73
  })),
76
74
  children: d || u
77
- }), v && g && /* @__PURE__ */ s("span", {
78
- className: e("ml-auto", A, i({
75
+ }), v && g && /* @__PURE__ */ o("span", {
76
+ className: e("ml-auto", A, r({
79
77
  size: y,
80
78
  hasError: S
81
79
  })),
@@ -89,131 +87,69 @@ var u = c.forwardRef(({ onChange: t, subtitle: r, isRequired: l = !1, assistiveT
89
87
  ]
90
88
  });
91
89
  });
92
- u.displayName = "TextFieldNormal";
93
- var d = l("flex items-center justify-between rounded-[4px] bg-surface-base-neutral-2 border transition-colors duration-200", {
94
- variants: {
95
- size: {
96
- large: "gap-2 p-[15px] min-h-[56px]",
97
- small: "gap-3 p-[11px] min-h-[48px]"
98
- },
99
- hasError: {
100
- true: "border-border-prominent-error",
101
- false: "border-transparent"
102
- },
103
- disabled: {
104
- true: "opacity-50",
105
- false: ""
106
- }
107
- },
108
- defaultVariants: { size: "large" }
109
- }), f = ({ label: t, placeholder: n, value: a, isRequired: c = !1, disabled: l = !1, assistiveText: u, errorText: f, onPress: p, className: m, size: h = "large" }) => {
110
- let g = !!f, _ = h === "large" ? "text-title-18-bold" : "text-title-14-bold", v = h === "large" ? "text-title-20-regular" : "text-body-16-regular";
111
- return /* @__PURE__ */ s("div", {
112
- className: e("flex w-full flex-col gap-2", m),
113
- children: [
114
- t && /* @__PURE__ */ s("div", {
115
- className: "flex items-start",
116
- children: [/* @__PURE__ */ o("span", {
117
- className: e(_, "text-text-base-neutral-5"),
118
- children: t
119
- }), c && /* @__PURE__ */ o("span", {
120
- className: e(_, "text-text-prominent-accent-1"),
121
- children: "*"
122
- })]
123
- }),
124
- /* @__PURE__ */ s("button", {
125
- type: "button",
126
- className: d({
127
- size: h,
128
- hasError: g,
129
- disabled: l
130
- }),
131
- onClick: p,
132
- disabled: l,
133
- children: [/* @__PURE__ */ o("span", {
134
- className: e(v, "flex-1", a ? "text-text-base-neutral-5" : "text-text-base-neutral-2"),
135
- style: {
136
- textAlign: "left",
137
- overflow: "hidden",
138
- textOverflow: "ellipsis"
139
- },
140
- children: a || n
141
- }), /* @__PURE__ */ o(r, { className: "text-icon-base-neutral-3 rotate-270" })]
142
- }),
143
- (u || f) && /* @__PURE__ */ o("div", {
144
- className: "flex items-start gap-2",
145
- children: /* @__PURE__ */ o("span", {
146
- className: i({
147
- size: h,
148
- hasError: g
149
- }),
150
- children: f || u
151
- })
152
- })
153
- ]
154
- });
155
- }, p = c.forwardRef(({ onChange: r, subtitle: l, isRequired: u = !1, assistiveText: d, errorText: f, disabled: p = !1, multiLine: m = !1, className: h, showCounter: g = !1, value: _, maxLength: v, size: y = "large", fieldRightElement: b, buttonText: x, onButtonClick: S, buttonDisabled: C = !1, ...w }, T) => {
156
- let E = !!f, D = c.useRef(null);
157
- c.useImperativeHandle(T, () => D.current);
158
- let O = c.useCallback(() => {
90
+ c.displayName = "TextFieldNormal";
91
+ var l = s.forwardRef(({ onChange: c, subtitle: l, isRequired: u = !1, assistiveText: d, errorText: f, disabled: p = !1, multiLine: m = !1, className: h, showCounter: g = !1, value: _, maxLength: v, size: y = "large", fieldRightElement: b, buttonText: x, onButtonClick: S, buttonDisabled: C = !1, ...w }, T) => {
92
+ let E = !!f, D = s.useRef(null);
93
+ s.useImperativeHandle(T, () => D.current);
94
+ let O = s.useCallback(() => {
159
95
  D.current?.focus();
160
96
  }, []), k = (typeof _ == "string" ? _ : "").length, A = w, j = w, M = y === "large" ? "text-title-20-regular" : "text-body-16-regular", N = y === "large" ? "text-title-18-bold" : "text-title-14-bold", P = y === "large" ? "text-body-16-regular" : "text-caption-12-medium";
161
- return /* @__PURE__ */ s("div", {
97
+ return /* @__PURE__ */ o("div", {
162
98
  className: e("flex flex-col gap-2", h),
163
99
  children: [
164
- l && /* @__PURE__ */ s("span", {
100
+ l && /* @__PURE__ */ o("span", {
165
101
  className: e(N, "text-text-base-neutral-5"),
166
- children: [l, u && /* @__PURE__ */ o("span", {
102
+ children: [l, u && /* @__PURE__ */ a("span", {
167
103
  className: "text-text-prominent-accent-1",
168
104
  children: "*"
169
105
  })]
170
106
  }),
171
- /* @__PURE__ */ s("div", {
107
+ /* @__PURE__ */ o("div", {
172
108
  className: "flex items-center gap-2",
173
- children: [/* @__PURE__ */ s("div", {
109
+ children: [/* @__PURE__ */ o("div", {
174
110
  onClick: p ? void 0 : O,
175
- className: e("group flex-1 overflow-hidden", a({
111
+ className: e("group flex-1 overflow-hidden", i({
176
112
  size: y,
177
113
  disabled: p,
178
114
  hasError: E
179
115
  }), !p && !E && "focus-within:border-border-base-neutral-4", m && "h-[120px] items-start"),
180
116
  children: [
181
- m ? /* @__PURE__ */ o("textarea", {
117
+ m ? /* @__PURE__ */ a("textarea", {
182
118
  ...j,
183
- onChange: r,
119
+ onChange: c,
184
120
  ref: D,
185
121
  value: _,
186
122
  maxLength: v,
187
123
  disabled: p,
188
124
  className: e("text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none", M, "resize-none overflow-y-auto")
189
- }) : /* @__PURE__ */ o("input", {
125
+ }) : /* @__PURE__ */ a("input", {
190
126
  ...A,
191
- onChange: r,
127
+ onChange: c,
192
128
  ref: D,
193
129
  value: _,
194
130
  maxLength: v,
195
131
  disabled: p,
196
132
  className: e("text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none", M, "overflow-hidden text-ellipsis whitespace-nowrap")
197
133
  }),
198
- b && /* @__PURE__ */ o("div", {
134
+ b && /* @__PURE__ */ a("div", {
199
135
  className: "shrink-0",
200
136
  children: b
201
137
  }),
202
- /* @__PURE__ */ o("button", {
138
+ /* @__PURE__ */ a("button", {
203
139
  type: "button",
204
- onClick: () => r && r({ target: { value: "" } }),
140
+ onClick: () => c && c({ target: { value: "" } }),
205
141
  tabIndex: -1,
206
142
  disabled: p,
207
143
  className: e("hidden shrink-0", {
208
144
  flex: E,
209
145
  "group-focus-within:flex": !p && k > 0
210
146
  }),
211
- children: /* @__PURE__ */ o(n, { className: "text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer" })
147
+ children: /* @__PURE__ */ a(n, { className: "text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer" })
212
148
  })
213
149
  ]
214
- }), /* @__PURE__ */ o("div", {
150
+ }), /* @__PURE__ */ a("div", {
215
151
  className: "shrink-0",
216
- children: /* @__PURE__ */ o(t, {
152
+ children: /* @__PURE__ */ a(t, {
217
153
  label: x,
218
154
  onClick: S,
219
155
  size: "medium",
@@ -222,16 +158,16 @@ var d = l("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
222
158
  })
223
159
  })]
224
160
  }),
225
- (d || f || v && g) && /* @__PURE__ */ s("div", {
161
+ (d || f || v && g) && /* @__PURE__ */ o("div", {
226
162
  className: "flex items-center justify-between gap-2",
227
- children: [(d || f) && /* @__PURE__ */ o("span", {
228
- className: e(P, i({
163
+ children: [(d || f) && /* @__PURE__ */ a("span", {
164
+ className: e(P, r({
229
165
  size: y,
230
166
  hasError: E
231
167
  })),
232
168
  children: f || d
233
- }), v && g && /* @__PURE__ */ s("span", {
234
- className: e("ml-auto", P, i({
169
+ }), v && g && /* @__PURE__ */ o("span", {
170
+ className: e("ml-auto", P, r({
235
171
  size: y,
236
172
  hasError: E
237
173
  })),
@@ -245,8 +181,8 @@ var d = l("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
245
181
  ]
246
182
  });
247
183
  });
248
- p.displayName = "TextFieldWithButton";
184
+ l.displayName = "TextFieldWithButton";
249
185
  //#endregion
250
- export { u as TextFieldNormal, f as TextFieldSelect, p as TextFieldWithButton };
186
+ export { c as TextFieldNormal, l as TextFieldWithButton };
251
187
 
252
188
  //# sourceMappingURL=text-field.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-field.js","names":[],"sources":["../src/components/text-field/TextField.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { CTAButton } from \"../cta-button/CTAButton\";\nimport { CancelFilledIcon } from \"../icons/action/CancelFilledIcon\";\nimport { ChevronLeftIcon } from \"../icons/action/ChevronLeftIcon\";\n\nimport {\n fieldContainerVariants as textFieldNormalContainerVariants,\n fieldMessageVariants as textFieldAssistiveAreaVariants,\n} from \"@/components/ui/fieldStyles\";\nimport { cn } from \"@/utils/TailwindUtil\";\n\ninterface TextFieldNormalProps extends Omit<React.InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement>, \"size\"> {\n subtitle?: string;\n isRequired?: boolean;\n assistiveText?: string | React.ReactNode;\n errorText?: string;\n disabled?: boolean;\n multiLine?: boolean;\n className?: string;\n rightElement?: React.ReactNode;\n showCounter?: boolean;\n size?: \"large\" | \"small\";\n}\n\nconst TextFieldNormal = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, TextFieldNormalProps>(\n (\n {\n onChange,\n subtitle,\n isRequired = false,\n assistiveText,\n errorText,\n disabled = false,\n multiLine = false,\n className,\n rightElement,\n showCounter = false,\n value,\n maxLength,\n size = \"large\",\n ...inputProps\n },\n ref,\n ) => {\n const hasError = !!errorText;\n const inputRef = React.useRef<HTMLInputElement | HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement | HTMLTextAreaElement);\n\n const handleContainerClick = React.useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n const stringValue = typeof value === \"string\" ? value : \"\";\n const currentLength = stringValue.length;\n\n const inputPropsForInput = inputProps as React.ComponentPropsWithoutRef<\"input\">;\n const inputPropsForTextarea = inputProps as React.ComponentPropsWithoutRef<\"textarea\">;\n\n // 사이즈별 폰트 크기\n const inputFontSize = size === \"large\" ? \"text-title-20-regular\" : \"text-body-16-regular\";\n const subtitleFontSize = size === \"large\" ? \"text-title-18-bold\" : \"text-title-14-bold\";\n const assistiveFontSize = size === \"large\" ? \"text-body-16-regular\" : \"text-caption-12-medium\";\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)}>\n {subtitle && (\n <span className={cn(subtitleFontSize, \"text-text-base-neutral-5\")}>\n {subtitle}\n {isRequired && <span className=\"text-text-prominent-accent-1\">*</span>}\n </span>\n )}\n\n <div\n onClick={disabled ? undefined : handleContainerClick}\n className={cn(\n \"group overflow-hidden\",\n textFieldNormalContainerVariants({ size, disabled, hasError }),\n !disabled && !hasError && \"focus-within:border-border-base-neutral-4\",\n multiLine && \"h-[120px] items-start\",\n )}\n >\n {multiLine ? (\n <textarea\n {...inputPropsForTextarea}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLTextAreaElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 h-full min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"resize-none overflow-y-auto\",\n )}\n />\n ) : (\n <input\n {...inputPropsForInput}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLInputElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"overflow-hidden text-ellipsis whitespace-nowrap\",\n )}\n />\n )}\n\n {rightElement && <div className=\"shrink-0\">{rightElement}</div>}\n\n <button\n type=\"button\"\n onClick={() =>\n onChange &&\n onChange({ target: { value: \"\" } } as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>)\n }\n tabIndex={-1}\n disabled={disabled}\n className={cn(\"hidden shrink-0\", {\n flex: hasError,\n \"group-focus-within:flex\": !disabled && currentLength > 0,\n })}\n >\n <CancelFilledIcon className=\"text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer\" />\n </button>\n </div>\n\n {(assistiveText || errorText || (maxLength && showCounter)) && (\n <div className=\"flex items-center justify-between gap-2\">\n {(assistiveText || errorText) && (\n <span className={cn(assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {errorText || assistiveText}\n </span>\n )}\n {maxLength && showCounter && (\n <span className={cn(\"ml-auto\", assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {currentLength}/{maxLength}\n </span>\n )}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldNormal.displayName = \"TextFieldNormal\";\n\n// TextField Select 컴포넌트\nconst textFieldSelectVariants = cva(\n \"flex items-center justify-between rounded-[4px] bg-surface-base-neutral-2 border transition-colors duration-200\",\n {\n variants: {\n size: {\n large: \"gap-2 p-[15px] min-h-[56px]\",\n small: \"gap-3 p-[11px] min-h-[48px]\",\n },\n hasError: {\n true: \"border-border-prominent-error\",\n false: \"border-transparent\",\n },\n disabled: {\n true: \"opacity-50\",\n false: \"\",\n },\n },\n defaultVariants: {\n size: \"large\",\n },\n },\n);\n\ninterface TextFieldSelectProps extends VariantProps<typeof textFieldSelectVariants> {\n label?: string;\n placeholder: string;\n value?: string;\n isRequired?: boolean;\n disabled?: boolean;\n assistiveText?: string | React.ReactNode;\n errorText?: string;\n onPress?: () => void;\n className?: string;\n size?: \"large\" | \"small\";\n}\n\nconst TextFieldSelect = ({\n label,\n placeholder,\n value,\n isRequired = false,\n disabled = false,\n assistiveText,\n errorText,\n onPress,\n className,\n size = \"large\",\n}: TextFieldSelectProps) => {\n const hasError = !!errorText;\n\n // 사이즈별 폰트 크기\n const labelFontSize = size === \"large\" ? \"text-title-18-bold\" : \"text-title-14-bold\";\n const valueFontSize = size === \"large\" ? \"text-title-20-regular\" : \"text-body-16-regular\";\n\n return (\n <div className={cn(\"flex w-full flex-col gap-2\", className)}>\n {/* Label with optional asterisk */}\n {label && (\n <div className=\"flex items-start\">\n <span className={cn(labelFontSize, \"text-text-base-neutral-5\")}>{label}</span>\n {isRequired && <span className={cn(labelFontSize, \"text-text-prominent-accent-1\")}>*</span>}\n </div>\n )}\n {/* Select Field */}\n <button\n type=\"button\"\n className={textFieldSelectVariants({ size, hasError, disabled })}\n onClick={onPress}\n disabled={disabled}\n >\n <span\n className={cn(valueFontSize, \"flex-1\", value ? \"text-text-base-neutral-5\" : \"text-text-base-neutral-2\")}\n style={{ textAlign: \"left\", overflow: \"hidden\", textOverflow: \"ellipsis\" }}\n >\n {value || placeholder}\n </span>\n <ChevronLeftIcon className=\"text-icon-base-neutral-3 rotate-270\" />\n </button>\n {/* Assistive/Error Text */}\n {(assistiveText || errorText) && (\n <div className=\"flex items-start gap-2\">\n <span className={textFieldAssistiveAreaVariants({ size, hasError })}>{errorText || assistiveText}</span>\n </div>\n )}\n </div>\n );\n};\n\n// TextField With Button 컴포넌트\ninterface TextFieldWithButtonProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement>, \"size\"> {\n subtitle?: string;\n isRequired?: boolean;\n assistiveText?: string | React.ReactNode;\n errorText?: string;\n disabled?: boolean;\n multiLine?: boolean;\n className?: string;\n showCounter?: boolean;\n size?: \"large\" | \"small\";\n fieldRightElement?: React.ReactNode;\n buttonText: string;\n onButtonClick: () => void;\n buttonDisabled?: boolean;\n}\n\nconst TextFieldWithButton = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, TextFieldWithButtonProps>(\n (\n {\n onChange,\n subtitle,\n isRequired = false,\n assistiveText,\n errorText,\n disabled = false,\n multiLine = false,\n className,\n showCounter = false,\n value,\n maxLength,\n size = \"large\",\n fieldRightElement,\n buttonText,\n onButtonClick,\n buttonDisabled = false,\n ...inputProps\n },\n ref,\n ) => {\n const hasError = !!errorText;\n const inputRef = React.useRef<HTMLInputElement | HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement | HTMLTextAreaElement);\n\n const handleContainerClick = React.useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n const stringValue = typeof value === \"string\" ? value : \"\";\n const currentLength = stringValue.length;\n\n const inputPropsForInput = inputProps as React.ComponentPropsWithoutRef<\"input\">;\n const inputPropsForTextarea = inputProps as React.ComponentPropsWithoutRef<\"textarea\">;\n\n // 사이즈별 폰트 크기\n const inputFontSize = size === \"large\" ? \"text-title-20-regular\" : \"text-body-16-regular\";\n const subtitleFontSize = size === \"large\" ? \"text-title-18-bold\" : \"text-title-14-bold\";\n const assistiveFontSize = size === \"large\" ? \"text-body-16-regular\" : \"text-caption-12-medium\";\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)}>\n {subtitle && (\n <span className={cn(subtitleFontSize, \"text-text-base-neutral-5\")}>\n {subtitle}\n {isRequired && <span className=\"text-text-prominent-accent-1\">*</span>}\n </span>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div\n onClick={disabled ? undefined : handleContainerClick}\n className={cn(\n \"group flex-1 overflow-hidden\",\n textFieldNormalContainerVariants({ size, disabled, hasError }),\n !disabled && !hasError && \"focus-within:border-border-base-neutral-4\",\n multiLine && \"h-[120px] items-start\",\n )}\n >\n {multiLine ? (\n <textarea\n {...inputPropsForTextarea}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLTextAreaElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"resize-none overflow-y-auto\",\n )}\n />\n ) : (\n <input\n {...inputPropsForInput}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLInputElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"overflow-hidden text-ellipsis whitespace-nowrap\",\n )}\n />\n )}\n\n {fieldRightElement && <div className=\"shrink-0\">{fieldRightElement}</div>}\n\n <button\n type=\"button\"\n onClick={() =>\n onChange &&\n onChange({ target: { value: \"\" } } as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>)\n }\n tabIndex={-1}\n disabled={disabled}\n className={cn(\"hidden shrink-0\", {\n flex: hasError,\n \"group-focus-within:flex\": !disabled && currentLength > 0,\n })}\n >\n <CancelFilledIcon className=\"text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer\" />\n </button>\n </div>\n\n <div className=\"shrink-0\">\n <CTAButton\n label={buttonText}\n onClick={onButtonClick}\n size=\"medium\"\n hierarchy=\"tertiary\"\n disabled={buttonDisabled || disabled}\n />\n </div>\n </div>\n\n {(assistiveText || errorText || (maxLength && showCounter)) && (\n <div className=\"flex items-center justify-between gap-2\">\n {(assistiveText || errorText) && (\n <span className={cn(assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {errorText || assistiveText}\n </span>\n )}\n {maxLength && showCounter && (\n <span className={cn(\"ml-auto\", assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {currentLength}/{maxLength}\n </span>\n )}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldWithButton.displayName = \"TextFieldWithButton\";\n\nexport { TextFieldNormal, TextFieldSelect, TextFieldWithButton };\n"],"mappings":"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"}
1
+ {"version":3,"file":"text-field.js","names":[],"sources":["../src/components/text-field/TextField.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nimport { CTAButton } from \"../cta-button/CTAButton\";\nimport { CancelFilledIcon } from \"../icons/action/CancelFilledIcon\";\n\nimport {\n fieldContainerVariants as textFieldNormalContainerVariants,\n fieldMessageVariants as textFieldAssistiveAreaVariants,\n} from \"@/components/ui/fieldStyles\";\nimport { cn } from \"@/utils/TailwindUtil\";\n\ninterface TextFieldNormalProps extends Omit<React.InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement>, \"size\"> {\n subtitle?: string;\n isRequired?: boolean;\n assistiveText?: string | React.ReactNode;\n errorText?: string;\n disabled?: boolean;\n multiLine?: boolean;\n className?: string;\n rightElement?: React.ReactNode;\n showCounter?: boolean;\n size?: \"large\" | \"small\";\n}\n\nconst TextFieldNormal = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, TextFieldNormalProps>(\n (\n {\n onChange,\n subtitle,\n isRequired = false,\n assistiveText,\n errorText,\n disabled = false,\n multiLine = false,\n className,\n rightElement,\n showCounter = false,\n value,\n maxLength,\n size = \"large\",\n ...inputProps\n },\n ref,\n ) => {\n const hasError = !!errorText;\n const inputRef = React.useRef<HTMLInputElement | HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement | HTMLTextAreaElement);\n\n const handleContainerClick = React.useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n const stringValue = typeof value === \"string\" ? value : \"\";\n const currentLength = stringValue.length;\n\n const inputPropsForInput = inputProps as React.ComponentPropsWithoutRef<\"input\">;\n const inputPropsForTextarea = inputProps as React.ComponentPropsWithoutRef<\"textarea\">;\n\n // 사이즈별 폰트 크기\n const inputFontSize = size === \"large\" ? \"text-title-20-regular\" : \"text-body-16-regular\";\n const subtitleFontSize = size === \"large\" ? \"text-title-18-bold\" : \"text-title-14-bold\";\n const assistiveFontSize = size === \"large\" ? \"text-body-16-regular\" : \"text-caption-12-medium\";\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)}>\n {subtitle && (\n <span className={cn(subtitleFontSize, \"text-text-base-neutral-5\")}>\n {subtitle}\n {isRequired && <span className=\"text-text-prominent-accent-1\">*</span>}\n </span>\n )}\n\n <div\n onClick={disabled ? undefined : handleContainerClick}\n className={cn(\n \"group overflow-hidden\",\n textFieldNormalContainerVariants({ size, disabled, hasError }),\n !disabled && !hasError && \"focus-within:border-border-base-neutral-4\",\n multiLine && \"h-[120px] items-start\",\n )}\n >\n {multiLine ? (\n <textarea\n {...inputPropsForTextarea}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLTextAreaElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 h-full min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"resize-none overflow-y-auto\",\n )}\n />\n ) : (\n <input\n {...inputPropsForInput}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLInputElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"overflow-hidden text-ellipsis whitespace-nowrap\",\n )}\n />\n )}\n\n {rightElement && <div className=\"shrink-0\">{rightElement}</div>}\n\n <button\n type=\"button\"\n onClick={() =>\n onChange &&\n onChange({ target: { value: \"\" } } as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>)\n }\n tabIndex={-1}\n disabled={disabled}\n className={cn(\"hidden shrink-0\", {\n flex: hasError,\n \"group-focus-within:flex\": !disabled && currentLength > 0,\n })}\n >\n <CancelFilledIcon className=\"text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer\" />\n </button>\n </div>\n\n {(assistiveText || errorText || (maxLength && showCounter)) && (\n <div className=\"flex items-center justify-between gap-2\">\n {(assistiveText || errorText) && (\n <span className={cn(assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {errorText || assistiveText}\n </span>\n )}\n {maxLength && showCounter && (\n <span className={cn(\"ml-auto\", assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {currentLength}/{maxLength}\n </span>\n )}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldNormal.displayName = \"TextFieldNormal\";\n\n// TextField With Button 컴포넌트\ninterface TextFieldWithButtonProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement>, \"size\"> {\n subtitle?: string;\n isRequired?: boolean;\n assistiveText?: string | React.ReactNode;\n errorText?: string;\n disabled?: boolean;\n multiLine?: boolean;\n className?: string;\n showCounter?: boolean;\n size?: \"large\" | \"small\";\n fieldRightElement?: React.ReactNode;\n buttonText: string;\n onButtonClick: () => void;\n buttonDisabled?: boolean;\n}\n\nconst TextFieldWithButton = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, TextFieldWithButtonProps>(\n (\n {\n onChange,\n subtitle,\n isRequired = false,\n assistiveText,\n errorText,\n disabled = false,\n multiLine = false,\n className,\n showCounter = false,\n value,\n maxLength,\n size = \"large\",\n fieldRightElement,\n buttonText,\n onButtonClick,\n buttonDisabled = false,\n ...inputProps\n },\n ref,\n ) => {\n const hasError = !!errorText;\n const inputRef = React.useRef<HTMLInputElement | HTMLTextAreaElement>(null);\n\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement | HTMLTextAreaElement);\n\n const handleContainerClick = React.useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n const stringValue = typeof value === \"string\" ? value : \"\";\n const currentLength = stringValue.length;\n\n const inputPropsForInput = inputProps as React.ComponentPropsWithoutRef<\"input\">;\n const inputPropsForTextarea = inputProps as React.ComponentPropsWithoutRef<\"textarea\">;\n\n // 사이즈별 폰트 크기\n const inputFontSize = size === \"large\" ? \"text-title-20-regular\" : \"text-body-16-regular\";\n const subtitleFontSize = size === \"large\" ? \"text-title-18-bold\" : \"text-title-14-bold\";\n const assistiveFontSize = size === \"large\" ? \"text-body-16-regular\" : \"text-caption-12-medium\";\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)}>\n {subtitle && (\n <span className={cn(subtitleFontSize, \"text-text-base-neutral-5\")}>\n {subtitle}\n {isRequired && <span className=\"text-text-prominent-accent-1\">*</span>}\n </span>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div\n onClick={disabled ? undefined : handleContainerClick}\n className={cn(\n \"group flex-1 overflow-hidden\",\n textFieldNormalContainerVariants({ size, disabled, hasError }),\n !disabled && !hasError && \"focus-within:border-border-base-neutral-4\",\n multiLine && \"h-[120px] items-start\",\n )}\n >\n {multiLine ? (\n <textarea\n {...inputPropsForTextarea}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLTextAreaElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"resize-none overflow-y-auto\",\n )}\n />\n ) : (\n <input\n {...inputPropsForInput}\n onChange={onChange}\n ref={inputRef as React.Ref<HTMLInputElement>}\n value={value}\n maxLength={maxLength}\n disabled={disabled}\n className={cn(\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 min-h-[24px] min-w-0 flex-1 border-none bg-transparent py-0 outline-none\",\n inputFontSize,\n \"overflow-hidden text-ellipsis whitespace-nowrap\",\n )}\n />\n )}\n\n {fieldRightElement && <div className=\"shrink-0\">{fieldRightElement}</div>}\n\n <button\n type=\"button\"\n onClick={() =>\n onChange &&\n onChange({ target: { value: \"\" } } as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>)\n }\n tabIndex={-1}\n disabled={disabled}\n className={cn(\"hidden shrink-0\", {\n flex: hasError,\n \"group-focus-within:flex\": !disabled && currentLength > 0,\n })}\n >\n <CancelFilledIcon className=\"text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer\" />\n </button>\n </div>\n\n <div className=\"shrink-0\">\n <CTAButton\n label={buttonText}\n onClick={onButtonClick}\n size=\"medium\"\n hierarchy=\"tertiary\"\n disabled={buttonDisabled || disabled}\n />\n </div>\n </div>\n\n {(assistiveText || errorText || (maxLength && showCounter)) && (\n <div className=\"flex items-center justify-between gap-2\">\n {(assistiveText || errorText) && (\n <span className={cn(assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {errorText || assistiveText}\n </span>\n )}\n {maxLength && showCounter && (\n <span className={cn(\"ml-auto\", assistiveFontSize, textFieldAssistiveAreaVariants({ size, hasError }))}>\n {currentLength}/{maxLength}\n </span>\n )}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldWithButton.displayName = \"TextFieldWithButton\";\n\nexport { TextFieldNormal, TextFieldWithButton };\n"],"mappings":"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"}
@@ -1 +1 @@
1
- export { TextFieldNormal, TextFieldSelect, TextFieldWithButton } from "../text-field.js";
1
+ export { TextFieldNormal, TextFieldWithButton } from "../text-field.js";
@@ -0,0 +1,59 @@
1
+ # 5.x → 6.0 마이그레이션 가이드
2
+
3
+ 6.0은 `Select`를 petify-admin-console과 같은 드롭다운(Radix Select)으로 바꾸고, 목록 없이 버튼만 있던
4
+ `TextFieldSelect`를 지운 릴리스다. 바뀐 항목 전체는 [CHANGELOG](../../CHANGELOG.md)를 본다.
5
+
6
+ ## 1. `TextFieldSelect` → `Select`
7
+
8
+ `TextFieldSelect`는 값과 셰브런을 보이는 버튼이었고, 목록은 소비 레포가 `onPress`로 직접 띄웠다. 6.0에서는
9
+ `Select`가 목록까지 그린다.
10
+
11
+ ```tsx
12
+ // 5.x
13
+ <TextFieldSelect
14
+ label="품종"
15
+ placeholder="품종을 선택해 주세요"
16
+ value={breed}
17
+ isRequired
18
+ onPress={() => openBreedSheet()}
19
+ />
20
+
21
+ // 6.0
22
+ <Select
23
+ label="품종"
24
+ placeholder="품종을 선택해 주세요"
25
+ options={BREEDS}
26
+ value={breed}
27
+ onChange={setBreed}
28
+ required
29
+ />
30
+ ```
31
+
32
+ | 5.x `TextFieldSelect` | 6.0 `Select` |
33
+ | ------------------------------------------------------------------------------------- | -------------------------------------------------------- |
34
+ | `isRequired` | `required` |
35
+ | `onPress` + 직접 띄운 목록 | `options` + `onChange(value)` |
36
+ | `value`(보이는 글자) | `value`(고른 옵션의 값), 표시 이름은 `options`의 `label` |
37
+ | `errorText`, `assistiveText`, `size`, `disabled`, `className`, `placeholder`, `label` | 같음 |
38
+
39
+ 옵션이 많아 검색이 필요하면 `Combobox`를 쓴다. 바텀시트 같은 자체 선택 화면을 계속 써야 하면 그 레포에
40
+ 버튼을 두고 `@petnow/ui`의 `TextFieldSelect`에 기대지 않는다.
41
+
42
+ ## 2. `Select`의 ref와 속성
43
+
44
+ - `ref`는 `<select>`가 아니라 트리거 `<button>`(`HTMLButtonElement`)을 가리킨다. `ref.current.value`로 값을
45
+ 읽던 코드는 `value`/`onChange`를 쓴다.
46
+ - 나머지 속성은 `<button>` 속성으로 넘어간다. `name`, `form`, `required`는 그대로 동작한다. 폼 안에서는 Radix가
47
+ 숨은 `<select>`를 그려 `FormData`와 브라우저 검증에 값이 들어간다.
48
+ - 옵션 값으로 `""`를 쓸 수 없다. `""`는 고르지 않은 상태이고 `placeholder`를 보이며, 값이 `""`인 옵션은
49
+ 그리지 않는다.
50
+ - 한 번 고른 뒤 사용자가 "고르지 않음"으로 되돌릴 수 없다. 네이티브 `<select>`는 placeholder 옵션을 다시 고를
51
+ 수 있었다. 되돌려야 하는 폼은 코드에서 `value`를 `""`로 바꾼다.
52
+ - 폼 `reset`이면 화면 값과 숨은 `<select>`가 `defaultValue`(없으면 고르지 않음)로 돌아간다. 제어 컴포넌트는
53
+ `onChange`로 그 값을 받는다.
54
+ - 모바일 브라우저에서도 시스템 피커 대신 같은 패널이 열린다.
55
+
56
+ ## 3. 확인
57
+
58
+ - 목록이 트리거 아래(공간이 없으면 위)에 열리고, 고른 옵션 앞에 체크가 보이는지.
59
+ - 폼을 제출하는 화면이면 `FormData`나 서버로 넘어가는 값이 그대로인지.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@petnow/ui",
3
- "version": "5.4.0",
3
+ "version": "6.0.0",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@11.1.3",
6
6
  "scripts": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"fieldStyles-DyZu__hI.js","names":[],"sources":["../src/components/ui/fieldStyles.ts"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\n// TextField, Select, Combobox가 함께 쓰는 입력 칸 스타일\n// 입력 칸과 목록 팝업이 같은 모서리를 쓴다. 소비 레포의 --radius-* 설정과 무관하게 4px로 고정한다.\nexport const FIELD_RADIUS = \"rounded-[4px]\";\n\nexport const fieldContainerVariants = cva(\n `flex items-center ${FIELD_RADIUS} bg-surface-base-neutral-2 border transition-colors duration-200`,\n {\n variants: {\n size: {\n large: \"gap-2 p-[15px] min-h-[56px]\",\n small: \"gap-3 p-[11px] min-h-[48px]\",\n },\n hasError: {\n true: \"border-border-prominent-error\",\n false: \"border-transparent\",\n },\n disabled: {\n true: \"opacity-50\",\n false: \"\",\n },\n },\n defaultVariants: {\n size: \"large\",\n disabled: false,\n hasError: false,\n },\n },\n);\n\nexport const fieldMessageVariants = cva(\"\", {\n variants: {\n size: {\n large: \"text-body-16-regular\",\n small: \"text-caption-12-medium\",\n },\n hasError: {\n true: \"text-text-prominent-error\",\n false: \"text-text-base-neutral-2\",\n },\n },\n defaultVariants: {\n size: \"large\",\n hasError: false,\n },\n});\n\nexport type FieldSize = \"large\" | \"small\";\n\nexport const fieldLabelFontSize = (size: FieldSize) => (size === \"large\" ? \"text-title-18-bold\" : \"text-title-14-bold\");\nexport const fieldValueFontSize = (size: FieldSize) =>\n size === \"large\" ? \"text-title-20-regular\" : \"text-body-16-regular\";\n\n// 소비 레포가 넘긴 aria-describedby와 필드 메시지 id를 합친다.\nexport const joinIds = (...ids: (string | false | undefined)[]) => ids.filter(Boolean).join(\" \") || undefined;\n"],"mappings":";;AAIA,IAAa,IAAe,iBAEf,IAAyB,EACpC,qBAAqB,EAAa,mEAClC;CACE,UAAU;EACR,MAAM;GACJ,OAAO;GACP,OAAO;EACT;EACA,UAAU;GACR,MAAM;GACN,OAAO;EACT;EACA,UAAU;GACR,MAAM;GACN,OAAO;EACT;CACF;CACA,iBAAiB;EACf,MAAM;EACN,UAAU;EACV,UAAU;CACZ;AACF,CACF,GAEa,IAAuB,EAAI,IAAI;CAC1C,UAAU;EACR,MAAM;GACJ,OAAO;GACP,OAAO;EACT;EACA,UAAU;GACR,MAAM;GACN,OAAO;EACT;CACF;CACA,iBAAiB;EACf,MAAM;EACN,UAAU;CACZ;AACF,CAAC,GAIY,KAAsB,MAAqB,MAAS,UAAU,uBAAuB,sBACrF,KAAsB,MACjC,MAAS,UAAU,0BAA0B,wBAGlC,KAAW,GAAG,MAAwC,EAAI,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA"}
@@ -1,27 +0,0 @@
1
- import { t as e } from "./TailwindUtil-DiNvXuNl.js";
2
- import { i as t, r as n } from "./fieldStyles-DyZu__hI.js";
3
- import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
- //#region src/components/ui/field.tsx
5
- var a = ({ id: t, htmlFor: a, size: o, required: s, children: c }) => /* @__PURE__ */ i("label", {
6
- id: t,
7
- htmlFor: a,
8
- className: e(n(o), "text-text-base-neutral-5"),
9
- children: [c, s && /* @__PURE__ */ r("span", {
10
- className: "text-text-prominent-accent-1",
11
- "aria-hidden": "true",
12
- children: "*"
13
- })]
14
- }), o = ({ id: e, size: n, errorText: i, assistiveText: a }) => !i && !a ? null : /* @__PURE__ */ r("span", {
15
- id: e,
16
- className: t({
17
- size: n,
18
- hasError: !!i
19
- }),
20
- children: i || a
21
- }), s = (...e) => (t) => {
22
- for (let n of e) typeof n == "function" ? n(t) : n && (n.current = t);
23
- };
24
- //#endregion
25
- export { a as n, o as r, s as t };
26
-
27
- //# sourceMappingURL=mergeRefs-BHwdBwNQ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mergeRefs-BHwdBwNQ.js","names":[],"sources":["../src/components/ui/field.tsx","../src/utils/mergeRefs.ts"],"sourcesContent":["import { fieldLabelFontSize, fieldMessageVariants, type FieldSize } from \"./fieldStyles\";\n\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/TailwindUtil\";\n\nexport const FieldLabel = ({\n id,\n htmlFor,\n size,\n required,\n children,\n}: {\n id?: string;\n htmlFor: string;\n size: FieldSize;\n required?: boolean;\n children: ReactNode;\n}) => (\n <label id={id} htmlFor={htmlFor} className={cn(fieldLabelFontSize(size), \"text-text-base-neutral-5\")}>\n {children}\n {required && (\n <span className=\"text-text-prominent-accent-1\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n);\n\nexport const FieldMessage = ({\n id,\n size,\n errorText,\n assistiveText,\n}: {\n id: string;\n size: FieldSize;\n errorText?: string;\n assistiveText?: ReactNode;\n}) => {\n if (!errorText && !assistiveText) return null;\n return (\n <span id={id} className={fieldMessageVariants({ size, hasError: Boolean(errorText) })}>\n {errorText || assistiveText}\n </span>\n );\n};\n","import type { Ref, RefCallback } from \"react\";\n\n// 내부 ref와 소비 레포가 넘긴 ref(React 19 ref prop)를 함께 연결한다.\nexport const mergeRefs =\n <T>(...refs: (Ref<T> | undefined)[]): RefCallback<T> =>\n (node) => {\n for (const ref of refs) {\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }\n };\n"],"mappings":";;;;AAMA,IAAa,KAAc,EACzB,OACA,YACA,SACA,aACA,kBAQA,kBAAC,SAAD;CAAW;CAAa;CAAS,WAAW,EAAG,EAAmB,CAAI,GAAG,0BAA0B;WAAnG,CACG,GACA,KACC,kBAAC,QAAD;EAAM,WAAU;EAA+B,eAAY;YAAO;CAE5D,CAAA,CAEH;IAGI,KAAgB,EAC3B,OACA,SACA,cACA,uBAOI,CAAC,KAAa,CAAC,IAAsB,OAEvC,kBAAC,QAAD;CAAU;CAAI,WAAW,EAAqB;EAAE;EAAM,UAAU,EAAQ;CAAW,CAAC;WACjF,KAAa;AACV,CAAA,GCzCG,KACP,GAAG,OACN,MAAS;CACR,KAAK,IAAM,KAAO,GAChB,AAAI,OAAO,KAAQ,aAAY,EAAI,CAAI,IAC9B,MAAK,EAAI,UAAU;AAEhC"}