react-native-a11y-order 0.8.2 → 0.9.1-rc

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 (61) hide show
  1. package/README.md +25 -152
  2. package/android/build.gradle +0 -18
  3. package/android/src/main/java/com/a11yorder/services/focus/A11yFocusDelegate.java +10 -32
  4. package/android/src/main/java/com/a11yorder/services/order/A11yOrderService.java +70 -65
  5. package/android/src/main/java/com/a11yorder/services/order/linking/A11yLinkingQueue.java +37 -63
  6. package/android/src/main/java/com/a11yorder/services/order/linking/A11yOrderLinking.java +11 -14
  7. package/android/src/main/java/com/a11yorder/services/order/linking/WeakTreeMap.java +53 -31
  8. package/android/src/main/java/com/a11yorder/utils/A11yHelper.java +39 -59
  9. package/android/src/main/java/com/a11yorder/utils/ChoreographerUtils.java +7 -12
  10. package/android/src/main/java/com/a11yorder/utils/FragmentUtils.java +8 -48
  11. package/android/src/main/java/com/a11yorder/views/A11yIndexView/A11yIndexView.java +1 -1
  12. package/android/src/main/java/com/a11yorder/views/A11yLockView/A11yLockViewManager.java +5 -0
  13. package/android/src/main/java/com/a11yorder/views/A11yView/A11yView.java +1 -1
  14. package/android/src/oldarch/A11yLockViewManagerSpec.java +2 -0
  15. package/ios/delegates/RNAOViewItemDelegate/RNAOViewItemDelegate.mm +1 -1
  16. package/ios/extensions/RCTModalHostViewComponentView+RNAOA11yOrder.mm +21 -21
  17. package/ios/extensions/UIView+RNAOA11yOrder.mm +17 -20
  18. package/ios/extensions/UIViewController+RNAOA11yOrder.mm +8 -8
  19. package/ios/helpers/RNAOSwizzleInstall.h +30 -0
  20. package/ios/services/RNAOA11yItemDelegate/RNAOA11yItemDelegate.h +4 -6
  21. package/ios/services/RNAOA11yItemDelegate/RNAOA11yItemDelegate.mm +98 -87
  22. package/ios/services/RNAOA11yOrderLinking/RNAOA11yOrderLinking.h +5 -3
  23. package/ios/services/RNAOA11yOrderLinking/RNAOA11yOrderLinking.mm +49 -49
  24. package/ios/services/RNAOA11yRelationship/RNAOA11yRelationship.h +1 -0
  25. package/ios/services/RNAOA11yRelationship/RNAOA11yRelationship.mm +42 -36
  26. package/ios/services/RNAOSortedMap/RNAOSortedMap.h +2 -1
  27. package/ios/services/RNAOSortedMap/RNAOSortedMap.mm +48 -47
  28. package/ios/views/RNAOA11yLockView/RNAOA11yLockView.h +4 -2
  29. package/ios/views/RNAOA11yLockView/RNAOA11yLockView.mm +89 -3
  30. package/ios/views/RNAOA11yLockView/RNAOA11yLockViewManager.mm +3 -0
  31. package/lib/commonjs/components/A11yLock/A11yBaseLock/A11yBaseLock.js +18 -2
  32. package/lib/commonjs/components/A11yLock/A11yBaseLock/A11yBaseLock.js.map +1 -1
  33. package/lib/commonjs/components/A11yLock/A11yFocusTrap/A11yFocusTrap.js +23 -7
  34. package/lib/commonjs/components/A11yLock/A11yFocusTrap/A11yFocusTrap.js.map +1 -1
  35. package/lib/commonjs/nativeSpecs/A11yLockNativeComponent.ts +1 -0
  36. package/lib/module/components/A11yLock/A11yBaseLock/A11yBaseLock.js +17 -2
  37. package/lib/module/components/A11yLock/A11yBaseLock/A11yBaseLock.js.map +1 -1
  38. package/lib/module/components/A11yLock/A11yFocusTrap/A11yFocusTrap.js +23 -7
  39. package/lib/module/components/A11yLock/A11yFocusTrap/A11yFocusTrap.js.map +1 -1
  40. package/lib/module/nativeSpecs/A11yLockNativeComponent.ts +1 -0
  41. package/lib/typescript/src/components/A11yLock/A11yBaseLock/A11yBaseLock.d.ts +2 -1
  42. package/lib/typescript/src/components/A11yLock/A11yBaseLock/A11yBaseLock.d.ts.map +1 -1
  43. package/lib/typescript/src/components/A11yLock/A11yFocusTrap/A11yFocusTrap.d.ts +1 -1
  44. package/lib/typescript/src/components/A11yLock/A11yFocusTrap/A11yFocusTrap.d.ts.map +1 -1
  45. package/lib/typescript/src/index.d.ts +1 -1
  46. package/lib/typescript/src/nativeSpecs/A11yLockNativeComponent.d.ts +1 -0
  47. package/lib/typescript/src/nativeSpecs/A11yLockNativeComponent.d.ts.map +1 -1
  48. package/lib/typescript/src/types/A11yLock.types.d.ts +1 -0
  49. package/lib/typescript/src/types/A11yLock.types.d.ts.map +1 -1
  50. package/package.json +3 -2
  51. package/src/components/A11yLock/A11yBaseLock/A11yBaseLock.tsx +20 -3
  52. package/src/components/A11yLock/A11yFocusTrap/A11yFocusTrap.tsx +24 -5
  53. package/src/nativeSpecs/A11yLockNativeComponent.ts +1 -0
  54. package/src/types/A11yLock.types.ts +1 -0
  55. package/lib/commonjs/components/A11yLock/A11yBaseLock/A11yBaseLock.android.js +0 -23
  56. package/lib/commonjs/components/A11yLock/A11yBaseLock/A11yBaseLock.android.js.map +0 -1
  57. package/lib/module/components/A11yLock/A11yBaseLock/A11yBaseLock.android.js +0 -18
  58. package/lib/module/components/A11yLock/A11yBaseLock/A11yBaseLock.android.js.map +0 -1
  59. package/lib/typescript/src/components/A11yLock/A11yBaseLock/A11yBaseLock.android.d.ts +0 -4
  60. package/lib/typescript/src/components/A11yLock/A11yBaseLock/A11yBaseLock.android.d.ts.map +0 -1
  61. package/src/components/A11yLock/A11yBaseLock/A11yBaseLock.android.tsx +0 -16
@@ -1,19 +1,15 @@
1
1
  package com.a11yorder.services.order.linking;
2
2
 
3
-
4
3
  import android.view.View;
5
4
 
6
5
  import java.util.HashMap;
7
6
  import java.util.Map;
8
7
 
9
8
  public class A11yOrderLinking {
10
-
11
9
  private static A11yOrderLinking instance;
12
- private final Map<String, A11yLinkingQueue> relationships;
10
+ private final Map<String, A11yLinkingQueue> relationships = new HashMap<>();
13
11
 
14
- private A11yOrderLinking() {
15
- relationships = new HashMap<>();
16
- }
12
+ private A11yOrderLinking() {}
17
13
 
18
14
  public static synchronized A11yOrderLinking getInstance() {
19
15
  if (instance == null) {
@@ -21,24 +17,25 @@ public class A11yOrderLinking {
21
17
  }
22
18
  return instance;
23
19
  }
24
- public void addViewRelationship(View view, String key, int position) {
25
- A11yLinkingQueue queue = relationships.get(key);
26
20
 
21
+ private A11yLinkingQueue getOrCreateQueue(String key) {
22
+ A11yLinkingQueue queue = relationships.get(key);
27
23
  if (queue == null) {
28
24
  queue = new A11yLinkingQueue();
29
25
  relationships.put(key, queue);
30
26
  }
31
-
32
- queue.addPosition(view, position);
27
+ return queue;
33
28
  }
34
29
 
30
+ public void addViewRelationship(View view, String key, int position) {
31
+ getOrCreateQueue(key).addPosition(view, position);
32
+ }
35
33
 
36
- public void removeRelationship(String key, int index) {
34
+ public void removeRelationship(String key, int position) {
37
35
  A11yLinkingQueue queue = relationships.get(key);
38
36
  if (queue == null) return;
39
-
40
- queue.removeFromOrder(index);
41
- if(queue.isEmpty()) {
37
+ queue.removeFromOrder(position);
38
+ if (queue.isEmpty()) {
42
39
  relationships.remove(key);
43
40
  }
44
41
  }
@@ -5,58 +5,80 @@ import android.view.View;
5
5
  import java.lang.ref.WeakReference;
6
6
  import java.util.Map;
7
7
  import java.util.NavigableMap;
8
- import java.util.Set;
9
8
  import java.util.TreeMap;
10
9
 
11
10
  public class WeakTreeMap {
12
- public NavigableMap<Integer, WeakReference<View>> viewMap = new TreeMap<>();
11
+ private final NavigableMap<Integer, WeakReference<View>> viewMap = new TreeMap<>();
13
12
 
14
- public static View unwrapViewRef(Map. Entry<Integer, WeakReference<View>> viewRef) {
15
- if(viewRef == null || viewRef.getValue() == null) return null;
16
- return viewRef.getValue().get();
13
+ public void put(int position, View view) {
14
+ viewMap.put(position, new WeakReference<>(view));
17
15
  }
18
16
 
19
- public View getNext (int position) {
20
- Map.Entry<Integer, WeakReference<View>> view = viewMap.higherEntry(position);
21
- if(view == null || view.getValue() == null) return null;
22
- return view.getValue().get();
17
+ public View get(int position) {
18
+ WeakReference<View> ref = viewMap.get(position);
19
+ return ref != null ? ref.get() : null;
23
20
  }
24
21
 
25
- public View getPrev (int position) {
26
- Map.Entry<Integer, WeakReference<View>> view = viewMap.lowerEntry(position);
27
- if(view == null || view.getValue() == null) return null;
28
- return view.getValue().get();
22
+ public void remove(int position) {
23
+ viewMap.remove(position);
24
+ // Purge zombie entries left by GC while we're already mutating the map.
25
+ viewMap.values().removeIf(ref -> ref.get() == null);
29
26
  }
30
27
 
31
- public WeakReference<View> put (int position, View view) {
32
- return viewMap.put(position, new WeakReference<>(view));
28
+ /**
29
+ * Returns the nearest live view at a position strictly greater than {@code position},
30
+ * skipping any GC'd entries along the way.
31
+ */
32
+ public View getNext(int position) {
33
+ for (WeakReference<View> ref : viewMap.tailMap(position, false).values()) {
34
+ View v = ref.get();
35
+ if (v != null) return v;
36
+ }
37
+ return null;
33
38
  }
34
39
 
35
- public View last () {
36
- Map.Entry<Integer, WeakReference<View>> lastView = viewMap.lastEntry();
37
- if(lastView == null || lastView.getValue() == null) return null;
38
- return lastView.getValue().get();
40
+ /**
41
+ * Returns the nearest live view at a position strictly less than {@code position},
42
+ * skipping any GC'd entries along the way.
43
+ */
44
+ public View getPrev(int position) {
45
+ for (WeakReference<View> ref : viewMap.headMap(position, false).descendingMap().values()) {
46
+ View v = ref.get();
47
+ if (v != null) return v;
48
+ }
49
+ return null;
39
50
  }
40
51
 
41
- public void remove (int position) {
42
- this.viewMap.remove(position);
52
+ /** Returns the live view with the highest position, skipping any GC'd entries. */
53
+ public View last() {
54
+ for (WeakReference<View> ref : viewMap.descendingMap().values()) {
55
+ View v = ref.get();
56
+ if (v != null) return v;
57
+ }
58
+ return null;
43
59
  }
44
60
 
45
- public View get (int position) {
46
- WeakReference<View> viewRef = this.viewMap.get(position);
47
- if(viewRef == null) return null;
48
- return viewRef.get();
61
+ public boolean containsKey(int position) {
62
+ return viewMap.containsKey(position);
49
63
  }
50
64
 
51
- public Set<Map.Entry<Integer, WeakReference<View>>> entrySet() {
52
- return this.viewMap.entrySet();
65
+ /** Returns {@code true} only if there are no live (non-GC'd) views in the map. */
66
+ public boolean isEmpty() {
67
+ for (WeakReference<View> ref : viewMap.values()) {
68
+ if (ref.get() != null) return false;
69
+ }
70
+ return true;
53
71
  }
54
72
 
55
- public boolean containsKey(int position) {
56
- return this.viewMap.containsKey(position);
73
+ /** Visits every live entry in ascending position order. */
74
+ public void forEachLive(LiveEntryAction action) {
75
+ for (Map.Entry<Integer, WeakReference<View>> entry : viewMap.entrySet()) {
76
+ View v = entry.getValue().get();
77
+ if (v != null) action.run(entry.getKey(), v);
78
+ }
57
79
  }
58
80
 
59
- public boolean isEmpty() {
60
- return this.viewMap.isEmpty();
81
+ public interface LiveEntryAction {
82
+ void run(int position, View view);
61
83
  }
62
84
  }
@@ -6,102 +6,82 @@ import android.view.ViewGroup;
6
6
  import android.view.accessibility.AccessibilityEvent;
7
7
  import android.view.accessibility.AccessibilityManager;
8
8
 
9
+ import androidx.annotation.NonNull;
9
10
  import androidx.annotation.Nullable;
10
11
  import androidx.core.view.ViewCompat;
11
12
 
12
13
  public class A11yHelper {
14
+
13
15
  public static boolean isAccessible(@Nullable View view) {
14
16
  return view != null && ViewCompat.isImportantForAccessibility(view);
15
17
  }
16
18
 
17
- public static View findFirstAccessible(@Nullable ViewGroup viewGroup, boolean ignoreRoot) {
18
- if (viewGroup == null) {
19
- return null;
20
- }
21
-
22
- if (!ignoreRoot && isAccessible(viewGroup)) {
23
- return viewGroup;
24
- }
25
-
26
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
27
- View child = viewGroup.getChildAt(i);
28
- if (isAccessible(child)) {
29
- return child;
30
- }
19
+ public static boolean isFocused(@Nullable View view) {
20
+ return view != null && view.isAccessibilityFocused();
21
+ }
31
22
 
32
- if (child instanceof ViewGroup) {
33
- View accessibleChild = findFirstAccessible((ViewGroup) child, true);
34
- if (accessibleChild != null) {
35
- return accessibleChild;
36
- }
23
+ public static void focus(@Nullable View view) {
24
+ if (view == null || isFocused(view)) return;
25
+ ChoreographerUtils.run(() -> {
26
+ if (!isFocused(view)) {
27
+ view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
37
28
  }
38
- }
29
+ });
30
+ }
39
31
 
40
- return null;
32
+ public static boolean isA11yServiceEnabled(@NonNull Context context) {
33
+ AccessibilityManager accessibilityManager =
34
+ (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
35
+ return accessibilityManager != null
36
+ && accessibilityManager.isEnabled()
37
+ && accessibilityManager.isTouchExplorationEnabled();
41
38
  }
42
39
 
43
40
  public static View findFirstAccessible(@Nullable ViewGroup viewGroup) {
44
41
  return findFirstAccessible(viewGroup, false);
45
42
  }
46
43
 
47
- public static boolean isFocused(@Nullable View view) {
48
- if (view == null) return false;
49
- return view.isAccessibilityFocused();
50
- }
51
-
52
- private static void baseFocus(@Nullable View view) {
53
- if (view != null) {
54
- view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
55
- }
56
- }
44
+ public static View findFirstAccessible(@Nullable ViewGroup viewGroup, boolean ignoreRoot) {
45
+ if (viewGroup == null) return null;
57
46
 
58
- public static void focus(@Nullable View view) {
59
- if (view == null || isFocused(view)) return;
60
- ChoreographerUtils.run(() -> baseFocus(view));
61
- }
47
+ if (!ignoreRoot && isAccessible(viewGroup)) return viewGroup;
62
48
 
63
- public static boolean isA11yServiceEnabled(Context context) {
64
- AccessibilityManager accessibilityManager =
65
- (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
49
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
50
+ View child = viewGroup.getChildAt(i);
51
+ if (isAccessible(child)) return child;
66
52
 
67
- if (accessibilityManager == null) {
68
- return false;
53
+ if (child instanceof ViewGroup) {
54
+ View accessibleChild = findFirstAccessible((ViewGroup) child, true);
55
+ if (accessibleChild != null) return accessibleChild;
56
+ }
69
57
  }
70
58
 
71
- return accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled();
59
+ return null;
72
60
  }
73
61
 
74
- public static View findFirstFocusable(@Nullable ViewGroup viewGroup, boolean ignoreRoot) {
75
- if (viewGroup == null) {
76
- return null;
77
- }
62
+ public static View findFirstFocusable(@Nullable ViewGroup viewGroup) {
63
+ return findFirstFocusable(viewGroup, false);
64
+ }
78
65
 
79
- if (!ignoreRoot && isKeyboardFocusable(viewGroup)) {
80
- return viewGroup;
81
- }
66
+ private static View findFirstFocusable(@Nullable ViewGroup viewGroup, boolean ignoreRoot) {
67
+ if (viewGroup == null) return null;
68
+
69
+ if (!ignoreRoot && isKeyboardFocusable(viewGroup)) return viewGroup;
82
70
 
83
71
  for (int i = 0; i < viewGroup.getChildCount(); i++) {
84
72
  View child = viewGroup.getChildAt(i);
85
- if (isKeyboardFocusable(child)) {
86
- return child;
87
- }
73
+ if (isKeyboardFocusable(child)) return child;
88
74
 
89
75
  if (child instanceof ViewGroup) {
90
76
  View focusableChild = findFirstFocusable((ViewGroup) child, true);
91
- if (focusableChild != null) {
92
- return focusableChild;
93
- }
77
+ if (focusableChild != null) return focusableChild;
94
78
  }
95
79
  }
96
80
 
97
81
  return null;
98
82
  }
99
83
 
100
- public static View findFirstFocusable(@Nullable ViewGroup viewGroup) {
101
- return findFirstFocusable(viewGroup, false);
102
- }
103
-
104
- private static boolean isKeyboardFocusable(View view) {
84
+ private static boolean isKeyboardFocusable(@NonNull View view) {
105
85
  return view.isFocusable() && view.getVisibility() == View.VISIBLE && view.isEnabled();
106
86
  }
107
87
  }
@@ -1,34 +1,29 @@
1
1
  package com.a11yorder.utils;
2
2
 
3
3
  import android.view.Choreographer;
4
- import androidx.annotation.Nullable;
4
+
5
+ import androidx.annotation.NonNull;
5
6
 
6
7
  public class ChoreographerUtils {
7
8
 
8
- public static void run(@Nullable Runnable task) {
9
+ public static void run(@NonNull Runnable task) {
9
10
  runAfterFrames(2, task);
10
11
  }
11
- public static void runAfterFrames(int frameCount, @Nullable Runnable task) {
12
- if (frameCount <= 0 || task == null) {
13
- return;
14
- }
15
12
 
13
+ private static void runAfterFrames(int frameCount, @NonNull Runnable task) {
16
14
  Choreographer choreographer = Choreographer.getInstance();
17
15
 
18
- Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
16
+ choreographer.postFrameCallback(new Choreographer.FrameCallback() {
19
17
  private int frameCounter = frameCount;
20
18
 
21
19
  @Override
22
20
  public void doFrame(long frameTimeNanos) {
23
- frameCounter--;
24
- if (frameCounter <= 0) {
21
+ if (--frameCounter <= 0) {
25
22
  task.run();
26
23
  } else {
27
24
  choreographer.postFrameCallback(this);
28
25
  }
29
26
  }
30
- };
31
-
32
- choreographer.postFrameCallback(frameCallback);
27
+ });
33
28
  }
34
29
  }
@@ -1,68 +1,28 @@
1
1
  package com.a11yorder.utils;
2
2
 
3
- import android.app.Activity;
4
3
  import android.view.View;
5
- import android.view.animation.Animation;
6
4
 
7
5
  import androidx.annotation.NonNull;
8
6
  import androidx.annotation.Nullable;
9
7
  import androidx.fragment.app.Fragment;
10
- import androidx.fragment.app.FragmentActivity;
11
8
  import androidx.fragment.app.FragmentManager;
9
+ import androidx.lifecycle.DefaultLifecycleObserver;
10
+ import androidx.lifecycle.LifecycleOwner;
12
11
 
13
12
  public class FragmentUtils {
14
13
 
15
- public static void waitForAnimationEnd(@NonNull Animation animation, @NonNull Runnable onAnimationEnd) {
16
- animation.setAnimationListener(new Animation.AnimationListener() {
14
+ public static void waitForFragmentResume(@NonNull Fragment fragment, @NonNull Runnable onReady) {
15
+ fragment.getLifecycle().addObserver(new DefaultLifecycleObserver() {
17
16
  @Override
18
- public void onAnimationStart(Animation animation) {
19
- }
20
-
21
- @Override
22
- public void onAnimationEnd(Animation animation) {
23
- onAnimationEnd.run();
24
- }
25
-
26
- @Override
27
- public void onAnimationRepeat(Animation animation) {
28
- }
29
- });
30
- }
31
-
32
- public static void waitForFragmentAnimation (@NonNull Fragment fragment, @NonNull Runnable onReady) {
33
- View fragmentView = fragment.getView();
34
- if (fragmentView != null) {
35
- Animation fragmentAnimation = fragmentView.getAnimation();
36
- if (fragmentAnimation != null) {
37
- waitForAnimationEnd(fragmentAnimation, onReady);
38
- } else {
17
+ public void onResume(@NonNull LifecycleOwner owner) {
18
+ owner.getLifecycle().removeObserver(this);
39
19
  onReady.run();
40
20
  }
41
- }
42
- }
43
-
44
- public static void waitForFragment(Activity activity, Fragment current, @NonNull Runnable onReady) {
45
- if (!(activity instanceof FragmentActivity)) {
46
- return;
47
- }
48
-
49
- FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager();
50
- fragmentManager.registerFragmentLifecycleCallbacks(
51
- new FragmentManager.FragmentLifecycleCallbacks() {
52
- @Override
53
- public void onFragmentResumed(@NonNull FragmentManager fm, @NonNull Fragment f) {
54
- super.onFragmentResumed(fm, f);
55
- if (f == current) {
56
- waitForFragmentAnimation(f, onReady);
57
- fragmentManager.unregisterFragmentLifecycleCallbacks(this); // Unregister to prevent future callbacks
58
- }
59
- }
60
- }, false);
21
+ });
61
22
  }
62
23
 
63
24
  @Nullable
64
- public static
65
- Fragment findFragmentSafely(View view) {
25
+ public static Fragment findFragmentSafely(View view) {
66
26
  try {
67
27
  return FragmentManager.findFragment(view);
68
28
  } catch (Exception ignored) {
@@ -29,7 +29,7 @@ public class A11yIndexView extends ReactViewGroup {
29
29
  }
30
30
 
31
31
  public void setOrderKey(String orderKey) {
32
- this.orderService.orderKey = orderKey;
32
+ this.orderService.setOrderKey(orderKey);
33
33
  }
34
34
 
35
35
  @Override
@@ -35,4 +35,9 @@ public class A11yLockViewManager extends com.a11yorder.A11yLockViewManagerSpec<A
35
35
  public void setLockDisabled(A11yLockView view, boolean value) {
36
36
  view.setLockDisabled(value);
37
37
  }
38
+
39
+ @Override
40
+ public void setForceLock(A11yLockView view, boolean value) {
41
+ //stub
42
+ }
38
43
  }
@@ -64,7 +64,7 @@ public class A11yView extends A11yViewGroup implements A11yFocusProtocol {
64
64
 
65
65
  if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED && autoFocus && !hasBeenFocused) {
66
66
  hasBeenFocused = true;
67
- a11yFocusDelegate.onAccessibilityEvent(child, event);
67
+ a11yFocusDelegate.onFocused();
68
68
  }
69
69
 
70
70
  if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED && isSubChild) {
@@ -9,5 +9,7 @@ public abstract class A11yLockViewManagerSpec<T extends A11yLockView> extends Re
9
9
  public abstract void setContainerKey(T view, String value);
10
10
 
11
11
  public abstract void setLockDisabled(T view, boolean value);
12
+
13
+ public abstract void setForceLock(A11yLockView view, boolean value);
12
14
  }
13
15
 
@@ -59,7 +59,7 @@
59
59
 
60
60
  - (void)clear {
61
61
  if(!_delegate) return;
62
- [_delegate onFocusItemLinked: _linkView];
62
+ [_delegate onFocusItemRemoved: _linkView];
63
63
  _isLinked = false;
64
64
  _linkView = nil;
65
65
  }
@@ -7,6 +7,7 @@
7
7
 
8
8
  #import <Foundation/Foundation.h>
9
9
  #import "RNAOSwizzleInstanceMethod.h"
10
+ #import "RNAOSwizzleInstall.h"
10
11
  #import <objc/runtime.h>
11
12
  #import "RNAOA11yAnnounceService.h"
12
13
  #import "RCTModalHostViewComponentView+RNAOA11yOrder.h"
@@ -16,20 +17,19 @@
16
17
 
17
18
  @implementation RCTModalHostViewComponentView (RNAOA11yOrder)
18
19
 
19
- + (void)load
20
- {
21
- static dispatch_once_t once_token;
22
-
23
- dispatch_once(&once_token, ^{
24
- RNAOSwizzleInstanceMethod([self class],
25
- @selector(dismissViewController:animated:completion:),
26
- @selector(rnaoDismissViewController:animated:completion:));
27
- RNAOSwizzleInstanceMethod([self class],
20
+ static void RNAORegisterModalPresentationSwizzles(void) {
21
+ Class cls = objc_getClass("RCTModalHostViewComponentView");
22
+ if (!cls) return;
23
+ RNAOSwizzleInstanceMethod(cls,
24
+ @selector(dismissViewController:animated:completion:),
25
+ @selector(rnaoDismissViewController:animated:completion:));
26
+ RNAOSwizzleInstanceMethod(cls,
28
27
  @selector(presentViewController:animated:completion:),
29
28
  @selector(rnaoPresentViewController:animated:completion:));
30
- });
31
29
  }
32
30
 
31
+ RNAO_INSTALL_SWIZZLES(RNAORegisterModalPresentationSwizzles)
32
+
33
33
  - (void)rnaoPresentViewController:(UIViewController *)modalViewController
34
34
  animated:(BOOL)animated
35
35
  completion:(void (^)(void))completion
@@ -52,19 +52,19 @@
52
52
 
53
53
  @implementation RCTModalHostView (RNAOA11yOrder)
54
54
 
55
- + (void)load
56
- {
57
- static dispatch_once_t once_token;
58
- dispatch_once(&once_token, ^{
59
- RNAOSwizzleInstanceMethod([self class],
60
- @selector(ensurePresentedOnlyIfNeeded),
61
- @selector(rnao_ensurePresentedOnlyIfNeeded));
62
- RNAOSwizzleInstanceMethod([self class],
63
- @selector(dismissModalViewController),
64
- @selector(rnao_dismissModalViewController));
65
- });
55
+ static void RNAORegisterModalPresentationSwizzles(void) {
56
+ Class cls = objc_getClass("RCTModalHostView");
57
+ if (!cls) return;
58
+ RNAOSwizzleInstanceMethod(cls,
59
+ @selector(ensurePresentedOnlyIfNeeded),
60
+ @selector(rnao_ensurePresentedOnlyIfNeeded));
61
+ RNAOSwizzleInstanceMethod(cls,
62
+ @selector(dismissModalViewController),
63
+ @selector(rnao_dismissModalViewController));
66
64
  }
67
65
 
66
+ RNAO_INSTALL_SWIZZLES(RNAORegisterModalPresentationSwizzles)
67
+
68
68
  - (void)rnao_ensurePresentedOnlyIfNeeded
69
69
  {
70
70
  [self rnao_ensurePresentedOnlyIfNeeded];
@@ -9,6 +9,7 @@
9
9
 
10
10
  #import "UIView+RNAOA11yOrder.h"
11
11
  #import "RNAOSwizzleInstanceMethod.h"
12
+ #import "RNAOSwizzleInstall.h"
12
13
  #import <objc/runtime.h>
13
14
 
14
15
  #ifdef RCT_NEW_ARCH_ENABLED
@@ -55,28 +56,24 @@ static char kRNAOScreenReaderFocusDelegate;
55
56
  }
56
57
 
57
58
 
58
- + (void)load {
59
- static dispatch_once_t onceToken;
60
- dispatch_once(&onceToken, ^{
61
- #ifdef RCT_NEW_ARCH_ENABLED
62
- Class swizzleClass = [RCTViewComponentView class];
63
- #else
64
- Class swizzleClass = [RCTView class];
65
- #endif
66
-
67
- RNAOSwizzleInstanceMethod(
68
- swizzleClass,
69
- @selector(accessibilityElementDidBecomeFocused),
70
- @selector(rnao_accessibilityElementDidBecomeFocused)
71
- );
72
- RNAOSwizzleInstanceMethod(
73
- swizzleClass,
74
- @selector(accessibilityElementDidLoseFocus),
75
- @selector(rnao_accessibilityElementDidLoseFocus)
76
- );
77
- });
59
+ static void RNAORegisterViewFocusSwizzles(void) {
60
+ #ifdef RCT_NEW_ARCH_ENABLED
61
+ Class swizzleClass = objc_getClass("RCTViewComponentView");
62
+ #else
63
+ Class swizzleClass = objc_getClass("RCTView");
64
+ #endif
65
+ if (!swizzleClass) return;
66
+
67
+ RNAOSwizzleInstanceMethod(swizzleClass,
68
+ @selector(accessibilityElementDidBecomeFocused),
69
+ @selector(rnao_accessibilityElementDidBecomeFocused));
70
+ RNAOSwizzleInstanceMethod(swizzleClass,
71
+ @selector(accessibilityElementDidLoseFocus),
72
+ @selector(rnao_accessibilityElementDidLoseFocus));
78
73
  }
79
74
 
75
+ RNAO_INSTALL_SWIZZLES(RNAORegisterViewFocusSwizzles)
76
+
80
77
  - (void)rnao_accessibilityElementDidBecomeFocused {
81
78
  [self rnao_accessibilityElementDidBecomeFocused];
82
79
  [self trigerScreenReaderFocusDelegate: true];
@@ -9,6 +9,7 @@
9
9
 
10
10
  #import "UIViewController+RNAOA11yOrder.h"
11
11
  #import "RNAOSwizzleInstanceMethod.h"
12
+ #import "RNAOSwizzleInstall.h"
12
13
  #import "RNAOA11yAnnounceService.h"
13
14
  #import <objc/runtime.h>
14
15
 
@@ -34,16 +35,15 @@ static char kRnaoFocusRestoreKey;
34
35
  return [objc_getAssociatedObject(self, &kRnaoFocusRestoreKey) boolValue];
35
36
  }
36
37
 
37
- + (void)load
38
- {
39
- static dispatch_once_t once_token;
40
-
41
- dispatch_once(&once_token, ^{
42
- RNAOSwizzleInstanceMethod([self class], @selector(viewDidAppear:), @selector(rnaoViewDidAppear:));
43
- RNAOSwizzleInstanceMethod([self class], @selector(viewWillDisappear:), @selector(rnaoViewWillDisappear:));
44
- });
38
+ static void RNAORegisterViewControllerSwizzles(void) {
39
+ Class cls = objc_getClass("UIViewController");
40
+ if (!cls) return;
41
+ RNAOSwizzleInstanceMethod(cls, @selector(viewDidAppear:), @selector(rnaoViewDidAppear:));
42
+ RNAOSwizzleInstanceMethod(cls, @selector(viewWillDisappear:), @selector(rnaoViewWillDisappear:));
45
43
  }
46
44
 
45
+ RNAO_INSTALL_SWIZZLES(RNAORegisterViewControllerSwizzles);
46
+
47
47
 
48
48
  - (void)saveAccessibilityFocusedView
49
49
  {
@@ -0,0 +1,30 @@
1
+ //
2
+ // RNAOSwizzleInstall.h
3
+ // react-native-a11y-order
4
+ //
5
+ // Created by Artur Kalach on 03/05/2026.
6
+ //
7
+
8
+ #ifndef RNAOSwizzleInstall_h
9
+ #define RNAOSwizzleInstall_h
10
+
11
+ #define RNAO_CONCAT_(a, b) a##b
12
+ #define RNAO_CONCAT(a, b) RNAO_CONCAT_(a, b)
13
+
14
+ #ifdef RCT_DYNAMIC_FRAMEWORKS
15
+
16
+ #define RNAO_INSTALL_SWIZZLES(registerFn) \
17
+ __attribute__((constructor)) \
18
+ static void RNAO_CONCAT(RNAOInstall_, registerFn)(void) { registerFn(); }
19
+
20
+ #else
21
+
22
+ #define RNAO_INSTALL_SWIZZLES(registerFn) \
23
+ +(void)load { \
24
+ static dispatch_once_t RNAO_CONCAT(once_, registerFn); \
25
+ dispatch_once(&RNAO_CONCAT(once_, registerFn), ^{ registerFn(); }); \
26
+ }
27
+
28
+ #endif
29
+
30
+ #endif /* RNAOSwizzleInstall_h */