gantt-lib 0.2.0 → 0.3.2

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/index.ts","../src/components/GanttChart/GanttChart.tsx","../src/utils/dateUtils.ts","../src/utils/dependencyUtils.ts","../src/components/TimeScaleHeader/TimeScaleHeader.tsx","../src/components/TaskRow/TaskRow.tsx","../src/utils/geometry.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/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/ui/Button.tsx"],"sourcesContent":["'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// 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 } from '../../utils/dateUtils';\nimport { calculateGridWidth } from '../../utils/geometry';\nimport { validateDependencies, cascadeByLinks } from '../../utils/dependencyUtils';\nimport type { ValidationResult } from '../../types';\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';\nimport '../TaskList/TaskList.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 /**\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 via drag/resize. Can receive either the new tasks array or a functional updater. */\n onChange?: (tasks: Task[] | ((currentTasks: Task[]) => 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}\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}\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 */\nexport const GanttChart = forwardRef<GanttChartHandle, GanttChartProps>(({\n tasks,\n dayWidth = 40,\n rowHeight = 40,\n headerHeight = 40,\n containerHeight,\n onChange,\n onValidateDependencies,\n enableAutoSchedule,\n disableConstraints,\n onCascade,\n showTaskList = false,\n taskListWidth = 520,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\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\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 // Calculate multi-month date range from tasks\n const dateRange = useMemo(() => getMultiMonthDays(tasks), [tasks]);\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 // Calculate total grid height\n const totalGridHeight = useMemo(\n () => tasks.length * rowHeight,\n [tasks.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 /**\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.scrollLeft = Math.max(0, scrollLeft);\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.scrollLeft = Math.max(0, scrollLeft);\n }, [tasks, dateRange, dayWidth]);\n\n /**\n * Expose scrollToToday and scrollToTask methods to parent component via ref\n */\n useImperativeHandle(\n ref,\n () => ({\n scrollToToday,\n scrollToTask,\n }),\n [scrollToToday, scrollToTask]\n );\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 * Stable callback for task updates\n *\n * FIXED: No longer depends on `tasks` to avoid stale closure bugs.\n * Uses functional state update pattern: the callback receives an updater function\n * that maps over the current tasks state, ensuring we always use the latest state.\n *\n * This prevents the \"reverting\" bug where dragging a second task causes the\n * first task to revert to its original position.\n *\n * To prevent re-render storms during drag:\n * 1. The onChange callback is only called AFTER drag completes (mouseUp)\n * 2. During drag, only the dragged TaskRow re-renders (due to its internal state)\n * 3. Other TaskRows don't re-render because their props haven't changed\n *\n * The React.memo comparison in TaskRow excludes onChange from comparison,\n * relying on the fact that onChange fires only after drag completes.\n */\n const handleTaskChange = useCallback((updatedTask: Task) => {\n // Find original task to detect date changes\n const originalTask = tasks.find(t => t.id === updatedTask.id);\n if (!originalTask) {\n onChange?.((currentTasks) => currentTasks.map(t => t.id === updatedTask.id ? updatedTask : t));\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 // No date change (name edit) or constraints disabled: simple update\n if (!datesChanged || disableConstraints) {\n onChange?.((currentTasks) => currentTasks.map(t => t.id === updatedTask.id ? updatedTask : t));\n return;\n }\n\n // Lags are fixed constraints — preserve as-is, only reposition dates\n const cascadedTask: Task = updatedTask;\n const cascadedChain = cascadeByLinks(updatedTask.id, newStart, newEnd, tasks);\n\n const allCascaded = [cascadedTask, ...cascadedChain];\n onChange?.((currentTasks) => {\n const m = new Map(allCascaded.map(t => [t.id, t]));\n return currentTasks.map(t => m.get(t.id) ?? t);\n });\n onCascade?.(allCascaded);\n }, [tasks, onChange, disableConstraints, onCascade]);\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 — updates all shifted tasks via onChange (functional updater)\n * and notifies the external onCascade consumer.\n */\n const handleCascade = useCallback((cascadedTasks: Task[]) => {\n // Update state by merging cascaded tasks into current tasks\n onChange?.((currentTasks) => {\n const cascadeMap = new Map(cascadedTasks.map(t => [t.id, t]));\n return currentTasks.map(t => cascadeMap.get(t.id) ?? t);\n });\n // Notify external consumer\n onCascade?.(cascadedTasks);\n }, [onChange, onCascade]);\n\n /**\n * Handle task selection from TaskList or TaskRow\n */\n const handleTaskSelect = useCallback((taskId: string | null) => {\n setSelectedTaskId(taskId);\n }, []);\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={tasks}\n rowHeight={rowHeight}\n headerHeight={headerHeight}\n taskListWidth={taskListWidth}\n onTaskChange={handleTaskChange}\n selectedTaskId={selectedTaskId ?? undefined}\n onTaskSelect={handleTaskSelect}\n show={showTaskList}\n disableTaskNameEditing={disableTaskNameEditing}\n disableDependencyEditing={disableDependencyEditing}\n onScrollToTask={scrollToTask}\n onSelectedChipChange={setSelectedChip}\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 />\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 />\n\n {todayInRange && <TodayIndicator monthStart={monthStart} dayWidth={dayWidth} />}\n\n {/* Dependency lines SVG overlay */}\n <DependencyLines\n tasks={tasks}\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 {tasks.map((task, index) => (\n <TaskRow\n key={task.id}\n task={task}\n monthStart={monthStart}\n dayWidth={dayWidth}\n rowHeight={rowHeight}\n onChange={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={tasks}\n enableAutoSchedule={enableAutoSchedule ?? false}\n disableConstraints={disableConstraints ?? false}\n overridePosition={cascadeOverrides.get(task.id)}\n onCascadeProgress={handleCascadeProgress}\n onCascade={handleCascade}\n />\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nGanttChart.displayName = 'GanttChart';\n\nexport default GanttChart;\n","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 (UTC comparison)\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 const today = new Date(Date.UTC(\n now.getUTCFullYear(),\n now.getUTCMonth(),\n now.getUTCDate()\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 * 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","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 * 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): 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 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 const constraintDate = calculateSuccessorDate(predStart, predEnd, dep.type, dep.lag ?? 0);\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 */\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 directSuccessors = getSuccessorChain(changedTaskId, allTasks, firstLevelLinkTypes);\n const chain = [...directSuccessors];\n const visited = new Set<string>([changedTaskId, ...directSuccessors.map(t => t.id)]);\n const queue = [...directSuccessors];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\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","'use client';\n\nimport React, { useMemo } from 'react';\nimport { format } from 'date-fns';\nimport { ru } from 'date-fns/locale';\nimport { getMonthSpans } 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}\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 columns\n * Bottom row: Day numbers (centered) in individual columns\n */\nconst TimeScaleHeader: React.FC<TimeScaleHeaderProps> = ({\n days,\n dayWidth,\n headerHeight,\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 return (\n <div\n className=\"gantt-tsh-header\"\n style={{ height: `${headerHeight}px` }}\n >\n {/* Month row - top */}\n <div\n className=\"gantt-tsh-monthRow\"\n style={{ height: `${rowHeight}px` }}\n >\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 </div>\n\n {/* Day row - bottom */}\n <div\n className=\"gantt-tsh-dayRow\"\n style={{\n height: `${rowHeight}px`,\n gridTemplateColumns: dayGridTemplate,\n }}\n >\n {days.map((day, index) => {\n const isWeekend = day.getDay() === 0 || day.getDay() === 6;\n const prevDay = days[index - 1];\n const isMonthBoundary = index > 0 && prevDay && prevDay.getMonth() !== day.getMonth();\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 ${isWeekend ? 'gantt-tsh-weekendDay' : ''} ${isMonthBoundary ? 'gantt-tsh-monthBoundary' : ''} ${isTodayDate ? 'gantt-tsh-today' : ''}`}>\n <span className=\"gantt-tsh-dayLabel\">{format(day, 'd')}</span>\n </div>\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 { useTaskDrag } from '../../hooks/useTaskDrag';\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 */\n onChange?: (updatedTask: 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}\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: onChange is intentionally excluded from this comparison because:\n * 1. The parent (GanttChart) wraps onChange in useCallback for referential stability\n * 2. onChange 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 onChange —\n * callbacks excluded from comparison because GanttChart wraps them in useCallback).\n *\n * Excluding onChange 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 // onChange, 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, onChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider }) => {\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 // 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 = task.color || 'var(--gantt-task-bar-default-color)';\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 (progressWidth === 100) {\n return task.accepted\n ? 'var(--gantt-progress-accepted, #22c55e)' // Green for accepted\n : 'var(--gantt-progress-completed, #fbbf24)'; // Yellow for completed\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 }, [progressWidth, task.accepted, task.color]);\n\n // Handle drag end - call onChange 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 onChange?.(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 // Determine if progress text fits inside the bar\n // Estimate: duration text (~\"15 д\" = ~30px) + progress text (~\"100%\" = ~30px) + padding (~16px)\n const estimatedTextWidth = durationDays >= 10 ? 76 : 62; // \"15 д 100%\" = ~76px, \"1 д 100%\" = ~62px\n const showProgressInside = progressWidth > 0 && displayWidth > estimatedTextWidth;\n\n return (\n <div\n className=\"gantt-tr-row\"\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' : ''}`}\n style={{\n left: `${displayLeft}px`,\n width: `${displayWidth}px`,\n backgroundColor: barColor,\n height: 'var(--gantt-task-bar-height)',\n cursor: dragHandleProps.style.cursor,\n userSelect: dragHandleProps.style.userSelect,\n }}\n onMouseDown={dragHandleProps.onMouseDown}\n >\n {progressWidth > 0 && (\n <div\n className=\"gantt-tr-progressBar\"\n style={{\n width: `${progressWidth}%`,\n backgroundColor: progressColor,\n }}\n />\n )}\n <div className=\"gantt-tr-resizeHandle gantt-tr-resizeHandleLeft\" />\n <span className=\"gantt-tr-taskDuration\">\n {durationDays} д\n </span>\n {progressWidth > 0 && showProgressInside && (\n <span className=\"gantt-tr-progressText\">\n {progressWidth}%\n </span>\n )}\n <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 + displayWidth}px`,\n }}\n >\n {progressWidth > 0 && !showProgressInside && (\n <span className=\"gantt-tr-externalProgress\">\n {progressWidth}%\n </span>\n )}\n <span className=\"gantt-tr-externalTaskName\">\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 = 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 * @returns Array of weekend block objects with left position and width\n */\nexport const calculateWeekendBlocks = (\n dateRange: Date[],\n dayWidth: number\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 const dayOfWeek = date.getUTCDay();\n const isWeekend = dayOfWeek === 0 || dayOfWeek === 6; // Sunday or Saturday\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 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","'use client';\n\nimport { useEffect, useRef, useState, useCallback } from 'react';\nimport { detectEdgeZone } from '../utils/geometry';\nimport type { Task, TaskDependency, LinkType } from '../types';\nimport { calculateSuccessorDate, getSuccessorChain, getTransitiveCascadeChain, recalculateIncomingLags } 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 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 { startX, initialLeft, initialWidth, mode, dayWidth, onProgress, allTasks } = globalActiveDrag;\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 && !globalActiveDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === globalActiveDrag?.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 = globalActiveDrag.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 globalActiveDrag.monthStart.getUTCFullYear(),\n globalActiveDrag.monthStart.getUTCMonth(),\n globalActiveDrag.monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * globalActiveDrag.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 = globalActiveDrag.initialLeft + globalActiveDrag.initialWidth;\n newWidth = Math.max(globalActiveDrag.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 && !globalActiveDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === globalActiveDrag?.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 = globalActiveDrag.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(globalActiveDrag.monthStart.getUTCFullYear(), globalActiveDrag.monthStart.getUTCMonth(), globalActiveDrag.monthStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * globalActiveDrag.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 + globalActiveDrag.initialWidth;\n if (proposedEndRight > sfBoundaryRight) {\n newLeft = Math.max(globalActiveDrag.initialLeft, sfBoundaryRight - globalActiveDrag.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(globalActiveDrag.dayWidth, sfBoundaryRight - newLeft);\n }\n }\n }\n }\n }\n\n // Phase 9: select chain based on drag mode\n // move: all FS+SS+FF+SF successors follow\n // resize-right: FS+FF successors (endA changes, SS/SF unaffected)\n // resize-left: SS+SF successors only (startA changes, FS/FF unaffected)\n // Phase 10: added SF\n const activeChain =\n mode === 'resize-right' ? globalActiveDrag.cascadeChainEnd : // FS + FF\n mode === 'resize-left' ? globalActiveDrag.cascadeChainStart : // SS + SF\n /* move */ globalActiveDrag.cascadeChain; // FS + SS + FF + SF\n\n // Hard mode cascade: emit position overrides for successor chain members\n if ((mode === 'move' || mode === 'resize-right' ||\n (mode === 'resize-left' && globalActiveDrag.cascadeChainStart.length > 0)) &&\n !globalActiveDrag.disableConstraints &&\n activeChain.length > 0 &&\n globalActiveDrag.onCascadeProgress) {\n // For move/resize-left: delta from left (startA shift)\n // For resize-right: delta from width (endA shift, startA fixed)\n const deltaDays = mode === 'resize-right'\n ? Math.round((newWidth - globalActiveDrag.initialWidth) / globalActiveDrag.dayWidth)\n : Math.round((newLeft - globalActiveDrag.initialLeft) / globalActiveDrag.dayWidth);\n const overrides = new Map<string, { left: number; width: number }>();\n const draggedTaskId = globalActiveDrag.taskId;\n const dayWidth = globalActiveDrag.dayWidth;\n const monthStart = globalActiveDrag.monthStart;\n\n for (const chainTask of activeChain) {\n // Phase 11: locked tasks cannot be moved by cascade\n if (chainTask.locked) continue;\n\n const chainStart = new Date(chainTask.startDate as string);\n const chainEnd = new Date(chainTask.endDate as string);\n const chainStartOffset = Math.round(\n (Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate()) -\n Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const chainEndOffset = Math.round(\n (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) -\n Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const chainDuration = Math.round(\n (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) -\n Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate())\n ) / (24 * 60 * 60 * 1000)\n );\n\n // Phase 9: Check if this chainTask has FF dependency on dragged task\n // For FF tasks, calculate position from end offset (not start offset)\n // This fixes negative lag preview where child starts before parent\n // Phase 10: SF tasks also position from end offset (endB constrained to startA)\n const hasFFDepOnDragged = chainTask.dependencies?.some(\n dep => dep.taskId === draggedTaskId && dep.type === 'FF'\n );\n const hasSFDepOnDragged = chainTask.dependencies?.some(\n dep => dep.taskId === draggedTaskId && dep.type === 'SF'\n );\n\n let chainLeft;\n if (hasFFDepOnDragged || hasSFDepOnDragged) {\n // FF/SF: position based on end date shift, then back up by duration\n // This works correctly even when child starts before parent (negative lag)\n // For SF: endB shifts with startA, then back up by duration\n chainLeft = Math.round((chainEndOffset + deltaDays - chainDuration) * dayWidth);\n } else {\n // FS/SS: position based on start date shift\n chainLeft = Math.round((chainStartOffset + deltaDays) * dayWidth);\n }\n\n const chainWidth = Math.round((chainDuration + 1) * dayWidth); // +1 inclusive\n\n // SS lag floor: when A moves left, B follows but chainLeft cannot go below A's new position\n // This keeps lag >= 0 (startB >= startA) during live drag preview\n // Phase 9: Only apply floor to SS tasks, not FF (FF allows negative lag)\n // Phase 10: SF uses end-based positioning, no floor needed\n const hasSSDepOnDragged = chainTask.dependencies?.some(\n dep => dep.taskId === draggedTaskId && dep.type === 'SS'\n );\n if (hasSSDepOnDragged && (mode === 'move' || mode === 'resize-left')) {\n chainLeft = Math.max(chainLeft, newLeft);\n }\n\n overrides.set(chainTask.id, { left: chainLeft, width: chainWidth });\n }\n globalActiveDrag.onCascadeProgress(overrides);\n }\n\n // Update current values in global state for completion\n globalActiveDrag.currentLeft = newLeft;\n globalActiveDrag.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: compute cascade and call onCascade\n\n // CHANGE C: Dual-delta logic — compute from both start and end date changes\n // Compute delta from startDate change (correct for move and resize-left)\n const origStartMs = Date.UTC(\n initialStartDate.getUTCFullYear(),\n initialStartDate.getUTCMonth(),\n initialStartDate.getUTCDate()\n );\n const newStartMs = Date.UTC(\n newStartDate.getUTCFullYear(),\n newStartDate.getUTCMonth(),\n newStartDate.getUTCDate()\n );\n const deltaFromStart = Math.round((newStartMs - origStartMs) / (24 * 60 * 60 * 1000));\n\n // Compute delta from endDate change (correct for resize-right)\n const origEndMs = Date.UTC(\n initialEndDate.getUTCFullYear(),\n initialEndDate.getUTCMonth(),\n initialEndDate.getUTCDate()\n );\n const newEndMs = Date.UTC(\n newEndDate.getUTCFullYear(),\n newEndDate.getUTCMonth(),\n newEndDate.getUTCDate()\n );\n const deltaFromEnd = Math.round((newEndMs - origEndMs) / (24 * 60 * 60 * 1000));\n\n // For resize-right: startDate unchanged, use endDate delta (FS successors follow end)\n // For move and resize-left: use startDate delta (SS and FS-move successors follow start)\n // Detect resize-right: startDate didn't change\n const deltaDays = deltaFromStart === 0 ? deltaFromEnd : deltaFromStart;\n\n // CHANGE D: Phase 8: get correct chain for completion based on what changed\n // - resize-right (deltaFromStart === 0): only endDate changed → FS successors follow end\n // - resize-left (deltaFromStart !== 0, deltaFromEnd === 0): only startDate changed →\n // SS successors follow start; FS successors are anchored to predecessor's END which\n // is unchanged, so FS successors must NOT cascade on resize-left\n // - move (deltaFromStart !== 0, deltaFromEnd !== 0): both dates shift equally →\n // both FS and SS successors follow\n //\n // FIX: For proper transitive closure in mixed link type chains (e.g., A--FS-->B--SS-->C),\n // we use getTransitiveCascadeChain which includes cascaded tasks' successors regardless of link type.\n // Phase 9: FF included in resize-right and move chains\n const isResizeLeft = deltaFromStart !== 0 && deltaFromEnd === 0;\n const chainForCompletion = deltaFromStart === 0\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS', 'FF']) // resize-right: FS + FF\n : isResizeLeft\n ? getTransitiveCascadeChain(taskId, allTasks, ['SS', 'SF']) // resize-left: SS + SF\n : getTransitiveCascadeChain(taskId, allTasks, ['FS', 'SS', 'FF', 'SF']); // move: all types\n\n if (chainForCompletion.length > 0) {\n const draggedTaskData = allTasks.find(t => t.id === taskId);\n const cascadedTasks: Task[] = [\n {\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 ...chainForCompletion\n .filter(chainTask => !chainTask.locked) // Phase 11: skip locked tasks in cascade\n .map(chainTask => {\n const origStart = new Date(chainTask.startDate as string);\n const origEnd = new Date(chainTask.endDate as string);\n const newStart = new Date(Date.UTC(\n origStart.getUTCFullYear(), origStart.getUTCMonth(), origStart.getUTCDate() + deltaDays\n ));\n const newEnd = new Date(Date.UTC(\n origEnd.getUTCFullYear(), origEnd.getUTCMonth(), origEnd.getUTCDate() + deltaDays\n ));\n return { ...chainTask, startDate: newStart.toISOString(), endDate: newEnd.toISOString() };\n }),\n ];\n onCascade(cascadedTasks);\n return; // Don't call onDragEnd — cascade covers the dragged task too\n }\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 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 // 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 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 } 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}\n\n/**\n * Custom comparison function for React.memo\n *\n * Performance optimization: Only re-renders if dateRange or dayWidth change.\n * totalHeight is excluded because it only affects container height, not grid calculations.\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 // totalHeight changes still trigger update\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\n * - React.memo optimization for performance\n * - Pointer events disabled (clicks pass through to tasks)\n */\nconst GridBackground: React.FC<GridBackgroundProps> = React.memo(\n ({ dateRange, dayWidth, totalHeight }) => {\n // Calculate grid line positions\n const gridLines = useMemo<GridLine[]>(() => {\n return calculateGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth]);\n\n // Calculate weekend background blocks\n const weekendBlocks = useMemo(() => {\n return calculateWeekendBlocks(dateRange, dayWidth);\n }, [dateRange, dayWidth]);\n\n // Calculate total grid width\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) */}\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 {gridLines.map((line, index) => {\n // Determine line type class based on flags\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : line.isWeekStart\n ? 'gantt-gb-weekSeparator'\n : 'gantt-gb-dayLine';\n\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 </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\nexport interface DependencyLinesProps {\n /** All tasks in the chart */\n tasks: Task[];\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 * 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 monthStart,\n dayWidth,\n rowHeight,\n gridWidth,\n dragOverrides,\n selectedDep,\n}) => {\n // Create a lookup map for task positions and their indices\n const { taskPositions, taskIndices } = useMemo(() => {\n const positions = new Map<string, { left: number; right: number; rowTop: number }>();\n const indices = new Map<string, number>();\n\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 });\n });\n\n return { taskPositions: positions, taskIndices: indices };\n }, [tasks, monthStart, dayWidth, rowHeight, dragOverrides]);\n\n // Detect cycles for highlighting\n const cycleInfo = useMemo(() => {\n const result = detectCycles(tasks);\n const cycleTaskIds = new Set(result.cyclePath || []);\n return cycleTaskIds;\n }, [tasks]);\n\n // Calculate all dependency line paths\n const lines = useMemo(() => {\n const edges = getAllDependencyEdges(tasks);\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 }> = [];\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 || predecessorIndex === undefined || successorIndex === undefined) {\n continue; // Skip if task not found (shouldn't happen with validation)\n }\n\n // Determine if tasks are in reverse order (predecessor appears below successor)\n const reverseOrder = predecessorIndex > successorIndex;\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 });\n }\n\n return lines;\n }, [tasks, taskPositions, taskIndices, cycleInfo, monthStart, dayWidth, dragOverrides]);\n\n return (\n <svg\n className=\"gantt-dependencies-svg\"\n width={gridWidth}\n height={tasks.length * rowHeight}\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 }) => {\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\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 { validateDependencies, calculateSuccessorDate } from '../../utils/dependencyUtils';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/Popover';\nimport { TaskListRow } from './TaskListRow';\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'];\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 task is modified via inline edit */\n onTaskChange?: (task: 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 /** 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}\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, 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 = 520,\n onTaskChange,\n selectedTaskId,\n onTaskSelect,\n show = true,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n onScrollToTask,\n onSelectedChipChange,\n}) => {\n const totalHeight = useMemo(\n () => tasks.length * rowHeight,\n [tasks.length, rowHeight]\n );\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 and chip selection\n useEffect(() => {\n if (!selectingPredecessorFor && !selectedChip) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setSelectingPredecessorFor(null);\n setSelectedChip(null);\n onSelectedChipChange?.(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 };\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, 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 onTaskChange?.(snappedTask);\n } else {\n // Predecessor not found — emit without snap (graceful fallback)\n onTaskChange?.(updatedTask);\n }\n\n setSelectingPredecessorFor(null);\n }, [tasks, onTaskChange]);\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 onTaskChange?.({ ...task, dependencies: updatedDeps });\n }, [tasks, onTaskChange]);\n\n return (\n <div\n ref={overlayRef}\n className={`gantt-tl-overlay${show ? '' : ' gantt-tl-hidden'}`}\n style={{ width: `${taskListWidth}px` }}\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 {/* 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 {tasks.map((task, index) => (\n <TaskListRow\n key={task.id}\n task={task}\n rowIndex={index}\n rowHeight={rowHeight}\n onTaskChange={onTaskChange}\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 />\n ))}\n </div>\n </div>\n </div>\n );\n};\n\nexport default TaskList;\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}\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}) => {\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 >\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, { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport type { Task } from '../GanttChart';\nimport type { LinkType } from '../../types';\nimport { parseUTCDate } from '../../utils/dateUtils';\nimport { computeLagFromDates } 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\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}\n\nconst TrashIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\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\nfunction formatDepDescription(type: LinkType, lag: number | undefined): string {\n const effectiveLag = lag ?? 0;\n\n if (type === 'FS') {\n if (effectiveLag > 0) return `Начать через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0) return `Начать за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Начать сразу после окончания`;\n }\n if (type === 'FF') {\n if (effectiveLag > 0) return `Завершить через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0) return `Завершить за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Завершить после окончания`;\n }\n if (type === 'SS') {\n if (effectiveLag > 0) return `Начать через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0) return `Начать за ${Math.abs(effectiveLag)} дн. до начала`;\n return `Начать вместе с началом`;\n }\n if (type === 'SF') {\n if (effectiveLag > 0) return `Завершить через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0) 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}) => {\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 onChipSelect?.(isSelected ? null : { successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });\n if (!isSelected) {\n onRowClick?.(taskId);\n onScrollToTask?.(taskId);\n }\n };\n\n const handleTrashClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onRemoveDependency?.(taskId, dep.taskId, dep.type);\n onChipSelectClear();\n };\n\n const Icon = LINK_TYPE_ICONS[dep.type];\n const depPrefix = formatDepDescription(dep.type, lag);\n const depName = predecessorName ?? dep.taskId;\n\n return (\n <Popover open={isSelected} onOpenChange={(open) => { if (!open) onChipSelectClear(); }}>\n <span className=\"gantt-tl-dep-chip-wrapper\">\n <PopoverTrigger asChild>\n <span\n className={`gantt-tl-dep-chip${isSelected ? ' gantt-tl-dep-chip-selected' : ''}`}\n\n onClick={handleClick}\n >\n <><Icon />{lag != null && lag !== 0 ? (lag > 0 ? `+${lag}` : `${lag}`) : ''}</>\n </span>\n </PopoverTrigger>\n {!disableDependencyEditing && (\n <button\n type=\"button\"\n className=\"gantt-tl-dep-chip-trash\"\n aria-label=\"Удалить связь\"\n onClick={handleTrashClick}\n >\n <TrashIcon />\n </button>\n )}\n </span>\n <PopoverContent portal={true} side=\"bottom\" align=\"start\" className=\"gantt-tl-dep-info-popover\">\n <span className=\"gantt-tl-dep-info-prefix\">{depPrefix}</span>\n <span className=\"gantt-tl-dep-info-name\">{depName}</span>\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 /** Height of the task row in pixels */\n rowHeight: number;\n /** Callback when task is modified via inline edit */\n onTaskChange?: (task: 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?: (successorTaskId: string, predecessorTaskId: string, linkType: LinkType) => void;\n /** Callback to remove a dependency link */\n onRemoveDependency?: (taskId: string, predecessorTaskId: string, linkType: LinkType) => void;\n /** Currently selected chip (for predecessor-side delete) */\n selectedChip?: { successorId: string; predecessorId: string; linkType: string } | null;\n /** Callback when a chip is clicked (selects it) */\n onChipSelect?: (chip: { successorId: string; predecessorId: string; linkType: LinkType } | null) => void;\n /** Callback to scroll the chart grid to center this task (called when № cell is clicked) */\n onScrollToTask?: (taskId: string) => void;\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')) 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 rowHeight,\n onTaskChange,\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 }) => {\n const [editingName, setEditingName] = useState(false);\n const [nameValue, setNameValue] = useState('');\n const nameInputRef = useRef<HTMLInputElement>(null);\n const [overflowOpen, setOverflowOpen] = useState(false);\n\n const isSelected = selectedTaskId === 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 }\n }, [editingName]);\n\n const handleNameClick = useCallback((e: React.MouseEvent) => {\n if (disableTaskNameEditing) return;\n e.stopPropagation();\n setNameValue(task.name);\n setEditingName(true);\n }, [task.name, disableTaskNameEditing]);\n\n const handleNameSave = useCallback(() => {\n if (nameValue.trim()) {\n onTaskChange?.({ ...task, name: nameValue.trim() });\n }\n setEditingName(false);\n }, [nameValue, task, onTaskChange]);\n\n const handleNameCancel = useCallback(() => {\n setEditingName(false);\n }, []);\n\n const handleNameKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') handleNameSave();\n else if (e.key === 'Escape') handleNameCancel();\n }, [handleNameSave, handleNameCancel]);\n\n // Both date pickers shift the whole task (preserving duration), same as drag-move\n const handleStartDateChange = useCallback((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 onTaskChange?.({ ...task, startDate: newDateISO, endDate: newEnd.toISOString().split('T')[0] });\n }, [task, onTaskChange]);\n\n const handleEndDateChange = useCallback((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 onTaskChange?.({ ...task, startDate: newStart.toISOString().split('T')[0], endDate: newDateISO });\n }, [task, onTaskChange]);\n\n const handleRowClickInternal = useCallback(() => {\n onRowClick?.(task.id);\n }, [task.id, onRowClick]);\n\n const handleNumberClick = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n onRowClick?.(task.id);\n onScrollToTask?.(task.id);\n }, [task.id, onRowClick, onScrollToTask]);\n\n // Dependency handlers\n const handleAddClick = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n onSetSelectingPredecessorFor?.(task.id);\n }, [task.id, onSetSelectingPredecessorFor]);\n\n const handlePredecessorPick = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n if (!isPicking || isSourceRow) return;\n if (!selectingPredecessorFor || !activeLinkType) return;\n onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);\n }, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);\n\n // True when this row is the predecessor for the currently selected chip\n const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;\n\n // Delete the selected dependency from the predecessor row's \"Удалить\" button\n const handleDeleteSelected = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selectedChip) return;\n onRemoveDependency?.(selectedChip.successorId, selectedChip.predecessorId, selectedChip.linkType as LinkType);\n onChipSelect?.(null);\n }, [selectedChip, onRemoveDependency, onChipSelect]);\n\n const startDateISO = toISODate(task.startDate);\n const endDateISO = toISODate(task.endDate);\n\n return (\n <div\n className={[\n 'gantt-tl-row',\n isSelected ? 'gantt-tl-row-selected' : '',\n isPicking && !isSourceRow ? 'gantt-tl-row-picking' : '',\n isSourceRow ? 'gantt-tl-row-picking-self' : '',\n ].filter(Boolean).join(' ')}\n style={{ minHeight: `${rowHeight}px` }}\n onClick={handleRowClickInternal}\n >\n {/* Number column — click selects the row and scrolls the grid to this task */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-number\"\n onClick={handleNumberClick}\n title=\"Перейти к работе\"\n >\n <span className=\"gantt-tl-num-label\">{rowIndex + 1}</span>\n <svg className=\"gantt-tl-num-icon\" 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\" />\n <path d=\"m11 18 6-6-6-6\" />\n <path d=\"M21 5v14\" />\n </svg>\n </div>\n\n {/* Name column — styled Input overlay on edit */}\n <div className=\"gantt-tl-cell gantt-tl-cell-name\">\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 onClick={(e) => e.stopPropagation()}\n />\n )}\n <button\n type=\"button\"\n className={`gantt-tl-name-trigger ${disableTaskNameEditing ? 'gantt-tl-name-locked' : ''}`}\n onClick={handleNameClick}\n style={editingName ? { visibility: 'hidden', pointerEvents: 'none' } : undefined}\n >\n {task.name}\n </button>\n </div>\n\n {/* Start Date — DatePicker component */}\n <div className=\"gantt-tl-cell gantt-tl-cell-date\" onClick={(e) => e.stopPropagation()}>\n <DatePicker\n value={startDateISO}\n onChange={handleStartDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n />\n </div>\n\n {/* End Date — DatePicker component */}\n <div className=\"gantt-tl-cell gantt-tl-cell-date\" onClick={(e) => e.stopPropagation()}>\n <DatePicker\n value={endDateISO}\n onChange={handleEndDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n />\n </div>\n\n {/* Dependencies column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-deps\"\n onClick={isPicking && !isSourceRow ? handlePredecessorPick : undefined}\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\">Связано с</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) => { e.stopPropagation(); setOverflowOpen(v => !v); }}\n >\n {chips.length} {linkWord}\n </button>\n </PopoverTrigger>\n <PopoverContent portal={true} align=\"start\">\n <div className=\"gantt-tl-dep-overflow-list\" onClick={(e) => e.stopPropagation()}>\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 />\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 />\n ) : null}\n\n {/* \"+\" add dependency button — hidden in picker mode and when editing disabled */}\n {!disableDependencyEditing && !isPicking && (\n <button\n type=\"button\"\n className=\"gantt-tl-dep-add\"\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 } from 'react';\nimport { format, isValid } 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}\n\n/**\n * DatePicker component — shows formatted date as a button, opens calendar popup on click\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}) => {\n const [open, setOpen] = useState(false);\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\n const displayValue = selectedDate\n ? format(selectedDate, displayFormat)\n : placeholder;\n\n const handleSelect = useCallback(\n (day: Date) => {\n // Convert to ISO string using local date parts to avoid timezone shift\n const iso = [\n day.getFullYear(),\n String(day.getMonth() + 1).padStart(2, '0'),\n String(day.getDate()).padStart(2, '0'),\n ].join('-');\n onChange?.(iso);\n setOpen(false);\n },\n [onChange]\n );\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 <Calendar\n mode=\"single\"\n selected={selectedDate}\n onSelect={handleSelect}\n initialDate={selectedDate}\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';\n\nexport interface CalendarProps {\n selected?: Date;\n onSelect?: (date: Date) => void;\n initialDate?: Date;\n mode?: 'single' | 'range';\n disabled?: boolean;\n}\n\nfunction getDayClassName(day: Date, selected: Date | undefined): 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 if (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}) => {\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 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(month.getFullYear(), month.getMonth(), dayNum);\n const className = getDayClassName(day, selected);\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(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 {emptyCells}\n {dayCells}\n </div>\n </div>\n );\n },\n [selected, onSelect, disabled]\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 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,IAAAA,iBAA0G;;;ACMnG,IAAM,eAAe,CAAC,SAA8B;AACzD,MAAI,OAAO,SAAS,UAAU;AAG5B,UAAM,UAAU,KAAK,SAAS,GAAG,IAAI,OAAO,GAAG,IAAI;AACnD,UAAM,SAAS,IAAI,KAAK,OAAO;AAC/B,QAAI,MAAM,OAAO,QAAQ,CAAC,GAAG;AAC3B,YAAM,IAAI,MAAM,wBAAwB,IAAI,EAAE;AAAA,IAChD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,IAAM,eAAe,CAAC,SAAgC;AAC3D,QAAM,UAAU,aAAa,IAAI;AACjC,QAAM,OAAO,QAAQ,eAAe;AACpC,QAAM,QAAQ,QAAQ,YAAY;AAGlC,QAAM,cAAc,IAAI,KAAK,KAAK,IAAI,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,WAAW;AAEtE,QAAM,OAAe,CAAC;AACtB,WAAS,MAAM,GAAG,OAAO,aAAa,OAAO;AAC3C,SAAK,KAAK,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,EAChD;AAEA,SAAO;AACT;AAQO,IAAM,eAAe,CAAC,MAAY,eAA6B;AACpE,QAAM,SAAS,KAAK;AAAA,IAClB,KAAK,eAAe;AAAA,IACpB,KAAK,YAAY;AAAA,IACjB,KAAK,WAAW;AAAA,EAClB;AACA,QAAM,UAAU,KAAK;AAAA,IACnB,WAAW,eAAe;AAAA,IAC1B,WAAW,YAAY;AAAA,IACvB,WAAW,WAAW;AAAA,EACxB;AACA,SAAO,KAAK,OAAO,SAAS,YAAY,MAAO,KAAK,KAAK,GAAG;AAC9D;AAOO,IAAM,UAAU,CAAC,SAAwB;AAC9C,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,QAAQ,IAAI,KAAK,KAAK;AAAA,IAC1B,IAAI,eAAe;AAAA,IACnB,IAAI,YAAY;AAAA,IAChB,IAAI,WAAW;AAAA,EACjB,CAAC;AACD,QAAM,cAAc,IAAI,KAAK,KAAK;AAAA,IAChC,KAAK,eAAe;AAAA,IACpB,KAAK,YAAY;AAAA,IACjB,KAAK,WAAW;AAAA,EAClB,CAAC;AACD,SAAO,MAAM,QAAQ,MAAM,YAAY,QAAQ;AACjD;AAOO,IAAM,YAAY,CAAC,SAAwB;AAChD,QAAM,MAAM,KAAK,UAAU;AAC3B,SAAO,QAAQ,KAAK,QAAQ;AAC9B;AASO,IAAM,oBAAoB,CAAC,UAA+E;AAE/G,MAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,WAAO,aAAa,oBAAI,KAAK,CAAC;AAAA,EAChC;AAGA,MAAI,UAAuB;AAC3B,MAAI,UAAuB;AAE3B,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,aAAa,KAAK,SAAS;AACzC,UAAM,MAAM,aAAa,KAAK,OAAO;AAErC,QAAI,CAAC,WAAW,MAAM,QAAQ,IAAI,QAAQ,QAAQ,GAAG;AACnD,gBAAU;AAAA,IACZ;AACA,QAAI,CAAC,WAAW,IAAI,QAAQ,IAAI,QAAQ,QAAQ,GAAG;AACjD,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,MAAI,CAAC,WAAW,CAAC,SAAS;AACxB,WAAO,aAAa,oBAAI,KAAK,CAAC;AAAA,EAChC;AAIA,QAAMC,gBAAe,IAAI,KAAK,KAAK;AAAA,IACjC,QAAQ,eAAe;AAAA,IACvB,QAAQ,YAAY;AAAA,IACpB;AAAA,EACF,CAAC;AAED,QAAM,aAAa,IAAI,KAAK,KAAK;AAAA,IAC/B,QAAQ,eAAe;AAAA,IACvB,QAAQ,YAAY,IAAI,IAAI;AAAA;AAAA,IAC5B;AAAA,EACF,CAAC;AAGD,QAAM,OAAe,CAAC;AACtB,QAAM,UAAU,IAAI,KAAKA,aAAY;AAErC,SAAO,QAAQ,QAAQ,KAAK,WAAW,QAAQ,GAAG;AAChD,SAAK,KAAK,IAAI,KAAK,KAAK;AAAA,MACtB,QAAQ,eAAe;AAAA,MACvB,QAAQ,YAAY;AAAA,MACpB,QAAQ,WAAW;AAAA,IACrB,CAAC,CAAC;AAEF,YAAQ,WAAW,QAAQ,WAAW,IAAI,CAAC;AAAA,EAC7C;AAEA,SAAO;AACT;AAOO,IAAM,gBAAgB,CAC3B,cAC6D;AAC7D,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,QAAkE,CAAC;AACzE,MAAI,mBAAmB,GAAG,UAAU,CAAC,EAAE,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,YAAY,CAAC;AACrF,MAAI,oBAAoB;AAExB,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,UAAM,OAAO,UAAU,CAAC;AACxB,UAAM,YAAY,GAAG,KAAK,eAAe,CAAC,IAAI,KAAK,YAAY,CAAC;AAGhE,QAAI,cAAc,kBAAkB;AAClC,YAAM,KAAK;AAAA,QACT,OAAO,IAAI,KAAK,KAAK;AAAA,UACnB,UAAU,iBAAiB,EAAE,eAAe;AAAA,UAC5C,UAAU,iBAAiB,EAAE,YAAY;AAAA,UACzC;AAAA,QACF,CAAC;AAAA,QACD,MAAM,IAAI;AAAA,QACV,YAAY;AAAA,MACd,CAAC;AACD,yBAAmB;AACnB,0BAAoB;AAAA,IACtB;AAGA,QAAI,MAAM,UAAU,SAAS,GAAG;AAC9B,YAAM,KAAK;AAAA,QACT,OAAO,IAAI,KAAK,KAAK;AAAA,UACnB,KAAK,eAAe;AAAA,UACpB,KAAK,YAAY;AAAA,UACjB;AAAA,QACF,CAAC;AAAA,QACD,MAAM,IAAI,oBAAoB;AAAA,QAC9B,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAOO,IAAM,kBAAkB,CAAC,SAAgC;AAC9D,QAAM,SAAS,aAAa,IAAI;AAChC,QAAM,MAAM,OAAO,OAAO,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AACvD,QAAM,QAAQ,OAAO,OAAO,YAAY,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAC9D,SAAO,GAAG,GAAG,IAAI,KAAK;AACxB;;;ACtNO,SAAS,mBAAmB,OAAsC;AACvE,QAAM,UAAU,IAAI,IAAI,MAAM,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACjD,QAAM,QAAQ,oBAAI,IAAsB;AAExC,aAAW,QAAQ,OAAO;AACxB,UAAM,aAAuB,CAAC;AAG9B,eAAW,aAAa,OAAO;AAC7B,UAAI,UAAU,cAAc;AAC1B,mBAAW,OAAO,UAAU,cAAc;AACxC,cAAI,IAAI,WAAW,KAAK,IAAI;AAC1B,uBAAW,KAAK,UAAU,EAAE;AAC5B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,IAAI,KAAK,IAAI,UAAU;AAAA,EAC/B;AAEA,SAAO;AACT;AAKO,SAAS,aAAa,OAA4D;AACvF,QAAM,QAAQ,mBAAmB,KAAK;AACtC,QAAM,WAAW,oBAAI,IAAY;AACjC,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,OAAiB,CAAC;AAExB,WAAS,IAAI,QAAyB;AACpC,QAAI,SAAS,IAAI,MAAM,GAAG;AAExB,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,IAAI,MAAM,GAAG;AACvB,aAAO;AAAA,IACT;AAEA,aAAS,IAAI,MAAM;AACnB,SAAK,KAAK,MAAM;AAEhB,UAAM,aAAa,MAAM,IAAI,MAAM,KAAK,CAAC;AACzC,eAAW,aAAa,YAAY;AAClC,UAAI,IAAI,SAAS,GAAG;AAClB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,aAAS,OAAO,MAAM;AACtB,SAAK,IAAI;AACT,YAAQ,IAAI,MAAM;AAClB,WAAO;AAAA,EACT;AAEA,aAAW,QAAQ,OAAO;AACxB,QAAI,IAAI,KAAK,EAAE,GAAG;AAChB,aAAO,EAAE,UAAU,MAAM,WAAW,CAAC,GAAG,IAAI,EAAE;AAAA,IAChD;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,MAAM;AAC3B;AAYO,SAAS,oBACd,UACA,WACA,SACA,WACA,SACQ;AACR,QAAM,SAAS,KAAK,KAAK,KAAK;AAC9B,QAAM,KAAK,KAAK,IAAI,UAAU,eAAe,GAAG,UAAU,YAAY,GAAG,UAAU,WAAW,CAAC;AAC/F,QAAM,KAAK,KAAK,IAAI,QAAQ,eAAe,GAAK,QAAQ,YAAY,GAAK,QAAQ,WAAW,CAAC;AAC7F,QAAM,KAAK,KAAK,IAAI,UAAU,eAAe,GAAG,UAAU,YAAY,GAAG,UAAU,WAAW,CAAC;AAC/F,QAAM,KAAK,KAAK,IAAI,QAAQ,eAAe,GAAK,QAAQ,YAAY,GAAK,QAAQ,WAAW,CAAC;AAC7F,UAAQ,UAAU;AAAA,IAChB,KAAK;AAAM,aAAO,KAAK,OAAO,KAAK,MAAM,MAAM,IAAI;AAAA,IACnD,KAAK;AAAM,aAAO,KAAK,OAAO,KAAK,MAAM,MAAM;AAAA,IAC/C,KAAK;AAAM,aAAO,KAAK,OAAO,KAAK,MAAM,MAAM;AAAA,IAC/C,KAAK;AAAM,aAAO,KAAK,OAAO,KAAK,MAAM,MAAM,IAAI;AAAA,EACrD;AACF;AAWO,SAAS,uBACd,kBACA,gBACA,UACA,MAAc,GACR;AACN,QAAM,SAAS,KAAK,KAAK,KAAK;AAE9B,UAAQ,UAAU;AAAA,IAChB,KAAK;AAEH,aAAO,IAAI,KAAK,eAAe,QAAQ,KAAK,MAAM,KAAK,MAAM;AAAA,IAC/D,KAAK;AACH,aAAO,IAAI,KAAK,iBAAiB,QAAQ,IAAI,MAAM,MAAM;AAAA,IAC3D,KAAK;AACH,aAAO,IAAI,KAAK,eAAe,QAAQ,IAAI,MAAM,MAAM;AAAA,IACzD,KAAK;AAEH,aAAO,IAAI,KAAK,iBAAiB,QAAQ,KAAK,MAAM,KAAK,MAAM;AAAA,EACnE;AACF;AAKO,SAAS,qBAAqB,OAAiC;AACpE,QAAM,SAA4B,CAAC;AACnC,QAAM,UAAU,IAAI,IAAI,MAAM,IAAI,OAAK,EAAE,EAAE,CAAC;AAG5C,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,cAAc;AACrB,iBAAW,OAAO,KAAK,cAAc;AACnC,YAAI,CAAC,QAAQ,IAAI,IAAI,MAAM,GAAG;AAC5B,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN,QAAQ,KAAK;AAAA,YACb,SAAS,4CAA4C,IAAI,MAAM;AAAA,YAC/D,gBAAgB,CAAC,IAAI,MAAM;AAAA,UAC7B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,aAAa,KAAK;AACtC,MAAI,YAAY,YAAY,YAAY,WAAW;AACjD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,QAAQ,YAAY,UAAU,CAAC;AAAA,MAC/B,SAAS;AAAA,MACT,gBAAgB,YAAY;AAAA,IAC9B,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,SAAS,OAAO,WAAW;AAAA,IAC3B;AAAA,EACF;AACF;AAeO,SAAS,kBACd,eACA,UACA,YAAwB,CAAC,IAAI,GACrB;AAER,QAAM,eAAe,oBAAI,IAAsB;AAC/C,aAAW,QAAQ,UAAU;AAC3B,iBAAa,IAAI,KAAK,IAAI,CAAC,CAAC;AAAA,EAC9B;AACA,aAAW,QAAQ,UAAU;AAC3B,QAAI,CAAC,KAAK,aAAc;AACxB,eAAW,OAAO,KAAK,cAAc;AACnC,UAAI,UAAU,SAAS,IAAI,IAAI,GAAG;AAChC,cAAM,OAAO,aAAa,IAAI,IAAI,MAAM,KAAK,CAAC;AAC9C,aAAK,KAAK,KAAK,EAAE;AACjB,qBAAa,IAAI,IAAI,QAAQ,IAAI;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,IAAI,SAAS,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACrD,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,QAAkB,CAAC,aAAa;AACtC,QAAM,QAAgB,CAAC;AACvB,UAAQ,IAAI,aAAa;AAEzB,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,MAAM;AAC5B,UAAM,aAAa,aAAa,IAAI,OAAO,KAAK,CAAC;AACjD,eAAW,OAAO,YAAY;AAC5B,UAAI,CAAC,QAAQ,IAAI,GAAG,GAAG;AACrB,gBAAQ,IAAI,GAAG;AACf,cAAM,IAAI,SAAS,IAAI,GAAG;AAC1B,YAAI,GAAG;AACL,gBAAM,KAAK,CAAC;AACZ,gBAAM,KAAK,GAAG;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAcO,SAAS,eACd,aACA,UACA,QACA,UACQ;AACR,QAAM,WAAW,IAAI,IAAI,SAAS,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAGrD,QAAM,eAAe,oBAAI,IAAwC;AACjE,eAAa,IAAI,aAAa,EAAE,OAAO,UAAU,KAAK,OAAO,CAAC;AAE9D,QAAM,SAAiB,CAAC;AACxB,QAAM,QAAkB,CAAC,WAAW;AACpC,QAAM,UAAU,oBAAI,IAAY,CAAC,WAAW,CAAC;AAE7C,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,YAAY,MAAM,MAAM;AAC9B,UAAM,EAAE,OAAO,WAAW,KAAK,QAAQ,IAAI,aAAa,IAAI,SAAS;AAErE,eAAW,QAAQ,UAAU;AAC3B,UAAI,QAAQ,IAAI,KAAK,EAAE,KAAK,CAAC,KAAK,gBAAgB,KAAK,OAAQ;AAE/D,iBAAW,OAAO,KAAK,cAAc;AACnC,YAAI,IAAI,WAAW,UAAW;AAE9B,cAAM,OAAO,SAAS,IAAI,KAAK,EAAE;AACjC,cAAM,YAAY,IAAI,KAAK,KAAK,SAAmB;AACnD,cAAM,UAAU,IAAI,KAAK,KAAK,OAAiB;AAC/C,cAAM,aAAa,QAAQ,QAAQ,IAAI,UAAU,QAAQ;AAEzD,cAAM,iBAAiB,uBAAuB,WAAW,SAAS,IAAI,MAAM,IAAI,OAAO,CAAC;AAExF,YAAI;AACJ,YAAI;AAEJ,YAAI,IAAI,SAAS,QAAQ,IAAI,SAAS,MAAM;AAC1C,yBAAe;AACf,uBAAa,IAAI,KAAK,eAAe,QAAQ,IAAI,UAAU;AAAA,QAC7D,OAAO;AAEL,uBAAa;AACb,yBAAe,IAAI,KAAK,eAAe,QAAQ,IAAI,UAAU;AAAA,QAC/D;AAEA,gBAAQ,IAAI,KAAK,EAAE;AACnB,qBAAa,IAAI,KAAK,IAAI,EAAE,OAAO,cAAc,KAAK,WAAW,CAAC;AAClE,eAAO,KAAK;AAAA,UACV,GAAG;AAAA,UACH,WAAW,aAAa,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,UAClD,SAAS,WAAW,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,QAChD,CAAC;AACD,cAAM,KAAK,KAAK,EAAE;AAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,0BACd,eACA,UACA,qBACQ;AACR,QAAM,uBAAuB,oBAAI,IAAoB;AACrD,aAAW,QAAQ,UAAU;AAC3B,yBAAqB,IAAI,KAAK,IAAI,CAAC,CAAC;AAAA,EACtC;AACA,aAAW,QAAQ,UAAU;AAC3B,QAAI,CAAC,KAAK,aAAc;AACxB,eAAW,OAAO,KAAK,cAAc;AACnC,YAAM,OAAO,qBAAqB,IAAI,IAAI,MAAM,KAAK,CAAC;AACtD,WAAK,KAAK,IAAI;AACd,2BAAqB,IAAI,IAAI,QAAQ,IAAI;AAAA,IAC3C;AAAA,EACF;AAEA,QAAM,mBAAmB,kBAAkB,eAAe,UAAU,mBAAmB;AACvF,QAAM,QAAQ,CAAC,GAAG,gBAAgB;AAClC,QAAM,UAAU,oBAAI,IAAY,CAAC,eAAe,GAAG,iBAAiB,IAAI,OAAK,EAAE,EAAE,CAAC,CAAC;AACnF,QAAM,QAAQ,CAAC,GAAG,gBAAgB;AAElC,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,MAAM;AAC5B,UAAM,aAAa,qBAAqB,IAAI,QAAQ,EAAE,KAAK,CAAC;AAC5D,eAAW,aAAa,YAAY;AAClC,UAAI,CAAC,QAAQ,IAAI,UAAU,EAAE,GAAG;AAC9B,gBAAQ,IAAI,UAAU,EAAE;AACxB,cAAM,KAAK,SAAS;AACpB,cAAM,KAAK,SAAS;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,wBACd,MACA,cACA,YACA,UACmC;AACnC,MAAI,CAAC,KAAK,aAAc,QAAO,CAAC;AAChC,QAAM,WAAW,IAAI,IAAI,SAAS,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAErD,SAAO,KAAK,aAAa,IAAI,SAAO;AAClC,UAAM,cAAc,SAAS,IAAI,IAAI,MAAM;AAC3C,QAAI,CAAC,YAAa,QAAO;AAEzB,UAAM,YAAY,IAAI,KAAK,YAAY,SAAmB;AAC1D,UAAM,UAAY,IAAI,KAAK,YAAY,OAAmB;AAC1D,UAAM,UAAY,oBAAoB,IAAI,MAAM,WAAW,SAAS,cAAc,UAAU;AAC5F,WAAO,EAAE,GAAG,KAAK,KAAK,QAAQ;AAAA,EAChC,CAAC;AACH;AAMO,SAAS,sBAAsB,OAKnC;AACD,QAAM,QAA4F,CAAC;AAEnG,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,cAAc;AACrB,iBAAW,OAAO,KAAK,cAAc;AACnC,cAAM,KAAK;AAAA,UACT,eAAe,IAAI;AAAA,UACnB,aAAa,KAAK;AAAA,UAClB,MAAM,IAAI;AAAA,UACV,KAAK,IAAI,OAAO;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC7YA,mBAA+B;AAC/B,sBAAuB;AACvB,oBAAmB;AAsCf;AAlBJ,IAAM,kBAAkD,CAAC;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AACF,MAAM;AAEJ,QAAM,iBAAa,sBAAQ,MAAM,cAAc,IAAI,GAAG,CAAC,IAAI,CAAC;AAG5D,QAAM,YAAY,eAAe;AAGjC,QAAM,sBAAkB;AAAA,IACtB,MAAM,UAAU,KAAK,MAAM,KAAK,QAAQ;AAAA,IACxC,CAAC,KAAK,QAAQ,QAAQ;AAAA,EACxB;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,QAAQ,GAAG,YAAY,KAAK;AAAA,MAGrC;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,QAAQ,GAAG,SAAS,KAAK;AAAA,YAEjC,qBAAW,IAAI,CAAC,MAAiB,UAChC;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAU;AAAA,gBACV,OAAO,EAAE,OAAO,GAAG,KAAK,OAAO,QAAQ,KAAK;AAAA,gBAE3C,sCAAO,KAAK,OAAO,aAAa,EAAE,QAAQ,iBAAG,CAAC,EAAE,QAAQ,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA;AAAA,cAJhF,SAAS,KAAK;AAAA,YAKrB,CACD;AAAA;AAAA,QACH;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,QAAQ,GAAG,SAAS;AAAA,cACpB,qBAAqB;AAAA,YACvB;AAAA,YAEC,eAAK,IAAI,CAAC,KAAK,UAAU;AACxB,oBAAMC,aAAY,IAAI,OAAO,MAAM,KAAK,IAAI,OAAO,MAAM;AACzD,oBAAM,UAAU,KAAK,QAAQ,CAAC;AAC9B,oBAAM,kBAAkB,QAAQ,KAAK,WAAW,QAAQ,SAAS,MAAM,IAAI,SAAS;AAEpF,oBAAM,MAAM,oBAAI,KAAK;AACrB,oBAAM,cACJ,IAAI,eAAe,MAAM,IAAI,YAAY,KACzC,IAAI,YAAY,MAAM,IAAI,SAAS,KACnC,IAAI,WAAW,MAAM,IAAI,QAAQ;AACnC,qBACE,4CAAC,SAAyB,WAAW,qBAAqBA,aAAY,yBAAyB,EAAE,IAAI,kBAAkB,4BAA4B,EAAE,IAAI,cAAc,oBAAoB,EAAE,IAC3L,sDAAC,UAAK,WAAU,sBAAsB,sCAAO,KAAK,GAAG,GAAE,KAD/C,OAAO,KAAK,EAEtB;AAAA,YAEJ,CAAC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,0BAAQ;;;ACzFf,IAAAC,gBAA+B;;;ACC/B,IAAM,sBAAsB,CAAC,OAAa,UAAwB;AAChE,QAAM,MAAM,KAAK;AAAA,IACf,MAAM,eAAe;AAAA,IACrB,MAAM,YAAY;AAAA,IAClB,MAAM,WAAW;AAAA,EACnB;AACA,QAAM,MAAM,KAAK;AAAA,IACf,MAAM,eAAe;AAAA,IACrB,MAAM,YAAY;AAAA,IAClB,MAAM,WAAW;AAAA,EACnB;AACA,SAAO,KAAK,OAAO,MAAM,QAAQ,MAAO,KAAK,KAAK,GAAG;AACvD;AAUO,IAAM,mBAAmB,CAC9B,eACA,aACA,YACA,aACoC;AACpC,QAAM,cAAc,oBAAoB,eAAe,UAAU;AACjE,QAAM,WAAW,oBAAoB,aAAa,aAAa;AAG/D,QAAM,OAAO,KAAK,MAAM,cAAc,QAAQ;AAC9C,QAAM,QAAQ,KAAK,OAAO,WAAW,KAAK,QAAQ;AAElD,SAAO,EAAE,MAAM,MAAM;AACvB;AASO,IAAM,eAAe,CAAC,QAAgB,YAAkB,aAA2B;AACxF,QAAM,OAAO,KAAK,MAAM,SAAS,QAAQ;AACzC,SAAO,IAAI,KAAK,KAAK;AAAA,IACnB,WAAW,eAAe;AAAA,IAC1B,WAAW,YAAY;AAAA,IACvB,WAAW,WAAW,IAAI;AAAA,EAC5B,CAAC;AACH;AAQO,IAAM,qBAAqB,CAAC,aAAqB,aAA6B;AACnF,SAAO,KAAK,MAAM,cAAc,QAAQ;AAC1C;AASO,IAAM,iBAAiB,CAC5B,SACA,gBACA,gBAAwB,OACM;AAC9B,QAAM,OAAO,eAAe,sBAAsB;AAClD,QAAM,YAAY,KAAK,MAAM,UAAU,KAAK,IAAI;AAChD,QAAM,QAAQ,KAAK,MAAM,KAAK,KAAK;AAGnC,MAAI,SAAS,IAAI,eAAe;AAE9B,UAAM,iBAAiB;AACvB,UAAM,kBAAkB,QAAQ;AAChC,WAAO,kBAAkB,kBAAkB,SAAS;AAAA,EACtD;AAGA,MAAI,aAAa,KAAK,aAAa,eAAe;AAChD,WAAO;AAAA,EACT;AAGA,MAAI,aAAa,QAAQ,iBAAiB,aAAa,OAAO;AAC5D,WAAO;AAAA,EACT;AAGA,SAAO;AACT;AAOO,IAAM,uBAAuB,CAAC,aAAgD;AACnF,UAAQ,UAAU;AAAA,IAChB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAQO,IAAM,qBAAqB,CAChC,WACA,aACsE;AACtE,QAAM,QAA2E,CAAC;AAElF,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,UAAM,OAAO,UAAU,CAAC;AACxB,UAAM,IAAI,KAAK,MAAM,IAAI,QAAQ;AACjC,UAAM,eAAe,KAAK,WAAW,MAAM;AAC3C,UAAM,cAAc,KAAK,UAAU,MAAM;AAEzC,UAAM,KAAK,EAAE,GAAG,cAAc,YAAY,CAAC;AAAA,EAC7C;AAGA,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,KAAK;AAAA,MACT,GAAG,KAAK,MAAM,UAAU,SAAS,QAAQ;AAAA,MACzC,cAAc;AAAA,MACd,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAQO,IAAM,yBAAyB,CACpC,WACA,aAC2C;AAC3C,QAAM,SAAiD,CAAC;AACxD,MAAI,YAAY;AAChB,MAAI,oBAAoB;AAExB,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,UAAM,OAAO,UAAU,CAAC;AACxB,UAAM,YAAY,KAAK,UAAU;AACjC,UAAMC,aAAY,cAAc,KAAK,cAAc;AAEnD,QAAIA,cAAa,CAAC,WAAW;AAE3B,kBAAY;AACZ,0BAAoB;AAAA,IACtB,WAAW,CAACA,cAAa,WAAW;AAElC,kBAAY;AACZ,YAAM,OAAO,KAAK,MAAM,oBAAoB,QAAQ;AACpD,YAAM,QAAQ,KAAK,OAAO,IAAI,qBAAqB,QAAQ;AAC3D,aAAO,KAAK,EAAE,MAAM,MAAM,CAAC;AAAA,IAC7B;AAAA,EACF;AAGA,MAAI,aAAa,qBAAqB,GAAG;AACvC,UAAM,OAAO,KAAK,MAAM,oBAAoB,QAAQ;AACpD,UAAM,QAAQ,KAAK,OAAO,UAAU,SAAS,qBAAqB,QAAQ;AAC1E,WAAO,KAAK,EAAE,MAAM,MAAM,CAAC;AAAA,EAC7B;AAEA,SAAO;AACT;AAQO,IAAM,sBAAsB,CACjC,MACA,OACW;AAGX,QAAM,mBAAmB,KAAK,IAAI,GAAG,IAAI,KAAK,CAAC;AAC/C,QAAM,WAAW,KAAK,IAAI,mBAAmB,KAAK,EAAE;AAGpD,MAAI,KAAK,MAAM,GAAG,GAAG;AACnB,UAAM,YAAY;AAClB,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK;AAC/B,WAAO,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,KAAK,IAAI,SAAS,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC;AAAA,EAC9E;AAGA,QAAM,OAAO,KAAK;AAClB,QAAM,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,IAAI,WAAW,CAAC;AACnD,QAAM,OAAO,GAAG;AAChB,QAAM,OAAO,GAAG,KAAK,GAAG,IAAI,KAAK,IAAI,WAAW,CAAC;AAEjD,SAAO,KAAK,KAAK,MAAM,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC;AAClL;AAeO,IAAM,0BAA0B,CACrC,MACA,IACA,qBACW;AACX,QAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAC5B,QAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAC5B,QAAM,KAAK,KAAK,MAAM,GAAG,CAAC;AAC1B,QAAM,KAAK,KAAK,MAAM,GAAG,CAAC;AAG1B,MAAI,OAAO,IAAI;AACb,WAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;AAAA,EAC9B;AAEA,QAAM,IAAI;AACV,QAAM,YAAY,KAAK;AACvB,QAAM,OAAO,YAAY,IAAI;AAE7B,MAAI,kBAAkB;AAKpB,UAAM,aAAa,MAAM;AACzB,UAAM,OAAO,aAAa,IAAI;AAE9B,QAAI,KAAK,IAAI,KAAK,EAAE,KAAK,KAAK,KAAK,IAAI,KAAK,EAAE,KAAK,GAAG;AACpD,aAAO;AAAA,QACL,KAAK,EAAE,IAAI,EAAE;AAAA,QACb,KAAK,KAAK,OAAO,CAAC;AAAA,QAClB,KAAK,EAAE,IAAI,KAAK,OAAO,CAAC;AAAA,QACxB,KAAK,EAAE;AAAA,MACT,EAAE,KAAK,GAAG;AAAA,IACZ;AACA,WAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE;AAAA,EACtC,OAAO;AAEL,UAAM,aAAa,MAAM;AACzB,UAAM,OAAO,aAAa,IAAI;AAE9B,QAAI,KAAK,IAAI,KAAK,EAAE,KAAK,KAAK,KAAK,IAAI,KAAK,EAAE,KAAK,GAAG;AACpD,aAAO;AAAA,QACL,KAAK,EAAE,IAAI,EAAE;AAAA,QACb,KAAK,KAAK,OAAO,CAAC;AAAA,QAClB,KAAK,EAAE,IAAI,KAAK,OAAO,CAAC;AAAA,QACxB,KAAK,EAAE;AAAA,MACT,EAAE,KAAK,GAAG;AAAA,IACZ;AACA,WAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE;AAAA,EACtC;AACF;AAUO,IAAM,0BAA0B,CACrC,MACA,OACW;AACX,QAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAC5B,QAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAC5B,QAAM,KAAK,KAAK,MAAM,GAAG,CAAC;AAC1B,QAAM,KAAK,KAAK,MAAM,GAAG,CAAC;AAG1B,MAAI,OAAO,IAAI;AACb,WAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;AAAA,EAC9B;AAEA,QAAM,IAAI;AACV,QAAM,YAAY,KAAK;AACvB,QAAM,aAAa,MAAM;AACzB,QAAM,OAAO,YAAY,IAAI;AAC7B,QAAM,OAAO,aAAa,IAAI;AAG9B,MAAI,KAAK,IAAI,KAAK,EAAE,KAAK,KAAK,KAAK,IAAI,KAAK,EAAE,KAAK,GAAG;AACpD,WAAO;AAAA,MACL,KAAK,EAAE,IAAI,EAAE;AAAA,MACb,KAAK,KAAK,OAAO,CAAC;AAAA,MAClB,KAAK,EAAE,IAAI,KAAK,OAAO,CAAC;AAAA,MACxB,KAAK,EAAE;AAAA,IACT,EAAE,KAAK,GAAG;AAAA,EACZ;AAGA,SAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE;AACtC;;;AC5UA,IAAAC,gBAAyD;AAyDzD,IAAI,mBAA2C;AAC/C,IAAI,cAA6B;AAKjC,SAAS,eAAe;AACtB,MAAI,gBAAgB,MAAM;AACxB,yBAAqB,WAAW;AAChC,kBAAc;AAAA,EAChB;AAEA,MAAI,kBAAkB;AAEpB,qBAAiB,oBAAoB,oBAAI,IAAI,CAAC;AAC9C,UAAM,EAAE,YAAY,aAAa,aAAa,IAAI;AAClD,uBAAmB;AACnB,eAAW,aAAa,YAAY;AAAA,EACtC;AACF;AAKA,SAAS,aAAa;AACpB,MAAI,gBAAgB,MAAM;AACxB,yBAAqB,WAAW;AAChC,kBAAc;AAAA,EAChB;AAEA,MAAI,kBAAkB;AACpB,UAAM,EAAE,SAAS,IAAI;AACrB,uBAAmB;AACnB,aAAS;AAAA,EACX;AACF;AAKA,SAAS,WAAW,QAAgB,UAA0B;AAC5D,SAAO,KAAK,MAAM,SAAS,QAAQ,IAAI;AACzC;AA+DA,SAAS,sBAAsB,GAAe;AAC5C,MAAI,CAAC,oBAAoB,gBAAgB,MAAM;AAC7C;AAAA,EACF;AAEA,gBAAc,sBAAsB,MAAM;AACxC,QAAI,CAAC,kBAAkB;AACrB,oBAAc;AACd;AAAA,IACF;AAEA,UAAM,EAAE,QAAQ,aAAa,cAAc,MAAM,UAAU,YAAY,SAAS,IAAI;AACpF,UAAM,SAAS,EAAE,UAAU;AAE3B,QAAI,UAAU;AACd,QAAI,WAAW;AAEf,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,kBAAU,WAAW,cAAc,QAAQ,QAAQ;AACnD;AAAA,MACF,KAAK;AACH,cAAM,cAAc,WAAW,cAAc,QAAQ,QAAQ;AAC7D,kBAAU;AACV,cAAM,YAAY,cAAc;AAChC,mBAAW,KAAK,IAAI,UAAU,YAAY,WAAW;AACrD;AAAA,MACF,KAAK;AACH,cAAM,eAAe,WAAW,eAAe,QAAQ,QAAQ;AAC/D,mBAAW,KAAK,IAAI,UAAU,YAAY;AAC1C;AAAA,IACJ;AAKA,SAAK,SAAS,UAAU,SAAS,kBAAkB,SAAS,SAAS,KAAK,CAAC,iBAAiB,oBAAoB;AAC9G,YAAM,cAAc,SAAS,KAAK,OAAK,EAAE,OAAO,kBAAkB,MAAM;AACxE,UAAI,eAAe,YAAY,gBAAgB,YAAY,aAAa,SAAS,GAAG;AAClF,YAAI,iBAAiB;AACrB,mBAAW,OAAO,YAAY,cAAc;AAC1C,cAAI,IAAI,SAAS,QAAQ,IAAI,SAAS,KAAM;AAC5C,gBAAM,cAAc,iBAAiB,SAAS,KAAK,OAAK,EAAE,OAAO,IAAI,MAAM;AAC3E,cAAI,CAAC,YAAa;AAElB,gBAAM,YAAY,IAAI,KAAK,YAAY,SAAmB;AAC1D,gBAAM,kBAAkB,KAAK;AAAA,aAC1B,KAAK,IAAI,UAAU,eAAe,GAAG,UAAU,YAAY,GAAG,UAAU,WAAW,CAAC,IACnF,KAAK;AAAA,cACH,iBAAiB,WAAW,eAAe;AAAA,cAC3C,iBAAiB,WAAW,YAAY;AAAA,cACxC,iBAAiB,WAAW,WAAW;AAAA,YACzC,MAAM,KAAK,KAAK,KAAK;AAAA,UACzB;AACA,gBAAM,gBAAgB,KAAK,MAAM,kBAAkB,iBAAiB,QAAQ;AAC5E,2BAAiB,KAAK,IAAI,gBAAgB,aAAa;AAAA,QACzD;AAEA,kBAAU,KAAK,IAAI,gBAAgB,OAAO;AAAA,MAC5C;AAEA,UAAI,SAAS,eAAe;AAC1B,cAAM,YAAY,iBAAiB,cAAc,iBAAiB;AAClE,mBAAW,KAAK,IAAI,iBAAiB,UAAU,YAAY,OAAO;AAAA,MACpE;AAAA,IACF;AAIA,SAAK,SAAS,UAAU,SAAS,mBAAmB,SAAS,SAAS,KAAK,CAAC,iBAAiB,oBAAoB;AAC/G,YAAM,cAAc,SAAS,KAAK,OAAK,EAAE,OAAO,kBAAkB,MAAM;AACxE,UAAI,eAAe,YAAY,gBAAgB,YAAY,aAAa,SAAS,GAAG;AAClF,mBAAW,OAAO,YAAY,cAAc;AAC1C,cAAI,IAAI,SAAS,KAAM;AACvB,gBAAM,cAAc,iBAAiB,SAAS,KAAK,OAAK,EAAE,OAAO,IAAI,MAAM;AAC3E,cAAI,CAAC,YAAa;AAClB,gBAAM,YAAY,IAAI,KAAK,YAAY,SAAmB;AAC1D,gBAAM,kBAAkB,KAAK;AAAA,aAC1B,KAAK,IAAI,UAAU,eAAe,GAAG,UAAU,YAAY,GAAG,UAAU,WAAW,CAAC,IACnF,KAAK,IAAI,iBAAiB,WAAW,eAAe,GAAG,iBAAiB,WAAW,YAAY,GAAG,iBAAiB,WAAW,WAAW,CAAC,MACzI,KAAK,KAAK,KAAK;AAAA,UACpB;AACA,gBAAM,gBAAgB,KAAK,MAAM,kBAAkB,iBAAiB,QAAQ;AAI5E,gBAAM,kBAAkB;AACxB,cAAI,SAAS,QAAQ;AAEnB,kBAAM,mBAAmB,UAAU,iBAAiB;AACpD,gBAAI,mBAAmB,iBAAiB;AACtC,wBAAU,KAAK,IAAI,iBAAiB,aAAa,kBAAkB,iBAAiB,YAAY;AAAA,YAClG;AAAA,UACF,OAAO;AAEL,kBAAM,kBAAkB,UAAU;AAClC,gBAAI,kBAAkB,iBAAiB;AACrC,yBAAW,KAAK,IAAI,iBAAiB,UAAU,kBAAkB,OAAO;AAAA,YAC1E;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAOA,UAAM,cACJ,SAAS,iBAAiB,iBAAiB;AAAA;AAAA,MAC3C,SAAS,gBAAiB,iBAAiB;AAAA;AAAA;AAAA,QACjB,iBAAiB;AAAA;AAAA;AAG7C,SAAK,SAAS,UAAU,SAAS,kBAC3B,SAAS,iBAAiB,iBAAiB,kBAAkB,SAAS,MACxE,CAAC,iBAAiB,sBAClB,YAAY,SAAS,KACrB,iBAAiB,mBAAmB;AAGtC,YAAM,YAAY,SAAS,iBACvB,KAAK,OAAO,WAAW,iBAAiB,gBAAgB,iBAAiB,QAAQ,IACjF,KAAK,OAAO,UAAU,iBAAiB,eAAe,iBAAiB,QAAQ;AACnF,YAAM,YAAY,oBAAI,IAA6C;AACnE,YAAM,gBAAgB,iBAAiB;AACvC,YAAMC,YAAW,iBAAiB;AAClC,YAAM,aAAa,iBAAiB;AAEpC,iBAAW,aAAa,aAAa;AAEnC,YAAI,UAAU,OAAQ;AAEtB,cAAM,aAAa,IAAI,KAAK,UAAU,SAAmB;AACzD,cAAM,WAAW,IAAI,KAAK,UAAU,OAAiB;AACrD,cAAM,mBAAmB,KAAK;AAAA,WAC3B,KAAK,IAAI,WAAW,eAAe,GAAG,WAAW,YAAY,GAAG,WAAW,WAAW,CAAC,IACtF,KAAK;AAAA,YACH,WAAW,eAAe;AAAA,YAC1B,WAAW,YAAY;AAAA,YACvB,WAAW,WAAW;AAAA,UACxB,MAAM,KAAK,KAAK,KAAK;AAAA,QACzB;AACA,cAAM,iBAAiB,KAAK;AAAA,WACzB,KAAK,IAAI,SAAS,eAAe,GAAG,SAAS,YAAY,GAAG,SAAS,WAAW,CAAC,IAChF,KAAK;AAAA,YACH,WAAW,eAAe;AAAA,YAC1B,WAAW,YAAY;AAAA,YACvB,WAAW,WAAW;AAAA,UACxB,MAAM,KAAK,KAAK,KAAK;AAAA,QACzB;AACA,cAAM,gBAAgB,KAAK;AAAA,WACxB,KAAK,IAAI,SAAS,eAAe,GAAG,SAAS,YAAY,GAAG,SAAS,WAAW,CAAC,IAChF,KAAK,IAAI,WAAW,eAAe,GAAG,WAAW,YAAY,GAAG,WAAW,WAAW,CAAC,MACpF,KAAK,KAAK,KAAK;AAAA,QACtB;AAMA,cAAM,oBAAoB,UAAU,cAAc;AAAA,UAChD,SAAO,IAAI,WAAW,iBAAiB,IAAI,SAAS;AAAA,QACtD;AACA,cAAM,oBAAoB,UAAU,cAAc;AAAA,UAChD,SAAO,IAAI,WAAW,iBAAiB,IAAI,SAAS;AAAA,QACtD;AAEA,YAAI;AACJ,YAAI,qBAAqB,mBAAmB;AAI1C,sBAAY,KAAK,OAAO,iBAAiB,YAAY,iBAAiBA,SAAQ;AAAA,QAChF,OAAO;AAEL,sBAAY,KAAK,OAAO,mBAAmB,aAAaA,SAAQ;AAAA,QAClE;AAEA,cAAM,aAAa,KAAK,OAAO,gBAAgB,KAAKA,SAAQ;AAM5D,cAAM,oBAAoB,UAAU,cAAc;AAAA,UAChD,SAAO,IAAI,WAAW,iBAAiB,IAAI,SAAS;AAAA,QACtD;AACA,YAAI,sBAAsB,SAAS,UAAU,SAAS,gBAAgB;AACpE,sBAAY,KAAK,IAAI,WAAW,OAAO;AAAA,QACzC;AAEA,kBAAU,IAAI,UAAU,IAAI,EAAE,MAAM,WAAW,OAAO,WAAW,CAAC;AAAA,MACpE;AACA,uBAAiB,kBAAkB,SAAS;AAAA,IAC9C;AAGA,qBAAiB,cAAc;AAC/B,qBAAiB,eAAe;AAEhC,eAAW,SAAS,QAAQ;AAC5B,kBAAc;AAAA,EAChB,CAAC;AACH;AAKA,SAAS,sBAAsB;AAC7B,MAAI,kBAAkB;AACpB,iBAAa;AAAA,EACf;AACF;AAKA,IAAI,0BAA0B;AAK9B,SAAS,wBAAwB;AAC/B,MAAI,CAAC,yBAAyB;AAC5B,WAAO,iBAAiB,aAAa,qBAAqB;AAC1D,WAAO,iBAAiB,WAAW,mBAAmB;AACtD,8BAA0B;AAAA,EAC5B;AACF;AA8EO,IAAM,cAAc,CAAC,YAAmD;AAC7E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,WAAW,CAAC;AAAA,IACZ;AAAA,IACA,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB;AAAA,IACA;AAAA,EACF,IAAI;AAGJ,QAAM,iBAAa,sBAAgB,KAAK;AACxC,QAAM,SAAS,QAAQ,UAAU;AAGjC,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAkB,KAAK;AAC3D,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAyD,IAAI;AAC7F,QAAM,CAAC,aAAa,cAAc,QAAI,wBAAiB,CAAC;AACxD,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAiB,CAAC;AAK1D,QAAM,yBAAqB,2BAAY,MAAuC;AAC5E,UAAMC,uBAAsB,CAAC,OAAa,UAAwB;AAChE,YAAM,MAAM,KAAK;AAAA,QACf,MAAM,eAAe;AAAA,QACrB,MAAM,YAAY;AAAA,QAClB,MAAM,WAAW;AAAA,MACnB;AACA,YAAM,MAAM,KAAK;AAAA,QACf,MAAM,eAAe;AAAA,QACrB,MAAM,YAAY;AAAA,QAClB,MAAM,WAAW;AAAA,MACnB;AACA,aAAO,KAAK,OAAO,MAAM,QAAQ,MAAO,KAAK,KAAK,GAAG;AAAA,IACvD;AAEA,UAAM,cAAcA,qBAAoB,kBAAkB,UAAU;AACpE,UAAM,WAAWA,qBAAoB,gBAAgB,gBAAgB;AAErE,UAAM,OAAO,KAAK,MAAM,cAAc,QAAQ;AAC9C,UAAM,QAAQ,KAAK,OAAO,WAAW,KAAK,QAAQ;AAElD,WAAO,EAAE,MAAM,MAAM;AAAA,EACvB,GAAG,CAAC,kBAAkB,gBAAgB,YAAY,QAAQ,CAAC;AAM3D,+BAAU,MAAM;AACd,QAAI,WAAW,WAAW,iBAAkB;AAC5C,UAAM,EAAE,MAAM,MAAM,IAAI,mBAAmB;AAC3C,mBAAe,IAAI;AACnB,oBAAgB,KAAK;AAAA,EACvB,GAAG,CAAC,kBAAkB,CAAC;AAOvB,+BAAU,MAAM;AACd,QAAI,CAAC,WAAW,WAAW,CAAC,iBAAkB;AAC9C,UAAM,gBAAgB,iBAAiB;AACvC,QAAI,kBAAkB,WAAY;AAClC,UAAM,YAAY,KAAK;AAAA,OACpB,KAAK,IAAI,cAAc,eAAe,GAAG,cAAc,YAAY,GAAG,cAAc,WAAW,CAAC,IAC/F,KAAK,IAAI,WAAW,eAAe,GAAG,WAAW,YAAY,GAAG,WAAW,WAAW,CAAC,MACtF,MAAO,KAAK,KAAK;AAAA,IACtB;AACA,UAAM,aAAa,YAAY;AAC/B,qBAAiB,eAAe;AAChC,qBAAiB,eAAe;AAChC,qBAAiB,aAAa;AAAA,EAChC,GAAG,CAAC,YAAY,QAAQ,CAAC;AAKzB,QAAM,qBAAiB,2BAAY,CAAC,MAAc,UAAkB;AAClE,mBAAe,IAAI;AACnB,oBAAgB,KAAK;AAErB,QAAI,qBAAqB,WAAW,SAAS;AAC3C,YAAM,OAAO,kBAAkB,QAAQ;AACvC,wBAAkB;AAAA,QAChB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,iBAAiB,CAAC;AAKtB,QAAM,qBAAiB,2BAAY,CAAC,WAAmB,eAAuB;AAC5E,UAAM,WAAW,WAAW;AAC5B,eAAW,UAAU;AAGrB,UAAM,YAAY,KAAK,MAAM,YAAY,QAAQ;AACjD,UAAM,eAAe,KAAK,MAAM,aAAa,QAAQ,IAAI;AAEzD,UAAM,eAAe,IAAI,KAAK,KAAK;AAAA,MACjC,WAAW,eAAe;AAAA,MAC1B,WAAW,YAAY;AAAA,MACvB,WAAW,WAAW,IAAI;AAAA,IAC5B,CAAC;AAED,UAAM,aAAa,IAAI,KAAK,KAAK;AAAA,MAC/B,WAAW,eAAe;AAAA,MAC1B,WAAW,YAAY;AAAA,MACvB,WAAW,WAAW,IAAI,YAAY;AAAA,IACxC,CAAC;AAGD,kBAAc,KAAK;AACnB,gBAAY,IAAI;AAGhB,QAAI,mBAAmB;AACrB,wBAAkB;AAAA,QAChB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,MAAM;AAAA,QACN,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI,UAAU;AACZ,UAAI,CAAC,sBAAsB,aAAa,SAAS,SAAS,GAAG;AAK3D,cAAM,cAAc,KAAK;AAAA,UACvB,iBAAiB,eAAe;AAAA,UAChC,iBAAiB,YAAY;AAAA,UAC7B,iBAAiB,WAAW;AAAA,QAC9B;AACA,cAAM,aAAa,KAAK;AAAA,UACtB,aAAa,eAAe;AAAA,UAC5B,aAAa,YAAY;AAAA,UACzB,aAAa,WAAW;AAAA,QAC1B;AACA,cAAM,iBAAiB,KAAK,OAAO,aAAa,gBAAgB,KAAK,KAAK,KAAK,IAAK;AAGpF,cAAM,YAAY,KAAK;AAAA,UACrB,eAAe,eAAe;AAAA,UAC9B,eAAe,YAAY;AAAA,UAC3B,eAAe,WAAW;AAAA,QAC5B;AACA,cAAM,WAAW,KAAK;AAAA,UACpB,WAAW,eAAe;AAAA,UAC1B,WAAW,YAAY;AAAA,UACvB,WAAW,WAAW;AAAA,QACxB;AACA,cAAM,eAAe,KAAK,OAAO,WAAW,cAAc,KAAK,KAAK,KAAK,IAAK;AAK9E,cAAM,YAAY,mBAAmB,IAAI,eAAe;AAaxD,cAAM,eAAe,mBAAmB,KAAK,iBAAiB;AAC9D,cAAM,qBAAqB,mBAAmB,IAC1C,0BAA0B,QAAQ,UAAU,CAAC,MAAM,IAAI,CAAC,IACxD,eACE,0BAA0B,QAAQ,UAAU,CAAC,MAAM,IAAI,CAAC,IACxD,0BAA0B,QAAQ,UAAU,CAAC,MAAM,MAAM,MAAM,IAAI,CAAC;AAE1E,YAAI,mBAAmB,SAAS,GAAG;AACjC,gBAAM,kBAAkB,SAAS,KAAK,OAAK,EAAE,OAAO,MAAM;AAC1D,gBAAM,gBAAwB;AAAA,YAC5B;AAAA,cACE,GAAI,mBAAmB,EAAE,IAAI,QAAQ,MAAM,IAAI,WAAW,IAAI,SAAS,GAAG;AAAA,cAC1E,WAAW,aAAa,YAAY;AAAA,cACpC,SAAS,WAAW,YAAY;AAAA,cAChC,GAAI,iBAAiB,gBAAgB;AAAA,gBACnC,cAAc,wBAAwB,iBAAiB,cAAc,YAAY,QAAQ;AAAA,cAC3F;AAAA,YACF;AAAA,YACA,GAAG,mBACA,OAAO,eAAa,CAAC,UAAU,MAAM,EACrC,IAAI,eAAa;AAClB,oBAAM,YAAY,IAAI,KAAK,UAAU,SAAmB;AACxD,oBAAM,UAAU,IAAI,KAAK,UAAU,OAAiB;AACpD,oBAAM,WAAW,IAAI,KAAK,KAAK;AAAA,gBAC7B,UAAU,eAAe;AAAA,gBAAG,UAAU,YAAY;AAAA,gBAAG,UAAU,WAAW,IAAI;AAAA,cAChF,CAAC;AACD,oBAAM,SAAS,IAAI,KAAK,KAAK;AAAA,gBAC3B,QAAQ,eAAe;AAAA,gBAAG,QAAQ,YAAY;AAAA,gBAAG,QAAQ,WAAW,IAAI;AAAA,cAC1E,CAAC;AACD,qBAAO,EAAE,GAAG,WAAW,WAAW,SAAS,YAAY,GAAG,SAAS,OAAO,YAAY,EAAE;AAAA,YAC1F,CAAC;AAAA,UACH;AACA,oBAAU,aAAa;AACvB;AAAA,QACF;AAAA,MACF;AAIA,UAAI,SAAS,SAAS,KAAK,WAAW;AACpC,cAAM,kBAAkB,SAAS,KAAK,OAAK,EAAE,OAAO,MAAM;AAC1D,cAAM,sBAAsB,iBAAiB,eACzC,wBAAwB,iBAAiB,cAAc,YAAY,QAAQ,IAC3E;AACJ,kBAAU,EAAE,IAAI,QAAQ,WAAW,cAAc,SAAS,YAAY,oBAAoB,CAAC;AAAA,MAC7F,WAAW,WAAW;AACpB,kBAAU,EAAE,IAAI,QAAQ,WAAW,cAAc,SAAS,WAAW,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,YAAY,WAAW,mBAAmB,QAAQ,oBAAoB,WAAW,UAAU,kBAAkB,cAAc,CAAC;AAK1I,QAAM,mBAAe,2BAAY,MAAM;AACrC,eAAW,UAAU;AACrB,kBAAc,KAAK;AACnB,gBAAY,IAAI;AAEhB,QAAI,mBAAmB;AACrB,wBAAkB;AAAA,QAChB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,MAAM;AAAA,QACN,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,mBAAmB,aAAa,YAAY,CAAC;AAKjD,+BAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,WAAW,WAAW,kBAAkB;AAE1C,mBAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAKL,QAAM,sBAAkB,2BAAY,CAAC,MAAwB;AAE3D,QAAI,OAAQ;AAEZ,UAAM,SAAS,EAAE;AACjB,UAAM,WAAW,eAAe,EAAE,SAAS,QAAQ,aAAa;AAGhE,QAAI,OAAuD;AAC3D,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,IACJ;AAEA,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AAGA,UAAM,cAAc;AACpB,UAAM,eAAe;AAGrB,eAAW,UAAU;AAGrB,kBAAc,IAAI;AAClB,gBAAY,IAAI;AAGhB,QAAI,mBAAmB;AACrB,wBAAkB;AAAA,QAChB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,MAAM;AAAA,QACN,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAGA,0BAAsB;AAGtB,uBAAmB;AAAA,MACjB;AAAA,MACA;AAAA,MACA,QAAQ,EAAE;AAAA,MACV;AAAA,MACA;AAAA,MACA,aAAa;AAAA;AAAA,MACb,cAAc;AAAA;AAAA,MACd;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA,cAAc,CAAC,qBACX,0BAA0B,QAAQ,UAAU,CAAC,MAAM,MAAM,MAAM,IAAI,CAAC,IACpE,CAAC;AAAA,MACL,gBAAgB,CAAC,qBACb,0BAA0B,QAAQ,UAAU,CAAC,IAAI,CAAC,IAClD,CAAC;AAAA,MACL,mBAAmB,CAAC,qBAChB,0BAA0B,QAAQ,UAAU,CAAC,MAAM,IAAI,CAAC,IACxD,CAAC;AAAA,MACL,iBAAiB,CAAC,qBACd,0BAA0B,QAAQ,UAAU,CAAC,MAAM,IAAI,CAAC,IACxD,CAAC;AAAA,MACL;AAAA,IACF;AAAA,EACF,GAAG,CAAC,eAAe,aAAa,cAAc,UAAU,YAAY,QAAQ,mBAAmB,gBAAgB,gBAAgB,cAAc,UAAU,oBAAoB,mBAAmB,WAAW,MAAM,CAAC;AAKhN,QAAM,qBAAiB,2BAAY,MAAc;AAC/C,QAAI,OAAQ,QAAO;AACnB,QAAI,YAAY;AACd,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,UAAU,CAAC;AAEvB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,MACf,aAAa;AAAA,MACb,OAAO;AAAA,QACL,QAAQ,eAAe;AAAA,QACvB,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;;;AF9oBkC,IAAAC,sBAAA;AAlIlC,IAAM,gBAAgB,CAAC,WAAyB,cAA4B;AAC1E,SACE,UAAU,KAAK,OAAO,UAAU,KAAK,MACrC,UAAU,KAAK,SAAS,UAAU,KAAK,QACvC,UAAU,KAAK,cAAc,UAAU,KAAK,aAC5C,UAAU,KAAK,YAAY,UAAU,KAAK,WAC1C,UAAU,KAAK,UAAU,UAAU,KAAK,SACxC,UAAU,KAAK,aAAa,UAAU,KAAK,YAC3C,UAAU,KAAK,aAAa,UAAU,KAAK,YAC3C,UAAU,WAAW,QAAQ,MAAM,UAAU,WAAW,QAAQ,KAChE,UAAU,aAAa,UAAU,YACjC,UAAU,cAAc,UAAU,aAClC,UAAU,kBAAkB,SAAS,UAAU,kBAAkB,QACjE,UAAU,kBAAkB,UAAU,UAAU,kBAAkB,SAClE,UAAU,aAAa,UAAU,YACjC,UAAU,uBAAuB,UAAU,sBAC3C,UAAU,KAAK,WAAW,UAAU,KAAK,UACzC,UAAU,KAAK,YAAY,UAAU,KAAK;AAG9C;AAQA,IAAM,UAAkC,cAAAC,QAAM;AAAA,EAC5C,CAAC,EAAE,MAAM,YAAY,UAAU,WAAW,UAAU,mBAAmB,UAAU,UAAU,oBAAoB,oBAAoB,kBAAkB,mBAAmB,WAAW,QAAQ,MAAM;AAE/L,UAAM,EAAE,SAAS,YAAY,IAAI;AAGjC,UAAM,oBAAgB,uBAAQ,MAAM,aAAa,KAAK,SAAS,GAAG,CAAC,KAAK,SAAS,CAAC;AAClF,UAAM,kBAAc,uBAAQ,MAAM,aAAa,KAAK,OAAO,GAAG,CAAC,KAAK,OAAO,CAAC;AAG5E,UAAM,EAAE,MAAM,MAAM,QAAI;AAAA,MACtB,MAAM,iBAAiB,eAAe,aAAa,YAAY,QAAQ;AAAA,MACvE,CAAC,eAAe,aAAa,YAAY,QAAQ;AAAA,IACnD;AAGA,UAAM,WAAW,KAAK,SAAS;AAG/B,UAAM,oBAAgB,uBAAQ,MAAM;AAClC,UAAI,KAAK,aAAa,UAAa,KAAK,YAAY,EAAG,QAAO;AAC9D,aAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,QAAQ,CAAC,CAAC;AAAA,IAC7D,GAAG,CAAC,KAAK,QAAQ,CAAC;AAGlB,UAAM,oBAAgB,uBAAQ,MAAM;AAClC,UAAI,kBAAkB,KAAK;AACzB,eAAO,KAAK,WACR,4CACA;AAAA,MACN;AAEA,YAAM,YAAY,KAAK,SAAS;AAChC,aAAO,sBAAsB,SAAS;AAAA,IACxC,GAAG,CAAC,eAAe,KAAK,UAAU,KAAK,KAAK,CAAC;AAG7C,UAAM,gBAAgB,CAAC,WAAuG;AAC5H,YAAM,cAAoB;AAAA,QACxB,GAAG;AAAA,QACH,WAAW,OAAO,UAAU,YAAY;AAAA,QACxC,SAAS,OAAO,QAAQ,YAAY;AAAA,QACpC,GAAI,OAAO,wBAAwB,UAAa,EAAE,cAAc,OAAO,oBAAoB;AAAA,MAC7F;AACA,iBAAW,WAAW;AAAA,IACxB;AAGA,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,YAAY;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,kBAAkB;AAAA,MAClB,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA,eAAe;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,IACF,CAAC;AAGD,UAAM,cAAc,kBAAkB,SAAS,aAAa,cAAc;AAC1E,UAAM,eAAe,kBAAkB,UAAU,aAAa,eAAe;AAG7E,UAAM,mBAAmB,aACrB,aAAa,aAAa,YAAY,QAAQ,IAC9C;AACJ,UAAM,iBAAiB,aACnB,aAAa,cAAc,eAAe,UAAU,YAAY,QAAQ,IACxE;AAEJ,UAAM,iBAAiB,gBAAgB,gBAAgB;AACvD,UAAM,eAAe,gBAAgB,cAAc;AAGnD,UAAM,eAAe,KAAK;AAAA,OACvB,eAAe,QAAQ,IAAI,iBAAiB,QAAQ,MAAM,MAAO,KAAK,KAAK;AAAA,IAC9E,IAAI;AAIJ,UAAM,qBAAqB,gBAAgB,KAAK,KAAK;AACrD,UAAM,qBAAqB,gBAAgB,KAAK,eAAe;AAE/D,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,GAAG,SAAS,KAAK;AAAA,QAEjC;AAAA,0BAAgB,SAAS,6CAAC,SAAI,WAAU,yCAAwC;AAAA,UACjF,8CAAC,SAAI,WAAU,0BACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAY;AAAA,gBACZ,WAAW,oBAAoB,aAAa,sBAAsB,EAAE,IAAI,KAAK,SAAS,oBAAoB,EAAE;AAAA,gBAC5G,OAAO;AAAA,kBACL,MAAM,GAAG,WAAW;AAAA,kBACpB,OAAO,GAAG,YAAY;AAAA,kBACtB,iBAAiB;AAAA,kBACjB,QAAQ;AAAA,kBACR,QAAQ,gBAAgB,MAAM;AAAA,kBAC9B,YAAY,gBAAgB,MAAM;AAAA,gBACpC;AAAA,gBACA,aAAa,gBAAgB;AAAA,gBAE5B;AAAA,kCAAgB,KACf;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,OAAO;AAAA,wBACL,OAAO,GAAG,aAAa;AAAA,wBACvB,iBAAiB;AAAA,sBACnB;AAAA;AAAA,kBACF;AAAA,kBAEF,6CAAC,SAAI,WAAU,mDAAkD;AAAA,kBACjE,8CAAC,UAAK,WAAU,yBACb;AAAA;AAAA,oBAAa;AAAA,qBAChB;AAAA,kBACC,gBAAgB,KAAK,sBACpB,8CAAC,UAAK,WAAU,yBACb;AAAA;AAAA,oBAAc;AAAA,qBACjB;AAAA,kBAEF,6CAAC,SAAI,WAAU,oDAAmD;AAAA;AAAA;AAAA,YACpE;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW,uBAAuB,KAAK,SAAS,+BAA+B,EAAE;AAAA,gBACjF,OAAO;AAAA,kBACL,MAAM,GAAG,WAAW;AAAA,gBACtB;AAAA,gBAEA,wDAAC,UAAK,WAAU,6CACb;AAAA;AAAA,kBAAe;AAAA,kBAAE;AAAA,mBACpB;AAAA;AAAA,YACF;AAAA,YACC,KAAK,UACJ;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA,kBACL,UAAU;AAAA,kBACV,MAAM,GAAG,cAAc,EAAE;AAAA,kBACzB,KAAK;AAAA,kBACL,WAAW;AAAA,kBACX,OAAO;AAAA,kBACP,QAAQ;AAAA,kBACR,OAAO;AAAA,kBACP,eAAe;AAAA,gBACjB;AAAA,gBACA,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,cAAW;AAAA,gBACX,eAAY;AAAA,gBAEZ,uDAAC,UAAK,GAAE,sOAAqO;AAAA;AAAA,YAC/O;AAAA,YAEF;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA,kBACL,MAAM,GAAG,cAAc,YAAY;AAAA,gBACrC;AAAA,gBAEC;AAAA,kCAAgB,KAAK,CAAC,sBACrB,8CAAC,UAAK,WAAU,6BACb;AAAA;AAAA,oBAAc;AAAA,qBACjB;AAAA,kBAEF,6CAAC,UAAK,WAAU,6BACb,eAAK,MACR;AAAA;AAAA;AAAA,YACF;AAAA,aACF;AAAA,UACC,gBAAgB,YAAY,6CAAC,SAAI,WAAU,4CAA2C;AAAA;AAAA;AAAA,IACzF;AAAA,EAEJ;AAAA,EACA;AACF;AAEA,QAAQ,cAAc;AAEtB,IAAO,kBAAQ;;;AG5Rf,IAAAC,gBAA+B;AAuC3B,IAAAC,sBAAA;AAtBJ,IAAM,iBAAgD,CAAC,EAAE,YAAY,SAAS,MAAM;AAElF,QAAM,QAAQ,oBAAI,KAAK;AACvB,QAAM,aAAa,IAAI,KAAK,KAAK;AAAA,IAC/B,MAAM,YAAY;AAAA,IAClB,MAAM,SAAS;AAAA,IACf,MAAM,QAAQ;AAAA,EAChB,CAAC;AAID,QAAM,eAAW,uBAAQ,MAAM;AAC7B,UAAM,SAAS,aAAa,YAAY,UAAU;AAClD,WAAO,KAAK,MAAM,SAAS,QAAQ;AAAA,EACrC,GAAG,CAAC,YAAY,UAAU,UAAU,CAAC;AAGrC,MAAI,MAAM,QAAQ,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO;AAAA,QACL,MAAM,GAAG,QAAQ;AAAA,QACjB,OAAO;AAAA,QACP,iBAAiB;AAAA,MACnB;AAAA,MACA,cAAW;AAAA;AAAA,EACb;AAEJ;AAEA,IAAO,yBAAQ;;;ACnDf,IAAAC,gBAA+B;AA0DzB,IAAAC,sBAAA;AAtCN,IAAMC,iBAAgB,CAAC,WAAgC,cAAmC;AACxF,SACE,UAAU,aAAa,UAAU,YACjC,UAAU,UAAU,WAAW,UAAU,UAAU,UACnD,UAAU,gBAAgB,UAAU;AAExC;AAcA,IAAM,iBAAgD,cAAAC,QAAM;AAAA,EAC1D,CAAC,EAAE,WAAW,UAAU,YAAY,MAAM;AAExC,UAAM,gBAAY,uBAAoB,MAAM;AAC1C,aAAO,mBAAmB,WAAW,QAAQ;AAAA,IAC/C,GAAG,CAAC,WAAW,QAAQ,CAAC;AAGxB,UAAM,oBAAgB,uBAAQ,MAAM;AAClC,aAAO,uBAAuB,WAAW,QAAQ;AAAA,IACnD,GAAG,CAAC,WAAW,QAAQ,CAAC;AAGxB,UAAM,gBAAY,uBAAQ,MAAM;AAC9B,aAAO,KAAK,MAAM,UAAU,SAAS,QAAQ;AAAA,IAC/C,GAAG,CAAC,UAAU,QAAQ,QAAQ,CAAC;AAE/B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,OAAO,GAAG,SAAS;AAAA,UACnB,QAAQ,GAAG,WAAW;AAAA,QACxB;AAAA,QAGC;AAAA,wBAAc,IAAI,CAAC,OAAO,UACzB;AAAA,YAAC;AAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,MAAM,GAAG,MAAM,IAAI;AAAA,gBACnB,OAAO,GAAG,MAAM,KAAK;AAAA,cACvB;AAAA;AAAA,YALK,WAAW,KAAK;AAAA,UAMvB,CACD;AAAA,UAGA,UAAU,IAAI,CAAC,MAAM,UAAU;AAE9B,kBAAM,YAAY,KAAK,eACnB,4BACA,KAAK,cACH,2BACA;AAEN,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAW,qBAAqB,SAAS;AAAA,gBACzC,OAAO;AAAA,kBACL,MAAM,GAAG,KAAK,CAAC;AAAA,gBACjB;AAAA;AAAA,cAJK,YAAY,KAAK;AAAA,YAKxB;AAAA,UAEJ,CAAC;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAAA,EACAD;AACF;AAEA,eAAe,cAAc;AAE7B,IAAO,yBAAQ;;;AC7EX,IAAAE,sBAAA;AAhBJ,IAAM,iBAAgD,CAAC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,MAAI,CAAC,cAAc,CAAC,UAAU;AAC5B,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,aAAa,UAAU,aAAa;AACzD,QAAM,gBAAgB,aAAa,UAAU,aAAa;AAE1D,SACE,8EACG;AAAA,oBACC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,MAAM,GAAG,IAAI;AAAA,UACb,QAAQ,GAAG,WAAW;AAAA,QACxB;AAAA;AAAA,IACF;AAAA,IAED,iBACC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,MAAM,GAAG,OAAO,KAAK;AAAA,UACrB,QAAQ,GAAG,WAAW;AAAA,QACxB;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;AAEA,IAAO,yBAAQ;;;AClDf,IAAAC,gBAA+B;AAsLzB,IAAAC,sBAAA;AA3KN,SAAS,sBACP,MACA,cACA,cACA,YACA,UACQ;AACR,QAAM,YAAY,aAAa,aAAa,MAAM,YAAY,QAAQ;AACtE,QAAM,UAAY,aAAa,aAAa,QAAQ,UAAU,YAAY,QAAQ;AAClF,QAAM,YAAY,aAAa,aAAa,MAAM,YAAY,QAAQ;AACtE,QAAM,UAAY,aAAa,aAAa,QAAQ,UAAU,YAAY,QAAQ;AAClF,SAAO,oBAAoB,KAAK,MAAkB,WAAW,SAAS,WAAW,OAAO;AAC1F;AA4BO,IAAM,kBAAkD,cAAAC,QAAM,KAAK,CAAC;AAAA,EACzE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AAEJ,QAAM,EAAE,eAAe,YAAY,QAAI,uBAAQ,MAAM;AACnD,UAAM,YAAY,oBAAI,IAA6D;AACnF,UAAM,UAAU,oBAAI,IAAoB;AAExC,UAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,YAAM,YAAY,IAAI,KAAK,KAAK,SAAS;AACzC,YAAM,UAAU,IAAI,KAAK,KAAK,OAAO;AACrC,YAAM,WAAW,iBAAiB,WAAW,SAAS,YAAY,QAAQ;AAG1E,YAAM,WAAW,eAAe,IAAI,KAAK,EAAE;AAC3C,YAAM,eAAe,UAAU,QAAQ,SAAS;AAChD,YAAM,gBAAgB,UAAU,SAAS,SAAS;AAElD,cAAQ,IAAI,KAAK,IAAI,KAAK;AAC1B,gBAAU,IAAI,KAAK,IAAI;AAAA,QACrB,MAAM;AAAA,QACN,OAAO,eAAe;AAAA,QACtB,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH,CAAC;AAED,WAAO,EAAE,eAAe,WAAW,aAAa,QAAQ;AAAA,EAC1D,GAAG,CAAC,OAAO,YAAY,UAAU,WAAW,aAAa,CAAC;AAG1D,QAAM,gBAAY,uBAAQ,MAAM;AAC9B,UAAM,SAAS,aAAa,KAAK;AACjC,UAAM,eAAe,IAAI,IAAI,OAAO,aAAa,CAAC,CAAC;AACnD,WAAO;AAAA,EACT,GAAG,CAAC,KAAK,CAAC;AAGV,QAAM,YAAQ,uBAAQ,MAAM;AAC1B,UAAM,QAAQ,sBAAsB,KAAK;AACzC,UAAMC,SASD,CAAC;AAEN,eAAW,QAAQ,OAAO;AACxB,YAAM,cAAc,cAAc,IAAI,KAAK,aAAa;AACxD,YAAM,YAAY,cAAc,IAAI,KAAK,WAAW;AACpD,YAAM,mBAAmB,YAAY,IAAI,KAAK,aAAa;AAC3D,YAAM,iBAAiB,YAAY,IAAI,KAAK,WAAW;AAEvD,UAAI,CAAC,eAAe,CAAC,aAAa,qBAAqB,UAAa,mBAAmB,QAAW;AAChG;AAAA,MACF;AAGA,YAAM,eAAe,mBAAmB;AAGxC,UAAI;AACJ,UAAI;AAEJ,UAAI,cAAc;AAEhB,gBAAQ,YAAY,SAAS;AAC7B,cAAM,UAAU,SAAS,YAAY;AAAA,MACvC,OAAO;AAEL,gBAAQ,YAAY,SAAS,YAAY;AACzC,cAAM,UAAU,SAAS;AAAA,MAC3B;AAOA,YAAM,QAAS,KAAK,SAAS,QAAQ,KAAK,SAAS,OAC/C,YAAY,OACZ,YAAY;AAEhB,YAAM,MAAO,KAAK,SAAS,QAAQ,KAAK,SAAS,OAC7C,UAAU,QACV,UAAU;AAEd,YAAM,mBAAmB,KAAK,SAAS,QAAQ,KAAK,SAAS;AAE7D,YAAM,OAAO,EAAE,GAAG,OAAO,GAAG,MAAM;AAClC,YAAM,KAAK,EAAE,GAAG,KAAK,GAAG,IAAI;AAE5B,YAAM,OAAO,wBAAwB,MAAM,IAAI,gBAAgB;AAG/D,YAAM,WAAW,UAAU,IAAI,KAAK,aAAa,KAAK,UAAU,IAAI,KAAK,WAAW;AAGpF,YAAM,MAAM,sBAAsB,MAAM,aAAa,WAAW,YAAY,QAAQ;AAEpF,MAAAA,OAAM,KAAK;AAAA,QACT,IAAI,GAAG,KAAK,aAAa,IAAI,KAAK,WAAW,IAAI,KAAK,IAAI;AAAA,QAC1D;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAOA;AAAA,EACT,GAAG,CAAC,OAAO,eAAe,aAAa,WAAW,YAAY,UAAU,aAAa,CAAC;AAEtF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,MAAM,SAAS;AAAA,MACvB,OAAM;AAAA,MAEN;AAAA,sDAAC,UAEC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,aAAY;AAAA,cACZ,cAAa;AAAA,cACb,aAAY;AAAA,cACZ,MAAK;AAAA,cACL,MAAK;AAAA,cACL,QAAO;AAAA,cAEP;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAO;AAAA,kBACP,MAAK;AAAA;AAAA,cACP;AAAA;AAAA,UACF;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,aAAY;AAAA,cACZ,cAAa;AAAA,cACb,aAAY;AAAA,cACZ,MAAK;AAAA,cACL,MAAK;AAAA,cACL,QAAO;AAAA,cAEP;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAO;AAAA,kBACP,MAAK;AAAA;AAAA,cACP;AAAA;AAAA,UACF;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,aAAY;AAAA,cACZ,cAAa;AAAA,cACb,aAAY;AAAA,cACZ,MAAK;AAAA,cACL,MAAK;AAAA,cACL,QAAO;AAAA,cAEP;AAAA,gBAAC;AAAA;AAAA,kBACC,QAAO;AAAA,kBACP,MAAK;AAAA;AAAA,cACP;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEC,MAAM,IAAI,CAAC,EAAE,IAAI,MAAM,UAAU,KAAK,OAAO,KAAK,OAAO,aAAa,MAAM;AAC3E,gBAAM,aACJ,eAAe,QACf,OAAO,GAAG,YAAY,aAAa,IAAI,YAAY,WAAW,IAAI,YAAY,QAAQ;AAExF,cAAI,gBAAgB;AACpB,cAAI,WAAY,kBAAiB;AAAA,mBACxB,SAAU,kBAAiB;AAEpC,cAAI;AACJ,cAAI,WAAY,aAAY;AAAA,mBACnB,SAAU,aAAY;AAAA,cAC1B,aAAY;AAEjB,gBAAM,WAAW,aACb,YACA,WACE,iDACA;AAEN,iBACE,8CAAC,cAAAD,QAAM,UAAN,EACC;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,GAAG;AAAA,gBACH,WAAW;AAAA,gBACX;AAAA;AAAA,YACF;AAAA,YACC,QAAQ,KACP;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,GAAG,MAAM,IAAI,MAAM,KAAK,MAAM;AAAA,gBAC9B,GAAG,eAAe,QAAQ,IAAI,QAAQ;AAAA,gBACtC,YAAW;AAAA,gBACX,UAAS;AAAA,gBACT,MAAM;AAAA,gBAEL,gBAAM,IAAI,IAAI,GAAG,KAAK,GAAG,GAAG;AAAA;AAAA,YAC/B;AAAA,eAhBiB,EAkBrB;AAAA,QAEJ,CAAC;AAAA;AAAA;AAAA,EACH;AAEJ,CAAC;AAED,gBAAgB,cAAc;AAE9B,IAAO,0BAAQ;;;ACxRf,IAAAE,iBAAyE;;;ACCzE,mBAA8B;AA+B1B,IAAAC,sBAAA;AAFG,IAAM,UAAkC,CAAC,EAAE,MAAM,cAAc,SAAS,MAAM;AACnF,SACE,6CAAc,mBAAb,EAAkB,MAAY,cAC5B,UACH;AAEJ;AAKO,IAAM,iBAA8B;AAKpC,IAAM,iBAAgD,CAAC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,mBAAmB;AACrB,MAAM;AACJ,QAAM,UACJ;AAAA,IAAc;AAAA,IAAb;AAAA,MACC,WAAW,gBAAgB,YAAY,IAAI,SAAS,KAAK,EAAE;AAAA,MAC3D;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MAEX;AAAA;AAAA,EACH;AAGF,MAAI,QAAQ;AACV,WAAO,6CAAc,qBAAb,EAAqB,mBAAQ;AAAA,EACvC;AAEA,SAAO;AACT;;;ACvEA,IAAAC,iBAAyE;;;ACAzE,IAAAC,gBAAkB;AAaZ,IAAAC,sBAAA;AAHC,IAAM,QAAQ,cAAAC,QAAM;AAAA,EACzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAAQ;AAChC,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW,cAAc,YAAY,IAAI,SAAS,KAAK,EAAE;AAAA,QACxD,GAAG;AAAA;AAAA,IACN;AAAA,EAEJ;AACF;AAEA,MAAM,cAAc;;;ACtBpB,IAAAC,gBAA6C;AAC7C,IAAAC,mBAAgC;;;ACDhC,IAAAC,gBAMO;AACP,IAAAC,mBAYO;AACP,IAAAC,iBAAmB;AAoGX,IAAAC,sBAAA;AA1FR,SAAS,gBAAgB,KAAW,UAAoC;AACtE,QAAM,UAAoB,CAAC,eAAe;AAE1C,MAAI,gBAAY,4BAAU,KAAK,QAAQ,EAAG,SAAQ,KAAK,UAAU;AACjE,UAAI,0BAAQ,GAAG,EAAG,SAAQ,KAAK,OAAO;AACtC,UAAI,4BAAU,GAAG,EAAG,SAAQ,KAAK,SAAS;AAC1C,UAAI,2BAAS,SAAK,6BAAW,oBAAI,KAAK,CAAC,CAAC,KAAK,KAAC,0BAAQ,GAAG,EAAG,SAAQ,KAAK,MAAM;AAE/E,SAAO,QAAQ,KAAK,GAAG;AACzB;AAEO,IAAM,WAAoC,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,WAAW;AACb,MAAM;AACJ,QAAM,gBAAY,sBAAuB,IAAI;AAE7C,QAAM,mBAAe;AAAA,IACnB,UAAM,+BAAa,eAAe,YAAY,oBAAI,KAAK,CAAC;AAAA;AAAA,IAExD,CAAC;AAAA,EACH;AAEA,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAAiB,MAAM;AAAA,QACjD,4BAAU,cAAc,CAAC;AAAA,IACzB;AAAA,QACA,4BAAU,cAAc,CAAC;AAAA,EAC3B,CAAC;AAED,QAAM,qBAAiB,2BAAY,CAAC,cAA6B;AAC/D,cAAU,CAAC,SAAS;AAClB,UAAI,cAAc,MAAM;AACtB,eAAO,KAAC,4BAAU,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI;AAAA,MACxC,OAAO;AACL,eAAO,CAAC,GAAG,UAAM,4BAAU,KAAK,KAAK,SAAS,CAAC,GAAG,CAAC,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,+BAAU,MAAM;AACd,UAAM,YAAY,UAAU;AAC5B,QAAI,CAAC,UAAW;AAEhB,UAAM,eAAe,MAAM;AACzB,UAAI,UAAU,aAAa,KAAK;AAC9B,cAAM,mBAAmB,UAAU;AACnC,cAAM,gBAAgB,UAAU;AAChC,uBAAe,IAAI;AACnB,mBAAW,MAAM;AACf,oBAAU,YACR,UAAU,eAAe,mBAAmB;AAAA,QAChD,GAAG,CAAC;AAAA,MACN,WACE,UAAU,YAAY,UAAU,gBAChC,UAAU,eAAe,KACzB;AACA,uBAAe,MAAM;AAAA,MACvB;AAAA,IACF;AAEA,cAAU,iBAAiB,UAAU,YAAY;AACjD,WAAO,MAAM,UAAU,oBAAoB,UAAU,YAAY;AAAA,EACnE,GAAG,CAAC,cAAc,CAAC;AAGnB,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,QAAS;AACxB,UAAM,SAAS,YAAY,eAAe,oBAAI,KAAK;AACnD,UAAM,eAAW,6BAAO,+BAAa,MAAM,GAAG,SAAS;AACvD,UAAM,KAAK,UAAU,QAAQ,cAAc,gBAAgB,QAAQ,IAAI;AACvE,QAAI,IAAI;AACN,MAAC,GAAmB,eAAe,EAAE,UAAU,QAAQ,OAAO,QAAQ,CAAC;AAAA,IACzE;AAAA,EAGF,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAc;AAAA,IAClB,CAAC,UAAgB;AACf,YAAM,eAAW,+BAAa,KAAK;AACnC,YAAM,gBAAY,iCAAe,KAAK;AAEtC,YAAM,iBAAa,yBAAO,QAAQ,IAAI,KAAK;AAC3C,YAAM,eAAW,yBAAO,OAAO,SAAS;AACxC,YAAM,iBAAa,yBAAO,OAAO,aAAa,EAAE,QAAQ,kBAAG,CAAC;AAE5D,YAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,UAAU,GAAG,CAAC,GAAG,MACvD,6CAAC,SAAmB,WAAU,yBAApB,KAAK,CAAC,EAAoC,CACrD;AAED,YAAM,WAAW,MAAM,KAAK,EAAE,QAAQ,UAAU,GAAG,CAAC,GAAG,MAAM;AAC3D,cAAM,SAAS,IAAI;AACnB,cAAM,MAAM,IAAI,KAAK,MAAM,YAAY,GAAG,MAAM,SAAS,GAAG,MAAM;AAClE,cAAM,YAAY,gBAAgB,KAAK,QAAQ;AAC/C,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL;AAAA,YACA;AAAA,YACA,SAAS,MAAM;AACb,kBAAI,CAAC,YAAY,UAAU;AACzB,yBAAS,IAAI,KAAK,MAAM,YAAY,GAAG,MAAM,SAAS,GAAG,MAAM,CAAC;AAAA,cAClE;AAAA,YACF;AAAA,YAEC;AAAA;AAAA,UAVI;AAAA,QAWP;AAAA,MAEJ,CAAC;AAED,aACE,8CAAC,SAAmB,WAAU,mBAAkB,cAAY,UAC1D;AAAA,qDAAC,SAAI,WAAU,0BAA0B,sBAAW;AAAA,QACpD,8CAAC,SAAI,WAAU,wBACZ;AAAA;AAAA,UACA;AAAA,WACH;AAAA,WALQ,QAMV;AAAA,IAEJ;AAAA,IACA,CAAC,UAAU,UAAU,QAAQ;AAAA,EAC/B;AAEA,QAAM,qBAAiB;AAAA,IACrB,MAAM,OAAO,IAAI,WAAW;AAAA,IAC5B,CAAC,QAAQ,WAAW;AAAA,EACtB;AAEA,SACE,6CAAC,SAAI,KAAK,WAAW,WAAU,uBAC5B,0BACH;AAEJ;AAEA,SAAS,cAAc;;;ADzGnB,IAAAC,uBAAA;AAtCG,IAAM,aAAwC,CAAC;AAAA,EACpD;AAAA,EACA;AAAA,EACA,QAAQ,gBAAgB;AAAA,EACxB,cAAc;AAAA,EACd,SAAS;AAAA,EACT;AAAA,EACA,WAAW;AACb,MAAM;AACJ,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,KAAK;AAGtC,QAAM,gBAAkC,MAAM;AAC5C,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,IAAI,oBAAI,KAAK,QAAQ,YAAY;AACvC,eAAO,0BAAQ,CAAC,IAAI,IAAI;AAAA,EAC1B,GAAG;AAGH,QAAM,eAAe,mBACjB,yBAAO,cAAc,aAAa,IAClC;AAEJ,QAAM,mBAAe;AAAA,IACnB,CAAC,QAAc;AAEb,YAAM,MAAM;AAAA,QACV,IAAI,YAAY;AAAA,QAChB,OAAO,IAAI,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,QAC1C,OAAO,IAAI,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MACvC,EAAE,KAAK,GAAG;AACV,iBAAW,GAAG;AACd,cAAQ,KAAK;AAAA,IACf;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,SACE,+CAAC,WAAQ,MAAY,cAAc,WAAW,SAAY,SACxD;AAAA,kDAAC,kBAAe,SAAO,MACrB;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,2BAA2B,YAAY,IAAI,SAAS,KAAK,EAAE;AAAA,QACtE;AAAA,QACA,SAAS,CAAC,MAAM;AACd,YAAE,gBAAgB;AAAA,QACpB;AAAA,QAEC;AAAA;AAAA,IACH,GACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAM;AAAA,QACN,MAAK;AAAA,QAEL;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,UAAU;AAAA,YACV,UAAU;AAAA,YACV,aAAa;AAAA;AAAA,QACf;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAEA,WAAW,cAAc;;;AE3FvB,IAAAC,uBAAA;AADF,IAAM,YAAY,MAChB,+CAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACxK;AAAA,gDAAC,UAAK,GAAE,kBAAiB;AAAA,EAAE,8CAAC,UAAK,GAAE,2BAA0B;AAAA,GAC/D;AAGF,IAAM,YAAY,MAChB,+CAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACxK;AAAA,gDAAC,UAAK,GAAE,WAAU;AAAA,EAAE,8CAAC,UAAK,GAAE,YAAW;AAAA,EAAE,8CAAC,UAAK,GAAE,kBAAiB;AAAA,GACpE;AAGF,IAAM,YAAY,MAChB,+CAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACxK;AAAA,gDAAC,UAAK,GAAE,YAAW;AAAA,EAAE,8CAAC,UAAK,GAAE,kBAAiB;AAAA,EAAE,8CAAC,UAAK,GAAE,YAAW;AAAA,GACrE;AAGF,IAAM,YAAY,MAChB,+CAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACxK;AAAA,gDAAC,UAAK,GAAE,kBAAiB;AAAA,EAAE,8CAAC,UAAK,GAAE,6BAA4B;AAAA,GACjE;AAGK,IAAM,kBAA8C;AAAA,EACzD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEO,IAAM,mBAA6C;AAAA,EACxD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;;;AJTE,IAAAC,uBAAA;AADF,IAAM,YAAY,MAChB,+CAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACxK;AAAA,gDAAC,UAAK,GAAE,4CAA2C;AAAA,EACnD,8CAAC,UAAK,GAAE,WAAU;AAAA,EAClB,8CAAC,UAAK,GAAE,0CAAyC;AAAA,GACnD;AAGF,SAAS,qBAAqB,MAAgB,KAAiC;AAC7E,QAAM,eAAe,OAAO;AAE5B,MAAI,SAAS,MAAM;AACjB,QAAI,eAAe,EAAG,QAAO,uEAAgB,YAAY;AACzD,QAAI,eAAe,EAAG,QAAO,qDAAa,KAAK,IAAI,YAAY,CAAC;AAChE,WAAO;AAAA,EACT;AACA,MAAI,SAAS,MAAM;AACjB,QAAI,eAAe,EAAG,QAAO,yFAAmB,YAAY;AAC5D,QAAI,eAAe,EAAG,QAAO,uEAAgB,KAAK,IAAI,YAAY,CAAC;AACnE,WAAO;AAAA,EACT;AACA,MAAI,SAAS,MAAM;AACjB,QAAI,eAAe,EAAG,QAAO,uEAAgB,YAAY;AACzD,QAAI,eAAe,EAAG,QAAO,qDAAa,KAAK,IAAI,YAAY,CAAC;AAChE,WAAO;AAAA,EACT;AACA,MAAI,SAAS,MAAM;AACjB,QAAI,eAAe,EAAG,QAAO,yFAAmB,YAAY;AAC5D,QAAI,eAAe,EAAG,QAAO,uEAAgB,KAAK,IAAI,YAAY,CAAC;AACnE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,IAAM,UAAkC,CAAC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,aACJ,cAAc,gBAAgB,UAC9B,cAAc,kBAAkB,IAAI,UACpC,cAAc,aAAa,IAAI;AAEjC,QAAM,cAAc,CAAC,MAAwB;AAC3C,MAAE,gBAAgB;AAClB,QAAI,yBAA0B;AAC9B,mBAAe,aAAa,OAAO,EAAE,aAAa,QAAQ,eAAe,IAAI,QAAQ,UAAU,IAAI,KAAK,CAAC;AACzG,QAAI,CAAC,YAAY;AACf,mBAAa,MAAM;AACnB,uBAAiB,MAAM;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,mBAAmB,CAAC,MAAwB;AAChD,MAAE,gBAAgB;AAClB,yBAAqB,QAAQ,IAAI,QAAQ,IAAI,IAAI;AACjD,sBAAkB;AAAA,EACpB;AAEA,QAAM,OAAO,gBAAgB,IAAI,IAAI;AACrC,QAAM,YAAY,qBAAqB,IAAI,MAAM,GAAG;AACpD,QAAM,UAAU,mBAAmB,IAAI;AAEvC,SACE,+CAAC,WAAQ,MAAM,YAAY,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,mBAAkB;AAAA,EAAG,GACnF;AAAA,mDAAC,UAAK,WAAU,6BACd;AAAA,oDAAC,kBAAe,SAAO,MACrB;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,oBAAoB,aAAa,gCAAgC,EAAE;AAAA,UAE9E,SAAS;AAAA,UAET,0FAAE;AAAA,0DAAC,QAAK;AAAA,YAAG,OAAO,QAAQ,QAAQ,IAAK,MAAM,IAAI,IAAI,GAAG,KAAK,GAAG,GAAG,KAAM;AAAA,aAAG;AAAA;AAAA,MAC9E,GACF;AAAA,MACC,CAAC,4BACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,cAAW;AAAA,UACX,SAAS;AAAA,UAET,wDAAC,aAAU;AAAA;AAAA,MACb;AAAA,OAEJ;AAAA,IACA,+CAAC,kBAAe,QAAQ,MAAM,MAAK,UAAS,OAAM,SAAQ,WAAU,6BAClE;AAAA,oDAAC,UAAK,WAAU,4BAA4B,qBAAU;AAAA,MACtD,8CAAC,UAAK,WAAU,0BAA0B,mBAAQ;AAAA,OACpD;AAAA,KACF;AAEJ;AAuCA,IAAM,YAAY,CAAC,UAAiC;AAClD,MAAI,iBAAiB,KAAM,QAAO,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAElE,MAAI,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG,EAAG,QAAO,MAAM,MAAM,GAAG,EAAE,CAAC;AAC/E,SAAO;AACT;AAEO,IAAM,cAA0C,eAAAC,QAAM;AAAA,EAC3D,CAAC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,yBAAyB;AAAA,IACzB,2BAA2B;AAAA,IAC3B,WAAW,CAAC;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,MAAM;AACJ,UAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,KAAK;AACpD,UAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,EAAE;AAC7C,UAAM,mBAAe,uBAAyB,IAAI;AAClD,UAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,KAAK;AAEtD,UAAM,aAAa,mBAAmB,KAAK;AAG3C,UAAM,YAAY,2BAA2B;AAC7C,UAAM,cAAc,aAAa,4BAA4B,KAAK;AAGlE,UAAM,YAAQ,wBAAQ,MAAM;AAC1B,YAAM,YAAY,IAAI,KAAK,KAAK,SAAmB;AACnD,YAAM,UAAU,IAAI,KAAK,KAAK,OAAiB;AAC/C,YAAM,WAAW,IAAI,KAAK,YAAY,CAAC,GAAG,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAC7D,cAAQ,KAAK,gBAAgB,CAAC,GAAG,IAAI,SAAO;AAC1C,cAAM,OAAO,SAAS,IAAI,IAAI,MAAM;AACpC,cAAM,MAAM,OACR;AAAA,UACA,IAAI;AAAA,UACJ,IAAI,KAAK,KAAK,SAAmB;AAAA,UACjC,IAAI,KAAK,KAAK,OAAiB;AAAA,UAC/B;AAAA,UACA;AAAA,QACF,IACG,IAAI,OAAO;AAChB,eAAO,EAAE,KAAK,KAAK,iBAAiB,MAAM,QAAQ,IAAI,OAAO;AAAA,MAC/D,CAAC;AAAA,IACH,GAAG,CAAC,KAAK,cAAc,KAAK,WAAW,KAAK,SAAS,QAAQ,CAAC;AAE9D,UAAM,WAAW,MAAM,UAAU,IAAI,mCAAU;AAE/C,kCAAU,MAAM;AACd,UAAI,eAAe,aAAa,SAAS;AACvC,qBAAa,QAAQ,MAAM;AAAA,MAC7B;AAAA,IACF,GAAG,CAAC,WAAW,CAAC;AAEhB,UAAM,sBAAkB,4BAAY,CAAC,MAAwB;AAC3D,UAAI,uBAAwB;AAC5B,QAAE,gBAAgB;AAClB,mBAAa,KAAK,IAAI;AACtB,qBAAe,IAAI;AAAA,IACrB,GAAG,CAAC,KAAK,MAAM,sBAAsB,CAAC;AAEtC,UAAM,qBAAiB,4BAAY,MAAM;AACvC,UAAI,UAAU,KAAK,GAAG;AACpB,uBAAe,EAAE,GAAG,MAAM,MAAM,UAAU,KAAK,EAAE,CAAC;AAAA,MACpD;AACA,qBAAe,KAAK;AAAA,IACtB,GAAG,CAAC,WAAW,MAAM,YAAY,CAAC;AAElC,UAAM,uBAAmB,4BAAY,MAAM;AACzC,qBAAe,KAAK;AAAA,IACtB,GAAG,CAAC,CAAC;AAEL,UAAM,wBAAoB,4BAAY,CAAC,MAA6C;AAClF,UAAI,EAAE,QAAQ,QAAS,gBAAe;AAAA,eAC7B,EAAE,QAAQ,SAAU,kBAAiB;AAAA,IAChD,GAAG,CAAC,gBAAgB,gBAAgB,CAAC;AAGrC,UAAM,4BAAwB,4BAAY,CAAC,eAAuB;AAChE,UAAI,CAAC,WAAY;AACjB,YAAM,YAAY,aAAa,KAAK,SAAS;AAC7C,YAAM,UAAU,aAAa,KAAK,OAAO;AACzC,YAAM,aAAa,QAAQ,QAAQ,IAAI,UAAU,QAAQ;AACzD,YAAM,WAAW,oBAAI,KAAK,aAAa,YAAY;AACnD,YAAM,SAAS,IAAI,KAAK,SAAS,QAAQ,IAAI,UAAU;AACvD,qBAAe,EAAE,GAAG,MAAM,WAAW,YAAY,SAAS,OAAO,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC;AAAA,IAChG,GAAG,CAAC,MAAM,YAAY,CAAC;AAEvB,UAAM,0BAAsB,4BAAY,CAAC,eAAuB;AAC9D,UAAI,CAAC,WAAY;AACjB,YAAM,YAAY,aAAa,KAAK,SAAS;AAC7C,YAAM,UAAU,aAAa,KAAK,OAAO;AACzC,YAAM,aAAa,QAAQ,QAAQ,IAAI,UAAU,QAAQ;AACzD,YAAM,SAAS,oBAAI,KAAK,aAAa,YAAY;AACjD,YAAM,WAAW,IAAI,KAAK,OAAO,QAAQ,IAAI,UAAU;AACvD,qBAAe,EAAE,GAAG,MAAM,WAAW,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,SAAS,WAAW,CAAC;AAAA,IAClG,GAAG,CAAC,MAAM,YAAY,CAAC;AAEvB,UAAM,6BAAyB,4BAAY,MAAM;AAC/C,mBAAa,KAAK,EAAE;AAAA,IACtB,GAAG,CAAC,KAAK,IAAI,UAAU,CAAC;AAExB,UAAM,wBAAoB,4BAAY,CAAC,MAAwB;AAC7D,QAAE,gBAAgB;AAClB,mBAAa,KAAK,EAAE;AACpB,uBAAiB,KAAK,EAAE;AAAA,IAC1B,GAAG,CAAC,KAAK,IAAI,YAAY,cAAc,CAAC;AAGxC,UAAM,qBAAiB,4BAAY,CAAC,MAAwB;AAC1D,QAAE,gBAAgB;AAClB,qCAA+B,KAAK,EAAE;AAAA,IACxC,GAAG,CAAC,KAAK,IAAI,4BAA4B,CAAC;AAE1C,UAAM,4BAAwB,4BAAY,CAAC,MAAwB;AACjE,QAAE,gBAAgB;AAClB,UAAI,CAAC,aAAa,YAAa;AAC/B,UAAI,CAAC,2BAA2B,CAAC,eAAgB;AACjD,wBAAkB,KAAK,IAAI,yBAAyB,cAAc;AAAA,IACpE,GAAG,CAAC,WAAW,aAAa,yBAAyB,KAAK,IAAI,gBAAgB,eAAe,CAAC;AAG9F,UAAM,wBAAwB,gBAAgB,QAAQ,aAAa,kBAAkB,KAAK;AAG1F,UAAM,2BAAuB,4BAAY,CAAC,MAAwB;AAChE,QAAE,gBAAgB;AAClB,UAAI,CAAC,aAAc;AACnB,2BAAqB,aAAa,aAAa,aAAa,eAAe,aAAa,QAAoB;AAC5G,qBAAe,IAAI;AAAA,IACrB,GAAG,CAAC,cAAc,oBAAoB,YAAY,CAAC;AAEnD,UAAM,eAAe,UAAU,KAAK,SAAS;AAC7C,UAAM,aAAa,UAAU,KAAK,OAAO;AAEzC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,aAAa,0BAA0B;AAAA,UACvC,aAAa,CAAC,cAAc,yBAAyB;AAAA,UACrD,cAAc,8BAA8B;AAAA,QAC9C,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,QAC1B,OAAO,EAAE,WAAW,GAAG,SAAS,KAAK;AAAA,QACrC,SAAS;AAAA,QAGT;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS;AAAA,cACT,OAAM;AAAA,cAEN;AAAA,8DAAC,UAAK,WAAU,sBAAsB,qBAAW,GAAE;AAAA,gBACnD,+CAAC,SAAI,WAAU,qBAAoB,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACtM;AAAA,gEAAC,UAAK,GAAE,YAAW;AAAA,kBACnB,8CAAC,UAAK,GAAE,kBAAiB;AAAA,kBACzB,8CAAC,UAAK,GAAE,YAAW;AAAA,mBACrB;AAAA;AAAA;AAAA,UACF;AAAA,UAGA,+CAAC,SAAI,WAAU,oCACZ;AAAA,2BACC;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK;AAAA,gBACL,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,gBAC5C,QAAQ;AAAA,gBACR,WAAW;AAAA,gBACX,WAAU;AAAA,gBACV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA;AAAA,YACpC;AAAA,YAEF;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,WAAW,yBAAyB,yBAAyB,yBAAyB,EAAE;AAAA,gBACxF,SAAS;AAAA,gBACT,OAAO,cAAc,EAAE,YAAY,UAAU,eAAe,OAAO,IAAI;AAAA,gBAEtE,eAAK;AAAA;AAAA,YACR;AAAA,aACF;AAAA,UAGA,8CAAC,SAAI,WAAU,oCAAmC,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAClF;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU;AAAA,cACV,QAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU,KAAK;AAAA;AAAA,UACjB,GACF;AAAA,UAGA,8CAAC,SAAI,WAAU,oCAAmC,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAClF;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU;AAAA,cACV,QAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU,KAAK;AAAA;AAAA,UACjB,GACF;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,aAAa,CAAC,cAAc,wBAAwB;AAAA,cAE5D,wBACC,8CAAC,UAAK,WAAU,4BAA2B,mGAAe,IACxD,yBAAyB,CAAC;AAAA;AAAA,gBAE5B;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS;AAAA,oBACT,cAAW;AAAA,oBAEX;AAAA,oEAAC,UAAK,WAAU,qCAAoC,+DAAS;AAAA,sBAC7D,8CAAC,UAAK,WAAU,mCAAkC,uFAAa;AAAA;AAAA;AAAA,gBACjE;AAAA,kBAEA,gFACG;AAAA,sBAAM,UAAU;AAAA;AAAA,kBAEf,+CAAC,WAAQ,MAAM,cAAc,cAAc,iBACzC;AAAA,kEAAC,kBAAe,SAAO,MACrB;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,WAAU;AAAA,wBACV,SAAS,CAAC,MAAM;AAAE,4BAAE,gBAAgB;AAAG,0CAAgB,OAAK,CAAC,CAAC;AAAA,wBAAG;AAAA,wBAEhE;AAAA,gCAAM;AAAA,0BAAO;AAAA,0BAAE;AAAA;AAAA;AAAA,oBAClB,GACF;AAAA,oBACA,8CAAC,kBAAe,QAAQ,MAAM,OAAM,SAClC,wDAAC,SAAI,WAAU,8BAA6B,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAC3E,gBAAM,IAAI,CAAC,EAAE,KAAK,KAAK,gBAAgB,MACtC;AAAA,sBAAC;AAAA;AAAA,wBAEC;AAAA,wBACA;AAAA,wBACA,QAAQ,KAAK;AAAA,wBACb;AAAA,wBACA;AAAA,wBACA;AAAA,wBACA;AAAA,wBACA;AAAA,wBACA;AAAA,wBACA;AAAA,wBACA,mBAAmB,MAAM,eAAe,IAAI;AAAA;AAAA,sBAXvC,GAAG,IAAI,MAAM,IAAI,IAAI,IAAI;AAAA,oBAYhC,CACD,GACH,GACF;AAAA,qBACF;AAAA,oBACE,MAAM,WAAW;AAAA;AAAA,kBAEnB;AAAA,oBAAC;AAAA;AAAA,sBACC,KAAK,MAAM,CAAC,EAAE;AAAA,sBACd,KAAK,MAAM,CAAC,EAAE;AAAA,sBACd,QAAQ,KAAK;AAAA,sBACb,iBAAiB,MAAM,CAAC,EAAE;AAAA,sBAC1B;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA,mBAAmB,MAAM,eAAe,IAAI;AAAA;AAAA,kBAC9C;AAAA,oBACE;AAAA,gBAGH,CAAC,4BAA4B,CAAC,aAC7B;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS;AAAA,oBACT,cAAW;AAAA,oBACZ;AAAA;AAAA,gBAED;AAAA,iBAEJ;AAAA;AAAA,UAEJ;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AAEA,YAAY,cAAc;;;AFpQhB,IAAAC,uBAAA;AA3MV,IAAM,kBAA8B,CAAC,MAAM,MAAM,MAAM,IAAI;AAmCpD,IAAM,WAAoC,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B;AAAA,EACA;AACF,MAAM;AACJ,QAAM,kBAAc;AAAA,IAClB,MAAM,MAAM,SAAS;AAAA,IACrB,CAAC,MAAM,QAAQ,SAAS;AAAA,EAC1B;AAEA,QAAM,qBAAiB,4BAAY,CAAC,WAAmB;AACrD,mBAAe,MAAM;AAAA,EACvB,GAAG,CAAC,YAAY,CAAC;AAGjB,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAAmB,IAAI;AACnE,QAAM,CAAC,yBAAyB,0BAA0B,QAAI,yBAAwB,IAAI;AAC1F,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,KAAK;AACtD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAS,KAAK;AAClD,QAAM,iBAAa,uBAAuB,IAAI;AAI9C,QAAM,CAAC,cAAc,eAAe,QAAI,yBAI9B,IAAI;AAEd,QAAM,uBAAmB,4BAAY,CAAC,SAIzB;AACX,oBAAgB,IAAI;AACpB,2BAAuB,IAAI;AAAA,EAC7B,GAAG,CAAC,oBAAoB,CAAC;AAGzB,gCAAU,MAAM;AACd,QAAI,CAAC,2BAA2B,CAAC,aAAc;AAC/C,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,UAAU;AACtB,mCAA2B,IAAI;AAC/B,wBAAgB,IAAI;AACpB,+BAAuB,IAAI;AAAA,MAC7B;AAAA,IACF;AACA,UAAM,kBAAkB,CAAC,MAAkB;AACzC,YAAM,SAAS,EAAE;AACjB,UAAI,WAAW,SAAS,SAAS,MAAM,EAAG;AAE1C,UAAI,OAAO,UAAU,gBAAgB,EAAG;AACxC,iCAA2B,IAAI;AAC/B,sBAAgB,IAAI;AACpB,6BAAuB,IAAI;AAAA,IAC7B;AACA,aAAS,iBAAiB,WAAW,aAAa;AAClD,aAAS,iBAAiB,aAAa,iBAAiB,IAAI;AAC5D,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,aAAa;AACrD,eAAS,oBAAoB,aAAa,iBAAiB,IAAI;AAAA,IACjE;AAAA,EACF,GAAG,CAAC,yBAAyB,cAAc,oBAAoB,CAAC;AAEhE,QAAM,0BAAsB,4BAAY,CACtC,iBACA,mBACA,aACG;AAEH,QAAI,oBAAoB,kBAAmB;AAG3C,UAAM,YAAY,MAAM,KAAK,OAAK,EAAE,OAAO,eAAe;AAC1D,QAAI,CAAC,UAAW;AAChB,UAAM,iBAAiB,UAAU,gBAAgB,CAAC,GAAG;AAAA,MACnD,OAAK,EAAE,WAAW,qBAAqB,EAAE,SAAS;AAAA,IACpD;AACA,QAAI,eAAe;AACjB,iCAA2B,IAAI;AAC/B;AAAA,IACF;AAGA,UAAM,SAAyB,EAAE,QAAQ,mBAAmB,MAAM,UAAU,KAAK,EAAE;AACnF,UAAM,eAAe,MAAM;AAAA,MAAI,OAC7B,EAAE,OAAO,kBACL,EAAE,GAAG,GAAG,cAAc,CAAC,GAAI,EAAE,gBAAgB,CAAC,GAAI,MAAM,EAAE,IAC1D;AAAA,IACN;AACA,UAAM,aAAa,qBAAqB,YAAY;AACpD,QAAI,CAAC,WAAW,SAAS;AACvB,oBAAc,IAAI;AAClB,iBAAW,MAAM,cAAc,KAAK,GAAG,GAAI;AAC3C;AAAA,IACF;AAEA,UAAM,cAAc,aAAa,KAAK,OAAK,EAAE,OAAO,eAAe;AAGnE,UAAM,cAAc,MAAM,KAAK,OAAK,EAAE,OAAO,iBAAiB;AAC9D,QAAI,aAAa;AACf,YAAM,YAAY,IAAI,KAAK,YAAY,SAAmB;AAC1D,YAAM,UAAU,IAAI,KAAK,YAAY,OAAiB;AACtD,YAAM,iBAAiB,uBAAuB,WAAW,SAAS,UAAU,CAAC;AAE7E,YAAM,gBAAgB,MAAM,KAAK,OAAK,EAAE,OAAO,eAAe;AAC9D,YAAM,aACJ,IAAI,KAAK,cAAc,OAAiB,EAAE,QAAQ,IAClD,IAAI,KAAK,cAAc,SAAmB,EAAE,QAAQ;AAEtD,UAAI;AACJ,UAAI;AAEJ,UAAI,aAAa,QAAQ,aAAa,MAAM;AAC1C,mBAAW;AACX,iBAAS,IAAI,KAAK,eAAe,QAAQ,IAAI,UAAU;AAAA,MACzD,OAAO;AACL,iBAAS;AACT,mBAAW,IAAI,KAAK,eAAe,QAAQ,IAAI,UAAU;AAAA,MAC3D;AAEA,YAAM,cAAoB;AAAA,QACxB,GAAG;AAAA,QACH,WAAW,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,QAC9C,SAAS,OAAO,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,MAC5C;AACA,qBAAe,WAAW;AAAA,IAC5B,OAAO;AAEL,qBAAe,WAAW;AAAA,IAC5B;AAEA,+BAA2B,IAAI;AAAA,EACjC,GAAG,CAAC,OAAO,YAAY,CAAC;AAExB,QAAM,6BAAyB,4BAAY,CACzC,QACA,mBACA,aACG;AACH,UAAM,OAAO,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM;AAC5C,QAAI,CAAC,KAAM;AACX,UAAM,eAAe,KAAK,gBAAgB,CAAC,GAAG;AAAA,MAC5C,OAAK,EAAE,EAAE,WAAW,qBAAqB,EAAE,SAAS;AAAA,IACtD;AACA,mBAAe,EAAE,GAAG,MAAM,cAAc,YAAY,CAAC;AAAA,EACvD,GAAG,CAAC,OAAO,YAAY,CAAC;AAExB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,mBAAmB,OAAO,KAAK,kBAAkB;AAAA,MAC5D,OAAO,EAAE,OAAO,GAAG,aAAa,KAAK;AAAA,MAErC,yDAAC,SAAI,WAAU,kBAEb;AAAA,uDAAC,SAAI,WAAU,mBAAkB,OAAO,EAAE,QAAQ,GAAG,eAAe,GAAG,KAAK,GAC1E;AAAA,wDAAC,SAAI,WAAU,4CAA2C,oBAAC;AAAA,UAC3D,8CAAC,SAAI,WAAU,0CAAyC,gCAAG;AAAA,UAC3D,8CAAC,SAAI,WAAU,0CAAyC,kDAAM;AAAA,UAC9D,8CAAC,SAAI,WAAU,0CAAyC,oEAAS;AAAA,UAEjE,+CAAC,SAAI,WAAU,0CAAyC,OAAO,EAAE,UAAU,WAAW,GACpF;AAAA,2DAAC,WAAQ,MAAM,cAAc,cAAc,iBACzC;AAAA,4DAAC,kBAAe,SAAO,MACrB;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,UAAU;AAAA,kBACV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,kBACnC;AAAA;AAAA,oBACQ,eAAAC,QAAM,cAAc,gBAAgB,cAAc,CAAC;AAAA,oBAAE;AAAA;AAAA;AAAA,cAC9D,GACF;AAAA,cACA,8CAAC,kBAAe,QAAQ,MAAM,OAAM,SAClC,wDAAC,SAAI,WAAU,0BACZ,0BAAgB,IAAI,QACnB;AAAA,gBAAC;AAAA;AAAA,kBAEC,WAAW,2BAA2B,mBAAmB,KAAK,YAAY,EAAE;AAAA,kBAC5E,SAAS,MAAM;AAAE,sCAAkB,EAAE;AAAG,oCAAgB,KAAK;AAAA,kBAAG;AAAA,kBAE/D;AAAA,mCAAAA,QAAM,cAAc,gBAAgB,EAAE,CAAC;AAAA,oBACxC,8CAAC,UAAM,2BAAiB,EAAE,GAAE;AAAA;AAAA;AAAA,gBALvB;AAAA,cAMP,CACD,GACH,GACF;AAAA,eACF;AAAA,YACC,cACC,8CAAC,SAAI,WAAU,sBAAqB,gHAAkB;AAAA,aAE1D;AAAA,WACF;AAAA,QAGA,8CAAC,SAAI,WAAU,iBAAgB,OAAO,EAAE,QAAQ,GAAG,WAAW,KAAK,GAChE,gBAAM,IAAI,CAAC,MAAM,UAChB;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAY;AAAA,YACZ;AAAA,YACA;AAAA,YACA,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA,8BAA8B;AAAA,YAC9B,iBAAiB;AAAA,YACjB,oBAAoB;AAAA,YACpB;AAAA,YACA,cAAc;AAAA,YACd;AAAA;AAAA,UAjBK,KAAK;AAAA,QAkBZ,CACD,GACH;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;;;AXsKU,IAAAC,uBAAA;AAzTH,IAAM,iBAAa,2BAA8C,CAAC;AAAA,EACvE;AAAA,EACA,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,yBAAyB;AAAA,EACzB,2BAA2B;AAC7B,GAAG,QAAQ;AACT,QAAM,yBAAqB,uBAAuB,IAAI;AAGtD,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAAwB,IAAI;AAGxE,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAkF,IAAI;AAG9H,QAAM,gBAAY,wBAAQ,MAAM,kBAAkB,KAAK,GAAG,CAAC,KAAK,CAAC;AAGjE,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,yBAAkC,IAAI;AAGtF,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,yBAAuD,oBAAI,IAAI,CAAC;AAGhH,QAAM,gBAAY;AAAA,IAChB,MAAM,KAAK,MAAM,UAAU,SAAS,QAAQ;AAAA,IAC5C,CAAC,UAAU,QAAQ,QAAQ;AAAA,EAC7B;AAGA,QAAM,sBAAkB;AAAA,IACtB,MAAM,MAAM,SAAS;AAAA,IACrB,CAAC,MAAM,QAAQ,SAAS;AAAA,EAC1B;AAGA,QAAM,iBAAa,wBAAQ,MAAM;AAC/B,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO,IAAI,KAAK,KAAK,KAAI,oBAAI,KAAK,GAAE,eAAe,IAAG,oBAAI,KAAK,GAAE,YAAY,GAAG,CAAC,CAAC;AAAA,IACpF;AACA,UAAM,WAAW,UAAU,CAAC;AAC5B,WAAO,IAAI,KAAK,KAAK,IAAI,SAAS,eAAe,GAAG,SAAS,YAAY,GAAG,CAAC,CAAC;AAAA,EAChF,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,mBAAe,wBAAQ,MAAM;AACjC,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,GAAG,IAAI,WAAW,CAAC,CAAC;AAC1F,WAAO,UAAU,KAAK,SAAO,IAAI,QAAQ,MAAM,MAAM,QAAQ,CAAC;AAAA,EAChE,GAAG,CAAC,SAAS,CAAC;AAGd,gCAAU,MAAM;AACd,UAAM,YAAY,mBAAmB;AACrC,QAAI,CAAC,aAAa,UAAU,WAAW,EAAG;AAE1C,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,GAAG,IAAI,WAAW,CAAC,CAAC;AAC1F,UAAM,aAAa,UAAU,UAAU,SAAO,IAAI,QAAQ,MAAM,MAAM,QAAQ,CAAC;AAE/E,QAAI,eAAe,GAAI;AAGvB,UAAM,cAAc,aAAa;AACjC,UAAM,iBAAiB,UAAU;AACjC,UAAM,aAAa,KAAK,MAAM,cAAe,iBAAiB,IAAM,WAAW,CAAE;AAEjF,cAAU,aAAa,KAAK,IAAI,GAAG,UAAU;AAAA,EAC/C,GAAG,CAAC,CAAC;AAKL,QAAM,oBAAgB,4BAAY,MAAM;AACtC,UAAM,YAAY,mBAAmB;AACrC,QAAI,CAAC,aAAa,UAAU,WAAW,EAAG;AAE1C,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,GAAG,IAAI,WAAW,CAAC,CAAC;AAC1F,UAAM,aAAa,UAAU,UAAU,SAAO,IAAI,QAAQ,MAAM,MAAM,QAAQ,CAAC;AAE/E,QAAI,eAAe,GAAI;AAGvB,UAAM,cAAc,aAAa;AACjC,UAAM,iBAAiB,UAAU;AACjC,UAAM,aAAa,KAAK,MAAM,cAAe,iBAAiB,IAAM,WAAW,CAAE;AAEjF,cAAU,aAAa,KAAK,IAAI,GAAG,UAAU;AAAA,EAC/C,GAAG,CAAC,WAAW,QAAQ,CAAC;AAKxB,QAAM,mBAAe,4BAAY,CAAC,WAAmB;AACnD,UAAM,YAAY,mBAAmB;AACrC,QAAI,CAAC,aAAa,UAAU,WAAW,EAAG;AAE1C,UAAM,OAAO,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM;AAC5C,QAAI,CAAC,KAAM;AAEX,UAAM,YAAY,IAAI,KAAK,KAAK,SAAmB;AACnD,UAAM,eAAe,IAAI,KAAK,KAAK;AAAA,MACjC,UAAU,eAAe;AAAA,MACzB,UAAU,YAAY;AAAA,MACtB,UAAU,WAAW;AAAA,IACvB,CAAC;AACD,UAAM,YAAY,UAAU,UAAU,SAAO,IAAI,QAAQ,MAAM,aAAa,QAAQ,CAAC;AACrF,QAAI,cAAc,GAAI;AAEtB,UAAM,aAAa,YAAY;AAC/B,UAAM,aAAa,KAAK,MAAM,aAAa,WAAW,CAAC;AACvD,cAAU,aAAa,KAAK,IAAI,GAAG,UAAU;AAAA,EAC/C,GAAG,CAAC,OAAO,WAAW,QAAQ,CAAC;AAK/B;AAAA,IACE;AAAA,IACA,OAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,eAAe,YAAY;AAAA,EAC9B;AAGA,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAKlC,IAAI;AAGd,QAAM,CAAC,qBAAqB,sBAAsB,QAAI,yBAAiE,IAAI;AAG3H,gCAAU,MAAM;AACd,UAAM,SAAS,qBAAqB,KAAK;AACzC,wBAAoB,MAAM;AAC1B,6BAAyB,MAAM;AAAA,EACjC,GAAG,CAAC,OAAO,sBAAsB,CAAC;AAoBlC,QAAM,uBAAmB,4BAAY,CAAC,gBAAsB;AAE1D,UAAM,eAAe,MAAM,KAAK,OAAK,EAAE,OAAO,YAAY,EAAE;AAC5D,QAAI,CAAC,cAAc;AACjB,iBAAW,CAAC,iBAAiB,aAAa,IAAI,OAAK,EAAE,OAAO,YAAY,KAAK,cAAc,CAAC,CAAC;AAC7F;AAAA,IACF;AAEA,UAAM,YAAY,IAAI,KAAK,aAAa,SAAmB;AAC3D,UAAM,UAAU,IAAI,KAAK,aAAa,OAAiB;AACvD,UAAM,WAAW,IAAI,KAAK,YAAY,SAAmB;AACzD,UAAM,SAAS,IAAI,KAAK,YAAY,OAAiB;AACrD,UAAM,eAAe,UAAU,QAAQ,MAAM,SAAS,QAAQ,KAAK,QAAQ,QAAQ,MAAM,OAAO,QAAQ;AAGxG,QAAI,CAAC,gBAAgB,oBAAoB;AACvC,iBAAW,CAAC,iBAAiB,aAAa,IAAI,OAAK,EAAE,OAAO,YAAY,KAAK,cAAc,CAAC,CAAC;AAC7F;AAAA,IACF;AAGA,UAAM,eAAqB;AAC3B,UAAM,gBAAgB,eAAe,YAAY,IAAI,UAAU,QAAQ,KAAK;AAE5E,UAAM,cAAc,CAAC,cAAc,GAAG,aAAa;AACnD,eAAW,CAAC,iBAAiB;AAC3B,YAAM,IAAI,IAAI,IAAI,YAAY,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACjD,aAAO,aAAa,IAAI,OAAK,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC;AAAA,IAC/C,CAAC;AACD,gBAAY,WAAW;AAAA,EACzB,GAAG,CAAC,OAAO,UAAU,oBAAoB,SAAS,CAAC;AAGnD,QAAM,0BAAsB,wBAAQ,MAAM;AACxC,UAAM,MAAM,IAAI,IAAI,gBAAgB;AACpC,QAAI,qBAAqB;AACvB,UAAI,IAAI,oBAAoB,QAAQ;AAAA,QAClC,MAAM,oBAAoB;AAAA,QAC1B,OAAO,oBAAoB;AAAA,MAC7B,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT,GAAG,CAAC,kBAAkB,mBAAmB,CAAC;AAO1C,QAAM,4BAAwB,4BAAY,CAAC,cAA4D;AACrG,wBAAoB,IAAI,IAAI,SAAS,CAAC;AAAA,EACxC,GAAG,CAAC,CAAC;AAML,QAAM,oBAAgB,4BAAY,CAAC,kBAA0B;AAE3D,eAAW,CAAC,iBAAiB;AAC3B,YAAM,aAAa,IAAI,IAAI,cAAc,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAC5D,aAAO,aAAa,IAAI,OAAK,WAAW,IAAI,EAAE,EAAE,KAAK,CAAC;AAAA,IACxD,CAAC;AAED,gBAAY,aAAa;AAAA,EAC3B,GAAG,CAAC,UAAU,SAAS,CAAC;AAKxB,QAAM,uBAAmB,4BAAY,CAAC,WAA0B;AAC9D,sBAAkB,MAAM;AAAA,EAC1B,GAAG,CAAC,CAAC;AAGL,QAAM,kBAAc,uBAAqG,IAAI;AAE7H,QAAM,qBAAiB,4BAAY,CAAC,MAAwB;AAE1D,QAAI,EAAE,WAAW,EAAG;AACpB,UAAM,SAAS,EAAE;AACjB,QAAI,OAAO,QAAQ,gBAAgB,EAAG;AACtC,QAAI,OAAO,QAAQ,4CAA4C,EAAG;AAClE,QAAI,OAAO,QAAQ,mBAAmB,EAAG;AAEzC,UAAM,YAAY,mBAAmB;AACrC,QAAI,CAAC,UAAW;AAEhB,gBAAY,UAAU;AAAA,MACpB,QAAQ;AAAA,MACR,QAAQ,EAAE;AAAA,MACV,QAAQ,EAAE;AAAA,MACV,SAAS,UAAU;AAAA,MACnB,SAAS,UAAU;AAAA,IACrB;AAEA,QAAI,SAAS,yBAAyB,aAAa;AACjD,eAAS,cAAc,KAAK;AAAA,IAC9B;AACA,cAAU,MAAM,SAAS;AACzB,MAAE,eAAe;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,gCAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,MAAkB;AACvC,YAAM,MAAM,YAAY;AACxB,UAAI,CAAC,KAAK,OAAQ;AAClB,YAAM,YAAY,mBAAmB;AACrC,UAAI,CAAC,UAAW;AAEhB,gBAAU,aAAa,IAAI,WAAW,EAAE,UAAU,IAAI;AACtD,gBAAU,YAAY,IAAI,WAAW,EAAE,UAAU,IAAI;AAAA,IACvD;AAEA,UAAM,eAAe,MAAM;AACzB,UAAI,CAAC,YAAY,SAAS,OAAQ;AAClC,kBAAY,UAAU;AACtB,YAAM,YAAY,mBAAmB;AACrC,UAAI,UAAW,WAAU,MAAM,SAAS;AAAA,IAC1C;AAEA,WAAO,iBAAiB,aAAa,aAAa;AAClD,WAAO,iBAAiB,WAAW,YAAY;AAC/C,WAAO,MAAM;AACX,aAAO,oBAAoB,aAAa,aAAa;AACrD,aAAO,oBAAoB,WAAW,YAAY;AAAA,IACpD;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,8CAAC,SAAI,WAAU,mBACb;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAU;AAAA,MACV,OAAO,EAAE,QAAQ,mBAAmB,QAAQ,QAAQ,OAAO;AAAA,MAC3D,aAAa;AAAA,MAGb,yDAAC,SAAI,WAAU,uBAEb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,cAAc;AAAA,YACd,gBAAgB,kBAAkB;AAAA,YAClC,cAAc;AAAA,YACd,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,gBAAgB;AAAA,YAChB,sBAAsB;AAAA;AAAA,QACxB;AAAA,QAGA,+CAAC,SAAI,OAAO,EAAE,UAAU,GAAG,SAAS,MAAM,MAAM,EAAE,GAEhD;AAAA,wDAAC,SAAI,WAAU,sBAAqB,OAAO,EAAE,OAAO,GAAG,SAAS,KAAK,GACnE;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN;AAAA,cACA;AAAA;AAAA,UACF,GACF;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,OAAO,GAAG,SAAS;AAAA,cACrB;AAAA,cAEJ;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC;AAAA,oBACA;AAAA,oBACA,aAAa;AAAA;AAAA,gBACf;AAAA,gBAEC,gBAAgB,8CAAC,0BAAe,YAAwB,UAAoB;AAAA,gBAG7E;AAAA,kBAAC;AAAA;AAAA,oBACC;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA,eAAe;AAAA,oBACf,aAAa;AAAA;AAAA,gBACf;AAAA,gBAEC,kBACC;AAAA,kBAAC;AAAA;AAAA,oBACC,YAAY,eAAe;AAAA,oBAC3B,UAAU,eAAe;AAAA,oBACzB,MAAM,eAAe;AAAA,oBACrB,OAAO,eAAe;AAAA,oBACtB,aAAa;AAAA;AAAA,gBACf;AAAA,gBAGD,MAAM,IAAI,CAAC,MAAM,UAChB;AAAA,kBAAC;AAAA;AAAA,oBAEC;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA,UAAU;AAAA,oBACV,mBAAmB,CAAC,UAAU;AAC5B,0BAAI,MAAM,YAAY;AACpB,0CAAkB,KAAK;AACvB,+CAAuB,EAAE,QAAQ,KAAK,IAAI,MAAM,MAAM,MAAM,OAAO,MAAM,MAAM,CAAC;AAAA,sBAClF,OAAO;AACL,0CAAkB,IAAI;AACtB,+CAAuB,IAAI;AAAA,sBAC7B;AAAA,oBACF;AAAA,oBACA,UAAU;AAAA,oBACV,UAAU;AAAA,oBACV,oBAAoB,sBAAsB;AAAA,oBAC1C,oBAAoB,sBAAsB;AAAA,oBAC1C,kBAAkB,iBAAiB,IAAI,KAAK,EAAE;AAAA,oBAC9C,mBAAmB;AAAA,oBACnB,WAAW;AAAA;AAAA,kBArBN,KAAK;AAAA,gBAsBZ,CACD;AAAA;AAAA;AAAA,UACD;AAAA,WACA;AAAA,SACF;AAAA;AAAA,EACF,GACF;AAEJ,CAAC;AAED,WAAW,cAAc;;;AkB9hBzB,IAAAC,iBAAkB;AA0BZ,IAAAC,uBAAA;AAZC,IAAM,SAAS,eAAAC,QAAM;AAAA,EAC1B,CAAC,EAAE,WAAW,UAAU,WAAW,OAAO,WAAW,UAAU,GAAG,MAAM,GAAG,QAAQ;AACjF,UAAM,UAAU;AAAA,MACd;AAAA,MACA,YAAY,YAAY,aAAa,OAAO,KAAK;AAAA,MACjD,SAAS,YAAY,aAAa,IAAI,KAAK;AAAA,MAC3C,aAAa;AAAA,IACf,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AAEX,WACE,8CAAC,YAAO,KAAU,WAAW,SAAU,GAAG,OACvC,UACH;AAAA,EAEJ;AACF;AAEA,OAAO,cAAc;","names":["import_react","startOfMonth","isWeekend","import_react","isWeekend","import_react","dayWidth","getUTCDayDifference","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","import_jsx_runtime","import_jsx_runtime","React","import_jsx_runtime","React","import_jsx_runtime","import_react","import_jsx_runtime","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/GanttChart/GanttChart.tsx","../src/utils/dateUtils.ts","../src/utils/dependencyUtils.ts","../src/components/TimeScaleHeader/TimeScaleHeader.tsx","../src/components/TaskRow/TaskRow.tsx","../src/utils/geometry.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/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/ui/Button.tsx"],"sourcesContent":["'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// 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 } from '../../utils/dateUtils';\nimport { calculateGridWidth } from '../../utils/geometry';\nimport { validateDependencies, cascadeByLinks } from '../../utils/dependencyUtils';\nimport type { ValidationResult } from '../../types';\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';\nimport '../TaskList/TaskList.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 /**\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 via drag/resize. Can receive either the new tasks array or a functional updater. */\n onChange?: (tasks: Task[] | ((currentTasks: Task[]) => 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}\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}\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 */\nexport const GanttChart = forwardRef<GanttChartHandle, GanttChartProps>(({\n tasks,\n dayWidth = 40,\n rowHeight = 40,\n headerHeight = 40,\n containerHeight,\n onChange,\n onValidateDependencies,\n enableAutoSchedule,\n disableConstraints,\n onCascade,\n showTaskList = false,\n taskListWidth = 520,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n highlightExpiredTasks = false,\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\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 // Calculate multi-month date range from tasks\n const dateRange = useMemo(() => getMultiMonthDays(tasks), [tasks]);\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 // Calculate total grid height\n const totalGridHeight = useMemo(\n () => tasks.length * rowHeight,\n [tasks.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 /**\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.scrollLeft = Math.max(0, scrollLeft);\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.scrollLeft = Math.max(0, scrollLeft);\n }, [tasks, dateRange, dayWidth]);\n\n /**\n * Expose scrollToToday and scrollToTask methods to parent component via ref\n */\n useImperativeHandle(\n ref,\n () => ({\n scrollToToday,\n scrollToTask,\n }),\n [scrollToToday, scrollToTask]\n );\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 * Stable callback for task updates\n *\n * FIXED: No longer depends on `tasks` to avoid stale closure bugs.\n * Uses functional state update pattern: the callback receives an updater function\n * that maps over the current tasks state, ensuring we always use the latest state.\n *\n * This prevents the \"reverting\" bug where dragging a second task causes the\n * first task to revert to its original position.\n *\n * To prevent re-render storms during drag:\n * 1. The onChange callback is only called AFTER drag completes (mouseUp)\n * 2. During drag, only the dragged TaskRow re-renders (due to its internal state)\n * 3. Other TaskRows don't re-render because their props haven't changed\n *\n * The React.memo comparison in TaskRow excludes onChange from comparison,\n * relying on the fact that onChange fires only after drag completes.\n */\n const handleTaskChange = useCallback((updatedTask: Task) => {\n // Find original task to detect date changes\n const originalTask = tasks.find(t => t.id === updatedTask.id);\n if (!originalTask) {\n onChange?.((currentTasks) => currentTasks.map(t => t.id === updatedTask.id ? updatedTask : t));\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 // No date change (name edit) or constraints disabled: simple update\n if (!datesChanged || disableConstraints) {\n onChange?.((currentTasks) => currentTasks.map(t => t.id === updatedTask.id ? updatedTask : t));\n return;\n }\n\n // Lags are fixed constraints — preserve as-is, only reposition dates\n const cascadedTask: Task = updatedTask;\n const cascadedChain = cascadeByLinks(updatedTask.id, newStart, newEnd, tasks);\n\n const allCascaded = [cascadedTask, ...cascadedChain];\n\n // Log isExpired calculation for each cascaded task\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n const msPerDay = 1000 * 60 * 60 * 24;\n\n console.log('[GanttChart handleTaskChange] IsExpired calculation:');\n for (const t of allCascaded) {\n const taskStart = new Date(t.startDate as string);\n const taskEnd = new Date(t.endDate as string);\n const actualProgress = t.progress ?? 0;\n\n if (actualProgress >= 100) {\n console.log(` [${t.id}] START=${t.startDate} END=${t.endDate} TODAY=${today.toISOString().split('T')[0]} PROGRESS=${actualProgress}% EXPECTED=N/A (completed) EXPIRED=NO`);\n continue;\n }\n\n // Simple formula: duration = (end - start + 1), elapsed = (min(today, end) - start)\n const duration = taskEnd.getTime() - taskStart.getTime() + msPerDay;\n const elapsedCutoff = taskEnd.getTime() < today.getTime() ? taskEnd.getTime() : today.getTime();\n const elapsed = elapsedCutoff - taskStart.getTime();\n const expectedProgress = Math.min(100, Math.max(0, (elapsed / duration) * 100));\n const isExpired = actualProgress < expectedProgress;\n\n const durationDays = Math.round(duration / msPerDay);\n const elapsedDays = Math.round(elapsed / msPerDay);\n console.log(` [${t.id}] START=${t.startDate} END=${t.endDate} TODAY=${today.toISOString().split('T')[0]} PROGRESS=${actualProgress}% DURATION=${durationDays}d ELAPSED=${elapsedDays}d EXPECTED=${expectedProgress.toFixed(1)}% EXPIRED=${isExpired ? 'YES' : 'NO'}`);\n }\n\n onChange?.((currentTasks) => {\n const m = new Map(allCascaded.map(t => [t.id, t]));\n return currentTasks.map(t => m.get(t.id) ?? t);\n });\n onCascade?.(allCascaded);\n }, [tasks, onChange, disableConstraints, onCascade]);\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 — updates all shifted tasks via onChange (functional updater)\n * and notifies the external onCascade consumer.\n */\n const handleCascade = useCallback((cascadedTasks: Task[]) => {\n // Update state by merging cascaded tasks into current tasks\n onChange?.((currentTasks) => {\n const cascadeMap = new Map(cascadedTasks.map(t => [t.id, t]));\n return currentTasks.map(t => cascadeMap.get(t.id) ?? t);\n });\n // Notify external consumer\n onCascade?.(cascadedTasks);\n }, [onChange, onCascade]);\n\n /**\n * Handle task selection from TaskList or TaskRow\n */\n const handleTaskSelect = useCallback((taskId: string | null) => {\n setSelectedTaskId(taskId);\n }, []);\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={tasks}\n rowHeight={rowHeight}\n headerHeight={headerHeight}\n taskListWidth={taskListWidth}\n onTaskChange={handleTaskChange}\n selectedTaskId={selectedTaskId ?? undefined}\n onTaskSelect={handleTaskSelect}\n show={showTaskList}\n disableTaskNameEditing={disableTaskNameEditing}\n disableDependencyEditing={disableDependencyEditing}\n onScrollToTask={scrollToTask}\n onSelectedChipChange={setSelectedChip}\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 />\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 />\n\n {todayInRange && <TodayIndicator monthStart={monthStart} dayWidth={dayWidth} />}\n\n {/* Dependency lines SVG overlay */}\n <DependencyLines\n tasks={tasks}\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 {tasks.map((task, index) => (\n <TaskRow\n key={task.id}\n task={task}\n monthStart={monthStart}\n dayWidth={dayWidth}\n rowHeight={rowHeight}\n onChange={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={tasks}\n enableAutoSchedule={enableAutoSchedule ?? false}\n disableConstraints={disableConstraints ?? false}\n overridePosition={cascadeOverrides.get(task.id)}\n onCascadeProgress={handleCascadeProgress}\n onCascade={handleCascade}\n highlightExpiredTasks={highlightExpiredTasks}\n />\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nGanttChart.displayName = 'GanttChart';\n\nexport default GanttChart;\n","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 (UTC comparison)\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 const today = new Date(Date.UTC(\n now.getUTCFullYear(),\n now.getUTCMonth(),\n now.getUTCDate()\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 * 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","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 * 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): 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 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 const constraintDate = calculateSuccessorDate(predStart, predEnd, dep.type, dep.lag ?? 0);\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 */\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 directSuccessors = getSuccessorChain(changedTaskId, allTasks, firstLevelLinkTypes);\n const chain = [...directSuccessors];\n const visited = new Set<string>([changedTaskId, ...directSuccessors.map(t => t.id)]);\n const queue = [...directSuccessors];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\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","'use client';\n\nimport React, { useMemo } from 'react';\nimport { format } from 'date-fns';\nimport { ru } from 'date-fns/locale';\nimport { getMonthSpans } 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}\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 columns\n * Bottom row: Day numbers (centered) in individual columns\n */\nconst TimeScaleHeader: React.FC<TimeScaleHeaderProps> = ({\n days,\n dayWidth,\n headerHeight,\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 return (\n <div\n className=\"gantt-tsh-header\"\n style={{ height: `${headerHeight}px` }}\n >\n {/* Month row - top */}\n <div\n className=\"gantt-tsh-monthRow\"\n style={{ height: `${rowHeight}px` }}\n >\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 </div>\n\n {/* Day row - bottom */}\n <div\n className=\"gantt-tsh-dayRow\"\n style={{\n height: `${rowHeight}px`,\n gridTemplateColumns: dayGridTemplate,\n }}\n >\n {days.map((day, index) => {\n const isWeekend = day.getDay() === 0 || day.getDay() === 6;\n const prevDay = days[index - 1];\n const isMonthBoundary = index > 0 && prevDay && prevDay.getMonth() !== day.getMonth();\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 ${isWeekend ? 'gantt-tsh-weekendDay' : ''} ${isMonthBoundary ? 'gantt-tsh-monthBoundary' : ''} ${isTodayDate ? 'gantt-tsh-today' : ''}`}>\n <span className=\"gantt-tsh-dayLabel\">{format(day, 'd')}</span>\n </div>\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 { useTaskDrag } from '../../hooks/useTaskDrag';\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 */\n onChange?: (updatedTask: 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}\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: onChange is intentionally excluded from this comparison because:\n * 1. The parent (GanttChart) wraps onChange in useCallback for referential stability\n * 2. onChange 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 onChange —\n * callbacks excluded from comparison because GanttChart wraps them in useCallback).\n *\n * Excluding onChange 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 // onChange, 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, onChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks }) => {\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 // Calculate expiration status for overdue tasks\n const isExpired = useMemo(() => {\n if (!highlightExpiredTasks) return false;\n\n // Create UTC today for comparison\n const now = new Date();\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n\n // Parse task dates as UTC\n const taskStart = parseUTCDate(task.startDate);\n const taskEnd = parseUTCDate(task.endDate);\n\n // Task must be incomplete (progress < 100%) to be expired\n const actualProgress = task.progress ?? 0;\n if (actualProgress >= 100) {\n return false; // Completed tasks are never expired\n }\n\n // Simple formula:\n // duration = (end - start + 1) days\n // elapsed = (min(today, end) - start) days\n // expected = elapsed / duration * 100\n const msPerDay = 1000 * 60 * 60 * 24;\n const duration = taskEnd.getTime() - taskStart.getTime() + msPerDay;\n const elapsedCutoff = taskEnd.getTime() < today.getTime() ? taskEnd.getTime() : today.getTime();\n const elapsed = elapsedCutoff - taskStart.getTime();\n const expected = (elapsed / duration) * 100;\n\n return actualProgress < expected;\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 // 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 // Handle drag end - call onChange 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 onChange?.(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 // Determine if progress text fits inside the bar\n // Estimate: duration text (~\"15 д\" = ~30px) + progress text (~\"100%\" = ~30px) + padding (~16px)\n const estimatedTextWidth = durationDays >= 10 ? 76 : 62; // \"15 д 100%\" = ~76px, \"1 д 100%\" = ~62px\n const showProgressInside = progressWidth > 0 && displayWidth > estimatedTextWidth;\n\n return (\n <div\n className=\"gantt-tr-row\"\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' : ''}`}\n style={{\n left: `${displayLeft}px`,\n width: `${displayWidth}px`,\n backgroundColor: barColor,\n height: 'var(--gantt-task-bar-height)',\n cursor: dragHandleProps.style.cursor,\n userSelect: dragHandleProps.style.userSelect,\n }}\n onMouseDown={dragHandleProps.onMouseDown}\n >\n {progressWidth > 0 && (\n <div\n className=\"gantt-tr-progressBar\"\n style={{\n width: `${progressWidth}%`,\n backgroundColor: progressColor,\n }}\n />\n )}\n <div className=\"gantt-tr-resizeHandle gantt-tr-resizeHandleLeft\" />\n <span className=\"gantt-tr-taskDuration\">\n {durationDays} д\n </span>\n {progressWidth > 0 && showProgressInside && (\n <span className=\"gantt-tr-progressText\">\n {progressWidth}%\n </span>\n )}\n <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 + displayWidth}px`,\n }}\n >\n {progressWidth > 0 && !showProgressInside && (\n <span className=\"gantt-tr-externalProgress\">\n {progressWidth}%\n </span>\n )}\n <span className=\"gantt-tr-externalTaskName\">\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 = 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 * @returns Array of weekend block objects with left position and width\n */\nexport const calculateWeekendBlocks = (\n dateRange: Date[],\n dayWidth: number\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 const dayOfWeek = date.getUTCDay();\n const isWeekend = dayOfWeek === 0 || dayOfWeek === 6; // Sunday or Saturday\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 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","'use client';\n\nimport { useEffect, useRef, useState, useCallback } from 'react';\nimport { detectEdgeZone } from '../utils/geometry';\nimport type { Task, TaskDependency, LinkType } from '../types';\nimport { calculateSuccessorDate, getSuccessorChain, getTransitiveCascadeChain, recalculateIncomingLags } 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 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 { startX, initialLeft, initialWidth, mode, dayWidth, onProgress, allTasks } = globalActiveDrag;\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 && !globalActiveDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === globalActiveDrag?.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 = globalActiveDrag.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 globalActiveDrag.monthStart.getUTCFullYear(),\n globalActiveDrag.monthStart.getUTCMonth(),\n globalActiveDrag.monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * globalActiveDrag.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 = globalActiveDrag.initialLeft + globalActiveDrag.initialWidth;\n newWidth = Math.max(globalActiveDrag.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 && !globalActiveDrag.disableConstraints) {\n const currentTask = allTasks.find(t => t.id === globalActiveDrag?.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 = globalActiveDrag.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(globalActiveDrag.monthStart.getUTCFullYear(), globalActiveDrag.monthStart.getUTCMonth(), globalActiveDrag.monthStart.getUTCDate()))\n / (24 * 60 * 60 * 1000)\n );\n const predStartLeft = Math.round(predStartOffset * globalActiveDrag.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 + globalActiveDrag.initialWidth;\n if (proposedEndRight > sfBoundaryRight) {\n newLeft = Math.max(globalActiveDrag.initialLeft, sfBoundaryRight - globalActiveDrag.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(globalActiveDrag.dayWidth, sfBoundaryRight - newLeft);\n }\n }\n }\n }\n }\n\n // Phase 9: select chain based on drag mode\n // move: all FS+SS+FF+SF successors follow\n // resize-right: FS+FF successors (endA changes, SS/SF unaffected)\n // resize-left: SS+SF successors only (startA changes, FS/FF unaffected)\n // Phase 10: added SF\n const activeChain =\n mode === 'resize-right' ? globalActiveDrag.cascadeChainEnd : // FS + FF\n mode === 'resize-left' ? globalActiveDrag.cascadeChainStart : // SS + SF\n /* move */ globalActiveDrag.cascadeChain; // FS + SS + FF + SF\n\n // Hard mode cascade: emit position overrides for successor chain members\n if ((mode === 'move' || mode === 'resize-right' ||\n (mode === 'resize-left' && globalActiveDrag.cascadeChainStart.length > 0)) &&\n !globalActiveDrag.disableConstraints &&\n activeChain.length > 0 &&\n globalActiveDrag.onCascadeProgress) {\n // For move/resize-left: delta from left (startA shift)\n // For resize-right: delta from width (endA shift, startA fixed)\n const deltaDays = mode === 'resize-right'\n ? Math.round((newWidth - globalActiveDrag.initialWidth) / globalActiveDrag.dayWidth)\n : Math.round((newLeft - globalActiveDrag.initialLeft) / globalActiveDrag.dayWidth);\n const overrides = new Map<string, { left: number; width: number }>();\n const draggedTaskId = globalActiveDrag.taskId;\n const dayWidth = globalActiveDrag.dayWidth;\n const monthStart = globalActiveDrag.monthStart;\n\n for (const chainTask of activeChain) {\n // Phase 11: locked tasks cannot be moved by cascade\n if (chainTask.locked) continue;\n\n const chainStart = new Date(chainTask.startDate as string);\n const chainEnd = new Date(chainTask.endDate as string);\n const chainStartOffset = Math.round(\n (Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate()) -\n Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const chainEndOffset = Math.round(\n (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) -\n Date.UTC(\n monthStart.getUTCFullYear(),\n monthStart.getUTCMonth(),\n monthStart.getUTCDate()\n )) / (24 * 60 * 60 * 1000)\n );\n const chainDuration = Math.round(\n (Date.UTC(chainEnd.getUTCFullYear(), chainEnd.getUTCMonth(), chainEnd.getUTCDate()) -\n Date.UTC(chainStart.getUTCFullYear(), chainStart.getUTCMonth(), chainStart.getUTCDate())\n ) / (24 * 60 * 60 * 1000)\n );\n\n // Phase 9: Check if this chainTask has FF dependency on dragged task\n // For FF tasks, calculate position from end offset (not start offset)\n // This fixes negative lag preview where child starts before parent\n // Phase 10: SF tasks also position from end offset (endB constrained to startA)\n const hasFFDepOnDragged = chainTask.dependencies?.some(\n dep => dep.taskId === draggedTaskId && dep.type === 'FF'\n );\n const hasSFDepOnDragged = chainTask.dependencies?.some(\n dep => dep.taskId === draggedTaskId && dep.type === 'SF'\n );\n\n let chainLeft;\n if (hasFFDepOnDragged || hasSFDepOnDragged) {\n // FF/SF: position based on end date shift, then back up by duration\n // This works correctly even when child starts before parent (negative lag)\n // For SF: endB shifts with startA, then back up by duration\n chainLeft = Math.round((chainEndOffset + deltaDays - chainDuration) * dayWidth);\n } else {\n // FS/SS: position based on start date shift\n chainLeft = Math.round((chainStartOffset + deltaDays) * dayWidth);\n }\n\n const chainWidth = Math.round((chainDuration + 1) * dayWidth); // +1 inclusive\n\n // SS lag floor: when A moves left, B follows but chainLeft cannot go below A's new position\n // This keeps lag >= 0 (startB >= startA) during live drag preview\n // Phase 9: Only apply floor to SS tasks, not FF (FF allows negative lag)\n // Phase 10: SF uses end-based positioning, no floor needed\n const hasSSDepOnDragged = chainTask.dependencies?.some(\n dep => dep.taskId === draggedTaskId && dep.type === 'SS'\n );\n if (hasSSDepOnDragged && (mode === 'move' || mode === 'resize-left')) {\n chainLeft = Math.max(chainLeft, newLeft);\n }\n\n overrides.set(chainTask.id, { left: chainLeft, width: chainWidth });\n }\n globalActiveDrag.onCascadeProgress(overrides);\n }\n\n // Update current values in global state for completion\n globalActiveDrag.currentLeft = newLeft;\n globalActiveDrag.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: compute cascade and call onCascade\n\n // CHANGE C: Dual-delta logic — compute from both start and end date changes\n // Compute delta from startDate change (correct for move and resize-left)\n const origStartMs = Date.UTC(\n initialStartDate.getUTCFullYear(),\n initialStartDate.getUTCMonth(),\n initialStartDate.getUTCDate()\n );\n const newStartMs = Date.UTC(\n newStartDate.getUTCFullYear(),\n newStartDate.getUTCMonth(),\n newStartDate.getUTCDate()\n );\n const deltaFromStart = Math.round((newStartMs - origStartMs) / (24 * 60 * 60 * 1000));\n\n // Compute delta from endDate change (correct for resize-right)\n const origEndMs = Date.UTC(\n initialEndDate.getUTCFullYear(),\n initialEndDate.getUTCMonth(),\n initialEndDate.getUTCDate()\n );\n const newEndMs = Date.UTC(\n newEndDate.getUTCFullYear(),\n newEndDate.getUTCMonth(),\n newEndDate.getUTCDate()\n );\n const deltaFromEnd = Math.round((newEndMs - origEndMs) / (24 * 60 * 60 * 1000));\n\n // For resize-right: startDate unchanged, use endDate delta (FS successors follow end)\n // For move and resize-left: use startDate delta (SS and FS-move successors follow start)\n // Detect resize-right: startDate didn't change\n const deltaDays = deltaFromStart === 0 ? deltaFromEnd : deltaFromStart;\n\n // CHANGE D: Phase 8: get correct chain for completion based on what changed\n // - resize-right (deltaFromStart === 0): only endDate changed → FS successors follow end\n // - resize-left (deltaFromStart !== 0, deltaFromEnd === 0): only startDate changed →\n // SS successors follow start; FS successors are anchored to predecessor's END which\n // is unchanged, so FS successors must NOT cascade on resize-left\n // - move (deltaFromStart !== 0, deltaFromEnd !== 0): both dates shift equally →\n // both FS and SS successors follow\n //\n // FIX: For proper transitive closure in mixed link type chains (e.g., A--FS-->B--SS-->C),\n // we use getTransitiveCascadeChain which includes cascaded tasks' successors regardless of link type.\n // Phase 9: FF included in resize-right and move chains\n const isResizeLeft = deltaFromStart !== 0 && deltaFromEnd === 0;\n const chainForCompletion = deltaFromStart === 0\n ? getTransitiveCascadeChain(taskId, allTasks, ['FS', 'FF']) // resize-right: FS + FF\n : isResizeLeft\n ? getTransitiveCascadeChain(taskId, allTasks, ['SS', 'SF']) // resize-left: SS + SF\n : getTransitiveCascadeChain(taskId, allTasks, ['FS', 'SS', 'FF', 'SF']); // move: all types\n\n if (chainForCompletion.length > 0) {\n const draggedTaskData = allTasks.find(t => t.id === taskId);\n const cascadedTasks: Task[] = [\n {\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 ...chainForCompletion\n .filter(chainTask => !chainTask.locked) // Phase 11: skip locked tasks in cascade\n .map(chainTask => {\n const origStart = new Date(chainTask.startDate as string);\n const origEnd = new Date(chainTask.endDate as string);\n const newStart = new Date(Date.UTC(\n origStart.getUTCFullYear(), origStart.getUTCMonth(), origStart.getUTCDate() + deltaDays\n ));\n const newEnd = new Date(Date.UTC(\n origEnd.getUTCFullYear(), origEnd.getUTCMonth(), origEnd.getUTCDate() + deltaDays\n ));\n return { ...chainTask, startDate: newStart.toISOString(), endDate: newEnd.toISOString() };\n }),\n ];\n onCascade(cascadedTasks);\n return; // Don't call onDragEnd — cascade covers the dragged task too\n }\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 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 // 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 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 } 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}\n\n/**\n * Custom comparison function for React.memo\n *\n * Performance optimization: Only re-renders if dateRange or dayWidth change.\n * totalHeight is excluded because it only affects container height, not grid calculations.\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 // totalHeight changes still trigger update\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\n * - React.memo optimization for performance\n * - Pointer events disabled (clicks pass through to tasks)\n */\nconst GridBackground: React.FC<GridBackgroundProps> = React.memo(\n ({ dateRange, dayWidth, totalHeight }) => {\n // Calculate grid line positions\n const gridLines = useMemo<GridLine[]>(() => {\n return calculateGridLines(dateRange, dayWidth);\n }, [dateRange, dayWidth]);\n\n // Calculate weekend background blocks\n const weekendBlocks = useMemo(() => {\n return calculateWeekendBlocks(dateRange, dayWidth);\n }, [dateRange, dayWidth]);\n\n // Calculate total grid width\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) */}\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 {gridLines.map((line, index) => {\n // Determine line type class based on flags\n const lineClass = line.isMonthStart\n ? 'gantt-gb-monthSeparator'\n : line.isWeekStart\n ? 'gantt-gb-weekSeparator'\n : 'gantt-gb-dayLine';\n\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 </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\nexport interface DependencyLinesProps {\n /** All tasks in the chart */\n tasks: Task[];\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 * 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 monthStart,\n dayWidth,\n rowHeight,\n gridWidth,\n dragOverrides,\n selectedDep,\n}) => {\n // Create a lookup map for task positions and their indices\n const { taskPositions, taskIndices } = useMemo(() => {\n const positions = new Map<string, { left: number; right: number; rowTop: number }>();\n const indices = new Map<string, number>();\n\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 });\n });\n\n return { taskPositions: positions, taskIndices: indices };\n }, [tasks, monthStart, dayWidth, rowHeight, dragOverrides]);\n\n // Detect cycles for highlighting\n const cycleInfo = useMemo(() => {\n const result = detectCycles(tasks);\n const cycleTaskIds = new Set(result.cyclePath || []);\n return cycleTaskIds;\n }, [tasks]);\n\n // Calculate all dependency line paths\n const lines = useMemo(() => {\n const edges = getAllDependencyEdges(tasks);\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 }> = [];\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 || predecessorIndex === undefined || successorIndex === undefined) {\n continue; // Skip if task not found (shouldn't happen with validation)\n }\n\n // Determine if tasks are in reverse order (predecessor appears below successor)\n const reverseOrder = predecessorIndex > successorIndex;\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 });\n }\n\n return lines;\n }, [tasks, taskPositions, taskIndices, cycleInfo, monthStart, dayWidth, dragOverrides]);\n\n return (\n <svg\n className=\"gantt-dependencies-svg\"\n width={gridWidth}\n height={tasks.length * rowHeight}\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 }) => {\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\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 { validateDependencies, calculateSuccessorDate } from '../../utils/dependencyUtils';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/Popover';\nimport { TaskListRow } from './TaskListRow';\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'];\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 task is modified via inline edit */\n onTaskChange?: (task: 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 /** 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}\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, 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 = 520,\n onTaskChange,\n selectedTaskId,\n onTaskSelect,\n show = true,\n disableTaskNameEditing = false,\n disableDependencyEditing = false,\n onScrollToTask,\n onSelectedChipChange,\n}) => {\n const totalHeight = useMemo(\n () => tasks.length * rowHeight,\n [tasks.length, rowHeight]\n );\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 and chip selection\n useEffect(() => {\n if (!selectingPredecessorFor && !selectedChip) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setSelectingPredecessorFor(null);\n setSelectedChip(null);\n onSelectedChipChange?.(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 };\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, 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 onTaskChange?.(snappedTask);\n } else {\n // Predecessor not found — emit without snap (graceful fallback)\n onTaskChange?.(updatedTask);\n }\n\n setSelectingPredecessorFor(null);\n }, [tasks, onTaskChange]);\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 onTaskChange?.({ ...task, dependencies: updatedDeps });\n }, [tasks, onTaskChange]);\n\n return (\n <div\n ref={overlayRef}\n className={`gantt-tl-overlay${show ? '' : ' gantt-tl-hidden'}`}\n style={{ width: `${taskListWidth}px` }}\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 {/* 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 {tasks.map((task, index) => (\n <TaskListRow\n key={task.id}\n task={task}\n rowIndex={index}\n rowHeight={rowHeight}\n onTaskChange={onTaskChange}\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 />\n ))}\n </div>\n </div>\n </div>\n );\n};\n\nexport default TaskList;\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, { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport type { Task } from '../GanttChart';\nimport type { LinkType } from '../../types';\nimport { parseUTCDate } from '../../utils/dateUtils';\nimport { computeLagFromDates } 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\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}\n\nconst TrashIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\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\nfunction formatDepDescription(type: LinkType, lag: number | undefined): string {\n const effectiveLag = lag ?? 0;\n\n if (type === 'FS') {\n if (effectiveLag > 0) return `Начать через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0) return `Начать за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Начать сразу после окончания`;\n }\n if (type === 'FF') {\n if (effectiveLag > 0) return `Завершить через ${effectiveLag} дн. после окончания`;\n if (effectiveLag < 0) return `Завершить за ${Math.abs(effectiveLag)} дн. до окончания`;\n return `Завершить после окончания`;\n }\n if (type === 'SS') {\n if (effectiveLag > 0) return `Начать через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0) return `Начать за ${Math.abs(effectiveLag)} дн. до начала`;\n return `Начать вместе с началом`;\n }\n if (type === 'SF') {\n if (effectiveLag > 0) return `Завершить через ${effectiveLag} дн. после начала`;\n if (effectiveLag < 0) 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}) => {\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 onChipSelect?.(isSelected ? null : { successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });\n if (!isSelected) {\n onRowClick?.(taskId);\n onScrollToTask?.(taskId);\n }\n };\n\n const handleTrashClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onRemoveDependency?.(taskId, dep.taskId, dep.type);\n onChipSelectClear();\n };\n\n const Icon = LINK_TYPE_ICONS[dep.type];\n const depPrefix = formatDepDescription(dep.type, lag);\n const depName = predecessorName ?? dep.taskId;\n\n return (\n <Popover open={isSelected} onOpenChange={(open) => {}}>\n <PopoverTrigger asChild>\n <span className=\"gantt-tl-dep-chip-wrapper\">\n <span\n className={`gantt-tl-dep-chip${isSelected ? ' gantt-tl-dep-chip-selected' : ''}`}\n onClick={handleClick}\n >\n <><Icon />{lag != null && lag !== 0 ? (lag > 0 ? `+${lag}` : `${lag}`) : ''}</>\n </span>\n {!disableDependencyEditing && (\n <button\n type=\"button\"\n className=\"gantt-tl-dep-chip-trash\"\n aria-label=\"Удалить связь\"\n onClick={handleTrashClick}\n >\n <TrashIcon />\n </button>\n )}\n </span>\n </PopoverTrigger>\n <PopoverContent\n portal={true}\n side=\"bottom\"\n align=\"start\"\n className=\"gantt-tl-dep-info-popover\"\n onInteractOutside={(event) => {\n // Don't close the popover when clicking:\n // - the chip itself (allows toggle off behavior)\n // - the \"Удалить связь\" button on the predecessor row\n // - the trash (X) button on the chip itself\n const target = event.target as Element;\n if (target?.closest?.('.gantt-tl-dep-chip') || target?.closest?.('.gantt-tl-dep-delete-label') || target?.closest?.('.gantt-tl-dep-chip-trash')) {\n event.preventDefault();\n } else {\n onChipSelectClear();\n }\n }}\n >\n <span className=\"gantt-tl-dep-info-prefix\">{depPrefix}</span>\n <span className=\"gantt-tl-dep-info-name\">{depName}</span>\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 /** Height of the task row in pixels */\n rowHeight: number;\n /** Callback when task is modified via inline edit */\n onTaskChange?: (task: 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?: (successorTaskId: string, predecessorTaskId: string, linkType: LinkType) => void;\n /** Callback to remove a dependency link */\n onRemoveDependency?: (taskId: string, predecessorTaskId: string, linkType: LinkType) => void;\n /** Currently selected chip (for predecessor-side delete) */\n selectedChip?: { successorId: string; predecessorId: string; linkType: string } | null;\n /** Callback when a chip is clicked (selects it) */\n onChipSelect?: (chip: { successorId: string; predecessorId: string; linkType: LinkType } | null) => void;\n /** Callback to scroll the chart grid to center this task (called when № cell is clicked) */\n onScrollToTask?: (taskId: string) => void;\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')) 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 rowHeight,\n onTaskChange,\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 }) => {\n const [editingName, setEditingName] = useState(false);\n const [nameValue, setNameValue] = useState('');\n const nameInputRef = useRef<HTMLInputElement>(null);\n const [overflowOpen, setOverflowOpen] = useState(false);\n\n const isSelected = selectedTaskId === 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 }\n }, [editingName]);\n\n const handleNameClick = useCallback((e: React.MouseEvent) => {\n if (disableTaskNameEditing) return;\n e.stopPropagation();\n setNameValue(task.name);\n setEditingName(true);\n }, [task.name, disableTaskNameEditing]);\n\n const handleNameSave = useCallback(() => {\n if (nameValue.trim()) {\n onTaskChange?.({ ...task, name: nameValue.trim() });\n }\n setEditingName(false);\n }, [nameValue, task, onTaskChange]);\n\n const handleNameCancel = useCallback(() => {\n setEditingName(false);\n }, []);\n\n const handleNameKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') handleNameSave();\n else if (e.key === 'Escape') handleNameCancel();\n }, [handleNameSave, handleNameCancel]);\n\n // Both date pickers shift the whole task (preserving duration), same as drag-move\n const handleStartDateChange = useCallback((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 onTaskChange?.({ ...task, startDate: newDateISO, endDate: newEnd.toISOString().split('T')[0] });\n }, [task, onTaskChange]);\n\n const handleEndDateChange = useCallback((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 onTaskChange?.({ ...task, startDate: newStart.toISOString().split('T')[0], endDate: newDateISO });\n }, [task, onTaskChange]);\n\n const handleRowClickInternal = useCallback(() => {\n onRowClick?.(task.id);\n }, [task.id, onRowClick]);\n\n const handleNumberClick = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n onRowClick?.(task.id);\n onScrollToTask?.(task.id);\n }, [task.id, onRowClick, onScrollToTask]);\n\n // Dependency handlers\n const handleAddClick = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n onSetSelectingPredecessorFor?.(task.id);\n }, [task.id, onSetSelectingPredecessorFor]);\n\n const handlePredecessorPick = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n if (!isPicking || isSourceRow) return;\n if (!selectingPredecessorFor || !activeLinkType) return;\n onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);\n }, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);\n\n // True when this row is the predecessor for the currently selected chip\n const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;\n\n // Delete the selected dependency from the predecessor row's \"Удалить\" button\n const handleDeleteSelected = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n if (!selectedChip) return;\n onRemoveDependency?.(selectedChip.successorId, selectedChip.predecessorId, selectedChip.linkType as LinkType);\n onChipSelect?.(null);\n }, [selectedChip, onRemoveDependency, onChipSelect]);\n\n const startDateISO = toISODate(task.startDate);\n const endDateISO = toISODate(task.endDate);\n\n return (\n <div\n className={[\n 'gantt-tl-row',\n isSelected ? 'gantt-tl-row-selected' : '',\n isPicking && !isSourceRow ? 'gantt-tl-row-picking' : '',\n isSourceRow ? 'gantt-tl-row-picking-self' : '',\n ].filter(Boolean).join(' ')}\n style={{ minHeight: `${rowHeight}px` }}\n onClick={handleRowClickInternal}\n >\n {/* Number column — click selects the row and scrolls the grid to this task */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-number\"\n onClick={handleNumberClick}\n title=\"Перейти к работе\"\n >\n <span className=\"gantt-tl-num-label\">{rowIndex + 1}</span>\n <svg className=\"gantt-tl-num-icon\" 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\" />\n <path d=\"m11 18 6-6-6-6\" />\n <path d=\"M21 5v14\" />\n </svg>\n </div>\n\n {/* Name column — styled Input overlay on edit */}\n <div className=\"gantt-tl-cell gantt-tl-cell-name\">\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 onClick={(e) => e.stopPropagation()}\n />\n )}\n <button\n type=\"button\"\n className={`gantt-tl-name-trigger ${disableTaskNameEditing ? 'gantt-tl-name-locked' : ''}`}\n onClick={handleNameClick}\n style={editingName ? { visibility: 'hidden', pointerEvents: 'none' } : undefined}\n >\n {task.name}\n </button>\n </div>\n\n {/* Start Date — DatePicker component */}\n <div className=\"gantt-tl-cell gantt-tl-cell-date\" onClick={(e) => e.stopPropagation()}>\n <DatePicker\n value={startDateISO}\n onChange={handleStartDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n />\n </div>\n\n {/* End Date — DatePicker component */}\n <div className=\"gantt-tl-cell gantt-tl-cell-date\" onClick={(e) => e.stopPropagation()}>\n <DatePicker\n value={endDateISO}\n onChange={handleEndDateChange}\n format=\"dd.MM.yy\"\n portal={true}\n disabled={task.locked}\n />\n </div>\n\n {/* Dependencies column */}\n <div\n className=\"gantt-tl-cell gantt-tl-cell-deps\"\n onClick={isPicking && !isSourceRow ? handlePredecessorPick : undefined}\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\">Связано с</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) => { e.stopPropagation(); setOverflowOpen(v => !v); }}\n >\n {chips.length} {linkWord}\n </button>\n </PopoverTrigger>\n <PopoverContent portal={true} align=\"start\">\n <div className=\"gantt-tl-dep-overflow-list\" onClick={(e) => e.stopPropagation()}>\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 />\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 />\n ) : null}\n\n {/* \"+\" add dependency button — hidden in picker mode and when editing disabled */}\n {!disableDependencyEditing && !isPicking && (\n <button\n type=\"button\"\n className=\"gantt-tl-dep-add\"\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 } from 'react';\nimport { format, isValid } 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}\n\n/**\n * DatePicker component — shows formatted date as a button, opens calendar popup on click\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}) => {\n const [open, setOpen] = useState(false);\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\n const displayValue = selectedDate\n ? format(selectedDate, displayFormat)\n : placeholder;\n\n const handleSelect = useCallback(\n (day: Date) => {\n // Convert to ISO string using local date parts to avoid timezone shift\n const iso = [\n day.getFullYear(),\n String(day.getMonth() + 1).padStart(2, '0'),\n String(day.getDate()).padStart(2, '0'),\n ].join('-');\n onChange?.(iso);\n setOpen(false);\n },\n [onChange]\n );\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 <Calendar\n mode=\"single\"\n selected={selectedDate}\n onSelect={handleSelect}\n initialDate={selectedDate}\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';\n\nexport interface CalendarProps {\n selected?: Date;\n onSelect?: (date: Date) => void;\n initialDate?: Date;\n mode?: 'single' | 'range';\n disabled?: boolean;\n}\n\nfunction getDayClassName(day: Date, selected: Date | undefined): 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 if (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}) => {\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 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(month.getFullYear(), month.getMonth(), dayNum);\n const className = getDayClassName(day, selected);\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(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 {emptyCells}\n {dayCells}\n </div>\n </div>\n );\n },\n [selected, onSelect, disabled]\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 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"],"mappings":"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","names":["import_react","startOfMonth","isWeekend","import_react","isWeekend","import_react","dayWidth","getUTCDayDifference","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","import_jsx_runtime","import_jsx_runtime","React","import_jsx_runtime","React","import_jsx_runtime","import_react","import_jsx_runtime","React"]}