/ ink / layout / geometry.ts
geometry.ts
 1  export type Point = {
 2    x: number
 3    y: number
 4  }
 5  
 6  export type Size = {
 7    width: number
 8    height: number
 9  }
10  
11  export type Rectangle = Point & Size
12  
13  /** Edge insets (padding, margin, border) */
14  export type Edges = {
15    top: number
16    right: number
17    bottom: number
18    left: number
19  }
20  
21  /** Create uniform edges */
22  export function edges(all: number): Edges
23  export function edges(vertical: number, horizontal: number): Edges
24  export function edges(
25    top: number,
26    right: number,
27    bottom: number,
28    left: number,
29  ): Edges
30  export function edges(a: number, b?: number, c?: number, d?: number): Edges {
31    if (b === undefined) {
32      return { top: a, right: a, bottom: a, left: a }
33    }
34    if (c === undefined) {
35      return { top: a, right: b, bottom: a, left: b }
36    }
37    return { top: a, right: b, bottom: c, left: d! }
38  }
39  
40  /** Add two edge values */
41  export function addEdges(a: Edges, b: Edges): Edges {
42    return {
43      top: a.top + b.top,
44      right: a.right + b.right,
45      bottom: a.bottom + b.bottom,
46      left: a.left + b.left,
47    }
48  }
49  
50  /** Zero edges constant */
51  export const ZERO_EDGES: Edges = { top: 0, right: 0, bottom: 0, left: 0 }
52  
53  /** Convert partial edges to full edges with defaults */
54  export function resolveEdges(partial?: Partial<Edges>): Edges {
55    return {
56      top: partial?.top ?? 0,
57      right: partial?.right ?? 0,
58      bottom: partial?.bottom ?? 0,
59      left: partial?.left ?? 0,
60    }
61  }
62  
63  export function unionRect(a: Rectangle, b: Rectangle): Rectangle {
64    const minX = Math.min(a.x, b.x)
65    const minY = Math.min(a.y, b.y)
66    const maxX = Math.max(a.x + a.width, b.x + b.width)
67    const maxY = Math.max(a.y + a.height, b.y + b.height)
68    return { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
69  }
70  
71  export function clampRect(rect: Rectangle, size: Size): Rectangle {
72    const minX = Math.max(0, rect.x)
73    const minY = Math.max(0, rect.y)
74    const maxX = Math.min(size.width - 1, rect.x + rect.width - 1)
75    const maxY = Math.min(size.height - 1, rect.y + rect.height - 1)
76    return {
77      x: minX,
78      y: minY,
79      width: Math.max(0, maxX - minX + 1),
80      height: Math.max(0, maxY - minY + 1),
81    }
82  }
83  
84  export function withinBounds(size: Size, point: Point): boolean {
85    return (
86      point.x >= 0 &&
87      point.y >= 0 &&
88      point.x < size.width &&
89      point.y < size.height
90    )
91  }
92  
93  export function clamp(value: number, min?: number, max?: number): number {
94    if (min !== undefined && value < min) return min
95    if (max !== undefined && value > max) return max
96    return value
97  }