react-native-windows 0.0.0-canary.821 → 0.0.0-canary.823
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 +1 -2
- package/Folly/TEMP_UntilFollyUpdate/ConstexprMath.h +4 -2
- package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +1 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +2 -1
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.windows.js +2 -1
- package/Libraries/Components/StatusBar/StatusBar.js +1 -21
- package/Libraries/Components/TextInput/TextInput.js +6 -3
- package/Libraries/Components/TextInput/TextInput.windows.js +6 -3
- package/Libraries/Components/View/ReactNativeStyleAttributes.js +6 -0
- package/Libraries/Core/Devtools/loadBundleFromServer.windows.js +153 -0
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Core/setUpPerformance.js +5 -3
- package/Libraries/IntersectionObserver/IntersectionObserverManager.js +6 -26
- package/Libraries/LogBox/Data/LogBoxData.js +0 -25
- package/Libraries/NativeComponent/BaseViewConfig.android.js +3 -0
- package/Libraries/NativeComponent/BaseViewConfig.ios.js +3 -0
- package/Libraries/NativeComponent/BaseViewConfig.windows.js +3 -0
- package/Libraries/ReactNative/getNativeComponentAttributes.js +3 -0
- package/Libraries/StyleSheet/StyleSheetTypes.js +6 -0
- package/Libraries/StyleSheet/processFilter.js +132 -0
- package/Libraries/StyleSheet/processTransform.js +18 -3
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +0 -2
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +0 -1
- package/Microsoft.ReactNative/packages.lock.json +42 -70
- package/Microsoft.ReactNative.Managed/packages.lock.json +3 -70
- package/PropertySheets/Generated/PackageVersion.g.props +2 -2
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/performance/timeline/BoundedConsumableBuffer.h +10 -10
- package/codegen/NativeAppStateSpec.g.h +8 -8
- package/codegen/NativeMutationObserverSpec.g.h +14 -14
- package/codegen/NativePushNotificationManagerIOSSpec.g.h +15 -15
- package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +15 -9
- package/codegen/react/components/rnwcore/States.h +0 -26
- package/codegen/rnwcoreJSI-generated.cpp +9 -22
- package/codegen/rnwcoreJSI.h +483 -529
- package/fmt/TEMP_UntilFmtUpdate/core.h +2925 -0
- package/fmt/fmt.vcxproj +1 -1
- package/jest/mockComponent.js +7 -0
- package/package.json +19 -19
- package/rn-get-polyfills.js +1 -0
- package/src/private/featureflags/ReactNativeFeatureFlags.js +9 -4
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +3 -2
- package/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js +0 -13
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/observers/events/EventPerformanceLogger.cpp +0 -200
- package/codegen/NativeAnimationsDebugModuleSpec.g.h +0 -40
- package/jest/ReactNativeInternalFeatureFlagsMock.js +0 -13
- package/src/private/specs/modules/NativeAnimationsDebugModule.js +0 -20
package/.flowconfig
CHANGED
|
@@ -257,7 +257,8 @@ constexpr auto& constexpr_iterated_squares_desc_2_v =
|
|
|
257
257
|
template <typename T, typename... Ts>
|
|
258
258
|
constexpr T constexpr_max(T a, Ts... ts) {
|
|
259
259
|
T list[] = {ts..., a}; // 0-length arrays are illegal
|
|
260
|
-
|
|
260
|
+
// [Windows #12703 - Fix folly CodeQL issues]
|
|
261
|
+
for (size_t i = 0; i < sizeof...(Ts); ++i) {
|
|
261
262
|
a = list[i] < a ? a : list[i];
|
|
262
263
|
}
|
|
263
264
|
return a;
|
|
@@ -268,7 +269,8 @@ constexpr T constexpr_max(T a, Ts... ts) {
|
|
|
268
269
|
template <typename T, typename... Ts>
|
|
269
270
|
constexpr T constexpr_min(T a, Ts... ts) {
|
|
270
271
|
T list[] = {ts..., a}; // 0-length arrays are illegal
|
|
271
|
-
|
|
272
|
+
// [Windows #12703 - Fix folly CodeQL issues]
|
|
273
|
+
for (size_t i = 0; i < sizeof...(Ts); ++i) {
|
|
272
274
|
a = list[i] < a ? list[i] : a;
|
|
273
275
|
}
|
|
274
276
|
return a;
|
|
@@ -45,6 +45,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
45
45
|
diff: require('../../Utilities/differ/pointsDiffer'),
|
|
46
46
|
},
|
|
47
47
|
decelerationRate: true,
|
|
48
|
+
enableSyncOnScroll: true, // Fabric only.
|
|
48
49
|
disableIntervalMomentum: true,
|
|
49
50
|
maintainVisibleContentPosition: true,
|
|
50
51
|
pagingEnabled: true,
|
|
@@ -134,7 +135,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
134
135
|
contentInsetAdjustmentBehavior: true,
|
|
135
136
|
decelerationRate: true,
|
|
136
137
|
endDraggingSensitivityMultiplier: true,
|
|
137
|
-
enableSyncOnScroll: true, //
|
|
138
|
+
enableSyncOnScroll: true, // Fabric only.
|
|
138
139
|
directionalLockEnabled: true,
|
|
139
140
|
disableIntervalMomentum: true,
|
|
140
141
|
indicatorStyle: true,
|
|
@@ -45,6 +45,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
45
45
|
diff: require('../../Utilities/differ/pointsDiffer'),
|
|
46
46
|
},
|
|
47
47
|
decelerationRate: true,
|
|
48
|
+
enableSyncOnScroll: true, // Fabric only.
|
|
48
49
|
disableIntervalMomentum: true,
|
|
49
50
|
maintainVisibleContentPosition: true,
|
|
50
51
|
pagingEnabled: true,
|
|
@@ -134,7 +135,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
|
|
|
134
135
|
contentInsetAdjustmentBehavior: true,
|
|
135
136
|
decelerationRate: true,
|
|
136
137
|
endDraggingSensitivityMultiplier: true,
|
|
137
|
-
enableSyncOnScroll: true, //
|
|
138
|
+
enableSyncOnScroll: true, // Fabric only.
|
|
138
139
|
directionalLockEnabled: true,
|
|
139
140
|
disableIntervalMomentum: true,
|
|
140
141
|
indicatorStyle: true,
|
|
@@ -163,29 +163,9 @@ function createStackEntry(props: any): any {
|
|
|
163
163
|
/**
|
|
164
164
|
* Component to control the app status bar.
|
|
165
165
|
*
|
|
166
|
-
* ### Usage with Navigator
|
|
167
|
-
*
|
|
168
166
|
* It is possible to have multiple `StatusBar` components mounted at the same
|
|
169
167
|
* time. The props will be merged in the order the `StatusBar` components were
|
|
170
|
-
* mounted.
|
|
171
|
-
*
|
|
172
|
-
* ```
|
|
173
|
-
* <View>
|
|
174
|
-
* <StatusBar
|
|
175
|
-
* backgroundColor="blue"
|
|
176
|
-
* barStyle="light-content"
|
|
177
|
-
* />
|
|
178
|
-
* <Navigator
|
|
179
|
-
* initialRoute={{statusBarHidden: true}}
|
|
180
|
-
* renderScene={(route, navigator) =>
|
|
181
|
-
* <View>
|
|
182
|
-
* <StatusBar hidden={route.statusBarHidden} />
|
|
183
|
-
* ...
|
|
184
|
-
* </View>
|
|
185
|
-
* }
|
|
186
|
-
* />
|
|
187
|
-
* </View>
|
|
188
|
-
* ```
|
|
168
|
+
* mounted.
|
|
189
169
|
*
|
|
190
170
|
* ### Imperative API
|
|
191
171
|
*
|
|
@@ -1099,12 +1099,14 @@ function InternalTextInput(props: Props): React.Node {
|
|
|
1099
1099
|
};
|
|
1100
1100
|
|
|
1101
1101
|
const [mostRecentEventCount, setMostRecentEventCount] = useState<number>(0);
|
|
1102
|
-
|
|
1103
1102
|
const [lastNativeText, setLastNativeText] = useState<?Stringish>(props.value);
|
|
1104
1103
|
const [lastNativeSelectionState, setLastNativeSelection] = useState<{|
|
|
1105
|
-
selection:
|
|
1104
|
+
selection: Selection,
|
|
1106
1105
|
mostRecentEventCount: number,
|
|
1107
|
-
|}>({
|
|
1106
|
+
|}>({
|
|
1107
|
+
selection: {start: -1, end: -1},
|
|
1108
|
+
mostRecentEventCount: mostRecentEventCount,
|
|
1109
|
+
});
|
|
1108
1110
|
|
|
1109
1111
|
const lastNativeSelection = lastNativeSelectionState.selection;
|
|
1110
1112
|
|
|
@@ -1442,6 +1444,7 @@ function InternalTextInput(props: Props): React.Node {
|
|
|
1442
1444
|
onSelectionChange={_onSelectionChange}
|
|
1443
1445
|
onSelectionChangeShouldSetResponder={emptyFunctionThatReturnsTrue}
|
|
1444
1446
|
selection={selection}
|
|
1447
|
+
selectionColor={selectionColor}
|
|
1445
1448
|
style={StyleSheet.compose(
|
|
1446
1449
|
useMultilineDefaultStyle ? styles.multilineDefault : null,
|
|
1447
1450
|
style,
|
|
@@ -1176,12 +1176,14 @@ function InternalTextInput(props: Props): React.Node {
|
|
|
1176
1176
|
};
|
|
1177
1177
|
|
|
1178
1178
|
const [mostRecentEventCount, setMostRecentEventCount] = useState<number>(0);
|
|
1179
|
-
|
|
1180
1179
|
const [lastNativeText, setLastNativeText] = useState<?Stringish>(props.value);
|
|
1181
1180
|
const [lastNativeSelectionState, setLastNativeSelection] = useState<{|
|
|
1182
|
-
selection:
|
|
1181
|
+
selection: Selection,
|
|
1183
1182
|
mostRecentEventCount: number,
|
|
1184
|
-
|}>({
|
|
1183
|
+
|}>({
|
|
1184
|
+
selection: {start: -1, end: -1},
|
|
1185
|
+
mostRecentEventCount: mostRecentEventCount,
|
|
1186
|
+
});
|
|
1185
1187
|
|
|
1186
1188
|
const lastNativeSelection = lastNativeSelectionState.selection;
|
|
1187
1189
|
|
|
@@ -1589,6 +1591,7 @@ function InternalTextInput(props: Props): React.Node {
|
|
|
1589
1591
|
onSelectionChange={_onSelectionChange}
|
|
1590
1592
|
onSelectionChangeShouldSetResponder={emptyFunctionThatReturnsTrue}
|
|
1591
1593
|
selection={selection}
|
|
1594
|
+
selectionColor={selectionColor}
|
|
1592
1595
|
style={StyleSheet.compose(
|
|
1593
1596
|
useMultilineDefaultStyle ? styles.multilineDefault : null,
|
|
1594
1597
|
style,
|
|
@@ -12,6 +12,7 @@ import type {AnyAttributeType} from '../../Renderer/shims/ReactNativeTypes';
|
|
|
12
12
|
|
|
13
13
|
import processAspectRatio from '../../StyleSheet/processAspectRatio';
|
|
14
14
|
import processColor from '../../StyleSheet/processColor';
|
|
15
|
+
import processFilter from '../../StyleSheet/processFilter';
|
|
15
16
|
import processFontVariant from '../../StyleSheet/processFontVariant';
|
|
16
17
|
import processTransform from '../../StyleSheet/processTransform';
|
|
17
18
|
import processTransformOrigin from '../../StyleSheet/processTransformOrigin';
|
|
@@ -114,6 +115,11 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
|
|
|
114
115
|
transform: {process: processTransform},
|
|
115
116
|
transformOrigin: {process: processTransformOrigin},
|
|
116
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Filter
|
|
120
|
+
*/
|
|
121
|
+
experimental_filter: {process: processFilter},
|
|
122
|
+
|
|
117
123
|
/**
|
|
118
124
|
* View
|
|
119
125
|
*/
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall react_native
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import Networking from '../../Network/RCTNetworking';
|
|
13
|
+
import DevLoadingView from '../../Utilities/DevLoadingView';
|
|
14
|
+
import HMRClient from '../../Utilities/HMRClient';
|
|
15
|
+
import getDevServer from './getDevServer';
|
|
16
|
+
|
|
17
|
+
declare var global: {globalEvalWithSourceUrl?: (string, string) => mixed, ...};
|
|
18
|
+
|
|
19
|
+
let pendingRequests = 0;
|
|
20
|
+
|
|
21
|
+
const cachedPromisesByUrl = new Map<string, Promise<void>>();
|
|
22
|
+
|
|
23
|
+
function asyncRequest(
|
|
24
|
+
url: string,
|
|
25
|
+
): Promise<{body: string, headers: {[string]: string}}> {
|
|
26
|
+
let id = null;
|
|
27
|
+
let responseText = null;
|
|
28
|
+
let headers = null;
|
|
29
|
+
let dataListener;
|
|
30
|
+
let completeListener;
|
|
31
|
+
let responseListener;
|
|
32
|
+
let incrementalDataListener;
|
|
33
|
+
return new Promise<{body: string, headers: {[string]: string}}>(
|
|
34
|
+
(resolve, reject) => {
|
|
35
|
+
dataListener = Networking.addListener(
|
|
36
|
+
'didReceiveNetworkData',
|
|
37
|
+
([requestId, response]) => {
|
|
38
|
+
if (requestId === id) {
|
|
39
|
+
responseText = response;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
incrementalDataListener = Networking.addListener(
|
|
44
|
+
'didReceiveNetworkIncrementalData',
|
|
45
|
+
([requestId, data]) => {
|
|
46
|
+
if (requestId === id) {
|
|
47
|
+
if (responseText != null) {
|
|
48
|
+
responseText += data;
|
|
49
|
+
} else {
|
|
50
|
+
responseText = data;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
responseListener = Networking.addListener(
|
|
56
|
+
'didReceiveNetworkResponse',
|
|
57
|
+
([requestId, status, responseHeaders]) => {
|
|
58
|
+
if (requestId === id) {
|
|
59
|
+
headers = responseHeaders;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
completeListener = Networking.addListener(
|
|
64
|
+
'didCompleteNetworkResponse',
|
|
65
|
+
([requestId, error]) => {
|
|
66
|
+
if (requestId === id) {
|
|
67
|
+
if (error) {
|
|
68
|
+
reject(error);
|
|
69
|
+
} else {
|
|
70
|
+
//$FlowFixMe[incompatible-call]
|
|
71
|
+
resolve({body: responseText, headers});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
Networking.sendRequest(
|
|
77
|
+
'GET',
|
|
78
|
+
'asyncRequest',
|
|
79
|
+
url,
|
|
80
|
+
{},
|
|
81
|
+
'',
|
|
82
|
+
'text',
|
|
83
|
+
true,
|
|
84
|
+
0,
|
|
85
|
+
requestId => {
|
|
86
|
+
id = requestId;
|
|
87
|
+
},
|
|
88
|
+
true,
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
).finally(() => {
|
|
92
|
+
dataListener?.remove();
|
|
93
|
+
completeListener?.remove();
|
|
94
|
+
responseListener?.remove();
|
|
95
|
+
incrementalDataListener?.remove();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function buildUrlForBundle(bundlePathAndQuery: string) {
|
|
100
|
+
const {url: serverUrl} = getDevServer();
|
|
101
|
+
return (
|
|
102
|
+
serverUrl.replace(/\/+$/, '') + '/' + bundlePathAndQuery.replace(/^\/+/, '')
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = function (bundlePathAndQuery: string): Promise<void> {
|
|
107
|
+
const requestUrl = buildUrlForBundle(bundlePathAndQuery);
|
|
108
|
+
let loadPromise = cachedPromisesByUrl.get(requestUrl);
|
|
109
|
+
|
|
110
|
+
if (loadPromise) {
|
|
111
|
+
return loadPromise;
|
|
112
|
+
}
|
|
113
|
+
DevLoadingView.showMessage('Downloading...', 'load');
|
|
114
|
+
++pendingRequests;
|
|
115
|
+
|
|
116
|
+
loadPromise = asyncRequest(requestUrl)
|
|
117
|
+
.then<void>(({body, headers}) => {
|
|
118
|
+
if (
|
|
119
|
+
headers['Content-Type'] != null &&
|
|
120
|
+
headers['Content-Type'].indexOf('application/json') >= 0
|
|
121
|
+
) {
|
|
122
|
+
// Errors are returned as JSON.
|
|
123
|
+
throw new Error(
|
|
124
|
+
JSON.parse(body).message ||
|
|
125
|
+
`Unknown error fetching '${bundlePathAndQuery}'`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
HMRClient.registerBundle(requestUrl);
|
|
130
|
+
|
|
131
|
+
// Some engines do not support `sourceURL` as a comment. We expose a
|
|
132
|
+
// `globalEvalWithSourceUrl` function to handle updates in that case.
|
|
133
|
+
if (global.globalEvalWithSourceUrl) {
|
|
134
|
+
global.globalEvalWithSourceUrl(body, requestUrl);
|
|
135
|
+
} else {
|
|
136
|
+
// [Windows #12704 - CodeQL patch]
|
|
137
|
+
// eslint-disable-next-line no-eval
|
|
138
|
+
eval(body); // CodeQL [js/eval-usage] Debug only. Developer inner loop.
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
.catch<void>(e => {
|
|
142
|
+
cachedPromisesByUrl.delete(requestUrl);
|
|
143
|
+
throw e;
|
|
144
|
+
})
|
|
145
|
+
.finally(() => {
|
|
146
|
+
if (!--pendingRequests) {
|
|
147
|
+
DevLoadingView.hide();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
cachedPromisesByUrl.set(requestUrl, loadPromise);
|
|
152
|
+
return loadPromise;
|
|
153
|
+
};
|
|
@@ -19,11 +19,13 @@ if (NativePerformance) {
|
|
|
19
19
|
} else {
|
|
20
20
|
if (!global.performance) {
|
|
21
21
|
// $FlowExpectedError[cannot-write]
|
|
22
|
-
global.performance =
|
|
23
|
-
|
|
22
|
+
global.performance = {
|
|
23
|
+
mark: () => {},
|
|
24
|
+
measure: () => {},
|
|
25
|
+
now: () => {
|
|
24
26
|
const performanceNow = global.nativePerformanceNow || Date.now;
|
|
25
27
|
return performanceNow();
|
|
26
28
|
},
|
|
27
|
-
}
|
|
29
|
+
};
|
|
28
30
|
}
|
|
29
31
|
}
|
|
@@ -67,19 +67,11 @@ function setTargetForInstanceHandle(
|
|
|
67
67
|
instanceHandleToTargetMap.set(key, target);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function unsetTargetForInstanceHandle(instanceHandle: mixed): void {
|
|
71
|
-
// $FlowExpectedError[incompatible-type] instanceHandle is typed as mixed but we know it's an object and we need it to be to use it as a key in a WeakMap.
|
|
72
|
-
const key: interface {} = instanceHandle;
|
|
73
|
-
instanceHandleToTargetMap.delete(key);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
70
|
// The mapping between ReactNativeElement and their corresponding shadow node
|
|
77
71
|
// also needs to be kept here because React removes the link when unmounting.
|
|
78
|
-
|
|
79
|
-
// from the target to unobserve.
|
|
80
|
-
const targetToShadowNodeAndInstanceHandleMap: WeakMap<
|
|
72
|
+
const targetToShadowNodeMap: WeakMap<
|
|
81
73
|
ReactNativeElement,
|
|
82
|
-
|
|
74
|
+
ReturnType<typeof getShadowNode>,
|
|
83
75
|
> = new WeakMap();
|
|
84
76
|
|
|
85
77
|
/**
|
|
@@ -163,12 +155,8 @@ export function observe({
|
|
|
163
155
|
// access it even after the instance handle has been unmounted.
|
|
164
156
|
setTargetForInstanceHandle(instanceHandle, target);
|
|
165
157
|
|
|
166
|
-
// Same for the mapping between the target and its shadow node
|
|
167
|
-
|
|
168
|
-
targetToShadowNodeAndInstanceHandleMap.set(target, [
|
|
169
|
-
targetShadowNode,
|
|
170
|
-
instanceHandle,
|
|
171
|
-
]);
|
|
158
|
+
// Same for the mapping between the target and its shadow node.
|
|
159
|
+
targetToShadowNodeMap.set(target, targetShadowNode);
|
|
172
160
|
|
|
173
161
|
if (!isConnected) {
|
|
174
162
|
NativeIntersectionObserver.connect(notifyIntersectionObservers);
|
|
@@ -201,26 +189,18 @@ export function unobserve(
|
|
|
201
189
|
return;
|
|
202
190
|
}
|
|
203
191
|
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
if (targetShadowNodeAndInstanceHandle == null) {
|
|
192
|
+
const targetShadowNode = targetToShadowNodeMap.get(target);
|
|
193
|
+
if (targetShadowNode == null) {
|
|
207
194
|
console.error(
|
|
208
195
|
'IntersectionObserverManager: could not find registration data for target',
|
|
209
196
|
);
|
|
210
197
|
return;
|
|
211
198
|
}
|
|
212
199
|
|
|
213
|
-
const [targetShadowNode, instanceHandle] = targetShadowNodeAndInstanceHandle;
|
|
214
|
-
|
|
215
200
|
NativeIntersectionObserver.unobserve(
|
|
216
201
|
intersectionObserverId,
|
|
217
202
|
targetShadowNode,
|
|
218
203
|
);
|
|
219
|
-
|
|
220
|
-
// We can guarantee we won't receive any more entries for this target,
|
|
221
|
-
// so we don't need to keep the mappings anymore.
|
|
222
|
-
unsetTargetForInstanceHandle(instanceHandle);
|
|
223
|
-
targetToShadowNodeAndInstanceHandleMap.delete(target);
|
|
224
204
|
}
|
|
225
205
|
|
|
226
206
|
/**
|
|
@@ -449,31 +449,6 @@ export function withSubscription(
|
|
|
449
449
|
this._subscription.unsubscribe();
|
|
450
450
|
}
|
|
451
451
|
}
|
|
452
|
-
|
|
453
|
-
_handleDismiss = (): void => {
|
|
454
|
-
// Here we handle the cases when the log is dismissed and it
|
|
455
|
-
// was either the last log, or when the current index
|
|
456
|
-
// is now outside the bounds of the log array.
|
|
457
|
-
const {selectedLogIndex, logs: stateLogs} = this.state;
|
|
458
|
-
const logsArray = Array.from(stateLogs);
|
|
459
|
-
if (selectedLogIndex != null) {
|
|
460
|
-
if (logsArray.length - 1 <= 0) {
|
|
461
|
-
setSelectedLog(-1);
|
|
462
|
-
} else if (selectedLogIndex >= logsArray.length - 1) {
|
|
463
|
-
setSelectedLog(selectedLogIndex - 1);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
dismiss(logsArray[selectedLogIndex]);
|
|
467
|
-
}
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
_handleMinimize = (): void => {
|
|
471
|
-
setSelectedLog(-1);
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
_handleSetSelectedLog = (index: number): void => {
|
|
475
|
-
setSelectedLog(index);
|
|
476
|
-
};
|
|
477
452
|
}
|
|
478
453
|
|
|
479
454
|
return LogBoxStateSubscription;
|
|
@@ -166,6 +166,9 @@ const validAttributesForNonEventProps = {
|
|
|
166
166
|
backgroundColor: {process: require('../StyleSheet/processColor').default},
|
|
167
167
|
transform: true,
|
|
168
168
|
transformOrigin: true,
|
|
169
|
+
experimental_filter: {
|
|
170
|
+
process: require('../StyleSheet/processFilter').default,
|
|
171
|
+
},
|
|
169
172
|
opacity: true,
|
|
170
173
|
elevation: true,
|
|
171
174
|
shadowColor: {process: require('../StyleSheet/processColor').default},
|
|
@@ -220,6 +220,9 @@ const validAttributesForNonEventProps = {
|
|
|
220
220
|
hitSlop: {diff: require('../Utilities/differ/insetsDiffer')},
|
|
221
221
|
collapsable: true,
|
|
222
222
|
collapsableChildren: true,
|
|
223
|
+
experimental_filter: {
|
|
224
|
+
process: require('../StyleSheet/processFilter').default,
|
|
225
|
+
},
|
|
223
226
|
|
|
224
227
|
borderTopWidth: true,
|
|
225
228
|
borderTopColor: {process: require('../StyleSheet/processColor').default},
|
|
@@ -240,6 +240,9 @@ const validAttributesForNonEventProps = {
|
|
|
240
240
|
hitSlop: {diff: require('../Utilities/differ/insetsDiffer')},
|
|
241
241
|
collapsable: true,
|
|
242
242
|
collapsableChildren: true,
|
|
243
|
+
experimental_filter: {
|
|
244
|
+
process: require('../StyleSheet/processFilter').default,
|
|
245
|
+
},
|
|
243
246
|
|
|
244
247
|
borderTopWidth: true,
|
|
245
248
|
borderTopColor: {process: require('../StyleSheet/processColor').default},
|
|
@@ -14,6 +14,7 @@ const ReactNativeStyleAttributes = require('../Components/View/ReactNativeStyleA
|
|
|
14
14
|
const resolveAssetSource = require('../Image/resolveAssetSource');
|
|
15
15
|
const processColor = require('../StyleSheet/processColor').default;
|
|
16
16
|
const processColorArray = require('../StyleSheet/processColorArray');
|
|
17
|
+
const processFilter = require('../StyleSheet/processFilter').default;
|
|
17
18
|
const insetsDiffer = require('../Utilities/differ/insetsDiffer');
|
|
18
19
|
const matricesDiffer = require('../Utilities/differ/matricesDiffer');
|
|
19
20
|
const pointsDiffer = require('../Utilities/differ/pointsDiffer');
|
|
@@ -188,6 +189,8 @@ function getProcessorForType(typeName: string): ?(nextProp: any) => any {
|
|
|
188
189
|
return processColor;
|
|
189
190
|
case 'ColorArray':
|
|
190
191
|
return processColorArray;
|
|
192
|
+
case 'Filter':
|
|
193
|
+
return processFilter;
|
|
191
194
|
case 'ImageSource':
|
|
192
195
|
return resolveAssetSource;
|
|
193
196
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
13
|
import type AnimatedNode from '../Animated/nodes/AnimatedNode';
|
|
14
|
+
import type {FilterPrimitive} from '../StyleSheet/processFilter';
|
|
14
15
|
import type {
|
|
15
16
|
____DangerouslyImpreciseStyle_InternalOverrides,
|
|
16
17
|
____ImageStyle_InternalOverrides,
|
|
@@ -690,10 +691,15 @@ export type ____ShadowStyle_Internal = $ReadOnly<{
|
|
|
690
691
|
...____ShadowStyle_InternalOverrides,
|
|
691
692
|
}>;
|
|
692
693
|
|
|
694
|
+
type ____FilterStyle_Internal = $ReadOnly<{
|
|
695
|
+
experimental_filter?: $ReadOnlyArray<FilterPrimitive>,
|
|
696
|
+
}>;
|
|
697
|
+
|
|
693
698
|
export type ____ViewStyle_InternalCore = $ReadOnly<{
|
|
694
699
|
...$Exact<____LayoutStyle_Internal>,
|
|
695
700
|
...$Exact<____ShadowStyle_Internal>,
|
|
696
701
|
...$Exact<____TransformStyle_Internal>,
|
|
702
|
+
...____FilterStyle_Internal,
|
|
697
703
|
backfaceVisibility?: 'visible' | 'hidden',
|
|
698
704
|
backgroundColor?: ____ColorValue_Internal,
|
|
699
705
|
borderColor?: ____ColorValue_Internal,
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @flow
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
export type FilterPrimitive =
|
|
14
|
+
| {brightness: number | string}
|
|
15
|
+
| {blur: number | string}
|
|
16
|
+
| {contrast: number | string}
|
|
17
|
+
| {grayscale: number | string}
|
|
18
|
+
| {hueRotate: number | string}
|
|
19
|
+
| {invert: number | string}
|
|
20
|
+
| {opacity: number | string}
|
|
21
|
+
| {saturate: number | string}
|
|
22
|
+
| {sepia: number | string};
|
|
23
|
+
|
|
24
|
+
export default function processFilter(
|
|
25
|
+
filter: $ReadOnlyArray<FilterPrimitive> | string,
|
|
26
|
+
): $ReadOnlyArray<FilterPrimitive> {
|
|
27
|
+
let result: Array<FilterPrimitive> = [];
|
|
28
|
+
if (typeof filter === 'string') {
|
|
29
|
+
// matches on functions with args like "brightness(1.5)"
|
|
30
|
+
const regex = new RegExp(/(\w+)\(([^)]+)\)/g);
|
|
31
|
+
let matches;
|
|
32
|
+
|
|
33
|
+
while ((matches = regex.exec(filter))) {
|
|
34
|
+
const amount = _getFilterAmount(matches[1], matches[2]);
|
|
35
|
+
|
|
36
|
+
if (amount != null) {
|
|
37
|
+
const filterPrimitive = {};
|
|
38
|
+
// $FlowFixMe The key will be the correct one but flow can't see that.
|
|
39
|
+
filterPrimitive[matches[1]] = amount;
|
|
40
|
+
// $FlowFixMe The key will be the correct one but flow can't see that.
|
|
41
|
+
result.push(filterPrimitive);
|
|
42
|
+
} else {
|
|
43
|
+
// If any primitive is invalid then apply none of the filters. This is how
|
|
44
|
+
// web works and makes it clear that something is wrong becuase no
|
|
45
|
+
// graphical effects are happening.
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
for (const filterPrimitive of filter) {
|
|
51
|
+
const [filterName, filterValue] = Object.entries(filterPrimitive)[0];
|
|
52
|
+
const amount = _getFilterAmount(filterName, filterValue);
|
|
53
|
+
|
|
54
|
+
if (amount != null) {
|
|
55
|
+
const resultObject = {};
|
|
56
|
+
// $FlowFixMe
|
|
57
|
+
resultObject[filterName] = amount;
|
|
58
|
+
// $FlowFixMe
|
|
59
|
+
result.push(resultObject);
|
|
60
|
+
} else {
|
|
61
|
+
// If any primitive is invalid then apply none of the filters. This is how
|
|
62
|
+
// web works and makes it clear that something is wrong becuase no
|
|
63
|
+
// graphical effects are happening.
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function _getFilterAmount(filterName: string, filterArgs: mixed): ?number {
|
|
73
|
+
let filterArgAsNumber: number;
|
|
74
|
+
let unit: string;
|
|
75
|
+
if (typeof filterArgs === 'string') {
|
|
76
|
+
// matches on args with units like "1.5 5% -80deg"
|
|
77
|
+
const argsWithUnitsRegex = new RegExp(/([+-]?\d*(\.\d+)?)([a-zA-Z%]+)?/g);
|
|
78
|
+
const match = argsWithUnitsRegex.exec(filterArgs);
|
|
79
|
+
|
|
80
|
+
if (!match || isNaN(Number(match[1]))) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
filterArgAsNumber = Number(match[1]);
|
|
85
|
+
unit = match[3];
|
|
86
|
+
} else if (typeof filterArgs === 'number') {
|
|
87
|
+
filterArgAsNumber = filterArgs;
|
|
88
|
+
} else {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
switch (filterName) {
|
|
93
|
+
// Hue rotate takes some angle that can have a unit and can be
|
|
94
|
+
// negative. Additionally, 0 with no unit is allowed.
|
|
95
|
+
case 'hueRotate':
|
|
96
|
+
if (filterArgAsNumber === 0) {
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
if (unit !== 'deg' && unit !== 'rad') {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
return unit === 'rad'
|
|
103
|
+
? (180 * filterArgAsNumber) / Math.PI
|
|
104
|
+
: filterArgAsNumber;
|
|
105
|
+
// blur takes any positive CSS length that is not a percent. In RN
|
|
106
|
+
// we currently only have DIPs, so we are not parsing units here.
|
|
107
|
+
case 'blur':
|
|
108
|
+
if ((unit && unit !== 'px') || filterArgAsNumber < 0) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
return filterArgAsNumber;
|
|
112
|
+
// All other filters except take a non negative number or percentage. There
|
|
113
|
+
// are no units associated with this value and percentage numbers map 1-to-1
|
|
114
|
+
// to a non-percentage number (e.g. 50% == 0.5).
|
|
115
|
+
case 'brightness':
|
|
116
|
+
case 'contrast':
|
|
117
|
+
case 'grayscale':
|
|
118
|
+
case 'invert':
|
|
119
|
+
case 'opacity':
|
|
120
|
+
case 'saturate':
|
|
121
|
+
case 'sepia':
|
|
122
|
+
if ((unit && unit !== '%' && unit !== 'px') || filterArgAsNumber < 0) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
if (unit === '%') {
|
|
126
|
+
filterArgAsNumber /= 100;
|
|
127
|
+
}
|
|
128
|
+
return filterArgAsNumber;
|
|
129
|
+
default:
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|