gantt-lib 0.22.2 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/dateUtils.ts","../src/index.ts","../src/components/GanttChart/GanttChart.tsx","../src/utils/dependencyUtils.ts","../src/utils/hierarchyOrder.ts","../src/components/TimeScaleHeader/TimeScaleHeader.tsx","../src/components/TaskRow/TaskRow.tsx","../src/utils/geometry.ts","../src/utils/expired.ts","../src/hooks/useTaskDrag.ts","../src/components/TodayIndicator/TodayIndicator.tsx","../src/components/GridBackground/GridBackground.tsx","../src/components/DragGuideLines/DragGuideLines.tsx","../src/components/DependencyLines/DependencyLines.tsx","../src/components/TaskList/TaskList.tsx","../src/utils/taskListReorder.ts","../src/components/ui/Popover.tsx","../src/components/TaskList/TaskListRow.tsx","../src/components/ui/Input.tsx","../src/components/ui/DatePicker.tsx","../src/components/ui/Calendar.tsx","../src/components/TaskList/DepIcons.tsx","../src/components/TaskList/NewTaskRow.tsx","../src/components/ui/Button.tsx","../src/utils/index.ts","../src/filters/index.ts"],"sourcesContent":["import { parseISO, isValid } from 'date-fns';\n\n/**\n * Parse date string as UTC to prevent DST issues\n * @param date - Date string or Date object\n * @returns Date object representing UTC midnight\n * @throws Error if date string is invalid\n */\nexport const parseUTCDate = (date: string | Date): Date => {\n if (typeof date === 'string') {\n // If already an ISO string (contains 'T'), parse directly\n // Otherwise, append UTC time for simple date strings (YYYY-MM-DD)\n const dateStr = date.includes('T') ? date : `${date}T00:00:00Z`;\n const parsed = new Date(dateStr);\n if (isNaN(parsed.getTime())) {\n throw new Error(`Invalid date string: ${date}`);\n }\n return parsed;\n }\n return date;\n};\n\n/**\n * Get all days in the month of given date (UTC)\n * @param date - Reference date (any day in the target month)\n * @returns Array of Date objects for each day in the month\n */\nexport const getMonthDays = (date: Date | string): Date[] => {\n const utcDate = parseUTCDate(date);\n const year = utcDate.getUTCFullYear();\n const month = utcDate.getUTCMonth();\n\n // Get days in month (handles leap years)\n const daysInMonth = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();\n\n const days: Date[] = [];\n for (let day = 1; day <= daysInMonth; day++) {\n days.push(new Date(Date.UTC(year, month, day)));\n }\n\n return days;\n};\n\n/**\n * Calculate day offset from month start (0-based)\n * @param date - The date to calculate offset for\n * @param monthStart - The start of the month as reference\n * @returns Number of days from month start (negative if date is before month start)\n */\nexport const getDayOffset = (date: Date, monthStart: Date): number => {\n const dateMs = Date.UTC(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n date.getUTCDate()\n );\n const startMs = Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate()\n );\n return Math.round((dateMs - startMs) / (1000 * 60 * 60 * 24));\n};\n\n/**\n * Check if date is today (local timezone comparison)\n * Uses local time to determine today's date boundary so the result matches\n * the user's timezone rather than UTC (prevents off-by-one errors at midnight).\n * @param date - Date to check\n * @returns True if date is today, false otherwise\n */\nexport const isToday = (date: Date): boolean => {\n const now = new Date();\n // Use local time methods so the \"today\" boundary reflects the user's timezone.\n // getUTCFullYear/Month/Date would shift the day for non-UTC users.\n const today = new Date(Date.UTC(\n now.getFullYear(),\n now.getMonth(),\n now.getDate()\n ));\n const compareDate = new Date(Date.UTC(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n date.getUTCDate()\n ));\n return today.getTime() === compareDate.getTime();\n};\n\n/**\n * Check if date is a weekend day (Saturday or Sunday)\n * @param date - Date to check\n * @returns True if date is Saturday (6) or Sunday (0), false otherwise\n */\nexport const isWeekend = (date: Date): boolean => {\n const day = date.getUTCDay();\n return day === 0 || day === 6; // Sunday (0) or Saturday (6)\n};\n\n/**\n * Create a UTC-safe key for Set-based date lookup\n * @param date - Date object to create key from\n * @returns String key in \"YYYY-M-D\" format using UTC date components\n *\n * Example:\n * createDateKey(new Date(Date.UTC(2026, 2, 15))) // \"2026-2-15\"\n *\n * Note: Uses UTC methods to prevent DST and timezone issues.\n * Month is 0-indexed (0=January, 11=December) per JavaScript Date convention.\n */\nexport const createDateKey = (date: Date): string => {\n return `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}`;\n};\n\n/**\n * Configuration for a single custom day\n */\nexport interface CustomDayConfig {\n /** The date to customize */\n date: Date;\n /** Type of day: 'weekend' marks as weekend, 'workday' marks as workday */\n type: 'weekend' | 'workday';\n}\n\n/**\n * Configuration for custom day predicate\n */\nexport interface CustomDayPredicateConfig {\n /** Array of custom day configurations with explicit types */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate (checked before customDays overrides) */\n isWeekend?: (date: Date) => boolean;\n}\n\n/**\n * Create a weekend predicate with unified custom day support\n *\n * Precedence order (highest to lowest):\n * 1. customDays.type='workday' - explicit workday (highest override)\n * 2. customDays.type='weekend' - explicit weekend (override)\n * 3. isWeekend (base predicate) - custom base logic\n * 4. default - Saturday (6) and Sunday (0)\n *\n * @param config - Custom day configuration with array and optional predicate\n * @returns Predicate function (date: Date) => boolean\n *\n * Example:\n * // Simple holidays + working Saturdays\n * const predicate = createCustomDayPredicate({\n * customDays: [\n * { date: new Date(Date.UTC(2026, 2, 15)), type: 'workday' }, // working Saturday\n * { date: new Date(Date.UTC(2026, 0, 1)), type: 'weekend' } // holiday Tuesday\n * ]\n * });\n *\n * // 4-day work week + occasional overrides\n * const predicate2 = createCustomDayPredicate({\n * isWeekend: (date) => {\n * const day = date.getUTCDay();\n * return day === 0 || day === 6 || day === 5; // Sun+Sat+Fri\n * },\n * customDays: [\n * { date: new Date(Date.UTC(2026, 2, 10)), type: 'workday' } // working Friday\n * ]\n * });\n */\nexport const createCustomDayPredicate = (\n config: CustomDayPredicateConfig\n): ((date: Date) => boolean) => {\n const { customDays, isWeekend: basePredicate } = config;\n\n // Build Set-based lookups for O(1) performance\n const workdaySet = new Set<string>();\n const weekendSet = new Set<string>();\n\n if (customDays && customDays.length > 0) {\n for (const item of customDays) {\n const key = createDateKey(item.date);\n if (item.type === 'workday') {\n workdaySet.add(key);\n } else { // weekend\n weekendSet.add(key);\n }\n }\n }\n\n return (date: Date): boolean => {\n const key = createDateKey(date);\n\n // Priority 1: customDays workdays (highest override)\n if (workdaySet.has(key)) {\n return false; // Explicitly a workday\n }\n\n // Priority 2: customDays weekends (override)\n if (weekendSet.has(key)) {\n return true; // Explicitly a weekend\n }\n\n // Priority 3: base predicate (if provided)\n if (basePredicate) {\n return basePredicate(date);\n }\n\n // Priority 4: default Saturday/Sunday\n const dayOfWeek = date.getUTCDay();\n return dayOfWeek === 0 || dayOfWeek === 6;\n };\n};\n\n/**\n * Calculate multi-month date range from task dates\n * Expands range to include full months with padding on both ends for drag flexibility\n * Adds 1 month before and 2 months after the task range\n * @param tasks - Array of tasks with startDate and endDate\n * @returns Array of Date objects for all days in the expanded range\n */\nexport const getMultiMonthDays = (tasks: Array<{ startDate: string | Date; endDate: string | Date }>): Date[] => {\n // Handle empty task array by returning current month\n if (!tasks || tasks.length === 0) {\n return getMonthDays(new Date());\n }\n\n // Find min and max dates from all tasks\n let minDate: Date | null = null;\n let maxDate: Date | null = null;\n\n for (const task of tasks) {\n const start = parseUTCDate(task.startDate);\n const end = parseUTCDate(task.endDate);\n\n if (!minDate || start.getTime() < minDate.getTime()) {\n minDate = start;\n }\n if (!maxDate || end.getTime() > maxDate.getTime()) {\n maxDate = end;\n }\n }\n\n if (!minDate || !maxDate) {\n return getMonthDays(new Date());\n }\n\n // Extend to full months: 1st of first month to last day of last month\n // Add padding: 2 months after for drag flexibility\n const startOfMonth = new Date(Date.UTC(\n minDate.getUTCFullYear(),\n minDate.getUTCMonth(),\n 1\n ));\n\n const endOfMonth = new Date(Date.UTC(\n maxDate.getUTCFullYear(),\n maxDate.getUTCMonth() + 1 + 2, // Original + 2 months padding after\n 0\n ));\n\n // Generate all dates in range\n const days: Date[] = [];\n const current = new Date(startOfMonth);\n\n while (current.getTime() <= endOfMonth.getTime()) {\n days.push(new Date(Date.UTC(\n current.getUTCFullYear(),\n current.getUTCMonth(),\n current.getUTCDate()\n )));\n // Move to next day\n current.setUTCDate(current.getUTCDate() + 1);\n }\n\n return days;\n};\n\n/**\n * Calculate month spans within a date range\n * @param dateRange - Array of Date objects representing the full range\n * @returns Array of month span objects with month, days count, and start index\n */\nexport const getMonthSpans = (\n dateRange: Date[]\n): Array<{ month: Date; days: number; startIndex: number }> => {\n if (dateRange.length === 0) {\n return [];\n }\n\n const spans: Array<{ month: Date; days: number; startIndex: number }> = [];\n let currentMonthYear = `${dateRange[0].getUTCFullYear()}-${dateRange[0].getUTCMonth()}`;\n let startOfMonthIndex = 0;\n\n for (let i = 0; i < dateRange.length; i++) {\n const date = dateRange[i];\n const monthYear = `${date.getUTCFullYear()}-${date.getUTCMonth()}`;\n\n // When month changes, finalize the previous span and start a new one\n if (monthYear !== currentMonthYear) {\n spans.push({\n month: new Date(Date.UTC(\n dateRange[startOfMonthIndex].getUTCFullYear(),\n dateRange[startOfMonthIndex].getUTCMonth(),\n 1\n )),\n days: i - startOfMonthIndex,\n startIndex: startOfMonthIndex\n });\n currentMonthYear = monthYear;\n startOfMonthIndex = i;\n }\n\n // Last date - finalize the last span\n if (i === dateRange.length - 1) {\n spans.push({\n month: new Date(Date.UTC(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n 1\n )),\n days: i - startOfMonthIndex + 1,\n startIndex: startOfMonthIndex\n });\n }\n }\n\n return spans;\n};\n\n/**\n * Format date as DD.MM (e.g., 25.03 for March 25th)\n * @param date - Date to format\n * @returns Formatted date string in DD.MM format\n */\nexport const formatDateLabel = (date: Date | string): string => {\n const parsed = parseUTCDate(date);\n const day = String(parsed.getUTCDate()).padStart(2, '0');\n const month = String(parsed.getUTCMonth() + 1).padStart(2, '0');\n return `${day}.${month}`;\n};\n\n/**\n * Return block boundaries for week-view, splitting on month boundaries.\n * Each block represents a column in the week-view header.\n * Blocks are typically 7 days, but split on month boundaries so\n * the first/last block of a month may be smaller.\n *\n * @param days - Array of dates from getMultiMonthDays\n * @returns Array of start dates for each block, with actual block sizes\n */\nexport interface WeekBlock {\n /** Start date of this block */\n startDate: Date;\n /** Number of days in this block (≤7, splits on month boundaries) */\n days: number;\n}\n\n/**\n * Split the date range into blocks, primarily 7-day weeks,\n * but splitting blocks on month boundaries for accurate month spans.\n */\nexport const getWeekBlocks = (days: Date[]): WeekBlock[] => {\n if (days.length === 0) return [];\n\n const blocks: WeekBlock[] = [];\n let blockStart = 0;\n\n while (blockStart < days.length) {\n // Target: 7-day block, but check for month boundary within\n const maxBlockEnd = Math.min(blockStart + 7, days.length);\n const startMonthYear = `${days[blockStart].getUTCFullYear()}-${days[blockStart].getUTCMonth()}`;\n\n let actualBlockEnd = blockStart + 7; // Default to full week\n if (actualBlockEnd > days.length) {\n actualBlockEnd = days.length;\n }\n\n // Check if month boundary falls within the 7-day window\n for (let i = blockStart + 1; i < maxBlockEnd; i++) {\n const monthYear = `${days[i].getUTCFullYear()}-${days[i].getUTCMonth()}`;\n if (monthYear !== startMonthYear) {\n // Split at month boundary\n actualBlockEnd = i;\n break;\n }\n }\n\n blocks.push({\n startDate: days[blockStart],\n days: actualBlockEnd - blockStart,\n });\n\n blockStart = actualBlockEnd;\n }\n\n return blocks;\n};\n\n/**\n * Represents a month span in week-view header row 1.\n * In week-view, the width is calculated from actual day counts,\n * not from a fixed column count.\n */\nexport interface WeekSpan {\n /** First day of the calendar month (UTC) */\n month: Date;\n /** Total number of days this month occupies across all blocks */\n days: number;\n /** Start index in the blocks array */\n startIndex: number;\n}\n\n/**\n * Calculate month spans based on week-block boundaries.\n * Groups consecutive blocks that belong to the same month.\n */\nexport const getWeekSpans = (days: Date[]): WeekSpan[] => {\n const blocks = getWeekBlocks(days);\n if (blocks.length === 0) return [];\n\n const spans: WeekSpan[] = [];\n let currentMonthYear = `${blocks[0].startDate.getUTCFullYear()}-${blocks[0].startDate.getUTCMonth()}`;\n let startIndex = 0;\n let totalDays = 0;\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const monthYear = `${block.startDate.getUTCFullYear()}-${block.startDate.getUTCMonth()}`;\n\n if (monthYear !== currentMonthYear) {\n // Finalize previous month span\n spans.push({\n month: new Date(Date.UTC(\n blocks[startIndex].startDate.getUTCFullYear(),\n blocks[startIndex].startDate.getUTCMonth(),\n 1\n )),\n days: totalDays,\n startIndex,\n });\n currentMonthYear = monthYear;\n startIndex = i;\n totalDays = 0;\n }\n\n totalDays += block.days;\n\n if (i === blocks.length - 1) {\n spans.push({\n month: new Date(Date.UTC(\n block.startDate.getUTCFullYear(),\n block.startDate.getUTCMonth(),\n 1\n )),\n days: totalDays,\n startIndex,\n });\n }\n }\n\n return spans;\n};\n\nexport interface MonthBlock {\n /** Первый день месяца (UTC) */\n startDate: Date;\n /** Количество дней в этом месяце внутри dateRange (может быть меньше при обрезке) */\n days: number;\n}\n\n/**\n * Разбивает dateRange на блоки по месяцам.\n * Каждый блок = один месяц (колонка в строке 2 month-view шапки).\n * Блок на краях может быть неполным если dateRange начинается/заканчивается не с 1-го числа.\n */\nexport const getMonthBlocks = (days: Date[]): MonthBlock[] => {\n if (days.length === 0) return [];\n // Переиспользуем getMonthSpans — его структура совпадает с MonthBlock\n return getMonthSpans(days).map(span => ({\n startDate: span.month,\n days: span.days,\n }));\n};\n\nexport interface YearSpan {\n /** 1 января года (UTC) */\n year: Date;\n /** Суммарное кол-во дней этого года внутри dateRange */\n days: number;\n /** Начальный индекс в массиве monthBlocks */\n startIndex: number;\n}\n\n/**\n * Группирует month-блоки по годам.\n * Используется в строке 1 month-view шапки (year label).\n */\nexport const getYearSpans = (days: Date[]): YearSpan[] => {\n const blocks = getMonthBlocks(days);\n if (blocks.length === 0) return [];\n\n const spans: YearSpan[] = [];\n let currentYear = blocks[0].startDate.getUTCFullYear();\n let startIndex = 0;\n let totalDays = 0;\n\n for (let i = 0; i < blocks.length; i++) {\n const blockYear = blocks[i].startDate.getUTCFullYear();\n if (blockYear !== currentYear) {\n spans.push({\n year: new Date(Date.UTC(currentYear, 0, 1)),\n days: totalDays,\n startIndex,\n });\n currentYear = blockYear;\n startIndex = i;\n totalDays = 0;\n }\n totalDays += blocks[i].days;\n if (i === blocks.length - 1) {\n spans.push({\n year: new Date(Date.UTC(currentYear, 0, 1)),\n days: totalDays,\n startIndex,\n });\n }\n }\n\n return spans;\n};\n\n/**\n * Normalize task dates to ensure startDate is always before or equal to endDate.\n * If dates are swapped (endDate < startDate), they are automatically swapped.\n * @param startDate - Task start date (string or Date)\n * @param endDate - Task end date (string or Date)\n * @returns Object with normalized startDate and endDate as ISO date strings (YYYY-MM-DD)\n */\nexport const normalizeTaskDates = (\n startDate: string | Date,\n endDate: string | Date\n): { startDate: string; endDate: string } => {\n const start = parseUTCDate(startDate);\n const end = parseUTCDate(endDate);\n\n // If dates are swapped, return them in correct order\n if (end.getTime() < start.getTime()) {\n return {\n startDate: end.toISOString().split('T')[0],\n endDate: start.toISOString().split('T')[0],\n };\n }\n\n // Dates are already in correct order\n return {\n startDate: start.toISOString().split('T')[0],\n endDate: end.toISOString().split('T')[0],\n };\n};\n","'use client';\n\n// CSS import triggers tsup to emit dist/index.css (renamed to dist/styles.css by onSuccess)\nimport './styles.css';\n\n// Components\nexport { GanttChart, type Task, type TaskDependency, type GanttChartProps, type GanttChartHandle } from './components/GanttChart';\nexport { default as TaskRow } from './components/TaskRow';\nexport { default as TimeScaleHeader } from './components/TimeScaleHeader';\nexport { default as GridBackground } from './components/GridBackground';\nexport { default as TodayIndicator } from './components/TodayIndicator';\nexport { default as DragGuideLines } from './components/DragGuideLines/DragGuideLines';\nexport { TaskList, type TaskListProps } from './components/TaskList';\n\n// UI Components\nexport { Input, type InputProps } from './components/ui/Input';\nexport { Button, type ButtonProps } from './components/ui/Button';\nexport { Popover, PopoverTrigger, PopoverContent, type PopoverProps, type PopoverContentProps } from './components/ui/Popover';\nexport { Calendar, type CalendarProps } from './components/ui/Calendar';\nexport { DatePicker, type DatePickerProps } from './components/ui/DatePicker';\n\n// Hooks\nexport { useTaskDrag } from './hooks';\n\n// Utils\nexport * from './utils';\n\n// Filters\nexport * from './filters';\n\n// Types\nexport type {\n GanttDateRange,\n TaskBarGeometry,\n GridConfig,\n MonthSpan,\n GridLine,\n WeekendBlock,\n} from './types';\n","'use client';\n\nimport React, { useMemo, useCallback, useRef, useState, useEffect, useImperativeHandle, forwardRef } from 'react';\nimport { getMultiMonthDays, createCustomDayPredicate, type CustomDayConfig, type CustomDayPredicateConfig } from '../../utils/dateUtils';\nimport { calculateGridWidth } from '../../utils/geometry';\nimport { validateDependencies, cascadeByLinks, computeParentDates, computeParentProgress, getChildren, removeDependenciesBetweenTasks, isTaskParent } from '../../utils/dependencyUtils';\nimport { normalizeHierarchyTasks } from '../../utils/hierarchyOrder';\nimport type { ValidationResult } from '../../types';\nimport { TaskPredicate } from '../../filters';\nimport TimeScaleHeader from '../TimeScaleHeader';\nimport TaskRow from '../TaskRow';\nimport TodayIndicator from '../TodayIndicator';\nimport GridBackground from '../GridBackground';\nimport DragGuideLines from '../DragGuideLines/DragGuideLines';\nimport { DependencyLines } from '../DependencyLines';\nimport { TaskList } from '../TaskList';\nimport './GanttChart.css';\n\n/**\n * Task data structure for Gantt chart\n */\nexport interface Task {\n /** Unique identifier for the task */\n id: string;\n /** Display name of the task */\n name: string;\n /** Task start date (ISO string or Date object) */\n startDate: string | Date;\n /** Task end date (ISO string or Date object) */\n endDate: string | Date;\n /** Optional color for task bar visualization */\n color?: string;\n /** Optional parent task ID for hierarchy relationship */\n parentId?: string;\n /**\n * Optional progress value from 0-100\n * - Decimal values are allowed and rounded to nearest integer for display\n * - Values are clamped to 0-100 range\n * - Undefined or 0 means no progress is displayed\n * - Progress is visual-only, no user interaction\n */\n progress?: number;\n /**\n * Optional flag indicating if task is accepted\n * - Only meaningful when progress is 100%\n * - Affects the color of the progress bar (green for accepted, yellow for completed)\n */\n accepted?: boolean;\n /**\n * Optional array of task dependencies\n * - Each dependency references a predecessor task by ID\n * - Supports 4 link types: FS (finish-to-start), SS (start-to-start), FF (finish-to-finish), SF (start-to-finish)\n * - Lag is optional and defaults to 0 (positive = delay, negative = overlap)\n */\n dependencies?: TaskDependency[];\n /**\n * Optional flag to prevent drag and resize interactions.\n * When true, the task bar cannot be moved or resized.\n * Independent of accepted/progress — consumer controls both separately.\n */\n locked?: boolean;\n /**\n * Optional horizontal divider line for visual grouping.\n * - 'top' renders a bold line above the task row\n * - 'bottom' renders a bold line below the task row\n * The line spans the full grid width.\n */\n divider?: 'top' | 'bottom';\n}\n\n/**\n * Task dependency definition\n */\nexport interface TaskDependency {\n /** ID of the predecessor task */\n taskId: string;\n /** Link type: FS, SS, FF, or SF */\n type: 'FS' | 'SS' | 'FF' | 'SF';\n /** Optional lag in days (default: 0) */\n lag?: number;\n}\n\nexport interface GanttChartProps {\n /** Array of tasks to display */\n tasks: Task[];\n /** Width of each day column in pixels (default: 40) */\n dayWidth?: number;\n /** Height of each task row in pixels (default: 40) */\n rowHeight?: number;\n /** Height of the header row in pixels (default: 40) */\n headerHeight?: number;\n /** Container height. Can be pixels (600), string (\"90vh\", \"100%\", \"500px\"), or undefined for auto height */\n containerHeight?: number | string;\n /** Callback when tasks are modified. Receives ONLY the changed tasks as full objects with all properties. */\n onTasksChange?: (tasks: Task[]) => void;\n /** Optional callback for dependency validation results */\n onValidateDependencies?: (result: ValidationResult) => void;\n /** Enable automatic shifting of dependent tasks when predecessor moves (default: false) */\n enableAutoSchedule?: boolean;\n /** Disable dependency constraint checking during drag (default: false) */\n disableConstraints?: boolean;\n /** Called when a cascade drag completes; receives all shifted tasks (including dragged task) in hard mode */\n onCascade?: (tasks: Task[]) => void;\n /** Show task list overlay on the left side of the chart (default: false) */\n showTaskList?: boolean;\n /** Width of the task list overlay in pixels (default: 300) */\n taskListWidth?: number;\n /** Disable task name editing in the task list (default: false) */\n disableTaskNameEditing?: boolean;\n /** Disable dependency editing in the task list (default: false) */\n disableDependencyEditing?: boolean;\n /** Highlight expired/overdue tasks with red background (default: false) */\n highlightExpiredTasks?: boolean;\n /** Callback when a new task is added via the task list */\n onAdd?: (task: Task) => void;\n /** Callback when a task is deleted via the task list */\n onDelete?: (taskId: string) => void;\n /** Callback when a new task is inserted after a specific task via the task list */\n onInsertAfter?: (taskId: string, newTask: Task) => void;\n /** Callback when tasks are reordered via drag in the task list */\n onReorder?: (tasks: Task[], movedTaskId?: string, inferredParentId?: string) => void;\n /** Callback when a task is promoted (parentId removed). If not provided, default internal logic is used. */\n onPromoteTask?: (taskId: string) => void;\n /** Callback when a task is demoted (parentId set). If not provided, default internal logic is used. */\n onDemoteTask?: (taskId: string, newParentId: string) => void;\n /** Enable add task button at bottom of task list (default: true) */\n enableAddTask?: boolean;\n /** View mode: 'day' renders one column per day, 'week' renders one column per 7 days, 'month' renders one column per month (default: 'day') */\n viewMode?: 'day' | 'week' | 'month';\n /** Custom day configurations with explicit type (weekend or workday) */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate (checked before customDays overrides) */\n isWeekend?: (date: Date) => boolean;\n /**\n * Optional predicate to mark tasks in the current view.\n * Matching tasks stay visible and are highlighted in the chart and task list.\n * Dependencies are still computed on ALL tasks (normalizedTasks).\n */\n taskFilter?: TaskPredicate;\n}\n\n/**\n * Ref handle type for GanttChart — exposes imperative scroll methods.\n */\nexport interface GanttChartHandle {\n scrollToToday: () => void;\n scrollToTask: (taskId: string) => void;\n collapseAll: () => void;\n expandAll: () => void;\n}\n\n/**\n * GanttChart component - displays tasks on a monthly timeline with Excel-like styling\n *\n * The calendar automatically shows full months based on task date ranges.\n * For example, if tasks span from March 25 to May 5, the calendar shows\n * the complete months of March, April, and May (March 1 - May 31).\n *\n * @example\n * ```tsx\n * <GanttChart\n * tasks={[\n * { id: '1', name: 'Task 1', startDate: '2026-02-01', endDate: '2026-02-05' }\n * ]}\n * />\n * ```\n * @example\n * ```tsx\n * // Hide add task button\n * <GanttChart\n * tasks={tasks}\n * enableAddTask={false}\n * />\n * ```\n */\nexport const GanttChart = forwardRef<GanttChartHandle, GanttChartProps>(({\n tasks,\n dayWidth = 40,\n rowHeight = 40,\n headerHeight = 40,\n containerHeight,\n onTasksChange,\n onValidateDependencies,\n enableAutoSchedule,\n disableConstraints,\n onCascade,\n showTaskList = false,\n taskListWidth = 660,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n highlightExpiredTasks = false,\n onAdd,\n onDelete,\n onInsertAfter,\n onReorder,\n onPromoteTask,\n onDemoteTask,\n enableAddTask = true,\n viewMode = 'day',\n customDays,\n isWeekend,\n taskFilter,\n}, ref) => {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n // Track selected task ID for highlighting in both TaskList and TaskRow\n const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);\n const [taskListHasRightShadow, setTaskListHasRightShadow] = useState(false);\n\n // Track selected dep chip for arrow highlighting in DependencyLines\n const [selectedChip, setSelectedChip] = useState<{ successorId: string; predecessorId: string; linkType: string } | null>(null);\n\n // Hierarchy state: collapsed parent IDs\n const [collapsedParentIds, setCollapsedParentIds] = useState<Set<string>>(new Set());\n\n // Track editing task ID for auto-edit mode after insert\n const [editingTaskId, setEditingTaskId] = useState<string | null>(null);\n\n const normalizedTasks = useMemo(() => normalizeHierarchyTasks(tasks), [tasks]);\n\n // Create custom weekend predicate from props (memoized for performance)\n const isCustomWeekend = useMemo(\n () => createCustomDayPredicate({ customDays, isWeekend }),\n [customDays, isWeekend]\n );\n\n // Calculate multi-month date range from normalized tasks\n const dateRange = useMemo(() => getMultiMonthDays(normalizedTasks), [normalizedTasks]);\n\n // Track dependency validation results\n const [validationResult, setValidationResult] = useState<ValidationResult | null>(null);\n\n // Cascade override positions for non-dragged chain members\n const [cascadeOverrides, setCascadeOverrides] = useState<Map<string, { left: number; width: number }>>(new Map());\n\n // Calculate grid width\n const gridWidth = useMemo(\n () => Math.round(dateRange.length * dayWidth),\n [dateRange.length, dayWidth]\n );\n\n // Visible tasks are determined only by collapsed parent state.\n // Checks the full ancestor chain so grandchildren are hidden when any ancestor is collapsed.\n const visibleTasks = useMemo(() => {\n const parentMap = new Map(normalizedTasks.map(t => [t.id, t.parentId]));\n\n function isAnyAncestorCollapsed(parentId: string | undefined): boolean {\n let current = parentId;\n while (current) {\n if (collapsedParentIds.has(current)) return true;\n current = parentMap.get(current);\n }\n return false;\n }\n\n return normalizedTasks.filter(task => !isAnyAncestorCollapsed(task.parentId));\n }, [normalizedTasks, collapsedParentIds]);\n\n const matchedTaskIds = useMemo(() => {\n if (!taskFilter) return new Set<string>();\n return new Set(visibleTasks.filter(taskFilter).map(task => task!.id));\n }, [visibleTasks, taskFilter]);\n\n // Calculate total grid height from currently visible rows.\n const totalGridHeight = useMemo(\n () => visibleTasks.length * rowHeight,\n [visibleTasks.length, rowHeight]\n );\n\n // Get month start for calculations (first day of date range)\n const monthStart = useMemo(() => {\n if (dateRange.length === 0) {\n return new Date(Date.UTC(new Date().getUTCFullYear(), new Date().getUTCMonth(), 1));\n }\n const firstDay = dateRange[0];\n return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));\n }, [dateRange]);\n\n // Only render TodayIndicator if today is in the visible date range\n const todayInRange = useMemo(() => {\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n return dateRange.some(day => day.getTime() === today.getTime());\n }, [dateRange]);\n\n // Center chart on today's date on initial mount\n useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container || dateRange.length === 0) return;\n\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n const todayIndex = dateRange.findIndex(day => day.getTime() === today.getTime());\n\n if (todayIndex === -1) return;\n\n // Calculate scroll position to center today\n const todayOffset = todayIndex * dayWidth;\n const containerWidth = container.clientWidth;\n const scrollLeft = Math.round(todayOffset - (containerWidth / 2) + (dayWidth / 2));\n\n container.scrollLeft = Math.max(0, scrollLeft);\n }, []); // Empty deps array - run only on mount\n\n useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const updateShadow = () => {\n setTaskListHasRightShadow(container.scrollLeft > 0);\n };\n\n updateShadow();\n container.addEventListener('scroll', updateShadow, { passive: true });\n return () => {\n container.removeEventListener('scroll', updateShadow);\n };\n }, []);\n\n /**\n * Scroll to today's date when the \"Today\" button is clicked\n */\n const scrollToToday = useCallback(() => {\n const container = scrollContainerRef.current;\n if (!container || dateRange.length === 0) return;\n\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n const todayIndex = dateRange.findIndex(day => day.getTime() === today.getTime());\n\n if (todayIndex === -1) return;\n\n // Calculate scroll position to center today\n const todayOffset = todayIndex * dayWidth;\n const containerWidth = container.clientWidth;\n const scrollLeft = Math.round(todayOffset - (containerWidth / 2) + (dayWidth / 2));\n\n container.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });\n }, [dateRange, dayWidth]);\n\n /**\n * Scroll to a specific task by ID, centering its start date horizontally in the grid.\n */\n const scrollToTask = useCallback((taskId: string) => {\n const container = scrollContainerRef.current;\n if (!container || dateRange.length === 0) return;\n\n const task = tasks.find(t => t.id === taskId);\n if (!task) return;\n\n const taskStart = new Date(task.startDate as string);\n const taskStartUTC = new Date(Date.UTC(\n taskStart.getUTCFullYear(),\n taskStart.getUTCMonth(),\n taskStart.getUTCDate()\n ));\n const taskIndex = dateRange.findIndex(day => day.getTime() === taskStartUTC.getTime());\n if (taskIndex === -1) return;\n\n const taskOffset = taskIndex * dayWidth;\n const scrollLeft = Math.round(taskOffset - dayWidth * 2);\n container.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });\n }, [tasks, dateRange, dayWidth]);\n\n // Track drag state for guide lines\n const [dragGuideLines, setDragGuideLines] = useState<{\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n } | null>(null);\n\n // Track currently-dragged task's pixel position for real-time dependency line updates\n const [draggedTaskOverride, setDraggedTaskOverride] = useState<{ taskId: string; left: number; width: number } | null>(null);\n\n // Validate dependencies when tasks change\n useEffect(() => {\n const result = validateDependencies(tasks);\n setValidationResult(result);\n onValidateDependencies?.(result);\n }, [tasks, onValidateDependencies]);\n\n /**\n * Callback when tasks are modified.\n * Always receives ONLY the changed tasks as full objects with all properties.\n * Single task = array of 1 element (batch of size 1).\n */\n const handleTaskChange = useCallback((updatedTasks: Task[]) => {\n const updatedTask = updatedTasks[0];\n if (!updatedTask) return;\n const originalTask = tasks.find(t => t.id === updatedTask.id);\n if (!originalTask) {\n // New task or task not found - pass all tasks as-is\n onTasksChange?.(updatedTasks);\n if (editingTaskId === updatedTask.id) {\n setEditingTaskId(null);\n }\n return;\n }\n\n const origStart = new Date(originalTask.startDate as string);\n const origEnd = new Date(originalTask.endDate as string);\n const newStart = new Date(updatedTask.startDate as string);\n const newEnd = new Date(updatedTask.endDate as string);\n const datesChanged = origStart.getTime() !== newStart.getTime() || origEnd.getTime() !== newEnd.getTime();\n\n if (!datesChanged) {\n // Special case: parent progress cascade (multiple tasks, no date changes)\n if (updatedTasks.length > 1) {\n onTasksChange?.(updatedTasks);\n if (editingTaskId === updatedTask.id) {\n setEditingTaskId(null);\n }\n return;\n }\n\n // Single task without date changes - compute parent progress if needed\n const taskParentId = (updatedTask as any).parentId;\n if (taskParentId) {\n const parentProgress = computeParentProgress(taskParentId, tasks.map(t => t.id === updatedTask.id ? updatedTask : t));\n const parentTask = tasks.find(t => t.id === taskParentId);\n if (parentTask) {\n const updatedParent = { ...parentTask, progress: parentProgress };\n onTasksChange?.([updatedTask, updatedParent]);\n } else {\n onTasksChange?.([updatedTask]);\n }\n } else {\n onTasksChange?.([updatedTask]);\n }\n if (editingTaskId === updatedTask.id) {\n setEditingTaskId(null);\n }\n return;\n }\n\n // Special handling for parent tasks: dates are computed from children\n const isParent = isTaskParent(updatedTask.id, tasks);\n if (isParent) {\n // When editing a parent task via task list, ignore the entered dates\n // and recalculate from children. Children should NOT be moved.\n const { startDate: parentStart, endDate: parentEnd } = computeParentDates(updatedTask.id, tasks);\n const parentWithRecalcDates = {\n ...updatedTask,\n startDate: parentStart.toISOString().split('T')[0],\n endDate: parentEnd.toISOString().split('T')[0],\n };\n\n // Cascade only dependency successors (not children) if constraints enabled\n const cascadedTasks = disableConstraints\n ? [parentWithRecalcDates]\n : [parentWithRecalcDates, ...cascadeByLinks(updatedTask.id, parentStart, parentEnd, tasks, true)]; // skipChildCascade=true\n\n onTasksChange?.(cascadedTasks);\n } else {\n // Regular task or child: normal cascade\n const cascadedTasks = disableConstraints\n ? [updatedTask]\n : [updatedTask, ...cascadeByLinks(updatedTask.id, newStart, newEnd, tasks)];\n\n onTasksChange?.(cascadedTasks);\n }\n }, [tasks, onTasksChange, disableConstraints, editingTaskId]);\n\n /**\n * Handle task deletion: collect all changed tasks (with cleaned dependencies),\n * emit onTasksChange with them, then emit onDelete for each deleted task ID\n * (original + all descendants) so the consumer can remove all of them.\n * For parent tasks, cascade delete to all children.\n */\n const handleDelete = useCallback((taskId: string) => {\n const toDelete = new Set<string>([taskId]);\n\n function collectDescendants(parentId: string) {\n const children = getChildren(parentId, tasks);\n children.forEach(child => {\n toDelete.add(child.id);\n collectDescendants(child.id);\n });\n }\n\n collectDescendants(taskId);\n\n const changedTasks: Task[] = [];\n tasks.forEach(task => {\n if (toDelete.has(task.id)) return;\n\n if (task.dependencies && task.dependencies.some(dep => toDelete.has(dep.taskId))) {\n changedTasks.push({\n ...task,\n dependencies: task.dependencies.filter(dep => !toDelete.has(dep.taskId))\n });\n }\n });\n\n if (changedTasks.length > 0) {\n onTasksChange?.(changedTasks);\n }\n\n // Call onDelete for each task in the cascade set (original + all descendants)\n // so the consumer removes all of them, not just the root.\n toDelete.forEach(id => onDelete?.(id));\n }, [tasks, onTasksChange, onDelete]);\n\n /**\n * Handle task insertion: set editingTaskId to trigger auto-edit mode,\n * then notify external consumer via onInsertAfter callback.\n *\n * NOTE: The external onInsertAfter callback is responsible for adding\n * the task and should emit onTasksChange with the new task.\n */\n const handleInsertAfter = useCallback((taskId: string, newTask: Task) => {\n setEditingTaskId(newTask.id);\n onInsertAfter?.(taskId, newTask);\n }, [onInsertAfter]);\n\n /**\n * Handle task reordering: notify external consumer via onTasksChange and onReorder callbacks.\n * Reordering changes all tasks positions, so we emit the full reordered array.\n */\n const handleReorder = useCallback((reorderedTasks: Task[], movedTaskId?: string, inferredParentId?: string) => {\n let updated = reorderedTasks;\n if (movedTaskId) {\n updated = updated.map(t => {\n if (t.id === movedTaskId) {\n return { ...t, parentId: inferredParentId || undefined };\n }\n return t;\n });\n }\n\n const normalized = normalizeHierarchyTasks(updated);\n onTasksChange?.(normalized);\n onReorder?.(normalized, movedTaskId, inferredParentId);\n }, [onTasksChange, onReorder]);\n\n // Build merged pixel overrides for DependencyLines: dragged task + cascade chain members\n const dependencyOverrides = useMemo(() => {\n const map = new Map(cascadeOverrides);\n if (draggedTaskOverride) {\n map.set(draggedTaskOverride.taskId, {\n left: draggedTaskOverride.left,\n width: draggedTaskOverride.width,\n });\n }\n return map;\n }, [cascadeOverrides, draggedTaskOverride]);\n\n /**\n * Handle real-time cascade progress — updates cascadeOverrides state each RAF\n * so non-dragged chain members re-render with their preview positions.\n * new Map() forces React to detect the state change.\n */\n const handleCascadeProgress = useCallback((overrides: Map<string, { left: number; width: number }>) => {\n setCascadeOverrides(new Map(overrides));\n }, []);\n\n /**\n * Handle cascade completion — emit all changed tasks.\n * Parent tasks are computed from children - don't send them in batch.\n */\n const handleCascade = useCallback((cascadedTasks: Task[]) => {\n // Backend should compute parent dates from children\n onTasksChange?.(cascadedTasks);\n }, [tasks, onTasksChange]);\n\n /**\n * Handle task selection from TaskList or TaskRow\n */\n const handleTaskSelect = useCallback((taskId: string | null) => {\n setSelectedTaskId(taskId);\n }, []);\n\n // Hierarchy callbacks\n const handleToggleCollapse = useCallback((parentId: string) => {\n setCollapsedParentIds(prev => {\n const next = new Set(prev);\n if (next.has(parentId)) {\n next.delete(parentId);\n } else {\n next.add(parentId);\n }\n return next;\n });\n }, []);\n\n // Get all parent task IDs\n const allParentIds = useMemo(() => {\n return new Set(normalizedTasks.filter(t => t.parentId).map(t => t.parentId!).filter(id => id));\n }, [normalizedTasks]);\n\n const handleCollapseAll = useCallback(() => {\n setCollapsedParentIds(allParentIds);\n }, [allParentIds]);\n\n const handleExpandAll = useCallback(() => {\n setCollapsedParentIds(new Set());\n }, []);\n\n // Expose collapse/expand methods via ref (must be after handlers are defined)\n useImperativeHandle(\n ref,\n () => ({\n scrollToToday,\n scrollToTask,\n collapseAll: handleCollapseAll,\n expandAll: handleExpandAll,\n }),\n [scrollToToday, scrollToTask, handleCollapseAll, handleExpandAll]\n );\n\n /**\n * Calculate the depth of a task in the hierarchy.\n * Root tasks have depth 0, their children have depth 1, etc.\n */\n function getTaskDepth(taskId: string, tasks: Task[]): number {\n let depth = 0;\n let current: Task | undefined = tasks.find(t => t.id === taskId);\n while (current) {\n if (!current.parentId) break;\n depth++;\n const parentId: string = current.parentId;\n current = tasks.find(t => t.id === parentId);\n }\n return depth;\n }\n\n const handlePromoteTask = useCallback((taskId: string) => {\n // If consumer provided custom callback, use it\n if (onPromoteTask) {\n onPromoteTask(taskId);\n return;\n }\n\n // Default internal logic\n const taskToPromote = tasks.find(t => t.id === taskId);\n if (!taskToPromote || !taskToPromote.parentId) {\n return;\n }\n\n // Calculate current depth and determine new parent for single-level promotion\n const depth = getTaskDepth(taskId, tasks);\n const grandparentId = depth > 1\n ? tasks.find(t => t.id === taskToPromote.parentId)?.parentId\n : undefined;\n\n const currentParentId = taskToPromote.parentId;\n const siblings = tasks.filter(t => t.parentId === currentParentId);\n\n const promotedTask = { ...taskToPromote, parentId: grandparentId };\n\n if (siblings.length <= 1) {\n onTasksChange?.([promotedTask]);\n return;\n }\n\n // Reorder: place after last sibling of the old parent group\n const lastSiblingIndex = tasks\n .map((t, i) => ({ task: t, index: i }))\n .filter(({ task }) => task.parentId === currentParentId)\n .sort((a, b) => b.index - a.index)[0];\n\n if (!lastSiblingIndex) {\n onTasksChange?.([promotedTask]);\n return;\n }\n\n const reorderedTasks = normalizeHierarchyTasks([\n ...tasks.filter(t => t.id !== taskId).slice(0, lastSiblingIndex.index + 1),\n promotedTask,\n ...tasks.filter(t => t.id !== taskId).slice(lastSiblingIndex.index + 1)\n ]);\n\n onTasksChange?.(reorderedTasks);\n }, [tasks, onTasksChange, onPromoteTask]);\n\n const handleDemoteTask = useCallback((taskId: string, newParentId: string) => {\n // If consumer provided custom callback, use it\n if (onDemoteTask) {\n onDemoteTask(taskId, newParentId);\n return;\n }\n\n // Default internal logic\n const wouldCreateCircular = (targetId: string, parentId: string, tasks: Task[]): boolean => {\n if (targetId === parentId) return true;\n\n const descendants = new Set<string>();\n function collect(id: string) {\n const children = getChildren(id, tasks);\n children.forEach(child => {\n descendants.add(child.id);\n collect(child.id);\n });\n }\n collect(targetId);\n return descendants.has(parentId);\n };\n\n if (wouldCreateCircular(taskId, newParentId, tasks)) {\n return;\n }\n\n let updatedTasks = removeDependenciesBetweenTasks(taskId, newParentId, tasks);\n\n const demotedTask = updatedTasks.find(t => t.id === taskId);\n if (!demotedTask) return;\n\n // If task was a parent (had children), save computed dates as its own dates\n // These become the task's \"own\" dates after demotion\n const wasParent = getChildren(taskId, tasks).length > 0;\n let taskDates = { startDate: demotedTask.startDate, endDate: demotedTask.endDate };\n\n if (wasParent) {\n const computedDates = computeParentDates(taskId, tasks);\n taskDates = {\n startDate: computedDates.startDate.toISOString().split('T')[0],\n endDate: computedDates.endDate.toISOString().split('T')[0]\n };\n }\n\n const updatedDemotedTask = {\n ...demotedTask,\n parentId: newParentId,\n startDate: taskDates.startDate,\n endDate: taskDates.endDate\n };\n\n // Only send the demoted task - parent dates are computed from children\n onTasksChange?.([updatedDemotedTask]);\n }, [tasks, onTasksChange, onDemoteTask]);\n\n // Pan (grab-scroll) on empty grid area\n const panStateRef = useRef<{ active: boolean; startX: number; startY: number; scrollX: number; scrollY: number } | null>(null);\n\n const handlePanStart = useCallback((e: React.MouseEvent) => {\n // Only pan on left click, skip if clicking on a task bar, input, or task list\n if (e.button !== 0) return;\n const target = e.target as HTMLElement;\n if (target.closest('[data-taskbar]')) return;\n if (target.closest('input, button, textarea, [contenteditable]')) return;\n if (target.closest('.gantt-tl-overlay')) return;\n\n const container = scrollContainerRef.current;\n if (!container) return;\n\n panStateRef.current = {\n active: true,\n startX: e.clientX,\n startY: e.clientY,\n scrollX: container.scrollLeft,\n scrollY: container.scrollTop,\n };\n // Blur any focused input so onBlur save handlers fire before pan starts\n if (document.activeElement instanceof HTMLElement) {\n document.activeElement.blur();\n }\n container.style.cursor = 'grabbing';\n e.preventDefault();\n }, []);\n\n useEffect(() => {\n const handlePanMove = (e: MouseEvent) => {\n const pan = panStateRef.current;\n if (!pan?.active) return;\n const container = scrollContainerRef.current;\n if (!container) return;\n\n container.scrollLeft = pan.scrollX - (e.clientX - pan.startX);\n container.scrollTop = pan.scrollY - (e.clientY - pan.startY);\n };\n\n const handlePanEnd = () => {\n if (!panStateRef.current?.active) return;\n panStateRef.current = null;\n const container = scrollContainerRef.current;\n if (container) container.style.cursor = '';\n };\n\n window.addEventListener('mousemove', handlePanMove);\n window.addEventListener('mouseup', handlePanEnd);\n return () => {\n window.removeEventListener('mousemove', handlePanMove);\n window.removeEventListener('mouseup', handlePanEnd);\n };\n }, []);\n\n return (\n <div className=\"gantt-container\">\n <div\n ref={scrollContainerRef}\n className=\"gantt-scrollContainer\"\n style={{ height: containerHeight ?? 'auto', cursor: 'grab' }}\n onMouseDown={handlePanStart}\n >\n {/* Content wrapper - enables TaskList to scroll with chart horizontally */}\n <div className=\"gantt-scrollContent\">\n {/* TaskList - sticky left, scrolls with content horizontally */}\n <TaskList\n tasks={normalizedTasks}\n rowHeight={rowHeight}\n headerHeight={headerHeight}\n taskListWidth={taskListWidth}\n onTasksChange={handleTaskChange}\n selectedTaskId={selectedTaskId ?? undefined}\n onTaskSelect={handleTaskSelect}\n show={showTaskList}\n hasRightShadow={taskListHasRightShadow}\n disableTaskNameEditing={disableTaskNameEditing}\n disableDependencyEditing={disableDependencyEditing}\n onScrollToTask={scrollToTask}\n onSelectedChipChange={setSelectedChip}\n onAdd={onAdd}\n onDelete={handleDelete}\n onInsertAfter={handleInsertAfter}\n onReorder={handleReorder}\n editingTaskId={editingTaskId}\n enableAddTask={enableAddTask}\n collapsedParentIds={collapsedParentIds}\n onToggleCollapse={handleToggleCollapse}\n onPromoteTask={onPromoteTask ?? handlePromoteTask}\n onDemoteTask={onDemoteTask ?? handleDemoteTask}\n highlightedTaskIds={matchedTaskIds}\n customDays={customDays}\n isWeekend={isWeekend}\n />\n\n {/* Chart area */}\n <div style={{ minWidth: `${gridWidth}px`, flex: 1 }}>\n {/* Sticky header - stays at top during vertical scroll, scrolls with content horizontally */}\n <div className=\"gantt-stickyHeader\" style={{ width: `${gridWidth}px` }}>\n <TimeScaleHeader\n days={dateRange}\n dayWidth={dayWidth}\n headerHeight={headerHeight}\n viewMode={viewMode}\n isCustomWeekend={isCustomWeekend}\n />\n </div>\n\n {/* Task area */}\n <div\n className=\"gantt-taskArea\"\n style={{\n position: 'relative',\n width: `${gridWidth}px`,\n }}\n >\n <GridBackground\n dateRange={dateRange}\n dayWidth={dayWidth}\n totalHeight={totalGridHeight}\n viewMode={viewMode}\n isCustomWeekend={isCustomWeekend}\n />\n\n {todayInRange && <TodayIndicator monthStart={monthStart} dayWidth={dayWidth} />}\n\n {/* Dependency lines SVG overlay */}\n <DependencyLines\n tasks={visibleTasks}\n allTasks={normalizedTasks}\n collapsedParentIds={collapsedParentIds}\n monthStart={monthStart}\n dayWidth={dayWidth}\n rowHeight={rowHeight}\n gridWidth={gridWidth}\n dragOverrides={dependencyOverrides}\n selectedDep={selectedChip}\n />\n\n {dragGuideLines && (\n <DragGuideLines\n isDragging={dragGuideLines.isDragging}\n dragMode={dragGuideLines.dragMode}\n left={dragGuideLines.left}\n width={dragGuideLines.width}\n totalHeight={totalGridHeight}\n />\n )}\n\n {visibleTasks.map((task, index) => (\n <TaskRow\n key={task.id}\n task={task}\n monthStart={monthStart}\n dayWidth={dayWidth}\n rowHeight={rowHeight}\n onTasksChange={handleTaskChange}\n onDragStateChange={(state) => {\n if (state.isDragging) {\n setDragGuideLines(state);\n setDraggedTaskOverride({ taskId: task.id, left: state.left, width: state.width });\n } else {\n setDragGuideLines(null);\n setDraggedTaskOverride(null);\n }\n }}\n rowIndex={index}\n allTasks={normalizedTasks}\n enableAutoSchedule={enableAutoSchedule ?? false}\n disableConstraints={disableConstraints ?? false}\n overridePosition={cascadeOverrides.get(task.id)}\n onCascadeProgress={handleCascadeProgress}\n onCascade={handleCascade}\n highlightExpiredTasks={highlightExpiredTasks}\n isFilterMatch={matchedTaskIds.has(task.id)}\n />\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nGanttChart.displayName = 'GanttChart';\n\nexport default GanttChart;\n","import { Task, TaskDependency, LinkType, ValidationResult, DependencyError } from '../types';\n\n/**\n * Build adjacency list for dependency graph (task -> successors)\n */\nexport function buildAdjacencyList(tasks: Task[]): Map<string, string[]> {\n const taskMap = new Map(tasks.map(t => [t.id, t]));\n const graph = new Map<string, string[]>();\n\n for (const task of tasks) {\n const successors: string[] = [];\n\n // Find all tasks that depend on this task (this task is a predecessor)\n for (const otherTask of tasks) {\n if (otherTask.dependencies) {\n for (const dep of otherTask.dependencies) {\n if (dep.taskId === task.id) {\n successors.push(otherTask.id);\n break;\n }\n }\n }\n }\n\n graph.set(task.id, successors);\n }\n\n return graph;\n}\n\n/**\n * Detect circular dependencies using depth-first search\n */\nexport function detectCycles(tasks: Task[]): { hasCycle: boolean; cyclePath?: string[] } {\n const graph = buildAdjacencyList(tasks);\n const visiting = new Set<string>();\n const visited = new Set<string>();\n const path: string[] = [];\n\n function dfs(taskId: string): boolean {\n if (visiting.has(taskId)) {\n // Found cycle - current task is already in recursion stack\n return true;\n }\n if (visited.has(taskId)) {\n return false;\n }\n\n visiting.add(taskId);\n path.push(taskId);\n\n const successors = graph.get(taskId) || [];\n for (const successor of successors) {\n if (dfs(successor)) {\n return true;\n }\n }\n\n visiting.delete(taskId);\n path.pop();\n visited.add(taskId);\n return false;\n }\n\n for (const task of tasks) {\n if (dfs(task.id)) {\n return { hasCycle: true, cyclePath: [...path] };\n }\n }\n\n return { hasCycle: false };\n}\n\n/**\n * Compute lag (in days) from actual predecessor/successor dates.\n * This is the single source of truth for lag semantics across chips, arrows, and drag.\n *\n * Semantics (lag=0 = natural, gap-free connection):\n * - FS: lag = succStart - predEnd - 1 (adjacent days = 0)\n * - SS: lag = succStart - predStart\n * - FF: lag = succEnd - predEnd\n * - SF: lag = succEnd - predStart + 1 (symmetric to FS)\n */\nexport function computeLagFromDates(\n linkType: LinkType,\n predStart: Date,\n predEnd: Date,\n succStart: Date,\n succEnd: Date\n): number {\n const DAY_MS = 24 * 60 * 60 * 1000;\n const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());\n const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());\n const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());\n const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());\n switch (linkType) {\n case 'FS': return Math.round((sS - pE) / DAY_MS) - 1;\n case 'SS': return Math.round((sS - pS) / DAY_MS);\n case 'FF': return Math.round((sE - pE) / DAY_MS);\n case 'SF': return Math.round((sE - pS) / DAY_MS) + 1;\n }\n}\n\n/**\n * Calculate successor date based on predecessor dates, link type, and lag\n *\n * Link type semantics:\n * - FS: Successor start = Predecessor end + lag + 1 day (lag=0 → next day)\n * - SS: Successor start = Predecessor start + lag\n * - FF: Successor end = Predecessor end + lag\n * - SF: Successor end = Predecessor start + lag - 1 day (lag=0 → day before)\n */\nexport function calculateSuccessorDate(\n predecessorStart: Date,\n predecessorEnd: Date,\n linkType: LinkType,\n lag: number = 0\n): Date {\n const DAY_MS = 24 * 60 * 60 * 1000;\n\n switch (linkType) {\n case 'FS':\n // lag=0 → successor starts the day after predecessor ends (inclusive dates)\n return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS);\n case 'SS':\n return new Date(predecessorStart.getTime() + lag * DAY_MS);\n case 'FF':\n return new Date(predecessorEnd.getTime() + lag * DAY_MS);\n case 'SF':\n // lag=0 → successor ends the day before predecessor starts (inclusive dates)\n return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS);\n }\n}\n\n/**\n * Validate all dependencies in the task list\n */\nexport function validateDependencies(tasks: Task[]): ValidationResult {\n const errors: DependencyError[] = [];\n const taskIds = new Set(tasks.map(t => t.id));\n\n // Check for missing predecessor references\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n if (!taskIds.has(dep.taskId)) {\n errors.push({\n type: 'missing-task',\n taskId: task.id,\n message: `Dependency references non-existent task: ${dep.taskId}`,\n relatedTaskIds: [dep.taskId],\n });\n }\n }\n }\n }\n\n // Check for cycles\n const cycleResult = detectCycles(tasks);\n if (cycleResult.hasCycle && cycleResult.cyclePath) {\n errors.push({\n type: 'cycle',\n taskId: cycleResult.cyclePath[0],\n message: 'Circular dependency detected',\n relatedTaskIds: cycleResult.cyclePath,\n });\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Get successor tasks of a dragged task using BFS, filtered by link type(s).\n *\n * Returns tasks in breadth-first order (direct successors first, then their successors).\n * The dragged task itself is NOT included in the returned array.\n *\n * The visited set prevents infinite loops in case of cycles (cycle detection already\n * prevents cycles in valid data, but the guard adds safety during cascade computation).\n *\n * @param draggedTaskId - ID of the task being dragged\n * @param allTasks - All tasks in the chart\n * @param linkTypes - Dependency types to follow (default: ['FS'] preserves Phase 7 behavior)\n */\nexport function getSuccessorChain(\n draggedTaskId: string,\n allTasks: Task[],\n linkTypes: LinkType[] = ['FS']\n): Task[] {\n // Build successor map filtered by requested link types: predecessor -> [successors]\n const successorMap = new Map<string, string[]>();\n for (const task of allTasks) {\n successorMap.set(task.id, []);\n }\n for (const task of allTasks) {\n if (!task.dependencies) continue;\n for (const dep of task.dependencies) {\n if (linkTypes.includes(dep.type)) {\n const list = successorMap.get(dep.taskId) ?? [];\n list.push(task.id);\n successorMap.set(dep.taskId, list);\n }\n }\n }\n\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n const visited = new Set<string>();\n const queue: string[] = [draggedTaskId];\n const chain: Task[] = [];\n visited.add(draggedTaskId); // seed — not added to chain\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n const successors = successorMap.get(current) ?? [];\n for (const sid of successors) {\n if (!visited.has(sid)) {\n visited.add(sid);\n const t = taskById.get(sid);\n if (t) {\n chain.push(t);\n queue.push(sid);\n }\n }\n }\n }\n\n return chain; // excludes dragged task\n}\n\n/**\n * Cascade successors by actual link constraints (BFS, constraint-based).\n *\n * Each successor in the chain is positioned using calculateSuccessorDate\n * with the predecessor's NEW dates and the actual lag — not a flat delta.\n *\n * - FS/SS: constraintDate = new start of successor (duration preserved)\n * - FF/SF: constraintDate = new end of successor (duration preserved)\n *\n * Locked tasks break the chain.\n * Also cascades hierarchy children when a parent moves (when parent moves by\n * dependency link, children must move with it to maintain parent-child relationship).\n * Returns only the cascaded successors (not the moved task itself).\n */\nexport function cascadeByLinks(\n movedTaskId: string,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[],\n skipChildCascade: boolean = false\n): Task[] {\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n\n // Track each task's updated dates\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTaskId, { start: newStart, end: newEnd });\n\n const result: Task[] = [];\n const queue: string[] = [movedTaskId];\n const visited = new Set<string>([movedTaskId]);\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n const { start: predStart, end: predEnd } = updatedDates.get(currentId)!;\n\n // First, cascade hierarchy children of the current task if it's a parent\n // Skip if skipChildCascade is true (for parent task editing via task list)\n if (!skipChildCascade) {\n const children = getChildren(currentId, allTasks);\n for (const child of children) {\n if (visited.has(child.id) || child.locked) continue;\n\n // When a parent moves, its children move by the same delta\n const origStart = new Date(child.startDate as string);\n const origEnd = new Date(child.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n const parentOrig = taskById.get(currentId)!;\n const parentOrigStart = new Date(parentOrig.startDate as string);\n const parentOrigEnd = new Date(parentOrig.endDate as string);\n\n // Calculate delta from parent's original to new position\n const parentStartDelta = predStart.getTime() - parentOrigStart.getTime();\n const parentEndDelta = predEnd.getTime() - parentOrigEnd.getTime();\n\n const newChildStart = new Date(origStart.getTime() + parentStartDelta);\n const newChildEnd = new Date(origEnd.getTime() + parentEndDelta);\n\n visited.add(child.id);\n updatedDates.set(child.id, { start: newChildStart, end: newChildEnd });\n result.push({\n ...child,\n startDate: newChildStart.toISOString().split('T')[0],\n endDate: newChildEnd.toISOString().split('T')[0],\n });\n queue.push(child.id);\n }\n }\n\n // Then, cascade dependency successors\n for (const task of allTasks) {\n if (visited.has(task.id) || !task.dependencies || task.locked) continue;\n\n for (const dep of task.dependencies) {\n if (dep.taskId !== currentId) continue;\n\n const orig = taskById.get(task.id)!;\n const origStart = new Date(orig.startDate as string);\n const origEnd = new Date(orig.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n // Use effective lag from dates, not stored dep.lag\n const predOrig = taskById.get(currentId)!;\n const predOrigStart = new Date(predOrig.startDate as string);\n const predOrigEnd = new Date(predOrig.endDate as string);\n const effectiveLag = computeLagFromDates(dep.type, predOrigStart, predOrigEnd, origStart, origEnd);\n\n const constraintDate = calculateSuccessorDate(predStart, predEnd, dep.type, effectiveLag);\n\n let newSuccStart: Date;\n let newSuccEnd: Date;\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n newSuccStart = constraintDate;\n newSuccEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n // FF or SF: constraintDate is the end date\n newSuccEnd = constraintDate;\n newSuccStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n visited.add(task.id);\n updatedDates.set(task.id, { start: newSuccStart, end: newSuccEnd });\n result.push({\n ...task,\n startDate: newSuccStart.toISOString().split('T')[0],\n endDate: newSuccEnd.toISOString().split('T')[0],\n });\n queue.push(task.id);\n break; // one predecessor per cascade step\n }\n }\n }\n\n return result;\n}\n\n/**\n * Get transitive closure of successors for cascading.\n *\n * Direct successors of the changed task are filtered by firstLevelLinkTypes.\n * Their successors (and so on) are included regardless of link type.\n *\n * Also includes hierarchy children of any parent task in the chain - when a parent\n * moves via dependency cascade, its children must move with it.\n */\nexport function getTransitiveCascadeChain(\n changedTaskId: string,\n allTasks: Task[],\n firstLevelLinkTypes: LinkType[]\n): Task[] {\n const allTypesSuccessorMap = new Map<string, Task[]>();\n for (const task of allTasks) {\n allTypesSuccessorMap.set(task.id, []);\n }\n for (const task of allTasks) {\n if (!task.dependencies) continue;\n for (const dep of task.dependencies) {\n const list = allTypesSuccessorMap.get(dep.taskId) ?? [];\n list.push(task);\n allTypesSuccessorMap.set(dep.taskId, list);\n }\n }\n\n const directChildren = getChildren(changedTaskId, allTasks);\n const directSuccessors = getSuccessorChain(changedTaskId, allTasks, firstLevelLinkTypes);\n const initialChain = [...directChildren, ...directSuccessors].filter((task, index, arr) =>\n arr.findIndex(candidate => candidate.id === task.id) === index\n );\n\n const chain = [...initialChain];\n const visited = new Set<string>([changedTaskId, ...initialChain.map(t => t.id)]);\n const queue = [...initialChain];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n // Add hierarchy children of the current task if it's a parent\n const children = getChildren(current.id, allTasks);\n for (const child of children) {\n if (!visited.has(child.id)) {\n visited.add(child.id);\n chain.push(child);\n queue.push(child);\n }\n }\n\n const successors = allTypesSuccessorMap.get(current.id) ?? [];\n for (const successor of successors) {\n if (!visited.has(successor.id)) {\n visited.add(successor.id);\n chain.push(successor);\n queue.push(successor);\n }\n }\n }\n\n return chain;\n}\n\n/**\n * Recalculate incoming dependency lags after a task's dates change.\n * Used when completing a drag or applying a manual date change.\n */\nexport function recalculateIncomingLags(\n task: Task,\n newStartDate: Date,\n newEndDate: Date,\n allTasks: Task[]\n): NonNullable<Task['dependencies']> {\n if (!task.dependencies) return [];\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n\n return task.dependencies.map(dep => {\n const predecessor = taskById.get(dep.taskId);\n if (!predecessor) return dep;\n\n const predStart = new Date(predecessor.startDate as string);\n const predEnd = new Date(predecessor.endDate as string);\n const lagDays = computeLagFromDates(dep.type, predStart, predEnd, newStartDate, newEndDate);\n return { ...dep, lag: lagDays };\n });\n}\n\n/**\n * Get all dependency edges for rendering\n * Returns array of { predecessorId, successorId, type, lag }\n */\nexport function getAllDependencyEdges(tasks: Task[]): Array<{\n predecessorId: string;\n successorId: string;\n type: LinkType;\n lag: number;\n}> {\n const edges: Array<{ predecessorId: string; successorId: string; type: LinkType; lag: number }> = [];\n\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n edges.push({\n predecessorId: dep.taskId,\n successorId: task.id,\n type: dep.type,\n lag: dep.lag ?? 0,\n });\n }\n }\n }\n\n return edges;\n}\n\n// ============================================================================\n// Hierarchy Utilities (Phase 19)\n// ============================================================================\n\n/**\n * Get all child tasks of a parent task.\n * Returns tasks where task.parentId === parentId.\n */\nexport function getChildren(parentId: string, tasks: Task[]): Task[] {\n return tasks.filter(t => (t as any).parentId === parentId);\n}\n\n/**\n * Check if a task is a parent (has children).\n * Returns true if any task has this task as parentId.\n */\nexport function isTaskParent(taskId: string, tasks: Task[]): boolean {\n return tasks.some(t => (t as any).parentId === taskId);\n}\n\n/**\n * Compute parent task dates from children.\n * Returns { startDate, endDate } where:\n * - startDate = min(children.startDate) or own startDate if no children\n * - endDate = max(children.endDate) or own endDate if no children\n */\nexport function computeParentDates(parentId: string, tasks: Task[]): { startDate: Date; endDate: Date } {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n // Empty parent - use own dates or default\n const parent = tasks.find(t => t.id === parentId);\n const start = parent ? new Date(parent.startDate) : new Date();\n const end = parent ? new Date(parent.endDate) : new Date();\n return { startDate: start, endDate: end };\n }\n\n const startDates = children.map(c => new Date(c.startDate));\n const endDates = children.map(c => new Date(c.endDate));\n\n const minTime = Math.min(...startDates.map(d => d.getTime()));\n const maxTime = Math.max(...endDates.map(d => d.getTime()));\n\n return {\n startDate: new Date(minTime),\n endDate: new Date(maxTime),\n };\n}\n\n/**\n * Compute parent task progress from children (weighted average by duration).\n * Returns 0 if no children.\n * Progress is rounded to 1 decimal place.\n */\nexport function computeParentProgress(parentId: string, tasks: Task[]): number {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n return 0;\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n let totalWeight = 0;\n let weightedSum = 0;\n\n for (const child of children) {\n const start = new Date(child.startDate).getTime();\n const end = new Date(child.endDate).getTime();\n // Inclusive duration: (end - start + 1 day) / DAY_MS\n const duration = (end - start + DAY_MS) / DAY_MS;\n const progress = (child.progress ?? 0);\n\n totalWeight += duration;\n weightedSum += duration * progress;\n }\n\n if (totalWeight === 0) {\n return 0;\n }\n\n // Round to 1 decimal place\n return Math.round((weightedSum / totalWeight) * 10) / 10;\n}\n\n/**\n * Remove dependencies between two tasks in both directions.\n * When tasks become parent-child, their dependency link becomes meaningless.\n *\n * @param taskId1 - First task ID\n * @param taskId2 - Second task ID\n * @param tasks - All tasks array\n * @returns New tasks array with dependencies between the two tasks removed\n */\nexport function removeDependenciesBetweenTasks(\n taskId1: string,\n taskId2: string,\n tasks: Task[]\n): Task[] {\n return tasks.map(task => {\n if (task.id === taskId1 || task.id === taskId2) {\n if (!task.dependencies) return task;\n const otherTaskId = task.id === taskId1 ? taskId2 : taskId1;\n const filteredDependencies = task.dependencies.filter(dep => dep.taskId !== otherTaskId);\n // Only create new object if dependencies actually changed\n if (filteredDependencies.length === task.dependencies.length) {\n return task;\n }\n return {\n ...task,\n dependencies: filteredDependencies.length > 0 ? filteredDependencies : undefined,\n };\n }\n return task;\n });\n}\n\n/**\n * Find the parent ID of a task.\n * Returns the parentId of the task if found, undefined otherwise.\n *\n * @param taskId - ID of the task to find parent for\n * @param tasks - All tasks array\n * @returns Parent task ID or undefined if task is root or not found\n */\nexport function findParentId(taskId: string, tasks: Task[]): string | undefined {\n const task = tasks.find(t => t.id === taskId);\n return task?.parentId;\n}\n\n// ============================================================================\n// Universal Cascade Engine (Phase 19 fix)\n// ============================================================================\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/**\n * How a task arrived in the BFS queue — controls which rules apply when\n * processing it.\n *\n * 'direct' — The explicitly moved task (seed).\n * 'child-delta' — Added by RULE 1: parent dragged, child inherits delta.\n * Children of THIS task also inherit the same delta (RULE 1 applies).\n * 'parent-recalc'— Added by RULE 2: a child moved, parent recomputed from children.\n * Children of THIS task must NOT be shifted again (RULE 1 skipped).\n * 'dependency' — Added by RULE 3: predecessor moved, successor repositioned.\n * Children of THIS task inherit the delta (RULE 1 applies).\n */\ntype ArrivalMode = 'direct' | 'child-delta' | 'parent-recalc' | 'dependency';\n\n/**\n * Universal cascade engine that propagates a moved task's new position through\n * the entire dependency+hierarchy graph using BFS with change detection.\n *\n * Three rules applied in BFS order:\n *\n * RULE 1 — Hierarchy children of a parent task shift by the parent's delta.\n * Applied only when the parent arrived as 'direct', 'child-delta', or 'dependency'.\n * Skipped for 'parent-recalc' (parent was computed FROM children).\n *\n * RULE 2 — Parent task is recomputed as min(children.start)..max(children.end).\n * Re-queued every time a child changes (no visited guard — uses change detection).\n * This ensures the parent reflects ALL cascaded children, not just the first one.\n *\n * RULE 3 — Dependency successors are repositioned via calculateSuccessorDate.\n * Effective lag is computed from original dates (not stored dep.lag).\n * Re-queued if predecessor's dates changed (change detection).\n *\n * Change detection prevents infinite loops: a task is only re-queued if its\n * computed dates differ from what's already in updatedDates.\n *\n * @param movedTask - The task that was directly moved/resized (already has new dates).\n * @param newStart - New start date of the moved task.\n * @param newEnd - New end date of the moved task.\n * @param allTasks - All tasks in the chart (original, unmodified dates).\n */\nexport function universalCascade(\n movedTask: Task,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[]\n): Task[] {\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n\n // updatedDates: authoritative new position for every affected task\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTask.id, { start: newStart, end: newEnd });\n\n // resultMap: deduplicated results keyed by task ID (updated in place on re-visits)\n const resultMap = new Map<string, Task>();\n\n // Queue entries: [taskId, arrivalMode]\n const queue: Array<[string, ArrivalMode]> = [[movedTask.id, 'direct']];\n\n // Guard: track which children have been shifted by RULE 1 to prevent double-shift\n const childShifted = new Set<string>();\n\n // Safety: max iterations to prevent runaway loops\n let iterations = 0;\n const MAX_ITERATIONS = allTasks.length * 3;\n\n while (queue.length > 0 && iterations < MAX_ITERATIONS) {\n iterations++;\n const [currentId, arrivalMode] = queue.shift()!;\n const { start: currStart, end: currEnd } = updatedDates.get(currentId)!;\n const currentOriginal = taskById.get(currentId)!;\n\n // ── RULE 1: Hierarchy children follow their parent ──────────────────────\n if (arrivalMode !== 'parent-recalc') {\n const children = getChildren(currentId, allTasks);\n for (const child of children) {\n if (childShifted.has(child.id) || child.locked) continue;\n\n const parentOrigStart = new Date(currentOriginal.startDate as string);\n const parentOrigEnd = new Date(currentOriginal.endDate as string);\n\n const childOrigStart = new Date(child.startDate as string);\n const childOrigEnd = new Date(child.endDate as string);\n\n const startDeltaMs = currStart.getTime() - parentOrigStart.getTime();\n const endDeltaMs = currEnd.getTime() - parentOrigEnd.getTime();\n\n const childNewStart = new Date(childOrigStart.getTime() + startDeltaMs);\n const childNewEnd = new Date(childOrigEnd.getTime() + endDeltaMs);\n\n // Change detection: skip if already at this position\n const prev = updatedDates.get(child.id);\n if (prev && prev.start.getTime() === childNewStart.getTime() && prev.end.getTime() === childNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(child.id, { start: childNewStart, end: childNewEnd });\n childShifted.add(child.id);\n queue.push([child.id, 'child-delta']);\n resultMap.set(child.id, {\n ...child,\n startDate: childNewStart.toISOString().split('T')[0],\n endDate: childNewEnd.toISOString().split('T')[0],\n });\n }\n }\n\n // ── RULE 2: Parent task is recomputed from its children ─────────────────\n // No visited guard — always recalculate, re-queue only if dates changed.\n // This ensures parent reflects ALL cascaded children (not just the first).\n const parentId = (currentOriginal as any).parentId as string | undefined;\n if (parentId) {\n const parent = taskById.get(parentId);\n if (parent && !parent.locked) {\n const siblings = getChildren(parentId, allTasks);\n\n const siblingPositions = siblings.map(sib => {\n if (updatedDates.has(sib.id)) return updatedDates.get(sib.id)!;\n return { start: new Date(sib.startDate as string), end: new Date(sib.endDate as string) };\n });\n\n const minStart = new Date(Math.min(...siblingPositions.map(p => p.start.getTime())));\n const maxEnd = new Date(Math.max(...siblingPositions.map(p => p.end.getTime())));\n\n // Change detection: only re-queue if parent dates actually changed\n const prev = updatedDates.get(parentId);\n if (!prev || prev.start.getTime() !== minStart.getTime() || prev.end.getTime() !== maxEnd.getTime()) {\n updatedDates.set(parentId, { start: minStart, end: maxEnd });\n queue.push([parentId, 'parent-recalc']);\n resultMap.set(parentId, {\n ...parent,\n startDate: minStart.toISOString().split('T')[0],\n endDate: maxEnd.toISOString().split('T')[0],\n });\n }\n }\n }\n\n // ── RULE 3: Dependency successors are repositioned ──────────────────────\n // No visited guard — uses change detection to allow re-cascading when\n // predecessor dates change (e.g., parent recalculated after more children cascade).\n for (const task of allTasks) {\n if (task.locked || !task.dependencies) continue;\n\n const dep = task.dependencies.find(d => d.taskId === currentId);\n if (!dep) continue;\n\n const origStart = new Date(task.startDate as string);\n const origEnd = new Date(task.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n // Effective lag from original dates (source of truth)\n const predOrigStart = new Date(currentOriginal.startDate as string);\n const predOrigEnd = new Date(currentOriginal.endDate as string);\n const effectiveLag = computeLagFromDates(dep.type, predOrigStart, predOrigEnd, origStart, origEnd);\n\n const constraintDate = calculateSuccessorDate(currStart, currEnd, dep.type, effectiveLag);\n\n let succNewStart: Date;\n let succNewEnd: Date;\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n succNewStart = constraintDate;\n succNewEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n succNewEnd = constraintDate;\n succNewStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n // Change detection: skip if already at this position\n const prev = updatedDates.get(task.id);\n if (prev && prev.start.getTime() === succNewStart.getTime() && prev.end.getTime() === succNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(task.id, { start: succNewStart, end: succNewEnd });\n queue.push([task.id, 'dependency']);\n resultMap.set(task.id, {\n ...task,\n startDate: succNewStart.toISOString().split('T')[0],\n endDate: succNewEnd.toISOString().split('T')[0],\n });\n }\n }\n\n return Array.from(resultMap.values());\n}\n","import type { Task } from '../types';\nimport { computeParentDates, computeParentProgress, isTaskParent } from './dependencyUtils';\nimport { normalizeTaskDates } from './dateUtils';\n\n/**\n * Build a stable depth-first task order from parentId links.\n * Sibling order follows the order in the input array.\n * Tasks with missing parents are treated as root tasks.\n */\nexport function flattenHierarchy<T extends Task>(tasks: T[]): T[] {\n const byId = new Map(tasks.map((task) => [task.id, task]));\n const byParent = new Map<string | undefined, T[]>();\n\n for (const task of tasks) {\n const normalizedParentId = task.parentId && byId.has(task.parentId)\n ? task.parentId\n : undefined;\n const siblings = byParent.get(normalizedParentId) ?? [];\n siblings.push(task);\n byParent.set(normalizedParentId, siblings);\n }\n\n const result: T[] = [];\n const visited = new Set<string>();\n\n const walk = (parentId?: string) => {\n const children = byParent.get(parentId) ?? [];\n for (const task of children) {\n if (visited.has(task.id)) continue;\n visited.add(task.id);\n result.push(task);\n walk(task.id);\n }\n };\n\n walk(undefined);\n\n for (const task of tasks) {\n if (!visited.has(task.id)) {\n result.push(task);\n }\n }\n\n return result;\n}\n\n/**\n * Normalize hierarchy-aware display fields.\n * Parent task dates and progress are always recomputed from children,\n * taking precedence over any hardcoded parent values from the input.\n * Also normalizes task dates to ensure startDate is always before or equal to endDate.\n */\nexport function normalizeHierarchyTasks<T extends Task>(tasks: T[]): T[] {\n const orderedTasks = flattenHierarchy(tasks).map((task) => {\n // Normalize dates for all tasks (swap if endDate < startDate)\n const { startDate, endDate } = normalizeTaskDates(task.startDate, task.endDate);\n return { ...task, startDate: startDate as T['startDate'], endDate: endDate as T['endDate'] };\n }) as T[];\n\n for (const task of [...orderedTasks].reverse()) {\n if (!isTaskParent(task.id, orderedTasks)) continue;\n\n const { startDate, endDate } = computeParentDates(task.id, orderedTasks);\n const progress = computeParentProgress(task.id, orderedTasks);\n const normalizedStartDate = startDate.toISOString().split('T')[0];\n const normalizedEndDate = endDate.toISOString().split('T')[0];\n const parentIndex = orderedTasks.findIndex((candidate) => candidate.id === task.id);\n\n if (parentIndex === -1) continue;\n\n orderedTasks[parentIndex] = {\n ...orderedTasks[parentIndex],\n startDate: normalizedStartDate as T['startDate'],\n endDate: normalizedEndDate as T['endDate'],\n progress: progress as T['progress'],\n };\n }\n\n return orderedTasks;\n}\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { format } from 'date-fns';\nimport { ru } from 'date-fns/locale';\nimport { getMonthSpans, getWeekSpans, getWeekBlocks, getMonthBlocks, getYearSpans, type WeekBlock, type WeekSpan, type MonthBlock, type YearSpan } from '../../utils/dateUtils';\nimport type { MonthSpan } from '../../types';\nimport './TimeScaleHeader.css';\n\nexport interface TimeScaleHeaderProps {\n /** Array of dates to display (from getMultiMonthDays) */\n days: Date[];\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Height of the header row in pixels */\n headerHeight: number;\n /** View mode: 'day' renders individual day columns, 'week' renders 7-day week columns, 'month' renders one column per month */\n viewMode?: 'day' | 'week' | 'month';\n /** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */\n isCustomWeekend?: (date: Date) => boolean;\n}\n\n/**\n * TimeScaleHeader component - displays two-row date headers for the Gantt chart\n *\n * Top row: Month names (Russian, left-aligned) spanning multiple day/week columns\n * Bottom row: Day numbers (centered) in individual day columns OR week start day numbers\n *\n * Supports two view modes:\n * - day (default): each column = 1 day, shows month names + individual day numbers\n * - week: each column = 7 days, shows month names spanning week columns + week-start dates\n */\nconst TimeScaleHeader: React.FC<TimeScaleHeaderProps> = ({\n days,\n dayWidth,\n headerHeight,\n viewMode = 'day',\n isCustomWeekend,\n}) => {\n // Calculate month spans using the utility from dateUtils\n const monthSpans = useMemo(() => getMonthSpans(days), [days]);\n\n // Split header height evenly between two rows\n const rowHeight = headerHeight / 2;\n\n // Calculate grid template for day row\n const dayGridTemplate = useMemo(\n () => `repeat(${days.length}, ${dayWidth}px)`,\n [days.length, dayWidth]\n );\n\n // Week-view: blocks with variable width (split on month boundaries)\n const weekBlocks = useMemo(\n () => (viewMode === 'week' ? getWeekBlocks(days) : []),\n [days, viewMode]\n );\n\n // Week-view: month spans grouped over week-blocks (row 1 labels)\n const weekSpans = useMemo(\n () => (viewMode === 'week' ? getWeekSpans(days) : []),\n [days, viewMode]\n );\n\n // Calculate column widths for each block (for grid template)\n const weekColumnWidths = useMemo(\n () => weekBlocks.map(b => b.days * dayWidth),\n [weekBlocks, dayWidth]\n );\n\n // Calculate total width for grid template\n const weekGridTemplate = useMemo(\n () => weekColumnWidths.map(w => `${w}px`).join(' '),\n [weekColumnWidths]\n );\n\n // Month-view: one block per calendar month (row 2 columns)\n const monthBlocks = useMemo(\n () => (viewMode === 'month' ? getMonthBlocks(days) : []),\n [days, viewMode]\n );\n\n // Month-view: year spans over month blocks (row 1 labels)\n const yearSpans = useMemo(\n () => (viewMode === 'month' ? getYearSpans(days) : []),\n [days, viewMode]\n );\n\n // Month-view: grid template for row 2 (variable column widths = days * dayWidth)\n const monthGridTemplate = useMemo(\n () => monthBlocks.map(b => `${b.days * dayWidth}px`).join(' '),\n [monthBlocks, dayWidth]\n );\n\n // Separator positions — same Math.round formula as GridBackground to guarantee pixel alignment.\n // fullHeight=true → spans both header rows (thick boundary between spans in row 1).\n // fullHeight=false → spans row 2 only (thin sub-column divider, doesn't cut through row 1 spans).\n const separators = useMemo(() => {\n const result: Array<{ x: number; isThick: boolean; fullHeight: boolean }> = [];\n if (viewMode === 'day') {\n for (let i = 1; i < days.length; i++) {\n if (days[i].getUTCDate() === 1) {\n result.push({ x: Math.round(i * dayWidth), isThick: true, fullHeight: true });\n }\n }\n } else if (viewMode === 'week') {\n let dayIndex = 0;\n for (let i = 0; i < weekBlocks.length; i++) {\n if (i > 0) {\n const isMonth = weekBlocks[i - 1].startDate.getUTCMonth() !== weekBlocks[i].startDate.getUTCMonth();\n result.push({ x: Math.round(dayIndex * dayWidth), isThick: isMonth, fullHeight: isMonth });\n }\n dayIndex += weekBlocks[i].days;\n }\n } else if (viewMode === 'month') {\n let dayIndex = 0;\n for (let i = 0; i < monthBlocks.length; i++) {\n if (i > 0) {\n const isYear = monthBlocks[i].startDate.getUTCMonth() === 0;\n result.push({ x: Math.round(dayIndex * dayWidth), isThick: isYear, fullHeight: isYear });\n }\n dayIndex += monthBlocks[i].days;\n }\n }\n return result;\n }, [days, weekBlocks, monthBlocks, dayWidth, viewMode]);\n\n return (\n <div\n className=\"gantt-tsh-header\"\n style={{ height: `${headerHeight}px`, position: 'relative' }}\n >\n {/* Separator lines — pixel-aligned with GridBackground */}\n {separators.map((sep, i) => (\n <div\n key={`sep-${i}`}\n className={`gantt-tsh-separator${sep.isThick ? ' gantt-tsh-separator--thick' : ''}`}\n style={sep.fullHeight\n ? { left: `${sep.x}px`, top: 0, bottom: 0 }\n : { left: `${sep.x}px`, top: rowHeight, height: rowHeight }}\n />\n ))}\n\n {/* Month row - top */}\n <div\n className=\"gantt-tsh-monthRow\"\n style={{ height: `${rowHeight}px` }}\n >\n {viewMode === 'week' ? (\n // Week-view row 1: month names spanning week blocks\n weekSpans.map((span: WeekSpan, index: number) => (\n <div\n key={`wmonth-${index}`}\n className=\"gantt-tsh-monthCell\"\n style={{ width: `${span.days * dayWidth}px` }}\n >\n {format(span.month, 'LLLL yyyy', { locale: ru }).replace(/^./, (c) => c.toUpperCase())}\n </div>\n ))\n ) : viewMode === 'month' ? (\n // Month-view row 1: year labels spanning all months of that year\n yearSpans.map((span: YearSpan, index: number) => (\n <div\n key={`year-${index}`}\n className=\"gantt-tsh-monthCell\"\n style={{ width: `${span.days * dayWidth}px` }}\n >\n {span.year.getUTCFullYear().toString()}\n </div>\n ))\n ) : (\n // Day-view row 1: month names spanning day columns (existing code)\n monthSpans.map((span: MonthSpan, index: number) => (\n <div\n key={`month-${index}`}\n className=\"gantt-tsh-monthCell\"\n style={{ width: `${span.days * dayWidth}px` }}\n >\n {format(span.month, 'LLLL yyyy', { locale: ru }).replace(/^./, (c) => c.toUpperCase())}\n </div>\n ))\n )}\n </div>\n\n {/* Day/Week row - bottom */}\n <div\n className=\"gantt-tsh-dayRow\"\n style={{\n height: `${rowHeight}px`,\n gridTemplateColumns: viewMode === 'week'\n ? weekGridTemplate\n : viewMode === 'month'\n ? monthGridTemplate\n : dayGridTemplate,\n }}\n >\n {viewMode === 'week' ? (\n // Week-view row 2: week block start day numbers (variable width)\n weekBlocks.map((block, index) => {\n const prevBlock = weekBlocks[index - 1];\n const isMonthBoundary =\n index > 0 && prevBlock &&\n prevBlock.startDate.getUTCMonth() !== block.startDate.getUTCMonth();\n // Show date only for full weeks (7 days)\n const showDate = block.days === 7;\n return (\n <div\n key={`week-${index}`}\n className=\"gantt-tsh-dayCell gantt-tsh-weekCell\"\n >\n <span className=\"gantt-tsh-dayLabel\">\n {showDate ? String(block.startDate.getUTCDate()).padStart(2, '0') : ''}\n </span>\n </div>\n );\n })\n ) : viewMode === 'month' ? (\n // Month-view row 2: one column per month, shows abbreviated month name\n monthBlocks.map((block: MonthBlock, index: number) => {\n const MIN_DAYS_TO_SHOW_LABEL = 15;\n const showLabel = block.days >= MIN_DAYS_TO_SHOW_LABEL;\n const isYearBoundary = index > 0 && block.startDate.getUTCMonth() === 0;\n return (\n <div\n key={`mblock-${index}`}\n className=\"gantt-tsh-dayCell gantt-tsh-weekCell\"\n >\n <span className=\"gantt-tsh-dayLabel\">\n {showLabel\n ? (() => { const s = block.startDate.toLocaleString('ru-RU', { month: 'long', timeZone: 'UTC' }); return s.charAt(0).toUpperCase() + s.slice(1); })()\n : ''}\n </span>\n </div>\n );\n })\n ) : (\n // Day-view row 2: individual day numbers (existing code)\n days.map((day, index) => {\n const isWeekendDay = isCustomWeekend\n ? isCustomWeekend(day)\n : day.getUTCDay() === 0 || day.getUTCDay() === 6;\n const prevDay = days[index - 1];\n const isMonthBoundary = index > 0 && prevDay && prevDay.getUTCMonth() !== day.getUTCMonth();\n // Use local date comparison for \"today\" (user's current date)\n const now = new Date();\n const isTodayDate =\n day.getUTCFullYear() === now.getFullYear() &&\n day.getUTCMonth() === now.getMonth() &&\n day.getUTCDate() === now.getDate();\n return (\n <div key={`day-${index}`} className={`gantt-tsh-dayCell ${isWeekendDay ? 'gantt-tsh-weekendDay' : ''} ${isTodayDate ? 'gantt-tsh-today' : ''}`}>\n <span className=\"gantt-tsh-dayLabel\">{format(day, 'd')}</span>\n </div>\n );\n })\n )}\n </div>\n </div>\n );\n};\n\nexport default TimeScaleHeader;\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { parseUTCDate, formatDateLabel } from '../../utils/dateUtils';\nimport { calculateTaskBar, pixelsToDate } from '../../utils/geometry';\nimport { isTaskExpired } from '../../utils/expired';\nimport { useTaskDrag } from '../../hooks/useTaskDrag';\nimport { isTaskParent, getChildren } from '../../utils/dependencyUtils';\nimport type { Task } from '../GanttChart';\nimport './TaskRow.css';\n\nexport interface TaskRowProps {\n /** Task data to render */\n task: Task;\n /** Start of the month for positioning calculations */\n monthStart: Date;\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Height of the task row in pixels */\n rowHeight: number;\n /** Callback when task is modified via drag/resize. Receives array of changed tasks. */\n onTasksChange?: (tasks: Task[]) => void;\n /** Callback when task drag state changes (for rendering guide lines) */\n onDragStateChange?: (state: {\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n }) => void;\n /** Index of the task row (used for dependency rendering) */\n rowIndex?: number;\n /** All tasks in the chart (used for dependency validation) */\n allTasks?: Task[];\n /** Whether auto-scheduling is enabled */\n enableAutoSchedule?: boolean;\n /** Whether to disable constraint checking during drag */\n disableConstraints?: boolean;\n /** Position override for cascade preview — when set, overrides both static and drag position */\n overridePosition?: { left: number; width: number };\n /** Called each RAF during cascade drag with override positions for non-dragged chain tasks */\n onCascadeProgress?: (overrides: Map<string, { left: number; width: number }>) => void;\n /** Called when cascade drag completes; receives all shifted tasks including dragged task */\n onCascade?: (tasks: Task[]) => void;\n /** Optional horizontal divider line - renders above or below the task row */\n divider?: 'top' | 'bottom';\n /** Highlight expired/overdue tasks with red background */\n highlightExpiredTasks?: boolean;\n /** Whether this row matches the active filter highlight */\n isFilterMatch?: boolean;\n}\n\n/**\n * Custom comparison function for React.memo\n *\n * Performance optimization: Only re-renders if task properties that affect rendering change.\n *\n * NOTE: onTasksChange is intentionally excluded from this comparison because:\n * 1. The parent (GanttChart) wraps onTasksChange in useCallback for referential stability\n * 2. onTasksChange is only called AFTER drag completes (not during drag)\n * 3. During drag, only the dragged TaskRow re-renders due to its internal drag state\n * 4. Other TaskRows don't need to re-render when one task is dragged\n *\n * NOTE: monthStart MUST be included because task positions are calculated relative to it.\n * When the grid expands (e.g., dragging a task left beyond the boundary), monthStart changes\n * and all tasks need to re-render to update their positions.\n *\n * NOTE: onCascadeProgress and onCascade are excluded from comparison (same pattern as onTasksChange —\n * callbacks excluded from comparison because GanttChart wraps them in useCallback).\n *\n * Excluding onTasksChange prevents re-render storms when dragging tasks with ~100 tasks.\n */\nconst arePropsEqual = (prevProps: TaskRowProps, nextProps: TaskRowProps) => {\n return (\n prevProps.task.id === nextProps.task.id &&\n prevProps.task.name === nextProps.task.name &&\n prevProps.task.startDate === nextProps.task.startDate &&\n prevProps.task.endDate === nextProps.task.endDate &&\n prevProps.task.color === nextProps.task.color &&\n prevProps.task.progress === nextProps.task.progress &&\n prevProps.task.accepted === nextProps.task.accepted &&\n prevProps.monthStart.getTime() === nextProps.monthStart.getTime() &&\n prevProps.dayWidth === nextProps.dayWidth &&\n prevProps.rowHeight === nextProps.rowHeight &&\n prevProps.overridePosition?.left === nextProps.overridePosition?.left &&\n prevProps.overridePosition?.width === nextProps.overridePosition?.width &&\n prevProps.allTasks === nextProps.allTasks &&\n prevProps.disableConstraints === nextProps.disableConstraints &&\n prevProps.task.locked === nextProps.task.locked &&\n prevProps.task.divider === nextProps.task.divider &&\n prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks &&\n prevProps.isFilterMatch === nextProps.isFilterMatch\n // onTasksChange, onCascadeProgress, onCascade excluded - see note above\n );\n};\n\n/**\n * TaskRow component - renders a single task row with a task bar\n *\n * Uses React.memo for performance optimization (QL-01).\n * The task bar is positioned absolutely based on start/end dates.\n */\nconst TaskRow: React.FC<TaskRowProps> = React.memo(\n ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isFilterMatch = false }) => {\n // Extract divider from task prop\n const { divider: taskDivider } = task;\n\n // Parse dates as UTC\n const taskStartDate = useMemo(() => parseUTCDate(task.startDate), [task.startDate]);\n const taskEndDate = useMemo(() => parseUTCDate(task.endDate), [task.endDate]);\n\n // Hierarchy: compute isParent and childCount\n const isParent = useMemo(() => {\n return allTasks ? isTaskParent(task.id, allTasks) : false;\n }, [allTasks, task.id]);\n\n const childCount = useMemo(() => {\n return allTasks ? getChildren(task.id, allTasks).length : 0;\n }, [allTasks, task.id]);\n\n // Calculate expiration status for overdue tasks\n const isExpired = useMemo(() => {\n if (!highlightExpiredTasks) return false;\n return isTaskExpired(task);\n }, [task.startDate, task.endDate, task.progress, highlightExpiredTasks]);\n\n // Calculate task bar position and dimensions\n const { left, width } = useMemo(\n () => calculateTaskBar(taskStartDate, taskEndDate, monthStart, dayWidth),\n [taskStartDate, taskEndDate, monthStart, dayWidth]\n );\n\n // Determine task bar color\n const barColor = isExpired\n ? 'var(--gantt-expired-color)'\n : (task.color || 'var(--gantt-task-bar-default-color)');\n\n // Color for the external task name label — parent tasks match their bar color\n const nameColor = isParent\n ? (task.color || 'var(--gantt-parent-bar-color, #333333)')\n : undefined; // regular tasks use CSS class color (#2563eb)\n\n // Calculate clamped and rounded progress width\n const progressWidth = useMemo(() => {\n if (task.progress === undefined || task.progress <= 0) return 0;\n return Math.min(100, Math.max(0, Math.round(task.progress)));\n }, [task.progress]);\n\n // Determine progress color based on completion status\n const progressColor = useMemo(() => {\n if (isExpired) {\n // Dark red for expired tasks\n return 'color-mix(in srgb, var(--gantt-expired-color) 40%, black)';\n }\n if (progressWidth === 100) {\n return task.accepted\n ? 'var(--gantt-progress-accepted, #22c55e)' // Green for accepted\n : 'var(--gantt-progress-completed, #fbbf24)'; // Yellow for completed (not accepted)\n }\n // Darker shade using color-mix() with task color or default\n const baseColor = task.color || 'var(--gantt-task-bar-default-color)';\n return `color-mix(in srgb, ${baseColor} 40%, black)`;\n }, [isExpired, progressWidth, task.accepted, task.color]);\n\n // At 100% progress, tint the bar itself instead of rendering a fill overlay.\n const barStyle = useMemo(() => {\n if (isParent) {\n if (progressWidth >= 100) {\n const c = 'color-mix(in srgb, var(--gantt-task-bar-default-color) 40%, black)';\n return { backgroundColor: c, '--gantt-parent-bar-color': c } as React.CSSProperties;\n }\n return {};\n }\n if (progressWidth >= 100) {\n return { backgroundColor: progressColor };\n }\n return { backgroundColor: barColor };\n }, [isParent, progressWidth, barColor, progressColor]);\n\n // Handle drag end - call onTasksChange with updated task\n const handleDragEnd = (result: { id: string; startDate: Date; endDate: Date; updatedDependencies?: Task['dependencies'] }) => {\n const updatedTask: Task = {\n ...task,\n startDate: result.startDate.toISOString(),\n endDate: result.endDate.toISOString(),\n ...(result.updatedDependencies !== undefined && { dependencies: result.updatedDependencies }),\n };\n onTasksChange?.([updatedTask]);\n };\n\n // Use drag hook for interactive drag/resize\n const {\n isDragging,\n dragMode,\n currentLeft,\n currentWidth,\n dragHandleProps,\n } = useTaskDrag({\n taskId: task.id,\n initialStartDate: taskStartDate,\n initialEndDate: taskEndDate,\n monthStart,\n dayWidth,\n onDragEnd: handleDragEnd,\n onDragStateChange,\n edgeZoneWidth: 20,\n allTasks,\n rowIndex,\n enableAutoSchedule,\n disableConstraints,\n locked: task.locked,\n onCascadeProgress,\n onCascade,\n });\n\n // Use override position (for cascade preview) with fallback to drag or static position\n const displayLeft = overridePosition?.left ?? (isDragging ? currentLeft : left);\n const displayWidth = overridePosition?.width ?? (isDragging ? currentWidth : width);\n\n // Format date labels for display - update in real-time during drag\n const currentStartDate = isDragging\n ? pixelsToDate(displayLeft, monthStart, dayWidth)\n : taskStartDate;\n const currentEndDate = isDragging\n ? pixelsToDate(displayLeft + displayWidth - dayWidth, monthStart, dayWidth)\n : taskEndDate;\n\n const startDateLabel = formatDateLabel(currentStartDate);\n const endDateLabel = formatDateLabel(currentEndDate);\n\n // Calculate duration in days\n const durationDays = Math.round(\n (currentEndDate.getTime() - currentStartDate.getTime()) / (1000 * 60 * 60 * 24)\n ) + 1;\n\n // Format child count label for parent tasks (Russian plural)\n const getChildCountLabel = (count: number): string => {\n if (count === 1) return '1 задача';\n // For 2, 3, 4 tasks use \"задачи\" (genitive singular)\n // For 5+ tasks use \"задач\" (genitive plural)\n const lastTwoDigits = count % 100;\n const lastDigit = count % 10;\n if (lastTwoDigits >= 11 && lastTwoDigits <= 14) return `${count} задач`;\n if (lastDigit === 1) return `${count} задача`;\n if (lastDigit >= 2 && lastDigit <= 4) return `${count} задачи`;\n return `${count} задач`;\n };\n\n // Determine if progress text fits inside the bar\n // Parent bars have overflow: visible (for bracket ears), so threshold must be stricter:\n // \"X задач 100%\" ≈ 60–70px text + 16px padding = ~110px\n // Regular: \"15 д 100%\" ≈ 76px, \"1 д 100%\" ≈ 62px\n const estimatedTextWidth = isParent ? 120 : (durationDays >= 10 ? 76 : 62);\n const showProgressInside = progressWidth > 0 && displayWidth > estimatedTextWidth;\n\n // Determine if duration fits inside the bar\n // For 1-day tasks: always show duration outside (too narrow)\n // Parent bars: child count label is longer — need more space\n const MIN_DURATION_WIDTH = isParent ? 80 : 50;\n const showDurationInside = durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;\n\n return (\n <div\n data-filter-match={isFilterMatch ? 'true' : 'false'}\n className={`gantt-tr-row ${isFilterMatch ? 'gantt-tr-row-filter-match' : ''}`}\n style={{ height: `${rowHeight}px` }}\n >\n {taskDivider === 'top' && <div className=\"gantt-tr-divider gantt-tr-divider-top\" />}\n <div className=\"gantt-tr-taskContainer\">\n <div\n data-taskbar\n className={`gantt-tr-taskBar ${isDragging ? 'gantt-tr-dragging' : ''} ${task.locked ? 'gantt-tr-locked' : ''} ${isParent ? 'gantt-tr-parentBar' : ''}`}\n style={{\n left: `${displayLeft}px`,\n width: `${displayWidth}px`,\n ...barStyle,\n height: isParent ? 'var(--gantt-parent-bar-height, 14px)' : 'var(--gantt-task-bar-height)',\n cursor: dragHandleProps.style.cursor,\n userSelect: dragHandleProps.style.userSelect,\n }}\n onMouseDown={dragHandleProps.onMouseDown}\n >\n {progressWidth > 0 && progressWidth < 100 && (\n <div\n className=\"gantt-tr-progressBar\"\n style={{\n width: `${progressWidth}%`,\n backgroundColor: progressColor,\n ...(isParent && {\n borderRadius: 'var(--gantt-parent-bar-radius, 8px) 0 0 0',\n }),\n }}\n />\n )}\n {!isParent && <div className=\"gantt-tr-resizeHandle gantt-tr-resizeHandleLeft\" />}\n {showDurationInside && (\n <span className=\"gantt-tr-taskDuration\">\n {isParent ? getChildCountLabel(childCount) : `${durationDays} д`}\n </span>\n )}\n {progressWidth > 0 && showProgressInside && (\n <span className=\"gantt-tr-progressText\">\n {progressWidth}%\n </span>\n )}\n {!isParent && <div className=\"gantt-tr-resizeHandle gantt-tr-resizeHandleRight\" />}\n </div>\n <div\n className={`gantt-tr-leftLabels ${task.locked ? 'gantt-tr-leftLabels-locked' : ''}`}\n style={{\n left: `${displayLeft}px`\n }}\n >\n <span className=\"gantt-tr-dateLabel gantt-tr-dateLabelLeft\">\n {startDateLabel}–{endDateLabel}\n </span>\n </div>\n {task.locked && (\n <svg\n className=\"gantt-tr-lockIcon\"\n style={{\n position: 'absolute',\n left: `${displayLeft - 16}px`,\n top: '50%',\n transform: 'translateY(-50%)',\n width: '12px',\n height: '12px',\n color: '#444',\n pointerEvents: 'none',\n }}\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n aria-label=\"Locked\"\n aria-hidden=\"false\"\n >\n <path d=\"M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM12 17c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z\" />\n </svg>\n )}\n <div\n className=\"gantt-tr-rightLabels\"\n style={{\n left: `${displayLeft + Math.max(displayWidth, 20) - Math.min(6, Math.max(displayWidth, 20) / 2) + 8}px`,\n }}\n >\n {!showDurationInside && (\n <span className=\"gantt-tr-externalDuration\">\n {isParent ? getChildCountLabel(childCount) : `${durationDays} д`}\n </span>\n )}\n {progressWidth > 0 && !showProgressInside && (\n <span className=\"gantt-tr-externalProgress\">\n {progressWidth}%\n </span>\n )}\n <span\n className=\"gantt-tr-externalTaskName\"\n style={nameColor ? { color: nameColor } : undefined}\n >\n {task.name}\n </span>\n </div>\n </div>\n {taskDivider === 'bottom' && <div className=\"gantt-tr-divider gantt-tr-divider-bottom\" />}\n </div>\n );\n },\n arePropsEqual\n);\n\nTaskRow.displayName = 'TaskRow';\n\nexport default TaskRow;\n","/**\n * Calculate day difference in UTC\n */\nconst getUTCDayDifference = (date1: Date, date2: Date): number => {\n const ms1 = Date.UTC(\n date1.getUTCFullYear(),\n date1.getUTCMonth(),\n date1.getUTCDate()\n );\n const ms2 = Date.UTC(\n date2.getUTCFullYear(),\n date2.getUTCMonth(),\n date2.getUTCDate()\n );\n return Math.round((ms1 - ms2) / (1000 * 60 * 60 * 24));\n};\n\n/**\n * Calculate task bar positioning and dimensions\n * @param taskStartDate - Start date of the task\n * @param taskEndDate - End date of the task\n * @param monthStart - Start of the month/visible range\n * @param dayWidth - Width of each day in pixels\n * @returns Object with left position and width in pixels\n */\nexport const calculateTaskBar = (\n taskStartDate: Date,\n taskEndDate: Date,\n monthStart: Date,\n dayWidth: number\n): { left: number; width: number } => {\n const startOffset = getUTCDayDifference(taskStartDate, monthStart);\n const duration = getUTCDayDifference(taskEndDate, taskStartDate);\n\n // Round to avoid sub-pixel rendering issues\n const left = Math.round(startOffset * dayWidth);\n const width = Math.round((duration + 1) * dayWidth); // +1 to include end date\n\n return { left, width };\n};\n\n/**\n * Convert pixel position to date (inverse of calculateTaskBar)\n * @param pixels - Position in pixels (left or width)\n * @param monthStart - Start of the month/visible range\n * @param dayWidth - Width of each day in pixels\n * @returns Date calculated from pixel position\n */\nexport const pixelsToDate = (pixels: number, monthStart: Date, dayWidth: number): Date => {\n const days = Math.round(pixels / dayWidth);\n return new Date(Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate() + days\n ));\n};\n\n/**\n * Calculate total width for month grid\n * @param daysInMonth - Number of days in the month\n * @param dayWidth - Width of each day in pixels\n * @returns Total grid width in pixels\n */\nexport const calculateGridWidth = (daysInMonth: number, dayWidth: number): number => {\n return Math.round(daysInMonth * dayWidth);\n};\n\n/**\n * Detect which edge zone the cursor is in on a task bar\n * @param clientX - Mouse X coordinate relative to viewport\n * @param taskBarElement - The task bar DOM element\n * @param edgeZoneWidth - Width of edge zones in pixels (default: 12px)\n * @returns 'left' if in left edge, 'right' if in right edge, 'move' if in middle\n */\nexport const detectEdgeZone = (\n clientX: number,\n taskBarElement: HTMLElement,\n edgeZoneWidth: number = 12\n): 'left' | 'right' | 'move' => {\n const rect = taskBarElement.getBoundingClientRect();\n const relativeX = Math.round(clientX - rect.left);\n const width = Math.round(rect.width);\n\n // When zones overlap (width <= 2 * edgeZoneWidth), prefer the closer edge\n if (width <= 2 * edgeZoneWidth) {\n // Cursor is in overlapping edge zone, return closer edge\n const distanceToLeft = relativeX;\n const distanceToRight = width - relativeX;\n return distanceToLeft <= distanceToRight ? 'left' : 'right';\n }\n\n // Check left edge zone\n if (relativeX >= 0 && relativeX <= edgeZoneWidth) {\n return 'left';\n }\n\n // Check right edge zone\n if (relativeX >= width - edgeZoneWidth && relativeX <= width) {\n return 'right';\n }\n\n // Middle area - move mode\n return 'move';\n};\n\n/**\n * Get appropriate cursor style for drag position\n * @param position - The drag position (left edge, right edge, or move)\n * @returns CSS cursor string for the position\n */\nexport const getCursorForPosition = (position: 'left' | 'right' | 'move'): string => {\n switch (position) {\n case 'left':\n case 'right':\n return 'ew-resize';\n case 'move':\n return 'grab';\n default:\n return 'default';\n }\n};\n\n/**\n * Calculate grid line positions for a date range\n * @param dateRange - Array of Date objects representing the visible range\n * @param dayWidth - Width of each day column in pixels\n * @returns Array of grid line objects with x position and flags\n */\nexport const calculateGridLines = (\n dateRange: Date[],\n dayWidth: number\n): Array<{ x: number; isMonthStart: boolean; isWeekStart: boolean }> => {\n const lines: Array<{ x: number; isMonthStart: boolean; isWeekStart: boolean }> = [];\n\n for (let i = 0; i < dateRange.length; i++) {\n const date = dateRange[i];\n const x = Math.round(i * dayWidth);\n const isMonthStart = i === 0 ? false : date.getUTCDate() === 1;\n const isWeekStart = date.getUTCDay() === 1; // Monday\n\n lines.push({ x, isMonthStart, isWeekStart });\n }\n\n // Add final line at the end of the range\n if (dateRange.length > 0) {\n lines.push({\n x: Math.round(dateRange.length * dayWidth),\n isMonthStart: false,\n isWeekStart: false\n });\n }\n\n return lines;\n};\n\n/**\n * Calculate weekend background blocks for a date range\n * @param dateRange - Array of Date objects representing the visible range\n * @param dayWidth - Width of each day column in pixels\n * @param isCustomWeekend - Optional predicate for custom weekend logic (e.g., holidays, shift patterns)\n * @returns Array of weekend block objects with left position and width\n *\n * Example:\n * // Default behavior (Saturday/Sunday)\n * calculateWeekendBlocks(dateRange, dayWidth)\n *\n * // Custom weekends (holidays, shifted workdays)\n * const isCustomWeekend = createIsWeekendPredicate({\n * weekends: [new Date(Date.UTC(2026, 2, 8))], // March 8 holiday\n * workdays: [new Date(Date.UTC(2026, 2, 15))] // March 15 workday\n * });\n * calculateWeekendBlocks(dateRange, dayWidth, isCustomWeekend)\n */\nexport const calculateWeekendBlocks = (\n dateRange: Date[],\n dayWidth: number,\n isCustomWeekend?: (date: Date) => boolean\n): Array<{ left: number; width: number }> => {\n const blocks: Array<{ left: number; width: number }> = [];\n let inWeekend = false;\n let weekendStartIndex = -1;\n\n for (let i = 0; i < dateRange.length; i++) {\n const date = dateRange[i];\n // Use custom predicate if provided, otherwise default Saturday/Sunday\n const isWeekend = isCustomWeekend\n ? isCustomWeekend(date)\n : date.getUTCDay() === 0 || date.getUTCDay() === 6;\n\n if (isWeekend && !inWeekend) {\n // Start of a weekend block\n inWeekend = true;\n weekendStartIndex = i;\n } else if (!isWeekend && inWeekend) {\n // End of a weekend block\n inWeekend = false;\n const left = Math.round(weekendStartIndex * dayWidth);\n const width = Math.round((i - weekendStartIndex) * dayWidth);\n blocks.push({ left, width });\n }\n }\n\n // Handle case where range ends on a weekend\n if (inWeekend && weekendStartIndex >= 0) {\n const left = Math.round(weekendStartIndex * dayWidth);\n const width = Math.round((dateRange.length - weekendStartIndex) * dayWidth);\n blocks.push({ left, width });\n }\n\n return blocks;\n};\n\n/**\n * Calculate SVG cubic Bezier curve path for dependency lines\n * @param from - Start point {x, y} (right edge of predecessor)\n * @param to - End point {x, y} (left edge of successor)\n * @returns SVG path string for cubic Bezier curve\n */\nexport const calculateBezierPath = (\n from: { x: number; y: number },\n to: { x: number; y: number }\n): string => {\n // Control points create smooth vertical curve\n // Offset is proportional to vertical distance for natural-looking curves\n const verticalDistance = Math.abs(to.y - from.y);\n const cpOffset = Math.max(verticalDistance * 0.5, 20); // Minimum 20px for same-row connections\n\n // For same-row connections, use arc above the task bars\n if (from.y === to.y) {\n const arcHeight = 20;\n const midX = (from.x + to.x) / 2;\n return `M ${from.x} ${from.y} Q ${midX} ${from.y - arcHeight} ${to.x} ${to.y}`;\n }\n\n // Standard cubic Bezier for multi-row connections\n const cp1x = from.x;\n const cp1y = from.y + (to.y > from.y ? cpOffset : -cpOffset);\n const cp2x = to.x;\n const cp2y = to.y - (to.y > from.y ? cpOffset : -cpOffset);\n\n return `M ${Math.round(from.x)} ${Math.round(from.y)} C ${Math.round(cp1x)} ${Math.round(cp1y)}, ${Math.round(cp2x)} ${Math.round(cp2y)}, ${Math.round(to.x)} ${Math.round(to.y)}`;\n};\n\n/**\n * Calculate SVG path for dependency lines based on link type connection semantics.\n *\n * Connection points per link type:\n * - FS: predecessor RIGHT → successor LEFT (arrow points right, enters left edge)\n * - SS: predecessor LEFT → successor LEFT (arrow points right, enters left edge)\n * - FF: predecessor RIGHT → successor RIGHT (arrow points left, enters right edge)\n * - SF: predecessor LEFT → successor RIGHT (arrow points left, enters right edge)\n *\n * @param from - Start point {x, y}\n * @param to - End point {x, y}\n * @param arrivesFromRight - true for FF and SF (arrow enters right edge of successor)\n */\nexport const calculateDependencyPath = (\n from: { x: number; y: number },\n to: { x: number; y: number },\n arrivesFromRight: boolean\n): string => {\n const fx = Math.round(from.x);\n const fy = Math.round(from.y);\n const tx = Math.round(to.x);\n const ty = Math.round(to.y);\n\n // Same row: straight horizontal line\n if (fy === ty) {\n return `M ${fx} ${fy} H ${tx}`;\n }\n\n const C = 2; // chamfer size\n const goingDown = ty > fy;\n const dirY = goingDown ? 1 : -1;\n\n if (arrivesFromRight) {\n // Arrow arrives at the RIGHT edge of successor (FF, SF).\n // Same chamfer formula as the FS/SS branch: stop C short of tx in the direction of travel,\n // then diagonal to tx, then vertical. The endpoints differ (right edge vs left edge),\n // but the path shape — natural inside-corner chamfer — is identical.\n const goingRight = tx >= fx;\n const dirX = goingRight ? 1 : -1;\n\n if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {\n return [\n `M ${fx} ${fy}`,\n `H ${tx - dirX * C}`,\n `L ${tx} ${fy + dirY * C}`,\n `V ${ty}`,\n ].join(' ');\n }\n return `M ${fx} ${fy} H ${tx} V ${ty}`;\n } else {\n // Arrow arrives at the LEFT edge of successor (FS, SS) — same as existing calculateOrthogonalPath\n const goingRight = tx >= fx;\n const dirX = goingRight ? 1 : -1;\n\n if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {\n return [\n `M ${fx} ${fy}`,\n `H ${tx - dirX * C}`,\n `L ${tx} ${fy + dirY * C}`,\n `V ${ty}`,\n ].join(' ');\n }\n return `M ${fx} ${fy} H ${tx} V ${ty}`;\n }\n};\n\n/**\n * Calculate grid line positions for week-view mode.\n * Lines appear at every 7-day boundary (each week column edge).\n * Month boundaries are always rendered at the exact day position (day 1 of a new month),\n * even when the boundary falls in the middle of a week column.\n * No day-level lines; no weekend blocks.\n *\n * @param dateRange - Array of Date objects (from getMultiMonthDays, day-based)\n * @param dayWidth - Width of each day in pixels\n * @returns Array of grid line objects sorted by x position\n */\nexport const calculateWeekGridLines = (\n dateRange: Date[],\n dayWidth: number\n): Array<{ x: number; isMonthStart: boolean }> => {\n // Import getWeekBlocks locally to avoid circular dependency\n const { getWeekBlocks } = require('./dateUtils');\n const blocks = getWeekBlocks(dateRange);\n\n const lines: Array<{ x: number; isMonthStart: boolean }> = [];\n let currentDayIndex = 0;\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n currentDayIndex += block.days;\n\n // Check if this block boundary is also a month boundary\n const blockEndMonth = dateRange[currentDayIndex - 1];\n const nextBlockMonth = currentDayIndex < dateRange.length\n ? dateRange[currentDayIndex]\n : null;\n\n const isMonthBoundary = nextBlockMonth &&\n blockEndMonth.getUTCMonth() !== nextBlockMonth.getUTCMonth();\n\n lines.push({\n x: Math.round(currentDayIndex * dayWidth),\n isMonthStart: isMonthBoundary || false,\n });\n }\n\n // Remove the last line if it's at the right edge (duplicates grid border)\n if (lines.length > 0 && lines[lines.length - 1].x === Math.round(dateRange.length * dayWidth)) {\n lines.pop();\n }\n\n return lines;\n};\n\n/**\n * Calculate grid line positions for month-view mode.\n * Thin line (isMonthStart=false) at each month boundary (1st of every month).\n * Thick line (isMonthStart=true) at each year boundary (1st of January).\n * No day-level or week-level lines.\n *\n * @param dateRange - Array of Date objects (from getMultiMonthDays)\n * @param dayWidth - Width of each day in pixels\n * @returns Array of grid line objects sorted by x position\n */\nexport const calculateMonthGridLines = (\n dateRange: Date[],\n dayWidth: number\n): Array<{ x: number; isMonthStart: boolean }> => {\n const lines: Array<{ x: number; isMonthStart: boolean }> = [];\n\n for (let i = 1; i < dateRange.length; i++) {\n const date = dateRange[i];\n // Линия только на 1-м числе месяца\n if (date.getUTCDate() === 1) {\n const x = Math.round(i * dayWidth);\n // Толстая линия на 1 января (граница года)\n const isYearBoundary = date.getUTCMonth() === 0;\n lines.push({ x, isMonthStart: isYearBoundary });\n }\n }\n\n return lines;\n};\n\n/**\n * Calculate SVG Г-shaped (L-shaped) path for FS dependency lines.\n * Goes vertically from the right edge of the predecessor bar, then horizontally\n * to the left edge of the successor bar. Supports negative lag (overlap).\n * @param from - Start point {x, y} (right edge of predecessor, vertical center)\n * @param to - End point {x, y} (left edge of successor, vertical center)\n * @returns SVG path string\n */\nexport const calculateOrthogonalPath = (\n from: { x: number; y: number },\n to: { x: number; y: number }\n): string => {\n const fx = Math.round(from.x);\n const fy = Math.round(from.y);\n const tx = Math.round(to.x);\n const ty = Math.round(to.y);\n\n // Same row: straight horizontal line\n if (fy === ty) {\n return `M ${fx} ${fy} H ${tx}`;\n }\n\n const C = 2; // chamfer size\n const goingDown = ty > fy;\n const goingRight = tx >= fx;\n const dirY = goingDown ? 1 : -1;\n const dirX = goingRight ? 1 : -1;\n\n // Shape: horizontal exit → chamfer → vertical arrival (arrow points down/up)\n if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {\n return [\n `M ${fx} ${fy}`,\n `H ${tx - dirX * C}`,\n `L ${tx} ${fy + dirY * C}`,\n `V ${ty}`,\n ].join(' ');\n }\n\n // Sharp corner fallback (very short segments)\n return `M ${fx} ${fy} H ${tx} V ${ty}`;\n};\n","import type { Task } from '../types';\nimport { parseUTCDate } from './dateUtils';\n\n/**\n * Checks whether a task is behind the expected progress for the current date.\n * Uses the same progress-based rule as expired task highlighting in TaskRow.\n */\nexport const isTaskExpired = (\n task: Task | undefined,\n referenceDate: Date = new Date(),\n): boolean => {\n if (!task) return false;\n\n const actualProgress = task.progress ?? 0;\n if (actualProgress >= 100) return false;\n\n // Align the day boundary to local time, then compare using UTC-safe task dates.\n const today = new Date(Date.UTC(\n referenceDate.getFullYear(),\n referenceDate.getMonth(),\n referenceDate.getDate(),\n ));\n\n const taskStart = parseUTCDate(task.startDate);\n const taskEnd = parseUTCDate(task.endDate);\n\n const msPerDay = 1000 * 60 * 60 * 24;\n const duration = taskEnd.getTime() - taskStart.getTime() + msPerDay;\n const elapsedFromToday = today.getTime() - taskStart.getTime();\n const elapsed = Math.min(Math.max(0, elapsedFromToday), duration);\n const expectedProgress = (elapsed / duration) * 100;\n\n return actualProgress < expectedProgress;\n};\n","'use client';\n\nimport { useEffect, useRef, useState, useCallback } from 'react';\nimport { detectEdgeZone } from '../utils/geometry';\nimport type { Task, TaskDependency, LinkType } from '../types';\nimport { calculateSuccessorDate, getTransitiveCascadeChain, recalculateIncomingLags, getChildren, isTaskParent, universalCascade } from '../utils/dependencyUtils';\n\n/**\n * Get transitive closure of successors for cascading.\n *\n * For proper cascading in mixed link type chains (e.g., A--FS-->B--SS-->C),\n * we need to include cascaded tasks' successors regardless of link type.\n *\n * The chain is:\n * 1. Direct successors of the dragged task, filtered by firstLevelLinkTypes\n * 2. ALL successors (any type) of those tasks, recursively\n *\n * @param draggedTaskId - ID of the task being dragged\n * @param allTasks - All tasks in the chart\n * @param firstLevelLinkTypes - Link types to use for direct successors\n * @returns Array of tasks in the cascade chain (transitive closure)\n */\n/**\n * Global drag manager that persists across HMR\n *\n * This singleton manages active drag operations at the module level,\n * ensuring that drag state survives React Fast Refresh (HMR).\n *\n * The key insight: When HMR occurs during a drag operation:\n * 1. The component unmounts and its useEffect cleanup removes window listeners\n * 2. The component remounts with fresh refs (isDraggingRef = false)\n * 3. But the user is still holding the mouse button!\n * 4. Without module-level state, the drag operation is orphaned\n *\n * Solution: Store active drag state in module-level singleton and\n * use a global cleanup effect to always handle mouseup/mousemove.\n */\ninterface ActiveDragState {\n taskId: string;\n mode: 'move' | 'resize-left' | 'resize-right';\n startX: number;\n initialLeft: number;\n initialWidth: number;\n currentLeft: number;\n currentWidth: number;\n dayWidth: number;\n monthStart: Date;\n onProgress: (left: number, width: number) => void;\n onComplete: (finalLeft: number, finalWidth: number) => void;\n onCancel: () => void;\n allTasks: Task[];\n disableConstraints?: boolean;\n cascadeChain: Task[]; // FS+SS+FF+SF successors of dragged task (Phase 10: added SF)\n cascadeChainFS: Task[]; // FS-only successors (part of resize-right cascade with FF)\n cascadeChainStart: Task[]; // SS+SF successors (resize-left cascade) - Phase 10: renamed from cascadeChainSS\n cascadeChainEnd: Task[]; // FS+FF successors (resize-right cascade) - Phase 9\n hierarchyChain: Task[]; // Phase 19: children of parent task (for cascade drag)\n onCascadeProgress?: (overrides: Map<string, { left: number; width: number }>) => void;\n}\n\nlet globalActiveDrag: ActiveDragState | null = null;\nlet globalRafId: number | null = null;\n\n/**\n * Complete the active drag operation\n */\nfunction completeDrag() {\n if (globalRafId !== null) {\n cancelAnimationFrame(globalRafId);\n globalRafId = null;\n }\n\n if (globalActiveDrag) {\n // Clear cascade overrides before completing (avoids stale preview positions)\n globalActiveDrag.onCascadeProgress?.(new Map());\n const { onComplete, currentLeft, currentWidth } = globalActiveDrag;\n globalActiveDrag = null;\n onComplete(currentLeft, currentWidth);\n }\n}\n\n/**\n * Cancel the active drag operation\n */\nfunction cancelDrag() {\n if (globalRafId !== null) {\n cancelAnimationFrame(globalRafId);\n globalRafId = null;\n }\n\n if (globalActiveDrag) {\n const { onCancel } = globalActiveDrag;\n globalActiveDrag = null;\n onCancel();\n }\n}\n\n/**\n * Snap pixel value to grid (day boundaries)\n */\nfunction snapToGrid(pixels: number, dayWidth: number): number {\n return Math.round(pixels / dayWidth) * dayWidth;\n}\n\n/**\n * Check if a task move would violate dependency constraints\n * Only blocks move operations, not resize (per requirements)\n */\nfunction canMoveTask(\n task: Task,\n newStartDate: Date,\n newEndDate: Date,\n allTasks: Task[]\n): { allowed: boolean; reason?: string } {\n if (!task.dependencies || task.dependencies.length === 0) {\n return { allowed: true };\n }\n\n // For each predecessor, check if the new position respects the constraint\n for (const dep of task.dependencies) {\n const predecessor = allTasks.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n\n const predecessorStart = new Date(predecessor.startDate);\n const predecessorEnd = new Date(predecessor.endDate);\n\n // Calculate expected date based on link type (lag ignored, always 0)\n const expectedDate = calculateSuccessorDate(\n predecessorStart,\n predecessorEnd,\n dep.type,\n 0 // lag not used in calculations\n );\n\n // Check constraint based on link type\n const targetIsStart = dep.type.endsWith('S');\n const targetDate = targetIsStart ? newStartDate : newEndDate;\n\n // Allow move if target date is on or after expected date\n // (give 1-day tolerance for rounding)\n const dayDiff = (targetDate.getTime() - expectedDate.getTime()) / (24 * 60 * 60 * 1000);\n\n if (dayDiff < -1) {\n return {\n allowed: false,\n reason: `Would violate ${dep.type} dependency from \"${predecessor.name}\"`\n };\n }\n }\n\n return { allowed: true };\n}\n\n/**\n * Recalculate lag values for incoming dependencies after drag completion.\n *\n * Lag formulas:\n * - FS: lag = startB - endA (can be negative)\n * - SS: lag = startB - startA (floor at 0)\n * - FF: lag = endB - endA (can be negative)\n * - SF: lag = endB - startA (ceiling at 0)\n */\n/**\n * Global mouse move handler - attached once and persists across HMR\n */\nfunction handleGlobalMouseMove(e: MouseEvent) {\n if (!globalActiveDrag || globalRafId !== null) {\n return;\n }\n\n globalRafId = requestAnimationFrame(() => {\n if (!globalActiveDrag) {\n globalRafId = null;\n return;\n }\n\n const activeDrag = globalActiveDrag;\n\n const { startX, initialLeft, initialWidth, mode, dayWidth, onProgress, allTasks } = activeDrag;\n const deltaX = e.clientX - startX;\n\n let newLeft = initialLeft;\n let newWidth = initialWidth;\n\n switch (mode) {\n case 'move':\n newLeft = snapToGrid(initialLeft + deltaX, dayWidth);\n break;\n case 'resize-left':\n const snappedLeft = snapToGrid(initialLeft + deltaX, dayWidth);\n newLeft = snappedLeft;\n const rightEdge = initialLeft + initialWidth;\n newWidth = Math.max(dayWidth, rightEdge - snappedLeft);\n break;\n case 'resize-right':\n const snappedWidth = snapToGrid(initialWidth + deltaX, dayWidth);\n newWidth = Math.max(dayWidth, snappedWidth);\n break;\n }\n\n // Hard mode: check left-move boundary against predecessor.startDate (Phase 7)\n // Child can move left until its startDate would go before predecessor.startDate\n // Also applies to resize-left: the left edge cannot cross the predecessor's start date\n if ((mode === 'move' || mode === 'resize-left') && allTasks.length > 0 && !activeDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === activeDrag.taskId);\n if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {\n let minAllowedLeft = -Infinity; // in pixels from monthStart; -Infinity means no floor unless a real FS/SS predecessor sets one\n for (const dep of currentTask.dependencies) {\n if (dep.type !== 'FS' && dep.type !== 'SS') continue; // Phase 8: FS and SS\n const predecessor = activeDrag.allTasks.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n // Boundary: child.startDate >= predecessor.startDate (allows negative lag)\n const predStart = new Date(predecessor.startDate as string);\n const predStartOffset = Math.round(\n (Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) -\n Date.UTC(\n activeDrag.monthStart.getUTCFullYear(),\n activeDrag.monthStart.getUTCMonth(),\n activeDrag.monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * activeDrag.dayWidth);\n minAllowedLeft = Math.max(minAllowedLeft, predStartLeft);\n }\n // Clamp: don't let task go left of boundary\n newLeft = Math.max(minAllowedLeft, newLeft);\n }\n // For resize-left, after clamping newLeft the right edge is fixed so newWidth must be recomputed\n if (mode === 'resize-left') {\n const rightEdge = activeDrag.initialLeft + activeDrag.initialWidth;\n newWidth = Math.max(activeDrag.dayWidth, rightEdge - newLeft);\n }\n }\n\n // Phase 10: SF constraint: endB <= startA (lag ceiling at 0)\n // Applies when B is moved right or resized-right\n if ((mode === 'move' || mode === 'resize-right') && allTasks.length > 0 && !activeDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === activeDrag.taskId);\n if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {\n for (const dep of currentTask.dependencies) {\n if (dep.type !== 'SF') continue;\n const predecessor = activeDrag.allTasks.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n const predStart = new Date(predecessor.startDate as string);\n const predStartOffset = Math.round(\n (Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) -\n Date.UTC(activeDrag.monthStart.getUTCFullYear(), activeDrag.monthStart.getUTCMonth(), activeDrag.monthStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * activeDrag.dayWidth);\n\n // SF lag=0 boundary: B's visual end = day before A's start (adjacent = lag 0)\n // B.right (exclusive pixel) = predStartLeft at lag=0\n const sfBoundaryRight = predStartLeft;\n if (mode === 'move') {\n // Move mode: when B would hit startA constraint, stop movement entirely\n const proposedEndRight = newLeft + activeDrag.initialWidth;\n if (proposedEndRight > sfBoundaryRight) {\n newLeft = Math.max(activeDrag.initialLeft, sfBoundaryRight - activeDrag.initialWidth);\n }\n } else {\n // Resize-right mode: clamp width so endB = startA (lag=0)\n const currentEndRight = newLeft + newWidth;\n if (currentEndRight > sfBoundaryRight) {\n newWidth = Math.max(activeDrag.dayWidth, sfBoundaryRight - newLeft);\n }\n }\n }\n }\n }\n\n const draggedTask = allTasks.find(t => t.id === activeDrag.taskId);\n\n // ── Universal preview cascade ──────────────────────────────────────────\n // Same algorithm as handleComplete — converts pixels→dates, runs\n // universalCascade, converts dates→pixels for overrides.\n\n // Universal preview: convert pixels → dates → universalCascade → pixels\n if (!activeDrag.disableConstraints && activeDrag.onCascadeProgress) {\n const { dayWidth, monthStart: mStart, taskId: dragId } = activeDrag;\n const previewStartDay = Math.round(newLeft / dayWidth);\n const previewEndDay = previewStartDay + Math.round(newWidth / dayWidth) - 1;\n const previewStartDate = new Date(Date.UTC(\n mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate() + previewStartDay\n ));\n const previewEndDate = new Date(Date.UTC(\n mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate() + previewEndDay\n ));\n\n const movedTaskData = draggedTask ?? { id: dragId, name: '', startDate: '', endDate: '' };\n const cascadeResult = universalCascade(\n { ...movedTaskData, startDate: previewStartDate.toISOString(), endDate: previewEndDate.toISOString() },\n previewStartDate,\n previewEndDate,\n allTasks\n );\n\n // Convert cascaded tasks → pixel overrides\n const overrides = new Map<string, { left: number; width: number }>();\n // Always include the dragged task itself\n overrides.set(dragId, { left: newLeft, width: newWidth });\n\n for (const task of cascadeResult) {\n if (task.id === dragId) continue;\n const taskStart = new Date(task.startDate as string);\n const taskEnd = new Date(task.endDate as string);\n const startOff = Math.round(\n (Date.UTC(taskStart.getUTCFullYear(), taskStart.getUTCMonth(), taskStart.getUTCDate()) -\n Date.UTC(mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n const endOff = Math.round(\n (Date.UTC(taskEnd.getUTCFullYear(), taskEnd.getUTCMonth(), taskEnd.getUTCDate()) -\n Date.UTC(mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n overrides.set(task.id, {\n left: Math.round(startOff * dayWidth),\n width: Math.round((endOff - startOff + 1) * dayWidth),\n });\n }\n\n activeDrag.onCascadeProgress(overrides);\n }\n\n // Update current values in global state for completion\n activeDrag.currentLeft = newLeft;\n activeDrag.currentWidth = newWidth;\n\n onProgress(newLeft, newWidth);\n globalRafId = null;\n });\n}\n\n/**\n * Global mouse up handler - attached once and persists across HMR\n */\nfunction handleGlobalMouseUp() {\n if (globalActiveDrag) {\n completeDrag();\n }\n}\n\n/**\n * Track whether global listeners are attached\n */\nlet globalListenersAttached = false;\n\n/**\n * Ensure global listeners are attached (idempotent)\n */\nfunction ensureGlobalListeners() {\n if (!globalListenersAttached) {\n window.addEventListener('mousemove', handleGlobalMouseMove);\n window.addEventListener('mouseup', handleGlobalMouseUp);\n globalListenersAttached = true;\n }\n}\n\n/**\n * Cleanup global listeners - called when no components are using drag\n * Note: In practice with HMR, we keep these attached for safety\n */\nfunction cleanupGlobalListeners() {\n // We keep global listeners attached to handle orphaned drags after HMR\n // They will be cleaned up when the page is refreshed\n}\n\n/**\n * Options for useTaskDrag hook\n */\nexport interface UseTaskDragOptions {\n /** Unique identifier for the task */\n taskId: string;\n /** Initial start date of the task */\n initialStartDate: Date;\n /** Initial end date of the task */\n initialEndDate: Date;\n /** Start of the visible range (e.g., month start) */\n monthStart: Date;\n /** Width of each day in pixels */\n dayWidth: number;\n /** Callback when drag operation completes */\n onDragEnd?: (result: { id: string; startDate: Date; endDate: Date; updatedDependencies?: Task['dependencies'] }) => void;\n /** Callback for drag state changes (for parent components to render guide lines) */\n onDragStateChange?: (state: {\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n }) => void;\n /** Width of edge zones for resize detection (default: 12px) */\n edgeZoneWidth?: number;\n /** Array of all tasks for dependency validation */\n allTasks?: Task[];\n /** Row index of this task (for task lookup) */\n rowIndex?: number;\n /** Enable automatic scheduling of dependent tasks */\n enableAutoSchedule?: boolean;\n /** When true, dependency constraint checking is skipped during drag (default: false) */\n disableConstraints?: boolean;\n /** Callback for real-time cascade preview — called each RAF with non-dragged chain member positions */\n onCascadeProgress?: (overrides: Map<string, { left: number; width: number }>) => void;\n /** Callback when cascade completes — receives all shifted tasks including dragged task */\n onCascade?: (tasks: Task[]) => void;\n /** When true, all drag and resize interactions are disabled for this task */\n locked?: boolean;\n}\n\n/**\n * Return value from useTaskDrag hook\n */\nexport interface UseTaskDragReturn {\n /** Whether a drag operation is in progress */\n isDragging: boolean;\n /** Current drag mode (null when not dragging) */\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n /** Current left position in pixels (updated during drag) */\n currentLeft: number;\n /** Current width in pixels (updated during drag) */\n currentWidth: number;\n /** Props to spread on the drag handle element */\n dragHandleProps: {\n onMouseDown: (e: React.MouseEvent) => void;\n style: React.CSSProperties;\n };\n}\n\n/**\n * Custom hook for managing task drag interactions\n *\n * HMR-SAFE: Uses module-level singleton to ensure drag state survives\n * React Fast Refresh. Window event listeners are attached once at module\n * level rather than per component instance.\n */\nexport const useTaskDrag = (options: UseTaskDragOptions): UseTaskDragReturn => {\n const {\n taskId,\n initialStartDate,\n initialEndDate,\n monthStart,\n dayWidth,\n onDragEnd,\n onDragStateChange,\n edgeZoneWidth = 12,\n allTasks = [],\n rowIndex,\n enableAutoSchedule = false,\n disableConstraints = false,\n onCascadeProgress,\n onCascade,\n } = options;\n\n // Track if this hook instance owns the current global drag\n const isOwnerRef = useRef<boolean>(false);\n const locked = options.locked ?? false;\n\n // Display state (triggers re-renders only when needed)\n const [isDragging, setIsDragging] = useState<boolean>(false);\n const [dragMode, setDragMode] = useState<'move' | 'resize-left' | 'resize-right' | null>(null);\n const [currentLeft, setCurrentLeft] = useState<number>(0);\n const [currentWidth, setCurrentWidth] = useState<number>(0);\n\n /**\n * Calculate initial pixel position from dates\n */\n const getInitialPosition = useCallback((): { left: number; width: number } => {\n const getUTCDayDifference = (date1: Date, date2: Date): number => {\n const ms1 = Date.UTC(\n date1.getUTCFullYear(),\n date1.getUTCMonth(),\n date1.getUTCDate()\n );\n const ms2 = Date.UTC(\n date2.getUTCFullYear(),\n date2.getUTCMonth(),\n date2.getUTCDate()\n );\n return Math.round((ms1 - ms2) / (1000 * 60 * 60 * 24));\n };\n\n const startOffset = getUTCDayDifference(initialStartDate, monthStart);\n const duration = getUTCDayDifference(initialEndDate, initialStartDate);\n\n const left = Math.round(startOffset * dayWidth);\n const width = Math.round((duration + 1) * dayWidth); // +1 to include end date\n\n return { left, width };\n }, [initialStartDate, initialEndDate, monthStart, dayWidth]);\n\n /**\n * Initialize position when dates or dayWidth changes.\n * Skipped when this instance owns an active drag to avoid overriding drag state.\n */\n useEffect(() => {\n if (isOwnerRef.current && globalActiveDrag) return;\n const { left, width } = getInitialPosition();\n setCurrentLeft(left);\n setCurrentWidth(width);\n }, [getInitialPosition]);\n\n /**\n * When monthStart changes during an active drag (e.g. a month is prepended),\n * the pixel coordinate origin shifts. Adjust globalActiveDrag so that\n * subsequent move calculations stay in the new coordinate space.\n */\n useEffect(() => {\n if (!isOwnerRef.current || !globalActiveDrag) return;\n const oldMonthStart = globalActiveDrag.monthStart;\n if (oldMonthStart === monthStart) return;\n const daysShift = Math.round(\n (Date.UTC(oldMonthStart.getUTCFullYear(), oldMonthStart.getUTCMonth(), oldMonthStart.getUTCDate()) -\n Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), monthStart.getUTCDate())) /\n (1000 * 60 * 60 * 24)\n );\n const pixelShift = daysShift * dayWidth;\n globalActiveDrag.initialLeft += pixelShift;\n globalActiveDrag.currentLeft += pixelShift;\n globalActiveDrag.monthStart = monthStart;\n }, [monthStart, dayWidth]);\n\n /**\n * Handle drag progress callback from global manager\n */\n const handleProgress = useCallback((left: number, width: number) => {\n setCurrentLeft(left);\n setCurrentWidth(width);\n\n if (onDragStateChange && isOwnerRef.current) {\n const mode = globalActiveDrag?.mode || null;\n onDragStateChange({\n isDragging: true,\n dragMode: mode,\n left,\n width,\n });\n }\n }, [onDragStateChange]);\n\n /**\n * Handle drag completion from global manager\n */\n const handleComplete = useCallback((finalLeft: number, finalWidth: number) => {\n const wasOwner = isOwnerRef.current;\n isOwnerRef.current = false;\n\n // Calculate new dates from final pixel values\n const dayOffset = Math.round(finalLeft / dayWidth);\n const durationDays = Math.round(finalWidth / dayWidth) - 1; // -1 because width includes end date\n\n const newStartDate = new Date(Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate() + dayOffset\n ));\n\n const newEndDate = new Date(Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate() + dayOffset + durationDays\n ));\n\n // Reset local state\n setIsDragging(false);\n setDragMode(null);\n\n // Notify parent of drag end\n if (onDragStateChange) {\n onDragStateChange({\n isDragging: false,\n dragMode: null,\n left: finalLeft,\n width: finalWidth,\n });\n }\n\n if (wasOwner) {\n if (!disableConstraints && onCascade && allTasks.length > 0) {\n // Hard mode with onCascade: use universalCascade for all cases\n // (parent drag, child drag, root task drag — all handled uniformly)\n const draggedTaskData = allTasks.find(t => t.id === taskId);\n\n const movedTask: Task = {\n ...(draggedTaskData ?? { id: taskId, name: '', startDate: '', endDate: '' }),\n startDate: newStartDate.toISOString(),\n endDate: newEndDate.toISOString(),\n ...(draggedTaskData?.dependencies && {\n dependencies: recalculateIncomingLags(draggedTaskData, newStartDate, newEndDate, allTasks),\n }),\n };\n\n const cascadeResult = universalCascade(movedTask, newStartDate, newEndDate, allTasks);\n\n if (cascadeResult.length > 0) {\n onCascade([movedTask, ...cascadeResult]);\n return; // Don't call onDragEnd — cascade covers the dragged task too\n }\n\n // No dependent tasks to cascade — still call onCascade with just the moved task\n // so the state update is consistent\n onCascade([movedTask]);\n return;\n }\n\n // Soft mode OR hard mode with no FS successors: call onDragEnd\n // Always recalculate lag so hard-mode drags (chain.length===0) also persist the new lag\n if (allTasks.length > 0 && onDragEnd) {\n const currentTaskData = allTasks.find(t => t.id === taskId);\n const updatedDependencies = currentTaskData?.dependencies\n ? recalculateIncomingLags(currentTaskData, newStartDate, newEndDate, allTasks)\n : undefined;\n onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate, updatedDependencies });\n } else if (onDragEnd) {\n onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate });\n }\n }\n }, [dayWidth, monthStart, onDragEnd, onDragStateChange, taskId, disableConstraints, onCascade, allTasks, initialStartDate, initialEndDate]);\n\n /**\n * Handle drag cancellation (e.g., if HMR orphaned the drag)\n */\n const handleCancel = useCallback(() => {\n isOwnerRef.current = false;\n setIsDragging(false);\n setDragMode(null);\n\n if (onDragStateChange) {\n onDragStateChange({\n isDragging: false,\n dragMode: null,\n left: currentLeft,\n width: currentWidth,\n });\n }\n }, [onDragStateChange, currentLeft, currentWidth]);\n\n /**\n * Cleanup on unmount - if this instance owns the drag, cancel it\n */\n useEffect(() => {\n return () => {\n if (isOwnerRef.current && globalActiveDrag) {\n // We're unmounting while owning the drag - cancel it\n cancelDrag();\n }\n };\n }, []);\n\n /**\n * Handle mouse down on drag handle\n */\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n // Phase 11: locked tasks cannot be dragged or resized\n if (locked) return;\n\n const target = e.currentTarget as HTMLElement;\n const edgeZone = detectEdgeZone(e.clientX, target, edgeZoneWidth);\n\n // Determine drag mode from edge zone\n let mode: 'move' | 'resize-left' | 'resize-right' | null = null;\n switch (edgeZone) {\n case 'left':\n mode = 'resize-left';\n break;\n case 'right':\n mode = 'resize-right';\n break;\n case 'move':\n mode = 'move';\n break;\n }\n\n // Phase 19: Parent tasks cannot be resized - their dates are computed from children\n // Force move mode for parent tasks to prevent resize operations\n if (mode === 'resize-left' || mode === 'resize-right') {\n const currentTask = allTasks.find(t => t.id === taskId);\n if (currentTask && isTaskParent(taskId, allTasks)) {\n mode = 'move';\n }\n }\n\n if (!mode) {\n return;\n }\n\n // Get current position from state (this is what we see on screen)\n const initialLeft = currentLeft;\n const initialWidth = currentWidth;\n\n // Mark this instance as the drag owner\n isOwnerRef.current = true;\n\n // Update display state\n setIsDragging(true);\n setDragMode(mode);\n\n // Notify parent of drag start\n if (onDragStateChange) {\n onDragStateChange({\n isDragging: true,\n dragMode: mode,\n left: initialLeft,\n width: initialWidth,\n });\n }\n\n // Ensure global listeners are attached (idempotent)\n ensureGlobalListeners();\n\n // Phase 19: Build hierarchy chain for real-time parent movement\n // When dragging a child: include parent so it moves with children\n // When dragging a parent: include all children so they move with parent\n const currentTask = allTasks.find(t => t.id === taskId);\n let hierarchyChain: Task[] = [];\n\n if (currentTask) {\n const taskParentId = (currentTask as any).parentId;\n if (taskParentId) {\n // Dragging a child - include parent for real-time updates\n const parentTask = allTasks.find(t => t.id === taskParentId);\n if (parentTask) {\n hierarchyChain.push(parentTask);\n }\n } else {\n // Dragging a parent - include all children\n hierarchyChain = getChildren(taskId, allTasks);\n }\n }\n\n // Store drag state in global singleton\n globalActiveDrag = {\n taskId,\n mode,\n startX: e.clientX,\n initialLeft,\n initialWidth,\n currentLeft: initialLeft, // Initially same as initial\n currentWidth: initialWidth, // Initially same as initial\n dayWidth,\n monthStart,\n onProgress: handleProgress,\n onComplete: handleComplete,\n onCancel: handleCancel,\n allTasks,\n disableConstraints,\n cascadeChain: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS', 'SS', 'FF', 'SF']) // all successors, used for move (Phase 10: added SF)\n : [],\n cascadeChainFS: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS']) // FS + transitive, used for resize-right\n : [],\n cascadeChainStart: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['SS', 'SF']) // SS + SF for resize-left cascade (Phase 10: renamed from cascadeChainSS)\n : [],\n cascadeChainEnd: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS', 'FF']) // FS + FF for resize-right cascade (Phase 9)\n : [],\n hierarchyChain, // Phase 19: children of parent task\n onCascadeProgress,\n };\n }, [edgeZoneWidth, currentLeft, currentWidth, dayWidth, monthStart, taskId, onDragStateChange, handleProgress, handleComplete, handleCancel, allTasks, disableConstraints, onCascadeProgress, onCascade, locked]);\n\n /**\n * Get cursor style based on current position\n */\n const getCursorStyle = useCallback((): string => {\n if (locked) return 'not-allowed';\n if (isDragging) {\n return 'grabbing';\n }\n return 'grab';\n }, [locked, isDragging]);\n\n return {\n isDragging,\n dragMode,\n currentLeft,\n currentWidth,\n dragHandleProps: {\n onMouseDown: handleMouseDown,\n style: {\n cursor: getCursorStyle(),\n userSelect: 'none',\n } as React.CSSProperties,\n },\n };\n};\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { getDayOffset } from '../../utils/dateUtils';\nimport './TodayIndicator.css';\n\nexport interface TodayIndicatorProps {\n /** Start of the month for positioning calculations */\n monthStart: Date;\n /** Width of each day column in pixels */\n dayWidth: number;\n}\n\n/**\n * TodayIndicator component - displays a vertical line at the current date\n *\n * Only renders when the current date is within the visible month range.\n * Satisfies REND-04 requirement for visual today indicator.\n */\nconst TodayIndicator: React.FC<TodayIndicatorProps> = ({ monthStart, dayWidth }) => {\n // Use local date for \"today\" (not UTC) - user's current date matters\n const today = new Date();\n const todayLocal = new Date(Date.UTC(\n today.getFullYear(),\n today.getMonth(),\n today.getDate()\n ));\n\n // Calculate position based on offset from monthStart\n // The parent GanttChart component handles the date range check via todayInRange\n const position = useMemo(() => {\n const offset = getDayOffset(todayLocal, monthStart);\n return Math.round(offset * dayWidth);\n }, [monthStart, dayWidth, todayLocal]);\n\n // Allow negative positions (today before monthStart) - parent handles visibility\n if (isNaN(position)) {\n return null;\n }\n\n return (\n <div\n className=\"gantt-ti-indicator\"\n style={{\n left: `${position}px`,\n width: 'var(--gantt-today-indicator-width)',\n backgroundColor: 'var(--gantt-today-indicator-color)',\n }}\n aria-label=\"Today\"\n />\n );\n};\n\nexport default TodayIndicator;\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { calculateGridLines, calculateWeekendBlocks, calculateWeekGridLines, calculateMonthGridLines } from '../../utils/geometry';\nimport type { GridLine } from '../../types';\nimport './GridBackground.css';\n\nexport interface GridBackgroundProps {\n /** Array of dates to display (from getMultiMonthDays) */\n dateRange: Date[];\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Total height of the grid area in pixels */\n totalHeight: number;\n /** View mode: 'day' renders per-day lines with weekend blocks, 'week' renders per-week lines only, 'month' renders per-month lines only */\n viewMode?: 'day' | 'week' | 'month';\n /** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */\n isCustomWeekend?: (date: Date) => boolean;\n}\n\n/**\n * Custom comparison function for React.memo\n *\n * Performance optimization: Re-renders when dateRange length, dayWidth, totalHeight, or viewMode change.\n * Returns true (skip re-render) only when all four are unchanged.\n */\nconst arePropsEqual = (prevProps: GridBackgroundProps, nextProps: GridBackgroundProps) => {\n return (\n prevProps.dayWidth === nextProps.dayWidth &&\n prevProps.dateRange.length === nextProps.dateRange.length &&\n prevProps.totalHeight === nextProps.totalHeight && // skip re-render only when totalHeight unchanged\n prevProps.viewMode === nextProps.viewMode &&\n prevProps.isCustomWeekend === nextProps.isCustomWeekend\n );\n};\n\n/**\n * GridBackground component - renders vertical grid lines and weekend background highlighting\n *\n * This component provides the visual grid structure that runs behind task rows.\n * It separates grid rendering from task rendering for better performance and cleaner code.\n *\n * Features:\n * - Vertical grid lines at month/week/day boundaries\n * - Pink background highlighting for weekend days (day-view only)\n * - React.memo optimization for performance\n * - Pointer events disabled (clicks pass through to tasks)\n *\n * View modes:\n * - day (default): per-day grid lines + weekend background blocks\n * - week: per-week grid lines only (no weekend blocks, lines every 7 days)\n */\nconst GridBackground: React.FC<GridBackgroundProps> = React.memo(\n ({ dateRange, dayWidth, totalHeight, viewMode = 'day', isCustomWeekend }) => {\n // Week-view: grid lines at each 7-day boundary\n const weekGridLines = useMemo(() => {\n if (viewMode !== 'week') return [];\n return calculateWeekGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth, viewMode]);\n\n // Day-view: grid line positions per day (existing logic)\n const gridLines = useMemo<GridLine[]>(() => {\n if (viewMode === 'week' || viewMode === 'month') return [];\n return calculateGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth, viewMode]);\n\n // Month-view: grid lines at each month/year boundary\n const monthGridLines = useMemo(() => {\n if (viewMode !== 'month') return [];\n return calculateMonthGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth, viewMode]);\n\n // Weekend background blocks: only in day-view (locked decision from RESEARCH.md)\n const weekendBlocks = useMemo(() => {\n if (viewMode === 'week' || viewMode === 'month') return []; // No weekend highlighting in week/month-view\n return calculateWeekendBlocks(dateRange, dayWidth, isCustomWeekend);\n }, [dateRange, dayWidth, viewMode, isCustomWeekend]);\n\n // Calculate total grid width (formula must not change — Pitfall 3)\n const gridWidth = useMemo(() => {\n return Math.round(dateRange.length * dayWidth);\n }, [dateRange.length, dayWidth]);\n\n return (\n <div\n className=\"gantt-gb-gridBackground\"\n style={{\n width: `${gridWidth}px`,\n height: `${totalHeight}px`,\n }}\n >\n {/* Weekend backgrounds (rendered first, behind lines) — day-view only */}\n {weekendBlocks.map((block, index) => (\n <div\n key={`weekend-${index}`}\n className=\"gantt-gb-weekendBlock\"\n style={{\n left: `${block.left}px`,\n width: `${block.width}px`,\n }}\n />\n ))}\n\n {/* Vertical grid lines */}\n {viewMode === 'week' ? (\n // Week-view: one line per week column boundary\n weekGridLines.map((line, index) => {\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : 'gantt-gb-weekSeparator';\n return (\n <div\n key={`wgridline-${index}`}\n className={`gantt-gb-gridLine ${lineClass}`}\n style={{ left: `${line.x}px` }}\n />\n );\n })\n ) : viewMode === 'month' ? (\n // Month-view: thin line at each month boundary, thick at year boundary\n monthGridLines.map((line, index) => {\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : 'gantt-gb-weekSeparator';\n return (\n <div\n key={`mgridline-${index}`}\n className={`gantt-gb-gridLine ${lineClass}`}\n style={{ left: `${line.x}px` }}\n />\n );\n })\n ) : (\n // Day-view: existing code (unchanged)\n gridLines.map((line, index) => {\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : line.isWeekStart\n ? 'gantt-gb-weekSeparator'\n : 'gantt-gb-dayLine';\n return (\n <div\n key={`gridline-${index}`}\n className={`gantt-gb-gridLine ${lineClass}`}\n style={{\n left: `${line.x}px`,\n }}\n />\n );\n })\n )}\n </div>\n );\n },\n arePropsEqual\n);\n\nGridBackground.displayName = 'GridBackground';\n\nexport default GridBackground;\n","'use client';\n\nimport React from 'react';\nimport './DragGuideLines.css';\n\nexport interface DragGuideLinesProps {\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n totalHeight: number;\n}\n\nconst DragGuideLines: React.FC<DragGuideLinesProps> = ({\n isDragging,\n dragMode,\n left,\n width,\n totalHeight,\n}) => {\n if (!isDragging || !dragMode) {\n return null;\n }\n\n // Determine which lines to show based on drag mode\n const showLeftLine = dragMode === 'move' || dragMode === 'resize-left';\n const showRightLine = dragMode === 'move' || dragMode === 'resize-right';\n\n return (\n <>\n {showLeftLine && (\n <div\n className=\"gantt-dgl-guideLine\"\n style={{\n left: `${left}px`,\n height: `${totalHeight}px`,\n }}\n />\n )}\n {showRightLine && (\n <div\n className=\"gantt-dgl-guideLine\"\n style={{\n left: `${left + width}px`,\n height: `${totalHeight}px`,\n }}\n />\n )}\n </>\n );\n};\n\nexport default DragGuideLines;\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { Task } from '../../types';\nimport { calculateTaskBar, calculateDependencyPath, pixelsToDate } from '../../utils/geometry';\nimport { getAllDependencyEdges, detectCycles, computeLagFromDates } from '../../utils/dependencyUtils';\nimport type { LinkType } from '../../types';\nimport './DependencyLines.css';\n\n/**\n * Calculate effective lag based on current task pixel positions.\n * Delegates to computeLagFromDates for consistent semantics.\n */\nfunction calculateEffectiveLag(\n edge: { type: string },\n predPosition: { left: number; right: number },\n succPosition: { left: number; right: number },\n monthStart: Date,\n dayWidth: number\n): number {\n const predStart = pixelsToDate(predPosition.left, monthStart, dayWidth);\n const predEnd = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);\n const succStart = pixelsToDate(succPosition.left, monthStart, dayWidth);\n const succEnd = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);\n return computeLagFromDates(edge.type as LinkType, predStart, predEnd, succStart, succEnd);\n}\n\n/**\n * Check if a task is hidden inside a collapsed parent.\n */\nfunction isTaskHidden(taskId: string, collapsedParentIds: Set<string>, taskMap: Map<string, Task>): boolean {\n const task = taskMap.get(taskId);\n if (!task || !task.parentId) return false;\n return collapsedParentIds.has(task.parentId);\n}\n\n/**\n * Find the nearest visible ancestor of a hidden task.\n * Returns the ancestor task or null if the task is visible.\n */\nfunction findVisibleAncestor(\n task: Task,\n collapsedParentIds: Set<string>,\n taskMap: Map<string, Task>\n): Task | null {\n if (!task.parentId) return null;\n if (collapsedParentIds.has(task.parentId)) {\n const parent = taskMap.get(task.parentId);\n if (!parent) return null;\n // Check if parent is also hidden\n if (parent.parentId && collapsedParentIds.has(parent.parentId)) {\n return findVisibleAncestor(parent, collapsedParentIds, taskMap);\n }\n return parent;\n }\n return null;\n}\n\n/**\n * Check if two tasks share the same collapsed parent ancestor.\n * If both predecessor and successor are hidden inside the same parent,\n * the dependency line should NOT be rendered (it's internal to the collapsed group).\n */\nfunction areBothHiddenInSameParent(\n predecessorId: string,\n successorId: string,\n collapsedParentIds: Set<string>,\n taskMap: Map<string, Task>\n): boolean {\n const predTask = taskMap.get(predecessorId);\n const succTask = taskMap.get(successorId);\n\n if (!predTask || !succTask) return false;\n\n // Both must have parentIds\n if (!predTask.parentId || !succTask.parentId) return false;\n\n // Find the visible ancestor (collapsed parent) for each\n const predVisibleAncestor = findVisibleAncestor(predTask, collapsedParentIds, taskMap);\n const succVisibleAncestor = findVisibleAncestor(succTask, collapsedParentIds, taskMap);\n\n // Both must be hidden (have visible ancestors)\n if (!predVisibleAncestor || !succVisibleAncestor) return false;\n\n // Check if they share the same collapsed parent\n return predVisibleAncestor.id === succVisibleAncestor.id;\n}\n\nexport interface DependencyLinesProps {\n /** Visible tasks only (for row calculation) */\n tasks: Task[];\n /** All tasks including hidden children (for virtual position calculation) */\n allTasks?: Task[];\n /** Set of collapsed parent IDs */\n collapsedParentIds?: Set<string>;\n /** Start of the visible range (e.g., month start) */\n monthStart: Date;\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Height of each task row in pixels */\n rowHeight: number;\n /** Total width of the grid in pixels */\n gridWidth: number;\n /** Real-time pixel overrides for task positions during drag (taskId -> {left, width}) */\n dragOverrides?: Map<string, { left: number; width: number }>;\n /** Currently selected dep chip — highlights the matching arrow in red */\n selectedDep?: { predecessorId: string; successorId: string; linkType: string } | null;\n}\n\n/**\n * SVG overlay component rendering dependency lines as orthogonal paths with rounded corners\n *\n * Lines connect from the right edge of predecessor tasks to the left edge\n * of successor tasks using horizontal/vertical lines with arc rounded corners.\n * Circular dependencies are highlighted in red.\n *\n * Virtual dependency links: When a task is hidden inside a collapsed parent,\n * its dependency lines render at \"virtual positions\" using the parent's row.\n * These virtual lines are styled with dashed strokes to indicate the hidden status.\n *\n * Performance: Uses React.memo to prevent re-renders when dependencies haven't changed.\n */\nexport const DependencyLines: React.FC<DependencyLinesProps> = React.memo(({\n tasks,\n allTasks,\n collapsedParentIds = new Set(),\n monthStart,\n dayWidth,\n rowHeight,\n gridWidth,\n dragOverrides,\n selectedDep,\n}) => {\n // Use allTasks for virtual position calculation if provided, otherwise use tasks\n const tasksForPositions = allTasks ?? tasks;\n\n // Create a lookup map for task positions and their indices\n const { taskPositions, taskIndices, hiddenTaskIds } = useMemo(() => {\n const positions = new Map<string, { left: number; right: number; rowTop: number; isVirtual: boolean }>();\n const indices = new Map<string, number>();\n const hidden = new Set<string>();\n const taskMap = new Map(tasksForPositions.map(t => [t.id, t]));\n const visibleTaskMap = new Map(tasks.map(t => [t.id, t]));\n\n // First pass: Calculate positions for visible tasks (existing logic)\n tasks.forEach((task, index) => {\n const startDate = new Date(task.startDate);\n const endDate = new Date(task.endDate);\n const computed = calculateTaskBar(startDate, endDate, monthStart, dayWidth);\n\n // Use real-time pixel override if available (during drag)\n const override = dragOverrides?.get(task.id);\n const resolvedLeft = override?.left ?? computed.left;\n const resolvedWidth = override?.width ?? computed.width;\n\n indices.set(task.id, index);\n positions.set(task.id, {\n left: resolvedLeft,\n right: resolvedLeft + resolvedWidth,\n rowTop: index * rowHeight,\n isVirtual: false,\n });\n });\n\n // Second pass: Calculate virtual positions for hidden tasks\n if (allTasks && collapsedParentIds.size > 0) {\n for (const task of allTasks) {\n // Skip if already processed (visible task)\n if (positions.has(task.id)) continue;\n\n // Check if task is hidden inside a collapsed parent\n if (!isTaskHidden(task.id, collapsedParentIds, taskMap)) continue;\n\n hidden.add(task.id);\n\n // Find the visible ancestor (collapsed parent)\n const visibleAncestor = findVisibleAncestor(task, collapsedParentIds, taskMap);\n if (!visibleAncestor) continue;\n\n // Get the ancestor's row position\n const ancestorPosition = positions.get(visibleAncestor.id);\n if (!ancestorPosition) continue;\n\n // Calculate horizontal position from task's dates\n const startDate = new Date(task.startDate);\n const endDate = new Date(task.endDate);\n const computed = calculateTaskBar(startDate, endDate, monthStart, dayWidth);\n\n // Use real-time pixel override if available (during drag)\n const override = dragOverrides?.get(task.id);\n const resolvedLeft = override?.left ?? computed.left;\n const resolvedWidth = override?.width ?? computed.width;\n\n // Store virtual position using ancestor's rowTop\n positions.set(task.id, {\n left: resolvedLeft,\n right: resolvedLeft + resolvedWidth,\n rowTop: ancestorPosition.rowTop,\n isVirtual: true,\n });\n }\n }\n\n return { taskPositions: positions, taskIndices: indices, hiddenTaskIds: hidden };\n }, [tasks, tasksForPositions, allTasks, collapsedParentIds, monthStart, dayWidth, rowHeight, dragOverrides]);\n\n // Detect cycles for highlighting (use allTasks for accurate cycle detection)\n const cycleInfo = useMemo(() => {\n const tasksForCycleDetection = allTasks ?? tasks;\n const result = detectCycles(tasksForCycleDetection);\n const cycleTaskIds = new Set(result.cyclePath || []);\n return cycleTaskIds;\n }, [tasks, allTasks]);\n\n // Calculate all dependency line paths (use allTasks if available)\n const lines = useMemo(() => {\n const tasksForEdges = allTasks ?? tasks;\n const edges = getAllDependencyEdges(tasksForEdges);\n const lines: Array<{\n id: string;\n path: string;\n hasCycle: boolean;\n lag: number;\n fromX: number;\n toX: number;\n fromY: number;\n reverseOrder: boolean;\n isVirtual: boolean;\n }> = [];\n\n for (const edge of edges) {\n const predecessor = taskPositions.get(edge.predecessorId);\n const successor = taskPositions.get(edge.successorId);\n const predecessorIndex = taskIndices.get(edge.predecessorId);\n const successorIndex = taskIndices.get(edge.successorId);\n\n if (!predecessor || !successor) {\n continue; // Skip if task not found (shouldn't happen with validation)\n }\n\n // Check if both tasks are hidden inside the same collapsed parent\n // If so, skip rendering this line (it's internal to the collapsed group)\n if (allTasks && collapsedParentIds.size > 0) {\n const taskMap = new Map(allTasks.map(t => [t.id, t]));\n if (areBothHiddenInSameParent(edge.predecessorId, edge.successorId, collapsedParentIds, taskMap)) {\n continue;\n }\n }\n\n // Check if either endpoint is virtual (hidden task)\n const isVirtual = predecessor.isVirtual || successor.isVirtual;\n\n // Determine if tasks are in reverse order (predecessor appears below successor)\n // For virtual tasks, use the predecessor's rowTop for comparison\n let reverseOrder = false;\n if (predecessorIndex !== undefined && successorIndex !== undefined) {\n reverseOrder = predecessorIndex > successorIndex;\n } else {\n // One or both are virtual - use rowTop for comparison\n reverseOrder = predecessor.rowTop > successor.rowTop;\n }\n\n // Calculate direction-specific Y coordinates\n let fromY: number;\n let toY: number;\n\n if (reverseOrder) {\n // Arrow goes UP: exit from top of parent bar, enter at bottom of child bar\n fromY = predecessor.rowTop + 10; // 8px from top of parent bar\n toY = successor.rowTop + rowHeight - 6; // 8px from bottom of child bar\n } else {\n // Arrow goes DOWN: exit from bottom of parent bar, enter at top of child bar\n fromY = predecessor.rowTop + rowHeight - 10; // 8px from bottom of parent bar\n toY = successor.rowTop + 6; // 8px from top of child bar\n }\n\n // Determine connection points based on link type:\n // FS: right → left\n // SS: left → left\n // FF: right → right\n // SF: left → right\n const fromX = (edge.type === 'SS' || edge.type === 'SF')\n ? predecessor.left\n : predecessor.right;\n\n const toX = (edge.type === 'FF' || edge.type === 'SF')\n ? successor.right\n : successor.left;\n\n const arrivesFromRight = edge.type === 'FF' || edge.type === 'SF';\n\n const from = { x: fromX, y: fromY };\n const to = { x: toX, y: toY };\n\n const path = calculateDependencyPath(from, to, arrivesFromRight);\n\n // Check if this edge is part of a cycle\n const hasCycle = cycleInfo.has(edge.predecessorId) || cycleInfo.has(edge.successorId);\n\n // Calculate effective lag from actual positions (always, not just during drag)\n const lag = calculateEffectiveLag(edge, predecessor, successor, monthStart, dayWidth);\n\n lines.push({\n id: `${edge.predecessorId}-${edge.successorId}-${edge.type}`,\n path,\n hasCycle,\n lag,\n fromX,\n toX,\n fromY,\n reverseOrder,\n isVirtual,\n });\n }\n\n return lines;\n }, [tasks, allTasks, taskPositions, taskIndices, cycleInfo, monthStart, dayWidth, dragOverrides]);\n\n // Calculate SVG height based on visible tasks (not all tasks)\n const svgHeight = tasks.length * rowHeight;\n\n return (\n <svg\n className=\"gantt-dependencies-svg\"\n width={gridWidth}\n height={svgHeight}\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n {/* Arrow marker for dependency lines */}\n <marker\n id=\"arrowhead\"\n markerWidth=\"8\"\n markerHeight=\"6\"\n markerUnits=\"userSpaceOnUse\"\n refX=\"7\"\n refY=\"3\"\n orient=\"auto\"\n >\n <polygon\n points=\"0 0, 8 3, 0 6\"\n fill=\"var(--gantt-dependency-line-color, #666666)\"\n />\n </marker>\n\n {/* Red arrow marker for circular dependencies */}\n <marker\n id=\"arrowhead-cycle\"\n markerWidth=\"8\"\n markerHeight=\"6\"\n markerUnits=\"userSpaceOnUse\"\n refX=\"7\"\n refY=\"3\"\n orient=\"auto\"\n >\n <polygon\n points=\"0 0, 8 3, 0 6\"\n fill=\"var(--gantt-dependency-cycle-color, #ef4444)\"\n />\n </marker>\n\n {/* Red arrow marker for selected dependency */}\n <marker\n id=\"arrowhead-selected\"\n markerWidth=\"8\"\n markerHeight=\"6\"\n markerUnits=\"userSpaceOnUse\"\n refX=\"7\"\n refY=\"3\"\n orient=\"auto\"\n >\n <polygon\n points=\"0 0, 8 3, 0 6\"\n fill=\"#ef4444\"\n />\n </marker>\n </defs>\n\n {lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder, isVirtual }) => {\n const isSelected =\n selectedDep != null &&\n id === `${selectedDep.predecessorId}-${selectedDep.successorId}-${selectedDep.linkType}`;\n\n let pathClassName = 'gantt-dependency-path';\n if (isSelected) pathClassName += ' gantt-dependency-selected';\n else if (hasCycle) pathClassName += ' gantt-dependency-cycle';\n if (isVirtual && !isSelected) pathClassName += ' gantt-dependency-virtual';\n\n let markerEnd: string;\n if (isSelected) markerEnd = 'url(#arrowhead-selected)';\n else if (hasCycle) markerEnd = 'url(#arrowhead-cycle)';\n else markerEnd = 'url(#arrowhead)';\n\n const lagColor = isSelected\n ? '#ef4444'\n : hasCycle\n ? 'var(--gantt-dependency-cycle-color, #ef4444)'\n : 'var(--gantt-dependency-line-color, #666666)';\n\n return (\n <React.Fragment key={id}>\n <path\n d={path}\n className={pathClassName}\n markerEnd={markerEnd}\n />\n {lag !== 0 && (\n <text\n className=\"gantt-dependency-lag-label\"\n x={lag < 0 ? toX + 14 : toX - 14}\n y={reverseOrder ? fromY - 4 : fromY + 12}\n textAnchor=\"middle\"\n fontSize=\"10\"\n fill={lagColor}\n >\n {lag > 0 ? `+${lag}` : `${lag}`}\n </text>\n )}\n </React.Fragment>\n );\n })}\n </svg>\n );\n});\n\nDependencyLines.displayName = 'DependencyLines';\n\nexport default DependencyLines;\n","'use client';\n\nimport React, { useMemo, useCallback, useState, useEffect, useRef } from 'react';\nimport type { Task, TaskDependency } from '../GanttChart';\nimport type { LinkType } from '../../types';\nimport type { CustomDayConfig } from '../../utils/dateUtils';\nimport { validateDependencies, calculateSuccessorDate, isTaskParent } from '../../utils/dependencyUtils';\nimport { normalizeHierarchyTasks } from '../../utils/hierarchyOrder';\nimport { getVisibleReorderPosition } from '../../utils/taskListReorder';\nimport { getChildren } from '../../utils/dependencyUtils';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/Popover';\nimport { TaskListRow } from './TaskListRow';\nimport { NewTaskRow } from './NewTaskRow';\nimport { LINK_TYPE_ICONS, LINK_TYPE_LABELS } from './DepIcons';\nimport './TaskList.css';\n\nexport { LINK_TYPE_ICONS };\n\nconst LINK_TYPE_ORDER: LinkType[] = ['FS', 'SS', 'FF', 'SF'];\nconst MIN_TASK_LIST_WIDTH = 640;\n\n/**\n * Get all descendant tasks of a parent task (recursively).\n * Returns an array of all tasks where task.parentId is in the parent chain.\n *\n * @param parentId - ID of the parent task\n * @param tasks - All tasks array\n * @returns Array of descendant tasks (not including the parent itself)\n */\nfunction getAllDescendants(parentId: string, tasks: Task[]): Task[] {\n const descendants: Task[] = [];\n const visited = new Set<string>();\n\n function collectChildren(taskId: string) {\n if (visited.has(taskId)) return;\n visited.add(taskId);\n\n const children = getChildren(taskId, tasks);\n for (const child of children) {\n descendants.push(child);\n collectChildren(child.id);\n }\n }\n\n collectChildren(parentId);\n return descendants;\n}\n\n/**\n * Вычисляет иерархический номер задачи на основе позиции в списке visibleTasks.\n * Корневые задачи: 1, 2, 3...\n * Дочерние задачи: 1.1, 1.2, 2.1, 2.1.1 и т.д.\n *\n * @param tasks - Массив видимых задач (уже отсортированных в иерархическом порядке)\n * @param taskIndex - Индекс задачи в массиве visibleTasks\n * @returns Иерархический номер в виде строки\n */\nfunction getTaskNumber(tasks: Task[], taskIndex: number): string {\n const task = tasks[taskIndex];\n if (!task) return '';\n\n // Если это корневая задача (нет parentId)\n if (!task.parentId) {\n // Найти порядковый номер среди корневых задач\n let rootIndex = 0;\n for (let i = 0; i < taskIndex; i++) {\n if (!tasks[i].parentId) {\n rootIndex++;\n }\n }\n return String(rootIndex + 1);\n }\n\n // Для дочерней задачи - найти родительский номер\n const parentIndex = tasks.findIndex(t => t.id === task.parentId);\n if (parentIndex === -1) {\n // Родитель не найден - fallback на плоский номер\n return String(taskIndex + 1);\n }\n\n const parentNumber = getTaskNumber(tasks, parentIndex);\n\n // Найти порядковый номер среди детей этого родителя\n let siblingIndex = 0;\n for (let i = 0; i < taskIndex; i++) {\n if (tasks[i].parentId === task.parentId) {\n siblingIndex++;\n }\n }\n\n return `${parentNumber}.${siblingIndex + 1}`;\n}\n\nexport interface TaskListProps {\n /** Array of tasks to display */\n tasks: Task[];\n /** Height of each row in pixels (must match Gantt chart's rowHeight) */\n rowHeight: number;\n /** Height of the header row in pixels (must match Gantt chart's headerHeight) */\n headerHeight: number;\n /** Width of the task list overlay in pixels (default: 400) */\n taskListWidth?: number;\n /** Callback when tasks are modified via inline edit. Receives array of changed tasks. */\n onTasksChange?: (tasks: Task[]) => void;\n /** ID of currently selected task */\n selectedTaskId?: string;\n /** Callback when task row is clicked */\n onTaskSelect?: (taskId: string | null) => void;\n /** Show or hide the task list (default: true) */\n show?: boolean;\n /** Show right-side shadow when chart content is horizontally scrolled */\n hasRightShadow?: boolean;\n /** Disable task name editing in the task list (default: false) */\n disableTaskNameEditing?: boolean;\n /** Disable dependency editing (hides +, ×, and type menu; read-only column) (default: false) */\n disableDependencyEditing?: boolean;\n /** Callback to scroll the chart grid to a task (wired to № cell click) */\n onScrollToTask?: (taskId: string) => void;\n /** Callback when selected chip changes (used by GanttChart to highlight the corresponding arrow) */\n onSelectedChipChange?: (chip: { successorId: string; predecessorId: string; linkType: string } | null) => void;\n /** Callback when a new task is added (called with full Task object including generated id) */\n onAdd?: (task: Task) => void;\n /** Callback when a task is deleted (called with taskId) */\n onDelete?: (taskId: string) => void;\n /** Callback when a new task is inserted after a specific task */\n onInsertAfter?: (taskId: string, newTask: Task) => void;\n /** Callback when tasks are reordered via drag in the task list */\n onReorder?: (tasks: Task[], movedTaskId?: string, inferredParentId?: string) => void;\n /** ID of task that should enter edit mode on mount (for auto-edit after insert) */\n editingTaskId?: string | null;\n /** Enable add task button at bottom of task list (default: true) */\n enableAddTask?: boolean;\n /** Set of collapsed parent task IDs */\n collapsedParentIds?: Set<string>;\n /** Callback when collapse/expand button is clicked */\n onToggleCollapse?: (parentId: string) => void;\n /** Callback when task is promoted (parentId removed) */\n onPromoteTask?: (taskId: string) => void;\n /** Callback when task is demoted (parentId set to previous task) */\n onDemoteTask?: (taskId: string, newParentId: string) => void;\n /** Custom day configurations for date picker */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate for date picker */\n isWeekend?: (date: Date) => boolean;\n /** Task IDs highlighted by the active filter */\n highlightedTaskIds?: Set<string>;\n}\n\n/**\n * TaskList component - displays tasks in a table format as an overlay\n *\n * Renders a table with columns: № (number), Name, Start Date, End Date, Duration, Progress, Dependencies\n * Uses position: sticky for synchronized vertical scrolling with the chart.\n */\nexport const TaskList: React.FC<TaskListProps> = ({\n tasks,\n rowHeight,\n headerHeight,\n taskListWidth = 640,\n onTasksChange,\n selectedTaskId,\n onTaskSelect,\n show = true,\n hasRightShadow = false,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n onScrollToTask,\n onSelectedChipChange,\n onAdd,\n onDelete,\n onInsertAfter,\n onReorder,\n editingTaskId: propEditingTaskId,\n enableAddTask = true,\n collapsedParentIds: externalCollapsedParentIds,\n onToggleCollapse: externalOnToggleCollapse,\n onPromoteTask,\n onDemoteTask,\n customDays,\n isWeekend,\n highlightedTaskIds = new Set(),\n}) => {\n // Hierarchy state: collapsed parent IDs (uncontrolled mode - internal state)\n const [internalCollapsedParentIds, setInternalCollapsedParentIds] = useState<Set<string>>(new Set());\n\n // Use external collapsedParentIds if provided (controlled mode), otherwise use internal state\n const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;\n\n // Use external onToggleCollapse if provided (controlled mode), otherwise use internal handler\n const handleToggleCollapse = externalOnToggleCollapse ?? useCallback((parentId: string) => {\n setInternalCollapsedParentIds(prev => {\n const next = new Set(prev);\n if (next.has(parentId)) {\n next.delete(parentId);\n } else {\n next.add(parentId);\n }\n return next;\n });\n }, []);\n\n const orderedTasks = useMemo(() => {\n return normalizeHierarchyTasks(tasks);\n }, [tasks]);\n\n // Filter tasks to hide children of collapsed parents.\n // Checks the full ancestor chain so grandchildren are hidden when any ancestor is collapsed.\n const visibleTasks = useMemo(() => {\n const parentMap = new Map(orderedTasks.map(t => [t.id, (t as any).parentId as string | undefined]));\n\n function isAnyAncestorCollapsed(parentId: string | undefined): boolean {\n let current = parentId;\n while (current) {\n if (collapsedParentIds.has(current)) return true;\n current = parentMap.get(current);\n }\n return false;\n }\n\n return orderedTasks.filter(task => !isAnyAncestorCollapsed((task as any).parentId));\n }, [orderedTasks, collapsedParentIds]);\n\n const totalHeight = useMemo(\n () => visibleTasks.length * rowHeight,\n [visibleTasks.length, rowHeight]\n );\n\n // Compute nesting depth for each task (0 = root, 1 = child, 2 = grandchild, etc.)\n const nestingDepthMap = useMemo(() => {\n const depthMap = new Map<string, number>();\n const taskById = new Map(tasks.map(t => [t.id, t]));\n\n function getDepth(taskId: string): number {\n if (depthMap.has(taskId)) return depthMap.get(taskId)!;\n const task = taskById.get(taskId);\n if (!task || !(task as any).parentId || !taskById.has((task as any).parentId)) {\n depthMap.set(taskId, 0);\n return 0;\n }\n const depth = getDepth((task as any).parentId) + 1;\n depthMap.set(taskId, depth);\n return depth;\n }\n\n for (const task of tasks) {\n getDepth(task.id);\n }\n return depthMap;\n }, [tasks]);\n\n // For each child task, determine if it's the last visible child of its parent\n const lastChildIds = useMemo(() => {\n const last = new Set<string>();\n const seenParents = new Set<string>();\n for (let i = visibleTasks.length - 1; i >= 0; i--) {\n const t = visibleTasks[i] as Task;\n if (t.parentId && !seenParents.has(t.parentId)) {\n last.add(t.id);\n seenParents.add(t.parentId);\n }\n }\n return last;\n }, [visibleTasks]);\n\n // For each task, track whether each ancestor level \"continues\" (has siblings below).\n // ancestorContinuesMap[taskId][i] = true means the ancestor at depth (i+1) is NOT the last child,\n // so a vertical continuation line should be drawn at horizontal position i.\n const ancestorContinuesMap = useMemo(() => {\n const taskById = new Map(tasks.map(t => [t.id, t]));\n const map = new Map<string, boolean[]>();\n for (const task of visibleTasks) {\n const continues: boolean[] = [];\n let current: any = taskById.get(task.id);\n while (current?.parentId && taskById.has(current.parentId)) {\n continues.unshift(!lastChildIds.has(current.id));\n current = taskById.get(current.parentId);\n }\n // Walk builds: [!isLastChild(outermost ancestor), ..., !isLastChild(parent), !isLastChild(task)]\n // We slice off the last entry (the task's own \"continues\" status) — the task's own vline\n // is rendered separately in TaskListRow using isLastChild.\n // Remaining entries: one per ancestor level, outermost first.\n // ancestorContinues[i] = true → draw vertical continuation line at position i * 20 + 9 px.\n map.set(task.id, continues.slice(0, -1));\n }\n return map;\n }, [tasks, visibleTasks, lastChildIds]);\n\n const handleRowClick = useCallback((taskId: string) => {\n onTaskSelect?.(taskId);\n }, [onTaskSelect]);\n\n // Dependency state\n const [activeLinkType, setActiveLinkType] = useState<LinkType>('FS');\n const [selectingPredecessorFor, setSelectingPredecessorFor] = useState<string | null>(null);\n const [typeMenuOpen, setTypeMenuOpen] = useState(false);\n const [cycleError, setCycleError] = useState(false);\n const overlayRef = useRef<HTMLDivElement>(null);\n\n // Selected chip state: clicking a chip on a successor row selects it,\n // causing the predecessor row to show a \"Удалить\" button\n const [selectedChip, setSelectedChip] = useState<{\n successorId: string;\n predecessorId: string;\n linkType: LinkType;\n } | null>(null);\n\n const handleChipSelect = useCallback((chip: {\n successorId: string;\n predecessorId: string;\n linkType: LinkType;\n } | null) => {\n setSelectedChip(chip);\n onSelectedChipChange?.(chip);\n }, [onSelectedChipChange]);\n\n // Escape / outside-click cancel for picker mode, chip selection, and task row selection\n useEffect(() => {\n if (!selectingPredecessorFor && !selectedChip && !selectedTaskId) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setSelectingPredecessorFor(null);\n setSelectedChip(null);\n onSelectedChipChange?.(null);\n onTaskSelect?.(null);\n }\n };\n const handleMouseDown = (e: MouseEvent) => {\n const target = e.target as Element;\n if (overlayRef.current?.contains(target)) return;\n // Don't clear when clicking inside a floating portal (popover, date picker, etc.)\n if (target.closest?.('.gantt-popover')) return;\n setSelectingPredecessorFor(null);\n setSelectedChip(null);\n onSelectedChipChange?.(null);\n onTaskSelect?.(null);\n };\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('mousedown', handleMouseDown, true);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('mousedown', handleMouseDown, true);\n };\n }, [selectingPredecessorFor, selectedChip, selectedTaskId, onTaskSelect, onSelectedChipChange]);\n\n const handleAddDependency = useCallback((\n successorTaskId: string,\n predecessorTaskId: string,\n linkType: LinkType\n ) => {\n // Guard: no self-links\n if (successorTaskId === predecessorTaskId) return;\n\n // Guard: no duplicate (same taskId + type)\n const successor = tasks.find(t => t.id === successorTaskId);\n if (!successor) return;\n const alreadyExists = (successor.dependencies ?? []).some(\n d => d.taskId === predecessorTaskId && d.type === linkType\n );\n if (alreadyExists) {\n setSelectingPredecessorFor(null);\n return;\n }\n\n // Build hypothetical tasks array to validate for cycles\n const newDep: TaskDependency = { taskId: predecessorTaskId, type: linkType, lag: 0 };\n const hypothetical = tasks.map(t =>\n t.id === successorTaskId\n ? { ...t, dependencies: [...(t.dependencies ?? []), newDep] }\n : t\n );\n const validation = validateDependencies(hypothetical);\n if (!validation.isValid) {\n setCycleError(true);\n setTimeout(() => setCycleError(false), 3000);\n return;\n }\n\n const updatedTask = hypothetical.find(t => t.id === successorTaskId)!;\n\n // Snap successor dates to the predecessor position (lag=0)\n const predecessor = tasks.find(t => t.id === predecessorTaskId);\n if (predecessor) {\n const predStart = new Date(predecessor.startDate as string);\n const predEnd = new Date(predecessor.endDate as string);\n const constraintDate = calculateSuccessorDate(predStart, predEnd, linkType, 0);\n\n const origSuccessor = tasks.find(t => t.id === successorTaskId)!;\n const durationMs =\n new Date(origSuccessor.endDate as string).getTime() -\n new Date(origSuccessor.startDate as string).getTime();\n\n let newStart: Date;\n let newEnd: Date;\n\n if (linkType === 'FS' || linkType === 'SS') {\n newStart = constraintDate;\n newEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n newEnd = constraintDate;\n newStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n const snappedTask: Task = {\n ...updatedTask,\n startDate: newStart.toISOString().split('T')[0],\n endDate: newEnd.toISOString().split('T')[0],\n };\n onTasksChange?.([snappedTask]);\n } else {\n // Predecessor not found — emit without snap (graceful fallback)\n onTasksChange?.([updatedTask]);\n }\n\n setSelectingPredecessorFor(null);\n }, [tasks, onTasksChange]);\n\n const handleRemoveDependency = useCallback((\n taskId: string,\n predecessorTaskId: string,\n linkType: LinkType\n ) => {\n const task = tasks.find(t => t.id === taskId);\n if (!task) return;\n const updatedDeps = (task.dependencies ?? []).filter(\n d => !(d.taskId === predecessorTaskId && d.type === linkType)\n );\n onTasksChange?.([{ ...task, dependencies: updatedDeps }]);\n }, [tasks, onTasksChange]);\n\n // New task creation state\n const [isCreating, setIsCreating] = useState(false);\n\n // Drag-to-reorder state\n const [draggingIndex, setDraggingIndex] = useState<number | null>(null);\n const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);\n const dragOriginIndexRef = useRef<number | null>(null);\n const dragTaskIdRef = useRef<string | null>(null);\n\n // Helper: check if a parent task can be dropped at a specific position\n // Parent tasks cannot be dropped:\n // 1. Between their own children\n // 2. Between another parent's children (would make them a child)\n // 3. Under their own descendants (would create a cycle)\n const isValidParentDrop = useCallback((draggedTaskId: string, dropIndex: number): boolean => {\n // If not a parent, allow all drops\n if (!isTaskParent(draggedTaskId, tasks)) {\n return true;\n }\n\n const dropTarget = visibleTasks[dropIndex];\n if (!dropTarget) return true;\n\n // Scenario 1: Dropping parent between its own children\n if (dropTarget.parentId === draggedTaskId) {\n return false;\n }\n\n // Scenario 2: Dropping parent between another parent's children\n // Allow this for unlimited nesting — parent can become nested under another task.\n // Scenarios 1 and 3 still protect against circular references and self-nesting.\n\n // Scenario 3: Dropping parent under one of its own descendants\n // This would create a cycle (parent becomes child of its descendant)\n // Check if dropTarget is a descendant of draggedTaskId\n const draggedTask = orderedTasks.find(t => t.id === draggedTaskId);\n if (!draggedTask) return true;\n\n const descendants = getAllDescendants(draggedTaskId, orderedTasks);\n const descendantIds = new Set(descendants.map(d => d.id));\n\n if (descendantIds.has(dropTarget.id)) {\n return false;\n }\n\n // Allow dropping on other root tasks (parents or non-parents)\n return true;\n }, [tasks, visibleTasks, orderedTasks]);\n\n const handleDragStart = useCallback((index: number, e: React.DragEvent) => {\n e.dataTransfer.effectAllowed = 'move';\n setDraggingIndex(index);\n dragOriginIndexRef.current = index;\n dragTaskIdRef.current = visibleTasks[index]?.id ?? null;\n }, [visibleTasks]);\n\n const handleDragOver = useCallback((index: number, e: React.DragEvent) => {\n e.preventDefault();\n\n const draggedTaskId = dragTaskIdRef.current;\n if (!draggedTaskId) return;\n\n // Don't show drop indication if this is an invalid parent drop\n if (!isValidParentDrop(draggedTaskId, index)) {\n setDragOverIndex(null);\n e.dataTransfer.dropEffect = 'none';\n return;\n }\n\n e.dataTransfer.dropEffect = 'move';\n setDragOverIndex(index);\n }, [isValidParentDrop]);\n\n const handleDrop = useCallback((dropIndex: number, e: React.DragEvent) => {\n e.preventDefault();\n const originVisibleIndex = dragOriginIndexRef.current;\n const movedTaskId = dragTaskIdRef.current;\n\n // No-op: same position (line is already where the row is)\n if (originVisibleIndex === null || movedTaskId === null || originVisibleIndex === dropIndex) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n // Reject invalid parent drops (parent being dragged into children or another parent)\n if (!isValidParentDrop(movedTaskId, dropIndex)) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n const reorderPosition = getVisibleReorderPosition(\n orderedTasks,\n visibleTasks,\n movedTaskId,\n originVisibleIndex,\n dropIndex,\n );\n\n if (!reorderPosition) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n const { originOrderedIndex, insertIndex } = reorderPosition;\n\n // Early exit: if insertIndex equals originOrderedIndex, the subtree would be removed\n // and re-inserted at the exact same position - a true no-op. Skip the callback.\n if (insertIndex === originOrderedIndex) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n const moved = orderedTasks[originOrderedIndex];\n\n // Check if this is a parent task with children\n const hasChildren = isTaskParent(moved.id, orderedTasks);\n\n // Extract the subtree to move (parent + all descendants, if any)\n let subtree: Task[];\n let subtreeCount: number;\n\n if (hasChildren) {\n // Get all descendants of the parent\n const descendants = getAllDescendants(moved.id, orderedTasks);\n subtree = [moved, ...descendants];\n subtreeCount = subtree.length;\n } else {\n // Single task (not a parent)\n subtree = [moved];\n subtreeCount = 1;\n }\n\n const reordered = [...orderedTasks];\n\n // Remove the entire subtree from its original position\n reordered.splice(originOrderedIndex, subtreeCount);\n\n // CRITICAL: insertIndex is already relative to reorderedWithoutMoved\n // After the splice, reordered === reorderedWithoutMoved (same array, same order)\n // So we should use insertIndex directly, NOT insertIndex - subtreeCount\n // The old code was subtracting subtreeCount again, which was incorrect\n const adjustedInsertIndex = insertIndex;\n\n // parentId inference: determine if task should be in a group\n // IMPORTANT: Calculate this BEFORE splicing moved task back into reordered\n // because we need to find the parent's position in the array WITHOUT the moved task\n let inferredParentId: string | undefined;\n\n if (moved.parentId) {\n // Task is currently a child - check if it's staying in or leaving its group\n // Find parent position in the array WITHOUT the moved task (reordered after first splice)\n const parentIndex = reordered.findIndex(t => t.id === moved.parentId);\n\n if (parentIndex === -1) {\n // Parent not found - should not happen, but handle gracefully\n inferredParentId = undefined;\n } else {\n // Calculate where the moved task will end up AFTER we splice it in\n // The key question: is insertIndex outside the range [parentIndex, parentIndex + numSiblings]?\n const numSiblings = reordered.filter(t => t.parentId === moved.parentId).length;\n const groupEnd = parentIndex + numSiblings;\n\n // If adjustedInsertIndex is <= parent (at or above parent position) or > groupEnd (below all siblings)\n // Note: adjustedInsertIndex == parentIndex means child will be inserted at parent's position,\n // which after splicing puts child above parent (parent shifts down by 1)\n if (adjustedInsertIndex <= parentIndex || adjustedInsertIndex > groupEnd) {\n inferredParentId = undefined; // Exit group - become root\n } else {\n // Staying within group - keep original parentId\n inferredParentId = moved.parentId;\n }\n }\n } else {\n // Task is currently root - check if it should join a group after splicing\n }\n\n // Now splice the entire subtree into its final position\n reordered.splice(adjustedInsertIndex, 0, ...subtree);\n\n // For root tasks, check if they should join a group (need reordered for this)\n // IMPORTANT: Parent tasks (hasChildren === true) must NEVER be reparented during drag-drop.\n // They always stay at root level regardless of where they are dropped.\n // Only leaf/child tasks (non-parents) can be adopted into a group by neighboring tasks.\n if (!moved.parentId && !hasChildren) {\n const taskAbove = adjustedInsertIndex > 0 ? reordered[adjustedInsertIndex - 1] : null;\n const taskBelow = adjustedInsertIndex < reordered.length - 1 ? reordered[adjustedInsertIndex + 1] : null;\n\n // Join a group ONLY if placed between parent and its first child,\n // or between two children of the same parent.\n // Dropping after the last child of a group keeps the task at root level.\n if (taskAbove && taskBelow && taskBelow.parentId === taskAbove.id) {\n // Placed between a parent and its first child\n inferredParentId = taskAbove.id;\n } else if (taskAbove && taskBelow && taskAbove.parentId && taskAbove.parentId === taskBelow.parentId) {\n // Placed between two children of the same parent\n inferredParentId = taskAbove.parentId;\n } else if (!taskAbove && taskBelow && taskBelow.parentId) {\n // Placed at the very top, above a child — join that group\n inferredParentId = taskBelow.parentId;\n }\n }\n\n onReorder?.(reordered, moved.id, inferredParentId);\n onTaskSelect?.(moved.id);\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n }, [orderedTasks, visibleTasks, onReorder, onTaskSelect]);\n\n const handleDragEnd = useCallback(() => {\n // Called when drag ends without a valid drop (Escape, or dropped outside)\n // handleDrop already clears state on successful drop, so this is only the cancel path\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n }, []);\n\n const handleConfirmNewTask = useCallback((name: string) => {\n const now = new Date();\n const todayISO = new Date(Date.UTC(\n now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()\n )).toISOString().split('T')[0];\n const endISO = new Date(Date.UTC(\n now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 7\n )).toISOString().split('T')[0];\n const newTask: Task = {\n id: crypto.randomUUID(),\n name,\n startDate: todayISO,\n endDate: endISO,\n };\n onAdd?.(newTask);\n setIsCreating(false);\n }, [onAdd]);\n\n const handleCancelNewTask = useCallback(() => setIsCreating(false), []);\n\n /**\n * Calculate the depth of a task in the hierarchy.\n * Root tasks have depth 0, their children have depth 1, etc.\n */\n function getTaskDepth(task: Task | undefined, tasks: Task[]): number {\n if (!task) return 0;\n let depth = 0;\n let current: Task | undefined = task;\n while (current) {\n if (!current.parentId) break;\n depth++;\n const parentId: string = current.parentId;\n current = tasks.find(t => t.id === parentId);\n }\n return depth;\n }\n\n /**\n * Demote wrapper — move task down one level in hierarchy.\n *\n * Rules:\n * 1. Find the PREVIOUS task at the SAME depth level (same hierarchy level)\n * 2. Make that task the parent of the current task\n * 3. If no previous task at same level exists (first task), create \"Новый раздел\"\n *\n * Example:\n * - Task 1.1 (depth 1)\n * - Task 1.2 (depth 1)\n * - [Task to demote] (depth 1) → becomes child of Task 1.2\n *\n * Result:\n * - Task 1.1 (depth 1)\n * - Task 1.2 (depth 1)\n * - Task to demote (depth 2, child of 1.2)\n *\n * The `_newParentId` argument from TaskListRow is ignored — we compute the correct parent here.\n */\n const handleDemoteWrapper = useCallback((taskId: string, _newParentId: string) => {\n const taskIndex = visibleTasks.findIndex(t => t.id === taskId);\n const currentTask = visibleTasks[taskIndex];\n const currentDepth = getTaskDepth(currentTask, orderedTasks);\n\n if (taskIndex > 0) {\n // Search backwards for the previous task at the same depth level\n for (let i = taskIndex - 1; i >= 0; i--) {\n const previousTask = visibleTasks[i];\n const previousDepth = getTaskDepth(previousTask, orderedTasks);\n\n // Found a task at the same level - use it as parent\n if (previousDepth === currentDepth) {\n onDemoteTask?.(taskId, previousTask.id);\n return;\n }\n\n // If we encounter a task at a shallower depth, stop searching\n // (no same-level task exists before this point)\n if (previousDepth < currentDepth) {\n break;\n }\n }\n\n // No same-level task found - cannot demote\n return;\n }\n\n // First-task case: create \"Новый раздел\" as a new root parent\n const demotedTask = orderedTasks.find(t => t.id === taskId);\n if (!demotedTask) return;\n\n const newSectionTask: Task = {\n id: crypto.randomUUID(),\n name: 'Новый раздел',\n startDate: demotedTask.startDate,\n endDate: demotedTask.endDate,\n };\n\n const updatedTasks: Task[] = [\n newSectionTask,\n ...orderedTasks.map(t =>\n t.id === taskId ? { ...t, parentId: newSectionTask.id } : t\n ),\n ];\n\n onReorder?.(updatedTasks, taskId, newSectionTask.id);\n }, [visibleTasks, orderedTasks, onDemoteTask, onReorder]);\n\n const effectiveTaskListWidth = Math.max(taskListWidth, MIN_TASK_LIST_WIDTH);\n\n return (\n <div\n ref={overlayRef}\n className={`gantt-tl-overlay${show ? '' : ' gantt-tl-hidden'}${hasRightShadow ? ' gantt-tl-overlay-shadowed' : ''}`}\n style={{ '--tasklist-width': `${effectiveTaskListWidth}px` } as React.CSSProperties}\n >\n <div className=\"gantt-tl-table\">\n {/* Header row - aligns with TimeScaleHeader, 1px taller for row alignment */}\n <div className=\"gantt-tl-header\" style={{ height: `${headerHeight + 0.5}px` }}>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-number\">№</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-name\">Имя</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-date\">Начало</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-date\">Окончание</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-duration\">Дн.</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-progress\">%</div>\n {/* Dependencies column header with type switcher */}\n <div className=\"gantt-tl-headerCell gantt-tl-cell-deps\" style={{ position: 'relative' }}>\n <Popover open={typeMenuOpen} onOpenChange={setTypeMenuOpen}>\n <PopoverTrigger asChild>\n <button\n className=\"gantt-tl-dep-type-trigger\"\n disabled={disableDependencyEditing}\n onClick={(e) => e.stopPropagation()}\n >\n Связи {React.createElement(LINK_TYPE_ICONS[activeLinkType])} &#9662;\n </button>\n </PopoverTrigger>\n <PopoverContent portal={true} align=\"start\">\n <div className=\"gantt-tl-dep-type-menu\">\n {LINK_TYPE_ORDER.map(lt => (\n <button\n key={lt}\n className={`gantt-tl-dep-type-option${activeLinkType === lt ? ' active' : ''}`}\n onClick={() => { setActiveLinkType(lt); setTypeMenuOpen(false); }}\n >\n {React.createElement(LINK_TYPE_ICONS[lt])}\n <span>{LINK_TYPE_LABELS[lt]}</span>\n </button>\n ))}\n </div>\n </PopoverContent>\n </Popover>\n {cycleError && (\n <div className=\"gantt-tl-dep-error\">Цикл зависимостей!</div>\n )}\n </div>\n </div>\n\n {/* Data rows */}\n <div className=\"gantt-tl-body\" style={{ height: `${totalHeight}px` }}>\n {visibleTasks.map((task, index) => (\n <TaskListRow\n key={task.id}\n task={task}\n rowIndex={index}\n taskNumber={getTaskNumber(visibleTasks, index)}\n rowHeight={rowHeight}\n onTasksChange={onTasksChange}\n selectedTaskId={selectedTaskId}\n onRowClick={handleRowClick}\n disableTaskNameEditing={disableTaskNameEditing}\n disableDependencyEditing={disableDependencyEditing}\n allTasks={tasks}\n activeLinkType={activeLinkType}\n selectingPredecessorFor={selectingPredecessorFor}\n onSetSelectingPredecessorFor={setSelectingPredecessorFor}\n onAddDependency={handleAddDependency}\n onRemoveDependency={handleRemoveDependency}\n selectedChip={selectedChip}\n onChipSelect={handleChipSelect}\n onScrollToTask={onScrollToTask}\n onDelete={onDelete}\n onAdd={onAdd}\n onInsertAfter={onInsertAfter}\n editingTaskId={propEditingTaskId}\n isDragging={draggingIndex === index}\n isDragOver={dragOverIndex === index}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n onDragEnd={handleDragEnd}\n collapsedParentIds={collapsedParentIds}\n onToggleCollapse={handleToggleCollapse}\n onPromoteTask={onPromoteTask}\n onDemoteTask={onDemoteTask ? handleDemoteWrapper : undefined}\n isLastChild={lastChildIds.has(task.id)}\n nestingDepth={nestingDepthMap.get(task.id) ?? 0}\n ancestorContinues={ancestorContinuesMap.get(task.id) ?? []}\n customDays={customDays}\n isWeekend={isWeekend}\n isFilterMatch={highlightedTaskIds.has(task.id)}\n />\n ))}\n </div>\n\n {/* Ghost row for new task creation — positioned OUTSIDE body div to avoid height desync */}\n {isCreating && (\n <NewTaskRow\n rowHeight={rowHeight}\n onConfirm={handleConfirmNewTask}\n onCancel={handleCancelNewTask}\n />\n )}\n\n {/* Add task button - also serves as drop target for moving tasks to end */}\n {enableAddTask && onAdd && !isCreating && (\n <button\n className={`gantt-tl-add-btn${dragOverIndex === visibleTasks.length ? ' gantt-tl-add-btn-drag-over' : ''}`}\n onClick={() => setIsCreating(true)}\n onDragEnter={(e) => {\n e.preventDefault();\n setDragOverIndex(visibleTasks.length);\n }}\n onDragOver={(e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n setDragOverIndex(visibleTasks.length);\n }}\n onDragLeave={(e) => {\n e.preventDefault();\n setDragOverIndex(null);\n }}\n onDrop={(e) => {\n e.preventDefault();\n handleDrop(visibleTasks.length, e);\n }}\n type=\"button\"\n >\n + Добавить задачу\n </button>\n )}\n </div>\n </div>\n );\n};\n\nexport default TaskList;\n","import type { Task } from '../components/GanttChart';\n\ntype TaskLike = { id: string };\n\nexport interface VisibleReorderPosition {\n originOrderedIndex: number;\n insertIndex: number;\n}\n\n/**\n * Get all descendant IDs of a task (recursively).\n * Used to identify the entire subtree that must move together when dragging a parent.\n */\nfunction getDescendantIds(taskId: string, tasks: TaskLike[]): string[] {\n const descendants: string[] = [];\n const visited = new Set<string>();\n\n function collect(id: string) {\n if (visited.has(id)) return;\n visited.add(id);\n\n // Find all direct children of this task\n for (const task of tasks) {\n if ((task as any).parentId === id && !visited.has(task.id)) {\n descendants.push(task.id);\n collect(task.id);\n }\n }\n }\n\n collect(taskId);\n return descendants;\n}\n\n/**\n * Map visible drag/drop positions to indices in the full ordered task list.\n * This keeps collapsed descendants attached to their parent row.\n *\n * When dragging a parent task, all its descendants are included in the move,\n * so they are all filtered out before calculating the insert position.\n */\nexport function getVisibleReorderPosition(\n orderedTasks: TaskLike[],\n visibleTasks: TaskLike[],\n movedTaskId: string,\n originVisibleIndex: number,\n dropVisibleIndex: number,\n): VisibleReorderPosition | null {\n const originOrderedIndex = orderedTasks.findIndex((task) => task.id === movedTaskId);\n if (originOrderedIndex === -1) {\n return null;\n }\n\n // Get all descendant IDs if this is a parent task\n const descendantIds = getDescendantIds(movedTaskId, orderedTasks);\n const allMovedIds = new Set([movedTaskId, ...descendantIds]);\n\n // Filter out ALL tasks that will move (parent + descendants)\n const reorderedWithoutMoved = orderedTasks.filter((task) => !allMovedIds.has(task.id));\n const visibleWithoutMoved = visibleTasks.filter((task) => !allMovedIds.has(task.id));\n\n if (visibleWithoutMoved.length === 0) {\n return { originOrderedIndex, insertIndex: 0 };\n }\n\n // CRITICAL: dropVisibleIndex is an index into the ORIGINAL visibleTasks, NOT into\n // visibleWithoutMoved (which has fewer items after removing the moved subtree).\n // We must look up the actual drop target task by its ID from the original list,\n // then find it in visibleWithoutMoved.\n\n // Look up the actual task at the drop position in the ORIGINAL visible list\n const dropTargetTask = visibleTasks[dropVisibleIndex];\n\n if (!dropTargetTask) {\n // dropVisibleIndex is beyond the end of the original list - append at end\n return {\n originOrderedIndex,\n insertIndex: reorderedWithoutMoved.length,\n };\n }\n\n // Find the drop target in the filtered array (visibleWithoutMoved has the moved subtree removed)\n const filteredDropIndex = visibleWithoutMoved.findIndex((t) => t.id === dropTargetTask.id);\n\n if (filteredDropIndex === -1) {\n // Drop target was part of the moved subtree - should not happen after isValidParentDrop check\n // Append at end as fallback\n return {\n originOrderedIndex,\n insertIndex: reorderedWithoutMoved.length,\n };\n }\n\n const targetVisibleTask = visibleWithoutMoved[filteredDropIndex];\n\n // Find the target in reorderedWithoutMoved.\n // The drop indicator semantics: indicator at position N shows the TOP border of row N,\n // meaning the task will be inserted ABOVE row N.\n // We use the drop target's position directly without skipping past its group.\n // This preserves \"drop at top of родитель2 = insert before родитель2\" semantics.\n // To move a parent PAST родитель2's entire group, the user must drag to the end of the list\n // (past all of родитель2's children), which triggers the \"append at end\" path above.\n const insertIndex = reorderedWithoutMoved.findIndex((task) => task.id === targetVisibleTask.id);\n\n return {\n originOrderedIndex,\n insertIndex,\n };\n}\n","'use client';\n\nimport React from 'react';\nimport * as RadixPopover from '@radix-ui/react-popover';\n\nexport interface PopoverProps {\n /** Whether the popover is open */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** The trigger element */\n children: React.ReactNode;\n}\n\nexport interface PopoverContentProps {\n /** Content to display inside the popover */\n children: React.ReactNode;\n /** Additional CSS class names */\n className?: string;\n /** Alignment relative to trigger */\n align?: 'start' | 'center' | 'end';\n /** Side to render the popover */\n side?: 'top' | 'right' | 'bottom' | 'left';\n /** Whether to use a portal for rendering */\n portal?: boolean;\n /** Collision padding */\n collisionPadding?: number;\n /** Callback when user interacts outside the popover */\n onInteractOutside?: (event: CustomEvent) => void;\n}\n\n/**\n * Popover root component wrapping Radix UI Popover\n */\nexport const Popover: React.FC<PopoverProps> = ({ open, onOpenChange, children }) => {\n return (\n <RadixPopover.Root open={open} onOpenChange={onOpenChange}>\n {children}\n </RadixPopover.Root>\n );\n};\n\n/**\n * Popover trigger — wraps the element that opens the popover\n */\nexport const PopoverTrigger = RadixPopover.Trigger;\n\n/**\n * Popover content — the floating panel\n */\nexport const PopoverContent: React.FC<PopoverContentProps> = ({\n children,\n className,\n align = 'start',\n side = 'bottom',\n portal = true,\n collisionPadding = 8,\n onInteractOutside,\n}) => {\n const content = (\n <RadixPopover.Content\n className={`gantt-popover${className ? ` ${className}` : ''}`}\n align={align}\n side={side}\n collisionPadding={collisionPadding}\n sideOffset={4}\n onInteractOutside={onInteractOutside}\n >\n {children}\n </RadixPopover.Content>\n );\n\n if (portal) {\n return <RadixPopover.Portal>{content}</RadixPopover.Portal>;\n }\n\n return content;\n};\n\nexport default Popover;\n","\"use client\";\n\nimport React, {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n} from \"react\";\nimport type { Task } from \"../GanttChart\";\nimport type { LinkType } from \"../../types\";\nimport type { CustomDayConfig } from \"../../utils/dateUtils\";\nimport { parseUTCDate, normalizeTaskDates, createCustomDayPredicate } from \"../../utils/dateUtils\";\nimport {\n computeLagFromDates,\n calculateSuccessorDate,\n isTaskParent,\n findParentId,\n getChildren,\n} from \"../../utils/dependencyUtils\";\nimport { Input } from \"../ui/Input\";\nimport { DatePicker } from \"../ui/DatePicker\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/Popover\";\nimport { LINK_TYPE_ICONS } from \"./DepIcons\";\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nconst getInclusiveDurationDays = (\n startDate: string | Date,\n endDate: string | Date,\n): number => {\n const start = parseUTCDate(startDate);\n const end = parseUTCDate(endDate);\n return Math.max(\n 1,\n Math.round((end.getTime() - start.getTime()) / DAY_MS) + 1,\n );\n};\n\nconst getEndDateFromDuration = (\n startDate: string | Date,\n durationDays: number,\n): string => {\n const start = parseUTCDate(startDate);\n return new Date(start.getTime() + (durationDays - 1) * DAY_MS)\n .toISOString()\n .split(\"T\")[0];\n};\n\n// ---------------------------------------------------------------------------\n// DepChip — local unified component used in both single-chip cell and popover\n// ---------------------------------------------------------------------------\ninterface DepChipProps {\n lag?: number;\n dep: { taskId: string; type: LinkType };\n taskId: string;\n predecessorName?: string;\n selectedChip: TaskListRowProps[\"selectedChip\"];\n disableDependencyEditing: boolean;\n onChipSelect: TaskListRowProps[\"onChipSelect\"];\n onRowClick: TaskListRowProps[\"onRowClick\"];\n onScrollToTask: TaskListRowProps[\"onScrollToTask\"];\n onRemoveDependency: TaskListRowProps[\"onRemoveDependency\"];\n onChipSelectClear: () => void;\n /** The successor task (needed for lag date computation) */\n task: Task;\n /** All tasks (needed to find predecessor dates) */\n allTasks: Task[];\n /** Callback to save date changes after lag modification */\n onTasksChange?: TaskListRowProps[\"onTasksChange\"];\n}\n\nconst TrashIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n);\n\nconst PlusIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M12 5v14M5 12h14\" />\n </svg>\n);\n\nconst DragHandleIcon = () => (\n <svg width=\"10\" height=\"14\" viewBox=\"0 0 10 14\" fill=\"currentColor\">\n <circle cx=\"2\" cy=\"2\" r=\"1.5\" />\n <circle cx=\"8\" cy=\"2\" r=\"1.5\" />\n <circle cx=\"2\" cy=\"7\" r=\"1.5\" />\n <circle cx=\"8\" cy=\"7\" r=\"1.5\" />\n <circle cx=\"2\" cy=\"12\" r=\"1.5\" />\n <circle cx=\"8\" cy=\"12\" r=\"1.5\" />\n </svg>\n);\n\nconst ChevronRightIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n);\n\n// ---------------------------------------------------------------------------\n// HierarchyButton — Single button with left/right arrows for hierarchy navigation\n// ---------------------------------------------------------------------------\ninterface HierarchyButtonProps {\n /** Whether the task is a child (can be promoted) */\n isChild: boolean;\n /** Row index - first row cannot demote */\n rowIndex: number;\n /** Callback when promote is clicked (left arrow) */\n onPromote?: (e: React.MouseEvent) => void;\n /** Callback when demote is clicked (right arrow) */\n onDemote?: (e: React.MouseEvent) => void;\n}\n\nconst ArrowLeft = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m12 19-7-7 7-7\" />\n <path d=\"M19 12H5\" />\n </svg>\n);\n\nconst ArrowRight = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M5 12h14\" />\n <path d=\"m12 5 7 7-7 7\" />\n </svg>\n);\n\nconst HierarchyButton: React.FC<HierarchyButtonProps> = ({\n isChild,\n rowIndex: _rowIndex,\n onPromote,\n onDemote,\n}) => {\n const canPromote = isChild && onPromote;\n // Demote is always allowed when the callback is provided.\n // rowIndex === 0 is handled upstream: clicking Demote on the first task\n // triggers \"Новый раздел\" parent creation (not blocked here).\n const canDemote = !!onDemote;\n\n if (!canPromote && !canDemote) return null;\n\n return (\n <>\n {canPromote && (\n <button\n type=\"button\"\n className=\"gantt-tl-name-action-btn gantt-tl-action-hierarchy\"\n onClick={(e) => {\n e.stopPropagation();\n onPromote!(e);\n }}\n title=\"Повысить уровень\"\n >\n <ArrowLeft />\n </button>\n )}\n {canDemote && (\n <button\n type=\"button\"\n className=\"gantt-tl-name-action-btn gantt-tl-action-hierarchy\"\n onClick={(e) => {\n e.stopPropagation();\n onDemote!(e);\n }}\n title=\"Понизить уровень\"\n >\n <ArrowRight />\n </button>\n )}\n </>\n );\n};\n\nfunction formatDepDescription(type: LinkType, lag: number | undefined): string {\n const effectiveLag = lag ?? 0;\n\n if (type === \"FS\") {\n if (effectiveLag > 0)\n return `Начать через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0)\n return `Начать за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Начать сразу после окончания`;\n }\n if (type === \"FF\") {\n if (effectiveLag > 0)\n return `Завершить через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0)\n return `Завершить за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Завершить после окончания`;\n }\n if (type === \"SS\") {\n if (effectiveLag > 0)\n return `Начать через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0)\n return `Начать за ${Math.abs(effectiveLag)} дн. до начала`;\n return `Начать вместе с началом`;\n }\n if (type === \"SF\") {\n if (effectiveLag > 0)\n return `Завершить через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0)\n return `Завершить за ${Math.abs(effectiveLag)} дн. до начала`;\n return `Завершить до начала`;\n }\n return \"\";\n}\n\nconst DepChip: React.FC<DepChipProps> = ({\n lag,\n dep,\n taskId,\n predecessorName,\n selectedChip,\n disableDependencyEditing,\n onChipSelect,\n onRowClick,\n onScrollToTask,\n onRemoveDependency,\n onChipSelectClear,\n task,\n allTasks,\n onTasksChange,\n}) => {\n const [popoverOpen, setPopoverOpen] = useState(false);\n const lagAbs = Math.abs(lag ?? 0);\n const [inputAbs, setInputAbs] = useState(lagAbs === 0 ? \"\" : String(lagAbs));\n useEffect(() => {\n const abs = Math.abs(lag ?? 0);\n setInputAbs(abs === 0 ? \"\" : String(abs));\n }, [lag]);\n\n const isSelected =\n selectedChip?.successorId === taskId &&\n selectedChip?.predecessorId === dep.taskId &&\n selectedChip?.linkType === dep.type;\n\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (disableDependencyEditing) return;\n // Toggle popover and chip selection together\n const nextOpen = !popoverOpen;\n setPopoverOpen(nextOpen);\n if (nextOpen) {\n onChipSelect?.({\n successorId: taskId,\n predecessorId: dep.taskId,\n linkType: dep.type,\n });\n onScrollToTask?.(dep.taskId);\n } else {\n // Only clear selection when explicitly closing via chip click\n onChipSelect?.(null);\n }\n };\n\n const handleOpenChange = useCallback(\n (open: boolean) => {\n setPopoverOpen(open);\n // Don't clear selectedChip on automatic popover close (e.g. focus loss, escape)\n // Only clear when user explicitly closes via chip click or trash button\n },\n [],\n );\n\n const handleTrashClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onRemoveDependency?.(taskId, dep.taskId, dep.type);\n onChipSelectClear();\n setPopoverOpen(false);\n };\n\n const handleLagChange = useCallback(\n (newLag: number) => {\n if (!onTasksChange || !allTasks) return;\n const taskById = new Map(allTasks.map((t) => [t.id, t]));\n const predecessor = taskById.get(dep.taskId);\n if (!predecessor) return;\n\n const predStart = parseUTCDate(predecessor.startDate);\n const predEnd = parseUTCDate(predecessor.endDate);\n const origStart = parseUTCDate(task.startDate);\n const origEnd = parseUTCDate(task.endDate);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n const constraintDate = calculateSuccessorDate(\n predStart,\n predEnd,\n dep.type,\n newLag,\n );\n\n let newStart: Date, newEnd: Date;\n if (dep.type === \"FS\" || dep.type === \"SS\") {\n newStart = constraintDate;\n newEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n newEnd = constraintDate;\n newStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n onTasksChange([\n {\n ...task,\n startDate: newStart.toISOString().split(\"T\")[0],\n endDate: newEnd.toISOString().split(\"T\")[0],\n },\n ]);\n },\n [dep, task, allTasks, onTasksChange],\n );\n\n const handleInputCommit = useCallback(\n (raw: string) => {\n if (raw === \"\") {\n handleLagChange(0);\n return;\n }\n const parsed = parseInt(raw, 10);\n const effectiveLag = lag ?? 0;\n if (isNaN(parsed)) {\n const abs = Math.abs(effectiveLag);\n setInputAbs(abs === 0 ? \"\" : String(abs));\n return;\n }\n let newLag: number;\n if (parsed === 0) {\n newLag = 0;\n } else if (dep.type === \"SF\") {\n newLag = -Math.abs(parsed);\n } else {\n // sign comes from what the user typed: \"-4\" → negative, \"4\" → positive\n newLag = parsed; // parseInt preserves the sign from input\n }\n if (newLag !== effectiveLag) handleLagChange(newLag);\n },\n [lag, dep.type, handleLagChange],\n );\n\n const Icon = LINK_TYPE_ICONS[dep.type];\n const depName = predecessorName ?? dep.taskId;\n const effectiveLag = lag ?? 0;\n\n // Derive action verb, preWord and afterWhat (sign-dependent for FS/FF/SS)\n const actionVerb =\n dep.type === \"FS\" || dep.type === \"SS\" ? \"начать\" : \"завершить\";\n const zeroPlaceholder =\n dep.type === \"SF\"\n ? \"чётко\"\n : dep.type === \"FF\"\n ? \"вместе\"\n : dep.type === \"SS\"\n ? \"вместе\"\n : \"сразу\";\n let afterWhat: string;\n let preWord: string | null = null;\n if (dep.type === \"SF\") {\n afterWhat = \"до начала\";\n if (effectiveLag > 0) preWord = \"через\";\n else if (effectiveLag < 0) preWord = \"за\";\n } else if (dep.type === \"SS\") {\n afterWhat =\n effectiveLag < 0\n ? \"до начала\"\n : effectiveLag === 0\n ? \"с началом\"\n : \"после начала\";\n if (effectiveLag > 0) preWord = \"через\";\n else if (effectiveLag < 0) preWord = \"за\";\n } else {\n // FS, FF\n if (effectiveLag > 0) {\n preWord = \"через\";\n afterWhat = \"после окончания\";\n } else if (effectiveLag < 0) {\n preWord = \"за\";\n afterWhat = \"до окончания\";\n } else {\n afterWhat = \"после окончания\";\n }\n }\n\n return (\n <Popover open={popoverOpen} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <span\n className={`gantt-tl-dep-chip${isSelected ? \" gantt-tl-dep-chip-selected\" : \"\"}`}\n onClick={handleClick}\n >\n <Icon />\n {effectiveLag !== 0\n ? effectiveLag > 0\n ? `+${effectiveLag}`\n : `${effectiveLag}`\n : \"\"}\n </span>\n </PopoverTrigger>\n <PopoverContent\n className=\"gantt-tl-dep-edit-popover\"\n portal={true}\n align=\"start\"\n >\n <div onClick={(e) => e.stopPropagation()}>\n <div className=\"gantt-tl-dep-edit-task\">{task.name}</div>\n <div className=\"gantt-tl-dep-edit-row\">\n <span className=\"gantt-tl-dep-edit-label\">\n {actionVerb}\n {preWord ? ` ${preWord}` : \"\"}\n </span>\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-btn\"\n onClick={() => handleLagChange(effectiveLag - 1)}\n >\n −\n </button>\n <input\n type=\"number\"\n className=\"gantt-tl-dep-edit-input\"\n value={inputAbs}\n placeholder={zeroPlaceholder}\n min=\"0\"\n onChange={(e) => setInputAbs(e.target.value)}\n onFocus={(e) => e.target.select()}\n onBlur={(e) => handleInputCommit(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleInputCommit(inputAbs);\n }}\n />\n {!(dep.type === \"SF\" && effectiveLag === 0) && (\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-btn\"\n onClick={() => handleLagChange(effectiveLag + 1)}\n >\n +\n </button>\n )}\n {effectiveLag !== 0 && <span>д.</span>}\n <span>{afterWhat}</span>\n </div>\n <div className=\"gantt-tl-dep-edit-pred\">{depName}</div>\n {!disableDependencyEditing && (\n <>\n <hr className=\"gantt-tl-dep-edit-divider\" />\n <div className=\"gantt-tl-dep-edit-actions\">\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-close\"\n onClick={() => {\n setPopoverOpen(false);\n onChipSelectClear();\n }}\n >\n Закрыть\n </button>\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-delete\"\n onClick={handleTrashClick}\n >\n Удалить связь\n </button>\n </div>\n </>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\nexport interface TaskListRowProps {\n /** Task data to render */\n task: Task;\n /** Index of the task row (for display in № column) */\n rowIndex: number;\n /** Hierarchical task number (e.g., \"1.2.3\") */\n taskNumber?: string;\n /** Height of the task row in pixels */\n rowHeight: number;\n /** Callback when task is modified via inline edit. Receives array of changed tasks. */\n onTasksChange?: (tasks: Task[]) => void;\n /** ID of currently selected task */\n selectedTaskId?: string;\n /** Callback when task row is clicked */\n onRowClick?: (taskId: string) => void;\n /** Disable task name editing (default: false) */\n disableTaskNameEditing?: boolean;\n /** Disable dependency editing (default: false) */\n disableDependencyEditing?: boolean;\n /** All tasks (for dependency picker) */\n allTasks?: Task[];\n /** Currently active link type for new dependencies */\n activeLinkType?: LinkType;\n /** Task ID currently in predecessor-picking mode (null if not picking) */\n selectingPredecessorFor?: string | null;\n /** Callback to set the task currently in predecessor-picking mode */\n onSetSelectingPredecessorFor?: (taskId: string | null) => void;\n /** Callback to add a dependency link */\n onAddDependency?: (\n successorTaskId: string,\n predecessorTaskId: string,\n linkType: LinkType,\n ) => void;\n /** Callback to remove a dependency link */\n onRemoveDependency?: (\n taskId: string,\n predecessorTaskId: string,\n linkType: LinkType,\n ) => void;\n /** Currently selected chip (for predecessor-side delete) */\n selectedChip?: {\n successorId: string;\n predecessorId: string;\n linkType: string;\n } | null;\n /** Callback when a chip is clicked (selects it) */\n onChipSelect?: (\n chip: {\n successorId: string;\n predecessorId: string;\n linkType: LinkType;\n } | null,\n ) => void;\n /** Callback to scroll the chart grid to center this task (called when task name is clicked) */\n onScrollToTask?: (taskId: string) => void;\n /** Callback when task is deleted */\n onDelete?: (taskId: string) => void;\n /** Callback when a new task is inserted below this row */\n onAdd?: (task: Task) => void;\n /** Callback when a new task is inserted after this task */\n onInsertAfter?: (taskId: string, newTask: Task) => void;\n /** ID of task that should enter edit mode on mount (for auto-edit after insert) */\n editingTaskId?: string | null;\n /** Whether this row is currently being dragged (shows semi-transparent) */\n isDragging?: boolean;\n /** Whether this row is the current drag-over target (shows top border indicator) */\n isDragOver?: boolean;\n /** Called when drag starts on the handle for this row */\n onDragStart?: (index: number, e: React.DragEvent) => void;\n /** Called when something is dragged over this row */\n onDragOver?: (index: number, e: React.DragEvent) => void;\n /** Called when something is dropped on this row */\n onDrop?: (index: number, e: React.DragEvent) => void;\n /** Called when drag ends (drop or Escape) */\n onDragEnd?: (e: React.DragEvent) => void;\n /** Set of collapsed parent task IDs */\n collapsedParentIds?: Set<string>;\n /** Callback when collapse/expand button is clicked */\n onToggleCollapse?: (parentId: string) => void;\n /** Callback when task is promoted (parentId removed) */\n onPromoteTask?: (taskId: string) => void;\n /** Callback when task is demoted (parentId set to previous task) */\n onDemoteTask?: (taskId: string, newParentId: string) => void;\n /** Whether this child is the last sibling (affects connector icon shape) */\n isLastChild?: boolean;\n /** Nesting depth (0 = root, 1 = child, 2 = grandchild, etc.) */\n nestingDepth?: number;\n /** For each ancestor above the direct parent: true if that ancestor has more siblings below */\n ancestorContinues?: boolean[];\n /** Custom day configurations for date picker */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate for date picker */\n isWeekend?: (date: Date) => boolean;\n /** Whether this row matches the active filter highlight */\n isFilterMatch?: boolean;\n}\n\nconst toISODate = (value: string | Date): string => {\n if (value instanceof Date) return value.toISOString().split(\"T\")[0];\n // Handle full ISO strings like \"2026-02-12T00:00:00.000Z\"\n if (typeof value === \"string\" && value.includes(\"T\"))\n return value.split(\"T\")[0];\n return value as string;\n};\n\nexport const TaskListRow: React.FC<TaskListRowProps> = React.memo(\n ({\n task,\n rowIndex,\n taskNumber,\n rowHeight,\n onTasksChange,\n selectedTaskId,\n onRowClick,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n allTasks = [],\n activeLinkType,\n selectingPredecessorFor,\n onSetSelectingPredecessorFor,\n onAddDependency,\n onRemoveDependency,\n selectedChip,\n onChipSelect,\n onScrollToTask,\n onDelete,\n onAdd,\n onInsertAfter,\n editingTaskId,\n isDragging = false,\n isDragOver = false,\n onDragStart,\n onDragOver,\n onDrop,\n onDragEnd,\n collapsedParentIds = new Set(),\n onToggleCollapse,\n onPromoteTask,\n onDemoteTask,\n isLastChild = true,\n nestingDepth = 0,\n ancestorContinues = [],\n customDays,\n isWeekend,\n isFilterMatch = false,\n }) => {\n const [editingName, setEditingName] = useState(false);\n const [nameValue, setNameValue] = useState(\"\");\n const nameInputRef = useRef<HTMLInputElement>(null);\n const [editingDuration, setEditingDuration] = useState(false);\n const [durationValue, setDurationValue] = useState(\n getInclusiveDurationDays(task.startDate, task.endDate),\n );\n const durationInputRef = useRef<HTMLInputElement>(null);\n const [editingProgress, setEditingProgress] = useState(false);\n const [progressValue, setProgressValue] = useState(0);\n const progressInputRef = useRef<HTMLInputElement>(null);\n const [overflowOpen, setOverflowOpen] = useState(false);\n const nameConfirmedRef = useRef(false); // Prevent double-save on Enter + blur\n const durationConfirmedRef = useRef(false); // Prevent double-save on Enter + blur\n const progressConfirmedRef = useRef(false); // Prevent double-save on Enter + blur\n const autoEditedForRef = useRef<string | null>(null); // Track which editingTaskId we already auto-entered for\n const editTriggerRef = useRef<\"keypress\" | \"doubleclick\" | \"autoedit\">(\n \"doubleclick\",\n ); // How editing was started\n const [deletePending, setDeletePending] = useState(false);\n const deleteButtonRef = useRef<HTMLButtonElement>(null);\n\n const isSelected = selectedTaskId === task.id;\n\n // Hierarchy computed values\n const isParent = useMemo(\n () => isTaskParent(task.id, allTasks),\n [task.id, allTasks],\n );\n const isChild = task.parentId !== undefined;\n\n // Create custom weekend predicate from props (memoized for performance)\n const weekendPredicate = useMemo(\n () => createCustomDayPredicate({ customDays, isWeekend }),\n [customDays, isWeekend]\n );\n const isCollapsed = collapsedParentIds.has(task.id);\n\n // Picker mode flags for this row\n const isPicking = selectingPredecessorFor != null;\n const isSourceRow = isPicking && selectingPredecessorFor === task.id;\n\n // Chip data: compute effective lag from actual dates (always correct, even on initial load)\n const chips = useMemo(() => {\n const succStart = new Date(task.startDate as string);\n const succEnd = new Date(task.endDate as string);\n const taskById = new Map((allTasks ?? []).map((t) => [t.id, t]));\n return (task.dependencies ?? []).map((dep) => {\n const pred = taskById.get(dep.taskId);\n const lag = pred\n ? computeLagFromDates(\n dep.type,\n new Date(pred.startDate as string),\n new Date(pred.endDate as string),\n succStart,\n succEnd,\n )\n : (dep.lag ?? 0);\n return { dep, lag, predecessorName: pred?.name ?? dep.taskId };\n });\n }, [task.dependencies, task.startDate, task.endDate, allTasks]);\n\n const linkWord = chips.length <= 4 ? \"связи\" : \"связей\";\n\n useEffect(() => {\n if (editingName && nameInputRef.current) {\n nameInputRef.current.focus();\n if (editTriggerRef.current === \"keypress\") {\n // Cursor to end — the typed char is already in the input, don't select it\n const len = nameInputRef.current.value.length;\n nameInputRef.current.setSelectionRange(len, len);\n } else {\n // Double-click or auto-edit-on-insert: select all for easy replacement\n nameInputRef.current.select();\n }\n }\n }, [editingName]);\n\n // Reset delete confirmation when clicking elsewhere\n useEffect(() => {\n const handleMouseDownOutside = (event: MouseEvent) => {\n if (\n deletePending &&\n deleteButtonRef.current &&\n !deleteButtonRef.current.contains(event.target as Node)\n ) {\n setDeletePending(false);\n }\n };\n\n if (deletePending) {\n document.addEventListener(\"mousedown\", handleMouseDownOutside);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleMouseDownOutside);\n };\n }, [deletePending]);\n\n // Auto-enter edit mode when this task is created via insert.\n // We track which editingTaskId we already reacted to (autoEditedForRef) so that\n // subsequent re-renders caused by saving the name (which changes task.name) do NOT\n // re-trigger edit mode. Without this guard, saving the name → onTasksChange → new task.name\n // → re-render → effect fires again → edit mode re-entered → user must press Enter twice.\n useEffect(() => {\n if (\n editingTaskId === task.id &&\n !disableTaskNameEditing &&\n autoEditedForRef.current !== editingTaskId\n ) {\n autoEditedForRef.current = editingTaskId;\n nameConfirmedRef.current = false; // Reset stale flag from any previous Enter-key save\n editTriggerRef.current = \"autoedit\";\n setNameValue(task.name);\n setEditingName(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editingTaskId, task.id, disableTaskNameEditing]);\n\n const handleNameClick = useCallback(\n (e: React.MouseEvent) => {\n if (disableTaskNameEditing) return;\n e.stopPropagation();\n onRowClick?.(task.id);\n onScrollToTask?.(task.id);\n },\n [task.id, disableTaskNameEditing, onRowClick, onScrollToTask],\n );\n\n const handleNameDoubleClick = useCallback(\n (e: React.MouseEvent) => {\n if (disableTaskNameEditing) return;\n e.stopPropagation();\n nameConfirmedRef.current = false; // Reset stale flag from any previous Enter-key save\n editTriggerRef.current = \"doubleclick\";\n setNameValue(task.name);\n setEditingName(true);\n },\n [task.name, disableTaskNameEditing],\n );\n\n const handleRowKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n // Don't handle row keyboard events when editing progress\n if (editingProgress) return;\n // F2: enter edit mode with cursor at end of existing name\n if (!editingName && !disableTaskNameEditing && e.key === \"F2\") {\n e.preventDefault();\n nameConfirmedRef.current = false; // Reset stale flag from any previous Enter-key save\n editTriggerRef.current = \"keypress\"; // 'keypress' trigger = cursor at end (not select-all)\n setNameValue(task.name);\n setEditingName(true);\n return;\n }\n },\n [editingName, disableTaskNameEditing, task.name],\n );\n\n const handleNameSave = useCallback(() => {\n if (nameConfirmedRef.current) {\n // Already saved via Enter key, skip blur handler\n nameConfirmedRef.current = false;\n return;\n }\n if (nameValue.trim()) {\n onTasksChange?.([{ ...task, name: nameValue.trim() }]);\n }\n setEditingName(false);\n }, [nameValue, task, onTasksChange]);\n\n const handleNameCancel = useCallback(() => {\n setEditingName(false);\n }, []);\n\n const handleNameKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n nameConfirmedRef.current = true; // Mark as saved to prevent blur from triggering again\n if (nameValue.trim()) {\n onTasksChange?.([{ ...task, name: nameValue.trim() }]);\n }\n setEditingName(false);\n } else if (e.key === \"Escape\") {\n handleNameCancel();\n }\n },\n [nameValue, task, onTasksChange, handleNameCancel],\n );\n\n const handleDurationClick = useCallback(\n (e: React.MouseEvent) => {\n if (task.locked) return;\n e.stopPropagation();\n durationConfirmedRef.current = false;\n setDurationValue(\n getInclusiveDurationDays(task.startDate, task.endDate),\n );\n setEditingDuration(true);\n },\n [task.locked, task.startDate, task.endDate],\n );\n\n const applyDurationChange = useCallback((nextDuration: number) => {\n const normalizedDuration = Math.max(1, Math.round(nextDuration) || 1);\n setDurationValue(normalizedDuration);\n }, []);\n\n const handleDurationSave = useCallback(() => {\n if (durationConfirmedRef.current) {\n durationConfirmedRef.current = false;\n return;\n }\n const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);\n onTasksChange?.([\n {\n ...task,\n endDate: getEndDateFromDuration(task.startDate, normalizedDuration),\n },\n ]);\n setEditingDuration(false);\n }, [durationValue, task, onTasksChange]);\n\n const handleDurationCancel = useCallback(() => {\n setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));\n setEditingDuration(false);\n }, [task.startDate, task.endDate]);\n\n const handleDurationAdjust = useCallback(\n (delta: number) => {\n applyDurationChange(durationValue + delta);\n },\n [applyDurationChange, durationValue],\n );\n\n const handleDurationKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n durationConfirmedRef.current = true;\n const normalizedDuration = Math.max(\n 1,\n Math.round(durationValue) || 1,\n );\n onTasksChange?.([\n {\n ...task,\n endDate: getEndDateFromDuration(\n task.startDate,\n normalizedDuration,\n ),\n },\n ]);\n setEditingDuration(false);\n } else if (e.key === \"Escape\") {\n handleDurationCancel();\n }\n },\n [durationValue, task, onTasksChange, handleDurationCancel],\n );\n\n const handleProgressClick = useCallback(\n (e: React.MouseEvent) => {\n if (task.locked) return;\n e.stopPropagation();\n progressConfirmedRef.current = false;\n setProgressValue(task.progress ?? 0);\n setEditingProgress(true);\n },\n [task.progress, task.locked],\n );\n\n const handleProgressSave = useCallback(() => {\n if (progressConfirmedRef.current) {\n progressConfirmedRef.current = false;\n return;\n }\n const clampedValue = Math.max(0, Math.min(100, progressValue));\n\n // Cascade 100% or 0% progress to all children when parent is marked complete/reset\n if (\n (clampedValue === 100 || clampedValue === 0) &&\n isTaskParent(task.id, allTasks)\n ) {\n const children = getChildren(task.id, allTasks);\n const updatedTasks = [\n { ...task, progress: clampedValue },\n ...children.map((child) => ({ ...child, progress: clampedValue })),\n ];\n onTasksChange?.(updatedTasks);\n } else {\n onTasksChange?.([{ ...task, progress: clampedValue }]);\n }\n setEditingProgress(false);\n }, [progressValue, task, onTasksChange, allTasks]);\n\n const handleProgressCancel = useCallback(() => {\n setEditingProgress(false);\n }, []);\n\n const handleProgressAdjust = useCallback((delta: number) => {\n setProgressValue((current) =>\n Math.max(0, Math.min(100, current + delta)),\n );\n }, []);\n\n const handleProgressKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n e.stopPropagation(); // Prevent row-level keyboard handler from interfering\n if (e.key === \"Enter\") {\n progressConfirmedRef.current = true;\n const clampedValue = Math.max(0, Math.min(100, progressValue));\n\n // Cascade 100% or 0% progress to all children when parent is marked complete/reset\n if (\n (clampedValue === 100 || clampedValue === 0) &&\n isTaskParent(task.id, allTasks)\n ) {\n const children = getChildren(task.id, allTasks);\n const updatedTasks = [\n { ...task, progress: clampedValue },\n ...children.map((child) => ({\n ...child,\n progress: clampedValue,\n })),\n ];\n onTasksChange?.(updatedTasks);\n } else {\n onTasksChange?.([{ ...task, progress: clampedValue }]);\n }\n setEditingProgress(false);\n } else if (e.key === \"Escape\") {\n handleProgressCancel();\n }\n },\n [progressValue, task, onTasksChange, handleProgressCancel, allTasks],\n );\n\n useEffect(() => {\n if (editingProgress && progressInputRef.current) {\n progressInputRef.current.focus();\n progressInputRef.current.select();\n }\n }, [editingProgress]);\n\n useEffect(() => {\n setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));\n }, [task.startDate, task.endDate]);\n\n useEffect(() => {\n if (editingDuration && durationInputRef.current) {\n durationInputRef.current.focus();\n durationInputRef.current.select();\n }\n }, [editingDuration]);\n\n // Both date pickers shift the whole task (preserving duration), same as drag-move\n // Also normalizes dates to ensure startDate is always before or equal to endDate\n const handleStartDateChange = useCallback(\n (newDateISO: string) => {\n if (!newDateISO) return;\n const origStart = parseUTCDate(task.startDate);\n const origEnd = parseUTCDate(task.endDate);\n const durationMs = origEnd.getTime() - origStart.getTime();\n const newStart = new Date(newDateISO + \"T00:00:00Z\");\n const newEnd = new Date(newStart.getTime() + durationMs);\n const { startDate: normalizedStart, endDate: normalizedEnd } =\n normalizeTaskDates(newDateISO, newEnd.toISOString().split(\"T\")[0]);\n onTasksChange?.([\n { ...task, startDate: normalizedStart, endDate: normalizedEnd },\n ]);\n },\n [task, onTasksChange],\n );\n\n const handleEndDateChange = useCallback(\n (newDateISO: string) => {\n if (!newDateISO) return;\n const origStart = parseUTCDate(task.startDate);\n const origEnd = parseUTCDate(task.endDate);\n const durationMs = origEnd.getTime() - origStart.getTime();\n const newEnd = new Date(newDateISO + \"T00:00:00Z\");\n const newStart = new Date(newEnd.getTime() - durationMs);\n const { startDate: normalizedStart, endDate: normalizedEnd } =\n normalizeTaskDates(newStart.toISOString().split(\"T\")[0], newDateISO);\n onTasksChange?.([\n { ...task, startDate: normalizedStart, endDate: normalizedEnd },\n ]);\n },\n [task, onTasksChange],\n );\n\n const handleRowClickInternal = useCallback(() => {\n onRowClick?.(task.id);\n }, [task.id, onRowClick]);\n\n const handleNumberClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onRowClick?.(task.id);\n },\n [task.id, onRowClick],\n );\n\n const handleToggleCollapse = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onToggleCollapse?.(task.id);\n },\n [task.id, onToggleCollapse],\n );\n\n // Hierarchy handlers - promote/demote\n const handlePromote = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onPromoteTask?.(task.id);\n },\n [task.id, onPromoteTask],\n );\n\n const handleDemote = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n // The parent calculation is done in TaskList.tsx's handleDemoteWrapper,\n // which has access to the ordered visible task list and implements the\n // \"previous visible task becomes parent\" principle.\n // Pass empty string as placeholder — the wrapper ignores this value.\n onDemoteTask?.(task.id, \"\");\n },\n [task.id, onDemoteTask],\n );\n\n // Dependency handlers\n const handleAddClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onSetSelectingPredecessorFor?.(task.id);\n },\n [task.id, onSetSelectingPredecessorFor],\n );\n\n const handlePredecessorPick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!isPicking || isSourceRow) return;\n if (!selectingPredecessorFor || !activeLinkType) return;\n onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);\n },\n [\n isPicking,\n isSourceRow,\n selectingPredecessorFor,\n task.id,\n activeLinkType,\n onAddDependency,\n ],\n );\n\n const handleCancelPicking = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onSetSelectingPredecessorFor?.(null);\n },\n [onSetSelectingPredecessorFor],\n );\n\n // True when this row is the predecessor for the currently selected chip\n const isSelectedPredecessor =\n selectedChip != null && selectedChip.predecessorId === task.id;\n\n // Delete the selected dependency from the predecessor row's \"Удалить\" button\n const handleDeleteSelected = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selectedChip) return;\n onRemoveDependency?.(\n selectedChip.successorId,\n selectedChip.predecessorId,\n selectedChip.linkType as LinkType,\n );\n onChipSelect?.(null);\n },\n [selectedChip?.successorId, selectedChip?.predecessorId, selectedChip?.linkType, onRemoveDependency, onChipSelect],\n );\n\n const startDateISO = toISODate(task.startDate);\n const endDateISO = editingDuration\n ? getEndDateFromDuration(task.startDate, durationValue)\n : toISODate(task.endDate);\n\n return (\n <div\n data-filter-match={isFilterMatch ? 'true' : 'false'}\n className={[\n \"gantt-tl-row\",\n isFilterMatch ? \"gantt-tl-row-filter-match\" : \"\",\n isSelected ? \"gantt-tl-row-selected\" : \"\",\n isPicking && !isSourceRow ? \"gantt-tl-row-picking\" : \"\",\n isSourceRow ? \"gantt-tl-row-picking-self\" : \"\",\n isDragging ? \"gantt-tl-row-dragging\" : \"\",\n isDragOver ? \"gantt-tl-row-drag-over\" : \"\",\n isChild ? \"gantt-tl-row-child\" : \"\",\n isParent ? \"gantt-tl-row-parent\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ minHeight: `${rowHeight}px`, position: \"relative\" }}\n onClick={handleRowClickInternal}\n onKeyDown={handleRowKeyDown}\n onDragOver={(e) => onDragOver?.(rowIndex, e)}\n onDrop={(e) => onDrop?.(rowIndex, e)}\n onMouseLeave={() => {\n if (deletePending) {\n setDeletePending(false);\n }\n }}\n tabIndex={isSelected ? 0 : -1}\n >\n {/* Number column — click selects the row */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-number\"\n onClick={handleNumberClick}\n >\n <span\n className=\"gantt-tl-drag-handle\"\n draggable={true}\n onDragStart={(e) => {\n e.stopPropagation();\n onDragStart?.(rowIndex, e);\n }}\n onDragEnd={(e) => onDragEnd?.(e)}\n onClick={(e) => e.stopPropagation()}\n >\n <DragHandleIcon />\n </span>\n <span className=\"gantt-tl-num-label\">\n {taskNumber || rowIndex + 1}\n </span>\n </div>\n\n {/* Name column — styled Input overlay on edit */}\n <div className=\"gantt-tl-cell gantt-tl-cell-name\">\n {isChild && !editingName && (\n <>\n {/* Ancestor continuation lines — full-height vertical bars for each ongoing ancestor level */}\n {ancestorContinues.map((continues, idx) =>\n continues ? (\n <span\n key={idx}\n style={{\n position: \"absolute\",\n left: `${idx * 20 + 9}px`,\n top: 0,\n height: `${rowHeight}px`,\n width: \"1.5px\",\n background: \"#d4bceb\",\n borderRadius: \"1px\",\n pointerEvents: \"none\",\n }}\n />\n ) : null,\n )}\n {/* Own vline — full height if not last child, half if last (L-shape) */}\n <span\n style={{\n position: \"absolute\",\n left: `${(nestingDepth - 1) * 20 + 9}px`,\n top: 0,\n height: isLastChild ? `${rowHeight / 2}px` : `${rowHeight}px`,\n width: \"1.5px\",\n background: \"#d4bceb\",\n borderRadius: \"1px\",\n pointerEvents: \"none\",\n }}\n />\n {/* Horizontal branch */}\n <span\n style={{\n position: \"absolute\",\n left: `${(nestingDepth - 1) * 20 + 9}px`,\n top: `${rowHeight / 2 - 0.75}px`,\n width: \"8px\",\n height: \"1.5px\",\n background: \"#d4bceb\",\n borderRadius: \"1px\",\n pointerEvents: \"none\",\n }}\n />\n {/* End dot */}\n <span\n style={{\n position: \"absolute\",\n left: `${(nestingDepth - 1) * 20 + 15}px`,\n top: `${rowHeight / 2 - 2}px`,\n width: \"4px\",\n height: \"4px\",\n borderRadius: \"50%\",\n background: \"#d4bceb\",\n pointerEvents: \"none\",\n }}\n />\n </>\n )}\n {isParent && !editingName && (\n <button\n type=\"button\"\n className={`gantt-tl-collapse-btn ${isCollapsed ? \"gantt-tl-collapse-btn-collapsed\" : \"\"}`}\n onClick={handleToggleCollapse}\n style={{ left: `${nestingDepth * 20 + 4}px` }}\n aria-label={isCollapsed ? \"Expand children\" : \"Collapse children\"}\n >\n <ChevronRightIcon />\n </button>\n )}\n {editingName && (\n <Input\n ref={nameInputRef}\n type=\"text\"\n value={nameValue}\n onChange={(e) => setNameValue(e.target.value)}\n onBlur={handleNameSave}\n onKeyDown={handleNameKeyDown}\n className=\"gantt-tl-name-input\"\n style={{\n paddingLeft:\n nestingDepth > 0 ? `${nestingDepth * 20 + 24}px` : undefined,\n }}\n onClick={(e) => e.stopPropagation()}\n />\n )}\n <button\n type=\"button\"\n className={[\n \"gantt-tl-name-trigger\",\n disableTaskNameEditing ? \"gantt-tl-name-locked\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n title={task.name}\n onClick={handleNameClick}\n onDoubleClick={handleNameDoubleClick}\n style={{\n paddingLeft:\n nestingDepth > 0\n ? `${nestingDepth * 20 + (isParent ? 26 : 8)}px`\n : isParent\n ? \"26px\"\n : undefined,\n ...(editingName\n ? { visibility: \"hidden\", pointerEvents: \"none\" }\n : undefined),\n }}\n >\n {task.name}\n </button>\n {!editingName && (\n <div className=\"gantt-tl-name-actions\">\n {onInsertAfter && (\n <button\n type=\"button\"\n className=\"gantt-tl-name-action-btn gantt-tl-action-insert\"\n onClick={(e) => {\n e.stopPropagation();\n const now = new Date();\n const todayISO = new Date(\n Date.UTC(\n now.getUTCFullYear(),\n now.getUTCMonth(),\n now.getUTCDate(),\n ),\n )\n .toISOString()\n .split(\"T\")[0];\n const endISO = new Date(\n Date.UTC(\n now.getUTCFullYear(),\n now.getUTCMonth(),\n now.getUTCDate() + 7,\n ),\n )\n .toISOString()\n .split(\"T\")[0];\n const newTask: Task = {\n id: crypto.randomUUID(),\n name: \"Новая задача\",\n startDate: todayISO,\n endDate: endISO,\n };\n onInsertAfter(task.id, newTask);\n }}\n aria-label=\"Вставить задачу после этой\"\n >\n <PlusIcon />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n ref={deleteButtonRef}\n className={`gantt-tl-name-action-btn gantt-tl-action-delete${deletePending ? \" gantt-tl-action-delete-confirm\" : \"\"}`}\n onClick={(e) => {\n e.stopPropagation();\n if (!deletePending) {\n setDeletePending(true);\n } else {\n setDeletePending(false);\n onDelete(task.id);\n }\n }}\n aria-label=\"Удалить задачу\"\n >\n {deletePending ? \"Удалить?\" : <TrashIcon />}\n </button>\n )}\n <HierarchyButton\n isChild={isChild}\n rowIndex={rowIndex}\n onPromote={onPromoteTask ? handlePromote : undefined}\n onDemote={onDemoteTask ? handleDemote : undefined}\n />\n </div>\n )}\n </div>\n\n {/* Start Date — DatePicker component */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-date\"\n onClick={(e) => e.stopPropagation()}\n >\n <DatePicker\n value={startDateISO}\n onChange={handleStartDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n isWeekend={weekendPredicate}\n />\n </div>\n\n {/* End Date — DatePicker component */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-date\"\n onClick={(e) => e.stopPropagation()}\n >\n <DatePicker\n value={endDateISO}\n onChange={handleEndDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n isWeekend={weekendPredicate}\n />\n </div>\n\n {/* Duration column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-duration\"\n onClick={handleDurationClick}\n >\n {editingDuration && (\n <div\n className=\"gantt-tl-number-editor\"\n onClick={(e) => e.stopPropagation()}\n >\n <Input\n ref={durationInputRef}\n type=\"number\"\n min={1}\n step={1}\n value={durationValue}\n onChange={(e) =>\n applyDurationChange(parseInt(e.target.value, 10) || 1)\n }\n onBlur={handleDurationSave}\n onKeyDown={handleDurationKeyDown}\n className=\"gantt-tl-number-input\"\n />\n <div className=\"gantt-tl-number-steppers\" aria-hidden=\"true\">\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleDurationAdjust(1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleDurationAdjust(-1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n </div>\n )}\n <span\n style={\n editingDuration\n ? { visibility: \"hidden\", pointerEvents: \"none\" }\n : undefined\n }\n >\n {getInclusiveDurationDays(task.startDate, task.endDate)}д\n </span>\n </div>\n\n {/* Progress column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-progress\"\n onClick={handleProgressClick}\n >\n {editingProgress && (\n <div\n className=\"gantt-tl-number-editor\"\n onClick={(e) => e.stopPropagation()}\n >\n <Input\n ref={progressInputRef}\n type=\"number\"\n min={0}\n max={100}\n step={1}\n value={progressValue}\n onChange={(e) =>\n setProgressValue(parseInt(e.target.value, 10) || 0)\n }\n onBlur={handleProgressSave}\n onKeyDown={handleProgressKeyDown}\n className=\"gantt-tl-number-input\"\n />\n <div className=\"gantt-tl-number-steppers\" aria-hidden=\"true\">\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleProgressAdjust(1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleProgressAdjust(-1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n </div>\n )}\n <span\n style={\n editingProgress\n ? { visibility: \"hidden\", pointerEvents: \"none\" }\n : task.progress === 100\n ? {\n backgroundColor: \"#17c864\",\n borderRadius: \"4px\",\n padding: \"2px 4px\",\n color: \"#ffffff\",\n }\n : undefined\n }\n >\n {task.progress\n ? Math.round(task.progress) === 100\n ? \"100\"\n : `${Math.round(task.progress)}%`\n : \"-\"}\n </span>\n </div>\n\n {/* Dependencies column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-deps\"\n onClick={\n isSourceRow\n ? handleCancelPicking\n : isPicking\n ? handlePredecessorPick\n : undefined\n }\n >\n {isSourceRow ? (\n <span className=\"gantt-tl-dep-source-hint\">Выберите задачу</span>\n ) : isSelectedPredecessor && !disableDependencyEditing ? (\n /* Full-replacement: \"Зависит от [name]\" → hover → \"Удалить\" */\n <button\n type=\"button\"\n className=\"gantt-tl-dep-delete-label\"\n onClick={handleDeleteSelected}\n aria-label=\"Удалить связь\"\n >\n <span className=\"gantt-tl-dep-delete-label-default\">\n Связано с\n </span>\n <span className=\"gantt-tl-dep-delete-label-hover\">× удалить</span>\n </button>\n ) : (\n <>\n {chips.length >= 2 ? (\n /* 2+ deps — show only \"N связей\" summary chip that opens a popover */\n <Popover open={overflowOpen} onOpenChange={setOverflowOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n className=\"gantt-tl-dep-summary-chip\"\n onClick={(e) => {\n e.stopPropagation();\n setOverflowOpen((v) => !v);\n }}\n >\n {chips.length} {linkWord}\n </button>\n </PopoverTrigger>\n <PopoverContent portal={true} align=\"start\">\n <div\n className=\"gantt-tl-dep-overflow-list\"\n onClick={(e) => e.stopPropagation()}\n >\n {chips.map(({ dep, lag, predecessorName }) => (\n <DepChip\n key={`${dep.taskId}-${dep.type}`}\n lag={lag}\n dep={dep}\n taskId={task.id}\n predecessorName={predecessorName}\n selectedChip={selectedChip}\n disableDependencyEditing={disableDependencyEditing}\n onChipSelect={onChipSelect}\n onRowClick={onRowClick}\n onScrollToTask={onScrollToTask}\n onRemoveDependency={onRemoveDependency}\n onChipSelectClear={() => onChipSelect?.(null)}\n task={task}\n allTasks={allTasks}\n onTasksChange={onTasksChange}\n />\n ))}\n </div>\n </PopoverContent>\n </Popover>\n ) : chips.length === 1 ? (\n /* Single chip — unified DepChip */\n <DepChip\n lag={chips[0].lag}\n dep={chips[0].dep}\n taskId={task.id}\n predecessorName={chips[0].predecessorName}\n selectedChip={selectedChip}\n disableDependencyEditing={disableDependencyEditing}\n onChipSelect={onChipSelect}\n onRowClick={onRowClick}\n onScrollToTask={onScrollToTask}\n onRemoveDependency={onRemoveDependency}\n onChipSelectClear={() => onChipSelect?.(null)}\n task={task}\n allTasks={allTasks}\n onTasksChange={onTasksChange}\n />\n ) : null}\n\n {/* \"+\" add dependency button — hidden in picker mode and when editing disabled, hover-reveal */}\n {!disableDependencyEditing && !isPicking && (\n <button\n type=\"button\"\n className={`gantt-tl-dep-add gantt-tl-dep-add-hover${selectedChip ? \" gantt-tl-dep-add-hidden\" : \"\"}`}\n onClick={handleAddClick}\n aria-label=\"Добавить связь\"\n >\n +\n </button>\n )}\n </>\n )}\n </div>\n </div>\n );\n },\n);\n\nTaskListRow.displayName = \"TaskListRow\";\nexport default TaskListRow;\n","'use client';\n\nimport React from 'react';\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n /** Additional CSS class names */\n className?: string;\n}\n\n/**\n * Styled text input component using gantt-lib CSS variables\n */\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, ...props }, ref) => {\n return (\n <input\n ref={ref}\n className={`gantt-input${className ? ` ${className}` : ''}`}\n {...props}\n />\n );\n }\n);\n\nInput.displayName = 'Input';\nexport default Input;\n","'use client';\n\nimport React, { useState, useCallback, useEffect, useRef } from 'react';\nimport { format, isValid, parse, addDays, addMonths, addYears, subMonths, subYears, subDays } from 'date-fns';\nimport { Calendar } from './Calendar';\nimport { Popover, PopoverTrigger, PopoverContent } from './Popover';\n\nexport interface DatePickerProps {\n /** Current date value as ISO string (YYYY-MM-DD) */\n value?: string;\n /** Callback with new ISO date string (YYYY-MM-DD) when date is selected */\n onChange?: (isoDate: string) => void;\n /** Display format for the input (default: dd.MM.yyyy) */\n format?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether to use portal for popover (default: true) */\n portal?: boolean;\n /** Additional CSS class names for the trigger button */\n className?: string;\n /** Whether the picker is disabled */\n disabled?: boolean;\n /** Optional predicate for custom weekend logic */\n isWeekend?: (date: Date) => boolean;\n}\n\nconst segments = [\n { start: 0, end: 2, label: 'day', max: 31 },\n { start: 3, end: 5, label: 'month', max: 12 },\n { start: 6, end: 8, label: 'year', max: 99 },\n];\n\n/**\n * DatePicker component — shows formatted date as a button, opens calendar popup on click.\n * The popup includes a keyboard-navigable date input field above the calendar.\n * Accepts and returns ISO date strings (YYYY-MM-DD)\n */\nexport const DatePicker: React.FC<DatePickerProps> = ({\n value,\n onChange,\n format: displayFormat = 'dd.MM.yyyy',\n placeholder = 'Pick a date',\n portal = true,\n className,\n disabled = false,\n isWeekend,\n}) => {\n const [open, setOpen] = useState(false);\n const [inputValue, setInputValue] = useState('');\n const dateInputRef = useRef<HTMLInputElement>(null);\n // Refs для синхронного отслеживания позиции — не зависят от DOM/rAF\n const segIdxRef = useRef(0); // текущий сегмент (0=day, 1=month, 2=year)\n const charPosRef = useRef(0); // позиция внутри сегмента (0 или 1)\n\n // Parse ISO string to Date for calendar\n const selectedDate: Date | undefined = (() => {\n if (!value) return undefined;\n const d = new Date(value + 'T00:00:00Z');\n return isValid(d) ? d : undefined;\n })();\n\n // Format Date for display on trigger button\n const displayValue = selectedDate\n ? format(selectedDate, displayFormat)\n : placeholder;\n\n // Sync inputValue with prop value\n useEffect(() => {\n if (value) {\n const d = new Date(value + 'T00:00:00Z');\n if (isValid(d)) setInputValue(format(d, 'dd.MM.yy'));\n } else {\n setInputValue('');\n }\n }, [value]);\n\n // Выделить сегмент по индексу (визуально)\n const selectSegByIdx = useCallback((idx: number) => {\n if (!dateInputRef.current) return;\n const seg = segments[idx] ?? segments[0];\n dateInputRef.current.setSelectionRange(seg.start, seg.end);\n }, []);\n\n // Auto-focus input when popup opens\n useEffect(() => {\n if (open) {\n setTimeout(() => {\n if (dateInputRef.current) {\n segIdxRef.current = 0;\n charPosRef.current = 0;\n dateInputRef.current.focus();\n selectSegByIdx(0);\n }\n }, 50);\n }\n }, [open, selectSegByIdx]);\n\n const handleFocus = () => {\n setTimeout(() => {\n segIdxRef.current = 0;\n charPosRef.current = 0;\n selectSegByIdx(0);\n }, 0);\n };\n\n const handleMouseDown = () => {\n setTimeout(() => {\n const pos = dateInputRef.current?.selectionStart ?? 0;\n const idx = segments.findIndex(s => pos >= s.start && pos <= s.end);\n segIdxRef.current = idx >= 0 ? idx : 0;\n charPosRef.current = 0;\n selectSegByIdx(segIdxRef.current);\n }, 0);\n };\n\n const updateFromDate = useCallback((newDate: Date) => {\n if (!isValid(newDate)) return;\n setInputValue(format(newDate, 'dd.MM.yy'));\n const iso = [\n newDate.getFullYear(),\n String(newDate.getMonth() + 1).padStart(2, '0'),\n String(newDate.getDate()).padStart(2, '0'),\n ].join('-');\n onChange?.(iso);\n }, [onChange]);\n\n const handleCalendarSelect = useCallback(\n (day: Date) => {\n updateFromDate(day);\n setOpen(false);\n },\n [updateFromDate]\n );\n\n const handleDayShift = useCallback(\n (delta: number) => {\n const base = selectedDate ?? new Date();\n updateFromDate(addDays(base, delta));\n },\n [selectedDate, updateFromDate]\n );\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!dateInputRef.current) return;\n const { value: inputVal } = dateInputRef.current;\n\n // Читаем сегмент из рефа — всегда актуально, даже при быстром вводе\n const segIdx = segIdxRef.current;\n const seg = segments[segIdx] ?? segments[0];\n\n if (e.key === 'Tab') return;\n\n if (e.key === 'Escape') {\n e.preventDefault(); e.stopPropagation();\n setOpen(false);\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault(); e.stopPropagation();\n setOpen(false);\n return;\n }\n\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault(); e.stopPropagation();\n const base = selectedDate ?? new Date();\n let newDate = base;\n if (seg.label === 'day') newDate = e.key === 'ArrowUp' ? addDays(base, 1) : subDays(base, 1);\n if (seg.label === 'month') newDate = e.key === 'ArrowUp' ? addMonths(base, 1) : subMonths(base, 1);\n if (seg.label === 'year') newDate = e.key === 'ArrowUp' ? addYears(base, 1) : subYears(base, 1);\n charPosRef.current = 0;\n updateFromDate(newDate);\n requestAnimationFrame(() => selectSegByIdx(segIdx));\n return;\n }\n\n if (e.key === 'Backspace' || e.key === 'Delete') {\n e.preventDefault(); e.stopPropagation();\n const chars = inputVal.split('');\n for (let i = seg.start; i < seg.end; i++) chars[i] = '0';\n charPosRef.current = 0;\n setInputValue(chars.join(''));\n requestAnimationFrame(() => selectSegByIdx(segIdx));\n return;\n }\n\n if (e.key === 'ArrowRight') {\n e.preventDefault(); e.stopPropagation();\n const next = segIdx + 1 < segments.length ? segIdx + 1 : 0;\n segIdxRef.current = next;\n charPosRef.current = 0;\n selectSegByIdx(next);\n return;\n }\n\n if (e.key === 'ArrowLeft') {\n e.preventDefault(); e.stopPropagation();\n const prev = segIdx - 1 >= 0 ? segIdx - 1 : segments.length - 1;\n segIdxRef.current = prev;\n charPosRef.current = 0;\n selectSegByIdx(prev);\n return;\n }\n\n if (/^\\d$/.test(e.key)) {\n e.preventDefault(); e.stopPropagation();\n const charPos = charPosRef.current;\n const charIndex = seg.start + charPos;\n const chars = inputVal.split('');\n\n // На первой позиции сегмента — сбрасываем вторую цифру\n if (charPos === 0) {\n for (let i = seg.start + 1; i < seg.end; i++) chars[i] = '0';\n }\n chars[charIndex] = e.key;\n\n const segStr = chars.slice(seg.start, seg.end).join('');\n const segVal = parseInt(segStr, 10);\n\n if (seg.label === 'month' && charPos === 0 && parseInt(e.key) > 1) return;\n if (seg.label === 'day' && charPos === 0 && parseInt(e.key) > 3) return;\n if (segVal > seg.max) return;\n\n const updated = chars.join('');\n setInputValue(updated);\n\n const segLen = seg.end - seg.start;\n if (charPos + 1 < segLen) {\n // Ещё не заполнили сегмент — двигаемся внутри\n charPosRef.current = charPos + 1;\n requestAnimationFrame(() => {\n dateInputRef.current?.setSelectionRange(charIndex + 1, seg.end);\n });\n } else {\n // Сегмент заполнен — переходим к следующему\n const nextIdx = segIdx + 1 < segments.length ? segIdx + 1 : segIdx;\n segIdxRef.current = nextIdx;\n charPosRef.current = 0;\n requestAnimationFrame(() => selectSegByIdx(nextIdx));\n }\n\n const parsed = parse(updated, 'dd.MM.yy', new Date());\n if (isValid(parsed) && !updated.includes('00.00')) {\n updateFromDate(parsed);\n }\n }\n }, [selectedDate, updateFromDate, selectSegByIdx]);\n\n return (\n <Popover open={open} onOpenChange={disabled ? undefined : setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n className={`gantt-datepicker-trigger${className ? ` ${className}` : ''}`}\n disabled={disabled}\n onClick={(e) => {\n e.stopPropagation();\n }}\n >\n {displayValue}\n </button>\n </PopoverTrigger>\n <PopoverContent\n portal={portal}\n align=\"start\"\n side=\"bottom\"\n >\n <div className=\"gantt-datepicker-input-row\">\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(-7)} tabIndex={-1}>-7</button>\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(-1)} tabIndex={-1}>-1</button>\n <input\n ref={dateInputRef}\n type=\"text\"\n className=\"gantt-datepicker-date-input\"\n value={inputValue}\n onChange={() => {}}\n onFocus={handleFocus}\n onMouseDown={handleMouseDown}\n onKeyDown={handleKeyDown}\n spellCheck={false}\n autoComplete=\"off\"\n />\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(1)} tabIndex={-1}>+1</button>\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(7)} tabIndex={-1}>+7</button>\n </div>\n <Calendar\n mode=\"single\"\n selected={selectedDate}\n onSelect={handleCalendarSelect}\n initialDate={selectedDate}\n isWeekend={isWeekend}\n />\n </PopoverContent>\n </Popover>\n );\n};\n\nDatePicker.displayName = 'DatePicker';\nexport default DatePicker;\n","'use client';\n\nimport React, {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n} from 'react';\nimport {\n startOfMonth,\n getDaysInMonth,\n format,\n addMonths,\n subMonths,\n isSameDay,\n getDay,\n isToday,\n isWeekend,\n isBefore,\n startOfDay,\n} from 'date-fns';\nimport { ru } from 'date-fns/locale';\nimport { createCustomDayPredicate } from '../../utils/dateUtils';\n\nexport interface CalendarProps {\n selected?: Date;\n onSelect?: (date: Date) => void;\n initialDate?: Date;\n mode?: 'single' | 'range';\n disabled?: boolean;\n /** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */\n isWeekend?: (date: Date) => boolean;\n}\n\n\nfunction getDayClassName(\n day: Date,\n selected: Date | undefined,\n isWeekendProp?: (date: Date) => boolean\n): string {\n const classes: string[] = ['gantt-day-btn'];\n\n if (selected && isSameDay(day, selected)) classes.push('selected');\n if (isToday(day)) classes.push('today');\n // Use custom predicate if provided, otherwise default\n if (isWeekendProp ? isWeekendProp(day) : isWeekend(day)) classes.push('weekend');\n if (isBefore(day, startOfDay(new Date())) && !isToday(day)) classes.push('past');\n\n return classes.join(' ');\n}\n\nexport const Calendar: React.FC<CalendarProps> = ({\n selected,\n onSelect,\n initialDate,\n mode = 'single',\n disabled = false,\n isWeekend: isWeekendProp,\n}) => {\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const initialMonth = useMemo(\n () => startOfMonth(initialDate ?? selected ?? new Date()),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const [months, setMonths] = useState<Date[]>(() => [\n subMonths(initialMonth, 1),\n initialMonth,\n addMonths(initialMonth, 1),\n ]);\n\n const loadMoreMonths = useCallback((direction: 'up' | 'down') => {\n setMonths((prev) => {\n if (direction === 'up') {\n return [subMonths(prev[0], 1), ...prev];\n } else {\n return [...prev, addMonths(prev[prev.length - 1], 1)];\n }\n });\n }, []);\n\n useEffect(() => {\n const container = scrollRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n if (container.scrollTop <= 100) {\n const prevScrollHeight = container.scrollHeight;\n const prevScrollTop = container.scrollTop;\n loadMoreMonths('up');\n setTimeout(() => {\n container.scrollTop =\n container.scrollHeight - prevScrollHeight + prevScrollTop;\n }, 0);\n } else if (\n container.scrollTop + container.clientHeight >=\n container.scrollHeight - 100\n ) {\n loadMoreMonths('down');\n }\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [loadMoreMonths]);\n\n // Scroll to the selected/initial month on mount\n useEffect(() => {\n if (!scrollRef.current) return;\n const target = selected ?? initialDate ?? new Date();\n const monthKey = format(startOfMonth(target), 'yyyy-MM');\n const el = scrollRef.current.querySelector(`[data-month=\"${monthKey}\"]`);\n if (el) {\n (el as HTMLElement).scrollIntoView({ behavior: 'auto', block: 'start' });\n }\n // Run once on mount only\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const renderMonth = useCallback(\n (month: Date) => {\n const firstDay = startOfMonth(month);\n const totalDays = getDaysInMonth(month);\n // Monday-first: Sunday (0) -> 6, Monday (1) -> 0, ...\n const emptyDays = (getDay(firstDay) + 6) % 7;\n const monthKey = format(month, 'yyyy-MM');\n const monthLabel = format(month, 'LLLL yyyy', { locale: ru });\n\n // Day of week headers (Monday-first)\n const weekdayLabels = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];\n const weekdayHeaders = weekdayLabels.map((label, i) => (\n <div key={`wd-${i}`} className=\"gantt-cal-weekday\">\n {label}\n </div>\n ));\n\n const emptyCells = Array.from({ length: emptyDays }, (_, i) => (\n <div key={`e-${i}`} className=\"gantt-cal-empty-day\" />\n ));\n\n const dayCells = Array.from({ length: totalDays }, (_, i) => {\n const dayNum = i + 1;\n const day = new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum));\n const className = getDayClassName(day, selected, isWeekendProp);\n return (\n <button\n key={dayNum}\n type=\"button\"\n className={className}\n disabled={disabled}\n onClick={() => {\n if (!disabled && onSelect) {\n onSelect(new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum)));\n }\n }}\n >\n {dayNum}\n </button>\n );\n });\n\n return (\n <div key={monthKey} className=\"gantt-cal-month\" data-month={monthKey}>\n <div className=\"gantt-cal-month-header\">{monthLabel}</div>\n <div className=\"gantt-cal-month-days\">\n {weekdayHeaders}\n {emptyCells}\n {dayCells}\n </div>\n </div>\n );\n },\n [selected, onSelect, disabled, isWeekendProp]\n );\n\n const renderedMonths = useMemo(\n () => months.map(renderMonth),\n [months, renderMonth]\n );\n\n return (\n <div ref={scrollRef} className=\"gantt-cal-container\">\n {renderedMonths}\n </div>\n );\n};\n\nCalendar.displayName = 'Calendar';\nexport default Calendar;\n","import React from 'react';\nimport type { LinkType } from '../../types';\n\nconst DepIconFS = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m10 15 5 5 5-5\" /><path d=\"M4 4h7a4 4 0 0 1 4 4v12\" />\n </svg>\n);\n\nconst DepIconSS = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M3 5v14\" /><path d=\"M21 12H7\" /><path d=\"m15 18 6-6-6-6\" />\n </svg>\n);\n\nconst DepIconFF = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M17 12H3\" /><path d=\"m11 18 6-6-6-6\" /><path d=\"M21 5v14\" />\n </svg>\n);\n\nconst DepIconSF = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m14 15-5 5-5-5\" /><path d=\"M20 4h-7a4 4 0 0 0-4 4v12\" />\n </svg>\n);\n\nexport const LINK_TYPE_ICONS: Record<LinkType, React.FC> = {\n FS: DepIconFS,\n SS: DepIconSS,\n FF: DepIconFF,\n SF: DepIconSF,\n};\n\nexport const LINK_TYPE_LABELS: Record<LinkType, string> = {\n FS: 'Окончание-начало',\n SS: 'Начало-начало',\n FF: 'Окончание-окончание',\n SF: 'Начало-окончание',\n};\n","'use client';\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { Input } from '../ui/Input';\n\ninterface NewTaskRowProps {\n rowHeight: number;\n onConfirm: (name: string) => void;\n onCancel: () => void;\n}\n\nexport const NewTaskRow: React.FC<NewTaskRowProps> = ({ rowHeight, onConfirm, onCancel }) => {\n const [nameValue, setNameValue] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n const confirmedRef = useRef(false);\n\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, []);\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n if (nameValue.trim()) {\n confirmedRef.current = true;\n onConfirm(nameValue.trim());\n } else {\n onCancel();\n }\n } else if (e.key === 'Escape') {\n onCancel();\n }\n };\n\n const handleBlur = () => {\n if (confirmedRef.current) return; // already confirmed via Enter\n if (nameValue.trim()) {\n confirmedRef.current = true;\n onConfirm(nameValue.trim());\n } else {\n onCancel();\n }\n };\n\n return (\n <div className=\"gantt-tl-row gantt-tl-row-new\" style={{ minHeight: `${rowHeight}px` }}>\n <div className=\"gantt-tl-cell gantt-tl-cell-number\" />\n <div className=\"gantt-tl-cell gantt-tl-cell-name gantt-tl-cell-new-name\">\n <Input\n ref={inputRef}\n value={nameValue}\n onChange={(e) => setNameValue(e.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n placeholder=\"Название\"\n className=\"gantt-tl-name-input\"\n />\n </div>\n <div className=\"gantt-tl-cell\" />\n <div className=\"gantt-tl-cell\" />\n <div className=\"gantt-tl-cell\" />\n </div>\n );\n};\n\nexport default NewTaskRow;\n","'use client';\n\nimport React from 'react';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual variant */\n variant?: 'default' | 'ghost' | 'outline';\n /** Size variant */\n size?: 'default' | 'sm' | 'icon';\n /** Additional CSS class names */\n className?: string;\n}\n\n/**\n * Simple button component for calendar navigation and UI actions\n */\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', children, ...props }, ref) => {\n const classes = [\n 'gantt-btn',\n variant !== 'default' ? `gantt-btn-${variant}` : '',\n size !== 'default' ? `gantt-btn-${size}` : '',\n className || '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <button ref={ref} className={classes} {...props}>\n {children}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\nexport default Button;\n","// Utility functions barrel export\nexport * from './dateUtils';\nexport * from './dependencyUtils';\nexport * from './expired';\nexport * from './geometry';\nexport * from './hierarchyOrder';\nexport * from './taskListReorder';\n","import { Task } from '../types';\nimport { parseUTCDate } from '../utils/dateUtils';\nimport { isTaskExpired } from '../utils/expired';\n\n/**\n * Predicate function for filtering tasks\n * @param task - Task to evaluate\n * @returns true to include task in filtered results, false to exclude\n */\nexport type TaskPredicate = (task: Task | undefined) => boolean;\n\n/**\n * Combine predicates with AND logic — all must be true\n * @param predicates - Array of predicate functions\n * @returns Composite predicate that returns true only if all predicates return true\n */\nexport const and = (...predicates: TaskPredicate[]): TaskPredicate =>\n (task) => predicates.every(p => p(task));\n\n/**\n * Combine predicates with OR logic — at least one must be true\n * @param predicates - Array of predicate functions\n * @returns Composite predicate that returns true if any predicate returns true\n */\nexport const or = (...predicates: TaskPredicate[]): TaskPredicate =>\n (task) => predicates.some(p => p(task));\n\n/**\n * Invert a predicate's logic\n * @param predicate - Predicate function to invert\n * @returns Composite predicate that returns the opposite of the input predicate\n */\nexport const not = (predicate: TaskPredicate): TaskPredicate =>\n (task) => !predicate(task);\n\n/**\n * Filter tasks that have no dependencies\n * @returns Predicate that returns true for tasks without dependencies array or with empty array\n */\nexport const withoutDeps = (): TaskPredicate =>\n (task) => !!task && (!task.dependencies || task.dependencies.length === 0);\n\n/**\n * Filter expired (overdue) tasks\n * @param referenceDate - Date to compare against (default: now)\n * @returns Predicate that returns true for tasks ending before reference date\n */\nexport const expired = (referenceDate: Date = new Date()): TaskPredicate =>\n (task) => isTaskExpired(task, referenceDate);\n\n/**\n * Filter tasks that intersect with a date range\n * Task intersects if: taskStart <= rangeEnd && taskEnd >= rangeStart\n * @param rangeStart - Start of the date range\n * @param rangeEnd - End of the date range\n * @returns Predicate that returns true for tasks intersecting the range\n */\nexport const inDateRange = (rangeStart: Date, rangeEnd: Date): TaskPredicate =>\n (task) => {\n if (!task) return false;\n const taskStart = parseUTCDate(task.startDate);\n const taskEnd = parseUTCDate(task.endDate);\n return taskStart.getTime() <= rangeEnd.getTime() && taskEnd.getTime() >= rangeStart.getTime();\n };\n\n/**\n * Filter tasks by progress value range\n * @param min - Minimum progress value (0-100)\n * @param max - Maximum progress value (0-100)\n * @returns Predicate that returns true for tasks with progress in [min, max] range\n */\nexport const progressInRange = (min: number, max: number): TaskPredicate =>\n (task) => {\n if (!task) return false;\n const progress = task.progress ?? 0;\n return progress >= min && progress <= max;\n };\n\n/**\n * Filter tasks by name substring search\n * @param substring - Text to search for in task name\n * @param caseSensitive - If false (default), search is case-insensitive\n * @returns Predicate that returns true for tasks with substring in name\n */\nexport const nameContains = (substring: string, caseSensitive = false): TaskPredicate =>\n (task) => {\n if (!task) return false;\n const name = task.name;\n const search = caseSensitive ? substring : substring.toLowerCase();\n const target = caseSensitive ? name : name.toLowerCase();\n return target.includes(search);\n };\n"],"mappings":"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","names":["startOfMonth","import_react","DAY_MS","import_react","isWeekend","getWeekBlocks","import_react","dayWidth","getUTCDayDifference","currentTask","import_jsx_runtime","React","import_react","import_jsx_runtime","import_react","import_jsx_runtime","arePropsEqual","React","import_jsx_runtime","import_react","import_jsx_runtime","React","lines","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","React","import_react","import_date_fns","import_react","import_date_fns","import_locale","import_jsx_runtime","import_jsx_runtime","isWeekend","import_jsx_runtime","import_jsx_runtime","DAY_MS","effectiveLag","React","isWeekend","import_react","import_jsx_runtime","import_jsx_runtime","isWeekend","tasks","React","import_jsx_runtime","isWeekend","tasks","import_react","import_jsx_runtime","React"]}
1
+ {"version":3,"sources":["../src/utils/dateUtils.ts","../src/index.ts","../src/components/GanttChart/GanttChart.tsx","../src/utils/dependencyUtils.ts","../src/utils/hierarchyOrder.ts","../src/components/TimeScaleHeader/TimeScaleHeader.tsx","../src/components/TaskRow/TaskRow.tsx","../src/utils/geometry.ts","../src/utils/expired.ts","../src/hooks/useTaskDrag.ts","../src/components/TodayIndicator/TodayIndicator.tsx","../src/components/GridBackground/GridBackground.tsx","../src/components/DragGuideLines/DragGuideLines.tsx","../src/components/DependencyLines/DependencyLines.tsx","../src/components/TaskList/TaskList.tsx","../src/utils/taskListReorder.ts","../src/components/ui/Popover.tsx","../src/components/TaskList/TaskListRow.tsx","../src/components/ui/Input.tsx","../src/components/ui/DatePicker.tsx","../src/components/ui/Calendar.tsx","../src/components/TaskList/DepIcons.tsx","../src/components/TaskList/NewTaskRow.tsx","../src/components/ui/Button.tsx","../src/utils/index.ts","../src/filters/index.ts"],"sourcesContent":["import { parseISO, isValid } from 'date-fns';\n\n/**\n * Parse date string as UTC to prevent DST issues\n * @param date - Date string or Date object\n * @returns Date object representing UTC midnight\n * @throws Error if date string is invalid\n */\nexport const parseUTCDate = (date: string | Date): Date => {\n if (typeof date === 'string') {\n // If already an ISO string (contains 'T'), parse directly\n // Otherwise, append UTC time for simple date strings (YYYY-MM-DD)\n const dateStr = date.includes('T') ? date : `${date}T00:00:00Z`;\n const parsed = new Date(dateStr);\n if (isNaN(parsed.getTime())) {\n throw new Error(`Invalid date string: ${date}`);\n }\n return parsed;\n }\n return date;\n};\n\n/**\n * Get all days in the month of given date (UTC)\n * @param date - Reference date (any day in the target month)\n * @returns Array of Date objects for each day in the month\n */\nexport const getMonthDays = (date: Date | string): Date[] => {\n const utcDate = parseUTCDate(date);\n const year = utcDate.getUTCFullYear();\n const month = utcDate.getUTCMonth();\n\n // Get days in month (handles leap years)\n const daysInMonth = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();\n\n const days: Date[] = [];\n for (let day = 1; day <= daysInMonth; day++) {\n days.push(new Date(Date.UTC(year, month, day)));\n }\n\n return days;\n};\n\n/**\n * Calculate day offset from month start (0-based)\n * @param date - The date to calculate offset for\n * @param monthStart - The start of the month as reference\n * @returns Number of days from month start (negative if date is before month start)\n */\nexport const getDayOffset = (date: Date, monthStart: Date): number => {\n const dateMs = Date.UTC(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n date.getUTCDate()\n );\n const startMs = Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate()\n );\n return Math.round((dateMs - startMs) / (1000 * 60 * 60 * 24));\n};\n\n/**\n * Check if date is today (local timezone comparison)\n * Uses local time to determine today's date boundary so the result matches\n * the user's timezone rather than UTC (prevents off-by-one errors at midnight).\n * @param date - Date to check\n * @returns True if date is today, false otherwise\n */\nexport const isToday = (date: Date): boolean => {\n const now = new Date();\n // Use local time methods so the \"today\" boundary reflects the user's timezone.\n // getUTCFullYear/Month/Date would shift the day for non-UTC users.\n const today = new Date(Date.UTC(\n now.getFullYear(),\n now.getMonth(),\n now.getDate()\n ));\n const compareDate = new Date(Date.UTC(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n date.getUTCDate()\n ));\n return today.getTime() === compareDate.getTime();\n};\n\n/**\n * Check if date is a weekend day (Saturday or Sunday)\n * @param date - Date to check\n * @returns True if date is Saturday (6) or Sunday (0), false otherwise\n */\nexport const isWeekend = (date: Date): boolean => {\n const day = date.getUTCDay();\n return day === 0 || day === 6; // Sunday (0) or Saturday (6)\n};\n\n/**\n * Create a UTC-safe key for Set-based date lookup\n * @param date - Date object to create key from\n * @returns String key in \"YYYY-M-D\" format using UTC date components\n *\n * Example:\n * createDateKey(new Date(Date.UTC(2026, 2, 15))) // \"2026-2-15\"\n *\n * Note: Uses UTC methods to prevent DST and timezone issues.\n * Month is 0-indexed (0=January, 11=December) per JavaScript Date convention.\n */\nexport const createDateKey = (date: Date): string => {\n return `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}`;\n};\n\n/**\n * Configuration for a single custom day\n */\nexport interface CustomDayConfig {\n /** The date to customize */\n date: Date;\n /** Type of day: 'weekend' marks as weekend, 'workday' marks as workday */\n type: 'weekend' | 'workday';\n}\n\n/**\n * Configuration for custom day predicate\n */\nexport interface CustomDayPredicateConfig {\n /** Array of custom day configurations with explicit types */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate (checked before customDays overrides) */\n isWeekend?: (date: Date) => boolean;\n}\n\n/**\n * Create a weekend predicate with unified custom day support\n *\n * Precedence order (highest to lowest):\n * 1. customDays.type='workday' - explicit workday (highest override)\n * 2. customDays.type='weekend' - explicit weekend (override)\n * 3. isWeekend (base predicate) - custom base logic\n * 4. default - Saturday (6) and Sunday (0)\n *\n * @param config - Custom day configuration with array and optional predicate\n * @returns Predicate function (date: Date) => boolean\n *\n * Example:\n * // Simple holidays + working Saturdays\n * const predicate = createCustomDayPredicate({\n * customDays: [\n * { date: new Date(Date.UTC(2026, 2, 15)), type: 'workday' }, // working Saturday\n * { date: new Date(Date.UTC(2026, 0, 1)), type: 'weekend' } // holiday Tuesday\n * ]\n * });\n *\n * // 4-day work week + occasional overrides\n * const predicate2 = createCustomDayPredicate({\n * isWeekend: (date) => {\n * const day = date.getUTCDay();\n * return day === 0 || day === 6 || day === 5; // Sun+Sat+Fri\n * },\n * customDays: [\n * { date: new Date(Date.UTC(2026, 2, 10)), type: 'workday' } // working Friday\n * ]\n * });\n */\nexport const createCustomDayPredicate = (\n config: CustomDayPredicateConfig\n): ((date: Date) => boolean) => {\n const { customDays, isWeekend: basePredicate } = config;\n\n // Build Set-based lookups for O(1) performance\n const workdaySet = new Set<string>();\n const weekendSet = new Set<string>();\n\n if (customDays && customDays.length > 0) {\n for (const item of customDays) {\n const key = createDateKey(item.date);\n if (item.type === 'workday') {\n workdaySet.add(key);\n } else { // weekend\n weekendSet.add(key);\n }\n }\n }\n\n return (date: Date): boolean => {\n const key = createDateKey(date);\n\n // Priority 1: customDays workdays (highest override)\n if (workdaySet.has(key)) {\n return false; // Explicitly a workday\n }\n\n // Priority 2: customDays weekends (override)\n if (weekendSet.has(key)) {\n return true; // Explicitly a weekend\n }\n\n // Priority 3: base predicate (if provided)\n if (basePredicate) {\n return basePredicate(date);\n }\n\n // Priority 4: default Saturday/Sunday\n const dayOfWeek = date.getUTCDay();\n return dayOfWeek === 0 || dayOfWeek === 6;\n };\n};\n\n/**\n * Calculate multi-month date range from task dates\n * Expands range to include full months with padding on both ends for drag flexibility\n * Adds 1 month before and 2 months after the task range\n * @param tasks - Array of tasks with startDate and endDate\n * @returns Array of Date objects for all days in the expanded range\n */\nexport const getMultiMonthDays = (tasks: Array<{ startDate: string | Date; endDate: string | Date }>): Date[] => {\n // Handle empty task array by returning current month\n if (!tasks || tasks.length === 0) {\n return getMonthDays(new Date());\n }\n\n // Find min and max dates from all tasks\n let minDate: Date | null = null;\n let maxDate: Date | null = null;\n\n for (const task of tasks) {\n const start = parseUTCDate(task.startDate);\n const end = parseUTCDate(task.endDate);\n\n if (!minDate || start.getTime() < minDate.getTime()) {\n minDate = start;\n }\n if (!maxDate || end.getTime() > maxDate.getTime()) {\n maxDate = end;\n }\n }\n\n if (!minDate || !maxDate) {\n return getMonthDays(new Date());\n }\n\n // Extend to full months: 1st of first month to last day of last month\n // Add padding: 2 months after for drag flexibility\n const startOfMonth = new Date(Date.UTC(\n minDate.getUTCFullYear(),\n minDate.getUTCMonth(),\n 1\n ));\n\n const endOfMonth = new Date(Date.UTC(\n maxDate.getUTCFullYear(),\n maxDate.getUTCMonth() + 1 + 2, // Original + 2 months padding after\n 0\n ));\n\n // Generate all dates in range\n const days: Date[] = [];\n const current = new Date(startOfMonth);\n\n while (current.getTime() <= endOfMonth.getTime()) {\n days.push(new Date(Date.UTC(\n current.getUTCFullYear(),\n current.getUTCMonth(),\n current.getUTCDate()\n )));\n // Move to next day\n current.setUTCDate(current.getUTCDate() + 1);\n }\n\n return days;\n};\n\n/**\n * Calculate month spans within a date range\n * @param dateRange - Array of Date objects representing the full range\n * @returns Array of month span objects with month, days count, and start index\n */\nexport const getMonthSpans = (\n dateRange: Date[]\n): Array<{ month: Date; days: number; startIndex: number }> => {\n if (dateRange.length === 0) {\n return [];\n }\n\n const spans: Array<{ month: Date; days: number; startIndex: number }> = [];\n let currentMonthYear = `${dateRange[0].getUTCFullYear()}-${dateRange[0].getUTCMonth()}`;\n let startOfMonthIndex = 0;\n\n for (let i = 0; i < dateRange.length; i++) {\n const date = dateRange[i];\n const monthYear = `${date.getUTCFullYear()}-${date.getUTCMonth()}`;\n\n // When month changes, finalize the previous span and start a new one\n if (monthYear !== currentMonthYear) {\n spans.push({\n month: new Date(Date.UTC(\n dateRange[startOfMonthIndex].getUTCFullYear(),\n dateRange[startOfMonthIndex].getUTCMonth(),\n 1\n )),\n days: i - startOfMonthIndex,\n startIndex: startOfMonthIndex\n });\n currentMonthYear = monthYear;\n startOfMonthIndex = i;\n }\n\n // Last date - finalize the last span\n if (i === dateRange.length - 1) {\n spans.push({\n month: new Date(Date.UTC(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n 1\n )),\n days: i - startOfMonthIndex + 1,\n startIndex: startOfMonthIndex\n });\n }\n }\n\n return spans;\n};\n\n/**\n * Format date as DD.MM (e.g., 25.03 for March 25th)\n * @param date - Date to format\n * @returns Formatted date string in DD.MM format\n */\nexport const formatDateLabel = (date: Date | string): string => {\n const parsed = parseUTCDate(date);\n const day = String(parsed.getUTCDate()).padStart(2, '0');\n const month = String(parsed.getUTCMonth() + 1).padStart(2, '0');\n return `${day}.${month}`;\n};\n\n/**\n * Return block boundaries for week-view, splitting on month boundaries.\n * Each block represents a column in the week-view header.\n * Blocks are typically 7 days, but split on month boundaries so\n * the first/last block of a month may be smaller.\n *\n * @param days - Array of dates from getMultiMonthDays\n * @returns Array of start dates for each block, with actual block sizes\n */\nexport interface WeekBlock {\n /** Start date of this block */\n startDate: Date;\n /** Number of days in this block (≤7, splits on month boundaries) */\n days: number;\n}\n\n/**\n * Split the date range into blocks, primarily 7-day weeks,\n * but splitting blocks on month boundaries for accurate month spans.\n */\nexport const getWeekBlocks = (days: Date[]): WeekBlock[] => {\n if (days.length === 0) return [];\n\n const blocks: WeekBlock[] = [];\n let blockStart = 0;\n\n while (blockStart < days.length) {\n // Target: 7-day block, but check for month boundary within\n const maxBlockEnd = Math.min(blockStart + 7, days.length);\n const startMonthYear = `${days[blockStart].getUTCFullYear()}-${days[blockStart].getUTCMonth()}`;\n\n let actualBlockEnd = blockStart + 7; // Default to full week\n if (actualBlockEnd > days.length) {\n actualBlockEnd = days.length;\n }\n\n // Check if month boundary falls within the 7-day window\n for (let i = blockStart + 1; i < maxBlockEnd; i++) {\n const monthYear = `${days[i].getUTCFullYear()}-${days[i].getUTCMonth()}`;\n if (monthYear !== startMonthYear) {\n // Split at month boundary\n actualBlockEnd = i;\n break;\n }\n }\n\n blocks.push({\n startDate: days[blockStart],\n days: actualBlockEnd - blockStart,\n });\n\n blockStart = actualBlockEnd;\n }\n\n return blocks;\n};\n\n/**\n * Represents a month span in week-view header row 1.\n * In week-view, the width is calculated from actual day counts,\n * not from a fixed column count.\n */\nexport interface WeekSpan {\n /** First day of the calendar month (UTC) */\n month: Date;\n /** Total number of days this month occupies across all blocks */\n days: number;\n /** Start index in the blocks array */\n startIndex: number;\n}\n\n/**\n * Calculate month spans based on week-block boundaries.\n * Groups consecutive blocks that belong to the same month.\n */\nexport const getWeekSpans = (days: Date[]): WeekSpan[] => {\n const blocks = getWeekBlocks(days);\n if (blocks.length === 0) return [];\n\n const spans: WeekSpan[] = [];\n let currentMonthYear = `${blocks[0].startDate.getUTCFullYear()}-${blocks[0].startDate.getUTCMonth()}`;\n let startIndex = 0;\n let totalDays = 0;\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const monthYear = `${block.startDate.getUTCFullYear()}-${block.startDate.getUTCMonth()}`;\n\n if (monthYear !== currentMonthYear) {\n // Finalize previous month span\n spans.push({\n month: new Date(Date.UTC(\n blocks[startIndex].startDate.getUTCFullYear(),\n blocks[startIndex].startDate.getUTCMonth(),\n 1\n )),\n days: totalDays,\n startIndex,\n });\n currentMonthYear = monthYear;\n startIndex = i;\n totalDays = 0;\n }\n\n totalDays += block.days;\n\n if (i === blocks.length - 1) {\n spans.push({\n month: new Date(Date.UTC(\n block.startDate.getUTCFullYear(),\n block.startDate.getUTCMonth(),\n 1\n )),\n days: totalDays,\n startIndex,\n });\n }\n }\n\n return spans;\n};\n\nexport interface MonthBlock {\n /** Первый день месяца (UTC) */\n startDate: Date;\n /** Количество дней в этом месяце внутри dateRange (может быть меньше при обрезке) */\n days: number;\n}\n\n/**\n * Разбивает dateRange на блоки по месяцам.\n * Каждый блок = один месяц (колонка в строке 2 month-view шапки).\n * Блок на краях может быть неполным если dateRange начинается/заканчивается не с 1-го числа.\n */\nexport const getMonthBlocks = (days: Date[]): MonthBlock[] => {\n if (days.length === 0) return [];\n // Переиспользуем getMonthSpans — его структура совпадает с MonthBlock\n return getMonthSpans(days).map(span => ({\n startDate: span.month,\n days: span.days,\n }));\n};\n\nexport interface YearSpan {\n /** 1 января года (UTC) */\n year: Date;\n /** Суммарное кол-во дней этого года внутри dateRange */\n days: number;\n /** Начальный индекс в массиве monthBlocks */\n startIndex: number;\n}\n\n/**\n * Группирует month-блоки по годам.\n * Используется в строке 1 month-view шапки (year label).\n */\nexport const getYearSpans = (days: Date[]): YearSpan[] => {\n const blocks = getMonthBlocks(days);\n if (blocks.length === 0) return [];\n\n const spans: YearSpan[] = [];\n let currentYear = blocks[0].startDate.getUTCFullYear();\n let startIndex = 0;\n let totalDays = 0;\n\n for (let i = 0; i < blocks.length; i++) {\n const blockYear = blocks[i].startDate.getUTCFullYear();\n if (blockYear !== currentYear) {\n spans.push({\n year: new Date(Date.UTC(currentYear, 0, 1)),\n days: totalDays,\n startIndex,\n });\n currentYear = blockYear;\n startIndex = i;\n totalDays = 0;\n }\n totalDays += blocks[i].days;\n if (i === blocks.length - 1) {\n spans.push({\n year: new Date(Date.UTC(currentYear, 0, 1)),\n days: totalDays,\n startIndex,\n });\n }\n }\n\n return spans;\n};\n\n/**\n * Normalize task dates to ensure startDate is always before or equal to endDate.\n * If dates are swapped (endDate < startDate), they are automatically swapped.\n * @param startDate - Task start date (string or Date)\n * @param endDate - Task end date (string or Date)\n * @returns Object with normalized startDate and endDate as ISO date strings (YYYY-MM-DD)\n */\nexport const normalizeTaskDates = (\n startDate: string | Date,\n endDate: string | Date\n): { startDate: string; endDate: string } => {\n const start = parseUTCDate(startDate);\n const end = parseUTCDate(endDate);\n\n // If dates are swapped, return them in correct order\n if (end.getTime() < start.getTime()) {\n return {\n startDate: end.toISOString().split('T')[0],\n endDate: start.toISOString().split('T')[0],\n };\n }\n\n // Dates are already in correct order\n return {\n startDate: start.toISOString().split('T')[0],\n endDate: end.toISOString().split('T')[0],\n };\n};\n","'use client';\n\n// CSS import triggers tsup to emit dist/index.css (renamed to dist/styles.css by onSuccess)\nimport './styles.css';\n\n// Components\nexport { GanttChart, type Task, type TaskDependency, type GanttChartProps, type GanttChartHandle } from './components/GanttChart';\nexport { default as TaskRow } from './components/TaskRow';\nexport { default as TimeScaleHeader } from './components/TimeScaleHeader';\nexport { default as GridBackground } from './components/GridBackground';\nexport { default as TodayIndicator } from './components/TodayIndicator';\nexport { default as DragGuideLines } from './components/DragGuideLines/DragGuideLines';\nexport { TaskList, type TaskListProps } from './components/TaskList';\n\n// UI Components\nexport { Input, type InputProps } from './components/ui/Input';\nexport { Button, type ButtonProps } from './components/ui/Button';\nexport { Popover, PopoverTrigger, PopoverContent, type PopoverProps, type PopoverContentProps } from './components/ui/Popover';\nexport { Calendar, type CalendarProps } from './components/ui/Calendar';\nexport { DatePicker, type DatePickerProps } from './components/ui/DatePicker';\n\n// Hooks\nexport { useTaskDrag } from './hooks';\n\n// Utils\nexport * from './utils';\n\n// Filters\nexport * from './filters';\n\n// Types\nexport type {\n GanttDateRange,\n TaskBarGeometry,\n GridConfig,\n MonthSpan,\n GridLine,\n WeekendBlock,\n} from './types';\n","'use client';\n\nimport React, { useMemo, useCallback, useRef, useState, useEffect, useImperativeHandle, forwardRef } from 'react';\nimport { getMultiMonthDays, createCustomDayPredicate, type CustomDayConfig, type CustomDayPredicateConfig } from '../../utils/dateUtils';\nimport { calculateGridWidth } from '../../utils/geometry';\nimport { validateDependencies, cascadeByLinks, computeParentDates, computeParentProgress, getChildren, removeDependenciesBetweenTasks, isTaskParent } from '../../utils/dependencyUtils';\nimport { normalizeHierarchyTasks } from '../../utils/hierarchyOrder';\nimport type { ValidationResult } from '../../types';\nimport { TaskPredicate } from '../../filters';\nimport TimeScaleHeader from '../TimeScaleHeader';\nimport TaskRow from '../TaskRow';\nimport TodayIndicator from '../TodayIndicator';\nimport GridBackground from '../GridBackground';\nimport DragGuideLines from '../DragGuideLines/DragGuideLines';\nimport { DependencyLines } from '../DependencyLines';\nimport { TaskList } from '../TaskList';\nimport './GanttChart.css';\n\n/**\n * Task data structure for Gantt chart\n */\nexport interface Task {\n /** Unique identifier for the task */\n id: string;\n /** Display name of the task */\n name: string;\n /** Task start date (ISO string or Date object) */\n startDate: string | Date;\n /** Task end date (ISO string or Date object) */\n endDate: string | Date;\n /** Optional color for task bar visualization */\n color?: string;\n /** Optional parent task ID for hierarchy relationship */\n parentId?: string;\n /**\n * Optional progress value from 0-100\n * - Decimal values are allowed and rounded to nearest integer for display\n * - Values are clamped to 0-100 range\n * - Undefined or 0 means no progress is displayed\n * - Progress is visual-only, no user interaction\n */\n progress?: number;\n /**\n * Optional flag indicating if task is accepted\n * - Only meaningful when progress is 100%\n * - Affects the color of the progress bar (green for accepted, yellow for completed)\n */\n accepted?: boolean;\n /**\n * Optional array of task dependencies\n * - Each dependency references a predecessor task by ID\n * - Supports 4 link types: FS (finish-to-start), SS (start-to-start), FF (finish-to-finish), SF (start-to-finish)\n * - Lag is optional and defaults to 0 (positive = delay, negative = overlap)\n */\n dependencies?: TaskDependency[];\n /**\n * Optional flag to prevent drag and resize interactions.\n * When true, the task bar cannot be moved or resized.\n * Independent of accepted/progress — consumer controls both separately.\n */\n locked?: boolean;\n /**\n * Optional horizontal divider line for visual grouping.\n * - 'top' renders a bold line above the task row\n * - 'bottom' renders a bold line below the task row\n * The line spans the full grid width.\n */\n divider?: 'top' | 'bottom';\n}\n\n/**\n * Task dependency definition\n */\nexport interface TaskDependency {\n /** ID of the predecessor task */\n taskId: string;\n /** Link type: FS, SS, FF, or SF */\n type: 'FS' | 'SS' | 'FF' | 'SF';\n /** Optional lag in days (default: 0) */\n lag?: number;\n}\n\nexport interface GanttChartProps {\n /** Array of tasks to display */\n tasks: Task[];\n /** Width of each day column in pixels (default: 40) */\n dayWidth?: number;\n /** Height of each task row in pixels (default: 40) */\n rowHeight?: number;\n /** Height of the header row in pixels (default: 40) */\n headerHeight?: number;\n /** Container height. Can be pixels (600), string (\"90vh\", \"100%\", \"500px\"), or undefined for auto height */\n containerHeight?: number | string;\n /** Callback when tasks are modified. Receives ONLY the changed tasks as full objects with all properties. */\n onTasksChange?: (tasks: Task[]) => void;\n /** Optional callback for dependency validation results */\n onValidateDependencies?: (result: ValidationResult) => void;\n /** Enable automatic shifting of dependent tasks when predecessor moves (default: false) */\n enableAutoSchedule?: boolean;\n /** Disable dependency constraint checking during drag (default: false) */\n disableConstraints?: boolean;\n /** Called when a cascade drag completes; receives all shifted tasks (including dragged task) in hard mode */\n onCascade?: (tasks: Task[]) => void;\n /** Show task list overlay on the left side of the chart (default: false) */\n showTaskList?: boolean;\n /** Width of the task list overlay in pixels (default: 300) */\n taskListWidth?: number;\n /** Disable task name editing in the task list (default: false) */\n disableTaskNameEditing?: boolean;\n /** Disable dependency editing in the task list (default: false) */\n disableDependencyEditing?: boolean;\n /** Highlight expired/overdue tasks with red background (default: false) */\n highlightExpiredTasks?: boolean;\n /** Callback when a new task is added via the task list */\n onAdd?: (task: Task) => void;\n /** Callback when a task is deleted via the task list */\n onDelete?: (taskId: string) => void;\n /** Callback when a new task is inserted after a specific task via the task list */\n onInsertAfter?: (taskId: string, newTask: Task) => void;\n /** Callback when tasks are reordered via drag in the task list */\n onReorder?: (tasks: Task[], movedTaskId?: string, inferredParentId?: string) => void;\n /** Callback when a task is promoted (parentId removed). If not provided, default internal logic is used. */\n onPromoteTask?: (taskId: string) => void;\n /** Callback when a task is demoted (parentId set). If not provided, default internal logic is used. */\n onDemoteTask?: (taskId: string, newParentId: string) => void;\n /** Enable add task button at bottom of task list (default: true) */\n enableAddTask?: boolean;\n /** View mode: 'day' renders one column per day, 'week' renders one column per 7 days, 'month' renders one column per month (default: 'day') */\n viewMode?: 'day' | 'week' | 'month';\n /** Custom day configurations with explicit type (weekend or workday) */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate (checked before customDays overrides) */\n isWeekend?: (date: Date) => boolean;\n /**\n * Optional predicate to mark tasks in the current view.\n * Matching tasks stay visible and are highlighted in the chart and task list.\n * Dependencies are still computed on ALL tasks (normalizedTasks).\n */\n taskFilter?: TaskPredicate;\n /** Set of collapsed parent task IDs for controlled mode */\n collapsedParentIds?: Set<string>;\n /** Callback when collapse/expand button is clicked (controlled mode) */\n onToggleCollapse?: (parentId: string) => void;\n}\n\n/**\n * Ref handle type for GanttChart — exposes imperative scroll methods.\n */\nexport interface GanttChartHandle {\n scrollToToday: () => void;\n scrollToTask: (taskId: string) => void;\n collapseAll: () => void;\n expandAll: () => void;\n}\n\n/**\n * GanttChart component - displays tasks on a monthly timeline with Excel-like styling\n *\n * The calendar automatically shows full months based on task date ranges.\n * For example, if tasks span from March 25 to May 5, the calendar shows\n * the complete months of March, April, and May (March 1 - May 31).\n *\n * @example\n * ```tsx\n * <GanttChart\n * tasks={[\n * { id: '1', name: 'Task 1', startDate: '2026-02-01', endDate: '2026-02-05' }\n * ]}\n * />\n * ```\n * @example\n * ```tsx\n * // Hide add task button\n * <GanttChart\n * tasks={tasks}\n * enableAddTask={false}\n * />\n * ```\n */\nexport const GanttChart = forwardRef<GanttChartHandle, GanttChartProps>(({\n tasks,\n dayWidth = 40,\n rowHeight = 40,\n headerHeight = 40,\n containerHeight,\n onTasksChange,\n onValidateDependencies,\n enableAutoSchedule,\n disableConstraints,\n onCascade,\n showTaskList = false,\n taskListWidth = 660,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n highlightExpiredTasks = false,\n onAdd,\n onDelete,\n onInsertAfter,\n onReorder,\n onPromoteTask,\n onDemoteTask,\n enableAddTask = true,\n viewMode = 'day',\n customDays,\n isWeekend,\n taskFilter,\n collapsedParentIds: externalCollapsedParentIds,\n onToggleCollapse: externalOnToggleCollapse,\n}, ref) => {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n // Track selected task ID for highlighting in both TaskList and TaskRow\n const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);\n const [taskListHasRightShadow, setTaskListHasRightShadow] = useState(false);\n\n // Track selected dep chip for arrow highlighting in DependencyLines\n const [selectedChip, setSelectedChip] = useState<{ successorId: string; predecessorId: string; linkType: string } | null>(null);\n\n // Hierarchy state: collapsed parent IDs (uncontrolled mode - internal state)\n const [internalCollapsedParentIds, setInternalCollapsedParentIds] = useState<Set<string>>(new Set());\n\n // Use external collapsedParentIds if provided (controlled mode), otherwise use internal state\n const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;\n\n // Track editing task ID for auto-edit mode after insert\n const [editingTaskId, setEditingTaskId] = useState<string | null>(null);\n\n const normalizedTasks = useMemo(() => normalizeHierarchyTasks(tasks), [tasks]);\n\n // Create custom weekend predicate from props (memoized for performance)\n const isCustomWeekend = useMemo(\n () => createCustomDayPredicate({ customDays, isWeekend }),\n [customDays, isWeekend]\n );\n\n // Calculate multi-month date range from normalized tasks\n const dateRange = useMemo(() => getMultiMonthDays(normalizedTasks), [normalizedTasks]);\n\n // Track dependency validation results\n const [validationResult, setValidationResult] = useState<ValidationResult | null>(null);\n\n // Cascade override positions for non-dragged chain members\n const [cascadeOverrides, setCascadeOverrides] = useState<Map<string, { left: number; width: number }>>(new Map());\n\n // Calculate grid width\n const gridWidth = useMemo(\n () => Math.round(dateRange.length * dayWidth),\n [dateRange.length, dayWidth]\n );\n\n // Visible tasks are determined only by collapsed parent state.\n // Checks the full ancestor chain so grandchildren are hidden when any ancestor is collapsed.\n const visibleTasks = useMemo(() => {\n const parentMap = new Map(normalizedTasks.map(t => [t.id, t.parentId]));\n\n function isAnyAncestorCollapsed(parentId: string | undefined): boolean {\n let current = parentId;\n while (current) {\n if (collapsedParentIds.has(current)) return true;\n current = parentMap.get(current);\n }\n return false;\n }\n\n return normalizedTasks.filter(task => !isAnyAncestorCollapsed(task.parentId));\n }, [normalizedTasks, collapsedParentIds]);\n\n const matchedTaskIds = useMemo(() => {\n if (!taskFilter) return new Set<string>();\n return new Set(visibleTasks.filter(taskFilter).map(task => task!.id));\n }, [visibleTasks, taskFilter]);\n\n // Calculate total grid height from currently visible rows.\n const totalGridHeight = useMemo(\n () => visibleTasks.length * rowHeight,\n [visibleTasks.length, rowHeight]\n );\n\n // Get month start for calculations (first day of date range)\n const monthStart = useMemo(() => {\n if (dateRange.length === 0) {\n return new Date(Date.UTC(new Date().getUTCFullYear(), new Date().getUTCMonth(), 1));\n }\n const firstDay = dateRange[0];\n return new Date(Date.UTC(firstDay.getUTCFullYear(), firstDay.getUTCMonth(), 1));\n }, [dateRange]);\n\n // Only render TodayIndicator if today is in the visible date range\n const todayInRange = useMemo(() => {\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n return dateRange.some(day => day.getTime() === today.getTime());\n }, [dateRange]);\n\n // Center chart on today's date on initial mount\n useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container || dateRange.length === 0) return;\n\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n const todayIndex = dateRange.findIndex(day => day.getTime() === today.getTime());\n\n if (todayIndex === -1) return;\n\n // Calculate scroll position to center today\n const todayOffset = todayIndex * dayWidth;\n const containerWidth = container.clientWidth;\n const scrollLeft = Math.round(todayOffset - (containerWidth / 2) + (dayWidth / 2));\n\n container.scrollLeft = Math.max(0, scrollLeft);\n }, []); // Empty deps array - run only on mount\n\n useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const updateShadow = () => {\n setTaskListHasRightShadow(container.scrollLeft > 0);\n };\n\n updateShadow();\n container.addEventListener('scroll', updateShadow, { passive: true });\n return () => {\n container.removeEventListener('scroll', updateShadow);\n };\n }, []);\n\n /**\n * Scroll to today's date when the \"Today\" button is clicked\n */\n const scrollToToday = useCallback(() => {\n const container = scrollContainerRef.current;\n if (!container || dateRange.length === 0) return;\n\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n const todayIndex = dateRange.findIndex(day => day.getTime() === today.getTime());\n\n if (todayIndex === -1) return;\n\n // Calculate scroll position to center today\n const todayOffset = todayIndex * dayWidth;\n const containerWidth = container.clientWidth;\n const scrollLeft = Math.round(todayOffset - (containerWidth / 2) + (dayWidth / 2));\n\n container.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });\n }, [dateRange, dayWidth]);\n\n /**\n * Scroll to a specific task by ID, centering its start date horizontally in the grid.\n */\n const scrollToTask = useCallback((taskId: string) => {\n const container = scrollContainerRef.current;\n if (!container || dateRange.length === 0) return;\n\n const task = tasks.find(t => t.id === taskId);\n if (!task) return;\n\n const taskStart = new Date(task.startDate as string);\n const taskStartUTC = new Date(Date.UTC(\n taskStart.getUTCFullYear(),\n taskStart.getUTCMonth(),\n taskStart.getUTCDate()\n ));\n const taskIndex = dateRange.findIndex(day => day.getTime() === taskStartUTC.getTime());\n if (taskIndex === -1) return;\n\n const taskOffset = taskIndex * dayWidth;\n const scrollLeft = Math.round(taskOffset - dayWidth * 2);\n container.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });\n }, [tasks, dateRange, dayWidth]);\n\n // Track drag state for guide lines\n const [dragGuideLines, setDragGuideLines] = useState<{\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n } | null>(null);\n\n // Track currently-dragged task's pixel position for real-time dependency line updates\n const [draggedTaskOverride, setDraggedTaskOverride] = useState<{ taskId: string; left: number; width: number } | null>(null);\n\n // Validate dependencies when tasks change\n useEffect(() => {\n const result = validateDependencies(tasks);\n setValidationResult(result);\n onValidateDependencies?.(result);\n }, [tasks, onValidateDependencies]);\n\n /**\n * Callback when tasks are modified.\n * Always receives ONLY the changed tasks as full objects with all properties.\n * Single task = array of 1 element (batch of size 1).\n */\n const handleTaskChange = useCallback((updatedTasks: Task[]) => {\n const updatedTask = updatedTasks[0];\n if (!updatedTask) return;\n const originalTask = tasks.find(t => t.id === updatedTask.id);\n if (!originalTask) {\n // New task or task not found - pass all tasks as-is\n onTasksChange?.(updatedTasks);\n if (editingTaskId === updatedTask.id) {\n setEditingTaskId(null);\n }\n return;\n }\n\n const origStart = new Date(originalTask.startDate as string);\n const origEnd = new Date(originalTask.endDate as string);\n const newStart = new Date(updatedTask.startDate as string);\n const newEnd = new Date(updatedTask.endDate as string);\n const datesChanged = origStart.getTime() !== newStart.getTime() || origEnd.getTime() !== newEnd.getTime();\n\n if (!datesChanged) {\n // Special case: parent progress cascade (multiple tasks, no date changes)\n if (updatedTasks.length > 1) {\n onTasksChange?.(updatedTasks);\n if (editingTaskId === updatedTask.id) {\n setEditingTaskId(null);\n }\n return;\n }\n\n // Single task without date changes - compute parent progress if needed\n const taskParentId = (updatedTask as any).parentId;\n if (taskParentId) {\n const parentProgress = computeParentProgress(taskParentId, tasks.map(t => t.id === updatedTask.id ? updatedTask : t));\n const parentTask = tasks.find(t => t.id === taskParentId);\n if (parentTask) {\n const updatedParent = { ...parentTask, progress: parentProgress };\n onTasksChange?.([updatedTask, updatedParent]);\n } else {\n onTasksChange?.([updatedTask]);\n }\n } else {\n onTasksChange?.([updatedTask]);\n }\n if (editingTaskId === updatedTask.id) {\n setEditingTaskId(null);\n }\n return;\n }\n\n // Special handling for parent tasks: dates are computed from children\n const isParent = isTaskParent(updatedTask.id, tasks);\n if (isParent) {\n // When editing a parent task via task list, ignore the entered dates\n // and recalculate from children. Children should NOT be moved.\n const { startDate: parentStart, endDate: parentEnd } = computeParentDates(updatedTask.id, tasks);\n const parentWithRecalcDates = {\n ...updatedTask,\n startDate: parentStart.toISOString().split('T')[0],\n endDate: parentEnd.toISOString().split('T')[0],\n };\n\n // Cascade only dependency successors (not children) if constraints enabled\n const cascadedTasks = disableConstraints\n ? [parentWithRecalcDates]\n : [parentWithRecalcDates, ...cascadeByLinks(updatedTask.id, parentStart, parentEnd, tasks, true)]; // skipChildCascade=true\n\n onTasksChange?.(cascadedTasks);\n } else {\n // Regular task or child: normal cascade\n const cascadedTasks = disableConstraints\n ? [updatedTask]\n : [updatedTask, ...cascadeByLinks(updatedTask.id, newStart, newEnd, tasks)];\n\n onTasksChange?.(cascadedTasks);\n }\n }, [tasks, onTasksChange, disableConstraints, editingTaskId]);\n\n /**\n * Handle task deletion: collect all changed tasks (with cleaned dependencies),\n * emit onTasksChange with them, then emit onDelete for each deleted task ID\n * (original + all descendants) so the consumer can remove all of them.\n * For parent tasks, cascade delete to all children.\n */\n const handleDelete = useCallback((taskId: string) => {\n const toDelete = new Set<string>([taskId]);\n\n function collectDescendants(parentId: string) {\n const children = getChildren(parentId, tasks);\n children.forEach(child => {\n toDelete.add(child.id);\n collectDescendants(child.id);\n });\n }\n\n collectDescendants(taskId);\n\n const changedTasks: Task[] = [];\n tasks.forEach(task => {\n if (toDelete.has(task.id)) return;\n\n if (task.dependencies && task.dependencies.some(dep => toDelete.has(dep.taskId))) {\n changedTasks.push({\n ...task,\n dependencies: task.dependencies.filter(dep => !toDelete.has(dep.taskId))\n });\n }\n });\n\n if (changedTasks.length > 0) {\n onTasksChange?.(changedTasks);\n }\n\n // Call onDelete for each task in the cascade set (original + all descendants)\n // so the consumer removes all of them, not just the root.\n toDelete.forEach(id => onDelete?.(id));\n }, [tasks, onTasksChange, onDelete]);\n\n /**\n * Handle task insertion: set editingTaskId to trigger auto-edit mode,\n * then notify external consumer via onInsertAfter callback.\n *\n * NOTE: The external onInsertAfter callback is responsible for adding\n * the task and should emit onTasksChange with the new task.\n */\n const handleInsertAfter = useCallback((taskId: string, newTask: Task) => {\n setEditingTaskId(newTask.id);\n onInsertAfter?.(taskId, newTask);\n }, [onInsertAfter]);\n\n /**\n * Handle task reordering: notify external consumer via onTasksChange and onReorder callbacks.\n * Reordering changes all tasks positions, so we emit the full reordered array.\n */\n const handleReorder = useCallback((reorderedTasks: Task[], movedTaskId?: string, inferredParentId?: string) => {\n let updated = reorderedTasks;\n if (movedTaskId) {\n updated = updated.map(t => {\n if (t.id === movedTaskId) {\n return { ...t, parentId: inferredParentId || undefined };\n }\n return t;\n });\n }\n\n const normalized = normalizeHierarchyTasks(updated);\n onTasksChange?.(normalized);\n onReorder?.(normalized, movedTaskId, inferredParentId);\n }, [onTasksChange, onReorder]);\n\n // Build merged pixel overrides for DependencyLines: dragged task + cascade chain members\n const dependencyOverrides = useMemo(() => {\n const map = new Map(cascadeOverrides);\n if (draggedTaskOverride) {\n map.set(draggedTaskOverride.taskId, {\n left: draggedTaskOverride.left,\n width: draggedTaskOverride.width,\n });\n }\n return map;\n }, [cascadeOverrides, draggedTaskOverride]);\n\n /**\n * Handle real-time cascade progress — updates cascadeOverrides state each RAF\n * so non-dragged chain members re-render with their preview positions.\n * new Map() forces React to detect the state change.\n */\n const handleCascadeProgress = useCallback((overrides: Map<string, { left: number; width: number }>) => {\n setCascadeOverrides(new Map(overrides));\n }, []);\n\n /**\n * Handle cascade completion — emit all changed tasks.\n * Parent tasks are computed from children - don't send them in batch.\n */\n const handleCascade = useCallback((cascadedTasks: Task[]) => {\n // Backend should compute parent dates from children\n onTasksChange?.(cascadedTasks);\n }, [tasks, onTasksChange]);\n\n /**\n * Handle task selection from TaskList or TaskRow\n */\n const handleTaskSelect = useCallback((taskId: string | null) => {\n setSelectedTaskId(taskId);\n }, []);\n\n // Hierarchy callbacks\n // Use external onToggleCollapse if provided (controlled mode), otherwise use internal handler\n const handleToggleCollapse = externalOnToggleCollapse ?? useCallback((parentId: string) => {\n setInternalCollapsedParentIds(prev => {\n const next = new Set(prev);\n if (next.has(parentId)) {\n next.delete(parentId);\n } else {\n next.add(parentId);\n }\n return next;\n });\n }, []);\n\n // Get all parent task IDs (tasks that have children)\n const allParentIds = useMemo(() => {\n return new Set(\n normalizedTasks\n .filter(t => isTaskParent(t.id, normalizedTasks))\n .map(t => t.id)\n );\n }, [normalizedTasks]);\n\n const handleCollapseAll = useCallback(() => {\n if (externalCollapsedParentIds) return; // Don't modify external state\n setInternalCollapsedParentIds(allParentIds);\n }, [allParentIds, externalCollapsedParentIds]);\n\n const handleExpandAll = useCallback(() => {\n if (externalCollapsedParentIds) return; // Don't modify external state\n setInternalCollapsedParentIds(new Set());\n }, [externalCollapsedParentIds]);\n\n // Expose collapse/expand methods via ref (must be after handlers are defined)\n useImperativeHandle(\n ref,\n () => ({\n scrollToToday,\n scrollToTask,\n collapseAll: handleCollapseAll,\n expandAll: handleExpandAll,\n }),\n [scrollToToday, scrollToTask, handleCollapseAll, handleExpandAll]\n );\n\n /**\n * Calculate the depth of a task in the hierarchy.\n * Root tasks have depth 0, their children have depth 1, etc.\n */\n function getTaskDepth(taskId: string, tasks: Task[]): number {\n let depth = 0;\n let current: Task | undefined = tasks.find(t => t.id === taskId);\n while (current) {\n if (!current.parentId) break;\n depth++;\n const parentId: string = current.parentId;\n current = tasks.find(t => t.id === parentId);\n }\n return depth;\n }\n\n const handlePromoteTask = useCallback((taskId: string) => {\n // If consumer provided custom callback, use it\n if (onPromoteTask) {\n onPromoteTask(taskId);\n return;\n }\n\n // Default internal logic\n const taskToPromote = tasks.find(t => t.id === taskId);\n if (!taskToPromote || !taskToPromote.parentId) {\n return;\n }\n\n // Calculate current depth and determine new parent for single-level promotion\n const depth = getTaskDepth(taskId, tasks);\n const grandparentId = depth > 1\n ? tasks.find(t => t.id === taskToPromote.parentId)?.parentId\n : undefined;\n\n const currentParentId = taskToPromote.parentId;\n const siblings = tasks.filter(t => t.parentId === currentParentId);\n\n const promotedTask = { ...taskToPromote, parentId: grandparentId };\n\n if (siblings.length <= 1) {\n onTasksChange?.([promotedTask]);\n return;\n }\n\n // Reorder: place after last sibling of the old parent group\n const lastSiblingIndex = tasks\n .map((t, i) => ({ task: t, index: i }))\n .filter(({ task }) => task.parentId === currentParentId)\n .sort((a, b) => b.index - a.index)[0];\n\n if (!lastSiblingIndex) {\n onTasksChange?.([promotedTask]);\n return;\n }\n\n const reorderedTasks = normalizeHierarchyTasks([\n ...tasks.filter(t => t.id !== taskId).slice(0, lastSiblingIndex.index + 1),\n promotedTask,\n ...tasks.filter(t => t.id !== taskId).slice(lastSiblingIndex.index + 1)\n ]);\n\n onTasksChange?.(reorderedTasks);\n }, [tasks, onTasksChange, onPromoteTask]);\n\n const handleDemoteTask = useCallback((taskId: string, newParentId: string) => {\n // If consumer provided custom callback, use it\n if (onDemoteTask) {\n onDemoteTask(taskId, newParentId);\n return;\n }\n\n // Default internal logic\n const wouldCreateCircular = (targetId: string, parentId: string, tasks: Task[]): boolean => {\n if (targetId === parentId) return true;\n\n const descendants = new Set<string>();\n function collect(id: string) {\n const children = getChildren(id, tasks);\n children.forEach(child => {\n descendants.add(child.id);\n collect(child.id);\n });\n }\n collect(targetId);\n return descendants.has(parentId);\n };\n\n if (wouldCreateCircular(taskId, newParentId, tasks)) {\n return;\n }\n\n let updatedTasks = removeDependenciesBetweenTasks(taskId, newParentId, tasks);\n\n const demotedTask = updatedTasks.find(t => t.id === taskId);\n if (!demotedTask) return;\n\n // If task was a parent (had children), save computed dates as its own dates\n // These become the task's \"own\" dates after demotion\n const wasParent = getChildren(taskId, tasks).length > 0;\n let taskDates = { startDate: demotedTask.startDate, endDate: demotedTask.endDate };\n\n if (wasParent) {\n const computedDates = computeParentDates(taskId, tasks);\n taskDates = {\n startDate: computedDates.startDate.toISOString().split('T')[0],\n endDate: computedDates.endDate.toISOString().split('T')[0]\n };\n }\n\n const updatedDemotedTask = {\n ...demotedTask,\n parentId: newParentId,\n startDate: taskDates.startDate,\n endDate: taskDates.endDate\n };\n\n // Only send the demoted task - parent dates are computed from children\n onTasksChange?.([updatedDemotedTask]);\n }, [tasks, onTasksChange, onDemoteTask]);\n\n // Pan (grab-scroll) on empty grid area\n const panStateRef = useRef<{ active: boolean; startX: number; startY: number; scrollX: number; scrollY: number } | null>(null);\n\n const handlePanStart = useCallback((e: React.MouseEvent) => {\n // Only pan on left click, skip if clicking on a task bar, input, or task list\n if (e.button !== 0) return;\n const target = e.target as HTMLElement;\n if (target.closest('[data-taskbar]')) return;\n if (target.closest('input, button, textarea, [contenteditable]')) return;\n if (target.closest('.gantt-tl-overlay')) return;\n\n const container = scrollContainerRef.current;\n if (!container) return;\n\n panStateRef.current = {\n active: true,\n startX: e.clientX,\n startY: e.clientY,\n scrollX: container.scrollLeft,\n scrollY: container.scrollTop,\n };\n // Blur any focused input so onBlur save handlers fire before pan starts\n if (document.activeElement instanceof HTMLElement) {\n document.activeElement.blur();\n }\n container.style.cursor = 'grabbing';\n e.preventDefault();\n }, []);\n\n useEffect(() => {\n const handlePanMove = (e: MouseEvent) => {\n const pan = panStateRef.current;\n if (!pan?.active) return;\n const container = scrollContainerRef.current;\n if (!container) return;\n\n container.scrollLeft = pan.scrollX - (e.clientX - pan.startX);\n container.scrollTop = pan.scrollY - (e.clientY - pan.startY);\n };\n\n const handlePanEnd = () => {\n if (!panStateRef.current?.active) return;\n panStateRef.current = null;\n const container = scrollContainerRef.current;\n if (container) container.style.cursor = '';\n };\n\n window.addEventListener('mousemove', handlePanMove);\n window.addEventListener('mouseup', handlePanEnd);\n return () => {\n window.removeEventListener('mousemove', handlePanMove);\n window.removeEventListener('mouseup', handlePanEnd);\n };\n }, []);\n\n return (\n <div className=\"gantt-container\">\n <div\n ref={scrollContainerRef}\n className=\"gantt-scrollContainer\"\n style={{ height: containerHeight ?? 'auto', cursor: 'grab' }}\n onMouseDown={handlePanStart}\n >\n {/* Content wrapper - enables TaskList to scroll with chart horizontally */}\n <div className=\"gantt-scrollContent\">\n {/* TaskList - sticky left, scrolls with content horizontally */}\n <TaskList\n tasks={normalizedTasks}\n rowHeight={rowHeight}\n headerHeight={headerHeight}\n taskListWidth={taskListWidth}\n onTasksChange={handleTaskChange}\n selectedTaskId={selectedTaskId ?? undefined}\n onTaskSelect={handleTaskSelect}\n show={showTaskList}\n hasRightShadow={taskListHasRightShadow}\n disableTaskNameEditing={disableTaskNameEditing}\n disableDependencyEditing={disableDependencyEditing}\n onScrollToTask={scrollToTask}\n onSelectedChipChange={setSelectedChip}\n onAdd={onAdd}\n onDelete={handleDelete}\n onInsertAfter={handleInsertAfter}\n onReorder={handleReorder}\n editingTaskId={editingTaskId}\n enableAddTask={enableAddTask}\n collapsedParentIds={collapsedParentIds}\n onToggleCollapse={handleToggleCollapse}\n onPromoteTask={onPromoteTask ?? handlePromoteTask}\n onDemoteTask={onDemoteTask ?? handleDemoteTask}\n highlightedTaskIds={matchedTaskIds}\n customDays={customDays}\n isWeekend={isWeekend}\n />\n\n {/* Chart area */}\n <div style={{ minWidth: `${gridWidth}px`, flex: 1 }}>\n {/* Sticky header - stays at top during vertical scroll, scrolls with content horizontally */}\n <div className=\"gantt-stickyHeader\" style={{ width: `${gridWidth}px` }}>\n <TimeScaleHeader\n days={dateRange}\n dayWidth={dayWidth}\n headerHeight={headerHeight}\n viewMode={viewMode}\n isCustomWeekend={isCustomWeekend}\n />\n </div>\n\n {/* Task area */}\n <div\n className=\"gantt-taskArea\"\n style={{\n position: 'relative',\n width: `${gridWidth}px`,\n }}\n >\n <GridBackground\n dateRange={dateRange}\n dayWidth={dayWidth}\n totalHeight={totalGridHeight}\n viewMode={viewMode}\n isCustomWeekend={isCustomWeekend}\n />\n\n {todayInRange && <TodayIndicator monthStart={monthStart} dayWidth={dayWidth} />}\n\n {/* Dependency lines SVG overlay */}\n <DependencyLines\n tasks={visibleTasks}\n allTasks={normalizedTasks}\n collapsedParentIds={collapsedParentIds}\n monthStart={monthStart}\n dayWidth={dayWidth}\n rowHeight={rowHeight}\n gridWidth={gridWidth}\n dragOverrides={dependencyOverrides}\n selectedDep={selectedChip}\n />\n\n {dragGuideLines && (\n <DragGuideLines\n isDragging={dragGuideLines.isDragging}\n dragMode={dragGuideLines.dragMode}\n left={dragGuideLines.left}\n width={dragGuideLines.width}\n totalHeight={totalGridHeight}\n />\n )}\n\n {visibleTasks.map((task, index) => (\n <TaskRow\n key={task.id}\n task={task}\n monthStart={monthStart}\n dayWidth={dayWidth}\n rowHeight={rowHeight}\n onTasksChange={handleTaskChange}\n onDragStateChange={(state) => {\n if (state.isDragging) {\n setDragGuideLines(state);\n setDraggedTaskOverride({ taskId: task.id, left: state.left, width: state.width });\n } else {\n setDragGuideLines(null);\n setDraggedTaskOverride(null);\n }\n }}\n rowIndex={index}\n allTasks={normalizedTasks}\n enableAutoSchedule={enableAutoSchedule ?? false}\n disableConstraints={disableConstraints ?? false}\n overridePosition={cascadeOverrides.get(task.id)}\n onCascadeProgress={handleCascadeProgress}\n onCascade={handleCascade}\n highlightExpiredTasks={highlightExpiredTasks}\n isFilterMatch={matchedTaskIds.has(task.id)}\n />\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nGanttChart.displayName = 'GanttChart';\n\nexport default GanttChart;\n","import { Task, TaskDependency, LinkType, ValidationResult, DependencyError } from '../types';\n\n/**\n * Build adjacency list for dependency graph (task -> successors)\n */\nexport function buildAdjacencyList(tasks: Task[]): Map<string, string[]> {\n const taskMap = new Map(tasks.map(t => [t.id, t]));\n const graph = new Map<string, string[]>();\n\n for (const task of tasks) {\n const successors: string[] = [];\n\n // Find all tasks that depend on this task (this task is a predecessor)\n for (const otherTask of tasks) {\n if (otherTask.dependencies) {\n for (const dep of otherTask.dependencies) {\n if (dep.taskId === task.id) {\n successors.push(otherTask.id);\n break;\n }\n }\n }\n }\n\n graph.set(task.id, successors);\n }\n\n return graph;\n}\n\n/**\n * Detect circular dependencies using depth-first search\n */\nexport function detectCycles(tasks: Task[]): { hasCycle: boolean; cyclePath?: string[] } {\n const graph = buildAdjacencyList(tasks);\n const visiting = new Set<string>();\n const visited = new Set<string>();\n const path: string[] = [];\n\n function dfs(taskId: string): boolean {\n if (visiting.has(taskId)) {\n // Found cycle - current task is already in recursion stack\n return true;\n }\n if (visited.has(taskId)) {\n return false;\n }\n\n visiting.add(taskId);\n path.push(taskId);\n\n const successors = graph.get(taskId) || [];\n for (const successor of successors) {\n if (dfs(successor)) {\n return true;\n }\n }\n\n visiting.delete(taskId);\n path.pop();\n visited.add(taskId);\n return false;\n }\n\n for (const task of tasks) {\n if (dfs(task.id)) {\n return { hasCycle: true, cyclePath: [...path] };\n }\n }\n\n return { hasCycle: false };\n}\n\n/**\n * Compute lag (in days) from actual predecessor/successor dates.\n * This is the single source of truth for lag semantics across chips, arrows, and drag.\n *\n * Semantics (lag=0 = natural, gap-free connection):\n * - FS: lag = succStart - predEnd - 1 (adjacent days = 0)\n * - SS: lag = succStart - predStart\n * - FF: lag = succEnd - predEnd\n * - SF: lag = succEnd - predStart + 1 (symmetric to FS)\n */\nexport function computeLagFromDates(\n linkType: LinkType,\n predStart: Date,\n predEnd: Date,\n succStart: Date,\n succEnd: Date\n): number {\n const DAY_MS = 24 * 60 * 60 * 1000;\n const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());\n const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());\n const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());\n const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());\n switch (linkType) {\n case 'FS': return Math.round((sS - pE) / DAY_MS) - 1;\n case 'SS': return Math.round((sS - pS) / DAY_MS);\n case 'FF': return Math.round((sE - pE) / DAY_MS);\n case 'SF': return Math.round((sE - pS) / DAY_MS) + 1;\n }\n}\n\n/**\n * Calculate successor date based on predecessor dates, link type, and lag\n *\n * Link type semantics:\n * - FS: Successor start = Predecessor end + lag + 1 day (lag=0 → next day)\n * - SS: Successor start = Predecessor start + lag\n * - FF: Successor end = Predecessor end + lag\n * - SF: Successor end = Predecessor start + lag - 1 day (lag=0 → day before)\n */\nexport function calculateSuccessorDate(\n predecessorStart: Date,\n predecessorEnd: Date,\n linkType: LinkType,\n lag: number = 0\n): Date {\n const DAY_MS = 24 * 60 * 60 * 1000;\n\n switch (linkType) {\n case 'FS':\n // lag=0 → successor starts the day after predecessor ends (inclusive dates)\n return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS);\n case 'SS':\n return new Date(predecessorStart.getTime() + lag * DAY_MS);\n case 'FF':\n return new Date(predecessorEnd.getTime() + lag * DAY_MS);\n case 'SF':\n // lag=0 → successor ends the day before predecessor starts (inclusive dates)\n return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS);\n }\n}\n\n/**\n * Validate all dependencies in the task list\n */\nexport function validateDependencies(tasks: Task[]): ValidationResult {\n const errors: DependencyError[] = [];\n const taskIds = new Set(tasks.map(t => t.id));\n\n // Check for missing predecessor references\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n if (!taskIds.has(dep.taskId)) {\n errors.push({\n type: 'missing-task',\n taskId: task.id,\n message: `Dependency references non-existent task: ${dep.taskId}`,\n relatedTaskIds: [dep.taskId],\n });\n }\n }\n }\n }\n\n // Check for cycles\n const cycleResult = detectCycles(tasks);\n if (cycleResult.hasCycle && cycleResult.cyclePath) {\n errors.push({\n type: 'cycle',\n taskId: cycleResult.cyclePath[0],\n message: 'Circular dependency detected',\n relatedTaskIds: cycleResult.cyclePath,\n });\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Get successor tasks of a dragged task using BFS, filtered by link type(s).\n *\n * Returns tasks in breadth-first order (direct successors first, then their successors).\n * The dragged task itself is NOT included in the returned array.\n *\n * The visited set prevents infinite loops in case of cycles (cycle detection already\n * prevents cycles in valid data, but the guard adds safety during cascade computation).\n *\n * @param draggedTaskId - ID of the task being dragged\n * @param allTasks - All tasks in the chart\n * @param linkTypes - Dependency types to follow (default: ['FS'] preserves Phase 7 behavior)\n */\nexport function getSuccessorChain(\n draggedTaskId: string,\n allTasks: Task[],\n linkTypes: LinkType[] = ['FS']\n): Task[] {\n // Build successor map filtered by requested link types: predecessor -> [successors]\n const successorMap = new Map<string, string[]>();\n for (const task of allTasks) {\n successorMap.set(task.id, []);\n }\n for (const task of allTasks) {\n if (!task.dependencies) continue;\n for (const dep of task.dependencies) {\n if (linkTypes.includes(dep.type)) {\n const list = successorMap.get(dep.taskId) ?? [];\n list.push(task.id);\n successorMap.set(dep.taskId, list);\n }\n }\n }\n\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n const visited = new Set<string>();\n const queue: string[] = [draggedTaskId];\n const chain: Task[] = [];\n visited.add(draggedTaskId); // seed — not added to chain\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n const successors = successorMap.get(current) ?? [];\n for (const sid of successors) {\n if (!visited.has(sid)) {\n visited.add(sid);\n const t = taskById.get(sid);\n if (t) {\n chain.push(t);\n queue.push(sid);\n }\n }\n }\n }\n\n return chain; // excludes dragged task\n}\n\n/**\n * Cascade successors by actual link constraints (BFS, constraint-based).\n *\n * Each successor in the chain is positioned using calculateSuccessorDate\n * with the predecessor's NEW dates and the actual lag — not a flat delta.\n *\n * - FS/SS: constraintDate = new start of successor (duration preserved)\n * - FF/SF: constraintDate = new end of successor (duration preserved)\n *\n * Locked tasks break the chain.\n * Also cascades hierarchy children when a parent moves (when parent moves by\n * dependency link, children must move with it to maintain parent-child relationship).\n * Returns only the cascaded successors (not the moved task itself).\n */\nexport function cascadeByLinks(\n movedTaskId: string,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[],\n skipChildCascade: boolean = false\n): Task[] {\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n\n // Track each task's updated dates\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTaskId, { start: newStart, end: newEnd });\n\n const result: Task[] = [];\n const queue: string[] = [movedTaskId];\n const visited = new Set<string>([movedTaskId]);\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n const { start: predStart, end: predEnd } = updatedDates.get(currentId)!;\n\n // First, cascade hierarchy children of the current task if it's a parent\n // Skip if skipChildCascade is true (for parent task editing via task list)\n if (!skipChildCascade) {\n const children = getChildren(currentId, allTasks);\n for (const child of children) {\n if (visited.has(child.id) || child.locked) continue;\n\n // When a parent moves, its children move by the same delta\n const origStart = new Date(child.startDate as string);\n const origEnd = new Date(child.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n const parentOrig = taskById.get(currentId)!;\n const parentOrigStart = new Date(parentOrig.startDate as string);\n const parentOrigEnd = new Date(parentOrig.endDate as string);\n\n // Calculate delta from parent's original to new position\n const parentStartDelta = predStart.getTime() - parentOrigStart.getTime();\n const parentEndDelta = predEnd.getTime() - parentOrigEnd.getTime();\n\n const newChildStart = new Date(origStart.getTime() + parentStartDelta);\n const newChildEnd = new Date(origEnd.getTime() + parentEndDelta);\n\n visited.add(child.id);\n updatedDates.set(child.id, { start: newChildStart, end: newChildEnd });\n result.push({\n ...child,\n startDate: newChildStart.toISOString().split('T')[0],\n endDate: newChildEnd.toISOString().split('T')[0],\n });\n queue.push(child.id);\n }\n }\n\n // Then, cascade dependency successors\n for (const task of allTasks) {\n if (visited.has(task.id) || !task.dependencies || task.locked) continue;\n\n for (const dep of task.dependencies) {\n if (dep.taskId !== currentId) continue;\n\n const orig = taskById.get(task.id)!;\n const origStart = new Date(orig.startDate as string);\n const origEnd = new Date(orig.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n // Use effective lag from dates, not stored dep.lag\n const predOrig = taskById.get(currentId)!;\n const predOrigStart = new Date(predOrig.startDate as string);\n const predOrigEnd = new Date(predOrig.endDate as string);\n const effectiveLag = computeLagFromDates(dep.type, predOrigStart, predOrigEnd, origStart, origEnd);\n\n const constraintDate = calculateSuccessorDate(predStart, predEnd, dep.type, effectiveLag);\n\n let newSuccStart: Date;\n let newSuccEnd: Date;\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n newSuccStart = constraintDate;\n newSuccEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n // FF or SF: constraintDate is the end date\n newSuccEnd = constraintDate;\n newSuccStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n visited.add(task.id);\n updatedDates.set(task.id, { start: newSuccStart, end: newSuccEnd });\n result.push({\n ...task,\n startDate: newSuccStart.toISOString().split('T')[0],\n endDate: newSuccEnd.toISOString().split('T')[0],\n });\n queue.push(task.id);\n break; // one predecessor per cascade step\n }\n }\n }\n\n return result;\n}\n\n/**\n * Get transitive closure of successors for cascading.\n *\n * Direct successors of the changed task are filtered by firstLevelLinkTypes.\n * Their successors (and so on) are included regardless of link type.\n *\n * Also includes hierarchy children of any parent task in the chain - when a parent\n * moves via dependency cascade, its children must move with it.\n */\nexport function getTransitiveCascadeChain(\n changedTaskId: string,\n allTasks: Task[],\n firstLevelLinkTypes: LinkType[]\n): Task[] {\n const allTypesSuccessorMap = new Map<string, Task[]>();\n for (const task of allTasks) {\n allTypesSuccessorMap.set(task.id, []);\n }\n for (const task of allTasks) {\n if (!task.dependencies) continue;\n for (const dep of task.dependencies) {\n const list = allTypesSuccessorMap.get(dep.taskId) ?? [];\n list.push(task);\n allTypesSuccessorMap.set(dep.taskId, list);\n }\n }\n\n const directChildren = getChildren(changedTaskId, allTasks);\n const directSuccessors = getSuccessorChain(changedTaskId, allTasks, firstLevelLinkTypes);\n const initialChain = [...directChildren, ...directSuccessors].filter((task, index, arr) =>\n arr.findIndex(candidate => candidate.id === task.id) === index\n );\n\n const chain = [...initialChain];\n const visited = new Set<string>([changedTaskId, ...initialChain.map(t => t.id)]);\n const queue = [...initialChain];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n // Add hierarchy children of the current task if it's a parent\n const children = getChildren(current.id, allTasks);\n for (const child of children) {\n if (!visited.has(child.id)) {\n visited.add(child.id);\n chain.push(child);\n queue.push(child);\n }\n }\n\n const successors = allTypesSuccessorMap.get(current.id) ?? [];\n for (const successor of successors) {\n if (!visited.has(successor.id)) {\n visited.add(successor.id);\n chain.push(successor);\n queue.push(successor);\n }\n }\n }\n\n return chain;\n}\n\n/**\n * Recalculate incoming dependency lags after a task's dates change.\n * Used when completing a drag or applying a manual date change.\n */\nexport function recalculateIncomingLags(\n task: Task,\n newStartDate: Date,\n newEndDate: Date,\n allTasks: Task[]\n): NonNullable<Task['dependencies']> {\n if (!task.dependencies) return [];\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n\n return task.dependencies.map(dep => {\n const predecessor = taskById.get(dep.taskId);\n if (!predecessor) return dep;\n\n const predStart = new Date(predecessor.startDate as string);\n const predEnd = new Date(predecessor.endDate as string);\n const lagDays = computeLagFromDates(dep.type, predStart, predEnd, newStartDate, newEndDate);\n return { ...dep, lag: lagDays };\n });\n}\n\n/**\n * Get all dependency edges for rendering\n * Returns array of { predecessorId, successorId, type, lag }\n */\nexport function getAllDependencyEdges(tasks: Task[]): Array<{\n predecessorId: string;\n successorId: string;\n type: LinkType;\n lag: number;\n}> {\n const edges: Array<{ predecessorId: string; successorId: string; type: LinkType; lag: number }> = [];\n\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n edges.push({\n predecessorId: dep.taskId,\n successorId: task.id,\n type: dep.type,\n lag: dep.lag ?? 0,\n });\n }\n }\n }\n\n return edges;\n}\n\n// ============================================================================\n// Hierarchy Utilities (Phase 19)\n// ============================================================================\n\n/**\n * Get all child tasks of a parent task.\n * Returns tasks where task.parentId === parentId.\n */\nexport function getChildren(parentId: string, tasks: Task[]): Task[] {\n return tasks.filter(t => (t as any).parentId === parentId);\n}\n\n/**\n * Check if a task is a parent (has children).\n * Returns true if any task has this task as parentId.\n */\nexport function isTaskParent(taskId: string, tasks: Task[]): boolean {\n return tasks.some(t => (t as any).parentId === taskId);\n}\n\n/**\n * Compute parent task dates from children.\n * Returns { startDate, endDate } where:\n * - startDate = min(children.startDate) or own startDate if no children\n * - endDate = max(children.endDate) or own endDate if no children\n */\nexport function computeParentDates(parentId: string, tasks: Task[]): { startDate: Date; endDate: Date } {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n // Empty parent - use own dates or default\n const parent = tasks.find(t => t.id === parentId);\n const start = parent ? new Date(parent.startDate) : new Date();\n const end = parent ? new Date(parent.endDate) : new Date();\n return { startDate: start, endDate: end };\n }\n\n const startDates = children.map(c => new Date(c.startDate));\n const endDates = children.map(c => new Date(c.endDate));\n\n const minTime = Math.min(...startDates.map(d => d.getTime()));\n const maxTime = Math.max(...endDates.map(d => d.getTime()));\n\n return {\n startDate: new Date(minTime),\n endDate: new Date(maxTime),\n };\n}\n\n/**\n * Compute parent task progress from children (weighted average by duration).\n * Returns 0 if no children.\n * Progress is rounded to 1 decimal place.\n */\nexport function computeParentProgress(parentId: string, tasks: Task[]): number {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n return 0;\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n let totalWeight = 0;\n let weightedSum = 0;\n\n for (const child of children) {\n const start = new Date(child.startDate).getTime();\n const end = new Date(child.endDate).getTime();\n // Inclusive duration: (end - start + 1 day) / DAY_MS\n const duration = (end - start + DAY_MS) / DAY_MS;\n const progress = (child.progress ?? 0);\n\n totalWeight += duration;\n weightedSum += duration * progress;\n }\n\n if (totalWeight === 0) {\n return 0;\n }\n\n // Round to 1 decimal place\n return Math.round((weightedSum / totalWeight) * 10) / 10;\n}\n\n/**\n * Remove dependencies between two tasks in both directions.\n * When tasks become parent-child, their dependency link becomes meaningless.\n *\n * @param taskId1 - First task ID\n * @param taskId2 - Second task ID\n * @param tasks - All tasks array\n * @returns New tasks array with dependencies between the two tasks removed\n */\nexport function removeDependenciesBetweenTasks(\n taskId1: string,\n taskId2: string,\n tasks: Task[]\n): Task[] {\n return tasks.map(task => {\n if (task.id === taskId1 || task.id === taskId2) {\n if (!task.dependencies) return task;\n const otherTaskId = task.id === taskId1 ? taskId2 : taskId1;\n const filteredDependencies = task.dependencies.filter(dep => dep.taskId !== otherTaskId);\n // Only create new object if dependencies actually changed\n if (filteredDependencies.length === task.dependencies.length) {\n return task;\n }\n return {\n ...task,\n dependencies: filteredDependencies.length > 0 ? filteredDependencies : undefined,\n };\n }\n return task;\n });\n}\n\n/**\n * Find the parent ID of a task.\n * Returns the parentId of the task if found, undefined otherwise.\n *\n * @param taskId - ID of the task to find parent for\n * @param tasks - All tasks array\n * @returns Parent task ID or undefined if task is root or not found\n */\nexport function findParentId(taskId: string, tasks: Task[]): string | undefined {\n const task = tasks.find(t => t.id === taskId);\n return task?.parentId;\n}\n\n/**\n * Get all descendant tasks of a parent task (transitive closure of children).\n * Returns all tasks where task.parentId is in the hierarchy of the parent.\n *\n * @param parentId - ID of the parent task\n * @param tasks - All tasks array\n * @returns Array of descendant tasks (not including the parent itself)\n */\nexport function getAllDescendants(parentId: string, tasks: Task[]): Task[] {\n const descendants: Task[] = [];\n const visited = new Set<string>();\n\n function collectChildren(taskId: string) {\n if (visited.has(taskId)) return;\n visited.add(taskId);\n\n const children = getChildren(taskId, tasks);\n for (const child of children) {\n descendants.push(child);\n collectChildren(child.id);\n }\n }\n\n collectChildren(parentId);\n return descendants;\n}\n\n// ============================================================================\n// Universal Cascade Engine (Phase 19 fix)\n// ============================================================================\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/**\n * How a task arrived in the BFS queue — controls which rules apply when\n * processing it.\n *\n * 'direct' — The explicitly moved task (seed).\n * 'child-delta' — Added by RULE 1: parent dragged, child inherits delta.\n * Children of THIS task also inherit the same delta (RULE 1 applies).\n * 'parent-recalc'— Added by RULE 2: a child moved, parent recomputed from children.\n * Children of THIS task must NOT be shifted again (RULE 1 skipped).\n * 'dependency' — Added by RULE 3: predecessor moved, successor repositioned.\n * Children of THIS task inherit the delta (RULE 1 applies).\n */\ntype ArrivalMode = 'direct' | 'child-delta' | 'parent-recalc' | 'dependency';\n\n/**\n * Universal cascade engine that propagates a moved task's new position through\n * the entire dependency+hierarchy graph using BFS with change detection.\n *\n * Three rules applied in BFS order:\n *\n * RULE 1 — Hierarchy children of a parent task shift by the parent's delta.\n * Applied only when the parent arrived as 'direct', 'child-delta', or 'dependency'.\n * Skipped for 'parent-recalc' (parent was computed FROM children).\n *\n * RULE 2 — Parent task is recomputed as min(children.start)..max(children.end).\n * Re-queued every time a child changes (no visited guard — uses change detection).\n * This ensures the parent reflects ALL cascaded children, not just the first one.\n *\n * RULE 3 — Dependency successors are repositioned via calculateSuccessorDate.\n * Effective lag is computed from original dates (not stored dep.lag).\n * Re-queued if predecessor's dates changed (change detection).\n *\n * Change detection prevents infinite loops: a task is only re-queued if its\n * computed dates differ from what's already in updatedDates.\n *\n * @param movedTask - The task that was directly moved/resized (already has new dates).\n * @param newStart - New start date of the moved task.\n * @param newEnd - New end date of the moved task.\n * @param allTasks - All tasks in the chart (original, unmodified dates).\n */\nexport function universalCascade(\n movedTask: Task,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[]\n): Task[] {\n const taskById = new Map(allTasks.map(t => [t.id, t]));\n\n // updatedDates: authoritative new position for every affected task\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTask.id, { start: newStart, end: newEnd });\n\n // resultMap: deduplicated results keyed by task ID (updated in place on re-visits)\n const resultMap = new Map<string, Task>();\n\n // Queue entries: [taskId, arrivalMode]\n const queue: Array<[string, ArrivalMode]> = [[movedTask.id, 'direct']];\n\n // Guard: track which children have been shifted by RULE 1 to prevent double-shift\n const childShifted = new Set<string>();\n\n // Safety: max iterations to prevent runaway loops\n let iterations = 0;\n const MAX_ITERATIONS = allTasks.length * 3;\n\n while (queue.length > 0 && iterations < MAX_ITERATIONS) {\n iterations++;\n const [currentId, arrivalMode] = queue.shift()!;\n const { start: currStart, end: currEnd } = updatedDates.get(currentId)!;\n const currentOriginal = taskById.get(currentId)!;\n\n // ── RULE 1: Hierarchy children follow their parent ──────────────────────\n if (arrivalMode !== 'parent-recalc') {\n const children = getChildren(currentId, allTasks);\n for (const child of children) {\n if (childShifted.has(child.id) || child.locked) continue;\n\n const parentOrigStart = new Date(currentOriginal.startDate as string);\n const parentOrigEnd = new Date(currentOriginal.endDate as string);\n\n const childOrigStart = new Date(child.startDate as string);\n const childOrigEnd = new Date(child.endDate as string);\n\n const startDeltaMs = currStart.getTime() - parentOrigStart.getTime();\n const endDeltaMs = currEnd.getTime() - parentOrigEnd.getTime();\n\n const childNewStart = new Date(childOrigStart.getTime() + startDeltaMs);\n const childNewEnd = new Date(childOrigEnd.getTime() + endDeltaMs);\n\n // Change detection: skip if already at this position\n const prev = updatedDates.get(child.id);\n if (prev && prev.start.getTime() === childNewStart.getTime() && prev.end.getTime() === childNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(child.id, { start: childNewStart, end: childNewEnd });\n childShifted.add(child.id);\n queue.push([child.id, 'child-delta']);\n resultMap.set(child.id, {\n ...child,\n startDate: childNewStart.toISOString().split('T')[0],\n endDate: childNewEnd.toISOString().split('T')[0],\n });\n }\n }\n\n // ── RULE 2: Parent task is recomputed from its children ─────────────────\n // No visited guard — always recalculate, re-queue only if dates changed.\n // This ensures parent reflects ALL cascaded children (not just the first).\n const parentId = (currentOriginal as any).parentId as string | undefined;\n if (parentId) {\n const parent = taskById.get(parentId);\n if (parent && !parent.locked) {\n const siblings = getChildren(parentId, allTasks);\n\n const siblingPositions = siblings.map(sib => {\n if (updatedDates.has(sib.id)) return updatedDates.get(sib.id)!;\n return { start: new Date(sib.startDate as string), end: new Date(sib.endDate as string) };\n });\n\n const minStart = new Date(Math.min(...siblingPositions.map(p => p.start.getTime())));\n const maxEnd = new Date(Math.max(...siblingPositions.map(p => p.end.getTime())));\n\n // Change detection: only re-queue if parent dates actually changed\n const prev = updatedDates.get(parentId);\n if (!prev || prev.start.getTime() !== minStart.getTime() || prev.end.getTime() !== maxEnd.getTime()) {\n updatedDates.set(parentId, { start: minStart, end: maxEnd });\n queue.push([parentId, 'parent-recalc']);\n resultMap.set(parentId, {\n ...parent,\n startDate: minStart.toISOString().split('T')[0],\n endDate: maxEnd.toISOString().split('T')[0],\n });\n }\n }\n }\n\n // ── RULE 3: Dependency successors are repositioned ──────────────────────\n // No visited guard — uses change detection to allow re-cascading when\n // predecessor dates change (e.g., parent recalculated after more children cascade).\n for (const task of allTasks) {\n if (task.locked || !task.dependencies) continue;\n\n const dep = task.dependencies.find(d => d.taskId === currentId);\n if (!dep) continue;\n\n const origStart = new Date(task.startDate as string);\n const origEnd = new Date(task.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n // Effective lag from original dates (source of truth)\n const predOrigStart = new Date(currentOriginal.startDate as string);\n const predOrigEnd = new Date(currentOriginal.endDate as string);\n const effectiveLag = computeLagFromDates(dep.type, predOrigStart, predOrigEnd, origStart, origEnd);\n\n const constraintDate = calculateSuccessorDate(currStart, currEnd, dep.type, effectiveLag);\n\n let succNewStart: Date;\n let succNewEnd: Date;\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n succNewStart = constraintDate;\n succNewEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n succNewEnd = constraintDate;\n succNewStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n // Change detection: skip if already at this position\n const prev = updatedDates.get(task.id);\n if (prev && prev.start.getTime() === succNewStart.getTime() && prev.end.getTime() === succNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(task.id, { start: succNewStart, end: succNewEnd });\n queue.push([task.id, 'dependency']);\n resultMap.set(task.id, {\n ...task,\n startDate: succNewStart.toISOString().split('T')[0],\n endDate: succNewEnd.toISOString().split('T')[0],\n });\n }\n }\n\n return Array.from(resultMap.values());\n}\n","import type { Task } from '../types';\nimport { computeParentDates, computeParentProgress, isTaskParent } from './dependencyUtils';\nimport { normalizeTaskDates } from './dateUtils';\n\n/**\n * Build a stable depth-first task order from parentId links.\n * Sibling order follows the order in the input array.\n * Tasks with missing parents are treated as root tasks.\n */\nexport function flattenHierarchy<T extends Task>(tasks: T[]): T[] {\n const byId = new Map(tasks.map((task) => [task.id, task]));\n const byParent = new Map<string | undefined, T[]>();\n\n for (const task of tasks) {\n const normalizedParentId = task.parentId && byId.has(task.parentId)\n ? task.parentId\n : undefined;\n const siblings = byParent.get(normalizedParentId) ?? [];\n siblings.push(task);\n byParent.set(normalizedParentId, siblings);\n }\n\n const result: T[] = [];\n const visited = new Set<string>();\n\n const walk = (parentId?: string) => {\n const children = byParent.get(parentId) ?? [];\n for (const task of children) {\n if (visited.has(task.id)) continue;\n visited.add(task.id);\n result.push(task);\n walk(task.id);\n }\n };\n\n walk(undefined);\n\n for (const task of tasks) {\n if (!visited.has(task.id)) {\n result.push(task);\n }\n }\n\n return result;\n}\n\n/**\n * Normalize hierarchy-aware display fields.\n * Parent task dates and progress are always recomputed from children,\n * taking precedence over any hardcoded parent values from the input.\n * Also normalizes task dates to ensure startDate is always before or equal to endDate.\n */\nexport function normalizeHierarchyTasks<T extends Task>(tasks: T[]): T[] {\n const orderedTasks = flattenHierarchy(tasks).map((task) => {\n // Normalize dates for all tasks (swap if endDate < startDate)\n const { startDate, endDate } = normalizeTaskDates(task.startDate, task.endDate);\n return { ...task, startDate: startDate as T['startDate'], endDate: endDate as T['endDate'] };\n }) as T[];\n\n for (const task of [...orderedTasks].reverse()) {\n if (!isTaskParent(task.id, orderedTasks)) continue;\n\n const { startDate, endDate } = computeParentDates(task.id, orderedTasks);\n const progress = computeParentProgress(task.id, orderedTasks);\n const normalizedStartDate = startDate.toISOString().split('T')[0];\n const normalizedEndDate = endDate.toISOString().split('T')[0];\n const parentIndex = orderedTasks.findIndex((candidate) => candidate.id === task.id);\n\n if (parentIndex === -1) continue;\n\n orderedTasks[parentIndex] = {\n ...orderedTasks[parentIndex],\n startDate: normalizedStartDate as T['startDate'],\n endDate: normalizedEndDate as T['endDate'],\n progress: progress as T['progress'],\n };\n }\n\n return orderedTasks;\n}\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { format } from 'date-fns';\nimport { ru } from 'date-fns/locale';\nimport { getMonthSpans, getWeekSpans, getWeekBlocks, getMonthBlocks, getYearSpans, type WeekBlock, type WeekSpan, type MonthBlock, type YearSpan } from '../../utils/dateUtils';\nimport type { MonthSpan } from '../../types';\nimport './TimeScaleHeader.css';\n\nexport interface TimeScaleHeaderProps {\n /** Array of dates to display (from getMultiMonthDays) */\n days: Date[];\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Height of the header row in pixels */\n headerHeight: number;\n /** View mode: 'day' renders individual day columns, 'week' renders 7-day week columns, 'month' renders one column per month */\n viewMode?: 'day' | 'week' | 'month';\n /** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */\n isCustomWeekend?: (date: Date) => boolean;\n}\n\n/**\n * TimeScaleHeader component - displays two-row date headers for the Gantt chart\n *\n * Top row: Month names (Russian, left-aligned) spanning multiple day/week columns\n * Bottom row: Day numbers (centered) in individual day columns OR week start day numbers\n *\n * Supports two view modes:\n * - day (default): each column = 1 day, shows month names + individual day numbers\n * - week: each column = 7 days, shows month names spanning week columns + week-start dates\n */\nconst TimeScaleHeader: React.FC<TimeScaleHeaderProps> = ({\n days,\n dayWidth,\n headerHeight,\n viewMode = 'day',\n isCustomWeekend,\n}) => {\n // Calculate month spans using the utility from dateUtils\n const monthSpans = useMemo(() => getMonthSpans(days), [days]);\n\n // Split header height evenly between two rows\n const rowHeight = headerHeight / 2;\n\n // Calculate grid template for day row\n const dayGridTemplate = useMemo(\n () => `repeat(${days.length}, ${dayWidth}px)`,\n [days.length, dayWidth]\n );\n\n // Week-view: blocks with variable width (split on month boundaries)\n const weekBlocks = useMemo(\n () => (viewMode === 'week' ? getWeekBlocks(days) : []),\n [days, viewMode]\n );\n\n // Week-view: month spans grouped over week-blocks (row 1 labels)\n const weekSpans = useMemo(\n () => (viewMode === 'week' ? getWeekSpans(days) : []),\n [days, viewMode]\n );\n\n // Calculate column widths for each block (for grid template)\n const weekColumnWidths = useMemo(\n () => weekBlocks.map(b => b.days * dayWidth),\n [weekBlocks, dayWidth]\n );\n\n // Calculate total width for grid template\n const weekGridTemplate = useMemo(\n () => weekColumnWidths.map(w => `${w}px`).join(' '),\n [weekColumnWidths]\n );\n\n // Month-view: one block per calendar month (row 2 columns)\n const monthBlocks = useMemo(\n () => (viewMode === 'month' ? getMonthBlocks(days) : []),\n [days, viewMode]\n );\n\n // Month-view: year spans over month blocks (row 1 labels)\n const yearSpans = useMemo(\n () => (viewMode === 'month' ? getYearSpans(days) : []),\n [days, viewMode]\n );\n\n // Month-view: grid template for row 2 (variable column widths = days * dayWidth)\n const monthGridTemplate = useMemo(\n () => monthBlocks.map(b => `${b.days * dayWidth}px`).join(' '),\n [monthBlocks, dayWidth]\n );\n\n // Separator positions — same Math.round formula as GridBackground to guarantee pixel alignment.\n // fullHeight=true → spans both header rows (thick boundary between spans in row 1).\n // fullHeight=false → spans row 2 only (thin sub-column divider, doesn't cut through row 1 spans).\n const separators = useMemo(() => {\n const result: Array<{ x: number; isThick: boolean; fullHeight: boolean }> = [];\n if (viewMode === 'day') {\n for (let i = 1; i < days.length; i++) {\n if (days[i].getUTCDate() === 1) {\n result.push({ x: Math.round(i * dayWidth), isThick: true, fullHeight: true });\n }\n }\n } else if (viewMode === 'week') {\n let dayIndex = 0;\n for (let i = 0; i < weekBlocks.length; i++) {\n if (i > 0) {\n const isMonth = weekBlocks[i - 1].startDate.getUTCMonth() !== weekBlocks[i].startDate.getUTCMonth();\n result.push({ x: Math.round(dayIndex * dayWidth), isThick: isMonth, fullHeight: isMonth });\n }\n dayIndex += weekBlocks[i].days;\n }\n } else if (viewMode === 'month') {\n let dayIndex = 0;\n for (let i = 0; i < monthBlocks.length; i++) {\n if (i > 0) {\n const isYear = monthBlocks[i].startDate.getUTCMonth() === 0;\n result.push({ x: Math.round(dayIndex * dayWidth), isThick: isYear, fullHeight: isYear });\n }\n dayIndex += monthBlocks[i].days;\n }\n }\n return result;\n }, [days, weekBlocks, monthBlocks, dayWidth, viewMode]);\n\n return (\n <div\n className=\"gantt-tsh-header\"\n style={{ height: `${headerHeight}px`, position: 'relative' }}\n >\n {/* Separator lines — pixel-aligned with GridBackground */}\n {separators.map((sep, i) => (\n <div\n key={`sep-${i}`}\n className={`gantt-tsh-separator${sep.isThick ? ' gantt-tsh-separator--thick' : ''}`}\n style={sep.fullHeight\n ? { left: `${sep.x}px`, top: 0, bottom: 0 }\n : { left: `${sep.x}px`, top: rowHeight, height: rowHeight }}\n />\n ))}\n\n {/* Month row - top */}\n <div\n className=\"gantt-tsh-monthRow\"\n style={{ height: `${rowHeight}px` }}\n >\n {viewMode === 'week' ? (\n // Week-view row 1: month names spanning week blocks\n weekSpans.map((span: WeekSpan, index: number) => (\n <div\n key={`wmonth-${index}`}\n className=\"gantt-tsh-monthCell\"\n style={{ width: `${span.days * dayWidth}px` }}\n >\n {format(span.month, 'LLLL yyyy', { locale: ru }).replace(/^./, (c) => c.toUpperCase())}\n </div>\n ))\n ) : viewMode === 'month' ? (\n // Month-view row 1: year labels spanning all months of that year\n yearSpans.map((span: YearSpan, index: number) => (\n <div\n key={`year-${index}`}\n className=\"gantt-tsh-monthCell\"\n style={{ width: `${span.days * dayWidth}px` }}\n >\n {span.year.getUTCFullYear().toString()}\n </div>\n ))\n ) : (\n // Day-view row 1: month names spanning day columns (existing code)\n monthSpans.map((span: MonthSpan, index: number) => (\n <div\n key={`month-${index}`}\n className=\"gantt-tsh-monthCell\"\n style={{ width: `${span.days * dayWidth}px` }}\n >\n {format(span.month, 'LLLL yyyy', { locale: ru }).replace(/^./, (c) => c.toUpperCase())}\n </div>\n ))\n )}\n </div>\n\n {/* Day/Week row - bottom */}\n <div\n className=\"gantt-tsh-dayRow\"\n style={{\n height: `${rowHeight}px`,\n gridTemplateColumns: viewMode === 'week'\n ? weekGridTemplate\n : viewMode === 'month'\n ? monthGridTemplate\n : dayGridTemplate,\n }}\n >\n {viewMode === 'week' ? (\n // Week-view row 2: week block start day numbers (variable width)\n weekBlocks.map((block, index) => {\n const prevBlock = weekBlocks[index - 1];\n const isMonthBoundary =\n index > 0 && prevBlock &&\n prevBlock.startDate.getUTCMonth() !== block.startDate.getUTCMonth();\n // Show date only for full weeks (7 days)\n const showDate = block.days === 7;\n return (\n <div\n key={`week-${index}`}\n className=\"gantt-tsh-dayCell gantt-tsh-weekCell\"\n >\n <span className=\"gantt-tsh-dayLabel\">\n {showDate ? String(block.startDate.getUTCDate()).padStart(2, '0') : ''}\n </span>\n </div>\n );\n })\n ) : viewMode === 'month' ? (\n // Month-view row 2: one column per month, shows abbreviated month name\n monthBlocks.map((block: MonthBlock, index: number) => {\n const MIN_DAYS_TO_SHOW_LABEL = 15;\n const showLabel = block.days >= MIN_DAYS_TO_SHOW_LABEL;\n const isYearBoundary = index > 0 && block.startDate.getUTCMonth() === 0;\n return (\n <div\n key={`mblock-${index}`}\n className=\"gantt-tsh-dayCell gantt-tsh-weekCell\"\n >\n <span className=\"gantt-tsh-dayLabel\">\n {showLabel\n ? (() => { const s = block.startDate.toLocaleString('ru-RU', { month: 'long', timeZone: 'UTC' }); return s.charAt(0).toUpperCase() + s.slice(1); })()\n : ''}\n </span>\n </div>\n );\n })\n ) : (\n // Day-view row 2: individual day numbers (existing code)\n days.map((day, index) => {\n const isWeekendDay = isCustomWeekend\n ? isCustomWeekend(day)\n : day.getUTCDay() === 0 || day.getUTCDay() === 6;\n const prevDay = days[index - 1];\n const isMonthBoundary = index > 0 && prevDay && prevDay.getUTCMonth() !== day.getUTCMonth();\n // Use local date comparison for \"today\" (user's current date)\n const now = new Date();\n const isTodayDate =\n day.getUTCFullYear() === now.getFullYear() &&\n day.getUTCMonth() === now.getMonth() &&\n day.getUTCDate() === now.getDate();\n return (\n <div key={`day-${index}`} className={`gantt-tsh-dayCell ${isWeekendDay ? 'gantt-tsh-weekendDay' : ''} ${isTodayDate ? 'gantt-tsh-today' : ''}`}>\n <span className=\"gantt-tsh-dayLabel\">{format(day, 'd')}</span>\n </div>\n );\n })\n )}\n </div>\n </div>\n );\n};\n\nexport default TimeScaleHeader;\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { parseUTCDate, formatDateLabel } from '../../utils/dateUtils';\nimport { calculateTaskBar, pixelsToDate } from '../../utils/geometry';\nimport { isTaskExpired } from '../../utils/expired';\nimport { useTaskDrag } from '../../hooks/useTaskDrag';\nimport { isTaskParent, getChildren } from '../../utils/dependencyUtils';\nimport type { Task } from '../GanttChart';\nimport './TaskRow.css';\n\nexport interface TaskRowProps {\n /** Task data to render */\n task: Task;\n /** Start of the month for positioning calculations */\n monthStart: Date;\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Height of the task row in pixels */\n rowHeight: number;\n /** Callback when task is modified via drag/resize. Receives array of changed tasks. */\n onTasksChange?: (tasks: Task[]) => void;\n /** Callback when task drag state changes (for rendering guide lines) */\n onDragStateChange?: (state: {\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n }) => void;\n /** Index of the task row (used for dependency rendering) */\n rowIndex?: number;\n /** All tasks in the chart (used for dependency validation) */\n allTasks?: Task[];\n /** Whether auto-scheduling is enabled */\n enableAutoSchedule?: boolean;\n /** Whether to disable constraint checking during drag */\n disableConstraints?: boolean;\n /** Position override for cascade preview — when set, overrides both static and drag position */\n overridePosition?: { left: number; width: number };\n /** Called each RAF during cascade drag with override positions for non-dragged chain tasks */\n onCascadeProgress?: (overrides: Map<string, { left: number; width: number }>) => void;\n /** Called when cascade drag completes; receives all shifted tasks including dragged task */\n onCascade?: (tasks: Task[]) => void;\n /** Optional horizontal divider line - renders above or below the task row */\n divider?: 'top' | 'bottom';\n /** Highlight expired/overdue tasks with red background */\n highlightExpiredTasks?: boolean;\n /** Whether this row matches the active filter highlight */\n isFilterMatch?: boolean;\n}\n\n/**\n * Custom comparison function for React.memo\n *\n * Performance optimization: Only re-renders if task properties that affect rendering change.\n *\n * NOTE: onTasksChange is intentionally excluded from this comparison because:\n * 1. The parent (GanttChart) wraps onTasksChange in useCallback for referential stability\n * 2. onTasksChange is only called AFTER drag completes (not during drag)\n * 3. During drag, only the dragged TaskRow re-renders due to its internal drag state\n * 4. Other TaskRows don't need to re-render when one task is dragged\n *\n * NOTE: monthStart MUST be included because task positions are calculated relative to it.\n * When the grid expands (e.g., dragging a task left beyond the boundary), monthStart changes\n * and all tasks need to re-render to update their positions.\n *\n * NOTE: onCascadeProgress and onCascade are excluded from comparison (same pattern as onTasksChange —\n * callbacks excluded from comparison because GanttChart wraps them in useCallback).\n *\n * Excluding onTasksChange prevents re-render storms when dragging tasks with ~100 tasks.\n */\nconst arePropsEqual = (prevProps: TaskRowProps, nextProps: TaskRowProps) => {\n return (\n prevProps.task.id === nextProps.task.id &&\n prevProps.task.name === nextProps.task.name &&\n prevProps.task.startDate === nextProps.task.startDate &&\n prevProps.task.endDate === nextProps.task.endDate &&\n prevProps.task.color === nextProps.task.color &&\n prevProps.task.progress === nextProps.task.progress &&\n prevProps.task.accepted === nextProps.task.accepted &&\n prevProps.monthStart.getTime() === nextProps.monthStart.getTime() &&\n prevProps.dayWidth === nextProps.dayWidth &&\n prevProps.rowHeight === nextProps.rowHeight &&\n prevProps.overridePosition?.left === nextProps.overridePosition?.left &&\n prevProps.overridePosition?.width === nextProps.overridePosition?.width &&\n prevProps.allTasks === nextProps.allTasks &&\n prevProps.disableConstraints === nextProps.disableConstraints &&\n prevProps.task.locked === nextProps.task.locked &&\n prevProps.task.divider === nextProps.task.divider &&\n prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks &&\n prevProps.isFilterMatch === nextProps.isFilterMatch\n // onTasksChange, onCascadeProgress, onCascade excluded - see note above\n );\n};\n\n/**\n * TaskRow component - renders a single task row with a task bar\n *\n * Uses React.memo for performance optimization (QL-01).\n * The task bar is positioned absolutely based on start/end dates.\n */\nconst TaskRow: React.FC<TaskRowProps> = React.memo(\n ({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isFilterMatch = false }) => {\n // Extract divider from task prop\n const { divider: taskDivider } = task;\n\n // Parse dates as UTC\n const taskStartDate = useMemo(() => parseUTCDate(task.startDate), [task.startDate]);\n const taskEndDate = useMemo(() => parseUTCDate(task.endDate), [task.endDate]);\n\n // Hierarchy: compute isParent and childCount\n const isParent = useMemo(() => {\n return allTasks ? isTaskParent(task.id, allTasks) : false;\n }, [allTasks, task.id]);\n\n const childCount = useMemo(() => {\n return allTasks ? getChildren(task.id, allTasks).length : 0;\n }, [allTasks, task.id]);\n\n // Calculate expiration status for overdue tasks\n const isExpired = useMemo(() => {\n if (!highlightExpiredTasks) return false;\n return isTaskExpired(task);\n }, [task.startDate, task.endDate, task.progress, highlightExpiredTasks]);\n\n // Calculate task bar position and dimensions\n const { left, width } = useMemo(\n () => calculateTaskBar(taskStartDate, taskEndDate, monthStart, dayWidth),\n [taskStartDate, taskEndDate, monthStart, dayWidth]\n );\n\n // Determine task bar color\n const barColor = isExpired\n ? 'var(--gantt-expired-color)'\n : (task.color || 'var(--gantt-task-bar-default-color)');\n\n // Color for the external task name label — parent tasks match their bar color\n const nameColor = isParent\n ? (task.color || 'var(--gantt-parent-bar-color, #333333)')\n : undefined; // regular tasks use CSS class color (#2563eb)\n\n // Calculate clamped and rounded progress width\n const progressWidth = useMemo(() => {\n if (task.progress === undefined || task.progress <= 0) return 0;\n return Math.min(100, Math.max(0, Math.round(task.progress)));\n }, [task.progress]);\n\n // Determine progress color based on completion status\n const progressColor = useMemo(() => {\n if (isExpired) {\n // Dark red for expired tasks\n return 'color-mix(in srgb, var(--gantt-expired-color) 40%, black)';\n }\n if (progressWidth === 100) {\n return task.accepted\n ? 'var(--gantt-progress-accepted, #22c55e)' // Green for accepted\n : 'var(--gantt-progress-completed, #fbbf24)'; // Yellow for completed (not accepted)\n }\n // Darker shade using color-mix() with task color or default\n const baseColor = task.color || 'var(--gantt-task-bar-default-color)';\n return `color-mix(in srgb, ${baseColor} 40%, black)`;\n }, [isExpired, progressWidth, task.accepted, task.color]);\n\n // At 100% progress, tint the bar itself instead of rendering a fill overlay.\n const barStyle = useMemo(() => {\n if (isParent) {\n if (progressWidth >= 100) {\n const c = 'color-mix(in srgb, var(--gantt-task-bar-default-color) 40%, black)';\n return { backgroundColor: c, '--gantt-parent-bar-color': c } as React.CSSProperties;\n }\n return {};\n }\n if (progressWidth >= 100) {\n return { backgroundColor: progressColor };\n }\n return { backgroundColor: barColor };\n }, [isParent, progressWidth, barColor, progressColor]);\n\n // Handle drag end - call onTasksChange with updated task\n const handleDragEnd = (result: { id: string; startDate: Date; endDate: Date; updatedDependencies?: Task['dependencies'] }) => {\n const updatedTask: Task = {\n ...task,\n startDate: result.startDate.toISOString(),\n endDate: result.endDate.toISOString(),\n ...(result.updatedDependencies !== undefined && { dependencies: result.updatedDependencies }),\n };\n onTasksChange?.([updatedTask]);\n };\n\n // Use drag hook for interactive drag/resize\n const {\n isDragging,\n dragMode,\n currentLeft,\n currentWidth,\n dragHandleProps,\n } = useTaskDrag({\n taskId: task.id,\n initialStartDate: taskStartDate,\n initialEndDate: taskEndDate,\n monthStart,\n dayWidth,\n onDragEnd: handleDragEnd,\n onDragStateChange,\n edgeZoneWidth: 20,\n allTasks,\n rowIndex,\n enableAutoSchedule,\n disableConstraints,\n locked: task.locked,\n onCascadeProgress,\n onCascade,\n });\n\n // Use override position (for cascade preview) with fallback to drag or static position\n const displayLeft = overridePosition?.left ?? (isDragging ? currentLeft : left);\n const displayWidth = overridePosition?.width ?? (isDragging ? currentWidth : width);\n\n // Format date labels for display - update in real-time during drag\n const currentStartDate = isDragging\n ? pixelsToDate(displayLeft, monthStart, dayWidth)\n : taskStartDate;\n const currentEndDate = isDragging\n ? pixelsToDate(displayLeft + displayWidth - dayWidth, monthStart, dayWidth)\n : taskEndDate;\n\n const startDateLabel = formatDateLabel(currentStartDate);\n const endDateLabel = formatDateLabel(currentEndDate);\n\n // Calculate duration in days\n const durationDays = Math.round(\n (currentEndDate.getTime() - currentStartDate.getTime()) / (1000 * 60 * 60 * 24)\n ) + 1;\n\n // Format child count label for parent tasks (Russian plural)\n const getChildCountLabel = (count: number): string => {\n if (count === 1) return '1 задача';\n // For 2, 3, 4 tasks use \"задачи\" (genitive singular)\n // For 5+ tasks use \"задач\" (genitive plural)\n const lastTwoDigits = count % 100;\n const lastDigit = count % 10;\n if (lastTwoDigits >= 11 && lastTwoDigits <= 14) return `${count} задач`;\n if (lastDigit === 1) return `${count} задача`;\n if (lastDigit >= 2 && lastDigit <= 4) return `${count} задачи`;\n return `${count} задач`;\n };\n\n // Determine if progress text fits inside the bar\n // Parent bars have overflow: visible (for bracket ears), so threshold must be stricter:\n // \"X задач 100%\" ≈ 60–70px text + 16px padding = ~110px\n // Regular: \"15 д 100%\" ≈ 76px, \"1 д 100%\" ≈ 62px\n const estimatedTextWidth = isParent ? 120 : (durationDays >= 10 ? 76 : 62);\n const showProgressInside = progressWidth > 0 && displayWidth > estimatedTextWidth;\n\n // Determine if duration fits inside the bar\n // For 1-day tasks: always show duration outside (too narrow)\n // Parent bars: child count label is longer — need more space\n const MIN_DURATION_WIDTH = isParent ? 80 : 50;\n const showDurationInside = durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;\n\n return (\n <div\n data-filter-match={isFilterMatch ? 'true' : 'false'}\n className={`gantt-tr-row ${isFilterMatch ? 'gantt-tr-row-filter-match' : ''}`}\n style={{ height: `${rowHeight}px` }}\n >\n {taskDivider === 'top' && <div className=\"gantt-tr-divider gantt-tr-divider-top\" />}\n <div className=\"gantt-tr-taskContainer\">\n <div\n data-taskbar\n className={`gantt-tr-taskBar ${isDragging ? 'gantt-tr-dragging' : ''} ${task.locked ? 'gantt-tr-locked' : ''} ${isParent ? 'gantt-tr-parentBar' : ''}`}\n style={{\n left: `${displayLeft}px`,\n width: `${displayWidth}px`,\n ...barStyle,\n height: isParent ? 'var(--gantt-parent-bar-height, 14px)' : 'var(--gantt-task-bar-height)',\n cursor: dragHandleProps.style.cursor,\n userSelect: dragHandleProps.style.userSelect,\n }}\n onMouseDown={dragHandleProps.onMouseDown}\n >\n {progressWidth > 0 && progressWidth < 100 && (\n <div\n className=\"gantt-tr-progressBar\"\n style={{\n width: `${progressWidth}%`,\n backgroundColor: progressColor,\n ...(isParent && {\n borderRadius: 'var(--gantt-parent-bar-radius, 8px) 0 0 0',\n }),\n }}\n />\n )}\n {!isParent && <div className=\"gantt-tr-resizeHandle gantt-tr-resizeHandleLeft\" />}\n {showDurationInside && (\n <span className=\"gantt-tr-taskDuration\">\n {isParent ? getChildCountLabel(childCount) : `${durationDays} д`}\n </span>\n )}\n {progressWidth > 0 && showProgressInside && (\n <span className=\"gantt-tr-progressText\">\n {progressWidth}%\n </span>\n )}\n {!isParent && <div className=\"gantt-tr-resizeHandle gantt-tr-resizeHandleRight\" />}\n </div>\n <div\n className={`gantt-tr-leftLabels ${task.locked ? 'gantt-tr-leftLabels-locked' : ''}`}\n style={{\n left: `${displayLeft}px`\n }}\n >\n <span className=\"gantt-tr-dateLabel gantt-tr-dateLabelLeft\">\n {startDateLabel}–{endDateLabel}\n </span>\n </div>\n {task.locked && (\n <svg\n className=\"gantt-tr-lockIcon\"\n style={{\n position: 'absolute',\n left: `${displayLeft - 16}px`,\n top: '50%',\n transform: 'translateY(-50%)',\n width: '12px',\n height: '12px',\n color: '#444',\n pointerEvents: 'none',\n }}\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n aria-label=\"Locked\"\n aria-hidden=\"false\"\n >\n <path d=\"M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM12 17c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z\" />\n </svg>\n )}\n <div\n className=\"gantt-tr-rightLabels\"\n style={{\n left: `${displayLeft + Math.max(displayWidth, 20) - Math.min(6, Math.max(displayWidth, 20) / 2) + 8}px`,\n }}\n >\n {!showDurationInside && (\n <span className=\"gantt-tr-externalDuration\">\n {isParent ? getChildCountLabel(childCount) : `${durationDays} д`}\n </span>\n )}\n {progressWidth > 0 && !showProgressInside && (\n <span className=\"gantt-tr-externalProgress\">\n {progressWidth}%\n </span>\n )}\n <span\n className=\"gantt-tr-externalTaskName\"\n style={nameColor ? { color: nameColor } : undefined}\n >\n {task.name}\n </span>\n </div>\n </div>\n {taskDivider === 'bottom' && <div className=\"gantt-tr-divider gantt-tr-divider-bottom\" />}\n </div>\n );\n },\n arePropsEqual\n);\n\nTaskRow.displayName = 'TaskRow';\n\nexport default TaskRow;\n","/**\n * Calculate day difference in UTC\n */\nconst getUTCDayDifference = (date1: Date, date2: Date): number => {\n const ms1 = Date.UTC(\n date1.getUTCFullYear(),\n date1.getUTCMonth(),\n date1.getUTCDate()\n );\n const ms2 = Date.UTC(\n date2.getUTCFullYear(),\n date2.getUTCMonth(),\n date2.getUTCDate()\n );\n return Math.round((ms1 - ms2) / (1000 * 60 * 60 * 24));\n};\n\n/**\n * Calculate task bar positioning and dimensions\n * @param taskStartDate - Start date of the task\n * @param taskEndDate - End date of the task\n * @param monthStart - Start of the month/visible range\n * @param dayWidth - Width of each day in pixels\n * @returns Object with left position and width in pixels\n */\nexport const calculateTaskBar = (\n taskStartDate: Date,\n taskEndDate: Date,\n monthStart: Date,\n dayWidth: number\n): { left: number; width: number } => {\n const startOffset = getUTCDayDifference(taskStartDate, monthStart);\n const duration = getUTCDayDifference(taskEndDate, taskStartDate);\n\n // Round to avoid sub-pixel rendering issues\n const left = Math.round(startOffset * dayWidth);\n const width = Math.round((duration + 1) * dayWidth); // +1 to include end date\n\n return { left, width };\n};\n\n/**\n * Convert pixel position to date (inverse of calculateTaskBar)\n * @param pixels - Position in pixels (left or width)\n * @param monthStart - Start of the month/visible range\n * @param dayWidth - Width of each day in pixels\n * @returns Date calculated from pixel position\n */\nexport const pixelsToDate = (pixels: number, monthStart: Date, dayWidth: number): Date => {\n const days = Math.round(pixels / dayWidth);\n return new Date(Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate() + days\n ));\n};\n\n/**\n * Calculate total width for month grid\n * @param daysInMonth - Number of days in the month\n * @param dayWidth - Width of each day in pixels\n * @returns Total grid width in pixels\n */\nexport const calculateGridWidth = (daysInMonth: number, dayWidth: number): number => {\n return Math.round(daysInMonth * dayWidth);\n};\n\n/**\n * Detect which edge zone the cursor is in on a task bar\n * @param clientX - Mouse X coordinate relative to viewport\n * @param taskBarElement - The task bar DOM element\n * @param edgeZoneWidth - Width of edge zones in pixels (default: 12px)\n * @returns 'left' if in left edge, 'right' if in right edge, 'move' if in middle\n */\nexport const detectEdgeZone = (\n clientX: number,\n taskBarElement: HTMLElement,\n edgeZoneWidth: number = 12\n): 'left' | 'right' | 'move' => {\n const rect = taskBarElement.getBoundingClientRect();\n const relativeX = Math.round(clientX - rect.left);\n const width = Math.round(rect.width);\n\n // When zones overlap (width <= 2 * edgeZoneWidth), prefer the closer edge\n if (width <= 2 * edgeZoneWidth) {\n // Cursor is in overlapping edge zone, return closer edge\n const distanceToLeft = relativeX;\n const distanceToRight = width - relativeX;\n return distanceToLeft <= distanceToRight ? 'left' : 'right';\n }\n\n // Check left edge zone\n if (relativeX >= 0 && relativeX <= edgeZoneWidth) {\n return 'left';\n }\n\n // Check right edge zone\n if (relativeX >= width - edgeZoneWidth && relativeX <= width) {\n return 'right';\n }\n\n // Middle area - move mode\n return 'move';\n};\n\n/**\n * Get appropriate cursor style for drag position\n * @param position - The drag position (left edge, right edge, or move)\n * @returns CSS cursor string for the position\n */\nexport const getCursorForPosition = (position: 'left' | 'right' | 'move'): string => {\n switch (position) {\n case 'left':\n case 'right':\n return 'ew-resize';\n case 'move':\n return 'grab';\n default:\n return 'default';\n }\n};\n\n/**\n * Calculate grid line positions for a date range\n * @param dateRange - Array of Date objects representing the visible range\n * @param dayWidth - Width of each day column in pixels\n * @returns Array of grid line objects with x position and flags\n */\nexport const calculateGridLines = (\n dateRange: Date[],\n dayWidth: number\n): Array<{ x: number; isMonthStart: boolean; isWeekStart: boolean }> => {\n const lines: Array<{ x: number; isMonthStart: boolean; isWeekStart: boolean }> = [];\n\n for (let i = 0; i < dateRange.length; i++) {\n const date = dateRange[i];\n const x = Math.round(i * dayWidth);\n const isMonthStart = i === 0 ? false : date.getUTCDate() === 1;\n const isWeekStart = date.getUTCDay() === 1; // Monday\n\n lines.push({ x, isMonthStart, isWeekStart });\n }\n\n // Add final line at the end of the range\n if (dateRange.length > 0) {\n lines.push({\n x: Math.round(dateRange.length * dayWidth),\n isMonthStart: false,\n isWeekStart: false\n });\n }\n\n return lines;\n};\n\n/**\n * Calculate weekend background blocks for a date range\n * @param dateRange - Array of Date objects representing the visible range\n * @param dayWidth - Width of each day column in pixels\n * @param isCustomWeekend - Optional predicate for custom weekend logic (e.g., holidays, shift patterns)\n * @returns Array of weekend block objects with left position and width\n *\n * Example:\n * // Default behavior (Saturday/Sunday)\n * calculateWeekendBlocks(dateRange, dayWidth)\n *\n * // Custom weekends (holidays, shifted workdays)\n * const isCustomWeekend = createIsWeekendPredicate({\n * weekends: [new Date(Date.UTC(2026, 2, 8))], // March 8 holiday\n * workdays: [new Date(Date.UTC(2026, 2, 15))] // March 15 workday\n * });\n * calculateWeekendBlocks(dateRange, dayWidth, isCustomWeekend)\n */\nexport const calculateWeekendBlocks = (\n dateRange: Date[],\n dayWidth: number,\n isCustomWeekend?: (date: Date) => boolean\n): Array<{ left: number; width: number }> => {\n const blocks: Array<{ left: number; width: number }> = [];\n let inWeekend = false;\n let weekendStartIndex = -1;\n\n for (let i = 0; i < dateRange.length; i++) {\n const date = dateRange[i];\n // Use custom predicate if provided, otherwise default Saturday/Sunday\n const isWeekend = isCustomWeekend\n ? isCustomWeekend(date)\n : date.getUTCDay() === 0 || date.getUTCDay() === 6;\n\n if (isWeekend && !inWeekend) {\n // Start of a weekend block\n inWeekend = true;\n weekendStartIndex = i;\n } else if (!isWeekend && inWeekend) {\n // End of a weekend block\n inWeekend = false;\n const left = Math.round(weekendStartIndex * dayWidth);\n const width = Math.round((i - weekendStartIndex) * dayWidth);\n blocks.push({ left, width });\n }\n }\n\n // Handle case where range ends on a weekend\n if (inWeekend && weekendStartIndex >= 0) {\n const left = Math.round(weekendStartIndex * dayWidth);\n const width = Math.round((dateRange.length - weekendStartIndex) * dayWidth);\n blocks.push({ left, width });\n }\n\n return blocks;\n};\n\n/**\n * Calculate SVG cubic Bezier curve path for dependency lines\n * @param from - Start point {x, y} (right edge of predecessor)\n * @param to - End point {x, y} (left edge of successor)\n * @returns SVG path string for cubic Bezier curve\n */\nexport const calculateBezierPath = (\n from: { x: number; y: number },\n to: { x: number; y: number }\n): string => {\n // Control points create smooth vertical curve\n // Offset is proportional to vertical distance for natural-looking curves\n const verticalDistance = Math.abs(to.y - from.y);\n const cpOffset = Math.max(verticalDistance * 0.5, 20); // Minimum 20px for same-row connections\n\n // For same-row connections, use arc above the task bars\n if (from.y === to.y) {\n const arcHeight = 20;\n const midX = (from.x + to.x) / 2;\n return `M ${from.x} ${from.y} Q ${midX} ${from.y - arcHeight} ${to.x} ${to.y}`;\n }\n\n // Standard cubic Bezier for multi-row connections\n const cp1x = from.x;\n const cp1y = from.y + (to.y > from.y ? cpOffset : -cpOffset);\n const cp2x = to.x;\n const cp2y = to.y - (to.y > from.y ? cpOffset : -cpOffset);\n\n return `M ${Math.round(from.x)} ${Math.round(from.y)} C ${Math.round(cp1x)} ${Math.round(cp1y)}, ${Math.round(cp2x)} ${Math.round(cp2y)}, ${Math.round(to.x)} ${Math.round(to.y)}`;\n};\n\n/**\n * Calculate SVG path for dependency lines based on link type connection semantics.\n *\n * Connection points per link type:\n * - FS: predecessor RIGHT → successor LEFT (arrow points right, enters left edge)\n * - SS: predecessor LEFT → successor LEFT (arrow points right, enters left edge)\n * - FF: predecessor RIGHT → successor RIGHT (arrow points left, enters right edge)\n * - SF: predecessor LEFT → successor RIGHT (arrow points left, enters right edge)\n *\n * @param from - Start point {x, y}\n * @param to - End point {x, y}\n * @param arrivesFromRight - true for FF and SF (arrow enters right edge of successor)\n */\nexport const calculateDependencyPath = (\n from: { x: number; y: number },\n to: { x: number; y: number },\n arrivesFromRight: boolean\n): string => {\n const fx = Math.round(from.x);\n const fy = Math.round(from.y);\n const tx = Math.round(to.x);\n const ty = Math.round(to.y);\n\n // Same row: straight horizontal line\n if (fy === ty) {\n return `M ${fx} ${fy} H ${tx}`;\n }\n\n const C = 2; // chamfer size\n const goingDown = ty > fy;\n const dirY = goingDown ? 1 : -1;\n\n if (arrivesFromRight) {\n // Arrow arrives at the RIGHT edge of successor (FF, SF).\n // Same chamfer formula as the FS/SS branch: stop C short of tx in the direction of travel,\n // then diagonal to tx, then vertical. The endpoints differ (right edge vs left edge),\n // but the path shape — natural inside-corner chamfer — is identical.\n const goingRight = tx >= fx;\n const dirX = goingRight ? 1 : -1;\n\n if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {\n return [\n `M ${fx} ${fy}`,\n `H ${tx - dirX * C}`,\n `L ${tx} ${fy + dirY * C}`,\n `V ${ty}`,\n ].join(' ');\n }\n return `M ${fx} ${fy} H ${tx} V ${ty}`;\n } else {\n // Arrow arrives at the LEFT edge of successor (FS, SS) — same as existing calculateOrthogonalPath\n const goingRight = tx >= fx;\n const dirX = goingRight ? 1 : -1;\n\n if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {\n return [\n `M ${fx} ${fy}`,\n `H ${tx - dirX * C}`,\n `L ${tx} ${fy + dirY * C}`,\n `V ${ty}`,\n ].join(' ');\n }\n return `M ${fx} ${fy} H ${tx} V ${ty}`;\n }\n};\n\n/**\n * Calculate grid line positions for week-view mode.\n * Lines appear at every 7-day boundary (each week column edge).\n * Month boundaries are always rendered at the exact day position (day 1 of a new month),\n * even when the boundary falls in the middle of a week column.\n * No day-level lines; no weekend blocks.\n *\n * @param dateRange - Array of Date objects (from getMultiMonthDays, day-based)\n * @param dayWidth - Width of each day in pixels\n * @returns Array of grid line objects sorted by x position\n */\nexport const calculateWeekGridLines = (\n dateRange: Date[],\n dayWidth: number\n): Array<{ x: number; isMonthStart: boolean }> => {\n // Import getWeekBlocks locally to avoid circular dependency\n const { getWeekBlocks } = require('./dateUtils');\n const blocks = getWeekBlocks(dateRange);\n\n const lines: Array<{ x: number; isMonthStart: boolean }> = [];\n let currentDayIndex = 0;\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n currentDayIndex += block.days;\n\n // Check if this block boundary is also a month boundary\n const blockEndMonth = dateRange[currentDayIndex - 1];\n const nextBlockMonth = currentDayIndex < dateRange.length\n ? dateRange[currentDayIndex]\n : null;\n\n const isMonthBoundary = nextBlockMonth &&\n blockEndMonth.getUTCMonth() !== nextBlockMonth.getUTCMonth();\n\n lines.push({\n x: Math.round(currentDayIndex * dayWidth),\n isMonthStart: isMonthBoundary || false,\n });\n }\n\n // Remove the last line if it's at the right edge (duplicates grid border)\n if (lines.length > 0 && lines[lines.length - 1].x === Math.round(dateRange.length * dayWidth)) {\n lines.pop();\n }\n\n return lines;\n};\n\n/**\n * Calculate grid line positions for month-view mode.\n * Thin line (isMonthStart=false) at each month boundary (1st of every month).\n * Thick line (isMonthStart=true) at each year boundary (1st of January).\n * No day-level or week-level lines.\n *\n * @param dateRange - Array of Date objects (from getMultiMonthDays)\n * @param dayWidth - Width of each day in pixels\n * @returns Array of grid line objects sorted by x position\n */\nexport const calculateMonthGridLines = (\n dateRange: Date[],\n dayWidth: number\n): Array<{ x: number; isMonthStart: boolean }> => {\n const lines: Array<{ x: number; isMonthStart: boolean }> = [];\n\n for (let i = 1; i < dateRange.length; i++) {\n const date = dateRange[i];\n // Линия только на 1-м числе месяца\n if (date.getUTCDate() === 1) {\n const x = Math.round(i * dayWidth);\n // Толстая линия на 1 января (граница года)\n const isYearBoundary = date.getUTCMonth() === 0;\n lines.push({ x, isMonthStart: isYearBoundary });\n }\n }\n\n return lines;\n};\n\n/**\n * Calculate SVG Г-shaped (L-shaped) path for FS dependency lines.\n * Goes vertically from the right edge of the predecessor bar, then horizontally\n * to the left edge of the successor bar. Supports negative lag (overlap).\n * @param from - Start point {x, y} (right edge of predecessor, vertical center)\n * @param to - End point {x, y} (left edge of successor, vertical center)\n * @returns SVG path string\n */\nexport const calculateOrthogonalPath = (\n from: { x: number; y: number },\n to: { x: number; y: number }\n): string => {\n const fx = Math.round(from.x);\n const fy = Math.round(from.y);\n const tx = Math.round(to.x);\n const ty = Math.round(to.y);\n\n // Same row: straight horizontal line\n if (fy === ty) {\n return `M ${fx} ${fy} H ${tx}`;\n }\n\n const C = 2; // chamfer size\n const goingDown = ty > fy;\n const goingRight = tx >= fx;\n const dirY = goingDown ? 1 : -1;\n const dirX = goingRight ? 1 : -1;\n\n // Shape: horizontal exit → chamfer → vertical arrival (arrow points down/up)\n if (Math.abs(ty - fy) >= C && Math.abs(tx - fx) >= C) {\n return [\n `M ${fx} ${fy}`,\n `H ${tx - dirX * C}`,\n `L ${tx} ${fy + dirY * C}`,\n `V ${ty}`,\n ].join(' ');\n }\n\n // Sharp corner fallback (very short segments)\n return `M ${fx} ${fy} H ${tx} V ${ty}`;\n};\n","import type { Task } from '../types';\nimport { parseUTCDate } from './dateUtils';\n\n/**\n * Checks whether a task is behind the expected progress for the current date.\n * Uses the same progress-based rule as expired task highlighting in TaskRow.\n */\nexport const isTaskExpired = (\n task: Task | undefined,\n referenceDate: Date = new Date(),\n): boolean => {\n if (!task) return false;\n\n const actualProgress = task.progress ?? 0;\n if (actualProgress >= 100) return false;\n\n // Align the day boundary to local time, then compare using UTC-safe task dates.\n const today = new Date(Date.UTC(\n referenceDate.getFullYear(),\n referenceDate.getMonth(),\n referenceDate.getDate(),\n ));\n\n const taskStart = parseUTCDate(task.startDate);\n const taskEnd = parseUTCDate(task.endDate);\n\n const msPerDay = 1000 * 60 * 60 * 24;\n const duration = taskEnd.getTime() - taskStart.getTime() + msPerDay;\n const elapsedFromToday = today.getTime() - taskStart.getTime();\n const elapsed = Math.min(Math.max(0, elapsedFromToday), duration);\n const expectedProgress = (elapsed / duration) * 100;\n\n return actualProgress < expectedProgress;\n};\n","'use client';\n\nimport { useEffect, useRef, useState, useCallback } from 'react';\nimport { detectEdgeZone } from '../utils/geometry';\nimport type { Task, TaskDependency, LinkType } from '../types';\nimport { calculateSuccessorDate, getTransitiveCascadeChain, recalculateIncomingLags, getChildren, isTaskParent, universalCascade } from '../utils/dependencyUtils';\n\n/**\n * Get transitive closure of successors for cascading.\n *\n * For proper cascading in mixed link type chains (e.g., A--FS-->B--SS-->C),\n * we need to include cascaded tasks' successors regardless of link type.\n *\n * The chain is:\n * 1. Direct successors of the dragged task, filtered by firstLevelLinkTypes\n * 2. ALL successors (any type) of those tasks, recursively\n *\n * @param draggedTaskId - ID of the task being dragged\n * @param allTasks - All tasks in the chart\n * @param firstLevelLinkTypes - Link types to use for direct successors\n * @returns Array of tasks in the cascade chain (transitive closure)\n */\n/**\n * Global drag manager that persists across HMR\n *\n * This singleton manages active drag operations at the module level,\n * ensuring that drag state survives React Fast Refresh (HMR).\n *\n * The key insight: When HMR occurs during a drag operation:\n * 1. The component unmounts and its useEffect cleanup removes window listeners\n * 2. The component remounts with fresh refs (isDraggingRef = false)\n * 3. But the user is still holding the mouse button!\n * 4. Without module-level state, the drag operation is orphaned\n *\n * Solution: Store active drag state in module-level singleton and\n * use a global cleanup effect to always handle mouseup/mousemove.\n */\ninterface ActiveDragState {\n taskId: string;\n mode: 'move' | 'resize-left' | 'resize-right';\n startX: number;\n initialLeft: number;\n initialWidth: number;\n currentLeft: number;\n currentWidth: number;\n dayWidth: number;\n monthStart: Date;\n onProgress: (left: number, width: number) => void;\n onComplete: (finalLeft: number, finalWidth: number) => void;\n onCancel: () => void;\n allTasks: Task[];\n disableConstraints?: boolean;\n cascadeChain: Task[]; // FS+SS+FF+SF successors of dragged task (Phase 10: added SF)\n cascadeChainFS: Task[]; // FS-only successors (part of resize-right cascade with FF)\n cascadeChainStart: Task[]; // SS+SF successors (resize-left cascade) - Phase 10: renamed from cascadeChainSS\n cascadeChainEnd: Task[]; // FS+FF successors (resize-right cascade) - Phase 9\n hierarchyChain: Task[]; // Phase 19: children of parent task (for cascade drag)\n onCascadeProgress?: (overrides: Map<string, { left: number; width: number }>) => void;\n}\n\nlet globalActiveDrag: ActiveDragState | null = null;\nlet globalRafId: number | null = null;\n\n/**\n * Complete the active drag operation\n */\nfunction completeDrag() {\n if (globalRafId !== null) {\n cancelAnimationFrame(globalRafId);\n globalRafId = null;\n }\n\n if (globalActiveDrag) {\n // Clear cascade overrides before completing (avoids stale preview positions)\n globalActiveDrag.onCascadeProgress?.(new Map());\n const { onComplete, currentLeft, currentWidth } = globalActiveDrag;\n globalActiveDrag = null;\n onComplete(currentLeft, currentWidth);\n }\n}\n\n/**\n * Cancel the active drag operation\n */\nfunction cancelDrag() {\n if (globalRafId !== null) {\n cancelAnimationFrame(globalRafId);\n globalRafId = null;\n }\n\n if (globalActiveDrag) {\n const { onCancel } = globalActiveDrag;\n globalActiveDrag = null;\n onCancel();\n }\n}\n\n/**\n * Snap pixel value to grid (day boundaries)\n */\nfunction snapToGrid(pixels: number, dayWidth: number): number {\n return Math.round(pixels / dayWidth) * dayWidth;\n}\n\n/**\n * Check if a task move would violate dependency constraints\n * Only blocks move operations, not resize (per requirements)\n */\nfunction canMoveTask(\n task: Task,\n newStartDate: Date,\n newEndDate: Date,\n allTasks: Task[]\n): { allowed: boolean; reason?: string } {\n if (!task.dependencies || task.dependencies.length === 0) {\n return { allowed: true };\n }\n\n // For each predecessor, check if the new position respects the constraint\n for (const dep of task.dependencies) {\n const predecessor = allTasks.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n\n const predecessorStart = new Date(predecessor.startDate);\n const predecessorEnd = new Date(predecessor.endDate);\n\n // Calculate expected date based on link type (lag ignored, always 0)\n const expectedDate = calculateSuccessorDate(\n predecessorStart,\n predecessorEnd,\n dep.type,\n 0 // lag not used in calculations\n );\n\n // Check constraint based on link type\n const targetIsStart = dep.type.endsWith('S');\n const targetDate = targetIsStart ? newStartDate : newEndDate;\n\n // Allow move if target date is on or after expected date\n // (give 1-day tolerance for rounding)\n const dayDiff = (targetDate.getTime() - expectedDate.getTime()) / (24 * 60 * 60 * 1000);\n\n if (dayDiff < -1) {\n return {\n allowed: false,\n reason: `Would violate ${dep.type} dependency from \"${predecessor.name}\"`\n };\n }\n }\n\n return { allowed: true };\n}\n\n/**\n * Recalculate lag values for incoming dependencies after drag completion.\n *\n * Lag formulas:\n * - FS: lag = startB - endA (can be negative)\n * - SS: lag = startB - startA (floor at 0)\n * - FF: lag = endB - endA (can be negative)\n * - SF: lag = endB - startA (ceiling at 0)\n */\n/**\n * Global mouse move handler - attached once and persists across HMR\n */\nfunction handleGlobalMouseMove(e: MouseEvent) {\n if (!globalActiveDrag || globalRafId !== null) {\n return;\n }\n\n globalRafId = requestAnimationFrame(() => {\n if (!globalActiveDrag) {\n globalRafId = null;\n return;\n }\n\n const activeDrag = globalActiveDrag;\n\n const { startX, initialLeft, initialWidth, mode, dayWidth, onProgress, allTasks } = activeDrag;\n const deltaX = e.clientX - startX;\n\n let newLeft = initialLeft;\n let newWidth = initialWidth;\n\n switch (mode) {\n case 'move':\n newLeft = snapToGrid(initialLeft + deltaX, dayWidth);\n break;\n case 'resize-left':\n const snappedLeft = snapToGrid(initialLeft + deltaX, dayWidth);\n newLeft = snappedLeft;\n const rightEdge = initialLeft + initialWidth;\n newWidth = Math.max(dayWidth, rightEdge - snappedLeft);\n break;\n case 'resize-right':\n const snappedWidth = snapToGrid(initialWidth + deltaX, dayWidth);\n newWidth = Math.max(dayWidth, snappedWidth);\n break;\n }\n\n // Hard mode: check left-move boundary against predecessor.startDate (Phase 7)\n // Child can move left until its startDate would go before predecessor.startDate\n // Also applies to resize-left: the left edge cannot cross the predecessor's start date\n if ((mode === 'move' || mode === 'resize-left') && allTasks.length > 0 && !activeDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === activeDrag.taskId);\n if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {\n let minAllowedLeft = -Infinity; // in pixels from monthStart; -Infinity means no floor unless a real FS/SS predecessor sets one\n for (const dep of currentTask.dependencies) {\n if (dep.type !== 'FS' && dep.type !== 'SS') continue; // Phase 8: FS and SS\n const predecessor = activeDrag.allTasks.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n // Boundary: child.startDate >= predecessor.startDate (allows negative lag)\n const predStart = new Date(predecessor.startDate as string);\n const predStartOffset = Math.round(\n (Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) -\n Date.UTC(\n activeDrag.monthStart.getUTCFullYear(),\n activeDrag.monthStart.getUTCMonth(),\n activeDrag.monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * activeDrag.dayWidth);\n minAllowedLeft = Math.max(minAllowedLeft, predStartLeft);\n }\n // Clamp: don't let task go left of boundary\n newLeft = Math.max(minAllowedLeft, newLeft);\n }\n // For resize-left, after clamping newLeft the right edge is fixed so newWidth must be recomputed\n if (mode === 'resize-left') {\n const rightEdge = activeDrag.initialLeft + activeDrag.initialWidth;\n newWidth = Math.max(activeDrag.dayWidth, rightEdge - newLeft);\n }\n }\n\n // Phase 10: SF constraint: endB <= startA (lag ceiling at 0)\n // Applies when B is moved right or resized-right\n if ((mode === 'move' || mode === 'resize-right') && allTasks.length > 0 && !activeDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === activeDrag.taskId);\n if (currentTask && currentTask.dependencies && currentTask.dependencies.length > 0) {\n for (const dep of currentTask.dependencies) {\n if (dep.type !== 'SF') continue;\n const predecessor = activeDrag.allTasks.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n const predStart = new Date(predecessor.startDate as string);\n const predStartOffset = Math.round(\n (Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) -\n Date.UTC(activeDrag.monthStart.getUTCFullYear(), activeDrag.monthStart.getUTCMonth(), activeDrag.monthStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * activeDrag.dayWidth);\n\n // SF lag=0 boundary: B's visual end = day before A's start (adjacent = lag 0)\n // B.right (exclusive pixel) = predStartLeft at lag=0\n const sfBoundaryRight = predStartLeft;\n if (mode === 'move') {\n // Move mode: when B would hit startA constraint, stop movement entirely\n const proposedEndRight = newLeft + activeDrag.initialWidth;\n if (proposedEndRight > sfBoundaryRight) {\n newLeft = Math.max(activeDrag.initialLeft, sfBoundaryRight - activeDrag.initialWidth);\n }\n } else {\n // Resize-right mode: clamp width so endB = startA (lag=0)\n const currentEndRight = newLeft + newWidth;\n if (currentEndRight > sfBoundaryRight) {\n newWidth = Math.max(activeDrag.dayWidth, sfBoundaryRight - newLeft);\n }\n }\n }\n }\n }\n\n const draggedTask = allTasks.find(t => t.id === activeDrag.taskId);\n\n // ── Universal preview cascade ──────────────────────────────────────────\n // Same algorithm as handleComplete — converts pixels→dates, runs\n // universalCascade, converts dates→pixels for overrides.\n\n // Universal preview: convert pixels → dates → universalCascade → pixels\n if (!activeDrag.disableConstraints && activeDrag.onCascadeProgress) {\n const { dayWidth, monthStart: mStart, taskId: dragId } = activeDrag;\n const previewStartDay = Math.round(newLeft / dayWidth);\n const previewEndDay = previewStartDay + Math.round(newWidth / dayWidth) - 1;\n const previewStartDate = new Date(Date.UTC(\n mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate() + previewStartDay\n ));\n const previewEndDate = new Date(Date.UTC(\n mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate() + previewEndDay\n ));\n\n const movedTaskData = draggedTask ?? { id: dragId, name: '', startDate: '', endDate: '' };\n const cascadeResult = universalCascade(\n { ...movedTaskData, startDate: previewStartDate.toISOString(), endDate: previewEndDate.toISOString() },\n previewStartDate,\n previewEndDate,\n allTasks\n );\n\n // Convert cascaded tasks → pixel overrides\n const overrides = new Map<string, { left: number; width: number }>();\n // Always include the dragged task itself\n overrides.set(dragId, { left: newLeft, width: newWidth });\n\n for (const task of cascadeResult) {\n if (task.id === dragId) continue;\n const taskStart = new Date(task.startDate as string);\n const taskEnd = new Date(task.endDate as string);\n const startOff = Math.round(\n (Date.UTC(taskStart.getUTCFullYear(), taskStart.getUTCMonth(), taskStart.getUTCDate()) -\n Date.UTC(mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n const endOff = Math.round(\n (Date.UTC(taskEnd.getUTCFullYear(), taskEnd.getUTCMonth(), taskEnd.getUTCDate()) -\n Date.UTC(mStart.getUTCFullYear(), mStart.getUTCMonth(), mStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n overrides.set(task.id, {\n left: Math.round(startOff * dayWidth),\n width: Math.round((endOff - startOff + 1) * dayWidth),\n });\n }\n\n activeDrag.onCascadeProgress(overrides);\n }\n\n // Update current values in global state for completion\n activeDrag.currentLeft = newLeft;\n activeDrag.currentWidth = newWidth;\n\n onProgress(newLeft, newWidth);\n globalRafId = null;\n });\n}\n\n/**\n * Global mouse up handler - attached once and persists across HMR\n */\nfunction handleGlobalMouseUp() {\n if (globalActiveDrag) {\n completeDrag();\n }\n}\n\n/**\n * Track whether global listeners are attached\n */\nlet globalListenersAttached = false;\n\n/**\n * Ensure global listeners are attached (idempotent)\n */\nfunction ensureGlobalListeners() {\n if (!globalListenersAttached) {\n window.addEventListener('mousemove', handleGlobalMouseMove);\n window.addEventListener('mouseup', handleGlobalMouseUp);\n globalListenersAttached = true;\n }\n}\n\n/**\n * Cleanup global listeners - called when no components are using drag\n * Note: In practice with HMR, we keep these attached for safety\n */\nfunction cleanupGlobalListeners() {\n // We keep global listeners attached to handle orphaned drags after HMR\n // They will be cleaned up when the page is refreshed\n}\n\n/**\n * Options for useTaskDrag hook\n */\nexport interface UseTaskDragOptions {\n /** Unique identifier for the task */\n taskId: string;\n /** Initial start date of the task */\n initialStartDate: Date;\n /** Initial end date of the task */\n initialEndDate: Date;\n /** Start of the visible range (e.g., month start) */\n monthStart: Date;\n /** Width of each day in pixels */\n dayWidth: number;\n /** Callback when drag operation completes */\n onDragEnd?: (result: { id: string; startDate: Date; endDate: Date; updatedDependencies?: Task['dependencies'] }) => void;\n /** Callback for drag state changes (for parent components to render guide lines) */\n onDragStateChange?: (state: {\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n }) => void;\n /** Width of edge zones for resize detection (default: 12px) */\n edgeZoneWidth?: number;\n /** Array of all tasks for dependency validation */\n allTasks?: Task[];\n /** Row index of this task (for task lookup) */\n rowIndex?: number;\n /** Enable automatic scheduling of dependent tasks */\n enableAutoSchedule?: boolean;\n /** When true, dependency constraint checking is skipped during drag (default: false) */\n disableConstraints?: boolean;\n /** Callback for real-time cascade preview — called each RAF with non-dragged chain member positions */\n onCascadeProgress?: (overrides: Map<string, { left: number; width: number }>) => void;\n /** Callback when cascade completes — receives all shifted tasks including dragged task */\n onCascade?: (tasks: Task[]) => void;\n /** When true, all drag and resize interactions are disabled for this task */\n locked?: boolean;\n}\n\n/**\n * Return value from useTaskDrag hook\n */\nexport interface UseTaskDragReturn {\n /** Whether a drag operation is in progress */\n isDragging: boolean;\n /** Current drag mode (null when not dragging) */\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n /** Current left position in pixels (updated during drag) */\n currentLeft: number;\n /** Current width in pixels (updated during drag) */\n currentWidth: number;\n /** Props to spread on the drag handle element */\n dragHandleProps: {\n onMouseDown: (e: React.MouseEvent) => void;\n style: React.CSSProperties;\n };\n}\n\n/**\n * Custom hook for managing task drag interactions\n *\n * HMR-SAFE: Uses module-level singleton to ensure drag state survives\n * React Fast Refresh. Window event listeners are attached once at module\n * level rather than per component instance.\n */\nexport const useTaskDrag = (options: UseTaskDragOptions): UseTaskDragReturn => {\n const {\n taskId,\n initialStartDate,\n initialEndDate,\n monthStart,\n dayWidth,\n onDragEnd,\n onDragStateChange,\n edgeZoneWidth = 12,\n allTasks = [],\n rowIndex,\n enableAutoSchedule = false,\n disableConstraints = false,\n onCascadeProgress,\n onCascade,\n } = options;\n\n // Track if this hook instance owns the current global drag\n const isOwnerRef = useRef<boolean>(false);\n const locked = options.locked ?? false;\n\n // Display state (triggers re-renders only when needed)\n const [isDragging, setIsDragging] = useState<boolean>(false);\n const [dragMode, setDragMode] = useState<'move' | 'resize-left' | 'resize-right' | null>(null);\n const [currentLeft, setCurrentLeft] = useState<number>(0);\n const [currentWidth, setCurrentWidth] = useState<number>(0);\n\n /**\n * Calculate initial pixel position from dates\n */\n const getInitialPosition = useCallback((): { left: number; width: number } => {\n const getUTCDayDifference = (date1: Date, date2: Date): number => {\n const ms1 = Date.UTC(\n date1.getUTCFullYear(),\n date1.getUTCMonth(),\n date1.getUTCDate()\n );\n const ms2 = Date.UTC(\n date2.getUTCFullYear(),\n date2.getUTCMonth(),\n date2.getUTCDate()\n );\n return Math.round((ms1 - ms2) / (1000 * 60 * 60 * 24));\n };\n\n const startOffset = getUTCDayDifference(initialStartDate, monthStart);\n const duration = getUTCDayDifference(initialEndDate, initialStartDate);\n\n const left = Math.round(startOffset * dayWidth);\n const width = Math.round((duration + 1) * dayWidth); // +1 to include end date\n\n return { left, width };\n }, [initialStartDate, initialEndDate, monthStart, dayWidth]);\n\n /**\n * Initialize position when dates or dayWidth changes.\n * Skipped when this instance owns an active drag to avoid overriding drag state.\n */\n useEffect(() => {\n if (isOwnerRef.current && globalActiveDrag) return;\n const { left, width } = getInitialPosition();\n setCurrentLeft(left);\n setCurrentWidth(width);\n }, [getInitialPosition]);\n\n /**\n * When monthStart changes during an active drag (e.g. a month is prepended),\n * the pixel coordinate origin shifts. Adjust globalActiveDrag so that\n * subsequent move calculations stay in the new coordinate space.\n */\n useEffect(() => {\n if (!isOwnerRef.current || !globalActiveDrag) return;\n const oldMonthStart = globalActiveDrag.monthStart;\n if (oldMonthStart === monthStart) return;\n const daysShift = Math.round(\n (Date.UTC(oldMonthStart.getUTCFullYear(), oldMonthStart.getUTCMonth(), oldMonthStart.getUTCDate()) -\n Date.UTC(monthStart.getUTCFullYear(), monthStart.getUTCMonth(), monthStart.getUTCDate())) /\n (1000 * 60 * 60 * 24)\n );\n const pixelShift = daysShift * dayWidth;\n globalActiveDrag.initialLeft += pixelShift;\n globalActiveDrag.currentLeft += pixelShift;\n globalActiveDrag.monthStart = monthStart;\n }, [monthStart, dayWidth]);\n\n /**\n * Handle drag progress callback from global manager\n */\n const handleProgress = useCallback((left: number, width: number) => {\n setCurrentLeft(left);\n setCurrentWidth(width);\n\n if (onDragStateChange && isOwnerRef.current) {\n const mode = globalActiveDrag?.mode || null;\n onDragStateChange({\n isDragging: true,\n dragMode: mode,\n left,\n width,\n });\n }\n }, [onDragStateChange]);\n\n /**\n * Handle drag completion from global manager\n */\n const handleComplete = useCallback((finalLeft: number, finalWidth: number) => {\n const wasOwner = isOwnerRef.current;\n isOwnerRef.current = false;\n\n // Calculate new dates from final pixel values\n const dayOffset = Math.round(finalLeft / dayWidth);\n const durationDays = Math.round(finalWidth / dayWidth) - 1; // -1 because width includes end date\n\n const newStartDate = new Date(Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate() + dayOffset\n ));\n\n const newEndDate = new Date(Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate() + dayOffset + durationDays\n ));\n\n // Reset local state\n setIsDragging(false);\n setDragMode(null);\n\n // Notify parent of drag end\n if (onDragStateChange) {\n onDragStateChange({\n isDragging: false,\n dragMode: null,\n left: finalLeft,\n width: finalWidth,\n });\n }\n\n if (wasOwner) {\n if (!disableConstraints && onCascade && allTasks.length > 0) {\n // Hard mode with onCascade: use universalCascade for all cases\n // (parent drag, child drag, root task drag — all handled uniformly)\n const draggedTaskData = allTasks.find(t => t.id === taskId);\n\n const movedTask: Task = {\n ...(draggedTaskData ?? { id: taskId, name: '', startDate: '', endDate: '' }),\n startDate: newStartDate.toISOString(),\n endDate: newEndDate.toISOString(),\n ...(draggedTaskData?.dependencies && {\n dependencies: recalculateIncomingLags(draggedTaskData, newStartDate, newEndDate, allTasks),\n }),\n };\n\n const cascadeResult = universalCascade(movedTask, newStartDate, newEndDate, allTasks);\n\n if (cascadeResult.length > 0) {\n onCascade([movedTask, ...cascadeResult]);\n return; // Don't call onDragEnd — cascade covers the dragged task too\n }\n\n // No dependent tasks to cascade — still call onCascade with just the moved task\n // so the state update is consistent\n onCascade([movedTask]);\n return;\n }\n\n // Soft mode OR hard mode with no FS successors: call onDragEnd\n // Always recalculate lag so hard-mode drags (chain.length===0) also persist the new lag\n if (allTasks.length > 0 && onDragEnd) {\n const currentTaskData = allTasks.find(t => t.id === taskId);\n const updatedDependencies = currentTaskData?.dependencies\n ? recalculateIncomingLags(currentTaskData, newStartDate, newEndDate, allTasks)\n : undefined;\n onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate, updatedDependencies });\n } else if (onDragEnd) {\n onDragEnd({ id: taskId, startDate: newStartDate, endDate: newEndDate });\n }\n }\n }, [dayWidth, monthStart, onDragEnd, onDragStateChange, taskId, disableConstraints, onCascade, allTasks, initialStartDate, initialEndDate]);\n\n /**\n * Handle drag cancellation (e.g., if HMR orphaned the drag)\n */\n const handleCancel = useCallback(() => {\n isOwnerRef.current = false;\n setIsDragging(false);\n setDragMode(null);\n\n if (onDragStateChange) {\n onDragStateChange({\n isDragging: false,\n dragMode: null,\n left: currentLeft,\n width: currentWidth,\n });\n }\n }, [onDragStateChange, currentLeft, currentWidth]);\n\n /**\n * Cleanup on unmount - if this instance owns the drag, cancel it\n */\n useEffect(() => {\n return () => {\n if (isOwnerRef.current && globalActiveDrag) {\n // We're unmounting while owning the drag - cancel it\n cancelDrag();\n }\n };\n }, []);\n\n /**\n * Handle mouse down on drag handle\n */\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n // Phase 11: locked tasks cannot be dragged or resized\n if (locked) return;\n\n const target = e.currentTarget as HTMLElement;\n const edgeZone = detectEdgeZone(e.clientX, target, edgeZoneWidth);\n\n // Determine drag mode from edge zone\n let mode: 'move' | 'resize-left' | 'resize-right' | null = null;\n switch (edgeZone) {\n case 'left':\n mode = 'resize-left';\n break;\n case 'right':\n mode = 'resize-right';\n break;\n case 'move':\n mode = 'move';\n break;\n }\n\n // Phase 19: Parent tasks cannot be resized - their dates are computed from children\n // Force move mode for parent tasks to prevent resize operations\n if (mode === 'resize-left' || mode === 'resize-right') {\n const currentTask = allTasks.find(t => t.id === taskId);\n if (currentTask && isTaskParent(taskId, allTasks)) {\n mode = 'move';\n }\n }\n\n if (!mode) {\n return;\n }\n\n // Get current position from state (this is what we see on screen)\n const initialLeft = currentLeft;\n const initialWidth = currentWidth;\n\n // Mark this instance as the drag owner\n isOwnerRef.current = true;\n\n // Update display state\n setIsDragging(true);\n setDragMode(mode);\n\n // Notify parent of drag start\n if (onDragStateChange) {\n onDragStateChange({\n isDragging: true,\n dragMode: mode,\n left: initialLeft,\n width: initialWidth,\n });\n }\n\n // Ensure global listeners are attached (idempotent)\n ensureGlobalListeners();\n\n // Phase 19: Build hierarchy chain for real-time parent movement\n // When dragging a child: include parent so it moves with children\n // When dragging a parent: include all children so they move with parent\n const currentTask = allTasks.find(t => t.id === taskId);\n let hierarchyChain: Task[] = [];\n\n if (currentTask) {\n const taskParentId = (currentTask as any).parentId;\n if (taskParentId) {\n // Dragging a child - include parent for real-time updates\n const parentTask = allTasks.find(t => t.id === taskParentId);\n if (parentTask) {\n hierarchyChain.push(parentTask);\n }\n } else {\n // Dragging a parent - include all children\n hierarchyChain = getChildren(taskId, allTasks);\n }\n }\n\n // Store drag state in global singleton\n globalActiveDrag = {\n taskId,\n mode,\n startX: e.clientX,\n initialLeft,\n initialWidth,\n currentLeft: initialLeft, // Initially same as initial\n currentWidth: initialWidth, // Initially same as initial\n dayWidth,\n monthStart,\n onProgress: handleProgress,\n onComplete: handleComplete,\n onCancel: handleCancel,\n allTasks,\n disableConstraints,\n cascadeChain: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS', 'SS', 'FF', 'SF']) // all successors, used for move (Phase 10: added SF)\n : [],\n cascadeChainFS: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS']) // FS + transitive, used for resize-right\n : [],\n cascadeChainStart: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['SS', 'SF']) // SS + SF for resize-left cascade (Phase 10: renamed from cascadeChainSS)\n : [],\n cascadeChainEnd: !disableConstraints\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS', 'FF']) // FS + FF for resize-right cascade (Phase 9)\n : [],\n hierarchyChain, // Phase 19: children of parent task\n onCascadeProgress,\n };\n }, [edgeZoneWidth, currentLeft, currentWidth, dayWidth, monthStart, taskId, onDragStateChange, handleProgress, handleComplete, handleCancel, allTasks, disableConstraints, onCascadeProgress, onCascade, locked]);\n\n /**\n * Get cursor style based on current position\n */\n const getCursorStyle = useCallback((): string => {\n if (locked) return 'not-allowed';\n if (isDragging) {\n return 'grabbing';\n }\n return 'grab';\n }, [locked, isDragging]);\n\n return {\n isDragging,\n dragMode,\n currentLeft,\n currentWidth,\n dragHandleProps: {\n onMouseDown: handleMouseDown,\n style: {\n cursor: getCursorStyle(),\n userSelect: 'none',\n } as React.CSSProperties,\n },\n };\n};\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { getDayOffset } from '../../utils/dateUtils';\nimport './TodayIndicator.css';\n\nexport interface TodayIndicatorProps {\n /** Start of the month for positioning calculations */\n monthStart: Date;\n /** Width of each day column in pixels */\n dayWidth: number;\n}\n\n/**\n * TodayIndicator component - displays a vertical line at the current date\n *\n * Only renders when the current date is within the visible month range.\n * Satisfies REND-04 requirement for visual today indicator.\n */\nconst TodayIndicator: React.FC<TodayIndicatorProps> = ({ monthStart, dayWidth }) => {\n // Use local date for \"today\" (not UTC) - user's current date matters\n const today = new Date();\n const todayLocal = new Date(Date.UTC(\n today.getFullYear(),\n today.getMonth(),\n today.getDate()\n ));\n\n // Calculate position based on offset from monthStart\n // The parent GanttChart component handles the date range check via todayInRange\n const position = useMemo(() => {\n const offset = getDayOffset(todayLocal, monthStart);\n return Math.round(offset * dayWidth);\n }, [monthStart, dayWidth, todayLocal]);\n\n // Allow negative positions (today before monthStart) - parent handles visibility\n if (isNaN(position)) {\n return null;\n }\n\n return (\n <div\n className=\"gantt-ti-indicator\"\n style={{\n left: `${position}px`,\n width: 'var(--gantt-today-indicator-width)',\n backgroundColor: 'var(--gantt-today-indicator-color)',\n }}\n aria-label=\"Today\"\n />\n );\n};\n\nexport default TodayIndicator;\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { calculateGridLines, calculateWeekendBlocks, calculateWeekGridLines, calculateMonthGridLines } from '../../utils/geometry';\nimport type { GridLine } from '../../types';\nimport './GridBackground.css';\n\nexport interface GridBackgroundProps {\n /** Array of dates to display (from getMultiMonthDays) */\n dateRange: Date[];\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Total height of the grid area in pixels */\n totalHeight: number;\n /** View mode: 'day' renders per-day lines with weekend blocks, 'week' renders per-week lines only, 'month' renders per-month lines only */\n viewMode?: 'day' | 'week' | 'month';\n /** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */\n isCustomWeekend?: (date: Date) => boolean;\n}\n\n/**\n * Custom comparison function for React.memo\n *\n * Performance optimization: Re-renders when dateRange length, dayWidth, totalHeight, or viewMode change.\n * Returns true (skip re-render) only when all four are unchanged.\n */\nconst arePropsEqual = (prevProps: GridBackgroundProps, nextProps: GridBackgroundProps) => {\n return (\n prevProps.dayWidth === nextProps.dayWidth &&\n prevProps.dateRange.length === nextProps.dateRange.length &&\n prevProps.totalHeight === nextProps.totalHeight && // skip re-render only when totalHeight unchanged\n prevProps.viewMode === nextProps.viewMode &&\n prevProps.isCustomWeekend === nextProps.isCustomWeekend\n );\n};\n\n/**\n * GridBackground component - renders vertical grid lines and weekend background highlighting\n *\n * This component provides the visual grid structure that runs behind task rows.\n * It separates grid rendering from task rendering for better performance and cleaner code.\n *\n * Features:\n * - Vertical grid lines at month/week/day boundaries\n * - Pink background highlighting for weekend days (day-view only)\n * - React.memo optimization for performance\n * - Pointer events disabled (clicks pass through to tasks)\n *\n * View modes:\n * - day (default): per-day grid lines + weekend background blocks\n * - week: per-week grid lines only (no weekend blocks, lines every 7 days)\n */\nconst GridBackground: React.FC<GridBackgroundProps> = React.memo(\n ({ dateRange, dayWidth, totalHeight, viewMode = 'day', isCustomWeekend }) => {\n // Week-view: grid lines at each 7-day boundary\n const weekGridLines = useMemo(() => {\n if (viewMode !== 'week') return [];\n return calculateWeekGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth, viewMode]);\n\n // Day-view: grid line positions per day (existing logic)\n const gridLines = useMemo<GridLine[]>(() => {\n if (viewMode === 'week' || viewMode === 'month') return [];\n return calculateGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth, viewMode]);\n\n // Month-view: grid lines at each month/year boundary\n const monthGridLines = useMemo(() => {\n if (viewMode !== 'month') return [];\n return calculateMonthGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth, viewMode]);\n\n // Weekend background blocks: only in day-view (locked decision from RESEARCH.md)\n const weekendBlocks = useMemo(() => {\n if (viewMode === 'week' || viewMode === 'month') return []; // No weekend highlighting in week/month-view\n return calculateWeekendBlocks(dateRange, dayWidth, isCustomWeekend);\n }, [dateRange, dayWidth, viewMode, isCustomWeekend]);\n\n // Calculate total grid width (formula must not change — Pitfall 3)\n const gridWidth = useMemo(() => {\n return Math.round(dateRange.length * dayWidth);\n }, [dateRange.length, dayWidth]);\n\n return (\n <div\n className=\"gantt-gb-gridBackground\"\n style={{\n width: `${gridWidth}px`,\n height: `${totalHeight}px`,\n }}\n >\n {/* Weekend backgrounds (rendered first, behind lines) — day-view only */}\n {weekendBlocks.map((block, index) => (\n <div\n key={`weekend-${index}`}\n className=\"gantt-gb-weekendBlock\"\n style={{\n left: `${block.left}px`,\n width: `${block.width}px`,\n }}\n />\n ))}\n\n {/* Vertical grid lines */}\n {viewMode === 'week' ? (\n // Week-view: one line per week column boundary\n weekGridLines.map((line, index) => {\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : 'gantt-gb-weekSeparator';\n return (\n <div\n key={`wgridline-${index}`}\n className={`gantt-gb-gridLine ${lineClass}`}\n style={{ left: `${line.x}px` }}\n />\n );\n })\n ) : viewMode === 'month' ? (\n // Month-view: thin line at each month boundary, thick at year boundary\n monthGridLines.map((line, index) => {\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : 'gantt-gb-weekSeparator';\n return (\n <div\n key={`mgridline-${index}`}\n className={`gantt-gb-gridLine ${lineClass}`}\n style={{ left: `${line.x}px` }}\n />\n );\n })\n ) : (\n // Day-view: existing code (unchanged)\n gridLines.map((line, index) => {\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : line.isWeekStart\n ? 'gantt-gb-weekSeparator'\n : 'gantt-gb-dayLine';\n return (\n <div\n key={`gridline-${index}`}\n className={`gantt-gb-gridLine ${lineClass}`}\n style={{\n left: `${line.x}px`,\n }}\n />\n );\n })\n )}\n </div>\n );\n },\n arePropsEqual\n);\n\nGridBackground.displayName = 'GridBackground';\n\nexport default GridBackground;\n","'use client';\n\nimport React from 'react';\nimport './DragGuideLines.css';\n\nexport interface DragGuideLinesProps {\n isDragging: boolean;\n dragMode: 'move' | 'resize-left' | 'resize-right' | null;\n left: number;\n width: number;\n totalHeight: number;\n}\n\nconst DragGuideLines: React.FC<DragGuideLinesProps> = ({\n isDragging,\n dragMode,\n left,\n width,\n totalHeight,\n}) => {\n if (!isDragging || !dragMode) {\n return null;\n }\n\n // Determine which lines to show based on drag mode\n const showLeftLine = dragMode === 'move' || dragMode === 'resize-left';\n const showRightLine = dragMode === 'move' || dragMode === 'resize-right';\n\n return (\n <>\n {showLeftLine && (\n <div\n className=\"gantt-dgl-guideLine\"\n style={{\n left: `${left}px`,\n height: `${totalHeight}px`,\n }}\n />\n )}\n {showRightLine && (\n <div\n className=\"gantt-dgl-guideLine\"\n style={{\n left: `${left + width}px`,\n height: `${totalHeight}px`,\n }}\n />\n )}\n </>\n );\n};\n\nexport default DragGuideLines;\n","'use client';\n\nimport React, { useMemo } from 'react';\nimport { Task } from '../../types';\nimport { calculateTaskBar, calculateDependencyPath, pixelsToDate } from '../../utils/geometry';\nimport { getAllDependencyEdges, detectCycles, computeLagFromDates } from '../../utils/dependencyUtils';\nimport type { LinkType } from '../../types';\nimport './DependencyLines.css';\n\n/**\n * Calculate effective lag based on current task pixel positions.\n * Delegates to computeLagFromDates for consistent semantics.\n */\nfunction calculateEffectiveLag(\n edge: { type: string },\n predPosition: { left: number; right: number },\n succPosition: { left: number; right: number },\n monthStart: Date,\n dayWidth: number\n): number {\n const predStart = pixelsToDate(predPosition.left, monthStart, dayWidth);\n const predEnd = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);\n const succStart = pixelsToDate(succPosition.left, monthStart, dayWidth);\n const succEnd = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);\n return computeLagFromDates(edge.type as LinkType, predStart, predEnd, succStart, succEnd);\n}\n\n/**\n * Check if a task is hidden inside a collapsed parent.\n */\nfunction isTaskHidden(taskId: string, collapsedParentIds: Set<string>, taskMap: Map<string, Task>): boolean {\n const task = taskMap.get(taskId);\n if (!task || !task.parentId) return false;\n return collapsedParentIds.has(task.parentId);\n}\n\n/**\n * Find the nearest visible ancestor of a hidden task.\n * Returns the ancestor task or null if the task is visible.\n */\nfunction findVisibleAncestor(\n task: Task,\n collapsedParentIds: Set<string>,\n taskMap: Map<string, Task>\n): Task | null {\n if (!task.parentId) return null;\n if (collapsedParentIds.has(task.parentId)) {\n const parent = taskMap.get(task.parentId);\n if (!parent) return null;\n // Check if parent is also hidden\n if (parent.parentId && collapsedParentIds.has(parent.parentId)) {\n return findVisibleAncestor(parent, collapsedParentIds, taskMap);\n }\n return parent;\n }\n return null;\n}\n\n/**\n * Check if two tasks share the same collapsed parent ancestor.\n * If both predecessor and successor are hidden inside the same parent,\n * the dependency line should NOT be rendered (it's internal to the collapsed group).\n */\nfunction areBothHiddenInSameParent(\n predecessorId: string,\n successorId: string,\n collapsedParentIds: Set<string>,\n taskMap: Map<string, Task>\n): boolean {\n const predTask = taskMap.get(predecessorId);\n const succTask = taskMap.get(successorId);\n\n if (!predTask || !succTask) return false;\n\n // Both must have parentIds\n if (!predTask.parentId || !succTask.parentId) return false;\n\n // Find the visible ancestor (collapsed parent) for each\n const predVisibleAncestor = findVisibleAncestor(predTask, collapsedParentIds, taskMap);\n const succVisibleAncestor = findVisibleAncestor(succTask, collapsedParentIds, taskMap);\n\n // Both must be hidden (have visible ancestors)\n if (!predVisibleAncestor || !succVisibleAncestor) return false;\n\n // Check if they share the same collapsed parent\n return predVisibleAncestor.id === succVisibleAncestor.id;\n}\n\nexport interface DependencyLinesProps {\n /** Visible tasks only (for row calculation) */\n tasks: Task[];\n /** All tasks including hidden children (for virtual position calculation) */\n allTasks?: Task[];\n /** Set of collapsed parent IDs */\n collapsedParentIds?: Set<string>;\n /** Start of the visible range (e.g., month start) */\n monthStart: Date;\n /** Width of each day column in pixels */\n dayWidth: number;\n /** Height of each task row in pixels */\n rowHeight: number;\n /** Total width of the grid in pixels */\n gridWidth: number;\n /** Real-time pixel overrides for task positions during drag (taskId -> {left, width}) */\n dragOverrides?: Map<string, { left: number; width: number }>;\n /** Currently selected dep chip — highlights the matching arrow in red */\n selectedDep?: { predecessorId: string; successorId: string; linkType: string } | null;\n}\n\n/**\n * SVG overlay component rendering dependency lines as orthogonal paths with rounded corners\n *\n * Lines connect from the right edge of predecessor tasks to the left edge\n * of successor tasks using horizontal/vertical lines with arc rounded corners.\n * Circular dependencies are highlighted in red.\n *\n * Virtual dependency links: When a task is hidden inside a collapsed parent,\n * its dependency lines render at \"virtual positions\" using the parent's row.\n * These virtual lines are styled with dashed strokes to indicate the hidden status.\n *\n * Performance: Uses React.memo to prevent re-renders when dependencies haven't changed.\n */\nexport const DependencyLines: React.FC<DependencyLinesProps> = React.memo(({\n tasks,\n allTasks,\n collapsedParentIds = new Set(),\n monthStart,\n dayWidth,\n rowHeight,\n gridWidth,\n dragOverrides,\n selectedDep,\n}) => {\n // Use allTasks for virtual position calculation if provided, otherwise use tasks\n const tasksForPositions = allTasks ?? tasks;\n\n // Create a lookup map for task positions and their indices\n const { taskPositions, taskIndices, hiddenTaskIds } = useMemo(() => {\n const positions = new Map<string, { left: number; right: number; rowTop: number; isVirtual: boolean }>();\n const indices = new Map<string, number>();\n const hidden = new Set<string>();\n const taskMap = new Map(tasksForPositions.map(t => [t.id, t]));\n const visibleTaskMap = new Map(tasks.map(t => [t.id, t]));\n\n // First pass: Calculate positions for visible tasks (existing logic)\n tasks.forEach((task, index) => {\n const startDate = new Date(task.startDate);\n const endDate = new Date(task.endDate);\n const computed = calculateTaskBar(startDate, endDate, monthStart, dayWidth);\n\n // Use real-time pixel override if available (during drag)\n const override = dragOverrides?.get(task.id);\n const resolvedLeft = override?.left ?? computed.left;\n const resolvedWidth = override?.width ?? computed.width;\n\n indices.set(task.id, index);\n positions.set(task.id, {\n left: resolvedLeft,\n right: resolvedLeft + resolvedWidth,\n rowTop: index * rowHeight,\n isVirtual: false,\n });\n });\n\n // Second pass: Calculate virtual positions for hidden tasks\n if (allTasks && collapsedParentIds.size > 0) {\n for (const task of allTasks) {\n // Skip if already processed (visible task)\n if (positions.has(task.id)) continue;\n\n // Check if task is hidden inside a collapsed parent\n if (!isTaskHidden(task.id, collapsedParentIds, taskMap)) continue;\n\n hidden.add(task.id);\n\n // Find the visible ancestor (collapsed parent)\n const visibleAncestor = findVisibleAncestor(task, collapsedParentIds, taskMap);\n if (!visibleAncestor) continue;\n\n // Get the ancestor's row position\n const ancestorPosition = positions.get(visibleAncestor.id);\n if (!ancestorPosition) continue;\n\n // Calculate horizontal position from task's dates\n const startDate = new Date(task.startDate);\n const endDate = new Date(task.endDate);\n const computed = calculateTaskBar(startDate, endDate, monthStart, dayWidth);\n\n // Use real-time pixel override if available (during drag)\n const override = dragOverrides?.get(task.id);\n const resolvedLeft = override?.left ?? computed.left;\n const resolvedWidth = override?.width ?? computed.width;\n\n // Store virtual position using ancestor's rowTop\n positions.set(task.id, {\n left: resolvedLeft,\n right: resolvedLeft + resolvedWidth,\n rowTop: ancestorPosition.rowTop,\n isVirtual: true,\n });\n }\n }\n\n return { taskPositions: positions, taskIndices: indices, hiddenTaskIds: hidden };\n }, [tasks, tasksForPositions, allTasks, collapsedParentIds, monthStart, dayWidth, rowHeight, dragOverrides]);\n\n // Detect cycles for highlighting (use allTasks for accurate cycle detection)\n const cycleInfo = useMemo(() => {\n const tasksForCycleDetection = allTasks ?? tasks;\n const result = detectCycles(tasksForCycleDetection);\n const cycleTaskIds = new Set(result.cyclePath || []);\n return cycleTaskIds;\n }, [tasks, allTasks]);\n\n // Calculate all dependency line paths (use allTasks if available)\n const lines = useMemo(() => {\n const tasksForEdges = allTasks ?? tasks;\n const edges = getAllDependencyEdges(tasksForEdges);\n const lines: Array<{\n id: string;\n path: string;\n hasCycle: boolean;\n lag: number;\n fromX: number;\n toX: number;\n fromY: number;\n reverseOrder: boolean;\n isVirtual: boolean;\n }> = [];\n\n for (const edge of edges) {\n const predecessor = taskPositions.get(edge.predecessorId);\n const successor = taskPositions.get(edge.successorId);\n const predecessorIndex = taskIndices.get(edge.predecessorId);\n const successorIndex = taskIndices.get(edge.successorId);\n\n if (!predecessor || !successor) {\n continue; // Skip if task not found (shouldn't happen with validation)\n }\n\n // Check if both tasks are hidden inside the same collapsed parent\n // If so, skip rendering this line (it's internal to the collapsed group)\n if (allTasks && collapsedParentIds.size > 0) {\n const taskMap = new Map(allTasks.map(t => [t.id, t]));\n if (areBothHiddenInSameParent(edge.predecessorId, edge.successorId, collapsedParentIds, taskMap)) {\n continue;\n }\n }\n\n // Check if either endpoint is virtual (hidden task)\n const isVirtual = predecessor.isVirtual || successor.isVirtual;\n\n // Determine if tasks are in reverse order (predecessor appears below successor)\n // For virtual tasks, use the predecessor's rowTop for comparison\n let reverseOrder = false;\n if (predecessorIndex !== undefined && successorIndex !== undefined) {\n reverseOrder = predecessorIndex > successorIndex;\n } else {\n // One or both are virtual - use rowTop for comparison\n reverseOrder = predecessor.rowTop > successor.rowTop;\n }\n\n // Calculate direction-specific Y coordinates\n let fromY: number;\n let toY: number;\n\n if (reverseOrder) {\n // Arrow goes UP: exit from top of parent bar, enter at bottom of child bar\n fromY = predecessor.rowTop + 10; // 8px from top of parent bar\n toY = successor.rowTop + rowHeight - 6; // 8px from bottom of child bar\n } else {\n // Arrow goes DOWN: exit from bottom of parent bar, enter at top of child bar\n fromY = predecessor.rowTop + rowHeight - 10; // 8px from bottom of parent bar\n toY = successor.rowTop + 6; // 8px from top of child bar\n }\n\n // Determine connection points based on link type:\n // FS: right → left\n // SS: left → left\n // FF: right → right\n // SF: left → right\n const fromX = (edge.type === 'SS' || edge.type === 'SF')\n ? predecessor.left\n : predecessor.right;\n\n const toX = (edge.type === 'FF' || edge.type === 'SF')\n ? successor.right\n : successor.left;\n\n const arrivesFromRight = edge.type === 'FF' || edge.type === 'SF';\n\n const from = { x: fromX, y: fromY };\n const to = { x: toX, y: toY };\n\n const path = calculateDependencyPath(from, to, arrivesFromRight);\n\n // Check if this edge is part of a cycle\n const hasCycle = cycleInfo.has(edge.predecessorId) || cycleInfo.has(edge.successorId);\n\n // Calculate effective lag from actual positions (always, not just during drag)\n const lag = calculateEffectiveLag(edge, predecessor, successor, monthStart, dayWidth);\n\n lines.push({\n id: `${edge.predecessorId}-${edge.successorId}-${edge.type}`,\n path,\n hasCycle,\n lag,\n fromX,\n toX,\n fromY,\n reverseOrder,\n isVirtual,\n });\n }\n\n return lines;\n }, [tasks, allTasks, taskPositions, taskIndices, cycleInfo, monthStart, dayWidth, dragOverrides]);\n\n // Calculate SVG height based on visible tasks (not all tasks)\n const svgHeight = tasks.length * rowHeight;\n\n return (\n <svg\n className=\"gantt-dependencies-svg\"\n width={gridWidth}\n height={svgHeight}\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n {/* Arrow marker for dependency lines */}\n <marker\n id=\"arrowhead\"\n markerWidth=\"8\"\n markerHeight=\"6\"\n markerUnits=\"userSpaceOnUse\"\n refX=\"7\"\n refY=\"3\"\n orient=\"auto\"\n >\n <polygon\n points=\"0 0, 8 3, 0 6\"\n fill=\"var(--gantt-dependency-line-color, #666666)\"\n />\n </marker>\n\n {/* Red arrow marker for circular dependencies */}\n <marker\n id=\"arrowhead-cycle\"\n markerWidth=\"8\"\n markerHeight=\"6\"\n markerUnits=\"userSpaceOnUse\"\n refX=\"7\"\n refY=\"3\"\n orient=\"auto\"\n >\n <polygon\n points=\"0 0, 8 3, 0 6\"\n fill=\"var(--gantt-dependency-cycle-color, #ef4444)\"\n />\n </marker>\n\n {/* Red arrow marker for selected dependency */}\n <marker\n id=\"arrowhead-selected\"\n markerWidth=\"8\"\n markerHeight=\"6\"\n markerUnits=\"userSpaceOnUse\"\n refX=\"7\"\n refY=\"3\"\n orient=\"auto\"\n >\n <polygon\n points=\"0 0, 8 3, 0 6\"\n fill=\"#ef4444\"\n />\n </marker>\n </defs>\n\n {lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder, isVirtual }) => {\n const isSelected =\n selectedDep != null &&\n id === `${selectedDep.predecessorId}-${selectedDep.successorId}-${selectedDep.linkType}`;\n\n let pathClassName = 'gantt-dependency-path';\n if (isSelected) pathClassName += ' gantt-dependency-selected';\n else if (hasCycle) pathClassName += ' gantt-dependency-cycle';\n if (isVirtual && !isSelected) pathClassName += ' gantt-dependency-virtual';\n\n let markerEnd: string;\n if (isSelected) markerEnd = 'url(#arrowhead-selected)';\n else if (hasCycle) markerEnd = 'url(#arrowhead-cycle)';\n else markerEnd = 'url(#arrowhead)';\n\n const lagColor = isSelected\n ? '#ef4444'\n : hasCycle\n ? 'var(--gantt-dependency-cycle-color, #ef4444)'\n : 'var(--gantt-dependency-line-color, #666666)';\n\n return (\n <React.Fragment key={id}>\n <path\n d={path}\n className={pathClassName}\n markerEnd={markerEnd}\n />\n {lag !== 0 && (\n <text\n className=\"gantt-dependency-lag-label\"\n x={lag < 0 ? toX + 14 : toX - 14}\n y={reverseOrder ? fromY - 4 : fromY + 12}\n textAnchor=\"middle\"\n fontSize=\"10\"\n fill={lagColor}\n >\n {lag > 0 ? `+${lag}` : `${lag}`}\n </text>\n )}\n </React.Fragment>\n );\n })}\n </svg>\n );\n});\n\nDependencyLines.displayName = 'DependencyLines';\n\nexport default DependencyLines;\n","'use client';\n\nimport React, { useMemo, useCallback, useState, useEffect, useRef } from 'react';\nimport type { Task, TaskDependency } from '../GanttChart';\nimport type { LinkType } from '../../types';\nimport type { CustomDayConfig } from '../../utils/dateUtils';\nimport { validateDependencies, calculateSuccessorDate, isTaskParent } from '../../utils/dependencyUtils';\nimport { normalizeHierarchyTasks } from '../../utils/hierarchyOrder';\nimport { getVisibleReorderPosition } from '../../utils/taskListReorder';\nimport { getChildren } from '../../utils/dependencyUtils';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/Popover';\nimport { TaskListRow } from './TaskListRow';\nimport { NewTaskRow } from './NewTaskRow';\nimport { LINK_TYPE_ICONS, LINK_TYPE_LABELS } from './DepIcons';\nimport './TaskList.css';\n\nexport { LINK_TYPE_ICONS };\n\nconst LINK_TYPE_ORDER: LinkType[] = ['FS', 'SS', 'FF', 'SF'];\nconst MIN_TASK_LIST_WIDTH = 640;\n\n/**\n * Get all descendant tasks of a parent task (recursively).\n * Returns an array of all tasks where task.parentId is in the parent chain.\n *\n * @param parentId - ID of the parent task\n * @param tasks - All tasks array\n * @returns Array of descendant tasks (not including the parent itself)\n */\nfunction getAllDescendants(parentId: string, tasks: Task[]): Task[] {\n const descendants: Task[] = [];\n const visited = new Set<string>();\n\n function collectChildren(taskId: string) {\n if (visited.has(taskId)) return;\n visited.add(taskId);\n\n const children = getChildren(taskId, tasks);\n for (const child of children) {\n descendants.push(child);\n collectChildren(child.id);\n }\n }\n\n collectChildren(parentId);\n return descendants;\n}\n\n/**\n * Вычисляет иерархический номер задачи на основе позиции в списке visibleTasks.\n * Корневые задачи: 1, 2, 3...\n * Дочерние задачи: 1.1, 1.2, 2.1, 2.1.1 и т.д.\n *\n * @param tasks - Массив видимых задач (уже отсортированных в иерархическом порядке)\n * @param taskIndex - Индекс задачи в массиве visibleTasks\n * @returns Иерархический номер в виде строки\n */\nfunction getTaskNumber(tasks: Task[], taskIndex: number): string {\n const task = tasks[taskIndex];\n if (!task) return '';\n\n // Если это корневая задача (нет parentId)\n if (!task.parentId) {\n // Найти порядковый номер среди корневых задач\n let rootIndex = 0;\n for (let i = 0; i < taskIndex; i++) {\n if (!tasks[i].parentId) {\n rootIndex++;\n }\n }\n return String(rootIndex + 1);\n }\n\n // Для дочерней задачи - найти родительский номер\n const parentIndex = tasks.findIndex(t => t.id === task.parentId);\n if (parentIndex === -1) {\n // Родитель не найден - fallback на плоский номер\n return String(taskIndex + 1);\n }\n\n const parentNumber = getTaskNumber(tasks, parentIndex);\n\n // Найти порядковый номер среди детей этого родителя\n let siblingIndex = 0;\n for (let i = 0; i < taskIndex; i++) {\n if (tasks[i].parentId === task.parentId) {\n siblingIndex++;\n }\n }\n\n return `${parentNumber}.${siblingIndex + 1}`;\n}\n\nexport interface TaskListProps {\n /** Array of tasks to display */\n tasks: Task[];\n /** Height of each row in pixels (must match Gantt chart's rowHeight) */\n rowHeight: number;\n /** Height of the header row in pixels (must match Gantt chart's headerHeight) */\n headerHeight: number;\n /** Width of the task list overlay in pixels (default: 400) */\n taskListWidth?: number;\n /** Callback when tasks are modified via inline edit. Receives array of changed tasks. */\n onTasksChange?: (tasks: Task[]) => void;\n /** ID of currently selected task */\n selectedTaskId?: string;\n /** Callback when task row is clicked */\n onTaskSelect?: (taskId: string | null) => void;\n /** Show or hide the task list (default: true) */\n show?: boolean;\n /** Show right-side shadow when chart content is horizontally scrolled */\n hasRightShadow?: boolean;\n /** Disable task name editing in the task list (default: false) */\n disableTaskNameEditing?: boolean;\n /** Disable dependency editing (hides +, ×, and type menu; read-only column) (default: false) */\n disableDependencyEditing?: boolean;\n /** Callback to scroll the chart grid to a task (wired to № cell click) */\n onScrollToTask?: (taskId: string) => void;\n /** Callback when selected chip changes (used by GanttChart to highlight the corresponding arrow) */\n onSelectedChipChange?: (chip: { successorId: string; predecessorId: string; linkType: string } | null) => void;\n /** Callback when a new task is added (called with full Task object including generated id) */\n onAdd?: (task: Task) => void;\n /** Callback when a task is deleted (called with taskId) */\n onDelete?: (taskId: string) => void;\n /** Callback when a new task is inserted after a specific task */\n onInsertAfter?: (taskId: string, newTask: Task) => void;\n /** Callback when tasks are reordered via drag in the task list */\n onReorder?: (tasks: Task[], movedTaskId?: string, inferredParentId?: string) => void;\n /** ID of task that should enter edit mode on mount (for auto-edit after insert) */\n editingTaskId?: string | null;\n /** Enable add task button at bottom of task list (default: true) */\n enableAddTask?: boolean;\n /** Set of collapsed parent task IDs */\n collapsedParentIds?: Set<string>;\n /** Callback when collapse/expand button is clicked */\n onToggleCollapse?: (parentId: string) => void;\n /** Callback when task is promoted (parentId removed) */\n onPromoteTask?: (taskId: string) => void;\n /** Callback when task is demoted (parentId set to previous task) */\n onDemoteTask?: (taskId: string, newParentId: string) => void;\n /** Custom day configurations for date picker */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate for date picker */\n isWeekend?: (date: Date) => boolean;\n /** Task IDs highlighted by the active filter */\n highlightedTaskIds?: Set<string>;\n}\n\n/**\n * TaskList component - displays tasks in a table format as an overlay\n *\n * Renders a table with columns: № (number), Name, Start Date, End Date, Duration, Progress, Dependencies\n * Uses position: sticky for synchronized vertical scrolling with the chart.\n */\nexport const TaskList: React.FC<TaskListProps> = ({\n tasks,\n rowHeight,\n headerHeight,\n taskListWidth = 640,\n onTasksChange,\n selectedTaskId,\n onTaskSelect,\n show = true,\n hasRightShadow = false,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n onScrollToTask,\n onSelectedChipChange,\n onAdd,\n onDelete,\n onInsertAfter,\n onReorder,\n editingTaskId: propEditingTaskId,\n enableAddTask = true,\n collapsedParentIds: externalCollapsedParentIds,\n onToggleCollapse: externalOnToggleCollapse,\n onPromoteTask,\n onDemoteTask,\n customDays,\n isWeekend,\n highlightedTaskIds = new Set(),\n}) => {\n // Hierarchy state: collapsed parent IDs (uncontrolled mode - internal state)\n const [internalCollapsedParentIds, setInternalCollapsedParentIds] = useState<Set<string>>(new Set());\n\n // Use external collapsedParentIds if provided (controlled mode), otherwise use internal state\n const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;\n\n // Use external onToggleCollapse if provided (controlled mode), otherwise use internal handler\n const handleToggleCollapse = externalOnToggleCollapse ?? useCallback((parentId: string) => {\n setInternalCollapsedParentIds(prev => {\n const next = new Set(prev);\n if (next.has(parentId)) {\n next.delete(parentId);\n } else {\n next.add(parentId);\n }\n return next;\n });\n }, []);\n\n const orderedTasks = useMemo(() => {\n return normalizeHierarchyTasks(tasks);\n }, [tasks]);\n\n // Filter tasks to hide children of collapsed parents.\n // Checks the full ancestor chain so grandchildren are hidden when any ancestor is collapsed.\n const visibleTasks = useMemo(() => {\n const parentMap = new Map(orderedTasks.map(t => [t.id, (t as any).parentId as string | undefined]));\n\n function isAnyAncestorCollapsed(parentId: string | undefined): boolean {\n let current = parentId;\n while (current) {\n if (collapsedParentIds.has(current)) return true;\n current = parentMap.get(current);\n }\n return false;\n }\n\n return orderedTasks.filter(task => !isAnyAncestorCollapsed((task as any).parentId));\n }, [orderedTasks, collapsedParentIds]);\n\n const totalHeight = useMemo(\n () => visibleTasks.length * rowHeight,\n [visibleTasks.length, rowHeight]\n );\n\n // Compute nesting depth for each task (0 = root, 1 = child, 2 = grandchild, etc.)\n const nestingDepthMap = useMemo(() => {\n const depthMap = new Map<string, number>();\n const taskById = new Map(tasks.map(t => [t.id, t]));\n\n function getDepth(taskId: string): number {\n if (depthMap.has(taskId)) return depthMap.get(taskId)!;\n const task = taskById.get(taskId);\n if (!task || !(task as any).parentId || !taskById.has((task as any).parentId)) {\n depthMap.set(taskId, 0);\n return 0;\n }\n const depth = getDepth((task as any).parentId) + 1;\n depthMap.set(taskId, depth);\n return depth;\n }\n\n for (const task of tasks) {\n getDepth(task.id);\n }\n return depthMap;\n }, [tasks]);\n\n // For each child task, determine if it's the last visible child of its parent\n const lastChildIds = useMemo(() => {\n const last = new Set<string>();\n const seenParents = new Set<string>();\n for (let i = visibleTasks.length - 1; i >= 0; i--) {\n const t = visibleTasks[i] as Task;\n if (t.parentId && !seenParents.has(t.parentId)) {\n last.add(t.id);\n seenParents.add(t.parentId);\n }\n }\n return last;\n }, [visibleTasks]);\n\n // For each task, track whether each ancestor level \"continues\" (has siblings below).\n // ancestorContinuesMap[taskId][i] = true means the ancestor at depth (i+1) is NOT the last child,\n // so a vertical continuation line should be drawn at horizontal position i.\n const ancestorContinuesMap = useMemo(() => {\n const taskById = new Map(tasks.map(t => [t.id, t]));\n const map = new Map<string, boolean[]>();\n for (const task of visibleTasks) {\n const continues: boolean[] = [];\n let current: any = taskById.get(task.id);\n while (current?.parentId && taskById.has(current.parentId)) {\n continues.unshift(!lastChildIds.has(current.id));\n current = taskById.get(current.parentId);\n }\n // Walk builds: [!isLastChild(outermost ancestor), ..., !isLastChild(parent), !isLastChild(task)]\n // We slice off the last entry (the task's own \"continues\" status) — the task's own vline\n // is rendered separately in TaskListRow using isLastChild.\n // Remaining entries: one per ancestor level, outermost first.\n // ancestorContinues[i] = true → draw vertical continuation line at position i * 20 + 9 px.\n map.set(task.id, continues.slice(0, -1));\n }\n return map;\n }, [tasks, visibleTasks, lastChildIds]);\n\n const handleRowClick = useCallback((taskId: string) => {\n onTaskSelect?.(taskId);\n }, [onTaskSelect]);\n\n // Dependency state\n const [activeLinkType, setActiveLinkType] = useState<LinkType>('FS');\n const [selectingPredecessorFor, setSelectingPredecessorFor] = useState<string | null>(null);\n const [typeMenuOpen, setTypeMenuOpen] = useState(false);\n const [cycleError, setCycleError] = useState(false);\n const overlayRef = useRef<HTMLDivElement>(null);\n\n // Selected chip state: clicking a chip on a successor row selects it,\n // causing the predecessor row to show a \"Удалить\" button\n const [selectedChip, setSelectedChip] = useState<{\n successorId: string;\n predecessorId: string;\n linkType: LinkType;\n } | null>(null);\n\n const handleChipSelect = useCallback((chip: {\n successorId: string;\n predecessorId: string;\n linkType: LinkType;\n } | null) => {\n setSelectedChip(chip);\n onSelectedChipChange?.(chip);\n }, [onSelectedChipChange]);\n\n // Escape / outside-click cancel for picker mode, chip selection, and task row selection\n useEffect(() => {\n if (!selectingPredecessorFor && !selectedChip && !selectedTaskId) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setSelectingPredecessorFor(null);\n setSelectedChip(null);\n onSelectedChipChange?.(null);\n onTaskSelect?.(null);\n }\n };\n const handleMouseDown = (e: MouseEvent) => {\n const target = e.target as Element;\n if (overlayRef.current?.contains(target)) return;\n // Don't clear when clicking inside a floating portal (popover, date picker, etc.)\n if (target.closest?.('.gantt-popover')) return;\n setSelectingPredecessorFor(null);\n setSelectedChip(null);\n onSelectedChipChange?.(null);\n onTaskSelect?.(null);\n };\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('mousedown', handleMouseDown, true);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('mousedown', handleMouseDown, true);\n };\n }, [selectingPredecessorFor, selectedChip, selectedTaskId, onTaskSelect, onSelectedChipChange]);\n\n const handleAddDependency = useCallback((\n successorTaskId: string,\n predecessorTaskId: string,\n linkType: LinkType\n ) => {\n // Guard: no self-links\n if (successorTaskId === predecessorTaskId) return;\n\n // Guard: no duplicate (same taskId + type)\n const successor = tasks.find(t => t.id === successorTaskId);\n if (!successor) return;\n const alreadyExists = (successor.dependencies ?? []).some(\n d => d.taskId === predecessorTaskId && d.type === linkType\n );\n if (alreadyExists) {\n setSelectingPredecessorFor(null);\n return;\n }\n\n // Build hypothetical tasks array to validate for cycles\n const newDep: TaskDependency = { taskId: predecessorTaskId, type: linkType, lag: 0 };\n const hypothetical = tasks.map(t =>\n t.id === successorTaskId\n ? { ...t, dependencies: [...(t.dependencies ?? []), newDep] }\n : t\n );\n const validation = validateDependencies(hypothetical);\n if (!validation.isValid) {\n setCycleError(true);\n setTimeout(() => setCycleError(false), 3000);\n return;\n }\n\n const updatedTask = hypothetical.find(t => t.id === successorTaskId)!;\n\n // Snap successor dates to the predecessor position (lag=0)\n const predecessor = tasks.find(t => t.id === predecessorTaskId);\n if (predecessor) {\n const predStart = new Date(predecessor.startDate as string);\n const predEnd = new Date(predecessor.endDate as string);\n const constraintDate = calculateSuccessorDate(predStart, predEnd, linkType, 0);\n\n const origSuccessor = tasks.find(t => t.id === successorTaskId)!;\n const durationMs =\n new Date(origSuccessor.endDate as string).getTime() -\n new Date(origSuccessor.startDate as string).getTime();\n\n let newStart: Date;\n let newEnd: Date;\n\n if (linkType === 'FS' || linkType === 'SS') {\n newStart = constraintDate;\n newEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n newEnd = constraintDate;\n newStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n const snappedTask: Task = {\n ...updatedTask,\n startDate: newStart.toISOString().split('T')[0],\n endDate: newEnd.toISOString().split('T')[0],\n };\n onTasksChange?.([snappedTask]);\n } else {\n // Predecessor not found — emit without snap (graceful fallback)\n onTasksChange?.([updatedTask]);\n }\n\n setSelectingPredecessorFor(null);\n }, [tasks, onTasksChange]);\n\n const handleRemoveDependency = useCallback((\n taskId: string,\n predecessorTaskId: string,\n linkType: LinkType\n ) => {\n const task = tasks.find(t => t.id === taskId);\n if (!task) return;\n const updatedDeps = (task.dependencies ?? []).filter(\n d => !(d.taskId === predecessorTaskId && d.type === linkType)\n );\n onTasksChange?.([{ ...task, dependencies: updatedDeps }]);\n }, [tasks, onTasksChange]);\n\n // New task creation state\n const [isCreating, setIsCreating] = useState(false);\n\n // Drag-to-reorder state\n const [draggingIndex, setDraggingIndex] = useState<number | null>(null);\n const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);\n const dragOriginIndexRef = useRef<number | null>(null);\n const dragTaskIdRef = useRef<string | null>(null);\n\n // Helper: check if a parent task can be dropped at a specific position\n // Parent tasks cannot be dropped:\n // 1. Between their own children\n // 2. Between another parent's children (would make them a child)\n // 3. Under their own descendants (would create a cycle)\n const isValidParentDrop = useCallback((draggedTaskId: string, dropIndex: number): boolean => {\n // If not a parent, allow all drops\n if (!isTaskParent(draggedTaskId, tasks)) {\n return true;\n }\n\n const dropTarget = visibleTasks[dropIndex];\n if (!dropTarget) return true;\n\n // Scenario 1: Dropping parent between its own children\n if (dropTarget.parentId === draggedTaskId) {\n return false;\n }\n\n // Scenario 2: Dropping parent between another parent's children\n // Allow this for unlimited nesting — parent can become nested under another task.\n // Scenarios 1 and 3 still protect against circular references and self-nesting.\n\n // Scenario 3: Dropping parent under one of its own descendants\n // This would create a cycle (parent becomes child of its descendant)\n // Check if dropTarget is a descendant of draggedTaskId\n const draggedTask = orderedTasks.find(t => t.id === draggedTaskId);\n if (!draggedTask) return true;\n\n const descendants = getAllDescendants(draggedTaskId, orderedTasks);\n const descendantIds = new Set(descendants.map(d => d.id));\n\n if (descendantIds.has(dropTarget.id)) {\n return false;\n }\n\n // Allow dropping on other root tasks (parents or non-parents)\n return true;\n }, [tasks, visibleTasks, orderedTasks]);\n\n const handleDragStart = useCallback((index: number, e: React.DragEvent) => {\n e.dataTransfer.effectAllowed = 'move';\n setDraggingIndex(index);\n dragOriginIndexRef.current = index;\n dragTaskIdRef.current = visibleTasks[index]?.id ?? null;\n }, [visibleTasks]);\n\n const handleDragOver = useCallback((index: number, e: React.DragEvent) => {\n e.preventDefault();\n\n const draggedTaskId = dragTaskIdRef.current;\n if (!draggedTaskId) return;\n\n // Don't show drop indication if this is an invalid parent drop\n if (!isValidParentDrop(draggedTaskId, index)) {\n setDragOverIndex(null);\n e.dataTransfer.dropEffect = 'none';\n return;\n }\n\n e.dataTransfer.dropEffect = 'move';\n setDragOverIndex(index);\n }, [isValidParentDrop]);\n\n const handleDrop = useCallback((dropIndex: number, e: React.DragEvent) => {\n e.preventDefault();\n const originVisibleIndex = dragOriginIndexRef.current;\n const movedTaskId = dragTaskIdRef.current;\n\n // No-op: same position (line is already where the row is)\n if (originVisibleIndex === null || movedTaskId === null || originVisibleIndex === dropIndex) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n // Reject invalid parent drops (parent being dragged into children or another parent)\n if (!isValidParentDrop(movedTaskId, dropIndex)) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n const reorderPosition = getVisibleReorderPosition(\n orderedTasks,\n visibleTasks,\n movedTaskId,\n originVisibleIndex,\n dropIndex,\n );\n\n if (!reorderPosition) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n const { originOrderedIndex, insertIndex } = reorderPosition;\n\n // Early exit: if insertIndex equals originOrderedIndex, the subtree would be removed\n // and re-inserted at the exact same position - a true no-op. Skip the callback.\n if (insertIndex === originOrderedIndex) {\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n return;\n }\n\n const moved = orderedTasks[originOrderedIndex];\n\n // Check if this is a parent task with children\n const hasChildren = isTaskParent(moved.id, orderedTasks);\n\n // Extract the subtree to move (parent + all descendants, if any)\n let subtree: Task[];\n let subtreeCount: number;\n\n if (hasChildren) {\n // Get all descendants of the parent\n const descendants = getAllDescendants(moved.id, orderedTasks);\n subtree = [moved, ...descendants];\n subtreeCount = subtree.length;\n } else {\n // Single task (not a parent)\n subtree = [moved];\n subtreeCount = 1;\n }\n\n const reordered = [...orderedTasks];\n\n // Remove the entire subtree from its original position\n reordered.splice(originOrderedIndex, subtreeCount);\n\n // CRITICAL: insertIndex is already relative to reorderedWithoutMoved\n // After the splice, reordered === reorderedWithoutMoved (same array, same order)\n // So we should use insertIndex directly, NOT insertIndex - subtreeCount\n // The old code was subtracting subtreeCount again, which was incorrect\n const adjustedInsertIndex = insertIndex;\n\n // parentId inference: determine if task should be in a group\n // IMPORTANT: Calculate this BEFORE splicing moved task back into reordered\n // because we need to find the parent's position in the array WITHOUT the moved task\n let inferredParentId: string | undefined;\n\n if (moved.parentId) {\n // Task is currently a child - check if it's staying in or leaving its group\n // Find parent position in the array WITHOUT the moved task (reordered after first splice)\n const parentIndex = reordered.findIndex(t => t.id === moved.parentId);\n\n if (parentIndex === -1) {\n // Parent not found - should not happen, but handle gracefully\n inferredParentId = undefined;\n } else {\n // Calculate where the moved task will end up AFTER we splice it in\n // The key question: is insertIndex outside the range [parentIndex, parentIndex + numSiblings]?\n const numSiblings = reordered.filter(t => t.parentId === moved.parentId).length;\n const groupEnd = parentIndex + numSiblings;\n\n // If adjustedInsertIndex is <= parent (at or above parent position) or > groupEnd (below all siblings)\n // Note: adjustedInsertIndex == parentIndex means child will be inserted at parent's position,\n // which after splicing puts child above parent (parent shifts down by 1)\n if (adjustedInsertIndex <= parentIndex || adjustedInsertIndex > groupEnd) {\n inferredParentId = undefined; // Exit group - become root\n } else {\n // Staying within group - keep original parentId\n inferredParentId = moved.parentId;\n }\n }\n } else {\n // Task is currently root - check if it should join a group after splicing\n }\n\n // Now splice the entire subtree into its final position\n reordered.splice(adjustedInsertIndex, 0, ...subtree);\n\n // For root tasks, check if they should join a group (need reordered for this)\n // IMPORTANT: Parent tasks (hasChildren === true) must NEVER be reparented during drag-drop.\n // They always stay at root level regardless of where they are dropped.\n // Only leaf/child tasks (non-parents) can be adopted into a group by neighboring tasks.\n if (!moved.parentId && !hasChildren) {\n const taskAbove = adjustedInsertIndex > 0 ? reordered[adjustedInsertIndex - 1] : null;\n const taskBelow = adjustedInsertIndex < reordered.length - 1 ? reordered[adjustedInsertIndex + 1] : null;\n\n // Join a group ONLY if placed between parent and its first child,\n // or between two children of the same parent.\n // Dropping after the last child of a group keeps the task at root level.\n if (taskAbove && taskBelow && taskBelow.parentId === taskAbove.id) {\n // Placed between a parent and its first child\n inferredParentId = taskAbove.id;\n } else if (taskAbove && taskBelow && taskAbove.parentId && taskAbove.parentId === taskBelow.parentId) {\n // Placed between two children of the same parent\n inferredParentId = taskAbove.parentId;\n } else if (!taskAbove && taskBelow && taskBelow.parentId) {\n // Placed at the very top, above a child — join that group\n inferredParentId = taskBelow.parentId;\n }\n }\n\n onReorder?.(reordered, moved.id, inferredParentId);\n onTaskSelect?.(moved.id);\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n }, [orderedTasks, visibleTasks, onReorder, onTaskSelect]);\n\n const handleDragEnd = useCallback(() => {\n // Called when drag ends without a valid drop (Escape, or dropped outside)\n // handleDrop already clears state on successful drop, so this is only the cancel path\n setDraggingIndex(null);\n setDragOverIndex(null);\n dragOriginIndexRef.current = null;\n dragTaskIdRef.current = null;\n }, []);\n\n const handleConfirmNewTask = useCallback((name: string) => {\n const now = new Date();\n const todayISO = new Date(Date.UTC(\n now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()\n )).toISOString().split('T')[0];\n const endISO = new Date(Date.UTC(\n now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 7\n )).toISOString().split('T')[0];\n const newTask: Task = {\n id: crypto.randomUUID(),\n name,\n startDate: todayISO,\n endDate: endISO,\n };\n onAdd?.(newTask);\n setIsCreating(false);\n }, [onAdd]);\n\n const handleCancelNewTask = useCallback(() => setIsCreating(false), []);\n\n /**\n * Calculate the depth of a task in the hierarchy.\n * Root tasks have depth 0, their children have depth 1, etc.\n */\n function getTaskDepth(task: Task | undefined, tasks: Task[]): number {\n if (!task) return 0;\n let depth = 0;\n let current: Task | undefined = task;\n while (current) {\n if (!current.parentId) break;\n depth++;\n const parentId: string = current.parentId;\n current = tasks.find(t => t.id === parentId);\n }\n return depth;\n }\n\n /**\n * Demote wrapper — move task down one level in hierarchy.\n *\n * Rules:\n * 1. Find the PREVIOUS task at the SAME depth level (same hierarchy level)\n * 2. Make that task the parent of the current task\n * 3. If no previous task at same level exists (first task), create \"Новый раздел\"\n *\n * Example:\n * - Task 1.1 (depth 1)\n * - Task 1.2 (depth 1)\n * - [Task to demote] (depth 1) → becomes child of Task 1.2\n *\n * Result:\n * - Task 1.1 (depth 1)\n * - Task 1.2 (depth 1)\n * - Task to demote (depth 2, child of 1.2)\n *\n * The `_newParentId` argument from TaskListRow is ignored — we compute the correct parent here.\n */\n const handleDemoteWrapper = useCallback((taskId: string, _newParentId: string) => {\n const taskIndex = visibleTasks.findIndex(t => t.id === taskId);\n const currentTask = visibleTasks[taskIndex];\n const currentDepth = getTaskDepth(currentTask, orderedTasks);\n\n if (taskIndex > 0) {\n // Search backwards for the previous task at the same depth level\n for (let i = taskIndex - 1; i >= 0; i--) {\n const previousTask = visibleTasks[i];\n const previousDepth = getTaskDepth(previousTask, orderedTasks);\n\n // Found a task at the same level - use it as parent\n if (previousDepth === currentDepth) {\n onDemoteTask?.(taskId, previousTask.id);\n return;\n }\n\n // If we encounter a task at a shallower depth, stop searching\n // (no same-level task exists before this point)\n if (previousDepth < currentDepth) {\n break;\n }\n }\n\n // No same-level task found - cannot demote\n return;\n }\n\n // First-task case: create \"Новый раздел\" as a new root parent\n const demotedTask = orderedTasks.find(t => t.id === taskId);\n if (!demotedTask) return;\n\n const newSectionTask: Task = {\n id: crypto.randomUUID(),\n name: 'Новый раздел',\n startDate: demotedTask.startDate,\n endDate: demotedTask.endDate,\n };\n\n const updatedTasks: Task[] = [\n newSectionTask,\n ...orderedTasks.map(t =>\n t.id === taskId ? { ...t, parentId: newSectionTask.id } : t\n ),\n ];\n\n onReorder?.(updatedTasks, taskId, newSectionTask.id);\n }, [visibleTasks, orderedTasks, onDemoteTask, onReorder]);\n\n const effectiveTaskListWidth = Math.max(taskListWidth, MIN_TASK_LIST_WIDTH);\n\n return (\n <div\n ref={overlayRef}\n className={`gantt-tl-overlay${show ? '' : ' gantt-tl-hidden'}${hasRightShadow ? ' gantt-tl-overlay-shadowed' : ''}`}\n style={{ '--tasklist-width': `${effectiveTaskListWidth}px` } as React.CSSProperties}\n >\n <div className=\"gantt-tl-table\">\n {/* Header row - aligns with TimeScaleHeader, 1px taller for row alignment */}\n <div className=\"gantt-tl-header\" style={{ height: `${headerHeight + 0.5}px` }}>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-number\">№</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-name\">Имя</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-date\">Начало</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-date\">Окончание</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-duration\">Дн.</div>\n <div className=\"gantt-tl-headerCell gantt-tl-cell-progress\">%</div>\n {/* Dependencies column header with type switcher */}\n <div className=\"gantt-tl-headerCell gantt-tl-cell-deps\" style={{ position: 'relative' }}>\n <Popover open={typeMenuOpen} onOpenChange={setTypeMenuOpen}>\n <PopoverTrigger asChild>\n <button\n className=\"gantt-tl-dep-type-trigger\"\n disabled={disableDependencyEditing}\n onClick={(e) => e.stopPropagation()}\n >\n Связи {React.createElement(LINK_TYPE_ICONS[activeLinkType])} &#9662;\n </button>\n </PopoverTrigger>\n <PopoverContent portal={true} align=\"start\">\n <div className=\"gantt-tl-dep-type-menu\">\n {LINK_TYPE_ORDER.map(lt => (\n <button\n key={lt}\n className={`gantt-tl-dep-type-option${activeLinkType === lt ? ' active' : ''}`}\n onClick={() => { setActiveLinkType(lt); setTypeMenuOpen(false); }}\n >\n {React.createElement(LINK_TYPE_ICONS[lt])}\n <span>{LINK_TYPE_LABELS[lt]}</span>\n </button>\n ))}\n </div>\n </PopoverContent>\n </Popover>\n {cycleError && (\n <div className=\"gantt-tl-dep-error\">Цикл зависимостей!</div>\n )}\n </div>\n </div>\n\n {/* Data rows */}\n <div className=\"gantt-tl-body\" style={{ height: `${totalHeight}px` }}>\n {visibleTasks.map((task, index) => (\n <TaskListRow\n key={task.id}\n task={task}\n rowIndex={index}\n taskNumber={getTaskNumber(visibleTasks, index)}\n rowHeight={rowHeight}\n onTasksChange={onTasksChange}\n selectedTaskId={selectedTaskId}\n onRowClick={handleRowClick}\n disableTaskNameEditing={disableTaskNameEditing}\n disableDependencyEditing={disableDependencyEditing}\n allTasks={tasks}\n activeLinkType={activeLinkType}\n selectingPredecessorFor={selectingPredecessorFor}\n onSetSelectingPredecessorFor={setSelectingPredecessorFor}\n onAddDependency={handleAddDependency}\n onRemoveDependency={handleRemoveDependency}\n selectedChip={selectedChip}\n onChipSelect={handleChipSelect}\n onScrollToTask={onScrollToTask}\n onDelete={onDelete}\n onAdd={onAdd}\n onInsertAfter={onInsertAfter}\n editingTaskId={propEditingTaskId}\n isDragging={draggingIndex === index}\n isDragOver={dragOverIndex === index}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n onDragEnd={handleDragEnd}\n collapsedParentIds={collapsedParentIds}\n onToggleCollapse={handleToggleCollapse}\n onPromoteTask={onPromoteTask}\n onDemoteTask={onDemoteTask ? handleDemoteWrapper : undefined}\n isLastChild={lastChildIds.has(task.id)}\n nestingDepth={nestingDepthMap.get(task.id) ?? 0}\n ancestorContinues={ancestorContinuesMap.get(task.id) ?? []}\n customDays={customDays}\n isWeekend={isWeekend}\n isFilterMatch={highlightedTaskIds.has(task.id)}\n />\n ))}\n </div>\n\n {/* Ghost row for new task creation — positioned OUTSIDE body div to avoid height desync */}\n {isCreating && (\n <NewTaskRow\n rowHeight={rowHeight}\n onConfirm={handleConfirmNewTask}\n onCancel={handleCancelNewTask}\n />\n )}\n\n {/* Add task button - also serves as drop target for moving tasks to end */}\n {enableAddTask && onAdd && !isCreating && (\n <button\n className={`gantt-tl-add-btn${dragOverIndex === visibleTasks.length ? ' gantt-tl-add-btn-drag-over' : ''}`}\n onClick={() => setIsCreating(true)}\n onDragEnter={(e) => {\n e.preventDefault();\n setDragOverIndex(visibleTasks.length);\n }}\n onDragOver={(e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n setDragOverIndex(visibleTasks.length);\n }}\n onDragLeave={(e) => {\n e.preventDefault();\n setDragOverIndex(null);\n }}\n onDrop={(e) => {\n e.preventDefault();\n handleDrop(visibleTasks.length, e);\n }}\n type=\"button\"\n >\n + Добавить задачу\n </button>\n )}\n </div>\n </div>\n );\n};\n\nexport default TaskList;\n","import type { Task } from '../components/GanttChart';\n\ntype TaskLike = { id: string };\n\nexport interface VisibleReorderPosition {\n originOrderedIndex: number;\n insertIndex: number;\n}\n\n/**\n * Get all descendant IDs of a task (recursively).\n * Used to identify the entire subtree that must move together when dragging a parent.\n */\nfunction getDescendantIds(taskId: string, tasks: TaskLike[]): string[] {\n const descendants: string[] = [];\n const visited = new Set<string>();\n\n function collect(id: string) {\n if (visited.has(id)) return;\n visited.add(id);\n\n // Find all direct children of this task\n for (const task of tasks) {\n if ((task as any).parentId === id && !visited.has(task.id)) {\n descendants.push(task.id);\n collect(task.id);\n }\n }\n }\n\n collect(taskId);\n return descendants;\n}\n\n/**\n * Map visible drag/drop positions to indices in the full ordered task list.\n * This keeps collapsed descendants attached to their parent row.\n *\n * When dragging a parent task, all its descendants are included in the move,\n * so they are all filtered out before calculating the insert position.\n */\nexport function getVisibleReorderPosition(\n orderedTasks: TaskLike[],\n visibleTasks: TaskLike[],\n movedTaskId: string,\n originVisibleIndex: number,\n dropVisibleIndex: number,\n): VisibleReorderPosition | null {\n const originOrderedIndex = orderedTasks.findIndex((task) => task.id === movedTaskId);\n if (originOrderedIndex === -1) {\n return null;\n }\n\n // Get all descendant IDs if this is a parent task\n const descendantIds = getDescendantIds(movedTaskId, orderedTasks);\n const allMovedIds = new Set([movedTaskId, ...descendantIds]);\n\n // Filter out ALL tasks that will move (parent + descendants)\n const reorderedWithoutMoved = orderedTasks.filter((task) => !allMovedIds.has(task.id));\n const visibleWithoutMoved = visibleTasks.filter((task) => !allMovedIds.has(task.id));\n\n if (visibleWithoutMoved.length === 0) {\n return { originOrderedIndex, insertIndex: 0 };\n }\n\n // CRITICAL: dropVisibleIndex is an index into the ORIGINAL visibleTasks, NOT into\n // visibleWithoutMoved (which has fewer items after removing the moved subtree).\n // We must look up the actual drop target task by its ID from the original list,\n // then find it in visibleWithoutMoved.\n\n // Look up the actual task at the drop position in the ORIGINAL visible list\n const dropTargetTask = visibleTasks[dropVisibleIndex];\n\n if (!dropTargetTask) {\n // dropVisibleIndex is beyond the end of the original list - append at end\n return {\n originOrderedIndex,\n insertIndex: reorderedWithoutMoved.length,\n };\n }\n\n // Find the drop target in the filtered array (visibleWithoutMoved has the moved subtree removed)\n const filteredDropIndex = visibleWithoutMoved.findIndex((t) => t.id === dropTargetTask.id);\n\n if (filteredDropIndex === -1) {\n // Drop target was part of the moved subtree - should not happen after isValidParentDrop check\n // Append at end as fallback\n return {\n originOrderedIndex,\n insertIndex: reorderedWithoutMoved.length,\n };\n }\n\n const targetVisibleTask = visibleWithoutMoved[filteredDropIndex];\n\n // Find the target in reorderedWithoutMoved.\n // The drop indicator semantics: indicator at position N shows the TOP border of row N,\n // meaning the task will be inserted ABOVE row N.\n // We use the drop target's position directly without skipping past its group.\n // This preserves \"drop at top of родитель2 = insert before родитель2\" semantics.\n // To move a parent PAST родитель2's entire group, the user must drag to the end of the list\n // (past all of родитель2's children), which triggers the \"append at end\" path above.\n const insertIndex = reorderedWithoutMoved.findIndex((task) => task.id === targetVisibleTask.id);\n\n return {\n originOrderedIndex,\n insertIndex,\n };\n}\n","'use client';\n\nimport React from 'react';\nimport * as RadixPopover from '@radix-ui/react-popover';\n\nexport interface PopoverProps {\n /** Whether the popover is open */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** The trigger element */\n children: React.ReactNode;\n}\n\nexport interface PopoverContentProps {\n /** Content to display inside the popover */\n children: React.ReactNode;\n /** Additional CSS class names */\n className?: string;\n /** Alignment relative to trigger */\n align?: 'start' | 'center' | 'end';\n /** Side to render the popover */\n side?: 'top' | 'right' | 'bottom' | 'left';\n /** Whether to use a portal for rendering */\n portal?: boolean;\n /** Collision padding */\n collisionPadding?: number;\n /** Callback when user interacts outside the popover */\n onInteractOutside?: (event: CustomEvent) => void;\n}\n\n/**\n * Popover root component wrapping Radix UI Popover\n */\nexport const Popover: React.FC<PopoverProps> = ({ open, onOpenChange, children }) => {\n return (\n <RadixPopover.Root open={open} onOpenChange={onOpenChange}>\n {children}\n </RadixPopover.Root>\n );\n};\n\n/**\n * Popover trigger — wraps the element that opens the popover\n */\nexport const PopoverTrigger = RadixPopover.Trigger;\n\n/**\n * Popover content — the floating panel\n */\nexport const PopoverContent: React.FC<PopoverContentProps> = ({\n children,\n className,\n align = 'start',\n side = 'bottom',\n portal = true,\n collisionPadding = 8,\n onInteractOutside,\n}) => {\n const content = (\n <RadixPopover.Content\n className={`gantt-popover${className ? ` ${className}` : ''}`}\n align={align}\n side={side}\n collisionPadding={collisionPadding}\n sideOffset={4}\n onInteractOutside={onInteractOutside}\n >\n {children}\n </RadixPopover.Content>\n );\n\n if (portal) {\n return <RadixPopover.Portal>{content}</RadixPopover.Portal>;\n }\n\n return content;\n};\n\nexport default Popover;\n","\"use client\";\n\nimport React, {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n} from \"react\";\nimport type { Task } from \"../GanttChart\";\nimport type { LinkType } from \"../../types\";\nimport type { CustomDayConfig } from \"../../utils/dateUtils\";\nimport { parseUTCDate, normalizeTaskDates, createCustomDayPredicate } from \"../../utils/dateUtils\";\nimport {\n computeLagFromDates,\n calculateSuccessorDate,\n isTaskParent,\n findParentId,\n getChildren,\n} from \"../../utils/dependencyUtils\";\nimport { Input } from \"../ui/Input\";\nimport { DatePicker } from \"../ui/DatePicker\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/Popover\";\nimport { LINK_TYPE_ICONS } from \"./DepIcons\";\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nconst getInclusiveDurationDays = (\n startDate: string | Date,\n endDate: string | Date,\n): number => {\n const start = parseUTCDate(startDate);\n const end = parseUTCDate(endDate);\n return Math.max(\n 1,\n Math.round((end.getTime() - start.getTime()) / DAY_MS) + 1,\n );\n};\n\nconst getEndDateFromDuration = (\n startDate: string | Date,\n durationDays: number,\n): string => {\n const start = parseUTCDate(startDate);\n return new Date(start.getTime() + (durationDays - 1) * DAY_MS)\n .toISOString()\n .split(\"T\")[0];\n};\n\n// ---------------------------------------------------------------------------\n// DepChip — local unified component used in both single-chip cell and popover\n// ---------------------------------------------------------------------------\ninterface DepChipProps {\n lag?: number;\n dep: { taskId: string; type: LinkType };\n taskId: string;\n predecessorName?: string;\n selectedChip: TaskListRowProps[\"selectedChip\"];\n disableDependencyEditing: boolean;\n onChipSelect: TaskListRowProps[\"onChipSelect\"];\n onRowClick: TaskListRowProps[\"onRowClick\"];\n onScrollToTask: TaskListRowProps[\"onScrollToTask\"];\n onRemoveDependency: TaskListRowProps[\"onRemoveDependency\"];\n onChipSelectClear: () => void;\n /** The successor task (needed for lag date computation) */\n task: Task;\n /** All tasks (needed to find predecessor dates) */\n allTasks: Task[];\n /** Callback to save date changes after lag modification */\n onTasksChange?: TaskListRowProps[\"onTasksChange\"];\n}\n\nconst TrashIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n);\n\nconst PlusIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M12 5v14M5 12h14\" />\n </svg>\n);\n\nconst DragHandleIcon = () => (\n <svg width=\"10\" height=\"14\" viewBox=\"0 0 10 14\" fill=\"currentColor\">\n <circle cx=\"2\" cy=\"2\" r=\"1.5\" />\n <circle cx=\"8\" cy=\"2\" r=\"1.5\" />\n <circle cx=\"2\" cy=\"7\" r=\"1.5\" />\n <circle cx=\"8\" cy=\"7\" r=\"1.5\" />\n <circle cx=\"2\" cy=\"12\" r=\"1.5\" />\n <circle cx=\"8\" cy=\"12\" r=\"1.5\" />\n </svg>\n);\n\nconst ChevronRightIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n);\n\n// ---------------------------------------------------------------------------\n// HierarchyButton — Single button with left/right arrows for hierarchy navigation\n// ---------------------------------------------------------------------------\ninterface HierarchyButtonProps {\n /** Whether the task is a child (can be promoted) */\n isChild: boolean;\n /** Row index - first row cannot demote */\n rowIndex: number;\n /** Callback when promote is clicked (left arrow) */\n onPromote?: (e: React.MouseEvent) => void;\n /** Callback when demote is clicked (right arrow) */\n onDemote?: (e: React.MouseEvent) => void;\n}\n\nconst ArrowLeft = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m12 19-7-7 7-7\" />\n <path d=\"M19 12H5\" />\n </svg>\n);\n\nconst ArrowRight = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M5 12h14\" />\n <path d=\"m12 5 7 7-7 7\" />\n </svg>\n);\n\nconst HierarchyButton: React.FC<HierarchyButtonProps> = ({\n isChild,\n rowIndex: _rowIndex,\n onPromote,\n onDemote,\n}) => {\n const canPromote = isChild && onPromote;\n // Demote is always allowed when the callback is provided.\n // rowIndex === 0 is handled upstream: clicking Demote on the first task\n // triggers \"Новый раздел\" parent creation (not blocked here).\n const canDemote = !!onDemote;\n\n if (!canPromote && !canDemote) return null;\n\n return (\n <>\n {canPromote && (\n <button\n type=\"button\"\n className=\"gantt-tl-name-action-btn gantt-tl-action-hierarchy\"\n onClick={(e) => {\n e.stopPropagation();\n onPromote!(e);\n }}\n title=\"Повысить уровень\"\n >\n <ArrowLeft />\n </button>\n )}\n {canDemote && (\n <button\n type=\"button\"\n className=\"gantt-tl-name-action-btn gantt-tl-action-hierarchy\"\n onClick={(e) => {\n e.stopPropagation();\n onDemote!(e);\n }}\n title=\"Понизить уровень\"\n >\n <ArrowRight />\n </button>\n )}\n </>\n );\n};\n\nfunction formatDepDescription(type: LinkType, lag: number | undefined): string {\n const effectiveLag = lag ?? 0;\n\n if (type === \"FS\") {\n if (effectiveLag > 0)\n return `Начать через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0)\n return `Начать за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Начать сразу после окончания`;\n }\n if (type === \"FF\") {\n if (effectiveLag > 0)\n return `Завершить через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0)\n return `Завершить за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Завершить после окончания`;\n }\n if (type === \"SS\") {\n if (effectiveLag > 0)\n return `Начать через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0)\n return `Начать за ${Math.abs(effectiveLag)} дн. до начала`;\n return `Начать вместе с началом`;\n }\n if (type === \"SF\") {\n if (effectiveLag > 0)\n return `Завершить через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0)\n return `Завершить за ${Math.abs(effectiveLag)} дн. до начала`;\n return `Завершить до начала`;\n }\n return \"\";\n}\n\nconst DepChip: React.FC<DepChipProps> = ({\n lag,\n dep,\n taskId,\n predecessorName,\n selectedChip,\n disableDependencyEditing,\n onChipSelect,\n onRowClick,\n onScrollToTask,\n onRemoveDependency,\n onChipSelectClear,\n task,\n allTasks,\n onTasksChange,\n}) => {\n const [popoverOpen, setPopoverOpen] = useState(false);\n const lagAbs = Math.abs(lag ?? 0);\n const [inputAbs, setInputAbs] = useState(lagAbs === 0 ? \"\" : String(lagAbs));\n useEffect(() => {\n const abs = Math.abs(lag ?? 0);\n setInputAbs(abs === 0 ? \"\" : String(abs));\n }, [lag]);\n\n const isSelected =\n selectedChip?.successorId === taskId &&\n selectedChip?.predecessorId === dep.taskId &&\n selectedChip?.linkType === dep.type;\n\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (disableDependencyEditing) return;\n // Toggle popover and chip selection together\n const nextOpen = !popoverOpen;\n setPopoverOpen(nextOpen);\n if (nextOpen) {\n onChipSelect?.({\n successorId: taskId,\n predecessorId: dep.taskId,\n linkType: dep.type,\n });\n onScrollToTask?.(dep.taskId);\n } else {\n // Only clear selection when explicitly closing via chip click\n onChipSelect?.(null);\n }\n };\n\n const handleOpenChange = useCallback(\n (open: boolean) => {\n setPopoverOpen(open);\n // Don't clear selectedChip on automatic popover close (e.g. focus loss, escape)\n // Only clear when user explicitly closes via chip click or trash button\n },\n [],\n );\n\n const handleTrashClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onRemoveDependency?.(taskId, dep.taskId, dep.type);\n onChipSelectClear();\n setPopoverOpen(false);\n };\n\n const handleLagChange = useCallback(\n (newLag: number) => {\n if (!onTasksChange || !allTasks) return;\n const taskById = new Map(allTasks.map((t) => [t.id, t]));\n const predecessor = taskById.get(dep.taskId);\n if (!predecessor) return;\n\n const predStart = parseUTCDate(predecessor.startDate);\n const predEnd = parseUTCDate(predecessor.endDate);\n const origStart = parseUTCDate(task.startDate);\n const origEnd = parseUTCDate(task.endDate);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n const constraintDate = calculateSuccessorDate(\n predStart,\n predEnd,\n dep.type,\n newLag,\n );\n\n let newStart: Date, newEnd: Date;\n if (dep.type === \"FS\" || dep.type === \"SS\") {\n newStart = constraintDate;\n newEnd = new Date(constraintDate.getTime() + durationMs);\n } else {\n newEnd = constraintDate;\n newStart = new Date(constraintDate.getTime() - durationMs);\n }\n\n onTasksChange([\n {\n ...task,\n startDate: newStart.toISOString().split(\"T\")[0],\n endDate: newEnd.toISOString().split(\"T\")[0],\n },\n ]);\n },\n [dep, task, allTasks, onTasksChange],\n );\n\n const handleInputCommit = useCallback(\n (raw: string) => {\n if (raw === \"\") {\n handleLagChange(0);\n return;\n }\n const parsed = parseInt(raw, 10);\n const effectiveLag = lag ?? 0;\n if (isNaN(parsed)) {\n const abs = Math.abs(effectiveLag);\n setInputAbs(abs === 0 ? \"\" : String(abs));\n return;\n }\n let newLag: number;\n if (parsed === 0) {\n newLag = 0;\n } else if (dep.type === \"SF\") {\n newLag = -Math.abs(parsed);\n } else {\n // sign comes from what the user typed: \"-4\" → negative, \"4\" → positive\n newLag = parsed; // parseInt preserves the sign from input\n }\n if (newLag !== effectiveLag) handleLagChange(newLag);\n },\n [lag, dep.type, handleLagChange],\n );\n\n const Icon = LINK_TYPE_ICONS[dep.type];\n const depName = predecessorName ?? dep.taskId;\n const effectiveLag = lag ?? 0;\n\n // Derive action verb, preWord and afterWhat (sign-dependent for FS/FF/SS)\n const actionVerb =\n dep.type === \"FS\" || dep.type === \"SS\" ? \"начать\" : \"завершить\";\n const zeroPlaceholder =\n dep.type === \"SF\"\n ? \"чётко\"\n : dep.type === \"FF\"\n ? \"вместе\"\n : dep.type === \"SS\"\n ? \"вместе\"\n : \"сразу\";\n let afterWhat: string;\n let preWord: string | null = null;\n if (dep.type === \"SF\") {\n afterWhat = \"до начала\";\n if (effectiveLag > 0) preWord = \"через\";\n else if (effectiveLag < 0) preWord = \"за\";\n } else if (dep.type === \"SS\") {\n afterWhat =\n effectiveLag < 0\n ? \"до начала\"\n : effectiveLag === 0\n ? \"с началом\"\n : \"после начала\";\n if (effectiveLag > 0) preWord = \"через\";\n else if (effectiveLag < 0) preWord = \"за\";\n } else {\n // FS, FF\n if (effectiveLag > 0) {\n preWord = \"через\";\n afterWhat = \"после окончания\";\n } else if (effectiveLag < 0) {\n preWord = \"за\";\n afterWhat = \"до окончания\";\n } else {\n afterWhat = \"после окончания\";\n }\n }\n\n return (\n <Popover open={popoverOpen} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <span\n className={`gantt-tl-dep-chip${isSelected ? \" gantt-tl-dep-chip-selected\" : \"\"}`}\n onClick={handleClick}\n >\n <Icon />\n {effectiveLag !== 0\n ? effectiveLag > 0\n ? `+${effectiveLag}`\n : `${effectiveLag}`\n : \"\"}\n </span>\n </PopoverTrigger>\n <PopoverContent\n className=\"gantt-tl-dep-edit-popover\"\n portal={true}\n align=\"start\"\n >\n <div onClick={(e) => e.stopPropagation()}>\n <div className=\"gantt-tl-dep-edit-task\">{task.name}</div>\n <div className=\"gantt-tl-dep-edit-row\">\n <span className=\"gantt-tl-dep-edit-label\">\n {actionVerb}\n {preWord ? ` ${preWord}` : \"\"}\n </span>\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-btn\"\n onClick={() => handleLagChange(effectiveLag - 1)}\n >\n −\n </button>\n <input\n type=\"number\"\n className=\"gantt-tl-dep-edit-input\"\n value={inputAbs}\n placeholder={zeroPlaceholder}\n min=\"0\"\n onChange={(e) => setInputAbs(e.target.value)}\n onFocus={(e) => e.target.select()}\n onBlur={(e) => handleInputCommit(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleInputCommit(inputAbs);\n }}\n />\n {!(dep.type === \"SF\" && effectiveLag === 0) && (\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-btn\"\n onClick={() => handleLagChange(effectiveLag + 1)}\n >\n +\n </button>\n )}\n {effectiveLag !== 0 && <span>д.</span>}\n <span>{afterWhat}</span>\n </div>\n <div className=\"gantt-tl-dep-edit-pred\">{depName}</div>\n {!disableDependencyEditing && (\n <>\n <hr className=\"gantt-tl-dep-edit-divider\" />\n <div className=\"gantt-tl-dep-edit-actions\">\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-close\"\n onClick={() => {\n setPopoverOpen(false);\n onChipSelectClear();\n }}\n >\n Закрыть\n </button>\n <button\n type=\"button\"\n className=\"gantt-tl-dep-edit-delete\"\n onClick={handleTrashClick}\n >\n Удалить связь\n </button>\n </div>\n </>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\nexport interface TaskListRowProps {\n /** Task data to render */\n task: Task;\n /** Index of the task row (for display in № column) */\n rowIndex: number;\n /** Hierarchical task number (e.g., \"1.2.3\") */\n taskNumber?: string;\n /** Height of the task row in pixels */\n rowHeight: number;\n /** Callback when task is modified via inline edit. Receives array of changed tasks. */\n onTasksChange?: (tasks: Task[]) => void;\n /** ID of currently selected task */\n selectedTaskId?: string;\n /** Callback when task row is clicked */\n onRowClick?: (taskId: string) => void;\n /** Disable task name editing (default: false) */\n disableTaskNameEditing?: boolean;\n /** Disable dependency editing (default: false) */\n disableDependencyEditing?: boolean;\n /** All tasks (for dependency picker) */\n allTasks?: Task[];\n /** Currently active link type for new dependencies */\n activeLinkType?: LinkType;\n /** Task ID currently in predecessor-picking mode (null if not picking) */\n selectingPredecessorFor?: string | null;\n /** Callback to set the task currently in predecessor-picking mode */\n onSetSelectingPredecessorFor?: (taskId: string | null) => void;\n /** Callback to add a dependency link */\n onAddDependency?: (\n successorTaskId: string,\n predecessorTaskId: string,\n linkType: LinkType,\n ) => void;\n /** Callback to remove a dependency link */\n onRemoveDependency?: (\n taskId: string,\n predecessorTaskId: string,\n linkType: LinkType,\n ) => void;\n /** Currently selected chip (for predecessor-side delete) */\n selectedChip?: {\n successorId: string;\n predecessorId: string;\n linkType: string;\n } | null;\n /** Callback when a chip is clicked (selects it) */\n onChipSelect?: (\n chip: {\n successorId: string;\n predecessorId: string;\n linkType: LinkType;\n } | null,\n ) => void;\n /** Callback to scroll the chart grid to center this task (called when task name is clicked) */\n onScrollToTask?: (taskId: string) => void;\n /** Callback when task is deleted */\n onDelete?: (taskId: string) => void;\n /** Callback when a new task is inserted below this row */\n onAdd?: (task: Task) => void;\n /** Callback when a new task is inserted after this task */\n onInsertAfter?: (taskId: string, newTask: Task) => void;\n /** ID of task that should enter edit mode on mount (for auto-edit after insert) */\n editingTaskId?: string | null;\n /** Whether this row is currently being dragged (shows semi-transparent) */\n isDragging?: boolean;\n /** Whether this row is the current drag-over target (shows top border indicator) */\n isDragOver?: boolean;\n /** Called when drag starts on the handle for this row */\n onDragStart?: (index: number, e: React.DragEvent) => void;\n /** Called when something is dragged over this row */\n onDragOver?: (index: number, e: React.DragEvent) => void;\n /** Called when something is dropped on this row */\n onDrop?: (index: number, e: React.DragEvent) => void;\n /** Called when drag ends (drop or Escape) */\n onDragEnd?: (e: React.DragEvent) => void;\n /** Set of collapsed parent task IDs */\n collapsedParentIds?: Set<string>;\n /** Callback when collapse/expand button is clicked */\n onToggleCollapse?: (parentId: string) => void;\n /** Callback when task is promoted (parentId removed) */\n onPromoteTask?: (taskId: string) => void;\n /** Callback when task is demoted (parentId set to previous task) */\n onDemoteTask?: (taskId: string, newParentId: string) => void;\n /** Whether this child is the last sibling (affects connector icon shape) */\n isLastChild?: boolean;\n /** Nesting depth (0 = root, 1 = child, 2 = grandchild, etc.) */\n nestingDepth?: number;\n /** For each ancestor above the direct parent: true if that ancestor has more siblings below */\n ancestorContinues?: boolean[];\n /** Custom day configurations for date picker */\n customDays?: CustomDayConfig[];\n /** Optional base weekend predicate for date picker */\n isWeekend?: (date: Date) => boolean;\n /** Whether this row matches the active filter highlight */\n isFilterMatch?: boolean;\n}\n\nconst toISODate = (value: string | Date): string => {\n if (value instanceof Date) return value.toISOString().split(\"T\")[0];\n // Handle full ISO strings like \"2026-02-12T00:00:00.000Z\"\n if (typeof value === \"string\" && value.includes(\"T\"))\n return value.split(\"T\")[0];\n return value as string;\n};\n\nexport const TaskListRow: React.FC<TaskListRowProps> = React.memo(\n ({\n task,\n rowIndex,\n taskNumber,\n rowHeight,\n onTasksChange,\n selectedTaskId,\n onRowClick,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n allTasks = [],\n activeLinkType,\n selectingPredecessorFor,\n onSetSelectingPredecessorFor,\n onAddDependency,\n onRemoveDependency,\n selectedChip,\n onChipSelect,\n onScrollToTask,\n onDelete,\n onAdd,\n onInsertAfter,\n editingTaskId,\n isDragging = false,\n isDragOver = false,\n onDragStart,\n onDragOver,\n onDrop,\n onDragEnd,\n collapsedParentIds = new Set(),\n onToggleCollapse,\n onPromoteTask,\n onDemoteTask,\n isLastChild = true,\n nestingDepth = 0,\n ancestorContinues = [],\n customDays,\n isWeekend,\n isFilterMatch = false,\n }) => {\n const [editingName, setEditingName] = useState(false);\n const [nameValue, setNameValue] = useState(\"\");\n const nameInputRef = useRef<HTMLInputElement>(null);\n const [editingDuration, setEditingDuration] = useState(false);\n const [durationValue, setDurationValue] = useState(\n getInclusiveDurationDays(task.startDate, task.endDate),\n );\n const durationInputRef = useRef<HTMLInputElement>(null);\n const [editingProgress, setEditingProgress] = useState(false);\n const [progressValue, setProgressValue] = useState(0);\n const progressInputRef = useRef<HTMLInputElement>(null);\n const [overflowOpen, setOverflowOpen] = useState(false);\n const nameConfirmedRef = useRef(false); // Prevent double-save on Enter + blur\n const durationConfirmedRef = useRef(false); // Prevent double-save on Enter + blur\n const progressConfirmedRef = useRef(false); // Prevent double-save on Enter + blur\n const autoEditedForRef = useRef<string | null>(null); // Track which editingTaskId we already auto-entered for\n const editTriggerRef = useRef<\"keypress\" | \"doubleclick\" | \"autoedit\">(\n \"doubleclick\",\n ); // How editing was started\n const [deletePending, setDeletePending] = useState(false);\n const deleteButtonRef = useRef<HTMLButtonElement>(null);\n\n const isSelected = selectedTaskId === task.id;\n\n // Hierarchy computed values\n const isParent = useMemo(\n () => isTaskParent(task.id, allTasks),\n [task.id, allTasks],\n );\n const isChild = task.parentId !== undefined;\n\n // Create custom weekend predicate from props (memoized for performance)\n const weekendPredicate = useMemo(\n () => createCustomDayPredicate({ customDays, isWeekend }),\n [customDays, isWeekend]\n );\n const isCollapsed = collapsedParentIds.has(task.id);\n\n // Picker mode flags for this row\n const isPicking = selectingPredecessorFor != null;\n const isSourceRow = isPicking && selectingPredecessorFor === task.id;\n\n // Chip data: compute effective lag from actual dates (always correct, even on initial load)\n const chips = useMemo(() => {\n const succStart = new Date(task.startDate as string);\n const succEnd = new Date(task.endDate as string);\n const taskById = new Map((allTasks ?? []).map((t) => [t.id, t]));\n return (task.dependencies ?? []).map((dep) => {\n const pred = taskById.get(dep.taskId);\n const lag = pred\n ? computeLagFromDates(\n dep.type,\n new Date(pred.startDate as string),\n new Date(pred.endDate as string),\n succStart,\n succEnd,\n )\n : (dep.lag ?? 0);\n return { dep, lag, predecessorName: pred?.name ?? dep.taskId };\n });\n }, [task.dependencies, task.startDate, task.endDate, allTasks]);\n\n const linkWord = chips.length <= 4 ? \"связи\" : \"связей\";\n\n useEffect(() => {\n if (editingName && nameInputRef.current) {\n nameInputRef.current.focus();\n if (editTriggerRef.current === \"keypress\") {\n // Cursor to end — the typed char is already in the input, don't select it\n const len = nameInputRef.current.value.length;\n nameInputRef.current.setSelectionRange(len, len);\n } else {\n // Double-click or auto-edit-on-insert: select all for easy replacement\n nameInputRef.current.select();\n }\n }\n }, [editingName]);\n\n // Reset delete confirmation when clicking elsewhere\n useEffect(() => {\n const handleMouseDownOutside = (event: MouseEvent) => {\n if (\n deletePending &&\n deleteButtonRef.current &&\n !deleteButtonRef.current.contains(event.target as Node)\n ) {\n setDeletePending(false);\n }\n };\n\n if (deletePending) {\n document.addEventListener(\"mousedown\", handleMouseDownOutside);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleMouseDownOutside);\n };\n }, [deletePending]);\n\n // Auto-enter edit mode when this task is created via insert.\n // We track which editingTaskId we already reacted to (autoEditedForRef) so that\n // subsequent re-renders caused by saving the name (which changes task.name) do NOT\n // re-trigger edit mode. Without this guard, saving the name → onTasksChange → new task.name\n // → re-render → effect fires again → edit mode re-entered → user must press Enter twice.\n useEffect(() => {\n if (\n editingTaskId === task.id &&\n !disableTaskNameEditing &&\n autoEditedForRef.current !== editingTaskId\n ) {\n autoEditedForRef.current = editingTaskId;\n nameConfirmedRef.current = false; // Reset stale flag from any previous Enter-key save\n editTriggerRef.current = \"autoedit\";\n setNameValue(task.name);\n setEditingName(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editingTaskId, task.id, disableTaskNameEditing]);\n\n const handleNameClick = useCallback(\n (e: React.MouseEvent) => {\n if (disableTaskNameEditing) return;\n e.stopPropagation();\n onRowClick?.(task.id);\n onScrollToTask?.(task.id);\n },\n [task.id, disableTaskNameEditing, onRowClick, onScrollToTask],\n );\n\n const handleNameDoubleClick = useCallback(\n (e: React.MouseEvent) => {\n if (disableTaskNameEditing) return;\n e.stopPropagation();\n nameConfirmedRef.current = false; // Reset stale flag from any previous Enter-key save\n editTriggerRef.current = \"doubleclick\";\n setNameValue(task.name);\n setEditingName(true);\n },\n [task.name, disableTaskNameEditing],\n );\n\n const handleRowKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n // Don't handle row keyboard events when editing progress\n if (editingProgress) return;\n // F2: enter edit mode with cursor at end of existing name\n if (!editingName && !disableTaskNameEditing && e.key === \"F2\") {\n e.preventDefault();\n nameConfirmedRef.current = false; // Reset stale flag from any previous Enter-key save\n editTriggerRef.current = \"keypress\"; // 'keypress' trigger = cursor at end (not select-all)\n setNameValue(task.name);\n setEditingName(true);\n return;\n }\n },\n [editingName, disableTaskNameEditing, task.name],\n );\n\n const handleNameSave = useCallback(() => {\n if (nameConfirmedRef.current) {\n // Already saved via Enter key, skip blur handler\n nameConfirmedRef.current = false;\n return;\n }\n if (nameValue.trim()) {\n onTasksChange?.([{ ...task, name: nameValue.trim() }]);\n }\n setEditingName(false);\n }, [nameValue, task, onTasksChange]);\n\n const handleNameCancel = useCallback(() => {\n setEditingName(false);\n }, []);\n\n const handleNameKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n nameConfirmedRef.current = true; // Mark as saved to prevent blur from triggering again\n if (nameValue.trim()) {\n onTasksChange?.([{ ...task, name: nameValue.trim() }]);\n }\n setEditingName(false);\n } else if (e.key === \"Escape\") {\n handleNameCancel();\n }\n },\n [nameValue, task, onTasksChange, handleNameCancel],\n );\n\n const handleDurationClick = useCallback(\n (e: React.MouseEvent) => {\n if (task.locked) return;\n e.stopPropagation();\n durationConfirmedRef.current = false;\n setDurationValue(\n getInclusiveDurationDays(task.startDate, task.endDate),\n );\n setEditingDuration(true);\n },\n [task.locked, task.startDate, task.endDate],\n );\n\n const applyDurationChange = useCallback((nextDuration: number) => {\n const normalizedDuration = Math.max(1, Math.round(nextDuration) || 1);\n setDurationValue(normalizedDuration);\n }, []);\n\n const handleDurationSave = useCallback(() => {\n if (durationConfirmedRef.current) {\n durationConfirmedRef.current = false;\n return;\n }\n const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);\n onTasksChange?.([\n {\n ...task,\n endDate: getEndDateFromDuration(task.startDate, normalizedDuration),\n },\n ]);\n setEditingDuration(false);\n }, [durationValue, task, onTasksChange]);\n\n const handleDurationCancel = useCallback(() => {\n setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));\n setEditingDuration(false);\n }, [task.startDate, task.endDate]);\n\n const handleDurationAdjust = useCallback(\n (delta: number) => {\n applyDurationChange(durationValue + delta);\n },\n [applyDurationChange, durationValue],\n );\n\n const handleDurationKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (e.key === \"Enter\") {\n durationConfirmedRef.current = true;\n const normalizedDuration = Math.max(\n 1,\n Math.round(durationValue) || 1,\n );\n onTasksChange?.([\n {\n ...task,\n endDate: getEndDateFromDuration(\n task.startDate,\n normalizedDuration,\n ),\n },\n ]);\n setEditingDuration(false);\n } else if (e.key === \"Escape\") {\n handleDurationCancel();\n }\n },\n [durationValue, task, onTasksChange, handleDurationCancel],\n );\n\n const handleProgressClick = useCallback(\n (e: React.MouseEvent) => {\n if (task.locked) return;\n e.stopPropagation();\n progressConfirmedRef.current = false;\n setProgressValue(task.progress ?? 0);\n setEditingProgress(true);\n },\n [task.progress, task.locked],\n );\n\n const handleProgressSave = useCallback(() => {\n if (progressConfirmedRef.current) {\n progressConfirmedRef.current = false;\n return;\n }\n const clampedValue = Math.max(0, Math.min(100, progressValue));\n\n // Cascade 100% or 0% progress to all children when parent is marked complete/reset\n if (\n (clampedValue === 100 || clampedValue === 0) &&\n isTaskParent(task.id, allTasks)\n ) {\n const children = getChildren(task.id, allTasks);\n const updatedTasks = [\n { ...task, progress: clampedValue },\n ...children.map((child) => ({ ...child, progress: clampedValue })),\n ];\n onTasksChange?.(updatedTasks);\n } else {\n onTasksChange?.([{ ...task, progress: clampedValue }]);\n }\n setEditingProgress(false);\n }, [progressValue, task, onTasksChange, allTasks]);\n\n const handleProgressCancel = useCallback(() => {\n setEditingProgress(false);\n }, []);\n\n const handleProgressAdjust = useCallback((delta: number) => {\n setProgressValue((current) =>\n Math.max(0, Math.min(100, current + delta)),\n );\n }, []);\n\n const handleProgressKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n e.stopPropagation(); // Prevent row-level keyboard handler from interfering\n if (e.key === \"Enter\") {\n progressConfirmedRef.current = true;\n const clampedValue = Math.max(0, Math.min(100, progressValue));\n\n // Cascade 100% or 0% progress to all children when parent is marked complete/reset\n if (\n (clampedValue === 100 || clampedValue === 0) &&\n isTaskParent(task.id, allTasks)\n ) {\n const children = getChildren(task.id, allTasks);\n const updatedTasks = [\n { ...task, progress: clampedValue },\n ...children.map((child) => ({\n ...child,\n progress: clampedValue,\n })),\n ];\n onTasksChange?.(updatedTasks);\n } else {\n onTasksChange?.([{ ...task, progress: clampedValue }]);\n }\n setEditingProgress(false);\n } else if (e.key === \"Escape\") {\n handleProgressCancel();\n }\n },\n [progressValue, task, onTasksChange, handleProgressCancel, allTasks],\n );\n\n useEffect(() => {\n if (editingProgress && progressInputRef.current) {\n progressInputRef.current.focus();\n progressInputRef.current.select();\n }\n }, [editingProgress]);\n\n useEffect(() => {\n setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));\n }, [task.startDate, task.endDate]);\n\n useEffect(() => {\n if (editingDuration && durationInputRef.current) {\n durationInputRef.current.focus();\n durationInputRef.current.select();\n }\n }, [editingDuration]);\n\n // Both date pickers shift the whole task (preserving duration), same as drag-move\n // Also normalizes dates to ensure startDate is always before or equal to endDate\n const handleStartDateChange = useCallback(\n (newDateISO: string) => {\n if (!newDateISO) return;\n const origStart = parseUTCDate(task.startDate);\n const origEnd = parseUTCDate(task.endDate);\n const durationMs = origEnd.getTime() - origStart.getTime();\n const newStart = new Date(newDateISO + \"T00:00:00Z\");\n const newEnd = new Date(newStart.getTime() + durationMs);\n const { startDate: normalizedStart, endDate: normalizedEnd } =\n normalizeTaskDates(newDateISO, newEnd.toISOString().split(\"T\")[0]);\n onTasksChange?.([\n { ...task, startDate: normalizedStart, endDate: normalizedEnd },\n ]);\n },\n [task, onTasksChange],\n );\n\n const handleEndDateChange = useCallback(\n (newDateISO: string) => {\n if (!newDateISO) return;\n const origStart = parseUTCDate(task.startDate);\n const origEnd = parseUTCDate(task.endDate);\n const durationMs = origEnd.getTime() - origStart.getTime();\n const newEnd = new Date(newDateISO + \"T00:00:00Z\");\n const newStart = new Date(newEnd.getTime() - durationMs);\n const { startDate: normalizedStart, endDate: normalizedEnd } =\n normalizeTaskDates(newStart.toISOString().split(\"T\")[0], newDateISO);\n onTasksChange?.([\n { ...task, startDate: normalizedStart, endDate: normalizedEnd },\n ]);\n },\n [task, onTasksChange],\n );\n\n const handleRowClickInternal = useCallback(() => {\n onRowClick?.(task.id);\n }, [task.id, onRowClick]);\n\n const handleNumberClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onRowClick?.(task.id);\n },\n [task.id, onRowClick],\n );\n\n const handleToggleCollapse = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onToggleCollapse?.(task.id);\n },\n [task.id, onToggleCollapse],\n );\n\n // Hierarchy handlers - promote/demote\n const handlePromote = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onPromoteTask?.(task.id);\n },\n [task.id, onPromoteTask],\n );\n\n const handleDemote = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n // The parent calculation is done in TaskList.tsx's handleDemoteWrapper,\n // which has access to the ordered visible task list and implements the\n // \"previous visible task becomes parent\" principle.\n // Pass empty string as placeholder — the wrapper ignores this value.\n onDemoteTask?.(task.id, \"\");\n },\n [task.id, onDemoteTask],\n );\n\n // Dependency handlers\n const handleAddClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onSetSelectingPredecessorFor?.(task.id);\n },\n [task.id, onSetSelectingPredecessorFor],\n );\n\n const handlePredecessorPick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!isPicking || isSourceRow) return;\n if (!selectingPredecessorFor || !activeLinkType) return;\n onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);\n },\n [\n isPicking,\n isSourceRow,\n selectingPredecessorFor,\n task.id,\n activeLinkType,\n onAddDependency,\n ],\n );\n\n const handleCancelPicking = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onSetSelectingPredecessorFor?.(null);\n },\n [onSetSelectingPredecessorFor],\n );\n\n // True when this row is the predecessor for the currently selected chip\n const isSelectedPredecessor =\n selectedChip != null && selectedChip.predecessorId === task.id;\n\n // Delete the selected dependency from the predecessor row's \"Удалить\" button\n const handleDeleteSelected = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selectedChip) return;\n onRemoveDependency?.(\n selectedChip.successorId,\n selectedChip.predecessorId,\n selectedChip.linkType as LinkType,\n );\n onChipSelect?.(null);\n },\n [selectedChip?.successorId, selectedChip?.predecessorId, selectedChip?.linkType, onRemoveDependency, onChipSelect],\n );\n\n const startDateISO = toISODate(task.startDate);\n const endDateISO = editingDuration\n ? getEndDateFromDuration(task.startDate, durationValue)\n : toISODate(task.endDate);\n\n return (\n <div\n data-filter-match={isFilterMatch ? 'true' : 'false'}\n className={[\n \"gantt-tl-row\",\n isFilterMatch ? \"gantt-tl-row-filter-match\" : \"\",\n isSelected ? \"gantt-tl-row-selected\" : \"\",\n isPicking && !isSourceRow ? \"gantt-tl-row-picking\" : \"\",\n isSourceRow ? \"gantt-tl-row-picking-self\" : \"\",\n isDragging ? \"gantt-tl-row-dragging\" : \"\",\n isDragOver ? \"gantt-tl-row-drag-over\" : \"\",\n isChild ? \"gantt-tl-row-child\" : \"\",\n isParent ? \"gantt-tl-row-parent\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ minHeight: `${rowHeight}px`, position: \"relative\" }}\n onClick={handleRowClickInternal}\n onKeyDown={handleRowKeyDown}\n onDragOver={(e) => onDragOver?.(rowIndex, e)}\n onDrop={(e) => onDrop?.(rowIndex, e)}\n onMouseLeave={() => {\n if (deletePending) {\n setDeletePending(false);\n }\n }}\n tabIndex={isSelected ? 0 : -1}\n >\n {/* Number column — click selects the row */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-number\"\n onClick={handleNumberClick}\n >\n <span\n className=\"gantt-tl-drag-handle\"\n draggable={true}\n onDragStart={(e) => {\n e.stopPropagation();\n onDragStart?.(rowIndex, e);\n }}\n onDragEnd={(e) => onDragEnd?.(e)}\n onClick={(e) => e.stopPropagation()}\n >\n <DragHandleIcon />\n </span>\n <span className=\"gantt-tl-num-label\">\n {taskNumber || rowIndex + 1}\n </span>\n </div>\n\n {/* Name column — styled Input overlay on edit */}\n <div className=\"gantt-tl-cell gantt-tl-cell-name\">\n {isChild && !editingName && (\n <>\n {/* Ancestor continuation lines — full-height vertical bars for each ongoing ancestor level */}\n {ancestorContinues.map((continues, idx) =>\n continues ? (\n <span\n key={idx}\n style={{\n position: \"absolute\",\n left: `${idx * 20 + 9}px`,\n top: 0,\n height: `${rowHeight}px`,\n width: \"1.5px\",\n background: \"#d4bceb\",\n borderRadius: \"1px\",\n pointerEvents: \"none\",\n }}\n />\n ) : null,\n )}\n {/* Own vline — full height if not last child, half if last (L-shape) */}\n <span\n style={{\n position: \"absolute\",\n left: `${(nestingDepth - 1) * 20 + 9}px`,\n top: 0,\n height: isLastChild ? `${rowHeight / 2}px` : `${rowHeight}px`,\n width: \"1.5px\",\n background: \"#d4bceb\",\n borderRadius: \"1px\",\n pointerEvents: \"none\",\n }}\n />\n {/* Horizontal branch */}\n <span\n style={{\n position: \"absolute\",\n left: `${(nestingDepth - 1) * 20 + 9}px`,\n top: `${rowHeight / 2 - 0.75}px`,\n width: \"8px\",\n height: \"1.5px\",\n background: \"#d4bceb\",\n borderRadius: \"1px\",\n pointerEvents: \"none\",\n }}\n />\n {/* End dot */}\n <span\n style={{\n position: \"absolute\",\n left: `${(nestingDepth - 1) * 20 + 15}px`,\n top: `${rowHeight / 2 - 2}px`,\n width: \"4px\",\n height: \"4px\",\n borderRadius: \"50%\",\n background: \"#d4bceb\",\n pointerEvents: \"none\",\n }}\n />\n </>\n )}\n {isParent && !editingName && (\n <button\n type=\"button\"\n className={`gantt-tl-collapse-btn ${isCollapsed ? \"gantt-tl-collapse-btn-collapsed\" : \"\"}`}\n onClick={handleToggleCollapse}\n style={{ left: `${nestingDepth * 20 + 4}px` }}\n aria-label={isCollapsed ? \"Expand children\" : \"Collapse children\"}\n >\n <ChevronRightIcon />\n </button>\n )}\n {editingName && (\n <Input\n ref={nameInputRef}\n type=\"text\"\n value={nameValue}\n onChange={(e) => setNameValue(e.target.value)}\n onBlur={handleNameSave}\n onKeyDown={handleNameKeyDown}\n className=\"gantt-tl-name-input\"\n style={{\n paddingLeft:\n nestingDepth > 0 ? `${nestingDepth * 20 + 24}px` : undefined,\n }}\n onClick={(e) => e.stopPropagation()}\n />\n )}\n <button\n type=\"button\"\n className={[\n \"gantt-tl-name-trigger\",\n disableTaskNameEditing ? \"gantt-tl-name-locked\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n title={task.name}\n onClick={handleNameClick}\n onDoubleClick={handleNameDoubleClick}\n style={{\n paddingLeft:\n nestingDepth > 0\n ? `${nestingDepth * 20 + (isParent ? 26 : 8)}px`\n : isParent\n ? \"26px\"\n : undefined,\n ...(editingName\n ? { visibility: \"hidden\", pointerEvents: \"none\" }\n : undefined),\n }}\n >\n {task.name}\n </button>\n {!editingName && (\n <div className=\"gantt-tl-name-actions\">\n {onInsertAfter && (\n <button\n type=\"button\"\n className=\"gantt-tl-name-action-btn gantt-tl-action-insert\"\n onClick={(e) => {\n e.stopPropagation();\n const now = new Date();\n const todayISO = new Date(\n Date.UTC(\n now.getUTCFullYear(),\n now.getUTCMonth(),\n now.getUTCDate(),\n ),\n )\n .toISOString()\n .split(\"T\")[0];\n const endISO = new Date(\n Date.UTC(\n now.getUTCFullYear(),\n now.getUTCMonth(),\n now.getUTCDate() + 7,\n ),\n )\n .toISOString()\n .split(\"T\")[0];\n const newTask: Task = {\n id: crypto.randomUUID(),\n name: \"Новая задача\",\n startDate: todayISO,\n endDate: endISO,\n };\n onInsertAfter(task.id, newTask);\n }}\n aria-label=\"Вставить задачу после этой\"\n >\n <PlusIcon />\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n ref={deleteButtonRef}\n className={`gantt-tl-name-action-btn gantt-tl-action-delete${deletePending ? \" gantt-tl-action-delete-confirm\" : \"\"}`}\n onClick={(e) => {\n e.stopPropagation();\n if (!deletePending) {\n setDeletePending(true);\n } else {\n setDeletePending(false);\n onDelete(task.id);\n }\n }}\n aria-label=\"Удалить задачу\"\n >\n {deletePending ? \"Удалить?\" : <TrashIcon />}\n </button>\n )}\n <HierarchyButton\n isChild={isChild}\n rowIndex={rowIndex}\n onPromote={onPromoteTask ? handlePromote : undefined}\n onDemote={onDemoteTask ? handleDemote : undefined}\n />\n </div>\n )}\n </div>\n\n {/* Start Date — DatePicker component */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-date\"\n onClick={(e) => e.stopPropagation()}\n >\n <DatePicker\n value={startDateISO}\n onChange={handleStartDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n isWeekend={weekendPredicate}\n />\n </div>\n\n {/* End Date — DatePicker component */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-date\"\n onClick={(e) => e.stopPropagation()}\n >\n <DatePicker\n value={endDateISO}\n onChange={handleEndDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n isWeekend={weekendPredicate}\n />\n </div>\n\n {/* Duration column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-duration\"\n onClick={handleDurationClick}\n >\n {editingDuration && (\n <div\n className=\"gantt-tl-number-editor\"\n onClick={(e) => e.stopPropagation()}\n >\n <Input\n ref={durationInputRef}\n type=\"number\"\n min={1}\n step={1}\n value={durationValue}\n onChange={(e) =>\n applyDurationChange(parseInt(e.target.value, 10) || 1)\n }\n onBlur={handleDurationSave}\n onKeyDown={handleDurationKeyDown}\n className=\"gantt-tl-number-input\"\n />\n <div className=\"gantt-tl-number-steppers\" aria-hidden=\"true\">\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleDurationAdjust(1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleDurationAdjust(-1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n </div>\n )}\n <span\n style={\n editingDuration\n ? { visibility: \"hidden\", pointerEvents: \"none\" }\n : undefined\n }\n >\n {getInclusiveDurationDays(task.startDate, task.endDate)}д\n </span>\n </div>\n\n {/* Progress column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-progress\"\n onClick={handleProgressClick}\n >\n {editingProgress && (\n <div\n className=\"gantt-tl-number-editor\"\n onClick={(e) => e.stopPropagation()}\n >\n <Input\n ref={progressInputRef}\n type=\"number\"\n min={0}\n max={100}\n step={1}\n value={progressValue}\n onChange={(e) =>\n setProgressValue(parseInt(e.target.value, 10) || 0)\n }\n onBlur={handleProgressSave}\n onKeyDown={handleProgressKeyDown}\n className=\"gantt-tl-number-input\"\n />\n <div className=\"gantt-tl-number-steppers\" aria-hidden=\"true\">\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleProgressAdjust(1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n className=\"gantt-tl-number-stepper\"\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleProgressAdjust(-1)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n </div>\n )}\n <span\n style={\n editingProgress\n ? { visibility: \"hidden\", pointerEvents: \"none\" }\n : task.progress === 100\n ? {\n backgroundColor: \"#17c864\",\n borderRadius: \"4px\",\n padding: \"2px 4px\",\n color: \"#ffffff\",\n }\n : undefined\n }\n >\n {task.progress\n ? Math.round(task.progress) === 100\n ? \"100\"\n : `${Math.round(task.progress)}%`\n : \"-\"}\n </span>\n </div>\n\n {/* Dependencies column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-deps\"\n onClick={\n isSourceRow\n ? handleCancelPicking\n : isPicking\n ? handlePredecessorPick\n : undefined\n }\n >\n {isSourceRow ? (\n <span className=\"gantt-tl-dep-source-hint\">Выберите задачу</span>\n ) : isSelectedPredecessor && !disableDependencyEditing ? (\n /* Full-replacement: \"Зависит от [name]\" → hover → \"Удалить\" */\n <button\n type=\"button\"\n className=\"gantt-tl-dep-delete-label\"\n onClick={handleDeleteSelected}\n aria-label=\"Удалить связь\"\n >\n <span className=\"gantt-tl-dep-delete-label-default\">\n Связано с\n </span>\n <span className=\"gantt-tl-dep-delete-label-hover\">× удалить</span>\n </button>\n ) : (\n <>\n {chips.length >= 2 ? (\n /* 2+ deps — show only \"N связей\" summary chip that opens a popover */\n <Popover open={overflowOpen} onOpenChange={setOverflowOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n className=\"gantt-tl-dep-summary-chip\"\n onClick={(e) => {\n e.stopPropagation();\n setOverflowOpen((v) => !v);\n }}\n >\n {chips.length} {linkWord}\n </button>\n </PopoverTrigger>\n <PopoverContent portal={true} align=\"start\">\n <div\n className=\"gantt-tl-dep-overflow-list\"\n onClick={(e) => e.stopPropagation()}\n >\n {chips.map(({ dep, lag, predecessorName }) => (\n <DepChip\n key={`${dep.taskId}-${dep.type}`}\n lag={lag}\n dep={dep}\n taskId={task.id}\n predecessorName={predecessorName}\n selectedChip={selectedChip}\n disableDependencyEditing={disableDependencyEditing}\n onChipSelect={onChipSelect}\n onRowClick={onRowClick}\n onScrollToTask={onScrollToTask}\n onRemoveDependency={onRemoveDependency}\n onChipSelectClear={() => onChipSelect?.(null)}\n task={task}\n allTasks={allTasks}\n onTasksChange={onTasksChange}\n />\n ))}\n </div>\n </PopoverContent>\n </Popover>\n ) : chips.length === 1 ? (\n /* Single chip — unified DepChip */\n <DepChip\n lag={chips[0].lag}\n dep={chips[0].dep}\n taskId={task.id}\n predecessorName={chips[0].predecessorName}\n selectedChip={selectedChip}\n disableDependencyEditing={disableDependencyEditing}\n onChipSelect={onChipSelect}\n onRowClick={onRowClick}\n onScrollToTask={onScrollToTask}\n onRemoveDependency={onRemoveDependency}\n onChipSelectClear={() => onChipSelect?.(null)}\n task={task}\n allTasks={allTasks}\n onTasksChange={onTasksChange}\n />\n ) : null}\n\n {/* \"+\" add dependency button — hidden in picker mode and when editing disabled, hover-reveal */}\n {!disableDependencyEditing && !isPicking && (\n <button\n type=\"button\"\n className={`gantt-tl-dep-add gantt-tl-dep-add-hover${selectedChip ? \" gantt-tl-dep-add-hidden\" : \"\"}`}\n onClick={handleAddClick}\n aria-label=\"Добавить связь\"\n >\n +\n </button>\n )}\n </>\n )}\n </div>\n </div>\n );\n },\n);\n\nTaskListRow.displayName = \"TaskListRow\";\nexport default TaskListRow;\n","'use client';\n\nimport React from 'react';\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n /** Additional CSS class names */\n className?: string;\n}\n\n/**\n * Styled text input component using gantt-lib CSS variables\n */\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, ...props }, ref) => {\n return (\n <input\n ref={ref}\n className={`gantt-input${className ? ` ${className}` : ''}`}\n {...props}\n />\n );\n }\n);\n\nInput.displayName = 'Input';\nexport default Input;\n","'use client';\n\nimport React, { useState, useCallback, useEffect, useRef } from 'react';\nimport { format, isValid, parse, addDays, addMonths, addYears, subMonths, subYears, subDays } from 'date-fns';\nimport { Calendar } from './Calendar';\nimport { Popover, PopoverTrigger, PopoverContent } from './Popover';\n\nexport interface DatePickerProps {\n /** Current date value as ISO string (YYYY-MM-DD) */\n value?: string;\n /** Callback with new ISO date string (YYYY-MM-DD) when date is selected */\n onChange?: (isoDate: string) => void;\n /** Display format for the input (default: dd.MM.yyyy) */\n format?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether to use portal for popover (default: true) */\n portal?: boolean;\n /** Additional CSS class names for the trigger button */\n className?: string;\n /** Whether the picker is disabled */\n disabled?: boolean;\n /** Optional predicate for custom weekend logic */\n isWeekend?: (date: Date) => boolean;\n}\n\nconst segments = [\n { start: 0, end: 2, label: 'day', max: 31 },\n { start: 3, end: 5, label: 'month', max: 12 },\n { start: 6, end: 8, label: 'year', max: 99 },\n];\n\n/**\n * DatePicker component — shows formatted date as a button, opens calendar popup on click.\n * The popup includes a keyboard-navigable date input field above the calendar.\n * Accepts and returns ISO date strings (YYYY-MM-DD)\n */\nexport const DatePicker: React.FC<DatePickerProps> = ({\n value,\n onChange,\n format: displayFormat = 'dd.MM.yyyy',\n placeholder = 'Pick a date',\n portal = true,\n className,\n disabled = false,\n isWeekend,\n}) => {\n const [open, setOpen] = useState(false);\n const [inputValue, setInputValue] = useState('');\n const dateInputRef = useRef<HTMLInputElement>(null);\n // Refs для синхронного отслеживания позиции — не зависят от DOM/rAF\n const segIdxRef = useRef(0); // текущий сегмент (0=day, 1=month, 2=year)\n const charPosRef = useRef(0); // позиция внутри сегмента (0 или 1)\n\n // Parse ISO string to Date for calendar\n const selectedDate: Date | undefined = (() => {\n if (!value) return undefined;\n const d = new Date(value + 'T00:00:00Z');\n return isValid(d) ? d : undefined;\n })();\n\n // Format Date for display on trigger button\n const displayValue = selectedDate\n ? format(selectedDate, displayFormat)\n : placeholder;\n\n // Sync inputValue with prop value\n useEffect(() => {\n if (value) {\n const d = new Date(value + 'T00:00:00Z');\n if (isValid(d)) setInputValue(format(d, 'dd.MM.yy'));\n } else {\n setInputValue('');\n }\n }, [value]);\n\n // Выделить сегмент по индексу (визуально)\n const selectSegByIdx = useCallback((idx: number) => {\n if (!dateInputRef.current) return;\n const seg = segments[idx] ?? segments[0];\n dateInputRef.current.setSelectionRange(seg.start, seg.end);\n }, []);\n\n // Auto-focus input when popup opens\n useEffect(() => {\n if (open) {\n setTimeout(() => {\n if (dateInputRef.current) {\n segIdxRef.current = 0;\n charPosRef.current = 0;\n dateInputRef.current.focus();\n selectSegByIdx(0);\n }\n }, 50);\n }\n }, [open, selectSegByIdx]);\n\n const handleFocus = () => {\n setTimeout(() => {\n segIdxRef.current = 0;\n charPosRef.current = 0;\n selectSegByIdx(0);\n }, 0);\n };\n\n const handleMouseDown = () => {\n setTimeout(() => {\n const pos = dateInputRef.current?.selectionStart ?? 0;\n const idx = segments.findIndex(s => pos >= s.start && pos <= s.end);\n segIdxRef.current = idx >= 0 ? idx : 0;\n charPosRef.current = 0;\n selectSegByIdx(segIdxRef.current);\n }, 0);\n };\n\n const updateFromDate = useCallback((newDate: Date) => {\n if (!isValid(newDate)) return;\n setInputValue(format(newDate, 'dd.MM.yy'));\n const iso = [\n newDate.getFullYear(),\n String(newDate.getMonth() + 1).padStart(2, '0'),\n String(newDate.getDate()).padStart(2, '0'),\n ].join('-');\n onChange?.(iso);\n }, [onChange]);\n\n const handleCalendarSelect = useCallback(\n (day: Date) => {\n updateFromDate(day);\n setOpen(false);\n },\n [updateFromDate]\n );\n\n const handleDayShift = useCallback(\n (delta: number) => {\n const base = selectedDate ?? new Date();\n updateFromDate(addDays(base, delta));\n },\n [selectedDate, updateFromDate]\n );\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!dateInputRef.current) return;\n const { value: inputVal } = dateInputRef.current;\n\n // Читаем сегмент из рефа — всегда актуально, даже при быстром вводе\n const segIdx = segIdxRef.current;\n const seg = segments[segIdx] ?? segments[0];\n\n if (e.key === 'Tab') return;\n\n if (e.key === 'Escape') {\n e.preventDefault(); e.stopPropagation();\n setOpen(false);\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault(); e.stopPropagation();\n setOpen(false);\n return;\n }\n\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault(); e.stopPropagation();\n const base = selectedDate ?? new Date();\n let newDate = base;\n if (seg.label === 'day') newDate = e.key === 'ArrowUp' ? addDays(base, 1) : subDays(base, 1);\n if (seg.label === 'month') newDate = e.key === 'ArrowUp' ? addMonths(base, 1) : subMonths(base, 1);\n if (seg.label === 'year') newDate = e.key === 'ArrowUp' ? addYears(base, 1) : subYears(base, 1);\n charPosRef.current = 0;\n updateFromDate(newDate);\n requestAnimationFrame(() => selectSegByIdx(segIdx));\n return;\n }\n\n if (e.key === 'Backspace' || e.key === 'Delete') {\n e.preventDefault(); e.stopPropagation();\n const chars = inputVal.split('');\n for (let i = seg.start; i < seg.end; i++) chars[i] = '0';\n charPosRef.current = 0;\n setInputValue(chars.join(''));\n requestAnimationFrame(() => selectSegByIdx(segIdx));\n return;\n }\n\n if (e.key === 'ArrowRight') {\n e.preventDefault(); e.stopPropagation();\n const next = segIdx + 1 < segments.length ? segIdx + 1 : 0;\n segIdxRef.current = next;\n charPosRef.current = 0;\n selectSegByIdx(next);\n return;\n }\n\n if (e.key === 'ArrowLeft') {\n e.preventDefault(); e.stopPropagation();\n const prev = segIdx - 1 >= 0 ? segIdx - 1 : segments.length - 1;\n segIdxRef.current = prev;\n charPosRef.current = 0;\n selectSegByIdx(prev);\n return;\n }\n\n if (/^\\d$/.test(e.key)) {\n e.preventDefault(); e.stopPropagation();\n const charPos = charPosRef.current;\n const charIndex = seg.start + charPos;\n const chars = inputVal.split('');\n\n // На первой позиции сегмента — сбрасываем вторую цифру\n if (charPos === 0) {\n for (let i = seg.start + 1; i < seg.end; i++) chars[i] = '0';\n }\n chars[charIndex] = e.key;\n\n const segStr = chars.slice(seg.start, seg.end).join('');\n const segVal = parseInt(segStr, 10);\n\n if (seg.label === 'month' && charPos === 0 && parseInt(e.key) > 1) return;\n if (seg.label === 'day' && charPos === 0 && parseInt(e.key) > 3) return;\n if (segVal > seg.max) return;\n\n const updated = chars.join('');\n setInputValue(updated);\n\n const segLen = seg.end - seg.start;\n if (charPos + 1 < segLen) {\n // Ещё не заполнили сегмент — двигаемся внутри\n charPosRef.current = charPos + 1;\n requestAnimationFrame(() => {\n dateInputRef.current?.setSelectionRange(charIndex + 1, seg.end);\n });\n } else {\n // Сегмент заполнен — переходим к следующему\n const nextIdx = segIdx + 1 < segments.length ? segIdx + 1 : segIdx;\n segIdxRef.current = nextIdx;\n charPosRef.current = 0;\n requestAnimationFrame(() => selectSegByIdx(nextIdx));\n }\n\n const parsed = parse(updated, 'dd.MM.yy', new Date());\n if (isValid(parsed) && !updated.includes('00.00')) {\n updateFromDate(parsed);\n }\n }\n }, [selectedDate, updateFromDate, selectSegByIdx]);\n\n return (\n <Popover open={open} onOpenChange={disabled ? undefined : setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n className={`gantt-datepicker-trigger${className ? ` ${className}` : ''}`}\n disabled={disabled}\n onClick={(e) => {\n e.stopPropagation();\n }}\n >\n {displayValue}\n </button>\n </PopoverTrigger>\n <PopoverContent\n portal={portal}\n align=\"start\"\n side=\"bottom\"\n >\n <div className=\"gantt-datepicker-input-row\">\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(-7)} tabIndex={-1}>-7</button>\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(-1)} tabIndex={-1}>-1</button>\n <input\n ref={dateInputRef}\n type=\"text\"\n className=\"gantt-datepicker-date-input\"\n value={inputValue}\n onChange={() => {}}\n onFocus={handleFocus}\n onMouseDown={handleMouseDown}\n onKeyDown={handleKeyDown}\n spellCheck={false}\n autoComplete=\"off\"\n />\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(1)} tabIndex={-1}>+1</button>\n <button type=\"button\" className=\"gantt-datepicker-shift-btn\" onClick={() => handleDayShift(7)} tabIndex={-1}>+7</button>\n </div>\n <Calendar\n mode=\"single\"\n selected={selectedDate}\n onSelect={handleCalendarSelect}\n initialDate={selectedDate}\n isWeekend={isWeekend}\n />\n </PopoverContent>\n </Popover>\n );\n};\n\nDatePicker.displayName = 'DatePicker';\nexport default DatePicker;\n","'use client';\n\nimport React, {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n} from 'react';\nimport {\n startOfMonth,\n getDaysInMonth,\n format,\n addMonths,\n subMonths,\n isSameDay,\n getDay,\n isToday,\n isWeekend,\n isBefore,\n startOfDay,\n} from 'date-fns';\nimport { ru } from 'date-fns/locale';\nimport { createCustomDayPredicate } from '../../utils/dateUtils';\n\nexport interface CalendarProps {\n selected?: Date;\n onSelect?: (date: Date) => void;\n initialDate?: Date;\n mode?: 'single' | 'range';\n disabled?: boolean;\n /** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */\n isWeekend?: (date: Date) => boolean;\n}\n\n\nfunction getDayClassName(\n day: Date,\n selected: Date | undefined,\n isWeekendProp?: (date: Date) => boolean\n): string {\n const classes: string[] = ['gantt-day-btn'];\n\n if (selected && isSameDay(day, selected)) classes.push('selected');\n if (isToday(day)) classes.push('today');\n // Use custom predicate if provided, otherwise default\n if (isWeekendProp ? isWeekendProp(day) : isWeekend(day)) classes.push('weekend');\n if (isBefore(day, startOfDay(new Date())) && !isToday(day)) classes.push('past');\n\n return classes.join(' ');\n}\n\nexport const Calendar: React.FC<CalendarProps> = ({\n selected,\n onSelect,\n initialDate,\n mode = 'single',\n disabled = false,\n isWeekend: isWeekendProp,\n}) => {\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const initialMonth = useMemo(\n () => startOfMonth(initialDate ?? selected ?? new Date()),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const [months, setMonths] = useState<Date[]>(() => [\n subMonths(initialMonth, 1),\n initialMonth,\n addMonths(initialMonth, 1),\n ]);\n\n const loadMoreMonths = useCallback((direction: 'up' | 'down') => {\n setMonths((prev) => {\n if (direction === 'up') {\n return [subMonths(prev[0], 1), ...prev];\n } else {\n return [...prev, addMonths(prev[prev.length - 1], 1)];\n }\n });\n }, []);\n\n useEffect(() => {\n const container = scrollRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n if (container.scrollTop <= 100) {\n const prevScrollHeight = container.scrollHeight;\n const prevScrollTop = container.scrollTop;\n loadMoreMonths('up');\n setTimeout(() => {\n container.scrollTop =\n container.scrollHeight - prevScrollHeight + prevScrollTop;\n }, 0);\n } else if (\n container.scrollTop + container.clientHeight >=\n container.scrollHeight - 100\n ) {\n loadMoreMonths('down');\n }\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [loadMoreMonths]);\n\n // Scroll to the selected/initial month on mount\n useEffect(() => {\n if (!scrollRef.current) return;\n const target = selected ?? initialDate ?? new Date();\n const monthKey = format(startOfMonth(target), 'yyyy-MM');\n const el = scrollRef.current.querySelector(`[data-month=\"${monthKey}\"]`);\n if (el) {\n (el as HTMLElement).scrollIntoView({ behavior: 'auto', block: 'start' });\n }\n // Run once on mount only\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const renderMonth = useCallback(\n (month: Date) => {\n const firstDay = startOfMonth(month);\n const totalDays = getDaysInMonth(month);\n // Monday-first: Sunday (0) -> 6, Monday (1) -> 0, ...\n const emptyDays = (getDay(firstDay) + 6) % 7;\n const monthKey = format(month, 'yyyy-MM');\n const monthLabel = format(month, 'LLLL yyyy', { locale: ru });\n\n // Day of week headers (Monday-first)\n const weekdayLabels = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];\n const weekdayHeaders = weekdayLabels.map((label, i) => (\n <div key={`wd-${i}`} className=\"gantt-cal-weekday\">\n {label}\n </div>\n ));\n\n const emptyCells = Array.from({ length: emptyDays }, (_, i) => (\n <div key={`e-${i}`} className=\"gantt-cal-empty-day\" />\n ));\n\n const dayCells = Array.from({ length: totalDays }, (_, i) => {\n const dayNum = i + 1;\n const day = new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum));\n const className = getDayClassName(day, selected, isWeekendProp);\n return (\n <button\n key={dayNum}\n type=\"button\"\n className={className}\n disabled={disabled}\n onClick={() => {\n if (!disabled && onSelect) {\n onSelect(new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum)));\n }\n }}\n >\n {dayNum}\n </button>\n );\n });\n\n return (\n <div key={monthKey} className=\"gantt-cal-month\" data-month={monthKey}>\n <div className=\"gantt-cal-month-header\">{monthLabel}</div>\n <div className=\"gantt-cal-month-days\">\n {weekdayHeaders}\n {emptyCells}\n {dayCells}\n </div>\n </div>\n );\n },\n [selected, onSelect, disabled, isWeekendProp]\n );\n\n const renderedMonths = useMemo(\n () => months.map(renderMonth),\n [months, renderMonth]\n );\n\n return (\n <div ref={scrollRef} className=\"gantt-cal-container\">\n {renderedMonths}\n </div>\n );\n};\n\nCalendar.displayName = 'Calendar';\nexport default Calendar;\n","import React from 'react';\nimport type { LinkType } from '../../types';\n\nconst DepIconFS = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m10 15 5 5 5-5\" /><path d=\"M4 4h7a4 4 0 0 1 4 4v12\" />\n </svg>\n);\n\nconst DepIconSS = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M3 5v14\" /><path d=\"M21 12H7\" /><path d=\"m15 18 6-6-6-6\" />\n </svg>\n);\n\nconst DepIconFF = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M17 12H3\" /><path d=\"m11 18 6-6-6-6\" /><path d=\"M21 5v14\" />\n </svg>\n);\n\nconst DepIconSF = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m14 15-5 5-5-5\" /><path d=\"M20 4h-7a4 4 0 0 0-4 4v12\" />\n </svg>\n);\n\nexport const LINK_TYPE_ICONS: Record<LinkType, React.FC> = {\n FS: DepIconFS,\n SS: DepIconSS,\n FF: DepIconFF,\n SF: DepIconSF,\n};\n\nexport const LINK_TYPE_LABELS: Record<LinkType, string> = {\n FS: 'Окончание-начало',\n SS: 'Начало-начало',\n FF: 'Окончание-окончание',\n SF: 'Начало-окончание',\n};\n","'use client';\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { Input } from '../ui/Input';\n\ninterface NewTaskRowProps {\n rowHeight: number;\n onConfirm: (name: string) => void;\n onCancel: () => void;\n}\n\nexport const NewTaskRow: React.FC<NewTaskRowProps> = ({ rowHeight, onConfirm, onCancel }) => {\n const [nameValue, setNameValue] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n const confirmedRef = useRef(false);\n\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, []);\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n if (nameValue.trim()) {\n confirmedRef.current = true;\n onConfirm(nameValue.trim());\n } else {\n onCancel();\n }\n } else if (e.key === 'Escape') {\n onCancel();\n }\n };\n\n const handleBlur = () => {\n if (confirmedRef.current) return; // already confirmed via Enter\n if (nameValue.trim()) {\n confirmedRef.current = true;\n onConfirm(nameValue.trim());\n } else {\n onCancel();\n }\n };\n\n return (\n <div className=\"gantt-tl-row gantt-tl-row-new\" style={{ minHeight: `${rowHeight}px` }}>\n <div className=\"gantt-tl-cell gantt-tl-cell-number\" />\n <div className=\"gantt-tl-cell gantt-tl-cell-name gantt-tl-cell-new-name\">\n <Input\n ref={inputRef}\n value={nameValue}\n onChange={(e) => setNameValue(e.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n placeholder=\"Название\"\n className=\"gantt-tl-name-input\"\n />\n </div>\n <div className=\"gantt-tl-cell\" />\n <div className=\"gantt-tl-cell\" />\n <div className=\"gantt-tl-cell\" />\n </div>\n );\n};\n\nexport default NewTaskRow;\n","'use client';\n\nimport React from 'react';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual variant */\n variant?: 'default' | 'ghost' | 'outline';\n /** Size variant */\n size?: 'default' | 'sm' | 'icon';\n /** Additional CSS class names */\n className?: string;\n}\n\n/**\n * Simple button component for calendar navigation and UI actions\n */\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', children, ...props }, ref) => {\n const classes = [\n 'gantt-btn',\n variant !== 'default' ? `gantt-btn-${variant}` : '',\n size !== 'default' ? `gantt-btn-${size}` : '',\n className || '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <button ref={ref} className={classes} {...props}>\n {children}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\nexport default Button;\n","// Utility functions barrel export\nexport * from './dateUtils';\nexport * from './dependencyUtils';\nexport * from './expired';\nexport * from './geometry';\nexport * from './hierarchyOrder';\nexport * from './taskListReorder';\n","import { Task } from '../types';\nimport { parseUTCDate } from '../utils/dateUtils';\nimport { isTaskExpired } from '../utils/expired';\n\n/**\n * Predicate function for filtering tasks\n * @param task - Task to evaluate\n * @returns true to include task in filtered results, false to exclude\n */\nexport type TaskPredicate = (task: Task | undefined) => boolean;\n\n/**\n * Combine predicates with AND logic — all must be true\n * @param predicates - Array of predicate functions\n * @returns Composite predicate that returns true only if all predicates return true\n */\nexport const and = (...predicates: TaskPredicate[]): TaskPredicate =>\n (task) => predicates.every(p => p(task));\n\n/**\n * Combine predicates with OR logic — at least one must be true\n * @param predicates - Array of predicate functions\n * @returns Composite predicate that returns true if any predicate returns true\n */\nexport const or = (...predicates: TaskPredicate[]): TaskPredicate =>\n (task) => predicates.some(p => p(task));\n\n/**\n * Invert a predicate's logic\n * @param predicate - Predicate function to invert\n * @returns Composite predicate that returns the opposite of the input predicate\n */\nexport const not = (predicate: TaskPredicate): TaskPredicate =>\n (task) => !predicate(task);\n\n/**\n * Filter tasks that have no dependencies\n * @returns Predicate that returns true for tasks without dependencies array or with empty array\n */\nexport const withoutDeps = (): TaskPredicate =>\n (task) => !!task && (!task.dependencies || task.dependencies.length === 0);\n\n/**\n * Filter expired (overdue) tasks\n * @param referenceDate - Date to compare against (default: now)\n * @returns Predicate that returns true for tasks ending before reference date\n */\nexport const expired = (referenceDate: Date = new Date()): TaskPredicate =>\n (task) => isTaskExpired(task, referenceDate);\n\n/**\n * Filter tasks that intersect with a date range\n * Task intersects if: taskStart <= rangeEnd && taskEnd >= rangeStart\n * @param rangeStart - Start of the date range\n * @param rangeEnd - End of the date range\n * @returns Predicate that returns true for tasks intersecting the range\n */\nexport const inDateRange = (rangeStart: Date, rangeEnd: Date): TaskPredicate =>\n (task) => {\n if (!task) return false;\n const taskStart = parseUTCDate(task.startDate);\n const taskEnd = parseUTCDate(task.endDate);\n return taskStart.getTime() <= rangeEnd.getTime() && taskEnd.getTime() >= rangeStart.getTime();\n };\n\n/**\n * Filter tasks by progress value range\n * @param min - Minimum progress value (0-100)\n * @param max - Maximum progress value (0-100)\n * @returns Predicate that returns true for tasks with progress in [min, max] range\n */\nexport const progressInRange = (min: number, max: number): TaskPredicate =>\n (task) => {\n if (!task) return false;\n const progress = task.progress ?? 0;\n return progress >= min && progress <= max;\n };\n\n/**\n * Filter tasks by name substring search\n * @param substring - Text to search for in task name\n * @param caseSensitive - If false (default), search is case-insensitive\n * @returns Predicate that returns true for tasks with substring in name\n */\nexport const nameContains = (substring: string, caseSensitive = false): TaskPredicate =>\n (task) => {\n if (!task) return false;\n const name = task.name;\n const search = caseSensitive ? substring : substring.toLowerCase();\n const target = caseSensitive ? name : name.toLowerCase();\n return target.includes(search);\n };\n"],"mappings":"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","names":["startOfMonth","import_react","DAY_MS","import_react","isWeekend","getWeekBlocks","import_react","dayWidth","getUTCDayDifference","currentTask","import_jsx_runtime","React","import_react","import_jsx_runtime","import_react","import_jsx_runtime","arePropsEqual","React","import_jsx_runtime","import_react","import_jsx_runtime","React","lines","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","React","import_react","import_date_fns","import_react","import_date_fns","import_locale","import_jsx_runtime","import_jsx_runtime","isWeekend","import_jsx_runtime","import_jsx_runtime","DAY_MS","effectiveLag","React","isWeekend","import_react","import_jsx_runtime","import_jsx_runtime","getAllDescendants","isWeekend","tasks","React","import_jsx_runtime","isWeekend","tasks","import_react","import_jsx_runtime","React"]}