@lodev09/react-native-true-sheet 3.11.0-beta.13 → 3.11.0-beta.15
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.
|
@@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
31
31
|
@optional
|
|
32
32
|
|
|
33
33
|
- (void)containerViewHeaderDidChangeSize:(CGSize)newSize;
|
|
34
|
+
- (void)containerViewFooterDidChangeSize:(CGSize)newSize;
|
|
34
35
|
|
|
35
36
|
@end
|
|
36
37
|
|
|
@@ -71,6 +72,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
71
72
|
*/
|
|
72
73
|
- (void)layoutFooter;
|
|
73
74
|
|
|
75
|
+
- (BOOL)hasAccessibilityFooterElements;
|
|
76
|
+
|
|
74
77
|
/**
|
|
75
78
|
* Setup scrollable content
|
|
76
79
|
*/
|
|
@@ -88,11 +88,22 @@ using namespace facebook::react;
|
|
|
88
88
|
[elements addObject:_contentView];
|
|
89
89
|
}
|
|
90
90
|
if (_footerView) {
|
|
91
|
-
|
|
91
|
+
// Footer hosts are layout containers; expose their children when present so
|
|
92
|
+
// VoiceOver and XCTest can target the actual footer controls.
|
|
93
|
+
NSArray *footerElements = _footerView.accessibilityElements;
|
|
94
|
+
if (footerElements.count > 0) {
|
|
95
|
+
[elements addObjectsFromArray:footerElements];
|
|
96
|
+
} else {
|
|
97
|
+
[elements addObject:_footerView];
|
|
98
|
+
}
|
|
92
99
|
}
|
|
93
100
|
return elements;
|
|
94
101
|
}
|
|
95
102
|
|
|
103
|
+
- (BOOL)hasAccessibilityFooterElements {
|
|
104
|
+
return _footerView && _footerView.accessibilityElements.count > 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
96
107
|
#pragma mark - Layout
|
|
97
108
|
|
|
98
109
|
- (void)layoutSubviews {
|
|
@@ -251,6 +262,7 @@ using namespace facebook::react;
|
|
|
251
262
|
#pragma mark - TrueSheetFooterViewDelegate
|
|
252
263
|
|
|
253
264
|
- (void)footerViewDidChangeSize:(CGSize)newSize {
|
|
265
|
+
[self.delegate containerViewFooterDidChangeSize:newSize];
|
|
254
266
|
if (@available(iOS 26.0, *)) {
|
|
255
267
|
[self setupEdgeInteractions];
|
|
256
268
|
}
|
|
@@ -53,13 +53,19 @@ using namespace facebook::react;
|
|
|
53
53
|
- (NSArray *)accessibilityElements {
|
|
54
54
|
NSMutableArray *elements = [NSMutableArray array];
|
|
55
55
|
[self collectAccessibilityElementsFromView:self into:elements];
|
|
56
|
-
|
|
56
|
+
if (elements.count > 0) {
|
|
57
|
+
return elements;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return [super accessibilityElements];
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
- (void)collectAccessibilityElementsFromView:(UIView *)view into:(NSMutableArray *)elements {
|
|
60
64
|
for (UIView *subview in view.subviews) {
|
|
61
65
|
if (subview.isAccessibilityElement || subview.accessibilityLabel || subview.accessibilityIdentifier) {
|
|
62
66
|
[elements addObject:subview];
|
|
67
|
+
} else if (subview.accessibilityElements.count > 0) {
|
|
68
|
+
[elements addObjectsFromArray:subview.accessibilityElements];
|
|
63
69
|
} else {
|
|
64
70
|
[self collectAccessibilityElementsFromView:subview into:elements];
|
|
65
71
|
}
|
package/ios/TrueSheetView.mm
CHANGED
|
@@ -573,6 +573,10 @@ using namespace facebook::react;
|
|
|
573
573
|
[self setupSheetDetentsForSizeChange];
|
|
574
574
|
}
|
|
575
575
|
|
|
576
|
+
- (void)containerViewFooterDidChangeSize:(CGSize)newSize {
|
|
577
|
+
[_controller setupAccessibilityContainer];
|
|
578
|
+
}
|
|
579
|
+
|
|
576
580
|
// When the ScrollView changes (e.g. conditional remount), re-pin the new ScrollView.
|
|
577
581
|
- (void)containerViewScrollViewDidChange {
|
|
578
582
|
[self setupScrollable];
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
//
|
|
8
8
|
|
|
9
9
|
#import "TrueSheetViewController.h"
|
|
10
|
+
#import "TrueSheetContainerView.h"
|
|
10
11
|
#import "TrueSheetContentView.h"
|
|
11
12
|
#import "core/TrueSheetBlurView.h"
|
|
12
13
|
#import "core/TrueSheetDetentCalculator.h"
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
|
|
19
20
|
#import <React/RCTLog.h>
|
|
20
21
|
#import <React/RCTScrollViewComponentView.h>
|
|
22
|
+
#import <objc/runtime.h>
|
|
21
23
|
#import <react/renderer/components/TrueSheetSpec/Props.h>
|
|
22
24
|
|
|
23
25
|
using namespace facebook::react;
|
|
@@ -32,8 +34,14 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
32
34
|
return fabs(a.position - b.position) <= 0.01 && fabs(a.detent - b.detent) <= 0.01 && fabs(a.index - b.index) <= 0.01;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
static char TrueSheetAccessibilityWindowOwnerKey;
|
|
38
|
+
static char TrueSheetAccessibilityWindowPreviousElementsKey;
|
|
39
|
+
|
|
35
40
|
@interface TrueSheetViewController ()
|
|
36
41
|
|
|
42
|
+
- (UIViewController *)accessibilityPresentingViewController;
|
|
43
|
+
- (void)restoreWindowAccessibilityElements;
|
|
44
|
+
- (void)setSheetAccessibilityElementsHidden:(BOOL)hidden;
|
|
37
45
|
- (void)setAccessibilityContentElement:(UIView *)contentView;
|
|
38
46
|
|
|
39
47
|
@end
|
|
@@ -57,6 +65,8 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
57
65
|
|
|
58
66
|
UIView *_anchorView;
|
|
59
67
|
|
|
68
|
+
__weak UIWindow *_accessibilityWindow;
|
|
69
|
+
|
|
60
70
|
TrueSheetBlurView *_blurView;
|
|
61
71
|
TrueSheetGrabberView *_grabberView;
|
|
62
72
|
TrueSheetDetentCalculator *_detentCalculator;
|
|
@@ -97,6 +107,7 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
- (void)dealloc {
|
|
110
|
+
[self restoreWindowAccessibilityElements];
|
|
100
111
|
[_transitioningTimer invalidate];
|
|
101
112
|
_transitioningTimer = nil;
|
|
102
113
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
@@ -227,6 +238,7 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
227
238
|
|
|
228
239
|
- (void)viewDidAppear:(BOOL)animated {
|
|
229
240
|
[super viewDidAppear:animated];
|
|
241
|
+
[self setSheetAccessibilityElementsHidden:NO];
|
|
230
242
|
|
|
231
243
|
if (!_isPresented) {
|
|
232
244
|
[_parentSheetController.delegate viewControllerDidBlur];
|
|
@@ -244,9 +256,10 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
244
256
|
});
|
|
245
257
|
|
|
246
258
|
[self setupGestureRecognizer];
|
|
247
|
-
[self setupAccessibilityContainer];
|
|
248
259
|
_isPresented = YES;
|
|
249
260
|
}
|
|
261
|
+
|
|
262
|
+
[self setupAccessibilityContainer];
|
|
250
263
|
}
|
|
251
264
|
|
|
252
265
|
- (void)setupAccessibilityContainer {
|
|
@@ -258,17 +271,124 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
258
271
|
[self setAccessibilityContentElement:contentView];
|
|
259
272
|
}
|
|
260
273
|
|
|
274
|
+
- (UIViewController *)accessibilityPresentingViewController {
|
|
275
|
+
UIViewController *presentingViewController = self.presentingViewController;
|
|
276
|
+
while ([presentingViewController isKindOfClass:[TrueSheetViewController class]] &&
|
|
277
|
+
presentingViewController.presentingViewController) {
|
|
278
|
+
presentingViewController = presentingViewController.presentingViewController;
|
|
279
|
+
}
|
|
280
|
+
return presentingViewController;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
- (void)restoreWindowAccessibilityElements {
|
|
284
|
+
UIWindow *window = _accessibilityWindow;
|
|
285
|
+
if (window) {
|
|
286
|
+
// The active sheet may temporarily own window accessibility traversal. Only
|
|
287
|
+
// restore the previous value when this controller still owns that override.
|
|
288
|
+
NSValue *ownerValue = objc_getAssociatedObject(window, &TrueSheetAccessibilityWindowOwnerKey);
|
|
289
|
+
if (ownerValue && ownerValue.nonretainedObjectValue == self) {
|
|
290
|
+
id previousElements = objc_getAssociatedObject(window, &TrueSheetAccessibilityWindowPreviousElementsKey);
|
|
291
|
+
window.accessibilityElements = previousElements == [NSNull null] ? nil : previousElements;
|
|
292
|
+
objc_setAssociatedObject(window, &TrueSheetAccessibilityWindowOwnerKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
293
|
+
objc_setAssociatedObject(
|
|
294
|
+
window, &TrueSheetAccessibilityWindowPreviousElementsKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
_accessibilityWindow = nil;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
- (void)setSheetAccessibilityElementsHidden:(BOOL)hidden {
|
|
302
|
+
self.view.accessibilityElementsHidden = hidden;
|
|
303
|
+
|
|
304
|
+
UIView *presentedView = self.presentationController.presentedView;
|
|
305
|
+
if (presentedView) {
|
|
306
|
+
presentedView.accessibilityElementsHidden = hidden;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
261
310
|
- (void)setAccessibilityContentElement:(UIView *)contentView {
|
|
311
|
+
BOOL hasAccessibilityFooterElements = [contentView isKindOfClass:[TrueSheetContainerView class]] &&
|
|
312
|
+
[(TrueSheetContainerView *)contentView hasAccessibilityFooterElements];
|
|
313
|
+
// Footer controls exposed as separate accessibility elements can be skipped
|
|
314
|
+
// by XCTest when the presented sheet is a hard modal accessibility boundary.
|
|
315
|
+
BOOL isAccessibilityModal = _dimmed && !hasAccessibilityFooterElements;
|
|
316
|
+
|
|
317
|
+
// At a hard modal boundary XCTest skips nested elements, so flatten the
|
|
318
|
+
// container's children into the array. Otherwise expose the container itself:
|
|
319
|
+
// its accessibilityElements getter recomputes live, so a footer/content subtree
|
|
320
|
+
// that remounts (e.g. swapping a footer button on a state change) stays
|
|
321
|
+
// discoverable instead of leaving this snapshot pointing at destroyed views.
|
|
322
|
+
NSArray *accessibilityElements;
|
|
323
|
+
if (isAccessibilityModal) {
|
|
324
|
+
NSArray *contentElements = contentView.accessibilityElements;
|
|
325
|
+
accessibilityElements = contentElements.count > 0 ? contentElements : @[ contentView ];
|
|
326
|
+
} else {
|
|
327
|
+
accessibilityElements = @[ contentView ];
|
|
328
|
+
}
|
|
329
|
+
|
|
262
330
|
self.view.isAccessibilityElement = NO;
|
|
263
331
|
self.view.accessibilityViewIsModal = YES;
|
|
264
|
-
self.view.accessibilityElements =
|
|
332
|
+
self.view.accessibilityElements = accessibilityElements;
|
|
265
333
|
|
|
266
334
|
UIView *presentedView = self.presentationController.presentedView;
|
|
267
335
|
if (presentedView) {
|
|
268
336
|
presentedView.isAccessibilityElement = NO;
|
|
269
|
-
presentedView.accessibilityViewIsModal =
|
|
270
|
-
presentedView.accessibilityElements =
|
|
337
|
+
presentedView.accessibilityViewIsModal = isAccessibilityModal;
|
|
338
|
+
presentedView.accessibilityElements = accessibilityElements;
|
|
339
|
+
|
|
340
|
+
UIWindow *window = self.view.window;
|
|
341
|
+
UIViewController *presentingViewController = [self accessibilityPresentingViewController];
|
|
342
|
+
if (window && presentingViewController.view) {
|
|
343
|
+
if (!_accessibilityWindow) {
|
|
344
|
+
_accessibilityWindow = window;
|
|
345
|
+
id previousElements = objc_getAssociatedObject(window, &TrueSheetAccessibilityWindowPreviousElementsKey);
|
|
346
|
+
if (!previousElements) {
|
|
347
|
+
previousElements = window.accessibilityElements ?: [NSNull null];
|
|
348
|
+
objc_setAssociatedObject(window, &TrueSheetAccessibilityWindowPreviousElementsKey, previousElements,
|
|
349
|
+
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
objc_setAssociatedObject(window, &TrueSheetAccessibilityWindowOwnerKey, [NSValue valueWithNonretainedObject:self],
|
|
353
|
+
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
354
|
+
window.accessibilityElements =
|
|
355
|
+
isAccessibilityModal ? @[ presentedView ] : @[ presentingViewController.view, presentedView ];
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
271
358
|
}
|
|
359
|
+
|
|
360
|
+
[self restoreWindowAccessibilityElements];
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
#pragma mark - Presentation
|
|
364
|
+
|
|
365
|
+
- (void)presentViewController:(UIViewController *)viewControllerToPresent
|
|
366
|
+
animated:(BOOL)flag
|
|
367
|
+
completion:(void (^)(void))completion {
|
|
368
|
+
// A non-sheet controller (e.g. an action sheet, alert, or image picker) is about
|
|
369
|
+
// to present over us. Clear our window accessibility override so UIKit's default
|
|
370
|
+
// traversal surfaces it for XCTest and assistive technologies; we reclaim the
|
|
371
|
+
// override when it dismisses. Nested sheets claim their own override.
|
|
372
|
+
if (![viewControllerToPresent isKindOfClass:[TrueSheetViewController class]]) {
|
|
373
|
+
self.view.window.accessibilityElements = nil;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
[super presentViewController:viewControllerToPresent animated:flag completion:completion];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
|
|
380
|
+
[super dismissViewControllerAnimated:flag
|
|
381
|
+
completion:^{
|
|
382
|
+
if (completion) {
|
|
383
|
+
completion();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Reclaim the window accessibility override once nothing
|
|
387
|
+
// else is presented over us.
|
|
388
|
+
if (self.isPresented && self.presentedViewController == nil) {
|
|
389
|
+
[self setupAccessibilityContainer];
|
|
390
|
+
}
|
|
391
|
+
}];
|
|
272
392
|
}
|
|
273
393
|
|
|
274
394
|
- (void)emitWillDismissEvents {
|
|
@@ -283,6 +403,7 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
283
403
|
|
|
284
404
|
- (void)emitDidDismissEvents {
|
|
285
405
|
if (self.isBeingDismissed) {
|
|
406
|
+
[self restoreWindowAccessibilityElements];
|
|
286
407
|
_isPresented = NO;
|
|
287
408
|
_isWillDismissEmitted = NO;
|
|
288
409
|
|
|
@@ -290,6 +411,7 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
290
411
|
_anchorView = nil;
|
|
291
412
|
|
|
292
413
|
[_parentSheetController.delegate viewControllerDidFocus];
|
|
414
|
+
[_parentSheetController setSheetAccessibilityElementsHidden:NO];
|
|
293
415
|
[_parentSheetController setupAccessibilityContainer];
|
|
294
416
|
_parentSheetController = nil;
|
|
295
417
|
|
|
@@ -300,6 +422,8 @@ static BOOL TrueSheetPositionStateEquals(TrueSheetPositionState a, TrueSheetPosi
|
|
|
300
422
|
|
|
301
423
|
- (void)viewWillDisappear:(BOOL)animated {
|
|
302
424
|
[super viewWillDisappear:animated];
|
|
425
|
+
[self restoreWindowAccessibilityElements];
|
|
426
|
+
[self setSheetAccessibilityElementsHidden:YES];
|
|
303
427
|
|
|
304
428
|
// Dispatch to allow pan gesture to set _isDragging before checking
|
|
305
429
|
// handleTransitionTracker will emit when sheet is transitioning to dismiss
|
package/package.json
CHANGED