import AppKit import SwiftUI public struct TextView: NSViewRepresentable { @Binding var text: String var font: NSFont? public init( text: Binding ) { self._text = text } public class Coordinator: NSObject, NSTextViewDelegate { var parent: TextView init(_ parent: TextView) { self.parent = parent } public func textDidChange(_ notification: Notification) { guard let textView = notification.object as? NSTextView else { return } parent.text = textView.string } } public func makeCoordinator() -> Coordinator { Coordinator(self) } public func makeNSView(context: Context) -> NSScrollView { let nsView = NSTextView.scrollableTextView() let textView = nsView.documentView as! NSTextView textView.delegate = context.coordinator textView.textContainerInset = .init(width: 10.0, height: 10.0) nsView.documentView = textView return nsView } public func updateNSView(_ nsView: NSScrollView, context: Context) { (nsView.documentView as! NSTextView).string = text } public func sizeThatFits(_ proposal: ProposedViewSize, nsView: NSScrollView, context: Context) -> CGSize? { let textView = nsView.documentView as! NSTextView guard let textLayoutManager = textView.textLayoutManager else { return nil } let rect = textLayoutManager.usageBoundsForTextContainer print(rect) let width = proposal.width ?? 0.0 let height = rect.height + textView.textContainerInset.height * 2 return CGSize(width: width, height: height) } } struct MainView: View { @State private var text: String = "This is sample text.\nHello, World!" var body: some View { VStack { ScrollView { LazyVStack { ForEach(Array(0..<100), id: \.self) { id in Text("\(id)") } } } .border(.blue) TextView(text: $text) .border(.red) .fixedSize(horizontal: false, vertical: true) } .scenePadding() } } #Preview { MainView() }