Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Accessibility states API. #24608

Closed
wants to merge 10 commits into from

Conversation

marcmulcahy
Copy link

Summary

As currently defined, accessibilityStates is an array of strings, which represents the state of an object. The array of strings notion doesn't well encapsulate how various states are related, nor enforce any level of correctness.

This PR converts accessibilityStates to an object with a specific definition. So, rather than:

<View
...
accessibilityStates={['unchecked']}>

We have:

<View
accessibilityStates={{'checked': false}}>

And specifically define the checked state to either take a boolean or the "mixed" string (to represent mixed checkboxes).

We feel this API is easier to understand an implement, and provides better semantic definition of the states themselves, and how states are related to one another.

Changelog

[general] [change] - Convert accessibilityStates to an object instead of an array of strings.

Test Plan

Converted code in RNTester to use the new accessibilityStates API, and modified the checkbox example to support the "mixed" state, which was one of the limitations of the current API which prompted this work.

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Amazon Partner: Amazon labels Apr 25, 2019
Copy link

@analysis-bot analysis-bot left a comment

Choose a reason for hiding this comment

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

Code analysis results:

  • eslint found some issues. Run yarn lint --fix to automatically fix problems.

if (disabled) {
buttonStyles.push(styles.buttonDisabled);
textStyles.push(styles.textDisabled);
accessibilityStates.push('disabled');
accessibilityStates['enabled'] = false;

Choose a reason for hiding this comment

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

dot-notation: ["enabled"] is better written in dot notation.

@pull-bot
Copy link

pull-bot commented Apr 25, 2019

Messages
📖

📋 Verify Changelog Format - A changelog entry has the following format: [CATEGORY] [TYPE] - Message.

CATEGORY may be:
  • General
  • iOS
  • Android
  • JavaScript
  • Internal (for changes that do not need to be called out in the release notes)

TYPE may be:

  • Added, for new features.
  • Changed, for changes in existing functionality.
  • Deprecated, for soon-to-be removed features.
  • Removed, for now removed features.
  • Fixed, for any bug fixes.
  • Security, in case of vulnerabilities.

MESSAGE may answer "what and why" on a feature level. Use this to briefly tell React Native users about notable changes.

Generated by 🚫 dangerJS against 780d6f5

@marcmulcahy marcmulcahy changed the title A11y states api New Accessibility states API. Apr 25, 2019
@necolas
Copy link
Contributor

necolas commented Apr 25, 2019

For context, this is a change I proposed here to provide an API that works for platforms where attributes must be present on host nodes to communicate their purpose to the native accessibility system

Copy link
Contributor

@necolas necolas left a comment

Choose a reason for hiding this comment

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

This might need to support but deprecate the old API to give people time to migrate

@marcmulcahy
Copy link
Author

@necolas Any thoughts about how to deprecate the older API, while strongly encouraging developers to move to the new one?

@necolas
Copy link
Contributor

necolas commented Apr 25, 2019

Any thoughts about how to deprecate the older API, while strongly encouraging developers to move to the new one?

Hopefully someone from RN Core will be able to advise

@cpojer
Copy link
Contributor

cpojer commented Apr 25, 2019

Ideally we make this a non-breaking change for now by supporting both arrays or objects for a while, then we’ll add a warning in the release after, and then release a codemod (I can help with that) and then remove it.

@marcmulcahy
Copy link
Author

@cpojer Not sure how to allow the native code to accept both an array of strings as well as an object. Any ideas?

@cpojer
Copy link
Contributor

cpojer commented May 7, 2019

Unfortunately we can't make a breaking change like that in a single pull request. We could wrap <View /> in JS, which would be slow and which we can't do. It seems like the only option here is to introduce a new prop and deprecate the existing one (in a separate PR later) which I don't think we want to do. I'll ask at FB if there are other possibilities but unless we want to introduce a new prop name this may not easily be possible atm.

@cpojer
Copy link
Contributor

cpojer commented May 9, 2019

@marcmulcahy do you have any idea for a new prop that we could introduce so that we could deprecate the existing one? I know this is unfortunate but it seems like the only way. If not, please close this PR.

@marcmulcahy
Copy link
Author

@cpojer I suppose we could simply add a new prop called something like accessibilityStates2 that's an object instead of an array of strings. Switch all the RNTester samples and components to use accessibilityStates2, and then eventually deprecate accessibilityStates, or rename accessibilityStates2 to accessibilityStates.

I do think this object-based API is much clearer, in that the component author must enumerate the states that "matter", and it makes much clearer how states are related to each other (expanded/collapsed, checked/unchecked, etc.).

I'm also happy to close the PR if this isn't something we want to tackle ATM. Let me know what FB prefers to do.

@cpojer
Copy link
Contributor

cpojer commented May 9, 2019

Alright, yeah I think we can do this. Can you change this PR to do the following:

  • Add deprecatedAccessibilityStates and make the native code work with that
  • Make it so accessibilityStates still keeps working exactly the same after your PR lands.

In a month from now (sorry, this is some fb internal issue we have to deal with) we can then change how accessibilityStates works as long as we don't have internal users for it any longer. A month after that we can bring back the accessibilityStates prop with the new API and kill the deprecatedAccessibilityStates API.

I'm sorry for this slow multi process step but I think it's worth doing it if you are up for it :)

@cpojer
Copy link
Contributor

cpojer commented May 9, 2019

Alternatively, if we can think of a better name than accessibilityStates, we can also just add the new prop with a new name and then remove the old one in a month from now. That is way less involved and faster. The process is:

  • Add a new prop with the new API
  • I will migrate all internal callsites at FB
  • Send a PR with the removal for the old accessibilityStates that can be merged in a month from now.

What would be a reasonable name for a new prop?

@necolas
Copy link
Contributor

necolas commented May 9, 2019

What would be a reasonable name for a new prop?

accessibilityState? Since the value is an object and the name is close enough. And thinking ahead to Marc's other proposal around relationships, that prop could be accessibilityRelationship (no s either).

@cpojer
Copy link
Contributor

cpojer commented May 9, 2019

I think that’s a great idea. Let’s do it!

@marcmulcahy
Copy link
Author

As we discussed, this version moves the new API to a new property called "accessibilityState" and leaves "accessibilityStates" in tact.

To verify that the existing prop was still working, I applied all the patches which add the new property, and left RNTester unchanged, and verified that RNTester behaves as before on both Android and iOS. I then modified RNTester to use "accessibilityState" instead of "accessibilityStates" and re-tested.

@necolas
Copy link
Contributor

necolas commented May 23, 2019

Looks good to me

Copy link
Contributor

@cpojer cpojer left a comment

Choose a reason for hiding this comment

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

That's fantastic. Thank you so much @marcmulcahy and I'm sorry for putting you through so much pain with this one but I really appreciate you were sticking with us :)

I made a few small inline reverts to ensure the current props keep working at FB during the migration phase. Once this PR is landed, do you mind sending a PR that removes accessibilityStates altogether? I can merge that one (in about a month from now) and then we'll be in a good state again :)

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@pull-bot
Copy link

Messages
📖

📋 Verify Changelog Format - A changelog entry has the following format: [CATEGORY] [TYPE] - Message.

CATEGORY may be:
  • General
  • iOS
  • Android
  • JavaScript
  • Internal (for changes that do not need to be called out in the release notes)

TYPE may be:

  • Added, for new features.
  • Changed, for changes in existing functionality.
  • Deprecated, for soon-to-be removed features.
  • Removed, for now removed features.
  • Fixed, for any bug fixes.
  • Security, in case of vulnerabilities.

MESSAGE may answer "what and why" on a feature level. Use this to briefly tell React Native users about notable changes.

Generated by 🚫 dangerJS against 998faa4

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@cpojer has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@react-native-bot
Copy link
Collaborator

This pull request was successfully merged by Marc Mulcahy in 099be9b.

When will my fix make it into a release? | Upcoming Releases

@react-native-bot react-native-bot added the Merged This PR has been merged. label May 23, 2019
@marcmulcahy marcmulcahy deleted the a11y-states-api branch May 31, 2019 15:30
M-i-k-e-l pushed a commit to M-i-k-e-l/react-native that referenced this pull request Mar 10, 2020
Summary:
As currently defined, accessibilityStates is an array of strings, which represents the state of an object. The array of strings notion doesn't well encapsulate how various states are related, nor enforce any level of correctness.

This PR converts accessibilityStates to an object with a specific definition. So, rather than:

<View
...
accessibilityStates={['unchecked']}>

We have:

<View
accessibilityStates={{'checked': false}}>

And specifically define the checked state to either take a boolean or the "mixed" string (to represent mixed checkboxes).

We feel this API is easier to understand an implement, and provides better semantic definition of the states themselves, and how states are related to one another.

## Changelog

[general] [change] - Convert accessibilityStates to an object instead of an array of strings.
Pull Request resolved: facebook#24608

Differential Revision: D15467980

Pulled By: cpojer

fbshipit-source-id: f0414c0ef6add3f10f7f551d323d82d978754278
AKB48 pushed a commit to UnPourTous/react-native that referenced this pull request Apr 21, 2020
facebook-github-bot pushed a commit that referenced this pull request Apr 5, 2021
…1144)

Summary:
This issue fixes #30955 and is a follow up to pr #24608 which added the basic Accessibility functionalities to React Native.

TextInput should announce "selected" to the user when screenreader focused.
The focus is moved to the TextInput by navigating with the screenreader to the TextInput.

This PR adds call to View#setSelected in BaseViewManager https://developer.android.com/reference/android/view/View#setSelected(boolean)
The View#setSelected method definition https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/view/View.java
```java
/**
 * Changes the selection state of this view. A view can be selected or not.
 * Note that selection is not the same as focus. Views are typically
 * selected in the context of an AdapterView like ListView or GridView;
 * the selected view is the view that is highlighted.
 *
 * param selected true if the view must be selected, false otherwise
 */
public void setSelected(boolean selected) {
  if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) {
    // ... hidden logic
    if (selected) {
      sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
    } // ... hidden logic
  }
}
```

VoiceOver and TalkBack was tested with video samples included below.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Fixed] - Fix Selected State does not announce when TextInput Component selected on Android

Pull Request resolved: #31144

Test Plan:
**<details><summary>CLICK TO OPEN TESTS RESULTS</summary>**
<p>

**ENABLE THE AUDIO** to hear the TalkBack announcing **SELECTED** when the user taps on the TextInput

```javascript
        <TextInput
          accessibilityLabel="element 20"
          accessibilityState={{
            selected: true,
          }} />
```

| selected is true |
|:-------------------------:|
| <video src="https://user-images.githubusercontent.com/24992535/111652826-afc4f000-8807-11eb-9c79-8c51d7bf455b.mp4" width="700" height="" /> |

```javascript
        <TextInput
          accessibilityLabel="element 20"
          accessibilityState={{
            selected: false,
          }} />
```

| selected is false |
|:-------------------------:|
| <video src="https://user-images.githubusercontent.com/24992535/111652919-c10dfc80-8807-11eb-8244-83db6c327bcd.mp4" width="700" height="" /> |

The functionality does not present issues on iOS

| iOS testing |
|:-------------------------:|
| <video src="https://user-images.githubusercontent.com/24992535/111647656-f401c180-8802-11eb-9fa9-a4c211cf1665.mp4" width="400" height="" /> |

</p>
</details>

</p>
</details>

Reviewed By: blavalla

Differential Revision: D27306166

Pulled By: kacieb

fbshipit-source-id: 1b3cb37b2d0875cf53f6f1bff4bf095a877b2f0e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. p: Amazon Partner: Amazon
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants