From d34d3e92daad53fd10cba1438000ba0ab8ee2ef5 Mon Sep 17 00:00:00 2001 From: Theo Weijmer Date: Thu, 1 Oct 2026 15:53:15 +0200 Subject: [PATCH] fix: no-op unknown removal, earlier-duplicate editor check, list focus for delete/undo Co-Authored-By: Claude Sonnet 5.5 --- Sources/Sst/DictionaryView.swift | 16 ++++++++++++++-- Sources/Sst/HistoryView.swift | 4 ++++ Sources/SstData/ViewSupport.swift | 10 +++++++++- Tests/SstDataTests/ViewSupportTests.swift | 17 +++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Sources/Sst/DictionaryView.swift b/Sources/Sst/DictionaryView.swift index 43d5228..40a9952 100644 --- a/Sources/Sst/DictionaryView.swift +++ b/Sources/Sst/DictionaryView.swift @@ -21,6 +21,7 @@ struct DictionaryView: View { @State private var selection: UUID? @State private var editing: EditorTarget? @FocusState private var searchFocused: Bool + @FocusState private var listFocused: Bool var body: some View { VStack(spacing: Layout.panelGap) { @@ -77,14 +78,25 @@ struct DictionaryView: View { ForEach(list.visibleRows) { row in DictionaryRow(row: row, isSelected: selection == row.id) .onTapGesture(count: 2) { editing = .existing(row.id) } - .onTapGesture { selection = row.id } + .onTapGesture { + selection = row.id + listFocused = true + } } } } } .focusable() + .focused($listFocused) + .focusEffectDisabled() .onDeleteCommand { - if let id = selection { list.remove(id: id) } + if let id = selection { + list.remove(id: id) + selection = nil + } + } + .onChange(of: list.rows) { _, rows in + if let s = selection, !rows.contains(where: { $0.id == s }) { selection = nil } } .onKeyPress(KeyEquivalent("z"), phases: .down) { press in guard press.modifiers == .command, list.canUndo else { return .ignored } diff --git a/Sources/Sst/HistoryView.swift b/Sources/Sst/HistoryView.swift index 3d7b331..e2ec19a 100644 --- a/Sources/Sst/HistoryView.swift +++ b/Sources/Sst/HistoryView.swift @@ -10,6 +10,7 @@ struct HistoryView: View { @EnvironmentObject private var model: AppModel @ObservedObject var list: HistoryViewModel @FocusState private var searchFocused: Bool + @FocusState private var listFocused: Bool var body: some View { VStack(spacing: Layout.panelGap) { @@ -47,6 +48,9 @@ struct HistoryView: View { } } .focusable() + .focused($listFocused) + .focusEffectDisabled() + .onChange(of: list.selection) { _, _ in listFocused = true } .onDeleteCommand { if let id = list.selection { list.delete(id: id) } } diff --git a/Sources/SstData/ViewSupport.swift b/Sources/SstData/ViewSupport.swift index 8844642..c34fa91 100644 --- a/Sources/SstData/ViewSupport.swift +++ b/Sources/SstData/ViewSupport.swift @@ -134,7 +134,14 @@ public final class DictionaryViewModel: ObservableObject { /// Live feedback for the editor; `id` is the entry being edited (nil for a new one). public func warnings(for kind: DictionaryEntry.Kind, editing id: UUID?) -> [EntryWarning] { - EntryWarnings.check(kind, among: store.entries.filter { $0.id != id }, knowledge: knowledge) + let entries = store.entries + let others: [DictionaryEntry] + if let id, let index = entries.firstIndex(where: { $0.id == id }) { + others = Array(entries[.. A\nCloud-Code => B\n") + let first = store.entries[0] + let second = store.entries[1] + #expect(!model.warnings(for: first.kind, editing: first.id).contains { $0.level == .error }) + #expect(model.warnings(for: second.kind, editing: second.id).contains { $0.level == .error }) + #expect(model.warnings(for: first.kind, editing: nil).contains { $0.level == .error }) + } }