import assert from 'node:assert/strict'; import test from 'node:test'; import { resolveLineDraft, type DrawShapeLike } from '../../src/features/layout/draw/lineDraft.ts'; const canvasWidth = 500; const canvasHeight = 300; function line(shape: Omit, 'type'>): DrawShapeLike { return { type: 'line', ...shape }; } function rect(): DrawShapeLike { return { type: 'rect', x: 40, y: 40, width: 80, height: 60 }; } test('creates a vertical divider from a horizontal gesture when no horizontal crossing line exists ahead', () => { assert.deepEqual(resolveLineDraft(120, 80, 300, 90, [], canvasWidth, canvasHeight), { startX: 120, startY: 0, endX: 120, endY: canvasHeight, orientation: 'vertical', }); assert.deepEqual(resolveLineDraft(120, 80, 10, 70, [], canvasWidth, canvasHeight), { startX: 120, startY: 0, endX: 120, endY: canvasHeight, orientation: 'vertical', }); }); test('creates a horizontal divider from a vertical gesture when no vertical crossing line exists ahead', () => { assert.deepEqual(resolveLineDraft(120, 80, 130, 220, [], canvasWidth, canvasHeight), { startX: 0, startY: 80, endX: canvasWidth, endY: 80, orientation: 'horizontal', }); assert.deepEqual(resolveLineDraft(120, 80, 110, 10, [], canvasWidth, canvasHeight), { startX: 0, startY: 80, endX: canvasWidth, endY: 80, orientation: 'horizontal', }); }); test('stops at the nearest horizontal crossing line for a horizontal gesture divider', () => { const shapes: DrawShapeLike[] = [ line({ x1: 20, y1: 40, x2: 220, y2: 40, orientation: 'horizontal' }), line({ x1: 40, y1: 180, x2: 260, y2: 180, orientation: 'horizontal' }), ]; assert.deepEqual(resolveLineDraft(120, 80, 480, 90, shapes, canvasWidth, canvasHeight), { startX: 120, startY: 40, endX: 120, endY: 180, orientation: 'vertical', }); }); test('stops at the nearest vertical crossing line for a vertical gesture divider', () => { const shapes: DrawShapeLike[] = [ line({ x1: 60, y1: 20, x2: 60, y2: 180, orientation: 'vertical' }), line({ x1: 260, y1: 20, x2: 260, y2: 160, orientation: 'vertical' }), ]; assert.deepEqual(resolveLineDraft(120, 80, 130, 260, shapes, canvasWidth, canvasHeight), { startX: 60, startY: 80, endX: 260, endY: 80, orientation: 'horizontal', }); }); test('ignores crossing lines that are behind the start point or outside the crossing range', () => { const shapes: DrawShapeLike[] = [ line({ x1: 60, y1: 20, x2: 60, y2: 180, orientation: 'vertical' }), line({ x1: 320, y1: 120, x2: 320, y2: 220, orientation: 'vertical' }), line({ x1: 20, y1: 20, x2: 260, y2: 20, orientation: 'horizontal' }), rect(), ]; assert.deepEqual(resolveLineDraft(120, 80, 480, 90, shapes, canvasWidth, canvasHeight), { startX: 120, startY: 20, endX: 120, endY: canvasHeight, orientation: 'vertical', }); assert.deepEqual(resolveLineDraft(120, 80, 130, 260, shapes, canvasWidth, canvasHeight), { startX: 60, startY: 80, endX: canvasWidth, endY: 80, orientation: 'horizontal', }); }); test('does not snap to a crossing line that starts exactly at the same point', () => { const shapes: DrawShapeLike[] = [ line({ x1: 120, y1: 40, x2: 120, y2: 160, orientation: 'vertical' }), line({ x1: 120, y1: 180, x2: 240, y2: 180, orientation: 'horizontal' }), ]; assert.deepEqual(resolveLineDraft(120, 80, 300, 90, shapes, canvasWidth, canvasHeight), { startX: 120, startY: 0, endX: 120, endY: 180, orientation: 'vertical', }); assert.deepEqual(resolveLineDraft(120, 180, 130, 260, shapes, canvasWidth, canvasHeight), { startX: 0, startY: 180, endX: canvasWidth, endY: 180, orientation: 'horizontal', }); }); test('extends to the nearest crossing line on both forward and reverse directions', () => { const shapes: DrawShapeLike[] = [ line({ x1: 60, y1: 20, x2: 60, y2: 180, orientation: 'vertical' }), line({ x1: 260, y1: 20, x2: 260, y2: 180, orientation: 'vertical' }), line({ x1: 20, y1: 40, x2: 220, y2: 40, orientation: 'horizontal' }), line({ x1: 20, y1: 180, x2: 220, y2: 180, orientation: 'horizontal' }), ]; assert.deepEqual(resolveLineDraft(120, 80, 320, 90, shapes, canvasWidth, canvasHeight), { startX: 120, startY: 40, endX: 120, endY: 180, orientation: 'vertical', }); assert.deepEqual(resolveLineDraft(120, 100, 130, 260, shapes, canvasWidth, canvasHeight), { startX: 60, startY: 100, endX: 260, endY: 100, orientation: 'horizontal', }); }); test('respects preferred orientation when the pointer drift would otherwise flip the axis', () => { assert.deepEqual(resolveLineDraft(120, 80, 140, 160, [], canvasWidth, canvasHeight, 'horizontal'), { startX: 0, startY: 80, endX: canvasWidth, endY: 80, orientation: 'horizontal', }); assert.deepEqual(resolveLineDraft(120, 80, 260, 100, [], canvasWidth, canvasHeight, 'vertical'), { startX: 120, startY: 0, endX: 120, endY: canvasHeight, orientation: 'vertical', }); });