diff --git a/.Jules/palette.md b/.Jules/palette.md index f61603c8..dcc41caa 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -25,3 +25,6 @@ ## 2026-06-23 - [SwiftUI Button Accessibility] **Learning:** Found a pattern where SwiftUI icon-only buttons or minimal UI elements were given `.help()` modifiers for hover tooltips but lacked `.accessibilityLabel()` modifiers for screen readers. **Action:** When adding `.help()` to buttons, always pair it with a corresponding `.accessibilityLabel()` to ensure full accessibility. +## 2024-11-20 - [Dynamic Context for Repeated List Actions] +**Learning:** When using generic actions like "Edit" or "Delete" in repeated list rows (e.g., Macros, Scripts), screen reader users hear only the action without context (e.g., "Edit, button. Delete, button."). +**Action:** Always inject dynamic context (e.g., the item's name) into `.accessibilityLabel()` and `.help()` modifiers for repeated list actions to ensure disambiguation for screen readers (e.g., `.accessibilityLabel("Edit \(item.name)")`). diff --git a/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroEditorSheet.swift b/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroEditorSheet.swift index cc90d386..706ed455 100644 --- a/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroEditorSheet.swift +++ b/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroEditorSheet.swift @@ -649,8 +649,8 @@ struct MacroStepEditorSheet: View { Image(systemName: "minus.circle.fill").foregroundColor(.red) } .buttonStyle(.plain) - .help("Remove header") - .accessibilityLabel("Remove header") + .help("Remove header \(key)") + .accessibilityLabel("Remove header \(key)") } } HStack { diff --git a/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroListView.swift b/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroListView.swift index 211ecb1e..88cd22d2 100644 --- a/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroListView.swift +++ b/XboxControllerMapper/XboxControllerMapper/Views/Macros/MacroListView.swift @@ -155,8 +155,8 @@ struct SharedMacroRow: View { .foregroundColor(.accentColor) } .buttonStyle(.borderless) - .help("Edit in shared library") - .accessibilityLabel("Edit in shared library") + .help("Edit \(macro.name) in shared library") + .accessibilityLabel("Edit \(macro.name) in shared library") } .padding(.horizontal, 12) .padding(.vertical, 8) @@ -206,16 +206,16 @@ struct MacroRow: View { .foregroundColor(.accentColor) } .buttonStyle(.borderless) - .help("Edit") - .accessibilityLabel("Edit") + .help("Edit \(macro.name)") + .accessibilityLabel("Edit \(macro.name)") Button(action: onDelete) { Image(systemName: "trash") .foregroundColor(.red.opacity(0.8)) } .buttonStyle(.borderless) - .help("Delete") - .accessibilityLabel("Delete") + .help("Delete \(macro.name)") + .accessibilityLabel("Delete \(macro.name)") } } .padding(.horizontal, 12) diff --git a/XboxControllerMapper/XboxControllerMapper/Views/MainWindow/ActionMappingEditor.swift b/XboxControllerMapper/XboxControllerMapper/Views/MainWindow/ActionMappingEditor.swift index 13d34e4f..fb1d7188 100644 --- a/XboxControllerMapper/XboxControllerMapper/Views/MainWindow/ActionMappingEditor.swift +++ b/XboxControllerMapper/XboxControllerMapper/Views/MainWindow/ActionMappingEditor.swift @@ -384,8 +384,8 @@ struct ActionMappingEditor: View { .foregroundColor(.red) } .buttonStyle(.plain) - .help("Remove header") - .accessibilityLabel("Remove header") + .help("Remove header \(key)") + .accessibilityLabel("Remove header \(key)") } } diff --git a/XboxControllerMapper/XboxControllerMapper/Views/Scripts/ScriptListView.swift b/XboxControllerMapper/XboxControllerMapper/Views/Scripts/ScriptListView.swift index 40c6f5ff..4ed0c100 100644 --- a/XboxControllerMapper/XboxControllerMapper/Views/Scripts/ScriptListView.swift +++ b/XboxControllerMapper/XboxControllerMapper/Views/Scripts/ScriptListView.swift @@ -217,21 +217,23 @@ struct ScriptRow: View { .onTapGesture { onEdit() } HStack(spacing: 12) { + let displayName = script.name.isEmpty ? "Untitled Script" : script.name + Button(action: onEdit) { Image(systemName: "pencil") .foregroundColor(.accentColor) } .buttonStyle(.borderless) - .help("Edit") - .accessibilityLabel("Edit") + .help("Edit \(displayName)") + .accessibilityLabel("Edit \(displayName)") Button(action: onDelete) { Image(systemName: "trash") .foregroundColor(.red.opacity(0.8)) } .buttonStyle(.borderless) - .help("Delete") - .accessibilityLabel("Delete") + .help("Delete \(displayName)") + .accessibilityLabel("Delete \(displayName)") } } .padding(.horizontal, 12)