Skip to content

Commit 035837f

Browse files
authored
feat(iOS): add unstable_accessibilityContainerViewIsModal prop for FullWindowOverlay (#2854)
## Description The prop defaults to `true` due to backward compatibility reasons. I believe this should be changed with major version change. There is no need to update Android interfaces, because we render plain `View` there in place of `FullWindowOverlay`. The prop is `unstable` since I haven't decided yet on whether I want to expose completely new prop or make `RNSFullWindowOverlayContainer` use value of `RNSFullWindowOverlay.accessibilityViewIsModal`. This would be possible, because it is regular prop on `View` component. See: https://reactnative.dev/docs/view#accessibilityviewismodal-ios Currently I went with new prop and not repurposing `accessibilityViewIsModal` on `RNSFullWindowOverlay` since I'm not that familiar with the accessibility API & want to avoid focus request collisions etc. & in case the original prop becomes utilised in the future. ## Changes Added new prop. ## Test code and steps to reproduce `Test1096` + VoiceOver, when `unstable_accessibilityContainerViewIsModal: false` you should be able to access content under the FWO with voice over. ## Checklist - [ ] Included code example that can be used to test this change - [ ] Updated TS types - [ ] Updated documentation: <!-- For adding new props to native-stack --> - [ ] https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md - [ ] https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md - [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/types.tsx - [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/native-stack/types.tsx - [ ] Ensured that CI passes
1 parent 3febf0c commit 035837f

4 files changed

Lines changed: 53 additions & 12 deletions

File tree

ios/RNSFullWindowOverlay.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace react = facebook::react;
2626
RCTView <RCTInvalidating>
2727
#endif // RCT_NEW_ARCH_ENABLED
2828

29+
@property (nonatomic) BOOL accessibilityContainerViewIsModal;
30+
2931
#ifdef RCT_NEW_ARCH_ENABLED
3032
@property (nonatomic) react::LayoutMetrics oldLayoutMetrics;
3133
@property (nonatomic) react::LayoutMetrics newLayoutMetrics;

ios/RNSFullWindowOverlay.mm

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717

1818
@implementation RNSFullWindowOverlayContainer
1919

20-
- (instancetype)initWithFrame:(CGRect)frame
20+
- (instancetype)initWithFrame:(CGRect)frame accessibilityViewIsModal:(BOOL)accessibilityViewIsModal
2121
{
2222
if (self = [super initWithFrame:frame]) {
23-
self.accessibilityViewIsModal = YES;
23+
self.accessibilityViewIsModal = accessibilityViewIsModal;
2424
}
2525
return self;
2626
}
@@ -92,29 +92,37 @@ - (instancetype)init
9292
if (self = [super init]) {
9393
static const auto defaultProps = std::make_shared<const react::RNSFullWindowOverlayProps>();
9494
_props = defaultProps;
95-
[self _initCommon];
95+
[self initCommonProps];
9696
}
9797
return self;
9898
}
99-
#endif // RCT_NEW_ARCH_ENABLED
100-
99+
#else
101100
- (instancetype)initWithBridge:(RCTBridge *)bridge
102101
{
103102
if (self = [super init]) {
104103
_bridge = bridge;
105-
[self _initCommon];
104+
[self initCommonProps];
106105
}
107106

108107
return self;
109108
}
109+
#endif // RCT_NEW_ARCH_ENABLED
110110

111-
- (void)_initCommon
111+
- (void)initCommonProps
112112
{
113+
// Default value used by container.
114+
_accessibilityContainerViewIsModal = YES;
113115
_reactFrame = CGRectNull;
114116
_container = self.container;
115117
[self show];
116118
}
117119

120+
- (void)setAccessibilityContainerViewIsModal:(BOOL)accessibilityContainerViewIsModal
121+
{
122+
_accessibilityContainerViewIsModal = accessibilityContainerViewIsModal;
123+
self.container.accessibilityViewIsModal = accessibilityContainerViewIsModal;
124+
}
125+
118126
- (void)addSubview:(UIView *)view
119127
{
120128
[_container addSubview:view];
@@ -123,7 +131,8 @@ - (void)addSubview:(UIView *)view
123131
- (RNSFullWindowOverlayContainer *)container
124132
{
125133
if (_container == nil) {
126-
_container = [[RNSFullWindowOverlayContainer alloc] initWithFrame:_reactFrame];
134+
_container = [[RNSFullWindowOverlayContainer alloc] initWithFrame:_reactFrame
135+
accessibilityViewIsModal:_accessibilityContainerViewIsModal];
127136
}
128137

129138
return _container;
@@ -220,6 +229,19 @@ - (void)updateLayoutMetrics:(react::LayoutMetrics const &)layoutMetrics
220229

221230
RNS_IGNORE_SUPER_CALL_END
222231

232+
- (void)updateProps:(const facebook::react::Props::Shared &)props
233+
oldProps:(const facebook::react::Props::Shared &)oldProps
234+
{
235+
const auto &oldComponentProps = *std::static_pointer_cast<const react::RNSFullWindowOverlayProps>(_props);
236+
const auto &newComponentProps = *std::static_pointer_cast<const react::RNSFullWindowOverlayProps>(props);
237+
238+
if (newComponentProps.accessibilityContainerViewIsModal != oldComponentProps.accessibilityContainerViewIsModal) {
239+
[self setAccessibilityContainerViewIsModal:newComponentProps.accessibilityContainerViewIsModal];
240+
}
241+
242+
[super updateProps:props oldProps:oldProps];
243+
}
244+
223245
#else
224246
#pragma mark - Paper specific
225247

@@ -250,6 +272,8 @@ @implementation RNSFullWindowOverlayManager
250272

251273
RCT_EXPORT_MODULE()
252274

275+
RCT_EXPORT_VIEW_PROPERTY(accessibilityContainerViewIsModal, BOOL)
276+
253277
#ifdef RCT_NEW_ARCH_ENABLED
254278
#else
255279
- (UIView *)view

src/components/FullWindowOverlay.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,32 @@ import {
1010

1111
// Native components
1212
import FullWindowOverlayNativeComponent from '../fabric/FullWindowOverlayNativeComponent';
13+
import type { NativeProps } from '../fabric/FullWindowOverlayNativeComponent';
14+
1315
const NativeFullWindowOverlay: React.ComponentType<
1416
PropsWithChildren<{
1517
style: StyleProp<ViewStyle>;
16-
}>
18+
}> &
19+
NativeProps
1720
> = FullWindowOverlayNativeComponent as any;
1821

19-
function FullWindowOverlay(props: { children: ReactNode }) {
22+
type FullWindowOverlayProps = {
23+
children: ReactNode;
24+
unstable_accessibilityContainerViewIsModal?: boolean;
25+
};
26+
27+
function FullWindowOverlay(props: FullWindowOverlayProps) {
2028
const { width, height } = useWindowDimensions();
2129
if (Platform.OS !== 'ios') {
2230
console.warn('Using FullWindowOverlay is only valid on iOS devices.');
2331
return <View {...props} />;
2432
}
2533
return (
2634
<NativeFullWindowOverlay
27-
style={[StyleSheet.absoluteFill, { width, height }]}>
35+
style={[StyleSheet.absoluteFill, { width, height }]}
36+
accessibilityContainerViewIsModal={
37+
props.unstable_accessibilityContainerViewIsModal
38+
}>
2839
{props.children}
2940
</NativeFullWindowOverlay>
3041
);

src/fabric/FullWindowOverlayNativeComponent.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
44
import type { ViewProps } from 'react-native';
5+
import { WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
56

6-
interface NativeProps extends ViewProps {}
7+
// Internal export, not part of stable library API.
8+
export interface NativeProps extends ViewProps {
9+
accessibilityContainerViewIsModal?: WithDefault<boolean, true>;
10+
}
711

812
export default codegenNativeComponent<NativeProps>('RNSFullWindowOverlay', {
913
interfaceOnly: true,

0 commit comments

Comments
 (0)