@assure-one/design-system 1.13.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6376,13 +6376,48 @@ var previewVariants = cva("bg-surface flex min-h-0 flex-col overflow-hidden", {
6376
6376
  },
6377
6377
  defaultVariants: { variant: "modal" }
6378
6378
  });
6379
+ var MIN_ZOOM = 0.5;
6380
+ var MAX_ZOOM = 2;
6381
+ var ZOOM_STEP = 0.25;
6382
+ var BASE_PAGE_WIDTH = 820;
6383
+ var clampZoom = (z) => Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, Math.round(z * 100) / 100));
6379
6384
  var headerAction = cn(
6380
6385
  "inline-flex size-7 shrink-0 items-center justify-center",
6381
6386
  "rounded-icon text-fg-4 transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
6382
6387
  "hover:bg-overlay-hover hover:text-fg",
6383
6388
  "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
6384
6389
  );
6385
- var PdfPreview = forwardRef(function PdfPreview2({ src, pages, fileName, onDownload, onClose, variant, className, ...props }, ref) {
6390
+ var zoomAction = cn(
6391
+ "inline-flex size-7 shrink-0 items-center justify-center",
6392
+ "rounded-icon text-fg-3 transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
6393
+ "hover:bg-overlay-hover hover:text-fg",
6394
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none",
6395
+ "disabled:pointer-events-none disabled:opacity-40"
6396
+ );
6397
+ var zoomLabel = cn(
6398
+ "inline-flex h-7 min-w-[3.25rem] items-center justify-center px-2",
6399
+ "rounded-icon text-fg-3 text-xs font-medium tabular-nums",
6400
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
6401
+ "hover:bg-overlay-hover hover:text-fg",
6402
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
6403
+ );
6404
+ var PdfPreview = forwardRef(function PdfPreview2({
6405
+ src,
6406
+ pages,
6407
+ fileName,
6408
+ onDownload,
6409
+ onApprove,
6410
+ approved,
6411
+ onReject,
6412
+ rejected,
6413
+ onClose,
6414
+ variant,
6415
+ zoomable,
6416
+ className,
6417
+ ...props
6418
+ }, ref) {
6419
+ const [zoom, setZoom] = useState(1);
6420
+ const zoomPercent = Math.round(zoom * 100);
6386
6421
  return /* @__PURE__ */ jsxs("div", { ref, className: cn(previewVariants({ variant }), className), ...props, children: [
6387
6422
  fileName && /* @__PURE__ */ jsxs("div", { className: "border-rule bg-surface flex shrink-0 items-center gap-3 border-b px-4 py-3", children: [
6388
6423
  /* @__PURE__ */ jsx(
@@ -6394,7 +6429,56 @@ var PdfPreview = forwardRef(function PdfPreview2({ src, pages, fileName, onDownl
6394
6429
  }
6395
6430
  ),
6396
6431
  /* @__PURE__ */ jsx("span", { className: "text-fg line-clamp-1 flex-1 text-sm font-medium", children: fileName }),
6397
- onDownload && /* @__PURE__ */ jsx("button", { type: "button", onClick: onDownload, "aria-label": "Download", className: headerAction, children: /* @__PURE__ */ jsx(DownloadIcon, { className: "size-4", "aria-hidden": "true" }) }),
6432
+ onApprove && (approved ? /* @__PURE__ */ jsxs("span", { className: "bg-success-bg text-success-fg rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold", children: [
6433
+ /* @__PURE__ */ jsx(CheckIcon, { className: "size-4", "aria-hidden": "true" }),
6434
+ "Approved"
6435
+ ] }) : /* @__PURE__ */ jsxs(
6436
+ "button",
6437
+ {
6438
+ type: "button",
6439
+ onClick: onApprove,
6440
+ className: cn(
6441
+ "rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold",
6442
+ "bg-success-fg text-fg-on-success hover:bg-success-fg-hover active:bg-success-fg-active",
6443
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
6444
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
6445
+ ),
6446
+ children: [
6447
+ /* @__PURE__ */ jsx(CheckIcon, { className: "size-4", "aria-hidden": "true" }),
6448
+ "Approve"
6449
+ ]
6450
+ }
6451
+ )),
6452
+ onReject && (rejected ? /* @__PURE__ */ jsxs("span", { className: "bg-danger-bg text-danger-fg rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold", children: [
6453
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-4", "aria-hidden": "true" }),
6454
+ "Rejected"
6455
+ ] }) : /* @__PURE__ */ jsxs(
6456
+ "button",
6457
+ {
6458
+ type: "button",
6459
+ onClick: onReject,
6460
+ className: cn(
6461
+ "rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold",
6462
+ "bg-danger-fg text-fg-on-danger hover:bg-danger-fg-hover active:bg-danger-fg-active",
6463
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
6464
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
6465
+ ),
6466
+ children: [
6467
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-4", "aria-hidden": "true" }),
6468
+ "Reject"
6469
+ ]
6470
+ }
6471
+ )),
6472
+ onDownload && /* @__PURE__ */ jsx(
6473
+ "button",
6474
+ {
6475
+ type: "button",
6476
+ onClick: onDownload,
6477
+ "aria-label": "Download",
6478
+ className: headerAction,
6479
+ children: /* @__PURE__ */ jsx(DownloadIcon, { className: "size-4", "aria-hidden": "true" })
6480
+ }
6481
+ ),
6398
6482
  onClose && /* @__PURE__ */ jsx("button", { type: "button", onClick: onClose, "aria-label": "Close", className: headerAction, children: /* @__PURE__ */ jsx(XIcon, { className: "size-4", "aria-hidden": "true" }) })
6399
6483
  ] }),
6400
6484
  src ? /* @__PURE__ */ jsx(
@@ -6404,15 +6488,72 @@ var PdfPreview = forwardRef(function PdfPreview2({ src, pages, fileName, onDownl
6404
6488
  title: fileName ?? "PDF preview",
6405
6489
  className: "bg-bg-2 min-h-0 flex-1 border-0"
6406
6490
  }
6407
- ) : pages && pages.length > 0 ? /* @__PURE__ */ jsx("div", { className: "scrollbar-thin bg-bg-2 min-h-0 flex-1 overflow-auto p-4 sm:p-6", children: /* @__PURE__ */ jsx("div", { className: "mx-auto flex max-w-[820px] flex-col gap-4", children: pages.map((page, i) => /* @__PURE__ */ jsx(
6408
- "img",
6409
- {
6410
- src: page,
6411
- alt: `Page ${i + 1}`,
6412
- className: "rounded-input border-rule shadow-card bg-surface w-full border"
6413
- },
6414
- i
6415
- )) }) }) : /* @__PURE__ */ jsxs("div", { className: "bg-bg-2 text-fg-4 flex min-h-0 flex-1 flex-col items-center justify-center gap-2 p-8", children: [
6491
+ ) : pages && pages.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
6492
+ /* @__PURE__ */ jsx("div", { className: "scrollbar-thin bg-bg-2 min-h-0 flex-1 overflow-auto p-4 sm:p-6", children: /* @__PURE__ */ jsx(
6493
+ "div",
6494
+ {
6495
+ className: cn("mx-auto flex flex-col gap-4", !zoomable && "max-w-[820px]"),
6496
+ style: zoomable ? {
6497
+ width: Math.round(BASE_PAGE_WIDTH * zoom),
6498
+ maxWidth: zoom <= 1 ? "100%" : void 0
6499
+ } : void 0,
6500
+ children: pages.map((page, i) => /* @__PURE__ */ jsx(
6501
+ "img",
6502
+ {
6503
+ src: page,
6504
+ alt: `Page ${i + 1}`,
6505
+ className: "rounded-input border-rule shadow-card bg-surface w-full border"
6506
+ },
6507
+ i
6508
+ ))
6509
+ }
6510
+ ) }),
6511
+ zoomable && /* @__PURE__ */ jsxs(
6512
+ "div",
6513
+ {
6514
+ role: "group",
6515
+ "aria-label": "Zoom controls",
6516
+ className: "border-rule bg-surface shadow-pop rounded-pill absolute bottom-4 left-1/2 flex -translate-x-1/2 items-center gap-0.5 border p-1",
6517
+ children: [
6518
+ /* @__PURE__ */ jsx(
6519
+ "button",
6520
+ {
6521
+ type: "button",
6522
+ onClick: () => setZoom((z) => clampZoom(z - ZOOM_STEP)),
6523
+ disabled: zoom <= MIN_ZOOM,
6524
+ "aria-label": "Zoom out",
6525
+ className: zoomAction,
6526
+ children: /* @__PURE__ */ jsx(ZoomOutIcon, { className: "size-4", "aria-hidden": "true" })
6527
+ }
6528
+ ),
6529
+ /* @__PURE__ */ jsxs(
6530
+ "button",
6531
+ {
6532
+ type: "button",
6533
+ onClick: () => setZoom(1),
6534
+ "aria-label": `Zoom ${zoomPercent}%, reset to 100%`,
6535
+ className: zoomLabel,
6536
+ children: [
6537
+ zoomPercent,
6538
+ "%"
6539
+ ]
6540
+ }
6541
+ ),
6542
+ /* @__PURE__ */ jsx(
6543
+ "button",
6544
+ {
6545
+ type: "button",
6546
+ onClick: () => setZoom((z) => clampZoom(z + ZOOM_STEP)),
6547
+ disabled: zoom >= MAX_ZOOM,
6548
+ "aria-label": "Zoom in",
6549
+ className: zoomAction,
6550
+ children: /* @__PURE__ */ jsx(ZoomInIcon, { className: "size-4", "aria-hidden": "true" })
6551
+ }
6552
+ )
6553
+ ]
6554
+ }
6555
+ )
6556
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "bg-bg-2 text-fg-4 flex min-h-0 flex-1 flex-col items-center justify-center gap-2 p-8", children: [
6416
6557
  /* @__PURE__ */ jsx(FileTextIcon, { className: "size-8", "aria-hidden": "true" }),
6417
6558
  /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No preview available" })
6418
6559
  ] })
@@ -8271,6 +8412,10 @@ var SpreadsheetPreview = forwardRef(
8271
8412
  minColumns = 0,
8272
8413
  fileName,
8273
8414
  onDownload,
8415
+ onApprove,
8416
+ approved,
8417
+ onReject,
8418
+ rejected,
8274
8419
  onClose,
8275
8420
  variant,
8276
8421
  className,
@@ -8291,6 +8436,46 @@ var SpreadsheetPreview = forwardRef(
8291
8436
  }
8292
8437
  ),
8293
8438
  /* @__PURE__ */ jsx("span", { className: "text-fg line-clamp-1 flex-1 text-sm font-medium", children: fileName }),
8439
+ onApprove && (approved ? /* @__PURE__ */ jsxs("span", { className: "bg-success-bg text-success-fg rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold", children: [
8440
+ /* @__PURE__ */ jsx(CheckIcon, { className: "size-4", "aria-hidden": "true" }),
8441
+ "Approved"
8442
+ ] }) : /* @__PURE__ */ jsxs(
8443
+ "button",
8444
+ {
8445
+ type: "button",
8446
+ onClick: onApprove,
8447
+ className: cn(
8448
+ "rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold",
8449
+ "bg-success-fg text-fg-on-success hover:bg-success-fg-hover active:bg-success-fg-active",
8450
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
8451
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
8452
+ ),
8453
+ children: [
8454
+ /* @__PURE__ */ jsx(CheckIcon, { className: "size-4", "aria-hidden": "true" }),
8455
+ "Approve"
8456
+ ]
8457
+ }
8458
+ )),
8459
+ onReject && (rejected ? /* @__PURE__ */ jsxs("span", { className: "bg-danger-bg text-danger-fg rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold", children: [
8460
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-4", "aria-hidden": "true" }),
8461
+ "Rejected"
8462
+ ] }) : /* @__PURE__ */ jsxs(
8463
+ "button",
8464
+ {
8465
+ type: "button",
8466
+ onClick: onReject,
8467
+ className: cn(
8468
+ "rounded-icon inline-flex h-7 shrink-0 items-center gap-1.5 px-2.5 text-xs font-semibold",
8469
+ "bg-danger-fg text-fg-on-danger hover:bg-danger-fg-hover active:bg-danger-fg-active",
8470
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
8471
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
8472
+ ),
8473
+ children: [
8474
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-4", "aria-hidden": "true" }),
8475
+ "Reject"
8476
+ ]
8477
+ }
8478
+ )),
8294
8479
  onDownload && /* @__PURE__ */ jsx(
8295
8480
  "button",
8296
8481
  {
@@ -8332,7 +8517,7 @@ var SpreadsheetPreview = forwardRef(
8332
8517
  /* @__PURE__ */ jsx(
8333
8518
  "th",
8334
8519
  {
8335
- className: cn(headerCell, "left-0 top-0 z-20 w-11 min-w-11"),
8520
+ className: cn(headerCell, "top-0 left-0 z-20 w-11 min-w-11"),
8336
8521
  "aria-hidden": "true"
8337
8522
  }
8338
8523
  ),
@@ -8362,8 +8547,8 @@ var SpreadsheetPreview = forwardRef(
8362
8547
  "td",
8363
8548
  {
8364
8549
  className: cn(
8365
- "border-rule-soft text-fg border-b border-r",
8366
- "h-8 min-w-[88px] max-w-[260px] truncate px-3 text-sm",
8550
+ "border-rule-soft text-fg border-r border-b",
8551
+ "h-8 max-w-[260px] min-w-[88px] truncate px-3 text-sm",
8367
8552
  typeof data?.[r]?.[c] === "number" && "text-right tabular-nums"
8368
8553
  ),
8369
8554
  children: data?.[r]?.[c] ?? ""
@@ -9493,19 +9678,17 @@ function ToastProvider({ children }) {
9493
9678
  setToasts((prev) => prev.filter((t) => t.id !== id));
9494
9679
  }, []);
9495
9680
  const addToast = useCallback((options) => {
9496
- const variant = options.variant ?? "default";
9497
- const duration = options.duration ?? (variant === "loading" ? 0 : DEFAULT_DURATION);
9498
9681
  const id = `toast-${++toastCount}`;
9499
9682
  setToasts((prev) => {
9500
9683
  if (options.dedupeKey) {
9501
9684
  const existing = prev.find((t) => t.dedupeKey === options.dedupeKey);
9502
9685
  if (existing) {
9503
9686
  return prev.map(
9504
- (t) => t.dedupeKey === options.dedupeKey ? { ...t, ...options, variant, duration, seq: t.seq + 1 } : t
9687
+ (t) => t.dedupeKey === options.dedupeKey ? { ...t, ...options, seq: t.seq + 1 } : t
9505
9688
  );
9506
9689
  }
9507
9690
  }
9508
- return [...prev, { id, seq: 0, ...options, variant, duration }];
9691
+ return [...prev, { id, seq: 0, ...options }];
9509
9692
  });
9510
9693
  return id;
9511
9694
  }, []);
@@ -9513,9 +9696,8 @@ function ToastProvider({ children }) {
9513
9696
  setToasts(
9514
9697
  (prev) => prev.map((t) => {
9515
9698
  if (t.id !== id) return t;
9516
- const variant = patch.variant ?? t.variant;
9517
9699
  const duration = patch.duration ?? (patch.variant && patch.variant !== "loading" ? DEFAULT_DURATION : t.duration);
9518
- return { ...t, ...patch, variant, duration, seq: t.seq + 1 };
9700
+ return { ...t, ...patch, duration, seq: t.seq + 1 };
9519
9701
  })
9520
9702
  );
9521
9703
  }, []);
@@ -9556,79 +9738,89 @@ function ToastProvider({ children }) {
9556
9738
  ] });
9557
9739
  }
9558
9740
  var variantConfig = {
9559
- default: { chip: "bg-pro-bg", icon: "text-pro-fg", bar: "bg-pro-fg", Icon: InfoCircleSolidIcon },
9741
+ default: {
9742
+ chip: "bg-pro-bg",
9743
+ icon: "text-pro-fg",
9744
+ stroke: "stroke-pro-fg",
9745
+ ring: "ring-pro-fg/15",
9746
+ Icon: InfoCircleSolidIcon
9747
+ },
9560
9748
  success: {
9561
9749
  chip: "bg-success-bg",
9562
9750
  icon: "text-success-fg",
9563
- bar: "bg-success-fg",
9751
+ stroke: "stroke-success-fg",
9752
+ ring: "ring-success-fg/15",
9564
9753
  Icon: CheckCircleSolidIcon
9565
9754
  },
9566
9755
  destructive: {
9567
9756
  chip: "bg-danger-bg",
9568
9757
  icon: "text-danger-fg",
9569
- bar: "bg-danger-fg",
9758
+ stroke: "stroke-danger-fg",
9759
+ ring: "ring-danger-fg/15",
9570
9760
  Icon: XCircleSolidIcon
9571
9761
  },
9572
9762
  warning: {
9573
9763
  chip: "bg-warning-bg",
9574
9764
  icon: "text-warning-fg",
9575
- bar: "bg-warning-fg",
9765
+ stroke: "stroke-warning-fg",
9766
+ ring: "ring-warning-fg/20",
9576
9767
  Icon: AlertTriangleSolidIcon
9577
9768
  },
9578
9769
  info: {
9579
9770
  chip: "bg-info/12",
9580
9771
  icon: "text-info",
9581
- bar: "bg-info",
9772
+ stroke: "stroke-info",
9773
+ ring: "ring-info/15",
9582
9774
  Icon: InfoCircleSolidIcon
9583
9775
  },
9584
9776
  loading: {
9585
9777
  chip: "bg-pro-bg",
9586
9778
  icon: "text-pro-fg",
9587
- bar: "bg-pro-fg",
9779
+ stroke: "stroke-pro-fg",
9780
+ ring: "ring-pro-fg/15",
9588
9781
  Icon: LoaderIcon,
9589
9782
  spin: true
9590
9783
  }
9591
9784
  };
9785
+ var RING_RADIUS2 = 11;
9786
+ var RING_CIRCUMFERENCE = 2 * Math.PI * RING_RADIUS2;
9592
9787
  var SWIPE_DISMISS_PX = 72;
9593
9788
  function ToastItem({ toast, onDismiss }) {
9594
- const [exiting, setExiting] = useState(false);
9789
+ const timerRef = useRef(void 0);
9790
+ const remainingRef = useRef(toast.duration ?? DEFAULT_DURATION);
9791
+ const startedAtRef = useRef(0);
9595
9792
  const cardRef = useRef(null);
9596
- const barRef = useRef(null);
9597
- const pausedRef = useRef(false);
9598
- const duration = toast.duration;
9599
- const showProgress = duration > 0;
9793
+ const [exiting, setExiting] = useState(false);
9794
+ const [paused, setPaused] = useState(false);
9795
+ const hasContent = toast.content != null;
9796
+ const duration = toast.duration ?? DEFAULT_DURATION;
9797
+ const isLoading = (toast.variant ?? "default") === "loading";
9798
+ const autoDismiss = duration > 0 && !hasContent && !isLoading;
9799
+ const isError = (toast.variant ?? "default") === "destructive";
9600
9800
  const close = useCallback(() => {
9601
9801
  setExiting(true);
9602
9802
  setTimeout(() => onDismiss(toast.id), 150);
9603
9803
  }, [toast.id, onDismiss]);
9604
9804
  useEffect(() => {
9605
- if (!showProgress) return;
9606
- let raf = 0;
9607
- let remaining = duration;
9608
- let last = performance.now();
9609
- const tick = (now) => {
9610
- const dt = now - last;
9611
- last = now;
9612
- if (!pausedRef.current) {
9613
- remaining -= dt;
9614
- if (barRef.current) {
9615
- barRef.current.style.width = `${Math.max(0, Math.min(100, (duration - remaining) / duration * 100))}%`;
9616
- }
9617
- if (remaining <= 0) {
9618
- close();
9619
- return;
9620
- }
9621
- }
9622
- raf = requestAnimationFrame(tick);
9805
+ remainingRef.current = toast.duration ?? DEFAULT_DURATION;
9806
+ }, [toast.seq, toast.duration]);
9807
+ useEffect(() => {
9808
+ if (!autoDismiss || exiting || paused) return;
9809
+ startedAtRef.current = Date.now();
9810
+ timerRef.current = setTimeout(close, remainingRef.current);
9811
+ return () => {
9812
+ clearTimeout(timerRef.current);
9813
+ remainingRef.current = Math.max(
9814
+ 0,
9815
+ remainingRef.current - (Date.now() - startedAtRef.current)
9816
+ );
9623
9817
  };
9624
- raf = requestAnimationFrame(tick);
9625
- return () => cancelAnimationFrame(raf);
9626
- }, [duration, showProgress, close, toast.seq]);
9818
+ }, [autoDismiss, exiting, paused, close, toast.seq]);
9627
9819
  const dragRef = useRef(null);
9628
9820
  const onPointerDown = (e) => {
9629
- if (e.target.closest("button")) return;
9821
+ if (e.target.closest("button, a, input, textarea")) return;
9630
9822
  dragRef.current = { startX: e.clientX, dx: 0 };
9631
- pausedRef.current = true;
9823
+ setPaused(true);
9632
9824
  cardRef.current?.setPointerCapture(e.pointerId);
9633
9825
  };
9634
9826
  const onPointerMove = (e) => {
@@ -9649,101 +9841,151 @@ function ToastItem({ toast, onDismiss }) {
9649
9841
  }
9650
9842
  cardRef.current.style.transform = "";
9651
9843
  cardRef.current.style.opacity = "";
9652
- pausedRef.current = false;
9844
+ setPaused(false);
9653
9845
  };
9654
- const { chip, icon, bar, Icon: Icon3, spin } = variantConfig[toast.variant];
9655
- return (
9656
- // Pointer/hover handlers add pause-on-hover + swipe-to-dismiss as progressive
9657
- // enhancement only — keyboard/AT users dismiss via the explicit Dismiss
9658
- // button below, and the live region (role=status) still announces content.
9659
- // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
9660
- /* @__PURE__ */ jsxs(
9661
- "div",
9662
- {
9663
- ref: cardRef,
9664
- role: "status",
9665
- "data-state": exiting ? "closed" : "open",
9666
- onPointerDown,
9667
- onPointerMove,
9668
- onPointerUp: endDrag,
9669
- onPointerCancel: endDrag,
9670
- onMouseEnter: () => {
9671
- pausedRef.current = true;
9672
- },
9673
- onMouseLeave: () => {
9674
- if (!dragRef.current) pausedRef.current = false;
9675
- },
9676
- onFocusCapture: () => {
9677
- pausedRef.current = true;
9678
- },
9679
- onBlurCapture: () => {
9680
- if (!dragRef.current) pausedRef.current = false;
9681
- },
9682
- className: cn(
9683
- "bg-surface border-rule text-fg rounded-card shadow-card pointer-events-auto relative w-80 touch-none overflow-hidden border p-4",
9684
- "font-body select-none",
9685
- // Unified data-state animation (spec §5.27) same model as Dialog/Tooltip:
9686
- // open → fade+slide in over --duration-overlay (200ms), ease-out-quart
9687
- // close → fade+slide out over --duration-fast (150ms), ease-in
9688
- "data-[state=open]:animate-in data-[state=open]:slide-in-from-right-8 data-[state=open]:fade-in-0",
9689
- "data-[state=open]:duration-[var(--duration-overlay)] data-[state=open]:ease-[var(--ease-out-quart)]",
9690
- "data-[state=closed]:animate-out data-[state=closed]:slide-out-to-right-8 data-[state=closed]:fade-out-0",
9691
- "data-[state=closed]:duration-[var(--duration-fast)] data-[state=closed]:ease-[var(--ease-in)]",
9692
- "motion-reduce:animate-none"
9846
+ const { chip, icon, stroke, ring, Icon: Icon3, spin } = variantConfig[toast.variant ?? "default"];
9847
+ return /* @__PURE__ */ jsx(
9848
+ "div",
9849
+ {
9850
+ ref: cardRef,
9851
+ role: hasContent ? "group" : isError ? "alert" : "status",
9852
+ "aria-atomic": hasContent ? void 0 : true,
9853
+ "data-state": exiting ? "closed" : "open",
9854
+ onPointerEnter: () => setPaused(true),
9855
+ onPointerLeave: () => {
9856
+ if (!dragRef.current) setPaused(false);
9857
+ },
9858
+ onPointerDown,
9859
+ onPointerMove,
9860
+ onPointerUp: endDrag,
9861
+ onPointerCancel: endDrag,
9862
+ onFocusCapture: () => setPaused(true),
9863
+ onBlurCapture: () => {
9864
+ if (!dragRef.current) setPaused(false);
9865
+ },
9866
+ className: cn(
9867
+ "bg-surface border-rule text-fg rounded-card shadow-card pointer-events-auto relative w-80 max-w-[calc(100vw-2rem)] touch-none overflow-hidden border",
9868
+ // Title-mode padding; rich content owns its own internal padding.
9869
+ hasContent ? "" : "p-4",
9870
+ "font-body select-none",
9871
+ // Tactile lift on hover/focus — signals the card is interactive and
9872
+ // that its countdown is held. Shadow only (not motion), so it needs no
9873
+ // reduced-motion fallback; the named property keeps us off transition-all.
9874
+ "transition-shadow duration-[var(--duration-fast)] ease-[var(--ease-out-quart)]",
9875
+ "hover:shadow-lg focus-within:shadow-lg motion-reduce:transition-none",
9876
+ // Unified data-state animation (spec §5.27) — same model as Dialog/Tooltip,
9877
+ // with a subtle zoom so the toast *pops* in rather than just appearing:
9878
+ // open → fade + slide-from-right + zoom-from-95 over --duration-normal (250ms), ease-out-quart
9879
+ // close → fade + slide-to-right + zoom-to-95 over --duration-fast (150ms), ease-in
9880
+ "data-[state=open]:animate-in data-[state=open]:slide-in-from-right-8 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
9881
+ "data-[state=open]:duration-[var(--duration-normal)] data-[state=open]:ease-[var(--ease-out-quart)]",
9882
+ "data-[state=closed]:animate-out data-[state=closed]:slide-out-to-right-8 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
9883
+ "data-[state=closed]:duration-[var(--duration-fast)] data-[state=closed]:ease-[var(--ease-in)]",
9884
+ "motion-reduce:animate-none"
9885
+ ),
9886
+ children: hasContent ? typeof toast.content === "function" ? toast.content(close) : toast.content : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
9887
+ /* @__PURE__ */ jsx(
9888
+ "span",
9889
+ {
9890
+ className: cn(
9891
+ // Same-hue inset ring gives the tinted chip a crafted edge instead
9892
+ // of a flat fill — definition without a heavy border.
9893
+ "inline-flex size-8 shrink-0 items-center justify-center rounded-[9px] ring-1 ring-inset",
9894
+ // Staggered pop — chip scales in ~80ms after the card lands so the
9895
+ // status glyph "arrives". motion-safe only; reduced motion shows it
9896
+ // at rest with no entrance.
9897
+ "motion-safe:animate-[toast-chip-in_280ms_var(--ease-out-quart)_80ms_both]",
9898
+ chip,
9899
+ icon,
9900
+ ring
9901
+ ),
9902
+ "aria-hidden": "true",
9903
+ children: /* @__PURE__ */ jsx(Icon3, { className: cn("size-5", spin && "animate-spin motion-reduce:animate-none") })
9904
+ }
9693
9905
  ),
9694
- children: [
9695
- /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
9696
- /* @__PURE__ */ jsx(
9697
- "span",
9698
- {
9699
- className: cn(
9700
- "inline-flex size-8 shrink-0 items-center justify-center rounded-[9px]",
9701
- chip,
9702
- icon
9703
- ),
9704
- "aria-hidden": "true",
9705
- children: /* @__PURE__ */ jsx(Icon3, { className: cn("size-5", spin && "animate-spin motion-reduce:animate-none") })
9706
- }
9906
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
9907
+ toast.title && /* @__PURE__ */ jsx("p", { className: "text-fg text-sm leading-tight font-semibold", children: toast.title }),
9908
+ toast.description && /* @__PURE__ */ jsx("p", { className: "text-fg-3 mt-0.5 text-sm leading-snug", children: toast.description }),
9909
+ toast.action && /* @__PURE__ */ jsx(
9910
+ "button",
9911
+ {
9912
+ type: "button",
9913
+ onClick: () => {
9914
+ toast.action?.onClick();
9915
+ close();
9916
+ },
9917
+ className: cn(
9918
+ "text-pro-fg mt-2 text-sm font-semibold",
9919
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] hover:underline motion-reduce:transition-none",
9920
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] rounded-sm focus-visible:outline-none"
9921
+ ),
9922
+ children: toast.action.label
9923
+ }
9924
+ )
9925
+ ] }),
9926
+ /* @__PURE__ */ jsxs(
9927
+ "button",
9928
+ {
9929
+ type: "button",
9930
+ onClick: close,
9931
+ className: cn(
9932
+ // size-7 click target with a -m-1 offset so the glyph keeps its
9933
+ // top-right optical position while the hit area (and ring) grow.
9934
+ "text-fg-4 hover:text-fg-2 hover:bg-overlay-hover relative -mt-1 -mr-1 inline-flex size-7 shrink-0 items-center justify-center rounded-full",
9935
+ "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
9936
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
9707
9937
  ),
9708
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
9709
- /* @__PURE__ */ jsx("p", { className: "text-fg text-sm leading-tight font-semibold", children: toast.title }),
9710
- toast.description && /* @__PURE__ */ jsx("p", { className: "text-fg-3 mt-0.5 text-sm leading-snug", children: toast.description }),
9711
- toast.action && /* @__PURE__ */ jsx(
9712
- "button",
9938
+ "aria-label": "Dismiss",
9939
+ children: [
9940
+ autoDismiss && // Countdown drains as a ring hugging the dismiss button the timer
9941
+ // and the close affordance share one spot. Pauses in lockstep with
9942
+ // the JS timer (animation-play-state). Hidden under reduced motion;
9943
+ // the timer still governs dismissal.
9944
+ /* @__PURE__ */ jsxs(
9945
+ "svg",
9713
9946
  {
9714
- type: "button",
9715
- onClick: () => {
9716
- toast.action?.onClick();
9717
- close();
9718
- },
9719
- className: cn(
9720
- "text-pro-fg mt-2 text-sm font-semibold",
9721
- "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] hover:underline motion-reduce:transition-none",
9722
- "focus-visible:[box-shadow:var(--shadow-focus-ring)] rounded-sm focus-visible:outline-none"
9723
- ),
9724
- children: toast.action.label
9947
+ viewBox: "0 0 28 28",
9948
+ className: "pointer-events-none absolute inset-0 size-7 -rotate-90 motion-reduce:hidden",
9949
+ "aria-hidden": "true",
9950
+ children: [
9951
+ /* @__PURE__ */ jsx(
9952
+ "circle",
9953
+ {
9954
+ cx: "14",
9955
+ cy: "14",
9956
+ r: RING_RADIUS2,
9957
+ fill: "none",
9958
+ strokeWidth: "2",
9959
+ className: "stroke-rule"
9960
+ }
9961
+ ),
9962
+ /* @__PURE__ */ jsx(
9963
+ "circle",
9964
+ {
9965
+ cx: "14",
9966
+ cy: "14",
9967
+ r: RING_RADIUS2,
9968
+ fill: "none",
9969
+ strokeWidth: "2",
9970
+ strokeLinecap: "round",
9971
+ className: cn("opacity-90", stroke),
9972
+ style: {
9973
+ strokeDasharray: RING_CIRCUMFERENCE,
9974
+ "--toast-ring-circ": RING_CIRCUMFERENCE,
9975
+ animation: `toast-ring-drain ${duration}ms linear forwards`,
9976
+ animationPlayState: paused ? "paused" : "running"
9977
+ }
9978
+ }
9979
+ )
9980
+ ]
9725
9981
  }
9726
- )
9727
- ] }),
9728
- /* @__PURE__ */ jsx(
9729
- "button",
9730
- {
9731
- type: "button",
9732
- onClick: close,
9733
- className: cn(
9734
- "text-fg-4 hover:text-fg-2 rounded-icon -mr-1 inline-flex size-5 shrink-0 items-center justify-center",
9735
- "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
9736
- "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
9737
- ),
9738
- "aria-label": "Dismiss",
9739
- children: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5", "aria-hidden": "true" })
9740
- }
9741
- )
9742
- ] }),
9743
- showProgress && /* @__PURE__ */ jsx("div", { className: "bg-rule absolute inset-x-0 bottom-0 h-1", "aria-hidden": "true", children: /* @__PURE__ */ jsx("div", { ref: barRef, className: cn("h-full", bar), style: { width: "0%" } }) })
9744
- ]
9745
- }
9746
- )
9982
+ ),
9983
+ /* @__PURE__ */ jsx(XIcon, { className: "relative size-3.5", "aria-hidden": "true" })
9984
+ ]
9985
+ }
9986
+ )
9987
+ ] }) })
9988
+ }
9747
9989
  );
9748
9990
  }
9749
9991
  var itemVariants = cva(
@@ -13866,36 +14108,36 @@ var DocumentDetailPanel = forwardRef(
13866
14108
  DocumentDetailPanel.displayName = "DocumentDetailPanel";
13867
14109
  var DocumentDetailHeader = forwardRef(
13868
14110
  function DocumentDetailHeader2({ tags, status, onClose, className, children, ...props }, ref) {
13869
- const showBar = tags || status || onClose;
14111
+ const showControls = Boolean(status || onClose);
14112
+ const tagsClearance = !showControls ? void 0 : status ? "pr-32" : "pr-12";
14113
+ const titleClearance = !showControls || tags ? void 0 : status ? "[&>:first-child]:pr-32" : "[&>:first-child]:pr-12";
13870
14114
  return /* @__PURE__ */ jsxs(
13871
14115
  "div",
13872
14116
  {
13873
14117
  ref,
13874
- className: cn("border-rule shrink-0 space-y-3 border-b px-5 py-4", className),
14118
+ className: cn("border-rule relative shrink-0 space-y-3 border-b px-5 py-4", className),
13875
14119
  ...props,
13876
14120
  children: [
13877
- showBar && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
13878
- /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-wrap items-center gap-1.5", children: tags }),
13879
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
13880
- status,
13881
- onClose && /* @__PURE__ */ jsx(
13882
- "button",
13883
- {
13884
- type: "button",
13885
- onClick: onClose,
13886
- "aria-label": "Close",
13887
- className: cn(
13888
- "inline-flex size-7 shrink-0 items-center justify-center",
13889
- "rounded-icon text-fg-4 transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
13890
- "hover:bg-overlay-hover hover:text-fg",
13891
- "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
13892
- ),
13893
- children: /* @__PURE__ */ jsx(XIcon, { className: "size-4", "aria-hidden": "true" })
13894
- }
13895
- )
13896
- ] })
14121
+ showControls && /* @__PURE__ */ jsxs("div", { className: "absolute top-4 right-5 z-10 flex shrink-0 items-center gap-2", children: [
14122
+ status,
14123
+ onClose && /* @__PURE__ */ jsx(
14124
+ "button",
14125
+ {
14126
+ type: "button",
14127
+ onClick: onClose,
14128
+ "aria-label": "Close",
14129
+ className: cn(
14130
+ "inline-flex size-7 shrink-0 items-center justify-center",
14131
+ "rounded-icon text-fg-4 transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
14132
+ "hover:bg-overlay-hover hover:text-fg",
14133
+ "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none"
14134
+ ),
14135
+ children: /* @__PURE__ */ jsx(XIcon, { className: "size-4", "aria-hidden": "true" })
14136
+ }
14137
+ )
13897
14138
  ] }),
13898
- children
14139
+ tags && /* @__PURE__ */ jsx("div", { className: cn("flex min-w-0 flex-wrap items-center gap-1.5", tagsClearance), children: tags }),
14140
+ /* @__PURE__ */ jsx("div", { className: cn("space-y-3", titleClearance), children })
13899
14141
  ]
13900
14142
  }
13901
14143
  );
@@ -13995,7 +14237,7 @@ var DocumentListSection = forwardRef(
13995
14237
  }
13996
14238
  );
13997
14239
  DocumentListSection.displayName = "DocumentListSection";
13998
- var DocumentRow = forwardRef(function DocumentRow2({ fileName, meta, icon, actions, className, ...props }, ref) {
14240
+ var DocumentRow = forwardRef(function DocumentRow2({ fileName, meta, icon, approved, rejected, actions, className, ...props }, ref) {
13999
14241
  return /* @__PURE__ */ jsxs(
14000
14242
  "div",
14001
14243
  {
@@ -14012,12 +14254,24 @@ var DocumentRow = forwardRef(function DocumentRow2({ fileName, meta, icon, actio
14012
14254
  "span",
14013
14255
  {
14014
14256
  "aria-hidden": "true",
14015
- className: "rounded-icon bg-bg-2 text-fg-3 inline-flex size-9 shrink-0 items-center justify-center",
14257
+ className: cn(
14258
+ "rounded-icon inline-flex size-9 shrink-0 items-center justify-center",
14259
+ approved ? "bg-success-bg text-success-fg" : rejected ? "bg-danger-bg text-danger-fg" : "bg-bg-2 text-fg-3"
14260
+ ),
14016
14261
  children: icon ?? /* @__PURE__ */ jsx(FileTextIcon, { className: "size-4.5" })
14017
14262
  }
14018
14263
  ),
14019
14264
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
14020
- /* @__PURE__ */ jsx("div", { className: "text-fg line-clamp-1 text-sm font-medium", children: fileName }),
14265
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [
14266
+ /* @__PURE__ */ jsx("span", { className: "text-fg line-clamp-1 min-w-0 text-sm font-medium", children: fileName }),
14267
+ approved ? /* @__PURE__ */ jsxs("span", { className: "bg-success-bg text-success-fg inline-flex shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-[10.5px] font-semibold", children: [
14268
+ /* @__PURE__ */ jsx(CheckIcon, { className: "size-3", "aria-hidden": "true" }),
14269
+ "Approved"
14270
+ ] }) : rejected ? /* @__PURE__ */ jsxs("span", { className: "bg-danger-bg text-danger-fg inline-flex shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-[10.5px] font-semibold", children: [
14271
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-3", "aria-hidden": "true" }),
14272
+ "Rejected"
14273
+ ] }) : null
14274
+ ] }),
14021
14275
  meta && /* @__PURE__ */ jsx("div", { className: "text-fg-4 line-clamp-1 text-xs", children: meta })
14022
14276
  ] }),
14023
14277
  actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-0.5", children: actions })
@@ -14038,11 +14292,30 @@ var TONE_PILL = {
14038
14292
  danger: "bg-danger-bg text-danger-fg",
14039
14293
  muted: "bg-surface-2 text-fg-3"
14040
14294
  };
14295
+ var TONE_DOT2 = {
14296
+ warning: "bg-warning-fg",
14297
+ success: "bg-success-fg",
14298
+ danger: "bg-danger-fg",
14299
+ muted: "bg-fg-4"
14300
+ };
14041
14301
  function initials(name) {
14042
14302
  return name.split(/\s+/).slice(0, 2).map((p) => p[0]?.toUpperCase() ?? "").join("");
14043
14303
  }
14044
14304
  var DocumentRequestCard = forwardRef(
14045
- function DocumentRequestCard2({ title, category, highPriority, due, comment, fulfilledCount, totalCount, items, assignees = [], onOpen, className, ...props }, ref) {
14305
+ function DocumentRequestCard2({
14306
+ title,
14307
+ category,
14308
+ highPriority,
14309
+ due,
14310
+ comment,
14311
+ fulfilledCount,
14312
+ totalCount,
14313
+ items,
14314
+ assignees = [],
14315
+ onOpen,
14316
+ className,
14317
+ ...props
14318
+ }, ref) {
14046
14319
  const docWord = totalCount === 1 ? "document" : "documents";
14047
14320
  return /* @__PURE__ */ jsxs(
14048
14321
  "div",
@@ -14060,7 +14333,7 @@ var DocumentRequestCard = forwardRef(
14060
14333
  className: cn(
14061
14334
  "rounded-card border-rule bg-surface cursor-pointer overflow-hidden border shadow-sm",
14062
14335
  "transition-shadow duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
14063
- "hover:shadow-md focus-visible:outline-none focus-visible:[box-shadow:var(--shadow-focus-ring)]",
14336
+ "hover:shadow-md focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none",
14064
14337
  className
14065
14338
  ),
14066
14339
  ...props,
@@ -14074,7 +14347,14 @@ var DocumentRequestCard = forwardRef(
14074
14347
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
14075
14348
  /* @__PURE__ */ jsx("span", { className: "text-fg min-w-0 truncate text-sm font-semibold", children: title }),
14076
14349
  category && /* @__PURE__ */ jsx("span", { className: "bg-surface-2 text-fg-3 inline-flex shrink-0 items-center rounded-md px-2 py-0.5 text-xs font-medium", children: category }),
14077
- highPriority && /* @__PURE__ */ jsx(AlertTriangleIcon, { size: 14, className: "text-warning-fg shrink-0", "aria-label": "Urgent request" }),
14350
+ highPriority && /* @__PURE__ */ jsx(
14351
+ AlertTriangleIcon,
14352
+ {
14353
+ size: 14,
14354
+ className: "text-warning-fg shrink-0",
14355
+ "aria-label": "Urgent request"
14356
+ }
14357
+ ),
14078
14358
  due && /* @__PURE__ */ jsx(
14079
14359
  "span",
14080
14360
  {
@@ -14103,12 +14383,25 @@ var DocumentRequestCard = forwardRef(
14103
14383
  comment,
14104
14384
  "\u201D"
14105
14385
  ] }),
14106
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 px-5 pb-4 pt-3", children: items.map((item) => /* @__PURE__ */ jsxs("div", { className: "bg-surface-2 flex items-center gap-3 rounded-xl px-4 py-3.5", children: [
14107
- /* @__PURE__ */ jsx(FileTextIcon, { size: 16, className: "text-fg-3 shrink-0" }),
14108
- /* @__PURE__ */ jsx("span", { className: "text-fg min-w-0 flex-1 truncate text-sm font-semibold", children: item.label }),
14109
- item.docType && /* @__PURE__ */ jsx("span", { className: "border-rule bg-surface text-fg-3 inline-flex shrink-0 items-center rounded-md border px-2 py-0.5 text-[10.5px] font-semibold uppercase tracking-wide", children: item.docType }),
14110
- /* @__PURE__ */ jsx("span", { className: cn("shrink-0 text-[13px] font-semibold", TONE_TEXT[item.statusTone]), children: item.statusLabel })
14111
- ] }, item.id)) }),
14386
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 px-5 pt-3 pb-4", children: items.map((item) => /* @__PURE__ */ jsxs(
14387
+ "div",
14388
+ {
14389
+ className: "bg-surface-2 flex items-center gap-3 rounded-xl px-4 py-3.5",
14390
+ children: [
14391
+ /* @__PURE__ */ jsx(FileTextIcon, { size: 16, className: "text-fg-3 shrink-0" }),
14392
+ /* @__PURE__ */ jsx("span", { className: "text-fg min-w-0 flex-1 truncate text-sm font-semibold", children: item.label }),
14393
+ item.docType && /* @__PURE__ */ jsx("span", { className: "border-rule bg-surface text-fg-3 inline-flex shrink-0 items-center rounded-md border px-2 py-0.5 text-[10.5px] font-semibold tracking-wide uppercase", children: item.docType }),
14394
+ /* @__PURE__ */ jsx(
14395
+ "span",
14396
+ {
14397
+ className: cn("shrink-0 text-[13px] font-semibold", TONE_TEXT[item.statusTone]),
14398
+ children: item.statusLabel
14399
+ }
14400
+ )
14401
+ ]
14402
+ },
14403
+ item.id
14404
+ )) }),
14112
14405
  /* @__PURE__ */ jsxs("div", { className: "border-rule flex items-center gap-2 border-t px-5 py-2.5", children: [
14113
14406
  /* @__PURE__ */ jsx(FolderClosedIcon, { size: 14, className: "text-fg-4 shrink-0" }),
14114
14407
  /* @__PURE__ */ jsxs("span", { className: "text-fg-3 text-[12.5px] tabular-nums", children: [
@@ -14177,8 +14470,10 @@ var DocumentRequestDetail = forwardRef(
14177
14470
  tab,
14178
14471
  defaultTab = "documents",
14179
14472
  onTabChange,
14180
- clientUploads,
14473
+ clientUploads = [],
14181
14474
  firmDocuments,
14475
+ requestedItems,
14476
+ otherUploads = [],
14182
14477
  onUploadFirmDocument,
14183
14478
  comments,
14184
14479
  commentDraft,
@@ -14189,20 +14484,22 @@ var DocumentRequestDetail = forwardRef(
14189
14484
  activity,
14190
14485
  className
14191
14486
  } = props;
14192
- const docCount = clientUploads.length + firmDocuments.length;
14487
+ const clientDocCount = requestedItems ? requestedItems.reduce((n, it) => n + it.documents.length, 0) + otherUploads.length : clientUploads.length;
14488
+ const docCount = clientDocCount + firmDocuments.length;
14489
+ const providedCount = requestedItems?.filter((it) => it.statusTone === "success").length ?? 0;
14193
14490
  const selectedAssignees = assignees.filter((a) => a.selected);
14194
14491
  return /* @__PURE__ */ jsxs(DocumentDetailPanel, { ref, className, children: [
14195
14492
  /* @__PURE__ */ jsxs(
14196
14493
  DocumentDetailHeader,
14197
14494
  {
14198
14495
  onClose,
14199
- tags: /* @__PURE__ */ jsxs(Fragment, { children: [
14496
+ tags: category || highPriority ? /* @__PURE__ */ jsxs(Fragment, { children: [
14200
14497
  category && /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "gap-1", children: [
14201
14498
  /* @__PURE__ */ jsx(FolderClosedIcon, { className: "size-3" }),
14202
14499
  category
14203
14500
  ] }),
14204
14501
  highPriority && /* @__PURE__ */ jsx(Badge, { variant: "warning", children: "High priority" })
14205
- ] }),
14502
+ ] }) : void 0,
14206
14503
  status: statusLabel ? /* @__PURE__ */ jsx(Badge, { variant: statusVariant, children: statusLabel }) : void 0,
14207
14504
  children: [
14208
14505
  /* @__PURE__ */ jsx(DocumentDetailTitle, { children: title }),
@@ -14260,7 +14557,12 @@ var DocumentRequestDetail = forwardRef(
14260
14557
  },
14261
14558
  className: "flex items-center gap-2.5 py-2",
14262
14559
  children: [
14263
- /* @__PURE__ */ jsx("span", { className: cn("size-2.5 shrink-0 rounded-full", opt.color ?? "bg-fg-4") }),
14560
+ /* @__PURE__ */ jsx(
14561
+ "span",
14562
+ {
14563
+ className: cn("size-2.5 shrink-0 rounded-full", opt.color ?? "bg-fg-4")
14564
+ }
14565
+ ),
14264
14566
  /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children: opt.label }),
14265
14567
  /* @__PURE__ */ jsx(
14266
14568
  "span",
@@ -14315,12 +14617,85 @@ var DocumentRequestDetail = forwardRef(
14315
14617
  /* @__PURE__ */ jsx(LockIcon, { size: 15, className: "shrink-0" }),
14316
14618
  "This request is locked \u2014 the client can no longer upload documents."
14317
14619
  ] }),
14318
- /* @__PURE__ */ jsxs(DocumentList, { children: [
14620
+ /* @__PURE__ */ jsx(DocumentList, { children: requestedItems ? /* @__PURE__ */ jsxs(Fragment, { children: [
14621
+ /* @__PURE__ */ jsxs("div", { className: "text-fg-3 px-2.5 text-[13px] font-medium tabular-nums", children: [
14622
+ providedCount,
14623
+ " of ",
14624
+ requestedItems.length,
14625
+ " provided"
14626
+ ] }),
14627
+ requestedItems.map((item) => /* @__PURE__ */ jsxs("section", { className: "space-y-1", children: [
14628
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2.5 py-1", children: [
14629
+ /* @__PURE__ */ jsx(FileTextIcon, { size: 15, className: "text-fg-3 shrink-0" }),
14630
+ /* @__PURE__ */ jsx("span", { className: "text-fg min-w-0 flex-1 truncate text-sm font-semibold", children: item.label }),
14631
+ item.docType && /* @__PURE__ */ jsx("span", { className: "border-rule bg-surface text-fg-3 inline-flex shrink-0 items-center rounded-md border px-1.5 py-0.5 text-[10px] font-semibold tracking-wide uppercase", children: item.docType }),
14632
+ /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1.5", children: [
14633
+ /* @__PURE__ */ jsx(
14634
+ "span",
14635
+ {
14636
+ "aria-hidden": true,
14637
+ className: cn("size-2 rounded-full", TONE_DOT2[item.statusTone])
14638
+ }
14639
+ ),
14640
+ /* @__PURE__ */ jsx("span", { className: cn("text-xs font-semibold", TONE_TEXT[item.statusTone]), children: item.statusLabel })
14641
+ ] })
14642
+ ] }),
14643
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5 pl-[1.625rem]", children: item.documents.length > 0 ? item.documents.map((d) => /* @__PURE__ */ jsx(
14644
+ DocumentRow,
14645
+ {
14646
+ fileName: d.fileName,
14647
+ meta: d.meta,
14648
+ approved: d.approved,
14649
+ rejected: d.rejected,
14650
+ className: d.active ? "bg-overlay-hover" : void 0,
14651
+ actions: /* @__PURE__ */ jsx(FileRowActions, { doc: d })
14652
+ },
14653
+ d.id
14654
+ )) : /* @__PURE__ */ jsx("p", { className: "text-fg-4 px-2.5 py-1.5 text-[13px]", children: "Awaiting client upload" }) })
14655
+ ] }, item.id)),
14656
+ otherUploads.length > 0 && /* @__PURE__ */ jsx(DocumentListSection, { label: "Other uploads", count: otherUploads.length, children: otherUploads.map((d) => /* @__PURE__ */ jsx(
14657
+ DocumentRow,
14658
+ {
14659
+ fileName: d.fileName,
14660
+ meta: d.meta,
14661
+ approved: d.approved,
14662
+ rejected: d.rejected,
14663
+ className: d.active ? "bg-overlay-hover" : void 0,
14664
+ actions: /* @__PURE__ */ jsx(FileRowActions, { doc: d })
14665
+ },
14666
+ d.id
14667
+ )) }),
14668
+ /* @__PURE__ */ jsx(
14669
+ DocumentListSection,
14670
+ {
14671
+ label: "Firm reference",
14672
+ count: firmDocuments.length,
14673
+ action: onUploadFirmDocument ? /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: onUploadFirmDocument, children: [
14674
+ /* @__PURE__ */ jsx(UploadIcon, {}),
14675
+ "Upload"
14676
+ ] }) : void 0,
14677
+ children: firmDocuments.length > 0 ? firmDocuments.map((d) => /* @__PURE__ */ jsx(
14678
+ DocumentRow,
14679
+ {
14680
+ fileName: d.fileName,
14681
+ meta: d.meta,
14682
+ approved: d.approved,
14683
+ rejected: d.rejected,
14684
+ className: d.active ? "bg-overlay-hover" : void 0,
14685
+ actions: /* @__PURE__ */ jsx(FileRowActions, { doc: d })
14686
+ },
14687
+ d.id
14688
+ )) : /* @__PURE__ */ jsx("p", { className: "text-fg-4 px-2.5 py-2 text-sm", children: "No firm documents attached." })
14689
+ }
14690
+ )
14691
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
14319
14692
  /* @__PURE__ */ jsx(DocumentListSection, { label: "Client uploads", count: clientUploads.length, children: clientUploads.length > 0 ? clientUploads.map((d) => /* @__PURE__ */ jsx(
14320
14693
  DocumentRow,
14321
14694
  {
14322
14695
  fileName: d.fileName,
14323
14696
  meta: d.meta,
14697
+ approved: d.approved,
14698
+ rejected: d.rejected,
14324
14699
  className: d.active ? "bg-overlay-hover" : void 0,
14325
14700
  actions: /* @__PURE__ */ jsx(FileRowActions, { doc: d })
14326
14701
  },
@@ -14340,6 +14715,8 @@ var DocumentRequestDetail = forwardRef(
14340
14715
  {
14341
14716
  fileName: d.fileName,
14342
14717
  meta: d.meta,
14718
+ approved: d.approved,
14719
+ rejected: d.rejected,
14343
14720
  className: d.active ? "bg-overlay-hover" : void 0,
14344
14721
  actions: /* @__PURE__ */ jsx(FileRowActions, { doc: d })
14345
14722
  },
@@ -14347,7 +14724,7 @@ var DocumentRequestDetail = forwardRef(
14347
14724
  )) : /* @__PURE__ */ jsx("p", { className: "text-fg-4 px-2.5 py-2 text-sm", children: "No firm documents attached." })
14348
14725
  }
14349
14726
  )
14350
- ] })
14727
+ ] }) })
14351
14728
  ] }),
14352
14729
  /* @__PURE__ */ jsxs(TabsContent, { value: "comments", className: "flex min-h-0 flex-1 flex-col", children: [
14353
14730
  /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-5 py-4", children: comments.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: comments.map((c) => /* @__PURE__ */ jsx(CommentRow, { comment: c }, c.id)) }) : /* @__PURE__ */ jsx("p", { className: "text-fg-4 text-sm", children: "No comments yet. Start the conversation below." }) }),
@@ -14410,7 +14787,7 @@ function AssigneePicker({
14410
14787
  const selected = assignees.filter((a) => a.selected);
14411
14788
  const stack = /* @__PURE__ */ jsx("span", { className: "flex -space-x-2", children: selected.map((a) => /* @__PURE__ */ jsx(Avatar, { size: "sm", name: a.name, variant: "branded" }, a.id)) });
14412
14789
  if (!onToggle) {
14413
- return /* @__PURE__ */ jsxs("span", { className: "rounded-pill border-rule inline-flex items-center gap-2 border py-1 pl-1.5 pr-2.5", children: [
14790
+ return /* @__PURE__ */ jsxs("span", { className: "rounded-pill border-rule inline-flex items-center gap-2 border py-1 pr-2.5 pl-1.5", children: [
14414
14791
  stack,
14415
14792
  /* @__PURE__ */ jsx("span", { className: "text-fg-2 text-sm font-semibold tabular-nums", children: selected.length })
14416
14793
  ] });
@@ -14421,7 +14798,7 @@ function AssigneePicker({
14421
14798
  {
14422
14799
  type: "button",
14423
14800
  "aria-label": "Edit assignees",
14424
- className: "rounded-pill border-rule hover:bg-overlay-hover inline-flex items-center gap-2 border py-1 pl-1.5 pr-2.5 transition-colors focus-visible:outline-none focus-visible:[box-shadow:var(--shadow-focus-ring)]",
14801
+ className: "rounded-pill border-rule hover:bg-overlay-hover inline-flex items-center gap-2 border py-1 pr-2.5 pl-1.5 transition-colors focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none",
14425
14802
  children: [
14426
14803
  stack,
14427
14804
  /* @__PURE__ */ jsx("span", { className: "text-fg-2 text-sm font-semibold tabular-nums", children: selected.length }),
@@ -14449,23 +14826,49 @@ function AssigneePicker({
14449
14826
  ] });
14450
14827
  }
14451
14828
  function CommentRow({ comment }) {
14452
- return /* @__PURE__ */ jsxs("div", { className: "flex gap-2.5", children: [
14453
- /* @__PURE__ */ jsx(Avatar, { size: "sm", name: comment.author, variant: "branded" }),
14454
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
14455
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
14456
- /* @__PURE__ */ jsxs("span", { className: "text-fg truncate text-[13px] font-semibold", children: [
14457
- comment.author,
14458
- comment.you && " (You)"
14459
- ] }),
14460
- /* @__PURE__ */ jsx(Badge, { variant: comment.isFirm ? "secondary" : "info", size: "sm", children: comment.isFirm ? "Firm" : "Client" }),
14461
- /* @__PURE__ */ jsx("span", { className: "text-fg-4 ml-auto shrink-0 text-[11.5px]", children: comment.time })
14462
- ] }),
14463
- /* @__PURE__ */ jsx("p", { className: "text-fg-2 mt-0.5 text-[13px] leading-snug", children: comment.body })
14464
- ] })
14829
+ const { isFirm } = comment;
14830
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-2.5", isFirm ? "flex-row-reverse" : "flex-row"), children: [
14831
+ /* @__PURE__ */ jsx(Avatar, { size: "sm", name: comment.author, variant: "branded", className: "mt-0.5 shrink-0" }),
14832
+ /* @__PURE__ */ jsxs(
14833
+ "div",
14834
+ {
14835
+ className: cn("flex max-w-[78%] min-w-0 flex-col", isFirm ? "items-end" : "items-start"),
14836
+ children: [
14837
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", isFirm && "flex-row-reverse"), children: [
14838
+ /* @__PURE__ */ jsxs("span", { className: "text-fg truncate text-[13px] font-semibold", children: [
14839
+ comment.author,
14840
+ comment.you && " (You)"
14841
+ ] }),
14842
+ /* @__PURE__ */ jsx("span", { className: "text-fg-4 shrink-0 text-[11.5px]", children: comment.time })
14843
+ ] }),
14844
+ /* @__PURE__ */ jsx(
14845
+ "div",
14846
+ {
14847
+ className: cn(
14848
+ "mt-1 rounded-2xl px-3 py-2 text-[13px] leading-snug",
14849
+ isFirm ? "bg-pro-bg text-pro-fg rounded-tr-sm" : "bg-surface-2 text-fg-2 rounded-tl-sm"
14850
+ ),
14851
+ children: /* @__PURE__ */ jsx("p", { className: "break-words whitespace-pre-wrap", children: comment.body })
14852
+ }
14853
+ )
14854
+ ]
14855
+ }
14856
+ )
14465
14857
  ] });
14466
14858
  }
14467
14859
  function FileRowActions({ doc }) {
14468
14860
  return /* @__PURE__ */ jsxs(Fragment, { children: [
14861
+ doc.onApprove && !doc.approved && /* @__PURE__ */ jsx(
14862
+ Button,
14863
+ {
14864
+ variant: "ghost",
14865
+ size: "icon-sm",
14866
+ "aria-label": "Approve",
14867
+ className: "hover:text-success-fg",
14868
+ onClick: doc.onApprove,
14869
+ children: /* @__PURE__ */ jsx(CheckIcon, {})
14870
+ }
14871
+ ),
14469
14872
  doc.onPreview && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Preview", onClick: doc.onPreview, children: /* @__PURE__ */ jsx(EyeIcon, {}) }),
14470
14873
  doc.onDownload && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Download", onClick: doc.onDownload, children: /* @__PURE__ */ jsx(DownloadIcon, {}) }),
14471
14874
  doc.onDelete && /* @__PURE__ */ jsx(