sh-ui-cli 0.45.2 → 0.45.3
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/data/changelog/versions.json +13 -0
- package/data/registry/react/components/accordion/index.tailwind.tsx +5 -7
- package/data/registry/react/components/accordion/index.tsx +5 -7
- package/data/registry/react/components/avatar/index.tailwind.tsx +4 -6
- package/data/registry/react/components/avatar/index.tsx +4 -6
- package/data/registry/react/components/badge/index.tailwind.tsx +2 -4
- package/data/registry/react/components/badge/index.tsx +2 -4
- package/data/registry/react/components/breadcrumb/index.tailwind.tsx +8 -10
- package/data/registry/react/components/breadcrumb/index.tsx +8 -10
- package/data/registry/react/components/button/index.tailwind.tsx +2 -1
- package/data/registry/react/components/button/index.tsx +3 -4
- package/data/registry/react/components/calendar/index.tailwind.tsx +10 -12
- package/data/registry/react/components/calendar/index.tsx +9 -11
- package/data/registry/react/components/card/index.tailwind.tsx +8 -10
- package/data/registry/react/components/card/index.tsx +8 -10
- package/data/registry/react/components/carousel/index.tailwind.tsx +7 -9
- package/data/registry/react/components/carousel/index.tsx +7 -9
- package/data/registry/react/components/checkbox/index.tailwind.tsx +3 -5
- package/data/registry/react/components/checkbox/index.tsx +3 -5
- package/data/registry/react/components/code-editor/index.tailwind.tsx +2 -4
- package/data/registry/react/components/code-editor/index.tsx +2 -4
- package/data/registry/react/components/code-panel/index.tailwind.tsx +5 -7
- package/data/registry/react/components/code-panel/index.tsx +5 -7
- package/data/registry/react/components/color-picker/index.tailwind.tsx +7 -6
- package/data/registry/react/components/color-picker/index.tsx +7 -6
- package/data/registry/react/components/combobox/index.tailwind.tsx +8 -10
- package/data/registry/react/components/combobox/index.tsx +8 -10
- package/data/registry/react/components/context-menu/index.tailwind.tsx +10 -12
- package/data/registry/react/components/context-menu/index.tsx +10 -12
- package/data/registry/react/components/date-picker/index.tailwind.tsx +7 -9
- package/data/registry/react/components/date-picker/index.tsx +7 -9
- package/data/registry/react/components/dialog/index.tailwind.tsx +6 -8
- package/data/registry/react/components/dialog/index.tsx +6 -8
- package/data/registry/react/components/dropdown-menu/index.tailwind.tsx +10 -12
- package/data/registry/react/components/dropdown-menu/index.tsx +10 -12
- package/data/registry/react/components/file-upload/index.tailwind.tsx +6 -8
- package/data/registry/react/components/file-upload/index.tsx +6 -8
- package/data/registry/react/components/form/field.tailwind.tsx +2 -1
- package/data/registry/react/components/form/field.tsx +2 -3
- package/data/registry/react/components/header/index.tailwind.tsx +17 -19
- package/data/registry/react/components/header/index.tsx +17 -19
- package/data/registry/react/components/input/index.tailwind.tsx +4 -6
- package/data/registry/react/components/input/index.tsx +4 -6
- package/data/registry/react/components/label/index.tailwind.tsx +6 -8
- package/data/registry/react/components/label/index.tsx +6 -8
- package/data/registry/react/components/markdown-editor/index.tailwind.tsx +2 -4
- package/data/registry/react/components/markdown-editor/index.tsx +2 -4
- package/data/registry/react/components/menubar/index.tailwind.tsx +2 -4
- package/data/registry/react/components/menubar/index.tsx +2 -4
- package/data/registry/react/components/numeric-input/index.tailwind.tsx +2 -4
- package/data/registry/react/components/numeric-input/index.tsx +2 -4
- package/data/registry/react/components/page-toc/index.tailwind.tsx +3 -2
- package/data/registry/react/components/page-toc/index.tsx +2 -3
- package/data/registry/react/components/pagination/index.tailwind.tsx +8 -10
- package/data/registry/react/components/pagination/index.tsx +8 -10
- package/data/registry/react/components/popover/index.tailwind.tsx +4 -6
- package/data/registry/react/components/popover/index.tsx +4 -6
- package/data/registry/react/components/progress/index.tailwind.tsx +3 -5
- package/data/registry/react/components/progress/index.tsx +2 -4
- package/data/registry/react/components/radio/index.tailwind.tsx +3 -5
- package/data/registry/react/components/radio/index.tsx +3 -5
- package/data/registry/react/components/rich-text-editor/index.tailwind.tsx +3 -5
- package/data/registry/react/components/rich-text-editor/index.tsx +3 -5
- package/data/registry/react/components/select/index.tailwind.tsx +8 -10
- package/data/registry/react/components/select/index.tsx +8 -10
- package/data/registry/react/components/separator/index.tailwind.tsx +2 -4
- package/data/registry/react/components/separator/index.tsx +2 -4
- package/data/registry/react/components/sidebar/index.tailwind.tsx +32 -43
- package/data/registry/react/components/sidebar/index.tsx +29 -46
- package/data/registry/react/components/skeleton/index.tailwind.tsx +2 -4
- package/data/registry/react/components/skeleton/index.tsx +2 -4
- package/data/registry/react/components/slider/index.tailwind.tsx +5 -7
- package/data/registry/react/components/slider/index.tsx +5 -7
- package/data/registry/react/components/spinner/index.tailwind.tsx +3 -5
- package/data/registry/react/components/spinner/index.tsx +2 -4
- package/data/registry/react/components/switch/index.tailwind.tsx +3 -5
- package/data/registry/react/components/switch/index.tsx +2 -4
- package/data/registry/react/components/tabs/index.tailwind.tsx +6 -8
- package/data/registry/react/components/tabs/index.tsx +6 -8
- package/data/registry/react/components/textarea/index.tailwind.tsx +2 -4
- package/data/registry/react/components/textarea/index.tsx +2 -4
- package/data/registry/react/components/toggle/index.tailwind.tsx +4 -6
- package/data/registry/react/components/toggle/index.tsx +4 -6
- package/data/registry/react/components/tooltip/index.tailwind.tsx +2 -4
- package/data/registry/react/components/tooltip/index.tsx +2 -4
- package/data/registry/react/lib/cn.tailwind.ts +17 -0
- package/data/registry/react/peer-versions.json +3 -1
- package/data/registry/react/registry.json +159 -43
- package/package.json +1 -1
- package/src/add.mjs +25 -1
- package/templates/ui-app-template/sh-ui.config.json +5 -0
|
@@ -4,11 +4,9 @@ import * as React from "react";
|
|
|
4
4
|
import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
5
5
|
import "./styles.css";
|
|
6
6
|
|
|
7
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
7
8
|
type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
|
|
8
9
|
|
|
9
|
-
function cx(...args: (string | undefined | false | null)[]) {
|
|
10
|
-
return args.filter(Boolean).join(" ");
|
|
11
|
-
}
|
|
12
10
|
|
|
13
11
|
/* ───────── Root ───────── */
|
|
14
12
|
|
|
@@ -23,7 +21,7 @@ export const DropdownMenuTrigger = React.forwardRef<
|
|
|
23
21
|
return (
|
|
24
22
|
<BaseMenu.Trigger
|
|
25
23
|
ref={ref}
|
|
26
|
-
className={
|
|
24
|
+
className={cn("sh-ui-dm__trigger", className)}
|
|
27
25
|
{...props}
|
|
28
26
|
/>
|
|
29
27
|
);
|
|
@@ -63,7 +61,7 @@ export const DropdownMenuContent = React.forwardRef<
|
|
|
63
61
|
>
|
|
64
62
|
<BaseMenu.Popup
|
|
65
63
|
ref={ref}
|
|
66
|
-
className={
|
|
64
|
+
className={cn("sh-ui-dm__content", className)}
|
|
67
65
|
{...props}
|
|
68
66
|
>
|
|
69
67
|
{children}
|
|
@@ -82,7 +80,7 @@ export const DropdownMenuItem = React.forwardRef<
|
|
|
82
80
|
return (
|
|
83
81
|
<BaseMenu.Item
|
|
84
82
|
ref={ref}
|
|
85
|
-
className={
|
|
83
|
+
className={cn("sh-ui-dm__item", className)}
|
|
86
84
|
{...props}
|
|
87
85
|
/>
|
|
88
86
|
);
|
|
@@ -102,7 +100,7 @@ export const DropdownMenuCheckboxItem = React.forwardRef<
|
|
|
102
100
|
return (
|
|
103
101
|
<BaseMenu.CheckboxItem
|
|
104
102
|
ref={ref}
|
|
105
|
-
className={
|
|
103
|
+
className={cn("sh-ui-dm__item", "sh-ui-dm__item--check", className)}
|
|
106
104
|
{...props}
|
|
107
105
|
>
|
|
108
106
|
<span className="sh-ui-dm__item-indicator" aria-hidden>
|
|
@@ -131,7 +129,7 @@ export const DropdownMenuRadioItem = React.forwardRef<
|
|
|
131
129
|
return (
|
|
132
130
|
<BaseMenu.RadioItem
|
|
133
131
|
ref={ref}
|
|
134
|
-
className={
|
|
132
|
+
className={cn("sh-ui-dm__item", "sh-ui-dm__item--check", className)}
|
|
135
133
|
{...props}
|
|
136
134
|
>
|
|
137
135
|
<span className="sh-ui-dm__item-indicator" aria-hidden>
|
|
@@ -153,7 +151,7 @@ export const DropdownMenuGroup = React.forwardRef<
|
|
|
153
151
|
return (
|
|
154
152
|
<BaseMenu.Group
|
|
155
153
|
ref={ref}
|
|
156
|
-
className={
|
|
154
|
+
className={cn("sh-ui-dm__group", className)}
|
|
157
155
|
{...props}
|
|
158
156
|
/>
|
|
159
157
|
);
|
|
@@ -166,7 +164,7 @@ export const DropdownMenuLabel = React.forwardRef<
|
|
|
166
164
|
return (
|
|
167
165
|
<BaseMenu.GroupLabel
|
|
168
166
|
ref={ref}
|
|
169
|
-
className={
|
|
167
|
+
className={cn("sh-ui-dm__label", className)}
|
|
170
168
|
{...props}
|
|
171
169
|
/>
|
|
172
170
|
);
|
|
@@ -185,7 +183,7 @@ export const DropdownMenuSeparator = React.forwardRef<
|
|
|
185
183
|
ref={ref}
|
|
186
184
|
role="separator"
|
|
187
185
|
aria-orientation="horizontal"
|
|
188
|
-
className={
|
|
186
|
+
className={cn("sh-ui-dm__separator", className)}
|
|
189
187
|
{...props}
|
|
190
188
|
/>
|
|
191
189
|
);
|
|
@@ -204,7 +202,7 @@ export const DropdownMenuSubTrigger = React.forwardRef<
|
|
|
204
202
|
return (
|
|
205
203
|
<BaseMenu.SubmenuTrigger
|
|
206
204
|
ref={ref}
|
|
207
|
-
className={
|
|
205
|
+
className={cn("sh-ui-dm__item", "sh-ui-dm__sub-trigger", className)}
|
|
208
206
|
{...props}
|
|
209
207
|
>
|
|
210
208
|
<span className="sh-ui-dm__item-text">{children}</span>
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
|
|
5
|
-
function cx(...args: (string | false | undefined)[]) {
|
|
6
|
-
return args.filter(Boolean).join(" ");
|
|
7
|
-
}
|
|
8
5
|
|
|
6
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
9
7
|
function formatBytes(bytes: number): string {
|
|
10
8
|
if (bytes < 1024) return `${bytes} B`;
|
|
11
9
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -100,7 +98,7 @@ export const FileUpload = React.forwardRef<HTMLInputElement, FileUploadProps>(
|
|
|
100
98
|
|
|
101
99
|
return (
|
|
102
100
|
<FileUploadContext.Provider value={ctx}>
|
|
103
|
-
<div className={
|
|
101
|
+
<div className={cn("flex flex-col gap-[var(--space-3)]", className)} style={style}>
|
|
104
102
|
<input
|
|
105
103
|
ref={inputRef}
|
|
106
104
|
id={id}
|
|
@@ -154,7 +152,7 @@ export const FileUploadDropzone = React.forwardRef<HTMLDivElement, FileUploadDro
|
|
|
154
152
|
tabIndex={disabled ? -1 : 0}
|
|
155
153
|
aria-disabled={disabled || undefined}
|
|
156
154
|
data-dragging={dragging || undefined}
|
|
157
|
-
className={
|
|
155
|
+
className={cn(
|
|
158
156
|
"relative flex flex-col items-center justify-center gap-[var(--space-2)] py-[var(--space-8)] px-[var(--space-6)] min-h-40 bg-background-subtle text-foreground-muted border-[1.5px] border-dashed border-border rounded-[var(--radius)] cursor-pointer text-center transition-[border-color,background-color,color] duration-[var(--duration-fast)] hover:border-border-strong hover:text-foreground focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-foreground focus-visible:outline-offset-2 focus-visible:border-foreground motion-reduce:transition-none",
|
|
159
157
|
dragging && "border-foreground bg-background-muted text-foreground",
|
|
160
158
|
disabled && "opacity-[var(--opacity-disabled)] cursor-not-allowed pointer-events-none",
|
|
@@ -190,7 +188,7 @@ export const FileUploadTrigger = React.forwardRef<HTMLButtonElement, FileUploadT
|
|
|
190
188
|
ref={ref}
|
|
191
189
|
type={type ?? "button"}
|
|
192
190
|
disabled={disabled || rest.disabled}
|
|
193
|
-
className={
|
|
191
|
+
className={cn(
|
|
194
192
|
"inline-flex items-center justify-center gap-[var(--space-2)] py-[var(--space-2)] px-[var(--space-3)] text-[length:var(--text-sm)] font-medium text-foreground bg-background border border-border rounded-[calc(var(--radius)-2px)] cursor-pointer transition-[background-color,border-color] duration-[var(--duration-fast)] hover:not-disabled:bg-background-muted hover:not-disabled:border-border-strong focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-foreground focus-visible:outline-offset-2 disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed",
|
|
195
193
|
className,
|
|
196
194
|
)}
|
|
@@ -220,7 +218,7 @@ export const FileUploadList = React.forwardRef<HTMLUListElement, FileUploadListP
|
|
|
220
218
|
: (children ?? files.map((f, i) => <FileUploadItem key={`${f.name}-${i}`} file={f} index={i} />));
|
|
221
219
|
|
|
222
220
|
return (
|
|
223
|
-
<ul ref={ref} className={
|
|
221
|
+
<ul ref={ref} className={cn("list-none m-0 p-0 flex flex-col gap-1.5", className)} {...rest}>
|
|
224
222
|
{content}
|
|
225
223
|
</ul>
|
|
226
224
|
);
|
|
@@ -239,7 +237,7 @@ export const FileUploadItem = React.forwardRef<HTMLLIElement, FileUploadItemProp
|
|
|
239
237
|
return (
|
|
240
238
|
<li
|
|
241
239
|
ref={ref}
|
|
242
|
-
className={
|
|
240
|
+
className={cn(
|
|
243
241
|
"flex items-center gap-2.5 py-[var(--space-2)] px-[var(--space-3)] bg-background border border-border rounded-[calc(var(--radius)-2px)] text-[length:var(--text-sm)] text-foreground [&>svg]:text-foreground-muted [&>svg]:shrink-0",
|
|
244
242
|
className,
|
|
245
243
|
)}
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import "./styles.css";
|
|
5
5
|
|
|
6
|
-
function cx(...args: (string | false | undefined)[]) {
|
|
7
|
-
return args.filter(Boolean).join(" ");
|
|
8
|
-
}
|
|
9
6
|
|
|
7
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
10
8
|
function formatBytes(bytes: number): string {
|
|
11
9
|
if (bytes < 1024) return `${bytes} B`;
|
|
12
10
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -200,7 +198,7 @@ export const FileUpload = React.forwardRef<HTMLInputElement, FileUploadProps>(
|
|
|
200
198
|
|
|
201
199
|
return (
|
|
202
200
|
<FileUploadContext.Provider value={ctx}>
|
|
203
|
-
<div className={
|
|
201
|
+
<div className={cn("sh-ui-file-upload", className)} style={style}>
|
|
204
202
|
{/* 공유 네이티브 input. Trigger/Dropzone 모두 이를 통해 파일 선택을 연다. */}
|
|
205
203
|
<input
|
|
206
204
|
ref={inputRef}
|
|
@@ -283,7 +281,7 @@ export const FileUploadDropzone = React.forwardRef<
|
|
|
283
281
|
tabIndex={disabled ? -1 : 0}
|
|
284
282
|
aria-disabled={disabled || undefined}
|
|
285
283
|
data-dragging={dragging || undefined}
|
|
286
|
-
className={
|
|
284
|
+
className={cn(
|
|
287
285
|
"sh-ui-file-upload__dropzone",
|
|
288
286
|
dragging && "sh-ui-file-upload__dropzone--drag",
|
|
289
287
|
disabled && "sh-ui-file-upload__dropzone--disabled",
|
|
@@ -332,7 +330,7 @@ export const FileUploadTrigger = React.forwardRef<
|
|
|
332
330
|
ref={ref}
|
|
333
331
|
type={type ?? "button"}
|
|
334
332
|
disabled={disabled || rest.disabled}
|
|
335
|
-
className={
|
|
333
|
+
className={cn("sh-ui-file-upload__trigger", className)}
|
|
336
334
|
onClick={(e) => {
|
|
337
335
|
// Dropzone 내부에 있을 때 상위 onClick이 중복 트리거되지 않도록 버블 차단
|
|
338
336
|
e.stopPropagation();
|
|
@@ -391,7 +389,7 @@ export const FileUploadList = React.forwardRef<
|
|
|
391
389
|
return (
|
|
392
390
|
<ul
|
|
393
391
|
ref={ref}
|
|
394
|
-
className={
|
|
392
|
+
className={cn("sh-ui-file-upload__list", className)}
|
|
395
393
|
{...rest}
|
|
396
394
|
>
|
|
397
395
|
{content}
|
|
@@ -418,7 +416,7 @@ export const FileUploadItem = React.forwardRef<
|
|
|
418
416
|
return (
|
|
419
417
|
<li
|
|
420
418
|
ref={ref}
|
|
421
|
-
className={
|
|
419
|
+
className={cn("sh-ui-file-upload__item", className)}
|
|
422
420
|
{...rest}
|
|
423
421
|
>
|
|
424
422
|
{children ?? (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
4
5
|
import { FormContext, FieldContext, SectionContext, StepContext, DisabledContext, useFormField } from "./context";
|
|
5
6
|
import type { FieldValidate, ValidateOn } from "./types";
|
|
6
7
|
import { scopedPath } from "./utils";
|
|
@@ -127,7 +128,7 @@ export function FormControl({ children, valueAs = "value", render }: FormControl
|
|
|
127
128
|
const store = React.useContext(FormContext)!;
|
|
128
129
|
const field = useFormField(ctx.path);
|
|
129
130
|
|
|
130
|
-
const describedBy =
|
|
131
|
+
const describedBy = cn(ctx.descId, field.hasError ? ctx.errorId : null) || undefined;
|
|
131
132
|
|
|
132
133
|
const ctrl: ControlProps = {
|
|
133
134
|
id: ctx.id, name: ctx.path,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
4
5
|
import {
|
|
5
6
|
FormContext,
|
|
6
7
|
FieldContext,
|
|
@@ -195,9 +196,7 @@ export function FormControl({
|
|
|
195
196
|
const field = useFormField(ctx.path);
|
|
196
197
|
|
|
197
198
|
const describedBy =
|
|
198
|
-
|
|
199
|
-
.filter(Boolean)
|
|
200
|
-
.join(" ") || undefined;
|
|
199
|
+
cn(ctx.descId, field.hasError ? ctx.errorId : null) || undefined;
|
|
201
200
|
|
|
202
201
|
const ctrl: ControlProps = {
|
|
203
202
|
id: ctx.id,
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
5
|
|
|
6
|
-
function cx(...args: (string | undefined | false | null)[]) {
|
|
7
|
-
return args.filter(Boolean).join(" ");
|
|
8
|
-
}
|
|
9
6
|
|
|
7
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
10
8
|
const FOCUSABLE_SELECTOR =
|
|
11
9
|
'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
12
10
|
|
|
@@ -151,7 +149,7 @@ export const Header = React.forwardRef<HTMLElement, HeaderProps>(function Header
|
|
|
151
149
|
<HeaderContext.Provider value={ctx}>
|
|
152
150
|
<header
|
|
153
151
|
ref={setRefs}
|
|
154
|
-
className={
|
|
152
|
+
className={cn(
|
|
155
153
|
"relative flex items-center gap-[var(--space-4)] h-[var(--control-md)] px-[var(--space-3)] border-b border-border transition-[transform,background-color] duration-[var(--duration-base)] [--sh-ui-header-hover-bg:var(--background-muted)] [--sh-ui-header-blur-opacity:85%] [--sh-ui-header-blur-radius:16px] motion-reduce:transition-none max-md:gap-[var(--space-2)] data-[sticky-hide][data-hidden]:-translate-y-full",
|
|
156
154
|
variantClasses[variant],
|
|
157
155
|
className,
|
|
@@ -169,19 +167,19 @@ export const Header = React.forwardRef<HTMLElement, HeaderProps>(function Header
|
|
|
169
167
|
|
|
170
168
|
export const HeaderBrand = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
171
169
|
function HeaderBrand({ className, ...props }, ref) {
|
|
172
|
-
return <div ref={ref} className={
|
|
170
|
+
return <div ref={ref} className={cn("inline-flex items-center gap-[var(--space-2)] shrink-0", className)} {...props} />;
|
|
173
171
|
},
|
|
174
172
|
);
|
|
175
173
|
|
|
176
174
|
export const HeaderLogo = React.forwardRef<HTMLSpanElement, React.HTMLAttributes<HTMLSpanElement>>(
|
|
177
175
|
function HeaderLogo({ className, ...props }, ref) {
|
|
178
|
-
return <span ref={ref} className={
|
|
176
|
+
return <span ref={ref} className={cn("inline-flex items-center text-foreground", className)} {...props} />;
|
|
179
177
|
},
|
|
180
178
|
);
|
|
181
179
|
|
|
182
180
|
export const HeaderTitle = React.forwardRef<HTMLSpanElement, React.HTMLAttributes<HTMLSpanElement>>(
|
|
183
181
|
function HeaderTitle({ className, ...props }, ref) {
|
|
184
|
-
return <span ref={ref} className={
|
|
182
|
+
return <span ref={ref} className={cn("text-[length:var(--text-base)] font-bold text-foreground tracking-[-0.3px]", className)} {...props} />;
|
|
185
183
|
},
|
|
186
184
|
);
|
|
187
185
|
|
|
@@ -198,7 +196,7 @@ export const HeaderTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTM
|
|
|
198
196
|
<button
|
|
199
197
|
ref={setRefs}
|
|
200
198
|
type="button"
|
|
201
|
-
className={
|
|
199
|
+
className={cn(
|
|
202
200
|
"hidden items-center justify-center w-9 h-9 p-0 bg-transparent border-0 text-foreground rounded-[calc(var(--radius)-2px)] cursor-pointer transition-[background-color] duration-[var(--duration-fast)] hover:bg-[var(--sh-ui-header-hover-bg)] focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-foreground focus-visible:outline-offset-2 max-md:inline-flex max-md:order-[-1]",
|
|
203
201
|
className,
|
|
204
202
|
)}
|
|
@@ -244,7 +242,7 @@ export const HeaderNav = React.forwardRef<HTMLElement, HeaderNavProps>(
|
|
|
244
242
|
<NavLocationContext.Provider value="inline">
|
|
245
243
|
<nav
|
|
246
244
|
ref={ref}
|
|
247
|
-
className={
|
|
245
|
+
className={cn(
|
|
248
246
|
"flex items-center gap-[var(--space-1)] flex-1 min-w-0 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden max-md:hidden",
|
|
249
247
|
className,
|
|
250
248
|
)}
|
|
@@ -293,7 +291,7 @@ export const HeaderItem = React.forwardRef<
|
|
|
293
291
|
<a
|
|
294
292
|
ref={ref}
|
|
295
293
|
href={href}
|
|
296
|
-
className={
|
|
294
|
+
className={cn(
|
|
297
295
|
"inline-flex items-center gap-[var(--space-1)] py-[var(--space-2)] px-[var(--space-3)] text-[length:var(--text-sm)] font-medium text-foreground-muted no-underline bg-transparent border-0 rounded-[calc(var(--radius)-2px)] cursor-pointer whitespace-nowrap transition-[color,background-color] duration-[var(--duration-fast)] hover:text-foreground hover:bg-[var(--sh-ui-header-hover-bg)] data-[active]:text-foreground data-[active]:font-semibold focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-foreground focus-visible:outline-offset-2 motion-reduce:transition-none max-md:py-[var(--space-3)] max-md:px-[var(--space-3)]",
|
|
298
296
|
className,
|
|
299
297
|
)}
|
|
@@ -311,19 +309,19 @@ export const HeaderItem = React.forwardRef<
|
|
|
311
309
|
|
|
312
310
|
export const HeaderActions = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
313
311
|
function HeaderActions({ className, ...props }, ref) {
|
|
314
|
-
return <div ref={ref} className={
|
|
312
|
+
return <div ref={ref} className={cn("inline-flex items-center gap-[var(--space-2)] ml-auto shrink-0", className)} {...props} />;
|
|
315
313
|
},
|
|
316
314
|
);
|
|
317
315
|
|
|
318
316
|
export const HeaderDesktopOnly = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
319
317
|
function HeaderDesktopOnly({ className, ...props }, ref) {
|
|
320
|
-
return <div ref={ref} className={
|
|
318
|
+
return <div ref={ref} className={cn("contents max-md:hidden", className)} {...props} />;
|
|
321
319
|
},
|
|
322
320
|
);
|
|
323
321
|
|
|
324
322
|
export const HeaderMobileOnly = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
325
323
|
function HeaderMobileOnly({ className, ...props }, ref) {
|
|
326
|
-
return <div ref={ref} className={
|
|
324
|
+
return <div ref={ref} className={cn("hidden max-md:contents", className)} {...props} />;
|
|
327
325
|
},
|
|
328
326
|
);
|
|
329
327
|
|
|
@@ -335,12 +333,12 @@ export const HeaderNavGroup = React.forwardRef<HTMLDivElement, HeaderNavGroupPro
|
|
|
335
333
|
function HeaderNavGroup({ className, label, children, ...props }, ref) {
|
|
336
334
|
const location = React.useContext(NavLocationContext);
|
|
337
335
|
if (location === "inline") {
|
|
338
|
-
return <div ref={ref} className={
|
|
336
|
+
return <div ref={ref} className={cn("contents", className)} {...props}>{children}</div>;
|
|
339
337
|
}
|
|
340
338
|
return (
|
|
341
339
|
<div
|
|
342
340
|
ref={ref}
|
|
343
|
-
className={
|
|
341
|
+
className={cn("flex flex-col mt-[var(--space-3)] first:mt-0", className)}
|
|
344
342
|
role="group"
|
|
345
343
|
aria-label={typeof label === "string" ? label : undefined}
|
|
346
344
|
{...props}
|
|
@@ -407,7 +405,7 @@ export function HeaderMenu({ children, className, defaultOpen = false }: { child
|
|
|
407
405
|
<MenuContext.Provider value={ctx}>
|
|
408
406
|
<div
|
|
409
407
|
ref={containerRef}
|
|
410
|
-
className={
|
|
408
|
+
className={cn(
|
|
411
409
|
"relative",
|
|
412
410
|
location === "inline" ? "inline-block" : "flex flex-col",
|
|
413
411
|
className,
|
|
@@ -438,7 +436,7 @@ export const HeaderMenuTrigger = React.forwardRef<HTMLButtonElement, React.Butto
|
|
|
438
436
|
aria-expanded={open}
|
|
439
437
|
aria-controls={contentId}
|
|
440
438
|
data-open={open ? "" : undefined}
|
|
441
|
-
className={
|
|
439
|
+
className={cn(
|
|
442
440
|
"inline-flex items-center gap-[var(--space-1)] py-[var(--space-2)] px-[var(--space-3)] text-[length:var(--text-sm)] font-medium text-foreground-muted bg-transparent border-0 rounded-[calc(var(--radius)-2px)] cursor-pointer whitespace-nowrap transition-[color,background-color] duration-[var(--duration-fast)] hover:text-foreground hover:bg-[var(--sh-ui-header-hover-bg)] data-[open]:text-foreground data-[open]:bg-[var(--sh-ui-header-hover-bg)] focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-foreground focus-visible:outline-offset-2 motion-reduce:transition-none",
|
|
443
441
|
location === "drawer" && "max-md:justify-between max-md:w-full max-md:py-[var(--space-3)] max-md:px-[var(--space-3)]",
|
|
444
442
|
className,
|
|
@@ -471,7 +469,7 @@ export const HeaderMenuContent = React.forwardRef<HTMLDivElement, React.HTMLAttr
|
|
|
471
469
|
aria-labelledby={triggerId}
|
|
472
470
|
data-open={open ? "" : undefined}
|
|
473
471
|
hidden={!open}
|
|
474
|
-
className={
|
|
472
|
+
className={cn(
|
|
475
473
|
"max-md:flex max-md:flex-col max-md:py-[var(--space-1)] max-md:pl-[var(--space-4)] max-md:gap-px max-md:[&[hidden]]:hidden",
|
|
476
474
|
className,
|
|
477
475
|
)}
|
|
@@ -513,7 +511,7 @@ export const HeaderMenuContent = React.forwardRef<HTMLDivElement, React.HTMLAttr
|
|
|
513
511
|
role="menu"
|
|
514
512
|
aria-labelledby={triggerId}
|
|
515
513
|
data-open=""
|
|
516
|
-
className={
|
|
514
|
+
className={cn(
|
|
517
515
|
"z-[var(--z-dropdown,50)] p-[var(--space-1)] bg-background border border-border rounded-[var(--radius)] shadow-[0_8px_24px_-8px_rgba(0,0,0,0.18)] flex flex-col gap-px text-foreground",
|
|
518
516
|
className,
|
|
519
517
|
)}
|
|
@@ -4,10 +4,8 @@ import * as React from "react";
|
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
5
|
import "./styles.css";
|
|
6
6
|
|
|
7
|
-
function cx(...args: (string | undefined | false | null)[]) {
|
|
8
|
-
return args.filter(Boolean).join(" ");
|
|
9
|
-
}
|
|
10
7
|
|
|
8
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
11
9
|
const FOCUSABLE_SELECTOR =
|
|
12
10
|
'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
13
11
|
|
|
@@ -264,7 +262,7 @@ export const Header = React.forwardRef<HTMLElement, HeaderProps>(function Header
|
|
|
264
262
|
<HeaderContext.Provider value={ctx}>
|
|
265
263
|
<header
|
|
266
264
|
ref={setRefs}
|
|
267
|
-
className={
|
|
265
|
+
className={cn("sh-ui-header", `sh-ui-header--${variant}`, className)}
|
|
268
266
|
data-drawer-open={open ? "" : undefined}
|
|
269
267
|
data-sticky-hide={stickyHide ? "" : undefined}
|
|
270
268
|
data-hidden={hidden ? "" : undefined}
|
|
@@ -282,21 +280,21 @@ export const HeaderBrand = React.forwardRef<
|
|
|
282
280
|
HTMLDivElement,
|
|
283
281
|
React.HTMLAttributes<HTMLDivElement>
|
|
284
282
|
>(function HeaderBrand({ className, ...props }, ref) {
|
|
285
|
-
return <div ref={ref} className={
|
|
283
|
+
return <div ref={ref} className={cn("sh-ui-header__brand", className)} {...props} />;
|
|
286
284
|
});
|
|
287
285
|
|
|
288
286
|
export const HeaderLogo = React.forwardRef<
|
|
289
287
|
HTMLSpanElement,
|
|
290
288
|
React.HTMLAttributes<HTMLSpanElement>
|
|
291
289
|
>(function HeaderLogo({ className, ...props }, ref) {
|
|
292
|
-
return <span ref={ref} className={
|
|
290
|
+
return <span ref={ref} className={cn("sh-ui-header__logo", className)} {...props} />;
|
|
293
291
|
});
|
|
294
292
|
|
|
295
293
|
export const HeaderTitle = React.forwardRef<
|
|
296
294
|
HTMLSpanElement,
|
|
297
295
|
React.HTMLAttributes<HTMLSpanElement>
|
|
298
296
|
>(function HeaderTitle({ className, ...props }, ref) {
|
|
299
|
-
return <span ref={ref} className={
|
|
297
|
+
return <span ref={ref} className={cn("sh-ui-header__title", className)} {...props} />;
|
|
300
298
|
});
|
|
301
299
|
|
|
302
300
|
/* ───────── Trigger ─────────
|
|
@@ -322,7 +320,7 @@ export const HeaderTrigger = React.forwardRef<
|
|
|
322
320
|
<button
|
|
323
321
|
ref={setRefs}
|
|
324
322
|
type="button"
|
|
325
|
-
className={
|
|
323
|
+
className={cn("sh-ui-header__trigger", className)}
|
|
326
324
|
aria-label={open ? "메뉴 닫기" : "메뉴 열기"}
|
|
327
325
|
aria-expanded={open}
|
|
328
326
|
data-open={open ? "" : undefined}
|
|
@@ -399,7 +397,7 @@ export const HeaderNav = React.forwardRef<HTMLElement, HeaderNavProps>(
|
|
|
399
397
|
return (
|
|
400
398
|
<NavMatchContext.Provider value={navMatch}>
|
|
401
399
|
<NavLocationContext.Provider value="inline">
|
|
402
|
-
<nav ref={ref} className={
|
|
400
|
+
<nav ref={ref} className={cn("sh-ui-header__nav", className)} {...props}>
|
|
403
401
|
{children}
|
|
404
402
|
</nav>
|
|
405
403
|
</NavLocationContext.Provider>
|
|
@@ -457,7 +455,7 @@ export const HeaderItem = React.forwardRef<
|
|
|
457
455
|
<a
|
|
458
456
|
ref={ref}
|
|
459
457
|
href={href}
|
|
460
|
-
className={
|
|
458
|
+
className={cn("sh-ui-header__item", className)}
|
|
461
459
|
data-active={computedActive ? "" : undefined}
|
|
462
460
|
aria-current={computedActive ? "page" : undefined}
|
|
463
461
|
onClick={(e) => {
|
|
@@ -478,7 +476,7 @@ export const HeaderActions = React.forwardRef<
|
|
|
478
476
|
React.HTMLAttributes<HTMLDivElement>
|
|
479
477
|
>(function HeaderActions({ className, ...props }, ref) {
|
|
480
478
|
return (
|
|
481
|
-
<div ref={ref} className={
|
|
479
|
+
<div ref={ref} className={cn("sh-ui-header__actions", className)} {...props} />
|
|
482
480
|
);
|
|
483
481
|
});
|
|
484
482
|
|
|
@@ -493,7 +491,7 @@ export const HeaderDesktopOnly = React.forwardRef<
|
|
|
493
491
|
React.HTMLAttributes<HTMLDivElement>
|
|
494
492
|
>(function HeaderDesktopOnly({ className, ...props }, ref) {
|
|
495
493
|
return (
|
|
496
|
-
<div ref={ref} className={
|
|
494
|
+
<div ref={ref} className={cn("sh-ui-header__desktop-only", className)} {...props} />
|
|
497
495
|
);
|
|
498
496
|
});
|
|
499
497
|
|
|
@@ -503,7 +501,7 @@ export const HeaderMobileOnly = React.forwardRef<
|
|
|
503
501
|
React.HTMLAttributes<HTMLDivElement>
|
|
504
502
|
>(function HeaderMobileOnly({ className, ...props }, ref) {
|
|
505
503
|
return (
|
|
506
|
-
<div ref={ref} className={
|
|
504
|
+
<div ref={ref} className={cn("sh-ui-header__mobile-only", className)} {...props} />
|
|
507
505
|
);
|
|
508
506
|
});
|
|
509
507
|
|
|
@@ -524,7 +522,7 @@ export const HeaderNavGroup = React.forwardRef<HTMLDivElement, HeaderNavGroupPro
|
|
|
524
522
|
return (
|
|
525
523
|
<div
|
|
526
524
|
ref={ref}
|
|
527
|
-
className={
|
|
525
|
+
className={cn("sh-ui-header__group sh-ui-header__group--inline", className)}
|
|
528
526
|
{...props}
|
|
529
527
|
>
|
|
530
528
|
{children}
|
|
@@ -534,7 +532,7 @@ export const HeaderNavGroup = React.forwardRef<HTMLDivElement, HeaderNavGroupPro
|
|
|
534
532
|
return (
|
|
535
533
|
<div
|
|
536
534
|
ref={ref}
|
|
537
|
-
className={
|
|
535
|
+
className={cn("sh-ui-header__group sh-ui-header__group--drawer", className)}
|
|
538
536
|
role="group"
|
|
539
537
|
aria-label={typeof label === "string" ? label : undefined}
|
|
540
538
|
{...props}
|
|
@@ -626,7 +624,7 @@ export function HeaderMenu({
|
|
|
626
624
|
<MenuContext.Provider value={ctx}>
|
|
627
625
|
<div
|
|
628
626
|
ref={containerRef}
|
|
629
|
-
className={
|
|
627
|
+
className={cn(
|
|
630
628
|
"sh-ui-header__menu",
|
|
631
629
|
`sh-ui-header__menu--${location}`,
|
|
632
630
|
open && "is-open",
|
|
@@ -665,7 +663,7 @@ export const HeaderMenuTrigger = React.forwardRef<
|
|
|
665
663
|
aria-expanded={open}
|
|
666
664
|
aria-controls={contentId}
|
|
667
665
|
data-open={open ? "" : undefined}
|
|
668
|
-
className={
|
|
666
|
+
className={cn("sh-ui-header__menu-trigger", className)}
|
|
669
667
|
onClick={(e) => {
|
|
670
668
|
setOpen(!open);
|
|
671
669
|
onClick?.(e);
|
|
@@ -704,7 +702,7 @@ export const HeaderMenuContent = React.forwardRef<
|
|
|
704
702
|
aria-labelledby={triggerId}
|
|
705
703
|
data-open={open ? "" : undefined}
|
|
706
704
|
hidden={!open}
|
|
707
|
-
className={
|
|
705
|
+
className={cn("sh-ui-header__menu-content", className)}
|
|
708
706
|
style={style}
|
|
709
707
|
{...props}
|
|
710
708
|
>
|
|
@@ -754,7 +752,7 @@ export const HeaderMenuContent = React.forwardRef<
|
|
|
754
752
|
role="menu"
|
|
755
753
|
aria-labelledby={triggerId}
|
|
756
754
|
data-open=""
|
|
757
|
-
className={
|
|
755
|
+
className={cn("sh-ui-header__menu-content sh-ui-header__menu-content--portal", className)}
|
|
758
756
|
style={{
|
|
759
757
|
position: "absolute",
|
|
760
758
|
top: pos.top,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
|
|
5
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
5
6
|
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "prefix"> {
|
|
6
7
|
/** input 우측에 부착할 보조 노드(아이콘·단위·버튼 등). 더 많은 슬롯이 필요하면 InputGroup 사용. */
|
|
7
8
|
suffix?: React.ReactNode;
|
|
@@ -9,9 +10,6 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
|
|
|
9
10
|
prefix?: React.ReactNode;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
function cx(...args: (string | undefined | null | false)[]) {
|
|
13
|
-
return args.filter(Boolean).join(" ");
|
|
14
|
-
}
|
|
15
13
|
|
|
16
14
|
/* ───────── Base utility 묶음 (반복 줄이기) ───────── */
|
|
17
15
|
|
|
@@ -69,7 +67,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
|
|
|
69
67
|
<InputGroupContext.Provider value={{ inGroup: true }}>
|
|
70
68
|
<div
|
|
71
69
|
ref={mergedRef}
|
|
72
|
-
className={
|
|
70
|
+
className={cn(baseGroupClasses, className)}
|
|
73
71
|
data-disabled={disabled || undefined}
|
|
74
72
|
aria-invalid={ariaInvalid}
|
|
75
73
|
onClick={handleClick}
|
|
@@ -91,7 +89,7 @@ export const InputAdornment = React.forwardRef<HTMLSpanElement, InputAdornmentPr
|
|
|
91
89
|
({ className, interactive, ...props }, ref) => (
|
|
92
90
|
<span
|
|
93
91
|
ref={ref}
|
|
94
|
-
className={
|
|
92
|
+
className={cn(
|
|
95
93
|
"inline-flex items-center justify-center flex-none text-foreground-muted px-[var(--space-1)] data-[interactive]:p-0",
|
|
96
94
|
className,
|
|
97
95
|
)}
|
|
@@ -112,7 +110,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
112
110
|
<input
|
|
113
111
|
ref={ref}
|
|
114
112
|
type={type}
|
|
115
|
-
className={
|
|
113
|
+
className={cn(
|
|
116
114
|
baseInputClasses,
|
|
117
115
|
inGroupOverrides,
|
|
118
116
|
!!prefix && "pl-[var(--space-10)]",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import "./styles.css";
|
|
5
5
|
|
|
6
|
+
import { cn } from "@SH_UI_UTILS@";
|
|
6
7
|
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "prefix"> {
|
|
7
8
|
/** input 우측에 부착할 보조 노드(아이콘·단위·버튼 등). 더 많은 슬롯이 필요하면 InputGroup 사용. */
|
|
8
9
|
suffix?: React.ReactNode;
|
|
@@ -10,9 +11,6 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
|
|
|
10
11
|
prefix?: React.ReactNode;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
function cx(...args: (string | undefined | null | false)[]) {
|
|
14
|
-
return args.filter(Boolean).join(" ");
|
|
15
|
-
}
|
|
16
14
|
|
|
17
15
|
/* ───────── InputGroup + InputAdornment (compound) ─────────
|
|
18
16
|
* <InputGroup>
|
|
@@ -87,7 +85,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
|
|
|
87
85
|
<InputGroupContext.Provider value={{ inGroup: true }}>
|
|
88
86
|
<div
|
|
89
87
|
ref={mergedRef}
|
|
90
|
-
className={
|
|
88
|
+
className={cn("sh-ui-input-group", className)}
|
|
91
89
|
data-disabled={disabled || undefined}
|
|
92
90
|
aria-invalid={ariaInvalid}
|
|
93
91
|
onClick={handleClick}
|
|
@@ -123,7 +121,7 @@ export const InputAdornment = React.forwardRef<
|
|
|
123
121
|
return (
|
|
124
122
|
<span
|
|
125
123
|
ref={ref}
|
|
126
|
-
className={
|
|
124
|
+
className={cn("sh-ui-input-group__adornment", className)}
|
|
127
125
|
data-interactive={interactive || undefined}
|
|
128
126
|
{...props}
|
|
129
127
|
/>
|
|
@@ -143,7 +141,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
143
141
|
<input
|
|
144
142
|
ref={ref}
|
|
145
143
|
type={type}
|
|
146
|
-
className={
|
|
144
|
+
className={cn(
|
|
147
145
|
"sh-ui-input",
|
|
148
146
|
!!prefix && "sh-ui-input--with-prefix",
|
|
149
147
|
!!suffix && "sh-ui-input--with-suffix",
|