react-native-a11y-order 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,157 +36,6 @@ npm install react-native-a11y-order
36
36
  yarn add react-native-a11y-order
37
37
  ```
38
38
 
39
- ## Recent Updates
40
-
41
- #### Screen Reader Focus Events
42
-
43
- | iOS | Android |
44
- | :-- | :-- |
45
- | <img src="/.github/images/screen-reader-focus-ios.gif" height="500" /> | <img src="/.github/images/screen-reader-focus-android.gif" height="500" /> |
46
-
47
- > To enhance accessibility and provide better focus management, screen reader focus handlers have been added. These handlers allow you to capture and respond to screen reader focus events effectively, enabling features like managing animations, timers, and other interactions based on focus changes.
48
-
49
- <details>
50
- <summary>More Information</summary>
51
-
52
- A11y.View Props:
53
- | Prop | Description |
54
- | :-- | :-- |
55
- | onScreenReaderFocused | Triggered when the view gets focus from the screen reader. |
56
- | onScreenReaderSubViewFocused | Triggered when a subview within the component is focused by the screen reader. |
57
- | onScreenReaderSubViewBlurred | Triggered when the screen reader focus moves away or is blurred from a subview. |
58
- | onScreenReaderSubViewFocusChange | Triggered when the focus status of a subview changes (either focused or blurred). |
59
- | onScreenReaderDescendantFocusChanged | Triggered when any descendant subview is focused by the screen reader. Provides an object containing the focus status and the nativeId of the focused subview, if applicable. Example: < { status: string, nativeId?: string } >. |
60
-
61
- ```tsx
62
- <A11y.View
63
- onScreenReaderDescendantFocusChanged={(e) => console.log(e)}
64
- onScreenReaderSubViewFocused={() => console.log('List has been focused')}
65
- onScreenReaderSubViewBlurred={() => console.log('List has been blurred')}
66
- onScreenReaderFocused={() => console.log('Focused')}
67
- >
68
- ...
69
- </A11y.View>
70
- ```
71
- </details>
72
-
73
- #### Focus Lock Functionality
74
-
75
- | iOS | Android |
76
- | :-- | :-- |
77
- | <img src="/.github/images/focus-lock-ios.gif" height="500" /> | <img src="/.github/images/focus-lock-android.gif" height="500" /> |
78
-
79
- > The focus lock functionality has been introduced with two new components: `A11y.FocusFrame` and `A11y.FocusTrap`. These components enable more robust accessibility by managing and restricting focus within specific areas of the screen.
80
-
81
- <details>
82
- <summary>More Information</summary>
83
-
84
- - On iOS, `A11y.FocusTrap` uses the native `accessibilityViewIsModal` property to keep the focus within a defined area.
85
- - On Android, where no equivalent to `accessibilityViewIsModal` exists, custom logic has been implemented as a workaround. By default, Android uses a custom Activity or Modal to limit focus. While using a Modal is considered the best practice for focus locking on Android, some scenarios—such as issues with React Native's Modal or library-specific constraints—may require alternative implementations.
86
-
87
- #### How It Works
88
-
89
- The focus lock functionality should be used as a pair:
90
-
91
- - `A11y.FocusFrame`: This component is used at the root level of a "screen" to detect focus leaks and ensure that focus remains contained.
92
- - `A11y.FocusTrap`: This component wraps the content area where focus should be explicitly locked.
93
-
94
- | Prop | Description |
95
- | :-- | :-- |
96
- | ViewProps | Includes all standard React Native View properties, such as style, testID, etc. |
97
-
98
- ```tsx
99
- <A11y.FocusFrame>
100
- ...
101
- <A11y.FocusTrap>
102
- <Text accessibilityRole="header">Locked Area</Text>
103
- <Button
104
- title="Confirm"
105
- accessibilityLabel="Confirm action"
106
- />
107
- </A11y.FocusTrap>
108
- ...
109
- </A11y.FocusFrame>
110
- ```
111
-
112
- </details>
113
-
114
- #### A11y.PaneTitle and A11y.ScreenChange
115
-
116
- | iOS | Android |
117
- | :-- | :-- |
118
- | <img src="/.github/images/announce-ios.gif" height="500" /> | <img src="/.github/images/announce-android.gif" height="500" /> |
119
-
120
- > The components `A11y.PaneTitle` and `A11y.ScreenChange` have been introduced to enhance accessibility by providing robust support for announcing screen changes and their states.
121
-
122
- <details>
123
- <summary>More Information</summary>
124
-
125
- Platform-Specific Behavior
126
- -On Android, `A11y.PaneTitle` and `A11y.ScreenChange` utilize native properties, specifically: `activity.setTitle` and `setAccessibilityPaneTitle`.
127
- - On iOS, due to the lack of equivalent native functionality, `A11yModule.announce` is used as a workaround to announce screen changes (see the `A11yModule.announce` section for details).
128
-
129
- ##### When to Use:
130
-
131
- Currently, React Native doesn't provide APIs for announcing modal or screen transitions. To address this and improve accessibility, you can use `A11y.PaneTitle` or `A11y.ScreenChange` to announce:
132
- - Screen transitions, such as navigating to a new screen (e.g., "Login Screen").
133
- - Modal presentations, such as when a modal appears (e.g., "Confirm Modal").
134
-
135
-
136
- A11y.PaneTitle Props
137
- | Prop | Description |
138
- | :-- | :-- |
139
- | title | The title message to be announced for the screen or modal. |
140
- | detachMessage | The message to be announced when this component is detached (e.g., when leaving the screen). |
141
- | type | The type of announcement for Android. Options: activity, pane, or announce. |
142
- | displayed | A trigger for screen focus changes, used to properly update the Android Activity title when switching screens. |
143
- | withFocusRestore | Ensures that the screen reader focus is preserved and restored appropriately after a screen change. (iOS-specific) |
144
-
145
- The A11y.ScreenChange component is a specialized implementation of A11y.PaneTitle. It is preconfigured with `type="activity"` for screen change announcements on Android and works identically to `A11y.PaneTitle`.
146
-
147
- Example:
148
- ```tsx
149
- export const LoginScreen = ({ navigation }) => {
150
- const isFocused = useIsFocused();
151
- return (
152
- <View>
153
- <A11y.ScreenChange
154
- title="Login Screen"
155
- displayed={isFocused}
156
- />
157
- <View style={styles.container}>
158
- <Text>Welcome to the Login Screen</Text>
159
- <Button title="Continue" onPress={() => navigation.navigate('Home')} />
160
- </View>
161
- </View>
162
- );
163
- };
164
- ```
165
- </details>
166
-
167
- #### A11yModule.announce - Alternative Announcement Function
168
-
169
- > The `A11yModule.announce` function has been introduced to improve accessibility announcement behavior on iOS.
170
-
171
- <details>
172
- <summary>More Information</summary>
173
- Why Use `A11yModule.announce`?
174
-
175
- On iOS, the default `AccessibilityInfo.announceForAccessibility` function can be interrupted by focus changes. This means that if you attempt to announce a message, the announcement could be prematurely cut off due to various events, such as screen navigation or the display of a modal.
176
-
177
- To address this limitation, `A11yModule.announce` uses a custom solution built on native events to ensure that announcements are made reliably and are less likely to be interrupted.
178
-
179
- A11yModule API:
180
- | Function | Description |
181
- | :-- | :-- |
182
- | announce(message: string): void | Posts a string to be announced by the screen reader, ensuring improved reliability on iOS. |
183
-
184
- ```tsx
185
- A11yModule.announce('This is a custom announcement, now more reliable on iOS!');
186
- ```
187
- </details>
188
-
189
-
190
39
  ## Usage
191
40
 
192
41
  #### A11y.Order, A11y.Index
@@ -322,9 +171,17 @@ These components enhance accessibility by providing better control over focus ma
322
171
  - `A11y.FocusFrame`: Used at the root level of a "screen" to detect and prevent focus leaks, ensuring focus remains contained.
323
172
  - `A11y.FocusTrap`: Wraps the content area to explicitly enforce focus confinement within a defined region.
324
173
 
174
+ On iOS, `A11y.FocusTrap` uses `accessibilityViewIsModal` to keep focus within the defined area. When `forceLock` is enabled, it additionally uses active enforcement — redirecting VoiceOver back into the trap whenever focus escapes and blocking focus from leaving at the system level.
175
+
176
+ On Android, `A11y.FocusTrap` uses a custom Activity or Modal to limit focus.
177
+
178
+ `A11y.FocusTrap` Props:
179
+
325
180
  | Prop | Description |
326
181
  | :-- | :-- |
327
182
  | ViewProps | Includes all standard React Native View properties, such as style, testID, etc. |
183
+ | lockDisabled? | Disables the focus lock when `true`. |
184
+ | forceLock? | (iOS only) Enables active focus enforcement — VoiceOver is redirected back into the trap whenever focus escapes. Use when `accessibilityViewIsModal` alone is not sufficient. |
328
185
 
329
186
  ```tsx
330
187
  <A11y.FocusFrame>
@@ -340,6 +197,22 @@ These components enhance accessibility by providing better control over focus ma
340
197
  </A11y.FocusFrame>
341
198
  ```
342
199
 
200
+ Use `forceLock` when the standard lock is not enough to keep VoiceOver inside the trap:
201
+
202
+ ```tsx
203
+ <A11y.FocusFrame>
204
+ ...
205
+ <A11y.FocusTrap forceLock>
206
+ <Text accessibilityRole="header">Locked Area</Text>
207
+ <Button
208
+ title="Confirm"
209
+ accessibilityLabel="Confirm action"
210
+ />
211
+ </A11y.FocusTrap>
212
+ ...
213
+ </A11y.FocusFrame>
214
+ ```
215
+
343
216
  ## A11y.PaneTitle, A11y.ScreenChange
344
217
 
345
218
  Components for screen change announcements
@@ -1,19 +1,3 @@
1
- buildscript {
2
- // Buildscript is evaluated before everything else so we can't use getExtOrDefault
3
- def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["ExternalKeyboard_kotlinVersion"]
4
-
5
- repositories {
6
- google()
7
- mavenCentral()
8
- }
9
-
10
- dependencies {
11
- classpath "com.android.tools.build:gradle:7.2.1"
12
- // noinspection DifferentKotlinGradleVersion
13
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14
- }
15
- }
16
-
17
1
  def reactNativeArchitectures() {
18
2
  def value = rootProject.getProperties().get("reactNativeArchitectures")
19
3
  return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
@@ -24,7 +8,6 @@ def isNewArchitectureEnabled() {
24
8
  }
25
9
 
26
10
  apply plugin: "com.android.library"
27
- apply plugin: "kotlin-android"
28
11
 
29
12
 
30
13
  def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
@@ -115,7 +98,6 @@ dependencies {
115
98
  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
116
99
  //noinspection GradleDynamicVersion
117
100
  implementation "com.facebook.react:react-native:+"
118
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
119
101
  }
120
102
 
121
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-a11y-order",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "ReactNative library for managing screen reader focus ordering",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",