@matsu1321/react-gantt-chart 1.0.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 ADDED
@@ -0,0 +1,1996 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const React = require("react");
5
+ const reactDom = require("react-dom");
6
+ var ViewMode = /* @__PURE__ */ ((ViewMode2) => {
7
+ ViewMode2["Hour"] = "Hour";
8
+ ViewMode2["QuarterDay"] = "Quarter Day";
9
+ ViewMode2["HalfDay"] = "Half Day";
10
+ ViewMode2["Day"] = "Day";
11
+ ViewMode2["Week"] = "Week";
12
+ ViewMode2["Month"] = "Month";
13
+ ViewMode2["Year"] = "Year";
14
+ return ViewMode2;
15
+ })(ViewMode || {});
16
+ const cache = {};
17
+ const getCachedDateTimeFormat = (locString, opts) => {
18
+ const key = JSON.stringify([locString, opts]);
19
+ let format = cache[key];
20
+ if (!format) {
21
+ format = new Intl.DateTimeFormat(locString, opts);
22
+ cache[key] = format;
23
+ }
24
+ return format;
25
+ };
26
+ const addToDate = (date, quantity, scale) => {
27
+ const newDate = new Date(date.getTime());
28
+ switch (scale) {
29
+ case "millisecond":
30
+ newDate.setMilliseconds(newDate.getMilliseconds() + quantity);
31
+ break;
32
+ case "second":
33
+ newDate.setSeconds(newDate.getSeconds() + quantity);
34
+ break;
35
+ case "minute":
36
+ newDate.setMinutes(newDate.getMinutes() + quantity);
37
+ break;
38
+ case "hour":
39
+ newDate.setHours(newDate.getHours() + quantity);
40
+ break;
41
+ case "day":
42
+ newDate.setDate(newDate.getDate() + quantity);
43
+ break;
44
+ case "week":
45
+ newDate.setDate(newDate.getDate() + quantity * 7);
46
+ break;
47
+ case "month":
48
+ newDate.setMonth(newDate.getMonth() + quantity);
49
+ break;
50
+ case "year":
51
+ newDate.setFullYear(newDate.getFullYear() + quantity);
52
+ break;
53
+ }
54
+ return newDate;
55
+ };
56
+ const startOfDate = (date, scale) => {
57
+ const newDate = new Date(date.getTime());
58
+ switch (scale) {
59
+ case "year":
60
+ newDate.setMonth(0, 1);
61
+ newDate.setHours(0, 0, 0, 0);
62
+ break;
63
+ case "month":
64
+ newDate.setDate(1);
65
+ newDate.setHours(0, 0, 0, 0);
66
+ break;
67
+ case "week":
68
+ const day = newDate.getDay();
69
+ const diff = newDate.getDate() - day + (day === 0 ? -6 : 1);
70
+ newDate.setDate(diff);
71
+ newDate.setHours(0, 0, 0, 0);
72
+ break;
73
+ case "day":
74
+ newDate.setHours(0, 0, 0, 0);
75
+ break;
76
+ case "hour":
77
+ newDate.setMinutes(0, 0, 0);
78
+ break;
79
+ case "minute":
80
+ newDate.setSeconds(0, 0);
81
+ break;
82
+ case "second":
83
+ newDate.setMilliseconds(0);
84
+ break;
85
+ }
86
+ return newDate;
87
+ };
88
+ const getWeekNumberISO8601 = (date) => {
89
+ const tempDate = new Date(date.valueOf());
90
+ const dayNum = (date.getDay() + 6) % 7;
91
+ tempDate.setDate(tempDate.getDate() - dayNum + 3);
92
+ const firstThursday = tempDate.valueOf();
93
+ tempDate.setMonth(0, 4);
94
+ const dayNumJan4 = (tempDate.getDay() + 6) % 7;
95
+ tempDate.setDate(tempDate.getDate() - dayNumJan4 + 3);
96
+ const weekNum = 1 + Math.round((firstThursday - tempDate.valueOf()) / 6048e5);
97
+ return weekNum < 10 ? `0${weekNum}` : `${weekNum}`;
98
+ };
99
+ const seedDates = (startDate, endDate, viewMode) => {
100
+ let currentDate = new Date(startDate.getTime());
101
+ const dates = [];
102
+ while (currentDate.getTime() < endDate.getTime()) {
103
+ dates.push(currentDate);
104
+ switch (viewMode) {
105
+ case ViewMode.Hour:
106
+ currentDate = addToDate(currentDate, 1, "hour");
107
+ break;
108
+ case ViewMode.QuarterDay:
109
+ currentDate = addToDate(currentDate, 6, "hour");
110
+ break;
111
+ case ViewMode.HalfDay:
112
+ currentDate = addToDate(currentDate, 12, "hour");
113
+ break;
114
+ case ViewMode.Day:
115
+ currentDate = addToDate(currentDate, 1, "day");
116
+ break;
117
+ case ViewMode.Week:
118
+ currentDate = addToDate(currentDate, 7, "day");
119
+ break;
120
+ case ViewMode.Month:
121
+ currentDate = addToDate(currentDate, 1, "month");
122
+ break;
123
+ case ViewMode.Year:
124
+ currentDate = addToDate(currentDate, 1, "year");
125
+ break;
126
+ }
127
+ }
128
+ return dates;
129
+ };
130
+ const ganttDateRange = (tasks, viewMode, preStepsCount) => {
131
+ let minDate = /* @__PURE__ */ new Date();
132
+ let maxDate = /* @__PURE__ */ new Date();
133
+ if (tasks.length > 0) {
134
+ let min = tasks[0].start.getTime();
135
+ let max = tasks[0].end.getTime();
136
+ for (let i = 1; i < tasks.length; i++) {
137
+ if (tasks[i].start.getTime() < min) min = tasks[i].start.getTime();
138
+ if (tasks[i].end.getTime() > max) max = tasks[i].end.getTime();
139
+ }
140
+ minDate = new Date(min);
141
+ maxDate = new Date(max);
142
+ }
143
+ let start = new Date(minDate.getTime());
144
+ let end = new Date(maxDate.getTime());
145
+ switch (viewMode) {
146
+ case ViewMode.Hour:
147
+ start = startOfDate(start, "day");
148
+ start = addToDate(start, -preStepsCount, "hour");
149
+ end = addToDate(end, 2, "day");
150
+ break;
151
+ case ViewMode.QuarterDay:
152
+ start = startOfDate(start, "day");
153
+ start = addToDate(start, -preStepsCount * 6, "hour");
154
+ end = addToDate(end, 3, "day");
155
+ break;
156
+ case ViewMode.HalfDay:
157
+ start = startOfDate(start, "day");
158
+ start = addToDate(start, -preStepsCount * 12, "hour");
159
+ end = addToDate(end, 5, "day");
160
+ break;
161
+ case ViewMode.Day:
162
+ start = startOfDate(start, "day");
163
+ start = addToDate(start, -preStepsCount, "day");
164
+ end = startOfDate(end, "day");
165
+ end = addToDate(end, 1, "month");
166
+ break;
167
+ case ViewMode.Week:
168
+ start = startOfDate(start, "week");
169
+ start = addToDate(start, -preStepsCount * 7, "day");
170
+ end = addToDate(end, 1.5, "month");
171
+ break;
172
+ case ViewMode.Month:
173
+ start = startOfDate(start, "month");
174
+ start = addToDate(start, -preStepsCount, "month");
175
+ end = startOfDate(end, "month");
176
+ end = addToDate(end, 1, "year");
177
+ break;
178
+ case ViewMode.Year:
179
+ start = startOfDate(start, "year");
180
+ start = addToDate(start, -preStepsCount, "year");
181
+ end = startOfDate(end, "year");
182
+ end = addToDate(end, 1, "year");
183
+ break;
184
+ }
185
+ return seedDates(start, end, viewMode);
186
+ };
187
+ const taskXCoordinate = (date, dates, columnWidth) => {
188
+ const dateVal = date.getTime();
189
+ const startVal = dates[0].getTime();
190
+ if (dateVal <= startVal) return 0;
191
+ const endVal = dates[dates.length - 1].getTime();
192
+ if (dateVal >= endVal) return (dates.length - 1) * columnWidth;
193
+ for (let i = 0; i < dates.length - 1; i++) {
194
+ const d1 = dates[i].getTime();
195
+ const d2 = dates[i + 1].getTime();
196
+ if (dateVal >= d1 && dateVal < d2) {
197
+ const ratio = (dateVal - d1) / (d2 - d1);
198
+ return i * columnWidth + ratio * columnWidth;
199
+ }
200
+ }
201
+ return 0;
202
+ };
203
+ const convertToRenderedTasks = (tasks, dates, columnWidth, rowHeight, taskHeight, barCornerRadius, handleWidth, rtl, barProgressColor, barProgressSelectedColor, barBackgroundColor, barBackgroundSelectedColor, projectProgressColor, projectProgressSelectedColor, projectBackgroundColor, projectBackgroundSelectedColor, milestoneBackgroundColor, milestoneBackgroundSelectedColor) => {
204
+ const renderedTasks = [];
205
+ for (let i = 0; i < tasks.length; i++) {
206
+ const t = tasks[i];
207
+ const y = i * rowHeight + (rowHeight - taskHeight) / 2;
208
+ let x1 = 0;
209
+ let x2 = 0;
210
+ if (t.type === "milestone") {
211
+ const x = taskXCoordinate(t.start, dates, columnWidth);
212
+ x1 = x - taskHeight / 2;
213
+ x2 = x + taskHeight / 2;
214
+ } else {
215
+ x1 = taskXCoordinate(t.start, dates, columnWidth);
216
+ x2 = taskXCoordinate(t.end, dates, columnWidth);
217
+ }
218
+ if (x2 < x1) x2 = x1;
219
+ const width = x2 - x1;
220
+ let typeInternal = t.type;
221
+ if (t.type === "task" && width < 80) {
222
+ typeInternal = "smalltask";
223
+ }
224
+ const [progressWidth, progressX] = calcProgressGeometry(x1, x2, t.progress, rtl);
225
+ const styleDefaults = {
226
+ backgroundColor: barBackgroundColor,
227
+ backgroundSelectedColor: barBackgroundSelectedColor,
228
+ progressColor: barProgressColor,
229
+ progressSelectedColor: barProgressSelectedColor
230
+ };
231
+ if (t.type === "project") {
232
+ styleDefaults.backgroundColor = projectBackgroundColor;
233
+ styleDefaults.backgroundSelectedColor = projectBackgroundSelectedColor;
234
+ styleDefaults.progressColor = projectProgressColor;
235
+ styleDefaults.progressSelectedColor = projectProgressSelectedColor;
236
+ } else if (t.type === "milestone") {
237
+ styleDefaults.backgroundColor = milestoneBackgroundColor;
238
+ styleDefaults.backgroundSelectedColor = milestoneBackgroundSelectedColor;
239
+ styleDefaults.progressColor = "";
240
+ styleDefaults.progressSelectedColor = "";
241
+ }
242
+ const mergedStyles = { ...styleDefaults, ...t.styles };
243
+ const renderedTask = {
244
+ ...t,
245
+ index: i,
246
+ typeInternal,
247
+ x1,
248
+ x2,
249
+ y,
250
+ height: taskHeight,
251
+ progressX,
252
+ progressWidth,
253
+ barCornerRadius,
254
+ handleWidth,
255
+ barChildren: [],
256
+ styles: mergedStyles
257
+ };
258
+ renderedTasks.push(renderedTask);
259
+ }
260
+ for (let i = 0; i < renderedTasks.length; i++) {
261
+ const parent = renderedTasks[i];
262
+ if (parent.type === "project") {
263
+ parent.barChildren = renderedTasks.filter((child) => child.project === parent.id);
264
+ }
265
+ }
266
+ return renderedTasks;
267
+ };
268
+ const calcProgressGeometry = (taskX1, taskX2, progress, rtl) => {
269
+ const width = taskX2 - taskX1;
270
+ const progressWidth = width * (progress / 100);
271
+ const progressX = rtl ? taskX2 - progressWidth : taskX1;
272
+ return [progressWidth, progressX];
273
+ };
274
+ const progressByProgressWidth = (progressWidth, task) => {
275
+ const width = task.x2 - task.x1;
276
+ if (width === 0) return 0;
277
+ const progress = progressWidth / width * 100;
278
+ return Math.min(100, Math.max(0, Math.round(progress)));
279
+ };
280
+ const getProgressHandlePoint = (progressX, taskY, taskHeight) => {
281
+ const y = taskY + taskHeight - 2;
282
+ return `${progressX},${y} ${progressX - 6},${y + 6} ${progressX + 6},${y + 6}`;
283
+ };
284
+ const applyDragToTask = (svgX, action, selectedTask, xStep, timeStep, initEventX1Delta, rtl) => {
285
+ const changedTask = { ...selectedTask };
286
+ let isChanged = false;
287
+ switch (action) {
288
+ case "progress": {
289
+ const progressWidth = svgX - selectedTask.x1;
290
+ const progress = progressByProgressWidth(progressWidth, selectedTask);
291
+ if (progress !== selectedTask.progress) {
292
+ changedTask.progress = progress;
293
+ const [progWidth, progX] = calcProgressGeometry(
294
+ selectedTask.x1,
295
+ selectedTask.x2,
296
+ progress,
297
+ rtl
298
+ );
299
+ changedTask.progressWidth = progWidth;
300
+ changedTask.progressX = progX;
301
+ isChanged = true;
302
+ }
303
+ break;
304
+ }
305
+ case "move": {
306
+ const x1 = svgX - initEventX1Delta;
307
+ const diffX = x1 - selectedTask.x1;
308
+ const steps = Math.round(diffX / xStep);
309
+ if (steps !== 0) {
310
+ const snapX = steps * xStep;
311
+ changedTask.x1 = selectedTask.x1 + snapX;
312
+ changedTask.x2 = selectedTask.x2 + snapX;
313
+ const timeShift = steps * timeStep;
314
+ changedTask.start = new Date(selectedTask.start.getTime() + timeShift);
315
+ changedTask.end = new Date(selectedTask.end.getTime() + timeShift);
316
+ const [progWidth, progX] = calcProgressGeometry(
317
+ changedTask.x1,
318
+ changedTask.x2,
319
+ changedTask.progress,
320
+ rtl
321
+ );
322
+ changedTask.progressWidth = progWidth;
323
+ changedTask.progressX = progX;
324
+ isChanged = true;
325
+ }
326
+ break;
327
+ }
328
+ case "start": {
329
+ const diffX = svgX - selectedTask.x1;
330
+ const steps = Math.round(diffX / xStep);
331
+ if (steps !== 0) {
332
+ const newX1 = selectedTask.x1 + steps * xStep;
333
+ if (newX1 <= selectedTask.x2 - 2 * selectedTask.handleWidth) {
334
+ changedTask.x1 = newX1;
335
+ changedTask.start = new Date(selectedTask.start.getTime() + steps * timeStep);
336
+ const [progWidth, progX] = calcProgressGeometry(
337
+ changedTask.x1,
338
+ changedTask.x2,
339
+ changedTask.progress,
340
+ rtl
341
+ );
342
+ changedTask.progressWidth = progWidth;
343
+ changedTask.progressX = progX;
344
+ const width = changedTask.x2 - changedTask.x1;
345
+ changedTask.typeInternal = changedTask.type === "task" && width < 80 ? "smalltask" : changedTask.type;
346
+ isChanged = true;
347
+ }
348
+ }
349
+ break;
350
+ }
351
+ case "end": {
352
+ const diffX = svgX - selectedTask.x2;
353
+ const steps = Math.round(diffX / xStep);
354
+ if (steps !== 0) {
355
+ const newX2 = selectedTask.x2 + steps * xStep;
356
+ if (newX2 >= selectedTask.x1 + 2 * selectedTask.handleWidth) {
357
+ changedTask.x2 = newX2;
358
+ changedTask.end = new Date(selectedTask.end.getTime() + steps * timeStep);
359
+ const [progWidth, progX] = calcProgressGeometry(
360
+ changedTask.x1,
361
+ changedTask.x2,
362
+ changedTask.progress,
363
+ rtl
364
+ );
365
+ changedTask.progressWidth = progWidth;
366
+ changedTask.progressX = progX;
367
+ const width = changedTask.x2 - changedTask.x1;
368
+ changedTask.typeInternal = changedTask.type === "task" && width < 80 ? "smalltask" : changedTask.type;
369
+ isChanged = true;
370
+ }
371
+ }
372
+ break;
373
+ }
374
+ }
375
+ return { isChanged, changedTask };
376
+ };
377
+ function removeHiddenTasks(tasks) {
378
+ const collapsedProjects = /* @__PURE__ */ new Set();
379
+ tasks.forEach((t) => {
380
+ if (t.type === "project" && t.hideChildren) {
381
+ collapsedProjects.add(t.id);
382
+ }
383
+ });
384
+ const isHidden = (task) => {
385
+ let parentId = task.project;
386
+ while (parentId) {
387
+ if (collapsedProjects.has(parentId)) {
388
+ return true;
389
+ }
390
+ const parent = tasks.find((t) => t.id === parentId);
391
+ parentId = parent == null ? void 0 : parent.project;
392
+ }
393
+ return false;
394
+ };
395
+ return tasks.filter((t) => !isHidden(t));
396
+ }
397
+ const sortTasks = (taskA, taskB) => {
398
+ const orderA = taskA.displayOrder ?? Number.MAX_SAFE_INTEGER;
399
+ const orderB = taskB.displayOrder ?? Number.MAX_SAFE_INTEGER;
400
+ if (orderA > orderB) return 1;
401
+ if (orderA < orderB) return -1;
402
+ return 0;
403
+ };
404
+ const TaskListHeaderDefault = ({ headerHeight, rowWidth, fontFamily, fontSize }) => {
405
+ return /* @__PURE__ */ jsxRuntime.jsxs(
406
+ "div",
407
+ {
408
+ className: "taskListHeader",
409
+ style: {
410
+ fontFamily,
411
+ fontSize,
412
+ height: headerHeight,
413
+ width: rowWidth,
414
+ display: "flex",
415
+ alignItems: "center",
416
+ boxSizing: "border-box"
417
+ },
418
+ children: [
419
+ /* @__PURE__ */ jsxRuntime.jsx(
420
+ "div",
421
+ {
422
+ className: "taskListHeaderCell",
423
+ style: {
424
+ flex: 1,
425
+ minWidth: 150,
426
+ paddingLeft: 10,
427
+ fontWeight: "bold",
428
+ boxSizing: "border-box"
429
+ },
430
+ children: "Name"
431
+ }
432
+ ),
433
+ /* @__PURE__ */ jsxRuntime.jsx(
434
+ "div",
435
+ {
436
+ className: "taskListHeaderCell",
437
+ style: {
438
+ width: 100,
439
+ minWidth: 100,
440
+ paddingLeft: 10,
441
+ fontWeight: "bold",
442
+ borderLeft: "1px solid #e0e0e0",
443
+ boxSizing: "border-box"
444
+ },
445
+ children: "From"
446
+ }
447
+ ),
448
+ /* @__PURE__ */ jsxRuntime.jsx(
449
+ "div",
450
+ {
451
+ className: "taskListHeaderCell",
452
+ style: {
453
+ width: 100,
454
+ minWidth: 100,
455
+ paddingLeft: 10,
456
+ fontWeight: "bold",
457
+ borderLeft: "1px solid #e0e0e0",
458
+ boxSizing: "border-box"
459
+ },
460
+ children: "To"
461
+ }
462
+ )
463
+ ]
464
+ }
465
+ );
466
+ };
467
+ const TaskListTableDefault = ({
468
+ rowHeight,
469
+ rowWidth,
470
+ fontFamily,
471
+ fontSize,
472
+ locale,
473
+ tasks,
474
+ visibleTasks,
475
+ selectedTaskId,
476
+ setSelectedTask,
477
+ onExpanderClick
478
+ }) => {
479
+ const itemsToRender = visibleTasks || tasks;
480
+ const formatDate = React.useMemo(() => {
481
+ const formatter = getCachedDateTimeFormat(locale, {
482
+ day: "numeric",
483
+ month: "numeric",
484
+ year: "numeric"
485
+ });
486
+ return (date) => formatter.format(date);
487
+ }, [locale]);
488
+ return /* @__PURE__ */ jsxRuntime.jsx(
489
+ "div",
490
+ {
491
+ className: "taskListTable",
492
+ style: {
493
+ fontFamily,
494
+ fontSize,
495
+ width: rowWidth,
496
+ height: tasks.length * rowHeight,
497
+ position: "relative"
498
+ },
499
+ children: itemsToRender.map((t) => {
500
+ const renderedTask = t;
501
+ const isSelected = selectedTaskId === t.id;
502
+ let level = 0;
503
+ let parentId = t.project;
504
+ while (parentId) {
505
+ level++;
506
+ const parent = tasks.find((p) => p.id === parentId);
507
+ parentId = parent == null ? void 0 : parent.project;
508
+ }
509
+ return /* @__PURE__ */ jsxRuntime.jsxs(
510
+ "div",
511
+ {
512
+ className: `taskListTableRow ${isSelected ? "taskListTableRowSelected" : ""}`,
513
+ style: {
514
+ height: rowHeight,
515
+ width: "100%",
516
+ position: "absolute",
517
+ top: renderedTask.index * rowHeight,
518
+ display: "flex",
519
+ alignItems: "center",
520
+ cursor: "pointer",
521
+ boxSizing: "border-box",
522
+ backgroundColor: isSelected ? "#f5f5f5" : void 0,
523
+ borderBottom: "1px solid #ebebeb"
524
+ },
525
+ onClick: () => setSelectedTask(t.id),
526
+ children: [
527
+ /* @__PURE__ */ jsxRuntime.jsxs(
528
+ "div",
529
+ {
530
+ className: "taskListTableCell",
531
+ style: {
532
+ flex: 1,
533
+ minWidth: 150,
534
+ paddingLeft: 10 + level * 16,
535
+ display: "flex",
536
+ alignItems: "center",
537
+ overflow: "hidden",
538
+ textOverflow: "ellipsis",
539
+ whiteSpace: "nowrap",
540
+ boxSizing: "border-box"
541
+ },
542
+ children: [
543
+ t.type === "project" ? /* @__PURE__ */ jsxRuntime.jsx(
544
+ "div",
545
+ {
546
+ className: "taskListExpander",
547
+ onClick: (e) => {
548
+ e.stopPropagation();
549
+ onExpanderClick(t);
550
+ },
551
+ style: {
552
+ cursor: "pointer",
553
+ display: "inline-flex",
554
+ alignItems: "center",
555
+ justifyContent: "center",
556
+ width: 16,
557
+ height: 16,
558
+ marginRight: 6,
559
+ userSelect: "none",
560
+ fontSize: "10px",
561
+ color: "#555"
562
+ },
563
+ children: t.hideChildren ? "▶" : "▼"
564
+ }
565
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: 22, height: 16, display: "inline-block" } }),
566
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: t.type === "project" ? "bold" : "normal" }, children: t.name })
567
+ ]
568
+ }
569
+ ),
570
+ /* @__PURE__ */ jsxRuntime.jsx(
571
+ "div",
572
+ {
573
+ className: "taskListTableCell",
574
+ style: {
575
+ width: 100,
576
+ minWidth: 100,
577
+ paddingLeft: 10,
578
+ overflow: "hidden",
579
+ textOverflow: "ellipsis",
580
+ whiteSpace: "nowrap",
581
+ borderLeft: "1px solid #ebebeb",
582
+ boxSizing: "border-box"
583
+ },
584
+ children: formatDate(t.start)
585
+ }
586
+ ),
587
+ /* @__PURE__ */ jsxRuntime.jsx(
588
+ "div",
589
+ {
590
+ className: "taskListTableCell",
591
+ style: {
592
+ width: 100,
593
+ minWidth: 100,
594
+ paddingLeft: 10,
595
+ overflow: "hidden",
596
+ textOverflow: "ellipsis",
597
+ whiteSpace: "nowrap",
598
+ borderLeft: "1px solid #ebebeb",
599
+ boxSizing: "border-box"
600
+ },
601
+ children: formatDate(t.end)
602
+ }
603
+ )
604
+ ]
605
+ },
606
+ t.id
607
+ );
608
+ })
609
+ }
610
+ );
611
+ };
612
+ const TaskList = ({
613
+ headerHeight,
614
+ rowWidth,
615
+ taskListWidth,
616
+ fontFamily,
617
+ fontSize,
618
+ rowHeight,
619
+ locale,
620
+ tasks,
621
+ visibleTasks,
622
+ selectedTask,
623
+ selectedTaskId,
624
+ setSelectedTask,
625
+ onExpanderClick,
626
+ TaskListHeader = TaskListHeaderDefault,
627
+ TaskListTable = TaskListTableDefault
628
+ }) => {
629
+ const resolvedRowWidth = rowWidth || `${taskListWidth || 250}px`;
630
+ const resolvedSelectedTaskId = selectedTaskId || (selectedTask == null ? void 0 : selectedTask.id) || "";
631
+ return /* @__PURE__ */ jsxRuntime.jsxs(
632
+ "div",
633
+ {
634
+ className: "taskListWrapper",
635
+ style: {
636
+ fontFamily,
637
+ fontSize,
638
+ flex: "none",
639
+ width: resolvedRowWidth,
640
+ position: "sticky",
641
+ left: 0,
642
+ zIndex: 20,
643
+ backgroundColor: "#fff"
644
+ },
645
+ children: [
646
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "sticky", top: 0, zIndex: 30, backgroundColor: "#fff" }, children: /* @__PURE__ */ jsxRuntime.jsx(
647
+ TaskListHeader,
648
+ {
649
+ headerHeight,
650
+ rowWidth: resolvedRowWidth,
651
+ fontFamily,
652
+ fontSize
653
+ }
654
+ ) }),
655
+ /* @__PURE__ */ jsxRuntime.jsx(
656
+ "div",
657
+ {
658
+ className: "taskListContainer",
659
+ children: /* @__PURE__ */ jsxRuntime.jsx(
660
+ TaskListTable,
661
+ {
662
+ rowHeight,
663
+ rowWidth: resolvedRowWidth,
664
+ fontFamily,
665
+ fontSize,
666
+ locale,
667
+ tasks,
668
+ visibleTasks,
669
+ selectedTaskId: resolvedSelectedTaskId,
670
+ setSelectedTask,
671
+ onExpanderClick
672
+ }
673
+ )
674
+ }
675
+ )
676
+ ]
677
+ }
678
+ );
679
+ };
680
+ const GridBody = ({
681
+ tasks,
682
+ dates,
683
+ svgWidth,
684
+ rowHeight,
685
+ columnWidth,
686
+ todayColor,
687
+ startIndex = 0,
688
+ endIndex = tasks.length - 1,
689
+ svgHeight
690
+ }) => {
691
+ const y1 = startIndex * rowHeight;
692
+ const y2 = (endIndex + 1) * rowHeight;
693
+ const totalHeight = y2 - y1;
694
+ const rowBackgrounds = React.useMemo(() => {
695
+ const bgs = [];
696
+ for (let i = startIndex; i <= endIndex; i++) {
697
+ const y = i * rowHeight;
698
+ bgs.push(
699
+ /* @__PURE__ */ jsxRuntime.jsx(
700
+ "rect",
701
+ {
702
+ x: 0,
703
+ y,
704
+ width: svgWidth,
705
+ height: rowHeight,
706
+ fill: i % 2 === 0 ? "transparent" : "#fbfbfb",
707
+ className: "gridRow"
708
+ },
709
+ `bg-${i}`
710
+ )
711
+ );
712
+ }
713
+ return bgs;
714
+ }, [startIndex, endIndex, svgWidth, rowHeight]);
715
+ const rowLines = React.useMemo(() => {
716
+ const lines = [];
717
+ for (let i = startIndex; i <= endIndex; i++) {
718
+ const y = i * rowHeight + rowHeight;
719
+ lines.push(
720
+ /* @__PURE__ */ jsxRuntime.jsx(
721
+ "line",
722
+ {
723
+ x1: 0,
724
+ y1: y,
725
+ x2: svgWidth,
726
+ y2: y,
727
+ className: "gridRowLine",
728
+ style: { stroke: "#ebebeb", strokeWidth: 1 }
729
+ },
730
+ `row-line-${i}`
731
+ )
732
+ );
733
+ }
734
+ return lines;
735
+ }, [startIndex, endIndex, svgWidth, rowHeight]);
736
+ const ticks = React.useMemo(() => {
737
+ const tk = [];
738
+ const height = svgHeight || y2;
739
+ for (let i = 0; i < dates.length; i++) {
740
+ const x = i * columnWidth;
741
+ tk.push(
742
+ /* @__PURE__ */ jsxRuntime.jsx(
743
+ "line",
744
+ {
745
+ x1: x,
746
+ y1: 0,
747
+ x2: x,
748
+ y2: height,
749
+ className: "gridTick",
750
+ style: { stroke: "#ebebeb", strokeWidth: 1 }
751
+ },
752
+ `tick-${i}`
753
+ )
754
+ );
755
+ }
756
+ return tk;
757
+ }, [dates, columnWidth, svgHeight, y2]);
758
+ const todayHighlight = React.useMemo(() => {
759
+ var _a, _b;
760
+ const today = /* @__PURE__ */ new Date();
761
+ const startVal = dates[0].getTime();
762
+ const endVal = dates[dates.length - 1].getTime() + (((_a = dates[1]) == null ? void 0 : _a.getTime()) - ((_b = dates[0]) == null ? void 0 : _b.getTime()) || 864e5);
763
+ if (today.getTime() >= startVal && today.getTime() <= endVal) {
764
+ const x = taskXCoordinate(today, dates, columnWidth);
765
+ const colIdx = Math.floor(x / columnWidth);
766
+ const snapX = colIdx * columnWidth;
767
+ return /* @__PURE__ */ jsxRuntime.jsx(
768
+ "rect",
769
+ {
770
+ x: snapX,
771
+ y: 0,
772
+ width: columnWidth,
773
+ height: svgHeight || totalHeight,
774
+ fill: todayColor,
775
+ className: "gridTodayHighlight"
776
+ }
777
+ );
778
+ }
779
+ return null;
780
+ }, [dates, columnWidth, svgHeight, totalHeight, todayColor]);
781
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "gridBody", children: [
782
+ /* @__PURE__ */ jsxRuntime.jsx("g", { className: "rows", children: rowBackgrounds }),
783
+ /* @__PURE__ */ jsxRuntime.jsx("g", { className: "ticks", children: ticks }),
784
+ /* @__PURE__ */ jsxRuntime.jsx("g", { className: "rowLines", children: rowLines }),
785
+ todayHighlight
786
+ ] });
787
+ };
788
+ const Grid = (props) => {
789
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { className: "grid", children: /* @__PURE__ */ jsxRuntime.jsx(GridBody, { ...props }) });
790
+ };
791
+ const TopPartOfCalendar = ({
792
+ value,
793
+ x1Line,
794
+ y1Line,
795
+ y2Line,
796
+ xText,
797
+ yText
798
+ }) => {
799
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "calendarHeader", children: [
800
+ /* @__PURE__ */ jsxRuntime.jsx(
801
+ "line",
802
+ {
803
+ x1: x1Line,
804
+ y1: y1Line,
805
+ x2: x1Line,
806
+ y2: y2Line,
807
+ className: "calendarHeaderLine",
808
+ style: { stroke: "#e6e6e6", strokeWidth: 1 }
809
+ }
810
+ ),
811
+ /* @__PURE__ */ jsxRuntime.jsx(
812
+ "text",
813
+ {
814
+ x: xText,
815
+ y: yText,
816
+ className: "calendarHeaderText",
817
+ style: {
818
+ fill: "#555",
819
+ textAnchor: "middle",
820
+ fontWeight: "bold",
821
+ dominantBaseline: "middle"
822
+ },
823
+ children: value
824
+ }
825
+ )
826
+ ] });
827
+ };
828
+ const Calendar = React.memo(({
829
+ dateSetup,
830
+ locale,
831
+ viewMode,
832
+ headerHeight,
833
+ columnWidth,
834
+ fontFamily,
835
+ fontSize,
836
+ calendarTopHeaderFormat,
837
+ calendarBottomHeaderFormat
838
+ }) => {
839
+ const { dates } = dateSetup;
840
+ const getTopHeaderValue = React.useMemo(() => {
841
+ return (date) => {
842
+ if (calendarTopHeaderFormat) {
843
+ return calendarTopHeaderFormat(date, viewMode);
844
+ }
845
+ switch (viewMode) {
846
+ case ViewMode.Hour:
847
+ case ViewMode.QuarterDay:
848
+ case ViewMode.HalfDay:
849
+ return getCachedDateTimeFormat(locale, {
850
+ month: "long",
851
+ day: "numeric",
852
+ year: "numeric"
853
+ }).format(date);
854
+ case ViewMode.Day:
855
+ case ViewMode.Week:
856
+ return getCachedDateTimeFormat(locale, {
857
+ month: "long",
858
+ year: "numeric"
859
+ }).format(date);
860
+ case ViewMode.Month:
861
+ return getCachedDateTimeFormat(locale, {
862
+ year: "numeric"
863
+ }).format(date);
864
+ case ViewMode.Year:
865
+ return getCachedDateTimeFormat(locale, {
866
+ year: "numeric"
867
+ }).format(date);
868
+ default:
869
+ return "";
870
+ }
871
+ };
872
+ }, [viewMode, locale, calendarTopHeaderFormat]);
873
+ const getBottomHeaderValue = React.useMemo(() => {
874
+ return (date) => {
875
+ if (calendarBottomHeaderFormat) {
876
+ return calendarBottomHeaderFormat(date, viewMode);
877
+ }
878
+ switch (viewMode) {
879
+ case ViewMode.Hour:
880
+ return getCachedDateTimeFormat(locale, {
881
+ hour: "numeric",
882
+ hour12: false
883
+ }).format(date);
884
+ case ViewMode.QuarterDay:
885
+ case ViewMode.HalfDay:
886
+ return getCachedDateTimeFormat(locale, {
887
+ hour: "numeric",
888
+ minute: "numeric",
889
+ hour12: false
890
+ }).format(date);
891
+ case ViewMode.Day:
892
+ return getCachedDateTimeFormat(locale, {
893
+ day: "numeric"
894
+ }).format(date);
895
+ case ViewMode.Week:
896
+ return `W${getWeekNumberISO8601(date)}`;
897
+ case ViewMode.Month:
898
+ return getCachedDateTimeFormat(locale, {
899
+ month: "short"
900
+ }).format(date);
901
+ case ViewMode.Year:
902
+ return getCachedDateTimeFormat(locale, {
903
+ year: "numeric"
904
+ }).format(date);
905
+ default:
906
+ return "";
907
+ }
908
+ };
909
+ }, [viewMode, locale, calendarBottomHeaderFormat]);
910
+ const topHeaderCells = React.useMemo(() => {
911
+ const cells = [];
912
+ let currentCell = null;
913
+ for (let i = 0; i < dates.length; i++) {
914
+ const val = getTopHeaderValue(dates[i]);
915
+ if (!currentCell || currentCell.value !== val) {
916
+ currentCell = {
917
+ value: val,
918
+ colSpan: 1,
919
+ startX: i * columnWidth
920
+ };
921
+ cells.push(currentCell);
922
+ } else {
923
+ currentCell.colSpan++;
924
+ }
925
+ }
926
+ return cells;
927
+ }, [dates, columnWidth, getTopHeaderValue]);
928
+ const topHeaders = React.useMemo(() => {
929
+ return topHeaderCells.map((cell, idx) => {
930
+ const width = cell.colSpan * columnWidth;
931
+ const xText = cell.startX + width / 2;
932
+ const yText = headerHeight * 0.25;
933
+ return /* @__PURE__ */ jsxRuntime.jsx(
934
+ TopPartOfCalendar,
935
+ {
936
+ value: cell.value,
937
+ x1Line: cell.startX,
938
+ y1Line: 0,
939
+ y2Line: headerHeight * 0.5,
940
+ xText,
941
+ yText
942
+ },
943
+ `top-hdr-${idx}`
944
+ );
945
+ });
946
+ }, [topHeaderCells, columnWidth, headerHeight]);
947
+ const bottomHeaders = React.useMemo(() => {
948
+ return dates.map((date, idx) => {
949
+ const x = idx * columnWidth;
950
+ const xText = x + columnWidth / 2;
951
+ const yText = headerHeight * 0.75;
952
+ const val = getBottomHeaderValue(date);
953
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "calendarHeader", children: [
954
+ /* @__PURE__ */ jsxRuntime.jsx(
955
+ "line",
956
+ {
957
+ x1: x,
958
+ y1: headerHeight * 0.5,
959
+ x2: x,
960
+ y2: headerHeight,
961
+ className: "calendarHeaderLine",
962
+ style: { stroke: "#e6e6e6", strokeWidth: 1 }
963
+ }
964
+ ),
965
+ /* @__PURE__ */ jsxRuntime.jsx(
966
+ "text",
967
+ {
968
+ x: xText,
969
+ y: yText,
970
+ className: "calendarHeaderText",
971
+ style: {
972
+ fill: "#555",
973
+ textAnchor: "middle",
974
+ fontSize: "12px",
975
+ dominantBaseline: "middle"
976
+ },
977
+ children: val
978
+ }
979
+ )
980
+ ] }, `bot-hdr-${idx}`);
981
+ });
982
+ }, [dates, columnWidth, headerHeight, getBottomHeaderValue]);
983
+ return /* @__PURE__ */ jsxRuntime.jsxs(
984
+ "g",
985
+ {
986
+ className: "calendar",
987
+ style: {
988
+ fontFamily,
989
+ fontSize
990
+ },
991
+ children: [
992
+ /* @__PURE__ */ jsxRuntime.jsx(
993
+ "rect",
994
+ {
995
+ x: 0,
996
+ y: 0,
997
+ width: dates.length * columnWidth,
998
+ height: headerHeight,
999
+ fill: "#fcfcfc",
1000
+ style: { stroke: "#e6e6e6", strokeWidth: 1 }
1001
+ }
1002
+ ),
1003
+ /* @__PURE__ */ jsxRuntime.jsx(
1004
+ "line",
1005
+ {
1006
+ x1: 0,
1007
+ y1: headerHeight * 0.5,
1008
+ x2: dates.length * columnWidth,
1009
+ y2: headerHeight * 0.5,
1010
+ className: "calendarHeaderLine",
1011
+ style: { stroke: "#e6e6e6", strokeWidth: 1 }
1012
+ }
1013
+ ),
1014
+ /* @__PURE__ */ jsxRuntime.jsx("g", { className: "topHeaders", children: topHeaders }),
1015
+ /* @__PURE__ */ jsxRuntime.jsx("g", { className: "bottomHeaders", children: bottomHeaders })
1016
+ ]
1017
+ }
1018
+ );
1019
+ });
1020
+ const Bar = ({
1021
+ task,
1022
+ isProgressChangeable,
1023
+ isDateChangeable,
1024
+ isSelected,
1025
+ rtl,
1026
+ onEventStart
1027
+ }) => {
1028
+ const width = task.x2 - task.x1;
1029
+ const isSmall = task.typeInternal === "smalltask";
1030
+ const barBg = isSelected ? task.styles.backgroundSelectedColor : task.styles.backgroundColor;
1031
+ const progBg = isSelected ? task.styles.progressSelectedColor : task.styles.progressColor;
1032
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "bar", children: [
1033
+ /* @__PURE__ */ jsxRuntime.jsx(
1034
+ "rect",
1035
+ {
1036
+ x: task.x1,
1037
+ y: task.y,
1038
+ width,
1039
+ height: task.height,
1040
+ rx: task.barCornerRadius,
1041
+ ry: task.barCornerRadius,
1042
+ fill: barBg,
1043
+ className: "barBackground",
1044
+ style: {
1045
+ cursor: isDateChangeable ? "move" : "default",
1046
+ strokeWidth: isSelected ? 1.5 : 0,
1047
+ stroke: isSelected ? "#333" : void 0
1048
+ },
1049
+ onMouseDown: (e) => {
1050
+ if (isDateChangeable) onEventStart("move", task, e);
1051
+ }
1052
+ }
1053
+ ),
1054
+ /* @__PURE__ */ jsxRuntime.jsx(
1055
+ "rect",
1056
+ {
1057
+ x: task.progressX,
1058
+ y: task.y,
1059
+ width: task.progressWidth,
1060
+ height: task.height,
1061
+ rx: task.barCornerRadius,
1062
+ ry: task.barCornerRadius,
1063
+ fill: progBg,
1064
+ className: "barProgress",
1065
+ style: { cursor: isDateChangeable ? "move" : "default" },
1066
+ onMouseDown: (e) => {
1067
+ if (isDateChangeable) onEventStart("move", task, e);
1068
+ }
1069
+ }
1070
+ ),
1071
+ isDateChangeable && /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "handleGroup", children: [
1072
+ /* @__PURE__ */ jsxRuntime.jsx(
1073
+ "rect",
1074
+ {
1075
+ x: task.x1,
1076
+ y: task.y,
1077
+ width: task.handleWidth,
1078
+ height: task.height,
1079
+ fill: "transparent",
1080
+ style: { cursor: "w-resize" },
1081
+ onMouseDown: (e) => onEventStart("start", task, e)
1082
+ }
1083
+ ),
1084
+ /* @__PURE__ */ jsxRuntime.jsx(
1085
+ "rect",
1086
+ {
1087
+ x: task.x2 - task.handleWidth,
1088
+ y: task.y,
1089
+ width: task.handleWidth,
1090
+ height: task.height,
1091
+ fill: "transparent",
1092
+ style: { cursor: "e-resize" },
1093
+ onMouseDown: (e) => onEventStart("end", task, e)
1094
+ }
1095
+ )
1096
+ ] }),
1097
+ isProgressChangeable && /* @__PURE__ */ jsxRuntime.jsx(
1098
+ "polygon",
1099
+ {
1100
+ points: getProgressHandlePoint(
1101
+ task.progressX + (rtl ? 0 : task.progressWidth),
1102
+ task.y,
1103
+ task.height
1104
+ ),
1105
+ className: "barProgressHandle",
1106
+ style: { cursor: "ew-resize", fill: "#333" },
1107
+ onMouseDown: (e) => onEventStart("progress", task, e)
1108
+ }
1109
+ ),
1110
+ /* @__PURE__ */ jsxRuntime.jsx(
1111
+ "text",
1112
+ {
1113
+ x: isSmall ? task.x2 + 10 : task.x1 + width / 2,
1114
+ y: task.y + task.height / 2,
1115
+ className: "barLabel",
1116
+ style: {
1117
+ textAnchor: isSmall ? "start" : "middle",
1118
+ dominantBaseline: "middle",
1119
+ fill: isSmall ? "#333" : "#fff",
1120
+ fontSize: "12px",
1121
+ userSelect: "none",
1122
+ pointerEvents: "none",
1123
+ fontWeight: isSmall ? "normal" : "500"
1124
+ },
1125
+ children: task.name
1126
+ }
1127
+ )
1128
+ ] });
1129
+ };
1130
+ const Project = ({
1131
+ task,
1132
+ isSelected,
1133
+ onEventStart
1134
+ }) => {
1135
+ const width = task.x2 - task.x1;
1136
+ const projectBg = isSelected ? task.styles.backgroundSelectedColor : task.styles.backgroundColor;
1137
+ const projectProgressBg = isSelected ? task.styles.progressSelectedColor : task.styles.progressColor;
1138
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "project", children: [
1139
+ /* @__PURE__ */ jsxRuntime.jsx(
1140
+ "rect",
1141
+ {
1142
+ x: task.x1,
1143
+ y: task.y,
1144
+ width,
1145
+ height: task.height,
1146
+ rx: task.barCornerRadius,
1147
+ ry: task.barCornerRadius,
1148
+ fill: projectBg,
1149
+ className: "projectBackground",
1150
+ style: {
1151
+ cursor: "pointer",
1152
+ strokeWidth: isSelected ? 1.5 : 0,
1153
+ stroke: isSelected ? "#333" : void 0
1154
+ },
1155
+ onMouseDown: (e) => onEventStart("click", task, e)
1156
+ }
1157
+ ),
1158
+ /* @__PURE__ */ jsxRuntime.jsx(
1159
+ "rect",
1160
+ {
1161
+ x: task.x1,
1162
+ y: task.y,
1163
+ width: task.progressWidth,
1164
+ height: task.height,
1165
+ rx: task.barCornerRadius,
1166
+ ry: task.barCornerRadius,
1167
+ fill: projectProgressBg,
1168
+ className: "projectProgress",
1169
+ style: { cursor: "pointer" },
1170
+ onMouseDown: (e) => onEventStart("click", task, e)
1171
+ }
1172
+ ),
1173
+ /* @__PURE__ */ jsxRuntime.jsx(
1174
+ "polygon",
1175
+ {
1176
+ points: `${task.x1},${task.y + task.height} ${task.x1 + 8},${task.y + task.height} ${task.x1},${task.y + task.height - 8}`,
1177
+ fill: projectProgressBg
1178
+ }
1179
+ ),
1180
+ /* @__PURE__ */ jsxRuntime.jsx(
1181
+ "polygon",
1182
+ {
1183
+ points: `${task.x2},${task.y + task.height} ${task.x2 - 8},${task.y + task.height} ${task.x2},${task.y + task.height - 8}`,
1184
+ fill: projectProgressBg
1185
+ }
1186
+ ),
1187
+ /* @__PURE__ */ jsxRuntime.jsx(
1188
+ "text",
1189
+ {
1190
+ x: task.x2 + 12,
1191
+ y: task.y + task.height / 2,
1192
+ className: "projectLabel",
1193
+ style: {
1194
+ textAnchor: "start",
1195
+ dominantBaseline: "middle",
1196
+ fill: "#333",
1197
+ fontSize: "12px",
1198
+ fontWeight: "bold",
1199
+ userSelect: "none",
1200
+ pointerEvents: "none"
1201
+ },
1202
+ children: task.name
1203
+ }
1204
+ )
1205
+ ] });
1206
+ };
1207
+ const Milestone = ({
1208
+ task,
1209
+ isDateChangeable,
1210
+ isSelected,
1211
+ onEventStart
1212
+ }) => {
1213
+ const milestoneBg = isSelected ? task.styles.backgroundSelectedColor : task.styles.backgroundColor;
1214
+ const halfHeight = task.height / 2;
1215
+ const cx = task.x1 + halfHeight;
1216
+ const cy = task.y + halfHeight;
1217
+ const points = `
1218
+ ${cx},${cy - halfHeight}
1219
+ ${cx + halfHeight},${cy}
1220
+ ${cx},${cy + halfHeight}
1221
+ ${cx - halfHeight},${cy}
1222
+ `.trim();
1223
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "milestone", children: [
1224
+ /* @__PURE__ */ jsxRuntime.jsx(
1225
+ "polygon",
1226
+ {
1227
+ points,
1228
+ fill: milestoneBg,
1229
+ className: "milestoneBackground",
1230
+ style: {
1231
+ cursor: isDateChangeable ? "move" : "default",
1232
+ strokeWidth: isSelected ? 1.5 : 0,
1233
+ stroke: isSelected ? "#333" : void 0
1234
+ },
1235
+ onMouseDown: (e) => {
1236
+ if (isDateChangeable) onEventStart("move", task, e);
1237
+ }
1238
+ }
1239
+ ),
1240
+ /* @__PURE__ */ jsxRuntime.jsx(
1241
+ "text",
1242
+ {
1243
+ x: cx + halfHeight + 10,
1244
+ y: cy,
1245
+ className: "milestoneLabel",
1246
+ style: {
1247
+ textAnchor: "start",
1248
+ dominantBaseline: "middle",
1249
+ fill: "#333",
1250
+ fontSize: "12px",
1251
+ userSelect: "none",
1252
+ pointerEvents: "none"
1253
+ },
1254
+ children: task.name
1255
+ }
1256
+ )
1257
+ ] });
1258
+ };
1259
+ const TaskItem = (props) => {
1260
+ const { task } = props;
1261
+ switch (task.type) {
1262
+ case "project":
1263
+ return /* @__PURE__ */ jsxRuntime.jsx(Project, { ...props });
1264
+ case "milestone":
1265
+ return /* @__PURE__ */ jsxRuntime.jsx(Milestone, { ...props });
1266
+ default:
1267
+ return /* @__PURE__ */ jsxRuntime.jsx(Bar, { ...props });
1268
+ }
1269
+ };
1270
+ const DependencyArrow = ({
1271
+ taskFrom,
1272
+ taskTo,
1273
+ taskHeight,
1274
+ arrowIndent,
1275
+ rtl
1276
+ }) => {
1277
+ let path = "";
1278
+ let arrowHeadPoints = "";
1279
+ const y1 = taskFrom.y + taskHeight / 2;
1280
+ const y2 = taskTo.y + taskHeight / 2;
1281
+ if (rtl) {
1282
+ const x1 = taskFrom.x1;
1283
+ const x2 = taskTo.x2;
1284
+ if (x1 - arrowIndent > x2) {
1285
+ const midX = x1 - arrowIndent;
1286
+ path = `M ${x1} ${y1} H ${midX} V ${y2} H ${x2}`;
1287
+ } else {
1288
+ const midX1 = x1 - arrowIndent;
1289
+ const midX2 = x2 + arrowIndent;
1290
+ const midY = y1 + (y2 - y1) / 2;
1291
+ path = `M ${x1} ${y1} H ${midX1} V ${midY} H ${midX2} V ${y2} H ${x2}`;
1292
+ }
1293
+ arrowHeadPoints = `${x2},${y2} ${x2 + 5},${y2 - 3} ${x2 + 5},${y2 + 3}`;
1294
+ } else {
1295
+ const x1 = taskFrom.x2;
1296
+ const x2 = taskTo.x1;
1297
+ if (x1 + arrowIndent < x2) {
1298
+ const midX = x1 + arrowIndent;
1299
+ path = `M ${x1} ${y1} H ${midX} V ${y2} H ${x2}`;
1300
+ } else {
1301
+ const midX1 = x1 + arrowIndent;
1302
+ const midX2 = x2 - arrowIndent;
1303
+ const midY = y1 + (y2 - y1) / 2;
1304
+ path = `M ${x1} ${y1} H ${midX1} V ${midY} H ${midX2} V ${y2} H ${x2}`;
1305
+ }
1306
+ arrowHeadPoints = `${x2},${y2} ${x2 - 5},${y2 - 3} ${x2 - 5},${y2 + 3}`;
1307
+ }
1308
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "dependencyArrow", children: [
1309
+ /* @__PURE__ */ jsxRuntime.jsx(
1310
+ "path",
1311
+ {
1312
+ d: path,
1313
+ fill: "transparent",
1314
+ stroke: "#fcb32c",
1315
+ strokeWidth: 1.5,
1316
+ className: "arrowPath"
1317
+ }
1318
+ ),
1319
+ /* @__PURE__ */ jsxRuntime.jsx(
1320
+ "polygon",
1321
+ {
1322
+ points: arrowHeadPoints,
1323
+ fill: "#fcb32c",
1324
+ className: "arrowHead"
1325
+ }
1326
+ )
1327
+ ] });
1328
+ };
1329
+ const DefaultTooltipContent = ({ task, fontSize, fontFamily }) => {
1330
+ const duration = Math.round((task.end.getTime() - task.start.getTime()) / 864e5);
1331
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1332
+ "div",
1333
+ {
1334
+ style: {
1335
+ padding: "10px 12px",
1336
+ backgroundColor: "rgba(255, 255, 255, 0.98)",
1337
+ border: "1px solid #ebebeb",
1338
+ borderRadius: "6px",
1339
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.08)",
1340
+ color: "#333",
1341
+ fontFamily,
1342
+ fontSize,
1343
+ lineHeight: "1.5em",
1344
+ pointerEvents: "none",
1345
+ minWidth: 180
1346
+ },
1347
+ children: [
1348
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: "bold", color: "#111", marginBottom: 6 }, children: task.name }),
1349
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "#666", fontSize: "11px", marginBottom: 2 }, children: [
1350
+ "開始: ",
1351
+ task.start.toLocaleDateString("ja-JP")
1352
+ ] }),
1353
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "#666", fontSize: "11px", marginBottom: 4 }, children: [
1354
+ "終了: ",
1355
+ task.end.toLocaleDateString("ja-JP")
1356
+ ] }),
1357
+ task.type !== "milestone" && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginTop: 6, paddingTop: 6, borderTop: "1px solid #f0f0f0", fontSize: "11px" }, children: [
1358
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1359
+ "期間: ",
1360
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
1361
+ duration,
1362
+ " 日間"
1363
+ ] })
1364
+ ] }),
1365
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1366
+ "進捗: ",
1367
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
1368
+ task.progress,
1369
+ "%"
1370
+ ] })
1371
+ ] })
1372
+ ] })
1373
+ ]
1374
+ }
1375
+ );
1376
+ };
1377
+ const TaskTooltip = ({
1378
+ task,
1379
+ rtl,
1380
+ fontSize,
1381
+ fontFamily,
1382
+ TooltipContent,
1383
+ mousePos = { x: 0, y: 0 }
1384
+ }) => {
1385
+ const tooltipRef = React.useRef(null);
1386
+ const [coords, setCoords] = React.useState({ x: 0, y: 0 });
1387
+ React.useEffect(() => {
1388
+ if (tooltipRef.current) {
1389
+ const width = tooltipRef.current.clientWidth || 200;
1390
+ let finalX = mousePos.x + 15;
1391
+ let finalY = mousePos.y + 15;
1392
+ if (rtl) {
1393
+ finalX = mousePos.x - width - 15;
1394
+ }
1395
+ setCoords({ x: finalX, y: finalY });
1396
+ }
1397
+ }, [mousePos, rtl]);
1398
+ return /* @__PURE__ */ jsxRuntime.jsx(
1399
+ "div",
1400
+ {
1401
+ ref: tooltipRef,
1402
+ style: {
1403
+ position: "fixed",
1404
+ left: coords.x,
1405
+ top: coords.y,
1406
+ zIndex: 1e3,
1407
+ pointerEvents: "none"
1408
+ },
1409
+ className: "ganttTooltip",
1410
+ children: !!(coords == null ? void 0 : coords.x) && !!(coords == null ? void 0 : coords.y) && /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { task, fontSize, fontFamily })
1411
+ }
1412
+ );
1413
+ };
1414
+ const TimelineContent = ({
1415
+ tasks,
1416
+ allTasks = [],
1417
+ interactionState,
1418
+ selectedTask,
1419
+ rowHeight,
1420
+ columnWidth,
1421
+ timeStep,
1422
+ svg,
1423
+ svgWidth,
1424
+ taskHeight,
1425
+ arrowIndent,
1426
+ fontSize,
1427
+ fontFamily,
1428
+ rtl,
1429
+ setInteractionState,
1430
+ setSelectedTask,
1431
+ mousePos = { x: 0, y: 0 },
1432
+ TooltipContent = DefaultTooltipContent,
1433
+ onDoubleClick,
1434
+ onClick,
1435
+ onDateChange,
1436
+ onProgressChange,
1437
+ onDelete
1438
+ }) => {
1439
+ const [hoveredTask, setHoveredTask] = React.useState(void 0);
1440
+ const dragX1DeltaRef = React.useRef(0);
1441
+ React.useEffect(() => {
1442
+ const handleMouseMove = async (event) => {
1443
+ if (!interactionState.action || !interactionState.originalSelectedTask || !(svg == null ? void 0 : svg.current)) {
1444
+ return;
1445
+ }
1446
+ event.preventDefault();
1447
+ const rect = svg.current.getBoundingClientRect();
1448
+ const svgX = event.clientX - rect.left;
1449
+ const { isChanged, changedTask } = applyDragToTask(
1450
+ svgX,
1451
+ interactionState.action,
1452
+ interactionState.originalSelectedTask,
1453
+ columnWidth,
1454
+ timeStep,
1455
+ dragX1DeltaRef.current,
1456
+ rtl
1457
+ );
1458
+ if (isChanged) {
1459
+ setInteractionState({ ...interactionState, changedTask });
1460
+ }
1461
+ };
1462
+ const handleMouseUp = async (event) => {
1463
+ if (!interactionState.action || !interactionState.originalSelectedTask) {
1464
+ return;
1465
+ }
1466
+ event.preventDefault();
1467
+ const { changedTask, originalSelectedTask, action } = interactionState;
1468
+ if (changedTask && changedTask !== originalSelectedTask) {
1469
+ try {
1470
+ if (action === "progress" && onProgressChange) {
1471
+ await onProgressChange(changedTask, changedTask.barChildren);
1472
+ } else if ((action === "move" || action === "start" || action === "end") && onDateChange) {
1473
+ await onDateChange(changedTask, changedTask.barChildren);
1474
+ }
1475
+ } catch (err) {
1476
+ console.error("Gantt action callback failed:", err);
1477
+ }
1478
+ }
1479
+ setInteractionState({ action: "" });
1480
+ };
1481
+ if (interactionState.action !== "") {
1482
+ window.addEventListener("mousemove", handleMouseMove);
1483
+ window.addEventListener("mouseup", handleMouseUp);
1484
+ }
1485
+ return () => {
1486
+ window.removeEventListener("mousemove", handleMouseMove);
1487
+ window.removeEventListener("mouseup", handleMouseUp);
1488
+ };
1489
+ }, [interactionState, svg, columnWidth, timeStep, rtl, onProgressChange, onDateChange, setInteractionState]);
1490
+ const handleEventStart = (action, task, event) => {
1491
+ if (event) {
1492
+ event.preventDefault();
1493
+ if ("clientX" in event && (svg == null ? void 0 : svg.current)) {
1494
+ const rect = svg.current.getBoundingClientRect();
1495
+ const svgX = event.clientX - rect.left;
1496
+ dragX1DeltaRef.current = svgX - task.x1;
1497
+ }
1498
+ }
1499
+ if (action === "click") {
1500
+ setSelectedTask(task.id);
1501
+ if (onClick) onClick(task);
1502
+ } else if (action === "dblclick") {
1503
+ if (onDoubleClick) onDoubleClick(task);
1504
+ } else if (action === "delete") {
1505
+ if (onDelete) onDelete(task);
1506
+ } else {
1507
+ setInteractionState({
1508
+ action,
1509
+ originalSelectedTask: task,
1510
+ changedTask: task
1511
+ });
1512
+ }
1513
+ };
1514
+ const arrows = React.useMemo(() => {
1515
+ const list = [];
1516
+ const tasksLookupList = allTasks.length > 0 ? allTasks : tasks;
1517
+ tasks.forEach((taskTo) => {
1518
+ if (taskTo.dependencies) {
1519
+ taskTo.dependencies.forEach((depId) => {
1520
+ const taskFrom = tasksLookupList.find((t) => t.id === depId);
1521
+ if (taskFrom) {
1522
+ list.push(
1523
+ /* @__PURE__ */ jsxRuntime.jsx(
1524
+ DependencyArrow,
1525
+ {
1526
+ taskFrom,
1527
+ taskTo,
1528
+ rowHeight,
1529
+ taskHeight,
1530
+ arrowIndent,
1531
+ rtl
1532
+ },
1533
+ `arrow-${taskFrom.id}-${taskTo.id}`
1534
+ )
1535
+ );
1536
+ }
1537
+ });
1538
+ }
1539
+ });
1540
+ return list;
1541
+ }, [tasks, allTasks, rowHeight, taskHeight, arrowIndent, rtl]);
1542
+ const isDateChangeable = (task) => !task.isDisabled;
1543
+ const isProgressChangeable = (task) => !task.isDisabled && task.type === "task";
1544
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "timelineContent", children: [
1545
+ /* @__PURE__ */ jsxRuntime.jsx("g", { className: "dependencyArrows", children: arrows }),
1546
+ /* @__PURE__ */ jsxRuntime.jsx("g", { className: "taskBars", children: tasks.map((task) => {
1547
+ const renderTask = interactionState.action !== "" && interactionState.changedTask && interactionState.changedTask.id === task.id ? interactionState.changedTask : task;
1548
+ const isSelected = (selectedTask == null ? void 0 : selectedTask.id) === task.id;
1549
+ return /* @__PURE__ */ jsxRuntime.jsx(
1550
+ "g",
1551
+ {
1552
+ className: "taskItemWrapper",
1553
+ onMouseEnter: () => setHoveredTask(task),
1554
+ onMouseLeave: () => setHoveredTask(void 0),
1555
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1556
+ TaskItem,
1557
+ {
1558
+ task: renderTask,
1559
+ arrowIndent,
1560
+ taskHeight,
1561
+ isProgressChangeable: isProgressChangeable(task),
1562
+ isDateChangeable: isDateChangeable(task),
1563
+ isDelete: true,
1564
+ isSelected,
1565
+ rtl,
1566
+ onEventStart: handleEventStart
1567
+ }
1568
+ )
1569
+ },
1570
+ task.id
1571
+ );
1572
+ }) }),
1573
+ hoveredTask && reactDom.createPortal(
1574
+ /* @__PURE__ */ jsxRuntime.jsx(
1575
+ TaskTooltip,
1576
+ {
1577
+ task: hoveredTask,
1578
+ arrowIndent,
1579
+ rtl,
1580
+ svgWidth,
1581
+ fontSize,
1582
+ fontFamily,
1583
+ TooltipContent,
1584
+ mousePos
1585
+ }
1586
+ ),
1587
+ document.body
1588
+ )
1589
+ ] });
1590
+ };
1591
+ const TimelinePanel = ({
1592
+ gridProps,
1593
+ calendarProps,
1594
+ contentProps
1595
+ }) => {
1596
+ const { svgWidth } = gridProps;
1597
+ const { headerHeight } = calendarProps;
1598
+ const svgRef = React.useRef(null);
1599
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1600
+ "div",
1601
+ {
1602
+ className: "ganttTimeline",
1603
+ style: {
1604
+ width: svgWidth,
1605
+ position: "relative"
1606
+ },
1607
+ children: [
1608
+ /* @__PURE__ */ jsxRuntime.jsx(
1609
+ "div",
1610
+ {
1611
+ className: "ganttCalendarHeader",
1612
+ style: {
1613
+ position: "sticky",
1614
+ top: 0,
1615
+ zIndex: 10,
1616
+ width: svgWidth,
1617
+ height: headerHeight,
1618
+ backgroundColor: "#fcfcfc",
1619
+ borderBottom: "1px solid #e6e6e6"
1620
+ },
1621
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1622
+ "svg",
1623
+ {
1624
+ width: svgWidth,
1625
+ height: headerHeight,
1626
+ className: "calendarSvg",
1627
+ children: /* @__PURE__ */ jsxRuntime.jsx(Calendar, { ...calendarProps })
1628
+ }
1629
+ )
1630
+ }
1631
+ ),
1632
+ /* @__PURE__ */ jsxRuntime.jsx(
1633
+ "div",
1634
+ {
1635
+ style: {
1636
+ width: svgWidth,
1637
+ height: contentProps.svgHeight,
1638
+ position: "relative"
1639
+ },
1640
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1641
+ "svg",
1642
+ {
1643
+ width: svgWidth,
1644
+ height: contentProps.svgHeight,
1645
+ className: "ganttSvg",
1646
+ ref: svgRef,
1647
+ children: [
1648
+ /* @__PURE__ */ jsxRuntime.jsx(Grid, { ...gridProps }),
1649
+ /* @__PURE__ */ jsxRuntime.jsx(
1650
+ TimelineContent,
1651
+ {
1652
+ ...contentProps,
1653
+ svg: svgRef
1654
+ }
1655
+ )
1656
+ ]
1657
+ }
1658
+ )
1659
+ }
1660
+ )
1661
+ ]
1662
+ }
1663
+ );
1664
+ };
1665
+ const Gantt = ({
1666
+ tasks,
1667
+ viewMode = ViewMode.Day,
1668
+ viewDate,
1669
+ preStepsCount = 1,
1670
+ locale = "en-GB",
1671
+ rtl = false,
1672
+ calendarTopHeaderFormat,
1673
+ calendarBottomHeaderFormat,
1674
+ headerHeight = 50,
1675
+ columnWidth,
1676
+ listCellWidth = "360px",
1677
+ rowHeight = 50,
1678
+ ganttHeight = 0,
1679
+ barCornerRadius = 3,
1680
+ handleWidth = 8,
1681
+ fontFamily = "Arial, Roboto, sans-serif",
1682
+ fontSize = "14px",
1683
+ barFill = 60,
1684
+ barProgressColor = "#a3a3ff",
1685
+ barProgressSelectedColor = "#8282ff",
1686
+ barBackgroundColor = "#b8c2cc",
1687
+ barBackgroundSelectedColor = "#a3aebe",
1688
+ projectProgressColor = "#7db3e8",
1689
+ projectProgressSelectedColor = "#5492d6",
1690
+ projectBackgroundColor = "#facfc3",
1691
+ projectBackgroundSelectedColor = "#f1b3a2",
1692
+ milestoneBackgroundColor = "#f1c40f",
1693
+ milestoneBackgroundSelectedColor = "#f39c12",
1694
+ arrowColor = "#fcb32c",
1695
+ arrowIndent = 20,
1696
+ todayColor = "rgba(252, 75, 113, 0.3)",
1697
+ TooltipContent,
1698
+ TaskListHeader,
1699
+ TaskListTable,
1700
+ timeStep = 36e5 * 24,
1701
+ onSelect,
1702
+ onDoubleClick,
1703
+ onClick,
1704
+ onDateChange,
1705
+ onProgressChange,
1706
+ onDelete,
1707
+ onExpanderClick
1708
+ }) => {
1709
+ const resolvedColumnWidth = React.useMemo(() => {
1710
+ if (columnWidth) return columnWidth;
1711
+ switch (viewMode) {
1712
+ case ViewMode.Hour:
1713
+ return 60;
1714
+ case ViewMode.QuarterDay:
1715
+ return 65;
1716
+ case ViewMode.HalfDay:
1717
+ return 80;
1718
+ case ViewMode.Day:
1719
+ return 60;
1720
+ case ViewMode.Week:
1721
+ return 250;
1722
+ case ViewMode.Month:
1723
+ return 300;
1724
+ case ViewMode.Year:
1725
+ return 350;
1726
+ default:
1727
+ return 60;
1728
+ }
1729
+ }, [columnWidth, viewMode]);
1730
+ const filteredTasks = React.useMemo(
1731
+ () => removeHiddenTasks(tasks).sort(sortTasks),
1732
+ [tasks]
1733
+ );
1734
+ const dates = React.useMemo(
1735
+ () => ganttDateRange(filteredTasks, viewMode, preStepsCount),
1736
+ [filteredTasks, viewMode, preStepsCount]
1737
+ );
1738
+ const renderedTasks = React.useMemo(
1739
+ () => convertToRenderedTasks(
1740
+ filteredTasks,
1741
+ dates,
1742
+ resolvedColumnWidth,
1743
+ rowHeight,
1744
+ rowHeight * (barFill / 100),
1745
+ barCornerRadius,
1746
+ handleWidth,
1747
+ rtl,
1748
+ barProgressColor,
1749
+ barProgressSelectedColor,
1750
+ barBackgroundColor,
1751
+ barBackgroundSelectedColor,
1752
+ projectProgressColor,
1753
+ projectProgressSelectedColor,
1754
+ projectBackgroundColor,
1755
+ projectBackgroundSelectedColor,
1756
+ milestoneBackgroundColor,
1757
+ milestoneBackgroundSelectedColor
1758
+ ),
1759
+ [
1760
+ filteredTasks,
1761
+ dates,
1762
+ resolvedColumnWidth,
1763
+ rowHeight,
1764
+ barFill,
1765
+ barCornerRadius,
1766
+ handleWidth,
1767
+ rtl,
1768
+ barProgressColor,
1769
+ barProgressSelectedColor,
1770
+ barBackgroundColor,
1771
+ barBackgroundSelectedColor,
1772
+ projectProgressColor,
1773
+ projectProgressSelectedColor,
1774
+ projectBackgroundColor,
1775
+ projectBackgroundSelectedColor,
1776
+ milestoneBackgroundColor,
1777
+ milestoneBackgroundSelectedColor
1778
+ ]
1779
+ );
1780
+ const [scrollTopState, setScrollTopState] = React.useState(0);
1781
+ const [mousePos, setMousePos] = React.useState({ x: 0, y: 0 });
1782
+ const [selectedTask, setSelectedTaskState] = React.useState(void 0);
1783
+ const [interactionState, setInteractionState] = React.useState({ action: "" });
1784
+ const [, setFailedTask] = React.useState(null);
1785
+ const ganttFullHeight = renderedTasks.length * rowHeight;
1786
+ const viewHeight = ganttHeight && ganttHeight > 0 ? ganttHeight : 500;
1787
+ const startIndex = Math.max(0, Math.floor(scrollTopState / rowHeight) - 3);
1788
+ const endIndex = Math.min(
1789
+ renderedTasks.length - 1,
1790
+ Math.ceil((scrollTopState + viewHeight) / rowHeight) + 3
1791
+ );
1792
+ const visibleRenderedTasks = React.useMemo(
1793
+ () => renderedTasks.slice(startIndex, endIndex + 1),
1794
+ [renderedTasks, startIndex, endIndex]
1795
+ );
1796
+ const taskListWidthNumber = React.useMemo(() => {
1797
+ const val = parseInt(listCellWidth, 10);
1798
+ return isNaN(val) ? 250 : val;
1799
+ }, [listCellWidth]);
1800
+ const [taskListWidth, setTaskListWidth] = React.useState(taskListWidthNumber);
1801
+ React.useEffect(() => {
1802
+ setTaskListWidth(taskListWidthNumber);
1803
+ }, [taskListWidthNumber]);
1804
+ const [isResizing, setIsResizing] = React.useState(false);
1805
+ const resizerRef = React.useRef(null);
1806
+ const handleResizerMouseDown = React.useCallback((e) => {
1807
+ resizerRef.current = { startX: e.clientX, startWidth: taskListWidth };
1808
+ setIsResizing(true);
1809
+ e.preventDefault();
1810
+ }, [taskListWidth]);
1811
+ React.useEffect(() => {
1812
+ const handleGlobalMouseMove = (e) => {
1813
+ if (!isResizing || !resizerRef.current) return;
1814
+ const diff = e.clientX - resizerRef.current.startX;
1815
+ setTaskListWidth(Math.max(0, resizerRef.current.startWidth + diff));
1816
+ };
1817
+ const handleGlobalMouseUp = () => {
1818
+ setIsResizing(false);
1819
+ resizerRef.current = null;
1820
+ };
1821
+ if (isResizing) {
1822
+ window.addEventListener("mousemove", handleGlobalMouseMove);
1823
+ window.addEventListener("mouseup", handleGlobalMouseUp);
1824
+ document.body.style.cursor = "col-resize";
1825
+ } else {
1826
+ document.body.style.cursor = "";
1827
+ }
1828
+ return () => {
1829
+ window.removeEventListener("mousemove", handleGlobalMouseMove);
1830
+ window.removeEventListener("mouseup", handleGlobalMouseUp);
1831
+ document.body.style.cursor = "";
1832
+ };
1833
+ }, [isResizing]);
1834
+ const svgWidth = dates.length * resolvedColumnWidth;
1835
+ const containerRef = React.useRef(null);
1836
+ React.useEffect(() => {
1837
+ if (viewDate && dates.length > 0 && containerRef.current) {
1838
+ const x = taskXCoordinate(viewDate, dates, resolvedColumnWidth);
1839
+ const targetLeft = Math.max(0, x - resolvedColumnWidth * 2);
1840
+ containerRef.current.scrollLeft = targetLeft;
1841
+ }
1842
+ }, [viewDate, dates, resolvedColumnWidth]);
1843
+ const handleScroll = React.useCallback((e) => {
1844
+ setScrollTopState(e.currentTarget.scrollTop);
1845
+ }, []);
1846
+ const handleMouseMove = React.useCallback((e) => {
1847
+ setMousePos({ x: e.clientX, y: e.clientY });
1848
+ }, []);
1849
+ const handleExpanderClick = React.useCallback(
1850
+ (task) => {
1851
+ if (onExpanderClick) onExpanderClick(task);
1852
+ },
1853
+ [onExpanderClick]
1854
+ );
1855
+ const setSelectedTask = React.useCallback(
1856
+ (taskId) => {
1857
+ const newTask = renderedTasks.find((t) => t.id === taskId);
1858
+ setSelectedTaskState(newTask);
1859
+ if (onSelect) onSelect(newTask, !!newTask);
1860
+ },
1861
+ [renderedTasks, onSelect]
1862
+ );
1863
+ const gridProps = {
1864
+ columnWidth: resolvedColumnWidth,
1865
+ svgWidth,
1866
+ svgHeight: ganttFullHeight,
1867
+ dates,
1868
+ rowHeight,
1869
+ rtl,
1870
+ todayColor,
1871
+ tasks: visibleRenderedTasks,
1872
+ startIndex,
1873
+ endIndex
1874
+ };
1875
+ const dateSetup = React.useMemo(() => ({ dates, viewMode }), [dates, viewMode]);
1876
+ const calendarProps = {
1877
+ dateSetup,
1878
+ locale,
1879
+ rtl,
1880
+ headerHeight,
1881
+ columnWidth: resolvedColumnWidth,
1882
+ fontFamily,
1883
+ fontSize,
1884
+ viewMode,
1885
+ calendarTopHeaderFormat,
1886
+ calendarBottomHeaderFormat
1887
+ };
1888
+ const contentProps = {
1889
+ tasks: visibleRenderedTasks,
1890
+ allTasks: renderedTasks,
1891
+ dates,
1892
+ interactionState,
1893
+ selectedTask,
1894
+ rowHeight,
1895
+ columnWidth: resolvedColumnWidth,
1896
+ timeStep,
1897
+ svgWidth,
1898
+ svgHeight: ganttFullHeight,
1899
+ taskHeight: rowHeight * (barFill / 100),
1900
+ arrowColor,
1901
+ arrowIndent,
1902
+ fontSize,
1903
+ fontFamily,
1904
+ rtl,
1905
+ setInteractionState,
1906
+ setFailedTask,
1907
+ setSelectedTask,
1908
+ onSelect,
1909
+ onDoubleClick,
1910
+ onClick,
1911
+ onDateChange,
1912
+ onProgressChange,
1913
+ onDelete,
1914
+ onExpanderClick: handleExpanderClick,
1915
+ TooltipContent,
1916
+ mousePos,
1917
+ ganttHeight: viewHeight,
1918
+ headerHeight
1919
+ };
1920
+ return /* @__PURE__ */ jsxRuntime.jsx(
1921
+ "div",
1922
+ {
1923
+ ref: containerRef,
1924
+ className: "ganttOuterWrapper",
1925
+ onScroll: handleScroll,
1926
+ onMouseMove: handleMouseMove,
1927
+ style: {
1928
+ fontFamily,
1929
+ fontSize,
1930
+ height: viewHeight,
1931
+ width: "100%",
1932
+ overflow: "auto",
1933
+ position: "relative"
1934
+ },
1935
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1936
+ "div",
1937
+ {
1938
+ className: "ganttWrapper",
1939
+ style: {
1940
+ display: "flex",
1941
+ width: taskListWidth + svgWidth + 6,
1942
+ // リサイザーの幅分追加
1943
+ height: ganttFullHeight + headerHeight,
1944
+ position: "relative",
1945
+ userSelect: isResizing ? "none" : "auto"
1946
+ },
1947
+ children: [
1948
+ /* @__PURE__ */ jsxRuntime.jsx(
1949
+ TaskList,
1950
+ {
1951
+ tasks: renderedTasks,
1952
+ visibleTasks: visibleRenderedTasks,
1953
+ rowWidth: `${taskListWidth}px`,
1954
+ taskListWidth,
1955
+ rowHeight,
1956
+ headerHeight,
1957
+ fontFamily,
1958
+ fontSize,
1959
+ locale,
1960
+ selectedTaskId: (selectedTask == null ? void 0 : selectedTask.id) || "",
1961
+ setSelectedTask,
1962
+ onExpanderClick: handleExpanderClick,
1963
+ TaskListHeader,
1964
+ TaskListTable
1965
+ }
1966
+ ),
1967
+ /* @__PURE__ */ jsxRuntime.jsx(
1968
+ "div",
1969
+ {
1970
+ className: "ganttResizer",
1971
+ onMouseDown: handleResizerMouseDown,
1972
+ style: {
1973
+ width: "6px",
1974
+ cursor: "col-resize",
1975
+ zIndex: 30,
1976
+ flexShrink: 0,
1977
+ transition: "background-color 0.2s"
1978
+ }
1979
+ }
1980
+ ),
1981
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { pointerEvents: isResizing ? "none" : "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1982
+ TimelinePanel,
1983
+ {
1984
+ gridProps,
1985
+ calendarProps,
1986
+ contentProps
1987
+ }
1988
+ ) })
1989
+ ]
1990
+ }
1991
+ )
1992
+ }
1993
+ );
1994
+ };
1995
+ exports.Gantt = Gantt;
1996
+ exports.ViewMode = ViewMode;