diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2026-06-18 23:53:25 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <jj@r.bdr.sh> | 2026-06-19 17:56:23 +0200 |
| commit | 49b0f4a3fb0064313d16782839865b763ef760ce (patch) | |
| tree | a58439f1433de9ff66dc0be28f025afe56e79cfe /Sources/NorgUI/Math/NorgInlineText.swift | |
| parent | cb91a73bfc845d74c3e4d1115bce5dfed10d456d (diff) | |
Support Math rendering1.2.0
Diffstat (limited to 'Sources/NorgUI/Math/NorgInlineText.swift')
| -rw-r--r-- | Sources/NorgUI/Math/NorgInlineText.swift | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/Sources/NorgUI/Math/NorgInlineText.swift b/Sources/NorgUI/Math/NorgInlineText.swift new file mode 100644 index 0000000..0d607f5 --- /dev/null +++ b/Sources/NorgUI/Math/NorgInlineText.swift @@ -0,0 +1,52 @@ +import NorgKit +import SwiftUI + +/// Renders a run of inline spans as a single `Text`, splicing in rendered +/// images for `.math` spans when a ``NorgMathRenderer`` is configured. +struct NorgInlineText: View { + @Environment(\.norgTheme) private var theme + + let spans: [InlineSpan] + var baseFont: Font = .body + + @State private var images: [Int: NorgMathImage] = [:] + + var body: some View { + text + .task(id: renderKey) { await renderMath() } + } + + private var text: Text { + var result = Text(verbatim: "") + for (index, span) in spans.enumerated() { + if span.styles.contains(.math), let image = images[index] { + result = result + Text(image.swiftUIImage).baselineOffset(-image.descent) + } else { + result = result + Text(AttributedString(norg: [span], baseFont: baseFont, theme: theme)) + } + } + return result + } + + private var mathSpans: [(offset: Int, element: InlineSpan)] { + spans.enumerated().filter { $0.element.styles.contains(.math) }.map { ($0.offset, $0.element) } + } + + private var renderKey: String { + mathSpans.map { "\($0.offset):\($0.element.text)" }.joined(separator: "|") + + "@\(theme.mathFontSize)" + } + + @MainActor + private func renderMath() async { + guard let renderer = theme.mathRenderer, !mathSpans.isEmpty else { return } + for (index, span) in mathSpans where images[index] == nil { + if let image = await renderer.render( + latex: span.text, mode: .inline, fontSize: theme.mathFontSize, color: nil) + { + images[index] = image + } + await Task.yield() + } + } +} |