@xonic0506/sonic-ui 0.1.0 → 0.2.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 (54) hide show
  1. package/AI-RULES.md +1 -1
  2. package/DESIGN.md +355 -16
  3. package/README.md +2 -0
  4. package/dist/components/alert-dialog.d.ts +16 -0
  5. package/dist/components/alert-dialog.js +46 -0
  6. package/dist/components/badge.d.ts +8 -0
  7. package/dist/components/badge.js +77 -0
  8. package/dist/components/button.d.ts +11 -2
  9. package/dist/components/button.js +24 -14
  10. package/dist/components/checkbox.d.ts +30 -0
  11. package/dist/components/checkbox.js +48 -0
  12. package/dist/components/dialog.d.ts +11 -0
  13. package/dist/components/dialog.js +17 -14
  14. package/dist/components/empty-state.d.ts +11 -0
  15. package/dist/components/empty-state.js +17 -0
  16. package/dist/components/error-state.d.ts +12 -0
  17. package/dist/components/error-state.js +24 -0
  18. package/dist/components/field.d.ts +13 -0
  19. package/dist/components/field.js +33 -0
  20. package/dist/components/input.d.ts +1 -0
  21. package/dist/components/input.js +5 -5
  22. package/dist/components/menu.d.ts +33 -0
  23. package/dist/components/menu.js +44 -0
  24. package/dist/components/popover.d.ts +26 -0
  25. package/dist/components/popover.js +50 -0
  26. package/dist/components/popup-styles.d.ts +3 -0
  27. package/dist/components/popup-styles.js +5 -0
  28. package/dist/components/progress.d.ts +16 -0
  29. package/dist/components/progress.js +27 -0
  30. package/dist/components/radio-group.d.ts +20 -0
  31. package/dist/components/radio-group.js +40 -0
  32. package/dist/components/select.d.ts +30 -0
  33. package/dist/components/select.js +66 -0
  34. package/dist/components/separator.d.ts +7 -0
  35. package/dist/components/separator.js +14 -0
  36. package/dist/components/skeleton.d.ts +8 -0
  37. package/dist/components/skeleton.js +22 -0
  38. package/dist/components/state-layout.d.ts +11 -0
  39. package/dist/components/state-layout.js +31 -0
  40. package/dist/components/switch.d.ts +12 -0
  41. package/dist/components/switch.js +24 -0
  42. package/dist/components/tabs.d.ts +31 -0
  43. package/dist/components/tabs.js +41 -0
  44. package/dist/components/textarea.d.ts +6 -0
  45. package/dist/components/textarea.js +20 -0
  46. package/dist/components/toast.d.ts +24 -0
  47. package/dist/components/toast.js +62 -0
  48. package/dist/components/tooltip.d.ts +11 -0
  49. package/dist/components/tooltip.js +19 -0
  50. package/dist/index.d.ts +18 -0
  51. package/dist/index.js +23 -5
  52. package/dist/styles.css +1 -1
  53. package/dist/tailwind.css +15 -0
  54. package/package.json +4 -2
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import { choiceFocusClass as t, choiceLabelClass as n } from "./checkbox.js";
4
+ import * as r from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ import { Fieldset as o } from "@base-ui/react/fieldset";
7
+ import { Radio as s } from "@base-ui/react/radio";
8
+ import { RadioGroup as c } from "@base-ui/react/radio-group";
9
+ //#region src/components/radio-group.tsx
10
+ function l({ label: t, value: n, defaultValue: r, onValueChange: s, disabled: l, name: u, className: d, children: f }) {
11
+ return /* @__PURE__ */ a(o.Root, {
12
+ className: e("sn:m-0 sn:flex sn:min-w-0 sn:flex-col sn:gap-3 sn:border-0 sn:p-0 sn:font-sans", d),
13
+ children: [/* @__PURE__ */ i(o.Legend, {
14
+ className: "sn:p-0 sn:text-label sn:text-default",
15
+ children: t
16
+ }), /* @__PURE__ */ i(c, {
17
+ value: n,
18
+ defaultValue: r,
19
+ onValueChange: s && ((e) => s(e)),
20
+ disabled: l,
21
+ name: u,
22
+ className: "sn:flex sn:flex-col sn:gap-2",
23
+ children: f
24
+ })]
25
+ });
26
+ }
27
+ var u = r.forwardRef(function({ value: r, disabled: o, className: c, children: l }, u) {
28
+ return /* @__PURE__ */ a("label", {
29
+ className: e(n, o && "sn:cursor-not-allowed sn:opacity-(--sn-opacity-disabled)", c),
30
+ children: [/* @__PURE__ */ i(s.Root, {
31
+ ref: u,
32
+ value: r,
33
+ disabled: o,
34
+ className: e("sn:box-border sn:inline-flex sn:size-4 sn:shrink-0 sn:items-center sn:justify-center sn:rounded-full sn:border sn:border-strong sn:bg-surface sn:data-checked:border-transparent sn:data-checked:bg-primary", t),
35
+ children: /* @__PURE__ */ i(s.Indicator, { className: "sn:size-2 sn:rounded-full sn:bg-(--sn-color-text-on-primary)" })
36
+ }), l]
37
+ });
38
+ });
39
+ //#endregion
40
+ export { u as Radio, l as RadioGroup };
@@ -0,0 +1,30 @@
1
+ import * as React from 'react';
2
+ export interface SelectOption {
3
+ value: string;
4
+ label: string;
5
+ disabled?: boolean;
6
+ }
7
+ interface SelectBaseProps {
8
+ options: SelectOption[];
9
+ placeholder?: string;
10
+ invalid?: boolean;
11
+ disabled?: boolean;
12
+ name?: string;
13
+ id?: string;
14
+ className?: string;
15
+ 'aria-label'?: string;
16
+ }
17
+ /** multiple이면 값이 배열이에요 */
18
+ export type SelectProps = SelectBaseProps & ({
19
+ multiple?: false;
20
+ value?: string | null;
21
+ defaultValue?: string | null;
22
+ onValueChange?: (value: string | null) => void;
23
+ } | {
24
+ multiple: true;
25
+ value?: string[];
26
+ defaultValue?: string[];
27
+ onValueChange?: (value: string[]) => void;
28
+ });
29
+ export declare function Select(props: SelectProps): React.JSX.Element;
30
+ export {};
@@ -0,0 +1,66 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import { inputClass as t } from "./input.js";
4
+ import { itemClass as n, popupClass as r } from "./popup-styles.js";
5
+ import "react";
6
+ import { Check as i, ChevronDown as a } from "lucide-react";
7
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
8
+ import { Select as c } from "@base-ui/react/select";
9
+ //#region src/components/select.tsx
10
+ function l(l) {
11
+ let { options: u, placeholder: d, invalid: f, disabled: p, name: m, id: h, className: g, multiple: _ } = l, v = (e) => u.find((t) => t.value === e)?.label ?? e;
12
+ return /* @__PURE__ */ s(c.Root, {
13
+ items: u,
14
+ multiple: _,
15
+ value: l.value,
16
+ defaultValue: l.defaultValue,
17
+ onValueChange: l.onValueChange && ((e) => l.onValueChange(e)),
18
+ disabled: p,
19
+ name: m,
20
+ children: [/* @__PURE__ */ s(c.Trigger, {
21
+ id: h,
22
+ "aria-label": l["aria-label"],
23
+ "aria-invalid": f || void 0,
24
+ className: e(t, "sn:group sn:flex sn:h-8 sn:items-center sn:gap-2 sn:text-left sn:cursor-default sn:data-popup-open:border-focus", g),
25
+ children: [/* @__PURE__ */ o(c.Value, {
26
+ placeholder: d,
27
+ className: "sn:min-w-0 sn:flex-1 sn:truncate sn:data-placeholder:text-muted",
28
+ children: _ ? (e) => e.length ? e.map(v).join(", ") : d : void 0
29
+ }), /* @__PURE__ */ o(c.Icon, {
30
+ className: "sn:flex sn:text-muted sn:transition-transform sn:duration-(--sn-duration-fast) sn:group-data-popup-open:rotate-180 sn:motion-reduce:transition-none sn:[&_svg]:size-4",
31
+ children: /* @__PURE__ */ o(a, {})
32
+ })]
33
+ }), /* @__PURE__ */ o(c.Portal, { children: /* @__PURE__ */ o(c.Positioner, {
34
+ sideOffset: 4,
35
+ alignItemWithTrigger: !1,
36
+ className: "sn:z-50 sn:outline-none",
37
+ children: /* @__PURE__ */ o(c.Popup, {
38
+ className: r,
39
+ children: /* @__PURE__ */ o(c.List, { children: u.map((t) => /* @__PURE__ */ s(c.Item, {
40
+ value: t.value,
41
+ disabled: t.disabled,
42
+ className: n,
43
+ children: [
44
+ _ && /* @__PURE__ */ o("span", {
45
+ className: e("sn:box-border sn:inline-flex sn:size-4 sn:shrink-0 sn:items-center sn:justify-center sn:rounded-sm sn:border sn:border-strong sn:bg-surface sn:text-on-primary sn:[&_svg]:size-3", "sn:group-data-selected:border-transparent sn:group-data-selected:bg-primary"),
46
+ children: /* @__PURE__ */ o(c.ItemIndicator, {
47
+ className: "sn:flex",
48
+ children: /* @__PURE__ */ o(i, {})
49
+ })
50
+ }),
51
+ /* @__PURE__ */ o(c.ItemText, {
52
+ className: "sn:min-w-0 sn:flex-1 sn:truncate",
53
+ children: t.label
54
+ }),
55
+ !_ && /* @__PURE__ */ o(c.ItemIndicator, {
56
+ className: "sn:flex",
57
+ children: /* @__PURE__ */ o(i, {})
58
+ })
59
+ ]
60
+ }, t.value)) })
61
+ })
62
+ }) })]
63
+ });
64
+ }
65
+ //#endregion
66
+ export { l as Select };
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ export interface SeparatorProps {
3
+ orientation?: 'horizontal' | 'vertical';
4
+ className?: string;
5
+ }
6
+ /** 관련 없는 묶음 사이를 나눌 때만 써요. 1px border/default */
7
+ export declare function Separator({ orientation, className }: SeparatorProps): React.JSX.Element;
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import "react";
4
+ import { jsx as t } from "react/jsx-runtime";
5
+ import { Separator as n } from "@base-ui/react/separator";
6
+ //#region src/components/separator.tsx
7
+ function r({ orientation: r = "horizontal", className: i }) {
8
+ return /* @__PURE__ */ t(n, {
9
+ orientation: r,
10
+ className: e("sn:shrink-0 sn:border-0 sn:bg-(--sn-color-border-default)", r === "horizontal" ? "sn:h-px sn:w-full" : "sn:w-px sn:self-stretch", i)
11
+ });
12
+ }
13
+ //#endregion
14
+ export { r as Separator };
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ export interface SkeletonProps {
3
+ shape?: 'text' | 'rect' | 'circle';
4
+ /** 크기는 쓰는 곳에서 정해요 (예: className="w-40") */
5
+ className?: string;
6
+ }
7
+ /** 로딩 자리 표시. 스크린 리더에는 숨겨요 — 로딩 영역 전체에 aria-busy를 두세요 */
8
+ export declare function Skeleton({ shape, className }: SkeletonProps): React.JSX.Element;
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import "react";
4
+ import { cva as t } from "class-variance-authority";
5
+ import { jsx as n } from "react/jsx-runtime";
6
+ //#region src/components/skeleton.tsx
7
+ var r = t("sn:block sn:shrink-0 sn:bg-subtle sn:animate-[sn-pulse_var(--sn-duration-loop)_ease-in-out_infinite] sn:motion-reduce:animate-none", {
8
+ variants: { shape: {
9
+ text: "sn:h-3 sn:w-full sn:rounded-sm",
10
+ rect: "sn:h-16 sn:w-full sn:rounded-md",
11
+ circle: "sn:size-8 sn:rounded-full"
12
+ } },
13
+ defaultVariants: { shape: "text" }
14
+ });
15
+ function i({ shape: t, className: i }) {
16
+ return /* @__PURE__ */ n("span", {
17
+ "aria-hidden": !0,
18
+ className: e(r({ shape: t }), i)
19
+ });
20
+ }
21
+ //#endregion
22
+ export { i as Skeleton };
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ export interface StateLayoutProps {
3
+ icon?: React.ReactNode;
4
+ iconClassName: string;
5
+ title: React.ReactNode;
6
+ description?: React.ReactNode;
7
+ className?: string;
8
+ role?: 'alert';
9
+ children?: React.ReactNode;
10
+ }
11
+ export declare function StateLayout({ icon, iconClassName, title, description, className, role, children }: StateLayoutProps): React.JSX.Element;
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import "react";
4
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
+ //#region src/components/state-layout.tsx
6
+ function r({ icon: r, iconClassName: i, title: a, description: o, className: s, role: c, children: l }) {
7
+ return /* @__PURE__ */ n("div", {
8
+ role: c,
9
+ className: e("sn:box-border sn:flex sn:flex-col sn:items-center sn:gap-4 sn:px-6 sn:py-12 sn:text-center sn:font-sans", s),
10
+ children: [
11
+ r && /* @__PURE__ */ t("span", {
12
+ "aria-hidden": !0,
13
+ className: e("sn:inline-flex sn:size-12 sn:items-center sn:justify-center sn:rounded-full sn:bg-subtle sn:[&_svg]:size-6", i),
14
+ children: r
15
+ }),
16
+ /* @__PURE__ */ n("div", {
17
+ className: "sn:flex sn:flex-col sn:gap-1",
18
+ children: [/* @__PURE__ */ t("p", {
19
+ className: "sn:m-0 sn:text-body-strong sn:text-default",
20
+ children: a
21
+ }), o && /* @__PURE__ */ t("p", {
22
+ className: "sn:m-0 sn:text-body sn:text-muted",
23
+ children: o
24
+ })]
25
+ }),
26
+ l
27
+ ]
28
+ });
29
+ }
30
+ //#endregion
31
+ export { r as StateLayout };
@@ -0,0 +1,12 @@
1
+ import * as React from 'react';
2
+ export interface SwitchProps {
3
+ checked?: boolean;
4
+ defaultChecked?: boolean;
5
+ onCheckedChange?: (checked: boolean) => void;
6
+ disabled?: boolean;
7
+ name?: string;
8
+ className?: string;
9
+ children?: React.ReactNode;
10
+ }
11
+ /** 누르는 즉시 적용되는 설정에만 써요 */
12
+ export declare const Switch: React.ForwardRefExoticComponent<SwitchProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import { choiceFocusClass as t, choiceLabelClass as n } from "./checkbox.js";
4
+ import * as r from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ import { Switch as o } from "@base-ui/react/switch";
7
+ //#region src/components/switch.tsx
8
+ var s = r.forwardRef(function({ checked: r, defaultChecked: s, onCheckedChange: c, disabled: l, name: u, className: d, children: f }, p) {
9
+ return /* @__PURE__ */ a("label", {
10
+ className: e(n, l && "sn:cursor-not-allowed sn:opacity-(--sn-opacity-disabled)", d),
11
+ children: [/* @__PURE__ */ i(o.Root, {
12
+ ref: p,
13
+ checked: r,
14
+ defaultChecked: s,
15
+ onCheckedChange: c && ((e) => c(e)),
16
+ disabled: l,
17
+ name: u,
18
+ className: e("sn:box-border sn:inline-flex sn:h-4 sn:w-7 sn:shrink-0 sn:items-center sn:rounded-full sn:border sn:border-strong sn:bg-subtle sn:p-px sn:transition-colors sn:duration-(--sn-duration-fast) sn:ease-standard sn:data-checked:border-transparent sn:data-checked:bg-primary sn:motion-reduce:transition-none", t),
19
+ children: /* @__PURE__ */ i(o.Thumb, { className: "sn:block sn:size-3 sn:rounded-full sn:bg-surface sn:transition-transform sn:duration-(--sn-duration-fast) sn:ease-standard sn:data-checked:translate-x-3 sn:data-checked:bg-(--sn-color-text-on-primary) sn:motion-reduce:transition-none" })
20
+ }), f]
21
+ });
22
+ });
23
+ //#endregion
24
+ export { s as Switch };
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ export interface TabsProps {
3
+ value?: string;
4
+ defaultValue?: string;
5
+ onValueChange?: (value: string) => void;
6
+ className?: string;
7
+ children?: React.ReactNode;
8
+ }
9
+ /** 같은 대상의 다른 보기를 오갈 때 써요. 페이지 이동 링크에는 쓰지 않아요 */
10
+ export declare function Tabs({ value, defaultValue, onValueChange, className, children }: TabsProps): React.JSX.Element;
11
+ export interface TabsListProps {
12
+ /** 화살표 키로 이동하면 바로 탭을 바꿀지 (기본 true). false면 화살표로 이동하고 Enter·Space로 바꿔요 */
13
+ activateOnFocus?: boolean;
14
+ /** 끝에서 화살표를 누르면 처음으로 돌아갈지 (기본 true) */
15
+ loopFocus?: boolean;
16
+ className?: string;
17
+ children?: React.ReactNode;
18
+ }
19
+ export declare function TabsList({ activateOnFocus, loopFocus, className, children }: TabsListProps): React.JSX.Element;
20
+ export interface TabProps {
21
+ value: string;
22
+ disabled?: boolean;
23
+ className?: string;
24
+ children?: React.ReactNode;
25
+ }
26
+ export declare const Tab: React.ForwardRefExoticComponent<TabProps & React.RefAttributes<HTMLButtonElement>>;
27
+ export declare function TabsPanel({ value, className, children }: {
28
+ value: string;
29
+ className?: string;
30
+ children?: React.ReactNode;
31
+ }): React.JSX.Element;
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import * as t from "react";
4
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
5
+ import { Tabs as i } from "@base-ui/react/tabs";
6
+ //#region src/components/tabs.tsx
7
+ function a({ value: t, defaultValue: r, onValueChange: a, className: o, children: s }) {
8
+ return /* @__PURE__ */ n(i.Root, {
9
+ value: t,
10
+ defaultValue: r,
11
+ onValueChange: a && ((e) => a(e)),
12
+ className: e("sn:flex sn:flex-col sn:gap-4 sn:font-sans", o),
13
+ children: s
14
+ });
15
+ }
16
+ function o({ activateOnFocus: t = !0, loopFocus: a = !0, className: o, children: s }) {
17
+ return /* @__PURE__ */ r(i.List, {
18
+ activateOnFocus: t,
19
+ loopFocus: a,
20
+ className: e("sn:relative sn:flex sn:border-b sn:border-default", o),
21
+ children: [s, /* @__PURE__ */ n(i.Indicator, { className: "sn:absolute sn:bottom-[-1px] sn:left-0 sn:h-0.5 sn:w-(--active-tab-width) sn:translate-x-(--active-tab-left) sn:bg-primary sn:transition-[translate,width] sn:duration-(--sn-duration-normal) sn:ease-standard sn:motion-reduce:transition-none" })]
22
+ });
23
+ }
24
+ var s = t.forwardRef(function({ value: t, disabled: r, className: a, children: o }, s) {
25
+ return /* @__PURE__ */ n(i.Tab, {
26
+ ref: s,
27
+ value: t,
28
+ disabled: r,
29
+ className: e("sn:box-border sn:flex sn:h-8 sn:items-center sn:border-0 sn:bg-transparent sn:px-3 sn:font-sans sn:text-body-strong sn:text-muted sn:cursor-pointer sn:focus-visible:outline-2 sn:focus-visible:-outline-offset-2 sn:focus-visible:outline-focus sn:transition-colors sn:duration-(--sn-duration-fast) sn:hover:not-data-disabled:text-default sn:data-active:text-default sn:data-disabled:cursor-not-allowed sn:data-disabled:opacity-(--sn-opacity-disabled)", a),
30
+ children: o
31
+ });
32
+ });
33
+ function c({ value: t, className: r, children: a }) {
34
+ return /* @__PURE__ */ n(i.Panel, {
35
+ value: t,
36
+ className: e("sn:text-body sn:text-default sn:focus-visible:outline-2 sn:focus-visible:outline-offset-2 sn:focus-visible:outline-focus", r),
37
+ children: a
38
+ });
39
+ }
40
+ //#endregion
41
+ export { s as Tab, a as Tabs, o as TabsList, c as TabsPanel };
@@ -0,0 +1,6 @@
1
+ import * as React from 'react';
2
+ export interface TextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'className'> {
3
+ invalid?: boolean;
4
+ className?: string;
5
+ }
6
+ export declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import { inputClass as t } from "./input.js";
4
+ import * as n from "react";
5
+ import { jsx as r } from "react/jsx-runtime";
6
+ import { Input as i } from "@base-ui/react/input";
7
+ //#region src/components/textarea.tsx
8
+ var a = n.forwardRef(function({ invalid: n, className: a, rows: o = 3, ...s }, c) {
9
+ return /* @__PURE__ */ r(i, {
10
+ render: /* @__PURE__ */ r("textarea", {
11
+ ref: c,
12
+ rows: o
13
+ }),
14
+ "aria-invalid": n || void 0,
15
+ className: e(t, "sn:min-h-20 sn:resize-y sn:py-2", a),
16
+ ...s
17
+ });
18
+ });
19
+ //#endregion
20
+ export { a as Textarea };
@@ -0,0 +1,24 @@
1
+ import * as React from 'react';
2
+ export type ToastTone = 'neutral' | 'success' | 'warning' | 'danger';
3
+ export interface ToastOptions {
4
+ /** 결과 한 줄 */
5
+ title: React.ReactNode;
6
+ description?: React.ReactNode;
7
+ tone?: ToastTone;
8
+ /** 사라지기까지 ms. 0이면 직접 닫을 때까지 남아요 (기본 5000) */
9
+ timeout?: number;
10
+ }
11
+ /** ToastProvider 안의 클라이언트 컴포넌트에서만 써요 */
12
+ export declare function useToast(): {
13
+ /** 알림을 띄우고 id를 돌려줘요 */
14
+ add: ({ tone, ...options }: ToastOptions) => string;
15
+ /** id가 없으면 모두 닫아요 */
16
+ close: (id?: string) => void;
17
+ };
18
+ export interface ToastProviderProps {
19
+ /** 기본 사라지는 시간 ms (기본 5000) */
20
+ timeout?: number;
21
+ children?: React.ReactNode;
22
+ }
23
+ /** 앱 최상단에 한 번 둬요. 알림은 화면 오른쪽 아래에 쌓여요 */
24
+ export declare function ToastProvider({ timeout, children }: ToastProviderProps): React.JSX.Element;
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import { Button as t } from "./button.js";
4
+ import * as n from "react";
5
+ import { CircleAlert as r, CircleCheck as i, Info as a, TriangleAlert as o, X as s } from "lucide-react";
6
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
+ import { Toast as u } from "@base-ui/react/toast";
8
+ //#region src/components/toast.tsx
9
+ var d = {
10
+ neutral: /* @__PURE__ */ c(a, { className: "sn:text-muted" }),
11
+ success: /* @__PURE__ */ c(i, { className: "sn:text-success" }),
12
+ warning: /* @__PURE__ */ c(o, { className: "sn:text-warning" }),
13
+ danger: /* @__PURE__ */ c(r, { className: "sn:text-danger" })
14
+ };
15
+ function f() {
16
+ let { add: e, close: t } = u.useToastManager();
17
+ return n.useMemo(() => ({
18
+ add: ({ tone: t = "neutral", ...n }) => e({
19
+ ...n,
20
+ type: t,
21
+ priority: t === "danger" ? "high" : "low"
22
+ }),
23
+ close: (e) => t(e)
24
+ }), [e, t]);
25
+ }
26
+ function p({ timeout: e, children: t }) {
27
+ return /* @__PURE__ */ l(u.Provider, {
28
+ timeout: e,
29
+ children: [t, /* @__PURE__ */ c(u.Portal, { children: /* @__PURE__ */ c(u.Viewport, {
30
+ "aria-label": "알림",
31
+ className: "sn:fixed sn:right-4 sn:bottom-4 sn:z-50 sn:flex sn:w-90 sn:max-w-[calc(100vw-2*var(--sn-space-4))] sn:flex-col-reverse sn:gap-2 sn:outline-none",
32
+ children: /* @__PURE__ */ c(m, {})
33
+ }) })]
34
+ });
35
+ }
36
+ function m() {
37
+ let { toasts: n } = u.useToastManager();
38
+ return n.map((n) => /* @__PURE__ */ l(u.Root, {
39
+ toast: n,
40
+ className: "sn:box-border sn:flex sn:items-start sn:gap-3 sn:rounded-lg sn:border sn:border-default sn:bg-surface sn:p-3 sn:font-sans sn:text-default sn:transition-[opacity,translate] sn:duration-(--sn-duration-normal) sn:ease-standard sn:focus-visible:outline-2 sn:focus-visible:outline-offset-2 sn:focus-visible:outline-focus sn:data-starting-style:translate-y-2 sn:data-starting-style:opacity-0 sn:data-ending-style:translate-y-2 sn:data-ending-style:opacity-0 sn:data-limited:hidden sn:motion-reduce:transition-none",
41
+ children: [
42
+ /* @__PURE__ */ c("span", {
43
+ className: "sn:flex sn:h-7 sn:shrink-0 sn:items-center sn:[&_svg]:size-4",
44
+ children: d[n.type ?? "neutral"]
45
+ }),
46
+ /* @__PURE__ */ l("div", {
47
+ className: "sn:flex sn:min-w-0 sn:flex-1 sn:flex-col sn:gap-1 sn:pt-1",
48
+ children: [/* @__PURE__ */ c(u.Title, { className: "sn:m-0 sn:text-body-strong sn:text-default" }), /* @__PURE__ */ c(u.Description, { className: e("sn:m-0 sn:text-caption sn:text-muted", !n.description && "sn:hidden") })]
49
+ }),
50
+ /* @__PURE__ */ c(u.Close, {
51
+ render: /* @__PURE__ */ c(t, {
52
+ size: "icon-sm",
53
+ variant: "ghost",
54
+ "aria-label": "알림 닫기"
55
+ }),
56
+ children: /* @__PURE__ */ c(s, {})
57
+ })
58
+ ]
59
+ }, n.id));
60
+ }
61
+ //#endregion
62
+ export { p as ToastProvider, f as useToast };
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ export interface TooltipProps {
3
+ /** 보여 줄 짧은 이름. 중요한 정보나 클릭할 요소는 넣지 않아요 */
4
+ content: React.ReactNode;
5
+ side?: 'top' | 'bottom' | 'left' | 'right';
6
+ className?: string;
7
+ /** 대상 요소 하나 (보통 아이콘 버튼) */
8
+ children: React.ReactElement;
9
+ }
10
+ /** 마우스는 600ms 뒤, 키보드 포커스는 바로 보여요 */
11
+ export declare function Tooltip({ content, side, className, children }: TooltipProps): React.JSX.Element;
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { cn as e } from "../lib/cn.js";
3
+ import "react";
4
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
+ import { Tooltip as r } from "@base-ui/react/tooltip";
6
+ //#region src/components/tooltip.tsx
7
+ function i({ content: i, side: a = "top", className: o, children: s }) {
8
+ return /* @__PURE__ */ n(r.Root, { children: [/* @__PURE__ */ t(r.Trigger, { render: s }), /* @__PURE__ */ t(r.Portal, { children: /* @__PURE__ */ t(r.Positioner, {
9
+ side: a,
10
+ sideOffset: 4,
11
+ className: "sn:z-50",
12
+ children: /* @__PURE__ */ t(r.Popup, {
13
+ className: e("sn:origin-(--transform-origin) sn:rounded-md sn:bg-inverse sn:px-2 sn:py-1 sn:font-sans sn:text-caption sn:text-inverse sn:transition-[opacity,scale] sn:duration-(--sn-duration-fast) sn:ease-standard sn:data-starting-style:scale-98 sn:data-starting-style:opacity-0 sn:data-ending-style:scale-98 sn:data-ending-style:opacity-0 sn:motion-reduce:transition-none", o),
14
+ children: i
15
+ })
16
+ }) })] });
17
+ }
18
+ //#endregion
19
+ export { i as Tooltip };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,24 @@
1
1
  export { Button, type ButtonProps } from './components/button';
2
2
  export { Input, type InputProps } from './components/input';
3
+ export { Textarea, type TextareaProps } from './components/textarea';
4
+ export { Checkbox, CheckboxGroup, type CheckboxProps, type CheckboxGroupProps } from './components/checkbox';
5
+ export { RadioGroup, Radio, type RadioGroupProps, type RadioProps } from './components/radio-group';
6
+ export { Switch, type SwitchProps } from './components/switch';
7
+ export { Select, type SelectProps, type SelectOption } from './components/select';
3
8
  export { Text, type TextProps, type TextVariant } from './components/text';
4
9
  export { Card, CardHeader, CardTitle, CardDescription, CardBody, CardFooter, type CardProps } from './components/card';
5
10
  export { Avatar, type AvatarProps } from './components/avatar';
11
+ export { Field, type FieldProps } from './components/field';
12
+ export { Skeleton, type SkeletonProps } from './components/skeleton';
13
+ export { EmptyState, type EmptyStateProps } from './components/empty-state';
14
+ export { ErrorState, type ErrorStateProps } from './components/error-state';
6
15
  export { Dialog, DialogTrigger, DialogPopup, DialogTitle, DialogDescription, DialogClose, DialogFooter, type DialogProps, type DialogButtonProps, type DialogPopupProps, } from './components/dialog';
16
+ export { AlertDialog, AlertDialogTrigger, AlertDialogPopup, AlertDialogTitle, AlertDialogDescription, AlertDialogClose, AlertDialogFooter, } from './components/alert-dialog';
17
+ export { Menu, MenuTrigger, MenuPopup, MenuItem, MenuSeparator, type MenuProps, type MenuTriggerProps, type MenuPopupProps, type MenuItemProps } from './components/menu';
18
+ export { Popover, PopoverTrigger, PopoverPopup, PopoverTitle, PopoverDescription, PopoverClose, type PopoverProps, type PopoverPopupProps } from './components/popover';
19
+ export { Tooltip, type TooltipProps } from './components/tooltip';
20
+ export { Tabs, TabsList, Tab, TabsPanel, type TabsProps, type TabsListProps, type TabProps } from './components/tabs';
21
+ export { Separator, type SeparatorProps } from './components/separator';
22
+ export { ToastProvider, useToast, type ToastProviderProps, type ToastOptions, type ToastTone } from './components/toast';
23
+ export { Badge, type BadgeProps } from './components/badge';
24
+ export { Progress, type ProgressProps } from './components/progress';
package/dist/index.js CHANGED
@@ -1,8 +1,26 @@
1
1
  "use client";
2
2
  import { Button as e } from "./components/button.js";
3
3
  import { Input as t } from "./components/input.js";
4
- import { Text as n } from "./components/text.js";
5
- import { Card as r, CardBody as i, CardDescription as a, CardFooter as o, CardHeader as s, CardTitle as c } from "./components/card.js";
6
- import { Avatar as l } from "./components/avatar.js";
7
- import { Dialog as u, DialogClose as d, DialogDescription as f, DialogFooter as p, DialogPopup as m, DialogTitle as h, DialogTrigger as g } from "./components/dialog.js";
8
- export { l as Avatar, e as Button, r as Card, i as CardBody, a as CardDescription, o as CardFooter, s as CardHeader, c as CardTitle, u as Dialog, d as DialogClose, f as DialogDescription, p as DialogFooter, m as DialogPopup, h as DialogTitle, g as DialogTrigger, t as Input, n as Text };
4
+ import { Textarea as n } from "./components/textarea.js";
5
+ import { Checkbox as r, CheckboxGroup as i } from "./components/checkbox.js";
6
+ import { Radio as a, RadioGroup as o } from "./components/radio-group.js";
7
+ import { Switch as s } from "./components/switch.js";
8
+ import { Select as c } from "./components/select.js";
9
+ import { Text as l } from "./components/text.js";
10
+ import { Card as u, CardBody as d, CardDescription as f, CardFooter as p, CardHeader as m, CardTitle as h } from "./components/card.js";
11
+ import { Avatar as g } from "./components/avatar.js";
12
+ import { Field as _ } from "./components/field.js";
13
+ import { Skeleton as v } from "./components/skeleton.js";
14
+ import { EmptyState as y } from "./components/empty-state.js";
15
+ import { ErrorState as b } from "./components/error-state.js";
16
+ import { Dialog as x, DialogClose as S, DialogDescription as C, DialogFooter as w, DialogPopup as T, DialogTitle as E, DialogTrigger as D } from "./components/dialog.js";
17
+ import { AlertDialog as O, AlertDialogClose as k, AlertDialogDescription as A, AlertDialogFooter as j, AlertDialogPopup as M, AlertDialogTitle as N, AlertDialogTrigger as P } from "./components/alert-dialog.js";
18
+ import { Menu as F, MenuItem as I, MenuPopup as L, MenuSeparator as R, MenuTrigger as z } from "./components/menu.js";
19
+ import { Popover as B, PopoverClose as V, PopoverDescription as H, PopoverPopup as U, PopoverTitle as W, PopoverTrigger as G } from "./components/popover.js";
20
+ import { Tooltip as K } from "./components/tooltip.js";
21
+ import { Tab as q, Tabs as J, TabsList as Y, TabsPanel as X } from "./components/tabs.js";
22
+ import { Separator as Z } from "./components/separator.js";
23
+ import { ToastProvider as Q, useToast as $ } from "./components/toast.js";
24
+ import { Badge as ee } from "./components/badge.js";
25
+ import { Progress as te } from "./components/progress.js";
26
+ export { O as AlertDialog, k as AlertDialogClose, A as AlertDialogDescription, j as AlertDialogFooter, M as AlertDialogPopup, N as AlertDialogTitle, P as AlertDialogTrigger, g as Avatar, ee as Badge, e as Button, u as Card, d as CardBody, f as CardDescription, p as CardFooter, m as CardHeader, h as CardTitle, r as Checkbox, i as CheckboxGroup, x as Dialog, S as DialogClose, C as DialogDescription, w as DialogFooter, T as DialogPopup, E as DialogTitle, D as DialogTrigger, y as EmptyState, b as ErrorState, _ as Field, t as Input, F as Menu, I as MenuItem, L as MenuPopup, R as MenuSeparator, z as MenuTrigger, B as Popover, V as PopoverClose, H as PopoverDescription, U as PopoverPopup, W as PopoverTitle, G as PopoverTrigger, te as Progress, a as Radio, o as RadioGroup, c as Select, Z as Separator, v as Skeleton, s as Switch, q as Tab, J as Tabs, Y as TabsList, X as TabsPanel, l as Text, n as Textarea, Q as ToastProvider, K as Tooltip, $ as useToast };