From ddba120da5d847849a1e06f39ea0bbb0e07430e5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 09:39:43 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20[Dynamic=20Context=20?= =?UTF-8?q?for=20Repeated=20List=20Actions]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 💡 What: Added dynamic context to accessibility labels and tooltips for list actions like Edit, Delete, and Remove. - 🎯 Why: When using generic actions in repeated list rows, screen reader users hear only the action without context (e.g., "Edit, button. Delete, button."). Adding the item name (e.g., "Edit MacroName") makes navigation unambiguous. - ♿ Accessibility: Improved screen reader experience in MacroListView, ScriptListView, MacroEditorSheet, and ActionMappingEditor. Co-authored-by: NSEvent <44446865+NSEvent@users.noreply.github.com> --- .Jules/palette.md | 3 +++ .../Views/Macros/MacroEditorSheet.swift | 4 ++-- .../Views/Macros/MacroListView.swift | 12 ++++++------ .../Views/MainWindow/ActionMappingEditor.swift | 4 ++-- .../Views/Scripts/ScriptListView.swift | 10 ++++++---- 5 files changed, 19 insertions(+), 14 deletions(-) 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)