@j3m-quantum/ui 1.10.0 → 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
  }
@@ -9985,7 +9996,7 @@ function CommentsSection({
9985
9996
  }) {
9986
9997
  const [viewCommentsOpen, setViewCommentsOpen] = React27__namespace.useState(true);
9987
9998
  const [addDialogOpen, setAddDialogOpen] = React27__namespace.useState(false);
9988
- const formatDate2 = (date) => {
9999
+ const formatDate3 = (date) => {
9989
10000
  return new Intl.DateTimeFormat("en-US", {
9990
10001
  month: "short",
9991
10002
  day: "numeric",
@@ -10029,7 +10040,7 @@ function CommentsSection({
10029
10040
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: comment.author }),
10030
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 })
10031
10042
  ] }),
10032
- /* @__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) })
10033
10044
  ] }),
10034
10045
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: comment.text })
10035
10046
  ] }, comment.id)) })
@@ -11021,11 +11032,11 @@ function getVisibleHours(visibleHours, singleDayEvents) {
11021
11032
  function getCalendarCells(selectedDate) {
11022
11033
  const currentYear = selectedDate.getFullYear();
11023
11034
  const currentMonth = selectedDate.getMonth();
11024
- const getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
11035
+ const getDaysInMonth2 = (year, month) => new Date(year, month + 1, 0).getDate();
11025
11036
  const getFirstDayOfMonth = (year, month) => new Date(year, month, 1).getDay();
11026
- const daysInMonth = getDaysInMonth(currentYear, currentMonth);
11037
+ const daysInMonth = getDaysInMonth2(currentYear, currentMonth);
11027
11038
  const firstDayOfMonth = getFirstDayOfMonth(currentYear, currentMonth);
11028
- const daysInPrevMonth = getDaysInMonth(currentYear, currentMonth - 1);
11039
+ const daysInPrevMonth = getDaysInMonth2(currentYear, currentMonth - 1);
11029
11040
  const totalDays = firstDayOfMonth + daysInMonth;
11030
11041
  const prevMonthCells = Array.from({ length: firstDayOfMonth }, (_, i) => ({
11031
11042
  day: daysInPrevMonth - firstDayOfMonth + i + 1,
@@ -13746,6 +13757,1569 @@ function CalendarView({
13746
13757
  return null;
13747
13758
  }
13748
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
+ };
13749
15323
 
13750
15324
  Object.defineProperty(exports, "flexRender", {
13751
15325
  enumerable: true,
@@ -13977,6 +15551,30 @@ exports.FormField = FormField;
13977
15551
  exports.FormItem = FormItem;
13978
15552
  exports.FormLabel = FormLabel;
13979
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;
13980
15578
  exports.HoverCard = HoverCard;
13981
15579
  exports.HoverCardContent = HoverCardContent;
13982
15580
  exports.HoverCardTrigger = HoverCardTrigger;
@@ -13997,6 +15595,11 @@ exports.ItemHeader = ItemHeader;
13997
15595
  exports.ItemMedia = ItemMedia;
13998
15596
  exports.ItemSeparator = ItemSeparator;
13999
15597
  exports.ItemTitle = ItemTitle;
15598
+ exports.KanbanBoard = KanbanBoard;
15599
+ exports.KanbanCard = KanbanCard;
15600
+ exports.KanbanCards = KanbanCards;
15601
+ exports.KanbanHeader = KanbanHeader;
15602
+ exports.KanbanProvider = KanbanProvider;
14000
15603
  exports.Kbd = Kbd;
14001
15604
  exports.KbdGroup = KbdGroup;
14002
15605
  exports.Label = Label2;
@@ -14244,6 +15847,8 @@ exports.useEventCalendar = useEventCalendar;
14244
15847
  exports.useEventsInRange = useEventsInRange;
14245
15848
  exports.useFilteredEvents = useFilteredEvents;
14246
15849
  exports.useFormField = useFormField;
15850
+ exports.useGanttDragging = useGanttDragging;
15851
+ exports.useGanttScrollX = useGanttScrollX;
14247
15852
  exports.useIsMobile = useIsMobile;
14248
15853
  exports.useSearchShortcut = useSearchShortcut;
14249
15854
  exports.useSidebar = useSidebar;