uilib-native 5.0.0-snapshot.7227 → 5.0.0-snapshot.7233
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/components/HighlighterOverlayView/index.js +1 -1
- package/components/HighlighterOverlayView/index.web.d.ts +1 -1
- package/components/Keyboard/KeyboardTrackingView/KeyboardTrackingView.ios.js +1 -1
- package/components/SafeArea/SafeAreaInsetsManager.d.ts +7 -4
- package/components/SafeArea/SafeAreaInsetsManager.js +10 -13
- package/components/SafeArea/SafeAreaSpacerView.d.ts +2 -2
- package/components/SafeArea/SafeAreaSpacerView.js +11 -8
- package/components/SafeArea/__tests__/SafeAreaInsetsManager.spec.js +271 -0
- package/components/SafeArea/index.d.ts +10 -0
- package/components/SafeArea/index.js +11 -0
- package/components/index.d.ts +1 -1
- package/components/index.js +1 -1
- package/package.json +1 -1
- package/specs/HighlighterViewNativeComponent.ts +78 -0
- package/specs/KeyboardTrackingViewNativeComponent.ts +74 -0
- package/components/HighlighterOverlayView/HighlighterViewNativeComponent.js +0 -2
- package/components/Keyboard/KeyboardTrackingView/KeyboardTrackingViewNativeComponent.js +0 -2
- /package/{components/HighlighterOverlayView → specs}/HighlighterViewNativeComponent.d.ts +0 -0
- /package/{components/Keyboard/KeyboardTrackingView → specs}/KeyboardTrackingViewNativeComponent.d.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { processColor, StyleSheet, Modal } from 'react-native';
|
|
3
3
|
// Import the Codegen specification for New Architecture
|
|
4
|
-
import HighlighterViewNativeComponent from "
|
|
4
|
+
import HighlighterViewNativeComponent from "../../specs/HighlighterViewNativeComponent";
|
|
5
5
|
const DefaultOverlayColor = 'rgba(0, 0, 0, 0.5)';
|
|
6
6
|
const HighlighterOverlayView = props => {
|
|
7
7
|
const {
|
|
@@ -19,7 +19,7 @@ export type HighlighterOverlayViewProps = {
|
|
|
19
19
|
onRequestClose?: () => void;
|
|
20
20
|
highlightFrame?: HighlightFrameType;
|
|
21
21
|
style?: ViewStyle;
|
|
22
|
-
highlightViewTag?: number
|
|
22
|
+
highlightViewTag?: number;
|
|
23
23
|
children?: JSX.Element[] | JSX.Element;
|
|
24
24
|
highlightViewTagParams?: HighlightViewTagParams;
|
|
25
25
|
minimumRectSize?: Pick<HighlightFrameType, 'width' | 'height'>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { PureComponent } from 'react';
|
|
2
2
|
import ReactNative, { NativeModules } from 'react-native';
|
|
3
3
|
// Import the Codegen specification for New Architecture
|
|
4
|
-
import KeyboardTrackingViewNativeComponent from "
|
|
4
|
+
import KeyboardTrackingViewNativeComponent from "../../../specs/KeyboardTrackingViewNativeComponent";
|
|
5
5
|
const KeyboardTrackingViewTempManager = NativeModules.KeyboardTrackingViewTempManager;
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
type SafeAreaInsetsType = {
|
|
1
|
+
export type SafeAreaInsetsType = {
|
|
2
2
|
top: number;
|
|
3
3
|
left: number;
|
|
4
4
|
bottom: number;
|
|
5
5
|
right: number;
|
|
6
6
|
} | null;
|
|
7
|
+
export type SafeAreaChangedDelegateType = {
|
|
8
|
+
onSafeAreaInsetsDidChangeEvent?: (insets: SafeAreaInsetsType) => void;
|
|
9
|
+
};
|
|
7
10
|
declare class SafeAreaInsetsManager {
|
|
8
11
|
_defaultInsets: SafeAreaInsetsType;
|
|
9
12
|
_safeAreaInsets: SafeAreaInsetsType;
|
|
10
|
-
_safeAreaChangedDelegates: Array<
|
|
13
|
+
_safeAreaChangedDelegates: Array<SafeAreaChangedDelegateType>;
|
|
11
14
|
_nativeModule: any;
|
|
12
15
|
constructor();
|
|
13
16
|
setupNativeConnection(): void;
|
|
@@ -16,8 +19,8 @@ declare class SafeAreaInsetsManager {
|
|
|
16
19
|
notifyDelegates(insets: SafeAreaInsetsType): void;
|
|
17
20
|
_updateInsets(): Promise<void>;
|
|
18
21
|
getSafeAreaInsets(): Promise<SafeAreaInsetsType>;
|
|
19
|
-
addSafeAreaChangedDelegate(delegate:
|
|
20
|
-
removeSafeAreaChangedDelegate(delegateToRemove:
|
|
22
|
+
addSafeAreaChangedDelegate(delegate: SafeAreaChangedDelegateType): void;
|
|
23
|
+
removeSafeAreaChangedDelegate(delegateToRemove: SafeAreaChangedDelegateType): void;
|
|
21
24
|
get defaultInsets(): SafeAreaInsetsType;
|
|
22
25
|
refreshSafeAreaInsets(): Promise<void>;
|
|
23
26
|
}
|
|
@@ -2,7 +2,7 @@ import _isEqual from "lodash/isEqual";
|
|
|
2
2
|
import _remove from "lodash/remove";
|
|
3
3
|
import _forEach from "lodash/forEach";
|
|
4
4
|
/* eslint no-underscore-dangle: 0 */
|
|
5
|
-
import { NativeModules, DeviceEventEmitter
|
|
5
|
+
import { NativeModules, DeviceEventEmitter } from 'react-native';
|
|
6
6
|
let SafeAreaInsetsCache = null;
|
|
7
7
|
class SafeAreaInsetsManager {
|
|
8
8
|
_defaultInsets = {
|
|
@@ -11,12 +11,7 @@ class SafeAreaInsetsManager {
|
|
|
11
11
|
bottom: 34,
|
|
12
12
|
right: 0
|
|
13
13
|
}; // Common iPhone safe area values
|
|
14
|
-
|
|
15
|
-
top: 47,
|
|
16
|
-
left: 0,
|
|
17
|
-
bottom: 34,
|
|
18
|
-
right: 0
|
|
19
|
-
};
|
|
14
|
+
|
|
20
15
|
_safeAreaChangedDelegates = [];
|
|
21
16
|
_nativeModule = null;
|
|
22
17
|
constructor() {
|
|
@@ -45,11 +40,8 @@ class SafeAreaInsetsManager {
|
|
|
45
40
|
}
|
|
46
41
|
}
|
|
47
42
|
setupEventListener() {
|
|
48
|
-
if (Platform.OS !== 'ios') {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
43
|
try {
|
|
52
|
-
// Use DeviceEventEmitter instead of NativeEventEmitter to avoid getConstants
|
|
44
|
+
// Use DeviceEventEmitter instead of NativeEventEmitter to avoid getConstants
|
|
53
45
|
DeviceEventEmitter.addListener('SafeAreaInsetsDidChangeEvent', data => {
|
|
54
46
|
if (data) {
|
|
55
47
|
SafeAreaInsetsCache = data;
|
|
@@ -86,8 +78,13 @@ class SafeAreaInsetsManager {
|
|
|
86
78
|
async _updateInsets() {
|
|
87
79
|
if (this._nativeModule && SafeAreaInsetsCache === null) {
|
|
88
80
|
try {
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
const insets = await this._nativeModule.getSafeAreaInsets();
|
|
82
|
+
if (insets) {
|
|
83
|
+
SafeAreaInsetsCache = insets;
|
|
84
|
+
this._safeAreaInsets = SafeAreaInsetsCache;
|
|
85
|
+
} else {
|
|
86
|
+
this._safeAreaInsets = this._defaultInsets;
|
|
87
|
+
}
|
|
91
88
|
} catch (error) {
|
|
92
89
|
console.warn('SafeAreaInsetsManager: Failed to get native insets:', error);
|
|
93
90
|
this._safeAreaInsets = this._defaultInsets;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ViewStyle } from 'react-native';
|
|
2
|
+
import { ViewStyle, StyleProp } from 'react-native';
|
|
3
3
|
export type SafeAreaSpacerViewProps = {
|
|
4
|
-
style?: ViewStyle
|
|
4
|
+
style?: StyleProp<ViewStyle>;
|
|
5
5
|
};
|
|
6
6
|
declare const SafeAreaSpacerView: {
|
|
7
7
|
({ style }: SafeAreaSpacerViewProps): React.JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useCallback, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useCallback, useEffect, useMemo } from 'react';
|
|
2
2
|
import { View, Dimensions } from 'react-native';
|
|
3
3
|
import SafeAreaInsetsManager from "./SafeAreaInsetsManager";
|
|
4
4
|
const SafeAreaSpacerView = ({
|
|
@@ -10,6 +10,7 @@ const SafeAreaSpacerView = ({
|
|
|
10
10
|
bottom: 0,
|
|
11
11
|
right: 0
|
|
12
12
|
});
|
|
13
|
+
const [componentHeight, setComponentHeight] = useState(0);
|
|
13
14
|
const [spacerHeight, setSpacerHeight] = useState(0);
|
|
14
15
|
useEffect(() => {
|
|
15
16
|
const getSafeAreaInsets = async () => {
|
|
@@ -43,22 +44,24 @@ const SafeAreaSpacerView = ({
|
|
|
43
44
|
const {
|
|
44
45
|
y
|
|
45
46
|
} = event.nativeEvent.layout;
|
|
47
|
+
setComponentHeight(y);
|
|
48
|
+
}, []);
|
|
49
|
+
useEffect(() => {
|
|
46
50
|
const screenHeight = Dimensions.get('window').height;
|
|
47
51
|
let height = 0;
|
|
48
52
|
// Check if positioned within safe area bounds
|
|
49
|
-
if (
|
|
53
|
+
if (componentHeight < safeAreaInsets.top) {
|
|
50
54
|
height = safeAreaInsets.top;
|
|
51
|
-
} else if (
|
|
55
|
+
} else if (componentHeight > screenHeight - safeAreaInsets.bottom) {
|
|
52
56
|
height = safeAreaInsets.bottom;
|
|
53
57
|
}
|
|
54
58
|
if (height !== spacerHeight) {
|
|
55
59
|
setSpacerHeight(height);
|
|
56
60
|
}
|
|
57
|
-
}, [safeAreaInsets, spacerHeight]);
|
|
58
|
-
const spacerStyle = {
|
|
59
|
-
height: spacerHeight
|
|
60
|
-
|
|
61
|
-
};
|
|
61
|
+
}, [componentHeight, safeAreaInsets, spacerHeight]);
|
|
62
|
+
const spacerStyle = useMemo(() => [{
|
|
63
|
+
height: spacerHeight
|
|
64
|
+
}, style], [spacerHeight, style]);
|
|
62
65
|
return <View style={spacerStyle} onLayout={handleLayout} />;
|
|
63
66
|
};
|
|
64
67
|
SafeAreaSpacerView.displayName = 'SafeAreaSpacerView';
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import {NativeModules, DeviceEventEmitter} from 'react-native';
|
|
2
|
+
|
|
3
|
+
describe('SafeAreaInsetsManager', () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
// Reset mocks
|
|
6
|
+
jest.clearAllMocks();
|
|
7
|
+
|
|
8
|
+
// Reset the SafeAreaInsetsCache by creating a fresh instance
|
|
9
|
+
jest.resetModules();
|
|
10
|
+
|
|
11
|
+
// Spy on console methods to verify logging
|
|
12
|
+
jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
13
|
+
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
// Restore console methods
|
|
18
|
+
jest.restoreAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('getSafeAreaInsets', () => {
|
|
22
|
+
it('should return default insets when native module is not available', async () => {
|
|
23
|
+
// Arrange
|
|
24
|
+
NativeModules.SafeAreaManager = null;
|
|
25
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
26
|
+
|
|
27
|
+
// Act
|
|
28
|
+
const result = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
29
|
+
|
|
30
|
+
// Assert
|
|
31
|
+
expect(result).toEqual({top: 47, left: 0, bottom: 34, right: 0});
|
|
32
|
+
expect(console.log).toHaveBeenCalledWith('SafeAreaInsetsManager: Native SafeAreaManager not available, using defaults');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should return insets from native module when available', async () => {
|
|
36
|
+
// Arrange
|
|
37
|
+
const mockInsets = {top: 50, left: 10, bottom: 30, right: 10};
|
|
38
|
+
NativeModules.SafeAreaManager = {
|
|
39
|
+
getSafeAreaInsets: jest.fn().mockResolvedValue(mockInsets)
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
43
|
+
|
|
44
|
+
// Act
|
|
45
|
+
const result = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
46
|
+
|
|
47
|
+
// Assert
|
|
48
|
+
expect(result).toEqual(mockInsets);
|
|
49
|
+
expect(NativeModules.SafeAreaManager.getSafeAreaInsets).toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it.skip('should return cached insets on subsequent calls', async () => {
|
|
53
|
+
// Arrange
|
|
54
|
+
const mockInsets = {top: 44, left: 0, bottom: 34, right: 0};
|
|
55
|
+
NativeModules.SafeAreaManager = {
|
|
56
|
+
getSafeAreaInsets: jest.fn().mockResolvedValue(mockInsets)
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
60
|
+
|
|
61
|
+
// Act
|
|
62
|
+
const result1 = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
63
|
+
const result2 = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
64
|
+
|
|
65
|
+
// Assert
|
|
66
|
+
expect(result1).toEqual(mockInsets);
|
|
67
|
+
expect(result2).toEqual(mockInsets);
|
|
68
|
+
expect(NativeModules.SafeAreaManager.getSafeAreaInsets).toHaveBeenCalledTimes(1); // Should only call native once due to caching
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should handle native module errors gracefully', async () => {
|
|
72
|
+
// Arrange
|
|
73
|
+
const mockError = new Error('Native module error');
|
|
74
|
+
NativeModules.SafeAreaManager = {
|
|
75
|
+
getSafeAreaInsets: jest.fn().mockRejectedValue(mockError)
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
79
|
+
|
|
80
|
+
// Act
|
|
81
|
+
const result = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
82
|
+
|
|
83
|
+
// Assert
|
|
84
|
+
expect(result).toEqual({top: 47, left: 0, bottom: 34, right: 0}); // Should fallback to defaults
|
|
85
|
+
expect(console.warn).toHaveBeenCalledWith('SafeAreaInsetsManager: Failed to get initial insets:', mockError);
|
|
86
|
+
expect(console.warn).toHaveBeenCalledWith('SafeAreaInsetsManager: Failed to get native insets:', mockError);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should handle native module setup errors gracefully', async () => {
|
|
90
|
+
// Arrange
|
|
91
|
+
Object.defineProperty(NativeModules, 'SafeAreaManager', {
|
|
92
|
+
get: () => {
|
|
93
|
+
throw new Error('Setup error');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
98
|
+
|
|
99
|
+
// Act
|
|
100
|
+
const result = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
101
|
+
|
|
102
|
+
// Assert
|
|
103
|
+
expect(result).toEqual({top: 47, left: 0, bottom: 34, right: 0}); // Should fallback to defaults
|
|
104
|
+
expect(console.warn).toHaveBeenCalledWith('SafeAreaInsetsManager: Failed to connect to native module:', expect.any(Error));
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should update insets when they change during the test', async () => {
|
|
108
|
+
// Arrange
|
|
109
|
+
const initialInsets = {top: 44, left: 0, bottom: 34, right: 0};
|
|
110
|
+
const updatedInsets = {top: 50, left: 0, bottom: 40, right: 0};
|
|
111
|
+
|
|
112
|
+
NativeModules.SafeAreaManager = {
|
|
113
|
+
// TODO: this will need to be changed when the we get caching to work in tests ("should return cached insets on subsequent calls")
|
|
114
|
+
// getSafeAreaInsets: jest.fn().mockResolvedValueOnce(initialInsets).mockResolvedValueOnce(updatedInsets)
|
|
115
|
+
getSafeAreaInsets: jest
|
|
116
|
+
.fn()
|
|
117
|
+
.mockResolvedValueOnce(initialInsets)
|
|
118
|
+
.mockResolvedValueOnce(initialInsets)
|
|
119
|
+
.mockResolvedValueOnce(updatedInsets)
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
123
|
+
|
|
124
|
+
// Act & Assert - Initial insets
|
|
125
|
+
const result1 = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
126
|
+
expect(result1).toEqual(initialInsets);
|
|
127
|
+
|
|
128
|
+
// Force refresh of insets
|
|
129
|
+
await SafeAreaInsetsManager.refreshSafeAreaInsets();
|
|
130
|
+
|
|
131
|
+
// Simulate insets change event from native side
|
|
132
|
+
DeviceEventEmitter.emit('SafeAreaInsetsDidChangeEvent', updatedInsets);
|
|
133
|
+
|
|
134
|
+
// Get insets again - should reflect the change
|
|
135
|
+
const result2 = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
136
|
+
expect(result2).toEqual(updatedInsets);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should notify delegates when insets change during the test', async () => {
|
|
140
|
+
// Arrange
|
|
141
|
+
const initialInsets = {top: 44, left: 0, bottom: 34, right: 0};
|
|
142
|
+
const updatedInsets = {top: 50, left: 0, bottom: 40, right: 0};
|
|
143
|
+
|
|
144
|
+
NativeModules.SafeAreaManager = {
|
|
145
|
+
getSafeAreaInsets: jest.fn().mockResolvedValue(initialInsets)
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
149
|
+
|
|
150
|
+
// Add a mock delegate
|
|
151
|
+
const mockDelegate = {
|
|
152
|
+
onSafeAreaInsetsDidChangeEvent: jest.fn()
|
|
153
|
+
};
|
|
154
|
+
SafeAreaInsetsManager.addSafeAreaChangedDelegate(mockDelegate);
|
|
155
|
+
|
|
156
|
+
// Act - Get initial insets
|
|
157
|
+
await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
158
|
+
|
|
159
|
+
// Simulate insets change event from native side
|
|
160
|
+
DeviceEventEmitter.emit('SafeAreaInsetsDidChangeEvent', updatedInsets);
|
|
161
|
+
|
|
162
|
+
// Assert - Delegate should be notified
|
|
163
|
+
expect(mockDelegate.onSafeAreaInsetsDidChangeEvent).toHaveBeenCalledWith(updatedInsets);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should handle refreshSafeAreaInsets correctly', async () => {
|
|
167
|
+
// Arrange
|
|
168
|
+
const initialInsets = {top: 44, left: 0, bottom: 34, right: 0};
|
|
169
|
+
const refreshedInsets = {top: 48, left: 0, bottom: 36, right: 0};
|
|
170
|
+
|
|
171
|
+
NativeModules.SafeAreaManager = {
|
|
172
|
+
// TODO: this will need to be changed when the we get caching to work in tests ("should return cached insets on subsequent calls")
|
|
173
|
+
// getSafeAreaInsets: jest.fn().mockResolvedValueOnce(initialInsets).mockResolvedValueOnce(updatedInsets)
|
|
174
|
+
getSafeAreaInsets: jest
|
|
175
|
+
.fn()
|
|
176
|
+
.mockResolvedValueOnce(initialInsets)
|
|
177
|
+
.mockResolvedValueOnce(initialInsets)
|
|
178
|
+
.mockResolvedValueOnce(refreshedInsets)
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
182
|
+
|
|
183
|
+
// Act
|
|
184
|
+
const result1 = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
185
|
+
expect(result1).toEqual(initialInsets);
|
|
186
|
+
|
|
187
|
+
// Refresh insets
|
|
188
|
+
await SafeAreaInsetsManager.refreshSafeAreaInsets();
|
|
189
|
+
|
|
190
|
+
const result2 = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
191
|
+
|
|
192
|
+
// Assert
|
|
193
|
+
expect(result2).toEqual(refreshedInsets);
|
|
194
|
+
// TODO: this will need to be changed when the we get caching to work in tests ("should return cached insets on subsequent calls")
|
|
195
|
+
expect(NativeModules.SafeAreaManager.getSafeAreaInsets).toHaveBeenCalledTimes(3);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should not notify delegates when insets remain the same after refresh', async () => {
|
|
199
|
+
// Arrange
|
|
200
|
+
const sameInsets = {top: 44, left: 0, bottom: 34, right: 0};
|
|
201
|
+
|
|
202
|
+
NativeModules.SafeAreaManager = {
|
|
203
|
+
getSafeAreaInsets: jest.fn().mockResolvedValue(sameInsets)
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
207
|
+
|
|
208
|
+
// Add a mock delegate
|
|
209
|
+
const mockDelegate = {
|
|
210
|
+
onSafeAreaInsetsDidChangeEvent: jest.fn()
|
|
211
|
+
};
|
|
212
|
+
SafeAreaInsetsManager.addSafeAreaChangedDelegate(mockDelegate);
|
|
213
|
+
|
|
214
|
+
// Act
|
|
215
|
+
await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
216
|
+
await SafeAreaInsetsManager.refreshSafeAreaInsets();
|
|
217
|
+
|
|
218
|
+
// TODO: this will need to be changed when the we get caching to work in tests ("should return cached insets on subsequent calls")
|
|
219
|
+
expect(NativeModules.SafeAreaManager.getSafeAreaInsets).toHaveBeenCalledTimes(3);
|
|
220
|
+
|
|
221
|
+
// Assert - Delegate should not be notified since insets didn't change
|
|
222
|
+
expect(mockDelegate.onSafeAreaInsetsDidChangeEvent).not.toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should return default insets when native getSafeAreaInsets returns null', async () => {
|
|
226
|
+
// Arrange
|
|
227
|
+
NativeModules.SafeAreaManager = {
|
|
228
|
+
getSafeAreaInsets: jest.fn().mockResolvedValue(null)
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
232
|
+
|
|
233
|
+
// Act
|
|
234
|
+
const result = await SafeAreaInsetsManager.getSafeAreaInsets();
|
|
235
|
+
|
|
236
|
+
// Assert
|
|
237
|
+
expect(result).toEqual({top: 47, left: 0, bottom: 34, right: 0});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should properly manage delegate lifecycle', async () => {
|
|
241
|
+
// Arrange
|
|
242
|
+
NativeModules.SafeAreaManager = {
|
|
243
|
+
getSafeAreaInsets: jest.fn().mockResolvedValue({top: 44, left: 0, bottom: 34, right: 0})
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const SafeAreaInsetsManager = require('../SafeAreaInsetsManager').default;
|
|
247
|
+
|
|
248
|
+
const mockDelegate1 = {
|
|
249
|
+
onSafeAreaInsetsDidChangeEvent: jest.fn()
|
|
250
|
+
};
|
|
251
|
+
const mockDelegate2 = {
|
|
252
|
+
onSafeAreaInsetsDidChangeEvent: jest.fn()
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Act
|
|
256
|
+
SafeAreaInsetsManager.addSafeAreaChangedDelegate(mockDelegate1);
|
|
257
|
+
SafeAreaInsetsManager.addSafeAreaChangedDelegate(mockDelegate2);
|
|
258
|
+
|
|
259
|
+
// Remove one delegate
|
|
260
|
+
SafeAreaInsetsManager.removeSafeAreaChangedDelegate(mockDelegate1);
|
|
261
|
+
|
|
262
|
+
// Trigger notification
|
|
263
|
+
const newInsets = {top: 50, left: 0, bottom: 40, right: 0};
|
|
264
|
+
SafeAreaInsetsManager.notifyDelegates(newInsets);
|
|
265
|
+
|
|
266
|
+
// Assert
|
|
267
|
+
expect(mockDelegate1.onSafeAreaInsetsDidChangeEvent).not.toHaveBeenCalled();
|
|
268
|
+
expect(mockDelegate2.onSafeAreaInsetsDidChangeEvent).toHaveBeenCalledWith(newInsets);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewStyle, StyleProp } from 'react-native';
|
|
3
|
+
export type SafeAreaSpacerViewProps = {
|
|
4
|
+
style?: StyleProp<ViewStyle>;
|
|
5
|
+
};
|
|
6
|
+
declare const SafeAreaSpacerView: {
|
|
7
|
+
({ style }: SafeAreaSpacerViewProps): React.JSX.Element;
|
|
8
|
+
displayName: string;
|
|
9
|
+
};
|
|
10
|
+
export default SafeAreaSpacerView;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Platform } from 'react-native';
|
|
3
|
+
import SafeAreaSpacerViewIos from "./SafeAreaSpacerView";
|
|
4
|
+
const isIOS = Platform.OS === 'ios';
|
|
5
|
+
const SafeAreaSpacerView = ({
|
|
6
|
+
style
|
|
7
|
+
}) => {
|
|
8
|
+
return isIOS ? <SafeAreaSpacerViewIos style={style} /> : <View style={style} />;
|
|
9
|
+
};
|
|
10
|
+
SafeAreaSpacerView.displayName = 'SafeAreaSpacerView';
|
|
11
|
+
export default SafeAreaSpacerView;
|
package/components/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import DynamicFonts, { FontExtension } from './DynamicFonts';
|
|
2
2
|
import HighlighterOverlayView from './HighlighterOverlayView';
|
|
3
|
-
import SafeAreaSpacerView from './SafeArea
|
|
3
|
+
import SafeAreaSpacerView from './SafeArea';
|
|
4
4
|
import SafeAreaInsetsManager from './SafeArea/SafeAreaInsetsManager';
|
|
5
5
|
import Keyboard, { KeyboardTrackingViewProps, KeyboardAccessoryViewProps } from './Keyboard';
|
|
6
6
|
export { DynamicFonts, FontExtension, HighlighterOverlayView, SafeAreaSpacerView, SafeAreaInsetsManager, Keyboard, KeyboardTrackingViewProps, KeyboardAccessoryViewProps };
|
package/components/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import DynamicFonts, { FontExtension } from "./DynamicFonts";
|
|
2
2
|
import HighlighterOverlayView from "./HighlighterOverlayView";
|
|
3
|
-
import SafeAreaSpacerView from "./SafeArea
|
|
3
|
+
import SafeAreaSpacerView from "./SafeArea";
|
|
4
4
|
import SafeAreaInsetsManager from "./SafeArea/SafeAreaInsetsManager";
|
|
5
5
|
import Keyboard, { KeyboardTrackingViewProps, KeyboardAccessoryViewProps } from "./Keyboard";
|
|
6
6
|
export { DynamicFonts, FontExtension, HighlighterOverlayView, SafeAreaSpacerView, SafeAreaInsetsManager, Keyboard, KeyboardTrackingViewProps, KeyboardAccessoryViewProps };
|
package/package.json
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type {ViewProps} from 'react-native';
|
|
2
|
+
// import {requireNativeComponent, type ViewProps} from 'react-native';
|
|
3
|
+
import type {Float, Int32, WithDefault} from 'react-native/Libraries/Types/CodegenTypes';
|
|
4
|
+
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
5
|
+
|
|
6
|
+
export interface HighlightFrame {
|
|
7
|
+
x: Float;
|
|
8
|
+
y: Float;
|
|
9
|
+
width: Float;
|
|
10
|
+
height: Float;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface MinimumRectSize {
|
|
14
|
+
width: Float;
|
|
15
|
+
height: Float;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface HighlightViewTagParams {
|
|
19
|
+
paddingLeft?: WithDefault<Float, 0>;
|
|
20
|
+
paddingTop?: WithDefault<Float, 0>;
|
|
21
|
+
paddingRight?: WithDefault<Float, 0>;
|
|
22
|
+
paddingBottom?: WithDefault<Float, 0>;
|
|
23
|
+
offsetX?: WithDefault<Float, 0>;
|
|
24
|
+
offsetY?: WithDefault<Float, 0>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface NativeProps extends ViewProps {
|
|
28
|
+
/**
|
|
29
|
+
* The frame to highlight with x, y, width, height coordinates
|
|
30
|
+
*/
|
|
31
|
+
highlightFrame?: HighlightFrame;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The overlay color (processed color int for Android)
|
|
35
|
+
*/
|
|
36
|
+
overlayColor?: WithDefault<Int32, 0>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The border radius for the highlighted area
|
|
40
|
+
*/
|
|
41
|
+
borderRadius?: WithDefault<Float, 0>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The stroke color (processed color int for Android)
|
|
45
|
+
*/
|
|
46
|
+
strokeColor?: WithDefault<Int32, 0>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The stroke width
|
|
50
|
+
*/
|
|
51
|
+
strokeWidth?: WithDefault<Float, 0>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The React tag of the view to highlight
|
|
55
|
+
*/
|
|
56
|
+
highlightViewTag?: Int32;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Parameters for view-based highlighting including padding and offset
|
|
60
|
+
*/
|
|
61
|
+
highlightViewTagParams?: HighlightViewTagParams;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Minimum rectangle size for the highlight area
|
|
65
|
+
*/
|
|
66
|
+
minimumRectSize?: MinimumRectSize;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Inner padding for the highlight area
|
|
70
|
+
*/
|
|
71
|
+
innerPadding?: WithDefault<Float, 0>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default codegenNativeComponent<NativeProps>('HighlighterView');
|
|
75
|
+
|
|
76
|
+
// const HighlighterViewNativeComponent = requireNativeComponent<NativeProps>('HighlighterView');
|
|
77
|
+
|
|
78
|
+
// export default HighlighterViewNativeComponent;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type {ViewProps} from 'react-native';
|
|
2
|
+
// import {requireNativeComponent, type ViewProps} from 'react-native';
|
|
3
|
+
import type {Int32, WithDefault} from 'react-native/Libraries/Types/CodegenTypes';
|
|
4
|
+
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
5
|
+
|
|
6
|
+
export interface NativeProps extends ViewProps {
|
|
7
|
+
/**
|
|
8
|
+
* Enables tracking of the keyboard when it's dismissed interactively (false by default).
|
|
9
|
+
*/
|
|
10
|
+
trackInteractive?: WithDefault<boolean, false>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* iOS only.
|
|
14
|
+
* Show the keyboard on a negative scroll
|
|
15
|
+
*/
|
|
16
|
+
revealKeyboardInteractive?: WithDefault<boolean, false>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* iOS only.
|
|
20
|
+
* Set to false to turn off inset management and manage it yourself
|
|
21
|
+
*/
|
|
22
|
+
manageScrollView?: WithDefault<boolean, true>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* iOS only.
|
|
26
|
+
* Set to true manageScrollView is set to true and still does not work
|
|
27
|
+
*/
|
|
28
|
+
requiresSameParentToManageScrollView?: WithDefault<boolean, false>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* iOS only.
|
|
32
|
+
* Allow hitting sub-views that are placed beyond the view bounds
|
|
33
|
+
*/
|
|
34
|
+
allowHitsOutsideBounds?: WithDefault<boolean, false>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Should the scrollView scroll to the focused input
|
|
38
|
+
*/
|
|
39
|
+
scrollToFocusedInput?: WithDefault<boolean, false>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* iOS only.
|
|
43
|
+
* The scrolling behavior (NONE | SCROLL_TO_BOTTOM_INVERTED_ONLY | FIXED_OFFSET)
|
|
44
|
+
*/
|
|
45
|
+
scrollBehavior?: WithDefault<Int32, 0>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* iOS only.
|
|
49
|
+
* Add a SafeArea view beneath the KeyboardAccessoryView
|
|
50
|
+
*/
|
|
51
|
+
addBottomView?: WithDefault<boolean, false>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* iOS only.
|
|
55
|
+
* The bottom view's color
|
|
56
|
+
*/
|
|
57
|
+
bottomViewColor?: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Allow control safe area
|
|
61
|
+
*/
|
|
62
|
+
useSafeArea?: WithDefault<boolean, false>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Whether or not to include bottom tab bar inset
|
|
66
|
+
*/
|
|
67
|
+
usesBottomTabs?: WithDefault<boolean, false>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default codegenNativeComponent<NativeProps>('KeyboardTrackingViewTemp');
|
|
71
|
+
|
|
72
|
+
// const KeyboardTrackingViewNativeComponent = requireNativeComponent<NativeProps>('KeyboardTrackingViewTemp');
|
|
73
|
+
|
|
74
|
+
// export default KeyboardTrackingViewNativeComponent;
|
|
File without changes
|
/package/{components/Keyboard/KeyboardTrackingView → specs}/KeyboardTrackingViewNativeComponent.d.ts
RENAMED
|
File without changes
|