Files
Nexus/apps/web/src/components/timeline/dragMath.ts
T

55 lines
1.7 KiB
TypeScript

/**
* Pure math utilities for timeline drag operations.
* Extracted from useTimelineDrag to make the conversion logic testable
* and reusable across different drag modes.
*/
/** Convert a pixel delta to a number of whole days based on cell width. */
export function pixelsToDays(deltaX: number, cellWidth: number): number {
if (!Number.isFinite(cellWidth) || cellWidth <= 0) {
return 0;
}
return Math.round(deltaX / cellWidth);
}
/**
* Shift a date by a given number of days, returning a new Date.
* Does not mutate the input.
*/
export function shiftDate(date: Date, daysDelta: number): Date {
const result = new Date(date);
result.setDate(result.getDate() + daysDelta);
return result;
}
/**
* Compute new start/end dates for a drag operation.
* Handles move, resize-start, and resize-end modes with clamping
* to prevent start from crossing past end (or vice versa).
*/
export function computeDragDates(
mode: "move" | "resize-start" | "resize-end",
originalStart: Date,
originalEnd: Date,
daysDelta: number,
): { start: Date; end: Date } {
const newStart = new Date(originalStart);
const newEnd = new Date(originalEnd);
if (mode === "move") {
newStart.setDate(newStart.getDate() + daysDelta);
newEnd.setDate(newEnd.getDate() + daysDelta);
} else if (mode === "resize-start") {
newStart.setDate(newStart.getDate() + daysDelta);
// Clamp: allow same-day but prevent crossing
if (newStart > newEnd) newStart.setTime(newEnd.getTime());
} else {
// resize-end
newEnd.setDate(newEnd.getDate() + daysDelta);
// Clamp: allow same-day but prevent crossing
if (newEnd < newStart) newEnd.setTime(newStart.getTime());
}
return { start: newStart, end: newEnd };
}