import { Entity, type ContentProjection } from '../tree/Entity'; import { IRenderer } from '../renderer/IRenderer'; export declare class TextEntity extends Entity { text: string; private atlas; private layout; private prepared; private nodes; fontSize: number; fillStyle: string | any; strokeStyle: string | any; hoveredFillStyle: string | any; lineWidth: number; private isHovered; /** Bumped by {@link applyLayout}; read by `Scene` to skip an unchanged sync. */ private contentEpoch; /** * Visual lines with real canvas geometry, rebuilt by {@link applyLayout} * exactly when `this.nodes` changes. * * Without this the Scene placed the DOM copy at the entity origin and let the * browser flow it at CSS `normal` line-height, while the canvas lays lines out * at `1.5em` pitch with the baseline at `0.8em` — so every line after the * first drifted further from the painted glyphs (measured ~6 px on line 0 and * ~0.35 em per line for a 24 px font, Firefox). Per-line carriers pin the DOM * baseline to the canvas baseline by construction, same as `ui/Text`. */ private projectionLines; constructor(text: string, atlas: any, maxWidth: number, fontSize?: number); /** * Mirror the rendered text into the DOM content layer: find-in-page, screen * readers, crawlers, and translation see the same string the canvas draws. * * Each visual line is emitted with its own y/baseline/line-height so the DOM * line boxes sit exactly on the drawn glyphs instead of flowing at the * browser's `normal` metrics. Line text is the LOGICAL source slice (not the * per-glyph visual text), so shaped or reordered content still copies and * finds in source order — the same contract `ui/Text` ships. */ getContentProjection(): ContentProjection | null; getContentEpoch(): number; /** * Replace the text content. Runs the **cold** measurement pass (re-segment + * re-measure) since the glyphs changed, then re-lays out. * * @returns `this` for chaining. */ setText(text: string): this; /** * Change the wrap width and reflow. Cheap **hot** path only — reuses the * cached {@link PreparedText}, doing no re-segmentation or re-measurement. * Ideal for responsive resize. * * @returns `this` for chaining. */ setMaxWidth(maxWidth: number): this; /** * Set horizontal alignment (`'justify'` stretches wrapped lines flush to * the wrap width; the last line stays ragged) and reflow. */ setTextAlign(align: 'left' | 'justify'): this; /** * Plug a hyphenator (word → parts). Break opportunities are baked in during * the cold pass, so this re-prepares the current text. Soft hyphens * (U+00AD) in the text work without one. */ setHyphenator(fn: ((word: string) => string[]) | null): this; /** Hot pass: place the cached {@link PreparedText} and refresh the a11y box. */ private applyLayout; isPointInside(globalX: number, globalY: number): boolean; render(renderer: IRenderer): void; }