gantt-lib 0.77.0 → 0.79.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.mjs CHANGED
@@ -1,28 +1,12 @@
1
1
  "use client";
2
2
 
3
3
  "use client";
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- };
11
- var __export = (target, all) => {
12
- for (var name in all)
13
- __defProp(target, name, { get: all[name], enumerable: true });
14
- };
15
- var __copyProps = (to, from, except, desc) => {
16
- if (from && typeof from === "object" || typeof from === "function") {
17
- for (let key of __getOwnPropNames(from))
18
- if (!__hasOwnProp.call(to, key) && key !== except)
19
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
- }
21
- return to;
22
- };
23
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
4
+
5
+ // src/components/GanttChart/GanttChart.tsx
6
+ import { useMemo as useMemo10, useCallback as useCallback8, useRef as useRef9, useState as useState8, useEffect as useEffect9, useImperativeHandle, forwardRef } from "react";
24
7
 
25
8
  // src/core/scheduling/dateMath.ts
9
+ var DAY_MS = 24 * 60 * 60 * 1e3;
26
10
  function normalizeUTCDate(date) {
27
11
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
28
12
  }
@@ -120,37 +104,328 @@ function getTaskDuration(startDate, endDate, businessDays = false, weekendPredic
120
104
  }
121
105
  return Math.max(1, Math.round((end.getTime() - start.getTime()) / DAY_MS) + 1);
122
106
  }
123
- var DAY_MS;
124
- var init_dateMath = __esm({
125
- "src/core/scheduling/dateMath.ts"() {
126
- "use strict";
127
- DAY_MS = 24 * 60 * 60 * 1e3;
128
- }
129
- });
130
107
 
131
108
  // src/utils/dateUtils.ts
132
- var dateUtils_exports = {};
133
- __export(dateUtils_exports, {
134
- addBusinessDays: () => addBusinessDays2,
135
- createCustomDayPredicate: () => createCustomDayPredicate,
136
- createDateKey: () => createDateKey,
137
- formatDateLabel: () => formatDateLabel,
138
- formatDateRangeLabel: () => formatDateRangeLabel,
139
- getBusinessDaysCount: () => getBusinessDaysCount2,
140
- getDayOffset: () => getDayOffset,
141
- getMonthBlocks: () => getMonthBlocks,
142
- getMonthDays: () => getMonthDays,
143
- getMonthSpans: () => getMonthSpans,
144
- getMultiMonthDays: () => getMultiMonthDays,
145
- getWeekBlocks: () => getWeekBlocks,
146
- getWeekSpans: () => getWeekSpans,
147
- getYearSpans: () => getYearSpans,
148
- isToday: () => isToday,
149
- isWeekend: () => isWeekend,
150
- normalizeTaskDates: () => normalizeTaskDates,
151
- parseUTCDate: () => parseUTCDate,
152
- subtractBusinessDays: () => subtractBusinessDays2
153
- });
109
+ var parseUTCDate = (date) => {
110
+ if (typeof date === "string") {
111
+ const dateStr = date.includes("T") ? date : `${date}T00:00:00Z`;
112
+ const parsed = new Date(dateStr);
113
+ if (isNaN(parsed.getTime())) {
114
+ throw new Error(`Invalid date string: ${date}`);
115
+ }
116
+ return parsed;
117
+ }
118
+ return date;
119
+ };
120
+ var getMonthDays = (date) => {
121
+ const utcDate = parseUTCDate(date);
122
+ const year = utcDate.getUTCFullYear();
123
+ const month = utcDate.getUTCMonth();
124
+ const daysInMonth = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
125
+ const days = [];
126
+ for (let day = 1; day <= daysInMonth; day++) {
127
+ days.push(new Date(Date.UTC(year, month, day)));
128
+ }
129
+ return days;
130
+ };
131
+ var getDayOffset = (date, monthStart) => {
132
+ const dateMs = Date.UTC(
133
+ date.getUTCFullYear(),
134
+ date.getUTCMonth(),
135
+ date.getUTCDate()
136
+ );
137
+ const startMs = Date.UTC(
138
+ monthStart.getUTCFullYear(),
139
+ monthStart.getUTCMonth(),
140
+ monthStart.getUTCDate()
141
+ );
142
+ return Math.round((dateMs - startMs) / (1e3 * 60 * 60 * 24));
143
+ };
144
+ var isToday = (date) => {
145
+ const now = /* @__PURE__ */ new Date();
146
+ const today = new Date(Date.UTC(
147
+ now.getFullYear(),
148
+ now.getMonth(),
149
+ now.getDate()
150
+ ));
151
+ const compareDate = new Date(Date.UTC(
152
+ date.getUTCFullYear(),
153
+ date.getUTCMonth(),
154
+ date.getUTCDate()
155
+ ));
156
+ return today.getTime() === compareDate.getTime();
157
+ };
158
+ var isWeekend = (date) => {
159
+ const day = date.getUTCDay();
160
+ return day === 0 || day === 6;
161
+ };
162
+ var createDateKey = (date) => {
163
+ return `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}`;
164
+ };
165
+ var createCustomDayPredicate = (config) => {
166
+ const { customDays, isWeekend: basePredicate } = config;
167
+ const workdaySet = /* @__PURE__ */ new Set();
168
+ const weekendSet = /* @__PURE__ */ new Set();
169
+ if (customDays && customDays.length > 0) {
170
+ for (const item of customDays) {
171
+ const key = createDateKey(item.date);
172
+ if (item.type === "workday") {
173
+ workdaySet.add(key);
174
+ } else {
175
+ weekendSet.add(key);
176
+ }
177
+ }
178
+ }
179
+ return (date) => {
180
+ const key = createDateKey(date);
181
+ if (workdaySet.has(key)) {
182
+ return false;
183
+ }
184
+ if (weekendSet.has(key)) {
185
+ return true;
186
+ }
187
+ if (basePredicate) {
188
+ return basePredicate(date);
189
+ }
190
+ const dayOfWeek = date.getUTCDay();
191
+ return dayOfWeek === 0 || dayOfWeek === 6;
192
+ };
193
+ };
194
+ var getMultiMonthDays = (tasks) => {
195
+ if (!tasks || tasks.length === 0) {
196
+ return getMonthDays(/* @__PURE__ */ new Date());
197
+ }
198
+ let minDate = null;
199
+ let maxDate = null;
200
+ for (const task of tasks) {
201
+ const start = parseUTCDate(task.startDate);
202
+ const end = parseUTCDate(task.endDate);
203
+ if (!minDate || start.getTime() < minDate.getTime()) {
204
+ minDate = start;
205
+ }
206
+ if (!maxDate || end.getTime() > maxDate.getTime()) {
207
+ maxDate = end;
208
+ }
209
+ }
210
+ if (!minDate || !maxDate) {
211
+ return getMonthDays(/* @__PURE__ */ new Date());
212
+ }
213
+ const startOfMonth2 = new Date(Date.UTC(
214
+ minDate.getUTCFullYear(),
215
+ minDate.getUTCMonth(),
216
+ 1
217
+ ));
218
+ const endOfMonth = new Date(Date.UTC(
219
+ maxDate.getUTCFullYear(),
220
+ maxDate.getUTCMonth() + 1 + 2,
221
+ // Original + 2 months padding after
222
+ 0
223
+ ));
224
+ const days = [];
225
+ const current = new Date(startOfMonth2);
226
+ while (current.getTime() <= endOfMonth.getTime()) {
227
+ days.push(new Date(Date.UTC(
228
+ current.getUTCFullYear(),
229
+ current.getUTCMonth(),
230
+ current.getUTCDate()
231
+ )));
232
+ current.setUTCDate(current.getUTCDate() + 1);
233
+ }
234
+ return days;
235
+ };
236
+ var getMonthSpans = (dateRange) => {
237
+ if (dateRange.length === 0) {
238
+ return [];
239
+ }
240
+ const spans = [];
241
+ let currentMonthYear = `${dateRange[0].getUTCFullYear()}-${dateRange[0].getUTCMonth()}`;
242
+ let startOfMonthIndex = 0;
243
+ for (let i = 0; i < dateRange.length; i++) {
244
+ const date = dateRange[i];
245
+ const monthYear = `${date.getUTCFullYear()}-${date.getUTCMonth()}`;
246
+ if (monthYear !== currentMonthYear) {
247
+ spans.push({
248
+ month: new Date(Date.UTC(
249
+ dateRange[startOfMonthIndex].getUTCFullYear(),
250
+ dateRange[startOfMonthIndex].getUTCMonth(),
251
+ 1
252
+ )),
253
+ days: i - startOfMonthIndex,
254
+ startIndex: startOfMonthIndex
255
+ });
256
+ currentMonthYear = monthYear;
257
+ startOfMonthIndex = i;
258
+ }
259
+ if (i === dateRange.length - 1) {
260
+ spans.push({
261
+ month: new Date(Date.UTC(
262
+ date.getUTCFullYear(),
263
+ date.getUTCMonth(),
264
+ 1
265
+ )),
266
+ days: i - startOfMonthIndex + 1,
267
+ startIndex: startOfMonthIndex
268
+ });
269
+ }
270
+ }
271
+ return spans;
272
+ };
273
+ var formatDateLabel = (date) => {
274
+ const parsed = parseUTCDate(date);
275
+ const day = String(parsed.getUTCDate()).padStart(2, "0");
276
+ const month = String(parsed.getUTCMonth() + 1).padStart(2, "0");
277
+ return `${day}.${month}`;
278
+ };
279
+ var MONTH_ABBR = [
280
+ "\u044F\u043D\u0432",
281
+ "\u0444\u0435\u0432",
282
+ "\u043C\u0430\u0440",
283
+ "\u0430\u043F\u0440",
284
+ "\u043C\u0430\u044F",
285
+ "\u0438\u044E\u043D",
286
+ "\u0438\u044E\u043B",
287
+ "\u0430\u0432\u0433",
288
+ "\u0441\u0435\u043D",
289
+ "\u043E\u043A\u0442",
290
+ "\u043D\u043E\u044F",
291
+ "\u0434\u0435\u043A"
292
+ ];
293
+ var formatDateRangeLabel = (startDate, endDate) => {
294
+ const start = parseUTCDate(startDate);
295
+ const end = parseUTCDate(endDate);
296
+ const startDay = start.getUTCDate();
297
+ const endDay = end.getUTCDate();
298
+ const startMonth = start.getUTCMonth();
299
+ const endMonth = end.getUTCMonth();
300
+ const startYear = start.getUTCFullYear();
301
+ const endYear = end.getUTCFullYear();
302
+ if (startMonth === endMonth && startYear === endYear) {
303
+ if (startDay === endDay) {
304
+ return `${startDay} ${MONTH_ABBR[startMonth]}`;
305
+ }
306
+ return `${startDay}\u2013${endDay} ${MONTH_ABBR[startMonth]}`;
307
+ }
308
+ if (startYear === endYear) {
309
+ return `${startDay} ${MONTH_ABBR[startMonth]}\u2013${endDay} ${MONTH_ABBR[endMonth]}`;
310
+ }
311
+ return `${startDay} ${MONTH_ABBR[startMonth]} ${startYear}\u2013${endDay} ${MONTH_ABBR[endMonth]} ${endYear}`;
312
+ };
313
+ var getWeekBlocks = (days) => {
314
+ if (days.length === 0) return [];
315
+ const blocks = [];
316
+ let blockStart = 0;
317
+ while (blockStart < days.length) {
318
+ const maxBlockEnd = Math.min(blockStart + 7, days.length);
319
+ const startMonthYear = `${days[blockStart].getUTCFullYear()}-${days[blockStart].getUTCMonth()}`;
320
+ let actualBlockEnd = blockStart + 7;
321
+ if (actualBlockEnd > days.length) {
322
+ actualBlockEnd = days.length;
323
+ }
324
+ for (let i = blockStart + 1; i < maxBlockEnd; i++) {
325
+ const monthYear = `${days[i].getUTCFullYear()}-${days[i].getUTCMonth()}`;
326
+ if (monthYear !== startMonthYear) {
327
+ actualBlockEnd = i;
328
+ break;
329
+ }
330
+ }
331
+ blocks.push({
332
+ startDate: days[blockStart],
333
+ days: actualBlockEnd - blockStart
334
+ });
335
+ blockStart = actualBlockEnd;
336
+ }
337
+ return blocks;
338
+ };
339
+ var getWeekSpans = (days) => {
340
+ const blocks = getWeekBlocks(days);
341
+ if (blocks.length === 0) return [];
342
+ const spans = [];
343
+ let currentMonthYear = `${blocks[0].startDate.getUTCFullYear()}-${blocks[0].startDate.getUTCMonth()}`;
344
+ let startIndex = 0;
345
+ let totalDays = 0;
346
+ for (let i = 0; i < blocks.length; i++) {
347
+ const block = blocks[i];
348
+ const monthYear = `${block.startDate.getUTCFullYear()}-${block.startDate.getUTCMonth()}`;
349
+ if (monthYear !== currentMonthYear) {
350
+ spans.push({
351
+ month: new Date(Date.UTC(
352
+ blocks[startIndex].startDate.getUTCFullYear(),
353
+ blocks[startIndex].startDate.getUTCMonth(),
354
+ 1
355
+ )),
356
+ days: totalDays,
357
+ startIndex
358
+ });
359
+ currentMonthYear = monthYear;
360
+ startIndex = i;
361
+ totalDays = 0;
362
+ }
363
+ totalDays += block.days;
364
+ if (i === blocks.length - 1) {
365
+ spans.push({
366
+ month: new Date(Date.UTC(
367
+ block.startDate.getUTCFullYear(),
368
+ block.startDate.getUTCMonth(),
369
+ 1
370
+ )),
371
+ days: totalDays,
372
+ startIndex
373
+ });
374
+ }
375
+ }
376
+ return spans;
377
+ };
378
+ var getMonthBlocks = (days) => {
379
+ if (days.length === 0) return [];
380
+ return getMonthSpans(days).map((span) => ({
381
+ startDate: span.month,
382
+ days: span.days
383
+ }));
384
+ };
385
+ var getYearSpans = (days) => {
386
+ const blocks = getMonthBlocks(days);
387
+ if (blocks.length === 0) return [];
388
+ const spans = [];
389
+ let currentYear = blocks[0].startDate.getUTCFullYear();
390
+ let startIndex = 0;
391
+ let totalDays = 0;
392
+ for (let i = 0; i < blocks.length; i++) {
393
+ const blockYear = blocks[i].startDate.getUTCFullYear();
394
+ if (blockYear !== currentYear) {
395
+ spans.push({
396
+ year: new Date(Date.UTC(currentYear, 0, 1)),
397
+ days: totalDays,
398
+ startIndex
399
+ });
400
+ currentYear = blockYear;
401
+ startIndex = i;
402
+ totalDays = 0;
403
+ }
404
+ totalDays += blocks[i].days;
405
+ if (i === blocks.length - 1) {
406
+ spans.push({
407
+ year: new Date(Date.UTC(currentYear, 0, 1)),
408
+ days: totalDays,
409
+ startIndex
410
+ });
411
+ }
412
+ }
413
+ return spans;
414
+ };
415
+ var normalizeTaskDates = (startDate, endDate) => {
416
+ const start = parseUTCDate(startDate);
417
+ const end = parseUTCDate(endDate);
418
+ if (end.getTime() < start.getTime()) {
419
+ return {
420
+ startDate: end.toISOString().split("T")[0],
421
+ endDate: start.toISOString().split("T")[0]
422
+ };
423
+ }
424
+ return {
425
+ startDate: start.toISOString().split("T")[0],
426
+ endDate: end.toISOString().split("T")[0]
427
+ };
428
+ };
154
429
  function getBusinessDaysCount2(startDate, endDate, weekendPredicate) {
155
430
  return getBusinessDaysCount(startDate, endDate, weekendPredicate);
156
431
  }
@@ -162,343 +437,8 @@ function subtractBusinessDays2(endDate, businessDays, weekendPredicate) {
162
437
  const result = subtractBusinessDays(endDate, businessDays, weekendPredicate);
163
438
  return result.toISOString().split("T")[0];
164
439
  }
165
- var parseUTCDate, getMonthDays, getDayOffset, isToday, isWeekend, createDateKey, createCustomDayPredicate, getMultiMonthDays, getMonthSpans, formatDateLabel, MONTH_ABBR, formatDateRangeLabel, getWeekBlocks, getWeekSpans, getMonthBlocks, getYearSpans, normalizeTaskDates;
166
- var init_dateUtils = __esm({
167
- "src/utils/dateUtils.ts"() {
168
- "use strict";
169
- init_dateMath();
170
- parseUTCDate = (date) => {
171
- if (typeof date === "string") {
172
- const dateStr = date.includes("T") ? date : `${date}T00:00:00Z`;
173
- const parsed = new Date(dateStr);
174
- if (isNaN(parsed.getTime())) {
175
- throw new Error(`Invalid date string: ${date}`);
176
- }
177
- return parsed;
178
- }
179
- return date;
180
- };
181
- getMonthDays = (date) => {
182
- const utcDate = parseUTCDate(date);
183
- const year = utcDate.getUTCFullYear();
184
- const month = utcDate.getUTCMonth();
185
- const daysInMonth = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
186
- const days = [];
187
- for (let day = 1; day <= daysInMonth; day++) {
188
- days.push(new Date(Date.UTC(year, month, day)));
189
- }
190
- return days;
191
- };
192
- getDayOffset = (date, monthStart) => {
193
- const dateMs = Date.UTC(
194
- date.getUTCFullYear(),
195
- date.getUTCMonth(),
196
- date.getUTCDate()
197
- );
198
- const startMs = Date.UTC(
199
- monthStart.getUTCFullYear(),
200
- monthStart.getUTCMonth(),
201
- monthStart.getUTCDate()
202
- );
203
- return Math.round((dateMs - startMs) / (1e3 * 60 * 60 * 24));
204
- };
205
- isToday = (date) => {
206
- const now = /* @__PURE__ */ new Date();
207
- const today = new Date(Date.UTC(
208
- now.getFullYear(),
209
- now.getMonth(),
210
- now.getDate()
211
- ));
212
- const compareDate = new Date(Date.UTC(
213
- date.getUTCFullYear(),
214
- date.getUTCMonth(),
215
- date.getUTCDate()
216
- ));
217
- return today.getTime() === compareDate.getTime();
218
- };
219
- isWeekend = (date) => {
220
- const day = date.getUTCDay();
221
- return day === 0 || day === 6;
222
- };
223
- createDateKey = (date) => {
224
- return `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}`;
225
- };
226
- createCustomDayPredicate = (config) => {
227
- const { customDays, isWeekend: basePredicate } = config;
228
- const workdaySet = /* @__PURE__ */ new Set();
229
- const weekendSet = /* @__PURE__ */ new Set();
230
- if (customDays && customDays.length > 0) {
231
- for (const item of customDays) {
232
- const key = createDateKey(item.date);
233
- if (item.type === "workday") {
234
- workdaySet.add(key);
235
- } else {
236
- weekendSet.add(key);
237
- }
238
- }
239
- }
240
- return (date) => {
241
- const key = createDateKey(date);
242
- if (workdaySet.has(key)) {
243
- return false;
244
- }
245
- if (weekendSet.has(key)) {
246
- return true;
247
- }
248
- if (basePredicate) {
249
- return basePredicate(date);
250
- }
251
- const dayOfWeek = date.getUTCDay();
252
- return dayOfWeek === 0 || dayOfWeek === 6;
253
- };
254
- };
255
- getMultiMonthDays = (tasks) => {
256
- if (!tasks || tasks.length === 0) {
257
- return getMonthDays(/* @__PURE__ */ new Date());
258
- }
259
- let minDate = null;
260
- let maxDate = null;
261
- for (const task of tasks) {
262
- const start = parseUTCDate(task.startDate);
263
- const end = parseUTCDate(task.endDate);
264
- if (!minDate || start.getTime() < minDate.getTime()) {
265
- minDate = start;
266
- }
267
- if (!maxDate || end.getTime() > maxDate.getTime()) {
268
- maxDate = end;
269
- }
270
- }
271
- if (!minDate || !maxDate) {
272
- return getMonthDays(/* @__PURE__ */ new Date());
273
- }
274
- const startOfMonth2 = new Date(Date.UTC(
275
- minDate.getUTCFullYear(),
276
- minDate.getUTCMonth(),
277
- 1
278
- ));
279
- const endOfMonth = new Date(Date.UTC(
280
- maxDate.getUTCFullYear(),
281
- maxDate.getUTCMonth() + 1 + 2,
282
- // Original + 2 months padding after
283
- 0
284
- ));
285
- const days = [];
286
- const current = new Date(startOfMonth2);
287
- while (current.getTime() <= endOfMonth.getTime()) {
288
- days.push(new Date(Date.UTC(
289
- current.getUTCFullYear(),
290
- current.getUTCMonth(),
291
- current.getUTCDate()
292
- )));
293
- current.setUTCDate(current.getUTCDate() + 1);
294
- }
295
- return days;
296
- };
297
- getMonthSpans = (dateRange) => {
298
- if (dateRange.length === 0) {
299
- return [];
300
- }
301
- const spans = [];
302
- let currentMonthYear = `${dateRange[0].getUTCFullYear()}-${dateRange[0].getUTCMonth()}`;
303
- let startOfMonthIndex = 0;
304
- for (let i = 0; i < dateRange.length; i++) {
305
- const date = dateRange[i];
306
- const monthYear = `${date.getUTCFullYear()}-${date.getUTCMonth()}`;
307
- if (monthYear !== currentMonthYear) {
308
- spans.push({
309
- month: new Date(Date.UTC(
310
- dateRange[startOfMonthIndex].getUTCFullYear(),
311
- dateRange[startOfMonthIndex].getUTCMonth(),
312
- 1
313
- )),
314
- days: i - startOfMonthIndex,
315
- startIndex: startOfMonthIndex
316
- });
317
- currentMonthYear = monthYear;
318
- startOfMonthIndex = i;
319
- }
320
- if (i === dateRange.length - 1) {
321
- spans.push({
322
- month: new Date(Date.UTC(
323
- date.getUTCFullYear(),
324
- date.getUTCMonth(),
325
- 1
326
- )),
327
- days: i - startOfMonthIndex + 1,
328
- startIndex: startOfMonthIndex
329
- });
330
- }
331
- }
332
- return spans;
333
- };
334
- formatDateLabel = (date) => {
335
- const parsed = parseUTCDate(date);
336
- const day = String(parsed.getUTCDate()).padStart(2, "0");
337
- const month = String(parsed.getUTCMonth() + 1).padStart(2, "0");
338
- return `${day}.${month}`;
339
- };
340
- MONTH_ABBR = [
341
- "\u044F\u043D\u0432",
342
- "\u0444\u0435\u0432",
343
- "\u043C\u0430\u0440",
344
- "\u0430\u043F\u0440",
345
- "\u043C\u0430\u044F",
346
- "\u0438\u044E\u043D",
347
- "\u0438\u044E\u043B",
348
- "\u0430\u0432\u0433",
349
- "\u0441\u0435\u043D",
350
- "\u043E\u043A\u0442",
351
- "\u043D\u043E\u044F",
352
- "\u0434\u0435\u043A"
353
- ];
354
- formatDateRangeLabel = (startDate, endDate) => {
355
- const start = parseUTCDate(startDate);
356
- const end = parseUTCDate(endDate);
357
- const startDay = start.getUTCDate();
358
- const endDay = end.getUTCDate();
359
- const startMonth = start.getUTCMonth();
360
- const endMonth = end.getUTCMonth();
361
- const startYear = start.getUTCFullYear();
362
- const endYear = end.getUTCFullYear();
363
- if (startMonth === endMonth && startYear === endYear) {
364
- if (startDay === endDay) {
365
- return `${startDay} ${MONTH_ABBR[startMonth]}`;
366
- }
367
- return `${startDay}\u2013${endDay} ${MONTH_ABBR[startMonth]}`;
368
- }
369
- if (startYear === endYear) {
370
- return `${startDay} ${MONTH_ABBR[startMonth]}\u2013${endDay} ${MONTH_ABBR[endMonth]}`;
371
- }
372
- return `${startDay} ${MONTH_ABBR[startMonth]} ${startYear}\u2013${endDay} ${MONTH_ABBR[endMonth]} ${endYear}`;
373
- };
374
- getWeekBlocks = (days) => {
375
- if (days.length === 0) return [];
376
- const blocks = [];
377
- let blockStart = 0;
378
- while (blockStart < days.length) {
379
- const maxBlockEnd = Math.min(blockStart + 7, days.length);
380
- const startMonthYear = `${days[blockStart].getUTCFullYear()}-${days[blockStart].getUTCMonth()}`;
381
- let actualBlockEnd = blockStart + 7;
382
- if (actualBlockEnd > days.length) {
383
- actualBlockEnd = days.length;
384
- }
385
- for (let i = blockStart + 1; i < maxBlockEnd; i++) {
386
- const monthYear = `${days[i].getUTCFullYear()}-${days[i].getUTCMonth()}`;
387
- if (monthYear !== startMonthYear) {
388
- actualBlockEnd = i;
389
- break;
390
- }
391
- }
392
- blocks.push({
393
- startDate: days[blockStart],
394
- days: actualBlockEnd - blockStart
395
- });
396
- blockStart = actualBlockEnd;
397
- }
398
- return blocks;
399
- };
400
- getWeekSpans = (days) => {
401
- const blocks = getWeekBlocks(days);
402
- if (blocks.length === 0) return [];
403
- const spans = [];
404
- let currentMonthYear = `${blocks[0].startDate.getUTCFullYear()}-${blocks[0].startDate.getUTCMonth()}`;
405
- let startIndex = 0;
406
- let totalDays = 0;
407
- for (let i = 0; i < blocks.length; i++) {
408
- const block = blocks[i];
409
- const monthYear = `${block.startDate.getUTCFullYear()}-${block.startDate.getUTCMonth()}`;
410
- if (monthYear !== currentMonthYear) {
411
- spans.push({
412
- month: new Date(Date.UTC(
413
- blocks[startIndex].startDate.getUTCFullYear(),
414
- blocks[startIndex].startDate.getUTCMonth(),
415
- 1
416
- )),
417
- days: totalDays,
418
- startIndex
419
- });
420
- currentMonthYear = monthYear;
421
- startIndex = i;
422
- totalDays = 0;
423
- }
424
- totalDays += block.days;
425
- if (i === blocks.length - 1) {
426
- spans.push({
427
- month: new Date(Date.UTC(
428
- block.startDate.getUTCFullYear(),
429
- block.startDate.getUTCMonth(),
430
- 1
431
- )),
432
- days: totalDays,
433
- startIndex
434
- });
435
- }
436
- }
437
- return spans;
438
- };
439
- getMonthBlocks = (days) => {
440
- if (days.length === 0) return [];
441
- return getMonthSpans(days).map((span) => ({
442
- startDate: span.month,
443
- days: span.days
444
- }));
445
- };
446
- getYearSpans = (days) => {
447
- const blocks = getMonthBlocks(days);
448
- if (blocks.length === 0) return [];
449
- const spans = [];
450
- let currentYear = blocks[0].startDate.getUTCFullYear();
451
- let startIndex = 0;
452
- let totalDays = 0;
453
- for (let i = 0; i < blocks.length; i++) {
454
- const blockYear = blocks[i].startDate.getUTCFullYear();
455
- if (blockYear !== currentYear) {
456
- spans.push({
457
- year: new Date(Date.UTC(currentYear, 0, 1)),
458
- days: totalDays,
459
- startIndex
460
- });
461
- currentYear = blockYear;
462
- startIndex = i;
463
- totalDays = 0;
464
- }
465
- totalDays += blocks[i].days;
466
- if (i === blocks.length - 1) {
467
- spans.push({
468
- year: new Date(Date.UTC(currentYear, 0, 1)),
469
- days: totalDays,
470
- startIndex
471
- });
472
- }
473
- }
474
- return spans;
475
- };
476
- normalizeTaskDates = (startDate, endDate) => {
477
- const start = parseUTCDate(startDate);
478
- const end = parseUTCDate(endDate);
479
- if (end.getTime() < start.getTime()) {
480
- return {
481
- startDate: end.toISOString().split("T")[0],
482
- endDate: start.toISOString().split("T")[0]
483
- };
484
- }
485
- return {
486
- startDate: start.toISOString().split("T")[0],
487
- endDate: end.toISOString().split("T")[0]
488
- };
489
- };
490
- }
491
- });
492
-
493
- // src/components/GanttChart/GanttChart.tsx
494
- init_dateUtils();
495
- import { useMemo as useMemo10, useCallback as useCallback8, useRef as useRef9, useState as useState8, useEffect as useEffect9, useImperativeHandle, forwardRef } from "react";
496
-
497
- // src/core/scheduling/index.ts
498
- init_dateMath();
499
440
 
500
441
  // src/core/scheduling/dependencies.ts
501
- init_dateMath();
502
442
  function normalizePredecessorDates(predecessor, parseDateFn) {
503
443
  const predStart = parseDateFn(predecessor.startDate);
504
444
  const isMilestone = predecessor.type === "milestone";
@@ -605,9 +545,6 @@ function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag
605
545
  return shiftBusinessDayOffset(anchorDate, offset, weekendPredicate);
606
546
  }
607
547
 
608
- // src/core/scheduling/cascade.ts
609
- init_dateMath();
610
-
611
548
  // src/core/scheduling/hierarchy.ts
612
549
  function getChildren(parentId, tasks) {
613
550
  return tasks.filter((t) => t.parentId === parentId);
@@ -729,7 +666,6 @@ function areTasksHierarchicallyRelated(taskId1, taskId2, tasks) {
729
666
  }
730
667
 
731
668
  // src/core/scheduling/commands.ts
732
- init_dateMath();
733
669
  function buildTaskRangeFromStart(startDate, duration, businessDays = false, weekendPredicate, snapDirection = 1) {
734
670
  const normalizedStart = businessDays && weekendPredicate ? alignToWorkingDay(startDate, snapDirection, weekendPredicate) : normalizeUTCDate(startDate);
735
671
  if (businessDays && weekendPredicate) {
@@ -1137,11 +1073,7 @@ function universalCascade(movedTask, newStart, newEnd, allTasks, businessDays =
1137
1073
  return Array.from(resultMap.values());
1138
1074
  }
1139
1075
 
1140
- // src/core/scheduling/modeSwitch.ts
1141
- init_dateMath();
1142
-
1143
1076
  // src/core/scheduling/execute.ts
1144
- init_dateMath();
1145
1077
  function toIsoDate(date) {
1146
1078
  return date.toISOString().split("T")[0];
1147
1079
  }
@@ -1583,7 +1515,6 @@ function validateDependencies(tasks) {
1583
1515
  }
1584
1516
 
1585
1517
  // src/utils/hierarchyOrder.ts
1586
- init_dateUtils();
1587
1518
  function flattenHierarchy(tasks) {
1588
1519
  const byId = new Map(tasks.map((task) => [task.id, task]));
1589
1520
  const byParent = /* @__PURE__ */ new Map();
@@ -1636,7 +1567,6 @@ function normalizeHierarchyTasks(tasks) {
1636
1567
  }
1637
1568
 
1638
1569
  // src/components/TimeScaleHeader/TimeScaleHeader.tsx
1639
- init_dateUtils();
1640
1570
  import { useMemo } from "react";
1641
1571
  import { format } from "date-fns";
1642
1572
  import { ru } from "date-fns/locale";
@@ -1827,7 +1757,6 @@ var TimeScaleHeader = ({
1827
1757
  var TimeScaleHeader_default = TimeScaleHeader;
1828
1758
 
1829
1759
  // src/components/TaskRow/TaskRow.tsx
1830
- init_dateUtils();
1831
1760
  import React2, { useMemo as useMemo2 } from "react";
1832
1761
 
1833
1762
  // src/utils/geometry.ts
@@ -2039,8 +1968,7 @@ var calculateDependencyPath = (from, to, arrivesFromRight) => {
2039
1968
  }
2040
1969
  };
2041
1970
  var calculateWeekGridLines = (dateRange, dayWidth) => {
2042
- const { getWeekBlocks: getWeekBlocks2 } = (init_dateUtils(), __toCommonJS(dateUtils_exports));
2043
- const blocks = getWeekBlocks2(dateRange);
1971
+ const blocks = getWeekBlocks(dateRange);
2044
1972
  const lines = [];
2045
1973
  let currentDayIndex = 0;
2046
1974
  for (let i = 0; i < blocks.length; i++) {
@@ -2096,7 +2024,6 @@ var calculateOrthogonalPath = (from, to) => {
2096
2024
  };
2097
2025
 
2098
2026
  // src/utils/expired.ts
2099
- init_dateUtils();
2100
2027
  var isTaskExpired = (task, referenceDate = /* @__PURE__ */ new Date()) => {
2101
2028
  if (!task) return false;
2102
2029
  const actualProgress = task.progress ?? 0;
@@ -2117,7 +2044,6 @@ var isTaskExpired = (task, referenceDate = /* @__PURE__ */ new Date()) => {
2117
2044
  };
2118
2045
 
2119
2046
  // src/utils/taskType.ts
2120
- init_dateUtils();
2121
2047
  var TASK_TYPE_DEFAULT = "task";
2122
2048
  function getTaskType(task) {
2123
2049
  return task.type ?? TASK_TYPE_DEFAULT;
@@ -2151,7 +2077,6 @@ function normalizeTaskDatesForType(task) {
2151
2077
  import { useEffect, useRef, useState, useCallback } from "react";
2152
2078
 
2153
2079
  // src/adapters/scheduling/drag.ts
2154
- init_dateMath();
2155
2080
  function resolveDateRangeFromPixels(mode, left, width, monthStart, dayWidth, task, businessDays, weekendPredicate) {
2156
2081
  const dayOffset = Math.round(left / dayWidth);
2157
2082
  const rawStartDate = new Date(Date.UTC(
@@ -3035,7 +2960,6 @@ TaskRow.displayName = "TaskRow";
3035
2960
  var TaskRow_default = TaskRow;
3036
2961
 
3037
2962
  // src/components/TodayIndicator/TodayIndicator.tsx
3038
- init_dateUtils();
3039
2963
  import { useMemo as useMemo3 } from "react";
3040
2964
  import { jsx as jsx3 } from "react/jsx-runtime";
3041
2965
  var TodayIndicator = ({ monthStart, dayWidth }) => {
@@ -3427,6 +3351,25 @@ var DependencyLines = React5.memo(({
3427
3351
  }
3428
3352
  )
3429
3353
  }
3354
+ ),
3355
+ /* @__PURE__ */ jsx6(
3356
+ "marker",
3357
+ {
3358
+ id: "arrowhead-hover",
3359
+ markerWidth: "8",
3360
+ markerHeight: "6",
3361
+ markerUnits: "userSpaceOnUse",
3362
+ refX: "7",
3363
+ refY: "3",
3364
+ orient: "auto",
3365
+ children: /* @__PURE__ */ jsx6(
3366
+ "polygon",
3367
+ {
3368
+ points: "0 0, 8 3, 0 6",
3369
+ fill: "var(--gantt-dependency-hover-color, #ef4444)"
3370
+ }
3371
+ )
3372
+ }
3430
3373
  )
3431
3374
  ] }),
3432
3375
  lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder, isVirtual }) => {
@@ -3441,14 +3384,23 @@ var DependencyLines = React5.memo(({
3441
3384
  else markerEnd = "url(#arrowhead)";
3442
3385
  const lagColor = isSelected ? "#ef4444" : hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)";
3443
3386
  return /* @__PURE__ */ jsxs5(React5.Fragment, { children: [
3444
- /* @__PURE__ */ jsx6(
3445
- "path",
3446
- {
3447
- d: path,
3448
- className: pathClassName,
3449
- markerEnd
3450
- }
3451
- ),
3387
+ /* @__PURE__ */ jsxs5("g", { className: "gantt-dependency-line", children: [
3388
+ /* @__PURE__ */ jsx6(
3389
+ "path",
3390
+ {
3391
+ d: path,
3392
+ className: "gantt-dependency-hit-area"
3393
+ }
3394
+ ),
3395
+ /* @__PURE__ */ jsx6(
3396
+ "path",
3397
+ {
3398
+ d: path,
3399
+ className: pathClassName,
3400
+ markerEnd
3401
+ }
3402
+ )
3403
+ ] }),
3452
3404
  lag !== 0 && /* @__PURE__ */ jsx6(
3453
3405
  "text",
3454
3406
  {
@@ -3471,7 +3423,6 @@ DependencyLines.displayName = "DependencyLines";
3471
3423
  var DependencyLines_default = DependencyLines;
3472
3424
 
3473
3425
  // src/components/TaskList/TaskList.tsx
3474
- init_dateUtils();
3475
3426
  import React11, { useMemo as useMemo8, useCallback as useCallback5, useState as useState6, useEffect as useEffect6, useRef as useRef6 } from "react";
3476
3427
 
3477
3428
  // src/utils/taskListReorder.ts
@@ -3560,7 +3511,6 @@ var PopoverContent = ({
3560
3511
  };
3561
3512
 
3562
3513
  // src/components/TaskList/TaskListRow.tsx
3563
- init_dateUtils();
3564
3514
  import React9, {
3565
3515
  useState as useState4,
3566
3516
  useRef as useRef4,
@@ -4089,7 +4039,6 @@ var LINK_TYPE_LABELS = {
4089
4039
  };
4090
4040
 
4091
4041
  // src/components/TaskList/defaultTaskDates.ts
4092
- init_dateUtils();
4093
4042
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
4094
4043
  var DEFAULT_TASK_DURATION_DAYS = 5;
4095
4044
  function toISODate(date) {
@@ -4525,12 +4474,20 @@ var DepChip = ({
4525
4474
  /* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs9(
4526
4475
  "span",
4527
4476
  {
4528
- className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
4477
+ className: `gantt-tl-dep-chip-with-number${isSelected ? " gantt-tl-dep-chip-with-number-selected" : ""}`,
4529
4478
  onClick: handleClick,
4530
- title: `[${LINK_TYPE_LABELS_RU[dep.type]}] ${formatTaskNumberLabel(predecessorTaskNumber)}${depName}`,
4479
+ "aria-label": `[${LINK_TYPE_LABELS_RU[dep.type]}] ${formatTaskNumberLabel(predecessorTaskNumber)}${depName}`,
4531
4480
  children: [
4532
- /* @__PURE__ */ jsx12(Icon, {}),
4533
- effectiveLag !== 0 ? effectiveLag > 0 ? `+${effectiveLag}` : `${effectiveLag}` : ""
4481
+ predecessorTaskNumber && /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-chip-task-number", children: predecessorTaskNumber }),
4482
+ /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-chip", children: /* @__PURE__ */ jsx12(Icon, {}) }),
4483
+ effectiveLag !== 0 && /* @__PURE__ */ jsx12("span", { className: "gantt-tl-dep-chip-lag", children: effectiveLag > 0 ? `+${effectiveLag}` : `${effectiveLag}` }),
4484
+ /* @__PURE__ */ jsxs9("span", { className: "gantt-tl-dep-chip-tooltip", role: "tooltip", children: [
4485
+ "[",
4486
+ LINK_TYPE_LABELS_RU[dep.type],
4487
+ "] ",
4488
+ formatTaskNumberLabel(predecessorTaskNumber),
4489
+ depName
4490
+ ] })
4534
4491
  ]
4535
4492
  }
4536
4493
  ) }),
@@ -6375,7 +6332,7 @@ var BUILT_IN_COLUMN_WIDTHS = {
6375
6332
  endDate: 90,
6376
6333
  duration: 60,
6377
6334
  progress: 50,
6378
- dependencies: 120,
6335
+ dependencies: 128,
6379
6336
  actions: 80
6380
6337
  };
6381
6338
  function createBuiltInColumns(opts) {
@@ -7285,11 +7242,9 @@ var TaskList = ({
7285
7242
  };
7286
7243
 
7287
7244
  // src/components/ResourceTimelineChart/ResourceTimelineChart.tsx
7288
- init_dateUtils();
7289
7245
  import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo9, useRef as useRef8 } from "react";
7290
7246
 
7291
7247
  // src/utils/resourceTimelineLayout.ts
7292
- init_dateUtils();
7293
7248
  var isInvalidDate = (date) => Number.isNaN(date.getTime());
7294
7249
  var getUTCDayNumber = (date) => {
7295
7250
  return Math.floor(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) / 864e5);
@@ -7684,35 +7639,6 @@ var ITEM_OUTER_VERTICAL_INSET = 2;
7684
7639
  var ITEM_INNER_VERTICAL_INSET = 1;
7685
7640
  var ITEM_HORIZONTAL_INSET = 1;
7686
7641
  var isValidDate = (date) => !Number.isNaN(date.getTime());
7687
- var getResourceTimelineDays = (items) => {
7688
- if (items.length === 0) {
7689
- return getMonthDays(/* @__PURE__ */ new Date());
7690
- }
7691
- let minDate = null;
7692
- let maxDate = null;
7693
- for (const item of items) {
7694
- const startDate = parseUTCDate(item.startDate);
7695
- const endDate = parseUTCDate(item.endDate);
7696
- if (!minDate || startDate.getTime() < minDate.getTime()) {
7697
- minDate = startDate;
7698
- }
7699
- if (!maxDate || endDate.getTime() > maxDate.getTime()) {
7700
- maxDate = endDate;
7701
- }
7702
- }
7703
- if (!minDate || !maxDate) {
7704
- return getMonthDays(/* @__PURE__ */ new Date());
7705
- }
7706
- const startOfMonth2 = new Date(Date.UTC(minDate.getUTCFullYear(), minDate.getUTCMonth(), 1));
7707
- const endOfMonth = new Date(Date.UTC(maxDate.getUTCFullYear(), maxDate.getUTCMonth() + 1, 0));
7708
- const days = [];
7709
- const current = new Date(startOfMonth2);
7710
- while (current.getTime() <= endOfMonth.getTime()) {
7711
- days.push(new Date(Date.UTC(current.getUTCFullYear(), current.getUTCMonth(), current.getUTCDate())));
7712
- current.setUTCDate(current.getUTCDate() + 1);
7713
- }
7714
- return days;
7715
- };
7716
7642
  var collectValidItems = (resources) => {
7717
7643
  return resources.flatMap(
7718
7644
  (resource) => resource.items.flatMap((item) => {
@@ -7785,9 +7711,11 @@ var getDurationValue = (startDate, endDate, businessDays, weekendPredicate) => b
7785
7711
  function ResourceTimelineChart({
7786
7712
  resources,
7787
7713
  dayWidth = DEFAULT_DAY_WIDTH,
7714
+ viewMode = "day",
7788
7715
  rowHeaderWidth = DEFAULT_ROW_HEADER_WIDTH,
7789
7716
  laneHeight = DEFAULT_LANE_HEIGHT,
7790
7717
  headerHeight = DEFAULT_HEADER_HEIGHT,
7718
+ containerHeight,
7791
7719
  allowVerticalPan = false,
7792
7720
  customDays,
7793
7721
  isWeekend: isWeekend3,
@@ -7803,9 +7731,7 @@ function ResourceTimelineChart({
7803
7731
  const gridRef = useRef8(null);
7804
7732
  const panStateRef = useRef8(null);
7805
7733
  const validItems = useMemo9(() => collectValidItems(resources), [resources]);
7806
- const dateRange = useMemo9(() => {
7807
- return getResourceTimelineDays(validItems);
7808
- }, [validItems]);
7734
+ const dateRange = useMemo9(() => getMultiMonthDays(validItems), [validItems]);
7809
7735
  const monthStart = useMemo9(() => {
7810
7736
  const firstDay = dateRange[0] ?? /* @__PURE__ */ new Date();
7811
7737
  return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));
@@ -7911,7 +7837,11 @@ function ResourceTimelineChart({
7911
7837
  {
7912
7838
  ref: scrollContainerRef,
7913
7839
  className: "gantt-resourceTimeline-scrollContainer",
7914
- style: { cursor: "grab" },
7840
+ style: {
7841
+ cursor: "grab",
7842
+ height: containerHeight ?? "auto",
7843
+ overflowY: containerHeight === void 0 ? void 0 : "auto"
7844
+ },
7915
7845
  "data-allow-vertical-pan": allowVerticalPan ? "true" : "false",
7916
7846
  onMouseDown: handlePanStart,
7917
7847
  children: /* @__PURE__ */ jsxs12("div", { className: "gantt-resourceTimeline-scrollContent", children: [
@@ -7966,6 +7896,7 @@ function ResourceTimelineChart({
7966
7896
  days: dateRange,
7967
7897
  dayWidth,
7968
7898
  headerHeight,
7899
+ viewMode,
7969
7900
  isCustomWeekend: weekendPredicate
7970
7901
  }
7971
7902
  ) }),
@@ -7982,6 +7913,7 @@ function ResourceTimelineChart({
7982
7913
  dateRange,
7983
7914
  dayWidth,
7984
7915
  totalHeight: layout.totalHeight,
7916
+ viewMode,
7985
7917
  isCustomWeekend: weekendPredicate
7986
7918
  }
7987
7919
  ),
@@ -8046,6 +7978,7 @@ function ResourceTimelineChart({
8046
7978
  {
8047
7979
  className,
8048
7980
  "data-resource-item-id": layoutItem.itemId,
7981
+ "data-resource-item-tooltip": layoutItem.item.title,
8049
7982
  onMouseDown: (event) => startDrag(event, layoutItem),
8050
7983
  onClick: () => onResourceItemClick?.(layoutItem.item),
8051
7984
  onKeyDown: (event) => {
@@ -9178,15 +9111,15 @@ var Button = React14.forwardRef(
9178
9111
  );
9179
9112
  Button.displayName = "Button";
9180
9113
 
9181
- // src/utils/index.ts
9182
- init_dateUtils();
9183
-
9184
9114
  // src/filters/index.ts
9185
- init_dateUtils();
9186
9115
  var and = (...predicates) => (task) => predicates.every((p) => p(task));
9187
9116
  var or = (...predicates) => (task) => predicates.some((p) => p(task));
9188
9117
  var not = (predicate) => (task) => !predicate(task);
9189
- var withoutDeps = () => (task) => !!task && (!task.dependencies || task.dependencies.length === 0);
9118
+ var withoutDeps = (options = {}) => (task) => {
9119
+ if (!task) return false;
9120
+ if (options.onlyChildren && !task.parentId) return false;
9121
+ return !task.dependencies || task.dependencies.length === 0;
9122
+ };
9190
9123
  var expired = (referenceDate = /* @__PURE__ */ new Date()) => (task) => isTaskExpired(task, referenceDate);
9191
9124
  var inDateRange = (rangeStart, rangeEnd) => (task) => {
9192
9125
  if (!task) return false;