@eeennsu/web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/badge.d.ts +6 -0
  2. package/dist/badge.d.ts.map +1 -0
  3. package/dist/badge.js +17 -0
  4. package/dist/badge.js.map +1 -0
  5. package/dist/box.d.ts +8 -0
  6. package/dist/box.d.ts.map +1 -0
  7. package/dist/box.js +8 -0
  8. package/dist/box.js.map +1 -0
  9. package/dist/button-group.d.ts +8 -0
  10. package/dist/button-group.d.ts.map +1 -0
  11. package/dist/button-group.js +9 -0
  12. package/dist/button-group.js.map +1 -0
  13. package/dist/button.d.ts +19 -0
  14. package/dist/button.d.ts.map +1 -0
  15. package/dist/button.js +39 -0
  16. package/dist/button.js.map +1 -0
  17. package/dist/card.d.ts +8 -0
  18. package/dist/card.d.ts.map +1 -0
  19. package/dist/card.js +8 -0
  20. package/dist/card.js.map +1 -0
  21. package/dist/cn.d.ts +8 -0
  22. package/dist/cn.d.ts.map +1 -0
  23. package/dist/cn.js +10 -0
  24. package/dist/cn.js.map +1 -0
  25. package/dist/dialog.d.ts +11 -0
  26. package/dist/dialog.d.ts.map +1 -0
  27. package/dist/dialog.js +14 -0
  28. package/dist/dialog.js.map +1 -0
  29. package/dist/drawer.d.ts +10 -0
  30. package/dist/drawer.d.ts.map +1 -0
  31. package/dist/drawer.js +17 -0
  32. package/dist/drawer.js.map +1 -0
  33. package/dist/form.d.ts +12 -0
  34. package/dist/form.d.ts.map +1 -0
  35. package/dist/form.js +15 -0
  36. package/dist/form.js.map +1 -0
  37. package/dist/icon.d.ts +25 -0
  38. package/dist/icon.d.ts.map +1 -0
  39. package/dist/icon.js +49 -0
  40. package/dist/icon.js.map +1 -0
  41. package/dist/index.d.ts +131 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +37 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/input.d.ts +13 -0
  46. package/dist/input.d.ts.map +1 -0
  47. package/dist/input.js +30 -0
  48. package/dist/input.js.map +1 -0
  49. package/dist/label.d.ts +8 -0
  50. package/dist/label.d.ts.map +1 -0
  51. package/dist/label.js +8 -0
  52. package/dist/label.js.map +1 -0
  53. package/dist/stack.d.ts +11 -0
  54. package/dist/stack.d.ts.map +1 -0
  55. package/dist/stack.js +26 -0
  56. package/dist/stack.js.map +1 -0
  57. package/dist/text.d.ts +10 -0
  58. package/dist/text.d.ts.map +1 -0
  59. package/dist/text.js +31 -0
  60. package/dist/text.js.map +1 -0
  61. package/dist/textarea.d.ts +10 -0
  62. package/dist/textarea.d.ts.map +1 -0
  63. package/dist/textarea.js +13 -0
  64. package/dist/textarea.js.map +1 -0
  65. package/dist/tooltip.d.ts +12 -0
  66. package/dist/tooltip.d.ts.map +1 -0
  67. package/dist/tooltip.js +14 -0
  68. package/dist/tooltip.js.map +1 -0
  69. package/package.json +46 -0
  70. package/themes/bakery.css +16 -0
  71. package/themes/base.css +16 -0
@@ -0,0 +1,6 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ type BadgeProps = Contracts<"web">["Badge"];
4
+ export declare const Badge: FC<BadgeProps>;
5
+ export {};
6
+ //# sourceMappingURL=badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../src/badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC,KAAK,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;AAkB5C,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAWhC,CAAC"}
package/dist/badge.js ADDED
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "./cn.js";
3
+ /** Button 과 같은 semantic 매핑이되 hover 가 없다(§4.2). */
4
+ const variants = {
5
+ primary: "bg-brand text-fg-on-brand",
6
+ secondary: "bg-surface-muted text-fg",
7
+ danger: "bg-danger text-fg-on-danger",
8
+ };
9
+ /**
10
+ * 투명 테두리를 둔다 — 같은 `py + text` 조합에서 Input 과 높이를 맞추기 위해서다(plan D-6).
11
+ */
12
+ const sizes = {
13
+ sm: "px-2 py-0 text-sm rounded-full",
14
+ md: "px-3 py-1 text-sm rounded-full",
15
+ };
16
+ export const Badge = ({ children, variant = "secondary", size = "sm", className }) => (_jsx("span", { className: cn("inline-flex items-center border border-transparent", variants[variant], sizes[size], className), children: children }));
17
+ //# sourceMappingURL=badge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge.js","sourceRoot":"","sources":["../src/badge.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAK7B,kDAAkD;AAClD,MAAM,QAAQ,GAAiC;IAC7C,OAAO,EAAE,2BAA2B;IACpC,SAAS,EAAE,0BAA0B;IACrC,MAAM,EAAE,6BAA6B;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,KAAK,GAA8B;IACvC,EAAE,EAAE,gCAAgC;IACpC,EAAE,EAAE,gCAAgC;CACrC,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAmB,CAAC,EAAE,QAAQ,EAAE,OAAO,GAAG,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CACpG,eACE,SAAS,EAAE,EAAE,CACX,oDAAoD,EACpD,QAAQ,CAAC,OAAO,CAAC,EACjB,KAAK,CAAC,IAAI,CAAC,EACX,SAAS,CACV,YAEA,QAAQ,GACJ,CACR,CAAC"}
package/dist/box.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ /**
4
+ * 스타일 없는 블록 컨테이너. `className` 을 붙일 자리다.
5
+ * 배치 prop 은 Stack 만 갖는다 — 둘 다 같은 prop 이면 하나가 죽은 코드가 된다(plan D-7).
6
+ */
7
+ export declare const Box: FC<Contracts<"web">["Box"]>;
8
+ //# sourceMappingURL=box.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"box.d.ts","sourceRoot":"","sources":["../src/box.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC;;;GAGG;AACH,eAAO,MAAM,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAE3C,CAAC"}
package/dist/box.js ADDED
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "./cn.js";
3
+ /**
4
+ * 스타일 없는 블록 컨테이너. `className` 을 붙일 자리다.
5
+ * 배치 prop 은 Stack 만 갖는다 — 둘 다 같은 prop 이면 하나가 죽은 코드가 된다(plan D-7).
6
+ */
7
+ export const Box = ({ children, className }) => (_jsx("div", { className: cn(className), children: children }));
8
+ //# sourceMappingURL=box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"box.js","sourceRoot":"","sources":["../src/box.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,GAAG,GAAgC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAC3E,cAAK,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAG,QAAQ,GAAO,CAChD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ /**
4
+ * 관련 Button 을 묶는다. `label` 이 그룹의 접근성 이름이 된다(C-13).
5
+ * 그룹 `size` 는 두지 않는다 — 자식 Button 이 각자 갖는다(plan D-30).
6
+ */
7
+ export declare const ButtonGroup: FC<Contracts<"web">["ButtonGroup"]>;
8
+ //# sourceMappingURL=button-group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button-group.d.ts","sourceRoot":"","sources":["../src/button-group.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAI3D,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { cn } from "./cn.js";
4
+ /**
5
+ * 관련 Button 을 묶는다. `label` 이 그룹의 접근성 이름이 된다(C-13).
6
+ * 그룹 `size` 는 두지 않는다 — 자식 Button 이 각자 갖는다(plan D-30).
7
+ */
8
+ export const ButtonGroup = ({ label, children, className }) => (_jsx("div", { role: "group", "aria-label": label, className: cn("inline-flex items-center gap-2", className), children: children }));
9
+ //# sourceMappingURL=button-group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button-group.js","sourceRoot":"","sources":["../src/button-group.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAIb,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAwC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAClG,cAAK,IAAI,EAAC,OAAO,gBAAa,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,gCAAgC,EAAE,SAAS,CAAC,YAC5F,QAAQ,GACL,CACP,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ type ButtonProps = Contracts<"web">["Button"];
4
+ /**
5
+ * 누름 버튼. `label` 이 가시 텍스트이자 접근성 이름이다 — `children` 이 없어
6
+ * WCAG 2.5.3(Label in Name) 위반 경로가 사라진다(C-13).
7
+ *
8
+ * `label` 은 아이콘 전용 모드에서도 항상 렌더된다(알려진 동작 9).
9
+ * `type="button"` 을 고정한다 — 기본값 `submit` 이면 `<form>` 안에서 Enter 가
10
+ * 암묵적 제출을 일으켜 `onClick` 이 실행된다(C-21).
11
+ *
12
+ * `ref` 는 엘리먼트를 그대로 넘긴다. HTMLElement 가 `FocusHandle` 을 구조적으로 만족하므로
13
+ * 계약 타입은 `Ref<FocusHandle>` 로 닫힌 채다(넓히는 방향은 스펙이 "추가적"이라 못박았다, C-17).
14
+ * 구성한 핸들을 넘기면 Base UI Tooltip 이 이 Button 을 앵커로 쓸 때 floating-ui 가
15
+ * `getBoundingClientRect` 를 찾지 못해 위치 계산이 깨진다.
16
+ */
17
+ export declare const Button: FC<ButtonProps>;
18
+ export {};
19
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../src/button.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAwB,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,EAAE,EAAO,MAAM,OAAO,CAAC;AAIrC,KAAK,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;AAiB9C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAkClC,CAAC"}
package/dist/button.js ADDED
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button as BaseButton } from "@base-ui/react/button";
4
+ import { cn } from "./cn.js";
5
+ import { Icon } from "./icon.js";
6
+ /** variant → semantic 색 매핑(§4.2). ghost 만 배경이 없다. */
7
+ const variants = {
8
+ primary: "bg-brand text-fg-on-brand hover:bg-brand-hover",
9
+ secondary: "bg-surface-muted text-fg hover:bg-surface-hover",
10
+ ghost: "text-fg hover:bg-surface-hover",
11
+ danger: "bg-danger text-fg-on-danger hover:bg-danger-hover",
12
+ };
13
+ /** 높이는 고정 `h-*` 없이 `py + text + 투명 테두리` 로 만든다 — 30 / 42 / 54 (plan D-6). */
14
+ const sizes = {
15
+ sm: "px-3 py-1 text-sm rounded-md gap-1",
16
+ md: "px-4 py-2 text-md rounded-md gap-2",
17
+ lg: "px-6 py-3 text-lg rounded-lg gap-2",
18
+ };
19
+ /**
20
+ * 누름 버튼. `label` 이 가시 텍스트이자 접근성 이름이다 — `children` 이 없어
21
+ * WCAG 2.5.3(Label in Name) 위반 경로가 사라진다(C-13).
22
+ *
23
+ * `label` 은 아이콘 전용 모드에서도 항상 렌더된다(알려진 동작 9).
24
+ * `type="button"` 을 고정한다 — 기본값 `submit` 이면 `<form>` 안에서 Enter 가
25
+ * 암묵적 제출을 일으켜 `onClick` 이 실행된다(C-21).
26
+ *
27
+ * `ref` 는 엘리먼트를 그대로 넘긴다. HTMLElement 가 `FocusHandle` 을 구조적으로 만족하므로
28
+ * 계약 타입은 `Ref<FocusHandle>` 로 닫힌 채다(넓히는 방향은 스펙이 "추가적"이라 못박았다, C-17).
29
+ * 구성한 핸들을 넘기면 Base UI Tooltip 이 이 Button 을 앵커로 쓸 때 floating-ui 가
30
+ * `getBoundingClientRect` 를 찾지 못해 위치 계산이 깨진다.
31
+ */
32
+ export const Button = ({ label, variant = "primary", size = "md", icon, loading = false, disabled = false, onClick, className, ref, }) => {
33
+ const inactive = disabled || loading;
34
+ return (_jsxs(BaseButton, { ref: ref, type: "button", disabled: inactive,
35
+ // 계약은 `() => void` 다. 그대로 넘기면 이벤트 객체가 새어 나가
36
+ // `onClick={setOpen}` 같은 코드가 이벤트를 상태로 넣는다.
37
+ onClick: onClick && (() => onClick()), className: cn("inline-flex items-center justify-center border border-transparent", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus", variants[variant], sizes[size], inactive && "opacity-50 pointer-events-none", className), children: [loading ? _jsx(Icon, { name: "loader", size: size, spin: true }) : icon ? _jsx(Icon, { name: icon, size: size }) : null, label] }));
38
+ };
39
+ //# sourceMappingURL=button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.js","sourceRoot":"","sources":["../src/button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,qDAAqD;AACrD,MAAM,QAAQ,GAA4B;IACxC,OAAO,EAAE,gDAAgD;IACzD,SAAS,EAAE,iDAAiD;IAC5D,KAAK,EAAE,gCAAgC;IACvC,MAAM,EAAE,mDAAmD;CAC5D,CAAC;AAEF,4EAA4E;AAC5E,MAAM,KAAK,GAAgC;IACzC,EAAE,EAAE,oCAAoC;IACxC,EAAE,EAAE,oCAAoC;IACxC,EAAE,EAAE,oCAAoC;CACzC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,MAAM,GAAoB,CAAC,EACtC,KAAK,EACL,OAAO,GAAG,SAAS,EACnB,IAAI,GAAG,IAAI,EACX,IAAI,EACJ,OAAO,GAAG,KAAK,EACf,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,SAAS,EACT,GAAG,GACJ,EAAE,EAAE;IACH,MAAM,QAAQ,GAAG,QAAQ,IAAI,OAAO,CAAC;IAErC,OAAO,CACL,MAAC,UAAU,IACT,GAAG,EAAE,GAAuB,EAC5B,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,QAAQ;QAClB,4CAA4C;QAC5C,2CAA2C;QAC3C,OAAO,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,EACrC,SAAS,EAAE,EAAE,CACX,mEAAmE,EACnE,2FAA2F,EAC3F,QAAQ,CAAC,OAAO,CAAC,EACjB,KAAK,CAAC,IAAI,CAAC,EACX,QAAQ,IAAI,gCAAgC,EAC5C,SAAS,CACV,aAEA,OAAO,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,IAAI,EAAC,QAAQ,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,SAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAI,CAAC,CAAC,CAAC,IAAI,EAClG,KAAK,IACK,CACd,CAAC;AACJ,CAAC,CAAC"}
package/dist/card.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ /**
4
+ * 표면 컨테이너. `variant` 를 두지 않는다 — 표면은 하나뿐이고
5
+ * 색을 바꾸려면 `className` 이다(§4.2).
6
+ */
7
+ export declare const Card: FC<Contracts<"web">["Card"]>;
8
+ //# sourceMappingURL=card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../src/card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC;;;GAGG;AACH,eAAO,MAAM,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAI7C,CAAC"}
package/dist/card.js ADDED
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "./cn.js";
3
+ /**
4
+ * 표면 컨테이너. `variant` 를 두지 않는다 — 표면은 하나뿐이고
5
+ * 색을 바꾸려면 `className` 이다(§4.2).
6
+ */
7
+ export const Card = ({ children, className }) => (_jsx("div", { className: cn("bg-surface border border-border rounded-lg shadow-sm p-4", className), children: children }));
8
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../src/card.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAiC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAC7E,cAAK,SAAS,EAAE,EAAE,CAAC,0DAA0D,EAAE,SAAS,CAAC,YACtF,QAAQ,GACL,CACP,CAAC"}
package/dist/cn.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * DS 기본 클래스와 소비자 `className` 을 병합한다. 충돌하면 소비자가 이긴다(C-15).
3
+ *
4
+ * `override` 여야 한다 — `extend` 는 기본 검증자에 concat 이라 spacing 의 기본 `isNumber`
5
+ * 가 남고, 존재하지 않는 `mt-5` 가 DS 의 `mt-4` 를 밀어낸다(plan v2 F-4, T-T5 테스트).
6
+ */
7
+ export declare const cn: (...classLists: import("tailwind-merge").ClassNameValue[]) => string;
8
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../src/cn.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,EAAE,sEAA8D,CAAC"}
package/dist/cn.js ADDED
@@ -0,0 +1,10 @@
1
+ import { twMergeConfig } from "@eeennsu/tokens";
2
+ import { extendTailwindMerge } from "tailwind-merge";
3
+ /**
4
+ * DS 기본 클래스와 소비자 `className` 을 병합한다. 충돌하면 소비자가 이긴다(C-15).
5
+ *
6
+ * `override` 여야 한다 — `extend` 는 기본 검증자에 concat 이라 spacing 의 기본 `isNumber`
7
+ * 가 남고, 존재하지 않는 `mt-5` 가 DS 의 `mt-4` 를 밀어낸다(plan v2 F-4, T-T5 테스트).
8
+ */
9
+ export const cn = extendTailwindMerge({ override: { theme: twMergeConfig } });
10
+ //# sourceMappingURL=cn.js.map
package/dist/cn.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.js","sourceRoot":"","sources":["../src/cn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,mBAAmB,CAAC,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ /**
4
+ * 모달 대화상자. `label` 은 제목으로 렌더되고 Base UI 가 `aria-labelledby` 를 연결한다(plan D-10).
5
+ *
6
+ * `Dialog.Trigger` 는 쓰지 않는다 — v1 오버레이는 제어 API 만 노출하고(C-12),
7
+ * 소비자가 Button 누름 이벤트로 `open` 을 토글한다.
8
+ * Base UI `onOpenChange` 는 `(open, eventDetails)` 2인자라 DS 가 boolean 하나로 감싼다.
9
+ */
10
+ export declare const Dialog: FC<Contracts<"web">["Dialog"]>;
11
+ //# sourceMappingURL=dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../src/dialog.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAIhC;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAkCjD,CAAC"}
package/dist/dialog.js ADDED
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Dialog as BaseDialog } from "@base-ui/react/dialog";
4
+ import { cn } from "./cn.js";
5
+ import { Icon } from "./icon.js";
6
+ /**
7
+ * 모달 대화상자. `label` 은 제목으로 렌더되고 Base UI 가 `aria-labelledby` 를 연결한다(plan D-10).
8
+ *
9
+ * `Dialog.Trigger` 는 쓰지 않는다 — v1 오버레이는 제어 API 만 노출하고(C-12),
10
+ * 소비자가 Button 누름 이벤트로 `open` 을 토글한다.
11
+ * Base UI `onOpenChange` 는 `(open, eventDetails)` 2인자라 DS 가 boolean 하나로 감싼다.
12
+ */
13
+ export const Dialog = ({ label, children, open, defaultOpen, onOpenChange, className, }) => (_jsx(BaseDialog.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: (next) => onOpenChange?.(next), children: _jsxs(BaseDialog.Portal, { children: [_jsx(BaseDialog.Backdrop, { className: "fixed inset-0 bg-overlay transition-opacity" }), _jsxs(BaseDialog.Popup, { className: cn("fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2", "bg-surface text-fg max-w-md w-full p-6 rounded-lg shadow-lg", className), children: [_jsx(BaseDialog.Title, { className: "text-xl", children: label }), children, _jsx(BaseDialog.Close, { "aria-label": "\uB2EB\uAE30", className: "absolute top-4 right-4 text-fg-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus", children: _jsx(Icon, { name: "x", size: "sm" }) })] })] }) }));
14
+ //# sourceMappingURL=dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.js","sourceRoot":"","sources":["../src/dialog.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAmC,CAAC,EACrD,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,SAAS,GACV,EAAE,EAAE,CAAC,CACJ,KAAC,UAAU,CAAC,IAAI,IACd,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,YAE5C,MAAC,UAAU,CAAC,MAAM,eAChB,KAAC,UAAU,CAAC,QAAQ,IAAC,SAAS,EAAC,6CAA6C,GAAG,EAC/E,MAAC,UAAU,CAAC,KAAK,IACf,SAAS,EAAE,EAAE,CACX,0DAA0D,EAC1D,6DAA6D,EAC7D,SAAS,CACV,aAED,KAAC,UAAU,CAAC,KAAK,IAAC,SAAS,EAAC,SAAS,YAAE,KAAK,GAAoB,EAC/D,QAAQ,EAET,KAAC,UAAU,CAAC,KAAK,kBACJ,cAAI,EACf,SAAS,EAAC,gIAAgI,YAE1I,KAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,IAAI,EAAC,IAAI,GAAG,GACV,IACF,IACD,GACJ,CACnB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ type DrawerProps = Contracts<"web">["Drawer"];
4
+ /**
5
+ * 가장자리에서 열리는 패널. Base UI Dialog 파트를 그대로 쓰고 위치 클래스만 바꾼다 —
6
+ * 별도 라이브러리를 들이지 않는다(plan D-12). 스와이프 닫기는 없다.
7
+ */
8
+ export declare const Drawer: FC<DrawerProps>;
9
+ export {};
10
+ //# sourceMappingURL=drawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../src/drawer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAIhC,KAAK,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC;AAS9C;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CA8BlC,CAAC"}
package/dist/drawer.js ADDED
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Dialog as BaseDialog } from "@base-ui/react/dialog";
4
+ import { cn } from "./cn.js";
5
+ import { Icon } from "./icon.js";
6
+ /** 가장자리 고정 위치. 폭 토큰은 좌·우에만 적용된다(§3.8 drawer.width). */
7
+ const sides = {
8
+ left: "inset-y-0 left-0 max-w-sm w-full",
9
+ right: "inset-y-0 right-0 max-w-sm w-full",
10
+ bottom: "inset-x-0 bottom-0 w-full",
11
+ };
12
+ /**
13
+ * 가장자리에서 열리는 패널. Base UI Dialog 파트를 그대로 쓰고 위치 클래스만 바꾼다 —
14
+ * 별도 라이브러리를 들이지 않는다(plan D-12). 스와이프 닫기는 없다.
15
+ */
16
+ export const Drawer = ({ label, children, side = "right", open, defaultOpen, onOpenChange, className, }) => (_jsx(BaseDialog.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: (next) => onOpenChange?.(next), children: _jsxs(BaseDialog.Portal, { children: [_jsx(BaseDialog.Backdrop, { className: "fixed inset-0 bg-overlay transition-opacity" }), _jsxs(BaseDialog.Popup, { className: cn("fixed bg-surface text-fg p-6 shadow-lg", sides[side], className), children: [_jsx(BaseDialog.Title, { className: "text-xl", children: label }), children, _jsx(BaseDialog.Close, { "aria-label": "\uB2EB\uAE30", className: "absolute top-4 right-4 text-fg-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus", children: _jsx(Icon, { name: "x", size: "sm" }) })] })] }) }));
17
+ //# sourceMappingURL=drawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer.js","sourceRoot":"","sources":["../src/drawer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,uDAAuD;AACvD,MAAM,KAAK,GAAqD;IAC9D,IAAI,EAAE,kCAAkC;IACxC,KAAK,EAAE,mCAAmC;IAC1C,MAAM,EAAE,2BAA2B;CACpC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAoB,CAAC,EACtC,KAAK,EACL,QAAQ,EACR,IAAI,GAAG,OAAO,EACd,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,SAAS,GACV,EAAE,EAAE,CAAC,CACJ,KAAC,UAAU,CAAC,IAAI,IACd,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,YAE5C,MAAC,UAAU,CAAC,MAAM,eAChB,KAAC,UAAU,CAAC,QAAQ,IAAC,SAAS,EAAC,6CAA6C,GAAG,EAC/E,MAAC,UAAU,CAAC,KAAK,IACf,SAAS,EAAE,EAAE,CAAC,wCAAwC,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,aAE/E,KAAC,UAAU,CAAC,KAAK,IAAC,SAAS,EAAC,SAAS,YAAE,KAAK,GAAoB,EAC/D,QAAQ,EACT,KAAC,UAAU,CAAC,KAAK,kBACJ,cAAI,EACf,SAAS,EAAC,gIAAgI,YAE1I,KAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,IAAI,EAAC,IAAI,GAAG,GACV,IACF,IACD,GACJ,CACnB,CAAC"}
package/dist/form.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ /**
4
+ * 레이아웃 + Label 연결 + 오류 텍스트 표시까지가 v1 범위다(C-21).
5
+ * submit 개념이 없고 계약에 `onSubmit` 도 없다 — 제출은 Button `onClick` 에서
6
+ * 소비자 코드가 처리한다. Enter 는 아무 동작도 하지 않는다(알려진 동작 5).
7
+ *
8
+ * Base UI `Form` / `Field` 를 쓰지 않는다 — v1 에 submit·검증이 없어 기능이 쓰이지 않고,
9
+ * `Field` 로 감싸면 Input 단독 사용과 DOM 이 달라진다(plan D-13, §9 S-4).
10
+ */
11
+ export declare const Form: FC<Contracts<"web">["Form"]>;
12
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAS7C,CAAC"}
package/dist/form.js ADDED
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { cn } from "./cn.js";
4
+ /**
5
+ * 레이아웃 + Label 연결 + 오류 텍스트 표시까지가 v1 범위다(C-21).
6
+ * submit 개념이 없고 계약에 `onSubmit` 도 없다 — 제출은 Button `onClick` 에서
7
+ * 소비자 코드가 처리한다. Enter 는 아무 동작도 하지 않는다(알려진 동작 5).
8
+ *
9
+ * Base UI `Form` / `Field` 를 쓰지 않는다 — v1 에 submit·검증이 없어 기능이 쓰이지 않고,
10
+ * `Field` 로 감싸면 Input 단독 사용과 DOM 이 달라진다(plan D-13, §9 S-4).
11
+ */
12
+ export const Form = ({ children, className }) => (_jsx("form", { onSubmit: (event) => {
13
+ event.preventDefault();
14
+ }, className: cn("flex flex-col gap-4", className), children: children }));
15
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAIb,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,IAAI,GAAiC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAC7E,eACE,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QAClB,KAAK,CAAC,cAAc,EAAE,CAAC;IACzB,CAAC,EACD,SAAS,EAAE,EAAE,CAAC,qBAAqB,EAAE,SAAS,CAAC,YAE9C,QAAQ,GACJ,CACR,CAAC"}
package/dist/icon.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { type ControlSize, type IconName } from "@eeennsu/tokens";
2
+ import { type LucideIcon } from "lucide-react";
3
+ /**
4
+ * `IconName` → lucide 컴포넌트. `Record<IconName, LucideIcon>` 이라 tokens 의 목록에
5
+ * 이름을 추가하고 이 맵을 빠뜨리면 컴파일 에러가 난다(plan D-8).
6
+ *
7
+ * lucide 의 **정식 export 이름**만 쓴다 — 별칭(`AlertCircle` → `CircleAlert`)은
8
+ * major 에서 사라질 수 있다(plan v2 F-6).
9
+ */
10
+ declare const icons: Record<IconName, LucideIcon>;
11
+ type IconProps = {
12
+ name: IconName;
13
+ size?: ControlSize;
14
+ spin?: boolean;
15
+ className?: string;
16
+ };
17
+ /**
18
+ * DS 내부 전용이다 — 공개 컴포넌트가 아니고 `Contracts` 에도 없다.
19
+ * 크기는 클래스가 아니라 lucide `size` prop(JS 숫자)으로 준다 — 20px 는 spacing 열거
20
+ * 밖이라 `size-5` 클래스가 생성되지 않기 때문이다(plan v2 F-8).
21
+ * 색은 `currentColor` 상속이라 별도 prop 이 없다(§9 S-17).
22
+ */
23
+ export declare function Icon({ name, size, spin, className }: IconProps): import("react").JSX.Element;
24
+ export { icons };
25
+ //# sourceMappingURL=icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon.d.ts","sourceRoot":"","sources":["../src/icon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7E,OAAO,EAeL,KAAK,UAAU,EAWhB,MAAM,cAAc,CAAC;AAEtB;;;;;;GAMG;AACH,QAAA,MAAM,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,CAyBvC,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,IAAW,EAAE,IAAY,EAAE,SAAS,EAAE,EAAE,SAAS,+BAS7E;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
package/dist/icon.js ADDED
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { component } from "@eeennsu/tokens";
3
+ import { cn } from "./cn.js";
4
+ import { ArrowLeft, ArrowRight, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, CircleAlert, ExternalLink, Eye, EyeOff, Info, Loader, Lock, Mail, Menu, Minus, Pencil, Plus, Search, Settings, Trash, User, X, } from "lucide-react";
5
+ /**
6
+ * `IconName` → lucide 컴포넌트. `Record<IconName, LucideIcon>` 이라 tokens 의 목록에
7
+ * 이름을 추가하고 이 맵을 빠뜨리면 컴파일 에러가 난다(plan D-8).
8
+ *
9
+ * lucide 의 **정식 export 이름**만 쓴다 — 별칭(`AlertCircle` → `CircleAlert`)은
10
+ * major 에서 사라질 수 있다(plan v2 F-6).
11
+ */
12
+ const icons = {
13
+ check: Check,
14
+ x: X,
15
+ plus: Plus,
16
+ minus: Minus,
17
+ trash: Trash,
18
+ pencil: Pencil,
19
+ search: Search,
20
+ "chevron-down": ChevronDown,
21
+ "chevron-up": ChevronUp,
22
+ "chevron-left": ChevronLeft,
23
+ "chevron-right": ChevronRight,
24
+ "arrow-left": ArrowLeft,
25
+ "arrow-right": ArrowRight,
26
+ menu: Menu,
27
+ settings: Settings,
28
+ user: User,
29
+ mail: Mail,
30
+ lock: Lock,
31
+ eye: Eye,
32
+ "eye-off": EyeOff,
33
+ info: Info,
34
+ "alert-circle": CircleAlert,
35
+ loader: Loader,
36
+ "external-link": ExternalLink,
37
+ };
38
+ /**
39
+ * DS 내부 전용이다 — 공개 컴포넌트가 아니고 `Contracts` 에도 없다.
40
+ * 크기는 클래스가 아니라 lucide `size` prop(JS 숫자)으로 준다 — 20px 는 spacing 열거
41
+ * 밖이라 `size-5` 클래스가 생성되지 않기 때문이다(plan v2 F-8).
42
+ * 색은 `currentColor` 상속이라 별도 prop 이 없다(§9 S-17).
43
+ */
44
+ export function Icon({ name, size = "md", spin = false, className }) {
45
+ const Glyph = icons[name];
46
+ return (_jsx(Glyph, { size: component.icon.size[size], "aria-hidden": "true", className: spin ? cn("animate-spin", className) : className }));
47
+ }
48
+ export { icons };
49
+ //# sourceMappingURL=icon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon.js","sourceRoot":"","sources":["../src/icon.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAmC,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EACL,SAAS,EACT,UAAU,EACV,KAAK,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,EACT,WAAW,EACX,YAAY,EACZ,GAAG,EACH,MAAM,EACN,IAAI,EACJ,MAAM,EACN,IAAI,EAEJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,MAAM,EACN,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,KAAK,EACL,IAAI,EACJ,CAAC,GACF,MAAM,cAAc,CAAC;AAEtB;;;;;;GAMG;AACH,MAAM,KAAK,GAAiC;IAC1C,KAAK,EAAE,KAAK;IACZ,CAAC,EAAE,CAAC;IACJ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,cAAc,EAAE,WAAW;IAC3B,YAAY,EAAE,SAAS;IACvB,cAAc,EAAE,WAAW;IAC3B,eAAe,EAAE,YAAY;IAC7B,YAAY,EAAE,SAAS;IACvB,aAAa,EAAE,UAAU;IACzB,IAAI,EAAE,IAAI;IACV,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,GAAG;IACR,SAAS,EAAE,MAAM;IACjB,IAAI,EAAE,IAAI;IACV,cAAc,EAAE,WAAW;IAC3B,MAAM,EAAE,MAAM;IACd,eAAe,EAAE,YAAY;CAC9B,CAAC;AASF;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,KAAK,EAAE,SAAS,EAAa;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,CACL,KAAC,KAAK,IACJ,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iBACnB,MAAM,EAClB,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,GAC3D,CACH,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
@@ -0,0 +1,131 @@
1
+ import { Badge } from "./badge.js";
2
+ import { Box } from "./box.js";
3
+ import { Button } from "./button.js";
4
+ import { ButtonGroup } from "./button-group.js";
5
+ import { Card } from "./card.js";
6
+ import { Dialog } from "./dialog.js";
7
+ import { Drawer } from "./drawer.js";
8
+ import { Form } from "./form.js";
9
+ import { Input } from "./input.js";
10
+ import { Label } from "./label.js";
11
+ import { Stack } from "./stack.js";
12
+ import { Text } from "./text.js";
13
+ import { Textarea } from "./textarea.js";
14
+ import { Tooltip } from "./tooltip.js";
15
+ export { Badge, Box, Button, ButtonGroup, Card, Dialog, Drawer, Form, Input, Label, Stack, Text, Textarea, Tooltip };
16
+ export { cn } from "./cn.js";
17
+ /**
18
+ * 계약 맵 테스트(C-17)가 보는 객체. 키 집합이 `webComponents` 와 같고
19
+ * 값 타입이 `FC<Contracts<"web">[K]>` 와 같아야 한다.
20
+ */
21
+ export declare const components: {
22
+ Button: import("react").FC<{
23
+ label: string;
24
+ variant?: import("@eeennsu/tokens").Variant;
25
+ size?: import("@eeennsu/tokens").ControlSize;
26
+ icon?: import("@eeennsu/tokens").IconName;
27
+ loading?: boolean;
28
+ disabled?: boolean;
29
+ className?: string;
30
+ ref?: import("react").Ref<import("@eeennsu/tokens").FocusHandle>;
31
+ } & {
32
+ onClick?: () => void;
33
+ }>;
34
+ ButtonGroup: import("react").FC<{
35
+ label: string;
36
+ children: import("react").ReactElement | import("react").ReactElement[];
37
+ className?: string;
38
+ }>;
39
+ Input: import("react").FC<{
40
+ label: string;
41
+ kind?: import("@eeennsu/tokens").InputKind;
42
+ size?: import("@eeennsu/tokens").ControlSize;
43
+ id?: string;
44
+ placeholder?: string;
45
+ disabled?: boolean;
46
+ invalid?: boolean;
47
+ value?: string;
48
+ defaultValue?: string;
49
+ onValueChange?: (value: string) => void;
50
+ className?: string;
51
+ ref?: import("react").Ref<import("@eeennsu/tokens").FocusHandle>;
52
+ }>;
53
+ Textarea: import("react").FC<{
54
+ label: string;
55
+ size?: import("@eeennsu/tokens").ControlSize;
56
+ id?: string;
57
+ placeholder?: string;
58
+ disabled?: boolean;
59
+ invalid?: boolean;
60
+ value?: string;
61
+ defaultValue?: string;
62
+ onValueChange?: (value: string) => void;
63
+ className?: string;
64
+ ref?: import("react").Ref<import("@eeennsu/tokens").FocusHandle>;
65
+ }>;
66
+ Label: import("react").FC<{
67
+ children: string | string[];
68
+ htmlFor?: string;
69
+ className?: string;
70
+ }>;
71
+ Card: import("react").FC<{
72
+ children: import("@eeennsu/tokens").ElementChildren;
73
+ className?: string;
74
+ }>;
75
+ Badge: import("react").FC<{
76
+ children: string | string[];
77
+ variant?: Extract<import("@eeennsu/tokens").Variant, "primary" | "secondary" | "danger">;
78
+ size?: import("@eeennsu/tokens").BadgeSize;
79
+ className?: string;
80
+ }>;
81
+ Text: import("react").FC<{
82
+ children: string | string[];
83
+ tone?: import("@eeennsu/tokens").Tone;
84
+ size?: import("@eeennsu/tokens").TypographyStep;
85
+ heading?: "1" | "2" | "3";
86
+ className?: string;
87
+ }>;
88
+ Stack: import("react").FC<{
89
+ children: import("@eeennsu/tokens").ElementChildren;
90
+ direction?: "row" | "column";
91
+ align?: "start" | "center" | "end" | "stretch";
92
+ justify?: "start" | "center" | "end" | "between";
93
+ wrap?: boolean;
94
+ className?: string;
95
+ }>;
96
+ Box: import("react").FC<{
97
+ children: import("@eeennsu/tokens").ElementChildren;
98
+ className?: string;
99
+ }>;
100
+ Tooltip: import("react").FC<{
101
+ label: string;
102
+ children: import("react").ReactElement;
103
+ side?: "top" | "bottom" | "left" | "right";
104
+ open?: boolean;
105
+ defaultOpen?: boolean;
106
+ onOpenChange?: (open: boolean) => void;
107
+ className?: string;
108
+ }>;
109
+ Dialog: import("react").FC<{
110
+ label: string;
111
+ children: import("react").ReactNode;
112
+ open?: boolean;
113
+ defaultOpen?: boolean;
114
+ onOpenChange?: (open: boolean) => void;
115
+ className?: string;
116
+ }>;
117
+ Drawer: import("react").FC<{
118
+ label: string;
119
+ children: import("react").ReactNode;
120
+ side?: "left" | "right" | "bottom";
121
+ open?: boolean;
122
+ defaultOpen?: boolean;
123
+ onOpenChange?: (open: boolean) => void;
124
+ className?: string;
125
+ }>;
126
+ Form: import("react").FC<{
127
+ children: import("react").ReactNode;
128
+ className?: string;
129
+ }>;
130
+ };
131
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACrH,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAetB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ import { Badge } from "./badge.js";
2
+ import { Box } from "./box.js";
3
+ import { Button } from "./button.js";
4
+ import { ButtonGroup } from "./button-group.js";
5
+ import { Card } from "./card.js";
6
+ import { Dialog } from "./dialog.js";
7
+ import { Drawer } from "./drawer.js";
8
+ import { Form } from "./form.js";
9
+ import { Input } from "./input.js";
10
+ import { Label } from "./label.js";
11
+ import { Stack } from "./stack.js";
12
+ import { Text } from "./text.js";
13
+ import { Textarea } from "./textarea.js";
14
+ import { Tooltip } from "./tooltip.js";
15
+ export { Badge, Box, Button, ButtonGroup, Card, Dialog, Drawer, Form, Input, Label, Stack, Text, Textarea, Tooltip };
16
+ export { cn } from "./cn.js";
17
+ /**
18
+ * 계약 맵 테스트(C-17)가 보는 객체. 키 집합이 `webComponents` 와 같고
19
+ * 값 타입이 `FC<Contracts<"web">[K]>` 와 같아야 한다.
20
+ */
21
+ export const components = {
22
+ Button,
23
+ ButtonGroup,
24
+ Input,
25
+ Textarea,
26
+ Label,
27
+ Card,
28
+ Badge,
29
+ Text,
30
+ Stack,
31
+ Box,
32
+ Tooltip,
33
+ Dialog,
34
+ Drawer,
35
+ Form,
36
+ };
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACrH,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,MAAM;IACN,WAAW;IACX,KAAK;IACL,QAAQ;IACR,KAAK;IACL,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,GAAG;IACH,OAAO;IACP,MAAM;IACN,MAAM;IACN,IAAI;CACL,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Contracts, ControlSize } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ type InputProps = Contracts<"web">["Input"];
4
+ export declare const inputSizes: Record<ControlSize, string>;
5
+ /** 테두리 1px 이 Button 과 높이를 맞춘다 — 없으면 Input 이 2px 낮다(plan D-6). */
6
+ export declare const controlBase = "block w-full bg-surface text-fg border border-border placeholder:text-fg-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus";
7
+ /**
8
+ * 한 줄 입력. `label` 은 `aria-label` 로만 간다 — 가시 라벨은 `Label` 조합이다(C-13).
9
+ * 값 제어는 `value` / `defaultValue` / `onValueChange` 3종뿐이다(C-12).
10
+ */
11
+ export declare const Input: FC<InputProps>;
12
+ export {};
13
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAa,MAAM,iBAAiB,CAAC;AACzE,OAAO,KAAK,EAAE,EAAE,EAAO,MAAM,OAAO,CAAC;AAGrC,KAAK,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;AAiB5C,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAIlD,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,WAAW,6KACoJ,CAAC;AAE7K;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAuChC,CAAC"}
package/dist/input.js ADDED
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { cn } from "./cn.js";
4
+ /**
5
+ * `kind` → DOM 속성 매핑(C-11). 계약은 열거형 4값뿐이고 이 표는 어댑터 구현 세부다.
6
+ * `number` 가 `type="number"` 가 아닌 이유는 스피너를 띄우지 않기 위해서다.
7
+ * 자동완성은 `new-password` 를 구분하지 않는다(알려진 동작 8).
8
+ */
9
+ const kinds = {
10
+ text: { type: "text" },
11
+ password: { type: "password", autoComplete: "current-password" },
12
+ email: { type: "email", autoComplete: "email" },
13
+ number: { type: "text", inputMode: "numeric" },
14
+ };
15
+ export const inputSizes = {
16
+ sm: "px-3 py-1 text-sm rounded-md",
17
+ md: "px-3 py-2 text-md rounded-md",
18
+ lg: "px-4 py-3 text-lg rounded-md",
19
+ };
20
+ /** 테두리 1px 이 Button 과 높이를 맞춘다 — 없으면 Input 이 2px 낮다(plan D-6). */
21
+ export const controlBase = "block w-full bg-surface text-fg border border-border placeholder:text-fg-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus";
22
+ /**
23
+ * 한 줄 입력. `label` 은 `aria-label` 로만 간다 — 가시 라벨은 `Label` 조합이다(C-13).
24
+ * 값 제어는 `value` / `defaultValue` / `onValueChange` 3종뿐이다(C-12).
25
+ */
26
+ export const Input = ({ label, kind = "text", size = "md", id, placeholder, disabled = false, invalid = false, value, defaultValue, onValueChange, className, ref, }) => {
27
+ const attributes = kinds[kind];
28
+ return (_jsx("input", { ref: ref, id: id, type: attributes.type, inputMode: attributes.inputMode, autoComplete: attributes.autoComplete, "aria-label": label, "aria-invalid": invalid || undefined, placeholder: placeholder, disabled: disabled, value: value, defaultValue: defaultValue, onChange: (event) => onValueChange?.(event.target.value), className: cn(controlBase, inputSizes[size], invalid && "border-danger", disabled && "opacity-50 pointer-events-none", className) }));
29
+ };
30
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAIb,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAI7B;;;;GAIG;AACH,MAAM,KAAK,GAGP;IACF,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;IACtB,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE;IAChE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE;IAC/C,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE;CAC/C,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAgC;IACrD,EAAE,EAAE,8BAA8B;IAClC,EAAE,EAAE,8BAA8B;IAClC,EAAE,EAAE,8BAA8B;CACnC,CAAC;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,WAAW,GACtB,0KAA0K,CAAC;AAE7K;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAmB,CAAC,EACpC,KAAK,EACL,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,IAAI,EACX,EAAE,EACF,WAAW,EACX,QAAQ,GAAG,KAAK,EAChB,OAAO,GAAG,KAAK,EACf,KAAK,EACL,YAAY,EACZ,aAAa,EACb,SAAS,EACT,GAAG,GACJ,EAAE,EAAE;IACH,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAE/B,OAAO,CACL,gBACE,GAAG,EAAE,GAA4B,EACjC,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,UAAU,CAAC,IAAI,EACrB,SAAS,EAAE,UAAU,CAAC,SAAS,EAC/B,YAAY,EAAE,UAAU,CAAC,YAAY,gBACzB,KAAK,kBACH,OAAO,IAAI,SAAS,EAClC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EACxD,SAAS,EAAE,EAAE,CACX,WAAW,EACX,UAAU,CAAC,IAAI,CAAC,EAChB,OAAO,IAAI,eAAe,EAC1B,QAAQ,IAAI,gCAAgC,EAC5C,SAAS,CACV,GACD,CACH,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ /**
4
+ * Input · Textarea 의 가시 라벨. `htmlFor` 와 컨트롤의 `id` 로 연결한다(C-13).
5
+ * 비인터랙티브라 `label` prop 대상이 아니다 — 가시 텍스트가 곧 내용이다.
6
+ */
7
+ export declare const Label: FC<Contracts<"web">["Label"]>;
8
+ //# sourceMappingURL=label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../src/label.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAI/C,CAAC"}
package/dist/label.js ADDED
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "./cn.js";
3
+ /**
4
+ * Input · Textarea 의 가시 라벨. `htmlFor` 와 컨트롤의 `id` 로 연결한다(C-13).
5
+ * 비인터랙티브라 `label` prop 대상이 아니다 — 가시 텍스트가 곧 내용이다.
6
+ */
7
+ export const Label = ({ children, htmlFor, className }) => (_jsx("label", { htmlFor: htmlFor, className: cn("text-sm text-fg", className), children: children }));
8
+ //# sourceMappingURL=label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.js","sourceRoot":"","sources":["../src/label.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAkC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CACxF,gBAAO,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,YACjE,QAAQ,GACH,CACT,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ type StackProps = Contracts<"web">["Stack"];
4
+ /**
5
+ * flex 컨테이너. 배치의 1순위 수단이다.
6
+ * 간격 prop 은 없다 — 소비자가 `className="gap-4"` 로 준다(C-14).
7
+ * 기본 방향이 `column` 인 것은 RN `View` 기본과 맞추기 위해서다(§4.4).
8
+ */
9
+ export declare const Stack: FC<StackProps>;
10
+ export {};
11
+ //# sourceMappingURL=stack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../src/stack.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC,KAAK,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;AAsB5C;;;;GAIG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAoBhC,CAAC"}
package/dist/stack.js ADDED
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "./cn.js";
3
+ /** 클래스는 전부 정적 리터럴이어야 `@source` 스캔이 잡는다(C-4 (2)). */
4
+ const directions = {
5
+ row: "flex-row",
6
+ column: "flex-col",
7
+ };
8
+ const aligns = {
9
+ start: "items-start",
10
+ center: "items-center",
11
+ end: "items-end",
12
+ stretch: "items-stretch",
13
+ };
14
+ const justifies = {
15
+ start: "justify-start",
16
+ center: "justify-center",
17
+ end: "justify-end",
18
+ between: "justify-between",
19
+ };
20
+ /**
21
+ * flex 컨테이너. 배치의 1순위 수단이다.
22
+ * 간격 prop 은 없다 — 소비자가 `className="gap-4"` 로 준다(C-14).
23
+ * 기본 방향이 `column` 인 것은 RN `View` 기본과 맞추기 위해서다(§4.4).
24
+ */
25
+ export const Stack = ({ children, direction = "column", align = "stretch", justify = "start", wrap = false, className, }) => (_jsx("div", { className: cn("flex", directions[direction], aligns[align], justifies[justify], wrap && "flex-wrap", className), children: children }));
26
+ //# sourceMappingURL=stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAI7B,oDAAoD;AACpD,MAAM,UAAU,GAAyD;IACvE,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,UAAU;CACnB,CAAC;AAEF,MAAM,MAAM,GAAqD;IAC/D,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,cAAc;IACtB,GAAG,EAAE,WAAW;IAChB,OAAO,EAAE,eAAe;CACzB,CAAC;AAEF,MAAM,SAAS,GAAuD;IACpE,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,gBAAgB;IACxB,GAAG,EAAE,aAAa;IAClB,OAAO,EAAE,iBAAiB;CAC3B,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAmB,CAAC,EACpC,QAAQ,EACR,SAAS,GAAG,QAAQ,EACpB,KAAK,GAAG,SAAS,EACjB,OAAO,GAAG,OAAO,EACjB,IAAI,GAAG,KAAK,EACZ,SAAS,GACV,EAAE,EAAE,CAAC,CACJ,cACE,SAAS,EAAE,EAAE,CACX,MAAM,EACN,UAAU,CAAC,SAAS,CAAC,EACrB,MAAM,CAAC,KAAK,CAAC,EACb,SAAS,CAAC,OAAO,CAAC,EAClB,IAAI,IAAI,WAAW,EACnB,SAAS,CACV,YAEA,QAAQ,GACL,CACP,CAAC"}
package/dist/text.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ type TextProps = Contracts<"web">["Text"];
4
+ /**
5
+ * 텍스트. `heading` 이 있으면 그 레벨의 제목 엘리먼트로 렌더한다 —
6
+ * 시각적 크기는 `size` 가 정하므로 의미와 크기가 분리된다.
7
+ */
8
+ export declare const Text: FC<TextProps>;
9
+ export {};
10
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAwB,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC,KAAK,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;AAkB1C;;;GAGG;AACH,eAAO,MAAM,IAAI,EAAE,EAAE,CAAC,SAAS,CAM9B,CAAC"}
package/dist/text.js ADDED
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "./cn.js";
3
+ /** `tone` 은 fg semantic 색과 1:1 이다(C-8). `danger` 는 `bg.danger` 별칭이다(plan D-3). */
4
+ const tones = {
5
+ default: "text-fg",
6
+ muted: "text-fg-muted",
7
+ danger: "text-fg-danger",
8
+ };
9
+ /** 스텝 하나가 크기·행간·무게를 함께 바꾼다(C-6 복합 폰트 변수). */
10
+ const steps = {
11
+ sm: "text-sm",
12
+ md: "text-md",
13
+ lg: "text-lg",
14
+ xl: "text-xl",
15
+ "2xl": "text-2xl",
16
+ };
17
+ /**
18
+ * 텍스트. `heading` 이 있으면 그 레벨의 제목 엘리먼트로 렌더한다 —
19
+ * 시각적 크기는 `size` 가 정하므로 의미와 크기가 분리된다.
20
+ */
21
+ export const Text = ({ children, tone = "default", size = "md", heading, className }) => {
22
+ const merged = cn(tones[tone], steps[size], className);
23
+ if (heading === "1")
24
+ return _jsx("h1", { className: merged, children: children });
25
+ if (heading === "2")
26
+ return _jsx("h2", { className: merged, children: children });
27
+ if (heading === "3")
28
+ return _jsx("h3", { className: merged, children: children });
29
+ return _jsx("span", { className: merged, children: children });
30
+ };
31
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../src/text.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAI7B,kFAAkF;AAClF,MAAM,KAAK,GAAyB;IAClC,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,gBAAgB;CACzB,CAAC;AAEF,6CAA6C;AAC7C,MAAM,KAAK,GAAmC;IAC5C,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;IACb,KAAK,EAAE,UAAU;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAkB,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;IACrG,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,aAAI,SAAS,EAAE,MAAM,YAAG,QAAQ,GAAM,CAAC;IACnE,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,aAAI,SAAS,EAAE,MAAM,YAAG,QAAQ,GAAM,CAAC;IACnE,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,aAAI,SAAS,EAAE,MAAM,YAAG,QAAQ,GAAM,CAAC;IACnE,OAAO,eAAM,SAAS,EAAE,MAAM,YAAG,QAAQ,GAAQ,CAAC;AACpD,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ type TextareaProps = Contracts<"web">["Textarea"];
4
+ /**
5
+ * 여러 줄 입력. `size` 는 글자 크기가 아니라 **행수**로 해석한다 — 3 / 5 / 8 (plan D-14).
6
+ * 패딩과 글자 크기는 Input `md` 로 고정한다.
7
+ */
8
+ export declare const Textarea: FC<TextareaProps>;
9
+ export {};
10
+ //# sourceMappingURL=textarea.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../src/textarea.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,EAAE,EAAO,MAAM,OAAO,CAAC;AAIrC,KAAK,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAkCtC,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { component } from "@eeennsu/tokens";
4
+ import { cn } from "./cn.js";
5
+ import { controlBase, inputSizes } from "./input.js";
6
+ /**
7
+ * 여러 줄 입력. `size` 는 글자 크기가 아니라 **행수**로 해석한다 — 3 / 5 / 8 (plan D-14).
8
+ * 패딩과 글자 크기는 Input `md` 로 고정한다.
9
+ */
10
+ export const Textarea = ({ label, size = "md", id, placeholder, disabled = false, invalid = false, value, defaultValue, onValueChange, className, ref, }) => {
11
+ return (_jsx("textarea", { ref: ref, id: id, rows: component.textarea.rows[size], "aria-label": label, "aria-invalid": invalid || undefined, placeholder: placeholder, disabled: disabled, value: value, defaultValue: defaultValue, onChange: (event) => onValueChange?.(event.target.value), className: cn(controlBase, inputSizes.md, invalid && "border-danger", disabled && "opacity-50 pointer-events-none", className) }));
12
+ };
13
+ //# sourceMappingURL=textarea.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textarea.js","sourceRoot":"","sources":["../src/textarea.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,SAAS,EAAkB,MAAM,iBAAiB,CAAC;AAE5D,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAIrD;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAsB,CAAC,EAC1C,KAAK,EACL,IAAI,GAAG,IAAI,EACX,EAAE,EACF,WAAW,EACX,QAAQ,GAAG,KAAK,EAChB,OAAO,GAAG,KAAK,EACf,KAAK,EACL,YAAY,EACZ,aAAa,EACb,SAAS,EACT,GAAG,GACJ,EAAE,EAAE;IACH,OAAO,CACL,mBACE,GAAG,EAAE,GAA+B,EACpC,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,gBACvB,KAAK,kBACH,OAAO,IAAI,SAAS,EAClC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EACxD,SAAS,EAAE,EAAE,CACX,WAAW,EACX,UAAU,CAAC,EAAE,EACb,OAAO,IAAI,eAAe,EAC1B,QAAQ,IAAI,gCAAgC,EAC5C,SAAS,CACV,GACD,CACH,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { Contracts } from "@eeennsu/tokens";
2
+ import type { FC } from "react";
3
+ /**
4
+ * 앵커에 붙는 설명. `label` 이 표시 내용이자 접근성 설명이다(C-13).
5
+ *
6
+ * `Provider` 를 컴포넌트마다 안에서 감싼다 — 소비자 설정 0 이 목표다(§4.3).
7
+ * `children` 은 앵커 엘리먼트 하나다. Base UI `Trigger` 의 `render` 로 넘기며 이는
8
+ * 내부 구현 디테일이라 공개 prop 이 아니다(C-10 · AC-12). DS Button 을 앵커로 쓰면
9
+ * React 19 에서 `ref` 가 일반 prop 이라 Base UI 가 주입할 수 있다.
10
+ */
11
+ export declare const Tooltip: FC<Contracts<"web">["Tooltip"]>;
12
+ //# sourceMappingURL=tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../src/tooltip.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CA8BnD,CAAC"}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
4
+ import { cn } from "./cn.js";
5
+ /**
6
+ * 앵커에 붙는 설명. `label` 이 표시 내용이자 접근성 설명이다(C-13).
7
+ *
8
+ * `Provider` 를 컴포넌트마다 안에서 감싼다 — 소비자 설정 0 이 목표다(§4.3).
9
+ * `children` 은 앵커 엘리먼트 하나다. Base UI `Trigger` 의 `render` 로 넘기며 이는
10
+ * 내부 구현 디테일이라 공개 prop 이 아니다(C-10 · AC-12). DS Button 을 앵커로 쓰면
11
+ * React 19 에서 `ref` 가 일반 prop 이라 Base UI 가 주입할 수 있다.
12
+ */
13
+ export const Tooltip = ({ label, children, side = "top", open, defaultOpen, onOpenChange, className, }) => (_jsx(BaseTooltip.Provider, { children: _jsxs(BaseTooltip.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: (next) => onOpenChange?.(next), children: [_jsx(BaseTooltip.Trigger, { render: children }), _jsx(BaseTooltip.Portal, { children: _jsx(BaseTooltip.Positioner, { side: side, children: _jsx(BaseTooltip.Popup, { className: cn("bg-surface text-fg border border-border px-2 py-1 text-sm rounded-sm shadow-md", className), children: label }) }) })] }) }));
14
+ //# sourceMappingURL=tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.js","sourceRoot":"","sources":["../src/tooltip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGhE,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,OAAO,GAAoC,CAAC,EACvD,KAAK,EACL,QAAQ,EACR,IAAI,GAAG,KAAK,EACZ,IAAI,EACJ,WAAW,EACX,YAAY,EACZ,SAAS,GACV,EAAE,EAAE,CAAC,CACJ,KAAC,WAAW,CAAC,QAAQ,cACnB,MAAC,WAAW,CAAC,IAAI,IACf,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,aAE5C,KAAC,WAAW,CAAC,OAAO,IAAC,MAAM,EAAE,QAAQ,GAAI,EACzC,KAAC,WAAW,CAAC,MAAM,cACjB,KAAC,WAAW,CAAC,UAAU,IAAC,IAAI,EAAE,IAAI,YAChC,KAAC,WAAW,CAAC,KAAK,IAChB,SAAS,EAAE,EAAE,CACX,gFAAgF,EAChF,SAAS,CACV,YAEA,KAAK,GACY,GACG,GACN,IACJ,GACE,CACxB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@eeennsu/web",
3
+ "version": "0.1.0",
4
+ "description": "웹(React 19 + Tailwind v4) 디자인 시스템 컴포넌트",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": [
8
+ "*.css"
9
+ ],
10
+ "files": [
11
+ "dist",
12
+ "themes"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "./themes/*.css": "./themes/*.css"
20
+ },
21
+ "dependencies": {
22
+ "@base-ui/react": "1.8.0",
23
+ "lucide-react": "1.41.0",
24
+ "tailwind-merge": "^3.6.0",
25
+ "@eeennsu/tokens": "0.1.0"
26
+ },
27
+ "peerDependencies": {
28
+ "react": ">=19",
29
+ "react-dom": ">=19",
30
+ "tailwindcss": ">=4.1"
31
+ },
32
+ "devDependencies": {
33
+ "@testing-library/jest-dom": "^7.0.1",
34
+ "@testing-library/react": "^16.3.3",
35
+ "@types/react": "^19.2.2",
36
+ "@types/react-dom": "^19.2.2",
37
+ "jsdom": "^30.0.1",
38
+ "react": "^19.2.0",
39
+ "react-dom": "^19.2.0",
40
+ "tailwindcss": "^4.3.3"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.json",
44
+ "test": "vitest run --typecheck --passWithNoTests"
45
+ }
46
+ }
@@ -0,0 +1,16 @@
1
+ /* 생성 파일. packages/tokens/scripts/build.ts 가 만든다. 직접 수정하지 않는다. */
2
+ /* @eeennsu/web — brand: bakery. 소비자 공개 경로다(C-3). */
3
+
4
+ @import "tailwindcss";
5
+ @import "@eeennsu/tokens/themes/bakery.css";
6
+
7
+ /* 다크모드 hybrid — 루트 클래스가 OS 설정보다 우선한다(C-20). */
8
+ @custom-variant dark {
9
+ &:where(.dark, .dark *) { @slot; }
10
+ @media (prefers-color-scheme: dark) {
11
+ &:where(:not(.light, .light *)) { @slot; }
12
+ }
13
+ }
14
+
15
+ /* DS 컴포넌트의 정적 클래스 문자열을 스캔한다(C-3 · C-4 (2)). */
16
+ @source "../dist";
@@ -0,0 +1,16 @@
1
+ /* 생성 파일. packages/tokens/scripts/build.ts 가 만든다. 직접 수정하지 않는다. */
2
+ /* @eeennsu/web — brand: base. 소비자 공개 경로다(C-3). */
3
+
4
+ @import "tailwindcss";
5
+ @import "@eeennsu/tokens/themes/base.css";
6
+
7
+ /* 다크모드 hybrid — 루트 클래스가 OS 설정보다 우선한다(C-20). */
8
+ @custom-variant dark {
9
+ &:where(.dark, .dark *) { @slot; }
10
+ @media (prefers-color-scheme: dark) {
11
+ &:where(:not(.light, .light *)) { @slot; }
12
+ }
13
+ }
14
+
15
+ /* DS 컴포넌트의 정적 클래스 문자열을 스캔한다(C-3 · C-4 (2)). */
16
+ @source "../dist";