Are accessibility labels supported within ConfirmationDialogState? #164
Replies: 7 comments 1 reply
-
@acosmicflamingo Have you tried reproducing in vanilla SwiftUI using |
Beta Was this translation helpful? Give feedback.
-
Actually, if I use the CaseStudies example and add accessibilityLabel modifier to a button, it works as expected. I think the problem (which in hindsight I should've mentioned in the initial issue description) is actually coming from how UIAlertController configures the buttons using ConfirmationDialogState in the convenience initializer: /// Creates a `UIAlertController` from `ConfirmationDialogState`.
///
/// - Parameters:
/// - state: The state of dialog that can be shown to the user.
/// - send: A function that wraps a dialog action in the view store's action type.
public convenience init<Action>(
state: ConfirmationDialogState<Action>, send: @escaping (Action) -> Void
) {
self.init(
title: String(state: state.title),
message: state.message.map { String(state: $0) },
preferredStyle: .actionSheet
)
for button in state.buttons {
self.addAction(.init(button, action: send))
}
} In the addAction function, it's getting a UIAlertAction object instantiated from the following convenience initializer: extension UIAlertAction {
convenience init<Action>(
_ button: AlertState<Action>.Button,
action: @escaping (Action) -> Void
) {
self.init(
title: String(state: button.label),
style: button.role.map(UIAlertAction.Style.init) ?? .default,
handler: button.action.map { _ in { _ in button.withAction(action) } }
)
self.accessibilityLabel = button.label.??? <= theoretical solution but don't know what property to use
}
} It looks like that is where the accessibility label information is not translating from SwiftUI to UIKit. The button parameter of type |
Beta Was this translation helpful? Give feedback.
-
It's definitely possible that var label = TextState("Hello!").accessibilityLabel("An enthusiastic greeting!")
label.accessibilityLabel // "An enthusiastic greeting!" We'd have to figure out how to treat certain defaults, though: var label = TextState("Hello!")
label.accessibilityLabel
// nil
// ...or...
// "Hello"? And composition makes it a little more tricky: var label = TextState("Hello!").accessibilityLabel("Greetings") + TextState(" And welcome!")
label.accessibilityLabel // What should be returned here? |
Beta Was this translation helpful? Give feedback.
-
That is tricky indeed. Well, what currently happens in UIKit is that accessibilityLabel is nil by default. Then, UIButton checks whether the property has a value and if it doesn't, then the UIButton's label's text value is instead used. If we were going to mimic this kind of behavior, then a solution below might get us close to that: extension UIAlertAction {
convenience init<Action>(
_ button: AlertState<Action>.Button,
action: @escaping (Action) -> Void
) {
self.init(
title: String(state: button.label),
style: button.role.map(UIAlertAction.Style.init) ?? .default,
handler: button.action.map { _ in { _ in button.withAction(action) } }
)
self.accessibilityLabel = String(state: (button.accessibilityLabel ?? button.label))
}
} For your examples, that would mean I'd expect the following: var label = TextState("Hello!")
label.accessibilityLabel // should be nil
var label = TextState("Hello!").accessibilityLabel("Greetings") + TextState(" And welcome!")
// oh noooooooooooooooooooooo things break down here :( I guess to be consistent, label.accessibilityLabel
// would be "Greetings"? |
Beta Was this translation helpful? Give feedback.
-
@acosmicflamingo Doing some spring cleaning and found this. I'm going to convert this to a discussion since we think it'd be a fine thing to revisit in the future, but we don't consider it a bug 😄 |
Beta Was this translation helpful? Give feedback.
-
Looking more into this, it seems like it does not make sense for extension UIAlertAction {
convenience init<Action>(
_ button: ButtonState<Action>,
action handler: @escaping (_ action: Action?) -> Void
) {
self.init(
title: String(state: button.label),
style: button.role.map(UIAlertAction.Style.init) ?? .default
) { _ in
button.withAction(handler)
}
if let accessibilityLabel = button.accessibilityLabel {
self.accessibilityLabel = String(state: accessibilityLabel)
}
}
} I've created a PR with these changes too: https://github.com/pointfreeco/swiftui-navigation/pull/171 |
Beta Was this translation helpful? Give feedback.
-
Now addressed in this commit: pointfreeco/swiftui-navigation@4ac2df7 |
Beta Was this translation helpful? Give feedback.
-
Let's say I want to initialize a ConfirmationDialogState object within a reducer like this:
In addition, I want to add accessibility labels (for example, I want to have a confirmation dialog display a timestamp but for VoiceOver users, I want it to not say 'zero colon 54'). I think the way to do this the SwiftUI way would be:
Doing this however does not actually pass accessibility labels as I'd expect, and it might have to do with how the convenience initializers and helper functions setup the buttons. But I do see that TCA includes accessibility support in TextState.swift. Perhaps I'm missing how to properly use accessibility labels? Or is there an issue with how ConfirmationDialogState supports accessibility labels? I'd be happy to debug this myself and create a PR, but I want to make sure I'm not missing anything. Thanks!
Beta Was this translation helpful? Give feedback.
All reactions