UNPKG

modern-text

Version:

Measure and render text in a way that describes the DOM.

390 lines (364 loc) 13 kB
import { NormalizedStyle, TextContent, NormalizedTextContent, NormalizedHighlight } from 'modern-idoc'; import { BoundingBox, Path2DDrawStyle, Path2D, Vector2, VectorLike, Path2DSet, Matrix3 } from 'modern-path2d'; import { Fonts, SFNT } from 'modern-font'; declare function parseColor(ctx: CanvasRenderingContext2D, source: string | CanvasGradient | CanvasPattern, box: BoundingBox): string | CanvasGradient | CanvasPattern; declare function uploadColor(style: Partial<NormalizedStyle>, box: BoundingBox, ctx: CanvasRenderingContext2D): void; interface LinearGradient { x0: number; y0: number; x1: number; y1: number; stops: { offset: number; color: string; }[]; } interface DrawShapePathsOptions extends Partial<NormalizedStyle>, Omit<Partial<Path2DDrawStyle>, 'fill' | 'outline'> { ctx: CanvasRenderingContext2D; path: Path2D; fontSize: number; clipRect?: BoundingBox; } declare function drawPath(options: DrawShapePathsOptions): void; declare function setupView(ctx: CanvasRenderingContext2D, pixelRatio: number, boundingBox: BoundingBox): void; declare class Fragment { content: string; style: Partial<NormalizedStyle>; parent: Paragraph; inlineBox: BoundingBox; characters: Character[]; computedStyle: NormalizedStyle; get computedContent(): string; constructor(content: string, style: Partial<NormalizedStyle> | undefined, parent: Paragraph); updateComputedStyle(): this; initCharacters(): this; } declare class Character { content: string; index: number; parent: Fragment; path: Path2D; lineBox: BoundingBox; inlineBox: BoundingBox; glyphBox?: BoundingBox; advanceWidth: number; advanceHeight: number; underlinePosition: number; underlineThickness: number; strikeoutPosition: number; strikeoutSize: number; ascender: number; descender: number; typoAscender: number; typoDescender: number; typoLineGap: number; winAscent: number; winDescent: number; xHeight: number; capHeight: number; baseline: number; centerDiviation: number; fontStyle?: 'bold' | 'italic'; get compatibleGlyphBox(): BoundingBox; get center(): Vector2; get computedStyle(): NormalizedStyle; get isVertical(): boolean; get fontSize(): number; get fontHeight(): number; constructor(content: string, index: number, parent: Fragment); protected _getFontSFNT(fonts?: Fonts): SFNT | undefined; updateGlyph(sfnt?: SFNT | undefined): this; update(fonts?: Fonts): this; protected _italic(path: Path2D, startPoint?: VectorLike): void; getGlyphMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): { min: Vector2; max: Vector2; } | undefined; getGlyphBoundingBox(withStyle?: boolean): BoundingBox | undefined; drawTo(ctx: CanvasRenderingContext2D, config?: Partial<NormalizedStyle>): void; } declare class Paragraph { style: Partial<NormalizedStyle>; parentStyle: NormalizedStyle; lineBox: BoundingBox; fragments: Fragment[]; computedStyle: NormalizedStyle; constructor(style: Partial<NormalizedStyle>, parentStyle: NormalizedStyle); updateComputedStyle(): this; addFragment(content: string, style?: Partial<NormalizedStyle>): Fragment; } interface TextPlugin { name: string; pathSet?: Path2DSet; getBoundingBox?: (text: Text$1) => BoundingBox | undefined; update?: (text: Text$1) => void; updateOrder?: number; render?: (ctx: CanvasRenderingContext2D, text: Text$1) => void; renderOrder?: number; load?: (text: Text$1) => Promise<void>; } interface TextOptions { debug?: boolean; style?: Partial<NormalizedStyle>; content?: TextContent; effects?: Partial<NormalizedStyle>[]; measureDOM?: HTMLElement; fonts?: Fonts; plugins?: TextPlugin[]; } type EventListenerValue<T = any> = (ev: T) => void; type EventListenerOptions = boolean | AddEventListenerOptions; interface EventListener<T = any> { value: EventListenerValue<T>; options?: EventListenerOptions; } declare class EventEmitter<T extends Record<string, any> = Record<string, any>> { eventListeners: Map<keyof T, EventListener<any> | EventListener<any>[]>; addEventListener<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this; removeEventListener<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this; removeAllListeners(): this; hasEventListener(event: string): boolean; dispatchEvent<K extends keyof T>(event: K, arg: T[K]): boolean; on<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this; once<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>): this; off<K extends keyof T>(event: K, listener: EventListenerValue<T[K]>, options?: EventListenerOptions): this; emit<K extends keyof T>(event: K, arg: T[K]): void; } interface MeasuredParagraph { paragraphIndex: number; left: number; top: number; width: number; height: number; } interface MeasuredFragment { paragraphIndex: number; fragmentIndex: number; left: number; top: number; width: number; height: number; } interface MeasuredCharacter { paragraphIndex: number; fragmentIndex: number; characterIndex: number; newParagraphIndex: number; content: string; left: number; top: number; width: number; height: number; textHeight: number; textWidth: number; } interface measureDOMResult { paragraphs: Paragraph[]; boundingBox: BoundingBox; } declare class Measurer { static notZeroStyles: Set<string>; static pxStyles: Set<string>; protected _toDOMStyle(style: Record<string, any>): Record<string, any>; /** * <section style="..."> * <ul> * <li style="..."> * <span style="...">...</span> * <span>...</span> * </li> * </ul> * </section> */ createDOM(paragraphs: Paragraph[], rootStyle: NormalizedStyle): HTMLElement; measureDOMText(text: Text): { content: string; top: number; left: number; width: number; height: number; }[]; measureDOM(dom: HTMLElement): { paragraphs: MeasuredParagraph[]; fragments: MeasuredFragment[]; characters: MeasuredCharacter[]; }; measureParagraphDOM(paragraphs: Paragraph[], dom: HTMLElement): measureDOMResult; measure(paragraphs: Paragraph[], rootStyle: NormalizedStyle, dom?: HTMLElement): measureDOMResult; } interface TextRenderOptions { view: HTMLCanvasElement; pixelRatio?: number; onContext?: (context: CanvasRenderingContext2D) => void; } interface MeasureResult { paragraphs: Paragraph[]; lineBox: BoundingBox; rawGlyphBox: BoundingBox; glyphBox: BoundingBox; pathBox: BoundingBox; boundingBox: BoundingBox; } declare const textDefaultStyle: NormalizedStyle; interface TextEventMap { update: { text: Text$1; }; measure: { text: Text$1; result: MeasureResult; }; render: { text: Text$1; view: HTMLCanvasElement; pixelRatio: number; }; } declare class Text$1 extends EventEmitter<TextEventMap> { debug: boolean; content: NormalizedTextContent; style: Partial<NormalizedStyle>; effects?: Partial<NormalizedStyle>[]; measureDOM?: HTMLElement; needsUpdate: boolean; computedStyle: NormalizedStyle; paragraphs: Paragraph[]; lineBox: BoundingBox; rawGlyphBox: BoundingBox; glyphBox: BoundingBox; pathBox: BoundingBox; boundingBox: BoundingBox; measurer: Measurer; plugins: Map<string, TextPlugin>; fonts?: Fonts; get fontSize(): number; get isVertical(): boolean; get characters(): Character[]; constructor(options?: TextOptions); set(options?: TextOptions): void; use(plugin: TextPlugin): this; forEachCharacter(handle: (character: Character, ctx: { paragraphIndex: number; fragmentIndex: number; characterIndex: number; }) => void): this; load(): Promise<void>; updateParagraphs(): this; createDOM(): HTMLElement; measure(dom?: HTMLElement | undefined): MeasureResult; getGlyphBox(): BoundingBox; updatePathBox(): this; updateBoundingBox(): this; requestUpdate(): this; update(dom?: HTMLElement | undefined): this; render(options: TextRenderOptions): void; toString(): string; } declare function uploadColors(ctx: CanvasRenderingContext2D, text: Text$1): void; declare function definePlugin(options: TextPlugin): TextPlugin; declare function measureText(options: TextOptions, load: true): Promise<MeasureResult>; declare function measureText(options: TextOptions): MeasureResult; type RenderTextOptions = TextOptions & TextRenderOptions; declare function renderText(options: RenderTextOptions, load: true): Promise<void>; declare function renderText(options: RenderTextOptions): void; declare function background(): TextPlugin; declare function getHighlightStyle(style: NormalizedStyle): NormalizedHighlight; declare function highlight(): TextPlugin; declare function listStyle(): TextPlugin; declare function outline(): TextPlugin; declare function render(): TextPlugin; declare function getTransform2D(text: Text$1, style: Partial<NormalizedStyle>): Matrix3; declare function textDecoration(): TextPlugin; interface SVGLoader { loaded: Map<string, string>; needsLoad: (source: string) => boolean; load: (svg: string) => Promise<void>; } declare function createSVGLoader(): SVGLoader; interface SVGParser { parsed: Map<string, { dom: SVGElement; pathSet: Path2DSet; }>; parse: (svg: string) => { dom: SVGElement; pathSet: Path2DSet; }; } declare function createSVGParser(loader: SVGLoader): SVGParser; interface ValueContext { total: number; fontSize: number; } declare function parseValueNumber(value: string | number, ctx: ValueContext): number; declare function parseColormap(colormap: 'none' | Record<string, string>): Record<string, string>; declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, any>): boolean; declare function isEqualValue(val1: any, val2: any): boolean; declare function hexToRgb(hex: string): string | null; declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined; interface SelectableCharacter { color: string; left: number; top: number; width: number; height: number; content: string; isFirst?: boolean; isLast?: boolean; isLastSelected?: boolean; isCrlf?: boolean; } declare class TextEditor extends HTMLElement { static observedAttributes: string[]; static register(): void; left: number; top: number; width: number; height: number; pixelRatio: number; text: Text$1; composition: boolean; selection: number[]; prevSelection: number[]; protected _oldText: string; $preview: HTMLCanvasElement; $textInput: HTMLTextAreaElement; $cursor: HTMLElement; $cursorInput: HTMLElement; get selectionMinMax(): { min: number; max: number; }; get selectedCharacters(): SelectableCharacter[]; get selectableCharacters(): SelectableCharacter[]; get cursorPosition(): { left: number; top: number; width: number; height: number; color: string; }; constructor(); update(options: TextOptions): void; getTextValue(): string; getContentValue(content: NormalizedTextContent, newString?: string, oldString?: string): NormalizedTextContent; setTextInput(newText: string): void; onInput(): void; protected _timer?: any; onKeydown(e: KeyboardEvent): void; onFocus(e: Event): void; onBlur(): void; findNearest(options: { x: number; y: number; xWeight?: number; yWeight?: number; }): number; updateSelection(): void; updateDOMSelection(): void; onMousedown(e: MouseEvent): void; render(): void; attributeChangedCallback(name: string, oldValue: any, newValue: any): void; } export { Character, Fragment, Measurer, Paragraph, Text$1 as Text, TextEditor, background, createSVGLoader, createSVGParser, definePlugin, drawPath, filterEmpty, getHighlightStyle, getTransform2D, hexToRgb, highlight, isEqualObject, isEqualValue, listStyle, measureText, outline, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, textDefaultStyle, uploadColor, uploadColors }; export type { DrawShapePathsOptions, LinearGradient, MeasureResult, MeasuredCharacter, MeasuredFragment, MeasuredParagraph, RenderTextOptions, SVGLoader, SVGParser, SelectableCharacter, TextEventMap, TextOptions, TextPlugin, TextRenderOptions, measureDOMResult };