Reputation: 49
I am trying to create Markdown in TextEditor using NSViewRepresentable, it is working fine, but the binding from NSViewRepresentable seems to confuse SwiftData. It will update properly until I select one item on the list, after that everything I write will be updated on the first item I clicked, even after selecting other item on the list. This won't happen if I link to default TextEditor view. Am I doing something wrong, or it's a bug?
Here is the "Content View":
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query(sort: \Entry.timestamp, order: .reverse, animation: .default) private var entries: [Entry]
@State var selection: Entry? = nil
var body: some View {
NavigationSplitView {
List(selection: $selection) {
ForEach(entries) { entry in
@Bindable var bindableEntry = entry
NavigationLink {
RichTextEditor(text: $bindableEntry.text)
} label: {
ListItemView(entry: entry, isFavorite: $bindableEntry.isFavorite)
.keyboardShortcut(.delete, modifiers: [])
.onDeleteCommand(perform: {
delete(entry)
})....
}
And here is the NSViewRepresentable:
struct RichTextEditor: NSViewRepresentable {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func makeNSView(context: Context) -> NSScrollView {
let scrollView = MyTextView.scrollableTextView()
let textView = scrollView.documentView as! MyTextView
textView.delegate = context.coordinator
return scrollView
}
func updateNSView(_ nsView: NSScrollView, context: Context) {
let textView = nsView.documentView as! MyTextView
let selectedRanges = textView.selectedRanges
textView.string = text
textView.selectedRanges = selectedRanges
}
func makeCoordinator() -> Coordinator {
return Coordinator(text: $text)
}
class Coordinator: NSObject, NSTextViewDelegate {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func textDidChange(_ notification: Notification) {
if let textView = notification.object as? MyTextView {
print("textDidChange")
let selectedRanges = textView.selectedRanges
text = textView.string
textView.selectedRanges = selectedRanges
}
}
}
}
It is wrapped on a NSScrollView because it NSTextView doesn't have scroll, but the same thing happens if I use a NSTextView.
I think is something related to the text = textView.string
in "textDidChange" on "Coordinator", I think it's strange that I have to set the value of a binding property, but it won't save it in swift data if I don't do it and I don't know how I could make it different.
Upvotes: 1
Views: 192