@art-tools/react-gantt 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/core/lruCache.ts","../src/core/utils.ts","../src/core/dateUtils.ts","../src/core/calendar.ts","../src/hooks/useResolvedCalendar.ts","../src/core/workingTime.ts","../src/core/taskDates.ts","../src/core/labels.ts","../src/core/prepareData.ts","../src/core/queue.ts","../src/core/scheduling.ts","../src/hooks/useTaskList.ts","../src/hooks/useLatestRef.ts","../src/hooks/useExpand.ts","../src/hooks/useIsomorphicLayoutEffect.ts","../src/hooks/useViewportMeasure.ts","../src/hooks/useScrollSync.ts","../src/hooks/useEventCallback.ts","../src/core/scroll.ts","../src/core/barUtils.ts","../src/core/scales.ts","../src/core/timeline.ts","../src/hooks/useRevealTask.ts","../src/hooks/useZoom.ts","../src/core/zoom.ts","../src/hooks/useDependencyDrag.ts","../src/context/useGanttHandle.ts","../src/context/useColumnApi.ts","../src/context/contexts.ts","../src/context/GanttProvider.tsx","../src/context/GanttSlotsContext.tsx","../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/core/slots.ts","../src/components/calendar/Calendar.module.css","../src/components/calendar/CalendarRow.tsx","../src/components/calendar/Calendar.tsx","../src/hooks/useAutoScroll.ts","../src/hooks/useDrag.ts","../src/components/bars/barTooltip/BarTooltip.module.css","../src/components/bars/barTooltip/BarTooltipContext.ts","../src/components/bars/barTooltip/BarTooltipRoot.tsx","../src/components/bars/barTooltip/BarTooltipTrigger.tsx","../src/components/bars/barTooltip/useTooltipPosition.ts","../src/components/bars/barTooltip/BarTooltip.tsx","../src/components/bars/barTooltip/BarTooltipConsumer.tsx","../src/components/bars/common/DraggableBar.tsx","../src/components/bars/milestoneBar/MilestoneBar.module.css","../src/components/bars/milestoneBar/MilestoneBar.tsx","../src/components/bars/progress/BarProgress.module.css","../src/components/bars/progress/BarProgressResizeHandle.tsx","../src/components/bars/progress/BarProgress.tsx","../src/components/bars/projectBar/ProjectBar.module.css","../src/components/bars/projectBar/ProjectBar.tsx","../src/components/bars/taskBar/TaskBar.module.css","../src/components/bars/taskBar/TaskResizer.tsx","../src/components/bars/taskBar/TaskBar.tsx","../src/components/bars/common/ConnectorHandles.module.css","../src/components/bars/common/ConnectorHandles.tsx","../src/components/bars/common/Row.module.css","../src/components/bars/common/Row.tsx","../src/components/dependency-links/geometry.ts","../src/components/dependency-links/DependencyLinksContext.tsx","../src/components/dependency-links/DependencyLinks.module.css","../src/components/dependency-links/DependencyLinks.tsx","../src/components/dependency-links/DependencyPreview.module.css","../src/components/dependency-links/DependencyPreview.tsx","../src/components/grid/GridColumns.module.css","../src/components/grid/GridColumns.tsx","../src/components/grid/Grid.module.css","../src/core/virtualize.ts","../src/components/grid/Grid.tsx","../src/components/grid/GridResizeHandle.module.css","../src/components/grid/GridResizeHandle.tsx","../src/components/taskList/TaskList.module.css","../src/components/taskList/TaskListHeader.tsx","../src/components/taskList/TreeCell.tsx","../src/components/taskList/TaskListRow.tsx","../src/hooks/useColumnWidths.ts","../src/components/taskList/TaskList.tsx","../src/hooks/useGridResize.ts","../src/components/taskList/ActionsCell.module.css","../src/components/taskList/ActionsCell.tsx","../src/components/taskList/defaultColumns.tsx","../src/Gantt.tsx"],"sourcesContent":["export class LRUCache<K, V> {\n private cache = new Map<K, V>();\n private capacity: number;\n\n constructor(size: number) {\n this.capacity = size;\n }\n\n private refreshKey(key: K): void {\n if (!this.cache.has(key)) {\n return;\n }\n const val = this.cache.get(key) as V;\n this.cache.delete(key);\n this.cache.set(key, val);\n }\n\n get(key: K): V | undefined {\n if (!this.cache.has(key)) {\n return undefined;\n }\n this.refreshKey(key);\n return this.cache.get(key);\n }\n\n put(key: K, value: V): void {\n this.refreshKey(key);\n this.cache.set(key, value);\n\n if (this.cache.size > this.capacity) {\n const [removeKey] = this.cache.keys();\n this.cache.delete(removeKey as K);\n }\n }\n}\n","import { LRUCache } from \"./lruCache\";\n\nexport function memoizeWithLRUCache<K, V>(fn: (arg: K) => V, cacheSize: number): (arg: K) => V {\n const cache = new LRUCache<K, V>(cacheSize);\n return (arg: K) => {\n const cached = cache.get(arg);\n if (cached != null) {\n return cached;\n }\n const result = fn(arg);\n cache.put(arg, result);\n return result;\n };\n}\n\nexport function memoize<K, V>(fn: (arg: K) => V, cacheSize: number): (arg: K) => V {\n return memoizeWithLRUCache(fn, cacheSize);\n}\n","import type { CalendarUnit } from \"../types\";\nimport { memoize } from \"./utils\";\n\nconst MS_PER_MINUTE = 60_000;\nconst MS_PER_HOUR = 3_600_000;\nconst MS_PER_DAY = 86_400_000;\nconst MS_PER_WEEK = MS_PER_DAY * 7;\n\n/** Fixed-length units convert to pixels by simple ms division. */\nconst LINEAR_UNIT_MS: Partial<Record<CalendarUnit, number>> = {\n minute: MS_PER_MINUTE,\n hour: MS_PER_HOUR,\n day: MS_PER_DAY,\n week: MS_PER_WEEK,\n};\n\nexport function periodKey(date: Date, unit: CalendarUnit, step: number): string {\n const y = date.getFullYear();\n const m = date.getMonth();\n const d = date.getDate();\n\n switch (unit) {\n case \"minute\": {\n const local = new Date(date);\n local.setSeconds(0, 0);\n const minuteIndex = Math.round(local.getTime() / MS_PER_MINUTE);\n return `mi-${Math.floor(minuteIndex / step)}`;\n }\n case \"hour\": {\n const local = new Date(date);\n local.setMinutes(0, 0, 0);\n const hourIndex = Math.round(local.getTime() / MS_PER_HOUR);\n return `h-${Math.floor(hourIndex / step)}`;\n }\n case \"day\": {\n const dayIndex = Math.floor(Date.UTC(y, m, d) / MS_PER_DAY);\n return `d-${Math.floor(dayIndex / step)}`;\n }\n case \"week\": {\n const local = new Date(y, m, d);\n const dow = local.getDay();\n const toMonday = dow === 0 ? -6 : 1 - dow;\n local.setDate(local.getDate() + toMonday);\n const weekIndex = Math.floor(local.getTime() / (MS_PER_DAY * 7));\n return `w-${Math.floor(weekIndex / step)}`;\n }\n case \"month\": {\n const monthIndex = y * 12 + m;\n return `mo-${Math.floor(monthIndex / step)}`;\n }\n case \"quarter\": {\n const quarterIndex = y * 4 + Math.floor(m / 3);\n return `q-${Math.floor(quarterIndex / step)}`;\n }\n case \"year\": {\n return `y-${Math.floor(y / step)}`;\n }\n default:\n throw new Error(`Unsupported unit: ${unit}`);\n }\n}\n\nexport function isWeekend(date: Date): boolean {\n const dow = date.getDay();\n return dow === 0 || dow === 6;\n}\n\n/**\n * Index of the local *civil* day containing `date` — days since 1970-01-01 by\n * calendar date, ignoring time of day and immune to DST because it is computed\n * from the civil fields rather than the epoch instant.\n *\n * The working-time calendar keys every day off this, so identical civil dates\n * in different timezones map to the same index.\n */\nexport function civilDayIndex(date: Date): number {\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / MS_PER_DAY;\n}\n\n/** Local midnight starting the civil day at `dayIndex`. Inverse of {@link civilDayIndex}. */\nexport function dateFromCivilDayIndex(dayIndex: number): Date {\n const utc = new Date(dayIndex * MS_PER_DAY);\n return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());\n}\n\nexport function diffDays(from: Date, to: Date): number {\n return civilDayIndex(to) - civilDayIndex(from);\n}\n\nexport function addDays(date: Date, days: number): Date {\n const d = new Date(date);\n d.setHours(0, 0, 0, 0);\n return new Date(d.getTime() + days * MS_PER_DAY);\n}\n\n/**\n * Start boundary of the calendar unit containing `date` (local time): top of the\n * minute/hour, midnight for `day`, Monday for `week`, the 1st for `month`, the\n * first day of the quarter for `quarter`, Jan 1 for `year`.\n */\nexport function startOfUnit(date: Date, unit: CalendarUnit): Date {\n const d = new Date(date);\n switch (unit) {\n case \"minute\": {\n d.setSeconds(0, 0);\n return d;\n }\n case \"hour\": {\n d.setMinutes(0, 0, 0);\n return d;\n }\n case \"day\": {\n d.setHours(0, 0, 0, 0);\n return d;\n }\n case \"week\": {\n d.setHours(0, 0, 0, 0);\n const dow = d.getDay();\n const toMonday = dow === 0 ? -6 : 1 - dow;\n d.setDate(d.getDate() + toMonday);\n return d;\n }\n case \"month\": {\n d.setHours(0, 0, 0, 0);\n d.setDate(1);\n return d;\n }\n case \"quarter\": {\n d.setHours(0, 0, 0, 0);\n d.setMonth(Math.floor(d.getMonth() / 3) * 3, 1);\n return d;\n }\n case \"year\": {\n d.setHours(0, 0, 0, 0);\n d.setMonth(0, 1);\n return d;\n }\n default: {\n throw new Error(`Unsupported unit: ${unit}`);\n }\n }\n}\n\n/**\n * Add `amount` whole calendar units to `date`. Minute/hour/day/week are fixed-ms\n * math; month/quarter/year use calendar arithmetic (`setMonth`/`setFullYear`) so\n * lengths and leap years are respected. Time-of-day is preserved for sub-day\n * units and via the calendar setters for month+.\n */\nexport function addUnit(date: Date, unit: CalendarUnit, amount: number): Date {\n const linearMs = LINEAR_UNIT_MS[unit];\n if (linearMs !== undefined) {\n if (unit === \"day\" || unit === \"week\") {\n return addDays(date, amount * (linearMs / MS_PER_DAY));\n }\n return new Date(date.getTime() + amount * linearMs);\n }\n const d = new Date(date);\n switch (unit) {\n case \"month\": {\n d.setMonth(d.getMonth() + amount);\n return d;\n }\n case \"quarter\": {\n d.setMonth(d.getMonth() + amount * 3);\n return d;\n }\n case \"year\": {\n d.setFullYear(d.getFullYear() + amount);\n return d;\n }\n default: {\n throw new Error(`Unsupported unit: ${unit}`);\n }\n }\n}\n\n/**\n * Fractional number of `unit` columns from `origin` to `date`. Fixed-length units\n * are linear ms; month/quarter/year count whole units with calendar-correct\n * boundaries and interpolate the partial unit within its own [start, next) span.\n * Inverse of {@link dateAtOffset}.\n */\nexport function unitOffset(origin: Date, date: Date, unit: CalendarUnit): number {\n const linearMs = LINEAR_UNIT_MS[unit];\n if (linearMs !== undefined) {\n return (date.getTime() - origin.getTime()) / linearMs;\n }\n // Bracket `date` between whole-unit boundaries addUnit(origin, unit, k) and\n // addUnit(origin, unit, k+1). Seed k from raw month arithmetic, then correct\n // (only a step or two) so the estimate survives varying month lengths.\n const monthsPerUnit = unit === \"month\" ? 1 : unit === \"quarter\" ? 3 : 12;\n const originMonths = origin.getFullYear() * 12 + origin.getMonth();\n const dateMonths = date.getFullYear() * 12 + date.getMonth();\n let k = Math.floor((dateMonths - originMonths) / monthsPerUnit);\n while (addUnit(origin, unit, k).getTime() > date.getTime()) {\n k -= 1;\n }\n while (addUnit(origin, unit, k + 1).getTime() <= date.getTime()) {\n k += 1;\n }\n const base = addUnit(origin, unit, k).getTime();\n const next = addUnit(origin, unit, k + 1).getTime();\n return k + (date.getTime() - base) / (next - base);\n}\n\n/**\n * Date at a fractional `offset` of `unit` columns from `origin`. Inverse of\n * {@link unitOffset}.\n */\nexport function dateAtOffset(origin: Date, unit: CalendarUnit, offset: number): Date {\n const linearMs = LINEAR_UNIT_MS[unit];\n if (linearMs !== undefined) {\n return new Date(origin.getTime() + offset * linearMs);\n }\n const whole = Math.floor(offset);\n const frac = offset - whole;\n const base = addUnit(origin, unit, whole).getTime();\n const next = addUnit(origin, unit, whole + 1).getTime();\n return new Date(base + frac * (next - base));\n}\n\nexport function buildDates(\n start: Date,\n count: number,\n unit: CalendarUnit = \"day\",\n step = 1,\n): Date[] {\n return Array.from({ length: count }, (_, i) => addUnit(start, unit, i * step));\n}\n\ninterface TaskDates {\n startDate: Date;\n endDate?: Date;\n}\n\nfunction getMinMaxDatesNonCached(tasks: readonly TaskDates[]): { min: Date; max: Date } | null {\n const first = tasks[0];\n if (!first) {\n return null;\n }\n let min = first.startDate;\n let max = first.endDate ?? first.startDate;\n for (const t of tasks) {\n if (t.startDate < min) {\n min = t.startDate;\n }\n const end = t.endDate ?? t.startDate;\n if (end > max) {\n max = end;\n }\n }\n return { min, max };\n}\n\nexport const getMinMaxDates = memoize(getMinMaxDatesNonCached, 3);\n","import type { DayHours, GanttCalendar, Weekday, WorkTimeRange } from \"../types\";\nimport { civilDayIndex } from \"./dateUtils\";\n\nexport const MINUTES_PER_DAY = 1440;\nexport const MS_PER_MINUTE = 60_000;\n\n/** Every day fully working — the shape a calendar resolves to when `hours` is omitted. */\nconst FULL_DAY_INTERVALS: readonly number[] = [0, MINUTES_PER_DAY];\n\n/**\n * The normalized working intervals of one civil day, as minutes from local\n * midnight. Sorted, non-overlapping, and non-adjacent — `[\"8:00-12:00\",\n * \"12:00-17:00\"]` merges to a single `8:00-17:00` interval and interns\n * identically to it.\n */\nexport interface DayShape {\n /** Flattened `[from0, to0, from1, to1, …]`. Empty means a day off. */\n readonly intervals: readonly number[];\n /**\n * Cumulative working minutes *before* each interval, so `prefix[i]` is the\n * work done by the time interval `i` starts. `prefix[0]` is always 0.\n */\n readonly prefix: readonly number[];\n /** Total working minutes: 0 for a day off, 1440 for a full day. */\n readonly totalMinutes: number;\n /** Interning id — structurally identical shapes are `===`, so `id` is only for debugging. */\n readonly id: number;\n}\n\n/**\n * A {@link GanttCalendar} resolved into a queryable form. Immutable, framework-free,\n * and identity-stable per content (see `calendarKey`), so it is safe to use\n * directly as a React dependency or cache key.\n */\nexport interface ResolvedCalendar {\n readonly key: string;\n /** Indexed by `Date.prototype.getDay()`; the global `hours` are already folded in. */\n readonly byWeekday: readonly DayShape[];\n /** Civil day index → shape, for `dates` overrides only. */\n readonly byDate: ReadonlyMap<number, DayShape>;\n /** Sorted `byDate` keys, so a walk can find the next override in O(log n). */\n readonly overrideDays: readonly number[];\n /** Every weekday is a full 00:00–24:00 day and there are no date overrides. */\n readonly isAlwaysWorking: boolean;\n /** No shape is partial — each is either empty or a full day. */\n readonly isDayGranular: boolean;\n /** Working minutes across the seven weekday shapes. 0 means a degenerate calendar. */\n readonly weekMinutes: number;\n /** Working ms that one `durationUnit: \"day\"` represents (ADR-018: the week's longest working day). */\n readonly msPerWorkingDay: number;\n}\n\nconst RANGE_RE = /^\\s*(\\d{1,2}):(\\d{2})\\s*-\\s*(\\d{1,2}):(\\d{2})\\s*$/;\n\n/**\n * Parse one `\"H:MM-H:MM\"` range into `[fromMinute, toMinute)`. Throws on anything\n * unparseable so a typo surfaces at the edge rather than as a silently wrong schedule.\n */\nexport function parseWorkTimeRange(range: WorkTimeRange): [number, number] {\n const m = RANGE_RE.exec(range);\n if (!m) {\n throw new Error(\n `Invalid working-hours range ${JSON.stringify(range)}: expected \"H:MM-H:MM\", e.g. \"8:30-12:00\".`,\n );\n }\n const from = Number(m[1]) * 60 + Number(m[2]);\n const to = Number(m[3]) * 60 + Number(m[4]);\n if (from < 0 || from >= MINUTES_PER_DAY) {\n throw new Error(\n `Invalid working-hours range ${JSON.stringify(range)}: start must be within the day.`,\n );\n }\n if (to <= from || to > MINUTES_PER_DAY) {\n throw new Error(\n `Invalid working-hours range ${JSON.stringify(range)}: end must be after start and no later than 24:00.`,\n );\n }\n return [from, to];\n}\n\n/** Sort, merge adjacent/overlapping, and flatten a day's ranges into interval pairs. */\nfunction normalizeIntervals(hours: DayHours | undefined): readonly number[] {\n if (hours === undefined) {\n return FULL_DAY_INTERVALS;\n }\n if (hours === false) {\n return [];\n }\n const pairs = hours.map(parseWorkTimeRange).toSorted((a, b) => a[0] - b[0]);\n const out: number[] = [];\n for (const [from, to] of pairs) {\n const lastEnd = out.length > 0 ? out[out.length - 1]! : undefined;\n if (lastEnd !== undefined && from <= lastEnd) {\n // Overlapping or adjacent — extend the run rather than emitting a gap.\n if (to > lastEnd) {\n out[out.length - 1] = to;\n }\n continue;\n }\n out.push(from, to);\n }\n return out;\n}\n\nfunction makeShape(intervals: readonly number[], id: number): DayShape {\n const prefix: number[] = [];\n let total = 0;\n for (let i = 0; i < intervals.length; i += 2) {\n prefix.push(total);\n total += intervals[i + 1]! - intervals[i]!;\n }\n return { intervals, prefix, totalMinutes: total, id };\n}\n\n/** Interns shapes by their normalized signature so identical days compare with `===`. */\nfunction shapeInterner() {\n const cache = new Map<string, DayShape>();\n return (intervals: readonly number[]): DayShape => {\n const signature = intervals.join(\",\");\n const existing = cache.get(signature);\n if (existing) {\n return existing;\n }\n const shape = makeShape(intervals, cache.size);\n cache.set(signature, shape);\n return shape;\n };\n}\n\nfunction hoursKey(hours: DayHours | undefined): string {\n if (hours === undefined) {\n return \"*\";\n }\n if (hours === false) {\n return \"-\";\n }\n return hours.join(\",\");\n}\n\n/**\n * A deterministic structural key for a calendar spec.\n *\n * Consumers write `calendar={{ … }}` inline, so keying the resolved calendar by\n * object *identity* would rebuild it — and invalidate everything memoized on it —\n * on every render. Keying by content makes an inline object free.\n *\n * `dates` keys are sorted explicitly: integer-like keys (`days`) are ordered by\n * the JS engine, but `\"2026-01-01\"` keys keep insertion order, which would\n * otherwise leak into the key. Keys are compared *raw*, so `\"8:00-12:00\"` and\n * `\"08:00-12:00\"` produce different keys for the same calendar — a cache miss,\n * never a wrong answer, and normalizing first would cost the parse this avoids.\n */\nexport function calendarKey(calendar: GanttCalendar | undefined): string {\n if (!calendar) {\n return \"\";\n }\n const parts: string[] = [hoursKey(calendar.hours)];\n for (let day = 0; day < 7; day++) {\n const hours = calendar.days?.[day as Weekday];\n if (hours !== undefined) {\n parts.push(`${day}=${hoursKey(hours)}`);\n }\n }\n const dates = calendar.dates;\n if (dates) {\n for (const date of Object.keys(dates).toSorted()) {\n parts.push(`${date}=${hoursKey(dates[date])}`);\n }\n }\n return parts.join(\"|\");\n}\n\nconst DATE_KEY_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\nfunction dayIndexFromDateKey(key: string): number {\n const m = DATE_KEY_RE.exec(key);\n if (!m) {\n throw new Error(\n `Invalid calendar date key ${JSON.stringify(key)}: expected a local civil date, \"YYYY-MM-DD\".`,\n );\n }\n return civilDayIndex(new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])));\n}\n\n/**\n * Resolve a spec into a queryable calendar. `key` should come from\n * {@link calendarKey}; it is carried so downstream caches can compare content.\n */\nexport function buildCalendar(calendar: GanttCalendar, key: string): ResolvedCalendar {\n const intern = shapeInterner();\n const globalIntervals = normalizeIntervals(calendar.hours);\n\n const byWeekday: DayShape[] = [];\n for (let day = 0; day < 7; day++) {\n const override = calendar.days?.[day as Weekday];\n byWeekday.push(intern(override === undefined ? globalIntervals : normalizeIntervals(override)));\n }\n\n const byDate = new Map<number, DayShape>();\n if (calendar.dates) {\n for (const [dateKey, hours] of Object.entries(calendar.dates)) {\n byDate.set(dayIndexFromDateKey(dateKey), intern(normalizeIntervals(hours)));\n }\n }\n const overrideDays = [...byDate.keys()].toSorted((a, b) => a - b);\n\n let weekMinutes = 0;\n let isDayGranular = true;\n let isAlwaysWorking = byDate.size === 0;\n for (const shape of byWeekday) {\n weekMinutes += shape.totalMinutes;\n if (shape.totalMinutes !== 0 && shape.totalMinutes !== MINUTES_PER_DAY) {\n isDayGranular = false;\n }\n if (shape.totalMinutes !== MINUTES_PER_DAY) {\n isAlwaysWorking = false;\n }\n }\n for (const shape of byDate.values()) {\n if (shape.totalMinutes !== 0 && shape.totalMinutes !== MINUTES_PER_DAY) {\n isDayGranular = false;\n }\n }\n\n // ADR-018: one `durationUnit: \"day\"` is the week's LONGEST working day, so a\n // weekends-off calendar over full days gives exactly 24h and `duration: 3`\n // stays three whole days.\n let longestDayMinutes = 0;\n for (const shape of byWeekday) {\n if (shape.totalMinutes > longestDayMinutes) {\n longestDayMinutes = shape.totalMinutes;\n }\n }\n\n return {\n key,\n byWeekday,\n byDate,\n overrideDays,\n isAlwaysWorking,\n isDayGranular,\n weekMinutes,\n msPerWorkingDay: longestDayMinutes * MS_PER_MINUTE,\n };\n}\n\n/** The working shape of the civil day at `dayIndex`: a date override if one exists, else the weekday rule. */\nexport function shapeFor(calendar: ResolvedCalendar, dayIndex: number): DayShape {\n const override = calendar.byDate.get(dayIndex);\n if (override) {\n return override;\n }\n // `dayIndex` 0 is 1970-01-01, a Thursday (getDay() === 4).\n return calendar.byWeekday[(((dayIndex + 4) % 7) + 7) % 7]!;\n}\n\n/**\n * Smallest date-override day `>= dayIndex`, or `Infinity`. Lets a walk skip whole\n * weeks safely: between here and the next override, only the weekday rules apply.\n */\nexport function nextOverrideDay(calendar: ResolvedCalendar, dayIndex: number): number {\n const days = calendar.overrideDays;\n let lo = 0;\n let hi = days.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (days[mid]! < dayIndex) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n return lo < days.length ? days[lo]! : Number.POSITIVE_INFINITY;\n}\n\n/** Largest date-override day `<= dayIndex`, or `-Infinity`. The backward-walk mirror. */\nexport function prevOverrideDay(calendar: ResolvedCalendar, dayIndex: number): number {\n const days = calendar.overrideDays;\n let lo = 0;\n let hi = days.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (days[mid]! <= dayIndex) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n return lo > 0 ? days[lo - 1]! : Number.NEGATIVE_INFINITY;\n}\n","import { useRef } from \"react\";\nimport { buildCalendar, calendarKey, type ResolvedCalendar } from \"../core/calendar\";\nimport type { GanttCalendar } from \"../types\";\n\ninterface Cached {\n key: string;\n value: ResolvedCalendar | null;\n}\n\n/**\n * Resolve a {@link GanttCalendar} into its queryable form, keyed by **content**.\n *\n * Consumers write the prop inline — `calendar={{ hours: [...], dates: {...} }}` —\n * so a fresh object arrives on every render. Keying on identity would rebuild the\n * calendar each time and, worse, churn the identity that the task-list memo and\n * every downstream cache depend on. Hashing the spec instead makes an inline\n * object free, and the returned object is identity-stable for as long as the\n * content is unchanged, so callers can use it as a plain dependency.\n *\n * Deliberately a ref rather than `useMemo`: the cache key is derived, not a\n * dependency list, and `useMemo` offers no correctness guarantee anyway.\n *\n * Returns `null` when no calendar is supplied — the signal for plain linear time\n * throughout `core/*`.\n */\nexport function useResolvedCalendar(calendar?: GanttCalendar): ResolvedCalendar | null {\n const cache = useRef<Cached | null>(null);\n const key = calendarKey(calendar);\n\n if (!cache.current || cache.current.key !== key) {\n cache.current = {\n key,\n value: calendar ? buildCalendar(calendar, key) : null,\n };\n }\n return cache.current.value;\n}\n","import type { DurationUnit } from \"../types\";\nimport {\n MINUTES_PER_DAY,\n MS_PER_MINUTE,\n nextOverrideDay,\n prevOverrideDay,\n shapeFor,\n type DayShape,\n type ResolvedCalendar,\n} from \"./calendar\";\nimport { civilDayIndex, dateFromCivilDayIndex } from \"./dateUtils\";\n\nconst MS_PER_HOUR = 3_600_000;\nconst MS_PER_DAY = 86_400_000;\n\n/** ~55 years. A walk that exceeds this is a degenerate calendar, not a real schedule. */\nconst MAX_WALK_DAYS = 20_000;\n\n/** Which way a walk projects a non-working anchor before moving (ADR-007). */\nexport type WalkDirection = 1 | -1;\n\n/**\n * Wall-clock minutes since local midnight, fractional to millisecond precision.\n *\n * Deliberately read from the civil fields rather than an epoch difference:\n * working time is measured in *civil* time, so a DST day is simply short or long\n * and `\"9:00\"` means nine o'clock on every day of the year.\n */\nfunction minuteOfDay(date: Date): number {\n const ms =\n date.getHours() * MS_PER_HOUR +\n date.getMinutes() * MS_PER_MINUTE +\n date.getSeconds() * 1000 +\n date.getMilliseconds();\n return ms / MS_PER_MINUTE;\n}\n\n/**\n * The instant `minute` wall-clock minutes into the civil day at `dayIndex`.\n *\n * Built with the local civil constructor and an overflowing millisecond field, so\n * `instantAt(d, 1440)` is local midnight of the next civil day whether that day is\n * 23, 24, or 25 hours long. Never add 86_400_000 ms instead — that drifts across\n * every DST boundary.\n */\nfunction instantAt(dayIndex: number, minute: number): Date {\n const base = dateFromCivilDayIndex(dayIndex);\n return new Date(\n base.getFullYear(),\n base.getMonth(),\n base.getDate(),\n 0,\n 0,\n 0,\n Math.round(minute * MS_PER_MINUTE),\n );\n}\n\n/** Working minutes strictly before `minute` within this day. */\nfunction workedBefore(shape: DayShape, minute: number): number {\n const { intervals, prefix } = shape;\n for (let i = 0, p = 0; i < intervals.length; i += 2, p++) {\n const from = intervals[i]!;\n const to = intervals[i + 1]!;\n if (minute <= from) {\n return prefix[p]!;\n }\n if (minute < to) {\n return prefix[p]! + (minute - from);\n }\n }\n return shape.totalMinutes;\n}\n\n/**\n * The minute at which `worked` minutes of work have elapsed, resolving an exact\n * interval boundary to that interval's **end**.\n *\n * This is the tie-break a forward walk needs: having worked through lunch, you\n * finish at 12:00, you do not start at 13:00.\n */\nfunction minuteAtWorkedBackAnchored(shape: DayShape, worked: number): number {\n const { intervals, prefix } = shape;\n let result = intervals.length > 0 ? intervals[0]! : 0;\n for (let i = 0, p = 0; i < intervals.length; i += 2, p++) {\n if (prefix[p]! >= worked) {\n break;\n }\n result = intervals[i]! + (worked - prefix[p]!);\n }\n return result;\n}\n\n/**\n * The minute at which `worked` minutes of work have elapsed, resolving an exact\n * interval boundary to the next interval's **start**.\n *\n * The mirror tie-break, for a backward walk computing a start: a task needing the\n * afternoon begins at 13:00, not at 12:00.\n */\nfunction minuteAtWorkedFwdAnchored(shape: DayShape, worked: number): number {\n const { intervals, prefix } = shape;\n for (let i = 0, p = 0; i < intervals.length; i += 2, p++) {\n const length = intervals[i + 1]! - intervals[i]!;\n if (worked < prefix[p]! + length) {\n return intervals[i]! + (worked - prefix[p]!);\n }\n }\n return intervals.length > 0 ? intervals[intervals.length - 1]! : 0;\n}\n\n/** First working minute at or after `minute` within this day, or `null`. */\nfunction nextStartAtOrAfter(shape: DayShape, minute: number): number | null {\n const { intervals } = shape;\n for (let i = 0; i < intervals.length; i += 2) {\n if (minute < intervals[i + 1]!) {\n return Math.max(minute, intervals[i]!);\n }\n }\n return null;\n}\n\n/** Last valid *finish* minute at or before `minute` within this day, or `null`. */\nfunction prevEndAtOrBefore(shape: DayShape, minute: number): number | null {\n const { intervals } = shape;\n let best: number | null = null;\n for (let i = 0; i < intervals.length; i += 2) {\n if (minute > intervals[i]!) {\n best = Math.min(minute, intervals[i + 1]!);\n }\n }\n return best;\n}\n\n/**\n * Is work happening at this instant? Half-open, matching the range syntax: with\n * hours ending at 17:00, `16:59:59.999` is working and `17:00` is not.\n */\nexport function isWorkingTime(calendar: ResolvedCalendar | null, date: Date): boolean {\n if (!calendar) {\n return true;\n }\n if (calendar.isAlwaysWorking) {\n return true;\n }\n const shape = shapeFor(calendar, civilDayIndex(date));\n const minute = minuteOfDay(date);\n const { intervals } = shape;\n for (let i = 0; i < intervals.length; i += 2) {\n if (minute >= intervals[i]! && minute < intervals[i + 1]!) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Project `date` onto working time in the direction a walk is about to travel.\n *\n * `dir === 1` returns the earliest working instant at or after `date` — the shape\n * a task **start** must have. `dir === -1` returns the latest valid **finish** at\n * or before it, i.e. the latest instant whose preceding moment is working.\n *\n * Idempotent in each direction, which is what keeps the dependency cascade's\n * fixpoint reachable. It is deliberately **not** symmetric: projecting a Saturday\n * forward lands on Monday morning and backward on Friday evening, so a round trip\n * does not return Saturday. See ADR-007 — that asymmetry is the design, because a\n * walk's meaning depends on whether it computes a start or a finish.\n */\nexport function closestWorkingTime(\n calendar: ResolvedCalendar | null,\n date: Date,\n dir: WalkDirection,\n): Date {\n if (!calendar || calendar.isAlwaysWorking) {\n return date;\n }\n if (calendar.weekMinutes === 0 && calendar.byDate.size === 0) {\n // Nothing is ever working: degrade to identity rather than scanning to the cap.\n return date;\n }\n let day = civilDayIndex(date);\n let minute = minuteOfDay(date);\n\n for (let guard = 0; guard < MAX_WALK_DAYS; guard++) {\n const shape = shapeFor(calendar, day);\n if (dir === 1) {\n const start = nextStartAtOrAfter(shape, minute);\n if (start !== null) {\n return start === minute && day === civilDayIndex(date) ? date : instantAt(day, start);\n }\n day += 1;\n minute = 0;\n continue;\n }\n const end = prevEndAtOrBefore(shape, minute);\n if (end !== null) {\n return end === minute && day === civilDayIndex(date) ? date : instantAt(day, end);\n }\n day -= 1;\n minute = MINUTES_PER_DAY;\n }\n // Degenerate calendar (no working time anywhere in range) — degrade rather than\n // hang a render.\n return date;\n}\n\n/** Nearest working instant in either direction; ties go forward. Milestones only (ADR-009). */\nexport function nearestWorkingTime(calendar: ResolvedCalendar | null, date: Date): Date {\n if (!calendar || calendar.isAlwaysWorking) {\n return date;\n }\n if (isWorkingTime(calendar, date)) {\n return date;\n }\n const forward = closestWorkingTime(calendar, date, 1);\n const backward = closestWorkingTime(calendar, date, -1);\n const forwardGap = forward.getTime() - date.getTime();\n const backwardGap = date.getTime() - backward.getTime();\n return forwardGap <= backwardGap ? forward : backward;\n}\n\nfunction walkForward(calendar: ResolvedCalendar, anchor: Date, minutes: number): Date {\n let day = civilDayIndex(anchor);\n let minute = minuteOfDay(anchor);\n let remaining = minutes;\n\n for (let guard = 0; guard < MAX_WALK_DAYS; guard++) {\n const shape = shapeFor(calendar, day);\n const worked = workedBefore(shape, minute);\n const available = shape.totalMinutes - worked;\n if (remaining <= available) {\n return instantAt(day, minuteAtWorkedBackAnchored(shape, worked + remaining));\n }\n remaining -= available;\n day += 1;\n minute = 0;\n\n // Whole-week skip: between here and the next date override only the weekday\n // rules apply, so a multi-year lag costs a binary search, not a day loop. Always\n // leave at least one week to walk so the landing minute is resolved day by day.\n if (calendar.weekMinutes > 0 && remaining > calendar.weekMinutes) {\n const nextOverride = nextOverrideDay(calendar, day);\n const safeWeeks =\n nextOverride === Number.POSITIVE_INFINITY\n ? Number.POSITIVE_INFINITY\n : Math.floor((nextOverride - day) / 7);\n const workWeeks = Math.ceil(remaining / calendar.weekMinutes) - 1;\n const weeks = Math.min(safeWeeks, workWeeks);\n if (weeks > 0 && Number.isFinite(weeks)) {\n day += weeks * 7;\n remaining -= weeks * calendar.weekMinutes;\n }\n }\n }\n return instantAt(day, minute);\n}\n\nfunction walkBackward(calendar: ResolvedCalendar, anchor: Date, minutes: number): Date {\n let day = civilDayIndex(anchor);\n let minute = minuteOfDay(anchor);\n let remaining = minutes;\n\n for (let guard = 0; guard < MAX_WALK_DAYS; guard++) {\n const shape = shapeFor(calendar, day);\n const worked = workedBefore(shape, minute);\n if (remaining <= worked) {\n return instantAt(day, minuteAtWorkedFwdAnchored(shape, worked - remaining));\n }\n remaining -= worked;\n day -= 1;\n minute = MINUTES_PER_DAY;\n\n if (calendar.weekMinutes > 0 && remaining > calendar.weekMinutes) {\n const previousOverride = prevOverrideDay(calendar, day);\n const safeWeeks =\n previousOverride === Number.NEGATIVE_INFINITY\n ? Number.POSITIVE_INFINITY\n : Math.floor((day - previousOverride) / 7);\n const workWeeks = Math.ceil(remaining / calendar.weekMinutes) - 1;\n const weeks = Math.min(safeWeeks, workWeeks);\n if (weeks > 0 && Number.isFinite(weeks)) {\n day -= weeks * 7;\n remaining -= weeks * calendar.weekMinutes;\n }\n }\n }\n return instantAt(day, minute);\n}\n\n/**\n * Advance `from` by `ms` of **working** time; a negative `ms` walks backward.\n *\n * `anchorDir` controls only the initial projection of `from` onto working time and\n * defaults to the direction of the walk. A caller computing a *finish* with\n * `ms === 0` must pass `-1` explicitly — that is exactly the `lag: 0` case in the\n * FF and SF branches of the cascade, where deriving the direction from the sign of\n * a zero would silently project the wrong way.\n *\n * Composition: `addWorkingMs(addWorkingMs(t, a), -a) === t` **iff** `t` is anchored\n * in the direction of `sign(a)` — see ADR-007. Project once at the boundary of an\n * operation, then compose freely inside it.\n */\nexport function addWorkingMs(\n calendar: ResolvedCalendar | null,\n from: Date,\n ms: number,\n anchorDir?: WalkDirection,\n): Date {\n if (!calendar) {\n return new Date(from.getTime() + ms);\n }\n const dir: WalkDirection = anchorDir ?? (ms < 0 ? -1 : 1);\n const anchor = closestWorkingTime(calendar, from, dir);\n if (ms === 0) {\n return anchor;\n }\n if (calendar.weekMinutes === 0 && calendar.byDate.size === 0) {\n return anchor;\n }\n return ms > 0\n ? walkForward(calendar, anchor, ms / MS_PER_MINUTE)\n : walkBackward(calendar, anchor, -ms / MS_PER_MINUTE);\n}\n\n/**\n * Working time in `[from, to)`, in milliseconds. Negative when `to < from`.\n *\n * Unlike {@link addWorkingMs} this is a plain integral, so it is unconditionally\n * additive: `count(a, b) + count(b, c) === count(a, c)` for any instants. That is\n * why span measurement always goes through it.\n */\nexport function countWorkingMs(calendar: ResolvedCalendar | null, from: Date, to: Date): number {\n if (!calendar) {\n return to.getTime() - from.getTime();\n }\n if (to.getTime() < from.getTime()) {\n return -countWorkingMs(calendar, to, from);\n }\n const endDay = civilDayIndex(to);\n let day = civilDayIndex(from);\n let minute = minuteOfDay(from);\n let minutes = 0;\n\n while (day < endDay) {\n if (minute === 0 && calendar.weekMinutes > 0) {\n const nextOverride = nextOverrideDay(calendar, day);\n const limit = Math.min(endDay, nextOverride);\n const weeks = Math.floor((limit - day) / 7);\n if (weeks > 0) {\n minutes += weeks * calendar.weekMinutes;\n day += weeks * 7;\n continue;\n }\n }\n const shape = shapeFor(calendar, day);\n minutes += shape.totalMinutes - workedBefore(shape, minute);\n day += 1;\n minute = 0;\n }\n\n const shape = shapeFor(calendar, day);\n minutes += workedBefore(shape, minuteOfDay(to)) - workedBefore(shape, minute);\n return minutes * MS_PER_MINUTE;\n}\n\n/** True when `[from, to)` contains no working time at all — the shading predicate. */\nexport function isNonWorkingSpan(calendar: ResolvedCalendar | null, from: Date, to: Date): boolean {\n if (!calendar) {\n return false;\n }\n return countWorkingMs(calendar, from, to) === 0;\n}\n\n/** Why a column is shaded. Weekend vs holiday matters only for styling. */\nexport type NonWorkingReason = \"weekend\" | \"holiday\" | \"offHours\";\n\nexport interface NonWorkingInfo {\n isNonWorking: boolean;\n reason?: NonWorkingReason;\n}\n\nconst WORKING: NonWorkingInfo = { isNonWorking: false };\n\n/**\n * Whether a timeline column covering `[colStart, colEnd)` is non-working, and why.\n *\n * With no calendar this falls back to the hardcoded Sat/Sun rule so the default\n * look is unchanged. A **partial** day (a short Friday) counts as working and is\n * not shaded at day scale — partial shading at 40px per column would be noise —\n * but at hour scale the off-hours columns inside it shade individually.\n */\nexport function nonWorkingInfo(\n calendar: ResolvedCalendar | null,\n colStart: Date,\n colEnd: Date,\n): NonWorkingInfo {\n if (!calendar) {\n const day = colStart.getDay();\n if (day === 0 || day === 6) {\n return { isNonWorking: true, reason: \"weekend\" };\n }\n return WORKING;\n }\n if (countWorkingMs(calendar, colStart, colEnd) > 0) {\n return WORKING;\n }\n const dayIndex = civilDayIndex(colStart);\n if (calendar.byDate.has(dayIndex)) {\n return { isNonWorking: true, reason: \"holiday\" };\n }\n // A whole day with no working time at all is a weekend rule; a shorter slice\n // inside an otherwise-working day is just off-hours.\n const shape = shapeFor(calendar, dayIndex);\n if (shape.totalMinutes === 0) {\n return { isNonWorking: true, reason: \"weekend\" };\n }\n return { isNonWorking: true, reason: \"offHours\" };\n}\n\n/**\n * Working milliseconds one `unit` represents. A `\"day\"` is the week's longest\n * working day (ADR-018), so a weekends-off calendar over full days keeps\n * `duration: 3` meaning three whole days.\n */\nexport function workingMsPerUnit(calendar: ResolvedCalendar | null, unit: DurationUnit): number {\n if (unit === \"minute\") {\n return MS_PER_MINUTE;\n }\n if (unit === \"hour\") {\n return MS_PER_HOUR;\n }\n if (!calendar || calendar.msPerWorkingDay === 0) {\n return MS_PER_DAY;\n }\n return calendar.msPerWorkingDay;\n}\n\n/** {@link addWorkingMs} in whole `durationUnit`s. */\nexport function addWorkingUnits(\n calendar: ResolvedCalendar | null,\n from: Date,\n amount: number,\n unit: DurationUnit,\n anchorDir?: WalkDirection,\n): Date {\n return addWorkingMs(calendar, from, amount * workingMsPerUnit(calendar, unit), anchorDir);\n}\n","import type { DurationUnit, GanttTask } from \"../types\";\nimport type { ResolvedCalendar } from \"./calendar\";\nimport { startOfUnit } from \"./dateUtils\";\nimport { addWorkingUnits, countWorkingMs, workingMsPerUnit } from \"./workingTime\";\n\n/**\n * Everything outside a task that its dates depend on. Threaded explicitly through\n * `core/*` rather than read from context, so every function here stays a pure\n * unit-testable function with no React and no module state.\n */\nexport interface SchedulingContext {\n /** `null` means no calendar prop: plain linear time, exactly as before this feature. */\n calendar: ResolvedCalendar | null;\n durationUnit: DurationUnit;\n /** Whether library-authored dates snap onto working time (ADR-012). */\n snapToWorking: boolean;\n}\n\n/** The context a chart has with no `calendar` prop — linear time (ADR-002). */\nexport const LINEAR_CONTEXT: SchedulingContext = {\n calendar: null,\n durationUnit: \"day\",\n snapToWorking: true,\n};\n\n/**\n * The instant a task stops — **exclusive** (ADR-014). A Monday-to-Friday all-day\n * task ends at Saturday 00:00; a 9-to-5 Friday task ends at Friday 17:00.\n *\n * Precedence, preserving what `getEndDate` used to do: an explicit `endDate` wins,\n * else `duration` is walked out in working time on the chart's `durationUnit`,\n * else the task is an instant.\n *\n * A milestone or a zero duration is always an instant (ADR-009): a moment in time,\n * exempt from any duration basis.\n */\nexport function endInstantOf(task: GanttTask, ctx: SchedulingContext): Date {\n if (task.type === \"milestone\" || task.duration === 0) {\n return task.startDate;\n }\n if (task.endDate) {\n return task.endDate;\n }\n if (task.duration === undefined) {\n return task.startDate;\n }\n return addWorkingUnits(ctx.calendar, task.startDate, task.duration, ctx.durationUnit, 1);\n}\n\n/**\n * The inclusive last-occupied civil day, for **display only**.\n *\n * Stored dates are exclusive instants, which reads wrong in a column: a task\n * running Monday through Friday stores Saturday. This converts back for humans —\n * the day containing the last worked moment. Never write the result back to a task.\n */\nexport function displayEndDate(startDate: Date, endInstant: Date): Date {\n if (endInstant.getTime() <= startDate.getTime()) {\n return startOfUnit(startDate, \"day\");\n }\n return startOfUnit(new Date(endInstant.getTime() - 1), \"day\");\n}\n\n/**\n * Inverse of {@link displayEndDate} for a whole-day edit: the exclusive instant\n * starting the day after `displayEnd`.\n *\n * This is what a `<input type=\"date\">` end-date editor needs — the user picks the\n * last day they mean, and the task stores the following midnight.\n */\nexport function endInstantFromDisplayDate(displayEnd: Date): Date {\n return new Date(displayEnd.getFullYear(), displayEnd.getMonth(), displayEnd.getDate() + 1);\n}\n\n/**\n * The task's user-facing end date, or `undefined` when it is an instant.\n *\n * Backs `ColumnApi.format.endDate`. Lives here rather than inside the provider so\n * it is a plain function over a {@link SchedulingContext} — testable without\n * mounting a chart, and reusable by any consumer with the same problem.\n */\nexport function displayEndOf(task: GanttTask, ctx: SchedulingContext): Date | undefined {\n const end = endInstantOf(task, ctx);\n if (end.getTime() <= task.startDate.getTime()) {\n return undefined;\n }\n return displayEndDate(task.startDate, end);\n}\n\n/**\n * Working time the task occupies, expressed in the chart's `durationUnit`.\n *\n * Backs `ColumnApi.format.duration`. Measured through `countWorkingMs` so it is\n * additive and calendar-aware, then divided by what one unit is worth under that\n * calendar (ADR-018).\n */\nexport function workingDurationOf(task: GanttTask, ctx: SchedulingContext): number {\n const worked = countWorkingMs(ctx.calendar, task.startDate, endInstantOf(task, ctx));\n return worked / workingMsPerUnit(ctx.calendar, ctx.durationUnit);\n}\n","import type { CalendarUnit, GanttLabels, GanttTask, ResolvedGanttLabels } from \"../types\";\n\nexport const DEFAULT_LABELS: ResolvedGanttLabels = {\n gantt: \"Gantt chart\",\n taskList: \"Task list\",\n timeline: \"Timeline\",\n expand: \"Expand\",\n collapse: \"Collapse\",\n resizeTaskList: \"Resize task list\",\n deleteDependency: \"Delete dependency\",\n editTask: (task) => `Edit ${task.name}`,\n addTaskAfter: (task) => `Add task after ${task.name}`,\n deleteTask: (task) => `Delete ${task.name}`,\n bar: (task, { progress }) => formatBarLabel(task, progress),\n};\n\nexport function resolveLabels(labels: GanttLabels | undefined): ResolvedGanttLabels {\n if (!labels) {\n return DEFAULT_LABELS;\n }\n return { ...DEFAULT_LABELS, ...labels };\n}\n\nfunction formatDate(date: Date): string {\n return date.toLocaleDateString(undefined, { dateStyle: \"medium\" });\n}\n\nconst TYPE_NAMES: Record<NonNullable<GanttTask[\"type\"]>, string> = {\n task: \"task\",\n milestone: \"milestone\",\n summary: \"summary\",\n};\n\nexport function formatBarLabel(task: GanttTask, progress: number): string {\n const type = TYPE_NAMES[task.type ?? \"task\"];\n const parts = [task.name, type];\n if (task.endDate && task.endDate.getTime() !== task.startDate.getTime()) {\n parts.push(`${formatDate(task.startDate)} to ${formatDate(task.endDate)}`);\n } else {\n parts.push(formatDate(task.startDate));\n }\n // Milestones are a point in time — a completion percentage is meaningless.\n if (task.type !== \"milestone\") {\n parts.push(`${Math.round(progress)}% complete`);\n }\n return parts.join(\", \");\n}\n\nexport function formatPeriodLabel(date: Date, unit: CalendarUnit, step: number): string {\n switch (unit) {\n case \"minute\":\n case \"hour\":\n return date.toLocaleString(undefined, { dateStyle: \"long\", timeStyle: \"short\" });\n case \"day\":\n return date.toLocaleDateString(undefined, { dateStyle: \"long\" });\n case \"week\":\n return `Week of ${date.toLocaleDateString(undefined, { dateStyle: \"long\" })}`;\n case \"month\":\n return date.toLocaleDateString(undefined, { month: \"long\", year: \"numeric\" });\n case \"quarter\": {\n const quarter = Math.floor(date.getMonth() / 3) + 1;\n return `Q${quarter} ${date.getFullYear()}`;\n }\n case \"year\":\n return step > 1\n ? `${date.getFullYear()} to ${date.getFullYear() + step - 1}`\n : String(date.getFullYear());\n }\n}\n","import type { ChangeLog, GanttTask, Id, TaskCommand } from \"../types\";\nimport { LRUCache } from \"./lruCache\";\nimport { endInstantOf, LINEAR_CONTEXT, type SchedulingContext } from \"./taskDates\";\n\ntype TaskRecordsByParentId = Map<Id | null, GanttTask[]>;\n\n/**\n * The resolved task state is a single insertion-ordered Map: the Map IS the\n * display order. `set` on an existing key keeps its position (updates),\n * `delete` is O(1) and order-preserving, so only positional creates need a\n * one-pass rebuild — no parallel `order` array with indexOf/splice.\n */\nexport type ResolvedTaskMap = Map<Id, GanttTask>;\n\n/**\n * Group an already-resolved, ordered task map into the flattened display list\n * (parents rolled up from their children). Takes the resolved map rather than\n * `(tasks, log)` so callers that already hold the resolved state don't pay for\n * a second replay.\n */\nexport function getTaskList(\n resolvedById: ResolvedTaskMap,\n ctx: SchedulingContext = LINEAR_CONTEXT,\n): GanttTask[] {\n const taskByParentId = groupTaskByParentId(resolvedById.values());\n const roots = taskByParentId.get(null) ?? [];\n const flattened: GanttTask[] = [];\n for (const root of roots) {\n appendSubtree(root, taskByParentId, flattened, ctx);\n }\n return flattened;\n}\n\n/** Seed resolved state from the tasks prop: id → task, in display order. */\nexport function seedResolvedTasks(tasks: GanttTask[]): ResolvedTaskMap {\n const byId: ResolvedTaskMap = new Map();\n for (const task of tasks) {\n byId.set(task.id, task);\n }\n return byId;\n}\n\n/**\n * Replay the applied slice of the change log (`transactions[0..cursor]`) over\n * the seed tasks, returning the effective tasks keyed by id in display order.\n * Pure full replay — prefer `resolveCommittedTasksCached` in render paths.\n */\nexport function resolveCommittedTasks(tasks: GanttTask[], log: ChangeLog): ResolvedTaskMap {\n let resolved = seedResolvedTasks(tasks);\n for (let k = 0; k < log.cursor; k++) {\n resolved = applyCommands(resolved, log.transactions[k]!);\n }\n return resolved;\n}\n\n/**\n * Apply one transaction immutably: returns a new map, structurally sharing\n * every untouched task. O(n) for the clone plus O(1) per update/delete.\n */\nexport function applyTransaction(\n resolved: ResolvedTaskMap,\n commands: TaskCommand[],\n): ResolvedTaskMap {\n return applyCommands(new Map(resolved), commands);\n}\n\n/**\n * Apply commands to a map the caller owns. Mutates `map` where possible and\n * returns the map to use afterwards (positional creates rebuild).\n */\nfunction applyCommands(map: ResolvedTaskMap, commands: TaskCommand[]): ResolvedTaskMap {\n for (const cmd of commands) {\n switch (cmd.type) {\n case \"update\":\n // set() on an existing key keeps its insertion position.\n if (map.has(cmd.task.id)) {\n map.set(cmd.task.id, cmd.task);\n }\n break;\n case \"delete\":\n map.delete(cmd.id);\n break;\n case \"create\":\n map = insertTask(map, cmd.task, cmd.afterId);\n break;\n }\n }\n return map;\n}\n\n/**\n * Insert `task` after `afterId`. Matches the historical replay semantics:\n * `afterId == null` appends; a given-but-missing `afterId` prepends.\n */\nfunction insertTask(\n map: ResolvedTaskMap,\n task: GanttTask,\n afterId: Id | null | undefined,\n): ResolvedTaskMap {\n if (afterId == null) {\n map.set(task.id, task);\n return map;\n }\n const next: ResolvedTaskMap = new Map();\n if (!map.has(afterId)) {\n next.set(task.id, task);\n }\n for (const [id, existing] of map) {\n next.set(id, existing);\n if (id === afterId) {\n next.set(task.id, task);\n }\n }\n return next;\n}\n\n// --- Cached incremental resolution -----------------------------------------\n\ninterface ResolveSnapshot {\n /** The transaction whose application produced this snapshot; null = seed. */\n producedBy: TaskCommand[] | null;\n map: ResolvedTaskMap;\n}\n\n/**\n * Snapshots of the resolved state keyed by cursor position. A transaction\n * array element is created exactly once at one log position with one fixed\n * prefix (appends preserve the kept prefix; dropped redo branches never\n * return), so `producedBy === log.transactions[k - 1]` proves the whole\n * prefix matches and the snapshot at `k` is valid.\n */\nexport interface ResolveCache {\n seedTasks: GanttTask[] | null;\n snapshots: LRUCache<number, ResolveSnapshot>;\n}\n\nconst RESOLVE_SNAPSHOT_CAPACITY = 32;\n\nexport function createResolveCache(): ResolveCache {\n return { seedTasks: null, snapshots: new LRUCache(RESOLVE_SNAPSHOT_CAPACITY) };\n}\n\n/**\n * Like `resolveCommittedTasks`, but incremental: reuses the deepest valid\n * snapshot at or below the cursor and only applies the transactions past it.\n * A new edit costs one O(n) clone instead of a full log replay; undo/redo to\n * a recently seen cursor returns the cached map with no work at all.\n */\nexport function resolveCommittedTasksCached(\n cache: ResolveCache,\n tasks: GanttTask[],\n log: ChangeLog,\n): ResolvedTaskMap {\n if (cache.seedTasks !== tasks) {\n cache.seedTasks = tasks;\n cache.snapshots = new LRUCache(RESOLVE_SNAPSHOT_CAPACITY);\n }\n\n let base = 0;\n let resolved: ResolvedTaskMap | null = null;\n for (let k = log.cursor; k >= 1; k--) {\n const snapshot = cache.snapshots.get(k);\n if (snapshot && snapshot.producedBy === log.transactions[k - 1]) {\n base = k;\n resolved = snapshot.map;\n break;\n }\n }\n if (!resolved) {\n const seed = cache.snapshots.get(0);\n resolved = seed ? seed.map : seedResolvedTasks(tasks);\n if (!seed) {\n cache.snapshots.put(0, { producedBy: null, map: resolved });\n }\n }\n\n for (let k = base; k < log.cursor; k++) {\n const transaction = log.transactions[k]!;\n resolved = applyTransaction(resolved, transaction);\n cache.snapshots.put(k + 1, { producedBy: transaction, map: resolved });\n }\n return resolved;\n}\n\n// --- Tree flattening --------------------------------------------------------\n\n/**\n * Emit `task`'s subtree depth-first into `out` and return the task's\n * effective (rolled-up) version. The parent is emitted as a placeholder\n * before its children, then patched in place once their roll-up is known —\n * one shared output array, no per-level flatMap/concat copying.\n */\nfunction appendSubtree(\n task: GanttTask,\n taskByParentId: TaskRecordsByParentId,\n out: GanttTask[],\n ctx: SchedulingContext,\n): GanttTask {\n const children = taskByParentId.get(task.id);\n if (!children || children.length === 0) {\n const leaf = materializeEnd(task, ctx);\n out.push(leaf);\n return leaf;\n }\n\n const slot = out.length;\n out.push(task);\n const effectiveChildren: GanttTask[] = [];\n for (const child of children) {\n effectiveChildren.push(appendSubtree(child, taskByParentId, out, ctx));\n }\n const effective = getParentTaskData(task, effectiveChildren, ctx);\n out[slot] = effective;\n return effective;\n}\n\n/**\n * Give every task in the display list a concrete exclusive `endDate` (ADR-019).\n *\n * This is where the calendar is applied, once. Downstream — `computeTaskPixels`,\n * the dependency-link geometry, `getMinMaxDates`, zoom, `buildDatesFromTasks` —\n * reads plain dates and needs no calendar awareness at all.\n *\n * Identity is preserved when nothing changes, so an already-dated task is not\n * re-allocated on every render.\n */\nfunction materializeEnd(task: GanttTask, ctx: SchedulingContext): GanttTask {\n const end = endInstantOf(task, ctx);\n if (task.endDate && task.endDate.getTime() === end.getTime()) {\n return task;\n }\n if (!task.endDate && end === task.startDate) {\n return task;\n }\n return { ...task, endDate: end };\n}\n\nexport function getParentTaskData(\n task: GanttTask,\n children: GanttTask[],\n ctx: SchedulingContext = LINEAR_CONTEXT,\n): GanttTask {\n // Only summary tasks roll their children's dates/progress up. A parent typed\n // \"task\" or \"milestone\" (or untyped) keeps its own data and renders as a\n // regular bar, even when it has children.\n if (task.type !== \"summary\" || children.length === 0) {\n return materializeEnd(task, ctx);\n }\n\n let startDate = children[0]!.startDate;\n let endDate = endInstantOf(children[0]!, ctx);\n let progressSum = 0;\n let notMilestoneCount = 0;\n\n for (const child of children) {\n if (child.startDate < startDate) {\n startDate = child.startDate;\n }\n\n // Resolve every child, not just those carrying an explicit endDate: a\n // `{ startDate, duration }` child used to contribute only its start, so the\n // parent silently under-reported its own span.\n const childEnd = endInstantOf(child, ctx);\n if (childEnd > endDate) {\n endDate = childEnd;\n }\n\n // Milestones are moments, not work: they contribute neither progress nor\n // weight to the roll-up. A non-milestone child without progress still\n // counts as 0% so unstarted work drags the average down.\n if (child.type !== \"milestone\") {\n notMilestoneCount++;\n progressSum += child.progress ?? 0;\n }\n }\n\n const progress = notMilestoneCount === 0 ? 0 : Math.round(progressSum / notMilestoneCount);\n\n return {\n ...task,\n startDate,\n endDate,\n progress,\n };\n}\n\nfunction groupTaskByParentId(tasks: Iterable<GanttTask>): TaskRecordsByParentId {\n const acc: TaskRecordsByParentId = new Map();\n for (const task of tasks) {\n const parentId = task.parentId ?? null;\n const siblings = acc.get(parentId) ?? [];\n siblings.push(task);\n acc.set(parentId, siblings);\n }\n return acc;\n}\n","/**\n * FIFO queue backed by a single array with a moving read cursor.\n *\n * Plain `Array.shift()` is O(n) — it re-indexes every remaining element on each\n * dequeue, so draining n items costs O(n²). Here `dequeue` just advances a head\n * pointer (O(1)); the consumed prefix is compacted lazily once it dominates the\n * array, keeping memory bounded without paying the re-index cost per item.\n */\nexport class Queue<T> {\n private items: T[] = [];\n private head = 0;\n\n constructor(initial?: Iterable<T>) {\n if (initial) {\n this.items.push(...initial);\n }\n }\n\n get size(): number {\n return this.items.length - this.head;\n }\n\n isEmpty(): boolean {\n return this.size === 0;\n }\n\n enqueue(item: T): void {\n this.items.push(item);\n }\n\n dequeue(): T | undefined {\n if (this.head >= this.items.length) {\n return undefined;\n }\n const item = this.items[this.head];\n this.head++;\n\n // Reclaim the consumed prefix once it grows past half the array.\n // this.head > this.items.length / 2 is equivalent but may involve a slower division, so we use a bit shift.\n if (this.head > this.items.length >> 1) {\n this.items = this.items.slice(this.head);\n this.head = 0;\n }\n\n return item;\n }\n}\n","import type { GanttTask, Id, TaskDependency, TaskDependencyType } from \"../types\";\nimport type { BarCommit } from \"./barUtils\";\nimport { Queue } from \"./queue\";\nimport { endInstantOf, LINEAR_CONTEXT, type SchedulingContext } from \"./taskDates\";\nimport {\n addWorkingMs,\n closestWorkingTime,\n countWorkingMs,\n nearestWorkingTime,\n workingMsPerUnit,\n} from \"./workingTime\";\n\ninterface Span {\n start: Date;\n /** The instant work stops — EXCLUSIVE (ADR-014). Equals `start` for milestones. */\n end: Date;\n}\n\nfunction spanOf(task: GanttTask, ctx: SchedulingContext): Span {\n return {\n start: task.startDate,\n end: endInstantOf(task, ctx),\n };\n}\n\n/** Working time a task occupies, in milliseconds. */\nfunction workingLengthOf(task: GanttTask, ctx: SchedulingContext): number {\n const { start, end } = spanOf(task, ctx);\n return countWorkingMs(ctx.calendar, start, end);\n}\n\n/**\n * Earliest start a successor may take given a single predecessor and the\n * relationship type, using ASAP forward-scheduling rules.\n *\n * `endDate` is an exclusive instant, so a finish-to-start link starts the\n * successor exactly where the predecessor stopped — the `+1`/`-1` day fudges the\n * old inclusive model needed are gone, not ported.\n *\n * FF and SF are **decomposed** into two separately anchored walks rather than\n * folding `lag - successorLength` into one offset (ADR-007). Folding is wrong\n * twice under working time: the two terms are measured from different anchors,\n * and they travel in opposite directions when their signs differ, so working-time\n * addition — which is not linear — cannot combine them.\n *\n * The explicit anchor direction matters most at `lag === 0`, the commonest value:\n * FS/SS compute a *start* and must project forward, while FF/SF compute a\n * *finish* and must project backward. Deriving the direction from the sign of a\n * zero would silently pick the wrong one.\n */\nfunction constrainedStart(\n pred: Span,\n type: TaskDependencyType,\n lagMs: number,\n successorLength: number,\n ctx: SchedulingContext,\n): Date {\n const cal = ctx.calendar;\n switch (type) {\n case \"FS\": // successor starts where the predecessor finished\n return addWorkingMs(cal, pred.end, lagMs, 1);\n case \"SS\": // successor starts together with the predecessor\n return addWorkingMs(cal, pred.start, lagMs, 1);\n case \"FF\": {\n // successor finishes together with the predecessor\n const finish = addWorkingMs(cal, pred.end, lagMs, -1);\n return addWorkingMs(cal, finish, -successorLength, -1);\n }\n case \"SF\": {\n // successor finishes when the predecessor starts\n const finish = addWorkingMs(cal, pred.start, lagMs, -1);\n return addWorkingMs(cal, finish, -successorLength, -1);\n }\n }\n}\n\n/**\n * Adjacency index over the dependency list, built once and reused across\n * commits (memoize on the dependency array). Both lookups are by task id so the\n * forward walk stays O(1) per edge.\n */\nexport interface DependencyGraph {\n /** predecessor id → ids of its direct successors (traversal order) */\n successorsOf: Map<Id, Id[]>;\n /** successor id → the dependencies that constrain it (constraint inputs) */\n predecessorDeps: Map<Id, TaskDependency[]>;\n /** number of dependency edges (used to bound the relaxation loop) */\n size: number;\n}\n\nexport function buildDependencyGraph(dependencies: TaskDependency[]): DependencyGraph {\n const successorsOf = new Map<Id, Id[]>();\n const predecessorDeps = new Map<Id, TaskDependency[]>();\n for (const dep of dependencies) {\n const successorList = successorsOf.get(dep.from);\n if (successorList) {\n successorList.push(dep.to);\n } else {\n successorsOf.set(dep.from, [dep.to]);\n }\n\n const deps = predecessorDeps.get(dep.to);\n if (deps) {\n deps.push(dep);\n } else {\n predecessorDeps.set(dep.to, [dep]);\n }\n }\n return { successorsOf, predecessorDeps, size: dependencies.length };\n}\n\n/**\n * The mutable working set a cascade walks: reads of the effective task state,\n * writes of the tasks it moves. A plain `Map` satisfies it; so does the\n * copy-on-write view from {@link overlayOf}, which is what keeps a cascade from\n * cloning the whole resolved map on every edit.\n */\nexport interface TaskWorkingSet {\n get(id: Id): GanttTask | undefined;\n set(id: Id, task: GanttTask): void;\n readonly size: number;\n}\n\n/**\n * Copy-on-write view over the resolved task map: reads fall through to `base`,\n * writes land in a small overlay, so `base` is never touched and no O(n) clone\n * is paid (~17ms at 100k tasks, on every single edit).\n */\nexport function overlayOf(base: ReadonlyMap<Id, GanttTask>): TaskWorkingSet {\n const patch = new Map<Id, GanttTask>();\n return {\n get: (id) => patch.get(id) ?? base.get(id),\n set: (id, task) => {\n patch.set(id, task);\n },\n // A cascade only ever replaces existing tasks, so the base size still bounds\n // the relaxation loop.\n get size() {\n return base.size;\n },\n };\n}\n\n/**\n * Earliest start `task` may take so that *every* incoming dependency is\n * satisfied — the latest constraint across all predecessors, or `null` when the\n * task has none.\n */\nfunction earliestStart(\n task: GanttTask,\n predecessorDeps: Map<Id, TaskDependency[]>,\n current: TaskWorkingSet,\n ctx: SchedulingContext,\n): Date | null {\n const length = workingLengthOf(task, ctx);\n const msPerUnit = workingMsPerUnit(ctx.calendar, ctx.durationUnit);\n let earliest: Date | null = null;\n for (const dep of predecessorDeps.get(task.id) ?? []) {\n const pred = current.get(dep.from);\n if (!pred) {\n continue;\n }\n const candidate = constrainedStart(\n spanOf(pred, ctx),\n dep.type,\n (dep.lag ?? 0) * msPerUnit,\n length,\n ctx,\n );\n if (earliest === null || candidate > earliest) {\n earliest = candidate;\n }\n }\n if (earliest === null) {\n return null;\n }\n // Project once, here, so the value the caller compares against is a fixpoint.\n // `closestWorkingTime` is idempotent, so a task already parked on this instant\n // stops moving; without this the strict comparison below could keep firing and\n // silently exhaust the iteration guard, yielding a wrong-but-stable schedule.\n return closestWorkingTime(ctx.calendar, earliest, 1);\n}\n\n/** A copy of `task` moved to `start`, preserving the working time it occupies. */\nfunction movedTo(task: GanttTask, start: Date, ctx: SchedulingContext): GanttTask {\n // A milestone is an instant: its end mirrors its start, never lags behind it.\n // This is the single milestone rule — `useTaskList` defers to it rather than\n // keeping its own.\n if (task.type === \"milestone\") {\n return { ...task, startDate: start, endDate: start };\n }\n return {\n ...task,\n startDate: start,\n endDate: addWorkingMs(ctx.calendar, start, workingLengthOf(task, ctx), 1),\n };\n}\n\n/**\n * Turn a finished drag into the dates to store — the one place a pixel-derived\n * value meets the calendar.\n *\n * A **move** preserves the task's working time, not its pixel width: drag a\n * three-working-day task onto a Thursday and it still occupies three working days,\n * growing visually across the weekend. A **resize** sets the working time instead,\n * so an edge dropped in non-working time settles back onto the nearest working\n * boundary (ADR-005) — quantization, which happens even with `snapToWorking` off.\n *\n * Starts always project forward and ends backward (ADR-020), which is what keeps\n * every library-authored task forward-anchored at its start and backward-anchored\n * at its end — the precondition that makes span round-trips exact.\n */\nexport function resolveCommit(\n task: GanttTask,\n commit: BarCommit,\n ctx: SchedulingContext,\n): { startDate: Date; endDate: Date } {\n const cal = ctx.calendar;\n const snap = ctx.snapToWorking;\n const span = spanOf(task, ctx);\n\n if (task.type === \"milestone\") {\n const raw = commit.kind === \"resizeEnd\" ? commit.endDate : commit.startDate;\n const at = snap ? nearestWorkingTime(cal, raw) : raw;\n return { startDate: at, endDate: at };\n }\n\n if (commit.kind === \"move\") {\n const length = countWorkingMs(cal, span.start, span.end);\n const start = snap ? closestWorkingTime(cal, commit.startDate, 1) : commit.startDate;\n return { startDate: start, endDate: addWorkingMs(cal, start, length, 1) };\n }\n\n // Resize: project both edges inward and clamp to at least some working time.\n // The untouched edge is unchanged pixel-wise, so projecting it is a no-op on an\n // already-valid task — which is also what fixes the old bug where snapping the\n // start handle could shift the far edge by a whole column.\n const rawStart = commit.kind === \"resizeStart\" ? commit.startDate : span.start;\n const rawEnd = commit.kind === \"resizeEnd\" ? commit.endDate : span.end;\n const start = snap ? closestWorkingTime(cal, rawStart, 1) : rawStart;\n const end = snap ? closestWorkingTime(cal, rawEnd, -1) : rawEnd;\n\n if (countWorkingMs(cal, start, end) <= 0) {\n // Collapsed or inverted — keep one unit of working time anchored on the edge\n // the user was NOT dragging.\n const unitMs = workingMsPerUnit(cal, ctx.durationUnit);\n if (commit.kind === \"resizeStart\") {\n return { startDate: addWorkingMs(cal, end, -unitMs, -1), endDate: end };\n }\n return { startDate: start, endDate: addWorkingMs(cal, start, unitMs, 1) };\n }\n return { startDate: start, endDate: end };\n}\n\n/**\n * Re-schedule the dependents of a changed task.\n *\n * First clamps the changed task itself forward if the user moved it so that it\n * violates one of its own predecessors — e.g. dragging a start-to-start\n * successor before its predecessor snaps its start back onto the predecessor's\n * (a valid earlier/later move is left untouched).\n *\n * Then walks the dependency graph forward from `changedId`. Dependencies act as\n * a lower bound: a successor is pushed later only when a move would violate it\n * (taking the latest constraint when several predecessors apply), and is never\n * pulled earlier when a predecessor moves back. Its duration is preserved and\n * its own successors are then revisited. Returns only the tasks whose dates\n * moved.\n *\n * `current` is the working set of effective tasks and is written to in place as\n * the schedule settles — pass {@link overlayOf} to leave the caller's resolved\n * map untouched. A per-call iteration cap keeps dependency cycles from looping\n * forever.\n */\nexport function scheduleDependents(\n current: TaskWorkingSet,\n graph: DependencyGraph,\n changedId: Id,\n ctx: SchedulingContext = LINEAR_CONTEXT,\n): Map<Id, GanttTask> {\n const { successorsOf, predecessorDeps } = graph;\n\n const changed = new Map<Id, GanttTask>();\n\n // Clamp the dragged task forward to satisfy its own predecessors before\n // cascading. Only a violating (too-early) move is corrected; the constraint\n // is a lower bound, so a valid drag is preserved.\n const changedTask = current.get(changedId);\n if (changedTask) {\n const earliest = earliestStart(changedTask, predecessorDeps, current, ctx);\n if (earliest !== null && earliest.getTime() > changedTask.startDate.getTime()) {\n const clamped = movedTo(changedTask, earliest, ctx);\n current.set(changedId, clamped);\n changed.set(changedId, clamped);\n }\n }\n\n const queue = new Queue<Id>([changedId]);\n const maxIterations = (graph.size + 1) * (current.size + 1);\n let iterations = 0;\n\n while (!queue.isEmpty()) {\n if (iterations++ > maxIterations) {\n break;\n } // guard against dependency cycles\n const predId = queue.dequeue()!;\n\n for (const successorId of successorsOf.get(predId) ?? []) {\n const successor = current.get(successorId);\n if (!successor) {\n continue;\n }\n\n const earliest = earliestStart(successor, predecessorDeps, current, ctx);\n if (earliest === null) {\n continue;\n }\n // Lower bound only: push a violating (too-early) successor forward, but\n // never pull it earlier when a predecessor moves back. Compared as instants\n // rather than whole days, so a sub-day violation cascades too.\n if (earliest.getTime() <= successor.startDate.getTime()) {\n continue;\n }\n\n const next = movedTo(successor, earliest, ctx);\n current.set(successorId, next);\n changed.set(successorId, next);\n queue.enqueue(successorId);\n }\n }\n\n return changed;\n}\n","import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type { ChangeLog, GanttTask, Id, TaskCommand, TaskDependency, TaskPatch } from \"../types\";\nimport {\n createResolveCache,\n getTaskList,\n resolveCommittedTasksCached,\n type ResolveCache,\n} from \"../core/prepareData\";\nimport {\n buildDependencyGraph,\n overlayOf,\n resolveCommit,\n scheduleDependents,\n} from \"../core/scheduling\";\nimport type { BarCommit } from \"../core/barUtils\";\nimport { LINEAR_CONTEXT, type SchedulingContext } from \"../core/taskDates\";\n\nconst EMPTY_LOG: ChangeLog = { transactions: [], cursor: 0 };\n\n// Module-level so an omitted `dependencies` prop keeps a stable identity and\n// the dependency graph isn't rebuilt on every render.\nexport const EMPTY_DEPENDENCIES: TaskDependency[] = [];\n\n/**\n * Every log mutation except `createTask` is scheduled at transition priority.\n *\n * The state update itself is trivial; the render it schedules is the expensive\n * half of an edit — rebuilding the display list and re-deriving every link's\n * geometry, ~230ms at 100k tasks. At transition priority React keeps the current\n * UI on screen while it prepares the next one, and real user input outranks that\n * work: a burst of edits restarts the pending render instead of committing every\n * intermediate one.\n *\n * This does not make an edit cheaper — the recompute is the same length either\n * way. It only stops that recompute from being the highest-priority thing on the\n * main thread.\n *\n * `createTask` stays synchronous (`flushSync`): its contract is that the new\n * task is already resolved when `onTaskCreate` fires.\n *\n * IMPORTANT for callers that pair a mutation with clearing a drag preview: both\n * updates must be made inside ONE `startTransition` so they land in the same\n * commit. Clearing the preview urgently while the dates arrive later paints one\n * frame of the bar back at its old position — see `Row`'s commit handlers.\n */\nfunction scheduleLogUpdate(update: () => void): void {\n startTransition(update);\n}\n\n/** Drop any redo branch, append `commands` as one transaction, advance the cursor. */\nfunction appendTransaction(log: ChangeLog, commands: TaskCommand[]): ChangeLog {\n const kept = log.transactions.slice(0, log.cursor);\n return { transactions: [...kept, commands], cursor: kept.length + 1 };\n}\n\n/** Field-agnostic value equality; `Date`s compare by instant, not reference. */\nfunction valuesEqual(a: unknown, b: unknown): boolean {\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n return Object.is(a, b);\n}\n\n/** True when two tasks are equal across every field (Date-aware). */\nfunction sameTask(a: GanttTask, b: GanttTask): boolean {\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n for (const key of keys) {\n if (!valuesEqual(a[key as keyof GanttTask], b[key as keyof GanttTask])) {\n return false;\n }\n }\n return true;\n}\n\nexport interface UseTaskListOptions {\n onTaskCreate?: (task: GanttTask, afterId?: Id | null) => void;\n onTaskDelete?: (id: Id) => void;\n onTasksChange?: (tasks: GanttTask[]) => void;\n}\n\nexport const useTaskList = (\n tasks: GanttTask[],\n dependencies: TaskDependency[] = EMPTY_DEPENDENCIES,\n options: UseTaskListOptions = {},\n ctx: SchedulingContext = LINEAR_CONTEXT,\n) => {\n // Latest-ref so the returned mutators stay identity-stable even when the\n // caller passes inline callbacks; handlers read the current options at call\n // time. Updated during render, same pattern as `resolvedRef` below.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // Same treatment for the scheduling context: event handlers need it fresh, but\n // must not gain a new identity when it changes, because `columnApi` and the\n // task-actions context memo on them. Memos below take it as a real dependency\n // instead — they need invalidation, not freshness.\n const ctxRef = useRef(ctx);\n ctxRef.current = ctx;\n const [log, setLog] = useState<ChangeLog>(EMPTY_LOG);\n\n // Built once per dependency list and reused across every commit.\n const dependencyGraph = useMemo(() => buildDependencyGraph(dependencies), [dependencies]);\n\n // Resolve the log incrementally: the cache reuses the snapshot at the\n // previous cursor, so an edit costs one map clone instead of replaying the\n // whole log, and undo/redo to a recent cursor reuses the cached map as-is.\n // Both the display list and the edit base derive from this single resolved\n // map — no second replay.\n const resolveCacheRef = useRef<ResolveCache | null>(null);\n const resolvedById = useMemo(() => {\n resolveCacheRef.current ??= createResolveCache();\n return resolveCommittedTasksCached(resolveCacheRef.current, tasks, log);\n }, [tasks, log]);\n\n // Mirror the latest resolved map so event handlers (updateTask) can read the\n // current effective state without replaying. Updated every render, so at the\n // time a handler fires it matches the committed `log` (= `prev`).\n const resolvedRef = useRef(resolvedById);\n resolvedRef.current = resolvedById;\n\n // Depends on the calendar: the roll-up resolves duration-only children through\n // it, so a calendar change must recompute or every summary bar goes stale.\n const tasksList = useMemo(() => getTaskList(resolvedById, ctx), [resolvedById, ctx]);\n\n /**\n * Commit a finished drag. Unlike `updateTask` — which writes consumer-supplied\n * dates verbatim — this is the library authoring dates, so it is the only path\n * that snaps onto working time (ADR-012).\n */\n const commitTask = useCallback(\n (id: Id, commit: BarCommit) => {\n const base = resolvedRef.current.get(id);\n if (!base) {\n return;\n }\n const { startDate, endDate } = resolveCommit(base, commit, ctxRef.current);\n const nextTask: GanttTask = { ...base, startDate, endDate };\n\n // A drag that resolves back to where it started records no undo step, which is\n // also what makes a bar dropped in non-working time visibly settle back: the\n // transient override is cleared unconditionally and nothing replaces it.\n if (sameTask(nextTask, base)) {\n return;\n }\n\n const commands: TaskCommand[] = [{ type: \"update\", task: nextTask }];\n if (dependencyGraph.size > 0) {\n // Copy-on-write view, not a clone: the cascade touches a handful of tasks,\n // so cloning the whole resolved map would dominate the edit at scale.\n const current = overlayOf(resolvedRef.current);\n current.set(id, nextTask);\n const rescheduled = scheduleDependents(current, dependencyGraph, id, ctxRef.current);\n for (const task of rescheduled.values()) {\n commands.push({ type: \"update\", task });\n }\n }\n scheduleLogUpdate(() => setLog((prev) => appendTransaction(prev, commands)));\n },\n [dependencyGraph],\n );\n\n const updateTask = useCallback(\n (id: Id, patch: TaskPatch) => {\n // Build on the latest committed task (pre-roll-up) from the resolved map.\n const base = resolvedRef.current.get(id);\n if (!base) {\n return;\n }\n\n const nextTask: GanttTask = { ...base };\n if (patch.name !== undefined) {\n nextTask.name = patch.name;\n }\n if (patch.startDate) {\n nextTask.startDate = patch.startDate;\n }\n if (patch.endDate) {\n nextTask.endDate = patch.endDate;\n }\n if (patch.progress !== undefined) {\n nextTask.progress = patch.progress;\n }\n\n // Nothing actually changed → skip the empty undo step (and any reschedule).\n if (sameTask(nextTask, base)) {\n return;\n }\n\n const commands: TaskCommand[] = [{ type: \"update\", task: nextTask }];\n\n // Automatic forward scheduling: when a task moves, realign its dependents\n // so each dependency relationship stays satisfied, then cascade onward.\n // All reschedules join the same transaction → one undo step.\n const moved = patch.startDate !== undefined || patch.endDate !== undefined;\n if (moved && dependencyGraph.size > 0) {\n // Copy-on-write view so scheduling never touches the shared resolved map,\n // without paying an O(n) clone for a cascade that moves a handful of tasks.\n const current = overlayOf(resolvedRef.current);\n current.set(id, nextTask);\n const rescheduled = scheduleDependents(current, dependencyGraph, id, ctxRef.current);\n for (const task of rescheduled.values()) {\n commands.push({ type: \"update\", task });\n }\n }\n\n scheduleLogUpdate(() => setLog((prev) => appendTransaction(prev, commands)));\n },\n [dependencyGraph],\n );\n\n const createTask = useCallback((task: GanttTask, afterId?: Id | null) => {\n // Commit synchronously so the new task is present in the resolved list (and\n // thus in the consumer's `visibleTasks`) before `onTaskCreate` fires. This\n // lets handlers like scroll-to-new-task read post-create state imperatively\n // without waiting for an effect.\n flushSync(() => {\n setLog((prev) => appendTransaction(prev, [{ type: \"create\", task, afterId }]));\n });\n optionsRef.current.onTaskCreate?.(task, afterId);\n }, []);\n\n const deleteTask = useCallback((id: Id) => {\n scheduleLogUpdate(() => setLog((prev) => appendTransaction(prev, [{ type: \"delete\", id }])));\n optionsRef.current.onTaskDelete?.(id);\n }, []);\n\n const undo = useCallback(() => {\n scheduleLogUpdate(() =>\n setLog((prev) => (prev.cursor > 0 ? { ...prev, cursor: prev.cursor - 1 } : prev)),\n );\n }, []);\n\n const redo = useCallback(() => {\n scheduleLogUpdate(() =>\n setLog((prev) =>\n prev.cursor < prev.transactions.length ? { ...prev, cursor: prev.cursor + 1 } : prev,\n ),\n );\n }, []);\n\n const canUndo = log.cursor > 0;\n const canRedo = log.cursor < log.transactions.length;\n\n const tasksListRef = useRef(tasksList);\n tasksListRef.current = tasksList;\n\n const notifiedLog = useRef(log);\n useEffect(() => {\n if (notifiedLog.current === log) {\n return;\n }\n notifiedLog.current = log;\n optionsRef.current.onTasksChange?.(tasksListRef.current);\n }, [log]);\n\n return {\n tasksList,\n updateTask,\n commitTask,\n createTask,\n deleteTask,\n undo,\n redo,\n canUndo,\n canRedo,\n };\n};\n","import { useRef } from \"react\";\n\n/**\n * Ref that always holds the latest `value`, written during render (not in an\n * effect). The render-phase write is deliberate and load-bearing: same-render\n * reads must see the current value — e.g. `createTask` flushSync-commits,\n * re-renders synchronously, then immediately reads refs updated by that very\n * render. Do not convert to an effect. (Same pattern as `useTaskList`'s\n * optionsRef and `useDrag`'s onDragRef.)\n */\nexport function useLatestRef<T>(value: T): React.RefObject<T> {\n const ref = useRef(value);\n ref.current = value;\n return ref;\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport type { GanttTask, Id } from \"../types\";\nimport { useLatestRef } from \"./useLatestRef\";\n\nexport function useExpand(tasksList: GanttTask[]) {\n const parentIds = useMemo(() => {\n const ids = new Set<Id>();\n for (const t of tasksList) {\n if (t.parentId != null) {\n ids.add(t.parentId);\n }\n }\n return ids;\n }, [tasksList]);\n\n const [collapsedIds, setCollapsedIds] = useState<Set<Id>>(new Set());\n\n const toggleExpand = useCallback((id: Id) => {\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n const tasksListRef = useLatestRef(tasksList);\n\n // Returns the previous set unchanged when nothing was collapsed, so a reveal\n // that has no work to do does not trigger a render.\n //\n // The id → task index is built here rather than memoized per render: nothing\n // reads it during render, so an eager index would tax every edit (~15ms at\n // 100k tasks) to serve a walk that only happens on an explicit reveal — and\n // only when something is actually collapsed.\n const revealAncestors = useCallback(\n (id: Id) => {\n setCollapsedIds((prev) => {\n if (prev.size === 0) {\n return prev;\n }\n const taskById = new Map<Id, GanttTask>();\n for (const t of tasksListRef.current) {\n taskById.set(t.id, t);\n }\n const next = new Set(prev);\n let changed = false;\n let cur = taskById.get(id);\n while (cur && cur.parentId != null) {\n if (next.delete(cur.parentId)) {\n changed = true;\n }\n cur = taskById.get(cur.parentId);\n }\n return changed ? next : prev;\n });\n },\n [tasksListRef],\n );\n\n const expandedIds = useMemo(() => {\n const expanded = new Set<Id>();\n for (const id of parentIds) {\n if (!collapsedIds.has(id)) {\n expanded.add(id);\n }\n }\n return expanded;\n }, [parentIds, collapsedIds]);\n\n const visibleTasks = useMemo(() => {\n if (collapsedIds.size === 0) {\n return tasksList;\n }\n const hiddenAncestors = new Set<Id>();\n const result: GanttTask[] = [];\n for (const task of tasksList) {\n if (\n task.parentId != null &&\n (hiddenAncestors.has(task.parentId) || collapsedIds.has(task.parentId))\n ) {\n hiddenAncestors.add(task.id);\n continue;\n }\n result.push(task);\n }\n return result;\n }, [tasksList, collapsedIds]);\n\n return { visibleTasks, expandedIds, parentIds, toggleExpand, revealAncestors };\n}\n","import { useEffect, useLayoutEffect } from \"react\";\n\n/**\n * `useLayoutEffect` on the client, `useEffect` during SSR. Neither runs on the\n * server, so behavior is identical — this only avoids React 18's dev warning\n * (\"useLayoutEffect does nothing on the server\") for SSR consumers. React 19\n * removed that warning; drop this alias if the peer range ever excludes 18.\n */\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { useLatestRef } from \"./useLatestRef\";\n\n/** Scroll offset + client size of a scroll viewport, read for virtualization. */\nexport interface ViewportMetrics {\n scrollTop: number;\n scrollLeft: number;\n clientWidth: number;\n clientHeight: number;\n}\n\nconst ZERO_METRICS: ViewportMetrics = {\n scrollTop: 0,\n scrollLeft: 0,\n clientWidth: 0,\n clientHeight: 0,\n};\n\nfunction readMetrics(el: HTMLDivElement): ViewportMetrics {\n return {\n scrollTop: el.scrollTop,\n scrollLeft: el.scrollLeft,\n clientWidth: el.clientWidth,\n clientHeight: el.clientHeight,\n };\n}\n\nfunction sameMetrics(a: ViewportMetrics, b: ViewportMetrics, trackHorizontal: boolean): boolean {\n if (a.scrollTop !== b.scrollTop || a.clientHeight !== b.clientHeight) {\n return false;\n }\n if (!trackHorizontal) {\n return true;\n }\n return a.scrollLeft === b.scrollLeft && a.clientWidth === b.clientWidth;\n}\n\ninterface UseViewportMeasureOptions {\n /**\n * Include scrollLeft/clientWidth in change detection. Off for panes that\n * only window rows vertically (TaskList): width churn from column/splitter\n * resizes must not re-render them.\n */\n trackHorizontal?: boolean;\n}\n\n/**\n * Track a scroll container's viewport metrics for virtualization: measured\n * before first paint, kept in sync via ResizeObserver, and re-measured on\n * demand (`scheduleMeasure`, typically from an onScroll handler). Bursts of\n * scroll/resize events coalesce into one state update per frame, with an\n * identity bail-out when metrics are unchanged. `scheduleMeasure` is\n * identity-stable forever.\n */\nexport function useViewportMeasure(\n targetRef: React.RefObject<HTMLDivElement | null>,\n { trackHorizontal = true }: UseViewportMeasureOptions = {},\n): { viewport: ViewportMetrics; scheduleMeasure: () => void } {\n const frameRef = useRef<number | null>(null);\n const trackHorizontalRef = useLatestRef(trackHorizontal);\n\n const [viewport, setViewport] = useState<ViewportMetrics>(ZERO_METRICS);\n\n // Coalesce bursts of scroll/resize events into one state update per frame.\n const scheduleMeasure = useCallback(() => {\n if (frameRef.current !== null) {\n return;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n const el = targetRef.current;\n if (!el) {\n return;\n }\n const next = readMetrics(el);\n setViewport((prev) => (sameMetrics(prev, next, trackHorizontalRef.current) ? prev : next));\n });\n }, [targetRef, trackHorizontalRef]);\n\n // Measure synchronously before first paint to avoid a blank initial frame,\n // and keep client size in sync with container resizes.\n // (Isomorphic: plain useEffect during SSR to avoid React 18's server warning.)\n useIsomorphicLayoutEffect(() => {\n const el = targetRef.current;\n if (!el) {\n return;\n }\n setViewport((prev) => {\n const next = readMetrics(el);\n return sameMetrics(prev, next, trackHorizontalRef.current) ? prev : next;\n });\n }, [targetRef]);\n\n useEffect(() => {\n const el = targetRef.current;\n if (!el || typeof ResizeObserver === \"undefined\") {\n return;\n }\n const observer = new ResizeObserver(scheduleMeasure);\n observer.observe(el);\n return () => {\n observer.disconnect();\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n };\n }, [scheduleMeasure, targetRef]);\n\n return { viewport, scheduleMeasure };\n}\n","import { useCallback, useRef } from \"react\";\nimport { useViewportMeasure } from \"./useViewportMeasure\";\n\nexport type { ViewportMetrics } from \"./useViewportMeasure\";\n\n/**\n * Keep the task-list and grid panes vertically locked together, and expose\n * the grid viewport's metrics for virtualization. Everything returned is\n * identity-stable forever.\n */\nexport function useScrollSync() {\n const taskListRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<HTMLDivElement>(null);\n const isSyncing = useRef(false);\n\n const { viewport, scheduleMeasure } = useViewportMeasure(gridRef);\n\n const onTaskListScroll = useCallback(() => {\n if (isSyncing.current) {\n return;\n }\n if (!taskListRef.current || !gridRef.current) {\n return;\n }\n isSyncing.current = true;\n gridRef.current.scrollTop = taskListRef.current.scrollTop;\n isSyncing.current = false;\n scheduleMeasure();\n }, [scheduleMeasure]);\n\n const onGridScroll = useCallback(() => {\n if (gridRef.current && taskListRef.current && !isSyncing.current) {\n isSyncing.current = true;\n taskListRef.current.scrollTop = gridRef.current.scrollTop;\n isSyncing.current = false;\n }\n scheduleMeasure();\n }, [scheduleMeasure]);\n\n return { taskListRef, gridRef, onTaskListScroll, onGridScroll, viewport };\n}\n","import { useCallback, useRef } from \"react\";\n\n/**\n * Wrap an optional callback in a stable identity that always calls the latest\n * version. Presence-preserving: `undefined` in → `undefined` out, so the\n * returned identity only changes when the callback's presence flips — never\n * when the consumer passes a new inline function. Use for callbacks handed to\n * consumers through context/memoized values so they don't churn on re-render.\n */\nexport function useEventCallback<A extends unknown[], R>(\n fn: ((...args: A) => R) | undefined,\n): ((...args: A) => R) | undefined {\n const ref = useRef(fn);\n ref.current = fn;\n const stable = useCallback((...args: A) => ref.current?.(...args) as R, []);\n if (!fn) {\n return undefined;\n }\n return stable;\n}\n","/**\n * Framework-agnostic scroll math. Given a span `[start, start + size]` and a\n * viewport of `viewSize` currently scrolled to `viewOffset`, return the scroll\n * offset that brings the span into view (keeping `margin` px of padding).\n *\n * Works for either axis (pass scrollLeft/clientWidth or scrollTop/clientHeight).\n * Pure — no DOM or framework dependency, so a Vue/Svelte/Solid/Angular adapter\n * can reuse it: read the container's metrics, call this, write the result back.\n *\n * Returns the clamped (>= 0) target offset, which equals `viewOffset` when the\n * span is already fully visible — callers can skip the write when unchanged.\n */\nexport function scrollOffsetToReveal(\n start: number,\n size: number,\n viewOffset: number,\n viewSize: number,\n margin = 0,\n): number {\n const viewEnd = viewOffset + viewSize;\n if (start - margin < viewOffset) {\n return Math.max(0, start - margin);\n }\n if (start + size + margin > viewEnd) {\n return start + size + margin - viewSize;\n }\n return viewOffset;\n}\n","import type { CalendarUnit, GanttTask, TaskState } from \"../types\";\nimport { dateAtOffset, unitOffset } from \"./dateUtils\";\n\nexport interface TaskPixels {\n left: number;\n width: number;\n progress: number;\n}\n\nexport function computeTaskPixels(\n task: GanttTask,\n override: Partial<TaskState> = {},\n origin: Date,\n colWidth: number,\n unit: CalendarUnit = \"day\",\n): TaskPixels {\n // Position by the task's true instants, never snapped to the column unit, so a\n // bar's size is proportional to its real duration. `endDate` is exclusive\n // (ADR-014), so it IS the right edge — no +1 day fudge. At a coarse unit (e.g.\n // quarter) a one-day task is a thin sliver, 1/90th of a column, not a whole one.\n //\n // The display list materializes `endDate` on every task (ADR-019), so the\n // fallback here only covers a task rendered straight from consumer data.\n const startDate = override.startDate ?? task.startDate;\n const endDate = override.endDate ?? task.endDate ?? startDate;\n const startOff = unitOffset(origin, startDate, unit);\n const endOff = unitOffset(origin, endDate, unit);\n const left = startOff * colWidth;\n const width = (endOff - startOff) * colWidth;\n\n return {\n left,\n width,\n progress: override.progress ?? task.progress ?? 0,\n };\n}\n\nexport function pxToDate(\n pxOffset: number,\n origin: Date,\n colWidth: number,\n unit: CalendarUnit = \"day\",\n): Date {\n return dateAtOffset(origin, unit, pxOffset / colWidth);\n}\n\nexport interface DatePatch {\n startDate?: Date;\n endDate?: Date;\n progress?: number;\n}\n\n/**\n * What a finished drag *meant*, rather than the two dates it happened to land on.\n *\n * The preview stays rigid and pixel-derived (ADR-008), so pixel width during a\n * drag is preview state, not intent — a move that crosses a weekend must preserve\n * the task's working time, which the pixels cannot express. Emitting an intent and\n * resolving it once on drop is what keeps every calendar read out of the mousemove\n * path by construction.\n */\nexport type BarCommit =\n /** Whole bar dropped with its left edge here; the end is re-derived. */\n | { kind: \"move\"; startDate: Date }\n /** Start edge dragged here; the end is pinned. */\n | { kind: \"resizeStart\"; startDate: Date }\n /** End edge dragged here; the start is pinned. */\n | { kind: \"resizeEnd\"; endDate: Date };\n","import type { CalendarUnit, Scale } from \"../types\";\n\n/**\n * Single source of truth for the default calendar scales. The Calendar renders\n * these rows and the TaskListHeader derives its height from their count\n * (`scales.length * rowHeight + 2`), so both MUST read the same array — keep\n * this the only default to prevent the header and calendar drifting apart.\n */\nexport const DEFAULT_SCALES: Scale[] = [\n {\n unit: \"month\",\n step: 1,\n format: (d: Date) => d.toLocaleString(undefined, { month: \"long\", year: \"numeric\" }),\n },\n {\n unit: \"day\",\n step: 1,\n format: (d: Date) => String(d.getDate()),\n },\n];\n\n/**\n * The unit of the bottom-most (finest) scale row — the one that maps 1:1 to a\n * column, and therefore defines the time span of a single `colWidth`. Bar\n * geometry uses this to convert dates <-> pixels. Falls back to the defaults\n * when `scales` is omitted, and to `\"day\"` for an empty array.\n */\nexport function resolveColumnUnit(scales?: Scale[]): CalendarUnit {\n return (scales ?? DEFAULT_SCALES).at(-1)?.unit ?? \"day\";\n}\n\n/**\n * The `step` of the bottom-most (finest) scale row — how many units each column\n * spans. Pairs with {@link resolveColumnUnit}; defaults to 1.\n */\nexport function resolveColumnStep(scales?: Scale[]): number {\n return (scales ?? DEFAULT_SCALES).at(-1)?.step ?? 1;\n}\n","import type { CalendarUnit, Scale } from \"../types\";\nimport { resolveColumnStep, resolveColumnUnit } from \"./scales\";\nimport { addUnit, buildDates, getMinMaxDates, startOfUnit, unitOffset } from \"./dateUtils\";\n\n/**\n * Task-range → timeline geometry. The only layer that knows both about tasks and\n * about scales; `dateUtils` below it is pure unit/instant math with no notion of\n * either.\n */\n\n/** The minimum a timeline needs to know about a task to place it. */\nexport interface TaskDates {\n startDate: Date;\n endDate?: Date;\n}\n\n/**\n * The timeline origin: the start-of-unit boundary containing the earliest task,\n * padded outward by `pad` whole columns.\n *\n * Every consumer must derive the origin from here. There were five separate\n * copies of the `getMinMaxDates` → `resolveColumnUnit` → `resolveColumnStep` →\n * `resolveOrigin` recipe (two of them byte-identical, in `useZoom`), and they did\n * not all agree — see {@link resolveOriginAt}.\n *\n * Returns `null` when there are no tasks, i.e. no timeline to place anything on.\n */\nexport function timelineOrigin(\n tasks: readonly TaskDates[],\n scales: Scale[] | undefined,\n pad: number,\n): Date | null {\n const range = getMinMaxDates(tasks);\n if (!range) {\n return null;\n }\n return resolveOriginAt(range.min, resolveColumnUnit(scales), pad, resolveColumnStep(scales));\n}\n\n/**\n * The padded start-of-unit boundary at or before `min`.\n *\n * The trailing `startOfUnit` is load-bearing, and is the fix for a real bug: for\n * `day` and `week`, `addUnit` routes through `addDays`, which zeroes to local\n * midnight and then adds a *fixed* number of milliseconds. Across a DST boundary\n * that lands on 23:00 or 01:00 rather than midnight — so the padded origin was not\n * on a unit boundary at all.\n *\n * The grid never saw it, because it read `dates[0]` from `buildDates`, whose first\n * element is `addUnit(start, unit, 0)` — which re-zeroes the time. The task list\n * and `useZoom` used the un-re-zeroed value directly, so the two disagreed by up\n * to 23 hours: ~38px, nearly a whole column at the default `colWidth`, in any DST\n * timezone. In UTC the drift is zero, which is why it went unnoticed.\n *\n * Normalising here makes the boundary claim true for every caller, and matches\n * what the grid was already using.\n */\nexport function resolveOriginAt(min: Date, unit: CalendarUnit, pad: number, step: number): Date {\n return startOfUnit(addUnit(startOfUnit(min, unit), unit, -pad * step), unit);\n}\n\n/**\n * The full column axis: one date per column, from the padded origin through the\n * padded end of the last task.\n */\nexport function buildTimelineDates(tasks: readonly TaskDates[], pad = 0, scales?: Scale[]): Date[] {\n const range = getMinMaxDates(tasks);\n if (!range) {\n return [];\n }\n const unit = resolveColumnUnit(scales);\n const step = resolveColumnStep(scales);\n const start = resolveOriginAt(range.min, unit, pad, step);\n const end = addUnit(startOfUnit(range.max, unit), unit, pad * step);\n const count = Math.round(unitOffset(start, end, unit) / step) + 1;\n return buildDates(start, count, unit, step);\n}\n","import { useCallback, useLayoutEffect, useRef } from \"react\";\nimport type { GanttTask, Id, Scale } from \"../types\";\nimport { scrollOffsetToReveal } from \"../core/scroll\";\nimport { computeTaskPixels } from \"../core/barUtils\";\nimport { timelineOrigin } from \"../core/timeline\";\nimport { resolveColumnUnit } from \"../core/scales\";\nimport { useLatestRef } from \"./useLatestRef\";\n\n/** Which axes to reveal on. Defaults match the historical `scrollToTask(id)`. */\nexport interface RevealOptions {\n /** Reveal the task's row vertically, in whichever pane is mounted. Default `true`. */\n vertical?: boolean;\n /** Reveal the task's bar horizontally in the grid. Default `false`. */\n horizontal?: boolean;\n}\n\ninterface UseRevealTaskOptions {\n taskListRef: React.RefObject<HTMLDivElement | null>;\n gridRef: React.RefObject<HTMLDivElement | null>;\n /** The whole list, so an id hidden under a collapsed parent is still known. */\n tasksList: GanttTask[];\n visibleTasks: GanttTask[];\n rowHeight: number;\n colWidth: number;\n scales?: Scale[];\n padDays: number;\n /** Expands every collapsed ancestor of an id; from `useExpand`. */\n revealAncestors: (id: Id) => void;\n}\n\n/**\n * The single way to bring a task into view.\n *\n * Replaces two same-named functions pulling in opposite directions: a\n * `scrollToTask(id)` on the context that revealed *vertically*, and a\n * component-local `scrollToTask(task)` inside `TaskList` that revealed\n * *horizontally* — which shadowed the importable one and duplicated the origin\n * derivation to do it.\n *\n * A bare `revealTask(id)` is byte-for-byte the old vertical behaviour, so the\n * defaults keep every existing caller intact.\n *\n * Identity-stable forever: it dispatches through a ref whose implementation is\n * reassigned each render, so it closes over current geometry without ever\n * changing identity — which matters because it is a dependency of `columnApi` and\n * the task-actions context, which every memoized row consumes.\n */\nexport function useRevealTask({\n taskListRef,\n gridRef,\n tasksList,\n visibleTasks,\n rowHeight,\n colWidth,\n scales,\n padDays,\n revealAncestors,\n}: UseRevealTaskOptions): (id: Id, options?: RevealOptions) => void {\n const tasksListRef = useLatestRef(tasksList);\n const visibleTasksRef = useLatestRef(visibleTasks);\n const implRef = useRef<(id: Id, options?: RevealOptions) => void>(() => {});\n /** A reveal waiting for an expansion to commit before it can find its row. */\n const pending = useRef<{ id: Id; options?: RevealOptions } | null>(null);\n\n const revealVertically = (index: number): void => {\n const el = taskListRef.current ?? gridRef.current;\n if (!el) {\n return;\n }\n const next = scrollOffsetToReveal(\n index * rowHeight,\n rowHeight,\n el.scrollTop,\n el.clientHeight,\n rowHeight,\n );\n if (next !== el.scrollTop) {\n el.scrollTop = next;\n }\n };\n\n const revealHorizontally = (task: GanttTask): void => {\n const grid = gridRef.current;\n const origin = timelineOrigin(visibleTasksRef.current, scales, padDays);\n if (!grid || !origin) {\n return;\n }\n const { left, width } = computeTaskPixels(\n task,\n {},\n origin,\n colWidth,\n resolveColumnUnit(scales),\n );\n const nextLeft = scrollOffsetToReveal(\n left,\n width,\n grid.scrollLeft,\n grid.clientWidth,\n colWidth, // keep one column of padding\n );\n if (nextLeft !== grid.scrollLeft) {\n grid.scrollLeft = nextLeft;\n }\n };\n\n implRef.current = (id, options) => {\n const { vertical = true, horizontal = false } = options ?? {};\n const index = visibleTasksRef.current.findIndex((t) => t.id === id);\n\n if (index < 0) {\n // Not in the window. Either the id is unknown — a documented no-op — or it\n // is hidden under a collapsed ancestor, which is what `revealAncestors`\n // exists for. Expansion is a state update, so the row cannot be measured\n // until it commits: park the request and finish in the layout effect below.\n // (Not `flushSync`: this is public via `apiRef` and a consumer may call it\n // from inside an effect, where flushing synchronously is a warning.)\n if (!tasksListRef.current.some((t) => t.id === id)) {\n return;\n }\n pending.current = { id, options };\n revealAncestors(id);\n return;\n }\n\n if (vertical) {\n revealVertically(index);\n }\n if (horizontal) {\n revealHorizontally(visibleTasksRef.current[index]!);\n }\n };\n\n useLayoutEffect(() => {\n const anchor = pending.current;\n if (!anchor) {\n return;\n }\n // Cleared unconditionally: a request left parked would fire a surprise scroll\n // on the next unrelated expand.\n pending.current = null;\n implRef.current(anchor.id, anchor.options);\n }, [visibleTasks]);\n\n return useCallback((id: Id, options?: RevealOptions) => implRef.current(id, options), []);\n}\n","import { useCallback, useLayoutEffect, useRef, useState } from \"react\";\nimport { dateAtOffset, unitOffset } from \"../core/dateUtils\";\nimport { timelineOrigin } from \"../core/timeline\";\nimport { resolveColumnUnit } from \"../core/scales\";\nimport type { ZoomLevel } from \"../core/zoom\";\nimport type { GanttTask } from \"../types\";\nimport { useLatestRef } from \"./useLatestRef\";\n\ninterface UseZoomParams {\n gridRef: React.RefObject<HTMLDivElement | null>;\n visibleTasks: GanttTask[];\n padDays: number;\n levels: ZoomLevel[];\n initialIndex: number;\n}\n\nexport interface ZoomState {\n index: number;\n level: ZoomLevel;\n count: number;\n canZoomIn: boolean;\n canZoomOut: boolean;\n /** Step one rung finer, keeping the viewport-center date fixed. */\n zoomIn: () => void;\n /** Step one rung coarser, keeping the viewport-center date fixed. */\n zoomOut: () => void;\n /** Jump to a rung (clamped), keeping the viewport-center date fixed. */\n setZoom: (index: number) => void;\n /**\n * Step by `delta` rungs while keeping the date currently under `focusPx`\n * (content-space px = scrollLeft + offset-in-viewport) under that same pixel.\n * Used by wheel-zoom to anchor on the cursor.\n */\n zoomAt: (focusPx: number, delta: number) => void;\n}\n\n/** What to restore after the grid re-renders at the new level. */\ninterface PendingAnchor {\n date: Date;\n /** Pixels from the viewport's left edge that the focus date should keep. */\n viewportOffset: number;\n}\n\n/**\n * Library-managed zoom: holds the active level index and, on every level change,\n * keeps a focus date pinned to its screen position. The focus date + its\n * viewport offset are captured (at the *previous* level) when a zoom is\n * requested, then — after the grid has re-rendered at the new level — the layout\n * effect converts the date back to pixels and reassigns `scrollLeft`.\n */\nexport function useZoom({\n gridRef,\n visibleTasks,\n padDays,\n levels,\n initialIndex,\n}: UseZoomParams): ZoomState {\n const clamp = useCallback(\n (i: number) => Math.max(0, Math.min(levels.length - 1, i)),\n [levels.length],\n );\n const [index, setIndex] = useState(() => clamp(initialIndex));\n\n const indexRef = useLatestRef(index);\n const visibleTasksRef = useLatestRef(visibleTasks);\n const padDaysRef = useLatestRef(padDays);\n const levelsRef = useLatestRef(levels);\n const pending = useRef<PendingAnchor | null>(null);\n\n const zoomAt = useCallback(\n (focusPx: number, delta: number) => {\n const cur = indexRef.current;\n const next = clamp(cur + delta);\n if (next === cur) {\n return;\n }\n const grid = gridRef.current;\n const level = levelsRef.current[cur]!;\n const origin = timelineOrigin(visibleTasksRef.current, level.scales, padDaysRef.current);\n if (grid && origin) {\n const unit = resolveColumnUnit(level.scales);\n pending.current = {\n date: dateAtOffset(origin, unit, focusPx / level.colWidth),\n viewportOffset: focusPx - grid.scrollLeft,\n };\n } else {\n pending.current = null;\n }\n setIndex(next);\n },\n [clamp, gridRef, indexRef, visibleTasksRef, padDaysRef, levelsRef],\n );\n\n const centerFocusPx = useCallback(() => {\n const grid = gridRef.current;\n return grid ? grid.scrollLeft + grid.clientWidth / 2 : 0;\n }, [gridRef]);\n\n const zoomIn = useCallback(() => zoomAt(centerFocusPx(), 1), [zoomAt, centerFocusPx]);\n const zoomOut = useCallback(() => zoomAt(centerFocusPx(), -1), [zoomAt, centerFocusPx]);\n const setZoom = useCallback(\n (i: number) => zoomAt(centerFocusPx(), clamp(i) - indexRef.current),\n [zoomAt, centerFocusPx, clamp, indexRef],\n );\n\n // Re-anchor after the grid has committed the new level. Depends on `index`\n // only: re-running on task edits would fight the user's scroll position.\n useLayoutEffect(() => {\n const anchor = pending.current;\n if (anchor === null) {\n return;\n }\n pending.current = null;\n const grid = gridRef.current;\n const level = levelsRef.current[index]!;\n const origin = timelineOrigin(visibleTasksRef.current, level.scales, padDaysRef.current);\n if (!grid || !origin) {\n return;\n }\n const unit = resolveColumnUnit(level.scales);\n const targetContentPx = unitOffset(origin, anchor.date, unit) * level.colWidth;\n grid.scrollLeft = Math.max(0, targetContentPx - anchor.viewportOffset);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [index]);\n\n return {\n index,\n level: levels[index]!,\n count: levels.length,\n canZoomIn: index < levels.length - 1,\n canZoomOut: index > 0,\n zoomIn,\n zoomOut,\n setZoom,\n zoomAt,\n };\n}\n","import type { Scale } from \"../types\";\n\n/**\n * One rung of the zoom ladder: the calendar `scales` to render and the pixel\n * width of a single (finest-unit) column. Zooming steps between levels.\n */\nexport interface ZoomLevel {\n scales: Scale[];\n colWidth: number;\n}\n\nconst pad2 = (n: number) => String(n).padStart(2, \"0\");\nconst yearLabel = (d: Date) => String(d.getFullYear());\nconst quarterLabel = (d: Date) => `Q${Math.floor(d.getMonth() / 3) + 1}`;\nconst monthLong = (d: Date) => d.toLocaleString(undefined, { month: \"long\", year: \"numeric\" });\nconst monthShort = (d: Date) => d.toLocaleString(undefined, { month: \"short\" });\nconst dayOfMonth = (d: Date) => String(d.getDate());\nconst weekdayDay = (d: Date) => d.toLocaleString(undefined, { weekday: \"short\", day: \"numeric\" });\nconst hourLabel = (d: Date) => `${pad2(d.getHours())}:00`;\n\n/**\n * Default zoom ladder, ordered coarse → fine. Zooming in moves toward finer\n * (higher-index) levels; each rung pairs a coarse header row with a finer\n * bottom row whose unit is the column unit.\n */\nexport const DEFAULT_ZOOM_LEVELS: ZoomLevel[] = [\n {\n colWidth: 56,\n scales: [\n { unit: \"year\", step: 1, format: yearLabel },\n { unit: \"quarter\", step: 1, format: quarterLabel },\n ],\n },\n {\n colWidth: 44,\n scales: [\n { unit: \"year\", step: 1, format: yearLabel },\n { unit: \"month\", step: 1, format: monthShort },\n ],\n },\n {\n colWidth: 60,\n scales: [\n { unit: \"month\", step: 1, format: monthLong },\n { unit: \"week\", step: 1, format: weekdayDay },\n ],\n },\n {\n colWidth: 40,\n scales: [\n { unit: \"month\", step: 1, format: monthLong },\n { unit: \"day\", step: 1, format: dayOfMonth },\n ],\n },\n {\n colWidth: 44,\n scales: [\n { unit: \"day\", step: 1, format: weekdayDay },\n { unit: \"hour\", step: 1, format: hourLabel },\n ],\n },\n];\n\n/** Index of the default (month / day) rung in {@link DEFAULT_ZOOM_LEVELS}. */\nexport const DEFAULT_ZOOM_INDEX = 3;\n\n/**\n * Resolve the ladder to use. A consumer's `zoomLevels` win verbatim; otherwise\n * start from the default ladder but let the standalone `scales`/`colWidth` props\n * override the default (month/day) rung, so existing consumers keep their look\n * and simply gain zoom.\n */\nexport function resolveZoomLevels(\n zoomLevels: ZoomLevel[] | undefined,\n scales: Scale[] | undefined,\n colWidth: number | undefined,\n): ZoomLevel[] {\n if (zoomLevels && zoomLevels.length > 0) {\n return zoomLevels;\n }\n if (!scales && colWidth === undefined) {\n return DEFAULT_ZOOM_LEVELS;\n }\n return DEFAULT_ZOOM_LEVELS.map((level, i) =>\n i === DEFAULT_ZOOM_INDEX\n ? { scales: scales ?? level.scales, colWidth: colWidth ?? level.colWidth }\n : level,\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { Id, TaskDependency } from \"../types\";\nimport { useLatestRef } from \"./useLatestRef\";\n\nexport type ConnectorHandle = \"start\" | \"end\";\n\nexport interface DependencyDragState {\n fromTaskId: Id;\n handle: ConnectorHandle;\n startX: number;\n startY: number;\n currentX: number;\n currentY: number;\n}\n\nconst HANDLE_TO_TYPE: Record<ConnectorHandle, Record<ConnectorHandle, TaskDependency[\"type\"]>> = {\n end: { start: \"FS\", end: \"FF\" },\n start: { start: \"SS\", end: \"SF\" },\n};\n\ninterface UseDependencyDragOptions {\n /** Grid body element; preview coordinates are relative to its rect. */\n gridBodyRef: React.RefObject<HTMLDivElement | null>;\n onDependencyCreate?: (dep: TaskDependency) => void;\n}\n\n/**\n * Imperative engine for drawing a dependency between two bars: window-level\n * mousemove/mouseup listeners installed at drag start, rAF-coalesced position\n * updates, idempotent teardown (mouseup / endDrag / unmount). `startDrag` and\n * `endDrag` are identity-stable forever.\n */\nexport function useDependencyDrag({ gridBodyRef, onDependencyCreate }: UseDependencyDragOptions): {\n drag: DependencyDragState | null;\n startDrag: (state: DependencyDragState) => void;\n endDrag: (toTaskId: Id | null, toHandle?: ConnectorHandle) => void;\n} {\n const onDependencyCreateRef = useLatestRef(onDependencyCreate);\n\n const [drag, setDrag] = useState<DependencyDragState | null>(null);\n // Mirror for handlers (endDrag) so they can read the current drag without\n // subscribing to it; drag is committed at mousedown, well before any mouseup.\n const dragRef = useLatestRef(drag);\n const dragListenersRef = useRef<{\n move: (e: MouseEvent) => void;\n up: (e: MouseEvent) => void;\n } | null>(null);\n const dragFrameRef = useRef<number | null>(null);\n const lastMouseRef = useRef<{ x: number; y: number } | null>(null);\n\n // Idempotent: safe to call from mouseup, endDrag, and unmount in any order.\n const clearDragListeners = useCallback(() => {\n if (dragListenersRef.current) {\n window.removeEventListener(\"mousemove\", dragListenersRef.current.move);\n window.removeEventListener(\"mouseup\", dragListenersRef.current.up);\n dragListenersRef.current = null;\n }\n if (dragFrameRef.current !== null) {\n cancelAnimationFrame(dragFrameRef.current);\n dragFrameRef.current = null;\n }\n }, []);\n\n // The window listeners would leak if the owner unmounted mid-drag.\n useEffect(() => clearDragListeners, [clearDragListeners]);\n\n const startDrag = useCallback(\n (state: DependencyDragState) => {\n setDrag(state);\n\n // Coalesce mousemove bursts into one state update per frame. The rect is\n // re-read inside the frame: the body's viewport-relative position shifts\n // while the grid scrolls under the cursor.\n const onMouseMove = (e: MouseEvent) => {\n lastMouseRef.current = { x: e.clientX, y: e.clientY };\n if (dragFrameRef.current !== null) {\n return;\n }\n dragFrameRef.current = requestAnimationFrame(() => {\n dragFrameRef.current = null;\n const body = gridBodyRef.current;\n const last = lastMouseRef.current;\n if (!body || !last) {\n return;\n }\n const rect = body.getBoundingClientRect();\n setDrag((prev) =>\n prev ? { ...prev, currentX: last.x - rect.left, currentY: last.y - rect.top } : null,\n );\n });\n };\n\n const onMouseUp = () => {\n setDrag(null);\n clearDragListeners();\n };\n\n dragListenersRef.current = { move: onMouseMove, up: onMouseUp };\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mouseup\", onMouseUp);\n },\n [clearDragListeners, gridBodyRef],\n );\n\n const endDrag = useCallback(\n (toTaskId: Id | null, toHandle?: ConnectorHandle) => {\n const current = dragRef.current;\n if (current && toTaskId !== null && toHandle && toTaskId !== current.fromTaskId) {\n const type = HANDLE_TO_TYPE[current.handle][toHandle];\n onDependencyCreateRef.current?.({ from: current.fromTaskId, to: toTaskId, type });\n }\n setDrag(null);\n clearDragListeners();\n },\n [clearDragListeners, dragRef, onDependencyCreateRef],\n );\n\n return { drag, startDrag, endDrag };\n}\n","import { useMemo } from \"react\";\nimport type { GanttHandle } from \"../types\";\n\n/**\n * Assembles the imperative handle once, so `apiRef` and `columnApi` cannot drift\n * apart.\n *\n * They shared nine members built in two separate `useMemo`s with two 9-entry\n * dependency arrays — and `ColumnApi extends GanttHandle` already said that set\n * *is* the handle. Building it here makes that structural, and collapses the two\n * arrays into one.\n *\n * Invalidation is unchanged: the returned object's identity changes exactly when\n * one of the nine changes, which is exactly when both old arrays fired.\n */\nexport function useGanttHandle(members: GanttHandle): GanttHandle {\n const { createTask, updateTask, deleteTask, undo, redo, revealTask, zoomIn, zoomOut, setZoom } =\n members;\n // Destructured above so the deps are the individual callbacks, not the argument\n // object — which is a fresh literal on every render of the provider.\n return useMemo(\n () => ({\n createTask,\n updateTask,\n deleteTask,\n undo,\n redo,\n revealTask,\n zoomIn,\n zoomOut,\n setZoom,\n }),\n [createTask, updateTask, deleteTask, undo, redo, revealTask, zoomIn, zoomOut, setZoom],\n );\n}\n","import { useMemo } from \"react\";\nimport type { ColumnApi, GanttHandle, GanttTask, ResolvedGanttLabels } from \"../types\";\nimport { displayEndOf, workingDurationOf, type SchedulingContext } from \"../core/taskDates\";\n\ninterface UseColumnApiOptions {\n handle: GanttHandle;\n readOnly: boolean;\n labels: ResolvedGanttLabels;\n schedulingContext: SchedulingContext;\n /** Latest-ref, so an inline `onTaskEdit` does not churn this value. */\n onTaskEditRef: React.RefObject<((task: GanttTask) => void) | undefined>;\n}\n\n/**\n * The API handed to `ColumnDef.render`: the imperative handle plus the few things\n * a column cannot reach on its own.\n *\n * `render` is a plain function, not a component, so it cannot call `useGanttLabels`\n * or read the calendar from context. `labels` and `format` are its channel to\n * both.\n *\n * This value is a dependency of the task-actions context, which every memoized\n * `TaskListRow` consumes — so it must only change when one of its inputs really\n * does. That is why the options object is destructured before the memo.\n */\nexport function useColumnApi({\n handle,\n readOnly,\n labels,\n schedulingContext,\n onTaskEditRef,\n}: UseColumnApiOptions): ColumnApi {\n return useMemo(\n () => ({\n ...handle,\n editTask: (task: GanttTask) => onTaskEditRef.current?.(task),\n readOnly,\n labels,\n format: {\n endDate: (task: GanttTask) => displayEndOf(task, schedulingContext),\n duration: (task: GanttTask) => workingDurationOf(task, schedulingContext),\n },\n }),\n // onTaskEditRef is identity-stable (useLatestRef); listed only to satisfy\n // exhaustive-deps.\n [handle, onTaskEditRef, readOnly, labels, schedulingContext],\n );\n}\n","import { createContext, useContext } from \"react\";\nimport type {\n ColumnApi,\n GanttTask,\n Id,\n ResolvedGanttLabels,\n Scale,\n TaskDependency,\n} from \"../types\";\nimport { LINEAR_CONTEXT, type SchedulingContext } from \"../core/taskDates\";\nimport { DEFAULT_LABELS } from \"../core/labels\";\nimport type { ViewportMetrics } from \"../hooks/useScrollSync\";\nimport type { ConnectorHandle, DependencyDragState } from \"../hooks/useDependencyDrag\";\nimport type { BarCommit, DatePatch } from \"../core/barUtils\";\nimport type { RevealOptions } from \"../hooks/useRevealTask\";\n\nexport type { ConnectorHandle, DependencyDragState } from \"../hooks/useDependencyDrag\";\n\n/**\n * Every Gantt context object and its consumer hook.\n *\n * Kept in one file on purpose: the value of the split is being able to see all\n * twelve boundaries and the cadence table below at a glance. Splitting further,\n * one file per context, would hide exactly the thing this design needs reviewed\n * together.\n *\n * The provider that supplies these lives in `GanttProvider.tsx`; nothing here\n * imports it, so a component may depend on a context without pulling in the\n * whole composition root.\n */\n\n// Contexts are split by update frequency so high-frequency state (drag\n// position, viewport, selection) never invalidates consumers that only need\n// stable references. Rough cadence, hottest first:\n// drag position → every drag-move frame (DependencyPreview only)\n// viewport → every scroll frame (Grid only)\n// selection → per click (TaskList only)\n// task state → per edit/expand (Grid, TaskList)\n// everything else is identity-stable across those updates.\n\n// --- Config ---------------------------------------------------------------\n\nexport interface GanttConfigValue {\n rowHeight: number;\n colWidth: number;\n scales?: Scale[];\n padDays: number;\n /** Total component height in px; undefined = grow with content. */\n height?: number;\n}\n\nexport const GanttConfigContext = createContext<GanttConfigValue | null>(null);\n\nexport function useGanttConfig(): GanttConfigValue {\n const ctx = useContext(GanttConfigContext);\n if (!ctx) {\n throw new Error(\"useGanttConfig must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Labels ---------------------------------------------------------------\n\n// Kept out of the config context on purpose: config churns on every zoom step,\n// while labels only change when the consumer's `labels` prop does. Bars and rows\n// are memoized and read this directly, so it has to stay identity-stable.\n//\n// Unlike the other contexts this one does NOT throw without a provider: labels are\n// presentational defaults, not required wiring, so sub-components stay renderable\n// on their own (which is how the slot tests exercise them).\nexport const GanttLabelsContext = createContext<ResolvedGanttLabels>(DEFAULT_LABELS);\n\nexport function useGanttLabels(): ResolvedGanttLabels {\n return useContext(GanttLabelsContext);\n}\n\n// --- Working-time calendar ------------------------------------------------\n\n// Kept out of the config context on purpose: config churns on every zoom step,\n// while the calendar changes only when the consumer's prop does — and it is a\n// dependency of the task-list memo, so it must stay identity-stable.\n//\n// Like the labels context this does NOT throw without a provider: `GridColumns`\n// and `CalendarRow` are rendered bare by the slot tests, and a chart with no\n// calendar is the normal case anyway.\nexport const GanttCalendarContext = createContext<SchedulingContext>(LINEAR_CONTEXT);\n\nexport function useGanttWorkCalendar(): SchedulingContext {\n return useContext(GanttCalendarContext);\n}\n\n// --- Read-only ------------------------------------------------------------\n\n// Primitive context, its own provider because it is read by memoized leaves\n// (bars, connector handles, links) and must not ride along with anything that\n// churns. Like labels it does NOT throw without a provider: `false` — fully\n// interactive — is the historical default, which is what keeps sub-components\n// renderable bare in the slot tests.\nexport const GanttReadOnlyContext = createContext<boolean>(false);\n\nexport function useGanttReadOnly(): boolean {\n return useContext(GanttReadOnlyContext);\n}\n\n// --- Task state -----------------------------------------------------------\n\nexport interface GanttTaskStateValue {\n tasksList: GanttTask[];\n visibleTasks: GanttTask[];\n expandedIds: Set<Id>;\n parentIds: Set<Id>;\n canUndo: boolean;\n canRedo: boolean;\n}\n\nexport const GanttTaskStateContext = createContext<GanttTaskStateValue | null>(null);\n\nexport function useGanttTaskState(): GanttTaskStateValue {\n const ctx = useContext(GanttTaskStateContext);\n if (!ctx) {\n throw new Error(\"useGanttTaskState must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Task actions ---------------------------------------------------------\n\n// Everything here is identity-stable except `updateTask`/`columnApi`, which\n// only change when the `dependencies` prop changes — so per-row consumers\n// (TaskListRow) can rely on memoization.\nexport interface GanttTaskActionsValue {\n updateTask: (id: Id, patch: DatePatch) => void;\n /** Commit a finished drag as an intent; the only path that snaps to working time. */\n commitTask: (id: Id, commit: BarCommit) => void;\n createTask: (task: GanttTask, afterId?: Id | null) => void;\n deleteTask: (id: Id) => void;\n undo: () => void;\n redo: () => void;\n /** API handed to `ColumnDef.render` so columns can mutate/edit tasks. */\n columnApi: ColumnApi;\n setSelectedId: (id: Id | null) => void;\n toggleExpand: (id: Id) => void;\n onTaskClick?: (task: GanttTask) => void;\n /** Bring a task into view. See `GanttHandle.revealTask`. */\n revealTask: (id: Id, options?: RevealOptions) => void;\n}\n\nexport const GanttTaskActionsContext = createContext<GanttTaskActionsValue | null>(null);\n\nexport function useGanttTaskActions(): GanttTaskActionsValue {\n const ctx = useContext(GanttTaskActionsContext);\n if (!ctx) {\n throw new Error(\"useGanttTaskActions must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Selection ------------------------------------------------------------\n\n// Primitive context (no null-throw pattern: `null` is a valid value, meaning\n// \"nothing selected\"). The setter lives in the actions context.\nexport const GanttSelectionContext = createContext<Id | null>(null);\n\nexport function useGanttSelectedId(): Id | null {\n return useContext(GanttSelectionContext);\n}\n\n// --- Scroll ---------------------------------------------------------------\n\n// Refs and handlers only — all identity-stable, so this context never\n// re-renders its consumers. Viewport metrics live in their own context below.\nexport interface GanttScrollValue {\n taskListRef: React.RefObject<HTMLDivElement | null>;\n gridRef: React.RefObject<HTMLDivElement | null>;\n gridBodyRef: React.RefObject<HTMLDivElement | null>;\n onTaskListScroll: () => void;\n onGridScroll: () => void;\n}\n\nexport const GanttScrollContext = createContext<GanttScrollValue | null>(null);\n\nexport function useGanttScroll(): GanttScrollValue {\n const ctx = useContext(GanttScrollContext);\n if (!ctx) {\n throw new Error(\"useGanttScroll must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Viewport -------------------------------------------------------------\n\n/** Scroll offset + client size of the grid viewport, for virtualization. */\nexport const GanttViewportContext = createContext<ViewportMetrics | null>(null);\n\nexport function useGanttViewport(): ViewportMetrics {\n const ctx = useContext(GanttViewportContext);\n if (!ctx) {\n throw new Error(\"useGanttViewport must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Dependency -----------------------------------------------------------\n\nexport interface GanttDependencyValue {\n dependencies: TaskDependency[];\n onDependencyDelete?: (dep: TaskDependency) => void;\n startDrag: (state: DependencyDragState) => void;\n endDrag: (toTaskId: Id | null, toHandle?: ConnectorHandle) => void;\n}\n\nexport const GanttDependencyContext = createContext<GanttDependencyValue | null>(null);\n\nexport function useGanttDependency(): GanttDependencyValue {\n const ctx = useContext(GanttDependencyContext);\n if (!ctx) {\n throw new Error(\"useGanttDependency must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Dependency drag ------------------------------------------------------\n\n// Split in two: per-row ConnectorHandles only need \"is a drag in progress\"\n// (changes at drag start/end), while DependencyPreview needs the coordinates\n// (changes every drag-move frame). Primitive contexts, plain defaults.\nexport const GanttDragActiveContext = createContext<boolean>(false);\n\nexport function useGanttDragActive(): boolean {\n return useContext(GanttDragActiveContext);\n}\n\nexport const GanttDragContext = createContext<DependencyDragState | null>(null);\n\nexport function useGanttDependencyDrag(): DependencyDragState | null {\n return useContext(GanttDragContext);\n}\n\n// --- Zoom -----------------------------------------------------------------\n\n// Zoom controls exposed to the grid (for wheel/keyboard wiring). Identity-stable\n// callbacks; the enabled flags are plain booleans.\nexport interface GanttZoomValue {\n zoomIn: () => void;\n zoomOut: () => void;\n zoomAt: (focusPx: number, delta: number) => void;\n wheelEnabled: boolean;\n keyboardEnabled: boolean;\n}\n\nexport const GanttZoomContext = createContext<GanttZoomValue | null>(null);\n\nexport function useGanttZoom(): GanttZoomValue {\n const ctx = useContext(GanttZoomContext);\n if (!ctx) {\n throw new Error(\"useGanttZoom must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n","import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from \"react\";\nimport type { GanttProviderProps } from \"../types\";\nimport type { GanttTask, Id } from \"../types\";\nimport { useResolvedCalendar } from \"../hooks/useResolvedCalendar\";\nimport { type SchedulingContext } from \"../core/taskDates\";\nimport { resolveLabels } from \"../core/labels\";\nimport { useTaskList, EMPTY_DEPENDENCIES } from \"../hooks/useTaskList\";\nimport { useExpand } from \"../hooks/useExpand\";\nimport { useScrollSync } from \"../hooks/useScrollSync\";\nimport { useEventCallback } from \"../hooks/useEventCallback\";\nimport { useLatestRef } from \"../hooks/useLatestRef\";\nimport { useRevealTask } from \"../hooks/useRevealTask\";\nimport { useZoom } from \"../hooks/useZoom\";\nimport { DEFAULT_ZOOM_INDEX, resolveZoomLevels } from \"../core/zoom\";\nimport { useDependencyDrag } from \"../hooks/useDependencyDrag\";\nimport { DEFAULT_PAD_DAYS, DEFAULT_ROW_HEIGHT } from \"../core/constants\";\nimport { useGanttHandle } from \"./useGanttHandle\";\nimport { useColumnApi } from \"./useColumnApi\";\nimport {\n GanttCalendarContext,\n GanttConfigContext,\n GanttDependencyContext,\n GanttDragActiveContext,\n GanttDragContext,\n GanttLabelsContext,\n GanttReadOnlyContext,\n GanttScrollContext,\n GanttSelectionContext,\n GanttTaskActionsContext,\n GanttTaskStateContext,\n GanttViewportContext,\n GanttZoomContext,\n type GanttConfigValue,\n type GanttDependencyValue,\n type GanttScrollValue,\n type GanttTaskActionsValue,\n type GanttTaskStateValue,\n type GanttZoomValue,\n} from \"./contexts\";\n\n/**\n * The composition root: owns every piece of chart state and publishes it through\n * the twelve contexts defined in `contexts.ts`.\n *\n * The provider nesting at the bottom is ordered stable-outermost, hottest-inside,\n * mirroring the cadence table in `contexts.ts`. That order is not load-bearing\n * today — no layer derives its value from another, and React resolves `useContext`\n * to the nearest provider at any depth — but it documents the architecture, and it\n * *becomes* load-bearing the moment a layer starts reading another context. Keep\n * it.\n */\nexport function GanttProvider({\n tasks,\n rowHeight = DEFAULT_ROW_HEIGHT,\n colWidth,\n height,\n scales,\n padDays = DEFAULT_PAD_DAYS,\n zoomLevels,\n defaultZoomIndex,\n onZoomChange,\n zoomWheel = false,\n zoomKeyboard = false,\n dependencies = EMPTY_DEPENDENCIES,\n onTaskClick,\n onDependencyCreate,\n onDependencyDelete,\n onTaskCreate: onTaskCreateProp,\n onTaskDelete,\n onTaskEdit,\n onTasksChange,\n apiRef,\n labels,\n calendar,\n snapToWorking = true,\n durationUnit = \"day\",\n readOnly = false,\n children,\n}: GanttProviderProps) {\n const [selectedId, setSelectedId] = useState<Id | null>(null);\n\n const labelsValue = useMemo(() => resolveLabels(labels), [labels]);\n\n // Content-keyed, so an inline `calendar={{...}}` prop does not churn identity.\n const resolvedCalendar = useResolvedCalendar(calendar);\n const schedulingContext = useMemo<SchedulingContext>(\n () => ({ calendar: resolvedCalendar, durationUnit, snapToWorking }),\n [resolvedCalendar, durationUnit, snapToWorking],\n );\n\n // Latest-refs for consumer callbacks used internally at a single call site,\n // so the handlers that wrap them keep a stable identity even when the\n // consumer passes inline functions.\n const onTaskEditRef = useLatestRef(onTaskEdit);\n\n // Callbacks handed to consumers through context: presence-preserving stable\n // wrappers, so context values only churn when the callback's presence flips.\n const onTaskClickStable = useEventCallback(onTaskClick);\n const onDependencyDeleteStable = useEventCallback(onDependencyDelete);\n\n const {\n tasksList,\n updateTask,\n commitTask,\n createTask: commitCreateTask,\n deleteTask,\n undo,\n redo,\n canUndo,\n canRedo,\n } = useTaskList(\n tasks,\n dependencies,\n {\n onTaskCreate: onTaskCreateProp,\n onTaskDelete,\n onTasksChange,\n },\n schedulingContext,\n );\n\n const { visibleTasks, expandedIds, parentIds, toggleExpand, revealAncestors } =\n useExpand(tasksList);\n const { taskListRef, gridRef, onTaskListScroll, onGridScroll, viewport } = useScrollSync();\n const gridBodyRef = useRef<HTMLDivElement>(null);\n\n // Zoom owns the effective `scales`/`colWidth`: each ladder rung defines the\n // calendar rows and the column width. Standalone `scales`/`colWidth` props\n // seed the default rung (see resolveZoomLevels).\n const zoomLevelsResolved = useMemo(\n () => resolveZoomLevels(zoomLevels, scales, colWidth),\n [zoomLevels, scales, colWidth],\n );\n const zoom = useZoom({\n gridRef,\n visibleTasks,\n padDays,\n levels: zoomLevelsResolved,\n initialIndex: defaultZoomIndex ?? DEFAULT_ZOOM_INDEX,\n });\n\n // After zoom: the horizontal reveal measures against the effective colWidth and\n // scales of the current rung, not the raw props.\n const revealTask = useRevealTask({\n taskListRef,\n gridRef,\n tasksList,\n visibleTasks,\n rowHeight,\n colWidth: zoom.level.colWidth,\n scales: zoom.level.scales,\n padDays,\n revealAncestors,\n });\n\n // Fires on mount as well as on every change, so a consumer can render zoom\n // controls from it without duplicating the initial-index resolution.\n const onZoomChangeRef = useLatestRef(onZoomChange);\n useEffect(() => {\n onZoomChangeRef.current?.({ index: zoom.index, count: zoom.count });\n }, [zoom.index, zoom.count, onZoomChangeRef]);\n\n // Commit (flushSync inside, so the consumer's onTaskCreate fires first),\n // then select and reveal the new task. `revealTask` sees the fresh list:\n // flushSync re-rendered this provider before returning.\n const createTask = useCallback(\n (task: GanttTask, afterId?: Id | null) => {\n commitCreateTask(task, afterId);\n setSelectedId(task.id);\n revealTask(task.id);\n },\n [commitCreateTask, revealTask],\n );\n\n const { zoomIn, zoomOut, setZoom, zoomAt } = zoom;\n\n // One handle, two consumers. `apiRef` and `columnApi` used to build the same\n // nine members separately, behind two 9-entry dep arrays.\n const handle = useGanttHandle({\n createTask,\n updateTask,\n deleteTask,\n undo,\n redo,\n revealTask,\n zoomIn,\n zoomOut,\n setZoom,\n });\n useImperativeHandle(apiRef, () => handle, [handle]);\n\n const columnApi = useColumnApi({\n handle,\n readOnly,\n labels: labelsValue,\n schedulingContext,\n onTaskEditRef,\n });\n\n const { drag, startDrag, endDrag } = useDependencyDrag({ gridBodyRef, onDependencyCreate });\n\n // --- Context values ---\n const configValue = useMemo<GanttConfigValue>(\n () => ({\n rowHeight,\n colWidth: zoom.level.colWidth,\n scales: zoom.level.scales,\n padDays,\n height,\n }),\n [rowHeight, zoom.level, padDays, height],\n );\n\n const zoomValue = useMemo<GanttZoomValue>(\n () => ({\n zoomIn,\n zoomOut,\n zoomAt,\n wheelEnabled: zoomWheel,\n keyboardEnabled: zoomKeyboard,\n }),\n [zoomIn, zoomOut, zoomAt, zoomWheel, zoomKeyboard],\n );\n\n const taskStateValue = useMemo<GanttTaskStateValue>(\n () => ({ tasksList, visibleTasks, expandedIds, parentIds, canUndo, canRedo }),\n [tasksList, visibleTasks, expandedIds, parentIds, canUndo, canRedo],\n );\n\n // `setSelectedId` is a useState setter — stable, safe to omit from deps.\n const taskActionsValue = useMemo<GanttTaskActionsValue>(\n () => ({\n updateTask,\n commitTask,\n createTask,\n deleteTask,\n undo,\n redo,\n columnApi,\n setSelectedId,\n toggleExpand,\n onTaskClick: onTaskClickStable,\n revealTask,\n }),\n [\n updateTask,\n commitTask,\n createTask,\n deleteTask,\n undo,\n redo,\n columnApi,\n toggleExpand,\n onTaskClickStable,\n revealTask,\n ],\n );\n\n // All members are stable refs/callbacks → created exactly once.\n const scrollValue = useMemo<GanttScrollValue>(\n () => ({ taskListRef, gridRef, gridBodyRef, onTaskListScroll, onGridScroll }),\n [taskListRef, gridRef, onTaskListScroll, onGridScroll],\n );\n\n const dependencyValue = useMemo<GanttDependencyValue>(\n () => ({\n dependencies,\n onDependencyDelete: onDependencyDeleteStable,\n startDrag,\n endDrag,\n }),\n [dependencies, onDependencyDeleteStable, startDrag, endDrag],\n );\n\n // `viewport`, `selectedId`, `drag`, and `drag !== null` are passed directly:\n // primitives or already identity-stable when unchanged.\n return (\n <GanttConfigContext.Provider value={configValue}>\n <GanttReadOnlyContext.Provider value={readOnly}>\n <GanttLabelsContext.Provider value={labelsValue}>\n <GanttCalendarContext.Provider value={schedulingContext}>\n <GanttZoomContext.Provider value={zoomValue}>\n <GanttScrollContext.Provider value={scrollValue}>\n <GanttTaskActionsContext.Provider value={taskActionsValue}>\n <GanttDependencyContext.Provider value={dependencyValue}>\n <GanttTaskStateContext.Provider value={taskStateValue}>\n <GanttSelectionContext.Provider value={selectedId}>\n <GanttDragActiveContext.Provider value={drag !== null}>\n <GanttViewportContext.Provider value={viewport}>\n <GanttDragContext.Provider value={drag}>\n {children}\n </GanttDragContext.Provider>\n </GanttViewportContext.Provider>\n </GanttDragActiveContext.Provider>\n </GanttSelectionContext.Provider>\n </GanttTaskStateContext.Provider>\n </GanttDependencyContext.Provider>\n </GanttTaskActionsContext.Provider>\n </GanttScrollContext.Provider>\n </GanttZoomContext.Provider>\n </GanttCalendarContext.Provider>\n </GanttLabelsContext.Provider>\n </GanttReadOnlyContext.Provider>\n </GanttConfigContext.Provider>\n );\n}\n","import { createContext, useContext, type ReactNode } from \"react\";\nimport type { TreeCellSlotConfig } from \"../components/taskList/TreeCell\";\nimport type { TaskListHeaderSlotConfig } from \"../components/taskList/TaskListHeader\";\nimport type { TaskBarSlotConfig } from \"../components/bars/taskBar/TaskBar\";\nimport type { ProjectBarSlotConfig } from \"../components/bars/projectBar/ProjectBar\";\nimport type { MilestoneBarSlotConfig } from \"../components/bars/milestoneBar/MilestoneBar\";\nimport type { BarProgressSlotConfig } from \"../components/bars/progress/BarProgress\";\nimport type { BarProgressResizeHandleSlotConfig } from \"../components/bars/progress/BarProgressResizeHandle\";\nimport type { TaskResizerSlotConfig } from \"../components/bars/taskBar/TaskResizer\";\nimport type { ConnectorHandlesSlotConfig } from \"../components/bars/common/ConnectorHandles\";\nimport type { BarTooltipSlotConfig } from \"../components/bars/barTooltip\";\nimport type { DependencyLinksSlotConfig } from \"../components/dependency-links/DependencyLinks\";\nimport type { DependencyPreviewSlotConfig } from \"../components/dependency-links/DependencyPreview\";\nimport type { CalendarRowSlotConfig } from \"../components/calendar/CalendarRow\";\nimport type { GridColumnsSlotConfig } from \"../components/grid/GridColumns\";\nimport type { GridSlotConfig } from \"../components/grid/Grid\";\nimport type { GridResizeHandleSlotConfig } from \"../components/grid/GridResizeHandle\";\n\n/** Slots for the task-list pane. Delivered by prop-drilling (see `<Gantt taskList>`). */\nexport interface GanttTaskListSlots {\n treeCell?: TreeCellSlotConfig;\n header?: TaskListHeaderSlotConfig;\n}\n\n/** Slots for the timeline bars and their handles. Delivered via context. */\nexport interface GanttBarsSlots {\n taskBar?: TaskBarSlotConfig;\n projectBar?: ProjectBarSlotConfig;\n milestoneBar?: MilestoneBarSlotConfig;\n barProgress?: BarProgressSlotConfig;\n barProgressResizeHandle?: BarProgressResizeHandleSlotConfig;\n taskResizer?: TaskResizerSlotConfig;\n connectorHandles?: ConnectorHandlesSlotConfig;\n /**\n * One slot for all three bar types, rendered by `DraggableBar` so it is\n * scoped to the bar's own hover. Empty by default: no tooltip is rendered and\n * the bar keeps its native `title`. Note it is lost if `slots.root` is\n * replaced, since `DraggableBar` is only the default root (ADR-022).\n */\n tooltip?: BarTooltipSlotConfig;\n}\n\n/** Slots for dependency links. Delivered via context. */\nexport interface GanttDependenciesSlots {\n links?: DependencyLinksSlotConfig;\n preview?: DependencyPreviewSlotConfig;\n}\n\n/** Slots for the calendar/grid timeline chrome. Delivered via context. */\nexport interface GanttTimelineSlots {\n calendarRow?: CalendarRowSlotConfig;\n gridColumn?: GridColumnsSlotConfig;\n grid?: GridSlotConfig;\n gridResizeHandle?: GridResizeHandleSlotConfig;\n}\n\n/**\n * The grid-side slot groups delivered through context (bars/dependencies/\n * timeline). The `taskList` group is prop-drilled separately and is NOT here.\n */\nexport interface GanttSlotsValue {\n bars?: GanttBarsSlots;\n dependencies?: GanttDependenciesSlots;\n timeline?: GanttTimelineSlots;\n}\n\n// Default is an empty object so components reading their slice work fine when\n// rendered outside a provider (e.g. in isolation tests) — the hook never throws.\nconst GanttSlotsContext = createContext<GanttSlotsValue>({});\n\nexport function GanttSlotsProvider({\n value,\n children,\n}: {\n value: GanttSlotsValue;\n children: ReactNode;\n}) {\n return <GanttSlotsContext.Provider value={value}>{children}</GanttSlotsContext.Provider>;\n}\n\n/** Read the grid-side slot groups. Returns `{}` outside a provider. */\nexport function useGanttSlots(): GanttSlotsValue {\n return useContext(GanttSlotsContext);\n}\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import { clsx } from \"clsx\";\nimport type { CSSProperties } from \"react\";\n\n/**\n * A consumer-supplied `slotProps` value for a single slot: either a props object,\n * or a function of the component's `ownerState` returning props.\n *\n * `P` is the target element's prop type. Per-slot we pass the native element props\n * (e.g. `ComponentProps<\"button\">`) so consumers get `className` / `onClick` / aria /\n * `data-*` autocomplete. If a consumer replaces the element with a custom component\n * via `slots`, the props stay loosely typed against the native shape (MUI's default).\n */\nexport type SlotPropsInput<P, OwnerState> = Partial<P> | ((ownerState: OwnerState) => Partial<P>);\n\n/** Convenience shape for a component's public `{ slots, slotProps }` config prop. */\nexport interface SlotConfig<Slots, SlotProps> {\n slots?: Slots;\n slotProps?: SlotProps;\n}\n\n/**\n * Merge library-owned internal props with a consumer's `slotProps` for one slot.\n *\n * - `className`: `clsx(internal, external)` — both apply, the consumer's comes last.\n * - `style`: shallow-merged, the consumer wins per key.\n * - all other props: the consumer overrides the internal value (MUI semantics — e.g.\n * passing `onClick` replaces the default handler; this is the consumer's\n * responsibility to preserve behavior).\n */\nexport function mergeSlotProps<\n Props extends { className?: string; style?: CSSProperties },\n OwnerState,\n>(\n internalProps: Props,\n slotProps: SlotPropsInput<Props, OwnerState> | undefined,\n ownerState: OwnerState,\n): Props {\n const external = typeof slotProps === \"function\" ? slotProps(ownerState) : slotProps;\n if (!external) {\n return internalProps;\n }\n const { className, style, ...rest } = external;\n return {\n ...internalProps,\n ...rest,\n className: clsx(internalProps.className, className),\n style: { ...internalProps.style, ...style },\n } as Props;\n}\n",".calendar {\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-radius: var(--am-gantt-calendar-radius, 6px);\n overflow: hidden;\n background: var(--am-gantt-calendar-bg, #ffffff);\n font-family: inherit;\n user-select: none;\n /* Stay pinned to the top while rows scroll under it when a height is set.\n Horizontal scroll still moves it (sticky only pins the vertical axis here),\n keeping the date columns aligned with the bars. */\n position: sticky;\n top: 0;\n z-index: var(--am-gantt-calendar-z-index, 30);\n}\n\n.row {\n position: relative;\n box-sizing: border-box;\n border-bottom: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n}\n\n.row:last-child {\n border-bottom: none;\n}\n\n.row:first-child .cell {\n background: var(--am-gantt-calendar-header-bg, #f8fafc);\n font-weight: 600;\n color: var(--am-gantt-calendar-header-color, #0f172a);\n}\n\n.cell {\n position: absolute;\n top: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n padding: 0 8px;\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n font-size: 13px;\n color: var(--am-gantt-calendar-color, #334155);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.cell:last-child {\n border-right: none;\n}\n\n.cellWeekend {\n background: var(--am-gantt-calendar-weekend-bg, #f1f5f9);\n color: var(--am-gantt-calendar-weekend-color, #64748b);\n}\n","import { clsx } from \"clsx\";\nimport { useMemo, type ComponentProps, type ElementType } from \"react\";\nimport { addUnit, isWeekend, periodKey } from \"../../core/dateUtils\";\nimport { nonWorkingInfo, type NonWorkingReason } from \"../../core/workingTime\";\nimport { useGanttWorkCalendar } from \"../../context/contexts\";\nimport { formatPeriodLabel } from \"../../core/labels\";\nimport type { Scale } from \"../../types\";\nimport type { IndexRange } from \"../../core/virtualize\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport styles from \"./Calendar.module.css\";\n\n/** State passed to the function form of the CalendarRow `row` slotProps. */\nexport interface CalendarRowOwnerState {\n scale: Scale;\n colWidth: number;\n rowHeight: number;\n highlightWeekends: boolean;\n}\n\n/** State passed to the function form of the CalendarRow `cell` slotProps (per group). */\nexport interface CalendarCellOwnerState {\n scale: Scale;\n /** Start date of the group this cell represents. */\n date: Date;\n /** Index of the group's first date column. */\n startIndex: number;\n /** Number of date columns the group spans. */\n count: number;\n /**\n * Whether the calendar excludes this cell from working time. Prefer this over\n * {@link CalendarCellOwnerState.isWeekend} — it also covers holidays.\n */\n isNonWorking: boolean;\n /** Why the cell is non-working, for styling weekends and holidays apart. */\n nonWorkingReason?: NonWorkingReason;\n /**\n * @deprecated Use {@link CalendarCellOwnerState.isNonWorking}. Retained as an\n * alias so existing slot code keeps working.\n */\n isWeekend: boolean;\n colWidth: number;\n}\n\nexport interface CalendarRowSlots {\n /** The row container. Default: `\"div\"`. */\n row?: ElementType;\n /** A per-group header cell. Default: `\"div\"`. */\n cell?: ElementType;\n}\n\nexport interface CalendarRowSlotProps {\n row?: SlotPropsInput<ComponentProps<\"div\">, CalendarRowOwnerState>;\n cell?: SlotPropsInput<ComponentProps<\"div\">, CalendarCellOwnerState>;\n}\n\n/**\n * Slot config for a calendar (header) row. Pass via the calendar's slot props.\n *\n * NOTE: pass a referentially stable / memoized object so downstream memoization\n * is not defeated by a fresh object each render.\n */\nexport type CalendarRowSlotConfig = SlotConfig<CalendarRowSlots, CalendarRowSlotProps>;\n\ntype CalendarRowProps = {\n scale: Scale;\n dates: Date[];\n colWidth: number;\n rowHeight: number;\n highlightWeekends?: boolean;\n /**\n * Half-open range of date indices in view (virtualization window).\n * When omitted, every group is rendered.\n */\n colRange?: IndexRange;\n /** 1-based row number within the enclosing grid, for `aria-rowindex`. */\n rowIndex?: number;\n slots?: CalendarRowSlots;\n slotProps?: CalendarRowSlotProps;\n};\n\ninterface Group {\n key: string;\n start: Date;\n /** Index of the group's first date column, for absolute positioning. */\n startIndex: number;\n count: number;\n}\n\nfunction groupDates(dates: Date[], scale: Scale): Group[] {\n const groups: Group[] = [];\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i]!;\n const key = periodKey(date, scale.unit, scale.step);\n const last = groups[groups.length - 1];\n if (last && last.key === key) {\n last.count += 1;\n } else {\n groups.push({ key, start: date, startIndex: i, count: 1 });\n }\n }\n return groups;\n}\n\n/**\n * Half-open slice of `groups` overlapping `colRange`. Groups tile the date axis\n * in order and without gaps, so the first visible one is a binary search away\n * and the last is a short walk from there — no pass over the full list, which\n * at day scale is one entry per rendered date.\n */\nfunction groupRange(groups: Group[], colRange: IndexRange | undefined): IndexRange {\n if (!colRange) {\n return { start: 0, end: groups.length };\n }\n let lo = 0;\n let hi = groups.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n const group = groups[mid]!;\n if (group.startIndex + group.count <= colRange.start) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n let end = lo;\n while (end < groups.length && groups[end]!.startIndex < colRange.end) {\n end += 1;\n }\n return { start: lo, end };\n}\n\nexport function CalendarRow({\n scale,\n dates,\n colWidth,\n rowHeight,\n highlightWeekends = false,\n colRange,\n rowIndex,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: CalendarRowProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.calendarRow?.slots;\n const { calendar } = useGanttWorkCalendar();\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.calendarRow?.slotProps;\n\n // Grouping walks every date, so it must not ride along with the scroll frames\n // that change `colRange`: `dates` only changes when the task range or zoom\n // level does.\n const groups = useMemo(() => groupDates(dates, scale), [dates, scale]);\n const visible = groupRange(groups, colRange);\n\n const Row = slots?.row ?? \"div\";\n const Cell = slots?.cell ?? \"div\";\n\n const rowOwnerState: CalendarRowOwnerState = {\n scale,\n colWidth,\n rowHeight,\n highlightWeekends,\n };\n\n const rowProps = mergeSlotProps(\n {\n className: styles.row,\n style: { height: rowHeight },\n role: \"row\",\n \"aria-rowindex\": rowIndex,\n },\n slotProps?.row,\n rowOwnerState,\n );\n\n return (\n <Row {...rowProps}>\n {groups.slice(visible.start, visible.end).map((group) => {\n const info =\n highlightWeekends && calendar\n ? nonWorkingInfo(calendar, group.start, addUnit(group.start, scale.unit, scale.step))\n : { isNonWorking: false, reason: undefined };\n // With no calendar, keep the historical Sat/Sun-only behaviour exactly.\n const nonWorking = calendar\n ? info.isNonWorking\n : highlightWeekends && isWeekend(group.start);\n const cellOwnerState: CalendarCellOwnerState = {\n scale,\n date: group.start,\n startIndex: group.startIndex,\n count: group.count,\n isNonWorking: nonWorking,\n nonWorkingReason: nonWorking ? (info.reason ?? \"weekend\") : undefined,\n isWeekend: nonWorking,\n colWidth,\n };\n\n const cellProps = mergeSlotProps(\n {\n className: clsx(styles.cell, nonWorking && styles.cellWeekend),\n style: {\n left: group.startIndex * colWidth,\n width: group.count * colWidth,\n },\n children: scale.format(group.start),\n role: \"columnheader\",\n \"aria-colindex\": group.startIndex + 1,\n \"aria-colspan\": group.count,\n \"aria-label\": scale.ariaFormat\n ? scale.ariaFormat(group.start)\n : formatPeriodLabel(group.start, scale.unit, scale.step),\n },\n slotProps?.cell,\n cellOwnerState,\n );\n return <Cell key={group.key} {...cellProps} />;\n })}\n </Row>\n );\n}\n","import type { Scale } from \"../../types\";\nimport type { IndexRange } from \"../../core/virtualize\";\nimport styles from \"./Calendar.module.css\";\nimport { CalendarRow } from \"./CalendarRow\";\nimport { DEFAULT_SCALES } from \"../../core/scales\";\n\nexport type CalendarProps = {\n colWidth: number;\n rowHeight: number;\n scales?: Scale[];\n dates: Date[];\n /** Half-open range of date indices in view (virtualization window). */\n colRange: IndexRange;\n};\n\nexport function Calendar({\n colWidth,\n rowHeight,\n scales = DEFAULT_SCALES,\n dates,\n colRange,\n}: CalendarProps) {\n const totalWidth = dates.length * colWidth;\n\n return (\n <div className={styles.calendar} style={{ width: totalWidth }} role=\"rowgroup\">\n {scales.map((scale, index) => (\n <CalendarRow\n key={`${scale.unit}-${scale.step}`}\n scale={scale}\n dates={dates}\n colWidth={colWidth}\n rowHeight={rowHeight}\n highlightWeekends={scale.unit === \"day\" && scale.step === 1}\n colRange={colRange}\n rowIndex={index + 1}\n />\n ))}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef } from \"react\";\n\nconst EDGE = 40;\nconst MAX_SPEED = 14;\n\nfunction findScrollContainer(el: HTMLElement | null): HTMLElement | null {\n let node = el;\n while (node) {\n const style = getComputedStyle(node);\n const hasScrollableOverflow = style.overflowX === \"auto\" || style.overflowX === \"scroll\";\n if (hasScrollableOverflow && node.scrollWidth > node.clientWidth) {\n return node;\n }\n node = node.parentElement;\n }\n return document.scrollingElement as HTMLElement | null;\n}\n\nfunction bounds(container: HTMLElement): { left: number; right: number } {\n if (container === document.scrollingElement) {\n return { left: 0, right: window.innerWidth };\n }\n const boundingRect = container.getBoundingClientRect();\n return { left: boundingRect.left, right: boundingRect.right };\n}\n\nfunction edgeSpeed(left: number, right: number, cursorX: number): number {\n if (cursorX < left + EDGE) {\n return -MAX_SPEED * Math.min(1, (left + EDGE - cursorX) / EDGE);\n }\n\n if (cursorX > right - EDGE) {\n return MAX_SPEED * Math.min(1, (cursorX - (right - EDGE)) / EDGE);\n }\n\n return 0;\n}\n\ninterface AutoScrollState {\n container: HTMLElement | null;\n scrollTarget: EventTarget | null;\n startScrollLeft: number;\n cursorX: number;\n rafId: number | null;\n}\n\ninterface UseAutoScrollOptions {\n enabled: boolean;\n onScroll: () => void;\n}\n\nexport interface AutoScrollHandle {\n start: (el: HTMLElement) => void;\n stop: () => void;\n setCursorX: (clientX: number) => void;\n getScrollDelta: () => number;\n}\n\nexport function useAutoScroll({ enabled, onScroll }: UseAutoScrollOptions): AutoScrollHandle {\n const stateRef = useRef<AutoScrollState>({\n container: null,\n scrollTarget: null,\n startScrollLeft: 0,\n cursorX: 0,\n rafId: null,\n });\n\n // Indirection: removeEventListener needs the same handler ref across\n // start/stop, but onScroll's identity changes on every render of useDrag.\n const onScrollRef = useRef(onScroll);\n onScrollRef.current = onScroll;\n const handleScroll = useCallback(() => onScrollRef.current(), []);\n\n const tick = useCallback(() => {\n const s = stateRef.current;\n if (!s.container) {\n s.rafId = null;\n return;\n }\n const { left, right } = bounds(s.container);\n const speed = edgeSpeed(left, right, s.cursorX);\n if (speed !== 0) {\n s.container.scrollLeft += speed;\n }\n s.rafId = requestAnimationFrame(tick);\n }, []);\n\n const stop = useCallback(() => {\n const s = stateRef.current;\n if (s.rafId !== null) {\n cancelAnimationFrame(s.rafId);\n }\n if (s.scrollTarget) {\n s.scrollTarget.removeEventListener(\"scroll\", handleScroll);\n }\n s.container = null;\n s.scrollTarget = null;\n s.rafId = null;\n }, [handleScroll]);\n\n const start = useCallback(\n (el: HTMLElement) => {\n if (!enabled) {\n return;\n }\n const s = stateRef.current;\n const container = findScrollContainer(el);\n s.container = container;\n s.startScrollLeft = container?.scrollLeft ?? 0;\n if (container) {\n s.scrollTarget = container === document.scrollingElement ? window : container;\n // Passive: the handler only re-fires the drag, it never preventDefaults,\n // so the browser must not wait on it to scroll.\n s.scrollTarget.addEventListener(\"scroll\", handleScroll, { passive: true });\n s.rafId = requestAnimationFrame(tick);\n }\n },\n [enabled, handleScroll, tick],\n );\n\n const setCursorX = useCallback((clientX: number) => {\n stateRef.current.cursorX = clientX;\n }, []);\n\n const getScrollDelta = useCallback(() => {\n const s = stateRef.current;\n return s.container ? s.container.scrollLeft - s.startScrollLeft : 0;\n }, []);\n\n useEffect(() => stop, [stop]);\n\n return { start, stop, setCursorX, getScrollDelta };\n}\n","import { useCallback, useEffect, useRef } from \"react\";\nimport { useAutoScroll } from \"./useAutoScroll\";\n\ninterface UseDragOptions<T> {\n onStart: (e: React.MouseEvent) => T;\n onDrag: (deltaX: number, ctx: T) => void;\n onEnd?: (deltaX: number, ctx: T) => void;\n autoScroll?: boolean;\n}\n\nexport function useDrag<T>({ onStart, onDrag, onEnd, autoScroll = false }: UseDragOptions<T>) {\n const isActiveRef = useRef(false);\n const ctxRef = useRef<T | null>(null);\n const startXRef = useRef(0);\n const lastClientXRef = useRef(0);\n const lastDeltaRef = useRef(0);\n\n const onDragRef = useRef(onDrag);\n const onEndRef = useRef(onEnd);\n onDragRef.current = onDrag;\n onEndRef.current = onEnd;\n\n // Forward ref to fireDrag so useAutoScroll can call it without a circular dep.\n const fireDragRef = useRef<() => void>(() => {});\n\n const {\n start: startAutoScroll,\n stop: stopAutoScroll,\n setCursorX,\n getScrollDelta,\n } = useAutoScroll({\n enabled: autoScroll,\n onScroll: () => fireDragRef.current(),\n });\n\n const fireDrag = useCallback(() => {\n if (!isActiveRef.current || ctxRef.current === null) {\n return;\n }\n const cursorDelta = lastClientXRef.current - startXRef.current;\n const deltaX = cursorDelta + getScrollDelta();\n lastDeltaRef.current = deltaX;\n onDragRef.current(deltaX, ctxRef.current);\n }, [getScrollDelta]);\n fireDragRef.current = fireDrag;\n\n const onMouseDown = useCallback(\n (e: React.MouseEvent) => {\n ctxRef.current = onStart(e);\n startXRef.current = e.clientX;\n lastClientXRef.current = e.clientX;\n lastDeltaRef.current = 0;\n isActiveRef.current = true;\n setCursorX(e.clientX);\n startAutoScroll(e.currentTarget as HTMLElement);\n e.preventDefault();\n e.stopPropagation();\n },\n [onStart, setCursorX, startAutoScroll],\n );\n\n useEffect(() => {\n const onMouseMove = (e: MouseEvent) => {\n if (!isActiveRef.current || ctxRef.current === null) {\n return;\n }\n lastClientXRef.current = e.clientX;\n setCursorX(e.clientX);\n fireDrag();\n e.preventDefault();\n };\n const onMouseUp = () => {\n if (isActiveRef.current && ctxRef.current !== null) {\n onEndRef.current?.(lastDeltaRef.current, ctxRef.current);\n }\n isActiveRef.current = false;\n ctxRef.current = null;\n stopAutoScroll();\n };\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mouseup\", onMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", onMouseMove);\n window.removeEventListener(\"mouseup\", onMouseUp);\n stopAutoScroll();\n };\n }, [fireDrag, setCursorX, stopAutoScroll]);\n\n return onMouseDown;\n}\n","/*\n * `left`/`top` are written inline by BarTooltip.tsx, which places the tooltip\n * from the cursor. Nothing here positions it (ADR-022).\n *\n * The element is portalled to `document.body`, which is what makes the z-index\n * below mean anything — rendered in place it sits inside `.row`, a stacking\n * context, and could never out-rank the calendar header. Being outside the grid\n * subtree is also what escapes its `overflow: auto`, so the containing-block\n * caveat that used to apply here no longer does.\n */\n.tooltip {\n position: fixed;\n\n /* Ranks at the top level now, so it must clear the calendar header (30) and\n * anything else the chart stacks. Themable for consumers whose own overlays\n * sit higher. */\n z-index: var(--am-gantt-tooltip-z-index, 1000);\n\n width: max-content;\n max-width: var(--am-gantt-tooltip-max-width, 260px);\n padding: var(--am-gantt-tooltip-padding, 8px 10px);\n border-radius: var(--am-gantt-tooltip-radius, 6px);\n background: var(--am-gantt-tooltip-bg, #0f172a);\n color: var(--am-gantt-tooltip-color, #f8fafc);\n font-size: var(--am-gantt-tooltip-font-size, 12px);\n line-height: 1.45;\n box-shadow: var(--am-gantt-tooltip-shadow, 0 4px 12px rgb(15 23 42 / 25%));\n pointer-events: none;\n}\n\n.name {\n font-weight: 600;\n margin-block-end: 4px;\n}\n\n.row {\n display: flex;\n gap: 12px;\n justify-content: space-between;\n}\n\n.label {\n opacity: 0.7;\n}\n","import { createContext, useContext, type RefObject } from \"react\";\n\n/**\n * Open state shared *within one tooltip slot*, owned by `BarTooltipRoot` and read\n * by `BarTooltipTrigger` and the popup.\n *\n * It sits inside the slot rather than in `BarTooltipConsumer` so that nothing\n * outside the slot has an opinion about open state (ADR-022).\n *\n * `null` means there is no root above, which is why `BarTooltipTrigger` is a\n * no-op rather than an error: `TaskBar`/`ProjectBar`/`MilestoneBar` are public\n * exports that render standalone.\n */\nexport interface BarTooltipContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n /** The bar's DOM node, used to verify the pointer really did leave it. */\n anchorRef: RefObject<HTMLDivElement | null>;\n}\n\nexport const BarTooltipContext = createContext<BarTooltipContextValue | null>(null);\n\n/** The enclosing `BarTooltipRoot`'s state, or `null` when there is none. */\nexport const useBarTooltip = (): BarTooltipContextValue | null => useContext(BarTooltipContext);\n","import { useMemo, useState, type ReactNode, type RefObject } from \"react\";\nimport { BarTooltipContext, type BarTooltipContextValue } from \"./BarTooltipContext\";\n\n/**\n * Owns one bar tooltip's open state and publishes it to `BarTooltipTrigger` and\n * whatever renders the popup.\n *\n * Belongs *inside* the tooltip slot, and a slot is free to skip it entirely and\n * use a third-party tooltip's root instead (ADR-022).\n *\n * Exported for the middle case: a custom tooltip that wants the library's hover\n * and closing behaviour with different markup. Compose it with\n * `BarTooltipTrigger` and `useBarTooltip`.\n */\nexport function BarTooltipRoot({\n anchorRef,\n children,\n}: {\n anchorRef: RefObject<HTMLDivElement | null>;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n\n const value = useMemo<BarTooltipContextValue>(\n () => ({ open, setOpen, anchorRef }),\n [open, anchorRef],\n );\n\n return <BarTooltipContext.Provider value={value}>{children}</BarTooltipContext.Provider>;\n}\n","import {\n cloneElement,\n isValidElement,\n useEffect,\n type ComponentProps,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n} from \"react\";\nimport { useBarTooltip } from \"./BarTooltipContext\";\n\n/**\n * Turns the element it is given into the tooltip's trigger. Belongs inside the\n * tooltip slot, under a `BarTooltipRoot` and wrapped around the slot's\n * `children`: that is what makes hover behaviour the slot's own business rather\n * than the bar's.\n *\n * It **merges** onto that element rather than wrapping it, which is not a style\n * preference: the bar contains `<button>` resize and connector handles, so a\n * wrapping trigger — Base UI's default renders a `<button>` — would nest buttons\n * and produce invalid HTML that breaks those controls. `cloneElement` adds no DOM\n * at all.\n *\n * Handlers are composed with whatever the element already has, so a consumer's\n * `slotProps.root` handlers and the a11y payload keep firing.\n */\nexport function BarTooltipTrigger({ children }: { children: ReactNode }) {\n const context = useBarTooltip();\n const open = context?.open ?? false;\n const setOpen = context?.setOpen;\n const anchorRef = context?.anchorRef;\n\n // `mouseleave` alone does not close the tooltip, and this is why it sometimes\n // stayed open. Boundary events follow *pointer movement*: when the bar leaves\n // from under a stationary pointer — a wheel scroll, a zoom changing `colWidth`,\n // a drag repositioning it — no `mouseout` is dispatched until the next pointer\n // event. Both listeners live only while open, and one bar is open at a time.\n useEffect(() => {\n if (!open || !setOpen) {\n return;\n }\n\n // Scroll is the case a pointer check cannot catch: a stationary cursor\n // produces no mousemove at all. Capture phase because `scroll` does not\n // bubble, on `document` so any scrolling ancestor counts.\n const closeOnScroll = () => setOpen(false);\n\n // A missed `mouseout` still leaves the pointer geometrically outside, so\n // verify the rect instead of trusting the event.\n const closeIfOutside = (event: MouseEvent) => {\n const rect = anchorRef?.current?.getBoundingClientRect();\n // A zero-size rect means the bar is not laid out yet — first paint, or\n // jsdom, which reports every rect as zero. Trusting it would read every\n // pointer position as \"outside\" and close immediately.\n if (!rect || rect.width === 0 || rect.height === 0) {\n return;\n }\n const inside =\n event.clientX >= rect.left &&\n event.clientX <= rect.right &&\n event.clientY >= rect.top &&\n event.clientY <= rect.bottom;\n if (!inside) {\n setOpen(false);\n }\n };\n\n document.addEventListener(\"scroll\", closeOnScroll, { capture: true, passive: true });\n document.addEventListener(\"mousemove\", closeIfOutside, { passive: true });\n return () => {\n document.removeEventListener(\"scroll\", closeOnScroll, { capture: true });\n document.removeEventListener(\"mousemove\", closeIfOutside);\n };\n }, [open, setOpen, anchorRef]);\n\n // `children` is typed as `ReactNode` because that is what a slot receives, so\n // the element case is checked rather than assumed. Anything else — a fragment,\n // a list, text — is handed back untouched: there is no single node to attach to.\n if (!setOpen || !isValidElement<ComponentProps<\"div\">>(children)) {\n return children;\n }\n\n const { onMouseEnter, onMouseLeave } = children.props;\n\n return cloneElement(children, {\n onMouseEnter: (event: ReactMouseEvent<HTMLDivElement>) => {\n onMouseEnter?.(event);\n setOpen(true);\n },\n onMouseLeave: (event: ReactMouseEvent<HTMLDivElement>) => {\n onMouseLeave?.(event);\n setOpen(false);\n },\n } as Partial<ComponentProps<\"div\">>);\n}\n","import {\n useContext,\n useState,\n type CSSProperties,\n type RefObject,\n useDeferredValue,\n useEffect,\n} from \"react\";\nimport { GanttScrollContext } from \"../../../context/contexts\";\n\n/** Gap between the cursor and the tooltip's nearest corner, px. */\nconst CURSOR_OFFSET = 12;\n/** Distance kept clear of the bounding edges, px. */\nconst EDGE_MARGIN = 8;\n\ninterface Bounds {\n left: number;\n top: number;\n right: number;\n bottom: number;\n}\n\nfunction placeAxis(cursor: number, size: number, min: number, max: number): number {\n const after = cursor + CURSOR_OFFSET;\n const fitsAfter = after + size <= max - EDGE_MARGIN;\n return Math.max(fitsAfter ? after : cursor - CURSOR_OFFSET - size, min + EDGE_MARGIN);\n}\n\nexport const useTooltipPosition = (\n tooltipRef: RefObject<HTMLDivElement | null>,\n open: boolean,\n): CSSProperties => {\n // Read the context, do not assert it: `useGanttScroll()` throws without a\n // provider, and this hook must not. Two cases reach it with no provider above.\n //\n // `TaskBar`/`ProjectBar`/`MilestoneBar` are public exports that render\n // standalone, and `GanttSlotsProvider` is public too — so a bar can be handed\n // this tooltip with no chart around it, the same case that makes\n // `useBarTooltip` return null rather than throw (ADR-022).\n //\n // The other is a hot reload. Re-evaluating `contexts.ts` mints a new context\n // object, which the already-mounted provider is not providing; the throwing\n // hook turned that into a crash on every HMR update with a tooltip open.\n //\n // Losing the grid only widens the bounds — the fallback below is the viewport,\n // which is why degrading here costs nothing but a clamp.\n const gridRef = useContext(GanttScrollContext)?.gridRef;\n const [positioningStyle, setPositiongStyle] = useState<CSSProperties>({\n left: -9999,\n top: -9999,\n });\n\n const deferredPosition = useDeferredValue(positioningStyle);\n\n useEffect(() => {\n // Gated on `open`, and that is not a micro-optimisation. The slot wraps the\n // bar, so one instance is mounted per visible row — roughly thirty. Without\n // this, every one of them would listen for mousemove and call `setState` on\n // every pointer move anywhere in the chart.\n if (!open) {\n return;\n }\n\n const handleMouseMove = (event: MouseEvent) => {\n const { clientX, clientY } = event;\n\n const grid = gridRef?.current?.getBoundingClientRect();\n const bounds: Bounds =\n grid && grid.width > 0 && grid.height > 0\n ? { left: grid.left, top: grid.top, right: grid.right, bottom: grid.bottom }\n : { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };\n\n // Outside the chart there is nothing to place against, and the trigger is\n // closing the tooltip on this same event anyway. Bailing out keeps a\n // pointer moving elsewhere on the page from re-rendering the tooltip on\n // every move, and stops it visibly chasing the cursor out of the grid on\n // the way.\n const outside =\n clientX < bounds.left ||\n clientX > bounds.right ||\n clientY < bounds.top ||\n clientY > bounds.bottom;\n if (outside) {\n return;\n }\n\n const self = tooltipRef.current?.getBoundingClientRect();\n const width = self?.width ?? 0;\n const height = self?.height ?? 0;\n\n const left = placeAxis(clientX, width, bounds.left, bounds.right);\n const top = placeAxis(clientY, height, bounds.top, bounds.bottom);\n\n // Clamping pins the tooltip to an edge over a range of cursor positions, so\n // a moving pointer often resolves to the position it already has. Bailing\n // on an unchanged result keeps those moves from re-rendering.\n setPositiongStyle((previous) =>\n previous.left === left && previous.top === top ? previous : { left, top },\n );\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n };\n }, [tooltipRef, gridRef, open]);\n\n return deferredPosition;\n};\n","import { useRef, type ComponentProps, type CSSProperties } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport styles from \"./BarTooltip.module.css\";\nimport { useBarTooltip } from \"./BarTooltipContext\";\nimport { BarTooltipRoot } from \"./BarTooltipRoot\";\nimport { BarTooltipTrigger } from \"./BarTooltipTrigger\";\nimport type { BarTooltipOwnerState, BarTooltipProps } from \"./types\";\nimport { useTooltipPosition } from \"./useTooltipPosition\";\n\nfunction formatDate(date: Date | undefined) {\n if (!date) {\n return \"—\";\n }\n\n return date.toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n}\n\n/**\n * The popup itself. Separate from `GanttBarTooltip` because it reads the open\n * state its sibling `BarTooltipRoot` provides, and a component cannot consume the\n * context it renders.\n *\n * Portalled to `document.body`. That is what lets its z-index rank at the top\n * level — rendered in place it sits inside `.row`, a stacking context, where no\n * value could out-rank the calendar header (ADR-022).\n */\nfunction BarTooltipPopup({\n task,\n progress,\n displayEnd,\n className,\n style,\n ...divProps\n}: Omit<BarTooltipOwnerState, \"children\"> & ComponentProps<\"div\">) {\n const ref = useRef<HTMLDivElement | null>(null);\n const open = useBarTooltip()?.open ?? false;\n\n const positioning: CSSProperties = useTooltipPosition(ref, open);\n\n // `document` is guarded rather than assumed: the popup only exists on hover, so\n // a server render never reaches it, but it must not be touched during one.\n if (!open || typeof document === \"undefined\") {\n return null;\n }\n\n return createPortal(\n <div\n role=\"tooltip\"\n ref={ref}\n className={className ? `${styles.tooltip} ${className}` : styles.tooltip}\n style={{ ...style, ...positioning }}\n {...divProps}\n >\n <div className={styles.name}>{task.name}</div>\n <div className={styles.row}>\n <span className={styles.label}>Start</span>\n <span>{formatDate(task.startDate)}</span>\n </div>\n <div className={styles.row}>\n <span className={styles.label}>End</span>\n <span>{formatDate(displayEnd)}</span>\n </div>\n <div className={styles.row}>\n <span className={styles.label}>Progress</span>\n <span>{Math.round(progress)}%</span>\n </div>\n </div>,\n document.body,\n );\n}\n\n/**\n * The built-in bar tooltip. Opt in with `slots={{ tooltip: GanttBarTooltip }}`;\n * it is never rendered by default.\n *\n * A wrapper, not a sibling: it renders the bar it is handed and mounts its own\n * root and trigger around it, so it holds no privileged position over any other\n * slot (ADR-022).\n *\n * Placed from the cursor in JS, not with CSS anchor positioning: anchoring to the\n * bar puts the tooltip at the midpoint of a bar that can be wider than the\n * viewport. It follows the pointer for as long as it is open; there is no dwell\n * delay.\n */\nexport function GanttBarTooltip({\n task,\n progress,\n displayEnd,\n anchorRef,\n className,\n style,\n children,\n ...divProps\n}: BarTooltipProps & ComponentProps<\"div\">) {\n return (\n <BarTooltipRoot anchorRef={anchorRef}>\n <BarTooltipTrigger>{children}</BarTooltipTrigger>\n <BarTooltipPopup\n task={task}\n progress={progress}\n displayEnd={displayEnd}\n className={className}\n style={style}\n {...divProps}\n />\n </BarTooltipRoot>\n );\n}\n","import type { ReactNode, RefObject } from \"react\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport { mergeSlotProps } from \"../../../core/slots\";\nimport type { BarTooltipOwnerState } from \"./types\";\n\n/**\n * Resolves the tooltip slot and wraps the bar in it. Stateless on purpose.\n *\n * There is no open state and no context here: whether the tooltip is showing is\n * the slot's business, held by `BarTooltipRoot` inside it. That is what lets a\n * slot be a third-party tooltip that brings its own root and trigger (ADR-022).\n *\n * The slot is a *wrapper*: it receives the bar as `children` and must render it.\n */\nexport function BarTooltipConsumer({\n children,\n tooltip,\n anchorRef,\n}: {\n children: ReactNode;\n tooltip?: BarTooltipOwnerState;\n anchorRef: RefObject<HTMLDivElement | null>;\n}) {\n const tooltipConfig = useGanttSlots().bars?.tooltip;\n const Tooltip = tooltipConfig?.slots?.tooltip;\n\n if (!Tooltip || !tooltip) {\n return children;\n }\n\n return (\n <Tooltip\n {...mergeSlotProps({}, tooltipConfig?.slotProps?.tooltip, tooltip)}\n anchorRef={anchorRef}\n {...tooltip}\n >\n {children}\n </Tooltip>\n );\n}\n","import { useRef, type ComponentPropsWithoutRef, type CSSProperties, type ReactNode } from \"react\";\n\nimport { useDrag } from \"../../../hooks/useDrag\";\nimport { BarTooltipConsumer, type BarTooltipOwnerState } from \"../barTooltip\";\n\nexport interface BarA11yProps {\n role: string;\n \"aria-colindex\": number;\n \"aria-colspan\": number;\n \"aria-label\": string;\n \"aria-selected\": boolean | undefined;\n /**\n * The native browser tooltip. Optional because a chart with a tooltip slot\n * suppresses it — two tooltips would stack. `aria-label` is unaffected, so\n * the accessible name survives either way.\n */\n title?: string;\n}\n\ninterface DraggableBarProps extends Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"style\" | \"className\" | \"title\" | \"children\" | \"onMouseDown\"\n> {\n left: number;\n top: number;\n width: number;\n height: number;\n colWidth: number;\n dragAnchor: number;\n className?: string;\n title?: string;\n style?: CSSProperties;\n /** Omitted on a read-only chart; without it the bar carries no drag listener. */\n onMove?: (newAnchor: number) => void;\n onMoveEnd?: (newAnchor: number) => void;\n /**\n * Task data for the tooltip slot; omit it and no tooltip is rendered.\n *\n * The tooltip lives here rather than in `Row` so it is scoped to the bar's own\n * hover — a row spans the whole timeline width — and so it can anchor to this\n * element without a ref threaded down from above.\n *\n * The cost, accepted deliberately: this is only the *default* root\n * (`Root = slots?.root ?? DraggableBar` in all three bars), so replacing\n * `slots.root` removes the tooltip unless the replacement forwards this prop\n * on to a `DraggableBar` of its own (ADR-022).\n */\n tooltip?: BarTooltipOwnerState;\n children?: ReactNode;\n}\n\nexport function DraggableBar({\n left,\n top,\n width,\n height,\n colWidth,\n dragAnchor,\n className,\n title,\n style,\n onMove,\n onMoveEnd,\n tooltip,\n onMouseEnter,\n onMouseLeave,\n children,\n ...rest\n}: DraggableBarProps) {\n const barRef = useRef<HTMLDivElement>(null);\n\n const readOnly = !onMove && !onMoveEnd;\n const onMouseDown = useDrag({\n onStart: () => ({ start: dragAnchor }),\n onDrag: (deltaX, { start }) => onMove?.(start + deltaX),\n onEnd: (deltaX, { start }) => {\n const snapped = Math.round((start + deltaX) / colWidth) * colWidth;\n onMoveEnd?.(snapped);\n },\n autoScroll: true,\n });\n\n const movable = Boolean(onMove || onMoveEnd);\n\n return (\n <BarTooltipConsumer tooltip={tooltip} anchorRef={barRef}>\n <div\n {...rest}\n ref={barRef}\n className={className}\n style={{ left, top, width, height, cursor: readOnly ? \"default\" : \"move\", ...style }}\n title={title}\n onMouseDown={movable ? onMouseDown : undefined}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n >\n {children}\n </div>\n </BarTooltipConsumer>\n );\n}\n",".milestone {\n position: absolute;\n}\n\n.milestoneShape {\n width: 100%;\n height: 100%;\n background-color: var(--am-gantt-milestone-bg);\n clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { DraggableBar, type BarA11yProps } from \"../common/DraggableBar\";\nimport styles from \"./MilestoneBar.module.css\";\n\nexport interface MilestoneBarOwnerState {\n size: number;\n title: string;\n}\n\nexport interface MilestoneBarSlots {\n /** The draggable bar wrapper. Default: `DraggableBar`. */\n root?: ElementType;\n /** The diamond shape. Default: `\"div\"`. */\n shape?: ElementType;\n}\n\nexport interface MilestoneBarSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, MilestoneBarOwnerState>;\n shape?: SlotPropsInput<ComponentProps<\"div\">, MilestoneBarOwnerState>;\n}\n\nexport type MilestoneBarSlotConfig = SlotConfig<MilestoneBarSlots, MilestoneBarSlotProps>;\n\ninterface MilestoneBarProps {\n size: number;\n centerLeft: number;\n top: number;\n colWidth: number;\n title: string;\n a11y?: BarA11yProps;\n /** Editing handlers; omitted on a read-only chart (see `TaskBar`). */\n onMove?: (newCenterLeft: number) => void;\n onMoveEnd?: (newCenterLeft: number) => void;\n /**\n * Task data handed to the root so it can render the tooltip slot. Forwarded\n * verbatim; a replaced `slots.root` that ignores it simply shows no tooltip.\n */\n tooltip?: BarTooltipOwnerState;\n slots?: MilestoneBarSlots;\n slotProps?: MilestoneBarSlotProps;\n}\n\nexport function MilestoneBar({\n size,\n centerLeft,\n top,\n colWidth,\n title,\n a11y,\n onMove,\n onMoveEnd,\n tooltip,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: MilestoneBarProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.milestoneBar?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.milestoneBar?.slotProps;\n\n const ownerState: MilestoneBarOwnerState = { size, title };\n\n const Root = slots?.root ?? DraggableBar;\n const Shape = slots?.shape ?? \"div\";\n\n // When `a11y` is supplied it owns the native tooltip, including deliberately\n // omitting it under a tooltip slot. The `title` prop is only the fallback for\n // standalone use of this component outside a chart.\n const rootProps = mergeSlotProps(\n { className: styles.milestone, ...a11y, title: a11y ? a11y.title : title },\n slotProps?.root,\n ownerState,\n );\n\n const shapeProps = mergeSlotProps(\n { className: styles.milestoneShape, \"aria-hidden\": true },\n slotProps?.shape,\n ownerState,\n );\n\n return (\n <Root\n tooltip={tooltip}\n left={centerLeft - size / 2}\n top={top}\n width={size}\n height={size}\n colWidth={colWidth}\n dragAnchor={centerLeft}\n onMove={onMove}\n onMoveEnd={onMoveEnd}\n {...rootProps}\n >\n <Shape {...shapeProps} />\n </Root>\n );\n}\n",".barProgress {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background-color: var(--am-gantt-bar-progress-bg, var(--am-gantt-task-bg-progress));\n border-radius: 4px 0 0 4px;\n}\n\n.barProgressResizeHandle {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 1px;\n height: 10px;\n cursor: ew-resize;\n background-color: transparent;\n z-index: 10;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n:global(.am-gantt-bar-task):hover .barProgressResizeHandle {\n opacity: 1;\n}\n\n.barProgressResizeHandle:after {\n content: \"\";\n position: absolute;\n top: 0;\n left: -5px;\n width: 10px;\n height: 10px;\n background-color: var(--am-gantt-calendar-border);\n /* triangle rotate */\n clip-path: polygon(50% 0%, 0% 100%, 100% 100%);\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { useDrag } from \"../../../hooks/useDrag\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport styles from \"./BarProgress.module.css\";\n\n/** State passed to the function form of the BarProgressResizeHandle slotProps. */\nexport interface BarProgressResizeHandleOwnerState {\n width: number;\n parentWidth: number;\n}\n\nexport interface BarProgressResizeHandleSlots {\n /** The progress resize handle element. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface BarProgressResizeHandleSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, BarProgressResizeHandleOwnerState>;\n}\n\nexport type BarProgressResizeHandleSlotConfig = SlotConfig<\n BarProgressResizeHandleSlots,\n BarProgressResizeHandleSlotProps\n>;\n\ntype BarProgressResizeHandleProps = {\n width: number;\n onResize: (newWidth: number) => void;\n onResizeEnd?: (newWidth: number) => void;\n parentWidth: number;\n slots?: BarProgressResizeHandleSlots;\n slotProps?: BarProgressResizeHandleSlotProps;\n};\n\nexport function BarProgressResizeHandle({\n width,\n onResize,\n onResizeEnd,\n parentWidth,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: BarProgressResizeHandleProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.barProgressResizeHandle?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.barProgressResizeHandle?.slotProps;\n\n const clampWidth = (deltaX: number, startWidth: number) =>\n Math.min(Math.max(0, startWidth + deltaX), parentWidth);\n\n const onMouseDown = useDrag({\n onStart: () => ({ startWidth: width }),\n onDrag: (deltaX, { startWidth }) => onResize(clampWidth(deltaX, startWidth)),\n onEnd: (deltaX, { startWidth }) => onResizeEnd?.(clampWidth(deltaX, startWidth)),\n });\n\n const ownerState: BarProgressResizeHandleOwnerState = { width, parentWidth };\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.barProgressResizeHandle,\n \"aria-hidden\": true,\n tabIndex: -1,\n onMouseDown,\n },\n slotProps?.root,\n ownerState,\n );\n\n return <Root {...rootProps} />;\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport styles from \"./BarProgress.module.css\";\nimport { BarProgressResizeHandle } from \"./BarProgressResizeHandle\";\n\n/** State passed to the function form of each BarProgress slotProps. */\nexport interface BarProgressOwnerState {\n progress: number;\n width: number;\n height: number;\n}\n\nexport interface BarProgressSlots {\n /** The progress fill element. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface BarProgressSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, BarProgressOwnerState>;\n}\n\n/** Slot config for the bar progress fill. */\nexport type BarProgressSlotConfig = SlotConfig<BarProgressSlots, BarProgressSlotProps>;\n\ninterface BarProgressProps {\n width: number;\n height: number;\n progress: number;\n onProgressChange?: (newProgress: number) => void;\n onProgressEnd?: (newProgress: number) => void;\n slots?: BarProgressSlots;\n slotProps?: BarProgressSlotProps;\n}\n\nexport function BarProgress({\n progress,\n width: parentWidth,\n height,\n onProgressChange,\n onProgressEnd,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: BarProgressProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.barProgress?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.barProgress?.slotProps;\n\n const width = (progress / 100) * parentWidth;\n const toProgress = (newWidth: number) => (newWidth / parentWidth) * 100;\n\n const ownerState: BarProgressOwnerState = { progress, width, height };\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n { className: styles.barProgress, style: { width, height } },\n slotProps?.root,\n ownerState,\n );\n\n return (\n <Root {...rootProps}>\n {onProgressChange && (\n <BarProgressResizeHandle\n width={width}\n parentWidth={parentWidth}\n onResize={(newWidth) => onProgressChange(toProgress(newWidth))}\n onResizeEnd={\n onProgressEnd ? (newWidth) => onProgressEnd(toProgress(newWidth)) : undefined\n }\n />\n )}\n </Root>\n );\n}\n",".project {\n position: absolute;\n box-sizing: border-box;\n background-color: var(--am-gantt-project-bg);\n border-radius: 4px;\n overflow: hidden;\n --am-gantt-bar-progress-bg: var(--am-gantt-project-bg-progress);\n}\n\n.projectInner {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.projectContent {\n vertical-align: middle;\n text-align: center;\n font-size: 14px;\n color: var(--am-gantt-project-color);\n font-weight: 600;\n position: relative;\n z-index: 1;\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { DraggableBar, type BarA11yProps } from \"../common/DraggableBar\";\nimport { BarProgress } from \"../progress/BarProgress\";\nimport styles from \"./ProjectBar.module.css\";\n\n/** State passed to the function form of each ProjectBar slotProps. */\nexport interface ProjectBarOwnerState {\n width: number;\n height: number;\n progress: number;\n title: string;\n}\n\nexport interface ProjectBarSlots {\n /** The draggable bar wrapper. Default: `DraggableBar`. */\n root?: ElementType;\n /** The inner layout wrapper holding progress/label. Default: `\"div\"`. */\n inner?: ElementType;\n /** The title label. Default: `\"div\"`. */\n label?: ElementType;\n}\n\nexport interface ProjectBarSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, ProjectBarOwnerState>;\n inner?: SlotPropsInput<ComponentProps<\"div\">, ProjectBarOwnerState>;\n label?: SlotPropsInput<ComponentProps<\"div\">, ProjectBarOwnerState>;\n}\n\n/** Slot config for the project bar. */\nexport type ProjectBarSlotConfig = SlotConfig<ProjectBarSlots, ProjectBarSlotProps>;\n\ninterface ProjectBarProps {\n width: number;\n height: number;\n left: number;\n top: number;\n colWidth: number;\n title: string;\n a11y?: BarA11yProps;\n progress: number;\n /** Editing handlers; omitted on a read-only chart (see `TaskBar`). */\n onProgressChange?: (newProgress: number) => void;\n onProgressEnd?: (newProgress: number) => void;\n onMove?: (newLeft: number) => void;\n onMoveEnd?: (newLeft: number) => void;\n /**\n * Task data handed to the root so it can render the tooltip slot. Forwarded\n * verbatim; a replaced `slots.root` that ignores it simply shows no tooltip.\n */\n tooltip?: BarTooltipOwnerState;\n slots?: ProjectBarSlots;\n slotProps?: ProjectBarSlotProps;\n}\n\nexport function ProjectBar({\n width,\n height,\n left,\n top,\n colWidth,\n title,\n a11y,\n progress,\n onProgressChange,\n onProgressEnd,\n onMove,\n onMoveEnd,\n tooltip,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: ProjectBarProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.projectBar?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.projectBar?.slotProps;\n\n const ownerState: ProjectBarOwnerState = { width, height, progress, title };\n\n const Root = slots?.root ?? DraggableBar;\n const Inner = slots?.inner ?? \"div\";\n const Label = slots?.label ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.project,\n style: { lineHeight: `${height}px` },\n ...a11y,\n },\n slotProps?.root,\n ownerState,\n );\n\n const innerProps = mergeSlotProps(\n { className: styles.projectInner, \"aria-hidden\": true },\n slotProps?.inner,\n ownerState,\n );\n\n const labelProps = mergeSlotProps(\n { className: styles.projectContent, children: title },\n slotProps?.label,\n ownerState,\n );\n\n return (\n <Root\n tooltip={tooltip}\n left={left}\n top={top}\n width={width}\n height={height}\n colWidth={colWidth}\n dragAnchor={left}\n onMove={onMove}\n onMoveEnd={onMoveEnd}\n {...rootProps}\n >\n <Inner {...innerProps}>\n <BarProgress\n width={width}\n height={height}\n progress={progress}\n onProgressChange={onProgressChange}\n onProgressEnd={onProgressEnd}\n />\n <Label {...labelProps} />\n </Inner>\n </Root>\n );\n}\n",".task {\n position: absolute;\n box-sizing: border-box;\n background-color: var(--am-gantt-task-bg);\n border-radius: var(--am-gantt-task-border-radius);\n --am-gantt-bar-progress-bg: var(--am-gantt-task-bg-progress);\n}\n\n.taskInner {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.taskContent {\n vertical-align: middle;\n text-align: center;\n font-size: var(--am-gantt-task-font-size);\n color: var(--am-gantt-task-color);\n padding-inline: 8px;\n position: relative;\n z-index: 1;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.resizer {\n position: absolute;\n top: 0;\n width: var(--am-gantt-resizer-width);\n height: 100%;\n cursor: ew-resize;\n background-color: transparent;\n z-index: 10;\n padding: 0;\n border: none;\n}\n\n.resizer::after {\n opacity: 0;\n content: \"\";\n width: var(--am-gantt-resizer-handle-width);\n inset: var(--am-gantt-resizer-handle-inset);\n height: calc(100% - (var(--am-gantt-resizer-handle-inset) * 2));\n border-radius: var(--am-gantt-resizer-handle-radius);\n background-color: var(--am-gantt-calendar-border);\n position: absolute;\n}\n\n.task:hover .resizer::after {\n opacity: 0.8;\n}\n\n.task:hover .resizer:hover .resizer::after {\n opacity: 1;\n}\n\n.startResizer {\n left: 0;\n}\n.endResizer {\n right: 0;\n}\n","import clsx from \"clsx\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { useDrag } from \"../../../hooks/useDrag\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport styles from \"./TaskBar.module.css\";\n\n/** State passed to the function form of each TaskResizer slotProps. */\nexport interface TaskResizerOwnerState {\n width: number;\n left: number;\n}\n\nexport interface TaskResizerSlots {\n /** The left/start resize button. Default: `\"button\"`. */\n startHandle?: ElementType;\n /** The right/end resize button. Default: `\"button\"`. */\n endHandle?: ElementType;\n}\n\nexport interface TaskResizerSlotProps {\n startHandle?: SlotPropsInput<ComponentProps<\"button\">, TaskResizerOwnerState>;\n endHandle?: SlotPropsInput<ComponentProps<\"button\">, TaskResizerOwnerState>;\n}\n\nexport type TaskResizerSlotConfig = SlotConfig<TaskResizerSlots, TaskResizerSlotProps>;\n\ninterface TaskResizerProps {\n width: number;\n left: number;\n colWidth: number;\n onResize: (newWidth: number, newLeft: number) => void;\n /**\n * Fired on release with ONLY the edge the user dragged, as an absolute pixel\n * position. The opposite edge is deliberately not reported: snapping both\n * independently is what used to let a start-handle drag shift the far edge by a\n * whole column.\n */\n onResizeEnd: (edge: \"start\" | \"end\", edgePx: number) => void;\n slots?: TaskResizerSlots;\n slotProps?: TaskResizerSlotProps;\n}\n\nexport function TaskResizer({\n width,\n left,\n colWidth,\n onResize,\n onResizeEnd,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: TaskResizerProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.taskResizer?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.taskResizer?.slotProps;\n\n const onStartHandleMouseDown = useDrag({\n onStart: () => ({ startWidth: width, startLeft: left }),\n onDrag: (deltaX, { startWidth, startLeft }) => {\n const clampedDelta = Math.min(deltaX, startWidth);\n const newWidth = startWidth - clampedDelta;\n const newLeft = startLeft + clampedDelta;\n onResize(newWidth, newLeft);\n },\n onEnd: (deltaX, { startWidth, startLeft }) => {\n const clampedDelta = Math.min(deltaX, startWidth);\n const rawLeft = startLeft + clampedDelta;\n onResizeEnd(\"start\", Math.round(rawLeft / colWidth) * colWidth);\n },\n });\n\n const onEndHandleMouseDown = useDrag({\n onStart: () => ({ startWidth: width, startLeft: left }),\n onDrag: (deltaX, { startWidth, startLeft }) => {\n const newWidth = Math.max(0, startWidth + deltaX);\n onResize(newWidth, startLeft);\n },\n onEnd: (deltaX, { startWidth, startLeft }) => {\n const rawRight = startLeft + Math.max(0, startWidth + deltaX);\n onResizeEnd(\"end\", Math.round(rawRight / colWidth) * colWidth);\n },\n });\n\n const ownerState: TaskResizerOwnerState = { width, left };\n\n const StartHandle = slots?.startHandle ?? \"button\";\n const EndHandle = slots?.endHandle ?? \"button\";\n\n const startHandleProps = mergeSlotProps(\n {\n type: \"button\" as const,\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.resizer, styles.startResizer),\n onMouseDown: onStartHandleMouseDown,\n },\n slotProps?.startHandle,\n ownerState,\n );\n\n const endHandleProps = mergeSlotProps(\n {\n type: \"button\" as const,\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.resizer, styles.endResizer),\n onMouseDown: onEndHandleMouseDown,\n },\n slotProps?.endHandle,\n ownerState,\n );\n\n return (\n <>\n <StartHandle {...startHandleProps} />\n <EndHandle {...endHandleProps} />\n </>\n );\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { DraggableBar, type BarA11yProps } from \"../common/DraggableBar\";\nimport { BarProgress } from \"../progress/BarProgress\";\nimport styles from \"./TaskBar.module.css\";\nimport { TaskResizer } from \"./TaskResizer\";\n\n/** State passed to the function form of each TaskBar slotProps. */\nexport interface TaskBarOwnerState {\n width: number;\n height: number;\n progress: number;\n title: string;\n}\n\nexport interface TaskBarSlots {\n /** The draggable bar wrapper. Default: `DraggableBar`. */\n root?: ElementType;\n /** The inner layout wrapper holding progress/label/resizer. Default: `\"div\"`. */\n inner?: ElementType;\n /** The title label. Default: `\"div\"`. */\n label?: ElementType;\n}\n\nexport interface TaskBarSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, TaskBarOwnerState>;\n inner?: SlotPropsInput<ComponentProps<\"div\">, TaskBarOwnerState>;\n label?: SlotPropsInput<ComponentProps<\"div\">, TaskBarOwnerState>;\n}\n\n/** Slot config for the task bar. */\nexport type TaskBarSlotConfig = SlotConfig<TaskBarSlots, TaskBarSlotProps>;\n\ninterface TaskBarProps {\n width: number;\n height: number;\n left: number;\n top: number;\n colWidth: number;\n title: string;\n a11y?: BarA11yProps;\n progress: number;\n /**\n * Editing handlers. All optional: a read-only chart omits them, and each\n * affordance is only rendered/wired when its handlers are present.\n */\n onProgressChange?: (newProgress: number) => void;\n onProgressEnd?: (newProgress: number) => void;\n onResize?: (newWidth: number, newLeft: number) => void;\n onResizeEnd?: (edge: \"start\" | \"end\", edgePx: number) => void;\n onMove?: (newLeft: number) => void;\n onMoveEnd?: (newLeft: number) => void;\n /**\n * Task data handed to the root so it can render the tooltip slot. Forwarded\n * verbatim; a replaced `slots.root` that ignores it simply shows no tooltip.\n */\n tooltip?: BarTooltipOwnerState;\n slots?: TaskBarSlots;\n slotProps?: TaskBarSlotProps;\n}\n\nexport function TaskBar({\n width,\n height,\n left,\n top,\n colWidth,\n title,\n a11y,\n progress = 30,\n onProgressChange,\n onProgressEnd,\n onResize,\n onResizeEnd,\n onMove,\n onMoveEnd,\n tooltip,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: TaskBarProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.taskBar?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.taskBar?.slotProps;\n\n const ownerState: TaskBarOwnerState = { width, height, progress, title };\n\n const Root = slots?.root ?? DraggableBar;\n const Inner = slots?.inner ?? \"div\";\n const Label = slots?.label ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: `${styles.task} am-gantt-bar-task`,\n style: { lineHeight: `${height}px` },\n ...a11y,\n },\n slotProps?.root,\n ownerState,\n );\n\n const innerProps = mergeSlotProps(\n { className: styles.taskInner, \"aria-hidden\": true },\n slotProps?.inner,\n ownerState,\n );\n\n // The label's native tooltip follows `a11y.title`, not the `title` prop: the\n // prop is the visible text, `a11y.title` is the native tooltip, and a chart\n // with a tooltip slot suppresses only the latter.\n const labelProps = mergeSlotProps(\n { className: styles.taskContent, title: a11y?.title, children: title },\n slotProps?.label,\n ownerState,\n );\n\n return (\n <Root\n tooltip={tooltip}\n left={left}\n top={top}\n width={width}\n height={height}\n colWidth={colWidth}\n dragAnchor={left}\n onMove={onMove}\n onMoveEnd={onMoveEnd}\n {...rootProps}\n >\n <Inner {...innerProps}>\n <BarProgress\n width={width}\n height={height}\n progress={progress}\n onProgressChange={onProgressChange}\n onProgressEnd={onProgressEnd}\n />\n <Label {...labelProps} />\n {onResize && onResizeEnd && (\n <TaskResizer\n width={width}\n left={left}\n colWidth={colWidth}\n onResize={onResize}\n onResizeEnd={onResizeEnd}\n />\n )}\n </Inner>\n </Root>\n );\n}\n",".handle {\n position: absolute;\n /* Keep in sync with CONNECTOR_HANDLE_SIZE in core/constants.ts */\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #3b82f6;\n border: 2px solid #fff;\n box-shadow: 0 0 0 1px #3b82f6;\n cursor: crosshair;\n z-index: 20;\n opacity: 0;\n transition: opacity 0.15s;\n pointer-events: auto;\n box-sizing: border-box;\n}\n\n.visible {\n opacity: 1;\n}\n","import { clsx } from \"clsx\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport {\n useGanttDependency,\n useGanttDragActive,\n useGanttScroll,\n type ConnectorHandle,\n} from \"../../../context/contexts\";\nimport { CONNECTOR_HANDLE_SIZE } from \"../../../core/constants\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { Id } from \"../../../types\";\nimport styles from \"./ConnectorHandles.module.css\";\n\nconst HANDLE_OFFSET = CONNECTOR_HANDLE_SIZE / 2;\n\n/** State passed to the function form of each ConnectorHandles slotProps. */\nexport interface ConnectorHandlesOwnerState {\n taskId: Id;\n barLeft: number;\n barWidth: number;\n barCenterY: number;\n show: boolean;\n isDragging: boolean;\n}\n\nexport interface ConnectorHandlesSlots {\n /** The left/start dependency-connector handle. Default: `\"div\"`. */\n startHandle?: ElementType;\n /** The right/end dependency-connector handle. Default: `\"div\"`. */\n endHandle?: ElementType;\n}\n\nexport interface ConnectorHandlesSlotProps {\n startHandle?: SlotPropsInput<ComponentProps<\"div\">, ConnectorHandlesOwnerState>;\n endHandle?: SlotPropsInput<ComponentProps<\"div\">, ConnectorHandlesOwnerState>;\n}\n\nexport type ConnectorHandlesSlotConfig = SlotConfig<\n ConnectorHandlesSlots,\n ConnectorHandlesSlotProps\n>;\n\ninterface ConnectorHandlesProps {\n taskId: Id;\n barLeft: number;\n barWidth: number;\n barCenterY: number;\n show: boolean;\n slots?: ConnectorHandlesSlots;\n slotProps?: ConnectorHandlesSlotProps;\n}\n\nexport function ConnectorHandles({\n taskId,\n barLeft,\n barWidth,\n barCenterY,\n show,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: ConnectorHandlesProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.connectorHandles?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.connectorHandles?.slotProps;\n\n const { startDrag, endDrag } = useGanttDependency();\n const isDragging = useGanttDragActive();\n const { gridBodyRef } = useGanttScroll();\n\n const getStartCoords = (e: React.MouseEvent, _handle: ConnectorHandle) => {\n const rect = gridBodyRef.current?.getBoundingClientRect();\n if (!rect) {\n return { x: 0, y: 0 };\n }\n const handleEl = e.currentTarget as HTMLElement;\n const hRect = handleEl.getBoundingClientRect();\n return {\n x: hRect.left + hRect.width / 2 - rect.left,\n y: hRect.top + hRect.height / 2 - rect.top,\n };\n };\n\n const onMouseDown = (e: React.MouseEvent, handle: ConnectorHandle) => {\n e.stopPropagation();\n e.preventDefault();\n const { x, y } = getStartCoords(e, handle);\n startDrag({ fromTaskId: taskId, handle, startX: x, startY: y, currentX: x, currentY: y });\n };\n\n const onMouseUp = (e: React.MouseEvent, handle: ConnectorHandle) => {\n if (isDragging) {\n e.stopPropagation();\n endDrag(taskId, handle);\n }\n };\n\n const ownerState: ConnectorHandlesOwnerState = {\n taskId,\n barLeft,\n barWidth,\n barCenterY,\n show,\n isDragging,\n };\n\n const StartHandle = slots?.startHandle ?? \"div\";\n const EndHandle = slots?.endHandle ?? \"div\";\n\n const isVisible = show || isDragging;\n\n const startHandleProps = mergeSlotProps(\n {\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.handle, isVisible && styles.visible),\n style: { left: barLeft - CONNECTOR_HANDLE_SIZE, top: barCenterY - HANDLE_OFFSET },\n onMouseDown: (e: React.MouseEvent) => onMouseDown(e, \"start\"),\n onMouseUp: (e: React.MouseEvent) => onMouseUp(e, \"start\"),\n },\n slotProps?.startHandle,\n ownerState,\n );\n\n const endHandleProps = mergeSlotProps(\n {\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.handle, isVisible && styles.visible),\n style: { left: barLeft + barWidth, top: barCenterY - HANDLE_OFFSET },\n onMouseDown: (e: React.MouseEvent) => onMouseDown(e, \"end\"),\n onMouseUp: (e: React.MouseEvent) => onMouseUp(e, \"end\"),\n },\n slotProps?.endHandle,\n ownerState,\n );\n\n return (\n <>\n <StartHandle {...startHandleProps} />\n <EndHandle {...endHandleProps} />\n </>\n );\n}\n","/*\n * `position: absolute` + a non-auto `z-index` makes this a stacking context, so\n * a tooltip rendered inside it can never out-rank the sticky calendar (30) — the\n * row's own 3 is what competes. That is why the tooltip is placed to avoid the\n * header band rather than to paint over it (ADR-022).\n *\n * Do not add `transform`, `filter`, `contain`, `will-change` or `perspective`\n * here, to the grid, or to anything between them. Each establishes a containing\n * block for fixed-position descendants, and the tooltip is `position: fixed`\n * precisely so it escapes the grid's `overflow: auto` without a portal. Adding\n * one re-clips it silently, and no test can observe that.\n */\n.row {\n position: absolute;\n left: 0;\n right: 0;\n border-bottom: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n box-sizing: border-box;\n z-index: var(--am-gantt-task-bar-z-index, 3);\n}\n\n.row:last-child {\n border-bottom: none;\n}\n","import { memo, startTransition, useState } from \"react\";\nimport {\n type BarCommit,\n computeTaskPixels,\n type DatePatch,\n pxToDate,\n} from \"../../../core/barUtils\";\nimport { TASK_VERTICAL_PADDING } from \"../../../core/constants\";\nimport {\n useGanttLabels,\n useGanttReadOnly,\n useGanttSelectedId,\n useGanttWorkCalendar,\n} from \"../../../context/contexts\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport { displayEndOf } from \"../../../core/taskDates\";\nimport type { CalendarUnit, GanttTask, Id, TaskState } from \"../../../types\";\nimport { MilestoneBar } from \"../milestoneBar/MilestoneBar\";\nimport { ProjectBar } from \"../projectBar/ProjectBar\";\nimport { TaskBar } from \"../taskBar/TaskBar\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { ConnectorHandles } from \"./ConnectorHandles\";\nimport type { BarA11yProps } from \"./DraggableBar\";\nimport styles from \"./Row.module.css\";\n\ninterface RowProps {\n task: GanttTask;\n index: number;\n origin: Date;\n colWidth: number;\n rowHeight: number;\n unit: CalendarUnit;\n onUpdate: (id: Id, patch: DatePatch) => void;\n onCommit: (id: Id, commit: BarCommit) => void;\n override?: Partial<TaskState>;\n onOverride: (id: Id, patch: DatePatch | null) => void;\n onTaskClick?: (task: GanttTask) => void;\n rowIndexOffset: number;\n}\n\nexport const Row = memo(function Row({\n task,\n index,\n origin,\n colWidth,\n rowHeight,\n unit,\n override,\n onOverride,\n onUpdate,\n onCommit,\n onTaskClick,\n rowIndexOffset,\n}: RowProps) {\n const labels = useGanttLabels();\n const readOnly = useGanttReadOnly();\n const selectedId = useGanttSelectedId();\n const isSelected = selectedId === task.id;\n\n const schedulingContext = useGanttWorkCalendar();\n // Read only to decide whether to suppress the native `title` — that has to\n // happen where `a11y` is assembled, which is here. The tooltip itself is\n // rendered by the bar.\n const Tooltip = useGanttSlots().bars?.tooltip?.slots?.tooltip;\n\n const { left, width, progress } = computeTaskPixels(task, override || {}, origin, colWidth, unit);\n const top = index * rowHeight;\n const visualLeft = left;\n const barHeight = rowHeight - TASK_VERTICAL_PADDING * 2;\n const barCenterY = TASK_VERTICAL_PADDING + barHeight / 2;\n\n // The handles bracket the bar's *painted* box, which for a milestone is not\n // its date span. A milestone is an instant, so `computeTaskPixels` returns\n // width 0, while `MilestoneBar` paints a `barHeight`-square diamond centred on\n // `visualLeft` — mirrored from its own `centerLeft - size / 2`. Passing the raw\n // span put the start handle over the diamond's left half and the end handle\n // exactly on its centre, instead of outside it as on every other bar type.\n const isMilestone = task.type === \"milestone\";\n const handleLeft = isMilestone ? visualLeft - barHeight / 2 : visualLeft;\n const handleWidth = isMilestone ? barHeight - 1 : width;\n\n // Row-level hover, for the connector handles: they should appear as the\n // pointer approaches the bar. The tooltip's own hover lives in the bar\n // (DraggableBar), which is what renders it (ADR-022).\n const [hovered, setHovered] = useState(false);\n\n // `endDate` is exclusive (ADR-014), so the bar's right edge maps straight to it —\n // no day subtracted back off.\n const moveAt = (newLeft: number): DatePatch => ({\n startDate: pxToDate(newLeft, origin, colWidth, unit),\n endDate: pxToDate(newLeft + width, origin, colWidth, unit),\n });\n\n const resizeAt = (newWidth: number, newLeft: number): DatePatch => ({\n startDate: pxToDate(newLeft, origin, colWidth, unit),\n endDate: pxToDate(newLeft + newWidth, origin, colWidth, unit),\n });\n\n const handleOverride = (patch: DatePatch) => {\n onOverride(task.id, patch);\n };\n\n const handleUpdate = (id: Id, patch: DatePatch) => {\n startTransition(() => {\n onUpdate(id, patch);\n onOverride(id, null);\n });\n };\n\n // Commits carry INTENT, not the two dates the pixels happened to land on: a move\n // must preserve working time, which pixel width cannot express once a calendar\n // exists. Clearing the override unconditionally is also what makes a bar dropped\n // in non-working time visibly settle back — a commit that resolves to no change\n // schedules no log update, so the preview clear is the only thing in the\n // transition and the bar settles on the next render.\n const handleCommit = (commit: BarCommit) => {\n startTransition(() => {\n onCommit(task.id, commit);\n onOverride(task.id, null);\n });\n };\n\n const commitMoveAt = (newLeft: number): BarCommit => ({\n kind: \"move\",\n startDate: pxToDate(newLeft, origin, colWidth, unit),\n });\n\n // A read-only bar is handed no editing handlers at all, rather than handlers\n // that decline: each affordance (drag listener, resizer, progress handle)\n // renders only when its callbacks arrive, so omitting them removes the\n // affordance itself — nothing to grab, nothing to explain away.\n const moveHandlers = readOnly\n ? {}\n : {\n onMove: (newVisualLeft: number) => handleOverride(moveAt(newVisualLeft)),\n onMoveEnd: (newVisualLeft: number) => handleCommit(commitMoveAt(newVisualLeft)),\n };\n\n const progressHandlers = readOnly\n ? {}\n : {\n onProgressChange: (p: number) => handleOverride({ progress: p }),\n onProgressEnd: (p: number) => handleUpdate(task.id, { progress: p }),\n };\n\n const resizeHandlers = readOnly\n ? {}\n : {\n onResize: (newWidth: number, newVisualLeft: number) =>\n handleOverride(resizeAt(newWidth, newVisualLeft)),\n onResizeEnd: (edge: \"start\" | \"end\", edgePx: number) =>\n handleCommit(\n edge === \"start\"\n ? { kind: \"resizeStart\", startDate: pxToDate(edgePx, origin, colWidth, unit) }\n : { kind: \"resizeEnd\", endDate: pxToDate(edgePx, origin, colWidth, unit) },\n ),\n };\n\n // The native `title` is dropped when a tooltip slot is configured: the browser\n // tooltip would otherwise surface on top of the custom one. `aria-label` is\n // untouched, so the accessible name is the same either way — which is also why\n // dropping it is safe with a hover-only tooltip (ADR-022).\n const a11y: BarA11yProps = {\n role: \"gridcell\",\n \"aria-colindex\": Math.max(1, Math.floor(visualLeft / colWidth) + 1),\n \"aria-colspan\": Math.max(1, Math.round(width / colWidth)),\n \"aria-label\": labels.bar(task, { progress }),\n \"aria-selected\": isSelected || undefined,\n title: Tooltip ? undefined : task.name,\n };\n\n // Data only — nothing here says whether the tooltip is showing, because that is\n // the slot's own state (ADR-022). `progress` is override-aware during a drag,\n // and `displayEnd` is inclusive (ADR-014) so no consumer rediscovers that\n // `task.endDate` is exclusive.\n const tooltipData: BarTooltipOwnerState = {\n task,\n progress,\n displayEnd: displayEndOf(task, schedulingContext),\n };\n\n return (\n <div\n className={styles.row}\n style={{ top, height: rowHeight }}\n onClick={onTaskClick ? () => onTaskClick(task) : undefined}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n role=\"row\"\n aria-rowindex={rowIndexOffset + index + 1}\n >\n {!readOnly && (\n <ConnectorHandles\n taskId={task.id}\n barLeft={handleLeft}\n barWidth={handleWidth}\n barCenterY={barCenterY}\n show={hovered}\n />\n )}\n\n {task.type === \"milestone\" && (\n <MilestoneBar\n tooltip={tooltipData}\n size={barHeight}\n centerLeft={visualLeft}\n top={TASK_VERTICAL_PADDING}\n colWidth={colWidth}\n title={task.name}\n a11y={a11y}\n {...moveHandlers}\n />\n )}\n {task.type === \"summary\" && (\n <ProjectBar\n tooltip={tooltipData}\n left={visualLeft}\n top={TASK_VERTICAL_PADDING}\n width={width}\n height={barHeight}\n colWidth={colWidth}\n title={task.name}\n a11y={a11y}\n progress={progress}\n {...progressHandlers}\n {...moveHandlers}\n />\n )}\n {task.type === \"task\" || !task.type ? (\n <TaskBar\n tooltip={tooltipData}\n left={visualLeft}\n top={TASK_VERTICAL_PADDING}\n width={width}\n height={barHeight}\n colWidth={colWidth}\n title={task.name}\n a11y={a11y}\n progress={progress}\n {...progressHandlers}\n {...moveHandlers}\n {...resizeHandlers}\n />\n ) : null}\n </div>\n );\n});\n\nRow.displayName = \"Row\";\n","import { computeTaskPixels } from \"../../core/barUtils\";\nimport { TASK_VERTICAL_PADDING } from \"../../core/constants\";\nimport type {\n CalendarUnit,\n GanttTask,\n Id,\n TaskDependency,\n TaskDependencyType,\n TaskState,\n} from \"../../types\";\n\n/** Length of the horizontal stub that leaves a bar before the link turns. */\nconst STUB = 12;\n\n/** Shared \"no override\" argument, so the base pass allocates nothing per task. */\nconst EMPTY_STATE: Partial<TaskState> = {};\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface DependencyLink {\n /** Stable key, e.g. `\"1->2\"`. */\n id: string;\n type: TaskDependencyType;\n /** Orthogonal polyline from the source edge to the target edge. */\n points: Point[];\n /** Bounding box of {@link DependencyLink.points}, precomputed for culling. */\n bounds: Bounds;\n /** The original dependency for callbacks. */\n dep: TaskDependency;\n}\n\n/** Axis-aligned pixel bounds. */\nexport interface Bounds {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\n/** Bounding box of a polyline, for viewport culling. */\nexport function linkBounds(points: Point[]): Bounds {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of points) {\n if (p.x < minX) {\n minX = p.x;\n }\n if (p.x > maxX) {\n maxX = p.x;\n }\n if (p.y < minY) {\n minY = p.y;\n }\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n return { minX, minY, maxX, maxY };\n}\n\n/** Midpoint of the middle segment of a polyline. */\nexport function midpoint(points: Point[]): Point {\n if (points.length < 2) {\n return points[0] ?? { x: 0, y: 0 };\n }\n const mid = Math.floor((points.length - 1) / 2);\n const a = points[mid]!;\n const b = points[mid + 1]!;\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n}\n\n/**\n * Pixel-space bounds of a single bar: its left/right edges and vertical center.\n *\n * Carries the `task` it was built from so a re-route can rebuild the box against\n * a drag override without a second id → task index (see {@link reRouteOverrides}).\n */\ninterface Box {\n startX: number;\n endX: number;\n centerY: number;\n task: GanttTask;\n}\n\n/** Pixel geometry inputs shared by the base pass and any later re-route. */\ninterface PixelParams {\n origin: Date;\n colWidth: number;\n rowHeight: number;\n unit: CalendarUnit;\n}\n\n/**\n * One task's pixel box at row centre `centerY`.\n *\n * x-coordinates come from {@link computeTaskPixels}, the same source the bars\n * use, so links stay glued to bar edges. Shared by the base pass and the\n * override re-route so the two can never drift apart.\n */\nfunction boxOf(\n task: GanttTask,\n state: Partial<TaskState>,\n centerY: number,\n { origin, colWidth, rowHeight, unit }: PixelParams,\n): Box {\n const { left, width } = computeTaskPixels(task, state, origin, colWidth, unit);\n if (task.type === \"milestone\") {\n // Milestones render as a diamond centered on `left`.\n const half = (rowHeight - TASK_VERTICAL_PADDING * 2) / 2;\n return { startX: left - half, endX: left + half, centerY, task };\n }\n return { startX: left, endX: left + width, centerY, task };\n}\n\n/**\n * Build a lookup of every task's pixel bounds. The y-coordinate is derived from\n * the task's row index — the visual order of `tasks` maps 1:1 to grid rows.\n */\nfunction buildBoxes(tasks: GanttTask[], params: PixelParams): Map<Id, Box> {\n const boxes = new Map<Id, Box>();\n const { rowHeight } = params;\n tasks.forEach((task, index) => {\n boxes.set(task.id, boxOf(task, EMPTY_STATE, index * rowHeight + rowHeight / 2, params));\n });\n return boxes;\n}\n\n/**\n * \"Staircase\" route: source edge points toward the target, so a single vertical\n * mid-segment connects the two horizontal runs. Used when the target edge sits\n * far enough ahead in the travel direction; otherwise we wrap (see `wrap`).\n */\nfunction staircase(s: Point, t: Point): Point[] {\n const midX = (s.x + t.x) / 2;\n return [s, { x: midX, y: s.y }, { x: midX, y: t.y }, t];\n}\n\n/**\n * \"Wrap\" route for when the target edge is behind the source's exit direction:\n * exit by a stub, drop to the mid-row, run across, then approach the target.\n */\nfunction wrap(s: Point, t: Point, sDir: number, tDir: number): Point[] {\n const ox = s.x + sDir * STUB; // source stub end\n const ix = t.x - tDir * STUB; // target stub start\n const midY = (s.y + t.y) / 2;\n return [s, { x: ox, y: s.y }, { x: ox, y: midY }, { x: ix, y: midY }, { x: ix, y: t.y }, t];\n}\n\n/**\n * \"L\" route for same-edge relationships (SS / FF): exit horizontally just past\n * the outermost of the two edges, drop straight to the target's row, then run\n * back in to the target edge. No backtracking past the bar.\n */\nfunction lShape(s: Point, t: Point, xv: number): Point[] {\n return [s, { x: xv, y: s.y }, { x: xv, y: t.y }, t];\n}\n\n/** Build the polyline for one dependency from the two bars' pixel bounds. */\nfunction routeLink(type: TaskDependencyType, from: Box, to: Box): Point[] {\n const sy = from.centerY;\n const ty = to.centerY;\n\n switch (type) {\n case \"FS\": {\n // finish → start: exit the source's right edge, enter the target's left.\n const s: Point = { x: from.endX, y: sy };\n const t: Point = { x: to.startX, y: ty };\n return to.startX >= from.endX + 2 * STUB ? staircase(s, t) : wrap(s, t, 1, 1);\n }\n case \"SS\": {\n // start ⇉ start: both exit left; drop at the leftmost edge, run in right.\n const s: Point = { x: from.startX, y: sy };\n const t: Point = { x: to.startX, y: ty };\n return lShape(s, t, Math.min(from.startX, to.startX) - STUB);\n }\n case \"FF\": {\n // finish ⇄ finish: both exit right; drop at the rightmost edge, run in left.\n const s: Point = { x: from.endX, y: sy };\n const t: Point = { x: to.endX, y: ty };\n return lShape(s, t, Math.max(from.endX, to.endX) + STUB);\n }\n case \"SF\": {\n // start → finish: exit the source's left edge, enter the target's right.\n const s: Point = { x: from.startX, y: sy };\n const t: Point = { x: to.endX, y: ty };\n return to.endX <= from.startX - 2 * STUB ? staircase(s, t) : wrap(s, t, -1, -1);\n }\n }\n}\n\nexport interface DependencyLinkParams extends PixelParams {\n tasks: GanttTask[];\n dependencies: TaskDependency[];\n}\n\n/**\n * The base geometry pass, plus the per-task boxes it was built from.\n *\n * Keeping the boxes is what makes a drag cheap: {@link reRouteOverrides} rebuilds\n * only the handful of links touching the dragged task instead of re-deriving all\n * of them (at 100k tasks / 84k links the full pass is ~100ms — far too slow to\n * repeat on every mousemove).\n */\nexport interface LinkGeometry {\n links: DependencyLink[];\n boxes: Map<Id, Box>;\n /**\n * Indices into `links` of every link touching a task, keyed by `String(id)` so\n * it can be queried straight from an overrides object's keys. Built on first\n * use — a chart that is never dragged never pays for it.\n */\n linksTouching(key: string): number[] | undefined;\n}\n\n/**\n * Compute the polyline geometry for every dependency, at each task's committed\n * position. Dependencies whose endpoints are not present in `tasks` are skipped.\n *\n * `lag` is intentionally not drawn: the gap it implies is already baked into\n * each task's scheduled dates, and therefore into the bar edges we connect.\n */\nexport function computeLinkGeometry({\n tasks,\n dependencies,\n ...params\n}: DependencyLinkParams): LinkGeometry {\n const boxes = buildBoxes(tasks, params);\n const links: DependencyLink[] = [];\n\n for (const dep of dependencies) {\n const from = boxes.get(dep.from);\n const to = boxes.get(dep.to);\n if (!from || !to) {\n continue;\n }\n links.push(linkOf(dep, from, to));\n }\n\n // Lazy, and owned by this result: the index is only worth building once a drag\n // starts re-routing, and it stays valid for exactly as long as `links` does.\n let byTask: Map<string, number[]> | null = null;\n return {\n links,\n boxes,\n linksTouching(key) {\n byTask ??= buildTouchIndex(links);\n return byTask.get(key);\n },\n };\n}\n\n/** One link between two known boxes. Bounds are baked in for viewport culling. */\nfunction linkOf(dep: TaskDependency, from: Box, to: Box): DependencyLink {\n // Bounds are computed here, not at render time: the renderer culls on every\n // scroll frame, and the geometry it culls against only changes when the\n // geometry itself is rebuilt.\n const points = routeLink(dep.type, from, to);\n return { id: `${dep.from}->${dep.to}`, type: dep.type, points, bounds: linkBounds(points), dep };\n}\n\n/** task key → indices of the links that start or end at it. */\nfunction buildTouchIndex(links: DependencyLink[]): Map<string, number[]> {\n const index = new Map<string, number[]>();\n const add = (key: string, i: number): void => {\n const list = index.get(key);\n if (list) {\n list.push(i);\n } else {\n index.set(key, [i]);\n }\n };\n links.forEach((link, i) => {\n add(String(link.dep.from), i);\n add(String(link.dep.to), i);\n });\n return index;\n}\n\n/**\n * Re-route only the links touching a task with a live drag override, reusing\n * every other link object from `base` untouched.\n *\n * This runs on every mousemove of a bar drag, so the work is bounded by the\n * dragged task's own edges, not the link count. Overrides are keyed by\n * `String(id)` because they arrive as an object literal, where a numeric `Id`\n * has already been stringified.\n */\nexport function reRouteOverrides(\n base: LinkGeometry,\n overrides: Record<string, Partial<TaskState>>,\n params: PixelParams,\n): DependencyLink[] {\n const keys = Object.keys(overrides);\n if (keys.length === 0) {\n return base.links;\n }\n const patched = new Map<Id, Box>();\n\n // Rebuild an overridden task's box on demand, keyed by its real `Id` — a drag\n // moves the bar horizontally only, so the row centre carries over.\n const boxFor = (id: Id): Box | undefined => {\n const box = base.boxes.get(id);\n const override = box && overrides[String(id)];\n if (!box || !override) {\n return box;\n }\n let next = patched.get(id);\n if (!next) {\n next = boxOf(box.task, override, box.centerY, params);\n patched.set(id, next);\n }\n return next;\n };\n\n let next: DependencyLink[] | null = null;\n for (const key of keys) {\n for (const i of base.linksTouching(key) ?? []) {\n const { dep } = base.links[i]!;\n const from = boxFor(dep.from);\n const to = boxFor(dep.to);\n if (!from || !to) {\n continue;\n }\n next ??= base.links.slice();\n next[i] = linkOf(dep, from, to);\n }\n }\n return next ?? base.links;\n}\n","import { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { CalendarUnit, GanttTask, TaskDependency, TaskState } from \"../../types\";\nimport { computeLinkGeometry, reRouteOverrides, type DependencyLink } from \"./geometry\";\n\nconst DependencyLinksContext = createContext<DependencyLink[] | null>(null);\n\ninterface DependencyLinksProviderProps {\n tasks: GanttTask[];\n dependencies: TaskDependency[];\n origin: Date;\n colWidth: number;\n rowHeight: number;\n unit: CalendarUnit;\n children: ReactNode;\n overrides: Record<string, Partial<TaskState>>;\n}\n\n/**\n * Computes dependency-link geometry once and exposes it to descendants. Keeping\n * the links in context lets the renderer (and any future consumers, e.g.\n * hover-highlighting) read them without re-deriving the geometry.\n *\n * Split in two on purpose. `overrides` churns on every mousemove of a bar drag,\n * while everything the base pass reads is stable for the whole gesture — so the\n * expensive pass (every task's box, every link's route) is kept off the drag\n * path, and each frame only re-routes the links touching the dragged bar.\n */\nexport function DependencyLinksProvider({\n tasks,\n dependencies,\n origin,\n colWidth,\n rowHeight,\n unit,\n children,\n overrides,\n}: DependencyLinksProviderProps) {\n const base = useMemo(\n () => computeLinkGeometry({ tasks, dependencies, origin, colWidth, rowHeight, unit }),\n [tasks, dependencies, origin, colWidth, rowHeight, unit],\n );\n\n const links = useMemo(\n () => reRouteOverrides(base, overrides, { origin, colWidth, rowHeight, unit }),\n [base, overrides, origin, colWidth, rowHeight, unit],\n );\n\n return (\n <DependencyLinksContext.Provider value={links}>{children}</DependencyLinksContext.Provider>\n );\n}\n\n/** Read the computed dependency links from context. */\nexport function useDependencyLinks(): DependencyLink[] {\n const links = useContext(DependencyLinksContext);\n if (links === null) {\n throw new Error(\"useDependencyLinks must be used within a <DependencyLinksProvider>\");\n }\n return links;\n}\n",".layer {\n position: absolute;\n inset: 0;\n z-index: var(--am-gantt-links-z-index, 2);\n pointer-events: none;\n}\n\n.hitArea {\n position: absolute;\n background: transparent;\n pointer-events: auto;\n cursor: pointer;\n}\n\n.segment {\n position: absolute;\n background: var(--am-gantt-dependency-color, #94a3b8);\n pointer-events: none;\n}\n\n.segmentSelected {\n background: #ef4444;\n}\n\n.arrowRight,\n.arrowLeft {\n position: absolute;\n width: 0;\n height: 0;\n border-top: 4px solid transparent;\n border-bottom: 4px solid transparent;\n pointer-events: none;\n}\n\n.arrowRight {\n border-left: 8px solid var(--am-gantt-dependency-color, #94a3b8);\n}\n\n.arrowLeft {\n border-right: 8px solid var(--am-gantt-dependency-color, #94a3b8);\n}\n\n.arrowSelected.arrowRight {\n border-left-color: #ef4444;\n}\n\n.arrowSelected.arrowLeft {\n border-right-color: #ef4444;\n}\n\n.lagLabel {\n position: absolute;\n background: var(--am-gantt-grid-bg, #ffffff);\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-radius: 3px;\n font-size: 11px;\n padding: 1px 4px;\n pointer-events: none;\n transform: translate(-50%, -100%);\n white-space: nowrap;\n color: var(--am-gantt-dependency-color, #94a3b8);\n line-height: 1.4;\n}\n\n.deleteBtn {\n position: absolute;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n border: 1px solid #ef4444;\n background: #fff;\n color: #ef4444;\n font-size: 16px;\n line-height: 1;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: auto;\n transform: translate(-50%, -50%);\n z-index: 10;\n padding: 0;\n}\n\n.deleteBtn:hover {\n background: #ef4444;\n color: #fff;\n}\n","import { Fragment, useEffect, useState, type ComponentProps, type ElementType } from \"react\";\nimport { useDependencyLinks } from \"./DependencyLinksContext\";\nimport { midpoint, type Bounds, type DependencyLink, type Point } from \"./geometry\";\nimport type { TaskDependency } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport { useGanttLabels, useGanttReadOnly } from \"../../context/contexts\";\nimport styles from \"./DependencyLinks.module.css\";\n\n/** Stroke thickness of the link, in pixels. */\nconst THICKNESS = 2;\n/** Side length of the arrowhead, in pixels. */\nconst ARROW = 8;\n/** Transparent hit-area padding around each segment, in pixels. */\nconst HIT_PADDING = 6;\n\n/** State passed to the function form of the `layer` slotProps. */\nexport interface DependencyLinksLayerOwnerState {\n width: number;\n height: number;\n /** Number of dependency links currently in the layer. */\n linkCount: number;\n}\n\n/** State shared by the per-link slots (`arrow`). */\nexport interface DependencyLinkOwnerState {\n /** The dependency link being rendered. */\n link: DependencyLink;\n /** Whether this link is currently selected. */\n isSelected: boolean;\n}\n\n/** State passed to the `segment` slotProps, per visible segment of a link. */\nexport interface DependencySegmentOwnerState extends DependencyLinkOwnerState {\n /** Start point of this segment. */\n from: Point;\n /** End point of this segment. */\n to: Point;\n /** Index of this segment within the link's polyline. */\n index: number;\n}\n\n/** State passed to the `lagLabel` slotProps. */\nexport interface DependencyLagLabelOwnerState extends DependencyLinkOwnerState {\n /** The lag value in days (non-zero when the label renders). */\n lag: number;\n}\n\n/** State passed to the `deleteButton` slotProps. */\nexport interface DependencyDeleteButtonOwnerState {\n /** The dependency the button will delete when clicked. */\n dependency: TaskDependency;\n}\n\nexport interface DependencyLinksSlots {\n /** The absolutely-positioned links layer container. Default: `\"div\"`. */\n layer?: ElementType;\n /** A single visible link segment. Default: `\"div\"`. */\n segment?: ElementType;\n /** The arrowhead at the target end of a link. Default: `\"div\"`. */\n arrow?: ElementType;\n /** The `+Nd` / `-Nd` lag label. Default: `\"div\"`. */\n lagLabel?: ElementType;\n /** The `×` delete button shown for the selected link. Default: `\"button\"`. */\n deleteButton?: ElementType;\n}\n\nexport interface DependencyLinksSlotProps {\n layer?: SlotPropsInput<ComponentProps<\"div\">, DependencyLinksLayerOwnerState>;\n segment?: SlotPropsInput<ComponentProps<\"div\">, DependencySegmentOwnerState>;\n arrow?: SlotPropsInput<ComponentProps<\"div\">, DependencyLinkOwnerState>;\n lagLabel?: SlotPropsInput<ComponentProps<\"div\">, DependencyLagLabelOwnerState>;\n deleteButton?: SlotPropsInput<ComponentProps<\"button\">, DependencyDeleteButtonOwnerState>;\n}\n\n/** Slot config for the dependency links layer. */\nexport type DependencyLinksSlotConfig = SlotConfig<DependencyLinksSlots, DependencyLinksSlotProps>;\n\ninterface DependencyLinksProps {\n width: number;\n height: number;\n onDependencyDelete?: (dep: TaskDependency) => void;\n /** Overscan-padded visible pixel rect; links outside it are not rendered. */\n visibleRect?: Bounds;\n slots?: DependencyLinksSlots;\n slotProps?: DependencyLinksSlotProps;\n}\n\n/** True when a link's bounding box overlaps the visible rect (or no rect set). */\nfunction linkInView(b: Bounds, rect: Bounds | undefined): boolean {\n if (!rect) {\n return true;\n }\n return b.minX <= rect.maxX && b.maxX >= rect.minX && b.minY <= rect.maxY && b.maxY >= rect.minY;\n}\n\n/** One straight segment as an absolutely-positioned box. */\nfunction segmentStyle(a: Point, b: Point): React.CSSProperties {\n if (a.y === b.y) {\n return {\n left: Math.min(a.x, b.x) - THICKNESS / 2,\n top: a.y - THICKNESS / 2,\n width: Math.abs(b.x - a.x) + THICKNESS,\n height: THICKNESS,\n };\n }\n return {\n left: a.x - THICKNESS / 2,\n top: Math.min(a.y, b.y) - THICKNESS / 2,\n width: THICKNESS,\n height: Math.abs(b.y - a.y) + THICKNESS,\n };\n}\n\n/** Wider transparent hit-area div for the same segment. */\nfunction hitAreaStyle(a: Point, b: Point): React.CSSProperties {\n if (a.y === b.y) {\n return {\n left: Math.min(a.x, b.x) - THICKNESS / 2,\n top: a.y - HIT_PADDING,\n width: Math.abs(b.x - a.x) + THICKNESS,\n height: THICKNESS + HIT_PADDING * 2,\n };\n }\n return {\n left: a.x - HIT_PADDING,\n top: Math.min(a.y, b.y) - THICKNESS / 2,\n width: THICKNESS + HIT_PADDING * 2,\n height: Math.abs(b.y - a.y) + THICKNESS,\n };\n}\n\nfunction segments(points: Point[]): Array<[Point, Point]> {\n const pairs: Array<[Point, Point]> = [];\n for (let i = 0; i + 1 < points.length; i++) {\n pairs.push([points[i]!, points[i + 1]!]);\n }\n return pairs;\n}\n\nfunction arrow(points: Point[]) {\n const tip = points[points.length - 1]!;\n const prev = points[points.length - 2]!;\n const pointsRight = tip.x >= prev.x;\n return {\n className: pointsRight ? styles.arrowRight : styles.arrowLeft,\n style: {\n left: pointsRight ? tip.x - ARROW : tip.x,\n top: tip.y - ARROW / 2,\n } as React.CSSProperties,\n };\n}\n\nexport function DependencyLinks({\n width,\n height,\n onDependencyDelete,\n visibleRect,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: DependencyLinksProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.dependencies?.links?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.dependencies?.links?.slotProps;\n const labels = useGanttLabels();\n // A read-only chart drops the hit areas, so no link can become selected —\n // which is also what keeps the Delete/Backspace shortcut below unreachable.\n const readOnly = useGanttReadOnly();\n\n const links = useDependencyLinks();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [deletePos, setDeletePos] = useState<{ x: number; y: number } | null>(null);\n\n const selectedLink = selectedId ? links.find((l) => l.id === selectedId) : null;\n\n useEffect(() => {\n if (!selectedId) {\n return;\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Delete\" || e.key === \"Backspace\") {\n if (selectedLink) {\n onDependencyDelete?.(selectedLink.dep);\n }\n setSelectedId(null);\n setDeletePos(null);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [selectedId, selectedLink, onDependencyDelete]);\n\n if (links.length === 0) {\n return null;\n }\n\n const handleLinkClick = (id: string, e: React.MouseEvent) => {\n e.stopPropagation();\n if (selectedId === id) {\n setSelectedId(null);\n setDeletePos(null);\n } else {\n setSelectedId(id);\n const layer = (e.currentTarget as HTMLElement).closest(`.${styles.layer}`);\n const rect = layer?.getBoundingClientRect();\n setDeletePos(rect ? { x: e.clientX - rect.left, y: e.clientY - rect.top } : null);\n }\n };\n\n const handleDelete = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (selectedLink) {\n onDependencyDelete?.(selectedLink.dep);\n }\n setSelectedId(null);\n setDeletePos(null);\n };\n\n const Layer = slots?.layer ?? \"div\";\n const Segment = slots?.segment ?? \"div\";\n const Arrow = slots?.arrow ?? \"div\";\n const LagLabel = slots?.lagLabel ?? \"div\";\n const DeleteButton = slots?.deleteButton ?? \"button\";\n const layerProps = mergeSlotProps(\n {\n className: styles.layer,\n style: { width, height },\n role: \"presentation\",\n \"aria-hidden\": true,\n onClick: () => {\n setSelectedId(null);\n setDeletePos(null);\n },\n },\n slotProps?.layer,\n { width, height, linkCount: links.length },\n );\n\n return (\n <Layer {...layerProps}>\n {links.map((link) => {\n const isSelected = link.id === selectedId;\n if (!isSelected && !linkInView(link.bounds, visibleRect)) {\n return null;\n }\n const head = arrow(link.points);\n const segs = segments(link.points);\n const mid = link.dep.lag ? midpoint(link.points) : null;\n const linkOwnerState: DependencyLinkOwnerState = { link, isSelected };\n\n const arrowProps = mergeSlotProps(\n {\n className: `${head.className} ${isSelected ? styles.arrowSelected : \"\"}`,\n style: head.style,\n },\n slotProps?.arrow,\n linkOwnerState,\n );\n\n return (\n <Fragment key={link.id}>\n {/* Transparent hit-area divs to capture clicks */}\n {!readOnly &&\n segs.map(([a, b]) => (\n <div\n key={`hit-${a.x},${a.y}-${b.x},${b.y}`}\n className={styles.hitArea}\n style={hitAreaStyle(a, b)}\n onClick={(e) => handleLinkClick(link.id, e)}\n />\n ))}\n {/* Visible segments */}\n {segs.map(([a, b], index) => {\n const segmentProps = mergeSlotProps(\n {\n className: `${styles.segment} ${isSelected ? styles.segmentSelected : \"\"}`,\n style: segmentStyle(a, b),\n },\n slotProps?.segment,\n { link, isSelected, from: a, to: b, index },\n );\n return <Segment key={`seg-${a.x},${a.y}-${b.x},${b.y}`} {...segmentProps} />;\n })}\n <Arrow {...arrowProps} />\n\n {/* Lag label */}\n {mid && link.dep.lag !== undefined && link.dep.lag !== 0 && (\n <LagLabel\n {...mergeSlotProps(\n {\n className: styles.lagLabel,\n style: { left: mid.x, top: mid.y },\n children: link.dep.lag > 0 ? `+${link.dep.lag}d` : `${link.dep.lag}d`,\n },\n slotProps?.lagLabel,\n { link, isSelected, lag: link.dep.lag },\n )}\n />\n )}\n </Fragment>\n );\n })}\n\n {!readOnly && selectedLink && deletePos && (\n <DeleteButton\n {...mergeSlotProps(\n {\n className: styles.deleteBtn,\n type: \"button\",\n tabIndex: -1,\n style: { left: deletePos.x, top: deletePos.y },\n onClick: handleDelete,\n \"aria-label\": labels.deleteDependency,\n children: \"×\",\n },\n slotProps?.deleteButton,\n { dependency: selectedLink.dep },\n )}\n />\n )}\n </Layer>\n );\n}\n",".preview {\n position: absolute;\n height: 2px;\n background: repeating-linear-gradient(\n to right,\n #3b82f6 0px,\n #3b82f6 6px,\n transparent 6px,\n transparent 12px\n );\n transform-origin: left center;\n pointer-events: none;\n z-index: 20;\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { useGanttDependencyDrag } from \"../../context/contexts\";\nimport type { DependencyDragState } from \"../../hooks/useDependencyDrag\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport styles from \"./DependencyPreview.module.css\";\n\n/** State passed to the function form of the `root` slotProps. */\nexport interface DependencyPreviewOwnerState {\n /** The in-progress dependency drag. */\n drag: DependencyDragState;\n /** Horizontal length of the rubber-band, in pixels. */\n length: number;\n /** Rotation of the rubber-band, in degrees. */\n angle: number;\n}\n\nexport interface DependencyPreviewSlots {\n /** The rubber-band preview line. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface DependencyPreviewSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, DependencyPreviewOwnerState>;\n}\n\n/** Slot config for the dependency drag preview. */\nexport type DependencyPreviewSlotConfig = SlotConfig<\n DependencyPreviewSlots,\n DependencyPreviewSlotProps\n>;\n\ninterface DependencyPreviewProps {\n slots?: DependencyPreviewSlots;\n slotProps?: DependencyPreviewSlotProps;\n}\n\nexport function DependencyPreview({\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: DependencyPreviewProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.dependencies?.preview?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.dependencies?.preview?.slotProps;\n\n const drag = useGanttDependencyDrag();\n if (!drag) {\n return null;\n }\n\n const dx = drag.currentX - drag.startX;\n const dy = drag.currentY - drag.startY;\n const length = Math.hypot(dx, dy);\n const angle = Math.atan2(dy, dx) * (180 / Math.PI);\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.preview,\n style: {\n left: drag.startX,\n top: drag.startY,\n width: length,\n transform: `rotate(${angle}deg)`,\n },\n \"aria-hidden\": true,\n },\n slotProps?.root,\n { drag, length, angle },\n );\n\n return <Root {...rootProps} />;\n}\n",".cols {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n.col {\n position: absolute;\n top: 0;\n box-sizing: border-box;\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n}\n\n.colWeekend {\n background: var(--am-gantt-calendar-weekend-bg, #f1f5f9);\n}\n","import { clsx } from \"clsx\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { addUnit, isWeekend } from \"../../core/dateUtils\";\nimport { nonWorkingInfo, type NonWorkingReason } from \"../../core/workingTime\";\nimport { useGanttWorkCalendar } from \"../../context/contexts\";\nimport type { CalendarUnit } from \"../../types\";\nimport type { IndexRange } from \"../../core/virtualize\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport styles from \"./GridColumns.module.css\";\n\n/** State passed to the function form of the GridColumns `column` slotProps (per day). */\nexport interface GridColumnOwnerState {\n /** The day this column paints. */\n date: Date;\n /** Absolute date-column index. */\n index: number;\n /**\n * Whether the calendar excludes this column from working time. Prefer this over\n * {@link GridColumnOwnerState.isWeekend} — it also covers holidays and, at hour\n * scale, off-hours.\n */\n isNonWorking: boolean;\n /** Why the column is non-working, for styling weekends and holidays apart. */\n nonWorkingReason?: NonWorkingReason;\n /**\n * @deprecated Use {@link GridColumnOwnerState.isNonWorking}. Retained as an\n * alias so existing slot code keeps working; it is now true for any\n * non-working column, not only Saturday and Sunday.\n */\n isWeekend: boolean;\n colWidth: number;\n bodyHeight: number;\n}\n\nexport interface GridColumnsSlots {\n /** A per-day background column. Default: `\"div\"`. */\n column?: ElementType;\n}\n\nexport interface GridColumnsSlotProps {\n column?: SlotPropsInput<ComponentProps<\"div\">, GridColumnOwnerState>;\n}\n\n/**\n * Slot config for the grid background columns. Pass via the grid's slot props.\n *\n * NOTE: pass a referentially stable / memoized object so downstream memoization\n * is not defeated by a fresh object each render.\n */\nexport type GridColumnsSlotConfig = SlotConfig<GridColumnsSlots, GridColumnsSlotProps>;\n\ninterface GridColumnsProps {\n dates: Date[];\n colWidth: number;\n bodyHeight: number;\n /** Half-open range of date indices to render (virtualization window). */\n colRange: IndexRange;\n /** Column unit. Non-working shading only applies at day scale or finer. */\n unit?: CalendarUnit;\n /** Units per column, so a column's full time span can be measured. */\n step?: number;\n slots?: GridColumnsSlots;\n slotProps?: GridColumnsSlotProps;\n}\n\n/**\n * Background layer that paints one vertical column per day, shading weekends.\n * Purely decorative — `aria-hidden` and non-interactive. Only the columns\n * inside `colRange` are rendered; each is absolutely positioned at its date\n * offset so the windowed subset still aligns with the full-width grid.\n */\nexport function GridColumns({\n dates,\n colWidth,\n bodyHeight,\n colRange,\n unit = \"day\",\n step = 1,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: GridColumnsProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.gridColumn?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.gridColumn?.slotProps;\n\n const Column = slots?.column ?? \"div\";\n const { calendar } = useGanttWorkCalendar();\n // Shading is meaningless on a week-or-coarser column: it is partly working by\n // construction, so painting the whole thing would be wrong.\n const shadeable = unit === \"day\" || unit === \"hour\" || unit === \"minute\";\n\n return (\n <div className={styles.cols} role=\"presentation\" aria-hidden>\n {dates.slice(colRange.start, colRange.end).map((date, i) => {\n const index = colRange.start + i;\n const info = shadeable\n ? nonWorkingInfo(calendar, date, addUnit(date, unit, step))\n : { isNonWorking: false, reason: undefined };\n // With no calendar, keep the historical Sat/Sun-only behaviour exactly.\n const nonWorking = calendar ? info.isNonWorking : unit === \"day\" && isWeekend(date);\n const ownerState: GridColumnOwnerState = {\n date,\n index,\n isNonWorking: nonWorking,\n nonWorkingReason: nonWorking ? (info.reason ?? \"weekend\") : undefined,\n isWeekend: nonWorking,\n colWidth,\n bodyHeight,\n };\n const columnProps = mergeSlotProps(\n {\n className: clsx(styles.col, nonWorking && styles.colWeekend),\n style: {\n left: index * colWidth,\n width: colWidth,\n height: bodyHeight,\n },\n },\n slotProps?.column,\n ownerState,\n );\n // Keyed by instant, not ISO string: the dates are distinct by\n // construction and this runs for every column on every scroll frame.\n return <Column key={date.getTime()} {...columnProps} />;\n })}\n </div>\n );\n}\n\nGridColumns.displayName = \"GridColumns\";\n",".gridWrapper {\n overflow-x: auto;\n overflow-y: auto;\n flex: 1 1 auto;\n min-width: 0;\n /* No rubber-band bounce / scroll chaining to the page (macOS, iOS). */\n overscroll-behavior: none;\n}\n\n.grid {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: inherit;\n}\n\n.body {\n position: relative;\n background: var(--am-gantt-grid-bg, #ffffff);\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-top: none;\n border-bottom-left-radius: var(--am-gantt-calendar-radius, 6px);\n border-bottom-right-radius: var(--am-gantt-calendar-radius, 6px);\n overflow: hidden;\n box-sizing: border-box;\n}\n","/**\n * Framework-agnostic windowing math for virtualized rendering. Given a scroll\n * `offset`, a `viewSize` (viewport extent), a fixed `itemSize`, and a total\n * `itemCount`, return the half-open index range `[start, end)` of items that\n * intersect the viewport, widened by `overscan` items on each side.\n *\n * Works for either axis (rows: pass scrollTop/clientHeight/rowHeight, or\n * columns: scrollLeft/clientWidth/colWidth). Pure — no DOM or framework\n * dependency. Mirrors the shape of `scrollOffsetToReveal` in `scroll.ts`.\n *\n * When `viewSize <= 0` the viewport hasn't been measured yet (first commit),\n * so we render a bounded window of the first `UNMEASURED_FALLBACK_COUNT`\n * items. Rendering everything here would make mounting a large dataset pay a\n * full unvirtualized commit (10k tasks ≈ tens of seconds) that is thrown away\n * one frame later; rendering the capped window is never visible as a flash,\n * because the real metrics arrive via `useLayoutEffect` and re-render before\n * the browser paints. The cap also keeps jsdom (client sizes always 0)\n * rendering enough rows for component tests. `itemSize <= 0` is treated the\n * same way.\n */\nimport { UNMEASURED_FALLBACK_COUNT } from \"./constants\";\n\nexport interface IndexRange {\n /** First visible item index (inclusive). */\n start: number;\n /** One past the last visible item index (exclusive). */\n end: number;\n}\n\nexport function rangeFromOffset(\n offset: number,\n viewSize: number,\n itemSize: number,\n itemCount: number,\n overscan = 0,\n): IndexRange {\n if (itemCount <= 0) {\n return { start: 0, end: 0 };\n }\n if (viewSize <= 0 || itemSize <= 0) {\n return { start: 0, end: Math.min(itemCount, UNMEASURED_FALLBACK_COUNT) };\n }\n\n const firstVisible = Math.floor(offset / itemSize);\n const lastVisible = Math.ceil((offset + viewSize) / itemSize);\n\n const start = Math.max(0, firstVisible - overscan);\n const end = Math.min(itemCount, lastVisible + overscan);\n\n return { start, end };\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { buildTimelineDates } from \"../../core/timeline\";\nimport { DEFAULT_SCALES, resolveColumnStep, resolveColumnUnit } from \"../../core/scales\";\nimport type { GanttTask, Id, Overrides, TaskState } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport { Calendar } from \"../calendar/Calendar\";\nimport { Row } from \"../bars/common/Row\";\nimport { DependencyLinksProvider } from \"../dependency-links/DependencyLinksContext\";\nimport { DependencyLinks } from \"../dependency-links/DependencyLinks\";\nimport { DependencyPreview } from \"../dependency-links/DependencyPreview\";\nimport { GridColumns } from \"./GridColumns\";\nimport styles from \"./Grid.module.css\";\nimport { rangeFromOffset } from \"../../core/virtualize\";\nimport { COL_OVERSCAN, ROW_OVERSCAN } from \"../../core/constants\";\nimport {\n useGanttConfig,\n useGanttDependency,\n useGanttLabels,\n useGanttScroll,\n useGanttTaskActions,\n useGanttTaskState,\n useGanttViewport,\n useGanttZoom,\n} from \"../../context/contexts\";\n\n/** State passed to the function form of the Grid slotProps. */\nexport interface GridOwnerState {\n /** Total content width in px (`dates.length * colWidth`). */\n totalWidth: number;\n /** Total body height in px (`visibleTasks.length * rowHeight`). */\n bodyHeight: number;\n /** Fixed grid-wrapper height when configured, else `undefined` (auto). */\n height: number | undefined;\n}\n\nexport interface GridSlots {\n /** The scroll wrapper (`styles.gridWrapper`). Default: `\"div\"`. */\n root?: ElementType;\n /** The scrollable body layer (`styles.body`). Default: `\"div\"`. */\n body?: ElementType;\n}\n\nexport interface GridSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, GridOwnerState>;\n body?: SlotPropsInput<ComponentProps<\"div\">, GridOwnerState>;\n}\n\n/**\n * Slot config for the Gantt grid. Threaded from `<Gantt>` in a later pass.\n *\n * NOTE: pass a referentially stable / memoized object so downstream memoization\n * is not defeated by a fresh object each render.\n */\nexport type GridSlotConfig = SlotConfig<GridSlots, GridSlotProps>;\n\ninterface GanttGridProps {\n slots?: GridSlots;\n slotProps?: GridSlotProps;\n}\n\nexport function GanttGrid({ slots: slotsProp, slotProps: slotPropsProp }: GanttGridProps = {}) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.grid?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.grid?.slotProps;\n\n const { visibleTasks } = useGanttTaskState();\n const { updateTask, commitTask, onTaskClick, setSelectedId } = useGanttTaskActions();\n const { colWidth, rowHeight, scales, padDays, height } = useGanttConfig();\n const labels = useGanttLabels();\n const { gridRef, onGridScroll, gridBodyRef } = useGanttScroll();\n const viewport = useGanttViewport();\n const { dependencies, onDependencyDelete } = useGanttDependency();\n const { zoomAt, zoomIn, zoomOut, wheelEnabled, keyboardEnabled } = useGanttZoom();\n\n useEffect(() => {\n const grid = gridRef.current;\n if (!grid || (!wheelEnabled && !keyboardEnabled)) {\n return;\n }\n const onWheel = (e: WheelEvent) => {\n if (!(e.ctrlKey || e.metaKey)) {\n return;\n }\n e.preventDefault();\n const rect = grid.getBoundingClientRect();\n const focusPx = grid.scrollLeft + (e.clientX - rect.left);\n zoomAt(focusPx, e.deltaY < 0 ? 1 : -1);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"+\" || e.key === \"=\") {\n e.preventDefault();\n zoomIn();\n } else if (e.key === \"-\" || e.key === \"_\") {\n e.preventDefault();\n zoomOut();\n }\n };\n if (wheelEnabled) {\n grid.addEventListener(\"wheel\", onWheel, { passive: false });\n }\n if (keyboardEnabled) {\n grid.tabIndex = 0;\n grid.addEventListener(\"keydown\", onKeyDown);\n }\n return () => {\n grid.removeEventListener(\"wheel\", onWheel);\n grid.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [gridRef, wheelEnabled, keyboardEnabled, zoomAt, zoomIn, zoomOut, visibleTasks.length]);\n\n const [overrides, setOverrides] = useState<Overrides>({});\n\n const handleSelect = useCallback(\n (task: GanttTask) => {\n setSelectedId(task.id);\n onTaskClick?.(task);\n },\n [setSelectedId, onTaskClick],\n );\n\n const handleOverride = useCallback((id: Id, patch: Partial<TaskState> | null) => {\n setOverrides((prev) => {\n if (patch === null) {\n const { [id]: _, ...rest } = prev;\n return rest;\n }\n return { ...prev, [id]: { ...prev[id], ...patch } };\n });\n }, []);\n\n const dates = useMemo(\n () => buildTimelineDates(visibleTasks, padDays, scales),\n [visibleTasks, padDays, scales],\n );\n\n const originMs = dates[0]?.getTime();\n const origin = useMemo(() => (originMs == null ? undefined : new Date(originMs)), [originMs]);\n if (!origin) {\n return null;\n }\n\n const unit = resolveColumnUnit(scales);\n const totalWidth = dates.length * colWidth;\n const bodyHeight = visibleTasks.length * rowHeight;\n\n const resolvedScales = scales ?? DEFAULT_SCALES;\n const headerRowCount = resolvedScales.length;\n\n const rowRange = rangeFromOffset(\n viewport.scrollTop,\n viewport.clientHeight,\n rowHeight,\n visibleTasks.length,\n ROW_OVERSCAN,\n );\n const colRange = rangeFromOffset(\n viewport.scrollLeft,\n viewport.clientWidth,\n colWidth,\n dates.length,\n COL_OVERSCAN,\n );\n\n // Overscan-padded visible pixel rect, reused to cull dependency links. The\n // ranges already include overscan and are clamped to the content bounds.\n const visibleRect = {\n minX: colRange.start * colWidth,\n maxX: colRange.end * colWidth,\n minY: rowRange.start * rowHeight,\n maxY: rowRange.end * rowHeight,\n };\n\n const Root = slots?.root ?? \"div\";\n const Body = slots?.body ?? \"div\";\n\n const ownerState: GridOwnerState = { totalWidth, bodyHeight, height };\n\n const rootProps = mergeSlotProps(\n {\n className: styles.gridWrapper,\n style: height !== undefined ? { height } : {},\n onScroll: onGridScroll,\n role: \"grid\",\n \"aria-label\": labels.timeline,\n \"aria-rowcount\": headerRowCount + visibleTasks.length,\n \"aria-colcount\": dates.length,\n },\n slotProps?.root,\n ownerState,\n );\n\n const bodyProps = mergeSlotProps(\n {\n className: styles.body,\n style: { height: bodyHeight, width: totalWidth },\n role: \"rowgroup\",\n },\n slotProps?.body,\n ownerState,\n );\n\n return (\n <Root ref={gridRef} {...rootProps}>\n <div className={styles.grid} style={{ width: totalWidth }} role=\"presentation\">\n <Calendar\n colWidth={colWidth}\n rowHeight={rowHeight}\n dates={dates}\n scales={scales}\n colRange={colRange}\n />\n <DependencyLinksProvider\n tasks={visibleTasks}\n dependencies={dependencies}\n origin={origin}\n colWidth={colWidth}\n rowHeight={rowHeight}\n unit={unit}\n overrides={overrides}\n >\n <Body ref={gridBodyRef} {...bodyProps}>\n <GridColumns\n dates={dates}\n colWidth={colWidth}\n bodyHeight={bodyHeight}\n colRange={colRange}\n unit={unit}\n step={resolveColumnStep(scales)}\n />\n <DependencyLinks\n width={totalWidth}\n height={bodyHeight}\n onDependencyDelete={onDependencyDelete}\n visibleRect={visibleRect}\n />\n <DependencyPreview />\n\n {visibleTasks.slice(rowRange.start, rowRange.end).map((task, i) => {\n const index = rowRange.start + i;\n return (\n <Row\n key={task.id}\n task={task}\n index={index}\n origin={origin}\n colWidth={colWidth}\n rowHeight={rowHeight}\n unit={unit}\n onUpdate={updateTask}\n onCommit={commitTask}\n override={overrides[task.id]}\n onOverride={handleOverride}\n onTaskClick={handleSelect}\n rowIndexOffset={headerRowCount}\n />\n );\n })}\n </Body>\n </DependencyLinksProvider>\n </div>\n </Root>\n );\n}\n\nGanttGrid.displayName = \"GanttGrid\";\n",".handle {\n width: 4px;\n align-self: stretch;\n cursor: col-resize;\n background: var(--am-gantt-calendar-border, #e2e8f0);\n flex-shrink: 0;\n user-select: none;\n transition: background 0.15s;\n}\n\n.handle:hover {\n background: var(--am-gantt-dependency-color, #94a3b8);\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport { useGanttLabels } from \"../../context/contexts\";\nimport styles from \"./GridResizeHandle.module.css\";\n\n/** State passed to the function form of the GridResizeHandle slotProps. */\nexport interface GridResizeHandleOwnerState {\n /** Whether a resize drag is currently in progress. */\n isResizing: boolean;\n}\n\nexport interface GridResizeHandleSlots {\n /** The pane splitter element. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface GridResizeHandleSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, GridResizeHandleOwnerState>;\n}\n\nexport type GridResizeHandleSlotConfig = SlotConfig<\n GridResizeHandleSlots,\n GridResizeHandleSlotProps\n>;\n\ninterface GridResizeHandleProps {\n onMouseDown: React.MouseEventHandler;\n isResizing?: boolean;\n slots?: GridResizeHandleSlots;\n slotProps?: GridResizeHandleSlotProps;\n}\n\nexport function GridResizeHandle({\n onMouseDown,\n isResizing = false,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: GridResizeHandleProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.gridResizeHandle?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.gridResizeHandle?.slotProps;\n\n const labels = useGanttLabels();\n const ownerState: GridResizeHandleOwnerState = { isResizing };\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.handle,\n onMouseDown,\n role: \"separator\",\n \"aria-orientation\": \"vertical\" as const,\n \"aria-label\": labels.resizeTaskList,\n },\n slotProps?.root,\n ownerState,\n );\n\n return <Root {...rootProps} />;\n}\n",".taskList {\n display: flex;\n flex-direction: column;\n font-family: inherit;\n background: var(--am-gantt-tasklist-bg, #ffffff);\n flex-shrink: 0;\n width: max-content;\n}\n\n.header {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n background: var(--am-gantt-calendar-header-bg, #f8fafc);\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-radius: var(--am-gantt-calendar-radius, 6px) var(--am-gantt-calendar-radius, 6px) 0 0;\n box-sizing: border-box;\n overflow: hidden;\n user-select: none;\n}\n\n.headerCell {\n position: relative;\n display: flex;\n align-items: center;\n padding: 0 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--am-gantt-calendar-header-color, #475569);\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n box-sizing: border-box;\n}\n\n.headerCell:last-child {\n border-right: none;\n}\n\n.body {\n position: relative;\n overflow-y: auto;\n overflow-x: hidden;\n /* No rubber-band bounce / scroll chaining to the page (macOS, iOS). */\n overscroll-behavior: none;\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-top: none;\n border-radius: 0 0 var(--am-gantt-calendar-radius, 6px) var(--am-gantt-calendar-radius, 6px);\n background: var(--am-gantt-tasklist-bg, #ffffff);\n box-sizing: border-box;\n}\n\n.rows {\n position: relative;\n}\n\n.row {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n border-bottom: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n box-sizing: border-box;\n}\n\n.row:last-child {\n border-bottom: none;\n}\n\n.row.selected {\n background: var(--am-gantt-row-selected-bg, #e0f2fe);\n}\n\n.cell {\n display: flex;\n align-items: center;\n padding: 0 8px;\n font-size: 13px;\n color: var(--am-gantt-tasklist-color, #334155);\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n box-sizing: border-box;\n}\n\n.cell:last-child {\n border-right: none;\n}\n\n.treeCell {\n overflow: hidden;\n}\n\n.nameContent {\n display: flex;\n align-items: center;\n gap: 4px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.expandBtn {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-size: 10px;\n color: var(--am-gantt-tasklist-color, #334155);\n width: 14px;\n flex-shrink: 0;\n line-height: 1;\n}\n\n.expandBtn:focus-visible {\n outline: var(--am-gantt-focus-ring-width, 2px) solid var(--am-gantt-focus-ring-color, #1d4ed8);\n outline-offset: var(--am-gantt-focus-ring-offset, -2px);\n border-radius: 2px;\n}\n\n.expandPlaceholder {\n display: inline-block;\n width: 14px;\n flex-shrink: 0;\n}\n\n.divider {\n position: absolute;\n top: 0;\n right: 0;\n width: 5px;\n height: 100%;\n cursor: col-resize;\n user-select: none;\n}\n\n.divider:hover {\n background: var(--am-gantt-dependency-color, #94a3b8);\n}\n","import type React from \"react\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport type { ColumnDef, Scale } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport styles from \"./TaskList.module.css\";\nimport { DEFAULT_SCALES } from \"../../core/scales\";\n\n/** State passed to the function form of the header (container) slotProps. */\nexport interface TaskListHeaderOwnerState {\n columns: ColumnDef[];\n headerHeight: number;\n}\n\n/** State passed to the function form of the per-column slotProps. */\nexport interface TaskListHeaderCellOwnerState {\n column: ColumnDef;\n index: number;\n}\n\nexport interface TaskListHeaderSlots {\n /** The header row container. Default: `\"div\"`. */\n header?: ElementType;\n /** A per-column header cell. Default: `\"div\"`. */\n headerCell?: ElementType;\n /** The per-column resize handle (divider). Default: `\"div\"`. */\n columnResizeHandle?: ElementType;\n}\n\nexport interface TaskListHeaderSlotProps {\n header?: SlotPropsInput<ComponentProps<\"div\">, TaskListHeaderOwnerState>;\n headerCell?: SlotPropsInput<ComponentProps<\"div\">, TaskListHeaderCellOwnerState>;\n columnResizeHandle?: SlotPropsInput<ComponentProps<\"div\">, TaskListHeaderCellOwnerState>;\n}\n\nexport type TaskListHeaderSlotConfig = SlotConfig<TaskListHeaderSlots, TaskListHeaderSlotProps>;\n\ninterface TaskListHeaderProps {\n columns: ColumnDef[];\n rowHeight: number;\n scales?: Scale[];\n onResizeStart: (key: string, startWidth: number, e: React.MouseEvent) => void;\n slots?: TaskListHeaderSlots;\n slotProps?: TaskListHeaderSlotProps;\n}\n\nexport function TaskListHeader({\n columns,\n rowHeight,\n scales = DEFAULT_SCALES,\n onResizeStart,\n slots,\n slotProps,\n}: TaskListHeaderProps) {\n // Height tracks the calendar: one row per scale, +2 for its 1px top/bottom\n // borders. Both default to the shared DEFAULT_SCALES so the counts can't drift.\n const headerHeight = scales.length * rowHeight + 2;\n\n const Header = slots?.header ?? \"div\";\n const HeaderCell = slots?.headerCell ?? \"div\";\n const ColumnResizeHandle = slots?.columnResizeHandle ?? \"div\";\n\n // Row 1 of the enclosing treegrid.\n const headerProps = mergeSlotProps(\n {\n className: styles.header,\n style: { minHeight: headerHeight, height: headerHeight },\n role: \"row\",\n \"aria-rowindex\": 1,\n },\n slotProps?.header,\n { columns, headerHeight },\n );\n\n return (\n <Header {...headerProps}>\n {columns.map((col, index) => {\n const cellOwnerState: TaskListHeaderCellOwnerState = { column: col, index };\n\n const headerCellProps = mergeSlotProps(\n {\n className: styles.headerCell,\n style: col.width\n ? { width: col.width, flexShrink: 0 }\n : { flex: \"1 1 auto\", minWidth: 100 },\n role: \"columnheader\",\n \"aria-colindex\": index + 1,\n },\n slotProps?.headerCell,\n cellOwnerState,\n );\n\n const resizeHandleProps = mergeSlotProps(\n {\n className: styles.divider,\n \"aria-hidden\": true,\n onMouseDown: (e: React.MouseEvent) => {\n // Read the rendered width from the DOM so flex (no explicit width)\n // columns snap cleanly to a fixed width on first drag.\n const cell = e.currentTarget.parentElement as HTMLElement;\n onResizeStart(col.key, cell.offsetWidth, e);\n },\n },\n slotProps?.columnResizeHandle,\n cellOwnerState,\n );\n\n return (\n <HeaderCell key={col.key} {...headerCellProps}>\n {col.header}\n <ColumnResizeHandle {...resizeHandleProps} />\n </HeaderCell>\n );\n })}\n </Header>\n );\n}\n","import type { ComponentProps, ElementType, ReactNode } from \"react\";\nimport type { Id } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttLabels } from \"../../context/contexts\";\nimport styles from \"./TaskList.module.css\";\n\nconst INDENT_PX = 16;\n\n/** State passed to the function form of each TreeCell slotProps. */\nexport interface TreeCellOwnerState {\n taskId: Id;\n depth: number;\n isParent: boolean;\n isExpanded: boolean;\n}\n\nexport interface TreeCellSlots {\n /** The `nameContent` wrapper. Default: `\"span\"`. */\n root?: ElementType;\n /** The ▾/▸ expand/collapse toggle. Default: `\"button\"`. */\n expandButton?: ElementType;\n /** The spacer rendered for leaf (non-parent) rows. Default: `\"span\"`. */\n placeholder?: ElementType;\n}\n\nexport interface TreeCellSlotProps {\n root?: SlotPropsInput<ComponentProps<\"span\">, TreeCellOwnerState>;\n expandButton?: SlotPropsInput<ComponentProps<\"button\">, TreeCellOwnerState>;\n placeholder?: SlotPropsInput<ComponentProps<\"span\">, TreeCellOwnerState>;\n}\n\n/**\n * Slot config for the tree cell. Pass via `<Gantt treeCell={...} />`.\n *\n * NOTE: pass a referentially stable / memoized object — `TaskListRow` is memoized,\n * so a fresh object each render defeats its memo and re-renders every row.\n */\nexport type TreeCellSlotConfig = SlotConfig<TreeCellSlots, TreeCellSlotProps>;\n\ninterface TreeCellProps {\n taskId: Id;\n depth: number;\n isParent: boolean;\n isExpanded: boolean;\n onToggleExpand: (id: Id) => void;\n children: ReactNode;\n slots?: TreeCellSlots;\n slotProps?: TreeCellSlotProps;\n}\n\nexport function TreeCell({\n taskId,\n depth,\n isParent,\n isExpanded,\n onToggleExpand,\n children,\n slots,\n slotProps,\n}: TreeCellProps) {\n const labels = useGanttLabels();\n const ownerState: TreeCellOwnerState = { taskId, depth, isParent, isExpanded };\n\n const Root = slots?.root ?? \"span\";\n const ExpandButton = slots?.expandButton ?? \"button\";\n const Placeholder = slots?.placeholder ?? \"span\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.nameContent,\n style: { paddingLeft: depth * INDENT_PX },\n },\n slotProps?.root,\n ownerState,\n );\n\n const buttonProps = mergeSlotProps(\n {\n className: styles.expandBtn,\n type: \"button\",\n onClick: (e: React.MouseEvent) => {\n e.stopPropagation();\n onToggleExpand(taskId);\n },\n \"aria-label\": isExpanded ? labels.collapse : labels.expand,\n children: isExpanded ? \"▾\" : \"▸\",\n },\n slotProps?.expandButton,\n ownerState,\n );\n\n const placeholderProps = mergeSlotProps(\n { className: styles.expandPlaceholder, \"aria-hidden\": true },\n slotProps?.placeholder,\n ownerState,\n );\n\n return (\n <Root {...rootProps}>\n {isParent ? <ExpandButton {...buttonProps} /> : <Placeholder {...placeholderProps} />}\n {children}\n </Root>\n );\n}\n","import { memo } from \"react\";\nimport type { ColumnDef, GanttTask, Id } from \"../../types\";\nimport { useGanttTaskActions } from \"../../context/contexts\";\nimport { TreeCell, type TreeCellSlotConfig } from \"./TreeCell\";\nimport styles from \"./TaskList.module.css\";\n\ninterface TaskListRowProps {\n task: GanttTask;\n rowHeight: number;\n rowIndex: number;\n depth: number;\n posinset: number;\n setsize: number;\n isParent: boolean;\n isExpanded: boolean;\n isSelected: boolean;\n onToggleExpand: (id: Id) => void;\n onSelect: (id: Id) => void;\n columns: ColumnDef[];\n treeCell?: TreeCellSlotConfig;\n}\n\nconst DEFAULT_COL_WIDTH = 100;\n\nexport const TaskListRow = memo(function TaskListRow({\n task,\n rowHeight,\n rowIndex,\n depth,\n posinset,\n setsize,\n isParent,\n isExpanded,\n isSelected,\n onToggleExpand,\n onSelect,\n columns,\n treeCell,\n}: TaskListRowProps) {\n const { columnApi } = useGanttTaskActions();\n return (\n <div\n className={`${styles.row} ${isSelected ? styles.selected : \"\"}`}\n style={{ height: rowHeight }}\n onClick={() => onSelect(task.id)}\n role=\"row\"\n aria-rowindex={rowIndex + 2}\n aria-level={depth + 1}\n aria-posinset={posinset}\n aria-setsize={setsize}\n aria-expanded={isParent ? isExpanded : undefined}\n aria-selected={isSelected || undefined}\n >\n {columns.map((col, index) => {\n return (\n <div\n key={col.key}\n className={`${styles.cell} ${col.isTreeColumn ? styles.treeCell : \"\"}`}\n style={{ width: col.width || DEFAULT_COL_WIDTH, flexShrink: 0 }}\n role={col.isTreeColumn ? \"rowheader\" : \"gridcell\"}\n aria-colindex={index + 1}\n >\n {col.isTreeColumn ? (\n <TreeCell\n taskId={task.id}\n depth={depth}\n isParent={isParent}\n isExpanded={isExpanded}\n onToggleExpand={onToggleExpand}\n slots={treeCell?.slots}\n slotProps={treeCell?.slotProps}\n >\n {col.render(task, columnApi)}\n </TreeCell>\n ) : (\n col.render(task, columnApi)\n )}\n </div>\n );\n })}\n </div>\n );\n});\n\nTaskListRow.displayName = \"TaskListRow\";\n","import { useCallback, useRef, useState } from \"react\";\nimport { COLUMN_MIN_WIDTH } from \"../core/constants\";\n\n/**\n * Session-local column-width overrides, keyed by `col.key`. Mirrors\n * `useGridResize`: mousedown captures the start width, window listeners track\n * the drag, and the width clamps at `COLUMN_MIN_WIDTH`.\n */\nexport function useColumnWidths() {\n const [widths, setWidths] = useState<Record<string, number>>({});\n const startRef = useRef<{ key: string; mouseX: number; width: number } | null>(null);\n\n const onResizeStart = useCallback((key: string, startWidth: number, e: React.MouseEvent) => {\n e.preventDefault();\n startRef.current = { key, mouseX: e.clientX, width: startWidth };\n\n const onMove = (ev: MouseEvent) => {\n if (!startRef.current) {\n return;\n }\n const { key: colKey, mouseX, width } = startRef.current;\n const next = Math.max(COLUMN_MIN_WIDTH, width + (ev.clientX - mouseX));\n setWidths((prev) => ({ ...prev, [colKey]: next }));\n };\n\n const onUp = () => {\n startRef.current = null;\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n };\n\n window.addEventListener(\"mousemove\", onMove);\n window.addEventListener(\"mouseup\", onUp);\n }, []);\n\n return { widths, onResizeStart };\n}\n","import { useCallback, useMemo } from \"react\";\nimport {\n useGanttConfig,\n useGanttLabels,\n useGanttScroll,\n useGanttSelectedId,\n useGanttTaskActions,\n useGanttTaskState,\n} from \"../../context/contexts\";\nimport type { ColumnDef, Id } from \"../../types\";\nimport { TaskListHeader } from \"./TaskListHeader\";\nimport { TaskListRow } from \"./TaskListRow\";\nimport type { GanttTaskListSlots } from \"../../context/GanttSlotsContext\";\nimport { rangeFromOffset } from \"../../core/virtualize\";\nimport { ROW_OVERSCAN } from \"../../core/constants\";\nimport { useColumnWidths } from \"../../hooks/useColumnWidths\";\nimport { useLatestRef } from \"../../hooks/useLatestRef\";\nimport { useViewportMeasure } from \"../../hooks/useViewportMeasure\";\nimport styles from \"./TaskList.module.css\";\n\n/** Static, so it is hoisted out of the render path rather than re-allocated. */\nconst BODY_STYLE = { flex: \"1 1 auto\", minHeight: 0 } as const;\n\ninterface TaskListProps {\n columns?: ColumnDef[];\n /** Slot overrides for the task-list pane (`treeCell`, `header`). Pass a stable object. */\n taskList?: GanttTaskListSlots;\n}\n\nexport function TaskList({ columns = [], taskList }: TaskListProps) {\n const { visibleTasks, expandedIds, parentIds } = useGanttTaskState();\n const { toggleExpand, setSelectedId, onTaskClick, revealTask } = useGanttTaskActions();\n const selectedId = useGanttSelectedId();\n const { rowHeight, scales, height } = useGanttConfig();\n const labels = useGanttLabels();\n const { taskListRef, onTaskListScroll } = useGanttScroll();\n\n const { widths, onResizeStart } = useColumnWidths();\n\n // Overlay the session-local resize widths onto the incoming columns. Both the\n // header and rows render this same array, so they stay aligned by construction.\n const resolvedColumns = useMemo(\n () =>\n columns.map((col) => (widths[col.key] != null ? { ...col, width: widths[col.key] } : col)),\n [columns, widths],\n );\n\n // Dispatched through a latest-ref so `handleSelect` is identity-stable\n // forever: it is handed to every memoized row, and closing over `visibleTasks`\n // directly would re-render the whole window on every edit, expand or zoom.\n // (Same pattern as `useRevealTask`.)\n const selectRef = useLatestRef((id: Id) => {\n setSelectedId(id);\n\n const task = visibleTasks.find((t) => t.id === id);\n if (task) {\n onTaskClick?.(task);\n // Horizontal only: clicking a row must not also scroll it vertically, since\n // the row the user just clicked is by definition already on screen.\n revealTask(id, { horizontal: true, vertical: false });\n }\n });\n const handleSelect = useCallback((id: Id) => selectRef.current(id), [selectRef]);\n\n const depthMap = useMemo(() => {\n const map = new Map<Id, number>();\n for (const t of visibleTasks) {\n const parentDepth = t.parentId != null ? (map.get(t.parentId) ?? 0) : -1;\n map.set(t.id, parentDepth + 1);\n }\n return map;\n }, [visibleTasks]);\n\n const siblingInfo = useMemo(() => {\n const counts = new Map<Id | null, number>();\n const map = new Map<Id, { posinset: number; setsize: number }>();\n for (const t of visibleTasks) {\n const parent = t.parentId ?? null;\n const pos = (counts.get(parent) ?? 0) + 1;\n counts.set(parent, pos);\n map.set(t.id, { posinset: pos, setsize: 0 });\n }\n for (const t of visibleTasks) {\n const entry = map.get(t.id)!;\n entry.setsize = counts.get(t.parentId ?? null) ?? 1;\n }\n return map;\n }, [visibleTasks]);\n\n const { viewport: listViewport, scheduleMeasure } = useViewportMeasure(taskListRef, {\n trackHorizontal: false,\n });\n\n // Order matters: sync the grid first, then measure, so the windowing reads the\n // scroll position both panes have settled on.\n const handleScroll = useCallback(() => {\n onTaskListScroll();\n scheduleMeasure();\n }, [onTaskListScroll, scheduleMeasure]);\n\n // Render only the rows intersecting the viewport (plus overscan). The `.rows`\n // height stays full (via the spacers) so the scrollbar extent is unaffected.\n const rowRange = rangeFromOffset(\n listViewport.scrollTop,\n listViewport.clientHeight,\n rowHeight,\n visibleTasks.length,\n ROW_OVERSCAN,\n );\n\n return (\n <div\n className={styles.taskList}\n style={{ height }}\n role=\"treegrid\"\n aria-label={labels.taskList}\n aria-rowcount={visibleTasks.length + 1}\n aria-colcount={resolvedColumns.length}\n >\n <TaskListHeader\n columns={resolvedColumns}\n rowHeight={rowHeight}\n scales={scales}\n onResizeStart={onResizeStart}\n slots={taskList?.header?.slots}\n slotProps={taskList?.header?.slotProps}\n />\n <div\n ref={taskListRef}\n className={styles.body}\n style={BODY_STYLE}\n onScroll={handleScroll}\n role=\"presentation\"\n >\n <div className={styles.rows} role=\"rowgroup\">\n <div\n style={{ height: rowRange.start * rowHeight }}\n role=\"presentation\"\n aria-hidden=\"true\"\n />\n {Array.from({ length: rowRange.end - rowRange.start }, (_, i) => {\n const index = rowRange.start + i;\n const task = visibleTasks[index]!;\n const siblings = siblingInfo.get(task.id);\n return (\n <TaskListRow\n key={task.id}\n task={task}\n rowHeight={rowHeight}\n rowIndex={index}\n depth={depthMap.get(task.id) ?? 0}\n posinset={siblings?.posinset ?? 1}\n setsize={siblings?.setsize ?? 1}\n isParent={parentIds.has(task.id)}\n isExpanded={expandedIds.has(task.id)}\n isSelected={selectedId === task.id}\n onToggleExpand={toggleExpand}\n onSelect={handleSelect}\n columns={resolvedColumns}\n treeCell={taskList?.treeCell}\n />\n );\n })}\n <div\n style={{\n height: (visibleTasks.length - rowRange.end) * rowHeight,\n }}\n role=\"presentation\"\n aria-hidden=\"true\"\n />\n </div>\n </div>\n </div>\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { GRID_MIN_WIDTH } from \"../core/constants\";\n\nexport function useGridResize(\n containerRef: React.RefObject<HTMLDivElement | null>,\n overlayRef: React.RefObject<HTMLDivElement | null>,\n) {\n const [gridWidth, setGridWidth] = useState<number | undefined>(undefined);\n const startRef = useRef<{ mouseX: number; width: number; containerW: number } | null>(null);\n\n const onHandleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const overlay = overlayRef.current;\n const container = containerRef.current;\n if (!overlay || !container) {\n return;\n }\n startRef.current = {\n mouseX: e.clientX,\n width: overlay.offsetWidth,\n containerW: container.offsetWidth,\n };\n\n const onMove = (ev: MouseEvent) => {\n if (!startRef.current) {\n return;\n }\n const { mouseX, width, containerW } = startRef.current;\n // Handle is on the grid's left edge: dragging left increases the width.\n const next = Math.min(containerW, Math.max(GRID_MIN_WIDTH, width + (mouseX - ev.clientX)));\n setGridWidth(next);\n };\n\n const onUp = () => {\n startRef.current = null;\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n };\n\n window.addEventListener(\"mousemove\", onMove);\n window.addEventListener(\"mouseup\", onUp);\n },\n [containerRef, overlayRef],\n );\n\n return { gridWidth, onHandleMouseDown };\n}\n",".actionsCell {\n display: flex;\n gap: 2px;\n}\n\n.actionsCell button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n opacity: 1;\n background-color: #0000;\n border-radius: 0;\n border: 0;\n cursor: pointer;\n}\n","import type { ColumnApi, GanttTask } from \"../../types\";\nimport { addDays } from \"../../core/dateUtils\";\n\nimport styles from \"./ActionsCell.module.css\";\n\n/**\n * Builds the task inserted by the actions-column \"add after\" button: a blank\n * one-day task starting the day after the clicked row, under the same parent.\n *\n * `endDate` is exclusive, so a one-day task ends at the following midnight.\n *\n * Known gap (ADR-012): this is a library-authored date that does NOT snap onto\n * working time, because a column's `render` is a plain function with no access to\n * the calendar. A task added after a Friday row can therefore land on a Saturday\n * until it is first dragged.\n */\nexport function buildActionTask(task: GanttTask): GanttTask {\n const start = addDays(task.startDate, 1);\n return {\n id: `task-${Date.now()}`,\n name: \"New task\",\n startDate: start,\n endDate: addDays(start, 1),\n duration: 1,\n progress: 0,\n type: \"task\",\n parentId: task.parentId ?? null,\n };\n}\n\n/**\n * The edit / add-after / delete controls of the built-in actions column.\n *\n * A real component rather than JSX inside an array literal, so it has somewhere\n * to grow a slot and somewhere to be tested from. Every handler stops propagation\n * because the whole row is clickable for selection.\n *\n * Labels come through `api.labels`, not `useGanttLabels()` — a column's `render`\n * is a plain function and cannot call hooks.\n */\nexport function ActionsCell({ task, api }: { task: GanttTask; api: ColumnApi }) {\n return (\n <div className={styles.actionsCell}>\n <button\n type=\"button\"\n title=\"Edit\"\n aria-label={api.labels.editTask(task)}\n onClick={(e) => {\n e.stopPropagation();\n api.editTask(task);\n }}\n >\n <span aria-hidden=\"true\">&#9998;</span>\n </button>\n <button\n type=\"button\"\n title=\"Add after\"\n aria-label={api.labels.addTaskAfter(task)}\n onClick={(e) => {\n e.stopPropagation();\n const created = buildActionTask(task);\n api.createTask(created, task.id);\n api.editTask(created);\n }}\n >\n <span aria-hidden=\"true\">&#10133;</span>\n </button>\n <button\n type=\"button\"\n title=\"Delete\"\n aria-label={api.labels.deleteTask(task)}\n style={{ fontSize: 9 }}\n onClick={(e) => {\n e.stopPropagation();\n api.deleteTask(task.id);\n }}\n >\n <span aria-hidden=\"true\">&#10060;</span>\n </button>\n </div>\n );\n}\n","import type { ColumnDef, GanttTask } from \"../../types\";\nimport { ActionsCell } from \"./ActionsCell\";\n\n/**\n * Key of the built-in edit/add/delete column, dropped when `readOnly` is set.\n *\n * Exported so a consumer can extend the built-in set rather than replace it:\n * `[...DEFAULT_COLUMNS.filter((c) => c.key !== ACTION_COLUMN_KEY), myColumn]`.\n */\nexport const ACTION_COLUMN_KEY = \"__action\";\n\n/**\n * The columns `<Gantt>` renders when no `columns` prop is given.\n *\n * Treat as immutable — it is module state shared by every chart on the page.\n */\nexport const DEFAULT_COLUMNS: ColumnDef[] = [\n {\n key: ACTION_COLUMN_KEY,\n header: \" \",\n width: 100,\n render: (task, api) => <ActionsCell task={task} api={api} />,\n },\n {\n key: \"__name\",\n header: \"Task Name\",\n render: (task: GanttTask) => task.name,\n width: 200,\n isTreeColumn: true,\n },\n {\n key: \"__start\",\n header: \"Start\",\n width: 90,\n render: (task: GanttTask) => task.startDate.toLocaleDateString(),\n },\n {\n key: \"__end\",\n header: \"End\",\n width: 90,\n // Stored ends are exclusive instants, so format through the api rather than\n // reading `task.endDate` — otherwise a Mon–Fri task reads as ending Saturday.\n render: (task: GanttTask, api) => api.format.endDate(task)?.toLocaleDateString() ?? \"—\",\n },\n {\n key: \"__progress\",\n header: \"Progress, %\",\n width: 90,\n render: (task: GanttTask) => `${task.progress ?? 0}%`,\n },\n];\n\n/** {@link DEFAULT_COLUMNS} without the actions column — the `readOnly` default. */\nexport const READ_ONLY_COLUMNS: ColumnDef[] = DEFAULT_COLUMNS.filter(\n (col) => col.key !== ACTION_COLUMN_KEY,\n);\n","import { useMemo, useRef } from \"react\";\nimport { GanttProvider } from \"./context/GanttProvider\";\nimport { GanttSlotsProvider } from \"./context/GanttSlotsContext\";\nimport { GanttGrid } from \"./components/grid/Grid\";\nimport { GridResizeHandle } from \"./components/grid/GridResizeHandle\";\nimport { TaskList } from \"./components/taskList/TaskList\";\nimport { useGridResize } from \"./hooks/useGridResize\";\nimport type { GanttProps } from \"./types\";\nimport { DEFAULT_COLUMNS, READ_ONLY_COLUMNS } from \"./components/taskList/defaultColumns\";\nimport { DEFAULT_LABELS } from \"./core/labels\";\n\nexport function Gantt({\n tasks,\n dependencies,\n rowHeight,\n colWidth,\n height,\n scales,\n padDays,\n zoomLevels,\n defaultZoomIndex,\n onZoomChange,\n zoomWheel,\n zoomKeyboard,\n onTaskClick,\n columns: columnsProp,\n defaultTaskListWidth = 280,\n onDependencyCreate,\n onDependencyDelete,\n onTaskCreate,\n onTaskDelete,\n onTaskEdit,\n onTasksChange,\n calendar,\n snapToWorking,\n durationUnit,\n readOnly = false,\n apiRef,\n hideTaskList,\n taskList,\n bars,\n dependencySlots,\n timeline,\n labels,\n}: GanttProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const overlayRef = useRef<HTMLDivElement>(null);\n const { gridWidth, onHandleMouseDown } = useGridResize(containerRef, overlayRef);\n // The built-in actions column only renders edit/add/delete buttons, so a\n // read-only chart drops it rather than shipping a column of dead controls.\n const columns = columnsProp ?? (readOnly ? READ_ONLY_COLUMNS : DEFAULT_COLUMNS);\n const showTaskList = !hideTaskList;\n\n // Grid-side slot groups reach deep components (bars, dependencies, calendar,\n // grid) via context instead of prop-drilling. `taskList` is drilled separately.\n const slotsValue = useMemo(\n () => ({ bars, dependencies: dependencySlots, timeline }),\n [bars, dependencySlots, timeline],\n );\n\n return (\n <GanttProvider\n tasks={tasks}\n dependencies={dependencies}\n rowHeight={rowHeight}\n colWidth={colWidth}\n height={height}\n scales={scales}\n padDays={padDays}\n zoomLevels={zoomLevels}\n defaultZoomIndex={defaultZoomIndex}\n onZoomChange={onZoomChange}\n zoomWheel={zoomWheel}\n zoomKeyboard={zoomKeyboard}\n onTaskClick={onTaskClick}\n onDependencyCreate={onDependencyCreate}\n onDependencyDelete={onDependencyDelete}\n onTaskCreate={onTaskCreate}\n onTaskDelete={onTaskDelete}\n onTaskEdit={onTaskEdit}\n onTasksChange={onTasksChange}\n apiRef={apiRef}\n labels={labels}\n calendar={calendar}\n snapToWorking={snapToWorking}\n durationUnit={durationUnit}\n readOnly={readOnly}\n >\n <GanttSlotsProvider value={slotsValue}>\n {showTaskList ? (\n <div\n ref={containerRef}\n role=\"group\"\n aria-label={labels?.gantt ?? DEFAULT_LABELS.gantt}\n style={{ position: \"relative\" }}\n >\n <TaskList columns={columns} taskList={taskList} />\n <div\n ref={overlayRef}\n style={{\n position: \"absolute\",\n top: 0,\n right: 0,\n zIndex: 1,\n display: \"flex\",\n flexDirection: \"row\",\n background: \"var(--am-gantt-grid-bg, #ffffff)\",\n ...(gridWidth !== undefined\n ? { width: gridWidth }\n : { left: defaultTaskListWidth }),\n }}\n >\n <GridResizeHandle onMouseDown={onHandleMouseDown} />\n <div style={{ flex: \"1 1 auto\", minWidth: 0 }}>\n <GanttGrid />\n </div>\n </div>\n </div>\n ) : (\n <GanttGrid />\n )}\n </GanttSlotsProvider>\n </GanttProvider>\n );\n}\n"],"x_google_ignoreList":[31],"mappings":"gJAAA,IAAa,EAAb,KAA4B,CAC1B,MAAgB,IAAI,IACpB,SAEA,YAAY,EAAc,CACxB,KAAK,SAAW,EAGlB,WAAmB,EAAc,CAC/B,GAAI,CAAC,KAAK,MAAM,IAAI,EAAI,CACtB,OAEF,IAAM,EAAM,KAAK,MAAM,IAAI,EAAI,CAC/B,KAAK,MAAM,OAAO,EAAI,CACtB,KAAK,MAAM,IAAI,EAAK,EAAI,CAG1B,IAAI,EAAuB,CACpB,QAAK,MAAM,IAAI,EAAI,CAIxB,OADA,KAAK,WAAW,EAAI,CACb,KAAK,MAAM,IAAI,EAAI,CAG5B,IAAI,EAAQ,EAAgB,CAI1B,GAHA,KAAK,WAAW,EAAI,CACpB,KAAK,MAAM,IAAI,EAAK,EAAM,CAEtB,KAAK,MAAM,KAAO,KAAK,SAAU,CACnC,GAAM,CAAC,GAAa,KAAK,MAAM,MAAM,CACrC,KAAK,MAAM,OAAO,EAAe,IC7BvC,SAAgB,EAA0B,EAAmB,EAAkC,CAC7F,IAAM,EAAQ,IAAI,EAAe,EAAU,CAC3C,MAAQ,IAAW,CACjB,IAAM,EAAS,EAAM,IAAI,EAAI,CAC7B,GAAI,GAAU,KACZ,OAAO,EAET,IAAM,EAAS,EAAG,EAAI,CAEtB,OADA,EAAM,IAAI,EAAK,EAAO,CACf,GAIX,SAAgB,EAAc,EAAmB,EAAkC,CACjF,OAAO,EAAoB,EAAI,EAAU,CCb3C,IAAM,EAAgB,IAChB,EAAc,KACd,EAAa,MAIb,EAAwD,CAC5D,OAAQ,EACR,KAAM,EACN,IAAK,EACL,KAPkB,EAAa,EAQhC,CAED,SAAgB,EAAU,EAAY,EAAoB,EAAsB,CAC9E,IAAM,EAAI,EAAK,aAAa,CACtB,EAAI,EAAK,UAAU,CACnB,EAAI,EAAK,SAAS,CAExB,OAAQ,EAAR,CACE,IAAK,SAAU,CACb,IAAM,EAAQ,IAAI,KAAK,EAAK,CAC5B,EAAM,WAAW,EAAG,EAAE,CACtB,IAAM,EAAc,KAAK,MAAM,EAAM,SAAS,CAAG,EAAc,CAC/D,MAAO,MAAM,KAAK,MAAM,EAAc,EAAK,GAE7C,IAAK,OAAQ,CACX,IAAM,EAAQ,IAAI,KAAK,EAAK,CAC5B,EAAM,WAAW,EAAG,EAAG,EAAE,CACzB,IAAM,EAAY,KAAK,MAAM,EAAM,SAAS,CAAG,EAAY,CAC3D,MAAO,KAAK,KAAK,MAAM,EAAY,EAAK,GAE1C,IAAK,MAAO,CACV,IAAM,EAAW,KAAK,MAAM,KAAK,IAAI,EAAG,EAAG,EAAE,CAAG,EAAW,CAC3D,MAAO,KAAK,KAAK,MAAM,EAAW,EAAK,GAEzC,IAAK,OAAQ,CACX,IAAM,EAAQ,IAAI,KAAK,EAAG,EAAG,EAAE,CACzB,EAAM,EAAM,QAAQ,CACpB,EAAW,IAAQ,EAAI,GAAK,EAAI,EACtC,EAAM,QAAQ,EAAM,SAAS,CAAG,EAAS,CACzC,IAAM,EAAY,KAAK,MAAM,EAAM,SAAS,EAAI,EAAa,GAAG,CAChE,MAAO,KAAK,KAAK,MAAM,EAAY,EAAK,GAE1C,IAAK,QAAS,CACZ,IAAM,EAAa,EAAI,GAAK,EAC5B,MAAO,MAAM,KAAK,MAAM,EAAa,EAAK,GAE5C,IAAK,UAAW,CACd,IAAM,EAAe,EAAI,EAAI,KAAK,MAAM,EAAI,EAAE,CAC9C,MAAO,KAAK,KAAK,MAAM,EAAe,EAAK,GAE7C,IAAK,OACH,MAAO,KAAK,KAAK,MAAM,EAAI,EAAK,GAElC,QACE,MAAU,MAAM,qBAAqB,IAAO,EAIlD,SAAgB,EAAU,EAAqB,CAC7C,IAAM,EAAM,EAAK,QAAQ,CACzB,OAAO,IAAQ,GAAK,IAAQ,EAW9B,SAAgB,EAAc,EAAoB,CAChD,OAAO,KAAK,IAAI,EAAK,aAAa,CAAE,EAAK,UAAU,CAAE,EAAK,SAAS,CAAC,CAAG,EAIzE,SAAgB,EAAsB,EAAwB,CAC5D,IAAM,EAAM,IAAI,KAAK,EAAW,EAAW,CAC3C,OAAO,IAAI,KAAK,EAAI,gBAAgB,CAAE,EAAI,aAAa,CAAE,EAAI,YAAY,CAAC,CAO5E,SAAgB,EAAQ,EAAY,EAAoB,CACtD,IAAM,EAAI,IAAI,KAAK,EAAK,CAExB,OADA,EAAE,SAAS,EAAG,EAAG,EAAG,EAAE,CACf,IAAI,KAAK,EAAE,SAAS,CAAG,EAAO,EAAW,CAQlD,SAAgB,EAAY,EAAY,EAA0B,CAChE,IAAM,EAAI,IAAI,KAAK,EAAK,CACxB,OAAQ,EAAR,CACE,IAAK,SAEH,OADA,EAAE,WAAW,EAAG,EAAE,CACX,EAET,IAAK,OAEH,OADA,EAAE,WAAW,EAAG,EAAG,EAAE,CACd,EAET,IAAK,MAEH,OADA,EAAE,SAAS,EAAG,EAAG,EAAG,EAAE,CACf,EAET,IAAK,OAAQ,CACX,EAAE,SAAS,EAAG,EAAG,EAAG,EAAE,CACtB,IAAM,EAAM,EAAE,QAAQ,CAChB,EAAW,IAAQ,EAAI,GAAK,EAAI,EAEtC,OADA,EAAE,QAAQ,EAAE,SAAS,CAAG,EAAS,CAC1B,EAET,IAAK,QAGH,OAFA,EAAE,SAAS,EAAG,EAAG,EAAG,EAAE,CACtB,EAAE,QAAQ,EAAE,CACL,EAET,IAAK,UAGH,OAFA,EAAE,SAAS,EAAG,EAAG,EAAG,EAAE,CACtB,EAAE,SAAS,KAAK,MAAM,EAAE,UAAU,CAAG,EAAE,CAAG,EAAG,EAAE,CACxC,EAET,IAAK,OAGH,OAFA,EAAE,SAAS,EAAG,EAAG,EAAG,EAAE,CACtB,EAAE,SAAS,EAAG,EAAE,CACT,EAET,QACE,MAAU,MAAM,qBAAqB,IAAO,EAWlD,SAAgB,EAAQ,EAAY,EAAoB,EAAsB,CAC5E,IAAM,EAAW,EAAe,GAChC,GAAI,IAAa,IAAA,GAIf,OAHI,IAAS,OAAS,IAAS,OACtB,EAAQ,EAAgB,EAAW,EAArB,EAAiC,CAEjD,IAAI,KAAK,EAAK,SAAS,CAAG,EAAS,EAAS,CAErD,IAAM,EAAI,IAAI,KAAK,EAAK,CACxB,OAAQ,EAAR,CACE,IAAK,QAEH,OADA,EAAE,SAAS,EAAE,UAAU,CAAG,EAAO,CAC1B,EAET,IAAK,UAEH,OADA,EAAE,SAAS,EAAE,UAAU,CAAG,EAAS,EAAE,CAC9B,EAET,IAAK,OAEH,OADA,EAAE,YAAY,EAAE,aAAa,CAAG,EAAO,CAChC,EAET,QACE,MAAU,MAAM,qBAAqB,IAAO,EAWlD,SAAgB,EAAW,EAAc,EAAY,EAA4B,CAC/E,IAAM,EAAW,EAAe,GAChC,GAAI,IAAa,IAAA,GACf,OAAQ,EAAK,SAAS,CAAG,EAAO,SAAS,EAAI,EAK/C,IAAM,EAAgB,IAAS,QAAU,EAAI,IAAS,UAAY,EAAI,GAChE,EAAe,EAAO,aAAa,CAAG,GAAK,EAAO,UAAU,CAC5D,EAAa,EAAK,aAAa,CAAG,GAAK,EAAK,UAAU,CACxD,EAAI,KAAK,OAAO,EAAa,GAAgB,EAAc,CAC/D,KAAO,EAAQ,EAAQ,EAAM,EAAE,CAAC,SAAS,CAAG,EAAK,SAAS,EACxD,IAEF,KAAO,EAAQ,EAAQ,EAAM,EAAI,EAAE,CAAC,SAAS,EAAI,EAAK,SAAS,EAC7D,GAAK,EAEP,IAAM,EAAO,EAAQ,EAAQ,EAAM,EAAE,CAAC,SAAS,CACzC,EAAO,EAAQ,EAAQ,EAAM,EAAI,EAAE,CAAC,SAAS,CACnD,OAAO,GAAK,EAAK,SAAS,CAAG,IAAS,EAAO,GAO/C,SAAgB,EAAa,EAAc,EAAoB,EAAsB,CACnF,IAAM,EAAW,EAAe,GAChC,GAAI,IAAa,IAAA,GACf,OAAO,IAAI,KAAK,EAAO,SAAS,CAAG,EAAS,EAAS,CAEvD,IAAM,EAAQ,KAAK,MAAM,EAAO,CAC1B,EAAO,EAAS,EAChB,EAAO,EAAQ,EAAQ,EAAM,EAAM,CAAC,SAAS,CAC7C,EAAO,EAAQ,EAAQ,EAAM,EAAQ,EAAE,CAAC,SAAS,CACvD,OAAO,IAAI,KAAK,EAAO,GAAQ,EAAO,GAAM,CAG9C,SAAgB,EACd,EACA,EACA,EAAqB,MACrB,EAAO,EACC,CACR,OAAO,MAAM,KAAK,CAAE,OAAQ,EAAO,EAAG,EAAG,IAAM,EAAQ,EAAO,EAAM,EAAI,EAAK,CAAC,CAQhF,SAAS,EAAwB,EAA8D,CAC7F,IAAM,EAAQ,EAAM,GACpB,GAAI,CAAC,EACH,OAAO,KAET,IAAI,EAAM,EAAM,UACZ,EAAM,EAAM,SAAW,EAAM,UACjC,IAAK,IAAM,KAAK,EAAO,CACjB,EAAE,UAAY,IAChB,EAAM,EAAE,WAEV,IAAM,EAAM,EAAE,SAAW,EAAE,UACvB,EAAM,IACR,EAAM,GAGV,MAAO,CAAE,MAAK,MAAK,CAGrB,IAAa,EAAiB,EAAQ,EAAyB,EAAE,CC5PpD,EAAkB,KAClB,EAAgB,IAGvB,EAAwC,CAAC,EAAG,EAAgB,CA6C5D,EAAW,oDAMjB,SAAgB,EAAmB,EAAwC,CACzE,IAAM,EAAI,EAAS,KAAK,EAAM,CAC9B,GAAI,CAAC,EACH,MAAU,MACR,+BAA+B,KAAK,UAAU,EAAM,CAAC,4CACtD,CAEH,IAAM,EAAO,OAAO,EAAE,GAAG,CAAG,GAAK,OAAO,EAAE,GAAG,CACvC,EAAK,OAAO,EAAE,GAAG,CAAG,GAAK,OAAO,EAAE,GAAG,CAC3C,GAAI,EAAO,GAAK,GAAA,KACd,MAAU,MACR,+BAA+B,KAAK,UAAU,EAAM,CAAC,iCACtD,CAEH,GAAI,GAAM,GAAQ,EAAA,KAChB,MAAU,MACR,+BAA+B,KAAK,UAAU,EAAM,CAAC,oDACtD,CAEH,MAAO,CAAC,EAAM,EAAG,CAInB,SAAS,EAAmB,EAAgD,CAC1E,GAAI,IAAU,IAAA,GACZ,OAAO,EAET,GAAI,IAAU,GACZ,MAAO,EAAE,CAEX,IAAM,EAAQ,EAAM,IAAI,EAAmB,CAAC,UAAU,EAAG,IAAM,EAAE,GAAK,EAAE,GAAG,CACrE,EAAgB,EAAE,CACxB,IAAK,GAAM,CAAC,EAAM,KAAO,EAAO,CAC9B,IAAM,EAAU,EAAI,OAAS,EAAI,EAAI,EAAI,OAAS,GAAM,IAAA,GACxD,GAAI,IAAY,IAAA,IAAa,GAAQ,EAAS,CAExC,EAAK,IACP,EAAI,EAAI,OAAS,GAAK,GAExB,SAEF,EAAI,KAAK,EAAM,EAAG,CAEpB,OAAO,EAGT,SAAS,EAAU,EAA8B,EAAsB,CACrE,IAAM,EAAmB,EAAE,CACvB,EAAQ,EACZ,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,OAAQ,GAAK,EACzC,EAAO,KAAK,EAAM,CAClB,GAAS,EAAU,EAAI,GAAM,EAAU,GAEzC,MAAO,CAAE,YAAW,SAAQ,aAAc,EAAO,KAAI,CAIvD,SAAS,IAAgB,CACvB,IAAM,EAAQ,IAAI,IAClB,MAAQ,IAA2C,CACjD,IAAM,EAAY,EAAU,KAAK,IAAI,CAC/B,EAAW,EAAM,IAAI,EAAU,CACrC,GAAI,EACF,OAAO,EAET,IAAM,EAAQ,EAAU,EAAW,EAAM,KAAK,CAE9C,OADA,EAAM,IAAI,EAAW,EAAM,CACpB,GAIX,SAAS,EAAS,EAAqC,CAOrD,OANI,IAAU,IAAA,GACL,IAEL,IAAU,GACL,IAEF,EAAM,KAAK,IAAI,CAgBxB,SAAgB,GAAY,EAA6C,CACvE,GAAI,CAAC,EACH,MAAO,GAET,IAAM,EAAkB,CAAC,EAAS,EAAS,MAAM,CAAC,CAClD,IAAK,IAAI,EAAM,EAAG,EAAM,EAAG,IAAO,CAChC,IAAM,EAAQ,EAAS,OAAO,GAC1B,IAAU,IAAA,IACZ,EAAM,KAAK,GAAG,EAAI,GAAG,EAAS,EAAM,GAAG,CAG3C,IAAM,EAAQ,EAAS,MACvB,GAAI,EACF,IAAK,IAAM,KAAQ,OAAO,KAAK,EAAM,CAAC,UAAU,CAC9C,EAAM,KAAK,GAAG,EAAK,GAAG,EAAS,EAAM,GAAM,GAAG,CAGlD,OAAO,EAAM,KAAK,IAAI,CAGxB,IAAM,EAAc,4BAEpB,SAAS,EAAoB,EAAqB,CAChD,IAAM,EAAI,EAAY,KAAK,EAAI,CAC/B,GAAI,CAAC,EACH,MAAU,MACR,6BAA6B,KAAK,UAAU,EAAI,CAAC,8CAClD,CAEH,OAAO,EAAc,IAAI,KAAK,OAAO,EAAE,GAAG,CAAE,OAAO,EAAE,GAAG,CAAG,EAAG,OAAO,EAAE,GAAG,CAAC,CAAC,CAO9E,SAAgB,EAAc,EAAyB,EAA+B,CACpF,IAAM,EAAS,IAAe,CACxB,EAAkB,EAAmB,EAAS,MAAM,CAEpD,EAAwB,EAAE,CAChC,IAAK,IAAI,EAAM,EAAG,EAAM,EAAG,IAAO,CAChC,IAAM,EAAW,EAAS,OAAO,GACjC,EAAU,KAAK,EAAO,IAAa,IAAA,GAAY,EAAkB,EAAmB,EAAS,CAAC,CAAC,CAGjG,IAAM,EAAS,IAAI,IACnB,GAAI,EAAS,MACX,IAAK,GAAM,CAAC,EAAS,KAAU,OAAO,QAAQ,EAAS,MAAM,CAC3D,EAAO,IAAI,EAAoB,EAAQ,CAAE,EAAO,EAAmB,EAAM,CAAC,CAAC,CAG/E,IAAM,EAAe,CAAC,GAAG,EAAO,MAAM,CAAC,CAAC,UAAU,EAAG,IAAM,EAAI,EAAE,CAE7D,EAAc,EACd,EAAgB,GAChB,EAAkB,EAAO,OAAS,EACtC,IAAK,IAAM,KAAS,EAClB,GAAe,EAAM,aACjB,EAAM,eAAiB,GAAK,EAAM,eAAA,OACpC,EAAgB,IAEd,EAAM,eAAA,OACR,EAAkB,IAGtB,IAAK,IAAM,KAAS,EAAO,QAAQ,CAC7B,EAAM,eAAiB,GAAK,EAAM,eAAA,OACpC,EAAgB,IAOpB,IAAI,EAAoB,EACxB,IAAK,IAAM,KAAS,EACd,EAAM,aAAe,IACvB,EAAoB,EAAM,cAI9B,MAAO,CACL,MACA,YACA,SACA,eACA,kBACA,gBACA,cACA,gBAAiB,EAAoB,EACtC,CAIH,SAAgB,EAAS,EAA4B,EAA4B,CAM/E,OALiB,EAAS,OAAO,IAAI,EACjC,EAIG,EAAS,YAAa,EAAW,GAAK,EAAK,GAAK,GAOzD,SAAgB,EAAgB,EAA4B,EAA0B,CACpF,IAAM,EAAO,EAAS,aAClB,EAAK,EACL,EAAK,EAAK,OACd,KAAO,EAAK,GAAI,CACd,IAAM,EAAO,EAAK,GAAO,EACrB,EAAK,GAAQ,EACf,EAAK,EAAM,EAEX,EAAK,EAGT,OAAO,EAAK,EAAK,OAAS,EAAK,GAAO,IAIxC,SAAgB,EAAgB,EAA4B,EAA0B,CACpF,IAAM,EAAO,EAAS,aAClB,EAAK,EACL,EAAK,EAAK,OACd,KAAO,EAAK,GAAI,CACd,IAAM,EAAO,EAAK,GAAO,EACrB,EAAK,IAAS,EAChB,EAAK,EAAM,EAEX,EAAK,EAGT,OAAO,EAAK,EAAI,EAAK,EAAK,GAAM,KCvQlC,SAAgB,GAAoB,EAAmD,CACrF,IAAM,GAAA,EAAA,EAAA,QAA8B,KAAK,CACnC,EAAM,GAAY,EAAS,CAQjC,OANI,CAAC,EAAM,SAAW,EAAM,QAAQ,MAAQ,KAC1C,EAAM,QAAU,CACd,MACA,MAAO,EAAW,EAAc,EAAU,EAAI,CAAG,KAClD,EAEI,EAAM,QAAQ,MCvBvB,IAAM,EAAc,KACd,EAAa,MAGb,EAAgB,IAYtB,SAAS,EAAY,EAAoB,CAMvC,OAJE,EAAK,UAAU,CAAG,EAClB,EAAK,YAAY,CAAG,EACpB,EAAK,YAAY,CAAG,IACpB,EAAK,iBAAiB,EACZ,EAWd,SAAS,EAAU,EAAkB,EAAsB,CACzD,IAAM,EAAO,EAAsB,EAAS,CAC5C,OAAO,IAAI,KACT,EAAK,aAAa,CAClB,EAAK,UAAU,CACf,EAAK,SAAS,CACd,EACA,EACA,EACA,KAAK,MAAM,EAAS,EAAc,CACnC,CAIH,SAAS,GAAa,EAAiB,EAAwB,CAC7D,GAAM,CAAE,YAAW,UAAW,EAC9B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,EAAI,EAAU,OAAQ,GAAK,EAAG,IAAK,CACxD,IAAM,EAAO,EAAU,GACjB,EAAK,EAAU,EAAI,GACzB,GAAI,GAAU,EACZ,OAAO,EAAO,GAEhB,GAAI,EAAS,EACX,OAAO,EAAO,IAAO,EAAS,GAGlC,OAAO,EAAM,aAUf,SAAS,GAA2B,EAAiB,EAAwB,CAC3E,GAAM,CAAE,YAAW,UAAW,EAC1B,EAAS,EAAU,OAAS,EAAI,EAAU,GAAM,EACpD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,EAAI,EAAU,QAC/B,IAAO,IAAO,GADyB,GAAK,EAAG,IAInD,EAAS,EAAU,IAAO,EAAS,EAAO,IAE5C,OAAO,EAUT,SAAS,GAA0B,EAAiB,EAAwB,CAC1E,GAAM,CAAE,YAAW,UAAW,EAC9B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,EAAI,EAAU,OAAQ,GAAK,EAAG,IAAK,CACxD,IAAM,EAAS,EAAU,EAAI,GAAM,EAAU,GAC7C,GAAI,EAAS,EAAO,GAAM,EACxB,OAAO,EAAU,IAAO,EAAS,EAAO,IAG5C,OAAO,EAAU,OAAS,EAAI,EAAU,EAAU,OAAS,GAAM,EAInE,SAAS,GAAmB,EAAiB,EAA+B,CAC1E,GAAM,CAAE,aAAc,EACtB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,OAAQ,GAAK,EACzC,GAAI,EAAS,EAAU,EAAI,GACzB,OAAO,KAAK,IAAI,EAAQ,EAAU,GAAI,CAG1C,OAAO,KAIT,SAAS,GAAkB,EAAiB,EAA+B,CACzE,GAAM,CAAE,aAAc,EAClB,EAAsB,KAC1B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,OAAQ,GAAK,EACrC,EAAS,EAAU,KACrB,EAAO,KAAK,IAAI,EAAQ,EAAU,EAAI,GAAI,EAG9C,OAAO,EAOT,SAAgB,GAAc,EAAmC,EAAqB,CAIpF,GAHI,CAAC,GAGD,EAAS,gBACX,MAAO,GAET,IAAM,EAAQ,EAAS,EAAU,EAAc,EAAK,CAAC,CAC/C,EAAS,EAAY,EAAK,CAC1B,CAAE,aAAc,EACtB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,OAAQ,GAAK,EACzC,GAAI,GAAU,EAAU,IAAO,EAAS,EAAU,EAAI,GACpD,MAAO,GAGX,MAAO,GAgBT,SAAgB,EACd,EACA,EACA,EACM,CAIN,GAHI,CAAC,GAAY,EAAS,iBAGtB,EAAS,cAAgB,GAAK,EAAS,OAAO,OAAS,EAEzD,OAAO,EAET,IAAI,EAAM,EAAc,EAAK,CACzB,EAAS,EAAY,EAAK,CAE9B,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAe,IAAS,CAClD,IAAM,EAAQ,EAAS,EAAU,EAAI,CACrC,GAAI,IAAQ,EAAG,CACb,IAAM,EAAQ,GAAmB,EAAO,EAAO,CAC/C,GAAI,IAAU,KACZ,OAAO,IAAU,GAAU,IAAQ,EAAc,EAAK,CAAG,EAAO,EAAU,EAAK,EAAM,CAEvF,GAAO,EACP,EAAS,EACT,SAEF,IAAM,EAAM,GAAkB,EAAO,EAAO,CAC5C,GAAI,IAAQ,KACV,OAAO,IAAQ,GAAU,IAAQ,EAAc,EAAK,CAAG,EAAO,EAAU,EAAK,EAAI,CAEnF,IACA,EAAS,EAIX,OAAO,EAIT,SAAgB,GAAmB,EAAmC,EAAkB,CAItF,GAHI,CAAC,GAAY,EAAS,iBAGtB,GAAc,EAAU,EAAK,CAC/B,OAAO,EAET,IAAM,EAAU,EAAmB,EAAU,EAAM,EAAE,CAC/C,EAAW,EAAmB,EAAU,EAAM,GAAG,CAGvD,OAFmB,EAAQ,SAAS,CAAG,EAAK,SAAS,EACjC,EAAK,SAAS,CAAG,EAAS,SAAS,CACpB,EAAU,EAG/C,SAAS,GAAY,EAA4B,EAAc,EAAuB,CACpF,IAAI,EAAM,EAAc,EAAO,CAC3B,EAAS,EAAY,EAAO,CAC5B,EAAY,EAEhB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAe,IAAS,CAClD,IAAM,EAAQ,EAAS,EAAU,EAAI,CAC/B,EAAS,GAAa,EAAO,EAAO,CACpC,EAAY,EAAM,aAAe,EACvC,GAAI,GAAa,EACf,OAAO,EAAU,EAAK,GAA2B,EAAO,EAAS,EAAU,CAAC,CAS9E,GAPA,GAAa,EACb,GAAO,EACP,EAAS,EAKL,EAAS,YAAc,GAAK,EAAY,EAAS,YAAa,CAChE,IAAM,EAAe,EAAgB,EAAU,EAAI,CAC7C,EACJ,IAAiB,IACb,IACA,KAAK,OAAO,EAAe,GAAO,EAAE,CACpC,EAAY,KAAK,KAAK,EAAY,EAAS,YAAY,CAAG,EAC1D,EAAQ,KAAK,IAAI,EAAW,EAAU,CACxC,EAAQ,GAAK,OAAO,SAAS,EAAM,GACrC,GAAO,EAAQ,EACf,GAAa,EAAQ,EAAS,cAIpC,OAAO,EAAU,EAAK,EAAO,CAG/B,SAAS,GAAa,EAA4B,EAAc,EAAuB,CACrF,IAAI,EAAM,EAAc,EAAO,CAC3B,EAAS,EAAY,EAAO,CAC5B,EAAY,EAEhB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAe,IAAS,CAClD,IAAM,EAAQ,EAAS,EAAU,EAAI,CAC/B,EAAS,GAAa,EAAO,EAAO,CAC1C,GAAI,GAAa,EACf,OAAO,EAAU,EAAK,GAA0B,EAAO,EAAS,EAAU,CAAC,CAM7E,GAJA,GAAa,EACb,IACA,EAAS,EAEL,EAAS,YAAc,GAAK,EAAY,EAAS,YAAa,CAChE,IAAM,EAAmB,EAAgB,EAAU,EAAI,CACjD,EACJ,IAAqB,KACjB,IACA,KAAK,OAAO,EAAM,GAAoB,EAAE,CACxC,EAAY,KAAK,KAAK,EAAY,EAAS,YAAY,CAAG,EAC1D,EAAQ,KAAK,IAAI,EAAW,EAAU,CACxC,EAAQ,GAAK,OAAO,SAAS,EAAM,GACrC,GAAO,EAAQ,EACf,GAAa,EAAQ,EAAS,cAIpC,OAAO,EAAU,EAAK,EAAO,CAgB/B,SAAgB,EACd,EACA,EACA,EACA,EACM,CACN,GAAI,CAAC,EACH,OAAO,IAAI,KAAK,EAAK,SAAS,CAAG,EAAG,CAGtC,IAAM,EAAS,EAAmB,EAAU,EADjB,IAAc,EAAK,EAAI,GAAK,GACD,CAOtD,OANI,IAAO,GAGP,EAAS,cAAgB,GAAK,EAAS,OAAO,OAAS,EAClD,EAEF,EAAK,EACR,GAAY,EAAU,EAAQ,EAAK,EAAc,CACjD,GAAa,EAAU,EAAQ,CAAC,EAAK,EAAc,CAUzD,SAAgB,GAAe,EAAmC,EAAY,EAAkB,CAC9F,GAAI,CAAC,EACH,OAAO,EAAG,SAAS,CAAG,EAAK,SAAS,CAEtC,GAAI,EAAG,SAAS,CAAG,EAAK,SAAS,CAC/B,MAAO,CAAC,GAAe,EAAU,EAAI,EAAK,CAE5C,IAAM,EAAS,EAAc,EAAG,CAC5B,EAAM,EAAc,EAAK,CACzB,EAAS,EAAY,EAAK,CAC1B,EAAU,EAEd,KAAO,EAAM,GAAQ,CACnB,GAAI,IAAW,GAAK,EAAS,YAAc,EAAG,CAC5C,IAAM,EAAe,EAAgB,EAAU,EAAI,CAE7C,EAAQ,KAAK,OADL,KAAK,IAAI,EAAQ,EACL,CAAQ,GAAO,EAAE,CAC3C,GAAI,EAAQ,EAAG,CACb,GAAW,EAAQ,EAAS,YAC5B,GAAO,EAAQ,EACf,UAGJ,IAAM,EAAQ,EAAS,EAAU,EAAI,CACrC,GAAW,EAAM,aAAe,GAAa,EAAO,EAAO,CAC3D,GAAO,EACP,EAAS,EAGX,IAAM,EAAQ,EAAS,EAAU,EAAI,CAErC,MADA,IAAW,GAAa,EAAO,EAAY,EAAG,CAAC,CAAG,GAAa,EAAO,EAAO,CACtE,EAAU,EAmBnB,IAAM,GAA0B,CAAE,aAAc,GAAO,CAUvD,SAAgB,EACd,EACA,EACA,EACgB,CAChB,GAAI,CAAC,EAAU,CACb,IAAM,EAAM,EAAS,QAAQ,CAI7B,OAHI,IAAQ,GAAK,IAAQ,EAChB,CAAE,aAAc,GAAM,OAAQ,UAAW,CAE3C,GAET,GAAI,GAAe,EAAU,EAAU,EAAO,CAAG,EAC/C,OAAO,GAET,IAAM,EAAW,EAAc,EAAS,CAUxC,OATI,EAAS,OAAO,IAAI,EAAS,CACxB,CAAE,aAAc,GAAM,OAAQ,UAAW,CAIpC,EAAS,EAAU,EAC7B,CAAM,eAAiB,EAClB,CAAE,aAAc,GAAM,OAAQ,UAAW,CAE3C,CAAE,aAAc,GAAM,OAAQ,WAAY,CAQnD,SAAgB,EAAiB,EAAmC,EAA4B,CAU9F,OATI,IAAS,SACJ,EAEL,IAAS,OACJ,EAEL,CAAC,GAAY,EAAS,kBAAoB,EACrC,EAEF,EAAS,gBAIlB,SAAgB,GACd,EACA,EACA,EACA,EACA,EACM,CACN,OAAO,EAAa,EAAU,EAAM,EAAS,EAAiB,EAAU,EAAK,CAAE,EAAU,CC3a3F,IAAa,EAAoC,CAC/C,SAAU,KACV,aAAc,MACd,cAAe,GAChB,CAaD,SAAgB,EAAa,EAAiB,EAA8B,CAU1E,OATI,EAAK,OAAS,aAAe,EAAK,WAAa,EAC1C,EAAK,UAEV,EAAK,QACA,EAAK,QAEV,EAAK,WAAa,IAAA,GACb,EAAK,UAEP,GAAgB,EAAI,SAAU,EAAK,UAAW,EAAK,SAAU,EAAI,aAAc,EAAE,CAU1F,SAAgB,GAAe,EAAiB,EAAwB,CAItE,OAHI,EAAW,SAAS,EAAI,EAAU,SAAS,CACtC,EAAY,EAAW,MAAM,CAE/B,EAAY,IAAI,KAAK,EAAW,SAAS,CAAG,EAAE,CAAE,MAAM,CAU/D,SAAgB,GAA0B,EAAwB,CAChE,OAAO,IAAI,KAAK,EAAW,aAAa,CAAE,EAAW,UAAU,CAAE,EAAW,SAAS,CAAG,EAAE,CAU5F,SAAgB,GAAa,EAAiB,EAA0C,CACtF,IAAM,EAAM,EAAa,EAAM,EAAI,CAC/B,OAAI,SAAS,EAAI,EAAK,UAAU,SAAS,EAG7C,OAAO,GAAe,EAAK,UAAW,EAAI,CAU5C,SAAgB,GAAkB,EAAiB,EAAgC,CAEjF,OADe,GAAe,EAAI,SAAU,EAAK,UAAW,EAAa,EAAM,EAAI,CAC5E,CAAS,EAAiB,EAAI,SAAU,EAAI,aAAa,CChGlE,IAAa,GAAsC,CACjD,MAAO,cACP,SAAU,YACV,SAAU,WACV,OAAQ,SACR,SAAU,WACV,eAAgB,mBAChB,iBAAkB,oBAClB,SAAW,GAAS,QAAQ,EAAK,OACjC,aAAe,GAAS,kBAAkB,EAAK,OAC/C,WAAa,GAAS,UAAU,EAAK,OACrC,KAAM,EAAM,CAAE,cAAe,GAAe,EAAM,EAAS,CAC5D,CAED,SAAgB,GAAc,EAAsD,CAIlF,OAHK,EAGE,CAAE,GAAG,GAAgB,GAAG,EAAQ,CAF9B,GAKX,SAAS,GAAW,EAAoB,CACtC,OAAO,EAAK,mBAAmB,IAAA,GAAW,CAAE,UAAW,SAAU,CAAC,CAGpE,IAAM,GAA6D,CACjE,KAAM,OACN,UAAW,YACX,QAAS,UACV,CAED,SAAgB,GAAe,EAAiB,EAA0B,CACxE,IAAM,EAAO,GAAW,EAAK,MAAQ,QAC/B,EAAQ,CAAC,EAAK,KAAM,EAAK,CAU/B,OATI,EAAK,SAAW,EAAK,QAAQ,SAAS,GAAK,EAAK,UAAU,SAAS,CACrE,EAAM,KAAK,GAAG,GAAW,EAAK,UAAU,CAAC,MAAM,GAAW,EAAK,QAAQ,GAAG,CAE1E,EAAM,KAAK,GAAW,EAAK,UAAU,CAAC,CAGpC,EAAK,OAAS,aAChB,EAAM,KAAK,GAAG,KAAK,MAAM,EAAS,CAAC,YAAY,CAE1C,EAAM,KAAK,KAAK,CAGzB,SAAgB,GAAkB,EAAY,EAAoB,EAAsB,CACtF,OAAQ,EAAR,CACE,IAAK,SACL,IAAK,OACH,OAAO,EAAK,eAAe,IAAA,GAAW,CAAE,UAAW,OAAQ,UAAW,QAAS,CAAC,CAClF,IAAK,MACH,OAAO,EAAK,mBAAmB,IAAA,GAAW,CAAE,UAAW,OAAQ,CAAC,CAClE,IAAK,OACH,MAAO,WAAW,EAAK,mBAAmB,IAAA,GAAW,CAAE,UAAW,OAAQ,CAAC,GAC7E,IAAK,QACH,OAAO,EAAK,mBAAmB,IAAA,GAAW,CAAE,MAAO,OAAQ,KAAM,UAAW,CAAC,CAC/E,IAAK,UAEH,MAAO,IADS,KAAK,MAAM,EAAK,UAAU,CAAG,EAAE,CAAG,EAC/B,GAAG,EAAK,aAAa,GAE1C,IAAK,OACH,OAAO,EAAO,EACV,GAAG,EAAK,aAAa,CAAC,MAAM,EAAK,aAAa,CAAG,EAAO,IACxD,OAAO,EAAK,aAAa,CAAC,EC9CpC,SAAgB,GACd,EACA,EAAyB,EACZ,CACb,IAAM,EAAiB,GAAoB,EAAa,QAAQ,CAAC,CAC3D,EAAQ,EAAe,IAAI,KAAK,EAAI,EAAE,CACtC,EAAyB,EAAE,CACjC,IAAK,IAAM,KAAQ,EACjB,GAAc,EAAM,EAAgB,EAAW,EAAI,CAErD,OAAO,EAIT,SAAgB,GAAkB,EAAqC,CACrE,IAAM,EAAwB,IAAI,IAClC,IAAK,IAAM,KAAQ,EACjB,EAAK,IAAI,EAAK,GAAI,EAAK,CAEzB,OAAO,EAoBT,SAAgB,GACd,EACA,EACiB,CACjB,OAAO,GAAc,IAAI,IAAI,EAAS,CAAE,EAAS,CAOnD,SAAS,GAAc,EAAsB,EAA0C,CACrF,IAAK,IAAM,KAAO,EAChB,OAAQ,EAAI,KAAZ,CACE,IAAK,SAEC,EAAI,IAAI,EAAI,KAAK,GAAG,EACtB,EAAI,IAAI,EAAI,KAAK,GAAI,EAAI,KAAK,CAEhC,MACF,IAAK,SACH,EAAI,OAAO,EAAI,GAAG,CAClB,MACF,IAAK,SACH,EAAM,GAAW,EAAK,EAAI,KAAM,EAAI,QAAQ,CAC5C,MAGN,OAAO,EAOT,SAAS,GACP,EACA,EACA,EACiB,CACjB,GAAI,GAAW,KAEb,OADA,EAAI,IAAI,EAAK,GAAI,EAAK,CACf,EAET,IAAM,EAAwB,IAAI,IAC7B,EAAI,IAAI,EAAQ,EACnB,EAAK,IAAI,EAAK,GAAI,EAAK,CAEzB,IAAK,GAAM,CAAC,EAAI,KAAa,EAC3B,EAAK,IAAI,EAAI,EAAS,CAClB,IAAO,GACT,EAAK,IAAI,EAAK,GAAI,EAAK,CAG3B,OAAO,EAuBT,IAAM,GAA4B,GAElC,SAAgB,IAAmC,CACjD,MAAO,CAAE,UAAW,KAAM,UAAW,IAAI,EAAS,GAA0B,CAAE,CAShF,SAAgB,GACd,EACA,EACA,EACiB,CACb,EAAM,YAAc,IACtB,EAAM,UAAY,EAClB,EAAM,UAAY,IAAI,EAAS,GAA0B,EAG3D,IAAI,EAAO,EACP,EAAmC,KACvC,IAAK,IAAI,EAAI,EAAI,OAAQ,GAAK,EAAG,IAAK,CACpC,IAAM,EAAW,EAAM,UAAU,IAAI,EAAE,CACvC,GAAI,GAAY,EAAS,aAAe,EAAI,aAAa,EAAI,GAAI,CAC/D,EAAO,EACP,EAAW,EAAS,IACpB,OAGJ,GAAI,CAAC,EAAU,CACb,IAAM,EAAO,EAAM,UAAU,IAAI,EAAE,CACnC,EAAW,EAAO,EAAK,IAAM,GAAkB,EAAM,CAChD,GACH,EAAM,UAAU,IAAI,EAAG,CAAE,WAAY,KAAM,IAAK,EAAU,CAAC,CAI/D,IAAK,IAAI,EAAI,EAAM,EAAI,EAAI,OAAQ,IAAK,CACtC,IAAM,EAAc,EAAI,aAAa,GACrC,EAAW,GAAiB,EAAU,EAAY,CAClD,EAAM,UAAU,IAAI,EAAI,EAAG,CAAE,WAAY,EAAa,IAAK,EAAU,CAAC,CAExE,OAAO,EAWT,SAAS,GACP,EACA,EACA,EACA,EACW,CACX,IAAM,EAAW,EAAe,IAAI,EAAK,GAAG,CAC5C,GAAI,CAAC,GAAY,EAAS,SAAW,EAAG,CACtC,IAAM,EAAO,GAAe,EAAM,EAAI,CAEtC,OADA,EAAI,KAAK,EAAK,CACP,EAGT,IAAM,EAAO,EAAI,OACjB,EAAI,KAAK,EAAK,CACd,IAAM,EAAiC,EAAE,CACzC,IAAK,IAAM,KAAS,EAClB,EAAkB,KAAK,GAAc,EAAO,EAAgB,EAAK,EAAI,CAAC,CAExE,IAAM,EAAY,GAAkB,EAAM,EAAmB,EAAI,CAEjE,MADA,GAAI,GAAQ,EACL,EAaT,SAAS,GAAe,EAAiB,EAAmC,CAC1E,IAAM,EAAM,EAAa,EAAM,EAAI,CAOnC,OANI,EAAK,SAAW,EAAK,QAAQ,SAAS,GAAK,EAAI,SAAS,EAGxD,CAAC,EAAK,SAAW,IAAQ,EAAK,UACzB,EAEF,CAAE,GAAG,EAAM,QAAS,EAAK,CAGlC,SAAgB,GACd,EACA,EACA,EAAyB,EACd,CAIX,GAAI,EAAK,OAAS,WAAa,EAAS,SAAW,EACjD,OAAO,GAAe,EAAM,EAAI,CAGlC,IAAI,EAAY,EAAS,GAAI,UACzB,EAAU,EAAa,EAAS,GAAK,EAAI,CACzC,EAAc,EACd,EAAoB,EAExB,IAAK,IAAM,KAAS,EAAU,CACxB,EAAM,UAAY,IACpB,EAAY,EAAM,WAMpB,IAAM,EAAW,EAAa,EAAO,EAAI,CACrC,EAAW,IACb,EAAU,GAMR,EAAM,OAAS,cACjB,IACA,GAAe,EAAM,UAAY,GAIrC,IAAM,EAAW,IAAsB,EAAI,EAAI,KAAK,MAAM,EAAc,EAAkB,CAE1F,MAAO,CACL,GAAG,EACH,YACA,UACA,WACD,CAGH,SAAS,GAAoB,EAAmD,CAC9E,IAAM,EAA6B,IAAI,IACvC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,UAAY,KAC5B,EAAW,EAAI,IAAI,EAAS,EAAI,EAAE,CACxC,EAAS,KAAK,EAAK,CACnB,EAAI,IAAI,EAAU,EAAS,CAE7B,OAAO,EC9RT,IAAa,GAAb,KAAsB,CACpB,MAAqB,EAAE,CACvB,KAAe,EAEf,YAAY,EAAuB,CAC7B,GACF,KAAK,MAAM,KAAK,GAAG,EAAQ,CAI/B,IAAI,MAAe,CACjB,OAAO,KAAK,MAAM,OAAS,KAAK,KAGlC,SAAmB,CACjB,OAAO,KAAK,OAAS,EAGvB,QAAQ,EAAe,CACrB,KAAK,MAAM,KAAK,EAAK,CAGvB,SAAyB,CACvB,GAAI,KAAK,MAAQ,KAAK,MAAM,OAC1B,OAEF,IAAM,EAAO,KAAK,MAAM,KAAK,MAU7B,MATA,MAAK,OAID,KAAK,KAAO,KAAK,MAAM,QAAU,IACnC,KAAK,MAAQ,KAAK,MAAM,MAAM,KAAK,KAAK,CACxC,KAAK,KAAO,GAGP,IC1BX,SAAS,GAAO,EAAiB,EAA8B,CAC7D,MAAO,CACL,MAAO,EAAK,UACZ,IAAK,EAAa,EAAM,EAAI,CAC7B,CAIH,SAAS,GAAgB,EAAiB,EAAgC,CACxE,GAAM,CAAE,QAAO,OAAQ,GAAO,EAAM,EAAI,CACxC,OAAO,GAAe,EAAI,SAAU,EAAO,EAAI,CAsBjD,SAAS,GACP,EACA,EACA,EACA,EACA,EACM,CACN,IAAM,EAAM,EAAI,SAChB,OAAQ,EAAR,CACE,IAAK,KACH,OAAO,EAAa,EAAK,EAAK,IAAK,EAAO,EAAE,CAC9C,IAAK,KACH,OAAO,EAAa,EAAK,EAAK,MAAO,EAAO,EAAE,CAChD,IAAK,KAGH,OAAO,EAAa,EADL,EAAa,EAAK,EAAK,IAAK,EAAO,GACzB,CAAQ,CAAC,EAAiB,GAAG,CAExD,IAAK,KAGH,OAAO,EAAa,EADL,EAAa,EAAK,EAAK,MAAO,EAAO,GAC3B,CAAQ,CAAC,EAAiB,GAAG,EAmB5D,SAAgB,GAAqB,EAAiD,CACpF,IAAM,EAAe,IAAI,IACnB,EAAkB,IAAI,IAC5B,IAAK,IAAM,KAAO,EAAc,CAC9B,IAAM,EAAgB,EAAa,IAAI,EAAI,KAAK,CAC5C,EACF,EAAc,KAAK,EAAI,GAAG,CAE1B,EAAa,IAAI,EAAI,KAAM,CAAC,EAAI,GAAG,CAAC,CAGtC,IAAM,EAAO,EAAgB,IAAI,EAAI,GAAG,CACpC,EACF,EAAK,KAAK,EAAI,CAEd,EAAgB,IAAI,EAAI,GAAI,CAAC,EAAI,CAAC,CAGtC,MAAO,CAAE,eAAc,kBAAiB,KAAM,EAAa,OAAQ,CAoBrE,SAAgB,GAAU,EAAkD,CAC1E,IAAM,EAAQ,IAAI,IAClB,MAAO,CACL,IAAM,GAAO,EAAM,IAAI,EAAG,EAAI,EAAK,IAAI,EAAG,CAC1C,KAAM,EAAI,IAAS,CACjB,EAAM,IAAI,EAAI,EAAK,EAIrB,IAAI,MAAO,CACT,OAAO,EAAK,MAEf,CAQH,SAAS,GACP,EACA,EACA,EACA,EACa,CACb,IAAM,EAAS,GAAgB,EAAM,EAAI,CACnC,EAAY,EAAiB,EAAI,SAAU,EAAI,aAAa,CAC9D,EAAwB,KAC5B,IAAK,IAAM,KAAO,EAAgB,IAAI,EAAK,GAAG,EAAI,EAAE,CAAE,CACpD,IAAM,EAAO,EAAQ,IAAI,EAAI,KAAK,CAClC,GAAI,CAAC,EACH,SAEF,IAAM,EAAY,GAChB,GAAO,EAAM,EAAI,CACjB,EAAI,MACH,EAAI,KAAO,GAAK,EACjB,EACA,EACD,EACG,IAAa,MAAQ,EAAY,KACnC,EAAW,GAUf,OAPI,IAAa,KACR,KAMF,EAAmB,EAAI,SAAU,EAAU,EAAE,CAItD,SAAS,GAAQ,EAAiB,EAAa,EAAmC,CAOhF,OAHI,EAAK,OAAS,YACT,CAAE,GAAG,EAAM,UAAW,EAAO,QAAS,EAAO,CAE/C,CACL,GAAG,EACH,UAAW,EACX,QAAS,EAAa,EAAI,SAAU,EAAO,GAAgB,EAAM,EAAI,CAAE,EAAE,CAC1E,CAiBH,SAAgB,GACd,EACA,EACA,EACoC,CACpC,IAAM,EAAM,EAAI,SACV,EAAO,EAAI,cACX,EAAO,GAAO,EAAM,EAAI,CAE9B,GAAI,EAAK,OAAS,YAAa,CAC7B,IAAM,EAAM,EAAO,OAAS,YAAc,EAAO,QAAU,EAAO,UAC5D,EAAK,EAAO,GAAmB,EAAK,EAAI,CAAG,EACjD,MAAO,CAAE,UAAW,EAAI,QAAS,EAAI,CAGvC,GAAI,EAAO,OAAS,OAAQ,CAC1B,IAAM,EAAS,GAAe,EAAK,EAAK,MAAO,EAAK,IAAI,CAClD,EAAQ,EAAO,EAAmB,EAAK,EAAO,UAAW,EAAE,CAAG,EAAO,UAC3E,MAAO,CAAE,UAAW,EAAO,QAAS,EAAa,EAAK,EAAO,EAAQ,EAAE,CAAE,CAO3E,IAAM,EAAW,EAAO,OAAS,cAAgB,EAAO,UAAY,EAAK,MACnE,EAAS,EAAO,OAAS,YAAc,EAAO,QAAU,EAAK,IAC7D,EAAQ,EAAO,EAAmB,EAAK,EAAU,EAAE,CAAG,EACtD,EAAM,EAAO,EAAmB,EAAK,EAAQ,GAAG,CAAG,EAEzD,GAAI,GAAe,EAAK,EAAO,EAAI,EAAI,EAAG,CAGxC,IAAM,EAAS,EAAiB,EAAK,EAAI,aAAa,CAItD,OAHI,EAAO,OAAS,cACX,CAAE,UAAW,EAAa,EAAK,EAAK,CAAC,EAAQ,GAAG,CAAE,QAAS,EAAK,CAElE,CAAE,UAAW,EAAO,QAAS,EAAa,EAAK,EAAO,EAAQ,EAAE,CAAE,CAE3E,MAAO,CAAE,UAAW,EAAO,QAAS,EAAK,CAuB3C,SAAgB,GACd,EACA,EACA,EACA,EAAyB,EACL,CACpB,GAAM,CAAE,eAAc,mBAAoB,EAEpC,EAAU,IAAI,IAKd,EAAc,EAAQ,IAAI,EAAU,CAC1C,GAAI,EAAa,CACf,IAAM,EAAW,GAAc,EAAa,EAAiB,EAAS,EAAI,CAC1E,GAAI,IAAa,MAAQ,EAAS,SAAS,CAAG,EAAY,UAAU,SAAS,CAAE,CAC7E,IAAM,EAAU,GAAQ,EAAa,EAAU,EAAI,CACnD,EAAQ,IAAI,EAAW,EAAQ,CAC/B,EAAQ,IAAI,EAAW,EAAQ,EAInC,IAAM,EAAQ,IAAI,GAAU,CAAC,EAAU,CAAC,CAClC,GAAiB,EAAM,KAAO,IAAM,EAAQ,KAAO,GACrD,EAAa,EAEjB,KAAO,CAAC,EAAM,SAAS,EACjB,MAAe,IADI,CAIvB,IAAM,EAAS,EAAM,SAAS,CAE9B,IAAK,IAAM,KAAe,EAAa,IAAI,EAAO,EAAI,EAAE,CAAE,CACxD,IAAM,EAAY,EAAQ,IAAI,EAAY,CAC1C,GAAI,CAAC,EACH,SAGF,IAAM,EAAW,GAAc,EAAW,EAAiB,EAAS,EAAI,CAOxE,GANI,IAAa,MAMb,EAAS,SAAS,EAAI,EAAU,UAAU,SAAS,CACrD,SAGF,IAAM,EAAO,GAAQ,EAAW,EAAU,EAAI,CAC9C,EAAQ,IAAI,EAAa,EAAK,CAC9B,EAAQ,IAAI,EAAa,EAAK,CAC9B,EAAM,QAAQ,EAAY,EAI9B,OAAO,ECzTT,IAAM,GAAuB,CAAE,aAAc,EAAE,CAAE,OAAQ,EAAG,CAI/C,GAAuC,EAAE,CAwBtD,SAAS,GAAkB,EAA0B,EACnD,EAAA,EAAA,iBAAgB,EAAO,CAIzB,SAAS,GAAkB,EAAgB,EAAoC,CAC7E,IAAM,EAAO,EAAI,aAAa,MAAM,EAAG,EAAI,OAAO,CAClD,MAAO,CAAE,aAAc,CAAC,GAAG,EAAM,EAAS,CAAE,OAAQ,EAAK,OAAS,EAAG,CAIvE,SAAS,GAAY,EAAY,EAAqB,CAIpD,OAHI,aAAa,MAAQ,aAAa,KAC7B,EAAE,SAAS,GAAK,EAAE,SAAS,CAE7B,OAAO,GAAG,EAAG,EAAE,CAIxB,SAAS,GAAS,EAAc,EAAuB,CACrD,IAAM,EAAO,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,EAAE,CAAE,GAAG,OAAO,KAAK,EAAE,CAAC,CAAC,CAC5D,IAAK,IAAM,KAAO,EAChB,GAAI,CAAC,GAAY,EAAE,GAAyB,EAAE,GAAwB,CACpE,MAAO,GAGX,MAAO,GAST,IAAa,IACX,EACA,EAAiC,GACjC,EAA8B,EAAE,CAChC,EAAyB,IACtB,CAIH,IAAM,GAAA,EAAA,EAAA,QAAoB,EAAQ,CAClC,EAAW,QAAU,EAMrB,IAAM,GAAA,EAAA,EAAA,QAAgB,EAAI,CAC1B,EAAO,QAAU,EACjB,GAAM,CAAC,EAAK,IAAA,EAAA,EAAA,UAA8B,GAAU,CAG9C,GAAA,EAAA,EAAA,aAAgC,GAAqB,EAAa,CAAE,CAAC,EAAa,CAAC,CAOnF,GAAA,EAAA,EAAA,QAA8C,KAAK,CACnD,GAAA,EAAA,EAAA,cACJ,EAAgB,UAAY,IAAoB,CACzC,GAA4B,EAAgB,QAAS,EAAO,EAAI,EACtE,CAAC,EAAO,EAAI,CAAC,CAKV,GAAA,EAAA,EAAA,QAAqB,EAAa,CACxC,EAAY,QAAU,EAItB,IAAM,GAAA,EAAA,EAAA,aAA0B,GAAY,EAAc,EAAI,CAAE,CAAC,EAAc,EAAI,CAAC,CAO9E,GAAA,EAAA,EAAA,cACH,EAAQ,IAAsB,CAC7B,IAAM,EAAO,EAAY,QAAQ,IAAI,EAAG,CACxC,GAAI,CAAC,EACH,OAEF,GAAM,CAAE,YAAW,WAAY,GAAc,EAAM,EAAQ,EAAO,QAAQ,CACpE,EAAsB,CAAE,GAAG,EAAM,YAAW,UAAS,CAK3D,GAAI,GAAS,EAAU,EAAK,CAC1B,OAGF,IAAM,EAA0B,CAAC,CAAE,KAAM,SAAU,KAAM,EAAU,CAAC,CACpE,GAAI,EAAgB,KAAO,EAAG,CAG5B,IAAM,EAAU,GAAU,EAAY,QAAQ,CAC9C,EAAQ,IAAI,EAAI,EAAS,CACzB,IAAM,EAAc,GAAmB,EAAS,EAAiB,EAAI,EAAO,QAAQ,CACpF,IAAK,IAAM,KAAQ,EAAY,QAAQ,CACrC,EAAS,KAAK,CAAE,KAAM,SAAU,OAAM,CAAC,CAG3C,OAAwB,EAAQ,GAAS,GAAkB,EAAM,EAAS,CAAC,CAAC,EAE9E,CAAC,EAAgB,CAClB,CAEK,GAAA,EAAA,EAAA,cACH,EAAQ,IAAqB,CAE5B,IAAM,EAAO,EAAY,QAAQ,IAAI,EAAG,CACxC,GAAI,CAAC,EACH,OAGF,IAAM,EAAsB,CAAE,GAAG,EAAM,CAevC,GAdI,EAAM,OAAS,IAAA,KACjB,EAAS,KAAO,EAAM,MAEpB,EAAM,YACR,EAAS,UAAY,EAAM,WAEzB,EAAM,UACR,EAAS,QAAU,EAAM,SAEvB,EAAM,WAAa,IAAA,KACrB,EAAS,SAAW,EAAM,UAIxB,GAAS,EAAU,EAAK,CAC1B,OAGF,IAAM,EAA0B,CAAC,CAAE,KAAM,SAAU,KAAM,EAAU,CAAC,CAMpE,IADc,EAAM,YAAc,IAAA,IAAa,EAAM,UAAY,IAAA,KACpD,EAAgB,KAAO,EAAG,CAGrC,IAAM,EAAU,GAAU,EAAY,QAAQ,CAC9C,EAAQ,IAAI,EAAI,EAAS,CACzB,IAAM,EAAc,GAAmB,EAAS,EAAiB,EAAI,EAAO,QAAQ,CACpF,IAAK,IAAM,KAAQ,EAAY,QAAQ,CACrC,EAAS,KAAK,CAAE,KAAM,SAAU,OAAM,CAAC,CAI3C,OAAwB,EAAQ,GAAS,GAAkB,EAAM,EAAS,CAAC,CAAC,EAE9E,CAAC,EAAgB,CAClB,CAEK,GAAA,EAAA,EAAA,cAA0B,EAAiB,IAAwB,EAKvE,EAAA,EAAA,eAAgB,CACd,EAAQ,GAAS,GAAkB,EAAM,CAAC,CAAE,KAAM,SAAU,OAAM,UAAS,CAAC,CAAC,CAAC,EAC9E,CACF,EAAW,QAAQ,eAAe,EAAM,EAAQ,EAC/C,EAAE,CAAC,CAEA,GAAA,EAAA,EAAA,aAA0B,GAAW,CACzC,OAAwB,EAAQ,GAAS,GAAkB,EAAM,CAAC,CAAE,KAAM,SAAU,KAAI,CAAC,CAAC,CAAC,CAAC,CAC5F,EAAW,QAAQ,eAAe,EAAG,EACpC,EAAE,CAAC,CAEA,GAAA,EAAA,EAAA,iBAAyB,CAC7B,OACE,EAAQ,GAAU,EAAK,OAAS,EAAI,CAAE,GAAG,EAAM,OAAQ,EAAK,OAAS,EAAG,CAAG,EAAM,CAClF,EACA,EAAE,CAAC,CAEA,GAAA,EAAA,EAAA,iBAAyB,CAC7B,OACE,EAAQ,GACN,EAAK,OAAS,EAAK,aAAa,OAAS,CAAE,GAAG,EAAM,OAAQ,EAAK,OAAS,EAAG,CAAG,EACjF,CACF,EACA,EAAE,CAAC,CAEA,EAAU,EAAI,OAAS,EACvB,EAAU,EAAI,OAAS,EAAI,aAAa,OAExC,GAAA,EAAA,EAAA,QAAsB,EAAU,CACtC,EAAa,QAAU,EAEvB,IAAM,GAAA,EAAA,EAAA,QAAqB,EAAI,CAS/B,OARA,EAAA,EAAA,eAAgB,CACV,EAAY,UAAY,IAG5B,EAAY,QAAU,EACtB,EAAW,QAAQ,gBAAgB,EAAa,QAAQ,GACvD,CAAC,EAAI,CAAC,CAEF,CACL,YACA,aACA,aACA,aACA,aACA,OACA,OACA,UACA,UACD,EChQH,SAAgB,EAAgB,EAA8B,CAC5D,IAAM,GAAA,EAAA,EAAA,QAAa,EAAM,CAEzB,MADA,GAAI,QAAU,EACP,ECTT,SAAgB,GAAU,EAAwB,CAChD,IAAM,GAAA,EAAA,EAAA,aAA0B,CAC9B,IAAM,EAAM,IAAI,IAChB,IAAK,IAAM,KAAK,EACV,EAAE,UAAY,MAChB,EAAI,IAAI,EAAE,SAAS,CAGvB,OAAO,GACN,CAAC,EAAU,CAAC,CAET,CAAC,EAAc,IAAA,EAAA,EAAA,UAAqC,IAAI,IAAM,CAE9D,GAAA,EAAA,EAAA,aAA4B,GAAW,CAC3C,EAAiB,GAAS,CACxB,IAAM,EAAO,IAAI,IAAI,EAAK,CAM1B,OALI,EAAK,IAAI,EAAG,CACd,EAAK,OAAO,EAAG,CAEf,EAAK,IAAI,EAAG,CAEP,GACP,EACD,EAAE,CAAC,CAEA,EAAe,EAAa,EAAU,CAStC,GAAA,EAAA,EAAA,aACH,GAAW,CACV,EAAiB,GAAS,CACxB,GAAI,EAAK,OAAS,EAChB,OAAO,EAET,IAAM,EAAW,IAAI,IACrB,IAAK,IAAM,KAAK,EAAa,QAC3B,EAAS,IAAI,EAAE,GAAI,EAAE,CAEvB,IAAM,EAAO,IAAI,IAAI,EAAK,CACtB,EAAU,GACV,EAAM,EAAS,IAAI,EAAG,CAC1B,KAAO,GAAO,EAAI,UAAY,MACxB,EAAK,OAAO,EAAI,SAAS,GAC3B,EAAU,IAEZ,EAAM,EAAS,IAAI,EAAI,SAAS,CAElC,OAAO,EAAU,EAAO,GACxB,EAEJ,CAAC,EAAa,CACf,CAEK,GAAA,EAAA,EAAA,aAA4B,CAChC,IAAM,EAAW,IAAI,IACrB,IAAK,IAAM,KAAM,EACV,EAAa,IAAI,EAAG,EACvB,EAAS,IAAI,EAAG,CAGpB,OAAO,GACN,CAAC,EAAW,EAAa,CAAC,CAqB7B,MAAO,CAAE,cAAA,EAAA,EAAA,aAnB0B,CACjC,GAAI,EAAa,OAAS,EACxB,OAAO,EAET,IAAM,EAAkB,IAAI,IACtB,EAAsB,EAAE,CAC9B,IAAK,IAAM,KAAQ,EAAW,CAC5B,GACE,EAAK,UAAY,OAChB,EAAgB,IAAI,EAAK,SAAS,EAAI,EAAa,IAAI,EAAK,SAAS,EACtE,CACA,EAAgB,IAAI,EAAK,GAAG,CAC5B,SAEF,EAAO,KAAK,EAAK,CAEnB,OAAO,GACN,CAAC,EAAW,EAAa,CAEnB,CAAc,cAAa,YAAW,eAAc,kBAAiB,CCpFhF,IAAa,GACX,OAAO,OAAW,IAAc,EAAA,gBAAkB,EAAA,UCG9C,GAAgC,CACpC,UAAW,EACX,WAAY,EACZ,YAAa,EACb,aAAc,EACf,CAED,SAAS,GAAY,EAAqC,CACxD,MAAO,CACL,UAAW,EAAG,UACd,WAAY,EAAG,WACf,YAAa,EAAG,YAChB,aAAc,EAAG,aAClB,CAGH,SAAS,GAAY,EAAoB,EAAoB,EAAmC,CAO9F,OANI,EAAE,YAAc,EAAE,WAAa,EAAE,eAAiB,EAAE,aAC/C,GAEJ,EAGE,EAAE,aAAe,EAAE,YAAc,EAAE,cAAgB,EAAE,YAFnD,GAsBX,SAAgB,GACd,EACA,CAAE,kBAAkB,IAAoC,EAAE,CACE,CAC5D,IAAM,GAAA,EAAA,EAAA,QAAiC,KAAK,CACtC,EAAqB,EAAa,EAAgB,CAElD,CAAC,EAAU,IAAA,EAAA,EAAA,UAAyC,GAAa,CAGjE,GAAA,EAAA,EAAA,iBAAoC,CACpC,EAAS,UAAY,OAGzB,EAAS,QAAU,0BAA4B,CAC7C,EAAS,QAAU,KACnB,IAAM,EAAK,EAAU,QACrB,GAAI,CAAC,EACH,OAEF,IAAM,EAAO,GAAY,EAAG,CAC5B,EAAa,GAAU,GAAY,EAAM,EAAM,EAAmB,QAAQ,CAAG,EAAO,EAAM,EAC1F,GACD,CAAC,EAAW,EAAmB,CAAC,CAgCnC,OA3BA,OAAgC,CAC9B,IAAM,EAAK,EAAU,QAChB,GAGL,EAAa,GAAS,CACpB,IAAM,EAAO,GAAY,EAAG,CAC5B,OAAO,GAAY,EAAM,EAAM,EAAmB,QAAQ,CAAG,EAAO,GACpE,EACD,CAAC,EAAU,CAAC,EAEf,EAAA,EAAA,eAAgB,CACd,IAAM,EAAK,EAAU,QACrB,GAAI,CAAC,GAAM,OAAO,eAAmB,IACnC,OAEF,IAAM,EAAW,IAAI,eAAe,EAAgB,CAEpD,OADA,EAAS,QAAQ,EAAG,KACP,CACX,EAAS,YAAY,CACjB,EAAS,UAAY,OACvB,qBAAqB,EAAS,QAAQ,CACtC,EAAS,QAAU,QAGtB,CAAC,EAAiB,EAAU,CAAC,CAEzB,CAAE,WAAU,kBAAiB,CCpGtC,SAAgB,IAAgB,CAC9B,IAAM,GAAA,EAAA,EAAA,QAAqC,KAAK,CAC1C,GAAA,EAAA,EAAA,QAAiC,KAAK,CACtC,GAAA,EAAA,EAAA,QAAmB,GAAM,CAEzB,CAAE,WAAU,mBAAoB,GAAmB,EAAQ,CAwBjE,MAAO,CAAE,cAAa,UAAS,kBAAA,EAAA,EAAA,iBAtBY,CACrC,EAAU,SAGV,CAAC,EAAY,SAAW,CAAC,EAAQ,UAGrC,EAAU,QAAU,GACpB,EAAQ,QAAQ,UAAY,EAAY,QAAQ,UAChD,EAAU,QAAU,GACpB,GAAiB,GAChB,CAAC,EAAgB,CAWW,CAAkB,cAAA,EAAA,EAAA,iBATV,CACjC,EAAQ,SAAW,EAAY,SAAW,CAAC,EAAU,UACvD,EAAU,QAAU,GACpB,EAAY,QAAQ,UAAY,EAAQ,QAAQ,UAChD,EAAU,QAAU,IAEtB,GAAiB,EAChB,CAAC,EAAgB,CAE6B,CAAc,WAAU,CC9B3E,SAAgB,GACd,EACiC,CACjC,IAAM,GAAA,EAAA,EAAA,QAAa,EAAG,CACtB,EAAI,QAAU,EACd,IAAM,GAAA,EAAA,EAAA,cAAsB,GAAG,IAAY,EAAI,UAAU,GAAG,EAAK,CAAO,EAAE,CAAC,CACtE,KAGL,OAAO,ECNT,SAAgB,GACd,EACA,EACA,EACA,EACA,EAAS,EACD,CACR,IAAM,EAAU,EAAa,EAO7B,OANI,EAAQ,EAAS,EACZ,KAAK,IAAI,EAAG,EAAQ,EAAO,CAEhC,EAAQ,EAAO,EAAS,EACnB,EAAQ,EAAO,EAAS,EAE1B,ECjBT,SAAgB,GACd,EACA,EAA+B,EAAE,CACjC,EACA,EACA,EAAqB,MACT,CAQZ,IAAM,EAAY,EAAS,WAAa,EAAK,UACvC,EAAU,EAAS,SAAW,EAAK,SAAW,EAC9C,EAAW,EAAW,EAAQ,EAAW,EAAK,CAC9C,EAAS,EAAW,EAAQ,EAAS,EAAK,CAIhD,MAAO,CACL,KAJW,EAAW,EAKtB,OAJa,EAAS,GAAY,EAKlC,SAAU,EAAS,UAAY,EAAK,UAAY,EACjD,CAGH,SAAgB,GACd,EACA,EACA,EACA,EAAqB,MACf,CACN,OAAO,EAAa,EAAQ,EAAM,EAAW,EAAS,CCnCxD,IAAa,GAA0B,CACrC,CACE,KAAM,QACN,KAAM,EACN,OAAS,GAAY,EAAE,eAAe,IAAA,GAAW,CAAE,MAAO,OAAQ,KAAM,UAAW,CAAC,CACrF,CACD,CACE,KAAM,MACN,KAAM,EACN,OAAS,GAAY,OAAO,EAAE,SAAS,CAAC,CACzC,CACF,CAQD,SAAgB,GAAkB,EAAgC,CAChE,OAAQ,GAAU,IAAgB,GAAG,GAAG,EAAE,MAAQ,MAOpD,SAAgB,GAAkB,EAA0B,CAC1D,OAAQ,GAAU,IAAgB,GAAG,GAAG,EAAE,MAAQ,ECTpD,SAAgB,GACd,EACA,EACA,EACa,CACb,IAAM,EAAQ,EAAe,EAAM,CAInC,OAHK,EAGE,GAAgB,EAAM,IAAK,GAAkB,EAAO,CAAE,EAAK,GAAkB,EAAO,CAAC,CAFnF,KAuBX,SAAgB,GAAgB,EAAW,EAAoB,EAAa,EAAoB,CAC9F,OAAO,EAAY,EAAQ,EAAY,EAAK,EAAK,CAAE,EAAM,CAAC,EAAM,EAAK,CAAE,EAAK,CAO9E,SAAgB,GAAmB,EAA6B,EAAM,EAAG,EAA0B,CACjG,IAAM,EAAQ,EAAe,EAAM,CACnC,GAAI,CAAC,EACH,MAAO,EAAE,CAEX,IAAM,EAAO,GAAkB,EAAO,CAChC,EAAO,GAAkB,EAAO,CAChC,EAAQ,GAAgB,EAAM,IAAK,EAAM,EAAK,EAAK,CACnD,EAAM,EAAQ,EAAY,EAAM,IAAK,EAAK,CAAE,EAAM,EAAM,EAAK,CAEnE,OAAO,EAAW,EADJ,KAAK,MAAM,EAAW,EAAO,EAAK,EAAK,CAAG,EAAK,CAAG,EAChC,EAAM,EAAK,CC5B7C,SAAgB,GAAc,CAC5B,cACA,UACA,YACA,eACA,YACA,WACA,SACA,UACA,mBACkE,CAClE,IAAM,EAAe,EAAa,EAAU,CACtC,EAAkB,EAAa,EAAa,CAC5C,GAAA,EAAA,EAAA,YAAkE,GAAG,CAErE,GAAA,EAAA,EAAA,QAA6D,KAAK,CAElE,EAAoB,GAAwB,CAChD,IAAM,EAAK,EAAY,SAAW,EAAQ,QAC1C,GAAI,CAAC,EACH,OAEF,IAAM,EAAO,GACX,EAAQ,EACR,EACA,EAAG,UACH,EAAG,aACH,EACD,CACG,IAAS,EAAG,YACd,EAAG,UAAY,IAIb,EAAsB,GAA0B,CACpD,IAAM,EAAO,EAAQ,QACf,EAAS,GAAe,EAAgB,QAAS,EAAQ,EAAQ,CACvE,GAAI,CAAC,GAAQ,CAAC,EACZ,OAEF,GAAM,CAAE,OAAM,SAAU,GACtB,EACA,EAAE,CACF,EACA,EACA,GAAkB,EAAO,CAC1B,CACK,EAAW,GACf,EACA,EACA,EAAK,WACL,EAAK,YACL,EACD,CACG,IAAa,EAAK,aACpB,EAAK,WAAa,IA0CtB,MAtCA,GAAQ,SAAW,EAAI,IAAY,CACjC,GAAM,CAAE,WAAW,GAAM,aAAa,IAAU,GAAW,EAAE,CACvD,EAAQ,EAAgB,QAAQ,UAAW,GAAM,EAAE,KAAO,EAAG,CAEnE,GAAI,EAAQ,EAAG,CAOb,GAAI,CAAC,EAAa,QAAQ,KAAM,GAAM,EAAE,KAAO,EAAG,CAChD,OAEF,EAAQ,QAAU,CAAE,KAAI,UAAS,CACjC,EAAgB,EAAG,CACnB,OAGE,GACF,EAAiB,EAAM,CAErB,GACF,EAAmB,EAAgB,QAAQ,GAAQ,GAIvD,EAAA,EAAA,qBAAsB,CACpB,IAAM,EAAS,EAAQ,QAClB,IAKL,EAAQ,QAAU,KAClB,EAAQ,QAAQ,EAAO,GAAI,EAAO,QAAQ,GACzC,CAAC,EAAa,CAAC,EAElB,EAAA,EAAA,cAAoB,EAAQ,IAA4B,EAAQ,QAAQ,EAAI,EAAQ,CAAE,EAAE,CAAC,CC9F3F,SAAgB,GAAQ,CACtB,UACA,eACA,UACA,SACA,gBAC2B,CAC3B,IAAM,GAAA,EAAA,EAAA,aACH,GAAc,KAAK,IAAI,EAAG,KAAK,IAAI,EAAO,OAAS,EAAG,EAAE,CAAC,CAC1D,CAAC,EAAO,OAAO,CAChB,CACK,CAAC,EAAO,IAAA,EAAA,EAAA,cAA2B,EAAM,EAAa,CAAC,CAEvD,EAAW,EAAa,EAAM,CAC9B,EAAkB,EAAa,EAAa,CAC5C,EAAa,EAAa,EAAQ,CAClC,EAAY,EAAa,EAAO,CAChC,GAAA,EAAA,EAAA,QAAuC,KAAK,CAE5C,GAAA,EAAA,EAAA,cACH,EAAiB,IAAkB,CAClC,IAAM,EAAM,EAAS,QACf,EAAO,EAAM,EAAM,EAAM,CAC/B,GAAI,IAAS,EACX,OAEF,IAAM,EAAO,EAAQ,QACf,EAAQ,EAAU,QAAQ,GAC1B,EAAS,GAAe,EAAgB,QAAS,EAAM,OAAQ,EAAW,QAAQ,CACpF,GAAQ,EAEV,EAAQ,QAAU,CAChB,KAAM,EAAa,EAFR,GAAkB,EAAM,OAER,CAAM,EAAU,EAAM,SAAS,CAC1D,eAAgB,EAAU,EAAK,WAChC,CAED,EAAQ,QAAU,KAEpB,EAAS,EAAK,EAEhB,CAAC,EAAO,EAAS,EAAU,EAAiB,EAAY,EAAU,CACnE,CAEK,GAAA,EAAA,EAAA,iBAAkC,CACtC,IAAM,EAAO,EAAQ,QACrB,OAAO,EAAO,EAAK,WAAa,EAAK,YAAc,EAAI,GACtD,CAAC,EAAQ,CAAC,CAEP,GAAA,EAAA,EAAA,iBAA2B,EAAO,GAAe,CAAE,EAAE,CAAE,CAAC,EAAQ,EAAc,CAAC,CAC/E,GAAA,EAAA,EAAA,iBAA4B,EAAO,GAAe,CAAE,GAAG,CAAE,CAAC,EAAQ,EAAc,CAAC,CACjF,GAAA,EAAA,EAAA,aACH,GAAc,EAAO,GAAe,CAAE,EAAM,EAAE,CAAG,EAAS,QAAQ,CACnE,CAAC,EAAQ,EAAe,EAAO,EAAS,CACzC,CAsBD,OAlBA,EAAA,EAAA,qBAAsB,CACpB,IAAM,EAAS,EAAQ,QACvB,GAAI,IAAW,KACb,OAEF,EAAQ,QAAU,KAClB,IAAM,EAAO,EAAQ,QACf,EAAQ,EAAU,QAAQ,GAC1B,EAAS,GAAe,EAAgB,QAAS,EAAM,OAAQ,EAAW,QAAQ,CACxF,GAAI,CAAC,GAAQ,CAAC,EACZ,OAEF,IAAM,EAAO,GAAkB,EAAM,OAAO,CACtC,EAAkB,EAAW,EAAQ,EAAO,KAAM,EAAK,CAAG,EAAM,SACtE,EAAK,WAAa,KAAK,IAAI,EAAG,EAAkB,EAAO,eAAe,EAErE,CAAC,EAAM,CAAC,CAEJ,CACL,QACA,MAAO,EAAO,GACd,MAAO,EAAO,OACd,UAAW,EAAQ,EAAO,OAAS,EACnC,WAAY,EAAQ,EACpB,SACA,UACA,UACA,SACD,CC5HH,IAAM,GAAQ,GAAc,OAAO,EAAE,CAAC,SAAS,EAAG,IAAI,CAChD,GAAa,GAAY,OAAO,EAAE,aAAa,CAAC,CAChD,GAAgB,GAAY,IAAI,KAAK,MAAM,EAAE,UAAU,CAAG,EAAE,CAAG,IAC/D,GAAa,GAAY,EAAE,eAAe,IAAA,GAAW,CAAE,MAAO,OAAQ,KAAM,UAAW,CAAC,CACxF,GAAc,GAAY,EAAE,eAAe,IAAA,GAAW,CAAE,MAAO,QAAS,CAAC,CACzE,GAAc,GAAY,OAAO,EAAE,SAAS,CAAC,CAC7C,GAAc,GAAY,EAAE,eAAe,IAAA,GAAW,CAAE,QAAS,QAAS,IAAK,UAAW,CAAC,CAQpF,GAAmC,CAC9C,CACE,SAAU,GACV,OAAQ,CACN,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,GAAW,CAC5C,CAAE,KAAM,UAAW,KAAM,EAAG,OAAQ,GAAc,CACnD,CACF,CACD,CACE,SAAU,GACV,OAAQ,CACN,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,GAAW,CAC5C,CAAE,KAAM,QAAS,KAAM,EAAG,OAAQ,GAAY,CAC/C,CACF,CACD,CACE,SAAU,GACV,OAAQ,CACN,CAAE,KAAM,QAAS,KAAM,EAAG,OAAQ,GAAW,CAC7C,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,GAAY,CAC9C,CACF,CACD,CACE,SAAU,GACV,OAAQ,CACN,CAAE,KAAM,QAAS,KAAM,EAAG,OAAQ,GAAW,CAC7C,CAAE,KAAM,MAAO,KAAM,EAAG,OAAQ,GAAY,CAC7C,CACF,CACD,CACE,SAAU,GACV,OAAQ,CACN,CAAE,KAAM,MAAO,KAAM,EAAG,OAAQ,GAAY,CAC5C,CAAE,KAAM,OAAQ,KAAM,EAAG,OAxCZ,GAAY,GAAG,GAAK,EAAE,UAAU,CAAC,CAAC,KAwCH,CAC7C,CACF,CACF,CAGY,GAAqB,EAQlC,SAAgB,GACd,EACA,EACA,EACa,CAOb,OANI,GAAc,EAAW,OAAS,EAC7B,EAEL,CAAC,GAAU,IAAa,IAAA,GACnB,GAEF,GAAoB,KAAK,EAAO,IACrC,IAAA,EACI,CAAE,OAAQ,GAAU,EAAM,OAAQ,SAAU,GAAY,EAAM,SAAU,CACxE,EACL,CCxEH,IAAM,GAA2F,CAC/F,IAAK,CAAE,MAAO,KAAM,IAAK,KAAM,CAC/B,MAAO,CAAE,MAAO,KAAM,IAAK,KAAM,CAClC,CAcD,SAAgB,GAAkB,CAAE,cAAa,sBAI/C,CACA,IAAM,EAAwB,EAAa,EAAmB,CAExD,CAAC,EAAM,IAAA,EAAA,EAAA,UAAgD,KAAK,CAG5D,EAAU,EAAa,EAAK,CAC5B,GAAA,EAAA,EAAA,QAGI,KAAK,CACT,GAAA,EAAA,EAAA,QAAqC,KAAK,CAC1C,GAAA,EAAA,EAAA,QAAuD,KAAK,CAG5D,GAAA,EAAA,EAAA,iBAAuC,CAC3C,AAGE,EAAiB,WAFjB,OAAO,oBAAoB,YAAa,EAAiB,QAAQ,KAAK,CACtE,OAAO,oBAAoB,UAAW,EAAiB,QAAQ,GAAG,CACvC,MAEzB,EAAa,UAAY,OAC3B,qBAAqB,EAAa,QAAQ,CAC1C,EAAa,QAAU,OAExB,EAAE,CAAC,CAwDN,OArDA,EAAA,EAAA,eAAgB,EAAoB,CAAC,EAAmB,CAAC,CAqDlD,CAAE,OAAM,WAAA,EAAA,EAAA,aAlDZ,GAA+B,CAC9B,EAAQ,EAAM,CAKd,IAAM,EAAe,GAAkB,CACrC,EAAa,QAAU,CAAE,EAAG,EAAE,QAAS,EAAG,EAAE,QAAS,CACjD,EAAa,UAAY,OAG7B,EAAa,QAAU,0BAA4B,CACjD,EAAa,QAAU,KACvB,IAAM,EAAO,EAAY,QACnB,EAAO,EAAa,QAC1B,GAAI,CAAC,GAAQ,CAAC,EACZ,OAEF,IAAM,EAAO,EAAK,uBAAuB,CACzC,EAAS,GACP,EAAO,CAAE,GAAG,EAAM,SAAU,EAAK,EAAI,EAAK,KAAM,SAAU,EAAK,EAAI,EAAK,IAAK,CAAG,KACjF,EACD,GAGE,MAAkB,CACtB,EAAQ,KAAK,CACb,GAAoB,EAGtB,EAAiB,QAAU,CAAE,KAAM,EAAa,GAAI,EAAW,CAC/D,OAAO,iBAAiB,YAAa,EAAY,CACjD,OAAO,iBAAiB,UAAW,EAAU,EAE/C,CAAC,EAAoB,EAAY,CAgBpB,CAAW,SAAA,EAAA,EAAA,cAZvB,EAAqB,IAA+B,CACnD,IAAM,EAAU,EAAQ,QACxB,GAAI,GAAW,IAAa,MAAQ,GAAY,IAAa,EAAQ,WAAY,CAC/E,IAAM,EAAO,GAAe,EAAQ,QAAQ,GAC5C,EAAsB,UAAU,CAAE,KAAM,EAAQ,WAAY,GAAI,EAAU,OAAM,CAAC,CAEnF,EAAQ,KAAK,CACb,GAAoB,EAEtB,CAAC,EAAoB,EAAS,EAAsB,CAG5B,CAAS,CCtGrC,SAAgB,GAAe,EAAmC,CAChE,GAAM,CAAE,aAAY,aAAY,aAAY,OAAM,OAAM,aAAY,SAAQ,UAAS,WACnF,EAGF,OAAA,EAAA,EAAA,cACS,CACL,aACA,aACA,aACA,OACA,OACA,aACA,SACA,UACA,UACD,EACD,CAAC,EAAY,EAAY,EAAY,EAAM,EAAM,EAAY,EAAQ,EAAS,EAAQ,CACvF,CCRH,SAAgB,GAAa,CAC3B,SACA,WACA,SACA,oBACA,iBACiC,CACjC,OAAA,EAAA,EAAA,cACS,CACL,GAAG,EACH,SAAW,GAAoB,EAAc,UAAU,EAAK,CAC5D,WACA,SACA,OAAQ,CACN,QAAU,GAAoB,GAAa,EAAM,EAAkB,CACnE,SAAW,GAAoB,GAAkB,EAAM,EAAkB,CAC1E,CACF,EAGD,CAAC,EAAQ,EAAe,EAAU,EAAQ,EAAkB,CAC7D,CCKH,IAAa,IAAA,EAAA,EAAA,eAA4D,KAAK,CAE9E,SAAgB,IAAmC,CACjD,IAAM,GAAA,EAAA,EAAA,YAAiB,GAAmB,CAC1C,GAAI,CAAC,EACH,MAAU,MAAM,uDAAuD,CAEzE,OAAO,EAYT,IAAa,IAAA,EAAA,EAAA,eAAwD,GAAe,CAEpF,SAAgB,IAAsC,CACpD,OAAA,EAAA,EAAA,YAAkB,GAAmB,CAYvC,IAAa,IAAA,EAAA,EAAA,eAAwD,EAAe,CAEpF,SAAgB,IAA0C,CACxD,OAAA,EAAA,EAAA,YAAkB,GAAqB,CAUzC,IAAa,IAAA,EAAA,EAAA,eAA8C,GAAM,CAEjE,SAAgB,IAA4B,CAC1C,OAAA,EAAA,EAAA,YAAkB,GAAqB,CAczC,IAAa,IAAA,EAAA,EAAA,eAAkE,KAAK,CAEpF,SAAgB,IAAyC,CACvD,IAAM,GAAA,EAAA,EAAA,YAAiB,GAAsB,CAC7C,GAAI,CAAC,EACH,MAAU,MAAM,0DAA0D,CAE5E,OAAO,EAyBT,IAAa,IAAA,EAAA,EAAA,eAAsE,KAAK,CAExF,SAAgB,IAA6C,CAC3D,IAAM,GAAA,EAAA,EAAA,YAAiB,GAAwB,CAC/C,GAAI,CAAC,EACH,MAAU,MAAM,4DAA4D,CAE9E,OAAO,EAOT,IAAa,IAAA,EAAA,EAAA,eAAiD,KAAK,CAEnE,SAAgB,IAAgC,CAC9C,OAAA,EAAA,EAAA,YAAkB,GAAsB,CAe1C,IAAa,IAAA,EAAA,EAAA,eAA4D,KAAK,CAE9E,SAAgB,IAAmC,CACjD,IAAM,GAAA,EAAA,EAAA,YAAiB,GAAmB,CAC1C,GAAI,CAAC,EACH,MAAU,MAAM,uDAAuD,CAEzE,OAAO,EAMT,IAAa,IAAA,EAAA,EAAA,eAA6D,KAAK,CAE/E,SAAgB,IAAoC,CAClD,IAAM,GAAA,EAAA,EAAA,YAAiB,GAAqB,CAC5C,GAAI,CAAC,EACH,MAAU,MAAM,yDAAyD,CAE3E,OAAO,EAYT,IAAa,IAAA,EAAA,EAAA,eAAoE,KAAK,CAEtF,SAAgB,IAA2C,CACzD,IAAM,GAAA,EAAA,EAAA,YAAiB,GAAuB,CAC9C,GAAI,CAAC,EACH,MAAU,MAAM,2DAA2D,CAE7E,OAAO,EAQT,IAAa,IAAA,EAAA,EAAA,eAAgD,GAAM,CAEnE,SAAgB,IAA8B,CAC5C,OAAA,EAAA,EAAA,YAAkB,GAAuB,CAG3C,IAAa,IAAA,EAAA,EAAA,eAA6D,KAAK,CAE/E,SAAgB,IAAqD,CACnE,OAAA,EAAA,EAAA,YAAkB,GAAiB,CAerC,IAAa,IAAA,EAAA,EAAA,eAAwD,KAAK,CAE1E,SAAgB,IAA+B,CAC7C,IAAM,GAAA,EAAA,EAAA,YAAiB,GAAiB,CACxC,GAAI,CAAC,EACH,MAAU,MAAM,qDAAqD,CAEvE,OAAO,EC9MT,SAAgB,GAAc,CAC5B,QACA,YAAA,GACA,WACA,SACA,SACA,UAAA,EACA,aACA,mBACA,eACA,YAAY,GACZ,eAAe,GACf,eAAe,GACf,cACA,qBACA,qBACA,aAAc,EACd,eACA,aACA,gBACA,SACA,SACA,WACA,gBAAgB,GAChB,eAAe,MACf,WAAW,GACX,YACqB,CACrB,GAAM,CAAC,EAAY,KAAA,EAAA,EAAA,UAAqC,KAAK,CAEvD,GAAA,EAAA,EAAA,aAA4B,GAAc,EAAO,CAAE,CAAC,EAAO,CAAC,CAG5D,GAAmB,GAAoB,EAAS,CAChD,GAAA,EAAA,EAAA,cACG,CAAE,SAAU,GAAkB,eAAc,gBAAe,EAClE,CAAC,GAAkB,EAAc,EAAc,CAChD,CAKK,EAAgB,EAAa,EAAW,CAIxC,EAAoB,GAAiB,EAAY,CACjD,EAA2B,GAAiB,EAAmB,CAE/D,CACJ,YACA,aACA,aACA,WAAY,EACZ,aACA,OACA,OACA,WACA,YACE,GACF,EACA,EACA,CACE,aAAc,EACd,eACA,gBACD,CACD,EACD,CAEK,CAAE,gBAAc,eAAa,aAAW,gBAAc,mBAC1D,GAAU,EAAU,CAChB,CAAE,eAAa,WAAS,oBAAkB,eAAc,aAAa,IAAe,CACpF,IAAA,EAAA,EAAA,QAAqC,KAAK,CAS1C,EAAO,GAAQ,CACnB,WACA,gBACA,UACA,QAAA,EAAA,EAAA,aAPM,GAAkB,EAAY,EAAQ,EAAS,CACrD,CAAC,EAAY,EAAQ,EAAS,CAMtB,CACR,aAAc,GAAA,EACf,CAAC,CAII,EAAa,GAAc,CAC/B,eACA,WACA,YACA,gBACA,YACA,SAAU,EAAK,MAAM,SACrB,OAAQ,EAAK,MAAM,OACnB,UACA,kBACD,CAAC,CAII,GAAkB,EAAa,EAAa,EAClD,EAAA,EAAA,eAAgB,CACd,GAAgB,UAAU,CAAE,MAAO,EAAK,MAAO,MAAO,EAAK,MAAO,CAAC,EAClE,CAAC,EAAK,MAAO,EAAK,MAAO,GAAgB,CAAC,CAK7C,IAAM,GAAA,EAAA,EAAA,cACH,EAAiB,IAAwB,CACxC,EAAiB,EAAM,EAAQ,CAC/B,GAAc,EAAK,GAAG,CACtB,EAAW,EAAK,GAAG,EAErB,CAAC,EAAkB,EAAW,CAC/B,CAEK,CAAE,SAAQ,WAAS,WAAS,WAAW,EAIvC,GAAS,GAAe,CAC5B,aACA,aACA,aACA,OACA,OACA,aACA,SACA,WACA,WACD,CAAC,EACF,EAAA,EAAA,qBAAoB,MAAc,GAAQ,CAAC,GAAO,CAAC,CAEnD,IAAM,GAAY,GAAa,CAC7B,UACA,WACA,OAAQ,EACR,oBACA,gBACD,CAAC,CAEI,CAAE,QAAM,aAAW,YAAY,GAAkB,CAAE,eAAa,qBAAoB,CAAC,CAGrF,IAAA,EAAA,EAAA,cACG,CACL,YACA,SAAU,EAAK,MAAM,SACrB,OAAQ,EAAK,MAAM,OACnB,UACA,SACD,EACD,CAAC,EAAW,EAAK,MAAO,EAAS,EAAO,CACzC,CAEK,IAAA,EAAA,EAAA,cACG,CACL,SACA,WACA,UACA,aAAc,EACd,gBAAiB,EAClB,EACD,CAAC,EAAQ,GAAS,GAAQ,EAAW,EAAa,CACnD,CAEK,IAAA,EAAA,EAAA,cACG,CAAE,YAAW,gBAAc,eAAa,aAAW,WAAS,WAAS,EAC5E,CAAC,EAAW,GAAc,GAAa,GAAW,GAAS,GAAQ,CACpE,CAGK,IAAA,EAAA,EAAA,cACG,CACL,aACA,aACA,aACA,aACA,OACA,OACA,aACA,iBACA,gBACA,YAAa,EACb,aACD,EACD,CACE,EACA,EACA,EACA,EACA,EACA,EACA,GACA,GACA,EACA,EACD,CACF,CAGK,IAAA,EAAA,EAAA,cACG,CAAE,eAAa,WAAS,eAAa,oBAAkB,eAAc,EAC5E,CAAC,GAAa,GAAS,GAAkB,EAAa,CACvD,CAEK,IAAA,EAAA,EAAA,cACG,CACL,eACA,mBAAoB,EACpB,aACA,WACD,EACD,CAAC,EAAc,EAA0B,GAAW,GAAQ,CAC7D,CAID,OACE,EAAA,EAAA,KAAC,GAAmB,SAApB,CAA6B,MAAO,aAClC,EAAA,EAAA,KAAC,GAAqB,SAAtB,CAA+B,MAAO,YACpC,EAAA,EAAA,KAAC,GAAmB,SAApB,CAA6B,MAAO,YAClC,EAAA,EAAA,KAAC,GAAqB,SAAtB,CAA+B,MAAO,YACpC,EAAA,EAAA,KAAC,GAAiB,SAAlB,CAA2B,MAAO,aAChC,EAAA,EAAA,KAAC,GAAmB,SAApB,CAA6B,MAAO,aAClC,EAAA,EAAA,KAAC,GAAwB,SAAzB,CAAkC,MAAO,aACvC,EAAA,EAAA,KAAC,GAAuB,SAAxB,CAAiC,MAAO,aACtC,EAAA,EAAA,KAAC,GAAsB,SAAvB,CAAgC,MAAO,aACrC,EAAA,EAAA,KAAC,GAAsB,SAAvB,CAAgC,MAAO,YACrC,EAAA,EAAA,KAAC,GAAuB,SAAxB,CAAiC,MAAO,KAAS,eAC/C,EAAA,EAAA,KAAC,GAAqB,SAAtB,CAA+B,MAAO,aACpC,EAAA,EAAA,KAAC,GAAiB,SAAlB,CAA2B,MAAO,GAC/B,WACyB,CAAA,CACE,CAAA,CACA,CAAA,CACH,CAAA,CACF,CAAA,CACD,CAAA,CACD,CAAA,CACP,CAAA,CACJ,CAAA,CACE,CAAA,CACJ,CAAA,CACA,CAAA,CACJ,CAAA,CC3OlC,IAAM,IAAA,EAAA,EAAA,eAAmD,EAAE,CAAC,CAE5D,SAAgB,GAAmB,CACjC,QACA,YAIC,CACD,OAAO,EAAA,EAAA,KAAC,GAAkB,SAAnB,CAAmC,QAAQ,WAAsC,CAAA,CAI1F,SAAgB,GAAiC,CAC/C,OAAA,EAAA,EAAA,YAAkB,GAAkB,CClFtC,SAAS,GAAE,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,GAAa,OAAO,GAAjB,UAA8B,OAAO,GAAjB,SAAmB,GAAG,UAAoB,OAAO,GAAjB,SAAmB,GAAG,MAAM,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAE,EAAE,GAAG,IAAI,IAAI,GAAG,KAAK,GAAG,QAAQ,IAAI,KAAK,EAAE,EAAE,KAAK,IAAI,GAAG,KAAK,GAAG,GAAG,OAAO,EAAE,SAAgB,IAAM,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,OAAO,EAAE,EAAE,KAAK,EAAE,UAAU,MAAM,EAAE,GAAE,EAAE,IAAI,IAAI,GAAG,KAAK,GAAG,GAAG,OAAO,EC6B9W,SAAgB,EAId,EACA,EACA,EACO,CACP,IAAM,EAAW,OAAO,GAAc,WAAa,EAAU,EAAW,CAAG,EAC3E,GAAI,CAAC,EACH,OAAO,EAET,GAAM,CAAE,YAAW,QAAO,GAAG,GAAS,EACtC,MAAO,CACL,GAAG,EACH,GAAG,EACH,UAAW,GAAK,EAAc,UAAW,EAAU,CACnD,MAAO,CAAE,GAAG,EAAc,MAAO,GAAG,EAAO,CAC5C,qHE0CH,SAAS,GAAW,EAAe,EAAuB,CACxD,IAAM,EAAkB,EAAE,CAC1B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,IAAM,EAAO,EAAM,GACb,EAAM,EAAU,EAAM,EAAM,KAAM,EAAM,KAAK,CAC7C,EAAO,EAAO,EAAO,OAAS,GAChC,GAAQ,EAAK,MAAQ,EACvB,EAAK,OAAS,EAEd,EAAO,KAAK,CAAE,MAAK,MAAO,EAAM,WAAY,EAAG,MAAO,EAAG,CAAC,CAG9D,OAAO,EAST,SAAS,GAAW,EAAiB,EAA8C,CACjF,GAAI,CAAC,EACH,MAAO,CAAE,MAAO,EAAG,IAAK,EAAO,OAAQ,CAEzC,IAAI,EAAK,EACL,EAAK,EAAO,OAChB,KAAO,EAAK,GAAI,CACd,IAAM,EAAO,EAAK,GAAO,EACnB,EAAQ,EAAO,GACjB,EAAM,WAAa,EAAM,OAAS,EAAS,MAC7C,EAAK,EAAM,EAEX,EAAK,EAGT,IAAI,EAAM,EACV,KAAO,EAAM,EAAO,QAAU,EAAO,GAAM,WAAa,EAAS,KAC/D,GAAO,EAET,MAAO,CAAE,MAAO,EAAI,MAAK,CAG3B,SAAgB,GAAY,CAC1B,QACA,QACA,WACA,YACA,oBAAoB,GACpB,WACA,WACA,MAAO,EACP,UAAW,GACQ,CACnB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,UAAU,aAAa,MACvD,CAAE,YAAa,IAAsB,CACrC,EAAY,GAAiB,EAAW,UAAU,aAAa,UAK/D,GAAA,EAAA,EAAA,aAAuB,GAAW,EAAO,EAAM,CAAE,CAAC,EAAO,EAAM,CAAC,CAChE,EAAU,GAAW,EAAQ,EAAS,CAEtC,EAAM,GAAO,KAAO,MACpB,EAAO,GAAO,MAAQ,MAEtB,EAAuC,CAC3C,QACA,WACA,YACA,oBACD,CAaD,OACE,EAAA,EAAA,KAAC,EAAD,CAAK,GAZU,EACf,CACE,UAAW,GAAO,IAClB,MAAO,CAAE,OAAQ,EAAW,CAC5B,KAAM,MACN,gBAAiB,EAClB,CACD,GAAW,IACX,EAIS,UACN,EAAO,MAAM,EAAQ,MAAO,EAAQ,IAAI,CAAC,IAAK,GAAU,CACvD,IAAM,EACJ,GAAqB,EACjB,EAAe,EAAU,EAAM,MAAO,EAAQ,EAAM,MAAO,EAAM,KAAM,EAAM,KAAK,CAAC,CACnF,CAAE,aAAc,GAAO,OAAQ,IAAA,GAAW,CAE1C,EAAa,EACf,EAAK,aACL,GAAqB,EAAU,EAAM,MAAM,CACzC,EAAyC,CAC7C,QACA,KAAM,EAAM,MACZ,WAAY,EAAM,WAClB,MAAO,EAAM,MACb,aAAc,EACd,iBAAkB,EAAc,EAAK,QAAU,UAAa,IAAA,GAC5D,UAAW,EACX,WACD,CAoBD,OAAO,EAAA,EAAA,KAAC,EAAD,CAAsB,GAlBX,EAChB,CACE,UAAW,GAAK,GAAO,KAAM,GAAc,GAAO,YAAY,CAC9D,MAAO,CACL,KAAM,EAAM,WAAa,EACzB,MAAO,EAAM,MAAQ,EACtB,CACD,SAAU,EAAM,OAAO,EAAM,MAAM,CACnC,KAAM,eACN,gBAAiB,EAAM,WAAa,EACpC,eAAgB,EAAM,MACtB,aAAc,EAAM,WAChB,EAAM,WAAW,EAAM,MAAM,CAC7B,GAAkB,EAAM,MAAO,EAAM,KAAM,EAAM,KAAK,CAC3D,CACD,GAAW,KACX,EAE+B,CAAa,CAA5B,EAAM,IAAsB,EAC9C,CACE,CAAA,CC1MV,SAAgB,GAAS,CACvB,WACA,YACA,SAAS,GACT,QACA,YACgB,CAChB,IAAM,EAAa,EAAM,OAAS,EAElC,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,GAAO,SAAU,MAAO,CAAE,MAAO,EAAY,CAAE,KAAK,oBACjE,EAAO,KAAK,EAAO,KAClB,EAAA,EAAA,KAAC,GAAD,CAES,QACA,QACG,WACC,YACX,kBAAmB,EAAM,OAAS,OAAS,EAAM,OAAS,EAChD,WACV,SAAU,EAAQ,EAClB,CARK,GAAG,EAAM,KAAK,GAAG,EAAM,OAQ5B,CACF,CACE,CAAA,CCpCV,IAAM,GAAO,GACP,GAAY,GAElB,SAAS,GAAoB,EAA4C,CACvE,IAAI,EAAO,EACX,KAAO,GAAM,CACX,IAAM,EAAQ,iBAAiB,EAAK,CAEpC,IAD8B,EAAM,YAAc,QAAU,EAAM,YAAc,WACnD,EAAK,YAAc,EAAK,YACnD,OAAO,EAET,EAAO,EAAK,cAEd,OAAO,SAAS,iBAGlB,SAAS,GAAO,EAAyD,CACvE,GAAI,IAAc,SAAS,iBACzB,MAAO,CAAE,KAAM,EAAG,MAAO,OAAO,WAAY,CAE9C,IAAM,EAAe,EAAU,uBAAuB,CACtD,MAAO,CAAE,KAAM,EAAa,KAAM,MAAO,EAAa,MAAO,CAG/D,SAAS,GAAU,EAAc,EAAe,EAAyB,CASvE,OARI,EAAU,EAAO,GACZ,CAAC,GAAY,KAAK,IAAI,GAAI,EAAO,GAAO,GAAW,GAAK,CAG7D,EAAU,EAAQ,GACb,GAAY,KAAK,IAAI,GAAI,GAAW,EAAQ,KAAS,GAAK,CAG5D,EAuBT,SAAgB,GAAc,CAAE,UAAS,YAAoD,CAC3F,IAAM,GAAA,EAAA,EAAA,QAAmC,CACvC,UAAW,KACX,aAAc,KACd,gBAAiB,EACjB,QAAS,EACT,MAAO,KACR,CAAC,CAII,GAAA,EAAA,EAAA,QAAqB,EAAS,CACpC,EAAY,QAAU,EACtB,IAAM,GAAA,EAAA,EAAA,iBAAiC,EAAY,SAAS,CAAE,EAAE,CAAC,CAE3D,GAAA,EAAA,EAAA,iBAAyB,CAC7B,IAAM,EAAI,EAAS,QACnB,GAAI,CAAC,EAAE,UAAW,CAChB,EAAE,MAAQ,KACV,OAEF,GAAM,CAAE,OAAM,SAAU,GAAO,EAAE,UAAU,CACrC,EAAQ,GAAU,EAAM,EAAO,EAAE,QAAQ,CAC3C,IAAU,IACZ,EAAE,UAAU,YAAc,GAE5B,EAAE,MAAQ,sBAAsB,EAAK,EACpC,EAAE,CAAC,CAEA,GAAA,EAAA,EAAA,iBAAyB,CAC7B,IAAM,EAAI,EAAS,QACf,EAAE,QAAU,MACd,qBAAqB,EAAE,MAAM,CAE3B,EAAE,cACJ,EAAE,aAAa,oBAAoB,SAAU,EAAa,CAE5D,EAAE,UAAY,KACd,EAAE,aAAe,KACjB,EAAE,MAAQ,MACT,CAAC,EAAa,CAAC,CAEZ,GAAA,EAAA,EAAA,aACH,GAAoB,CACnB,GAAI,CAAC,EACH,OAEF,IAAM,EAAI,EAAS,QACb,EAAY,GAAoB,EAAG,CACzC,EAAE,UAAY,EACd,EAAE,gBAAkB,GAAW,YAAc,EACzC,IACF,EAAE,aAAe,IAAc,SAAS,iBAAmB,OAAS,EAGpE,EAAE,aAAa,iBAAiB,SAAU,EAAc,CAAE,QAAS,GAAM,CAAC,CAC1E,EAAE,MAAQ,sBAAsB,EAAK,GAGzC,CAAC,EAAS,EAAc,EAAK,CAC9B,CAEK,GAAA,EAAA,EAAA,aAA0B,GAAoB,CAClD,EAAS,QAAQ,QAAU,GAC1B,EAAE,CAAC,CAEA,GAAA,EAAA,EAAA,iBAAmC,CACvC,IAAM,EAAI,EAAS,QACnB,OAAO,EAAE,UAAY,EAAE,UAAU,WAAa,EAAE,gBAAkB,GACjE,EAAE,CAAC,CAIN,OAFA,EAAA,EAAA,eAAgB,EAAM,CAAC,EAAK,CAAC,CAEtB,CAAE,QAAO,OAAM,aAAY,iBAAgB,CCzHpD,SAAgB,GAAW,CAAE,UAAS,SAAQ,QAAO,aAAa,IAA4B,CAC5F,IAAM,GAAA,EAAA,EAAA,QAAqB,GAAM,CAC3B,GAAA,EAAA,EAAA,QAA0B,KAAK,CAC/B,GAAA,EAAA,EAAA,QAAmB,EAAE,CACrB,GAAA,EAAA,EAAA,QAAwB,EAAE,CAC1B,GAAA,EAAA,EAAA,QAAsB,EAAE,CAExB,GAAA,EAAA,EAAA,QAAmB,EAAO,CAC1B,GAAA,EAAA,EAAA,QAAkB,EAAM,CAC9B,EAAU,QAAU,EACpB,EAAS,QAAU,EAGnB,IAAM,GAAA,EAAA,EAAA,YAAuC,GAAG,CAE1C,CACJ,MAAO,EACP,KAAM,EACN,aACA,kBACE,GAAc,CAChB,QAAS,EACT,aAAgB,EAAY,SAAS,CACtC,CAAC,CAEI,GAAA,EAAA,EAAA,iBAA6B,CACjC,GAAI,CAAC,EAAY,SAAW,EAAO,UAAY,KAC7C,OAGF,IAAM,EADc,EAAe,QAAU,EAAU,QAC1B,GAAgB,CAC7C,EAAa,QAAU,EACvB,EAAU,QAAQ,EAAQ,EAAO,QAAQ,EACxC,CAAC,EAAe,CAAC,CACpB,EAAY,QAAU,EAEtB,IAAM,GAAA,EAAA,EAAA,aACH,GAAwB,CACvB,EAAO,QAAU,EAAQ,EAAE,CAC3B,EAAU,QAAU,EAAE,QACtB,EAAe,QAAU,EAAE,QAC3B,EAAa,QAAU,EACvB,EAAY,QAAU,GACtB,EAAW,EAAE,QAAQ,CACrB,EAAgB,EAAE,cAA6B,CAC/C,EAAE,gBAAgB,CAClB,EAAE,iBAAiB,EAErB,CAAC,EAAS,EAAY,EAAgB,CACvC,CA6BD,OA3BA,EAAA,EAAA,eAAgB,CACd,IAAM,EAAe,GAAkB,CACjC,CAAC,EAAY,SAAW,EAAO,UAAY,OAG/C,EAAe,QAAU,EAAE,QAC3B,EAAW,EAAE,QAAQ,CACrB,GAAU,CACV,EAAE,gBAAgB,GAEd,MAAkB,CAClB,EAAY,SAAW,EAAO,UAAY,MAC5C,EAAS,UAAU,EAAa,QAAS,EAAO,QAAQ,CAE1D,EAAY,QAAU,GACtB,EAAO,QAAU,KACjB,GAAgB,EAIlB,OAFA,OAAO,iBAAiB,YAAa,EAAY,CACjD,OAAO,iBAAiB,UAAW,EAAU,KAChC,CACX,OAAO,oBAAoB,YAAa,EAAY,CACpD,OAAO,oBAAoB,UAAW,EAAU,CAChD,GAAgB,GAEjB,CAAC,EAAU,EAAY,EAAe,CAAC,CAEnC,uGEpEI,IAAA,EAAA,EAAA,eAAiE,KAAK,CAGtE,QAAA,EAAA,EAAA,YAAgE,GAAkB,CCT/F,SAAgB,GAAe,CAC7B,YACA,YAIC,CACD,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,UAAoB,GAAM,CAEjC,GAAA,EAAA,EAAA,cACG,CAAE,OAAM,UAAS,YAAW,EACnC,CAAC,EAAM,EAAU,CAClB,CAED,OAAO,EAAA,EAAA,KAAC,GAAkB,SAAnB,CAAmC,QAAQ,WAAsC,CAAA,CCH1F,SAAgB,GAAkB,CAAE,YAAqC,CACvE,IAAM,EAAU,IAAe,CACzB,EAAO,GAAS,MAAQ,GACxB,EAAU,GAAS,QACnB,EAAY,GAAS,UAgD3B,IAzCA,EAAA,EAAA,eAAgB,CACd,GAAI,CAAC,GAAQ,CAAC,EACZ,OAMF,IAAM,MAAsB,EAAQ,GAAM,CAIpC,EAAkB,GAAsB,CAC5C,IAAM,EAAO,GAAW,SAAS,uBAAuB,CAIpD,CAAC,GAAQ,EAAK,QAAU,GAAK,EAAK,SAAW,GAI/C,EAAM,SAAW,EAAK,MACtB,EAAM,SAAW,EAAK,OACtB,EAAM,SAAW,EAAK,KACtB,EAAM,SAAW,EAAK,QAEtB,EAAQ,GAAM,EAMlB,OAFA,SAAS,iBAAiB,SAAU,EAAe,CAAE,QAAS,GAAM,QAAS,GAAM,CAAC,CACpF,SAAS,iBAAiB,YAAa,EAAgB,CAAE,QAAS,GAAM,CAAC,KAC5D,CACX,SAAS,oBAAoB,SAAU,EAAe,CAAE,QAAS,GAAM,CAAC,CACxE,SAAS,oBAAoB,YAAa,EAAe,GAE1D,CAAC,EAAM,EAAS,EAAU,CAAC,CAK1B,CAAC,GAAW,EAAA,EAAA,EAAA,gBAAuC,EAAS,CAC9D,OAAO,EAGT,GAAM,CAAE,eAAc,gBAAiB,EAAS,MAEhD,OAAA,EAAA,EAAA,cAAoB,EAAU,CAC5B,aAAe,GAA2C,CACxD,IAAe,EAAM,CACrB,EAAQ,GAAK,EAEf,aAAe,GAA2C,CACxD,IAAe,EAAM,CACrB,EAAQ,GAAM,EAEjB,CAAmC,CCjFtC,IAAM,GAAgB,GAEhB,GAAc,EASpB,SAAS,GAAU,EAAgB,EAAc,EAAa,EAAqB,CACjF,IAAM,EAAQ,EAAS,GACjB,EAAY,EAAQ,GAAQ,EAAM,GACxC,OAAO,KAAK,IAAI,EAAY,EAAQ,EAAS,GAAgB,EAAM,EAAM,GAAY,CAGvF,IAAa,IACX,EACA,IACkB,CAelB,IAAM,GAAA,EAAA,EAAA,YAAqB,GAAmB,EAAE,QAC1C,CAAC,EAAkB,IAAA,EAAA,EAAA,UAA6C,CACpE,KAAM,MACN,IAAK,MACN,CAAC,CAEI,GAAA,EAAA,EAAA,kBAAoC,EAAiB,CAuD3D,OArDA,EAAA,EAAA,eAAgB,CAKd,GAAI,CAAC,EACH,OAGF,IAAM,EAAmB,GAAsB,CAC7C,GAAM,CAAE,UAAS,WAAY,EAEvB,EAAO,GAAS,SAAS,uBAAuB,CAChD,EACJ,GAAQ,EAAK,MAAQ,GAAK,EAAK,OAAS,EACpC,CAAE,KAAM,EAAK,KAAM,IAAK,EAAK,IAAK,MAAO,EAAK,MAAO,OAAQ,EAAK,OAAQ,CAC1E,CAAE,KAAM,EAAG,IAAK,EAAG,MAAO,OAAO,WAAY,OAAQ,OAAO,YAAa,CAY/E,GAJE,EAAU,EAAO,MACjB,EAAU,EAAO,OACjB,EAAU,EAAO,KACjB,EAAU,EAAO,OAEjB,OAGF,IAAM,EAAO,EAAW,SAAS,uBAAuB,CAClD,EAAQ,GAAM,OAAS,EACvB,EAAS,GAAM,QAAU,EAEzB,EAAO,GAAU,EAAS,EAAO,EAAO,KAAM,EAAO,MAAM,CAC3D,EAAM,GAAU,EAAS,EAAQ,EAAO,IAAK,EAAO,OAAO,CAKjE,EAAmB,GACjB,EAAS,OAAS,GAAQ,EAAS,MAAQ,EAAM,EAAW,CAAE,OAAM,MAAK,CAC1E,EAIH,OADA,OAAO,iBAAiB,YAAa,EAAgB,KACxC,CACX,OAAO,oBAAoB,YAAa,EAAgB,GAEzD,CAAC,EAAY,EAAS,EAAK,CAAC,CAExB,GClGT,SAAS,GAAW,EAAwB,CAK1C,OAJK,EAIE,EAAK,mBAAmB,IAAA,GAAW,CACxC,KAAM,UACN,MAAO,QACP,IAAK,UACN,CAAC,CAPO,IAmBX,SAAS,GAAgB,CACvB,OACA,WACA,aACA,YACA,QACA,GAAG,GAC8D,CACjE,IAAM,GAAA,EAAA,EAAA,QAAoC,KAAK,CACzC,EAAO,IAAe,EAAE,MAAQ,GAEhC,EAA6B,GAAmB,EAAK,EAAK,CAQhE,MAJI,CAAC,GAAQ,OAAO,SAAa,IACxB,MAGT,EAAA,EAAA,eACE,EAAA,EAAA,MAAC,MAAD,CACE,KAAK,UACA,MACL,UAAW,EAAY,GAAG,EAAO,QAAQ,GAAG,IAAc,EAAO,QACjE,MAAO,CAAE,GAAG,EAAO,GAAG,EAAa,CACnC,GAAI,WALN,EAOE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAO,cAAO,EAAK,KAAW,CAAA,EAC9C,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,EAAO,aAAvB,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAO,eAAO,QAAY,CAAA,EAC3C,EAAA,EAAA,KAAC,OAAD,CAAA,SAAO,GAAW,EAAK,UAAU,CAAQ,CAAA,CACrC,IACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,EAAO,aAAvB,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAO,eAAO,MAAU,CAAA,EACzC,EAAA,EAAA,KAAC,OAAD,CAAA,SAAO,GAAW,EAAW,CAAQ,CAAA,CACjC,IACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,EAAO,aAAvB,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAO,eAAO,WAAe,CAAA,EAC9C,EAAA,EAAA,MAAC,OAAD,CAAA,SAAA,CAAO,KAAK,MAAM,EAAS,CAAC,IAAQ,CAAA,CAAA,CAChC,GACF,GACN,SAAS,KACV,CAgBH,SAAgB,GAAgB,CAC9B,OACA,WACA,aACA,YACA,YACA,QACA,WACA,GAAG,GACuC,CAC1C,OACE,EAAA,EAAA,MAAC,GAAD,CAA2B,qBAA3B,EACE,EAAA,EAAA,KAAC,GAAD,CAAoB,WAA6B,CAAA,EACjD,EAAA,EAAA,KAAC,GAAD,CACQ,OACI,WACE,aACD,YACJ,QACP,GAAI,EACJ,CAAA,CACa,GC/FrB,SAAgB,GAAmB,CACjC,WACA,UACA,aAKC,CACD,IAAM,EAAgB,GAAe,CAAC,MAAM,QACtC,EAAU,GAAe,OAAO,QAMtC,MAJI,CAAC,GAAW,CAAC,EACR,GAIP,EAAA,EAAA,KAAC,EAAD,CACE,GAAI,EAAe,EAAE,CAAE,GAAe,WAAW,QAAS,EAAQ,CACvD,YACX,GAAI,EAEH,WACO,CAAA,CCcd,SAAgB,GAAa,CAC3B,OACA,MACA,QACA,SACA,WACA,aACA,YACA,QACA,QACA,SACA,YACA,UACA,eACA,eACA,WACA,GAAG,GACiB,CACpB,IAAM,GAAA,EAAA,EAAA,QAAgC,KAAK,CAErC,EAAW,CAAC,GAAU,CAAC,EACvB,EAAc,GAAQ,CAC1B,aAAgB,CAAE,MAAO,EAAY,EACrC,QAAS,EAAQ,CAAE,WAAY,IAAS,EAAQ,EAAO,CACvD,OAAQ,EAAQ,CAAE,WAAY,CAC5B,IAAM,EAAU,KAAK,OAAO,EAAQ,GAAU,EAAS,CAAG,EAC1D,IAAY,EAAQ,EAEtB,WAAY,GACb,CAAC,CAEI,EAAU,GAAQ,GAAU,GAElC,OACE,EAAA,EAAA,KAAC,GAAD,CAA6B,UAAS,UAAW,YAC/C,EAAA,EAAA,KAAC,MAAD,CACE,GAAI,EACJ,IAAK,EACM,YACX,MAAO,CAAE,OAAM,MAAK,QAAO,SAAQ,OAAQ,EAAW,UAAY,OAAQ,GAAG,EAAO,CAC7E,QACP,YAAa,EAAU,EAAc,IAAA,GACvB,eACA,eAEb,WACG,CAAA,CACa,CAAA,kFErDzB,SAAgB,GAAa,CAC3B,OACA,aACA,MACA,WACA,QACA,OACA,SACA,YACA,UACA,MAAO,EACP,UAAW,GACS,CACpB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,MAAM,cAAc,MACpD,EAAY,GAAiB,EAAW,MAAM,cAAc,UAE5D,EAAqC,CAAE,OAAM,QAAO,CAEpD,EAAO,GAAO,MAAQ,GACtB,EAAQ,GAAO,OAAS,MAKxB,EAAY,EAChB,CAAE,UAAW,GAAO,UAAW,GAAG,EAAM,MAAO,EAAO,EAAK,MAAQ,EAAO,CAC1E,GAAW,KACX,EACD,CAEK,EAAa,EACjB,CAAE,UAAW,GAAO,eAAgB,cAAe,GAAM,CACzD,GAAW,MACX,EACD,CAED,OACE,EAAA,EAAA,KAAC,EAAD,CACW,UACT,KAAM,EAAa,EAAO,EACrB,MACL,MAAO,EACP,OAAQ,EACE,WACV,WAAY,EACJ,SACG,YACX,GAAI,YAEJ,EAAA,EAAA,KAAC,EAAD,CAAO,GAAI,EAAc,CAAA,CACpB,CAAA,yGE7DX,SAAgB,GAAwB,CACtC,QACA,WACA,cACA,cACA,MAAO,EACP,UAAW,GACoB,CAC/B,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,MAAM,yBAAyB,MAC/D,EAAY,GAAiB,EAAW,MAAM,yBAAyB,UAEvE,GAAc,EAAgB,IAClC,KAAK,IAAI,KAAK,IAAI,EAAG,EAAa,EAAO,CAAE,EAAY,CAEnD,EAAc,GAAQ,CAC1B,aAAgB,CAAE,WAAY,EAAO,EACrC,QAAS,EAAQ,CAAE,gBAAiB,EAAS,EAAW,EAAQ,EAAW,CAAC,CAC5E,OAAQ,EAAQ,CAAE,gBAAiB,IAAc,EAAW,EAAQ,EAAW,CAAC,CACjF,CAAC,CAEI,EAAgD,CAAE,QAAO,cAAa,CAe5E,OAAO,EAAA,EAAA,KAbM,GAAO,MAAQ,MAarB,CAAM,GAXK,EAChB,CACE,UAAW,GAAO,wBAClB,cAAe,GACf,SAAU,GACV,cACD,CACD,GAAW,KACX,EAGe,CAAa,CAAA,CCpChC,SAAgB,GAAY,CAC1B,WACA,MAAO,EACP,SACA,mBACA,gBACA,MAAO,EACP,UAAW,GACQ,CACnB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,MAAM,aAAa,MACnD,EAAY,GAAiB,EAAW,MAAM,aAAa,UAE3D,EAAS,EAAW,IAAO,EAC3B,EAAc,GAAsB,EAAW,EAAe,IAE9D,EAAoC,CAAE,WAAU,QAAO,SAAQ,CAUrE,OACE,EAAA,EAAA,KATW,GAAO,MAAQ,MAS1B,CAAM,GAPU,EAChB,CAAE,UAAW,GAAO,YAAa,MAAO,CAAE,QAAO,SAAQ,CAAE,CAC3D,GAAW,KACX,EAIU,UACP,IACC,EAAA,EAAA,KAAC,GAAD,CACS,QACM,cACb,SAAW,GAAa,EAAiB,EAAW,EAAS,CAAC,CAC9D,YACE,EAAiB,GAAa,EAAc,EAAW,EAAS,CAAC,CAAG,IAAA,GAEtE,CAAA,CAEC,CAAA,qHEhBX,SAAgB,GAAW,CACzB,QACA,SACA,OACA,MACA,WACA,QACA,OACA,WACA,mBACA,gBACA,SACA,YACA,UACA,MAAO,EACP,UAAW,GACO,CAClB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,MAAM,YAAY,MAClD,EAAY,GAAiB,EAAW,MAAM,YAAY,UAE1D,EAAmC,CAAE,QAAO,SAAQ,WAAU,QAAO,CAErE,EAAO,GAAO,MAAQ,GACtB,EAAQ,GAAO,OAAS,MACxB,EAAQ,GAAO,OAAS,MAExB,EAAY,EAChB,CACE,UAAW,GAAO,QAClB,MAAO,CAAE,WAAY,GAAG,EAAO,IAAK,CACpC,GAAG,EACJ,CACD,GAAW,KACX,EACD,CAEK,EAAa,EACjB,CAAE,UAAW,GAAO,aAAc,cAAe,GAAM,CACvD,GAAW,MACX,EACD,CAEK,EAAa,EACjB,CAAE,UAAW,GAAO,eAAgB,SAAU,EAAO,CACrD,GAAW,MACX,EACD,CAED,OACE,EAAA,EAAA,KAAC,EAAD,CACW,UACH,OACD,MACE,QACC,SACE,WACV,WAAY,EACJ,SACG,YACX,GAAI,YAEJ,EAAA,EAAA,MAAC,EAAD,CAAO,GAAI,WAAX,EACE,EAAA,EAAA,KAAC,GAAD,CACS,QACC,SACE,WACQ,mBACH,gBACf,CAAA,EACF,EAAA,EAAA,KAAC,EAAD,CAAO,GAAI,EAAc,CAAA,CACnB,GACH,CAAA,sMEtFX,SAAgB,GAAY,CAC1B,QACA,OACA,WACA,WACA,cACA,MAAO,EACP,UAAW,GACQ,CACnB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,MAAM,aAAa,MACnD,EAAY,GAAiB,EAAW,MAAM,aAAa,UAE3D,EAAyB,GAAQ,CACrC,aAAgB,CAAE,WAAY,EAAO,UAAW,EAAM,EACtD,QAAS,EAAQ,CAAE,aAAY,eAAgB,CAC7C,IAAM,EAAe,KAAK,IAAI,EAAQ,EAAW,CAGjD,EAFiB,EAAa,EACd,EAAY,EACD,EAE7B,OAAQ,EAAQ,CAAE,aAAY,eAAgB,CAE5C,IAAM,EAAU,EADK,KAAK,IAAI,EAAQ,EACV,CAC5B,EAAY,QAAS,KAAK,MAAM,EAAU,EAAS,CAAG,EAAS,EAElE,CAAC,CAEI,EAAuB,GAAQ,CACnC,aAAgB,CAAE,WAAY,EAAO,UAAW,EAAM,EACtD,QAAS,EAAQ,CAAE,aAAY,eAAgB,CAE7C,EADiB,KAAK,IAAI,EAAG,EAAa,EACjC,CAAU,EAAU,EAE/B,OAAQ,EAAQ,CAAE,aAAY,eAAgB,CAC5C,IAAM,EAAW,EAAY,KAAK,IAAI,EAAG,EAAa,EAAO,CAC7D,EAAY,MAAO,KAAK,MAAM,EAAW,EAAS,CAAG,EAAS,EAEjE,CAAC,CAEI,EAAoC,CAAE,QAAO,OAAM,CAEnD,EAAc,GAAO,aAAe,SACpC,EAAY,GAAO,WAAa,SAEhC,EAAmB,EACvB,CACE,KAAM,SACN,cAAe,GACf,SAAU,GACV,UAAW,GAAK,GAAO,QAAS,GAAO,aAAa,CACpD,YAAa,EACd,CACD,GAAW,YACX,EACD,CAEK,EAAiB,EACrB,CACE,KAAM,SACN,cAAe,GACf,SAAU,GACV,UAAW,GAAK,GAAO,QAAS,GAAO,WAAW,CAClD,YAAa,EACd,CACD,GAAW,UACX,EACD,CAED,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAD,CAAa,GAAI,EAAoB,CAAA,EACrC,EAAA,EAAA,KAAC,EAAD,CAAW,GAAI,EAAkB,CAAA,CAChC,CAAA,CAAA,CCrDP,SAAgB,GAAQ,CACtB,QACA,SACA,OACA,MACA,WACA,QACA,OACA,WAAW,GACX,mBACA,gBACA,WACA,cACA,SACA,YACA,UACA,MAAO,EACP,UAAW,GACI,CACf,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,MAAM,SAAS,MAC/C,EAAY,GAAiB,EAAW,MAAM,SAAS,UAEvD,EAAgC,CAAE,QAAO,SAAQ,WAAU,QAAO,CAElE,EAAO,GAAO,MAAQ,GACtB,EAAQ,GAAO,OAAS,MACxB,EAAQ,GAAO,OAAS,MAExB,EAAY,EAChB,CACE,UAAW,GAAG,GAAO,KAAK,oBAC1B,MAAO,CAAE,WAAY,GAAG,EAAO,IAAK,CACpC,GAAG,EACJ,CACD,GAAW,KACX,EACD,CAEK,EAAa,EACjB,CAAE,UAAW,GAAO,UAAW,cAAe,GAAM,CACpD,GAAW,MACX,EACD,CAKK,EAAa,EACjB,CAAE,UAAW,GAAO,YAAa,MAAO,GAAM,MAAO,SAAU,EAAO,CACtE,GAAW,MACX,EACD,CAED,OACE,EAAA,EAAA,KAAC,EAAD,CACW,UACH,OACD,MACE,QACC,SACE,WACV,WAAY,EACJ,SACG,YACX,GAAI,YAEJ,EAAA,EAAA,MAAC,EAAD,CAAO,GAAI,WAAX,EACE,EAAA,EAAA,KAAC,GAAD,CACS,QACC,SACE,WACQ,mBACH,gBACf,CAAA,EACF,EAAA,EAAA,KAAC,EAAD,CAAO,GAAI,EAAc,CAAA,CACxB,GAAY,IACX,EAAA,EAAA,KAAC,GAAD,CACS,QACD,OACI,WACA,WACG,cACb,CAAA,CAEE,GACH,CAAA,+DEvIL,GAAA,GAAwC,EAuC9C,SAAgB,GAAiB,CAC/B,SACA,UACA,WACA,aACA,OACA,MAAO,EACP,UAAW,GACa,CACxB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,MAAM,kBAAkB,MACxD,EAAY,GAAiB,EAAW,MAAM,kBAAkB,UAEhE,CAAE,YAAW,WAAY,IAAoB,CAC7C,EAAa,IAAoB,CACjC,CAAE,eAAgB,IAAgB,CAElC,GAAkB,EAAqB,IAA6B,CACxE,IAAM,EAAO,EAAY,SAAS,uBAAuB,CACzD,GAAI,CAAC,EACH,MAAO,CAAE,EAAG,EAAG,EAAG,EAAG,CAGvB,IAAM,EADW,EAAE,cACI,uBAAuB,CAC9C,MAAO,CACL,EAAG,EAAM,KAAO,EAAM,MAAQ,EAAI,EAAK,KACvC,EAAG,EAAM,IAAM,EAAM,OAAS,EAAI,EAAK,IACxC,EAGG,GAAe,EAAqB,IAA4B,CACpE,EAAE,iBAAiB,CACnB,EAAE,gBAAgB,CAClB,GAAM,CAAE,IAAG,KAAM,EAAe,EAAG,EAAO,CAC1C,EAAU,CAAE,WAAY,EAAQ,SAAQ,OAAQ,EAAG,OAAQ,EAAG,SAAU,EAAG,SAAU,EAAG,CAAC,EAGrF,GAAa,EAAqB,IAA4B,CAC9D,IACF,EAAE,iBAAiB,CACnB,EAAQ,EAAQ,EAAO,GAIrB,EAAyC,CAC7C,SACA,UACA,WACA,aACA,OACA,aACD,CAEK,EAAc,GAAO,aAAe,MACpC,EAAY,GAAO,WAAa,MAEhC,EAAY,GAAQ,EAEpB,EAAmB,EACvB,CACE,cAAe,GACf,SAAU,GACV,UAAW,GAAK,GAAO,OAAQ,GAAa,GAAO,QAAQ,CAC3D,MAAO,CAAE,KAAM,EAAA,GAAiC,IAAK,EAAa,GAAe,CACjF,YAAc,GAAwB,EAAY,EAAG,QAAQ,CAC7D,UAAY,GAAwB,EAAU,EAAG,QAAQ,CAC1D,CACD,GAAW,YACX,EACD,CAEK,EAAiB,EACrB,CACE,cAAe,GACf,SAAU,GACV,UAAW,GAAK,GAAO,OAAQ,GAAa,GAAO,QAAQ,CAC3D,MAAO,CAAE,KAAM,EAAU,EAAU,IAAK,EAAa,GAAe,CACpE,YAAc,GAAwB,EAAY,EAAG,MAAM,CAC3D,UAAY,GAAwB,EAAU,EAAG,MAAM,CACxD,CACD,GAAW,UACX,EACD,CAED,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAD,CAAa,GAAI,EAAoB,CAAA,EACrC,EAAA,EAAA,KAAC,EAAD,CAAW,GAAI,EAAkB,CAAA,CAChC,CAAA,CAAA,8BErGM,IAAA,EAAA,EAAA,MAAW,SAAa,CACnC,OACA,QACA,SACA,WACA,YACA,OACA,WACA,aACA,WACA,WACA,cACA,kBACW,CACX,IAAM,EAAS,IAAgB,CACzB,EAAW,IAAkB,CAE7B,EADa,IACA,GAAe,EAAK,GAEjC,EAAoB,IAAsB,CAI1C,EAAU,GAAe,CAAC,MAAM,SAAS,OAAO,QAEhD,CAAE,OAAM,QAAO,YAAa,GAAkB,EAAM,GAAY,EAAE,CAAE,EAAQ,EAAU,EAAK,CAC3F,EAAM,EAAQ,EACd,EAAa,EACb,EAAY,EAAA,GACZ,EAAA,EAAqC,EAAY,EAQjD,EAAc,EAAK,OAAS,YAC5B,EAAa,EAAc,EAAa,EAAY,EAAI,EACxD,EAAc,EAAc,EAAY,EAAI,EAK5C,CAAC,GAAS,IAAA,EAAA,EAAA,UAAuB,GAAM,CAIvC,GAAU,IAAgC,CAC9C,UAAW,GAAS,EAAS,EAAQ,EAAU,EAAK,CACpD,QAAS,GAAS,EAAU,EAAO,EAAQ,EAAU,EAAK,CAC3D,EAEK,GAAY,EAAkB,KAAgC,CAClE,UAAW,GAAS,EAAS,EAAQ,EAAU,EAAK,CACpD,QAAS,GAAS,EAAU,EAAU,EAAQ,EAAU,EAAK,CAC9D,EAEK,EAAkB,GAAqB,CAC3C,EAAW,EAAK,GAAI,EAAM,EAGtB,GAAgB,EAAQ,IAAqB,EACjD,EAAA,EAAA,qBAAsB,CACpB,EAAS,EAAI,EAAM,CACnB,EAAW,EAAI,KAAK,EACpB,EASE,EAAgB,GAAsB,EAC1C,EAAA,EAAA,qBAAsB,CACpB,EAAS,EAAK,GAAI,EAAO,CACzB,EAAW,EAAK,GAAI,KAAK,EACzB,EAGE,EAAgB,IAAgC,CACpD,KAAM,OACN,UAAW,GAAS,EAAS,EAAQ,EAAU,EAAK,CACrD,EAMK,EAAe,EACjB,EAAE,CACF,CACE,OAAS,GAA0B,EAAe,GAAO,EAAc,CAAC,CACxE,UAAY,GAA0B,EAAa,EAAa,EAAc,CAAC,CAChF,CAEC,GAAmB,EACrB,EAAE,CACF,CACE,iBAAmB,GAAc,EAAe,CAAE,SAAU,EAAG,CAAC,CAChE,cAAgB,GAAc,EAAa,EAAK,GAAI,CAAE,SAAU,EAAG,CAAC,CACrE,CAEC,EAAiB,EACnB,EAAE,CACF,CACE,UAAW,EAAkB,IAC3B,EAAe,EAAS,EAAU,EAAc,CAAC,CACnD,aAAc,EAAuB,IACnC,EACE,IAAS,QACL,CAAE,KAAM,cAAe,UAAW,GAAS,EAAQ,EAAQ,EAAU,EAAK,CAAE,CAC5E,CAAE,KAAM,YAAa,QAAS,GAAS,EAAQ,EAAQ,EAAU,EAAK,CAAE,CAC7E,CACJ,CAMC,EAAqB,CACzB,KAAM,WACN,gBAAiB,KAAK,IAAI,EAAG,KAAK,MAAM,EAAa,EAAS,CAAG,EAAE,CACnE,eAAgB,KAAK,IAAI,EAAG,KAAK,MAAM,EAAQ,EAAS,CAAC,CACzD,aAAc,EAAO,IAAI,EAAM,CAAE,WAAU,CAAC,CAC5C,gBAAiB,GAAc,IAAA,GAC/B,MAAO,EAAU,IAAA,GAAY,EAAK,KACnC,CAMK,EAAoC,CACxC,OACA,WACA,WAAY,GAAa,EAAM,EAAkB,CAClD,CAED,OACE,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,GAAO,IAClB,MAAO,CAAE,MAAK,OAAQ,EAAW,CACjC,QAAS,MAAoB,EAAY,EAAK,CAAG,IAAA,GACjD,iBAAoB,EAAW,GAAK,CACpC,iBAAoB,EAAW,GAAM,CACrC,KAAK,MACL,gBAAe,EAAiB,EAAQ,WAP1C,CASG,CAAC,IACA,EAAA,EAAA,KAAC,GAAD,CACE,OAAQ,EAAK,GACb,QAAS,EACT,SAAU,EACE,aACZ,KAAM,GACN,CAAA,CAGH,EAAK,OAAS,cACb,EAAA,EAAA,KAAC,GAAD,CACE,QAAS,EACT,KAAM,EACN,WAAY,EACZ,IAAA,EACU,WACV,MAAO,EAAK,KACN,OACN,GAAI,EACJ,CAAA,CAEH,EAAK,OAAS,YACb,EAAA,EAAA,KAAC,GAAD,CACE,QAAS,EACT,KAAM,EACN,IAAA,EACO,QACP,OAAQ,EACE,WACV,MAAO,EAAK,KACN,OACI,WACV,GAAI,GACJ,GAAI,EACJ,CAAA,CAEH,EAAK,OAAS,QAAU,CAAC,EAAK,MAC7B,EAAA,EAAA,KAAC,GAAD,CACE,QAAS,EACT,KAAM,EACN,IAAA,EACO,QACP,OAAQ,EACE,WACV,MAAO,EAAK,KACN,OACI,WACV,GAAI,GACJ,GAAI,EACJ,GAAI,EACJ,CAAA,CACA,KACA,IAER,CAEF,GAAI,YAAc,MC5OlB,IAAM,GAAO,GAGP,GAAkC,EAAE,CA4B1C,SAAgB,GAAW,EAAyB,CAClD,IAAI,EAAO,IACP,EAAO,IACP,EAAO,KACP,EAAO,KACX,IAAK,IAAM,KAAK,EACV,EAAE,EAAI,IACR,EAAO,EAAE,GAEP,EAAE,EAAI,IACR,EAAO,EAAE,GAEP,EAAE,EAAI,IACR,EAAO,EAAE,GAEP,EAAE,EAAI,IACR,EAAO,EAAE,GAGb,MAAO,CAAE,OAAM,OAAM,OAAM,OAAM,CAInC,SAAgB,GAAS,EAAwB,CAC/C,GAAI,EAAO,OAAS,EAClB,OAAO,EAAO,IAAM,CAAE,EAAG,EAAG,EAAG,EAAG,CAEpC,IAAM,EAAM,KAAK,OAAO,EAAO,OAAS,GAAK,EAAE,CACzC,EAAI,EAAO,GACX,EAAI,EAAO,EAAM,GACvB,MAAO,CAAE,GAAI,EAAE,EAAI,EAAE,GAAK,EAAG,GAAI,EAAE,EAAI,EAAE,GAAK,EAAG,CA+BnD,SAAS,GACP,EACA,EACA,EACA,CAAE,SAAQ,WAAU,YAAW,QAC1B,CACL,GAAM,CAAE,OAAM,SAAU,GAAkB,EAAM,EAAO,EAAQ,EAAU,EAAK,CAC9E,GAAI,EAAK,OAAS,YAAa,CAE7B,IAAM,GAAQ,EAAA,IAAyC,EACvD,MAAO,CAAE,OAAQ,EAAO,EAAM,KAAM,EAAO,EAAM,UAAS,OAAM,CAElE,MAAO,CAAE,OAAQ,EAAM,KAAM,EAAO,EAAO,UAAS,OAAM,CAO5D,SAAS,GAAW,EAAoB,EAAmC,CACzE,IAAM,EAAQ,IAAI,IACZ,CAAE,aAAc,EAItB,OAHA,EAAM,SAAS,EAAM,IAAU,CAC7B,EAAM,IAAI,EAAK,GAAI,GAAM,EAAM,GAAa,EAAQ,EAAY,EAAY,EAAG,EAAO,CAAC,EACvF,CACK,EAQT,SAAS,GAAU,EAAU,EAAmB,CAC9C,IAAM,GAAQ,EAAE,EAAI,EAAE,GAAK,EAC3B,MAAO,CAAC,EAAG,CAAE,EAAG,EAAM,EAAG,EAAE,EAAG,CAAE,CAAE,EAAG,EAAM,EAAG,EAAE,EAAG,CAAE,EAAE,CAOzD,SAAS,GAAK,EAAU,EAAU,EAAc,EAAuB,CACrE,IAAM,EAAK,EAAE,EAAI,EAAO,GAClB,EAAK,EAAE,EAAI,EAAO,GAClB,GAAQ,EAAE,EAAI,EAAE,GAAK,EAC3B,MAAO,CAAC,EAAG,CAAE,EAAG,EAAI,EAAG,EAAE,EAAG,CAAE,CAAE,EAAG,EAAI,EAAG,EAAM,CAAE,CAAE,EAAG,EAAI,EAAG,EAAM,CAAE,CAAE,EAAG,EAAI,EAAG,EAAE,EAAG,CAAE,EAAE,CAQ7F,SAAS,GAAO,EAAU,EAAU,EAAqB,CACvD,MAAO,CAAC,EAAG,CAAE,EAAG,EAAI,EAAG,EAAE,EAAG,CAAE,CAAE,EAAG,EAAI,EAAG,EAAE,EAAG,CAAE,EAAE,CAIrD,SAAS,GAAU,EAA0B,EAAW,EAAkB,CACxE,IAAM,EAAK,EAAK,QACV,EAAK,EAAG,QAEd,OAAQ,EAAR,CACE,IAAK,KAAM,CAET,IAAM,EAAW,CAAE,EAAG,EAAK,KAAM,EAAG,EAAI,CAClC,EAAW,CAAE,EAAG,EAAG,OAAQ,EAAG,EAAI,CACxC,OAAO,EAAG,QAAU,EAAK,KAAO,EAAI,GAAO,GAAU,EAAG,EAAE,CAAG,GAAK,EAAG,EAAG,EAAG,EAAE,CAE/E,IAAK,KAIH,OAAO,GAAO,CAFK,EAAG,EAAK,OAAQ,EAAG,EAExB,CAAG,CADE,EAAG,EAAG,OAAQ,EAAG,EACnB,CAAG,KAAK,IAAI,EAAK,OAAQ,EAAG,OAAO,CAAG,GAAK,CAE9D,IAAK,KAIH,OAAO,GAAO,CAFK,EAAG,EAAK,KAAM,EAAG,EAEtB,CAAG,CADE,EAAG,EAAG,KAAM,EAAG,EACjB,CAAG,KAAK,IAAI,EAAK,KAAM,EAAG,KAAK,CAAG,GAAK,CAE1D,IAAK,KAAM,CAET,IAAM,EAAW,CAAE,EAAG,EAAK,OAAQ,EAAG,EAAI,CACpC,EAAW,CAAE,EAAG,EAAG,KAAM,EAAG,EAAI,CACtC,OAAO,EAAG,MAAQ,EAAK,OAAS,EAAI,GAAO,GAAU,EAAG,EAAE,CAAG,GAAK,EAAG,EAAG,GAAI,GAAG,GAoCrF,SAAgB,GAAoB,CAClC,QACA,eACA,GAAG,GACkC,CACrC,IAAM,EAAQ,GAAW,EAAO,EAAO,CACjC,EAA0B,EAAE,CAElC,IAAK,IAAM,KAAO,EAAc,CAC9B,IAAM,EAAO,EAAM,IAAI,EAAI,KAAK,CAC1B,EAAK,EAAM,IAAI,EAAI,GAAG,CACxB,CAAC,GAAQ,CAAC,GAGd,EAAM,KAAK,GAAO,EAAK,EAAM,EAAG,CAAC,CAKnC,IAAI,EAAuC,KAC3C,MAAO,CACL,QACA,QACA,cAAc,EAAK,CAEjB,MADA,KAAW,GAAgB,EAAM,CAC1B,EAAO,IAAI,EAAI,EAEzB,CAIH,SAAS,GAAO,EAAqB,EAAW,EAAyB,CAIvE,IAAM,EAAS,GAAU,EAAI,KAAM,EAAM,EAAG,CAC5C,MAAO,CAAE,GAAI,GAAG,EAAI,KAAK,IAAI,EAAI,KAAM,KAAM,EAAI,KAAM,SAAQ,OAAQ,GAAW,EAAO,CAAE,MAAK,CAIlG,SAAS,GAAgB,EAAgD,CACvE,IAAM,EAAQ,IAAI,IACZ,GAAO,EAAa,IAAoB,CAC5C,IAAM,EAAO,EAAM,IAAI,EAAI,CACvB,EACF,EAAK,KAAK,EAAE,CAEZ,EAAM,IAAI,EAAK,CAAC,EAAE,CAAC,EAOvB,OAJA,EAAM,SAAS,EAAM,IAAM,CACzB,EAAI,OAAO,EAAK,IAAI,KAAK,CAAE,EAAE,CAC7B,EAAI,OAAO,EAAK,IAAI,GAAG,CAAE,EAAE,EAC3B,CACK,EAYT,SAAgB,GACd,EACA,EACA,EACkB,CAClB,IAAM,EAAO,OAAO,KAAK,EAAU,CACnC,GAAI,EAAK,SAAW,EAClB,OAAO,EAAK,MAEd,IAAM,EAAU,IAAI,IAId,EAAU,GAA4B,CAC1C,IAAM,EAAM,EAAK,MAAM,IAAI,EAAG,CACxB,EAAW,GAAO,EAAU,OAAO,EAAG,EAC5C,GAAI,CAAC,GAAO,CAAC,EACX,OAAO,EAET,IAAI,EAAO,EAAQ,IAAI,EAAG,CAK1B,OAJK,IACH,EAAO,GAAM,EAAI,KAAM,EAAU,EAAI,QAAS,EAAO,CACrD,EAAQ,IAAI,EAAI,EAAK,EAEhB,GAGL,EAAgC,KACpC,IAAK,IAAM,KAAO,EAChB,IAAK,IAAM,KAAK,EAAK,cAAc,EAAI,EAAI,EAAE,CAAE,CAC7C,GAAM,CAAE,OAAQ,EAAK,MAAM,GACrB,EAAO,EAAO,EAAI,KAAK,CACvB,EAAK,EAAO,EAAI,GAAG,CACrB,CAAC,GAAQ,CAAC,IAGd,IAAS,EAAK,MAAM,OAAO,CAC3B,EAAK,GAAK,GAAO,EAAK,EAAM,EAAG,EAGnC,OAAO,GAAQ,EAAK,MCxUtB,IAAM,IAAA,EAAA,EAAA,eAAgE,KAAK,CAuB3E,SAAgB,GAAwB,CACtC,QACA,eACA,SACA,WACA,YACA,OACA,WACA,aAC+B,CAC/B,IAAM,GAAA,EAAA,EAAA,aACE,GAAoB,CAAE,QAAO,eAAc,SAAQ,WAAU,YAAW,OAAM,CAAC,CACrF,CAAC,EAAO,EAAc,EAAQ,EAAU,EAAW,EAAK,CACzD,CAEK,GAAA,EAAA,EAAA,aACE,GAAiB,EAAM,EAAW,CAAE,SAAQ,WAAU,YAAW,OAAM,CAAC,CAC9E,CAAC,EAAM,EAAW,EAAQ,EAAU,EAAW,EAAK,CACrD,CAED,OACE,EAAA,EAAA,KAAC,GAAuB,SAAxB,CAAiC,MAAO,EAAQ,WAA2C,CAAA,CAK/F,SAAgB,IAAuC,CACrD,IAAM,GAAA,EAAA,EAAA,YAAmB,GAAuB,CAChD,GAAI,IAAU,KACZ,MAAU,MAAM,qEAAqE,CAEvF,OAAO,4SEhDH,EAAY,EAEZ,GAAQ,EAER,GAAc,EA2EpB,SAAS,GAAW,EAAW,EAAmC,CAIhE,OAHK,EAGE,EAAE,MAAQ,EAAK,MAAQ,EAAE,MAAQ,EAAK,MAAQ,EAAE,MAAQ,EAAK,MAAQ,EAAE,MAAQ,EAAK,KAFlF,GAMX,SAAS,GAAa,EAAU,EAA+B,CAS7D,OARI,EAAE,IAAM,EAAE,EACL,CACL,KAAM,KAAK,IAAI,EAAE,EAAG,EAAE,EAAE,CAAG,EAAY,EACvC,IAAK,EAAE,EAAI,EAAY,EACvB,MAAO,KAAK,IAAI,EAAE,EAAI,EAAE,EAAE,CAAG,EAC7B,OAAQ,EACT,CAEI,CACL,KAAM,EAAE,EAAI,EAAY,EACxB,IAAK,KAAK,IAAI,EAAE,EAAG,EAAE,EAAE,CAAG,EAAY,EACtC,MAAO,EACP,OAAQ,KAAK,IAAI,EAAE,EAAI,EAAE,EAAE,CAAG,EAC/B,CAIH,SAAS,GAAa,EAAU,EAA+B,CAS7D,OARI,EAAE,IAAM,EAAE,EACL,CACL,KAAM,KAAK,IAAI,EAAE,EAAG,EAAE,EAAE,CAAG,EAAY,EACvC,IAAK,EAAE,EAAI,GACX,MAAO,KAAK,IAAI,EAAE,EAAI,EAAE,EAAE,CAAG,EAC7B,OAAQ,EAAY,GAAc,EACnC,CAEI,CACL,KAAM,EAAE,EAAI,GACZ,IAAK,KAAK,IAAI,EAAE,EAAG,EAAE,EAAE,CAAG,EAAY,EACtC,MAAO,EAAY,GAAc,EACjC,OAAQ,KAAK,IAAI,EAAE,EAAI,EAAE,EAAE,CAAG,EAC/B,CAGH,SAAS,GAAS,EAAwC,CACxD,IAAM,EAA+B,EAAE,CACvC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,EAAO,OAAQ,IACrC,EAAM,KAAK,CAAC,EAAO,GAAK,EAAO,EAAI,GAAI,CAAC,CAE1C,OAAO,EAGT,SAAS,GAAM,EAAiB,CAC9B,IAAM,EAAM,EAAO,EAAO,OAAS,GAC7B,EAAO,EAAO,EAAO,OAAS,GAC9B,EAAc,EAAI,GAAK,EAAK,EAClC,MAAO,CACL,UAAW,EAAc,EAAO,WAAa,EAAO,UACpD,MAAO,CACL,KAAM,EAAc,EAAI,EAAI,GAAQ,EAAI,EACxC,IAAK,EAAI,EAAI,GAAQ,EACtB,CACF,CAGH,SAAgB,GAAgB,CAC9B,QACA,SACA,qBACA,cACA,MAAO,EACP,UAAW,GACY,CACvB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,cAAc,OAAO,MACrD,EAAY,GAAiB,EAAW,cAAc,OAAO,UAC7D,EAAS,IAAgB,CAGzB,EAAW,IAAkB,CAE7B,EAAQ,IAAoB,CAC5B,CAAC,EAAY,IAAA,EAAA,EAAA,UAAyC,KAAK,CAC3D,CAAC,EAAW,IAAA,EAAA,EAAA,UAA0D,KAAK,CAE3E,EAAe,EAAa,EAAM,KAAM,GAAM,EAAE,KAAO,EAAW,CAAG,KAmB3E,IAjBA,EAAA,EAAA,eAAgB,CACd,GAAI,CAAC,EACH,OAEF,IAAM,EAAS,GAAqB,EAC9B,EAAE,MAAQ,UAAY,EAAE,MAAQ,eAC9B,GACF,IAAqB,EAAa,IAAI,CAExC,EAAc,KAAK,CACnB,EAAa,KAAK,GAItB,OADA,OAAO,iBAAiB,UAAW,EAAM,KAC5B,OAAO,oBAAoB,UAAW,EAAM,EACxD,CAAC,EAAY,EAAc,EAAmB,CAAC,CAE9C,EAAM,SAAW,EACnB,OAAO,KAGT,IAAM,GAAmB,EAAY,IAAwB,CAE3D,GADA,EAAE,iBAAiB,CACf,IAAe,EACjB,EAAc,KAAK,CACnB,EAAa,KAAK,KACb,CACL,EAAc,EAAG,CAEjB,IAAM,EADS,EAAE,cAA8B,QAAQ,IAAI,EAAO,QACrD,EAAO,uBAAuB,CAC3C,EAAa,EAAO,CAAE,EAAG,EAAE,QAAU,EAAK,KAAM,EAAG,EAAE,QAAU,EAAK,IAAK,CAAG,KAAK,GAI/E,EAAgB,GAAwB,CAC5C,EAAE,iBAAiB,CACf,GACF,IAAqB,EAAa,IAAI,CAExC,EAAc,KAAK,CACnB,EAAa,KAAK,EAGd,EAAQ,GAAO,OAAS,MACxB,EAAU,GAAO,SAAW,MAC5B,EAAQ,GAAO,OAAS,MACxB,EAAW,GAAO,UAAY,MAC9B,EAAe,GAAO,cAAgB,SAgB5C,OACE,EAAA,EAAA,MAAC,EAAD,CAAO,GAhBU,EACjB,CACE,UAAW,EAAO,MAClB,MAAO,CAAE,QAAO,SAAQ,CACxB,KAAM,eACN,cAAe,GACf,YAAe,CACb,EAAc,KAAK,CACnB,EAAa,KAAK,EAErB,CACD,GAAW,MACX,CAAE,QAAO,SAAQ,UAAW,EAAM,OAAQ,CAI/B,UAAX,CACG,EAAM,IAAK,GAAS,CACnB,IAAM,EAAa,EAAK,KAAO,EAC/B,GAAI,CAAC,GAAc,CAAC,GAAW,EAAK,OAAQ,EAAY,CACtD,OAAO,KAET,IAAM,EAAO,GAAM,EAAK,OAAO,CACzB,EAAO,GAAS,EAAK,OAAO,CAC5B,EAAM,EAAK,IAAI,IAAM,GAAS,EAAK,OAAO,CAAG,KAC7C,EAA2C,CAAE,OAAM,aAAY,CAE/D,EAAa,EACjB,CACE,UAAW,GAAG,EAAK,UAAU,GAAG,EAAa,EAAO,cAAgB,KACpE,MAAO,EAAK,MACb,CACD,GAAW,MACX,EACD,CAED,OACE,EAAA,EAAA,MAAC,EAAA,SAAD,CAAA,SAAA,CAEG,CAAC,GACA,EAAK,KAAK,CAAC,EAAG,MACZ,EAAA,EAAA,KAAC,MAAD,CAEE,UAAW,EAAO,QAClB,MAAO,GAAa,EAAG,EAAE,CACzB,QAAU,GAAM,EAAgB,EAAK,GAAI,EAAE,CAC3C,CAJK,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,IAInC,CACF,CAEH,EAAK,KAAK,CAAC,EAAG,GAAI,KASV,EAAA,EAAA,KAAC,EAAD,CAAiD,GARnC,EACnB,CACE,UAAW,GAAG,EAAO,QAAQ,GAAG,EAAa,EAAO,gBAAkB,KACtE,MAAO,GAAa,EAAG,EAAE,CAC1B,CACD,GAAW,QACX,CAAE,OAAM,aAAY,KAAM,EAAG,GAAI,EAAG,QAAO,CAEe,CAAgB,CAAvD,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,IAAyB,CAC5E,EACF,EAAA,EAAA,KAAC,EAAD,CAAO,GAAI,EAAc,CAAA,CAGxB,GAAO,EAAK,IAAI,MAAQ,IAAA,IAAa,EAAK,IAAI,MAAQ,IACrD,EAAA,EAAA,KAAC,EAAD,CACE,GAAI,EACF,CACE,UAAW,EAAO,SAClB,MAAO,CAAE,KAAM,EAAI,EAAG,IAAK,EAAI,EAAG,CAClC,SAAU,EAAK,IAAI,IAAM,EAAI,IAAI,EAAK,IAAI,IAAI,GAAK,GAAG,EAAK,IAAI,IAAI,GACpE,CACD,GAAW,SACX,CAAE,OAAM,aAAY,IAAK,EAAK,IAAI,IAAK,CACxC,CACD,CAAA,CAEK,CAAA,CAvCI,EAAK,GAuCT,EAEb,CAED,CAAC,GAAY,GAAgB,IAC5B,EAAA,EAAA,KAAC,EAAD,CACE,GAAI,EACF,CACE,UAAW,EAAO,UAClB,KAAM,SACN,SAAU,GACV,MAAO,CAAE,KAAM,EAAU,EAAG,IAAK,EAAU,EAAG,CAC9C,QAAS,EACT,aAAc,EAAO,iBACrB,SAAU,IACX,CACD,GAAW,aACX,CAAE,WAAY,EAAa,IAAK,CACjC,CACD,CAAA,CAEE,uCE3RZ,SAAgB,GAAkB,CAChC,MAAO,EACP,UAAW,GACc,CACzB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,cAAc,SAAS,MACvD,EAAY,GAAiB,EAAW,cAAc,SAAS,UAE/D,EAAO,IAAwB,CACrC,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,EAAK,EAAK,SAAW,EAAK,OAC1B,EAAK,EAAK,SAAW,EAAK,OAC1B,EAAS,KAAK,MAAM,EAAI,EAAG,CAC3B,EAA8B,IAAM,KAAK,GAAjC,KAAK,MAAM,EAAI,EAAG,CAmBhC,OAAO,EAAA,EAAA,KAjBM,GAAO,MAAQ,MAiBrB,CAAM,GAfK,EAChB,CACE,UAAW,GAAO,QAClB,MAAO,CACL,KAAM,EAAK,OACX,IAAK,EAAK,OACV,MAAO,EACP,UAAW,UAAU,EAAM,MAC5B,CACD,cAAe,GAChB,CACD,GAAW,KACX,CAAE,OAAM,SAAQ,QAAO,CAGR,CAAa,CAAA,oFEAhC,SAAgB,GAAY,CAC1B,QACA,WACA,aACA,WACA,OAAO,MACP,OAAO,EACP,MAAO,EACP,UAAW,GACQ,CACnB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,UAAU,YAAY,MACtD,EAAY,GAAiB,EAAW,UAAU,YAAY,UAE9D,EAAS,GAAO,QAAU,MAC1B,CAAE,YAAa,IAAsB,CAGrC,EAAY,IAAS,OAAS,IAAS,QAAU,IAAS,SAEhE,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,GAAO,KAAM,KAAK,eAAe,cAAA,YAC9C,EAAM,MAAM,EAAS,MAAO,EAAS,IAAI,CAAC,KAAK,EAAM,IAAM,CAC1D,IAAM,EAAQ,EAAS,MAAQ,EACzB,EAAO,EACT,EAAe,EAAU,EAAM,EAAQ,EAAM,EAAM,EAAK,CAAC,CACzD,CAAE,aAAc,GAAO,OAAQ,IAAA,GAAW,CAExC,EAAa,EAAW,EAAK,aAAe,IAAS,OAAS,EAAU,EAAK,CAC7E,EAAmC,CACvC,OACA,QACA,aAAc,EACd,iBAAkB,EAAc,EAAK,QAAU,UAAa,IAAA,GAC5D,UAAW,EACX,WACA,aACD,CAeD,OAAO,EAAA,EAAA,KAAC,EAAD,CAA6B,GAdhB,EAClB,CACE,UAAW,GAAK,GAAO,IAAK,GAAc,GAAO,WAAW,CAC5D,MAAO,CACL,KAAM,EAAQ,EACd,MAAO,EACP,OAAQ,EACT,CACF,CACD,GAAW,OACX,EAIsC,CAAe,CAAnC,EAAK,SAAS,CAAqB,EACvD,CACE,CAAA,CAIV,GAAY,YAAc,qGErG1B,SAAgB,GACd,EACA,EACA,EACA,EACA,EAAW,EACC,CACZ,GAAI,GAAa,EACf,MAAO,CAAE,MAAO,EAAG,IAAK,EAAG,CAE7B,GAAI,GAAY,GAAK,GAAY,EAC/B,MAAO,CAAE,MAAO,EAAG,IAAK,KAAK,IAAI,EAAA,IAAqC,CAAE,CAG1E,IAAM,EAAe,KAAK,MAAM,EAAS,EAAS,CAC5C,EAAc,KAAK,MAAM,EAAS,GAAY,EAAS,CAK7D,MAAO,CAAE,MAHK,KAAK,IAAI,EAAG,EAAe,EAGhC,CAAO,IAFJ,KAAK,IAAI,EAAW,EAAc,EAE9B,CAAK,CCavB,SAAgB,GAAU,CAAE,MAAO,EAAW,UAAW,GAAkC,EAAE,CAAE,CAC7F,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,UAAU,MAAM,MAChD,EAAY,GAAiB,EAAW,UAAU,MAAM,UAExD,CAAE,gBAAiB,IAAmB,CACtC,CAAE,aAAY,aAAY,cAAa,iBAAkB,IAAqB,CAC9E,CAAE,WAAU,YAAW,SAAQ,UAAS,UAAW,IAAgB,CACnE,EAAS,IAAgB,CACzB,CAAE,UAAS,eAAc,eAAgB,IAAgB,CACzD,EAAW,IAAkB,CAC7B,CAAE,eAAc,sBAAuB,IAAoB,CAC3D,CAAE,SAAQ,SAAQ,UAAS,eAAc,mBAAoB,IAAc,EAEjF,EAAA,EAAA,eAAgB,CACd,IAAM,EAAO,EAAQ,QACrB,GAAI,CAAC,GAAS,CAAC,GAAgB,CAAC,EAC9B,OAEF,IAAM,EAAW,GAAkB,CACjC,GAAI,EAAE,EAAE,SAAW,EAAE,SACnB,OAEF,EAAE,gBAAgB,CAClB,IAAM,EAAO,EAAK,uBAAuB,CAEzC,EADgB,EAAK,YAAc,EAAE,QAAU,EAAK,MACpC,EAAE,OAAS,EAAI,EAAI,GAAG,EAElC,EAAa,GAAqB,CAClC,EAAE,MAAQ,KAAO,EAAE,MAAQ,KAC7B,EAAE,gBAAgB,CAClB,GAAQ,GACC,EAAE,MAAQ,KAAO,EAAE,MAAQ,OACpC,EAAE,gBAAgB,CAClB,GAAS,GAUb,OAPI,GACF,EAAK,iBAAiB,QAAS,EAAS,CAAE,QAAS,GAAO,CAAC,CAEzD,IACF,EAAK,SAAW,EAChB,EAAK,iBAAiB,UAAW,EAAU,MAEhC,CACX,EAAK,oBAAoB,QAAS,EAAQ,CAC1C,EAAK,oBAAoB,UAAW,EAAU,GAE/C,CAAC,EAAS,EAAc,EAAiB,EAAQ,EAAQ,EAAS,EAAa,OAAO,CAAC,CAE1F,GAAM,CAAC,GAAW,IAAA,EAAA,EAAA,UAAoC,EAAE,CAAC,CAEnD,IAAA,EAAA,EAAA,aACH,GAAoB,CACnB,EAAc,EAAK,GAAG,CACtB,IAAc,EAAK,EAErB,CAAC,EAAe,EAAY,CAC7B,CAEK,GAAA,EAAA,EAAA,cAA8B,EAAQ,IAAqC,CAC/E,EAAc,GAAS,CACrB,GAAI,IAAU,KAAM,CAClB,GAAM,EAAG,GAAK,EAAG,GAAG,GAAS,EAC7B,OAAO,EAET,MAAO,CAAE,GAAG,GAAO,GAAK,CAAE,GAAG,EAAK,GAAK,GAAG,EAAO,CAAE,EACnD,EACD,EAAE,CAAC,CAEA,GAAA,EAAA,EAAA,aACE,GAAmB,EAAc,EAAS,EAAO,CACvD,CAAC,EAAc,EAAS,EAAO,CAChC,CAEK,EAAW,EAAM,IAAI,SAAS,CAC9B,GAAA,EAAA,EAAA,aAAwB,GAAY,KAAO,IAAA,GAAY,IAAI,KAAK,EAAS,CAAG,CAAC,EAAS,CAAC,CAC7F,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,EAAO,GAAkB,EAAO,CAChC,EAAa,EAAM,OAAS,EAC5B,GAAa,EAAa,OAAS,EAGnC,GADiB,GAAU,IACK,OAEhC,EAAW,GACf,EAAS,UACT,EAAS,aACT,EACA,EAAa,OAAA,EAEd,CACK,EAAW,GACf,EAAS,WACT,EAAS,YACT,EACA,EAAM,OAAA,EAEP,CAIK,EAAc,CAClB,KAAM,EAAS,MAAQ,EACvB,KAAM,EAAS,IAAM,EACrB,KAAM,EAAS,MAAQ,EACvB,KAAM,EAAS,IAAM,EACtB,CAEK,EAAO,GAAO,MAAQ,MACtB,GAAO,GAAO,MAAQ,MAEtB,GAA6B,CAAE,aAAY,cAAY,SAAQ,CAE/D,GAAY,EAChB,CACE,UAAW,GAAO,YAClB,MAAO,IAAW,IAAA,GAAyB,EAAE,CAAf,CAAE,SAAQ,CACxC,SAAU,EACV,KAAM,OACN,aAAc,EAAO,SACrB,gBAAiB,EAAiB,EAAa,OAC/C,gBAAiB,EAAM,OACxB,CACD,GAAW,KACX,GACD,CAEK,GAAY,EAChB,CACE,UAAW,GAAO,KAClB,MAAO,CAAE,OAAQ,GAAY,MAAO,EAAY,CAChD,KAAM,WACP,CACD,GAAW,KACX,GACD,CAED,OACE,EAAA,EAAA,KAAC,EAAD,CAAM,IAAK,EAAS,GAAI,aACtB,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,GAAO,KAAM,MAAO,CAAE,MAAO,EAAY,CAAE,KAAK,wBAAhE,EACE,EAAA,EAAA,KAAC,GAAD,CACY,WACC,YACJ,QACC,SACE,WACV,CAAA,EACF,EAAA,EAAA,KAAC,GAAD,CACE,MAAO,EACO,eACN,SACE,WACC,YACL,OACK,uBAEX,EAAA,EAAA,MAAC,GAAD,CAAM,IAAK,EAAa,GAAI,YAA5B,EACE,EAAA,EAAA,KAAC,GAAD,CACS,QACG,WACE,cACF,WACJ,OACN,KAAM,GAAkB,EAAO,CAC/B,CAAA,EACF,EAAA,EAAA,KAAC,GAAD,CACE,MAAO,EACP,OAAQ,GACY,qBACP,cACb,CAAA,EACF,EAAA,EAAA,KAAC,GAAD,EAAqB,CAAA,CAEpB,EAAa,MAAM,EAAS,MAAO,EAAS,IAAI,CAAC,KAAK,EAAM,KAGzD,EAAA,EAAA,KAAC,GAAD,CAEQ,OACC,MALG,EAAS,MAAQ,EAMnB,SACE,WACC,YACL,OACN,SAAU,EACV,SAAU,EACV,SAAU,GAAU,EAAK,IACzB,WAAY,EACZ,YAAa,GACb,eAAgB,EAChB,CAbK,EAAK,GAaV,CAEJ,CACG,GACiB,CAAA,CACtB,GACD,CAAA,CAIX,GAAU,YAAc,8CEzOxB,SAAgB,GAAiB,CAC/B,cACA,aAAa,GACb,MAAO,EACP,UAAW,GACa,CACxB,IAAM,EAAa,GAAe,CAC5B,EAAQ,GAAa,EAAW,UAAU,kBAAkB,MAC5D,EAAY,GAAiB,EAAW,UAAU,kBAAkB,UAEpE,EAAS,IAAgB,CACzB,EAAyC,CAAE,aAAY,CAgB7D,OAAO,EAAA,EAAA,KAdM,GAAO,MAAQ,MAcrB,CAAM,GAZK,EAChB,CACE,UAAW,GAAO,OAClB,cACA,KAAM,YACN,mBAAoB,WACpB,aAAc,EAAO,eACtB,CACD,GAAW,KACX,EAGe,CAAa,CAAA,uYEfhC,SAAgB,GAAe,CAC7B,UACA,YACA,SAAS,GACT,gBACA,QACA,aACsB,CAGtB,IAAM,EAAe,EAAO,OAAS,EAAY,EAE3C,EAAS,GAAO,QAAU,MAC1B,EAAa,GAAO,YAAc,MAClC,EAAqB,GAAO,oBAAsB,MAcxD,OACE,EAAA,EAAA,KAAC,EAAD,CAAQ,GAZU,EAClB,CACE,UAAW,EAAO,OAClB,MAAO,CAAE,UAAW,EAAc,OAAQ,EAAc,CACxD,KAAM,MACN,gBAAiB,EAClB,CACD,GAAW,OACX,CAAE,UAAS,eAAc,CAIb,UACT,EAAQ,KAAK,EAAK,IAAU,CAC3B,IAAM,EAA+C,CAAE,OAAQ,EAAK,QAAO,CAErE,EAAkB,EACtB,CACE,UAAW,EAAO,WAClB,MAAO,EAAI,MACP,CAAE,MAAO,EAAI,MAAO,WAAY,EAAG,CACnC,CAAE,KAAM,WAAY,SAAU,IAAK,CACvC,KAAM,eACN,gBAAiB,EAAQ,EAC1B,CACD,GAAW,WACX,EACD,CAEK,EAAoB,EACxB,CACE,UAAW,EAAO,QAClB,cAAe,GACf,YAAc,GAAwB,CAGpC,IAAM,EAAO,EAAE,cAAc,cAC7B,EAAc,EAAI,IAAK,EAAK,YAAa,EAAE,EAE9C,CACD,GAAW,mBACX,EACD,CAED,OACE,EAAA,EAAA,MAAC,EAAD,CAA0B,GAAI,WAA9B,CACG,EAAI,QACL,EAAA,EAAA,KAAC,EAAD,CAAoB,GAAI,EAAqB,CAAA,CAClC,EAHI,EAAI,IAGR,EAEf,CACK,CAAA,CC3Gb,IAAM,GAAY,GA4ClB,SAAgB,GAAS,CACvB,SACA,QACA,WACA,aACA,iBACA,WACA,QACA,aACgB,CAChB,IAAM,EAAS,IAAgB,CACzB,EAAiC,CAAE,SAAQ,QAAO,WAAU,aAAY,CAExE,EAAO,GAAO,MAAQ,OACtB,EAAe,GAAO,cAAgB,SACtC,EAAc,GAAO,aAAe,OAEpC,EAAY,EAChB,CACE,UAAW,EAAO,YAClB,MAAO,CAAE,YAAa,EAAQ,GAAW,CAC1C,CACD,GAAW,KACX,EACD,CAEK,EAAc,EAClB,CACE,UAAW,EAAO,UAClB,KAAM,SACN,QAAU,GAAwB,CAChC,EAAE,iBAAiB,CACnB,EAAe,EAAO,EAExB,aAAc,EAAa,EAAO,SAAW,EAAO,OACpD,SAAU,EAAa,IAAM,IAC9B,CACD,GAAW,aACX,EACD,CAEK,EAAmB,EACvB,CAAE,UAAW,EAAO,kBAAmB,cAAe,GAAM,CAC5D,GAAW,YACX,EACD,CAED,OACE,EAAA,EAAA,MAAC,EAAD,CAAM,GAAI,WAAV,CACG,GAAW,EAAA,EAAA,KAAC,EAAD,CAAc,GAAI,EAAe,CAAA,EAAG,EAAA,EAAA,KAAC,EAAD,CAAa,GAAI,EAAoB,CAAA,CACpF,EACI,GC/EX,IAAM,GAAoB,IAEb,IAAA,EAAA,EAAA,MAAmB,SAAqB,CACnD,OACA,YACA,WACA,QACA,WACA,UACA,WACA,aACA,aACA,iBACA,WACA,UACA,YACmB,CACnB,GAAM,CAAE,aAAc,IAAqB,CAC3C,OACE,EAAA,EAAA,KAAC,MAAD,CACE,UAAW,GAAG,EAAO,IAAI,GAAG,EAAa,EAAO,SAAW,KAC3D,MAAO,CAAE,OAAQ,EAAW,CAC5B,YAAe,EAAS,EAAK,GAAG,CAChC,KAAK,MACL,gBAAe,EAAW,EAC1B,aAAY,EAAQ,EACpB,gBAAe,EACf,eAAc,EACd,gBAAe,EAAW,EAAa,IAAA,GACvC,gBAAe,GAAc,IAAA,YAE5B,EAAQ,KAAK,EAAK,KAEf,EAAA,EAAA,KAAC,MAAD,CAEE,UAAW,GAAG,EAAO,KAAK,GAAG,EAAI,aAAe,EAAO,SAAW,KAClE,MAAO,CAAE,MAAO,EAAI,OAAS,GAAmB,WAAY,EAAG,CAC/D,KAAM,EAAI,aAAe,YAAc,WACvC,gBAAe,EAAQ,WAEtB,EAAI,cACH,EAAA,EAAA,KAAC,GAAD,CACE,OAAQ,EAAK,GACN,QACG,WACE,aACI,iBAChB,MAAO,GAAU,MACjB,UAAW,GAAU,mBAEpB,EAAI,OAAO,EAAM,EAAU,CACnB,CAAA,CAEX,EAAI,OAAO,EAAM,EAAU,CAEzB,CArBC,EAAI,IAqBL,CAER,CACE,CAAA,EAER,CAEF,GAAY,YAAc,cC5E1B,SAAgB,IAAkB,CAChC,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,UAA8C,EAAE,CAAC,CAC1D,GAAA,EAAA,EAAA,QAAyE,KAAK,CAyBpF,MAAO,CAAE,SAAQ,eAAA,EAAA,EAAA,cAvBkB,EAAa,EAAoB,IAAwB,CAC1F,EAAE,gBAAgB,CAClB,EAAS,QAAU,CAAE,MAAK,OAAQ,EAAE,QAAS,MAAO,EAAY,CAEhE,IAAM,EAAU,GAAmB,CACjC,GAAI,CAAC,EAAS,QACZ,OAEF,GAAM,CAAE,IAAK,EAAQ,SAAQ,SAAU,EAAS,QAC1C,EAAO,KAAK,IAAA,GAAsB,GAAS,EAAG,QAAU,GAAQ,CACtE,EAAW,IAAU,CAAE,GAAG,GAAO,GAAS,EAAM,EAAE,EAG9C,MAAa,CACjB,EAAS,QAAU,KACnB,OAAO,oBAAoB,YAAa,EAAO,CAC/C,OAAO,oBAAoB,UAAW,EAAK,EAG7C,OAAO,iBAAiB,YAAa,EAAO,CAC5C,OAAO,iBAAiB,UAAW,EAAK,EACvC,EAAE,CAEY,CAAe,CCdlC,IAAM,GAAa,CAAE,KAAM,WAAY,UAAW,EAAG,CAQrD,SAAgB,GAAS,CAAE,UAAU,EAAE,CAAE,YAA2B,CAClE,GAAM,CAAE,eAAc,cAAa,aAAc,IAAmB,CAC9D,CAAE,eAAc,gBAAe,cAAa,cAAe,IAAqB,CAChF,EAAa,IAAoB,CACjC,CAAE,YAAW,SAAQ,UAAW,IAAgB,CAChD,EAAS,IAAgB,CACzB,CAAE,cAAa,oBAAqB,IAAgB,CAEpD,CAAE,SAAQ,iBAAkB,IAAiB,CAI7C,GAAA,EAAA,EAAA,aAEF,EAAQ,IAAK,GAAS,EAAO,EAAI,MAAQ,KAA4C,EAArC,CAAE,GAAG,EAAK,MAAO,EAAO,EAAI,KAAM,CAAQ,CAC5F,CAAC,EAAS,EAAO,CAClB,CAMK,EAAY,EAAc,GAAW,CACzC,EAAc,EAAG,CAEjB,IAAM,EAAO,EAAa,KAAM,GAAM,EAAE,KAAO,EAAG,CAC9C,IACF,IAAc,EAAK,CAGnB,EAAW,EAAI,CAAE,WAAY,GAAM,SAAU,GAAO,CAAC,GAEvD,CACI,GAAA,EAAA,EAAA,aAA4B,GAAW,EAAU,QAAQ,EAAG,CAAE,CAAC,EAAU,CAAC,CAE1E,GAAA,EAAA,EAAA,aAAyB,CAC7B,IAAM,EAAM,IAAI,IAChB,IAAK,IAAM,KAAK,EAAc,CAC5B,IAAM,EAAc,EAAE,UAAY,KAAoC,GAA5B,EAAI,IAAI,EAAE,SAAS,EAAI,EACjE,EAAI,IAAI,EAAE,GAAI,EAAc,EAAE,CAEhC,OAAO,GACN,CAAC,EAAa,CAAC,CAEZ,GAAA,EAAA,EAAA,aAA4B,CAChC,IAAM,EAAS,IAAI,IACb,EAAM,IAAI,IAChB,IAAK,IAAM,KAAK,EAAc,CAC5B,IAAM,EAAS,EAAE,UAAY,KACvB,GAAO,EAAO,IAAI,EAAO,EAAI,GAAK,EACxC,EAAO,IAAI,EAAQ,EAAI,CACvB,EAAI,IAAI,EAAE,GAAI,CAAE,SAAU,EAAK,QAAS,EAAG,CAAC,CAE9C,IAAK,IAAM,KAAK,EAAc,CAC5B,IAAM,EAAQ,EAAI,IAAI,EAAE,GAAG,CAC3B,EAAM,QAAU,EAAO,IAAI,EAAE,UAAY,KAAK,EAAI,EAEpD,OAAO,GACN,CAAC,EAAa,CAAC,CAEZ,CAAE,SAAU,EAAc,mBAAoB,GAAmB,EAAa,CAClF,gBAAiB,GAClB,CAAC,CAII,GAAA,EAAA,EAAA,iBAAiC,CACrC,GAAkB,CAClB,GAAiB,EAChB,CAAC,EAAkB,EAAgB,CAAC,CAIjC,EAAW,GACf,EAAa,UACb,EAAa,aACb,EACA,EAAa,OAAA,EAEd,CAED,OACE,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,EAAO,SAClB,MAAO,CAAE,SAAQ,CACjB,KAAK,WACL,aAAY,EAAO,SACnB,gBAAe,EAAa,OAAS,EACrC,gBAAe,EAAgB,gBANjC,EAQE,EAAA,EAAA,KAAC,GAAD,CACE,QAAS,EACE,YACH,SACO,gBACf,MAAO,GAAU,QAAQ,MACzB,UAAW,GAAU,QAAQ,UAC7B,CAAA,EACF,EAAA,EAAA,KAAC,MAAD,CACE,IAAK,EACL,UAAW,EAAO,KAClB,MAAO,GACP,SAAU,EACV,KAAK,yBAEL,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,EAAO,KAAM,KAAK,oBAAlC,EACE,EAAA,EAAA,KAAC,MAAD,CACE,MAAO,CAAE,OAAQ,EAAS,MAAQ,EAAW,CAC7C,KAAK,eACL,cAAY,OACZ,CAAA,CACD,MAAM,KAAK,CAAE,OAAQ,EAAS,IAAM,EAAS,MAAO,EAAG,EAAG,IAAM,CAC/D,IAAM,EAAQ,EAAS,MAAQ,EACzB,EAAO,EAAa,GACpB,EAAW,EAAY,IAAI,EAAK,GAAG,CACzC,OACE,EAAA,EAAA,KAAC,GAAD,CAEQ,OACK,YACX,SAAU,EACV,MAAO,EAAS,IAAI,EAAK,GAAG,EAAI,EAChC,SAAU,GAAU,UAAY,EAChC,QAAS,GAAU,SAAW,EAC9B,SAAU,EAAU,IAAI,EAAK,GAAG,CAChC,WAAY,EAAY,IAAI,EAAK,GAAG,CACpC,WAAY,IAAe,EAAK,GAChC,eAAgB,EAChB,SAAU,EACV,QAAS,EACT,SAAU,GAAU,SACpB,CAdK,EAAK,GAcV,EAEJ,EACF,EAAA,EAAA,KAAC,MAAD,CACE,MAAO,CACL,QAAS,EAAa,OAAS,EAAS,KAAO,EAChD,CACD,KAAK,eACL,cAAY,OACZ,CAAA,CACE,GACF,CAAA,CACF,GCzKV,SAAgB,GACd,EACA,EACA,CACA,GAAM,CAAC,EAAW,IAAA,EAAA,EAAA,UAA6C,IAAA,GAAU,CACnE,GAAA,EAAA,EAAA,QAAgF,KAAK,CAsC3F,MAAO,CAAE,YAAW,mBAAA,EAAA,EAAA,aAnCjB,GAAwB,CACvB,EAAE,gBAAgB,CAClB,IAAM,EAAU,EAAW,QACrB,EAAY,EAAa,QAC/B,GAAI,CAAC,GAAW,CAAC,EACf,OAEF,EAAS,QAAU,CACjB,OAAQ,EAAE,QACV,MAAO,EAAQ,YACf,WAAY,EAAU,YACvB,CAED,IAAM,EAAU,GAAmB,CACjC,GAAI,CAAC,EAAS,QACZ,OAEF,GAAM,CAAE,SAAQ,QAAO,cAAe,EAAS,QAG/C,EADa,KAAK,IAAI,EAAY,KAAK,IAAA,GAAoB,GAAS,EAAS,EAAG,SAAS,CAC5E,CAAK,EAGd,MAAa,CACjB,EAAS,QAAU,KACnB,OAAO,oBAAoB,YAAa,EAAO,CAC/C,OAAO,oBAAoB,UAAW,EAAK,EAG7C,OAAO,iBAAiB,YAAa,EAAO,CAC5C,OAAO,iBAAiB,UAAW,EAAK,EAE1C,CAAC,EAAc,EAAW,CAGR,CAAmB,6CE9BzC,SAAgB,GAAgB,EAA4B,CAC1D,IAAM,EAAQ,EAAQ,EAAK,UAAW,EAAE,CACxC,MAAO,CACL,GAAI,QAAQ,KAAK,KAAK,GACtB,KAAM,WACN,UAAW,EACX,QAAS,EAAQ,EAAO,EAAE,CAC1B,SAAU,EACV,SAAU,EACV,KAAM,OACN,SAAU,EAAK,UAAY,KAC5B,CAaH,SAAgB,GAAY,CAAE,OAAM,OAA4C,CAC9E,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,GAAO,qBAAvB,EACE,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,MAAM,OACN,aAAY,EAAI,OAAO,SAAS,EAAK,CACrC,QAAU,GAAM,CACd,EAAE,iBAAiB,CACnB,EAAI,SAAS,EAAK,YAGpB,EAAA,EAAA,KAAC,OAAD,CAAM,cAAY,gBAAO,IAAc,CAAA,CAChC,CAAA,EACT,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,MAAM,YACN,aAAY,EAAI,OAAO,aAAa,EAAK,CACzC,QAAU,GAAM,CACd,EAAE,iBAAiB,CACnB,IAAM,EAAU,GAAgB,EAAK,CACrC,EAAI,WAAW,EAAS,EAAK,GAAG,CAChC,EAAI,SAAS,EAAQ,YAGvB,EAAA,EAAA,KAAC,OAAD,CAAM,cAAY,gBAAO,IAAe,CAAA,CACjC,CAAA,EACT,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,MAAM,SACN,aAAY,EAAI,OAAO,WAAW,EAAK,CACvC,MAAO,CAAE,SAAU,EAAG,CACtB,QAAU,GAAM,CACd,EAAE,iBAAiB,CACnB,EAAI,WAAW,EAAK,GAAG,YAGzB,EAAA,EAAA,KAAC,OAAD,CAAM,cAAY,gBAAO,IAAe,CAAA,CACjC,CAAA,CACL,GCtEV,IAAa,GAAoB,WAOpB,GAA+B,CAC1C,CACE,IAAK,GACL,OAAQ,KACR,MAAO,IACP,QAAS,EAAM,KAAQ,EAAA,EAAA,KAAC,GAAD,CAAmB,OAAW,MAAO,CAAA,CAC7D,CACD,CACE,IAAK,SACL,OAAQ,YACR,OAAS,GAAoB,EAAK,KAClC,MAAO,IACP,aAAc,GACf,CACD,CACE,IAAK,UACL,OAAQ,QACR,MAAO,GACP,OAAS,GAAoB,EAAK,UAAU,oBAAoB,CACjE,CACD,CACE,IAAK,QACL,OAAQ,MACR,MAAO,GAGP,QAAS,EAAiB,IAAQ,EAAI,OAAO,QAAQ,EAAK,EAAE,oBAAoB,EAAI,IACrF,CACD,CACE,IAAK,aACL,OAAQ,cACR,MAAO,GACP,OAAS,GAAoB,GAAG,EAAK,UAAY,EAAE,GACpD,CACF,CAGY,GAAiC,GAAgB,OAC3D,GAAQ,EAAI,MAAQ,GACtB,CC5CD,SAAgB,GAAM,CACpB,QACA,eACA,YACA,WACA,SACA,SACA,UACA,aACA,mBACA,eACA,YACA,eACA,cACA,QAAS,EACT,uBAAuB,IACvB,qBACA,qBACA,eACA,eACA,aACA,gBACA,WACA,gBACA,eACA,WAAW,GACX,SACA,eACA,YACA,OACA,mBACA,WACA,UACa,CACb,IAAM,GAAA,EAAA,EAAA,QAAsC,KAAK,CAC3C,GAAA,EAAA,EAAA,QAAoC,KAAK,CACzC,CAAE,YAAW,qBAAsB,GAAc,EAAc,EAAW,CAG1E,GAAU,IAAgB,EAAW,GAAoB,IACzD,EAAe,CAAC,EAStB,OACE,EAAA,EAAA,KAAC,GAAD,CACS,QACO,eACH,YACD,WACF,SACA,SACC,UACG,aACM,mBACJ,eACH,YACG,eACD,cACO,qBACA,qBACN,eACA,eACF,aACG,gBACP,SACA,SACE,WACK,gBACD,eACJ,qBAEV,EAAA,EAAA,KAAC,GAAD,CAAoB,OAAA,EAAA,EAAA,cAhCf,CAAE,OAAM,aAAc,GAAiB,WAAU,EACxD,CAAC,EAAM,GAAiB,EAAS,CA+BJ,UACxB,GACC,EAAA,EAAA,MAAC,MAAD,CACE,IAAK,EACL,KAAK,QACL,aAAY,GAAQ,OAAS,GAAe,MAC5C,MAAO,CAAE,SAAU,WAAY,UAJjC,EAME,EAAA,EAAA,KAAC,GAAD,CAAmB,WAAmB,YAAY,CAAA,EAClD,EAAA,EAAA,MAAC,MAAD,CACE,IAAK,EACL,MAAO,CACL,SAAU,WACV,IAAK,EACL,MAAO,EACP,OAAQ,EACR,QAAS,OACT,cAAe,MACf,WAAY,mCACZ,GAAI,IAAc,IAAA,GAEd,CAAE,KAAM,EAAsB,CAD9B,CAAE,MAAO,EAAW,CAEzB,UAbH,EAeE,EAAA,EAAA,KAAC,GAAD,CAAkB,YAAa,EAAqB,CAAA,EACpD,EAAA,EAAA,KAAC,MAAD,CAAK,MAAO,CAAE,KAAM,WAAY,SAAU,EAAG,WAC3C,EAAA,EAAA,KAAC,GAAD,EAAa,CAAA,CACT,CAAA,CACF,GACF,IAEN,EAAA,EAAA,KAAC,GAAD,EAAa,CAAA,CAEI,CAAA,CACP,CAAA"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/core/lruCache.ts","../src/core/utils.ts","../src/core/dateUtils.ts","../src/core/calendar.ts","../src/hooks/useResolvedCalendar.ts","../src/core/workingTime.ts","../src/core/taskDates.ts","../src/core/labels.ts","../src/core/prepareData.ts","../src/core/queue.ts","../src/core/scheduling.ts","../src/hooks/useTaskList.ts","../src/hooks/useLatestRef.ts","../src/hooks/useExpand.ts","../src/hooks/useIsomorphicLayoutEffect.ts","../src/hooks/useViewportMeasure.ts","../src/hooks/useScrollSync.ts","../src/hooks/useEventCallback.ts","../src/core/scroll.ts","../src/core/barUtils.ts","../src/core/scales.ts","../src/core/timeline.ts","../src/hooks/useRevealTask.ts","../src/hooks/useZoom.ts","../src/core/zoom.ts","../src/hooks/useDependencyDrag.ts","../src/context/useGanttHandle.ts","../src/context/useColumnApi.ts","../src/context/contexts.ts","../src/context/GanttProvider.tsx","../src/context/GanttSlotsContext.tsx","../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/core/slots.ts","../src/components/calendar/Calendar.module.css","../src/components/calendar/CalendarRow.tsx","../src/components/calendar/Calendar.tsx","../src/hooks/useAutoScroll.ts","../src/hooks/useDrag.ts","../src/components/bars/barTooltip/BarTooltip.module.css","../src/components/bars/barTooltip/BarTooltipContext.ts","../src/components/bars/barTooltip/BarTooltipRoot.tsx","../src/components/bars/barTooltip/useTooltipPosition.ts","../src/components/bars/barTooltip/BarTooltipTrigger.tsx","../src/components/bars/barTooltip/BarTooltip.tsx","../src/components/bars/barTooltip/BarTooltipConsumer.tsx","../src/components/bars/common/DraggableBar.tsx","../src/components/bars/milestoneBar/MilestoneBar.module.css","../src/components/bars/milestoneBar/MilestoneBar.tsx","../src/components/bars/progress/BarProgress.module.css","../src/components/bars/progress/BarProgressResizeHandle.tsx","../src/components/bars/progress/BarProgress.tsx","../src/components/bars/projectBar/ProjectBar.module.css","../src/components/bars/projectBar/ProjectBar.tsx","../src/components/bars/taskBar/TaskBar.module.css","../src/components/bars/taskBar/TaskResizer.tsx","../src/components/bars/taskBar/TaskBar.tsx","../src/components/bars/common/ConnectorHandles.module.css","../src/components/bars/common/ConnectorHandles.tsx","../src/components/bars/common/Row.module.css","../src/components/bars/common/Row.tsx","../src/components/dependency-links/geometry.ts","../src/components/dependency-links/DependencyLinksContext.tsx","../src/components/dependency-links/DependencyLinks.module.css","../src/components/dependency-links/DependencyLinks.tsx","../src/components/dependency-links/DependencyPreview.module.css","../src/components/dependency-links/DependencyPreview.tsx","../src/components/grid/GridColumns.module.css","../src/components/grid/GridColumns.tsx","../src/components/grid/Grid.module.css","../src/core/virtualize.ts","../src/components/grid/Grid.tsx","../src/components/grid/GridResizeHandle.module.css","../src/components/grid/GridResizeHandle.tsx","../src/components/taskList/TaskList.module.css","../src/components/taskList/TaskListHeader.tsx","../src/components/taskList/TreeCell.tsx","../src/components/taskList/TaskListRow.tsx","../src/hooks/useColumnWidths.ts","../src/components/taskList/TaskList.tsx","../src/hooks/useGridResize.ts","../src/components/taskList/ActionsCell.module.css","../src/components/taskList/ActionsCell.tsx","../src/components/taskList/defaultColumns.tsx","../src/Gantt.tsx"],"sourcesContent":["export class LRUCache<K, V> {\n private cache = new Map<K, V>();\n private capacity: number;\n\n constructor(size: number) {\n this.capacity = size;\n }\n\n private refreshKey(key: K): void {\n if (!this.cache.has(key)) {\n return;\n }\n const val = this.cache.get(key) as V;\n this.cache.delete(key);\n this.cache.set(key, val);\n }\n\n get(key: K): V | undefined {\n if (!this.cache.has(key)) {\n return undefined;\n }\n this.refreshKey(key);\n return this.cache.get(key);\n }\n\n put(key: K, value: V): void {\n this.refreshKey(key);\n this.cache.set(key, value);\n\n if (this.cache.size > this.capacity) {\n const [removeKey] = this.cache.keys();\n this.cache.delete(removeKey as K);\n }\n }\n}\n","import { LRUCache } from \"./lruCache\";\n\nexport function memoizeWithLRUCache<K, V>(fn: (arg: K) => V, cacheSize: number): (arg: K) => V {\n const cache = new LRUCache<K, V>(cacheSize);\n return (arg: K) => {\n const cached = cache.get(arg);\n if (cached != null) {\n return cached;\n }\n const result = fn(arg);\n cache.put(arg, result);\n return result;\n };\n}\n\nexport function memoize<K, V>(fn: (arg: K) => V, cacheSize: number): (arg: K) => V {\n return memoizeWithLRUCache(fn, cacheSize);\n}\n","import type { CalendarUnit } from \"../types\";\nimport { memoize } from \"./utils\";\n\nconst MS_PER_MINUTE = 60_000;\nconst MS_PER_HOUR = 3_600_000;\nconst MS_PER_DAY = 86_400_000;\nconst MS_PER_WEEK = MS_PER_DAY * 7;\n\n/** Fixed-length units convert to pixels by simple ms division. */\nconst LINEAR_UNIT_MS: Partial<Record<CalendarUnit, number>> = {\n minute: MS_PER_MINUTE,\n hour: MS_PER_HOUR,\n day: MS_PER_DAY,\n week: MS_PER_WEEK,\n};\n\nexport function periodKey(date: Date, unit: CalendarUnit, step: number): string {\n const y = date.getFullYear();\n const m = date.getMonth();\n const d = date.getDate();\n\n switch (unit) {\n case \"minute\": {\n const local = new Date(date);\n local.setSeconds(0, 0);\n const minuteIndex = Math.round(local.getTime() / MS_PER_MINUTE);\n return `mi-${Math.floor(minuteIndex / step)}`;\n }\n case \"hour\": {\n const local = new Date(date);\n local.setMinutes(0, 0, 0);\n const hourIndex = Math.round(local.getTime() / MS_PER_HOUR);\n return `h-${Math.floor(hourIndex / step)}`;\n }\n case \"day\": {\n const dayIndex = Math.floor(Date.UTC(y, m, d) / MS_PER_DAY);\n return `d-${Math.floor(dayIndex / step)}`;\n }\n case \"week\": {\n const local = new Date(y, m, d);\n const dow = local.getDay();\n const toMonday = dow === 0 ? -6 : 1 - dow;\n local.setDate(local.getDate() + toMonday);\n const weekIndex = Math.floor(local.getTime() / (MS_PER_DAY * 7));\n return `w-${Math.floor(weekIndex / step)}`;\n }\n case \"month\": {\n const monthIndex = y * 12 + m;\n return `mo-${Math.floor(monthIndex / step)}`;\n }\n case \"quarter\": {\n const quarterIndex = y * 4 + Math.floor(m / 3);\n return `q-${Math.floor(quarterIndex / step)}`;\n }\n case \"year\": {\n return `y-${Math.floor(y / step)}`;\n }\n default:\n throw new Error(`Unsupported unit: ${unit}`);\n }\n}\n\nexport function isWeekend(date: Date): boolean {\n const dow = date.getDay();\n return dow === 0 || dow === 6;\n}\n\n/**\n * Index of the local *civil* day containing `date` — days since 1970-01-01 by\n * calendar date, ignoring time of day and immune to DST because it is computed\n * from the civil fields rather than the epoch instant.\n *\n * The working-time calendar keys every day off this, so identical civil dates\n * in different timezones map to the same index.\n */\nexport function civilDayIndex(date: Date): number {\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / MS_PER_DAY;\n}\n\n/** Local midnight starting the civil day at `dayIndex`. Inverse of {@link civilDayIndex}. */\nexport function dateFromCivilDayIndex(dayIndex: number): Date {\n const utc = new Date(dayIndex * MS_PER_DAY);\n return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());\n}\n\nexport function diffDays(from: Date, to: Date): number {\n return civilDayIndex(to) - civilDayIndex(from);\n}\n\nexport function addDays(date: Date, days: number): Date {\n const d = new Date(date);\n d.setHours(0, 0, 0, 0);\n return new Date(d.getTime() + days * MS_PER_DAY);\n}\n\n/**\n * Start boundary of the calendar unit containing `date` (local time): top of the\n * minute/hour, midnight for `day`, Monday for `week`, the 1st for `month`, the\n * first day of the quarter for `quarter`, Jan 1 for `year`.\n */\nexport function startOfUnit(date: Date, unit: CalendarUnit): Date {\n const d = new Date(date);\n switch (unit) {\n case \"minute\": {\n d.setSeconds(0, 0);\n return d;\n }\n case \"hour\": {\n d.setMinutes(0, 0, 0);\n return d;\n }\n case \"day\": {\n d.setHours(0, 0, 0, 0);\n return d;\n }\n case \"week\": {\n d.setHours(0, 0, 0, 0);\n const dow = d.getDay();\n const toMonday = dow === 0 ? -6 : 1 - dow;\n d.setDate(d.getDate() + toMonday);\n return d;\n }\n case \"month\": {\n d.setHours(0, 0, 0, 0);\n d.setDate(1);\n return d;\n }\n case \"quarter\": {\n d.setHours(0, 0, 0, 0);\n d.setMonth(Math.floor(d.getMonth() / 3) * 3, 1);\n return d;\n }\n case \"year\": {\n d.setHours(0, 0, 0, 0);\n d.setMonth(0, 1);\n return d;\n }\n default: {\n throw new Error(`Unsupported unit: ${unit}`);\n }\n }\n}\n\n/**\n * Add `amount` whole calendar units to `date`. Minute/hour/day/week are fixed-ms\n * math; month/quarter/year use calendar arithmetic (`setMonth`/`setFullYear`) so\n * lengths and leap years are respected. Time-of-day is preserved for sub-day\n * units and via the calendar setters for month+.\n */\nexport function addUnit(date: Date, unit: CalendarUnit, amount: number): Date {\n const linearMs = LINEAR_UNIT_MS[unit];\n if (linearMs !== undefined) {\n if (unit === \"day\" || unit === \"week\") {\n return addDays(date, amount * (linearMs / MS_PER_DAY));\n }\n return new Date(date.getTime() + amount * linearMs);\n }\n const d = new Date(date);\n switch (unit) {\n case \"month\": {\n d.setMonth(d.getMonth() + amount);\n return d;\n }\n case \"quarter\": {\n d.setMonth(d.getMonth() + amount * 3);\n return d;\n }\n case \"year\": {\n d.setFullYear(d.getFullYear() + amount);\n return d;\n }\n default: {\n throw new Error(`Unsupported unit: ${unit}`);\n }\n }\n}\n\n/**\n * Fractional number of `unit` columns from `origin` to `date`. Fixed-length units\n * are linear ms; month/quarter/year count whole units with calendar-correct\n * boundaries and interpolate the partial unit within its own [start, next) span.\n * Inverse of {@link dateAtOffset}.\n */\nexport function unitOffset(origin: Date, date: Date, unit: CalendarUnit): number {\n const linearMs = LINEAR_UNIT_MS[unit];\n if (linearMs !== undefined) {\n return (date.getTime() - origin.getTime()) / linearMs;\n }\n // Bracket `date` between whole-unit boundaries addUnit(origin, unit, k) and\n // addUnit(origin, unit, k+1). Seed k from raw month arithmetic, then correct\n // (only a step or two) so the estimate survives varying month lengths.\n const monthsPerUnit = unit === \"month\" ? 1 : unit === \"quarter\" ? 3 : 12;\n const originMonths = origin.getFullYear() * 12 + origin.getMonth();\n const dateMonths = date.getFullYear() * 12 + date.getMonth();\n let k = Math.floor((dateMonths - originMonths) / monthsPerUnit);\n while (addUnit(origin, unit, k).getTime() > date.getTime()) {\n k -= 1;\n }\n while (addUnit(origin, unit, k + 1).getTime() <= date.getTime()) {\n k += 1;\n }\n const base = addUnit(origin, unit, k).getTime();\n const next = addUnit(origin, unit, k + 1).getTime();\n return k + (date.getTime() - base) / (next - base);\n}\n\n/**\n * Date at a fractional `offset` of `unit` columns from `origin`. Inverse of\n * {@link unitOffset}.\n */\nexport function dateAtOffset(origin: Date, unit: CalendarUnit, offset: number): Date {\n const linearMs = LINEAR_UNIT_MS[unit];\n if (linearMs !== undefined) {\n return new Date(origin.getTime() + offset * linearMs);\n }\n const whole = Math.floor(offset);\n const frac = offset - whole;\n const base = addUnit(origin, unit, whole).getTime();\n const next = addUnit(origin, unit, whole + 1).getTime();\n return new Date(base + frac * (next - base));\n}\n\nexport function buildDates(\n start: Date,\n count: number,\n unit: CalendarUnit = \"day\",\n step = 1,\n): Date[] {\n return Array.from({ length: count }, (_, i) => addUnit(start, unit, i * step));\n}\n\ninterface TaskDates {\n startDate: Date;\n endDate?: Date;\n}\n\nfunction getMinMaxDatesNonCached(tasks: readonly TaskDates[]): { min: Date; max: Date } | null {\n const first = tasks[0];\n if (!first) {\n return null;\n }\n let min = first.startDate;\n let max = first.endDate ?? first.startDate;\n for (const t of tasks) {\n if (t.startDate < min) {\n min = t.startDate;\n }\n const end = t.endDate ?? t.startDate;\n if (end > max) {\n max = end;\n }\n }\n return { min, max };\n}\n\nexport const getMinMaxDates = memoize(getMinMaxDatesNonCached, 3);\n","import type { DayHours, GanttCalendar, Weekday, WorkTimeRange } from \"../types\";\nimport { civilDayIndex } from \"./dateUtils\";\n\nexport const MINUTES_PER_DAY = 1440;\nexport const MS_PER_MINUTE = 60_000;\n\n/** Every day fully working — the shape a calendar resolves to when `hours` is omitted. */\nconst FULL_DAY_INTERVALS: readonly number[] = [0, MINUTES_PER_DAY];\n\n/**\n * The normalized working intervals of one civil day, as minutes from local\n * midnight. Sorted, non-overlapping, and non-adjacent — `[\"8:00-12:00\",\n * \"12:00-17:00\"]` merges to a single `8:00-17:00` interval and interns\n * identically to it.\n */\nexport interface DayShape {\n /** Flattened `[from0, to0, from1, to1, …]`. Empty means a day off. */\n readonly intervals: readonly number[];\n /**\n * Cumulative working minutes *before* each interval, so `prefix[i]` is the\n * work done by the time interval `i` starts. `prefix[0]` is always 0.\n */\n readonly prefix: readonly number[];\n /** Total working minutes: 0 for a day off, 1440 for a full day. */\n readonly totalMinutes: number;\n /** Interning id — structurally identical shapes are `===`, so `id` is only for debugging. */\n readonly id: number;\n}\n\n/**\n * A {@link GanttCalendar} resolved into a queryable form. Immutable, framework-free,\n * and identity-stable per content (see `calendarKey`), so it is safe to use\n * directly as a React dependency or cache key.\n */\nexport interface ResolvedCalendar {\n readonly key: string;\n /** Indexed by `Date.prototype.getDay()`; the global `hours` are already folded in. */\n readonly byWeekday: readonly DayShape[];\n /** Civil day index → shape, for `dates` overrides only. */\n readonly byDate: ReadonlyMap<number, DayShape>;\n /** Sorted `byDate` keys, so a walk can find the next override in O(log n). */\n readonly overrideDays: readonly number[];\n /** Every weekday is a full 00:00–24:00 day and there are no date overrides. */\n readonly isAlwaysWorking: boolean;\n /** No shape is partial — each is either empty or a full day. */\n readonly isDayGranular: boolean;\n /** Working minutes across the seven weekday shapes. 0 means a degenerate calendar. */\n readonly weekMinutes: number;\n /** Working ms that one `durationUnit: \"day\"` represents (ADR-018: the week's longest working day). */\n readonly msPerWorkingDay: number;\n}\n\nconst RANGE_RE = /^\\s*(\\d{1,2}):(\\d{2})\\s*-\\s*(\\d{1,2}):(\\d{2})\\s*$/;\n\n/**\n * Parse one `\"H:MM-H:MM\"` range into `[fromMinute, toMinute)`. Throws on anything\n * unparseable so a typo surfaces at the edge rather than as a silently wrong schedule.\n */\nexport function parseWorkTimeRange(range: WorkTimeRange): [number, number] {\n const m = RANGE_RE.exec(range);\n if (!m) {\n throw new Error(\n `Invalid working-hours range ${JSON.stringify(range)}: expected \"H:MM-H:MM\", e.g. \"8:30-12:00\".`,\n );\n }\n const from = Number(m[1]) * 60 + Number(m[2]);\n const to = Number(m[3]) * 60 + Number(m[4]);\n if (from < 0 || from >= MINUTES_PER_DAY) {\n throw new Error(\n `Invalid working-hours range ${JSON.stringify(range)}: start must be within the day.`,\n );\n }\n if (to <= from || to > MINUTES_PER_DAY) {\n throw new Error(\n `Invalid working-hours range ${JSON.stringify(range)}: end must be after start and no later than 24:00.`,\n );\n }\n return [from, to];\n}\n\n/** Sort, merge adjacent/overlapping, and flatten a day's ranges into interval pairs. */\nfunction normalizeIntervals(hours: DayHours | undefined): readonly number[] {\n if (hours === undefined) {\n return FULL_DAY_INTERVALS;\n }\n if (hours === false) {\n return [];\n }\n const pairs = hours.map(parseWorkTimeRange).toSorted((a, b) => a[0] - b[0]);\n const out: number[] = [];\n for (const [from, to] of pairs) {\n const lastEnd = out.length > 0 ? out[out.length - 1]! : undefined;\n if (lastEnd !== undefined && from <= lastEnd) {\n // Overlapping or adjacent — extend the run rather than emitting a gap.\n if (to > lastEnd) {\n out[out.length - 1] = to;\n }\n continue;\n }\n out.push(from, to);\n }\n return out;\n}\n\nfunction makeShape(intervals: readonly number[], id: number): DayShape {\n const prefix: number[] = [];\n let total = 0;\n for (let i = 0; i < intervals.length; i += 2) {\n prefix.push(total);\n total += intervals[i + 1]! - intervals[i]!;\n }\n return { intervals, prefix, totalMinutes: total, id };\n}\n\n/** Interns shapes by their normalized signature so identical days compare with `===`. */\nfunction shapeInterner() {\n const cache = new Map<string, DayShape>();\n return (intervals: readonly number[]): DayShape => {\n const signature = intervals.join(\",\");\n const existing = cache.get(signature);\n if (existing) {\n return existing;\n }\n const shape = makeShape(intervals, cache.size);\n cache.set(signature, shape);\n return shape;\n };\n}\n\nfunction hoursKey(hours: DayHours | undefined): string {\n if (hours === undefined) {\n return \"*\";\n }\n if (hours === false) {\n return \"-\";\n }\n return hours.join(\",\");\n}\n\n/**\n * A deterministic structural key for a calendar spec.\n *\n * Consumers write `calendar={{ … }}` inline, so keying the resolved calendar by\n * object *identity* would rebuild it — and invalidate everything memoized on it —\n * on every render. Keying by content makes an inline object free.\n *\n * `dates` keys are sorted explicitly: integer-like keys (`days`) are ordered by\n * the JS engine, but `\"2026-01-01\"` keys keep insertion order, which would\n * otherwise leak into the key. Keys are compared *raw*, so `\"8:00-12:00\"` and\n * `\"08:00-12:00\"` produce different keys for the same calendar — a cache miss,\n * never a wrong answer, and normalizing first would cost the parse this avoids.\n */\nexport function calendarKey(calendar: GanttCalendar | undefined): string {\n if (!calendar) {\n return \"\";\n }\n const parts: string[] = [hoursKey(calendar.hours)];\n for (let day = 0; day < 7; day++) {\n const hours = calendar.days?.[day as Weekday];\n if (hours !== undefined) {\n parts.push(`${day}=${hoursKey(hours)}`);\n }\n }\n const dates = calendar.dates;\n if (dates) {\n for (const date of Object.keys(dates).toSorted()) {\n parts.push(`${date}=${hoursKey(dates[date])}`);\n }\n }\n return parts.join(\"|\");\n}\n\nconst DATE_KEY_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\nfunction dayIndexFromDateKey(key: string): number {\n const m = DATE_KEY_RE.exec(key);\n if (!m) {\n throw new Error(\n `Invalid calendar date key ${JSON.stringify(key)}: expected a local civil date, \"YYYY-MM-DD\".`,\n );\n }\n return civilDayIndex(new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])));\n}\n\n/**\n * Resolve a spec into a queryable calendar. `key` should come from\n * {@link calendarKey}; it is carried so downstream caches can compare content.\n */\nexport function buildCalendar(calendar: GanttCalendar, key: string): ResolvedCalendar {\n const intern = shapeInterner();\n const globalIntervals = normalizeIntervals(calendar.hours);\n\n const byWeekday: DayShape[] = [];\n for (let day = 0; day < 7; day++) {\n const override = calendar.days?.[day as Weekday];\n byWeekday.push(intern(override === undefined ? globalIntervals : normalizeIntervals(override)));\n }\n\n const byDate = new Map<number, DayShape>();\n if (calendar.dates) {\n for (const [dateKey, hours] of Object.entries(calendar.dates)) {\n byDate.set(dayIndexFromDateKey(dateKey), intern(normalizeIntervals(hours)));\n }\n }\n const overrideDays = [...byDate.keys()].toSorted((a, b) => a - b);\n\n let weekMinutes = 0;\n let isDayGranular = true;\n let isAlwaysWorking = byDate.size === 0;\n for (const shape of byWeekday) {\n weekMinutes += shape.totalMinutes;\n if (shape.totalMinutes !== 0 && shape.totalMinutes !== MINUTES_PER_DAY) {\n isDayGranular = false;\n }\n if (shape.totalMinutes !== MINUTES_PER_DAY) {\n isAlwaysWorking = false;\n }\n }\n for (const shape of byDate.values()) {\n if (shape.totalMinutes !== 0 && shape.totalMinutes !== MINUTES_PER_DAY) {\n isDayGranular = false;\n }\n }\n\n // ADR-018: one `durationUnit: \"day\"` is the week's LONGEST working day, so a\n // weekends-off calendar over full days gives exactly 24h and `duration: 3`\n // stays three whole days.\n let longestDayMinutes = 0;\n for (const shape of byWeekday) {\n if (shape.totalMinutes > longestDayMinutes) {\n longestDayMinutes = shape.totalMinutes;\n }\n }\n\n return {\n key,\n byWeekday,\n byDate,\n overrideDays,\n isAlwaysWorking,\n isDayGranular,\n weekMinutes,\n msPerWorkingDay: longestDayMinutes * MS_PER_MINUTE,\n };\n}\n\n/** The working shape of the civil day at `dayIndex`: a date override if one exists, else the weekday rule. */\nexport function shapeFor(calendar: ResolvedCalendar, dayIndex: number): DayShape {\n const override = calendar.byDate.get(dayIndex);\n if (override) {\n return override;\n }\n // `dayIndex` 0 is 1970-01-01, a Thursday (getDay() === 4).\n return calendar.byWeekday[(((dayIndex + 4) % 7) + 7) % 7]!;\n}\n\n/**\n * Smallest date-override day `>= dayIndex`, or `Infinity`. Lets a walk skip whole\n * weeks safely: between here and the next override, only the weekday rules apply.\n */\nexport function nextOverrideDay(calendar: ResolvedCalendar, dayIndex: number): number {\n const days = calendar.overrideDays;\n let lo = 0;\n let hi = days.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (days[mid]! < dayIndex) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n return lo < days.length ? days[lo]! : Number.POSITIVE_INFINITY;\n}\n\n/** Largest date-override day `<= dayIndex`, or `-Infinity`. The backward-walk mirror. */\nexport function prevOverrideDay(calendar: ResolvedCalendar, dayIndex: number): number {\n const days = calendar.overrideDays;\n let lo = 0;\n let hi = days.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (days[mid]! <= dayIndex) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n return lo > 0 ? days[lo - 1]! : Number.NEGATIVE_INFINITY;\n}\n","import { useRef } from \"react\";\nimport { buildCalendar, calendarKey, type ResolvedCalendar } from \"../core/calendar\";\nimport type { GanttCalendar } from \"../types\";\n\ninterface Cached {\n key: string;\n value: ResolvedCalendar | null;\n}\n\n/**\n * Resolve a {@link GanttCalendar} into its queryable form, keyed by **content**.\n *\n * Consumers write the prop inline — `calendar={{ hours: [...], dates: {...} }}` —\n * so a fresh object arrives on every render. Keying on identity would rebuild the\n * calendar each time and, worse, churn the identity that the task-list memo and\n * every downstream cache depend on. Hashing the spec instead makes an inline\n * object free, and the returned object is identity-stable for as long as the\n * content is unchanged, so callers can use it as a plain dependency.\n *\n * Deliberately a ref rather than `useMemo`: the cache key is derived, not a\n * dependency list, and `useMemo` offers no correctness guarantee anyway.\n *\n * Returns `null` when no calendar is supplied — the signal for plain linear time\n * throughout `core/*`.\n */\nexport function useResolvedCalendar(calendar?: GanttCalendar): ResolvedCalendar | null {\n const cache = useRef<Cached | null>(null);\n const key = calendarKey(calendar);\n\n if (!cache.current || cache.current.key !== key) {\n cache.current = {\n key,\n value: calendar ? buildCalendar(calendar, key) : null,\n };\n }\n return cache.current.value;\n}\n","import type { DurationUnit } from \"../types\";\nimport {\n MINUTES_PER_DAY,\n MS_PER_MINUTE,\n nextOverrideDay,\n prevOverrideDay,\n shapeFor,\n type DayShape,\n type ResolvedCalendar,\n} from \"./calendar\";\nimport { civilDayIndex, dateFromCivilDayIndex } from \"./dateUtils\";\n\nconst MS_PER_HOUR = 3_600_000;\nconst MS_PER_DAY = 86_400_000;\n\n/** ~55 years. A walk that exceeds this is a degenerate calendar, not a real schedule. */\nconst MAX_WALK_DAYS = 20_000;\n\n/** Which way a walk projects a non-working anchor before moving (ADR-007). */\nexport type WalkDirection = 1 | -1;\n\n/**\n * Wall-clock minutes since local midnight, fractional to millisecond precision.\n *\n * Deliberately read from the civil fields rather than an epoch difference:\n * working time is measured in *civil* time, so a DST day is simply short or long\n * and `\"9:00\"` means nine o'clock on every day of the year.\n */\nfunction minuteOfDay(date: Date): number {\n const ms =\n date.getHours() * MS_PER_HOUR +\n date.getMinutes() * MS_PER_MINUTE +\n date.getSeconds() * 1000 +\n date.getMilliseconds();\n return ms / MS_PER_MINUTE;\n}\n\n/**\n * The instant `minute` wall-clock minutes into the civil day at `dayIndex`.\n *\n * Built with the local civil constructor and an overflowing millisecond field, so\n * `instantAt(d, 1440)` is local midnight of the next civil day whether that day is\n * 23, 24, or 25 hours long. Never add 86_400_000 ms instead — that drifts across\n * every DST boundary.\n */\nfunction instantAt(dayIndex: number, minute: number): Date {\n const base = dateFromCivilDayIndex(dayIndex);\n return new Date(\n base.getFullYear(),\n base.getMonth(),\n base.getDate(),\n 0,\n 0,\n 0,\n Math.round(minute * MS_PER_MINUTE),\n );\n}\n\n/** Working minutes strictly before `minute` within this day. */\nfunction workedBefore(shape: DayShape, minute: number): number {\n const { intervals, prefix } = shape;\n for (let i = 0, p = 0; i < intervals.length; i += 2, p++) {\n const from = intervals[i]!;\n const to = intervals[i + 1]!;\n if (minute <= from) {\n return prefix[p]!;\n }\n if (minute < to) {\n return prefix[p]! + (minute - from);\n }\n }\n return shape.totalMinutes;\n}\n\n/**\n * The minute at which `worked` minutes of work have elapsed, resolving an exact\n * interval boundary to that interval's **end**.\n *\n * This is the tie-break a forward walk needs: having worked through lunch, you\n * finish at 12:00, you do not start at 13:00.\n */\nfunction minuteAtWorkedBackAnchored(shape: DayShape, worked: number): number {\n const { intervals, prefix } = shape;\n let result = intervals.length > 0 ? intervals[0]! : 0;\n for (let i = 0, p = 0; i < intervals.length; i += 2, p++) {\n if (prefix[p]! >= worked) {\n break;\n }\n result = intervals[i]! + (worked - prefix[p]!);\n }\n return result;\n}\n\n/**\n * The minute at which `worked` minutes of work have elapsed, resolving an exact\n * interval boundary to the next interval's **start**.\n *\n * The mirror tie-break, for a backward walk computing a start: a task needing the\n * afternoon begins at 13:00, not at 12:00.\n */\nfunction minuteAtWorkedFwdAnchored(shape: DayShape, worked: number): number {\n const { intervals, prefix } = shape;\n for (let i = 0, p = 0; i < intervals.length; i += 2, p++) {\n const length = intervals[i + 1]! - intervals[i]!;\n if (worked < prefix[p]! + length) {\n return intervals[i]! + (worked - prefix[p]!);\n }\n }\n return intervals.length > 0 ? intervals[intervals.length - 1]! : 0;\n}\n\n/** First working minute at or after `minute` within this day, or `null`. */\nfunction nextStartAtOrAfter(shape: DayShape, minute: number): number | null {\n const { intervals } = shape;\n for (let i = 0; i < intervals.length; i += 2) {\n if (minute < intervals[i + 1]!) {\n return Math.max(minute, intervals[i]!);\n }\n }\n return null;\n}\n\n/** Last valid *finish* minute at or before `minute` within this day, or `null`. */\nfunction prevEndAtOrBefore(shape: DayShape, minute: number): number | null {\n const { intervals } = shape;\n let best: number | null = null;\n for (let i = 0; i < intervals.length; i += 2) {\n if (minute > intervals[i]!) {\n best = Math.min(minute, intervals[i + 1]!);\n }\n }\n return best;\n}\n\n/**\n * Is work happening at this instant? Half-open, matching the range syntax: with\n * hours ending at 17:00, `16:59:59.999` is working and `17:00` is not.\n */\nexport function isWorkingTime(calendar: ResolvedCalendar | null, date: Date): boolean {\n if (!calendar) {\n return true;\n }\n if (calendar.isAlwaysWorking) {\n return true;\n }\n const shape = shapeFor(calendar, civilDayIndex(date));\n const minute = minuteOfDay(date);\n const { intervals } = shape;\n for (let i = 0; i < intervals.length; i += 2) {\n if (minute >= intervals[i]! && minute < intervals[i + 1]!) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Project `date` onto working time in the direction a walk is about to travel.\n *\n * `dir === 1` returns the earliest working instant at or after `date` — the shape\n * a task **start** must have. `dir === -1` returns the latest valid **finish** at\n * or before it, i.e. the latest instant whose preceding moment is working.\n *\n * Idempotent in each direction, which is what keeps the dependency cascade's\n * fixpoint reachable. It is deliberately **not** symmetric: projecting a Saturday\n * forward lands on Monday morning and backward on Friday evening, so a round trip\n * does not return Saturday. See ADR-007 — that asymmetry is the design, because a\n * walk's meaning depends on whether it computes a start or a finish.\n */\nexport function closestWorkingTime(\n calendar: ResolvedCalendar | null,\n date: Date,\n dir: WalkDirection,\n): Date {\n if (!calendar || calendar.isAlwaysWorking) {\n return date;\n }\n if (calendar.weekMinutes === 0 && calendar.byDate.size === 0) {\n // Nothing is ever working: degrade to identity rather than scanning to the cap.\n return date;\n }\n let day = civilDayIndex(date);\n let minute = minuteOfDay(date);\n\n for (let guard = 0; guard < MAX_WALK_DAYS; guard++) {\n const shape = shapeFor(calendar, day);\n if (dir === 1) {\n const start = nextStartAtOrAfter(shape, minute);\n if (start !== null) {\n return start === minute && day === civilDayIndex(date) ? date : instantAt(day, start);\n }\n day += 1;\n minute = 0;\n continue;\n }\n const end = prevEndAtOrBefore(shape, minute);\n if (end !== null) {\n return end === minute && day === civilDayIndex(date) ? date : instantAt(day, end);\n }\n day -= 1;\n minute = MINUTES_PER_DAY;\n }\n // Degenerate calendar (no working time anywhere in range) — degrade rather than\n // hang a render.\n return date;\n}\n\n/** Nearest working instant in either direction; ties go forward. Milestones only (ADR-009). */\nexport function nearestWorkingTime(calendar: ResolvedCalendar | null, date: Date): Date {\n if (!calendar || calendar.isAlwaysWorking) {\n return date;\n }\n if (isWorkingTime(calendar, date)) {\n return date;\n }\n const forward = closestWorkingTime(calendar, date, 1);\n const backward = closestWorkingTime(calendar, date, -1);\n const forwardGap = forward.getTime() - date.getTime();\n const backwardGap = date.getTime() - backward.getTime();\n return forwardGap <= backwardGap ? forward : backward;\n}\n\nfunction walkForward(calendar: ResolvedCalendar, anchor: Date, minutes: number): Date {\n let day = civilDayIndex(anchor);\n let minute = minuteOfDay(anchor);\n let remaining = minutes;\n\n for (let guard = 0; guard < MAX_WALK_DAYS; guard++) {\n const shape = shapeFor(calendar, day);\n const worked = workedBefore(shape, minute);\n const available = shape.totalMinutes - worked;\n if (remaining <= available) {\n return instantAt(day, minuteAtWorkedBackAnchored(shape, worked + remaining));\n }\n remaining -= available;\n day += 1;\n minute = 0;\n\n // Whole-week skip: between here and the next date override only the weekday\n // rules apply, so a multi-year lag costs a binary search, not a day loop. Always\n // leave at least one week to walk so the landing minute is resolved day by day.\n if (calendar.weekMinutes > 0 && remaining > calendar.weekMinutes) {\n const nextOverride = nextOverrideDay(calendar, day);\n const safeWeeks =\n nextOverride === Number.POSITIVE_INFINITY\n ? Number.POSITIVE_INFINITY\n : Math.floor((nextOverride - day) / 7);\n const workWeeks = Math.ceil(remaining / calendar.weekMinutes) - 1;\n const weeks = Math.min(safeWeeks, workWeeks);\n if (weeks > 0 && Number.isFinite(weeks)) {\n day += weeks * 7;\n remaining -= weeks * calendar.weekMinutes;\n }\n }\n }\n return instantAt(day, minute);\n}\n\nfunction walkBackward(calendar: ResolvedCalendar, anchor: Date, minutes: number): Date {\n let day = civilDayIndex(anchor);\n let minute = minuteOfDay(anchor);\n let remaining = minutes;\n\n for (let guard = 0; guard < MAX_WALK_DAYS; guard++) {\n const shape = shapeFor(calendar, day);\n const worked = workedBefore(shape, minute);\n if (remaining <= worked) {\n return instantAt(day, minuteAtWorkedFwdAnchored(shape, worked - remaining));\n }\n remaining -= worked;\n day -= 1;\n minute = MINUTES_PER_DAY;\n\n if (calendar.weekMinutes > 0 && remaining > calendar.weekMinutes) {\n const previousOverride = prevOverrideDay(calendar, day);\n const safeWeeks =\n previousOverride === Number.NEGATIVE_INFINITY\n ? Number.POSITIVE_INFINITY\n : Math.floor((day - previousOverride) / 7);\n const workWeeks = Math.ceil(remaining / calendar.weekMinutes) - 1;\n const weeks = Math.min(safeWeeks, workWeeks);\n if (weeks > 0 && Number.isFinite(weeks)) {\n day -= weeks * 7;\n remaining -= weeks * calendar.weekMinutes;\n }\n }\n }\n return instantAt(day, minute);\n}\n\n/**\n * Advance `from` by `ms` of **working** time; a negative `ms` walks backward.\n *\n * `anchorDir` controls only the initial projection of `from` onto working time and\n * defaults to the direction of the walk. A caller computing a *finish* with\n * `ms === 0` must pass `-1` explicitly — that is exactly the `lag: 0` case in the\n * FF and SF branches of the cascade, where deriving the direction from the sign of\n * a zero would silently project the wrong way.\n *\n * Composition: `addWorkingMs(addWorkingMs(t, a), -a) === t` **iff** `t` is anchored\n * in the direction of `sign(a)` — see ADR-007. Project once at the boundary of an\n * operation, then compose freely inside it.\n */\nexport function addWorkingMs(\n calendar: ResolvedCalendar | null,\n from: Date,\n ms: number,\n anchorDir?: WalkDirection,\n): Date {\n if (!calendar) {\n return new Date(from.getTime() + ms);\n }\n const dir: WalkDirection = anchorDir ?? (ms < 0 ? -1 : 1);\n const anchor = closestWorkingTime(calendar, from, dir);\n if (ms === 0) {\n return anchor;\n }\n if (calendar.weekMinutes === 0 && calendar.byDate.size === 0) {\n return anchor;\n }\n return ms > 0\n ? walkForward(calendar, anchor, ms / MS_PER_MINUTE)\n : walkBackward(calendar, anchor, -ms / MS_PER_MINUTE);\n}\n\n/**\n * Working time in `[from, to)`, in milliseconds. Negative when `to < from`.\n *\n * Unlike {@link addWorkingMs} this is a plain integral, so it is unconditionally\n * additive: `count(a, b) + count(b, c) === count(a, c)` for any instants. That is\n * why span measurement always goes through it.\n */\nexport function countWorkingMs(calendar: ResolvedCalendar | null, from: Date, to: Date): number {\n if (!calendar) {\n return to.getTime() - from.getTime();\n }\n if (to.getTime() < from.getTime()) {\n return -countWorkingMs(calendar, to, from);\n }\n const endDay = civilDayIndex(to);\n let day = civilDayIndex(from);\n let minute = minuteOfDay(from);\n let minutes = 0;\n\n while (day < endDay) {\n if (minute === 0 && calendar.weekMinutes > 0) {\n const nextOverride = nextOverrideDay(calendar, day);\n const limit = Math.min(endDay, nextOverride);\n const weeks = Math.floor((limit - day) / 7);\n if (weeks > 0) {\n minutes += weeks * calendar.weekMinutes;\n day += weeks * 7;\n continue;\n }\n }\n const shape = shapeFor(calendar, day);\n minutes += shape.totalMinutes - workedBefore(shape, minute);\n day += 1;\n minute = 0;\n }\n\n const shape = shapeFor(calendar, day);\n minutes += workedBefore(shape, minuteOfDay(to)) - workedBefore(shape, minute);\n return minutes * MS_PER_MINUTE;\n}\n\n/** True when `[from, to)` contains no working time at all — the shading predicate. */\nexport function isNonWorkingSpan(calendar: ResolvedCalendar | null, from: Date, to: Date): boolean {\n if (!calendar) {\n return false;\n }\n return countWorkingMs(calendar, from, to) === 0;\n}\n\n/** Why a column is shaded. Weekend vs holiday matters only for styling. */\nexport type NonWorkingReason = \"weekend\" | \"holiday\" | \"offHours\";\n\nexport interface NonWorkingInfo {\n isNonWorking: boolean;\n reason?: NonWorkingReason;\n}\n\nconst WORKING: NonWorkingInfo = { isNonWorking: false };\n\n/**\n * Whether a timeline column covering `[colStart, colEnd)` is non-working, and why.\n *\n * With no calendar this falls back to the hardcoded Sat/Sun rule so the default\n * look is unchanged. A **partial** day (a short Friday) counts as working and is\n * not shaded at day scale — partial shading at 40px per column would be noise —\n * but at hour scale the off-hours columns inside it shade individually.\n */\nexport function nonWorkingInfo(\n calendar: ResolvedCalendar | null,\n colStart: Date,\n colEnd: Date,\n): NonWorkingInfo {\n if (!calendar) {\n const day = colStart.getDay();\n if (day === 0 || day === 6) {\n return { isNonWorking: true, reason: \"weekend\" };\n }\n return WORKING;\n }\n if (countWorkingMs(calendar, colStart, colEnd) > 0) {\n return WORKING;\n }\n const dayIndex = civilDayIndex(colStart);\n if (calendar.byDate.has(dayIndex)) {\n return { isNonWorking: true, reason: \"holiday\" };\n }\n // A whole day with no working time at all is a weekend rule; a shorter slice\n // inside an otherwise-working day is just off-hours.\n const shape = shapeFor(calendar, dayIndex);\n if (shape.totalMinutes === 0) {\n return { isNonWorking: true, reason: \"weekend\" };\n }\n return { isNonWorking: true, reason: \"offHours\" };\n}\n\n/**\n * Working milliseconds one `unit` represents. A `\"day\"` is the week's longest\n * working day (ADR-018), so a weekends-off calendar over full days keeps\n * `duration: 3` meaning three whole days.\n */\nexport function workingMsPerUnit(calendar: ResolvedCalendar | null, unit: DurationUnit): number {\n if (unit === \"minute\") {\n return MS_PER_MINUTE;\n }\n if (unit === \"hour\") {\n return MS_PER_HOUR;\n }\n if (!calendar || calendar.msPerWorkingDay === 0) {\n return MS_PER_DAY;\n }\n return calendar.msPerWorkingDay;\n}\n\n/** {@link addWorkingMs} in whole `durationUnit`s. */\nexport function addWorkingUnits(\n calendar: ResolvedCalendar | null,\n from: Date,\n amount: number,\n unit: DurationUnit,\n anchorDir?: WalkDirection,\n): Date {\n return addWorkingMs(calendar, from, amount * workingMsPerUnit(calendar, unit), anchorDir);\n}\n","import type { DurationUnit, GanttTask } from \"../types\";\nimport type { ResolvedCalendar } from \"./calendar\";\nimport { startOfUnit } from \"./dateUtils\";\nimport { addWorkingUnits, countWorkingMs, workingMsPerUnit } from \"./workingTime\";\n\n/**\n * Everything outside a task that its dates depend on. Threaded explicitly through\n * `core/*` rather than read from context, so every function here stays a pure\n * unit-testable function with no React and no module state.\n */\nexport interface SchedulingContext {\n /** `null` means no calendar prop: plain linear time, exactly as before this feature. */\n calendar: ResolvedCalendar | null;\n durationUnit: DurationUnit;\n /** Whether library-authored dates snap onto working time (ADR-012). */\n snapToWorking: boolean;\n}\n\n/** The context a chart has with no `calendar` prop — linear time (ADR-002). */\nexport const LINEAR_CONTEXT: SchedulingContext = {\n calendar: null,\n durationUnit: \"day\",\n snapToWorking: true,\n};\n\n/**\n * The instant a task stops — **exclusive** (ADR-014). A Monday-to-Friday all-day\n * task ends at Saturday 00:00; a 9-to-5 Friday task ends at Friday 17:00.\n *\n * Precedence, preserving what `getEndDate` used to do: an explicit `endDate` wins,\n * else `duration` is walked out in working time on the chart's `durationUnit`,\n * else the task is an instant.\n *\n * A milestone or a zero duration is always an instant (ADR-009): a moment in time,\n * exempt from any duration basis.\n */\nexport function endInstantOf(task: GanttTask, ctx: SchedulingContext): Date {\n if (task.type === \"milestone\" || task.duration === 0) {\n return task.startDate;\n }\n if (task.endDate) {\n return task.endDate;\n }\n if (task.duration === undefined) {\n return task.startDate;\n }\n return addWorkingUnits(ctx.calendar, task.startDate, task.duration, ctx.durationUnit, 1);\n}\n\n/**\n * The inclusive last-occupied civil day, for **display only**.\n *\n * Stored dates are exclusive instants, which reads wrong in a column: a task\n * running Monday through Friday stores Saturday. This converts back for humans —\n * the day containing the last worked moment. Never write the result back to a task.\n */\nexport function displayEndDate(startDate: Date, endInstant: Date): Date {\n if (endInstant.getTime() <= startDate.getTime()) {\n return startOfUnit(startDate, \"day\");\n }\n return startOfUnit(new Date(endInstant.getTime() - 1), \"day\");\n}\n\n/**\n * Inverse of {@link displayEndDate} for a whole-day edit: the exclusive instant\n * starting the day after `displayEnd`.\n *\n * This is what a `<input type=\"date\">` end-date editor needs — the user picks the\n * last day they mean, and the task stores the following midnight.\n */\nexport function endInstantFromDisplayDate(displayEnd: Date): Date {\n return new Date(displayEnd.getFullYear(), displayEnd.getMonth(), displayEnd.getDate() + 1);\n}\n\n/**\n * The task's user-facing end date, or `undefined` when it is an instant.\n *\n * Backs `ColumnApi.format.endDate`. Lives here rather than inside the provider so\n * it is a plain function over a {@link SchedulingContext} — testable without\n * mounting a chart, and reusable by any consumer with the same problem.\n */\nexport function displayEndOf(task: GanttTask, ctx: SchedulingContext): Date | undefined {\n const end = endInstantOf(task, ctx);\n if (end.getTime() <= task.startDate.getTime()) {\n return undefined;\n }\n return displayEndDate(task.startDate, end);\n}\n\n/**\n * Working time the task occupies, expressed in the chart's `durationUnit`.\n *\n * Backs `ColumnApi.format.duration`. Measured through `countWorkingMs` so it is\n * additive and calendar-aware, then divided by what one unit is worth under that\n * calendar (ADR-018).\n */\nexport function workingDurationOf(task: GanttTask, ctx: SchedulingContext): number {\n const worked = countWorkingMs(ctx.calendar, task.startDate, endInstantOf(task, ctx));\n return worked / workingMsPerUnit(ctx.calendar, ctx.durationUnit);\n}\n","import type { CalendarUnit, GanttLabels, GanttTask, ResolvedGanttLabels } from \"../types\";\n\nexport const DEFAULT_LABELS: ResolvedGanttLabels = {\n gantt: \"Gantt chart\",\n taskList: \"Task list\",\n timeline: \"Timeline\",\n expand: \"Expand\",\n collapse: \"Collapse\",\n resizeTaskList: \"Resize task list\",\n deleteDependency: \"Delete dependency\",\n editTask: (task) => `Edit ${task.name}`,\n addTaskAfter: (task) => `Add task after ${task.name}`,\n deleteTask: (task) => `Delete ${task.name}`,\n bar: (task, { progress }) => formatBarLabel(task, progress),\n};\n\nexport function resolveLabels(labels: GanttLabels | undefined): ResolvedGanttLabels {\n if (!labels) {\n return DEFAULT_LABELS;\n }\n return { ...DEFAULT_LABELS, ...labels };\n}\n\nfunction formatDate(date: Date): string {\n return date.toLocaleDateString(undefined, { dateStyle: \"medium\" });\n}\n\nconst TYPE_NAMES: Record<NonNullable<GanttTask[\"type\"]>, string> = {\n task: \"task\",\n milestone: \"milestone\",\n summary: \"summary\",\n};\n\nexport function formatBarLabel(task: GanttTask, progress: number): string {\n const type = TYPE_NAMES[task.type ?? \"task\"];\n const parts = [task.name, type];\n if (task.endDate && task.endDate.getTime() !== task.startDate.getTime()) {\n parts.push(`${formatDate(task.startDate)} to ${formatDate(task.endDate)}`);\n } else {\n parts.push(formatDate(task.startDate));\n }\n // Milestones are a point in time — a completion percentage is meaningless.\n if (task.type !== \"milestone\") {\n parts.push(`${Math.round(progress)}% complete`);\n }\n return parts.join(\", \");\n}\n\nexport function formatPeriodLabel(date: Date, unit: CalendarUnit, step: number): string {\n switch (unit) {\n case \"minute\":\n case \"hour\":\n return date.toLocaleString(undefined, { dateStyle: \"long\", timeStyle: \"short\" });\n case \"day\":\n return date.toLocaleDateString(undefined, { dateStyle: \"long\" });\n case \"week\":\n return `Week of ${date.toLocaleDateString(undefined, { dateStyle: \"long\" })}`;\n case \"month\":\n return date.toLocaleDateString(undefined, { month: \"long\", year: \"numeric\" });\n case \"quarter\": {\n const quarter = Math.floor(date.getMonth() / 3) + 1;\n return `Q${quarter} ${date.getFullYear()}`;\n }\n case \"year\":\n return step > 1\n ? `${date.getFullYear()} to ${date.getFullYear() + step - 1}`\n : String(date.getFullYear());\n }\n}\n","import type { ChangeLog, GanttTask, Id, TaskCommand } from \"../types\";\nimport { LRUCache } from \"./lruCache\";\nimport { endInstantOf, LINEAR_CONTEXT, type SchedulingContext } from \"./taskDates\";\n\ntype TaskRecordsByParentId = Map<Id | null, GanttTask[]>;\n\n/**\n * The resolved task state is a single insertion-ordered Map: the Map IS the\n * display order. `set` on an existing key keeps its position (updates),\n * `delete` is O(1) and order-preserving, so only positional creates need a\n * one-pass rebuild — no parallel `order` array with indexOf/splice.\n */\nexport type ResolvedTaskMap = Map<Id, GanttTask>;\n\n/**\n * Group an already-resolved, ordered task map into the flattened display list\n * (parents rolled up from their children). Takes the resolved map rather than\n * `(tasks, log)` so callers that already hold the resolved state don't pay for\n * a second replay.\n */\nexport function getTaskList(\n resolvedById: ResolvedTaskMap,\n ctx: SchedulingContext = LINEAR_CONTEXT,\n): GanttTask[] {\n const taskByParentId = groupTaskByParentId(resolvedById.values());\n const roots = taskByParentId.get(null) ?? [];\n const flattened: GanttTask[] = [];\n for (const root of roots) {\n appendSubtree(root, taskByParentId, flattened, ctx);\n }\n return flattened;\n}\n\n/** Seed resolved state from the tasks prop: id → task, in display order. */\nexport function seedResolvedTasks(tasks: GanttTask[]): ResolvedTaskMap {\n const byId: ResolvedTaskMap = new Map();\n for (const task of tasks) {\n byId.set(task.id, task);\n }\n return byId;\n}\n\n/**\n * Replay the applied slice of the change log (`transactions[0..cursor]`) over\n * the seed tasks, returning the effective tasks keyed by id in display order.\n * Pure full replay — prefer `resolveCommittedTasksCached` in render paths.\n */\nexport function resolveCommittedTasks(tasks: GanttTask[], log: ChangeLog): ResolvedTaskMap {\n let resolved = seedResolvedTasks(tasks);\n for (let k = 0; k < log.cursor; k++) {\n resolved = applyCommands(resolved, log.transactions[k]!);\n }\n return resolved;\n}\n\n/**\n * Apply one transaction immutably: returns a new map, structurally sharing\n * every untouched task. O(n) for the clone plus O(1) per update/delete.\n */\nexport function applyTransaction(\n resolved: ResolvedTaskMap,\n commands: TaskCommand[],\n): ResolvedTaskMap {\n return applyCommands(new Map(resolved), commands);\n}\n\n/**\n * Apply commands to a map the caller owns. Mutates `map` where possible and\n * returns the map to use afterwards (positional creates rebuild).\n */\nfunction applyCommands(map: ResolvedTaskMap, commands: TaskCommand[]): ResolvedTaskMap {\n for (const cmd of commands) {\n switch (cmd.type) {\n case \"update\":\n // set() on an existing key keeps its insertion position.\n if (map.has(cmd.task.id)) {\n map.set(cmd.task.id, cmd.task);\n }\n break;\n case \"delete\":\n map.delete(cmd.id);\n break;\n case \"create\":\n map = insertTask(map, cmd.task, cmd.afterId);\n break;\n }\n }\n return map;\n}\n\n/**\n * Insert `task` after `afterId`. Matches the historical replay semantics:\n * `afterId == null` appends; a given-but-missing `afterId` prepends.\n */\nfunction insertTask(\n map: ResolvedTaskMap,\n task: GanttTask,\n afterId: Id | null | undefined,\n): ResolvedTaskMap {\n if (afterId == null) {\n map.set(task.id, task);\n return map;\n }\n const next: ResolvedTaskMap = new Map();\n if (!map.has(afterId)) {\n next.set(task.id, task);\n }\n for (const [id, existing] of map) {\n next.set(id, existing);\n if (id === afterId) {\n next.set(task.id, task);\n }\n }\n return next;\n}\n\n// --- Cached incremental resolution -----------------------------------------\n\ninterface ResolveSnapshot {\n /** The transaction whose application produced this snapshot; null = seed. */\n producedBy: TaskCommand[] | null;\n map: ResolvedTaskMap;\n}\n\n/**\n * Snapshots of the resolved state keyed by cursor position. A transaction\n * array element is created exactly once at one log position with one fixed\n * prefix (appends preserve the kept prefix; dropped redo branches never\n * return), so `producedBy === log.transactions[k - 1]` proves the whole\n * prefix matches and the snapshot at `k` is valid.\n */\nexport interface ResolveCache {\n seedTasks: GanttTask[] | null;\n snapshots: LRUCache<number, ResolveSnapshot>;\n}\n\nconst RESOLVE_SNAPSHOT_CAPACITY = 32;\n\nexport function createResolveCache(): ResolveCache {\n return { seedTasks: null, snapshots: new LRUCache(RESOLVE_SNAPSHOT_CAPACITY) };\n}\n\n/**\n * Like `resolveCommittedTasks`, but incremental: reuses the deepest valid\n * snapshot at or below the cursor and only applies the transactions past it.\n * A new edit costs one O(n) clone instead of a full log replay; undo/redo to\n * a recently seen cursor returns the cached map with no work at all.\n */\nexport function resolveCommittedTasksCached(\n cache: ResolveCache,\n tasks: GanttTask[],\n log: ChangeLog,\n): ResolvedTaskMap {\n if (cache.seedTasks !== tasks) {\n cache.seedTasks = tasks;\n cache.snapshots = new LRUCache(RESOLVE_SNAPSHOT_CAPACITY);\n }\n\n let base = 0;\n let resolved: ResolvedTaskMap | null = null;\n for (let k = log.cursor; k >= 1; k--) {\n const snapshot = cache.snapshots.get(k);\n if (snapshot && snapshot.producedBy === log.transactions[k - 1]) {\n base = k;\n resolved = snapshot.map;\n break;\n }\n }\n if (!resolved) {\n const seed = cache.snapshots.get(0);\n resolved = seed ? seed.map : seedResolvedTasks(tasks);\n if (!seed) {\n cache.snapshots.put(0, { producedBy: null, map: resolved });\n }\n }\n\n for (let k = base; k < log.cursor; k++) {\n const transaction = log.transactions[k]!;\n resolved = applyTransaction(resolved, transaction);\n cache.snapshots.put(k + 1, { producedBy: transaction, map: resolved });\n }\n return resolved;\n}\n\n// --- Tree flattening --------------------------------------------------------\n\n/**\n * Emit `task`'s subtree depth-first into `out` and return the task's\n * effective (rolled-up) version. The parent is emitted as a placeholder\n * before its children, then patched in place once their roll-up is known —\n * one shared output array, no per-level flatMap/concat copying.\n */\nfunction appendSubtree(\n task: GanttTask,\n taskByParentId: TaskRecordsByParentId,\n out: GanttTask[],\n ctx: SchedulingContext,\n): GanttTask {\n const children = taskByParentId.get(task.id);\n if (!children || children.length === 0) {\n const leaf = materializeEnd(task, ctx);\n out.push(leaf);\n return leaf;\n }\n\n const slot = out.length;\n out.push(task);\n const effectiveChildren: GanttTask[] = [];\n for (const child of children) {\n effectiveChildren.push(appendSubtree(child, taskByParentId, out, ctx));\n }\n const effective = getParentTaskData(task, effectiveChildren, ctx);\n out[slot] = effective;\n return effective;\n}\n\n/**\n * Give every task in the display list a concrete exclusive `endDate` (ADR-019).\n *\n * This is where the calendar is applied, once. Downstream — `computeTaskPixels`,\n * the dependency-link geometry, `getMinMaxDates`, zoom, `buildDatesFromTasks` —\n * reads plain dates and needs no calendar awareness at all.\n *\n * Identity is preserved when nothing changes, so an already-dated task is not\n * re-allocated on every render.\n */\nfunction materializeEnd(task: GanttTask, ctx: SchedulingContext): GanttTask {\n const end = endInstantOf(task, ctx);\n if (task.endDate && task.endDate.getTime() === end.getTime()) {\n return task;\n }\n if (!task.endDate && end === task.startDate) {\n return task;\n }\n return { ...task, endDate: end };\n}\n\nexport function getParentTaskData(\n task: GanttTask,\n children: GanttTask[],\n ctx: SchedulingContext = LINEAR_CONTEXT,\n): GanttTask {\n // Only summary tasks roll their children's dates/progress up. A parent typed\n // \"task\" or \"milestone\" (or untyped) keeps its own data and renders as a\n // regular bar, even when it has children.\n if (task.type !== \"summary\" || children.length === 0) {\n return materializeEnd(task, ctx);\n }\n\n let startDate = children[0]!.startDate;\n let endDate = endInstantOf(children[0]!, ctx);\n let progressSum = 0;\n let notMilestoneCount = 0;\n\n for (const child of children) {\n if (child.startDate < startDate) {\n startDate = child.startDate;\n }\n\n // Resolve every child, not just those carrying an explicit endDate: a\n // `{ startDate, duration }` child used to contribute only its start, so the\n // parent silently under-reported its own span.\n const childEnd = endInstantOf(child, ctx);\n if (childEnd > endDate) {\n endDate = childEnd;\n }\n\n // Milestones are moments, not work: they contribute neither progress nor\n // weight to the roll-up. A non-milestone child without progress still\n // counts as 0% so unstarted work drags the average down.\n if (child.type !== \"milestone\") {\n notMilestoneCount++;\n progressSum += child.progress ?? 0;\n }\n }\n\n const progress = notMilestoneCount === 0 ? 0 : Math.round(progressSum / notMilestoneCount);\n\n return {\n ...task,\n startDate,\n endDate,\n progress,\n };\n}\n\nfunction groupTaskByParentId(tasks: Iterable<GanttTask>): TaskRecordsByParentId {\n const acc: TaskRecordsByParentId = new Map();\n for (const task of tasks) {\n const parentId = task.parentId ?? null;\n const siblings = acc.get(parentId) ?? [];\n siblings.push(task);\n acc.set(parentId, siblings);\n }\n return acc;\n}\n","/**\n * FIFO queue backed by a single array with a moving read cursor.\n *\n * Plain `Array.shift()` is O(n) — it re-indexes every remaining element on each\n * dequeue, so draining n items costs O(n²). Here `dequeue` just advances a head\n * pointer (O(1)); the consumed prefix is compacted lazily once it dominates the\n * array, keeping memory bounded without paying the re-index cost per item.\n */\nexport class Queue<T> {\n private items: T[] = [];\n private head = 0;\n\n constructor(initial?: Iterable<T>) {\n if (initial) {\n this.items.push(...initial);\n }\n }\n\n get size(): number {\n return this.items.length - this.head;\n }\n\n isEmpty(): boolean {\n return this.size === 0;\n }\n\n enqueue(item: T): void {\n this.items.push(item);\n }\n\n dequeue(): T | undefined {\n if (this.head >= this.items.length) {\n return undefined;\n }\n const item = this.items[this.head];\n this.head++;\n\n // Reclaim the consumed prefix once it grows past half the array.\n // this.head > this.items.length / 2 is equivalent but may involve a slower division, so we use a bit shift.\n if (this.head > this.items.length >> 1) {\n this.items = this.items.slice(this.head);\n this.head = 0;\n }\n\n return item;\n }\n}\n","import type { GanttTask, Id, TaskDependency, TaskDependencyType } from \"../types\";\nimport type { BarCommit } from \"./barUtils\";\nimport { Queue } from \"./queue\";\nimport { endInstantOf, LINEAR_CONTEXT, type SchedulingContext } from \"./taskDates\";\nimport {\n addWorkingMs,\n closestWorkingTime,\n countWorkingMs,\n nearestWorkingTime,\n workingMsPerUnit,\n} from \"./workingTime\";\n\ninterface Span {\n start: Date;\n /** The instant work stops — EXCLUSIVE (ADR-014). Equals `start` for milestones. */\n end: Date;\n}\n\nfunction spanOf(task: GanttTask, ctx: SchedulingContext): Span {\n return {\n start: task.startDate,\n end: endInstantOf(task, ctx),\n };\n}\n\n/** Working time a task occupies, in milliseconds. */\nfunction workingLengthOf(task: GanttTask, ctx: SchedulingContext): number {\n const { start, end } = spanOf(task, ctx);\n return countWorkingMs(ctx.calendar, start, end);\n}\n\n/**\n * Earliest start a successor may take given a single predecessor and the\n * relationship type, using ASAP forward-scheduling rules.\n *\n * `endDate` is an exclusive instant, so a finish-to-start link starts the\n * successor exactly where the predecessor stopped — the `+1`/`-1` day fudges the\n * old inclusive model needed are gone, not ported.\n *\n * FF and SF are **decomposed** into two separately anchored walks rather than\n * folding `lag - successorLength` into one offset (ADR-007). Folding is wrong\n * twice under working time: the two terms are measured from different anchors,\n * and they travel in opposite directions when their signs differ, so working-time\n * addition — which is not linear — cannot combine them.\n *\n * The explicit anchor direction matters most at `lag === 0`, the commonest value:\n * FS/SS compute a *start* and must project forward, while FF/SF compute a\n * *finish* and must project backward. Deriving the direction from the sign of a\n * zero would silently pick the wrong one.\n */\nfunction constrainedStart(\n pred: Span,\n type: TaskDependencyType,\n lagMs: number,\n successorLength: number,\n ctx: SchedulingContext,\n): Date {\n const cal = ctx.calendar;\n switch (type) {\n case \"FS\": // successor starts where the predecessor finished\n return addWorkingMs(cal, pred.end, lagMs, 1);\n case \"SS\": // successor starts together with the predecessor\n return addWorkingMs(cal, pred.start, lagMs, 1);\n case \"FF\": {\n // successor finishes together with the predecessor\n const finish = addWorkingMs(cal, pred.end, lagMs, -1);\n return addWorkingMs(cal, finish, -successorLength, -1);\n }\n case \"SF\": {\n // successor finishes when the predecessor starts\n const finish = addWorkingMs(cal, pred.start, lagMs, -1);\n return addWorkingMs(cal, finish, -successorLength, -1);\n }\n }\n}\n\n/**\n * Adjacency index over the dependency list, built once and reused across\n * commits (memoize on the dependency array). Both lookups are by task id so the\n * forward walk stays O(1) per edge.\n */\nexport interface DependencyGraph {\n /** predecessor id → ids of its direct successors (traversal order) */\n successorsOf: Map<Id, Id[]>;\n /** successor id → the dependencies that constrain it (constraint inputs) */\n predecessorDeps: Map<Id, TaskDependency[]>;\n /** number of dependency edges (used to bound the relaxation loop) */\n size: number;\n}\n\nexport function buildDependencyGraph(dependencies: TaskDependency[]): DependencyGraph {\n const successorsOf = new Map<Id, Id[]>();\n const predecessorDeps = new Map<Id, TaskDependency[]>();\n for (const dep of dependencies) {\n const successorList = successorsOf.get(dep.from);\n if (successorList) {\n successorList.push(dep.to);\n } else {\n successorsOf.set(dep.from, [dep.to]);\n }\n\n const deps = predecessorDeps.get(dep.to);\n if (deps) {\n deps.push(dep);\n } else {\n predecessorDeps.set(dep.to, [dep]);\n }\n }\n return { successorsOf, predecessorDeps, size: dependencies.length };\n}\n\n/**\n * The mutable working set a cascade walks: reads of the effective task state,\n * writes of the tasks it moves. A plain `Map` satisfies it; so does the\n * copy-on-write view from {@link overlayOf}, which is what keeps a cascade from\n * cloning the whole resolved map on every edit.\n */\nexport interface TaskWorkingSet {\n get(id: Id): GanttTask | undefined;\n set(id: Id, task: GanttTask): void;\n readonly size: number;\n}\n\n/**\n * Copy-on-write view over the resolved task map: reads fall through to `base`,\n * writes land in a small overlay, so `base` is never touched and no O(n) clone\n * is paid (~17ms at 100k tasks, on every single edit).\n */\nexport function overlayOf(base: ReadonlyMap<Id, GanttTask>): TaskWorkingSet {\n const patch = new Map<Id, GanttTask>();\n return {\n get: (id) => patch.get(id) ?? base.get(id),\n set: (id, task) => {\n patch.set(id, task);\n },\n // A cascade only ever replaces existing tasks, so the base size still bounds\n // the relaxation loop.\n get size() {\n return base.size;\n },\n };\n}\n\n/**\n * Earliest start `task` may take so that *every* incoming dependency is\n * satisfied — the latest constraint across all predecessors, or `null` when the\n * task has none.\n */\nfunction earliestStart(\n task: GanttTask,\n predecessorDeps: Map<Id, TaskDependency[]>,\n current: TaskWorkingSet,\n ctx: SchedulingContext,\n): Date | null {\n const length = workingLengthOf(task, ctx);\n const msPerUnit = workingMsPerUnit(ctx.calendar, ctx.durationUnit);\n let earliest: Date | null = null;\n for (const dep of predecessorDeps.get(task.id) ?? []) {\n const pred = current.get(dep.from);\n if (!pred) {\n continue;\n }\n const candidate = constrainedStart(\n spanOf(pred, ctx),\n dep.type,\n (dep.lag ?? 0) * msPerUnit,\n length,\n ctx,\n );\n if (earliest === null || candidate > earliest) {\n earliest = candidate;\n }\n }\n if (earliest === null) {\n return null;\n }\n // Project once, here, so the value the caller compares against is a fixpoint.\n // `closestWorkingTime` is idempotent, so a task already parked on this instant\n // stops moving; without this the strict comparison below could keep firing and\n // silently exhaust the iteration guard, yielding a wrong-but-stable schedule.\n return closestWorkingTime(ctx.calendar, earliest, 1);\n}\n\n/** A copy of `task` moved to `start`, preserving the working time it occupies. */\nfunction movedTo(task: GanttTask, start: Date, ctx: SchedulingContext): GanttTask {\n // A milestone is an instant: its end mirrors its start, never lags behind it.\n // This is the single milestone rule — `useTaskList` defers to it rather than\n // keeping its own.\n if (task.type === \"milestone\") {\n return { ...task, startDate: start, endDate: start };\n }\n return {\n ...task,\n startDate: start,\n endDate: addWorkingMs(ctx.calendar, start, workingLengthOf(task, ctx), 1),\n };\n}\n\n/**\n * Turn a finished drag into the dates to store — the one place a pixel-derived\n * value meets the calendar.\n *\n * A **move** preserves the task's working time, not its pixel width: drag a\n * three-working-day task onto a Thursday and it still occupies three working days,\n * growing visually across the weekend. A **resize** sets the working time instead,\n * so an edge dropped in non-working time settles back onto the nearest working\n * boundary (ADR-005) — quantization, which happens even with `snapToWorking` off.\n *\n * Starts always project forward and ends backward (ADR-020), which is what keeps\n * every library-authored task forward-anchored at its start and backward-anchored\n * at its end — the precondition that makes span round-trips exact.\n */\nexport function resolveCommit(\n task: GanttTask,\n commit: BarCommit,\n ctx: SchedulingContext,\n): { startDate: Date; endDate: Date } {\n const cal = ctx.calendar;\n const snap = ctx.snapToWorking;\n const span = spanOf(task, ctx);\n\n if (task.type === \"milestone\") {\n const raw = commit.kind === \"resizeEnd\" ? commit.endDate : commit.startDate;\n const at = snap ? nearestWorkingTime(cal, raw) : raw;\n return { startDate: at, endDate: at };\n }\n\n if (commit.kind === \"move\") {\n const length = countWorkingMs(cal, span.start, span.end);\n const start = snap ? closestWorkingTime(cal, commit.startDate, 1) : commit.startDate;\n return { startDate: start, endDate: addWorkingMs(cal, start, length, 1) };\n }\n\n // Resize: project both edges inward and clamp to at least some working time.\n // The untouched edge is unchanged pixel-wise, so projecting it is a no-op on an\n // already-valid task — which is also what fixes the old bug where snapping the\n // start handle could shift the far edge by a whole column.\n const rawStart = commit.kind === \"resizeStart\" ? commit.startDate : span.start;\n const rawEnd = commit.kind === \"resizeEnd\" ? commit.endDate : span.end;\n const start = snap ? closestWorkingTime(cal, rawStart, 1) : rawStart;\n const end = snap ? closestWorkingTime(cal, rawEnd, -1) : rawEnd;\n\n if (countWorkingMs(cal, start, end) <= 0) {\n // Collapsed or inverted — keep one unit of working time anchored on the edge\n // the user was NOT dragging.\n const unitMs = workingMsPerUnit(cal, ctx.durationUnit);\n if (commit.kind === \"resizeStart\") {\n return { startDate: addWorkingMs(cal, end, -unitMs, -1), endDate: end };\n }\n return { startDate: start, endDate: addWorkingMs(cal, start, unitMs, 1) };\n }\n return { startDate: start, endDate: end };\n}\n\n/**\n * Re-schedule the dependents of a changed task.\n *\n * First clamps the changed task itself forward if the user moved it so that it\n * violates one of its own predecessors — e.g. dragging a start-to-start\n * successor before its predecessor snaps its start back onto the predecessor's\n * (a valid earlier/later move is left untouched).\n *\n * Then walks the dependency graph forward from `changedId`. Dependencies act as\n * a lower bound: a successor is pushed later only when a move would violate it\n * (taking the latest constraint when several predecessors apply), and is never\n * pulled earlier when a predecessor moves back. Its duration is preserved and\n * its own successors are then revisited. Returns only the tasks whose dates\n * moved.\n *\n * `current` is the working set of effective tasks and is written to in place as\n * the schedule settles — pass {@link overlayOf} to leave the caller's resolved\n * map untouched. A per-call iteration cap keeps dependency cycles from looping\n * forever.\n */\nexport function scheduleDependents(\n current: TaskWorkingSet,\n graph: DependencyGraph,\n changedId: Id,\n ctx: SchedulingContext = LINEAR_CONTEXT,\n): Map<Id, GanttTask> {\n const { successorsOf, predecessorDeps } = graph;\n\n const changed = new Map<Id, GanttTask>();\n\n // Clamp the dragged task forward to satisfy its own predecessors before\n // cascading. Only a violating (too-early) move is corrected; the constraint\n // is a lower bound, so a valid drag is preserved.\n const changedTask = current.get(changedId);\n if (changedTask) {\n const earliest = earliestStart(changedTask, predecessorDeps, current, ctx);\n if (earliest !== null && earliest.getTime() > changedTask.startDate.getTime()) {\n const clamped = movedTo(changedTask, earliest, ctx);\n current.set(changedId, clamped);\n changed.set(changedId, clamped);\n }\n }\n\n const queue = new Queue<Id>([changedId]);\n const maxIterations = (graph.size + 1) * (current.size + 1);\n let iterations = 0;\n\n while (!queue.isEmpty()) {\n if (iterations++ > maxIterations) {\n break;\n } // guard against dependency cycles\n const predId = queue.dequeue()!;\n\n for (const successorId of successorsOf.get(predId) ?? []) {\n const successor = current.get(successorId);\n if (!successor) {\n continue;\n }\n\n const earliest = earliestStart(successor, predecessorDeps, current, ctx);\n if (earliest === null) {\n continue;\n }\n // Lower bound only: push a violating (too-early) successor forward, but\n // never pull it earlier when a predecessor moves back. Compared as instants\n // rather than whole days, so a sub-day violation cascades too.\n if (earliest.getTime() <= successor.startDate.getTime()) {\n continue;\n }\n\n const next = movedTo(successor, earliest, ctx);\n current.set(successorId, next);\n changed.set(successorId, next);\n queue.enqueue(successorId);\n }\n }\n\n return changed;\n}\n","import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type { ChangeLog, GanttTask, Id, TaskCommand, TaskDependency, TaskPatch } from \"../types\";\nimport {\n createResolveCache,\n getTaskList,\n resolveCommittedTasksCached,\n type ResolveCache,\n} from \"../core/prepareData\";\nimport {\n buildDependencyGraph,\n overlayOf,\n resolveCommit,\n scheduleDependents,\n} from \"../core/scheduling\";\nimport type { BarCommit } from \"../core/barUtils\";\nimport { LINEAR_CONTEXT, type SchedulingContext } from \"../core/taskDates\";\n\nconst EMPTY_LOG: ChangeLog = { transactions: [], cursor: 0 };\n\n// Module-level so an omitted `dependencies` prop keeps a stable identity and\n// the dependency graph isn't rebuilt on every render.\nexport const EMPTY_DEPENDENCIES: TaskDependency[] = [];\n\n/**\n * Every log mutation except `createTask` is scheduled at transition priority.\n *\n * The state update itself is trivial; the render it schedules is the expensive\n * half of an edit — rebuilding the display list and re-deriving every link's\n * geometry, ~230ms at 100k tasks. At transition priority React keeps the current\n * UI on screen while it prepares the next one, and real user input outranks that\n * work: a burst of edits restarts the pending render instead of committing every\n * intermediate one.\n *\n * This does not make an edit cheaper — the recompute is the same length either\n * way. It only stops that recompute from being the highest-priority thing on the\n * main thread.\n *\n * `createTask` stays synchronous (`flushSync`): its contract is that the new\n * task is already resolved when `onTaskCreate` fires.\n *\n * IMPORTANT for callers that pair a mutation with clearing a drag preview: both\n * updates must be made inside ONE `startTransition` so they land in the same\n * commit. Clearing the preview urgently while the dates arrive later paints one\n * frame of the bar back at its old position — see `Row`'s commit handlers.\n */\nfunction scheduleLogUpdate(update: () => void): void {\n startTransition(update);\n}\n\n/** Drop any redo branch, append `commands` as one transaction, advance the cursor. */\nfunction appendTransaction(log: ChangeLog, commands: TaskCommand[]): ChangeLog {\n const kept = log.transactions.slice(0, log.cursor);\n return { transactions: [...kept, commands], cursor: kept.length + 1 };\n}\n\n/** Field-agnostic value equality; `Date`s compare by instant, not reference. */\nfunction valuesEqual(a: unknown, b: unknown): boolean {\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n return Object.is(a, b);\n}\n\n/** True when two tasks are equal across every field (Date-aware). */\nfunction sameTask(a: GanttTask, b: GanttTask): boolean {\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n for (const key of keys) {\n if (!valuesEqual(a[key as keyof GanttTask], b[key as keyof GanttTask])) {\n return false;\n }\n }\n return true;\n}\n\nexport interface UseTaskListOptions {\n onTaskCreate?: (task: GanttTask, afterId?: Id | null) => void;\n onTaskDelete?: (id: Id) => void;\n onTasksChange?: (tasks: GanttTask[]) => void;\n}\n\nexport const useTaskList = (\n tasks: GanttTask[],\n dependencies: TaskDependency[] = EMPTY_DEPENDENCIES,\n options: UseTaskListOptions = {},\n ctx: SchedulingContext = LINEAR_CONTEXT,\n) => {\n // Latest-ref so the returned mutators stay identity-stable even when the\n // caller passes inline callbacks; handlers read the current options at call\n // time. Updated during render, same pattern as `resolvedRef` below.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // Same treatment for the scheduling context: event handlers need it fresh, but\n // must not gain a new identity when it changes, because `columnApi` and the\n // task-actions context memo on them. Memos below take it as a real dependency\n // instead — they need invalidation, not freshness.\n const ctxRef = useRef(ctx);\n ctxRef.current = ctx;\n const [log, setLog] = useState<ChangeLog>(EMPTY_LOG);\n\n // Built once per dependency list and reused across every commit.\n const dependencyGraph = useMemo(() => buildDependencyGraph(dependencies), [dependencies]);\n\n // Resolve the log incrementally: the cache reuses the snapshot at the\n // previous cursor, so an edit costs one map clone instead of replaying the\n // whole log, and undo/redo to a recent cursor reuses the cached map as-is.\n // Both the display list and the edit base derive from this single resolved\n // map — no second replay.\n const resolveCacheRef = useRef<ResolveCache | null>(null);\n const resolvedById = useMemo(() => {\n resolveCacheRef.current ??= createResolveCache();\n return resolveCommittedTasksCached(resolveCacheRef.current, tasks, log);\n }, [tasks, log]);\n\n // Mirror the latest resolved map so event handlers (updateTask) can read the\n // current effective state without replaying. Updated every render, so at the\n // time a handler fires it matches the committed `log` (= `prev`).\n const resolvedRef = useRef(resolvedById);\n resolvedRef.current = resolvedById;\n\n // Depends on the calendar: the roll-up resolves duration-only children through\n // it, so a calendar change must recompute or every summary bar goes stale.\n const tasksList = useMemo(() => getTaskList(resolvedById, ctx), [resolvedById, ctx]);\n\n /**\n * Commit a finished drag. Unlike `updateTask` — which writes consumer-supplied\n * dates verbatim — this is the library authoring dates, so it is the only path\n * that snaps onto working time (ADR-012).\n */\n const commitTask = useCallback(\n (id: Id, commit: BarCommit) => {\n const base = resolvedRef.current.get(id);\n if (!base) {\n return;\n }\n const { startDate, endDate } = resolveCommit(base, commit, ctxRef.current);\n const nextTask: GanttTask = { ...base, startDate, endDate };\n\n // A drag that resolves back to where it started records no undo step, which is\n // also what makes a bar dropped in non-working time visibly settle back: the\n // transient override is cleared unconditionally and nothing replaces it.\n if (sameTask(nextTask, base)) {\n return;\n }\n\n const commands: TaskCommand[] = [{ type: \"update\", task: nextTask }];\n if (dependencyGraph.size > 0) {\n // Copy-on-write view, not a clone: the cascade touches a handful of tasks,\n // so cloning the whole resolved map would dominate the edit at scale.\n const current = overlayOf(resolvedRef.current);\n current.set(id, nextTask);\n const rescheduled = scheduleDependents(current, dependencyGraph, id, ctxRef.current);\n for (const task of rescheduled.values()) {\n commands.push({ type: \"update\", task });\n }\n }\n scheduleLogUpdate(() => setLog((prev) => appendTransaction(prev, commands)));\n },\n [dependencyGraph],\n );\n\n const updateTask = useCallback(\n (id: Id, patch: TaskPatch) => {\n // Build on the latest committed task (pre-roll-up) from the resolved map.\n const base = resolvedRef.current.get(id);\n if (!base) {\n return;\n }\n\n const nextTask: GanttTask = { ...base };\n if (patch.name !== undefined) {\n nextTask.name = patch.name;\n }\n if (patch.startDate) {\n nextTask.startDate = patch.startDate;\n }\n if (patch.endDate) {\n nextTask.endDate = patch.endDate;\n }\n if (patch.progress !== undefined) {\n nextTask.progress = patch.progress;\n }\n\n // Nothing actually changed → skip the empty undo step (and any reschedule).\n if (sameTask(nextTask, base)) {\n return;\n }\n\n const commands: TaskCommand[] = [{ type: \"update\", task: nextTask }];\n\n // Automatic forward scheduling: when a task moves, realign its dependents\n // so each dependency relationship stays satisfied, then cascade onward.\n // All reschedules join the same transaction → one undo step.\n const moved = patch.startDate !== undefined || patch.endDate !== undefined;\n if (moved && dependencyGraph.size > 0) {\n // Copy-on-write view so scheduling never touches the shared resolved map,\n // without paying an O(n) clone for a cascade that moves a handful of tasks.\n const current = overlayOf(resolvedRef.current);\n current.set(id, nextTask);\n const rescheduled = scheduleDependents(current, dependencyGraph, id, ctxRef.current);\n for (const task of rescheduled.values()) {\n commands.push({ type: \"update\", task });\n }\n }\n\n scheduleLogUpdate(() => setLog((prev) => appendTransaction(prev, commands)));\n },\n [dependencyGraph],\n );\n\n const createTask = useCallback((task: GanttTask, afterId?: Id | null) => {\n // Commit synchronously so the new task is present in the resolved list (and\n // thus in the consumer's `visibleTasks`) before `onTaskCreate` fires. This\n // lets handlers like scroll-to-new-task read post-create state imperatively\n // without waiting for an effect.\n flushSync(() => {\n setLog((prev) => appendTransaction(prev, [{ type: \"create\", task, afterId }]));\n });\n optionsRef.current.onTaskCreate?.(task, afterId);\n }, []);\n\n const deleteTask = useCallback((id: Id) => {\n scheduleLogUpdate(() => setLog((prev) => appendTransaction(prev, [{ type: \"delete\", id }])));\n optionsRef.current.onTaskDelete?.(id);\n }, []);\n\n const undo = useCallback(() => {\n scheduleLogUpdate(() =>\n setLog((prev) => (prev.cursor > 0 ? { ...prev, cursor: prev.cursor - 1 } : prev)),\n );\n }, []);\n\n const redo = useCallback(() => {\n scheduleLogUpdate(() =>\n setLog((prev) =>\n prev.cursor < prev.transactions.length ? { ...prev, cursor: prev.cursor + 1 } : prev,\n ),\n );\n }, []);\n\n const canUndo = log.cursor > 0;\n const canRedo = log.cursor < log.transactions.length;\n\n const tasksListRef = useRef(tasksList);\n tasksListRef.current = tasksList;\n\n const notifiedLog = useRef(log);\n useEffect(() => {\n if (notifiedLog.current === log) {\n return;\n }\n notifiedLog.current = log;\n optionsRef.current.onTasksChange?.(tasksListRef.current);\n }, [log]);\n\n return {\n tasksList,\n updateTask,\n commitTask,\n createTask,\n deleteTask,\n undo,\n redo,\n canUndo,\n canRedo,\n };\n};\n","import { useRef } from \"react\";\n\n/**\n * Ref that always holds the latest `value`, written during render (not in an\n * effect). The render-phase write is deliberate and load-bearing: same-render\n * reads must see the current value — e.g. `createTask` flushSync-commits,\n * re-renders synchronously, then immediately reads refs updated by that very\n * render. Do not convert to an effect. (Same pattern as `useTaskList`'s\n * optionsRef and `useDrag`'s onDragRef.)\n */\nexport function useLatestRef<T>(value: T): React.RefObject<T> {\n const ref = useRef(value);\n ref.current = value;\n return ref;\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport type { GanttTask, Id } from \"../types\";\nimport { useLatestRef } from \"./useLatestRef\";\n\nexport function useExpand(tasksList: GanttTask[]) {\n const parentIds = useMemo(() => {\n const ids = new Set<Id>();\n for (const t of tasksList) {\n if (t.parentId != null) {\n ids.add(t.parentId);\n }\n }\n return ids;\n }, [tasksList]);\n\n const [collapsedIds, setCollapsedIds] = useState<Set<Id>>(new Set());\n\n const toggleExpand = useCallback((id: Id) => {\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n const tasksListRef = useLatestRef(tasksList);\n\n // Returns the previous set unchanged when nothing was collapsed, so a reveal\n // that has no work to do does not trigger a render.\n //\n // The id → task index is built here rather than memoized per render: nothing\n // reads it during render, so an eager index would tax every edit (~15ms at\n // 100k tasks) to serve a walk that only happens on an explicit reveal — and\n // only when something is actually collapsed.\n const revealAncestors = useCallback(\n (id: Id) => {\n setCollapsedIds((prev) => {\n if (prev.size === 0) {\n return prev;\n }\n const taskById = new Map<Id, GanttTask>();\n for (const t of tasksListRef.current) {\n taskById.set(t.id, t);\n }\n const next = new Set(prev);\n let changed = false;\n let cur = taskById.get(id);\n while (cur && cur.parentId != null) {\n if (next.delete(cur.parentId)) {\n changed = true;\n }\n cur = taskById.get(cur.parentId);\n }\n return changed ? next : prev;\n });\n },\n [tasksListRef],\n );\n\n const expandedIds = useMemo(() => {\n const expanded = new Set<Id>();\n for (const id of parentIds) {\n if (!collapsedIds.has(id)) {\n expanded.add(id);\n }\n }\n return expanded;\n }, [parentIds, collapsedIds]);\n\n const visibleTasks = useMemo(() => {\n if (collapsedIds.size === 0) {\n return tasksList;\n }\n const hiddenAncestors = new Set<Id>();\n const result: GanttTask[] = [];\n for (const task of tasksList) {\n if (\n task.parentId != null &&\n (hiddenAncestors.has(task.parentId) || collapsedIds.has(task.parentId))\n ) {\n hiddenAncestors.add(task.id);\n continue;\n }\n result.push(task);\n }\n return result;\n }, [tasksList, collapsedIds]);\n\n return { visibleTasks, expandedIds, parentIds, toggleExpand, revealAncestors };\n}\n","import { useEffect, useLayoutEffect } from \"react\";\n\n/**\n * `useLayoutEffect` on the client, `useEffect` during SSR. Neither runs on the\n * server, so behavior is identical — this only avoids React 18's dev warning\n * (\"useLayoutEffect does nothing on the server\") for SSR consumers. React 19\n * removed that warning; drop this alias if the peer range ever excludes 18.\n */\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { useLatestRef } from \"./useLatestRef\";\n\n/** Scroll offset + client size of a scroll viewport, read for virtualization. */\nexport interface ViewportMetrics {\n scrollTop: number;\n scrollLeft: number;\n clientWidth: number;\n clientHeight: number;\n}\n\nconst ZERO_METRICS: ViewportMetrics = {\n scrollTop: 0,\n scrollLeft: 0,\n clientWidth: 0,\n clientHeight: 0,\n};\n\nfunction readMetrics(el: HTMLDivElement): ViewportMetrics {\n return {\n scrollTop: el.scrollTop,\n scrollLeft: el.scrollLeft,\n clientWidth: el.clientWidth,\n clientHeight: el.clientHeight,\n };\n}\n\nfunction sameMetrics(a: ViewportMetrics, b: ViewportMetrics, trackHorizontal: boolean): boolean {\n if (a.scrollTop !== b.scrollTop || a.clientHeight !== b.clientHeight) {\n return false;\n }\n if (!trackHorizontal) {\n return true;\n }\n return a.scrollLeft === b.scrollLeft && a.clientWidth === b.clientWidth;\n}\n\ninterface UseViewportMeasureOptions {\n /**\n * Include scrollLeft/clientWidth in change detection. Off for panes that\n * only window rows vertically (TaskList): width churn from column/splitter\n * resizes must not re-render them.\n */\n trackHorizontal?: boolean;\n}\n\n/**\n * Track a scroll container's viewport metrics for virtualization: measured\n * before first paint, kept in sync via ResizeObserver, and re-measured on\n * demand (`scheduleMeasure`, typically from an onScroll handler). Bursts of\n * scroll/resize events coalesce into one state update per frame, with an\n * identity bail-out when metrics are unchanged. `scheduleMeasure` is\n * identity-stable forever.\n */\nexport function useViewportMeasure(\n targetRef: React.RefObject<HTMLDivElement | null>,\n { trackHorizontal = true }: UseViewportMeasureOptions = {},\n): { viewport: ViewportMetrics; scheduleMeasure: () => void } {\n const frameRef = useRef<number | null>(null);\n const trackHorizontalRef = useLatestRef(trackHorizontal);\n\n const [viewport, setViewport] = useState<ViewportMetrics>(ZERO_METRICS);\n\n // Coalesce bursts of scroll/resize events into one state update per frame.\n const scheduleMeasure = useCallback(() => {\n if (frameRef.current !== null) {\n return;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n const el = targetRef.current;\n if (!el) {\n return;\n }\n const next = readMetrics(el);\n setViewport((prev) => (sameMetrics(prev, next, trackHorizontalRef.current) ? prev : next));\n });\n }, [targetRef, trackHorizontalRef]);\n\n // Measure synchronously before first paint to avoid a blank initial frame,\n // and keep client size in sync with container resizes.\n // (Isomorphic: plain useEffect during SSR to avoid React 18's server warning.)\n useIsomorphicLayoutEffect(() => {\n const el = targetRef.current;\n if (!el) {\n return;\n }\n setViewport((prev) => {\n const next = readMetrics(el);\n return sameMetrics(prev, next, trackHorizontalRef.current) ? prev : next;\n });\n }, [targetRef]);\n\n useEffect(() => {\n const el = targetRef.current;\n if (!el || typeof ResizeObserver === \"undefined\") {\n return;\n }\n const observer = new ResizeObserver(scheduleMeasure);\n observer.observe(el);\n return () => {\n observer.disconnect();\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n };\n }, [scheduleMeasure, targetRef]);\n\n return { viewport, scheduleMeasure };\n}\n","import { useCallback, useRef } from \"react\";\nimport { useViewportMeasure } from \"./useViewportMeasure\";\n\nexport type { ViewportMetrics } from \"./useViewportMeasure\";\n\n/**\n * Keep the task-list and grid panes vertically locked together, and expose\n * the grid viewport's metrics for virtualization. Everything returned is\n * identity-stable forever.\n */\nexport function useScrollSync() {\n const taskListRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<HTMLDivElement>(null);\n const isSyncing = useRef(false);\n\n const { viewport, scheduleMeasure } = useViewportMeasure(gridRef);\n\n const onTaskListScroll = useCallback(() => {\n if (isSyncing.current) {\n return;\n }\n if (!taskListRef.current || !gridRef.current) {\n return;\n }\n isSyncing.current = true;\n gridRef.current.scrollTop = taskListRef.current.scrollTop;\n isSyncing.current = false;\n scheduleMeasure();\n }, [scheduleMeasure]);\n\n const onGridScroll = useCallback(() => {\n if (gridRef.current && taskListRef.current && !isSyncing.current) {\n isSyncing.current = true;\n taskListRef.current.scrollTop = gridRef.current.scrollTop;\n isSyncing.current = false;\n }\n scheduleMeasure();\n }, [scheduleMeasure]);\n\n return { taskListRef, gridRef, onTaskListScroll, onGridScroll, viewport };\n}\n","import { useCallback, useRef } from \"react\";\n\n/**\n * Wrap an optional callback in a stable identity that always calls the latest\n * version. Presence-preserving: `undefined` in → `undefined` out, so the\n * returned identity only changes when the callback's presence flips — never\n * when the consumer passes a new inline function. Use for callbacks handed to\n * consumers through context/memoized values so they don't churn on re-render.\n */\nexport function useEventCallback<A extends unknown[], R>(\n fn: ((...args: A) => R) | undefined,\n): ((...args: A) => R) | undefined {\n const ref = useRef(fn);\n ref.current = fn;\n const stable = useCallback((...args: A) => ref.current?.(...args) as R, []);\n if (!fn) {\n return undefined;\n }\n return stable;\n}\n","/**\n * Framework-agnostic scroll math. Given a span `[start, start + size]` and a\n * viewport of `viewSize` currently scrolled to `viewOffset`, return the scroll\n * offset that brings the span into view (keeping `margin` px of padding).\n *\n * Works for either axis (pass scrollLeft/clientWidth or scrollTop/clientHeight).\n * Pure — no DOM or framework dependency, so a Vue/Svelte/Solid/Angular adapter\n * can reuse it: read the container's metrics, call this, write the result back.\n *\n * Returns the clamped (>= 0) target offset, which equals `viewOffset` when the\n * span is already fully visible — callers can skip the write when unchanged.\n */\nexport function scrollOffsetToReveal(\n start: number,\n size: number,\n viewOffset: number,\n viewSize: number,\n margin = 0,\n): number {\n const viewEnd = viewOffset + viewSize;\n if (start - margin < viewOffset) {\n return Math.max(0, start - margin);\n }\n if (start + size + margin > viewEnd) {\n return start + size + margin - viewSize;\n }\n return viewOffset;\n}\n","import type { CalendarUnit, GanttTask, TaskState } from \"../types\";\nimport { dateAtOffset, unitOffset } from \"./dateUtils\";\n\nexport interface TaskPixels {\n left: number;\n width: number;\n progress: number;\n}\n\nexport function computeTaskPixels(\n task: GanttTask,\n override: Partial<TaskState> = {},\n origin: Date,\n colWidth: number,\n unit: CalendarUnit = \"day\",\n): TaskPixels {\n // Position by the task's true instants, never snapped to the column unit, so a\n // bar's size is proportional to its real duration. `endDate` is exclusive\n // (ADR-014), so it IS the right edge — no +1 day fudge. At a coarse unit (e.g.\n // quarter) a one-day task is a thin sliver, 1/90th of a column, not a whole one.\n //\n // The display list materializes `endDate` on every task (ADR-019), so the\n // fallback here only covers a task rendered straight from consumer data.\n const startDate = override.startDate ?? task.startDate;\n const endDate = override.endDate ?? task.endDate ?? startDate;\n const startOff = unitOffset(origin, startDate, unit);\n const endOff = unitOffset(origin, endDate, unit);\n const left = startOff * colWidth;\n const width = (endOff - startOff) * colWidth;\n\n return {\n left,\n width,\n progress: override.progress ?? task.progress ?? 0,\n };\n}\n\nexport function pxToDate(\n pxOffset: number,\n origin: Date,\n colWidth: number,\n unit: CalendarUnit = \"day\",\n): Date {\n return dateAtOffset(origin, unit, pxOffset / colWidth);\n}\n\nexport interface DatePatch {\n startDate?: Date;\n endDate?: Date;\n progress?: number;\n}\n\n/**\n * What a finished drag *meant*, rather than the two dates it happened to land on.\n *\n * The preview stays rigid and pixel-derived (ADR-008), so pixel width during a\n * drag is preview state, not intent — a move that crosses a weekend must preserve\n * the task's working time, which the pixels cannot express. Emitting an intent and\n * resolving it once on drop is what keeps every calendar read out of the mousemove\n * path by construction.\n */\nexport type BarCommit =\n /** Whole bar dropped with its left edge here; the end is re-derived. */\n | { kind: \"move\"; startDate: Date }\n /** Start edge dragged here; the end is pinned. */\n | { kind: \"resizeStart\"; startDate: Date }\n /** End edge dragged here; the start is pinned. */\n | { kind: \"resizeEnd\"; endDate: Date };\n","import type { CalendarUnit, Scale } from \"../types\";\n\n/**\n * Single source of truth for the default calendar scales. The Calendar renders\n * these rows and the TaskListHeader derives its height from their count\n * (`scales.length * rowHeight + 2`), so both MUST read the same array — keep\n * this the only default to prevent the header and calendar drifting apart.\n */\nexport const DEFAULT_SCALES: Scale[] = [\n {\n unit: \"month\",\n step: 1,\n format: (d: Date) => d.toLocaleString(undefined, { month: \"long\", year: \"numeric\" }),\n },\n {\n unit: \"day\",\n step: 1,\n format: (d: Date) => String(d.getDate()),\n },\n];\n\n/**\n * The unit of the bottom-most (finest) scale row — the one that maps 1:1 to a\n * column, and therefore defines the time span of a single `colWidth`. Bar\n * geometry uses this to convert dates <-> pixels. Falls back to the defaults\n * when `scales` is omitted, and to `\"day\"` for an empty array.\n */\nexport function resolveColumnUnit(scales?: Scale[]): CalendarUnit {\n return (scales ?? DEFAULT_SCALES).at(-1)?.unit ?? \"day\";\n}\n\n/**\n * The `step` of the bottom-most (finest) scale row — how many units each column\n * spans. Pairs with {@link resolveColumnUnit}; defaults to 1.\n */\nexport function resolveColumnStep(scales?: Scale[]): number {\n return (scales ?? DEFAULT_SCALES).at(-1)?.step ?? 1;\n}\n","import type { CalendarUnit, Scale } from \"../types\";\nimport { resolveColumnStep, resolveColumnUnit } from \"./scales\";\nimport { addUnit, buildDates, getMinMaxDates, startOfUnit, unitOffset } from \"./dateUtils\";\n\n/**\n * Task-range → timeline geometry. The only layer that knows both about tasks and\n * about scales; `dateUtils` below it is pure unit/instant math with no notion of\n * either.\n */\n\n/** The minimum a timeline needs to know about a task to place it. */\nexport interface TaskDates {\n startDate: Date;\n endDate?: Date;\n}\n\n/**\n * The timeline origin: the start-of-unit boundary containing the earliest task,\n * padded outward by `pad` whole columns.\n *\n * Every consumer must derive the origin from here. There were five separate\n * copies of the `getMinMaxDates` → `resolveColumnUnit` → `resolveColumnStep` →\n * `resolveOrigin` recipe (two of them byte-identical, in `useZoom`), and they did\n * not all agree — see {@link resolveOriginAt}.\n *\n * Returns `null` when there are no tasks, i.e. no timeline to place anything on.\n */\nexport function timelineOrigin(\n tasks: readonly TaskDates[],\n scales: Scale[] | undefined,\n pad: number,\n): Date | null {\n const range = getMinMaxDates(tasks);\n if (!range) {\n return null;\n }\n return resolveOriginAt(range.min, resolveColumnUnit(scales), pad, resolveColumnStep(scales));\n}\n\n/**\n * The padded start-of-unit boundary at or before `min`.\n *\n * The trailing `startOfUnit` is load-bearing, and is the fix for a real bug: for\n * `day` and `week`, `addUnit` routes through `addDays`, which zeroes to local\n * midnight and then adds a *fixed* number of milliseconds. Across a DST boundary\n * that lands on 23:00 or 01:00 rather than midnight — so the padded origin was not\n * on a unit boundary at all.\n *\n * The grid never saw it, because it read `dates[0]` from `buildDates`, whose first\n * element is `addUnit(start, unit, 0)` — which re-zeroes the time. The task list\n * and `useZoom` used the un-re-zeroed value directly, so the two disagreed by up\n * to 23 hours: ~38px, nearly a whole column at the default `colWidth`, in any DST\n * timezone. In UTC the drift is zero, which is why it went unnoticed.\n *\n * Normalising here makes the boundary claim true for every caller, and matches\n * what the grid was already using.\n */\nexport function resolveOriginAt(min: Date, unit: CalendarUnit, pad: number, step: number): Date {\n return startOfUnit(addUnit(startOfUnit(min, unit), unit, -pad * step), unit);\n}\n\n/**\n * The full column axis: one date per column, from the padded origin through the\n * padded end of the last task.\n */\nexport function buildTimelineDates(tasks: readonly TaskDates[], pad = 0, scales?: Scale[]): Date[] {\n const range = getMinMaxDates(tasks);\n if (!range) {\n return [];\n }\n const unit = resolveColumnUnit(scales);\n const step = resolveColumnStep(scales);\n const start = resolveOriginAt(range.min, unit, pad, step);\n const end = addUnit(startOfUnit(range.max, unit), unit, pad * step);\n const count = Math.round(unitOffset(start, end, unit) / step) + 1;\n return buildDates(start, count, unit, step);\n}\n","import { useCallback, useLayoutEffect, useRef } from \"react\";\nimport type { GanttTask, Id, Scale } from \"../types\";\nimport { scrollOffsetToReveal } from \"../core/scroll\";\nimport { computeTaskPixels } from \"../core/barUtils\";\nimport { timelineOrigin } from \"../core/timeline\";\nimport { resolveColumnUnit } from \"../core/scales\";\nimport { useLatestRef } from \"./useLatestRef\";\n\n/** Which axes to reveal on. Defaults match the historical `scrollToTask(id)`. */\nexport interface RevealOptions {\n /** Reveal the task's row vertically, in whichever pane is mounted. Default `true`. */\n vertical?: boolean;\n /** Reveal the task's bar horizontally in the grid. Default `false`. */\n horizontal?: boolean;\n}\n\ninterface UseRevealTaskOptions {\n taskListRef: React.RefObject<HTMLDivElement | null>;\n gridRef: React.RefObject<HTMLDivElement | null>;\n /** The whole list, so an id hidden under a collapsed parent is still known. */\n tasksList: GanttTask[];\n visibleTasks: GanttTask[];\n rowHeight: number;\n colWidth: number;\n scales?: Scale[];\n padDays: number;\n /** Expands every collapsed ancestor of an id; from `useExpand`. */\n revealAncestors: (id: Id) => void;\n}\n\n/**\n * The single way to bring a task into view.\n *\n * Replaces two same-named functions pulling in opposite directions: a\n * `scrollToTask(id)` on the context that revealed *vertically*, and a\n * component-local `scrollToTask(task)` inside `TaskList` that revealed\n * *horizontally* — which shadowed the importable one and duplicated the origin\n * derivation to do it.\n *\n * A bare `revealTask(id)` is byte-for-byte the old vertical behaviour, so the\n * defaults keep every existing caller intact.\n *\n * Identity-stable forever: it dispatches through a ref whose implementation is\n * reassigned each render, so it closes over current geometry without ever\n * changing identity — which matters because it is a dependency of `columnApi` and\n * the task-actions context, which every memoized row consumes.\n */\nexport function useRevealTask({\n taskListRef,\n gridRef,\n tasksList,\n visibleTasks,\n rowHeight,\n colWidth,\n scales,\n padDays,\n revealAncestors,\n}: UseRevealTaskOptions): (id: Id, options?: RevealOptions) => void {\n const tasksListRef = useLatestRef(tasksList);\n const visibleTasksRef = useLatestRef(visibleTasks);\n const implRef = useRef<(id: Id, options?: RevealOptions) => void>(() => {});\n /** A reveal waiting for an expansion to commit before it can find its row. */\n const pending = useRef<{ id: Id; options?: RevealOptions } | null>(null);\n\n const revealVertically = (index: number): void => {\n const el = taskListRef.current ?? gridRef.current;\n if (!el) {\n return;\n }\n const next = scrollOffsetToReveal(\n index * rowHeight,\n rowHeight,\n el.scrollTop,\n el.clientHeight,\n rowHeight,\n );\n if (next !== el.scrollTop) {\n el.scrollTop = next;\n }\n };\n\n const revealHorizontally = (task: GanttTask): void => {\n const grid = gridRef.current;\n const origin = timelineOrigin(visibleTasksRef.current, scales, padDays);\n if (!grid || !origin) {\n return;\n }\n const { left, width } = computeTaskPixels(\n task,\n {},\n origin,\n colWidth,\n resolveColumnUnit(scales),\n );\n const nextLeft = scrollOffsetToReveal(\n left,\n width,\n grid.scrollLeft,\n grid.clientWidth,\n colWidth, // keep one column of padding\n );\n if (nextLeft !== grid.scrollLeft) {\n grid.scrollLeft = nextLeft;\n }\n };\n\n implRef.current = (id, options) => {\n const { vertical = true, horizontal = false } = options ?? {};\n const index = visibleTasksRef.current.findIndex((t) => t.id === id);\n\n if (index < 0) {\n // Not in the window. Either the id is unknown — a documented no-op — or it\n // is hidden under a collapsed ancestor, which is what `revealAncestors`\n // exists for. Expansion is a state update, so the row cannot be measured\n // until it commits: park the request and finish in the layout effect below.\n // (Not `flushSync`: this is public via `apiRef` and a consumer may call it\n // from inside an effect, where flushing synchronously is a warning.)\n if (!tasksListRef.current.some((t) => t.id === id)) {\n return;\n }\n pending.current = { id, options };\n revealAncestors(id);\n return;\n }\n\n if (vertical) {\n revealVertically(index);\n }\n if (horizontal) {\n revealHorizontally(visibleTasksRef.current[index]!);\n }\n };\n\n useLayoutEffect(() => {\n const anchor = pending.current;\n if (!anchor) {\n return;\n }\n // Cleared unconditionally: a request left parked would fire a surprise scroll\n // on the next unrelated expand.\n pending.current = null;\n implRef.current(anchor.id, anchor.options);\n }, [visibleTasks]);\n\n return useCallback((id: Id, options?: RevealOptions) => implRef.current(id, options), []);\n}\n","import { useCallback, useLayoutEffect, useRef, useState } from \"react\";\nimport { dateAtOffset, unitOffset } from \"../core/dateUtils\";\nimport { timelineOrigin } from \"../core/timeline\";\nimport { resolveColumnUnit } from \"../core/scales\";\nimport type { ZoomLevel } from \"../core/zoom\";\nimport type { GanttTask } from \"../types\";\nimport { useLatestRef } from \"./useLatestRef\";\n\ninterface UseZoomParams {\n gridRef: React.RefObject<HTMLDivElement | null>;\n visibleTasks: GanttTask[];\n padDays: number;\n levels: ZoomLevel[];\n initialIndex: number;\n}\n\nexport interface ZoomState {\n index: number;\n level: ZoomLevel;\n count: number;\n canZoomIn: boolean;\n canZoomOut: boolean;\n /** Step one rung finer, keeping the viewport-center date fixed. */\n zoomIn: () => void;\n /** Step one rung coarser, keeping the viewport-center date fixed. */\n zoomOut: () => void;\n /** Jump to a rung (clamped), keeping the viewport-center date fixed. */\n setZoom: (index: number) => void;\n /**\n * Step by `delta` rungs while keeping the date currently under `focusPx`\n * (content-space px = scrollLeft + offset-in-viewport) under that same pixel.\n * Used by wheel-zoom to anchor on the cursor.\n */\n zoomAt: (focusPx: number, delta: number) => void;\n}\n\n/** What to restore after the grid re-renders at the new level. */\ninterface PendingAnchor {\n date: Date;\n /** Pixels from the viewport's left edge that the focus date should keep. */\n viewportOffset: number;\n}\n\n/**\n * Library-managed zoom: holds the active level index and, on every level change,\n * keeps a focus date pinned to its screen position. The focus date + its\n * viewport offset are captured (at the *previous* level) when a zoom is\n * requested, then — after the grid has re-rendered at the new level — the layout\n * effect converts the date back to pixels and reassigns `scrollLeft`.\n */\nexport function useZoom({\n gridRef,\n visibleTasks,\n padDays,\n levels,\n initialIndex,\n}: UseZoomParams): ZoomState {\n const clamp = useCallback(\n (i: number) => Math.max(0, Math.min(levels.length - 1, i)),\n [levels.length],\n );\n const [index, setIndex] = useState(() => clamp(initialIndex));\n\n const indexRef = useLatestRef(index);\n const visibleTasksRef = useLatestRef(visibleTasks);\n const padDaysRef = useLatestRef(padDays);\n const levelsRef = useLatestRef(levels);\n const pending = useRef<PendingAnchor | null>(null);\n\n const zoomAt = useCallback(\n (focusPx: number, delta: number) => {\n const cur = indexRef.current;\n const next = clamp(cur + delta);\n if (next === cur) {\n return;\n }\n const grid = gridRef.current;\n const level = levelsRef.current[cur]!;\n const origin = timelineOrigin(visibleTasksRef.current, level.scales, padDaysRef.current);\n if (grid && origin) {\n const unit = resolveColumnUnit(level.scales);\n pending.current = {\n date: dateAtOffset(origin, unit, focusPx / level.colWidth),\n viewportOffset: focusPx - grid.scrollLeft,\n };\n } else {\n pending.current = null;\n }\n setIndex(next);\n },\n [clamp, gridRef, indexRef, visibleTasksRef, padDaysRef, levelsRef],\n );\n\n const centerFocusPx = useCallback(() => {\n const grid = gridRef.current;\n return grid ? grid.scrollLeft + grid.clientWidth / 2 : 0;\n }, [gridRef]);\n\n const zoomIn = useCallback(() => zoomAt(centerFocusPx(), 1), [zoomAt, centerFocusPx]);\n const zoomOut = useCallback(() => zoomAt(centerFocusPx(), -1), [zoomAt, centerFocusPx]);\n const setZoom = useCallback(\n (i: number) => zoomAt(centerFocusPx(), clamp(i) - indexRef.current),\n [zoomAt, centerFocusPx, clamp, indexRef],\n );\n\n // Re-anchor after the grid has committed the new level. Depends on `index`\n // only: re-running on task edits would fight the user's scroll position.\n useLayoutEffect(() => {\n const anchor = pending.current;\n if (anchor === null) {\n return;\n }\n pending.current = null;\n const grid = gridRef.current;\n const level = levelsRef.current[index]!;\n const origin = timelineOrigin(visibleTasksRef.current, level.scales, padDaysRef.current);\n if (!grid || !origin) {\n return;\n }\n const unit = resolveColumnUnit(level.scales);\n const targetContentPx = unitOffset(origin, anchor.date, unit) * level.colWidth;\n grid.scrollLeft = Math.max(0, targetContentPx - anchor.viewportOffset);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [index]);\n\n return {\n index,\n level: levels[index]!,\n count: levels.length,\n canZoomIn: index < levels.length - 1,\n canZoomOut: index > 0,\n zoomIn,\n zoomOut,\n setZoom,\n zoomAt,\n };\n}\n","import type { Scale } from \"../types\";\n\n/**\n * One rung of the zoom ladder: the calendar `scales` to render and the pixel\n * width of a single (finest-unit) column. Zooming steps between levels.\n */\nexport interface ZoomLevel {\n scales: Scale[];\n colWidth: number;\n}\n\nconst pad2 = (n: number) => String(n).padStart(2, \"0\");\nconst yearLabel = (d: Date) => String(d.getFullYear());\nconst quarterLabel = (d: Date) => `Q${Math.floor(d.getMonth() / 3) + 1}`;\nconst monthLong = (d: Date) => d.toLocaleString(undefined, { month: \"long\", year: \"numeric\" });\nconst monthShort = (d: Date) => d.toLocaleString(undefined, { month: \"short\" });\nconst dayOfMonth = (d: Date) => String(d.getDate());\nconst weekdayDay = (d: Date) => d.toLocaleString(undefined, { weekday: \"short\", day: \"numeric\" });\nconst hourLabel = (d: Date) => `${pad2(d.getHours())}:00`;\n\n/**\n * Default zoom ladder, ordered coarse → fine. Zooming in moves toward finer\n * (higher-index) levels; each rung pairs a coarse header row with a finer\n * bottom row whose unit is the column unit.\n */\nexport const DEFAULT_ZOOM_LEVELS: ZoomLevel[] = [\n {\n colWidth: 56,\n scales: [\n { unit: \"year\", step: 1, format: yearLabel },\n { unit: \"quarter\", step: 1, format: quarterLabel },\n ],\n },\n {\n colWidth: 44,\n scales: [\n { unit: \"year\", step: 1, format: yearLabel },\n { unit: \"month\", step: 1, format: monthShort },\n ],\n },\n {\n colWidth: 60,\n scales: [\n { unit: \"month\", step: 1, format: monthLong },\n { unit: \"week\", step: 1, format: weekdayDay },\n ],\n },\n {\n colWidth: 40,\n scales: [\n { unit: \"month\", step: 1, format: monthLong },\n { unit: \"day\", step: 1, format: dayOfMonth },\n ],\n },\n {\n colWidth: 44,\n scales: [\n { unit: \"day\", step: 1, format: weekdayDay },\n { unit: \"hour\", step: 1, format: hourLabel },\n ],\n },\n];\n\n/** Index of the default (month / day) rung in {@link DEFAULT_ZOOM_LEVELS}. */\nexport const DEFAULT_ZOOM_INDEX = 3;\n\n/**\n * Resolve the ladder to use. A consumer's `zoomLevels` win verbatim; otherwise\n * start from the default ladder but let the standalone `scales`/`colWidth` props\n * override the default (month/day) rung, so existing consumers keep their look\n * and simply gain zoom.\n */\nexport function resolveZoomLevels(\n zoomLevels: ZoomLevel[] | undefined,\n scales: Scale[] | undefined,\n colWidth: number | undefined,\n): ZoomLevel[] {\n if (zoomLevels && zoomLevels.length > 0) {\n return zoomLevels;\n }\n if (!scales && colWidth === undefined) {\n return DEFAULT_ZOOM_LEVELS;\n }\n return DEFAULT_ZOOM_LEVELS.map((level, i) =>\n i === DEFAULT_ZOOM_INDEX\n ? { scales: scales ?? level.scales, colWidth: colWidth ?? level.colWidth }\n : level,\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { Id, TaskDependency } from \"../types\";\nimport { useLatestRef } from \"./useLatestRef\";\n\nexport type ConnectorHandle = \"start\" | \"end\";\n\nexport interface DependencyDragState {\n fromTaskId: Id;\n handle: ConnectorHandle;\n startX: number;\n startY: number;\n currentX: number;\n currentY: number;\n}\n\nconst HANDLE_TO_TYPE: Record<ConnectorHandle, Record<ConnectorHandle, TaskDependency[\"type\"]>> = {\n end: { start: \"FS\", end: \"FF\" },\n start: { start: \"SS\", end: \"SF\" },\n};\n\ninterface UseDependencyDragOptions {\n /** Grid body element; preview coordinates are relative to its rect. */\n gridBodyRef: React.RefObject<HTMLDivElement | null>;\n onDependencyCreate?: (dep: TaskDependency) => void;\n}\n\n/**\n * Imperative engine for drawing a dependency between two bars: window-level\n * mousemove/mouseup listeners installed at drag start, rAF-coalesced position\n * updates, idempotent teardown (mouseup / endDrag / unmount). `startDrag` and\n * `endDrag` are identity-stable forever.\n */\nexport function useDependencyDrag({ gridBodyRef, onDependencyCreate }: UseDependencyDragOptions): {\n drag: DependencyDragState | null;\n startDrag: (state: DependencyDragState) => void;\n endDrag: (toTaskId: Id | null, toHandle?: ConnectorHandle) => void;\n} {\n const onDependencyCreateRef = useLatestRef(onDependencyCreate);\n\n const [drag, setDrag] = useState<DependencyDragState | null>(null);\n // Mirror for handlers (endDrag) so they can read the current drag without\n // subscribing to it; drag is committed at mousedown, well before any mouseup.\n const dragRef = useLatestRef(drag);\n const dragListenersRef = useRef<{\n move: (e: MouseEvent) => void;\n up: (e: MouseEvent) => void;\n } | null>(null);\n const dragFrameRef = useRef<number | null>(null);\n const lastMouseRef = useRef<{ x: number; y: number } | null>(null);\n\n // Idempotent: safe to call from mouseup, endDrag, and unmount in any order.\n const clearDragListeners = useCallback(() => {\n if (dragListenersRef.current) {\n window.removeEventListener(\"mousemove\", dragListenersRef.current.move);\n window.removeEventListener(\"mouseup\", dragListenersRef.current.up);\n dragListenersRef.current = null;\n }\n if (dragFrameRef.current !== null) {\n cancelAnimationFrame(dragFrameRef.current);\n dragFrameRef.current = null;\n }\n }, []);\n\n // The window listeners would leak if the owner unmounted mid-drag.\n useEffect(() => clearDragListeners, [clearDragListeners]);\n\n const startDrag = useCallback(\n (state: DependencyDragState) => {\n setDrag(state);\n\n // Coalesce mousemove bursts into one state update per frame. The rect is\n // re-read inside the frame: the body's viewport-relative position shifts\n // while the grid scrolls under the cursor.\n const onMouseMove = (e: MouseEvent) => {\n lastMouseRef.current = { x: e.clientX, y: e.clientY };\n if (dragFrameRef.current !== null) {\n return;\n }\n dragFrameRef.current = requestAnimationFrame(() => {\n dragFrameRef.current = null;\n const body = gridBodyRef.current;\n const last = lastMouseRef.current;\n if (!body || !last) {\n return;\n }\n const rect = body.getBoundingClientRect();\n setDrag((prev) =>\n prev ? { ...prev, currentX: last.x - rect.left, currentY: last.y - rect.top } : null,\n );\n });\n };\n\n const onMouseUp = () => {\n setDrag(null);\n clearDragListeners();\n };\n\n dragListenersRef.current = { move: onMouseMove, up: onMouseUp };\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mouseup\", onMouseUp);\n },\n [clearDragListeners, gridBodyRef],\n );\n\n const endDrag = useCallback(\n (toTaskId: Id | null, toHandle?: ConnectorHandle) => {\n const current = dragRef.current;\n if (current && toTaskId !== null && toHandle && toTaskId !== current.fromTaskId) {\n const type = HANDLE_TO_TYPE[current.handle][toHandle];\n onDependencyCreateRef.current?.({ from: current.fromTaskId, to: toTaskId, type });\n }\n setDrag(null);\n clearDragListeners();\n },\n [clearDragListeners, dragRef, onDependencyCreateRef],\n );\n\n return { drag, startDrag, endDrag };\n}\n","import { useMemo } from \"react\";\nimport type { GanttHandle } from \"../types\";\n\n/**\n * Assembles the imperative handle once, so `apiRef` and `columnApi` cannot drift\n * apart.\n *\n * They shared nine members built in two separate `useMemo`s with two 9-entry\n * dependency arrays — and `ColumnApi extends GanttHandle` already said that set\n * *is* the handle. Building it here makes that structural, and collapses the two\n * arrays into one.\n *\n * Invalidation is unchanged: the returned object's identity changes exactly when\n * one of the nine changes, which is exactly when both old arrays fired.\n */\nexport function useGanttHandle(members: GanttHandle): GanttHandle {\n const { createTask, updateTask, deleteTask, undo, redo, revealTask, zoomIn, zoomOut, setZoom } =\n members;\n // Destructured above so the deps are the individual callbacks, not the argument\n // object — which is a fresh literal on every render of the provider.\n return useMemo(\n () => ({\n createTask,\n updateTask,\n deleteTask,\n undo,\n redo,\n revealTask,\n zoomIn,\n zoomOut,\n setZoom,\n }),\n [createTask, updateTask, deleteTask, undo, redo, revealTask, zoomIn, zoomOut, setZoom],\n );\n}\n","import { useMemo } from \"react\";\nimport type { ColumnApi, GanttHandle, GanttTask, ResolvedGanttLabels } from \"../types\";\nimport { displayEndOf, workingDurationOf, type SchedulingContext } from \"../core/taskDates\";\n\ninterface UseColumnApiOptions {\n handle: GanttHandle;\n readOnly: boolean;\n labels: ResolvedGanttLabels;\n schedulingContext: SchedulingContext;\n /** Latest-ref, so an inline `onTaskEdit` does not churn this value. */\n onTaskEditRef: React.RefObject<((task: GanttTask) => void) | undefined>;\n}\n\n/**\n * The API handed to `ColumnDef.render`: the imperative handle plus the few things\n * a column cannot reach on its own.\n *\n * `render` is a plain function, not a component, so it cannot call `useGanttLabels`\n * or read the calendar from context. `labels` and `format` are its channel to\n * both.\n *\n * This value is a dependency of the task-actions context, which every memoized\n * `TaskListRow` consumes — so it must only change when one of its inputs really\n * does. That is why the options object is destructured before the memo.\n */\nexport function useColumnApi({\n handle,\n readOnly,\n labels,\n schedulingContext,\n onTaskEditRef,\n}: UseColumnApiOptions): ColumnApi {\n return useMemo(\n () => ({\n ...handle,\n editTask: (task: GanttTask) => onTaskEditRef.current?.(task),\n readOnly,\n labels,\n format: {\n endDate: (task: GanttTask) => displayEndOf(task, schedulingContext),\n duration: (task: GanttTask) => workingDurationOf(task, schedulingContext),\n },\n }),\n // onTaskEditRef is identity-stable (useLatestRef); listed only to satisfy\n // exhaustive-deps.\n [handle, onTaskEditRef, readOnly, labels, schedulingContext],\n );\n}\n","import { createContext, useContext } from \"react\";\nimport type {\n ColumnApi,\n GanttTask,\n Id,\n ResolvedGanttLabels,\n Scale,\n TaskDependency,\n} from \"../types\";\nimport { LINEAR_CONTEXT, type SchedulingContext } from \"../core/taskDates\";\nimport { DEFAULT_LABELS } from \"../core/labels\";\nimport type { ViewportMetrics } from \"../hooks/useScrollSync\";\nimport type { ConnectorHandle, DependencyDragState } from \"../hooks/useDependencyDrag\";\nimport type { BarCommit, DatePatch } from \"../core/barUtils\";\nimport type { RevealOptions } from \"../hooks/useRevealTask\";\n\nexport type { ConnectorHandle, DependencyDragState } from \"../hooks/useDependencyDrag\";\n\n/**\n * Every Gantt context object and its consumer hook.\n *\n * Kept in one file on purpose: the value of the split is being able to see all\n * twelve boundaries and the cadence table below at a glance. Splitting further,\n * one file per context, would hide exactly the thing this design needs reviewed\n * together.\n *\n * The provider that supplies these lives in `GanttProvider.tsx`; nothing here\n * imports it, so a component may depend on a context without pulling in the\n * whole composition root.\n */\n\n// Contexts are split by update frequency so high-frequency state (drag\n// position, viewport, selection) never invalidates consumers that only need\n// stable references. Rough cadence, hottest first:\n// drag position → every drag-move frame (DependencyPreview only)\n// viewport → every scroll frame (Grid only)\n// selection → per click (TaskList only)\n// task state → per edit/expand (Grid, TaskList)\n// everything else is identity-stable across those updates.\n\n// --- Config ---------------------------------------------------------------\n\nexport interface GanttConfigValue {\n rowHeight: number;\n colWidth: number;\n scales?: Scale[];\n padDays: number;\n /** Total component height in px; undefined = grow with content. */\n height?: number;\n}\n\nexport const GanttConfigContext = createContext<GanttConfigValue | null>(null);\n\nexport function useGanttConfig(): GanttConfigValue {\n const ctx = useContext(GanttConfigContext);\n if (!ctx) {\n throw new Error(\"useGanttConfig must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Labels ---------------------------------------------------------------\n\n// Kept out of the config context on purpose: config churns on every zoom step,\n// while labels only change when the consumer's `labels` prop does. Bars and rows\n// are memoized and read this directly, so it has to stay identity-stable.\n//\n// Unlike the other contexts this one does NOT throw without a provider: labels are\n// presentational defaults, not required wiring, so sub-components stay renderable\n// on their own (which is how the slot tests exercise them).\nexport const GanttLabelsContext = createContext<ResolvedGanttLabels>(DEFAULT_LABELS);\n\nexport function useGanttLabels(): ResolvedGanttLabels {\n return useContext(GanttLabelsContext);\n}\n\n// --- Working-time calendar ------------------------------------------------\n\n// Kept out of the config context on purpose: config churns on every zoom step,\n// while the calendar changes only when the consumer's prop does — and it is a\n// dependency of the task-list memo, so it must stay identity-stable.\n//\n// Like the labels context this does NOT throw without a provider: `GridColumns`\n// and `CalendarRow` are rendered bare by the slot tests, and a chart with no\n// calendar is the normal case anyway.\nexport const GanttCalendarContext = createContext<SchedulingContext>(LINEAR_CONTEXT);\n\nexport function useGanttWorkCalendar(): SchedulingContext {\n return useContext(GanttCalendarContext);\n}\n\n// --- Read-only ------------------------------------------------------------\n\n// Primitive context, its own provider because it is read by memoized leaves\n// (bars, connector handles, links) and must not ride along with anything that\n// churns. Like labels it does NOT throw without a provider: `false` — fully\n// interactive — is the historical default, which is what keeps sub-components\n// renderable bare in the slot tests.\nexport const GanttReadOnlyContext = createContext<boolean>(false);\n\nexport function useGanttReadOnly(): boolean {\n return useContext(GanttReadOnlyContext);\n}\n\n// --- Task state -----------------------------------------------------------\n\nexport interface GanttTaskStateValue {\n tasksList: GanttTask[];\n visibleTasks: GanttTask[];\n expandedIds: Set<Id>;\n parentIds: Set<Id>;\n canUndo: boolean;\n canRedo: boolean;\n}\n\nexport const GanttTaskStateContext = createContext<GanttTaskStateValue | null>(null);\n\nexport function useGanttTaskState(): GanttTaskStateValue {\n const ctx = useContext(GanttTaskStateContext);\n if (!ctx) {\n throw new Error(\"useGanttTaskState must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Task actions ---------------------------------------------------------\n\n// Everything here is identity-stable except `updateTask`/`columnApi`, which\n// only change when the `dependencies` prop changes — so per-row consumers\n// (TaskListRow) can rely on memoization.\nexport interface GanttTaskActionsValue {\n updateTask: (id: Id, patch: DatePatch) => void;\n /** Commit a finished drag as an intent; the only path that snaps to working time. */\n commitTask: (id: Id, commit: BarCommit) => void;\n createTask: (task: GanttTask, afterId?: Id | null) => void;\n deleteTask: (id: Id) => void;\n undo: () => void;\n redo: () => void;\n /** API handed to `ColumnDef.render` so columns can mutate/edit tasks. */\n columnApi: ColumnApi;\n setSelectedId: (id: Id | null) => void;\n toggleExpand: (id: Id) => void;\n onTaskClick?: (task: GanttTask) => void;\n /** Bring a task into view. See `GanttHandle.revealTask`. */\n revealTask: (id: Id, options?: RevealOptions) => void;\n}\n\nexport const GanttTaskActionsContext = createContext<GanttTaskActionsValue | null>(null);\n\nexport function useGanttTaskActions(): GanttTaskActionsValue {\n const ctx = useContext(GanttTaskActionsContext);\n if (!ctx) {\n throw new Error(\"useGanttTaskActions must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Selection ------------------------------------------------------------\n\n// Primitive context (no null-throw pattern: `null` is a valid value, meaning\n// \"nothing selected\"). The setter lives in the actions context.\nexport const GanttSelectionContext = createContext<Id | null>(null);\n\nexport function useGanttSelectedId(): Id | null {\n return useContext(GanttSelectionContext);\n}\n\n// --- Scroll ---------------------------------------------------------------\n\n// Refs and handlers only — all identity-stable, so this context never\n// re-renders its consumers. Viewport metrics live in their own context below.\nexport interface GanttScrollValue {\n taskListRef: React.RefObject<HTMLDivElement | null>;\n gridRef: React.RefObject<HTMLDivElement | null>;\n gridBodyRef: React.RefObject<HTMLDivElement | null>;\n onTaskListScroll: () => void;\n onGridScroll: () => void;\n}\n\nexport const GanttScrollContext = createContext<GanttScrollValue | null>(null);\n\nexport function useGanttScroll(): GanttScrollValue {\n const ctx = useContext(GanttScrollContext);\n if (!ctx) {\n throw new Error(\"useGanttScroll must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Viewport -------------------------------------------------------------\n\n/** Scroll offset + client size of the grid viewport, for virtualization. */\nexport const GanttViewportContext = createContext<ViewportMetrics | null>(null);\n\nexport function useGanttViewport(): ViewportMetrics {\n const ctx = useContext(GanttViewportContext);\n if (!ctx) {\n throw new Error(\"useGanttViewport must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Dependency -----------------------------------------------------------\n\nexport interface GanttDependencyValue {\n dependencies: TaskDependency[];\n onDependencyDelete?: (dep: TaskDependency) => void;\n startDrag: (state: DependencyDragState) => void;\n endDrag: (toTaskId: Id | null, toHandle?: ConnectorHandle) => void;\n}\n\nexport const GanttDependencyContext = createContext<GanttDependencyValue | null>(null);\n\nexport function useGanttDependency(): GanttDependencyValue {\n const ctx = useContext(GanttDependencyContext);\n if (!ctx) {\n throw new Error(\"useGanttDependency must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n\n// --- Dependency drag ------------------------------------------------------\n\n// Split in two: per-row ConnectorHandles only need \"is a drag in progress\"\n// (changes at drag start/end), while DependencyPreview needs the coordinates\n// (changes every drag-move frame). Primitive contexts, plain defaults.\nexport const GanttDragActiveContext = createContext<boolean>(false);\n\nexport function useGanttDragActive(): boolean {\n return useContext(GanttDragActiveContext);\n}\n\nexport const GanttDragContext = createContext<DependencyDragState | null>(null);\n\nexport function useGanttDependencyDrag(): DependencyDragState | null {\n return useContext(GanttDragContext);\n}\n\n// --- Zoom -----------------------------------------------------------------\n\n// Zoom controls exposed to the grid (for wheel/keyboard wiring). Identity-stable\n// callbacks; the enabled flags are plain booleans.\nexport interface GanttZoomValue {\n zoomIn: () => void;\n zoomOut: () => void;\n zoomAt: (focusPx: number, delta: number) => void;\n wheelEnabled: boolean;\n keyboardEnabled: boolean;\n}\n\nexport const GanttZoomContext = createContext<GanttZoomValue | null>(null);\n\nexport function useGanttZoom(): GanttZoomValue {\n const ctx = useContext(GanttZoomContext);\n if (!ctx) {\n throw new Error(\"useGanttZoom must be used within a <GanttProvider>\");\n }\n return ctx;\n}\n","import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from \"react\";\nimport type { GanttProviderProps } from \"../types\";\nimport type { GanttTask, Id } from \"../types\";\nimport { useResolvedCalendar } from \"../hooks/useResolvedCalendar\";\nimport { type SchedulingContext } from \"../core/taskDates\";\nimport { resolveLabels } from \"../core/labels\";\nimport { useTaskList, EMPTY_DEPENDENCIES } from \"../hooks/useTaskList\";\nimport { useExpand } from \"../hooks/useExpand\";\nimport { useScrollSync } from \"../hooks/useScrollSync\";\nimport { useEventCallback } from \"../hooks/useEventCallback\";\nimport { useLatestRef } from \"../hooks/useLatestRef\";\nimport { useRevealTask } from \"../hooks/useRevealTask\";\nimport { useZoom } from \"../hooks/useZoom\";\nimport { DEFAULT_ZOOM_INDEX, resolveZoomLevels } from \"../core/zoom\";\nimport { useDependencyDrag } from \"../hooks/useDependencyDrag\";\nimport { DEFAULT_PAD_DAYS, DEFAULT_ROW_HEIGHT } from \"../core/constants\";\nimport { useGanttHandle } from \"./useGanttHandle\";\nimport { useColumnApi } from \"./useColumnApi\";\nimport {\n GanttCalendarContext,\n GanttConfigContext,\n GanttDependencyContext,\n GanttDragActiveContext,\n GanttDragContext,\n GanttLabelsContext,\n GanttReadOnlyContext,\n GanttScrollContext,\n GanttSelectionContext,\n GanttTaskActionsContext,\n GanttTaskStateContext,\n GanttViewportContext,\n GanttZoomContext,\n type GanttConfigValue,\n type GanttDependencyValue,\n type GanttScrollValue,\n type GanttTaskActionsValue,\n type GanttTaskStateValue,\n type GanttZoomValue,\n} from \"./contexts\";\n\n/**\n * The composition root: owns every piece of chart state and publishes it through\n * the twelve contexts defined in `contexts.ts`.\n *\n * The provider nesting at the bottom is ordered stable-outermost, hottest-inside,\n * mirroring the cadence table in `contexts.ts`. That order is not load-bearing\n * today — no layer derives its value from another, and React resolves `useContext`\n * to the nearest provider at any depth — but it documents the architecture, and it\n * *becomes* load-bearing the moment a layer starts reading another context. Keep\n * it.\n */\nexport function GanttProvider({\n tasks,\n rowHeight = DEFAULT_ROW_HEIGHT,\n colWidth,\n height,\n scales,\n padDays = DEFAULT_PAD_DAYS,\n zoomLevels,\n defaultZoomIndex,\n onZoomChange,\n zoomWheel = false,\n zoomKeyboard = false,\n dependencies = EMPTY_DEPENDENCIES,\n onTaskClick,\n onDependencyCreate,\n onDependencyDelete,\n onTaskCreate: onTaskCreateProp,\n onTaskDelete,\n onTaskEdit,\n onTasksChange,\n apiRef,\n labels,\n calendar,\n snapToWorking = true,\n durationUnit = \"day\",\n readOnly = false,\n children,\n}: GanttProviderProps) {\n const [selectedId, setSelectedId] = useState<Id | null>(null);\n\n const labelsValue = useMemo(() => resolveLabels(labels), [labels]);\n\n // Content-keyed, so an inline `calendar={{...}}` prop does not churn identity.\n const resolvedCalendar = useResolvedCalendar(calendar);\n const schedulingContext = useMemo<SchedulingContext>(\n () => ({ calendar: resolvedCalendar, durationUnit, snapToWorking }),\n [resolvedCalendar, durationUnit, snapToWorking],\n );\n\n // Latest-refs for consumer callbacks used internally at a single call site,\n // so the handlers that wrap them keep a stable identity even when the\n // consumer passes inline functions.\n const onTaskEditRef = useLatestRef(onTaskEdit);\n\n // Callbacks handed to consumers through context: presence-preserving stable\n // wrappers, so context values only churn when the callback's presence flips.\n const onTaskClickStable = useEventCallback(onTaskClick);\n const onDependencyDeleteStable = useEventCallback(onDependencyDelete);\n\n const {\n tasksList,\n updateTask,\n commitTask,\n createTask: commitCreateTask,\n deleteTask,\n undo,\n redo,\n canUndo,\n canRedo,\n } = useTaskList(\n tasks,\n dependencies,\n {\n onTaskCreate: onTaskCreateProp,\n onTaskDelete,\n onTasksChange,\n },\n schedulingContext,\n );\n\n const { visibleTasks, expandedIds, parentIds, toggleExpand, revealAncestors } =\n useExpand(tasksList);\n const { taskListRef, gridRef, onTaskListScroll, onGridScroll, viewport } = useScrollSync();\n const gridBodyRef = useRef<HTMLDivElement>(null);\n\n // Zoom owns the effective `scales`/`colWidth`: each ladder rung defines the\n // calendar rows and the column width. Standalone `scales`/`colWidth` props\n // seed the default rung (see resolveZoomLevels).\n const zoomLevelsResolved = useMemo(\n () => resolveZoomLevels(zoomLevels, scales, colWidth),\n [zoomLevels, scales, colWidth],\n );\n const zoom = useZoom({\n gridRef,\n visibleTasks,\n padDays,\n levels: zoomLevelsResolved,\n initialIndex: defaultZoomIndex ?? DEFAULT_ZOOM_INDEX,\n });\n\n // After zoom: the horizontal reveal measures against the effective colWidth and\n // scales of the current rung, not the raw props.\n const revealTask = useRevealTask({\n taskListRef,\n gridRef,\n tasksList,\n visibleTasks,\n rowHeight,\n colWidth: zoom.level.colWidth,\n scales: zoom.level.scales,\n padDays,\n revealAncestors,\n });\n\n // Fires on mount as well as on every change, so a consumer can render zoom\n // controls from it without duplicating the initial-index resolution.\n const onZoomChangeRef = useLatestRef(onZoomChange);\n useEffect(() => {\n onZoomChangeRef.current?.({ index: zoom.index, count: zoom.count });\n }, [zoom.index, zoom.count, onZoomChangeRef]);\n\n // Commit (flushSync inside, so the consumer's onTaskCreate fires first),\n // then select and reveal the new task. `revealTask` sees the fresh list:\n // flushSync re-rendered this provider before returning.\n const createTask = useCallback(\n (task: GanttTask, afterId?: Id | null) => {\n commitCreateTask(task, afterId);\n setSelectedId(task.id);\n revealTask(task.id);\n },\n [commitCreateTask, revealTask],\n );\n\n const { zoomIn, zoomOut, setZoom, zoomAt } = zoom;\n\n // One handle, two consumers. `apiRef` and `columnApi` used to build the same\n // nine members separately, behind two 9-entry dep arrays.\n const handle = useGanttHandle({\n createTask,\n updateTask,\n deleteTask,\n undo,\n redo,\n revealTask,\n zoomIn,\n zoomOut,\n setZoom,\n });\n useImperativeHandle(apiRef, () => handle, [handle]);\n\n const columnApi = useColumnApi({\n handle,\n readOnly,\n labels: labelsValue,\n schedulingContext,\n onTaskEditRef,\n });\n\n const { drag, startDrag, endDrag } = useDependencyDrag({ gridBodyRef, onDependencyCreate });\n\n // --- Context values ---\n const configValue = useMemo<GanttConfigValue>(\n () => ({\n rowHeight,\n colWidth: zoom.level.colWidth,\n scales: zoom.level.scales,\n padDays,\n height,\n }),\n [rowHeight, zoom.level, padDays, height],\n );\n\n const zoomValue = useMemo<GanttZoomValue>(\n () => ({\n zoomIn,\n zoomOut,\n zoomAt,\n wheelEnabled: zoomWheel,\n keyboardEnabled: zoomKeyboard,\n }),\n [zoomIn, zoomOut, zoomAt, zoomWheel, zoomKeyboard],\n );\n\n const taskStateValue = useMemo<GanttTaskStateValue>(\n () => ({ tasksList, visibleTasks, expandedIds, parentIds, canUndo, canRedo }),\n [tasksList, visibleTasks, expandedIds, parentIds, canUndo, canRedo],\n );\n\n // `setSelectedId` is a useState setter — stable, safe to omit from deps.\n const taskActionsValue = useMemo<GanttTaskActionsValue>(\n () => ({\n updateTask,\n commitTask,\n createTask,\n deleteTask,\n undo,\n redo,\n columnApi,\n setSelectedId,\n toggleExpand,\n onTaskClick: onTaskClickStable,\n revealTask,\n }),\n [\n updateTask,\n commitTask,\n createTask,\n deleteTask,\n undo,\n redo,\n columnApi,\n toggleExpand,\n onTaskClickStable,\n revealTask,\n ],\n );\n\n // All members are stable refs/callbacks → created exactly once.\n const scrollValue = useMemo<GanttScrollValue>(\n () => ({ taskListRef, gridRef, gridBodyRef, onTaskListScroll, onGridScroll }),\n [taskListRef, gridRef, onTaskListScroll, onGridScroll],\n );\n\n const dependencyValue = useMemo<GanttDependencyValue>(\n () => ({\n dependencies,\n onDependencyDelete: onDependencyDeleteStable,\n startDrag,\n endDrag,\n }),\n [dependencies, onDependencyDeleteStable, startDrag, endDrag],\n );\n\n // `viewport`, `selectedId`, `drag`, and `drag !== null` are passed directly:\n // primitives or already identity-stable when unchanged.\n return (\n <GanttConfigContext.Provider value={configValue}>\n <GanttReadOnlyContext.Provider value={readOnly}>\n <GanttLabelsContext.Provider value={labelsValue}>\n <GanttCalendarContext.Provider value={schedulingContext}>\n <GanttZoomContext.Provider value={zoomValue}>\n <GanttScrollContext.Provider value={scrollValue}>\n <GanttTaskActionsContext.Provider value={taskActionsValue}>\n <GanttDependencyContext.Provider value={dependencyValue}>\n <GanttTaskStateContext.Provider value={taskStateValue}>\n <GanttSelectionContext.Provider value={selectedId}>\n <GanttDragActiveContext.Provider value={drag !== null}>\n <GanttViewportContext.Provider value={viewport}>\n <GanttDragContext.Provider value={drag}>\n {children}\n </GanttDragContext.Provider>\n </GanttViewportContext.Provider>\n </GanttDragActiveContext.Provider>\n </GanttSelectionContext.Provider>\n </GanttTaskStateContext.Provider>\n </GanttDependencyContext.Provider>\n </GanttTaskActionsContext.Provider>\n </GanttScrollContext.Provider>\n </GanttZoomContext.Provider>\n </GanttCalendarContext.Provider>\n </GanttLabelsContext.Provider>\n </GanttReadOnlyContext.Provider>\n </GanttConfigContext.Provider>\n );\n}\n","import { createContext, useContext, type ReactNode } from \"react\";\nimport type { TreeCellSlotConfig } from \"../components/taskList/TreeCell\";\nimport type { TaskListHeaderSlotConfig } from \"../components/taskList/TaskListHeader\";\nimport type { TaskBarSlotConfig } from \"../components/bars/taskBar/TaskBar\";\nimport type { ProjectBarSlotConfig } from \"../components/bars/projectBar/ProjectBar\";\nimport type { MilestoneBarSlotConfig } from \"../components/bars/milestoneBar/MilestoneBar\";\nimport type { BarProgressSlotConfig } from \"../components/bars/progress/BarProgress\";\nimport type { BarProgressResizeHandleSlotConfig } from \"../components/bars/progress/BarProgressResizeHandle\";\nimport type { TaskResizerSlotConfig } from \"../components/bars/taskBar/TaskResizer\";\nimport type { ConnectorHandlesSlotConfig } from \"../components/bars/common/ConnectorHandles\";\nimport type { BarTooltipSlotConfig } from \"../components/bars/barTooltip\";\nimport type { DependencyLinksSlotConfig } from \"../components/dependency-links/DependencyLinks\";\nimport type { DependencyPreviewSlotConfig } from \"../components/dependency-links/DependencyPreview\";\nimport type { CalendarRowSlotConfig } from \"../components/calendar/CalendarRow\";\nimport type { GridColumnsSlotConfig } from \"../components/grid/GridColumns\";\nimport type { GridSlotConfig } from \"../components/grid/Grid\";\nimport type { GridResizeHandleSlotConfig } from \"../components/grid/GridResizeHandle\";\n\n/** Slots for the task-list pane. Delivered by prop-drilling (see `<Gantt taskList>`). */\nexport interface GanttTaskListSlots {\n treeCell?: TreeCellSlotConfig;\n header?: TaskListHeaderSlotConfig;\n}\n\n/** Slots for the timeline bars and their handles. Delivered via context. */\nexport interface GanttBarsSlots {\n taskBar?: TaskBarSlotConfig;\n projectBar?: ProjectBarSlotConfig;\n milestoneBar?: MilestoneBarSlotConfig;\n barProgress?: BarProgressSlotConfig;\n barProgressResizeHandle?: BarProgressResizeHandleSlotConfig;\n taskResizer?: TaskResizerSlotConfig;\n connectorHandles?: ConnectorHandlesSlotConfig;\n /**\n * One slot for all three bar types, rendered by `DraggableBar` so it is\n * scoped to the bar's own hover. Empty by default: no tooltip is rendered and\n * the bar keeps its native `title`. Note it is lost if `slots.root` is\n * replaced, since `DraggableBar` is only the default root (ADR-022).\n */\n tooltip?: BarTooltipSlotConfig;\n}\n\n/** Slots for dependency links. Delivered via context. */\nexport interface GanttDependenciesSlots {\n links?: DependencyLinksSlotConfig;\n preview?: DependencyPreviewSlotConfig;\n}\n\n/** Slots for the calendar/grid timeline chrome. Delivered via context. */\nexport interface GanttTimelineSlots {\n calendarRow?: CalendarRowSlotConfig;\n gridColumn?: GridColumnsSlotConfig;\n grid?: GridSlotConfig;\n gridResizeHandle?: GridResizeHandleSlotConfig;\n}\n\n/**\n * The grid-side slot groups delivered through context (bars/dependencies/\n * timeline). The `taskList` group is prop-drilled separately and is NOT here.\n */\nexport interface GanttSlotsValue {\n bars?: GanttBarsSlots;\n dependencies?: GanttDependenciesSlots;\n timeline?: GanttTimelineSlots;\n}\n\n// Default is an empty object so components reading their slice work fine when\n// rendered outside a provider (e.g. in isolation tests) — the hook never throws.\nconst GanttSlotsContext = createContext<GanttSlotsValue>({});\n\nexport function GanttSlotsProvider({\n value,\n children,\n}: {\n value: GanttSlotsValue;\n children: ReactNode;\n}) {\n return <GanttSlotsContext.Provider value={value}>{children}</GanttSlotsContext.Provider>;\n}\n\n/** Read the grid-side slot groups. Returns `{}` outside a provider. */\nexport function useGanttSlots(): GanttSlotsValue {\n return useContext(GanttSlotsContext);\n}\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import { clsx } from \"clsx\";\nimport type { CSSProperties } from \"react\";\n\n/**\n * A consumer-supplied `slotProps` value for a single slot: either a props object,\n * or a function of the component's `ownerState` returning props.\n *\n * `P` is the target element's prop type. Per-slot we pass the native element props\n * (e.g. `ComponentProps<\"button\">`) so consumers get `className` / `onClick` / aria /\n * `data-*` autocomplete. If a consumer replaces the element with a custom component\n * via `slots`, the props stay loosely typed against the native shape (MUI's default).\n */\nexport type SlotPropsInput<P, OwnerState> = Partial<P> | ((ownerState: OwnerState) => Partial<P>);\n\n/** Convenience shape for a component's public `{ slots, slotProps }` config prop. */\nexport interface SlotConfig<Slots, SlotProps> {\n slots?: Slots;\n slotProps?: SlotProps;\n}\n\n/**\n * Merge library-owned internal props with a consumer's `slotProps` for one slot.\n *\n * - `className`: `clsx(internal, external)` — both apply, the consumer's comes last.\n * - `style`: shallow-merged, the consumer wins per key.\n * - all other props: the consumer overrides the internal value (MUI semantics — e.g.\n * passing `onClick` replaces the default handler; this is the consumer's\n * responsibility to preserve behavior).\n */\nexport function mergeSlotProps<\n Props extends { className?: string; style?: CSSProperties },\n OwnerState,\n>(\n internalProps: Props,\n slotProps: SlotPropsInput<Props, OwnerState> | undefined,\n ownerState: OwnerState,\n): Props {\n const external = typeof slotProps === \"function\" ? slotProps(ownerState) : slotProps;\n if (!external) {\n return internalProps;\n }\n const { className, style, ...rest } = external;\n return {\n ...internalProps,\n ...rest,\n className: clsx(internalProps.className, className),\n style: { ...internalProps.style, ...style },\n } as Props;\n}\n",".calendar {\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-radius: var(--am-gantt-calendar-radius, 6px);\n overflow: hidden;\n background: var(--am-gantt-calendar-bg, #ffffff);\n font-family: inherit;\n user-select: none;\n /* Stay pinned to the top while rows scroll under it when a height is set.\n Horizontal scroll still moves it (sticky only pins the vertical axis here),\n keeping the date columns aligned with the bars. */\n position: sticky;\n top: 0;\n z-index: var(--am-gantt-calendar-z-index, 30);\n}\n\n.row {\n position: relative;\n box-sizing: border-box;\n border-bottom: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n}\n\n.row:last-child {\n border-bottom: none;\n}\n\n.row:first-child .cell {\n background: var(--am-gantt-calendar-header-bg, #f8fafc);\n font-weight: 600;\n color: var(--am-gantt-calendar-header-color, #0f172a);\n}\n\n.cell {\n position: absolute;\n top: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n padding: 0 8px;\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n font-size: 13px;\n color: var(--am-gantt-calendar-color, #334155);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.cell:last-child {\n border-right: none;\n}\n\n.cellWeekend {\n background: var(--am-gantt-calendar-weekend-bg, #f1f5f9);\n color: var(--am-gantt-calendar-weekend-color, #64748b);\n}\n","import { clsx } from \"clsx\";\nimport { useMemo, type ComponentProps, type ElementType } from \"react\";\nimport { addUnit, isWeekend, periodKey } from \"../../core/dateUtils\";\nimport { nonWorkingInfo, type NonWorkingReason } from \"../../core/workingTime\";\nimport { useGanttWorkCalendar } from \"../../context/contexts\";\nimport { formatPeriodLabel } from \"../../core/labels\";\nimport type { Scale } from \"../../types\";\nimport type { IndexRange } from \"../../core/virtualize\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport styles from \"./Calendar.module.css\";\n\n/** State passed to the function form of the CalendarRow `row` slotProps. */\nexport interface CalendarRowOwnerState {\n scale: Scale;\n colWidth: number;\n rowHeight: number;\n highlightWeekends: boolean;\n}\n\n/** State passed to the function form of the CalendarRow `cell` slotProps (per group). */\nexport interface CalendarCellOwnerState {\n scale: Scale;\n /** Start date of the group this cell represents. */\n date: Date;\n /** Index of the group's first date column. */\n startIndex: number;\n /** Number of date columns the group spans. */\n count: number;\n /**\n * Whether the calendar excludes this cell from working time. Prefer this over\n * {@link CalendarCellOwnerState.isWeekend} — it also covers holidays.\n */\n isNonWorking: boolean;\n /** Why the cell is non-working, for styling weekends and holidays apart. */\n nonWorkingReason?: NonWorkingReason;\n /**\n * @deprecated Use {@link CalendarCellOwnerState.isNonWorking}. Retained as an\n * alias so existing slot code keeps working.\n */\n isWeekend: boolean;\n colWidth: number;\n}\n\nexport interface CalendarRowSlots {\n /** The row container. Default: `\"div\"`. */\n row?: ElementType;\n /** A per-group header cell. Default: `\"div\"`. */\n cell?: ElementType;\n}\n\nexport interface CalendarRowSlotProps {\n row?: SlotPropsInput<ComponentProps<\"div\">, CalendarRowOwnerState>;\n cell?: SlotPropsInput<ComponentProps<\"div\">, CalendarCellOwnerState>;\n}\n\n/**\n * Slot config for a calendar (header) row. Pass via the calendar's slot props.\n *\n * NOTE: pass a referentially stable / memoized object so downstream memoization\n * is not defeated by a fresh object each render.\n */\nexport type CalendarRowSlotConfig = SlotConfig<CalendarRowSlots, CalendarRowSlotProps>;\n\ntype CalendarRowProps = {\n scale: Scale;\n dates: Date[];\n colWidth: number;\n rowHeight: number;\n highlightWeekends?: boolean;\n /**\n * Half-open range of date indices in view (virtualization window).\n * When omitted, every group is rendered.\n */\n colRange?: IndexRange;\n /** 1-based row number within the enclosing grid, for `aria-rowindex`. */\n rowIndex?: number;\n slots?: CalendarRowSlots;\n slotProps?: CalendarRowSlotProps;\n};\n\ninterface Group {\n key: string;\n start: Date;\n /** Index of the group's first date column, for absolute positioning. */\n startIndex: number;\n count: number;\n}\n\nfunction groupDates(dates: Date[], scale: Scale): Group[] {\n const groups: Group[] = [];\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i]!;\n const key = periodKey(date, scale.unit, scale.step);\n const last = groups[groups.length - 1];\n if (last && last.key === key) {\n last.count += 1;\n } else {\n groups.push({ key, start: date, startIndex: i, count: 1 });\n }\n }\n return groups;\n}\n\n/**\n * Half-open slice of `groups` overlapping `colRange`. Groups tile the date axis\n * in order and without gaps, so the first visible one is a binary search away\n * and the last is a short walk from there — no pass over the full list, which\n * at day scale is one entry per rendered date.\n */\nfunction groupRange(groups: Group[], colRange: IndexRange | undefined): IndexRange {\n if (!colRange) {\n return { start: 0, end: groups.length };\n }\n let lo = 0;\n let hi = groups.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n const group = groups[mid]!;\n if (group.startIndex + group.count <= colRange.start) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n let end = lo;\n while (end < groups.length && groups[end]!.startIndex < colRange.end) {\n end += 1;\n }\n return { start: lo, end };\n}\n\nexport function CalendarRow({\n scale,\n dates,\n colWidth,\n rowHeight,\n highlightWeekends = false,\n colRange,\n rowIndex,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: CalendarRowProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.calendarRow?.slots;\n const { calendar } = useGanttWorkCalendar();\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.calendarRow?.slotProps;\n\n // Grouping walks every date, so it must not ride along with the scroll frames\n // that change `colRange`: `dates` only changes when the task range or zoom\n // level does.\n const groups = useMemo(() => groupDates(dates, scale), [dates, scale]);\n const visible = groupRange(groups, colRange);\n\n const Row = slots?.row ?? \"div\";\n const Cell = slots?.cell ?? \"div\";\n\n const rowOwnerState: CalendarRowOwnerState = {\n scale,\n colWidth,\n rowHeight,\n highlightWeekends,\n };\n\n const rowProps = mergeSlotProps(\n {\n className: styles.row,\n style: { height: rowHeight },\n role: \"row\",\n \"aria-rowindex\": rowIndex,\n },\n slotProps?.row,\n rowOwnerState,\n );\n\n return (\n <Row {...rowProps}>\n {groups.slice(visible.start, visible.end).map((group) => {\n const info =\n highlightWeekends && calendar\n ? nonWorkingInfo(calendar, group.start, addUnit(group.start, scale.unit, scale.step))\n : { isNonWorking: false, reason: undefined };\n // With no calendar, keep the historical Sat/Sun-only behaviour exactly.\n const nonWorking = calendar\n ? info.isNonWorking\n : highlightWeekends && isWeekend(group.start);\n const cellOwnerState: CalendarCellOwnerState = {\n scale,\n date: group.start,\n startIndex: group.startIndex,\n count: group.count,\n isNonWorking: nonWorking,\n nonWorkingReason: nonWorking ? (info.reason ?? \"weekend\") : undefined,\n isWeekend: nonWorking,\n colWidth,\n };\n\n const cellProps = mergeSlotProps(\n {\n className: clsx(styles.cell, nonWorking && styles.cellWeekend),\n style: {\n left: group.startIndex * colWidth,\n width: group.count * colWidth,\n },\n children: scale.format(group.start),\n role: \"columnheader\",\n \"aria-colindex\": group.startIndex + 1,\n \"aria-colspan\": group.count,\n \"aria-label\": scale.ariaFormat\n ? scale.ariaFormat(group.start)\n : formatPeriodLabel(group.start, scale.unit, scale.step),\n },\n slotProps?.cell,\n cellOwnerState,\n );\n return <Cell key={group.key} {...cellProps} />;\n })}\n </Row>\n );\n}\n","import type { Scale } from \"../../types\";\nimport type { IndexRange } from \"../../core/virtualize\";\nimport styles from \"./Calendar.module.css\";\nimport { CalendarRow } from \"./CalendarRow\";\nimport { DEFAULT_SCALES } from \"../../core/scales\";\n\nexport type CalendarProps = {\n colWidth: number;\n rowHeight: number;\n scales?: Scale[];\n dates: Date[];\n /** Half-open range of date indices in view (virtualization window). */\n colRange: IndexRange;\n};\n\nexport function Calendar({\n colWidth,\n rowHeight,\n scales = DEFAULT_SCALES,\n dates,\n colRange,\n}: CalendarProps) {\n const totalWidth = dates.length * colWidth;\n\n return (\n <div className={styles.calendar} style={{ width: totalWidth }} role=\"rowgroup\">\n {scales.map((scale, index) => (\n <CalendarRow\n key={`${scale.unit}-${scale.step}`}\n scale={scale}\n dates={dates}\n colWidth={colWidth}\n rowHeight={rowHeight}\n highlightWeekends={scale.unit === \"day\" && scale.step === 1}\n colRange={colRange}\n rowIndex={index + 1}\n />\n ))}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef } from \"react\";\n\nconst EDGE = 40;\nconst MAX_SPEED = 14;\n\nfunction findScrollContainer(el: HTMLElement | null): HTMLElement | null {\n let node = el;\n while (node) {\n const style = getComputedStyle(node);\n const hasScrollableOverflow = style.overflowX === \"auto\" || style.overflowX === \"scroll\";\n if (hasScrollableOverflow && node.scrollWidth > node.clientWidth) {\n return node;\n }\n node = node.parentElement;\n }\n return document.scrollingElement as HTMLElement | null;\n}\n\nfunction bounds(container: HTMLElement): { left: number; right: number } {\n if (container === document.scrollingElement) {\n return { left: 0, right: window.innerWidth };\n }\n const boundingRect = container.getBoundingClientRect();\n return { left: boundingRect.left, right: boundingRect.right };\n}\n\nfunction edgeSpeed(left: number, right: number, cursorX: number): number {\n if (cursorX < left + EDGE) {\n return -MAX_SPEED * Math.min(1, (left + EDGE - cursorX) / EDGE);\n }\n\n if (cursorX > right - EDGE) {\n return MAX_SPEED * Math.min(1, (cursorX - (right - EDGE)) / EDGE);\n }\n\n return 0;\n}\n\ninterface AutoScrollState {\n container: HTMLElement | null;\n scrollTarget: EventTarget | null;\n startScrollLeft: number;\n cursorX: number;\n rafId: number | null;\n}\n\ninterface UseAutoScrollOptions {\n enabled: boolean;\n onScroll: () => void;\n}\n\nexport interface AutoScrollHandle {\n start: (el: HTMLElement) => void;\n stop: () => void;\n setCursorX: (clientX: number) => void;\n getScrollDelta: () => number;\n}\n\nexport function useAutoScroll({ enabled, onScroll }: UseAutoScrollOptions): AutoScrollHandle {\n const stateRef = useRef<AutoScrollState>({\n container: null,\n scrollTarget: null,\n startScrollLeft: 0,\n cursorX: 0,\n rafId: null,\n });\n\n // Indirection: removeEventListener needs the same handler ref across\n // start/stop, but onScroll's identity changes on every render of useDrag.\n const onScrollRef = useRef(onScroll);\n onScrollRef.current = onScroll;\n const handleScroll = useCallback(() => onScrollRef.current(), []);\n\n const tick = useCallback(() => {\n const s = stateRef.current;\n if (!s.container) {\n s.rafId = null;\n return;\n }\n const { left, right } = bounds(s.container);\n const speed = edgeSpeed(left, right, s.cursorX);\n if (speed !== 0) {\n s.container.scrollLeft += speed;\n }\n s.rafId = requestAnimationFrame(tick);\n }, []);\n\n const stop = useCallback(() => {\n const s = stateRef.current;\n if (s.rafId !== null) {\n cancelAnimationFrame(s.rafId);\n }\n if (s.scrollTarget) {\n s.scrollTarget.removeEventListener(\"scroll\", handleScroll);\n }\n s.container = null;\n s.scrollTarget = null;\n s.rafId = null;\n }, [handleScroll]);\n\n const start = useCallback(\n (el: HTMLElement) => {\n if (!enabled) {\n return;\n }\n const s = stateRef.current;\n const container = findScrollContainer(el);\n s.container = container;\n s.startScrollLeft = container?.scrollLeft ?? 0;\n if (container) {\n s.scrollTarget = container === document.scrollingElement ? window : container;\n // Passive: the handler only re-fires the drag, it never preventDefaults,\n // so the browser must not wait on it to scroll.\n s.scrollTarget.addEventListener(\"scroll\", handleScroll, { passive: true });\n s.rafId = requestAnimationFrame(tick);\n }\n },\n [enabled, handleScroll, tick],\n );\n\n const setCursorX = useCallback((clientX: number) => {\n stateRef.current.cursorX = clientX;\n }, []);\n\n const getScrollDelta = useCallback(() => {\n const s = stateRef.current;\n return s.container ? s.container.scrollLeft - s.startScrollLeft : 0;\n }, []);\n\n useEffect(() => stop, [stop]);\n\n return { start, stop, setCursorX, getScrollDelta };\n}\n","import { useCallback, useEffect, useRef } from \"react\";\nimport { useAutoScroll } from \"./useAutoScroll\";\n\ninterface UseDragOptions<T> {\n onStart: (e: React.MouseEvent) => T;\n onDrag: (deltaX: number, ctx: T) => void;\n onEnd?: (deltaX: number, ctx: T) => void;\n autoScroll?: boolean;\n}\n\nexport function useDrag<T>({ onStart, onDrag, onEnd, autoScroll = false }: UseDragOptions<T>) {\n const isActiveRef = useRef(false);\n const ctxRef = useRef<T | null>(null);\n const startXRef = useRef(0);\n const lastClientXRef = useRef(0);\n const lastDeltaRef = useRef(0);\n\n const onDragRef = useRef(onDrag);\n const onEndRef = useRef(onEnd);\n onDragRef.current = onDrag;\n onEndRef.current = onEnd;\n\n // Forward ref to fireDrag so useAutoScroll can call it without a circular dep.\n const fireDragRef = useRef<() => void>(() => {});\n\n const {\n start: startAutoScroll,\n stop: stopAutoScroll,\n setCursorX,\n getScrollDelta,\n } = useAutoScroll({\n enabled: autoScroll,\n onScroll: () => fireDragRef.current(),\n });\n\n const fireDrag = useCallback(() => {\n if (!isActiveRef.current || ctxRef.current === null) {\n return;\n }\n const cursorDelta = lastClientXRef.current - startXRef.current;\n const deltaX = cursorDelta + getScrollDelta();\n lastDeltaRef.current = deltaX;\n onDragRef.current(deltaX, ctxRef.current);\n }, [getScrollDelta]);\n fireDragRef.current = fireDrag;\n\n const onMouseDown = useCallback(\n (e: React.MouseEvent) => {\n ctxRef.current = onStart(e);\n startXRef.current = e.clientX;\n lastClientXRef.current = e.clientX;\n lastDeltaRef.current = 0;\n isActiveRef.current = true;\n setCursorX(e.clientX);\n startAutoScroll(e.currentTarget as HTMLElement);\n e.preventDefault();\n e.stopPropagation();\n },\n [onStart, setCursorX, startAutoScroll],\n );\n\n useEffect(() => {\n const onMouseMove = (e: MouseEvent) => {\n if (!isActiveRef.current || ctxRef.current === null) {\n return;\n }\n lastClientXRef.current = e.clientX;\n setCursorX(e.clientX);\n fireDrag();\n e.preventDefault();\n };\n const onMouseUp = () => {\n if (isActiveRef.current && ctxRef.current !== null) {\n onEndRef.current?.(lastDeltaRef.current, ctxRef.current);\n }\n isActiveRef.current = false;\n ctxRef.current = null;\n stopAutoScroll();\n };\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mouseup\", onMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", onMouseMove);\n window.removeEventListener(\"mouseup\", onMouseUp);\n stopAutoScroll();\n };\n }, [fireDrag, setCursorX, stopAutoScroll]);\n\n return onMouseDown;\n}\n","/*\n * `left`/`top` are written inline by BarTooltip.tsx, which places the tooltip\n * from the cursor. Nothing here positions it (ADR-022).\n *\n * The element is portalled to `document.body`, which is what makes the z-index\n * below mean anything — rendered in place it sits inside `.row`, a stacking\n * context, and could never out-rank the calendar header. Being outside the grid\n * subtree is also what escapes its `overflow: auto`, so the containing-block\n * caveat that used to apply here no longer does.\n */\n.tooltip {\n position: fixed;\n\n /* Ranks at the top level now, so it must clear the calendar header (30) and\n * anything else the chart stacks. Themable for consumers whose own overlays\n * sit higher. */\n z-index: var(--am-gantt-tooltip-z-index, 1000);\n\n width: max-content;\n max-width: var(--am-gantt-tooltip-max-width, 260px);\n padding: var(--am-gantt-tooltip-padding, 8px 10px);\n border-radius: var(--am-gantt-tooltip-radius, 6px);\n background: var(--am-gantt-tooltip-bg, #0f172a);\n color: var(--am-gantt-tooltip-color, #f8fafc);\n font-size: var(--am-gantt-tooltip-font-size, 12px);\n line-height: 1.45;\n box-shadow: var(--am-gantt-tooltip-shadow, 0 4px 12px rgb(15 23 42 / 25%));\n pointer-events: none;\n}\n\n.name {\n font-weight: 600;\n margin-block-end: 4px;\n}\n\n.row {\n display: flex;\n gap: 12px;\n justify-content: space-between;\n}\n\n.label {\n opacity: 0.7;\n}\n","import { createContext, useContext, type RefObject } from \"react\";\n\n/**\n * Open state shared *within one tooltip slot*, owned by `BarTooltipRoot` and read\n * by `BarTooltipTrigger` and the popup.\n *\n * It sits inside the slot rather than in `BarTooltipConsumer` so that nothing\n * outside the slot has an opinion about open state (ADR-022).\n *\n * `null` means there is no root above, which is why `BarTooltipTrigger` is a\n * no-op rather than an error: `TaskBar`/`ProjectBar`/`MilestoneBar` are public\n * exports that render standalone.\n */\nexport interface BarTooltipContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n /** The bar's DOM node, used to verify the pointer really did leave it. */\n anchorRef: RefObject<HTMLDivElement | null>;\n}\n\nexport const BarTooltipContext = createContext<BarTooltipContextValue | null>(null);\n\n/** The enclosing `BarTooltipRoot`'s state, or `null` when there is none. */\nexport const useBarTooltip = (): BarTooltipContextValue | null => useContext(BarTooltipContext);\n","import { useMemo, useState, type ReactNode, type RefObject } from \"react\";\nimport { BarTooltipContext, type BarTooltipContextValue } from \"./BarTooltipContext\";\n\n/**\n * Owns one bar tooltip's open state and publishes it to `BarTooltipTrigger` and\n * whatever renders the popup.\n *\n * Belongs *inside* the tooltip slot, and a slot is free to skip it entirely and\n * use a third-party tooltip's root instead (ADR-022).\n *\n * Exported for the middle case: a custom tooltip that wants the library's hover\n * and closing behaviour with different markup. Compose it with\n * `BarTooltipTrigger` and `useBarTooltip`.\n */\nexport function BarTooltipRoot({\n anchorRef,\n children,\n}: {\n anchorRef: RefObject<HTMLDivElement | null>;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n\n const value = useMemo<BarTooltipContextValue>(\n () => ({ open, setOpen, anchorRef }),\n [open, anchorRef],\n );\n\n return <BarTooltipContext.Provider value={value}>{children}</BarTooltipContext.Provider>;\n}\n","import { useContext, useState, type CSSProperties, type RefObject, useDeferredValue } from \"react\";\nimport { GanttScrollContext } from \"../../../context/contexts\";\nimport { useIsomorphicLayoutEffect } from \"../../../hooks/useIsomorphicLayoutEffect\";\n\n/** Gap between the cursor and the tooltip's nearest corner, px. */\nconst CURSOR_OFFSET = 12;\n/** Distance kept clear of the bounding edges, px. */\nconst EDGE_MARGIN = 8;\n\nlet openedAt: { x: number; y: number } | null = null;\n\nexport function rememberOpenPointer(x: number, y: number) {\n openedAt = { x, y };\n}\n\ninterface Bounds {\n left: number;\n top: number;\n right: number;\n bottom: number;\n}\n\nfunction placeAxis(cursor: number, size: number, min: number, max: number): number {\n const after = cursor + CURSOR_OFFSET;\n const fitsAfter = after + size <= max - EDGE_MARGIN;\n return Math.max(fitsAfter ? after : cursor - CURSOR_OFFSET - size, min + EDGE_MARGIN);\n}\n\nexport const useTooltipPosition = (\n tooltipRef: RefObject<HTMLDivElement | null>,\n open: boolean,\n): CSSProperties => {\n // Read the context, do not assert it: `useGanttScroll()` throws without a\n // provider, and this hook must not. Two cases reach it with no provider above.\n //\n // `TaskBar`/`ProjectBar`/`MilestoneBar` are public exports that render\n // standalone, and `GanttSlotsProvider` is public too — so a bar can be handed\n // this tooltip with no chart around it, the same case that makes\n // `useBarTooltip` return null rather than throw (ADR-022).\n //\n // The other is a hot reload. Re-evaluating `contexts.ts` mints a new context\n // object, which the already-mounted provider is not providing; the throwing\n // hook turned that into a crash on every HMR update with a tooltip open.\n //\n // Losing the grid only widens the bounds — the fallback below is the viewport,\n // which is why degrading here costs nothing but a clamp.\n const gridRef = useContext(GanttScrollContext)?.gridRef;\n const [positioningStyle, setPositiongStyle] = useState<CSSProperties>({\n left: -9999,\n top: -9999,\n });\n\n const deferredPosition = useDeferredValue(positioningStyle);\n\n useIsomorphicLayoutEffect(() => {\n // Gated on `open`, and that is not a micro-optimisation. The slot wraps the\n // bar, so one instance is mounted per visible row — roughly thirty. Without\n // this, every one of them would listen for mousemove and call `setState` on\n // every pointer move anywhere in the chart.\n if (!open) {\n return;\n }\n\n const place = (clientX: number, clientY: number) => {\n const grid = gridRef?.current?.getBoundingClientRect();\n const bounds: Bounds =\n grid && grid.width > 0 && grid.height > 0\n ? { left: grid.left, top: grid.top, right: grid.right, bottom: grid.bottom }\n : { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };\n\n // Outside the chart there is nothing to place against, and the trigger is\n // closing the tooltip on this same event anyway. Bailing out keeps a\n // pointer moving elsewhere on the page from re-rendering the tooltip on\n // every move, and stops it visibly chasing the cursor out of the grid on\n // the way.\n const outside =\n clientX < bounds.left ||\n clientX > bounds.right ||\n clientY < bounds.top ||\n clientY > bounds.bottom;\n if (outside) {\n return;\n }\n\n const self = tooltipRef.current?.getBoundingClientRect();\n const width = self?.width ?? 0;\n const height = self?.height ?? 0;\n\n const left = placeAxis(clientX, width, bounds.left, bounds.right);\n const top = placeAxis(clientY, height, bounds.top, bounds.bottom);\n\n // Clamping pins the tooltip to an edge over a range of cursor positions, so\n // a moving pointer often resolves to the position it already has. Bailing\n // on an unchanged result keeps those moves from re-rendering.\n setPositiongStyle((previous) =>\n previous.left === left && previous.top === top ? previous : { left, top },\n );\n };\n\n // Place from the pointer that opened it, rather than waiting for a mousemove\n // that may never come. `mouseenter` is synthesized from `mouseover`, so it\n // fires however sparsely the pointer is sampled — but if the cursor comes to\n // rest the instant it is inside the bar, no later move arrives and the popup\n // used to sit at its off-screen starting point, open and invisible. That is\n // the \"fast entry shows nothing\" case, and it is why closing is not involved.\n //\n // Runs before the mousemove listener is attached, so the position is already\n // right when the first move lands.\n if (openedAt) {\n place(openedAt.x, openedAt.y);\n }\n\n const handleMouseMove = (event: MouseEvent) => place(event.clientX, event.clientY);\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n };\n }, [tooltipRef, gridRef, open]);\n\n return deferredPosition;\n};\n","import {\n cloneElement,\n isValidElement,\n useEffect,\n type ComponentProps,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n} from \"react\";\nimport { useBarTooltip } from \"./BarTooltipContext\";\nimport { rememberOpenPointer } from \"./useTooltipPosition\";\n\n/**\n * Turns the element it is given into the tooltip's trigger. Belongs inside the\n * tooltip slot, under a `BarTooltipRoot` and wrapped around the slot's\n * `children`: that is what makes hover behaviour the slot's own business rather\n * than the bar's.\n *\n * It **merges** onto that element rather than wrapping it, which is not a style\n * preference: the bar contains `<button>` resize and connector handles, so a\n * wrapping trigger — Base UI's default renders a `<button>` — would nest buttons\n * and produce invalid HTML that breaks those controls. `cloneElement` adds no DOM\n * at all.\n *\n * Handlers are composed with whatever the element already has, so a consumer's\n * `slotProps.root` handlers and the a11y payload keep firing.\n */\nexport function BarTooltipTrigger({ children }: { children: ReactNode }) {\n const context = useBarTooltip();\n const open = context?.open ?? false;\n const setOpen = context?.setOpen;\n const anchorRef = context?.anchorRef;\n\n // `mouseleave` alone does not close the tooltip, and this is why it sometimes\n // stayed open. Boundary events follow *pointer movement*: when the bar leaves\n // from under a stationary pointer — a wheel scroll, a zoom changing `colWidth`,\n // a drag repositioning it — no `mouseout` is dispatched until the next pointer\n // event. Both listeners live only while open, and one bar is open at a time.\n useEffect(() => {\n if (!open || !setOpen) {\n return;\n }\n\n // Scroll is the case a pointer check cannot catch: a stationary cursor\n // produces no mousemove at all. Capture phase because `scroll` does not\n // bubble, on `document` so any scrolling ancestor counts.\n const closeOnScroll = () => setOpen(false);\n\n const closeIfOutside = (event: MouseEvent) => {\n const bar = anchorRef?.current;\n const target = event.target;\n\n // No node to compare against: leave it open rather than guess. Same posture\n // as the old unmeasured-rect guard.\n if (!bar || !(target instanceof Node)) {\n return;\n }\n if (!bar.contains(target)) {\n setOpen(false);\n }\n };\n\n document.addEventListener(\"scroll\", closeOnScroll, { capture: true, passive: true });\n document.addEventListener(\"mousemove\", closeIfOutside, { passive: true });\n return () => {\n document.removeEventListener(\"scroll\", closeOnScroll, { capture: true });\n document.removeEventListener(\"mousemove\", closeIfOutside);\n };\n }, [open, setOpen, anchorRef]);\n\n // `children` is typed as `ReactNode` because that is what a slot receives, so\n // the element case is checked rather than assumed. Anything else — a fragment,\n // a list, text — is handed back untouched: there is no single node to attach to.\n if (!setOpen || !isValidElement<ComponentProps<\"div\">>(children)) {\n return children;\n }\n\n const { onMouseEnter, onMouseLeave } = children.props;\n\n return cloneElement(children, {\n onMouseEnter: (event: ReactMouseEvent<HTMLDivElement>) => {\n onMouseEnter?.(event);\n rememberOpenPointer(event.clientX, event.clientY);\n setOpen(true);\n },\n onMouseLeave: (event: ReactMouseEvent<HTMLDivElement>) => {\n onMouseLeave?.(event);\n setOpen(false);\n },\n } as Partial<ComponentProps<\"div\">>);\n}\n","import { useRef, type ComponentProps, type CSSProperties } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport styles from \"./BarTooltip.module.css\";\nimport { useBarTooltip } from \"./BarTooltipContext\";\nimport { BarTooltipRoot } from \"./BarTooltipRoot\";\nimport { BarTooltipTrigger } from \"./BarTooltipTrigger\";\nimport type { BarTooltipOwnerState, BarTooltipProps } from \"./types\";\nimport { useTooltipPosition } from \"./useTooltipPosition\";\n\nfunction formatDate(date: Date | undefined) {\n if (!date) {\n return \"—\";\n }\n\n return date.toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n}\n\n/**\n * The popup itself. Separate from `GanttBarTooltip` because it reads the open\n * state its sibling `BarTooltipRoot` provides, and a component cannot consume the\n * context it renders.\n *\n * Portalled to `document.body`. That is what lets its z-index rank at the top\n * level — rendered in place it sits inside `.row`, a stacking context, where no\n * value could out-rank the calendar header (ADR-022).\n */\nfunction BarTooltipPopup({\n task,\n progress,\n displayEnd,\n className,\n style,\n ...divProps\n}: Omit<BarTooltipOwnerState, \"children\"> & ComponentProps<\"div\">) {\n const ref = useRef<HTMLDivElement | null>(null);\n const open = useBarTooltip()?.open ?? false;\n\n const positioning: CSSProperties = useTooltipPosition(ref, open);\n\n // `document` is guarded rather than assumed: the popup only exists on hover, so\n // a server render never reaches it, but it must not be touched during one.\n if (!open || typeof document === \"undefined\") {\n return null;\n }\n\n return createPortal(\n <div\n role=\"tooltip\"\n ref={ref}\n className={className ? `${styles.tooltip} ${className}` : styles.tooltip}\n style={{ ...style, ...positioning }}\n {...divProps}\n >\n <div className={styles.name}>{task.name}</div>\n <div className={styles.row}>\n <span className={styles.label}>Start</span>\n <span>{formatDate(task.startDate)}</span>\n </div>\n <div className={styles.row}>\n <span className={styles.label}>End</span>\n <span>{formatDate(displayEnd)}</span>\n </div>\n <div className={styles.row}>\n <span className={styles.label}>Progress</span>\n <span>{Math.round(progress)}%</span>\n </div>\n </div>,\n document.body,\n );\n}\n\n/**\n * The built-in bar tooltip. Opt in with `slots={{ tooltip: GanttBarTooltip }}`;\n * it is never rendered by default.\n *\n * A wrapper, not a sibling: it renders the bar it is handed and mounts its own\n * root and trigger around it, so it holds no privileged position over any other\n * slot (ADR-022).\n *\n * Placed from the cursor in JS, not with CSS anchor positioning: anchoring to the\n * bar puts the tooltip at the midpoint of a bar that can be wider than the\n * viewport. It follows the pointer for as long as it is open; there is no dwell\n * delay.\n */\nexport function GanttBarTooltip({\n task,\n progress,\n displayEnd,\n anchorRef,\n className,\n style,\n children,\n ...divProps\n}: BarTooltipProps & ComponentProps<\"div\">) {\n return (\n <BarTooltipRoot anchorRef={anchorRef}>\n <BarTooltipTrigger>{children}</BarTooltipTrigger>\n <BarTooltipPopup\n task={task}\n progress={progress}\n displayEnd={displayEnd}\n className={className}\n style={style}\n {...divProps}\n />\n </BarTooltipRoot>\n );\n}\n","import type { ReactNode, RefObject } from \"react\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport { mergeSlotProps } from \"../../../core/slots\";\nimport type { BarTooltipOwnerState } from \"./types\";\n\n/**\n * Resolves the tooltip slot and wraps the bar in it. Stateless on purpose.\n *\n * There is no open state and no context here: whether the tooltip is showing is\n * the slot's business, held by `BarTooltipRoot` inside it. That is what lets a\n * slot be a third-party tooltip that brings its own root and trigger (ADR-022).\n *\n * The slot is a *wrapper*: it receives the bar as `children` and must render it.\n */\nexport function BarTooltipConsumer({\n children,\n tooltip,\n anchorRef,\n}: {\n children: ReactNode;\n tooltip?: BarTooltipOwnerState;\n anchorRef: RefObject<HTMLDivElement | null>;\n}) {\n const tooltipConfig = useGanttSlots().bars?.tooltip;\n const Tooltip = tooltipConfig?.slots?.tooltip;\n\n if (!Tooltip || !tooltip) {\n return children;\n }\n\n return (\n <Tooltip\n {...mergeSlotProps({}, tooltipConfig?.slotProps?.tooltip, tooltip)}\n anchorRef={anchorRef}\n {...tooltip}\n >\n {children}\n </Tooltip>\n );\n}\n","import { useRef, type ComponentPropsWithoutRef, type CSSProperties, type ReactNode } from \"react\";\n\nimport { useDrag } from \"../../../hooks/useDrag\";\nimport { BarTooltipConsumer, type BarTooltipOwnerState } from \"../barTooltip\";\n\nexport interface BarA11yProps {\n role: string;\n \"aria-colindex\": number;\n \"aria-colspan\": number;\n \"aria-label\": string;\n \"aria-selected\": boolean | undefined;\n /**\n * The native browser tooltip. Optional because a chart with a tooltip slot\n * suppresses it — two tooltips would stack. `aria-label` is unaffected, so\n * the accessible name survives either way.\n */\n title?: string;\n}\n\ninterface DraggableBarProps extends Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"style\" | \"className\" | \"title\" | \"children\" | \"onMouseDown\"\n> {\n left: number;\n top: number;\n width: number;\n height: number;\n colWidth: number;\n dragAnchor: number;\n className?: string;\n title?: string;\n style?: CSSProperties;\n /** Omitted on a read-only chart; without it the bar carries no drag listener. */\n onMove?: (newAnchor: number) => void;\n onMoveEnd?: (newAnchor: number) => void;\n /**\n * Task data for the tooltip slot; omit it and no tooltip is rendered.\n *\n * The tooltip lives here rather than in `Row` so it is scoped to the bar's own\n * hover — a row spans the whole timeline width — and so it can anchor to this\n * element without a ref threaded down from above.\n *\n * The cost, accepted deliberately: this is only the *default* root\n * (`Root = slots?.root ?? DraggableBar` in all three bars), so replacing\n * `slots.root` removes the tooltip unless the replacement forwards this prop\n * on to a `DraggableBar` of its own (ADR-022).\n */\n tooltip?: BarTooltipOwnerState;\n children?: ReactNode;\n}\n\nexport function DraggableBar({\n left,\n top,\n width,\n height,\n colWidth,\n dragAnchor,\n className,\n title,\n style,\n onMove,\n onMoveEnd,\n tooltip,\n onMouseEnter,\n onMouseLeave,\n children,\n ...rest\n}: DraggableBarProps) {\n const barRef = useRef<HTMLDivElement>(null);\n\n const readOnly = !onMove && !onMoveEnd;\n const onMouseDown = useDrag({\n onStart: () => ({ start: dragAnchor }),\n onDrag: (deltaX, { start }) => onMove?.(start + deltaX),\n onEnd: (deltaX, { start }) => {\n const snapped = Math.round((start + deltaX) / colWidth) * colWidth;\n onMoveEnd?.(snapped);\n },\n autoScroll: true,\n });\n\n const movable = Boolean(onMove || onMoveEnd);\n\n return (\n <BarTooltipConsumer tooltip={tooltip} anchorRef={barRef}>\n <div\n {...rest}\n ref={barRef}\n className={className}\n style={{ left, top, width, height, cursor: readOnly ? \"default\" : \"move\", ...style }}\n title={title}\n onMouseDown={movable ? onMouseDown : undefined}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n >\n {children}\n </div>\n </BarTooltipConsumer>\n );\n}\n",".milestone {\n position: absolute;\n}\n\n.milestoneShape {\n width: 100%;\n height: 100%;\n background-color: var(--am-gantt-milestone-bg);\n clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { DraggableBar, type BarA11yProps } from \"../common/DraggableBar\";\nimport styles from \"./MilestoneBar.module.css\";\n\nexport interface MilestoneBarOwnerState {\n size: number;\n title: string;\n}\n\nexport interface MilestoneBarSlots {\n /** The draggable bar wrapper. Default: `DraggableBar`. */\n root?: ElementType;\n /** The diamond shape. Default: `\"div\"`. */\n shape?: ElementType;\n}\n\nexport interface MilestoneBarSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, MilestoneBarOwnerState>;\n shape?: SlotPropsInput<ComponentProps<\"div\">, MilestoneBarOwnerState>;\n}\n\nexport type MilestoneBarSlotConfig = SlotConfig<MilestoneBarSlots, MilestoneBarSlotProps>;\n\ninterface MilestoneBarProps {\n size: number;\n centerLeft: number;\n top: number;\n colWidth: number;\n title: string;\n a11y?: BarA11yProps;\n /** Editing handlers; omitted on a read-only chart (see `TaskBar`). */\n onMove?: (newCenterLeft: number) => void;\n onMoveEnd?: (newCenterLeft: number) => void;\n /**\n * Task data handed to the root so it can render the tooltip slot. Forwarded\n * verbatim; a replaced `slots.root` that ignores it simply shows no tooltip.\n */\n tooltip?: BarTooltipOwnerState;\n slots?: MilestoneBarSlots;\n slotProps?: MilestoneBarSlotProps;\n}\n\nexport function MilestoneBar({\n size,\n centerLeft,\n top,\n colWidth,\n title,\n a11y,\n onMove,\n onMoveEnd,\n tooltip,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: MilestoneBarProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.milestoneBar?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.milestoneBar?.slotProps;\n\n const ownerState: MilestoneBarOwnerState = { size, title };\n\n const Root = slots?.root ?? DraggableBar;\n const Shape = slots?.shape ?? \"div\";\n\n // When `a11y` is supplied it owns the native tooltip, including deliberately\n // omitting it under a tooltip slot. The `title` prop is only the fallback for\n // standalone use of this component outside a chart.\n const rootProps = mergeSlotProps(\n { className: styles.milestone, ...a11y, title: a11y ? a11y.title : title },\n slotProps?.root,\n ownerState,\n );\n\n const shapeProps = mergeSlotProps(\n { className: styles.milestoneShape, \"aria-hidden\": true },\n slotProps?.shape,\n ownerState,\n );\n\n return (\n <Root\n tooltip={tooltip}\n left={centerLeft - size / 2}\n top={top}\n width={size}\n height={size}\n colWidth={colWidth}\n dragAnchor={centerLeft}\n onMove={onMove}\n onMoveEnd={onMoveEnd}\n {...rootProps}\n >\n <Shape {...shapeProps} />\n </Root>\n );\n}\n",".barProgress {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background-color: var(--am-gantt-bar-progress-bg, var(--am-gantt-task-bg-progress));\n border-radius: 4px 0 0 4px;\n}\n\n.barProgressResizeHandle {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 1px;\n height: 10px;\n cursor: ew-resize;\n background-color: transparent;\n z-index: 10;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n:global(.am-gantt-bar-task):hover .barProgressResizeHandle {\n opacity: 1;\n}\n\n.barProgressResizeHandle:after {\n content: \"\";\n position: absolute;\n top: 0;\n left: -5px;\n width: 10px;\n height: 10px;\n background-color: var(--am-gantt-calendar-border);\n /* triangle rotate */\n clip-path: polygon(50% 0%, 0% 100%, 100% 100%);\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { useDrag } from \"../../../hooks/useDrag\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport styles from \"./BarProgress.module.css\";\n\n/** State passed to the function form of the BarProgressResizeHandle slotProps. */\nexport interface BarProgressResizeHandleOwnerState {\n width: number;\n parentWidth: number;\n}\n\nexport interface BarProgressResizeHandleSlots {\n /** The progress resize handle element. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface BarProgressResizeHandleSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, BarProgressResizeHandleOwnerState>;\n}\n\nexport type BarProgressResizeHandleSlotConfig = SlotConfig<\n BarProgressResizeHandleSlots,\n BarProgressResizeHandleSlotProps\n>;\n\ntype BarProgressResizeHandleProps = {\n width: number;\n onResize: (newWidth: number) => void;\n onResizeEnd?: (newWidth: number) => void;\n parentWidth: number;\n slots?: BarProgressResizeHandleSlots;\n slotProps?: BarProgressResizeHandleSlotProps;\n};\n\nexport function BarProgressResizeHandle({\n width,\n onResize,\n onResizeEnd,\n parentWidth,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: BarProgressResizeHandleProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.barProgressResizeHandle?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.barProgressResizeHandle?.slotProps;\n\n const clampWidth = (deltaX: number, startWidth: number) =>\n Math.min(Math.max(0, startWidth + deltaX), parentWidth);\n\n const onMouseDown = useDrag({\n onStart: () => ({ startWidth: width }),\n onDrag: (deltaX, { startWidth }) => onResize(clampWidth(deltaX, startWidth)),\n onEnd: (deltaX, { startWidth }) => onResizeEnd?.(clampWidth(deltaX, startWidth)),\n });\n\n const ownerState: BarProgressResizeHandleOwnerState = { width, parentWidth };\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.barProgressResizeHandle,\n \"aria-hidden\": true,\n tabIndex: -1,\n onMouseDown,\n },\n slotProps?.root,\n ownerState,\n );\n\n return <Root {...rootProps} />;\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport styles from \"./BarProgress.module.css\";\nimport { BarProgressResizeHandle } from \"./BarProgressResizeHandle\";\n\n/** State passed to the function form of each BarProgress slotProps. */\nexport interface BarProgressOwnerState {\n progress: number;\n width: number;\n height: number;\n}\n\nexport interface BarProgressSlots {\n /** The progress fill element. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface BarProgressSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, BarProgressOwnerState>;\n}\n\n/** Slot config for the bar progress fill. */\nexport type BarProgressSlotConfig = SlotConfig<BarProgressSlots, BarProgressSlotProps>;\n\ninterface BarProgressProps {\n width: number;\n height: number;\n progress: number;\n onProgressChange?: (newProgress: number) => void;\n onProgressEnd?: (newProgress: number) => void;\n slots?: BarProgressSlots;\n slotProps?: BarProgressSlotProps;\n}\n\nexport function BarProgress({\n progress,\n width: parentWidth,\n height,\n onProgressChange,\n onProgressEnd,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: BarProgressProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.barProgress?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.barProgress?.slotProps;\n\n const width = (progress / 100) * parentWidth;\n const toProgress = (newWidth: number) => (newWidth / parentWidth) * 100;\n\n const ownerState: BarProgressOwnerState = { progress, width, height };\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n { className: styles.barProgress, style: { width, height } },\n slotProps?.root,\n ownerState,\n );\n\n return (\n <Root {...rootProps}>\n {onProgressChange && (\n <BarProgressResizeHandle\n width={width}\n parentWidth={parentWidth}\n onResize={(newWidth) => onProgressChange(toProgress(newWidth))}\n onResizeEnd={\n onProgressEnd ? (newWidth) => onProgressEnd(toProgress(newWidth)) : undefined\n }\n />\n )}\n </Root>\n );\n}\n",".project {\n position: absolute;\n box-sizing: border-box;\n background-color: var(--am-gantt-project-bg);\n border-radius: 4px;\n overflow: hidden;\n --am-gantt-bar-progress-bg: var(--am-gantt-project-bg-progress);\n}\n\n.projectInner {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.projectContent {\n vertical-align: middle;\n text-align: center;\n font-size: 14px;\n color: var(--am-gantt-project-color);\n font-weight: 600;\n position: relative;\n z-index: 1;\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { DraggableBar, type BarA11yProps } from \"../common/DraggableBar\";\nimport { BarProgress } from \"../progress/BarProgress\";\nimport styles from \"./ProjectBar.module.css\";\n\n/** State passed to the function form of each ProjectBar slotProps. */\nexport interface ProjectBarOwnerState {\n width: number;\n height: number;\n progress: number;\n title: string;\n}\n\nexport interface ProjectBarSlots {\n /** The draggable bar wrapper. Default: `DraggableBar`. */\n root?: ElementType;\n /** The inner layout wrapper holding progress/label. Default: `\"div\"`. */\n inner?: ElementType;\n /** The title label. Default: `\"div\"`. */\n label?: ElementType;\n}\n\nexport interface ProjectBarSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, ProjectBarOwnerState>;\n inner?: SlotPropsInput<ComponentProps<\"div\">, ProjectBarOwnerState>;\n label?: SlotPropsInput<ComponentProps<\"div\">, ProjectBarOwnerState>;\n}\n\n/** Slot config for the project bar. */\nexport type ProjectBarSlotConfig = SlotConfig<ProjectBarSlots, ProjectBarSlotProps>;\n\ninterface ProjectBarProps {\n width: number;\n height: number;\n left: number;\n top: number;\n colWidth: number;\n title: string;\n a11y?: BarA11yProps;\n progress: number;\n /** Editing handlers; omitted on a read-only chart (see `TaskBar`). */\n onProgressChange?: (newProgress: number) => void;\n onProgressEnd?: (newProgress: number) => void;\n onMove?: (newLeft: number) => void;\n onMoveEnd?: (newLeft: number) => void;\n /**\n * Task data handed to the root so it can render the tooltip slot. Forwarded\n * verbatim; a replaced `slots.root` that ignores it simply shows no tooltip.\n */\n tooltip?: BarTooltipOwnerState;\n slots?: ProjectBarSlots;\n slotProps?: ProjectBarSlotProps;\n}\n\nexport function ProjectBar({\n width,\n height,\n left,\n top,\n colWidth,\n title,\n a11y,\n progress,\n onProgressChange,\n onProgressEnd,\n onMove,\n onMoveEnd,\n tooltip,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: ProjectBarProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.projectBar?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.projectBar?.slotProps;\n\n const ownerState: ProjectBarOwnerState = { width, height, progress, title };\n\n const Root = slots?.root ?? DraggableBar;\n const Inner = slots?.inner ?? \"div\";\n const Label = slots?.label ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.project,\n style: { lineHeight: `${height}px` },\n ...a11y,\n },\n slotProps?.root,\n ownerState,\n );\n\n const innerProps = mergeSlotProps(\n { className: styles.projectInner, \"aria-hidden\": true },\n slotProps?.inner,\n ownerState,\n );\n\n const labelProps = mergeSlotProps(\n { className: styles.projectContent, children: title },\n slotProps?.label,\n ownerState,\n );\n\n return (\n <Root\n tooltip={tooltip}\n left={left}\n top={top}\n width={width}\n height={height}\n colWidth={colWidth}\n dragAnchor={left}\n onMove={onMove}\n onMoveEnd={onMoveEnd}\n {...rootProps}\n >\n <Inner {...innerProps}>\n <BarProgress\n width={width}\n height={height}\n progress={progress}\n onProgressChange={onProgressChange}\n onProgressEnd={onProgressEnd}\n />\n <Label {...labelProps} />\n </Inner>\n </Root>\n );\n}\n",".task {\n position: absolute;\n box-sizing: border-box;\n background-color: var(--am-gantt-task-bg);\n border-radius: var(--am-gantt-task-border-radius);\n --am-gantt-bar-progress-bg: var(--am-gantt-task-bg-progress);\n}\n\n.taskInner {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.taskContent {\n vertical-align: middle;\n text-align: center;\n font-size: var(--am-gantt-task-font-size);\n color: var(--am-gantt-task-color);\n padding-inline: 8px;\n position: relative;\n z-index: 1;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.resizer {\n position: absolute;\n top: 0;\n width: var(--am-gantt-resizer-width);\n height: 100%;\n cursor: ew-resize;\n background-color: transparent;\n z-index: 10;\n padding: 0;\n border: none;\n}\n\n.resizer::after {\n opacity: 0;\n content: \"\";\n width: var(--am-gantt-resizer-handle-width);\n inset: var(--am-gantt-resizer-handle-inset);\n height: calc(100% - (var(--am-gantt-resizer-handle-inset) * 2));\n border-radius: var(--am-gantt-resizer-handle-radius);\n background-color: var(--am-gantt-calendar-border);\n position: absolute;\n}\n\n.task:hover .resizer::after {\n opacity: 0.8;\n}\n\n.task:hover .resizer:hover .resizer::after {\n opacity: 1;\n}\n\n.startResizer {\n left: 0;\n}\n.endResizer {\n right: 0;\n}\n","import clsx from \"clsx\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { useDrag } from \"../../../hooks/useDrag\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport styles from \"./TaskBar.module.css\";\n\n/** State passed to the function form of each TaskResizer slotProps. */\nexport interface TaskResizerOwnerState {\n width: number;\n left: number;\n}\n\nexport interface TaskResizerSlots {\n /** The left/start resize button. Default: `\"button\"`. */\n startHandle?: ElementType;\n /** The right/end resize button. Default: `\"button\"`. */\n endHandle?: ElementType;\n}\n\nexport interface TaskResizerSlotProps {\n startHandle?: SlotPropsInput<ComponentProps<\"button\">, TaskResizerOwnerState>;\n endHandle?: SlotPropsInput<ComponentProps<\"button\">, TaskResizerOwnerState>;\n}\n\nexport type TaskResizerSlotConfig = SlotConfig<TaskResizerSlots, TaskResizerSlotProps>;\n\ninterface TaskResizerProps {\n width: number;\n left: number;\n colWidth: number;\n onResize: (newWidth: number, newLeft: number) => void;\n /**\n * Fired on release with ONLY the edge the user dragged, as an absolute pixel\n * position. The opposite edge is deliberately not reported: snapping both\n * independently is what used to let a start-handle drag shift the far edge by a\n * whole column.\n */\n onResizeEnd: (edge: \"start\" | \"end\", edgePx: number) => void;\n slots?: TaskResizerSlots;\n slotProps?: TaskResizerSlotProps;\n}\n\nexport function TaskResizer({\n width,\n left,\n colWidth,\n onResize,\n onResizeEnd,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: TaskResizerProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.taskResizer?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.taskResizer?.slotProps;\n\n const onStartHandleMouseDown = useDrag({\n onStart: () => ({ startWidth: width, startLeft: left }),\n onDrag: (deltaX, { startWidth, startLeft }) => {\n const clampedDelta = Math.min(deltaX, startWidth);\n const newWidth = startWidth - clampedDelta;\n const newLeft = startLeft + clampedDelta;\n onResize(newWidth, newLeft);\n },\n onEnd: (deltaX, { startWidth, startLeft }) => {\n const clampedDelta = Math.min(deltaX, startWidth);\n const rawLeft = startLeft + clampedDelta;\n onResizeEnd(\"start\", Math.round(rawLeft / colWidth) * colWidth);\n },\n });\n\n const onEndHandleMouseDown = useDrag({\n onStart: () => ({ startWidth: width, startLeft: left }),\n onDrag: (deltaX, { startWidth, startLeft }) => {\n const newWidth = Math.max(0, startWidth + deltaX);\n onResize(newWidth, startLeft);\n },\n onEnd: (deltaX, { startWidth, startLeft }) => {\n const rawRight = startLeft + Math.max(0, startWidth + deltaX);\n onResizeEnd(\"end\", Math.round(rawRight / colWidth) * colWidth);\n },\n });\n\n const ownerState: TaskResizerOwnerState = { width, left };\n\n const StartHandle = slots?.startHandle ?? \"button\";\n const EndHandle = slots?.endHandle ?? \"button\";\n\n const startHandleProps = mergeSlotProps(\n {\n type: \"button\" as const,\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.resizer, styles.startResizer),\n onMouseDown: onStartHandleMouseDown,\n },\n slotProps?.startHandle,\n ownerState,\n );\n\n const endHandleProps = mergeSlotProps(\n {\n type: \"button\" as const,\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.resizer, styles.endResizer),\n onMouseDown: onEndHandleMouseDown,\n },\n slotProps?.endHandle,\n ownerState,\n );\n\n return (\n <>\n <StartHandle {...startHandleProps} />\n <EndHandle {...endHandleProps} />\n </>\n );\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { DraggableBar, type BarA11yProps } from \"../common/DraggableBar\";\nimport { BarProgress } from \"../progress/BarProgress\";\nimport styles from \"./TaskBar.module.css\";\nimport { TaskResizer } from \"./TaskResizer\";\n\n/** State passed to the function form of each TaskBar slotProps. */\nexport interface TaskBarOwnerState {\n width: number;\n height: number;\n progress: number;\n title: string;\n}\n\nexport interface TaskBarSlots {\n /** The draggable bar wrapper. Default: `DraggableBar`. */\n root?: ElementType;\n /** The inner layout wrapper holding progress/label/resizer. Default: `\"div\"`. */\n inner?: ElementType;\n /** The title label. Default: `\"div\"`. */\n label?: ElementType;\n}\n\nexport interface TaskBarSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, TaskBarOwnerState>;\n inner?: SlotPropsInput<ComponentProps<\"div\">, TaskBarOwnerState>;\n label?: SlotPropsInput<ComponentProps<\"div\">, TaskBarOwnerState>;\n}\n\n/** Slot config for the task bar. */\nexport type TaskBarSlotConfig = SlotConfig<TaskBarSlots, TaskBarSlotProps>;\n\ninterface TaskBarProps {\n width: number;\n height: number;\n left: number;\n top: number;\n colWidth: number;\n title: string;\n a11y?: BarA11yProps;\n progress: number;\n /**\n * Editing handlers. All optional: a read-only chart omits them, and each\n * affordance is only rendered/wired when its handlers are present.\n */\n onProgressChange?: (newProgress: number) => void;\n onProgressEnd?: (newProgress: number) => void;\n onResize?: (newWidth: number, newLeft: number) => void;\n onResizeEnd?: (edge: \"start\" | \"end\", edgePx: number) => void;\n onMove?: (newLeft: number) => void;\n onMoveEnd?: (newLeft: number) => void;\n /**\n * Task data handed to the root so it can render the tooltip slot. Forwarded\n * verbatim; a replaced `slots.root` that ignores it simply shows no tooltip.\n */\n tooltip?: BarTooltipOwnerState;\n slots?: TaskBarSlots;\n slotProps?: TaskBarSlotProps;\n}\n\nexport function TaskBar({\n width,\n height,\n left,\n top,\n colWidth,\n title,\n a11y,\n progress = 30,\n onProgressChange,\n onProgressEnd,\n onResize,\n onResizeEnd,\n onMove,\n onMoveEnd,\n tooltip,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: TaskBarProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.taskBar?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.taskBar?.slotProps;\n\n const ownerState: TaskBarOwnerState = { width, height, progress, title };\n\n const Root = slots?.root ?? DraggableBar;\n const Inner = slots?.inner ?? \"div\";\n const Label = slots?.label ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: `${styles.task} am-gantt-bar-task`,\n style: { lineHeight: `${height}px` },\n ...a11y,\n },\n slotProps?.root,\n ownerState,\n );\n\n const innerProps = mergeSlotProps(\n { className: styles.taskInner, \"aria-hidden\": true },\n slotProps?.inner,\n ownerState,\n );\n\n // The label's native tooltip follows `a11y.title`, not the `title` prop: the\n // prop is the visible text, `a11y.title` is the native tooltip, and a chart\n // with a tooltip slot suppresses only the latter.\n const labelProps = mergeSlotProps(\n { className: styles.taskContent, title: a11y?.title, children: title },\n slotProps?.label,\n ownerState,\n );\n\n return (\n <Root\n tooltip={tooltip}\n left={left}\n top={top}\n width={width}\n height={height}\n colWidth={colWidth}\n dragAnchor={left}\n onMove={onMove}\n onMoveEnd={onMoveEnd}\n {...rootProps}\n >\n <Inner {...innerProps}>\n <BarProgress\n width={width}\n height={height}\n progress={progress}\n onProgressChange={onProgressChange}\n onProgressEnd={onProgressEnd}\n />\n <Label {...labelProps} />\n {onResize && onResizeEnd && (\n <TaskResizer\n width={width}\n left={left}\n colWidth={colWidth}\n onResize={onResize}\n onResizeEnd={onResizeEnd}\n />\n )}\n </Inner>\n </Root>\n );\n}\n",".handle {\n position: absolute;\n /* Keep in sync with CONNECTOR_HANDLE_SIZE in core/constants.ts */\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #3b82f6;\n border: 2px solid #fff;\n box-shadow: 0 0 0 1px #3b82f6;\n cursor: crosshair;\n z-index: 20;\n opacity: 0;\n transition: opacity 0.15s;\n pointer-events: auto;\n box-sizing: border-box;\n}\n\n.visible {\n opacity: 1;\n}\n","import { clsx } from \"clsx\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport {\n useGanttDependency,\n useGanttDragActive,\n useGanttScroll,\n type ConnectorHandle,\n} from \"../../../context/contexts\";\nimport { CONNECTOR_HANDLE_SIZE } from \"../../../core/constants\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../../core/slots\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport type { Id } from \"../../../types\";\nimport styles from \"./ConnectorHandles.module.css\";\n\nconst HANDLE_OFFSET = CONNECTOR_HANDLE_SIZE / 2;\n\n/** State passed to the function form of each ConnectorHandles slotProps. */\nexport interface ConnectorHandlesOwnerState {\n taskId: Id;\n barLeft: number;\n barWidth: number;\n barCenterY: number;\n show: boolean;\n isDragging: boolean;\n}\n\nexport interface ConnectorHandlesSlots {\n /** The left/start dependency-connector handle. Default: `\"div\"`. */\n startHandle?: ElementType;\n /** The right/end dependency-connector handle. Default: `\"div\"`. */\n endHandle?: ElementType;\n}\n\nexport interface ConnectorHandlesSlotProps {\n startHandle?: SlotPropsInput<ComponentProps<\"div\">, ConnectorHandlesOwnerState>;\n endHandle?: SlotPropsInput<ComponentProps<\"div\">, ConnectorHandlesOwnerState>;\n}\n\nexport type ConnectorHandlesSlotConfig = SlotConfig<\n ConnectorHandlesSlots,\n ConnectorHandlesSlotProps\n>;\n\ninterface ConnectorHandlesProps {\n taskId: Id;\n barLeft: number;\n barWidth: number;\n barCenterY: number;\n show: boolean;\n slots?: ConnectorHandlesSlots;\n slotProps?: ConnectorHandlesSlotProps;\n}\n\nexport function ConnectorHandles({\n taskId,\n barLeft,\n barWidth,\n barCenterY,\n show,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: ConnectorHandlesProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.bars?.connectorHandles?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.bars?.connectorHandles?.slotProps;\n\n const { startDrag, endDrag } = useGanttDependency();\n const isDragging = useGanttDragActive();\n const { gridBodyRef } = useGanttScroll();\n\n const getStartCoords = (e: React.MouseEvent, _handle: ConnectorHandle) => {\n const rect = gridBodyRef.current?.getBoundingClientRect();\n if (!rect) {\n return { x: 0, y: 0 };\n }\n const handleEl = e.currentTarget as HTMLElement;\n const hRect = handleEl.getBoundingClientRect();\n return {\n x: hRect.left + hRect.width / 2 - rect.left,\n y: hRect.top + hRect.height / 2 - rect.top,\n };\n };\n\n const onMouseDown = (e: React.MouseEvent, handle: ConnectorHandle) => {\n e.stopPropagation();\n e.preventDefault();\n const { x, y } = getStartCoords(e, handle);\n startDrag({ fromTaskId: taskId, handle, startX: x, startY: y, currentX: x, currentY: y });\n };\n\n const onMouseUp = (e: React.MouseEvent, handle: ConnectorHandle) => {\n if (isDragging) {\n e.stopPropagation();\n endDrag(taskId, handle);\n }\n };\n\n const ownerState: ConnectorHandlesOwnerState = {\n taskId,\n barLeft,\n barWidth,\n barCenterY,\n show,\n isDragging,\n };\n\n const StartHandle = slots?.startHandle ?? \"div\";\n const EndHandle = slots?.endHandle ?? \"div\";\n\n const isVisible = show || isDragging;\n\n const startHandleProps = mergeSlotProps(\n {\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.handle, isVisible && styles.visible),\n style: { left: barLeft - CONNECTOR_HANDLE_SIZE, top: barCenterY - HANDLE_OFFSET },\n onMouseDown: (e: React.MouseEvent) => onMouseDown(e, \"start\"),\n onMouseUp: (e: React.MouseEvent) => onMouseUp(e, \"start\"),\n },\n slotProps?.startHandle,\n ownerState,\n );\n\n const endHandleProps = mergeSlotProps(\n {\n \"aria-hidden\": true,\n tabIndex: -1,\n className: clsx(styles.handle, isVisible && styles.visible),\n style: { left: barLeft + barWidth, top: barCenterY - HANDLE_OFFSET },\n onMouseDown: (e: React.MouseEvent) => onMouseDown(e, \"end\"),\n onMouseUp: (e: React.MouseEvent) => onMouseUp(e, \"end\"),\n },\n slotProps?.endHandle,\n ownerState,\n );\n\n return (\n <>\n <StartHandle {...startHandleProps} />\n <EndHandle {...endHandleProps} />\n </>\n );\n}\n","/*\n * `position: absolute` + a non-auto `z-index` makes this a stacking context, so\n * a tooltip rendered inside it can never out-rank the sticky calendar (30) — the\n * row's own 3 is what competes. That is why the tooltip is placed to avoid the\n * header band rather than to paint over it (ADR-022).\n *\n * Do not add `transform`, `filter`, `contain`, `will-change` or `perspective`\n * here, to the grid, or to anything between them. Each establishes a containing\n * block for fixed-position descendants, and the tooltip is `position: fixed`\n * precisely so it escapes the grid's `overflow: auto` without a portal. Adding\n * one re-clips it silently, and no test can observe that.\n */\n.row {\n position: absolute;\n left: 0;\n right: 0;\n border-bottom: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n box-sizing: border-box;\n z-index: var(--am-gantt-task-bar-z-index, 3);\n}\n\n.row:last-child {\n border-bottom: none;\n}\n","import { memo, startTransition, useState } from \"react\";\nimport {\n type BarCommit,\n computeTaskPixels,\n type DatePatch,\n pxToDate,\n} from \"../../../core/barUtils\";\nimport { TASK_VERTICAL_PADDING } from \"../../../core/constants\";\nimport {\n useGanttLabels,\n useGanttReadOnly,\n useGanttSelectedId,\n useGanttWorkCalendar,\n} from \"../../../context/contexts\";\nimport { useGanttSlots } from \"../../../context/GanttSlotsContext\";\nimport { displayEndOf } from \"../../../core/taskDates\";\nimport type { CalendarUnit, GanttTask, Id, TaskState } from \"../../../types\";\nimport { MilestoneBar } from \"../milestoneBar/MilestoneBar\";\nimport { ProjectBar } from \"../projectBar/ProjectBar\";\nimport { TaskBar } from \"../taskBar/TaskBar\";\nimport type { BarTooltipOwnerState } from \"../barTooltip\";\nimport { ConnectorHandles } from \"./ConnectorHandles\";\nimport type { BarA11yProps } from \"./DraggableBar\";\nimport styles from \"./Row.module.css\";\n\ninterface RowProps {\n task: GanttTask;\n index: number;\n origin: Date;\n colWidth: number;\n rowHeight: number;\n unit: CalendarUnit;\n onUpdate: (id: Id, patch: DatePatch) => void;\n onCommit: (id: Id, commit: BarCommit) => void;\n override?: Partial<TaskState>;\n onOverride: (id: Id, patch: DatePatch | null) => void;\n onTaskClick?: (task: GanttTask) => void;\n rowIndexOffset: number;\n}\n\nexport const Row = memo(function Row({\n task,\n index,\n origin,\n colWidth,\n rowHeight,\n unit,\n override,\n onOverride,\n onUpdate,\n onCommit,\n onTaskClick,\n rowIndexOffset,\n}: RowProps) {\n const labels = useGanttLabels();\n const readOnly = useGanttReadOnly();\n const selectedId = useGanttSelectedId();\n const isSelected = selectedId === task.id;\n\n const schedulingContext = useGanttWorkCalendar();\n // Read only to decide whether to suppress the native `title` — that has to\n // happen where `a11y` is assembled, which is here. The tooltip itself is\n // rendered by the bar.\n const Tooltip = useGanttSlots().bars?.tooltip?.slots?.tooltip;\n\n const { left, width, progress } = computeTaskPixels(task, override || {}, origin, colWidth, unit);\n const top = index * rowHeight;\n const visualLeft = left;\n const barHeight = rowHeight - TASK_VERTICAL_PADDING * 2;\n const barCenterY = TASK_VERTICAL_PADDING + barHeight / 2;\n\n // The handles bracket the bar's *painted* box, which for a milestone is not\n // its date span. A milestone is an instant, so `computeTaskPixels` returns\n // width 0, while `MilestoneBar` paints a `barHeight`-square diamond centred on\n // `visualLeft` — mirrored from its own `centerLeft - size / 2`. Passing the raw\n // span put the start handle over the diamond's left half and the end handle\n // exactly on its centre, instead of outside it as on every other bar type.\n const isMilestone = task.type === \"milestone\";\n const handleLeft = isMilestone ? visualLeft - barHeight / 2 : visualLeft;\n const handleWidth = isMilestone ? barHeight - 1 : width;\n\n // Row-level hover, for the connector handles: they should appear as the\n // pointer approaches the bar. The tooltip's own hover lives in the bar\n // (DraggableBar), which is what renders it (ADR-022).\n const [hovered, setHovered] = useState(false);\n\n // `endDate` is exclusive (ADR-014), so the bar's right edge maps straight to it —\n // no day subtracted back off.\n const moveAt = (newLeft: number): DatePatch => ({\n startDate: pxToDate(newLeft, origin, colWidth, unit),\n endDate: pxToDate(newLeft + width, origin, colWidth, unit),\n });\n\n const resizeAt = (newWidth: number, newLeft: number): DatePatch => ({\n startDate: pxToDate(newLeft, origin, colWidth, unit),\n endDate: pxToDate(newLeft + newWidth, origin, colWidth, unit),\n });\n\n const handleOverride = (patch: DatePatch) => {\n onOverride(task.id, patch);\n };\n\n const handleUpdate = (id: Id, patch: DatePatch) => {\n startTransition(() => {\n onUpdate(id, patch);\n onOverride(id, null);\n });\n };\n\n // Commits carry INTENT, not the two dates the pixels happened to land on: a move\n // must preserve working time, which pixel width cannot express once a calendar\n // exists. Clearing the override unconditionally is also what makes a bar dropped\n // in non-working time visibly settle back — a commit that resolves to no change\n // schedules no log update, so the preview clear is the only thing in the\n // transition and the bar settles on the next render.\n const handleCommit = (commit: BarCommit) => {\n startTransition(() => {\n onCommit(task.id, commit);\n onOverride(task.id, null);\n });\n };\n\n const commitMoveAt = (newLeft: number): BarCommit => ({\n kind: \"move\",\n startDate: pxToDate(newLeft, origin, colWidth, unit),\n });\n\n // A read-only bar is handed no editing handlers at all, rather than handlers\n // that decline: each affordance (drag listener, resizer, progress handle)\n // renders only when its callbacks arrive, so omitting them removes the\n // affordance itself — nothing to grab, nothing to explain away.\n const moveHandlers = readOnly\n ? {}\n : {\n onMove: (newVisualLeft: number) => handleOverride(moveAt(newVisualLeft)),\n onMoveEnd: (newVisualLeft: number) => handleCommit(commitMoveAt(newVisualLeft)),\n };\n\n const progressHandlers = readOnly\n ? {}\n : {\n onProgressChange: (p: number) => handleOverride({ progress: p }),\n onProgressEnd: (p: number) => handleUpdate(task.id, { progress: p }),\n };\n\n const resizeHandlers = readOnly\n ? {}\n : {\n onResize: (newWidth: number, newVisualLeft: number) =>\n handleOverride(resizeAt(newWidth, newVisualLeft)),\n onResizeEnd: (edge: \"start\" | \"end\", edgePx: number) =>\n handleCommit(\n edge === \"start\"\n ? { kind: \"resizeStart\", startDate: pxToDate(edgePx, origin, colWidth, unit) }\n : { kind: \"resizeEnd\", endDate: pxToDate(edgePx, origin, colWidth, unit) },\n ),\n };\n\n // The native `title` is dropped when a tooltip slot is configured: the browser\n // tooltip would otherwise surface on top of the custom one. `aria-label` is\n // untouched, so the accessible name is the same either way — which is also why\n // dropping it is safe with a hover-only tooltip (ADR-022).\n const a11y: BarA11yProps = {\n role: \"gridcell\",\n \"aria-colindex\": Math.max(1, Math.floor(visualLeft / colWidth) + 1),\n \"aria-colspan\": Math.max(1, Math.round(width / colWidth)),\n \"aria-label\": labels.bar(task, { progress }),\n \"aria-selected\": isSelected || undefined,\n title: Tooltip ? undefined : task.name,\n };\n\n // Data only — nothing here says whether the tooltip is showing, because that is\n // the slot's own state (ADR-022). `progress` is override-aware during a drag,\n // and `displayEnd` is inclusive (ADR-014) so no consumer rediscovers that\n // `task.endDate` is exclusive.\n const tooltipData: BarTooltipOwnerState = {\n task,\n progress,\n displayEnd: displayEndOf(task, schedulingContext),\n };\n\n return (\n <div\n className={styles.row}\n style={{ top, height: rowHeight }}\n onClick={onTaskClick ? () => onTaskClick(task) : undefined}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n role=\"row\"\n aria-rowindex={rowIndexOffset + index + 1}\n >\n {!readOnly && (\n <ConnectorHandles\n taskId={task.id}\n barLeft={handleLeft}\n barWidth={handleWidth}\n barCenterY={barCenterY}\n show={hovered}\n />\n )}\n\n {task.type === \"milestone\" && (\n <MilestoneBar\n tooltip={tooltipData}\n size={barHeight}\n centerLeft={visualLeft}\n top={TASK_VERTICAL_PADDING}\n colWidth={colWidth}\n title={task.name}\n a11y={a11y}\n {...moveHandlers}\n />\n )}\n {task.type === \"summary\" && (\n <ProjectBar\n tooltip={tooltipData}\n left={visualLeft}\n top={TASK_VERTICAL_PADDING}\n width={width}\n height={barHeight}\n colWidth={colWidth}\n title={task.name}\n a11y={a11y}\n progress={progress}\n {...progressHandlers}\n {...moveHandlers}\n />\n )}\n {task.type === \"task\" || !task.type ? (\n <TaskBar\n tooltip={tooltipData}\n left={visualLeft}\n top={TASK_VERTICAL_PADDING}\n width={width}\n height={barHeight}\n colWidth={colWidth}\n title={task.name}\n a11y={a11y}\n progress={progress}\n {...progressHandlers}\n {...moveHandlers}\n {...resizeHandlers}\n />\n ) : null}\n </div>\n );\n});\n\nRow.displayName = \"Row\";\n","import { computeTaskPixels } from \"../../core/barUtils\";\nimport { TASK_VERTICAL_PADDING } from \"../../core/constants\";\nimport type {\n CalendarUnit,\n GanttTask,\n Id,\n TaskDependency,\n TaskDependencyType,\n TaskState,\n} from \"../../types\";\n\n/** Length of the horizontal stub that leaves a bar before the link turns. */\nconst STUB = 12;\n\n/** Shared \"no override\" argument, so the base pass allocates nothing per task. */\nconst EMPTY_STATE: Partial<TaskState> = {};\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface DependencyLink {\n /** Stable key, e.g. `\"1->2\"`. */\n id: string;\n type: TaskDependencyType;\n /** Orthogonal polyline from the source edge to the target edge. */\n points: Point[];\n /** Bounding box of {@link DependencyLink.points}, precomputed for culling. */\n bounds: Bounds;\n /** The original dependency for callbacks. */\n dep: TaskDependency;\n}\n\n/** Axis-aligned pixel bounds. */\nexport interface Bounds {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n}\n\n/** Bounding box of a polyline, for viewport culling. */\nexport function linkBounds(points: Point[]): Bounds {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of points) {\n if (p.x < minX) {\n minX = p.x;\n }\n if (p.x > maxX) {\n maxX = p.x;\n }\n if (p.y < minY) {\n minY = p.y;\n }\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n return { minX, minY, maxX, maxY };\n}\n\n/** Midpoint of the middle segment of a polyline. */\nexport function midpoint(points: Point[]): Point {\n if (points.length < 2) {\n return points[0] ?? { x: 0, y: 0 };\n }\n const mid = Math.floor((points.length - 1) / 2);\n const a = points[mid]!;\n const b = points[mid + 1]!;\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n}\n\n/**\n * Pixel-space bounds of a single bar: its left/right edges and vertical center.\n *\n * Carries the `task` it was built from so a re-route can rebuild the box against\n * a drag override without a second id → task index (see {@link reRouteOverrides}).\n */\ninterface Box {\n startX: number;\n endX: number;\n centerY: number;\n task: GanttTask;\n}\n\n/** Pixel geometry inputs shared by the base pass and any later re-route. */\ninterface PixelParams {\n origin: Date;\n colWidth: number;\n rowHeight: number;\n unit: CalendarUnit;\n}\n\n/**\n * One task's pixel box at row centre `centerY`.\n *\n * x-coordinates come from {@link computeTaskPixels}, the same source the bars\n * use, so links stay glued to bar edges. Shared by the base pass and the\n * override re-route so the two can never drift apart.\n */\nfunction boxOf(\n task: GanttTask,\n state: Partial<TaskState>,\n centerY: number,\n { origin, colWidth, rowHeight, unit }: PixelParams,\n): Box {\n const { left, width } = computeTaskPixels(task, state, origin, colWidth, unit);\n if (task.type === \"milestone\") {\n // Milestones render as a diamond centered on `left`.\n const half = (rowHeight - TASK_VERTICAL_PADDING * 2) / 2;\n return { startX: left - half, endX: left + half, centerY, task };\n }\n return { startX: left, endX: left + width, centerY, task };\n}\n\n/**\n * Build a lookup of every task's pixel bounds. The y-coordinate is derived from\n * the task's row index — the visual order of `tasks` maps 1:1 to grid rows.\n */\nfunction buildBoxes(tasks: GanttTask[], params: PixelParams): Map<Id, Box> {\n const boxes = new Map<Id, Box>();\n const { rowHeight } = params;\n tasks.forEach((task, index) => {\n boxes.set(task.id, boxOf(task, EMPTY_STATE, index * rowHeight + rowHeight / 2, params));\n });\n return boxes;\n}\n\n/**\n * \"Staircase\" route: source edge points toward the target, so a single vertical\n * mid-segment connects the two horizontal runs. Used when the target edge sits\n * far enough ahead in the travel direction; otherwise we wrap (see `wrap`).\n */\nfunction staircase(s: Point, t: Point): Point[] {\n const midX = (s.x + t.x) / 2;\n return [s, { x: midX, y: s.y }, { x: midX, y: t.y }, t];\n}\n\n/**\n * \"Wrap\" route for when the target edge is behind the source's exit direction:\n * exit by a stub, drop to the mid-row, run across, then approach the target.\n */\nfunction wrap(s: Point, t: Point, sDir: number, tDir: number): Point[] {\n const ox = s.x + sDir * STUB; // source stub end\n const ix = t.x - tDir * STUB; // target stub start\n const midY = (s.y + t.y) / 2;\n return [s, { x: ox, y: s.y }, { x: ox, y: midY }, { x: ix, y: midY }, { x: ix, y: t.y }, t];\n}\n\n/**\n * \"L\" route for same-edge relationships (SS / FF): exit horizontally just past\n * the outermost of the two edges, drop straight to the target's row, then run\n * back in to the target edge. No backtracking past the bar.\n */\nfunction lShape(s: Point, t: Point, xv: number): Point[] {\n return [s, { x: xv, y: s.y }, { x: xv, y: t.y }, t];\n}\n\n/** Build the polyline for one dependency from the two bars' pixel bounds. */\nfunction routeLink(type: TaskDependencyType, from: Box, to: Box): Point[] {\n const sy = from.centerY;\n const ty = to.centerY;\n\n switch (type) {\n case \"FS\": {\n // finish → start: exit the source's right edge, enter the target's left.\n const s: Point = { x: from.endX, y: sy };\n const t: Point = { x: to.startX, y: ty };\n return to.startX >= from.endX + 2 * STUB ? staircase(s, t) : wrap(s, t, 1, 1);\n }\n case \"SS\": {\n // start ⇉ start: both exit left; drop at the leftmost edge, run in right.\n const s: Point = { x: from.startX, y: sy };\n const t: Point = { x: to.startX, y: ty };\n return lShape(s, t, Math.min(from.startX, to.startX) - STUB);\n }\n case \"FF\": {\n // finish ⇄ finish: both exit right; drop at the rightmost edge, run in left.\n const s: Point = { x: from.endX, y: sy };\n const t: Point = { x: to.endX, y: ty };\n return lShape(s, t, Math.max(from.endX, to.endX) + STUB);\n }\n case \"SF\": {\n // start → finish: exit the source's left edge, enter the target's right.\n const s: Point = { x: from.startX, y: sy };\n const t: Point = { x: to.endX, y: ty };\n return to.endX <= from.startX - 2 * STUB ? staircase(s, t) : wrap(s, t, -1, -1);\n }\n }\n}\n\nexport interface DependencyLinkParams extends PixelParams {\n tasks: GanttTask[];\n dependencies: TaskDependency[];\n}\n\n/**\n * The base geometry pass, plus the per-task boxes it was built from.\n *\n * Keeping the boxes is what makes a drag cheap: {@link reRouteOverrides} rebuilds\n * only the handful of links touching the dragged task instead of re-deriving all\n * of them (at 100k tasks / 84k links the full pass is ~100ms — far too slow to\n * repeat on every mousemove).\n */\nexport interface LinkGeometry {\n links: DependencyLink[];\n boxes: Map<Id, Box>;\n /**\n * Indices into `links` of every link touching a task, keyed by `String(id)` so\n * it can be queried straight from an overrides object's keys. Built on first\n * use — a chart that is never dragged never pays for it.\n */\n linksTouching(key: string): number[] | undefined;\n}\n\n/**\n * Compute the polyline geometry for every dependency, at each task's committed\n * position. Dependencies whose endpoints are not present in `tasks` are skipped.\n *\n * `lag` is intentionally not drawn: the gap it implies is already baked into\n * each task's scheduled dates, and therefore into the bar edges we connect.\n */\nexport function computeLinkGeometry({\n tasks,\n dependencies,\n ...params\n}: DependencyLinkParams): LinkGeometry {\n const boxes = buildBoxes(tasks, params);\n const links: DependencyLink[] = [];\n\n for (const dep of dependencies) {\n const from = boxes.get(dep.from);\n const to = boxes.get(dep.to);\n if (!from || !to) {\n continue;\n }\n links.push(linkOf(dep, from, to));\n }\n\n // Lazy, and owned by this result: the index is only worth building once a drag\n // starts re-routing, and it stays valid for exactly as long as `links` does.\n let byTask: Map<string, number[]> | null = null;\n return {\n links,\n boxes,\n linksTouching(key) {\n byTask ??= buildTouchIndex(links);\n return byTask.get(key);\n },\n };\n}\n\n/** One link between two known boxes. Bounds are baked in for viewport culling. */\nfunction linkOf(dep: TaskDependency, from: Box, to: Box): DependencyLink {\n // Bounds are computed here, not at render time: the renderer culls on every\n // scroll frame, and the geometry it culls against only changes when the\n // geometry itself is rebuilt.\n const points = routeLink(dep.type, from, to);\n return { id: `${dep.from}->${dep.to}`, type: dep.type, points, bounds: linkBounds(points), dep };\n}\n\n/** task key → indices of the links that start or end at it. */\nfunction buildTouchIndex(links: DependencyLink[]): Map<string, number[]> {\n const index = new Map<string, number[]>();\n const add = (key: string, i: number): void => {\n const list = index.get(key);\n if (list) {\n list.push(i);\n } else {\n index.set(key, [i]);\n }\n };\n links.forEach((link, i) => {\n add(String(link.dep.from), i);\n add(String(link.dep.to), i);\n });\n return index;\n}\n\n/**\n * Re-route only the links touching a task with a live drag override, reusing\n * every other link object from `base` untouched.\n *\n * This runs on every mousemove of a bar drag, so the work is bounded by the\n * dragged task's own edges, not the link count. Overrides are keyed by\n * `String(id)` because they arrive as an object literal, where a numeric `Id`\n * has already been stringified.\n */\nexport function reRouteOverrides(\n base: LinkGeometry,\n overrides: Record<string, Partial<TaskState>>,\n params: PixelParams,\n): DependencyLink[] {\n const keys = Object.keys(overrides);\n if (keys.length === 0) {\n return base.links;\n }\n const patched = new Map<Id, Box>();\n\n // Rebuild an overridden task's box on demand, keyed by its real `Id` — a drag\n // moves the bar horizontally only, so the row centre carries over.\n const boxFor = (id: Id): Box | undefined => {\n const box = base.boxes.get(id);\n const override = box && overrides[String(id)];\n if (!box || !override) {\n return box;\n }\n let next = patched.get(id);\n if (!next) {\n next = boxOf(box.task, override, box.centerY, params);\n patched.set(id, next);\n }\n return next;\n };\n\n let next: DependencyLink[] | null = null;\n for (const key of keys) {\n for (const i of base.linksTouching(key) ?? []) {\n const { dep } = base.links[i]!;\n const from = boxFor(dep.from);\n const to = boxFor(dep.to);\n if (!from || !to) {\n continue;\n }\n next ??= base.links.slice();\n next[i] = linkOf(dep, from, to);\n }\n }\n return next ?? base.links;\n}\n","import { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { CalendarUnit, GanttTask, TaskDependency, TaskState } from \"../../types\";\nimport { computeLinkGeometry, reRouteOverrides, type DependencyLink } from \"./geometry\";\n\nconst DependencyLinksContext = createContext<DependencyLink[] | null>(null);\n\ninterface DependencyLinksProviderProps {\n tasks: GanttTask[];\n dependencies: TaskDependency[];\n origin: Date;\n colWidth: number;\n rowHeight: number;\n unit: CalendarUnit;\n children: ReactNode;\n overrides: Record<string, Partial<TaskState>>;\n}\n\n/**\n * Computes dependency-link geometry once and exposes it to descendants. Keeping\n * the links in context lets the renderer (and any future consumers, e.g.\n * hover-highlighting) read them without re-deriving the geometry.\n *\n * Split in two on purpose. `overrides` churns on every mousemove of a bar drag,\n * while everything the base pass reads is stable for the whole gesture — so the\n * expensive pass (every task's box, every link's route) is kept off the drag\n * path, and each frame only re-routes the links touching the dragged bar.\n */\nexport function DependencyLinksProvider({\n tasks,\n dependencies,\n origin,\n colWidth,\n rowHeight,\n unit,\n children,\n overrides,\n}: DependencyLinksProviderProps) {\n const base = useMemo(\n () => computeLinkGeometry({ tasks, dependencies, origin, colWidth, rowHeight, unit }),\n [tasks, dependencies, origin, colWidth, rowHeight, unit],\n );\n\n const links = useMemo(\n () => reRouteOverrides(base, overrides, { origin, colWidth, rowHeight, unit }),\n [base, overrides, origin, colWidth, rowHeight, unit],\n );\n\n return (\n <DependencyLinksContext.Provider value={links}>{children}</DependencyLinksContext.Provider>\n );\n}\n\n/** Read the computed dependency links from context. */\nexport function useDependencyLinks(): DependencyLink[] {\n const links = useContext(DependencyLinksContext);\n if (links === null) {\n throw new Error(\"useDependencyLinks must be used within a <DependencyLinksProvider>\");\n }\n return links;\n}\n",".layer {\n position: absolute;\n inset: 0;\n z-index: var(--am-gantt-links-z-index, 2);\n pointer-events: none;\n}\n\n.hitArea {\n position: absolute;\n background: transparent;\n pointer-events: auto;\n cursor: pointer;\n}\n\n.segment {\n position: absolute;\n background: var(--am-gantt-dependency-color, #94a3b8);\n pointer-events: none;\n}\n\n.segmentSelected {\n background: #ef4444;\n}\n\n.arrowRight,\n.arrowLeft {\n position: absolute;\n width: 0;\n height: 0;\n border-top: 4px solid transparent;\n border-bottom: 4px solid transparent;\n pointer-events: none;\n}\n\n.arrowRight {\n border-left: 8px solid var(--am-gantt-dependency-color, #94a3b8);\n}\n\n.arrowLeft {\n border-right: 8px solid var(--am-gantt-dependency-color, #94a3b8);\n}\n\n.arrowSelected.arrowRight {\n border-left-color: #ef4444;\n}\n\n.arrowSelected.arrowLeft {\n border-right-color: #ef4444;\n}\n\n.lagLabel {\n position: absolute;\n background: var(--am-gantt-grid-bg, #ffffff);\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-radius: 3px;\n font-size: 11px;\n padding: 1px 4px;\n pointer-events: none;\n transform: translate(-50%, -100%);\n white-space: nowrap;\n color: var(--am-gantt-dependency-color, #94a3b8);\n line-height: 1.4;\n}\n\n.deleteBtn {\n position: absolute;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n border: 1px solid #ef4444;\n background: #fff;\n color: #ef4444;\n font-size: 16px;\n line-height: 1;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: auto;\n transform: translate(-50%, -50%);\n z-index: 10;\n padding: 0;\n}\n\n.deleteBtn:hover {\n background: #ef4444;\n color: #fff;\n}\n","import { Fragment, useEffect, useState, type ComponentProps, type ElementType } from \"react\";\nimport { useDependencyLinks } from \"./DependencyLinksContext\";\nimport { midpoint, type Bounds, type DependencyLink, type Point } from \"./geometry\";\nimport type { TaskDependency } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport { useGanttLabels, useGanttReadOnly } from \"../../context/contexts\";\nimport styles from \"./DependencyLinks.module.css\";\n\n/** Stroke thickness of the link, in pixels. */\nconst THICKNESS = 2;\n/** Side length of the arrowhead, in pixels. */\nconst ARROW = 8;\n/** Transparent hit-area padding around each segment, in pixels. */\nconst HIT_PADDING = 6;\n\n/** State passed to the function form of the `layer` slotProps. */\nexport interface DependencyLinksLayerOwnerState {\n width: number;\n height: number;\n /** Number of dependency links currently in the layer. */\n linkCount: number;\n}\n\n/** State shared by the per-link slots (`arrow`). */\nexport interface DependencyLinkOwnerState {\n /** The dependency link being rendered. */\n link: DependencyLink;\n /** Whether this link is currently selected. */\n isSelected: boolean;\n}\n\n/** State passed to the `segment` slotProps, per visible segment of a link. */\nexport interface DependencySegmentOwnerState extends DependencyLinkOwnerState {\n /** Start point of this segment. */\n from: Point;\n /** End point of this segment. */\n to: Point;\n /** Index of this segment within the link's polyline. */\n index: number;\n}\n\n/** State passed to the `lagLabel` slotProps. */\nexport interface DependencyLagLabelOwnerState extends DependencyLinkOwnerState {\n /** The lag value in days (non-zero when the label renders). */\n lag: number;\n}\n\n/** State passed to the `deleteButton` slotProps. */\nexport interface DependencyDeleteButtonOwnerState {\n /** The dependency the button will delete when clicked. */\n dependency: TaskDependency;\n}\n\nexport interface DependencyLinksSlots {\n /** The absolutely-positioned links layer container. Default: `\"div\"`. */\n layer?: ElementType;\n /** A single visible link segment. Default: `\"div\"`. */\n segment?: ElementType;\n /** The arrowhead at the target end of a link. Default: `\"div\"`. */\n arrow?: ElementType;\n /** The `+Nd` / `-Nd` lag label. Default: `\"div\"`. */\n lagLabel?: ElementType;\n /** The `×` delete button shown for the selected link. Default: `\"button\"`. */\n deleteButton?: ElementType;\n}\n\nexport interface DependencyLinksSlotProps {\n layer?: SlotPropsInput<ComponentProps<\"div\">, DependencyLinksLayerOwnerState>;\n segment?: SlotPropsInput<ComponentProps<\"div\">, DependencySegmentOwnerState>;\n arrow?: SlotPropsInput<ComponentProps<\"div\">, DependencyLinkOwnerState>;\n lagLabel?: SlotPropsInput<ComponentProps<\"div\">, DependencyLagLabelOwnerState>;\n deleteButton?: SlotPropsInput<ComponentProps<\"button\">, DependencyDeleteButtonOwnerState>;\n}\n\n/** Slot config for the dependency links layer. */\nexport type DependencyLinksSlotConfig = SlotConfig<DependencyLinksSlots, DependencyLinksSlotProps>;\n\ninterface DependencyLinksProps {\n width: number;\n height: number;\n onDependencyDelete?: (dep: TaskDependency) => void;\n /** Overscan-padded visible pixel rect; links outside it are not rendered. */\n visibleRect?: Bounds;\n slots?: DependencyLinksSlots;\n slotProps?: DependencyLinksSlotProps;\n}\n\n/** True when a link's bounding box overlaps the visible rect (or no rect set). */\nfunction linkInView(b: Bounds, rect: Bounds | undefined): boolean {\n if (!rect) {\n return true;\n }\n return b.minX <= rect.maxX && b.maxX >= rect.minX && b.minY <= rect.maxY && b.maxY >= rect.minY;\n}\n\n/** One straight segment as an absolutely-positioned box. */\nfunction segmentStyle(a: Point, b: Point): React.CSSProperties {\n if (a.y === b.y) {\n return {\n left: Math.min(a.x, b.x) - THICKNESS / 2,\n top: a.y - THICKNESS / 2,\n width: Math.abs(b.x - a.x) + THICKNESS,\n height: THICKNESS,\n };\n }\n return {\n left: a.x - THICKNESS / 2,\n top: Math.min(a.y, b.y) - THICKNESS / 2,\n width: THICKNESS,\n height: Math.abs(b.y - a.y) + THICKNESS,\n };\n}\n\n/** Wider transparent hit-area div for the same segment. */\nfunction hitAreaStyle(a: Point, b: Point): React.CSSProperties {\n if (a.y === b.y) {\n return {\n left: Math.min(a.x, b.x) - THICKNESS / 2,\n top: a.y - HIT_PADDING,\n width: Math.abs(b.x - a.x) + THICKNESS,\n height: THICKNESS + HIT_PADDING * 2,\n };\n }\n return {\n left: a.x - HIT_PADDING,\n top: Math.min(a.y, b.y) - THICKNESS / 2,\n width: THICKNESS + HIT_PADDING * 2,\n height: Math.abs(b.y - a.y) + THICKNESS,\n };\n}\n\nfunction segments(points: Point[]): Array<[Point, Point]> {\n const pairs: Array<[Point, Point]> = [];\n for (let i = 0; i + 1 < points.length; i++) {\n pairs.push([points[i]!, points[i + 1]!]);\n }\n return pairs;\n}\n\nfunction arrow(points: Point[]) {\n const tip = points[points.length - 1]!;\n const prev = points[points.length - 2]!;\n const pointsRight = tip.x >= prev.x;\n return {\n className: pointsRight ? styles.arrowRight : styles.arrowLeft,\n style: {\n left: pointsRight ? tip.x - ARROW : tip.x,\n top: tip.y - ARROW / 2,\n } as React.CSSProperties,\n };\n}\n\nexport function DependencyLinks({\n width,\n height,\n onDependencyDelete,\n visibleRect,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: DependencyLinksProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.dependencies?.links?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.dependencies?.links?.slotProps;\n const labels = useGanttLabels();\n // A read-only chart drops the hit areas, so no link can become selected —\n // which is also what keeps the Delete/Backspace shortcut below unreachable.\n const readOnly = useGanttReadOnly();\n\n const links = useDependencyLinks();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [deletePos, setDeletePos] = useState<{ x: number; y: number } | null>(null);\n\n const selectedLink = selectedId ? links.find((l) => l.id === selectedId) : null;\n\n useEffect(() => {\n if (!selectedId) {\n return;\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Delete\" || e.key === \"Backspace\") {\n if (selectedLink) {\n onDependencyDelete?.(selectedLink.dep);\n }\n setSelectedId(null);\n setDeletePos(null);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [selectedId, selectedLink, onDependencyDelete]);\n\n if (links.length === 0) {\n return null;\n }\n\n const handleLinkClick = (id: string, e: React.MouseEvent) => {\n e.stopPropagation();\n if (selectedId === id) {\n setSelectedId(null);\n setDeletePos(null);\n } else {\n setSelectedId(id);\n const layer = (e.currentTarget as HTMLElement).closest(`.${styles.layer}`);\n const rect = layer?.getBoundingClientRect();\n setDeletePos(rect ? { x: e.clientX - rect.left, y: e.clientY - rect.top } : null);\n }\n };\n\n const handleDelete = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (selectedLink) {\n onDependencyDelete?.(selectedLink.dep);\n }\n setSelectedId(null);\n setDeletePos(null);\n };\n\n const Layer = slots?.layer ?? \"div\";\n const Segment = slots?.segment ?? \"div\";\n const Arrow = slots?.arrow ?? \"div\";\n const LagLabel = slots?.lagLabel ?? \"div\";\n const DeleteButton = slots?.deleteButton ?? \"button\";\n const layerProps = mergeSlotProps(\n {\n className: styles.layer,\n style: { width, height },\n role: \"presentation\",\n \"aria-hidden\": true,\n onClick: () => {\n setSelectedId(null);\n setDeletePos(null);\n },\n },\n slotProps?.layer,\n { width, height, linkCount: links.length },\n );\n\n return (\n <Layer {...layerProps}>\n {links.map((link) => {\n const isSelected = link.id === selectedId;\n if (!isSelected && !linkInView(link.bounds, visibleRect)) {\n return null;\n }\n const head = arrow(link.points);\n const segs = segments(link.points);\n const mid = link.dep.lag ? midpoint(link.points) : null;\n const linkOwnerState: DependencyLinkOwnerState = { link, isSelected };\n\n const arrowProps = mergeSlotProps(\n {\n className: `${head.className} ${isSelected ? styles.arrowSelected : \"\"}`,\n style: head.style,\n },\n slotProps?.arrow,\n linkOwnerState,\n );\n\n return (\n <Fragment key={link.id}>\n {/* Transparent hit-area divs to capture clicks */}\n {!readOnly &&\n segs.map(([a, b]) => (\n <div\n key={`hit-${a.x},${a.y}-${b.x},${b.y}`}\n className={styles.hitArea}\n style={hitAreaStyle(a, b)}\n onClick={(e) => handleLinkClick(link.id, e)}\n />\n ))}\n {/* Visible segments */}\n {segs.map(([a, b], index) => {\n const segmentProps = mergeSlotProps(\n {\n className: `${styles.segment} ${isSelected ? styles.segmentSelected : \"\"}`,\n style: segmentStyle(a, b),\n },\n slotProps?.segment,\n { link, isSelected, from: a, to: b, index },\n );\n return <Segment key={`seg-${a.x},${a.y}-${b.x},${b.y}`} {...segmentProps} />;\n })}\n <Arrow {...arrowProps} />\n\n {/* Lag label */}\n {mid && link.dep.lag !== undefined && link.dep.lag !== 0 && (\n <LagLabel\n {...mergeSlotProps(\n {\n className: styles.lagLabel,\n style: { left: mid.x, top: mid.y },\n children: link.dep.lag > 0 ? `+${link.dep.lag}d` : `${link.dep.lag}d`,\n },\n slotProps?.lagLabel,\n { link, isSelected, lag: link.dep.lag },\n )}\n />\n )}\n </Fragment>\n );\n })}\n\n {!readOnly && selectedLink && deletePos && (\n <DeleteButton\n {...mergeSlotProps(\n {\n className: styles.deleteBtn,\n type: \"button\",\n tabIndex: -1,\n style: { left: deletePos.x, top: deletePos.y },\n onClick: handleDelete,\n \"aria-label\": labels.deleteDependency,\n children: \"×\",\n },\n slotProps?.deleteButton,\n { dependency: selectedLink.dep },\n )}\n />\n )}\n </Layer>\n );\n}\n",".preview {\n position: absolute;\n height: 2px;\n background: repeating-linear-gradient(\n to right,\n #3b82f6 0px,\n #3b82f6 6px,\n transparent 6px,\n transparent 12px\n );\n transform-origin: left center;\n pointer-events: none;\n z-index: 20;\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { useGanttDependencyDrag } from \"../../context/contexts\";\nimport type { DependencyDragState } from \"../../hooks/useDependencyDrag\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport styles from \"./DependencyPreview.module.css\";\n\n/** State passed to the function form of the `root` slotProps. */\nexport interface DependencyPreviewOwnerState {\n /** The in-progress dependency drag. */\n drag: DependencyDragState;\n /** Horizontal length of the rubber-band, in pixels. */\n length: number;\n /** Rotation of the rubber-band, in degrees. */\n angle: number;\n}\n\nexport interface DependencyPreviewSlots {\n /** The rubber-band preview line. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface DependencyPreviewSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, DependencyPreviewOwnerState>;\n}\n\n/** Slot config for the dependency drag preview. */\nexport type DependencyPreviewSlotConfig = SlotConfig<\n DependencyPreviewSlots,\n DependencyPreviewSlotProps\n>;\n\ninterface DependencyPreviewProps {\n slots?: DependencyPreviewSlots;\n slotProps?: DependencyPreviewSlotProps;\n}\n\nexport function DependencyPreview({\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: DependencyPreviewProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.dependencies?.preview?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.dependencies?.preview?.slotProps;\n\n const drag = useGanttDependencyDrag();\n if (!drag) {\n return null;\n }\n\n const dx = drag.currentX - drag.startX;\n const dy = drag.currentY - drag.startY;\n const length = Math.hypot(dx, dy);\n const angle = Math.atan2(dy, dx) * (180 / Math.PI);\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.preview,\n style: {\n left: drag.startX,\n top: drag.startY,\n width: length,\n transform: `rotate(${angle}deg)`,\n },\n \"aria-hidden\": true,\n },\n slotProps?.root,\n { drag, length, angle },\n );\n\n return <Root {...rootProps} />;\n}\n",".cols {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n.col {\n position: absolute;\n top: 0;\n box-sizing: border-box;\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n}\n\n.colWeekend {\n background: var(--am-gantt-calendar-weekend-bg, #f1f5f9);\n}\n","import { clsx } from \"clsx\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { addUnit, isWeekend } from \"../../core/dateUtils\";\nimport { nonWorkingInfo, type NonWorkingReason } from \"../../core/workingTime\";\nimport { useGanttWorkCalendar } from \"../../context/contexts\";\nimport type { CalendarUnit } from \"../../types\";\nimport type { IndexRange } from \"../../core/virtualize\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport styles from \"./GridColumns.module.css\";\n\n/** State passed to the function form of the GridColumns `column` slotProps (per day). */\nexport interface GridColumnOwnerState {\n /** The day this column paints. */\n date: Date;\n /** Absolute date-column index. */\n index: number;\n /**\n * Whether the calendar excludes this column from working time. Prefer this over\n * {@link GridColumnOwnerState.isWeekend} — it also covers holidays and, at hour\n * scale, off-hours.\n */\n isNonWorking: boolean;\n /** Why the column is non-working, for styling weekends and holidays apart. */\n nonWorkingReason?: NonWorkingReason;\n /**\n * @deprecated Use {@link GridColumnOwnerState.isNonWorking}. Retained as an\n * alias so existing slot code keeps working; it is now true for any\n * non-working column, not only Saturday and Sunday.\n */\n isWeekend: boolean;\n colWidth: number;\n bodyHeight: number;\n}\n\nexport interface GridColumnsSlots {\n /** A per-day background column. Default: `\"div\"`. */\n column?: ElementType;\n}\n\nexport interface GridColumnsSlotProps {\n column?: SlotPropsInput<ComponentProps<\"div\">, GridColumnOwnerState>;\n}\n\n/**\n * Slot config for the grid background columns. Pass via the grid's slot props.\n *\n * NOTE: pass a referentially stable / memoized object so downstream memoization\n * is not defeated by a fresh object each render.\n */\nexport type GridColumnsSlotConfig = SlotConfig<GridColumnsSlots, GridColumnsSlotProps>;\n\ninterface GridColumnsProps {\n dates: Date[];\n colWidth: number;\n bodyHeight: number;\n /** Half-open range of date indices to render (virtualization window). */\n colRange: IndexRange;\n /** Column unit. Non-working shading only applies at day scale or finer. */\n unit?: CalendarUnit;\n /** Units per column, so a column's full time span can be measured. */\n step?: number;\n slots?: GridColumnsSlots;\n slotProps?: GridColumnsSlotProps;\n}\n\n/**\n * Background layer that paints one vertical column per day, shading weekends.\n * Purely decorative — `aria-hidden` and non-interactive. Only the columns\n * inside `colRange` are rendered; each is absolutely positioned at its date\n * offset so the windowed subset still aligns with the full-width grid.\n */\nexport function GridColumns({\n dates,\n colWidth,\n bodyHeight,\n colRange,\n unit = \"day\",\n step = 1,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: GridColumnsProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.gridColumn?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.gridColumn?.slotProps;\n\n const Column = slots?.column ?? \"div\";\n const { calendar } = useGanttWorkCalendar();\n // Shading is meaningless on a week-or-coarser column: it is partly working by\n // construction, so painting the whole thing would be wrong.\n const shadeable = unit === \"day\" || unit === \"hour\" || unit === \"minute\";\n\n return (\n <div className={styles.cols} role=\"presentation\" aria-hidden>\n {dates.slice(colRange.start, colRange.end).map((date, i) => {\n const index = colRange.start + i;\n const info = shadeable\n ? nonWorkingInfo(calendar, date, addUnit(date, unit, step))\n : { isNonWorking: false, reason: undefined };\n // With no calendar, keep the historical Sat/Sun-only behaviour exactly.\n const nonWorking = calendar ? info.isNonWorking : unit === \"day\" && isWeekend(date);\n const ownerState: GridColumnOwnerState = {\n date,\n index,\n isNonWorking: nonWorking,\n nonWorkingReason: nonWorking ? (info.reason ?? \"weekend\") : undefined,\n isWeekend: nonWorking,\n colWidth,\n bodyHeight,\n };\n const columnProps = mergeSlotProps(\n {\n className: clsx(styles.col, nonWorking && styles.colWeekend),\n style: {\n left: index * colWidth,\n width: colWidth,\n height: bodyHeight,\n },\n },\n slotProps?.column,\n ownerState,\n );\n // Keyed by instant, not ISO string: the dates are distinct by\n // construction and this runs for every column on every scroll frame.\n return <Column key={date.getTime()} {...columnProps} />;\n })}\n </div>\n );\n}\n\nGridColumns.displayName = \"GridColumns\";\n",".gridWrapper {\n overflow-x: auto;\n overflow-y: auto;\n flex: 1 1 auto;\n min-width: 0;\n /* No rubber-band bounce / scroll chaining to the page (macOS, iOS). */\n overscroll-behavior: none;\n}\n\n.grid {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: inherit;\n}\n\n.body {\n position: relative;\n background: var(--am-gantt-grid-bg, #ffffff);\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-top: none;\n border-bottom-left-radius: var(--am-gantt-calendar-radius, 6px);\n border-bottom-right-radius: var(--am-gantt-calendar-radius, 6px);\n overflow: hidden;\n box-sizing: border-box;\n}\n","/**\n * Framework-agnostic windowing math for virtualized rendering. Given a scroll\n * `offset`, a `viewSize` (viewport extent), a fixed `itemSize`, and a total\n * `itemCount`, return the half-open index range `[start, end)` of items that\n * intersect the viewport, widened by `overscan` items on each side.\n *\n * Works for either axis (rows: pass scrollTop/clientHeight/rowHeight, or\n * columns: scrollLeft/clientWidth/colWidth). Pure — no DOM or framework\n * dependency. Mirrors the shape of `scrollOffsetToReveal` in `scroll.ts`.\n *\n * When `viewSize <= 0` the viewport hasn't been measured yet (first commit),\n * so we render a bounded window of the first `UNMEASURED_FALLBACK_COUNT`\n * items. Rendering everything here would make mounting a large dataset pay a\n * full unvirtualized commit (10k tasks ≈ tens of seconds) that is thrown away\n * one frame later; rendering the capped window is never visible as a flash,\n * because the real metrics arrive via `useLayoutEffect` and re-render before\n * the browser paints. The cap also keeps jsdom (client sizes always 0)\n * rendering enough rows for component tests. `itemSize <= 0` is treated the\n * same way.\n */\nimport { UNMEASURED_FALLBACK_COUNT } from \"./constants\";\n\nexport interface IndexRange {\n /** First visible item index (inclusive). */\n start: number;\n /** One past the last visible item index (exclusive). */\n end: number;\n}\n\nexport function rangeFromOffset(\n offset: number,\n viewSize: number,\n itemSize: number,\n itemCount: number,\n overscan = 0,\n): IndexRange {\n if (itemCount <= 0) {\n return { start: 0, end: 0 };\n }\n if (viewSize <= 0 || itemSize <= 0) {\n return { start: 0, end: Math.min(itemCount, UNMEASURED_FALLBACK_COUNT) };\n }\n\n const firstVisible = Math.floor(offset / itemSize);\n const lastVisible = Math.ceil((offset + viewSize) / itemSize);\n\n const start = Math.max(0, firstVisible - overscan);\n const end = Math.min(itemCount, lastVisible + overscan);\n\n return { start, end };\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { buildTimelineDates } from \"../../core/timeline\";\nimport { DEFAULT_SCALES, resolveColumnStep, resolveColumnUnit } from \"../../core/scales\";\nimport type { GanttTask, Id, Overrides, TaskState } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport { Calendar } from \"../calendar/Calendar\";\nimport { Row } from \"../bars/common/Row\";\nimport { DependencyLinksProvider } from \"../dependency-links/DependencyLinksContext\";\nimport { DependencyLinks } from \"../dependency-links/DependencyLinks\";\nimport { DependencyPreview } from \"../dependency-links/DependencyPreview\";\nimport { GridColumns } from \"./GridColumns\";\nimport styles from \"./Grid.module.css\";\nimport { rangeFromOffset } from \"../../core/virtualize\";\nimport { COL_OVERSCAN, ROW_OVERSCAN } from \"../../core/constants\";\nimport {\n useGanttConfig,\n useGanttDependency,\n useGanttLabels,\n useGanttScroll,\n useGanttTaskActions,\n useGanttTaskState,\n useGanttViewport,\n useGanttZoom,\n} from \"../../context/contexts\";\n\n/** State passed to the function form of the Grid slotProps. */\nexport interface GridOwnerState {\n /** Total content width in px (`dates.length * colWidth`). */\n totalWidth: number;\n /** Total body height in px (`visibleTasks.length * rowHeight`). */\n bodyHeight: number;\n /** Fixed grid-wrapper height when configured, else `undefined` (auto). */\n height: number | undefined;\n}\n\nexport interface GridSlots {\n /** The scroll wrapper (`styles.gridWrapper`). Default: `\"div\"`. */\n root?: ElementType;\n /** The scrollable body layer (`styles.body`). Default: `\"div\"`. */\n body?: ElementType;\n}\n\nexport interface GridSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, GridOwnerState>;\n body?: SlotPropsInput<ComponentProps<\"div\">, GridOwnerState>;\n}\n\n/**\n * Slot config for the Gantt grid. Threaded from `<Gantt>` in a later pass.\n *\n * NOTE: pass a referentially stable / memoized object so downstream memoization\n * is not defeated by a fresh object each render.\n */\nexport type GridSlotConfig = SlotConfig<GridSlots, GridSlotProps>;\n\ninterface GanttGridProps {\n slots?: GridSlots;\n slotProps?: GridSlotProps;\n}\n\nexport function GanttGrid({ slots: slotsProp, slotProps: slotPropsProp }: GanttGridProps = {}) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.grid?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.grid?.slotProps;\n\n const { visibleTasks } = useGanttTaskState();\n const { updateTask, commitTask, onTaskClick, setSelectedId } = useGanttTaskActions();\n const { colWidth, rowHeight, scales, padDays, height } = useGanttConfig();\n const labels = useGanttLabels();\n const { gridRef, onGridScroll, gridBodyRef } = useGanttScroll();\n const viewport = useGanttViewport();\n const { dependencies, onDependencyDelete } = useGanttDependency();\n const { zoomAt, zoomIn, zoomOut, wheelEnabled, keyboardEnabled } = useGanttZoom();\n\n useEffect(() => {\n const grid = gridRef.current;\n if (!grid || (!wheelEnabled && !keyboardEnabled)) {\n return;\n }\n const onWheel = (e: WheelEvent) => {\n if (!(e.ctrlKey || e.metaKey)) {\n return;\n }\n e.preventDefault();\n const rect = grid.getBoundingClientRect();\n const focusPx = grid.scrollLeft + (e.clientX - rect.left);\n zoomAt(focusPx, e.deltaY < 0 ? 1 : -1);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"+\" || e.key === \"=\") {\n e.preventDefault();\n zoomIn();\n } else if (e.key === \"-\" || e.key === \"_\") {\n e.preventDefault();\n zoomOut();\n }\n };\n if (wheelEnabled) {\n grid.addEventListener(\"wheel\", onWheel, { passive: false });\n }\n if (keyboardEnabled) {\n grid.tabIndex = 0;\n grid.addEventListener(\"keydown\", onKeyDown);\n }\n return () => {\n grid.removeEventListener(\"wheel\", onWheel);\n grid.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [gridRef, wheelEnabled, keyboardEnabled, zoomAt, zoomIn, zoomOut, visibleTasks.length]);\n\n const [overrides, setOverrides] = useState<Overrides>({});\n\n const handleSelect = useCallback(\n (task: GanttTask) => {\n setSelectedId(task.id);\n onTaskClick?.(task);\n },\n [setSelectedId, onTaskClick],\n );\n\n const handleOverride = useCallback((id: Id, patch: Partial<TaskState> | null) => {\n setOverrides((prev) => {\n if (patch === null) {\n const { [id]: _, ...rest } = prev;\n return rest;\n }\n return { ...prev, [id]: { ...prev[id], ...patch } };\n });\n }, []);\n\n const dates = useMemo(\n () => buildTimelineDates(visibleTasks, padDays, scales),\n [visibleTasks, padDays, scales],\n );\n\n const originMs = dates[0]?.getTime();\n const origin = useMemo(() => (originMs == null ? undefined : new Date(originMs)), [originMs]);\n if (!origin) {\n return null;\n }\n\n const unit = resolveColumnUnit(scales);\n const totalWidth = dates.length * colWidth;\n const bodyHeight = visibleTasks.length * rowHeight;\n\n const resolvedScales = scales ?? DEFAULT_SCALES;\n const headerRowCount = resolvedScales.length;\n\n const rowRange = rangeFromOffset(\n viewport.scrollTop,\n viewport.clientHeight,\n rowHeight,\n visibleTasks.length,\n ROW_OVERSCAN,\n );\n const colRange = rangeFromOffset(\n viewport.scrollLeft,\n viewport.clientWidth,\n colWidth,\n dates.length,\n COL_OVERSCAN,\n );\n\n // Overscan-padded visible pixel rect, reused to cull dependency links. The\n // ranges already include overscan and are clamped to the content bounds.\n const visibleRect = {\n minX: colRange.start * colWidth,\n maxX: colRange.end * colWidth,\n minY: rowRange.start * rowHeight,\n maxY: rowRange.end * rowHeight,\n };\n\n const Root = slots?.root ?? \"div\";\n const Body = slots?.body ?? \"div\";\n\n const ownerState: GridOwnerState = { totalWidth, bodyHeight, height };\n\n const rootProps = mergeSlotProps(\n {\n className: styles.gridWrapper,\n style: height !== undefined ? { height } : {},\n onScroll: onGridScroll,\n role: \"grid\",\n \"aria-label\": labels.timeline,\n \"aria-rowcount\": headerRowCount + visibleTasks.length,\n \"aria-colcount\": dates.length,\n },\n slotProps?.root,\n ownerState,\n );\n\n const bodyProps = mergeSlotProps(\n {\n className: styles.body,\n style: { height: bodyHeight, width: totalWidth },\n role: \"rowgroup\",\n },\n slotProps?.body,\n ownerState,\n );\n\n return (\n <Root ref={gridRef} {...rootProps}>\n <div className={styles.grid} style={{ width: totalWidth }} role=\"presentation\">\n <Calendar\n colWidth={colWidth}\n rowHeight={rowHeight}\n dates={dates}\n scales={scales}\n colRange={colRange}\n />\n <DependencyLinksProvider\n tasks={visibleTasks}\n dependencies={dependencies}\n origin={origin}\n colWidth={colWidth}\n rowHeight={rowHeight}\n unit={unit}\n overrides={overrides}\n >\n <Body ref={gridBodyRef} {...bodyProps}>\n <GridColumns\n dates={dates}\n colWidth={colWidth}\n bodyHeight={bodyHeight}\n colRange={colRange}\n unit={unit}\n step={resolveColumnStep(scales)}\n />\n <DependencyLinks\n width={totalWidth}\n height={bodyHeight}\n onDependencyDelete={onDependencyDelete}\n visibleRect={visibleRect}\n />\n <DependencyPreview />\n\n {visibleTasks.slice(rowRange.start, rowRange.end).map((task, i) => {\n const index = rowRange.start + i;\n return (\n <Row\n key={task.id}\n task={task}\n index={index}\n origin={origin}\n colWidth={colWidth}\n rowHeight={rowHeight}\n unit={unit}\n onUpdate={updateTask}\n onCommit={commitTask}\n override={overrides[task.id]}\n onOverride={handleOverride}\n onTaskClick={handleSelect}\n rowIndexOffset={headerRowCount}\n />\n );\n })}\n </Body>\n </DependencyLinksProvider>\n </div>\n </Root>\n );\n}\n\nGanttGrid.displayName = \"GanttGrid\";\n",".handle {\n width: 4px;\n align-self: stretch;\n cursor: col-resize;\n background: var(--am-gantt-calendar-border, #e2e8f0);\n flex-shrink: 0;\n user-select: none;\n transition: background 0.15s;\n}\n\n.handle:hover {\n background: var(--am-gantt-dependency-color, #94a3b8);\n}\n","import type { ComponentProps, ElementType } from \"react\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttSlots } from \"../../context/GanttSlotsContext\";\nimport { useGanttLabels } from \"../../context/contexts\";\nimport styles from \"./GridResizeHandle.module.css\";\n\n/** State passed to the function form of the GridResizeHandle slotProps. */\nexport interface GridResizeHandleOwnerState {\n /** Whether a resize drag is currently in progress. */\n isResizing: boolean;\n}\n\nexport interface GridResizeHandleSlots {\n /** The pane splitter element. Default: `\"div\"`. */\n root?: ElementType;\n}\n\nexport interface GridResizeHandleSlotProps {\n root?: SlotPropsInput<ComponentProps<\"div\">, GridResizeHandleOwnerState>;\n}\n\nexport type GridResizeHandleSlotConfig = SlotConfig<\n GridResizeHandleSlots,\n GridResizeHandleSlotProps\n>;\n\ninterface GridResizeHandleProps {\n onMouseDown: React.MouseEventHandler;\n isResizing?: boolean;\n slots?: GridResizeHandleSlots;\n slotProps?: GridResizeHandleSlotProps;\n}\n\nexport function GridResizeHandle({\n onMouseDown,\n isResizing = false,\n slots: slotsProp,\n slotProps: slotPropsProp,\n}: GridResizeHandleProps) {\n const ganttSlots = useGanttSlots();\n const slots = slotsProp ?? ganttSlots.timeline?.gridResizeHandle?.slots;\n const slotProps = slotPropsProp ?? ganttSlots.timeline?.gridResizeHandle?.slotProps;\n\n const labels = useGanttLabels();\n const ownerState: GridResizeHandleOwnerState = { isResizing };\n\n const Root = slots?.root ?? \"div\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.handle,\n onMouseDown,\n role: \"separator\",\n \"aria-orientation\": \"vertical\" as const,\n \"aria-label\": labels.resizeTaskList,\n },\n slotProps?.root,\n ownerState,\n );\n\n return <Root {...rootProps} />;\n}\n",".taskList {\n display: flex;\n flex-direction: column;\n font-family: inherit;\n background: var(--am-gantt-tasklist-bg, #ffffff);\n flex-shrink: 0;\n width: max-content;\n}\n\n.header {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n background: var(--am-gantt-calendar-header-bg, #f8fafc);\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-radius: var(--am-gantt-calendar-radius, 6px) var(--am-gantt-calendar-radius, 6px) 0 0;\n box-sizing: border-box;\n overflow: hidden;\n user-select: none;\n}\n\n.headerCell {\n position: relative;\n display: flex;\n align-items: center;\n padding: 0 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--am-gantt-calendar-header-color, #475569);\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n box-sizing: border-box;\n}\n\n.headerCell:last-child {\n border-right: none;\n}\n\n.body {\n position: relative;\n overflow-y: auto;\n overflow-x: hidden;\n /* No rubber-band bounce / scroll chaining to the page (macOS, iOS). */\n overscroll-behavior: none;\n border: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n border-top: none;\n border-radius: 0 0 var(--am-gantt-calendar-radius, 6px) var(--am-gantt-calendar-radius, 6px);\n background: var(--am-gantt-tasklist-bg, #ffffff);\n box-sizing: border-box;\n}\n\n.rows {\n position: relative;\n}\n\n.row {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n border-bottom: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n box-sizing: border-box;\n}\n\n.row:last-child {\n border-bottom: none;\n}\n\n.row.selected {\n background: var(--am-gantt-row-selected-bg, #e0f2fe);\n}\n\n.cell {\n display: flex;\n align-items: center;\n padding: 0 8px;\n font-size: 13px;\n color: var(--am-gantt-tasklist-color, #334155);\n border-right: 1px solid var(--am-gantt-calendar-border, #e2e8f0);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n box-sizing: border-box;\n}\n\n.cell:last-child {\n border-right: none;\n}\n\n.treeCell {\n overflow: hidden;\n}\n\n.nameContent {\n display: flex;\n align-items: center;\n gap: 4px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.expandBtn {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-size: 10px;\n color: var(--am-gantt-tasklist-color, #334155);\n width: 14px;\n flex-shrink: 0;\n line-height: 1;\n}\n\n.expandBtn:focus-visible {\n outline: var(--am-gantt-focus-ring-width, 2px) solid var(--am-gantt-focus-ring-color, #1d4ed8);\n outline-offset: var(--am-gantt-focus-ring-offset, -2px);\n border-radius: 2px;\n}\n\n.expandPlaceholder {\n display: inline-block;\n width: 14px;\n flex-shrink: 0;\n}\n\n.divider {\n position: absolute;\n top: 0;\n right: 0;\n width: 5px;\n height: 100%;\n cursor: col-resize;\n user-select: none;\n}\n\n.divider:hover {\n background: var(--am-gantt-dependency-color, #94a3b8);\n}\n","import type React from \"react\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport type { ColumnDef, Scale } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport styles from \"./TaskList.module.css\";\nimport { DEFAULT_SCALES } from \"../../core/scales\";\n\n/** State passed to the function form of the header (container) slotProps. */\nexport interface TaskListHeaderOwnerState {\n columns: ColumnDef[];\n headerHeight: number;\n}\n\n/** State passed to the function form of the per-column slotProps. */\nexport interface TaskListHeaderCellOwnerState {\n column: ColumnDef;\n index: number;\n}\n\nexport interface TaskListHeaderSlots {\n /** The header row container. Default: `\"div\"`. */\n header?: ElementType;\n /** A per-column header cell. Default: `\"div\"`. */\n headerCell?: ElementType;\n /** The per-column resize handle (divider). Default: `\"div\"`. */\n columnResizeHandle?: ElementType;\n}\n\nexport interface TaskListHeaderSlotProps {\n header?: SlotPropsInput<ComponentProps<\"div\">, TaskListHeaderOwnerState>;\n headerCell?: SlotPropsInput<ComponentProps<\"div\">, TaskListHeaderCellOwnerState>;\n columnResizeHandle?: SlotPropsInput<ComponentProps<\"div\">, TaskListHeaderCellOwnerState>;\n}\n\nexport type TaskListHeaderSlotConfig = SlotConfig<TaskListHeaderSlots, TaskListHeaderSlotProps>;\n\ninterface TaskListHeaderProps {\n columns: ColumnDef[];\n rowHeight: number;\n scales?: Scale[];\n onResizeStart: (key: string, startWidth: number, e: React.MouseEvent) => void;\n slots?: TaskListHeaderSlots;\n slotProps?: TaskListHeaderSlotProps;\n}\n\nexport function TaskListHeader({\n columns,\n rowHeight,\n scales = DEFAULT_SCALES,\n onResizeStart,\n slots,\n slotProps,\n}: TaskListHeaderProps) {\n // Height tracks the calendar: one row per scale, +2 for its 1px top/bottom\n // borders. Both default to the shared DEFAULT_SCALES so the counts can't drift.\n const headerHeight = scales.length * rowHeight + 2;\n\n const Header = slots?.header ?? \"div\";\n const HeaderCell = slots?.headerCell ?? \"div\";\n const ColumnResizeHandle = slots?.columnResizeHandle ?? \"div\";\n\n // Row 1 of the enclosing treegrid.\n const headerProps = mergeSlotProps(\n {\n className: styles.header,\n style: { minHeight: headerHeight, height: headerHeight },\n role: \"row\",\n \"aria-rowindex\": 1,\n },\n slotProps?.header,\n { columns, headerHeight },\n );\n\n return (\n <Header {...headerProps}>\n {columns.map((col, index) => {\n const cellOwnerState: TaskListHeaderCellOwnerState = { column: col, index };\n\n const headerCellProps = mergeSlotProps(\n {\n className: styles.headerCell,\n style: col.width\n ? { width: col.width, flexShrink: 0 }\n : { flex: \"1 1 auto\", minWidth: 100 },\n role: \"columnheader\",\n \"aria-colindex\": index + 1,\n },\n slotProps?.headerCell,\n cellOwnerState,\n );\n\n const resizeHandleProps = mergeSlotProps(\n {\n className: styles.divider,\n \"aria-hidden\": true,\n onMouseDown: (e: React.MouseEvent) => {\n // Read the rendered width from the DOM so flex (no explicit width)\n // columns snap cleanly to a fixed width on first drag.\n const cell = e.currentTarget.parentElement as HTMLElement;\n onResizeStart(col.key, cell.offsetWidth, e);\n },\n },\n slotProps?.columnResizeHandle,\n cellOwnerState,\n );\n\n return (\n <HeaderCell key={col.key} {...headerCellProps}>\n {col.header}\n <ColumnResizeHandle {...resizeHandleProps} />\n </HeaderCell>\n );\n })}\n </Header>\n );\n}\n","import type { ComponentProps, ElementType, ReactNode } from \"react\";\nimport type { Id } from \"../../types\";\nimport { mergeSlotProps, type SlotConfig, type SlotPropsInput } from \"../../core/slots\";\nimport { useGanttLabels } from \"../../context/contexts\";\nimport styles from \"./TaskList.module.css\";\n\nconst INDENT_PX = 16;\n\n/** State passed to the function form of each TreeCell slotProps. */\nexport interface TreeCellOwnerState {\n taskId: Id;\n depth: number;\n isParent: boolean;\n isExpanded: boolean;\n}\n\nexport interface TreeCellSlots {\n /** The `nameContent` wrapper. Default: `\"span\"`. */\n root?: ElementType;\n /** The ▾/▸ expand/collapse toggle. Default: `\"button\"`. */\n expandButton?: ElementType;\n /** The spacer rendered for leaf (non-parent) rows. Default: `\"span\"`. */\n placeholder?: ElementType;\n}\n\nexport interface TreeCellSlotProps {\n root?: SlotPropsInput<ComponentProps<\"span\">, TreeCellOwnerState>;\n expandButton?: SlotPropsInput<ComponentProps<\"button\">, TreeCellOwnerState>;\n placeholder?: SlotPropsInput<ComponentProps<\"span\">, TreeCellOwnerState>;\n}\n\n/**\n * Slot config for the tree cell. Pass via `<Gantt treeCell={...} />`.\n *\n * NOTE: pass a referentially stable / memoized object — `TaskListRow` is memoized,\n * so a fresh object each render defeats its memo and re-renders every row.\n */\nexport type TreeCellSlotConfig = SlotConfig<TreeCellSlots, TreeCellSlotProps>;\n\ninterface TreeCellProps {\n taskId: Id;\n depth: number;\n isParent: boolean;\n isExpanded: boolean;\n onToggleExpand: (id: Id) => void;\n children: ReactNode;\n slots?: TreeCellSlots;\n slotProps?: TreeCellSlotProps;\n}\n\nexport function TreeCell({\n taskId,\n depth,\n isParent,\n isExpanded,\n onToggleExpand,\n children,\n slots,\n slotProps,\n}: TreeCellProps) {\n const labels = useGanttLabels();\n const ownerState: TreeCellOwnerState = { taskId, depth, isParent, isExpanded };\n\n const Root = slots?.root ?? \"span\";\n const ExpandButton = slots?.expandButton ?? \"button\";\n const Placeholder = slots?.placeholder ?? \"span\";\n\n const rootProps = mergeSlotProps(\n {\n className: styles.nameContent,\n style: { paddingLeft: depth * INDENT_PX },\n },\n slotProps?.root,\n ownerState,\n );\n\n const buttonProps = mergeSlotProps(\n {\n className: styles.expandBtn,\n type: \"button\",\n onClick: (e: React.MouseEvent) => {\n e.stopPropagation();\n onToggleExpand(taskId);\n },\n \"aria-label\": isExpanded ? labels.collapse : labels.expand,\n children: isExpanded ? \"▾\" : \"▸\",\n },\n slotProps?.expandButton,\n ownerState,\n );\n\n const placeholderProps = mergeSlotProps(\n { className: styles.expandPlaceholder, \"aria-hidden\": true },\n slotProps?.placeholder,\n ownerState,\n );\n\n return (\n <Root {...rootProps}>\n {isParent ? <ExpandButton {...buttonProps} /> : <Placeholder {...placeholderProps} />}\n {children}\n </Root>\n );\n}\n","import { memo } from \"react\";\nimport type { ColumnDef, GanttTask, Id } from \"../../types\";\nimport { useGanttTaskActions } from \"../../context/contexts\";\nimport { TreeCell, type TreeCellSlotConfig } from \"./TreeCell\";\nimport styles from \"./TaskList.module.css\";\n\ninterface TaskListRowProps {\n task: GanttTask;\n rowHeight: number;\n rowIndex: number;\n depth: number;\n posinset: number;\n setsize: number;\n isParent: boolean;\n isExpanded: boolean;\n isSelected: boolean;\n onToggleExpand: (id: Id) => void;\n onSelect: (id: Id) => void;\n columns: ColumnDef[];\n treeCell?: TreeCellSlotConfig;\n}\n\nconst DEFAULT_COL_WIDTH = 100;\n\nexport const TaskListRow = memo(function TaskListRow({\n task,\n rowHeight,\n rowIndex,\n depth,\n posinset,\n setsize,\n isParent,\n isExpanded,\n isSelected,\n onToggleExpand,\n onSelect,\n columns,\n treeCell,\n}: TaskListRowProps) {\n const { columnApi } = useGanttTaskActions();\n return (\n <div\n className={`${styles.row} ${isSelected ? styles.selected : \"\"}`}\n style={{ height: rowHeight }}\n onClick={() => onSelect(task.id)}\n role=\"row\"\n aria-rowindex={rowIndex + 2}\n aria-level={depth + 1}\n aria-posinset={posinset}\n aria-setsize={setsize}\n aria-expanded={isParent ? isExpanded : undefined}\n aria-selected={isSelected || undefined}\n >\n {columns.map((col, index) => {\n return (\n <div\n key={col.key}\n className={`${styles.cell} ${col.isTreeColumn ? styles.treeCell : \"\"}`}\n style={{ width: col.width || DEFAULT_COL_WIDTH, flexShrink: 0 }}\n role={col.isTreeColumn ? \"rowheader\" : \"gridcell\"}\n aria-colindex={index + 1}\n >\n {col.isTreeColumn ? (\n <TreeCell\n taskId={task.id}\n depth={depth}\n isParent={isParent}\n isExpanded={isExpanded}\n onToggleExpand={onToggleExpand}\n slots={treeCell?.slots}\n slotProps={treeCell?.slotProps}\n >\n {col.render(task, columnApi)}\n </TreeCell>\n ) : (\n col.render(task, columnApi)\n )}\n </div>\n );\n })}\n </div>\n );\n});\n\nTaskListRow.displayName = \"TaskListRow\";\n","import { useCallback, useRef, useState } from \"react\";\nimport { COLUMN_MIN_WIDTH } from \"../core/constants\";\n\n/**\n * Session-local column-width overrides, keyed by `col.key`. Mirrors\n * `useGridResize`: mousedown captures the start width, window listeners track\n * the drag, and the width clamps at `COLUMN_MIN_WIDTH`.\n */\nexport function useColumnWidths() {\n const [widths, setWidths] = useState<Record<string, number>>({});\n const startRef = useRef<{ key: string; mouseX: number; width: number } | null>(null);\n\n const onResizeStart = useCallback((key: string, startWidth: number, e: React.MouseEvent) => {\n e.preventDefault();\n startRef.current = { key, mouseX: e.clientX, width: startWidth };\n\n const onMove = (ev: MouseEvent) => {\n if (!startRef.current) {\n return;\n }\n const { key: colKey, mouseX, width } = startRef.current;\n const next = Math.max(COLUMN_MIN_WIDTH, width + (ev.clientX - mouseX));\n setWidths((prev) => ({ ...prev, [colKey]: next }));\n };\n\n const onUp = () => {\n startRef.current = null;\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n };\n\n window.addEventListener(\"mousemove\", onMove);\n window.addEventListener(\"mouseup\", onUp);\n }, []);\n\n return { widths, onResizeStart };\n}\n","import { useCallback, useMemo } from \"react\";\nimport {\n useGanttConfig,\n useGanttLabels,\n useGanttScroll,\n useGanttSelectedId,\n useGanttTaskActions,\n useGanttTaskState,\n} from \"../../context/contexts\";\nimport type { ColumnDef, Id } from \"../../types\";\nimport { TaskListHeader } from \"./TaskListHeader\";\nimport { TaskListRow } from \"./TaskListRow\";\nimport type { GanttTaskListSlots } from \"../../context/GanttSlotsContext\";\nimport { rangeFromOffset } from \"../../core/virtualize\";\nimport { ROW_OVERSCAN } from \"../../core/constants\";\nimport { useColumnWidths } from \"../../hooks/useColumnWidths\";\nimport { useLatestRef } from \"../../hooks/useLatestRef\";\nimport { useViewportMeasure } from \"../../hooks/useViewportMeasure\";\nimport styles from \"./TaskList.module.css\";\n\n/** Static, so it is hoisted out of the render path rather than re-allocated. */\nconst BODY_STYLE = { flex: \"1 1 auto\", minHeight: 0 } as const;\n\ninterface TaskListProps {\n columns?: ColumnDef[];\n /** Slot overrides for the task-list pane (`treeCell`, `header`). Pass a stable object. */\n taskList?: GanttTaskListSlots;\n}\n\nexport function TaskList({ columns = [], taskList }: TaskListProps) {\n const { visibleTasks, expandedIds, parentIds } = useGanttTaskState();\n const { toggleExpand, setSelectedId, onTaskClick, revealTask } = useGanttTaskActions();\n const selectedId = useGanttSelectedId();\n const { rowHeight, scales, height } = useGanttConfig();\n const labels = useGanttLabels();\n const { taskListRef, onTaskListScroll } = useGanttScroll();\n\n const { widths, onResizeStart } = useColumnWidths();\n\n // Overlay the session-local resize widths onto the incoming columns. Both the\n // header and rows render this same array, so they stay aligned by construction.\n const resolvedColumns = useMemo(\n () =>\n columns.map((col) => (widths[col.key] != null ? { ...col, width: widths[col.key] } : col)),\n [columns, widths],\n );\n\n // Dispatched through a latest-ref so `handleSelect` is identity-stable\n // forever: it is handed to every memoized row, and closing over `visibleTasks`\n // directly would re-render the whole window on every edit, expand or zoom.\n // (Same pattern as `useRevealTask`.)\n const selectRef = useLatestRef((id: Id) => {\n setSelectedId(id);\n\n const task = visibleTasks.find((t) => t.id === id);\n if (task) {\n onTaskClick?.(task);\n // Horizontal only: clicking a row must not also scroll it vertically, since\n // the row the user just clicked is by definition already on screen.\n revealTask(id, { horizontal: true, vertical: false });\n }\n });\n const handleSelect = useCallback((id: Id) => selectRef.current(id), [selectRef]);\n\n const depthMap = useMemo(() => {\n const map = new Map<Id, number>();\n for (const t of visibleTasks) {\n const parentDepth = t.parentId != null ? (map.get(t.parentId) ?? 0) : -1;\n map.set(t.id, parentDepth + 1);\n }\n return map;\n }, [visibleTasks]);\n\n const siblingInfo = useMemo(() => {\n const counts = new Map<Id | null, number>();\n const map = new Map<Id, { posinset: number; setsize: number }>();\n for (const t of visibleTasks) {\n const parent = t.parentId ?? null;\n const pos = (counts.get(parent) ?? 0) + 1;\n counts.set(parent, pos);\n map.set(t.id, { posinset: pos, setsize: 0 });\n }\n for (const t of visibleTasks) {\n const entry = map.get(t.id)!;\n entry.setsize = counts.get(t.parentId ?? null) ?? 1;\n }\n return map;\n }, [visibleTasks]);\n\n const { viewport: listViewport, scheduleMeasure } = useViewportMeasure(taskListRef, {\n trackHorizontal: false,\n });\n\n // Order matters: sync the grid first, then measure, so the windowing reads the\n // scroll position both panes have settled on.\n const handleScroll = useCallback(() => {\n onTaskListScroll();\n scheduleMeasure();\n }, [onTaskListScroll, scheduleMeasure]);\n\n // Render only the rows intersecting the viewport (plus overscan). The `.rows`\n // height stays full (via the spacers) so the scrollbar extent is unaffected.\n const rowRange = rangeFromOffset(\n listViewport.scrollTop,\n listViewport.clientHeight,\n rowHeight,\n visibleTasks.length,\n ROW_OVERSCAN,\n );\n\n return (\n <div\n className={styles.taskList}\n style={{ height }}\n role=\"treegrid\"\n aria-label={labels.taskList}\n aria-rowcount={visibleTasks.length + 1}\n aria-colcount={resolvedColumns.length}\n >\n <TaskListHeader\n columns={resolvedColumns}\n rowHeight={rowHeight}\n scales={scales}\n onResizeStart={onResizeStart}\n slots={taskList?.header?.slots}\n slotProps={taskList?.header?.slotProps}\n />\n <div\n ref={taskListRef}\n className={styles.body}\n style={BODY_STYLE}\n onScroll={handleScroll}\n role=\"presentation\"\n >\n <div className={styles.rows} role=\"rowgroup\">\n <div\n style={{ height: rowRange.start * rowHeight }}\n role=\"presentation\"\n aria-hidden=\"true\"\n />\n {Array.from({ length: rowRange.end - rowRange.start }, (_, i) => {\n const index = rowRange.start + i;\n const task = visibleTasks[index]!;\n const siblings = siblingInfo.get(task.id);\n return (\n <TaskListRow\n key={task.id}\n task={task}\n rowHeight={rowHeight}\n rowIndex={index}\n depth={depthMap.get(task.id) ?? 0}\n posinset={siblings?.posinset ?? 1}\n setsize={siblings?.setsize ?? 1}\n isParent={parentIds.has(task.id)}\n isExpanded={expandedIds.has(task.id)}\n isSelected={selectedId === task.id}\n onToggleExpand={toggleExpand}\n onSelect={handleSelect}\n columns={resolvedColumns}\n treeCell={taskList?.treeCell}\n />\n );\n })}\n <div\n style={{\n height: (visibleTasks.length - rowRange.end) * rowHeight,\n }}\n role=\"presentation\"\n aria-hidden=\"true\"\n />\n </div>\n </div>\n </div>\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { GRID_MIN_WIDTH } from \"../core/constants\";\n\nexport function useGridResize(\n containerRef: React.RefObject<HTMLDivElement | null>,\n overlayRef: React.RefObject<HTMLDivElement | null>,\n) {\n const [gridWidth, setGridWidth] = useState<number | undefined>(undefined);\n const startRef = useRef<{ mouseX: number; width: number; containerW: number } | null>(null);\n\n const onHandleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const overlay = overlayRef.current;\n const container = containerRef.current;\n if (!overlay || !container) {\n return;\n }\n startRef.current = {\n mouseX: e.clientX,\n width: overlay.offsetWidth,\n containerW: container.offsetWidth,\n };\n\n const onMove = (ev: MouseEvent) => {\n if (!startRef.current) {\n return;\n }\n const { mouseX, width, containerW } = startRef.current;\n // Handle is on the grid's left edge: dragging left increases the width.\n const next = Math.min(containerW, Math.max(GRID_MIN_WIDTH, width + (mouseX - ev.clientX)));\n setGridWidth(next);\n };\n\n const onUp = () => {\n startRef.current = null;\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n };\n\n window.addEventListener(\"mousemove\", onMove);\n window.addEventListener(\"mouseup\", onUp);\n },\n [containerRef, overlayRef],\n );\n\n return { gridWidth, onHandleMouseDown };\n}\n",".actionsCell {\n display: flex;\n gap: 2px;\n}\n\n.actionsCell button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n opacity: 1;\n background-color: #0000;\n border-radius: 0;\n border: 0;\n cursor: pointer;\n}\n","import type { ColumnApi, GanttTask } from \"../../types\";\nimport { addDays } from \"../../core/dateUtils\";\n\nimport styles from \"./ActionsCell.module.css\";\n\n/**\n * Builds the task inserted by the actions-column \"add after\" button: a blank\n * one-day task starting the day after the clicked row, under the same parent.\n *\n * `endDate` is exclusive, so a one-day task ends at the following midnight.\n *\n * Known gap (ADR-012): this is a library-authored date that does NOT snap onto\n * working time, because a column's `render` is a plain function with no access to\n * the calendar. A task added after a Friday row can therefore land on a Saturday\n * until it is first dragged.\n */\nexport function buildActionTask(task: GanttTask): GanttTask {\n const start = addDays(task.startDate, 1);\n return {\n id: `task-${Date.now()}`,\n name: \"New task\",\n startDate: start,\n endDate: addDays(start, 1),\n duration: 1,\n progress: 0,\n type: \"task\",\n parentId: task.parentId ?? null,\n };\n}\n\n/**\n * The edit / add-after / delete controls of the built-in actions column.\n *\n * A real component rather than JSX inside an array literal, so it has somewhere\n * to grow a slot and somewhere to be tested from. Every handler stops propagation\n * because the whole row is clickable for selection.\n *\n * Labels come through `api.labels`, not `useGanttLabels()` — a column's `render`\n * is a plain function and cannot call hooks.\n */\nexport function ActionsCell({ task, api }: { task: GanttTask; api: ColumnApi }) {\n return (\n <div className={styles.actionsCell}>\n <button\n type=\"button\"\n title=\"Edit\"\n aria-label={api.labels.editTask(task)}\n onClick={(e) => {\n e.stopPropagation();\n api.editTask(task);\n }}\n >\n <span aria-hidden=\"true\">&#9998;</span>\n </button>\n <button\n type=\"button\"\n title=\"Add after\"\n aria-label={api.labels.addTaskAfter(task)}\n onClick={(e) => {\n e.stopPropagation();\n const created = buildActionTask(task);\n api.createTask(created, task.id);\n api.editTask(created);\n }}\n >\n <span aria-hidden=\"true\">&#10133;</span>\n </button>\n <button\n type=\"button\"\n title=\"Delete\"\n aria-label={api.labels.deleteTask(task)}\n style={{ fontSize: 9 }}\n onClick={(e) => {\n e.stopPropagation();\n api.deleteTask(task.id);\n }}\n >\n <span aria-hidden=\"true\">&#10060;</span>\n </button>\n </div>\n );\n}\n","import type { ColumnDef, GanttTask } from \"../../types\";\nimport { ActionsCell } from \"./ActionsCell\";\n\n/**\n * Key of the built-in edit/add/delete column, dropped when `readOnly` is set.\n *\n * Exported so a consumer can extend the built-in set rather than replace it:\n * `[...DEFAULT_COLUMNS.filter((c) => c.key !== ACTION_COLUMN_KEY), myColumn]`.\n */\nexport const ACTION_COLUMN_KEY = \"__action\";\n\n/**\n * The columns `<Gantt>` renders when no `columns` prop is given.\n *\n * Treat as immutable — it is module state shared by every chart on the page.\n */\nexport const DEFAULT_COLUMNS: ColumnDef[] = [\n {\n key: ACTION_COLUMN_KEY,\n header: \" \",\n width: 100,\n render: (task, api) => <ActionsCell task={task} api={api} />,\n },\n {\n key: \"__name\",\n header: \"Task Name\",\n render: (task: GanttTask) => task.name,\n width: 200,\n isTreeColumn: true,\n },\n {\n key: \"__start\",\n header: \"Start\",\n width: 90,\n render: (task: GanttTask) => task.startDate.toLocaleDateString(),\n },\n {\n key: \"__end\",\n header: \"End\",\n width: 90,\n // Stored ends are exclusive instants, so format through the api rather than\n // reading `task.endDate` — otherwise a Mon–Fri task reads as ending Saturday.\n render: (task: GanttTask, api) => api.format.endDate(task)?.toLocaleDateString() ?? \"—\",\n },\n {\n key: \"__progress\",\n header: \"Progress, %\",\n width: 90,\n render: (task: GanttTask) => `${task.progress ?? 0}%`,\n },\n];\n\n/** {@link DEFAULT_COLUMNS} without the actions column — the `readOnly` default. */\nexport const READ_ONLY_COLUMNS: ColumnDef[] = DEFAULT_COLUMNS.filter(\n (col) => col.key !== ACTION_COLUMN_KEY,\n);\n","import { useMemo, useRef } from \"react\";\nimport { GanttProvider } from \"./context/GanttProvider\";\nimport { GanttSlotsProvider } from \"./context/GanttSlotsContext\";\nimport { GanttGrid } from \"./components/grid/Grid\";\nimport { GridResizeHandle } from \"./components/grid/GridResizeHandle\";\nimport { TaskList } from \"./components/taskList/TaskList\";\nimport { useGridResize } from \"./hooks/useGridResize\";\nimport type { GanttProps } from \"./types\";\nimport { DEFAULT_COLUMNS, READ_ONLY_COLUMNS } from \"./components/taskList/defaultColumns\";\nimport { DEFAULT_LABELS } from \"./core/labels\";\n\nexport function Gantt({\n tasks,\n dependencies,\n rowHeight,\n colWidth,\n height,\n scales,\n padDays,\n zoomLevels,\n defaultZoomIndex,\n onZoomChange,\n zoomWheel,\n zoomKeyboard,\n onTaskClick,\n columns: columnsProp,\n defaultTaskListWidth = 280,\n onDependencyCreate,\n onDependencyDelete,\n onTaskCreate,\n onTaskDelete,\n onTaskEdit,\n onTasksChange,\n calendar,\n snapToWorking,\n durationUnit,\n readOnly = false,\n apiRef,\n hideTaskList,\n taskList,\n bars,\n dependencySlots,\n timeline,\n labels,\n}: GanttProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const overlayRef = useRef<HTMLDivElement>(null);\n const { gridWidth, onHandleMouseDown } = useGridResize(containerRef, overlayRef);\n // The built-in actions column only renders edit/add/delete buttons, so a\n // read-only chart drops it rather than shipping a column of dead controls.\n const columns = columnsProp ?? (readOnly ? READ_ONLY_COLUMNS : DEFAULT_COLUMNS);\n const showTaskList = !hideTaskList;\n\n // Grid-side slot groups reach deep components (bars, dependencies, calendar,\n // grid) via context instead of prop-drilling. `taskList` is drilled separately.\n const slotsValue = useMemo(\n () => ({ bars, dependencies: dependencySlots, timeline }),\n [bars, dependencySlots, timeline],\n );\n\n return (\n <GanttProvider\n tasks={tasks}\n dependencies={dependencies}\n rowHeight={rowHeight}\n colWidth={colWidth}\n height={height}\n scales={scales}\n padDays={padDays}\n zoomLevels={zoomLevels}\n defaultZoomIndex={defaultZoomIndex}\n onZoomChange={onZoomChange}\n zoomWheel={zoomWheel}\n zoomKeyboard={zoomKeyboard}\n onTaskClick={onTaskClick}\n onDependencyCreate={onDependencyCreate}\n onDependencyDelete={onDependencyDelete}\n onTaskCreate={onTaskCreate}\n onTaskDelete={onTaskDelete}\n onTaskEdit={onTaskEdit}\n onTasksChange={onTasksChange}\n apiRef={apiRef}\n labels={labels}\n calendar={calendar}\n snapToWorking={snapToWorking}\n durationUnit={durationUnit}\n readOnly={readOnly}\n >\n <GanttSlotsProvider value={slotsValue}>\n {showTaskList ? (\n <div\n ref={containerRef}\n role=\"group\"\n aria-label={labels?.gantt ?? DEFAULT_LABELS.gantt}\n style={{ position: \"relative\" }}\n >\n <TaskList columns={columns} taskList={taskList} />\n <div\n ref={overlayRef}\n style={{\n position: \"absolute\",\n top: 0,\n right: 0,\n zIndex: 1,\n display: \"flex\",\n flexDirection: \"row\",\n background: \"var(--am-gantt-grid-bg, #ffffff)\",\n ...(gridWidth !== undefined\n ? { width: gridWidth }\n : { left: defaultTaskListWidth }),\n }}\n >\n <GridResizeHandle onMouseDown={onHandleMouseDown} />\n <div style={{ flex: \"1 1 auto\", minWidth: 0 }}>\n <GanttGrid />\n </div>\n </div>\n </div>\n ) : (\n <GanttGrid />\n )}\n </GanttSlotsProvider>\n </GanttProvider>\n );\n}\n"],"x_google_ignoreList":[31],"mappings":"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"}