@petnow/ui 5.2.0 → 5.3.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.
- package/CHANGELOG.md +29 -0
- package/dist/checkbox.js +3 -3
- package/dist/checkbox.js.map +1 -1
- package/dist/combobox.js +201 -0
- package/dist/combobox.js.map +1 -0
- package/dist/fieldStyles-DyZu__hI.js +42 -0
- package/dist/fieldStyles-DyZu__hI.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +15 -13
- package/dist/mergeRefs-BHwdBwNQ.js +27 -0
- package/dist/mergeRefs-BHwdBwNQ.js.map +1 -0
- package/dist/select.js +82 -0
- package/dist/select.js.map +1 -0
- package/dist/src/components/checkbox/Checkbox.d.ts +3 -2
- package/dist/src/components/combobox/Combobox.d.ts +35 -0
- package/dist/src/components/select/Select.d.ts +24 -0
- package/dist/src/components/ui/field.d.ts +15 -0
- package/dist/src/components/ui/fieldStyles.d.ts +14 -0
- package/dist/src/utils/mergeRefs.d.ts +2 -0
- package/dist/text-field.js +61 -95
- package/dist/text-field.js.map +1 -1
- package/package.json +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.3.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`Select`** (`@petnow/ui/select`): pick one option from a list. It is a native `<select>` styled like
|
|
8
|
+
`TextField`, so it keeps the mobile picker, form validation (`required`) and keyboard behavior of the
|
|
9
|
+
browser. Props: `label`, `options` (`string` or `{ value, label, disabled }`), `value` / `defaultValue`,
|
|
10
|
+
`onChange(value)`, `placeholder`, `errorText`, `assistiveText`, `size` (`large` | `small`), plus every
|
|
11
|
+
`<select>` attribute and `ref`.
|
|
12
|
+
- **`Combobox`** (`@petnow/ui/combobox`): type to search and pick one option (WAI-ARIA combobox with list
|
|
13
|
+
autocomplete). Focus stays in the input and the active option is announced with
|
|
14
|
+
`aria-activedescendant`. Only a picked option becomes `value`; typing after a pick calls
|
|
15
|
+
`onChange("")`, and text equal to an option label (for example from browser autofill) picks it.
|
|
16
|
+
Escape and blur discard the query, and a new `value` from outside (a form reset) replaces it. IME
|
|
17
|
+
composition keys (Korean, Japanese) never pick an option. With `required`, text that is not a picked
|
|
18
|
+
option fails browser validation (`invalidSelectionText`). It is controlled only (`value` and
|
|
19
|
+
`onChange`; no `defaultValue`). Other props as `Select`, plus `filter`, `emptyText`, `toggleLabel` and
|
|
20
|
+
`name` (submitted through a hidden input with the picked value). The list is positioned below the input,
|
|
21
|
+
so a parent with `overflow: hidden` clips it.
|
|
22
|
+
- Both are tagged `source-dev` in Storybook: they follow `TextField`, not a separate design baseline.
|
|
23
|
+
|
|
24
|
+
### Changes
|
|
25
|
+
|
|
26
|
+
- `Checkbox` accepts `ref` (React 19 ref prop), which reaches the `<input>`. Without `isChecked` it is
|
|
27
|
+
uncontrolled and `defaultChecked` sets the first state.
|
|
28
|
+
- `Checkbox` is dimmed (`opacity-50`, box and check mark) and shows a not-allowed cursor when
|
|
29
|
+
`disabled`. A consumer `disabled:opacity-*` class still wins for the box.
|
|
30
|
+
- `TextField` shares its field styles with `Select` and `Combobox`. Its classes are unchanged.
|
|
31
|
+
|
|
3
32
|
## 5.2.0
|
|
4
33
|
|
|
5
34
|
### Changes
|
package/dist/checkbox.js
CHANGED
|
@@ -3,20 +3,20 @@ import { t as e } from "./TailwindUtil-DiNvXuNl.js";
|
|
|
3
3
|
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/checkbox/Checkbox.tsx
|
|
5
5
|
var r = ({ className: r, id: i, onChange: a, disabled: o, isChecked: s, ...c }) => /* @__PURE__ */ n("label", {
|
|
6
|
-
className: "relative flex h-min w-min cursor-pointer items-center rounded-full",
|
|
6
|
+
className: "relative flex h-min w-min cursor-pointer items-center rounded-full has-disabled:cursor-not-allowed",
|
|
7
7
|
htmlFor: i,
|
|
8
8
|
children: [/* @__PURE__ */ t("input", {
|
|
9
9
|
...c,
|
|
10
10
|
type: "checkbox",
|
|
11
11
|
disabled: o,
|
|
12
|
-
className: e("peer bg-petnow-grey-primary checked:bg-surface-primary-accent focus-visible:outline-border-prominent-accent relative size-6 cursor-pointer appearance-none rounded-xl border border-transparent transition-all focus-visible:outline-2 focus-visible:outline-offset-2", r),
|
|
12
|
+
className: e("peer bg-petnow-grey-primary checked:bg-surface-primary-accent focus-visible:outline-border-prominent-accent relative size-6 cursor-pointer appearance-none rounded-xl border border-transparent transition-all focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-50", r),
|
|
13
13
|
id: i,
|
|
14
14
|
checked: s,
|
|
15
15
|
onChange: (e) => {
|
|
16
16
|
a?.(e.target.checked);
|
|
17
17
|
}
|
|
18
18
|
}), /* @__PURE__ */ t("span", {
|
|
19
|
-
className: "text-petnow-grey-secondary peer-checked:text-icon-prominent-neutral pointer-events-none absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 transition",
|
|
19
|
+
className: "text-petnow-grey-secondary peer-checked:text-icon-prominent-neutral pointer-events-none absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 transition peer-disabled:opacity-50",
|
|
20
20
|
children: /* @__PURE__ */ t("svg", {
|
|
21
21
|
xmlns: "http://www.w3.org/2000/svg",
|
|
22
22
|
className: "h-4 w-4",
|
package/dist/checkbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.js","names":[],"sources":["../src/components/checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../../utils/TailwindUtil\";\n\nimport type {
|
|
1
|
+
{"version":3,"file":"checkbox.js","names":[],"sources":["../src/components/checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../../utils/TailwindUtil\";\n\nimport type { ComponentPropsWithRef } from \"react\";\n\ninterface Props extends Omit<ComponentPropsWithRef<\"input\">, \"type\" | \"checked\" | \"onChange\"> {\n className?: string;\n id?: string;\n onChange?: (newValue: boolean) => void;\n disabled?: boolean;\n /** 제어 컴포넌트로 쓸 때의 체크 상태. 넘기지 않으면 비제어 컴포넌트가 되고, 처음 상태는 `defaultChecked`로 정한다. */\n isChecked?: boolean;\n}\n\nconst Checkbox = ({ className, id, onChange, disabled, isChecked, ...inputProps }: Props) => {\n return (\n <label\n className=\"relative flex h-min w-min cursor-pointer items-center rounded-full has-disabled:cursor-not-allowed\"\n htmlFor={id}\n >\n <input\n {...inputProps}\n type=\"checkbox\"\n disabled={disabled}\n className={cn(\n \"peer bg-petnow-grey-primary checked:bg-surface-primary-accent focus-visible:outline-border-prominent-accent relative size-6 cursor-pointer appearance-none rounded-xl border border-transparent transition-all focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n id={id}\n checked={isChecked}\n onChange={(event) => {\n onChange?.(event.target.checked);\n }}\n />\n <span className=\"text-petnow-grey-secondary peer-checked:text-icon-prominent-neutral pointer-events-none absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 transition peer-disabled:opacity-50\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n stroke=\"currentColor\"\n strokeWidth=\"1\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n clipRule=\"evenodd\"\n ></path>\n </svg>\n </span>\n </label>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;AAeA,IAAM,KAAY,EAAE,cAAW,OAAI,aAAU,aAAU,cAAW,GAAG,QAEjE,kBAAC,SAAD;CACE,WAAU;CACV,SAAS;WAFX,CAIE,kBAAC,SAAD;EACE,GAAI;EACJ,MAAK;EACK;EACV,WAAW,EACT,yTACA,CACF;EACI;EACJ,SAAS;EACT,WAAW,MAAU;GACnB,IAAW,EAAM,OAAO,OAAO;EACjC;CACD,CAAA,GACD,kBAAC,QAAD;EAAM,WAAU;YACd,kBAAC,OAAD;GACE,OAAM;GACN,WAAU;GACV,SAAQ;GACR,MAAK;GACL,QAAO;GACP,aAAY;aAEZ,kBAAC,QAAD;IACE,UAAS;IACT,GAAE;IACF,UAAS;GACJ,CAAA;EACJ,CAAA;CACD,CAAA,CACD"}
|
package/dist/combobox.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "./TailwindUtil-DiNvXuNl.js";
|
|
3
|
+
import { a as t, n, o as r, t as ee } from "./fieldStyles-DyZu__hI.js";
|
|
4
|
+
import { ChevronDownIcon as te } from "./icons/action/chevron-down.js";
|
|
5
|
+
import { n as ne, r as re, t as ie } from "./mergeRefs-BHwdBwNQ.js";
|
|
6
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
7
|
+
import { useEffect as o, useId as s, useMemo as c, useRef as l, useState as u } from "react";
|
|
8
|
+
//#region src/components/combobox/Combobox.tsx
|
|
9
|
+
var d = (e) => e.toLocaleLowerCase().replace(/\s+/g, ""), f = (e, t) => d(e.label).includes(d(t)), p = ({ id: p, label: m, options: ae, value: h, onChange: oe, filter: g = f, emptyText: _, toggleLabel: v, invalidSelectionText: y = "Select an option from the list.", errorText: b, assistiveText: x, size: S = "large", name: C, required: w, disabled: T = !1, placeholder: se, className: ce, autoComplete: le = "off", "aria-describedby": ue, onBlur: de, onKeyDown: fe, onClick: pe, ref: E, ...D }) => {
|
|
10
|
+
let me = s(), O = p ?? me, k = `${O}-listbox`, A = `${O}-message`, j = (e) => `${O}-option-${e}`, M = !!b, he = !!(b || x), N = `${O}-label`, P = l(null), F = c(() => ie(P, E), [E]), I = l(null), L = l(!1), R = ae.map((e) => typeof e == "string" ? {
|
|
11
|
+
value: e,
|
|
12
|
+
label: e
|
|
13
|
+
} : e), z = R.find((e) => e.value === h), [B, V] = u(null), [H, U] = u(!1), [W, G] = u(-1), K = R.map((e, t) => ({
|
|
14
|
+
option: e,
|
|
15
|
+
index: t
|
|
16
|
+
})).filter(({ option: e }) => !B || g(e, B)), q = H && !T && (K.length > 0 || _ !== void 0), J = K.filter(({ option: e }) => !e.disabled);
|
|
17
|
+
o(() => {
|
|
18
|
+
let e = L.current;
|
|
19
|
+
L.current = !1, !(!q || W < 0 || !e) && document.getElementById(j(W))?.scrollIntoView?.({ block: "nearest" });
|
|
20
|
+
}, [q, W]), o(() => {
|
|
21
|
+
h !== I.current && V(null), I.current = null;
|
|
22
|
+
}, [h]), o(() => {
|
|
23
|
+
I.current = null;
|
|
24
|
+
});
|
|
25
|
+
let Y = !!(w && !z && B);
|
|
26
|
+
o(() => {
|
|
27
|
+
P.current?.setCustomValidity(Y ? y : "");
|
|
28
|
+
}, [Y, y]);
|
|
29
|
+
let X = (e) => {
|
|
30
|
+
I.current = e, oe(e);
|
|
31
|
+
}, Z = () => {
|
|
32
|
+
L.current = !0, U(!0), G(z && !z.disabled ? R.indexOf(z) : -1);
|
|
33
|
+
}, Q = () => {
|
|
34
|
+
U(!1), V(null), G(-1);
|
|
35
|
+
}, $ = (e) => {
|
|
36
|
+
e.disabled || (X(e.value), Q());
|
|
37
|
+
}, ge = (e) => {
|
|
38
|
+
if (J.length === 0) return;
|
|
39
|
+
let t = J.findIndex(({ index: e }) => e === W), n = t === -1 ? e === 1 ? 0 : J.length - 1 : (t + e + J.length) % J.length;
|
|
40
|
+
L.current = !0, G(J[n].index);
|
|
41
|
+
}, _e = (e) => {
|
|
42
|
+
if (fe?.(e), !(e.defaultPrevented || e.nativeEvent.isComposing || e.keyCode === 229)) switch (e.key) {
|
|
43
|
+
case "ArrowDown":
|
|
44
|
+
case "ArrowUp":
|
|
45
|
+
if (e.preventDefault(), H && e.altKey && e.key === "ArrowUp") {
|
|
46
|
+
Q();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (!H) {
|
|
50
|
+
U(!0);
|
|
51
|
+
let t = z && !z.disabled ? R.indexOf(z) : -1, n = e.key === "ArrowDown" ? J[0] : J[J.length - 1];
|
|
52
|
+
L.current = !0, G(t >= 0 || e.altKey ? t : n?.index ?? -1);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
ge(e.key === "ArrowDown" ? 1 : -1);
|
|
56
|
+
return;
|
|
57
|
+
case "Enter":
|
|
58
|
+
q && W >= 0 && (e.preventDefault(), $(R[W]));
|
|
59
|
+
return;
|
|
60
|
+
case "Escape":
|
|
61
|
+
(q || B !== null) && (e.preventDefault(), Q());
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}, ve = (e) => {
|
|
65
|
+
let t = e.trim() ? R.find((t) => !t.disabled && d(t.label) === d(e)) : void 0;
|
|
66
|
+
if (t ? t.value !== h && X(t.value) : h !== "" && X(""), document.activeElement !== P.current) {
|
|
67
|
+
V(t ? null : e);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
V(e), U(!0);
|
|
71
|
+
let n = R.findIndex((t) => !t.disabled && (!e || g(t, e)));
|
|
72
|
+
L.current = !0, G(t ? R.indexOf(t) : e ? n : -1);
|
|
73
|
+
};
|
|
74
|
+
return /* @__PURE__ */ a("div", {
|
|
75
|
+
className: e("flex w-full min-w-0 flex-col gap-2", ce),
|
|
76
|
+
children: [
|
|
77
|
+
m && /* @__PURE__ */ i(ne, {
|
|
78
|
+
id: N,
|
|
79
|
+
htmlFor: O,
|
|
80
|
+
size: S,
|
|
81
|
+
required: w,
|
|
82
|
+
children: m
|
|
83
|
+
}),
|
|
84
|
+
/* @__PURE__ */ a("div", {
|
|
85
|
+
className: "relative",
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ a("div", {
|
|
88
|
+
className: "relative",
|
|
89
|
+
children: [/* @__PURE__ */ i("input", {
|
|
90
|
+
...D,
|
|
91
|
+
ref: F,
|
|
92
|
+
id: O,
|
|
93
|
+
type: "text",
|
|
94
|
+
role: "combobox",
|
|
95
|
+
"aria-expanded": q,
|
|
96
|
+
"aria-controls": k,
|
|
97
|
+
"aria-autocomplete": "list",
|
|
98
|
+
"aria-activedescendant": q && W >= 0 ? j(W) : void 0,
|
|
99
|
+
"aria-invalid": M || void 0,
|
|
100
|
+
"aria-describedby": r(ue, he && A),
|
|
101
|
+
autoComplete: le,
|
|
102
|
+
required: w,
|
|
103
|
+
disabled: T,
|
|
104
|
+
placeholder: se,
|
|
105
|
+
value: B ?? z?.label ?? "",
|
|
106
|
+
onChange: (e) => ve(e.target.value),
|
|
107
|
+
onKeyDown: _e,
|
|
108
|
+
onClick: (e) => {
|
|
109
|
+
pe?.(e), !H && !e.defaultPrevented && Z();
|
|
110
|
+
},
|
|
111
|
+
onBlur: (e) => {
|
|
112
|
+
de?.(e), Q();
|
|
113
|
+
},
|
|
114
|
+
className: e(n({
|
|
115
|
+
size: S,
|
|
116
|
+
hasError: M,
|
|
117
|
+
disabled: T
|
|
118
|
+
}), "text-text-base-neutral-5 placeholder:text-text-base-neutral-2 w-full min-w-0 truncate outline-none disabled:cursor-not-allowed", !T && !M && "focus:border-border-base-neutral-4", S === "large" ? "pr-14" : "pr-12", t(S))
|
|
119
|
+
}), /* @__PURE__ */ i("button", {
|
|
120
|
+
type: "button",
|
|
121
|
+
tabIndex: -1,
|
|
122
|
+
"aria-label": v ?? m ?? D["aria-label"],
|
|
123
|
+
"aria-controls": k,
|
|
124
|
+
"aria-expanded": q,
|
|
125
|
+
disabled: T,
|
|
126
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
127
|
+
onClick: () => {
|
|
128
|
+
q ? Q() : Z(), P.current?.focus();
|
|
129
|
+
},
|
|
130
|
+
className: e("absolute inset-y-0 right-0 flex cursor-pointer items-center justify-center disabled:cursor-not-allowed", S === "large" ? "w-14" : "w-12"),
|
|
131
|
+
children: /* @__PURE__ */ i(te, {
|
|
132
|
+
"aria-hidden": "true",
|
|
133
|
+
className: e("size-6 transition-transform duration-200", q ? "text-icon-prominent-accent-1 rotate-180" : "text-icon-base-neutral-3")
|
|
134
|
+
})
|
|
135
|
+
})]
|
|
136
|
+
}),
|
|
137
|
+
C && /* @__PURE__ */ i("input", {
|
|
138
|
+
type: "hidden",
|
|
139
|
+
name: C,
|
|
140
|
+
value: h,
|
|
141
|
+
disabled: T,
|
|
142
|
+
form: D.form
|
|
143
|
+
}),
|
|
144
|
+
/* @__PURE__ */ a("ul", {
|
|
145
|
+
id: k,
|
|
146
|
+
role: "listbox",
|
|
147
|
+
"aria-labelledby": m ? N : void 0,
|
|
148
|
+
"aria-label": m ? void 0 : D["aria-label"],
|
|
149
|
+
hidden: !q,
|
|
150
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
151
|
+
className: e("border-border-base-neutral-2 bg-surface-base-neutral-1 absolute z-20 mt-2 max-h-72 w-full overflow-y-auto border py-1 shadow-lg", ee),
|
|
152
|
+
children: [K.map(({ option: t, index: n }) => {
|
|
153
|
+
let r = t.value === h;
|
|
154
|
+
return /* @__PURE__ */ a("li", {
|
|
155
|
+
id: j(n),
|
|
156
|
+
role: "option",
|
|
157
|
+
"aria-selected": r,
|
|
158
|
+
"aria-disabled": t.disabled || void 0,
|
|
159
|
+
onMouseMove: () => {
|
|
160
|
+
L.current = !1, t.disabled || G(n);
|
|
161
|
+
},
|
|
162
|
+
onClick: () => $(t),
|
|
163
|
+
className: e("text-text-base-neutral-5 flex cursor-pointer items-center gap-3 px-3 py-2.5 select-none", S === "large" ? "text-body-16-regular" : "text-body-14-regular", n === W && "bg-surface-base-neutral-2", r && "font-medium", t.disabled && "cursor-not-allowed opacity-50"),
|
|
164
|
+
children: [/* @__PURE__ */ i("span", {
|
|
165
|
+
className: "min-w-0 flex-1 truncate",
|
|
166
|
+
children: t.label
|
|
167
|
+
}), r && /* @__PURE__ */ i("svg", {
|
|
168
|
+
"aria-hidden": "true",
|
|
169
|
+
viewBox: "0 0 20 20",
|
|
170
|
+
fill: "none",
|
|
171
|
+
className: "text-icon-prominent-accent-1 size-4 shrink-0",
|
|
172
|
+
children: /* @__PURE__ */ i("path", {
|
|
173
|
+
d: "m4 10 3.5 3.5L16 5",
|
|
174
|
+
stroke: "currentColor",
|
|
175
|
+
strokeWidth: "2",
|
|
176
|
+
strokeLinecap: "round",
|
|
177
|
+
strokeLinejoin: "round"
|
|
178
|
+
})
|
|
179
|
+
})]
|
|
180
|
+
}, t.value);
|
|
181
|
+
}), K.length === 0 && _ !== void 0 && /* @__PURE__ */ i("li", {
|
|
182
|
+
role: "presentation",
|
|
183
|
+
className: "text-text-base-neutral-2 text-body-14-regular px-3 py-2.5",
|
|
184
|
+
children: _
|
|
185
|
+
})]
|
|
186
|
+
})
|
|
187
|
+
]
|
|
188
|
+
}),
|
|
189
|
+
/* @__PURE__ */ i(re, {
|
|
190
|
+
id: A,
|
|
191
|
+
size: S,
|
|
192
|
+
errorText: b,
|
|
193
|
+
assistiveText: x
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
//#endregion
|
|
199
|
+
export { p as Combobox };
|
|
200
|
+
|
|
201
|
+
//# sourceMappingURL=combobox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../src/components/combobox/Combobox.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\n\nimport { ChevronDownIcon } from \"../icons/action/ChevronDownIcon\";\n\nimport type { ComponentPropsWithRef, KeyboardEvent, ReactNode } from \"react\";\n\nimport { FieldLabel, FieldMessage } from \"@/components/ui/field\";\nimport {\n FIELD_RADIUS,\n fieldContainerVariants,\n fieldValueFontSize,\n joinIds,\n type FieldSize,\n} from \"@/components/ui/fieldStyles\";\nimport { mergeRefs } from \"@/utils/mergeRefs\";\nimport { cn } from \"@/utils/TailwindUtil\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\ninterface ComboboxProps\n extends Omit<\n ComponentPropsWithRef<\"input\">,\n \"size\" | \"value\" | \"defaultValue\" | \"onChange\" | \"type\" | \"role\" | \"children\"\n > {\n /** 칸 위에 보이는 이름. `<label>`로 입력에 연결된다. */\n label?: string;\n /** 문자열 옵션은 값과 표시 이름이 같다. */\n options: (string | ComboboxOption)[];\n /** 고른 옵션의 값. 고르지 않았으면 `\"\"`. */\n value: string;\n /** 옵션을 고르면 그 값으로, 고른 뒤 다시 입력하기 시작하면 `\"\"`로 호출된다. */\n onChange: (value: string) => void;\n /** 입력한 검색어로 옵션을 거른다. 기본은 대소문자·공백을 무시한 부분 일치. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** 맞는 옵션이 없을 때 목록에 보이는 문구. 없으면 목록을 닫는다. */\n emptyText?: ReactNode;\n /** 목록 열기 버튼의 접근 가능한 이름. 기본은 `label`. */\n toggleLabel?: string;\n /** `required`인데 입력한 글자가 옵션으로 골라지지 않았을 때 브라우저 검증 메시지. 다국어 페이지에서는 번역해 넘긴다. */\n invalidSelectionText?: string;\n errorText?: string;\n assistiveText?: ReactNode;\n size?: FieldSize;\n}\n\nconst normalize = (text: string) => text.toLocaleLowerCase().replace(/\\s+/g, \"\");\n\nconst defaultFilter = (option: ComboboxOption, query: string) => normalize(option.label).includes(normalize(query));\n\n/**\n * 입력해서 검색하고 목록에서 하나를 고르는 입력(WAI-ARIA combobox, list autocomplete).\n * 포커스는 입력에 남고 목록의 현재 항목은 `aria-activedescendant`로 알린다.\n * 고른 값만 `value`가 되고, 입력한 글자는 고르기 전까지 값이 아니다.\n */\nconst Combobox = ({\n id,\n label,\n options,\n value,\n onChange,\n filter = defaultFilter,\n emptyText,\n toggleLabel,\n invalidSelectionText = \"Select an option from the list.\",\n errorText,\n assistiveText,\n size = \"large\",\n name,\n required,\n disabled = false,\n placeholder,\n className,\n autoComplete = \"off\",\n \"aria-describedby\": ariaDescribedBy,\n onBlur,\n onKeyDown,\n onClick,\n ref,\n ...inputProps\n}: ComboboxProps) => {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const listboxId = `${inputId}-listbox`;\n const messageId = `${inputId}-message`;\n const optionId = (index: number) => `${inputId}-option-${index}`;\n const hasError = Boolean(errorText);\n const hasMessage = Boolean(errorText || assistiveText);\n const labelId = `${inputId}-label`;\n const inputRef = useRef<HTMLInputElement | null>(null);\n const setRef = useMemo(() => mergeRefs(inputRef, ref), [ref]);\n // 이 컴포넌트가 onChange로 낸 값. 바깥에서 value를 바꿨는지 구분한다.\n const emittedValue = useRef<string | null>(null);\n // 키보드로 옮길 때만 현재 항목을 스크롤한다. 마우스 hover로 스크롤하면 목록이 흔들린다.\n const scrollOnMove = useRef(false);\n\n const normalized = options.map((option) => (typeof option === \"string\" ? { value: option, label: option } : option));\n const selected = normalized.find((option) => option.value === value);\n // null이면 검색 중이 아니고, 입력에는 고른 옵션 이름이 보인다.\n const [query, setQuery] = useState<string | null>(null);\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n\n // 인덱스는 전체 옵션 기준이라 거르더라도 id가 다른 옵션으로 넘어가지 않는다.\n const matches = normalized\n .map((option, index) => ({ option, index }))\n .filter(({ option }) => (query ? filter(option, query) : true));\n const expanded = open && !disabled && (matches.length > 0 || emptyText !== undefined);\n const enabledMatches = matches.filter(({ option }) => !option.disabled);\n\n useEffect(() => {\n const shouldScroll = scrollOnMove.current;\n scrollOnMove.current = false;\n if (!expanded || activeIndex < 0 || !shouldScroll) return;\n document.getElementById(optionId(activeIndex))?.scrollIntoView?.({ block: \"nearest\" });\n // optionId는 inputId에서만 바뀐다.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [expanded, activeIndex]);\n\n // 바깥에서 value가 바뀌면(폼 reset 등) 입력 중인 검색어를 버리고 새 값의 이름을 보인다.\n useEffect(() => {\n if (value !== emittedValue.current) setQuery(null);\n emittedValue.current = null;\n }, [value]);\n\n // 부모가 낸 값을 받아들이지 않아 value가 그대로면, 다음 바깥 변경을 우리 값으로 오인하지 않게 비운다.\n useEffect(() => {\n emittedValue.current = null;\n });\n\n // 브라우저 검증은 보이는 글자를 본다. 글자는 있는데 고른 옵션이 없으면 통과하지 않게 한다.\n const selectionMissing = Boolean(required && !selected && query);\n useEffect(() => {\n inputRef.current?.setCustomValidity(selectionMissing ? invalidSelectionText : \"\");\n }, [selectionMissing, invalidSelectionText]);\n\n const emit = (next: string) => {\n emittedValue.current = next;\n onChange(next);\n };\n\n const openList = () => {\n scrollOnMove.current = true;\n setOpen(true);\n setActiveIndex(selected && !selected.disabled ? normalized.indexOf(selected) : -1);\n };\n\n const close = () => {\n setOpen(false);\n setQuery(null);\n setActiveIndex(-1);\n };\n\n const pick = (option: ComboboxOption) => {\n if (option.disabled) return;\n emit(option.value);\n close();\n };\n\n const move = (step: 1 | -1) => {\n if (enabledMatches.length === 0) return;\n const position = enabledMatches.findIndex(({ index }) => index === activeIndex);\n const next =\n position === -1\n ? step === 1\n ? 0\n : enabledMatches.length - 1\n : (position + step + enabledMatches.length) % enabledMatches.length;\n scrollOnMove.current = true;\n setActiveIndex(enabledMatches[next].index);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event);\n // IME 조합(한글·일본어) 중 Enter·방향키는 조합을 확정하는 키다. keyCode 229는 Safari용.\n if (event.defaultPrevented || event.nativeEvent.isComposing || event.keyCode === 229) return;\n\n switch (event.key) {\n case \"ArrowDown\":\n case \"ArrowUp\":\n event.preventDefault();\n if (open && event.altKey && event.key === \"ArrowUp\") {\n close();\n return;\n }\n if (!open) {\n // 열 때는 고른 옵션을, 고른 게 없으면 방향에 맞는 첫 옵션을 가리킨다. Alt는 열기만 한다.\n setOpen(true);\n const selectedIndex = selected && !selected.disabled ? normalized.indexOf(selected) : -1;\n const edge = event.key === \"ArrowDown\" ? enabledMatches[0] : enabledMatches[enabledMatches.length - 1];\n scrollOnMove.current = true;\n setActiveIndex(selectedIndex >= 0 || event.altKey ? selectedIndex : (edge?.index ?? -1));\n return;\n }\n move(event.key === \"ArrowDown\" ? 1 : -1);\n return;\n case \"Enter\":\n if (expanded && activeIndex >= 0) {\n event.preventDefault();\n pick(normalized[activeIndex]);\n }\n return;\n case \"Escape\":\n if (expanded || query !== null) {\n event.preventDefault();\n close();\n }\n return;\n }\n };\n\n const handleInput = (text: string) => {\n // 브라우저 자동완성처럼 옵션 이름과 똑같이 입력되면 그 옵션을 고른 것으로 본다.\n const exact = text.trim()\n ? normalized.find((option) => !option.disabled && normalize(option.label) === normalize(text))\n : undefined;\n if (exact) {\n if (exact.value !== value) emit(exact.value);\n } else if (value !== \"\") {\n emit(\"\");\n }\n\n // 포커스가 없을 때 들어온 입력(다른 칸에서 시작한 자동완성)은 목록을 열지 않는다.\n if (document.activeElement !== inputRef.current) {\n setQuery(exact ? null : text);\n return;\n }\n\n setQuery(text);\n setOpen(true);\n const firstMatch = normalized.findIndex((option) => !option.disabled && (text ? filter(option, text) : true));\n scrollOnMove.current = true;\n setActiveIndex(exact ? normalized.indexOf(exact) : text ? firstMatch : -1);\n };\n\n return (\n <div className={cn(\"flex w-full min-w-0 flex-col gap-2\", className)}>\n {label && (\n <FieldLabel id={labelId} htmlFor={inputId} size={size} required={required}>\n {label}\n </FieldLabel>\n )}\n <div className=\"relative\">\n <div className=\"relative\">\n <input\n {...inputProps}\n ref={setRef}\n id={inputId}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={expanded}\n aria-controls={listboxId}\n aria-autocomplete=\"list\"\n aria-activedescendant={expanded && activeIndex >= 0 ? optionId(activeIndex) : undefined}\n aria-invalid={hasError || undefined}\n aria-describedby={joinIds(ariaDescribedBy, hasMessage && messageId)}\n autoComplete={autoComplete}\n required={required}\n disabled={disabled}\n placeholder={placeholder}\n value={query ?? selected?.label ?? \"\"}\n onChange={(event) => handleInput(event.target.value)}\n onKeyDown={handleKeyDown}\n onClick={(event) => {\n onClick?.(event);\n if (!open && !event.defaultPrevented) openList();\n }}\n onBlur={(event) => {\n onBlur?.(event);\n close();\n }}\n className={cn(\n fieldContainerVariants({ size, hasError, disabled }),\n \"text-text-base-neutral-5 placeholder:text-text-base-neutral-2 w-full min-w-0 truncate outline-none disabled:cursor-not-allowed\",\n !disabled && !hasError && \"focus:border-border-base-neutral-4\",\n size === \"large\" ? \"pr-14\" : \"pr-12\",\n fieldValueFontSize(size),\n )}\n />\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={toggleLabel ?? label ?? inputProps[\"aria-label\"]}\n aria-controls={listboxId}\n aria-expanded={expanded}\n disabled={disabled}\n // 입력의 포커스를 유지해야 blur로 목록이 닫히지 않는다.\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n if (expanded) close();\n else openList();\n inputRef.current?.focus();\n }}\n className={cn(\n \"absolute inset-y-0 right-0 flex cursor-pointer items-center justify-center disabled:cursor-not-allowed\",\n size === \"large\" ? \"w-14\" : \"w-12\",\n )}\n >\n <ChevronDownIcon\n aria-hidden=\"true\"\n className={cn(\n \"size-6 transition-transform duration-200\",\n expanded ? \"text-icon-prominent-accent-1 rotate-180\" : \"text-icon-base-neutral-3\",\n )}\n />\n </button>\n </div>\n {name && <input type=\"hidden\" name={name} value={value} disabled={disabled} form={inputProps.form} />}\n <ul\n id={listboxId}\n role=\"listbox\"\n aria-labelledby={label ? labelId : undefined}\n aria-label={label ? undefined : inputProps[\"aria-label\"]}\n hidden={!expanded}\n onMouseDown={(event) => event.preventDefault()}\n className={cn(\n \"border-border-base-neutral-2 bg-surface-base-neutral-1 absolute z-20 mt-2 max-h-72 w-full overflow-y-auto border py-1 shadow-lg\",\n FIELD_RADIUS,\n )}\n >\n {matches.map(({ option, index }) => {\n const isSelected = option.value === value;\n return (\n <li\n key={option.value}\n id={optionId(index)}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled || undefined}\n onMouseMove={() => {\n scrollOnMove.current = false;\n if (!option.disabled) setActiveIndex(index);\n }}\n onClick={() => pick(option)}\n className={cn(\n \"text-text-base-neutral-5 flex cursor-pointer items-center gap-3 px-3 py-2.5 select-none\",\n size === \"large\" ? \"text-body-16-regular\" : \"text-body-14-regular\",\n index === activeIndex && \"bg-surface-base-neutral-2\",\n isSelected && \"font-medium\",\n option.disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <span className=\"min-w-0 flex-1 truncate\">{option.label}</span>\n {isSelected && (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n className=\"text-icon-prominent-accent-1 size-4 shrink-0\"\n >\n <path\n d=\"m4 10 3.5 3.5L16 5\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )}\n </li>\n );\n })}\n {matches.length === 0 && emptyText !== undefined && (\n <li role=\"presentation\" className=\"text-text-base-neutral-2 text-body-14-regular px-3 py-2.5\">\n {emptyText}\n </li>\n )}\n </ul>\n </div>\n <FieldMessage id={messageId} size={size} errorText={errorText} assistiveText={assistiveText} />\n </div>\n );\n};\n\nexport { Combobox };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { cva as e } from "class-variance-authority";
|
|
2
|
+
//#region src/components/ui/fieldStyles.ts
|
|
3
|
+
var t = "rounded-[4px]", n = e(`flex items-center ${t} bg-surface-base-neutral-2 border transition-colors duration-200`, {
|
|
4
|
+
variants: {
|
|
5
|
+
size: {
|
|
6
|
+
large: "gap-2 p-[15px] min-h-[56px]",
|
|
7
|
+
small: "gap-3 p-[11px] min-h-[48px]"
|
|
8
|
+
},
|
|
9
|
+
hasError: {
|
|
10
|
+
true: "border-border-prominent-error",
|
|
11
|
+
false: "border-transparent"
|
|
12
|
+
},
|
|
13
|
+
disabled: {
|
|
14
|
+
true: "opacity-50",
|
|
15
|
+
false: ""
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
size: "large",
|
|
20
|
+
disabled: !1,
|
|
21
|
+
hasError: !1
|
|
22
|
+
}
|
|
23
|
+
}), r = e("", {
|
|
24
|
+
variants: {
|
|
25
|
+
size: {
|
|
26
|
+
large: "text-body-16-regular",
|
|
27
|
+
small: "text-caption-12-medium"
|
|
28
|
+
},
|
|
29
|
+
hasError: {
|
|
30
|
+
true: "text-text-prominent-error",
|
|
31
|
+
false: "text-text-base-neutral-2"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
size: "large",
|
|
36
|
+
hasError: !1
|
|
37
|
+
}
|
|
38
|
+
}), i = (e) => e === "large" ? "text-title-18-bold" : "text-title-14-bold", a = (e) => e === "large" ? "text-title-20-regular" : "text-body-16-regular", o = (...e) => e.filter(Boolean).join(" ") || void 0;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { a, r as i, n, o, i as r, t };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=fieldStyles-DyZu__hI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export { Chip } from './src/components/chip/Chip';
|
|
|
7
7
|
export { CTAButton } from './src/components/cta-button/CTAButton';
|
|
8
8
|
export { Popup } from './src/components/popup/Popup';
|
|
9
9
|
export { TextFieldNormal, TextFieldSelect, TextFieldWithButton } from './src/components/text-field/TextField';
|
|
10
|
+
export { Select, type SelectOption } from './src/components/select/Select';
|
|
11
|
+
export { Combobox, type ComboboxOption } from './src/components/combobox/Combobox';
|
|
10
12
|
export { CancelFilledIcon } from './src/components/icons/action/CancelFilledIcon';
|
|
11
13
|
export { CancelIcon } from './src/components/icons/action/CancelIcon';
|
|
12
14
|
export { ChevronDownIcon } from './src/components/icons/action/ChevronDownIcon';
|
package/dist/index.es.js
CHANGED
|
@@ -9,16 +9,18 @@ import { t as s } from "./Popup-DRf-ERpL.js";
|
|
|
9
9
|
import { CancelFilledIcon as c } from "./icons/action/cancel-filled.js";
|
|
10
10
|
import { ChevronLeftIcon as l } from "./icons/action/chevron-left.js";
|
|
11
11
|
import { TextFieldNormal as u, TextFieldSelect as d, TextFieldWithButton as f } from "./text-field.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
12
|
+
import { ChevronDownIcon as p } from "./icons/action/chevron-down.js";
|
|
13
|
+
import { Select as m } from "./select.js";
|
|
14
|
+
import { Combobox as h } from "./combobox.js";
|
|
15
|
+
import { CancelIcon as g } from "./icons/action/cancel.js";
|
|
16
|
+
import { ChevronRightIcon as _ } from "./icons/action/chevron-right.js";
|
|
17
|
+
import { ChevronUpIcon as v } from "./icons/action/chevron-up.js";
|
|
18
|
+
import { FilterIcon as y } from "./icons/action/filter.js";
|
|
19
|
+
import { RetryIcon as b } from "./icons/action/retry.js";
|
|
20
|
+
import { SortingIcon as x } from "./icons/action/sorting.js";
|
|
21
|
+
import { CloseIcon as S } from "./icons/static/close.js";
|
|
22
|
+
import { DeleteIcon as C } from "./icons/static/delete.js";
|
|
23
|
+
import { RecentIcon as w } from "./icons/static/recent.js";
|
|
24
|
+
import { ReportIcon as T } from "./icons/static/report.js";
|
|
25
|
+
import { ShieldDoneIcon as E } from "./icons/static/shield-done.js";
|
|
26
|
+
export { i as Badge, o as CTAButton, c as CancelFilledIcon, g as CancelIcon, n as Checkbox, p as ChevronDownIcon, l as ChevronLeftIcon, _ as ChevronRightIcon, v as ChevronUpIcon, a as Chip, S as CloseIcon, h as Combobox, C as DeleteIcon, y as FilterIcon, s as Popup, e as Radio, w as RecentIcon, T as ReportIcon, b as RetryIcon, m as Select, E as ShieldDoneIcon, x as SortingIcon, t as Tabs, u as TextFieldNormal, d as TextFieldSelect, f as TextFieldWithButton, r as Toggle };
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
package/dist/select.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "./TailwindUtil-DiNvXuNl.js";
|
|
3
|
+
import { a as t, n, o as r } from "./fieldStyles-DyZu__hI.js";
|
|
4
|
+
import { ChevronDownIcon as i } from "./icons/action/chevron-down.js";
|
|
5
|
+
import { n as a, r as o, t as s } from "./mergeRefs-BHwdBwNQ.js";
|
|
6
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
|
+
import { useEffect as u, useId as d, useMemo as f, useRef as p, useState as m } from "react";
|
|
8
|
+
//#region src/components/select/Select.tsx
|
|
9
|
+
var h = ({ id: h, label: g, options: _, value: v, defaultValue: y, onChange: b, placeholder: x, errorText: S, assistiveText: C, size: w = "large", required: T, disabled: E = !1, className: D, "aria-describedby": O, ref: k, ...A }) => {
|
|
10
|
+
let j = d(), M = h ?? j, N = `${M}-message`, P = !!S, F = !!(S || C), [I, L] = m(y ?? ""), R = v ?? I, z = _.map((e) => typeof e == "string" ? {
|
|
11
|
+
value: e,
|
|
12
|
+
label: e
|
|
13
|
+
} : e), B = x === void 0 && !z.some((e) => e.value === R), V = p(null), H = f(() => s(V, k), [k]);
|
|
14
|
+
return u(() => {
|
|
15
|
+
let e = V.current?.form;
|
|
16
|
+
if (v !== void 0 || !e) return;
|
|
17
|
+
let t = () => setTimeout(() => L(V.current?.value ?? ""));
|
|
18
|
+
return e.addEventListener("reset", t), () => e.removeEventListener("reset", t);
|
|
19
|
+
}, [v]), /* @__PURE__ */ l("div", {
|
|
20
|
+
className: e("flex w-full min-w-0 flex-col gap-2", D),
|
|
21
|
+
children: [
|
|
22
|
+
g && /* @__PURE__ */ c(a, {
|
|
23
|
+
htmlFor: M,
|
|
24
|
+
size: w,
|
|
25
|
+
required: T,
|
|
26
|
+
children: g
|
|
27
|
+
}),
|
|
28
|
+
/* @__PURE__ */ l("div", {
|
|
29
|
+
className: "relative",
|
|
30
|
+
children: [/* @__PURE__ */ l("select", {
|
|
31
|
+
...A,
|
|
32
|
+
ref: H,
|
|
33
|
+
id: M,
|
|
34
|
+
value: v,
|
|
35
|
+
defaultValue: v === void 0 ? y ?? "" : void 0,
|
|
36
|
+
required: T,
|
|
37
|
+
disabled: E,
|
|
38
|
+
"aria-invalid": P || void 0,
|
|
39
|
+
"aria-describedby": r(O, F && N),
|
|
40
|
+
onChange: (e) => {
|
|
41
|
+
L(e.target.value), b?.(e.target.value);
|
|
42
|
+
},
|
|
43
|
+
className: e(n({
|
|
44
|
+
size: w,
|
|
45
|
+
hasError: P,
|
|
46
|
+
disabled: E
|
|
47
|
+
}), "w-full min-w-0 cursor-pointer appearance-none truncate outline-none disabled:cursor-not-allowed", !E && !P && "focus:border-border-base-neutral-4", w === "large" ? "pr-12" : "pr-11", t(w), R ? "text-text-base-neutral-5" : "text-text-base-neutral-2"),
|
|
48
|
+
children: [
|
|
49
|
+
x !== void 0 && /* @__PURE__ */ c("option", {
|
|
50
|
+
value: "",
|
|
51
|
+
children: x
|
|
52
|
+
}),
|
|
53
|
+
B && /* @__PURE__ */ c("option", {
|
|
54
|
+
value: R,
|
|
55
|
+
hidden: !0,
|
|
56
|
+
disabled: !0
|
|
57
|
+
}),
|
|
58
|
+
z.map((e) => /* @__PURE__ */ c("option", {
|
|
59
|
+
value: e.value,
|
|
60
|
+
disabled: e.disabled,
|
|
61
|
+
className: "text-text-base-neutral-5",
|
|
62
|
+
children: e.label
|
|
63
|
+
}, e.value))
|
|
64
|
+
]
|
|
65
|
+
}), /* @__PURE__ */ c(i, {
|
|
66
|
+
"aria-hidden": "true",
|
|
67
|
+
className: e("text-icon-base-neutral-3 pointer-events-none absolute top-1/2 size-6 -translate-y-1/2", w === "large" ? "right-4" : "right-3")
|
|
68
|
+
})]
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ c(o, {
|
|
71
|
+
id: N,
|
|
72
|
+
size: w,
|
|
73
|
+
errorText: S,
|
|
74
|
+
assistiveText: C
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { h as Select };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","names":[],"sources":["../src/components/select/Select.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\n\nimport { ChevronDownIcon } from \"../icons/action/ChevronDownIcon\";\n\nimport type { ComponentPropsWithRef, ReactNode } from \"react\";\n\nimport { FieldLabel, FieldMessage } from \"@/components/ui/field\";\nimport { fieldContainerVariants, fieldValueFontSize, joinIds, type FieldSize } from \"@/components/ui/fieldStyles\";\nimport { mergeRefs } from \"@/utils/mergeRefs\";\nimport { cn } from \"@/utils/TailwindUtil\";\n\nexport interface SelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\ninterface SelectProps\n extends Omit<ComponentPropsWithRef<\"select\">, \"size\" | \"value\" | \"defaultValue\" | \"onChange\" | \"children\"> {\n /** 칸 위에 보이는 이름. `<label>`로 `<select>`에 연결된다. */\n label?: string;\n /** 문자열 옵션은 값과 표시 이름이 같다. */\n options: (string | SelectOption)[];\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n /** 값이 없을 때 보이는 첫 옵션(값 `\"\"`). `required`이면 이 옵션으로는 제출되지 않는다. */\n placeholder?: string;\n errorText?: string;\n assistiveText?: ReactNode;\n size?: FieldSize;\n}\n\n/** 목록에서 하나를 고르는 입력. 브라우저 기본 `<select>`라 모바일 선택기·폼 검증·키보드 조작을 그대로 쓴다. */\nconst Select = ({\n id,\n label,\n options,\n value,\n defaultValue,\n onChange,\n placeholder,\n errorText,\n assistiveText,\n size = \"large\",\n required,\n disabled = false,\n className,\n \"aria-describedby\": ariaDescribedBy,\n ref,\n ...selectProps\n}: SelectProps) => {\n const generatedId = useId();\n const selectId = id ?? generatedId;\n const messageId = `${selectId}-message`;\n const hasError = Boolean(errorText);\n const hasMessage = Boolean(errorText || assistiveText);\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? \"\");\n const currentValue = value ?? uncontrolledValue;\n const normalized = options.map((option) => (typeof option === \"string\" ? { value: option, label: option } : option));\n // placeholder 없이 옵션에 없는 값(예: \"\")이면 브라우저가 첫 옵션을 보여 주므로, 숨긴 빈 옵션을 고른 상태로 둔다.\n const needsEmptyOption = placeholder === undefined && !normalized.some((option) => option.value === currentValue);\n const selectRef = useRef<HTMLSelectElement | null>(null);\n const setRef = useMemo(() => mergeRefs(selectRef, ref), [ref]);\n\n // 비제어일 때 form.reset()은 onChange 없이 값을 되돌리므로 placeholder 색을 다시 맞춘다.\n useEffect(() => {\n const form = selectRef.current?.form;\n if (value !== undefined || !form) return;\n const sync = () => setTimeout(() => setUncontrolledValue(selectRef.current?.value ?? \"\"));\n form.addEventListener(\"reset\", sync);\n return () => form.removeEventListener(\"reset\", sync);\n }, [value]);\n\n return (\n <div className={cn(\"flex w-full min-w-0 flex-col gap-2\", className)}>\n {label && (\n <FieldLabel htmlFor={selectId} size={size} required={required}>\n {label}\n </FieldLabel>\n )}\n <div className=\"relative\">\n <select\n {...selectProps}\n ref={setRef}\n id={selectId}\n value={value}\n defaultValue={value === undefined ? (defaultValue ?? \"\") : undefined}\n required={required}\n disabled={disabled}\n aria-invalid={hasError || undefined}\n aria-describedby={joinIds(ariaDescribedBy, hasMessage && messageId)}\n onChange={(event) => {\n setUncontrolledValue(event.target.value);\n onChange?.(event.target.value);\n }}\n className={cn(\n fieldContainerVariants({ size, hasError, disabled }),\n \"w-full min-w-0 cursor-pointer appearance-none truncate outline-none disabled:cursor-not-allowed\",\n !disabled && !hasError && \"focus:border-border-base-neutral-4\",\n size === \"large\" ? \"pr-12\" : \"pr-11\",\n fieldValueFontSize(size),\n currentValue ? \"text-text-base-neutral-5\" : \"text-text-base-neutral-2\",\n )}\n >\n {placeholder !== undefined && <option value=\"\">{placeholder}</option>}\n {needsEmptyOption && <option value={currentValue} hidden disabled />}\n {normalized.map((option) => (\n <option\n key={option.value}\n value={option.value}\n disabled={option.disabled}\n className=\"text-text-base-neutral-5\"\n >\n {option.label}\n </option>\n ))}\n </select>\n <ChevronDownIcon\n aria-hidden=\"true\"\n className={cn(\n \"text-icon-base-neutral-3 pointer-events-none absolute top-1/2 size-6 -translate-y-1/2\",\n size === \"large\" ? \"right-4\" : \"right-3\",\n )}\n />\n </div>\n <FieldMessage id={messageId} size={size} errorText={errorText} assistiveText={assistiveText} />\n </div>\n );\n};\n\nexport { Select };\n"],"mappings":";;;;;;;;AAoCA,IAAM,KAAU,EACd,OACA,UACA,YACA,UACA,iBACA,aACA,gBACA,cACA,kBACA,UAAO,SACP,aACA,cAAW,IACX,cACA,oBAAoB,GACpB,QACA,GAAG,QACc;CACjB,IAAM,IAAc,EAAM,GACpB,IAAW,KAAM,GACjB,IAAY,GAAG,EAAS,WACxB,IAAW,EAAQ,GACnB,IAAa,GAAQ,KAAa,IAClC,CAAC,GAAmB,KAAwB,EAAS,KAAgB,EAAE,GACvE,IAAe,KAAS,GACxB,IAAa,EAAQ,KAAK,MAAY,OAAO,KAAW,WAAW;EAAE,OAAO;EAAQ,OAAO;CAAO,IAAI,CAAO,GAE7G,IAAmB,MAAgB,KAAA,KAAa,CAAC,EAAW,MAAM,MAAW,EAAO,UAAU,CAAY,GAC1G,IAAY,EAAiC,IAAI,GACjD,IAAS,QAAc,EAAU,GAAW,CAAG,GAAG,CAAC,CAAG,CAAC;CAW7D,OARA,QAAgB;EACd,IAAM,IAAO,EAAU,SAAS;EAChC,IAAI,MAAU,KAAA,KAAa,CAAC,GAAM;EAClC,IAAM,UAAa,iBAAiB,EAAqB,EAAU,SAAS,SAAS,EAAE,CAAC;EAExF,OADA,EAAK,iBAAiB,SAAS,CAAI,SACtB,EAAK,oBAAoB,SAAS,CAAI;CACrD,GAAG,CAAC,CAAK,CAAC,GAGR,kBAAC,OAAD;EAAK,WAAW,EAAG,sCAAsC,CAAS;YAAlE;GACG,KACC,kBAAC,GAAD;IAAY,SAAS;IAAgB;IAAgB;cAClD;GACS,CAAA;GAEd,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,GAAI;KACJ,KAAK;KACL,IAAI;KACG;KACP,cAAc,MAAU,KAAA,IAAa,KAAgB,KAAM,KAAA;KACjD;KACA;KACV,gBAAc,KAAY,KAAA;KAC1B,oBAAkB,EAAQ,GAAiB,KAAc,CAAS;KAClE,WAAW,MAAU;MAEnB,AADA,EAAqB,EAAM,OAAO,KAAK,GACvC,IAAW,EAAM,OAAO,KAAK;KAC/B;KACA,WAAW,EACT,EAAuB;MAAE;MAAM;MAAU;KAAS,CAAC,GACnD,mGACA,CAAC,KAAY,CAAC,KAAY,sCAC1B,MAAS,UAAU,UAAU,SAC7B,EAAmB,CAAI,GACvB,IAAe,6BAA6B,0BAC9C;eArBF;MAuBG,MAAgB,KAAA,KAAa,kBAAC,UAAD;OAAQ,OAAM;iBAAI;MAAoB,CAAA;MACnE,KAAoB,kBAAC,UAAD;OAAQ,OAAO;OAAc,QAAA;OAAO,UAAA;MAAU,CAAA;MAClE,EAAW,KAAK,MACf,kBAAC,UAAD;OAEE,OAAO,EAAO;OACd,UAAU,EAAO;OACjB,WAAU;iBAET,EAAO;MACF,GAND,EAAO,KAMN,CACT;KACK;QACR,kBAAC,GAAD;KACE,eAAY;KACZ,WAAW,EACT,yFACA,MAAS,UAAU,YAAY,SACjC;IACD,CAAA,CACE;;GACL,kBAAC,GAAD;IAAc,IAAI;IAAiB;IAAiB;IAA0B;GAAgB,CAAA;EAC3F;;AAET"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
interface Props extends Omit<
|
|
1
|
+
import { ComponentPropsWithRef } from 'react';
|
|
2
|
+
interface Props extends Omit<ComponentPropsWithRef<"input">, "type" | "checked" | "onChange"> {
|
|
3
3
|
className?: string;
|
|
4
4
|
id?: string;
|
|
5
5
|
onChange?: (newValue: boolean) => void;
|
|
6
6
|
disabled?: boolean;
|
|
7
|
+
/** 제어 컴포넌트로 쓸 때의 체크 상태. 넘기지 않으면 비제어 컴포넌트가 되고, 처음 상태는 `defaultChecked`로 정한다. */
|
|
7
8
|
isChecked?: boolean;
|
|
8
9
|
}
|
|
9
10
|
declare const Checkbox: ({ className, id, onChange, disabled, isChecked, ...inputProps }: Props) => import("react").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import { FieldSize } from '../ui/fieldStyles';
|
|
3
|
+
export interface ComboboxOption {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface ComboboxProps extends Omit<ComponentPropsWithRef<"input">, "size" | "value" | "defaultValue" | "onChange" | "type" | "role" | "children"> {
|
|
9
|
+
/** 칸 위에 보이는 이름. `<label>`로 입력에 연결된다. */
|
|
10
|
+
label?: string;
|
|
11
|
+
/** 문자열 옵션은 값과 표시 이름이 같다. */
|
|
12
|
+
options: (string | ComboboxOption)[];
|
|
13
|
+
/** 고른 옵션의 값. 고르지 않았으면 `""`. */
|
|
14
|
+
value: string;
|
|
15
|
+
/** 옵션을 고르면 그 값으로, 고른 뒤 다시 입력하기 시작하면 `""`로 호출된다. */
|
|
16
|
+
onChange: (value: string) => void;
|
|
17
|
+
/** 입력한 검색어로 옵션을 거른다. 기본은 대소문자·공백을 무시한 부분 일치. */
|
|
18
|
+
filter?: (option: ComboboxOption, query: string) => boolean;
|
|
19
|
+
/** 맞는 옵션이 없을 때 목록에 보이는 문구. 없으면 목록을 닫는다. */
|
|
20
|
+
emptyText?: ReactNode;
|
|
21
|
+
/** 목록 열기 버튼의 접근 가능한 이름. 기본은 `label`. */
|
|
22
|
+
toggleLabel?: string;
|
|
23
|
+
/** `required`인데 입력한 글자가 옵션으로 골라지지 않았을 때 브라우저 검증 메시지. 다국어 페이지에서는 번역해 넘긴다. */
|
|
24
|
+
invalidSelectionText?: string;
|
|
25
|
+
errorText?: string;
|
|
26
|
+
assistiveText?: ReactNode;
|
|
27
|
+
size?: FieldSize;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 입력해서 검색하고 목록에서 하나를 고르는 입력(WAI-ARIA combobox, list autocomplete).
|
|
31
|
+
* 포커스는 입력에 남고 목록의 현재 항목은 `aria-activedescendant`로 알린다.
|
|
32
|
+
* 고른 값만 `value`가 되고, 입력한 글자는 고르기 전까지 값이 아니다.
|
|
33
|
+
*/
|
|
34
|
+
declare const Combobox: ({ id, label, options, value, onChange, filter, emptyText, toggleLabel, invalidSelectionText, errorText, assistiveText, size, name, required, disabled, placeholder, className, autoComplete, "aria-describedby": ariaDescribedBy, onBlur, onKeyDown, onClick, ref, ...inputProps }: ComboboxProps) => import("react").JSX.Element;
|
|
35
|
+
export { Combobox };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import { FieldSize } from '../ui/fieldStyles';
|
|
3
|
+
export interface SelectOption {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface SelectProps extends Omit<ComponentPropsWithRef<"select">, "size" | "value" | "defaultValue" | "onChange" | "children"> {
|
|
9
|
+
/** 칸 위에 보이는 이름. `<label>`로 `<select>`에 연결된다. */
|
|
10
|
+
label?: string;
|
|
11
|
+
/** 문자열 옵션은 값과 표시 이름이 같다. */
|
|
12
|
+
options: (string | SelectOption)[];
|
|
13
|
+
value?: string;
|
|
14
|
+
defaultValue?: string;
|
|
15
|
+
onChange?: (value: string) => void;
|
|
16
|
+
/** 값이 없을 때 보이는 첫 옵션(값 `""`). `required`이면 이 옵션으로는 제출되지 않는다. */
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
errorText?: string;
|
|
19
|
+
assistiveText?: ReactNode;
|
|
20
|
+
size?: FieldSize;
|
|
21
|
+
}
|
|
22
|
+
/** 목록에서 하나를 고르는 입력. 브라우저 기본 `<select>`라 모바일 선택기·폼 검증·키보드 조작을 그대로 쓴다. */
|
|
23
|
+
declare const Select: ({ id, label, options, value, defaultValue, onChange, placeholder, errorText, assistiveText, size, required, disabled, className, "aria-describedby": ariaDescribedBy, ref, ...selectProps }: SelectProps) => import("react").JSX.Element;
|
|
24
|
+
export { Select };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FieldSize } from './fieldStyles';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
export declare const FieldLabel: ({ id, htmlFor, size, required, children, }: {
|
|
4
|
+
id?: string;
|
|
5
|
+
htmlFor: string;
|
|
6
|
+
size: FieldSize;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
10
|
+
export declare const FieldMessage: ({ id, size, errorText, assistiveText, }: {
|
|
11
|
+
id: string;
|
|
12
|
+
size: FieldSize;
|
|
13
|
+
errorText?: string;
|
|
14
|
+
assistiveText?: ReactNode;
|
|
15
|
+
}) => import("react").JSX.Element | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const FIELD_RADIUS = "rounded-[4px]";
|
|
2
|
+
export declare const fieldContainerVariants: (props?: ({
|
|
3
|
+
size?: "small" | "large" | null | undefined;
|
|
4
|
+
hasError?: boolean | null | undefined;
|
|
5
|
+
disabled?: boolean | null | undefined;
|
|
6
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
7
|
+
export declare const fieldMessageVariants: (props?: ({
|
|
8
|
+
size?: "small" | "large" | null | undefined;
|
|
9
|
+
hasError?: boolean | null | undefined;
|
|
10
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
11
|
+
export type FieldSize = "large" | "small";
|
|
12
|
+
export declare const fieldLabelFontSize: (size: FieldSize) => "text-title-18-bold" | "text-title-14-bold";
|
|
13
|
+
export declare const fieldValueFontSize: (size: FieldSize) => "text-title-20-regular" | "text-body-16-regular";
|
|
14
|
+
export declare const joinIds: (...ids: (string | false | undefined)[]) => string | undefined;
|
package/dist/text-field.js
CHANGED
|
@@ -3,70 +3,36 @@ 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
5
|
import { ChevronLeftIcon as r } from "./icons/action/chevron-left.js";
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
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";
|
|
9
10
|
//#region src/components/text-field/TextField.tsx
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
small: "gap-3 p-[11px] min-h-[48px]"
|
|
15
|
-
},
|
|
16
|
-
hasError: {
|
|
17
|
-
true: "border-border-prominent-error",
|
|
18
|
-
false: "border-transparent"
|
|
19
|
-
},
|
|
20
|
-
disabled: {
|
|
21
|
-
true: "opacity-50",
|
|
22
|
-
false: ""
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
defaultVariants: {
|
|
26
|
-
size: "large",
|
|
27
|
-
disabled: !1,
|
|
28
|
-
hasError: !1
|
|
29
|
-
}
|
|
30
|
-
}), l = s("", {
|
|
31
|
-
variants: {
|
|
32
|
-
size: {
|
|
33
|
-
large: "text-body-16-regular",
|
|
34
|
-
small: "text-caption-12-medium"
|
|
35
|
-
},
|
|
36
|
-
hasError: {
|
|
37
|
-
true: "text-text-prominent-error",
|
|
38
|
-
false: "text-text-base-neutral-2"
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
defaultVariants: {
|
|
42
|
-
size: "large",
|
|
43
|
-
hasError: !1
|
|
44
|
-
}
|
|
45
|
-
}), u = o.forwardRef(({ onChange: t, subtitle: r, isRequired: s = !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) => {
|
|
46
|
-
let S = !!d, C = o.useRef(null);
|
|
47
|
-
o.useImperativeHandle(x, () => C.current);
|
|
48
|
-
let w = o.useCallback(() => {
|
|
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(() => {
|
|
49
15
|
C.current?.focus();
|
|
50
16
|
}, []), 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";
|
|
51
|
-
return /* @__PURE__ */
|
|
17
|
+
return /* @__PURE__ */ s("div", {
|
|
52
18
|
className: e("flex flex-col gap-2", m),
|
|
53
19
|
children: [
|
|
54
|
-
r && /* @__PURE__ */
|
|
20
|
+
r && /* @__PURE__ */ s("span", {
|
|
55
21
|
className: e(k, "text-text-base-neutral-5"),
|
|
56
|
-
children: [r,
|
|
22
|
+
children: [r, l && /* @__PURE__ */ o("span", {
|
|
57
23
|
className: "text-text-prominent-accent-1",
|
|
58
24
|
children: "*"
|
|
59
25
|
})]
|
|
60
26
|
}),
|
|
61
|
-
/* @__PURE__ */
|
|
27
|
+
/* @__PURE__ */ s("div", {
|
|
62
28
|
onClick: f ? void 0 : w,
|
|
63
|
-
className: e("group overflow-hidden",
|
|
29
|
+
className: e("group overflow-hidden", a({
|
|
64
30
|
size: y,
|
|
65
31
|
disabled: f,
|
|
66
32
|
hasError: S
|
|
67
33
|
}), !f && !S && "focus-within:border-border-base-neutral-4", p && "h-[120px] items-start"),
|
|
68
34
|
children: [
|
|
69
|
-
p ? /* @__PURE__ */
|
|
35
|
+
p ? /* @__PURE__ */ o("textarea", {
|
|
70
36
|
...D,
|
|
71
37
|
onChange: t,
|
|
72
38
|
ref: C,
|
|
@@ -74,7 +40,7 @@ var c = s("flex items-center rounded-[4px] bg-surface-base-neutral-2 border tran
|
|
|
74
40
|
maxLength: v,
|
|
75
41
|
disabled: f,
|
|
76
42
|
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")
|
|
77
|
-
}) : /* @__PURE__ */
|
|
43
|
+
}) : /* @__PURE__ */ o("input", {
|
|
78
44
|
...E,
|
|
79
45
|
onChange: t,
|
|
80
46
|
ref: C,
|
|
@@ -83,11 +49,11 @@ var c = s("flex items-center rounded-[4px] bg-surface-base-neutral-2 border tran
|
|
|
83
49
|
disabled: f,
|
|
84
50
|
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")
|
|
85
51
|
}),
|
|
86
|
-
h && /* @__PURE__ */
|
|
52
|
+
h && /* @__PURE__ */ o("div", {
|
|
87
53
|
className: "shrink-0",
|
|
88
54
|
children: h
|
|
89
55
|
}),
|
|
90
|
-
/* @__PURE__ */
|
|
56
|
+
/* @__PURE__ */ o("button", {
|
|
91
57
|
type: "button",
|
|
92
58
|
onClick: () => t && t({ target: { value: "" } }),
|
|
93
59
|
tabIndex: -1,
|
|
@@ -96,20 +62,20 @@ var c = s("flex items-center rounded-[4px] bg-surface-base-neutral-2 border tran
|
|
|
96
62
|
flex: S,
|
|
97
63
|
"group-focus-within:flex": !f && T > 0
|
|
98
64
|
}),
|
|
99
|
-
children: /* @__PURE__ */
|
|
65
|
+
children: /* @__PURE__ */ o(n, { className: "text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer" })
|
|
100
66
|
})
|
|
101
67
|
]
|
|
102
68
|
}),
|
|
103
|
-
(u || d || v && g) && /* @__PURE__ */
|
|
69
|
+
(u || d || v && g) && /* @__PURE__ */ s("div", {
|
|
104
70
|
className: "flex items-center justify-between gap-2",
|
|
105
|
-
children: [(u || d) && /* @__PURE__ */
|
|
106
|
-
className: e(A,
|
|
71
|
+
children: [(u || d) && /* @__PURE__ */ o("span", {
|
|
72
|
+
className: e(A, i({
|
|
107
73
|
size: y,
|
|
108
74
|
hasError: S
|
|
109
75
|
})),
|
|
110
76
|
children: d || u
|
|
111
|
-
}), v && g && /* @__PURE__ */
|
|
112
|
-
className: e("ml-auto", A,
|
|
77
|
+
}), v && g && /* @__PURE__ */ s("span", {
|
|
78
|
+
className: e("ml-auto", A, i({
|
|
113
79
|
size: y,
|
|
114
80
|
hasError: S
|
|
115
81
|
})),
|
|
@@ -124,7 +90,7 @@ var c = s("flex items-center rounded-[4px] bg-surface-base-neutral-2 border tran
|
|
|
124
90
|
});
|
|
125
91
|
});
|
|
126
92
|
u.displayName = "TextFieldNormal";
|
|
127
|
-
var d =
|
|
93
|
+
var d = l("flex items-center justify-between rounded-[4px] bg-surface-base-neutral-2 border transition-colors duration-200", {
|
|
128
94
|
variants: {
|
|
129
95
|
size: {
|
|
130
96
|
large: "gap-2 p-[15px] min-h-[56px]",
|
|
@@ -140,44 +106,44 @@ var d = s("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
|
|
|
140
106
|
}
|
|
141
107
|
},
|
|
142
108
|
defaultVariants: { size: "large" }
|
|
143
|
-
}), f = ({ label: t, placeholder: n, value:
|
|
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" }) => {
|
|
144
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";
|
|
145
|
-
return /* @__PURE__ */
|
|
111
|
+
return /* @__PURE__ */ s("div", {
|
|
146
112
|
className: e("flex w-full flex-col gap-2", m),
|
|
147
113
|
children: [
|
|
148
|
-
t && /* @__PURE__ */
|
|
114
|
+
t && /* @__PURE__ */ s("div", {
|
|
149
115
|
className: "flex items-start",
|
|
150
|
-
children: [/* @__PURE__ */
|
|
116
|
+
children: [/* @__PURE__ */ o("span", {
|
|
151
117
|
className: e(_, "text-text-base-neutral-5"),
|
|
152
118
|
children: t
|
|
153
|
-
}),
|
|
119
|
+
}), c && /* @__PURE__ */ o("span", {
|
|
154
120
|
className: e(_, "text-text-prominent-accent-1"),
|
|
155
121
|
children: "*"
|
|
156
122
|
})]
|
|
157
123
|
}),
|
|
158
|
-
/* @__PURE__ */
|
|
124
|
+
/* @__PURE__ */ s("button", {
|
|
159
125
|
type: "button",
|
|
160
126
|
className: d({
|
|
161
127
|
size: h,
|
|
162
128
|
hasError: g,
|
|
163
|
-
disabled:
|
|
129
|
+
disabled: l
|
|
164
130
|
}),
|
|
165
131
|
onClick: p,
|
|
166
|
-
disabled:
|
|
167
|
-
children: [/* @__PURE__ */
|
|
168
|
-
className: e(v, "flex-1",
|
|
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"),
|
|
169
135
|
style: {
|
|
170
136
|
textAlign: "left",
|
|
171
137
|
overflow: "hidden",
|
|
172
138
|
textOverflow: "ellipsis"
|
|
173
139
|
},
|
|
174
|
-
children:
|
|
175
|
-
}), /* @__PURE__ */
|
|
140
|
+
children: a || n
|
|
141
|
+
}), /* @__PURE__ */ o(r, { className: "text-icon-base-neutral-3 rotate-270" })]
|
|
176
142
|
}),
|
|
177
|
-
(u || f) && /* @__PURE__ */
|
|
143
|
+
(u || f) && /* @__PURE__ */ o("div", {
|
|
178
144
|
className: "flex items-start gap-2",
|
|
179
|
-
children: /* @__PURE__ */
|
|
180
|
-
className:
|
|
145
|
+
children: /* @__PURE__ */ o("span", {
|
|
146
|
+
className: i({
|
|
181
147
|
size: h,
|
|
182
148
|
hasError: g
|
|
183
149
|
}),
|
|
@@ -186,33 +152,33 @@ var d = s("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
|
|
|
186
152
|
})
|
|
187
153
|
]
|
|
188
154
|
});
|
|
189
|
-
}, p =
|
|
190
|
-
let E = !!f, D =
|
|
191
|
-
|
|
192
|
-
let O =
|
|
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(() => {
|
|
193
159
|
D.current?.focus();
|
|
194
160
|
}, []), 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";
|
|
195
|
-
return /* @__PURE__ */
|
|
161
|
+
return /* @__PURE__ */ s("div", {
|
|
196
162
|
className: e("flex flex-col gap-2", h),
|
|
197
163
|
children: [
|
|
198
|
-
|
|
164
|
+
l && /* @__PURE__ */ s("span", {
|
|
199
165
|
className: e(N, "text-text-base-neutral-5"),
|
|
200
|
-
children: [
|
|
166
|
+
children: [l, u && /* @__PURE__ */ o("span", {
|
|
201
167
|
className: "text-text-prominent-accent-1",
|
|
202
168
|
children: "*"
|
|
203
169
|
})]
|
|
204
170
|
}),
|
|
205
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ s("div", {
|
|
206
172
|
className: "flex items-center gap-2",
|
|
207
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ s("div", {
|
|
208
174
|
onClick: p ? void 0 : O,
|
|
209
|
-
className: e("group flex-1 overflow-hidden",
|
|
175
|
+
className: e("group flex-1 overflow-hidden", a({
|
|
210
176
|
size: y,
|
|
211
177
|
disabled: p,
|
|
212
178
|
hasError: E
|
|
213
179
|
}), !p && !E && "focus-within:border-border-base-neutral-4", m && "h-[120px] items-start"),
|
|
214
180
|
children: [
|
|
215
|
-
m ? /* @__PURE__ */
|
|
181
|
+
m ? /* @__PURE__ */ o("textarea", {
|
|
216
182
|
...j,
|
|
217
183
|
onChange: r,
|
|
218
184
|
ref: D,
|
|
@@ -220,7 +186,7 @@ var d = s("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
|
|
|
220
186
|
maxLength: v,
|
|
221
187
|
disabled: p,
|
|
222
188
|
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")
|
|
223
|
-
}) : /* @__PURE__ */
|
|
189
|
+
}) : /* @__PURE__ */ o("input", {
|
|
224
190
|
...A,
|
|
225
191
|
onChange: r,
|
|
226
192
|
ref: D,
|
|
@@ -229,11 +195,11 @@ var d = s("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
|
|
|
229
195
|
disabled: p,
|
|
230
196
|
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")
|
|
231
197
|
}),
|
|
232
|
-
b && /* @__PURE__ */
|
|
198
|
+
b && /* @__PURE__ */ o("div", {
|
|
233
199
|
className: "shrink-0",
|
|
234
200
|
children: b
|
|
235
201
|
}),
|
|
236
|
-
/* @__PURE__ */
|
|
202
|
+
/* @__PURE__ */ o("button", {
|
|
237
203
|
type: "button",
|
|
238
204
|
onClick: () => r && r({ target: { value: "" } }),
|
|
239
205
|
tabIndex: -1,
|
|
@@ -242,12 +208,12 @@ var d = s("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
|
|
|
242
208
|
flex: E,
|
|
243
209
|
"group-focus-within:flex": !p && k > 0
|
|
244
210
|
}),
|
|
245
|
-
children: /* @__PURE__ */
|
|
211
|
+
children: /* @__PURE__ */ o(n, { className: "text-icon-base-neutral-3 h-6 w-6 shrink-0 cursor-pointer" })
|
|
246
212
|
})
|
|
247
213
|
]
|
|
248
|
-
}), /* @__PURE__ */
|
|
214
|
+
}), /* @__PURE__ */ o("div", {
|
|
249
215
|
className: "shrink-0",
|
|
250
|
-
children: /* @__PURE__ */
|
|
216
|
+
children: /* @__PURE__ */ o(t, {
|
|
251
217
|
label: x,
|
|
252
218
|
onClick: S,
|
|
253
219
|
size: "medium",
|
|
@@ -256,16 +222,16 @@ var d = s("flex items-center justify-between rounded-[4px] bg-surface-base-neutr
|
|
|
256
222
|
})
|
|
257
223
|
})]
|
|
258
224
|
}),
|
|
259
|
-
(d || f || v && g) && /* @__PURE__ */
|
|
225
|
+
(d || f || v && g) && /* @__PURE__ */ s("div", {
|
|
260
226
|
className: "flex items-center justify-between gap-2",
|
|
261
|
-
children: [(d || f) && /* @__PURE__ */
|
|
262
|
-
className: e(P,
|
|
227
|
+
children: [(d || f) && /* @__PURE__ */ o("span", {
|
|
228
|
+
className: e(P, i({
|
|
263
229
|
size: y,
|
|
264
230
|
hasError: E
|
|
265
231
|
})),
|
|
266
232
|
children: f || d
|
|
267
|
-
}), v && g && /* @__PURE__ */
|
|
268
|
-
className: e("ml-auto", P,
|
|
233
|
+
}), v && g && /* @__PURE__ */ s("span", {
|
|
234
|
+
className: e("ml-auto", P, i({
|
|
269
235
|
size: y,
|
|
270
236
|
hasError: E
|
|
271
237
|
})),
|
package/dist/text-field.js.map
CHANGED
|
@@ -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 { cn } from \"@/utils/TailwindUtil\";\n\n// TextField Normal 컴포넌트 스타일 정의\nconst textFieldNormalContainerVariants = cva(\n \"flex items-center 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 disabled: false,\n hasError: false,\n },\n },\n);\n\nconst textFieldAssistiveAreaVariants = 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\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 { 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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@petnow/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@11.1.3",
|
|
6
6
|
"scripts": {
|
|
@@ -117,6 +117,14 @@
|
|
|
117
117
|
"types": "./dist/src/components/text-field/TextField.d.ts",
|
|
118
118
|
"import": "./dist/text-field.js"
|
|
119
119
|
},
|
|
120
|
+
"./select": {
|
|
121
|
+
"types": "./dist/src/components/select/Select.d.ts",
|
|
122
|
+
"import": "./dist/select.js"
|
|
123
|
+
},
|
|
124
|
+
"./combobox": {
|
|
125
|
+
"types": "./dist/src/components/combobox/Combobox.d.ts",
|
|
126
|
+
"import": "./dist/combobox.js"
|
|
127
|
+
},
|
|
120
128
|
"./icons/action/cancel-filled": {
|
|
121
129
|
"types": "./dist/src/components/icons/action/CancelFilledIcon.d.ts",
|
|
122
130
|
"import": "./dist/icons/action/cancel-filled.js"
|