-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwrap_label.ts
More file actions
32 lines (30 loc) · 1.21 KB
/
Copy pathwrap_label.ts
File metadata and controls
32 lines (30 loc) · 1.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Label wrap helper. Splits at the space nearest the middle if the estimated
// width exceeds the budget. Caps at 2 lines. Per design_advice/LAYOUT_PIPELINE.md
// Stage 9 wrap rule.
import { AVG_CHAR_WIDTH_PCT } from "./constants.js";
// avgCharWidthPct and budgetTolerance default to the canonical constant values
// so existing callers stay byte-identical; layoutLabels passes the resolved
// LayoutConfig values so wrapping reads through the config layer.
export function wrapLabel(
label: string | undefined,
budget: number,
avgCharWidthPct: number = AVG_CHAR_WIDTH_PCT,
budgetTolerance = 1.1,
): string[] {
if (!label) return [""];
const estWidth = label.length * avgCharWidthPct;
if (estWidth <= budget * budgetTolerance) return [label];
const mid = label.length / 2;
const spaces: number[] = [];
const re = /\s+/g;
let m: RegExpExecArray | null;
while ((m = re.exec(label)) !== null) spaces.push(m.index);
if (spaces.length === 0) return [label];
const nearest = spaces.reduce(
(best, s) => (Math.abs(s - mid) < Math.abs(best - mid) ? s : best),
spaces[0] as number,
);
const head = label.slice(0, nearest).trim();
const tail = label.slice(nearest).trim();
return [head, tail];
}