import { GetHtmlOptions } from './text-html.js'; import type { TextElementLike } from './text-types.js'; /** * The shared shrink-to-fit loop for `textOverflow: 'change-font-size'`, used * by the editor canvas and html-export so their fit results can't drift. * svg-export and pdf-export deliberately keep their own LOOPS, on their own * layout engines — see "Deliberate divergences" in ../DESIGN_NOTES.md before * trying to converge them. The `FIT_*` values below are NOT part of that * divergence: a renderer that steps on a different schedule lands on a * different font size than the canvas, which is the one thing every converter * has to match. They are exported for those loops to import, never to restate. * * What stays private is everything that only makes sense PER PASS. This loop * is not the whole fit: the editor writes each result back onto the element * and fits again, so `MAX_STEPS` and the relative `MIN_SCALE_FACTOR` are rate * limits the next pass resumes past — a single-pass renderer that imported * them would stop early and call it converged. ../DESIGN_NOTES.md has the case. * * Callers inject environment specifics as plain parameters (this module is * flag/mobx-free): the editor wraps it with its live flags and the render-tag * measurer; html-export calls it with the defaults (DOM `detectSize` * measurement — under jsdom heights come back 0 so the fit is a no-op; in * plain Node without a DOM it throws, which callers catch). */ export type FitResult = { fontSize: number; text?: string; }; export type MeasureHeight = (html: string) => number; export interface FitTextOptions { /** Options forwarded to `getHtml` when building each measured candidate. */ getHtmlOptions?: GetHtmlOptions; measureHeight?: MeasureHeight; /** * Allow mid-word wrapping. When false (the default, mirroring the editor's * `flags.textSplitAllowed`), a mid-word wrap counts as overflow and shrinks * the font even when the height fits. */ textSplitAllowed?: boolean; } /** The plain-JSON snapshot of a text element the fit loop reads: the same * shape `getHtml` consumes, with the fields the loop scales required. */ export type FitTextElement = TextElementLike & { fontSize: number; fontFamily: string; }; export declare const FIT_SCALE_STEP = 0.02; export declare const FIT_FONT_SIZE_STEP = 0.5; export declare const FIT_HEIGHT_EPSILON = 0.02; export declare const FIT_MIN_FONT_SIZE = 1; export declare function findFitFontSize(element: FitTextElement, options?: FitTextOptions): FitResult; /** * The shrink-to-fit loop for a converter that lays its text out with * **render-tag** — svg-export and pdf-export both do, and drawing from the same * layout is what lets them share one loop. * * This is NOT `findFitFontSize` above, and the two are not convergeable: that * one measures rendered HTML and carries the editor's overflow VERDICT (a * mid-word wrap counts as overflow unless `textSplitAllowed`), while a * converter fits on HEIGHT alone — polotno-node leaves `textSplitAllowed` at * its default and still breaks the long word rather than shrinking, so * height-only is what matches the render every converter is measured against. * See "Deliberate divergences" in ../DESIGN_NOTES.md. * * What the two share is the SCHEDULE — `FIT_*` above — because a renderer that * steps differently lands on a different font size than the canvas. * * `layoutAt` is the caller's own layout call, so each converter keeps measuring * with the engine it draws with. `R` is whatever that returns; the loop reads * only `height`. */ export declare function fitByLayout({ element, shrink, layoutAt, }: { element: TextElementLike & { fontSize: number; }; /** False for `textOverflow: 'resize'`, which renders at natural height. */ shrink: boolean; layoutAt: (fontSize: number, text?: string, textIsNormalized?: boolean) => R; }): { result: R; fontSize: number; };