@object-ui/plugin-gantt 6.2.3 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,15 +1,198 @@
1
1
  import * as e from "react";
2
- import { useCallback as t, useEffect as n, useMemo as r, useState as i } from "react";
3
- import { ComponentRegistry as a, buildExpandFields as o, extractRecords as s } from "@object-ui/core";
4
- import { useNavigationOverlay as c, useObjectTranslation as l, useSchemaContext as u } from "@object-ui/react";
5
- import { GanttConfigSchema as d } from "@objectstack/spec/ui";
6
- import { RecordDetailDrawer as f, deriveRecordPageHref as p } from "@object-ui/plugin-detail";
7
- import { AlertDialog as m, AlertDialogAction as h, AlertDialogCancel as g, AlertDialogContent as _, AlertDialogDescription as v, AlertDialogFooter as y, AlertDialogHeader as b, AlertDialogTitle as x, Button as S, cn as C, useResizeObserver as w } from "@object-ui/components";
8
- import { getSemanticColorName as T, getSemanticHex as E } from "@object-ui/fields";
9
- import { CalendarDays as ee, ChevronLeft as D, ChevronRight as O, PanelLeft as te, PanelLeftClose as k, ZoomIn as ne, ZoomOut as A } from "lucide-react";
10
- import { Fragment as j, jsx as M, jsxs as N } from "react/jsx-runtime";
2
+ import { useCallback as t, useEffect as n, useMemo as r, useRef as i, useState as a } from "react";
3
+ import { ComponentRegistry as o, buildExpandFields as s, extractRecords as c } from "@object-ui/core";
4
+ import { useNavigationOverlay as l, useObjectTranslation as u, useSchemaContext as d } from "@object-ui/react";
5
+ import { GanttConfigSchema as f } from "@objectstack/spec/ui";
6
+ import { resolveFieldCurrency as p, useLocalization as m } from "@object-ui/i18n";
7
+ import { RecordDetailDrawer as h, deriveRecordPageHref as g } from "@object-ui/plugin-detail";
8
+ import { AlertDialog as _, AlertDialogAction as v, AlertDialogCancel as ee, AlertDialogContent as te, AlertDialogDescription as ne, AlertDialogFooter as re, AlertDialogHeader as ie, AlertDialogTitle as ae, Button as y, cn as b, useResizeObserver as oe } from "@object-ui/components";
9
+ import { formatCurrency as se, formatDate as ce, formatDateTime as x, formatNumber as le, formatPercent as S, getSemanticColorName as ue, getSemanticHex as de, humanizeLabel as fe } from "@object-ui/fields";
10
+ import { Activity as pe, ChevronDown as me, ChevronLeft as he, ChevronRight as C, Crosshair as ge, Download as _e, FileDown as ve, Lock as w, Maximize2 as T, Minimize2 as ye, PanelLeft as E, PanelLeftClose as be, Redo2 as xe, Save as Se, Undo2 as Ce, Wand2 as we, ZoomIn as Te, ZoomOut as Ee } from "lucide-react";
11
+ import { Fragment as De, jsx as D, jsxs as O } from "react/jsx-runtime";
12
+ //#region src/scheduling.ts
13
+ var Oe = 1e3 * 60 * 60 * 24, k = (e) => e.toISOString().slice(0, 10);
14
+ function A(e, t) {
15
+ if (t.skipWeekends) {
16
+ let t = e.getUTCDay();
17
+ if (t === 0 || t === 6) return !1;
18
+ }
19
+ return !(t.holidays && t.holidays.has(k(e)));
20
+ }
21
+ function j(e) {
22
+ let t = new Date(e);
23
+ return t.setUTCHours(0, 0, 0, 0), t;
24
+ }
25
+ function M(e, t) {
26
+ let n = j(e);
27
+ for (; !A(n, t);) n = new Date(n.getTime() + Oe);
28
+ return n.getTime();
29
+ }
30
+ function ke(e, t, n) {
31
+ if (t <= e) return 0;
32
+ let r = 0, i = j(e), a = j(t).getTime();
33
+ for (; i.getTime() < a;) A(i, n) && r++, i = new Date(i.getTime() + Oe);
34
+ return r;
35
+ }
36
+ function N(e, t, n) {
37
+ if (t <= 0) return j(e).getTime();
38
+ let r = j(e), i = t;
39
+ for (; i > 0;) A(r, n) && i--, r = new Date(r.getTime() + Oe);
40
+ return r.getTime();
41
+ }
42
+ function Ae(e, t, n) {
43
+ if (t <= 0) return j(e).getTime();
44
+ let r = j(e), i = t;
45
+ for (; i > 0;) r = /* @__PURE__ */ new Date(r.getTime() - Oe), A(r, n) && i--;
46
+ return r.getTime();
47
+ }
48
+ var P = (e) => String(e);
49
+ function je(e) {
50
+ return e === "ss" || e === "ff" || e === "sf" ? e : "fs";
51
+ }
52
+ function Me(e) {
53
+ let t = new Set(e.map((e) => P(e.id))), n = [];
54
+ for (let r of e) {
55
+ let e = P(r.id);
56
+ for (let i of r.dependencies ?? []) {
57
+ let r = typeof i == "object" && !!i, a = r ? i.id : i;
58
+ if (a == null || a === "") continue;
59
+ let o = P(a);
60
+ o === e || !t.has(o) || n.push({
61
+ pred: o,
62
+ succ: e,
63
+ type: je(r ? i.type : void 0)
64
+ });
65
+ }
66
+ }
67
+ return n;
68
+ }
69
+ function Ne(e) {
70
+ let t = /* @__PURE__ */ new Set();
71
+ for (let n of e) n.parent != null && n.parent !== "" && t.add(P(n.parent));
72
+ return t;
73
+ }
74
+ function F(e, t) {
75
+ let n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
76
+ for (let t of e) n.set(t, 0), r.set(t, []);
77
+ for (let e of t) r.get(e.pred).push(e.succ), n.set(e.succ, (n.get(e.succ) ?? 0) + 1);
78
+ let i = e.filter((e) => (n.get(e) ?? 0) === 0), a = [];
79
+ for (; i.length;) {
80
+ let e = i.shift();
81
+ a.push(e);
82
+ for (let t of r.get(e) ?? []) {
83
+ let e = (n.get(t) ?? 0) - 1;
84
+ n.set(t, e), e === 0 && i.push(t);
85
+ }
86
+ }
87
+ if (a.length < e.length) {
88
+ let t = new Set(a);
89
+ for (let n of e) t.has(n) || a.push(n);
90
+ return {
91
+ order: a,
92
+ hasCycle: !0
93
+ };
94
+ }
95
+ return {
96
+ order: a,
97
+ hasCycle: !1
98
+ };
99
+ }
100
+ function Pe(e, t) {
101
+ let n = {
102
+ criticalIds: /* @__PURE__ */ new Set(),
103
+ criticalEdges: /* @__PURE__ */ new Set()
104
+ };
105
+ if (!e.length) return n;
106
+ let r = /* @__PURE__ */ new Map();
107
+ for (let n of e) {
108
+ let e = t ? ke(n.start.getTime(), n.end.getTime(), t) : (n.end.getTime() - n.start.getTime()) / Oe;
109
+ r.set(P(n.id), Number.isFinite(e) && e > 0 ? e : 0);
110
+ }
111
+ let i = Me(e), a = e.map((e) => P(e.id)), { order: o, hasCycle: s } = F(a, i);
112
+ if (s) return n;
113
+ let c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map();
114
+ for (let e of a) c.set(e, []), l.set(e, []);
115
+ for (let e of i) c.get(e.succ).push(e), l.get(e.pred).push(e);
116
+ let u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map();
117
+ for (let e of o) {
118
+ let t = 0;
119
+ for (let n of c.get(e) ?? []) t = Math.max(t, d.get(n.pred) ?? 0);
120
+ u.set(e, t), d.set(e, t + (r.get(e) ?? 0));
121
+ }
122
+ let f = Math.max(0, ...a.map((e) => d.get(e) ?? 0)), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map();
123
+ for (let e = o.length - 1; e >= 0; e--) {
124
+ let t = o[e], n = l.get(t) ?? [], i = f;
125
+ n.length && (i = Math.min(...n.map((e) => m.get(e.succ) ?? f))), p.set(t, i), m.set(t, i - (r.get(t) ?? 0));
126
+ }
127
+ let h = 1e-6, g = /* @__PURE__ */ new Set();
128
+ for (let e of a) {
129
+ let t = (m.get(e) ?? 0) - (u.get(e) ?? 0);
130
+ Math.abs(t) <= h && g.add(e);
131
+ }
132
+ let _ = /* @__PURE__ */ new Set();
133
+ for (let e of i) _.add(e.pred), _.add(e.succ);
134
+ for (let e of [...g]) !_.has(e) && (r.get(e) ?? 0) === 0 && g.delete(e);
135
+ let v = /* @__PURE__ */ new Set();
136
+ for (let e of i) !g.has(e.pred) || !g.has(e.succ) || Math.abs((d.get(e.pred) ?? 0) - (u.get(e.succ) ?? 0)) <= h && v.add(`${e.pred}->${e.succ}`);
137
+ return {
138
+ criticalIds: g,
139
+ criticalEdges: v
140
+ };
141
+ }
142
+ function Fe(e, t) {
143
+ if (!e.length) return [];
144
+ let n = Me(e), r = e.map((e) => P(e.id)), { order: i, hasCycle: a } = F(r, n);
145
+ if (a) return [];
146
+ let o = Ne(e), s = /* @__PURE__ */ new Map();
147
+ for (let t of e) s.set(P(t.id), t);
148
+ let c = /* @__PURE__ */ new Map();
149
+ for (let e of r) c.set(e, []);
150
+ for (let e of n) c.get(e.succ).push(e);
151
+ let l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
152
+ for (let t of e) l.set(P(t.id), t.start.getTime()), u.set(P(t.id), t.end.getTime());
153
+ for (let e of i) {
154
+ let n = s.get(e);
155
+ if (!n) continue;
156
+ let r = t ? ke(l.get(e), u.get(e), t) : u.get(e) - l.get(e), i = n.start.getTime();
157
+ for (let n of c.get(e) ?? []) {
158
+ let e = l.get(n.pred), a = u.get(n.pred), o;
159
+ switch (n.type) {
160
+ case "ss":
161
+ o = e;
162
+ break;
163
+ case "ff":
164
+ o = t ? Ae(a, r, t) : a - r;
165
+ break;
166
+ case "sf":
167
+ o = t ? Ae(e, r, t) : e - r;
168
+ break;
169
+ default:
170
+ o = a;
171
+ break;
172
+ }
173
+ o > i && (i = o);
174
+ }
175
+ if (!o.has(e)) if (t) {
176
+ let n = M(i, t);
177
+ l.set(e, n), u.set(e, N(n, r, t));
178
+ } else l.set(e, i), u.set(e, i + r);
179
+ }
180
+ let d = [];
181
+ for (let t of e) {
182
+ let e = P(t.id);
183
+ if (o.has(e)) continue;
184
+ let n = l.get(e), r = u.get(e);
185
+ (n !== t.start.getTime() || r !== t.end.getTime()) && d.push({
186
+ id: e,
187
+ start: new Date(n),
188
+ end: new Date(r)
189
+ });
190
+ }
191
+ return d;
192
+ }
193
+ //#endregion
11
194
  //#region src/useGanttTranslation.ts
12
- var P = {
195
+ var Ie = {
13
196
  "gantt.column.taskName": "Task Name",
14
197
  "gantt.column.start": "Start",
15
198
  "gantt.column.end": "End",
@@ -19,79 +202,399 @@ var P = {
19
202
  "gantt.toolbar.zoomOut": "Zoom out",
20
203
  "gantt.toolbar.jumpToToday": "Jump to today",
21
204
  "gantt.toolbar.today": "Today",
205
+ "gantt.toolbar.thisWeek": "This week",
206
+ "gantt.toolbar.thisMonth": "This month",
207
+ "gantt.toolbar.exportPdf": "Export PDF",
208
+ "gantt.toolbar.saveLayout": "Save layout",
22
209
  "gantt.toolbar.showTaskList": "Show task list",
23
- "gantt.toolbar.hideTaskList": "Hide task list"
24
- }, F = "gantt.column.taskName";
210
+ "gantt.toolbar.hideTaskList": "Hide task list",
211
+ "gantt.toolbar.viewMode": "Timeline granularity",
212
+ "gantt.toolbar.enterFullscreen": "Enter fullscreen",
213
+ "gantt.toolbar.exitFullscreen": "Exit fullscreen",
214
+ "gantt.toolbar.criticalPath": "Highlight critical path",
215
+ "gantt.toolbar.autoSchedule": "Auto-schedule dependencies",
216
+ "gantt.toolbar.exportPng": "Export as PNG",
217
+ "gantt.toolbar.undo": "Undo",
218
+ "gantt.toolbar.redo": "Redo",
219
+ "gantt.viewMode.day": "Day",
220
+ "gantt.viewMode.week": "Week",
221
+ "gantt.viewMode.month": "Month",
222
+ "gantt.viewMode.quarter": "Quarter",
223
+ "gantt.viewMode.year": "Year",
224
+ "gantt.row.expand": "Expand",
225
+ "gantt.row.collapse": "Collapse",
226
+ "gantt.row.locate": "Locate on timeline",
227
+ "gantt.aria.taskList": "Task list",
228
+ "gantt.tooltip.days": "d",
229
+ "gantt.menu.view": "View details",
230
+ "gantt.menu.edit": "Edit inline",
231
+ "gantt.menu.delete": "Delete",
232
+ "gantt.menu.addPredecessor": "Add predecessor…",
233
+ "gantt.menu.addSuccessor": "Add successor…",
234
+ "gantt.menu.removeDependency": "Remove dependency",
235
+ "gantt.menu.noCandidates": "No available tasks",
236
+ "gantt.linkType.fs": "Finish → Start",
237
+ "gantt.linkType.ss": "Start → Start",
238
+ "gantt.linkType.ff": "Finish → Finish",
239
+ "gantt.linkType.sf": "Start → Finish",
240
+ "gantt.linkEnd.start": "start",
241
+ "gantt.linkEnd.end": "end",
242
+ "gantt.conflict.title": "Schedule conflict",
243
+ "gantt.conflict.body": "This move conflicts with dependency constraints. Auto-reschedule {count} affected task(s)?",
244
+ "gantt.conflict.confirm": "Auto-reschedule",
245
+ "gantt.conflict.cancel": "Keep as is",
246
+ "gantt.resource.header": "Resource",
247
+ "gantt.resource.peak": "Peak",
248
+ "gantt.resource.over": "overloaded",
249
+ "gantt.resource.empty": "No tasks to allocate.",
250
+ "gantt.readOnly": "Read-only",
251
+ "gantt.readOnlyHint": "Editing is disabled for this view."
252
+ };
25
253
  function I(e, t) {
26
- let n = P[e] || e;
254
+ let n = Ie[e] || e;
27
255
  if (t) for (let [e, r] of Object.entries(t)) n = n.replace(`{{${e}}}`, String(r));
28
256
  return n;
29
257
  }
30
- function re() {
258
+ function Le() {
31
259
  try {
32
- let e = l();
33
- return e.t(F) === F ? { t: I } : { t: e.t };
260
+ let e = u();
261
+ return {
262
+ t: (t, n) => {
263
+ let r = e.t(t, n);
264
+ return typeof r == "string" && r !== t ? r : I(t, n);
265
+ },
266
+ language: e.language
267
+ };
34
268
  } catch {
35
- return { t: I };
269
+ return {
270
+ t: I,
271
+ language: void 0
272
+ };
36
273
  }
37
274
  }
38
275
  //#endregion
39
276
  //#region src/GanttView.tsx
40
- function L(e) {
41
- return e < 640 ? 35 : e < 1024 ? 50 : 60;
277
+ function Re(e) {
278
+ return 110;
42
279
  }
43
- function ie(e) {
280
+ function ze(e) {
44
281
  return e < 640 ? 140 : e < 1024 ? 220 : 320;
45
282
  }
46
- function R(e) {
283
+ function Be(e) {
47
284
  return e >= 280;
48
285
  }
49
- function ae(e) {
286
+ function Ve(e) {
50
287
  return e < 640 ? 32 : 40;
51
288
  }
52
- function z({ tasks: t, startDate: n, endDate: r, onTaskClick: i, onTaskUpdate: a, className: o, inlineEdit: s = !1 }) {
53
- let { t: c } = re(), [l, u] = e.useState(/* @__PURE__ */ new Date()), d = e.useRef(null), { width: f } = w(d), p = f || (typeof window < "u" ? window.innerWidth : 1024), m = p < 640, h = ae(p), g = L(p), [_, v] = e.useState(null), y = _ ?? g, [b, x] = e.useState(!1), T = e.useRef(!1);
289
+ var He = [
290
+ "day",
291
+ "week",
292
+ "month",
293
+ "quarter",
294
+ "year"
295
+ ], Ue = {
296
+ day: 1,
297
+ week: 7,
298
+ month: 30.44,
299
+ quarter: 91.31,
300
+ year: 365.25
301
+ }, We = 1e3 * 60 * 60 * 24;
302
+ function Ge(e, t) {
303
+ let n = new Date(e);
304
+ return n.setHours(0, 0, 0, 0), t === "week" ? n.setDate(n.getDate() - (n.getDay() + 6) % 7) : t === "month" ? n.setDate(1) : t === "quarter" ? n.setMonth(Math.floor(n.getMonth() / 3) * 3, 1) : t === "year" && n.setMonth(0, 1), n;
305
+ }
306
+ function Ke(e, t, n) {
307
+ let r = e.length - 1, i = 0;
308
+ for (; i < r && e[i + 1] < t;) i++;
309
+ let a = i;
310
+ for (; a < r && e[a] < n;) a++;
311
+ return {
312
+ start: i,
313
+ end: a
314
+ };
315
+ }
316
+ function qe(e, t, n) {
317
+ let r = new Date(e);
318
+ if (n === "day") r.setDate(r.getDate() + t);
319
+ else if (n === "week") r.setDate(r.getDate() + t * 7);
320
+ else {
321
+ let e = t * (n === "month" ? 1 : n === "quarter" ? 3 : 12), i = r.getDate();
322
+ r.setDate(1), r.setMonth(r.getMonth() + e);
323
+ let a = new Date(r.getFullYear(), r.getMonth() + 1, 0).getDate();
324
+ r.setDate(Math.min(i, a));
325
+ }
326
+ return r;
327
+ }
328
+ function Je(e, t, n, r = 2) {
329
+ return new Promise((i) => {
330
+ let a = new Blob([e], { type: "image/svg+xml;charset=utf-8" }), o = URL.createObjectURL(a), s = new Image();
331
+ s.onload = () => {
332
+ let e = document.createElement("canvas");
333
+ e.width = t * r, e.height = n * r;
334
+ let a = e.getContext("2d");
335
+ a && (a.fillStyle = "#ffffff", a.fillRect(0, 0, e.width, e.height), a.scale(r, r), a.drawImage(s, 0, 0)), URL.revokeObjectURL(o), i(e);
336
+ }, s.onerror = () => {
337
+ URL.revokeObjectURL(o), i(null);
338
+ }, s.src = o;
339
+ });
340
+ }
341
+ function Ye(e, t) {
342
+ let n = document.createElement("a");
343
+ n.href = URL.createObjectURL(e), n.download = t, document.body.appendChild(n), n.click(), n.remove(), setTimeout(() => URL.revokeObjectURL(n.href), 1e3);
344
+ }
345
+ function Xe(e, t, n) {
346
+ let r = (e) => {
347
+ let t = new Uint8Array(e.length);
348
+ for (let n = 0; n < e.length; n++) t[n] = e.charCodeAt(n) & 255;
349
+ return t;
350
+ }, i = `q ${t} 0 0 ${n} 0 0 cm /Im0 Do Q`, a = [], o = [], s = 0, c = (e) => {
351
+ a.push(e), s += e.length;
352
+ }, l = () => {
353
+ o.push(s);
354
+ };
355
+ c(r("%PDF-1.3\n%ÿÿÿÿ\n")), l(), c(r("1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n")), l(), c(r("2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n")), l(), c(r(`3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${t} ${n}] /Resources << /XObject << /Im0 4 0 R >> >> /Contents 5 0 R >>\nendobj\n`)), l(), c(r(`4 0 obj\n<< /Type /XObject /Subtype /Image /Width ${t} /Height ${n} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${e.length} >>\nstream\n`)), c(e), c(r("\nendstream\nendobj\n")), l(), c(r(`5 0 obj\n<< /Length ${i.length} >>\nstream\n${i}\nendstream\nendobj\n`));
356
+ let u = s, d = "xref\n0 6\n0000000000 65535 f \n";
357
+ for (let e of o) d += `${String(e).padStart(10, "0")} 00000 n \n`;
358
+ return d += `trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${u}\n%%EOF\n`, c(r(d)), new Blob(a, { type: "application/pdf" });
359
+ }
360
+ function Ze(e) {
361
+ let t = e.slice(e.indexOf(",") + 1), n = atob(t), r = new Uint8Array(n.length);
362
+ for (let e = 0; e < n.length; e++) r[e] = n.charCodeAt(e);
363
+ return r;
364
+ }
365
+ var Qe = "gantt-layout:";
366
+ function $e(e) {
367
+ if (!e || typeof window > "u") return null;
368
+ try {
369
+ let t = window.localStorage.getItem(Qe + e);
370
+ if (!t) return null;
371
+ let n = JSON.parse(t), r = n.viewMode && He.includes(n.viewMode) ? n.viewMode : null;
372
+ if (!r) return null;
373
+ let i = typeof n.columnWidth == "number" && isFinite(n.columnWidth) ? n.columnWidth : null, a = typeof n.taskListWidth == "number" && isFinite(n.taskListWidth) ? n.taskListWidth : null;
374
+ return {
375
+ viewMode: r,
376
+ columnWidth: i,
377
+ taskListCollapsed: !!n.taskListCollapsed,
378
+ taskListWidth: a
379
+ };
380
+ } catch {
381
+ return null;
382
+ }
383
+ }
384
+ function et(e, t) {
385
+ if (!(typeof window > "u")) try {
386
+ window.localStorage.setItem(Qe + e, JSON.stringify(t));
387
+ } catch {}
388
+ }
389
+ function tt({ tasks: t, viewMode: n, startDate: r, endDate: i, markers: a, onTaskClick: o, onTaskUpdate: s, onTaskDelete: c, onViewChange: l, onDependencyCreate: u, onDependencyDelete: d, onTaskReorder: f, className: p, inlineEdit: m = !1, autoSchedule: h = !1, rescheduleOnConflict: g = !1, criticalPathDefault: _ = !1, workingCalendar: v, showBaselines: ee = !0, readOnly: te = !1, mobileReadOnly: ne = !1, groupBy: re, ungroupedLabel: ie = "Ungrouped", defaultCollapsedDepth: ae, persistLayoutKey: se, onLayoutChange: ce }) {
390
+ let { t: x, language: le } = Le(), S = le || void 0, [ue, de] = e.useState(/* @__PURE__ */ new Date()), fe = e.useRef(null), { width: Oe } = oe(fe), k = Oe || (typeof window < "u" ? window.innerWidth : 1024), A = k < 640, j = te || ne && A, M = j ? void 0 : s, ke = j ? void 0 : c, N = j ? void 0 : u, Ae = j ? void 0 : d, P = j ? void 0 : f, je = j ? !1 : m, Me = j ? !1 : h, Ne = j ? !1 : g, F = Ve(k), Ie = Re(k), I = e.useRef(void 0);
391
+ I.current === void 0 && (I.current = $e(se));
392
+ let Qe = I.current, [tt, nt] = e.useState(Qe ? Qe.columnWidth : null), [rt, it] = e.useState(Qe ? Qe.taskListWidth ?? null : null), [L, at] = e.useState(n && He.includes(n) ? n : Qe?.viewMode ?? "day");
393
+ e.useEffect(() => {
394
+ n && He.includes(n) && at(n);
395
+ }, [n]);
396
+ let ot = e.useRef(null), st = e.useRef(null), ct = e.useRef(!0), [lt, ut] = e.useState(Qe ? Qe.taskListCollapsed : !1), dt = e.useRef(!1);
54
397
  e.useEffect(() => {
55
- !T.current && m && (x(!0), T.current = !0);
56
- }, [m]);
57
- let E = b ? 0 : ie(p), P = R(E), [F, I] = e.useState(null), [z, B] = e.useState({}), [V, H] = e.useState(null), U = e.useRef(null);
398
+ !dt.current && A && (ut(!0), dt.current = !0);
399
+ }, [A]);
400
+ let ft = Math.max(160, k - 200), R = lt ? 0 : rt == null ? ze(k) : Math.max(160, Math.min(rt, ft)), pt = e.useMemo(() => {
401
+ if (tt != null || i || t.length === 0) return null;
402
+ let e = r ? new Date(r) : new Date(Math.min(...t.map((e) => e.start.getTime()))), n = new Date(Math.max(...t.map((e) => e.end.getTime())));
403
+ r || e.setDate(e.getDate() - 7), n.setDate(n.getDate() + 14), e = Ge(e, L), n.setHours(23, 59, 59, 999);
404
+ let a = Math.max(1, (n.getTime() - e.getTime()) / We), o = Math.max(0, k - R);
405
+ if (o <= 0) return null;
406
+ let s = o / a * Ue[L];
407
+ if (s <= Ie) return null;
408
+ let c = Math.min(s, o * .6);
409
+ return c > Ie ? c : null;
410
+ }, [
411
+ tt,
412
+ t,
413
+ r,
414
+ i,
415
+ L,
416
+ k,
417
+ R,
418
+ Ie
419
+ ]), z = tt ?? pt ?? Ie, mt = z / Ue[L], ht = Be(R), [gt, _t] = e.useState(null), [vt, yt] = e.useState({}), [bt, xt] = e.useState(null), B = e.useMemo(() => {
420
+ if (!re) return t;
421
+ let e = /* @__PURE__ */ new Set();
422
+ for (let n of t) {
423
+ let t = n.parent != null && n.parent !== "" ? String(n.parent) : null;
424
+ t && e.add(t);
425
+ }
426
+ let n = /* @__PURE__ */ new Map();
427
+ for (let r of t) {
428
+ if (e.has(String(r.id))) continue;
429
+ let t = re(r), i = t ? String(t.key) : "__ungrouped__", a = t ? t.label : ie, o = n.get(i);
430
+ o || (o = {
431
+ key: i,
432
+ label: a,
433
+ items: []
434
+ }, n.set(i, o)), o.items.push(r);
435
+ }
436
+ let r = [];
437
+ for (let e of n.values()) {
438
+ let t = `__group__${e.key}`, n = e.items[0];
439
+ r.push({
440
+ id: t,
441
+ title: e.label,
442
+ start: n.start,
443
+ end: n.end,
444
+ progress: 0,
445
+ type: "summary",
446
+ parent: null,
447
+ data: { __group: !0 }
448
+ });
449
+ for (let n of e.items) r.push({
450
+ ...n,
451
+ parent: t
452
+ });
453
+ }
454
+ return r;
455
+ }, [
456
+ re,
457
+ t,
458
+ ie
459
+ ]), St = e.useMemo(() => {
460
+ let e = new Set(B.map((e) => String(e.id))), t = /* @__PURE__ */ new Map();
461
+ for (let n of B) {
462
+ let r = n.parent != null && n.parent !== "" ? String(n.parent) : null;
463
+ if (r && r !== String(n.id) && e.has(r)) {
464
+ let e = t.get(r);
465
+ e ? e.push(n) : t.set(r, [n]);
466
+ }
467
+ }
468
+ return t;
469
+ }, [B]), Ct = e.useMemo(() => {
470
+ let e = /* @__PURE__ */ new Map();
471
+ for (let t of B) e.set(String(t.id), t);
472
+ return e;
473
+ }, [B]), wt = e.useCallback((e) => {
474
+ let t = [], n = /* @__PURE__ */ new Set(), r = (e) => {
475
+ for (let i of St.get(e) ?? []) {
476
+ let e = String(i.id);
477
+ n.has(e) || (n.add(e), t.push(i), r(e));
478
+ }
479
+ };
480
+ return r(String(e)), t;
481
+ }, [St]), [V, Tt] = e.useState(null), Et = e.useRef(null);
58
482
  e.useEffect(() => {
59
- U.current = V;
483
+ Et.current = V;
60
484
  }, [V]);
61
- let W = e.useRef(!1), G = e.useCallback((e) => {
62
- let t = 1e3 * 60 * 60 * 24, n = t, r = e.dayDelta * t, i = new Date(e.originStart), a = new Date(e.originEnd);
63
- return e.mode === "move" ? (i = new Date(e.originStart.getTime() + r), a = new Date(e.originEnd.getTime() + r)) : e.mode === "resize-left" ? (i = new Date(e.originStart.getTime() + r), a.getTime() - i.getTime() < n && (i = new Date(a.getTime() - n))) : e.mode === "resize-right" && (a = new Date(e.originEnd.getTime() + r), a.getTime() - i.getTime() < n && (a = new Date(i.getTime() + n))), {
64
- start: i,
65
- end: a
485
+ let Dt = e.useRef(!1), Ot = e.useCallback((e) => {
486
+ let t = We, n = (e, t) => Cn.current ? Cn.current(e, t) : qe(e, t, L), r = new Date(e.originStart), i = new Date(e.originEnd);
487
+ return e.mode === "move" ? (r = n(e.originStart, e.unitDelta), i = new Date(e.originEnd.getTime() + (r.getTime() - e.originStart.getTime()))) : e.mode === "resize-left" ? (r = n(e.originStart, e.unitDelta), i.getTime() - r.getTime() < t && (r = /* @__PURE__ */ new Date(i.getTime() - t))) : e.mode === "resize-right" && (i = n(e.originEnd, e.unitDelta), i.getTime() - r.getTime() < t && (i = new Date(r.getTime() + t))), {
488
+ start: r,
489
+ end: i
66
490
  };
67
- }, []);
491
+ }, [L]), kt = e.useRef(t);
492
+ kt.current = t;
493
+ let At = e.useRef([]), jt = e.useRef([]), [Mt, Nt] = e.useState(0), H = e.useCallback((e) => {
494
+ if (!M) return;
495
+ let t = [];
496
+ for (let { task: n, changes: r } of e) {
497
+ let e = {}, i = {}, a = !1;
498
+ for (let t of Object.keys(r)) {
499
+ let o = r[t], s = n[t], c = o instanceof Date && s instanceof Date ? o.getTime() === s.getTime() : o === s;
500
+ e[t] = s, i[t] = o, c || (a = !0);
501
+ }
502
+ M(n, r), a && t.push({
503
+ taskId: String(n.id),
504
+ before: e,
505
+ after: i
506
+ });
507
+ }
508
+ t.length && (At.current.push(t), jt.current = [], Nt((e) => e + 1));
509
+ }, [M]), [Pt, Ft] = e.useState(null), It = e.useCallback((e) => {
510
+ if (!Ne) return;
511
+ let t = /* @__PURE__ */ new Map();
512
+ for (let { task: n, changes: r } of e) t.set(String(n.id), {
513
+ start: r.start ?? n.start,
514
+ end: r.end ?? n.end
515
+ });
516
+ let n = Fe(kt.current.map((e) => {
517
+ let n = t.get(String(e.id));
518
+ return n ? {
519
+ ...e,
520
+ start: n.start,
521
+ end: n.end
522
+ } : e;
523
+ }), v).filter((e) => {
524
+ let n = t.get(e.id);
525
+ return !n || e.start.getTime() !== n.start.getTime() || e.end.getTime() !== n.end.getTime();
526
+ });
527
+ n.length && Ft(n);
528
+ }, [Ne, v]), Lt = e.useCallback(() => {
529
+ if (!Pt) return;
530
+ let e = Pt.map((e) => {
531
+ let t = kt.current.find((t) => String(t.id) === e.id);
532
+ return t ? {
533
+ task: t,
534
+ changes: {
535
+ start: e.start,
536
+ end: e.end
537
+ }
538
+ } : null;
539
+ }).filter(Boolean);
540
+ e.length && H(e), Ft(null);
541
+ }, [Pt, H]), Rt = e.useCallback((e, t) => {
542
+ if (M) for (let n of e) {
543
+ let e = kt.current.find((e) => String(e.id) === n.taskId);
544
+ e && M(e, t === "undo" ? n.before : n.after);
545
+ }
546
+ }, [M]), zt = e.useCallback(() => {
547
+ let e = At.current.pop();
548
+ e && (Rt(e, "undo"), jt.current.push(e), Nt((e) => e + 1));
549
+ }, [Rt]), Bt = e.useCallback(() => {
550
+ let e = jt.current.pop();
551
+ e && (Rt(e, "redo"), At.current.push(e), Nt((e) => e + 1));
552
+ }, [Rt]), { canUndo: Vt, canRedo: Ht } = e.useMemo(() => ({
553
+ canUndo: At.current.length > 0,
554
+ canRedo: jt.current.length > 0
555
+ }), [Mt]);
68
556
  e.useEffect(() => {
69
557
  if (!V) return;
70
558
  let e = (e) => {
71
- let t = U.current;
559
+ let t = Et.current;
72
560
  if (!t) return;
73
- let n = Math.round((e.clientX - t.originClientX) / Math.max(y, 1));
74
- n !== t.dayDelta && H({
561
+ let n = Math.round((e.clientX - t.originClientX) / Math.max(z, 1));
562
+ n !== t.unitDelta && Tt({
75
563
  ...t,
76
- dayDelta: n
564
+ unitDelta: n
77
565
  });
78
566
  }, n = () => {
79
- let e = U.current;
567
+ let e = Et.current;
80
568
  if (e) {
81
- if (e.dayDelta !== 0) {
569
+ if (e.unitDelta !== 0) {
82
570
  let n = t.find((t) => t.id === e.taskId);
83
- if (n && a) {
84
- let { start: t, end: r } = G(e);
85
- a(n, {
86
- start: t,
87
- end: r
88
- });
571
+ if (n && M) {
572
+ let { start: t, end: r } = Ot(e);
573
+ if (e.group) {
574
+ let r = t.getTime() - e.originStart.getTime(), i = [n, ...wt(n.id)].map((e) => ({
575
+ task: e,
576
+ changes: {
577
+ start: new Date(e.start.getTime() + r),
578
+ end: new Date(e.end.getTime() + r)
579
+ }
580
+ }));
581
+ H(i), It(i);
582
+ } else {
583
+ let e = [{
584
+ task: n,
585
+ changes: {
586
+ start: t,
587
+ end: r
588
+ }
589
+ }];
590
+ H(e), It(e);
591
+ }
89
592
  }
90
- W.current = !0, window.setTimeout(() => {
91
- W.current = !1;
593
+ Dt.current = !0, window.setTimeout(() => {
594
+ Dt.current = !1;
92
595
  }, 0);
93
596
  }
94
- H(null);
597
+ Tt(null);
95
598
  }
96
599
  };
97
600
  return window.addEventListener("pointermove", e), window.addEventListener("pointerup", n), window.addEventListener("pointercancel", n), () => {
@@ -99,416 +602,2476 @@ function z({ tasks: t, startDate: n, endDate: r, onTaskClick: i, onTaskUpdate: a
99
602
  };
100
603
  }, [
101
604
  V,
102
- y,
605
+ z,
103
606
  t,
104
- a,
105
- G
607
+ M,
608
+ Ot,
609
+ wt,
610
+ H,
611
+ It
106
612
  ]);
107
- let K = e.useCallback((e, t, n) => {
108
- a && (n.stopPropagation(), n.preventDefault(), H({
613
+ let Ut = e.useCallback((e, t, n, r) => {
614
+ !M || e.data?.__group || (n.stopPropagation(), n.preventDefault(), Tt({
109
615
  taskId: e.id,
110
616
  mode: t,
111
- originStart: new Date(e.start),
112
- originEnd: new Date(e.end),
617
+ group: r?.group ?? !1,
618
+ originStart: new Date(r?.originStart ?? e.start),
619
+ originEnd: new Date(r?.originEnd ?? e.end),
113
620
  originClientX: n.clientX,
114
- dayDelta: 0
621
+ unitDelta: 0
115
622
  }));
116
- }, [a]), q = e.useMemo(() => {
117
- let e = n ? new Date(n) : /* @__PURE__ */ new Date(), i = r ? new Date(r) : /* @__PURE__ */ new Date();
118
- return !n && t.length > 0 && (e = new Date(Math.min(...t.map((e) => e.start.getTime()))), e.setDate(e.getDate() - 7)), !r && t.length > 0 && (i = new Date(Math.max(...t.map((e) => e.end.getTime()))), i.setDate(i.getDate() + 14)), e.setHours(0, 0, 0, 0), i.setHours(23, 59, 59, 999), {
623
+ }, [M]), [Wt, Gt] = e.useState(null), Kt = e.useRef(null);
624
+ e.useEffect(() => {
625
+ Kt.current = Wt;
626
+ }, [Wt]), e.useEffect(() => {
627
+ if (!Wt) return;
628
+ let e = (e) => {
629
+ let t = Kt.current;
630
+ if (!t) return;
631
+ let n = Math.min(100, Math.max(0, Math.round(t.originProgress + (e.clientX - t.originClientX) / Math.max(t.barWidth, 1) * 100)));
632
+ n !== t.value && Gt({
633
+ ...t,
634
+ value: n
635
+ });
636
+ }, n = () => {
637
+ let e = Kt.current;
638
+ if (e) {
639
+ if (e.value !== e.originProgress) {
640
+ let n = t.find((t) => t.id === e.taskId);
641
+ n && M && H([{
642
+ task: n,
643
+ changes: { progress: e.value }
644
+ }]), Dt.current = !0, window.setTimeout(() => {
645
+ Dt.current = !1;
646
+ }, 0);
647
+ }
648
+ Gt(null);
649
+ }
650
+ };
651
+ return window.addEventListener("pointermove", e), window.addEventListener("pointerup", n), window.addEventListener("pointercancel", n), () => {
652
+ window.removeEventListener("pointermove", e), window.removeEventListener("pointerup", n), window.removeEventListener("pointercancel", n);
653
+ };
654
+ }, [
655
+ Wt,
656
+ t,
657
+ M,
658
+ H
659
+ ]);
660
+ let qt = e.useRef(null), [U, Jt] = e.useState(null), Yt = e.useRef(null);
661
+ e.useEffect(() => {
662
+ Yt.current = U;
663
+ }, [U]), e.useEffect(() => {
664
+ if (!U) return;
665
+ let e = (e) => {
666
+ let t = qt.current?.getBoundingClientRect();
667
+ if (!t) return;
668
+ let n = e.clientX - t.left, r = e.clientY - t.top;
669
+ Jt((e) => e && {
670
+ ...e,
671
+ x: n,
672
+ y: r
673
+ });
674
+ }, n = () => {
675
+ let e = Yt.current;
676
+ if (e && e.targetId != null && String(e.targetId) !== String(e.sourceId) && N) {
677
+ let n = t.find((t) => String(t.id) === String(e.sourceId)), r = t.find((t) => String(t.id) === String(e.targetId)), i = e.targetEnd ?? "start", a = `${e.sourceEnd === "end" ? "f" : "s"}${i === "end" ? "f" : "s"}`;
678
+ n && r && N(n, r, a);
679
+ }
680
+ Dt.current = !0, window.setTimeout(() => {
681
+ Dt.current = !1;
682
+ }, 0), Jt(null);
683
+ };
684
+ return window.addEventListener("pointermove", e), window.addEventListener("pointerup", n), window.addEventListener("pointercancel", n), () => {
685
+ window.removeEventListener("pointermove", e), window.removeEventListener("pointerup", n), window.removeEventListener("pointercancel", n);
686
+ };
687
+ }, [
688
+ U,
689
+ t,
690
+ N
691
+ ]);
692
+ let [Xt, Zt] = e.useState(null), Qt = e.useRef(null);
693
+ e.useEffect(() => {
694
+ if (!Xt) return;
695
+ let e = (e) => {
696
+ Qt.current && e.target instanceof Node && Qt.current.contains(e.target) || Zt(null);
697
+ }, t = (e) => {
698
+ e.key === "Escape" && Zt(null);
699
+ };
700
+ return window.addEventListener("pointerdown", e, !0), window.addEventListener("keydown", t), () => {
701
+ window.removeEventListener("pointerdown", e, !0), window.removeEventListener("keydown", t);
702
+ };
703
+ }, [Xt]);
704
+ let [W, $t] = e.useState(null), en = e.useRef(null);
705
+ e.useEffect(() => {
706
+ if (!W) return;
707
+ let e = (e) => {
708
+ en.current && e.target instanceof Node && en.current.contains(e.target) || $t(null);
709
+ }, t = (e) => {
710
+ e.key === "Escape" && $t(null);
711
+ };
712
+ return window.addEventListener("pointerdown", e, !0), window.addEventListener("keydown", t), () => {
713
+ window.removeEventListener("pointerdown", e, !0), window.removeEventListener("keydown", t);
714
+ };
715
+ }, [W]);
716
+ let [tn, nn] = e.useState(null), rn = e.useRef(null);
717
+ e.useEffect(() => {
718
+ if (!tn) return;
719
+ let e = (e) => {
720
+ rn.current && e.target instanceof Node && rn.current.contains(e.target) || nn(null);
721
+ }, t = (e) => {
722
+ e.key === "Escape" && nn(null);
723
+ };
724
+ return window.addEventListener("pointerdown", e, !0), window.addEventListener("keydown", t), () => {
725
+ window.removeEventListener("pointerdown", e, !0), window.removeEventListener("keydown", t);
726
+ };
727
+ }, [tn]);
728
+ let [an, on] = e.useState(null), sn = !!(o || M || N || ke), cn = e.useCallback((e, t) => {
729
+ t.preventDefault(), t.stopPropagation(), on(e.id), sn && Zt({
730
+ x: t.clientX,
731
+ y: t.clientY,
732
+ taskId: e.id
733
+ });
734
+ }, [sn]), ln = e.useCallback((e, t, n, r) => {
735
+ r.preventDefault(), r.stopPropagation(), !(!N && !Ae) && $t({
736
+ x: r.clientX,
737
+ y: r.clientY,
738
+ sourceId: e,
739
+ targetId: t,
740
+ type: n
741
+ });
742
+ }, [N, Ae]), [un, dn] = e.useState(() => /* @__PURE__ */ new Set()), fn = e.useCallback((e) => {
743
+ dn((t) => {
744
+ let n = new Set(t), r = String(e);
745
+ return n.has(r) ? n.delete(r) : n.add(r), n;
746
+ });
747
+ }, []), pn = e.useRef(!1);
748
+ e.useEffect(() => {
749
+ if (pn.current || ae == null || B.length === 0) return;
750
+ pn.current = !0;
751
+ let e = new Map(B.map((e) => [String(e.id), e])), t = /* @__PURE__ */ new Set();
752
+ for (let n of B) {
753
+ let r = n.parent != null && n.parent !== "" ? String(n.parent) : null;
754
+ r && r !== String(n.id) && e.has(r) && t.add(r);
755
+ }
756
+ let n = (t) => {
757
+ let n = 0, r = new Set([String(t.id)]), i = t.parent != null && t.parent !== "" ? e.get(String(t.parent)) : void 0;
758
+ for (; i && !r.has(String(i.id));) n += 1, r.add(String(i.id)), i = i.parent != null && i.parent !== "" ? e.get(String(i.parent)) : void 0;
759
+ return n;
760
+ }, r = /* @__PURE__ */ new Set();
761
+ for (let e of B) {
762
+ let i = String(e.id);
763
+ t.has(i) && n(e) >= ae && r.add(i);
764
+ }
765
+ r.size && dn((e) => e.size ? e : r);
766
+ }, [ae, B]);
767
+ let G = e.useMemo(() => {
768
+ let e = new Set(B.map((e) => String(e.id))), t = /* @__PURE__ */ new Map(), n = [];
769
+ for (let r of B) {
770
+ let i = r.parent != null && r.parent !== "" ? String(r.parent) : null;
771
+ if (i && i !== String(r.id) && e.has(i)) {
772
+ let e = t.get(i);
773
+ e ? e.push(r) : t.set(i, [r]);
774
+ } else n.push(r);
775
+ }
776
+ let r = /* @__PURE__ */ new Map(), i = (e, n) => {
777
+ let a = String(e.id), o = r.get(a);
778
+ if (o) return o;
779
+ let s = t.get(a) ?? [], c;
780
+ if (!s.length || n.has(a)) c = {
781
+ start: e.start,
782
+ end: e.end,
783
+ progress: e.progress
784
+ };
785
+ else {
786
+ n.add(a);
787
+ let e = null, t = null, r = 0, o = 0;
788
+ for (let a of s) {
789
+ let s = i(a, n);
790
+ (!e || s.start < e) && (e = s.start), (!t || s.end > t) && (t = s.end);
791
+ let c = Math.max(s.end.getTime() - s.start.getTime(), We);
792
+ r += c * s.progress, o += c;
793
+ }
794
+ n.delete(a), c = {
795
+ start: e,
796
+ end: t,
797
+ progress: o ? r / o : 0
798
+ };
799
+ }
800
+ return r.set(a, c), c;
801
+ }, a = [], o = /* @__PURE__ */ new Set(), s = (e) => {
802
+ for (let n of t.get(String(e.id)) ?? []) o.has(String(n.id)) || (o.add(String(n.id)), s(n));
803
+ }, c = (e, n) => {
804
+ let r = String(e.id);
805
+ if (o.has(r)) return;
806
+ o.add(r);
807
+ let l = t.get(r) ?? [], u = l.length > 0, d = u || e.type === "summary", f = u ? i(e, /* @__PURE__ */ new Set()) : {
808
+ start: e.start,
809
+ end: e.end,
810
+ progress: e.progress
811
+ }, p = !d && (e.type === "milestone" || e.end.getTime() <= e.start.getTime());
812
+ if (a.push({
813
+ task: e,
814
+ depth: n,
815
+ hasChildren: u,
816
+ isSummary: d,
817
+ isMilestone: p,
818
+ ...f
819
+ }), u) if (un.has(r)) s(e);
820
+ else for (let e of l) c(e, n + 1);
821
+ };
822
+ for (let e of n) c(e, 0);
823
+ for (let e of B) o.has(String(e.id)) || c(e, 0);
824
+ return a;
825
+ }, [B, un]), mn = e.useCallback((e) => {
826
+ if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
827
+ if ((e.ctrlKey || e.metaKey) && (e.key === "z" || e.key === "Z")) {
828
+ e.preventDefault(), e.shiftKey ? Bt() : zt();
829
+ return;
830
+ }
831
+ if ((e.ctrlKey || e.metaKey) && (e.key === "y" || e.key === "Y")) {
832
+ e.preventDefault(), Bt();
833
+ return;
834
+ }
835
+ if (!G.length) return;
836
+ let t = an == null ? -1 : G.findIndex((e) => String(e.task.id) === String(an));
837
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
838
+ e.preventDefault();
839
+ let n = e.key === "ArrowDown" ? Math.min(G.length - 1, t + 1) : Math.max(0, t <= 0 ? 0 : t - 1);
840
+ on(G[n].task.id);
841
+ let r = X.current;
842
+ if (r) {
843
+ let e = n * F;
844
+ e < r.scrollTop ? r.scrollTop = e : e + F > r.scrollTop + r.clientHeight && (r.scrollTop = e + F - r.clientHeight);
845
+ }
846
+ return;
847
+ }
848
+ if (t < 0) return;
849
+ let n = G[t];
850
+ e.key === "Enter" ? (e.preventDefault(), o?.(n.task)) : e.key === "Delete" || e.key === "Backspace" ? ke && (e.preventDefault(), ke(n.task)) : (e.key === "ArrowRight" && n.hasChildren && un.has(String(n.task.id)) || e.key === "ArrowLeft" && n.hasChildren && !un.has(String(n.task.id))) && (e.preventDefault(), fn(n.task.id));
851
+ }, [
852
+ G,
853
+ an,
854
+ o,
855
+ ke,
856
+ un,
857
+ fn,
858
+ F,
859
+ zt,
860
+ Bt
861
+ ]), K = e.useMemo(() => {
862
+ let e = r ? new Date(r) : /* @__PURE__ */ new Date(), n = i ? new Date(i) : /* @__PURE__ */ new Date();
863
+ return !r && t.length > 0 && (e = new Date(Math.min(...t.map((e) => e.start.getTime()))), e.setDate(e.getDate() - 7)), !i && t.length > 0 && (n = new Date(Math.max(...t.map((e) => e.end.getTime()))), n.setDate(n.getDate() + 14)), e = Ge(e, L), n.setHours(23, 59, 59, 999), {
119
864
  start: e,
120
- end: i
865
+ end: n
121
866
  };
122
867
  }, [
123
- n,
124
868
  r,
125
- t
869
+ i,
870
+ t,
871
+ L
872
+ ]), hn = L === "day" && !!v && (!!v.skipWeekends || !!(v.holidays && v.holidays.size)), gn = e.useCallback((e) => {
873
+ if (!v) return !0;
874
+ if (v.skipWeekends) {
875
+ let t = e.getDay();
876
+ if (t === 0 || t === 6) return !1;
877
+ }
878
+ if (v.holidays && v.holidays.size) {
879
+ let t = `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
880
+ if (v.holidays.has(t)) return !1;
881
+ }
882
+ return !0;
883
+ }, [v]), q = e.useMemo(() => {
884
+ let e = [], t = new Date(K.start);
885
+ for (; t <= K.end;) {
886
+ let n = qe(t, 1, L);
887
+ if (hn && !gn(t)) {
888
+ t = n;
889
+ continue;
890
+ }
891
+ let r = (n.getTime() - t.getTime()) / We * mt, i, a;
892
+ L === "day" ? (i = String(t.getDate()), a = t.toLocaleDateString(S, { weekday: "narrow" })) : i = L === "week" ? t.toLocaleDateString(S, {
893
+ month: "numeric",
894
+ day: "numeric"
895
+ }) : L === "month" ? t.toLocaleDateString(S, { month: "short" }) : L === "quarter" ? `Q${Math.floor(t.getMonth() / 3) + 1}` : String(t.getFullYear()), e.push({
896
+ date: new Date(t),
897
+ label: i,
898
+ sublabel: a,
899
+ isWeekend: L === "day" && (t.getDay() === 0 || t.getDay() === 6),
900
+ width: r
901
+ }), t = n;
902
+ }
903
+ return e;
904
+ }, [
905
+ K,
906
+ L,
907
+ mt,
908
+ S,
909
+ hn,
910
+ gn
126
911
  ]), J = e.useMemo(() => {
127
- let e = [], t = new Date(q.start);
128
- for (; t <= q.end;) e.push({
129
- date: new Date(t),
130
- label: t.getDate().toString(),
131
- isWeekend: t.getDay() === 0 || t.getDay() === 6
132
- }), t.setDate(t.getDate() + 1);
912
+ let e = Array(q.length + 1), t = 0;
913
+ for (let n = 0; n < q.length; n++) e[n] = t, t += q[n].width;
914
+ return e[q.length] = t, e;
915
+ }, [q]), _n = J[J.length - 1], vn = e.useMemo(() => q.map((e) => e.date.getTime()), [q]), yn = e.useMemo(() => q.map((e) => qe(e.date, 1, L).getTime() - e.date.getTime()), [q, L]), Y = e.useCallback((e) => {
916
+ let t = q.length;
917
+ if (t === 0) return 0;
918
+ let n = e.getTime(), r = 0, i = t - 1, a = 0;
919
+ for (; r <= i;) {
920
+ let e = r + i >> 1;
921
+ vn[e] <= n ? (a = e, r = e + 1) : i = e - 1;
922
+ }
923
+ let o = yn[a] || 864e5, s = (n - vn[a]) / o;
924
+ return hn && (s = Math.max(0, Math.min(s, 1))), J[a] + s * q[a].width;
925
+ }, [
926
+ q,
927
+ vn,
928
+ yn,
929
+ J,
930
+ hn
931
+ ]), bn = e.useCallback((e) => {
932
+ let t = q.length;
933
+ if (t === 0) return new Date(K.start);
934
+ let n = 0, r = t - 1, i = 0;
935
+ for (; n <= r;) {
936
+ let t = n + r >> 1;
937
+ J[t] <= e ? (i = t, n = t + 1) : r = t - 1;
938
+ }
939
+ let a = q[i].width || 1, o = (e - J[i]) / a;
940
+ return new Date(vn[i] + o * (yn[i] || 864e5));
941
+ }, [
942
+ q,
943
+ vn,
944
+ yn,
945
+ J,
946
+ K
947
+ ]), xn = e.useCallback((e) => {
948
+ let t = X.current;
949
+ st.current == null && t && t.clientWidth > 0 && (st.current = bn(t.scrollLeft)), ot.current = st.current, ct.current = !0, at(e), l?.(e);
950
+ }, [l, bn]);
951
+ e.useLayoutEffect(() => {
952
+ let e = ot.current;
953
+ if (e == null) return;
954
+ ot.current = null;
955
+ let t = X.current;
956
+ if (!t || t.clientWidth === 0) return;
957
+ let n = Math.max(0, t.scrollWidth - t.clientWidth), r = Math.max(0, Math.min(Math.round(Y(Ge(e, L))), n));
958
+ t.scrollLeft !== r && (t.scrollLeft = r);
959
+ }, [L, Y]);
960
+ let Sn = e.useCallback((e, t) => {
961
+ let n = q.length;
962
+ if (n === 0 || t === 0) return new Date(e);
963
+ let r = e.getTime(), i = 0, a = n - 1, o = 0;
964
+ for (; i <= a;) {
965
+ let e = i + a >> 1;
966
+ vn[e] <= r ? (o = e, i = e + 1) : a = e - 1;
967
+ }
968
+ let s = Math.min(n - 1, Math.max(0, o + t)), c = r - vn[o];
969
+ return new Date(vn[s] + c);
970
+ }, [q, vn]), Cn = e.useRef(null);
971
+ Cn.current = hn ? Sn : null;
972
+ let wn = e.useMemo(() => {
973
+ let e = [], t = L === "year" ? "decade" : L === "month" || L === "quarter" ? "year" : "month", n = 0;
974
+ for (let r of q) {
975
+ let i = r.date.getFullYear(), a = Math.floor(i / 10) * 10, o = t === "decade" ? String(a) : t === "year" ? String(i) : `${i}-${r.date.getMonth()}`, s = e[e.length - 1];
976
+ s && s.key === o ? s.width += r.width : e.push({
977
+ key: o,
978
+ label: t === "decade" ? `${a}s` : t === "year" ? String(i) : r.date.toLocaleDateString(S, {
979
+ month: "short",
980
+ year: "numeric"
981
+ }),
982
+ width: r.width,
983
+ offset: n
984
+ }), n += r.width;
985
+ }
133
986
  return e;
134
- }, [q]), Y = e.useRef(null), X = e.useRef(null), oe = e.useRef(null), Z = e.useRef(null), Q = e.useRef(null), se = e.useCallback((e) => {
987
+ }, [
988
+ q,
989
+ L,
990
+ S
991
+ ]), Tn = e.useMemo(() => (a ?? []).map((e, t) => {
992
+ let n = e.date instanceof Date ? e.date : new Date(e.date);
993
+ return {
994
+ index: t,
995
+ label: e.label,
996
+ color: e.color || "hsl(var(--primary))",
997
+ left: Math.round(Y(n)),
998
+ valid: !isNaN(n.getTime()) && n >= K.start && n <= K.end
999
+ };
1000
+ }).filter((e) => e.valid), [
1001
+ a,
1002
+ K,
1003
+ Y
1004
+ ]), En = e.useRef(null), Dn = e.useRef(null), On = e.useRef(null), X = e.useRef(null);
1005
+ e.useEffect(() => {
1006
+ let e = X.current;
1007
+ if (!e) return;
1008
+ let t = () => {
1009
+ ct.current = !1;
1010
+ }, n = new Set([
1011
+ "ArrowLeft",
1012
+ "ArrowRight",
1013
+ "ArrowUp",
1014
+ "ArrowDown",
1015
+ "PageUp",
1016
+ "PageDown",
1017
+ "Home",
1018
+ "End",
1019
+ " ",
1020
+ "Spacebar"
1021
+ ]), r = (e) => {
1022
+ n.has(e.key) && t();
1023
+ };
1024
+ return e.addEventListener("wheel", t, { passive: !0 }), e.addEventListener("touchstart", t, { passive: !0 }), e.addEventListener("pointerdown", t, { passive: !0 }), e.addEventListener("keydown", r), () => {
1025
+ e.removeEventListener("wheel", t), e.removeEventListener("touchstart", t), e.removeEventListener("pointerdown", t), e.removeEventListener("keydown", r);
1026
+ };
1027
+ }, []);
1028
+ let [kn, An] = e.useState(null), jn = e.useRef([]), Mn = e.useRef(null), [Nn, Pn] = e.useState({
1029
+ top: 0,
1030
+ left: 0
1031
+ }), [Fn, In] = e.useState({
1032
+ width: 4e3,
1033
+ height: 600
1034
+ }), Ln = e.useCallback(() => {
1035
+ let e = X.current;
1036
+ if (!e) return;
1037
+ let t = e.clientWidth || 4e3, n = e.clientHeight || 600;
1038
+ In((e) => e.width === t && e.height === n ? e : {
1039
+ width: t,
1040
+ height: n
1041
+ });
1042
+ }, []);
1043
+ e.useLayoutEffect(() => {
1044
+ Ln();
1045
+ let e = X.current;
1046
+ if (!e || typeof ResizeObserver > "u") return;
1047
+ let t = new ResizeObserver(Ln);
1048
+ return t.observe(e), () => t.disconnect();
1049
+ }, [Ln]);
1050
+ let Rn = e.useMemo(() => Ke(J, Nn.left - 240, Nn.left + Fn.width + 240), [
1051
+ J,
1052
+ Nn.left,
1053
+ Fn.width
1054
+ ]), zn = e.useMemo(() => {
1055
+ let e = wn.map((e) => e.offset);
1056
+ return e.push(_n), e;
1057
+ }, [wn, _n]), Bn = e.useMemo(() => Ke(zn, Nn.left - 240, Nn.left + Fn.width + 240), [
1058
+ zn,
1059
+ Nn.left,
1060
+ Fn.width
1061
+ ]), Z = e.useMemo(() => ({
1062
+ startIdx: Math.max(0, Math.floor(Nn.top / F) - 6),
1063
+ endIdx: Math.min(G.length, Math.ceil((Nn.top + Fn.height) / F) + 6)
1064
+ }), [
1065
+ Nn.top,
1066
+ Fn.height,
1067
+ F,
1068
+ G.length
1069
+ ]), Vn = G.length * F, [Hn, Un] = e.useState(!1);
1070
+ e.useEffect(() => {
1071
+ let e = () => Un(!!document.fullscreenElement);
1072
+ return document.addEventListener("fullscreenchange", e), () => document.removeEventListener("fullscreenchange", e);
1073
+ }, []);
1074
+ let Wn = e.useCallback(() => {
1075
+ let e = fe.current;
1076
+ e && (document.fullscreenElement ? document.exitFullscreen?.() : e.requestFullscreen?.());
1077
+ }, []), Gn = e.useRef(null), Kn = e.useCallback((e) => {
135
1078
  if (e.touches.length === 2) {
136
1079
  let t = e.touches[0].clientX - e.touches[1].clientX, n = e.touches[0].clientY - e.touches[1].clientY;
137
- Q.current = {
1080
+ Gn.current = {
138
1081
  baseDistance: Math.max(1, Math.sqrt(t * t + n * n)),
139
- baseColumn: y
1082
+ baseColumn: z
140
1083
  };
141
1084
  }
142
- }, [y]), ce = e.useCallback((e) => {
143
- if (e.touches.length !== 2 || !Q.current) return;
144
- let t = e.touches[0].clientX - e.touches[1].clientX, n = e.touches[0].clientY - e.touches[1].clientY, r = Math.max(1, Math.sqrt(t * t + n * n)) / Q.current.baseDistance;
145
- v(Math.max(15, Math.min(120, Math.round(Q.current.baseColumn * r))));
146
- }, []), le = e.useCallback(() => {
147
- Q.current = null;
148
- }, []), $ = e.useMemo(() => {
1085
+ }, [z]), qn = e.useCallback((e) => {
1086
+ if (e.touches.length !== 2 || !Gn.current) return;
1087
+ let t = e.touches[0].clientX - e.touches[1].clientX, n = e.touches[0].clientY - e.touches[1].clientY, r = Math.max(1, Math.sqrt(t * t + n * n)) / Gn.current.baseDistance;
1088
+ nt(Math.max(15, Math.min(120, Math.round(Gn.current.baseColumn * r))));
1089
+ }, []), Jn = e.useCallback(() => {
1090
+ Gn.current = null;
1091
+ }, []), Q = e.useMemo(() => {
149
1092
  let e = /* @__PURE__ */ new Date();
150
- if (e < q.start || e > q.end) return null;
151
- let t = (e.getTime() - q.start.getTime()) / (1440 * 60 * 1e3);
152
- return Math.round(t * y);
153
- }, [q, y]), ue = e.useCallback(() => {
154
- if ($ == null || !Z.current) return;
155
- let e = Math.max(0, $ - Z.current.clientWidth / 2);
156
- Z.current.scrollTo({
1093
+ return e < K.start || e > K.end ? null : Math.round(Y(e));
1094
+ }, [K, Y]), Yn = e.useCallback(() => {
1095
+ if (Q == null || !X.current) return;
1096
+ let e = Math.max(0, Q - X.current.clientWidth / 2);
1097
+ X.current.scrollTo({
157
1098
  left: e,
158
1099
  behavior: "smooth"
159
1100
  });
160
- }, [$]), de = (e) => {
161
- Y.current && (Y.current.scrollLeft = e.currentTarget.scrollLeft), X.current && (X.current.scrollTop = e.currentTarget.scrollTop);
162
- }, fe = (e) => {
163
- q.end.getTime() - q.start.getTime();
164
- let t = y, n = 1e3 * 60 * 60 * 24, r = e.start.getTime() - q.start.getTime(), i = e.end.getTime() - e.start.getTime();
1101
+ }, [Q]), Xn = e.useRef(!1);
1102
+ e.useEffect(() => {
1103
+ if (Xn.current || t.length === 0) return;
1104
+ let e = window.requestAnimationFrame(() => {
1105
+ let e = X.current;
1106
+ if (!e || e.clientWidth === 0) return;
1107
+ let n = Q;
1108
+ if (n == null) {
1109
+ let e = new Date(Math.min(...t.map((e) => e.start.getTime())));
1110
+ n = Math.round(Y(e));
1111
+ }
1112
+ e.scrollLeft = Math.max(0, n - e.clientWidth / 2), Xn.current = !0;
1113
+ });
1114
+ return () => window.cancelAnimationFrame(e);
1115
+ }, [
1116
+ t,
1117
+ Q,
1118
+ Y
1119
+ ]);
1120
+ let Zn = e.useCallback((e, t = "left") => {
1121
+ let n = X.current;
1122
+ if (!n || e < K.start || e > K.end) return !1;
1123
+ let r = Math.round(Y(e)), i = t === "center" ? r - n.clientWidth / 2 : r - 24;
1124
+ return n.scrollTo({
1125
+ left: Math.max(0, i),
1126
+ behavior: "smooth"
1127
+ }), !0;
1128
+ }, [K, Y]), Qn = e.useCallback((e, t, n) => {
1129
+ let r = X.current;
1130
+ if (!r) return;
1131
+ let i = Y(e), a = Y(t), o = Math.max(0, r.scrollWidth - r.clientWidth), s = Math.min(96, r.clientWidth * .15), c = a - i <= r.clientWidth - s ? (i + a) / 2 - r.clientWidth / 2 : i - s, l = Math.max(0, Math.min(c, o));
1132
+ jn.current.forEach((e) => window.clearTimeout(e)), jn.current = [], Mn.current?.(), Mn.current = null, An(null);
1133
+ let u = () => {
1134
+ if (n == null) return;
1135
+ let e = window.requestAnimationFrame(() => {
1136
+ An(n), jn.current.push(window.setTimeout(() => An((e) => e === n ? null : e), 1500));
1137
+ });
1138
+ Mn.current = () => window.cancelAnimationFrame(e);
1139
+ }, d = Math.abs(r.scrollLeft - l) > 2;
1140
+ if (r.scrollTo({
1141
+ left: l,
1142
+ behavior: "smooth"
1143
+ }), !d) {
1144
+ u();
1145
+ return;
1146
+ }
1147
+ let f = "onscrollend" in r, p = !1, m = () => {
1148
+ p || (p = !0, r.removeEventListener("scrollend", m), u());
1149
+ };
1150
+ r.addEventListener("scrollend", m), jn.current.push(window.setTimeout(m, f ? 1500 : 500)), Mn.current = () => r.removeEventListener("scrollend", m);
1151
+ }, [Y]);
1152
+ e.useEffect(() => () => {
1153
+ jn.current.forEach((e) => window.clearTimeout(e)), Mn.current?.();
1154
+ }, []);
1155
+ let $n = e.useCallback(() => Zn(Ge(/* @__PURE__ */ new Date(), "week")), [Zn]), er = e.useCallback(() => Zn(Ge(/* @__PURE__ */ new Date(), "month")), [Zn]), tr = (e) => {
1156
+ let t = e.currentTarget;
1157
+ !ct.current && t.clientWidth > 0 && (st.current = bn(t.scrollLeft)), En.current && (En.current.scrollLeft = t.scrollLeft), Dn.current && Dn.current.scrollTop !== t.scrollTop && (Dn.current.scrollTop = t.scrollTop), Pn((e) => e.top === t.scrollTop && e.left === t.scrollLeft ? e : {
1158
+ top: t.scrollTop,
1159
+ left: t.scrollLeft
1160
+ }), Ln();
1161
+ }, nr = (e) => {
1162
+ let t = e.currentTarget, n = X.current;
1163
+ n && n.scrollTop !== t.scrollTop && (n.scrollTop = t.scrollTop), Pn((e) => e.top === t.scrollTop ? e : {
1164
+ ...e,
1165
+ top: t.scrollTop
1166
+ });
1167
+ }, rr = (e, t) => {
1168
+ let n = Y(e);
165
1169
  return {
166
- left: r / n * t,
167
- width: Math.max(i / n * t, t)
1170
+ left: n,
1171
+ width: Math.max(Y(t) - n, mt, 3)
168
1172
  };
169
- };
170
- return /* @__PURE__ */ N("div", {
171
- ref: d,
172
- className: C("flex flex-col h-full bg-background overflow-hidden min-w-0", o),
173
- children: [/* @__PURE__ */ N("div", {
174
- className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 p-2 border-b bg-card",
175
- children: [/* @__PURE__ */ N("div", {
176
- className: "flex items-center gap-2",
177
- children: [
178
- /* @__PURE__ */ M(S, {
179
- variant: "ghost",
180
- size: "icon",
181
- className: "h-8 w-8",
182
- "aria-label": c("gantt.toolbar.prevPeriod"),
183
- children: /* @__PURE__ */ M(D, { className: "h-4 w-4" })
184
- }),
185
- /* @__PURE__ */ M(S, {
186
- variant: "ghost",
187
- size: "icon",
188
- className: "h-8 w-8",
189
- "aria-label": c("gantt.toolbar.nextPeriod"),
190
- children: /* @__PURE__ */ M(O, { className: "h-4 w-4" })
191
- }),
192
- /* @__PURE__ */ M("span", {
193
- className: "font-semibold text-xs sm:text-sm",
194
- children: q.start.toLocaleDateString(void 0, {
195
- month: "long",
196
- year: "numeric"
1173
+ }, ir = V?.group ? V.taskId : null, ar = e.useMemo(() => {
1174
+ if (ir == null) return null;
1175
+ let e = new Set([String(ir)]);
1176
+ for (let t of wt(ir)) e.add(String(t.id));
1177
+ return e;
1178
+ }, [ir, wt]), or = e.useMemo(() => {
1179
+ if (!V || V.group) return null;
1180
+ let e = /* @__PURE__ */ new Set(), t = /* @__PURE__ */ new Set(), n = Ct.get(String(V.taskId));
1181
+ for (; n && n.parent != null && n.parent !== "";) {
1182
+ let r = String(n.parent);
1183
+ if (t.has(r) || !Ct.has(r)) break;
1184
+ t.add(r), e.add(r), n = Ct.get(r);
1185
+ }
1186
+ return e.size ? e : null;
1187
+ }, [V, Ct]), sr = (e) => {
1188
+ if (V) {
1189
+ if (ar?.has(String(e.task.id))) {
1190
+ let t = Ot(V).start.getTime() - V.originStart.getTime();
1191
+ return rr(new Date(e.start.getTime() + t), new Date(e.end.getTime() + t));
1192
+ }
1193
+ if (!e.isSummary && V.taskId === e.task.id) {
1194
+ let e = Ot(V);
1195
+ return rr(e.start, e.end);
1196
+ }
1197
+ if (e.isSummary && or?.has(String(e.task.id))) {
1198
+ let t = Ot(V), n = String(V.taskId), r = null, i = null;
1199
+ for (let a of wt(e.task.id)) {
1200
+ if ((St.get(String(a.id)) ?? []).length !== 0) continue;
1201
+ let e = String(a.id) === n ? t.start : a.start, o = String(a.id) === n ? t.end : a.end;
1202
+ (!r || e < r) && (r = e), (!i || o > i) && (i = o);
1203
+ }
1204
+ if (r && i) return rr(r, i);
1205
+ }
1206
+ }
1207
+ return rr(e.start, e.end);
1208
+ }, cr = e.useMemo(() => {
1209
+ let e = /* @__PURE__ */ new Map();
1210
+ G.forEach((t, n) => e.set(String(t.task.id), n));
1211
+ let t = [];
1212
+ return G.forEach(({ task: n }, r) => {
1213
+ for (let i of n.dependencies ?? []) {
1214
+ let a = typeof i == "object" && !!i, o = a ? i.id : i;
1215
+ if (o == null || o === "") continue;
1216
+ let s = e.get(String(o));
1217
+ if (s == null || s === r) continue;
1218
+ let c = a ? i.type : void 0, l = c === "ss" || c === "ff" || c === "sf" ? c : "fs";
1219
+ t.push({
1220
+ key: `${String(o)}->${String(n.id)}:${l}`,
1221
+ sourceId: o,
1222
+ targetId: n.id,
1223
+ type: l,
1224
+ sourceIndex: s,
1225
+ targetIndex: r
1226
+ });
1227
+ }
1228
+ }), t;
1229
+ }, [G]), lr = Math.round(F * .2), ur = F - lr * 2, dr = Math.max(Math.round(F * .4), 12), fr = dr * Math.SQRT2 / 2, pr = ur, mr = lr, hr = Math.max(3, Math.round(F * .13)), gr = F - hr - 1, _r = "rgba(100, 116, 139, 0.35)", vr = "rgba(100, 116, 139, 0.6)", yr = (e) => {
1230
+ let t = G[e.sourceIndex], n = G[e.targetIndex];
1231
+ if (!t || !n) return null;
1232
+ let r = sr(t), i = sr(n), a = (e) => e.isSummary ? mr + pr / 2 : F / 2, o = e.sourceIndex * F + a(t), s = e.targetIndex * F + a(n), c = e.type === "fs" || e.type === "ff", l = e.type === "ff" || e.type === "sf", u = t.isMilestone ? r.left + (c ? fr : -fr) : c ? r.left + r.width : r.left, d = n.isMilestone ? i.left + (l ? fr : -fr) : l ? i.left + i.width : i.left, f = u + (c ? 10 : -10), p = d + (l ? 10 : -10), m = Math.round, h = [`M ${m(u)} ${m(o)}`, `L ${m(f)} ${m(o)}`];
1233
+ if (l ? f >= p : f <= p) h.push(`L ${m(f)} ${m(s)}`, `L ${m(d)} ${m(s)}`);
1234
+ else {
1235
+ let t = s >= o ? (e.sourceIndex + 1) * F : e.sourceIndex * F;
1236
+ h.push(`L ${m(f)} ${m(t)}`, `L ${m(p)} ${m(t)}`, `L ${m(p)} ${m(s)}`, `L ${m(d)} ${m(s)}`);
1237
+ }
1238
+ return h.join(" ");
1239
+ }, br = V?.taskId ?? bt, [xr, Sr] = e.useState(_), Cr = e.useMemo(() => xr ? Pe(t, v) : null, [
1240
+ xr,
1241
+ t,
1242
+ v
1243
+ ]), wr = e.useCallback((e) => Cr?.criticalIds.has(String(e)) ?? !1, [Cr]), $ = "#dc2626", Tr = e.useCallback(() => {
1244
+ if (!M) return;
1245
+ let e = Fe(t, v), n = [];
1246
+ for (let r of e) {
1247
+ let e = t.find((e) => String(e.id) === r.id);
1248
+ e && n.push({
1249
+ task: e,
1250
+ changes: {
1251
+ start: r.start,
1252
+ end: r.end
1253
+ }
1254
+ });
1255
+ }
1256
+ H(n);
1257
+ }, [
1258
+ t,
1259
+ M,
1260
+ v,
1261
+ H
1262
+ ]), Er = e.useCallback(() => {
1263
+ if (typeof document > "u" || !t.length) return null;
1264
+ let e = (e) => String(e).replace(/[&<>"]/g, (e) => ({
1265
+ "&": "&amp;",
1266
+ "<": "&lt;",
1267
+ ">": "&gt;",
1268
+ "\"": "&quot;"
1269
+ })[e]), n = Math.max(R, 200), r = Math.ceil(n + _n), i = Math.ceil(36 + G.length * F), a = Cr?.criticalEdges ?? null, o = [];
1270
+ o.push(`<rect x="0" y="0" width="${r}" height="${i}" fill="#ffffff"/>`), o.push(`<rect x="0" y="0" width="${r}" height="36" fill="#f8fafc"/>`), o.push(`<g transform="translate(${n},0)" font-family="sans-serif" font-size="10" fill="#475569">`), wn.forEach((t) => {
1271
+ o.push(`<line x1="${t.offset.toFixed(1)}" y1="0" x2="${t.offset.toFixed(1)}" y2="36" stroke="#e2e8f0"/>`), o.push(`<text x="${(t.offset + t.width / 2).toFixed(1)}" y="12" text-anchor="middle" font-weight="600">${e(t.label)}</text>`);
1272
+ }), q.forEach((t, n) => {
1273
+ let r = J[n];
1274
+ o.push(`<line x1="${r.toFixed(1)}" y1="18" x2="${r.toFixed(1)}" y2="${i}" stroke="#eef2f7"/>`), o.push(`<text x="${(r + t.width / 2).toFixed(1)}" y="30" text-anchor="middle" fill="#1f2937">${e(t.label)}</text>`);
1275
+ }), o.push("</g>"), o.push(`<line x1="0" y1="18" x2="${r}" y2="18" stroke="#e2e8f0"/>`), o.push(`<line x1="0" y1="36" x2="${r}" y2="36" stroke="#cbd5e1"/>`), o.push(`<line x1="${n}" y1="0" x2="${n}" y2="${i}" stroke="#cbd5e1"/>`), o.push("<g transform=\"translate(0,36)\" font-family=\"sans-serif\" font-size=\"11\" fill=\"#1f2937\">"), G.forEach((t, r) => {
1276
+ let i = r * F;
1277
+ o.push(`<line x1="0" y1="${(i + F).toFixed(1)}" x2="${n}" y2="${(i + F).toFixed(1)}" stroke="#f1f5f9"/>`);
1278
+ let a = 8 + t.depth * 14, s = Math.max(4, Math.floor((n - a) / 6.5)), c = t.task.title.length > s ? t.task.title.slice(0, s - 1) + "…" : t.task.title, l = t.isSummary ? " font-weight=\"600\"" : "";
1279
+ o.push(`<text x="${a}" y="${(i + F / 2 + 4).toFixed(1)}"${l}>${e(c)}</text>`);
1280
+ }), o.push("</g>"), o.push(`<g transform="translate(${n},36)" font-family="sans-serif" font-size="9">`), G.forEach((e, t) => {
1281
+ let n = t * F, { left: r, width: i } = rr(e.start, e.end), a = wr(e.task.id), s = a ? ` stroke="${$}" stroke-width="2"` : "";
1282
+ if (ee && e.task.baselineStart && e.task.baselineEnd) {
1283
+ let t = rr(e.task.baselineStart, e.task.baselineEnd);
1284
+ o.push(`<rect x="${t.left.toFixed(1)}" y="${(n + gr).toFixed(1)}" width="${Math.max(2, t.width).toFixed(1)}" height="${hr}" rx="1" fill="${_r}" stroke="${vr}"/>`);
1285
+ }
1286
+ if (e.isMilestone) {
1287
+ let t = r, i = n + F / 2, s = dr / 2, c = a ? $ : e.task.color || "#3b82f6";
1288
+ o.push(`<polygon points="${t},${i - s} ${t + s},${i} ${t},${i + s} ${t - s},${i}" fill="${c}"/>`);
1289
+ } else if (e.isSummary) {
1290
+ let t = e.task.color || "#64748b";
1291
+ o.push(`<rect x="${r.toFixed(1)}" y="${(n + mr).toFixed(1)}" width="${i.toFixed(1)}" height="${pr}" rx="3" fill="${t}"${s}/>`);
1292
+ let a = i * Math.min(100, Math.max(0, e.progress)) / 100;
1293
+ o.push(`<rect x="${r.toFixed(1)}" y="${(n + mr).toFixed(1)}" width="${a.toFixed(1)}" height="${pr}" rx="3" fill="rgba(0,0,0,0.2)"/>`);
1294
+ } else {
1295
+ let t = e.task.color || "#3b82f6";
1296
+ o.push(`<rect x="${r.toFixed(1)}" y="${(n + lr).toFixed(1)}" width="${i.toFixed(1)}" height="${ur}" rx="3" fill="${t}"${s}/>`);
1297
+ let a = i * Math.min(100, Math.max(0, e.progress)) / 100;
1298
+ o.push(`<rect x="${r.toFixed(1)}" y="${(n + lr).toFixed(1)}" width="${a.toFixed(1)}" height="${ur}" rx="3" fill="rgba(0,0,0,0.18)"/>`), i >= 24 && o.push(`<text x="${(r + i / 2).toFixed(1)}" y="${(n + F / 2 + 3).toFixed(1)}" text-anchor="middle" fill="#ffffff">${Math.round(e.progress)}%</text>`);
1299
+ }
1300
+ }), cr.forEach((e) => {
1301
+ let t = yr(e);
1302
+ if (!t) return;
1303
+ let n = a?.has(`${String(e.sourceId)}->${String(e.targetId)}`) ?? !1, r = n ? $ : "#94a3b8";
1304
+ o.push(`<path d="${t}" fill="none" stroke="${r}" stroke-width="${n ? 2 : 1.5}"/>`);
1305
+ }), Q != null && o.push(`<line x1="${Q.toFixed(1)}" y1="0" x2="${Q.toFixed(1)}" y2="${G.length * F}" stroke="#ef4444" stroke-width="1.5"/>`);
1306
+ let s = G.length * F;
1307
+ return Tn.forEach((t) => {
1308
+ let n = /var\(/.test(t.color) ? "#6366f1" : t.color;
1309
+ if (o.push(`<line x1="${t.left.toFixed(1)}" y1="0" x2="${t.left.toFixed(1)}" y2="${s}" stroke="${e(n)}" stroke-width="1.5"/>`), t.label) {
1310
+ let r = t.label.length * 6 + 8;
1311
+ o.push(`<rect x="${(t.left - r / 2).toFixed(1)}" y="0" width="${r}" height="14" rx="2" fill="${e(n)}"/>`), o.push(`<text x="${t.left.toFixed(1)}" y="10" text-anchor="middle" font-size="9" font-weight="600" fill="#ffffff">${e(t.label)}</text>`);
1312
+ }
1313
+ }), o.push("</g>"), {
1314
+ svg: `<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${i}" viewBox="0 0 ${r} ${i}">${o.join("")}</svg>`,
1315
+ W: r,
1316
+ H: i
1317
+ };
1318
+ }, [
1319
+ t,
1320
+ G,
1321
+ cr,
1322
+ yr,
1323
+ rr,
1324
+ wr,
1325
+ Cr,
1326
+ q,
1327
+ J,
1328
+ _n,
1329
+ R,
1330
+ F,
1331
+ lr,
1332
+ ur,
1333
+ mr,
1334
+ pr,
1335
+ dr,
1336
+ Q,
1337
+ L,
1338
+ ee,
1339
+ gr,
1340
+ hr,
1341
+ _r,
1342
+ vr,
1343
+ Tn,
1344
+ wn
1345
+ ]), Dr = e.useCallback(async () => {
1346
+ let e = Er();
1347
+ if (!e) return;
1348
+ let t = await Je(e.svg, e.W, e.H);
1349
+ t && t.toBlob((e) => {
1350
+ e && Ye(e, `gantt-${L}.png`);
1351
+ }, "image/png");
1352
+ }, [Er, L]), Or = e.useCallback(async () => {
1353
+ let e = Er();
1354
+ if (!e) return;
1355
+ let t = await Je(e.svg, e.W, e.H);
1356
+ t && Ye(Xe(Ze(t.toDataURL("image/jpeg", .92)), t.width, t.height), `gantt-${L}.pdf`);
1357
+ }, [Er, L]), [kr, Ar] = e.useState(!1), jr = e.useCallback(() => {
1358
+ let e = {
1359
+ viewMode: L,
1360
+ columnWidth: tt,
1361
+ taskListCollapsed: lt,
1362
+ taskListWidth: rt
1363
+ };
1364
+ se && et(se, e), ce?.(e), Ar(!0);
1365
+ }, [
1366
+ L,
1367
+ tt,
1368
+ lt,
1369
+ rt,
1370
+ se,
1371
+ ce
1372
+ ]);
1373
+ return e.useEffect(() => {
1374
+ if (!kr) return;
1375
+ let e = setTimeout(() => Ar(!1), 1500);
1376
+ return () => clearTimeout(e);
1377
+ }, [kr]), /* @__PURE__ */ O("div", {
1378
+ ref: fe,
1379
+ className: b("flex flex-col h-full bg-background overflow-hidden min-w-0", p),
1380
+ "data-readonly": j ? "true" : void 0,
1381
+ "data-mobile-readonly": ne && A ? "true" : void 0,
1382
+ children: [
1383
+ /* @__PURE__ */ D("style", { children: "\n .gantt-resize-handle:hover { background-color: rgba(255, 255, 255, 0.4); }\n .gantt-bar-hover:hover { filter: brightness(1.1); }\n .gantt-locate-btn { opacity: 0; transition: opacity 0.15s ease; }\n .group\\/task-row:hover .gantt-locate-btn { opacity: 0.6; }\n .gantt-locate-btn:hover, .gantt-locate-btn:focus-visible { opacity: 1; }\n /* 定位闪烁: blink the located bar 3× with a thick ring + colored glow so\n it's hard to miss. The ring is an outline (not box-shadow) and the glow\n is a drop-shadow *filter* — both stay clear of the critical-path bar's\n inline box-shadow, which they'd otherwise clobber. */\n @keyframes gantt-flash {\n 0%, 25%, 50%, 100% {\n outline-color: rgba(37, 99, 235, 0);\n filter: drop-shadow(0 0 0 rgba(37, 99, 235, 0));\n }\n 12%, 37%, 62% {\n outline-color: rgba(37, 99, 235, 1);\n filter: drop-shadow(0 0 9px rgba(37, 99, 235, 0.9));\n }\n }\n .gantt-flash {\n outline: 3px solid transparent;\n outline-offset: 3px;\n border-radius: 2px;\n animation: gantt-flash 1.5s ease-in-out;\n }\n @media (min-width: 640px) {\n .gantt-sm-h50 { height: 50px; }\n .gantt-sm-w20 { width: 80px; }\n .gantt-sm-hidden { display: none; }\n }\n /* Persistent, grabbable timeline scrollbars. macOS (and iOS) default to\n overlay scrollbars that collapse to 0px and auto-hide, so the\n timeline's vertical scrollbar was nearly impossible to find. Defining\n ::-webkit-scrollbar opts this pane into a classic, always-visible bar\n regardless of the OS overlay preference. The thumb gets a min size so\n that with thousands of virtualized rows (scrollHeight in the hundreds\n of thousands of px) it never shrinks to an un-grabbable sliver. Scoped\n to the gantt pane so the host app's own scrollbars are untouched, and\n themed with neutral rgba (not theme utilities, which don't always\n reach a consuming app) so it's visible on any background. */\n /* Firefox (and any engine without ::-webkit-scrollbar) only: the\n standard props. We must NOT set these unconditionally — modern Chrome\n now honors scrollbar-width and, when it's present, IGNORES the\n ::-webkit-scrollbar rule below, falling back to the 0px auto-hiding\n overlay bar we're trying to replace. */\n @supports not selector(::-webkit-scrollbar) {\n [data-testid=\"gantt-timeline\"] {\n scrollbar-width: thin;\n scrollbar-color: rgba(130,130,130,0.55) transparent;\n }\n }\n [data-testid=\"gantt-timeline\"]::-webkit-scrollbar {\n width: 14px;\n height: 14px;\n }\n [data-testid=\"gantt-timeline\"]::-webkit-scrollbar-track {\n background: transparent;\n }\n [data-testid=\"gantt-timeline\"]::-webkit-scrollbar-thumb {\n background-color: rgba(130,130,130,0.55);\n border-radius: 8px;\n border: 3px solid transparent;\n background-clip: padding-box;\n min-height: 40px;\n min-width: 40px;\n }\n [data-testid=\"gantt-timeline\"]::-webkit-scrollbar-thumb:hover {\n background-color: rgba(110,110,110,0.85);\n }\n [data-testid=\"gantt-timeline\"]::-webkit-scrollbar-corner {\n background: transparent;\n }\n /* The task-list pane scrolls in lockstep with the timeline, so its own\n vertical scrollbar (butted against the divider) was a confusing second\n bar. Hide it — the pane stays wheel/drag-scrollable and synced. */\n .gantt-task-list::-webkit-scrollbar { width: 0; height: 0; }\n .gantt-task-list { scrollbar-width: none; }\n " }),
1384
+ /* @__PURE__ */ O("div", {
1385
+ className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 p-2 border-b bg-card",
1386
+ children: [/* @__PURE__ */ O("div", {
1387
+ className: "flex items-center gap-2",
1388
+ children: [
1389
+ /* @__PURE__ */ D(y, {
1390
+ variant: "ghost",
1391
+ size: "icon",
1392
+ className: "h-8 w-8",
1393
+ "aria-label": x("gantt.toolbar.prevPeriod"),
1394
+ children: /* @__PURE__ */ D(he, { className: "h-4 w-4" })
1395
+ }),
1396
+ /* @__PURE__ */ D(y, {
1397
+ variant: "ghost",
1398
+ size: "icon",
1399
+ className: "h-8 w-8",
1400
+ "aria-label": x("gantt.toolbar.nextPeriod"),
1401
+ children: /* @__PURE__ */ D(C, { className: "h-4 w-4" })
1402
+ }),
1403
+ /* @__PURE__ */ D("span", {
1404
+ className: "font-semibold text-xs sm:text-sm",
1405
+ children: K.start.toLocaleDateString(S, {
1406
+ month: "long",
1407
+ year: "numeric"
1408
+ })
1409
+ }),
1410
+ j && /* @__PURE__ */ O("span", {
1411
+ className: "inline-flex items-center gap-1 rounded-full border bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
1412
+ "data-testid": "gantt-readonly-badge",
1413
+ title: x("gantt.readOnlyHint"),
1414
+ children: [/* @__PURE__ */ D(w, { className: "h-3 w-3" }), x("gantt.readOnly")]
197
1415
  })
198
- })
199
- ]
200
- }), /* @__PURE__ */ N("div", {
201
- className: "flex items-center gap-2",
202
- children: [
203
- /* @__PURE__ */ N("div", {
204
- className: "flex bg-muted rounded-md p-1",
205
- children: [/* @__PURE__ */ M(S, {
1416
+ ]
1417
+ }), /* @__PURE__ */ O("div", {
1418
+ className: "flex items-center gap-2",
1419
+ children: [
1420
+ /* @__PURE__ */ D("div", {
1421
+ className: "flex bg-muted rounded-md p-1",
1422
+ role: "group",
1423
+ "aria-label": x("gantt.toolbar.viewMode"),
1424
+ children: He.map((e) => /* @__PURE__ */ D(y, {
1425
+ variant: "ghost",
1426
+ size: "sm",
1427
+ className: b("h-6 px-1.5 sm:px-2 text-xs", L === e && "bg-background shadow-sm hover:bg-background"),
1428
+ onClick: () => xn(e),
1429
+ "aria-pressed": L === e,
1430
+ "data-testid": `gantt-view-mode-${e}`,
1431
+ children: x(`gantt.viewMode.${e}`)
1432
+ }, e))
1433
+ }),
1434
+ /* @__PURE__ */ O("div", {
1435
+ className: "flex bg-muted rounded-md p-1",
1436
+ children: [/* @__PURE__ */ D(y, {
1437
+ variant: "ghost",
1438
+ size: "icon",
1439
+ className: "h-6 w-6",
1440
+ onClick: () => {
1441
+ if (z > 15) nt(Math.max(15, z - 10));
1442
+ else {
1443
+ let e = He.indexOf(L);
1444
+ e < He.length - 1 && (xn(He[e + 1]), nt(Ie));
1445
+ }
1446
+ },
1447
+ "aria-label": x("gantt.toolbar.zoomOut"),
1448
+ children: /* @__PURE__ */ D(Ee, { className: "h-3 w-3" })
1449
+ }), /* @__PURE__ */ D(y, {
1450
+ variant: "ghost",
1451
+ size: "icon",
1452
+ className: "h-6 w-6",
1453
+ onClick: () => {
1454
+ if (z < 120) nt(Math.min(120, z + 10));
1455
+ else {
1456
+ let e = He.indexOf(L);
1457
+ e > 0 && (xn(He[e - 1]), nt(Ie));
1458
+ }
1459
+ },
1460
+ "aria-label": x("gantt.toolbar.zoomIn"),
1461
+ children: /* @__PURE__ */ D(Te, { className: "h-3 w-3" })
1462
+ })]
1463
+ }),
1464
+ /* @__PURE__ */ D(y, {
206
1465
  variant: "ghost",
207
1466
  size: "icon",
208
- className: "h-6 w-6",
209
- onClick: () => v(Math.max(15, y - 10)),
210
- "aria-label": c("gantt.toolbar.zoomOut"),
211
- children: /* @__PURE__ */ M(A, { className: "h-3 w-3" })
212
- }), /* @__PURE__ */ M(S, {
1467
+ className: "h-8 w-8",
1468
+ onClick: () => ut((e) => !e),
1469
+ "aria-label": x(lt ? "gantt.toolbar.showTaskList" : "gantt.toolbar.hideTaskList"),
1470
+ "aria-pressed": lt,
1471
+ "data-testid": "gantt-toggle-task-list",
1472
+ children: D(lt ? E : be, { className: "h-4 w-4" })
1473
+ }),
1474
+ /* @__PURE__ */ D(y, {
1475
+ variant: "ghost",
1476
+ size: "sm",
1477
+ className: "h-8 px-2 text-xs",
1478
+ onClick: Yn,
1479
+ disabled: Q == null,
1480
+ "aria-label": x("gantt.toolbar.jumpToToday"),
1481
+ "data-testid": "gantt-jump-today",
1482
+ children: x("gantt.toolbar.today")
1483
+ }),
1484
+ /* @__PURE__ */ D(y, {
1485
+ variant: "ghost",
1486
+ size: "sm",
1487
+ className: "h-8 px-2 text-xs",
1488
+ onClick: $n,
1489
+ "aria-label": x("gantt.toolbar.thisWeek"),
1490
+ "data-testid": "gantt-jump-week",
1491
+ children: x("gantt.toolbar.thisWeek")
1492
+ }),
1493
+ /* @__PURE__ */ D(y, {
1494
+ variant: "ghost",
1495
+ size: "sm",
1496
+ className: "h-8 px-2 text-xs",
1497
+ onClick: er,
1498
+ "aria-label": x("gantt.toolbar.thisMonth"),
1499
+ "data-testid": "gantt-jump-month",
1500
+ children: x("gantt.toolbar.thisMonth")
1501
+ }),
1502
+ M ? /* @__PURE__ */ O(De, { children: [/* @__PURE__ */ D(y, {
213
1503
  variant: "ghost",
214
1504
  size: "icon",
215
- className: "h-6 w-6",
216
- onClick: () => v(Math.min(120, y + 10)),
217
- "aria-label": c("gantt.toolbar.zoomIn"),
218
- children: /* @__PURE__ */ M(ne, { className: "h-3 w-3" })
219
- })]
220
- }),
221
- /* @__PURE__ */ M(S, {
222
- variant: "ghost",
223
- size: "icon",
224
- className: "h-8 w-8",
225
- onClick: () => x((e) => !e),
226
- "aria-label": c(b ? "gantt.toolbar.showTaskList" : "gantt.toolbar.hideTaskList"),
227
- "aria-pressed": b,
228
- "data-testid": "gantt-toggle-task-list",
229
- children: M(b ? te : k, { className: "h-4 w-4" })
1505
+ className: "h-8 w-8",
1506
+ onClick: zt,
1507
+ disabled: !Vt,
1508
+ "aria-label": x("gantt.toolbar.undo"),
1509
+ "data-testid": "gantt-undo",
1510
+ children: /* @__PURE__ */ D(Ce, { className: "h-4 w-4" })
1511
+ }), /* @__PURE__ */ D(y, {
1512
+ variant: "ghost",
1513
+ size: "icon",
1514
+ className: "h-8 w-8",
1515
+ onClick: Bt,
1516
+ disabled: !Ht,
1517
+ "aria-label": x("gantt.toolbar.redo"),
1518
+ "data-testid": "gantt-redo",
1519
+ children: /* @__PURE__ */ D(xe, { className: "h-4 w-4" })
1520
+ })] }) : null,
1521
+ /* @__PURE__ */ D(y, {
1522
+ variant: "ghost",
1523
+ size: "icon",
1524
+ className: "h-8 w-8",
1525
+ onClick: () => Sr((e) => !e),
1526
+ "aria-label": x("gantt.toolbar.criticalPath"),
1527
+ "aria-pressed": xr,
1528
+ "data-testid": "gantt-critical-path",
1529
+ style: xr ? { color: $ } : void 0,
1530
+ children: /* @__PURE__ */ D(pe, { className: "h-4 w-4" })
1531
+ }),
1532
+ Me && M ? /* @__PURE__ */ D(y, {
1533
+ variant: "ghost",
1534
+ size: "icon",
1535
+ className: "h-8 w-8",
1536
+ onClick: Tr,
1537
+ "aria-label": x("gantt.toolbar.autoSchedule"),
1538
+ "data-testid": "gantt-auto-schedule",
1539
+ children: /* @__PURE__ */ D(we, { className: "h-4 w-4" })
1540
+ }) : null,
1541
+ /* @__PURE__ */ D(y, {
1542
+ variant: "ghost",
1543
+ size: "icon",
1544
+ className: "h-8 w-8",
1545
+ onClick: Dr,
1546
+ "aria-label": x("gantt.toolbar.exportPng"),
1547
+ "data-testid": "gantt-export-png",
1548
+ children: /* @__PURE__ */ D(_e, { className: "h-4 w-4" })
1549
+ }),
1550
+ /* @__PURE__ */ D(y, {
1551
+ variant: "ghost",
1552
+ size: "icon",
1553
+ className: "h-8 w-8",
1554
+ onClick: Or,
1555
+ "aria-label": x("gantt.toolbar.exportPdf"),
1556
+ "data-testid": "gantt-export-pdf",
1557
+ children: /* @__PURE__ */ D(ve, { className: "h-4 w-4" })
1558
+ }),
1559
+ ce || se ? /* @__PURE__ */ D(y, {
1560
+ variant: "ghost",
1561
+ size: "icon",
1562
+ className: "h-8 w-8",
1563
+ onClick: jr,
1564
+ "aria-label": x("gantt.toolbar.saveLayout"),
1565
+ "aria-pressed": kr,
1566
+ "data-testid": "gantt-save-layout",
1567
+ style: kr ? { color: $ } : void 0,
1568
+ children: /* @__PURE__ */ D(Se, { className: "h-4 w-4" })
1569
+ }) : null,
1570
+ /* @__PURE__ */ D(y, {
1571
+ variant: "ghost",
1572
+ size: "icon",
1573
+ className: "h-8 w-8",
1574
+ onClick: Wn,
1575
+ "aria-label": x(Hn ? "gantt.toolbar.exitFullscreen" : "gantt.toolbar.enterFullscreen"),
1576
+ "aria-pressed": Hn,
1577
+ "data-testid": "gantt-fullscreen",
1578
+ children: D(Hn ? ye : T, { className: "h-4 w-4" })
1579
+ })
1580
+ ]
1581
+ })]
1582
+ }),
1583
+ /* @__PURE__ */ O("div", {
1584
+ className: "relative flex flex-col flex-1 overflow-hidden outline-none focus-visible:ring-1 focus-visible:ring-ring",
1585
+ tabIndex: 0,
1586
+ onKeyDown: mn,
1587
+ "data-testid": "gantt-body",
1588
+ children: [
1589
+ !lt && R > 0 && /* @__PURE__ */ D("div", {
1590
+ className: "absolute top-0 bottom-0 z-30 group/splitter",
1591
+ style: {
1592
+ left: R - 3,
1593
+ width: 7,
1594
+ cursor: "col-resize"
1595
+ },
1596
+ "data-testid": "gantt-list-resize",
1597
+ role: "separator",
1598
+ "aria-orientation": "vertical",
1599
+ onPointerDown: (e) => {
1600
+ if (e.button !== 0) return;
1601
+ e.preventDefault();
1602
+ let t = e.clientX, n = R, r = Math.max(160, k - 200), i = (e) => {
1603
+ it(Math.max(160, Math.min(n + (e.clientX - t), r)));
1604
+ }, a = () => {
1605
+ window.removeEventListener("pointermove", i), window.removeEventListener("pointerup", a), window.removeEventListener("pointercancel", a), document.body.style.cursor = "";
1606
+ };
1607
+ document.body.style.cursor = "col-resize", window.addEventListener("pointermove", i), window.addEventListener("pointerup", a), window.addEventListener("pointercancel", a);
1608
+ },
1609
+ onDoubleClick: () => it(null),
1610
+ children: /* @__PURE__ */ D("div", { className: "absolute inset-y-0 left-1/2 -translate-x-1/2 w-px bg-border group-hover/splitter:w-[3px] group-hover/splitter:bg-primary transition-all" })
230
1611
  }),
231
- /* @__PURE__ */ M(S, {
232
- variant: "ghost",
233
- size: "icon",
234
- className: "h-8 w-8",
235
- onClick: ue,
236
- disabled: $ == null,
237
- "aria-label": c("gantt.toolbar.jumpToToday"),
238
- "data-testid": "gantt-jump-today",
239
- children: /* @__PURE__ */ M(ee, { className: "h-4 w-4" })
240
- })
241
- ]
242
- })]
243
- }), /* @__PURE__ */ N("div", {
244
- className: "flex flex-col flex-1 overflow-hidden",
245
- children: [/* @__PURE__ */ N("div", {
246
- className: "flex border-b bg-muted/30 shrink-0 h-10 sm:h-[50px]",
247
- children: [/* @__PURE__ */ N("div", {
248
- className: "flex items-center font-medium text-xs text-muted-foreground px-2 sm:px-4 border-r bg-card z-20 shadow-sm",
249
- style: {
250
- width: E,
251
- minWidth: E
252
- },
253
- children: [/* @__PURE__ */ M("div", {
254
- className: "flex-1 truncate",
255
- children: c("gantt.column.taskName")
256
- }), P && /* @__PURE__ */ N(j, { children: [/* @__PURE__ */ M("div", {
257
- className: "w-16 sm:w-20 text-right",
258
- children: c("gantt.column.start")
259
- }), /* @__PURE__ */ M("div", {
260
- className: "w-16 sm:w-20 text-right",
261
- children: c("gantt.column.end")
262
- })] })]
263
- }), /* @__PURE__ */ M("div", {
264
- className: "flex-1 overflow-hidden",
265
- ref: Y,
266
- children: /* @__PURE__ */ M("div", {
267
- className: "flex h-full",
268
- style: { width: J.length * y },
269
- children: J.map((e, t) => /* @__PURE__ */ N("div", {
270
- className: C("flex flex-col items-center justify-center border-r text-xs text-muted-foreground h-full", e.isWeekend && "bg-muted/50"),
1612
+ /* @__PURE__ */ O("div", {
1613
+ className: "flex border-b bg-muted/30 shrink-0 h-10 gantt-sm-h50",
1614
+ children: [/* @__PURE__ */ O("div", {
1615
+ className: "flex items-center font-medium text-xs text-muted-foreground px-2 sm:px-4 border-r bg-card z-20 shadow-sm",
271
1616
  style: {
272
- width: y,
273
- minWidth: y
1617
+ width: R,
1618
+ minWidth: R
274
1619
  },
275
- children: [/* @__PURE__ */ M("span", {
276
- className: "font-medium text-foreground",
277
- children: e.label
278
- }), /* @__PURE__ */ M("span", {
279
- className: "text-[10px] opacity-70",
280
- children: e.date.toLocaleDateString(void 0, { weekday: "narrow" })
281
- })]
282
- }, t))
283
- })
284
- })]
285
- }), /* @__PURE__ */ N("div", {
286
- className: "flex flex-1 overflow-hidden",
287
- children: [/* @__PURE__ */ M("div", {
288
- className: "overflow-hidden border-r bg-card z-10 shadow-sm",
289
- ref: X,
290
- style: {
291
- width: E,
292
- minWidth: E
293
- },
294
- children: t.map((e) => {
295
- let t = s && F === e.id;
296
- return /* @__PURE__ */ N("div", {
297
- className: "group/task-row flex items-center border-b px-2 sm:px-4 hover:bg-accent/50 cursor-pointer transition-colors touch-manipulation",
298
- style: { height: h },
299
- onClick: () => !t && i?.(e),
300
- onDoubleClick: () => {
301
- s && a && (I(e.id), B({
302
- title: e.title,
303
- start: e.start.toLocaleDateString("en-CA"),
304
- end: e.end.toLocaleDateString("en-CA"),
305
- progress: String(e.progress)
306
- }));
1620
+ children: [/* @__PURE__ */ D("div", {
1621
+ className: "flex-1 truncate",
1622
+ children: x("gantt.column.taskName")
1623
+ }), ht && /* @__PURE__ */ O(De, { children: [/* @__PURE__ */ D("div", {
1624
+ className: "w-16 gantt-sm-w20 text-right",
1625
+ children: x("gantt.column.start")
1626
+ }), /* @__PURE__ */ D("div", {
1627
+ className: "w-16 gantt-sm-w20 text-right",
1628
+ children: x("gantt.column.end")
1629
+ })] })]
1630
+ }), /* @__PURE__ */ D("div", {
1631
+ className: "flex-1 overflow-hidden",
1632
+ ref: En,
1633
+ children: /* @__PURE__ */ O("div", {
1634
+ className: "flex flex-col h-full",
1635
+ style: { width: _n },
1636
+ children: [/* @__PURE__ */ D("div", {
1637
+ className: "relative border-b",
1638
+ style: { height: "45%" },
1639
+ "data-testid": "gantt-header-groups",
1640
+ children: wn.slice(Bn.start, Bn.end).map((e) => /* @__PURE__ */ D("div", {
1641
+ className: "absolute top-0 bottom-0 flex items-center justify-center border-r text-[10px] font-medium text-muted-foreground overflow-hidden",
1642
+ style: {
1643
+ left: e.offset,
1644
+ width: e.width
1645
+ },
1646
+ children: /* @__PURE__ */ D("span", {
1647
+ className: "truncate px-1",
1648
+ children: e.label
1649
+ })
1650
+ }, e.key))
1651
+ }), /* @__PURE__ */ D("div", {
1652
+ className: "relative flex-1",
1653
+ "data-testid": "gantt-header-units",
1654
+ children: q.slice(Rn.start, Rn.end).map((e, t) => {
1655
+ let n = Rn.start + t;
1656
+ return /* @__PURE__ */ O("div", {
1657
+ className: b("absolute top-0 bottom-0 flex items-center justify-center gap-1 border-r text-xs text-muted-foreground overflow-hidden", e.isWeekend && "bg-muted/50"),
1658
+ style: {
1659
+ left: J[n],
1660
+ width: e.width
1661
+ },
1662
+ children: [/* @__PURE__ */ D("span", {
1663
+ className: "font-medium text-foreground truncate",
1664
+ children: e.label
1665
+ }), e.sublabel && z >= 32 && /* @__PURE__ */ D("span", {
1666
+ className: "text-[10px] opacity-70",
1667
+ children: e.sublabel
1668
+ })]
1669
+ }, n);
1670
+ })
1671
+ })]
1672
+ })
1673
+ })]
1674
+ }),
1675
+ /* @__PURE__ */ O("div", {
1676
+ className: "flex flex-1 overflow-hidden",
1677
+ children: [/* @__PURE__ */ O("div", {
1678
+ className: "gantt-task-list overflow-y-auto overflow-x-hidden border-r bg-card z-10 shadow-sm",
1679
+ ref: Dn,
1680
+ onScroll: nr,
1681
+ style: {
1682
+ width: R,
1683
+ minWidth: R
307
1684
  },
1685
+ role: "tree",
1686
+ "aria-label": x("gantt.aria.taskList"),
308
1687
  children: [
309
- /* @__PURE__ */ N("div", {
310
- className: "flex-1 truncate font-medium text-xs sm:text-sm flex items-center gap-2",
311
- children: [/* @__PURE__ */ M("div", {
312
- className: "w-2 h-2 rounded-full shrink-0",
313
- style: { backgroundColor: e.color || "#3b82f6" }
314
- }), t ? /* @__PURE__ */ M("input", {
315
- className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
316
- value: z.title || "",
317
- onChange: (e) => B((t) => ({
318
- ...t,
319
- title: e.target.value
320
- })),
321
- onKeyDown: (t) => {
322
- t.key === "Enter" ? (a?.(e, {
323
- title: z.title,
324
- start: new Date(z.start),
325
- end: new Date(z.end),
326
- progress: Number(z.progress) || 0
327
- }), I(null)) : t.key === "Escape" && I(null);
1688
+ Z.startIdx > 0 && /* @__PURE__ */ D("div", {
1689
+ style: { height: Z.startIdx * F },
1690
+ "aria-hidden": "true"
1691
+ }),
1692
+ G.slice(Z.startIdx, Z.endIdx).map((e) => {
1693
+ let t = e.task, n = je && gt === t.id, r = un.has(String(t.id)), i = an != null && String(an) === String(t.id);
1694
+ return /* @__PURE__ */ O("div", {
1695
+ className: b("group/task-row relative flex items-center border-b px-2 sm:px-4 hover:bg-accent/50 cursor-pointer transition-colors", i && "bg-accent/50"),
1696
+ style: {
1697
+ height: F,
1698
+ touchAction: "manipulation"
1699
+ },
1700
+ role: "treeitem",
1701
+ "aria-level": e.depth + 1,
1702
+ "aria-selected": i,
1703
+ "aria-expanded": e.hasChildren ? !r : void 0,
1704
+ draggable: !!P && !n && !t.locked,
1705
+ onDragStart: P ? (e) => {
1706
+ e.dataTransfer.setData("text/plain", String(t.id)), e.dataTransfer.effectAllowed = "move";
1707
+ } : void 0,
1708
+ onDragOver: P ? (e) => {
1709
+ e.preventDefault(), e.dataTransfer.dropEffect = "move";
1710
+ } : void 0,
1711
+ onDrop: P ? (e) => {
1712
+ e.preventDefault();
1713
+ let n = e.dataTransfer.getData("text/plain");
1714
+ if (!n || n === String(t.id)) return;
1715
+ let r = Ct.get(n);
1716
+ r && String(r.parent ?? "") === String(t.parent ?? "") && P(r, t);
1717
+ } : void 0,
1718
+ onContextMenu: (e) => cn(t, e),
1719
+ onClick: () => {
1720
+ on(t.id), n || o?.(t);
328
1721
  },
329
- onClick: (e) => e.stopPropagation(),
330
- autoFocus: !0
331
- }) : /* @__PURE__ */ N("span", {
332
- className: "flex flex-col min-w-0",
333
- children: [/* @__PURE__ */ M("span", {
334
- className: "truncate",
335
- children: e.title
336
- }), /* @__PURE__ */ N("span", {
337
- className: "text-[10px] text-muted-foreground sm:hidden",
338
- children: [
339
- e.start.toLocaleDateString(void 0, {
1722
+ onDoubleClick: () => {
1723
+ je && M && !e.isSummary && !t.locked && (_t(t.id), yt({
1724
+ title: t.title,
1725
+ start: t.start.toLocaleDateString("en-CA"),
1726
+ end: t.end.toLocaleDateString("en-CA"),
1727
+ progress: String(t.progress)
1728
+ }));
1729
+ },
1730
+ children: [
1731
+ /* @__PURE__ */ O("div", {
1732
+ className: "flex-1 truncate font-medium text-xs sm:text-sm flex items-center gap-2",
1733
+ style: e.depth > 0 ? { paddingLeft: e.depth * 14 } : void 0,
1734
+ children: [
1735
+ e.hasChildren ? /* @__PURE__ */ D("button", {
1736
+ type: "button",
1737
+ className: "h-4 w-4 shrink-0 flex items-center justify-center text-muted-foreground hover:text-foreground",
1738
+ style: { marginLeft: -4 },
1739
+ onClick: (e) => {
1740
+ e.stopPropagation(), fn(t.id);
1741
+ },
1742
+ "aria-expanded": !r,
1743
+ "aria-label": x(r ? "gantt.row.expand" : "gantt.row.collapse"),
1744
+ "data-testid": `gantt-row-toggle-${t.id}`,
1745
+ children: D(r ? C : me, { className: "h-3.5 w-3.5" })
1746
+ }) : /* @__PURE__ */ D("span", {
1747
+ className: "w-3 shrink-0",
1748
+ style: { marginLeft: -4 },
1749
+ "aria-hidden": "true"
1750
+ }),
1751
+ /* @__PURE__ */ D("div", {
1752
+ className: "w-2 h-2 rounded-full shrink-0",
1753
+ style: { backgroundColor: t.color || "#3b82f6" }
1754
+ }),
1755
+ n ? /* @__PURE__ */ D("input", {
1756
+ className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
1757
+ value: vt.title || "",
1758
+ onChange: (e) => yt((t) => ({
1759
+ ...t,
1760
+ title: e.target.value
1761
+ })),
1762
+ onKeyDown: (e) => {
1763
+ e.key === "Enter" ? (H([{
1764
+ task: t,
1765
+ changes: {
1766
+ title: vt.title,
1767
+ start: new Date(vt.start),
1768
+ end: new Date(vt.end),
1769
+ progress: Number(vt.progress) || 0
1770
+ }
1771
+ }]), _t(null)) : e.key === "Escape" && _t(null);
1772
+ },
1773
+ onClick: (e) => e.stopPropagation(),
1774
+ autoFocus: !0
1775
+ }) : /* @__PURE__ */ O("span", {
1776
+ className: "flex flex-col min-w-0",
1777
+ children: [/* @__PURE__ */ D("span", {
1778
+ className: b("truncate", e.isSummary && "font-semibold"),
1779
+ children: t.title
1780
+ }), /* @__PURE__ */ O("span", {
1781
+ className: "text-[10px] text-muted-foreground gantt-sm-hidden",
1782
+ children: [
1783
+ e.start.toLocaleDateString(S, {
1784
+ month: "numeric",
1785
+ day: "numeric"
1786
+ }),
1787
+ " → ",
1788
+ e.end.toLocaleDateString(S, {
1789
+ month: "numeric",
1790
+ day: "numeric"
1791
+ })
1792
+ ]
1793
+ })]
1794
+ })
1795
+ ]
1796
+ }),
1797
+ /* @__PURE__ */ D("div", {
1798
+ className: "w-16 gantt-sm-w20 text-right text-xs text-muted-foreground hidden sm:block",
1799
+ hidden: !ht,
1800
+ style: ht ? void 0 : { display: "none" },
1801
+ children: n ? /* @__PURE__ */ D("input", {
1802
+ type: "date",
1803
+ className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
1804
+ value: vt.start || "",
1805
+ onChange: (e) => yt((t) => ({
1806
+ ...t,
1807
+ start: e.target.value
1808
+ })),
1809
+ onClick: (e) => e.stopPropagation()
1810
+ }) : e.start.toLocaleDateString(S, {
340
1811
  month: "numeric",
341
1812
  day: "numeric"
342
- }),
343
- " → ",
344
- e.end.toLocaleDateString(void 0, {
1813
+ })
1814
+ }),
1815
+ /* @__PURE__ */ D("div", {
1816
+ className: "w-16 gantt-sm-w20 text-right text-xs text-muted-foreground hidden sm:block",
1817
+ hidden: !ht,
1818
+ style: ht ? void 0 : { display: "none" },
1819
+ children: n ? /* @__PURE__ */ D("input", {
1820
+ type: "date",
1821
+ className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
1822
+ value: vt.end || "",
1823
+ onChange: (e) => yt((t) => ({
1824
+ ...t,
1825
+ end: e.target.value
1826
+ })),
1827
+ onClick: (e) => e.stopPropagation()
1828
+ }) : e.end.toLocaleDateString(S, {
345
1829
  month: "numeric",
346
1830
  day: "numeric"
347
1831
  })
348
- ]
349
- })]
350
- })]
1832
+ }),
1833
+ !n && /* @__PURE__ */ D("button", {
1834
+ type: "button",
1835
+ title: x("gantt.row.locate"),
1836
+ "aria-label": x("gantt.row.locate"),
1837
+ className: "gantt-locate-btn hidden sm:block absolute top-1/2 -translate-y-1/2",
1838
+ style: { right: 1 },
1839
+ onClick: (t) => {
1840
+ t.stopPropagation(), Qn(e.start, e.end, e.task.id);
1841
+ },
1842
+ children: /* @__PURE__ */ D(ge, { className: "w-3 h-3" })
1843
+ })
1844
+ ]
1845
+ }, t.id);
351
1846
  }),
352
- /* @__PURE__ */ M("div", {
353
- className: "w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block",
354
- hidden: !P,
355
- style: P ? void 0 : { display: "none" },
356
- children: t ? /* @__PURE__ */ M("input", {
357
- type: "date",
358
- className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
359
- value: z.start || "",
360
- onChange: (e) => B((t) => ({
361
- ...t,
362
- start: e.target.value
363
- })),
364
- onClick: (e) => e.stopPropagation()
365
- }) : e.start.toLocaleDateString(void 0, {
366
- month: "numeric",
367
- day: "numeric"
368
- })
369
- }),
370
- /* @__PURE__ */ M("div", {
371
- className: "w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block",
372
- hidden: !P,
373
- style: P ? void 0 : { display: "none" },
374
- children: t ? /* @__PURE__ */ M("input", {
375
- type: "date",
376
- className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
377
- value: z.end || "",
378
- onChange: (e) => B((t) => ({
379
- ...t,
380
- end: e.target.value
381
- })),
382
- onClick: (e) => e.stopPropagation()
383
- }) : e.end.toLocaleDateString(void 0, {
384
- month: "numeric",
385
- day: "numeric"
386
- })
1847
+ Z.endIdx < G.length && /* @__PURE__ */ D("div", {
1848
+ style: { height: (G.length - Z.endIdx) * F },
1849
+ "aria-hidden": "true"
387
1850
  })
388
1851
  ]
389
- }, e.id);
390
- })
391
- }), /* @__PURE__ */ M("div", {
392
- className: "flex-1 overflow-auto bg-background/50 relative [-webkit-overflow-scrolling:touch]",
393
- ref: (e) => {
394
- oe.current = e, Z.current = e;
395
- },
396
- onScroll: de,
397
- onTouchStart: se,
398
- onTouchMove: ce,
399
- onTouchEnd: le,
400
- "data-testid": "gantt-timeline",
401
- children: /* @__PURE__ */ N("div", {
402
- className: "relative",
403
- style: { width: J.length * y },
404
- children: [$ != null && /* @__PURE__ */ M("div", {
405
- className: "absolute top-0 bottom-0 w-px bg-red-500/80 z-20 pointer-events-none",
406
- style: { left: $ },
407
- "data-testid": "gantt-today-marker",
408
- "aria-label": c("gantt.toolbar.today"),
409
- children: /* @__PURE__ */ M("div", {
410
- className: "absolute -top-2 -translate-x-1/2 left-0 text-[10px] font-semibold text-white bg-red-500 rounded-sm px-1 py-0.5 whitespace-nowrap",
411
- children: c("gantt.toolbar.today")
412
- })
413
- }), /* @__PURE__ */ N("div", {
414
- className: "relative",
415
- children: [
416
- /* @__PURE__ */ M("div", {
417
- className: "absolute inset-0 flex pointer-events-none z-0",
418
- children: J.map((e, t) => /* @__PURE__ */ M("div", {
419
- className: C("border-r h-full", e.isWeekend && "bg-muted/20"),
1852
+ }), /* @__PURE__ */ D("div", {
1853
+ className: "flex-1 overflow-auto bg-background/50 relative [-webkit-overflow-scrolling:touch]",
1854
+ ref: (e) => {
1855
+ On.current = e, X.current = e;
1856
+ },
1857
+ onScroll: tr,
1858
+ onTouchStart: Kn,
1859
+ onTouchMove: qn,
1860
+ onTouchEnd: Jn,
1861
+ "data-testid": "gantt-timeline",
1862
+ children: /* @__PURE__ */ O("div", {
1863
+ className: "relative",
1864
+ style: { width: _n },
1865
+ children: [
1866
+ Q != null && /* @__PURE__ */ D("div", {
1867
+ className: "absolute top-0 bottom-0 w-px z-20 pointer-events-none",
420
1868
  style: {
421
- width: y,
422
- minWidth: y
423
- }
424
- }, t))
425
- }),
426
- t.map((e) => {
427
- let t = fe(e), n = V?.taskId === e.id, r = t;
428
- if (n && V) {
429
- let t = G(V);
430
- r = fe({
431
- ...e,
432
- start: t.start,
433
- end: t.end
434
- });
435
- }
436
- let o = !!a;
437
- return /* @__PURE__ */ N("div", {
438
- className: "relative border-b hover:bg-black/5",
439
- style: { height: h },
440
- children: [n && /* @__PURE__ */ M("div", {
441
- className: "absolute top-1 sm:top-2 h-[calc(100%-8px)] sm:h-[calc(100%-16px)] rounded-sm border border-dashed border-primary/60 pointer-events-none",
1869
+ left: Q,
1870
+ backgroundColor: "rgba(239, 68, 68, 0.8)"
1871
+ },
1872
+ "data-testid": "gantt-today-marker",
1873
+ "aria-label": x("gantt.toolbar.today"),
1874
+ children: /* @__PURE__ */ D("div", {
1875
+ className: "absolute -translate-x-1/2 left-0 text-[10px] font-semibold text-white rounded-sm px-1 py-0.5 whitespace-nowrap z-30",
442
1876
  style: {
443
- left: t.left,
444
- width: t.width,
445
- opacity: .35
1877
+ top: 2,
1878
+ backgroundColor: "#ef4444"
446
1879
  },
447
- "aria-hidden": "true"
448
- }), /* @__PURE__ */ N("div", {
449
- className: C("absolute top-1 sm:top-2 h-[calc(100%-8px)] sm:h-[calc(100%-16px)] rounded-sm bg-primary border border-primary-foreground/20 shadow-sm hover:brightness-110 flex items-center px-2 group select-none", o ? "cursor-grab active:cursor-grabbing" : "cursor-pointer", n && "ring-2 ring-primary/60 brightness-110 z-10"),
1880
+ children: x("gantt.toolbar.today")
1881
+ })
1882
+ }),
1883
+ Tn.map((e) => /* @__PURE__ */ D("div", {
1884
+ className: "absolute top-0 bottom-0 w-px z-20 pointer-events-none",
1885
+ style: {
1886
+ left: e.left,
1887
+ backgroundColor: e.color
1888
+ },
1889
+ "data-testid": `gantt-marker-${e.index}`,
1890
+ "aria-label": e.label,
1891
+ children: e.label && /* @__PURE__ */ D("div", {
1892
+ className: "absolute -translate-x-1/2 left-0 text-[10px] font-semibold text-white rounded-sm px-1 py-0.5 whitespace-nowrap z-30",
450
1893
  style: {
451
- left: r.left,
452
- width: r.width,
453
- backgroundColor: e.color || "#3b82f6"
1894
+ top: 2,
1895
+ backgroundColor: e.color
454
1896
  },
455
- "data-testid": `gantt-task-bar-${e.id}`,
456
- onClick: () => {
457
- W.current || i?.(e);
458
- },
459
- onPointerDown: o ? (t) => {
460
- t.button === 0 && K(e, "move", t);
461
- } : void 0,
462
- children: [
463
- o && r.width >= 14 && /* @__PURE__ */ N(j, { children: [/* @__PURE__ */ M("div", {
464
- className: "absolute left-0 top-0 bottom-0 w-1.5 cursor-ew-resize hover:bg-white/40",
465
- "data-testid": `gantt-task-resize-left-${e.id}`,
466
- onPointerDown: (t) => {
467
- t.button === 0 && K(e, "resize-left", t);
1897
+ children: e.label
1898
+ })
1899
+ }, e.index)),
1900
+ /* @__PURE__ */ O("div", {
1901
+ className: "relative",
1902
+ ref: qt,
1903
+ children: [
1904
+ /* @__PURE__ */ D("div", {
1905
+ className: "absolute inset-0 pointer-events-none",
1906
+ style: { zIndex: 0 },
1907
+ children: q.slice(Rn.start, Rn.end).map((e, t) => {
1908
+ let n = Rn.start + t;
1909
+ return /* @__PURE__ */ D("div", {
1910
+ className: "absolute top-0 bottom-0 border-r",
1911
+ style: {
1912
+ left: J[n],
1913
+ width: e.width,
1914
+ backgroundColor: e.isWeekend ? "hsl(var(--muted) / 0.4)" : void 0
1915
+ }
1916
+ }, n);
1917
+ })
1918
+ }),
1919
+ Z.startIdx > 0 && /* @__PURE__ */ D("div", {
1920
+ style: { height: Z.startIdx * F },
1921
+ "aria-hidden": "true"
1922
+ }),
1923
+ G.slice(Z.startIdx, Z.endIdx).map((t) => {
1924
+ let n = t.task, r = wr(n.id), i = rr(t.start, t.end), a = ee && n.baselineStart && n.baselineEnd ? rr(n.baselineStart, n.baselineEnd) : null, s = a ? /* @__PURE__ */ D("div", {
1925
+ className: "absolute pointer-events-none rounded-[1px]",
1926
+ style: {
1927
+ left: a.left,
1928
+ width: Math.max(2, a.width),
1929
+ top: gr,
1930
+ height: hr,
1931
+ backgroundColor: _r,
1932
+ border: `1px solid ${vr}`
468
1933
  },
469
- onClick: (e) => e.stopPropagation()
470
- }), /* @__PURE__ */ M("div", {
471
- className: "absolute right-0 top-0 bottom-0 w-1.5 cursor-ew-resize hover:bg-white/40",
472
- "data-testid": `gantt-task-resize-right-${e.id}`,
473
- onPointerDown: (t) => {
474
- t.button === 0 && K(e, "resize-right", t);
1934
+ "data-testid": `gantt-baseline-${n.id}`,
1935
+ "aria-hidden": "true"
1936
+ }) : null, c = V?.taskId === n.id, l = ar?.has(String(n.id)) ?? !1, u = or?.has(String(n.id)) ?? !1, d = c || l || u ? sr(t) : i, f = !!n.locked, p = !!M && !t.isSummary && !f, m = U != null && U.targetId != null && String(U.targetId) === String(n.id) && String(U.sourceId) !== String(n.id), h = U ? (e) => {
1937
+ let t = e.currentTarget.getBoundingClientRect(), r = t.width > 0 && e.clientX - t.left > t.width / 2 ? "end" : "start";
1938
+ Jt((e) => e && String(e.sourceId) !== String(n.id) ? {
1939
+ ...e,
1940
+ targetId: n.id,
1941
+ targetEnd: r
1942
+ } : e);
1943
+ } : void 0, g = U ? (e) => {
1944
+ e.target === e.currentTarget && Jt((e) => e && {
1945
+ ...e,
1946
+ targetId: null,
1947
+ targetEnd: null
1948
+ });
1949
+ } : void 0, _ = Math.max(1, Math.round((t.end.getTime() - t.start.getTime()) / We)), v = bt === n.id && !V && !Wt && !U ? /* @__PURE__ */ O("div", {
1950
+ className: "absolute z-30 pointer-events-none rounded-md border bg-popover text-popover-foreground px-2.5 py-1.5 text-xs shadow-md whitespace-nowrap",
1951
+ style: {
1952
+ left: Math.max(d.left + 8, 4),
1953
+ top: F - 8
475
1954
  },
476
- onClick: (e) => e.stopPropagation()
477
- })] }),
478
- e.progress > 0 && /* @__PURE__ */ M("div", {
479
- className: "absolute left-0 top-0 bottom-0 bg-black/20 rounded-l-sm pointer-events-none",
480
- style: { width: `${e.progress}%` }
481
- }),
482
- /* @__PURE__ */ M("span", {
483
- className: "text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none",
484
- children: n ? `${G(V).start.toLocaleDateString(void 0, {
485
- month: "numeric",
486
- day: "numeric"
487
- })} → ${G(V).end.toLocaleDateString(void 0, {
488
- month: "numeric",
489
- day: "numeric"
490
- })}` : `${Math.round(e.progress)}%`
491
- })
492
- ]
493
- })]
494
- }, e.id);
495
- }),
496
- /* @__PURE__ */ M("div", {
497
- className: "absolute top-0 bottom-0 w-px bg-red-500 z-20 pointer-events-none",
498
- style: { left: ((/* @__PURE__ */ new Date()).getTime() - q.start.getTime()) / (1e3 * 60 * 60 * 24) * y },
499
- children: /* @__PURE__ */ M("div", { className: "w-2 h-2 rounded-full bg-red-500 -ml-[3px]" })
500
- })
501
- ]
1955
+ role: "tooltip",
1956
+ "data-testid": `gantt-tooltip-${n.id}`,
1957
+ children: [/* @__PURE__ */ D("div", {
1958
+ className: "font-semibold",
1959
+ children: n.title
1960
+ }), n.fields && n.fields.length > 0 ? /* @__PURE__ */ D("div", {
1961
+ style: {
1962
+ display: "grid",
1963
+ gridTemplateColumns: "auto 1fr",
1964
+ columnGap: 10,
1965
+ rowGap: 2,
1966
+ marginTop: 4
1967
+ },
1968
+ children: n.fields.map((t, n) => /* @__PURE__ */ O(e.Fragment, { children: [/* @__PURE__ */ D("span", {
1969
+ className: "text-muted-foreground",
1970
+ children: t.label
1971
+ }), /* @__PURE__ */ D("span", {
1972
+ style: { fontWeight: 500 },
1973
+ children: t.value
1974
+ })] }, n))
1975
+ }) : /* @__PURE__ */ O("div", {
1976
+ className: "text-muted-foreground",
1977
+ children: [
1978
+ t.start.toLocaleDateString(S, {
1979
+ month: "short",
1980
+ day: "numeric"
1981
+ }),
1982
+ " → ",
1983
+ t.end.toLocaleDateString(S, {
1984
+ month: "short",
1985
+ day: "numeric"
1986
+ }),
1987
+ " · ",
1988
+ _,
1989
+ x("gantt.tooltip.days"),
1990
+ " · ",
1991
+ Math.round(t.progress),
1992
+ "%"
1993
+ ]
1994
+ })]
1995
+ }) : null;
1996
+ if (n.type === "group") return /* @__PURE__ */ D("div", {
1997
+ className: "relative border-b hover:bg-accent/50",
1998
+ style: { height: F },
1999
+ onPointerMove: g,
2000
+ children: v
2001
+ }, n.id);
2002
+ if (t.isSummary) {
2003
+ let e = n.color || "#0d9488";
2004
+ return /* @__PURE__ */ O("div", {
2005
+ className: "relative border-b hover:bg-accent/50",
2006
+ style: { height: F },
2007
+ onPointerMove: g,
2008
+ children: [
2009
+ s,
2010
+ /* @__PURE__ */ O("div", {
2011
+ className: b("gantt-bar-hover absolute rounded-sm border shadow-sm flex items-center px-2 select-none", M ? "cursor-grab active:cursor-grabbing" : "cursor-pointer", c && "ring-2 ring-primary z-10", kn === n.id && "gantt-flash z-10"),
2012
+ style: {
2013
+ left: d.left,
2014
+ width: d.width,
2015
+ top: mr,
2016
+ height: pr,
2017
+ backgroundColor: e,
2018
+ borderColor: r ? $ : "hsl(var(--primary-foreground) / 0.2)",
2019
+ boxShadow: r ? `0 0 0 2px ${$}` : void 0
2020
+ },
2021
+ "data-critical": r ? "true" : void 0,
2022
+ "data-testid": `gantt-summary-bar-${n.id}`,
2023
+ "data-progress": Math.round(t.progress),
2024
+ onMouseEnter: () => xt(n.id),
2025
+ onMouseLeave: () => xt((e) => e === n.id ? null : e),
2026
+ onPointerDown: (e) => {
2027
+ e.button === 0 && Ut(n, "move", e, {
2028
+ group: !0,
2029
+ originStart: t.start,
2030
+ originEnd: t.end
2031
+ });
2032
+ },
2033
+ onClick: () => {
2034
+ Dt.current || o?.(n);
2035
+ },
2036
+ onContextMenu: (e) => cn(n, e),
2037
+ children: [/* @__PURE__ */ D("div", {
2038
+ className: "absolute left-0 top-0 bottom-0 pointer-events-none",
2039
+ style: {
2040
+ width: `${Math.round(t.progress)}%`,
2041
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
2042
+ borderTopLeftRadius: "var(--radius-sm)",
2043
+ borderBottomLeftRadius: "var(--radius-sm)"
2044
+ }
2045
+ }), /* @__PURE__ */ D("span", {
2046
+ className: "relative text-[10px] text-white font-medium truncate pointer-events-none",
2047
+ children: n.title
2048
+ })]
2049
+ }),
2050
+ c && V && /* @__PURE__ */ O("div", {
2051
+ className: "absolute z-30 pointer-events-none rounded border bg-popover text-popover-foreground px-1.5 py-0.5 text-[10px] shadow whitespace-nowrap",
2052
+ style: {
2053
+ left: Math.max(d.left, 4),
2054
+ top: mr + pr + 2
2055
+ },
2056
+ "data-testid": `gantt-summary-drag-chip-${n.id}`,
2057
+ children: [
2058
+ Ot(V).start.toLocaleDateString(S, {
2059
+ month: "numeric",
2060
+ day: "numeric"
2061
+ }),
2062
+ " → ",
2063
+ Ot(V).end.toLocaleDateString(S, {
2064
+ month: "numeric",
2065
+ day: "numeric"
2066
+ })
2067
+ ]
2068
+ }),
2069
+ v
2070
+ ]
2071
+ }, n.id);
2072
+ }
2073
+ if (t.isMilestone) {
2074
+ let e = dr;
2075
+ return /* @__PURE__ */ O("div", {
2076
+ className: "relative border-b hover:bg-accent/50",
2077
+ style: { height: F },
2078
+ onPointerMove: g,
2079
+ children: [
2080
+ s,
2081
+ /* @__PURE__ */ D("div", {
2082
+ className: b("gantt-bar-hover absolute rotate-45 rounded-[2px] border shadow-sm select-none", p ? "cursor-grab active:cursor-grabbing" : "cursor-pointer", c && "ring-2 ring-primary z-10", m && "ring-2 ring-primary", kn === n.id && "gantt-flash z-10"),
2083
+ style: {
2084
+ left: d.left - e / 2,
2085
+ top: (F - e) / 2,
2086
+ width: e,
2087
+ height: e,
2088
+ backgroundColor: r ? $ : n.color || "#3b82f6",
2089
+ borderColor: r ? $ : "hsl(var(--primary-foreground) / 0.2)",
2090
+ boxShadow: r ? `0 0 0 2px ${$}` : void 0
2091
+ },
2092
+ "data-critical": r ? "true" : void 0,
2093
+ "data-testid": `gantt-milestone-${n.id}`,
2094
+ onMouseEnter: () => xt(n.id),
2095
+ onMouseLeave: () => xt((e) => e === n.id ? null : e),
2096
+ onClick: () => {
2097
+ Dt.current || o?.(n);
2098
+ },
2099
+ onContextMenu: (e) => cn(n, e),
2100
+ onPointerMove: h,
2101
+ onPointerDown: p ? (e) => {
2102
+ e.button === 0 && Ut(n, "move", e);
2103
+ } : void 0
2104
+ }),
2105
+ v
2106
+ ]
2107
+ }, n.id);
2108
+ }
2109
+ let te = Wt && Wt.taskId === n.id ? Wt.value : n.progress;
2110
+ return /* @__PURE__ */ O("div", {
2111
+ className: "relative border-b hover:bg-accent/50",
2112
+ style: { height: F },
2113
+ onPointerMove: g,
2114
+ onMouseEnter: () => xt(n.id),
2115
+ onMouseLeave: () => xt((e) => e === n.id ? null : e),
2116
+ children: [
2117
+ c && /* @__PURE__ */ D("div", {
2118
+ className: "absolute rounded-sm border border-dashed pointer-events-none",
2119
+ style: {
2120
+ left: i.left,
2121
+ width: i.width,
2122
+ top: lr,
2123
+ height: ur,
2124
+ opacity: .35,
2125
+ borderColor: "hsl(var(--primary) / 0.6)"
2126
+ },
2127
+ "aria-hidden": "true"
2128
+ }),
2129
+ s,
2130
+ /* @__PURE__ */ O("div", {
2131
+ className: b("gantt-bar-hover absolute rounded-sm bg-primary border shadow-sm flex items-center px-2 group select-none", p ? "cursor-grab active:cursor-grabbing" : "cursor-pointer", c && "ring-2 ring-primary z-10", m && "ring-2 ring-primary", kn === n.id && "gantt-flash z-10"),
2132
+ style: {
2133
+ left: d.left,
2134
+ width: d.width,
2135
+ top: lr,
2136
+ height: ur,
2137
+ backgroundColor: n.color || "#3b82f6",
2138
+ borderColor: r ? $ : "hsl(var(--primary-foreground) / 0.2)",
2139
+ boxShadow: r ? `0 0 0 2px ${$}` : void 0
2140
+ },
2141
+ "data-critical": r ? "true" : void 0,
2142
+ "data-testid": `gantt-task-bar-${n.id}`,
2143
+ onClick: () => {
2144
+ Dt.current || o?.(n);
2145
+ },
2146
+ onContextMenu: (e) => cn(n, e),
2147
+ onPointerMove: h,
2148
+ onPointerDown: p ? (e) => {
2149
+ e.button === 0 && Ut(n, "move", e);
2150
+ } : void 0,
2151
+ children: [
2152
+ p && d.width >= 14 && /* @__PURE__ */ O(De, { children: [/* @__PURE__ */ D("div", {
2153
+ className: "gantt-resize-handle absolute left-0 top-0 bottom-0",
2154
+ style: {
2155
+ width: 6,
2156
+ cursor: "ew-resize"
2157
+ },
2158
+ "data-testid": `gantt-task-resize-left-${n.id}`,
2159
+ onPointerDown: (e) => {
2160
+ e.button === 0 && Ut(n, "resize-left", e);
2161
+ },
2162
+ onClick: (e) => e.stopPropagation()
2163
+ }), /* @__PURE__ */ D("div", {
2164
+ className: "gantt-resize-handle absolute right-0 top-0 bottom-0",
2165
+ style: {
2166
+ width: 6,
2167
+ cursor: "ew-resize"
2168
+ },
2169
+ "data-testid": `gantt-task-resize-right-${n.id}`,
2170
+ onPointerDown: (e) => {
2171
+ e.button === 0 && Ut(n, "resize-right", e);
2172
+ },
2173
+ onClick: (e) => e.stopPropagation()
2174
+ })] }),
2175
+ te > 0 && /* @__PURE__ */ D("div", {
2176
+ className: "absolute left-0 top-0 bottom-0 pointer-events-none",
2177
+ style: {
2178
+ width: `${te}%`,
2179
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
2180
+ borderTopLeftRadius: "var(--radius-sm)",
2181
+ borderBottomLeftRadius: "var(--radius-sm)"
2182
+ }
2183
+ }),
2184
+ p && d.width >= 30 && /* @__PURE__ */ D("div", {
2185
+ className: b("absolute bottom-0 h-1/2 w-4 -translate-x-1/2 cursor-col-resize flex items-end justify-center pb-px", Wt?.taskId === n.id ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity"),
2186
+ style: { left: `${te}%` },
2187
+ "data-testid": `gantt-progress-handle-${n.id}`,
2188
+ onPointerDown: (e) => {
2189
+ e.button === 0 && (e.stopPropagation(), e.preventDefault(), Gt({
2190
+ taskId: n.id,
2191
+ originClientX: e.clientX,
2192
+ originProgress: n.progress,
2193
+ barWidth: d.width,
2194
+ value: n.progress
2195
+ }));
2196
+ },
2197
+ onClick: (e) => e.stopPropagation(),
2198
+ children: /* @__PURE__ */ D("div", { style: {
2199
+ width: 0,
2200
+ height: 0,
2201
+ borderLeft: "5px solid transparent",
2202
+ borderRight: "5px solid transparent",
2203
+ borderBottom: "7px solid #fff",
2204
+ filter: "drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35))"
2205
+ } })
2206
+ }),
2207
+ N && !f && ["start", "end"].map((e) => {
2208
+ let t = U != null && String(U.sourceId) === String(n.id) && U.sourceEnd === e, r = t || bt === n.id, i = r && U == null;
2209
+ return /* @__PURE__ */ D("div", {
2210
+ className: "absolute top-1/2 -translate-y-1/2 z-20 flex items-center transition-opacity",
2211
+ style: {
2212
+ [e === "start" ? "left" : "right"]: -28,
2213
+ height: 24,
2214
+ width: 30,
2215
+ cursor: "crosshair",
2216
+ opacity: +!!r,
2217
+ pointerEvents: i ? "auto" : "none",
2218
+ justifyContent: e === "start" ? "flex-start" : "flex-end",
2219
+ paddingLeft: e === "start" ? 4 : 0,
2220
+ paddingRight: e === "end" ? 4 : 0
2221
+ },
2222
+ "data-testid": `gantt-link-dot-${e}-${n.id}`,
2223
+ onPointerDown: (t) => {
2224
+ if (t.button !== 0) return;
2225
+ t.stopPropagation(), t.preventDefault();
2226
+ let r = qt.current?.getBoundingClientRect();
2227
+ Jt({
2228
+ sourceId: n.id,
2229
+ sourceEnd: e,
2230
+ x: r ? t.clientX - r.left : 0,
2231
+ y: r ? t.clientY - r.top : 0,
2232
+ targetId: null,
2233
+ targetEnd: null
2234
+ });
2235
+ },
2236
+ onClick: (e) => e.stopPropagation(),
2237
+ children: /* @__PURE__ */ D("div", {
2238
+ className: "rounded-full",
2239
+ style: {
2240
+ height: 12,
2241
+ width: 12,
2242
+ backgroundColor: "hsl(var(--background))",
2243
+ border: "2px solid hsl(var(--primary))",
2244
+ boxShadow: t ? "0 0 0 3px hsl(var(--primary) / 0.25)" : "0 1px 2px rgba(0,0,0,0.25)"
2245
+ }
2246
+ })
2247
+ }, e);
2248
+ }),
2249
+ /* @__PURE__ */ D("span", {
2250
+ className: "relative text-[10px] text-white font-medium truncate pointer-events-none group-hover:opacity-0 transition-opacity",
2251
+ children: n.title
2252
+ }),
2253
+ /* @__PURE__ */ D("span", {
2254
+ className: "absolute inset-0 flex items-center px-2 text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none",
2255
+ children: c ? `${Ot(V).start.toLocaleDateString(S, {
2256
+ month: "numeric",
2257
+ day: "numeric"
2258
+ })} → ${Ot(V).end.toLocaleDateString(S, {
2259
+ month: "numeric",
2260
+ day: "numeric"
2261
+ })}` : `${Math.round(te)}%`
2262
+ })
2263
+ ]
2264
+ }),
2265
+ v
2266
+ ]
2267
+ }, n.id);
2268
+ }),
2269
+ Z.endIdx < G.length && /* @__PURE__ */ D("div", {
2270
+ style: { height: (G.length - Z.endIdx) * F },
2271
+ "aria-hidden": "true"
2272
+ }),
2273
+ (cr.length > 0 || U) && /* @__PURE__ */ O("svg", {
2274
+ className: "absolute top-0 left-0 pointer-events-none z-10",
2275
+ width: _n,
2276
+ height: Vn,
2277
+ "data-testid": "gantt-links",
2278
+ "aria-hidden": "true",
2279
+ children: [
2280
+ /* @__PURE__ */ O("defs", { children: [
2281
+ /* @__PURE__ */ D("marker", {
2282
+ id: "gantt-link-arrow",
2283
+ viewBox: "0 0 8 8",
2284
+ refX: "7",
2285
+ refY: "4",
2286
+ markerWidth: "6",
2287
+ markerHeight: "6",
2288
+ orient: "auto",
2289
+ children: /* @__PURE__ */ D("path", {
2290
+ d: "M 0 0 L 8 4 L 0 8 z",
2291
+ fill: "hsl(var(--muted-foreground))"
2292
+ })
2293
+ }),
2294
+ /* @__PURE__ */ D("marker", {
2295
+ id: "gantt-link-arrow-active",
2296
+ viewBox: "0 0 8 8",
2297
+ refX: "7",
2298
+ refY: "4",
2299
+ markerWidth: "6",
2300
+ markerHeight: "6",
2301
+ orient: "auto",
2302
+ children: /* @__PURE__ */ D("path", {
2303
+ d: "M 0 0 L 8 4 L 0 8 z",
2304
+ fill: "hsl(var(--primary))"
2305
+ })
2306
+ }),
2307
+ /* @__PURE__ */ D("marker", {
2308
+ id: "gantt-link-arrow-critical",
2309
+ viewBox: "0 0 8 8",
2310
+ refX: "7",
2311
+ refY: "4",
2312
+ markerWidth: "6",
2313
+ markerHeight: "6",
2314
+ orient: "auto",
2315
+ children: /* @__PURE__ */ D("path", {
2316
+ d: "M 0 0 L 8 4 L 0 8 z",
2317
+ fill: $
2318
+ })
2319
+ })
2320
+ ] }),
2321
+ cr.map((t) => {
2322
+ let n = Math.min(t.sourceIndex, t.targetIndex);
2323
+ if (Math.max(t.sourceIndex, t.targetIndex) < Z.startIdx - 6 || n > Z.endIdx + 6) return null;
2324
+ let r = yr(t);
2325
+ if (!r) return null;
2326
+ let i = br != null && (String(t.sourceId) === String(br) || String(t.targetId) === String(br)), a = Cr?.criticalEdges.has(`${String(t.sourceId)}->${String(t.targetId)}`) ?? !1, o = a ? "gantt-link-arrow-critical" : i ? "gantt-link-arrow-active" : "gantt-link-arrow", s = !!(Ae || N);
2327
+ return /* @__PURE__ */ O(e.Fragment, { children: [/* @__PURE__ */ D("path", {
2328
+ d: r,
2329
+ fill: "none",
2330
+ stroke: a ? $ : i ? "hsl(var(--primary))" : "hsl(var(--muted-foreground))",
2331
+ strokeOpacity: a || i ? 1 : .7,
2332
+ strokeWidth: a || i ? 2 : 1.5,
2333
+ markerEnd: `url(#${o})`,
2334
+ "data-testid": `gantt-link-${t.sourceId}-${t.targetId}`,
2335
+ "data-link-type": t.type,
2336
+ "data-active": i ? "true" : "false",
2337
+ "data-critical": a ? "true" : void 0
2338
+ }), s && /* @__PURE__ */ D("path", {
2339
+ d: r,
2340
+ fill: "none",
2341
+ stroke: "transparent",
2342
+ strokeWidth: 10,
2343
+ style: {
2344
+ pointerEvents: "stroke",
2345
+ cursor: "context-menu"
2346
+ },
2347
+ "data-testid": `gantt-link-hit-${t.sourceId}-${t.targetId}`,
2348
+ onContextMenu: (e) => ln(t.sourceId, t.targetId, t.type, e)
2349
+ })] }, t.key);
2350
+ }),
2351
+ U && (() => {
2352
+ let e = G.findIndex((e) => String(e.task.id) === String(U.sourceId));
2353
+ if (e < 0) return null;
2354
+ let t = sr(G[e]), n = G[e].isMilestone ? t.left + (U.sourceEnd === "start" ? -fr : fr) : U.sourceEnd === "start" ? t.left : t.left + t.width, r = e * F + F / 2;
2355
+ return /* @__PURE__ */ D("path", {
2356
+ d: `M ${Math.round(n)} ${Math.round(r)} L ${Math.round(U.x)} ${Math.round(U.y)}`,
2357
+ fill: "none",
2358
+ stroke: "hsl(var(--primary))",
2359
+ strokeWidth: 1.5,
2360
+ strokeDasharray: "4 3",
2361
+ "data-testid": "gantt-link-draft"
2362
+ });
2363
+ })()
2364
+ ]
2365
+ }),
2366
+ U && (() => {
2367
+ let e = t.find((e) => String(e.id) === String(U.sourceId));
2368
+ if (!e) return null;
2369
+ let n = U.targetId == null ? null : t.find((e) => String(e.id) === String(U.targetId)), r = (e) => x(`gantt.linkEnd.${e}`), i = n ? `${e.title} (${r(U.sourceEnd)}) → ${n.title} (${r(U.targetEnd ?? "start")})` : `${e.title} (${r(U.sourceEnd)})`;
2370
+ return /* @__PURE__ */ D("div", {
2371
+ className: "absolute z-30 pointer-events-none rounded-md border bg-popover text-popover-foreground px-2 py-1 text-[11px] font-medium shadow-md whitespace-nowrap",
2372
+ style: {
2373
+ left: U.x + 12,
2374
+ top: U.y + 12
2375
+ },
2376
+ "data-testid": "gantt-link-draft-hint",
2377
+ children: i
2378
+ });
2379
+ })()
2380
+ ]
2381
+ })
2382
+ ]
2383
+ })
502
2384
  })]
503
2385
  })
2386
+ ]
2387
+ }),
2388
+ Xt && (() => {
2389
+ let e = t.find((e) => String(e.id) === String(Xt.taskId));
2390
+ if (!e) return null;
2391
+ let n = G.find((e) => String(e.task.id) === String(Xt.taskId)), r = "w-full text-left px-3 py-1.5 hover:bg-accent focus:bg-accent outline-none";
2392
+ return /* @__PURE__ */ O("div", {
2393
+ ref: Qt,
2394
+ className: "fixed z-50 min-w-[160px] rounded-md border bg-popover text-popover-foreground shadow-md py-1 text-sm",
2395
+ style: {
2396
+ left: Xt.x,
2397
+ top: Xt.y
2398
+ },
2399
+ role: "menu",
2400
+ "data-testid": "gantt-context-menu",
2401
+ children: [
2402
+ o && /* @__PURE__ */ D("button", {
2403
+ type: "button",
2404
+ role: "menuitem",
2405
+ className: r,
2406
+ "data-testid": "gantt-context-menu-view",
2407
+ onClick: () => {
2408
+ Zt(null), o(e);
2409
+ },
2410
+ children: x("gantt.menu.view")
2411
+ }),
2412
+ je && M && n && !n.isSummary && !e.locked && /* @__PURE__ */ D("button", {
2413
+ type: "button",
2414
+ role: "menuitem",
2415
+ className: r,
2416
+ "data-testid": "gantt-context-menu-edit",
2417
+ onClick: () => {
2418
+ Zt(null), _t(e.id), yt({
2419
+ title: e.title,
2420
+ start: e.start.toLocaleDateString("en-CA"),
2421
+ end: e.end.toLocaleDateString("en-CA"),
2422
+ progress: String(e.progress)
2423
+ });
2424
+ },
2425
+ children: x("gantt.menu.edit")
2426
+ }),
2427
+ N && n && !n.isMilestone && !e.locked && /* @__PURE__ */ O(De, { children: [/* @__PURE__ */ D("button", {
2428
+ type: "button",
2429
+ role: "menuitem",
2430
+ className: r,
2431
+ "data-testid": "gantt-context-menu-add-predecessor",
2432
+ onClick: () => {
2433
+ let t = Xt;
2434
+ Zt(null), nn({
2435
+ x: t.x,
2436
+ y: t.y,
2437
+ taskId: e.id,
2438
+ relation: "pred"
2439
+ });
2440
+ },
2441
+ children: x("gantt.menu.addPredecessor")
2442
+ }), /* @__PURE__ */ D("button", {
2443
+ type: "button",
2444
+ role: "menuitem",
2445
+ className: r,
2446
+ "data-testid": "gantt-context-menu-add-successor",
2447
+ onClick: () => {
2448
+ let t = Xt;
2449
+ Zt(null), nn({
2450
+ x: t.x,
2451
+ y: t.y,
2452
+ taskId: e.id,
2453
+ relation: "succ"
2454
+ });
2455
+ },
2456
+ children: x("gantt.menu.addSuccessor")
2457
+ })] }),
2458
+ ke && !e.locked && /* @__PURE__ */ D("button", {
2459
+ type: "button",
2460
+ role: "menuitem",
2461
+ className: b(r, "text-destructive"),
2462
+ "data-testid": "gantt-context-menu-delete",
2463
+ onClick: () => {
2464
+ Zt(null), ke(e);
2465
+ },
2466
+ children: x("gantt.menu.delete")
2467
+ })
2468
+ ]
2469
+ });
2470
+ })(),
2471
+ W && (() => {
2472
+ let e = t.find((e) => String(e.id) === String(W.sourceId)), n = t.find((e) => String(e.id) === String(W.targetId));
2473
+ if (!e || !n) return null;
2474
+ let r = "w-full text-left px-3 py-1.5 hover:bg-accent focus:bg-accent outline-none";
2475
+ return /* @__PURE__ */ O("div", {
2476
+ ref: en,
2477
+ className: "fixed z-50 min-w-[180px] rounded-md border bg-popover text-popover-foreground shadow-md py-1 text-sm",
2478
+ style: {
2479
+ left: W.x,
2480
+ top: W.y
2481
+ },
2482
+ role: "menu",
2483
+ "data-testid": "gantt-link-context-menu",
2484
+ children: [
2485
+ /* @__PURE__ */ O("div", {
2486
+ className: "px-3 py-1 text-xs text-muted-foreground truncate",
2487
+ children: [
2488
+ e.title,
2489
+ " → ",
2490
+ n.title
2491
+ ]
2492
+ }),
2493
+ N && [
2494
+ "fs",
2495
+ "ss",
2496
+ "ff",
2497
+ "sf"
2498
+ ].map((t) => /* @__PURE__ */ O("button", {
2499
+ type: "button",
2500
+ role: "menuitemradio",
2501
+ "aria-checked": W.type === t,
2502
+ className: b(r, W.type === t && "font-semibold"),
2503
+ "data-testid": `gantt-link-menu-type-${t}`,
2504
+ onClick: () => {
2505
+ $t(null), t !== W.type && N(e, n, t);
2506
+ },
2507
+ children: [W.type === t ? "✓ " : "\xA0\xA0", x(`gantt.linkType.${t}`)]
2508
+ }, t)),
2509
+ Ae && /* @__PURE__ */ O(De, { children: [/* @__PURE__ */ D("div", { className: "my-1 border-t" }), /* @__PURE__ */ D("button", {
2510
+ type: "button",
2511
+ role: "menuitem",
2512
+ className: b(r, "text-destructive"),
2513
+ "data-testid": "gantt-link-menu-remove",
2514
+ onClick: () => {
2515
+ $t(null), Ae(e, n);
2516
+ },
2517
+ children: x("gantt.menu.removeDependency")
2518
+ })] })
2519
+ ]
2520
+ });
2521
+ })(),
2522
+ tn && N && (() => {
2523
+ let e = t.find((e) => String(e.id) === String(tn.taskId));
2524
+ if (!e) return null;
2525
+ let n = new Set(cr.map((e) => `${String(e.sourceId)}->${String(e.targetId)}`)), r = t.filter((t) => {
2526
+ if (String(t.id) === String(e.id) || t.type === "summary") return !1;
2527
+ let r = tn.relation === "pred" ? `${String(t.id)}->${String(e.id)}` : `${String(e.id)}->${String(t.id)}`;
2528
+ return !n.has(r);
2529
+ });
2530
+ return /* @__PURE__ */ O("div", {
2531
+ ref: rn,
2532
+ className: "fixed z-50 min-w-[200px] max-h-[280px] overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md py-1 text-sm",
2533
+ style: {
2534
+ left: tn.x,
2535
+ top: tn.y
2536
+ },
2537
+ role: "menu",
2538
+ "data-testid": "gantt-dep-picker",
2539
+ children: [/* @__PURE__ */ D("div", {
2540
+ className: "px-3 py-1 text-xs text-muted-foreground",
2541
+ children: tn.relation === "pred" ? x("gantt.menu.addPredecessor") : x("gantt.menu.addSuccessor")
2542
+ }), r.length === 0 ? /* @__PURE__ */ D("div", {
2543
+ className: "px-3 py-1.5 text-muted-foreground",
2544
+ children: x("gantt.menu.noCandidates")
2545
+ }) : r.map((t) => /* @__PURE__ */ D("button", {
2546
+ type: "button",
2547
+ role: "menuitem",
2548
+ className: "w-full text-left px-3 py-1.5 hover:bg-accent focus:bg-accent outline-none truncate",
2549
+ "data-testid": `gantt-dep-picker-option-${t.id}`,
2550
+ onClick: () => {
2551
+ nn(null), tn.relation === "pred" ? N(t, e, "fs") : N(e, t, "fs");
2552
+ },
2553
+ children: t.title
2554
+ }, String(t.id)))]
2555
+ });
2556
+ })(),
2557
+ Pt && /* @__PURE__ */ D("div", {
2558
+ className: "fixed inset-0 z-[60] flex items-center justify-center bg-black/30",
2559
+ "data-testid": "gantt-conflict-overlay",
2560
+ onClick: () => Ft(null),
2561
+ children: /* @__PURE__ */ O("div", {
2562
+ className: "min-w-[280px] max-w-[360px] rounded-lg border bg-popover text-popover-foreground shadow-lg p-4",
2563
+ role: "alertdialog",
2564
+ "aria-modal": "true",
2565
+ "data-testid": "gantt-conflict-dialog",
2566
+ onClick: (e) => e.stopPropagation(),
2567
+ children: [
2568
+ /* @__PURE__ */ D("div", {
2569
+ className: "text-sm font-semibold mb-1",
2570
+ "data-testid": "gantt-conflict-title",
2571
+ children: x("gantt.conflict.title")
2572
+ }),
2573
+ /* @__PURE__ */ D("div", {
2574
+ className: "text-sm text-muted-foreground mb-3",
2575
+ children: x("gantt.conflict.body").replace("{count}", String(Pt.length))
2576
+ }),
2577
+ /* @__PURE__ */ O("div", {
2578
+ className: "flex justify-end gap-2",
2579
+ children: [/* @__PURE__ */ D("button", {
2580
+ type: "button",
2581
+ className: "px-3 py-1.5 text-sm rounded-md border hover:bg-accent outline-none",
2582
+ "data-testid": "gantt-conflict-cancel",
2583
+ onClick: () => Ft(null),
2584
+ children: x("gantt.conflict.cancel")
2585
+ }), /* @__PURE__ */ D("button", {
2586
+ type: "button",
2587
+ className: "px-3 py-1.5 text-sm rounded-md bg-primary text-primary-foreground hover:opacity-90 outline-none",
2588
+ "data-testid": "gantt-conflict-confirm",
2589
+ onClick: Lt,
2590
+ children: x("gantt.conflict.confirm")
2591
+ })]
2592
+ })
2593
+ ]
2594
+ })
2595
+ })
2596
+ ]
2597
+ });
2598
+ }
2599
+ //#endregion
2600
+ //#region src/workload.ts
2601
+ function nt(e, t, n, r) {
2602
+ return t.getTime() === e.getTime() ? e.getTime() >= n.getTime() && e.getTime() < r.getTime() : e.getTime() < r.getTime() && t.getTime() > n.getTime();
2603
+ }
2604
+ function rt(e, t, n) {
2605
+ let { assignee: r, effort: i, capacity: a = 1, unassignedLabel: o = "Unassigned" } = n, s = (e) => typeof a == "function" ? a(e) : a, c = (e) => {
2606
+ let t = i ? i(e) : 1;
2607
+ return Number.isFinite(t) && t > 0 ? t : 0;
2608
+ }, l = /* @__PURE__ */ new Map();
2609
+ for (let t of e) {
2610
+ let e = r(t), n = e ? String(e.key) : "__unassigned__", i = e ? e.label : o, a = l.get(n);
2611
+ a || (a = {
2612
+ key: n,
2613
+ label: i,
2614
+ items: []
2615
+ }, l.set(n, a)), a.items.push(t);
2616
+ }
2617
+ let u = [];
2618
+ for (let e of l.values()) {
2619
+ let n = s(e.key), r = 0, i = 0, a = t.map((t) => {
2620
+ let a = 0;
2621
+ for (let n of e.items) nt(n.start, n.end, t.start, t.end) && (a += c(n));
2622
+ a > r && (r = a);
2623
+ let o = a > n + 1e-9;
2624
+ return o && i++, {
2625
+ load: a,
2626
+ capacity: n,
2627
+ overloaded: o
2628
+ };
2629
+ });
2630
+ u.push({
2631
+ key: e.key,
2632
+ label: e.label,
2633
+ capacity: n,
2634
+ cells: a,
2635
+ peak: r,
2636
+ overloadedCount: i
2637
+ });
2638
+ }
2639
+ return u;
2640
+ }
2641
+ //#endregion
2642
+ //#region src/ResourceWorkload.tsx
2643
+ var it = {
2644
+ day: 26,
2645
+ week: 56,
2646
+ month: 76,
2647
+ quarter: 88,
2648
+ year: 104
2649
+ }, L = 48, at = 34, ot = 180;
2650
+ function st(e, t, n) {
2651
+ return t === "day" ? String(e.getDate()) : t === "week" ? e.toLocaleDateString(n, {
2652
+ month: "numeric",
2653
+ day: "numeric"
2654
+ }) : t === "month" ? e.toLocaleDateString(n, { month: "short" }) : t === "year" ? String(e.getFullYear()) : `Q${Math.floor(e.getMonth() / 3) + 1}`;
2655
+ }
2656
+ function ct({ tasks: t, assignee: n, effort: r, capacity: i = 1, viewMode: a = "day", unassignedLabel: o = "Unassigned", className: s }) {
2657
+ let { t: c, language: l } = Le(), u = l || void 0, d = it[a], f = e.useMemo(() => {
2658
+ if (!t.length) return [];
2659
+ let e = new Date(Math.min(...t.map((e) => e.start.getTime()))), n = new Date(Math.max(...t.map((e) => e.end.getTime()))), r = Ge(e, a), i = qe(Ge(n, a), 1, a), o = [], s = 0;
2660
+ for (; r < i && s++ < 4e3;) {
2661
+ let e = qe(r, 1, a);
2662
+ o.push({
2663
+ date: new Date(r),
2664
+ col: {
2665
+ start: new Date(r),
2666
+ end: new Date(e)
2667
+ },
2668
+ label: st(r, a, u)
2669
+ }), r = e;
2670
+ }
2671
+ return o;
2672
+ }, [
2673
+ t,
2674
+ a,
2675
+ u
2676
+ ]), p = e.useMemo(() => rt(t, f.map((e) => e.col), {
2677
+ assignee: n,
2678
+ effort: r,
2679
+ capacity: i,
2680
+ unassignedLabel: o
2681
+ }), [
2682
+ t,
2683
+ f,
2684
+ n,
2685
+ r,
2686
+ i,
2687
+ o
2688
+ ]), m = e.useMemo(() => {
2689
+ let e = 0;
2690
+ for (let t of p) e = Math.max(e, t.peak, t.capacity);
2691
+ return e || 1;
2692
+ }, [p]), h = f.length * d;
2693
+ return t.length ? /* @__PURE__ */ D("div", {
2694
+ className: s,
2695
+ "data-testid": "resource-workload",
2696
+ style: {
2697
+ display: "flex",
2698
+ flexDirection: "column",
2699
+ height: "100%",
2700
+ overflow: "auto"
2701
+ },
2702
+ children: /* @__PURE__ */ O("div", {
2703
+ style: {
2704
+ display: "flex",
2705
+ minWidth: ot + h
2706
+ },
2707
+ children: [/* @__PURE__ */ O("div", {
2708
+ style: {
2709
+ width: ot,
2710
+ flexShrink: 0
2711
+ },
2712
+ children: [/* @__PURE__ */ D("div", {
2713
+ style: {
2714
+ height: 28,
2715
+ display: "flex",
2716
+ alignItems: "center",
2717
+ padding: "0 12px",
2718
+ fontSize: 12,
2719
+ fontWeight: 600,
2720
+ borderBottom: "1px solid hsl(var(--border))"
2721
+ },
2722
+ children: c("gantt.resource.header")
2723
+ }), p.map((e) => /* @__PURE__ */ O("div", {
2724
+ "data-testid": `resource-row-${e.key}`,
2725
+ style: {
2726
+ height: L,
2727
+ display: "flex",
2728
+ flexDirection: "column",
2729
+ justifyContent: "center",
2730
+ padding: "0 12px",
2731
+ borderBottom: "1px solid hsl(var(--border) / 0.5)"
2732
+ },
2733
+ children: [/* @__PURE__ */ D("span", {
2734
+ style: {
2735
+ fontSize: 13,
2736
+ fontWeight: 500,
2737
+ whiteSpace: "nowrap",
2738
+ overflow: "hidden",
2739
+ textOverflow: "ellipsis"
2740
+ },
2741
+ children: e.label
2742
+ }), /* @__PURE__ */ O("span", {
2743
+ "data-testid": `resource-peak-${e.key}`,
2744
+ "data-overloaded": e.overloadedCount > 0 ? "true" : void 0,
2745
+ style: {
2746
+ fontSize: 10,
2747
+ color: e.overloadedCount > 0 ? "hsl(var(--destructive))" : "hsl(var(--muted-foreground))"
2748
+ },
2749
+ children: [
2750
+ c("gantt.resource.peak"),
2751
+ ": ",
2752
+ Math.round(e.peak * 100) / 100,
2753
+ " / ",
2754
+ e.capacity,
2755
+ e.overloadedCount > 0 ? ` · ${e.overloadedCount} ${c("gantt.resource.over")}` : ""
2756
+ ]
2757
+ })]
2758
+ }, e.key))]
2759
+ }), /* @__PURE__ */ O("div", {
2760
+ style: { flex: 1 },
2761
+ children: [/* @__PURE__ */ D("div", {
2762
+ style: {
2763
+ display: "flex",
2764
+ height: 28,
2765
+ borderBottom: "1px solid hsl(var(--border))"
2766
+ },
2767
+ children: f.map((e, t) => /* @__PURE__ */ D("div", {
2768
+ style: {
2769
+ width: d,
2770
+ flexShrink: 0,
2771
+ textAlign: "center",
2772
+ fontSize: 10,
2773
+ color: "hsl(var(--muted-foreground))",
2774
+ borderLeft: "1px solid hsl(var(--border) / 0.4)",
2775
+ display: "flex",
2776
+ alignItems: "center",
2777
+ justifyContent: "center"
2778
+ },
2779
+ children: e.label
2780
+ }, t))
2781
+ }), p.map((e) => {
2782
+ let t = at * (1 - Math.min(e.capacity / m, 1));
2783
+ return /* @__PURE__ */ O("div", {
2784
+ style: {
2785
+ position: "relative",
2786
+ display: "flex",
2787
+ height: L,
2788
+ borderBottom: "1px solid hsl(var(--border) / 0.5)"
2789
+ },
2790
+ children: [/* @__PURE__ */ D("div", {
2791
+ "aria-hidden": "true",
2792
+ style: {
2793
+ position: "absolute",
2794
+ left: 0,
2795
+ right: 0,
2796
+ top: (L - at) / 2 + t,
2797
+ borderTop: "1px dashed hsl(var(--muted-foreground) / 0.6)",
2798
+ pointerEvents: "none",
2799
+ zIndex: 1
2800
+ }
2801
+ }), e.cells.map((t, n) => {
2802
+ let r = Math.max(t.load > 0 ? 2 : 0, at * Math.min(t.load / m, 1));
2803
+ return /* @__PURE__ */ D("div", {
2804
+ "data-testid": `resource-cell-${e.key}-${n}`,
2805
+ "data-load": t.load,
2806
+ "data-overloaded": t.overloaded ? "true" : void 0,
2807
+ title: `${f[n]?.date.toLocaleDateString(u)} — ${Math.round(t.load * 100) / 100} / ${t.capacity}`,
2808
+ style: {
2809
+ width: d,
2810
+ flexShrink: 0,
2811
+ position: "relative",
2812
+ borderLeft: "1px solid hsl(var(--border) / 0.4)",
2813
+ display: "flex",
2814
+ alignItems: "flex-end",
2815
+ justifyContent: "center",
2816
+ paddingBottom: (L - at) / 2
2817
+ },
2818
+ children: t.load > 0 && /* @__PURE__ */ D("div", { style: {
2819
+ width: d - 6,
2820
+ height: r,
2821
+ borderRadius: 2,
2822
+ backgroundColor: t.overloaded ? "hsl(var(--destructive))" : "hsl(var(--primary))",
2823
+ opacity: t.overloaded ? .9 : .75
2824
+ } })
2825
+ }, n);
2826
+ })]
2827
+ }, e.key);
504
2828
  })]
505
2829
  })]
2830
+ })
2831
+ }) : /* @__PURE__ */ D("div", {
2832
+ className: s,
2833
+ "data-testid": "resource-workload",
2834
+ children: /* @__PURE__ */ D("div", {
2835
+ className: "flex items-center justify-center h-40 text-sm text-muted-foreground",
2836
+ children: c("gantt.resource.empty")
2837
+ })
2838
+ });
2839
+ }
2840
+ //#endregion
2841
+ //#region src/QuickFilterBar.tsx
2842
+ var lt = {
2843
+ display: "flex",
2844
+ flexWrap: "wrap",
2845
+ alignItems: "center",
2846
+ gap: 8,
2847
+ padding: "8px 12px",
2848
+ borderBottom: "1px solid hsl(var(--border))",
2849
+ background: "hsl(var(--background))",
2850
+ fontSize: 13
2851
+ }, ut = {
2852
+ display: "inline-flex",
2853
+ alignItems: "center",
2854
+ gap: 6,
2855
+ height: 30,
2856
+ padding: "0 10px",
2857
+ borderRadius: 6,
2858
+ border: "1px solid hsl(var(--border))",
2859
+ background: "hsl(var(--background))",
2860
+ color: "hsl(var(--foreground))",
2861
+ cursor: "pointer",
2862
+ whiteSpace: "nowrap",
2863
+ lineHeight: "28px"
2864
+ }, dt = {
2865
+ position: "absolute",
2866
+ top: "calc(100% + 4px)",
2867
+ left: 0,
2868
+ zIndex: 50,
2869
+ minWidth: 200,
2870
+ maxHeight: 320,
2871
+ overflowY: "auto",
2872
+ padding: 4,
2873
+ borderRadius: 8,
2874
+ border: "1px solid hsl(var(--border))",
2875
+ background: "hsl(var(--popover, var(--background)))",
2876
+ color: "hsl(var(--popover-foreground, var(--foreground)))",
2877
+ boxShadow: "0 8px 24px rgba(0,0,0,0.18)"
2878
+ }, ft = {
2879
+ display: "flex",
2880
+ alignItems: "center",
2881
+ gap: 8,
2882
+ padding: "6px 8px",
2883
+ borderRadius: 6,
2884
+ cursor: "pointer",
2885
+ userSelect: "none"
2886
+ };
2887
+ function R({ checked: e }) {
2888
+ return /* @__PURE__ */ D("span", {
2889
+ "aria-hidden": !0,
2890
+ style: {
2891
+ display: "inline-flex",
2892
+ alignItems: "center",
2893
+ justifyContent: "center",
2894
+ width: 15,
2895
+ height: 15,
2896
+ flex: "0 0 auto",
2897
+ borderRadius: 3,
2898
+ border: `1px solid ${e ? "hsl(var(--primary))" : "hsl(var(--border))"}`,
2899
+ background: e ? "hsl(var(--primary))" : "transparent",
2900
+ color: "hsl(var(--primary-foreground, var(--background)))",
2901
+ fontSize: 11,
2902
+ lineHeight: 1
2903
+ },
2904
+ children: e ? "✓" : ""
2905
+ });
2906
+ }
2907
+ function pt({ filter: e, selected: t, onChange: r, labels: o }) {
2908
+ let [s, c] = a(!1), l = i(null);
2909
+ n(() => {
2910
+ if (!s) return;
2911
+ let e = (e) => {
2912
+ l.current && !l.current.contains(e.target) && c(!1);
2913
+ }, t = (e) => {
2914
+ e.key === "Escape" && c(!1);
2915
+ };
2916
+ return document.addEventListener("pointerdown", e), document.addEventListener("keydown", t), () => {
2917
+ document.removeEventListener("pointerdown", e), document.removeEventListener("keydown", t);
2918
+ };
2919
+ }, [s]);
2920
+ let u = new Set(t), d = t.length, f = e.options.length > 0 && d === e.options.length, p = (t) => {
2921
+ let n = new Set(u);
2922
+ n.has(t) ? n.delete(t) : n.add(t), n.size === e.options.length ? r([]) : r([...n]);
2923
+ }, m = () => {
2924
+ r(d > 0 ? [] : e.options.map((e) => e.value));
2925
+ }, h = d === 0 ? e.label : d === 1 ? `${e.label}: ${e.options.find((e) => e.value === t[0])?.label ?? t[0]}` : `${e.label} · ${d}`;
2926
+ return /* @__PURE__ */ O("div", {
2927
+ ref: l,
2928
+ style: { position: "relative" },
2929
+ "data-testid": `quick-filter-${e.field}`,
2930
+ children: [/* @__PURE__ */ O("button", {
2931
+ type: "button",
2932
+ style: {
2933
+ ...ut,
2934
+ borderColor: d > 0 ? "hsl(var(--primary))" : "hsl(var(--border))",
2935
+ color: d > 0 ? "hsl(var(--primary))" : "hsl(var(--foreground))"
2936
+ },
2937
+ "aria-haspopup": "listbox",
2938
+ "aria-expanded": s,
2939
+ "data-testid": `quick-filter-trigger-${e.field}`,
2940
+ onClick: () => c((e) => !e),
2941
+ children: [/* @__PURE__ */ D("span", { children: h }), /* @__PURE__ */ D("span", {
2942
+ "aria-hidden": !0,
2943
+ style: {
2944
+ fontSize: 10,
2945
+ opacity: .7
2946
+ },
2947
+ children: "▾"
2948
+ })]
2949
+ }), s && /* @__PURE__ */ D("div", {
2950
+ role: "listbox",
2951
+ style: dt,
2952
+ "data-testid": `quick-filter-panel-${e.field}`,
2953
+ children: e.options.length === 0 ? /* @__PURE__ */ D("div", {
2954
+ style: {
2955
+ ...ft,
2956
+ cursor: "default",
2957
+ opacity: .6
2958
+ },
2959
+ children: o.empty
2960
+ }) : /* @__PURE__ */ O(De, { children: [
2961
+ /* @__PURE__ */ O("div", {
2962
+ role: "option",
2963
+ "aria-selected": f,
2964
+ style: {
2965
+ ...ft,
2966
+ fontWeight: 600
2967
+ },
2968
+ "data-testid": `quick-filter-all-${e.field}`,
2969
+ onClick: () => m(),
2970
+ children: [/* @__PURE__ */ D(R, { checked: f }), /* @__PURE__ */ D("span", { children: o.all })]
2971
+ }),
2972
+ /* @__PURE__ */ D("div", { style: {
2973
+ height: 1,
2974
+ background: "hsl(var(--border))",
2975
+ margin: "2px 0"
2976
+ } }),
2977
+ e.options.map((t) => {
2978
+ let n = u.has(t.value);
2979
+ return /* @__PURE__ */ O("div", {
2980
+ role: "option",
2981
+ "aria-selected": n,
2982
+ style: {
2983
+ ...ft,
2984
+ background: n ? "hsl(var(--accent, var(--muted)))" : "transparent"
2985
+ },
2986
+ "data-testid": `quick-filter-option-${e.field}-${t.value}`,
2987
+ onClick: () => p(t.value),
2988
+ children: [/* @__PURE__ */ D(R, { checked: n }), /* @__PURE__ */ D("span", { children: t.label })]
2989
+ }, t.value);
2990
+ })
2991
+ ] })
506
2992
  })]
507
2993
  });
508
2994
  }
2995
+ var z = ({ filters: e, value: t, onChange: n, onClear: r, resultCount: i, totalCount: a, labels: o, className: s }) => {
2996
+ if (!e.length) return null;
2997
+ let c = o?.all ?? "All", l = o?.empty ?? "No options", u = o?.clear ?? "Clear", d = e.some((e) => (t[e.field]?.length ?? 0) > 0);
2998
+ return /* @__PURE__ */ O("div", {
2999
+ style: lt,
3000
+ className: s,
3001
+ "data-testid": "quick-filter-bar",
3002
+ children: [
3003
+ e.map((e) => /* @__PURE__ */ D(pt, {
3004
+ filter: e,
3005
+ selected: t[e.field] ?? [],
3006
+ onChange: (t) => n(e.field, t),
3007
+ labels: {
3008
+ all: c,
3009
+ empty: l
3010
+ }
3011
+ }, e.field)),
3012
+ d && /* @__PURE__ */ D("button", {
3013
+ type: "button",
3014
+ style: {
3015
+ ...ut,
3016
+ height: 28,
3017
+ color: "hsl(var(--muted-foreground))"
3018
+ },
3019
+ "data-testid": "quick-filter-clear",
3020
+ onClick: r,
3021
+ children: u
3022
+ }),
3023
+ o?.resultSummary && i != null && a != null && /* @__PURE__ */ D("span", {
3024
+ "data-testid": "quick-filter-summary",
3025
+ style: {
3026
+ marginLeft: "auto",
3027
+ color: "hsl(var(--muted-foreground))"
3028
+ },
3029
+ children: o.resultSummary(i, a)
3030
+ })
3031
+ ]
3032
+ });
3033
+ };
509
3034
  //#endregion
510
3035
  //#region src/ObjectGantt.tsx
511
- function B(e) {
3036
+ function mt(e) {
3037
+ if (e == null) return;
3038
+ let t = String(e).toLowerCase().trim();
3039
+ if (t === "milestone") return "milestone";
3040
+ if (t === "group" || t === "folder") return "group";
3041
+ if (t === "summary" || t === "project" || t === "phase") return "summary";
3042
+ if (t === "task") return "task";
3043
+ }
3044
+ var ht = {
3045
+ fs: "fs",
3046
+ ss: "ss",
3047
+ ff: "ff",
3048
+ sf: "sf",
3049
+ finish_to_start: "fs",
3050
+ start_to_start: "ss",
3051
+ finish_to_finish: "ff",
3052
+ start_to_finish: "sf",
3053
+ end_to_start: "fs",
3054
+ end_to_end: "ff",
3055
+ start_to_end: "sf"
3056
+ };
3057
+ function gt(e) {
3058
+ if (e == null || e === "") return [];
3059
+ if (typeof e == "string") return e.split(",").map((e) => e.trim()).filter(Boolean);
3060
+ if (typeof e == "number") return [e];
3061
+ if (!Array.isArray(e)) return [];
3062
+ let t = [];
3063
+ for (let n of e) if (!(n == null || n === "")) if (typeof n == "object") {
3064
+ let e = n.id ?? n._id ?? n.task ?? n.target;
3065
+ if (e == null || e === "") continue;
3066
+ let r = ht[String(n.type ?? "").toLowerCase().replace(/-/g, "_")];
3067
+ t.push(r ? {
3068
+ id: e,
3069
+ type: r
3070
+ } : { id: e });
3071
+ } else t.push(n);
3072
+ return t;
3073
+ }
3074
+ function _t(e) {
512
3075
  return e.data ? e.data : e.staticData ? {
513
3076
  provider: "value",
514
3077
  items: e.staticData
@@ -517,7 +3080,7 @@ function B(e) {
517
3080
  object: e.objectName
518
3081
  } : null;
519
3082
  }
520
- function V(e) {
3083
+ function vt(e) {
521
3084
  if (e) {
522
3085
  if (typeof e == "string") {
523
3086
  let t = e.split(" "), n = t[0], r = t[1]?.toLowerCase() === "desc" ? "desc" : "asc";
@@ -526,7 +3089,7 @@ function V(e) {
526
3089
  if (Array.isArray(e)) return e.reduce((e, t) => (t.field && t.order && (e[t.field] = t.order), e), {});
527
3090
  }
528
3091
  }
529
- function H(e) {
3092
+ function yt(e) {
530
3093
  let t = null;
531
3094
  if (e.startDateField && e.endDateField) return t = {
532
3095
  startDateField: e.startDateField,
@@ -534,68 +3097,82 @@ function H(e) {
534
3097
  titleField: e.titleField || "name",
535
3098
  progressField: e.progressField,
536
3099
  dependenciesField: e.dependenciesField || e.dependencyField,
537
- colorField: e.colorField
3100
+ colorField: e.colorField,
3101
+ parentField: e.parentField,
3102
+ typeField: e.typeField,
3103
+ lockField: e.lockField,
3104
+ defaultCollapsedDepth: e.defaultCollapsedDepth,
3105
+ tooltipFields: e.tooltipFields,
3106
+ baselineStartField: e.baselineStartField,
3107
+ baselineEndField: e.baselineEndField,
3108
+ groupByField: e.groupByField,
3109
+ resourceView: e.resourceView,
3110
+ assigneeField: e.assigneeField,
3111
+ effortField: e.effortField,
3112
+ capacity: e.capacity,
3113
+ quickFilters: e.quickFilters,
3114
+ autoZoomToFilter: e.autoZoomToFilter
538
3115
  }, t;
539
3116
  if (e.gantt && (t = e.gantt), t) {
540
- let e = d.safeParse(t);
3117
+ let e = f.safeParse(t);
541
3118
  return e.success || console.warn("[ObjectGantt] Invalid gantt configuration:", e.error.format()), t;
542
3119
  }
543
3120
  return null;
544
3121
  }
545
- var U = ({ schema: e, dataSource: a, className: l, onTaskClick: u, onRowClick: d, ...S }) => {
546
- let [C, w] = i([]), [ee, D] = i(!0), [O, te] = i(null), [k, ne] = i(null), A = B(e), P = r(() => A, [JSON.stringify(A)]), F = H(e), I = P?.provider === "value";
3122
+ var bt = ({ schema: e, dataSource: i, className: o, onTaskClick: u, onRowClick: d, ...f }) => {
3123
+ let [y, b] = a([]), [oe, pe] = a(!0), [me, he] = a(null), [C, ge] = a(null), { currency: _e } = m(), ve = _t(e), w = r(() => ve, [JSON.stringify(ve)]), T = yt(e), ye = w?.provider === "value";
547
3124
  n(() => {
548
3125
  (async () => {
549
3126
  try {
550
- if (D(!0), S.data && Array.isArray(S.data)) {
551
- w(S.data), D(!1);
3127
+ if (pe(!0), f.data && Array.isArray(f.data)) {
3128
+ b(f.data), pe(!1);
552
3129
  return;
553
3130
  }
554
- if (I && P?.provider === "value") {
555
- w(P.items), D(!1);
3131
+ if (ye && w?.provider === "value") {
3132
+ b(w.items), pe(!1);
556
3133
  return;
557
3134
  }
558
- if (!a || typeof a.find != "function") throw Error("DataSource required for object/api providers");
559
- if (P?.provider === "object") {
560
- let t = P.object, n = o(k?.fields);
561
- w(s(await a.find(t, {
3135
+ if (!i || typeof i.find != "function") throw Error("DataSource required for object/api providers");
3136
+ if (w?.provider === "object") {
3137
+ let t = w.object, n = s(C?.fields);
3138
+ b(c(await i.find(t, {
562
3139
  $filter: e.filter,
563
- $orderby: V(e.sort),
3140
+ $orderby: vt(e.sort),
564
3141
  ...n.length > 0 ? { $expand: n } : {}
565
3142
  })));
566
- } else P?.provider === "api" && (console.warn("API provider not yet implemented for ObjectGantt"), w([]));
567
- D(!1);
3143
+ } else w?.provider === "api" && (console.warn("API provider not yet implemented for ObjectGantt"), b([]));
3144
+ pe(!1);
568
3145
  } catch (e) {
569
- te(e), D(!1);
3146
+ he(e), pe(!1);
570
3147
  }
571
3148
  })();
572
3149
  }, [
573
- P,
574
- a,
575
- I,
3150
+ w,
3151
+ i,
3152
+ ye,
576
3153
  e.filter,
577
3154
  e.sort,
578
- k
3155
+ C
579
3156
  ]), n(() => {
580
- !I && a && (async () => {
3157
+ !ye && i && (async () => {
581
3158
  try {
582
- if (!a) return;
583
- let t = P?.provider === "object" ? P.object : e.objectName;
3159
+ if (!i) return;
3160
+ let t = w?.provider === "object" ? w.object : e.objectName;
584
3161
  if (!t) return;
585
- ne(await a.getObjectSchema(t));
3162
+ ge(await i.getObjectSchema(t));
586
3163
  } catch (e) {
587
3164
  console.error("Failed to fetch object schema:", e);
588
3165
  }
589
3166
  })();
590
3167
  }, [
591
3168
  e.objectName,
592
- a,
593
- I,
594
- P
3169
+ i,
3170
+ ye,
3171
+ w
595
3172
  ]);
596
- let re = r(() => {
597
- if (!F || !C.length) return [];
598
- let { startDateField: e, endDateField: t, titleField: n, progressField: r, dependenciesField: i, colorField: a } = F, o = (e, t) => {
3173
+ let E = r(() => {
3174
+ if (!T || !y.length) return [];
3175
+ let { startDateField: e, endDateField: t, titleField: n, progressField: r, dependenciesField: i, colorField: a, parentField: o, typeField: s, lockField: c, tooltipFields: l, baselineStartField: u, baselineEndField: d } = T, f = C?.fields ?? {}, m = (e, t) => {
599
3176
  if (!t) return;
600
3177
  let n = t.split("."), r = e;
601
3178
  for (let e of n) {
@@ -603,9 +3180,9 @@ var U = ({ schema: e, dataSource: a, className: l, onTaskClick: u, onRowClick: d
603
3180
  r = r[e];
604
3181
  }
605
3182
  return r;
606
- }, s = (e) => {
3183
+ }, h = (e) => {
607
3184
  let t = [
608
- o(e, n),
3185
+ m(e, n),
609
3186
  e?.name,
610
3187
  e?.title,
611
3188
  e?.subject,
@@ -618,189 +3195,527 @@ var U = ({ schema: e, dataSource: a, className: l, onTaskClick: u, onRowClick: d
618
3195
  ];
619
3196
  for (let e of t) if (e != null && String(e).trim() !== "") return String(e);
620
3197
  return "Untitled";
3198
+ }, g = (e, t) => {
3199
+ if (t) return t;
3200
+ let n = f[e] ?? f[e.split(".")[0]];
3201
+ return n?.label ? n.label : fe(e);
3202
+ }, _ = (e, t) => {
3203
+ if (e == null || e === "") return "—";
3204
+ let n = f[t] ?? f[t.split(".")[0]], r = n?.type, i = n?.options;
3205
+ if (Array.isArray(i) && i.length) {
3206
+ let t = i.find((t) => String(t.value) === String(e));
3207
+ if (t) return t.label;
3208
+ }
3209
+ switch (r) {
3210
+ case "date": return ce(e);
3211
+ case "datetime": return x(e);
3212
+ case "number":
3213
+ case "integer":
3214
+ case "float":
3215
+ case "decimal": return le(Number(e));
3216
+ case "currency": return se(Number(e), p(n, _e));
3217
+ case "percent": return S(Number(e));
3218
+ case "boolean":
3219
+ case "checkbox": return e ? "Yes" : "No";
3220
+ default:
3221
+ if (Array.isArray(e)) {
3222
+ let t = e.map((e) => {
3223
+ if (e == null) return "";
3224
+ if (typeof e == "object") {
3225
+ let t = e;
3226
+ return String(t.name ?? t.label ?? t.title ?? t.id ?? "");
3227
+ }
3228
+ return String(e);
3229
+ }).filter(Boolean);
3230
+ return t.length ? t.join(", ") : "—";
3231
+ }
3232
+ if (typeof e == "object") {
3233
+ let t = e;
3234
+ return String(t.name ?? t.label ?? t.title ?? t.id ?? "—");
3235
+ }
3236
+ return String(e);
3237
+ }
3238
+ }, v = (e) => {
3239
+ if (!l || !l.length) return;
3240
+ let t = [];
3241
+ for (let n of l) {
3242
+ let r = typeof n == "string" ? n : n?.field;
3243
+ if (!r) continue;
3244
+ let i = typeof n == "object" ? n.label : void 0;
3245
+ t.push({
3246
+ label: g(r, i),
3247
+ value: _(m(e, r), r)
3248
+ });
3249
+ }
3250
+ return t.length ? t : void 0;
621
3251
  };
622
- return C.map((n, o) => {
623
- let c = n[e], l = n[t], u = s(n), d = r ? n[r] : 0, f = i ? n[i] : [], p = a ? n[a] : void 0;
624
- if (!p) {
3252
+ return y.map((n, l) => {
3253
+ let f = n[e], p = n[t], m = u ? n[u] : void 0, g = d ? n[d] : void 0, _ = m ? new Date(m) : void 0, ee = g ? new Date(g) : void 0, te = h(n), ne = r ? n[r] : 0, re = i ? n[i] : [], ie = a ? n[a] : void 0;
3254
+ if (!ie) {
625
3255
  let e = n.status ?? n.state ?? n.priority ?? n.severity;
626
3256
  if (e != null && e !== "") {
627
- let t = T(void 0, e);
628
- t && (p = E(t));
3257
+ let t = ue(void 0, e);
3258
+ t && (ie = de(t));
629
3259
  }
630
3260
  }
631
3261
  return {
632
- id: n.id || n._id || `task-${o}`,
633
- title: u,
634
- start: c ? new Date(c) : /* @__PURE__ */ new Date(),
635
- end: l ? new Date(l) : /* @__PURE__ */ new Date(),
636
- progress: Math.min(100, Math.max(0, d || 0)),
637
- dependencies: Array.isArray(f) ? f : [],
638
- color: p,
3262
+ id: n.id || n._id || `task-${l}`,
3263
+ title: te,
3264
+ start: f ? new Date(f) : /* @__PURE__ */ new Date(),
3265
+ end: p ? new Date(p) : /* @__PURE__ */ new Date(),
3266
+ progress: Math.min(100, Math.max(0, ne || 0)),
3267
+ dependencies: gt(re),
3268
+ parent: o ? n[o] ?? null : void 0,
3269
+ type: s ? mt(n[s]) : void 0,
3270
+ locked: c ? !!n[c] : void 0,
3271
+ color: ie,
3272
+ baselineStart: _ && !isNaN(_.getTime()) ? _ : void 0,
3273
+ baselineEnd: ee && !isNaN(ee.getTime()) ? ee : void 0,
3274
+ fields: v(n),
639
3275
  data: n
640
3276
  };
641
3277
  }).filter((e) => !isNaN(e.start.getTime()) && !isNaN(e.end.getTime()));
642
- }, [C, F]), L = e.navigation ?? {
3278
+ }, [
3279
+ y,
3280
+ T,
3281
+ C
3282
+ ]), be = r(() => {
3283
+ let e = T?.groupByField;
3284
+ if (!e) return;
3285
+ let t = C?.fields ?? {}, n = (e, t) => {
3286
+ if (!t) return;
3287
+ let n = e;
3288
+ for (let e of t.split(".")) {
3289
+ if (n == null) return;
3290
+ n = n[e];
3291
+ }
3292
+ return n;
3293
+ }, r = (n) => {
3294
+ let r = (t[e] ?? t[e.split(".")[0]])?.options;
3295
+ if (Array.isArray(r) && r.length) {
3296
+ let e = r.find((e) => String(e.value) === String(n));
3297
+ if (e) return e.label;
3298
+ }
3299
+ if (typeof n == "object" && n) {
3300
+ let e = n;
3301
+ return String(e.name ?? e.label ?? e.title ?? e.id ?? n);
3302
+ }
3303
+ return String(n);
3304
+ };
3305
+ return (t) => {
3306
+ let i = n(t.data, e);
3307
+ return i == null || i === "" ? null : {
3308
+ key: typeof i == "object" && i ? String(i.id ?? i._id ?? r(i)) : i,
3309
+ label: r(i)
3310
+ };
3311
+ };
3312
+ }, [T?.groupByField, C]), xe = r(() => {
3313
+ let e = T?.assigneeField;
3314
+ if (!e) return;
3315
+ let t = C?.fields ?? {}, n = (e, t) => {
3316
+ if (!t) return;
3317
+ let n = e;
3318
+ for (let e of t.split(".")) {
3319
+ if (n == null) return;
3320
+ n = n[e];
3321
+ }
3322
+ return n;
3323
+ }, r = (n) => {
3324
+ let r = (t[e] ?? t[e.split(".")[0]])?.options;
3325
+ if (Array.isArray(r) && r.length) {
3326
+ let e = r.find((e) => String(e.value) === String(n));
3327
+ if (e) return e.label;
3328
+ }
3329
+ if (typeof n == "object" && n) {
3330
+ let e = n;
3331
+ return String(e.name ?? e.label ?? e.title ?? e.id ?? n);
3332
+ }
3333
+ return String(n);
3334
+ };
3335
+ return (t) => {
3336
+ let i = n(t.data, e);
3337
+ return i == null || i === "" ? null : {
3338
+ key: typeof i == "object" && i ? String(i.id ?? i._id ?? r(i)) : i,
3339
+ label: r(i)
3340
+ };
3341
+ };
3342
+ }, [T?.assigneeField, C]), Se = r(() => {
3343
+ let e = T?.effortField;
3344
+ if (e) return (t) => {
3345
+ let n = t.data?.[e], r = Number(n);
3346
+ return Number.isFinite(r) && r > 0 ? r : 1;
3347
+ };
3348
+ }, [T?.effortField]), Ce = r(() => {
3349
+ let t = e.skipWeekends, n = e.holidays;
3350
+ if (!(!t && (!n || n.length === 0))) return {
3351
+ skipWeekends: !!t,
3352
+ holidays: n && n.length ? new Set(n) : void 0
3353
+ };
3354
+ }, [e]), we = t((e, t) => {
3355
+ if (!e || !t) return null;
3356
+ let n = e;
3357
+ for (let e of t.split(".")) {
3358
+ if (n == null) return null;
3359
+ n = n[e];
3360
+ }
3361
+ if (n == null || n === "") return null;
3362
+ if (typeof n == "object") {
3363
+ let e = n;
3364
+ return String(e.id ?? e._id ?? e.value ?? e.name ?? "");
3365
+ }
3366
+ return String(n);
3367
+ }, []), Te = T?.quickFilters, [Ee, Oe] = a({});
3368
+ n(() => {
3369
+ if (!Te?.length || !i || typeof i.find != "function") return;
3370
+ let e = C?.fields ?? {}, t = !1;
3371
+ return (async () => {
3372
+ let n = {};
3373
+ for (let t of Te) {
3374
+ if (t.options) continue;
3375
+ let r = e[t.field] ?? e[t.field.split(".")[0]], a = r?.type;
3376
+ if (a !== "lookup" && a !== "master_detail") continue;
3377
+ let o = r?.reference_to ?? r?.referenceTo;
3378
+ if (o) try {
3379
+ let e = c(await i.find(o, { $top: 1e3 }));
3380
+ n[t.field] = e.map((e) => ({
3381
+ value: String(e.id ?? e._id ?? e.value ?? ""),
3382
+ label: String(e.name ?? e.label ?? e.title ?? e.id ?? e._id ?? "")
3383
+ }));
3384
+ } catch (e) {
3385
+ console.warn(`[ObjectGantt] Failed to load quick-filter options for "${t.field}":`, e);
3386
+ }
3387
+ }
3388
+ t || Oe((e) => ({
3389
+ ...e,
3390
+ ...n
3391
+ }));
3392
+ })(), () => {
3393
+ t = !0;
3394
+ };
3395
+ }, [
3396
+ JSON.stringify(Te),
3397
+ i,
3398
+ C
3399
+ ]);
3400
+ let k = r(() => {
3401
+ if (!Te?.length) return [];
3402
+ let e = C?.fields ?? {};
3403
+ return Te.map((t) => {
3404
+ let n = e[t.field] ?? e[t.field.split(".")[0]], r = t.label ?? n?.label ?? fe(t.field), i = [];
3405
+ if (t.options?.length) i = t.options.map((e) => typeof e == "object" ? {
3406
+ value: String(e.value),
3407
+ label: String(e.label ?? e.value)
3408
+ } : {
3409
+ value: String(e),
3410
+ label: String(e)
3411
+ });
3412
+ else if (Array.isArray(n?.options) && n.options.length) i = n.options.map((e) => ({
3413
+ value: String(e.value ?? e),
3414
+ label: String(e.label ?? e.value ?? e)
3415
+ }));
3416
+ else if (Ee[t.field]?.length) i = Ee[t.field];
3417
+ else {
3418
+ let e = /* @__PURE__ */ new Map();
3419
+ for (let n of y) {
3420
+ let r = we(n, t.field);
3421
+ if (r != null && !e.has(r)) {
3422
+ let i = n;
3423
+ for (let e of t.field.split(".")) i = i?.[e];
3424
+ let a = i && typeof i == "object" ? String(i.name ?? i.label ?? i.title ?? r) : r;
3425
+ e.set(r, a);
3426
+ }
3427
+ }
3428
+ i = [...e.entries()].map(([e, t]) => ({
3429
+ value: e,
3430
+ label: t
3431
+ }));
3432
+ }
3433
+ return {
3434
+ field: t.field,
3435
+ label: r,
3436
+ options: i
3437
+ };
3438
+ });
3439
+ }, [
3440
+ Te,
3441
+ C,
3442
+ Ee,
3443
+ y,
3444
+ we
3445
+ ]), [A, j] = a({}), M = t((e, t) => {
3446
+ j((n) => ({
3447
+ ...n,
3448
+ [e]: t
3449
+ }));
3450
+ }, []), ke = t(() => j({}), []), N = r(() => {
3451
+ let e = Object.entries(A).filter(([, e]) => e.length > 0);
3452
+ return e.length ? E.filter((t) => e.every(([e, n]) => {
3453
+ let r = we(t.data, e);
3454
+ return r != null && n.includes(r);
3455
+ })) : E;
3456
+ }, [
3457
+ E,
3458
+ A,
3459
+ we
3460
+ ]), Ae = r(() => {
3461
+ if (T?.autoZoomToFilter !== !1 || !E.length) return null;
3462
+ let e = E[0].start.getTime(), t = E[0].end.getTime();
3463
+ for (let n of E) e = Math.min(e, n.start.getTime()), t = Math.max(t, n.end.getTime());
3464
+ return {
3465
+ start: new Date(e),
3466
+ end: new Date(t)
3467
+ };
3468
+ }, [E, T?.autoZoomToFilter]), P = e.navigation ?? {
643
3469
  mode: "drawer",
644
3470
  width: "min(960px, 60vw)"
645
- }, ie = L.mode === "drawer" || L.mode === "modal" || L.mode === "split" || L.mode === "popover", R = c({
646
- navigation: L,
3471
+ }, je = P.mode === "drawer" || P.mode === "modal" || P.mode === "split" || P.mode === "popover", Me = l({
3472
+ navigation: P,
647
3473
  objectName: e.objectName,
648
- onRowClick: ie ? void 0 : d
649
- }), ae = t(async (t, n) => {
650
- if (!F) return;
651
- let r = P?.provider === "object" ? P.object : e.objectName;
652
- if (!r || !a || typeof a.update != "function") return;
653
- let { startDateField: i, endDateField: o, titleField: s, progressField: c } = F, l = {};
654
- if (n.start instanceof Date && (l[i] = n.start.toISOString()), n.end instanceof Date && (l[o] = n.end.toISOString()), typeof n.title == "string" && s && (l[s] = n.title), typeof n.progress == "number" && c && (l[c] = n.progress), Object.keys(l).length === 0) return;
3474
+ onRowClick: je ? void 0 : d
3475
+ }), Ne = t(async (t, n) => {
3476
+ if (!T) return;
3477
+ let r = w?.provider === "object" ? w.object : e.objectName;
3478
+ if (!r || !i || typeof i.update != "function") return;
3479
+ let { startDateField: a, endDateField: o, titleField: s, progressField: c } = T, l = {};
3480
+ if (n.start instanceof Date && (l[a] = n.start.toISOString()), n.end instanceof Date && (l[o] = n.end.toISOString()), typeof n.title == "string" && s && (l[s] = n.title), typeof n.progress == "number" && c && (l[c] = n.progress), Object.keys(l).length === 0) return;
655
3481
  let u = t.data?.id ?? t.data?._id ?? t.id;
656
3482
  if (u == null) return;
657
- let d = C;
658
- w((e) => e.map((e) => String(e.id ?? e._id) === String(u) ? {
3483
+ let d = y;
3484
+ b((e) => e.map((e) => String(e.id ?? e._id) === String(u) ? {
659
3485
  ...e,
660
3486
  ...l
661
3487
  } : e));
662
3488
  try {
663
- await a.update(r, String(u), l);
3489
+ await i.update(r, String(u), l);
664
3490
  } catch (e) {
665
- console.error("[ObjectGantt] Failed to persist task update:", e), w(d);
3491
+ console.error("[ObjectGantt] Failed to persist task update:", e), b(d);
666
3492
  }
667
3493
  }, [
668
- F,
669
- P,
670
- a,
3494
+ T,
3495
+ w,
3496
+ i,
671
3497
  e.objectName,
672
- C
673
- ]), [U, W] = i(null), [G, K] = i(!1), q = t((e) => {
674
- W(e);
675
- }, []), J = t(async () => {
676
- if (!U) return;
677
- let t = P?.provider === "object" ? P.object : e.objectName;
678
- if (!t || !a?.delete) {
679
- W(null);
3498
+ y
3499
+ ]), F = (e, t) => {
3500
+ let n = t.some((e) => typeof e == "object" && e.type && e.type !== "fs");
3501
+ return !n && typeof e == "string" ? t.map((e) => String(typeof e == "object" ? e.id : e)).join(",") : n ? t.map((e) => typeof e == "object" ? e.type && e.type !== "fs" ? {
3502
+ id: e.id,
3503
+ type: e.type
3504
+ } : e.id : e) : t.map((e) => typeof e == "object" ? e.id : e);
3505
+ }, Pe = t(async (t, n, r) => {
3506
+ let a = T?.dependenciesField;
3507
+ if (!a) return;
3508
+ let o = w?.provider === "object" ? w.object : e.objectName;
3509
+ if (!o || !i || typeof i.update != "function") return;
3510
+ let s = F(n, r), c = y;
3511
+ b((e) => e.map((e) => String(e.id ?? e._id) === String(t) ? {
3512
+ ...e,
3513
+ [a]: s
3514
+ } : e));
3515
+ try {
3516
+ await i.update(o, String(t), { [a]: s });
3517
+ } catch (e) {
3518
+ console.error("[ObjectGantt] Failed to persist dependency:", e), b(c);
3519
+ }
3520
+ }, [
3521
+ T,
3522
+ w,
3523
+ i,
3524
+ e.objectName,
3525
+ y
3526
+ ]), Fe = t(async (e, t, n = "fs") => {
3527
+ let r = e.data?.id ?? e.data?._id ?? e.id, i = t.data?.id ?? t.data?._id ?? t.id;
3528
+ if (r == null || i == null) return;
3529
+ let a = T?.dependenciesField;
3530
+ if (!a) return;
3531
+ let o = y.find((e) => String(e.id ?? e._id) === String(i))?.[a], s = gt(o), c = (e) => String(typeof e == "object" ? e.id : e), l = s.find((e) => c(e) === String(r)), u = l && typeof l == "object" ? l.type ?? "fs" : "fs";
3532
+ if (l && u === n) return;
3533
+ let d = n === "fs" ? r : {
3534
+ id: r,
3535
+ type: n
3536
+ };
3537
+ await Pe(i, o, l ? s.map((e) => c(e) === String(r) ? d : e) : [...s, d]);
3538
+ }, [
3539
+ T,
3540
+ y,
3541
+ Pe
3542
+ ]), Ie = t(async (e, t) => {
3543
+ let n = e.data?.id ?? e.data?._id ?? e.id, r = t.data?.id ?? t.data?._id ?? t.id;
3544
+ if (n == null || r == null) return;
3545
+ let i = T?.dependenciesField;
3546
+ if (!i) return;
3547
+ let a = y.find((e) => String(e.id ?? e._id) === String(r))?.[i], o = gt(a), s = (e) => String(typeof e == "object" ? e.id : e), c = o.filter((e) => s(e) !== String(n));
3548
+ c.length !== o.length && await Pe(r, a, c);
3549
+ }, [
3550
+ T,
3551
+ y,
3552
+ Pe
3553
+ ]), [I, Le] = a(null), [Re, ze] = a(!1), Be = t((e) => {
3554
+ Le(e);
3555
+ }, []), Ve = t(async () => {
3556
+ if (!I) return;
3557
+ let t = w?.provider === "object" ? w.object : e.objectName;
3558
+ if (!t || !i?.delete) {
3559
+ Le(null);
680
3560
  return;
681
3561
  }
682
- let n = U.data?.id ?? U.data?._id ?? U.id;
3562
+ let n = I.data?.id ?? I.data?._id ?? I.id;
683
3563
  if (n == null) {
684
- W(null);
3564
+ Le(null);
685
3565
  return;
686
3566
  }
687
- K(!0);
688
- let r = C;
689
- w((e) => e.filter((e) => String(e.id ?? e._id) !== String(n)));
3567
+ ze(!0);
3568
+ let r = y;
3569
+ b((e) => e.filter((e) => String(e.id ?? e._id) !== String(n)));
690
3570
  try {
691
- await a.delete(t, String(n)), W(null);
3571
+ await i.delete(t, String(n)), Le(null);
692
3572
  } catch (e) {
693
- console.error("[ObjectGantt] Failed to delete:", e), w(r), W(null);
3573
+ console.error("[ObjectGantt] Failed to delete:", e), b(r), Le(null);
694
3574
  } finally {
695
- K(!1);
3575
+ ze(!1);
696
3576
  }
697
3577
  }, [
698
- U,
699
- P,
700
- a,
3578
+ I,
3579
+ w,
3580
+ i,
701
3581
  e.objectName,
702
- C
3582
+ y
703
3583
  ]);
704
- return ee ? /* @__PURE__ */ M("div", {
705
- className: l,
706
- children: /* @__PURE__ */ M("div", {
3584
+ return oe ? /* @__PURE__ */ D("div", {
3585
+ className: o,
3586
+ children: /* @__PURE__ */ D("div", {
707
3587
  className: "flex items-center justify-center h-96",
708
- children: /* @__PURE__ */ M("div", {
3588
+ children: /* @__PURE__ */ D("div", {
709
3589
  className: "text-muted-foreground",
710
3590
  children: "Loading Gantt chart..."
711
3591
  })
712
3592
  })
713
- }) : O ? /* @__PURE__ */ M("div", {
714
- className: l,
715
- children: /* @__PURE__ */ M("div", {
3593
+ }) : me ? /* @__PURE__ */ D("div", {
3594
+ className: o,
3595
+ children: /* @__PURE__ */ D("div", {
716
3596
  className: "flex items-center justify-center h-96",
717
- children: /* @__PURE__ */ N("div", {
3597
+ children: /* @__PURE__ */ O("div", {
718
3598
  className: "text-destructive",
719
- children: ["Error: ", O.message]
3599
+ children: ["Error: ", me.message]
720
3600
  })
721
3601
  })
722
- }) : F ? /* @__PURE__ */ N("div", {
723
- className: l,
3602
+ }) : T ? /* @__PURE__ */ O("div", {
3603
+ className: o,
724
3604
  children: [
725
- /* @__PURE__ */ M("div", {
3605
+ k.length > 0 && /* @__PURE__ */ D(z, {
3606
+ filters: k,
3607
+ value: A,
3608
+ onChange: M,
3609
+ onClear: ke,
3610
+ resultCount: N.length,
3611
+ totalCount: E.length,
3612
+ labels: {
3613
+ all: "全部",
3614
+ clear: "清除筛选",
3615
+ empty: "无可选项",
3616
+ resultSummary: (e, t) => `显示 ${e} / ${t} 项任务`
3617
+ }
3618
+ }),
3619
+ /* @__PURE__ */ D("div", {
726
3620
  className: "h-[calc(100vh-200px)] min-h-[600px]",
727
- children: /* @__PURE__ */ M(z, {
728
- tasks: re,
3621
+ children: T?.resourceView && xe ? /* @__PURE__ */ D(ct, {
3622
+ tasks: N,
3623
+ assignee: xe,
3624
+ effort: Se,
3625
+ capacity: T?.capacity ?? 1,
3626
+ viewMode: e.viewMode || "day"
3627
+ }) : /* @__PURE__ */ D(tt, {
3628
+ tasks: N,
3629
+ startDate: Ae?.start,
3630
+ endDate: Ae?.end,
729
3631
  onTaskClick: (e) => {
730
- R.handleClick(e.data), u?.(e.data);
3632
+ Me.handleClick(e.data), u?.(e.data);
731
3633
  },
732
- onTaskUpdate: ae,
733
- onTaskDelete: q,
3634
+ onTaskUpdate: Ne,
3635
+ onTaskDelete: Be,
3636
+ onDependencyCreate: T?.dependenciesField ? Fe : void 0,
3637
+ onDependencyDelete: T?.dependenciesField ? Ie : void 0,
3638
+ markers: e.markers,
3639
+ autoSchedule: !!T?.dependenciesField,
3640
+ rescheduleOnConflict: !!T?.dependenciesField,
3641
+ criticalPathDefault: !!e.criticalPath,
3642
+ workingCalendar: Ce,
3643
+ showBaselines: e.showBaselines !== !1,
3644
+ readOnly: !!e.readOnly,
3645
+ mobileReadOnly: e.mobileReadOnly !== !1,
3646
+ persistLayoutKey: e.persistLayout === !1 ? void 0 : `${e.objectName || (w?.provider === "object" ? w.object : "") || "gantt"}:${e.viewName || "default"}`,
3647
+ groupBy: be,
3648
+ defaultCollapsedDepth: T?.defaultCollapsedDepth,
734
3649
  inlineEdit: !0
735
3650
  })
736
3651
  }),
737
- R.isOverlay && R.isOpen && R.selectedRecord && (() => {
738
- let t = P?.provider === "object" ? P.object : e.objectName, n = R.selectedRecord, r = n.id ?? n._id;
3652
+ Me.isOverlay && Me.isOpen && Me.selectedRecord && (() => {
3653
+ let t = w?.provider === "object" ? w.object : e.objectName, n = Me.selectedRecord, r = n.id ?? n._id;
739
3654
  if (!t || r == null) return null;
740
- let i = F?.titleField ? String(n[F.titleField] ?? "Task Details") : "Task Details";
741
- return /* @__PURE__ */ M(f, {
3655
+ let a = T?.titleField ? String(n[T.titleField] ?? "Task Details") : "Task Details";
3656
+ return /* @__PURE__ */ D(h, {
742
3657
  open: !0,
743
- onClose: R.close,
744
- title: i,
3658
+ onClose: Me.close,
3659
+ title: a,
745
3660
  record: n,
746
3661
  objectName: t,
747
3662
  recordId: r,
748
- dataSource: a,
749
- objectSchema: k,
750
- width: R.width,
751
- fullPageHref: p(t, r) ?? void 0,
3663
+ dataSource: i,
3664
+ objectSchema: C,
3665
+ width: Me.width,
3666
+ fullPageHref: g(t, r) ?? void 0,
752
3667
  onFieldSave: async (e, n) => {
753
- a?.update && (await a.update(t, String(r), { [e]: n }), w((t) => t.map((t) => String(t.id ?? t._id) === String(r) ? {
3668
+ i?.update && (await i.update(t, String(r), { [e]: n }), b((t) => t.map((t) => String(t.id ?? t._id) === String(r) ? {
754
3669
  ...t,
755
3670
  [e]: n
756
3671
  } : t)));
757
3672
  },
758
3673
  onDelete: async () => {
759
- a?.delete && (await a.delete(t, String(r)), w((e) => e.filter((e) => String(e.id ?? e._id) !== String(r))));
3674
+ i?.delete && (await i.delete(t, String(r)), b((e) => e.filter((e) => String(e.id ?? e._id) !== String(r))));
760
3675
  }
761
3676
  });
762
3677
  })(),
763
- /* @__PURE__ */ M(m, {
764
- open: !!U,
3678
+ /* @__PURE__ */ D(_, {
3679
+ open: !!I,
765
3680
  onOpenChange: (e) => {
766
- !e && !G && W(null);
3681
+ !e && !Re && Le(null);
767
3682
  },
768
- children: /* @__PURE__ */ N(_, { children: [/* @__PURE__ */ N(b, { children: [/* @__PURE__ */ M(x, { children: "Delete this task?" }), /* @__PURE__ */ M(v, { children: U ? /* @__PURE__ */ N(j, { children: [
3683
+ children: /* @__PURE__ */ O(te, { children: [/* @__PURE__ */ O(ie, { children: [/* @__PURE__ */ D(ae, { children: "Delete this task?" }), /* @__PURE__ */ D(ne, { children: I ? /* @__PURE__ */ O(De, { children: [
769
3684
  "\"",
770
- U.title,
3685
+ I.title,
771
3686
  "\" will be permanently removed. This action cannot be undone."
772
- ] }) : null })] }), /* @__PURE__ */ N(y, { children: [/* @__PURE__ */ M(g, {
773
- disabled: G,
3687
+ ] }) : null })] }), /* @__PURE__ */ O(re, { children: [/* @__PURE__ */ D(ee, {
3688
+ disabled: Re,
774
3689
  children: "Cancel"
775
- }), /* @__PURE__ */ M(h, {
3690
+ }), /* @__PURE__ */ D(v, {
776
3691
  onClick: (e) => {
777
- e.preventDefault(), J();
3692
+ e.preventDefault(), Ve();
778
3693
  },
779
- disabled: G,
3694
+ disabled: Re,
780
3695
  "data-testid": "gantt-delete-confirm",
781
3696
  className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
782
- children: G ? "Deleting…" : "Delete"
3697
+ children: Re ? "Deleting…" : "Delete"
783
3698
  })] })] })
784
3699
  })
785
3700
  ]
786
- }) : /* @__PURE__ */ M("div", {
787
- className: l,
788
- children: /* @__PURE__ */ M("div", {
3701
+ }) : /* @__PURE__ */ D("div", {
3702
+ className: o,
3703
+ children: /* @__PURE__ */ D("div", {
789
3704
  className: "flex items-center justify-center h-96",
790
- children: /* @__PURE__ */ M("div", {
3705
+ children: /* @__PURE__ */ D("div", {
791
3706
  className: "text-muted-foreground",
792
3707
  children: "Gantt configuration required. Please specify startDateField, endDateField, and titleField."
793
3708
  })
794
3709
  })
795
3710
  });
796
- }, W = ({ schema: e }) => {
797
- let { dataSource: t } = u() || {};
798
- return /* @__PURE__ */ M(U, {
3711
+ }, xt = ({ schema: e }) => {
3712
+ let { dataSource: t } = d() || {};
3713
+ return /* @__PURE__ */ D(bt, {
799
3714
  schema: e,
800
3715
  dataSource: t
801
3716
  });
802
3717
  };
803
- a.register("object-gantt", W, {
3718
+ o.register("object-gantt", xt, {
804
3719
  namespace: "plugin-gantt",
805
3720
  label: "Object Gantt",
806
3721
  category: "view",
@@ -815,7 +3730,7 @@ a.register("object-gantt", W, {
815
3730
  label: "Gantt Config",
816
3731
  description: "startDateField, endDateField, titleField, progressField, percentageField, colorField, dependenciesField"
817
3732
  }]
818
- }), a.register("gantt", W, {
3733
+ }), o.register("gantt", xt, {
819
3734
  namespace: "view",
820
3735
  label: "Gantt View",
821
3736
  category: "view",
@@ -832,4 +3747,4 @@ a.register("object-gantt", W, {
832
3747
  }]
833
3748
  });
834
3749
  //#endregion
835
- export { z as GanttView, U as ObjectGantt, W as ObjectGanttRenderer };
3750
+ export { tt as GanttView, bt as ObjectGantt, xt as ObjectGanttRenderer, z as QuickFilterBar, ct as ResourceWorkload, rt as computeWorkload, gt as normalizeDependencies, mt as normalizeTaskType };