@olundot/ui 0.20.0-next.4 → 0.20.0-next.6

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 CHANGED
@@ -184,21 +184,46 @@ function useOlunTheme() {
184
184
  // src/components/ui/button.tsx
185
185
  import * as React from "react";
186
186
  import { cva } from "class-variance-authority";
187
- import { Loader2 } from "lucide-react";
187
+ import { ChevronDown, Loader2 } from "lucide-react";
188
188
  import { Slot } from "radix-ui";
189
189
 
190
+ // src/components/ui/surface.ts
191
+ var insetMarkerContext = "[--fill-on-bg:var(--fill-on-inset)]";
192
+ var surfaceMarkerContext = "[--fill-on-bg:initial]";
193
+ var surfaceClassNames = {
194
+ surface: `bg-[var(--bg-surface)] ${surfaceMarkerContext}`,
195
+ canvas: `bg-[var(--bg-canvas)] ${surfaceMarkerContext}`,
196
+ raised: `bg-[var(--bg-raised)] ${surfaceMarkerContext}`
197
+ };
198
+ var fieldSurfaceClassNames = {
199
+ surface: "bg-[var(--bg-surface)]",
200
+ canvas: "bg-[var(--bg-canvas)]",
201
+ raised: "bg-[var(--bg-raised)]"
202
+ };
203
+ var selectSurfaceClassNames = {
204
+ surface: "bg-[var(--bg-surface)] [background-color:var(--bg-surface)]",
205
+ canvas: "bg-[var(--bg-canvas)] [background-color:var(--bg-canvas)]",
206
+ raised: "bg-[var(--bg-raised)] [background-color:var(--bg-raised)]"
207
+ };
208
+
190
209
  // src/components/ui/action-variants.ts
191
210
  var actionPaint = {
192
211
  // = Button `primary`
193
212
  filledPrimary: "border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-fg)] hover:bg-[var(--primary-hover)] hover:border-[var(--primary-hover)]",
194
213
  // = IconButton `subtle`; the transparent 1px border keeps Button's box model
195
- filledNeutral: "border-transparent bg-[var(--bg-inset)] text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
214
+ filledNeutral: `border-transparent bg-[var(--bg-inset)] text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground ${insetMarkerContext}`,
196
215
  // = Button `danger`
197
216
  filledDanger: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
198
217
  // = Button `secondary`
199
- outlineNeutral: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
218
+ outlineNeutral: `border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)] ${surfaceMarkerContext}`,
219
+ // Destructive action that is not the main one: outline neutral's surface, error border and
220
+ // label, error wash on hover.
221
+ outlineDanger: `border-[var(--error)] bg-[var(--bg-surface)] text-[var(--error)] hover:bg-[var(--error-bg)] ${surfaceMarkerContext}`,
200
222
  // = Button and IconButton `ghost`
201
- ghostNeutral: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground"
223
+ ghostNeutral: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
224
+ // Button `appearance="link"` only: the label color; the box and underline live in button.tsx.
225
+ linkPrimary: "text-[var(--accent)]",
226
+ linkDanger: "text-[var(--error)]"
202
227
  };
203
228
  var actionAxisVariants = {
204
229
  appearance: { filled: "", outline: "", ghost: "" },
@@ -209,6 +234,7 @@ var actionCompoundVariants = [
209
234
  { appearance: "filled", tone: "neutral", className: actionPaint.filledNeutral },
210
235
  { appearance: "filled", tone: "danger", className: actionPaint.filledDanger },
211
236
  { appearance: "outline", tone: "neutral", className: actionPaint.outlineNeutral },
237
+ { appearance: "outline", tone: "danger", className: actionPaint.outlineDanger },
212
238
  { appearance: "ghost", tone: "neutral", className: actionPaint.ghostNeutral }
213
239
  ];
214
240
  function resolveActionStyle(appearance, tone, fallback) {
@@ -228,17 +254,13 @@ var buttonSizes = {
228
254
  // xs/sm: invisible ::before stretches the hit area to 44px tall (#69), vertically only so
229
255
  // side-by-side buttons never overlap. Its inset is measured from the padding box, inside
230
256
  // the 1px border every variant carries: inset = (44 - (height - 2 × 1px)) / 2.
231
- // IconButton with text reuses these through `buttonSizeClassName`.
257
+ // IconButton with text renders through `buttonVariants`, so it takes these too.
232
258
  xs: "relative h-[28px] gap-[6px] px-[var(--space-3)] text-[12px] leading-[14px] before:absolute before:inset-x-0 before:-inset-y-[9px] before:content-[''] [&_svg]:size-[14px] [&_svg]:stroke-[1.75]",
233
259
  sm: "relative h-[30px] gap-[6px] px-[var(--space-3)] text-body-sm leading-[16px] before:absolute before:inset-x-0 before:-inset-y-[8px] before:content-[''] [&_svg]:size-[16px]",
234
260
  md: buttonSizeMd,
235
261
  lg: "h-[36px] gap-[var(--space-2)] px-[var(--space-4)] text-[15px] leading-[18px] [&_svg]:size-[18px]",
236
262
  xl: "h-[40px] gap-[var(--space-2)] px-5 text-[15px] leading-[18px] [&_svg]:size-[18px]",
237
- default: buttonSizeMd,
238
- /** @deprecated Use IconButton `size="lg"`. */
239
- icon: "size-[36px] p-0 [&_svg]:size-[18px]",
240
- /** @deprecated Use IconButton `size="md"`. */
241
- "icon-xs": "size-[32px] p-0 [&_svg]:size-[14px] [&_svg]:stroke-[1.75]"
263
+ default: buttonSizeMd
242
264
  };
243
265
  var buttonCva = cva(
244
266
  [
@@ -252,70 +274,62 @@ var buttonCva = cva(
252
274
  ].join(" "),
253
275
  {
254
276
  variants: {
255
- // Legacy single axis, deprecated in 0.19 for `appearance` × `tone` and removed in 0.20.
256
- // Frozen at 0.18; button-appearance.test.tsx keeps each value equal to its new pair.
257
- variant: {
258
- /** @deprecated Use `appearance="filled" tone="primary"`. */
259
- primary: "border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-fg)] hover:bg-[var(--primary-hover)] hover:border-[var(--primary-hover)]",
260
- /** @deprecated Use `appearance="outline" tone="neutral"`. */
261
- outline: "border-[var(--border)] bg-transparent text-foreground hover:border-[var(--border-strong)] hover:bg-[var(--action-hover)]",
262
- /** @deprecated Use `appearance="ghost" tone="neutral"`. */
263
- ghost: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
264
- /** @deprecated Use `appearance="filled" tone="danger"`. */
265
- danger: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
266
- /** @deprecated Use `appearance="filled" tone="danger"`. */
267
- emergency: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
268
- /** @deprecated Use `appearance="outline" tone="neutral"`. */
269
- subtle: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
270
- /** @deprecated Use `appearance="filled" tone="primary"`. */
271
- default: "border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-fg)] hover:bg-[var(--primary-hover)] hover:border-[var(--primary-hover)]",
272
- /** @deprecated Use `appearance="filled" tone="danger"`. */
273
- destructive: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
274
- /** @deprecated Use `appearance="outline" tone="neutral"`. */
275
- secondary: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
276
- /** @deprecated No replacement on Button; a link component is planned. */
277
- link: "border-transparent bg-transparent px-0 text-[var(--accent)] underline-offset-4 hover:underline"
278
- },
279
- ...actionAxisVariants,
277
+ // `link` is Button's own appearance (IconButton has no link); its box comes after the
278
+ // size in the compounds below.
279
+ appearance: { ...actionAxisVariants.appearance, link: "" },
280
+ tone: actionAxisVariants.tone,
280
281
  size: buttonSizes
281
282
  },
282
- compoundVariants: [...actionCompoundVariants],
283
+ compoundVariants: [
284
+ ...actionCompoundVariants,
285
+ // Compounds render after the size, so px-0 beats the size's px-*. The height and the xs/sm
286
+ // 44px band stay. Underline on hover only, no visited look; disabled keeps the transparent
287
+ // box with Button's disabled text color.
288
+ {
289
+ appearance: "link",
290
+ className: [
291
+ "border-transparent bg-transparent px-0 underline-offset-4 hover:underline",
292
+ "disabled:border-transparent disabled:bg-transparent disabled:no-underline",
293
+ "aria-disabled:border-transparent aria-disabled:bg-transparent aria-disabled:no-underline"
294
+ ].join(" ")
295
+ },
296
+ { appearance: "link", tone: "primary", className: actionPaint.linkPrimary },
297
+ { appearance: "link", tone: "danger", className: actionPaint.linkDanger }
298
+ ],
283
299
  defaultVariants: {
284
- variant: "primary",
285
300
  size: "md"
286
301
  }
287
302
  }
288
303
  );
304
+ function resolveButtonStyle(appearance, tone) {
305
+ if (appearance === "link") return { appearance, tone: tone ?? "primary" };
306
+ return resolveActionStyle(appearance, tone, "filled");
307
+ }
289
308
  function buttonVariants(options) {
290
- if (options?.appearance == null && options?.tone == null) return buttonCva(options);
291
- return buttonCva({
292
- ...options,
293
- ...resolveActionStyle(options.appearance, options.tone, "filled"),
294
- variant: null
295
- });
309
+ return cn(buttonCva({ ...options, ...resolveButtonStyle(options?.appearance, options?.tone) }));
296
310
  }
297
- var buttonSizeClassName = (size) => buttonSizes[size];
298
311
  var footerButtonHitAreaClassName = "relative before:absolute before:inset-x-0 before:-inset-y-[5px] before:content-['']";
312
+ function preventActivation(event) {
313
+ event.preventDefault();
314
+ event.stopPropagation();
315
+ }
299
316
  var Button = React.forwardRef(
300
317
  ({
301
318
  asChild = false,
302
319
  className,
303
320
  children,
304
321
  disabled,
305
- leadingIcon: LeadingIcon,
306
322
  loading,
307
- trailingIcon: TrailingIcon,
308
323
  type = "button",
309
- variant,
310
324
  appearance,
311
325
  tone,
312
326
  size,
313
327
  style,
328
+ menuIndicator,
314
329
  ...props
315
330
  }, ref) => {
316
331
  const Comp = asChild ? Slot.Root : "button";
317
332
  const isDisabled = disabled || loading;
318
- const IconBefore = loading ? Loader2 : LeadingIcon;
319
333
  const internalRef = React.useRef(null);
320
334
  const frozenWidthRef = React.useRef(null);
321
335
  if (loading && internalRef.current && frozenWidthRef.current === null) {
@@ -343,20 +357,14 @@ var Button = React.forwardRef(
343
357
  "aria-disabled": isDisabled ? true : void 0,
344
358
  disabled: !asChild ? isDisabled : void 0,
345
359
  type: !asChild ? type : void 0,
346
- className: cn(buttonVariants({ variant, appearance, tone, size, className })),
360
+ className: cn(buttonVariants({ appearance, tone, size, className })),
347
361
  style: frozenStyle ? { ...frozenStyle, ...style } : style,
348
362
  ...props,
363
+ ...asChild && isDisabled ? { tabIndex: -1, onClickCapture: preventActivation, onAuxClickCapture: preventActivation } : null,
349
364
  children: [
350
- IconBefore ? /* @__PURE__ */ jsx(
351
- IconBefore,
352
- {
353
- "aria-hidden": "true",
354
- "data-slot": loading ? "button-spinner" : "button-leading-icon",
355
- className: loading ? "animate-spin" : void 0
356
- }
357
- ) : null,
358
- children,
359
- !loading && TrailingIcon ? /* @__PURE__ */ jsx(TrailingIcon, { "aria-hidden": "true", "data-slot": "button-trailing-icon" }) : null
365
+ loading ? /* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", "data-slot": "button-spinner", className: "animate-spin" }) : null,
366
+ asChild ? /* @__PURE__ */ jsx(Slot.Slottable, { children }) : children,
367
+ menuIndicator ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true", "data-slot": "button-menu-indicator" }) : null
360
368
  ]
361
369
  }
362
370
  );
@@ -393,7 +401,8 @@ var CopyButton = React2.forwardRef(
393
401
  onCopied,
394
402
  size = "sm",
395
403
  value,
396
- variant = "secondary",
404
+ appearance = "outline",
405
+ tone,
397
406
  ...props
398
407
  }, ref) => {
399
408
  const [copied, setCopied] = React2.useState(false);
@@ -424,7 +433,7 @@ var CopyButton = React2.forwardRef(
424
433
  "aria-label": ariaLabel ?? getCopyButtonAriaLabel(label, value),
425
434
  "data-slot": "copy-button",
426
435
  size,
427
- variant,
436
+ ...{ appearance, tone },
428
437
  onClick: handleClick,
429
438
  ...props,
430
439
  children: [
@@ -450,25 +459,6 @@ CopyButton.displayName = "CopyButton";
450
459
  import * as React3 from "react";
451
460
  import { cva as cva2 } from "class-variance-authority";
452
461
  import { AlertCircle, CheckCircle2 } from "lucide-react";
453
-
454
- // src/components/ui/surface.ts
455
- var surfaceClassNames = {
456
- surface: "bg-[var(--bg-surface)]",
457
- canvas: "bg-[var(--bg-canvas)]",
458
- raised: "bg-[var(--bg-raised)]"
459
- };
460
- var fieldSurfaceClassNames = {
461
- surface: "bg-[var(--bg-surface)]",
462
- canvas: "bg-[var(--bg-canvas)]",
463
- raised: "bg-[var(--bg-raised)]"
464
- };
465
- var selectSurfaceClassNames = {
466
- surface: "bg-[var(--bg-surface)] [background-color:var(--bg-surface)]",
467
- canvas: "bg-[var(--bg-canvas)] [background-color:var(--bg-canvas)]",
468
- raised: "bg-[var(--bg-raised)] [background-color:var(--bg-raised)]"
469
- };
470
-
471
- // src/components/ui/input.tsx
472
462
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
473
463
  var inputVariants = cva2(
474
464
  [
@@ -667,6 +657,8 @@ var fileUploadZoneVariants = cva3(
667
657
  "hover:border-[var(--border-strong)] hover:bg-[var(--action-hover)]",
668
658
  "focus-within:border-[var(--focus-ring)] focus-within:shadow-[0_0_0_1px_var(--focus-ring)]",
669
659
  "data-[has-file=true]:border-solid data-[has-file=true]:border-[var(--border-strong)] data-[has-file=true]:bg-[var(--bg-inset)]",
660
+ // the filled zone is an inset well for neutral markers inside it (insetMarkerContext, surface.ts)
661
+ "data-[has-file=true]:[--fill-on-bg:var(--fill-on-inset)]",
670
662
  "data-[dragging=true]:border-[var(--border-strong)] data-[dragging=true]:bg-[var(--action-active)]",
671
663
  "data-[error=true]:border-[var(--error)]",
672
664
  "data-[disabled=true]:cursor-not-allowed data-[disabled=true]:border-[var(--border-subtle)] data-[disabled=true]:bg-[var(--action-disabled-bg)]",
@@ -1420,7 +1412,7 @@ import { cva as cva5 } from "class-variance-authority";
1420
1412
  import {
1421
1413
  AlertCircle as AlertCircle3,
1422
1414
  CheckCircle2 as CheckCircle23,
1423
- ChevronDown,
1415
+ ChevronDown as ChevronDown2,
1424
1416
  ChevronUp
1425
1417
  } from "lucide-react";
1426
1418
  import { Select as SelectPrimitive } from "radix-ui";
@@ -1631,7 +1623,7 @@ var Select = React7.forwardRef(
1631
1623
  {
1632
1624
  "data-slot": "select-scroll-down",
1633
1625
  className: "flex items-center justify-center border-t border-[var(--border)] bg-[var(--bg-surface)] py-[var(--space-1)] text-text-tertiary",
1634
- children: /* @__PURE__ */ jsx7(ChevronDown, { "aria-hidden": "true", className: "size-[16px]" })
1626
+ children: /* @__PURE__ */ jsx7(ChevronDown2, { "aria-hidden": "true", className: "size-[16px]" })
1635
1627
  }
1636
1628
  )
1637
1629
  ]
@@ -1674,7 +1666,7 @@ var Select = React7.forwardRef(
1674
1666
  "data-slot": "select-icon",
1675
1667
  className: "ml-[var(--space-2)] inline-flex size-[14px] shrink-0 items-center justify-center text-text-tertiary group-disabled:text-text-disabled",
1676
1668
  children: /* @__PURE__ */ jsx7(
1677
- ChevronDown,
1669
+ ChevronDown2,
1678
1670
  {
1679
1671
  "aria-hidden": "true",
1680
1672
  className: "size-[14px]",
@@ -1925,9 +1917,26 @@ Label.displayName = "Label";
1925
1917
 
1926
1918
  // src/components/ui/switch.tsx
1927
1919
  import * as React9 from "react";
1920
+ import { cva as cva7 } from "class-variance-authority";
1928
1921
  import { Loader2 as Loader22 } from "lucide-react";
1929
1922
  import { Switch as SwitchPrimitive } from "radix-ui";
1930
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1923
+ import { Fragment, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1924
+ var switchFieldVariants = cva7("", {
1925
+ variants: {
1926
+ labelPlacement: {
1927
+ end: "flex flex-col gap-[var(--space-1)]",
1928
+ start: "flex items-start gap-[var(--space-3)]"
1929
+ },
1930
+ fullWidth: {
1931
+ true: "w-full",
1932
+ false: "w-fit"
1933
+ }
1934
+ },
1935
+ defaultVariants: {
1936
+ labelPlacement: "end",
1937
+ fullWidth: false
1938
+ }
1939
+ });
1931
1940
  var Switch = React9.forwardRef(
1932
1941
  ({
1933
1942
  className,
@@ -1935,6 +1944,8 @@ var Switch = React9.forwardRef(
1935
1944
  description,
1936
1945
  required,
1937
1946
  loading,
1947
+ labelPlacement = "end",
1948
+ fullWidth = false,
1938
1949
  disabled,
1939
1950
  id,
1940
1951
  ...props
@@ -1944,95 +1955,108 @@ var Switch = React9.forwardRef(
1944
1955
  const labelId = id ? `${id}-label` : `${generatedId}-label`;
1945
1956
  const descriptionId = description ? id ? `${id}-description` : `${generatedId}-description` : void 0;
1946
1957
  const isDisabled = disabled || loading;
1947
- return /* @__PURE__ */ jsxs10(
1948
- "div",
1958
+ const isStart = labelPlacement === "start";
1959
+ const track = /* @__PURE__ */ jsxs10(
1960
+ SwitchPrimitive.Root,
1949
1961
  {
1950
- "data-slot": "switch-field",
1951
- "data-disabled": isDisabled ? "" : void 0,
1952
- className: "flex flex-col gap-[var(--space-1)] w-fit",
1962
+ ref,
1963
+ id: switchId,
1964
+ "data-slot": "switch",
1965
+ disabled: isDisabled,
1966
+ "aria-required": required || void 0,
1967
+ "aria-busy": loading || void 0,
1968
+ "aria-describedby": descriptionId,
1969
+ className: cn(
1970
+ "group relative inline-flex h-[24px] w-[44px] cursor-pointer items-center rounded-full transition-colors",
1971
+ "bg-[var(--border)] data-[state=checked]:bg-[var(--primary)]",
1972
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)]",
1973
+ "disabled:cursor-not-allowed disabled:opacity-50",
1974
+ isStart && "shrink-0",
1975
+ className
1976
+ ),
1977
+ ...props,
1953
1978
  children: [
1954
- /* @__PURE__ */ jsxs10("div", { className: "inline-flex items-center gap-[var(--space-3)]", children: [
1955
- /* @__PURE__ */ jsxs10(
1956
- SwitchPrimitive.Root,
1957
- {
1958
- ref,
1959
- id: switchId,
1960
- "data-slot": "switch",
1961
- disabled: isDisabled,
1962
- "aria-required": required || void 0,
1963
- "aria-busy": loading || void 0,
1964
- "aria-describedby": descriptionId,
1965
- className: cn(
1966
- "group relative inline-flex h-[24px] w-[44px] cursor-pointer items-center rounded-full transition-colors",
1967
- "bg-[var(--border)] data-[state=checked]:bg-[var(--primary)]",
1968
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)]",
1969
- "disabled:cursor-not-allowed disabled:opacity-50",
1970
- className
1971
- ),
1972
- ...props,
1973
- children: [
1974
- /* @__PURE__ */ jsx10(
1975
- SwitchPrimitive.Thumb,
1976
- {
1977
- "data-slot": "switch-thumb",
1978
- className: cn(
1979
- "pointer-events-none block h-[20px] w-[20px] rounded-full bg-[var(--bg-surface)] shadow",
1980
- "transition-transform translate-x-[2px] data-[state=checked]:translate-x-[22px]"
1981
- )
1982
- }
1983
- ),
1984
- loading ? /* @__PURE__ */ jsx10(
1985
- "span",
1986
- {
1987
- "aria-hidden": "true",
1988
- "data-slot": "switch-loading",
1989
- className: "absolute inset-0 flex items-center justify-center",
1990
- children: /* @__PURE__ */ jsx10(Loader22, { className: "size-[14px] animate-spin text-text-secondary" })
1991
- }
1992
- ) : null
1993
- ]
1994
- }
1995
- ),
1996
- /* @__PURE__ */ jsxs10(
1997
- "label",
1998
- {
1999
- htmlFor: switchId,
2000
- id: labelId,
2001
- "data-slot": "switch-label",
2002
- className: cn(
2003
- "cursor-pointer select-none text-sm font-medium text-foreground",
2004
- isDisabled && "cursor-not-allowed text-text-disabled"
2005
- ),
2006
- children: [
2007
- label,
2008
- required ? /* @__PURE__ */ jsx10(
2009
- "span",
2010
- {
2011
- "aria-hidden": "true",
2012
- "data-slot": "switch-required-marker",
2013
- className: "ml-[var(--space-1)] font-bold text-[var(--semantic-error,var(--error))]",
2014
- children: "*"
2015
- }
2016
- ) : null
2017
- ]
2018
- }
2019
- )
2020
- ] }),
2021
- description ? /* @__PURE__ */ jsx10(
2022
- "p",
1979
+ /* @__PURE__ */ jsx10(
1980
+ SwitchPrimitive.Thumb,
2023
1981
  {
2024
- id: descriptionId,
2025
- "data-slot": "switch-description",
1982
+ "data-slot": "switch-thumb",
2026
1983
  className: cn(
2027
- "ml-[var(--space-3)] text-xs font-normal leading-normal text-text-tertiary",
2028
- isDisabled && "text-text-disabled"
2029
- ),
2030
- children: description
1984
+ "pointer-events-none block h-[20px] w-[20px] rounded-full bg-[var(--bg-surface)] shadow",
1985
+ "transition-transform translate-x-[2px] data-[state=checked]:translate-x-[22px]"
1986
+ )
1987
+ }
1988
+ ),
1989
+ loading ? /* @__PURE__ */ jsx10(
1990
+ "span",
1991
+ {
1992
+ "aria-hidden": "true",
1993
+ "data-slot": "switch-loading",
1994
+ className: "absolute inset-0 flex items-center justify-center",
1995
+ children: /* @__PURE__ */ jsx10(Loader22, { className: "size-[14px] animate-spin text-text-secondary" })
1996
+ }
1997
+ ) : null
1998
+ ]
1999
+ }
2000
+ );
2001
+ const labelNode = /* @__PURE__ */ jsxs10(
2002
+ "label",
2003
+ {
2004
+ htmlFor: switchId,
2005
+ id: labelId,
2006
+ "data-slot": "switch-label",
2007
+ className: cn(
2008
+ "cursor-pointer select-none break-keep text-sm font-medium text-foreground [overflow-wrap:anywhere]",
2009
+ isStart && "leading-6",
2010
+ isDisabled && "cursor-not-allowed text-text-disabled"
2011
+ ),
2012
+ children: [
2013
+ label,
2014
+ required ? /* @__PURE__ */ jsx10(
2015
+ "span",
2016
+ {
2017
+ "aria-hidden": "true",
2018
+ "data-slot": "switch-required-marker",
2019
+ className: "ml-[var(--space-1)] font-bold text-[var(--semantic-error,var(--error))]",
2020
+ children: "*"
2031
2021
  }
2032
2022
  ) : null
2033
2023
  ]
2034
2024
  }
2035
2025
  );
2026
+ const descriptionNode = description ? /* @__PURE__ */ jsx10(
2027
+ "p",
2028
+ {
2029
+ id: descriptionId,
2030
+ "data-slot": "switch-description",
2031
+ className: cn(
2032
+ "break-keep text-xs font-normal leading-normal text-text-tertiary [overflow-wrap:anywhere]",
2033
+ !isStart && "ml-[var(--space-3)]",
2034
+ isDisabled && "text-text-disabled"
2035
+ ),
2036
+ children: description
2037
+ }
2038
+ ) : null;
2039
+ return /* @__PURE__ */ jsx10(
2040
+ "div",
2041
+ {
2042
+ "data-slot": "switch-field",
2043
+ "data-disabled": isDisabled ? "" : void 0,
2044
+ className: switchFieldVariants({ labelPlacement, fullWidth }),
2045
+ children: isStart ? /* @__PURE__ */ jsxs10(Fragment, { children: [
2046
+ /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 grow flex-col gap-[var(--space-1)]", children: [
2047
+ labelNode,
2048
+ descriptionNode
2049
+ ] }),
2050
+ track
2051
+ ] }) : /* @__PURE__ */ jsxs10(Fragment, { children: [
2052
+ /* @__PURE__ */ jsxs10("div", { className: "inline-flex items-center gap-[var(--space-3)]", children: [
2053
+ track,
2054
+ labelNode
2055
+ ] }),
2056
+ descriptionNode
2057
+ ] })
2058
+ }
2059
+ );
2036
2060
  }
2037
2061
  );
2038
2062
  Switch.displayName = "Switch";
@@ -2136,7 +2160,7 @@ function TooltipContent({
2136
2160
  }
2137
2161
 
2138
2162
  // src/components/ui/permission-guard.tsx
2139
- import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2163
+ import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2140
2164
  var defaultDisabledReason = "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4";
2141
2165
  var PermissionContext = React11.createContext(
2142
2166
  void 0
@@ -2183,7 +2207,7 @@ function PermissionGuard({
2183
2207
  const state = React11.useContext(PermissionContext);
2184
2208
  const allowed = evaluatePermission(permission, permissions ?? state, scope);
2185
2209
  if (allowed) {
2186
- return /* @__PURE__ */ jsx12(Fragment2, { children });
2210
+ return /* @__PURE__ */ jsx12(Fragment3, { children });
2187
2211
  }
2188
2212
  if (fallback === "hide" || fallback == null) {
2189
2213
  return null;
@@ -2191,7 +2215,7 @@ function PermissionGuard({
2191
2215
  if (fallback === "disabled") {
2192
2216
  return renderDisabledFallback(children, disabledReason);
2193
2217
  }
2194
- return /* @__PURE__ */ jsx12(Fragment2, { children: fallback });
2218
+ return /* @__PURE__ */ jsx12(Fragment3, { children: fallback });
2195
2219
  }
2196
2220
  function getPermissionCandidates(permission, scope) {
2197
2221
  const candidates = /* @__PURE__ */ new Set([permission]);
@@ -2244,9 +2268,9 @@ function isPermissionState(value) {
2244
2268
 
2245
2269
  // src/components/ui/card.tsx
2246
2270
  import * as React12 from "react";
2247
- import { cva as cva7 } from "class-variance-authority";
2271
+ import { cva as cva8 } from "class-variance-authority";
2248
2272
  import { jsx as jsx13 } from "react/jsx-runtime";
2249
- var cardBaseVariants = cva7(
2273
+ var cardBaseVariants = cva8(
2250
2274
  [
2251
2275
  "rounded-[var(--radius-lg)] border border-[var(--border)]",
2252
2276
  "px-[var(--space-6)] py-[var(--space-4)] text-foreground"
@@ -2631,7 +2655,7 @@ DataLayout.displayName = "DataLayout";
2631
2655
  // src/components/ui/wizard-layout.tsx
2632
2656
  import * as React16 from "react";
2633
2657
  import { Check as Check2 } from "lucide-react";
2634
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2658
+ import { Fragment as Fragment6, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2635
2659
  var circleBaseClassName = [
2636
2660
  "flex items-center justify-center rounded-[var(--radius-full)] border text-[12px] font-semibold leading-none",
2637
2661
  "transition-[background-color,border-color,color] motion-reduce:transition-none"
@@ -2922,7 +2946,7 @@ var WizardLayout = React16.forwardRef(
2922
2946
  ) : null
2923
2947
  ]
2924
2948
  }
2925
- ) : /* @__PURE__ */ jsxs16(Fragment5, { children: [
2949
+ ) : /* @__PURE__ */ jsxs16(Fragment6, { children: [
2926
2950
  /* @__PURE__ */ jsx17(
2927
2951
  "span",
2928
2952
  {
@@ -2989,10 +3013,10 @@ import * as React18 from "react";
2989
3013
  // src/components/ui/tabs.tsx
2990
3014
  import * as React17 from "react";
2991
3015
  import { Tabs as TabsPrimitive } from "radix-ui";
2992
- import { cva as cva8 } from "class-variance-authority";
3016
+ import { cva as cva9 } from "class-variance-authority";
2993
3017
  import { Lock } from "lucide-react";
2994
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
2995
- var tabsRootVariants = cva8("w-full", {
3018
+ import { Fragment as Fragment7, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3019
+ var tabsRootVariants = cva9("w-full", {
2996
3020
  variants: {
2997
3021
  orientation: {
2998
3022
  horizontal: "",
@@ -3003,13 +3027,14 @@ var tabsRootVariants = cva8("w-full", {
3003
3027
  orientation: "horizontal"
3004
3028
  }
3005
3029
  });
3006
- var tabsListVariants = cva8(
3007
- "flex",
3030
+ var tabsListVariants = cva9(
3031
+ // A list that overflows scrolls sideways without showing a scrollbar.
3032
+ "flex [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden",
3008
3033
  {
3009
3034
  variants: {
3010
3035
  variant: {
3011
3036
  line: "",
3012
- contained: "rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--bg-inset)] p-[var(--space-1)]"
3037
+ contained: `rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--bg-inset)] p-[var(--space-1)] ${insetMarkerContext}`
3013
3038
  },
3014
3039
  orientation: {
3015
3040
  horizontal: "",
@@ -3044,7 +3069,7 @@ var tabsListVariants = cva8(
3044
3069
  }
3045
3070
  }
3046
3071
  );
3047
- var tabsTriggerVariants = cva8(
3072
+ var tabsTriggerVariants = cva9(
3048
3073
  [
3049
3074
  "relative inline-flex shrink-0 cursor-pointer items-center gap-[var(--space-2)]",
3050
3075
  "px-0 py-[var(--space-2)] text-body-sm font-medium",
@@ -3098,7 +3123,7 @@ var tabsTriggerVariants = cva8(
3098
3123
  }
3099
3124
  }
3100
3125
  );
3101
- var tabsIndicatorVariants = cva8(
3126
+ var tabsIndicatorVariants = cva9(
3102
3127
  [
3103
3128
  "pointer-events-none absolute invisible bg-[var(--text-primary)]",
3104
3129
  // transition-property stays none (duration alone would animate every property, visibility included)
@@ -3127,18 +3152,11 @@ var tabsLabelReserveClassName = [
3127
3152
  "before:invisible before:h-0 before:overflow-hidden before:font-medium before:content-[attr(data-label)]",
3128
3153
  "after:invisible after:h-0 after:overflow-hidden after:font-bold after:content-[attr(data-label)]"
3129
3154
  ].join(" ");
3130
- var tabsBadgeVariants = cva8(
3155
+ var tabsBadgeVariants = cva9(
3131
3156
  [
3132
- "inline-flex h-[18px] min-w-[18px] items-center justify-center",
3133
- "rounded-[var(--radius-full)] border border-[var(--border-subtle)]",
3134
- "bg-[var(--bg-inset)] px-[var(--space-1)]",
3135
- "font-[family-name:var(--font-display)] text-xs font-semibold leading-none tabular-nums",
3136
- // R14 — Badge는 metadata, 추가 marker(filled wash)가 아니다. marker 종류는
3137
- // trigger underline 하나(active-state doctrine). single-hue-family: active 시 인접
3138
- // visible token(underline + badge text + badge border)을 같은 hue family로 — text는
3139
- // inherit, border는 active만 중립 --border-strong로 lift(accent rationing — selection은 brand 미사용). filled wash는 여전히 금지.
3140
- "text-inherit",
3141
- "group-data-[state=active]:border-[var(--border-strong)]"
3157
+ "inline-flex h-[var(--space-4)] min-w-[var(--space-4)] items-center justify-center",
3158
+ "rounded-[var(--radius-full)] px-[var(--space-1)] bg-[var(--action-selected)]",
3159
+ "font-[family-name:var(--font-display)] text-xs font-medium tabular-nums text-inherit"
3142
3160
  ].join(" ")
3143
3161
  );
3144
3162
  function useTabsIndicator(enabled, activeKey, tabsKey, listRef, indicatorRef) {
@@ -3198,7 +3216,15 @@ function useTabsIndicator(enabled, activeKey, tabsKey, listRef, indicatorRef) {
3198
3216
  }, [enabled, tabsKey, place, listRef]);
3199
3217
  }
3200
3218
  function formatTabBadge(value) {
3201
- return value > 99 ? "99+" : String(value);
3219
+ return value > 999 ? "999+" : String(value);
3220
+ }
3221
+ function isShownTabBadge(value) {
3222
+ if (value === void 0) return false;
3223
+ if (Number.isFinite(value) && value >= 0) return true;
3224
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3225
+ console.warn(`Tabs: badge must be a number 0 or greater (got ${value}). The badge is not shown.`);
3226
+ }
3227
+ return false;
3202
3228
  }
3203
3229
  function getTabId(baseId, key) {
3204
3230
  return baseId ? `${baseId}-tab-${key}` : `tab-${key}`;
@@ -3256,7 +3282,10 @@ var Tabs = React17.forwardRef(
3256
3282
  className: cn("group", tabsTriggerVariants({ variant, orientation }), triggerClassName),
3257
3283
  children: [
3258
3284
  isLine ? /* @__PURE__ */ jsx18("span", { "data-label": tab.label, className: tabsLabelReserveClassName, children: tab.label }) : /* @__PURE__ */ jsx18("span", { children: tab.label }),
3259
- tab.badge !== void 0 && tab.badge > 0 ? /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", "data-slot": "tabs-badge", className: tabsBadgeVariants(), children: formatTabBadge(tab.badge) }) : null,
3285
+ isShownTabBadge(tab.badge) ? /* @__PURE__ */ jsxs17(Fragment7, { children: [
3286
+ /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", "data-slot": "tabs-badge", className: tabsBadgeVariants(), children: formatTabBadge(tab.badge) }),
3287
+ /* @__PURE__ */ jsx18("span", { className: "sr-only", children: ` ${tab.badge}` })
3288
+ ] }) : null,
3260
3289
  tab.disabled ? /* @__PURE__ */ jsx18(
3261
3290
  Lock,
3262
3291
  {
@@ -3312,7 +3341,7 @@ var TabsContent = React17.forwardRef(({ className, tabKey, baseId, ...props }, r
3312
3341
  TabsContent.displayName = TabsPrimitive.Content.displayName;
3313
3342
 
3314
3343
  // src/components/ui/detail-layout.tsx
3315
- import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
3344
+ import { Fragment as Fragment8, jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
3316
3345
  function DetailLayoutBody({
3317
3346
  children,
3318
3347
  aside,
@@ -3365,7 +3394,7 @@ function appendFooterToActiveTabsContent(children, activeTab, footer) {
3365
3394
  return React18.cloneElement(
3366
3395
  child,
3367
3396
  void 0,
3368
- /* @__PURE__ */ jsxs18(Fragment6, { children: [
3397
+ /* @__PURE__ */ jsxs18(Fragment8, { children: [
3369
3398
  child.props.children,
3370
3399
  /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-footer", className: "min-w-0", children: footer })
3371
3400
  ] })
@@ -3447,7 +3476,7 @@ var DetailLayout = React18.forwardRef(
3447
3476
  baseId,
3448
3477
  forceMount: true,
3449
3478
  hidden: tab.key !== activeTab,
3450
- children: tab.key === activeTab ? /* @__PURE__ */ jsxs18(Fragment6, { children: [
3479
+ children: tab.key === activeTab ? /* @__PURE__ */ jsxs18(Fragment8, { children: [
3451
3480
  body,
3452
3481
  footer ? /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-footer", className: "min-w-0", children: footer }) : null
3453
3482
  ] }) : null
@@ -3455,7 +3484,7 @@ var DetailLayout = React18.forwardRef(
3455
3484
  tab.key
3456
3485
  ))
3457
3486
  }
3458
- ) : /* @__PURE__ */ jsxs18(Fragment6, { children: [
3487
+ ) : /* @__PURE__ */ jsxs18(Fragment8, { children: [
3459
3488
  body,
3460
3489
  footer ? /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-footer", className: "min-w-0", children: footer }) : null
3461
3490
  ] })
@@ -3468,7 +3497,7 @@ DetailLayout.displayName = "DetailLayout";
3468
3497
 
3469
3498
  // src/components/ui/form-layout.tsx
3470
3499
  import * as React19 from "react";
3471
- import { ChevronDown as ChevronDown2 } from "lucide-react";
3500
+ import { ChevronDown as ChevronDown3 } from "lucide-react";
3472
3501
  import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
3473
3502
  function FormLayoutSectionBlock({
3474
3503
  section,
@@ -3537,7 +3566,7 @@ function FormLayoutSectionBlock({
3537
3566
  children: /* @__PURE__ */ jsxs19("div", { className: "flex min-w-0 items-start gap-[var(--space-2)]", children: [
3538
3567
  /* @__PURE__ */ jsx20("div", { className: "min-w-0 flex-1", children: sectionHeader }),
3539
3568
  /* @__PURE__ */ jsx20(
3540
- ChevronDown2,
3569
+ ChevronDown3,
3541
3570
  {
3542
3571
  "aria-hidden": "true",
3543
3572
  className: cn(
@@ -3884,9 +3913,11 @@ import { Dialog as DialogPrimitive } from "radix-ui";
3884
3913
 
3885
3914
  // src/components/ui/icon-button.tsx
3886
3915
  import * as React23 from "react";
3887
- import { cva as cva9 } from "class-variance-authority";
3916
+ import { cva as cva10 } from "class-variance-authority";
3917
+ import { ChevronDown as ChevronDown4, Loader2 as Loader23 } from "lucide-react";
3888
3918
  import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
3889
- var iconButtonCva = cva9(
3919
+ var pressedNeutralClassName = "border-[var(--border-strong)] bg-[var(--action-selected)] text-foreground";
3920
+ var iconButtonCva = cva10(
3890
3921
  [
3891
3922
  "olun-icon-button relative inline-flex cursor-pointer shrink-0 items-center justify-center before:absolute before:content-['']",
3892
3923
  "rounded-[var(--radius-md)] border font-medium",
@@ -3897,28 +3928,17 @@ var iconButtonCva = cva9(
3897
3928
  ].join(" "),
3898
3929
  {
3899
3930
  variants: {
3900
- // Legacy single axis, deprecated in 0.19 for `appearance` × `tone` and removed in 0.20.
3901
- // Frozen at 0.18; button-appearance.test.tsx keeps ghost and subtle equal to their new
3902
- // pair. `outline` and `danger` differ from the pair they migrate to (outline + neutral =
3903
- // Button secondary, filled + danger = solid red).
3904
- variant: {
3905
- /** @deprecated Use `appearance="ghost" tone="neutral"` (the default). */
3906
- ghost: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
3907
- /** @deprecated Use `appearance="outline" tone="neutral"`. */
3908
- 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",
3909
- /** @deprecated Use `appearance="filled" tone="neutral"`. */
3910
- subtle: "border-transparent bg-[var(--bg-inset)] text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
3911
- /** @deprecated Use `appearance="filled" tone="danger"` (solid red, like Button). */
3912
- danger: "border-transparent bg-[var(--error-bg)] text-[var(--error)] hover:bg-[var(--action-hover)]"
3913
- },
3914
3931
  ...actionAxisVariants,
3915
- // Hit area = 44px on every size. The ::before is absolutely positioned, so its
3916
- // inset is measured from the padding box — inside the 1px border every variant
3917
- // carries (transparent or not). Inset = (44 - (size - 2 × 1px border)) / 2.
3932
+ // Button's five heights, so one size is one height with or without text. Icon only is
3933
+ // square with a 44px hit area: the ::before is absolutely positioned, so its inset is
3934
+ // measured from the padding box — inside the 1px border every pair carries (transparent
3935
+ // or not). Inset = (44 - (size - 2 × 1px border)) / 2. With text the box is Button's.
3918
3936
  size: {
3919
- sm: "size-[28px] before:-inset-[9px]",
3937
+ xs: "size-[28px] before:-inset-[9px]",
3938
+ sm: "size-[30px] before:-inset-[8px]",
3920
3939
  md: "size-[32px] before:-inset-[7px]",
3921
- lg: "size-[40px] before:-inset-[3px]"
3940
+ lg: "size-[36px] before:-inset-[5px]",
3941
+ xl: "size-[40px] before:-inset-[3px]"
3922
3942
  },
3923
3943
  pressed: {
3924
3944
  true: "",
@@ -3927,39 +3947,17 @@ var iconButtonCva = cva9(
3927
3947
  },
3928
3948
  compoundVariants: [
3929
3949
  ...actionCompoundVariants,
3930
- {
3931
- pressed: true,
3932
- variant: ["ghost", "outline", "subtle"],
3933
- className: "border-[var(--border-strong)] bg-[var(--action-selected)] text-foreground"
3934
- },
3935
- {
3936
- pressed: true,
3937
- variant: "danger",
3938
- className: "border-[var(--error)] bg-[var(--error-bg)] text-[var(--error)]"
3939
- },
3940
- {
3941
- pressed: true,
3942
- tone: "neutral",
3943
- className: "border-[var(--border-strong)] bg-[var(--action-selected)] text-foreground"
3944
- }
3950
+ { pressed: true, tone: "neutral", className: pressedNeutralClassName }
3945
3951
  ],
3946
3952
  // ghost is the intended default, not a fallback: ghost is reserved for icon-only
3947
3953
  // actions repeated in rows or chrome (toolbars, headers, table rows), and
3948
3954
  // IconButton is its canonical entry point (#58). Text actions use Button.
3949
3955
  defaultVariants: {
3950
- variant: "ghost",
3951
3956
  size: "md",
3952
3957
  pressed: false
3953
3958
  }
3954
3959
  }
3955
3960
  );
3956
- var axisSizeClassName = {
3957
- xs: "size-[28px] before:-inset-[9px]",
3958
- sm: "size-[30px] before:-inset-[8px]",
3959
- md: "size-[32px] before:-inset-[7px]",
3960
- lg: "size-[36px] before:-inset-[5px]",
3961
- xl: "size-[40px] before:-inset-[3px]"
3962
- };
3963
3961
  var axisIcon = {
3964
3962
  xs: { size: 14, strokeWidth: 1.75 },
3965
3963
  sm: { size: 16, strokeWidth: 2 },
@@ -3968,19 +3966,12 @@ var axisIcon = {
3968
3966
  xl: { size: 18, strokeWidth: 2 }
3969
3967
  };
3970
3968
  function iconButtonVariants(options) {
3971
- if (options?.appearance == null && options?.tone == null) {
3972
- return iconButtonCva(options);
3973
- }
3974
- const { size, ...rest } = options;
3975
- const paint = iconButtonCva({
3976
- ...rest,
3977
- ...resolveActionStyle(options.appearance, options.tone, "ghost"),
3978
- variant: null,
3979
- size: null
3969
+ return iconButtonCva({
3970
+ ...options,
3971
+ ...resolveActionStyle(options?.appearance, options?.tone, "ghost")
3980
3972
  });
3981
- return size === null ? paint : `${paint} ${axisSizeClassName[size ?? "md"]}`;
3982
3973
  }
3983
- var iconButtonBadgeVariants = cva9(
3974
+ var iconButtonBadgeVariants = cva10(
3984
3975
  [
3985
3976
  "pointer-events-none absolute right-0 top-0 inline-flex",
3986
3977
  "olun-icon-button__badge",
@@ -4001,25 +3992,9 @@ var iconButtonBadgeVariants = cva9(
4001
3992
  }
4002
3993
  }
4003
3994
  );
4004
- var iconSize2 = {
4005
- sm: 14,
4006
- md: 16,
4007
- lg: 18
4008
- };
4009
- var textButtonSize = {
4010
- sm: "xs",
4011
- md: "md",
4012
- lg: "xl"
4013
- };
4014
- var iconStrokeWidth = {
4015
- sm: 2.25,
4016
- md: 2.25,
4017
- lg: 1.75
4018
- };
4019
3995
  var IconButton = React23.forwardRef(
4020
3996
  ({
4021
3997
  className,
4022
- variant = "ghost",
4023
3998
  appearance,
4024
3999
  tone,
4025
4000
  size = "md",
@@ -4032,28 +4007,37 @@ var IconButton = React23.forwardRef(
4032
4007
  "aria-label": ariaLabel,
4033
4008
  "aria-labelledby": ariaLabelledBy,
4034
4009
  iconPosition = "start",
4010
+ loading,
4011
+ menuIndicator,
4012
+ disabled,
4035
4013
  label,
4036
4014
  children,
4037
4015
  ...props
4038
4016
  }, ref) => {
4039
4017
  const resolvedSize = size ?? "md";
4040
- const usesAxes = appearance != null || tone != null;
4041
4018
  const isToggle = pressed !== void 0;
4042
4019
  const isPressed = pressed === true;
4043
4020
  const hoverTitle = title ?? (typeof ariaLabel === "string" ? ariaLabel : void 0);
4044
4021
  const text = label ?? children;
4045
4022
  const hasText = text !== void 0 && text !== null && text !== false;
4046
- const style = usesAxes ? resolveActionStyle(appearance, tone, "ghost") : void 0;
4047
- const axisSize = usesAxes ? resolvedSize : void 0;
4048
- const legacySize = resolvedSize;
4049
- const textBoxSize = axisSize ?? textButtonSize[legacySize];
4050
- const icon = /* @__PURE__ */ jsx22(
4023
+ const isDisabled = disabled || loading;
4024
+ const style = resolveActionStyle(appearance, tone, "ghost");
4025
+ const icon = loading ? /* @__PURE__ */ jsx22(
4026
+ Loader23,
4027
+ {
4028
+ "aria-hidden": "true",
4029
+ "data-slot": "icon-button-spinner",
4030
+ className: "animate-spin",
4031
+ size: axisIcon[resolvedSize].size,
4032
+ strokeWidth: axisIcon[resolvedSize].strokeWidth
4033
+ }
4034
+ ) : /* @__PURE__ */ jsx22(
4051
4035
  Icon,
4052
4036
  {
4053
4037
  "aria-hidden": "true",
4054
4038
  "data-slot": "icon-button-icon",
4055
- size: axisSize ? axisIcon[axisSize].size : iconSize2[legacySize],
4056
- strokeWidth: axisSize ? axisIcon[axisSize].strokeWidth : hasText ? void 0 : iconStrokeWidth[legacySize]
4039
+ size: axisIcon[resolvedSize].size,
4040
+ strokeWidth: axisIcon[resolvedSize].strokeWidth
4057
4041
  }
4058
4042
  );
4059
4043
  return /* @__PURE__ */ jsxs20(
@@ -4062,25 +4046,27 @@ var IconButton = React23.forwardRef(
4062
4046
  ref,
4063
4047
  ...props,
4064
4048
  "data-slot": "icon-button",
4065
- "data-variant": usesAxes ? void 0 : variant,
4066
- "data-appearance": style?.appearance,
4067
- "data-tone": style?.tone,
4049
+ "data-appearance": style.appearance,
4050
+ "data-tone": style.tone,
4068
4051
  "data-size": resolvedSize,
4069
4052
  "data-icon-position": hasText ? iconPosition : void 0,
4070
4053
  "data-pressed": isToggle ? String(isPressed) : void 0,
4054
+ "data-loading": loading ? "true" : void 0,
4055
+ "aria-busy": loading ? true : void 0,
4056
+ "aria-disabled": isDisabled ? true : void 0,
4057
+ disabled: isDisabled,
4071
4058
  "aria-label": ariaLabel,
4072
4059
  "aria-labelledby": ariaLabelledBy,
4073
4060
  "aria-pressed": isToggle ? isPressed : void 0,
4074
4061
  title: hoverTitle,
4075
4062
  className: cn(
4076
- iconButtonVariants({
4077
- variant,
4078
- appearance,
4079
- tone,
4080
- size: hasText ? null : size,
4081
- pressed: isPressed
4082
- }),
4083
- hasText && ["whitespace-nowrap", buttonSizeClassName(textBoxSize)],
4063
+ hasText ? [
4064
+ "olun-icon-button",
4065
+ buttonVariants({ ...style, size: resolvedSize }),
4066
+ isPressed && style.tone === "neutral" && pressedNeutralClassName,
4067
+ // The badge sits on the corner; Button xs/sm are already relative.
4068
+ badge !== void 0 && "relative"
4069
+ ] : iconButtonVariants({ appearance, tone, size: resolvedSize, pressed: isPressed }),
4084
4070
  className
4085
4071
  ),
4086
4072
  type: type ?? "button",
@@ -4088,6 +4074,15 @@ var IconButton = React23.forwardRef(
4088
4074
  hasText && iconPosition === "end" ? null : icon,
4089
4075
  hasText ? text : null,
4090
4076
  hasText && iconPosition === "end" ? icon : null,
4077
+ hasText && menuIndicator ? /* @__PURE__ */ jsx22(
4078
+ ChevronDown4,
4079
+ {
4080
+ "aria-hidden": "true",
4081
+ "data-slot": "icon-button-menu-indicator",
4082
+ size: axisIcon[resolvedSize].size,
4083
+ strokeWidth: axisIcon[resolvedSize].strokeWidth
4084
+ }
4085
+ ) : null,
4091
4086
  badge !== void 0 ? /* @__PURE__ */ jsx22(
4092
4087
  "span",
4093
4088
  {
@@ -4690,7 +4685,7 @@ function SheetDescription({
4690
4685
  }
4691
4686
 
4692
4687
  // src/components/ui/dialog.tsx
4693
- import { Fragment as Fragment7, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
4688
+ import { Fragment as Fragment9, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
4694
4689
  function dialogMobileSheetStyle(style) {
4695
4690
  return getDefaultSheetMotionStyle(style);
4696
4691
  }
@@ -4784,7 +4779,7 @@ function StructuredDialog({
4784
4779
  footerRow
4785
4780
  ]
4786
4781
  }
4787
- ) : /* @__PURE__ */ jsxs23(Fragment7, { children: [
4782
+ ) : /* @__PURE__ */ jsxs23(Fragment9, { children: [
4788
4783
  body,
4789
4784
  footerRow
4790
4785
  ] })
@@ -4985,7 +4980,7 @@ function FormModal({
4985
4980
 
4986
4981
  // src/components/ui/alert-dialog.tsx
4987
4982
  import { AlertDialog as AlertDialogPrimitive2 } from "radix-ui";
4988
- import { Fragment as Fragment8, jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
4983
+ import { Fragment as Fragment10, jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
4989
4984
  function AlertDialogFrame({
4990
4985
  open,
4991
4986
  onOpenChange,
@@ -5049,7 +5044,7 @@ function AlertDialog({
5049
5044
  disabled: confirmDisabled,
5050
5045
  onError
5051
5046
  });
5052
- const footer = confirmLabel != null ? /* @__PURE__ */ jsxs25(Fragment8, { children: [
5047
+ const footer = confirmLabel != null ? /* @__PURE__ */ jsxs25(Fragment10, { children: [
5053
5048
  /* @__PURE__ */ jsx28(AlertDialogPrimitive2.Cancel, { asChild: true, children: /* @__PURE__ */ jsx28(Button, { appearance: "outline", tone: "neutral", size: "lg", className: footerButtonHitAreaClassName, disabled: isBusy, children: cancelLabel }) }),
5054
5049
  /* @__PURE__ */ jsx28(
5055
5050
  Button,
@@ -5124,11 +5119,11 @@ import { SlidersHorizontal } from "lucide-react";
5124
5119
 
5125
5120
  // src/components/ui/chip.tsx
5126
5121
  import * as React27 from "react";
5127
- import { cva as cva10 } from "class-variance-authority";
5122
+ import { cva as cva11 } from "class-variance-authority";
5128
5123
  import { X as X2 } from "lucide-react";
5129
5124
  import { Slot as Slot2 } from "radix-ui";
5130
5125
  import { jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
5131
- var chipVariants = cva10(
5126
+ var chipVariants = cva11(
5132
5127
  [
5133
5128
  "inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap",
5134
5129
  "rounded-[var(--radius-full)] border leading-none",
@@ -5149,7 +5144,7 @@ var chipVariants = cva10(
5149
5144
  "status-filter": "cursor-default"
5150
5145
  },
5151
5146
  tone: {
5152
- neutral: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-text-secondary hover:bg-[var(--action-hover)]",
5147
+ neutral: `border-[var(--border-subtle)] bg-[var(--bg-surface)] text-text-secondary hover:bg-[var(--action-hover)] ${surfaceMarkerContext}`,
5153
5148
  accent: "border-[var(--border-accent)] bg-transparent text-[var(--accent)] hover:bg-[var(--accent-bg-strong)]",
5154
5149
  success: "border-transparent bg-[var(--success-bg)] text-[var(--success)] hover:bg-[var(--action-hover)]",
5155
5150
  warning: "border-transparent bg-[var(--warning-bg)] text-[var(--warning)] hover:bg-[var(--action-hover)]",
@@ -5181,7 +5176,7 @@ var chipVariants = cva10(
5181
5176
  {
5182
5177
  pressed: true,
5183
5178
  tone: "muted",
5184
- className: "border-[var(--border-strong)] bg-[var(--bg-inset)] text-text-secondary"
5179
+ className: `border-[var(--border-strong)] bg-[var(--bg-inset)] text-text-secondary ${insetMarkerContext}`
5185
5180
  }
5186
5181
  ],
5187
5182
  defaultVariants: {
@@ -5192,7 +5187,7 @@ var chipVariants = cva10(
5192
5187
  }
5193
5188
  }
5194
5189
  );
5195
- var chipCountVariants = cva10(
5190
+ var chipCountVariants = cva11(
5196
5191
  [
5197
5192
  "inline-flex min-w-[var(--space-4)] items-center justify-center",
5198
5193
  "rounded-[var(--radius-full)] px-[var(--space-1)]",
@@ -5201,12 +5196,13 @@ var chipCountVariants = cva10(
5201
5196
  {
5202
5197
  variants: {
5203
5198
  tone: {
5204
- neutral: "bg-[var(--bg-inset)] text-text-tertiary",
5199
+ // neutral·muted take --fill-on-bg when an inset background sets it (see surface.ts).
5200
+ neutral: "bg-[var(--fill-on-bg,var(--bg-inset))] text-text-tertiary",
5205
5201
  accent: "bg-[var(--accent-pop)] text-[var(--accent-on-fill)]",
5206
5202
  success: "bg-[var(--success)] text-[var(--success-contrast)]",
5207
5203
  warning: "bg-[var(--warning)] text-[var(--warning-contrast)]",
5208
5204
  danger: "bg-[var(--error)] text-[var(--error-contrast)]",
5209
- muted: "bg-[var(--bg-inset)] text-text-tertiary"
5205
+ muted: "bg-[var(--fill-on-bg,var(--bg-inset))] text-text-tertiary"
5210
5206
  },
5211
5207
  size: {
5212
5208
  sm: "h-[var(--space-4)] text-xs",
@@ -5377,7 +5373,7 @@ var PopoverArrow = React28.forwardRef(({ className, ...props }, ref) => /* @__PU
5377
5373
  PopoverArrow.displayName = PopoverPrimitive.Arrow.displayName;
5378
5374
 
5379
5375
  // src/components/ui/filter-toolbar.tsx
5380
- import { Fragment as Fragment9, jsx as jsx32, jsxs as jsxs28 } from "react/jsx-runtime";
5376
+ import { Fragment as Fragment11, jsx as jsx32, jsxs as jsxs28 } from "react/jsx-runtime";
5381
5377
  var collapsibleClassNames = {
5382
5378
  sm: {
5383
5379
  inline: "hidden @[640px]:flex",
@@ -5482,7 +5478,8 @@ var FilterToolbar = React29.forwardRef(
5482
5478
  "aria-label": collapseTriggerLabel,
5483
5479
  icon: SlidersHorizontal,
5484
5480
  size: "md",
5485
- variant: "outline",
5481
+ appearance: "outline",
5482
+ tone: "neutral",
5486
5483
  onClick: () => handleOverlayOpenChange(true)
5487
5484
  }
5488
5485
  ),
@@ -5588,7 +5585,7 @@ var FilterToolbar = React29.forwardRef(
5588
5585
  activeFilterCount,
5589
5586
  "\uAC1C \uC801\uC6A9"
5590
5587
  ] }),
5591
- onClearFilters ? /* @__PURE__ */ jsxs28(Fragment9, { children: [
5588
+ onClearFilters ? /* @__PURE__ */ jsxs28(Fragment11, { children: [
5592
5589
  /* @__PURE__ */ jsx32("span", { "aria-hidden": "true", children: " \xB7 " }),
5593
5590
  /* @__PURE__ */ jsx32(
5594
5591
  "button",
@@ -5637,17 +5634,17 @@ var FilterToolbar = React29.forwardRef(
5637
5634
  FilterToolbar.displayName = "FilterToolbar";
5638
5635
 
5639
5636
  // src/components/ui/data-table.tsx
5640
- import * as React32 from "react";
5641
- import { ChevronDown as ChevronDown3, ChevronUp as ChevronUp2, ChevronsUpDown } from "lucide-react";
5642
- import { cva as cva12 } from "class-variance-authority";
5637
+ import * as React33 from "react";
5638
+ import { ChevronDown as ChevronDown5, ChevronRight as ChevronRight3, ChevronUp as ChevronUp2, ChevronsUpDown } from "lucide-react";
5639
+ import { cva as cva13 } from "class-variance-authority";
5643
5640
 
5644
5641
  // src/components/ui/checkbox.tsx
5645
5642
  import * as React30 from "react";
5646
- import { cva as cva11 } from "class-variance-authority";
5643
+ import { cva as cva12 } from "class-variance-authority";
5647
5644
  import { Check as Check3, Minus } from "lucide-react";
5648
5645
  import { Checkbox as CheckboxPrimitive } from "radix-ui";
5649
5646
  import { jsx as jsx33, jsxs as jsxs29 } from "react/jsx-runtime";
5650
- var checkboxFieldVariants = cva11(
5647
+ var checkboxFieldVariants = cva12(
5651
5648
  "flex flex-col gap-[var(--space-1)]",
5652
5649
  {
5653
5650
  variants: {
@@ -5662,14 +5659,14 @@ var checkboxFieldVariants = cva11(
5662
5659
  }
5663
5660
  );
5664
5661
  var checkboxVariants = checkboxFieldVariants;
5665
- var checkboxRootVariants = cva11(
5662
+ var checkboxRootVariants = cva12(
5666
5663
  [
5667
5664
  "group shrink-0 cursor-pointer rounded-[var(--radius-xs)]",
5668
5665
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)]",
5669
5666
  "disabled:cursor-not-allowed"
5670
5667
  ].join(" ")
5671
5668
  );
5672
- var checkboxBoxVariants = cva11(
5669
+ var checkboxBoxVariants = cva12(
5673
5670
  [
5674
5671
  "flex shrink-0 items-center justify-center rounded-[var(--radius-xs)] border",
5675
5672
  "border-[var(--border-strong)] bg-[var(--bg-surface)] text-transparent",
@@ -5693,7 +5690,7 @@ var checkboxBoxVariants = cva11(
5693
5690
  }
5694
5691
  }
5695
5692
  );
5696
- var checkboxGroupItemVariants = cva11(
5693
+ var checkboxGroupItemVariants = cva12(
5697
5694
  [
5698
5695
  "group w-full cursor-pointer text-left transition-colors motion-reduce:transition-none",
5699
5696
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)]",
@@ -5735,7 +5732,7 @@ var checkboxGroupItemVariants = cva11(
5735
5732
  }
5736
5733
  }
5737
5734
  );
5738
- var checkboxGroupBoxVariants = cva11(
5735
+ var checkboxGroupBoxVariants = cva12(
5739
5736
  "mt-[2px]",
5740
5737
  {
5741
5738
  variants: {
@@ -6225,84 +6222,313 @@ function DropdownMenuSubContent({
6225
6222
  }
6226
6223
 
6227
6224
  // src/components/ui/list-card.tsx
6225
+ import * as React32 from "react";
6226
+ import { ChevronRight as ChevronRight2, MoreVertical } from "lucide-react";
6227
+
6228
+ // src/components/ui/action-menu.tsx
6228
6229
  import * as React31 from "react";
6229
- import { ChevronRight as ChevronRight2 } from "lucide-react";
6230
- import { Fragment as Fragment11, jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
6231
- function lineTokens(value) {
6232
- return React31.Children.toArray(value).filter((token) => token !== "");
6233
- }
6234
- function lineTitle(tokens) {
6235
- if (!tokens.every((token) => typeof token === "string" || typeof token === "number")) {
6236
- return void 0;
6237
- }
6238
- return tokens.join(" \xB7 ");
6239
- }
6240
- function MetaLine({ tokens, slot }) {
6241
- return /* @__PURE__ */ jsx35(
6242
- "span",
6243
- {
6244
- "data-slot": slot,
6245
- className: "block truncate whitespace-nowrap text-[12px] leading-[16px] text-text-secondary",
6246
- title: lineTitle(tokens),
6247
- children: tokens.map((token, index) => /* @__PURE__ */ jsxs31(React31.Fragment, { children: [
6248
- index > 0 ? " \xB7 " : null,
6249
- token
6250
- ] }, index))
6251
- }
6252
- );
6253
- }
6254
- function ListCard({
6230
+ import { Dialog as DialogPrimitive4, Slot as Slot3 } from "radix-ui";
6231
+ import { Fragment as Fragment13, jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
6232
+ var sheetRowClassName = cn(
6233
+ "group flex min-h-12 w-full cursor-pointer items-center gap-[var(--space-3)] px-[var(--space-4)] py-[var(--space-2)] text-left",
6234
+ "border-t border-[var(--border-subtle)] text-[13px] font-medium leading-normal text-text-primary",
6235
+ "transition-colors motion-reduce:transition-none hover:bg-[var(--action-hover)]",
6236
+ "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--focus-ring)]",
6237
+ "enabled:data-[destructive]:text-[var(--semantic-error-fg)]",
6238
+ "disabled:cursor-not-allowed disabled:bg-[var(--action-disabled-bg)] disabled:text-text-disabled"
6239
+ );
6240
+ var sheetRowDescriptionClassName = "block text-[12px] font-normal text-text-secondary group-disabled:text-text-disabled";
6241
+ var sheetGroupLabelClassName = "px-[var(--space-4)] pt-[var(--space-3)] pb-[var(--space-2)] text-[12px] font-semibold leading-normal text-text-tertiary";
6242
+ var sheetGroupSeparatorClassName = "h-[var(--space-2)] bg-[var(--bg-inset)]";
6243
+ function ActionMenuSheet({
6244
+ open,
6245
+ onOpenChange,
6255
6246
  title,
6256
- meta,
6257
- status,
6258
- caption,
6259
- leading,
6260
- value,
6261
- trailing = "chevron",
6262
- href,
6263
- linkComponent,
6264
- linkProps,
6265
- onClick,
6266
- slot = "list-card",
6267
- className
6247
+ description,
6248
+ closeLabel,
6249
+ groups,
6250
+ onOpenAutoFocus,
6251
+ onCloseAutoFocus
6268
6252
  }) {
6269
- const meta1 = lineTokens(meta?.[0]);
6270
- const meta2 = lineTokens(meta?.[1]);
6271
- const hasValue = value != null;
6272
- const chevron = /* @__PURE__ */ jsx35(
6273
- ChevronRight2,
6274
- {
6275
- "data-slot": `${slot}-suffix`,
6276
- "aria-hidden": true,
6277
- className: "size-[var(--space-4)] shrink-0 text-text-tertiary"
6253
+ const pendingRef = React31.useRef(null);
6254
+ const surfaceRef = React31.useRef(null);
6255
+ const labelId = React31.useId();
6256
+ const handleOpenChange = (nextOpen) => {
6257
+ pendingRef.current = null;
6258
+ onOpenChange(nextOpen);
6259
+ };
6260
+ const swipe = useSwipeDismiss({
6261
+ enabled: OVERLAY_POLICY.menu.swipe,
6262
+ onDismiss: () => handleOpenChange(false),
6263
+ surfaceRef,
6264
+ always: true
6265
+ });
6266
+ const handleSelect = (item) => {
6267
+ onOpenChange(false);
6268
+ pendingRef.current = item;
6269
+ };
6270
+ const handleOpenAutoFocus = (event) => {
6271
+ onOpenAutoFocus?.(event);
6272
+ const firstRow = surfaceRef.current?.querySelector('[data-slot="action-menu-item"]:enabled');
6273
+ if (!firstRow) return;
6274
+ event.preventDefault();
6275
+ firstRow.focus();
6276
+ };
6277
+ const handleCloseAutoFocus = (event) => {
6278
+ onCloseAutoFocus(event);
6279
+ const item = pendingRef.current;
6280
+ pendingRef.current = null;
6281
+ item?.onSelect();
6282
+ };
6283
+ return /* @__PURE__ */ jsx35(DialogPrimitive4.Root, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs31(DialogPrimitive4.Portal, { children: [
6284
+ /* @__PURE__ */ jsx35(OverlayScrimLayer, { kind: "menu" }),
6285
+ /* @__PURE__ */ jsxs31(
6286
+ DialogPrimitive4.Content,
6287
+ {
6288
+ ref: surfaceRef,
6289
+ "data-slot": "action-menu-sheet",
6290
+ className: overlayBoxClassName("menu"),
6291
+ onOpenAutoFocus: handleOpenAutoFocus,
6292
+ onCloseAutoFocus: handleCloseAutoFocus,
6293
+ ...description ? {} : { "aria-describedby": void 0 },
6294
+ children: [
6295
+ /* @__PURE__ */ jsx35(OverlayGrabber, { always: true, ...swipe.handleProps }),
6296
+ /* @__PURE__ */ jsx35(
6297
+ OverlayHeader,
6298
+ {
6299
+ kind: "menu",
6300
+ title,
6301
+ description,
6302
+ closeLabel,
6303
+ dragHandleProps: swipe.handleProps
6304
+ }
6305
+ ),
6306
+ /* @__PURE__ */ jsx35(OverlayBody, { kind: "menu", children: groups.map((group, index) => /* @__PURE__ */ jsxs31(React31.Fragment, { children: [
6307
+ index > 0 ? /* @__PURE__ */ jsx35("div", { role: "separator", className: sheetGroupSeparatorClassName }) : null,
6308
+ /* @__PURE__ */ jsxs31("div", { role: "group", "aria-labelledby": group.label ? `${labelId}-${index}` : void 0, children: [
6309
+ group.label ? /* @__PURE__ */ jsx35("div", { id: `${labelId}-${index}`, className: sheetGroupLabelClassName, children: group.label }) : null,
6310
+ group.items.map((item) => {
6311
+ const Icon = item.icon;
6312
+ return /* @__PURE__ */ jsxs31(
6313
+ "button",
6314
+ {
6315
+ type: "button",
6316
+ "data-slot": "action-menu-item",
6317
+ "data-destructive": item.destructive ? "" : void 0,
6318
+ className: sheetRowClassName,
6319
+ disabled: item.disabled,
6320
+ onClick: () => handleSelect(item),
6321
+ children: [
6322
+ Icon ? /* @__PURE__ */ jsx35(Icon, { "aria-hidden": true, size: 17, strokeWidth: 1.75, className: "shrink-0" }) : null,
6323
+ /* @__PURE__ */ jsxs31("span", { className: "min-w-0 flex-1 break-keep", children: [
6324
+ item.label,
6325
+ item.description ? /* @__PURE__ */ jsx35("span", { className: sheetRowDescriptionClassName, children: item.description }) : null
6326
+ ] })
6327
+ ]
6328
+ },
6329
+ item.id
6330
+ );
6331
+ })
6332
+ ] })
6333
+ ] }, group.id)) })
6334
+ ]
6335
+ }
6336
+ )
6337
+ ] }) });
6338
+ }
6339
+ var readPresentation = () => window.matchMedia?.(OVERLAY_DESKTOP_QUERY).matches ?? true ? "dropdown" : "sheet";
6340
+ var subscribeNothing = () => () => void 0;
6341
+ var useHydrated = () => React31.useSyncExternalStore(
6342
+ subscribeNothing,
6343
+ () => true,
6344
+ () => false
6345
+ );
6346
+ function ActionMenu({
6347
+ trigger,
6348
+ title,
6349
+ description,
6350
+ open: openProp,
6351
+ onOpenChange,
6352
+ closeLabel,
6353
+ items,
6354
+ groups
6355
+ }) {
6356
+ const [uncontrolledOpen, setUncontrolledOpen] = React31.useState(false);
6357
+ const hydrated = useHydrated();
6358
+ const open = (openProp ?? uncontrolledOpen) && hydrated;
6359
+ const [shown, setShown] = React31.useState({
6360
+ open: false,
6361
+ presentation: "dropdown"
6362
+ });
6363
+ let presentation = shown.presentation;
6364
+ if (shown.open !== open) {
6365
+ if (open) presentation = readPresentation();
6366
+ setShown({ open, presentation });
6367
+ }
6368
+ const triggerRef = React31.useRef(null);
6369
+ const pendingRef = React31.useRef(null);
6370
+ const setOpen = (nextOpen) => {
6371
+ if (nextOpen) pendingRef.current = null;
6372
+ if (openProp === void 0) setUncontrolledOpen(nextOpen);
6373
+ onOpenChange?.(nextOpen);
6374
+ };
6375
+ const menuGroups = groups ?? [{ id: "items", items: items ?? [] }];
6376
+ const handleDropdownCloseAutoFocus = (event) => {
6377
+ const item = pendingRef.current;
6378
+ pendingRef.current = null;
6379
+ if (!item) return;
6380
+ event.preventDefault();
6381
+ triggerRef.current?.focus();
6382
+ item.onSelect();
6383
+ };
6384
+ const handleSheetCloseAutoFocus = (event) => {
6385
+ event.preventDefault();
6386
+ triggerRef.current?.focus();
6387
+ };
6388
+ const triggerLabel = trigger.props["aria-label"];
6389
+ return /* @__PURE__ */ jsxs31(Fragment13, { children: [
6390
+ /* @__PURE__ */ jsxs31(DropdownMenu, { open: open && presentation === "dropdown", onOpenChange: setOpen, children: [
6391
+ /* @__PURE__ */ jsx35(DropdownMenuTrigger, { asChild: true, "aria-expanded": open, children: /* @__PURE__ */ jsx35(Slot3.Root, { ref: triggerRef, children: trigger }) }),
6392
+ /* @__PURE__ */ jsx35(DropdownMenuContent, { align: "end", onCloseAutoFocus: handleDropdownCloseAutoFocus, children: menuGroups.map((group, index) => /* @__PURE__ */ jsxs31(React31.Fragment, { children: [
6393
+ index > 0 ? /* @__PURE__ */ jsx35(DropdownMenuSeparator, {}) : null,
6394
+ /* @__PURE__ */ jsxs31(DropdownMenuGroup, { children: [
6395
+ group.label ? /* @__PURE__ */ jsx35(DropdownMenuLabel, { children: group.label }) : null,
6396
+ group.items.map((item) => {
6397
+ const Icon = item.icon;
6398
+ return /* @__PURE__ */ jsxs31(
6399
+ DropdownMenuItem,
6400
+ {
6401
+ variant: item.destructive ? "destructive" : "default",
6402
+ disabled: item.disabled,
6403
+ onSelect: () => {
6404
+ pendingRef.current = item;
6405
+ },
6406
+ children: [
6407
+ Icon ? /* @__PURE__ */ jsx35(Icon, { "aria-hidden": true, size: 16, strokeWidth: 1.75 }) : null,
6408
+ item.label
6409
+ ]
6410
+ },
6411
+ item.id
6412
+ );
6413
+ })
6414
+ ] })
6415
+ ] }, group.id)) })
6416
+ ] }),
6417
+ /* @__PURE__ */ jsx35(
6418
+ ActionMenuSheet,
6419
+ {
6420
+ open: open && presentation === "sheet",
6421
+ onOpenChange: setOpen,
6422
+ title: title ?? /* @__PURE__ */ jsx35("span", { className: "sr-only", children: triggerLabel }),
6423
+ description,
6424
+ closeLabel,
6425
+ groups: menuGroups,
6426
+ onCloseAutoFocus: handleSheetCloseAutoFocus
6427
+ }
6428
+ )
6429
+ ] });
6430
+ }
6431
+
6432
+ // src/components/ui/list-card.tsx
6433
+ import { Fragment as Fragment14, jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
6434
+ function lineTokens(value) {
6435
+ return React32.Children.toArray(value).filter((token) => token !== "");
6436
+ }
6437
+ function MetaLine({
6438
+ tokens,
6439
+ slot,
6440
+ first,
6441
+ last
6442
+ }) {
6443
+ return /* @__PURE__ */ jsx36(
6444
+ "span",
6445
+ {
6446
+ "data-slot": slot,
6447
+ className: cn(
6448
+ "flex flex-wrap gap-x-[var(--space-3)] gap-y-[2px] text-[12px] leading-[16px] text-text-secondary",
6449
+ first ? "mt-[var(--space-1)]" : "mt-[2px]"
6450
+ ),
6451
+ children: tokens.map((token, index) => /* @__PURE__ */ jsxs32(
6452
+ "span",
6453
+ {
6454
+ className: "max-w-full truncate whitespace-nowrap",
6455
+ title: typeof token === "string" || typeof token === "number" ? String(token) : void 0,
6456
+ children: [
6457
+ token,
6458
+ index < tokens.length - 1 || !last ? /* @__PURE__ */ jsx36("span", { className: "sr-only", children: ", " }) : null
6459
+ ]
6460
+ },
6461
+ index
6462
+ ))
6278
6463
  }
6279
6464
  );
6280
- const trailingNode = trailing === "chevron" ? chevron : trailing === "none" ? null : /* @__PURE__ */ jsx35("span", { "data-slot": `${slot}-suffix`, children: trailing });
6465
+ }
6466
+ var titleClassName = "line-clamp-2 text-[13px] font-medium leading-[18px] text-text-primary [overflow-wrap:anywhere] [word-break:keep-all]";
6467
+ var overlayClassName = cn(
6468
+ "text-inherit no-underline outline-none after:absolute after:inset-0 after:content-['']",
6469
+ "focus-visible:after:ring-2 focus-visible:after:ring-inset focus-visible:after:ring-[var(--focus-ring)]"
6470
+ );
6471
+ function ListCard({
6472
+ title,
6473
+ meta,
6474
+ status,
6475
+ caption,
6476
+ leading,
6477
+ value,
6478
+ trailing = "chevron",
6479
+ actions,
6480
+ href,
6481
+ linkComponent,
6482
+ linkProps,
6483
+ onClick,
6484
+ slot = "list-card",
6485
+ className
6486
+ }) {
6487
+ const meta1 = lineTokens(meta?.[0]);
6488
+ const meta2 = lineTokens(meta?.[1]);
6489
+ const hasValue = value != null;
6490
+ const overlay = actions != null && (href != null || onClick != null);
6491
+ const trailingNode = trailing === "chevron" ? /* @__PURE__ */ jsx36(
6492
+ ChevronRight2,
6493
+ {
6494
+ "data-slot": `${slot}-suffix`,
6495
+ "aria-hidden": true,
6496
+ className: "size-[var(--space-4)] shrink-0 text-text-tertiary"
6497
+ }
6498
+ ) : trailing === "none" ? null : /* @__PURE__ */ jsx36("span", { "data-slot": `${slot}-suffix`, children: trailing });
6499
+ const bottomIcon = actions != null && trailingNode != null;
6500
+ const hasEnd = hasValue || actions != null || trailingNode != null;
6281
6501
  const rootClassName = cn(
6282
- "relative grid w-full min-w-0 items-center gap-x-[var(--space-2)] whitespace-normal text-left outline-none",
6502
+ "relative grid w-full min-w-0 items-start gap-x-[var(--space-2)] whitespace-normal text-left outline-none",
6283
6503
  "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--focus-ring)]",
6284
- // The right track is the 16px chevron, or `auto` when a value sits before it.
6285
- leading ? hasValue ? "grid-cols-[auto_minmax(0,1fr)_auto]" : "grid-cols-[auto_minmax(0,1fr)_16px]" : hasValue ? "grid-cols-[minmax(0,1fr)_auto]" : "grid-cols-[minmax(0,1fr)_16px]",
6286
- href && "after:absolute after:inset-0 after:content-['']",
6504
+ // An empty end keeps the 16px chevron track.
6505
+ leading ? hasEnd ? "grid-cols-[auto_minmax(0,1fr)_auto]" : "grid-cols-[auto_minmax(0,1fr)_16px]" : hasEnd ? "grid-cols-[minmax(0,1fr)_auto]" : "grid-cols-[minmax(0,1fr)_16px]",
6506
+ // 84 = the ⋮ hit area (2 above the top to 42 below) meets the chevron's (42 above the bottom to 2 below).
6507
+ bottomIcon ? "min-h-[calc(var(--space-20)+var(--space-1))]" : null,
6508
+ href && !overlay && "after:absolute after:inset-0 after:content-['']",
6287
6509
  className
6288
6510
  );
6289
- const content = /* @__PURE__ */ jsxs31(Fragment11, { children: [
6290
- leading != null ? /* @__PURE__ */ jsx35("span", { className: "flex items-center", children: leading }) : null,
6291
- /* @__PURE__ */ jsxs31("span", { className: "min-w-0", children: [
6292
- /* @__PURE__ */ jsx35(
6293
- "span",
6294
- {
6295
- "data-slot": `${slot}-title`,
6296
- className: "line-clamp-2 text-[13px] font-medium leading-[18px] text-text-primary [overflow-wrap:anywhere] [word-break:keep-all]",
6297
- title: typeof title === "string" || typeof title === "number" ? String(title) : void 0,
6298
- children: title
6299
- }
6300
- ),
6301
- meta1.length > 0 ? /* @__PURE__ */ jsx35("span", { className: "mt-[var(--space-1)] block", children: /* @__PURE__ */ jsx35(MetaLine, { tokens: meta1, slot: `${slot}-meta1` }) }) : null,
6302
- meta2.length > 0 ? /* @__PURE__ */ jsx35("span", { className: "mt-[2px] block", children: /* @__PURE__ */ jsx35(MetaLine, { tokens: meta2, slot: `${slot}-meta2` }) }) : null,
6303
- status != null ? /* @__PURE__ */ jsxs31("span", { "data-slot": `${slot}-bottom`, className: "mt-[var(--space-2)] flex min-h-[18px] items-center gap-[var(--space-2)]", children: [
6304
- /* @__PURE__ */ jsx35("span", { "data-slot": `${slot}-badge`, className: "flex items-center", children: status }),
6305
- caption != null ? /* @__PURE__ */ jsx35(
6511
+ const titleNode = /* @__PURE__ */ jsx36(
6512
+ "span",
6513
+ {
6514
+ "data-slot": `${slot}-title`,
6515
+ className: titleClassName,
6516
+ title: typeof title === "string" || typeof title === "number" ? String(title) : void 0,
6517
+ children: overlay && href != null ? React32.createElement(linkComponent ?? "a", { ...linkProps, href, className: overlayClassName }, title) : title
6518
+ }
6519
+ );
6520
+ const content = /* @__PURE__ */ jsxs32(Fragment14, { children: [
6521
+ leading != null ? /* @__PURE__ */ jsx36("span", { className: "flex min-h-[18px] items-center", children: leading }) : null,
6522
+ /* @__PURE__ */ jsxs32("span", { className: "min-w-0", children: [
6523
+ overlay && href == null ? (
6524
+ // A block button keeps the title's two-line clamp inside it.
6525
+ /* @__PURE__ */ jsx36("button", { type: "button", onClick, className: cn(overlayClassName, "block w-full text-left"), children: titleNode })
6526
+ ) : titleNode,
6527
+ meta1.length > 0 ? /* @__PURE__ */ jsx36(MetaLine, { tokens: meta1, slot: `${slot}-meta1`, first: true, last: meta2.length === 0 }) : null,
6528
+ meta2.length > 0 ? /* @__PURE__ */ jsx36(MetaLine, { tokens: meta2, slot: `${slot}-meta2`, first: meta1.length === 0, last: true }) : null,
6529
+ status != null || caption != null ? /* @__PURE__ */ jsxs32("span", { "data-slot": `${slot}-bottom`, className: "mt-[var(--space-2)] flex min-h-[18px] items-center gap-[var(--space-2)]", children: [
6530
+ status != null ? /* @__PURE__ */ jsx36("span", { "data-slot": `${slot}-badge`, className: "flex items-center", children: status }) : null,
6531
+ caption != null ? /* @__PURE__ */ jsx36(
6306
6532
  "span",
6307
6533
  {
6308
6534
  "data-slot": `${slot}-caption`,
@@ -6312,31 +6538,52 @@ function ListCard({
6312
6538
  ) : null
6313
6539
  ] }) : null
6314
6540
  ] }),
6315
- hasValue ? /* @__PURE__ */ jsxs31(
6316
- "span",
6317
- {
6318
- "data-slot": `${slot}-trailing`,
6319
- className: "inline-flex items-center gap-[var(--space-2)] text-[13px] leading-[20px] text-text-secondary tabular-nums",
6320
- children: [
6321
- /* @__PURE__ */ jsx35("span", { "data-slot": `${slot}-value`, children: value }),
6322
- trailingNode
6323
- ]
6324
- }
6325
- ) : trailingNode
6541
+ hasEnd ? /* @__PURE__ */ jsxs32("span", { "data-slot": `${slot}-trailing`, className: "flex flex-col items-end justify-between self-stretch", children: [
6542
+ /* @__PURE__ */ jsxs32(
6543
+ "span",
6544
+ {
6545
+ className: cn(
6546
+ "-mt-[var(--space-2)] flex min-h-[var(--space-8)] items-center",
6547
+ actions != null ? "-mr-[var(--space-2)] gap-[var(--space-1)]" : "gap-[var(--space-2)]"
6548
+ ),
6549
+ children: [
6550
+ hasValue ? /* @__PURE__ */ jsx36("span", { "data-slot": `${slot}-value`, className: "text-[13px] leading-[20px] text-text-secondary tabular-nums", children: value }) : null,
6551
+ actions != null ? /* @__PURE__ */ jsx36("span", { className: "relative z-[1] flex", children: /* @__PURE__ */ jsx36(
6552
+ ActionMenu,
6553
+ {
6554
+ title: typeof title === "string" ? title : void 0,
6555
+ items: [...actions.items],
6556
+ trigger: /* @__PURE__ */ jsx36(
6557
+ IconButton,
6558
+ {
6559
+ icon: MoreVertical,
6560
+ "aria-label": actions.label,
6561
+ appearance: "ghost",
6562
+ tone: "neutral",
6563
+ size: "md"
6564
+ }
6565
+ )
6566
+ }
6567
+ ) }) : trailingNode
6568
+ ]
6569
+ }
6570
+ ),
6571
+ bottomIcon ? trailingNode : null
6572
+ ] }) : null
6326
6573
  ] });
6327
- if (href) {
6574
+ if (href && !overlay) {
6328
6575
  const LinkComponent = linkComponent ?? "a";
6329
- return /* @__PURE__ */ jsx35(LinkComponent, { ...linkProps, href, className: rootClassName, children: content });
6576
+ return /* @__PURE__ */ jsx36(LinkComponent, { ...linkProps, href, className: rootClassName, children: content });
6330
6577
  }
6331
- if (onClick) {
6332
- return /* @__PURE__ */ jsx35("button", { type: "button", onClick, className: rootClassName, children: content });
6578
+ if (onClick && !overlay) {
6579
+ return /* @__PURE__ */ jsx36("button", { type: "button", onClick, className: rootClassName, children: content });
6333
6580
  }
6334
- return /* @__PURE__ */ jsx35("div", { className: rootClassName, children: content });
6581
+ return /* @__PURE__ */ jsx36("div", { className: rootClassName, children: content });
6335
6582
  }
6336
6583
 
6337
6584
  // src/components/ui/data-table.tsx
6338
- import { Fragment as Fragment12, jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
6339
- var dataTableVariants = cva12(
6585
+ import { Fragment as Fragment15, jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
6586
+ var dataTableVariants = cva13(
6340
6587
  [
6341
6588
  "relative overflow-hidden rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
6342
6589
  "text-foreground"
@@ -6355,7 +6602,7 @@ var dataTableVariants = cva12(
6355
6602
  }
6356
6603
  }
6357
6604
  );
6358
- var dataTableRowVariants = cva12(
6605
+ var dataTableRowVariants = cva13(
6359
6606
  [
6360
6607
  "grid min-h-[48px] items-center border-t border-[var(--border-subtle)]",
6361
6608
  "text-body-sm leading-compact text-foreground",
@@ -6386,9 +6633,9 @@ var alignmentClass = {
6386
6633
  function getRowId(row, keyField) {
6387
6634
  return String(row[keyField]);
6388
6635
  }
6389
- function getGridTemplate(columns, selectable) {
6636
+ function getGridTemplate(columns, selectable, expandable) {
6390
6637
  const columnWidths = columns.map((column) => column.width ?? "1fr");
6391
- return [selectable ? "44px" : null, ...columnWidths].filter(Boolean).join(" ");
6638
+ return [selectable ? "44px" : null, ...columnWidths, expandable ? "40px" : null].filter(Boolean).join(" ");
6392
6639
  }
6393
6640
  function getRenderedCell(row, column) {
6394
6641
  if (column.render) {
@@ -6398,7 +6645,7 @@ function getRenderedCell(row, column) {
6398
6645
  if (value === null || value === void 0) {
6399
6646
  return null;
6400
6647
  }
6401
- if (React32.isValidElement(value)) {
6648
+ if (React33.isValidElement(value)) {
6402
6649
  return value;
6403
6650
  }
6404
6651
  return String(value);
@@ -6418,7 +6665,7 @@ function isInteractiveTarget(target) {
6418
6665
  function SortIcon({ sort, columnKey }) {
6419
6666
  const isActive = sort?.key === columnKey;
6420
6667
  if (!isActive) {
6421
- return /* @__PURE__ */ jsx36(
6668
+ return /* @__PURE__ */ jsx37(
6422
6669
  ChevronsUpDown,
6423
6670
  {
6424
6671
  "aria-hidden": "true",
@@ -6429,8 +6676,8 @@ function SortIcon({ sort, columnKey }) {
6429
6676
  }
6430
6677
  );
6431
6678
  }
6432
- const Icon = sort.dir === "asc" ? ChevronUp2 : ChevronDown3;
6433
- return /* @__PURE__ */ jsx36(
6679
+ const Icon = sort.dir === "asc" ? ChevronUp2 : ChevronDown5;
6680
+ return /* @__PURE__ */ jsx37(
6434
6681
  Icon,
6435
6682
  {
6436
6683
  "aria-hidden": "true",
@@ -6448,8 +6695,8 @@ function MobileSortMenu({
6448
6695
  onSortChange
6449
6696
  }) {
6450
6697
  const active = sortBy ? columns.find((column) => column.key === sortBy.key) : void 0;
6451
- return /* @__PURE__ */ jsxs32(DropdownMenu, { children: [
6452
- /* @__PURE__ */ jsx36(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs32(
6698
+ return /* @__PURE__ */ jsxs33(DropdownMenu, { children: [
6699
+ /* @__PURE__ */ jsx37(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs33(
6453
6700
  Button,
6454
6701
  {
6455
6702
  "data-slot": "data-table-mobile-sort-button",
@@ -6458,26 +6705,26 @@ function MobileSortMenu({
6458
6705
  size: "sm",
6459
6706
  className: "ml-auto min-w-0",
6460
6707
  children: [
6461
- active && sortBy ? /* @__PURE__ */ jsxs32(Fragment12, { children: [
6462
- /* @__PURE__ */ jsx36("span", { className: "sr-only", children: "\uC815\uB82C " }),
6463
- /* @__PURE__ */ jsx36("span", { className: "truncate", children: active.header }),
6464
- /* @__PURE__ */ jsxs32("span", { className: "sr-only", children: [
6708
+ active && sortBy ? /* @__PURE__ */ jsxs33(Fragment15, { children: [
6709
+ /* @__PURE__ */ jsx37("span", { className: "sr-only", children: "\uC815\uB82C " }),
6710
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: active.header }),
6711
+ /* @__PURE__ */ jsxs33("span", { className: "sr-only", children: [
6465
6712
  ", ",
6466
6713
  sortBy.dir === "asc" ? "\uC624\uB984\uCC28\uC21C" : "\uB0B4\uB9BC\uCC28\uC21C"
6467
6714
  ] })
6468
6715
  ] }) : "\uC815\uB82C",
6469
- /* @__PURE__ */ jsx36(SortIcon, { sort: sortBy, columnKey: active?.key ?? "" })
6716
+ /* @__PURE__ */ jsx37(SortIcon, { sort: sortBy, columnKey: active?.key ?? "" })
6470
6717
  ]
6471
6718
  }
6472
6719
  ) }),
6473
- /* @__PURE__ */ jsx36(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx36(DropdownMenuRadioGroup, { value: active?.key ?? "", children: columns.map((column) => /* @__PURE__ */ jsxs32(
6720
+ /* @__PURE__ */ jsx37(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx37(DropdownMenuRadioGroup, { value: active?.key ?? "", children: columns.map((column) => /* @__PURE__ */ jsxs33(
6474
6721
  DropdownMenuRadioItem,
6475
6722
  {
6476
6723
  value: column.key,
6477
6724
  onSelect: () => onSortChange?.(column.key, getNextSort(sortBy, column.key)),
6478
6725
  children: [
6479
- /* @__PURE__ */ jsx36("span", { className: "truncate", children: column.header }),
6480
- column.key === active?.key ? /* @__PURE__ */ jsx36("span", { className: "ml-auto pl-[var(--space-4)]", children: /* @__PURE__ */ jsx36(SortIcon, { sort: sortBy, columnKey: column.key }) }) : null
6726
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: column.header }),
6727
+ column.key === active?.key ? /* @__PURE__ */ jsx37("span", { className: "ml-auto pl-[var(--space-4)]", children: /* @__PURE__ */ jsx37(SortIcon, { sort: sortBy, columnKey: column.key }) }) : null
6481
6728
  ]
6482
6729
  },
6483
6730
  column.key
@@ -6496,14 +6743,14 @@ function MobileToolbar({
6496
6743
  if (!selectable && sortableColumns.length === 0) {
6497
6744
  return null;
6498
6745
  }
6499
- return /* @__PURE__ */ jsxs32(
6746
+ return /* @__PURE__ */ jsxs33(
6500
6747
  "div",
6501
6748
  {
6502
6749
  "data-slot": "data-table-mobile-toolbar",
6503
6750
  className: "flex min-w-0 items-center gap-[var(--space-2)] px-[var(--space-4)] py-[var(--space-2)]",
6504
6751
  children: [
6505
- selectable ? /* @__PURE__ */ jsx36(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll }) : null,
6506
- sortableColumns.length > 0 ? /* @__PURE__ */ jsx36(MobileSortMenu, { columns: sortableColumns, sortBy, onSortChange }) : null
6752
+ selectable ? /* @__PURE__ */ jsx37(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll }) : null,
6753
+ sortableColumns.length > 0 ? /* @__PURE__ */ jsx37(MobileSortMenu, { columns: sortableColumns, sortBy, onSortChange }) : null
6507
6754
  ]
6508
6755
  }
6509
6756
  );
@@ -6512,13 +6759,13 @@ function SelectAllCheckbox({
6512
6759
  checked,
6513
6760
  onToggleAll
6514
6761
  }) {
6515
- return /* @__PURE__ */ jsx36(
6762
+ return /* @__PURE__ */ jsx37(
6516
6763
  Checkbox,
6517
6764
  {
6518
6765
  "aria-label": "\uC804\uCCB4 \uD589 \uC120\uD0DD",
6519
6766
  checked,
6520
6767
  onCheckedChange: (nextChecked) => onToggleAll(nextChecked === true),
6521
- children: /* @__PURE__ */ jsx36("span", { className: "sr-only", children: "\uC804\uCCB4 \uD589 \uC120\uD0DD" })
6768
+ children: /* @__PURE__ */ jsx37("span", { className: "sr-only", children: "\uC804\uCCB4 \uD589 \uC120\uD0DD" })
6522
6769
  }
6523
6770
  );
6524
6771
  }
@@ -6529,13 +6776,13 @@ function RowCheckbox({
6529
6776
  selected,
6530
6777
  onToggle
6531
6778
  }) {
6532
- return /* @__PURE__ */ jsx36(
6779
+ return /* @__PURE__ */ jsx37(
6533
6780
  Checkbox,
6534
6781
  {
6535
6782
  "aria-label": `${String(row[columns[0]?.key] ?? rowId)} \uD589 \uC120\uD0DD`,
6536
6783
  checked: selected,
6537
6784
  onCheckedChange: (nextChecked) => onToggle(rowId, nextChecked === true),
6538
- children: /* @__PURE__ */ jsxs32("span", { className: "sr-only", children: [
6785
+ children: /* @__PURE__ */ jsxs33("span", { className: "sr-only", children: [
6539
6786
  rowId,
6540
6787
  " \uD589 \uC120\uD0DD"
6541
6788
  ] })
@@ -6552,17 +6799,17 @@ function SkeletonRows({
6552
6799
  // role="table"의 허용 자식은 row/rowgroup뿐이라 컨테이너는 rowgroup이어야 한다.
6553
6800
  // 로딩 알림은 그 안의 row/cell 안에 둔다 — 종전에는 컨테이너가 role="status"라
6554
6801
  // aria-required-children(Critical)이 났다.
6555
- /* @__PURE__ */ jsxs32("div", { role: "rowgroup", children: [
6556
- /* @__PURE__ */ jsx36("div", { role: "row", children: /* @__PURE__ */ jsx36("div", { role: "cell", "aria-colindex": 1, "aria-label": "\uB370\uC774\uD130 \uB85C\uB4DC \uC911", children: /* @__PURE__ */ jsx36("span", { role: "status", className: "sr-only", children: "\uB370\uC774\uD130 \uB85C\uB4DC \uC911" }) }) }),
6557
- Array.from({ length: count }, (_, rowIndex) => /* @__PURE__ */ jsxs32(
6802
+ /* @__PURE__ */ jsxs33("div", { role: "rowgroup", children: [
6803
+ /* @__PURE__ */ jsx37("div", { role: "row", children: /* @__PURE__ */ jsx37("div", { role: "cell", "aria-colindex": 1, "aria-label": "\uB370\uC774\uD130 \uB85C\uB4DC \uC911", children: /* @__PURE__ */ jsx37("span", { role: "status", className: "sr-only", children: "\uB370\uC774\uD130 \uB85C\uB4DC \uC911" }) }) }),
6804
+ Array.from({ length: count }, (_, rowIndex) => /* @__PURE__ */ jsxs33(
6558
6805
  "div",
6559
6806
  {
6560
6807
  "data-slot": "data-table-skeleton-row",
6561
6808
  className: "grid min-h-[48px] items-center border-t border-[var(--border-subtle)]",
6562
6809
  style: { gridTemplateColumns },
6563
6810
  children: [
6564
- selectable ? /* @__PURE__ */ jsx36("div", { "aria-hidden": "true", className: "px-[var(--space-4)]" }) : null,
6565
- columns.map((column, columnIndex) => /* @__PURE__ */ jsx36("div", { className: "px-[var(--space-4)] py-[var(--space-2)]", children: /* @__PURE__ */ jsx36(
6811
+ selectable ? /* @__PURE__ */ jsx37("div", { "aria-hidden": "true", className: "px-[var(--space-4)]" }) : null,
6812
+ columns.map((column, columnIndex) => /* @__PURE__ */ jsx37("div", { className: "px-[var(--space-4)] py-[var(--space-2)]", children: /* @__PURE__ */ jsx37(
6566
6813
  "div",
6567
6814
  {
6568
6815
  className: cn(
@@ -6579,15 +6826,15 @@ function SkeletonRows({
6579
6826
  );
6580
6827
  }
6581
6828
  function MobileSkeletonCards({ count }) {
6582
- return /* @__PURE__ */ jsx36("div", { "data-slot": "data-table-mobile-skeleton", "aria-label": "\uB370\uC774\uD130 \uB85C\uB4DC \uC911", role: "status", children: Array.from({ length: count }, (_, rowIndex) => /* @__PURE__ */ jsxs32(
6829
+ return /* @__PURE__ */ jsx37("div", { "data-slot": "data-table-mobile-skeleton", "aria-label": "\uB370\uC774\uD130 \uB85C\uB4DC \uC911", role: "status", children: Array.from({ length: count }, (_, rowIndex) => /* @__PURE__ */ jsxs33(
6583
6830
  "div",
6584
6831
  {
6585
6832
  "data-slot": "data-table-mobile-skeleton-card",
6586
6833
  className: "flex flex-col gap-[var(--space-2)] border-t border-[var(--border-subtle)] px-[var(--space-4)] py-[var(--space-4)]",
6587
6834
  children: [
6588
- /* @__PURE__ */ jsx36("div", { className: "h-[14px] w-[72%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
6589
- /* @__PURE__ */ jsx36("div", { className: "h-[12px] w-[56%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
6590
- /* @__PURE__ */ jsx36("div", { className: "h-[12px] w-[64%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" })
6835
+ /* @__PURE__ */ jsx37("div", { className: "h-[14px] w-[72%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
6836
+ /* @__PURE__ */ jsx37("div", { className: "h-[12px] w-[56%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
6837
+ /* @__PURE__ */ jsx37("div", { className: "h-[12px] w-[64%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" })
6591
6838
  ]
6592
6839
  },
6593
6840
  rowIndex
@@ -6598,6 +6845,19 @@ var rowLinkClass = cn(
6598
6845
  "text-inherit no-underline outline-none after:absolute after:inset-0 after:content-['']",
6599
6846
  "focus-visible:after:ring-2 focus-visible:after:ring-inset focus-visible:after:ring-[var(--focus-ring)]"
6600
6847
  );
6848
+ var expandedPanelClass = cn(
6849
+ "grid grid-rows-[0fr] invisible data-[state=open]:grid-rows-[1fr] data-[state=open]:visible",
6850
+ "motion-safe:[transition:grid-template-rows_var(--dur-base)_var(--ease-standard),visibility_0s_linear_var(--dur-base)]",
6851
+ "motion-safe:data-[state=open]:[transition:grid-template-rows_var(--dur-base)_var(--ease-out),visibility_0s]"
6852
+ );
6853
+ var expandChevronClass = "motion-safe:transition-transform motion-safe:duration-[var(--dur-base)] motion-safe:ease-[var(--ease-standard)]";
6854
+ function useOpenedOnce(expanded) {
6855
+ const [opened, setOpened] = React33.useState(expanded);
6856
+ if (expanded && !opened) {
6857
+ setOpened(true);
6858
+ }
6859
+ return opened || expanded;
6860
+ }
6601
6861
  function useActivationHandlers({ row, href, activatable, onActivate }) {
6602
6862
  return {
6603
6863
  onClick: (event) => {
@@ -6630,12 +6890,14 @@ function DataTableRowView({
6630
6890
  onToggle,
6631
6891
  onActivate,
6632
6892
  onRowContextMenu,
6893
+ expand,
6633
6894
  gridTemplateColumns,
6634
6895
  ariaRowIndex
6635
6896
  }) {
6636
6897
  const linked = Boolean(LinkComponent && href);
6637
6898
  const handlers = useActivationHandlers({ row, href, activatable, onActivate });
6638
- return /* @__PURE__ */ jsxs32(
6899
+ const opened = useOpenedOnce(expand?.expanded ?? false);
6900
+ const dataRow = /* @__PURE__ */ jsxs33(
6639
6901
  "div",
6640
6902
  {
6641
6903
  "data-slot": "data-table-row",
@@ -6645,19 +6907,21 @@ function DataTableRowView({
6645
6907
  "aria-rowindex": ariaRowIndex,
6646
6908
  tabIndex: activatable ? 0 : void 0,
6647
6909
  className: cn(
6648
- dataTableRowVariants({ interactive: activatable || linked, selected: visuallySelected }),
6910
+ dataTableRowVariants({ interactive: activatable || linked || expand != null, selected: visuallySelected }),
6649
6911
  linked ? rowLinkHostClass : null
6650
6912
  ),
6651
6913
  style: { gridTemplateColumns },
6652
6914
  onContextMenu: (event) => onRowContextMenu?.(rowId, event),
6653
- onClick: handlers.onClick,
6915
+ onClick: expand ? (event) => {
6916
+ if (!isInteractiveTarget(event.target)) expand.onToggle(rowId);
6917
+ } : handlers.onClick,
6654
6918
  onKeyDown: handlers.onKeyDown,
6655
6919
  children: [
6656
- selectable ? /* @__PURE__ */ jsx36("div", { role: "cell", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx36(RowCheckbox, { row, rowId, columns, selected, onToggle }) }) : null,
6920
+ selectable ? /* @__PURE__ */ jsx37("div", { role: "cell", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx37(RowCheckbox, { row, rowId, columns, selected, onToggle }) }) : null,
6657
6921
  columns.map((column, columnIndex) => {
6658
6922
  const align = column.align ?? "left";
6659
6923
  const content = getRenderedCell(row, column);
6660
- return /* @__PURE__ */ jsx36(
6924
+ return /* @__PURE__ */ jsx37(
6661
6925
  "div",
6662
6926
  {
6663
6927
  "data-slot": "data-table-cell",
@@ -6667,14 +6931,57 @@ function DataTableRowView({
6667
6931
  alignmentClass[align],
6668
6932
  column.tabular ? "font-[family-name:var(--font-display)] tabular-nums" : null
6669
6933
  ),
6670
- children: /* @__PURE__ */ jsx36("span", { className: "min-w-0 truncate", children: linked && columnIndex === 0 && LinkComponent ? /* @__PURE__ */ jsx36(LinkComponent, { href, "data-slot": "data-table-row-link", className: rowLinkClass, children: content }) : content })
6934
+ children: /* @__PURE__ */ jsx37("span", { className: "min-w-0 truncate", children: linked && columnIndex === 0 && LinkComponent ? /* @__PURE__ */ jsx37(LinkComponent, { href, "data-slot": "data-table-row-link", className: rowLinkClass, children: content }) : content })
6671
6935
  },
6672
6936
  column.key
6673
6937
  );
6674
- })
6938
+ }),
6939
+ expand ? /* @__PURE__ */ jsx37("div", { role: "cell", "data-slot": "data-table-expand-cell", className: "flex items-center justify-end pr-[var(--space-2)]", children: /* @__PURE__ */ jsx37(
6940
+ IconButton,
6941
+ {
6942
+ icon: ChevronRight3,
6943
+ "aria-label": expand.label,
6944
+ "aria-expanded": expand.expanded,
6945
+ "aria-controls": expand.panelId,
6946
+ appearance: "ghost",
6947
+ tone: "neutral",
6948
+ size: "md",
6949
+ className: cn(
6950
+ "aria-expanded:[&_svg]:rotate-90",
6951
+ "motion-safe:[&_svg]:transition-transform motion-safe:[&_svg]:duration-[var(--dur-base)] motion-safe:[&_svg]:ease-[var(--ease-standard)]"
6952
+ ),
6953
+ onClick: () => expand.onToggle(rowId)
6954
+ }
6955
+ ) }) : null
6675
6956
  ]
6676
6957
  }
6677
6958
  );
6959
+ if (!expand) {
6960
+ return dataRow;
6961
+ }
6962
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
6963
+ dataRow,
6964
+ /* @__PURE__ */ jsx37(
6965
+ "div",
6966
+ {
6967
+ role: "row",
6968
+ "data-slot": "data-table-expanded-row",
6969
+ "data-row-id": rowId,
6970
+ "data-state": expand.expanded ? "open" : "closed",
6971
+ className: expandedPanelClass,
6972
+ children: /* @__PURE__ */ jsx37(
6973
+ "div",
6974
+ {
6975
+ role: "cell",
6976
+ id: expand.panelId,
6977
+ "aria-colspan": columns.length + (selectable ? 2 : 1),
6978
+ className: "min-h-0 min-w-0 overflow-hidden",
6979
+ children: opened ? expand.render(row) : null
6980
+ }
6981
+ )
6982
+ }
6983
+ )
6984
+ ] });
6678
6985
  }
6679
6986
  function DataTableMobileCardView({
6680
6987
  row,
@@ -6689,20 +6996,50 @@ function DataTableMobileCardView({
6689
6996
  onToggle,
6690
6997
  onActivate,
6691
6998
  onRowContextMenu,
6999
+ expand,
6692
7000
  getMobileCardContent,
6693
7001
  ariaPosInSet,
6694
7002
  ariaSetSize,
6695
7003
  first
6696
7004
  }) {
6697
7005
  const linked = Boolean(LinkComponent && href);
6698
- const handlers = useActivationHandlers({ row, href, activatable, onActivate });
6699
7006
  const content = getMobileCardContent(row);
6700
7007
  const navigable = linked || activatable;
6701
- const leading = selectable || content.leading != null ? /* @__PURE__ */ jsxs32("span", { className: "flex items-center gap-[var(--space-2)]", children: [
6702
- selectable ? /* @__PURE__ */ jsx36(RowCheckbox, { row, rowId, columns, selected, onToggle }) : null,
7008
+ const opened = useOpenedOnce(expand?.expanded ?? false);
7009
+ const leading = selectable || content.leading != null ? /* @__PURE__ */ jsxs33("span", { className: "flex items-center gap-[var(--space-2)]", children: [
7010
+ selectable ? /* @__PURE__ */ jsx37(RowCheckbox, { row, rowId, columns, selected, onToggle }) : null,
6703
7011
  content.leading
6704
7012
  ] }) : void 0;
6705
- return /* @__PURE__ */ jsx36(
7013
+ let title = content.title;
7014
+ if (expand) {
7015
+ title = /* @__PURE__ */ jsx37(
7016
+ "button",
7017
+ {
7018
+ type: "button",
7019
+ "data-slot": "data-table-row-link",
7020
+ "aria-label": expand.label,
7021
+ "aria-expanded": expand.expanded,
7022
+ "aria-controls": expand.panelId,
7023
+ className: cn(rowLinkClass, "block w-full text-left"),
7024
+ onClick: () => expand.onToggle(rowId),
7025
+ children: /* @__PURE__ */ jsx37("span", { className: "line-clamp-2", children: content.title })
7026
+ }
7027
+ );
7028
+ } else if (linked && LinkComponent) {
7029
+ title = /* @__PURE__ */ jsx37(LinkComponent, { href, "data-slot": "data-table-row-link", className: rowLinkClass, children: content.title });
7030
+ } else if (activatable) {
7031
+ title = /* @__PURE__ */ jsx37(
7032
+ "button",
7033
+ {
7034
+ type: "button",
7035
+ "data-slot": "data-table-row-link",
7036
+ className: cn(rowLinkClass, "block w-full text-left"),
7037
+ onClick: (event) => onActivate(row, href, event),
7038
+ children: /* @__PURE__ */ jsx37("span", { className: "line-clamp-2", children: content.title })
7039
+ }
7040
+ );
7041
+ }
7042
+ return /* @__PURE__ */ jsxs33(
6706
7043
  "div",
6707
7044
  {
6708
7045
  "data-slot": "data-table-mobile-card",
@@ -6711,37 +7048,57 @@ function DataTableMobileCardView({
6711
7048
  role: "listitem",
6712
7049
  "aria-posinset": ariaPosInSet,
6713
7050
  "aria-setsize": ariaSetSize,
6714
- "aria-label": content.ariaLabel,
6715
- tabIndex: activatable ? 0 : void 0,
7051
+ "aria-label": content.ariaLabel ?? String(content.title),
6716
7052
  className: cn(
6717
7053
  "min-w-0 border-t border-[var(--border-subtle)] transition-colors motion-reduce:transition-none",
6718
7054
  first ? "border-t-0" : null,
6719
- navigable ? "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,
7055
+ navigable ? "cursor-pointer hover:bg-[var(--action-hover)]" : null,
6720
7056
  visuallySelected ? "bg-[var(--action-selected)]" : null,
6721
- linked ? rowLinkHostClass : null
7057
+ navigable ? rowLinkHostClass : null
6722
7058
  ),
6723
7059
  onContextMenu: (event) => onRowContextMenu?.(rowId, event),
6724
- onClick: handlers.onClick,
6725
- onKeyDown: handlers.onKeyDown,
6726
- children: /* @__PURE__ */ jsx36(
6727
- ListCard,
6728
- {
6729
- className: "px-[var(--space-4)] py-[var(--space-3)]",
6730
- title: linked && LinkComponent ? /* @__PURE__ */ jsx36(LinkComponent, { href, "data-slot": "data-table-row-link", className: rowLinkClass, children: content.title }) : content.title,
6731
- meta: content.meta ? [content.meta[0], content.meta[1]] : void 0,
6732
- status: content.status,
6733
- caption: content.date,
6734
- value: content.value,
6735
- leading,
6736
- trailing: navigable ? "chevron" : "none"
6737
- }
6738
- )
7060
+ children: [
7061
+ /* @__PURE__ */ jsx37(
7062
+ ListCard,
7063
+ {
7064
+ className: cn(
7065
+ "px-[var(--space-4)] py-[var(--space-3)]",
7066
+ expand ? ["cursor-pointer transition-colors hover:bg-[var(--action-hover)] motion-reduce:transition-none", rowLinkHostClass] : null
7067
+ ),
7068
+ title,
7069
+ meta: content.meta ? [content.meta[0], content.meta[1]] : void 0,
7070
+ status: content.status,
7071
+ caption: content.date,
7072
+ value: content.value,
7073
+ leading,
7074
+ trailing: expand ? /* @__PURE__ */ jsx37(
7075
+ ChevronRight3,
7076
+ {
7077
+ "aria-hidden": true,
7078
+ "data-state": expand.expanded ? "open" : "closed",
7079
+ className: cn("block size-[var(--space-4)] shrink-0 text-text-tertiary data-[state=open]:rotate-90", expandChevronClass)
7080
+ }
7081
+ ) : navigable ? "chevron" : "none",
7082
+ actions: content.actions
7083
+ }
7084
+ ),
7085
+ expand ? /* @__PURE__ */ jsx37(
7086
+ "div",
7087
+ {
7088
+ id: expand.panelId,
7089
+ "data-slot": "data-table-expanded",
7090
+ "data-state": expand.expanded ? "open" : "closed",
7091
+ className: expandedPanelClass,
7092
+ children: /* @__PURE__ */ jsx37("div", { className: "min-h-0 min-w-0 overflow-hidden", children: opened ? expand.render(row) : null })
7093
+ }
7094
+ ) : null
7095
+ ]
6739
7096
  }
6740
7097
  );
6741
7098
  }
6742
- var MemoDataTableRow = React32.memo(DataTableRowView);
6743
- var MemoDataTableMobileCard = React32.memo(DataTableMobileCardView);
6744
- var useIsomorphicLayoutEffect = typeof window === "undefined" ? React32.useEffect : React32.useLayoutEffect;
7099
+ var MemoDataTableRow = React33.memo(DataTableRowView);
7100
+ var MemoDataTableMobileCard = React33.memo(DataTableMobileCardView);
7101
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? React33.useEffect : React33.useLayoutEffect;
6745
7102
  var VIRTUAL_DEFAULT_OVERSCAN = 8;
6746
7103
  var VIRTUAL_INITIAL_ROWS = 24;
6747
7104
  var VIRTUAL_FALLBACK_SIZE = { desktop: 48, mobile: 120 };
@@ -6821,7 +7178,7 @@ function useVirtualWindow({
6821
7178
  mobileListRef
6822
7179
  }) {
6823
7180
  const count = rowIds.length;
6824
- const [win, setWin] = React32.useState({
7181
+ const [win, setWin] = React33.useState({
6825
7182
  layout: null,
6826
7183
  start: 0,
6827
7184
  end: VIRTUAL_INITIAL_ROWS,
@@ -6829,12 +7186,12 @@ function useVirtualWindow({
6829
7186
  padTop: 0,
6830
7187
  padBottom: 0
6831
7188
  });
6832
- const desktopSize = React32.useRef(0);
6833
- const cardHeights = React32.useRef(null);
7189
+ const desktopSize = React33.useRef(0);
7190
+ const cardHeights = React33.useRef(null);
6834
7191
  cardHeights.current ??= new CardHeights();
6835
- const update = React32.useRef(() => void 0);
6836
- const reported = React32.useRef("");
6837
- const latest = React32.useRef({
7192
+ const update = React33.useRef(() => void 0);
7193
+ const reported = React33.useRef("");
7194
+ const latest = React33.useRef({
6838
7195
  count,
6839
7196
  layout: "desktop",
6840
7197
  extent: uniformExtent(VIRTUAL_FALLBACK_SIZE.desktop)
@@ -6897,7 +7254,7 @@ function useVirtualWindow({
6897
7254
  useIsomorphicLayoutEffect(() => {
6898
7255
  update.current();
6899
7256
  });
6900
- React32.useEffect(() => {
7257
+ React33.useEffect(() => {
6901
7258
  if (!enabled) {
6902
7259
  return;
6903
7260
  }
@@ -6919,7 +7276,7 @@ function useVirtualWindow({
6919
7276
  window.cancelAnimationFrame(frame);
6920
7277
  };
6921
7278
  }, [enabled]);
6922
- const scrollToIndex = React32.useCallback(
7279
+ const scrollToIndex = React33.useCallback(
6923
7280
  (index) => {
6924
7281
  const { count: rowCount, layout, extent } = latest.current;
6925
7282
  const list = (layout === "desktop" ? desktopListRef : mobileListRef).current;
@@ -6952,7 +7309,7 @@ function useVisibleLayout({
6952
7309
  desktopRef,
6953
7310
  mobileRef
6954
7311
  }) {
6955
- const [layout, setLayout] = React32.useState(null);
7312
+ const [layout, setLayout] = React33.useState(null);
6956
7313
  useIsomorphicLayoutEffect(() => {
6957
7314
  if (!enabled) {
6958
7315
  return;
@@ -6989,9 +7346,9 @@ function useLayoutFocusHandoff({
6989
7346
  layout,
6990
7347
  containers
6991
7348
  }) {
6992
- const lastFocus = React32.useRef(null);
6993
- const previousLayout = React32.useRef(layout);
6994
- React32.useEffect(() => {
7349
+ const lastFocus = React33.useRef(null);
7350
+ const previousLayout = React33.useRef(layout);
7351
+ React33.useEffect(() => {
6995
7352
  const root = rootRef.current;
6996
7353
  if (!root) {
6997
7354
  return;
@@ -7043,7 +7400,7 @@ function useLayoutFocusHandoff({
7043
7400
  const item = record.rowId ? Array.from(container.querySelectorAll("[data-row-id]")).find(
7044
7401
  (node) => node.getAttribute("data-row-id") === record.rowId
7045
7402
  ) : void 0;
7046
- const target = (item && (record.checkbox ? item.querySelector('[role="checkbox"]') : item.hasAttribute("tabindex") ? item : item.querySelector("a[href]"))) ?? item ?? container;
7403
+ const target = (item && (record.checkbox ? item.querySelector('[role="checkbox"]') : item.hasAttribute("tabindex") ? item : item.querySelector('[data-slot="data-table-row-link"],[data-slot="data-table-expand-cell"] button'))) ?? item ?? container;
7047
7404
  if (target instanceof HTMLElement) {
7048
7405
  if (!target.hasAttribute("tabindex") && !target.matches("a[href],button,input")) {
7049
7406
  target.tabIndex = -1;
@@ -7075,19 +7432,23 @@ function DataTableInner({
7075
7432
  linkComponent,
7076
7433
  onRowClick,
7077
7434
  virtual,
7435
+ renderExpanded,
7436
+ getExpandLabel,
7437
+ expandedIds,
7438
+ onExpandedChange,
7078
7439
  skeletonRowCount = 8,
7079
7440
  "aria-label": ariaLabel = "\uB370\uC774\uD130 \uD14C\uC774\uBE14",
7080
7441
  ...props
7081
7442
  }, ref) {
7082
7443
  const virtualOptions = virtual ? virtual === true ? {} : virtual : null;
7083
7444
  const isVirtual = virtualOptions !== null;
7084
- const rootRef = React32.useRef(null);
7085
- const desktopRef = React32.useRef(null);
7086
- const headerRef = React32.useRef(null);
7087
- const desktopListRef = React32.useRef(null);
7088
- const mobileRef = React32.useRef(null);
7089
- const mobileListRef = React32.useRef(null);
7090
- const setRootRef = React32.useCallback(
7445
+ const rootRef = React33.useRef(null);
7446
+ const desktopRef = React33.useRef(null);
7447
+ const headerRef = React33.useRef(null);
7448
+ const desktopListRef = React33.useRef(null);
7449
+ const mobileRef = React33.useRef(null);
7450
+ const mobileListRef = React33.useRef(null);
7451
+ const setRootRef = React33.useCallback(
7091
7452
  (node) => {
7092
7453
  rootRef.current = node;
7093
7454
  if (typeof ref === "function") ref(node);
@@ -7106,7 +7467,7 @@ function DataTableInner({
7106
7467
  desktopListRef,
7107
7468
  mobileListRef
7108
7469
  });
7109
- React32.useImperativeHandle(virtualOptions?.handleRef, () => ({ scrollToIndex }), [scrollToIndex]);
7470
+ React33.useImperativeHandle(virtualOptions?.handleRef, () => ({ scrollToIndex }), [scrollToIndex]);
7110
7471
  const visibleLayout = useVisibleLayout({ enabled: !isVirtual, desktopRef, mobileRef });
7111
7472
  const activeLayout = isVirtual ? virtualWindow.layout : visibleLayout;
7112
7473
  useLayoutFocusHandoff({
@@ -7122,7 +7483,23 @@ function DataTableInner({
7122
7483
  const allVisibleRowsSelected = rowIds.length > 0 && selectedCount === rowIds.length;
7123
7484
  const partiallySelected = selectedCount > 0 && !allVisibleRowsSelected;
7124
7485
  const selectAllChecked = partiallySelected ? "indeterminate" : allVisibleRowsSelected;
7125
- const gridTemplateColumns = getGridTemplate(columns, selectable);
7486
+ const expandable = renderExpanded != null;
7487
+ const gridTemplateColumns = getGridTemplate(columns, selectable, expandable);
7488
+ const panelIdBase = React33.useId();
7489
+ const [ownExpandedIds, setOwnExpandedIds] = React33.useState(() => /* @__PURE__ */ new Set());
7490
+ const resolvedExpandedIds = expandedIds ?? ownExpandedIds;
7491
+ const toggleExpanded = (id) => {
7492
+ const nextIds = new Set(resolvedExpandedIds);
7493
+ if (nextIds.has(id)) {
7494
+ nextIds.delete(id);
7495
+ } else {
7496
+ nextIds.add(id);
7497
+ }
7498
+ if (expandedIds === void 0) {
7499
+ setOwnExpandedIds(nextIds);
7500
+ }
7501
+ onExpandedChange?.(nextIds);
7502
+ };
7126
7503
  const emitSelection = (nextIds) => {
7127
7504
  onSelectionChange?.(nextIds);
7128
7505
  };
@@ -7151,23 +7528,23 @@ function DataTableInner({
7151
7528
  window.location.assign(href);
7152
7529
  }
7153
7530
  };
7154
- const latestHandlers = React32.useRef({ toggleRow, activateRow, onRowContextMenu });
7531
+ const latestHandlers = React33.useRef({ toggleRow, activateRow, onRowContextMenu });
7155
7532
  useIsomorphicLayoutEffect(() => {
7156
7533
  latestHandlers.current = { toggleRow, activateRow, onRowContextMenu };
7157
7534
  });
7158
- const stableToggleRow = React32.useCallback(
7535
+ const stableToggleRow = React33.useCallback(
7159
7536
  (id, checked) => latestHandlers.current.toggleRow(id, checked),
7160
7537
  []
7161
7538
  );
7162
- const stableActivateRow = React32.useCallback(
7539
+ const stableActivateRow = React33.useCallback(
7163
7540
  (row, href, event) => latestHandlers.current.activateRow(row, href, event),
7164
7541
  []
7165
7542
  );
7166
- const stableRowContextMenu = React32.useCallback(
7543
+ const stableRowContextMenu = React33.useCallback(
7167
7544
  (rowId, event) => latestHandlers.current.onRowContextMenu?.(rowId, event),
7168
7545
  []
7169
7546
  );
7170
- const getItemProps = (row) => {
7547
+ const getItemProps = (row, layout, index) => {
7171
7548
  const rowId = getRowId(row, keyField);
7172
7549
  const selected = resolvedSelectedIds.has(rowId);
7173
7550
  const href = rowHref?.(row);
@@ -7184,7 +7561,14 @@ function DataTableInner({
7184
7561
  LinkComponent: linkComponent,
7185
7562
  onToggle: isVirtual ? stableToggleRow : toggleRow,
7186
7563
  onActivate: isVirtual ? stableActivateRow : activateRow,
7187
- onRowContextMenu: isVirtual ? stableRowContextMenu : onRowContextMenu
7564
+ onRowContextMenu: isVirtual ? stableRowContextMenu : onRowContextMenu,
7565
+ expand: renderExpanded && getExpandLabel ? {
7566
+ expanded: resolvedExpandedIds.has(rowId),
7567
+ label: getExpandLabel(row),
7568
+ panelId: `${panelIdBase}-${layout}-${index}`,
7569
+ render: renderExpanded,
7570
+ onToggle: toggleExpanded
7571
+ } : void 0
7188
7572
  };
7189
7573
  };
7190
7574
  const sliceFor = (layout) => {
@@ -7215,7 +7599,7 @@ function DataTableInner({
7215
7599
  const mobileSlice = sliceFor("mobile");
7216
7600
  const RowComponent = isVirtual ? MemoDataTableRow : DataTableRowView;
7217
7601
  const CardComponent = isVirtual ? MemoDataTableMobileCard : DataTableMobileCardView;
7218
- return /* @__PURE__ */ jsxs32(
7602
+ return /* @__PURE__ */ jsxs33(
7219
7603
  "div",
7220
7604
  {
7221
7605
  ref: setRootRef,
@@ -7229,7 +7613,7 @@ function DataTableInner({
7229
7613
  ),
7230
7614
  ...props,
7231
7615
  children: [
7232
- selectable && announceSelection ? /* @__PURE__ */ jsx36(
7616
+ selectable && announceSelection ? /* @__PURE__ */ jsx37(
7233
7617
  "div",
7234
7618
  {
7235
7619
  "data-slot": "data-table-selection-status",
@@ -7238,23 +7622,23 @@ function DataTableInner({
7238
7622
  children: selectedCount > 0 ? `${selectedCount.toLocaleString("ko-KR")}${selectionUnit} \uC120\uD0DD\uB428` : ""
7239
7623
  }
7240
7624
  ) : null,
7241
- loading && data.length > 0 ? /* @__PURE__ */ jsx36(
7625
+ loading && data.length > 0 ? /* @__PURE__ */ jsx37(
7242
7626
  "div",
7243
7627
  {
7244
7628
  "data-slot": "data-table-progress",
7245
7629
  "aria-hidden": "true",
7246
7630
  className: "absolute left-0 right-0 top-0 z-10 h-[2px] overflow-hidden bg-[var(--action-selected)]",
7247
- children: /* @__PURE__ */ jsx36("div", { className: "h-full w-1/3 animate-pulse bg-[var(--primary)]" })
7631
+ children: /* @__PURE__ */ jsx37("div", { className: "h-full w-1/3 animate-pulse bg-[var(--primary)]" })
7248
7632
  }
7249
7633
  ) : null,
7250
- /* @__PURE__ */ jsx36("div", { ref: desktopRef, "data-slot": "data-table-desktop", className: "max-lg:hidden lg:block", children: /* @__PURE__ */ jsxs32(
7634
+ /* @__PURE__ */ jsx37("div", { ref: desktopRef, "data-slot": "data-table-desktop", className: "max-lg:hidden lg:block", children: /* @__PURE__ */ jsxs33(
7251
7635
  "div",
7252
7636
  {
7253
7637
  role: "table",
7254
7638
  "aria-label": ariaLabel,
7255
7639
  "aria-rowcount": isVirtual && data.length > 0 ? data.length + 1 : void 0,
7256
7640
  children: [
7257
- /* @__PURE__ */ jsxs32(
7641
+ /* @__PURE__ */ jsxs33(
7258
7642
  "div",
7259
7643
  {
7260
7644
  ref: headerRef,
@@ -7269,12 +7653,12 @@ function DataTableInner({
7269
7653
  ),
7270
7654
  style: { gridTemplateColumns },
7271
7655
  children: [
7272
- selectable ? /* @__PURE__ */ jsx36("div", { role: "columnheader", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx36(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll: toggleAllRows }) }) : null,
7656
+ selectable ? /* @__PURE__ */ jsx37("div", { role: "columnheader", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx37(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll: toggleAllRows }) }) : null,
7273
7657
  columns.map((column) => {
7274
7658
  const align = column.align ?? "left";
7275
7659
  const nextSort = getNextSort(sortBy, column.key);
7276
7660
  const ariaSort = sortBy?.key === column.key ? sortBy.dir === "asc" ? "ascending" : "descending" : void 0;
7277
- return /* @__PURE__ */ jsx36(
7661
+ return /* @__PURE__ */ jsx37(
7278
7662
  "div",
7279
7663
  {
7280
7664
  role: "columnheader",
@@ -7283,7 +7667,7 @@ function DataTableInner({
7283
7667
  "flex min-w-0 items-center gap-[var(--space-1)] px-[var(--space-4)] py-[var(--space-2)]",
7284
7668
  alignmentClass[align]
7285
7669
  ),
7286
- children: column.sortable ? /* @__PURE__ */ jsxs32(
7670
+ children: column.sortable ? /* @__PURE__ */ jsxs33(
7287
7671
  "button",
7288
7672
  {
7289
7673
  type: "button",
@@ -7294,19 +7678,20 @@ function DataTableInner({
7294
7678
  ),
7295
7679
  onClick: () => onSortChange?.(column.key, nextSort),
7296
7680
  children: [
7297
- /* @__PURE__ */ jsx36("span", { className: "truncate", children: column.header }),
7298
- /* @__PURE__ */ jsx36(SortIcon, { sort: sortBy, columnKey: column.key })
7681
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: column.header }),
7682
+ /* @__PURE__ */ jsx37(SortIcon, { sort: sortBy, columnKey: column.key })
7299
7683
  ]
7300
7684
  }
7301
- ) : /* @__PURE__ */ jsx36("span", { className: "truncate", children: column.header })
7685
+ ) : /* @__PURE__ */ jsx37("span", { className: "truncate", children: column.header })
7302
7686
  },
7303
7687
  column.key
7304
7688
  );
7305
- })
7689
+ }),
7690
+ expandable ? /* @__PURE__ */ jsx37("div", { role: "cell" }) : null
7306
7691
  ]
7307
7692
  }
7308
7693
  ),
7309
- loading && data.length === 0 ? /* @__PURE__ */ jsx36(
7694
+ loading && data.length === 0 ? /* @__PURE__ */ jsx37(
7310
7695
  SkeletonRows,
7311
7696
  {
7312
7697
  columns,
@@ -7317,7 +7702,7 @@ function DataTableInner({
7317
7702
  ) : data.length === 0 ? (
7318
7703
  /* role="table" 직계 자식은 row/rowgroup이어야 한다. data-slot과 테두리는
7319
7704
  그대로 유지해 시각 계약을 깨지 않는다(빈 상태에서도 표가 테두리를 그린다). */
7320
- /* @__PURE__ */ jsx36("div", { role: "rowgroup", children: /* @__PURE__ */ jsx36("div", { role: "row", children: /* @__PURE__ */ jsx36(
7705
+ /* @__PURE__ */ jsx37("div", { role: "rowgroup", children: /* @__PURE__ */ jsx37("div", { role: "row", children: /* @__PURE__ */ jsx37(
7321
7706
  "div",
7322
7707
  {
7323
7708
  role: "cell",
@@ -7327,9 +7712,9 @@ function DataTableInner({
7327
7712
  children: emptyState
7328
7713
  }
7329
7714
  ) }) })
7330
- ) : /* @__PURE__ */ jsx36("div", { ref: desktopListRef, role: "rowgroup", style: desktopSlice.style, children: desktopSlice.rows.map((row, index) => {
7331
- const itemProps = getItemProps(row);
7332
- return /* @__PURE__ */ jsx36(
7715
+ ) : /* @__PURE__ */ jsx37("div", { ref: desktopListRef, role: "rowgroup", style: desktopSlice.style, children: desktopSlice.rows.map((row, index) => {
7716
+ const itemProps = getItemProps(row, "desktop", desktopSlice.start + index);
7717
+ return /* @__PURE__ */ jsx37(
7333
7718
  RowComponent,
7334
7719
  {
7335
7720
  ...itemProps,
@@ -7342,8 +7727,8 @@ function DataTableInner({
7342
7727
  ]
7343
7728
  }
7344
7729
  ) }),
7345
- /* @__PURE__ */ jsxs32("div", { ref: mobileRef, "data-slot": "data-table-mobile", className: "lg:hidden", children: [
7346
- /* @__PURE__ */ jsx36(
7730
+ /* @__PURE__ */ jsxs33("div", { ref: mobileRef, "data-slot": "data-table-mobile", className: "lg:hidden", children: [
7731
+ /* @__PURE__ */ jsx37(
7347
7732
  MobileToolbar,
7348
7733
  {
7349
7734
  columns,
@@ -7354,7 +7739,7 @@ function DataTableInner({
7354
7739
  onToggleAll: toggleAllRows
7355
7740
  }
7356
7741
  ),
7357
- loading && data.length === 0 ? /* @__PURE__ */ jsx36(MobileSkeletonCards, { count: skeletonRowCount }) : data.length === 0 ? /* @__PURE__ */ jsx36("div", { "data-slot": "data-table-mobile-empty", className: "border-t border-[var(--border-subtle)] p-[var(--space-4)]", children: emptyState }) : /* @__PURE__ */ jsx36(
7742
+ loading && data.length === 0 ? /* @__PURE__ */ jsx37(MobileSkeletonCards, { count: skeletonRowCount }) : data.length === 0 ? /* @__PURE__ */ jsx37("div", { "data-slot": "data-table-mobile-empty", className: "border-t border-[var(--border-subtle)] p-[var(--space-4)]", children: emptyState }) : /* @__PURE__ */ jsx37(
7358
7743
  "div",
7359
7744
  {
7360
7745
  ref: mobileListRef,
@@ -7363,9 +7748,9 @@ function DataTableInner({
7363
7748
  "aria-label": `${ariaLabel} \uBAA8\uBC14\uC77C \uCE74\uB4DC \uBAA9\uB85D`,
7364
7749
  style: mobileSlice.style,
7365
7750
  children: mobileSlice.rows.map((row, index) => {
7366
- const itemProps = getItemProps(row);
7367
7751
  const rowIndex = mobileSlice.start + index;
7368
- return /* @__PURE__ */ jsx36(
7752
+ const itemProps = getItemProps(row, "mobile", rowIndex);
7753
+ return /* @__PURE__ */ jsx37(
7369
7754
  CardComponent,
7370
7755
  {
7371
7756
  ...itemProps,
@@ -7384,11 +7769,11 @@ function DataTableInner({
7384
7769
  }
7385
7770
  );
7386
7771
  }
7387
- var DataTable = React32.forwardRef(DataTableInner);
7772
+ var DataTable = React33.forwardRef(DataTableInner);
7388
7773
  DataTable.displayName = "DataTable";
7389
7774
 
7390
7775
  // src/components/ui/context-menu.tsx
7391
- import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
7776
+ import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
7392
7777
  function ContextMenu({
7393
7778
  open,
7394
7779
  onOpenChange,
@@ -7399,8 +7784,8 @@ function ContextMenu({
7399
7784
  if (!position) {
7400
7785
  return null;
7401
7786
  }
7402
- return /* @__PURE__ */ jsxs33(DropdownMenu, { open, onOpenChange, modal: false, children: [
7403
- /* @__PURE__ */ jsx37(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx37(
7787
+ return /* @__PURE__ */ jsxs34(DropdownMenu, { open, onOpenChange, modal: false, children: [
7788
+ /* @__PURE__ */ jsx38(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx38(
7404
7789
  "span",
7405
7790
  {
7406
7791
  "aria-hidden": "true",
@@ -7414,19 +7799,19 @@ function ContextMenu({
7414
7799
  }
7415
7800
  }
7416
7801
  ) }),
7417
- /* @__PURE__ */ jsx37(DropdownMenuContent, { ...contentProps, children })
7802
+ /* @__PURE__ */ jsx38(DropdownMenuContent, { ...contentProps, children })
7418
7803
  ] });
7419
7804
  }
7420
7805
 
7421
7806
  // src/components/ui/bulk-action-bar.tsx
7422
- import * as React33 from "react";
7807
+ import * as React34 from "react";
7423
7808
  import { X as X3 } from "lucide-react";
7424
- import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
7809
+ import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
7425
7810
  function ActionButton({ action }) {
7426
7811
  const danger = action.variant === "destructive";
7427
7812
  const off = action.disabled;
7428
7813
  const Icon = action.icon;
7429
- return /* @__PURE__ */ jsxs34(
7814
+ return /* @__PURE__ */ jsxs35(
7430
7815
  "button",
7431
7816
  {
7432
7817
  type: "button",
@@ -7453,7 +7838,7 @@ function ActionButton({ action }) {
7453
7838
  whiteSpace: "nowrap"
7454
7839
  },
7455
7840
  children: [
7456
- Icon ? /* @__PURE__ */ jsx38(
7841
+ Icon ? /* @__PURE__ */ jsx39(
7457
7842
  Icon,
7458
7843
  {
7459
7844
  "aria-hidden": "true",
@@ -7468,7 +7853,7 @@ function ActionButton({ action }) {
7468
7853
  );
7469
7854
  }
7470
7855
  function Divider() {
7471
- return /* @__PURE__ */ jsx38(
7856
+ return /* @__PURE__ */ jsx39(
7472
7857
  "span",
7473
7858
  {
7474
7859
  "aria-hidden": "true",
@@ -7483,7 +7868,7 @@ function Divider() {
7483
7868
  );
7484
7869
  }
7485
7870
  function ClearButton({ onClear }) {
7486
- return /* @__PURE__ */ jsx38(
7871
+ return /* @__PURE__ */ jsx39(
7487
7872
  "button",
7488
7873
  {
7489
7874
  type: "button",
@@ -7505,7 +7890,7 @@ function ClearButton({ onClear }) {
7505
7890
  justifyContent: "center",
7506
7891
  borderRadius: "var(--radius-md)"
7507
7892
  },
7508
- children: /* @__PURE__ */ jsx38(X3, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" })
7893
+ children: /* @__PURE__ */ jsx39(X3, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" })
7509
7894
  }
7510
7895
  );
7511
7896
  }
@@ -7560,10 +7945,10 @@ var idleLineStyle = {
7560
7945
  fontVariantNumeric: "tabular-nums",
7561
7946
  color: "var(--text-secondary)"
7562
7947
  };
7563
- var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React33.useEffect : React33.useLayoutEffect;
7948
+ var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React34.useEffect : React34.useLayoutEffect;
7564
7949
  function useCompactSummary(slot, enabled) {
7565
- const [fullWidth, setFullWidth] = React33.useState(null);
7566
- const measure = React33.useCallback(() => {
7950
+ const [fullWidth, setFullWidth] = React34.useState(null);
7951
+ const measure = React34.useCallback(() => {
7567
7952
  if (!slot) return;
7568
7953
  setFullWidth((prev) => {
7569
7954
  if (prev === null) return slot.scrollWidth > slot.clientWidth ? slot.scrollWidth : null;
@@ -7573,7 +7958,7 @@ function useCompactSummary(slot, enabled) {
7573
7958
  useIsomorphicLayoutEffect2(() => {
7574
7959
  if (enabled) measure();
7575
7960
  });
7576
- React33.useEffect(() => {
7961
+ React34.useEffect(() => {
7577
7962
  if (!enabled || !slot || typeof ResizeObserver === "undefined") return;
7578
7963
  const observer = new ResizeObserver(measure);
7579
7964
  observer.observe(slot);
@@ -7597,7 +7982,7 @@ function BulkActionBar({
7597
7982
  ...props
7598
7983
  }) {
7599
7984
  const inline = placement === "inline";
7600
- const trailingSlot = trailing !== void 0 && trailing !== null ? /* @__PURE__ */ jsx38(
7985
+ const trailingSlot = trailing !== void 0 && trailing !== null ? /* @__PURE__ */ jsx39(
7601
7986
  "div",
7602
7987
  {
7603
7988
  "data-slot": "bulk-action-bar-trailing",
@@ -7610,13 +7995,13 @@ function BulkActionBar({
7610
7995
  children: trailing
7611
7996
  }
7612
7997
  ) : null;
7613
- const [summaryElement, setSummaryElement] = React33.useState(null);
7998
+ const [summaryElement, setSummaryElement] = React34.useState(null);
7614
7999
  const compact = useCompactSummary(
7615
8000
  summaryElement,
7616
8001
  inline && compactSummary !== void 0 && compactSummary !== null
7617
8002
  );
7618
8003
  if (count === 0 && idleContent !== void 0 && trailingSlot) {
7619
- return /* @__PURE__ */ jsxs34(
8004
+ return /* @__PURE__ */ jsxs35(
7620
8005
  "div",
7621
8006
  {
7622
8007
  "data-slot": "bulk-action-bar",
@@ -7626,7 +8011,7 @@ function BulkActionBar({
7626
8011
  style: { ...idleLineStyle, overflow: "visible", ...style },
7627
8012
  ...props,
7628
8013
  children: [
7629
- /* @__PURE__ */ jsx38(
8014
+ /* @__PURE__ */ jsx39(
7630
8015
  "div",
7631
8016
  {
7632
8017
  role: "status",
@@ -7648,7 +8033,7 @@ function BulkActionBar({
7648
8033
  );
7649
8034
  }
7650
8035
  if (count === 0 && idleContent !== void 0) {
7651
- return /* @__PURE__ */ jsx38(
8036
+ return /* @__PURE__ */ jsx39(
7652
8037
  "div",
7653
8038
  {
7654
8039
  role: "status",
@@ -7665,7 +8050,7 @@ function BulkActionBar({
7665
8050
  if (count === 0 && emptyHint === void 0) {
7666
8051
  return null;
7667
8052
  }
7668
- const countLabel = /* @__PURE__ */ jsx38(
8053
+ const countLabel = /* @__PURE__ */ jsx39(
7669
8054
  "span",
7670
8055
  {
7671
8056
  "data-slot": "bulk-action-bar-count",
@@ -7682,7 +8067,7 @@ function BulkActionBar({
7682
8067
  children: count > 0 ? `${count.toLocaleString("ko-KR")}${unit} \uC120\uD0DD\uB428` : emptyHint
7683
8068
  }
7684
8069
  );
7685
- const summarySlot = summary !== void 0 && summary !== null ? /* @__PURE__ */ jsx38(
8070
+ const summarySlot = summary !== void 0 && summary !== null ? /* @__PURE__ */ jsx39(
7686
8071
  "span",
7687
8072
  {
7688
8073
  ref: setSummaryElement,
@@ -7716,7 +8101,7 @@ function BulkActionBar({
7716
8101
  children: compact ? compactSummary : summary
7717
8102
  }
7718
8103
  ) : null;
7719
- const actionGroup = /* @__PURE__ */ jsx38(
8104
+ const actionGroup = /* @__PURE__ */ jsx39(
7720
8105
  "div",
7721
8106
  {
7722
8107
  "data-slot": "bulk-action-bar-actions",
@@ -7728,11 +8113,11 @@ function BulkActionBar({
7728
8113
  justifyContent: "flex-end",
7729
8114
  gap: 2
7730
8115
  },
7731
- children: actions.map((action) => /* @__PURE__ */ jsx38(ActionButton, { action }, action.key))
8116
+ children: actions.map((action) => /* @__PURE__ */ jsx39(ActionButton, { action }, action.key))
7732
8117
  }
7733
8118
  );
7734
8119
  if (inline) {
7735
- return /* @__PURE__ */ jsxs34(
8120
+ return /* @__PURE__ */ jsxs35(
7736
8121
  "div",
7737
8122
  {
7738
8123
  role: "toolbar",
@@ -7743,7 +8128,7 @@ function BulkActionBar({
7743
8128
  style: { ...inlineStyle, ...style },
7744
8129
  ...props,
7745
8130
  children: [
7746
- /* @__PURE__ */ jsxs34(
8131
+ /* @__PURE__ */ jsxs35(
7747
8132
  "div",
7748
8133
  {
7749
8134
  role: "status",
@@ -7761,7 +8146,7 @@ function BulkActionBar({
7761
8146
  ]
7762
8147
  }
7763
8148
  ),
7764
- /* @__PURE__ */ jsxs34(
8149
+ /* @__PURE__ */ jsxs35(
7765
8150
  "div",
7766
8151
  {
7767
8152
  "data-slot": "bulk-action-bar-controls",
@@ -7772,10 +8157,10 @@ function BulkActionBar({
7772
8157
  gap: "var(--space-1)"
7773
8158
  },
7774
8159
  children: [
7775
- count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx38(Divider, {}) : null,
8160
+ count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx39(Divider, {}) : null,
7776
8161
  actionGroup,
7777
- /* @__PURE__ */ jsx38(Divider, {}),
7778
- /* @__PURE__ */ jsx38(ClearButton, { onClear })
8162
+ /* @__PURE__ */ jsx39(Divider, {}),
8163
+ /* @__PURE__ */ jsx39(ClearButton, { onClear })
7779
8164
  ]
7780
8165
  }
7781
8166
  ),
@@ -7784,7 +8169,7 @@ function BulkActionBar({
7784
8169
  }
7785
8170
  );
7786
8171
  }
7787
- return /* @__PURE__ */ jsxs34(
8172
+ return /* @__PURE__ */ jsxs35(
7788
8173
  "div",
7789
8174
  {
7790
8175
  role: "toolbar",
@@ -7799,7 +8184,7 @@ function BulkActionBar({
7799
8184
  style: { ...floatingStyle, ...style },
7800
8185
  ...props,
7801
8186
  children: [
7802
- /* @__PURE__ */ jsxs34(
8187
+ /* @__PURE__ */ jsxs35(
7803
8188
  "div",
7804
8189
  {
7805
8190
  role: "status",
@@ -7816,10 +8201,10 @@ function BulkActionBar({
7816
8201
  ]
7817
8202
  }
7818
8203
  ),
7819
- count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx38(Divider, {}) : null,
8204
+ count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx39(Divider, {}) : null,
7820
8205
  actionGroup,
7821
- /* @__PURE__ */ jsx38(Divider, {}),
7822
- /* @__PURE__ */ jsx38(ClearButton, { onClear }),
8206
+ /* @__PURE__ */ jsx39(Divider, {}),
8207
+ /* @__PURE__ */ jsx39(ClearButton, { onClear }),
7823
8208
  trailingSlot
7824
8209
  ]
7825
8210
  }
@@ -7827,7 +8212,7 @@ function BulkActionBar({
7827
8212
  }
7828
8213
 
7829
8214
  // src/components/ui/confirm-dialog.tsx
7830
- import { jsx as jsx39 } from "react/jsx-runtime";
8215
+ import { jsx as jsx40 } from "react/jsx-runtime";
7831
8216
  function ConfirmDialog({
7832
8217
  open,
7833
8218
  onOpenChange,
@@ -7842,7 +8227,7 @@ function ConfirmDialog({
7842
8227
  confirmDisabled,
7843
8228
  scrim
7844
8229
  }) {
7845
- return /* @__PURE__ */ jsx39(
8230
+ return /* @__PURE__ */ jsx40(
7846
8231
  AlertDialog,
7847
8232
  {
7848
8233
  open,
@@ -7863,14 +8248,14 @@ function ConfirmDialog({
7863
8248
 
7864
8249
  // src/components/ui/separator.tsx
7865
8250
  import { Separator as SeparatorPrimitive } from "radix-ui";
7866
- import { jsx as jsx40 } from "react/jsx-runtime";
8251
+ import { jsx as jsx41 } from "react/jsx-runtime";
7867
8252
  function Separator2({
7868
8253
  className,
7869
8254
  orientation = "horizontal",
7870
8255
  decorative = true,
7871
8256
  ...props
7872
8257
  }) {
7873
- return /* @__PURE__ */ jsx40(
8258
+ return /* @__PURE__ */ jsx41(
7874
8259
  SeparatorPrimitive.Root,
7875
8260
  {
7876
8261
  "data-slot": "separator",
@@ -7887,13 +8272,13 @@ function Separator2({
7887
8272
 
7888
8273
  // src/components/ui/avatar.tsx
7889
8274
  import { Avatar as AvatarPrimitive } from "radix-ui";
7890
- import { jsx as jsx41 } from "react/jsx-runtime";
8275
+ import { jsx as jsx42 } from "react/jsx-runtime";
7891
8276
  function Avatar({
7892
8277
  className,
7893
8278
  size = "md",
7894
8279
  ...props
7895
8280
  }) {
7896
- return /* @__PURE__ */ jsx41(
8281
+ return /* @__PURE__ */ jsx42(
7897
8282
  AvatarPrimitive.Root,
7898
8283
  {
7899
8284
  "data-slot": "avatar",
@@ -7914,7 +8299,7 @@ function AvatarImage({
7914
8299
  className,
7915
8300
  ...props
7916
8301
  }) {
7917
- return /* @__PURE__ */ jsx41(
8302
+ return /* @__PURE__ */ jsx42(
7918
8303
  AvatarPrimitive.Image,
7919
8304
  {
7920
8305
  "data-slot": "avatar-image",
@@ -7939,7 +8324,7 @@ function AvatarFallback({
7939
8324
  ...props
7940
8325
  }) {
7941
8326
  const fallbackText = children ?? (name ? getAvatarFallbackText(name) : null);
7942
- return /* @__PURE__ */ jsx41(
8327
+ return /* @__PURE__ */ jsx42(
7943
8328
  AvatarPrimitive.Fallback,
7944
8329
  {
7945
8330
  "data-slot": "avatar-fallback",
@@ -7958,7 +8343,7 @@ function AvatarFallback({
7958
8343
 
7959
8344
  // src/components/ui/sheet-drawer.tsx
7960
8345
  import { Maximize2Icon, Minimize2Icon } from "lucide-react";
7961
- import { jsx as jsx42, jsxs as jsxs35 } from "react/jsx-runtime";
8346
+ import { jsx as jsx43, jsxs as jsxs36 } from "react/jsx-runtime";
7962
8347
  var expandButtonClassName = cn(
7963
8348
  "inline-flex cursor-pointer items-center justify-center gap-[var(--space-1)]",
7964
8349
  "rounded-[var(--radius-md)] text-text-tertiary transition-colors",
@@ -7993,7 +8378,7 @@ function SheetDrawer({
7993
8378
  const showExpandAction = Boolean(hasExpandedToggle || expandHref || onExpand);
7994
8379
  const resolvedExpandLabel = hasExpandedToggle && expanded ? collapseLabel : expandLabel;
7995
8380
  const ExpandActionIcon = hasExpandedToggle && expanded ? Minimize2Icon : Maximize2Icon;
7996
- const expandAction = showExpandAction ? hasExpandedToggle ? /* @__PURE__ */ jsxs35(
8381
+ const expandAction = showExpandAction ? hasExpandedToggle ? /* @__PURE__ */ jsxs36(
7997
8382
  "button",
7998
8383
  {
7999
8384
  type: "button",
@@ -8004,14 +8389,14 @@ function SheetDrawer({
8004
8389
  className: expandButtonClassName,
8005
8390
  onClick: () => onExpandedChange(!expanded),
8006
8391
  children: [
8007
- /* @__PURE__ */ jsx42(ExpandActionIcon, { className: "size-[16px]" }),
8008
- /* @__PURE__ */ jsx42("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: resolvedExpandLabel })
8392
+ /* @__PURE__ */ jsx43(ExpandActionIcon, { className: "size-[16px]" }),
8393
+ /* @__PURE__ */ jsx43("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: resolvedExpandLabel })
8009
8394
  ]
8010
8395
  }
8011
- ) : expandHref ? /* @__PURE__ */ jsxs35("a", { href: expandHref, "aria-label": expandLabel, "data-slot": "sheet-drawer-expand", className: expandButtonClassName, children: [
8012
- /* @__PURE__ */ jsx42(ExpandActionIcon, { className: "size-[16px]" }),
8013
- /* @__PURE__ */ jsx42("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: expandLabel })
8014
- ] }) : /* @__PURE__ */ jsxs35(
8396
+ ) : expandHref ? /* @__PURE__ */ jsxs36("a", { href: expandHref, "aria-label": expandLabel, "data-slot": "sheet-drawer-expand", className: expandButtonClassName, children: [
8397
+ /* @__PURE__ */ jsx43(ExpandActionIcon, { className: "size-[16px]" }),
8398
+ /* @__PURE__ */ jsx43("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: expandLabel })
8399
+ ] }) : /* @__PURE__ */ jsxs36(
8015
8400
  "button",
8016
8401
  {
8017
8402
  type: "button",
@@ -8020,12 +8405,12 @@ function SheetDrawer({
8020
8405
  className: expandButtonClassName,
8021
8406
  onClick: onExpand,
8022
8407
  children: [
8023
- /* @__PURE__ */ jsx42(ExpandActionIcon, { className: "size-[16px]" }),
8024
- /* @__PURE__ */ jsx42("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: expandLabel })
8408
+ /* @__PURE__ */ jsx43(ExpandActionIcon, { className: "size-[16px]" }),
8409
+ /* @__PURE__ */ jsx43("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: expandLabel })
8025
8410
  ]
8026
8411
  }
8027
8412
  ) : void 0;
8028
- return /* @__PURE__ */ jsx42(
8413
+ return /* @__PURE__ */ jsx43(
8029
8414
  Sheet,
8030
8415
  {
8031
8416
  open,
@@ -8043,210 +8428,6 @@ function SheetDrawer({
8043
8428
  );
8044
8429
  }
8045
8430
 
8046
- // src/components/ui/action-menu.tsx
8047
- import * as React34 from "react";
8048
- import { Dialog as DialogPrimitive4, Slot as Slot3 } from "radix-ui";
8049
- import { Fragment as Fragment14, jsx as jsx43, jsxs as jsxs36 } from "react/jsx-runtime";
8050
- var sheetRowClassName = cn(
8051
- "group flex min-h-12 w-full cursor-pointer items-center gap-[var(--space-3)] px-[var(--space-4)] py-[var(--space-2)] text-left",
8052
- "border-t border-[var(--border-subtle)] text-[13px] font-medium leading-normal text-text-primary",
8053
- "transition-colors motion-reduce:transition-none hover:bg-[var(--action-hover)]",
8054
- "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--focus-ring)]",
8055
- "enabled:data-[destructive]:text-[var(--semantic-error-fg)]",
8056
- "disabled:cursor-not-allowed disabled:bg-[var(--action-disabled-bg)] disabled:text-text-disabled"
8057
- );
8058
- var sheetRowDescriptionClassName = "block text-[12px] font-normal text-text-secondary group-disabled:text-text-disabled";
8059
- var sheetGroupLabelClassName = "px-[var(--space-4)] pt-[var(--space-3)] pb-[var(--space-2)] text-[12px] font-semibold leading-normal text-text-tertiary";
8060
- var sheetGroupSeparatorClassName = "h-[var(--space-2)] bg-[var(--bg-inset)]";
8061
- function ActionMenuSheet({
8062
- open,
8063
- onOpenChange,
8064
- title,
8065
- description,
8066
- closeLabel,
8067
- groups,
8068
- onOpenAutoFocus,
8069
- onCloseAutoFocus
8070
- }) {
8071
- const pendingRef = React34.useRef(null);
8072
- const surfaceRef = React34.useRef(null);
8073
- const labelId = React34.useId();
8074
- const handleOpenChange = (nextOpen) => {
8075
- pendingRef.current = null;
8076
- onOpenChange(nextOpen);
8077
- };
8078
- const swipe = useSwipeDismiss({
8079
- enabled: OVERLAY_POLICY.menu.swipe,
8080
- onDismiss: () => handleOpenChange(false),
8081
- surfaceRef,
8082
- always: true
8083
- });
8084
- const handleSelect = (item) => {
8085
- onOpenChange(false);
8086
- pendingRef.current = item;
8087
- };
8088
- const handleOpenAutoFocus = (event) => {
8089
- onOpenAutoFocus?.(event);
8090
- const firstRow = surfaceRef.current?.querySelector('[data-slot="action-menu-item"]:enabled');
8091
- if (!firstRow) return;
8092
- event.preventDefault();
8093
- firstRow.focus();
8094
- };
8095
- const handleCloseAutoFocus = (event) => {
8096
- onCloseAutoFocus(event);
8097
- const item = pendingRef.current;
8098
- pendingRef.current = null;
8099
- item?.onSelect();
8100
- };
8101
- return /* @__PURE__ */ jsx43(DialogPrimitive4.Root, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs36(DialogPrimitive4.Portal, { children: [
8102
- /* @__PURE__ */ jsx43(OverlayScrimLayer, { kind: "menu" }),
8103
- /* @__PURE__ */ jsxs36(
8104
- DialogPrimitive4.Content,
8105
- {
8106
- ref: surfaceRef,
8107
- "data-slot": "action-menu-sheet",
8108
- className: overlayBoxClassName("menu"),
8109
- onOpenAutoFocus: handleOpenAutoFocus,
8110
- onCloseAutoFocus: handleCloseAutoFocus,
8111
- ...description ? {} : { "aria-describedby": void 0 },
8112
- children: [
8113
- /* @__PURE__ */ jsx43(OverlayGrabber, { always: true, ...swipe.handleProps }),
8114
- /* @__PURE__ */ jsx43(
8115
- OverlayHeader,
8116
- {
8117
- kind: "menu",
8118
- title,
8119
- description,
8120
- closeLabel,
8121
- dragHandleProps: swipe.handleProps
8122
- }
8123
- ),
8124
- /* @__PURE__ */ jsx43(OverlayBody, { kind: "menu", children: groups.map((group, index) => /* @__PURE__ */ jsxs36(React34.Fragment, { children: [
8125
- index > 0 ? /* @__PURE__ */ jsx43("div", { role: "separator", className: sheetGroupSeparatorClassName }) : null,
8126
- /* @__PURE__ */ jsxs36("div", { role: "group", "aria-labelledby": group.label ? `${labelId}-${index}` : void 0, children: [
8127
- group.label ? /* @__PURE__ */ jsx43("div", { id: `${labelId}-${index}`, className: sheetGroupLabelClassName, children: group.label }) : null,
8128
- group.items.map((item) => {
8129
- const Icon = item.icon;
8130
- return /* @__PURE__ */ jsxs36(
8131
- "button",
8132
- {
8133
- type: "button",
8134
- "data-slot": "action-menu-item",
8135
- "data-destructive": item.destructive ? "" : void 0,
8136
- className: sheetRowClassName,
8137
- disabled: item.disabled,
8138
- onClick: () => handleSelect(item),
8139
- children: [
8140
- Icon ? /* @__PURE__ */ jsx43(Icon, { "aria-hidden": true, size: 17, strokeWidth: 1.75, className: "shrink-0" }) : null,
8141
- /* @__PURE__ */ jsxs36("span", { className: "min-w-0 flex-1 break-keep", children: [
8142
- item.label,
8143
- item.description ? /* @__PURE__ */ jsx43("span", { className: sheetRowDescriptionClassName, children: item.description }) : null
8144
- ] })
8145
- ]
8146
- },
8147
- item.id
8148
- );
8149
- })
8150
- ] })
8151
- ] }, group.id)) })
8152
- ]
8153
- }
8154
- )
8155
- ] }) });
8156
- }
8157
- var readPresentation = () => window.matchMedia?.(OVERLAY_DESKTOP_QUERY).matches ?? true ? "dropdown" : "sheet";
8158
- var subscribeNothing = () => () => void 0;
8159
- var useHydrated = () => React34.useSyncExternalStore(
8160
- subscribeNothing,
8161
- () => true,
8162
- () => false
8163
- );
8164
- function ActionMenu({
8165
- trigger,
8166
- title,
8167
- description,
8168
- open: openProp,
8169
- onOpenChange,
8170
- closeLabel,
8171
- items,
8172
- groups
8173
- }) {
8174
- const [uncontrolledOpen, setUncontrolledOpen] = React34.useState(false);
8175
- const hydrated = useHydrated();
8176
- const open = (openProp ?? uncontrolledOpen) && hydrated;
8177
- const [shown, setShown] = React34.useState({
8178
- open: false,
8179
- presentation: "dropdown"
8180
- });
8181
- let presentation = shown.presentation;
8182
- if (shown.open !== open) {
8183
- if (open) presentation = readPresentation();
8184
- setShown({ open, presentation });
8185
- }
8186
- const triggerRef = React34.useRef(null);
8187
- const pendingRef = React34.useRef(null);
8188
- const setOpen = (nextOpen) => {
8189
- if (nextOpen) pendingRef.current = null;
8190
- if (openProp === void 0) setUncontrolledOpen(nextOpen);
8191
- onOpenChange?.(nextOpen);
8192
- };
8193
- const menuGroups = groups ?? [{ id: "items", items: items ?? [] }];
8194
- const handleDropdownCloseAutoFocus = (event) => {
8195
- const item = pendingRef.current;
8196
- pendingRef.current = null;
8197
- if (!item) return;
8198
- event.preventDefault();
8199
- triggerRef.current?.focus();
8200
- item.onSelect();
8201
- };
8202
- const handleSheetCloseAutoFocus = (event) => {
8203
- event.preventDefault();
8204
- triggerRef.current?.focus();
8205
- };
8206
- const triggerLabel = trigger.props["aria-label"];
8207
- return /* @__PURE__ */ jsxs36(Fragment14, { children: [
8208
- /* @__PURE__ */ jsxs36(DropdownMenu, { open: open && presentation === "dropdown", onOpenChange: setOpen, children: [
8209
- /* @__PURE__ */ jsx43(DropdownMenuTrigger, { asChild: true, "aria-expanded": open, children: /* @__PURE__ */ jsx43(Slot3.Root, { ref: triggerRef, children: trigger }) }),
8210
- /* @__PURE__ */ jsx43(DropdownMenuContent, { align: "end", onCloseAutoFocus: handleDropdownCloseAutoFocus, children: menuGroups.map((group, index) => /* @__PURE__ */ jsxs36(React34.Fragment, { children: [
8211
- index > 0 ? /* @__PURE__ */ jsx43(DropdownMenuSeparator, {}) : null,
8212
- /* @__PURE__ */ jsxs36(DropdownMenuGroup, { children: [
8213
- group.label ? /* @__PURE__ */ jsx43(DropdownMenuLabel, { children: group.label }) : null,
8214
- group.items.map((item) => {
8215
- const Icon = item.icon;
8216
- return /* @__PURE__ */ jsxs36(
8217
- DropdownMenuItem,
8218
- {
8219
- variant: item.destructive ? "destructive" : "default",
8220
- disabled: item.disabled,
8221
- onSelect: () => {
8222
- pendingRef.current = item;
8223
- },
8224
- children: [
8225
- Icon ? /* @__PURE__ */ jsx43(Icon, { "aria-hidden": true, size: 16, strokeWidth: 1.75 }) : null,
8226
- item.label
8227
- ]
8228
- },
8229
- item.id
8230
- );
8231
- })
8232
- ] })
8233
- ] }, group.id)) })
8234
- ] }),
8235
- /* @__PURE__ */ jsx43(
8236
- ActionMenuSheet,
8237
- {
8238
- open: open && presentation === "sheet",
8239
- onOpenChange: setOpen,
8240
- title: title ?? /* @__PURE__ */ jsx43("span", { className: "sr-only", children: triggerLabel }),
8241
- description,
8242
- closeLabel,
8243
- groups: menuGroups,
8244
- onCloseAutoFocus: handleSheetCloseAutoFocus
8245
- }
8246
- )
8247
- ] });
8248
- }
8249
-
8250
8431
  // src/components/ui/action-sheet.tsx
8251
8432
  import { jsx as jsx44 } from "react/jsx-runtime";
8252
8433
  function ActionSheet({
@@ -8277,7 +8458,7 @@ function ActionSheet({
8277
8458
  import * as React35 from "react";
8278
8459
  import { jsx as jsx45 } from "react/jsx-runtime";
8279
8460
  var TONE = {
8280
- neutral: "bg-[var(--semantic-neutral-bg)] text-[var(--semantic-neutral-fg)]",
8461
+ neutral: "bg-[var(--fill-on-bg,var(--semantic-neutral-bg))] text-[var(--semantic-neutral-fg)]",
8281
8462
  info: "bg-[var(--semantic-info-bg)] text-[var(--semantic-info-fg)]",
8282
8463
  success: "bg-[var(--semantic-success-bg)] text-[var(--semantic-success-fg)]",
8283
8464
  warning: "bg-[var(--semantic-warning-bg)] text-[var(--semantic-warning-fg)]",
@@ -8315,7 +8496,8 @@ var FG = {
8315
8496
  error: "var(--semantic-error-fg)"
8316
8497
  };
8317
8498
  var BG = {
8318
- neutral: "var(--bg-inset)",
8499
+ // takes --fill-on-bg when an inset background sets it (see surface.ts)
8500
+ neutral: "var(--fill-on-bg, var(--bg-inset))",
8319
8501
  info: "var(--semantic-info-bg)",
8320
8502
  success: "var(--semantic-success-bg)",
8321
8503
  warning: "var(--semantic-warning-bg)",
@@ -8384,7 +8566,7 @@ var TwoTierBadge = React36.forwardRef(
8384
8566
  style: {
8385
8567
  borderLeft: `1px solid ${divider}`,
8386
8568
  color: "var(--text-tertiary)",
8387
- background: strong ? "var(--bg-inset)" : "transparent"
8569
+ background: strong ? BG.neutral : "transparent"
8388
8570
  },
8389
8571
  children: secondary
8390
8572
  }
@@ -8458,9 +8640,9 @@ StatusDot.displayName = "StatusDot";
8458
8640
 
8459
8641
  // src/components/ui/notification-badge.tsx
8460
8642
  import * as React39 from "react";
8461
- import { cva as cva13 } from "class-variance-authority";
8643
+ import { cva as cva14 } from "class-variance-authority";
8462
8644
  import { jsx as jsx49 } from "react/jsx-runtime";
8463
- var notificationBadgeVariants = cva13(
8645
+ var notificationBadgeVariants = cva14(
8464
8646
  [
8465
8647
  "inline-flex shrink-0 items-center justify-center rounded-[var(--radius-full)]",
8466
8648
  "bg-[var(--semantic-error,var(--error))] text-[var(--error-contrast)]",
@@ -8524,9 +8706,9 @@ NotificationBadge.displayName = "NotificationBadge";
8524
8706
 
8525
8707
  // src/components/ui/empty-state.tsx
8526
8708
  import * as React40 from "react";
8527
- import { cva as cva14 } from "class-variance-authority";
8709
+ import { cva as cva15 } from "class-variance-authority";
8528
8710
  import { jsx as jsx50, jsxs as jsxs39 } from "react/jsx-runtime";
8529
- var emptyStateBaseVariants = cva14(
8711
+ var emptyStateBaseVariants = cva15(
8530
8712
  [
8531
8713
  "flex flex-col items-center justify-center text-center",
8532
8714
  "text-foreground"
@@ -8539,16 +8721,82 @@ var emptyStateBaseVariants = cva14(
8539
8721
  lg: "gap-[var(--space-4)] px-[var(--space-8)] py-[var(--space-12)]"
8540
8722
  },
8541
8723
  bordered: {
8542
- true: "rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
8724
+ true: "mx-auto w-full max-w-[560px] rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
8543
8725
  false: ""
8544
8726
  }
8545
8727
  },
8728
+ compoundVariants: [{ bordered: true, size: "md", className: "min-h-60" }],
8546
8729
  defaultVariants: {
8547
8730
  size: "md",
8548
8731
  bordered: false
8549
8732
  }
8550
8733
  }
8551
8734
  );
8735
+ var PAGE_FILL_QUERY = "(min-width: 768px)";
8736
+ var useIsomorphicLayoutEffect3 = typeof window === "undefined" ? React40.useEffect : React40.useLayoutEffect;
8737
+ function findScrollParent(node) {
8738
+ for (let el = node.parentElement; el && el !== document.body && el !== document.documentElement; el = el.parentElement) {
8739
+ const { overflowY } = getComputedStyle(el);
8740
+ if (overflowY === "auto" || overflowY === "scroll") return el;
8741
+ }
8742
+ return null;
8743
+ }
8744
+ function freeHeight(area) {
8745
+ const rect = area.getBoundingClientRect();
8746
+ const style = getComputedStyle(area);
8747
+ const start = area === document.documentElement ? rect.top : rect.top + area.clientTop - area.scrollTop;
8748
+ let end = start + parseFloat(style.paddingTop);
8749
+ for (const child of Array.from(area.children)) {
8750
+ const childStyle = getComputedStyle(child);
8751
+ if (childStyle.display === "none" || childStyle.position === "absolute" || childStyle.position === "fixed") continue;
8752
+ end = Math.max(end, child.getBoundingClientRect().bottom + parseFloat(childStyle.marginBottom));
8753
+ }
8754
+ return area.clientHeight - (end - start + parseFloat(style.paddingBottom));
8755
+ }
8756
+ function usePageFill(ref, enabled) {
8757
+ useIsomorphicLayoutEffect3(() => {
8758
+ const node = ref.current;
8759
+ if (!enabled || !node) return;
8760
+ const scroller = findScrollParent(node);
8761
+ const parent = node.parentElement;
8762
+ const media = typeof window.matchMedia === "function" ? window.matchMedia(PAGE_FILL_QUERY) : null;
8763
+ let observer = null;
8764
+ let frame = 0;
8765
+ const fit = () => {
8766
+ const previous = node.style.minHeight;
8767
+ let next = "";
8768
+ if (media?.matches ?? true) {
8769
+ node.style.minHeight = "";
8770
+ const free = freeHeight(scroller ?? document.scrollingElement ?? document.documentElement);
8771
+ if (free > 0) next = `${Math.floor(node.getBoundingClientRect().height + free)}px`;
8772
+ }
8773
+ node.style.minHeight = next;
8774
+ if (next !== previous && observer && parent && !frame) {
8775
+ observer.unobserve(parent);
8776
+ frame = requestAnimationFrame(() => {
8777
+ frame = 0;
8778
+ observer?.observe(parent);
8779
+ });
8780
+ }
8781
+ };
8782
+ fit();
8783
+ if (typeof ResizeObserver === "function") {
8784
+ observer = new ResizeObserver(fit);
8785
+ if (scroller) observer.observe(scroller);
8786
+ if (parent) observer.observe(parent);
8787
+ }
8788
+ if (!scroller) window.addEventListener("resize", fit);
8789
+ media?.addEventListener?.("change", fit);
8790
+ return () => {
8791
+ observer?.disconnect();
8792
+ observer = null;
8793
+ cancelAnimationFrame(frame);
8794
+ window.removeEventListener("resize", fit);
8795
+ media?.removeEventListener?.("change", fit);
8796
+ node.style.minHeight = "";
8797
+ };
8798
+ }, [enabled]);
8799
+ }
8552
8800
  function getEmptyStateToneSurface(tone) {
8553
8801
  switch (tone) {
8554
8802
  case "muted":
@@ -8574,7 +8822,7 @@ function emptyStateVariants({
8574
8822
  className
8575
8823
  );
8576
8824
  }
8577
- var emptyStateIconVariants = cva14(
8825
+ var emptyStateIconVariants = cva15(
8578
8826
  [
8579
8827
  "inline-flex items-center justify-center rounded-[var(--radius-full)]",
8580
8828
  "border border-[var(--border-subtle)] bg-[var(--bg-inset)] text-text-tertiary"
@@ -8592,7 +8840,7 @@ var emptyStateIconVariants = cva14(
8592
8840
  }
8593
8841
  }
8594
8842
  );
8595
- var iconSize3 = {
8843
+ var iconSize2 = {
8596
8844
  sm: 18,
8597
8845
  md: 20,
8598
8846
  lg: 24
@@ -8609,10 +8857,13 @@ var EmptyState = React40.forwardRef(
8609
8857
  hint,
8610
8858
  action,
8611
8859
  bordered = false,
8860
+ layout = "inline",
8612
8861
  ...props
8613
8862
  }, ref) => {
8614
8863
  const resolvedSize = size ?? "md";
8615
- return /* @__PURE__ */ jsxs39(
8864
+ const pageRef = React40.useRef(null);
8865
+ usePageFill(pageRef, layout === "page");
8866
+ const box = /* @__PURE__ */ jsxs39(
8616
8867
  "div",
8617
8868
  {
8618
8869
  ref,
@@ -8627,7 +8878,7 @@ var EmptyState = React40.forwardRef(
8627
8878
  "aria-hidden": "true",
8628
8879
  "data-slot": "empty-state-icon",
8629
8880
  className: emptyStateIconVariants({ size: resolvedSize }),
8630
- children: /* @__PURE__ */ jsx50(Icon, { size: iconSize3[resolvedSize], strokeWidth: 1.75 })
8881
+ children: /* @__PURE__ */ jsx50(Icon, { size: iconSize2[resolvedSize], strokeWidth: 1.75 })
8631
8882
  }
8632
8883
  ) : null,
8633
8884
  /* @__PURE__ */ jsxs39("div", { className: "flex max-w-[420px] flex-col items-center gap-[var(--space-2)]", children: [
@@ -8660,6 +8911,17 @@ var EmptyState = React40.forwardRef(
8660
8911
  ]
8661
8912
  }
8662
8913
  );
8914
+ if (layout !== "page") return box;
8915
+ return /* @__PURE__ */ jsx50(
8916
+ "div",
8917
+ {
8918
+ ref: pageRef,
8919
+ "data-slot": "empty-state-page",
8920
+ "data-layout": "page",
8921
+ className: "flex w-full flex-col justify-start pt-[var(--space-12)] md:justify-center md:pt-0",
8922
+ children: box
8923
+ }
8924
+ );
8663
8925
  }
8664
8926
  );
8665
8927
  EmptyState.displayName = "EmptyState";
@@ -8667,9 +8929,9 @@ EmptyState.displayName = "EmptyState";
8667
8929
  // src/components/ui/error-state.tsx
8668
8930
  import * as React41 from "react";
8669
8931
  import { AlertTriangle } from "lucide-react";
8670
- import { cva as cva15 } from "class-variance-authority";
8932
+ import { cva as cva16 } from "class-variance-authority";
8671
8933
  import { jsx as jsx51, jsxs as jsxs40 } from "react/jsx-runtime";
8672
- var errorStateVariants = cva15(
8934
+ var errorStateVariants = cva16(
8673
8935
  [
8674
8936
  "flex flex-col items-center justify-center text-center",
8675
8937
  "rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
@@ -8745,7 +9007,7 @@ var ErrorState = React41.forwardRef(
8745
9007
  }
8746
9008
  ) : null
8747
9009
  ] }),
8748
- onRetry ? /* @__PURE__ */ jsx51(Button, { size: "sm", variant: "secondary", onClick: onRetry, children: retryLabel }) : null
9010
+ onRetry ? /* @__PURE__ */ jsx51(Button, { size: "sm", appearance: "outline", tone: "neutral", onClick: onRetry, children: retryLabel }) : null
8749
9011
  ]
8750
9012
  }
8751
9013
  )
@@ -8754,9 +9016,9 @@ ErrorState.displayName = "ErrorState";
8754
9016
 
8755
9017
  // src/components/ui/skeleton.tsx
8756
9018
  import * as React42 from "react";
8757
- import { cva as cva16 } from "class-variance-authority";
9019
+ import { cva as cva17 } from "class-variance-authority";
8758
9020
  import { jsx as jsx52 } from "react/jsx-runtime";
8759
- var skeletonVariants = cva16(
9021
+ var skeletonVariants = cva17(
8760
9022
  [
8761
9023
  // bg-inset: light #F1F2F4 reads on white surfaces (bg-raised was white = invisible);
8762
9024
  // dark value equals the old bg-raised (#16181D), so dark mode is unchanged.
@@ -8776,7 +9038,7 @@ var skeletonVariants = cva16(
8776
9038
  }
8777
9039
  }
8778
9040
  );
8779
- var spinnerVariants = cva16(
9041
+ var spinnerVariants = cva17(
8780
9042
  [
8781
9043
  "inline-block shrink-0 animate-spin rounded-[var(--radius-full)] border-2",
8782
9044
  "border-[var(--border-subtle)] border-t-[var(--primary)]",
@@ -8907,8 +9169,8 @@ Spinner.displayName = "Spinner";
8907
9169
 
8908
9170
  // src/components/ui/pagination.tsx
8909
9171
  import * as React43 from "react";
8910
- import { ChevronsLeft, ChevronLeft, ChevronRight as ChevronRight3, ChevronsRight } from "lucide-react";
8911
- import { cva as cva17 } from "class-variance-authority";
9172
+ import { ChevronsLeft, ChevronLeft, ChevronRight as ChevronRight4, ChevronsRight } from "lucide-react";
9173
+ import { cva as cva18 } from "class-variance-authority";
8912
9174
 
8913
9175
  // src/components/ui/page-size-select.tsx
8914
9176
  import { jsx as jsx53, jsxs as jsxs41 } from "react/jsx-runtime";
@@ -8963,7 +9225,7 @@ function PageSizeSelect({
8963
9225
 
8964
9226
  // src/components/ui/pagination.tsx
8965
9227
  import { jsx as jsx54, jsxs as jsxs42 } from "react/jsx-runtime";
8966
- var paginationVariants = cva17(
9228
+ var paginationVariants = cva18(
8967
9229
  [
8968
9230
  "flex w-full flex-col gap-[var(--space-3)]",
8969
9231
  "text-sm text-text-secondary",
@@ -8981,7 +9243,7 @@ var paginationVariants = cva17(
8981
9243
  }
8982
9244
  }
8983
9245
  );
8984
- var paginationControlVariants = cva17(
9246
+ var paginationControlVariants = cva18(
8985
9247
  [
8986
9248
  "inline-flex shrink-0 items-center justify-center rounded-[var(--radius-md)] border",
8987
9249
  "border-transparent bg-transparent font-medium text-text-secondary",
@@ -9158,7 +9420,7 @@ var Pagination = React43.forwardRef(
9158
9420
  page: Math.min(pageCount, currentPage + 1),
9159
9421
  disabled: isLastPage,
9160
9422
  size: resolvedSize,
9161
- icon: ChevronRight3,
9423
+ icon: ChevronRight4,
9162
9424
  onPageChange
9163
9425
  }
9164
9426
  ),
@@ -9184,15 +9446,16 @@ var Pagination = React43.forwardRef(
9184
9446
  Pagination.displayName = "Pagination";
9185
9447
 
9186
9448
  // src/components/ui/mode-toggle.tsx
9187
- import { cva as cva18 } from "class-variance-authority";
9449
+ import { cva as cva19 } from "class-variance-authority";
9188
9450
  import { jsx as jsx55, jsxs as jsxs43 } from "react/jsx-runtime";
9189
- var modeToggleVariants = cva18(
9451
+ var modeToggleVariants = cva19(
9190
9452
  [
9191
9453
  "inline-flex items-center rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
9192
- "bg-[var(--bg-inset)] p-[2px]"
9454
+ "bg-[var(--bg-inset)] p-[2px]",
9455
+ insetMarkerContext
9193
9456
  ].join(" ")
9194
9457
  );
9195
- var modeToggleItemVariants = cva18(
9458
+ var modeToggleItemVariants = cva19(
9196
9459
  [
9197
9460
  "inline-flex min-h-[28px] cursor-pointer items-center justify-center gap-[var(--space-1)]",
9198
9461
  "rounded-[calc(var(--radius-md)_-_2px)] px-[var(--space-3)] py-[var(--space-1)]",
@@ -9254,9 +9517,9 @@ function ModeToggle({
9254
9517
 
9255
9518
  // src/components/ui/action-footer.tsx
9256
9519
  import * as React44 from "react";
9257
- import { cva as cva19 } from "class-variance-authority";
9520
+ import { cva as cva20 } from "class-variance-authority";
9258
9521
  import { jsx as jsx56, jsxs as jsxs44 } from "react/jsx-runtime";
9259
- var actionFooterVariants = cva19(
9522
+ var actionFooterVariants = cva20(
9260
9523
  [
9261
9524
  // Below sm: two fixed rows — destructive actions (start) and status (end) on top, the main
9262
9525
  // actions filling the bottom row. The top row is omitted when both are absent. From sm: one
@@ -9281,7 +9544,7 @@ var actionFooterVariants = cva19(
9281
9544
  }
9282
9545
  }
9283
9546
  );
9284
- var actionFooterStatusVariants = cva19(
9547
+ var actionFooterStatusVariants = cva20(
9285
9548
  [
9286
9549
  "col-start-2 flex min-w-0 items-center justify-self-end gap-[var(--space-2)]",
9287
9550
  "sm:ml-auto",
@@ -9300,8 +9563,9 @@ var actionFooterStatusVariants = cva19(
9300
9563
  }
9301
9564
  }
9302
9565
  );
9303
- var destructiveVariants = /* @__PURE__ */ new Set(["danger", "destructive", "emergency"]);
9304
- var primaryVariants = /* @__PURE__ */ new Set(["default", "primary"]);
9566
+ var actionStyle = (action) => resolveActionStyle(action.appearance, action.tone, "filled");
9567
+ var isDestructive = (action) => actionStyle(action).tone === "danger";
9568
+ var isPrimary = (action) => actionStyle(action).tone === "primary";
9305
9569
  function canRenderAction(action, permissions) {
9306
9570
  if (!action.permission) {
9307
9571
  return true;
@@ -9313,8 +9577,8 @@ function canRenderAction(action, permissions) {
9313
9577
  }
9314
9578
  function sortMainActions(actions) {
9315
9579
  return [...actions].sort((first, second) => {
9316
- const firstRank = primaryVariants.has(first.variant ?? "default") ? 1 : 0;
9317
- const secondRank = primaryVariants.has(second.variant ?? "default") ? 1 : 0;
9580
+ const firstRank = isPrimary(first) ? 1 : 0;
9581
+ const secondRank = isPrimary(second) ? 1 : 0;
9318
9582
  return firstRank - secondRank;
9319
9583
  });
9320
9584
  }
@@ -9330,20 +9594,28 @@ function getStatusLabel(status) {
9330
9594
  }
9331
9595
  }
9332
9596
  function renderAction(action, className) {
9333
- return /* @__PURE__ */ jsx56(
9334
- Button,
9335
- {
9336
- variant: action.variant,
9337
- size: "lg",
9338
- className: cn(footerButtonHitAreaClassName, className),
9339
- disabled: action.disabled,
9340
- loading: action.loading,
9341
- leadingIcon: action.leadingIcon,
9342
- onClick: action.onClick,
9343
- children: action.label
9344
- },
9345
- action.id ?? action.label
9346
- );
9597
+ const key = action.id ?? action.label;
9598
+ const common = {
9599
+ className: cn(footerButtonHitAreaClassName, className),
9600
+ disabled: action.disabled,
9601
+ onClick: action.onClick
9602
+ };
9603
+ const style = actionStyle(action);
9604
+ if (action.leadingIcon) {
9605
+ return /* @__PURE__ */ jsx56(
9606
+ IconButton,
9607
+ {
9608
+ ...common,
9609
+ ...style,
9610
+ size: "lg",
9611
+ icon: action.leadingIcon,
9612
+ label: action.label,
9613
+ loading: action.loading
9614
+ },
9615
+ key
9616
+ );
9617
+ }
9618
+ return /* @__PURE__ */ jsx56(Button, { ...common, ...style, size: "lg", loading: action.loading, children: action.label }, key);
9347
9619
  }
9348
9620
  var ActionFooter = React44.forwardRef(
9349
9621
  ({
@@ -9356,12 +9628,8 @@ var ActionFooter = React44.forwardRef(
9356
9628
  ...props
9357
9629
  }, ref) => {
9358
9630
  const visibleActions = actions.filter((action) => canRenderAction(action, permissions));
9359
- const destructiveActions = visibleActions.filter(
9360
- (action) => destructiveVariants.has(action.variant ?? "default")
9361
- );
9362
- const mainActions = sortMainActions(
9363
- visibleActions.filter((action) => !destructiveVariants.has(action.variant ?? "default"))
9364
- );
9631
+ const destructiveActions = visibleActions.filter(isDestructive);
9632
+ const mainActions = sortMainActions(visibleActions.filter((action) => !isDestructive(action)));
9365
9633
  return /* @__PURE__ */ jsxs44(
9366
9634
  "div",
9367
9635
  {
@@ -9420,7 +9688,7 @@ ActionFooter.displayName = "ActionFooter";
9420
9688
 
9421
9689
  // src/components/ui/toast.tsx
9422
9690
  import * as React45 from "react";
9423
- import { cva as cva20 } from "class-variance-authority";
9691
+ import { cva as cva21 } from "class-variance-authority";
9424
9692
  import { jsx as jsx57, jsxs as jsxs45 } from "react/jsx-runtime";
9425
9693
  var DOT3 = {
9426
9694
  default: "var(--neutral)",
@@ -9429,7 +9697,7 @@ var DOT3 = {
9429
9697
  info: "var(--info)",
9430
9698
  error: "var(--error)"
9431
9699
  };
9432
- var toastVariants = cva20(
9700
+ var toastVariants = cva21(
9433
9701
  [
9434
9702
  "flex min-w-[280px] max-w-[420px] items-center",
9435
9703
  "gap-[11px] rounded-[10px] border border-[var(--border)]",
@@ -9451,7 +9719,7 @@ var toastVariants = cva20(
9451
9719
  defaultVariants: { variant: "default" }
9452
9720
  }
9453
9721
  );
9454
- var toastViewportVariants = cva20(
9722
+ var toastViewportVariants = cva21(
9455
9723
  [
9456
9724
  "fixed bottom-[var(--space-6)] right-[var(--space-6)] z-[var(--z-toast,50)]",
9457
9725
  "flex w-[min(420px,calc(100vw-var(--space-12)))] list-none flex-col gap-[var(--space-2)]",
@@ -9629,7 +9897,8 @@ var ToastRoot = React45.forwardRef(
9629
9897
  {
9630
9898
  "data-slot": "toast-action",
9631
9899
  size: "xs",
9632
- variant: "secondary",
9900
+ appearance: "outline",
9901
+ tone: "neutral",
9633
9902
  onClick: action.onClick,
9634
9903
  children: action.label
9635
9904
  }
@@ -9682,10 +9951,10 @@ function ToastProvider({ children, maxToasts = 3, className, ...props }) {
9682
9951
 
9683
9952
  // src/components/ui/otp-field.tsx
9684
9953
  import * as React46 from "react";
9685
- import { cva as cva21 } from "class-variance-authority";
9954
+ import { cva as cva22 } from "class-variance-authority";
9686
9955
  import { AlertCircle as AlertCircle4 } from "lucide-react";
9687
- import { Fragment as Fragment15, jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
9688
- var otpFieldVariants = cva21("flex w-full min-w-0 flex-col gap-[var(--space-3)]", {
9956
+ import { Fragment as Fragment16, jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
9957
+ var otpFieldVariants = cva22("flex w-full min-w-0 flex-col gap-[var(--space-3)]", {
9689
9958
  variants: {
9690
9959
  size: {
9691
9960
  default: "",
@@ -9696,7 +9965,7 @@ var otpFieldVariants = cva21("flex w-full min-w-0 flex-col gap-[var(--space-3)]"
9696
9965
  size: "default"
9697
9966
  }
9698
9967
  });
9699
- var otpFieldGroupVariants = cva21("flex items-start gap-[var(--space-2)] pt-[var(--space-1)]", {
9968
+ var otpFieldGroupVariants = cva22("flex items-start gap-[var(--space-2)] pt-[var(--space-1)]", {
9700
9969
  variants: {
9701
9970
  size: {
9702
9971
  default: "",
@@ -9712,7 +9981,7 @@ var otpFieldGroupVariants = cva21("flex items-start gap-[var(--space-2)] pt-[var
9712
9981
  fluid: false
9713
9982
  }
9714
9983
  });
9715
- var otpCellVariants = cva21(
9984
+ var otpCellVariants = cva22(
9716
9985
  [
9717
9986
  "flex items-center justify-center rounded-[var(--radius-md)] border",
9718
9987
  "border-[var(--border)] text-foreground",
@@ -9767,7 +10036,7 @@ var otpCellVariants = cva21(
9767
10036
  }
9768
10037
  }
9769
10038
  );
9770
- var otpFieldMessageVariants = cva21("flex items-start gap-[var(--space-1)] text-xs leading-snug", {
10039
+ var otpFieldMessageVariants = cva22("flex items-start gap-[var(--space-1)] text-xs leading-snug", {
9771
10040
  variants: {
9772
10041
  state: {
9773
10042
  default: "text-text-tertiary",
@@ -10006,7 +10275,7 @@ var OTPField = React46.forwardRef(
10006
10275
  "data-slot": "otp-field-message",
10007
10276
  "data-kind": errorText ? "error" : "helper",
10008
10277
  className: otpFieldMessageVariants({ state: resolvedState }),
10009
- children: errorText ? /* @__PURE__ */ jsxs46(Fragment15, { children: [
10278
+ children: errorText ? /* @__PURE__ */ jsxs46(Fragment16, { children: [
10010
10279
  /* @__PURE__ */ jsx58(
10011
10280
  AlertCircle4,
10012
10281
  {
@@ -10042,9 +10311,9 @@ OTPField.displayName = "OTPField";
10042
10311
  // src/components/ui/search-field.tsx
10043
10312
  import * as React47 from "react";
10044
10313
  import { Search, X as X4 } from "lucide-react";
10045
- import { cva as cva22 } from "class-variance-authority";
10314
+ import { cva as cva23 } from "class-variance-authority";
10046
10315
  import { jsx as jsx59, jsxs as jsxs47 } from "react/jsx-runtime";
10047
- var searchFieldVariants = cva22("relative flex w-full items-center", {
10316
+ var searchFieldVariants = cva23("relative flex w-full items-center", {
10048
10317
  variants: {
10049
10318
  size: {
10050
10319
  // Field-control scale follows Select: sm/md/lg = 30/32/36px. Pair with Button sm/md/lg.
@@ -10057,7 +10326,7 @@ var searchFieldVariants = cva22("relative flex w-full items-center", {
10057
10326
  size: "md"
10058
10327
  }
10059
10328
  });
10060
- var searchFieldInputVariants = cva22(
10329
+ var searchFieldInputVariants = cva23(
10061
10330
  [
10062
10331
  "h-full w-full rounded-[var(--radius-md)] border",
10063
10332
  "border-[var(--border)]",
@@ -10100,7 +10369,7 @@ var searchFieldInputVariants = cva22(
10100
10369
  }
10101
10370
  }
10102
10371
  );
10103
- var iconSize4 = {
10372
+ var iconSize3 = {
10104
10373
  sm: 14,
10105
10374
  md: 16,
10106
10375
  lg: 18
@@ -10155,7 +10424,7 @@ var SearchField = React47.forwardRef(
10155
10424
  "aria-hidden": "true",
10156
10425
  "data-slot": "search-field-icon",
10157
10426
  className: "pointer-events-none absolute left-[10px] top-1/2 -translate-y-1/2 text-text-tertiary",
10158
- size: iconSize4[resolvedSize],
10427
+ size: iconSize3[resolvedSize],
10159
10428
  strokeWidth: resolvedSize === "sm" ? 2 : 1.75
10160
10429
  }
10161
10430
  ),
@@ -10200,9 +10469,9 @@ SearchField.displayName = "SearchField";
10200
10469
 
10201
10470
  // src/components/ui/checkbox-group.tsx
10202
10471
  import * as React48 from "react";
10203
- import { cva as cva23 } from "class-variance-authority";
10472
+ import { cva as cva24 } from "class-variance-authority";
10204
10473
  import { jsx as jsx60 } from "react/jsx-runtime";
10205
- var checkboxGroupVariants = cva23("gap-[var(--space-2)]", {
10474
+ var checkboxGroupVariants = cva24("gap-[var(--space-2)]", {
10206
10475
  variants: {
10207
10476
  appearance: {
10208
10477
  plain: "flex",
@@ -10302,11 +10571,11 @@ CheckboxGroup.displayName = "CheckboxGroup";
10302
10571
 
10303
10572
  // src/components/ui/radio-group.tsx
10304
10573
  import * as React49 from "react";
10305
- import { cva as cva24 } from "class-variance-authority";
10574
+ import { cva as cva25 } from "class-variance-authority";
10306
10575
  import { Circle } from "lucide-react";
10307
10576
  import { RadioGroup as RadioGroupPrimitive } from "radix-ui";
10308
10577
  import { jsx as jsx61, jsxs as jsxs48 } from "react/jsx-runtime";
10309
- var radioGroupVariants = cva24("gap-[var(--space-2)]", {
10578
+ var radioGroupVariants = cva25("gap-[var(--space-2)]", {
10310
10579
  variants: {
10311
10580
  appearance: {
10312
10581
  plain: "flex",
@@ -10331,7 +10600,7 @@ var radioGroupVariants = cva24("gap-[var(--space-2)]", {
10331
10600
  columns: "one"
10332
10601
  }
10333
10602
  });
10334
- var radioVariants = cva24(
10603
+ var radioVariants = cva25(
10335
10604
  [
10336
10605
  "group w-full cursor-pointer text-left transition-colors motion-reduce:transition-none",
10337
10606
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)]",
@@ -10373,7 +10642,7 @@ var radioVariants = cva24(
10373
10642
  }
10374
10643
  }
10375
10644
  );
10376
- var radioControlVariants = cva24(
10645
+ var radioControlVariants = cva25(
10377
10646
  [
10378
10647
  "flex size-[calc(var(--space-4)+var(--space-1))] shrink-0 items-center justify-center",
10379
10648
  "rounded-[var(--radius-full)] border border-[var(--border-strong)] bg-[var(--bg-surface)] text-transparent",
@@ -10607,13 +10876,13 @@ function Progress({
10607
10876
 
10608
10877
  // src/components/ui/tree-view.tsx
10609
10878
  import * as React50 from "react";
10610
- import { ChevronRight as ChevronRight4 } from "lucide-react";
10611
- import { cva as cva25 } from "class-variance-authority";
10879
+ import { ChevronRight as ChevronRight5 } from "lucide-react";
10880
+ import { cva as cva26 } from "class-variance-authority";
10612
10881
  import { jsx as jsx64, jsxs as jsxs50 } from "react/jsx-runtime";
10613
- var treeViewVariants = cva25(
10882
+ var treeViewVariants = cva26(
10614
10883
  "m-0 list-none p-[var(--space-1)] text-body-sm text-foreground"
10615
10884
  );
10616
- var treeItemRowVariants = cva25(
10885
+ var treeItemRowVariants = cva26(
10617
10886
  [
10618
10887
  "flex min-h-[32px] w-full cursor-pointer select-none items-center gap-[var(--space-2)]",
10619
10888
  "rounded-[var(--radius-sm)] py-[var(--space-2)] pr-[var(--space-3)]",
@@ -10824,7 +11093,7 @@ function TreeView({
10824
11093
  },
10825
11094
  className: "flex size-[var(--space-4)] shrink-0 items-center justify-center text-text-tertiary",
10826
11095
  children: /* @__PURE__ */ jsx64(
10827
- ChevronRight4,
11096
+ ChevronRight5,
10828
11097
  {
10829
11098
  "aria-hidden": "true",
10830
11099
  "data-slot": "treeitem-chevron",
@@ -10872,7 +11141,7 @@ function TreeView({
10872
11141
 
10873
11142
  // src/components/branding/olun-logo.tsx
10874
11143
  import { OLUN_MASTER, OLUN_SYMBOL, OLUN_WORDMARK } from "@olundot/tokens/brand";
10875
- import { Fragment as Fragment16, jsx as jsx65, jsxs as jsxs51 } from "react/jsx-runtime";
11144
+ import { Fragment as Fragment17, jsx as jsx65, jsxs as jsxs51 } from "react/jsx-runtime";
10876
11145
  var ACCENT_FILL = "var(--accent-pop)";
10877
11146
  var INK = { color: "var(--text-primary)" };
10878
11147
  var INK_TIGHT = { ...INK, display: "block", overflow: "visible" };
@@ -10882,7 +11151,7 @@ function symbolGeometry(size) {
10882
11151
  function SymbolCircles({ size }) {
10883
11152
  const { ring } = OLUN_SYMBOL;
10884
11153
  const g = symbolGeometry(size);
10885
- return /* @__PURE__ */ jsxs51(Fragment16, { children: [
11154
+ return /* @__PURE__ */ jsxs51(Fragment17, { children: [
10886
11155
  /* @__PURE__ */ jsx65(
10887
11156
  "circle",
10888
11157
  {