import { View } from "@react-pdf/renderer"; import { getMeasurer, measureToken } from "../engine/measure"; import { resolveFace, roleToken, type RoleName, type TypeToken } from "../fonts/roles"; import { chunkIdentifier } from "../model/text"; import { useAvailableWidth } from "./AvailableWidth"; import { fitSize, type FitInfo } from "./FitText"; import { Txt, type TxtProps } from "./Txt"; export interface IdTextInfo extends FitInfo { mode: "single" | "chunked"; chunks: string[]; } export interface IdTextProps extends Omit { role: RoleName | TypeToken; children: string; /** Width to fit; defaults to the available width of the enclosing cell. */ width?: number; minSize?: number; /** For tests and audits only. */ onFit?: (info: IdTextInfo) => void; } /** * Text for identifiers (e-mail, URL, GSTIN, phone). textkit never breaks inside a word, so a long * value would overflow silently. This shrinks it to the role's minimum size; if it is still too wide * it is split at "@ . / - _" into a flex-wrap row of adjacent Text chunks (no gaps, so extraction * joins them back into the original string). */ export function IdText({ role, children, width, minSize, onFit, ...rest }: IdTextProps) { const avail = useAvailableWidth(); const target = width ?? avail; const token = roleToken(role); const fit = fitSize(token, children, target, minSize, { weight: rest.weight, italic: rest.italic }); if (fit.fits) { onFit?.({ ...fit, mode: "single", chunks: [children] }); return {children}; } const sized: TypeToken = { ...token, size: fit.size }; const m = getMeasurer(); const family = resolveFace(token.face, rest.faceOverrides); const widthOf = (s: string) => measureToken(m, sized, s, { weight: rest.weight, italic: rest.italic, family }); let chunks = chunkIdentifier(children, 1); for (let max = children.length; max >= 1; max--) { const candidate = chunkIdentifier(children, max); if (candidate.every((c) => widthOf(c) <= target + 1e-6)) { chunks = candidate; break; } } onFit?.({ ...fit, mode: "chunked", chunks }); return ( {chunks.map((c, i) => ( {c} ))} ); }