import { Box, BoxModel, Editor, TLDefaultVerticalAlignStyle, TLMeasureTextSpanOpts, } from '@tldraw/editor' function correctSpacesToNbsp(input: string) { return input.replace(/\s/g, '\xa0') } export interface TLCreateTextJsxFromSpansOpts extends TLMeasureTextSpanOpts { verticalTextAlign: TLDefaultVerticalAlignStyle offsetX: number offsetY: number stroke?: string strokeWidth?: number fill?: string } /** Get an SVG element for a text shape. */ export function createTextJsxFromSpans( editor: Editor, spans: { text: string; box: BoxModel }[], opts: TLCreateTextJsxFromSpansOpts ) { const { padding = 0 } = opts if (spans.length === 0) return null const bounds = Box.From(spans[0].box) for (const { box } of spans) { bounds.union(box) } const offsetX = padding + (opts.offsetX ?? 0) const offsetY = (opts.offsetY ?? 0) + opts.fontSize / 2 + (opts.verticalTextAlign === 'start' ? padding : opts.verticalTextAlign === 'end' ? opts.height - padding - bounds.height : (Math.ceil(opts.height) - bounds.height) / 2) // Create text span elements for each word let currentLineTop = null const children = [] for (const { text, box } of spans) { // if we broke a line, add a line break span. This helps tools like // figma import our exported svg correctly const didBreakLine = currentLineTop !== null && box.y > currentLineTop if (didBreakLine) { children.push( {'\n'} ) } children.push( {correctSpacesToNbsp(text)} ) currentLineTop = box.y } return ( {children} ) }