import SwiftUI import AppKit import VorleserKit struct BookTextView: NSViewRepresentable { let attributedText: NSAttributedString let highlightRange: Range? let onClickCharacter: (CharacterOffset) -> Void var scrollToOffset: CharacterOffset? func makeNSView(context: Context) -> NSScrollView { let scrollView = NSTextView.scrollableTextView() let textView = scrollView.documentView as! NSTextView textView.isEditable = false textView.isSelectable = false 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) { guard let textView = scrollView.documentView as? NSTextView else { return } let highlighted = NSMutableAttributedString(attributedString: attributedText) if let range = highlightRange, range.lowerBound >= 0, range.upperBound <= attributedText.length { let nsRange = NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound) highlighted.addAttribute(.backgroundColor, value: NSColor.systemYellow.withAlphaComponent(0.3), range: nsRange) } textView.textStorage?.setAttributedString(highlighted) if let range = highlightRange, range.lowerBound >= 0, range.upperBound <= attributedText.length { let nsRange = NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound) textView.scrollRangeToVisible(nsRange) } if let offset = scrollToOffset, offset >= 0, offset < attributedText.length { let nsRange = NSRange(location: offset, length: 1) textView.scrollRangeToVisible(nsRange) } } 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) } } } }