@j3m-quantum/ui 1.9.1 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -43,6 +43,15 @@ var ResizablePrimitive = require('react-resizable-panels');
43
43
  var reactLeaflet = require('react-leaflet');
44
44
  var reactTable = require('@tanstack/react-table');
45
45
  var dateFns = require('date-fns');
46
+ var core = require('@dnd-kit/core');
47
+ var modifiers = require('@dnd-kit/modifiers');
48
+ var usehooks = require('@uidotdev/usehooks');
49
+ var jotai = require('jotai');
50
+ var throttle = require('lodash.throttle');
51
+ var sortable = require('@dnd-kit/sortable');
52
+ var utilities = require('@dnd-kit/utilities');
53
+ var reactDom = require('react-dom');
54
+ var tunnel = require('tunnel-rat');
46
55
 
47
56
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
48
57
 
@@ -93,6 +102,8 @@ var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitiv
93
102
  var HoverCardPrimitive__namespace = /*#__PURE__*/_interopNamespace(HoverCardPrimitive);
94
103
  var CollapsiblePrimitive__namespace = /*#__PURE__*/_interopNamespace(CollapsiblePrimitive);
95
104
  var ResizablePrimitive__namespace = /*#__PURE__*/_interopNamespace(ResizablePrimitive);
105
+ var throttle__default = /*#__PURE__*/_interopDefault(throttle);
106
+ var tunnel__default = /*#__PURE__*/_interopDefault(tunnel);
96
107
 
97
108
  // src/hooks/use-mobile.ts
98
109
  var MOBILE_BREAKPOINT = 768;
@@ -6828,7 +6839,7 @@ function PlanningWeekCommentPopover({
6828
6839
  onCommentClick(comment);
6829
6840
  }
6830
6841
  };
6831
- const formatDate2 = (date) => {
6842
+ const formatDate3 = (date) => {
6832
6843
  return new Intl.DateTimeFormat("en-US", {
6833
6844
  month: "short",
6834
6845
  day: "numeric",
@@ -6908,7 +6919,7 @@ function PlanningWeekCommentPopover({
6908
6919
  ] }),
6909
6920
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
6910
6921
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
6911
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
6922
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
6912
6923
  ] }),
6913
6924
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
6914
6925
  ]
@@ -7435,7 +7446,7 @@ function DeliveryCommentPopover({
7435
7446
  setNewCommentText("");
7436
7447
  }
7437
7448
  };
7438
- const formatDate2 = (date) => {
7449
+ const formatDate3 = (date) => {
7439
7450
  return new Intl.DateTimeFormat("en-US", {
7440
7451
  month: "short",
7441
7452
  day: "numeric",
@@ -7481,7 +7492,7 @@ function DeliveryCommentPopover({
7481
7492
  /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-muted/50 p-3 space-y-2", children: [
7482
7493
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7483
7494
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
7484
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
7495
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
7485
7496
  ] }),
7486
7497
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
7487
7498
  ] }, comment.id)) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
@@ -7575,7 +7586,7 @@ function ProductionCommentSection({
7575
7586
  setNewComment("");
7576
7587
  }
7577
7588
  };
7578
- const formatDate2 = (date) => {
7589
+ const formatDate3 = (date) => {
7579
7590
  return new Intl.DateTimeFormat("en-US", {
7580
7591
  month: "short",
7581
7592
  day: "numeric",
@@ -7587,7 +7598,7 @@ function ProductionCommentSection({
7587
7598
  comments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-muted/50 p-2.5 space-y-1", children: [
7588
7599
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7589
7600
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
7590
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
7601
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
7591
7602
  ] }),
7592
7603
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
7593
7604
  ] }, comment.id)) }),
@@ -8531,7 +8542,7 @@ function CommentPopover({
8531
8542
  setNewCommentText("");
8532
8543
  }
8533
8544
  };
8534
- const formatDate2 = (date) => {
8545
+ const formatDate3 = (date) => {
8535
8546
  return new Intl.DateTimeFormat("en-US", {
8536
8547
  month: "short",
8537
8548
  day: "numeric",
@@ -8599,7 +8610,7 @@ function CommentPopover({
8599
8610
  ),
8600
8611
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
8601
8612
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
8602
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
8613
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
8603
8614
  ] }),
8604
8615
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: comment.text })
8605
8616
  ]
@@ -9318,7 +9329,7 @@ function generateLoadingWeek(date) {
9318
9329
  const today = /* @__PURE__ */ new Date();
9319
9330
  today.setHours(0, 0, 0, 0);
9320
9331
  const isCurrentWeek = monday <= today && today <= friday;
9321
- const formatDate2 = (d) => {
9332
+ const formatDate3 = (d) => {
9322
9333
  return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
9323
9334
  };
9324
9335
  return {
@@ -9326,7 +9337,7 @@ function generateLoadingWeek(date) {
9326
9337
  label: `W${getLoadingISOWeek(monday).toString().padStart(2, "0")}`,
9327
9338
  startDate: monday,
9328
9339
  endDate: friday,
9329
- dateRange: `${formatDate2(monday)} - ${formatDate2(friday)}`,
9340
+ dateRange: `${formatDate3(monday)} - ${formatDate3(friday)}`,
9330
9341
  isCurrentWeek
9331
9342
  };
9332
9343
  }
@@ -9418,36 +9429,41 @@ function getLeftStrokeStyles(state, hasRisk, isHovered) {
9418
9429
  stroke: "border-l-[3px] border-l-red-500",
9419
9430
  content: "text-foreground",
9420
9431
  progressBg: "bg-red-500",
9421
- iconColor: "text-red-600 dark:text-red-400"
9432
+ iconColor: "text-red-600 dark:text-red-400",
9433
+ cardBg: "bg-background"
9422
9434
  };
9423
9435
  }
9424
9436
  switch (state) {
9425
9437
  case "sent":
9426
9438
  return {
9427
- stroke: "border-l-[3px] border-l-green-500/50",
9428
- content: "text-muted-foreground/60",
9429
- progressBg: "bg-green-500",
9430
- iconColor: "text-green-600 dark:text-green-400"
9439
+ stroke: "border-l-[3px] border-l-green-500/40",
9440
+ content: "text-muted-foreground/50",
9441
+ progressBg: "bg-green-500/50",
9442
+ iconColor: "text-green-600/50 dark:text-green-400/50",
9443
+ cardBg: "bg-muted/30"
9431
9444
  };
9432
9445
  case "ready":
9433
9446
  return {
9434
9447
  stroke: "border-l-[3px] border-l-green-500",
9435
9448
  content: "text-foreground",
9436
9449
  progressBg: "bg-green-500",
9437
- iconColor: "text-green-600 dark:text-green-400"
9450
+ iconColor: "text-green-600 dark:text-green-400",
9451
+ cardBg: "bg-background"
9438
9452
  };
9439
9453
  default:
9440
9454
  return {
9441
9455
  stroke: isHovered ? "border-l-[3px] border-l-primary/50" : "border-l-[3px] border-l-border",
9442
9456
  content: "text-foreground",
9443
9457
  progressBg: "bg-primary",
9444
- iconColor: "text-muted-foreground"
9458
+ iconColor: "text-muted-foreground",
9459
+ cardBg: "bg-background"
9445
9460
  };
9446
9461
  }
9447
9462
  }
9448
9463
  function DeliveryBadge({
9449
9464
  delivery,
9450
9465
  onClick,
9466
+ onCommentClick,
9451
9467
  className
9452
9468
  }) {
9453
9469
  const [isHovered, setIsHovered] = React27__namespace.useState(false);
@@ -9510,70 +9526,125 @@ function DeliveryBadge({
9510
9526
  onClick?.();
9511
9527
  }
9512
9528
  };
9529
+ const handleCommentClick = (e) => {
9530
+ e.stopPropagation();
9531
+ onCommentClick?.();
9532
+ };
9533
+ const amountColorClass = React27__namespace.useMemo(() => {
9534
+ if (visualState === "sent") {
9535
+ return "text-muted-foreground/40";
9536
+ }
9537
+ if (delivery.isReadyToUnload) {
9538
+ return "text-green-600 dark:text-green-400";
9539
+ }
9540
+ if (delivery.hasProductionRisk) {
9541
+ return "text-red-600 dark:text-red-400";
9542
+ }
9543
+ return "text-muted-foreground";
9544
+ }, [visualState, delivery.isReadyToUnload, delivery.hasProductionRisk]);
9513
9545
  return /* @__PURE__ */ jsxRuntime.jsxs(
9514
- "button",
9546
+ "div",
9515
9547
  {
9516
- type: "button",
9517
- onClick: handleClick,
9518
- onKeyDown: handleKeyDown,
9519
- onMouseEnter: () => setIsHovered(true),
9520
- onMouseLeave: () => setIsHovered(false),
9521
9548
  className: cn(
9522
- // Position relative for comment dot
9549
+ // Position relative for comment button
9523
9550
  "relative",
9524
9551
  // Full-width in cell, 90° corners
9525
9552
  "w-full rounded-none",
9526
9553
  // Sizing using Quantum tokens:
9527
- // - h-[80px] card height
9528
- // - px-6 = 24px horizontal (j3m.spacing.l)
9529
- // - py-4 = 16px vertical (j3m.spacing.m)
9530
- "h-[80px] px-6 py-4",
9531
- // Layout
9532
- "flex items-center",
9533
- // Card base: white background, complete border
9534
- "bg-background border border-border",
9554
+ // - min-h-[100px] card min-height
9555
+ // - pt-4 pb-3 = vertical padding (j3m.spacing.m / j3m.spacing.s)
9556
+ // - pl-4 = left padding (j3m.spacing.m)
9557
+ // - pr-2 = minimal right padding (progress bar extends further)
9558
+ "min-h-[100px] pt-4 pb-3 pl-4 pr-2",
9559
+ // Card base: dynamic background based on state, complete border
9560
+ styles.cardBg,
9561
+ "border border-border",
9535
9562
  // Left stroke for status
9536
9563
  styles.stroke,
9537
- // Interactive states
9538
- "cursor-pointer transition-all duration-200 ease-out",
9539
- "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
9540
- "active:translate-y-0 active:shadow-sm",
9541
- // Focus state
9542
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1",
9543
- // Greyed out for sent state
9544
- visualState === "sent" && "opacity-60",
9564
+ // Interactive states (reduced for sent state)
9565
+ "transition-all duration-200 ease-out",
9566
+ visualState !== "sent" && "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
9545
9567
  className
9546
9568
  ),
9547
9569
  children: [
9548
- hasComments && /* @__PURE__ */ jsxRuntime.jsx(
9549
- "span",
9570
+ /* @__PURE__ */ jsxRuntime.jsx(
9571
+ Button,
9550
9572
  {
9551
- className: "absolute -top-1 -right-1 h-3 w-3 rounded-full bg-primary ring-2 ring-background",
9552
- "aria-label": "Has comments"
9573
+ type: "button",
9574
+ variant: "ghost",
9575
+ size: "icon",
9576
+ className: cn(
9577
+ "absolute top-2 right-2",
9578
+ // 44px touch target for accessibility
9579
+ "h-11 w-11",
9580
+ "rounded-full",
9581
+ hasComments && "text-primary"
9582
+ ),
9583
+ onClick: handleCommentClick,
9584
+ "aria-label": hasComments ? `${delivery.comments.length} comments` : "Add comment",
9585
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
9586
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-5 w-5" }),
9587
+ hasComments && /* @__PURE__ */ jsxRuntime.jsx(
9588
+ "span",
9589
+ {
9590
+ className: "absolute -top-1 -right-1 h-2.5 w-2.5 rounded-full bg-primary border-2 border-background",
9591
+ "aria-hidden": "true"
9592
+ }
9593
+ )
9594
+ ] })
9553
9595
  }
9554
9596
  ),
9555
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center gap-3 min-w-0 flex-1 overflow-hidden", children: [
9556
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 overflow-hidden", children: [
9557
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-sm font-semibold truncate", styles.content), children: prefixTitle }),
9558
- visualState === "sent" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4 text-green-600 dark:text-green-400 shrink-0" }),
9559
- delivery.hasProductionRisk && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-4 w-4 text-red-500 shrink-0" }),
9560
- delivery.supplierName && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground truncate ml-auto", children: delivery.supplierName })
9561
- ] }),
9562
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9563
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: cn("h-3.5 w-3.5 shrink-0", styles.iconColor) }),
9564
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-1.5 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
9565
- "div",
9566
- {
9567
- className: cn("h-full rounded-full transition-all", styles.progressBg),
9568
- style: { width: `${productionProgress}%` }
9569
- }
9570
- ) }),
9571
- productionDisplay && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9572
- "text-xs tabular-nums font-medium shrink-0",
9573
- delivery.isReadyToUnload ? "text-green-600 dark:text-green-400" : delivery.hasProductionRisk ? "text-red-600 dark:text-red-400" : "text-muted-foreground"
9574
- ), children: productionDisplay })
9575
- ] })
9576
- ] })
9597
+ /* @__PURE__ */ jsxRuntime.jsxs(
9598
+ "button",
9599
+ {
9600
+ type: "button",
9601
+ onClick: handleClick,
9602
+ onKeyDown: handleKeyDown,
9603
+ onMouseEnter: () => setIsHovered(true),
9604
+ onMouseLeave: () => setIsHovered(false),
9605
+ className: cn(
9606
+ // Full width, no background (inherits from parent)
9607
+ "w-full bg-transparent text-left",
9608
+ // Layout - vertical stack
9609
+ "flex flex-col gap-2",
9610
+ // Interactive states
9611
+ "cursor-pointer",
9612
+ "active:translate-y-0 active:shadow-sm",
9613
+ // Focus state
9614
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1"
9615
+ ),
9616
+ children: [
9617
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 overflow-hidden pr-12", children: [
9618
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-sm font-semibold truncate", styles.content), children: prefixTitle }),
9619
+ delivery.hasProductionRisk && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-4 w-4 text-red-500 shrink-0" }),
9620
+ delivery.supplierName && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9621
+ "text-xs truncate ml-auto",
9622
+ visualState === "sent" ? "text-muted-foreground/40" : "text-muted-foreground"
9623
+ ), children: delivery.supplierName })
9624
+ ] }),
9625
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-14", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
9626
+ "div",
9627
+ {
9628
+ className: cn("h-full rounded-full transition-all", styles.progressBg),
9629
+ style: { width: `${productionProgress}%` }
9630
+ }
9631
+ ) }) }),
9632
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
9633
+ productionDisplay && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
9634
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Factory, { className: cn("h-3 w-3 shrink-0", styles.iconColor) }),
9635
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9636
+ "text-[11px] tabular-nums font-medium",
9637
+ amountColorClass
9638
+ ), children: productionDisplay })
9639
+ ] }),
9640
+ visualState === "sent" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-auto", children: [
9641
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5 text-green-600/60 dark:text-green-400/60 shrink-0" }),
9642
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium text-muted-foreground/50 uppercase tracking-wide", children: "Sent" })
9643
+ ] })
9644
+ ] })
9645
+ ]
9646
+ }
9647
+ )
9577
9648
  ]
9578
9649
  }
9579
9650
  );
@@ -9583,7 +9654,7 @@ function WeeklyLoadingView({
9583
9654
  deliveries,
9584
9655
  onDeliveryClick,
9585
9656
  onWeekChange,
9586
- onDayCommentClick,
9657
+ onDeliveryCommentClick,
9587
9658
  showNavigation = true,
9588
9659
  className
9589
9660
  }) {
@@ -9614,20 +9685,6 @@ function WeeklyLoadingView({
9614
9685
  }
9615
9686
  return grouped;
9616
9687
  }, [deliveries]);
9617
- const commentCountByDay = React27__namespace.useMemo(() => {
9618
- const counts = /* @__PURE__ */ new Map();
9619
- for (let i = 1; i <= 5; i++) {
9620
- counts.set(i, 0);
9621
- }
9622
- for (const delivery of deliveries) {
9623
- const dayOfWeek = delivery.date.getDay();
9624
- if (dayOfWeek >= 1 && dayOfWeek <= 5) {
9625
- const current = counts.get(dayOfWeek) ?? 0;
9626
- counts.set(dayOfWeek, current + delivery.comments.length);
9627
- }
9628
- }
9629
- return counts;
9630
- }, [deliveries]);
9631
9688
  const totalDeliveries = deliveries.length;
9632
9689
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col", className), children: [
9633
9690
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 border-b border-border p-4 lg:flex-row lg:items-center lg:justify-between", children: [
@@ -9692,54 +9749,27 @@ function WeeklyLoadingView({
9692
9749
  ] }),
9693
9750
  /* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "flex-1", children: [
9694
9751
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden sm:block", children: [
9695
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-5 border-b border-border bg-muted/30", children: weekDays.map(({ date, dayOfWeek, isToday: dayIsToday }) => {
9696
- const dayCommentCount = commentCountByDay.get(dayOfWeek) ?? 0;
9697
- return /* @__PURE__ */ jsxRuntime.jsxs(
9698
- "div",
9699
- {
9700
- className: cn(
9701
- // Relative for positioning comment button
9702
- "relative",
9703
- // Compact padding: py-2 px-3 (j3m.spacing.xs / j3m.spacing.s)
9704
- "flex items-center justify-center gap-2 py-2 px-3",
9705
- dayIsToday && "bg-primary/5"
9706
- ),
9707
- children: [
9708
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9709
- "text-xs font-medium uppercase tracking-wide",
9710
- dayIsToday ? "text-primary" : "text-muted-foreground"
9711
- ), children: getShortDayLabel(dayOfWeek) }),
9712
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9713
- "text-base font-semibold tabular-nums",
9714
- dayIsToday ? "text-primary" : "text-foreground"
9715
- ), children: date.getDate() }),
9716
- /* @__PURE__ */ jsxRuntime.jsxs(
9717
- Button,
9718
- {
9719
- variant: "ghost",
9720
- size: "icon",
9721
- className: cn(
9722
- "absolute top-1 right-1 h-7 w-7",
9723
- dayCommentCount > 0 && "text-primary"
9724
- ),
9725
- onClick: (e) => {
9726
- e.stopPropagation();
9727
- onDayCommentClick?.(dayOfWeek, date);
9728
- },
9729
- children: [
9730
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
9731
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-4 w-4" }),
9732
- dayCommentCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-primary" })
9733
- ] }),
9734
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: dayCommentCount > 0 ? `${dayCommentCount} comments on ${getShortDayLabel(dayOfWeek)}` : `Add comment for ${getShortDayLabel(dayOfWeek)}` })
9735
- ]
9736
- }
9737
- )
9738
- ]
9739
- },
9740
- dayOfWeek
9741
- );
9742
- }) }),
9752
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-5 border-b border-border bg-muted/30", children: weekDays.map(({ date, dayOfWeek, isToday: dayIsToday }) => /* @__PURE__ */ jsxRuntime.jsxs(
9753
+ "div",
9754
+ {
9755
+ className: cn(
9756
+ // Compact padding
9757
+ "flex flex-col items-center justify-center py-2 px-2",
9758
+ dayIsToday && "bg-primary/5"
9759
+ ),
9760
+ children: [
9761
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9762
+ "text-[11px] font-semibold uppercase tracking-wide leading-none",
9763
+ dayIsToday ? "text-primary" : "text-muted-foreground"
9764
+ ), children: getShortDayLabel(dayOfWeek) }),
9765
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9766
+ "text-lg font-medium tabular-nums leading-tight mt-0.5",
9767
+ dayIsToday ? "text-primary" : "text-foreground"
9768
+ ), children: date.getDate() })
9769
+ ]
9770
+ },
9771
+ dayOfWeek
9772
+ )) }),
9743
9773
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-5", children: weekDays.map(({ dayOfWeek, isToday: dayIsToday }) => {
9744
9774
  const dayDeliveries = deliveriesByDay.get(dayOfWeek) ?? [];
9745
9775
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -9754,7 +9784,8 @@ function WeeklyLoadingView({
9754
9784
  DeliveryBadge,
9755
9785
  {
9756
9786
  delivery,
9757
- onClick: () => onDeliveryClick?.(delivery)
9787
+ onClick: () => onDeliveryClick?.(delivery),
9788
+ onCommentClick: () => onDeliveryCommentClick?.(delivery)
9758
9789
  },
9759
9790
  delivery.id
9760
9791
  )) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-6 text-sm text-muted-foreground/40", children: "\u2014" }) })
@@ -9765,7 +9796,6 @@ function WeeklyLoadingView({
9765
9796
  ] }),
9766
9797
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sm:hidden divide-y divide-border", children: weekDays.map(({ date, dayOfWeek, isToday: dayIsToday }) => {
9767
9798
  const dayDeliveries = deliveriesByDay.get(dayOfWeek) ?? [];
9768
- const dayCommentCount = commentCountByDay.get(dayOfWeek) ?? 0;
9769
9799
  return /* @__PURE__ */ jsxRuntime.jsxs(
9770
9800
  "div",
9771
9801
  {
@@ -9774,52 +9804,31 @@ function WeeklyLoadingView({
9774
9804
  ),
9775
9805
  children: [
9776
9806
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2", children: [
9777
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9778
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9779
- "text-xs font-medium uppercase",
9780
- dayIsToday ? "text-primary" : "text-muted-foreground"
9781
- ), children: getShortDayLabel(dayOfWeek) }),
9782
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9783
- "text-base font-semibold tabular-nums",
9784
- dayIsToday ? "text-primary" : "text-foreground"
9785
- ), children: date.getDate() }),
9786
- dayIsToday && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-primary font-medium", children: "Today" })
9787
- ] }),
9788
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9789
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
9790
- dayDeliveries.length,
9791
- " ",
9792
- dayDeliveries.length === 1 ? "delivery" : "deliveries"
9807
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
9808
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center min-w-[40px]", children: [
9809
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9810
+ "text-[11px] font-semibold uppercase tracking-wide leading-none",
9811
+ dayIsToday ? "text-primary" : "text-muted-foreground"
9812
+ ), children: getShortDayLabel(dayOfWeek) }),
9813
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
9814
+ "text-lg font-medium tabular-nums leading-tight mt-0.5",
9815
+ dayIsToday ? "text-primary" : "text-foreground"
9816
+ ), children: date.getDate() })
9793
9817
  ] }),
9794
- /* @__PURE__ */ jsxRuntime.jsxs(
9795
- Button,
9796
- {
9797
- variant: "ghost",
9798
- size: "icon",
9799
- className: cn(
9800
- "h-7 w-7",
9801
- dayCommentCount > 0 && "text-primary"
9802
- ),
9803
- onClick: (e) => {
9804
- e.stopPropagation();
9805
- onDayCommentClick?.(dayOfWeek, date);
9806
- },
9807
- children: [
9808
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
9809
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-4 w-4" }),
9810
- dayCommentCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-primary" })
9811
- ] }),
9812
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Comments" })
9813
- ]
9814
- }
9815
- )
9818
+ dayIsToday && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-primary font-medium bg-primary/10 px-2 py-0.5 rounded", children: "Today" })
9819
+ ] }),
9820
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
9821
+ dayDeliveries.length,
9822
+ " ",
9823
+ dayDeliveries.length === 1 ? "delivery" : "deliveries"
9816
9824
  ] })
9817
9825
  ] }),
9818
9826
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-3 p-3 pt-0", children: dayDeliveries.length > 0 ? dayDeliveries.map((delivery) => /* @__PURE__ */ jsxRuntime.jsx(
9819
9827
  DeliveryBadge,
9820
9828
  {
9821
9829
  delivery,
9822
- onClick: () => onDeliveryClick?.(delivery)
9830
+ onClick: () => onDeliveryClick?.(delivery),
9831
+ onCommentClick: () => onDeliveryCommentClick?.(delivery)
9823
9832
  },
9824
9833
  delivery.id
9825
9834
  )) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground/40 py-4 text-center", children: "\u2014" }) })
@@ -9929,7 +9938,7 @@ function AddCommentDialog({
9929
9938
  }, [open]);
9930
9939
  return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-md", children: [
9931
9940
  /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
9932
- /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Add pre-unloading note" }),
9941
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Add pre-loading note" }),
9933
9942
  /* @__PURE__ */ jsxRuntime.jsxs(DialogDescription, { children: [
9934
9943
  "Add a note for ",
9935
9944
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: delivery.label }),
@@ -9945,7 +9954,7 @@ function AddCommentDialog({
9945
9954
  Textarea,
9946
9955
  {
9947
9956
  id: "comment-text",
9948
- placeholder: "Add a note before unloading...",
9957
+ placeholder: "Add a note before loading...",
9949
9958
  value: commentText,
9950
9959
  onChange: (e) => setCommentText(e.target.value),
9951
9960
  onKeyDown: handleKeyDown,
@@ -9987,7 +9996,7 @@ function CommentsSection({
9987
9996
  }) {
9988
9997
  const [viewCommentsOpen, setViewCommentsOpen] = React27__namespace.useState(true);
9989
9998
  const [addDialogOpen, setAddDialogOpen] = React27__namespace.useState(false);
9990
- const formatDate2 = (date) => {
9999
+ const formatDate3 = (date) => {
9991
10000
  return new Intl.DateTimeFormat("en-US", {
9992
10001
  month: "short",
9993
10002
  day: "numeric",
@@ -10000,7 +10009,7 @@ function CommentsSection({
10000
10009
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
10001
10010
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10002
10011
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-4 w-4 text-muted-foreground" }),
10003
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Notes before unloading" }),
10012
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Notes before loading" }),
10004
10013
  comments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", className: "text-[10px] h-5", children: comments.length })
10005
10014
  ] }),
10006
10015
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -10031,11 +10040,11 @@ function CommentsSection({
10031
10040
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
10032
10041
  comment.supplierName && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "outline", className: "text-[9px] px-1.5 py-0 h-4", children: comment.prefixName ? `${comment.supplierName} - ${comment.prefixName}` : comment.supplierName })
10033
10042
  ] }),
10034
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate2(comment.createdAt) })
10043
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
10035
10044
  ] }),
10036
10045
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: comment.text })
10037
10046
  ] }, comment.id)) })
10038
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground", children: "No pre-unloading notes yet. Add notes before confirming the load." })
10047
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground", children: "No pre-loading notes yet. Add notes before confirming the load." })
10039
10048
  ] }),
10040
10049
  /* @__PURE__ */ jsxRuntime.jsx(
10041
10050
  AddCommentDialog,
@@ -10098,7 +10107,7 @@ function DeliveryDetailPage({
10098
10107
  const addons = delivery.elements.filter((e) => e.status === "addon");
10099
10108
  return { loaded, missing, moved, addons };
10100
10109
  }, [delivery.elements]);
10101
- const preUnloadingComments = delivery.comments.filter((c) => c.context === "pre_unloading");
10110
+ const preLoadingComments = delivery.comments.filter((c) => c.context === "pre_unloading");
10102
10111
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [
10103
10112
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 px-4 py-3 border-b bg-background sticky top-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs(
10104
10113
  Button,
@@ -10147,7 +10156,7 @@ function DeliveryDetailPage({
10147
10156
  {
10148
10157
  variant: "outline",
10149
10158
  className: "bg-green-100 dark:bg-green-900/50 border-green-300 dark:border-green-700 text-green-700 dark:text-green-300",
10150
- children: "Ready to unload"
10159
+ children: "Ready to load"
10151
10160
  }
10152
10161
  )
10153
10162
  ] })
@@ -10238,13 +10247,13 @@ function DeliveryDetailPage({
10238
10247
  ] })
10239
10248
  ] })
10240
10249
  ] }),
10241
- delivery.elements.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
10250
+ (elementsByStatus.loaded.length > 0 || elementsByStatus.missing.length > 0 || elementsByStatus.moved.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
10242
10251
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10243
10252
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Package, { className: "h-4 w-4 text-muted-foreground" }),
10244
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Elements to Unload" }),
10253
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "What should be packed" }),
10245
10254
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
10246
- delivery.elements.length,
10247
- " total"
10255
+ elementsByStatus.loaded.length + elementsByStatus.missing.length + elementsByStatus.moved.length,
10256
+ " items"
10248
10257
  ] })
10249
10258
  ] }),
10250
10259
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(Table, { children: [
@@ -10255,7 +10264,7 @@ function DeliveryDetailPage({
10255
10264
  /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold text-right", children: "Size (m\xB2)" }),
10256
10265
  /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold text-center", children: "Status" })
10257
10266
  ] }) }),
10258
- /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: delivery.elements.map((element) => /* @__PURE__ */ jsxRuntime.jsxs(
10267
+ /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: [...elementsByStatus.loaded, ...elementsByStatus.missing, ...elementsByStatus.moved].map((element) => /* @__PURE__ */ jsxRuntime.jsxs(
10259
10268
  TableRow,
10260
10269
  {
10261
10270
  className: getElementRowBg(element.status),
@@ -10283,10 +10292,6 @@ function DeliveryDetailPage({
10283
10292
  element.status === "moved" && element.actualDeliveryLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[9px] text-blue-600 dark:text-blue-400", children: [
10284
10293
  "\u2192 ",
10285
10294
  element.actualDeliveryLabel
10286
- ] }),
10287
- element.status === "addon" && element.originalDeliveryLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[9px] text-purple-600 dark:text-purple-400", children: [
10288
- "from ",
10289
- element.originalDeliveryLabel
10290
10295
  ] })
10291
10296
  ] }) })
10292
10297
  ]
@@ -10295,10 +10300,48 @@ function DeliveryDetailPage({
10295
10300
  )) })
10296
10301
  ] }) })
10297
10302
  ] }),
10303
+ elementsByStatus.addons.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
10304
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10305
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 text-purple-600 dark:text-purple-400" }),
10306
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Extra items (moved to this delivery)" }),
10307
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
10308
+ elementsByStatus.addons.length,
10309
+ " items"
10310
+ ] })
10311
+ ] }),
10312
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "These items were originally planned for other deliveries but have been moved to this one." }),
10313
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-purple-200 dark:border-purple-800 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(Table, { children: [
10314
+ /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { className: "bg-purple-50/50 dark:bg-purple-950/30 hover:bg-purple-50/50 dark:hover:bg-purple-950/30", children: [
10315
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold", children: "Prefix" }),
10316
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold", children: "Type" }),
10317
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold text-right", children: "Weight" }),
10318
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold text-right", children: "Size (m\xB2)" }),
10319
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "font-semibold", children: "Moved from" })
10320
+ ] }) }),
10321
+ /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: elementsByStatus.addons.map((element) => /* @__PURE__ */ jsxRuntime.jsxs(
10322
+ TableRow,
10323
+ {
10324
+ className: "bg-purple-50/30 dark:bg-purple-950/10",
10325
+ children: [
10326
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "font-medium", children: element.prefix }),
10327
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: element.type }),
10328
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "text-right tabular-nums", children: element.weight ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
10329
+ element.weight,
10330
+ " ",
10331
+ element.weightUnit || "kg"
10332
+ ] }) : "\u2014" }),
10333
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "text-right tabular-nums", children: element.sizeSqm ?? "\u2014" }),
10334
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: element.originalDeliveryLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-purple-600 dark:text-purple-400", children: element.originalDeliveryLabel }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" }) })
10335
+ ]
10336
+ },
10337
+ element.id
10338
+ )) })
10339
+ ] }) })
10340
+ ] }),
10298
10341
  /* @__PURE__ */ jsxRuntime.jsx(
10299
10342
  CommentsSection,
10300
10343
  {
10301
- comments: preUnloadingComments,
10344
+ comments: preLoadingComments,
10302
10345
  delivery,
10303
10346
  weekId: week.weekKey,
10304
10347
  onAddComment
@@ -10335,6 +10378,9 @@ function SupplierWeeklyLoading({
10335
10378
  }) {
10336
10379
  const [selectedDelivery, setSelectedDelivery] = React27__namespace.useState(null);
10337
10380
  const [sheetOpen, setSheetOpen] = React27__namespace.useState(false);
10381
+ const [commentDelivery, setCommentDelivery] = React27__namespace.useState(null);
10382
+ const [commentDialogOpen, setCommentDialogOpen] = React27__namespace.useState(false);
10383
+ const [commentText, setCommentText] = React27__namespace.useState("");
10338
10384
  const handleDeliveryClick = (delivery) => {
10339
10385
  setSelectedDelivery(delivery);
10340
10386
  setSheetOpen(true);
@@ -10345,6 +10391,38 @@ function SupplierWeeklyLoading({
10345
10391
  setTimeout(() => setSelectedDelivery(null), 200);
10346
10392
  onBack?.();
10347
10393
  };
10394
+ const handleDeliveryCommentClick = (delivery) => {
10395
+ setCommentDelivery(delivery);
10396
+ setCommentDialogOpen(true);
10397
+ };
10398
+ const handleCommentDialogClose = () => {
10399
+ setCommentDialogOpen(false);
10400
+ setCommentText("");
10401
+ setTimeout(() => setCommentDelivery(null), 200);
10402
+ };
10403
+ const handleCommentSubmit = () => {
10404
+ if (commentText.trim() && commentDelivery && onAddComment) {
10405
+ onAddComment({
10406
+ author: "Current User",
10407
+ // Would come from auth context in real app
10408
+ text: commentText.trim(),
10409
+ context: "pre_unloading",
10410
+ weekId: week.weekKey,
10411
+ deliveryId: commentDelivery.id,
10412
+ supplierId: commentDelivery.supplierId,
10413
+ supplierName: commentDelivery.supplierName,
10414
+ prefixId: commentDelivery.prefixScope,
10415
+ prefixName: commentDelivery.prefixScope
10416
+ });
10417
+ handleCommentDialogClose();
10418
+ }
10419
+ };
10420
+ const handleCommentKeyDown = (e) => {
10421
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
10422
+ e.preventDefault();
10423
+ handleCommentSubmit();
10424
+ }
10425
+ };
10348
10426
  const Wrapper = bordered ? Card : "div";
10349
10427
  const Content14 = bordered ? CardContent : "div";
10350
10428
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -10363,6 +10441,7 @@ function SupplierWeeklyLoading({
10363
10441
  week,
10364
10442
  deliveries,
10365
10443
  onDeliveryClick: handleDeliveryClick,
10444
+ onDeliveryCommentClick: handleDeliveryCommentClick,
10366
10445
  onWeekChange,
10367
10446
  showNavigation
10368
10447
  }
@@ -10391,7 +10470,58 @@ function SupplierWeeklyLoading({
10391
10470
  )
10392
10471
  ]
10393
10472
  }
10394
- ) })
10473
+ ) }),
10474
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: commentDialogOpen, onOpenChange: (open) => !open && handleCommentDialogClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-md", children: [
10475
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
10476
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Add pre-loading note" }),
10477
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogDescription, { children: [
10478
+ "Add a note for ",
10479
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: commentDelivery?.label }),
10480
+ " (",
10481
+ commentDelivery?.supplierName,
10482
+ commentDelivery?.prefixScope && ` \u2022 ${commentDelivery.prefixScope}`,
10483
+ ")."
10484
+ ] })
10485
+ ] }),
10486
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
10487
+ /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: "card-comment-text", className: "text-sm font-medium", children: "Note" }),
10488
+ /* @__PURE__ */ jsxRuntime.jsx(
10489
+ Textarea,
10490
+ {
10491
+ id: "card-comment-text",
10492
+ placeholder: "Add a note before loading...",
10493
+ value: commentText,
10494
+ onChange: (e) => setCommentText(e.target.value),
10495
+ onKeyDown: handleCommentKeyDown,
10496
+ className: "min-h-[120px] text-base resize-none",
10497
+ autoFocus: true
10498
+ }
10499
+ ),
10500
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "\u2318+Enter to save" })
10501
+ ] }) }),
10502
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { className: "gap-2 sm:gap-0", children: [
10503
+ /* @__PURE__ */ jsxRuntime.jsx(
10504
+ Button,
10505
+ {
10506
+ variant: "ghost",
10507
+ onClick: handleCommentDialogClose,
10508
+ children: "Cancel"
10509
+ }
10510
+ ),
10511
+ /* @__PURE__ */ jsxRuntime.jsxs(
10512
+ Button,
10513
+ {
10514
+ onClick: handleCommentSubmit,
10515
+ disabled: !commentText.trim(),
10516
+ className: "gap-1.5",
10517
+ children: [
10518
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-4 w-4" }),
10519
+ "Save note"
10520
+ ]
10521
+ }
10522
+ )
10523
+ ] })
10524
+ ] }) })
10395
10525
  ] });
10396
10526
  }
10397
10527
  function getStatusBadgeVariant3(status) {
@@ -10902,11 +11032,11 @@ function getVisibleHours(visibleHours, singleDayEvents) {
10902
11032
  function getCalendarCells(selectedDate) {
10903
11033
  const currentYear = selectedDate.getFullYear();
10904
11034
  const currentMonth = selectedDate.getMonth();
10905
- const getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
11035
+ const getDaysInMonth2 = (year, month) => new Date(year, month + 1, 0).getDate();
10906
11036
  const getFirstDayOfMonth = (year, month) => new Date(year, month, 1).getDay();
10907
- const daysInMonth = getDaysInMonth(currentYear, currentMonth);
11037
+ const daysInMonth = getDaysInMonth2(currentYear, currentMonth);
10908
11038
  const firstDayOfMonth = getFirstDayOfMonth(currentYear, currentMonth);
10909
- const daysInPrevMonth = getDaysInMonth(currentYear, currentMonth - 1);
11039
+ const daysInPrevMonth = getDaysInMonth2(currentYear, currentMonth - 1);
10910
11040
  const totalDays = firstDayOfMonth + daysInMonth;
10911
11041
  const prevMonthCells = Array.from({ length: firstDayOfMonth }, (_, i) => ({
10912
11042
  day: daysInPrevMonth - firstDayOfMonth + i + 1,
@@ -13627,6 +13757,1569 @@ function CalendarView({
13627
13757
  return null;
13628
13758
  }
13629
13759
  }
13760
+ var draggingAtom = jotai.atom(false);
13761
+ var scrollXAtom = jotai.atom(0);
13762
+ var useGanttDragging = () => jotai.useAtom(draggingAtom);
13763
+ var useGanttScrollX = () => jotai.useAtom(scrollXAtom);
13764
+ var getDifferenceIn = (range) => {
13765
+ if (range === "weekly") {
13766
+ return dateFns.differenceInWeeks;
13767
+ }
13768
+ return dateFns.differenceInMonths;
13769
+ };
13770
+ var getInnerDifferenceIn = (range) => {
13771
+ if (range === "weekly") {
13772
+ return dateFns.differenceInDays;
13773
+ }
13774
+ return dateFns.differenceInDays;
13775
+ };
13776
+ var getStartOf = (range) => {
13777
+ if (range === "weekly") {
13778
+ return (date) => dateFns.startOfWeek(date, { weekStartsOn: 1 });
13779
+ }
13780
+ return dateFns.startOfMonth;
13781
+ };
13782
+ var getEndOf = (range) => {
13783
+ if (range === "weekly") {
13784
+ return (date) => dateFns.endOfWeek(date, { weekStartsOn: 1 });
13785
+ }
13786
+ return dateFns.endOfMonth;
13787
+ };
13788
+ var getAddRange = (range) => {
13789
+ if (range === "weekly") {
13790
+ return dateFns.addWeeks;
13791
+ }
13792
+ return dateFns.addMonths;
13793
+ };
13794
+ var getDateByMousePosition = (context, mouseX) => {
13795
+ const columnWidth = context.columnWidth * context.zoom / 100;
13796
+ const offset = Math.floor(mouseX / columnWidth);
13797
+ const addRange = getAddRange(context.range);
13798
+ if (context.range === "weekly") {
13799
+ const firstYear = context.timelineData[0].year;
13800
+ const weekStart = getWeekStartDate(firstYear, 1);
13801
+ const targetWeekStart = addRange(weekStart, offset);
13802
+ const pixelsPerDay2 = columnWidth / 7;
13803
+ const dayOffset2 = Math.floor(mouseX % columnWidth / pixelsPerDay2);
13804
+ return dateFns.addDays(targetWeekStart, dayOffset2);
13805
+ }
13806
+ const timelineStartDate = new Date(context.timelineData[0].year, 0, 1);
13807
+ const month = addRange(timelineStartDate, offset);
13808
+ const daysInMonth = dateFns.getDaysInMonth(month);
13809
+ const pixelsPerDay = Math.round(columnWidth / daysInMonth);
13810
+ const dayOffset = Math.floor(mouseX % columnWidth / pixelsPerDay);
13811
+ return dateFns.addDays(month, dayOffset);
13812
+ };
13813
+ var createInitialTimelineData = (today) => {
13814
+ const data = [];
13815
+ data.push(
13816
+ { year: today.getFullYear() - 1, quarters: new Array(4).fill(null) },
13817
+ { year: today.getFullYear(), quarters: new Array(4).fill(null) },
13818
+ { year: today.getFullYear() + 1, quarters: new Array(4).fill(null) }
13819
+ );
13820
+ for (const yearObj of data) {
13821
+ yearObj.quarters = new Array(4).fill(null).map((_, quarterIndex) => ({
13822
+ months: new Array(3).fill(null).map((_2, monthIndex) => {
13823
+ const month = quarterIndex * 3 + monthIndex;
13824
+ return {
13825
+ days: dateFns.getDaysInMonth(new Date(yearObj.year, month, 1))
13826
+ };
13827
+ })
13828
+ }));
13829
+ }
13830
+ return data;
13831
+ };
13832
+ var getOffset = (date, timelineStartDate, context) => {
13833
+ const parsedColumnWidth = context.columnWidth * context.zoom / 100;
13834
+ const differenceIn = getDifferenceIn(context.range);
13835
+ const startOf = getStartOf(context.range);
13836
+ const fullColumns = differenceIn(startOf(date), startOf(timelineStartDate));
13837
+ if (context.range === "weekly") {
13838
+ const weekStart = startOf(date);
13839
+ const dayOfWeek = dateFns.differenceInDays(date, weekStart);
13840
+ const pixelsPerDay2 = parsedColumnWidth / 7;
13841
+ return fullColumns * parsedColumnWidth + dayOfWeek * pixelsPerDay2;
13842
+ }
13843
+ const partialColumns = date.getDate();
13844
+ const daysInMonth = dateFns.getDaysInMonth(date);
13845
+ const pixelsPerDay = parsedColumnWidth / daysInMonth;
13846
+ return fullColumns * parsedColumnWidth + partialColumns * pixelsPerDay;
13847
+ };
13848
+ var getWidth = (startAt, endAt, context) => {
13849
+ const parsedColumnWidth = context.columnWidth * context.zoom / 100;
13850
+ if (!endAt) {
13851
+ return parsedColumnWidth * 2;
13852
+ }
13853
+ const startOf = getStartOf(context.range);
13854
+ if (context.range === "weekly") {
13855
+ const pixelsPerDay = parsedColumnWidth / 7;
13856
+ const daysDiff = dateFns.differenceInDays(endAt, startAt);
13857
+ return Math.max(pixelsPerDay, daysDiff * pixelsPerDay);
13858
+ }
13859
+ const differenceIn = getDifferenceIn(context.range);
13860
+ const daysInStartMonth = dateFns.getDaysInMonth(startAt);
13861
+ const pixelsPerDayInStartMonth = parsedColumnWidth / daysInStartMonth;
13862
+ if (dateFns.isSameDay(startAt, endAt)) {
13863
+ return pixelsPerDayInStartMonth;
13864
+ }
13865
+ const innerDifferenceIn = getInnerDifferenceIn(context.range);
13866
+ if (dateFns.isSameDay(startOf(startAt), startOf(endAt))) {
13867
+ return innerDifferenceIn(endAt, startAt) * pixelsPerDayInStartMonth;
13868
+ }
13869
+ const startRangeOffset = daysInStartMonth - dateFns.getDate(startAt);
13870
+ const endRangeOffset = dateFns.getDate(endAt);
13871
+ const fullRangeOffset = differenceIn(startOf(endAt), startOf(startAt));
13872
+ const daysInEndMonth = dateFns.getDaysInMonth(endAt);
13873
+ const pixelsPerDayInEndMonth = parsedColumnWidth / daysInEndMonth;
13874
+ return (fullRangeOffset - 1) * parsedColumnWidth + startRangeOffset * pixelsPerDayInStartMonth + endRangeOffset * pixelsPerDayInEndMonth;
13875
+ };
13876
+ var calculateInnerOffset = (date, range, columnWidth) => {
13877
+ const startOf = getStartOf(range);
13878
+ const endOf = getEndOf(range);
13879
+ const startOfRange = startOf(date);
13880
+ const endOfRange = endOf(date);
13881
+ if (range === "weekly") {
13882
+ const dayOfWeek = dateFns.differenceInDays(date, startOfRange);
13883
+ return dayOfWeek / 7 * columnWidth;
13884
+ }
13885
+ const totalRangeDays = dateFns.differenceInDays(endOfRange, startOfRange);
13886
+ const dayOfMonth = date.getDate();
13887
+ return dayOfMonth / totalRangeDays * columnWidth;
13888
+ };
13889
+ var GanttContext = React27.createContext({
13890
+ zoom: 100,
13891
+ range: "monthly",
13892
+ columnWidth: 50,
13893
+ headerHeight: 60,
13894
+ sidebarWidth: 300,
13895
+ rowHeight: 36,
13896
+ onAddItem: void 0,
13897
+ placeholderLength: 2,
13898
+ timelineData: [],
13899
+ ref: null,
13900
+ scrollToFeature: void 0,
13901
+ expandedGroups: {},
13902
+ setGroupExpanded: () => {
13903
+ }
13904
+ });
13905
+ var GanttContentHeader = ({
13906
+ title,
13907
+ columns,
13908
+ renderHeaderItem
13909
+ }) => {
13910
+ const id = React27.useId();
13911
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13912
+ "div",
13913
+ {
13914
+ className: "sticky top-0 z-20 grid w-full shrink-0 bg-background/95 backdrop-blur-sm",
13915
+ style: { height: "var(--gantt-header-height)" },
13916
+ children: [
13917
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
13918
+ "div",
13919
+ {
13920
+ className: "sticky inline-flex whitespace-nowrap px-3 py-2 text-muted-foreground text-xs",
13921
+ style: {
13922
+ left: "var(--gantt-sidebar-width)"
13923
+ },
13924
+ children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: title })
13925
+ }
13926
+ ) }),
13927
+ /* @__PURE__ */ jsxRuntime.jsx(
13928
+ "div",
13929
+ {
13930
+ className: "grid w-full",
13931
+ style: {
13932
+ gridTemplateColumns: `repeat(${columns}, var(--gantt-column-width))`
13933
+ },
13934
+ children: Array.from({ length: columns }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
13935
+ "div",
13936
+ {
13937
+ className: "shrink-0 border-border/50 border-b py-1 text-center text-xs",
13938
+ children: renderHeaderItem(index)
13939
+ },
13940
+ `${id}-${index}`
13941
+ ))
13942
+ }
13943
+ )
13944
+ ]
13945
+ }
13946
+ );
13947
+ };
13948
+ var getWeeksInYear = (year) => {
13949
+ const dec28 = new Date(year, 11, 28);
13950
+ return dateFns.getISOWeek(dec28);
13951
+ };
13952
+ var getWeekStartDate = (year, weekNumber) => {
13953
+ const jan4 = new Date(year, 0, 4);
13954
+ const week1Start = dateFns.startOfWeek(jan4, { weekStartsOn: 1 });
13955
+ return dateFns.addWeeks(week1Start, weekNumber - 1);
13956
+ };
13957
+ var WeeklyHeader = () => {
13958
+ const gantt = React27.useContext(GanttContext);
13959
+ const weeklyData = React27.useMemo(() => {
13960
+ const result = [];
13961
+ for (const yearData of gantt.timelineData) {
13962
+ const year = yearData.year;
13963
+ const weeksInYear = getWeeksInYear(year);
13964
+ const weeks = [];
13965
+ for (let w = 1; w <= weeksInYear; w++) {
13966
+ weeks.push({
13967
+ weekNumber: w,
13968
+ startDate: getWeekStartDate(year, w)
13969
+ });
13970
+ }
13971
+ result.push({ year, weeks });
13972
+ }
13973
+ return result;
13974
+ }, [gantt.timelineData]);
13975
+ return weeklyData.map((yearData) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col", children: [
13976
+ /* @__PURE__ */ jsxRuntime.jsx(
13977
+ GanttContentHeader,
13978
+ {
13979
+ columns: yearData.weeks.length,
13980
+ renderHeaderItem: (weekIndex) => {
13981
+ const week = yearData.weeks[weekIndex];
13982
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
13983
+ "W",
13984
+ week.weekNumber.toString().padStart(2, "0")
13985
+ ] }) });
13986
+ },
13987
+ title: `${yearData.year}`
13988
+ }
13989
+ ),
13990
+ /* @__PURE__ */ jsxRuntime.jsx(GanttColumns, { columns: yearData.weeks.length })
13991
+ ] }, yearData.year));
13992
+ };
13993
+ var MonthlyHeader = () => {
13994
+ const gantt = React27.useContext(GanttContext);
13995
+ return gantt.timelineData.map((year) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col", children: [
13996
+ /* @__PURE__ */ jsxRuntime.jsx(
13997
+ GanttContentHeader,
13998
+ {
13999
+ columns: year.quarters.flatMap((quarter) => quarter.months).length,
14000
+ renderHeaderItem: (item) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: dateFns.format(new Date(year.year, item, 1), "MMM") }),
14001
+ title: `${year.year}`
14002
+ }
14003
+ ),
14004
+ /* @__PURE__ */ jsxRuntime.jsx(
14005
+ GanttColumns,
14006
+ {
14007
+ columns: year.quarters.flatMap((quarter) => quarter.months).length
14008
+ }
14009
+ )
14010
+ ] }, year.year));
14011
+ };
14012
+ var QuarterlyHeader = () => {
14013
+ const gantt = React27.useContext(GanttContext);
14014
+ return gantt.timelineData.map(
14015
+ (year) => year.quarters.map((quarter, quarterIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
14016
+ "div",
14017
+ {
14018
+ className: "relative flex flex-col",
14019
+ children: [
14020
+ /* @__PURE__ */ jsxRuntime.jsx(
14021
+ GanttContentHeader,
14022
+ {
14023
+ columns: quarter.months.length,
14024
+ renderHeaderItem: (item) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: dateFns.format(new Date(year.year, quarterIndex * 3 + item, 1), "MMM") }),
14025
+ title: `Q${quarterIndex + 1} ${year.year}`
14026
+ }
14027
+ ),
14028
+ /* @__PURE__ */ jsxRuntime.jsx(GanttColumns, { columns: quarter.months.length })
14029
+ ]
14030
+ },
14031
+ `${year.year}-${quarterIndex}`
14032
+ ))
14033
+ );
14034
+ };
14035
+ var headers = {
14036
+ weekly: WeeklyHeader,
14037
+ monthly: MonthlyHeader,
14038
+ quarterly: QuarterlyHeader
14039
+ };
14040
+ var GanttHeader = ({ className }) => {
14041
+ const gantt = React27.useContext(GanttContext);
14042
+ const Header2 = headers[gantt.range];
14043
+ return /* @__PURE__ */ jsxRuntime.jsx(
14044
+ "div",
14045
+ {
14046
+ className: cn(
14047
+ "-space-x-px flex h-full w-max divide-x-2 divide-border",
14048
+ className
14049
+ ),
14050
+ children: /* @__PURE__ */ jsxRuntime.jsx(Header2, {})
14051
+ }
14052
+ );
14053
+ };
14054
+ var GanttSidebarItem = ({
14055
+ feature,
14056
+ onSelectItem,
14057
+ className
14058
+ }) => {
14059
+ const gantt = React27.useContext(GanttContext);
14060
+ const tempEndAt = feature.endAt && dateFns.isSameDay(feature.startAt, feature.endAt) ? dateFns.addDays(feature.endAt, 1) : feature.endAt;
14061
+ const duration = tempEndAt ? dateFns.formatDistance(feature.startAt, tempEndAt) : `${dateFns.formatDistance(feature.startAt, /* @__PURE__ */ new Date())} so far`;
14062
+ const handleClick = (event) => {
14063
+ if (event.target === event.currentTarget) {
14064
+ gantt.scrollToFeature?.(feature);
14065
+ onSelectItem?.(feature.id);
14066
+ }
14067
+ };
14068
+ const handleKeyDown = (event) => {
14069
+ if (event.key === "Enter") {
14070
+ gantt.scrollToFeature?.(feature);
14071
+ onSelectItem?.(feature.id);
14072
+ }
14073
+ };
14074
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14075
+ "div",
14076
+ {
14077
+ className: cn(
14078
+ "relative flex items-center gap-2.5 px-2.5 py-1.5 text-xs hover:bg-muted/50 border-b border-border/30",
14079
+ className
14080
+ ),
14081
+ onClick: handleClick,
14082
+ onKeyDown: handleKeyDown,
14083
+ role: "button",
14084
+ style: {
14085
+ height: "var(--gantt-row-height)"
14086
+ },
14087
+ tabIndex: 0,
14088
+ children: [
14089
+ /* @__PURE__ */ jsxRuntime.jsx(
14090
+ "div",
14091
+ {
14092
+ className: "pointer-events-none h-2 w-2 shrink-0 rounded-full",
14093
+ style: {
14094
+ backgroundColor: feature.status.color
14095
+ }
14096
+ }
14097
+ ),
14098
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pointer-events-none flex-1 truncate text-left font-medium", children: feature.name }),
14099
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pointer-events-none text-muted-foreground text-[11px]", children: duration })
14100
+ ]
14101
+ },
14102
+ feature.id
14103
+ );
14104
+ };
14105
+ var GanttSidebarHeader = ({
14106
+ title = "Tasks",
14107
+ durationLabel = "Duration"
14108
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(
14109
+ "div",
14110
+ {
14111
+ className: "sticky top-0 z-10 flex shrink-0 items-end justify-between gap-2.5 border-border/50 border-b bg-background/95 px-2.5 py-2 font-medium text-muted-foreground text-xs backdrop-blur-sm",
14112
+ style: { height: "var(--gantt-header-height)" },
14113
+ children: [
14114
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "flex-1 truncate text-left", children: title }),
14115
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0", children: durationLabel })
14116
+ ]
14117
+ }
14118
+ );
14119
+ function computeGroupRange(features) {
14120
+ if (features.length === 0) {
14121
+ return { start: null, end: null };
14122
+ }
14123
+ let minStart = features[0].startAt;
14124
+ let maxEnd = features[0].endAt;
14125
+ for (const feature of features) {
14126
+ if (feature.startAt < minStart) {
14127
+ minStart = feature.startAt;
14128
+ }
14129
+ if (feature.endAt > maxEnd) {
14130
+ maxEnd = feature.endAt;
14131
+ }
14132
+ }
14133
+ return { start: minStart, end: maxEnd };
14134
+ }
14135
+ var GanttGroupSummaryBar = React27.memo(({
14136
+ group,
14137
+ className
14138
+ }) => {
14139
+ const gantt = React27.useContext(GanttContext);
14140
+ const timelineStartDate = React27.useMemo(
14141
+ () => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
14142
+ [gantt.timelineData]
14143
+ );
14144
+ const { start: groupStart, end: groupEnd } = React27.useMemo(
14145
+ () => computeGroupRange(group.features),
14146
+ [group.features]
14147
+ );
14148
+ const offset = React27.useMemo(() => {
14149
+ if (!groupStart) return 0;
14150
+ return Math.round(getOffset(groupStart, timelineStartDate, gantt));
14151
+ }, [groupStart, timelineStartDate, gantt]);
14152
+ const width = React27.useMemo(() => {
14153
+ if (!groupStart || !groupEnd) return 0;
14154
+ return Math.round(getWidth(groupStart, groupEnd, gantt));
14155
+ }, [groupStart, groupEnd, gantt]);
14156
+ if (!groupStart || !groupEnd || width === 0) {
14157
+ return null;
14158
+ }
14159
+ return /* @__PURE__ */ jsxRuntime.jsx(
14160
+ "div",
14161
+ {
14162
+ className: cn(
14163
+ "absolute pointer-events-none",
14164
+ className
14165
+ ),
14166
+ style: {
14167
+ height: "calc(var(--gantt-row-height) - 12px)",
14168
+ top: "6px",
14169
+ width,
14170
+ left: offset
14171
+ },
14172
+ children: /* @__PURE__ */ jsxRuntime.jsx(
14173
+ "div",
14174
+ {
14175
+ className: "h-full w-full rounded-sm border border-border/60 bg-muted/40 shadow-sm",
14176
+ style: {
14177
+ // Subtle gradient for depth
14178
+ background: "linear-gradient(180deg, hsl(var(--muted) / 0.5) 0%, hsl(var(--muted) / 0.3) 100%)"
14179
+ }
14180
+ }
14181
+ )
14182
+ }
14183
+ );
14184
+ });
14185
+ GanttGroupSummaryBar.displayName = "GanttGroupSummaryBar";
14186
+ var GanttCollapsibleSidebarGroup = ({
14187
+ group,
14188
+ children,
14189
+ className
14190
+ }) => {
14191
+ const gantt = React27.useContext(GanttContext);
14192
+ const isExpanded = gantt.expandedGroups[group.id] ?? true;
14193
+ const { start: groupStart, end: groupEnd } = React27.useMemo(
14194
+ () => computeGroupRange(group.features),
14195
+ [group.features]
14196
+ );
14197
+ const duration = React27.useMemo(() => {
14198
+ if (!groupStart || !groupEnd) return null;
14199
+ return dateFns.formatDistance(groupStart, groupEnd);
14200
+ }, [groupStart, groupEnd]);
14201
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14202
+ Collapsible,
14203
+ {
14204
+ open: isExpanded,
14205
+ onOpenChange: (open) => gantt.setGroupExpanded(group.id, open),
14206
+ className,
14207
+ children: [
14208
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
14209
+ "button",
14210
+ {
14211
+ className: "flex w-full items-center gap-2 px-2.5 py-2 text-left font-medium text-xs hover:bg-muted/30 border-b border-border/50 bg-background",
14212
+ style: { height: "var(--gantt-row-height)" },
14213
+ type: "button",
14214
+ children: [
14215
+ /* @__PURE__ */ jsxRuntime.jsx(
14216
+ lucideReact.ChevronRightIcon,
14217
+ {
14218
+ className: cn(
14219
+ "h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200",
14220
+ isExpanded && "rotate-90"
14221
+ )
14222
+ }
14223
+ ),
14224
+ group.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: group.icon }),
14225
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: group.title }),
14226
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground", children: group.features.length }),
14227
+ duration && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: duration })
14228
+ ]
14229
+ }
14230
+ ) }),
14231
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent2, { className: "[&[data-state]]:!opacity-100", children })
14232
+ ]
14233
+ }
14234
+ );
14235
+ };
14236
+ var GanttCollapsibleTimelineGroup = ({
14237
+ group,
14238
+ children,
14239
+ className
14240
+ }) => {
14241
+ const gantt = React27.useContext(GanttContext);
14242
+ const isExpanded = gantt.expandedGroups[group.id] ?? true;
14243
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14244
+ Collapsible,
14245
+ {
14246
+ open: isExpanded,
14247
+ onOpenChange: (open) => gantt.setGroupExpanded(group.id, open),
14248
+ className,
14249
+ children: [
14250
+ /* @__PURE__ */ jsxRuntime.jsx(
14251
+ "div",
14252
+ {
14253
+ className: "relative w-full border-b border-border/50",
14254
+ style: { height: "var(--gantt-row-height)" },
14255
+ children: /* @__PURE__ */ jsxRuntime.jsx(GanttGroupSummaryBar, { group })
14256
+ }
14257
+ ),
14258
+ /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent2, { className: "[&[data-state]]:!opacity-100", children })
14259
+ ]
14260
+ }
14261
+ );
14262
+ };
14263
+ var GanttSidebarGroup = ({
14264
+ children,
14265
+ name,
14266
+ className
14267
+ }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
14268
+ /* @__PURE__ */ jsxRuntime.jsx(
14269
+ "p",
14270
+ {
14271
+ className: "w-full truncate px-2.5 py-2 text-left font-medium text-muted-foreground text-xs border-b border-border/50 bg-background",
14272
+ style: { height: "var(--gantt-row-height)" },
14273
+ children: name
14274
+ }
14275
+ ),
14276
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children })
14277
+ ] });
14278
+ var GanttSidebar = ({
14279
+ children,
14280
+ className
14281
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(
14282
+ "div",
14283
+ {
14284
+ className: cn(
14285
+ "sticky left-0 z-30 h-max min-h-full border-border/50 border-r bg-background",
14286
+ className
14287
+ ),
14288
+ style: { width: "var(--gantt-sidebar-width)" },
14289
+ "data-roadmap-ui": "gantt-sidebar",
14290
+ children: [
14291
+ /* @__PURE__ */ jsxRuntime.jsx(GanttSidebarHeader, {}),
14292
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children })
14293
+ ]
14294
+ }
14295
+ );
14296
+ var GanttAddFeatureHelper = ({
14297
+ top,
14298
+ className
14299
+ }) => {
14300
+ const [scrollX] = useGanttScrollX();
14301
+ const gantt = React27.useContext(GanttContext);
14302
+ const [mousePosition, mouseRef] = usehooks.useMouse();
14303
+ const handleClick = () => {
14304
+ const ganttRect = gantt.ref?.current?.getBoundingClientRect();
14305
+ const x = mousePosition.x - (ganttRect?.left ?? 0) + scrollX - gantt.sidebarWidth;
14306
+ const currentDate = getDateByMousePosition(gantt, x);
14307
+ gantt.onAddItem?.(currentDate);
14308
+ };
14309
+ return /* @__PURE__ */ jsxRuntime.jsx(
14310
+ "div",
14311
+ {
14312
+ className: cn("absolute top-0 w-full px-0.5", className),
14313
+ ref: mouseRef,
14314
+ style: {
14315
+ marginTop: -gantt.rowHeight / 2,
14316
+ transform: `translateY(${top}px)`
14317
+ },
14318
+ children: /* @__PURE__ */ jsxRuntime.jsx(
14319
+ "button",
14320
+ {
14321
+ className: "flex h-full w-full items-center justify-center rounded-sm border border-dashed p-2",
14322
+ onClick: handleClick,
14323
+ type: "button",
14324
+ children: /* @__PURE__ */ jsxRuntime.jsx(
14325
+ lucideReact.PlusIcon,
14326
+ {
14327
+ className: "pointer-events-none select-none text-muted-foreground",
14328
+ size: 16
14329
+ }
14330
+ )
14331
+ }
14332
+ )
14333
+ }
14334
+ );
14335
+ };
14336
+ var GanttColumn = ({
14337
+ index,
14338
+ isColumnSecondary
14339
+ }) => {
14340
+ const gantt = React27.useContext(GanttContext);
14341
+ const [dragging] = useGanttDragging();
14342
+ const [mousePosition, mouseRef] = usehooks.useMouse();
14343
+ const [hovering, setHovering] = React27.useState(false);
14344
+ const [windowScroll] = usehooks.useWindowScroll();
14345
+ const handleMouseEnter = () => setHovering(true);
14346
+ const handleMouseLeave = () => setHovering(false);
14347
+ const top = usehooks.useThrottle(
14348
+ mousePosition.y - (mouseRef.current?.getBoundingClientRect().y ?? 0) - (windowScroll.y ?? 0),
14349
+ 10
14350
+ );
14351
+ return (
14352
+ // biome-ignore lint/a11y/noStaticElementInteractions: "This is a clickable column"
14353
+ // biome-ignore lint/nursery/noNoninteractiveElementInteractions: "This is a clickable column"
14354
+ /* @__PURE__ */ jsxRuntime.jsx(
14355
+ "div",
14356
+ {
14357
+ className: cn(
14358
+ "group relative h-full overflow-hidden",
14359
+ isColumnSecondary?.(index) ? "bg-muted/30" : ""
14360
+ ),
14361
+ onMouseEnter: handleMouseEnter,
14362
+ onMouseLeave: handleMouseLeave,
14363
+ ref: mouseRef,
14364
+ children: !dragging && hovering && gantt.onAddItem ? /* @__PURE__ */ jsxRuntime.jsx(GanttAddFeatureHelper, { top }) : null
14365
+ }
14366
+ )
14367
+ );
14368
+ };
14369
+ var GanttColumns = ({
14370
+ columns,
14371
+ isColumnSecondary
14372
+ }) => {
14373
+ const id = React27.useId();
14374
+ return /* @__PURE__ */ jsxRuntime.jsx(
14375
+ "div",
14376
+ {
14377
+ className: "divide grid h-full w-full divide-x divide-border",
14378
+ style: {
14379
+ gridTemplateColumns: `repeat(${columns}, var(--gantt-column-width))`
14380
+ },
14381
+ children: Array.from({ length: columns }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
14382
+ GanttColumn,
14383
+ {
14384
+ index,
14385
+ isColumnSecondary
14386
+ },
14387
+ `${id}-${index}`
14388
+ ))
14389
+ }
14390
+ );
14391
+ };
14392
+ var GanttGridLines = React27.memo(({
14393
+ className
14394
+ }) => {
14395
+ const gantt = React27.useContext(GanttContext);
14396
+ const id = React27.useId();
14397
+ const { columns, monthBoundaryIndices } = React27.useMemo(() => {
14398
+ let totalColumns = 0;
14399
+ const monthIndices = [];
14400
+ if (gantt.range === "weekly") {
14401
+ let weekIndex = 0;
14402
+ for (const yearData of gantt.timelineData) {
14403
+ const weeksInYear = getWeeksInYear(yearData.year);
14404
+ let currentMonth = -1;
14405
+ for (let w = 1; w <= weeksInYear; w++) {
14406
+ const weekStart = getWeekStartDate(yearData.year, w);
14407
+ const monthOfWeek = weekStart.getMonth();
14408
+ if (monthOfWeek !== currentMonth) {
14409
+ monthIndices.push(weekIndex);
14410
+ currentMonth = monthOfWeek;
14411
+ }
14412
+ weekIndex++;
14413
+ }
14414
+ totalColumns += weeksInYear;
14415
+ }
14416
+ } else {
14417
+ for (const yearData of gantt.timelineData) {
14418
+ const monthsInYear = yearData.quarters.flatMap((q) => q.months).length;
14419
+ totalColumns += monthsInYear;
14420
+ }
14421
+ }
14422
+ return { columns: totalColumns, monthBoundaryIndices: monthIndices };
14423
+ }, [gantt.timelineData, gantt.range]);
14424
+ const columnWidth = gantt.columnWidth * gantt.zoom / 100;
14425
+ const totalWidth = columns * columnWidth;
14426
+ return /* @__PURE__ */ jsxRuntime.jsx(
14427
+ "div",
14428
+ {
14429
+ className: cn(
14430
+ "pointer-events-none absolute top-0 left-0 h-full",
14431
+ className
14432
+ ),
14433
+ style: {
14434
+ marginTop: "var(--gantt-header-height)",
14435
+ width: totalWidth
14436
+ },
14437
+ children: Array.from({ length: columns + 1 }).map((_, index) => {
14438
+ const isMonthBoundary = gantt.range === "weekly" && monthBoundaryIndices.includes(index);
14439
+ const x = Math.round(index * columnWidth);
14440
+ return /* @__PURE__ */ jsxRuntime.jsx(
14441
+ "div",
14442
+ {
14443
+ className: "absolute top-0 bottom-0",
14444
+ style: {
14445
+ left: x,
14446
+ width: isMonthBoundary ? "2px" : "1px",
14447
+ backgroundColor: isMonthBoundary ? "hsl(var(--foreground) / 0.25)" : "hsl(var(--border) / 0.8)"
14448
+ }
14449
+ },
14450
+ `${id}-grid-${index}`
14451
+ );
14452
+ })
14453
+ }
14454
+ );
14455
+ });
14456
+ GanttGridLines.displayName = "GanttGridLines";
14457
+ var GanttCreateMarkerTrigger = ({
14458
+ onCreateMarker,
14459
+ className
14460
+ }) => {
14461
+ const gantt = React27.useContext(GanttContext);
14462
+ const [mousePosition, mouseRef] = usehooks.useMouse();
14463
+ const [windowScroll] = usehooks.useWindowScroll();
14464
+ const x = usehooks.useThrottle(
14465
+ mousePosition.x - (mouseRef.current?.getBoundingClientRect().x ?? 0) - (windowScroll.x ?? 0),
14466
+ 10
14467
+ );
14468
+ const date = getDateByMousePosition(gantt, x);
14469
+ const handleClick = () => onCreateMarker(date);
14470
+ return /* @__PURE__ */ jsxRuntime.jsx(
14471
+ "div",
14472
+ {
14473
+ className: cn(
14474
+ "group pointer-events-none absolute top-0 left-0 h-full w-full select-none overflow-visible",
14475
+ className
14476
+ ),
14477
+ ref: mouseRef,
14478
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
14479
+ "div",
14480
+ {
14481
+ className: "-ml-2 pointer-events-auto sticky top-6 z-20 flex w-4 flex-col items-center justify-center gap-1 overflow-visible opacity-0 group-hover:opacity-100",
14482
+ style: { transform: `translateX(${x}px)` },
14483
+ children: [
14484
+ /* @__PURE__ */ jsxRuntime.jsx(
14485
+ "button",
14486
+ {
14487
+ className: "z-50 inline-flex h-4 w-4 items-center justify-center rounded-full bg-card",
14488
+ onClick: handleClick,
14489
+ type: "button",
14490
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { className: "text-muted-foreground", size: 12 })
14491
+ }
14492
+ ),
14493
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-nowrap rounded-sm border border-border/50 bg-background/95 px-2 py-1 text-foreground text-xs backdrop-blur-sm", children: dateFns.formatDate(date, "MMM dd, yyyy") })
14494
+ ]
14495
+ }
14496
+ )
14497
+ }
14498
+ );
14499
+ };
14500
+ var GanttFeatureDragHelper = ({
14501
+ direction,
14502
+ featureId,
14503
+ date
14504
+ }) => {
14505
+ const [, setDragging] = useGanttDragging();
14506
+ const { attributes, listeners, setNodeRef } = core.useDraggable({
14507
+ id: `feature-drag-helper-${featureId}`
14508
+ });
14509
+ const isPressed = Boolean(attributes["aria-pressed"]);
14510
+ React27.useEffect(() => setDragging(isPressed), [isPressed, setDragging]);
14511
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14512
+ "div",
14513
+ {
14514
+ className: cn(
14515
+ "group -translate-y-1/2 !cursor-col-resize absolute top-1/2 z-[3] h-full w-6 rounded-sm outline-none",
14516
+ direction === "left" ? "-left-2.5" : "-right-2.5"
14517
+ ),
14518
+ ref: setNodeRef,
14519
+ ...attributes,
14520
+ ...listeners,
14521
+ children: [
14522
+ /* @__PURE__ */ jsxRuntime.jsx(
14523
+ "div",
14524
+ {
14525
+ className: cn(
14526
+ "-translate-y-1/2 absolute top-1/2 h-[80%] w-1 rounded-sm bg-muted-foreground opacity-0 transition-all",
14527
+ direction === "left" ? "left-2.5" : "right-2.5",
14528
+ direction === "left" ? "group-hover:left-0" : "group-hover:right-0",
14529
+ isPressed && (direction === "left" ? "left-0" : "right-0"),
14530
+ "group-hover:opacity-100",
14531
+ isPressed && "opacity-100"
14532
+ )
14533
+ }
14534
+ ),
14535
+ date && /* @__PURE__ */ jsxRuntime.jsx(
14536
+ "div",
14537
+ {
14538
+ className: cn(
14539
+ "-translate-x-1/2 absolute top-10 hidden whitespace-nowrap rounded-sm border border-border/50 bg-background/95 px-2 py-1 text-foreground text-xs backdrop-blur-sm group-hover:block",
14540
+ isPressed && "block"
14541
+ ),
14542
+ children: dateFns.format(date, "MMM dd, yyyy")
14543
+ }
14544
+ )
14545
+ ]
14546
+ }
14547
+ );
14548
+ };
14549
+ var GanttFeatureItemCard = ({
14550
+ id,
14551
+ children
14552
+ }) => {
14553
+ const [, setDragging] = useGanttDragging();
14554
+ const { attributes, listeners, setNodeRef } = core.useDraggable({ id });
14555
+ const isPressed = Boolean(attributes["aria-pressed"]);
14556
+ React27.useEffect(() => setDragging(isPressed), [isPressed, setDragging]);
14557
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "h-full w-full rounded-sm border bg-background px-2 py-1.5 text-xs shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
14558
+ "div",
14559
+ {
14560
+ className: cn(
14561
+ "flex h-full w-full items-center justify-between gap-2 text-left",
14562
+ isPressed && "cursor-grabbing"
14563
+ ),
14564
+ ...attributes,
14565
+ ...listeners,
14566
+ ref: setNodeRef,
14567
+ children
14568
+ }
14569
+ ) });
14570
+ };
14571
+ var GanttFeatureItem = ({
14572
+ onMove,
14573
+ contextMenuActions,
14574
+ onEdit,
14575
+ onDelete,
14576
+ onDuplicate,
14577
+ children,
14578
+ className,
14579
+ ...feature
14580
+ }) => {
14581
+ const [scrollX] = useGanttScrollX();
14582
+ const gantt = React27.useContext(GanttContext);
14583
+ const timelineStartDate = React27.useMemo(
14584
+ () => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
14585
+ [gantt.timelineData]
14586
+ );
14587
+ const [startAt, setStartAt] = React27.useState(feature.startAt);
14588
+ const [endAt, setEndAt] = React27.useState(feature.endAt);
14589
+ const width = React27.useMemo(
14590
+ () => Math.round(getWidth(startAt, endAt, gantt)),
14591
+ [startAt, endAt, gantt]
14592
+ );
14593
+ const offset = React27.useMemo(
14594
+ () => Math.round(getOffset(startAt, timelineStartDate, gantt)),
14595
+ [startAt, timelineStartDate, gantt]
14596
+ );
14597
+ const addRange = React27.useMemo(() => getAddRange(gantt.range), [gantt.range]);
14598
+ const [mousePosition] = usehooks.useMouse();
14599
+ const [previousMouseX, setPreviousMouseX] = React27.useState(0);
14600
+ const [previousStartAt, setPreviousStartAt] = React27.useState(startAt);
14601
+ const [previousEndAt, setPreviousEndAt] = React27.useState(endAt);
14602
+ const mouseSensor = core.useSensor(core.MouseSensor, {
14603
+ activationConstraint: {
14604
+ distance: 10
14605
+ }
14606
+ });
14607
+ const handleItemDragStart = React27.useCallback(() => {
14608
+ setPreviousMouseX(mousePosition.x);
14609
+ setPreviousStartAt(startAt);
14610
+ setPreviousEndAt(endAt);
14611
+ }, [mousePosition.x, startAt, endAt]);
14612
+ const handleItemDragMove = React27.useCallback(() => {
14613
+ const currentDate = getDateByMousePosition(gantt, mousePosition.x);
14614
+ const originalDate = getDateByMousePosition(gantt, previousMouseX);
14615
+ const delta = gantt.range === "weekly" ? dateFns.differenceInDays(currentDate, originalDate) : getInnerDifferenceIn(gantt.range)(currentDate, originalDate);
14616
+ const newStartDate = dateFns.addDays(previousStartAt, delta);
14617
+ const newEndDate = previousEndAt ? dateFns.addDays(previousEndAt, delta) : null;
14618
+ setStartAt(newStartDate);
14619
+ setEndAt(newEndDate);
14620
+ }, [gantt, mousePosition.x, previousMouseX, previousStartAt, previousEndAt]);
14621
+ const onDragEnd = React27.useCallback(
14622
+ () => onMove?.(feature.id, startAt, endAt),
14623
+ [onMove, feature.id, startAt, endAt]
14624
+ );
14625
+ const handleLeftDragMove = React27.useCallback(() => {
14626
+ const ganttRect = gantt.ref?.current?.getBoundingClientRect();
14627
+ const x = mousePosition.x - (ganttRect?.left ?? 0) + scrollX - gantt.sidebarWidth;
14628
+ const newStartAt = getDateByMousePosition(gantt, x);
14629
+ setStartAt(newStartAt);
14630
+ }, [gantt, mousePosition.x, scrollX]);
14631
+ const handleRightDragMove = React27.useCallback(() => {
14632
+ const ganttRect = gantt.ref?.current?.getBoundingClientRect();
14633
+ const x = mousePosition.x - (ganttRect?.left ?? 0) + scrollX - gantt.sidebarWidth;
14634
+ const newEndAt = getDateByMousePosition(gantt, x);
14635
+ setEndAt(newEndAt);
14636
+ }, [gantt, mousePosition.x, scrollX]);
14637
+ return /* @__PURE__ */ jsxRuntime.jsx(
14638
+ "div",
14639
+ {
14640
+ className: cn("relative flex w-max min-w-full", className),
14641
+ style: { height: "var(--gantt-row-height)" },
14642
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
14643
+ "div",
14644
+ {
14645
+ className: "pointer-events-auto absolute",
14646
+ style: {
14647
+ height: "calc(var(--gantt-row-height) - 8px)",
14648
+ top: "4px",
14649
+ width,
14650
+ left: offset
14651
+ },
14652
+ children: [
14653
+ onMove && /* @__PURE__ */ jsxRuntime.jsx(
14654
+ core.DndContext,
14655
+ {
14656
+ modifiers: [modifiers.restrictToHorizontalAxis],
14657
+ onDragEnd,
14658
+ onDragMove: handleLeftDragMove,
14659
+ sensors: [mouseSensor],
14660
+ children: /* @__PURE__ */ jsxRuntime.jsx(
14661
+ GanttFeatureDragHelper,
14662
+ {
14663
+ date: startAt,
14664
+ direction: "left",
14665
+ featureId: feature.id
14666
+ }
14667
+ )
14668
+ }
14669
+ ),
14670
+ /* @__PURE__ */ jsxRuntime.jsxs(ContextMenu, { children: [
14671
+ /* @__PURE__ */ jsxRuntime.jsx(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
14672
+ core.DndContext,
14673
+ {
14674
+ modifiers: [modifiers.restrictToHorizontalAxis],
14675
+ onDragEnd,
14676
+ onDragMove: handleItemDragMove,
14677
+ onDragStart: handleItemDragStart,
14678
+ sensors: [mouseSensor],
14679
+ children: /* @__PURE__ */ jsxRuntime.jsx(GanttFeatureItemCard, { id: feature.id, children: children ?? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "flex-1 truncate text-xs", children: feature.name }) })
14680
+ }
14681
+ ) }) }),
14682
+ /* @__PURE__ */ jsxRuntime.jsxs(ContextMenuContent, { children: [
14683
+ onEdit && /* @__PURE__ */ jsxRuntime.jsxs(
14684
+ ContextMenuItem,
14685
+ {
14686
+ className: "flex items-center gap-2",
14687
+ onClick: () => onEdit(feature),
14688
+ children: [
14689
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PencilIcon, { size: 14 }),
14690
+ "Edit"
14691
+ ]
14692
+ }
14693
+ ),
14694
+ onDuplicate && /* @__PURE__ */ jsxRuntime.jsxs(
14695
+ ContextMenuItem,
14696
+ {
14697
+ className: "flex items-center gap-2",
14698
+ onClick: () => onDuplicate(feature),
14699
+ children: [
14700
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyIcon, { size: 14 }),
14701
+ "Duplicate"
14702
+ ]
14703
+ }
14704
+ ),
14705
+ contextMenuActions?.map((action, index) => /* @__PURE__ */ jsxRuntime.jsxs(
14706
+ ContextMenuItem,
14707
+ {
14708
+ className: cn(
14709
+ "flex items-center gap-2",
14710
+ action.destructive && "text-destructive"
14711
+ ),
14712
+ onClick: () => action.onClick(feature),
14713
+ disabled: action.disabled,
14714
+ children: [
14715
+ action.icon,
14716
+ action.label
14717
+ ]
14718
+ },
14719
+ index
14720
+ )),
14721
+ onDelete && /* @__PURE__ */ jsxRuntime.jsxs(
14722
+ ContextMenuItem,
14723
+ {
14724
+ className: "flex items-center gap-2 text-destructive",
14725
+ onClick: () => onDelete(feature),
14726
+ children: [
14727
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrashIcon, { size: 14 }),
14728
+ "Delete"
14729
+ ]
14730
+ }
14731
+ )
14732
+ ] })
14733
+ ] }),
14734
+ onMove && /* @__PURE__ */ jsxRuntime.jsx(
14735
+ core.DndContext,
14736
+ {
14737
+ modifiers: [modifiers.restrictToHorizontalAxis],
14738
+ onDragEnd,
14739
+ onDragMove: handleRightDragMove,
14740
+ sensors: [mouseSensor],
14741
+ children: /* @__PURE__ */ jsxRuntime.jsx(
14742
+ GanttFeatureDragHelper,
14743
+ {
14744
+ date: endAt ?? addRange(startAt, 2),
14745
+ direction: "right",
14746
+ featureId: feature.id
14747
+ }
14748
+ )
14749
+ }
14750
+ )
14751
+ ]
14752
+ }
14753
+ )
14754
+ }
14755
+ );
14756
+ };
14757
+ var GanttFeatureListGroup = ({
14758
+ children,
14759
+ className
14760
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
14761
+ "div",
14762
+ {
14763
+ className,
14764
+ style: { paddingTop: "var(--gantt-row-height)" },
14765
+ children
14766
+ }
14767
+ );
14768
+ var GanttFeatureRow = ({
14769
+ features,
14770
+ onMove,
14771
+ children,
14772
+ className
14773
+ }) => {
14774
+ const sortedFeatures = [...features].sort(
14775
+ (a, b) => a.startAt.getTime() - b.startAt.getTime()
14776
+ );
14777
+ const featureWithPositions = [];
14778
+ const subRowEndTimes = [];
14779
+ for (const feature of sortedFeatures) {
14780
+ let subRow = 0;
14781
+ while (subRow < subRowEndTimes.length && subRowEndTimes[subRow] > feature.startAt) {
14782
+ subRow++;
14783
+ }
14784
+ if (subRow === subRowEndTimes.length) {
14785
+ subRowEndTimes.push(feature.endAt);
14786
+ } else {
14787
+ subRowEndTimes[subRow] = feature.endAt;
14788
+ }
14789
+ featureWithPositions.push({ ...feature, subRow });
14790
+ }
14791
+ const maxSubRows = Math.max(1, subRowEndTimes.length);
14792
+ const subRowHeight = 36;
14793
+ return /* @__PURE__ */ jsxRuntime.jsx(
14794
+ "div",
14795
+ {
14796
+ className: cn("relative", className),
14797
+ style: {
14798
+ height: `${maxSubRows * subRowHeight}px`,
14799
+ minHeight: "var(--gantt-row-height)"
14800
+ },
14801
+ children: featureWithPositions.map((feature) => /* @__PURE__ */ jsxRuntime.jsx(
14802
+ "div",
14803
+ {
14804
+ className: "absolute w-full",
14805
+ style: {
14806
+ top: `${feature.subRow * subRowHeight}px`,
14807
+ height: `${subRowHeight}px`
14808
+ },
14809
+ children: /* @__PURE__ */ jsxRuntime.jsx(GanttFeatureItem, { ...feature, onMove, children: children ? children(feature) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "flex-1 truncate text-xs", children: feature.name }) })
14810
+ },
14811
+ feature.id
14812
+ ))
14813
+ }
14814
+ );
14815
+ };
14816
+ var GanttFeatureList = ({
14817
+ className,
14818
+ children
14819
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
14820
+ "div",
14821
+ {
14822
+ className: cn("absolute top-0 left-0 h-max w-max min-w-full", className),
14823
+ style: { marginTop: "var(--gantt-header-height)" },
14824
+ children
14825
+ }
14826
+ );
14827
+ var GanttMarker = React27.memo(({ label, date, id, onRemove, className }) => {
14828
+ const gantt = React27.useContext(GanttContext);
14829
+ const differenceIn = React27.useMemo(
14830
+ () => getDifferenceIn(gantt.range),
14831
+ [gantt.range]
14832
+ );
14833
+ const timelineStartDate = React27.useMemo(
14834
+ () => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
14835
+ [gantt.timelineData]
14836
+ );
14837
+ const offset = React27.useMemo(
14838
+ () => differenceIn(date, timelineStartDate),
14839
+ [differenceIn, date, timelineStartDate]
14840
+ );
14841
+ const innerOffset = React27.useMemo(
14842
+ () => calculateInnerOffset(
14843
+ date,
14844
+ gantt.range,
14845
+ gantt.columnWidth * gantt.zoom / 100
14846
+ ),
14847
+ [date, gantt.range, gantt.columnWidth, gantt.zoom]
14848
+ );
14849
+ const handleRemove = React27.useCallback(() => onRemove?.(id), [onRemove, id]);
14850
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14851
+ "div",
14852
+ {
14853
+ className: "pointer-events-none absolute top-0 left-0 z-20 flex h-full select-none flex-col items-center justify-center overflow-visible",
14854
+ style: {
14855
+ width: 0,
14856
+ transform: `translateX(calc(var(--gantt-column-width) * ${offset} + ${Math.round(innerOffset)}px))`
14857
+ },
14858
+ children: [
14859
+ /* @__PURE__ */ jsxRuntime.jsxs(ContextMenu, { children: [
14860
+ /* @__PURE__ */ jsxRuntime.jsx(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
14861
+ "div",
14862
+ {
14863
+ className: cn(
14864
+ "group pointer-events-auto sticky top-0 flex select-auto flex-col flex-nowrap items-center justify-center whitespace-nowrap rounded-sm bg-card px-2 py-1 text-foreground text-xs shadow-sm",
14865
+ className
14866
+ ),
14867
+ children: [
14868
+ label,
14869
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-h-[0] overflow-hidden opacity-80 transition-all group-hover:max-h-[2rem]", children: dateFns.formatDate(date, "MMM dd, yyyy") })
14870
+ ]
14871
+ }
14872
+ ) }),
14873
+ /* @__PURE__ */ jsxRuntime.jsx(ContextMenuContent, { children: onRemove ? /* @__PURE__ */ jsxRuntime.jsxs(
14874
+ ContextMenuItem,
14875
+ {
14876
+ className: "flex items-center gap-2 text-destructive",
14877
+ onClick: handleRemove,
14878
+ children: [
14879
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrashIcon, { size: 16 }),
14880
+ "Remove marker"
14881
+ ]
14882
+ }
14883
+ ) : null })
14884
+ ] }),
14885
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-full w-px bg-card", className) })
14886
+ ]
14887
+ }
14888
+ );
14889
+ });
14890
+ GanttMarker.displayName = "GanttMarker";
14891
+ var GanttProvider = ({
14892
+ zoom = 100,
14893
+ range = "monthly",
14894
+ onAddItem,
14895
+ children,
14896
+ className,
14897
+ defaultExpandedGroups = {}
14898
+ }) => {
14899
+ const scrollRef = React27.useRef(null);
14900
+ const [timelineData, setTimelineData] = React27.useState(
14901
+ createInitialTimelineData(/* @__PURE__ */ new Date())
14902
+ );
14903
+ const [, setScrollX] = useGanttScrollX();
14904
+ const sidebarWidth = 280;
14905
+ const [expandedGroups, setExpandedGroups] = React27.useState(defaultExpandedGroups);
14906
+ const setGroupExpanded = React27.useCallback((groupId, expanded) => {
14907
+ setExpandedGroups((prev) => ({ ...prev, [groupId]: expanded }));
14908
+ }, []);
14909
+ const headerHeight = 60;
14910
+ const rowHeight = 36;
14911
+ let columnWidth = 50;
14912
+ if (range === "monthly") {
14913
+ columnWidth = 150;
14914
+ } else if (range === "quarterly") {
14915
+ columnWidth = 100;
14916
+ }
14917
+ const cssVariables = React27.useMemo(
14918
+ () => ({
14919
+ "--gantt-zoom": `${zoom}`,
14920
+ "--gantt-column-width": `${zoom / 100 * columnWidth}px`,
14921
+ "--gantt-header-height": `${headerHeight}px`,
14922
+ "--gantt-row-height": `${rowHeight}px`,
14923
+ "--gantt-sidebar-width": `${sidebarWidth}px`
14924
+ }),
14925
+ [zoom, columnWidth, sidebarWidth]
14926
+ );
14927
+ React27.useEffect(() => {
14928
+ if (scrollRef.current) {
14929
+ scrollRef.current.scrollLeft = scrollRef.current.scrollWidth / 2 - scrollRef.current.clientWidth / 2;
14930
+ setScrollX(scrollRef.current.scrollLeft);
14931
+ }
14932
+ }, [setScrollX]);
14933
+ const handleScroll = React27.useCallback(
14934
+ throttle__default.default(() => {
14935
+ const scrollElement = scrollRef.current;
14936
+ if (!scrollElement) {
14937
+ return;
14938
+ }
14939
+ const { scrollLeft, scrollWidth, clientWidth } = scrollElement;
14940
+ setScrollX(scrollLeft);
14941
+ if (scrollLeft === 0) {
14942
+ const firstYear = timelineData[0]?.year;
14943
+ if (!firstYear) {
14944
+ return;
14945
+ }
14946
+ const newTimelineData = [...timelineData];
14947
+ newTimelineData.unshift({
14948
+ year: firstYear - 1,
14949
+ quarters: new Array(4).fill(null).map((_, quarterIndex) => ({
14950
+ months: new Array(3).fill(null).map((_2, monthIndex) => {
14951
+ const month = quarterIndex * 3 + monthIndex;
14952
+ return {
14953
+ days: dateFns.getDaysInMonth(new Date(firstYear, month, 1))
14954
+ };
14955
+ })
14956
+ }))
14957
+ });
14958
+ setTimelineData(newTimelineData);
14959
+ scrollElement.scrollLeft = scrollElement.clientWidth;
14960
+ setScrollX(scrollElement.scrollLeft);
14961
+ } else if (scrollLeft + clientWidth >= scrollWidth) {
14962
+ const lastYear = timelineData.at(-1)?.year;
14963
+ if (!lastYear) {
14964
+ return;
14965
+ }
14966
+ const newTimelineData = [...timelineData];
14967
+ newTimelineData.push({
14968
+ year: lastYear + 1,
14969
+ quarters: new Array(4).fill(null).map((_, quarterIndex) => ({
14970
+ months: new Array(3).fill(null).map((_2, monthIndex) => {
14971
+ const month = quarterIndex * 3 + monthIndex;
14972
+ return {
14973
+ days: dateFns.getDaysInMonth(new Date(lastYear, month, 1))
14974
+ };
14975
+ })
14976
+ }))
14977
+ });
14978
+ setTimelineData(newTimelineData);
14979
+ scrollElement.scrollLeft = scrollElement.scrollWidth - scrollElement.clientWidth;
14980
+ setScrollX(scrollElement.scrollLeft);
14981
+ }
14982
+ }, 100),
14983
+ []
14984
+ );
14985
+ React27.useEffect(() => {
14986
+ const scrollElement = scrollRef.current;
14987
+ if (scrollElement) {
14988
+ scrollElement.addEventListener("scroll", handleScroll);
14989
+ }
14990
+ return () => {
14991
+ if (scrollElement) {
14992
+ scrollElement.removeEventListener("scroll", handleScroll);
14993
+ }
14994
+ };
14995
+ }, [handleScroll]);
14996
+ const scrollToFeature = React27.useCallback(
14997
+ (feature) => {
14998
+ const scrollElement = scrollRef.current;
14999
+ if (!scrollElement) {
15000
+ return;
15001
+ }
15002
+ const timelineStartDate = new Date(timelineData[0].year, 0, 1);
15003
+ const offset = getOffset(feature.startAt, timelineStartDate, {
15004
+ zoom,
15005
+ range,
15006
+ columnWidth});
15007
+ const targetScrollLeft = Math.max(0, offset);
15008
+ scrollElement.scrollTo({
15009
+ left: targetScrollLeft,
15010
+ behavior: "smooth"
15011
+ });
15012
+ },
15013
+ [timelineData, zoom, range, columnWidth, sidebarWidth, onAddItem, expandedGroups, setGroupExpanded]
15014
+ );
15015
+ return /* @__PURE__ */ jsxRuntime.jsx(
15016
+ GanttContext.Provider,
15017
+ {
15018
+ value: {
15019
+ zoom,
15020
+ range,
15021
+ headerHeight,
15022
+ columnWidth,
15023
+ sidebarWidth,
15024
+ rowHeight,
15025
+ onAddItem,
15026
+ timelineData,
15027
+ placeholderLength: 2,
15028
+ ref: scrollRef,
15029
+ scrollToFeature,
15030
+ expandedGroups,
15031
+ setGroupExpanded
15032
+ },
15033
+ children: /* @__PURE__ */ jsxRuntime.jsx(
15034
+ "div",
15035
+ {
15036
+ className: cn(
15037
+ "gantt relative isolate grid h-full w-full flex-none select-none rounded-sm border bg-background",
15038
+ range,
15039
+ className
15040
+ ),
15041
+ style: {
15042
+ ...cssVariables,
15043
+ gridTemplateColumns: "var(--gantt-sidebar-width) 1fr"
15044
+ },
15045
+ children: /* @__PURE__ */ jsxRuntime.jsx(
15046
+ "div",
15047
+ {
15048
+ className: "col-span-2 grid overflow-auto",
15049
+ ref: scrollRef,
15050
+ style: {
15051
+ gridTemplateColumns: "var(--gantt-sidebar-width) 1fr"
15052
+ },
15053
+ children
15054
+ }
15055
+ )
15056
+ }
15057
+ )
15058
+ }
15059
+ );
15060
+ };
15061
+ var GanttTimeline = ({
15062
+ children,
15063
+ className
15064
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
15065
+ "div",
15066
+ {
15067
+ className: cn(
15068
+ "relative flex h-max min-h-full w-max flex-none",
15069
+ className
15070
+ ),
15071
+ children
15072
+ }
15073
+ );
15074
+ var GanttToday = ({ className }) => {
15075
+ const label = "Today";
15076
+ const date = React27.useMemo(() => /* @__PURE__ */ new Date(), []);
15077
+ const gantt = React27.useContext(GanttContext);
15078
+ const differenceIn = React27.useMemo(
15079
+ () => getDifferenceIn(gantt.range),
15080
+ [gantt.range]
15081
+ );
15082
+ const timelineStartDate = React27.useMemo(
15083
+ () => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
15084
+ [gantt.timelineData]
15085
+ );
15086
+ const offset = React27.useMemo(
15087
+ () => differenceIn(date, timelineStartDate),
15088
+ [differenceIn, date, timelineStartDate]
15089
+ );
15090
+ const innerOffset = React27.useMemo(
15091
+ () => Math.round(calculateInnerOffset(
15092
+ date,
15093
+ gantt.range,
15094
+ gantt.columnWidth * gantt.zoom / 100
15095
+ )),
15096
+ [date, gantt.range, gantt.columnWidth, gantt.zoom]
15097
+ );
15098
+ return /* @__PURE__ */ jsxRuntime.jsxs(
15099
+ "div",
15100
+ {
15101
+ className: "pointer-events-none absolute top-0 left-0 z-20 flex h-full select-none flex-col items-center justify-center overflow-visible",
15102
+ style: {
15103
+ width: 0,
15104
+ transform: `translateX(calc(var(--gantt-column-width) * ${offset} + ${innerOffset}px))`
15105
+ },
15106
+ children: [
15107
+ /* @__PURE__ */ jsxRuntime.jsxs(
15108
+ "div",
15109
+ {
15110
+ className: cn(
15111
+ "group pointer-events-auto sticky top-0 flex select-auto flex-col flex-nowrap items-center justify-center whitespace-nowrap rounded-sm bg-primary px-2 py-1 text-primary-foreground text-xs shadow-sm",
15112
+ className
15113
+ ),
15114
+ children: [
15115
+ label,
15116
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-h-[0] overflow-hidden opacity-80 transition-all group-hover:max-h-[2rem]", children: dateFns.formatDate(date, "MMM dd, yyyy") })
15117
+ ]
15118
+ }
15119
+ ),
15120
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-full w-px bg-primary", className) })
15121
+ ]
15122
+ }
15123
+ );
15124
+ };
15125
+ var t = tunnel__default.default();
15126
+ var KanbanContext = React27.createContext({
15127
+ columns: [],
15128
+ data: [],
15129
+ activeCardId: null
15130
+ });
15131
+ var KanbanBoard = ({ id, children, className }) => {
15132
+ const { isOver, setNodeRef } = core.useDroppable({
15133
+ id
15134
+ });
15135
+ return /* @__PURE__ */ jsxRuntime.jsx(
15136
+ "div",
15137
+ {
15138
+ className: cn(
15139
+ "flex size-full min-h-40 flex-col divide-y overflow-hidden rounded-md border bg-secondary text-xs shadow-sm ring-2 transition-all",
15140
+ isOver ? "ring-primary" : "ring-transparent",
15141
+ className
15142
+ ),
15143
+ ref: setNodeRef,
15144
+ children
15145
+ }
15146
+ );
15147
+ };
15148
+ var KanbanCard = ({
15149
+ id,
15150
+ name,
15151
+ children,
15152
+ className
15153
+ }) => {
15154
+ const {
15155
+ attributes,
15156
+ listeners,
15157
+ setNodeRef,
15158
+ transition,
15159
+ transform,
15160
+ isDragging
15161
+ } = sortable.useSortable({
15162
+ id
15163
+ });
15164
+ const { activeCardId } = React27.useContext(KanbanContext);
15165
+ const style = {
15166
+ transition,
15167
+ transform: utilities.CSS.Transform.toString(transform)
15168
+ };
15169
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15170
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style, ...listeners, ...attributes, ref: setNodeRef, className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
15171
+ Card,
15172
+ {
15173
+ className: cn(
15174
+ "cursor-grab gap-4 rounded-md p-2 shadow-sm overflow-hidden",
15175
+ isDragging && "pointer-events-none cursor-grabbing opacity-30",
15176
+ className
15177
+ ),
15178
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-0 font-medium text-sm", children: name })
15179
+ }
15180
+ ) }),
15181
+ activeCardId === id && /* @__PURE__ */ jsxRuntime.jsx(t.In, { children: /* @__PURE__ */ jsxRuntime.jsx(
15182
+ Card,
15183
+ {
15184
+ className: cn(
15185
+ "cursor-grab gap-4 rounded-md p-2 shadow-sm ring-2 ring-primary overflow-hidden",
15186
+ isDragging && "cursor-grabbing",
15187
+ className
15188
+ ),
15189
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "m-0 font-medium text-sm", children: name })
15190
+ }
15191
+ ) })
15192
+ ] });
15193
+ };
15194
+ var KanbanCards = ({
15195
+ children,
15196
+ className,
15197
+ ...props
15198
+ }) => {
15199
+ const { data } = React27.useContext(KanbanContext);
15200
+ const filteredData = data.filter((item) => item.column === props.id);
15201
+ const items = filteredData.map((item) => item.id);
15202
+ return /* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "overflow-hidden", children: [
15203
+ /* @__PURE__ */ jsxRuntime.jsx(sortable.SortableContext, { items, children: /* @__PURE__ */ jsxRuntime.jsx(
15204
+ "div",
15205
+ {
15206
+ className: cn("flex flex-grow flex-col gap-2 p-2", className),
15207
+ ...props,
15208
+ children: filteredData.map(children)
15209
+ }
15210
+ ) }),
15211
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollBar, { orientation: "vertical" })
15212
+ ] });
15213
+ };
15214
+ var KanbanHeader = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("m-0 p-2 font-semibold text-sm", className), ...props });
15215
+ var KanbanProvider = ({
15216
+ children,
15217
+ onDragStart,
15218
+ onDragEnd,
15219
+ onDragOver,
15220
+ className,
15221
+ columns,
15222
+ data,
15223
+ onDataChange,
15224
+ ...props
15225
+ }) => {
15226
+ const [activeCardId, setActiveCardId] = React27.useState(null);
15227
+ const sensors = core.useSensors(
15228
+ core.useSensor(core.MouseSensor),
15229
+ core.useSensor(core.TouchSensor),
15230
+ core.useSensor(core.KeyboardSensor)
15231
+ );
15232
+ const handleDragStart = (event) => {
15233
+ const card = data.find((item) => item.id === event.active.id);
15234
+ if (card) {
15235
+ setActiveCardId(event.active.id);
15236
+ }
15237
+ onDragStart?.(event);
15238
+ };
15239
+ const handleDragOver = (event) => {
15240
+ const { active, over } = event;
15241
+ if (!over) {
15242
+ return;
15243
+ }
15244
+ const activeItem = data.find((item) => item.id === active.id);
15245
+ const overItem = data.find((item) => item.id === over.id);
15246
+ if (!activeItem) {
15247
+ return;
15248
+ }
15249
+ const activeColumn = activeItem.column;
15250
+ const overColumn = overItem?.column || columns.find((col) => col.id === over.id)?.id || columns[0]?.id;
15251
+ if (activeColumn !== overColumn) {
15252
+ let newData = [...data];
15253
+ const activeIndex = newData.findIndex((item) => item.id === active.id);
15254
+ const overIndex = newData.findIndex((item) => item.id === over.id);
15255
+ newData[activeIndex].column = overColumn;
15256
+ newData = sortable.arrayMove(newData, activeIndex, overIndex);
15257
+ onDataChange?.(newData);
15258
+ }
15259
+ onDragOver?.(event);
15260
+ };
15261
+ const handleDragEnd = (event) => {
15262
+ setActiveCardId(null);
15263
+ onDragEnd?.(event);
15264
+ const { active, over } = event;
15265
+ if (!over || active.id === over.id) {
15266
+ return;
15267
+ }
15268
+ let newData = [...data];
15269
+ const oldIndex = newData.findIndex((item) => item.id === active.id);
15270
+ const newIndex = newData.findIndex((item) => item.id === over.id);
15271
+ newData = sortable.arrayMove(newData, oldIndex, newIndex);
15272
+ onDataChange?.(newData);
15273
+ };
15274
+ const announcements = {
15275
+ onDragStart({ active }) {
15276
+ const { name, column } = data.find((item) => item.id === active.id) ?? {};
15277
+ return `Picked up the card "${name}" from the "${column}" column`;
15278
+ },
15279
+ onDragOver({ active, over }) {
15280
+ const { name } = data.find((item) => item.id === active.id) ?? {};
15281
+ const newColumn = columns.find((column) => column.id === over?.id)?.name;
15282
+ return `Dragged the card "${name}" over the "${newColumn}" column`;
15283
+ },
15284
+ onDragEnd({ active, over }) {
15285
+ const { name } = data.find((item) => item.id === active.id) ?? {};
15286
+ const newColumn = columns.find((column) => column.id === over?.id)?.name;
15287
+ return `Dropped the card "${name}" into the "${newColumn}" column`;
15288
+ },
15289
+ onDragCancel({ active }) {
15290
+ const { name } = data.find((item) => item.id === active.id) ?? {};
15291
+ return `Cancelled dragging the card "${name}"`;
15292
+ }
15293
+ };
15294
+ return /* @__PURE__ */ jsxRuntime.jsx(KanbanContext.Provider, { value: { columns, data, activeCardId }, children: /* @__PURE__ */ jsxRuntime.jsxs(
15295
+ core.DndContext,
15296
+ {
15297
+ accessibility: { announcements },
15298
+ collisionDetection: core.closestCenter,
15299
+ onDragEnd: handleDragEnd,
15300
+ onDragOver: handleDragOver,
15301
+ onDragStart: handleDragStart,
15302
+ sensors,
15303
+ ...props,
15304
+ children: [
15305
+ /* @__PURE__ */ jsxRuntime.jsx(
15306
+ "div",
15307
+ {
15308
+ className: cn(
15309
+ "grid size-full auto-cols-fr grid-flow-col gap-4",
15310
+ className
15311
+ ),
15312
+ children: columns.map((column) => children(column))
15313
+ }
15314
+ ),
15315
+ typeof window !== "undefined" && reactDom.createPortal(
15316
+ /* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { children: /* @__PURE__ */ jsxRuntime.jsx(t.Out, {}) }),
15317
+ document.body
15318
+ )
15319
+ ]
15320
+ }
15321
+ ) });
15322
+ };
13630
15323
 
13631
15324
  Object.defineProperty(exports, "flexRender", {
13632
15325
  enumerable: true,
@@ -13858,6 +15551,30 @@ exports.FormField = FormField;
13858
15551
  exports.FormItem = FormItem;
13859
15552
  exports.FormLabel = FormLabel;
13860
15553
  exports.FormMessage = FormMessage;
15554
+ exports.GanttAddFeatureHelper = GanttAddFeatureHelper;
15555
+ exports.GanttCollapsibleSidebarGroup = GanttCollapsibleSidebarGroup;
15556
+ exports.GanttCollapsibleTimelineGroup = GanttCollapsibleTimelineGroup;
15557
+ exports.GanttColumn = GanttColumn;
15558
+ exports.GanttColumns = GanttColumns;
15559
+ exports.GanttContentHeader = GanttContentHeader;
15560
+ exports.GanttCreateMarkerTrigger = GanttCreateMarkerTrigger;
15561
+ exports.GanttFeatureDragHelper = GanttFeatureDragHelper;
15562
+ exports.GanttFeatureItem = GanttFeatureItem;
15563
+ exports.GanttFeatureItemCard = GanttFeatureItemCard;
15564
+ exports.GanttFeatureList = GanttFeatureList;
15565
+ exports.GanttFeatureListGroup = GanttFeatureListGroup;
15566
+ exports.GanttFeatureRow = GanttFeatureRow;
15567
+ exports.GanttGridLines = GanttGridLines;
15568
+ exports.GanttGroupSummaryBar = GanttGroupSummaryBar;
15569
+ exports.GanttHeader = GanttHeader;
15570
+ exports.GanttMarker = GanttMarker;
15571
+ exports.GanttProvider = GanttProvider;
15572
+ exports.GanttSidebar = GanttSidebar;
15573
+ exports.GanttSidebarGroup = GanttSidebarGroup;
15574
+ exports.GanttSidebarHeader = GanttSidebarHeader;
15575
+ exports.GanttSidebarItem = GanttSidebarItem;
15576
+ exports.GanttTimeline = GanttTimeline;
15577
+ exports.GanttToday = GanttToday;
13861
15578
  exports.HoverCard = HoverCard;
13862
15579
  exports.HoverCardContent = HoverCardContent;
13863
15580
  exports.HoverCardTrigger = HoverCardTrigger;
@@ -13878,6 +15595,11 @@ exports.ItemHeader = ItemHeader;
13878
15595
  exports.ItemMedia = ItemMedia;
13879
15596
  exports.ItemSeparator = ItemSeparator;
13880
15597
  exports.ItemTitle = ItemTitle;
15598
+ exports.KanbanBoard = KanbanBoard;
15599
+ exports.KanbanCard = KanbanCard;
15600
+ exports.KanbanCards = KanbanCards;
15601
+ exports.KanbanHeader = KanbanHeader;
15602
+ exports.KanbanProvider = KanbanProvider;
13881
15603
  exports.Kbd = Kbd;
13882
15604
  exports.KbdGroup = KbdGroup;
13883
15605
  exports.Label = Label2;
@@ -14125,6 +15847,8 @@ exports.useEventCalendar = useEventCalendar;
14125
15847
  exports.useEventsInRange = useEventsInRange;
14126
15848
  exports.useFilteredEvents = useFilteredEvents;
14127
15849
  exports.useFormField = useFormField;
15850
+ exports.useGanttDragging = useGanttDragging;
15851
+ exports.useGanttScrollX = useGanttScrollX;
14128
15852
  exports.useIsMobile = useIsMobile;
14129
15853
  exports.useSearchShortcut = useSearchShortcut;
14130
15854
  exports.useSidebar = useSidebar;