react-native-a11y-order 1.0.0-rc → 1.0.0

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.
Files changed (80) hide show
  1. package/README.md +9 -2
  2. package/android/src/main/java/com/a11yorder/core/A11yManagedFocusView.java +29 -0
  3. package/android/src/main/java/com/a11yorder/core/A11yViewOrder.java +1 -1
  4. package/android/src/main/java/com/a11yorder/modules/A11yAnnounceModule.java +20 -7
  5. package/android/src/main/java/com/a11yorder/views/A11yIndexView/A11yIndexViewManager.java +0 -6
  6. package/android/src/oldarch/A11yAnnounceModuleSpec.java +8 -1
  7. package/android/src/oldarch/A11yIndexViewManagerSpec.java +0 -1
  8. package/ios/helpers/RNAOSpeechAttributes.h +35 -0
  9. package/ios/helpers/RNAOSpeechAttributes.mm +64 -0
  10. package/ios/modules/RNAOA11yAnnounceModule.h +13 -9
  11. package/ios/modules/RNAOA11yAnnounceModule.mm +220 -14
  12. package/ios/services/RNAOA11yAnnounceService/RNAOA11yAnnounceService.h +11 -1
  13. package/ios/services/RNAOA11yAnnounceService/RNAOA11yAnnounceService.mm +55 -51
  14. package/ios/views/RNAOA11yIndexView/RNAOA11yIndexView.mm +0 -4
  15. package/ios/views/RNAOA11yIndexView/RNAOA11yIndexViewManager.mm +5 -5
  16. package/ios/views/RNAOA11yPaneTitleView/RNAOA11yPaneTitleView.mm +12 -2
  17. package/ios/views/base/{RNAOA11yAutoFocusView.h → RNAOA11yManagedFocusView.h} +5 -7
  18. package/ios/views/base/{RNAOA11yAutoFocusView.mm → RNAOA11yManagedFocusView.mm} +2 -19
  19. package/ios/views/base/RNAOA11yViewOrder.h +3 -3
  20. package/lib/commonjs/components/A11yCard/A11yCard.ios.js +8 -1
  21. package/lib/commonjs/components/A11yCard/A11yCard.ios.js.map +1 -1
  22. package/lib/commonjs/components/A11yIndex/A11yIndex.js +3 -2
  23. package/lib/commonjs/components/A11yIndex/A11yIndex.js.map +1 -1
  24. package/lib/commonjs/index.js +22 -4
  25. package/lib/commonjs/index.js.map +1 -1
  26. package/lib/commonjs/index.web.js +4 -4
  27. package/lib/commonjs/modules/A11yAnnounceModule.android.js +37 -3
  28. package/lib/commonjs/modules/A11yAnnounceModule.android.js.map +1 -1
  29. package/lib/commonjs/modules/A11yAnnounceModule.js +66 -8
  30. package/lib/commonjs/modules/A11yAnnounceModule.js.map +1 -1
  31. package/lib/commonjs/nativeSpecs/A11yIndexNativeComponent.ts +0 -1
  32. package/lib/commonjs/nativeSpecs/NativeA11yAnnounceModule.js +2 -0
  33. package/lib/commonjs/nativeSpecs/NativeA11yAnnounceModule.js.map +1 -1
  34. package/lib/module/components/A11yCard/A11yCard.ios.js +8 -1
  35. package/lib/module/components/A11yCard/A11yCard.ios.js.map +1 -1
  36. package/lib/module/components/A11yIndex/A11yIndex.js +3 -2
  37. package/lib/module/components/A11yIndex/A11yIndex.js.map +1 -1
  38. package/lib/module/index.js +1 -1
  39. package/lib/module/index.js.map +1 -1
  40. package/lib/module/index.web.js +1 -1
  41. package/lib/module/index.web.js.map +1 -1
  42. package/lib/module/modules/A11yAnnounceModule.android.js +32 -2
  43. package/lib/module/modules/A11yAnnounceModule.android.js.map +1 -1
  44. package/lib/module/modules/A11yAnnounceModule.js +62 -7
  45. package/lib/module/modules/A11yAnnounceModule.js.map +1 -1
  46. package/lib/module/nativeSpecs/A11yIndexNativeComponent.ts +0 -1
  47. package/lib/module/nativeSpecs/NativeA11yAnnounceModule.js +4 -0
  48. package/lib/module/nativeSpecs/NativeA11yAnnounceModule.js.map +1 -1
  49. package/lib/typescript/src/components/A11yCard/A11yCard.ios.d.ts.map +1 -1
  50. package/lib/typescript/src/components/A11yIndex/A11yIndex.d.ts +0 -1
  51. package/lib/typescript/src/components/A11yIndex/A11yIndex.d.ts.map +1 -1
  52. package/lib/typescript/src/components/A11yIndex/A11yIndex.types.d.ts +0 -4
  53. package/lib/typescript/src/components/A11yIndex/A11yIndex.types.d.ts.map +1 -1
  54. package/lib/typescript/src/components/A11yIndex/A11yIndex.web.d.ts +0 -1
  55. package/lib/typescript/src/components/A11yIndex/A11yIndex.web.d.ts.map +1 -1
  56. package/lib/typescript/src/components/A11yView/A11yView.d.ts +0 -1
  57. package/lib/typescript/src/components/A11yView/A11yView.d.ts.map +1 -1
  58. package/lib/typescript/src/index.d.ts +2 -3
  59. package/lib/typescript/src/index.d.ts.map +1 -1
  60. package/lib/typescript/src/index.web.d.ts +1 -2
  61. package/lib/typescript/src/index.web.d.ts.map +1 -1
  62. package/lib/typescript/src/modules/A11yAnnounceModule.android.d.ts +25 -2
  63. package/lib/typescript/src/modules/A11yAnnounceModule.android.d.ts.map +1 -1
  64. package/lib/typescript/src/modules/A11yAnnounceModule.d.ts +112 -4
  65. package/lib/typescript/src/modules/A11yAnnounceModule.d.ts.map +1 -1
  66. package/lib/typescript/src/nativeSpecs/A11yIndexNativeComponent.d.ts +0 -1
  67. package/lib/typescript/src/nativeSpecs/A11yIndexNativeComponent.d.ts.map +1 -1
  68. package/lib/typescript/src/nativeSpecs/NativeA11yAnnounceModule.d.ts +21 -1
  69. package/lib/typescript/src/nativeSpecs/NativeA11yAnnounceModule.d.ts.map +1 -1
  70. package/package.json +1 -1
  71. package/src/components/A11yCard/A11yCard.ios.tsx +8 -1
  72. package/src/components/A11yIndex/A11yIndex.tsx +5 -4
  73. package/src/components/A11yIndex/A11yIndex.types.ts +0 -5
  74. package/src/index.ts +12 -1
  75. package/src/index.web.ts +1 -1
  76. package/src/modules/A11yAnnounceModule.android.ts +18 -2
  77. package/src/modules/A11yAnnounceModule.ts +153 -9
  78. package/src/nativeSpecs/A11yIndexNativeComponent.ts +0 -1
  79. package/src/nativeSpecs/NativeA11yAnnounceModule.ts +31 -1
  80. package/android/src/main/java/com/a11yorder/core/A11yAutoFocusView.java +0 -61
@@ -1,6 +1,26 @@
1
1
  import type { TurboModule } from 'react-native';
2
+ type AnnounceOptions = Readonly<{
3
+ priority?: string;
4
+ queue?: boolean;
5
+ calm?: boolean;
6
+ delayMs?: number;
7
+ language?: string;
8
+ pitch?: number;
9
+ spellOut?: boolean;
10
+ punctuation?: boolean;
11
+ ipaNotation?: string;
12
+ }>;
13
+ type AnnouncementResult = Readonly<{
14
+ id: string;
15
+ status: string;
16
+ }>;
2
17
  export interface Spec extends TurboModule {
3
- announce(message: string): void;
18
+ /** Enqueues a screen reader announcement. Resolves with AnnouncementResult. */
19
+ announce(message: string, options?: AnnounceOptions): Promise<AnnouncementResult>;
20
+ /** Cancels a specific announcement by its id. Resolves with the cancelled item's result. */
21
+ cancel(id: string): Promise<AnnouncementResult>;
22
+ /** Drains the queue and interrupts current speech. */
23
+ cancelAll(): Promise<AnnouncementResult>;
4
24
  }
5
25
  declare const _default: Spec | null | undefined;
6
26
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"NativeA11yAnnounceModule.d.ts","sourceRoot":"","sources":["../../../../src/nativeSpecs/NativeA11yAnnounceModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;;AAED,wBAAmE"}
1
+ {"version":3,"file":"NativeA11yAnnounceModule.d.ts","sourceRoot":"","sources":["../../../../src/nativeSpecs/NativeA11yAnnounceModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKhD,KAAK,eAAe,GAAG,QAAQ,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC,CAAC;AAEH,KAAK,kBAAkB,GAAG,QAAQ,CAAC;IACjC,EAAE,EAAE,MAAM,CAAC;IAIX,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,+EAA+E;IAC/E,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/B,4FAA4F;IAC5F,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChD,sDAAsD;IACtD,SAAS,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC1C;;AAED,wBAAmE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-a11y-order",
3
- "version": "1.0.0-rc",
3
+ "version": "1.0.0",
4
4
  "description": "ReactNative library for managing screen reader focus ordering",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -22,6 +22,7 @@ export const A11yCard = ({
22
22
  {...accessibility}
23
23
  accessible
24
24
  pointerEvents="none"
25
+ collapsable={false}
25
26
  onAccessibilityTap={onPress}
26
27
  style={styles.overlay}
27
28
  />
@@ -40,5 +41,11 @@ export const A11yCard = ({
40
41
 
41
42
  const styles = StyleSheet.create({
42
43
  container: { position: 'relative' },
43
- overlay: StyleSheet.absoluteFillObject,
44
+ overlay: {
45
+ position: 'absolute',
46
+ top: 0,
47
+ left: 0,
48
+ right: 0,
49
+ bottom: 0,
50
+ },
44
51
  });
@@ -103,16 +103,17 @@ function useOrderProps(
103
103
  }
104
104
 
105
105
  const resolvedOrderType = orderType ?? 'default';
106
- const importantForAccessibilityFallback =
107
- resolvedOrderType === 'default' ? ('yes' as const) : undefined;
106
+ const isDefaultOrderType = resolvedOrderType === 'default';
107
+
108
+ const importantForAccessibility =
109
+ hasOrderInfo && isDefaultOrderType ? 'yes' : importantForAccessibilityProp;
108
110
 
109
111
  return {
110
112
  orderKey,
111
113
  orderFocusType: hasOrderInfo
112
114
  ? A11yOrderTypeEnum[resolvedOrderType]
113
115
  : undefined,
114
- importantForAccessibility:
115
- importantForAccessibilityProp ?? importantForAccessibilityFallback,
116
+ importantForAccessibility,
116
117
  };
117
118
  }
118
119
 
@@ -88,11 +88,6 @@ export type A11yIndexProps = ViewProps & {
88
88
  */
89
89
  shouldGroupAccessibilityChildren?: boolean;
90
90
 
91
- /**
92
- * When `true`, requests screen reader focus on this element immediately after mount.
93
- */
94
- autoFocus?: boolean;
95
-
96
91
  /**
97
92
  * Called when the screen reader focuses this element directly (not a descendant).
98
93
  */
package/src/index.ts CHANGED
@@ -46,4 +46,15 @@ export const A11y = {
46
46
  Card: A11yCard,
47
47
  };
48
48
 
49
- export { A11yModule } from './modules/A11yAnnounceModule';
49
+ export {
50
+ ScreenReader,
51
+ announce,
52
+ cancel,
53
+ cancelAll,
54
+ } from './modules/A11yAnnounceModule';
55
+ export type {
56
+ AnnouncePriority,
57
+ AnnounceStatus,
58
+ AnnounceOptions,
59
+ AnnouncementResult,
60
+ } from './modules/A11yAnnounceModule';
package/src/index.web.ts CHANGED
@@ -23,4 +23,4 @@ export const A11y = {
23
23
  Card: View,
24
24
  };
25
25
 
26
- export { A11yModule } from './modules/A11yAnnounceModule';
26
+ export { ScreenReader } from './modules/A11yAnnounceModule';
@@ -1,5 +1,21 @@
1
+ // Android stub — bypasses the native bridge, uses the built-in API directly.
1
2
  import { AccessibilityInfo } from 'react-native';
2
3
 
3
- export const A11yModule = {
4
- announce: AccessibilityInfo.announceForAccessibility,
4
+ export const ScreenReader = {
5
+ announce: (message: string) => {
6
+ AccessibilityInfo.announceForAccessibility(message);
7
+ return Promise.resolve({ id: '', status: 'fired' as const });
8
+ },
9
+ cancel: () => Promise.resolve({ id: '', status: 'cancelled' as const }),
10
+ cancelAll: () => Promise.resolve({ id: '', status: 'cancelled' as const }),
5
11
  };
12
+
13
+ export const announce = (message: string) => {
14
+ AccessibilityInfo.announceForAccessibility(message);
15
+ return Promise.resolve({ id: '', status: 'fired' as const });
16
+ };
17
+
18
+ export const cancel = () =>
19
+ Promise.resolve({ id: '', status: 'cancelled' as const });
20
+ export const cancelAll = () =>
21
+ Promise.resolve({ id: '', status: 'cancelled' as const });
@@ -1,19 +1,21 @@
1
1
  import { NativeModules, Platform } from 'react-native';
2
+ import NativeA11yAnnounceModule from '../nativeSpecs/NativeA11yAnnounceModule';
2
3
 
3
4
  const LINKING_ERROR =
4
- `The package 'react-native-external-keyboard' doesn't seem to be linked. Make sure: \n\n${Platform.select(
5
+ `The package 'react-native-a11y-order' doesn't seem to be linked. Make sure: \n\n${Platform.select(
5
6
  { ios: "- You have run 'pod install'\n", default: '' }
6
7
  )}- You rebuilt the app after installing the package\n` +
7
8
  `- You are not using Expo Go\n`;
8
9
 
9
10
  // @ts-expect-error
10
11
  const isTurboModuleEnabled = global.__turboModuleProxy != null;
11
- const A11yAnnounceModule = isTurboModuleEnabled
12
- ? require('../nativeSpecs/NativeA11yAnnounceModule').default
12
+
13
+ const A11yAnnounceNative = isTurboModuleEnabled
14
+ ? NativeA11yAnnounceModule
13
15
  : NativeModules.A11yAnnounceModule;
14
16
 
15
- export const A11yAnnounce =
16
- A11yAnnounceModule ||
17
+ const A11yAnnounceProxy: typeof NativeA11yAnnounceModule =
18
+ A11yAnnounceNative ??
17
19
  new Proxy(
18
20
  {},
19
21
  {
@@ -23,10 +25,152 @@ export const A11yAnnounce =
23
25
  }
24
26
  );
25
27
 
26
- export function announce(message: string) {
27
- A11yAnnounce.announce(message);
28
+ // ─── Types ────────────────────────────────────────────────────────────────────
29
+
30
+ export type AnnouncePriority = 'low' | 'default' | 'high';
31
+
32
+ export type AnnounceStatus = 'spoken' | 'fired' | 'cancelled';
33
+
34
+ export type AnnounceOptions = {
35
+ /**
36
+ * Controls urgency. iOS 17+: maps to `UIAccessibilityPriority`.
37
+ *
38
+ * - `'low'` — spoken only when the screen reader is fully idle
39
+ * - `'default'` — standard queued announcement (default)
40
+ * - `'high'` — may preempt lower-priority pending items
41
+ */
42
+ priority?: AnnouncePriority;
43
+
44
+ /**
45
+ * When `true`, waits for current speech before speaking.
46
+ * When `false`, may interrupt current speech.
47
+ * Default: `true`
48
+ */
49
+ queue?: boolean;
50
+
51
+ /**
52
+ * Navigation-aware mode. When `true`, the announcement waits for:
53
+ * - Active navigation transitions to finish (1 s lock after screen change)
54
+ * - The screen reader to have a focused element
55
+ * - A 300 ms debounce to prevent overlap with focus changes
56
+ *
57
+ * Promise resolves when the service **actually fires** the announcement
58
+ * (not just when it's enqueued), so `await` is meaningful.
59
+ * Default: `false`
60
+ */
61
+ calm?: boolean;
62
+
63
+ /**
64
+ * Explicit delay in milliseconds before the announcement is posted.
65
+ * In `calm` mode the service manages its own timing; this is ignored.
66
+ * Default: `0`
67
+ */
68
+ delayMs?: number;
69
+
70
+ /**
71
+ * iOS-only speech characteristics. No-op on Android.
72
+ * Only relevant in direct mode (`calm: false`).
73
+ */
74
+ speech?: {
75
+ /**
76
+ * BCP-47 language tag (e.g. `'fr-FR'`). Defaults to the system language.
77
+ * @platform ios
78
+ */
79
+ language?: string;
80
+
81
+ /**
82
+ * Voice pitch multiplier, range `0.0`–`2.0`. Default: `1.0`.
83
+ * @platform ios
84
+ */
85
+ pitch?: number;
86
+
87
+ /**
88
+ * Spell each character individually.
89
+ * Useful for codes, CAPTCHAs, or abbreviations.
90
+ * @platform ios
91
+ */
92
+ spellOut?: boolean;
93
+
94
+ /**
95
+ * Read punctuation marks aloud (e.g. "comma", "period").
96
+ * @platform ios
97
+ */
98
+ punctuation?: boolean;
99
+
100
+ /**
101
+ * IPA pronunciation hint applied to the entire string.
102
+ * @platform ios
103
+ */
104
+ ipaNotation?: string;
105
+ };
106
+ };
107
+
108
+ export type AnnouncementResult = {
109
+ /** UUID assigned at enqueue time. */
110
+ id: string;
111
+ /**
112
+ * - `'spoken'` — VoiceOver confirmed full speech (iOS direct mode only).
113
+ * - `'fired'` — posted to the screen reader; completion not confirmed.
114
+ * Always the case on Android. iOS calm mode resolves here
115
+ * once the service actually fires the announcement.
116
+ * - `'cancelled'` — explicitly cancelled via `cancel()` or `cancelAll()`.
117
+ */
118
+ status: AnnounceStatus;
119
+ };
120
+
121
+ // ─── Core API ─────────────────────────────────────────────────────────────────
122
+
123
+ /**
124
+ * Posts a screen reader announcement.
125
+ *
126
+ * **calm mode** (`calm: true`): navigation-aware — waits for transitions to
127
+ * settle and for VoiceOver/TalkBack to have a focused element. Promise
128
+ * resolves when the announcement is **actually fired** (not just enqueued).
129
+ *
130
+ * **direct mode** (`calm: false`, default): posts immediately with speech
131
+ * attributes. On iOS, Promise resolves when VoiceOver confirms speech finished
132
+ * (`status: 'spoken'`) or was interrupted (`status: 'fired'`).
133
+ * On Android, always resolves immediately with `status: 'fired'`.
134
+ */
135
+ export function announce(
136
+ message: string,
137
+ options?: AnnounceOptions
138
+ ): Promise<AnnouncementResult> {
139
+ const { speech, ...rest } = options ?? {};
140
+ return A11yAnnounceProxy!.announce(message, {
141
+ ...rest,
142
+ ...speech,
143
+ }) as Promise<AnnouncementResult>;
28
144
  }
29
145
 
30
- export const A11yModule = {
31
- announce,
146
+ /**
147
+ * Cancels the announcement with the given `id`.
148
+ * In calm mode, removes it from the service queue if not yet fired.
149
+ * In direct mode, interrupts the active announcement if it matches.
150
+ */
151
+ export function cancel(id: string): Promise<AnnouncementResult> {
152
+ return A11yAnnounceProxy!.cancel(id) as Promise<AnnouncementResult>;
153
+ }
154
+
155
+ /**
156
+ * Cancels all pending and active announcements.
157
+ * Calm-mode promises resolve with `status: 'cancelled'`.
158
+ */
159
+ export function cancelAll(): Promise<AnnouncementResult> {
160
+ return A11yAnnounceProxy!.cancelAll() as Promise<AnnouncementResult>;
161
+ }
162
+
163
+ // ─── Namespace export (backward-compatible) ───────────────────────────────────
164
+
165
+ export const ScreenReader = {
166
+ /**
167
+ * Posts a navigation-aware announcement (calm mode).
168
+ * Waits for transitions to finish before speaking.
169
+ * Promise resolves when the announcement is actually fired.
170
+ */
171
+ announce: (message: string, options?: AnnounceOptions) =>
172
+ announce(message, { calm: true, ...options }),
173
+
174
+ cancel,
175
+ cancelAll,
32
176
  };
@@ -24,7 +24,6 @@ export interface A11yIndexNativeComponentProps extends ViewProps {
24
24
  orderFocusType?: Int32;
25
25
  shouldGroupAccessibilityChildren?: Int32;
26
26
 
27
- autoFocus?: boolean;
28
27
  descendantFocusChangedEnabled?: boolean;
29
28
 
30
29
  onScreenReaderFocused?: DirectEventHandler<{}>;
@@ -1,8 +1,38 @@
1
1
  import type { TurboModule } from 'react-native';
2
2
  import { TurboModuleRegistry } from 'react-native';
3
3
 
4
+ // Speech options are kept flat here (bridge contract).
5
+ // The JS API groups them under `speech: {}` and flattens before calling native.
6
+ type AnnounceOptions = Readonly<{
7
+ priority?: string;
8
+ queue?: boolean;
9
+ calm?: boolean;
10
+ delayMs?: number;
11
+ language?: string;
12
+ pitch?: number;
13
+ spellOut?: boolean;
14
+ punctuation?: boolean;
15
+ ipaNotation?: string;
16
+ }>;
17
+
18
+ type AnnouncementResult = Readonly<{
19
+ id: string;
20
+ // 'spoken' — VoiceOver confirmed full speech (iOS direct only)
21
+ // 'fired' — posted to screen reader; no completion confirmation
22
+ // 'cancelled' — explicitly cancelled via cancel() / cancelAll()
23
+ status: string;
24
+ }>;
25
+
4
26
  export interface Spec extends TurboModule {
5
- announce(message: string): void;
27
+ /** Enqueues a screen reader announcement. Resolves with AnnouncementResult. */
28
+ announce(
29
+ message: string,
30
+ options?: AnnounceOptions
31
+ ): Promise<AnnouncementResult>;
32
+ /** Cancels a specific announcement by its id. Resolves with the cancelled item's result. */
33
+ cancel(id: string): Promise<AnnouncementResult>;
34
+ /** Drains the queue and interrupts current speech. */
35
+ cancelAll(): Promise<AnnouncementResult>;
6
36
  }
7
37
 
8
38
  export default TurboModuleRegistry.get<Spec>('A11yAnnounceModule');
@@ -1,61 +0,0 @@
1
- package com.a11yorder.core;
2
-
3
- import android.content.Context;
4
- import android.view.View;
5
- import android.view.accessibility.AccessibilityEvent;
6
-
7
- import com.a11yorder.services.focus.A11yFocusDelegate;
8
- import com.a11yorder.services.focus.A11yFocusProtocol;
9
- import com.facebook.react.bridge.ReactContext;
10
-
11
- public class A11yAutoFocusView extends A11yScreenReaderView implements A11yFocusProtocol {
12
- private final A11yFocusDelegate a11yFocusDelegate;
13
- private Boolean autoFocus = false;
14
- private Boolean autoFocusOnce = false;
15
- private Boolean hasBeenFocused = false;
16
-
17
- public A11yAutoFocusView(Context context) {
18
- super(context);
19
- this.a11yFocusDelegate = new A11yFocusDelegate((ReactContext) context, this);
20
- }
21
-
22
- @Override
23
- public boolean isViewFocused() {
24
- View focusTarget = this.isFocusable() ? this : this.getSubChild();
25
- if (focusTarget == null) return false;
26
- return focusTarget.isAccessibilityFocused();
27
- }
28
-
29
- public void setAutoFocus(Boolean value) {
30
- this.autoFocus = value;
31
- }
32
-
33
- public void focus() {
34
- a11yFocusDelegate.requestFocus();
35
- }
36
-
37
- @Override
38
- public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
39
- int eventType = event.getEventType();
40
-
41
- if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED && autoFocus && !hasBeenFocused) {
42
- hasBeenFocused = true;
43
- a11yFocusDelegate.onFocused();
44
- }
45
-
46
- return super.onRequestSendAccessibilityEvent(child, event);
47
- }
48
-
49
- @Override
50
- protected void onAttachedToWindow() {
51
- super.onAttachedToWindow();
52
- if (autoFocus && !autoFocusOnce) {
53
- autoFocusOnce = true;
54
-
55
- if (!isViewFocused()) {
56
- hasBeenFocused = false;
57
- a11yFocusDelegate.requestFocus();
58
- }
59
- }
60
- }
61
- }