@crossangle-org/cs-ui 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordion/cs-accordion.js +116 -0
- package/dist/components/accordion/cs-accordion.js.map +1 -0
- package/dist/components/alert-dialog/cs-alert-dialog.js +148 -0
- package/dist/components/alert-dialog/cs-alert-dialog.js.map +1 -0
- package/dist/components/avatar/cs-avatar.js +44 -0
- package/dist/components/avatar/cs-avatar.js.map +1 -0
- package/dist/components/badge/cs-badge.js +40 -0
- package/dist/components/badge/cs-badge.js.map +1 -0
- package/dist/components/box/cs-box.js +37 -0
- package/dist/components/box/cs-box.js.map +1 -0
- package/dist/components/button/cs-button.js +91 -0
- package/dist/components/button/cs-button.js.map +1 -0
- package/dist/components/calendar/cs-calendar.js +199 -0
- package/dist/components/calendar/cs-calendar.js.map +1 -0
- package/dist/components/card/cs-card.js +95 -0
- package/dist/components/card/cs-card.js.map +1 -0
- package/dist/components/chart/cs-chart.js +88 -0
- package/dist/components/chart/cs-chart.js.map +1 -0
- package/dist/components/checkbox/cs-checkbox.js +55 -0
- package/dist/components/checkbox/cs-checkbox.js.map +1 -0
- package/dist/components/code-block/cs-code-block.js +39 -0
- package/dist/components/code-block/cs-code-block.js.map +1 -0
- package/dist/components/code-block/cs-code-highlighter.js +59 -0
- package/dist/components/code-block/cs-code-highlighter.js.map +1 -0
- package/dist/components/collapsible/cs-collapsible.js +36 -0
- package/dist/components/collapsible/cs-collapsible.js.map +1 -0
- package/dist/components/date-picker/cs-date-picker.js +25 -0
- package/dist/components/date-picker/cs-date-picker.js.map +1 -0
- package/dist/components/dialog/cs-dialog.js +131 -0
- package/dist/components/dialog/cs-dialog.js.map +1 -0
- package/dist/components/drawer/cs-drawer.js +131 -0
- package/dist/components/drawer/cs-drawer.js.map +1 -0
- package/dist/components/dropdown-menu/cs-dropdown-menu.js +247 -0
- package/dist/components/dropdown-menu/cs-dropdown-menu.js.map +1 -0
- package/dist/components/dropzone/cs-dropzone.js +147 -0
- package/dist/components/dropzone/cs-dropzone.js.map +1 -0
- package/dist/components/empty/cs-empty.js +107 -0
- package/dist/components/empty/cs-empty.js.map +1 -0
- package/dist/components/field/cs-field.js +218 -0
- package/dist/components/field/cs-field.js.map +1 -0
- package/dist/components/input/cs-input-group.js +207 -0
- package/dist/components/input/cs-input-group.js.map +1 -0
- package/dist/components/input/cs-input.js +40 -0
- package/dist/components/input/cs-input.js.map +1 -0
- package/dist/components/label/cs-label.js +26 -0
- package/dist/components/label/cs-label.js.map +1 -0
- package/dist/components/navigation-menu/cs-navigation-menu.js +214 -0
- package/dist/components/navigation-menu/cs-navigation-menu.js.map +1 -0
- package/dist/components/pagination/cs-pagination.js +124 -0
- package/dist/components/pagination/cs-pagination.js.map +1 -0
- package/dist/components/popover/cs-popover.js +60 -0
- package/dist/components/popover/cs-popover.js.map +1 -0
- package/dist/components/progress/cs-progress.js +62 -0
- package/dist/components/progress/cs-progress.js.map +1 -0
- package/dist/components/scroll-area/cs-scroll-area.js +61 -0
- package/dist/components/scroll-area/cs-scroll-area.js.map +1 -0
- package/dist/components/select/cs-select.js +195 -0
- package/dist/components/select/cs-select.js.map +1 -0
- package/dist/components/select/cs-simple-select.js +32 -0
- package/dist/components/select/cs-simple-select.js.map +1 -0
- package/dist/components/separator/cs-separator.js +28 -0
- package/dist/components/separator/cs-separator.js.map +1 -0
- package/dist/components/sheet/cs-sheet.js +128 -0
- package/dist/components/sheet/cs-sheet.js.map +1 -0
- package/dist/components/sidebar/cs-sidebar.js +657 -0
- package/dist/components/sidebar/cs-sidebar.js.map +1 -0
- package/dist/components/skeleton/cs-skeleton.js +32 -0
- package/dist/components/skeleton/cs-skeleton.js.map +1 -0
- package/dist/components/sonner/cs-sonner.js +76 -0
- package/dist/components/sonner/cs-sonner.js.map +1 -0
- package/dist/components/spinner/cs-spinner.js +34 -0
- package/dist/components/spinner/cs-spinner.js.map +1 -0
- package/dist/components/switch/cs-switch.js +38 -0
- package/dist/components/switch/cs-switch.js.map +1 -0
- package/dist/components/table/cs-data-base-table.js +108 -0
- package/dist/components/table/cs-data-base-table.js.map +1 -0
- package/dist/components/table/cs-data-table.js +32 -0
- package/dist/components/table/cs-data-table.js.map +1 -0
- package/dist/components/table/cs-skeleton-table.js +41 -0
- package/dist/components/table/cs-skeleton-table.js.map +1 -0
- package/dist/components/table/cs-table.js +120 -0
- package/dist/components/table/cs-table.js.map +1 -0
- package/dist/components/tabs/cs-simple-tabs.js +24 -0
- package/dist/components/tabs/cs-simple-tabs.js.map +1 -0
- package/dist/components/tabs/cs-tabs.js +114 -0
- package/dist/components/tabs/cs-tabs.js.map +1 -0
- package/dist/components/toggle/cs-toggle-group.js +65 -0
- package/dist/components/toggle/cs-toggle-group.js.map +1 -0
- package/dist/components/toggle/cs-toggle.js +46 -0
- package/dist/components/toggle/cs-toggle.js.map +1 -0
- package/dist/components/tooltip/cs-simple-tooltip.js +16 -0
- package/dist/components/tooltip/cs-simple-tooltip.js.map +1 -0
- package/dist/components/tooltip/cs-tooltip.js +72 -0
- package/dist/components/tooltip/cs-tooltip.js.map +1 -0
- package/dist/constants/cs-chart-option.constant.js +105 -0
- package/dist/constants/cs-chart-option.constant.js.map +1 -0
- package/dist/cs-ui.css +73 -108
- package/dist/hooks/use-accordion.js +54 -0
- package/dist/hooks/use-accordion.js.map +1 -0
- package/dist/hooks/use-infinite-scroll.js +40 -0
- package/dist/hooks/use-infinite-scroll.js.map +1 -0
- package/dist/hooks/use-laptop.js +20 -0
- package/dist/hooks/use-laptop.js.map +1 -0
- package/dist/hooks/use-mobile.js +20 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/index.d.ts +19 -6
- package/dist/index.js +287 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/chart.util.js +48 -0
- package/dist/lib/chart.util.js.map +1 -0
- package/dist/lib/style.util.js +19 -0
- package/dist/lib/style.util.js.map +1 -0
- package/dist/lib/utils.js +27 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +4 -5
- package/dist/index.cjs.js +0 -147659
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.es.js +0 -147624
- package/dist/index.es.js.map +0 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { CsButton } from "../button/cs-button.js";
|
|
6
|
+
const csInputGroupVariants = cva(
|
|
7
|
+
"group/input-group relative flex w-full items-center transition-[color,box-shadow] outline-none min-w-0 border-none ring-(length:--input-common-border-width) rounded-(--input-common-radius) px-(--input-common-padding-x) py-(--input-common-padding-y) gap-(--input-common-gap) has-[>input:disabled]:opacity-(--input-common-opacity) has-[>textarea:disabled]:opacity-(--input-common-opacity)has-[>textarea]:h-auto min-h-(--input-common-height) has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[[data-slot~=input-group-control]:focus-visible]:border-none has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-solid-focus-border) has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-common-border-width) ",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
solid: [
|
|
12
|
+
"bg-(--input-solid-default-bg) ring-transparent",
|
|
13
|
+
"hover:bg-(--input-solid-hover-bg) hover:ring-(--input-solid-hover-border)",
|
|
14
|
+
"has-[[data-slot~=input-group-control]:focus-visible]:bg-(--input-solid-focus-bg) has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-solid-focus-border)",
|
|
15
|
+
"has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:bg-(--input-solid-filled-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:ring-(--input-solid-filled-border)",
|
|
16
|
+
"has-[[data-slot~=input-group-control][aria-invalid=true]]:bg-(--input-solid-fail-bg) has-[[data-slot~=input-group-control][aria-invalid=true]]:ring-(--input-solid-fail-border)",
|
|
17
|
+
"has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:bg-(--input-solid-success-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:ring-(--input-solid-success-border)"
|
|
18
|
+
].join(" "),
|
|
19
|
+
outline: [
|
|
20
|
+
"bg-(--input-outline-default-bg) ring-(length:--input-common-border-width) ring-(--input-outline-default-border)",
|
|
21
|
+
"hover:bg-(--input-outline-hover-bg) hover:ring-(--input-outline-hover-border)",
|
|
22
|
+
"has-[[data-slot~=input-group-control]:focus-visible]:bg-(--input-outline-focus-bg) has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-outline-focus-border)",
|
|
23
|
+
"has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:bg-(--input-outline-filled-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:ring-(--input-outline-filled-border)",
|
|
24
|
+
"has-[[data-slot~=input-group-control][aria-invalid=true]]:bg-(--input-outline-fail-bg) has-[[data-slot~=input-group-control][aria-invalid=true]]:ring-(--input-outline-fail-border)",
|
|
25
|
+
"has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:bg-(--input-outline-success-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:ring-(--input-outline-success-border)"
|
|
26
|
+
].join(" ")
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "solid"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
function CsInputGroup({
|
|
35
|
+
className,
|
|
36
|
+
variant = "solid",
|
|
37
|
+
disabled,
|
|
38
|
+
...props
|
|
39
|
+
}) {
|
|
40
|
+
return /* @__PURE__ */ jsx(
|
|
41
|
+
"div",
|
|
42
|
+
{
|
|
43
|
+
"data-slot": "input-group",
|
|
44
|
+
"data-variant": variant,
|
|
45
|
+
"data-disabled": disabled ? "true" : void 0,
|
|
46
|
+
role: "group",
|
|
47
|
+
className: cn(csInputGroupVariants({ variant }), className),
|
|
48
|
+
...props
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const csInputGroupAddonVariants = cva(
|
|
53
|
+
"flex cursor-text items-center justify-center gap-(--input-common-gap) select-none [&>kbd]:rounded-[calc(var(--input-common-radius)-5px)] group-data-[disabled=true]/input-group:opacity-(--input-common-opacity) [&>svg:not([class*='size-'])]:size-(--input-common-icon-size-sm) group-data-[variant=solid]/input-group:[&>svg]:text-(--input-solid-default-icon) group-data-[variant=solid]/input-group:group-hover/input-group:[&>svg]:text-(--input-solid-hover-icon) group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control]:focus-visible]/input-group:[&>svg]:text-(--input-solid-focus-icon) group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)]/input-group:[&>svg]:text-(--input-solid-filled-icon) group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control][aria-invalid=true]]/input-group:[&>svg]:text-(--input-solid-fail-icon) group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]/input-group:[&>svg]:text-(--input-solid-success-icon) group-data-[variant=outline]/input-group:[&>svg]:text-(--input-outline-default-icon) group-data-[variant=outline]/input-group:group-hover/input-group:[&>svg]:text-(--input-outline-hover-icon) group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control]:focus-visible]/input-group:[&>svg]:text-(--input-outline-focus-icon) group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)]/input-group:[&>svg]:text-(--input-outline-filled-icon) group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control][aria-invalid=true]]/input-group:[&>svg]:text-(--input-outline-fail-icon) group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]/input-group:[&>svg]:text-(--input-outline-success-icon) ",
|
|
54
|
+
{
|
|
55
|
+
variants: {
|
|
56
|
+
align: {
|
|
57
|
+
"inline-start": "order-first",
|
|
58
|
+
"inline-end": "order-last",
|
|
59
|
+
"block-start": "order-first w-full justify-start",
|
|
60
|
+
"block-end": "order-last w-full justify-start"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
defaultVariants: {
|
|
64
|
+
align: "inline-start"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
function CsInputGroupAddon({
|
|
69
|
+
className,
|
|
70
|
+
align = "inline-start",
|
|
71
|
+
...props
|
|
72
|
+
}) {
|
|
73
|
+
return /* @__PURE__ */ jsx(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
role: "group",
|
|
77
|
+
"data-slot": "input-group-addon",
|
|
78
|
+
"data-align": align,
|
|
79
|
+
className: cn(csInputGroupAddonVariants({ align }), className),
|
|
80
|
+
onClick: (e) => {
|
|
81
|
+
if (e.target.closest("button")) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
e.currentTarget.parentElement?.querySelector("input")?.focus();
|
|
85
|
+
},
|
|
86
|
+
...props
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
const csInputGroupButtonVariants = cva(
|
|
91
|
+
"[&_svg]:size-(--input-common-icon-size-sm) px-(--input-common-padding-x) py-(--input-common-padding-y) gap-(--input-common-gap)",
|
|
92
|
+
{
|
|
93
|
+
variants: {
|
|
94
|
+
size: {
|
|
95
|
+
default: "",
|
|
96
|
+
small: [
|
|
97
|
+
"h-(--scale-control-sm)"
|
|
98
|
+
].join(" ")
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
defaultVariants: {
|
|
102
|
+
size: "default"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
function CsInputGroupButton({
|
|
107
|
+
className,
|
|
108
|
+
type = "button",
|
|
109
|
+
variant = "ghost",
|
|
110
|
+
size = "default",
|
|
111
|
+
...props
|
|
112
|
+
}) {
|
|
113
|
+
return /* @__PURE__ */ jsx(
|
|
114
|
+
CsButton,
|
|
115
|
+
{
|
|
116
|
+
type,
|
|
117
|
+
"data-size": size,
|
|
118
|
+
variant,
|
|
119
|
+
className: cn(csInputGroupButtonVariants({ size }), className),
|
|
120
|
+
...props
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function CsInputGroupText({ className, ...props }) {
|
|
125
|
+
return /* @__PURE__ */ jsx(
|
|
126
|
+
"span",
|
|
127
|
+
{
|
|
128
|
+
className: cn(
|
|
129
|
+
"typo-productive-caption text-(--font-color-secondary-default)",
|
|
130
|
+
className
|
|
131
|
+
),
|
|
132
|
+
...props
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
function CsInputGroupInput({
|
|
137
|
+
className,
|
|
138
|
+
...props
|
|
139
|
+
}) {
|
|
140
|
+
return /* @__PURE__ */ jsx(
|
|
141
|
+
"input",
|
|
142
|
+
{
|
|
143
|
+
"data-slot": "input-group-control",
|
|
144
|
+
className: cn(
|
|
145
|
+
"w-full min-w-0 outline-none disabled:pointer-events-none disabled:cursor-not-allowed",
|
|
146
|
+
"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 p-0",
|
|
147
|
+
"typo-body-sm",
|
|
148
|
+
// solid variant font states
|
|
149
|
+
"group-data-[variant=solid]/input-group:text-(--input-solid-default-font) group-data-[variant=solid]/input-group:placeholder:text-(--input-solid-default-font)",
|
|
150
|
+
"group-hover/input-group:group-data-[variant=solid]/input-group:text-(--input-solid-hover-font)",
|
|
151
|
+
"group-data-[variant=solid]/input-group:focus-visible:text-(--input-solid-focus-font)",
|
|
152
|
+
"group-data-[variant=solid]/input-group:not(:placeholder-shown):text-(--input-solid-filled-font)",
|
|
153
|
+
"group-data-[variant=solid]/input-group:aria-invalid:text-(--input-solid-fail-font)",
|
|
154
|
+
"group-data-[variant=solid]/input-group:not(:placeholder-shown):aria-[invalid=false]:text-(--input-solid-success-font)",
|
|
155
|
+
// outline variant font states
|
|
156
|
+
"group-data-[variant=outline]/input-group:text-(--input-outline-default-font) group-data-[variant=outline]/input-group:placeholder:text-(--input-outline-default-font)",
|
|
157
|
+
"group-hover/input-group:group-data-[variant=outline]/input-group:text-(--input-outline-hover-font)",
|
|
158
|
+
"group-data-[variant=outline]/input-group:focus-visible:text-(--input-outline-focus-font)",
|
|
159
|
+
"group-data-[variant=outline]/input-group:not(:placeholder-shown):text-(--input-outline-filled-font)",
|
|
160
|
+
"group-data-[variant=outline]/input-group:aria-invalid:text-(--input-outline-fail-font)",
|
|
161
|
+
"group-data-[variant=outline]/input-group:not(:placeholder-shown):aria-[invalid=false]:text-(--input-outline-success-font)",
|
|
162
|
+
className
|
|
163
|
+
),
|
|
164
|
+
...props
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
function CsInputGroupTextarea({
|
|
169
|
+
className,
|
|
170
|
+
resizable = false,
|
|
171
|
+
...props
|
|
172
|
+
}) {
|
|
173
|
+
return /* @__PURE__ */ jsx(
|
|
174
|
+
"textarea",
|
|
175
|
+
{
|
|
176
|
+
"data-slot": "input-group-control textarea",
|
|
177
|
+
className: cn(
|
|
178
|
+
"w-full min-w-0 outline-none disabled:pointer-events-none disabled:cursor-not-allowed",
|
|
179
|
+
"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 p-0",
|
|
180
|
+
"typo-body-sm",
|
|
181
|
+
// solid variant font states
|
|
182
|
+
"group-data-[variant=solid]/input-group:text-(--input-solid-default-font) group-data-[variant=solid]/input-group:placeholder:text-(--input-solid-default-font)",
|
|
183
|
+
"group-hover/input-group:group-data-[variant=solid]/input-group:text-(--input-solid-hover-font)",
|
|
184
|
+
"group-data-[variant=solid]/input-group:focus-visible:text-(--input-solid-focus-font)",
|
|
185
|
+
"group-data-[variant=solid]/input-group:not(:placeholder-shown):text-(--input-solid-filled-font)",
|
|
186
|
+
// outline variant font states
|
|
187
|
+
"group-data-[variant=outline]/input-group:text-(--input-outline-default-font) group-data-[variant=outline]/input-group:placeholder:text-(--input-outline-default-font)",
|
|
188
|
+
"group-hover/input-group:group-data-[variant=outline]/input-group:text-(--input-outline-hover-font)",
|
|
189
|
+
"group-data-[variant=outline]/input-group:focus-visible:text-(--input-outline-focus-font)",
|
|
190
|
+
"group-data-[variant=outline]/input-group:not(:placeholder-shown):text-(--input-outline-filled-font)",
|
|
191
|
+
resizable ? "resize-y" : "resize-none",
|
|
192
|
+
className
|
|
193
|
+
),
|
|
194
|
+
...props
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
CsInputGroup,
|
|
200
|
+
CsInputGroupAddon,
|
|
201
|
+
CsInputGroupButton,
|
|
202
|
+
CsInputGroupInput,
|
|
203
|
+
CsInputGroupText,
|
|
204
|
+
CsInputGroupTextarea,
|
|
205
|
+
csInputGroupVariants
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=cs-input-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cs-input-group.js","sources":["../../../src/components/input/cs-input-group.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\nimport { CsButton } from \"../button\"\n\n/**\n * CsInputGroup 스타일 시스템 (Design Token Reference)\n *\n * ## Figma Token → Props 매핑\n * | Figma 토큰 패턴 | Props |\n * |----------------|-------|\n * | `input/solid/*` | `variant=\"solid\"` |\n * | `input/outline/*` | `variant=\"outline\"` |\n *\n * ## State 매핑 (복잡함 - CSS 선택자 기반)\n * | UI 상태 | Token state | CSS 선택자 |\n * |---------|-------------|-----------|\n * | 기본 | default | - |\n * | hover: | hover | :hover |\n * | focus-visible: | focus | :focus-visible |\n * | 값 입력됨 | filled | :not(:placeholder-shown) |\n * | 유효성 실패 | fail | [aria-invalid=true] |\n * | 유효성 성공 | success | :not(:placeholder-shown)[aria-invalid=false] |\n *\n * ## CSS Variables\n * ```css\n * --input-common-radius | padding-x | padding-y | gap | height | border-width | opacity\n * --input-common-icon-size-sm | icon-size-md | helpertext | group-gap | resizer\n * --input-{variant}-{state}-bg | border | font | icon\n * ```\n */\nconst csInputGroupVariants = cva(\n \"group/input-group relative flex w-full items-center transition-[color,box-shadow] outline-none min-w-0 \" +\n \"border-none ring-(length:--input-common-border-width) rounded-(--input-common-radius) px-(--input-common-padding-x) py-(--input-common-padding-y) gap-(--input-common-gap) \" + \n \"has-[>input:disabled]:opacity-(--input-common-opacity) has-[>textarea:disabled]:opacity-(--input-common-opacity)\" +\n \"has-[>textarea]:h-auto min-h-(--input-common-height) \" +\n \"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col \" +\n \"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col \" +\n \"has-[[data-slot~=input-group-control]:focus-visible]:border-none has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-solid-focus-border) has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-common-border-width) \",\n {\n variants: {\n variant: {\n solid: [\n \"bg-(--input-solid-default-bg) ring-transparent\",\n \"hover:bg-(--input-solid-hover-bg) hover:ring-(--input-solid-hover-border)\",\n \"has-[[data-slot~=input-group-control]:focus-visible]:bg-(--input-solid-focus-bg) has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-solid-focus-border)\",\n \"has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:bg-(--input-solid-filled-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:ring-(--input-solid-filled-border)\",\n \"has-[[data-slot~=input-group-control][aria-invalid=true]]:bg-(--input-solid-fail-bg) has-[[data-slot~=input-group-control][aria-invalid=true]]:ring-(--input-solid-fail-border)\",\n \"has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:bg-(--input-solid-success-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:ring-(--input-solid-success-border)\",\n ].join(\" \"),\n outline: [\n \"bg-(--input-outline-default-bg) ring-(length:--input-common-border-width) ring-(--input-outline-default-border)\",\n \"hover:bg-(--input-outline-hover-bg) hover:ring-(--input-outline-hover-border)\",\n \"has-[[data-slot~=input-group-control]:focus-visible]:bg-(--input-outline-focus-bg) has-[[data-slot~=input-group-control]:focus-visible]:ring-(--input-outline-focus-border)\",\n \"has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:bg-(--input-outline-filled-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)]:ring-(--input-outline-filled-border)\",\n \"has-[[data-slot~=input-group-control][aria-invalid=true]]:bg-(--input-outline-fail-bg) has-[[data-slot~=input-group-control][aria-invalid=true]]:ring-(--input-outline-fail-border)\",\n \"has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:bg-(--input-outline-success-bg) has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]:ring-(--input-outline-success-border)\",\n ].join(\" \"),\n },\n },\n defaultVariants: {\n variant: \"solid\",\n },\n }\n)\n\ntype CsInputGroupVariantsProps = VariantProps<typeof csInputGroupVariants>\n\n/**\n * CsInputGroup Props\n *\n * ## 아이콘/Addon 사용\n * CsInputGroupAddon으로 아이콘, 버튼, 텍스트를 배치.\n * SVG는 자동으로 `--input-common-icon-size-sm` 크기와 상태별 색상 적용.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input | MDN input}\n */\ntype CsInputGroupProps = React.ComponentProps<\"div\"> & CsInputGroupVariantsProps & {\n /**\n * 입력 필드 스타일\n * - `solid`: 채워진 배경 (기본) - 폼 내부, 일반 입력\n * - `outline`: 테두리 스타일 - 검색창, 강조가 필요한 입력\n * @default 'solid'\n */\n variant?: 'solid' | 'outline'\n\n /**\n * 비활성화 상태\n * 그룹 전체에 opacity 적용, 내부 input도 disabled 전달 필요\n * @default false\n */\n disabled?: boolean\n}\n\n/**\n * CS Design System Input 그룹 컨테이너\n *\n * 내부에 CsInputGroupInput/Textarea + CsInputGroupAddon 등을 조합하여 사용.\n * 상태(hover, focus, filled, fail, success)에 따라 전체 그룹 스타일이 자동 변경됨.\n *\n * @example 기본 조합\n * ```tsx\n * <CsInputGroup variant=\"solid\">\n * <CsInputGroupAddon><Search /></CsInputGroupAddon>\n * <CsInputGroupInput placeholder=\"검색...\" />\n * </CsInputGroup>\n * ```\n *\n * @example 유효성 검사\n * ```tsx\n * <CsInputGroup variant=\"outline\">\n * <CsInputGroupInput aria-invalid={hasError} />\n * </CsInputGroup>\n * ```\n *\n * @see CsInput - 단순 사용 시 래퍼 컴포넌트 권장\n */\nfunction CsInputGroup({\n className,\n variant = \"solid\",\n disabled,\n ...props\n}: CsInputGroupProps) {\n return (\n <div\n data-slot=\"input-group\"\n data-variant={variant}\n data-disabled={disabled ? \"true\" : undefined}\n role=\"group\"\n className={cn(csInputGroupVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\n/**\n * CsInputGroupAddon 스타일 (Addon 위치 제어)\n *\n * ## align 옵션\n * - `inline-start`: 입력 필드 왼쪽 (아이콘용)\n * - `inline-end`: 입력 필드 오른쪽 (버튼, 아이콘용)\n * - `block-start`: 입력 필드 위 (라벨용)\n * - `block-end`: 입력 필드 아래 (헬퍼텍스트용)\n *\n * ## 아이콘 자동 스타일링\n * - 크기: `--input-common-icon-size-sm` 적용\n * - 색상: 그룹의 variant/state에 따라 `--input-{variant}-{state}-icon` 자동 적용\n */\nconst csInputGroupAddonVariants = cva(\n \"flex cursor-text items-center justify-center gap-(--input-common-gap) select-none [&>kbd]:rounded-[calc(var(--input-common-radius)-5px)] group-data-[disabled=true]/input-group:opacity-(--input-common-opacity) \" +\n \"[&>svg:not([class*='size-'])]:size-(--input-common-icon-size-sm) \" +\n // solid variant icon states\n \"group-data-[variant=solid]/input-group:[&>svg]:text-(--input-solid-default-icon) \" +\n \"group-data-[variant=solid]/input-group:group-hover/input-group:[&>svg]:text-(--input-solid-hover-icon) \" +\n \"group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control]:focus-visible]/input-group:[&>svg]:text-(--input-solid-focus-icon) \" +\n \"group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)]/input-group:[&>svg]:text-(--input-solid-filled-icon) \" +\n \"group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control][aria-invalid=true]]/input-group:[&>svg]:text-(--input-solid-fail-icon) \" +\n \"group-data-[variant=solid]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]/input-group:[&>svg]:text-(--input-solid-success-icon) \" +\n // outline variant icon states\n \"group-data-[variant=outline]/input-group:[&>svg]:text-(--input-outline-default-icon) \" +\n \"group-data-[variant=outline]/input-group:group-hover/input-group:[&>svg]:text-(--input-outline-hover-icon) \" +\n \"group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control]:focus-visible]/input-group:[&>svg]:text-(--input-outline-focus-icon) \" +\n \"group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)]/input-group:[&>svg]:text-(--input-outline-filled-icon) \" +\n \"group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control][aria-invalid=true]]/input-group:[&>svg]:text-(--input-outline-fail-icon) \" +\n \"group-data-[variant=outline]/input-group:group-has-[[data-slot~=input-group-control]:not(:placeholder-shown)[aria-invalid=false]]/input-group:[&>svg]:text-(--input-outline-success-icon) \",\n {\n variants: {\n align: {\n \"inline-start\":\n \"order-first\",\n \"inline-end\":\n \"order-last\",\n \"block-start\":\n \"order-first w-full justify-start\",\n \"block-end\":\n \"order-last w-full justify-start\",\n },\n },\n defaultVariants: {\n align: \"inline-start\",\n },\n }\n)\n\n/**\n * CsInputGroupAddon Props\n */\ntype CsInputGroupAddonProps = React.ComponentProps<\"div\"> & {\n /**\n * Addon 배치 위치\n * - `inline-start`: 입력 필드 왼쪽 (검색 아이콘 등)\n * - `inline-end`: 입력 필드 오른쪽 (지우기 버튼, 단위 표시 등)\n * - `block-start`: 입력 필드 위 (인라인 라벨)\n * - `block-end`: 입력 필드 아래 (헬퍼텍스트)\n * @default 'inline-start'\n */\n align?: 'inline-start' | 'inline-end' | 'block-start' | 'block-end'\n}\n\n/**\n * Input 그룹 내 아이콘/텍스트 영역\n *\n * @example 아이콘 추가\n * ```tsx\n * <CsInputGroupAddon align=\"inline-start\"><Search /></CsInputGroupAddon>\n * <CsInputGroupAddon align=\"inline-end\"><X /></CsInputGroupAddon>\n * ```\n *\n * @example 라벨/헬퍼텍스트\n * ```tsx\n * <CsInputGroupAddon align=\"block-start\">\n * <CsInputGroupText>라벨</CsInputGroupText>\n * </CsInputGroupAddon>\n * ```\n */\nfunction CsInputGroupAddon({\n className,\n align = \"inline-start\",\n ...props\n}: CsInputGroupAddonProps) {\n return (\n <div\n role=\"group\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(csInputGroupAddonVariants({ align }), className)}\n onClick={(e) => {\n if ((e.target as HTMLElement).closest(\"button\")) {\n return\n }\n e.currentTarget.parentElement?.querySelector(\"input\")?.focus()\n }}\n {...props}\n />\n )\n}\n\n/** Input 그룹 내 버튼 스타일 (CsButton ghost variant 기반) */\nconst csInputGroupButtonVariants = cva(\n \"[&_svg]:size-(--input-common-icon-size-sm) px-(--input-common-padding-x) py-(--input-common-padding-y) gap-(--input-common-gap)\",\n {\n variants: {\n size: {\n default: \"\",\n small: [\n \"h-(--scale-control-sm)\",\n ].join(' '),\n }\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n)\n\n/**\n * Input 그룹 내 버튼 (검색, 지우기 등)\n *\n * @example\n * ```tsx\n * <CsInputGroupAddon align=\"inline-end\">\n * <CsInputGroupButton onClick={handleClear}><X /></CsInputGroupButton>\n * </CsInputGroupAddon>\n * ```\n */\nfunction CsInputGroupButton({\n className,\n type = \"button\",\n variant = \"ghost\",\n size = \"default\",\n ...props\n}: Omit<React.ComponentProps<typeof CsButton>, \"size\"> &\n VariantProps<typeof csInputGroupButtonVariants>) {\n return (\n <CsButton\n type={type}\n data-size={size}\n variant={variant}\n className={cn(csInputGroupButtonVariants({ size }), className)}\n {...props}\n />\n )\n}\n\n/** Input 그룹 내 텍스트 (라벨, 헬퍼텍스트 등) */\nfunction CsInputGroupText({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n className={cn(\n \"typo-productive-caption text-(--font-color-secondary-default)\",\n className\n )}\n {...props}\n />\n )\n}\n\n/**\n * Input 그룹 내 실제 input 요소\n *\n * 유효성 검사: `aria-invalid` 속성으로 fail/success 상태 제어\n * - `aria-invalid={true}`: fail 상태 (빨간색)\n * - `aria-invalid={false}` + 값 입력: success 상태 (초록색)\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input | MDN input}\n */\nfunction CsInputGroupInput({\n className,\n ...props\n}: React.ComponentProps<\"input\">) {\n return (\n <input\n data-slot=\"input-group-control\"\n className={cn(\n \"w-full min-w-0 outline-none disabled:pointer-events-none disabled:cursor-not-allowed\",\n \"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 p-0\",\n \"typo-body-sm\",\n // solid variant font states\n \"group-data-[variant=solid]/input-group:text-(--input-solid-default-font) group-data-[variant=solid]/input-group:placeholder:text-(--input-solid-default-font)\",\n \"group-hover/input-group:group-data-[variant=solid]/input-group:text-(--input-solid-hover-font)\",\n \"group-data-[variant=solid]/input-group:focus-visible:text-(--input-solid-focus-font)\",\n \"group-data-[variant=solid]/input-group:not(:placeholder-shown):text-(--input-solid-filled-font)\",\n \"group-data-[variant=solid]/input-group:aria-invalid:text-(--input-solid-fail-font)\",\n \"group-data-[variant=solid]/input-group:not(:placeholder-shown):aria-[invalid=false]:text-(--input-solid-success-font)\",\n // outline variant font states\n \"group-data-[variant=outline]/input-group:text-(--input-outline-default-font) group-data-[variant=outline]/input-group:placeholder:text-(--input-outline-default-font)\",\n \"group-hover/input-group:group-data-[variant=outline]/input-group:text-(--input-outline-hover-font)\",\n \"group-data-[variant=outline]/input-group:focus-visible:text-(--input-outline-focus-font)\",\n \"group-data-[variant=outline]/input-group:not(:placeholder-shown):text-(--input-outline-filled-font)\",\n \"group-data-[variant=outline]/input-group:aria-invalid:text-(--input-outline-fail-font)\",\n \"group-data-[variant=outline]/input-group:not(:placeholder-shown):aria-[invalid=false]:text-(--input-outline-success-font)\",\n className\n )}\n {...props}\n />\n )\n}\n\n/**\n * Input 그룹 내 실제 textarea 요소\n *\n * @param resizable - true면 세로 리사이즈 가능\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea | MDN textarea}\n */\nfunction CsInputGroupTextarea({\n className,\n resizable = false,\n ...props\n}: React.ComponentProps<\"textarea\"> & {\n /** 세로 리사이즈 가능 여부 @default false */\n resizable?: boolean\n}) {\n return (\n <textarea\n data-slot=\"input-group-control textarea\"\n className={cn(\n \"w-full min-w-0 outline-none disabled:pointer-events-none disabled:cursor-not-allowed\",\n \"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 p-0\",\n \"typo-body-sm\",\n // solid variant font states\n \"group-data-[variant=solid]/input-group:text-(--input-solid-default-font) group-data-[variant=solid]/input-group:placeholder:text-(--input-solid-default-font)\",\n \"group-hover/input-group:group-data-[variant=solid]/input-group:text-(--input-solid-hover-font)\",\n \"group-data-[variant=solid]/input-group:focus-visible:text-(--input-solid-focus-font)\",\n \"group-data-[variant=solid]/input-group:not(:placeholder-shown):text-(--input-solid-filled-font)\",\n // outline variant font states\n \"group-data-[variant=outline]/input-group:text-(--input-outline-default-font) group-data-[variant=outline]/input-group:placeholder:text-(--input-outline-default-font)\",\n \"group-hover/input-group:group-data-[variant=outline]/input-group:text-(--input-outline-hover-font)\",\n \"group-data-[variant=outline]/input-group:focus-visible:text-(--input-outline-focus-font)\",\n \"group-data-[variant=outline]/input-group:not(:placeholder-shown):text-(--input-outline-filled-font)\",\n resizable ? \"resize-y\" : \"resize-none\",\n className\n )}\n {...props}\n />\n )\n}\n\ntype CsInputGroupInputProps = React.ComponentProps<typeof CsInputGroupInput>\ntype CsInputGroupTextareaProps = React.ComponentProps<typeof CsInputGroupTextarea>\n\nexport {\n CsInputGroup,\n CsInputGroupAddon,\n CsInputGroupButton,\n CsInputGroupText,\n CsInputGroupInput,\n CsInputGroupTextarea,\n csInputGroupVariants,\n type CsInputGroupProps,\n type CsInputGroupAddonProps,\n type CsInputGroupVariantsProps\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { CsInputGroup, CsInputGroupInput, CsInputGroupTextarea } from "./cs-input-group.js";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
const CsInput = forwardRef(
|
|
5
|
+
({
|
|
6
|
+
variant,
|
|
7
|
+
className,
|
|
8
|
+
style,
|
|
9
|
+
children,
|
|
10
|
+
disabled,
|
|
11
|
+
...props
|
|
12
|
+
}, ref) => {
|
|
13
|
+
return /* @__PURE__ */ jsxs(CsInputGroup, { variant, className, style, disabled, children: [
|
|
14
|
+
/* @__PURE__ */ jsx(CsInputGroupInput, { ref, disabled, ...props }),
|
|
15
|
+
children
|
|
16
|
+
] });
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
CsInput.displayName = "CsInput";
|
|
20
|
+
const CsTextarea = forwardRef(
|
|
21
|
+
({
|
|
22
|
+
variant,
|
|
23
|
+
className,
|
|
24
|
+
style,
|
|
25
|
+
children,
|
|
26
|
+
disabled,
|
|
27
|
+
...props
|
|
28
|
+
}, ref) => {
|
|
29
|
+
return /* @__PURE__ */ jsxs(CsInputGroup, { variant, className, style, disabled, children: [
|
|
30
|
+
/* @__PURE__ */ jsx(CsInputGroupTextarea, { ref, disabled, ...props }),
|
|
31
|
+
children
|
|
32
|
+
] });
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
CsTextarea.displayName = "CsTextarea";
|
|
36
|
+
export {
|
|
37
|
+
CsInput,
|
|
38
|
+
CsTextarea
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=cs-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cs-input.js","sources":["../../../src/components/input/cs-input.tsx"],"sourcesContent":["import { CsInputGroup, CsInputGroupInput, CsInputGroupTextarea, CsInputGroupVariantsProps } from \"./cs-input-group\"\nimport { forwardRef, PropsWithChildren } from \"react\"\n\n/**\n * CsInput 스타일 시스템 (Design Token Reference)\n *\n * CsInputGroup의 래퍼 컴포넌트입니다.\n * 상세한 토큰 매핑은 CsInputGroup 문서를 참조하세요.\n *\n * ## Figma Token → Props 매핑\n * | Figma 토큰 패턴 | Props |\n * |----------------|-------|\n * | `input/solid/*` | `variant=\"solid\"` (기본) |\n * | `input/outline/*` | `variant=\"outline\"` |\n *\n * ## State 매핑\n * | UI 상태 | 적용 방법 |\n * |---------|----------|\n * | 유효성 실패 | `aria-invalid={true}` |\n * | 유효성 성공 | `aria-invalid={false}` + 값 입력 |\n *\n * @see CsInputGroup - 토큰 매핑 상세 정보\n */\n\n/**\n * CsInput Props\n *\n * HTML input 속성 + variant 스타일링.\n * children으로 CsInputGroupAddon 추가 가능.\n */\ntype CsInputProps = React.ComponentProps<typeof CsInputGroupInput> & CsInputGroupVariantsProps & {\n /**\n * 입력 필드 스타일\n * - `solid`: 채워진 배경 (기본) - 폼 내부, 일반 입력\n * - `outline`: 테두리 스타일 - 검색창, 강조가 필요한 입력\n * @default 'solid'\n */\n variant?: 'solid' | 'outline'\n}\n\n/**\n * CS Design System 입력 필드\n *\n * 사용자로부터 한 줄 텍스트 데이터를 입력받는 컴포넌트.\n * 이메일, 검색어, 이름, 전화번호 등 짧은 텍스트 입력에 사용됩니다.\n * CsInputGroup + CsInputGroupInput의 간편 래퍼입니다.\n *\n * ## 사용 시나리오\n * - 폼 입력 필드: `variant=\"solid\"` (기본) - 일반적인 폼 내부\n * - 검색 입력: `variant=\"outline\"` + 검색 아이콘 addon\n * - 이메일/전화번호: `type=\"email\"` 또는 `type=\"tel\"` 지정\n * - 숫자 입력: `type=\"number\"` 지정\n * - 비밀번호: `type=\"password\"` 지정\n * - 유효성 실패 표시: `aria-invalid={true}` 속성 사용\n *\n * ## 유사 컴포넌트와의 차이\n * - **CsTextarea**: 여러 줄 텍스트 입력 (긴 설명, 본문 등)\n * - **CsInputGroup**: 복잡한 조합 (여러 addon, 버튼 포함) 필요 시 직접 사용\n *\n * @example 기본\n * ```tsx\n * <CsInput placeholder=\"이메일\" />\n * <CsInput variant=\"outline\" placeholder=\"검색...\" />\n * ```\n *\n * @example 아이콘 추가\n * ```tsx\n * <CsInput placeholder=\"검색...\">\n * <CsInputGroupAddon align=\"inline-start\"><Search /></CsInputGroupAddon>\n * </CsInput>\n * ```\n *\n * @example 유효성 검사\n * ```tsx\n * <CsInput aria-invalid={hasError} placeholder=\"이메일\" />\n * ```\n *\n * @see CsInputGroup - 복잡한 조합이 필요할 때 직접 사용\n */\nconst CsInput = forwardRef<HTMLInputElement, PropsWithChildren<CsInputProps>>(\n ({ \n variant,\n className,\n style,\n children,\n disabled,\n ...props \n }, ref) => {\n return (\n <CsInputGroup variant={variant} className={className} style={style} disabled={disabled}>\n <CsInputGroupInput ref={ref} disabled={disabled} {...props} />\n {children}\n </CsInputGroup>\n )\n }\n)\nCsInput.displayName = \"CsInput\"\n\n/**\n * CsTextarea Props\n *\n * HTML textarea 속성 + variant 스타일링 + resizable 옵션.\n */\ntype CsTextareaProps = React.ComponentProps<typeof CsInputGroupTextarea> & CsInputGroupVariantsProps & {\n /**\n * 텍스트 영역 스타일\n * - `solid`: 채워진 배경 (기본)\n * - `outline`: 테두리 스타일\n * @default 'solid'\n */\n variant?: 'solid' | 'outline'\n}\n\n/**\n * CS Design System 텍스트 영역\n *\n * 사용자로부터 여러 줄의 긴 텍스트를 입력받는 컴포넌트.\n * 설명, 댓글, 본문 등 긴 내용 입력에 사용됩니다.\n * CsInputGroup + CsInputGroupTextarea의 간편 래퍼입니다.\n *\n * ## 사용 시나리오\n * - 긴 설명 입력: `variant=\"solid\"` (기본) - 상품 설명, 게시글 본문\n * - 댓글/리뷰: 여러 줄 입력 필드\n * - 사용자 메모: 자유 형식 텍스트 입력\n * - 크기 조절 가능: `resizable` prop으로 사용자가 높이 조절 가능\n * - 고정 크기: `resizable={false}` + `rows={5}` 등으로 높이 고정\n *\n * ## 유사 컴포넌트와의 차이\n * - **CsInput**: 한 줄 짧은 텍스트 입력 (이름, 이메일 등)\n *\n * @example 기본\n * ```tsx\n * <CsTextarea placeholder=\"내용을 입력하세요\" />\n * <CsTextarea variant=\"outline\" resizable />\n * ```\n *\n * @see CsInputGroup - 복잡한 조합이 필요할 때 직접 사용\n */\nconst CsTextarea = forwardRef<HTMLTextAreaElement, PropsWithChildren<CsTextareaProps>>(\n ({ \n variant,\n className,\n style,\n children,\n disabled,\n ...props \n }, ref) => {\n return (\n <CsInputGroup variant={variant} className={className} style={style} disabled={disabled}>\n <CsInputGroupTextarea ref={ref} disabled={disabled} {...props} />\n {children}\n </CsInputGroup>\n )\n }\n)\nCsTextarea.displayName = \"CsTextarea\"\n\nexport {\n CsInput,\n CsTextarea,\n type CsInputProps,\n type CsTextareaProps\n}\n"],"names":[],"mappings":";;;AA+EA,MAAM,UAAU;AAAA,EACd,CAAC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GACF,QAAQ;AACT,WACE,qBAAC,cAAA,EAAa,SAAkB,WAAsB,OAAc,UAClE,UAAA;AAAA,MAAA,oBAAC,mBAAA,EAAkB,KAAU,UAAqB,GAAG,MAAA,CAAO;AAAA,MAC3D;AAAA,IAAA,GACH;AAAA,EAEJ;AACF;AACA,QAAQ,cAAc;AA0CtB,MAAM,aAAa;AAAA,EACjB,CAAC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GACF,QAAQ;AACT,WACE,qBAAC,cAAA,EAAa,SAAkB,WAAsB,OAAc,UAClE,UAAA;AAAA,MAAA,oBAAC,sBAAA,EAAqB,KAAU,UAAqB,GAAG,MAAA,CAAO;AAAA,MAC9D;AAAA,IAAA,GACH;AAAA,EAEJ;AACF;AACA,WAAW,cAAc;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
function CsLabel({
|
|
6
|
+
className,
|
|
7
|
+
disabled,
|
|
8
|
+
...props
|
|
9
|
+
}) {
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
LabelPrimitive.Root,
|
|
12
|
+
{
|
|
13
|
+
"data-slot": "label",
|
|
14
|
+
"data-disabled": disabled,
|
|
15
|
+
className: cn(
|
|
16
|
+
"flex items-center gap-(--label-gap) typo-productive-label-md text-(--label-font-default) select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:text-(--label-font-disabled) peer-disabled:cursor-not-allowed peer-disabled:text-(--label-font-disabled) peer-data-[disabled=true]:pointer-events-none peer-data-[disabled=true]:text-(--label-font-disabled) has-[[data-slot=input-group][data-disabled=true]]:pointer-events-none has-[[data-slot=input-group][data-disabled=true]]:text-(--label-font-disabled)",
|
|
17
|
+
className
|
|
18
|
+
),
|
|
19
|
+
...props
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
CsLabel
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=cs-label.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cs-label.js","sources":["../../../src/components/label/cs-label.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\n\nimport { cn } from \"../../lib/utils\"\n\n/**\n * CsLabel 스타일 시스템 (Design Token Reference)\n *\n * ## Figma Token → Props 매핑\n * | Figma 토큰 패턴 | 상태 |\n * |----------------|------|\n * | `label/font-default` | 기본 상태 |\n * | `label/font-disabled` | `disabled={true}` |\n *\n * ## State 매핑\n * | UI 상태 | 조건 | 스타일 변화 |\n * |---------|------|------------|\n * | 기본 | - | label-font-default |\n * | 비활성 | disabled, peer-disabled | label-font-disabled, pointer-events-none |\n *\n * ## CSS Variables\n * ```css\n * --label-gap | font-default | font-disabled\n * ```\n *\n * @see {@link https://www.radix-ui.com/primitives/docs/components/label | Radix Label}\n */\n\n/**\n * CsLabel Props\n */\ntype CsLabelProps = React.ComponentProps<typeof LabelPrimitive.Root> & {\n /**\n * 비활성 상태\n * 연결된 입력 요소가 비활성일 때 자동 스타일 적용됨\n * (peer-disabled, group-data-[disabled])\n */\n disabled?: boolean\n /**\n * 연결할 입력 요소의 id\n * 클릭 시 해당 요소에 포커스\n */\n htmlFor?: string\n}\n\n/**\n * CS Design System 라벨 컴포넌트\n *\n * 폼 입력 요소(Input, Checkbox 등)의 라벨을 표시하는 컴포넌트. Radix UI 기반.\n * htmlFor로 명시적 연결하거나 감싸서 암묵적 연결이 가능하며,\n * 라벨 클릭 시 연결된 입력 요소에 자동으로 포커스됩니다.\n *\n * ## 사용 시나리오\n * - 텍스트 입력: `htmlFor=\"email\"` - Input과 명시적 연결\n * - 체크박스: 감싸기 방식 - Checkbox를 Label로 감싸서 클릭 영역 확대\n * - CsField와 조합: CsFieldLabel로 자동 연결 (권장)\n * - 비활성 상태: `disabled` prop으로 비활성 스타일 적용\n * - 폼 접근성: screen reader를 위한 명확한 라벨 제공\n *\n * ## 유사 컴포넌트와의 차이\n * - **CsField**: 폼 필드 래퍼 - 라벨 + 입력 + 에러 자동 관리\n * - Label은 라벨만, Field는 전체 폼 필드 구조 제공\n *\n * @example 기본\n * ```tsx\n * <CsLabel htmlFor=\"email\">이메일</CsLabel>\n * <CsInput id=\"email\" />\n * ```\n *\n * @example CsField와 함께\n * ```tsx\n * <CsField>\n * <CsFieldLabel>이름</CsFieldLabel>\n * <CsInput />\n * </CsField>\n * ```\n *\n * @example 감싸서 연결\n * ```tsx\n * <CsLabel>\n * <CsCheckbox />\n * 동의합니다\n * </CsLabel>\n * ```\n */\nfunction CsLabel({\n className,\n disabled,\n ...props\n}: CsLabelProps) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n data-disabled={disabled}\n className={cn(\n \"flex items-center gap-(--label-gap) typo-productive-label-md text-(--label-font-default) select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:text-(--label-font-disabled) peer-disabled:cursor-not-allowed peer-disabled:text-(--label-font-disabled) peer-data-[disabled=true]:pointer-events-none peer-data-[disabled=true]:text-(--label-font-disabled) has-[[data-slot=input-group][data-disabled=true]]:pointer-events-none has-[[data-slot=input-group][data-disabled=true]]:text-(--label-font-disabled)\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { CsLabel, type CsLabelProps }\n"],"names":[],"mappings":";;;;AAuFiB,SACf,QAAA;AAAA,EACA;AAAA,EACA;AAAA,EACF,GAAiB;AACf;AACE,SAAgB;AAAA,IAAf,eAAA;AAAA,IAAA;AAAA,MAEC,aAAA;AAAA,MACA,iBAAW;AAAA,MAAA,WACT;AAAA,QACA;AAAA,QACF;AAAA,MACC;AAAA,MAAG,GAAA;AAAA,IACN;AAAA,EAEJ;;"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
import { ChevronDownIcon } from "lucide-react";
|
|
7
|
+
import { cn } from "../../lib/utils.js";
|
|
8
|
+
const NavigationMenuVariantContext = React.createContext("solid-ghost");
|
|
9
|
+
function CsNavigationMenu({
|
|
10
|
+
className,
|
|
11
|
+
children,
|
|
12
|
+
viewport = true,
|
|
13
|
+
variant = "solid-ghost",
|
|
14
|
+
...props
|
|
15
|
+
}) {
|
|
16
|
+
return /* @__PURE__ */ jsx(NavigationMenuVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsxs(
|
|
17
|
+
NavigationMenuPrimitive.Root,
|
|
18
|
+
{
|
|
19
|
+
"data-slot": "navigation-menu",
|
|
20
|
+
"data-viewport": viewport,
|
|
21
|
+
"data-variant": variant,
|
|
22
|
+
className: cn(
|
|
23
|
+
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center gap-(--navigation-button-container-gap)",
|
|
24
|
+
className
|
|
25
|
+
),
|
|
26
|
+
...props,
|
|
27
|
+
children: [
|
|
28
|
+
children,
|
|
29
|
+
viewport && /* @__PURE__ */ jsx(CsNavigationMenuViewport, {})
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
) });
|
|
33
|
+
}
|
|
34
|
+
function CsNavigationMenuList({
|
|
35
|
+
className,
|
|
36
|
+
...props
|
|
37
|
+
}) {
|
|
38
|
+
return /* @__PURE__ */ jsx(
|
|
39
|
+
NavigationMenuPrimitive.List,
|
|
40
|
+
{
|
|
41
|
+
"data-slot": "navigation-menu-list",
|
|
42
|
+
className: cn(
|
|
43
|
+
"group flex flex-1 list-none items-center justify-center gap-(--navigation-button-container-gap)",
|
|
44
|
+
className
|
|
45
|
+
),
|
|
46
|
+
...props
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
function CsNavigationMenuItem({
|
|
51
|
+
className,
|
|
52
|
+
...props
|
|
53
|
+
}) {
|
|
54
|
+
return /* @__PURE__ */ jsx(
|
|
55
|
+
NavigationMenuPrimitive.Item,
|
|
56
|
+
{
|
|
57
|
+
"data-slot": "navigation-menu-item",
|
|
58
|
+
className: cn("relative", className),
|
|
59
|
+
...props
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const csNavigationMenuTriggerStyle = cva(
|
|
64
|
+
// disabled: <button>용 (:disabled pseudo), aria-disabled: <a>용 ([aria-disabled=true] attr)
|
|
65
|
+
"typo-body-sm group inline-flex w-max items-center justify-center px-(--navigation-button-common-padding-x) py-(--navigation-button-common-padding-y) gap-(--navigation-button-common-gap) outline-none transition-[color,background-color] disabled:pointer-events-none disabled:opacity-(--opacity-state-disabled) aria-disabled:pointer-events-none aria-disabled:opacity-(--opacity-state-disabled) [&_svg]:size-(--navigation-button-common-icon-size) [&_svg]:transition-colors",
|
|
66
|
+
{
|
|
67
|
+
variants: {
|
|
68
|
+
variant: {
|
|
69
|
+
"solid-ghost": "rounded-(--navigation-button-common-radius) text-(--navigation-button-solid-ghost-default-font) hover:bg-(--navigation-button-solid-ghost-active-bg) hover:text-(--navigation-button-solid-ghost-active-font) data-[state=open]:bg-(--navigation-button-solid-ghost-active-bg) data-[state=open]:text-(--navigation-button-solid-ghost-active-font) data-[active=true]:bg-(--navigation-button-solid-ghost-active-bg) data-[active=true]:text-(--navigation-button-solid-ghost-active-font) disabled:text-(--navigation-button-solid-ghost-disabled-font) aria-disabled:text-(--navigation-button-solid-ghost-disabled-font) [&_svg]:text-(--navigation-button-solid-ghost-default-icon) hover:[&_svg]:text-(--navigation-button-solid-ghost-active-icon) data-[state=open]:[&_svg]:text-(--navigation-button-solid-ghost-active-icon) data-[active=true]:[&_svg]:text-(--navigation-button-solid-ghost-active-icon) disabled:[&_svg]:text-(--navigation-button-solid-ghost-disabled-icon) aria-disabled:[&_svg]:text-(--navigation-button-solid-ghost-disabled-icon)",
|
|
70
|
+
"bottom-border": "text-(--navigation-button-bottom-border-default-font) hover:text-(--navigation-button-bottom-border-hover-font) data-[state=open]:text-(--navigation-button-bottom-border-active-font) data-[active=true]:text-(--navigation-button-bottom-border-active-font) disabled:text-(--navigation-button-bottom-border-disabled-font) aria-disabled:text-(--navigation-button-bottom-border-disabled-font) [&_svg]:text-(--navigation-button-bottom-border-default-icon) hover:[&_svg]:text-(--navigation-button-bottom-border-hover-icon) data-[state=open]:[&_svg]:text-(--navigation-button-bottom-border-active-icon) data-[active=true]:[&_svg]:text-(--navigation-button-bottom-border-active-icon) disabled:[&_svg]:text-(--navigation-button-bottom-border-disabled-icon) aria-disabled:[&_svg]:text-(--navigation-button-bottom-border-disabled-icon) border-b-transparent border-b-(length:--navigation-button-bottom-border-active-border-width) hover:border-b-(--navigation-button-bottom-border-active-border) data-[state=open]:border-b-(--navigation-button-bottom-border-active-border) data-[active=true]:border-b-(--navigation-button-bottom-border-active-border)",
|
|
71
|
+
"gradient": "rounded-(--navigation-button-common-radius) text-(--navigation-button-gradient-default-font) hover:gradient-primary-vertical data-[state=open]:gradient-primary-vertical data-[state=open]:text-(--navigation-button-gradient-active-font) data-[active=true]:gradient-primary-vertical data-[active=true]:text-(--navigation-button-gradient-active-font) disabled:text-(--navigation-button-gradient-disabled-font) aria-disabled:text-(--navigation-button-gradient-disabled-font) [&_svg]:text-(--navigation-button-gradient-default-icon) hover:[&_svg]:text-(--navigation-button-gradient-active-icon) data-[state=open]:[&_svg]:text-(--navigation-button-gradient-active-icon) data-[active=true]:[&_svg]:text-(--navigation-button-gradient-active-icon) disabled:[&_svg]:text-(--navigation-button-gradient-disabled-icon) aria-disabled:[&_svg]:text-(--navigation-button-gradient-disabled-icon)"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
defaultVariants: {
|
|
75
|
+
variant: "solid-ghost"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
function CsNavigationMenuTrigger({
|
|
80
|
+
className,
|
|
81
|
+
children,
|
|
82
|
+
...props
|
|
83
|
+
}) {
|
|
84
|
+
const variant = React.useContext(NavigationMenuVariantContext);
|
|
85
|
+
return /* @__PURE__ */ jsxs(
|
|
86
|
+
NavigationMenuPrimitive.Trigger,
|
|
87
|
+
{
|
|
88
|
+
"data-slot": "navigation-menu-trigger",
|
|
89
|
+
className: cn(
|
|
90
|
+
csNavigationMenuTriggerStyle({ variant }),
|
|
91
|
+
"group flex items-center gap-(--navigation-button-common-gap)",
|
|
92
|
+
className
|
|
93
|
+
),
|
|
94
|
+
...props,
|
|
95
|
+
children: [
|
|
96
|
+
children,
|
|
97
|
+
/* @__PURE__ */ jsx(
|
|
98
|
+
ChevronDownIcon,
|
|
99
|
+
{
|
|
100
|
+
className: "relative size-(--navigation-button-common-icon-size) transition duration-300 group-data-[state=open]:rotate-180",
|
|
101
|
+
"aria-hidden": "true"
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const NavigationMenuInContentContext = React.createContext(false);
|
|
109
|
+
function CsNavigationMenuContent({
|
|
110
|
+
className,
|
|
111
|
+
...props
|
|
112
|
+
}) {
|
|
113
|
+
return /* @__PURE__ */ jsx(NavigationMenuInContentContext.Provider, { value: true, children: /* @__PURE__ */ jsx(
|
|
114
|
+
NavigationMenuPrimitive.Content,
|
|
115
|
+
{
|
|
116
|
+
"data-slot": "navigation-menu-content",
|
|
117
|
+
className: cn(
|
|
118
|
+
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 bg-(--navigation-item-container-bg) text-(--font-color-primary-default) rounded-(--navigation-item-container-radius) border-(--navigation-item-container-border) border-(length:--navigation-item-container-border-width) px-(--navigation-item-container-padding-x) py-(--navigation-item-container-padding-y) gap-(--navigation-item-container-gap) absolute w-full",
|
|
119
|
+
"group-data-[viewport=false]/navigation-menu:z-[100] group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:outline-none",
|
|
120
|
+
"boxshadow-lg flex flex-col",
|
|
121
|
+
className
|
|
122
|
+
),
|
|
123
|
+
...props
|
|
124
|
+
}
|
|
125
|
+
) });
|
|
126
|
+
}
|
|
127
|
+
function CsNavigationMenuViewport({
|
|
128
|
+
className,
|
|
129
|
+
...props
|
|
130
|
+
}) {
|
|
131
|
+
return /* @__PURE__ */ jsx(NavigationMenuInContentContext.Provider, { value: true, children: /* @__PURE__ */ jsx(
|
|
132
|
+
"div",
|
|
133
|
+
{
|
|
134
|
+
className: cn(
|
|
135
|
+
"absolute top-full left-0 isolate z-[100] flex justify-center w-full"
|
|
136
|
+
),
|
|
137
|
+
children: /* @__PURE__ */ jsx(
|
|
138
|
+
NavigationMenuPrimitive.Viewport,
|
|
139
|
+
{
|
|
140
|
+
"data-slot": "navigation-menu-viewport",
|
|
141
|
+
className: cn(
|
|
142
|
+
"origin-top-center data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-(--navigation-item-container-radius)",
|
|
143
|
+
"boxshadow-lg",
|
|
144
|
+
className
|
|
145
|
+
),
|
|
146
|
+
...props
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
) });
|
|
151
|
+
}
|
|
152
|
+
const csNavigationMenuLinkVariants = cva(
|
|
153
|
+
"typo-body-sm flex transition-all outline-none whitespace-nowrap [&_svg]:transition-colors",
|
|
154
|
+
{
|
|
155
|
+
variants: {
|
|
156
|
+
variant: {
|
|
157
|
+
item: "items-center gap-(--navigation-item-common-gap) rounded-(--navigation-item-common-radius) px-(--navigation-item-common-padding-x) py-(--navigation-item-common-padding-y) data-[active=true]:bg-(--navigation-item-hover-bg) data-[active=true]:text-(--navigation-item-hover-font) hover:bg-(--navigation-item-hover-bg) hover:text-(--navigation-item-hover-font) focus:bg-(--navigation-item-hover-bg) focus:text-(--navigation-item-hover-font) text-(--navigation-item-default-font) [&_svg:not([class*='text-'])]:text-(--navigation-item-default-icon) [&_svg:not([class*='size-'])]:size-(--navigation-item-common-icon-size) hover:[&_svg:not([class*='text-'])]:text-(--navigation-item-hover-icon) data-[active=true]:[&_svg:not([class*='text-'])]:text-(--navigation-item-hover-icon)",
|
|
158
|
+
"item-content": "flex-col gap-(--navigation-item-content-common-gap) rounded-(--navigation-item-content-common-radius) px-(--navigation-item-content-common-padding-x) py-(--navigation-item-content-common-padding-y) data-[active=true]:bg-(--navigation-item-content-hover-bg) data-[active=true]:text-(--navigation-item-content-hover-title) hover:bg-(--navigation-item-content-hover-bg) hover:text-(--navigation-item-content-hover-title) focus:bg-(--navigation-item-content-hover-bg) focus:text-(--navigation-item-content-hover-title) text-(--navigation-item-content-default-title) [&_svg:not([class*='text-'])]:text-(--navigation-item-content-default-icon) [&_svg:not([class*='size-'])]:size-(--navigation-item-content-common-icon-size) data-[active=true]:[&_svg]:text-(--navigation-item-content-hover-icon) hover:[&_svg]:text-(--navigation-item-content-hover-icon)"
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
defaultVariants: {
|
|
162
|
+
variant: "item"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
function CsNavigationMenuLink({
|
|
167
|
+
className,
|
|
168
|
+
variant = "item",
|
|
169
|
+
...props
|
|
170
|
+
}) {
|
|
171
|
+
const contextVariant = React.useContext(NavigationMenuVariantContext);
|
|
172
|
+
const isInsideContent = React.useContext(NavigationMenuInContentContext);
|
|
173
|
+
return /* @__PURE__ */ jsx(
|
|
174
|
+
NavigationMenuPrimitive.Link,
|
|
175
|
+
{
|
|
176
|
+
"data-slot": "navigation-menu-link",
|
|
177
|
+
className: cn(
|
|
178
|
+
isInsideContent ? [csNavigationMenuLinkVariants({ variant }), "w-full"] : csNavigationMenuTriggerStyle({ variant: contextVariant }),
|
|
179
|
+
className
|
|
180
|
+
),
|
|
181
|
+
...props
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
function CsNavigationMenuIndicator({
|
|
186
|
+
className,
|
|
187
|
+
...props
|
|
188
|
+
}) {
|
|
189
|
+
return /* @__PURE__ */ jsx(
|
|
190
|
+
NavigationMenuPrimitive.Indicator,
|
|
191
|
+
{
|
|
192
|
+
"data-slot": "navigation-menu-indicator",
|
|
193
|
+
className: cn(
|
|
194
|
+
"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
|
|
195
|
+
className
|
|
196
|
+
),
|
|
197
|
+
...props,
|
|
198
|
+
children: /* @__PURE__ */ jsx("div", { className: "bg-(--navigation-item-container-border) relative top-[60%] h-2 w-2 rotate-45 rounded-(--radius-small)" })
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
export {
|
|
203
|
+
CsNavigationMenu,
|
|
204
|
+
CsNavigationMenuContent,
|
|
205
|
+
CsNavigationMenuIndicator,
|
|
206
|
+
CsNavigationMenuItem,
|
|
207
|
+
CsNavigationMenuLink,
|
|
208
|
+
CsNavigationMenuList,
|
|
209
|
+
CsNavigationMenuTrigger,
|
|
210
|
+
CsNavigationMenuViewport,
|
|
211
|
+
csNavigationMenuLinkVariants,
|
|
212
|
+
csNavigationMenuTriggerStyle
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=cs-navigation-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cs-navigation-menu.js","sources":["../../../src/components/navigation-menu/cs-navigation-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as React from \"react\"\nimport * as NavigationMenuPrimitive from \"@radix-ui/react-navigation-menu\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { ChevronDownIcon } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nconst NavigationMenuVariantContext = React.createContext<\"solid-ghost\" | \"bottom-border\" | \"gradient\">(\"solid-ghost\")\n\n/**\n * CsNavigationMenu 스타일 시스템 (Design Token Reference)\n *\n * ## Figma Token → Props 매핑\n * | Figma 토큰 패턴 | Props |\n * |----------------|-------|\n * | `navigation-button/solid-ghost/*` | `variant=\"solid-ghost\"` (기본) |\n * | `navigation-button/bottom-border/*` | `variant=\"bottom-border\"` |\n * | `navigation-button/gradient/*` | `variant=\"gradient\"` |\n * | `navigation-item/*` | 드롭다운 콘텐츠 |\n *\n * ## State 매핑\n * | UI 상태 | 적용 방법 | 스타일 변화 |\n * |---------|----------|------------|\n * | 기본 | - | default-font, default-icon |\n * | 열림 | `data-state=\"open\"` (Radix 자동) | active-* |\n * | hover | - | hover-* |\n * | 활성 (현재 라우트) | `data-active=\"true\"` | active-* |\n * | 비활성 (Trigger) | `disabled` | disabled-*, opacity 감소 |\n * | 비활성 (Link) | `aria-disabled=\"true\"` | disabled-*, opacity 감소 |\n *\n * ## CSS Variables\n * ```css\n * --navigation-button-container-gap | common-padding-x | common-padding-y | common-gap | common-radius | common-icon-size\n * --navigation-button-{variant}-{state}-font | icon | bg | border\n * --navigation-item-container-* | common-* | default-* | hover-*\n * ```\n *\n * ## 서브 컴포넌트 구조\n * ```\n * CsNavigationMenu (Root)\n * ├── CsNavigationMenuList\n * │ └── CsNavigationMenuItem\n * │ ├── CsNavigationMenuTrigger (드롭다운)\n * │ ├── CsNavigationMenuContent\n * │ │ └── CsNavigationMenuLink\n * │ └── CsNavigationMenuLink (단일 링크)\n * └── CsNavigationMenuViewport\n * ```\n *\n * @see {@link https://www.radix-ui.com/primitives/docs/components/navigation-menu | Radix NavigationMenu}\n */\n\n/**\n * CsNavigationMenu Props\n */\ntype CsNavigationMenuProps = React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {\n /**\n * Viewport 사용 여부\n * false면 콘텐츠가 트리거 직접 하위에 렌더링\n * @default true\n */\n viewport?: boolean\n /**\n * 네비게이션 버튼 스타일\n * - `solid-ghost`: 호버 시 배경 (기본)\n * - `bottom-border`: 하단 보더 강조\n * - `gradient`: 그라데이션 호버\n * @default 'solid-ghost'\n */\n variant?: \"solid-ghost\" | \"bottom-border\" | \"gradient\"\n}\n\n/**\n * CS Design System 네비게이션 메뉴 컴포넌트\n *\n * 애플리케이션의 주요 페이지와 섹션 간 이동을 제공하는 전역 네비게이션 메뉴.\n * 헤더, 상단 메뉴바 등에 사용되며, 드롭다운 서브 메뉴를 지원합니다.\n * variant로 스타일 변경이 가능합니다.\n *\n * ## 사용 시나리오\n * - 헤더 메뉴: 주요 페이지 링크 (홈, 제품, 가격, 문의)\n * - 상단 네비게이션 바: 드롭다운 서브 메뉴 포함\n * - 섹션 전환: 앱 내 주요 영역 이동\n *\n * ## 유사 컴포넌트와의 차이\n * - **CsTabs**: 페이지 내 섹션 전환 (같은 페이지 내부)\n * - NavigationMenu는 페이지 간 이동, Tabs는 페이지 내 섹션 전환\n *\n * @example 기본 조합\n * ```tsx\n * <CsNavigationMenu>\n * <CsNavigationMenuList>\n * <CsNavigationMenuItem>\n * <CsNavigationMenuTrigger>메뉴</CsNavigationMenuTrigger>\n * <CsNavigationMenuContent>\n * <CsNavigationMenuLink href=\"/page1\">페이지 1</CsNavigationMenuLink>\n * <CsNavigationMenuLink href=\"/page2\">페이지 2</CsNavigationMenuLink>\n * </CsNavigationMenuContent>\n * </CsNavigationMenuItem>\n * </CsNavigationMenuList>\n * </CsNavigationMenu>\n * ```\n *\n * @example variant 변경\n * ```tsx\n * <CsNavigationMenu variant=\"bottom-border\">...</CsNavigationMenu>\n * <CsNavigationMenu variant=\"gradient\">...</CsNavigationMenu>\n * ```\n *\n * @example Active 상태 (현재 라우트 표시)\n * ```tsx\n * // Trigger, Link 모두 data-active=\"true\" 사용\n * <CsNavigationMenuTrigger data-active=\"true\">현재 메뉴</CsNavigationMenuTrigger>\n * <CsNavigationMenuLink href=\"/current\" data-active=\"true\">현재 페이지</CsNavigationMenuLink>\n *\n * // 드롭다운 아이템에도 동일하게 적용\n * <CsNavigationMenuContent>\n * <CsNavigationMenuLink href=\"/sub\" data-active=\"true\">활성 아이템</CsNavigationMenuLink>\n * </CsNavigationMenuContent>\n * ```\n *\n * @example Disabled 상태\n * ```tsx\n * // Trigger (button) → disabled prop 사용\n * <CsNavigationMenuTrigger disabled>비활성 메뉴</CsNavigationMenuTrigger>\n *\n * // Link (anchor) → aria-disabled 사용 (<a>는 :disabled 미지원)\n * <CsNavigationMenuLink href=\"/page\" aria-disabled=\"true\">비활성 링크</CsNavigationMenuLink>\n * ```\n */\nfunction CsNavigationMenu({\n className,\n children,\n viewport = true,\n variant = \"solid-ghost\",\n ...props\n}: CsNavigationMenuProps) {\n return (\n <NavigationMenuVariantContext.Provider value={variant}>\n <NavigationMenuPrimitive.Root\n data-slot=\"navigation-menu\"\n data-viewport={viewport}\n data-variant={variant}\n className={cn(\n \"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center gap-(--navigation-button-container-gap)\",\n className\n )}\n {...props}\n >\n {children}\n {viewport && <CsNavigationMenuViewport />}\n </NavigationMenuPrimitive.Root>\n </NavigationMenuVariantContext.Provider>\n )\n}\n\n/** 네비게이션 메뉴 리스트 컨테이너 */\nfunction CsNavigationMenuList({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {\n return (\n <NavigationMenuPrimitive.List\n data-slot=\"navigation-menu-list\"\n className={cn(\n \"group flex flex-1 list-none items-center justify-center gap-(--navigation-button-container-gap)\",\n className\n )}\n {...props}\n />\n )\n}\n\n/** 네비게이션 메뉴 개별 항목 */\nfunction CsNavigationMenuItem({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {\n return (\n <NavigationMenuPrimitive.Item\n data-slot=\"navigation-menu-item\"\n className={cn(\"relative\", className)}\n {...props}\n />\n )\n}\n\nconst csNavigationMenuTriggerStyle = cva(\n // disabled: <button>용 (:disabled pseudo), aria-disabled: <a>용 ([aria-disabled=true] attr)\n \"typo-body-sm group inline-flex w-max items-center justify-center px-(--navigation-button-common-padding-x) py-(--navigation-button-common-padding-y) gap-(--navigation-button-common-gap) outline-none transition-[color,background-color] disabled:pointer-events-none disabled:opacity-(--opacity-state-disabled) aria-disabled:pointer-events-none aria-disabled:opacity-(--opacity-state-disabled) [&_svg]:size-(--navigation-button-common-icon-size) [&_svg]:transition-colors\",\n {\n variants: {\n variant: {\n \"solid-ghost\": \"rounded-(--navigation-button-common-radius) text-(--navigation-button-solid-ghost-default-font) hover:bg-(--navigation-button-solid-ghost-active-bg) hover:text-(--navigation-button-solid-ghost-active-font) data-[state=open]:bg-(--navigation-button-solid-ghost-active-bg) data-[state=open]:text-(--navigation-button-solid-ghost-active-font) data-[active=true]:bg-(--navigation-button-solid-ghost-active-bg) data-[active=true]:text-(--navigation-button-solid-ghost-active-font) disabled:text-(--navigation-button-solid-ghost-disabled-font) aria-disabled:text-(--navigation-button-solid-ghost-disabled-font) [&_svg]:text-(--navigation-button-solid-ghost-default-icon) hover:[&_svg]:text-(--navigation-button-solid-ghost-active-icon) data-[state=open]:[&_svg]:text-(--navigation-button-solid-ghost-active-icon) data-[active=true]:[&_svg]:text-(--navigation-button-solid-ghost-active-icon) disabled:[&_svg]:text-(--navigation-button-solid-ghost-disabled-icon) aria-disabled:[&_svg]:text-(--navigation-button-solid-ghost-disabled-icon)\",\n \"bottom-border\": \"text-(--navigation-button-bottom-border-default-font) hover:text-(--navigation-button-bottom-border-hover-font) data-[state=open]:text-(--navigation-button-bottom-border-active-font) data-[active=true]:text-(--navigation-button-bottom-border-active-font) disabled:text-(--navigation-button-bottom-border-disabled-font) aria-disabled:text-(--navigation-button-bottom-border-disabled-font) [&_svg]:text-(--navigation-button-bottom-border-default-icon) hover:[&_svg]:text-(--navigation-button-bottom-border-hover-icon) data-[state=open]:[&_svg]:text-(--navigation-button-bottom-border-active-icon) data-[active=true]:[&_svg]:text-(--navigation-button-bottom-border-active-icon) disabled:[&_svg]:text-(--navigation-button-bottom-border-disabled-icon) aria-disabled:[&_svg]:text-(--navigation-button-bottom-border-disabled-icon) border-b-transparent border-b-(length:--navigation-button-bottom-border-active-border-width) hover:border-b-(--navigation-button-bottom-border-active-border) data-[state=open]:border-b-(--navigation-button-bottom-border-active-border) data-[active=true]:border-b-(--navigation-button-bottom-border-active-border)\",\n \"gradient\": \"rounded-(--navigation-button-common-radius) text-(--navigation-button-gradient-default-font) hover:gradient-primary-vertical data-[state=open]:gradient-primary-vertical data-[state=open]:text-(--navigation-button-gradient-active-font) data-[active=true]:gradient-primary-vertical data-[active=true]:text-(--navigation-button-gradient-active-font) disabled:text-(--navigation-button-gradient-disabled-font) aria-disabled:text-(--navigation-button-gradient-disabled-font) [&_svg]:text-(--navigation-button-gradient-default-icon) hover:[&_svg]:text-(--navigation-button-gradient-active-icon) data-[state=open]:[&_svg]:text-(--navigation-button-gradient-active-icon) data-[active=true]:[&_svg]:text-(--navigation-button-gradient-active-icon) disabled:[&_svg]:text-(--navigation-button-gradient-disabled-icon) aria-disabled:[&_svg]:text-(--navigation-button-gradient-disabled-icon)\",\n }\n },\n defaultVariants: {\n variant: \"solid-ghost\",\n }\n }\n)\n\n/** 네비게이션 드롭다운 트리거 - ChevronDown 자동 포함 */\nfunction CsNavigationMenuTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {\n const variant = React.useContext(NavigationMenuVariantContext)\n \n return (\n <NavigationMenuPrimitive.Trigger\n data-slot=\"navigation-menu-trigger\"\n className={cn(\n csNavigationMenuTriggerStyle({ variant }),\n \"group flex items-center gap-(--navigation-button-common-gap)\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDownIcon\n className=\"relative size-(--navigation-button-common-icon-size) transition duration-300 group-data-[state=open]:rotate-180\"\n aria-hidden=\"true\"\n />\n </NavigationMenuPrimitive.Trigger>\n )\n}\n\nconst NavigationMenuInContentContext = React.createContext<boolean>(false)\n\n/** 네비게이션 드롭다운 콘텐츠 영역 */\nfunction CsNavigationMenuContent({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {\n return (\n <NavigationMenuInContentContext.Provider value={true}>\n <NavigationMenuPrimitive.Content\n data-slot=\"navigation-menu-content\"\n className={cn(\n \"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 bg-(--navigation-item-container-bg) text-(--font-color-primary-default) rounded-(--navigation-item-container-radius) border-(--navigation-item-container-border) border-(length:--navigation-item-container-border-width) px-(--navigation-item-container-padding-x) py-(--navigation-item-container-padding-y) gap-(--navigation-item-container-gap) absolute w-full\",\n \"group-data-[viewport=false]/navigation-menu:z-[100] group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:outline-none\",\n \"boxshadow-lg flex flex-col\",\n className\n )}\n {...props}\n />\n </NavigationMenuInContentContext.Provider>\n )\n}\n\n/** 네비게이션 뷰포트 - 콘텐츠 렌더링 영역 */\nfunction CsNavigationMenuViewport({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {\n return (\n <NavigationMenuInContentContext.Provider value={true}>\n <div\n className={cn(\n \"absolute top-full left-0 isolate z-[100] flex justify-center w-full\"\n )}\n >\n <NavigationMenuPrimitive.Viewport\n data-slot=\"navigation-menu-viewport\"\n className={cn(\n \"origin-top-center data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-(--navigation-item-container-radius)\",\n \"boxshadow-lg\",\n className\n )}\n {...props}\n />\n </div>\n </NavigationMenuInContentContext.Provider>\n )\n}\n\nconst csNavigationMenuLinkVariants = cva(\n \"typo-body-sm flex transition-all outline-none whitespace-nowrap [&_svg]:transition-colors\",\n {\n variants: {\n variant: {\n item: \"items-center gap-(--navigation-item-common-gap) rounded-(--navigation-item-common-radius) px-(--navigation-item-common-padding-x) py-(--navigation-item-common-padding-y) data-[active=true]:bg-(--navigation-item-hover-bg) data-[active=true]:text-(--navigation-item-hover-font) hover:bg-(--navigation-item-hover-bg) hover:text-(--navigation-item-hover-font) focus:bg-(--navigation-item-hover-bg) focus:text-(--navigation-item-hover-font) text-(--navigation-item-default-font) [&_svg:not([class*='text-'])]:text-(--navigation-item-default-icon) [&_svg:not([class*='size-'])]:size-(--navigation-item-common-icon-size) hover:[&_svg:not([class*='text-'])]:text-(--navigation-item-hover-icon) data-[active=true]:[&_svg:not([class*='text-'])]:text-(--navigation-item-hover-icon)\",\n \"item-content\": \"flex-col gap-(--navigation-item-content-common-gap) rounded-(--navigation-item-content-common-radius) px-(--navigation-item-content-common-padding-x) py-(--navigation-item-content-common-padding-y) data-[active=true]:bg-(--navigation-item-content-hover-bg) data-[active=true]:text-(--navigation-item-content-hover-title) hover:bg-(--navigation-item-content-hover-bg) hover:text-(--navigation-item-content-hover-title) focus:bg-(--navigation-item-content-hover-bg) focus:text-(--navigation-item-content-hover-title) text-(--navigation-item-content-default-title) [&_svg:not([class*='text-'])]:text-(--navigation-item-content-default-icon) [&_svg:not([class*='size-'])]:size-(--navigation-item-content-common-icon-size) data-[active=true]:[&_svg]:text-(--navigation-item-content-hover-icon) hover:[&_svg]:text-(--navigation-item-content-hover-icon)\",\n }\n },\n defaultVariants: {\n variant: \"item\",\n }\n }\n)\n\n/**\n * CsNavigationMenuLink Props\n */\ntype CsNavigationMenuLinkProps = React.ComponentProps<typeof NavigationMenuPrimitive.Link> &\n VariantProps<typeof csNavigationMenuLinkVariants> & {\n /**\n * 링크 스타일\n * - `item`: 기본 메뉴 항목\n * - `item-content`: 제목+설명 포함 카드형\n * @default 'item'\n */\n variant?: 'item' | 'item-content'\n}\n\n/** 네비게이션 링크 - 단일 또는 콘텐츠 내부 */\nfunction CsNavigationMenuLink({\n className,\n variant = \"item\",\n ...props\n}: CsNavigationMenuLinkProps) {\n const contextVariant = React.useContext(NavigationMenuVariantContext)\n const isInsideContent = React.useContext(NavigationMenuInContentContext)\n\n return (\n <NavigationMenuPrimitive.Link\n data-slot=\"navigation-menu-link\"\n className={cn(\n isInsideContent\n ? [csNavigationMenuLinkVariants({ variant }), \"w-full\"]\n : csNavigationMenuTriggerStyle({ variant: contextVariant }),\n className\n )}\n {...props}\n />\n )\n}\n\n/** 네비게이션 인디케이터 */\nfunction CsNavigationMenuIndicator({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {\n return (\n <NavigationMenuPrimitive.Indicator\n data-slot=\"navigation-menu-indicator\"\n className={cn(\n \"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden\",\n className\n )}\n {...props}\n >\n <div className=\"bg-(--navigation-item-container-border) relative top-[60%] h-2 w-2 rotate-45 rounded-(--radius-small)\" />\n </NavigationMenuPrimitive.Indicator>\n )\n}\n\nexport {\n CsNavigationMenu,\n CsNavigationMenuList,\n CsNavigationMenuItem,\n CsNavigationMenuContent,\n CsNavigationMenuTrigger,\n CsNavigationMenuLink,\n CsNavigationMenuIndicator,\n CsNavigationMenuViewport,\n csNavigationMenuTriggerStyle,\n csNavigationMenuLinkVariants,\n type CsNavigationMenuProps,\n type CsNavigationMenuLinkProps,\n}\n"],"names":[],"mappings":"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"}
|