@@ -31,6 +31,7 @@ internal final class EditorTabInteractionView: NSView {
3131 /// the content.
3232 internal var onRowCountChanged : ( ( Int ) -> Void ) ?
3333
34+ private var isResolvingAccessibilityHit = false
3435 private var hoverTrackingArea : NSTrackingArea ?
3536 private var lastActivatedTabId : UUID ?
3637
@@ -110,12 +111,27 @@ internal final class EditorTabInteractionView: NSView {
110111
111112 /// Claims the track and nothing else, so a press on a tab is this view's and a press on the
112113 /// new-tab button, on the band's insets or on the chrome below the track is not.
114+ ///
115+ /// The claim is for the pointer alone. Accessibility resolves a screen point through this same
116+ /// method, so claiming it unconditionally answered "the strip" for every tab and took all of
117+ /// them out of reach of VoiceOver, Switch Control, Voice Control and XCUITest at once: this
118+ /// view publishes nothing, so there was no element under a tab to speak, press or click. That
119+ /// shipped in #2571 and turned the whole UI suite red from the commit that merged it.
113120 override internal func hitTest( _ point: NSPoint ) -> NSView ? {
121+ guard !isResolvingAccessibilityHit else { return super. hitTest ( point) }
114122 let local = convert ( point, from: superview)
115123 guard trackRect. contains ( local) else { return super. hitTest ( point) }
116124 return self
117125 }
118126
127+ /// Answers from the SwiftUI tree, which is where the tabs publish themselves. The pointer's
128+ /// claim is lifted for the length of the question.
129+ override internal func accessibilityHitTest( _ point: NSPoint ) -> Any ? {
130+ isResolvingAccessibilityHit = true
131+ defer { isResolvingAccessibilityHit = false }
132+ return super. accessibilityHitTest ( point)
133+ }
134+
119135 private func tabIndex( atViewPoint point: CGPoint ) -> Int ? {
120136 EditorTabRunLayoutBuilder . index ( at: contentPoint ( fromViewPoint: point) , in: interaction. run)
121137 }
0 commit comments