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

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,7 +184,7 @@ 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
190
  // src/components/ui/action-variants.ts
@@ -197,8 +197,14 @@ var actionPaint = {
197
197
  filledDanger: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
198
198
  // = Button `secondary`
199
199
  outlineNeutral: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
200
+ // Destructive action that is not the main one: outline neutral's surface, error border and
201
+ // label, error wash on hover.
202
+ outlineDanger: "border-[var(--error)] bg-[var(--bg-surface)] text-[var(--error)] hover:bg-[var(--error-bg)]",
200
203
  // = Button and IconButton `ghost`
201
- ghostNeutral: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground"
204
+ ghostNeutral: "border-transparent bg-transparent text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
205
+ // Button `appearance="link"` only: the label color; the box and underline live in button.tsx.
206
+ linkPrimary: "text-[var(--accent)]",
207
+ linkDanger: "text-[var(--error)]"
202
208
  };
203
209
  var actionAxisVariants = {
204
210
  appearance: { filled: "", outline: "", ghost: "" },
@@ -209,6 +215,7 @@ var actionCompoundVariants = [
209
215
  { appearance: "filled", tone: "neutral", className: actionPaint.filledNeutral },
210
216
  { appearance: "filled", tone: "danger", className: actionPaint.filledDanger },
211
217
  { appearance: "outline", tone: "neutral", className: actionPaint.outlineNeutral },
218
+ { appearance: "outline", tone: "danger", className: actionPaint.outlineDanger },
212
219
  { appearance: "ghost", tone: "neutral", className: actionPaint.ghostNeutral }
213
220
  ];
214
221
  function resolveActionStyle(appearance, tone, fallback) {
@@ -228,17 +235,13 @@ var buttonSizes = {
228
235
  // xs/sm: invisible ::before stretches the hit area to 44px tall (#69), vertically only so
229
236
  // side-by-side buttons never overlap. Its inset is measured from the padding box, inside
230
237
  // the 1px border every variant carries: inset = (44 - (height - 2 × 1px)) / 2.
231
- // IconButton with text reuses these through `buttonSizeClassName`.
238
+ // IconButton with text renders through `buttonVariants`, so it takes these too.
232
239
  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
240
  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
241
  md: buttonSizeMd,
235
242
  lg: "h-[36px] gap-[var(--space-2)] px-[var(--space-4)] text-[15px] leading-[18px] [&_svg]:size-[18px]",
236
243
  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]"
244
+ default: buttonSizeMd
242
245
  };
243
246
  var buttonCva = cva(
244
247
  [
@@ -252,70 +255,62 @@ var buttonCva = cva(
252
255
  ].join(" "),
253
256
  {
254
257
  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,
258
+ // `link` is Button's own appearance (IconButton has no link); its box comes after the
259
+ // size in the compounds below.
260
+ appearance: { ...actionAxisVariants.appearance, link: "" },
261
+ tone: actionAxisVariants.tone,
280
262
  size: buttonSizes
281
263
  },
282
- compoundVariants: [...actionCompoundVariants],
264
+ compoundVariants: [
265
+ ...actionCompoundVariants,
266
+ // Compounds render after the size, so px-0 beats the size's px-*. The height and the xs/sm
267
+ // 44px band stay. Underline on hover only, no visited look; disabled keeps the transparent
268
+ // box with Button's disabled text color.
269
+ {
270
+ appearance: "link",
271
+ className: [
272
+ "border-transparent bg-transparent px-0 underline-offset-4 hover:underline",
273
+ "disabled:border-transparent disabled:bg-transparent disabled:no-underline",
274
+ "aria-disabled:border-transparent aria-disabled:bg-transparent aria-disabled:no-underline"
275
+ ].join(" ")
276
+ },
277
+ { appearance: "link", tone: "primary", className: actionPaint.linkPrimary },
278
+ { appearance: "link", tone: "danger", className: actionPaint.linkDanger }
279
+ ],
283
280
  defaultVariants: {
284
- variant: "primary",
285
281
  size: "md"
286
282
  }
287
283
  }
288
284
  );
285
+ function resolveButtonStyle(appearance, tone) {
286
+ if (appearance === "link") return { appearance, tone: tone ?? "primary" };
287
+ return resolveActionStyle(appearance, tone, "filled");
288
+ }
289
289
  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
- });
290
+ return cn(buttonCva({ ...options, ...resolveButtonStyle(options?.appearance, options?.tone) }));
296
291
  }
297
- var buttonSizeClassName = (size) => buttonSizes[size];
298
292
  var footerButtonHitAreaClassName = "relative before:absolute before:inset-x-0 before:-inset-y-[5px] before:content-['']";
293
+ function preventActivation(event) {
294
+ event.preventDefault();
295
+ event.stopPropagation();
296
+ }
299
297
  var Button = React.forwardRef(
300
298
  ({
301
299
  asChild = false,
302
300
  className,
303
301
  children,
304
302
  disabled,
305
- leadingIcon: LeadingIcon,
306
303
  loading,
307
- trailingIcon: TrailingIcon,
308
304
  type = "button",
309
- variant,
310
305
  appearance,
311
306
  tone,
312
307
  size,
313
308
  style,
309
+ menuIndicator,
314
310
  ...props
315
311
  }, ref) => {
316
312
  const Comp = asChild ? Slot.Root : "button";
317
313
  const isDisabled = disabled || loading;
318
- const IconBefore = loading ? Loader2 : LeadingIcon;
319
314
  const internalRef = React.useRef(null);
320
315
  const frozenWidthRef = React.useRef(null);
321
316
  if (loading && internalRef.current && frozenWidthRef.current === null) {
@@ -343,20 +338,14 @@ var Button = React.forwardRef(
343
338
  "aria-disabled": isDisabled ? true : void 0,
344
339
  disabled: !asChild ? isDisabled : void 0,
345
340
  type: !asChild ? type : void 0,
346
- className: cn(buttonVariants({ variant, appearance, tone, size, className })),
341
+ className: cn(buttonVariants({ appearance, tone, size, className })),
347
342
  style: frozenStyle ? { ...frozenStyle, ...style } : style,
348
343
  ...props,
344
+ ...asChild && isDisabled ? { tabIndex: -1, onClickCapture: preventActivation, onAuxClickCapture: preventActivation } : null,
349
345
  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
346
+ loading ? /* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", "data-slot": "button-spinner", className: "animate-spin" }) : null,
347
+ asChild ? /* @__PURE__ */ jsx(Slot.Slottable, { children }) : children,
348
+ menuIndicator ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true", "data-slot": "button-menu-indicator" }) : null
360
349
  ]
361
350
  }
362
351
  );
@@ -393,7 +382,8 @@ var CopyButton = React2.forwardRef(
393
382
  onCopied,
394
383
  size = "sm",
395
384
  value,
396
- variant = "secondary",
385
+ appearance = "outline",
386
+ tone,
397
387
  ...props
398
388
  }, ref) => {
399
389
  const [copied, setCopied] = React2.useState(false);
@@ -424,7 +414,7 @@ var CopyButton = React2.forwardRef(
424
414
  "aria-label": ariaLabel ?? getCopyButtonAriaLabel(label, value),
425
415
  "data-slot": "copy-button",
426
416
  size,
427
- variant,
417
+ ...{ appearance, tone },
428
418
  onClick: handleClick,
429
419
  ...props,
430
420
  children: [
@@ -1420,7 +1410,7 @@ import { cva as cva5 } from "class-variance-authority";
1420
1410
  import {
1421
1411
  AlertCircle as AlertCircle3,
1422
1412
  CheckCircle2 as CheckCircle23,
1423
- ChevronDown,
1413
+ ChevronDown as ChevronDown2,
1424
1414
  ChevronUp
1425
1415
  } from "lucide-react";
1426
1416
  import { Select as SelectPrimitive } from "radix-ui";
@@ -1631,7 +1621,7 @@ var Select = React7.forwardRef(
1631
1621
  {
1632
1622
  "data-slot": "select-scroll-down",
1633
1623
  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]" })
1624
+ children: /* @__PURE__ */ jsx7(ChevronDown2, { "aria-hidden": "true", className: "size-[16px]" })
1635
1625
  }
1636
1626
  )
1637
1627
  ]
@@ -1674,7 +1664,7 @@ var Select = React7.forwardRef(
1674
1664
  "data-slot": "select-icon",
1675
1665
  className: "ml-[var(--space-2)] inline-flex size-[14px] shrink-0 items-center justify-center text-text-tertiary group-disabled:text-text-disabled",
1676
1666
  children: /* @__PURE__ */ jsx7(
1677
- ChevronDown,
1667
+ ChevronDown2,
1678
1668
  {
1679
1669
  "aria-hidden": "true",
1680
1670
  className: "size-[14px]",
@@ -3468,7 +3458,7 @@ DetailLayout.displayName = "DetailLayout";
3468
3458
 
3469
3459
  // src/components/ui/form-layout.tsx
3470
3460
  import * as React19 from "react";
3471
- import { ChevronDown as ChevronDown2 } from "lucide-react";
3461
+ import { ChevronDown as ChevronDown3 } from "lucide-react";
3472
3462
  import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
3473
3463
  function FormLayoutSectionBlock({
3474
3464
  section,
@@ -3537,7 +3527,7 @@ function FormLayoutSectionBlock({
3537
3527
  children: /* @__PURE__ */ jsxs19("div", { className: "flex min-w-0 items-start gap-[var(--space-2)]", children: [
3538
3528
  /* @__PURE__ */ jsx20("div", { className: "min-w-0 flex-1", children: sectionHeader }),
3539
3529
  /* @__PURE__ */ jsx20(
3540
- ChevronDown2,
3530
+ ChevronDown3,
3541
3531
  {
3542
3532
  "aria-hidden": "true",
3543
3533
  className: cn(
@@ -3885,7 +3875,9 @@ import { Dialog as DialogPrimitive } from "radix-ui";
3885
3875
  // src/components/ui/icon-button.tsx
3886
3876
  import * as React23 from "react";
3887
3877
  import { cva as cva9 } from "class-variance-authority";
3878
+ import { ChevronDown as ChevronDown4, Loader2 as Loader23 } from "lucide-react";
3888
3879
  import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
3880
+ var pressedNeutralClassName = "border-[var(--border-strong)] bg-[var(--action-selected)] text-foreground";
3889
3881
  var iconButtonCva = cva9(
3890
3882
  [
3891
3883
  "olun-icon-button relative inline-flex cursor-pointer shrink-0 items-center justify-center before:absolute before:content-['']",
@@ -3897,28 +3889,17 @@ var iconButtonCva = cva9(
3897
3889
  ].join(" "),
3898
3890
  {
3899
3891
  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
3892
  ...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.
3893
+ // Button's five heights, so one size is one height with or without text. Icon only is
3894
+ // square with a 44px hit area: the ::before is absolutely positioned, so its inset is
3895
+ // measured from the padding box — inside the 1px border every pair carries (transparent
3896
+ // or not). Inset = (44 - (size - 2 × 1px border)) / 2. With text the box is Button's.
3918
3897
  size: {
3919
- sm: "size-[28px] before:-inset-[9px]",
3898
+ xs: "size-[28px] before:-inset-[9px]",
3899
+ sm: "size-[30px] before:-inset-[8px]",
3920
3900
  md: "size-[32px] before:-inset-[7px]",
3921
- lg: "size-[40px] before:-inset-[3px]"
3901
+ lg: "size-[36px] before:-inset-[5px]",
3902
+ xl: "size-[40px] before:-inset-[3px]"
3922
3903
  },
3923
3904
  pressed: {
3924
3905
  true: "",
@@ -3927,39 +3908,17 @@ var iconButtonCva = cva9(
3927
3908
  },
3928
3909
  compoundVariants: [
3929
3910
  ...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
- }
3911
+ { pressed: true, tone: "neutral", className: pressedNeutralClassName }
3945
3912
  ],
3946
3913
  // ghost is the intended default, not a fallback: ghost is reserved for icon-only
3947
3914
  // actions repeated in rows or chrome (toolbars, headers, table rows), and
3948
3915
  // IconButton is its canonical entry point (#58). Text actions use Button.
3949
3916
  defaultVariants: {
3950
- variant: "ghost",
3951
3917
  size: "md",
3952
3918
  pressed: false
3953
3919
  }
3954
3920
  }
3955
3921
  );
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
3922
  var axisIcon = {
3964
3923
  xs: { size: 14, strokeWidth: 1.75 },
3965
3924
  sm: { size: 16, strokeWidth: 2 },
@@ -3968,17 +3927,10 @@ var axisIcon = {
3968
3927
  xl: { size: 18, strokeWidth: 2 }
3969
3928
  };
3970
3929
  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
3930
+ return iconButtonCva({
3931
+ ...options,
3932
+ ...resolveActionStyle(options?.appearance, options?.tone, "ghost")
3980
3933
  });
3981
- return size === null ? paint : `${paint} ${axisSizeClassName[size ?? "md"]}`;
3982
3934
  }
3983
3935
  var iconButtonBadgeVariants = cva9(
3984
3936
  [
@@ -4001,25 +3953,9 @@ var iconButtonBadgeVariants = cva9(
4001
3953
  }
4002
3954
  }
4003
3955
  );
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
3956
  var IconButton = React23.forwardRef(
4020
3957
  ({
4021
3958
  className,
4022
- variant = "ghost",
4023
3959
  appearance,
4024
3960
  tone,
4025
3961
  size = "md",
@@ -4032,28 +3968,37 @@ var IconButton = React23.forwardRef(
4032
3968
  "aria-label": ariaLabel,
4033
3969
  "aria-labelledby": ariaLabelledBy,
4034
3970
  iconPosition = "start",
3971
+ loading,
3972
+ menuIndicator,
3973
+ disabled,
4035
3974
  label,
4036
3975
  children,
4037
3976
  ...props
4038
3977
  }, ref) => {
4039
3978
  const resolvedSize = size ?? "md";
4040
- const usesAxes = appearance != null || tone != null;
4041
3979
  const isToggle = pressed !== void 0;
4042
3980
  const isPressed = pressed === true;
4043
3981
  const hoverTitle = title ?? (typeof ariaLabel === "string" ? ariaLabel : void 0);
4044
3982
  const text = label ?? children;
4045
3983
  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(
3984
+ const isDisabled = disabled || loading;
3985
+ const style = resolveActionStyle(appearance, tone, "ghost");
3986
+ const icon = loading ? /* @__PURE__ */ jsx22(
3987
+ Loader23,
3988
+ {
3989
+ "aria-hidden": "true",
3990
+ "data-slot": "icon-button-spinner",
3991
+ className: "animate-spin",
3992
+ size: axisIcon[resolvedSize].size,
3993
+ strokeWidth: axisIcon[resolvedSize].strokeWidth
3994
+ }
3995
+ ) : /* @__PURE__ */ jsx22(
4051
3996
  Icon,
4052
3997
  {
4053
3998
  "aria-hidden": "true",
4054
3999
  "data-slot": "icon-button-icon",
4055
- size: axisSize ? axisIcon[axisSize].size : iconSize2[legacySize],
4056
- strokeWidth: axisSize ? axisIcon[axisSize].strokeWidth : hasText ? void 0 : iconStrokeWidth[legacySize]
4000
+ size: axisIcon[resolvedSize].size,
4001
+ strokeWidth: axisIcon[resolvedSize].strokeWidth
4057
4002
  }
4058
4003
  );
4059
4004
  return /* @__PURE__ */ jsxs20(
@@ -4062,25 +4007,27 @@ var IconButton = React23.forwardRef(
4062
4007
  ref,
4063
4008
  ...props,
4064
4009
  "data-slot": "icon-button",
4065
- "data-variant": usesAxes ? void 0 : variant,
4066
- "data-appearance": style?.appearance,
4067
- "data-tone": style?.tone,
4010
+ "data-appearance": style.appearance,
4011
+ "data-tone": style.tone,
4068
4012
  "data-size": resolvedSize,
4069
4013
  "data-icon-position": hasText ? iconPosition : void 0,
4070
4014
  "data-pressed": isToggle ? String(isPressed) : void 0,
4015
+ "data-loading": loading ? "true" : void 0,
4016
+ "aria-busy": loading ? true : void 0,
4017
+ "aria-disabled": isDisabled ? true : void 0,
4018
+ disabled: isDisabled,
4071
4019
  "aria-label": ariaLabel,
4072
4020
  "aria-labelledby": ariaLabelledBy,
4073
4021
  "aria-pressed": isToggle ? isPressed : void 0,
4074
4022
  title: hoverTitle,
4075
4023
  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)],
4024
+ hasText ? [
4025
+ "olun-icon-button",
4026
+ buttonVariants({ ...style, size: resolvedSize }),
4027
+ isPressed && style.tone === "neutral" && pressedNeutralClassName,
4028
+ // The badge sits on the corner; Button xs/sm are already relative.
4029
+ badge !== void 0 && "relative"
4030
+ ] : iconButtonVariants({ appearance, tone, size: resolvedSize, pressed: isPressed }),
4084
4031
  className
4085
4032
  ),
4086
4033
  type: type ?? "button",
@@ -4088,6 +4035,15 @@ var IconButton = React23.forwardRef(
4088
4035
  hasText && iconPosition === "end" ? null : icon,
4089
4036
  hasText ? text : null,
4090
4037
  hasText && iconPosition === "end" ? icon : null,
4038
+ hasText && menuIndicator ? /* @__PURE__ */ jsx22(
4039
+ ChevronDown4,
4040
+ {
4041
+ "aria-hidden": "true",
4042
+ "data-slot": "icon-button-menu-indicator",
4043
+ size: axisIcon[resolvedSize].size,
4044
+ strokeWidth: axisIcon[resolvedSize].strokeWidth
4045
+ }
4046
+ ) : null,
4091
4047
  badge !== void 0 ? /* @__PURE__ */ jsx22(
4092
4048
  "span",
4093
4049
  {
@@ -5482,7 +5438,8 @@ var FilterToolbar = React29.forwardRef(
5482
5438
  "aria-label": collapseTriggerLabel,
5483
5439
  icon: SlidersHorizontal,
5484
5440
  size: "md",
5485
- variant: "outline",
5441
+ appearance: "outline",
5442
+ tone: "neutral",
5486
5443
  onClick: () => handleOverlayOpenChange(true)
5487
5444
  }
5488
5445
  ),
@@ -5637,8 +5594,8 @@ var FilterToolbar = React29.forwardRef(
5637
5594
  FilterToolbar.displayName = "FilterToolbar";
5638
5595
 
5639
5596
  // src/components/ui/data-table.tsx
5640
- import * as React32 from "react";
5641
- import { ChevronDown as ChevronDown3, ChevronUp as ChevronUp2, ChevronsUpDown } from "lucide-react";
5597
+ import * as React33 from "react";
5598
+ import { ChevronDown as ChevronDown5, ChevronUp as ChevronUp2, ChevronsUpDown } from "lucide-react";
5642
5599
  import { cva as cva12 } from "class-variance-authority";
5643
5600
 
5644
5601
  // src/components/ui/checkbox.tsx
@@ -6225,32 +6182,252 @@ function DropdownMenuSubContent({
6225
6182
  }
6226
6183
 
6227
6184
  // src/components/ui/list-card.tsx
6185
+ import * as React32 from "react";
6186
+ import { ChevronRight as ChevronRight2, MoreVertical } from "lucide-react";
6187
+
6188
+ // src/components/ui/action-menu.tsx
6228
6189
  import * as React31 from "react";
6229
- import { ChevronRight as ChevronRight2 } from "lucide-react";
6190
+ import { Dialog as DialogPrimitive4, Slot as Slot3 } from "radix-ui";
6230
6191
  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 !== "");
6192
+ var sheetRowClassName = cn(
6193
+ "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",
6194
+ "border-t border-[var(--border-subtle)] text-[13px] font-medium leading-normal text-text-primary",
6195
+ "transition-colors motion-reduce:transition-none hover:bg-[var(--action-hover)]",
6196
+ "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--focus-ring)]",
6197
+ "enabled:data-[destructive]:text-[var(--semantic-error-fg)]",
6198
+ "disabled:cursor-not-allowed disabled:bg-[var(--action-disabled-bg)] disabled:text-text-disabled"
6199
+ );
6200
+ var sheetRowDescriptionClassName = "block text-[12px] font-normal text-text-secondary group-disabled:text-text-disabled";
6201
+ var sheetGroupLabelClassName = "px-[var(--space-4)] pt-[var(--space-3)] pb-[var(--space-2)] text-[12px] font-semibold leading-normal text-text-tertiary";
6202
+ var sheetGroupSeparatorClassName = "h-[var(--space-2)] bg-[var(--bg-inset)]";
6203
+ function ActionMenuSheet({
6204
+ open,
6205
+ onOpenChange,
6206
+ title,
6207
+ description,
6208
+ closeLabel,
6209
+ groups,
6210
+ onOpenAutoFocus,
6211
+ onCloseAutoFocus
6212
+ }) {
6213
+ const pendingRef = React31.useRef(null);
6214
+ const surfaceRef = React31.useRef(null);
6215
+ const labelId = React31.useId();
6216
+ const handleOpenChange = (nextOpen) => {
6217
+ pendingRef.current = null;
6218
+ onOpenChange(nextOpen);
6219
+ };
6220
+ const swipe = useSwipeDismiss({
6221
+ enabled: OVERLAY_POLICY.menu.swipe,
6222
+ onDismiss: () => handleOpenChange(false),
6223
+ surfaceRef,
6224
+ always: true
6225
+ });
6226
+ const handleSelect = (item) => {
6227
+ onOpenChange(false);
6228
+ pendingRef.current = item;
6229
+ };
6230
+ const handleOpenAutoFocus = (event) => {
6231
+ onOpenAutoFocus?.(event);
6232
+ const firstRow = surfaceRef.current?.querySelector('[data-slot="action-menu-item"]:enabled');
6233
+ if (!firstRow) return;
6234
+ event.preventDefault();
6235
+ firstRow.focus();
6236
+ };
6237
+ const handleCloseAutoFocus = (event) => {
6238
+ onCloseAutoFocus(event);
6239
+ const item = pendingRef.current;
6240
+ pendingRef.current = null;
6241
+ item?.onSelect();
6242
+ };
6243
+ return /* @__PURE__ */ jsx35(DialogPrimitive4.Root, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs31(DialogPrimitive4.Portal, { children: [
6244
+ /* @__PURE__ */ jsx35(OverlayScrimLayer, { kind: "menu" }),
6245
+ /* @__PURE__ */ jsxs31(
6246
+ DialogPrimitive4.Content,
6247
+ {
6248
+ ref: surfaceRef,
6249
+ "data-slot": "action-menu-sheet",
6250
+ className: overlayBoxClassName("menu"),
6251
+ onOpenAutoFocus: handleOpenAutoFocus,
6252
+ onCloseAutoFocus: handleCloseAutoFocus,
6253
+ ...description ? {} : { "aria-describedby": void 0 },
6254
+ children: [
6255
+ /* @__PURE__ */ jsx35(OverlayGrabber, { always: true, ...swipe.handleProps }),
6256
+ /* @__PURE__ */ jsx35(
6257
+ OverlayHeader,
6258
+ {
6259
+ kind: "menu",
6260
+ title,
6261
+ description,
6262
+ closeLabel,
6263
+ dragHandleProps: swipe.handleProps
6264
+ }
6265
+ ),
6266
+ /* @__PURE__ */ jsx35(OverlayBody, { kind: "menu", children: groups.map((group, index) => /* @__PURE__ */ jsxs31(React31.Fragment, { children: [
6267
+ index > 0 ? /* @__PURE__ */ jsx35("div", { role: "separator", className: sheetGroupSeparatorClassName }) : null,
6268
+ /* @__PURE__ */ jsxs31("div", { role: "group", "aria-labelledby": group.label ? `${labelId}-${index}` : void 0, children: [
6269
+ group.label ? /* @__PURE__ */ jsx35("div", { id: `${labelId}-${index}`, className: sheetGroupLabelClassName, children: group.label }) : null,
6270
+ group.items.map((item) => {
6271
+ const Icon = item.icon;
6272
+ return /* @__PURE__ */ jsxs31(
6273
+ "button",
6274
+ {
6275
+ type: "button",
6276
+ "data-slot": "action-menu-item",
6277
+ "data-destructive": item.destructive ? "" : void 0,
6278
+ className: sheetRowClassName,
6279
+ disabled: item.disabled,
6280
+ onClick: () => handleSelect(item),
6281
+ children: [
6282
+ Icon ? /* @__PURE__ */ jsx35(Icon, { "aria-hidden": true, size: 17, strokeWidth: 1.75, className: "shrink-0" }) : null,
6283
+ /* @__PURE__ */ jsxs31("span", { className: "min-w-0 flex-1 break-keep", children: [
6284
+ item.label,
6285
+ item.description ? /* @__PURE__ */ jsx35("span", { className: sheetRowDescriptionClassName, children: item.description }) : null
6286
+ ] })
6287
+ ]
6288
+ },
6289
+ item.id
6290
+ );
6291
+ })
6292
+ ] })
6293
+ ] }, group.id)) })
6294
+ ]
6295
+ }
6296
+ )
6297
+ ] }) });
6233
6298
  }
6234
- function lineTitle(tokens) {
6235
- if (!tokens.every((token) => typeof token === "string" || typeof token === "number")) {
6236
- return void 0;
6299
+ var readPresentation = () => window.matchMedia?.(OVERLAY_DESKTOP_QUERY).matches ?? true ? "dropdown" : "sheet";
6300
+ var subscribeNothing = () => () => void 0;
6301
+ var useHydrated = () => React31.useSyncExternalStore(
6302
+ subscribeNothing,
6303
+ () => true,
6304
+ () => false
6305
+ );
6306
+ function ActionMenu({
6307
+ trigger,
6308
+ title,
6309
+ description,
6310
+ open: openProp,
6311
+ onOpenChange,
6312
+ closeLabel,
6313
+ items,
6314
+ groups
6315
+ }) {
6316
+ const [uncontrolledOpen, setUncontrolledOpen] = React31.useState(false);
6317
+ const hydrated = useHydrated();
6318
+ const open = (openProp ?? uncontrolledOpen) && hydrated;
6319
+ const [shown, setShown] = React31.useState({
6320
+ open: false,
6321
+ presentation: "dropdown"
6322
+ });
6323
+ let presentation = shown.presentation;
6324
+ if (shown.open !== open) {
6325
+ if (open) presentation = readPresentation();
6326
+ setShown({ open, presentation });
6237
6327
  }
6238
- return tokens.join(" \xB7 ");
6328
+ const triggerRef = React31.useRef(null);
6329
+ const pendingRef = React31.useRef(null);
6330
+ const setOpen = (nextOpen) => {
6331
+ if (nextOpen) pendingRef.current = null;
6332
+ if (openProp === void 0) setUncontrolledOpen(nextOpen);
6333
+ onOpenChange?.(nextOpen);
6334
+ };
6335
+ const menuGroups = groups ?? [{ id: "items", items: items ?? [] }];
6336
+ const handleDropdownCloseAutoFocus = (event) => {
6337
+ const item = pendingRef.current;
6338
+ pendingRef.current = null;
6339
+ if (!item) return;
6340
+ event.preventDefault();
6341
+ triggerRef.current?.focus();
6342
+ item.onSelect();
6343
+ };
6344
+ const handleSheetCloseAutoFocus = (event) => {
6345
+ event.preventDefault();
6346
+ triggerRef.current?.focus();
6347
+ };
6348
+ const triggerLabel = trigger.props["aria-label"];
6349
+ return /* @__PURE__ */ jsxs31(Fragment11, { children: [
6350
+ /* @__PURE__ */ jsxs31(DropdownMenu, { open: open && presentation === "dropdown", onOpenChange: setOpen, children: [
6351
+ /* @__PURE__ */ jsx35(DropdownMenuTrigger, { asChild: true, "aria-expanded": open, children: /* @__PURE__ */ jsx35(Slot3.Root, { ref: triggerRef, children: trigger }) }),
6352
+ /* @__PURE__ */ jsx35(DropdownMenuContent, { align: "end", onCloseAutoFocus: handleDropdownCloseAutoFocus, children: menuGroups.map((group, index) => /* @__PURE__ */ jsxs31(React31.Fragment, { children: [
6353
+ index > 0 ? /* @__PURE__ */ jsx35(DropdownMenuSeparator, {}) : null,
6354
+ /* @__PURE__ */ jsxs31(DropdownMenuGroup, { children: [
6355
+ group.label ? /* @__PURE__ */ jsx35(DropdownMenuLabel, { children: group.label }) : null,
6356
+ group.items.map((item) => {
6357
+ const Icon = item.icon;
6358
+ return /* @__PURE__ */ jsxs31(
6359
+ DropdownMenuItem,
6360
+ {
6361
+ variant: item.destructive ? "destructive" : "default",
6362
+ disabled: item.disabled,
6363
+ onSelect: () => {
6364
+ pendingRef.current = item;
6365
+ },
6366
+ children: [
6367
+ Icon ? /* @__PURE__ */ jsx35(Icon, { "aria-hidden": true, size: 16, strokeWidth: 1.75 }) : null,
6368
+ item.label
6369
+ ]
6370
+ },
6371
+ item.id
6372
+ );
6373
+ })
6374
+ ] })
6375
+ ] }, group.id)) })
6376
+ ] }),
6377
+ /* @__PURE__ */ jsx35(
6378
+ ActionMenuSheet,
6379
+ {
6380
+ open: open && presentation === "sheet",
6381
+ onOpenChange: setOpen,
6382
+ title: title ?? /* @__PURE__ */ jsx35("span", { className: "sr-only", children: triggerLabel }),
6383
+ description,
6384
+ closeLabel,
6385
+ groups: menuGroups,
6386
+ onCloseAutoFocus: handleSheetCloseAutoFocus
6387
+ }
6388
+ )
6389
+ ] });
6239
6390
  }
6240
- function MetaLine({ tokens, slot }) {
6241
- return /* @__PURE__ */ jsx35(
6391
+
6392
+ // src/components/ui/list-card.tsx
6393
+ import { Fragment as Fragment12, jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
6394
+ function lineTokens(value) {
6395
+ return React32.Children.toArray(value).filter((token) => token !== "");
6396
+ }
6397
+ function MetaLine({
6398
+ tokens,
6399
+ slot,
6400
+ first,
6401
+ last
6402
+ }) {
6403
+ return /* @__PURE__ */ jsx36(
6242
6404
  "span",
6243
6405
  {
6244
6406
  "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))
6407
+ className: cn(
6408
+ "flex flex-wrap gap-x-[var(--space-3)] gap-y-[2px] text-[12px] leading-[16px] text-text-secondary",
6409
+ first ? "mt-[var(--space-1)]" : "mt-[2px]"
6410
+ ),
6411
+ children: tokens.map((token, index) => /* @__PURE__ */ jsxs32(
6412
+ "span",
6413
+ {
6414
+ className: "max-w-full truncate whitespace-nowrap",
6415
+ title: typeof token === "string" || typeof token === "number" ? String(token) : void 0,
6416
+ children: [
6417
+ token,
6418
+ index < tokens.length - 1 || !last ? /* @__PURE__ */ jsx36("span", { className: "sr-only", children: ", " }) : null
6419
+ ]
6420
+ },
6421
+ index
6422
+ ))
6251
6423
  }
6252
6424
  );
6253
6425
  }
6426
+ var titleClassName = "line-clamp-2 text-[13px] font-medium leading-[18px] text-text-primary [overflow-wrap:anywhere] [word-break:keep-all]";
6427
+ var overlayClassName = cn(
6428
+ "text-inherit no-underline outline-none after:absolute after:inset-0 after:content-['']",
6429
+ "focus-visible:after:ring-2 focus-visible:after:ring-inset focus-visible:after:ring-[var(--focus-ring)]"
6430
+ );
6254
6431
  function ListCard({
6255
6432
  title,
6256
6433
  meta,
@@ -6259,6 +6436,7 @@ function ListCard({
6259
6436
  leading,
6260
6437
  value,
6261
6438
  trailing = "chevron",
6439
+ actions,
6262
6440
  href,
6263
6441
  linkComponent,
6264
6442
  linkProps,
@@ -6269,40 +6447,48 @@ function ListCard({
6269
6447
  const meta1 = lineTokens(meta?.[0]);
6270
6448
  const meta2 = lineTokens(meta?.[1]);
6271
6449
  const hasValue = value != null;
6272
- const chevron = /* @__PURE__ */ jsx35(
6450
+ const overlay = actions != null && (href != null || onClick != null);
6451
+ const trailingNode = trailing === "chevron" ? /* @__PURE__ */ jsx36(
6273
6452
  ChevronRight2,
6274
6453
  {
6275
6454
  "data-slot": `${slot}-suffix`,
6276
6455
  "aria-hidden": true,
6277
6456
  className: "size-[var(--space-4)] shrink-0 text-text-tertiary"
6278
6457
  }
6279
- );
6280
- const trailingNode = trailing === "chevron" ? chevron : trailing === "none" ? null : /* @__PURE__ */ jsx35("span", { "data-slot": `${slot}-suffix`, children: trailing });
6458
+ ) : trailing === "none" ? null : /* @__PURE__ */ jsx36("span", { "data-slot": `${slot}-suffix`, children: trailing });
6459
+ const bottomIcon = actions != null && trailingNode != null;
6460
+ const hasEnd = hasValue || actions != null || trailingNode != null;
6281
6461
  const rootClassName = cn(
6282
- "relative grid w-full min-w-0 items-center gap-x-[var(--space-2)] whitespace-normal text-left outline-none",
6462
+ "relative grid w-full min-w-0 items-start gap-x-[var(--space-2)] whitespace-normal text-left outline-none",
6283
6463
  "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-['']",
6464
+ // An empty end keeps the 16px chevron track.
6465
+ 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]",
6466
+ // 84 = the ⋮ hit area (2 above the top to 42 below) meets the chevron's (42 above the bottom to 2 below).
6467
+ bottomIcon ? "min-h-[calc(var(--space-20)+var(--space-1))]" : null,
6468
+ href && !overlay && "after:absolute after:inset-0 after:content-['']",
6287
6469
  className
6288
6470
  );
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(
6471
+ const titleNode = /* @__PURE__ */ jsx36(
6472
+ "span",
6473
+ {
6474
+ "data-slot": `${slot}-title`,
6475
+ className: titleClassName,
6476
+ title: typeof title === "string" || typeof title === "number" ? String(title) : void 0,
6477
+ children: overlay && href != null ? React32.createElement(linkComponent ?? "a", { ...linkProps, href, className: overlayClassName }, title) : title
6478
+ }
6479
+ );
6480
+ const content = /* @__PURE__ */ jsxs32(Fragment12, { children: [
6481
+ leading != null ? /* @__PURE__ */ jsx36("span", { className: "flex min-h-[18px] items-center", children: leading }) : null,
6482
+ /* @__PURE__ */ jsxs32("span", { className: "min-w-0", children: [
6483
+ overlay && href == null ? (
6484
+ // A block button keeps the title's two-line clamp inside it.
6485
+ /* @__PURE__ */ jsx36("button", { type: "button", onClick, className: cn(overlayClassName, "block w-full text-left"), children: titleNode })
6486
+ ) : titleNode,
6487
+ meta1.length > 0 ? /* @__PURE__ */ jsx36(MetaLine, { tokens: meta1, slot: `${slot}-meta1`, first: true, last: meta2.length === 0 }) : null,
6488
+ meta2.length > 0 ? /* @__PURE__ */ jsx36(MetaLine, { tokens: meta2, slot: `${slot}-meta2`, first: meta1.length === 0, last: true }) : null,
6489
+ 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: [
6490
+ status != null ? /* @__PURE__ */ jsx36("span", { "data-slot": `${slot}-badge`, className: "flex items-center", children: status }) : null,
6491
+ caption != null ? /* @__PURE__ */ jsx36(
6306
6492
  "span",
6307
6493
  {
6308
6494
  "data-slot": `${slot}-caption`,
@@ -6312,30 +6498,51 @@ function ListCard({
6312
6498
  ) : null
6313
6499
  ] }) : null
6314
6500
  ] }),
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
6501
+ hasEnd ? /* @__PURE__ */ jsxs32("span", { "data-slot": `${slot}-trailing`, className: "flex flex-col items-end justify-between self-stretch", children: [
6502
+ /* @__PURE__ */ jsxs32(
6503
+ "span",
6504
+ {
6505
+ className: cn(
6506
+ "-mt-[var(--space-2)] flex min-h-[var(--space-8)] items-center",
6507
+ actions != null ? "-mr-[var(--space-2)] gap-[var(--space-1)]" : "gap-[var(--space-2)]"
6508
+ ),
6509
+ children: [
6510
+ hasValue ? /* @__PURE__ */ jsx36("span", { "data-slot": `${slot}-value`, className: "text-[13px] leading-[20px] text-text-secondary tabular-nums", children: value }) : null,
6511
+ actions != null ? /* @__PURE__ */ jsx36("span", { className: "relative z-[1] flex", children: /* @__PURE__ */ jsx36(
6512
+ ActionMenu,
6513
+ {
6514
+ title: typeof title === "string" ? title : void 0,
6515
+ items: [...actions.items],
6516
+ trigger: /* @__PURE__ */ jsx36(
6517
+ IconButton,
6518
+ {
6519
+ icon: MoreVertical,
6520
+ "aria-label": actions.label,
6521
+ appearance: "ghost",
6522
+ tone: "neutral",
6523
+ size: "md"
6524
+ }
6525
+ )
6526
+ }
6527
+ ) }) : trailingNode
6528
+ ]
6529
+ }
6530
+ ),
6531
+ bottomIcon ? trailingNode : null
6532
+ ] }) : null
6326
6533
  ] });
6327
- if (href) {
6534
+ if (href && !overlay) {
6328
6535
  const LinkComponent = linkComponent ?? "a";
6329
- return /* @__PURE__ */ jsx35(LinkComponent, { ...linkProps, href, className: rootClassName, children: content });
6536
+ return /* @__PURE__ */ jsx36(LinkComponent, { ...linkProps, href, className: rootClassName, children: content });
6330
6537
  }
6331
- if (onClick) {
6332
- return /* @__PURE__ */ jsx35("button", { type: "button", onClick, className: rootClassName, children: content });
6538
+ if (onClick && !overlay) {
6539
+ return /* @__PURE__ */ jsx36("button", { type: "button", onClick, className: rootClassName, children: content });
6333
6540
  }
6334
- return /* @__PURE__ */ jsx35("div", { className: rootClassName, children: content });
6541
+ return /* @__PURE__ */ jsx36("div", { className: rootClassName, children: content });
6335
6542
  }
6336
6543
 
6337
6544
  // src/components/ui/data-table.tsx
6338
- import { Fragment as Fragment12, jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
6545
+ import { Fragment as Fragment13, jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
6339
6546
  var dataTableVariants = cva12(
6340
6547
  [
6341
6548
  "relative overflow-hidden rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
@@ -6398,7 +6605,7 @@ function getRenderedCell(row, column) {
6398
6605
  if (value === null || value === void 0) {
6399
6606
  return null;
6400
6607
  }
6401
- if (React32.isValidElement(value)) {
6608
+ if (React33.isValidElement(value)) {
6402
6609
  return value;
6403
6610
  }
6404
6611
  return String(value);
@@ -6418,7 +6625,7 @@ function isInteractiveTarget(target) {
6418
6625
  function SortIcon({ sort, columnKey }) {
6419
6626
  const isActive = sort?.key === columnKey;
6420
6627
  if (!isActive) {
6421
- return /* @__PURE__ */ jsx36(
6628
+ return /* @__PURE__ */ jsx37(
6422
6629
  ChevronsUpDown,
6423
6630
  {
6424
6631
  "aria-hidden": "true",
@@ -6429,8 +6636,8 @@ function SortIcon({ sort, columnKey }) {
6429
6636
  }
6430
6637
  );
6431
6638
  }
6432
- const Icon = sort.dir === "asc" ? ChevronUp2 : ChevronDown3;
6433
- return /* @__PURE__ */ jsx36(
6639
+ const Icon = sort.dir === "asc" ? ChevronUp2 : ChevronDown5;
6640
+ return /* @__PURE__ */ jsx37(
6434
6641
  Icon,
6435
6642
  {
6436
6643
  "aria-hidden": "true",
@@ -6448,8 +6655,8 @@ function MobileSortMenu({
6448
6655
  onSortChange
6449
6656
  }) {
6450
6657
  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(
6658
+ return /* @__PURE__ */ jsxs33(DropdownMenu, { children: [
6659
+ /* @__PURE__ */ jsx37(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs33(
6453
6660
  Button,
6454
6661
  {
6455
6662
  "data-slot": "data-table-mobile-sort-button",
@@ -6458,26 +6665,26 @@ function MobileSortMenu({
6458
6665
  size: "sm",
6459
6666
  className: "ml-auto min-w-0",
6460
6667
  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: [
6668
+ active && sortBy ? /* @__PURE__ */ jsxs33(Fragment13, { children: [
6669
+ /* @__PURE__ */ jsx37("span", { className: "sr-only", children: "\uC815\uB82C " }),
6670
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: active.header }),
6671
+ /* @__PURE__ */ jsxs33("span", { className: "sr-only", children: [
6465
6672
  ", ",
6466
6673
  sortBy.dir === "asc" ? "\uC624\uB984\uCC28\uC21C" : "\uB0B4\uB9BC\uCC28\uC21C"
6467
6674
  ] })
6468
6675
  ] }) : "\uC815\uB82C",
6469
- /* @__PURE__ */ jsx36(SortIcon, { sort: sortBy, columnKey: active?.key ?? "" })
6676
+ /* @__PURE__ */ jsx37(SortIcon, { sort: sortBy, columnKey: active?.key ?? "" })
6470
6677
  ]
6471
6678
  }
6472
6679
  ) }),
6473
- /* @__PURE__ */ jsx36(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx36(DropdownMenuRadioGroup, { value: active?.key ?? "", children: columns.map((column) => /* @__PURE__ */ jsxs32(
6680
+ /* @__PURE__ */ jsx37(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx37(DropdownMenuRadioGroup, { value: active?.key ?? "", children: columns.map((column) => /* @__PURE__ */ jsxs33(
6474
6681
  DropdownMenuRadioItem,
6475
6682
  {
6476
6683
  value: column.key,
6477
6684
  onSelect: () => onSortChange?.(column.key, getNextSort(sortBy, column.key)),
6478
6685
  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
6686
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: column.header }),
6687
+ 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
6688
  ]
6482
6689
  },
6483
6690
  column.key
@@ -6496,14 +6703,14 @@ function MobileToolbar({
6496
6703
  if (!selectable && sortableColumns.length === 0) {
6497
6704
  return null;
6498
6705
  }
6499
- return /* @__PURE__ */ jsxs32(
6706
+ return /* @__PURE__ */ jsxs33(
6500
6707
  "div",
6501
6708
  {
6502
6709
  "data-slot": "data-table-mobile-toolbar",
6503
6710
  className: "flex min-w-0 items-center gap-[var(--space-2)] px-[var(--space-4)] py-[var(--space-2)]",
6504
6711
  children: [
6505
- selectable ? /* @__PURE__ */ jsx36(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll }) : null,
6506
- sortableColumns.length > 0 ? /* @__PURE__ */ jsx36(MobileSortMenu, { columns: sortableColumns, sortBy, onSortChange }) : null
6712
+ selectable ? /* @__PURE__ */ jsx37(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll }) : null,
6713
+ sortableColumns.length > 0 ? /* @__PURE__ */ jsx37(MobileSortMenu, { columns: sortableColumns, sortBy, onSortChange }) : null
6507
6714
  ]
6508
6715
  }
6509
6716
  );
@@ -6512,13 +6719,13 @@ function SelectAllCheckbox({
6512
6719
  checked,
6513
6720
  onToggleAll
6514
6721
  }) {
6515
- return /* @__PURE__ */ jsx36(
6722
+ return /* @__PURE__ */ jsx37(
6516
6723
  Checkbox,
6517
6724
  {
6518
6725
  "aria-label": "\uC804\uCCB4 \uD589 \uC120\uD0DD",
6519
6726
  checked,
6520
6727
  onCheckedChange: (nextChecked) => onToggleAll(nextChecked === true),
6521
- children: /* @__PURE__ */ jsx36("span", { className: "sr-only", children: "\uC804\uCCB4 \uD589 \uC120\uD0DD" })
6728
+ children: /* @__PURE__ */ jsx37("span", { className: "sr-only", children: "\uC804\uCCB4 \uD589 \uC120\uD0DD" })
6522
6729
  }
6523
6730
  );
6524
6731
  }
@@ -6529,13 +6736,13 @@ function RowCheckbox({
6529
6736
  selected,
6530
6737
  onToggle
6531
6738
  }) {
6532
- return /* @__PURE__ */ jsx36(
6739
+ return /* @__PURE__ */ jsx37(
6533
6740
  Checkbox,
6534
6741
  {
6535
6742
  "aria-label": `${String(row[columns[0]?.key] ?? rowId)} \uD589 \uC120\uD0DD`,
6536
6743
  checked: selected,
6537
6744
  onCheckedChange: (nextChecked) => onToggle(rowId, nextChecked === true),
6538
- children: /* @__PURE__ */ jsxs32("span", { className: "sr-only", children: [
6745
+ children: /* @__PURE__ */ jsxs33("span", { className: "sr-only", children: [
6539
6746
  rowId,
6540
6747
  " \uD589 \uC120\uD0DD"
6541
6748
  ] })
@@ -6552,17 +6759,17 @@ function SkeletonRows({
6552
6759
  // role="table"의 허용 자식은 row/rowgroup뿐이라 컨테이너는 rowgroup이어야 한다.
6553
6760
  // 로딩 알림은 그 안의 row/cell 안에 둔다 — 종전에는 컨테이너가 role="status"라
6554
6761
  // 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(
6762
+ /* @__PURE__ */ jsxs33("div", { role: "rowgroup", children: [
6763
+ /* @__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" }) }) }),
6764
+ Array.from({ length: count }, (_, rowIndex) => /* @__PURE__ */ jsxs33(
6558
6765
  "div",
6559
6766
  {
6560
6767
  "data-slot": "data-table-skeleton-row",
6561
6768
  className: "grid min-h-[48px] items-center border-t border-[var(--border-subtle)]",
6562
6769
  style: { gridTemplateColumns },
6563
6770
  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(
6771
+ selectable ? /* @__PURE__ */ jsx37("div", { "aria-hidden": "true", className: "px-[var(--space-4)]" }) : null,
6772
+ columns.map((column, columnIndex) => /* @__PURE__ */ jsx37("div", { className: "px-[var(--space-4)] py-[var(--space-2)]", children: /* @__PURE__ */ jsx37(
6566
6773
  "div",
6567
6774
  {
6568
6775
  className: cn(
@@ -6579,15 +6786,15 @@ function SkeletonRows({
6579
6786
  );
6580
6787
  }
6581
6788
  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(
6789
+ 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
6790
  "div",
6584
6791
  {
6585
6792
  "data-slot": "data-table-mobile-skeleton-card",
6586
6793
  className: "flex flex-col gap-[var(--space-2)] border-t border-[var(--border-subtle)] px-[var(--space-4)] py-[var(--space-4)]",
6587
6794
  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)]" })
6795
+ /* @__PURE__ */ jsx37("div", { className: "h-[14px] w-[72%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
6796
+ /* @__PURE__ */ jsx37("div", { className: "h-[12px] w-[56%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" }),
6797
+ /* @__PURE__ */ jsx37("div", { className: "h-[12px] w-[64%] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-inset)]" })
6591
6798
  ]
6592
6799
  },
6593
6800
  rowIndex
@@ -6635,7 +6842,7 @@ function DataTableRowView({
6635
6842
  }) {
6636
6843
  const linked = Boolean(LinkComponent && href);
6637
6844
  const handlers = useActivationHandlers({ row, href, activatable, onActivate });
6638
- return /* @__PURE__ */ jsxs32(
6845
+ return /* @__PURE__ */ jsxs33(
6639
6846
  "div",
6640
6847
  {
6641
6848
  "data-slot": "data-table-row",
@@ -6653,11 +6860,11 @@ function DataTableRowView({
6653
6860
  onClick: handlers.onClick,
6654
6861
  onKeyDown: handlers.onKeyDown,
6655
6862
  children: [
6656
- selectable ? /* @__PURE__ */ jsx36("div", { role: "cell", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx36(RowCheckbox, { row, rowId, columns, selected, onToggle }) }) : null,
6863
+ selectable ? /* @__PURE__ */ jsx37("div", { role: "cell", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx37(RowCheckbox, { row, rowId, columns, selected, onToggle }) }) : null,
6657
6864
  columns.map((column, columnIndex) => {
6658
6865
  const align = column.align ?? "left";
6659
6866
  const content = getRenderedCell(row, column);
6660
- return /* @__PURE__ */ jsx36(
6867
+ return /* @__PURE__ */ jsx37(
6661
6868
  "div",
6662
6869
  {
6663
6870
  "data-slot": "data-table-cell",
@@ -6667,7 +6874,7 @@ function DataTableRowView({
6667
6874
  alignmentClass[align],
6668
6875
  column.tabular ? "font-[family-name:var(--font-display)] tabular-nums" : null
6669
6876
  ),
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 })
6877
+ 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
6878
  },
6672
6879
  column.key
6673
6880
  );
@@ -6695,14 +6902,28 @@ function DataTableMobileCardView({
6695
6902
  first
6696
6903
  }) {
6697
6904
  const linked = Boolean(LinkComponent && href);
6698
- const handlers = useActivationHandlers({ row, href, activatable, onActivate });
6699
6905
  const content = getMobileCardContent(row);
6700
6906
  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,
6907
+ const leading = selectable || content.leading != null ? /* @__PURE__ */ jsxs33("span", { className: "flex items-center gap-[var(--space-2)]", children: [
6908
+ selectable ? /* @__PURE__ */ jsx37(RowCheckbox, { row, rowId, columns, selected, onToggle }) : null,
6703
6909
  content.leading
6704
6910
  ] }) : void 0;
6705
- return /* @__PURE__ */ jsx36(
6911
+ let title = content.title;
6912
+ if (linked && LinkComponent) {
6913
+ title = /* @__PURE__ */ jsx37(LinkComponent, { href, "data-slot": "data-table-row-link", className: rowLinkClass, children: content.title });
6914
+ } else if (activatable) {
6915
+ title = /* @__PURE__ */ jsx37(
6916
+ "button",
6917
+ {
6918
+ type: "button",
6919
+ "data-slot": "data-table-row-link",
6920
+ className: cn(rowLinkClass, "block w-full text-left"),
6921
+ onClick: (event) => onActivate(row, href, event),
6922
+ children: /* @__PURE__ */ jsx37("span", { className: "line-clamp-2", children: content.title })
6923
+ }
6924
+ );
6925
+ }
6926
+ return /* @__PURE__ */ jsx37(
6706
6927
  "div",
6707
6928
  {
6708
6929
  "data-slot": "data-table-mobile-card",
@@ -6711,37 +6932,35 @@ function DataTableMobileCardView({
6711
6932
  role: "listitem",
6712
6933
  "aria-posinset": ariaPosInSet,
6713
6934
  "aria-setsize": ariaSetSize,
6714
- "aria-label": content.ariaLabel,
6715
- tabIndex: activatable ? 0 : void 0,
6935
+ "aria-label": content.ariaLabel ?? String(content.title),
6716
6936
  className: cn(
6717
6937
  "min-w-0 border-t border-[var(--border-subtle)] transition-colors motion-reduce:transition-none",
6718
6938
  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,
6939
+ navigable ? "cursor-pointer hover:bg-[var(--action-hover)]" : null,
6720
6940
  visuallySelected ? "bg-[var(--action-selected)]" : null,
6721
- linked ? rowLinkHostClass : null
6941
+ navigable ? rowLinkHostClass : null
6722
6942
  ),
6723
6943
  onContextMenu: (event) => onRowContextMenu?.(rowId, event),
6724
- onClick: handlers.onClick,
6725
- onKeyDown: handlers.onKeyDown,
6726
- children: /* @__PURE__ */ jsx36(
6944
+ children: /* @__PURE__ */ jsx37(
6727
6945
  ListCard,
6728
6946
  {
6729
6947
  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,
6948
+ title,
6731
6949
  meta: content.meta ? [content.meta[0], content.meta[1]] : void 0,
6732
6950
  status: content.status,
6733
6951
  caption: content.date,
6734
6952
  value: content.value,
6735
6953
  leading,
6736
- trailing: navigable ? "chevron" : "none"
6954
+ trailing: navigable ? "chevron" : "none",
6955
+ actions: content.actions
6737
6956
  }
6738
6957
  )
6739
6958
  }
6740
6959
  );
6741
6960
  }
6742
- var MemoDataTableRow = React32.memo(DataTableRowView);
6743
- var MemoDataTableMobileCard = React32.memo(DataTableMobileCardView);
6744
- var useIsomorphicLayoutEffect = typeof window === "undefined" ? React32.useEffect : React32.useLayoutEffect;
6961
+ var MemoDataTableRow = React33.memo(DataTableRowView);
6962
+ var MemoDataTableMobileCard = React33.memo(DataTableMobileCardView);
6963
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? React33.useEffect : React33.useLayoutEffect;
6745
6964
  var VIRTUAL_DEFAULT_OVERSCAN = 8;
6746
6965
  var VIRTUAL_INITIAL_ROWS = 24;
6747
6966
  var VIRTUAL_FALLBACK_SIZE = { desktop: 48, mobile: 120 };
@@ -6821,7 +7040,7 @@ function useVirtualWindow({
6821
7040
  mobileListRef
6822
7041
  }) {
6823
7042
  const count = rowIds.length;
6824
- const [win, setWin] = React32.useState({
7043
+ const [win, setWin] = React33.useState({
6825
7044
  layout: null,
6826
7045
  start: 0,
6827
7046
  end: VIRTUAL_INITIAL_ROWS,
@@ -6829,12 +7048,12 @@ function useVirtualWindow({
6829
7048
  padTop: 0,
6830
7049
  padBottom: 0
6831
7050
  });
6832
- const desktopSize = React32.useRef(0);
6833
- const cardHeights = React32.useRef(null);
7051
+ const desktopSize = React33.useRef(0);
7052
+ const cardHeights = React33.useRef(null);
6834
7053
  cardHeights.current ??= new CardHeights();
6835
- const update = React32.useRef(() => void 0);
6836
- const reported = React32.useRef("");
6837
- const latest = React32.useRef({
7054
+ const update = React33.useRef(() => void 0);
7055
+ const reported = React33.useRef("");
7056
+ const latest = React33.useRef({
6838
7057
  count,
6839
7058
  layout: "desktop",
6840
7059
  extent: uniformExtent(VIRTUAL_FALLBACK_SIZE.desktop)
@@ -6897,7 +7116,7 @@ function useVirtualWindow({
6897
7116
  useIsomorphicLayoutEffect(() => {
6898
7117
  update.current();
6899
7118
  });
6900
- React32.useEffect(() => {
7119
+ React33.useEffect(() => {
6901
7120
  if (!enabled) {
6902
7121
  return;
6903
7122
  }
@@ -6919,7 +7138,7 @@ function useVirtualWindow({
6919
7138
  window.cancelAnimationFrame(frame);
6920
7139
  };
6921
7140
  }, [enabled]);
6922
- const scrollToIndex = React32.useCallback(
7141
+ const scrollToIndex = React33.useCallback(
6923
7142
  (index) => {
6924
7143
  const { count: rowCount, layout, extent } = latest.current;
6925
7144
  const list = (layout === "desktop" ? desktopListRef : mobileListRef).current;
@@ -6952,7 +7171,7 @@ function useVisibleLayout({
6952
7171
  desktopRef,
6953
7172
  mobileRef
6954
7173
  }) {
6955
- const [layout, setLayout] = React32.useState(null);
7174
+ const [layout, setLayout] = React33.useState(null);
6956
7175
  useIsomorphicLayoutEffect(() => {
6957
7176
  if (!enabled) {
6958
7177
  return;
@@ -6989,9 +7208,9 @@ function useLayoutFocusHandoff({
6989
7208
  layout,
6990
7209
  containers
6991
7210
  }) {
6992
- const lastFocus = React32.useRef(null);
6993
- const previousLayout = React32.useRef(layout);
6994
- React32.useEffect(() => {
7211
+ const lastFocus = React33.useRef(null);
7212
+ const previousLayout = React33.useRef(layout);
7213
+ React33.useEffect(() => {
6995
7214
  const root = rootRef.current;
6996
7215
  if (!root) {
6997
7216
  return;
@@ -7043,7 +7262,7 @@ function useLayoutFocusHandoff({
7043
7262
  const item = record.rowId ? Array.from(container.querySelectorAll("[data-row-id]")).find(
7044
7263
  (node) => node.getAttribute("data-row-id") === record.rowId
7045
7264
  ) : void 0;
7046
- const target = (item && (record.checkbox ? item.querySelector('[role="checkbox"]') : item.hasAttribute("tabindex") ? item : item.querySelector("a[href]"))) ?? item ?? container;
7265
+ const target = (item && (record.checkbox ? item.querySelector('[role="checkbox"]') : item.hasAttribute("tabindex") ? item : item.querySelector('[data-slot="data-table-row-link"]'))) ?? item ?? container;
7047
7266
  if (target instanceof HTMLElement) {
7048
7267
  if (!target.hasAttribute("tabindex") && !target.matches("a[href],button,input")) {
7049
7268
  target.tabIndex = -1;
@@ -7081,13 +7300,13 @@ function DataTableInner({
7081
7300
  }, ref) {
7082
7301
  const virtualOptions = virtual ? virtual === true ? {} : virtual : null;
7083
7302
  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(
7303
+ const rootRef = React33.useRef(null);
7304
+ const desktopRef = React33.useRef(null);
7305
+ const headerRef = React33.useRef(null);
7306
+ const desktopListRef = React33.useRef(null);
7307
+ const mobileRef = React33.useRef(null);
7308
+ const mobileListRef = React33.useRef(null);
7309
+ const setRootRef = React33.useCallback(
7091
7310
  (node) => {
7092
7311
  rootRef.current = node;
7093
7312
  if (typeof ref === "function") ref(node);
@@ -7106,7 +7325,7 @@ function DataTableInner({
7106
7325
  desktopListRef,
7107
7326
  mobileListRef
7108
7327
  });
7109
- React32.useImperativeHandle(virtualOptions?.handleRef, () => ({ scrollToIndex }), [scrollToIndex]);
7328
+ React33.useImperativeHandle(virtualOptions?.handleRef, () => ({ scrollToIndex }), [scrollToIndex]);
7110
7329
  const visibleLayout = useVisibleLayout({ enabled: !isVirtual, desktopRef, mobileRef });
7111
7330
  const activeLayout = isVirtual ? virtualWindow.layout : visibleLayout;
7112
7331
  useLayoutFocusHandoff({
@@ -7151,19 +7370,19 @@ function DataTableInner({
7151
7370
  window.location.assign(href);
7152
7371
  }
7153
7372
  };
7154
- const latestHandlers = React32.useRef({ toggleRow, activateRow, onRowContextMenu });
7373
+ const latestHandlers = React33.useRef({ toggleRow, activateRow, onRowContextMenu });
7155
7374
  useIsomorphicLayoutEffect(() => {
7156
7375
  latestHandlers.current = { toggleRow, activateRow, onRowContextMenu };
7157
7376
  });
7158
- const stableToggleRow = React32.useCallback(
7377
+ const stableToggleRow = React33.useCallback(
7159
7378
  (id, checked) => latestHandlers.current.toggleRow(id, checked),
7160
7379
  []
7161
7380
  );
7162
- const stableActivateRow = React32.useCallback(
7381
+ const stableActivateRow = React33.useCallback(
7163
7382
  (row, href, event) => latestHandlers.current.activateRow(row, href, event),
7164
7383
  []
7165
7384
  );
7166
- const stableRowContextMenu = React32.useCallback(
7385
+ const stableRowContextMenu = React33.useCallback(
7167
7386
  (rowId, event) => latestHandlers.current.onRowContextMenu?.(rowId, event),
7168
7387
  []
7169
7388
  );
@@ -7215,7 +7434,7 @@ function DataTableInner({
7215
7434
  const mobileSlice = sliceFor("mobile");
7216
7435
  const RowComponent = isVirtual ? MemoDataTableRow : DataTableRowView;
7217
7436
  const CardComponent = isVirtual ? MemoDataTableMobileCard : DataTableMobileCardView;
7218
- return /* @__PURE__ */ jsxs32(
7437
+ return /* @__PURE__ */ jsxs33(
7219
7438
  "div",
7220
7439
  {
7221
7440
  ref: setRootRef,
@@ -7229,7 +7448,7 @@ function DataTableInner({
7229
7448
  ),
7230
7449
  ...props,
7231
7450
  children: [
7232
- selectable && announceSelection ? /* @__PURE__ */ jsx36(
7451
+ selectable && announceSelection ? /* @__PURE__ */ jsx37(
7233
7452
  "div",
7234
7453
  {
7235
7454
  "data-slot": "data-table-selection-status",
@@ -7238,23 +7457,23 @@ function DataTableInner({
7238
7457
  children: selectedCount > 0 ? `${selectedCount.toLocaleString("ko-KR")}${selectionUnit} \uC120\uD0DD\uB428` : ""
7239
7458
  }
7240
7459
  ) : null,
7241
- loading && data.length > 0 ? /* @__PURE__ */ jsx36(
7460
+ loading && data.length > 0 ? /* @__PURE__ */ jsx37(
7242
7461
  "div",
7243
7462
  {
7244
7463
  "data-slot": "data-table-progress",
7245
7464
  "aria-hidden": "true",
7246
7465
  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)]" })
7466
+ children: /* @__PURE__ */ jsx37("div", { className: "h-full w-1/3 animate-pulse bg-[var(--primary)]" })
7248
7467
  }
7249
7468
  ) : null,
7250
- /* @__PURE__ */ jsx36("div", { ref: desktopRef, "data-slot": "data-table-desktop", className: "max-lg:hidden lg:block", children: /* @__PURE__ */ jsxs32(
7469
+ /* @__PURE__ */ jsx37("div", { ref: desktopRef, "data-slot": "data-table-desktop", className: "max-lg:hidden lg:block", children: /* @__PURE__ */ jsxs33(
7251
7470
  "div",
7252
7471
  {
7253
7472
  role: "table",
7254
7473
  "aria-label": ariaLabel,
7255
7474
  "aria-rowcount": isVirtual && data.length > 0 ? data.length + 1 : void 0,
7256
7475
  children: [
7257
- /* @__PURE__ */ jsxs32(
7476
+ /* @__PURE__ */ jsxs33(
7258
7477
  "div",
7259
7478
  {
7260
7479
  ref: headerRef,
@@ -7269,12 +7488,12 @@ function DataTableInner({
7269
7488
  ),
7270
7489
  style: { gridTemplateColumns },
7271
7490
  children: [
7272
- selectable ? /* @__PURE__ */ jsx36("div", { role: "columnheader", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx36(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll: toggleAllRows }) }) : null,
7491
+ selectable ? /* @__PURE__ */ jsx37("div", { role: "columnheader", className: "px-[var(--space-4)]", children: /* @__PURE__ */ jsx37(SelectAllCheckbox, { checked: selectAllChecked, onToggleAll: toggleAllRows }) }) : null,
7273
7492
  columns.map((column) => {
7274
7493
  const align = column.align ?? "left";
7275
7494
  const nextSort = getNextSort(sortBy, column.key);
7276
7495
  const ariaSort = sortBy?.key === column.key ? sortBy.dir === "asc" ? "ascending" : "descending" : void 0;
7277
- return /* @__PURE__ */ jsx36(
7496
+ return /* @__PURE__ */ jsx37(
7278
7497
  "div",
7279
7498
  {
7280
7499
  role: "columnheader",
@@ -7283,7 +7502,7 @@ function DataTableInner({
7283
7502
  "flex min-w-0 items-center gap-[var(--space-1)] px-[var(--space-4)] py-[var(--space-2)]",
7284
7503
  alignmentClass[align]
7285
7504
  ),
7286
- children: column.sortable ? /* @__PURE__ */ jsxs32(
7505
+ children: column.sortable ? /* @__PURE__ */ jsxs33(
7287
7506
  "button",
7288
7507
  {
7289
7508
  type: "button",
@@ -7294,11 +7513,11 @@ function DataTableInner({
7294
7513
  ),
7295
7514
  onClick: () => onSortChange?.(column.key, nextSort),
7296
7515
  children: [
7297
- /* @__PURE__ */ jsx36("span", { className: "truncate", children: column.header }),
7298
- /* @__PURE__ */ jsx36(SortIcon, { sort: sortBy, columnKey: column.key })
7516
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: column.header }),
7517
+ /* @__PURE__ */ jsx37(SortIcon, { sort: sortBy, columnKey: column.key })
7299
7518
  ]
7300
7519
  }
7301
- ) : /* @__PURE__ */ jsx36("span", { className: "truncate", children: column.header })
7520
+ ) : /* @__PURE__ */ jsx37("span", { className: "truncate", children: column.header })
7302
7521
  },
7303
7522
  column.key
7304
7523
  );
@@ -7306,7 +7525,7 @@ function DataTableInner({
7306
7525
  ]
7307
7526
  }
7308
7527
  ),
7309
- loading && data.length === 0 ? /* @__PURE__ */ jsx36(
7528
+ loading && data.length === 0 ? /* @__PURE__ */ jsx37(
7310
7529
  SkeletonRows,
7311
7530
  {
7312
7531
  columns,
@@ -7317,7 +7536,7 @@ function DataTableInner({
7317
7536
  ) : data.length === 0 ? (
7318
7537
  /* role="table" 직계 자식은 row/rowgroup이어야 한다. data-slot과 테두리는
7319
7538
  그대로 유지해 시각 계약을 깨지 않는다(빈 상태에서도 표가 테두리를 그린다). */
7320
- /* @__PURE__ */ jsx36("div", { role: "rowgroup", children: /* @__PURE__ */ jsx36("div", { role: "row", children: /* @__PURE__ */ jsx36(
7539
+ /* @__PURE__ */ jsx37("div", { role: "rowgroup", children: /* @__PURE__ */ jsx37("div", { role: "row", children: /* @__PURE__ */ jsx37(
7321
7540
  "div",
7322
7541
  {
7323
7542
  role: "cell",
@@ -7327,9 +7546,9 @@ function DataTableInner({
7327
7546
  children: emptyState
7328
7547
  }
7329
7548
  ) }) })
7330
- ) : /* @__PURE__ */ jsx36("div", { ref: desktopListRef, role: "rowgroup", style: desktopSlice.style, children: desktopSlice.rows.map((row, index) => {
7549
+ ) : /* @__PURE__ */ jsx37("div", { ref: desktopListRef, role: "rowgroup", style: desktopSlice.style, children: desktopSlice.rows.map((row, index) => {
7331
7550
  const itemProps = getItemProps(row);
7332
- return /* @__PURE__ */ jsx36(
7551
+ return /* @__PURE__ */ jsx37(
7333
7552
  RowComponent,
7334
7553
  {
7335
7554
  ...itemProps,
@@ -7342,8 +7561,8 @@ function DataTableInner({
7342
7561
  ]
7343
7562
  }
7344
7563
  ) }),
7345
- /* @__PURE__ */ jsxs32("div", { ref: mobileRef, "data-slot": "data-table-mobile", className: "lg:hidden", children: [
7346
- /* @__PURE__ */ jsx36(
7564
+ /* @__PURE__ */ jsxs33("div", { ref: mobileRef, "data-slot": "data-table-mobile", className: "lg:hidden", children: [
7565
+ /* @__PURE__ */ jsx37(
7347
7566
  MobileToolbar,
7348
7567
  {
7349
7568
  columns,
@@ -7354,7 +7573,7 @@ function DataTableInner({
7354
7573
  onToggleAll: toggleAllRows
7355
7574
  }
7356
7575
  ),
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(
7576
+ 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
7577
  "div",
7359
7578
  {
7360
7579
  ref: mobileListRef,
@@ -7365,7 +7584,7 @@ function DataTableInner({
7365
7584
  children: mobileSlice.rows.map((row, index) => {
7366
7585
  const itemProps = getItemProps(row);
7367
7586
  const rowIndex = mobileSlice.start + index;
7368
- return /* @__PURE__ */ jsx36(
7587
+ return /* @__PURE__ */ jsx37(
7369
7588
  CardComponent,
7370
7589
  {
7371
7590
  ...itemProps,
@@ -7384,11 +7603,11 @@ function DataTableInner({
7384
7603
  }
7385
7604
  );
7386
7605
  }
7387
- var DataTable = React32.forwardRef(DataTableInner);
7606
+ var DataTable = React33.forwardRef(DataTableInner);
7388
7607
  DataTable.displayName = "DataTable";
7389
7608
 
7390
7609
  // src/components/ui/context-menu.tsx
7391
- import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
7610
+ import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
7392
7611
  function ContextMenu({
7393
7612
  open,
7394
7613
  onOpenChange,
@@ -7399,8 +7618,8 @@ function ContextMenu({
7399
7618
  if (!position) {
7400
7619
  return null;
7401
7620
  }
7402
- return /* @__PURE__ */ jsxs33(DropdownMenu, { open, onOpenChange, modal: false, children: [
7403
- /* @__PURE__ */ jsx37(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx37(
7621
+ return /* @__PURE__ */ jsxs34(DropdownMenu, { open, onOpenChange, modal: false, children: [
7622
+ /* @__PURE__ */ jsx38(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx38(
7404
7623
  "span",
7405
7624
  {
7406
7625
  "aria-hidden": "true",
@@ -7414,19 +7633,19 @@ function ContextMenu({
7414
7633
  }
7415
7634
  }
7416
7635
  ) }),
7417
- /* @__PURE__ */ jsx37(DropdownMenuContent, { ...contentProps, children })
7636
+ /* @__PURE__ */ jsx38(DropdownMenuContent, { ...contentProps, children })
7418
7637
  ] });
7419
7638
  }
7420
7639
 
7421
7640
  // src/components/ui/bulk-action-bar.tsx
7422
- import * as React33 from "react";
7641
+ import * as React34 from "react";
7423
7642
  import { X as X3 } from "lucide-react";
7424
- import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
7643
+ import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
7425
7644
  function ActionButton({ action }) {
7426
7645
  const danger = action.variant === "destructive";
7427
7646
  const off = action.disabled;
7428
7647
  const Icon = action.icon;
7429
- return /* @__PURE__ */ jsxs34(
7648
+ return /* @__PURE__ */ jsxs35(
7430
7649
  "button",
7431
7650
  {
7432
7651
  type: "button",
@@ -7453,7 +7672,7 @@ function ActionButton({ action }) {
7453
7672
  whiteSpace: "nowrap"
7454
7673
  },
7455
7674
  children: [
7456
- Icon ? /* @__PURE__ */ jsx38(
7675
+ Icon ? /* @__PURE__ */ jsx39(
7457
7676
  Icon,
7458
7677
  {
7459
7678
  "aria-hidden": "true",
@@ -7468,7 +7687,7 @@ function ActionButton({ action }) {
7468
7687
  );
7469
7688
  }
7470
7689
  function Divider() {
7471
- return /* @__PURE__ */ jsx38(
7690
+ return /* @__PURE__ */ jsx39(
7472
7691
  "span",
7473
7692
  {
7474
7693
  "aria-hidden": "true",
@@ -7483,7 +7702,7 @@ function Divider() {
7483
7702
  );
7484
7703
  }
7485
7704
  function ClearButton({ onClear }) {
7486
- return /* @__PURE__ */ jsx38(
7705
+ return /* @__PURE__ */ jsx39(
7487
7706
  "button",
7488
7707
  {
7489
7708
  type: "button",
@@ -7505,7 +7724,7 @@ function ClearButton({ onClear }) {
7505
7724
  justifyContent: "center",
7506
7725
  borderRadius: "var(--radius-md)"
7507
7726
  },
7508
- children: /* @__PURE__ */ jsx38(X3, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" })
7727
+ children: /* @__PURE__ */ jsx39(X3, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" })
7509
7728
  }
7510
7729
  );
7511
7730
  }
@@ -7560,10 +7779,10 @@ var idleLineStyle = {
7560
7779
  fontVariantNumeric: "tabular-nums",
7561
7780
  color: "var(--text-secondary)"
7562
7781
  };
7563
- var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React33.useEffect : React33.useLayoutEffect;
7782
+ var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React34.useEffect : React34.useLayoutEffect;
7564
7783
  function useCompactSummary(slot, enabled) {
7565
- const [fullWidth, setFullWidth] = React33.useState(null);
7566
- const measure = React33.useCallback(() => {
7784
+ const [fullWidth, setFullWidth] = React34.useState(null);
7785
+ const measure = React34.useCallback(() => {
7567
7786
  if (!slot) return;
7568
7787
  setFullWidth((prev) => {
7569
7788
  if (prev === null) return slot.scrollWidth > slot.clientWidth ? slot.scrollWidth : null;
@@ -7573,7 +7792,7 @@ function useCompactSummary(slot, enabled) {
7573
7792
  useIsomorphicLayoutEffect2(() => {
7574
7793
  if (enabled) measure();
7575
7794
  });
7576
- React33.useEffect(() => {
7795
+ React34.useEffect(() => {
7577
7796
  if (!enabled || !slot || typeof ResizeObserver === "undefined") return;
7578
7797
  const observer = new ResizeObserver(measure);
7579
7798
  observer.observe(slot);
@@ -7597,7 +7816,7 @@ function BulkActionBar({
7597
7816
  ...props
7598
7817
  }) {
7599
7818
  const inline = placement === "inline";
7600
- const trailingSlot = trailing !== void 0 && trailing !== null ? /* @__PURE__ */ jsx38(
7819
+ const trailingSlot = trailing !== void 0 && trailing !== null ? /* @__PURE__ */ jsx39(
7601
7820
  "div",
7602
7821
  {
7603
7822
  "data-slot": "bulk-action-bar-trailing",
@@ -7610,13 +7829,13 @@ function BulkActionBar({
7610
7829
  children: trailing
7611
7830
  }
7612
7831
  ) : null;
7613
- const [summaryElement, setSummaryElement] = React33.useState(null);
7832
+ const [summaryElement, setSummaryElement] = React34.useState(null);
7614
7833
  const compact = useCompactSummary(
7615
7834
  summaryElement,
7616
7835
  inline && compactSummary !== void 0 && compactSummary !== null
7617
7836
  );
7618
7837
  if (count === 0 && idleContent !== void 0 && trailingSlot) {
7619
- return /* @__PURE__ */ jsxs34(
7838
+ return /* @__PURE__ */ jsxs35(
7620
7839
  "div",
7621
7840
  {
7622
7841
  "data-slot": "bulk-action-bar",
@@ -7626,7 +7845,7 @@ function BulkActionBar({
7626
7845
  style: { ...idleLineStyle, overflow: "visible", ...style },
7627
7846
  ...props,
7628
7847
  children: [
7629
- /* @__PURE__ */ jsx38(
7848
+ /* @__PURE__ */ jsx39(
7630
7849
  "div",
7631
7850
  {
7632
7851
  role: "status",
@@ -7648,7 +7867,7 @@ function BulkActionBar({
7648
7867
  );
7649
7868
  }
7650
7869
  if (count === 0 && idleContent !== void 0) {
7651
- return /* @__PURE__ */ jsx38(
7870
+ return /* @__PURE__ */ jsx39(
7652
7871
  "div",
7653
7872
  {
7654
7873
  role: "status",
@@ -7665,7 +7884,7 @@ function BulkActionBar({
7665
7884
  if (count === 0 && emptyHint === void 0) {
7666
7885
  return null;
7667
7886
  }
7668
- const countLabel = /* @__PURE__ */ jsx38(
7887
+ const countLabel = /* @__PURE__ */ jsx39(
7669
7888
  "span",
7670
7889
  {
7671
7890
  "data-slot": "bulk-action-bar-count",
@@ -7682,7 +7901,7 @@ function BulkActionBar({
7682
7901
  children: count > 0 ? `${count.toLocaleString("ko-KR")}${unit} \uC120\uD0DD\uB428` : emptyHint
7683
7902
  }
7684
7903
  );
7685
- const summarySlot = summary !== void 0 && summary !== null ? /* @__PURE__ */ jsx38(
7904
+ const summarySlot = summary !== void 0 && summary !== null ? /* @__PURE__ */ jsx39(
7686
7905
  "span",
7687
7906
  {
7688
7907
  ref: setSummaryElement,
@@ -7716,7 +7935,7 @@ function BulkActionBar({
7716
7935
  children: compact ? compactSummary : summary
7717
7936
  }
7718
7937
  ) : null;
7719
- const actionGroup = /* @__PURE__ */ jsx38(
7938
+ const actionGroup = /* @__PURE__ */ jsx39(
7720
7939
  "div",
7721
7940
  {
7722
7941
  "data-slot": "bulk-action-bar-actions",
@@ -7728,11 +7947,11 @@ function BulkActionBar({
7728
7947
  justifyContent: "flex-end",
7729
7948
  gap: 2
7730
7949
  },
7731
- children: actions.map((action) => /* @__PURE__ */ jsx38(ActionButton, { action }, action.key))
7950
+ children: actions.map((action) => /* @__PURE__ */ jsx39(ActionButton, { action }, action.key))
7732
7951
  }
7733
7952
  );
7734
7953
  if (inline) {
7735
- return /* @__PURE__ */ jsxs34(
7954
+ return /* @__PURE__ */ jsxs35(
7736
7955
  "div",
7737
7956
  {
7738
7957
  role: "toolbar",
@@ -7743,7 +7962,7 @@ function BulkActionBar({
7743
7962
  style: { ...inlineStyle, ...style },
7744
7963
  ...props,
7745
7964
  children: [
7746
- /* @__PURE__ */ jsxs34(
7965
+ /* @__PURE__ */ jsxs35(
7747
7966
  "div",
7748
7967
  {
7749
7968
  role: "status",
@@ -7761,7 +7980,7 @@ function BulkActionBar({
7761
7980
  ]
7762
7981
  }
7763
7982
  ),
7764
- /* @__PURE__ */ jsxs34(
7983
+ /* @__PURE__ */ jsxs35(
7765
7984
  "div",
7766
7985
  {
7767
7986
  "data-slot": "bulk-action-bar-controls",
@@ -7772,10 +7991,10 @@ function BulkActionBar({
7772
7991
  gap: "var(--space-1)"
7773
7992
  },
7774
7993
  children: [
7775
- count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx38(Divider, {}) : null,
7994
+ count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx39(Divider, {}) : null,
7776
7995
  actionGroup,
7777
- /* @__PURE__ */ jsx38(Divider, {}),
7778
- /* @__PURE__ */ jsx38(ClearButton, { onClear })
7996
+ /* @__PURE__ */ jsx39(Divider, {}),
7997
+ /* @__PURE__ */ jsx39(ClearButton, { onClear })
7779
7998
  ]
7780
7999
  }
7781
8000
  ),
@@ -7784,7 +8003,7 @@ function BulkActionBar({
7784
8003
  }
7785
8004
  );
7786
8005
  }
7787
- return /* @__PURE__ */ jsxs34(
8006
+ return /* @__PURE__ */ jsxs35(
7788
8007
  "div",
7789
8008
  {
7790
8009
  role: "toolbar",
@@ -7799,7 +8018,7 @@ function BulkActionBar({
7799
8018
  style: { ...floatingStyle, ...style },
7800
8019
  ...props,
7801
8020
  children: [
7802
- /* @__PURE__ */ jsxs34(
8021
+ /* @__PURE__ */ jsxs35(
7803
8022
  "div",
7804
8023
  {
7805
8024
  role: "status",
@@ -7816,10 +8035,10 @@ function BulkActionBar({
7816
8035
  ]
7817
8036
  }
7818
8037
  ),
7819
- count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx38(Divider, {}) : null,
8038
+ count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx39(Divider, {}) : null,
7820
8039
  actionGroup,
7821
- /* @__PURE__ */ jsx38(Divider, {}),
7822
- /* @__PURE__ */ jsx38(ClearButton, { onClear }),
8040
+ /* @__PURE__ */ jsx39(Divider, {}),
8041
+ /* @__PURE__ */ jsx39(ClearButton, { onClear }),
7823
8042
  trailingSlot
7824
8043
  ]
7825
8044
  }
@@ -7827,7 +8046,7 @@ function BulkActionBar({
7827
8046
  }
7828
8047
 
7829
8048
  // src/components/ui/confirm-dialog.tsx
7830
- import { jsx as jsx39 } from "react/jsx-runtime";
8049
+ import { jsx as jsx40 } from "react/jsx-runtime";
7831
8050
  function ConfirmDialog({
7832
8051
  open,
7833
8052
  onOpenChange,
@@ -7842,7 +8061,7 @@ function ConfirmDialog({
7842
8061
  confirmDisabled,
7843
8062
  scrim
7844
8063
  }) {
7845
- return /* @__PURE__ */ jsx39(
8064
+ return /* @__PURE__ */ jsx40(
7846
8065
  AlertDialog,
7847
8066
  {
7848
8067
  open,
@@ -7863,14 +8082,14 @@ function ConfirmDialog({
7863
8082
 
7864
8083
  // src/components/ui/separator.tsx
7865
8084
  import { Separator as SeparatorPrimitive } from "radix-ui";
7866
- import { jsx as jsx40 } from "react/jsx-runtime";
8085
+ import { jsx as jsx41 } from "react/jsx-runtime";
7867
8086
  function Separator2({
7868
8087
  className,
7869
8088
  orientation = "horizontal",
7870
8089
  decorative = true,
7871
8090
  ...props
7872
8091
  }) {
7873
- return /* @__PURE__ */ jsx40(
8092
+ return /* @__PURE__ */ jsx41(
7874
8093
  SeparatorPrimitive.Root,
7875
8094
  {
7876
8095
  "data-slot": "separator",
@@ -7887,13 +8106,13 @@ function Separator2({
7887
8106
 
7888
8107
  // src/components/ui/avatar.tsx
7889
8108
  import { Avatar as AvatarPrimitive } from "radix-ui";
7890
- import { jsx as jsx41 } from "react/jsx-runtime";
8109
+ import { jsx as jsx42 } from "react/jsx-runtime";
7891
8110
  function Avatar({
7892
8111
  className,
7893
8112
  size = "md",
7894
8113
  ...props
7895
8114
  }) {
7896
- return /* @__PURE__ */ jsx41(
8115
+ return /* @__PURE__ */ jsx42(
7897
8116
  AvatarPrimitive.Root,
7898
8117
  {
7899
8118
  "data-slot": "avatar",
@@ -7914,7 +8133,7 @@ function AvatarImage({
7914
8133
  className,
7915
8134
  ...props
7916
8135
  }) {
7917
- return /* @__PURE__ */ jsx41(
8136
+ return /* @__PURE__ */ jsx42(
7918
8137
  AvatarPrimitive.Image,
7919
8138
  {
7920
8139
  "data-slot": "avatar-image",
@@ -7939,7 +8158,7 @@ function AvatarFallback({
7939
8158
  ...props
7940
8159
  }) {
7941
8160
  const fallbackText = children ?? (name ? getAvatarFallbackText(name) : null);
7942
- return /* @__PURE__ */ jsx41(
8161
+ return /* @__PURE__ */ jsx42(
7943
8162
  AvatarPrimitive.Fallback,
7944
8163
  {
7945
8164
  "data-slot": "avatar-fallback",
@@ -7958,7 +8177,7 @@ function AvatarFallback({
7958
8177
 
7959
8178
  // src/components/ui/sheet-drawer.tsx
7960
8179
  import { Maximize2Icon, Minimize2Icon } from "lucide-react";
7961
- import { jsx as jsx42, jsxs as jsxs35 } from "react/jsx-runtime";
8180
+ import { jsx as jsx43, jsxs as jsxs36 } from "react/jsx-runtime";
7962
8181
  var expandButtonClassName = cn(
7963
8182
  "inline-flex cursor-pointer items-center justify-center gap-[var(--space-1)]",
7964
8183
  "rounded-[var(--radius-md)] text-text-tertiary transition-colors",
@@ -7993,7 +8212,7 @@ function SheetDrawer({
7993
8212
  const showExpandAction = Boolean(hasExpandedToggle || expandHref || onExpand);
7994
8213
  const resolvedExpandLabel = hasExpandedToggle && expanded ? collapseLabel : expandLabel;
7995
8214
  const ExpandActionIcon = hasExpandedToggle && expanded ? Minimize2Icon : Maximize2Icon;
7996
- const expandAction = showExpandAction ? hasExpandedToggle ? /* @__PURE__ */ jsxs35(
8215
+ const expandAction = showExpandAction ? hasExpandedToggle ? /* @__PURE__ */ jsxs36(
7997
8216
  "button",
7998
8217
  {
7999
8218
  type: "button",
@@ -8004,14 +8223,14 @@ function SheetDrawer({
8004
8223
  className: expandButtonClassName,
8005
8224
  onClick: () => onExpandedChange(!expanded),
8006
8225
  children: [
8007
- /* @__PURE__ */ jsx42(ExpandActionIcon, { className: "size-[16px]" }),
8008
- /* @__PURE__ */ jsx42("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: resolvedExpandLabel })
8226
+ /* @__PURE__ */ jsx43(ExpandActionIcon, { className: "size-[16px]" }),
8227
+ /* @__PURE__ */ jsx43("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: resolvedExpandLabel })
8009
8228
  ]
8010
8229
  }
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(
8230
+ ) : expandHref ? /* @__PURE__ */ jsxs36("a", { href: expandHref, "aria-label": expandLabel, "data-slot": "sheet-drawer-expand", className: expandButtonClassName, children: [
8231
+ /* @__PURE__ */ jsx43(ExpandActionIcon, { className: "size-[16px]" }),
8232
+ /* @__PURE__ */ jsx43("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: expandLabel })
8233
+ ] }) : /* @__PURE__ */ jsxs36(
8015
8234
  "button",
8016
8235
  {
8017
8236
  type: "button",
@@ -8020,12 +8239,12 @@ function SheetDrawer({
8020
8239
  className: expandButtonClassName,
8021
8240
  onClick: onExpand,
8022
8241
  children: [
8023
- /* @__PURE__ */ jsx42(ExpandActionIcon, { className: "size-[16px]" }),
8024
- /* @__PURE__ */ jsx42("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: expandLabel })
8242
+ /* @__PURE__ */ jsx43(ExpandActionIcon, { className: "size-[16px]" }),
8243
+ /* @__PURE__ */ jsx43("span", { className: "hidden text-sm font-medium leading-normal lg:inline", children: expandLabel })
8025
8244
  ]
8026
8245
  }
8027
8246
  ) : void 0;
8028
- return /* @__PURE__ */ jsx42(
8247
+ return /* @__PURE__ */ jsx43(
8029
8248
  Sheet,
8030
8249
  {
8031
8250
  open,
@@ -8043,210 +8262,6 @@ function SheetDrawer({
8043
8262
  );
8044
8263
  }
8045
8264
 
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
8265
  // src/components/ui/action-sheet.tsx
8251
8266
  import { jsx as jsx44 } from "react/jsx-runtime";
8252
8267
  function ActionSheet({
@@ -8539,10 +8554,11 @@ var emptyStateBaseVariants = cva14(
8539
8554
  lg: "gap-[var(--space-4)] px-[var(--space-8)] py-[var(--space-12)]"
8540
8555
  },
8541
8556
  bordered: {
8542
- true: "rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
8557
+ true: "mx-auto w-full max-w-[560px] rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
8543
8558
  false: ""
8544
8559
  }
8545
8560
  },
8561
+ compoundVariants: [{ bordered: true, size: "md", className: "min-h-60" }],
8546
8562
  defaultVariants: {
8547
8563
  size: "md",
8548
8564
  bordered: false
@@ -8592,7 +8608,7 @@ var emptyStateIconVariants = cva14(
8592
8608
  }
8593
8609
  }
8594
8610
  );
8595
- var iconSize3 = {
8611
+ var iconSize2 = {
8596
8612
  sm: 18,
8597
8613
  md: 20,
8598
8614
  lg: 24
@@ -8627,7 +8643,7 @@ var EmptyState = React40.forwardRef(
8627
8643
  "aria-hidden": "true",
8628
8644
  "data-slot": "empty-state-icon",
8629
8645
  className: emptyStateIconVariants({ size: resolvedSize }),
8630
- children: /* @__PURE__ */ jsx50(Icon, { size: iconSize3[resolvedSize], strokeWidth: 1.75 })
8646
+ children: /* @__PURE__ */ jsx50(Icon, { size: iconSize2[resolvedSize], strokeWidth: 1.75 })
8631
8647
  }
8632
8648
  ) : null,
8633
8649
  /* @__PURE__ */ jsxs39("div", { className: "flex max-w-[420px] flex-col items-center gap-[var(--space-2)]", children: [
@@ -8745,7 +8761,7 @@ var ErrorState = React41.forwardRef(
8745
8761
  }
8746
8762
  ) : null
8747
8763
  ] }),
8748
- onRetry ? /* @__PURE__ */ jsx51(Button, { size: "sm", variant: "secondary", onClick: onRetry, children: retryLabel }) : null
8764
+ onRetry ? /* @__PURE__ */ jsx51(Button, { size: "sm", appearance: "outline", tone: "neutral", onClick: onRetry, children: retryLabel }) : null
8749
8765
  ]
8750
8766
  }
8751
8767
  )
@@ -9300,8 +9316,9 @@ var actionFooterStatusVariants = cva19(
9300
9316
  }
9301
9317
  }
9302
9318
  );
9303
- var destructiveVariants = /* @__PURE__ */ new Set(["danger", "destructive", "emergency"]);
9304
- var primaryVariants = /* @__PURE__ */ new Set(["default", "primary"]);
9319
+ var actionStyle = (action) => resolveActionStyle(action.appearance, action.tone, "filled");
9320
+ var isDestructive = (action) => actionStyle(action).tone === "danger";
9321
+ var isPrimary = (action) => actionStyle(action).tone === "primary";
9305
9322
  function canRenderAction(action, permissions) {
9306
9323
  if (!action.permission) {
9307
9324
  return true;
@@ -9313,8 +9330,8 @@ function canRenderAction(action, permissions) {
9313
9330
  }
9314
9331
  function sortMainActions(actions) {
9315
9332
  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;
9333
+ const firstRank = isPrimary(first) ? 1 : 0;
9334
+ const secondRank = isPrimary(second) ? 1 : 0;
9318
9335
  return firstRank - secondRank;
9319
9336
  });
9320
9337
  }
@@ -9330,20 +9347,28 @@ function getStatusLabel(status) {
9330
9347
  }
9331
9348
  }
9332
9349
  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
- );
9350
+ const key = action.id ?? action.label;
9351
+ const common = {
9352
+ className: cn(footerButtonHitAreaClassName, className),
9353
+ disabled: action.disabled,
9354
+ onClick: action.onClick
9355
+ };
9356
+ const style = actionStyle(action);
9357
+ if (action.leadingIcon) {
9358
+ return /* @__PURE__ */ jsx56(
9359
+ IconButton,
9360
+ {
9361
+ ...common,
9362
+ ...style,
9363
+ size: "lg",
9364
+ icon: action.leadingIcon,
9365
+ label: action.label,
9366
+ loading: action.loading
9367
+ },
9368
+ key
9369
+ );
9370
+ }
9371
+ return /* @__PURE__ */ jsx56(Button, { ...common, ...style, size: "lg", loading: action.loading, children: action.label }, key);
9347
9372
  }
9348
9373
  var ActionFooter = React44.forwardRef(
9349
9374
  ({
@@ -9356,12 +9381,8 @@ var ActionFooter = React44.forwardRef(
9356
9381
  ...props
9357
9382
  }, ref) => {
9358
9383
  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
- );
9384
+ const destructiveActions = visibleActions.filter(isDestructive);
9385
+ const mainActions = sortMainActions(visibleActions.filter((action) => !isDestructive(action)));
9365
9386
  return /* @__PURE__ */ jsxs44(
9366
9387
  "div",
9367
9388
  {
@@ -9629,7 +9650,8 @@ var ToastRoot = React45.forwardRef(
9629
9650
  {
9630
9651
  "data-slot": "toast-action",
9631
9652
  size: "xs",
9632
- variant: "secondary",
9653
+ appearance: "outline",
9654
+ tone: "neutral",
9633
9655
  onClick: action.onClick,
9634
9656
  children: action.label
9635
9657
  }
@@ -9684,7 +9706,7 @@ function ToastProvider({ children, maxToasts = 3, className, ...props }) {
9684
9706
  import * as React46 from "react";
9685
9707
  import { cva as cva21 } from "class-variance-authority";
9686
9708
  import { AlertCircle as AlertCircle4 } from "lucide-react";
9687
- import { Fragment as Fragment15, jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
9709
+ import { Fragment as Fragment14, jsx as jsx58, jsxs as jsxs46 } from "react/jsx-runtime";
9688
9710
  var otpFieldVariants = cva21("flex w-full min-w-0 flex-col gap-[var(--space-3)]", {
9689
9711
  variants: {
9690
9712
  size: {
@@ -10006,7 +10028,7 @@ var OTPField = React46.forwardRef(
10006
10028
  "data-slot": "otp-field-message",
10007
10029
  "data-kind": errorText ? "error" : "helper",
10008
10030
  className: otpFieldMessageVariants({ state: resolvedState }),
10009
- children: errorText ? /* @__PURE__ */ jsxs46(Fragment15, { children: [
10031
+ children: errorText ? /* @__PURE__ */ jsxs46(Fragment14, { children: [
10010
10032
  /* @__PURE__ */ jsx58(
10011
10033
  AlertCircle4,
10012
10034
  {
@@ -10100,7 +10122,7 @@ var searchFieldInputVariants = cva22(
10100
10122
  }
10101
10123
  }
10102
10124
  );
10103
- var iconSize4 = {
10125
+ var iconSize3 = {
10104
10126
  sm: 14,
10105
10127
  md: 16,
10106
10128
  lg: 18
@@ -10155,7 +10177,7 @@ var SearchField = React47.forwardRef(
10155
10177
  "aria-hidden": "true",
10156
10178
  "data-slot": "search-field-icon",
10157
10179
  className: "pointer-events-none absolute left-[10px] top-1/2 -translate-y-1/2 text-text-tertiary",
10158
- size: iconSize4[resolvedSize],
10180
+ size: iconSize3[resolvedSize],
10159
10181
  strokeWidth: resolvedSize === "sm" ? 2 : 1.75
10160
10182
  }
10161
10183
  ),
@@ -10872,7 +10894,7 @@ function TreeView({
10872
10894
 
10873
10895
  // src/components/branding/olun-logo.tsx
10874
10896
  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";
10897
+ import { Fragment as Fragment15, jsx as jsx65, jsxs as jsxs51 } from "react/jsx-runtime";
10876
10898
  var ACCENT_FILL = "var(--accent-pop)";
10877
10899
  var INK = { color: "var(--text-primary)" };
10878
10900
  var INK_TIGHT = { ...INK, display: "block", overflow: "visible" };
@@ -10882,7 +10904,7 @@ function symbolGeometry(size) {
10882
10904
  function SymbolCircles({ size }) {
10883
10905
  const { ring } = OLUN_SYMBOL;
10884
10906
  const g = symbolGeometry(size);
10885
- return /* @__PURE__ */ jsxs51(Fragment16, { children: [
10907
+ return /* @__PURE__ */ jsxs51(Fragment15, { children: [
10886
10908
  /* @__PURE__ */ jsx65(
10887
10909
  "circle",
10888
10910
  {