File size: 2,293 Bytes
064bfd6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | import type { DOMElement } from './dom.js'
import type { TextStyles } from './styles.js'
/**
* A segment of text with its associated styles.
* Used for structured rendering without ANSI string transforms.
*/
export type StyledSegment = {
text: string
styles: TextStyles
hyperlink?: string
}
/**
* Squash text nodes into styled segments, propagating styles down through the tree.
* This allows structured styling without relying on ANSI string transforms.
*/
export function squashTextNodesToSegments(
node: DOMElement,
inheritedStyles: TextStyles = {},
inheritedHyperlink?: string,
out: StyledSegment[] = [],
): StyledSegment[] {
const mergedStyles = node.textStyles
? { ...inheritedStyles, ...node.textStyles }
: inheritedStyles
for (const childNode of node.childNodes) {
if (childNode === undefined) {
continue
}
if (childNode.nodeName === '#text') {
if (childNode.nodeValue.length > 0) {
out.push({
text: childNode.nodeValue,
styles: mergedStyles,
hyperlink: inheritedHyperlink,
})
}
} else if (
childNode.nodeName === 'ink-text' ||
childNode.nodeName === 'ink-virtual-text'
) {
squashTextNodesToSegments(
childNode,
mergedStyles,
inheritedHyperlink,
out,
)
} else if (childNode.nodeName === 'ink-link') {
const href = childNode.attributes['href'] as string | undefined
squashTextNodesToSegments(
childNode,
mergedStyles,
href || inheritedHyperlink,
out,
)
}
}
return out
}
/**
* Squash text nodes into a plain string (without styles).
* Used for text measurement in layout calculations.
*/
function squashTextNodes(node: DOMElement): string {
let text = ''
for (const childNode of node.childNodes) {
if (childNode === undefined) {
continue
}
if (childNode.nodeName === '#text') {
text += childNode.nodeValue
} else if (
childNode.nodeName === 'ink-text' ||
childNode.nodeName === 'ink-virtual-text'
) {
text += squashTextNodes(childNode)
} else if (childNode.nodeName === 'ink-link') {
text += squashTextNodes(childNode)
}
}
return text
}
export default squashTextNodes
|