@olundot/ui 0.16.0 → 0.17.1
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/CHANGELOG.md +33 -0
- package/dist/index.d.ts +129 -26
- package/dist/index.js +909 -384
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -213,12 +213,13 @@ var buttonVariants = cva(
|
|
|
213
213
|
},
|
|
214
214
|
size: {
|
|
215
215
|
// Cross-control height map: Button sm/md/lg match field controls sm/md/lg (30/32/36px).
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
// Height comes from h-* alone — no vertical padding (py-12 inside h-32 left a 6px content box).
|
|
217
|
+
xs: "h-[28px] gap-[6px] px-pad-compact-x text-[12px] [&_svg]:size-[14px] [&_svg]:stroke-[1.75]",
|
|
218
|
+
sm: "h-[30px] gap-[6px] px-pad-compact-x text-body-sm [&_svg]:size-[16px]",
|
|
219
|
+
md: "h-[32px] gap-[6px] px-pad-default-x text-body-sm [&_svg]:size-[16px]",
|
|
220
|
+
lg: "h-[36px] gap-[var(--space-2)] px-pad-default-x text-[15px] [&_svg]:size-[18px]",
|
|
220
221
|
xl: "h-[40px] gap-[var(--space-2)] px-5 text-[15px] [&_svg]:size-[18px]",
|
|
221
|
-
default: "h-[32px] gap-[6px] px-pad-default-x
|
|
222
|
+
default: "h-[32px] gap-[6px] px-pad-default-x text-body-sm [&_svg]:size-[16px]",
|
|
222
223
|
icon: "size-[36px] p-0 [&_svg]:size-[18px]",
|
|
223
224
|
"icon-xs": "size-[32px] p-0 [&_svg]:size-[14px] [&_svg]:stroke-[1.75]"
|
|
224
225
|
}
|
|
@@ -403,13 +404,13 @@ var selectSurfaceClassNames = {
|
|
|
403
404
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
404
405
|
var inputVariants = cva2(
|
|
405
406
|
[
|
|
406
|
-
"flex rounded-[var(--radius-
|
|
407
|
+
"flex rounded-[var(--radius-md)] border",
|
|
407
408
|
"border-[var(--border)] text-foreground",
|
|
408
409
|
"placeholder:text-text-disabled",
|
|
409
410
|
"transition-[border-color,box-shadow] motion-reduce:transition-none",
|
|
410
411
|
"focus:outline-none focus:border-[var(--focus-ring)] focus:shadow-[0_0_0_1px_var(--focus-ring)]",
|
|
411
412
|
"disabled:cursor-not-allowed disabled:border-[var(--border-subtle)] disabled:bg-[var(--action-disabled-bg)] disabled:text-text-disabled",
|
|
412
|
-
"read-only:border-[var(--border-subtle)] read-only:bg-[var(--bg-
|
|
413
|
+
"read-only:border-[var(--border-subtle)] read-only:bg-[var(--bg-inset)] read-only:focus:border-[var(--border-subtle)] read-only:focus:shadow-none",
|
|
413
414
|
"file:border-0 file:bg-transparent file:text-sm file:font-medium",
|
|
414
415
|
"data-[state=error]:border-[var(--error)] data-[state=error]:focus:shadow-[0_0_0_1px_var(--error)]",
|
|
415
416
|
"data-[state=success]:border-[var(--success)] data-[state=success]:focus:shadow-[0_0_0_1px_var(--success)]",
|
|
@@ -1125,14 +1126,14 @@ import { AlertCircle as AlertCircle2, CheckCircle2 as CheckCircle22 } from "luci
|
|
|
1125
1126
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1126
1127
|
var textareaVariants = cva4(
|
|
1127
1128
|
[
|
|
1128
|
-
"flex resize-y rounded-[var(--radius-
|
|
1129
|
+
"flex resize-y rounded-[var(--radius-md)] border",
|
|
1129
1130
|
"border-[var(--border)] text-foreground",
|
|
1130
1131
|
"px-pad-default-x py-pad-default-y text-sm leading-normal",
|
|
1131
1132
|
"placeholder:text-text-disabled",
|
|
1132
1133
|
"transition-[border-color,box-shadow] motion-reduce:transition-none",
|
|
1133
1134
|
"focus:outline-none focus:border-[var(--focus-ring)] focus:shadow-[0_0_0_1px_var(--focus-ring)]",
|
|
1134
1135
|
"disabled:cursor-not-allowed disabled:border-[var(--border-subtle)] disabled:bg-[var(--action-disabled-bg)] disabled:text-text-disabled",
|
|
1135
|
-
"read-only:cursor-default read-only:border-[var(--border-subtle)] read-only:bg-[var(--bg-
|
|
1136
|
+
"read-only:cursor-default read-only:border-[var(--border-subtle)] read-only:bg-[var(--bg-inset)] read-only:text-text-secondary read-only:focus:border-[var(--border-subtle)] read-only:focus:shadow-none",
|
|
1136
1137
|
"data-[state=error]:border-[var(--error)] data-[state=error]:focus:shadow-[0_0_0_1px_var(--error)]",
|
|
1137
1138
|
"data-[state=success]:border-[var(--success)] data-[state=success]:focus:shadow-[0_0_0_1px_var(--success)]",
|
|
1138
1139
|
"aria-[invalid=true]:border-[var(--error)] aria-[invalid=true]:focus:shadow-[0_0_0_1px_var(--error)]",
|
|
@@ -1358,7 +1359,7 @@ import { Select as SelectPrimitive } from "radix-ui";
|
|
|
1358
1359
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1359
1360
|
var selectVariants = cva5(
|
|
1360
1361
|
[
|
|
1361
|
-
"group flex cursor-pointer items-center justify-between rounded-[var(--radius-
|
|
1362
|
+
"group flex cursor-pointer items-center justify-between rounded-[var(--radius-md)] border",
|
|
1362
1363
|
"border-[var(--border)] text-foreground",
|
|
1363
1364
|
"[border-color:var(--border)] [color:var(--text-primary)]",
|
|
1364
1365
|
"transition-[border-color,box-shadow,background-color,color] motion-reduce:transition-none",
|
|
@@ -2940,7 +2941,7 @@ var tabsListVariants = cva8(
|
|
|
2940
2941
|
variants: {
|
|
2941
2942
|
variant: {
|
|
2942
2943
|
line: "",
|
|
2943
|
-
contained: "rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--bg-
|
|
2944
|
+
contained: "rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--bg-inset)] p-[var(--space-1)]"
|
|
2944
2945
|
},
|
|
2945
2946
|
orientation: {
|
|
2946
2947
|
horizontal: "",
|
|
@@ -3012,7 +3013,7 @@ var tabsBadgeVariants = cva8(
|
|
|
3012
3013
|
[
|
|
3013
3014
|
"inline-flex h-[18px] min-w-[18px] items-center justify-center",
|
|
3014
3015
|
"rounded-[var(--radius-full)] border border-[var(--border-subtle)]",
|
|
3015
|
-
"bg-[var(--bg-
|
|
3016
|
+
"bg-[var(--bg-inset)] px-[var(--space-1)]",
|
|
3016
3017
|
"font-[family-name:var(--font-display)] text-xs font-semibold leading-none tabular-nums",
|
|
3017
3018
|
// R14 — Badge는 metadata, 추가 marker(filled wash)가 아니다. marker 종류는
|
|
3018
3019
|
// trigger underline 하나(active-state doctrine). single-hue-family: active 시 인접
|
|
@@ -3818,7 +3819,7 @@ var chipVariants = cva9(
|
|
|
3818
3819
|
{
|
|
3819
3820
|
pressed: true,
|
|
3820
3821
|
tone: "muted",
|
|
3821
|
-
className: "border-[var(--border-strong)] bg-[var(--bg-
|
|
3822
|
+
className: "border-[var(--border-strong)] bg-[var(--bg-inset)] text-text-secondary"
|
|
3822
3823
|
}
|
|
3823
3824
|
],
|
|
3824
3825
|
defaultVariants: {
|
|
@@ -3838,12 +3839,12 @@ var chipCountVariants = cva9(
|
|
|
3838
3839
|
{
|
|
3839
3840
|
variants: {
|
|
3840
3841
|
tone: {
|
|
3841
|
-
neutral: "bg-[var(--bg-
|
|
3842
|
+
neutral: "bg-[var(--bg-inset)] text-text-tertiary",
|
|
3842
3843
|
accent: "bg-[var(--accent-pop)] text-[var(--accent-on-fill)]",
|
|
3843
3844
|
success: "bg-[var(--success)] text-[var(--success-contrast)]",
|
|
3844
3845
|
warning: "bg-[var(--warning)] text-[var(--warning-contrast)]",
|
|
3845
3846
|
danger: "bg-[var(--error)] text-[var(--error-contrast)]",
|
|
3846
|
-
muted: "bg-[var(--bg-
|
|
3847
|
+
muted: "bg-[var(--bg-inset)] text-text-tertiary"
|
|
3847
3848
|
},
|
|
3848
3849
|
size: {
|
|
3849
3850
|
sm: "h-[var(--space-4)] text-xs",
|
|
@@ -3970,13 +3971,16 @@ var iconButtonVariants = cva10(
|
|
|
3970
3971
|
variant: {
|
|
3971
3972
|
ghost: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
3972
3973
|
outline: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-text-secondary hover:border-[var(--border-strong)] hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
3973
|
-
subtle: "border-transparent bg-[var(--bg-
|
|
3974
|
+
subtle: "border-transparent bg-[var(--bg-inset)] text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
|
|
3974
3975
|
danger: "border-transparent bg-[var(--error-bg)] text-[var(--error)] hover:bg-[var(--action-hover)]"
|
|
3975
3976
|
},
|
|
3977
|
+
// Hit area = 44px on every size. The ::before is absolutely positioned, so its
|
|
3978
|
+
// inset is measured from the padding box — inside the 1px border every variant
|
|
3979
|
+
// carries (transparent or not). Inset = (44 - (size - 2 × 1px border)) / 2.
|
|
3976
3980
|
size: {
|
|
3977
|
-
sm: "size-[28px] before:-inset-[
|
|
3978
|
-
md: "size-[32px] before:-inset-[
|
|
3979
|
-
lg: "size-[40px] before:-inset-[
|
|
3981
|
+
sm: "size-[28px] before:-inset-[9px]",
|
|
3982
|
+
md: "size-[32px] before:-inset-[7px]",
|
|
3983
|
+
lg: "size-[40px] before:-inset-[3px]"
|
|
3980
3984
|
},
|
|
3981
3985
|
pressed: {
|
|
3982
3986
|
true: "",
|
|
@@ -5327,7 +5331,7 @@ function SkeletonRows({
|
|
|
5327
5331
|
"div",
|
|
5328
5332
|
{
|
|
5329
5333
|
className: cn(
|
|
5330
|
-
"h-[14px] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-
|
|
5334
|
+
"h-[14px] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]",
|
|
5331
5335
|
columnIndex === 0 ? "w-[72%]" : column.align === "right" ? "ml-auto w-[54%]" : "w-[62%]"
|
|
5332
5336
|
)
|
|
5333
5337
|
}
|
|
@@ -5353,9 +5357,9 @@ function MobileSkeletonCards({ count }) {
|
|
|
5353
5357
|
"data-slot": "data-table-mobile-skeleton-card",
|
|
5354
5358
|
className: "flex flex-col gap-[var(--space-2)] border-t border-[var(--border-subtle)] px-[var(--space-4)] py-[var(--space-4)]",
|
|
5355
5359
|
children: [
|
|
5356
|
-
/* @__PURE__ */ jsx31("div", { className: "h-[14px] w-[72%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-
|
|
5357
|
-
/* @__PURE__ */ jsx31("div", { className: "h-[12px] w-[56%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-
|
|
5358
|
-
/* @__PURE__ */ jsx31("div", { className: "h-[12px] w-[64%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-
|
|
5360
|
+
/* @__PURE__ */ jsx31("div", { className: "h-[14px] w-[72%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
|
|
5361
|
+
/* @__PURE__ */ jsx31("div", { className: "h-[12px] w-[56%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
|
|
5362
|
+
/* @__PURE__ */ jsx31("div", { className: "h-[12px] w-[64%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" })
|
|
5359
5363
|
]
|
|
5360
5364
|
},
|
|
5361
5365
|
rowIndex
|
|
@@ -5363,6 +5367,329 @@ function MobileSkeletonCards({ count }) {
|
|
|
5363
5367
|
}
|
|
5364
5368
|
);
|
|
5365
5369
|
}
|
|
5370
|
+
var rowLinkHostClass = "relative [&_:is(a,button,input,select,textarea,label,[role=button],[role=checkbox]):not([data-slot=data-table-row-link])]:relative [&_:is(a,button,input,select,textarea,label,[role=button],[role=checkbox]):not([data-slot=data-table-row-link])]:z-[1]";
|
|
5371
|
+
var rowLinkClass = cn(
|
|
5372
|
+
"text-inherit no-underline outline-none after:absolute after:inset-0 after:content-['']",
|
|
5373
|
+
"focus-visible:after:ring-2 focus-visible:after:ring-inset focus-visible:after:ring-[var(--focus-ring)]"
|
|
5374
|
+
);
|
|
5375
|
+
function useActivationHandlers({ row, href, activatable, onActivate }) {
|
|
5376
|
+
return {
|
|
5377
|
+
onClick: (event) => {
|
|
5378
|
+
if (!activatable || isInteractiveTarget(event.target)) {
|
|
5379
|
+
return;
|
|
5380
|
+
}
|
|
5381
|
+
onActivate(row, href, event);
|
|
5382
|
+
},
|
|
5383
|
+
onKeyDown: (event) => {
|
|
5384
|
+
if (!activatable || isInteractiveTarget(event.target)) {
|
|
5385
|
+
return;
|
|
5386
|
+
}
|
|
5387
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
5388
|
+
event.preventDefault();
|
|
5389
|
+
onActivate(row, href, event);
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
};
|
|
5393
|
+
}
|
|
5394
|
+
function DataTableRowView({
|
|
5395
|
+
row,
|
|
5396
|
+
rowId,
|
|
5397
|
+
columns,
|
|
5398
|
+
selectable,
|
|
5399
|
+
selected,
|
|
5400
|
+
visuallySelected,
|
|
5401
|
+
href,
|
|
5402
|
+
activatable,
|
|
5403
|
+
LinkComponent,
|
|
5404
|
+
onToggle,
|
|
5405
|
+
onActivate,
|
|
5406
|
+
onRowContextMenu,
|
|
5407
|
+
gridTemplateColumns,
|
|
5408
|
+
ariaRowIndex
|
|
5409
|
+
}) {
|
|
5410
|
+
const linked = Boolean(LinkComponent && href);
|
|
5411
|
+
const handlers = useActivationHandlers({ row, href, activatable, onActivate });
|
|
5412
|
+
return /* @__PURE__ */ jsxs30(
|
|
5413
|
+
"div",
|
|
5414
|
+
{
|
|
5415
|
+
"data-slot": "data-table-row",
|
|
5416
|
+
"data-row-id": rowId,
|
|
5417
|
+
"data-href": href,
|
|
5418
|
+
role: "row",
|
|
5419
|
+
"aria-rowindex": ariaRowIndex,
|
|
5420
|
+
tabIndex: activatable ? 0 : void 0,
|
|
5421
|
+
className: cn(
|
|
5422
|
+
dataTableRowVariants({ interactive: activatable || linked, selected: visuallySelected }),
|
|
5423
|
+
linked ? rowLinkHostClass : null
|
|
5424
|
+
),
|
|
5425
|
+
style: { gridTemplateColumns },
|
|
5426
|
+
onContextMenu: (event) => onRowContextMenu?.(rowId, event),
|
|
5427
|
+
onClick: handlers.onClick,
|
|
5428
|
+
onKeyDown: handlers.onKeyDown,
|
|
5429
|
+
children: [
|
|
5430
|
+
selectable ? /* @__PURE__ */ jsx31("div", { role: "cell", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx31(
|
|
5431
|
+
Checkbox,
|
|
5432
|
+
{
|
|
5433
|
+
"aria-label": `${String(row[columns[0]?.key] ?? rowId)} \uD589 \uC120\uD0DD`,
|
|
5434
|
+
checked: selected,
|
|
5435
|
+
onCheckedChange: (nextChecked) => onToggle(rowId, nextChecked === true),
|
|
5436
|
+
children: /* @__PURE__ */ jsxs30("span", { className: "sr-only", children: [
|
|
5437
|
+
rowId,
|
|
5438
|
+
" \uD589 \uC120\uD0DD"
|
|
5439
|
+
] })
|
|
5440
|
+
}
|
|
5441
|
+
) }) : null,
|
|
5442
|
+
columns.map((column, columnIndex) => {
|
|
5443
|
+
const align = column.align ?? "left";
|
|
5444
|
+
const content = getRenderedCell(row, column);
|
|
5445
|
+
return /* @__PURE__ */ jsx31(
|
|
5446
|
+
"div",
|
|
5447
|
+
{
|
|
5448
|
+
"data-slot": "data-table-cell",
|
|
5449
|
+
role: "cell",
|
|
5450
|
+
className: cn(
|
|
5451
|
+
"flex min-w-0 items-center px-[var(--space-4)] py-[var(--space-2)]",
|
|
5452
|
+
alignmentClass[align],
|
|
5453
|
+
column.tabular ? "font-[family-name:var(--font-display)] tabular-nums" : null,
|
|
5454
|
+
align === "right" ? "text-text-tertiary" : null
|
|
5455
|
+
),
|
|
5456
|
+
children: /* @__PURE__ */ jsx31("span", { className: "min-w-0 truncate", children: linked && columnIndex === 0 && LinkComponent ? /* @__PURE__ */ jsx31(LinkComponent, { href, "data-slot": "data-table-row-link", className: rowLinkClass, children: content }) : content })
|
|
5457
|
+
},
|
|
5458
|
+
column.key
|
|
5459
|
+
);
|
|
5460
|
+
})
|
|
5461
|
+
]
|
|
5462
|
+
}
|
|
5463
|
+
);
|
|
5464
|
+
}
|
|
5465
|
+
function DataTableMobileCardView({
|
|
5466
|
+
row,
|
|
5467
|
+
rowId,
|
|
5468
|
+
columns,
|
|
5469
|
+
selectable,
|
|
5470
|
+
selected,
|
|
5471
|
+
visuallySelected,
|
|
5472
|
+
href,
|
|
5473
|
+
activatable,
|
|
5474
|
+
LinkComponent,
|
|
5475
|
+
onToggle,
|
|
5476
|
+
onActivate,
|
|
5477
|
+
onRowContextMenu,
|
|
5478
|
+
ariaPosInSet,
|
|
5479
|
+
ariaSetSize
|
|
5480
|
+
}) {
|
|
5481
|
+
const linked = Boolean(LinkComponent && href);
|
|
5482
|
+
const handlers = useActivationHandlers({ row, href, activatable, onActivate });
|
|
5483
|
+
const primaryColumn = columns[0];
|
|
5484
|
+
const secondaryColumns = columns.slice(1);
|
|
5485
|
+
const primaryText = getAccessibleCellText(row, primaryColumn, rowId);
|
|
5486
|
+
const primaryLabel = primaryColumn ? getHeaderLabel(primaryColumn) : "\uD589";
|
|
5487
|
+
const primaryContent = primaryColumn ? getRenderedCell(row, primaryColumn) : primaryText;
|
|
5488
|
+
return /* @__PURE__ */ jsxs30(
|
|
5489
|
+
"div",
|
|
5490
|
+
{
|
|
5491
|
+
"data-slot": "data-table-mobile-card",
|
|
5492
|
+
"data-row-id": rowId,
|
|
5493
|
+
"data-href": href,
|
|
5494
|
+
role: "listitem",
|
|
5495
|
+
"aria-posinset": ariaPosInSet,
|
|
5496
|
+
"aria-setsize": ariaSetSize,
|
|
5497
|
+
tabIndex: activatable ? 0 : void 0,
|
|
5498
|
+
"aria-label": `${primaryLabel}: ${primaryText}`,
|
|
5499
|
+
className: cn(
|
|
5500
|
+
"flex min-w-0 flex-col gap-[var(--space-3)] border-t border-[var(--border-subtle)] px-[var(--space-4)] py-[var(--space-4)]",
|
|
5501
|
+
"text-body-sm leading-compact text-foreground transition-colors motion-reduce:transition-none",
|
|
5502
|
+
activatable || linked ? "cursor-pointer hover:bg-[var(--action-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--focus-ring)]" : null,
|
|
5503
|
+
visuallySelected ? "bg-[var(--action-selected)]" : null,
|
|
5504
|
+
linked ? rowLinkHostClass : null
|
|
5505
|
+
),
|
|
5506
|
+
onContextMenu: (event) => onRowContextMenu?.(rowId, event),
|
|
5507
|
+
onClick: handlers.onClick,
|
|
5508
|
+
onKeyDown: handlers.onKeyDown,
|
|
5509
|
+
children: [
|
|
5510
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex min-w-0 items-start gap-[var(--space-3)]", children: [
|
|
5511
|
+
selectable ? /* @__PURE__ */ jsx31("div", { "data-slot": "data-table-mobile-card-select", className: "shrink-0 pt-[2px]", children: /* @__PURE__ */ jsx31(
|
|
5512
|
+
Checkbox,
|
|
5513
|
+
{
|
|
5514
|
+
"aria-label": `${primaryText} \uBAA8\uBC14\uC77C \uCE74\uB4DC \uC120\uD0DD`,
|
|
5515
|
+
checked: selected,
|
|
5516
|
+
onCheckedChange: (nextChecked) => onToggle(rowId, nextChecked === true),
|
|
5517
|
+
children: /* @__PURE__ */ jsxs30("span", { className: "sr-only", children: [
|
|
5518
|
+
rowId,
|
|
5519
|
+
" \uBAA8\uBC14\uC77C \uCE74\uB4DC \uC120\uD0DD"
|
|
5520
|
+
] })
|
|
5521
|
+
}
|
|
5522
|
+
) }) : null,
|
|
5523
|
+
/* @__PURE__ */ jsx31(
|
|
5524
|
+
"div",
|
|
5525
|
+
{
|
|
5526
|
+
"data-slot": "data-table-mobile-card-primary",
|
|
5527
|
+
className: "min-w-0 flex-1 font-medium text-foreground",
|
|
5528
|
+
children: linked && LinkComponent ? /* @__PURE__ */ jsx31(LinkComponent, { href, "data-slot": "data-table-row-link", className: rowLinkClass, children: primaryContent }) : primaryContent
|
|
5529
|
+
}
|
|
5530
|
+
)
|
|
5531
|
+
] }),
|
|
5532
|
+
secondaryColumns.length > 0 ? /* @__PURE__ */ jsx31("dl", { className: "grid min-w-0 gap-[var(--space-2)]", children: secondaryColumns.map((column) => {
|
|
5533
|
+
const align = column.align ?? "left";
|
|
5534
|
+
return /* @__PURE__ */ jsxs30(
|
|
5535
|
+
"div",
|
|
5536
|
+
{
|
|
5537
|
+
"data-slot": "data-table-mobile-card-field",
|
|
5538
|
+
className: "grid min-w-0 grid-cols-[minmax(0,0.42fr)_minmax(0,1fr)] gap-[var(--space-2)] text-[12px] leading-snug",
|
|
5539
|
+
children: [
|
|
5540
|
+
/* @__PURE__ */ jsx31("dt", { className: "min-w-0 text-text-tertiary", children: /* @__PURE__ */ jsx31("span", { className: "truncate", children: column.header }) }),
|
|
5541
|
+
/* @__PURE__ */ jsx31(
|
|
5542
|
+
"dd",
|
|
5543
|
+
{
|
|
5544
|
+
className: cn(
|
|
5545
|
+
"min-w-0 text-text-secondary",
|
|
5546
|
+
alignmentClass[align],
|
|
5547
|
+
column.tabular ? "font-[family-name:var(--font-display)] tabular-nums" : null
|
|
5548
|
+
),
|
|
5549
|
+
children: /* @__PURE__ */ jsx31("span", { className: "min-w-0 truncate", children: getRenderedCell(row, column) })
|
|
5550
|
+
}
|
|
5551
|
+
)
|
|
5552
|
+
]
|
|
5553
|
+
},
|
|
5554
|
+
column.key
|
|
5555
|
+
);
|
|
5556
|
+
}) }) : null
|
|
5557
|
+
]
|
|
5558
|
+
}
|
|
5559
|
+
);
|
|
5560
|
+
}
|
|
5561
|
+
var MemoDataTableRow = React27.memo(DataTableRowView);
|
|
5562
|
+
var MemoDataTableMobileCard = React27.memo(DataTableMobileCardView);
|
|
5563
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? React27.useEffect : React27.useLayoutEffect;
|
|
5564
|
+
var VIRTUAL_DEFAULT_OVERSCAN = 8;
|
|
5565
|
+
var VIRTUAL_INITIAL_ROWS = 24;
|
|
5566
|
+
var VIRTUAL_FALLBACK_SIZE = { desktop: 48, mobile: 120 };
|
|
5567
|
+
function getScrollParent(node) {
|
|
5568
|
+
for (let el = node.parentElement; el && el !== document.body; el = el.parentElement) {
|
|
5569
|
+
const { overflowY } = window.getComputedStyle(el);
|
|
5570
|
+
if ((overflowY === "auto" || overflowY === "scroll") && el.scrollHeight > el.clientHeight) {
|
|
5571
|
+
return el;
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
return null;
|
|
5575
|
+
}
|
|
5576
|
+
function useVirtualWindow({
|
|
5577
|
+
enabled,
|
|
5578
|
+
count,
|
|
5579
|
+
overscan,
|
|
5580
|
+
onRangeChange,
|
|
5581
|
+
desktopRef,
|
|
5582
|
+
headerRef,
|
|
5583
|
+
desktopListRef,
|
|
5584
|
+
mobileListRef
|
|
5585
|
+
}) {
|
|
5586
|
+
const [win, setWin] = React27.useState({
|
|
5587
|
+
layout: null,
|
|
5588
|
+
start: 0,
|
|
5589
|
+
end: VIRTUAL_INITIAL_ROWS,
|
|
5590
|
+
size: 0
|
|
5591
|
+
});
|
|
5592
|
+
const measuredSize = React27.useRef({ desktop: 0, mobile: 0 });
|
|
5593
|
+
const update = React27.useRef(() => void 0);
|
|
5594
|
+
const reported = React27.useRef("");
|
|
5595
|
+
const latest = React27.useRef({ count, layout: "desktop" });
|
|
5596
|
+
update.current = () => {
|
|
5597
|
+
if (!enabled) {
|
|
5598
|
+
return;
|
|
5599
|
+
}
|
|
5600
|
+
const desktop = desktopRef.current;
|
|
5601
|
+
const layout = desktop && window.getComputedStyle(desktop).display === "none" ? "mobile" : "desktop";
|
|
5602
|
+
const list = (layout === "desktop" ? desktopListRef : mobileListRef).current;
|
|
5603
|
+
const firstItem = list?.firstElementChild;
|
|
5604
|
+
const itemHeight = firstItem ? firstItem.getBoundingClientRect().height : 0;
|
|
5605
|
+
if (itemHeight > 0) {
|
|
5606
|
+
measuredSize.current[layout] = itemHeight;
|
|
5607
|
+
}
|
|
5608
|
+
const size = measuredSize.current[layout] || VIRTUAL_FALLBACK_SIZE[layout];
|
|
5609
|
+
latest.current = { count, layout };
|
|
5610
|
+
let start = 0;
|
|
5611
|
+
let end = Math.min(count, VIRTUAL_INITIAL_ROWS);
|
|
5612
|
+
if (list) {
|
|
5613
|
+
const top = list.getBoundingClientRect().top;
|
|
5614
|
+
const viewport = window.innerHeight || document.documentElement.clientHeight;
|
|
5615
|
+
start = Math.min(count, Math.max(0, Math.floor(-top / size) - overscan));
|
|
5616
|
+
end = Math.min(count, Math.max(start, Math.ceil((viewport - top) / size) + overscan));
|
|
5617
|
+
if (onRangeChange) {
|
|
5618
|
+
const container = getScrollParent(list);
|
|
5619
|
+
const bounds = container?.getBoundingClientRect();
|
|
5620
|
+
let visibleTop = Math.max(0, bounds ? bounds.top : 0);
|
|
5621
|
+
const visibleBottom = Math.min(viewport, bounds ? bounds.bottom : viewport);
|
|
5622
|
+
const header = headerRef.current;
|
|
5623
|
+
if (layout === "desktop" && header) {
|
|
5624
|
+
visibleTop = Math.max(visibleTop, header.getBoundingClientRect().bottom);
|
|
5625
|
+
}
|
|
5626
|
+
const first = Math.min(count, Math.max(0, Math.floor((visibleTop - top) / size)));
|
|
5627
|
+
const last = Math.min(count, Math.max(first, Math.ceil((visibleBottom - top) / size)));
|
|
5628
|
+
const key = `${first}:${last}:${count}`;
|
|
5629
|
+
if (reported.current !== key) {
|
|
5630
|
+
reported.current = key;
|
|
5631
|
+
onRangeChange({ start: first, end: last });
|
|
5632
|
+
}
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
setWin(
|
|
5636
|
+
(prev) => prev.layout === layout && prev.start === start && prev.end === end && prev.size === size ? prev : { layout, start, end, size }
|
|
5637
|
+
);
|
|
5638
|
+
};
|
|
5639
|
+
useIsomorphicLayoutEffect(() => {
|
|
5640
|
+
update.current();
|
|
5641
|
+
});
|
|
5642
|
+
React27.useEffect(() => {
|
|
5643
|
+
if (!enabled) {
|
|
5644
|
+
return;
|
|
5645
|
+
}
|
|
5646
|
+
let frame = 0;
|
|
5647
|
+
const schedule = () => {
|
|
5648
|
+
if (frame) {
|
|
5649
|
+
return;
|
|
5650
|
+
}
|
|
5651
|
+
frame = window.requestAnimationFrame(() => {
|
|
5652
|
+
frame = 0;
|
|
5653
|
+
update.current();
|
|
5654
|
+
});
|
|
5655
|
+
};
|
|
5656
|
+
window.addEventListener("scroll", schedule, { capture: true, passive: true });
|
|
5657
|
+
window.addEventListener("resize", schedule);
|
|
5658
|
+
return () => {
|
|
5659
|
+
window.removeEventListener("scroll", schedule, { capture: true });
|
|
5660
|
+
window.removeEventListener("resize", schedule);
|
|
5661
|
+
window.cancelAnimationFrame(frame);
|
|
5662
|
+
};
|
|
5663
|
+
}, [enabled]);
|
|
5664
|
+
const scrollToIndex = React27.useCallback(
|
|
5665
|
+
(index) => {
|
|
5666
|
+
const { count: rowCount, layout } = latest.current;
|
|
5667
|
+
const list = (layout === "desktop" ? desktopListRef : mobileListRef).current;
|
|
5668
|
+
if (!list || rowCount === 0) {
|
|
5669
|
+
return;
|
|
5670
|
+
}
|
|
5671
|
+
const row = Math.min(rowCount - 1, Math.max(0, Math.floor(index)));
|
|
5672
|
+
const size = measuredSize.current[layout] || VIRTUAL_FALLBACK_SIZE[layout];
|
|
5673
|
+
const container = getScrollParent(list);
|
|
5674
|
+
let target = container ? container.getBoundingClientRect().top : 0;
|
|
5675
|
+
const header = headerRef.current;
|
|
5676
|
+
if (layout === "desktop" && header) {
|
|
5677
|
+
const { position, top } = window.getComputedStyle(header);
|
|
5678
|
+
if (position === "sticky") {
|
|
5679
|
+
target += (Number.parseFloat(top) || 0) + header.getBoundingClientRect().height;
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
const delta = list.getBoundingClientRect().top + row * size - target;
|
|
5683
|
+
if (container) {
|
|
5684
|
+
container.scrollTop += delta;
|
|
5685
|
+
} else {
|
|
5686
|
+
window.scrollBy(0, delta);
|
|
5687
|
+
}
|
|
5688
|
+
},
|
|
5689
|
+
[desktopListRef, headerRef, mobileListRef]
|
|
5690
|
+
);
|
|
5691
|
+
return { win, scrollToIndex };
|
|
5692
|
+
}
|
|
5366
5693
|
function DataTableInner({
|
|
5367
5694
|
className,
|
|
5368
5695
|
density = "standard",
|
|
@@ -5373,6 +5700,8 @@ function DataTableInner({
|
|
|
5373
5700
|
selectable = false,
|
|
5374
5701
|
selectedIds,
|
|
5375
5702
|
onSelectionChange,
|
|
5703
|
+
selectionUnit = "\uAC1C",
|
|
5704
|
+
announceSelection = true,
|
|
5376
5705
|
activeRowId,
|
|
5377
5706
|
onRowContextMenu,
|
|
5378
5707
|
sortBy,
|
|
@@ -5380,18 +5709,36 @@ function DataTableInner({
|
|
|
5380
5709
|
loading = false,
|
|
5381
5710
|
emptyState,
|
|
5382
5711
|
rowHref,
|
|
5712
|
+
linkComponent,
|
|
5713
|
+
onRowClick,
|
|
5714
|
+
virtual,
|
|
5383
5715
|
skeletonRowCount = 8,
|
|
5384
5716
|
"aria-label": ariaLabel = "\uB370\uC774\uD130 \uD14C\uC774\uBE14",
|
|
5385
5717
|
...props
|
|
5386
5718
|
}, ref) {
|
|
5719
|
+
const virtualOptions = virtual ? virtual === true ? {} : virtual : null;
|
|
5720
|
+
const isVirtual = virtualOptions !== null;
|
|
5721
|
+
const desktopRef = React27.useRef(null);
|
|
5722
|
+
const headerRef = React27.useRef(null);
|
|
5723
|
+
const desktopListRef = React27.useRef(null);
|
|
5724
|
+
const mobileListRef = React27.useRef(null);
|
|
5725
|
+
const { win: virtualWindow, scrollToIndex } = useVirtualWindow({
|
|
5726
|
+
enabled: isVirtual,
|
|
5727
|
+
count: data.length,
|
|
5728
|
+
overscan: virtualOptions?.overscan ?? VIRTUAL_DEFAULT_OVERSCAN,
|
|
5729
|
+
onRangeChange: virtualOptions?.onRangeChange,
|
|
5730
|
+
desktopRef,
|
|
5731
|
+
headerRef,
|
|
5732
|
+
desktopListRef,
|
|
5733
|
+
mobileListRef
|
|
5734
|
+
});
|
|
5735
|
+
React27.useImperativeHandle(virtualOptions?.handleRef, () => ({ scrollToIndex }), [scrollToIndex]);
|
|
5387
5736
|
const resolvedSelectedIds = selectedIds ?? /* @__PURE__ */ new Set();
|
|
5388
5737
|
const rowIds = data.map((row) => getRowId(row, keyField));
|
|
5389
5738
|
const selectedCount = rowIds.filter((id) => resolvedSelectedIds.has(id)).length;
|
|
5390
5739
|
const allVisibleRowsSelected = rowIds.length > 0 && selectedCount === rowIds.length;
|
|
5391
5740
|
const partiallySelected = selectedCount > 0 && !allVisibleRowsSelected;
|
|
5392
5741
|
const gridTemplateColumns = getGridTemplate(columns, selectable);
|
|
5393
|
-
const primaryColumn = columns[0];
|
|
5394
|
-
const secondaryColumns = columns.slice(1);
|
|
5395
5742
|
const emitSelection = (nextIds) => {
|
|
5396
5743
|
onSelectionChange?.(nextIds);
|
|
5397
5744
|
};
|
|
@@ -5413,21 +5760,90 @@ function DataTableInner({
|
|
|
5413
5760
|
}
|
|
5414
5761
|
emitSelection(nextIds);
|
|
5415
5762
|
};
|
|
5763
|
+
const activateRow = (row, href, event) => {
|
|
5764
|
+
if (onRowClick) {
|
|
5765
|
+
onRowClick(row, event);
|
|
5766
|
+
} else if (href) {
|
|
5767
|
+
window.location.assign(href);
|
|
5768
|
+
}
|
|
5769
|
+
};
|
|
5770
|
+
const latestHandlers = React27.useRef({ toggleRow, activateRow, onRowContextMenu });
|
|
5771
|
+
useIsomorphicLayoutEffect(() => {
|
|
5772
|
+
latestHandlers.current = { toggleRow, activateRow, onRowContextMenu };
|
|
5773
|
+
});
|
|
5774
|
+
const stableToggleRow = React27.useCallback(
|
|
5775
|
+
(id, checked) => latestHandlers.current.toggleRow(id, checked),
|
|
5776
|
+
[]
|
|
5777
|
+
);
|
|
5778
|
+
const stableActivateRow = React27.useCallback(
|
|
5779
|
+
(row, href, event) => latestHandlers.current.activateRow(row, href, event),
|
|
5780
|
+
[]
|
|
5781
|
+
);
|
|
5782
|
+
const stableRowContextMenu = React27.useCallback(
|
|
5783
|
+
(rowId, event) => latestHandlers.current.onRowContextMenu?.(rowId, event),
|
|
5784
|
+
[]
|
|
5785
|
+
);
|
|
5786
|
+
const getItemProps = (row) => {
|
|
5787
|
+
const rowId = getRowId(row, keyField);
|
|
5788
|
+
const selected = resolvedSelectedIds.has(rowId);
|
|
5789
|
+
const href = rowHref?.(row);
|
|
5790
|
+
const linked = Boolean(linkComponent && href);
|
|
5791
|
+
return {
|
|
5792
|
+
row,
|
|
5793
|
+
rowId,
|
|
5794
|
+
columns,
|
|
5795
|
+
selectable,
|
|
5796
|
+
selected,
|
|
5797
|
+
visuallySelected: selected || rowId === activeRowId,
|
|
5798
|
+
href,
|
|
5799
|
+
activatable: !linked && Boolean(href || onRowClick),
|
|
5800
|
+
LinkComponent: linkComponent,
|
|
5801
|
+
onToggle: isVirtual ? stableToggleRow : toggleRow,
|
|
5802
|
+
onActivate: isVirtual ? stableActivateRow : activateRow,
|
|
5803
|
+
onRowContextMenu: isVirtual ? stableRowContextMenu : onRowContextMenu
|
|
5804
|
+
};
|
|
5805
|
+
};
|
|
5806
|
+
const sliceFor = (layout) => {
|
|
5807
|
+
if (!isVirtual) {
|
|
5808
|
+
return { rows: data, start: 0, style: void 0 };
|
|
5809
|
+
}
|
|
5810
|
+
if (virtualWindow.layout !== null && virtualWindow.layout !== layout) {
|
|
5811
|
+
return { rows: [], start: 0, style: void 0 };
|
|
5812
|
+
}
|
|
5813
|
+
const size = virtualWindow.size || VIRTUAL_FALLBACK_SIZE[layout];
|
|
5814
|
+
const end = Math.min(data.length, virtualWindow.end);
|
|
5815
|
+
const start = Math.min(virtualWindow.start, end);
|
|
5816
|
+
return {
|
|
5817
|
+
rows: data.slice(start, end),
|
|
5818
|
+
start,
|
|
5819
|
+
style: { paddingTop: start * size, paddingBottom: (data.length - end) * size }
|
|
5820
|
+
};
|
|
5821
|
+
};
|
|
5822
|
+
const desktopSlice = sliceFor("desktop");
|
|
5823
|
+
const mobileSlice = sliceFor("mobile");
|
|
5824
|
+
const RowComponent = isVirtual ? MemoDataTableRow : DataTableRowView;
|
|
5825
|
+
const CardComponent = isVirtual ? MemoDataTableMobileCard : DataTableMobileCardView;
|
|
5416
5826
|
return /* @__PURE__ */ jsxs30(
|
|
5417
5827
|
"div",
|
|
5418
5828
|
{
|
|
5419
5829
|
ref,
|
|
5420
5830
|
"data-slot": "data-table",
|
|
5421
|
-
className: cn(
|
|
5831
|
+
className: cn(
|
|
5832
|
+
dataTableVariants({ density, surface }),
|
|
5833
|
+
// clip, not hidden: keeps the rounded corners without becoming the sticky
|
|
5834
|
+
// header's scroll container.
|
|
5835
|
+
isVirtual && "overflow-clip",
|
|
5836
|
+
className
|
|
5837
|
+
),
|
|
5422
5838
|
...props,
|
|
5423
5839
|
children: [
|
|
5424
|
-
selectable ? /* @__PURE__ */ jsx31(
|
|
5840
|
+
selectable && announceSelection ? /* @__PURE__ */ jsx31(
|
|
5425
5841
|
"div",
|
|
5426
5842
|
{
|
|
5427
5843
|
"data-slot": "data-table-selection-status",
|
|
5428
5844
|
"aria-live": "polite",
|
|
5429
5845
|
className: "sr-only",
|
|
5430
|
-
children: selectedCount > 0 ? `${selectedCount.toLocaleString("ko-KR")}
|
|
5846
|
+
children: selectedCount > 0 ? `${selectedCount.toLocaleString("ko-KR")}${selectionUnit} \uC120\uD0DD\uB428` : ""
|
|
5431
5847
|
}
|
|
5432
5848
|
) : null,
|
|
5433
5849
|
loading && data.length > 0 ? /* @__PURE__ */ jsx31(
|
|
@@ -5439,149 +5855,109 @@ function DataTableInner({
|
|
|
5439
5855
|
children: /* @__PURE__ */ jsx31("div", { className: "h-full w-1/3 animate-pulse bg-[var(--primary)]" })
|
|
5440
5856
|
}
|
|
5441
5857
|
) : null,
|
|
5442
|
-
/* @__PURE__ */ jsx31("div", { "data-slot": "data-table-desktop", className: "max-md:hidden md:block", children: /* @__PURE__ */ jsxs30(
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5858
|
+
/* @__PURE__ */ jsx31("div", { ref: desktopRef, "data-slot": "data-table-desktop", className: "max-md:hidden md:block", children: /* @__PURE__ */ jsxs30(
|
|
5859
|
+
"div",
|
|
5860
|
+
{
|
|
5861
|
+
role: "table",
|
|
5862
|
+
"aria-label": ariaLabel,
|
|
5863
|
+
"aria-rowcount": isVirtual && data.length > 0 ? data.length + 1 : void 0,
|
|
5864
|
+
children: [
|
|
5865
|
+
/* @__PURE__ */ jsxs30(
|
|
5866
|
+
"div",
|
|
5867
|
+
{
|
|
5868
|
+
ref: headerRef,
|
|
5869
|
+
"data-slot": "data-table-header",
|
|
5870
|
+
role: "row",
|
|
5871
|
+
className: cn(
|
|
5872
|
+
"grid min-h-[40px] items-center bg-[var(--bg-raised)] text-[12px] font-semibold uppercase leading-snug text-text-tertiary",
|
|
5873
|
+
// Virtual lists are long: the header sticks inside the scroll container,
|
|
5874
|
+
// below an inline BulkActionBar band (40px, --z-sticky) rendered before
|
|
5875
|
+
// the table — band on top, header under it, rows beneath both.
|
|
5876
|
+
isVirtual && "sticky top-0 z-[2] [[data-slot=bulk-action-bar][data-placement=inline]:not([data-state=idle])~[data-slot=data-table]_&]:top-[40px]"
|
|
5877
|
+
),
|
|
5878
|
+
style: { gridTemplateColumns },
|
|
5879
|
+
children: [
|
|
5880
|
+
selectable ? /* @__PURE__ */ jsx31("div", { role: "columnheader", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx31(
|
|
5881
|
+
Checkbox,
|
|
5882
|
+
{
|
|
5883
|
+
"aria-label": "\uC804\uCCB4 \uD589 \uC120\uD0DD",
|
|
5884
|
+
checked: partiallySelected ? "indeterminate" : allVisibleRowsSelected,
|
|
5885
|
+
onCheckedChange: (nextChecked) => toggleAllRows(nextChecked === true),
|
|
5886
|
+
children: /* @__PURE__ */ jsx31("span", { className: "sr-only", children: "\uC804\uCCB4 \uD589 \uC120\uD0DD" })
|
|
5887
|
+
}
|
|
5888
|
+
) }) : null,
|
|
5889
|
+
columns.map((column) => {
|
|
5890
|
+
const align = column.align ?? "left";
|
|
5891
|
+
const nextSort = getNextSort(sortBy, column.key);
|
|
5892
|
+
const ariaSort = sortBy?.key === column.key ? sortBy.dir === "asc" ? "ascending" : "descending" : void 0;
|
|
5893
|
+
return /* @__PURE__ */ jsx31(
|
|
5894
|
+
"div",
|
|
5475
5895
|
{
|
|
5476
|
-
|
|
5896
|
+
role: "columnheader",
|
|
5897
|
+
"aria-sort": ariaSort,
|
|
5477
5898
|
className: cn(
|
|
5478
|
-
"
|
|
5479
|
-
|
|
5480
|
-
"hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)]"
|
|
5899
|
+
"flex min-w-0 items-center gap-[var(--space-1)] px-[var(--space-4)] py-[var(--space-2)]",
|
|
5900
|
+
alignmentClass[align]
|
|
5481
5901
|
),
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
{
|
|
5525
|
-
"data-slot": "data-table-row",
|
|
5526
|
-
"data-row-id": rowId,
|
|
5527
|
-
"data-href": href,
|
|
5528
|
-
role: "row",
|
|
5529
|
-
tabIndex: href ? 0 : void 0,
|
|
5530
|
-
className: cn(dataTableRowVariants({ interactive: Boolean(href), selected: visuallySelected })),
|
|
5531
|
-
style: { gridTemplateColumns },
|
|
5532
|
-
onContextMenu: (event) => onRowContextMenu?.(rowId, event),
|
|
5533
|
-
onClick: (event) => {
|
|
5534
|
-
if (!href || isInteractiveTarget(event.target)) {
|
|
5535
|
-
return;
|
|
5536
|
-
}
|
|
5537
|
-
window.location.assign(href);
|
|
5538
|
-
},
|
|
5539
|
-
onKeyDown: (event) => {
|
|
5540
|
-
if (!href || isInteractiveTarget(event.target)) {
|
|
5541
|
-
return;
|
|
5542
|
-
}
|
|
5543
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
5544
|
-
event.preventDefault();
|
|
5545
|
-
window.location.assign(href);
|
|
5902
|
+
children: column.sortable ? /* @__PURE__ */ jsxs30(
|
|
5903
|
+
"button",
|
|
5904
|
+
{
|
|
5905
|
+
type: "button",
|
|
5906
|
+
className: cn(
|
|
5907
|
+
"inline-flex min-w-0 cursor-pointer items-center gap-[var(--space-1)] rounded-[var(--radius-xs)]",
|
|
5908
|
+
"text-inherit transition-colors motion-reduce:transition-none",
|
|
5909
|
+
"hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)]"
|
|
5910
|
+
),
|
|
5911
|
+
onClick: () => onSortChange?.(column.key, nextSort),
|
|
5912
|
+
children: [
|
|
5913
|
+
/* @__PURE__ */ jsx31("span", { className: "truncate", children: column.header }),
|
|
5914
|
+
/* @__PURE__ */ jsx31(SortIcon, { sort: sortBy, columnKey: column.key })
|
|
5915
|
+
]
|
|
5916
|
+
}
|
|
5917
|
+
) : /* @__PURE__ */ jsx31("span", { className: "truncate", children: column.header })
|
|
5918
|
+
},
|
|
5919
|
+
column.key
|
|
5920
|
+
);
|
|
5921
|
+
})
|
|
5922
|
+
]
|
|
5923
|
+
}
|
|
5924
|
+
),
|
|
5925
|
+
loading && data.length === 0 ? /* @__PURE__ */ jsx31(
|
|
5926
|
+
SkeletonRows,
|
|
5927
|
+
{
|
|
5928
|
+
columns,
|
|
5929
|
+
selectable,
|
|
5930
|
+
gridTemplateColumns,
|
|
5931
|
+
count: skeletonRowCount
|
|
5932
|
+
}
|
|
5933
|
+
) : data.length === 0 ? (
|
|
5934
|
+
/* role="table" 직계 자식은 row/rowgroup이어야 한다. data-slot과 테두리는
|
|
5935
|
+
그대로 유지해 시각 계약을 깨지 않는다(빈 상태에서도 표가 테두리를 그린다). */
|
|
5936
|
+
/* @__PURE__ */ jsx31("div", { role: "rowgroup", children: /* @__PURE__ */ jsx31("div", { role: "row", children: /* @__PURE__ */ jsx31(
|
|
5937
|
+
"div",
|
|
5938
|
+
{
|
|
5939
|
+
role: "cell",
|
|
5940
|
+
"aria-colindex": 1,
|
|
5941
|
+
"data-slot": "data-table-empty",
|
|
5942
|
+
className: "border-t border-[var(--border-subtle)] p-[var(--space-4)]",
|
|
5943
|
+
children: emptyState
|
|
5546
5944
|
}
|
|
5547
|
-
}
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
return /* @__PURE__ */ jsx31(
|
|
5564
|
-
"div",
|
|
5565
|
-
{
|
|
5566
|
-
"data-slot": "data-table-cell",
|
|
5567
|
-
role: "cell",
|
|
5568
|
-
className: cn(
|
|
5569
|
-
"flex min-w-0 items-center px-[var(--space-4)] py-[var(--space-2)]",
|
|
5570
|
-
alignmentClass[align],
|
|
5571
|
-
column.tabular ? "font-[family-name:var(--font-display)] tabular-nums" : null,
|
|
5572
|
-
align === "right" ? "text-text-tertiary" : null
|
|
5573
|
-
),
|
|
5574
|
-
children: /* @__PURE__ */ jsx31("span", { className: "min-w-0 truncate", children: getRenderedCell(row, column) })
|
|
5575
|
-
},
|
|
5576
|
-
column.key
|
|
5577
|
-
);
|
|
5578
|
-
})
|
|
5579
|
-
]
|
|
5580
|
-
},
|
|
5581
|
-
rowId
|
|
5582
|
-
);
|
|
5583
|
-
}) })
|
|
5584
|
-
] }) }),
|
|
5945
|
+
) }) })
|
|
5946
|
+
) : /* @__PURE__ */ jsx31("div", { ref: desktopListRef, role: "rowgroup", style: desktopSlice.style, children: desktopSlice.rows.map((row, index) => {
|
|
5947
|
+
const itemProps = getItemProps(row);
|
|
5948
|
+
return /* @__PURE__ */ jsx31(
|
|
5949
|
+
RowComponent,
|
|
5950
|
+
{
|
|
5951
|
+
...itemProps,
|
|
5952
|
+
gridTemplateColumns,
|
|
5953
|
+
ariaRowIndex: isVirtual ? desktopSlice.start + index + 2 : void 0
|
|
5954
|
+
},
|
|
5955
|
+
itemProps.rowId
|
|
5956
|
+
);
|
|
5957
|
+
}) })
|
|
5958
|
+
]
|
|
5959
|
+
}
|
|
5960
|
+
) }),
|
|
5585
5961
|
/* @__PURE__ */ jsx31(
|
|
5586
5962
|
MobileSortControls,
|
|
5587
5963
|
{
|
|
@@ -5602,99 +5978,22 @@ function DataTableInner({
|
|
|
5602
5978
|
) : /* @__PURE__ */ jsx31(
|
|
5603
5979
|
"div",
|
|
5604
5980
|
{
|
|
5981
|
+
ref: mobileListRef,
|
|
5605
5982
|
"data-slot": "data-table-mobile-list",
|
|
5606
5983
|
role: "list",
|
|
5607
5984
|
"aria-label": `${ariaLabel} \uBAA8\uBC14\uC77C \uCE74\uB4DC \uBAA9\uB85D`,
|
|
5608
5985
|
className: "md:hidden",
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
const
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
const primaryText = getAccessibleCellText(row, primaryColumn, rowId);
|
|
5615
|
-
const primaryLabel = primaryColumn ? getHeaderLabel(primaryColumn) : "\uD589";
|
|
5616
|
-
return /* @__PURE__ */ jsxs30(
|
|
5617
|
-
"div",
|
|
5986
|
+
style: mobileSlice.style,
|
|
5987
|
+
children: mobileSlice.rows.map((row, index) => {
|
|
5988
|
+
const itemProps = getItemProps(row);
|
|
5989
|
+
return /* @__PURE__ */ jsx31(
|
|
5990
|
+
CardComponent,
|
|
5618
5991
|
{
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
role: "listitem",
|
|
5623
|
-
tabIndex: href ? 0 : void 0,
|
|
5624
|
-
"aria-label": `${primaryLabel}: ${primaryText}`,
|
|
5625
|
-
className: cn(
|
|
5626
|
-
"flex min-w-0 flex-col gap-[var(--space-3)] border-t border-[var(--border-subtle)] px-[var(--space-4)] py-[var(--space-4)]",
|
|
5627
|
-
"text-body-sm leading-compact text-foreground transition-colors motion-reduce:transition-none",
|
|
5628
|
-
href ? "cursor-pointer hover:bg-[var(--action-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--focus-ring)]" : null,
|
|
5629
|
-
visuallySelected ? "bg-[var(--action-selected)]" : null
|
|
5630
|
-
),
|
|
5631
|
-
onContextMenu: (event) => onRowContextMenu?.(rowId, event),
|
|
5632
|
-
onClick: (event) => {
|
|
5633
|
-
if (!href || isInteractiveTarget(event.target)) {
|
|
5634
|
-
return;
|
|
5635
|
-
}
|
|
5636
|
-
window.location.assign(href);
|
|
5637
|
-
},
|
|
5638
|
-
onKeyDown: (event) => {
|
|
5639
|
-
if (!href || isInteractiveTarget(event.target)) {
|
|
5640
|
-
return;
|
|
5641
|
-
}
|
|
5642
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
5643
|
-
event.preventDefault();
|
|
5644
|
-
window.location.assign(href);
|
|
5645
|
-
}
|
|
5646
|
-
},
|
|
5647
|
-
children: [
|
|
5648
|
-
/* @__PURE__ */ jsxs30("div", { className: "flex min-w-0 items-start gap-[var(--space-3)]", children: [
|
|
5649
|
-
selectable ? /* @__PURE__ */ jsx31("div", { "data-slot": "data-table-mobile-card-select", className: "shrink-0 pt-[2px]", children: /* @__PURE__ */ jsx31(
|
|
5650
|
-
Checkbox,
|
|
5651
|
-
{
|
|
5652
|
-
"aria-label": `${primaryText} \uBAA8\uBC14\uC77C \uCE74\uB4DC \uC120\uD0DD`,
|
|
5653
|
-
checked: selected,
|
|
5654
|
-
onCheckedChange: (nextChecked) => toggleRow(rowId, nextChecked === true),
|
|
5655
|
-
children: /* @__PURE__ */ jsxs30("span", { className: "sr-only", children: [
|
|
5656
|
-
rowId,
|
|
5657
|
-
" \uBAA8\uBC14\uC77C \uCE74\uB4DC \uC120\uD0DD"
|
|
5658
|
-
] })
|
|
5659
|
-
}
|
|
5660
|
-
) }) : null,
|
|
5661
|
-
/* @__PURE__ */ jsx31(
|
|
5662
|
-
"div",
|
|
5663
|
-
{
|
|
5664
|
-
"data-slot": "data-table-mobile-card-primary",
|
|
5665
|
-
className: "min-w-0 flex-1 font-medium text-foreground",
|
|
5666
|
-
children: primaryColumn ? getRenderedCell(row, primaryColumn) : primaryText
|
|
5667
|
-
}
|
|
5668
|
-
)
|
|
5669
|
-
] }),
|
|
5670
|
-
secondaryColumns.length > 0 ? /* @__PURE__ */ jsx31("dl", { className: "grid min-w-0 gap-[var(--space-2)]", children: secondaryColumns.map((column) => {
|
|
5671
|
-
const align = column.align ?? "left";
|
|
5672
|
-
return /* @__PURE__ */ jsxs30(
|
|
5673
|
-
"div",
|
|
5674
|
-
{
|
|
5675
|
-
"data-slot": "data-table-mobile-card-field",
|
|
5676
|
-
className: "grid min-w-0 grid-cols-[minmax(0,0.42fr)_minmax(0,1fr)] gap-[var(--space-2)] text-[12px] leading-snug",
|
|
5677
|
-
children: [
|
|
5678
|
-
/* @__PURE__ */ jsx31("dt", { className: "min-w-0 text-text-tertiary", children: /* @__PURE__ */ jsx31("span", { className: "truncate", children: column.header }) }),
|
|
5679
|
-
/* @__PURE__ */ jsx31(
|
|
5680
|
-
"dd",
|
|
5681
|
-
{
|
|
5682
|
-
className: cn(
|
|
5683
|
-
"min-w-0 text-text-secondary",
|
|
5684
|
-
alignmentClass[align],
|
|
5685
|
-
column.tabular ? "font-[family-name:var(--font-display)] tabular-nums" : null
|
|
5686
|
-
),
|
|
5687
|
-
children: /* @__PURE__ */ jsx31("span", { className: "min-w-0 truncate", children: getRenderedCell(row, column) })
|
|
5688
|
-
}
|
|
5689
|
-
)
|
|
5690
|
-
]
|
|
5691
|
-
},
|
|
5692
|
-
column.key
|
|
5693
|
-
);
|
|
5694
|
-
}) }) : null
|
|
5695
|
-
]
|
|
5992
|
+
...itemProps,
|
|
5993
|
+
ariaPosInSet: isVirtual ? mobileSlice.start + index + 1 : void 0,
|
|
5994
|
+
ariaSetSize: isVirtual ? data.length : void 0
|
|
5696
5995
|
},
|
|
5697
|
-
rowId
|
|
5996
|
+
itemProps.rowId
|
|
5698
5997
|
);
|
|
5699
5998
|
})
|
|
5700
5999
|
}
|
|
@@ -5988,6 +6287,7 @@ function ContextMenu({
|
|
|
5988
6287
|
}
|
|
5989
6288
|
|
|
5990
6289
|
// src/components/ui/bulk-action-bar.tsx
|
|
6290
|
+
import * as React28 from "react";
|
|
5991
6291
|
import { X as X3 } from "lucide-react";
|
|
5992
6292
|
import { jsx as jsx34, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
5993
6293
|
function ActionButton({ action }) {
|
|
@@ -6077,18 +6377,281 @@ function ClearButton({ onClear }) {
|
|
|
6077
6377
|
}
|
|
6078
6378
|
);
|
|
6079
6379
|
}
|
|
6380
|
+
var INLINE_HEIGHT = 40;
|
|
6381
|
+
var HIT_AREA = 44;
|
|
6382
|
+
var HIT_INSET = 8;
|
|
6383
|
+
var floatingStyle = {
|
|
6384
|
+
position: "sticky",
|
|
6385
|
+
bottom: "calc(var(--space-4) + env(safe-area-inset-bottom))",
|
|
6386
|
+
zIndex: 1100,
|
|
6387
|
+
margin: "0 auto",
|
|
6388
|
+
display: "flex",
|
|
6389
|
+
minHeight: 32,
|
|
6390
|
+
width: "fit-content",
|
|
6391
|
+
maxWidth: "calc(100% - var(--space-8))",
|
|
6392
|
+
alignItems: "center",
|
|
6393
|
+
gap: "var(--space-2)",
|
|
6394
|
+
borderRadius: 9999,
|
|
6395
|
+
border: "1px solid var(--border)",
|
|
6396
|
+
background: "var(--bg-raised)",
|
|
6397
|
+
padding: "var(--space-1) var(--space-2)",
|
|
6398
|
+
boxShadow: "var(--shadow-8)"
|
|
6399
|
+
};
|
|
6400
|
+
var inlineStyle = {
|
|
6401
|
+
position: "sticky",
|
|
6402
|
+
top: 0,
|
|
6403
|
+
zIndex: "var(--z-sticky)",
|
|
6404
|
+
display: "flex",
|
|
6405
|
+
boxSizing: "border-box",
|
|
6406
|
+
height: INLINE_HEIGHT,
|
|
6407
|
+
alignItems: "center",
|
|
6408
|
+
gap: "var(--space-2)",
|
|
6409
|
+
borderRadius: "var(--radius-md)",
|
|
6410
|
+
border: "1px solid var(--border)",
|
|
6411
|
+
background: "var(--bg-surface)",
|
|
6412
|
+
padding: "0 var(--space-1) 0 var(--space-3)",
|
|
6413
|
+
boxShadow: "var(--shadow-2)",
|
|
6414
|
+
fontFamily: "var(--font-sans)",
|
|
6415
|
+
fontSize: 13,
|
|
6416
|
+
fontVariantNumeric: "tabular-nums"
|
|
6417
|
+
};
|
|
6418
|
+
var idleLineStyle = {
|
|
6419
|
+
display: "flex",
|
|
6420
|
+
boxSizing: "border-box",
|
|
6421
|
+
height: INLINE_HEIGHT,
|
|
6422
|
+
overflow: "hidden",
|
|
6423
|
+
alignItems: "center",
|
|
6424
|
+
columnGap: "var(--space-3)",
|
|
6425
|
+
whiteSpace: "nowrap",
|
|
6426
|
+
fontFamily: "var(--font-sans)",
|
|
6427
|
+
fontSize: 13,
|
|
6428
|
+
fontVariantNumeric: "tabular-nums",
|
|
6429
|
+
color: "var(--text-secondary)"
|
|
6430
|
+
};
|
|
6431
|
+
var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React28.useEffect : React28.useLayoutEffect;
|
|
6432
|
+
function useCompactSummary(slot, enabled) {
|
|
6433
|
+
const [fullWidth, setFullWidth] = React28.useState(null);
|
|
6434
|
+
const measure = React28.useCallback(() => {
|
|
6435
|
+
if (!slot) return;
|
|
6436
|
+
setFullWidth((prev) => {
|
|
6437
|
+
if (prev === null) return slot.scrollWidth > slot.clientWidth ? slot.scrollWidth : null;
|
|
6438
|
+
return slot.clientWidth >= prev ? null : prev;
|
|
6439
|
+
});
|
|
6440
|
+
}, [slot]);
|
|
6441
|
+
useIsomorphicLayoutEffect2(() => {
|
|
6442
|
+
if (enabled) measure();
|
|
6443
|
+
});
|
|
6444
|
+
React28.useEffect(() => {
|
|
6445
|
+
if (!enabled || !slot || typeof ResizeObserver === "undefined") return;
|
|
6446
|
+
const observer = new ResizeObserver(measure);
|
|
6447
|
+
observer.observe(slot);
|
|
6448
|
+
return () => observer.disconnect();
|
|
6449
|
+
}, [enabled, slot, measure]);
|
|
6450
|
+
return enabled && fullWidth !== null;
|
|
6451
|
+
}
|
|
6080
6452
|
function BulkActionBar({
|
|
6081
6453
|
count,
|
|
6082
6454
|
actions,
|
|
6083
6455
|
onClear,
|
|
6084
6456
|
emptyHint,
|
|
6457
|
+
placement = "floating",
|
|
6458
|
+
unit = "\uAC1C",
|
|
6459
|
+
summary,
|
|
6460
|
+
compactSummary,
|
|
6461
|
+
idleContent,
|
|
6462
|
+
trailing,
|
|
6085
6463
|
className,
|
|
6086
6464
|
style,
|
|
6087
6465
|
...props
|
|
6088
6466
|
}) {
|
|
6467
|
+
const inline = placement === "inline";
|
|
6468
|
+
const trailingSlot = trailing !== void 0 && trailing !== null ? /* @__PURE__ */ jsx34(
|
|
6469
|
+
"div",
|
|
6470
|
+
{
|
|
6471
|
+
"data-slot": "bulk-action-bar-trailing",
|
|
6472
|
+
style: {
|
|
6473
|
+
display: "flex",
|
|
6474
|
+
flexShrink: 0,
|
|
6475
|
+
alignItems: "center",
|
|
6476
|
+
gap: "var(--space-2)"
|
|
6477
|
+
},
|
|
6478
|
+
children: trailing
|
|
6479
|
+
}
|
|
6480
|
+
) : null;
|
|
6481
|
+
const [summaryElement, setSummaryElement] = React28.useState(null);
|
|
6482
|
+
const compact = useCompactSummary(
|
|
6483
|
+
summaryElement,
|
|
6484
|
+
inline && compactSummary !== void 0 && compactSummary !== null
|
|
6485
|
+
);
|
|
6486
|
+
if (count === 0 && idleContent !== void 0 && trailingSlot) {
|
|
6487
|
+
return /* @__PURE__ */ jsxs33(
|
|
6488
|
+
"div",
|
|
6489
|
+
{
|
|
6490
|
+
"data-slot": "bulk-action-bar",
|
|
6491
|
+
"data-placement": placement,
|
|
6492
|
+
"data-state": "idle",
|
|
6493
|
+
className,
|
|
6494
|
+
style: { ...idleLineStyle, overflow: "visible", ...style },
|
|
6495
|
+
...props,
|
|
6496
|
+
children: [
|
|
6497
|
+
/* @__PURE__ */ jsx34(
|
|
6498
|
+
"div",
|
|
6499
|
+
{
|
|
6500
|
+
role: "status",
|
|
6501
|
+
"data-slot": "bulk-action-bar-idle",
|
|
6502
|
+
style: {
|
|
6503
|
+
display: "flex",
|
|
6504
|
+
flex: "1 1 auto",
|
|
6505
|
+
minWidth: 0,
|
|
6506
|
+
alignItems: "center",
|
|
6507
|
+
columnGap: "var(--space-3)",
|
|
6508
|
+
overflow: "hidden"
|
|
6509
|
+
},
|
|
6510
|
+
children: idleContent
|
|
6511
|
+
}
|
|
6512
|
+
),
|
|
6513
|
+
trailingSlot
|
|
6514
|
+
]
|
|
6515
|
+
}
|
|
6516
|
+
);
|
|
6517
|
+
}
|
|
6518
|
+
if (count === 0 && idleContent !== void 0) {
|
|
6519
|
+
return /* @__PURE__ */ jsx34(
|
|
6520
|
+
"div",
|
|
6521
|
+
{
|
|
6522
|
+
role: "status",
|
|
6523
|
+
"data-slot": "bulk-action-bar",
|
|
6524
|
+
"data-placement": placement,
|
|
6525
|
+
"data-state": "idle",
|
|
6526
|
+
className,
|
|
6527
|
+
style: { ...idleLineStyle, ...style },
|
|
6528
|
+
...props,
|
|
6529
|
+
children: idleContent
|
|
6530
|
+
}
|
|
6531
|
+
);
|
|
6532
|
+
}
|
|
6089
6533
|
if (count === 0 && emptyHint === void 0) {
|
|
6090
6534
|
return null;
|
|
6091
6535
|
}
|
|
6536
|
+
const countLabel = /* @__PURE__ */ jsx34(
|
|
6537
|
+
"span",
|
|
6538
|
+
{
|
|
6539
|
+
"data-slot": "bulk-action-bar-count",
|
|
6540
|
+
style: {
|
|
6541
|
+
paddingLeft: inline ? void 0 : "var(--space-2)",
|
|
6542
|
+
paddingRight: "var(--space-1)",
|
|
6543
|
+
fontFamily: "var(--font-sans)",
|
|
6544
|
+
fontSize: 13,
|
|
6545
|
+
fontWeight: inline ? 600 : 500,
|
|
6546
|
+
fontVariantNumeric: "tabular-nums",
|
|
6547
|
+
color: "var(--text-primary)",
|
|
6548
|
+
whiteSpace: "nowrap"
|
|
6549
|
+
},
|
|
6550
|
+
children: count > 0 ? `${count.toLocaleString("ko-KR")}${unit} \uC120\uD0DD\uB428` : emptyHint
|
|
6551
|
+
}
|
|
6552
|
+
);
|
|
6553
|
+
const summarySlot = summary !== void 0 && summary !== null ? /* @__PURE__ */ jsx34(
|
|
6554
|
+
"span",
|
|
6555
|
+
{
|
|
6556
|
+
ref: setSummaryElement,
|
|
6557
|
+
"data-slot": "bulk-action-bar-summary",
|
|
6558
|
+
style: {
|
|
6559
|
+
display: inline ? "flex" : "inline-flex",
|
|
6560
|
+
minWidth: 0,
|
|
6561
|
+
alignItems: "center",
|
|
6562
|
+
columnGap: "var(--space-3)",
|
|
6563
|
+
fontFamily: "var(--font-sans)",
|
|
6564
|
+
fontSize: 13,
|
|
6565
|
+
color: "var(--text-secondary)",
|
|
6566
|
+
...inline ? (
|
|
6567
|
+
// inline-size containment: the summary never widens the band's parent. The
|
|
6568
|
+
// slot clips text, so it is as tall as an IconButton's hit area (overhanging
|
|
6569
|
+
// the 40px band) and has that inset as its left gutter: a compact IconButton
|
|
6570
|
+
// keeps its full 44px target. The right gutter stays 3px (focus ring) so
|
|
6571
|
+
// clipped text keeps clear of the controls.
|
|
6572
|
+
{
|
|
6573
|
+
flex: "1 1 0",
|
|
6574
|
+
alignSelf: "center",
|
|
6575
|
+
height: HIT_AREA,
|
|
6576
|
+
margin: `0 -3px 0 -${HIT_INSET}px`,
|
|
6577
|
+
padding: `0 3px 0 ${HIT_INSET}px`,
|
|
6578
|
+
overflow: "hidden",
|
|
6579
|
+
whiteSpace: "nowrap",
|
|
6580
|
+
contain: "inline-size"
|
|
6581
|
+
}
|
|
6582
|
+
) : { flexWrap: "wrap", wordBreak: "keep-all" }
|
|
6583
|
+
},
|
|
6584
|
+
children: compact ? compactSummary : summary
|
|
6585
|
+
}
|
|
6586
|
+
) : null;
|
|
6587
|
+
const actionGroup = /* @__PURE__ */ jsx34(
|
|
6588
|
+
"div",
|
|
6589
|
+
{
|
|
6590
|
+
"data-slot": "bulk-action-bar-actions",
|
|
6591
|
+
style: {
|
|
6592
|
+
display: "flex",
|
|
6593
|
+
minWidth: 0,
|
|
6594
|
+
flexWrap: inline ? "nowrap" : "wrap",
|
|
6595
|
+
alignItems: "center",
|
|
6596
|
+
justifyContent: "flex-end",
|
|
6597
|
+
gap: 2
|
|
6598
|
+
},
|
|
6599
|
+
children: actions.map((action) => /* @__PURE__ */ jsx34(ActionButton, { action }, action.key))
|
|
6600
|
+
}
|
|
6601
|
+
);
|
|
6602
|
+
if (inline) {
|
|
6603
|
+
return /* @__PURE__ */ jsxs33(
|
|
6604
|
+
"div",
|
|
6605
|
+
{
|
|
6606
|
+
role: "toolbar",
|
|
6607
|
+
"aria-label": "\uC120\uD0DD \uD56D\uBAA9 \uC77C\uAD04 \uC791\uC5C5",
|
|
6608
|
+
"data-slot": "bulk-action-bar",
|
|
6609
|
+
"data-placement": "inline",
|
|
6610
|
+
className,
|
|
6611
|
+
style: { ...inlineStyle, ...style },
|
|
6612
|
+
...props,
|
|
6613
|
+
children: [
|
|
6614
|
+
/* @__PURE__ */ jsxs33(
|
|
6615
|
+
"div",
|
|
6616
|
+
{
|
|
6617
|
+
role: "status",
|
|
6618
|
+
"data-slot": "bulk-action-bar-state",
|
|
6619
|
+
style: {
|
|
6620
|
+
display: "flex",
|
|
6621
|
+
flex: "1 1 auto",
|
|
6622
|
+
minWidth: 0,
|
|
6623
|
+
alignItems: "center",
|
|
6624
|
+
columnGap: "var(--space-3)"
|
|
6625
|
+
},
|
|
6626
|
+
children: [
|
|
6627
|
+
countLabel,
|
|
6628
|
+
summarySlot
|
|
6629
|
+
]
|
|
6630
|
+
}
|
|
6631
|
+
),
|
|
6632
|
+
/* @__PURE__ */ jsxs33(
|
|
6633
|
+
"div",
|
|
6634
|
+
{
|
|
6635
|
+
"data-slot": "bulk-action-bar-controls",
|
|
6636
|
+
style: {
|
|
6637
|
+
display: "flex",
|
|
6638
|
+
marginLeft: "auto",
|
|
6639
|
+
alignItems: "center",
|
|
6640
|
+
gap: "var(--space-1)"
|
|
6641
|
+
},
|
|
6642
|
+
children: [
|
|
6643
|
+
count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx34(Divider, {}) : null,
|
|
6644
|
+
actionGroup,
|
|
6645
|
+
/* @__PURE__ */ jsx34(Divider, {}),
|
|
6646
|
+
/* @__PURE__ */ jsx34(ClearButton, { onClear })
|
|
6647
|
+
]
|
|
6648
|
+
}
|
|
6649
|
+
),
|
|
6650
|
+
trailingSlot
|
|
6651
|
+
]
|
|
6652
|
+
}
|
|
6653
|
+
);
|
|
6654
|
+
}
|
|
6092
6655
|
return /* @__PURE__ */ jsxs33(
|
|
6093
6656
|
"div",
|
|
6094
6657
|
{
|
|
@@ -6101,68 +6664,23 @@ function BulkActionBar({
|
|
|
6101
6664
|
"animate-[olun-bulk-action-bar-in_var(--dur-fast)_var(--ease-out)_both] motion-reduce:animate-none",
|
|
6102
6665
|
className
|
|
6103
6666
|
),
|
|
6104
|
-
style: {
|
|
6105
|
-
position: "sticky",
|
|
6106
|
-
bottom: "calc(var(--space-4) + env(safe-area-inset-bottom))",
|
|
6107
|
-
zIndex: 1100,
|
|
6108
|
-
margin: "0 auto",
|
|
6109
|
-
display: "flex",
|
|
6110
|
-
minHeight: 32,
|
|
6111
|
-
width: "fit-content",
|
|
6112
|
-
maxWidth: "calc(100% - var(--space-8))",
|
|
6113
|
-
alignItems: "center",
|
|
6114
|
-
gap: "var(--space-2)",
|
|
6115
|
-
borderRadius: 9999,
|
|
6116
|
-
border: "1px solid var(--border)",
|
|
6117
|
-
background: "var(--bg-raised)",
|
|
6118
|
-
padding: "var(--space-1) var(--space-2)",
|
|
6119
|
-
boxShadow: "var(--shadow-8)",
|
|
6120
|
-
...style
|
|
6121
|
-
},
|
|
6667
|
+
style: { ...floatingStyle, ...style },
|
|
6122
6668
|
...props,
|
|
6123
6669
|
children: [
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
{
|
|
6127
|
-
"data-slot": "bulk-action-bar-count",
|
|
6128
|
-
style: {
|
|
6129
|
-
paddingLeft: "var(--space-2)",
|
|
6130
|
-
paddingRight: "var(--space-1)",
|
|
6131
|
-
fontFamily: "var(--font-sans)",
|
|
6132
|
-
fontSize: 13,
|
|
6133
|
-
fontWeight: 500,
|
|
6134
|
-
fontVariantNumeric: "tabular-nums",
|
|
6135
|
-
color: "var(--text-primary)",
|
|
6136
|
-
whiteSpace: "nowrap"
|
|
6137
|
-
},
|
|
6138
|
-
children: count > 0 ? `${count.toLocaleString("ko-KR")}\uAC1C \uC120\uD0DD\uB428` : emptyHint
|
|
6139
|
-
}
|
|
6140
|
-
),
|
|
6670
|
+
countLabel,
|
|
6671
|
+
summarySlot,
|
|
6141
6672
|
count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx34(Divider, {}) : null,
|
|
6142
|
-
|
|
6143
|
-
"div",
|
|
6144
|
-
{
|
|
6145
|
-
"data-slot": "bulk-action-bar-actions",
|
|
6146
|
-
style: {
|
|
6147
|
-
display: "flex",
|
|
6148
|
-
minWidth: 0,
|
|
6149
|
-
flexWrap: "wrap",
|
|
6150
|
-
alignItems: "center",
|
|
6151
|
-
justifyContent: "flex-end",
|
|
6152
|
-
gap: 2
|
|
6153
|
-
},
|
|
6154
|
-
children: actions.map((action) => /* @__PURE__ */ jsx34(ActionButton, { action }, action.key))
|
|
6155
|
-
}
|
|
6156
|
-
),
|
|
6673
|
+
actionGroup,
|
|
6157
6674
|
/* @__PURE__ */ jsx34(Divider, {}),
|
|
6158
|
-
/* @__PURE__ */ jsx34(ClearButton, { onClear })
|
|
6675
|
+
/* @__PURE__ */ jsx34(ClearButton, { onClear }),
|
|
6676
|
+
trailingSlot
|
|
6159
6677
|
]
|
|
6160
6678
|
}
|
|
6161
6679
|
);
|
|
6162
6680
|
}
|
|
6163
6681
|
|
|
6164
6682
|
// src/components/ui/confirm-dialog.tsx
|
|
6165
|
-
import * as
|
|
6683
|
+
import * as React29 from "react";
|
|
6166
6684
|
import { Fragment as Fragment8, jsx as jsx35, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
6167
6685
|
var confirmDialogContentClassName = cn(
|
|
6168
6686
|
"fixed left-1/2 top-1/2 z-[var(--z-modal)]",
|
|
@@ -6179,6 +6697,7 @@ var confirmDialogTitleClassName = cn(
|
|
|
6179
6697
|
var confirmDialogDescriptionClassName = cn(
|
|
6180
6698
|
"break-keep text-[14px] leading-relaxed text-text-secondary"
|
|
6181
6699
|
);
|
|
6700
|
+
var confirmDialogBodyClassName = "min-w-0 text-[14px] leading-relaxed text-text-secondary";
|
|
6182
6701
|
var confirmDialogFooterClassName = "flex items-center justify-end gap-[var(--space-3)]";
|
|
6183
6702
|
function ConfirmDialog({
|
|
6184
6703
|
open,
|
|
@@ -6189,12 +6708,14 @@ function ConfirmDialog({
|
|
|
6189
6708
|
confirmLabel,
|
|
6190
6709
|
cancelLabel = "\uCDE8\uC18C",
|
|
6191
6710
|
onConfirm,
|
|
6192
|
-
loading = false
|
|
6711
|
+
loading = false,
|
|
6712
|
+
children,
|
|
6713
|
+
confirmDisabled = false
|
|
6193
6714
|
}) {
|
|
6194
|
-
const [pending, setPending] =
|
|
6195
|
-
const busyRef =
|
|
6715
|
+
const [pending, setPending] = React29.useState(false);
|
|
6716
|
+
const busyRef = React29.useRef(false);
|
|
6196
6717
|
const isBusy = loading || pending;
|
|
6197
|
-
const handleOpenChange =
|
|
6718
|
+
const handleOpenChange = React29.useCallback(
|
|
6198
6719
|
(nextOpen) => {
|
|
6199
6720
|
if (!nextOpen && isBusy) {
|
|
6200
6721
|
return;
|
|
@@ -6203,8 +6724,8 @@ function ConfirmDialog({
|
|
|
6203
6724
|
},
|
|
6204
6725
|
[isBusy, onOpenChange]
|
|
6205
6726
|
);
|
|
6206
|
-
const handleConfirm =
|
|
6207
|
-
if (busyRef.current || loading) {
|
|
6727
|
+
const handleConfirm = React29.useCallback(async () => {
|
|
6728
|
+
if (busyRef.current || loading || confirmDisabled) {
|
|
6208
6729
|
return;
|
|
6209
6730
|
}
|
|
6210
6731
|
busyRef.current = true;
|
|
@@ -6216,7 +6737,7 @@ function ConfirmDialog({
|
|
|
6216
6737
|
busyRef.current = false;
|
|
6217
6738
|
setPending(false);
|
|
6218
6739
|
}
|
|
6219
|
-
}, [loading, onConfirm, onOpenChange]);
|
|
6740
|
+
}, [confirmDisabled, loading, onConfirm, onOpenChange]);
|
|
6220
6741
|
const dialogBody = /* @__PURE__ */ jsxs34(Fragment8, { children: [
|
|
6221
6742
|
/* @__PURE__ */ jsx35("div", { className: "flex items-start justify-between gap-[var(--space-4)]", children: /* @__PURE__ */ jsxs34("div", { className: "min-w-0 space-y-[var(--space-2)]", children: [
|
|
6222
6743
|
/* @__PURE__ */ jsx35(
|
|
@@ -6236,6 +6757,7 @@ function ConfirmDialog({
|
|
|
6236
6757
|
}
|
|
6237
6758
|
) : null
|
|
6238
6759
|
] }) }),
|
|
6760
|
+
children != null ? /* @__PURE__ */ jsx35("div", { "data-slot": "confirm-dialog-body", className: confirmDialogBodyClassName, children }) : null,
|
|
6239
6761
|
/* @__PURE__ */ jsxs34(
|
|
6240
6762
|
"div",
|
|
6241
6763
|
{
|
|
@@ -6248,6 +6770,7 @@ function ConfirmDialog({
|
|
|
6248
6770
|
{
|
|
6249
6771
|
variant: tone === "destructive" ? "destructive" : "primary",
|
|
6250
6772
|
loading: isBusy,
|
|
6773
|
+
disabled: confirmDisabled,
|
|
6251
6774
|
onClick: handleConfirm,
|
|
6252
6775
|
children: confirmLabel
|
|
6253
6776
|
}
|
|
@@ -6301,7 +6824,7 @@ function Avatar({
|
|
|
6301
6824
|
"data-size": size,
|
|
6302
6825
|
className: cn(
|
|
6303
6826
|
"group/avatar relative flex shrink-0 overflow-hidden rounded-full select-none",
|
|
6304
|
-
"border border-[var(--border-subtle)] bg-[var(--bg-
|
|
6827
|
+
"border border-[var(--border-subtle)] bg-[var(--bg-inset)] text-text-secondary",
|
|
6305
6828
|
"h-9 w-9",
|
|
6306
6829
|
"data-[size=sm]:h-8 data-[size=sm]:w-8",
|
|
6307
6830
|
"data-[size=lg]:h-11 data-[size=lg]:w-11",
|
|
@@ -6346,7 +6869,7 @@ function AvatarFallback({
|
|
|
6346
6869
|
"data-slot": "avatar-fallback",
|
|
6347
6870
|
className: cn(
|
|
6348
6871
|
"flex h-full w-full items-center justify-center rounded-full",
|
|
6349
|
-
"bg-[var(--bg-
|
|
6872
|
+
"bg-[var(--bg-inset)] text-sm font-semibold text-text-secondary",
|
|
6350
6873
|
"font-[family-name:var(--font-display)]",
|
|
6351
6874
|
"group-data-[size=sm]/avatar:text-xs",
|
|
6352
6875
|
className
|
|
@@ -6358,7 +6881,7 @@ function AvatarFallback({
|
|
|
6358
6881
|
}
|
|
6359
6882
|
|
|
6360
6883
|
// src/components/ui/badge.tsx
|
|
6361
|
-
import * as
|
|
6884
|
+
import * as React30 from "react";
|
|
6362
6885
|
import { jsx as jsx38, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
6363
6886
|
var DOT = {
|
|
6364
6887
|
error: "var(--semantic-error-fg)",
|
|
@@ -6368,7 +6891,7 @@ var DOT = {
|
|
|
6368
6891
|
neutral: "var(--text-tertiary)",
|
|
6369
6892
|
brand: "var(--accent-pop)"
|
|
6370
6893
|
};
|
|
6371
|
-
var Badge =
|
|
6894
|
+
var Badge = React30.forwardRef(
|
|
6372
6895
|
({ tone = "neutral", className, children, ...props }, ref) => /* @__PURE__ */ jsxs35(
|
|
6373
6896
|
"span",
|
|
6374
6897
|
{
|
|
@@ -6400,7 +6923,7 @@ var Badge = React29.forwardRef(
|
|
|
6400
6923
|
Badge.displayName = "Badge";
|
|
6401
6924
|
|
|
6402
6925
|
// src/components/ui/two-tier-badge.tsx
|
|
6403
|
-
import * as
|
|
6926
|
+
import * as React31 from "react";
|
|
6404
6927
|
import { jsx as jsx39, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
6405
6928
|
var FG = {
|
|
6406
6929
|
neutral: "var(--text-secondary)",
|
|
@@ -6422,7 +6945,7 @@ var SEGMENT = {
|
|
|
6422
6945
|
md: "gap-[7px] py-[var(--space-1)] px-[var(--space-3)] text-[14px]"
|
|
6423
6946
|
};
|
|
6424
6947
|
var DOT2 = { xs: 5, sm: 6, md: 7 };
|
|
6425
|
-
var TwoTierBadge =
|
|
6948
|
+
var TwoTierBadge = React31.forwardRef(
|
|
6426
6949
|
({ primary, secondary, tone = "neutral", emphasis = "subtle", size = "sm", showDot = false, className, style, ...props }, ref) => {
|
|
6427
6950
|
const strong = emphasis === "strong";
|
|
6428
6951
|
const fg = FG[tone];
|
|
@@ -6492,7 +7015,7 @@ var TwoTierBadge = React30.forwardRef(
|
|
|
6492
7015
|
TwoTierBadge.displayName = "TwoTierBadge";
|
|
6493
7016
|
|
|
6494
7017
|
// src/components/ui/status-badge.tsx
|
|
6495
|
-
import * as
|
|
7018
|
+
import * as React32 from "react";
|
|
6496
7019
|
import { jsx as jsx40, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
6497
7020
|
var ROLE = {
|
|
6498
7021
|
error: "error",
|
|
@@ -6522,7 +7045,7 @@ var SIZE = {
|
|
|
6522
7045
|
sm: { cls: "gap-[6px] py-[var(--space-1)] px-[var(--space-2)] text-[12px]", dot: 6 },
|
|
6523
7046
|
md: { cls: "gap-[var(--space-2)] py-[var(--space-1)] px-[14px] text-[14px]", dot: 7 }
|
|
6524
7047
|
};
|
|
6525
|
-
var StatusBadge =
|
|
7048
|
+
var StatusBadge = React32.forwardRef(
|
|
6526
7049
|
({ status = "active", emphasis = "subtle", size = "sm", showDot = true, pulse = true, className, children, style, ...props }, ref) => {
|
|
6527
7050
|
const role = ROLE[status];
|
|
6528
7051
|
const fg = FG2[role];
|
|
@@ -6573,7 +7096,7 @@ var StatusBadge = React31.forwardRef(
|
|
|
6573
7096
|
StatusBadge.displayName = "StatusBadge";
|
|
6574
7097
|
|
|
6575
7098
|
// src/components/ui/notification-badge.tsx
|
|
6576
|
-
import * as
|
|
7099
|
+
import * as React33 from "react";
|
|
6577
7100
|
import { cva as cva13 } from "class-variance-authority";
|
|
6578
7101
|
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
6579
7102
|
var notificationBadgeVariants = cva13(
|
|
@@ -6606,7 +7129,7 @@ function formatNotificationCount(count, max) {
|
|
|
6606
7129
|
}
|
|
6607
7130
|
return String(count);
|
|
6608
7131
|
}
|
|
6609
|
-
var NotificationBadge =
|
|
7132
|
+
var NotificationBadge = React33.forwardRef(
|
|
6610
7133
|
({
|
|
6611
7134
|
className,
|
|
6612
7135
|
count,
|
|
@@ -6639,7 +7162,7 @@ var NotificationBadge = React32.forwardRef(
|
|
|
6639
7162
|
NotificationBadge.displayName = "NotificationBadge";
|
|
6640
7163
|
|
|
6641
7164
|
// src/components/ui/empty-state.tsx
|
|
6642
|
-
import * as
|
|
7165
|
+
import * as React34 from "react";
|
|
6643
7166
|
import { cva as cva14 } from "class-variance-authority";
|
|
6644
7167
|
import { jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
6645
7168
|
var emptyStateBaseVariants = cva14(
|
|
@@ -6713,7 +7236,7 @@ var iconSize3 = {
|
|
|
6713
7236
|
md: 20,
|
|
6714
7237
|
lg: 24
|
|
6715
7238
|
};
|
|
6716
|
-
var EmptyState =
|
|
7239
|
+
var EmptyState = React34.forwardRef(
|
|
6717
7240
|
({
|
|
6718
7241
|
className,
|
|
6719
7242
|
size = "md",
|
|
@@ -6781,7 +7304,7 @@ var EmptyState = React33.forwardRef(
|
|
|
6781
7304
|
EmptyState.displayName = "EmptyState";
|
|
6782
7305
|
|
|
6783
7306
|
// src/components/ui/error-state.tsx
|
|
6784
|
-
import * as
|
|
7307
|
+
import * as React35 from "react";
|
|
6785
7308
|
import { AlertTriangle } from "lucide-react";
|
|
6786
7309
|
import { cva as cva15 } from "class-variance-authority";
|
|
6787
7310
|
import { jsx as jsx43, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
@@ -6806,7 +7329,7 @@ var errorStateVariants = cva15(
|
|
|
6806
7329
|
}
|
|
6807
7330
|
}
|
|
6808
7331
|
);
|
|
6809
|
-
var ErrorState =
|
|
7332
|
+
var ErrorState = React35.forwardRef(
|
|
6810
7333
|
({
|
|
6811
7334
|
className,
|
|
6812
7335
|
size = "md",
|
|
@@ -6869,12 +7392,14 @@ var ErrorState = React34.forwardRef(
|
|
|
6869
7392
|
ErrorState.displayName = "ErrorState";
|
|
6870
7393
|
|
|
6871
7394
|
// src/components/ui/skeleton.tsx
|
|
6872
|
-
import * as
|
|
7395
|
+
import * as React36 from "react";
|
|
6873
7396
|
import { cva as cva16 } from "class-variance-authority";
|
|
6874
7397
|
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
6875
7398
|
var skeletonVariants = cva16(
|
|
6876
7399
|
[
|
|
6877
|
-
|
|
7400
|
+
// bg-inset: light #F1F2F4 reads on white surfaces (bg-raised was white = invisible);
|
|
7401
|
+
// dark value equals the old bg-raised (#16181D), so dark mode is unchanged.
|
|
7402
|
+
"animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]",
|
|
6878
7403
|
"motion-reduce:animate-none motion-reduce:opacity-80"
|
|
6879
7404
|
].join(" "),
|
|
6880
7405
|
{
|
|
@@ -6913,7 +7438,7 @@ var spinnerVariants = cva16(
|
|
|
6913
7438
|
}
|
|
6914
7439
|
}
|
|
6915
7440
|
);
|
|
6916
|
-
var Skeleton =
|
|
7441
|
+
var Skeleton = React36.forwardRef(
|
|
6917
7442
|
({ className, shape, style, ...props }, ref) => /* @__PURE__ */ jsx44(
|
|
6918
7443
|
"div",
|
|
6919
7444
|
{
|
|
@@ -6927,7 +7452,7 @@ var Skeleton = React35.forwardRef(
|
|
|
6927
7452
|
);
|
|
6928
7453
|
Skeleton.displayName = "Skeleton";
|
|
6929
7454
|
var defaultTextWidths = ["92%", "84%", "68%", "76%"];
|
|
6930
|
-
var SkeletonText =
|
|
7455
|
+
var SkeletonText = React36.forwardRef(
|
|
6931
7456
|
({ className, lines = 3, widths = defaultTextWidths, ...props }, ref) => /* @__PURE__ */ jsx44(
|
|
6932
7457
|
"div",
|
|
6933
7458
|
{
|
|
@@ -6947,7 +7472,7 @@ var SkeletonText = React35.forwardRef(
|
|
|
6947
7472
|
)
|
|
6948
7473
|
);
|
|
6949
7474
|
SkeletonText.displayName = "SkeletonText";
|
|
6950
|
-
var SkeletonRow =
|
|
7475
|
+
var SkeletonRow = React36.forwardRef(
|
|
6951
7476
|
({
|
|
6952
7477
|
className,
|
|
6953
7478
|
columns,
|
|
@@ -7004,7 +7529,7 @@ var SkeletonRow = React35.forwardRef(
|
|
|
7004
7529
|
}
|
|
7005
7530
|
);
|
|
7006
7531
|
SkeletonRow.displayName = "SkeletonRow";
|
|
7007
|
-
var Spinner =
|
|
7532
|
+
var Spinner = React36.forwardRef(
|
|
7008
7533
|
({ className, size, label = "\uB85C\uB529 \uC911", ...props }, ref) => /* @__PURE__ */ jsx44(
|
|
7009
7534
|
"span",
|
|
7010
7535
|
{
|
|
@@ -7020,7 +7545,7 @@ var Spinner = React35.forwardRef(
|
|
|
7020
7545
|
Spinner.displayName = "Spinner";
|
|
7021
7546
|
|
|
7022
7547
|
// src/components/ui/pagination.tsx
|
|
7023
|
-
import * as
|
|
7548
|
+
import * as React37 from "react";
|
|
7024
7549
|
import { ChevronsLeft, ChevronLeft, ChevronRight as ChevronRight2, ChevronsRight } from "lucide-react";
|
|
7025
7550
|
import { cva as cva17 } from "class-variance-authority";
|
|
7026
7551
|
|
|
@@ -7161,7 +7686,7 @@ function NavigationButton({
|
|
|
7161
7686
|
}
|
|
7162
7687
|
);
|
|
7163
7688
|
}
|
|
7164
|
-
var Pagination =
|
|
7689
|
+
var Pagination = React37.forwardRef(
|
|
7165
7690
|
({
|
|
7166
7691
|
className,
|
|
7167
7692
|
size = "standard",
|
|
@@ -7303,7 +7828,7 @@ import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
|
7303
7828
|
var modeToggleVariants = cva18(
|
|
7304
7829
|
[
|
|
7305
7830
|
"inline-flex items-center rounded-[var(--radius-sm)] border border-[var(--border-subtle)]",
|
|
7306
|
-
"bg-[var(--bg-
|
|
7831
|
+
"bg-[var(--bg-inset)] p-[2px]"
|
|
7307
7832
|
].join(" ")
|
|
7308
7833
|
);
|
|
7309
7834
|
var modeToggleItemVariants = cva18(
|
|
@@ -7367,7 +7892,7 @@ function ModeToggle({
|
|
|
7367
7892
|
}
|
|
7368
7893
|
|
|
7369
7894
|
// src/components/ui/action-footer.tsx
|
|
7370
|
-
import * as
|
|
7895
|
+
import * as React38 from "react";
|
|
7371
7896
|
import { cva as cva19 } from "class-variance-authority";
|
|
7372
7897
|
import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
7373
7898
|
var actionFooterVariants = cva19(
|
|
@@ -7454,7 +7979,7 @@ function renderAction(action) {
|
|
|
7454
7979
|
action.id ?? action.label
|
|
7455
7980
|
);
|
|
7456
7981
|
}
|
|
7457
|
-
var ActionFooter =
|
|
7982
|
+
var ActionFooter = React38.forwardRef(
|
|
7458
7983
|
({
|
|
7459
7984
|
className,
|
|
7460
7985
|
status,
|
|
@@ -7524,7 +8049,7 @@ var ActionFooter = React37.forwardRef(
|
|
|
7524
8049
|
ActionFooter.displayName = "ActionFooter";
|
|
7525
8050
|
|
|
7526
8051
|
// src/components/ui/toast.tsx
|
|
7527
|
-
import * as
|
|
8052
|
+
import * as React39 from "react";
|
|
7528
8053
|
import { cva as cva20 } from "class-variance-authority";
|
|
7529
8054
|
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
7530
8055
|
var DOT3 = {
|
|
@@ -7644,7 +8169,7 @@ var toast = {
|
|
|
7644
8169
|
}
|
|
7645
8170
|
};
|
|
7646
8171
|
var Toast = toast;
|
|
7647
|
-
var ToastRoot =
|
|
8172
|
+
var ToastRoot = React39.forwardRef(
|
|
7648
8173
|
({
|
|
7649
8174
|
className,
|
|
7650
8175
|
id,
|
|
@@ -7661,10 +8186,10 @@ var ToastRoot = React38.forwardRef(
|
|
|
7661
8186
|
...props
|
|
7662
8187
|
}, ref) => {
|
|
7663
8188
|
const durationMs = getToastDuration({ message, variant, duration });
|
|
7664
|
-
const onCloseRef =
|
|
8189
|
+
const onCloseRef = React39.useRef(onClose);
|
|
7665
8190
|
onCloseRef.current = onClose;
|
|
7666
|
-
const timerRef =
|
|
7667
|
-
|
|
8191
|
+
const timerRef = React39.useRef(null);
|
|
8192
|
+
React39.useEffect(() => {
|
|
7668
8193
|
if (!onCloseRef.current) return void 0;
|
|
7669
8194
|
const timer = createToastTimer(durationMs, () => onCloseRef.current?.());
|
|
7670
8195
|
timerRef.current = timer;
|
|
@@ -7761,7 +8286,7 @@ var ToastRoot = React38.forwardRef(
|
|
|
7761
8286
|
}
|
|
7762
8287
|
);
|
|
7763
8288
|
ToastRoot.displayName = "ToastRoot";
|
|
7764
|
-
var ToastViewport =
|
|
8289
|
+
var ToastViewport = React39.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx49(
|
|
7765
8290
|
"ol",
|
|
7766
8291
|
{
|
|
7767
8292
|
ref,
|
|
@@ -7772,8 +8297,8 @@ var ToastViewport = React38.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
7772
8297
|
));
|
|
7773
8298
|
ToastViewport.displayName = "ToastViewport";
|
|
7774
8299
|
function ToastProvider({ children, maxToasts = 3, className, ...props }) {
|
|
7775
|
-
const [items, setItems] =
|
|
7776
|
-
|
|
8300
|
+
const [items, setItems] = React39.useState([]);
|
|
8301
|
+
React39.useEffect(
|
|
7777
8302
|
() => toast.subscribe((nextItems) => {
|
|
7778
8303
|
setItems(limitToasts(nextItems, maxToasts));
|
|
7779
8304
|
}),
|
|
@@ -7786,7 +8311,7 @@ function ToastProvider({ children, maxToasts = 3, className, ...props }) {
|
|
|
7786
8311
|
}
|
|
7787
8312
|
|
|
7788
8313
|
// src/components/ui/otp-field.tsx
|
|
7789
|
-
import * as
|
|
8314
|
+
import * as React40 from "react";
|
|
7790
8315
|
import { cva as cva21 } from "class-variance-authority";
|
|
7791
8316
|
import { AlertCircle as AlertCircle4 } from "lucide-react";
|
|
7792
8317
|
import { Fragment as Fragment9, jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
@@ -7819,14 +8344,14 @@ var otpFieldGroupVariants = cva21("flex items-start gap-[var(--space-2)] pt-[var
|
|
|
7819
8344
|
});
|
|
7820
8345
|
var otpCellVariants = cva21(
|
|
7821
8346
|
[
|
|
7822
|
-
"flex items-center justify-center rounded-[var(--radius-
|
|
8347
|
+
"flex items-center justify-center rounded-[var(--radius-md)] border",
|
|
7823
8348
|
"border-[var(--border)] text-foreground",
|
|
7824
8349
|
"font-[family-name:var(--font-display)] tabular-nums",
|
|
7825
8350
|
"text-center leading-none caret-[var(--text-primary)]",
|
|
7826
8351
|
"transition-[border-color,box-shadow,background-color,color] motion-reduce:transition-none",
|
|
7827
8352
|
"focus:outline-none focus:border-[var(--focus-ring)] focus:shadow-[0_0_0_1px_var(--focus-ring)]",
|
|
7828
8353
|
"disabled:cursor-not-allowed disabled:border-[var(--border-subtle)] disabled:bg-[var(--action-disabled-bg)] disabled:text-text-disabled",
|
|
7829
|
-
"read-only:cursor-default read-only:bg-[var(--bg-
|
|
8354
|
+
"read-only:cursor-default read-only:bg-[var(--bg-inset)] read-only:text-text-secondary",
|
|
7830
8355
|
"aria-[invalid=true]:border-[var(--error)] aria-[invalid=true]:focus:shadow-[0_0_0_1px_var(--error)]",
|
|
7831
8356
|
"data-[state=error]:border-[var(--error)] data-[state=error]:focus:shadow-[0_0_0_1px_var(--error)]",
|
|
7832
8357
|
"data-[state=filled]:border-[var(--border-strong)]"
|
|
@@ -7916,7 +8441,7 @@ function fillDigitsFromIndex(slots, index, inserted, length) {
|
|
|
7916
8441
|
focusIndex: Math.min(cursor, length - 1)
|
|
7917
8442
|
};
|
|
7918
8443
|
}
|
|
7919
|
-
var OTPField =
|
|
8444
|
+
var OTPField = React40.forwardRef(
|
|
7920
8445
|
({
|
|
7921
8446
|
className,
|
|
7922
8447
|
defaultValue,
|
|
@@ -7938,24 +8463,24 @@ var OTPField = React39.forwardRef(
|
|
|
7938
8463
|
required,
|
|
7939
8464
|
...props
|
|
7940
8465
|
}, ref) => {
|
|
7941
|
-
const generatedId =
|
|
8466
|
+
const generatedId = React40.useId();
|
|
7942
8467
|
const fieldId = id ?? generatedId;
|
|
7943
8468
|
const labelId = `${fieldId}-label`;
|
|
7944
8469
|
const helperId = helperText ? `${fieldId}-helper` : void 0;
|
|
7945
8470
|
const errorId = errorText ? `${fieldId}-error` : void 0;
|
|
7946
8471
|
const resolvedState = invalid || errorText ? "error" : "default";
|
|
7947
8472
|
const isControlled = value !== void 0;
|
|
7948
|
-
const [uncontrolledSlots, setUncontrolledSlots] =
|
|
8473
|
+
const [uncontrolledSlots, setUncontrolledSlots] = React40.useState(
|
|
7949
8474
|
() => toDigitsArray(onlyDigits(defaultValue, length), length)
|
|
7950
8475
|
);
|
|
7951
|
-
const resolvedSlots =
|
|
8476
|
+
const resolvedSlots = React40.useMemo(
|
|
7952
8477
|
() => isControlled ? toDigitsArray(onlyDigits(value, length), length) : uncontrolledSlots,
|
|
7953
8478
|
[isControlled, length, uncontrolledSlots, value]
|
|
7954
8479
|
);
|
|
7955
8480
|
const resolvedValue = joinDigits(resolvedSlots).slice(0, length);
|
|
7956
|
-
const cellsRef =
|
|
8481
|
+
const cellsRef = React40.useRef([]);
|
|
7957
8482
|
const groupDescribedBy = [helperId, errorId].filter(Boolean).join(" ") || void 0;
|
|
7958
|
-
const setResolvedValue =
|
|
8483
|
+
const setResolvedValue = React40.useCallback(
|
|
7959
8484
|
(nextSlots, focusIndex) => {
|
|
7960
8485
|
const normalizedSlots = nextSlots.slice(0, length);
|
|
7961
8486
|
const normalizedValue = joinDigits(normalizedSlots).slice(0, length);
|
|
@@ -8145,7 +8670,7 @@ var OTPField = React39.forwardRef(
|
|
|
8145
8670
|
OTPField.displayName = "OTPField";
|
|
8146
8671
|
|
|
8147
8672
|
// src/components/ui/search-field.tsx
|
|
8148
|
-
import * as
|
|
8673
|
+
import * as React41 from "react";
|
|
8149
8674
|
import { Search, X as X4 } from "lucide-react";
|
|
8150
8675
|
import { cva as cva22 } from "class-variance-authority";
|
|
8151
8676
|
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
@@ -8164,7 +8689,7 @@ var searchFieldVariants = cva22("relative flex w-full items-center", {
|
|
|
8164
8689
|
});
|
|
8165
8690
|
var searchFieldInputVariants = cva22(
|
|
8166
8691
|
[
|
|
8167
|
-
"h-full w-full rounded-[var(--radius-
|
|
8692
|
+
"h-full w-full rounded-[var(--radius-md)] border",
|
|
8168
8693
|
"border-[var(--border)]",
|
|
8169
8694
|
"appearance-none [&::-webkit-search-cancel-button]:hidden [&::-webkit-search-decoration]:hidden",
|
|
8170
8695
|
"font-[family-name:var(--font-body)] text-foreground",
|
|
@@ -8213,7 +8738,7 @@ var iconSize4 = {
|
|
|
8213
8738
|
function hasVisibleValue(value) {
|
|
8214
8739
|
return typeof value === "string" ? value.length > 0 : value !== void 0;
|
|
8215
8740
|
}
|
|
8216
|
-
var SearchField =
|
|
8741
|
+
var SearchField = React41.forwardRef(
|
|
8217
8742
|
({
|
|
8218
8743
|
className,
|
|
8219
8744
|
inputMode = "search",
|
|
@@ -8229,12 +8754,12 @@ var SearchField = React40.forwardRef(
|
|
|
8229
8754
|
...props
|
|
8230
8755
|
}, ref) => {
|
|
8231
8756
|
const resolvedSize = size ?? "md";
|
|
8232
|
-
const inputRef =
|
|
8233
|
-
const [hasText, setHasText] =
|
|
8757
|
+
const inputRef = React41.useRef(null);
|
|
8758
|
+
const [hasText, setHasText] = React41.useState(
|
|
8234
8759
|
() => hasVisibleValue(value ?? defaultValue)
|
|
8235
8760
|
);
|
|
8236
|
-
|
|
8237
|
-
|
|
8761
|
+
React41.useImperativeHandle(ref, () => inputRef.current);
|
|
8762
|
+
React41.useEffect(() => {
|
|
8238
8763
|
if (value !== void 0) {
|
|
8239
8764
|
setHasText(hasVisibleValue(value));
|
|
8240
8765
|
}
|
|
@@ -8304,7 +8829,7 @@ var SearchField = React40.forwardRef(
|
|
|
8304
8829
|
SearchField.displayName = "SearchField";
|
|
8305
8830
|
|
|
8306
8831
|
// src/components/ui/checkbox-group.tsx
|
|
8307
|
-
import * as
|
|
8832
|
+
import * as React42 from "react";
|
|
8308
8833
|
import { cva as cva23 } from "class-variance-authority";
|
|
8309
8834
|
import { jsx as jsx52 } from "react/jsx-runtime";
|
|
8310
8835
|
var checkboxGroupVariants = cva23("gap-[var(--space-2)]", {
|
|
@@ -8332,7 +8857,7 @@ var checkboxGroupVariants = cva23("gap-[var(--space-2)]", {
|
|
|
8332
8857
|
function toSelectionSet(value) {
|
|
8333
8858
|
return new Set(value ?? []);
|
|
8334
8859
|
}
|
|
8335
|
-
var CheckboxGroup =
|
|
8860
|
+
var CheckboxGroup = React42.forwardRef(
|
|
8336
8861
|
({
|
|
8337
8862
|
className,
|
|
8338
8863
|
children,
|
|
@@ -8348,14 +8873,14 @@ var CheckboxGroup = React41.forwardRef(
|
|
|
8348
8873
|
...props
|
|
8349
8874
|
}, ref) => {
|
|
8350
8875
|
const isControlled = value != null;
|
|
8351
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
8876
|
+
const [uncontrolledValue, setUncontrolledValue] = React42.useState(
|
|
8352
8877
|
() => toSelectionSet(defaultValue)
|
|
8353
8878
|
);
|
|
8354
|
-
const selectedValues =
|
|
8879
|
+
const selectedValues = React42.useMemo(
|
|
8355
8880
|
() => isControlled ? toSelectionSet(value) : uncontrolledValue,
|
|
8356
8881
|
[isControlled, uncontrolledValue, value]
|
|
8357
8882
|
);
|
|
8358
|
-
const toggleValue =
|
|
8883
|
+
const toggleValue = React42.useCallback(
|
|
8359
8884
|
(itemValue, checked) => {
|
|
8360
8885
|
const nextValues = new Set(selectedValues);
|
|
8361
8886
|
if (checked) {
|
|
@@ -8371,7 +8896,7 @@ var CheckboxGroup = React41.forwardRef(
|
|
|
8371
8896
|
},
|
|
8372
8897
|
[isControlled, onValueChange, selectedValues]
|
|
8373
8898
|
);
|
|
8374
|
-
const contextValue =
|
|
8899
|
+
const contextValue = React42.useMemo(
|
|
8375
8900
|
() => ({
|
|
8376
8901
|
appearance,
|
|
8377
8902
|
density,
|
|
@@ -8406,7 +8931,7 @@ var CheckboxGroup = React41.forwardRef(
|
|
|
8406
8931
|
CheckboxGroup.displayName = "CheckboxGroup";
|
|
8407
8932
|
|
|
8408
8933
|
// src/components/ui/radio-group.tsx
|
|
8409
|
-
import * as
|
|
8934
|
+
import * as React43 from "react";
|
|
8410
8935
|
import { cva as cva24 } from "class-variance-authority";
|
|
8411
8936
|
import { Circle } from "lucide-react";
|
|
8412
8937
|
import { RadioGroup as RadioGroupPrimitive } from "radix-ui";
|
|
@@ -8499,11 +9024,11 @@ var radioControlVariants = cva24(
|
|
|
8499
9024
|
}
|
|
8500
9025
|
}
|
|
8501
9026
|
);
|
|
8502
|
-
var RadioGroupContext =
|
|
9027
|
+
var RadioGroupContext = React43.createContext({
|
|
8503
9028
|
appearance: "plain",
|
|
8504
9029
|
density: "comfortable"
|
|
8505
9030
|
});
|
|
8506
|
-
var RadioGroup =
|
|
9031
|
+
var RadioGroup = React43.forwardRef(
|
|
8507
9032
|
({
|
|
8508
9033
|
className,
|
|
8509
9034
|
children,
|
|
@@ -8514,7 +9039,7 @@ var RadioGroup = React42.forwardRef(
|
|
|
8514
9039
|
required,
|
|
8515
9040
|
...props
|
|
8516
9041
|
}, ref) => {
|
|
8517
|
-
const contextValue =
|
|
9042
|
+
const contextValue = React43.useMemo(
|
|
8518
9043
|
() => ({ appearance, density }),
|
|
8519
9044
|
[appearance, density]
|
|
8520
9045
|
);
|
|
@@ -8541,9 +9066,9 @@ var RadioGroup = React42.forwardRef(
|
|
|
8541
9066
|
}
|
|
8542
9067
|
);
|
|
8543
9068
|
RadioGroup.displayName = "RadioGroup";
|
|
8544
|
-
var Radio =
|
|
8545
|
-
const { appearance, density } =
|
|
8546
|
-
const generatedId =
|
|
9069
|
+
var Radio = React43.forwardRef(({ className, children, description, id, ...props }, ref) => {
|
|
9070
|
+
const { appearance, density } = React43.useContext(RadioGroupContext);
|
|
9071
|
+
const generatedId = React43.useId();
|
|
8547
9072
|
const radioId = id ?? generatedId;
|
|
8548
9073
|
const labelId = `${radioId}-label`;
|
|
8549
9074
|
const descriptionId = description ? `${radioId}-description` : void 0;
|
|
@@ -8711,7 +9236,7 @@ function Progress({
|
|
|
8711
9236
|
}
|
|
8712
9237
|
|
|
8713
9238
|
// src/components/ui/tree-view.tsx
|
|
8714
|
-
import * as
|
|
9239
|
+
import * as React44 from "react";
|
|
8715
9240
|
import { ChevronRight as ChevronRight3 } from "lucide-react";
|
|
8716
9241
|
import { cva as cva25 } from "class-variance-authority";
|
|
8717
9242
|
import { jsx as jsx56, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
@@ -8817,27 +9342,27 @@ function TreeView({
|
|
|
8817
9342
|
...rest
|
|
8818
9343
|
}) {
|
|
8819
9344
|
const isExpandedControlled = expandedIds !== void 0;
|
|
8820
|
-
const [internalExpanded, setInternalExpanded] =
|
|
9345
|
+
const [internalExpanded, setInternalExpanded] = React44.useState(
|
|
8821
9346
|
() => defaultExpandedIds ?? []
|
|
8822
9347
|
);
|
|
8823
9348
|
const expandedList = isExpandedControlled ? expandedIds : internalExpanded;
|
|
8824
|
-
const expandedSet =
|
|
8825
|
-
const items =
|
|
9349
|
+
const expandedSet = React44.useMemo(() => new Set(expandedList), [expandedList]);
|
|
9350
|
+
const items = React44.useMemo(
|
|
8826
9351
|
() => flattenVisibleNodes(nodes, getChildren, expandedSet),
|
|
8827
9352
|
[nodes, getChildren, expandedSet]
|
|
8828
9353
|
);
|
|
8829
|
-
const [focusedId, setFocusedId] =
|
|
9354
|
+
const [focusedId, setFocusedId] = React44.useState(null);
|
|
8830
9355
|
const visibleIds = items.map((item) => item.id);
|
|
8831
9356
|
const activeId = focusedId && visibleIds.includes(focusedId) ? focusedId : selectedId && visibleIds.includes(selectedId) ? selectedId : visibleIds[0] ?? null;
|
|
8832
|
-
const itemRefs =
|
|
8833
|
-
const commitExpanded =
|
|
9357
|
+
const itemRefs = React44.useRef(/* @__PURE__ */ new Map());
|
|
9358
|
+
const commitExpanded = React44.useCallback(
|
|
8834
9359
|
(next) => {
|
|
8835
9360
|
if (!isExpandedControlled) setInternalExpanded(next);
|
|
8836
9361
|
onExpandedChange?.(next);
|
|
8837
9362
|
},
|
|
8838
9363
|
[isExpandedControlled, onExpandedChange]
|
|
8839
9364
|
);
|
|
8840
|
-
const setExpanded =
|
|
9365
|
+
const setExpanded = React44.useCallback(
|
|
8841
9366
|
(id, expand) => {
|
|
8842
9367
|
const has = expandedSet.has(id);
|
|
8843
9368
|
if (expand && !has) {
|
|
@@ -8848,7 +9373,7 @@ function TreeView({
|
|
|
8848
9373
|
},
|
|
8849
9374
|
[commitExpanded, expandedList, expandedSet]
|
|
8850
9375
|
);
|
|
8851
|
-
const focusItem =
|
|
9376
|
+
const focusItem = React44.useCallback((id) => {
|
|
8852
9377
|
setFocusedId(id);
|
|
8853
9378
|
itemRefs.current.get(id)?.focus();
|
|
8854
9379
|
}, []);
|