@3w-witim/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,3739 @@
1
+ 'use strict';
2
+
3
+ var clsx = require('clsx');
4
+ var tailwindMerge = require('tailwind-merge');
5
+ var React16 = require('react');
6
+ var reactSlot = require('@radix-ui/react-slot');
7
+ var classVarianceAuthority = require('class-variance-authority');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+ var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
10
+
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n.default = e;
26
+ return Object.freeze(n);
27
+ }
28
+
29
+ var React16__namespace = /*#__PURE__*/_interopNamespace(React16);
30
+ var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPrimitive);
31
+
32
+ // src/utils.ts
33
+ function cn(...inputs) {
34
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
35
+ }
36
+ var buttonVariants = classVarianceAuthority.cva(
37
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded text-base font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-5 [&_svg]:shrink-0",
38
+ {
39
+ variants: {
40
+ variant: {
41
+ primary: "bg-brand-solid text-text-on-brand hover:bg-brand-solid-hover active:bg-brand-solid-pressed",
42
+ neutral: "border border-border-default bg-surface-default text-text-default hover:bg-surface-hover active:bg-surface-pressed",
43
+ ghost: "text-text-default hover:bg-surface-hover active:bg-surface-pressed",
44
+ danger: "bg-danger-solid text-text-on-brand hover:bg-danger-solid-hover",
45
+ "danger-outline": "border border-danger-border bg-transparent text-danger-text hover:bg-danger-subtle active:bg-danger-subtle"
46
+ },
47
+ size: {
48
+ sm: "h-9 px-3",
49
+ // 36px · px 12
50
+ md: "h-10 px-4",
51
+ // 40px · px 16 (기본)
52
+ lg: "h-12 px-5"
53
+ // 48px · px 20
54
+ }
55
+ },
56
+ defaultVariants: {
57
+ variant: "primary",
58
+ size: "md"
59
+ }
60
+ }
61
+ );
62
+ var Button = React16__namespace.forwardRef(
63
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
64
+ const Comp = asChild ? reactSlot.Slot : "button";
65
+ return /* @__PURE__ */ jsxRuntime.jsx(
66
+ Comp,
67
+ {
68
+ className: cn(buttonVariants({ variant, size, className })),
69
+ ref,
70
+ ...props
71
+ }
72
+ );
73
+ }
74
+ );
75
+ Button.displayName = "Button";
76
+ var inputVariants = classVarianceAuthority.cva(
77
+ "flex w-full items-center rounded border bg-surface-default text-text-default transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-text-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:cursor-not-allowed disabled:bg-surface-sunken disabled:text-text-disabled disabled:placeholder:text-text-disabled",
78
+ {
79
+ variants: {
80
+ state: {
81
+ default: "border-border-default hover:border-border-strong focus-visible:border-border-focus focus-visible:ring-brand-border",
82
+ error: "border-danger-border focus-visible:border-danger-border focus-visible:ring-danger-border"
83
+ },
84
+ inputSize: {
85
+ sm: "h-9 gap-1.5 px-2.5 text-sm",
86
+ md: "h-10 gap-2 px-3 text-base",
87
+ lg: "h-12 gap-2.5 px-3.5 text-base"
88
+ }
89
+ },
90
+ defaultVariants: {
91
+ state: "default",
92
+ inputSize: "md"
93
+ }
94
+ }
95
+ );
96
+ var Input = React16__namespace.forwardRef(
97
+ ({
98
+ className,
99
+ type = "text",
100
+ state,
101
+ inputSize,
102
+ startIcon,
103
+ endIcon,
104
+ helperText,
105
+ id,
106
+ "aria-describedby": ariaDescribedby,
107
+ ...props
108
+ }, ref) => {
109
+ const isError = state === "error";
110
+ const reactId = React16__namespace.useId();
111
+ const helperId = helperText ? `${id ?? reactId}-helper` : void 0;
112
+ const describedBy = [ariaDescribedby, helperId].filter(Boolean).join(" ") || void 0;
113
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full flex-col gap-1.5", children: [
114
+ /* @__PURE__ */ jsxRuntime.jsxs(
115
+ "div",
116
+ {
117
+ className: cn(
118
+ inputVariants({ state, inputSize }),
119
+ (startIcon || endIcon) && "cursor-text",
120
+ className
121
+ ),
122
+ children: [
123
+ startIcon ? /* @__PURE__ */ jsxRuntime.jsx(
124
+ "span",
125
+ {
126
+ "aria-hidden": "true",
127
+ className: cn(
128
+ "flex size-5 shrink-0 items-center justify-center [&_svg]:size-5",
129
+ isError ? "text-danger-text" : "text-text-subtle"
130
+ ),
131
+ children: startIcon
132
+ }
133
+ ) : null,
134
+ /* @__PURE__ */ jsxRuntime.jsx(
135
+ "input",
136
+ {
137
+ id: id ?? reactId,
138
+ type,
139
+ ref,
140
+ "aria-invalid": isError || void 0,
141
+ "aria-describedby": describedBy,
142
+ className: "h-full w-full min-w-0 bg-transparent outline-none placeholder:text-text-subtle disabled:cursor-not-allowed disabled:text-text-disabled",
143
+ ...props
144
+ }
145
+ ),
146
+ endIcon ? /* @__PURE__ */ jsxRuntime.jsx(
147
+ "span",
148
+ {
149
+ "aria-hidden": "true",
150
+ className: cn(
151
+ "flex size-5 shrink-0 items-center justify-center [&_svg]:size-5",
152
+ isError ? "text-danger-text" : "text-text-subtle"
153
+ ),
154
+ children: endIcon
155
+ }
156
+ ) : null
157
+ ]
158
+ }
159
+ ),
160
+ helperText ? /* @__PURE__ */ jsxRuntime.jsxs(
161
+ "p",
162
+ {
163
+ id: helperId,
164
+ className: cn(
165
+ "flex items-center gap-1 text-sm [&_svg]:size-4",
166
+ isError ? "text-danger-text" : "text-text-subtle"
167
+ ),
168
+ children: [
169
+ isError ? /* @__PURE__ */ jsxRuntime.jsx(
170
+ "svg",
171
+ {
172
+ "aria-hidden": "true",
173
+ viewBox: "0 0 20 20",
174
+ fill: "currentColor",
175
+ className: "shrink-0",
176
+ children: /* @__PURE__ */ jsxRuntime.jsx(
177
+ "path",
178
+ {
179
+ fillRule: "evenodd",
180
+ d: "M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm-.75-11.5a.75.75 0 0 1 1.5 0v4a.75.75 0 0 1-1.5 0v-4ZM10 14.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z",
181
+ clipRule: "evenodd"
182
+ }
183
+ )
184
+ }
185
+ ) : null,
186
+ helperText
187
+ ]
188
+ }
189
+ ) : null
190
+ ] });
191
+ }
192
+ );
193
+ Input.displayName = "Input";
194
+ var textareaVariants = classVarianceAuthority.cva(
195
+ "flex w-full resize-none rounded border bg-surface-default text-base text-text-default transition-colors placeholder:text-text-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:cursor-not-allowed disabled:opacity-50",
196
+ {
197
+ variants: {
198
+ state: {
199
+ default: "border-border-default focus-visible:border-border-focus focus-visible:ring-brand-border",
200
+ error: "border-danger-border focus-visible:border-danger-border focus-visible:ring-danger-border"
201
+ },
202
+ size: {
203
+ sm: "min-h-[64px] p-2 text-sm",
204
+ md: "min-h-[80px] p-3 text-base",
205
+ lg: "min-h-[120px] p-4 text-base"
206
+ }
207
+ },
208
+ defaultVariants: {
209
+ state: "default",
210
+ size: "md"
211
+ }
212
+ }
213
+ );
214
+ var Textarea = React16__namespace.forwardRef(
215
+ ({ className, state, size, "aria-invalid": ariaInvalid, ...props }, ref) => {
216
+ return /* @__PURE__ */ jsxRuntime.jsx(
217
+ "textarea",
218
+ {
219
+ ref,
220
+ "aria-invalid": ariaInvalid ?? (state === "error" ? true : void 0),
221
+ className: cn(textareaVariants({ state, size, className })),
222
+ ...props
223
+ }
224
+ );
225
+ }
226
+ );
227
+ Textarea.displayName = "Textarea";
228
+ var cardVariants = classVarianceAuthority.cva("rounded-lg text-text-default transition-colors", {
229
+ variants: {
230
+ variant: {
231
+ default: "border border-border-subtle bg-surface-default shadow-card",
232
+ raised: "border border-border-subtle bg-surface-raised shadow-md",
233
+ outline: "border border-border-default bg-transparent"
234
+ }
235
+ },
236
+ defaultVariants: {
237
+ variant: "default"
238
+ }
239
+ });
240
+ var Card = React16__namespace.forwardRef(
241
+ ({ className, variant, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
242
+ "div",
243
+ {
244
+ ref,
245
+ className: cn(cardVariants({ variant, className })),
246
+ ...props
247
+ }
248
+ )
249
+ );
250
+ Card.displayName = "Card";
251
+ var CardHeader = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
252
+ "div",
253
+ {
254
+ ref,
255
+ className: cn("flex flex-col gap-3 p-5", className),
256
+ ...props
257
+ }
258
+ ));
259
+ CardHeader.displayName = "CardHeader";
260
+ var CardTitle = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
261
+ "div",
262
+ {
263
+ ref,
264
+ className: cn(
265
+ "font-semibold leading-none tracking-tight text-text-strong",
266
+ className
267
+ ),
268
+ ...props
269
+ }
270
+ ));
271
+ CardTitle.displayName = "CardTitle";
272
+ var CardDescription = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
273
+ "div",
274
+ {
275
+ ref,
276
+ className: cn("text-sm text-text-subtle", className),
277
+ ...props
278
+ }
279
+ ));
280
+ CardDescription.displayName = "CardDescription";
281
+ var CardContent = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-5 pt-0", className), ...props }));
282
+ CardContent.displayName = "CardContent";
283
+ var CardFooter = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
284
+ "div",
285
+ {
286
+ ref,
287
+ className: cn("flex items-center gap-3 p-5 pt-0", className),
288
+ ...props
289
+ }
290
+ ));
291
+ CardFooter.displayName = "CardFooter";
292
+ var ScrollArea = React16__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
293
+ ScrollAreaPrimitive__namespace.Root,
294
+ {
295
+ ref,
296
+ className: cn("relative overflow-hidden", className),
297
+ ...props,
298
+ children: [
299
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollAreaPrimitive__namespace.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
300
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
301
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollAreaPrimitive__namespace.Corner, {})
302
+ ]
303
+ }
304
+ ));
305
+ ScrollArea.displayName = ScrollAreaPrimitive__namespace.Root.displayName;
306
+ var ScrollBar = React16__namespace.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
307
+ ScrollAreaPrimitive__namespace.ScrollAreaScrollbar,
308
+ {
309
+ ref,
310
+ orientation,
311
+ className: cn(
312
+ "flex touch-none select-none transition-colors",
313
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
314
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
315
+ className
316
+ ),
317
+ ...props,
318
+ children: /* @__PURE__ */ jsxRuntime.jsx(ScrollAreaPrimitive__namespace.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-slate-300 hover:bg-slate-400" })
319
+ }
320
+ ));
321
+ ScrollBar.displayName = ScrollAreaPrimitive__namespace.ScrollAreaScrollbar.displayName;
322
+ var labelVariants = classVarianceAuthority.cva(
323
+ "inline-flex items-center justify-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium whitespace-nowrap [&_svg]:pointer-events-none [&_svg]:size-3 [&_svg]:shrink-0",
324
+ {
325
+ variants: {
326
+ variant: {
327
+ brand: "bg-brand-subtle text-brand-text",
328
+ danger: "bg-danger-subtle text-danger-text",
329
+ neutral: "bg-[var(--comp-label-neutral-bg)] text-[var(--comp-label-neutral-text)]"
330
+ }
331
+ },
332
+ defaultVariants: {
333
+ variant: "neutral"
334
+ }
335
+ }
336
+ );
337
+ var Label = React16__namespace.forwardRef(
338
+ ({ className, variant, ...props }, ref) => {
339
+ return /* @__PURE__ */ jsxRuntime.jsx(
340
+ "span",
341
+ {
342
+ ref,
343
+ className: cn(labelVariants({ variant, className })),
344
+ ...props
345
+ }
346
+ );
347
+ }
348
+ );
349
+ Label.displayName = "Label";
350
+ var skeletonVariants = classVarianceAuthority.cva("animate-pulse bg-border-subtle", {
351
+ variants: {
352
+ variant: {
353
+ text: "rounded-lg h-4 w-full",
354
+ circle: "rounded-full",
355
+ rect: "rounded-lg"
356
+ }
357
+ },
358
+ defaultVariants: {
359
+ variant: "rect"
360
+ }
361
+ });
362
+ var Skeleton = React16__namespace.forwardRef(
363
+ ({ className, variant, ...props }, ref) => {
364
+ return /* @__PURE__ */ jsxRuntime.jsx(
365
+ "div",
366
+ {
367
+ ref,
368
+ role: "status",
369
+ "aria-busy": "true",
370
+ "aria-live": "polite",
371
+ "aria-label": "\uB85C\uB529 \uC911",
372
+ className: cn(skeletonVariants({ variant, className })),
373
+ ...props,
374
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "\uB85C\uB529 \uC911" })
375
+ }
376
+ );
377
+ }
378
+ );
379
+ Skeleton.displayName = "Skeleton";
380
+ var progressTrackVariants = classVarianceAuthority.cva(
381
+ "relative w-full overflow-hidden rounded-full bg-border-subtle",
382
+ {
383
+ variants: {
384
+ size: {
385
+ md: "h-1.5"
386
+ }
387
+ },
388
+ defaultVariants: {
389
+ size: "md"
390
+ }
391
+ }
392
+ );
393
+ var progressFillVariants = classVarianceAuthority.cva(
394
+ "h-full rounded-full bg-brand-solid transition-[width] duration-300 ease-out",
395
+ {
396
+ variants: {
397
+ indeterminate: {
398
+ true: "w-full animate-pulse rounded-full",
399
+ false: ""
400
+ }
401
+ },
402
+ defaultVariants: {
403
+ indeterminate: false
404
+ }
405
+ }
406
+ );
407
+ function clamp(value) {
408
+ if (Number.isNaN(value)) return 0;
409
+ return Math.min(100, Math.max(0, value));
410
+ }
411
+ var Progress = React16__namespace.forwardRef(
412
+ ({
413
+ className,
414
+ size,
415
+ value = 0,
416
+ indeterminate = false,
417
+ label = "Loading",
418
+ ...props
419
+ }, ref) => {
420
+ const pct = clamp(value);
421
+ return /* @__PURE__ */ jsxRuntime.jsx(
422
+ "div",
423
+ {
424
+ ref,
425
+ role: "progressbar",
426
+ "aria-label": label,
427
+ "aria-valuemin": indeterminate ? void 0 : 0,
428
+ "aria-valuemax": indeterminate ? void 0 : 100,
429
+ "aria-valuenow": indeterminate ? void 0 : pct,
430
+ "aria-valuetext": indeterminate ? "Loading" : `${pct}%`,
431
+ className: cn(progressTrackVariants({ size, className })),
432
+ ...props,
433
+ children: /* @__PURE__ */ jsxRuntime.jsx(
434
+ "div",
435
+ {
436
+ className: cn(progressFillVariants({ indeterminate })),
437
+ style: indeterminate ? void 0 : { width: `${pct}%` }
438
+ }
439
+ )
440
+ }
441
+ );
442
+ }
443
+ );
444
+ Progress.displayName = "Progress";
445
+ var checkboxVariants = classVarianceAuthority.cva(
446
+ "relative flex size-5 shrink-0 items-center justify-center rounded border-2 transition-colors peer-focus-visible:outline-none peer-focus-visible:ring-2 peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-bg-base peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
447
+ {
448
+ variants: {
449
+ state: {
450
+ default: "border-border-strong bg-surface-default peer-focus-visible:ring-border-focus peer-checked:border-brand-solid peer-checked:bg-brand-solid",
451
+ error: "border-danger-border bg-surface-default peer-focus-visible:ring-danger-solid peer-checked:border-danger-border peer-checked:bg-danger-solid"
452
+ }
453
+ },
454
+ defaultVariants: {
455
+ state: "default"
456
+ }
457
+ }
458
+ );
459
+ var CheckIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx(
460
+ "svg",
461
+ {
462
+ viewBox: "0 0 12 12",
463
+ fill: "none",
464
+ "aria-hidden": "true",
465
+ className: cn("size-3", className),
466
+ children: /* @__PURE__ */ jsxRuntime.jsx(
467
+ "path",
468
+ {
469
+ d: "M2.5 6.2 5 8.7l4.5-5",
470
+ stroke: "currentColor",
471
+ strokeWidth: 2,
472
+ strokeLinecap: "round",
473
+ strokeLinejoin: "round"
474
+ }
475
+ )
476
+ }
477
+ );
478
+ var Checkbox = React16__namespace.forwardRef(
479
+ ({ className, state, error, label, id, disabled, "aria-invalid": ariaInvalid, ...props }, ref) => {
480
+ const reactId = React16__namespace.useId();
481
+ const inputId = id ?? reactId;
482
+ const resolvedState = error ? "error" : state ?? "default";
483
+ const isInvalid = resolvedState === "error";
484
+ return /* @__PURE__ */ jsxRuntime.jsxs(
485
+ "label",
486
+ {
487
+ htmlFor: inputId,
488
+ className: cn(
489
+ "group inline-flex items-start gap-2 text-sm text-text-default",
490
+ disabled ? "cursor-not-allowed text-text-disabled" : "cursor-pointer"
491
+ ),
492
+ children: [
493
+ /* @__PURE__ */ jsxRuntime.jsx(
494
+ "input",
495
+ {
496
+ ref,
497
+ id: inputId,
498
+ type: "checkbox",
499
+ disabled,
500
+ "aria-invalid": ariaInvalid ?? (isInvalid || void 0),
501
+ className: "peer sr-only",
502
+ ...props
503
+ }
504
+ ),
505
+ /* @__PURE__ */ jsxRuntime.jsx(
506
+ "span",
507
+ {
508
+ className: cn(
509
+ checkboxVariants({ state: resolvedState }),
510
+ // 여러 줄 라벨에서 첫 줄 글자와 광학적으로 맞추기 위한 미세 보정(2px)
511
+ "mt-0.5 peer-checked:[&>svg]:opacity-100",
512
+ className
513
+ ),
514
+ children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-text-on-brand opacity-0 transition-opacity" })
515
+ }
516
+ ),
517
+ label != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "select-none", children: label })
518
+ ]
519
+ }
520
+ );
521
+ }
522
+ );
523
+ Checkbox.displayName = "Checkbox";
524
+ var RadioGroupContext = React16__namespace.createContext(
525
+ null
526
+ );
527
+ var RadioGroup = React16__namespace.forwardRef(
528
+ ({
529
+ className,
530
+ name,
531
+ value,
532
+ defaultValue,
533
+ onValueChange,
534
+ disabled,
535
+ error,
536
+ children,
537
+ ...props
538
+ }, ref) => {
539
+ const [internalValue, setInternalValue] = React16__namespace.useState(defaultValue);
540
+ const isControlled = value !== void 0;
541
+ const currentValue = isControlled ? value : internalValue;
542
+ const handleValueChange = React16__namespace.useCallback(
543
+ (next) => {
544
+ if (!isControlled) setInternalValue(next);
545
+ onValueChange?.(next);
546
+ },
547
+ [isControlled, onValueChange]
548
+ );
549
+ const ctx = React16__namespace.useMemo(
550
+ () => ({
551
+ name,
552
+ value: currentValue,
553
+ onValueChange: handleValueChange,
554
+ disabled,
555
+ error
556
+ }),
557
+ [name, currentValue, handleValueChange, disabled, error]
558
+ );
559
+ return /* @__PURE__ */ jsxRuntime.jsx(RadioGroupContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
560
+ "div",
561
+ {
562
+ ref,
563
+ role: "radiogroup",
564
+ "aria-invalid": error || void 0,
565
+ className: cn("flex flex-col gap-3", className),
566
+ ...props,
567
+ children
568
+ }
569
+ ) });
570
+ }
571
+ );
572
+ RadioGroup.displayName = "RadioGroup";
573
+ var radioVariants = classVarianceAuthority.cva(
574
+ "relative grid h-5 w-5 shrink-0 place-items-center rounded-full border-2 bg-surface-default transition-colors peer-focus-visible:outline-none peer-focus-visible:ring-2 peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-bg-base disabled:cursor-not-allowed",
575
+ {
576
+ variants: {
577
+ state: {
578
+ default: "border-border-strong peer-focus-visible:ring-border-focus peer-checked:border-brand-border",
579
+ error: "border-danger-border peer-focus-visible:ring-danger-solid peer-checked:border-danger-border"
580
+ }
581
+ },
582
+ defaultVariants: {
583
+ state: "default"
584
+ }
585
+ }
586
+ );
587
+ var radioDotVariants = classVarianceAuthority.cva(
588
+ "h-2 w-2 rounded-full scale-0 transition-transform peer-checked:scale-100",
589
+ {
590
+ variants: {
591
+ state: {
592
+ default: "bg-brand-solid",
593
+ error: "bg-danger-solid"
594
+ }
595
+ },
596
+ defaultVariants: {
597
+ state: "default"
598
+ }
599
+ }
600
+ );
601
+ var Radio = React16__namespace.forwardRef(
602
+ ({
603
+ className,
604
+ id,
605
+ value,
606
+ label,
607
+ description,
608
+ name: nameProp,
609
+ checked: checkedProp,
610
+ disabled: disabledProp,
611
+ error: errorProp,
612
+ onValueChange,
613
+ onChange,
614
+ onClick,
615
+ ...props
616
+ }, ref) => {
617
+ const group = React16__namespace.useContext(RadioGroupContext);
618
+ const reactId = React16__namespace.useId();
619
+ const inputId = id ?? reactId;
620
+ const isGroup = group != null;
621
+ const isControlled = checkedProp !== void 0;
622
+ const [internalChecked, setInternalChecked] = React16__namespace.useState(false);
623
+ const name = nameProp ?? group?.name;
624
+ const disabled = disabledProp ?? group?.disabled ?? false;
625
+ const error = errorProp ?? group?.error ?? false;
626
+ const checked = isControlled ? checkedProp : isGroup ? group.value === value : internalChecked;
627
+ const state = error ? "error" : "default";
628
+ const handleChange = (event) => {
629
+ onChange?.(event);
630
+ if (event.target.checked) {
631
+ onValueChange?.(value);
632
+ group?.onValueChange?.(value);
633
+ }
634
+ };
635
+ const handleClick = (event) => {
636
+ onClick?.(event);
637
+ if (!isControlled && !isGroup) {
638
+ setInternalChecked((prev) => !prev);
639
+ }
640
+ };
641
+ const control = /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex", children: [
642
+ /* @__PURE__ */ jsxRuntime.jsx(
643
+ "input",
644
+ {
645
+ ref,
646
+ id: inputId,
647
+ type: "radio",
648
+ name,
649
+ value,
650
+ checked,
651
+ disabled,
652
+ "aria-invalid": error || void 0,
653
+ onChange: handleChange,
654
+ onClick: handleClick,
655
+ className: "peer sr-only",
656
+ ...props
657
+ }
658
+ ),
659
+ /* @__PURE__ */ jsxRuntime.jsx(
660
+ "span",
661
+ {
662
+ "aria-hidden": "true",
663
+ className: cn(
664
+ radioVariants({ state }),
665
+ disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
666
+ )
667
+ }
668
+ ),
669
+ /* @__PURE__ */ jsxRuntime.jsx(
670
+ "span",
671
+ {
672
+ "aria-hidden": "true",
673
+ className: cn(
674
+ radioDotVariants({ state }),
675
+ "pointer-events-none absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2",
676
+ disabled && "opacity-50"
677
+ )
678
+ }
679
+ )
680
+ ] });
681
+ if (!label && !description) {
682
+ return control;
683
+ }
684
+ return /* @__PURE__ */ jsxRuntime.jsxs(
685
+ "label",
686
+ {
687
+ htmlFor: inputId,
688
+ className: cn(
689
+ "flex items-start gap-2",
690
+ disabled ? "cursor-not-allowed" : "cursor-pointer",
691
+ className
692
+ ),
693
+ children: [
694
+ control,
695
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col gap-0.5", children: [
696
+ label ? /* @__PURE__ */ jsxRuntime.jsx(
697
+ "span",
698
+ {
699
+ className: cn(
700
+ "text-sm leading-5",
701
+ disabled ? "text-text-disabled" : "text-text-default"
702
+ ),
703
+ children: label
704
+ }
705
+ ) : null,
706
+ description ? /* @__PURE__ */ jsxRuntime.jsx(
707
+ "span",
708
+ {
709
+ className: cn(
710
+ "text-xs leading-4",
711
+ error ? "text-danger-text" : "text-text-subtle"
712
+ ),
713
+ children: description
714
+ }
715
+ ) : null
716
+ ] })
717
+ ]
718
+ }
719
+ );
720
+ }
721
+ );
722
+ Radio.displayName = "Radio";
723
+ var toggleTrackVariants = classVarianceAuthority.cva(
724
+ "relative inline-flex shrink-0 cursor-pointer items-center rounded-full p-0.5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:cursor-not-allowed disabled:opacity-50 data-[state=off]:bg-surface-sunken data-[state=on]:bg-brand-solid",
725
+ {
726
+ variants: {
727
+ size: {
728
+ sm: "h-5 w-9",
729
+ md: "h-6 w-11"
730
+ }
731
+ },
732
+ defaultVariants: {
733
+ size: "md"
734
+ }
735
+ }
736
+ );
737
+ var toggleThumbVariants = classVarianceAuthority.cva(
738
+ "pointer-events-none block rounded-full bg-surface-default shadow-sm transition-transform data-[state=off]:translate-x-0",
739
+ {
740
+ variants: {
741
+ size: {
742
+ sm: "h-4 w-4 data-[state=on]:translate-x-4",
743
+ md: "h-5 w-5 data-[state=on]:translate-x-5"
744
+ }
745
+ },
746
+ defaultVariants: {
747
+ size: "md"
748
+ }
749
+ }
750
+ );
751
+ var Toggle = React16__namespace.forwardRef(
752
+ ({
753
+ className,
754
+ size,
755
+ checked,
756
+ defaultChecked = false,
757
+ onCheckedChange,
758
+ disabled,
759
+ onClick,
760
+ ...props
761
+ }, ref) => {
762
+ const isControlled = checked !== void 0;
763
+ const [internalChecked, setInternalChecked] = React16__namespace.useState(defaultChecked);
764
+ const isOn = isControlled ? checked : internalChecked;
765
+ const state = isOn ? "on" : "off";
766
+ const handleClick = (event) => {
767
+ onClick?.(event);
768
+ if (event.defaultPrevented || disabled) return;
769
+ const next = !isOn;
770
+ if (!isControlled) setInternalChecked(next);
771
+ onCheckedChange?.(next);
772
+ };
773
+ return /* @__PURE__ */ jsxRuntime.jsx(
774
+ "button",
775
+ {
776
+ ref,
777
+ type: "button",
778
+ role: "switch",
779
+ "aria-checked": isOn,
780
+ "data-state": state,
781
+ disabled,
782
+ onClick: handleClick,
783
+ className: cn(toggleTrackVariants({ size, className })),
784
+ ...props,
785
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-state": state, className: cn(toggleThumbVariants({ size })) })
786
+ }
787
+ );
788
+ }
789
+ );
790
+ Toggle.displayName = "Toggle";
791
+ var chipVariants = classVarianceAuthority.cva(
792
+ "inline-flex h-8 items-center gap-1 rounded border px-3 text-sm font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
793
+ {
794
+ variants: {
795
+ variant: {
796
+ default: "border-border-default bg-surface-default text-text-default hover:bg-surface-hover active:bg-surface-pressed",
797
+ selected: "border-brand-border bg-brand-subtle text-brand-text font-bold hover:bg-brand-subtle active:bg-brand-subtle"
798
+ }
799
+ },
800
+ defaultVariants: {
801
+ variant: "default"
802
+ }
803
+ }
804
+ );
805
+ var CheckIcon2 = () => /* @__PURE__ */ jsxRuntime.jsx(
806
+ "svg",
807
+ {
808
+ viewBox: "0 0 16 16",
809
+ fill: "none",
810
+ stroke: "currentColor",
811
+ strokeWidth: "2",
812
+ strokeLinecap: "round",
813
+ strokeLinejoin: "round",
814
+ "aria-hidden": "true",
815
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M13 4.5 6.5 11.5 3 8" })
816
+ }
817
+ );
818
+ var CloseIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
819
+ "svg",
820
+ {
821
+ viewBox: "0 0 16 16",
822
+ fill: "none",
823
+ stroke: "currentColor",
824
+ strokeWidth: "2",
825
+ strokeLinecap: "round",
826
+ strokeLinejoin: "round",
827
+ "aria-hidden": "true",
828
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4l8 8M12 4l-8 8" })
829
+ }
830
+ );
831
+ var Chip = React16__namespace.forwardRef(
832
+ ({
833
+ className,
834
+ variant,
835
+ showSelectedIcon = false,
836
+ removable = false,
837
+ onRemove,
838
+ removeLabel = "Remove",
839
+ children,
840
+ disabled,
841
+ ...props
842
+ }, ref) => {
843
+ return /* @__PURE__ */ jsxRuntime.jsxs(
844
+ "button",
845
+ {
846
+ type: "button",
847
+ ref,
848
+ disabled,
849
+ "aria-pressed": variant === "selected",
850
+ className: cn(chipVariants({ variant }), removable && "pr-2", className),
851
+ ...props,
852
+ children: [
853
+ showSelectedIcon && variant === "selected" ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon2, {}) : null,
854
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }),
855
+ removable ? /* @__PURE__ */ jsxRuntime.jsx(
856
+ "span",
857
+ {
858
+ role: "button",
859
+ "aria-label": removeLabel,
860
+ tabIndex: disabled ? -1 : 0,
861
+ onClick: (e) => {
862
+ e.stopPropagation();
863
+ if (!disabled) onRemove?.();
864
+ },
865
+ onKeyDown: (e) => {
866
+ if (e.key === "Enter" || e.key === " ") {
867
+ e.preventDefault();
868
+ e.stopPropagation();
869
+ if (!disabled) onRemove?.();
870
+ }
871
+ },
872
+ className: "-mr-1 ml-0.5 inline-flex size-4 items-center justify-center rounded-full text-text-subtle transition-colors hover:bg-surface-hover hover:text-text-default focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base",
873
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
874
+ }
875
+ ) : null
876
+ ]
877
+ }
878
+ );
879
+ }
880
+ );
881
+ Chip.displayName = "Chip";
882
+ var alertVariants = classVarianceAuthority.cva(
883
+ "relative flex gap-3 rounded-lg border p-3 [&>svg]:size-5 [&>svg]:shrink-0 [&>svg]:mt-0.5",
884
+ {
885
+ variants: {
886
+ variant: {
887
+ info: "bg-surface-sunken border-border-default text-text-default [&>svg]:text-text-subtle",
888
+ danger: "bg-danger-subtle border-danger-border text-danger-text [&>svg]:text-danger-text"
889
+ }
890
+ },
891
+ defaultVariants: {
892
+ variant: "info"
893
+ }
894
+ }
895
+ );
896
+ var Alert = React16__namespace.forwardRef(
897
+ ({ className, variant, role = "alert", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
898
+ "div",
899
+ {
900
+ ref,
901
+ role,
902
+ className: cn(alertVariants({ variant, className })),
903
+ ...props
904
+ }
905
+ )
906
+ );
907
+ Alert.displayName = "Alert";
908
+ var AlertTitle = React16__namespace.forwardRef(
909
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
910
+ "p",
911
+ {
912
+ ref,
913
+ className: cn(
914
+ "text-sm font-semibold leading-5 text-text-strong",
915
+ className
916
+ ),
917
+ ...props
918
+ }
919
+ )
920
+ );
921
+ AlertTitle.displayName = "AlertTitle";
922
+ var AlertDescription = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
923
+ "p",
924
+ {
925
+ ref,
926
+ className: cn("mt-1 text-sm leading-5 [&_p]:leading-5", className),
927
+ ...props
928
+ }
929
+ ));
930
+ AlertDescription.displayName = "AlertDescription";
931
+ var SIZE_PX = { sm: 12, md: 16, lg: 20 };
932
+ var PRESENCE_LABEL = {
933
+ online: "\uC628\uB77C\uC778",
934
+ away: "\uC790\uB9AC\uBE44\uC6C0",
935
+ offline: "\uC624\uD504\uB77C\uC778",
936
+ remote: "\uC7AC\uD0DD"
937
+ };
938
+ function HouseMark({ px }) {
939
+ const s = Math.round(px * 0.64);
940
+ return /* @__PURE__ */ jsxRuntime.jsx(
941
+ "svg",
942
+ {
943
+ width: s,
944
+ height: s,
945
+ viewBox: "0 0 24 24",
946
+ fill: "currentColor",
947
+ "aria-hidden": true,
948
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3 4 9v12h5v-7h6v7h5V9z" })
949
+ }
950
+ );
951
+ }
952
+ function Presence({
953
+ status = "online",
954
+ size = "md",
955
+ className,
956
+ ...props
957
+ }) {
958
+ const px = SIZE_PX[size];
959
+ const label = PRESENCE_LABEL[status];
960
+ const base = "inline-flex shrink-0 items-center justify-center rounded-full font-extrabold leading-none";
961
+ const STATUS_STYLE = {
962
+ online: "bg-brand-solid text-text-on-brand",
963
+ away: "bg-presence-away-bg text-presence-away-fg",
964
+ offline: "bg-presence-offline",
965
+ remote: "bg-brand-solid text-text-on-brand"
966
+ };
967
+ return /* @__PURE__ */ jsxRuntime.jsxs(
968
+ "span",
969
+ {
970
+ role: "img",
971
+ "aria-label": label,
972
+ title: label,
973
+ className: cn(base, STATUS_STYLE[status], className),
974
+ style: { width: px, height: px, fontSize: Math.round(px * 0.58) },
975
+ ...props,
976
+ children: [
977
+ status === "away" && "Z",
978
+ status === "remote" && /* @__PURE__ */ jsxRuntime.jsx(HouseMark, { px })
979
+ ]
980
+ }
981
+ );
982
+ }
983
+ var avatarVariants = classVarianceAuthority.cva(
984
+ "relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-surface-sunken align-middle ring-2 ring-border-subtle select-none",
985
+ {
986
+ variants: {
987
+ size: {
988
+ xs: "h-6 w-6 text-[10px]",
989
+ // 24px
990
+ sm: "h-8 w-8 text-sm",
991
+ // 32px · font14 기본
992
+ md: "h-10 w-10 text-base",
993
+ // 40px
994
+ lg: "h-12 w-12 text-lg",
995
+ // 48px
996
+ xl: "h-16 w-16 text-2xl"
997
+ // 64px
998
+ }
999
+ },
1000
+ defaultVariants: {
1001
+ size: "sm"
1002
+ }
1003
+ }
1004
+ );
1005
+ var presenceSizeForAvatar = {
1006
+ xs: "sm",
1007
+ sm: "sm",
1008
+ md: "md",
1009
+ lg: "md",
1010
+ xl: "lg"
1011
+ };
1012
+ var MASCOTS = {};
1013
+ try {
1014
+ MASCOTS = undefined(
1015
+ "../../design-system/avatars/avatar-mascot-*.svg",
1016
+ { query: "?url", import: "default", eager: true }
1017
+ );
1018
+ } catch {
1019
+ MASCOTS = {};
1020
+ }
1021
+ var MASCOT_BY_COLOR = {};
1022
+ for (const [path, url] of Object.entries(MASCOTS)) {
1023
+ const m = path.match(/avatar-mascot-([a-z]+)\.svg$/);
1024
+ if (m) MASCOT_BY_COLOR[m[1]] = url;
1025
+ }
1026
+ var AVATAR_COLORS = Object.keys(
1027
+ MASCOT_BY_COLOR
1028
+ ).sort();
1029
+ function defaultColor(seed) {
1030
+ if (AVATAR_COLORS.length === 0) return "gray";
1031
+ const s = seed ?? "";
1032
+ let h = 0;
1033
+ for (let i = 0; i < s.length; i++) h = h * 31 + s.charCodeAt(i) >>> 0;
1034
+ return AVATAR_COLORS[h % AVATAR_COLORS.length];
1035
+ }
1036
+ function mascotUrl(color, seed) {
1037
+ const c = color ?? defaultColor(seed);
1038
+ return MASCOT_BY_COLOR[c] ?? MASCOT_BY_COLOR[AVATAR_COLORS[0]] ?? "";
1039
+ }
1040
+ function MascotImage({
1041
+ color,
1042
+ seed,
1043
+ alt
1044
+ }) {
1045
+ return /* @__PURE__ */ jsxRuntime.jsx(
1046
+ "img",
1047
+ {
1048
+ src: mascotUrl(color, seed),
1049
+ alt: alt ?? "",
1050
+ "aria-hidden": alt ? void 0 : true,
1051
+ className: "h-full w-full object-cover"
1052
+ }
1053
+ );
1054
+ }
1055
+ var Avatar = React16__namespace.forwardRef(
1056
+ ({ className, size = "sm", src, alt, color, presence, children, ...props }, ref) => {
1057
+ const resolvedSize = size ?? "sm";
1058
+ return (
1059
+ // presence badge가 원 밖으로 걸치도록 wrapper(relative)에 이미지 원 + badge를 형제로 배치.
1060
+ /* @__PURE__ */ jsxRuntime.jsxs(
1061
+ "span",
1062
+ {
1063
+ ref,
1064
+ className: cn("relative inline-flex shrink-0 align-middle", className),
1065
+ ...props,
1066
+ children: [
1067
+ /* @__PURE__ */ jsxRuntime.jsx(
1068
+ "span",
1069
+ {
1070
+ className: cn(
1071
+ avatarVariants({ size }),
1072
+ // 가이드: 오프라인이면 아바타를 흐리게(opacity .55)
1073
+ presence === "offline" && "opacity-[.55]"
1074
+ ),
1075
+ children: children ?? (src ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src, alt, color, seed: alt }) : (
1076
+ // 기본: 무조건 마스코트 이미지. color 선택 시 그 색, 없으면 이름 기반 기본값.
1077
+ /* @__PURE__ */ jsxRuntime.jsx(MascotImage, { color, seed: alt, alt })
1078
+ ))
1079
+ }
1080
+ ),
1081
+ presence ? /* @__PURE__ */ jsxRuntime.jsx(
1082
+ Presence,
1083
+ {
1084
+ status: presence,
1085
+ size: presenceSizeForAvatar[resolvedSize],
1086
+ className: "absolute -bottom-0.5 -right-0.5 ring-2 ring-bg-base"
1087
+ }
1088
+ ) : null
1089
+ ]
1090
+ }
1091
+ )
1092
+ );
1093
+ }
1094
+ );
1095
+ Avatar.displayName = "Avatar";
1096
+ var AvatarImage = React16__namespace.forwardRef(
1097
+ ({ className, alt = "", color, seed, ...props }, ref) => {
1098
+ const [errored, setErrored] = React16__namespace.useState(false);
1099
+ if (errored) {
1100
+ return /* @__PURE__ */ jsxRuntime.jsx(MascotImage, { color, seed: seed ?? alt, alt });
1101
+ }
1102
+ return /* @__PURE__ */ jsxRuntime.jsx(
1103
+ "img",
1104
+ {
1105
+ ref,
1106
+ alt,
1107
+ className: cn("h-full w-full object-cover", className),
1108
+ onError: () => setErrored(true),
1109
+ ...props
1110
+ }
1111
+ );
1112
+ }
1113
+ );
1114
+ AvatarImage.displayName = "AvatarImage";
1115
+ var AvatarFallback = React16__namespace.forwardRef(
1116
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1117
+ "span",
1118
+ {
1119
+ ref,
1120
+ className: cn(
1121
+ "flex h-full w-full items-center justify-center bg-surface-sunken font-medium text-text-subtle",
1122
+ className
1123
+ ),
1124
+ ...props
1125
+ }
1126
+ )
1127
+ );
1128
+ AvatarFallback.displayName = "AvatarFallback";
1129
+ var AvatarGroup = React16__namespace.forwardRef(
1130
+ ({ className, children, max, size = "sm", ...props }, ref) => {
1131
+ const items = React16__namespace.Children.toArray(children).filter(React16__namespace.isValidElement);
1132
+ const visible = typeof max === "number" ? items.slice(0, max) : items;
1133
+ const overflow = items.length - visible.length;
1134
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex items-center", className), ...props, children: [
1135
+ visible.map((child, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: i === 0 ? "" : "-ml-2", children: child }, i)),
1136
+ overflow > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
1137
+ "span",
1138
+ {
1139
+ className: cn(
1140
+ avatarVariants({ size }),
1141
+ "-ml-2 font-medium text-text-subtle"
1142
+ ),
1143
+ "aria-label": `\uC678 ${overflow}\uBA85`,
1144
+ title: `\uC678 ${overflow}\uBA85`,
1145
+ children: [
1146
+ "+",
1147
+ overflow
1148
+ ]
1149
+ }
1150
+ ) : null
1151
+ ] });
1152
+ }
1153
+ );
1154
+ AvatarGroup.displayName = "AvatarGroup";
1155
+ var tooltipContentVariants = classVarianceAuthority.cva(
1156
+ "pointer-events-none absolute z-50 w-max max-w-xs whitespace-normal rounded bg-[var(--comp-tooltip-bg)] px-2 py-1 text-xs font-medium text-[var(--comp-tooltip-text)] shadow-popover",
1157
+ {
1158
+ variants: {
1159
+ placement: {
1160
+ top: "bottom-full left-1/2 mb-2 -translate-x-1/2",
1161
+ "top-left": "bottom-full left-0 mb-2",
1162
+ "top-right": "bottom-full right-0 mb-2",
1163
+ right: "left-full top-1/2 ml-2 -translate-y-1/2",
1164
+ bottom: "top-full left-1/2 mt-2 -translate-x-1/2",
1165
+ "bottom-left": "top-full left-0 mt-2",
1166
+ "bottom-right": "top-full right-0 mt-2",
1167
+ left: "right-full top-1/2 mr-2 -translate-y-1/2"
1168
+ }
1169
+ },
1170
+ defaultVariants: {
1171
+ placement: "top"
1172
+ }
1173
+ }
1174
+ );
1175
+ var tooltipArrowVariants = classVarianceAuthority.cva(
1176
+ "pointer-events-none absolute z-50 h-2 w-2 rotate-45 bg-[var(--comp-tooltip-bg)]",
1177
+ {
1178
+ variants: {
1179
+ placement: {
1180
+ top: "bottom-full left-1/2 -translate-x-1/2 mb-[5px]",
1181
+ "top-left": "bottom-full left-1/2 -translate-x-1/2 mb-[5px]",
1182
+ "top-right": "bottom-full left-1/2 -translate-x-1/2 mb-[5px]",
1183
+ right: "left-full top-1/2 -translate-y-1/2 ml-[5px]",
1184
+ bottom: "top-full left-1/2 -translate-x-1/2 mt-[5px]",
1185
+ "bottom-left": "top-full left-1/2 -translate-x-1/2 mt-[5px]",
1186
+ "bottom-right": "top-full left-1/2 -translate-x-1/2 mt-[5px]",
1187
+ left: "right-full top-1/2 -translate-y-1/2 mr-[5px]"
1188
+ }
1189
+ },
1190
+ defaultVariants: {
1191
+ placement: "top"
1192
+ }
1193
+ }
1194
+ );
1195
+ var Tooltip = React16__namespace.forwardRef(
1196
+ ({
1197
+ className,
1198
+ content,
1199
+ children,
1200
+ placement = "top",
1201
+ open,
1202
+ arrow = true,
1203
+ disabled = false,
1204
+ ...props
1205
+ }, ref) => {
1206
+ const [hovered, setHovered] = React16__namespace.useState(false);
1207
+ const isControlled = open !== void 0;
1208
+ const visible = !disabled && (isControlled ? open : hovered);
1209
+ const tooltipId = React16__namespace.useId();
1210
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1211
+ "div",
1212
+ {
1213
+ ref,
1214
+ className: cn("relative inline-flex", className),
1215
+ onMouseEnter: isControlled ? void 0 : () => setHovered(true),
1216
+ onMouseLeave: isControlled ? void 0 : () => setHovered(false),
1217
+ onFocus: isControlled ? void 0 : () => setHovered(true),
1218
+ onBlur: isControlled ? void 0 : () => setHovered(false),
1219
+ ...props,
1220
+ children: [
1221
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-describedby": visible ? tooltipId : void 0, children }),
1222
+ /* @__PURE__ */ jsxRuntime.jsx(
1223
+ "div",
1224
+ {
1225
+ id: tooltipId,
1226
+ role: "tooltip",
1227
+ "aria-hidden": !visible,
1228
+ className: cn(
1229
+ tooltipContentVariants({ placement }),
1230
+ "transition-opacity duration-150",
1231
+ visible ? "opacity-100" : "opacity-0"
1232
+ ),
1233
+ children: content
1234
+ }
1235
+ ),
1236
+ arrow ? /* @__PURE__ */ jsxRuntime.jsx(
1237
+ "span",
1238
+ {
1239
+ "aria-hidden": true,
1240
+ className: cn(
1241
+ tooltipArrowVariants({ placement }),
1242
+ "transition-opacity duration-150",
1243
+ visible ? "opacity-100" : "opacity-0"
1244
+ )
1245
+ }
1246
+ ) : null
1247
+ ]
1248
+ }
1249
+ );
1250
+ }
1251
+ );
1252
+ Tooltip.displayName = "Tooltip";
1253
+ var DropdownMenuContext = React16__namespace.createContext(null);
1254
+ function useDropdownMenuContext(component) {
1255
+ const ctx = React16__namespace.useContext(DropdownMenuContext);
1256
+ if (!ctx) {
1257
+ throw new Error(`${component} must be used within <DropdownMenu>`);
1258
+ }
1259
+ return ctx;
1260
+ }
1261
+ var DropdownMenu = React16__namespace.forwardRef(
1262
+ ({ className, open: openProp, defaultOpen = false, onOpenChange, ...props }, ref) => {
1263
+ const [uncontrolledOpen, setUncontrolledOpen] = React16__namespace.useState(defaultOpen);
1264
+ const isControlled = openProp !== void 0;
1265
+ const open = isControlled ? openProp : uncontrolledOpen;
1266
+ const setOpen = React16__namespace.useCallback(
1267
+ (value) => {
1268
+ const next = typeof value === "function" ? value(open) : value;
1269
+ if (!isControlled) setUncontrolledOpen(next);
1270
+ onOpenChange?.(next);
1271
+ },
1272
+ [isControlled, onOpenChange, open]
1273
+ );
1274
+ const ctx = React16__namespace.useMemo(() => ({ open, setOpen }), [open, setOpen]);
1275
+ return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
1276
+ "div",
1277
+ {
1278
+ ref,
1279
+ className: cn("relative inline-block text-left", className),
1280
+ ...props
1281
+ }
1282
+ ) });
1283
+ }
1284
+ );
1285
+ DropdownMenu.displayName = "DropdownMenu";
1286
+ var DropdownMenuTrigger = React16__namespace.forwardRef(({ className, onClick, disabled, ...props }, ref) => {
1287
+ const { open, setOpen } = useDropdownMenuContext("DropdownMenuTrigger");
1288
+ return /* @__PURE__ */ jsxRuntime.jsx(
1289
+ "button",
1290
+ {
1291
+ ref,
1292
+ type: "button",
1293
+ "aria-haspopup": "menu",
1294
+ "aria-expanded": open,
1295
+ disabled,
1296
+ onClick: (event) => {
1297
+ onClick?.(event);
1298
+ if (!event.defaultPrevented) setOpen((prev) => !prev);
1299
+ },
1300
+ className: cn(
1301
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded border border-border-default bg-surface-default px-4 py-2 text-sm font-medium text-text-default transition-colors hover:bg-surface-hover active:bg-surface-pressed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1302
+ className
1303
+ ),
1304
+ ...props
1305
+ }
1306
+ );
1307
+ });
1308
+ DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
1309
+ var dropdownMenuContentVariants = classVarianceAuthority.cva(
1310
+ // panel padding 4 · radius sm(8) · min-w 180 · shadow-dropdown
1311
+ "z-50 min-w-[180px] rounded-lg border border-border-subtle bg-surface-raised p-1 shadow-dropdown outline-none",
1312
+ {
1313
+ variants: {
1314
+ align: {
1315
+ start: "left-0",
1316
+ end: "right-0"
1317
+ }
1318
+ },
1319
+ defaultVariants: {
1320
+ align: "start"
1321
+ }
1322
+ }
1323
+ );
1324
+ var DropdownMenuContent = React16__namespace.forwardRef(({ className, align, forceMount = false, ...props }, ref) => {
1325
+ const { open } = useDropdownMenuContext("DropdownMenuContent");
1326
+ if (!open && !forceMount) return null;
1327
+ return /* @__PURE__ */ jsxRuntime.jsx(
1328
+ "div",
1329
+ {
1330
+ ref,
1331
+ role: "menu",
1332
+ "aria-orientation": "vertical",
1333
+ className: cn(
1334
+ "absolute top-[calc(100%+4px)]",
1335
+ dropdownMenuContentVariants({ align, className })
1336
+ ),
1337
+ ...props
1338
+ }
1339
+ );
1340
+ });
1341
+ DropdownMenuContent.displayName = "DropdownMenuContent";
1342
+ var dropdownMenuItemVariants = classVarianceAuthority.cva(
1343
+ // item px12 py8 · item radius xs(4) · hover bg-surface-hover
1344
+ "relative flex w-full cursor-pointer select-none items-center gap-2 rounded px-3 py-2 text-sm text-text-default outline-none transition-colors hover:bg-surface-hover focus-visible:bg-surface-hover focus-visible:outline-none data-[disabled=true]:pointer-events-none data-[disabled=true]:text-text-disabled data-[disabled=true]:opacity-60 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1345
+ {
1346
+ variants: {
1347
+ variant: {
1348
+ default: "",
1349
+ danger: "text-danger-text hover:bg-danger-subtle focus-visible:bg-danger-subtle"
1350
+ }
1351
+ },
1352
+ defaultVariants: {
1353
+ variant: "default"
1354
+ }
1355
+ }
1356
+ );
1357
+ var DropdownMenuItem = React16__namespace.forwardRef(
1358
+ ({
1359
+ className,
1360
+ variant,
1361
+ disabled = false,
1362
+ icon,
1363
+ trailing,
1364
+ children,
1365
+ ...props
1366
+ }, ref) => {
1367
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1368
+ "button",
1369
+ {
1370
+ ref,
1371
+ type: "button",
1372
+ role: "menuitem",
1373
+ "aria-disabled": disabled || void 0,
1374
+ "data-disabled": disabled,
1375
+ tabIndex: disabled ? -1 : 0,
1376
+ className: cn(dropdownMenuItemVariants({ variant, className })),
1377
+ ...props,
1378
+ children: [
1379
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: icon }) : null,
1380
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate text-left", children }),
1381
+ trailing ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 text-xs text-text-subtle", children: trailing }) : null
1382
+ ]
1383
+ }
1384
+ );
1385
+ }
1386
+ );
1387
+ DropdownMenuItem.displayName = "DropdownMenuItem";
1388
+ var DropdownMenuLabel = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1389
+ "div",
1390
+ {
1391
+ ref,
1392
+ className: cn(
1393
+ "px-3 py-2 text-xs font-semibold uppercase tracking-wide text-text-subtle",
1394
+ className
1395
+ ),
1396
+ ...props
1397
+ }
1398
+ ));
1399
+ DropdownMenuLabel.displayName = "DropdownMenuLabel";
1400
+ var DropdownMenuSeparator = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1401
+ "div",
1402
+ {
1403
+ ref,
1404
+ role: "separator",
1405
+ "aria-orientation": "horizontal",
1406
+ className: cn("my-1 h-px bg-border-subtle", className),
1407
+ ...props
1408
+ }
1409
+ ));
1410
+ DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
1411
+ var DropdownMenuEmpty = React16__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1412
+ "div",
1413
+ {
1414
+ ref,
1415
+ className: cn("px-3 py-6 text-center text-sm text-text-subtle", className),
1416
+ ...props,
1417
+ children: children ?? "No items"
1418
+ }
1419
+ ));
1420
+ DropdownMenuEmpty.displayName = "DropdownMenuEmpty";
1421
+ var selectTriggerVariants = classVarianceAuthority.cva(
1422
+ "flex h-10 w-full items-center justify-between gap-2 rounded border bg-surface-default px-3 text-sm text-text-default transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:cursor-not-allowed disabled:bg-surface-sunken disabled:text-text-disabled",
1423
+ {
1424
+ variants: {
1425
+ state: {
1426
+ default: "border-border-default hover:border-border-strong focus-visible:ring-brand-border",
1427
+ error: "border-danger-border focus-visible:ring-danger-border"
1428
+ }
1429
+ },
1430
+ defaultVariants: {
1431
+ state: "default"
1432
+ }
1433
+ }
1434
+ );
1435
+ var ChevronIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx(
1436
+ "svg",
1437
+ {
1438
+ width: 20,
1439
+ height: 20,
1440
+ viewBox: "0 0 20 20",
1441
+ fill: "none",
1442
+ stroke: "currentColor",
1443
+ strokeWidth: 1.5,
1444
+ strokeLinecap: "round",
1445
+ strokeLinejoin: "round",
1446
+ "aria-hidden": "true",
1447
+ className,
1448
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 7.5 10 12.5 15 7.5" })
1449
+ }
1450
+ );
1451
+ var CheckIcon3 = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx(
1452
+ "svg",
1453
+ {
1454
+ width: 20,
1455
+ height: 20,
1456
+ viewBox: "0 0 20 20",
1457
+ fill: "none",
1458
+ stroke: "currentColor",
1459
+ strokeWidth: 1.5,
1460
+ strokeLinecap: "round",
1461
+ strokeLinejoin: "round",
1462
+ "aria-hidden": "true",
1463
+ className,
1464
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m4.5 10.5 3.5 3.5 7.5-8" })
1465
+ }
1466
+ );
1467
+ var Select = React16__namespace.forwardRef(
1468
+ ({
1469
+ className,
1470
+ state,
1471
+ options,
1472
+ value,
1473
+ placeholder = "\uC120\uD0DD\uD558\uC138\uC694",
1474
+ onValueChange,
1475
+ disabled = false,
1476
+ defaultOpen = false,
1477
+ errorMessageId,
1478
+ "aria-label": ariaLabel,
1479
+ ...props
1480
+ }, ref) => {
1481
+ const [open, setOpen] = React16__namespace.useState(defaultOpen);
1482
+ const selected = React16__namespace.useMemo(
1483
+ () => options.find((o) => o.value === value),
1484
+ [options, value]
1485
+ );
1486
+ const isError = state === "error";
1487
+ const handleSelect = (option) => {
1488
+ if (option.disabled) return;
1489
+ onValueChange?.(option.value);
1490
+ setOpen(false);
1491
+ };
1492
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("relative w-full", className), ...props, children: [
1493
+ /* @__PURE__ */ jsxRuntime.jsxs(
1494
+ "button",
1495
+ {
1496
+ type: "button",
1497
+ disabled,
1498
+ "aria-haspopup": "listbox",
1499
+ "aria-expanded": open,
1500
+ "aria-invalid": isError || void 0,
1501
+ "aria-describedby": isError ? errorMessageId : void 0,
1502
+ "aria-label": ariaLabel,
1503
+ onClick: () => setOpen((o) => !o),
1504
+ className: cn(selectTriggerVariants({ state })),
1505
+ children: [
1506
+ /* @__PURE__ */ jsxRuntime.jsx(
1507
+ "span",
1508
+ {
1509
+ className: cn(
1510
+ "truncate",
1511
+ !selected && "text-text-subtle"
1512
+ ),
1513
+ children: selected ? selected.label : placeholder
1514
+ }
1515
+ ),
1516
+ /* @__PURE__ */ jsxRuntime.jsx(
1517
+ ChevronIcon,
1518
+ {
1519
+ className: cn(
1520
+ "shrink-0 text-text-subtle transition-transform",
1521
+ open && "rotate-180"
1522
+ )
1523
+ }
1524
+ )
1525
+ ]
1526
+ }
1527
+ ),
1528
+ open && !disabled && /* @__PURE__ */ jsxRuntime.jsxs(
1529
+ "ul",
1530
+ {
1531
+ role: "listbox",
1532
+ "aria-label": ariaLabel,
1533
+ className: "absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded border border-border-subtle bg-surface-raised p-1 shadow-dropdown",
1534
+ children: [
1535
+ options.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-sm text-text-subtle", children: "\uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" }),
1536
+ options.map((option) => {
1537
+ const isSelected = option.value === value;
1538
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1539
+ "li",
1540
+ {
1541
+ role: "option",
1542
+ "aria-selected": isSelected,
1543
+ "aria-disabled": option.disabled || void 0,
1544
+ onClick: () => handleSelect(option),
1545
+ className: cn(
1546
+ "flex items-center justify-between gap-2 rounded px-3 py-2 text-sm text-text-default",
1547
+ option.disabled ? "cursor-not-allowed text-text-disabled" : "cursor-pointer hover:bg-surface-hover active:bg-surface-pressed",
1548
+ isSelected && "bg-brand-subtle text-brand-text"
1549
+ ),
1550
+ children: [
1551
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: option.label }),
1552
+ isSelected && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon3, { className: "shrink-0 text-brand-text" })
1553
+ ]
1554
+ },
1555
+ option.value
1556
+ );
1557
+ })
1558
+ ]
1559
+ }
1560
+ )
1561
+ ] });
1562
+ }
1563
+ );
1564
+ Select.displayName = "Select";
1565
+ var DialogOverlay = React16__namespace.forwardRef(
1566
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1567
+ "div",
1568
+ {
1569
+ ref,
1570
+ className: cn(
1571
+ "absolute inset-0 bg-bg-emphasis/60 backdrop-blur-sm",
1572
+ className
1573
+ ),
1574
+ ...props
1575
+ }
1576
+ )
1577
+ );
1578
+ DialogOverlay.displayName = "DialogOverlay";
1579
+ var dialogPanelVariants = classVarianceAuthority.cva(
1580
+ "relative flex w-full flex-col gap-4 border border-border-subtle bg-surface-raised p-6 pb-4 text-text-default shadow-modal rounded-lg focus-visible:outline-none",
1581
+ {
1582
+ variants: {
1583
+ size: {
1584
+ sm: "min-w-[280px] max-w-[360px]",
1585
+ md: "min-w-[280px] max-w-[480px]",
1586
+ lg: "min-w-[280px] max-w-[640px]"
1587
+ }
1588
+ },
1589
+ defaultVariants: {
1590
+ size: "md"
1591
+ }
1592
+ }
1593
+ );
1594
+ var Dialog = React16__namespace.forwardRef(
1595
+ ({
1596
+ open = true,
1597
+ onOpenChange,
1598
+ size,
1599
+ className,
1600
+ overlayClassName,
1601
+ children,
1602
+ ...props
1603
+ }, ref) => {
1604
+ if (!open) return null;
1605
+ const handleKeyDown = (event) => {
1606
+ if (event.key === "Escape") onOpenChange?.(false);
1607
+ };
1608
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1609
+ "div",
1610
+ {
1611
+ className: "absolute inset-0 z-50 flex items-center justify-center p-4",
1612
+ onKeyDown: handleKeyDown,
1613
+ children: [
1614
+ /* @__PURE__ */ jsxRuntime.jsx(
1615
+ DialogOverlay,
1616
+ {
1617
+ className: overlayClassName,
1618
+ onClick: () => onOpenChange?.(false)
1619
+ }
1620
+ ),
1621
+ /* @__PURE__ */ jsxRuntime.jsx(
1622
+ "div",
1623
+ {
1624
+ ref,
1625
+ role: "dialog",
1626
+ "aria-modal": "true",
1627
+ className: cn(dialogPanelVariants({ size }), className),
1628
+ ...props,
1629
+ children
1630
+ }
1631
+ )
1632
+ ]
1633
+ }
1634
+ );
1635
+ }
1636
+ );
1637
+ Dialog.displayName = "Dialog";
1638
+ var DialogHeader = React16__namespace.forwardRef(
1639
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1640
+ "div",
1641
+ {
1642
+ ref,
1643
+ className: cn("flex flex-col gap-1.5 text-left", className),
1644
+ ...props
1645
+ }
1646
+ )
1647
+ );
1648
+ DialogHeader.displayName = "DialogHeader";
1649
+ var DialogTitle = React16__namespace.forwardRef(
1650
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1651
+ "h2",
1652
+ {
1653
+ ref,
1654
+ className: cn(
1655
+ "text-base font-semibold leading-tight text-text-strong",
1656
+ className
1657
+ ),
1658
+ ...props
1659
+ }
1660
+ )
1661
+ );
1662
+ DialogTitle.displayName = "DialogTitle";
1663
+ var DialogDescription = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1664
+ "p",
1665
+ {
1666
+ ref,
1667
+ className: cn("text-sm leading-relaxed text-text-subtle", className),
1668
+ ...props
1669
+ }
1670
+ ));
1671
+ DialogDescription.displayName = "DialogDescription";
1672
+ var DialogBody = React16__namespace.forwardRef(
1673
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1674
+ "div",
1675
+ {
1676
+ ref,
1677
+ className: cn("text-sm text-text-default", className),
1678
+ ...props
1679
+ }
1680
+ )
1681
+ );
1682
+ DialogBody.displayName = "DialogBody";
1683
+ var DialogFooter = React16__namespace.forwardRef(
1684
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1685
+ "div",
1686
+ {
1687
+ ref,
1688
+ className: cn(
1689
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
1690
+ className
1691
+ ),
1692
+ ...props
1693
+ }
1694
+ )
1695
+ );
1696
+ DialogFooter.displayName = "DialogFooter";
1697
+ var sheetOverlayVariants = classVarianceAuthority.cva(
1698
+ "absolute inset-0 bg-[var(--color-overlay-scrim)] transition-opacity duration-200",
1699
+ {
1700
+ variants: {
1701
+ open: {
1702
+ true: "opacity-100",
1703
+ false: "pointer-events-none opacity-0"
1704
+ }
1705
+ },
1706
+ defaultVariants: { open: false }
1707
+ }
1708
+ );
1709
+ var sheetPanelVariants = classVarianceAuthority.cva(
1710
+ "absolute flex flex-col gap-4 bg-surface-raised px-5 pb-6 pt-4 text-text-default shadow-modal transition-transform duration-300 ease-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-border focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base",
1711
+ {
1712
+ variants: {
1713
+ side: {
1714
+ bottom: "inset-x-0 bottom-0 rounded-b-none rounded-t-[var(--radius-lg)] data-[state=closed]:translate-y-full",
1715
+ top: "inset-x-0 top-0 rounded-b-[var(--radius-lg)] data-[state=closed]:-translate-y-full",
1716
+ left: "inset-y-0 left-0 h-full w-80 max-w-[85%] rounded-r-[var(--radius-lg)] data-[state=closed]:-translate-x-full",
1717
+ right: "inset-y-0 right-0 h-full w-80 max-w-[85%] rounded-l-[var(--radius-lg)] data-[state=closed]:translate-x-full"
1718
+ }
1719
+ },
1720
+ defaultVariants: { side: "bottom" }
1721
+ }
1722
+ );
1723
+ var Sheet = React16__namespace.forwardRef(
1724
+ ({
1725
+ className,
1726
+ side = "bottom",
1727
+ open = false,
1728
+ onOpenChange,
1729
+ showHandle = true,
1730
+ children,
1731
+ ...props
1732
+ }, ref) => {
1733
+ const state = open ? "open" : "closed";
1734
+ const handleVisible = showHandle && (side === "bottom" || side === "top");
1735
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1736
+ "div",
1737
+ {
1738
+ className: cn(
1739
+ "pointer-events-none absolute inset-0 overflow-hidden",
1740
+ open && "pointer-events-auto"
1741
+ ),
1742
+ "data-state": state,
1743
+ children: [
1744
+ /* @__PURE__ */ jsxRuntime.jsx(
1745
+ "div",
1746
+ {
1747
+ "aria-hidden": "true",
1748
+ className: sheetOverlayVariants({ open }),
1749
+ onClick: () => onOpenChange?.(false)
1750
+ }
1751
+ ),
1752
+ /* @__PURE__ */ jsxRuntime.jsxs(
1753
+ "div",
1754
+ {
1755
+ ref,
1756
+ role: "dialog",
1757
+ "aria-modal": "true",
1758
+ "aria-hidden": !open,
1759
+ "data-state": state,
1760
+ tabIndex: -1,
1761
+ className: cn(sheetPanelVariants({ side }), className),
1762
+ ...props,
1763
+ children: [
1764
+ handleVisible ? /* @__PURE__ */ jsxRuntime.jsx(SheetHandle, {}) : null,
1765
+ children
1766
+ ]
1767
+ }
1768
+ )
1769
+ ]
1770
+ }
1771
+ );
1772
+ }
1773
+ );
1774
+ Sheet.displayName = "Sheet";
1775
+ var SheetHandle = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1776
+ "div",
1777
+ {
1778
+ ref,
1779
+ "aria-hidden": "true",
1780
+ className: cn(
1781
+ "mx-auto mb-1 h-1 w-10 shrink-0 rounded-full bg-bg-emphasis",
1782
+ className
1783
+ ),
1784
+ ...props
1785
+ }
1786
+ ));
1787
+ SheetHandle.displayName = "SheetHandle";
1788
+ var SheetHeader = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1789
+ "div",
1790
+ {
1791
+ ref,
1792
+ className: cn("flex flex-col gap-0.5", className),
1793
+ ...props
1794
+ }
1795
+ ));
1796
+ SheetHeader.displayName = "SheetHeader";
1797
+ var SheetTitle = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1798
+ "h2",
1799
+ {
1800
+ ref,
1801
+ className: cn("text-lg font-semibold text-text-strong", className),
1802
+ ...props
1803
+ }
1804
+ ));
1805
+ SheetTitle.displayName = "SheetTitle";
1806
+ var SheetDescription = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1807
+ "p",
1808
+ {
1809
+ ref,
1810
+ className: cn("text-sm text-text-subtle", className),
1811
+ ...props
1812
+ }
1813
+ ));
1814
+ SheetDescription.displayName = "SheetDescription";
1815
+ var SheetBody = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1816
+ "div",
1817
+ {
1818
+ ref,
1819
+ className: cn("flex flex-1 flex-col gap-4 overflow-y-auto", className),
1820
+ ...props
1821
+ }
1822
+ ));
1823
+ SheetBody.displayName = "SheetBody";
1824
+ var SheetFooter = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1825
+ "div",
1826
+ {
1827
+ ref,
1828
+ className: cn(
1829
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
1830
+ className
1831
+ ),
1832
+ ...props
1833
+ }
1834
+ ));
1835
+ SheetFooter.displayName = "SheetFooter";
1836
+ var TabsContext = React16__namespace.createContext(null);
1837
+ function useTabsContext(component) {
1838
+ const ctx = React16__namespace.useContext(TabsContext);
1839
+ if (!ctx) {
1840
+ throw new Error(`<${component}> must be used within <Tabs>`);
1841
+ }
1842
+ return ctx;
1843
+ }
1844
+ var Tabs = React16__namespace.forwardRef(
1845
+ ({ className, value, defaultValue, onValueChange, children, ...props }, ref) => {
1846
+ const baseId = React16__namespace.useId();
1847
+ const [internalValue, setInternalValue] = React16__namespace.useState(
1848
+ defaultValue ?? ""
1849
+ );
1850
+ const isControlled = value !== void 0;
1851
+ const activeValue = isControlled ? value : internalValue;
1852
+ const setValue = React16__namespace.useCallback(
1853
+ (next) => {
1854
+ if (!isControlled) setInternalValue(next);
1855
+ onValueChange?.(next);
1856
+ },
1857
+ [isControlled, onValueChange]
1858
+ );
1859
+ const ctx = React16__namespace.useMemo(
1860
+ () => ({ value: activeValue, setValue, baseId }),
1861
+ [activeValue, setValue, baseId]
1862
+ );
1863
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col gap-4", className), ...props, children }) });
1864
+ }
1865
+ );
1866
+ Tabs.displayName = "Tabs";
1867
+ var tabsListVariants = classVarianceAuthority.cva(
1868
+ "relative flex items-center border-b border-border-subtle",
1869
+ {
1870
+ variants: {
1871
+ fullWidth: {
1872
+ true: "w-full",
1873
+ false: "w-fit"
1874
+ }
1875
+ },
1876
+ defaultVariants: {
1877
+ fullWidth: false
1878
+ }
1879
+ }
1880
+ );
1881
+ var TabsList = React16__namespace.forwardRef(
1882
+ ({ className, fullWidth, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1883
+ "div",
1884
+ {
1885
+ ref,
1886
+ role: "tablist",
1887
+ className: cn(tabsListVariants({ fullWidth }), "gap-1", className),
1888
+ ...props
1889
+ }
1890
+ )
1891
+ );
1892
+ TabsList.displayName = "TabsList";
1893
+ var tabsTriggerVariants = classVarianceAuthority.cva(
1894
+ [
1895
+ "relative inline-flex items-center justify-center gap-2 whitespace-nowrap px-3 py-2 text-sm font-medium",
1896
+ "transition-colors focus-visible:outline-none",
1897
+ "focus-visible:ring-2 focus-visible:ring-brand-border focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base",
1898
+ "disabled:pointer-events-none disabled:text-text-disabled",
1899
+ "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1900
+ // bottom indicator element (2px)
1901
+ "after:absolute after:inset-x-0 after:-bottom-px after:h-0.5 after:rounded-full after:transition-colors"
1902
+ ],
1903
+ {
1904
+ variants: {
1905
+ active: {
1906
+ true: "text-text-strong after:bg-brand-solid",
1907
+ false: "text-text-subtle hover:text-text-default after:bg-transparent"
1908
+ }
1909
+ },
1910
+ defaultVariants: {
1911
+ active: false
1912
+ }
1913
+ }
1914
+ );
1915
+ var TabsTrigger = React16__namespace.forwardRef(
1916
+ ({ className, value, disabled, ...props }, ref) => {
1917
+ const { value: activeValue, setValue, baseId } = useTabsContext("TabsTrigger");
1918
+ const isActive = activeValue === value;
1919
+ return /* @__PURE__ */ jsxRuntime.jsx(
1920
+ "button",
1921
+ {
1922
+ ref,
1923
+ type: "button",
1924
+ role: "tab",
1925
+ id: `${baseId}-trigger-${value}`,
1926
+ "aria-selected": isActive,
1927
+ "aria-controls": `${baseId}-content-${value}`,
1928
+ tabIndex: isActive ? 0 : -1,
1929
+ disabled,
1930
+ "data-state": isActive ? "active" : "inactive",
1931
+ onClick: () => setValue(value),
1932
+ className: cn(tabsTriggerVariants({ active: isActive }), className),
1933
+ ...props
1934
+ }
1935
+ );
1936
+ }
1937
+ );
1938
+ TabsTrigger.displayName = "TabsTrigger";
1939
+ var TabsContent = React16__namespace.forwardRef(
1940
+ ({ className, value, forceMount, children, ...props }, ref) => {
1941
+ const { value: activeValue, baseId } = useTabsContext("TabsContent");
1942
+ const isActive = activeValue === value;
1943
+ if (!isActive && !forceMount) return null;
1944
+ return /* @__PURE__ */ jsxRuntime.jsx(
1945
+ "div",
1946
+ {
1947
+ ref,
1948
+ role: "tabpanel",
1949
+ id: `${baseId}-content-${value}`,
1950
+ "aria-labelledby": `${baseId}-trigger-${value}`,
1951
+ hidden: !isActive,
1952
+ tabIndex: 0,
1953
+ "data-state": isActive ? "active" : "inactive",
1954
+ className: cn(
1955
+ "text-sm text-text-default focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-border focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base",
1956
+ className
1957
+ ),
1958
+ ...props,
1959
+ children
1960
+ }
1961
+ );
1962
+ }
1963
+ );
1964
+ TabsContent.displayName = "TabsContent";
1965
+ var tableVariants = classVarianceAuthority.cva(
1966
+ "w-full caption-bottom border-separate border-spacing-0 overflow-hidden rounded-lg border border-border-default text-sm text-text-default",
1967
+ {
1968
+ variants: {
1969
+ density: {
1970
+ comfortable: "[&_td]:py-2 [&_th]:py-2",
1971
+ compact: "[&_td]:py-1 [&_th]:py-1"
1972
+ }
1973
+ },
1974
+ defaultVariants: {
1975
+ density: "comfortable"
1976
+ }
1977
+ }
1978
+ );
1979
+ var Table = React16__namespace.forwardRef(
1980
+ ({ className, density, containerProps, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1981
+ "div",
1982
+ {
1983
+ ...containerProps,
1984
+ className: cn("relative w-full overflow-x-auto", containerProps?.className),
1985
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1986
+ "table",
1987
+ {
1988
+ ref,
1989
+ className: cn(tableVariants({ density, className })),
1990
+ ...props
1991
+ }
1992
+ )
1993
+ }
1994
+ )
1995
+ );
1996
+ Table.displayName = "Table";
1997
+ var TableHeader = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1998
+ "thead",
1999
+ {
2000
+ ref,
2001
+ className: cn("bg-surface-sunken text-text-subtle", className),
2002
+ ...props
2003
+ }
2004
+ ));
2005
+ TableHeader.displayName = "TableHeader";
2006
+ var TableBody = React16__namespace.forwardRef(
2007
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("", className), ...props })
2008
+ );
2009
+ TableBody.displayName = "TableBody";
2010
+ var tableRowVariants = classVarianceAuthority.cva(
2011
+ "border-b border-border-default transition-colors [&>*]:border-b [&>*]:border-border-default last:[&>*]:border-b-0",
2012
+ {
2013
+ variants: {
2014
+ interactive: {
2015
+ true: "cursor-pointer hover:bg-surface-hover data-[selected=true]:bg-brand-subtle",
2016
+ false: "hover:bg-surface-hover"
2017
+ }
2018
+ },
2019
+ defaultVariants: {
2020
+ interactive: false
2021
+ }
2022
+ }
2023
+ );
2024
+ var TableRow = React16__namespace.forwardRef(
2025
+ ({ className, interactive, selected, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2026
+ "tr",
2027
+ {
2028
+ ref,
2029
+ "data-selected": selected ? "true" : void 0,
2030
+ "aria-selected": selected,
2031
+ className: cn(tableRowVariants({ interactive, className })),
2032
+ ...props
2033
+ }
2034
+ )
2035
+ );
2036
+ TableRow.displayName = "TableRow";
2037
+ var TableHead = React16__namespace.forwardRef(
2038
+ ({ className, sort, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2039
+ "th",
2040
+ {
2041
+ ref,
2042
+ scope: "col",
2043
+ "aria-sort": sort === "asc" ? "ascending" : sort === "desc" ? "descending" : sort === "none" ? "none" : void 0,
2044
+ className: cn(
2045
+ "h-9 px-3 py-2 text-left align-middle text-xs font-medium text-text-subtle",
2046
+ "[&:has([role=checkbox])]:pr-0",
2047
+ className
2048
+ ),
2049
+ ...props,
2050
+ children: sort && sort !== "none" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
2051
+ children,
2052
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "text-text-subtle", children: sort === "asc" ? "\u2191" : "\u2193" })
2053
+ ] }) : children
2054
+ }
2055
+ )
2056
+ );
2057
+ TableHead.displayName = "TableHead";
2058
+ var TableCell = React16__namespace.forwardRef(
2059
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2060
+ "td",
2061
+ {
2062
+ ref,
2063
+ className: cn(
2064
+ "px-3 py-2 align-middle text-sm text-text-default [&:has([role=checkbox])]:pr-0",
2065
+ className
2066
+ ),
2067
+ ...props
2068
+ }
2069
+ )
2070
+ );
2071
+ TableCell.displayName = "TableCell";
2072
+ var TableCaption = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2073
+ "caption",
2074
+ {
2075
+ ref,
2076
+ className: cn("mt-3 text-xs text-text-subtle", className),
2077
+ ...props
2078
+ }
2079
+ ));
2080
+ TableCaption.displayName = "TableCaption";
2081
+ var paginationItemVariants = classVarianceAuthority.cva(
2082
+ "inline-flex h-8 min-w-8 items-center justify-center rounded-lg px-2 text-sm font-medium transition-colors select-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:pointer-events-none disabled:text-text-disabled [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
2083
+ {
2084
+ variants: {
2085
+ active: {
2086
+ true: "bg-brand-solid text-text-on-brand hover:bg-brand-solid-hover",
2087
+ false: "text-text-default hover:bg-surface-hover active:bg-surface-pressed"
2088
+ }
2089
+ },
2090
+ defaultVariants: {
2091
+ active: false
2092
+ }
2093
+ }
2094
+ );
2095
+ var ChevronLeftIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx(
2096
+ "svg",
2097
+ {
2098
+ viewBox: "0 0 24 24",
2099
+ fill: "none",
2100
+ stroke: "currentColor",
2101
+ strokeWidth: 2,
2102
+ strokeLinecap: "round",
2103
+ strokeLinejoin: "round",
2104
+ "aria-hidden": "true",
2105
+ ...props,
2106
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" })
2107
+ }
2108
+ );
2109
+ var ChevronRightIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx(
2110
+ "svg",
2111
+ {
2112
+ viewBox: "0 0 24 24",
2113
+ fill: "none",
2114
+ stroke: "currentColor",
2115
+ strokeWidth: 2,
2116
+ strokeLinecap: "round",
2117
+ strokeLinejoin: "round",
2118
+ "aria-hidden": "true",
2119
+ ...props,
2120
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" })
2121
+ }
2122
+ );
2123
+ var EllipsisIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
2124
+ "svg",
2125
+ {
2126
+ viewBox: "0 0 24 24",
2127
+ fill: "currentColor",
2128
+ stroke: "none",
2129
+ "aria-hidden": "true",
2130
+ ...props,
2131
+ children: [
2132
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "5", cy: "12", r: "1.5" }),
2133
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "1.5" }),
2134
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "19", cy: "12", r: "1.5" })
2135
+ ]
2136
+ }
2137
+ );
2138
+ var PaginationItem = React16__namespace.forwardRef(
2139
+ ({ className, active, page, ...props }, ref) => {
2140
+ return /* @__PURE__ */ jsxRuntime.jsx(
2141
+ "button",
2142
+ {
2143
+ ref,
2144
+ type: "button",
2145
+ "aria-current": active ? "page" : void 0,
2146
+ "aria-label": `Go to page ${page}`,
2147
+ className: cn(paginationItemVariants({ active, className })),
2148
+ ...props,
2149
+ children: page
2150
+ }
2151
+ );
2152
+ }
2153
+ );
2154
+ PaginationItem.displayName = "PaginationItem";
2155
+ var PaginationEllipsis = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
2156
+ "span",
2157
+ {
2158
+ ref,
2159
+ "aria-hidden": "true",
2160
+ className: cn(
2161
+ "inline-flex h-8 min-w-8 items-center justify-center px-1 text-sm text-text-subtle",
2162
+ className
2163
+ ),
2164
+ ...props,
2165
+ children: [
2166
+ /* @__PURE__ */ jsxRuntime.jsx(EllipsisIcon, {}),
2167
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "More pages" })
2168
+ ]
2169
+ }
2170
+ ));
2171
+ PaginationEllipsis.displayName = "PaginationEllipsis";
2172
+ var PaginationPrevious = React16__namespace.forwardRef(({ className, disabled, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2173
+ "button",
2174
+ {
2175
+ ref,
2176
+ type: "button",
2177
+ disabled,
2178
+ "aria-label": "Go to previous page",
2179
+ className: cn(paginationItemVariants({ active: false, className })),
2180
+ ...props,
2181
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeftIcon, {})
2182
+ }
2183
+ ));
2184
+ PaginationPrevious.displayName = "PaginationPrevious";
2185
+ var PaginationNext = React16__namespace.forwardRef(
2186
+ ({ className, disabled, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2187
+ "button",
2188
+ {
2189
+ ref,
2190
+ type: "button",
2191
+ disabled,
2192
+ "aria-label": "Go to next page",
2193
+ className: cn(paginationItemVariants({ active: false, className })),
2194
+ ...props,
2195
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, {})
2196
+ }
2197
+ )
2198
+ );
2199
+ PaginationNext.displayName = "PaginationNext";
2200
+ function buildPageRange(current, total, siblingCount = 1) {
2201
+ const totalSlots = siblingCount * 2 + 5;
2202
+ if (total <= totalSlots) {
2203
+ return Array.from({ length: total }, (_, i) => i + 1);
2204
+ }
2205
+ const leftSibling = Math.max(current - siblingCount, 1);
2206
+ const rightSibling = Math.min(current + siblingCount, total);
2207
+ const showLeftEllipsis = leftSibling > 2;
2208
+ const showRightEllipsis = rightSibling < total - 1;
2209
+ const range = [];
2210
+ if (!showLeftEllipsis && showRightEllipsis) {
2211
+ const leftItemCount = siblingCount * 2 + 3;
2212
+ for (let i = 1; i <= leftItemCount; i++) range.push(i);
2213
+ range.push("ellipsis", total);
2214
+ } else if (showLeftEllipsis && !showRightEllipsis) {
2215
+ const rightItemCount = siblingCount * 2 + 3;
2216
+ range.push(1, "ellipsis");
2217
+ for (let i = total - rightItemCount + 1; i <= total; i++) range.push(i);
2218
+ } else {
2219
+ range.push(1, "ellipsis");
2220
+ for (let i = leftSibling; i <= rightSibling; i++) range.push(i);
2221
+ range.push("ellipsis", total);
2222
+ }
2223
+ return range;
2224
+ }
2225
+ var Pagination = React16__namespace.forwardRef(
2226
+ ({
2227
+ className,
2228
+ totalPages,
2229
+ page,
2230
+ onPageChange,
2231
+ siblingCount = 1,
2232
+ label = "Pagination",
2233
+ ...props
2234
+ }, ref) => {
2235
+ const safeTotal = Math.max(totalPages, 1);
2236
+ const current = Math.min(Math.max(page, 1), safeTotal);
2237
+ const items = buildPageRange(current, safeTotal, siblingCount);
2238
+ const goTo = (target) => {
2239
+ if (target < 1 || target > safeTotal || target === current) return;
2240
+ onPageChange?.(target);
2241
+ };
2242
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2243
+ "nav",
2244
+ {
2245
+ ref,
2246
+ role: "navigation",
2247
+ "aria-label": label,
2248
+ className: cn("flex items-center gap-1", className),
2249
+ ...props,
2250
+ children: [
2251
+ /* @__PURE__ */ jsxRuntime.jsx(
2252
+ PaginationPrevious,
2253
+ {
2254
+ disabled: current <= 1,
2255
+ onClick: () => goTo(current - 1)
2256
+ }
2257
+ ),
2258
+ items.map(
2259
+ (item, index) => item === "ellipsis" ? /* @__PURE__ */ jsxRuntime.jsx(PaginationEllipsis, {}, `ellipsis-${index}`) : /* @__PURE__ */ jsxRuntime.jsx(
2260
+ PaginationItem,
2261
+ {
2262
+ page: item,
2263
+ active: item === current,
2264
+ onClick: () => goTo(item)
2265
+ },
2266
+ item
2267
+ )
2268
+ ),
2269
+ /* @__PURE__ */ jsxRuntime.jsx(
2270
+ PaginationNext,
2271
+ {
2272
+ disabled: current >= safeTotal,
2273
+ onClick: () => goTo(current + 1)
2274
+ }
2275
+ )
2276
+ ]
2277
+ }
2278
+ );
2279
+ }
2280
+ );
2281
+ Pagination.displayName = "Pagination";
2282
+ var segmentContainerVariants = classVarianceAuthority.cva(
2283
+ "relative inline-grid h-8 auto-cols-fr grid-flow-col items-center rounded-lg bg-surface-sunken p-0.5 text-sm",
2284
+ {
2285
+ variants: {
2286
+ fullWidth: {
2287
+ true: "flex w-full",
2288
+ false: "inline-grid w-auto"
2289
+ }
2290
+ },
2291
+ defaultVariants: {
2292
+ fullWidth: false
2293
+ }
2294
+ }
2295
+ );
2296
+ var segmentItemVariants = classVarianceAuthority.cva(
2297
+ "relative z-10 inline-flex h-full w-full items-center justify-center gap-1.5 whitespace-nowrap rounded-lg px-3 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
2298
+ {
2299
+ variants: {
2300
+ // 활성=label1 굵기(semibold/600) · 비활성=body-sm 굵기(regular/400), 둘 다 14px.
2301
+ // NOTE: text-label1/body-sm 클래스는 twMerge가 text-* 색상과 같은 충돌군으로
2302
+ // 보고 제거하므로, 색상과 충돌 안 하는 font-weight 유틸로 굵기를 지정한다.
2303
+ active: {
2304
+ true: "font-semibold text-text-strong",
2305
+ false: "font-normal text-text-subtle hover:text-text-default"
2306
+ }
2307
+ },
2308
+ defaultVariants: {
2309
+ active: false
2310
+ }
2311
+ }
2312
+ );
2313
+ var SegmentedControl = React16__namespace.forwardRef(
2314
+ ({
2315
+ className,
2316
+ items,
2317
+ value,
2318
+ defaultValue,
2319
+ onValueChange,
2320
+ disabled = false,
2321
+ fullWidth,
2322
+ "aria-label": ariaLabel,
2323
+ ...props
2324
+ }, ref) => {
2325
+ const isControlled = value !== void 0;
2326
+ const [internalValue, setInternalValue] = React16__namespace.useState(
2327
+ defaultValue ?? items[0]?.value ?? ""
2328
+ );
2329
+ const currentValue = isControlled ? value : internalValue;
2330
+ const activeIndex = Math.max(
2331
+ 0,
2332
+ items.findIndex((item) => item.value === currentValue)
2333
+ );
2334
+ const count = items.length || 1;
2335
+ const handleSelect = (next) => {
2336
+ if (!isControlled) setInternalValue(next);
2337
+ onValueChange?.(next);
2338
+ };
2339
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2340
+ "div",
2341
+ {
2342
+ ref,
2343
+ role: "tablist",
2344
+ "aria-label": ariaLabel,
2345
+ "aria-disabled": disabled || void 0,
2346
+ className: cn(segmentContainerVariants({ fullWidth }), className),
2347
+ ...props,
2348
+ children: [
2349
+ items.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2350
+ "span",
2351
+ {
2352
+ "aria-hidden": "true",
2353
+ className: "pointer-events-none absolute bottom-0.5 left-0.5 top-0.5 z-0 rounded-lg bg-surface-default shadow-sm transition-transform duration-200 ease-out",
2354
+ style: {
2355
+ width: `calc((100% - 0.25rem) / ${count})`,
2356
+ transform: `translateX(calc(${activeIndex} * 100%))`
2357
+ }
2358
+ }
2359
+ ),
2360
+ items.map((item) => {
2361
+ const isActive = item.value === currentValue;
2362
+ const isDisabled = disabled || item.disabled;
2363
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2364
+ "button",
2365
+ {
2366
+ type: "button",
2367
+ role: "tab",
2368
+ "aria-selected": isActive,
2369
+ disabled: isDisabled,
2370
+ tabIndex: isActive ? 0 : -1,
2371
+ onClick: () => handleSelect(item.value),
2372
+ className: cn(segmentItemVariants({ active: isActive })),
2373
+ children: [
2374
+ item.icon,
2375
+ item.label
2376
+ ]
2377
+ },
2378
+ item.value
2379
+ );
2380
+ })
2381
+ ]
2382
+ }
2383
+ );
2384
+ }
2385
+ );
2386
+ SegmentedControl.displayName = "SegmentedControl";
2387
+ var toastVariants = classVarianceAuthority.cva(
2388
+ "pointer-events-auto flex w-full max-w-sm gap-3 rounded-lg border px-4 py-4 shadow-toast focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base",
2389
+ {
2390
+ variants: {
2391
+ variant: {
2392
+ default: "border-border-default bg-surface-raised text-text-default focus-visible:ring-border-focus",
2393
+ danger: "border-danger-border bg-danger-subtle text-danger-text focus-visible:ring-danger-border"
2394
+ }
2395
+ },
2396
+ defaultVariants: {
2397
+ variant: "default"
2398
+ }
2399
+ }
2400
+ );
2401
+ function InfoIcon(props) {
2402
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2403
+ "svg",
2404
+ {
2405
+ viewBox: "0 0 20 20",
2406
+ fill: "none",
2407
+ stroke: "currentColor",
2408
+ strokeWidth: 1.6,
2409
+ strokeLinecap: "round",
2410
+ strokeLinejoin: "round",
2411
+ "aria-hidden": "true",
2412
+ ...props,
2413
+ children: [
2414
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "7.5" }),
2415
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 9v4.5" }),
2416
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 6.5h.01" })
2417
+ ]
2418
+ }
2419
+ );
2420
+ }
2421
+ function AlertIcon(props) {
2422
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2423
+ "svg",
2424
+ {
2425
+ viewBox: "0 0 20 20",
2426
+ fill: "none",
2427
+ stroke: "currentColor",
2428
+ strokeWidth: 1.6,
2429
+ strokeLinecap: "round",
2430
+ strokeLinejoin: "round",
2431
+ "aria-hidden": "true",
2432
+ ...props,
2433
+ children: [
2434
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 2.5 18 16.5H2z" }),
2435
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 8v3.5" }),
2436
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 14h.01" })
2437
+ ]
2438
+ }
2439
+ );
2440
+ }
2441
+ function CloseIcon2(props) {
2442
+ return /* @__PURE__ */ jsxRuntime.jsx(
2443
+ "svg",
2444
+ {
2445
+ viewBox: "0 0 20 20",
2446
+ fill: "none",
2447
+ stroke: "currentColor",
2448
+ strokeWidth: 1.6,
2449
+ strokeLinecap: "round",
2450
+ strokeLinejoin: "round",
2451
+ "aria-hidden": "true",
2452
+ ...props,
2453
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 5l10 10M15 5L5 15" })
2454
+ }
2455
+ );
2456
+ }
2457
+ var Toast = React16__namespace.forwardRef(
2458
+ ({
2459
+ className,
2460
+ variant,
2461
+ message,
2462
+ title,
2463
+ icon = true,
2464
+ dismissible = true,
2465
+ onClose,
2466
+ closeLabel = "Close",
2467
+ ...props
2468
+ }, ref) => {
2469
+ const StatusIcon = variant === "danger" ? AlertIcon : InfoIcon;
2470
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2471
+ "div",
2472
+ {
2473
+ ref,
2474
+ role: variant === "danger" ? "alert" : "status",
2475
+ "aria-live": variant === "danger" ? "assertive" : "polite",
2476
+ className: cn(
2477
+ toastVariants({ variant, className }),
2478
+ title ? "items-start" : "items-center"
2479
+ ),
2480
+ ...props,
2481
+ children: [
2482
+ /* @__PURE__ */ jsxRuntime.jsxs(
2483
+ "div",
2484
+ {
2485
+ className: cn(
2486
+ "flex min-w-0 flex-1 gap-2",
2487
+ title ? "items-start" : "items-center"
2488
+ ),
2489
+ children: [
2490
+ icon ? /* @__PURE__ */ jsxRuntime.jsx(
2491
+ StatusIcon,
2492
+ {
2493
+ className: cn(
2494
+ "size-5 shrink-0",
2495
+ variant === "danger" ? "text-danger-text" : "text-text-subtle"
2496
+ )
2497
+ }
2498
+ ) : null,
2499
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
2500
+ title ? /* @__PURE__ */ jsxRuntime.jsx(
2501
+ "p",
2502
+ {
2503
+ className: cn(
2504
+ "text-label1",
2505
+ variant === "danger" ? "text-danger-text" : "text-text-strong"
2506
+ ),
2507
+ children: title
2508
+ }
2509
+ ) : null,
2510
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-body-sm break-words", title && "mt-0.5"), children: message })
2511
+ ] })
2512
+ ]
2513
+ }
2514
+ ),
2515
+ dismissible ? /* @__PURE__ */ jsxRuntime.jsx(
2516
+ "button",
2517
+ {
2518
+ type: "button",
2519
+ onClick: onClose,
2520
+ "aria-label": closeLabel,
2521
+ className: cn(
2522
+ "-mr-1 inline-flex size-6 shrink-0 items-center justify-center rounded text-text-subtle transition-colors hover:bg-surface-hover hover:text-text-default active:bg-surface-pressed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base",
2523
+ title && "-mt-0.5"
2524
+ ),
2525
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon2, { className: "size-4" })
2526
+ }
2527
+ ) : null
2528
+ ]
2529
+ }
2530
+ );
2531
+ }
2532
+ );
2533
+ Toast.displayName = "Toast";
2534
+ var SIZES = {
2535
+ lg: {
2536
+ plate: 180,
2537
+ art: 120,
2538
+ pad: "px-6 py-12",
2539
+ plateMb: "mb-4",
2540
+ title: "text-xl",
2541
+ desc: "text-base max-w-[360px]",
2542
+ gap: "mt-1",
2543
+ act: "mt-5"
2544
+ },
2545
+ md: {
2546
+ plate: 144,
2547
+ art: 96,
2548
+ pad: "px-5 py-10",
2549
+ plateMb: "mb-3",
2550
+ title: "text-lg",
2551
+ desc: "text-base max-w-[300px]",
2552
+ gap: "mt-0.5",
2553
+ act: "mt-4"
2554
+ },
2555
+ sm: {
2556
+ plate: 108,
2557
+ art: 72,
2558
+ pad: "px-4 py-8",
2559
+ plateMb: "mb-3",
2560
+ title: "text-lg",
2561
+ desc: "text-sm max-w-[240px]",
2562
+ gap: "mt-0.5",
2563
+ act: "mt-4"
2564
+ }
2565
+ };
2566
+ function EmptyState({
2567
+ size = "lg",
2568
+ illustration,
2569
+ title,
2570
+ description,
2571
+ action,
2572
+ className,
2573
+ ...props
2574
+ }) {
2575
+ const s = SIZES[size];
2576
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2577
+ "div",
2578
+ {
2579
+ className: cn("flex flex-col items-center text-center", s.pad, className),
2580
+ ...props,
2581
+ children: [
2582
+ illustration && // 플레이트: border-subtle = 라이트 gray-20(sunken) · 다크 gray-60(카드 gray-80보다 밝아 떠 보임)
2583
+ /* @__PURE__ */ jsxRuntime.jsx(
2584
+ "div",
2585
+ {
2586
+ className: cn(
2587
+ "flex items-center justify-center rounded-full bg-border-subtle",
2588
+ s.plateMb
2589
+ ),
2590
+ style: { width: s.plate, height: s.plate },
2591
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2592
+ "span",
2593
+ {
2594
+ className: "inline-flex [&>img]:h-full [&>img]:w-full [&>img]:object-contain [&>svg]:h-full [&>svg]:w-full",
2595
+ style: { width: s.art, height: s.art },
2596
+ children: illustration
2597
+ }
2598
+ )
2599
+ }
2600
+ ),
2601
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: cn("font-bold leading-snug text-text-strong", s.title), children: title }),
2602
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("leading-relaxed text-text-subtle", s.desc, s.gap), children: description }),
2603
+ action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-2", s.act), children: action })
2604
+ ]
2605
+ }
2606
+ );
2607
+ }
2608
+ function IconBase({
2609
+ size = 20,
2610
+ children,
2611
+ ...props
2612
+ }) {
2613
+ return /* @__PURE__ */ jsxRuntime.jsx(
2614
+ "svg",
2615
+ {
2616
+ xmlns: "http://www.w3.org/2000/svg",
2617
+ width: size,
2618
+ height: size,
2619
+ viewBox: "0 0 24 24",
2620
+ fill: "none",
2621
+ stroke: "currentColor",
2622
+ strokeWidth: 1.5,
2623
+ strokeLinecap: "round",
2624
+ strokeLinejoin: "round",
2625
+ "aria-hidden": "true",
2626
+ ...props,
2627
+ children
2628
+ }
2629
+ );
2630
+ }
2631
+ var CheckIcon4 = (props) => /* @__PURE__ */ jsxRuntime.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" }) });
2632
+ var ChevronDownIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) });
2633
+ var ChevronLeftIcon2 = (props) => /* @__PURE__ */ jsxRuntime.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 6-6 6 6 6" }) });
2634
+ var ChevronRightIcon2 = (props) => /* @__PURE__ */ jsxRuntime.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 6 6 6-6 6" }) });
2635
+ var HashIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 9h16M4 15h16M10 3 8 21M16 3 14 21" }) });
2636
+ var LockIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(IconBase, { ...props, children: [
2637
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "18", height: "11", x: "3", y: "11", rx: "3", ry: "3" }),
2638
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
2639
+ ] });
2640
+ var PinIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(IconBase, { ...props, children: [
2641
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 17v5" }),
2642
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" })
2643
+ ] });
2644
+ var PlusIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5v14M5 12h14" }) });
2645
+ var SearchIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(IconBase, { ...props, children: [
2646
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
2647
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m20 20-3.4-3.4" })
2648
+ ] });
2649
+ var XIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx(IconBase, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) });
2650
+ var AccordionItem = React16__namespace.forwardRef(
2651
+ ({ className, title, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
2652
+ "details",
2653
+ {
2654
+ ref,
2655
+ className: cn(
2656
+ "group border-t border-border-subtle first:border-t-0",
2657
+ className
2658
+ ),
2659
+ ...props,
2660
+ children: [
2661
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex cursor-pointer select-none list-none items-center justify-between gap-2.5 px-4 py-3.5 text-sm font-semibold text-text-default group-open:text-brand-text [&::-webkit-details-marker]:hidden", children: [
2662
+ title,
2663
+ /* @__PURE__ */ jsxRuntime.jsx(
2664
+ ChevronDownIcon,
2665
+ {
2666
+ size: 18,
2667
+ className: "shrink-0 text-text-subtle transition-transform duration-200 group-open:rotate-180"
2668
+ }
2669
+ )
2670
+ ] }),
2671
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-3.5 text-sm leading-relaxed text-text-subtle", children })
2672
+ ]
2673
+ }
2674
+ )
2675
+ );
2676
+ AccordionItem.displayName = "AccordionItem";
2677
+ var Accordion = React16__namespace.forwardRef(
2678
+ ({ className, items, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2679
+ "div",
2680
+ {
2681
+ ref,
2682
+ className: cn(
2683
+ "overflow-hidden rounded-lg border border-border-subtle bg-surface-default",
2684
+ className
2685
+ ),
2686
+ ...props,
2687
+ children: items ? items.map((it) => /* @__PURE__ */ jsxRuntime.jsx(
2688
+ AccordionItem,
2689
+ {
2690
+ title: it.title,
2691
+ open: it.defaultOpen,
2692
+ children: it.content
2693
+ },
2694
+ it.id ?? String(it.title)
2695
+ )) : children
2696
+ }
2697
+ )
2698
+ );
2699
+ Accordion.displayName = "Accordion";
2700
+ var KpiRow = React16__namespace.forwardRef(
2701
+ ({ items, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex w-[360px] gap-2", className), ...props, children: items.map((k) => /* @__PURE__ */ jsxRuntime.jsxs(
2702
+ "div",
2703
+ {
2704
+ className: "flex-1 rounded-lg border border-border-subtle bg-surface-default p-3",
2705
+ children: [
2706
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
2707
+ k.dot != null && /* @__PURE__ */ jsxRuntime.jsx(
2708
+ "span",
2709
+ {
2710
+ className: cn("h-2 w-2 shrink-0 rounded-full", k.dot),
2711
+ "aria-hidden": true
2712
+ }
2713
+ ),
2714
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-text-subtle", children: k.label })
2715
+ ] }),
2716
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-2xl font-bold text-text-strong", children: k.value })
2717
+ ]
2718
+ },
2719
+ k.label
2720
+ )) })
2721
+ );
2722
+ KpiRow.displayName = "KpiRow";
2723
+ var ProgressList = React16__namespace.forwardRef(
2724
+ ({ items, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2725
+ "div",
2726
+ {
2727
+ ref,
2728
+ className: cn("flex w-[320px] flex-col gap-3", className),
2729
+ ...props,
2730
+ children: items.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2731
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex justify-between text-sm", children: [
2732
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-default", children: r.label }),
2733
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: r.danger ? "text-danger-text" : "text-brand-text", children: [
2734
+ r.pct,
2735
+ "%"
2736
+ ] })
2737
+ ] }),
2738
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 overflow-hidden rounded-full bg-surface-sunken", children: /* @__PURE__ */ jsxRuntime.jsx(
2739
+ "div",
2740
+ {
2741
+ className: cn(
2742
+ "h-full rounded-full",
2743
+ r.danger ? "bg-danger-solid" : "bg-brand-solid"
2744
+ ),
2745
+ style: { width: `${r.pct}%` }
2746
+ }
2747
+ ) })
2748
+ ] }, r.label))
2749
+ }
2750
+ )
2751
+ );
2752
+ ProgressList.displayName = "ProgressList";
2753
+ var Ring = React16__namespace.forwardRef(
2754
+ ({ pct, size = 84, label, className, style, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
2755
+ "div",
2756
+ {
2757
+ ref,
2758
+ className: cn("relative grid place-items-center", className),
2759
+ style: { height: size, width: size, ...style },
2760
+ ...props,
2761
+ children: [
2762
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 36 36", className: "h-full w-full -rotate-90", children: [
2763
+ /* @__PURE__ */ jsxRuntime.jsx(
2764
+ "circle",
2765
+ {
2766
+ cx: "18",
2767
+ cy: "18",
2768
+ r: "15.5",
2769
+ fill: "none",
2770
+ strokeWidth: "3",
2771
+ className: "stroke-surface-sunken"
2772
+ }
2773
+ ),
2774
+ /* @__PURE__ */ jsxRuntime.jsx(
2775
+ "circle",
2776
+ {
2777
+ cx: "18",
2778
+ cy: "18",
2779
+ r: "15.5",
2780
+ fill: "none",
2781
+ strokeWidth: "3",
2782
+ strokeLinecap: "round",
2783
+ pathLength: 100,
2784
+ strokeDasharray: `${pct} 100`,
2785
+ className: "stroke-brand-solid"
2786
+ }
2787
+ )
2788
+ ] }),
2789
+ /* @__PURE__ */ jsxRuntime.jsx("b", { className: "absolute text-sm font-bold text-text-strong", children: label ?? `${pct}%` })
2790
+ ]
2791
+ }
2792
+ )
2793
+ );
2794
+ Ring.displayName = "Ring";
2795
+ var StackBar = React16__namespace.forwardRef(
2796
+ ({ segments, showLegend = true, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("w-[360px]", className), ...props, children: [
2797
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-6 gap-0.5", children: segments.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
2798
+ "div",
2799
+ {
2800
+ className: cn(
2801
+ s.className ?? "bg-brand-solid",
2802
+ i === 0 && "rounded-l-full",
2803
+ i === segments.length - 1 && "rounded-r-full"
2804
+ ),
2805
+ style: { width: `${s.pct}%` }
2806
+ },
2807
+ s.label
2808
+ )) }),
2809
+ showLegend && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-x-4 gap-y-1", children: segments.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
2810
+ "div",
2811
+ {
2812
+ className: "flex items-center gap-1.5 text-xs text-text-subtle",
2813
+ children: [
2814
+ /* @__PURE__ */ jsxRuntime.jsx(
2815
+ "span",
2816
+ {
2817
+ className: cn(
2818
+ "h-2.5 w-2.5 rounded-full",
2819
+ s.className ?? "bg-brand-solid"
2820
+ )
2821
+ }
2822
+ ),
2823
+ s.label,
2824
+ " ",
2825
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-text-default", children: [
2826
+ s.pct,
2827
+ "%"
2828
+ ] })
2829
+ ]
2830
+ },
2831
+ s.label
2832
+ )) })
2833
+ ] })
2834
+ );
2835
+ StackBar.displayName = "StackBar";
2836
+ var BAR_BY_STATE = {
2837
+ reached: "bg-brand-solid",
2838
+ unreached: "bg-brand-subtle",
2839
+ pending: "bg-surface-sunken"
2840
+ };
2841
+ var WorkHoursBar = React16__namespace.forwardRef(
2842
+ ({ data, max = 12, height = 120, caption, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className, ...props, children: [
2843
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-end gap-3", children: data.map((d) => {
2844
+ const barH = d.state === "pending" ? 4 : d.hours / max * height;
2845
+ const labelCls = d.today ? "text-brand-text font-semibold" : d.future ? "text-text-disabled" : "text-text-subtle";
2846
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2", children: [
2847
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-8 items-end", style: { height }, children: /* @__PURE__ */ jsxRuntime.jsx(
2848
+ "div",
2849
+ {
2850
+ className: cn("w-full rounded-t", BAR_BY_STATE[d.state]),
2851
+ style: { height: barH }
2852
+ }
2853
+ ) }),
2854
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-xs", labelCls), children: d.day })
2855
+ ] }, d.day);
2856
+ }) }),
2857
+ caption != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-xs text-text-subtle", children: caption })
2858
+ ] })
2859
+ );
2860
+ WorkHoursBar.displayName = "WorkHoursBar";
2861
+ var Kbd = React16__namespace.forwardRef(
2862
+ ({ active, className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2863
+ "kbd",
2864
+ {
2865
+ ref,
2866
+ className: cn(
2867
+ "rounded border px-1.5 py-px font-mono text-xs",
2868
+ active ? "border-current bg-transparent text-brand-text" : "border-border-subtle bg-bg-base text-text-subtle",
2869
+ className
2870
+ ),
2871
+ ...props,
2872
+ children
2873
+ }
2874
+ )
2875
+ );
2876
+ Kbd.displayName = "Kbd";
2877
+ var CommandPalette = React16__namespace.forwardRef(
2878
+ ({
2879
+ groups,
2880
+ onSelect,
2881
+ activeId,
2882
+ placeholder = "\uBA85\uB839 \uB610\uB294 \uAC80\uC0C9\u2026",
2883
+ searchKbd = "\u2318K",
2884
+ open = true,
2885
+ className,
2886
+ ...props
2887
+ }, ref) => {
2888
+ if (!open) return null;
2889
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2890
+ "div",
2891
+ {
2892
+ ref,
2893
+ role: "dialog",
2894
+ "aria-label": "\uCEE4\uB9E8\uB4DC \uD314\uB808\uD2B8",
2895
+ className: cn(
2896
+ "w-[420px] max-w-full overflow-hidden rounded-lg border border-border-subtle bg-surface-default shadow-lg",
2897
+ className
2898
+ ),
2899
+ ...props,
2900
+ children: [
2901
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 border-b border-border-subtle px-4 py-3.5", children: [
2902
+ /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { size: 18, className: "text-text-subtle" }),
2903
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-sm text-text-subtle", children: placeholder }),
2904
+ searchKbd ? /* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: searchKbd }) : null
2905
+ ] }),
2906
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1.5", children: groups.map((group, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2907
+ group.heading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2.5 pb-1 pt-2 text-xs font-bold uppercase tracking-wide text-text-subtle", children: group.heading }) : null,
2908
+ group.items.map((item) => {
2909
+ const active = item.id === activeId;
2910
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2911
+ "button",
2912
+ {
2913
+ type: "button",
2914
+ onClick: () => onSelect?.(item),
2915
+ className: cn(
2916
+ "flex w-full items-center gap-2.5 rounded px-2.5 py-2 text-left text-sm [&>svg]:h-[17px] [&>svg]:w-[17px]",
2917
+ active ? "bg-brand-subtle text-brand-text" : "text-text-default hover:bg-surface-hover"
2918
+ ),
2919
+ children: [
2920
+ item.icon,
2921
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
2922
+ item.kbd ? /* @__PURE__ */ jsxRuntime.jsx(Kbd, { active, children: item.kbd }) : null
2923
+ ]
2924
+ },
2925
+ item.id
2926
+ );
2927
+ })
2928
+ ] }, group.heading ?? gi)) })
2929
+ ]
2930
+ }
2931
+ );
2932
+ }
2933
+ );
2934
+ CommandPalette.displayName = "CommandPalette";
2935
+ var AvatarWithPresence = React16__namespace.forwardRef(
2936
+ ({
2937
+ name,
2938
+ status = "online",
2939
+ color,
2940
+ src,
2941
+ size,
2942
+ ringClassName = "ring-surface-default",
2943
+ className
2944
+ }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("span", { ref, className: cn("relative inline-flex shrink-0", className), children: [
2945
+ /* @__PURE__ */ jsxRuntime.jsx(
2946
+ Avatar,
2947
+ {
2948
+ size,
2949
+ color,
2950
+ src,
2951
+ alt: name,
2952
+ className: cn("ring-0", status === "offline" && "opacity-[.55]")
2953
+ }
2954
+ ),
2955
+ /* @__PURE__ */ jsxRuntime.jsx(
2956
+ Presence,
2957
+ {
2958
+ status,
2959
+ size: "sm",
2960
+ className: cn("absolute -bottom-0.5 -right-0.5 ring-2", ringClassName)
2961
+ }
2962
+ )
2963
+ ] })
2964
+ );
2965
+ AvatarWithPresence.displayName = "AvatarWithPresence";
2966
+ var SidebarSection = React16__namespace.forwardRef(({ title, addable, onAdd, addLabel, className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className, ...props, children: [
2967
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-2 pb-1.5 pt-2.5 text-xs font-semibold text-text-subtle", children: [
2968
+ title,
2969
+ addable && /* @__PURE__ */ jsxRuntime.jsx(
2970
+ Button,
2971
+ {
2972
+ type: "button",
2973
+ variant: "ghost",
2974
+ size: "sm",
2975
+ onClick: onAdd,
2976
+ "aria-label": addLabel ?? `${title} \uCD94\uAC00`,
2977
+ className: "ml-auto h-6 w-6 rounded p-0 text-brand-solid",
2978
+ children: /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, { size: 16 })
2979
+ }
2980
+ )
2981
+ ] }),
2982
+ children
2983
+ ] }));
2984
+ SidebarSection.displayName = "SidebarSection";
2985
+ var SidebarChannel = React16__namespace.forwardRef(({ name, icon, locked, active, badge, className, ...props }, ref) => {
2986
+ const resolvedIcon = icon ?? (locked ? /* @__PURE__ */ jsxRuntime.jsx(LockIcon, { size: 17 }) : /* @__PURE__ */ jsxRuntime.jsx(HashIcon, { size: 17 }));
2987
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2988
+ "button",
2989
+ {
2990
+ ref,
2991
+ type: "button",
2992
+ "aria-current": active ? "page" : void 0,
2993
+ className: cn(
2994
+ "flex h-9 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2.5 text-left text-sm hover:bg-sidebar-accent",
2995
+ active ? "bg-sidebar-accent font-semibold text-sidebar-accent-fg" : "text-sidebar-fg",
2996
+ className
2997
+ ),
2998
+ ...props,
2999
+ children: [
3000
+ /* @__PURE__ */ jsxRuntime.jsx(
3001
+ "span",
3002
+ {
3003
+ className: cn(
3004
+ "inline-flex shrink-0",
3005
+ active ? "text-sidebar-accent-fg" : "text-sidebar-fg"
3006
+ ),
3007
+ children: resolvedIcon
3008
+ }
3009
+ ),
3010
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: name }),
3011
+ badge != null && badge !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto inline-flex h-[18px] min-w-[18px] shrink-0 items-center justify-center rounded-full bg-brand-solid px-1.5 text-[11px] font-semibold leading-none text-text-on-brand", children: badge })
3012
+ ]
3013
+ }
3014
+ );
3015
+ });
3016
+ SidebarChannel.displayName = "SidebarChannel";
3017
+ var SidebarDm = React16__namespace.forwardRef(
3018
+ ({ name, status = "online", color, avatarSrc, pinned, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
3019
+ "button",
3020
+ {
3021
+ ref,
3022
+ type: "button",
3023
+ className: cn(
3024
+ "flex h-9 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2.5 text-left text-sm text-sidebar-fg hover:bg-sidebar-accent",
3025
+ className
3026
+ ),
3027
+ ...props,
3028
+ children: [
3029
+ /* @__PURE__ */ jsxRuntime.jsx(
3030
+ AvatarWithPresence,
3031
+ {
3032
+ name,
3033
+ status,
3034
+ color,
3035
+ src: avatarSrc,
3036
+ size: "xs",
3037
+ ringClassName: "ring-sidebar-bg"
3038
+ }
3039
+ ),
3040
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: name }),
3041
+ pinned && /* @__PURE__ */ jsxRuntime.jsx(
3042
+ PinIcon,
3043
+ {
3044
+ size: 14,
3045
+ className: "ml-auto shrink-0 text-text-subtle",
3046
+ "aria-label": "\uACE0\uC815\uB428"
3047
+ }
3048
+ )
3049
+ ]
3050
+ }
3051
+ )
3052
+ );
3053
+ SidebarDm.displayName = "SidebarDm";
3054
+ var sidebarContainerVariants = classVarianceAuthority.cva(
3055
+ "border-border-subtle bg-sidebar-bg p-2",
3056
+ {
3057
+ variants: {
3058
+ variant: {
3059
+ panel: "w-[260px] max-w-full rounded-lg border",
3060
+ shell: "h-full border-r"
3061
+ }
3062
+ },
3063
+ defaultVariants: { variant: "panel" }
3064
+ }
3065
+ );
3066
+ var SidebarPanel = React16__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3067
+ "div",
3068
+ {
3069
+ ref,
3070
+ className: cn(sidebarContainerVariants({ variant: "panel" }), className),
3071
+ ...props
3072
+ }
3073
+ ));
3074
+ SidebarPanel.displayName = "SidebarPanel";
3075
+ var Sidebar = React16__namespace.forwardRef(
3076
+ ({ sections, variant = "panel", className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3077
+ "nav",
3078
+ {
3079
+ ref,
3080
+ className: cn(sidebarContainerVariants({ variant }), className),
3081
+ ...props,
3082
+ children: sections.map((section, si) => /* @__PURE__ */ jsxRuntime.jsx(
3083
+ SidebarSection,
3084
+ {
3085
+ title: section.title,
3086
+ addable: section.addable,
3087
+ onAdd: section.onAdd,
3088
+ children: section.items.map((item, ii) => {
3089
+ const key = item.id ?? item.name + ii;
3090
+ if (item.kind === "dm") {
3091
+ const { kind: kind2, id: id2, ...rest2 } = item;
3092
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarDm, { ...rest2 }, key);
3093
+ }
3094
+ const { kind, id, ...rest } = item;
3095
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarChannel, { ...rest }, key);
3096
+ })
3097
+ },
3098
+ section.title + si
3099
+ ))
3100
+ }
3101
+ )
3102
+ );
3103
+ Sidebar.displayName = "Sidebar";
3104
+ var List = React16__namespace.forwardRef(
3105
+ ({ className, bordered = true, divided = true, ...props }, ref) => {
3106
+ return /* @__PURE__ */ jsxRuntime.jsx(
3107
+ "ul",
3108
+ {
3109
+ ref,
3110
+ className: cn(
3111
+ "bg-surface-default px-4",
3112
+ bordered && "rounded-lg border border-border-subtle",
3113
+ divided && "[&>li+li]:border-t [&>li+li]:border-border-subtle",
3114
+ className
3115
+ ),
3116
+ ...props
3117
+ }
3118
+ );
3119
+ }
3120
+ );
3121
+ List.displayName = "List";
3122
+ var ListItem = React16__namespace.forwardRef(
3123
+ ({ className, leading, title, description, trailing, ...props }, ref) => {
3124
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3125
+ "li",
3126
+ {
3127
+ ref,
3128
+ className: cn("flex items-center gap-3 py-2.5", className),
3129
+ ...props,
3130
+ children: [
3131
+ leading != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative shrink-0", children: leading }) : null,
3132
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3133
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-semibold text-text-default", children: title }),
3134
+ description != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs text-text-subtle", children: description }) : null
3135
+ ] }),
3136
+ trailing != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: trailing }) : null
3137
+ ]
3138
+ }
3139
+ );
3140
+ }
3141
+ );
3142
+ ListItem.displayName = "ListItem";
3143
+ var SuccessCheck = React16__namespace.forwardRef(
3144
+ ({ size = 22, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3145
+ "span",
3146
+ {
3147
+ ref,
3148
+ className: cn(
3149
+ "inline-flex shrink-0 items-center justify-center rounded-full bg-brand-solid text-text-on-brand",
3150
+ className
3151
+ ),
3152
+ style: { width: size, height: size },
3153
+ ...props,
3154
+ children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon4, { size: Math.round(size * 0.6), strokeWidth: 3 })
3155
+ }
3156
+ )
3157
+ );
3158
+ SuccessCheck.displayName = "SuccessCheck";
3159
+ var separatorVariants = classVarianceAuthority.cva("shrink-0 border-border-default", {
3160
+ variants: {
3161
+ orientation: {
3162
+ horizontal: "w-full border-t",
3163
+ vertical: "h-full self-stretch border-l"
3164
+ }
3165
+ },
3166
+ defaultVariants: {
3167
+ orientation: "horizontal"
3168
+ }
3169
+ });
3170
+ var Separator = React16__namespace.forwardRef(
3171
+ ({ className, orientation = "horizontal", label, decorative = false, ...props }, ref) => {
3172
+ const resolvedOrientation = orientation === "vertical" ? "vertical" : "horizontal";
3173
+ const ariaOrientation = label != null ? "horizontal" : resolvedOrientation;
3174
+ const a11yProps = decorative ? { role: "none" } : { role: "separator", "aria-orientation": ariaOrientation };
3175
+ if (label != null) {
3176
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3177
+ "div",
3178
+ {
3179
+ ref,
3180
+ ...a11yProps,
3181
+ className: cn(
3182
+ "flex w-full items-center gap-3 text-sm text-text-subtle",
3183
+ className
3184
+ ),
3185
+ ...props,
3186
+ children: [
3187
+ /* @__PURE__ */ jsxRuntime.jsx(
3188
+ "span",
3189
+ {
3190
+ "aria-hidden": "true",
3191
+ className: "flex-1 border-t border-border-default"
3192
+ }
3193
+ ),
3194
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: label }),
3195
+ /* @__PURE__ */ jsxRuntime.jsx(
3196
+ "span",
3197
+ {
3198
+ "aria-hidden": "true",
3199
+ className: "flex-1 border-t border-border-default"
3200
+ }
3201
+ )
3202
+ ]
3203
+ }
3204
+ );
3205
+ }
3206
+ return /* @__PURE__ */ jsxRuntime.jsx(
3207
+ "div",
3208
+ {
3209
+ ref,
3210
+ ...a11yProps,
3211
+ className: cn(
3212
+ separatorVariants({ orientation: resolvedOrientation }),
3213
+ className
3214
+ ),
3215
+ ...props
3216
+ }
3217
+ );
3218
+ }
3219
+ );
3220
+ Separator.displayName = "Separator";
3221
+ var popoverContentVariants = classVarianceAuthority.cva(
3222
+ // content shell: raised surface · border · radius lg(8) · shadow-popover · padding
3223
+ "absolute z-50 w-max min-w-[220px] max-w-xs rounded-lg border border-border-default bg-surface-default p-4 text-sm text-text-default shadow-popover outline-none",
3224
+ {
3225
+ variants: {
3226
+ placement: {
3227
+ top: "bottom-full mb-2",
3228
+ bottom: "top-full mt-2",
3229
+ left: "right-full mr-2",
3230
+ right: "left-full ml-2"
3231
+ },
3232
+ align: {
3233
+ start: "",
3234
+ center: "",
3235
+ end: ""
3236
+ }
3237
+ },
3238
+ compoundVariants: [
3239
+ // vertical placements (top/bottom) → align along the X axis
3240
+ { placement: ["top", "bottom"], align: "start", class: "left-0" },
3241
+ {
3242
+ placement: ["top", "bottom"],
3243
+ align: "center",
3244
+ class: "left-1/2 -translate-x-1/2"
3245
+ },
3246
+ { placement: ["top", "bottom"], align: "end", class: "right-0" },
3247
+ // horizontal placements (left/right) → align along the Y axis
3248
+ { placement: ["left", "right"], align: "start", class: "top-0" },
3249
+ {
3250
+ placement: ["left", "right"],
3251
+ align: "center",
3252
+ class: "top-1/2 -translate-y-1/2"
3253
+ },
3254
+ { placement: ["left", "right"], align: "end", class: "bottom-0" }
3255
+ ],
3256
+ defaultVariants: {
3257
+ placement: "bottom",
3258
+ align: "center"
3259
+ }
3260
+ }
3261
+ );
3262
+ var Popover = React16__namespace.forwardRef(
3263
+ ({
3264
+ className,
3265
+ content,
3266
+ children,
3267
+ placement = "bottom",
3268
+ align = "center",
3269
+ open: openProp,
3270
+ defaultOpen = false,
3271
+ onOpenChange,
3272
+ ...props
3273
+ }, ref) => {
3274
+ const [uncontrolledOpen, setUncontrolledOpen] = React16__namespace.useState(defaultOpen);
3275
+ const isControlled = openProp !== void 0;
3276
+ const open = isControlled ? openProp : uncontrolledOpen;
3277
+ const innerRef = React16__namespace.useRef(null);
3278
+ React16__namespace.useImperativeHandle(ref, () => innerRef.current, []);
3279
+ const contentId = React16__namespace.useId();
3280
+ const setOpen = React16__namespace.useCallback(
3281
+ (next) => {
3282
+ if (!isControlled) setUncontrolledOpen(next);
3283
+ onOpenChange?.(next);
3284
+ },
3285
+ [isControlled, onOpenChange]
3286
+ );
3287
+ React16__namespace.useEffect(() => {
3288
+ if (!open) return;
3289
+ const onPointerDown = (event) => {
3290
+ const node = innerRef.current;
3291
+ if (node && !node.contains(event.target)) setOpen(false);
3292
+ };
3293
+ const onKeyDown = (event) => {
3294
+ if (event.key === "Escape") setOpen(false);
3295
+ };
3296
+ document.addEventListener("pointerdown", onPointerDown);
3297
+ document.addEventListener("keydown", onKeyDown);
3298
+ return () => {
3299
+ document.removeEventListener("pointerdown", onPointerDown);
3300
+ document.removeEventListener("keydown", onKeyDown);
3301
+ };
3302
+ }, [open, setOpen]);
3303
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3304
+ "div",
3305
+ {
3306
+ ref: innerRef,
3307
+ className: cn("relative inline-flex", className),
3308
+ ...props,
3309
+ children: [
3310
+ /* @__PURE__ */ jsxRuntime.jsx(
3311
+ "span",
3312
+ {
3313
+ className: "inline-flex",
3314
+ "aria-haspopup": "dialog",
3315
+ "aria-expanded": open,
3316
+ "aria-controls": open ? contentId : void 0,
3317
+ onClick: (event) => {
3318
+ if (!event.defaultPrevented) setOpen(!open);
3319
+ },
3320
+ children
3321
+ }
3322
+ ),
3323
+ open ? /* @__PURE__ */ jsxRuntime.jsx(
3324
+ "div",
3325
+ {
3326
+ id: contentId,
3327
+ role: "dialog",
3328
+ "aria-modal": "false",
3329
+ className: cn(popoverContentVariants({ placement, align })),
3330
+ children: content
3331
+ }
3332
+ ) : null
3333
+ ]
3334
+ }
3335
+ );
3336
+ }
3337
+ );
3338
+ Popover.displayName = "Popover";
3339
+ var fieldVariants = classVarianceAuthority.cva("flex gap-1.5", {
3340
+ variants: {
3341
+ orientation: {
3342
+ vertical: "flex-col",
3343
+ horizontal: "flex-row items-start gap-4"
3344
+ }
3345
+ },
3346
+ defaultVariants: {
3347
+ orientation: "vertical"
3348
+ }
3349
+ });
3350
+ var Field = React16__namespace.forwardRef(
3351
+ ({
3352
+ className,
3353
+ orientation = "vertical",
3354
+ label,
3355
+ htmlFor,
3356
+ required = false,
3357
+ optional = false,
3358
+ hint,
3359
+ error,
3360
+ children,
3361
+ ...props
3362
+ }, ref) => {
3363
+ const reactId = React16__namespace.useId();
3364
+ const controlId = htmlFor ?? reactId;
3365
+ const isHorizontal = orientation === "horizontal";
3366
+ const messageId = error ? `${controlId}-error` : hint ? `${controlId}-hint` : void 0;
3367
+ const control = React16__namespace.isValidElement(children) ? React16__namespace.cloneElement(children, {
3368
+ id: children.props.id ?? controlId,
3369
+ "aria-invalid": error ? true : children.props["aria-invalid"],
3370
+ "aria-describedby": [children.props["aria-describedby"], messageId].filter(Boolean).join(" ") || void 0
3371
+ }) : children;
3372
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3373
+ "div",
3374
+ {
3375
+ ref,
3376
+ className: cn(fieldVariants({ orientation }), className),
3377
+ ...props,
3378
+ children: [
3379
+ label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(isHorizontal && "w-40 shrink-0 pt-2"), children: /* @__PURE__ */ jsxRuntime.jsxs(
3380
+ "label",
3381
+ {
3382
+ htmlFor: controlId,
3383
+ className: "inline-flex items-center gap-1.5 text-sm font-medium text-text-default",
3384
+ children: [
3385
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
3386
+ label,
3387
+ required ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "text-danger-text", children: "*" }) : null
3388
+ ] }),
3389
+ optional && !required ? /* @__PURE__ */ jsxRuntime.jsx(Label, { variant: "neutral", children: "\uC120\uD0DD" }) : null
3390
+ ]
3391
+ }
3392
+ ) }) : null,
3393
+ /* @__PURE__ */ jsxRuntime.jsxs(
3394
+ "div",
3395
+ {
3396
+ className: cn(
3397
+ "flex min-w-0 flex-col gap-1.5",
3398
+ isHorizontal && "flex-1"
3399
+ ),
3400
+ children: [
3401
+ control,
3402
+ error ? /* @__PURE__ */ jsxRuntime.jsx(
3403
+ "p",
3404
+ {
3405
+ id: `${controlId}-error`,
3406
+ className: "flex items-center gap-1 text-sm text-danger-text",
3407
+ children: error
3408
+ }
3409
+ ) : hint ? /* @__PURE__ */ jsxRuntime.jsx(
3410
+ "p",
3411
+ {
3412
+ id: `${controlId}-hint`,
3413
+ className: "flex items-center gap-1 text-sm text-text-subtle",
3414
+ children: hint
3415
+ }
3416
+ ) : null
3417
+ ]
3418
+ }
3419
+ )
3420
+ ]
3421
+ }
3422
+ );
3423
+ }
3424
+ );
3425
+ Field.displayName = "Field";
3426
+ var accessoryButtonClass = "inline-flex size-6 shrink-0 items-center justify-center rounded text-text-subtle transition-colors hover:bg-surface-hover hover:text-text-default active:bg-surface-pressed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-border disabled:pointer-events-none disabled:text-text-disabled";
3427
+ var SearchField = React16__namespace.forwardRef(
3428
+ ({
3429
+ className,
3430
+ value,
3431
+ defaultValue,
3432
+ onValueChange,
3433
+ placeholder = "\uAC80\uC0C9",
3434
+ resultCount,
3435
+ onPrev,
3436
+ onNext,
3437
+ onClear,
3438
+ size,
3439
+ disabled,
3440
+ ...props
3441
+ }, ref) => {
3442
+ const isControlled = value !== void 0;
3443
+ const [internalValue, setInternalValue] = React16__namespace.useState(
3444
+ defaultValue ?? ""
3445
+ );
3446
+ const currentValue = isControlled ? value : internalValue;
3447
+ const innerRef = React16__namespace.useRef(null);
3448
+ React16__namespace.useImperativeHandle(ref, () => innerRef.current);
3449
+ const commit = (next) => {
3450
+ if (!isControlled) setInternalValue(next);
3451
+ onValueChange?.(next);
3452
+ };
3453
+ const handleClear = () => {
3454
+ commit("");
3455
+ onClear?.();
3456
+ innerRef.current?.focus();
3457
+ };
3458
+ const hasCount = typeof resultCount === "number";
3459
+ const hasNav = Boolean(onPrev || onNext);
3460
+ const showClear = Boolean(onClear) && currentValue.length > 0;
3461
+ const showAccessories = hasCount || hasNav || showClear;
3462
+ const showDivider = hasCount && (hasNav || showClear);
3463
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3464
+ "div",
3465
+ {
3466
+ className: cn(
3467
+ inputVariants({ inputSize: size }),
3468
+ "cursor-text focus-within:border-border-focus focus-within:ring-2 focus-within:ring-brand-border focus-within:ring-offset-2 focus-within:ring-offset-bg-base",
3469
+ disabled && "cursor-not-allowed bg-surface-sunken text-text-disabled",
3470
+ className
3471
+ ),
3472
+ children: [
3473
+ /* @__PURE__ */ jsxRuntime.jsx(
3474
+ "span",
3475
+ {
3476
+ "aria-hidden": "true",
3477
+ className: "flex size-5 shrink-0 items-center justify-center text-text-subtle [&_svg]:size-5",
3478
+ children: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, {})
3479
+ }
3480
+ ),
3481
+ /* @__PURE__ */ jsxRuntime.jsx(
3482
+ "input",
3483
+ {
3484
+ ref: innerRef,
3485
+ type: "search",
3486
+ role: "searchbox",
3487
+ value: currentValue,
3488
+ placeholder,
3489
+ disabled,
3490
+ onChange: (event) => commit(event.target.value),
3491
+ className: "h-full w-full min-w-0 bg-transparent text-text-default outline-none placeholder:text-text-subtle disabled:cursor-not-allowed disabled:text-text-disabled [&::-webkit-search-cancel-button]:hidden",
3492
+ ...props
3493
+ }
3494
+ ),
3495
+ showAccessories ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
3496
+ hasCount ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 whitespace-nowrap text-sm tabular-nums text-text-subtle", children: [
3497
+ resultCount,
3498
+ "\uAC74"
3499
+ ] }) : null,
3500
+ showDivider ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "h-4 w-px bg-border-subtle" }) : null,
3501
+ onPrev ? /* @__PURE__ */ jsxRuntime.jsx(
3502
+ "button",
3503
+ {
3504
+ type: "button",
3505
+ "aria-label": "\uC774\uC804 \uACB0\uACFC",
3506
+ disabled,
3507
+ onClick: onPrev,
3508
+ className: accessoryButtonClass,
3509
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeftIcon2, { size: 16 })
3510
+ }
3511
+ ) : null,
3512
+ onNext ? /* @__PURE__ */ jsxRuntime.jsx(
3513
+ "button",
3514
+ {
3515
+ type: "button",
3516
+ "aria-label": "\uB2E4\uC74C \uACB0\uACFC",
3517
+ disabled,
3518
+ onClick: onNext,
3519
+ className: accessoryButtonClass,
3520
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon2, { size: 16 })
3521
+ }
3522
+ ) : null,
3523
+ showClear ? /* @__PURE__ */ jsxRuntime.jsx(
3524
+ "button",
3525
+ {
3526
+ type: "button",
3527
+ "aria-label": "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
3528
+ disabled,
3529
+ onClick: handleClear,
3530
+ className: accessoryButtonClass,
3531
+ children: /* @__PURE__ */ jsxRuntime.jsx(XIcon, { size: 16 })
3532
+ }
3533
+ ) : null
3534
+ ] }) : null
3535
+ ]
3536
+ }
3537
+ );
3538
+ }
3539
+ );
3540
+ SearchField.displayName = "SearchField";
3541
+ var bannerVariants = classVarianceAuthority.cva(
3542
+ "flex w-full items-start gap-3 rounded-lg border p-4 text-sm",
3543
+ {
3544
+ variants: {
3545
+ variant: {
3546
+ neutral: "border-border-default bg-surface-sunken text-text-default",
3547
+ brand: "border-brand-border bg-brand-subtle text-brand-text",
3548
+ danger: "border-danger-border bg-danger-subtle text-danger-text"
3549
+ }
3550
+ },
3551
+ defaultVariants: {
3552
+ variant: "neutral"
3553
+ }
3554
+ }
3555
+ );
3556
+ var Banner = React16__namespace.forwardRef(
3557
+ ({
3558
+ className,
3559
+ variant,
3560
+ icon,
3561
+ title,
3562
+ dismissible = false,
3563
+ onDismiss,
3564
+ children,
3565
+ role = "status",
3566
+ ...props
3567
+ }, ref) => {
3568
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3569
+ "div",
3570
+ {
3571
+ ref,
3572
+ role,
3573
+ className: cn(bannerVariants({ variant }), className),
3574
+ ...props,
3575
+ children: [
3576
+ icon ? /* @__PURE__ */ jsxRuntime.jsx(
3577
+ "span",
3578
+ {
3579
+ "aria-hidden": "true",
3580
+ className: "mt-0.5 flex size-5 shrink-0 items-center justify-center [&_svg]:size-5",
3581
+ children: icon
3582
+ }
3583
+ ) : null,
3584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3585
+ title ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold leading-5", children: title }) : null,
3586
+ children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("leading-5", title && "mt-1"), children }) : null
3587
+ ] }),
3588
+ dismissible ? /* @__PURE__ */ jsxRuntime.jsx(
3589
+ "button",
3590
+ {
3591
+ type: "button",
3592
+ "aria-label": "\uB2EB\uAE30",
3593
+ onClick: onDismiss,
3594
+ className: "-m-1 inline-flex size-6 shrink-0 items-center justify-center rounded text-current opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-border focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base",
3595
+ children: /* @__PURE__ */ jsxRuntime.jsx(XIcon, { className: "size-4" })
3596
+ }
3597
+ ) : null
3598
+ ]
3599
+ }
3600
+ );
3601
+ }
3602
+ );
3603
+ Banner.displayName = "Banner";
3604
+
3605
+ exports.AVATAR_COLORS = AVATAR_COLORS;
3606
+ exports.Accordion = Accordion;
3607
+ exports.AccordionItem = AccordionItem;
3608
+ exports.Alert = Alert;
3609
+ exports.AlertDescription = AlertDescription;
3610
+ exports.AlertTitle = AlertTitle;
3611
+ exports.Avatar = Avatar;
3612
+ exports.AvatarFallback = AvatarFallback;
3613
+ exports.AvatarGroup = AvatarGroup;
3614
+ exports.AvatarImage = AvatarImage;
3615
+ exports.AvatarWithPresence = AvatarWithPresence;
3616
+ exports.Banner = Banner;
3617
+ exports.Button = Button;
3618
+ exports.Card = Card;
3619
+ exports.CardContent = CardContent;
3620
+ exports.CardDescription = CardDescription;
3621
+ exports.CardFooter = CardFooter;
3622
+ exports.CardHeader = CardHeader;
3623
+ exports.CardTitle = CardTitle;
3624
+ exports.Checkbox = Checkbox;
3625
+ exports.Chip = Chip;
3626
+ exports.CommandPalette = CommandPalette;
3627
+ exports.Dialog = Dialog;
3628
+ exports.DialogAction = Button;
3629
+ exports.DialogBody = DialogBody;
3630
+ exports.DialogDescription = DialogDescription;
3631
+ exports.DialogFooter = DialogFooter;
3632
+ exports.DialogHeader = DialogHeader;
3633
+ exports.DialogOverlay = DialogOverlay;
3634
+ exports.DialogTitle = DialogTitle;
3635
+ exports.DropdownMenu = DropdownMenu;
3636
+ exports.DropdownMenuContent = DropdownMenuContent;
3637
+ exports.DropdownMenuEmpty = DropdownMenuEmpty;
3638
+ exports.DropdownMenuItem = DropdownMenuItem;
3639
+ exports.DropdownMenuLabel = DropdownMenuLabel;
3640
+ exports.DropdownMenuSeparator = DropdownMenuSeparator;
3641
+ exports.DropdownMenuTrigger = DropdownMenuTrigger;
3642
+ exports.EmptyState = EmptyState;
3643
+ exports.Field = Field;
3644
+ exports.Input = Input;
3645
+ exports.Kbd = Kbd;
3646
+ exports.KpiRow = KpiRow;
3647
+ exports.Label = Label;
3648
+ exports.List = List;
3649
+ exports.ListItem = ListItem;
3650
+ exports.PRESENCE_LABEL = PRESENCE_LABEL;
3651
+ exports.Pagination = Pagination;
3652
+ exports.PaginationEllipsis = PaginationEllipsis;
3653
+ exports.PaginationItem = PaginationItem;
3654
+ exports.PaginationNext = PaginationNext;
3655
+ exports.PaginationPrevious = PaginationPrevious;
3656
+ exports.Popover = Popover;
3657
+ exports.Presence = Presence;
3658
+ exports.Progress = Progress;
3659
+ exports.ProgressList = ProgressList;
3660
+ exports.Radio = Radio;
3661
+ exports.RadioGroup = RadioGroup;
3662
+ exports.Ring = Ring;
3663
+ exports.ScrollArea = ScrollArea;
3664
+ exports.ScrollBar = ScrollBar;
3665
+ exports.SearchField = SearchField;
3666
+ exports.SegmentedControl = SegmentedControl;
3667
+ exports.Select = Select;
3668
+ exports.Separator = Separator;
3669
+ exports.Sheet = Sheet;
3670
+ exports.SheetBody = SheetBody;
3671
+ exports.SheetDescription = SheetDescription;
3672
+ exports.SheetFooter = SheetFooter;
3673
+ exports.SheetHandle = SheetHandle;
3674
+ exports.SheetHeader = SheetHeader;
3675
+ exports.SheetTitle = SheetTitle;
3676
+ exports.Sidebar = Sidebar;
3677
+ exports.SidebarChannel = SidebarChannel;
3678
+ exports.SidebarDm = SidebarDm;
3679
+ exports.SidebarPanel = SidebarPanel;
3680
+ exports.SidebarSection = SidebarSection;
3681
+ exports.Skeleton = Skeleton;
3682
+ exports.StackBar = StackBar;
3683
+ exports.SuccessCheck = SuccessCheck;
3684
+ exports.Table = Table;
3685
+ exports.TableBody = TableBody;
3686
+ exports.TableCaption = TableCaption;
3687
+ exports.TableCell = TableCell;
3688
+ exports.TableHead = TableHead;
3689
+ exports.TableHeader = TableHeader;
3690
+ exports.TableRow = TableRow;
3691
+ exports.Tabs = Tabs;
3692
+ exports.TabsContent = TabsContent;
3693
+ exports.TabsList = TabsList;
3694
+ exports.TabsTrigger = TabsTrigger;
3695
+ exports.Textarea = Textarea;
3696
+ exports.Toast = Toast;
3697
+ exports.Toggle = Toggle;
3698
+ exports.Tooltip = Tooltip;
3699
+ exports.WorkHoursBar = WorkHoursBar;
3700
+ exports.alertVariants = alertVariants;
3701
+ exports.avatarVariants = avatarVariants;
3702
+ exports.bannerVariants = bannerVariants;
3703
+ exports.buildPageRange = buildPageRange;
3704
+ exports.buttonVariants = buttonVariants;
3705
+ exports.cardVariants = cardVariants;
3706
+ exports.checkboxVariants = checkboxVariants;
3707
+ exports.chipVariants = chipVariants;
3708
+ exports.cn = cn;
3709
+ exports.dialogPanelVariants = dialogPanelVariants;
3710
+ exports.dropdownMenuContentVariants = dropdownMenuContentVariants;
3711
+ exports.dropdownMenuItemVariants = dropdownMenuItemVariants;
3712
+ exports.fieldVariants = fieldVariants;
3713
+ exports.inputVariants = inputVariants;
3714
+ exports.labelVariants = labelVariants;
3715
+ exports.paginationItemVariants = paginationItemVariants;
3716
+ exports.popoverContentVariants = popoverContentVariants;
3717
+ exports.progressFillVariants = progressFillVariants;
3718
+ exports.progressTrackVariants = progressTrackVariants;
3719
+ exports.radioVariants = radioVariants;
3720
+ exports.segmentContainerVariants = segmentContainerVariants;
3721
+ exports.segmentItemVariants = segmentItemVariants;
3722
+ exports.selectTriggerVariants = selectTriggerVariants;
3723
+ exports.separatorVariants = separatorVariants;
3724
+ exports.sheetOverlayVariants = sheetOverlayVariants;
3725
+ exports.sheetPanelVariants = sheetPanelVariants;
3726
+ exports.sidebarContainerVariants = sidebarContainerVariants;
3727
+ exports.skeletonVariants = skeletonVariants;
3728
+ exports.tableRowVariants = tableRowVariants;
3729
+ exports.tableVariants = tableVariants;
3730
+ exports.tabsListVariants = tabsListVariants;
3731
+ exports.tabsTriggerVariants = tabsTriggerVariants;
3732
+ exports.textareaVariants = textareaVariants;
3733
+ exports.toastVariants = toastVariants;
3734
+ exports.toggleThumbVariants = toggleThumbVariants;
3735
+ exports.toggleTrackVariants = toggleTrackVariants;
3736
+ exports.tooltipArrowVariants = tooltipArrowVariants;
3737
+ exports.tooltipContentVariants = tooltipContentVariants;
3738
+ //# sourceMappingURL=index.js.map
3739
+ //# sourceMappingURL=index.js.map