import SwiftUI import AppKit import VorleserKit struct MacReadingTextView: NSViewRepresentable { let text: String let highlightedRange: Range? let onClickCharacter: (CharacterOffset) -> Void func makeNSView(context: Context) -> NSScrollView { let scrollView = NSTextView.scrollableTextView() let textView = scrollView.documentView as! NSTextView textView.isEditable = false textView.isSelectable = false textView.font = .preferredFont(forTextStyle: .body) textView.textContainerInset = NSSize(width: 16, height: 16) let click = NSClickGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleClick(_:))) textView.addGestureRecognizer(click) context.coordinator.textView = textView return scrollView } func updateNSView(_ scrollView: NSScrollView, context: Context) { let textView = scrollView.documentView as! NSTextView let attributed = NSMutableAttributedString( string: text, attributes: [ .font: NSFont.preferredFont(forTextStyle: .body), .foregroundColor: NSColor.textColor, ] ) if let range = highlightedRange, range.lowerBound >= 0, range.upperBound <= text.count { let nsRange = NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound) attributed.addAttribute(.backgroundColor, value: NSColor.systemYellow.withAlphaComponent(0.3), range: nsRange) } textView.textStorage?.setAttributedString(attributed) } func makeCoordinator() -> Coordinator { Coordinator(onClickCharacter: onClickCharacter) } class Coordinator: NSObject { weak var textView: NSTextView? let onClickCharacter: (CharacterOffset) -> Void init(onClickCharacter: @escaping (CharacterOffset) -> Void) { self.onClickCharacter = onClickCharacter } @objc func handleClick(_ gesture: NSClickGestureRecognizer) { guard let textView else { return } let point = gesture.location(in: textView) let characterIndex = textView.characterIndexForInsertion(at: point) if characterIndex < textView.string.count { onClickCharacter(characterIndex) } } } }