# @react-pdf/textkit > An advanced text layout framework A comprehensive text layout engine for react-pdf. Handles complex text rendering including bidirectional text, line breaking, hyphenation, justification, font substitution, and text decoration. ## Acknowledges This project is a fork of [textkit](https://github.com/foliojs/textkit) by @devongovett and continued under the scope of this project since it has react-pdf specific features. Any recongnition should go to him and the original project mantainers. ## Installation ```bash yarn add @react-pdf/textkit ``` ## Usage ```js import layoutEngine, { bidi, linebreaker, justification, textDecoration, scriptItemizer, wordHyphenation, fontSubstitution, fromFragments, } from '@react-pdf/textkit'; // Create engines configuration const engines = { bidi: bidi(), linebreaker: linebreaker({}), justification: justification({}), textDecoration: textDecoration(), scriptItemizer: scriptItemizer(), wordHyphenation: wordHyphenation(), fontSubstitution: fontSubstitution(), }; // Create attributed string from fragments const attributedString = fromFragments([ { string: 'Hello ', attributes: { fontSize: 12, font: [myFont] } }, { string: 'World!', attributes: { fontSize: 12, font: [myFont] } }, ]); // Define container const container = { x: 0, y: 0, width: 400, height: 600, }; // Layout text const layout = layoutEngine(engines); const paragraphs = layout(attributedString, container, {}); ``` ## Layout Process The layout engine processes text through the following steps: 1. Split into paragraphs 2. Get bidi runs and paragraph direction 3. Font substitution - map to resolved font runs 4. Script itemization 5. Font shaping - text to glyphs 6. Line breaking 7. Bidi reordering 8. Justification 9. Get a list of rectangles by intersecting path, line, and exclusion paths 10. Perform line breaking to get acceptable break points for each fragment 11. Ellipsize line if necessary 12. Bidi reordering 13. Justification ## Engines The layout engine uses several specialized engines that can be customized: ### bidi Handles bidirectional text analysis using the Unicode Bidirectional Algorithm. Determines text direction for mixed LTR/RTL content. ```js import { bidi } from '@react-pdf/textkit'; const bidiEngine = bidi(); const result = bidiEngine(attributedString); ``` ### linebreaker Performs line breaking using the Knuth-Plass algorithm with fallback to best-fit. Handles hyphenation points and produces optimal line breaks. ```js import { linebreaker } from '@react-pdf/textkit'; const linebreakerEngine = linebreaker({ tolerance: 4, hyphenationPenalty: 100, }); ``` ### justification Adjusts character and word spacing to achieve justified text alignment. Based on Apple's justification algorithm. ```js import { justification } from '@react-pdf/textkit'; const justificationEngine = justification({ expandCharFactor: { before: 0, after: 0 }, shrinkCharFactor: { before: 0, after: 0 }, expandWhitespaceFactor: { before: 0.5, after: 0.5 }, shrinkWhitespaceFactor: { before: 0.5, after: 0.5 }, }); ``` ### fontSubstitution Automatically substitutes fonts when the primary font doesn't have glyphs for certain characters. Picks the best font from the font stack. ```js import { fontSubstitution } from '@react-pdf/textkit'; const fontSubstitutionEngine = fontSubstitution(); ``` ### scriptItemizer Identifies Unicode script runs in text (Latin, Arabic, Han, etc.) to enable proper font selection and shaping. ```js import { scriptItemizer } from '@react-pdf/textkit'; const scriptItemizerEngine = scriptItemizer(); ``` ### wordHyphenation Provides word hyphenation using language-specific patterns. Supports soft hyphens and custom hyphenation callbacks. ```js import { wordHyphenation } from '@react-pdf/textkit'; const wordHyphenationEngine = wordHyphenation(); const syllables = wordHyphenationEngine('hyphenation'); // ['hy', 'phen', 'a', 'tion'] ``` ### textDecoration Generates decoration lines (underline, strikethrough) for styled text runs. ```js import { textDecoration } from '@react-pdf/textkit'; const textDecorationEngine = textDecoration(); ``` ## API Reference ### layoutEngine(engines) Creates a layout function with the specified engines. ```js const layout = layoutEngine(engines); const paragraphs = layout(attributedString, container, options); ``` ### fromFragments(fragments) Creates an AttributedString from text fragments. ```js import { fromFragments } from '@react-pdf/textkit'; const attributedString = fromFragments([ { string: 'Hello ', attributes: { fontSize: 14 } }, { string: 'World!', attributes: { fontSize: 14, color: 'blue' } }, ]); ``` ## Types ### AttributedString The main data structure representing styled text: ```ts type AttributedString = { string: string; runs: Run[]; syllables?: string[]; box?: Rect; decorationLines?: DecorationLine[]; }; ``` ### Run A styled segment of text: ```ts type Run = { start: number; end: number; attributes: Attributes; glyphs?: Glyph[]; positions?: Position[]; stringIndices?: number[]; glyphIndices?: number[]; }; ``` ### Attributes Style attributes for text runs: ```ts type Attributes = { align?: string; alignLastLine?: string; attachment?: Attachment; backgroundColor?: string; bidiLevel?: number; characterSpacing?: number; color?: string; direction?: 'rtl' | 'ltr'; features?: unknown[]; fill?: boolean; font?: Font[]; fontSize?: number; hangingPunctuation?: boolean; hyphenationFactor?: number; indent?: number; justificationFactor?: number; lineHeight?: number; lineSpacing?: number; link?: string; margin?: number; marginLeft?: number; marginRight?: number; opacity?: number; padding?: number; paddingTop?: number; paragraphSpacing?: number; scale?: number; script?: unknown; shrinkFactor?: number; strike?: boolean; strikeColor?: string; strikeStyle?: string; stroke?: boolean; underline?: boolean; underlineColor?: string; underlineStyle?: string; verticalAlign?: string; wordSpacing?: number; yOffset?: number; }; ``` ### Container The area where text will be laid out: ```ts type Container = { x: number; y: number; width: number; height: number; truncateMode?: 'ellipsis'; maxLines?: number; excludeRects?: Rect[]; }; ``` ### Rect A rectangle definition: ```ts type Rect = { x: number; y: number; width: number; height: number; }; ``` ### Fragment Input format for creating attributed strings: ```ts type Fragment = { string: string; attributes?: Attributes; }; ``` ### LayoutOptions Options for the layout process: ```ts type LayoutOptions = { hyphenationCallback?: ( word: string | null, fallback: (word: string | null) => string[], ) => string[]; tolerance?: number; hyphenationPenalty?: number; expandCharFactor?: JustificationFactor; shrinkCharFactor?: JustificationFactor; expandWhitespaceFactor?: JustificationFactor; shrinkWhitespaceFactor?: JustificationFactor; }; ``` ### Engines The engines configuration object: ```ts type Engines = { bidi: ReturnType; linebreaker: ReturnType; justification: ReturnType; fontSubstitution: ReturnType; scriptItemizer: ReturnType; textDecoration: ReturnType; wordHyphenation?: ReturnType; }; ``` ## License MIT