@office-iss/react-native-win32 0.0.0-canary.275 → 0.0.0-canary.277
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/.flowconfig +2 -1
- package/CHANGELOG.json +31 -1
- package/CHANGELOG.md +20 -4
- package/Libraries/Animated/useAnimatedProps.js +2 -14
- package/Libraries/Components/Keyboard/KeyboardAvoidingView.js +2 -0
- package/Libraries/Components/View/ViewPropTypes.js +0 -3
- package/Libraries/Components/View/ViewPropTypes.win32.js +0 -3
- package/Libraries/Core/ExceptionsManager.js +6 -0
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/Image/Image.android.js +0 -2
- package/Libraries/Image/ImageViewNativeComponent.js +3 -1
- package/Libraries/LayoutAnimation/LayoutAnimation.js +2 -2
- package/Libraries/NewAppScreen/components/HermesBadge.js +1 -1
- package/Libraries/StyleSheet/processBackgroundImage.js +87 -110
- package/Libraries/TurboModule/TurboModuleRegistry.js +5 -5
- package/Libraries/Utilities/Appearance.js +3 -1
- package/jest/setup.js +5 -1
- package/overrides.json +3 -3
- package/package.json +11 -11
- package/src/private/featureflags/ReactNativeFeatureFlags.js +15 -15
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +2 -2
- package/src/private/setup/setUpDOM.js +14 -6
- package/src/private/setup/setUpMutationObserver.js +5 -0
- package/src/private/webapis/dom/nodes/ReactNativeElement.js +48 -6
- package/src/private/webapis/dom/nodes/ReadOnlyNode.js +3 -1
- package/src/private/webapis/intersectionobserver/IntersectionObserver.js +96 -11
- package/src/private/webapis/intersectionobserver/IntersectionObserverEntry.js +26 -0
- package/src/private/webapis/intersectionobserver/IntersectionObserverManager.js +1 -0
- package/src/private/webapis/intersectionobserver/specs/NativeIntersectionObserver.js +1 -0
- package/src/private/webapis/intersectionobserver/specs/__mocks__/NativeIntersectionObserver.js +9 -0
package/.flowconfig
CHANGED
package/CHANGELOG.json
CHANGED
|
@@ -2,7 +2,37 @@
|
|
|
2
2
|
"name": "@office-iss/react-native-win32",
|
|
3
3
|
"entries": [
|
|
4
4
|
{
|
|
5
|
-
"date": "
|
|
5
|
+
"date": "Fri, 20 Dec 2024 06:21:41 GMT",
|
|
6
|
+
"version": "0.0.0-canary.277",
|
|
7
|
+
"tag": "@office-iss/react-native-win32_v0.0.0-canary.277",
|
|
8
|
+
"comments": {
|
|
9
|
+
"prerelease": [
|
|
10
|
+
{
|
|
11
|
+
"author": "email not defined",
|
|
12
|
+
"package": "@office-iss/react-native-win32",
|
|
13
|
+
"commit": "9372e929083b78c3d8c05ee713a57537f864cdd9",
|
|
14
|
+
"comment": "integrate 0.78.0-nightly-20241201-91e217ff5"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"date": "Wed, 18 Dec 2024 06:22:23 GMT",
|
|
21
|
+
"version": "0.0.0-canary.276",
|
|
22
|
+
"tag": "@office-iss/react-native-win32_v0.0.0-canary.276",
|
|
23
|
+
"comments": {
|
|
24
|
+
"prerelease": [
|
|
25
|
+
{
|
|
26
|
+
"author": "email not defined",
|
|
27
|
+
"package": "@office-iss/react-native-win32",
|
|
28
|
+
"commit": "d669d78450c97decf9f9f5acc09e526ddf8dd911",
|
|
29
|
+
"comment": "integrate RN-Nightly 0.77.0-nightly-20241125-4cffff35e"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"date": "Sat, 14 Dec 2024 06:29:12 GMT",
|
|
6
36
|
"version": "0.0.0-canary.275",
|
|
7
37
|
"tag": "@office-iss/react-native-win32_v0.0.0-canary.275",
|
|
8
38
|
"comments": {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
# Change Log - @office-iss/react-native-win32
|
|
2
2
|
|
|
3
|
-
<!-- This log was last generated on
|
|
3
|
+
<!-- This log was last generated on Fri, 20 Dec 2024 06:21:41 GMT and should not be manually modified. -->
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
-
## 0.0.0-canary.
|
|
7
|
+
## 0.0.0-canary.277
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Fri, 20 Dec 2024 06:21:41 GMT
|
|
10
10
|
|
|
11
11
|
### Changes
|
|
12
12
|
|
|
13
|
-
- integrate
|
|
13
|
+
- integrate 0.78.0-nightly-20241201-91e217ff5 (email not defined)
|
|
14
14
|
|
|
15
|
+
## 0.0.0-canary.276
|
|
16
|
+
|
|
17
|
+
Wed, 18 Dec 2024 06:22:23 GMT
|
|
18
|
+
|
|
19
|
+
### Changes
|
|
20
|
+
|
|
21
|
+
- integrate RN-Nightly 0.77.0-nightly-20241125-4cffff35e (email not defined)
|
|
22
|
+
|
|
23
|
+
## 0.0.0-canary.275
|
|
24
|
+
|
|
25
|
+
Sat, 14 Dec 2024 06:29:12 GMT
|
|
26
|
+
|
|
27
|
+
### Changes
|
|
28
|
+
|
|
29
|
+
- integrate RN Nightly 0.77.0-nightly-20241118-3986eefed (tatianakapos@microsoft.com)
|
|
30
|
+
|
|
15
31
|
## 0.0.0-canary.274
|
|
16
32
|
|
|
17
33
|
Fri, 06 Dec 2024 06:22:27 GMT
|
|
@@ -73,8 +73,6 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
|
|
|
73
73
|
|
|
74
74
|
const useNativePropsInFabric =
|
|
75
75
|
ReactNativeFeatureFlags.shouldUseSetNativePropsInFabric();
|
|
76
|
-
const useSetNativePropsInNativeAnimationsInFabric =
|
|
77
|
-
ReactNativeFeatureFlags.shouldUseSetNativePropsInNativeAnimationsInFabric();
|
|
78
76
|
|
|
79
77
|
const useAnimatedPropsLifecycle =
|
|
80
78
|
ReactNativeFeatureFlags.useInsertionEffectsForAnimations()
|
|
@@ -119,12 +117,7 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
|
|
|
119
117
|
if (isFabricNode) {
|
|
120
118
|
// Call `scheduleUpdate` to synchronise Fiber and Shadow tree.
|
|
121
119
|
// Must not be called in Paper.
|
|
122
|
-
|
|
123
|
-
// $FlowFixMe[incompatible-use]
|
|
124
|
-
instance.setNativeProps(node.__getAnimatedValue());
|
|
125
|
-
} else {
|
|
126
|
-
scheduleUpdate();
|
|
127
|
-
}
|
|
120
|
+
scheduleUpdate();
|
|
128
121
|
}
|
|
129
122
|
return;
|
|
130
123
|
}
|
|
@@ -201,12 +194,7 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
|
|
|
201
194
|
}
|
|
202
195
|
};
|
|
203
196
|
},
|
|
204
|
-
[
|
|
205
|
-
node,
|
|
206
|
-
useNativePropsInFabric,
|
|
207
|
-
useSetNativePropsInNativeAnimationsInFabric,
|
|
208
|
-
props,
|
|
209
|
-
],
|
|
197
|
+
[node, useNativePropsInFabric, props],
|
|
210
198
|
);
|
|
211
199
|
const callbackRef = useRefEffect<TInstance>(refEffect);
|
|
212
200
|
|
|
@@ -116,6 +116,8 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
|
|
116
116
|
};
|
|
117
117
|
|
|
118
118
|
_onLayout = async (event: ViewLayoutEvent) => {
|
|
119
|
+
event.persist();
|
|
120
|
+
|
|
119
121
|
const oldFrame = this._frame;
|
|
120
122
|
this._frame = event.nativeEvent.layout;
|
|
121
123
|
if (!this._initialFrameHeight) {
|
|
@@ -567,9 +567,6 @@ export type ViewProps = $ReadOnly<{|
|
|
|
567
567
|
* optimization. Set this property to `false` to disable this optimization and
|
|
568
568
|
* ensure that this `View` exists in the native view hierarchy.
|
|
569
569
|
*
|
|
570
|
-
* @platform android
|
|
571
|
-
* In Fabric, this prop is used in ios as well.
|
|
572
|
-
*
|
|
573
570
|
* See https://reactnative.dev/docs/view#collapsable
|
|
574
571
|
*/
|
|
575
572
|
collapsable?: ?boolean,
|
|
@@ -628,9 +628,6 @@ export type ViewProps = $ReadOnly<{|
|
|
|
628
628
|
* optimization. Set this property to `false` to disable this optimization and
|
|
629
629
|
* ensure that this `View` exists in the native view hierarchy.
|
|
630
630
|
*
|
|
631
|
-
* @platform android
|
|
632
|
-
* In Fabric, this prop is used in ios as well.
|
|
633
|
-
*
|
|
634
631
|
* See https://reactnative.dev/docs/view#collapsable
|
|
635
632
|
*/
|
|
636
633
|
collapsable?: ?boolean,
|
|
@@ -121,6 +121,12 @@ function reportException(
|
|
|
121
121
|
const NativeExceptionsManager =
|
|
122
122
|
require('./NativeExceptionsManager').default;
|
|
123
123
|
if (NativeExceptionsManager) {
|
|
124
|
+
if (isFatal) {
|
|
125
|
+
if (global.RN$hasHandledFatalException?.()) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
global.RN$notifyOfFatalException?.();
|
|
129
|
+
}
|
|
124
130
|
NativeExceptionsManager.reportException(data);
|
|
125
131
|
}
|
|
126
132
|
}
|
|
@@ -133,7 +133,6 @@ let BaseImage: AbstractImageAndroid = React.forwardRef(
|
|
|
133
133
|
width: undefined,
|
|
134
134
|
height: undefined,
|
|
135
135
|
};
|
|
136
|
-
const defaultSource = resolveAssetSource(props.defaultSource);
|
|
137
136
|
const loadingIndicatorSource = resolveAssetSource(
|
|
138
137
|
props.loadingIndicatorSource,
|
|
139
138
|
);
|
|
@@ -179,7 +178,6 @@ let BaseImage: AbstractImageAndroid = React.forwardRef(
|
|
|
179
178
|
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
|
180
179
|
* when making Flow check .android.js files. */
|
|
181
180
|
headers: (source?.[0]?.headers || source?.headers: ?{[string]: string}),
|
|
182
|
-
defaultSrc: defaultSource ? defaultSource.uri : null,
|
|
183
181
|
loadingIndicatorSrc: loadingIndicatorSource
|
|
184
182
|
? loadingIndicatorSource.uri
|
|
185
183
|
: null,
|
|
@@ -82,6 +82,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
82
82
|
},
|
|
83
83
|
validAttributes: {
|
|
84
84
|
blurRadius: true,
|
|
85
|
+
defaultSource: {
|
|
86
|
+
process: require('./resolveAssetSource'),
|
|
87
|
+
},
|
|
85
88
|
internal_analyticTag: true,
|
|
86
89
|
resizeMethod: true,
|
|
87
90
|
resizeMode: true,
|
|
@@ -100,7 +103,6 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
100
103
|
borderRadius: true,
|
|
101
104
|
headers: true,
|
|
102
105
|
shouldNotifyLoadEvents: true,
|
|
103
|
-
defaultSrc: true,
|
|
104
106
|
overlayColor: {
|
|
105
107
|
process: require('../StyleSheet/processColor').default,
|
|
106
108
|
},
|
|
@@ -121,7 +121,7 @@ const Presets = {
|
|
|
121
121
|
'opacity',
|
|
122
122
|
): LayoutAnimationConfig),
|
|
123
123
|
linear: (create(500, 'linear', 'opacity'): LayoutAnimationConfig),
|
|
124
|
-
spring: {
|
|
124
|
+
spring: ({
|
|
125
125
|
duration: 700,
|
|
126
126
|
create: {
|
|
127
127
|
type: 'linear',
|
|
@@ -135,7 +135,7 @@ const Presets = {
|
|
|
135
135
|
type: 'linear',
|
|
136
136
|
property: 'opacity',
|
|
137
137
|
},
|
|
138
|
-
},
|
|
138
|
+
}: LayoutAnimationConfig),
|
|
139
139
|
};
|
|
140
140
|
|
|
141
141
|
/**
|
|
@@ -14,25 +14,28 @@ import type {ProcessedColorValue} from './processColor';
|
|
|
14
14
|
import type {GradientValue} from './StyleSheetTypes';
|
|
15
15
|
|
|
16
16
|
const processColor = require('./processColor').default;
|
|
17
|
-
const
|
|
18
|
-
/^to\s+(?:top|bottom|left|right)(?:\s+(?:top|bottom|left|right))
|
|
17
|
+
const DIRECTION_KEYWORD_REGEX =
|
|
18
|
+
/^to\s+(?:top|bottom|left|right)(?:\s+(?:top|bottom|left|right))?/i;
|
|
19
19
|
const ANGLE_UNIT_REGEX = /^([+-]?\d*\.?\d+)(deg|grad|rad|turn)$/i;
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
21
|
+
type LinearGradientDirection =
|
|
22
|
+
| {type: 'angle', value: number}
|
|
23
|
+
| {type: 'keyword', value: string};
|
|
25
24
|
|
|
26
25
|
type ParsedGradientValue = {
|
|
27
26
|
type: 'linearGradient',
|
|
28
|
-
|
|
29
|
-
end: {x: number, y: number},
|
|
27
|
+
direction: LinearGradientDirection,
|
|
30
28
|
colorStops: $ReadOnlyArray<{
|
|
31
29
|
color: ProcessedColorValue,
|
|
32
30
|
position: number,
|
|
33
31
|
}>,
|
|
34
32
|
};
|
|
35
33
|
|
|
34
|
+
const DEFAULT_DIRECTION: LinearGradientDirection = {
|
|
35
|
+
type: 'angle',
|
|
36
|
+
value: 180,
|
|
37
|
+
};
|
|
38
|
+
|
|
36
39
|
export default function processBackgroundImage(
|
|
37
40
|
backgroundImage: ?($ReadOnlyArray<GradientValue> | string),
|
|
38
41
|
): $ReadOnlyArray<ParsedGradientValue> {
|
|
@@ -76,37 +79,43 @@ export default function processBackgroundImage(
|
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
let
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
|
|
82
|
+
let direction: LinearGradientDirection = DEFAULT_DIRECTION;
|
|
83
|
+
const bgDirection =
|
|
84
|
+
bgImage.direction != null ? bgImage.direction.toLowerCase() : null;
|
|
85
|
+
|
|
86
|
+
if (bgDirection != null) {
|
|
87
|
+
if (ANGLE_UNIT_REGEX.test(bgDirection)) {
|
|
88
|
+
const parsedAngle = getAngleInDegrees(bgDirection);
|
|
89
|
+
if (parsedAngle != null) {
|
|
90
|
+
direction = {
|
|
91
|
+
type: 'angle',
|
|
92
|
+
value: parsedAngle,
|
|
93
|
+
};
|
|
94
|
+
} else {
|
|
95
|
+
// If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
} else if (DIRECTION_KEYWORD_REGEX.test(bgDirection)) {
|
|
99
|
+
const parsedDirection = getDirectionForKeyword(bgDirection);
|
|
100
|
+
if (parsedDirection != null) {
|
|
101
|
+
direction = parsedDirection;
|
|
102
|
+
} else {
|
|
103
|
+
// If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
// If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
|
|
108
|
+
return [];
|
|
97
109
|
}
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
const fixedColorStops = getFixedColorStops(processedColorStops);
|
|
101
113
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
colorStops: fixedColorStops,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
114
|
+
result = result.concat({
|
|
115
|
+
type: 'linearGradient',
|
|
116
|
+
direction,
|
|
117
|
+
colorStops: fixedColorStops,
|
|
118
|
+
});
|
|
110
119
|
}
|
|
111
120
|
}
|
|
112
121
|
|
|
@@ -118,30 +127,39 @@ function parseCSSLinearGradient(
|
|
|
118
127
|
): $ReadOnlyArray<ParsedGradientValue> {
|
|
119
128
|
const gradients = [];
|
|
120
129
|
let match;
|
|
130
|
+
|
|
131
|
+
// matches one or more linear-gradient functions in CSS
|
|
121
132
|
const linearGradientRegex = /linear-gradient\s*\(((?:\([^)]*\)|[^())])*)\)/gi;
|
|
122
133
|
|
|
123
134
|
while ((match = linearGradientRegex.exec(cssString))) {
|
|
124
135
|
const gradientContent = match[1];
|
|
125
136
|
const parts = gradientContent.split(',');
|
|
126
|
-
let
|
|
137
|
+
let direction: LinearGradientDirection = DEFAULT_DIRECTION;
|
|
127
138
|
const trimmedDirection = parts[0].trim().toLowerCase();
|
|
139
|
+
|
|
140
|
+
// matches individual color stops in a gradient function
|
|
141
|
+
// supports various color formats: named colors, hex colors, rgb(a), and hsl(a)
|
|
142
|
+
// e.g. "red 20%", "blue 50%", "rgba(0, 0, 0, 0.5) 30% 50%"
|
|
143
|
+
// TODO: does not support color hint syntax yet. It is WIP.
|
|
128
144
|
const colorStopRegex =
|
|
129
145
|
/\s*((?:(?:rgba?|hsla?)\s*\([^)]+\))|#[0-9a-fA-F]+|[a-zA-Z]+)(?:\s+(-?[0-9.]+%?)(?:\s+(-?[0-9.]+%?))?)?\s*/gi;
|
|
130
146
|
|
|
131
147
|
if (ANGLE_UNIT_REGEX.test(trimmedDirection)) {
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
134
|
-
|
|
148
|
+
const parsedAngle = getAngleInDegrees(trimmedDirection);
|
|
149
|
+
if (parsedAngle != null) {
|
|
150
|
+
direction = {
|
|
151
|
+
type: 'angle',
|
|
152
|
+
value: parsedAngle,
|
|
153
|
+
};
|
|
135
154
|
parts.shift();
|
|
136
155
|
} else {
|
|
137
156
|
// If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
|
|
138
157
|
return [];
|
|
139
158
|
}
|
|
140
|
-
} else if (
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
points = parsedPoints;
|
|
159
|
+
} else if (DIRECTION_KEYWORD_REGEX.test(trimmedDirection)) {
|
|
160
|
+
const parsedDirection = getDirectionForKeyword(trimmedDirection);
|
|
161
|
+
if (parsedDirection != null) {
|
|
162
|
+
direction = parsedDirection;
|
|
145
163
|
parts.shift();
|
|
146
164
|
} else {
|
|
147
165
|
// If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
|
|
@@ -198,8 +216,7 @@ function parseCSSLinearGradient(
|
|
|
198
216
|
|
|
199
217
|
gradients.push({
|
|
200
218
|
type: 'linearGradient',
|
|
201
|
-
|
|
202
|
-
end: points.end,
|
|
219
|
+
direction,
|
|
203
220
|
colorStops: fixedColorStops,
|
|
204
221
|
});
|
|
205
222
|
}
|
|
@@ -207,83 +224,43 @@ function parseCSSLinearGradient(
|
|
|
207
224
|
return gradients;
|
|
208
225
|
}
|
|
209
226
|
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
227
|
+
function getDirectionForKeyword(direction?: string): ?LinearGradientDirection {
|
|
228
|
+
if (direction == null) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
214
231
|
// Remove extra whitespace
|
|
215
|
-
const
|
|
232
|
+
const normalized = direction.replace(/\s+/g, ' ').toLowerCase();
|
|
216
233
|
|
|
217
|
-
switch (
|
|
234
|
+
switch (normalized) {
|
|
235
|
+
case 'to top':
|
|
236
|
+
return {type: 'angle', value: 0};
|
|
218
237
|
case 'to right':
|
|
219
|
-
return {
|
|
220
|
-
start: {x: 0, y: 0.5},
|
|
221
|
-
end: {x: 1, y: 0.5},
|
|
222
|
-
};
|
|
223
|
-
case 'to left':
|
|
224
|
-
return {
|
|
225
|
-
start: {x: 1, y: 0.5},
|
|
226
|
-
end: {x: 0, y: 0.5},
|
|
227
|
-
};
|
|
238
|
+
return {type: 'angle', value: 90};
|
|
228
239
|
case 'to bottom':
|
|
229
|
-
return
|
|
230
|
-
case 'to
|
|
231
|
-
return {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
};
|
|
240
|
+
return {type: 'angle', value: 180};
|
|
241
|
+
case 'to left':
|
|
242
|
+
return {type: 'angle', value: 270};
|
|
243
|
+
case 'to top right':
|
|
244
|
+
case 'to right top':
|
|
245
|
+
return {type: 'keyword', value: 'to top right'};
|
|
235
246
|
case 'to bottom right':
|
|
236
247
|
case 'to right bottom':
|
|
237
|
-
return {
|
|
238
|
-
start: {x: 0, y: 0},
|
|
239
|
-
end: {x: 1, y: 1},
|
|
240
|
-
};
|
|
248
|
+
return {type: 'keyword', value: 'to bottom right'};
|
|
241
249
|
case 'to top left':
|
|
242
250
|
case 'to left top':
|
|
243
|
-
return {
|
|
244
|
-
start: {x: 1, y: 1},
|
|
245
|
-
end: {x: 0, y: 0},
|
|
246
|
-
};
|
|
251
|
+
return {type: 'keyword', value: 'to top left'};
|
|
247
252
|
case 'to bottom left':
|
|
248
253
|
case 'to left bottom':
|
|
249
|
-
return {
|
|
250
|
-
start: {x: 1, y: 0},
|
|
251
|
-
end: {x: 0, y: 1},
|
|
252
|
-
};
|
|
253
|
-
case 'to top right':
|
|
254
|
-
case 'to right top':
|
|
255
|
-
return {
|
|
256
|
-
start: {x: 0, y: 1},
|
|
257
|
-
end: {x: 1, y: 0},
|
|
258
|
-
};
|
|
254
|
+
return {type: 'keyword', value: 'to bottom left'};
|
|
259
255
|
default:
|
|
260
256
|
return null;
|
|
261
257
|
}
|
|
262
258
|
}
|
|
263
259
|
|
|
264
|
-
function
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
} {
|
|
268
|
-
// Normalize angle to be between 0 and 2π
|
|
269
|
-
let angleRadiansNormalized = angleRadians % (2 * Math.PI);
|
|
270
|
-
if (angleRadiansNormalized < 0) {
|
|
271
|
-
angleRadiansNormalized += 2 * Math.PI;
|
|
260
|
+
function getAngleInDegrees(angle?: string): ?number {
|
|
261
|
+
if (angle == null) {
|
|
262
|
+
return null;
|
|
272
263
|
}
|
|
273
|
-
|
|
274
|
-
const endX = 0.5 + 0.5 * Math.sin(angleRadiansNormalized);
|
|
275
|
-
const endY = 0.5 - 0.5 * Math.cos(angleRadiansNormalized);
|
|
276
|
-
|
|
277
|
-
const startX = 1 - endX;
|
|
278
|
-
const startY = 1 - endY;
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
start: {x: startX, y: startY},
|
|
282
|
-
end: {x: endX, y: endY},
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function parseAngle(angle: string): ?number {
|
|
287
264
|
const match = angle.match(ANGLE_UNIT_REGEX);
|
|
288
265
|
if (!match) {
|
|
289
266
|
return null;
|
|
@@ -294,13 +271,13 @@ function parseAngle(angle: string): ?number {
|
|
|
294
271
|
const numericValue = parseFloat(value);
|
|
295
272
|
switch (unit) {
|
|
296
273
|
case 'deg':
|
|
297
|
-
return
|
|
274
|
+
return numericValue;
|
|
298
275
|
case 'grad':
|
|
299
|
-
return
|
|
276
|
+
return numericValue * 0.9; // 1 grad = 0.9 degrees
|
|
300
277
|
case 'rad':
|
|
301
|
-
return numericValue;
|
|
278
|
+
return (numericValue * 180) / Math.PI;
|
|
302
279
|
case 'turn':
|
|
303
|
-
return numericValue *
|
|
280
|
+
return numericValue * 360; // 1 turn = 360 degrees
|
|
304
281
|
default:
|
|
305
282
|
return null;
|
|
306
283
|
}
|
|
@@ -16,9 +16,6 @@ const NativeModules = require('../BatchedBridge/NativeModules');
|
|
|
16
16
|
|
|
17
17
|
const turboModuleProxy = global.__turboModuleProxy;
|
|
18
18
|
|
|
19
|
-
const useLegacyNativeModuleInterop =
|
|
20
|
-
global.RN$Bridgeless !== true || global.RN$TurboInterop === true;
|
|
21
|
-
|
|
22
19
|
function requireModule<T: TurboModule>(name: string): ?T {
|
|
23
20
|
if (turboModuleProxy != null) {
|
|
24
21
|
const module: ?T = turboModuleProxy(name);
|
|
@@ -27,8 +24,11 @@ function requireModule<T: TurboModule>(name: string): ?T {
|
|
|
27
24
|
}
|
|
28
25
|
}
|
|
29
26
|
|
|
30
|
-
if (
|
|
31
|
-
|
|
27
|
+
if (
|
|
28
|
+
global.RN$Bridgeless !== true ||
|
|
29
|
+
global.RN$TurboInterop === true ||
|
|
30
|
+
global.RN$UnifiedNativeModuleProxy === true
|
|
31
|
+
) {
|
|
32
32
|
const legacyModule: ?T = NativeModules[name];
|
|
33
33
|
if (legacyModule != null) {
|
|
34
34
|
return legacyModule;
|
|
@@ -105,7 +105,9 @@ export function setColorScheme(colorScheme: ?ColorSchemeName): void {
|
|
|
105
105
|
const {NativeAppearance} = state;
|
|
106
106
|
if (NativeAppearance != null) {
|
|
107
107
|
NativeAppearance.setColorScheme(colorScheme ?? 'unspecified');
|
|
108
|
-
state.appearance = {
|
|
108
|
+
state.appearance = {
|
|
109
|
+
colorScheme: toColorScheme(NativeAppearance.getColorScheme()),
|
|
110
|
+
};
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
|
package/jest/setup.js
CHANGED
package/overrides.json
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
"**/__snapshots__/**",
|
|
8
8
|
"src-win/rntypes/**"
|
|
9
9
|
],
|
|
10
|
-
"baseVersion": "0.
|
|
10
|
+
"baseVersion": "0.78.0-nightly-20241201-91e217ff5",
|
|
11
11
|
"overrides": [
|
|
12
12
|
{
|
|
13
13
|
"type": "derived",
|
|
14
14
|
"file": ".flowconfig",
|
|
15
15
|
"baseFile": ".flowconfig",
|
|
16
|
-
"baseHash": "
|
|
16
|
+
"baseHash": "38943f268bd48c91a2ace6ad2a9302a3bb346dbd"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"type": "derived",
|
|
@@ -197,7 +197,7 @@
|
|
|
197
197
|
"type": "patch",
|
|
198
198
|
"file": "src-win/Libraries/Components/View/ViewPropTypes.win32.js",
|
|
199
199
|
"baseFile": "packages/react-native/Libraries/Components/View/ViewPropTypes.js",
|
|
200
|
-
"baseHash": "
|
|
200
|
+
"baseHash": "994aead3d5ab49e6bd34a497094a4bc131a8bdb1",
|
|
201
201
|
"issue": 6240
|
|
202
202
|
},
|
|
203
203
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@office-iss/react-native-win32",
|
|
3
|
-
"version": "0.0.0-canary.
|
|
3
|
+
"version": "0.0.0-canary.277",
|
|
4
4
|
"description": "Implementation of react native on top of Office's Win32 platform.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,19 +30,19 @@
|
|
|
30
30
|
"@react-native-community/cli-platform-android": "15.0.0-alpha.2",
|
|
31
31
|
"@react-native-community/cli-platform-ios": "15.0.0-alpha.2",
|
|
32
32
|
"@react-native/assets": "1.0.0",
|
|
33
|
-
"@react-native/assets-registry": "0.
|
|
34
|
-
"@react-native/codegen": "0.
|
|
35
|
-
"@react-native/community-cli-plugin": "0.
|
|
36
|
-
"@react-native/gradle-plugin": "0.
|
|
37
|
-
"@react-native/js-polyfills": "0.
|
|
38
|
-
"@react-native/normalize-colors": "0.
|
|
39
|
-
"@react-native/virtualized-lists": "0.
|
|
33
|
+
"@react-native/assets-registry": "0.78.0-nightly-20241201-91e217ff5",
|
|
34
|
+
"@react-native/codegen": "0.78.0-nightly-20241201-91e217ff5",
|
|
35
|
+
"@react-native/community-cli-plugin": "0.78.0-nightly-20241201-91e217ff5",
|
|
36
|
+
"@react-native/gradle-plugin": "0.78.0-nightly-20241201-91e217ff5",
|
|
37
|
+
"@react-native/js-polyfills": "0.78.0-nightly-20241201-91e217ff5",
|
|
38
|
+
"@react-native/normalize-colors": "0.78.0-nightly-20241201-91e217ff5",
|
|
39
|
+
"@react-native/virtualized-lists": "0.78.0-nightly-20241201-91e217ff5",
|
|
40
40
|
"abort-controller": "^3.0.0",
|
|
41
41
|
"anser": "^1.4.9",
|
|
42
42
|
"ansi-regex": "^5.0.0",
|
|
43
43
|
"art": "^0.10.0",
|
|
44
44
|
"babel-jest": "^29.7.0",
|
|
45
|
-
"babel-plugin-syntax-hermes-parser": "0.
|
|
45
|
+
"babel-plugin-syntax-hermes-parser": "0.25.1",
|
|
46
46
|
"base64-js": "^1.5.1",
|
|
47
47
|
"chalk": "^4.0.0",
|
|
48
48
|
"commander": "^12.0.0",
|
|
@@ -90,14 +90,14 @@
|
|
|
90
90
|
"just-scripts": "^1.3.3",
|
|
91
91
|
"prettier": "2.8.8",
|
|
92
92
|
"react": "18.3.1",
|
|
93
|
-
"react-native": "0.
|
|
93
|
+
"react-native": "0.78.0-nightly-20241201-91e217ff5",
|
|
94
94
|
"react-native-platform-override": "^1.9.49",
|
|
95
95
|
"typescript": "5.0.4"
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
98
98
|
"@types/react": "^18.2.6",
|
|
99
99
|
"react": "^18.2.0",
|
|
100
|
-
"react-native": "0.
|
|
100
|
+
"react-native": "0.78.0-nightly-20241201-91e217ff5"
|
|
101
101
|
},
|
|
102
102
|
"beachball": {
|
|
103
103
|
"defaultNpmTag": "canary",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<38ad29621eeb29a9f82735dc187c13d4>>
|
|
8
8
|
* @flow strict
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -31,17 +31,17 @@ export type ReactNativeFeatureFlagsJsOnly = {
|
|
|
31
31
|
animatedShouldDebounceQueueFlush: Getter<boolean>,
|
|
32
32
|
animatedShouldUseSingleOp: Getter<boolean>,
|
|
33
33
|
disableInteractionManager: Getter<boolean>,
|
|
34
|
+
disableInteractionManagerInBatchinator: Getter<boolean>,
|
|
34
35
|
enableAccessToHostTreeInFabric: Getter<boolean>,
|
|
35
36
|
enableAnimatedAllowlist: Getter<boolean>,
|
|
36
37
|
enableAnimatedClearImmediateFix: Getter<boolean>,
|
|
37
38
|
enableAnimatedPropsMemo: Getter<boolean>,
|
|
38
|
-
|
|
39
|
+
fixVirtualizeListCollapseWindowSize: Getter<boolean>,
|
|
39
40
|
isLayoutAnimationEnabled: Getter<boolean>,
|
|
40
41
|
shouldSkipStateUpdatesForLoopingAnimations: Getter<boolean>,
|
|
41
42
|
shouldUseAnimatedObjectForTransform: Getter<boolean>,
|
|
42
43
|
shouldUseRemoveClippedSubviewsAsDefaultOnIOS: Getter<boolean>,
|
|
43
44
|
shouldUseSetNativePropsInFabric: Getter<boolean>,
|
|
44
|
-
shouldUseSetNativePropsInNativeAnimationsInFabric: Getter<boolean>,
|
|
45
45
|
useInsertionEffectsForAnimations: Getter<boolean>,
|
|
46
46
|
useRefsForTextInputState: Getter<boolean>,
|
|
47
47
|
};
|
|
@@ -68,6 +68,7 @@ export type ReactNativeFeatureFlags = {
|
|
|
68
68
|
enableFixForViewCommandRace: Getter<boolean>,
|
|
69
69
|
enableGranularShadowTreeStateReconciliation: Getter<boolean>,
|
|
70
70
|
enableIOSViewClipToPaddingBox: Getter<boolean>,
|
|
71
|
+
enableImagePrefetchingAndroid: Getter<boolean>,
|
|
71
72
|
enableLayoutAnimationsOnAndroid: Getter<boolean>,
|
|
72
73
|
enableLayoutAnimationsOnIOS: Getter<boolean>,
|
|
73
74
|
enableLongTaskAPI: Getter<boolean>,
|
|
@@ -86,7 +87,6 @@ export type ReactNativeFeatureFlags = {
|
|
|
86
87
|
initEagerTurboModulesOnNativeModulesQueueAndroid: Getter<boolean>,
|
|
87
88
|
lazyAnimationCallbacks: Getter<boolean>,
|
|
88
89
|
loadVectorDrawablesOnImages: Getter<boolean>,
|
|
89
|
-
setAndroidLayoutDirection: Getter<boolean>,
|
|
90
90
|
traceTurboModulePromiseRejectionsOnAndroid: Getter<boolean>,
|
|
91
91
|
useAlwaysAvailableJSErrorHandling: Getter<boolean>,
|
|
92
92
|
useFabricInterop: Getter<boolean>,
|
|
@@ -119,6 +119,11 @@ export const animatedShouldUseSingleOp: Getter<boolean> = createJavaScriptFlagGe
|
|
|
119
119
|
*/
|
|
120
120
|
export const disableInteractionManager: Getter<boolean> = createJavaScriptFlagGetter('disableInteractionManager', false);
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Skips InteractionManager in `Batchinator` and invokes callbacks synchronously.
|
|
124
|
+
*/
|
|
125
|
+
export const disableInteractionManagerInBatchinator: Getter<boolean> = createJavaScriptFlagGetter('disableInteractionManagerInBatchinator', false);
|
|
126
|
+
|
|
122
127
|
/**
|
|
123
128
|
* Enables access to the host tree in Fabric using DOM-compatible APIs.
|
|
124
129
|
*/
|
|
@@ -140,9 +145,9 @@ export const enableAnimatedClearImmediateFix: Getter<boolean> = createJavaScript
|
|
|
140
145
|
export const enableAnimatedPropsMemo: Getter<boolean> = createJavaScriptFlagGetter('enableAnimatedPropsMemo', true);
|
|
141
146
|
|
|
142
147
|
/**
|
|
143
|
-
*
|
|
148
|
+
* Fixing an edge case where the current window size is not properly calculated with fast scrolling. Window size collapsed to 1 element even if windowSize more than the current amount of elements
|
|
144
149
|
*/
|
|
145
|
-
export const
|
|
150
|
+
export const fixVirtualizeListCollapseWindowSize: Getter<boolean> = createJavaScriptFlagGetter('fixVirtualizeListCollapseWindowSize', false);
|
|
146
151
|
|
|
147
152
|
/**
|
|
148
153
|
* Function used to enable / disabled Layout Animations in React Native.
|
|
@@ -169,11 +174,6 @@ export const shouldUseRemoveClippedSubviewsAsDefaultOnIOS: Getter<boolean> = cre
|
|
|
169
174
|
*/
|
|
170
175
|
export const shouldUseSetNativePropsInFabric: Getter<boolean> = createJavaScriptFlagGetter('shouldUseSetNativePropsInFabric', true);
|
|
171
176
|
|
|
172
|
-
/**
|
|
173
|
-
* Enables use of setNativeProps in Native driven animations in Fabric.
|
|
174
|
-
*/
|
|
175
|
-
export const shouldUseSetNativePropsInNativeAnimationsInFabric: Getter<boolean> = createJavaScriptFlagGetter('shouldUseSetNativePropsInNativeAnimationsInFabric', false);
|
|
176
|
-
|
|
177
177
|
/**
|
|
178
178
|
* Changes construction of the animation graph to `useInsertionEffect` instead of `useLayoutEffect`.
|
|
179
179
|
*/
|
|
@@ -256,6 +256,10 @@ export const enableGranularShadowTreeStateReconciliation: Getter<boolean> = crea
|
|
|
256
256
|
* iOS Views will clip to their padding box vs border box
|
|
257
257
|
*/
|
|
258
258
|
export const enableIOSViewClipToPaddingBox: Getter<boolean> = createNativeFlagGetter('enableIOSViewClipToPaddingBox', false);
|
|
259
|
+
/**
|
|
260
|
+
* When enabled, Andoid will build and initiate image prefetch requests on ImageShadowNode::layout
|
|
261
|
+
*/
|
|
262
|
+
export const enableImagePrefetchingAndroid: Getter<boolean> = createNativeFlagGetter('enableImagePrefetchingAndroid', false);
|
|
259
263
|
/**
|
|
260
264
|
* When enabled, LayoutAnimations API will animate state changes on Android.
|
|
261
265
|
*/
|
|
@@ -328,10 +332,6 @@ export const lazyAnimationCallbacks: Getter<boolean> = createNativeFlagGetter('l
|
|
|
328
332
|
* Adds support for loading vector drawable assets in the Image component (only on Android)
|
|
329
333
|
*/
|
|
330
334
|
export const loadVectorDrawablesOnImages: Getter<boolean> = createNativeFlagGetter('loadVectorDrawablesOnImages', false);
|
|
331
|
-
/**
|
|
332
|
-
* Propagate layout direction to Android views.
|
|
333
|
-
*/
|
|
334
|
-
export const setAndroidLayoutDirection: Getter<boolean> = createNativeFlagGetter('setAndroidLayoutDirection', true);
|
|
335
335
|
/**
|
|
336
336
|
* Enables storing js caller stack when creating promise in native module. This is useful in case of Promise rejection and tracing the cause.
|
|
337
337
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @generated SignedSource<<
|
|
7
|
+
* @generated SignedSource<<17c0e677f7b308795e836c558b15d1d1>>
|
|
8
8
|
* @flow strict
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -41,6 +41,7 @@ export interface Spec extends TurboModule {
|
|
|
41
41
|
+enableFixForViewCommandRace?: () => boolean;
|
|
42
42
|
+enableGranularShadowTreeStateReconciliation?: () => boolean;
|
|
43
43
|
+enableIOSViewClipToPaddingBox?: () => boolean;
|
|
44
|
+
+enableImagePrefetchingAndroid?: () => boolean;
|
|
44
45
|
+enableLayoutAnimationsOnAndroid?: () => boolean;
|
|
45
46
|
+enableLayoutAnimationsOnIOS?: () => boolean;
|
|
46
47
|
+enableLongTaskAPI?: () => boolean;
|
|
@@ -59,7 +60,6 @@ export interface Spec extends TurboModule {
|
|
|
59
60
|
+initEagerTurboModulesOnNativeModulesQueueAndroid?: () => boolean;
|
|
60
61
|
+lazyAnimationCallbacks?: () => boolean;
|
|
61
62
|
+loadVectorDrawablesOnImages?: () => boolean;
|
|
62
|
-
+setAndroidLayoutDirection?: () => boolean;
|
|
63
63
|
+traceTurboModulePromiseRejectionsOnAndroid?: () => boolean;
|
|
64
64
|
+useAlwaysAvailableJSErrorHandling?: () => boolean;
|
|
65
65
|
+useFabricInterop?: () => boolean;
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
* @format
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import
|
|
12
|
-
import DOMRectReadOnly from '../webapis/dom/geometry/DOMRectReadOnly';
|
|
11
|
+
import {polyfillGlobal} from '../../../Libraries/Utilities/PolyfillFunctions';
|
|
13
12
|
|
|
14
13
|
let initialized = false;
|
|
15
14
|
|
|
@@ -20,9 +19,18 @@ export default function setUpDOM() {
|
|
|
20
19
|
|
|
21
20
|
initialized = true;
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
polyfillGlobal(
|
|
23
|
+
'DOMRect',
|
|
24
|
+
() => require('../webapis/dom/geometry/DOMRect').default,
|
|
25
|
+
);
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
polyfillGlobal(
|
|
28
|
+
'DOMRectReadOnly',
|
|
29
|
+
() => require('../webapis/dom/geometry/DOMRectReadOnly').default,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
polyfillGlobal(
|
|
33
|
+
'NodeList',
|
|
34
|
+
() => require('../webapis/dom/oldstylecollections/NodeList').default,
|
|
35
|
+
);
|
|
28
36
|
}
|
|
@@ -23,4 +23,9 @@ export default function setUpMutationObserver() {
|
|
|
23
23
|
'MutationObserver',
|
|
24
24
|
() => require('../webapis/mutationobserver/MutationObserver').default,
|
|
25
25
|
);
|
|
26
|
+
|
|
27
|
+
polyfillGlobal(
|
|
28
|
+
'MutationRecord',
|
|
29
|
+
() => require('../webapis/mutationobserver/MutationRecord').default,
|
|
30
|
+
);
|
|
26
31
|
}
|
|
@@ -25,7 +25,7 @@ import {getFabricUIManager} from '../../../../../Libraries/ReactNative/FabricUIM
|
|
|
25
25
|
import {create as createAttributePayload} from '../../../../../Libraries/ReactNative/ReactFabricPublicInstance/ReactNativeAttributePayload';
|
|
26
26
|
import warnForStyleProps from '../../../../../Libraries/ReactNative/ReactFabricPublicInstance/warnForStyleProps';
|
|
27
27
|
import ReadOnlyElement, {getBoundingClientRect} from './ReadOnlyElement';
|
|
28
|
-
import ReadOnlyNode from './ReadOnlyNode';
|
|
28
|
+
import ReadOnlyNode, {setInstanceHandle} from './ReadOnlyNode';
|
|
29
29
|
import {
|
|
30
30
|
getPublicInstanceFromInternalInstanceHandle,
|
|
31
31
|
getShadowNode,
|
|
@@ -35,7 +35,26 @@ import nullthrows from 'nullthrows';
|
|
|
35
35
|
|
|
36
36
|
const noop = () => {};
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
// Ideally, this class would be exported as-is, but this implementation is
|
|
39
|
+
// significantly slower than the existing `ReactFabricHostComponent`.
|
|
40
|
+
// This is a very hot code path (this class is instantiated once per rendered
|
|
41
|
+
// host component in the tree) and we can't regress performance here.
|
|
42
|
+
//
|
|
43
|
+
// This implementation is slower because this is a subclass and we have to call
|
|
44
|
+
// super(), which is a very slow operation the way that Babel transforms it at
|
|
45
|
+
// the moment.
|
|
46
|
+
//
|
|
47
|
+
// The optimization we're doing is using an old-style function constructor,
|
|
48
|
+
// where we're not required to use `super()`, and we make that constructor
|
|
49
|
+
// extend this class so it inherits all the methods and it sets the class
|
|
50
|
+
// hierarchy correctly.
|
|
51
|
+
//
|
|
52
|
+
// An alternative implementation was to implement the constructor as a function
|
|
53
|
+
// returning a manually constructed instance using `Object.create()` but that
|
|
54
|
+
// was slower than this method because the engine has to create an object than
|
|
55
|
+
// we then discard to create a new one.
|
|
56
|
+
|
|
57
|
+
class ReactNativeElementMethods
|
|
39
58
|
extends ReadOnlyElement
|
|
40
59
|
implements INativeMethods
|
|
41
60
|
{
|
|
@@ -43,8 +62,10 @@ export default class ReactNativeElement
|
|
|
43
62
|
__nativeTag: number;
|
|
44
63
|
__internalInstanceHandle: InternalInstanceHandle;
|
|
45
64
|
|
|
46
|
-
|
|
65
|
+
__viewConfig: ViewConfig;
|
|
47
66
|
|
|
67
|
+
// This constructor isn't really used. See the `ReactNativeElement` function
|
|
68
|
+
// below.
|
|
48
69
|
constructor(
|
|
49
70
|
tag: number,
|
|
50
71
|
viewConfig: ViewConfig,
|
|
@@ -54,7 +75,7 @@ export default class ReactNativeElement
|
|
|
54
75
|
|
|
55
76
|
this.__nativeTag = tag;
|
|
56
77
|
this.__internalInstanceHandle = internalInstanceHandle;
|
|
57
|
-
this
|
|
78
|
+
this.__viewConfig = viewConfig;
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
get offsetHeight(): number {
|
|
@@ -171,12 +192,12 @@ export default class ReactNativeElement
|
|
|
171
192
|
|
|
172
193
|
setNativeProps(nativeProps: {...}): void {
|
|
173
194
|
if (__DEV__) {
|
|
174
|
-
warnForStyleProps(nativeProps, this
|
|
195
|
+
warnForStyleProps(nativeProps, this.__viewConfig.validAttributes);
|
|
175
196
|
}
|
|
176
197
|
|
|
177
198
|
const updatePayload = createAttributePayload(
|
|
178
199
|
nativeProps,
|
|
179
|
-
this
|
|
200
|
+
this.__viewConfig.validAttributes,
|
|
180
201
|
);
|
|
181
202
|
|
|
182
203
|
const node = getShadowNode(this);
|
|
@@ -186,3 +207,24 @@ export default class ReactNativeElement
|
|
|
186
207
|
}
|
|
187
208
|
}
|
|
188
209
|
}
|
|
210
|
+
|
|
211
|
+
// Alternative constructor just implemented to provide a better performance than
|
|
212
|
+
// calling super() in the original class.
|
|
213
|
+
function ReactNativeElement(
|
|
214
|
+
this: ReactNativeElementMethods,
|
|
215
|
+
tag: number,
|
|
216
|
+
viewConfig: ViewConfig,
|
|
217
|
+
internalInstanceHandle: InternalInstanceHandle,
|
|
218
|
+
) {
|
|
219
|
+
this.__nativeTag = tag;
|
|
220
|
+
this.__internalInstanceHandle = internalInstanceHandle;
|
|
221
|
+
this.__viewConfig = viewConfig;
|
|
222
|
+
setInstanceHandle(this, internalInstanceHandle);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
ReactNativeElement.prototype = Object.create(
|
|
226
|
+
ReactNativeElementMethods.prototype,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
// $FlowExpectedError[prop-missing]
|
|
230
|
+
export default ReactNativeElement as typeof ReactNativeElementMethods;
|
|
@@ -26,6 +26,8 @@ let ReadOnlyElementClass: Class<ReadOnlyElement>;
|
|
|
26
26
|
|
|
27
27
|
export default class ReadOnlyNode {
|
|
28
28
|
constructor(internalInstanceHandle: InternalInstanceHandle) {
|
|
29
|
+
// This constructor is inlined in `ReactNativeElement` so if you modify
|
|
30
|
+
// this make sure that their implementation stays in sync.
|
|
29
31
|
setInstanceHandle(this, internalInstanceHandle);
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -293,7 +295,7 @@ export function getInstanceHandle(node: ReadOnlyNode): InternalInstanceHandle {
|
|
|
293
295
|
return node[INSTANCE_HANDLE_KEY];
|
|
294
296
|
}
|
|
295
297
|
|
|
296
|
-
function setInstanceHandle(
|
|
298
|
+
export function setInstanceHandle(
|
|
297
299
|
node: ReadOnlyNode,
|
|
298
300
|
instanceHandle: InternalInstanceHandle,
|
|
299
301
|
): void {
|
|
@@ -25,6 +25,18 @@ type IntersectionObserverInit = {
|
|
|
25
25
|
// root?: ReactNativeElement, // This option exists on the Web but it's not currently supported in React Native.
|
|
26
26
|
// rootMargin?: string, // This option exists on the Web but it's not currently supported in React Native.
|
|
27
27
|
threshold?: number | $ReadOnlyArray<number>,
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* This is a React Native specific option (not spec compliant) that specifies
|
|
31
|
+
* ratio threshold(s) of the intersection area to the total `root` area.
|
|
32
|
+
*
|
|
33
|
+
* If set, it will either be a singular ratio value between 0-1 (inclusive)
|
|
34
|
+
* or an array of such ratios.
|
|
35
|
+
*
|
|
36
|
+
* Note: If `rn_rootThreshold` is set, and `threshold` is not set,
|
|
37
|
+
* `threshold` will not default to [0] (as per spec)
|
|
38
|
+
*/
|
|
39
|
+
rn_rootThreshold?: number | $ReadOnlyArray<number>,
|
|
28
40
|
};
|
|
29
41
|
|
|
30
42
|
/**
|
|
@@ -44,13 +56,16 @@ type IntersectionObserverInit = {
|
|
|
44
56
|
* elements with the same observer.
|
|
45
57
|
*
|
|
46
58
|
* This implementation only supports the `threshold` option at the moment
|
|
47
|
-
* (`root` and `rootMargin` are not supported)
|
|
59
|
+
* (`root` and `rootMargin` are not supported) and provides a React Native specific
|
|
60
|
+
* option `rn_rootThreshold`.
|
|
61
|
+
*
|
|
48
62
|
*/
|
|
49
63
|
export default class IntersectionObserver {
|
|
50
64
|
_callback: IntersectionObserverCallback;
|
|
51
65
|
_thresholds: $ReadOnlyArray<number>;
|
|
52
66
|
_observationTargets: Set<ReactNativeElement> = new Set();
|
|
53
67
|
_intersectionObserverId: ?IntersectionObserverId;
|
|
68
|
+
_rootThresholds: $ReadOnlyArray<number> | null;
|
|
54
69
|
|
|
55
70
|
constructor(
|
|
56
71
|
callback: IntersectionObserverCallback,
|
|
@@ -83,7 +98,12 @@ export default class IntersectionObserver {
|
|
|
83
98
|
}
|
|
84
99
|
|
|
85
100
|
this._callback = callback;
|
|
86
|
-
|
|
101
|
+
|
|
102
|
+
this._rootThresholds = normalizeRootThreshold(options?.rn_rootThreshold);
|
|
103
|
+
this._thresholds = normalizeThreshold(
|
|
104
|
+
options?.threshold,
|
|
105
|
+
this._rootThresholds != null, // only provide default if no rootThreshold
|
|
106
|
+
);
|
|
87
107
|
}
|
|
88
108
|
|
|
89
109
|
/**
|
|
@@ -115,14 +135,27 @@ export default class IntersectionObserver {
|
|
|
115
135
|
* A list of thresholds, sorted in increasing numeric order, where each
|
|
116
136
|
* threshold is a ratio of intersection area to bounding box area of an
|
|
117
137
|
* observed target.
|
|
118
|
-
* Notifications for a target are generated when any of the thresholds
|
|
119
|
-
* crossed for that target.
|
|
120
|
-
*
|
|
138
|
+
* Notifications for a target are generated when any of the thresholds specified
|
|
139
|
+
* in `rn_rootThreshold` or `threshold` are crossed for that target.
|
|
140
|
+
*
|
|
141
|
+
* If no value was passed to the constructor, and no `rn_rootThreshold`
|
|
142
|
+
* is set, `0` is used.
|
|
121
143
|
*/
|
|
122
144
|
get thresholds(): $ReadOnlyArray<number> {
|
|
123
145
|
return this._thresholds;
|
|
124
146
|
}
|
|
125
147
|
|
|
148
|
+
/**
|
|
149
|
+
* A list of root thresholds, sorted in increasing numeric order, where each
|
|
150
|
+
* threshold is a ratio of intersection area to bounding box area of the specified
|
|
151
|
+
* root view, which defaults to the viewport.
|
|
152
|
+
* Notifications for a target are generated when any of the thresholds specified
|
|
153
|
+
* in `rn_rootThreshold` or `threshold` are crossed for that target.
|
|
154
|
+
*/
|
|
155
|
+
get rootThresholds(): $ReadOnlyArray<number> | null {
|
|
156
|
+
return this._rootThresholds;
|
|
157
|
+
}
|
|
158
|
+
|
|
126
159
|
/**
|
|
127
160
|
* Adds an element to the set of target elements being watched by the
|
|
128
161
|
* `IntersectionObserver`.
|
|
@@ -221,32 +254,84 @@ export default class IntersectionObserver {
|
|
|
221
254
|
* Converts the user defined `threshold` value into an array of sorted valid
|
|
222
255
|
* threshold options for `IntersectionObserver` (double ∈ [0, 1]).
|
|
223
256
|
*
|
|
257
|
+
* If `defaultEmpty` is true, then defaults to empty array, otherwise [0].
|
|
258
|
+
*
|
|
224
259
|
* @example
|
|
225
260
|
* normalizeThresholds(0.5); // → [0.5]
|
|
226
261
|
* normalizeThresholds([1, 0.5, 0]); // → [0, 0.5, 1]
|
|
227
262
|
* normalizeThresholds(['1', '0.5', '0']); // → [0, 0.5, 1]
|
|
263
|
+
* normalizeThresholds(null); // → [0]
|
|
264
|
+
* normalizeThresholds([null, null]); // → [0, 0]
|
|
265
|
+
*
|
|
266
|
+
* normalizeThresholds([null], true); // → [0]
|
|
267
|
+
* normalizeThresholds(null, true); // → []
|
|
268
|
+
* normalizeThresholds([], true); // → []
|
|
228
269
|
*/
|
|
229
|
-
function
|
|
270
|
+
function normalizeThreshold(
|
|
271
|
+
threshold: mixed,
|
|
272
|
+
defaultEmpty: boolean = false,
|
|
273
|
+
): $ReadOnlyArray<number> {
|
|
230
274
|
if (Array.isArray(threshold)) {
|
|
231
275
|
if (threshold.length > 0) {
|
|
232
|
-
return threshold
|
|
276
|
+
return threshold
|
|
277
|
+
.map(t => normalizeThresholdValue(t, 'threshold'))
|
|
278
|
+
.map(t => t ?? 0)
|
|
279
|
+
.sort();
|
|
280
|
+
} else if (defaultEmpty) {
|
|
281
|
+
return [];
|
|
233
282
|
} else {
|
|
234
283
|
return [0];
|
|
235
284
|
}
|
|
236
285
|
}
|
|
237
286
|
|
|
238
|
-
|
|
287
|
+
const normalized = normalizeThresholdValue(threshold, 'threshold');
|
|
288
|
+
if (normalized == null) {
|
|
289
|
+
return defaultEmpty ? [] : [0];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return [normalized];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Converts the user defined `rn_rootThreshold` value into an array of sorted valid
|
|
297
|
+
* threshold options for `IntersectionObserver` (double ∈ [0, 1]).
|
|
298
|
+
*
|
|
299
|
+
* If invalid array or null, returns null.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* normalizeRootThreshold(0.5); // → [0.5]
|
|
303
|
+
* normalizeRootThresholds([1, 0.5, 0]); // → [0, 0.5, 1]
|
|
304
|
+
* normalizeRootThresholds([null, '0.5', '0']); // → [0, 0.5]
|
|
305
|
+
* normalizeRootThresholds(null); // → null
|
|
306
|
+
* normalizeRootThresholds([null, null]); // → null
|
|
307
|
+
*/
|
|
308
|
+
function normalizeRootThreshold(
|
|
309
|
+
rootThreshold: mixed,
|
|
310
|
+
): null | $ReadOnlyArray<number> {
|
|
311
|
+
if (Array.isArray(rootThreshold)) {
|
|
312
|
+
const normalizedArr = rootThreshold
|
|
313
|
+
.map(rt => normalizeThresholdValue(rt, 'rn_rootThreshold'))
|
|
314
|
+
.filter((rt): rt is number => rt != null)
|
|
315
|
+
.sort();
|
|
316
|
+
return normalizedArr.length === 0 ? null : normalizedArr;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const normalized = normalizeThresholdValue(rootThreshold, 'rn_rootThreshold');
|
|
320
|
+
return normalized == null ? null : [normalized];
|
|
239
321
|
}
|
|
240
322
|
|
|
241
|
-
function normalizeThresholdValue(
|
|
323
|
+
function normalizeThresholdValue(
|
|
324
|
+
threshold: mixed,
|
|
325
|
+
property: string,
|
|
326
|
+
): null | number {
|
|
242
327
|
if (threshold == null) {
|
|
243
|
-
return
|
|
328
|
+
return null;
|
|
244
329
|
}
|
|
245
330
|
|
|
246
331
|
const thresholdAsNumber = Number(threshold);
|
|
247
332
|
if (!Number.isFinite(thresholdAsNumber)) {
|
|
248
333
|
throw new TypeError(
|
|
249
|
-
|
|
334
|
+
`Failed to read the '${property}' property from 'IntersectionObserverInit': The provided double value is non-finite.`,
|
|
250
335
|
);
|
|
251
336
|
}
|
|
252
337
|
|
|
@@ -74,6 +74,32 @@ export default class IntersectionObserverEntry {
|
|
|
74
74
|
return Math.min(ratio, 1);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Returns the ratio of the `intersectionRect` to the `boundingRootRect`.
|
|
79
|
+
*/
|
|
80
|
+
get rn_intersectionRootRatio(): number {
|
|
81
|
+
const intersectionRect = this.intersectionRect;
|
|
82
|
+
|
|
83
|
+
const rootRect = this._nativeEntry.rootRect;
|
|
84
|
+
const boundingRootRect = new DOMRectReadOnly(
|
|
85
|
+
rootRect[0],
|
|
86
|
+
rootRect[1],
|
|
87
|
+
rootRect[2],
|
|
88
|
+
rootRect[3],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (boundingRootRect.width === 0 || boundingRootRect.height === 0) {
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const ratio =
|
|
96
|
+
(intersectionRect.width * intersectionRect.height) /
|
|
97
|
+
(boundingRootRect.width * boundingRootRect.height);
|
|
98
|
+
|
|
99
|
+
// Prevent rounding errors from making this value greater than 1.
|
|
100
|
+
return Math.min(ratio, 1);
|
|
101
|
+
}
|
|
102
|
+
|
|
77
103
|
/**
|
|
78
104
|
* Returns a `DOMRectReadOnly` representing the target's visible area.
|
|
79
105
|
*/
|
package/src/private/webapis/intersectionobserver/specs/__mocks__/NativeIntersectionObserver.js
CHANGED
|
@@ -23,8 +23,10 @@ import nullthrows from 'nullthrows';
|
|
|
23
23
|
|
|
24
24
|
type ObserverState = {
|
|
25
25
|
thresholds: $ReadOnlyArray<number>,
|
|
26
|
+
rootThresholds?: ?$ReadOnlyArray<number>,
|
|
26
27
|
intersecting: boolean,
|
|
27
28
|
currentThreshold: ?number,
|
|
29
|
+
currentRootThreshold: ?number,
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
type Observation = {
|
|
@@ -74,8 +76,10 @@ const NativeIntersectionObserverMock = {
|
|
|
74
76
|
...options,
|
|
75
77
|
state: {
|
|
76
78
|
thresholds: options.thresholds,
|
|
79
|
+
rootThresholds: options.rootThresholds,
|
|
77
80
|
intersecting: false,
|
|
78
81
|
currentThreshold: null,
|
|
82
|
+
currentRootThreshold: null,
|
|
79
83
|
},
|
|
80
84
|
};
|
|
81
85
|
observations.push(observation);
|
|
@@ -141,9 +145,14 @@ const NativeIntersectionObserverMock = {
|
|
|
141
145
|
if (observation.state.intersecting) {
|
|
142
146
|
observation.state.intersecting = false;
|
|
143
147
|
observation.state.currentThreshold = null;
|
|
148
|
+
observation.state.currentRootThreshold = null;
|
|
144
149
|
} else {
|
|
145
150
|
observation.state.intersecting = true;
|
|
146
151
|
observation.state.currentThreshold = observation.thresholds[0];
|
|
152
|
+
observation.state.currentRootThreshold =
|
|
153
|
+
observation.rootThresholds != null
|
|
154
|
+
? observation.rootThresholds[0]
|
|
155
|
+
: null;
|
|
147
156
|
}
|
|
148
157
|
pendingRecords.push(createRecordFromObservation(observation));
|
|
149
158
|
setImmediate(notifyIntersectionObservers);
|