Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 3 additions & 27 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,3 @@
## 2024-06-03 - Missing tooltips and accessibility on list item actions
**Learning:** Icon-only buttons used for item actions (like 'Edit', 'Delete', 'Remove') within list views often lack tooltips and accessibility labels. This omission makes the UI ambiguous for mouse users on macOS and inaccessible to screen readers.
**Action:** Always add `.help("Action Name")` and `.accessibilityLabel("Action Name Item Type")` to icon-only buttons, especially those located at the trailing edge of list rows.

## 2024-11-20 - Ensure Symmetry in Accessibility and Tooltips for SwiftUI Icon Buttons
**Learning:** In macOS SwiftUI applications, icon-only buttons often have either `.help()` (for hover tooltips) or `.accessibilityLabel()` (for VoiceOver), but frequently lack both. Both are necessary because they serve different user interaction modelsβ€”`.help` for visual hover feedback and `.accessibilityLabel` for screen readers.
**Action:** When adding or reviewing icon-only buttons in SwiftUI, always ensure symmetry by defining both `.help("Description")` and `.accessibilityLabel("Description")` to cover all accessibility and usability vectors.
## 2026-06-06 - Ensure Symmetry in Accessibility and Tooltips for SwiftUI Icon Buttons
**Learning:** In macOS SwiftUI applications, icon-only buttons often have either `.help()` (for hover tooltips) or `.accessibilityLabel()` (for VoiceOver), but frequently lack both. Both are necessary because they serve different user interaction modelsβ€”`.help` for visual hover feedback and `.accessibilityLabel` for screen readers.
**Action:** When adding or reviewing icon-only buttons in SwiftUI, always ensure symmetry by defining both `.help("Description")` and `.accessibilityLabel("Description")` to cover all accessibility and usability vectors.

## 2024-05-19 - [Missing Accessibility on Dynamic Form Dictionary Buttons]
**Learning:** Icon-only buttons used for adding/removing items in dynamic dictionary forms (e.g., webhook headers with `plus.circle.fill` and `minus.circle.fill`) are frequent vectors for missing accessibility labels and tooltips, because they are often implemented with plain button styles without considering screen reader context.
**Action:** Always verify that inline addition/removal buttons in repeated form elements have explicit `.help()` and `.accessibilityLabel()` modifiers attached to them to ensure they can be understood and navigated accurately by all users.
## 2024-05-14 - [Icon Button Accessibility Gap]
**Learning:** In standard SwiftUI development for macOS, icon-only buttons (`Image(systemName: ...)`) are frequently missing `.help()` (for hover tooltips) and `.accessibilityLabel()` (for VoiceOver). Several core navigation components (like Layer tabs and Sidebar buttons) suffered from this pattern.
**Action:** Always verify that every `Button` wrapping an `Image` has both `.help()` and `.accessibilityLabel()` strings defined, unless explicitly marked as decorative.

## 2024-06-08 - Ensure Symmetry in Accessibility and Tooltips for SwiftUI Icon Buttons
**Learning:** Verified the necessity of ensuring full symmetry in accessibility and tooltips for icon-only buttons (`Image(systemName: ...)`). These buttons often get one but not the other (`.help()` without `.accessibilityLabel()`, or vice-versa), which causes poor UX for some group of users.
**Action:** When adding or modifying icon buttons, always apply both `.help("Action")` and `.accessibilityLabel("Action")`.
## 2026-06-16 - Ensure Symmetry in Accessibility and Tooltips for SwiftUI Icon Buttons
**Learning:** Verified the necessity of ensuring full symmetry in accessibility and tooltips for icon-only buttons (`Image(systemName: ...)`). These buttons often get one but not the other (`.help()` without `.accessibilityLabel()`, or vice-versa), which causes poor UX for some group of users.
**Action:** When adding or modifying icon buttons, always apply both `.help("Action")` and `.accessibilityLabel("Action")`.
## 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-06-25 - [Accessibility Context in Lists]
**Learning:** In repeated lists or loops, icon-only buttons with generic `.accessibilityLabel()` or `.help()` (like "Edit" or "Delete") lose context, confusing screen reader users.
**Action:** Always inject dynamic context from the current item (e.g., `item.displayName`) into the accessibility label and help modifiers to disambiguate the action (e.g., "Edit Home Button").
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,16 @@ struct ChordRow: View {
.foregroundColor(.accentColor)
}
.buttonStyle(.borderless)
.help("Edit")
.accessibilityLabel("Edit")
.help("Edit \(chord.actionDisplayString)")
.accessibilityLabel("Edit \(chord.actionDisplayString)")

Button(action: onDelete) {
Image(systemName: "trash")
.foregroundColor(.red.opacity(0.8))
}
.buttonStyle(.borderless)
.help("Delete")
.accessibilityLabel("Delete")
.help("Delete \(chord.actionDisplayString)")
.accessibilityLabel("Delete \(chord.actionDisplayString)")
Comment on lines +118 to +127

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚑ Quick win

Use the row-specific trigger text in these labels.

actionDisplayString is still an action descriptor, so repeated chord/sequence rows can end up with the same Edit/Delete label (Macro, Script, etc.). Prefer the row identifiers already available here (buttonsDisplayString / stepsDisplayString) so assistive tech can distinguish which item is being edited or deleted.

Suggested fix
-                .help("Edit \(chord.actionDisplayString)")
-                .accessibilityLabel("Edit \(chord.actionDisplayString)")
+                .help("Edit \(chord.buttonsDisplayString)")
+                .accessibilityLabel("Edit \(chord.buttonsDisplayString)")

-                .help("Delete \(chord.actionDisplayString)")
-                .accessibilityLabel("Delete \(chord.actionDisplayString)")
+                .help("Delete \(chord.buttonsDisplayString)")
+                .accessibilityLabel("Delete \(chord.buttonsDisplayString)")
-                .help("Edit \(sequence.actionDisplayString)")
-                .accessibilityLabel("Edit \(sequence.actionDisplayString)")
+                .help("Edit \(sequence.stepsDisplayString)")
+                .accessibilityLabel("Edit \(sequence.stepsDisplayString)")

-                .help("Delete \(sequence.actionDisplayString)")
-                .accessibilityLabel("Delete \(sequence.actionDisplayString)")
+                .help("Delete \(sequence.stepsDisplayString)")
+                .accessibilityLabel("Delete \(sequence.stepsDisplayString)")

Also applies to: 264-273

πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@XboxControllerMapper/XboxControllerMapper/Views/MainWindow/ChordSequenceListViews.swift`
around lines 118 - 127, The Edit/Delete help and accessibility labels in the row
actions are using action-level text, which can repeat across rows. Update the
labels in the row action view(s) around the Edit/Delete buttons to use the
row-specific trigger text already available there, such as buttonsDisplayString
or stepsDisplayString, and apply the same change in the other matching section
so assistive tech can distinguish each row.

}
}
.padding(.horizontal, 12)
Expand Down Expand Up @@ -261,16 +261,16 @@ struct SequenceRow: View {
.foregroundColor(.accentColor)
}
.buttonStyle(.borderless)
.help("Edit")
.accessibilityLabel("Edit")
.help("Edit \(sequence.actionDisplayString)")
.accessibilityLabel("Edit \(sequence.actionDisplayString)")

Button(action: onDelete) {
Image(systemName: "trash")
.foregroundColor(.red.opacity(0.8))
}
.buttonStyle(.borderless)
.help("Delete")
.accessibilityLabel("Delete")
.help("Delete \(sequence.actionDisplayString)")
.accessibilityLabel("Delete \(sequence.actionDisplayString)")
}
}
.padding(.horizontal, 12)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ struct CommandWheelActionRow: View {
}
.buttonStyle(.plain)
.foregroundColor(.secondary)
.help("Edit")
.accessibilityLabel("Edit Command Wheel Action")
.help("Edit \(action.displayName.isEmpty ? "Unnamed" : action.displayName)")
.accessibilityLabel("Edit \(action.displayName.isEmpty ? "Unnamed" : action.displayName)")

// Delete button
Button(action: onDelete) {
Expand All @@ -186,8 +186,8 @@ struct CommandWheelActionRow: View {
}
.buttonStyle(.plain)
.foregroundColor(.secondary)
.help("Delete")
.accessibilityLabel("Delete Command Wheel Action")
.help("Delete \(action.displayName.isEmpty ? "Unnamed" : action.displayName)")
.accessibilityLabel("Delete \(action.displayName.isEmpty ? "Unnamed" : action.displayName)")
}
.padding(.vertical, 4)
.padding(.horizontal, 6)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ struct GestureRow: View {
.foregroundColor(.accentColor)
}
.buttonStyle(.borderless)
.help("Edit")
.accessibilityLabel("Edit")
.help("Edit \(gestureType.displayName)")
.accessibilityLabel("Edit \(gestureType.displayName)")

if mapping?.hasAction == true {
Button(action: onClear) {
Image(systemName: "trash")
.foregroundColor(.red.opacity(0.8))
}
.buttonStyle(.borderless)
.help("Clear")
.accessibilityLabel("Clear")
.help("Clear \(gestureType.displayName)")
.accessibilityLabel("Clear \(gestureType.displayName)")
}
}
}
Expand Down
Loading