gantt-lib 0.18.0 → 0.19.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
@@ -36,6 +36,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
36
36
  // src/utils/dateUtils.ts
37
37
  var dateUtils_exports = {};
38
38
  __export(dateUtils_exports, {
39
+ createDateKey: () => createDateKey,
40
+ createIsWeekendPredicate: () => createIsWeekendPredicate,
39
41
  formatDateLabel: () => formatDateLabel,
40
42
  getDayOffset: () => getDayOffset,
41
43
  getMonthBlocks: () => getMonthBlocks,
@@ -50,7 +52,7 @@ __export(dateUtils_exports, {
50
52
  normalizeTaskDates: () => normalizeTaskDates,
51
53
  parseUTCDate: () => parseUTCDate
52
54
  });
53
- var parseUTCDate, getMonthDays, getDayOffset, isToday, isWeekend, getMultiMonthDays, getMonthSpans, formatDateLabel, getWeekBlocks, getWeekSpans, getMonthBlocks, getYearSpans, normalizeTaskDates;
55
+ var parseUTCDate, getMonthDays, getDayOffset, isToday, isWeekend, createDateKey, createIsWeekendPredicate, getMultiMonthDays, getMonthSpans, formatDateLabel, getWeekBlocks, getWeekSpans, getMonthBlocks, getYearSpans, normalizeTaskDates;
54
56
  var init_dateUtils = __esm({
55
57
  "src/utils/dateUtils.ts"() {
56
58
  "use strict";
@@ -107,6 +109,41 @@ var init_dateUtils = __esm({
107
109
  const day = date.getUTCDay();
108
110
  return day === 0 || day === 6;
109
111
  };
112
+ createDateKey = (date) => {
113
+ return `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}`;
114
+ };
115
+ createIsWeekendPredicate = (config) => {
116
+ const { weekends, workdays, isWeekend: customPredicate } = config;
117
+ if (customPredicate) {
118
+ return customPredicate;
119
+ }
120
+ if (workdays && workdays.length > 0) {
121
+ const workdaySet = new Set(workdays.map(createDateKey));
122
+ return (date) => {
123
+ const key = createDateKey(date);
124
+ if (workdaySet.has(key)) {
125
+ return false;
126
+ }
127
+ const dayOfWeek = date.getUTCDay();
128
+ return dayOfWeek === 0 || dayOfWeek === 6;
129
+ };
130
+ }
131
+ if (weekends && weekends.length > 0) {
132
+ const weekendSet = new Set(weekends.map(createDateKey));
133
+ return (date) => {
134
+ const key = createDateKey(date);
135
+ if (weekendSet.has(key)) {
136
+ return true;
137
+ }
138
+ const dayOfWeek = date.getUTCDay();
139
+ return dayOfWeek === 0 || dayOfWeek === 6;
140
+ };
141
+ }
142
+ return (date) => {
143
+ const dayOfWeek = date.getUTCDay();
144
+ return dayOfWeek === 0 || dayOfWeek === 6;
145
+ };
146
+ };
110
147
  getMultiMonthDays = (tasks) => {
111
148
  if (!tasks || tasks.length === 0) {
112
149
  return getMonthDays(/* @__PURE__ */ new Date());
@@ -343,6 +380,8 @@ __export(index_exports, {
343
380
  computeLagFromDates: () => computeLagFromDates,
344
381
  computeParentDates: () => computeParentDates,
345
382
  computeParentProgress: () => computeParentProgress,
383
+ createDateKey: () => createDateKey,
384
+ createIsWeekendPredicate: () => createIsWeekendPredicate,
346
385
  detectCycles: () => detectCycles,
347
386
  detectEdgeZone: () => detectEdgeZone,
348
387
  findParentId: () => findParentId,
@@ -896,7 +935,8 @@ var TimeScaleHeader = ({
896
935
  days,
897
936
  dayWidth,
898
937
  headerHeight,
899
- viewMode = "day"
938
+ viewMode = "day",
939
+ isCustomWeekend
900
940
  }) => {
901
941
  const monthSpans = (0, import_react.useMemo)(() => getMonthSpans(days), [days]);
902
942
  const rowHeight = headerHeight / 2;
@@ -1060,12 +1100,12 @@ var TimeScaleHeader = ({
1060
1100
  ) : (
1061
1101
  // Day-view row 2: individual day numbers (existing code)
1062
1102
  days.map((day, index) => {
1063
- const isWeekend3 = day.getDay() === 0 || day.getDay() === 6;
1103
+ const isWeekendDay = isCustomWeekend ? isCustomWeekend(day) : day.getUTCDay() === 0 || day.getUTCDay() === 6;
1064
1104
  const prevDay = days[index - 1];
1065
- const isMonthBoundary = index > 0 && prevDay && prevDay.getMonth() !== day.getMonth();
1105
+ const isMonthBoundary = index > 0 && prevDay && prevDay.getUTCMonth() !== day.getUTCMonth();
1066
1106
  const now = /* @__PURE__ */ new Date();
1067
1107
  const isTodayDate = day.getUTCFullYear() === now.getFullYear() && day.getUTCMonth() === now.getMonth() && day.getUTCDate() === now.getDate();
1068
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `gantt-tsh-dayCell ${isWeekend3 ? "gantt-tsh-weekendDay" : ""} ${isTodayDate ? "gantt-tsh-today" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gantt-tsh-dayLabel", children: (0, import_date_fns.format)(day, "d") }) }, `day-${index}`);
1108
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `gantt-tsh-dayCell ${isWeekendDay ? "gantt-tsh-weekendDay" : ""} ${isTodayDate ? "gantt-tsh-today" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "gantt-tsh-dayLabel", children: (0, import_date_fns.format)(day, "d") }) }, `day-${index}`);
1069
1109
  })
1070
1110
  )
1071
1111
  }
@@ -1158,14 +1198,13 @@ var calculateGridLines = (dateRange, dayWidth) => {
1158
1198
  }
1159
1199
  return lines;
1160
1200
  };
1161
- var calculateWeekendBlocks = (dateRange, dayWidth) => {
1201
+ var calculateWeekendBlocks = (dateRange, dayWidth, isCustomWeekend) => {
1162
1202
  const blocks = [];
1163
1203
  let inWeekend = false;
1164
1204
  let weekendStartIndex = -1;
1165
1205
  for (let i = 0; i < dateRange.length; i++) {
1166
1206
  const date = dateRange[i];
1167
- const dayOfWeek = date.getUTCDay();
1168
- const isWeekend3 = dayOfWeek === 0 || dayOfWeek === 6;
1207
+ const isWeekend3 = isCustomWeekend ? isCustomWeekend(date) : date.getUTCDay() === 0 || date.getUTCDay() === 6;
1169
1208
  if (isWeekend3 && !inWeekend) {
1170
1209
  inWeekend = true;
1171
1210
  weekendStartIndex = i;
@@ -1981,10 +2020,10 @@ var import_react5 = __toESM(require("react"));
1981
2020
  var import_jsx_runtime4 = require("react/jsx-runtime");
1982
2021
  var arePropsEqual2 = (prevProps, nextProps) => {
1983
2022
  return prevProps.dayWidth === nextProps.dayWidth && prevProps.dateRange.length === nextProps.dateRange.length && prevProps.totalHeight === nextProps.totalHeight && // skip re-render only when totalHeight unchanged
1984
- prevProps.viewMode === nextProps.viewMode;
2023
+ prevProps.viewMode === nextProps.viewMode && prevProps.isCustomWeekend === nextProps.isCustomWeekend;
1985
2024
  };
1986
2025
  var GridBackground = import_react5.default.memo(
1987
- ({ dateRange, dayWidth, totalHeight, viewMode = "day" }) => {
2026
+ ({ dateRange, dayWidth, totalHeight, viewMode = "day", isCustomWeekend }) => {
1988
2027
  const weekGridLines = (0, import_react5.useMemo)(() => {
1989
2028
  if (viewMode !== "week") return [];
1990
2029
  return calculateWeekGridLines(dateRange, dayWidth);
@@ -1999,8 +2038,8 @@ var GridBackground = import_react5.default.memo(
1999
2038
  }, [dateRange, dayWidth, viewMode]);
2000
2039
  const weekendBlocks = (0, import_react5.useMemo)(() => {
2001
2040
  if (viewMode === "week" || viewMode === "month") return [];
2002
- return calculateWeekendBlocks(dateRange, dayWidth);
2003
- }, [dateRange, dayWidth, viewMode]);
2041
+ return calculateWeekendBlocks(dateRange, dayWidth, isCustomWeekend);
2042
+ }, [dateRange, dayWidth, viewMode, isCustomWeekend]);
2004
2043
  const gridWidth = (0, import_react5.useMemo)(() => {
2005
2044
  return Math.round(dateRange.length * dayWidth);
2006
2045
  }, [dateRange.length, dayWidth]);
@@ -2497,12 +2536,13 @@ var import_date_fns3 = require("date-fns");
2497
2536
  var import_react8 = require("react");
2498
2537
  var import_date_fns2 = require("date-fns");
2499
2538
  var import_locale2 = require("date-fns/locale");
2539
+ init_dateUtils();
2500
2540
  var import_jsx_runtime9 = require("react/jsx-runtime");
2501
- function getDayClassName(day, selected) {
2541
+ function getDayClassName(day, selected, isWeekendProp) {
2502
2542
  const classes = ["gantt-day-btn"];
2503
2543
  if (selected && (0, import_date_fns2.isSameDay)(day, selected)) classes.push("selected");
2504
2544
  if ((0, import_date_fns2.isToday)(day)) classes.push("today");
2505
- if ((0, import_date_fns2.isWeekend)(day)) classes.push("weekend");
2545
+ if (isWeekendProp ? isWeekendProp(day) : (0, import_date_fns2.isWeekend)(day)) classes.push("weekend");
2506
2546
  if ((0, import_date_fns2.isBefore)(day, (0, import_date_fns2.startOfDay)(/* @__PURE__ */ new Date())) && !(0, import_date_fns2.isToday)(day)) classes.push("past");
2507
2547
  return classes.join(" ");
2508
2548
  }
@@ -2511,9 +2551,22 @@ var Calendar = ({
2511
2551
  onSelect,
2512
2552
  initialDate,
2513
2553
  mode = "single",
2514
- disabled = false
2554
+ disabled = false,
2555
+ isWeekend: isWeekendProp,
2556
+ weekends,
2557
+ workdays
2515
2558
  }) => {
2516
2559
  const scrollRef = (0, import_react8.useRef)(null);
2560
+ const derivedWeekendPredicate = (0, import_react8.useMemo)(() => {
2561
+ if (isWeekendProp) return isWeekendProp;
2562
+ if (weekends || workdays) {
2563
+ return createIsWeekendPredicate({
2564
+ weekends: weekends ?? [],
2565
+ workdays: workdays ?? []
2566
+ });
2567
+ }
2568
+ return void 0;
2569
+ }, [isWeekendProp, weekends, workdays]);
2517
2570
  const initialMonth = (0, import_react8.useMemo)(
2518
2571
  () => (0, import_date_fns2.startOfMonth)(initialDate ?? selected ?? /* @__PURE__ */ new Date()),
2519
2572
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2567,11 +2620,13 @@ var Calendar = ({
2567
2620
  const emptyDays = ((0, import_date_fns2.getDay)(firstDay) + 6) % 7;
2568
2621
  const monthKey = (0, import_date_fns2.format)(month, "yyyy-MM");
2569
2622
  const monthLabel = (0, import_date_fns2.format)(month, "LLLL yyyy", { locale: import_locale2.ru });
2623
+ const weekdayLabels = ["\u041F\u043D", "\u0412\u0442", "\u0421\u0440", "\u0427\u0442", "\u041F\u0442", "\u0421\u0431", "\u0412\u0441"];
2624
+ const weekdayHeaders = weekdayLabels.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "gantt-cal-weekday", children: label }, `wd-${i}`));
2570
2625
  const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "gantt-cal-empty-day" }, `e-${i}`));
2571
2626
  const dayCells = Array.from({ length: totalDays }, (_, i) => {
2572
2627
  const dayNum = i + 1;
2573
- const day = new Date(month.getFullYear(), month.getMonth(), dayNum);
2574
- const className = getDayClassName(day, selected);
2628
+ const day = new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum));
2629
+ const className = getDayClassName(day, selected, derivedWeekendPredicate);
2575
2630
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2576
2631
  "button",
2577
2632
  {
@@ -2580,7 +2635,7 @@ var Calendar = ({
2580
2635
  disabled,
2581
2636
  onClick: () => {
2582
2637
  if (!disabled && onSelect) {
2583
- onSelect(new Date(month.getFullYear(), month.getMonth(), dayNum));
2638
+ onSelect(new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum)));
2584
2639
  }
2585
2640
  },
2586
2641
  children: dayNum
@@ -2591,12 +2646,13 @@ var Calendar = ({
2591
2646
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "gantt-cal-month", "data-month": monthKey, children: [
2592
2647
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "gantt-cal-month-header", children: monthLabel }),
2593
2648
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "gantt-cal-month-days", children: [
2649
+ weekdayHeaders,
2594
2650
  emptyCells,
2595
2651
  dayCells
2596
2652
  ] })
2597
2653
  ] }, monthKey);
2598
2654
  },
2599
- [selected, onSelect, disabled]
2655
+ [selected, onSelect, disabled, derivedWeekendPredicate]
2600
2656
  );
2601
2657
  const renderedMonths = (0, import_react8.useMemo)(
2602
2658
  () => months.map(renderMonth),
@@ -2620,7 +2676,10 @@ var DatePicker = ({
2620
2676
  placeholder = "Pick a date",
2621
2677
  portal = true,
2622
2678
  className,
2623
- disabled = false
2679
+ disabled = false,
2680
+ weekends,
2681
+ workdays,
2682
+ isWeekend: isWeekend3
2624
2683
  }) => {
2625
2684
  const [open, setOpen] = (0, import_react9.useState)(false);
2626
2685
  const [inputValue, setInputValue] = (0, import_react9.useState)("");
@@ -2840,7 +2899,10 @@ var DatePicker = ({
2840
2899
  mode: "single",
2841
2900
  selected: selectedDate,
2842
2901
  onSelect: handleCalendarSelect,
2843
- initialDate: selectedDate
2902
+ initialDate: selectedDate,
2903
+ weekends,
2904
+ workdays,
2905
+ isWeekend: isWeekend3
2844
2906
  }
2845
2907
  )
2846
2908
  ]
@@ -3306,7 +3368,10 @@ var TaskListRow = import_react10.default.memo(
3306
3368
  onDemoteTask,
3307
3369
  isLastChild = true,
3308
3370
  nestingDepth = 0,
3309
- ancestorContinues = []
3371
+ ancestorContinues = [],
3372
+ weekends,
3373
+ workdays,
3374
+ isWeekend: isWeekend3
3310
3375
  }) => {
3311
3376
  const [editingName, setEditingName] = (0, import_react10.useState)(false);
3312
3377
  const [nameValue, setNameValue] = (0, import_react10.useState)("");
@@ -3935,7 +4000,10 @@ var TaskListRow = import_react10.default.memo(
3935
4000
  onChange: handleStartDateChange,
3936
4001
  format: "dd.MM.yy",
3937
4002
  portal: true,
3938
- disabled: task.locked
4003
+ disabled: task.locked,
4004
+ weekends,
4005
+ workdays,
4006
+ isWeekend: isWeekend3
3939
4007
  }
3940
4008
  )
3941
4009
  }
@@ -3952,7 +4020,10 @@ var TaskListRow = import_react10.default.memo(
3952
4020
  onChange: handleEndDateChange,
3953
4021
  format: "dd.MM.yy",
3954
4022
  portal: true,
3955
- disabled: task.locked
4023
+ disabled: task.locked,
4024
+ weekends,
4025
+ workdays,
4026
+ isWeekend: isWeekend3
3956
4027
  }
3957
4028
  )
3958
4029
  }
@@ -4376,7 +4447,10 @@ var TaskList = ({
4376
4447
  collapsedParentIds: externalCollapsedParentIds,
4377
4448
  onToggleCollapse: externalOnToggleCollapse,
4378
4449
  onPromoteTask,
4379
- onDemoteTask
4450
+ onDemoteTask,
4451
+ weekends,
4452
+ workdays,
4453
+ isWeekend: isWeekend3
4380
4454
  }) => {
4381
4455
  const [internalCollapsedParentIds, setInternalCollapsedParentIds] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
4382
4456
  const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;
@@ -4842,7 +4916,10 @@ var TaskList = ({
4842
4916
  onDemoteTask: onDemoteTask ? handleDemoteWrapper : void 0,
4843
4917
  isLastChild: lastChildIds.has(task.id),
4844
4918
  nestingDepth: nestingDepthMap.get(task.id) ?? 0,
4845
- ancestorContinues: ancestorContinuesMap.get(task.id) ?? []
4919
+ ancestorContinues: ancestorContinuesMap.get(task.id) ?? [],
4920
+ weekends,
4921
+ workdays,
4922
+ isWeekend: isWeekend3
4846
4923
  },
4847
4924
  task.id
4848
4925
  )) }),
@@ -4910,7 +4987,10 @@ var GanttChart = (0, import_react13.forwardRef)(({
4910
4987
  onPromoteTask,
4911
4988
  onDemoteTask,
4912
4989
  enableAddTask = true,
4913
- viewMode = "day"
4990
+ viewMode = "day",
4991
+ weekends,
4992
+ workdays,
4993
+ isWeekend: isWeekend3
4914
4994
  }, ref) => {
4915
4995
  const scrollContainerRef = (0, import_react13.useRef)(null);
4916
4996
  const [selectedTaskId, setSelectedTaskId] = (0, import_react13.useState)(null);
@@ -4919,6 +4999,10 @@ var GanttChart = (0, import_react13.forwardRef)(({
4919
4999
  const [collapsedParentIds, setCollapsedParentIds] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
4920
5000
  const [editingTaskId, setEditingTaskId] = (0, import_react13.useState)(null);
4921
5001
  const normalizedTasks = (0, import_react13.useMemo)(() => normalizeHierarchyTasks(tasks), [tasks]);
5002
+ const isCustomWeekend = (0, import_react13.useMemo)(
5003
+ () => createIsWeekendPredicate({ weekends, workdays, isWeekend: isWeekend3 }),
5004
+ [weekends, workdays, isWeekend3]
5005
+ );
4922
5006
  const dateRange = (0, import_react13.useMemo)(() => getMultiMonthDays(normalizedTasks), [normalizedTasks]);
4923
5007
  const [validationResult, setValidationResult] = (0, import_react13.useState)(null);
4924
5008
  const [cascadeOverrides, setCascadeOverrides] = (0, import_react13.useState)(/* @__PURE__ */ new Map());
@@ -5310,7 +5394,10 @@ var GanttChart = (0, import_react13.forwardRef)(({
5310
5394
  collapsedParentIds,
5311
5395
  onToggleCollapse: handleToggleCollapse,
5312
5396
  onPromoteTask: onPromoteTask ?? handlePromoteTask,
5313
- onDemoteTask: onDemoteTask ?? handleDemoteTask
5397
+ onDemoteTask: onDemoteTask ?? handleDemoteTask,
5398
+ weekends,
5399
+ workdays,
5400
+ isWeekend: isWeekend3
5314
5401
  }
5315
5402
  ),
5316
5403
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
@@ -5320,7 +5407,8 @@ var GanttChart = (0, import_react13.forwardRef)(({
5320
5407
  days: dateRange,
5321
5408
  dayWidth,
5322
5409
  headerHeight,
5323
- viewMode
5410
+ viewMode,
5411
+ isCustomWeekend
5324
5412
  }
5325
5413
  ) }),
5326
5414
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
@@ -5338,7 +5426,8 @@ var GanttChart = (0, import_react13.forwardRef)(({
5338
5426
  dateRange,
5339
5427
  dayWidth,
5340
5428
  totalHeight: totalGridHeight,
5341
- viewMode
5429
+ viewMode,
5430
+ isCustomWeekend
5342
5431
  }
5343
5432
  ),
5344
5433
  todayInRange && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
@@ -5453,6 +5542,8 @@ init_dateUtils();
5453
5542
  computeLagFromDates,
5454
5543
  computeParentDates,
5455
5544
  computeParentProgress,
5545
+ createDateKey,
5546
+ createIsWeekendPredicate,
5456
5547
  detectCycles,
5457
5548
  detectEdgeZone,
5458
5549
  findParentId,