"use client"; export type TimelineVisualEntry = { id: string; startDate: Date | string; endDate: Date | string; }; export type TimelineVisualOverride = { startDate: Date; endDate: Date; }; export type TimelineVisualOverrides = ReadonlyMap; export function getDragPointerOffset( pointerDeltaX: number, daysDelta: number, cellWidth: number, ): number { return pointerDeltaX - daysDelta * cellWidth; } export function applyPointerOffsetPreviewRect({ left, width, mode, pointerOffsetX, minWidth, }: { left: number; width: number; mode: "move" | "resize-start" | "resize-end"; pointerOffsetX: number; minWidth: number; }): { left: number; width: number; transform?: string } { if (pointerOffsetX === 0) { return { left, width }; } if (mode === "move") { return { left, width, transform: `translateX(${pointerOffsetX}px)` }; } if (mode === "resize-start") { const nextWidth = width - pointerOffsetX; if (nextWidth < minWidth) { return { left: left + (width - minWidth), width: minWidth, }; } return { left: left + pointerOffsetX, width: nextWidth, }; } return { left, width: Math.max(minWidth, width + pointerOffsetX), }; } export function applyVisualOverrides( entries: readonly T[], overrides: TimelineVisualOverrides, ): T[] { if (overrides.size === 0) { return entries as T[]; } let changed = false; const nextEntries = entries.map((entry) => { const override = overrides.get(entry.id); if (!override) { return entry; } changed = true; return { ...entry, startDate: new Date(override.startDate), endDate: new Date(override.endDate), }; }); return changed ? nextEntries : (entries as T[]); }